commit 218ca90543758a20ac326e444ca0643174ca7384 Author: Rebellion Developments Date: Thu Mar 16 11:25:00 2000 +0100 Import Aliens vs Predator - Gold (Build 116) Source code release, imported from: https://www.gamefront.com/games/aliens-vs-predator-3/file/avp-gold-complete-source-code All text files were converted to Unix format. diff --git a/3dc/AFONT.C b/3dc/AFONT.C new file mode 100644 index 0000000..46ac394 --- /dev/null +++ b/3dc/AFONT.C @@ -0,0 +1,914 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" + +#include "gamedef.h" +#include "font.h" + +#include "indexfnt.hpp" + +#define UseLocalAssert 1 +#include "ourasert.h" + + +/* Roxbys font stuff. any comments will be useful!!! + + font control - Fonts description and sturctures game/plat/font.h + Platform dependent processing game/plat/platsup.c or ddplat.cpp +*/ + + + +/* general ideas. Crap I know!!! + + written to maintain compatiblity with the current texture (bitmap) processing tools. + all the information about spacing of the font is maintained witin the bitmap itself, + using hotspots for the texture processing, that way we dont need extra tools to convert + fonts. It also allows complete font positioning (except different letter combos changing) + I have shifted most of the emphasis onto the artists to set up the font and to mark it how they + see fit. All the fonts must contain hotspots for all the letters. In that way we can easily + expand fonts. The character offests at the mo are simply -32. We may have to set up jump tables + at some later date to get chars for different languages. + + Nothing supports anti-aliasing at the moment. Be careful with colours!!! + + Most of the info is being passed as locals. Clumsy I know. I didnt want to take up more + space than was nessecery + + + HARD coded. Names of the fonts + Number of fonts to load + Number of characters in the font. you can leave letters blank. The number of + characters in the fonts can be changed for different languages + + AVP-Win95 + + This loads all the fonts in the structure PFFONT AvpFonts[] that is passed + to while NUM_FONTS. The Imageheader->ImagePtr for the data is maintained + untill we have processd the characters. I dont fancy manipulating the data + in a LPDIRECTDRAWSURFACE. The character descriptors in the font contain + nothing but a src RECT. the void* pointer in the PFFONT structure in this + case is cast to LPDIRECTDRAWSURFACE. + + + + Not that the entire font is placed into a + file That is then processed. CLUT where to + put the CLU???? Put it into the vid memory. + use a void* +*/ + +/* + Only have 8 bit support a tne moment. More to come!!! + Screen modes. I recommend loading up different fonts for different screen modes. + Simply reference a different structure. +*/ + + +#define CHAR_WIDTH(font_num, offset) ((AvpFonts[font_num].srcRect[offset].right - AvpFonts[font_num].srcRect[offset].left)) +#define CHAR_HEIGHT(font_num, offset) ((AvpFonts[font_num].srcRect[offset].bottom - AvpFonts[font_num].srcRect[offset].top)) +#define IS_CHAR_WHITE_SPACE(ch) ((ch == '\t' || ch == '\n' || ch == ' ' || (int)ch == 0x0)) + + + +static int ProcessFontEntry +( + PFFONT* font, + unsigned char* fontstartaddress, + unsigned pitch, + int* countfromrow, + int* countfromcol, + int charnum +); + +static int ProcessLineLength +( + char* start_ch, // start char of string + AVP_FONTS fontnum, // the font we are using + int offset, // the offset from the font + int max_width, // the width of the line + char** end_ch, // filled with end address + int* line_length +); + +void LoadAllFonts() +{ + // these fonts end up being in memory all the time, + // I will also supply a function which is delete + // specific font. + + int fontnum = 0; + + while(fontnum < NUM_FONTS) + { + /* load the font in turn */ + LoadPFFont(fontnum); + fontnum ++; + } +} + + +void LoadPFFont(int fontnum) +{ + // these fonts end up being in memory all the time, + // I will also supply a function which is delete + // specific font. + + PFFONT *font = &AvpFonts[fontnum]; + unsigned nPitch; + unsigned char * pSurface; + + LoadFont(font); + + /* get the hotspot color first entry in */ + + if(font->fttexBitDepth == 15)font->fttexBitDepth = 16; + + pSurface = FontLock(font,&nPitch); + GLOBALASSERT(pSurface); + + font->hotSpotValue = *(unsigned *)pSurface & (font->fttexBitDepth<32 ? (1<fttexBitDepth)-1 : 0xffffffffU); + + /* the hotspot value is the top-left pixel */ + { + int charnum = 0; + int countfromrow = 1; + int countfromcol = 0; + + /* + find the hotspots and send everything to the + processing function. This part of routine find the + hotspots in numbers of pixels + */ + + /*Top line of the texture is redundent we get the hotspot from this*/ + /*edge of the texture has only lines*/ + + + while(charnum < font->num_chars_in_font) + { + ProcessFontEntry(font,pSurface,nPitch,&countfromrow,&countfromcol,charnum); + charnum++; + } + + #if 0 + // Taken out by DHM 26/11/97: + fontnum++; + #endif + charnum = 0; + } + + FontUnlock(font); + + #if SupportWindows95 + INDEXFNT_PFLoadHook + ( + (FontIndex) fontnum, + // FontIndex I_Font_New, + font // PFFONT *pffont_New + ); + #endif +} + + + +static int ProcessFontEntry +( + PFFONT* font, + unsigned char* fontstartaddress, + unsigned pitch, + int* countfromrow, + int* countfromcol, + int charnum +) +{ + /* + okay set the starting point + + countfromrow marks the current depth of the processing row in the texture. + countfromcol marks how far along the current coloum we have processed + + * = HOTSPOT .. the first pixel is used as the hotspot + + ********************** + * ** ** **** * <---- startfromrow + ### + # + ## # # ### + # # # # # ## + ### ### #### ## + * * # * **** * Blank chars marked by two hotspots adjacent + ### ^^ |at the top and the bottom + * * || | + ^ ||______| + | + | + startfromcol + + ********************* Note that the spot in col 0 marks a new linw of chars + + */ + + + int curr_row = *countfromrow; + int curr_col = *countfromcol; + int y_offset = 0, x_offset = curr_col; + + + GLOBALASSERT(font); + GLOBALASSERT(fontstartaddress); + GLOBALASSERT(charnum < font->num_chars_in_font); + GLOBALASSERT(curr_row < font->fttexHeight); + GLOBALASSERT(curr_col <= font->fttexWidth); + + /*remember that all the corrdinates are done by pixels + find the x and y corrdinates of the left lower hotspot + we process each line (row) from startfromrow to the end + first find the next marker in startfromrow + */ + + // only supported if bit depth is a whole number of bytes + GLOBALASSERT(8==font->fttexBitDepth || 16==font->fttexBitDepth || 24==font->fttexBitDepth || 32==font->fttexBitDepth); + + while(1) + { + // this bit processes the chars, finds uvs, extents and fills in the sturcture*/ + // count along the row to find the next x position + + unsigned int colour_here; + + if(x_offset > font->fttexWidth - 1) + { + // reached the end of the line! reset x and then y + + x_offset = 0; + curr_col = 0; + + curr_row += font->fontHeight; // max line height + *countfromrow = curr_row; + + GLOBALASSERT(curr_row < font->fttexHeight); + } + + switch (font->fttexBitDepth) + { + default: + GLOBALASSERT(0); + case 8: + colour_here = *(fontstartaddress + (curr_row*pitch + x_offset)); + break; + case 16: + colour_here = *(unsigned short *)(fontstartaddress + (curr_row*pitch + 2*x_offset)); + break; + case 24: + { + unsigned char * pPixel = fontstartaddress + (curr_row*pitch + 3*x_offset); + // assuming the right endianness + colour_here = pPixel[0] | (unsigned)pPixel[1] << 8 | (unsigned)pPixel[2] << 16; + break; + } + case 32: + colour_here = *(unsigned *)(fontstartaddress + (curr_row*pitch + 4*x_offset)); + break; + + } + + if(colour_here == font->hotSpotValue) + { + int width = -1, height = -1; + /* set up the uv corrds of the top left corner*/ + int u = x_offset + 1; + int v = curr_row + 1; + + + /* scan down to give height*/ + for(y_offset = (curr_row + 1); y_offset < font->fttexHeight; y_offset++) + { + switch (font->fttexBitDepth) + { + default: + GLOBALASSERT(0); + case 8: + colour_here = *(fontstartaddress + (y_offset*pitch + x_offset)); + break; + case 16: + colour_here = *(unsigned short *)(fontstartaddress + (y_offset*pitch + 2*x_offset)); + break; + case 24: + { + unsigned char * pPixel = fontstartaddress + (y_offset*pitch + 3*x_offset); + // assuming the right endianness + colour_here = pPixel[0] | (unsigned)pPixel[1] << 8 | (unsigned)pPixel[2] << 16; + break; + } + case 32: + colour_here = *(unsigned *)(fontstartaddress + (y_offset*pitch + 4*x_offset)); + break; + + } + + if(colour_here == font->hotSpotValue) + { + height = y_offset - curr_row - 1; // -1 because we exclude the top and bottom hotspots + break; + } + } + + /* scan along to get the width*/ + for(++x_offset; x_offset < font->fttexWidth; x_offset ++) + { + switch (font->fttexBitDepth) + { + default: + GLOBALASSERT(0); + case 8: + colour_here = *(fontstartaddress + (curr_row*pitch + x_offset)); + break; + case 16: + colour_here = *(unsigned short *)(fontstartaddress + (curr_row*pitch + 2*x_offset)); + break; + case 24: + { + unsigned char * pPixel = fontstartaddress + (curr_row*pitch + 3*x_offset); + // assuming the right endianness + colour_here = pPixel[0] | (unsigned)pPixel[1] << 8 | (unsigned)pPixel[2] << 16; + break; + } + case 32: + colour_here = *(unsigned *)(fontstartaddress + (curr_row*pitch + 4*x_offset)); + break; + + } + + if(colour_here == font->hotSpotValue) + { + width = x_offset - curr_col - 1; // exclude end hotspot + break; + } + } + + *countfromcol = x_offset + 1; /* ready for the next char*/ + + /*fill in the data structure - platform dependent*/ + FillCharacterSlot(u, v, width, height, charnum, font); + return 0; + } + + x_offset++; + + } + return 0; +} + + +#if 0 // obsolete +static int Process8BitEntry(PFFONT* font, + char* fontstartaddress, + int* countfromrow, + int* countfromcol, + int charnum) +{ + /* + okay set the starting point + + countfromrow marks the current depth of the processing row in the texture. + countfromcol marks how far along the current coloum we have processed + + * = HOTSPOT .. the first pixel is used as the hotspot + + ********************** + * ** ** **** * <---- startfromrow + ### + # + ## # # ### + # # # # # ## + ### ### #### ## + * * # * **** * Blank chars marked by two hotspots adjacent + ### ^^ |at the top and the bottom + * * || | + ^ ||______| + | + | + startfromcol + + ********************* Note that the spot in col 0 marks a new linw of chars + + */ + + + int curr_row = *countfromrow; + int curr_col = *countfromcol; + int y_offset = 0, x_offset = curr_col; + + + GLOBALASSERT(font); + GLOBALASSERT(fontstartaddress); + GLOBALASSERT(charnum < font->num_chars_in_font); + GLOBALASSERT(curr_row < font->fttexHeight); + GLOBALASSERT(curr_col <= font->fttexWidth); + + /*remember that all the corrdinates are done by pixels + find the x and y corrdinates of the left lower hotspot + we process each line (row) from startfromrow to the end + first find the next marker in startfromrow + */ + + while(1) + { + // this bit processes the chars, finds uvs, extents and fills in the sturcture*/ + // count along the row to find the next x position + + unsigned int colour_here; + + if(x_offset > font->fttexWidth - 1) + { + // reached the end of the line! reset x and then y + + x_offset = 0; + curr_col = 0; + + curr_row += font->fontHeight; // max line height + *countfromrow = curr_row; + + GLOBALASSERT(curr_row < font->fttexHeight); + } + + colour_here = (int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset)); + + + if(colour_here == font->hotSpotValue) + { + int width = -1, height = -1; + /* set up the uv corrds of the top left corner*/ + int u = x_offset + 1; + int v = curr_row + 1; + + + /* scan down to give height*/ + for(y_offset = (curr_row + 1); y_offset < font->fttexHeight; y_offset++) + { + colour_here = (int)*(fontstartaddress + (y_offset*font->fttexWidth + x_offset)); + + if(colour_here == font->hotSpotValue) + { + height = y_offset - curr_row - 1; // -1 because we exclude the top and bottom hotspots + break; + } + } + + /* scan along to get the width*/ + for(++x_offset; x_offset < font->fttexWidth; x_offset ++) + { + colour_here = (int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset)); + + + if(colour_here == font->hotSpotValue) + { + width = x_offset - curr_col - 1; // exclude end hotspot + break; + } + } + + *countfromcol = x_offset + 1; /* ready for the next char*/ + + /*fill in the data structure - platform dependent*/ + FillCharacterSlot(u, v, width, height, charnum, font); + return 0; + } + + x_offset++; + + } a +} + + + + +static int Process16BitEntry(PFFONT *font, + char* fontstartaddress, + int* countfromrow, + int* countfromcol, + int charnum) +{ +int curr_row = *countfromrow; +int curr_col = *countfromcol; +int y_offset = 0, x_offset = curr_col; + + +GLOBALASSERT(font); +GLOBALASSERT(fontstartaddress); +GLOBALASSERT(charnum < font->num_chars_in_font); +GLOBALASSERT(curr_row < font->fttexHeight); +GLOBALASSERT(curr_col <= font->fttexWidth); + +/*remember that all the corrdinates are done by pixels + find the x and y corrdinates of the left lower hotspot + we process each line (row) from startfromrow to the end + first find the next marker in startfromrow +*/ + + while(1) + { + // this bit processes the chars, finds uvs, extents and fills in the sturcture*/ + // count along the row to find the next x position + + unsigned int colour_here; + + if(x_offset > font->fttexWidth - 1) + { + // reached the end of the line! reset x and then y + + x_offset = 0; + curr_col = 0; + + curr_row += font->fontHeight; // max line height + *countfromrow = curr_row; + + GLOBALASSERT(curr_row < font->fttexHeight); + } + + { + unsigned int colour_high = 0x000000ff & (unsigned int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset)*2); + unsigned int colour_low = 0x000000ff & (int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset)*2 + 1); + colour_here = (colour_high << 8) | colour_low; + } + + if(colour_here == font->hotSpotValue) + { + int width = -1, height = -1; + /* set up the uv corrds of the top left corner*/ + int u = x_offset + 1; + int v = curr_row + 1; + + + /* scan down to give height*/ + for(y_offset = (curr_row + 1); y_offset < font->fttexHeight; y_offset++) + { + { + int colour_high = 0x000000ff & (int)*(fontstartaddress + (y_offset*font->fttexWidth + x_offset)*2); + int colour_low = 0x000000ff & (int)*(fontstartaddress + (y_offset*font->fttexWidth + x_offset)*2 + 1); + colour_here = (colour_high << 8) | colour_low; + } + + if(colour_here == font->hotSpotValue) + { + height = y_offset - curr_row - 1; // -1 because we exclude the top and bottom hotspots + break; + } + } + + /* scan along to get the width*/ + for(++x_offset; x_offset < font->fttexWidth; x_offset ++) + { + { + int colour_high = 0x000000ff & (int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset)*2); + int colour_low = 0x000000ff & (int)*(fontstartaddress + (curr_row*font->fttexWidth + x_offset)*2 + 1); + colour_here = (colour_high << 8) | colour_low; + } + + if(colour_here == font->hotSpotValue) + { + width = x_offset - curr_col - 1; // exclude end hotspot + break; + } + } + + *countfromcol = x_offset + 1; /* ready for the next char*/ + + /*fill in the data structure - platform dependent*/ + FillCharacterSlot(u, v, width, height, charnum, font); + return 0; + } + + x_offset++; + + } + return 0; +} + +static int Process24BitEntry(PFFONT* font, + char* fontstartaddress, + int* countfromrow, + int* countfromcol, + int charnum) +{ + return 0; +} + +#endif + + + + + +void BLTWholeFont(int fontnum, int x , int y, int win_width) +{ + int i = 0; + int plotto_x = x, plotto_y = y; + + while(i < AvpFonts[fontnum].num_chars_in_font) + { + int charwidth = AvpFonts[fontnum].srcRect[i].right - AvpFonts[fontnum].srcRect[i].left; + + if((charwidth + plotto_x - x) > win_width) + { + plotto_y += AvpFonts[fontnum].fontHeight; + plotto_x= x; + } + + BLTFontOffsetToHUD(&AvpFonts[fontnum], plotto_x, plotto_y, i); + + plotto_x += charwidth + 1; + + i++; + } + return; +} + + +void BLTString(FONT_DESC str_packet) +{ + PFFONT font = AvpFonts[str_packet.fontnum]; + + unsigned char *strptr = str_packet.string; + int offset = 0; + int not_finished = Yes; + int pos_x = str_packet.destx; + int pos_y = str_packet.desty; + int white_space_width = CHAR_WIDTH(str_packet.fontnum, 0); + + + // set up the font processing varibles depending on the type of font + + switch(font.font_type) + { + case(I_FONT_NUMERIC): + { + offset = 0x30; + break; + } + case(I_FONT_UC_NUMERIC): + { + offset = 0x20; + break; + } + case(I_FONT_UCLC_NUMERIC): + { + offset = 0x20; + break; + } + default: + GLOBALASSERT(2<1); + } + + while(not_finished) + { + int line_length; + char *end_char; + + + // find the line length and the end char in the line + + not_finished = ProcessLineLength + ( + strptr, // start char of string + str_packet.fontnum, // the font we are using + offset, // the offset from the font + str_packet.width, // the width of the line + &end_char, // filled with end address + &line_length // filled with line length + ); + + + // work out where to print the line + + if(line_length) + { + switch(str_packet.just) + { + + case FJ_LEFT_JUST: + { + pos_x = str_packet.destx; + break; + } + case FJ_CENTRED: + { + pos_x = str_packet.destx + ((str_packet.width - line_length) >> 1); + break; + } + case FJ_RIGHT_JUST: + { + pos_x = str_packet.destx + (str_packet.width - line_length); + break; + } + default: + { + ; + } + } + + // now print the line untill we reach the address of + // the end char + + do + { + if(*strptr == ' ') + { + pos_x += white_space_width; + } + else if(*strptr == '\t') + { + pos_x += 4*white_space_width; + } + else if(*strptr == '\n' || strptr == 0x0) + { + GLOBALASSERT(strptr == end_char); + } + else if((int)*strptr == 0xD) + { + // carrige return + // do nothing - our next char should be '\n' + + GLOBALASSERT(*(strptr + 1) == '\n'); + } + else + { + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + int end_pos = pos_x + CHAR_WIDTH(str_packet.fontnum, ((int)*strptr - offset)); + int bottom_pos = pos_y + CHAR_HEIGHT(str_packet.fontnum, ((int)*strptr - offset)); + + if(end_pos > ScreenDescriptorBlock.SDB_Width || pos_x < 0) + { + //dont draw + //not_finished = No; + } + else if( bottom_pos > ScreenDescriptorBlock.SDB_Height || pos_y < 0) + { + not_finished = No; + } + else + { + pos_x += BLTFontOffsetToHUD + ( + &font, + pos_x, + pos_y, + (int)*strptr - offset + ); + + pos_x ++; // to make space between letters + } + } + } + while(++strptr != end_char); + + pos_y += font.fontHeight - 2; + } + + strptr++; + } +} + + + +/* +RWH - changes to font line processing +This function takes a pointer to a string a font and a width and +puts the length of the line into line_length AND puts the end char address into end_ch + +It returns 0 when we have reached the end of a string + +*/ + + + +int ProcessLineLength +( + char* start_ch, // start char of string + AVP_FONTS fontnum, // the font we are using + int offset, // the offset from the font + int max_width, // the width of the line + char** end_ch, // filled with end address + int* line_length +) +{ + int continue_to_process_word = Yes; + int white_space_width = CHAR_WIDTH(fontnum, 0); + char *word_ptr = start_ch; + + *line_length = 0; + + if(start_ch == NULL) + { + *end_ch = NULL; + *line_length = 0; + return 0; + } + + // first process any white space at the end of the + // line out + + while(*start_ch == ' ') + { + // make sure we havent run out + // of chars to process + if(*start_ch == 0x0) + { + *end_ch = NULL; + *line_length = 0; + return 0; + } + + start_ch++; + } + + // Now we can start on the characters in the line + // note that we have to have two loops. The first + // continues untill we break out of it. The second + // adds up the length of each word and sees if the line + // with the new word will overrun the max_width + + + // the word_ptr points to the current char - it is only incremented + // when we can be sure that we can add the current letter to the word + + + while(1) + { + int word_length = 0; + + continue_to_process_word = Yes; + + while(continue_to_process_word) + { + // is the next char white space ? + // if so close the word + + if(IS_CHAR_WHITE_SPACE(*(word_ptr + 1))) + { + // hit white space - finish this current word but only + // AFTER we have processed the current char + continue_to_process_word = No; + } + + // need to process every white space seperately + if(*word_ptr == '\t') + { + // a one char word! + word_length = 4 * white_space_width; + continue_to_process_word = No; + word_ptr++; + } + else if(*word_ptr == 0x0) + { + // reached end of file - need to return 0 + + *end_ch = word_ptr; + return 0; + } + else if(*word_ptr == '\n') + { + *end_ch = word_ptr; + return 1; + } + else if(*word_ptr == ' ') + { + if(word_length) + { + // tag on the white space onto the word length + word_length += white_space_width; + } + // other wise keep on tiking on + + word_ptr++; + } + else + { + // yeah add a letter to the word length + int char_off = (char)(*word_ptr - offset); + word_length += CHAR_WIDTH(fontnum, char_off); + word_length ++; //for space between lettes + + word_ptr++; //process next char + } + } + + // okay we have the length of this word - check to see if + // it overruns the end of the line - if it is too long, + // break out of the line loop + + + if((word_length + *line_length) >= max_width) + { + *end_ch = start_ch; + return 1; + } + else + { + *line_length += word_length; + // set up the next word save the beginning of teh word in start_ch + start_ch = word_ptr; + } + } +} \ No newline at end of file diff --git a/3dc/AvP_Alien_Readme.txt b/3dc/AvP_Alien_Readme.txt new file mode 100644 index 0000000..4e5ad5a --- /dev/null +++ b/3dc/AvP_Alien_Readme.txt @@ -0,0 +1,262 @@ +*********************************************************************** + + + + ALIENS VERSUS PREDATOR + Alien Demo + + Version 1.2 + Readme File + Jan 20th 1999 + + + +*********************************************************************** + + CONTENTS + +*********************************************************************** + + 1. MINIMUM REQUIREMENTS + 2. DEMO OBJECTIVES + 3. INSTALLATION + 4. GAME CONTROLS + 5. ALIEN ABILITIES + 6. ALIEN WEAPONS + 7. CONTACT & LEGAL INFORMATION + +*********************************************************************** + + 1. MINIMUM REQUIREMENTS + +*********************************************************************** + +Intel Pentium 200 MMX PC (or 100% compatible CPU) +DirectX supported 3D Accelerator Card +DirectX v.6 (Included on Installation CD) +32Mb RAM (64Mb recommended) +64Mb free Hard Drive +Windows 95 + + +The ALIENS VERSUS PREDATOR Demo is a work in-progress. Thus it is not +fully optimized and configured for lower spec machines. These issues +will be corrected for the full retail version, giving the end user +control over engine and special effect variables ensuring smooth +gameplay over a wide variety of CPUs, accelerator cards and RAM. + +Due to the complexity of the ALIENS VERSUS PREDATOR models, users with +32Mb of RAM may experience some memory paging, especially when exiting +the game and returning to Windows. These problems will be fixed for the +release version of the game. + + +KNOWN ISSUE WITH SOUNDBLASTER LIVE! CARDS: + +Currently with SoundBlaster Live! cards, the EAX environmental +extensions are applied to all the audio being played from the CD. +While this does not necessarily interfere with the game; to stop +it from happening, follow these steps: + +1. Access your Creative AudioHQ, usually found in + + Start Menu --> Programs --> Creative--> Soundblaster Live! --> AudioHQ + +2. Access the 'Environmental Audio' control applet + +3. Click on the 'Options' tab within the Environmental Audio window. + +4. Check the 'Always Save Changes Automatically' preference box. + +5. Click the 'Source' tab. + +6. Select the CD Digital source and set the Reverb & Chorus amounts + to 0%. Leave the Original Sound source at 100%. + +7. Do the same with the CD Audio source. (Reverb & Chorus at 0%) + +8. Click on 'Close' and you will be prompted to input a name for your + new settings. We suggest 'No CD effects' or similar. + +9. You are now ready to play ALIENS VERSUS PREDATOR with normal CD + music. This issue should be resolved for the full release of the game. + + +*********************************************************************** + + 2. DEMO OBJECTIVES + +*********************************************************************** + +Playing as an Alien, you start in an Atmosphere Processor secured +by Colonial Marines. You must escape to the planet's surface to alert +the Hive. You must proceed with speed and stealth, and use guile to +disable and destroy those forces which you cannot attack head-on. + + +*********************************************************************** + + 3. INSTALLATION + +*********************************************************************** + +ALIENS VERSUS PREDATOR requires DirectX 6. This can be found within the +game's installation directory and you will be prompted to install it if +it is not on your system when you install the Demo. + +To install the ALIENS VERSUS PREDATOR Demo, double click on Setup.exe +Follow the onscreen instructions. + +ALIENS VERSUS PREDATOR dynamically streams FMV from your machine's +local hard-drive. This playback is greatly enhanced if the FMV files +are installed on a defragmented directory. We STRONGLY recommend +de-fragging your hard drive before installing ALIENS VERSUS PREDATOR. + +To de-fragment your drive, either use the Windows95 accessory +'Disk Defragmenter' or any other 3rd party defragmentation utility. + +Although the ALIENS VERSUS PREDATOR Demo will work with other +applications running in the background, for the best results it is +recommended that you run the game as a stand-alone application +(with no other applications running). + +As well as avoiding possible conflicts from other applications, this +will also help prevent Windows from accessing the hard drive Virtual +Memory swap file, and affecting the speed and sound effects of the +game. + +*********************************************************************** + + 4. GAME CONTROLS + +*********************************************************************** + +ALIENS VERSUS PREDATOR supports all DirectX compatible controllers. You +must install and set up these controllers before entering the game. + +Other keys and mouse configurations can be defined either from the main +menu screen or from the in-game menus. + +The default keys are: + +UPARROW Forward +DOWNARROW Backward +LEFTARROW Strafe Left +RIGHTARROW Strafe Right +NUMPAD 4 Turn Left +NUMPAD 6 Turn Right +RIGHT_ALT Strafe +A Look Up +Z Look Down +S Centre View +LEFTSHIFT Walk +RIGHTCTRL Crouch/Climb +RIGHTSHIFT Jump +SPACE Operate +I Toggle between HUNT and NAVIGATION vision modes + +The default mouse settings are full MouseLook. +The default mouse buttons are "Claw Attack" and "Tail Attack". + +F8 Take screenshot (currently only 16bit video modes) + +*********************************************************************** + + 5. ALIEN ABILITIES + +*********************************************************************** + +HEALTH + +Health is displayed as the numerals in the top right of your screen. +When you are damaged, your screen will flash yellow from the sides. +Your health can be replenished by feeding on other lifeforms - see +JAW ATTACK in the ALIEN WEAPONS section. + +ARMOR + +The strength of the Alien's exoskeleton is displayed as the numerals +directly under HEALTH. As with HEALTH, damage to the exoskeleton can +be repaired by feeding on other lifeforms. + +VISION MODES + +The Alien has the ability to 'see' the world through two modes: +HUNTING and NAVIGATION. In HUNTING mode the Alien's senses are +attuned to searching for prey, whereas in NAVIGATION mode the +senses are concentrated on defining the surrounding environment. + +MOVEMENT & CLIMBING + +The Alien has the ability to move on any surface. Simply hold down +the 'Crouch/Climb' key whilst moving. When climbing, releasing the +key will release the Alien's grip and drop it to the floor. Using +the 'Jump' key while climbing will cause the Alien to pounce in the +direction it is looking. + + +*********************************************************************** + + 6. ALIEN WEAPONS + +*********************************************************************** + +CLAWS + +Tapping or holding the 'Claw Attack' button triggers a flurry of +swipes and slashes. In the right circumstances the 'Claw Attack' +button can also trigger the secondary jaws. + +JAW + +The secondary jaws can be used to feed on other lifeforms, thus +replenishing HEALTH and ARMOR. Jaw attacks require a certain amount +of skill to achieve. When a target's head is close enough and in the +centre of the screen (the 'sweet-spot') the Alien's inner jaws will +become visible to indicate that a jaw attack is possible. Pressing +the 'Claw Attack' key will then launch the jaw attack. + +N.B. Jaw attacking corpses provides less of a health/armor bonus than +live prey - assuming that the corpse still has a head. Try practicing +on unarmed personnel! + +TAIL + +Tapping 'Tail Attack' causes a quick, low power, jab, whereas holding +down the 'Tail Attack' button readies the tail for a more powerful +strike. The tail will automatically target any prey in front of the +Alien. + + +*********************************************************************** + + 7. CONTACT & LEGAL INFORMATION + +*********************************************************************** + +CONTACT INFORMATION + +For more information, or to communicate with us with regards to this or +any Fox Interactive product, please consult our Worldwide Web site at: + + http://www.foxinteractive.com + +...or for questions/technical issues send us an email at: + + avp@fox.com + +LEGAL INFORMATION + +ALIENS VERSUS PREDATOR is published by Fox Interactive and developed +by Rebellion Developments, Ltd. + +ALIENS TM & (c) 1986, 1998 Twentieth Century Fox Film Corporation. +PREDATOR TM & (c) 1987, 1998 Twentieth Century Fox Film Corporation. +ALIENS VERSUS PREDATOR TM & (c) 1998 Twentieth Century Fox Film +Corporation. All Rights Reserved. "Aliens," "Predator," "Fox," and +"Fox Interactive" and their associated logos are the property of +Twentieth Century Fox Film Corporation. All Rights Reserved. + +*********************************************************************** + + diff --git a/3dc/AvP_Marine_Readme.txt b/3dc/AvP_Marine_Readme.txt new file mode 100644 index 0000000..1395a9c --- /dev/null +++ b/3dc/AvP_Marine_Readme.txt @@ -0,0 +1,284 @@ +*********************************************************************** + + + + ALIENS VERSUS PREDATOR + Marine Demo + + Version 1.0 + Readme File + Nov 23rd 1998 + + + +*********************************************************************** + + CONTENTS + +*********************************************************************** + + 1. MINIMUM REQUIREMENTS + 2. DEMO OBJECTIVES + 3. INSTALLATION + 4. GAME CONTROLS + 5. MARINE EQUIPMENT + 6. MARINE WEAPONRY + 7. CONTACT & LEGAL INFORMATION + +*********************************************************************** + + 1. MINIMUM REQUIREMENTS + +*********************************************************************** + +Intel Pentium 200 MMX PC (or 100% compatible CPU) +DirectX supported 3D Accelerator Card +DirectX v.6 (Included on Installation CD) +32Mb RAM (64Mb recommended) +64Mb free Hard Drive +Windows 95 + + +The ALIENS VERSUS PREDATOR Demo is a work in-progress. Thus it is not +fully optimised and configured for lower spec machines. These issues +will be corrected for the full retail version, giving the end user +control over engine and special effect variables ensuring smooth +gameplay over a wide variety of CPUs, accelerator cards and RAM. + +Due to the complexity of the ALIENS VERSUS PREDATOR models, users with +32Mb of RAM may experience some memory paging, especially when exiting +the game and returning to Windows. These problems will be fixed for the +release version of the game. + + +KNOWN ISSUE WITH SOUNDBLASTER LIVE! CARDS: + +Currently with SoundBlaster Live! cards, the EAX environmental +extensions are applied to all the audio being played from the CD. +While this does not necessarily interfere with the game; to stop +it from happening, follow these steps: + +1. Access your Creative AudioHQ, usually found in + + Start Menu --> Programs --> Creative--> Soundblaster Live! --> AudioHQ + +2. Access the 'Environmental Audio' control applet + +3. Click on the 'Options' tab within the Environmental Audio window. + +4. Check the 'Always Save Changes Automatically' preference box. + +5. Click the 'Source' tab. + +6. Select the CD Digital source and set the Reverb & Chorus amounts + to 0%. Leave the Original Sound source at 100%. + +7. Do the same with the CD Audio source. (Reverb & Chorus at 0%) + +8. Click on 'Close' and you will be prompted to input a name for your + new settings. We suggest 'No CD effects' or similar. + +9. You are now ready to play ALIENS VERSUS PREDATOR with normal CD + music. This issue should be resolved for the full release of the game. + + +*********************************************************************** + + 2. DEMO OBJECTIVES + +*********************************************************************** + +As the Marine, you are the last surviving member of your squad. Your +mission was to explore and investigate the Atmosphere Processor, then +destroy it. You were to remain as guard inside the APC... until your +squad were brutally massacred by forces unknown. Your mission is now +to survive and follow the instructions beamed down to you from your +mission commander from his support ship in low orbit. + + +*********************************************************************** + + 3. INSTALLATION + +*********************************************************************** + +ALIENS VERSUS PREDATOR requires DirectX 6. This can be found within the +game's installation directory and you will be prompted to install it if +it is not on your system when you install the Demo. + +To install the ALIENS VERSUS PREDATOR Demo, double click on Setup.exe +Follow the onscreen instructions. + +ALIENS VERSUS PREDATOR dynamically streams FMV from your machine's +local hard-drive. This playback is greatly enhanced if the FMV files +are installed on a defragmented directory. We STRONGLY recommend +de-fragging your hard drive before installing ALIENS VERSUS PREDATOR. + +To de-fragment your drive, either use the Windows95 accessory +'Disk Defragmenter' or any other 3rd party defragmentation utility. + +Although the ALIENS VERSUS PREDATOR Demo will work with other +applications running in the background, for the best results it is +recommended that you run the game as a stand-alone application +(with no other applications running). + +As well as avoiding possible conflicts from other applications, this +will also help prevent Windows from accessing the hard drive Virtual +Memory swap file, and affecting the speed and sound effects of the +game. + +*********************************************************************** + + 4. GAME CONTROLS + +*********************************************************************** + +ALIENS VERSUS PREDATOR supports all DirectX compatible controllers. You +must install and set up these controllers before entering the game. + +Other keys and mouse configurations can be defined either from the main +menu screen or from the in-game menus. + +The default keys are: + +UPARROW Forward +DOWNARROW Backward +LEFTARROW Strafe Left +RIGHTARROW Strafe Right +NUMPAD 4 Turn Left +NUMPAD 6 Turn Right +RIGHT_ALT Strafe +A Look Up +Z Look Down +S Centre View +LEFTSHIFT Walk +RIGHTSHIFT Jump +SPACE Operate +I Toggle Image Intensifier +Q Next Weapon +W Previous Weapon +L Throw Flare +BACKSPACE Flashback weapon (switches to previous held) + +The default mouse settings are full MouseLook. +The default mouse buttons are fire primary and fire secondary. + + + +*********************************************************************** + + 5. MARINE EQUIPMENT + +*********************************************************************** + +HEALTH + +Health is displayed as green numerals in the top right of your screen. +When you are damaged, your screen will flash red from the sides. Your +health can be replenished from healthpacks your comrades have dropped +in various levels of the Atmosphere Processor. + + +ARMOR + +Armor protects you from both acid blood and other forms of damage. It +is displayed beneath the health numerals as a percentage. You may don +extra armor if you find it. + + +IMAGE INTENSIFIER + +All Colonial Marines are equipped with image intensification optics. +Once activated your vision is augmented for low light conditions, thus +allowing you to see even in pitch darkness. You may use the Intensifier +at will, although it does temporarily burn-out if you are near a strong +light source (such as your weapon firing). + + +FLARES + +You come equipped with small phosphorus flares that you may throw to +light your way. These will stick to any surface and provide a strong +yet temporary light, as well as a deal of smoke. Flares and your +Image Intensifier naturally do not mix well. + + +*********************************************************************** + + 6. MARINE WEAPONS + +*********************************************************************** + +PULSERIFLE (slot 1) + +A Colonial Marine's standard weapon, combining a powerful assault rifle +with an under and over grenade launcher. It carries 99 rounds in the +magazine - watch for reloads! The number of grenades it can carry are +limited - look for your companion's old pulserifles for reloads. +The PulseRifle is less accurate if you are moving whilst firing. + + +SMARTGUN (slot 2) + +A mobile Colonial Marine's most powerful weapon, the SmartGun is a +masterpiece of technology. Mounted on a gyroscopic harness, it literally +aims itself, targeting the centre of mass. It is linked to the marine's +Head Up Display - once it has acquired a target the recticle turns red +and begins to track. To fully use a SmartGun, the operator must watch +where the gun wishes to move and lead it manually - this drastically +decreases aiming time. Smartguns are less useful against smaller, more +agile targets. The smartgun is belt-fed from a large magazine mounted +on the harness, so rarely runs out of ammunition. Care should be taken +as the armour piercing bullets from the SmartGun will deal with most +targets in an explosive manner - short bursts will be sufficient to +deal with almost any foe. + + +FLAMETHROWER (Slot 3) + +The Flamethrower is specifically designed as a close-combat weapon for +the clearing of areas. It is somewhat inaccurate, but the jet of napalm +will eventually kill anything it ignites. Keep the jet trained on a +target to inflict more direct damage. +The flamethrower runs out of fuel in a very short space of time - short +controlled bursts are the most economical method of firing. + +WARNING! The napalm fired from the flamethrower is dangerous - do NOT +run forwards whilst firing (walking is OK) else you will set yourself +on fire. Additionally, it is possible that the napalm will 'bounce' off +a surface and back onto the user. However, nothing is more effective +than the flamethrower when exterminating vermin. + + +*********************************************************************** + + 7. CONTACT & LEGAL INFORMATION + +*********************************************************************** + +CONTACT INFORMATION + +For more information, or to communicate with us with regards to this or +any Fox Interactive product, please consult our Worldwide Web site at: + + http://www.foxinteractive.com + +...or for questions/technical issues send us an email at: + + avp@fox.com + +LEGAL INFORMATION + +ALIENS VERSUS PREDATOR is published by Fox Interactive and developed +by Rebellion Developments, Ltd. + +ALIENS TM & (c) 1986, 1998 Twentieth Century Fox Film Corporation. +PREDATOR TM & (c) 1987, 1998 Twentieth Century Fox Film Corporation. +ALIENS VERSUS PREDATOR TM & (c) 1998 Twentieth Century Fox Film +Corporation. All Rights Reserved. "Aliens," "Predator," "Fox," and +"Fox Interactive" and their associated logos are the property of +Twentieth Century Fox Film Corporation. All Rights Reserved. + +*********************************************************************** + + diff --git a/3dc/AvP_Predator_Readme.txt b/3dc/AvP_Predator_Readme.txt new file mode 100644 index 0000000..bd45aab --- /dev/null +++ b/3dc/AvP_Predator_Readme.txt @@ -0,0 +1,264 @@ +*********************************************************************** + + + + ALIENS VERSUS PREDATOR + Predator Demo + + Version 1.3 + Readme File + Oct 22nd 1998 + + + +*********************************************************************** + + CONTENTS + +*********************************************************************** + + 1. MINIMUM REQUIREMENTS + 2. DEMO OBJECTIVES + 3. INSTALLATION + 4. GAME CONTROLS + 5. PREDATOR EQUIPMENT + 6. PREDATOR WEAPONRY + 7. CONTACT & LEGAL INFORMATION + +*********************************************************************** + + 1. MINIMUM REQUIREMENTS + +*********************************************************************** + +Intel Pentium 200 MMX PC (or 100% compatible CPU) +DirectX supported 3D Accelerator Card +DirectX v.6 (Included on Installation CD) +32Mb RAM (64Mb reccommended) +64Mb free Hard Drive +Windows 95 + + +The ALIENS VERSUS PREDATOR Demo is a work in-progress. Thus it is not +fully optimised and configured for lower spec machines. These issues +will be corrected for the full retail version, giving the end user +control over engine and special effect variables ensuring smooth +gameplay over a wide variety of CPUs, accelerator cards and RAM. + +Due to the complexity of the ALIENS VERSUS PREDATOR models, users with +32Mb of RAM may experience some memory paging, especially when exiting +the game and returning to Windows. These problems will be fixed for the +release version of the game. + + +*********************************************************************** + + 2. DEMO OBJECTIVES + +*********************************************************************** + +As the Predator, you must descend through an Alien-infested Atmosphere +Processor to eliminate the Marines who are defending an APC at the base +of the structure. Your weapons are Wrist-blades, Speargun and shoulder +mounted Plasmacaster. You also possess an emergency medical kit. + + + +*********************************************************************** + + 3. INSTALLATION + +*********************************************************************** + +ALIENS VERSUS PREDATOR requires DirectX 6. This can be found within the +game's installation directory and you will be prompted to install it if +it is not on your system when you install the Demo. + +To install the ALIENS VERSUS PREDATOR Demo, double click on Setup.exe +Follow the onscreen instructions. + +ALIENS VERSUS PREDATOR dynamically streams FMV from your machine's +local hard-drive. This playback is greatly enhanced if the FMV files +are installed on a defragmented directory. We STRONGLY recommend +de-fragging your hard drive before installing ALIENS VERSUS PREDATOR. + +To de-fragment your drive, either use the Windows95 accessory +'Disk Defragmenter' or any other 3rd party defragmentation utility. + +Although the ALIENS VERSUS PREDATOR Demo will work with other +Applications running in the background, for the best results it is +recommended that you run the game as a stand-alone application +(with no other applications running). + +As well as avoiding possible conflicts from other applications, this +will also help prevent Windows from accessing the hard drive Virtual +Memory swap file, and affecting the speed and sound effects of the +game. + +*********************************************************************** + + 4. GAME CONTROLS + +*********************************************************************** + +ALIENS VERSUS PREDATOR supports all DirectX compatible controllers. You +must install and set up these controllers before entering the game. + +Other keys and mouse configurations can be defined either from the main +menu screen or from the in-game menus. + +The default keys are: + +UPARROW Forward +DOWNARROW Backward +LEFTARROW Strafe Left +RIGHTARROW Strafe Right +NUMPAD 4 Turn Left +NUMPAD 6 Turn Right +RIGHT_ALT Strafe +A Look Up +Z Look Down +S Centre View +LEFTSHIFT Walk +RIGHTSHIFT Jump +SPACE Operate +I Toggle Cloaking +Q Next Weapon +W Previous Weapon +PAGEUP Zoom In +PAGEDOWN Zoom Out +L Cycle Vision Modes + +The default mouse settings are full MouseLook. +The default mouse buttons are fire primary and fire secondary. + + + +*********************************************************************** + + 5. PREDATOR EQUIPMENT + +*********************************************************************** + +HEALTH + +Health is displayed as a vertical red bar on the left hand side of the +screen. As the Predator is wounded, these digits are removed from the +bottom up. When health is low, the Predator should use the MediComp. +The Predator has no Health pick-ups in ALIENS VERSUS PREDATOR. + + +FIELD CHARGE + +All of the Predator's weapons and equipment run off the Predator's +Field Charge, a general measure of power. This is displayed as a +vertical blue bar on the right hand side of the screen. The Predator +can find extremely limited amounts of Field Charge in the Demo. +Field Charge is drained by a number of the Predator's abilities, +which are listed below: + +Healing. The MediComp (q.v.) is expensive to run. +Plasmacaster. This can drain however much is required. +Cloaking. Both a chunk to enter cloak and a small permanent drain. + + +CLOAKING + +The Predator has the ability to 'bend light' around itself. This can +render it almost invisible under most lighting conditions unless it +gives it's position away. Unfortunately, the Xenomorph species does +not use light to detect it's prey, so cloaking is not effective. +Whilst in cloak, the Predator sees the world differently as the +light is processed for his vision. +Entering cloak is costly for Field Charge. + + +VISION MODES + +There are two vision modes available in this demo - Thermal and +Electro-magnetic. Thermal vision shows up Humans as bright red and +yellow heat sources, while the rest of the world is cold and blue. +Electro-magnetic vision displays the Aliens clearly, whilst failing +to pick up on the human targets. Some of the Predator's abilities +depend on picking the correct vision modes. + + + +*********************************************************************** + + 6. PREDATOR WEAPONS + +*********************************************************************** + +WRISTBLADES (slot 1) + +A set of lethal razor-sharp blades mounted on the Predator's right +wrist. Use Primary Fire to perform a quick jab. Use Secondary Fire to +pull back and charge up a high-powered swipe. The Predator may use the +wristblades while cloaked. + + +SPEARGUN (slot 3) + +A high-velocity harpoon-style weapon, this fires a jagged bolt of metal +capable of ripping parts off the Predator's enemies. The extreme power +is tempered by the slow rate-of-fire and the fact that Aliens can easily +survive traumatic injuries. Ammunition is limited and the use of this +weapon de-activates the Predator's cloaking. + + +PLASMACASTER (slot 4) + +The Predator's most effective weapon is computer-controlled from the +wrist console. It has it's own charge meter (found on the Wrist Console +as a small red bar) which displays how much power is contained within +the blast. This can be charged either by Primary Fire and upon release +the bolt is fired, or can have charge stored within it via the use of +Secondary Fire. + +The Plasmacaster is fully auto-tracking, locking onto a target in +seconds as long as it remains within view. The Plasmacaster can only +target enemies if fired from the Predator's correct vision mode for +that species. + + +MEDICOMP (Slot 6) + +Not really a weapon, the MediComp is the Predator's only hope of +regaining health while in combat. It is extremely expensive of +Field Charge and takes some time to use, during which the Predator +is effectively defenseless. It is therefore important to use it during +lulls in combat. + +Primary fire begins the healing sequence. + +Secondary fire activates the Predator's fire-damping abilities should +it unfortunately be caught by a flamethrower or incendiary. This is +far less expensive than a full heal. + + +*********************************************************************** + + 7. CONTACT & LEGAL INFORMATION + +*********************************************************************** + +CONTACT INFORMATION + +For more information, or to communicate with us with regards to this or +any Fox Interactive product, please consult our Worldwide Web site at: + + http://www.foxinteractive.com + +LEGAL INFORMATION + +ALIENS T & c 1986, 1998 Twentieth Century Fox Film Corporation. +PREDATOR T & c 1987, 1998 Twentieth Century Fox Film Corporation. +ALIENS VERSUS PREDATOR T & c 1998 Twentieth Century Fox Film +Corporation. All Rights Reserved. "Aliens," "Predator," "Fox," and +"Fox Interactive" and their associated logos are the property of +Twentieth Century Fox Film Corporation. All Rights Reserved. + +*********************************************************************** + + diff --git a/3dc/AvP_Readme+Credits.txt b/3dc/AvP_Readme+Credits.txt new file mode 100644 index 0000000..b5a9d64 --- /dev/null +++ b/3dc/AvP_Readme+Credits.txt @@ -0,0 +1,278 @@ +*********************************************************************** + Fox Interactive presents + A Rebellion Game +*********************************************************************** + + + Aliens Versus Predator + Predator Demo + + Version 1.0 + Readme File + 10/16/98 + + + +*********************************************************************** + + CONTENTS + +*********************************************************************** + + 1. MINIMUM REQUIREMENTS + 2. DEMO OBJECTIVES + 3. INSTALLATION + 4. GAME CONTROLS + 5. PREDATOR EQUIPMENT + 6. PREDATOR WEAPONRY + 7. CREDITS + + +*********************************************************************** + + 1. MINIMUM REQUIREMENTS + +*********************************************************************** + +P200 MMX PC +Intel or 100% compatible CPU +DirectX supported 3D Accelerator Card +DirectX v.6 (Included on Installation CD) +32Mb RAM +Windows 95 + + +The Aliens Versus Predator Demo is a work in-progress. Thus it is not +fully optimised and configured for lower spec machines. These issues +will be corrected for the full retail version, giving the end user +control over engine and special effect variables ensuring smooth +gameplay over a wide variety of CPUs, accelerator cards and RAM. + + +*********************************************************************** + + 2. DEMO OBJECTIVES + +*********************************************************************** + +As the Predator, you must descend through an Alien-infested Atmosphere +Processor to eliminate the Marines who are defending an APC at the base +of the structure. Your weapons are Wrist-blades, Speargun and shoulder +mounted Plasmacaster. You also possess an emergency medical kit. + + + +*********************************************************************** + + 3. INSTALLATION + +*********************************************************************** + +To install the Aliens Versus Predator Demo, double click on Setup.exe +Follow the onscreen instructions. + +Aliens Versus Predator dynamically streams FMV from your machine's +local hard-drive. This playback is greatly enhanced if the FMV files +are installed on a defragmented directory. We STRONGLY reccomend +de-fragging your hard drive before installing Aliens Versus Predator. + +To de-fragment your drive, either use the Windows95 accessory +'Disk Defragmenter' or any other 3rd party defragmentation utility. + + +*********************************************************************** + + 4. GAME CONTROLS + +*********************************************************************** + +Aliens Versus Predator supports all DirectX compatible controllers. You +must install and set up these controllers before entering the game. + +Other keys and mouse configurations can be defined either from the main +menu screen or from the in-game menus. + +The default keys are: + +UPARROW Forward +DOWNARROW Backward +LEFTARROW Strafe Left +RIGHTARROW Strafe Right +NUMPAD 4 Turn Reft +NUMPAD 6 Turn Right +RIGHT_ALT Strafe +A Look Up +Z Look Down +S Centre View +LEFTSHIFT Walk +RIGHTSHIFT Jump +SPACE Operate +I Toggle Cloaking +Q Next Weapon +W Previous Weapon +PAGEUP Zoom In +PAGEDOWN Zoon Out +L Cycle Vision Modes + +The default mouse settings are full mouselook. +The default mouse buttons are fire primary and fire secondary. + + + +*********************************************************************** + + 5. PREDATOR EQUIPMENT + +*********************************************************************** + +HEALTH + +Health is displayed as a vertical red bar on the left hand side of the +screen. As the Predator is wounded, these digits are removed from the +bottom up. When health is low, the Predator should use the Medicomp. +The Predator has no Health pick-ups in Aliens Versus Predator. + + +FIELD CHARGE + +All of the Predator's weapons and equipment run off the predator's +Field Charge, a general measure of power. This is displayed as a +vertical blue bar on the right hand side of the screen. The Predator +can find extremely limited amounts of Field Charge in the Demo. +Field Charge is drained by a number of the Predator's abilities, +which are listed below: + +Healing. The Medicomp (qv) is expensive to run. +Plasmacaster. This can drain however much is required. +Cloaking. Both a chunk to enter cloak and a small permanent drain. + + +CLOAKING + +The Predator has the ability to 'bend light' around itself. This can +render it almost invisible under most lighting conditions unless it +gives it's position away. Unfortunately, the Xenomorph species does +not use light to detect it's prey, so cloaking is not effective. +Whilst in cloak, the Predator sees the world differently as the +light is processed for his vision. +Entering cloak is costly for Field Charge. + + +VISION MODES + +There are two vision modes available in this demo - Thermal and +Electro-magnetic. Thermal vision shows up Humans as bright red and +yellow heat sources, while the rest of the world is cold and blue. +Electro-magnetic vision displays the Aliens clearly, whilst failing +to pick up on the human targets. Some of the Predator's abilities +depend on picking the correct vision modes. + + + +*********************************************************************** + + 6. PREDATOR WEAPONS + +*********************************************************************** + +WRISTBLADES (slot 1) + +A set of lethal razor-sharp blades mounted on the Predator's right +wrist. Use Primary Fire to perform a quick jab. Use Secondary Fire to +pull back and charge up a high-powered swipe. The Predator may use the +wristblades while cloaked. + + +SPEARGUN (slot 3) + +A high-velocity harpoon-style weapon, this fires a jagged bolt of metal +capable of ripping parts off the Predator's enemies. The extreme power +is tempered by the slow rate-of-fire and the fact that Aliens can easily +survive traumatic injuries. Ammunition is limited and the use of this +weapon de-activates the Predator's cloaking. + + +PLASMACASTER (slot 4) + +The Predator's most effective weapon is computer-controlled from the +wrist console. It has it's own charge meter (found on the Wrist Console +as a small red bar) which displays how much power is contained within +the blast. This can be charged either by Primary Fire and upon release +the bolt is fired, or can have charge stored within it via the use of +Secondary Fire. + +The Plasmacaster is fully auto-tracking, locking onto a target in +seconds as long as it remains within view. The Plasmacaster can only +target enemies if fired from the Predator's correct vision mode for +that species. + + +MEDICOMP (Slot 6) + +Not really a weapon, the Medicomp is the Predator's only hope of +regaining health while in combat. It is extremely expensive of +Field Charge and takes some time to use, during which the Predator +is effectively defenseless. It is therefore important to use it during +lulls in combat. + +Primary fire begins the healing sequence. + +Secondary fire activates the Predator's fire-damping abilities should +it unfortunately be caught by a flamethrower or incendiary. This is +far less expensive than a full heal. + + +*********************************************************************** + + 7. CREDITS + +*********************************************************************** + +REBELLION CREDITS + +Creative Director Jason Kingsley +Technical Director Chris Kingsley + +Lead Programmer Kevin Lea +AI Programmer Chris Fox +Tools Programmer Richard Rice +Additional Programming Jake Hotson + Dave Wall + +Producer Alastair Halsby + +Level Design Julian Breddy + Ed Cookson + Adam Comiskey + Joe Gelder + Alastair Halsby + Tim Jones + +Level Texturemaps Julian Breddy + Ed Cookson + Adam Comiskey + Joe Gelder + Alastair Halsby + Tim Jones + Matthew Riordan + +Character Models +& Animation Ken Turner + Adam Comiskey + +Character Texturemaps Alastair Halsby + Tim Jones + Ken Turner + Adam Comiskey + +Sound Ed Cookson + Tim Jones + Alastair Halsby + +Thanks To: +Patrick Dickinson, George Launchbury, Jake Hempson, John Bryden, +Andy Nixon, Will Davis, Shelagh Lewins, Luke Harman, Dan Mitchell, +Lee Brimmicombe-Wood, Sophie Mobbs, Bernard H. Wood and Paul Topping. + + +FOX INTERACTIVE CREDITS \ No newline at end of file diff --git a/3dc/AvP_Readme.txt b/3dc/AvP_Readme.txt new file mode 100644 index 0000000..664dec3 --- /dev/null +++ b/3dc/AvP_Readme.txt @@ -0,0 +1,226 @@ +*********************************************************************** + Fox Interactive presents + A Rebellion Game +*********************************************************************** + + + Aliens Versus Predator + Predator Demo + + Version 1.0 + Readme File + 10/16/98 + + + +*********************************************************************** + + CONTENTS + +*********************************************************************** + + 1. MINIMUM REQUIREMENTS + 2. DEMO OBJECTIVES + 3. INSTALLATION + 4. GAME CONTROLS + 5. PREDATOR EQUIPMENT + 6. PREDATOR WEAPONRY + + +*********************************************************************** + + 1. MINIMUM REQUIREMENTS + +*********************************************************************** + +P200 MMX PC +Intel or 100% compatible CPU +DirectX supported 3D Accelerator Card +DirectX v.6 (Included on Installation CD) +32Mb RAM +Windows 95 + + +The Aliens Versus Predator Demo is a work in-progress. Thus it is not +fully optimised and configured for lower spec machines. These issues +will be corrected for the full retail version, giving the end user +control over engine and special effect variables ensuring smooth +gameplay over a wide variety of CPUs, accelerator cards and RAM. + + + +*********************************************************************** + + 2. DEMO OBJECTIVES + +*********************************************************************** + +As the Predator, you must descend through an Alien-infested Atmosphere +Processor to eliminate the Marines who are defending an APC at the base +of the structure. Your weapons are Wrist-blades, Speargun and shoulder +mounted Plasmacaster. You also possess an emergency medical kit. + + + +*********************************************************************** + + 3. INSTALLATION + +*********************************************************************** + +To install the Aliens Versus Predator Demo, double click on Setup.exe +Follow the onscreen instructions. + +Aliens Versus Predator dynamically streams FMV from your machine's +local hard-drive. This playback is greatly enhanced if the FMV files +are installed on a defragmented directory. We STRONGLY reccomend +de-fragging your hard drive before installing Aliens Versus Predator. + +To de-fragment your drive, either use the Windows95 accessory +'Disk Defragmenter' or any other 3rd party defragmentation utility. + + +*********************************************************************** + + 4. GAME CONTROLS + +*********************************************************************** + +Aliens Versus Predator supports all DirectX compatible controllers. You +must install and set up these controllers before entering the game. + +Other keys and mouse configurations can be defined either from the main +menu screen or from the in-game menus. + +The default keys are: + +UPARROW Forward +DOWNARROW Backward +LEFTARROW Strafe Left +RIGHTARROW Strafe Right +NUMPAD 4 Turn Reft +NUMPAD 6 Turn Right +RIGHT_ALT Strafe +A Look Up +Z Look Down +S Centre View +LEFTSHIFT Walk +RIGHTSHIFT Jump +SPACE Operate +I Toggle Cloaking +Q Next Weapon +W Previous Weapon +PAGEUP Zoom In +PAGEDOWN Zoon Out +L Cycle Vision Modes + +The default mouse settings are full mouselook. +The default mouse buttons are fire primary and fire secondary. + + + +*********************************************************************** + + 5. PREDATOR EQUIPMENT + +*********************************************************************** + +HEALTH + +Health is displayed as a vertical red bar on the left hand side of the +screen. As the Predator is wounded, these digits are removed from the +bottom up. When health is low, the Predator should use the Medicomp. +The Predator has no Health pick-ups in Aliens Versus Predator. + + +FIELD CHARGE + +All of the Predator's weapons and equipment run off the predator's +Field Charge, a general measure of power. This is displayed as a +vertical blue bar on the right hand side of the screen. The Predator +can find extremely limited amounts of Field Charge in the Demo. +Field Charge is drained by a number of the Predator's abilities, +which are listed below: + +Healing. The Medicomp (qv) is expensive to run. +Plasmacaster. This can drain however much is required. +Cloaking. Both a chunk to enter cloak and a small permanent drain. + + +CLOAKING + +The Predator has the ability to 'bend light' around itself. This can +render it almost invisible under most lighting conditions unless it +gives it's position away. Unfortunately, the Xenomorph species does +not use light to detect it's prey, so cloaking is not effective. +Whilst in cloak, the Predator sees the world differently as the +light is processed for his vision. +Entering cloak is costly for Field Charge. + + +VISION MODES + +There are two vision modes available in this demo - Thermal and +Electro-magnetic. Thermal vision shows up Humans as bright red and +yellow heat sources, while the rest of the world is cold and blue. +Electro-magnetic vision displays the Aliens clearly, whilst failing +to pick up on the human targets. Some of the Predator's abilities +depend on picking the correct vision modes. + + + +*********************************************************************** + + 6. PREDATOR WEAPONS + +*********************************************************************** + +WRISTBLADES (slot 1) + +A set of lethal razor-sharp blades mounted on the Predator's right +wrist. Use Primary Fire to perform a quick jab. Use Secondary Fire to +pull back and charge up a high-powered swipe. The Predator may use the +wristblades while cloaked. + + +SPEARGUN (slot 3) + +A high-velocity harpoon-style weapon, this fires a jagged bolt of metal +capable of ripping parts off the Predator's enemies. The extreme power +is tempered by the slow rate-of-fire and the fact that Aliens can easily +survive traumatic injuries. Ammunition is limited and the use of this +weapon de-activates the Predator's cloaking. + + +PLASMACASTER (slot 4) + +The Predator's most effective weapon is computer-controlled from the +wrist console. It has it's own charge meter (found on the Wrist Console +as a small red bar) which displays how much power is contained within +the blast. This can be charged either by Primary Fire and upon release +the bolt is fired, or can have charge stored within it via the use of +Secondary Fire. + +The Plasmacaster is fully auto-tracking, locking onto a target in +seconds as long as it remains within view. The Plasmacaster can only +target enemies if fired from the Predator's correct vision mode for +that species. + + +MEDICOMP (Slot 6) + +Not really a weapon, the Medicomp is the Predator's only hope of +regaining health while in combat. It is extremely expensive of +Field Charge and takes some time to use, during which the Predator +is effectively defenseless. It is therefore important to use it during +lulls in combat. + +Primary fire begins the healing sequence. + +Secondary fire activates the Predator's fire-damping abilities should +it unfortunately be caught by a flamethrower or incendiary. This is +far less expensive than a full heal. + + +*********************************************************************** + diff --git a/3dc/CD Tracks.txt b/3dc/CD Tracks.txt new file mode 100644 index 0000000..b4c593a --- /dev/null +++ b/3dc/CD Tracks.txt @@ -0,0 +1,77 @@ +;CD track list +;Only lines starting with a # are looked at. +;After the # a list of cd track numbers should be provided +;All track numbers for a give level must appear on one line +;Any symbol can be used to seperate the numbers (Other than ;) , I'm using commas. +;Anything coming after a semicolon is ignored + + + + +;Default tracks for each character. +;Used in multiplayer games , or if no tracks have been assigned +;to a level +# 1,2,3,4,5 ;Marine +# 6,7,8,9,10 ;Predator +# 11,12,13,14,15 ;Alien + +;Cd tracks assigned to each level + +;Marine +# 2 ; AVP_ENVIRONMENT_DERELICT, +# 1 ; AVP_ENVIRONMENT_COLONY, +# 4 ; AVP_ENVIRONMENT_INVASION, +# 3 ; AVP_ENVIRONMENT_ORBITAL, +# 5 ; AVP_ENVIRONMENT_TYRARGO, +# 5 ; AVP_ENVIRONMENT_TYRARGOHANGAR, + +;Predator +# 7 ; AVP_ENVIRONMENT_WATERFALL, +# 6 ; AVP_ENVIRONMENT_AREA52, +# 8 ; AVP_ENVIRONMENT_VAULTS, +# 10 ; AVP_ENVIRONMENT_FURY161, +# 9 ; AVP_ENVIRONMENT_CAVERNS, +# 9 ; AVP_ENVIRONMENT_CAVERNSEND, + +;Alien +# 11 ; AVP_ENVIRONMENT_FERARCO, +# 12 ; AVP_ENVIRONMENT_TEMPLE, +# 13 ; AVP_ENVIRONMENT_GATEWAY, +# 14 ; AVP_ENVIRONMENT_ESCAPE, +# 15 ; AVP_ENVIRONMENT_EARTHBOUND, + +;Multiplayer part 1(ignored , but leave the same number of #'s) +# ; +# ; +# ; +# ; +# ; + +;Alien bonus +# ; AVP_ENVIRONMENT_INVASION_A, +# ; AVP_ENVIRONMENT_DERELICT_A, +# ; AVP_ENVIRONMENT_TYRARGO_A, +# ; AVP_ENVIRONMENT_FURY161_A, +# ; AVP_ENVIRONMENT_CAVERNS_A, + +;Predator bonus +# ; AVP_ENVIRONMENT_INVASION_P, +# ; AVP_ENVIRONMENT_TYRARGO_P, +# ; AVP_ENVIRONMENT_TEMPLE_P, +# ; AVP_ENVIRONMENT_ESCAPE_P, +# ; AVP_ENVIRONMENT_EARTHBOUND_P, + +;Marine bonus +# ; AVP_ENVIRONMENT_WATERFALL_M, +# ; AVP_ENVIRONMENT_VAULTS_M, +# ; AVP_ENVIRONMENT_FERARCO_M, +# ; AVP_ENVIRONMENT_TEMPLE_M, +# ; AVP_ENVIRONMENT_GATEWAY_M, + +;Multiplayer part 2(ignored , but leave the same number of #'s) +# ; +# ; +# ; +# ; +# ; +# ; diff --git a/3dc/CREDITS.txt b/3dc/CREDITS.txt new file mode 100644 index 0000000..7c69f3f --- /dev/null +++ b/3dc/CREDITS.txt @@ -0,0 +1,340 @@ + + + +}Fox Interactive Presents + + + +}Aliens Versus Predator + +}Gold Edition + + +}Fox Interactive +}------------- + +Producer|David Stalker + +Senior Associate Producer|Chris Miller + +Associate Producer|Aaron Blean + + +}Fox QA Department + +QA Manager|David Ortiz +QA Lead|Igor Krinitsky +QA Co-Lead|Chris Wilson +Testers|Arabian +|Aron Ahles +|Ken Anderson +|Eric Asevo +|Sweet Billy +|Ben Borth +|Pete Cesario +|Francis Choi +|Kristian Davila +|Matt Dell +|Ryan Dowling +|Michael Dunn +|Tim Hall +|Tim Harrison +|Judd Hollander +|Kevin Huynh +|Cris Lee +|Jeremy Luyties +|Red Magpantay +|Kerry Marshall +|Young Park +|Kyle Peschel +|Harish Rao +|Don Sexton +|Gabe Slater +|Jeff Tatman +|Luke Thai +|Tim Tran +|Daan Wisehart +|Sung Yoo +|Brian Zenns + + + + +}Rebellion +}------- + +Creative Director|Jason Kingsley + +Technical Director|Chris Kingsley + +Senior Producer|Mark Eyles + +Production Manager|Graeme Williams + +Technology Manager|Kevin Lea + +Producer & Lead Artist|Tim Jones + +Network Code & Tools Programmer|Richard Rice + + + +Art|Julian Breddy +|Ed Cookson +|Dominic Jeffery +|Tim Jones +|Ken Turner + + + +Sound|Ed Cookson + +Additional Sound|Julian Breddy +|Dominic Jeffery +|Tim Jones + + +Thanks to|Al Halsby +|Chris Fox +|Jessica Sharp +|Nadia Cocklin +|Harry Harris +|April Chung +|Anna Floyer +|Siobhan Boughton +|Helen Szirtes +|Christian Russell +|Phil Moss +|Matt Black +|The Special K Massive (Big up stylee!) + + +}Gold Edition FMVs + + +Cast|Ed Cookson +|Aeron Guy +|Mike Healey +|Ben Jones +|Tim Jones +|Chris Kingsley +|Ed Niblett +|Ken Turner + +Creative Director and Lighting|Jason Kingsley + +Direction|Ed Cookson +|Tim Jones +|Ken Turner + + +Editing and Sound Effects|Ed Cookson +|Ken Turner + +Special Effects|Ken, Ben, Ed C and Tim + +Thanks to|Everyone at Rebellion who gave up their weekend + + + + + + + + + +}Aliens Versus Predator + + +}Fox Interactive +}------------- + + +Producer|David Stalker + +Associate Producer|Chris Miller + +Music Composition|Rich Ragsdale + +Sound Effects|Jered C. Miller + + +}Fox QA Department + +QA Manager|Mike Schneider +QA Lead|Aaron Blean +Testers|Seth Roth +|Ken Anderson +|Eric Asevo +|Pete Cesario +|Ryan Dowling +|Michael Dunn +|Tim Hall +|Igor Krinitsky +|Red Magpantay +|Sweet Billy +|Paul Pawlicki +|Harish Rao +|Tim Ramage +|Nick Stecher +|Jeff Tatman +|Tim Tran +|Sung Yoo +|Kristian Davila + + + +}Big Shouts out to: + +The unsung folks at Fox|Paul Provenzano +|Mark Dawson +|Dave Shaw +|Alan Alder +|Brian Thomas +|Melissa Totten +|Ellen Gameral +|Jamie Samson +|Michele Birkner +|Priscilla Bourbonnais +|Mike Arkin +|Andrea Griffiths +|Simon Etchells + + +The folks who made the movies|Ridley Scott +|H.R. Giger +|James Cameron +|John McTiernan +|James Horner +|Jerry Goldsmith +|Elliot Goldenthal +|Stan Winston +|and many other talented individuals + + +}Rebellion +}------- + + +Creative Director|Jason Kingsley + +Technical Director|Chris Kingsley + +Producer & Lead Artist|Alastair Halsby + +Engine Code & Lead Programmer|Kevin Lea + +Network Code & Tools Programmer|Richard Rice + +AI Programmer|Chris Fox + + + +}Additional Programming + +Sound|Dave Wall +Tools|Jake Hotson +AI|Alex Thomson + + + +Art|Julian Breddy +|Ed Cookson +|Al Halsby +|Tim Jones + + + +Additional Art|Ken Turner +|Matthew Riordan +|Adam Comiskey +|Kevin Lea + + + +Lead Animator & Character Design|Ken Turner + +Additional Animation|Adam Comiskey + +Character Art|Al Halsby +|Tim Jones +|Julian Breddy + + + + +Sound|Ed Cookson + +Additional Sound|Tim Jones +|Will Davies +|Al Halsby + + + +Male Voice Talent|Julian Breddy +|Ken Turner +|Dominic Jeffrey + + +Female Voice Talent|Becky Kneubuhl +|April Chung +|Nadia Cocklin + + + +Rebellion Thanks:|Jessica Sharp +|Patrick Dickinson +|George Launchbury +|Roxby Hartley +|Jake Hempson +|John Bryden +|Andy Nixon +|Shelagh Lewins +|Luke Harman +|Dan Mitchell +|Lee Brimmicombe-Wood +|Sophie Mobbs +|Bernard H. Wood +|Paul Topping + + + + + +}Mondo Media +}----------- + +Art Director|Marco Bertoldo + +Producer|Liz Stuart + +Senior Producer|Vivian Barad + +3D Artists|Brittnal Anderson +|Robert Jeffery +|Kelley Lamsens +|Jeanne Littooy +|Manuel Marquez +|Art Matsuura + +Storyboard Artist|Rhode Montijo + + + + + + + + + + + + + + + + + + + +# diff --git a/3dc/ENGLISH.TXT b/3dc/ENGLISH.TXT new file mode 100644 index 0000000..9f7f0e9 --- /dev/null +++ b/3dc/ENGLISH.TXT @@ -0,0 +1,4252 @@ +REBINFF2 +#AVP - please leave this line +# +# Reserved space for level-specific messages (e.g. mission briefings, goals, etc) +# Here so that there will be fixed numbers available for level designers to assign +# to things. +# +# This means, for example, that an artist can attach string 34 somewhere +# in the tools system, and be sure that the meaning of string 34 will be fixed. +# +# (Artists can decide amongst themselves on how to allocate numbers) + +# +# Genshd1 +"COM: Power is back on-line. Activate switch to open door." + +# +# Genshd1 +"DUMMY LEVEL-SPECIFIC MSG 002" + +# +# Genshd1 +"DUMMY LEVEL-SPECIFIC MSG 003" + +# +# Genshd1 +"DUMMY LEVEL-SPECIFIC MSG 004" + +# +# Genshd1 +"DUMMY LEVEL-SPECIFIC MSG 005" + +# +# Genshd1 +"DUMMY LEVEL-SPECIFIC MSG 006" + +# +# GENSHD1 objective#3, message when completed: +"COM: Manual bypass collected." + +# +# Genshd1 +"DUMMY LEVEL-SPECIFIC MSG 008" + +# +# Genshd1 +"COM: Manual bypass in operation." + +# +# Genshd1 +"COM: PDT is near - look around for a small device." + +# +# Genshd1 +"Warning! Safety system failure." + +# AREA 52 MESSAGES START HERE +# + +# +# AREA52 +"Caution! Safety system active." + +# +"Door welded shut." + +# +"Gain access to base." + +# +"Base accessed. Now locate controls to lower bridge." + +# +"Device unlocks door." + +# +"Door unlocked." + +# +"Entered lift." + +# +"There is some field charge in here." + +# +"Bridge down. Now access second security level." + +# +"Platform lift." + +# +"Device lowers bridge." + +# +"There is the ship. Locate access to hangar." + +# +"Entered second security level. All doors have been locked." + +# +"Attention all units! The Predator has accessed level four. All doors have been secured. Stay on maximum alert. This thing must be stopped NOW." + +# +"This door leads to the second security level." + +# +"All units! We have a system error. Xenomorph specimens are on the loose! Get to the ops area now! Oh shit, they're in here!" + +# +"Hello.hello? Is there anyone alive down there? Well we've shut down the power and we think we can stop them if we..." + +# +"Doors on this level have been unlocked. Gain access to the third security level." + +# +"A sentry gun. Find another way around." + +# +"Access to the third security level denied! Find another way to access the hangar." + +# +# +#ONE DERELICT MESSAGE: + +# +"COM: Don't worry about those weird-looking eggs, marine. They've been sterilized." + +# +# +#BACK TO AREA52 MESSAGING: +# +# + +# +"This looks like a challenging jump." + +# +"Kill all threats and access the ship." + +# +"Attention all base units! The Predator has infiltrated the installation. Now it's up to us. Keep it cool and watch each others' backs." + +# +"Marines! Security level two has been breached. All doors are being sealed. Stand your ground, Marines, let's bag this thing." + +# +"What the Hell's going on out there? We've lost sight of the intruder. All units report immediately!" + +# +"To retain honor amongst your clan your electrical weapons have been disabled." + +# +"DUMMY LEVEL-SPECIFIC MSG 039" + +# +"You are next to a laundry chute." + + +# GATEWAY BEGINS HERE +# + + +# +"The vessel has docked, a hive presence can be felt, seek it." + +# +"Destroy the power sources to the fans." + +# +"Blades must be stopped." + +# +"Hive are near, chambers are fresh with their scent." + +# +"Join us." + +# +"Hive trapped behind powered bars." + +# +# END OF GATEWAY +# +# MORE COLONY (FROM TEXTSTRING 162) +# +# +"Welcome to the main Colony base, Marine. Looks like the colonists shit a brick and pulled out. There's an APC beyond the Main Gate. But the power's shut down. You'll have to open the gate remotely. Find the Generator Shed, turn on the power, and await further instructions." + +# +"COM: You made it marine, let's get this APC prepped and moving." + +# +# END OF COLONY MESSAGING + +# +"Mission Accomplished" +# +# +# +# +# +# INVASION MESSAGES BEGIN HERE +# +# +# +"Orders from above, you MUST shut down the cooling system before they'll authorize an airlift. You need to power down the five, repeat FIVE, ventilation fans, and make your way through the Processor to the landing platform. I'll be in radio contact." + +# +"" + +# +"COM: Bad news Private; The Company says you've gotta turn off the ventilation fans before they'll authorize an evac." + +# +"COM: OK Marine. Your location is directly under one of the ventilation fans. Blueprints say the pressure wheel's a level above you. Don't waste time!" + +# +"COM: Keep it sharp Private; There's a cooling fan directly ahead to the right." + +# +"Nice work, Private. Cooling systems degraded by twenty percent. Looks like the direct route is closed off. You'll have to go through the substructure and make your way down." + +# +"COM: According to the computer, The route is closed off between you and the local control room. You'll need to go via the sub-structure. Make your way down." + +# +"COM: Looks like the bugs got to the pressure hose for this door. There's a local pressure cylinder nearby. Find it and activate it!" + +# +"COM: Good going - pressure door reactivated. Company reps say they're prepping a dropship for you. Guess we gotta believe em...." + +# +"COM: Don't waste time - The Processor's fitting to blow real soon now. Find the lift upwards A.S.A.P." + +# +"COM: Looks like you're in a subsidiary fuel room of some kind. Good. Keep it tight and keep climbing." + +# +"COM: Pull back Private! You're heading into the ventilation fans! You'll be mince!" + +# +"COM: Private, you need to access the door opposite the stairs." + +# +"COM: Proceed down to Ventilation Control." + +# +"Okay, Private. Two fans down, three to go. A dropship's being prepared for you right now." + +# +"COM: Proceed left into the local Control Room." + +# +"COM: There's a pressure wheel in the viewing gallery." + +# +"The cooling towers are starting to vent. I'm reading serious power surges here. Keep it up. Two more fans to go." + +# +"COM: Good work Marine, just one more fan." + +# +"Great work, Private! Cooling system shutting down. But I wouldn't stick around if I were you - it's gonna start getting real hot down there. The airship's coming down but you don't have that much time. Get your ass up to the landing platform. I mean NOW !" + +# +"COM: Good news, Marine - the Dropship's on its way. Get to the landing platform." + +# +"COM: Remember your safety training and stand well back from the dropship. It ain't safe underneath it." + +# +# +# +#MORE AREA 52 MESSAGES START HERE +# +# +# +# + +# +"You should shut off that alarm." + +# +"A security pass is needed to access the second level." + +# +"You have picked up the second level security pass." + +# +#AREA 52 MESSAGES END HERE +# + +# +# +# +#VAULTS MESSAGES START HERE +# +# +# +# + +# +"Proceed deeper into the installation." + +# +"It is impossible to get up there." + +# +"All doors have been locked. Find way to proceed." + +# +"Destroy mainframe control system to unlock doors. There are four mainframe terminals in the area." + +# +"Mainframe terminals still active." + +# +"Two mainframe terminals still active." + +# +"One mainframe terminal still active." + +# +"Doors are unlocked. Continue with hunt." + +# +"Holding pen was opened when mainframe was destroyed. Life-forms being held in base are now loose." + +# +"This way leads deeper into installation." + +# +"Systems shut down by humans. All doors locked. Must find manual override switch in control room attached to xenoborg-holding room." + +# +"There is another way into this room." + +# +"A xenoborg-holding room" + +# +"A facehugger-holding room." + +# +"An operating room." + +# +"Central lift is controlled through here." + +# +"Something has burnt hole in door." + +# +"Security pass needed." + +# +"This lift needs to be activated from the nearby control room." + +# +"Loose facehuggers about." + +# +"A control room." + +# +"Installation systems reactivated." + +# +"DUMMY LEVEL-SPECIFIC MSG 097" + +# +"Where humans were holding xenomorphs." + +# +"Fellow hunter has been moved from cell to experimentation chamber." + +# +#Vaults messages continued at levelmsg_125 +# +# + +# Derelict messages begin here: +# +# +"Proceed through the tunnels and rendezvous with Op 3. They'll escort you out. We've had some light failures so you may need to use your image intensifier." + +# +"Look alive, Private! You're in some serious shit. We're bugging - out now! Level 3 doors are already locked. So Get your ass to the Comm room. I'll brief you from there." + +# +"COM: Security systems have locked down the doors. There should be a manual override somewhere." + +# +"Okay, Private, We've got a security breach. Move your ass to the airlock. You've gotta go through the egg lab first. Open the blast doors by pulling on the override switch. And don't worry about those eggs, they've been sterilized. Now move it!" + +# +"COM: OK marine, you should be near the airlock. Activate it and cycle through." + +# +"COM: By the way Private, company says you ain't seeing anything down there, so don't waste time looking." + +# +"Okay private We've lost contact with the Ops team. Careful, we've got some weird signals. Something's moving down there." + +# +"COM: Nice to see you're awake now, marine!" + +# +"God damn it! We're getting our asses kicked. Looks like you're on your own. Take the underground access duct to the main colony. Try using the override switch for the observation door. Just don't get yourself killed." + +# +"COM: Right son, this is where it gets tricky. Most doors are locked - you need to find the override before you can proceed." + +# +"DUMMY LEVEL-SPECIFIC MSG 110" + +# +"COM: That's it! Now get your ass down to the main research floor." + +# +"COM: Don't panic marine - you need to proceed carefully inside the artifact. There's a tunnel through it to the access ducts." + +# +"IN CASE OF EMERGENCY BREAK GLASS" + +# +"Thought we lost you back there. Okay, you're almost to the colony access duct. Stay sharp!" + +# +"COM: The suits say you shouldn't be looking at that - I say get a move on and quit wasting time." + +# +# EARtHBOUND MESSAGE BEGINS HERE and some new gateway ooer a bit scruffy +# + +# +"Locked." + +# +"Hive eggs have been taken, find them." + +# +"Caution, the fans need to be stopped but drone guns guard the power source." + +# +"Feel power running from lower chambers." + +# +"Attention dock personnel! The R&D Tower has been breached. We are evacuating transit sections 1, 2, and 3. Security teams, remain at your posts. Everyone, please follow standard Company emergency procedures." + +# +"Lebowski here? How you doing with those egg specimens? Get 'em down to Dock 4 ASAP. The Earthbound ship is ready to dock and load." + +# +"Hive eggs are nearby." + +# +"Kill the Predator threat." + +# +"Join the eggs; they will need protection on the long passage to the human homeworld." +# +# END OF EARTHBOUND MESSAGING +# +#Vaults messages continued from levelmsg_099 +# +# + +# +"Fellow warrior has been here." + +# +"Human office. Security pass in here." + +# +"Security pass collected." + +# +"DUMMY LEVEL-SPECIFIC MSG 128" + +# +"DUMMY LEVEL-SPECIFIC MSG 129" + +# +"Defense system de-activated." + +# +"Fellow hunter genetically defiled! Slay the abomination! Release your brother's spirit!" + +# +"Activate the lift." + +# +"Central lift is now operational." + +# +"Door needs security pass." + +# +"A lift." + +# +"Get back inside ship." + +# +# +#VAULTS MESSAGES CONTINUES AT LINE 190 +# +# + + +# +# +# NOST03 MESSAGES BEGIN HERE +# +# + +# +"COM: Security Pass picked up." + +# +"This door leads to the main deck." + +# +"Sabotage the ship and kill all crew." + +# +"Attention crew. Mother has detected an alien lifeform onboard this ship. Garage Deck. At present time, there is no way it can access the other decks. Now I know some of you will be concerned. But rest assured every step is being taken to protect the ship and her crew. Captain out." + +# +"Attention crew. The Alien has reached the main deck. There's no need to panic. I repeat, NO need to panic. The area is monitored. And Mother is confident that the xenomorph can be contained. Return to your stations and remain calm. Captain out." + +# +"Attention crew. I'm getting garbled reports and false sightings. This is of no use to Mother or myself. The last reliable sighting indicates the Alien may have entered our ventilation system. But I need confirmation. I'm also authorizing the use of all weapons. I need you all to be vigilant - our lives may depend on it. Captain out." + +# +"Sentry is guarding end-vents." + +# +"Attention, This damned Alien can and will be stopped! There's only one of them and it only takes one of us to kill it! We have the brains, we have the guns, so let's DO THIS! Go out there, watch your backs, and do your jobs. Captain out. This is hopeless." + +# +"Jones? It's me. I've selected a handful of synthetics to pilot the escape shuttle. At least a few of us might make it out of here alive. I need you to secure the shuttle . Got that? If we're gonna get out of here we're gonna NEED that shuttle!" + +# +"The brain of the ship is vulnerable, it must be destroyed." + +# +"This ship is dying, join the escapees." + +# +"Join the escaping vessel." + +# MORE NOST03 MESSAGES AT 195 +# + +# +"DUMMY LEVEL-SPECIFIC MSG 149" +# +# Station Messages begin here +# +# +"COM: Welcome to the orbital platform USS Odobenus. Please proceed through the airlock for decontamination." + +# +"COM: Decontamination complete. Have a nice day." + +# +"DUMMY LEVEL-SPECIFIC MSG 152" + +# +"COM: You are now located in the secondary residential area." + +# +"This just keeps getting better. We got hostiles in a parallel orbit - looks like they're gonna dock with the platform. The rest of us have pulled back to the cruisers. You need to get down to the living quarters. And one more thing: the Company has activated a new defense system. I don't have any specs on it yet. All know is that it's new and nasty as Hell. So watch yourself." + +# +"COM: You'd better watch yourself, Private - The Company rep's just powered up the automated defenses, including some really nasty experimentals. They don't seem to want any security breaches." + +# +"COM: Marine - there's an escape capsule at the end of each hydroponics section. Get to the algae tanks and the rest should be obvious." + +# +"COM: Intruder detected in local control section. Defenses at maximum." + +# +"Bad news. The hostiles have destroyed all the docking arms, so the only way off the platform is in one of the escape capsules. They're located at the end of the hydroponics garden. But in order to get there, you have to get passed this new defense system. Details are still classified but what I do know is that it's based on some kind of laser technology. Whatever you do, don't let it get a laser lock on you!" + +# +"DUMMY LEVEL-SPECIFIC MSG 159" + +# +"COM: You are now located in the hydroponic gardens." + +# +"COM: Here's a hint, marine - the defenses are laser-targeted. If they get a lock-on, be somewhere else." + +# +# +#COLONY MESSAGE BEGINS HERE +# +# + +# +"DUMMY LEVEL-SPECIFIC MSG 162" + +# +"DUMMY LEVEL-SPECIFIC MSG 163" + +# +"COM: This door isn't gonna work until the power is back on-line." + +# +"COM: This leads to the Generator Shed." + +# +"COM: Activate all 4 Generators." + +# +"All right, Private. Main Base is back on-line. Now get inside the Colony Building and find Ops room, Level 3. You'll be able to unlock the Main Gate from there." + +# +"You're on the home stretch. Stay focused, Marine get across that field and get to the APC." + +# +"COM: Control Room - Nice going marine - you need to activate all 5 switches." + +# +"Damn! Did you throw all FIVE switches? Well the Gate's locked down tight. You need a bypass kit. The Engineer had one - it might still be on him. His body is in Medlab on Level 2.Got that? Level 2." + +# +"COM: Main Base doors are waking up." + +# +"DUMMY LEVEL-SPECIFIC MSG 172" + +# +"COM: The Main Gate." + +# +"COM: The APC is waiting for you." + +# COLONY MESSAGING CONTINUES AT TEXTSTRING 047 +# +#Caverns messaging. +# +# + +# +"All doors are locked." + +# +"Need to access underground marine research posts." + +# +"Door opened by device." + +# +"The door above has opened." + +# +"You need to get down here, but the lift is not going to work." + +# +"Leads to the underground hive network." + +# +"Door opened elsewhere." + +# +"Doors controlled here." + +# +"Doors have opened." + +# +"DUMMY LEVEL-SPECIFIC MSG 184" + +# +"The Queen is close. Good prize for hunter." + +# +"Praetorian guards!" + +# +"Now to fulfill your highest honor. Hunt and kill the Queen." + +# +"COM: Congratulations, Sir; The destruction sequence has been terminated, but you must kill that predator." + +# +"The base will self-destruct in T-10 seconds." + +# +"The base will self-destruct in T-1 minute." + +# +"The base will self-destruct in T-30 seconds." + +# +"The base will self-destruct in T-5 seconds." + +# +"Destruction initiated." + +# +"Self-destruct sequence terminated." + +# +# EXTRA NOST03 MESSAGES +# + +# +"DUMMY LEVEL-SPECIFIC MSG 195" + +# +"DUMMY LEVEL-SPECIFIC MSG 196" + + +# +# EXTRA VAULTS MESSAGES +# + +# +"COM: You had better hurry up. The aliens will reach the upper communications level in less than a minute." + +# +"COM: Sir, we have a problem. The predator that infiltrated the base has triggered the base's self-destruct. We have just had word that one of the company heads is still in the base. You must destroy the four liquid tanks in the basement to terminate the sequence. You have less than a minute!" + +# +"COM: Sir, we have another problem. We have learned that the company head is in the upper communications level alone and unarmed. There appear to be some loose xenomorphs heading that way. You must locate him before it is too late." + +# +"COM: The aliens have reached the upper communications level, sir. You have but a few seconds!" + + +# +# Sulaco messages begin here +# + + + +# +"Here's the latest. Tyrargo is overrun with Aliens, and it's gonna be tough going. So watch your back." + +# +"COM: Don't like the look of this - better watch that motion tracker." + +# +"COM: C'mon, Private! Ain't you got more important things to do than play about with that crane?" + +# +"COM: Good, that's the switch - the hangar door is now unlocked." + +# +"The crew has already bugged out. Don't bother looking for survivors. Make your way through the mess hall to engineering." + +# +"COM: Door unlocked." + +# +"COM: No time ta freshen up!" + +# +"COM: Find the vents to access the mess hall - from there you can reach the reactor core." + +# +"COM: Grating destroyed." + +# +"COM: Platform lift activated." + +# +"The doors to the reactor core are sealed. To open 'em, you'll have to re-activate the cooling systems. Once you're through, open the emergency exit and get outta there!" + +# +"COM: Cooling systems activated." + +# +"All right Marine, Thank you for your services, Private, you've been most.useful. However, I have to inform you that the Company is unable to evacuate you at this time.you understand it's nothing personal." + +# +"Not much time so listen up, I'm opening the hangar door. Hurry, Marine! Move your ass outta there!" + +# +"COM: This lift must be activated." + +# +"COM: End." + +# +"Three officers on board. Kill them." + +# +"Use airducts to avoid sentry guns." + +# +"Officer killed." + + +# +# +# Temp E3demosp messages +# +# +"Warning. A predator has entered the base." + +# +"Base self-destruct initiated. T-5 minutes and counting." + +# +"4" + +# +"3" + +# +"2" + +# +"1" + +# +"Base atomized. Have a nice day." + +# +# +# More Vaults-Bonus level massages. +# +# + +# +"COM: The head of the company has been killed. This won't look good on your resume. You've failed in your mission!" + +# +"COM: Well done, Sir. The area has been secured. The company wishes to express its deepest gratitude. You have an extra half day's leave." + +# +"COM: OK, Sir. The level is sealed off. Now you must clear the area of aliens and protect the head of the company." +# + +# +#TEXT FOR ALIEN BONUS TYRARGO LEVEL +# + + +# +"Watch out for the predator!" + +# +"DUMMY LEVEL-SPECIFIC MSG 231" + +# +"DUMMY LEVEL-SPECIFIC MSG 232" + +# +"DUMMY LEVEL-SPECIFIC MSG 233" + +# +"DUMMY LEVEL-SPECIFIC MSG 234" + +# +"DUMMY LEVEL-SPECIFIC MSG 235" + +# +"DUMMY LEVEL-SPECIFIC MSG 236" + +# +#MORE TEXT FOR CAVERNS +# + + +# +"DUMMY LEVEL-SPECIFIC MSG 237" + +# +"Unit three-two. We've collected specimen batch twenty-seven. Ready to pull out." + +# +"All units. The Predator is heading for the breeding ground. I don't know what it's planning but it must not reach the hive." + +# +#TEXT FOR ALIEN BONUS DERELICT LEVEL +# + + + +# +"The ship must be reclaimed from the creatures that have desecrated it. Kill the company heads that have sealed themselves in the base." + +# +"You have killed one company head, but there is one still alive." + +# +"Mission accomplished. An evacuation has been ordered. The Hive is safe again!" + +# +"DUMMY LEVEL-SPECIFIC MSG 243" + +# +#TEXT FOR ALIEN BONUS CAVERNS LEVEL +# + + +# +"QUEEN: Worker, a predator is approaching the hive. Find it and kill it." + +# +"QUEEN: The hive is now safe." + +# +"All containment doors have been secured." + +# +"Containment doors have opened." + +# +"DUMMY LEVEL-SPECIFIC MSG 248" + +# +# A VAULTS MARINE BONUS MESSAGE +# + + +# +"COM: You may want to find Russell's minigun to help you with that predator. Russell's last com came from the predator-holding pen. " + +# +# WATERFALL MESSAGES BEGIN HERE +# + +# +"Fight through defenses to access human's research facility." + +# +"Jump here." + +# +"Door activates below." + +# +"Door unlocks." + +# +"Unit 2, report in. Report in Unit 2. Unit 2, do you copy? Damn! His comm must be down." + +# +"There is another way around." + +# +"Second security area." + +# +"All units report casualties. Repeat, all units report now! How bad are the casualties, people?" + +# +"Door locked." + +# +"Find way onto gantries above." + +# +"Must be some important traffic coming through this way." + +# +"Okay, Marines. We've got another Predator creature in here. Patrol in groups. Do NOT allow yourselves to be separated. We handled the last one and we can do it again. Stay frosty, Marines!" + +# +"Platform lift activated." + +# +"Entrance to research facility." + +# +"Airlock activated." + +# +"Dead." + +# +# TEXT FOR THE MARINE WATERFALL BONUS LEVEL +# + +# +"COM: Intruder Alert! Protect the base." + +# +"COM: Platform lift activated." + +# +"COM: Door unlocked." + +# +"COM: Lights activated." + +# +"COM: Sentry gun de-activated." + +# +"COM: A predator!" + +# +"DUMMY LEVEL-SPECIFIC MSG 272" + +# +"DUMMY LEVEL-SPECIFIC MSG 273" + +# +"DUMMY LEVEL-SPECIFIC MSG 274" + +# +"DUMMY LEVEL-SPECIFIC MSG 275" + +# +"DUMMY LEVEL-SPECIFIC MSG 276" + +# +"DUMMY LEVEL-SPECIFIC MSG 277" + +# +"DUMMY LEVEL-SPECIFIC MSG 278" + +# +"DUMMY LEVEL-SPECIFIC MSG 279" + +# +"DUMMY LEVEL-SPECIFIC MSG 280" + +# +"DUMMY LEVEL-SPECIFIC MSG 281" + +# +"DUMMY LEVEL-SPECIFIC MSG 282" + +# +"DUMMY LEVEL-SPECIFIC MSG 283" + +# +"DUMMY LEVEL-SPECIFIC MSG 284" + +# +"DUMMY LEVEL-SPECIFIC MSG 285" + +# +"DUMMY LEVEL-SPECIFIC MSG 286" + +# +"DUMMY LEVEL-SPECIFIC MSG 287" + +# +"DUMMY LEVEL-SPECIFIC MSG 288" + +# +"DUMMY LEVEL-SPECIFIC MSG 289" + +# +"DUMMY LEVEL-SPECIFIC MSG 290" + +# +"DUMMY LEVEL-SPECIFIC MSG 291" + +# +"DUMMY LEVEL-SPECIFIC MSG 292" + +# +"DUMMY LEVEL-SPECIFIC MSG 293" + +# +"DUMMY LEVEL-SPECIFIC MSG 294" + +# +"DUMMY LEVEL-SPECIFIC MSG 295" + +# +"DUMMY LEVEL-SPECIFIC MSG 296" + +# +"DUMMY LEVEL-SPECIFIC MSG 297" + +# +# FURY 161 MESSAGES BEGIN HERE +# + +# +"Everyone's dead up here! Everyone! I'm the last. The escape vehicle is primed and I'm getting the Hell out!" + +# +"Report in, section 3. Section 3? We've spotted an unidentified craft on approach. Headed straight for you! Could be a Predator ship. I suggest you get your ass out of their immediately." + +# +"Area overrun by aliens. Good hunting." + +# +"Door locked." + +# +"Use platform lift on left." + +# +"Follow gantries around to switch at top." + +# +"Door unlocks." + +# +"Pipe looks weak...." + +# +"Fan deactivated." + +# +"Must activate all switches in room." + +# +"Access lower levels via elevator." + +# +"Mess hall." + +# +"Morgue." + +# +"Human emergency escape vehicle has been salvaged." + +# +"Killed it." + +# +"Accessed lead smelting plant. Watch out for humans." + +# +"Don't step in molten lead." + +# +"Get into ship." + +# +"Dead." + +# +# GOODNESS GRACIOUS ME IT'S THE ALIEN VERSION OF FURY161 MESSAGES +# + +# +"Deactivate sentry guns and hunt human fodder." + +# +"Sentry gun deactivated." + +# +"Kill the predator!" + +jules bonus level messages + +BREAKOUT_P + +# +"The Predator race has been defiled, restore honor - kill the Commanding Officer." + +# +"The captive Aliens have broken loose and overrun the Base." + +# +"Destroy the substations to stop the fans." + +# +"The Officer is dead, honor is restored." + +STAT101_M + +# +"COM: ALERT!!! Aliens are loose in the base, pullback to the bottom deck for immediate evac." + +# +"COM: You have made it, Marine." + +NOST03_M + +# +"COM: This ship is dead and infested - your mission is to power up the Mother Module." + +# +"COM: Uh Oh - looks like power is off again - you will have to trigger local Generators so keep your eyes peeled." + +# +"COM: The Mother Module requires a Security Pass - get searching Marine." + +# +"COM: Mother Module is powering up - mission accomplished." + +TEMPLE_M + +# +"COM: You're lucky to be alive, Private - the temple is outta control! Keep headin' up to reach evac." + +# +"COM: Local generator needs to be powered to budge this lift." + +# +"COM: Top access is blocked - override it by destroyin' the four local sub-stations." + +# +"COM: The evac craft are in sight. Looks like ya made it!" + +END OF JULES BONUS MESSAGES + +# +"DUMMY LEVEL-SPECIFIC MSG 334" + +# +"DUMMY LEVEL-SPECIFIC MSG 335" + +# +"DUMMY LEVEL-SPECIFIC MSG 336" + +# +"DUMMY LEVEL-SPECIFIC MSG 337" + +# +"DUMMY LEVEL-SPECIFIC MSG 338" + +# +"DUMMY LEVEL-SPECIFIC MSG 339" + +# +"DUMMY LEVEL-SPECIFIC MSG 340" + +# +"DUMMY LEVEL-SPECIFIC MSG 341" + +# +"DUMMY LEVEL-SPECIFIC MSG 342" + +# +"DUMMY LEVEL-SPECIFIC MSG 343" + +# +"DUMMY LEVEL-SPECIFIC MSG 344" + +# +"DUMMY LEVEL-SPECIFIC MSG 345" + +# +"DUMMY LEVEL-SPECIFIC MSG 346" + +# +# TEMPLE MESSAGES BEGIN HERE +# + +# +"The labs are locked. Protect the security systems. We can't let the xenomorphs disrupt the experiments." + +# +"All units! Lab integrity has been compromised. Get up there and take out that xenomorph!" + +# +"What the Hell's going on down there? Don't let it get to the Hive - we can't contain it there!" + +# +"Our temple has been violated. Eliminate intruders and seal the entrances." + +# +"DUMMY LEVEL-SPECIFIC MSG 351" + +# +"Destroy the supports and block the fuel pipes for the fire." + +# +"Fire extinguished. Access lower temple areas." + +# +"Destroy security systems and access laboratories." + +# +"There is an easier way around." + +# +"Bypass the sentry guns via these tunnels." + +# +"Laboratory One unlocked. Destroy equipment and prevent further experiments." + +# +"Laboratory Two unlocked. All experiments must stop! Destroy equipment." + +# +"Platform lift access to lower level activated." + +# +"A door opens." + +# +"This is the power generator room." + +# +"Destroy the blockades and allow the doors to shut." + +# +"Temple sealed. Return to our Hive." + +# +"Find the tunnel down to our lair." + +# +# WHO WOULD HAVE THOUGHT IT? PREDATOR MESSAGES FOR TEMPLE BONUS LEVEL! +# + + +# +"Escape from hive and infiltrate facehugger shrine." + +# +"Must kill praetorian guards to deactivate fire." + +# +"Facehugger shrine." + +# +"DUMMY LEVEL-SPECIFIC MSG 368" + +# +"DUMMY LEVEL-SPECIFIC MSG 369" + +# +"DUMMY LEVEL-SPECIFIC MSG 370" + +# +"DUMMY LEVEL-SPECIFIC MSG 371" + +# +"DUMMY LEVEL-SPECIFIC MSG 372" + +# +"DUMMY LEVEL-SPECIFIC MSG 373" + +# +"DUMMY LEVEL-SPECIFIC MSG 374" + + + + +# +# +#SULACO_P BONUS LEVEL MESSAGES START HERE +# +# + + +# +"Find and destroy two xenoborgs and get back here." + +# +"COM: Security alert! A predator has accessed section D." + +# +"Hangar doors are already open!" + +# +"Xenoborgs are stored behind these doors." + +# +"Security has overridden the doors." + +# +"COM: Warning! If the predator is not contained soon the base will be evacuated." + +# +"COM: Message to all units. Prepare for evacuation. Opening evacuation doors." + +# +"COM: Message to all units. Opening the doors has caused a security breach. The base has been infiltrated by xenomorphs." + +# +"Return to section D airlock lift and escape!" + +# +"Wait for a few moments for lift to activate." + +# +"Do you copy? Damn it! Is anybody hearing this? We've encountered multiple hostiles, but they are not xenomorphs. I Repeat, they are NOT xenomorphs. Now These guys have some serious firepower and they're appearing out of thin air! We've taken heavy, heavy casualties so we've had to fall back and Dock 4 is no longer secure, I say again, we can no longer hold Dock 4. Now you've got to cancel the Earthbound cargo ship. I say again, call off the Earthbound ship..." + +# +"Attention station personnel! There is an intruder in the R&D Tower. It Looks like we picked up a xenomorph stowaway. This security breakdown has been corrected and the xenomorph will soon be neutralized." + +# +"Attention sub-station personnel! We must keep the xenomorph away from the local generators. Lock yourselves in and wait for back-up. This is NOT a drill!" + +# +"This is Lebowski, I'm in the Holding Pens. Please halt all specimen transfers until further notice. The Marines have yet to neutralize the xenomorph. So much for military efficiency... " + +# +"DUMMY LEVEL-SPECIFIC MSG 389" + +# +"DUMMY LEVEL-SPECIFIC MSG 390" + +# +# INVASION ALIEN DEMO BONUS LEVEL TEXT MESSAGES +# + +# +"Seek the planet surface to escape the installation." + +# +"Power generator room." + +# +"DUMMY LEVEL-SPECIFIC MSG 393" + +# +"DUMMY LEVEL-SPECIFIC MSG 394" + +# +"DUMMY LEVEL-SPECIFIC MSG 395" + +# +"DUMMY LEVEL-SPECIFIC MSG 396" + +# +"DUMMY LEVEL-SPECIFIC MSG 397" + +# +"DUMMY LEVEL-SPECIFIC MSG 398" + +# +# ONE DERELICT MESSAGE +# + +# +"COM: The doors will be locked, but there should be an emergency release on your left, behind the glass." + +# +# ESCAPE MESSAGES BEGIN HERE +# + +# +"Leave lair and infiltrate human base, then escape." + +# +"Door is welded shut." + +# +"Door is locked." + +# +"A door unlocks." + +# +"A secret passage opens." + +# +"Use vents to navigate base." + +# +"Go through airlocks to access research laboratories." + +# +"Seems humans are evacuating with eggs. Hitch a ride." + +# +"Get on that ship." + +# +"Break the glass." + +# +"Let's see where eggs are being taken..." + + +# +# UM... PREDATOR MESSAGES FOR ESCAPE BONUS LEVEL +# + + +# +"Move through base. Kill all game." + +# +"Use the airducts." + +# +"A way into the hive. Kill those inside." + +# +# ESCAPE FMV SCRIPTS +# + +# +"Attention all personnel! A xenomorph has been contained in Biolab 2, but we believe another is still at large. The creature will be contained, keep the eggs moving on schedule." + +# +"The xenomorph has bypassed the labs. We can't seal it off from here. Prepare for immediate evacuation." + +# +"The xenomorph must be stopped! Do NOT let it get on the ship!" + +# +"DUMMY LEVEL-SPECIFIC MSG 327" + +# +"DUMMY LEVEL-SPECIFIC MSG 328" + +# +"DUMMY LEVEL-SPECIFIC MSG 329" + +# +"DUMMY LEVEL-SPECIFIC MSG 420" + +# +"DUMMY LEVEL-SPECIFIC MSG 421" + +# +"DUMMY LEVEL-SPECIFIC MSG 422" + +# +"DUMMY LEVEL-SPECIFIC MSG 423" + +# +"DUMMY LEVEL-SPECIFIC MSG 424" + +# +"DUMMY LEVEL-SPECIFIC MSG 425" + +# +"DUMMY LEVEL-SPECIFIC MSG 426" + +# +"DUMMY LEVEL-SPECIFIC MSG 427" + +# +"DUMMY LEVEL-SPECIFIC MSG 428" + +# +"DUMMY LEVEL-SPECIFIC MSG 429" + +# +"DUMMY LEVEL-SPECIFIC MSG 430" + +# +"DUMMY LEVEL-SPECIFIC MSG 431" + +# +"DUMMY LEVEL-SPECIFIC MSG 432" + +# +"DUMMY LEVEL-SPECIFIC MSG 433" + +# +"DUMMY LEVEL-SPECIFIC MSG 434" + +# +"DUMMY LEVEL-SPECIFIC MSG 435" + +# +"DUMMY LEVEL-SPECIFIC MSG 436" + +# +"DUMMY LEVEL-SPECIFIC MSG 437" + +# +"DUMMY LEVEL-SPECIFIC MSG 438" + +# +"DUMMY LEVEL-SPECIFIC MSG 439" + +# +"DUMMY LEVEL-SPECIFIC MSG 440" + +# +"DUMMY LEVEL-SPECIFIC MSG 441" + +# +"DUMMY LEVEL-SPECIFIC MSG 442" + +# +"DUMMY LEVEL-SPECIFIC MSG 443" + +# +"DUMMY LEVEL-SPECIFIC MSG 444" + +# +"DUMMY LEVEL-SPECIFIC MSG 445" + +# +"DUMMY LEVEL-SPECIFIC MSG 446" + +# +"DUMMY LEVEL-SPECIFIC MSG 447" + +# +"DUMMY LEVEL-SPECIFIC MSG 448" + +# +"DUMMY LEVEL-SPECIFIC MSG 449" + +# +"DUMMY LEVEL-SPECIFIC MSG 450" + + +# End of level-specific messages + +# +"Aliens Versus Predator" + +# +"Single Player" + +# +"Start a Single Player game." + +# +"Select your species: Alien, Colonial Marine or Predator." + +# +"Select your species: Alien, Colonial Marine or Predator." + +# +"Select your species: Alien, Colonial Marine or Predator." + +# +"Multiplayer" + +# +"Join or host a multiplayer game." + +# +"Skirmish" + +# +"Configure and launch a single player skirmish game." + +# +"Controls" + +# +"Set up your controllers and keys for playing the game." + +# +"Change User Profile" + +# +"Select a different user profile; your current profile will be saved." + +# +"Cheat Options" + +# +"Access the cheat options menu." + +# +"Cheat Mode" + +# +"Pigsticking" + +# +"SlugTrail" + +# +"SniperMunch" + +# +"Terror" + +# +"SuperGore" + +# +"Grenade" + +# +"Mirror" + +# +"Pipecleaner" + +# +"DiscoInferno" + +# +"TripTastic" + +# +"MotionBlur" + +# +"UnderWater" + +# +"JohnWooMode" + +# +"WarpSpeed" + +# +"LandOfTheGiants" + +# +"ImpossibleMission" + +# +"RainbowBlood" + +# +"TickerTape" + +# +"Nausea" + +# +"FreeFall" + +# +"BallsOfFire" + +# +"Some cheat modes will only allow specific species and environments." + +# +"Choose the species you wish to play." + +# +"Choose the environment in which you will be playing. You may only select an environment that you have previously completed normally." + +# +"Video Card & Resolution" + +# +"Select a hardware card and resolution to run the game." + +# +"Audio/Video Options" + +# +"Configure the audio and video settings for the game." + +# +"Movie Volume" + +# +"Adjust the volume of the in-game and scene-setting movies." + +# +"Master Volume" + +# +"Adjust the volume of all in-game sound effects. (Also affects movie volume accordingly.)" + +# +"In-game Movies" + +# +"Choose whether to play in-game movies. This may affect performance on lower spec machines." + +# +"Intro/Outro Movies" + +# +"Choose whether to play scene-setting movies." + +# +"Use These Settings" + +# +"Accept these settings and return to the previous menu." + +# +"Gamma Setting" + +# +"Adjusts the brightness and contrast of the game." + +# +"Exit Game" + +# +"Quit the game and return to Windows." + +# +"Select User Profile" + +# +"New Profile" + +# +"Enter Name For New Profile" + +# +"Press ENTER to select a profile, or BACKSPACE to delete a profile." + +# +"Delete Profile - Are You Sure?" + +# +"Deleting a profile will permanently remove it, and all game data saved in the profile will be lost." + +# +"Please enter a name for your profile. Press BACKSPACE to delete characters and ENTER to finish" + +# +"Use the above name for the profile." + +# +"Exit Game - Are You Sure?" + +# +"Select Episode" + +# +"Start" + +# +"Press ENTER to go to the species selection menu." + +# +"Press ENTER to start the game." + +# +"Host New Game" + +# +"Press ENTER to host a new multiplayer game , setting the options yourself." + +# +"Join Existing Game" + +# +"Press ENTER to join a multiplayer game hosted by another player." + +# +"Continue" + +# +"Continue to the configuration menu" + +# +"Player Species" + +# +"Select the species or type of marine you would like to play as." + +# +"Marine" + +# +"Predator" + +# +"Alien" + +# +"Marine - Pulse Rifle" + +# +"Marine - Smartgun" + +# +"Marine - Flamethrower" + +# +"Marine - Sadar" + +# +"Marine - Grenade" + +# +"Marine - Minigun" + +# +"Marine - Skeeter" + +# +"Marine - Pistols" + +# +"Player Name" + +# +"Type in the name that you would like to appear as in the game." + +# +"Session Name" + +# +"Find Local Servers" + +# +"Press ENTER to search for games being played on a local network." + +# +"Open IP Address" + +# +"Press ENTER to specify an IP address of a computer to connect to." + +# +"IP Address" + +# +"Load IP Address" + +# +"Press ENTER to attempt to connect using the selected IP address" + +# +"TCP/IP" + +# +"IPX" + +# +"Serial" + +# +"Modem" + +# +"Select the network protocol to use for the multiplayer game." + +# +"No available connections" + +# +"Was Unable to setup TCPIP, IPX, serial or modem connection. Therefore it isn't possible to start a multiplayer game" + +# +"Make Connection" + +# +"Press ENTER to attempt to connect using the selected IP address." + +# +"Available Sessions" + +# +"Press ENTER to join the selected multiplayer session." + +# +"No sessions were found" + +# +"Was unable to find any multiplayer sessions. You may need to wait for the host to finish configuring the game." + +# +"Environment" + +# +"Game Style" + +# +"Deathmatch" + +# +"Species Deathmatch" + +# +"Last Man Standing" + +# +"Predator Tag" + +# +"Cooperative" + +# +"Alien Tag" + +# +"Max Aliens" + +# +"Max Predators" + +# +"Max Marines" + +# +"Max Standard Marines" + +# +"Max Pulse Rifle Marines" + +# +"Max Smartgun Marines" + +# +"Max Flamer Marines" + +# +"Max Sadar Marines" + +# +"Max Grenade Marines" + +# +"Max Minigun Marines" + +# +"Max Skeeter Marines" + +# +"Max Twin Pistol Marines" + +# +"Allow Smartgun" + +# +"Allow Flamethrower" + +# +"Allow Sadar" + +# +"Allow Grenade Launcher" + +# +"Allow Minigun" + +# +"Allow Skeeter" + +# +"Allow Marine Pistols" + +# +"Allow Disc" + +# +"Allow Predator Pistol" + +# +"Allow Shoulder Cannon" + +# +"Allow Speargun" + +# +"Allow Medicomp" + +# +"Use Dynamic Scoring" + +# +"Use Species Scoring" + +# +"Base Kill Value" + +# +"Alien Value" + +# +"Marine Value" + +# +"Predator Value" + +# +"Send Decals" + +# +"Score Limit" + +# +"No Score Limit" + +# +"Time Limit" + +# +"No Time Limit" + +# +"Invulnerability Time" + +# +"Lives" + +# +"Infinite" + +# +"Use Shared Lives" + +# +"Object Respawn Score" + +# +"No Score Based Respawn" + +# +"Object Respawn Time" + +# +"No Time Based Respawn" + +# +"Game Speed" + +# +"70 %" + +# +"80 %" + +# +"90 %" + +# +"100 %" + +# +"Pre-Destroy Lights" + +# +"Disable Friendly Fire" + +# +"Falling Damage" + +# +"Pistols Have Infinite Ammo" + +# +"Specialists Have Pistols" + +# +"Points" + +# +"Seconds" + +# +"Minutes" + +# +"Multiplayer Configuration" + +# +"Save Configuration" + +# +"Save the current game configuration" + +# +"Load Configuration" + +# +"Load a previously saved game configuration" + +# +"AI Alien Value" + +# +"AI Predalien Value" + +# +"AI Praetorian Value" + +# +"Score" + +# +"Score For" + +# +"Score Against" + +# +"Time" + +# +"Lives Left" + +# +"Species Score" + +# +"Aliens" + +# +"Predaliens" + +# +"Praetorians" + +# +"Weapons have respawned" + +# +"This is the session name players will see when attempting to join a game." + +# +"Every player against every other player." + +# +"Each species against the others. Score is lost for killing your own species." + +# +"All players enter as marines except the host who is an alien. When an alien kills a marine, that marine returns as an alien. The 'last man standing' marine gets bonus scores for killing aliens. When the last marine dies, the game is restarted with a new player chosen as the alien. The scores are reset after every player has started a game as an alien." + +# +"All players enter as marines or aliens except the host who is a predator. Only the predator may score. The player who kills the predator assumes that character." + +# +"All players are marines or predators. They must survive against computer controlled aliens, predaliens and praetorians." + +# +"All players enter as marines or predators except the host who is an alien. Only the alien may score. The player who kills the alien assumes that character." + +# +"This is the environment that you will be playing in." + +# +"If the game speed is set to less than 100% , then the speed of all movement within the game will be scaled down." + +# +"When this score is reached, the game will end." + +# +"When this time is up, the game will end." + +# +"This is the time that a character is invulnerable for after respawning. Invulnerability is lost if you fire a weapon." + +# +"This is the limit on the number of characters of this type that can join the game." + +# +"This is the limit on the number of this type of marine that can join the game. For a player to join as a marine there must be enough 'marine slots' , and also enough 'specialist slots' of the appropriate type " + +# +"If this option is set to no then no weapons of this type will be available within the level. Also players won't be able to join as specialist marines of this type." + +# +"If this option is set to no , then predators won't be given this weapon." + +# +"If this option is set to yes then the score for killing a player will change according to how the player is doing. The score is determined by comparing the points scored by the killed player to the points scored against that player. This option is ignored in last man standing games." + +# +"If this option is set to yes then the score for killing a player will depend on their species. This option is ignored in last man standing games." + +# +"This value is the number of points lost when a player commits suicide. It is also used as the score for killing a player if species based scoring is off." + +# +"This value is the number of points awarded for killing a player alien. This is only used if species based scoring is on." + +# +"This value is the number of points awarded for killing a player marine. This is only used if species based scoring is on." + +# +"This value is the number of points awarded for killing a player predator. This is only used if species based scoring is on." + +# +"This is the number of points awarded for killing a computer controlled character of this type." + +# +"This defines the total lives of each player. Once a player's lives are gone , that player can only observe until the game restarts. The game will end when all players have lost their lives." + +# +"This determines whether each player has their life limit , or all players have a common life limit. This option is ignored if there is no life limit." + +# +"All weapon and health pickups will respawn whenever the total points scored by all player passes a multiple of this value. If this value is set to 0 then objects will never respawn as a result of score. Pickups may still respawn based on time , if the option below is not set to 'No Time Based Respawn'." + +# +"This determines how frequently weapons and health pickups respawn in the game. If this value is set to 0 then objects will never respawn as a result of time passing. Pickups may still respawn based on score , if the option above is not set to 'No Score Based Respawn'." + +# +"If this option is turned on then all destructable lights will start the game destroyed." + +# +"If this option is turned on then you can't harm players on the same team as you." + +# +"This turns falling damage on and off." + +# +"If on, all pistols have infinite ammo." + +# +"If on, all specialists have backup pistols." + +# +"Type the IP address that you want to connect to." + +# +"Use a previously saved IP address." + +# +"Type a filename here if you want this IP address saved for later use." + +# +#Multiplayer console messages +# + +# +"%1 has been killed by %2" + +# +"%1 has commited suicide" + +# +"%1 has left the game" + +# +"%1 has joined the game" + +# +"%1 has connected to the game" + +# +"This machine is now host" + +# +"Press any key to restart game" + +# +"Please wait for the host to restart the game" + +# +"%1 has killed an alien" + +# +"%1 has killed a predalien" + +# +"%1 has killed a praetorian" + +# +"%1 has been killed by an Alien" + +# +"%1 has been killed by a Predalien" + +# +"%1 has been killed by a Praetorian" + +# +"You see %1" + +# +#Strings for the last man standing game +# + +# +"All marines are dead." + +# +"Please wait for the host to restart" + +# +"Press operate to restart." + +# +"Go!" + +# +"%1 is the last man standing." + +# +"%1 will be the alien." + +# +"Sewer" + +# +"Massacre" + +# +"Statue" + +# +"Jockey" + +# +"Hive" + +# +"Leadworks" + +# +"Hadley's Hope" + +# +"Meat Factory" + +# +"Nostromo" + +# +"Subway" + +# +"Elevator" + +# +"Lab 14" + +# +"Compound" + +# +"Office" + +# +"Stranded" + +# +"Hive" + +# +"Trapped" + +# +"Sewer" + +# +"Jockey" + +# +"Leadworks" + +# +"Hadley's Hope" + +# +"Meat Factory" + +# +"Nostromo" + +# +"Subway" + +# +"Elevator" + +# +"Lab 14" + +# +"Compound" + +# +"Start Marine Demo" + +# +"Start Predator Demo" + +# +"Start Alien Demo" + +# +"Start Deathmatch Demo" + + +# For the PC mouse options menu + +# +"Mouse Configuration" + +# +"Configure your mouse for playing the game." + +# +"Horizontal Sensitivity" + +# +"Choose sensitivity level: right is more, left is less." + +# +"Vertical Sensitivity" + +# +"Choose sensitivity level: right is more, left is less." + +# +"Vertical Axis" + +# +"Choose a function for the vertical axis." + +# +"Horizontal Axis" + +# +"Choose a function for the horizontal axis." + +# +"Looking" + +# +"Movement" + +# +"Sidestepping" + +# +"Turning" + +# +"Invert Vertical Axis" + +# +"Reverses the vertical axis of the mouse, e.g. moving upwards will cause your character to look down." + +# +"Reverses the vertical axis of the joystick, e.g. pushing upwards will cause your character to look down." + +# +"Auto-centre" + +# +"When moving, snaps the characters view back to looking directly ahead." + +# +"Use These Settings" + +# +# Note! this is used as a general string, not just for the mouse settings +"Accept these settings and return to the previous menu." + +# +"Reset To Defaults" + +# +"Resets all variables to their defaults. Does not return to the previous menu." + +# +"Joystick Configuration" + +# +"Configure your joystick for playing the game." + +# +"Joystick Enabled" + +# +"Sets whether you may use a joystick for playing the game." + +# +"Ignored" + +# +"Movement" + +# +"POV Hat Invert Vertical Axis" + +# +"Reverses the HAT vertical axis." + +# +"POV Hat Vertical Axis" + +# +"Choose a function for the POV hat vertical axis." + +# +"POV Hat Horizontal Axis" + +# +"Choose a function for the POV hat horizontal axis." + +# +"Rudder Enabled" + +# +"Sets whether you may use a joystick rudder for playing the game." + +# +"Rudder Axis" + +# +"Choose a function for the rudder axis." + +# +"Predator Key Configuration" + +# +"Configure the Predator key controls for playing the game. This does not affect other species." + +# +"Alien Key Configuration" + +# +"Configure the Alien key controls for playing the game. This does not affect other species." + +# +"Marine Key Configuration" + +# +"Configure the Marine key controls for playing the game. This does not affect other species." + +# +"Use the cursor keys to navigate. To change a setting, press ENTER followed by the key of your choice (this includes mouse and joystick buttons). Press BACKSPACE to erase a setting. Any settings which are shown in yellow indicate key clashing." + +# Start of the episode names +# +# +"Episode I: Derelict" + +# +"Episode II: Colony" + +# +"Episode III: Invasion" + +# +"Episode IV: Orbital" + +# +"Episode V: Tyrargo" + +# +"Episode VI: Hangar" + +# +"Bonus I: Temple" + +# +"Bonus II: Vaults" + +# +"Bonus III: Ferarco" + +# +"Bonus IV: Gateway" + +# +"Bonus V: Waterfall" + +# +"Episode I: Waterfall" + +# +"Episode II: Area 52" + +# +"Episode III: Vaults" + +# +"Episode IV: Fury 161" + +# +"Episode V: Caverns" + +# +"Episode VI: Battle" + +# +"Bonus I: Invasion" + +# +"Bonus II: Escape" + +# +"Bonus III: Temple" + +# +"Bonus IV: Earthbound" + +# +"Bonus V: Tyrargo" + +# +"Episode I: Temple" + +# +"Episode II: Escape" + +# +"Episode III: Ferarco" + +# +"Episode IV: Gateway" + +# +"Episode V: Earthbound" + +# +"Bonus I: Invasion" + +# +"Bonus II: Derelict" + +# +"Bonus III: Tyrargo" + +# +"Bonus IV: Caverns" + +# +"Bonus V: Fury 161" + +# +"Weyland-Yutani Bioweapons Research Facility on LV-426." +# +"2154 - Ten years after Hadleys Hope Incident." +# +"Massive biocontainment failure." +# +"Scientific & Civilian personnel evacuation complete." +# +"" + + +# +"Weyland-Yutani Scientific & Civilian Support Installation." +# +"Severe Xenomorph infestation." +# +"Research teams and support engineers evacuated." +# +"Power generators offline." +# +"" + +# +"Weyland-Yutani Atmosphere Processor." +# +"Extreme Xenomorph infestation apparent." +# +"Civilian support personnel missing - presumed infected." +# +"Control mechanisms damaged - systems critical." +# +"" + +# +"USCM Low-Orbit Operations Platform 'Odobenus'." +# +"Integrity compromised - internal pressure dropping." +# +"Biocontainment failure due to external damage." +# +"Security systems online." +# +"" + +# +"USCM Costanoga class cruiser 'Tyrargo'." +# +"Biocontainment systems sabotaged." +# +"Crew complement evacuated or MIA" +# +"Hangar deck security systems inactive." +# +"" + +# +"USCM Cruiser 'Tyrargo' Hangar Deck." +# +"Security systems inactive." +# +"Extensive damage reported." +# +"" +# +"" + +# +"Temple of unknown origin." +# +"USCM investigation halted due to Xenomorph infestation." +# +"" +# +"Special equipment - Jetpack" +# +"" + +# +"Xenobiological Storage Facility" +# +"Massive biocontainment failure." +# +"Predator infiltration detected." +# +"Base self-destruct sequence initiated." +# +"" + +# +"Weyland-Yutani General Purpose Freighter 'Ferarco'." +# +"Suspected Xenomorph infestation of vessel." +# +"USCM specialist dispatched for recon." +# +"Special equipment - Jetpack." +# +"" + +# +"Deep Space Freight Terminal 'Gateway'." +# +"Weyland-Yutani secure R&D Tower." +# +"Evacuation in progress." +# +"Special equipment - Jetpack." +# +"" + +# +"Entrance to Weyland-Yutani 'Area 52' Installation." +# +"Go out there and kill things." +# +"" +# +"" +# +"" + + +# +"Entrance to Weyland-Yutani 'Area 52' Installation" +# +"Security patrol teams on alert status." +# +"" +# +"" +# +"" + +# +"'Area 52' Xenobiological Research Installation." +# +"Location of contained Predator ship." +# +"Unauthorized access detected." +# +"Security personnel mobilized." +# +"" + +# +"Xenobiological Storage Facility." +# +"Captive Predator moved from holding pen to experimentation cell." +# +"" +# +"Pistol and Disc collected from Predator ship." +# +"" + +# +"'Fury 161' Smelting Plant." +# +"Extensive Xenomorph infestation." +# +"" +# +"USCM Recon Team en route." +# +"" + +# +"USCM Controlled Xenomorph Habitat." +# +"Specimen acquisition in progress." +# +"" +# +"Queen activity detected." +# +"" + +# +"Queen's Birthing Chamber." +# +"" +# +"" +# +"" +# +"" + +# +"Weyland-Yutani Atmosphere Processor." +# +"Extreme Xenomorph infestation apparent." +# +"USCM team in control of lower areas." +# +"" +# +"" + +# +"Weyland-Yutani field laboratory." +# +"Investigation of adjacent temple in progress." +# +"" +# +"Special equipment - Grappling hook." +# +"" + +# +"Temple of unknown origin." +# +"USCM evacuation in progress." +# +"Severe Xenomorph infestation." +# +"Special equipment - Grappling hook." +# +"" + +# +"Gateway Docking Umbilical." +# +"Massive containment breach." +# +"Unknown intruder detected in Dock 4." +# +"Special equipment - Grappling hook." +# +"" + +# +"USCM Costanoga class cruiser 'Tyrargo'." +# +"Xenoborg cargo in transit." +# +"" +# +"" +# +"" + +# +"Temple of unknown origin." +# +"Phase 2 of USCM investigation in progress." +# +"Lower levels of artifact secured." +# +"" +# +"" + +# +"Weyland-Yutani Field Laboratory." +# +"Preliminary specimen analysis and sterilization in progress." +# +"Low orbit transit shuttle expected." +# +"" +# +"" + +# +"Weyland-Yutani General Purpose Freighter 'Ferarco'." +# +"Crew complement 50." +# +"Cargo - Unknown." +# +"Destination - Unknown." +# +"" + +# +"Deep Space Freight Terminal 'Gateway'." +# +"Weyland-Yutani secure R&D tower." +# +"Specimen containment systems nominal." +# +"" +# +"" + +# +"Gateway Docking Umbilical." +# +"Specimen relay in progress." +# +"R&D tower locked off due to containment breach." +# +"Earthbound shuttle craft approaching." +# +"" + +# +"Weyland-Yutani Atmosphere Processor." +# +"USCM personnel attempting repair of systems." +# +"Temporary power generators installed." +# +"Xenomorph infestation under control by USCM teams." +# +"" + +# +"Weyland-Yutani Bioweapons Research Facility on LV-426." +# +"Heavy USCM presence." +# +"" +# +"" +# +"" + +# +"USCM Costanoga class cruiser 'Tyrargo'." +# +"Full crew complement." +# +"Hangar deck security systems active." +# +"" +# +"" + +# +"USCM controlled Xenomorph habitat." +# +"USCM specimen acquisition in progress." +# +"Predator threat approaching." +# +"" +# +"" + +# +"'Fury 161' Smelting plant." +# +"Strong USCM presence attempting Xenomorph neutralization." +# +"" +# +"" +# +"" + +# +"Resume Play" + +# +"Restart Mission" + +# +"Abort Play" + +# +"Difficulty Level" + +# +"Training" + +# +"Realistic" + +# +"Director's Cut" + +# +"Play on Training Mode - Easy difficulty." + +# +"Play on Realistic - Medium difficulty." + +# +"Play on Director's Cut - Hard difficulty." + +# +"Not yet completed" + +# +"Completed on Training" + +# +"Completed on Realistic" + +# +"Completed on Director's Cut" + +# +"Completed" + +# +"Not yet available - to access complete game on Realistic" + +# +"Not yet available - to access complete game on Director's Cut" + +# +"Detail Levels Menu" + +# +"Configure the graphical effects for playing the game. Adjusting these can improve performance on lower spec machines." + +# +"Number of Decals" + +# +"Sets how many bulletholes, blood splashes and acid burns are displayed in game." + +# +"Light Coronas" + +# +"Switches glowing light coronas on or off. Can improve performance if disabled." + +# +"Decals On Characters" + +# +"Switches whether you see bulletholes on character models. Can improve performance if disabled." + +# +"Deformable Explosions" + +# +"Sets whether explosions dynamically deform to the environment. Can improve performance if disabled." + +# +"Character Complexity" + +# +"Selects the complexity of the in-game character models. Lower settings can improve performance." + +# +"Complex Particle Effects" + +# +"Reduces the amount of flame, smoke and other particles in the game. Can improve performance if disabled." + +# +"Very Low" + +# +"Low" + +# +"Medium" + +# +"High (Default)" + +# +"Off" + +# +"On (Default)" + +# +"Mission Briefing" + +# +"Continue" + +# +"No" + +# +"Yes" + +# +"MISSION ACCOMPLISHED" + +# +"Press any key to continue" + +# +"Message Number:" + +# +"CHEAT MODE ACTIVATED" + +# +"Medikit" + +# +"Ammo" + +# +"Pulse Rifle" + +# +"Smartgun" + +# +"Flamethrower" + +# +"SADAR" + +# +"Grenade Launcher" + +# +"Minigun" + +# +"Pistol" + +# +"Skeeter Launcher" + +# +"Pistols" + +# +"Claw" + +# +"Tail" + +# +"Wristblade" + +# +"Pistol" + +# +"Speargun" + +# +"Shoulder Cannon" + +# +"Disc" + +# +# The predator medical/heal thing +"Medicomp" + +# +"Image Intensifier Activated" + +# +"Image Intensifier Deactivated" + +# +"Health" + +# +"Armor" + +# +"Free Mode" + +# +"Track Mode" + +# +"Forward" + +# +"Backward" + +# +"Left" + +# +"Right" + +# +"Strafe" + +# +"Strafe Left" + +# +"Strafe Right" + +# +"Look Up" + +# +"Look Down" + +# +"Centre View" + +# +"Walk" + +# +"Crouch" + +# +"Jump" + +# +"Operate" + +# +"Fire Primary" + +# +"Fire Secondary" + +# +"Next Weapon" + +# +"Previous Weapon" + +# +"Flashback Weapon" + +# +"Cloak" + +# +"Cycle Vision Modes" + +# +"Zoom In" + +# +"Zoom Out" + +# +"Grappling Hook" + +# +"Recall Disc" + +# +"Taunt" + +# +"Message History" + +# +"Say" + +# +"Species Say" + +# +"Show Scores" + +# now for the Marine's keys + +# +"Forward" + +# +"Backward" + +# +"Left" + +# +"Right" + +# +"Strafe" + +# +"Strafe Left" + +# +"Strafe Right" + +# +"Look Up" + +# +"Look Down" + +# +"Centre View" + +# +"Walk" + +# +"Crouch" + +# +"Jump" + +# +"Operate" + +# +"Fire Primary" + +# +"Fire Secondary" + +# +"Next Weapon" + +# +"Previous Weapon" + +# +"Flashback Weapon" + +# +"Image Intensifier" + +# +"Throw Flare" + +# +"Jetpack" + +# +"Taunt" + +# +"Message History" + +# +"Say" + +# +"Species Say" + +# +"Show Scores" + + +# alien's keys + +# +"Forward" + +# +"Backward" + +# +"Left" + +# +"Right" + +# +"Strafe" + +# +"Strafe Left" + +# +"Strafe Right" + +# +"Look Up" + +# +"Look Down" + +# +"Centre View" + +# +"Walk" + +# +"Crouch/Climb" + +# +"Jump" + +# +"Operate" + +# +"Claw Attack" + +# +"Tail Attack" + +# +"Navigate/Hunt Toggle" + +# +"Taunt" + +# +"Message History" + +# +"Say" + +# +"Species Say" + +# +"Show Scores" + + +# Next, the actual names of keys + +# +"LEFT" + +# +"RIGHT" + +# +"UP" + +# +"DOWN" + +# +"RETURN" + +# +"TAB" + +# +"INSERT" + +# +"DELETE" + +# +"END" + +# +"HOME" + +# +"PAGEUP" + +# +"PAGEDOWN" + +# +"BACKSP" + +# +"COMMA" + +# +"PERIOD" + +# +"SPACE" + +# +"LSHIFT" + +# +"RSHIFT" + +# +"LALT" + +# +"RALT" + +# +"LCTRL" + +# +"RCTRL" + +# +"CAPSLOCK" + +# +"NUMLOCK" + +# +"SCRLOCK" + +# +"PAD0" + +# +"PAD1" + +# +"PAD2" + +# +"PAD3" + +# +"PAD4" + +# +"PAD5" + +# +"PAD6" + +# +"PAD7" + +# +"PAD8" + +# +"PAD9" + +# +"PADSUB" + +# +"PADADD" + +# +"PADDEL" + +# +"PADENTER" + +# +"PADDIVIDE" + +# +"PADMULTIPLY" + +# +"LBRACKET" + +# +"RBRACKET" + +# +"SEMICOLON" + +# +"APOSTROPHE" + +# +"GRAVE" + +# +"BACKSLASH" + +# +"SLASH" + +# +"CAPITAL" + +# +"MINUS" + +# +"EQUALS" + +# +"LWINDOWS" + +# +"RWINDOWS" + +# +"APPSMENU" + +# +"F1" + +# +"F2" + +# +"F3" + +# +"F4" + +# +"F5" + +# +"F6" + +# +"F7" + +# +"F8" + +# +"F9" + +# +"F10" + +# +"F11" + +# +"F12" + +# +"JOYBUTTON1" + +# +"JOYBUTTON2" + +# +"JOYBUTTON3" + +# +"JOYBUTTON4" + +# +"JOYBUTTON5" + +# +"JOYBUTTON6" + +# +"JOYBUTTON7" + +# +"JOYBUTTON8" + +# +"JOYBUTTON9" + +# +"JOYBUTTON10" + +# +"MOUSE1" + +# +"MOUSE2" + +# +"MOUSE3" + +# +"MOUSE4" + +# +"MWHEELUP" + +# +"MWHEELDOWN" + +# Short names for the different types of ammunition to potentially appear on a status panel +# (added 20/11/97 by DHM; I've taken the names from Lee Brimmicombe-Wood's book except where +# noted as placeholder) +# Do the fonts contain numbers? lower case for the mm? dashes? + +# +# Ammunition name for use on weapon status panel: what to use when the ammo type doesn't have a sensible name +"No Ammo" + +# +# Ammunition name for use on weapon status panel: 10MM_CULW +"Pulse Ammo" + +# +# Ammunition name for use on weapon status panel: SHOTGUN (placeholder) +"Shotgun" + +# +# Ammunition name for use on weapon status panel: SMARTGUN +"Smart ammo" + +# +# Ammunition name for use on weapon status panel: FLAMETHROWER +"Napalm" + +# +# Ammunition name for use on weapon status panel: SADAR_TOW +# SADAR is an acronym for Shoulder-launched Active-homing Disposable Anti-tank Rocket +"M83A2 SADAR" + +# +# Ammunition name for use on weapon status panel: GRENADE (placeholder) +"Grenade" + +# +# Ammunition name for use on weapon status panel: MINIGUN (placeholder) +"Minigun" + +# +# Ammunition name for use on weapon status panel: PULSE_GRENADE +"Pulse grenade" + +# +# Ammunition name for use on weapon status panel: MARINE_PISTOL_PC +"Pistol ammo" + +# +# Ammunition name for use on weapon status panel: FRISBEE +"Skeeter" + +# +# Ammunition name for use on weapon status panel: FLARE_GRENADE (placeholder) +"Flare" + +# +# Ammunition name for use on weapon status panel: FRAGMENTATION_GRENADE (placeholder) +"Frag" + +# +# Ammunition name for use on weapon status panel: PROXIMITY_GRENADE (placeholder) +"Prox Mine" + +# No names have been assigned for predator or alien +# ammunition types yet... + +# Messages to give feedback when different grenade types are selected +# (added 20/11/97 by DHM) + +# +"Standard Grenades Selected" + +# +"Flare Grenades Selected" + +# +"Proximity Grenades Selected" + +# +"Fragmentation Grenades Selected" + +# Names for the different status panels available in the Marine game +# (added 20/11/97 by DHM) + +# Feedback strings + +# +# String to appear on HUD for ammo readout - rounds remaining +"Rounds" + +# +# String to appear on HUD for ammo readout - magazines remaining +"Magazines" + +# +# String to appear on HUD for ammo readout - magazines remaining for flame thrower +"Cannisters" + +# +"Filename" + +# +"Type in the filename (without extension) that you would like to use for this configuration." + + +# +"Description" + +# +"Type in a description for this configuration. This description will appear when you select a configuration to load." + +# +"Save" + +# +"Press ENTER to save this configuration. (Press ESCAPE to cancel)." + +# Here starts all my game stats screen stuff - CDF 14/4/99 + +# +"Level Completed" + +# +"Level Not Completed" + +# +"Current:" + +# +"Best:" + +# +"Target:" + +# +"Time Elapsed:" + +# +"Time Cloaked:" + +# +"Killed:" + +# +"Trophies Collected:" + +# +"Live Head Bites:" + +# +"Dead Head Bites:" + +# +"Average Speed:" + +# +"Preferred Vision Mode:" + +# +"Health Damage Taken:" + +# +"Armor Damage Taken:" + +# +"Head Shots:" + +# +"Preferred Weapon:" + +# +"Total Shots Fired:" + +# +"Accuracy:" + +# +"Spotted:" + +# +"Field Charge Used:" + +# +"Cheat Mode Enabled!" + +# +"Facehugger" + +# +"Xenomorph" + +# +"Praetorian" + +# +"Queen" + +# +"Xenoborg" + +# +"Predalien" + +# +"Predator" + +# +"Marine" + +# +"Civilian" + +# +"Android" + +# Now the plurals - I guess they might be different in other languages. +# +"Facehuggers" + +# +"Xenomorphs" + +# +"Praetorians" + +# +"Queens" + +# +"Xenoborgs" + +# +"Predaliens" + +# +"Predators" + +# +"Marines" + +# +"Civilians" + +# +"Androids" + +# Now vision mode names. +# +"Normal" + +# +"Navigation Sense" + +# +"Image Intensifier" + +# +"Thermal" + +# +"Electrical" + +# +"PredTech" + +# +"Play AvP free on Mplayer.com" + +# +"Change Me!" + +# +"Change Me!" + +# +"Change Me!" + +# +"Change Me!" + +# +"No ammo for weapon" + +# +"Previous Game" + +# +"Your 3D hardware does not have enough memory to run in this resolution or bit-depth. Please select a lower setting." + +# +"Alien Tag" + +# +"Frantic Cooperative" + +# +"Last Man Standing" + +# +"Marine Cooperative" + +# +"Murder In The Dark" + +# +"Predator Tag" + +# +"Straight Deathmatch" + + +# +"All players are Marines with one Alien. Only the Alien may score. The Marine who kills the Alien takes its place." + +# +"A fast moving cooperative game in a tight environment. You must score frags before any powerups respawn." + +# +"A match lasting as many games as there are players with participants switching sides during each game. As a Marine you must survive longest to score highest. As an Alien you must stop Marines scoring." + +# +"The marines have been dropped by an EEV. To survive they must reach the fortified base at the end of the canyons." + +# +"All players play as Marines in a completely dark environment. No proxmines are permitted. This is an atmospheric deathmatch popular at Rebellion." + +# +"All players are Marines with one Predator. Only the Predator can score points. The Marine that kills the Predator takes its place." + +# +"Straight deathmatch in any DM level." + +# +"Joining Game" + +# +"Waiting for host to start" + +# +"Waiting for game description" + +# +"Error : Host's version of AvP is incompatable" + +# +"Error : You don't have the chosen level" + +# +"Attempting to join multiplayer game. Press ESCAPE to abort." + +# +"Error setting up game" + +# +"There was a problem setting up the multiplayer game." + +# +"Looking for sessions , please wait." + +# additions after language localisation lock :) KJL + +# +"Trackball Enabled" + +# +"Enable trackball support on joysticks such as the Mad Catzª Panther XL." + +# +"Invert Trackball Vertical Axis" + +# +"Reverses the vertical axis of the trackball, so that moving the ball forwards will cause your character to look down." + +# +"Trackball Horizontal Sensitivity" + +# +"Trackball Vertical Sensitivity" + +# +"JOYBUTTON11" + +# +"JOYBUTTON12" + +# +"JOYBUTTON13" + +# +"JOYBUTTON14" + +# +"JOYBUTTON15" + +# +"JOYBUTTON16" + +# +"Press ESCAPE to restart level, or any other key to continue." + +# +"CD Volume" + +# +"Adjust the volume of music played from the CD." + +# +"Extrapolate Movement" + +# +"When enabled, other players' movement in multiplayer will look smoother, at the possible cost of accuracy." + +# +"(Full)" + +# +"Fox Interactive" + +# +"Presents" + +# +"Delete Configuration" + +# +"Select yes to delete this configuration. Deleting a configuration will destroy it permanently." + +# +"Press ENTER to load the selected configuration. Press BACKSPACE to delete a configuration. Press ESCAPE to return to the previous menu without doing anything." + +# +"Load Game" + +# +"Load a previously saved single player game." + +# +"Save Game" + +# +"Select a slot from which to load." + +# +"Select a slot to which to save." + +# +"Empty Save Slot" + +# +"Error: game has not been saved." + +# +"Error: save file is corrupt." + +# +"No saves left." + +# +"Game saved successfully." + +# +"Game loaded successfully." + +# +"No save in cheat/debug mode." + +# +"Saves left" + +# +"Auto Weapon Change" + +# +"Do you want to change weapons when you pick up one that you don't already have?" + +# +"Gold Edition" + +# +"Predator Pistol" + +# +"Unavailable weapons :" + +# +"New" + +# +"Custom" + +# +"Press operate to respawn" + +# +"Press operate to observe remaining players" + +@ This line signifies end of file. Do not delete! + \ No newline at end of file diff --git a/3dc/GENPARAM.TXT b/3dc/GENPARAM.TXT new file mode 100644 index 0000000..988f67e --- /dev/null +++ b/3dc/GENPARAM.TXT @@ -0,0 +1,140 @@ +# AVP ALIEN GENERATOR DATA FILE +# +# This file contains level parameters for alien/marine generation. +# There are three parameters defined for each level: +# 1. Maximum number of aliens/marines in the level +# 2. Number of aliens/marines generated per minute +# 3. The increase in number generated per minute, per minute +# +# For an example of how these parameters work: if the initial +# number of aliens generated per minute is 3, and the increase +# in number per minute is 2, then during the first minute of +# play time 3 aliens will be generated, during the second minute +# 5 more will be generated, and during the third minute another +# 7 will be generated. +# +# The format of this file is: comment lines start with a hash, +# and each data item sits a new line. Each data item is preceeded +# with a comment, stating what it is +# +# CHANGING THIS FILE +# ------------------ +# You may change any parameter for any level in this file. Save the +# file, and the next time you run the game the new parameter value +# will be used... however, you must follow these rules: +# +# 1. Stick to the format conventions described above +# 2. Do not insert comment lines longer than 80 characters +# 3. Do not change the order of the data items in this file +# 4. Do not save the file as anything other than a ASCII text file +# If you just edit the particular data item you are interested in, +# and then save the file, you shouldn't get any problems. +# +# Value Ranges +# ------------ +# Maximum number of aliens should be between 0 and 255: +# 25 is a typical value. +# Aliens per minute should be between 0 and 255: +# 3 is a typical value +# Increase in aliens per minute should be between 0 and 255 +# 2 is a typical value +# +# Patrick. +# ----------------------------------------------------------------- +# +# GEN 1 (GENERAL ACCESS) : MAX ALIENS +25 +# GEN 1 (GENERAL ACCESS) : ALIENS PER MINUTE +3 +# GEN 1 (GENERAL ACCESS) : INCREASE IN ALIENS PER MINUTE +2 +# GEN 2 (LIVING QUARTERS) : MAX ALIENS +25 +# GEN 2 (LIVING QUARTERS) : ALIENS PER MINUTE +4 +# GEN 2 (LIVING QUARTERS) : INCREASE IN ALIENS PER MINUTE +2 +# GEN 3 (HANGER1) : MAX ALIENS +25 +# GEN 3 (HANGER1) : ALIENS PER MINUTE +4 +# GEN 3 (HANGER1) : INCREASE IN ALIENS PER MINUTE +2 +# MEDLAB : MAX ALIENS +25 +# MEDLAB : ALIENS PER MINUTE +3 +# MEDLAB : INCREASE IN ALIENS PER MINUTE +2 +# CMC 2 (HANGER 2) : MAX ALIENS +25 +# CMC 2 (HANGER 2) : ALIENS PER MINUTE +3 +# CMC 2 (HANGER 2) : INCREASE IN ALIENS PER MINUTE +2 +# CMC 4 (MAIN ARMOURY) : MAX ALIENS +25 +# CMC 4 (MAIN ARMOURY) : ALIENS PER MINUTE +3 +# CMC 4 (MAIN ARMOURY) : INCREASE IN ALIENS PER MINUTE +2 +# CMC 6 (MAIN CONTROL) : MAX ALIENS +25 +# CMC 6 (MAIN CONTROL) : ALIENS PER MINUTE +3 +# CMC 6 (MAIN CONTROL) : INCREASE IN ALIENS PER MINUTE +2 +# SP2 (SECURITY POINT 2) : MAX ALIENS +10 +# SP2 (SECURITY POINT 2) : ALIENS PER MINUTE +1 +# SP2 (SECURITY POINT 2) : INCREASE IN ALIENS PER MINUTE +1 +# SP3 (SECURITY POINT 3) : MAX ALIENS +10 +# SP3 (SECURITY POINT 3) : ALIENS PER MINUTE +1 +# SP3 (SECURITY POINT 3) : INCREASE IN ALIENS PER MINUTE +1 +# R&D 2 (BIOWEAPONS RESEARCH) : MAX ALIENS +25 +# R&D 2 (BIOWEAPONS RESEARCH) : ALIENS PER MINUTE +3 +# R&D 2 (BIOWEAPONS RESEARCH) : INCREASE IN ALIENS PER MINUTE +2 +# R&D 3 (CYBERNETIC AUGMENTATION) : MAX ALIENS +25 +# R&D 3 (CYBERNETIC AUGMENTATION) : ALIENS PER MINUTE +3 +# R&D 3 (CYBERNETIC AUGMENTATION) : INCREASE IN ALIENS PER MINUTE +2 +# R&D 4 (NON-TERRESTRIAL TECH) : MAX ALIENS +25 +# R&D 4 (NON-TERRESTRIAL TECH) : ALIENS PER MINUTE +3 +# R&D 4 (NON-TERRESTRIAL TECH) : INCREASE IN ALIENS PER MINUTE +2 +# MPS 2 (POWER SITE MAINTAINANCE) : MAX ALIENS +25 +# MPS 2 (POWER SITE MAINTAINANCE) : ALIENS PER MINUTE +3 +# MPS 2 (POWER SITE MAINTAINANCE) : INCREASE IN ALIENS PER MINUTE +2 +# MPS 4 (MAIN REACTOR / NEST) : MAX ALIENS +10 +# MPS 4 (MAIN REACTOR / NEST) : ALIENS PER MINUTE +1 +# MPS 4 (MAIN REACTOR / NEST) : INCREASE IN ALIENS PER MINUTE +1 +# SURFACE : MAX ALIENS +25 +# SURFACE : ALIENS PER MINUTE +5 +# SURFACE : INCREASE IN ALIENS PER MINUTE +4 +# ENTRANCE : MAX ALIENS +10 +# ENTRANCE : ALIENS PER MINUTE +2 +# ENTRANCE : INCREASE IN ALIENS PER MINUTE +1 \ No newline at end of file diff --git a/3dc/KSHAPE.H b/3dc/KSHAPE.H new file mode 100644 index 0000000..9282ccd --- /dev/null +++ b/3dc/KSHAPE.H @@ -0,0 +1,134 @@ +#ifndef _kshape_h_ /* Is this your first time? */ +#define _kshape_h_ 1 + +#include "particle.h" + +#define SOFTWARE_RENDERER 0 + +#if SOFTWARE_RENDERER +#include "SoftwareRender.hpp" +#endif + + +typedef struct +{ + /* base coords */ + int X; + int Y; + int Z; + + /* texels and intensity */ + int U; + int V; + + /* coloured components */ + unsigned char R; + unsigned char G; + unsigned char B; + + /* alpha component */ + unsigned char A; + + /* specular colour */ + unsigned char SpecularR; + unsigned char SpecularG; + unsigned char SpecularB; + + /* fog component */ + unsigned char Fog; + + +} RENDERVERTEX; + +typedef struct +{ + /* stamp used for lazy evaluation */ + int Stamp; + + /* colour scalings */ + unsigned char R; + unsigned char G; + unsigned char B; + + /* specular colour */ + unsigned char SpecularR; + unsigned char SpecularG; + unsigned char SpecularB; + + /* fog component */ + unsigned char Fog; + +} COLOURINTENSITIES; + + +typedef struct +{ + RENDERVERTEX Vertices[maxpolypts]; + + unsigned int NumberOfVertices; + + unsigned int MinZ; + unsigned int MaxZ; + + int ImageIndex; + + unsigned char IsTextured :1; + unsigned char IsLit :1; + unsigned char IsSpecularLit :1; + enum TRANSLUCENCY_TYPE TranslucencyMode; + +} RENDERPOLYGON; + +extern RENDERVERTEX VerticesBuffer[9]; +extern RENDERPOLYGON RenderPolygon; + + + + +enum LIGHTING_MODEL_ID +{ + LIGHTING_MODEL_STANDARD, + LIGHTING_MODEL_HIERARCHICAL, + LIGHTING_MODEL_PRELIT, +}; + + + +extern void InitialiseLightIntensityStamps(void); + +extern int FindHeatSourcesInHModel(DISPLAYBLOCK *dispPtr); + + +extern void TranslationSetup(void); +extern void TranslatePointIntoViewspace(VECTORCH *pointPtr); + + +extern void CheckRenderStatesForModule(MODULE *modulePtr); + + + +extern void RenderDecal(DECAL *decalPtr); +extern void RenderParticle(PARTICLE *particlePtr); + +/* KJL 10:25:44 7/23/97 - this offset is used to push back the normal game gfx, +so that the HUD can be drawn over the top without sinking into walls, etc. */ +extern int HeadUpDisplayZOffset; + +/* KJL 16:17:13 11/02/98 - heat source containment */ +typedef struct +{ + VECTORCH Position; +} HEATSOURCE; + +#define MAX_NUMBER_OF_HEAT_SOURCES 10 +extern HEATSOURCE HeatSourceList[]; +extern int NumberOfHeatSources; + +#define MIRRORING_ON 1 + +#if MIRRORING_ON +extern int MirroringActive; +extern int MirroringAxis; +#endif + +#endif \ No newline at end of file diff --git a/3dc/Kshape.bak b/3dc/Kshape.bak new file mode 100644 index 0000000..8e1cbb3 --- /dev/null +++ b/3dc/Kshape.bak @@ -0,0 +1,8501 @@ +/*KJL************************************************************************************ +* kshape.c - replacement for all the pipeline stuff previously done in shape.c & clip.c * +************************************************************************************KJL*/ +#include "3dc.h" +#include +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" + +#include "kshape.h" +#include "kzsort.h" +#include "frustrum.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "equipmnt.h" +#include "bh_pred.h" +#include "bh_marin.h" +#include "bh_corpse.h" +#include "bh_debri.h" +#include "bh_weap.h" +#include "bh_types.h" +#include "pldghost.h" +#include "particle.h" +#include "vision.h" +#include "sfx.h" +#include "d3d_render.h" +#include "avpview.h" +#include "sphere.h" +#include "detaillevels.h" +#include "avp_userprofile.h" + +#if SOFTWARE_RENDERER +#define D3D_ZBufferedGouraudTexturedPolygon_Output Software_ZBufferedGouraudTexturedPolygon_Output +#endif +#define ALIENS_LIFEFORCE_GLOW_COLOUR 0x20ff8080 +#define MARINES_LIFEFORCE_GLOW_COLOUR 0x208080ff +#define PREDATORS_LIFEFORCE_GLOW_COLOUR 0x2080ff80 + +/* KJL 15:02:50 05/14/97 - new max lighting intensity */ +#define MAX_INTENSITY (65536*4-1) + +extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; +extern DISPLAYBLOCK *Global_ODB_Ptr; +extern EXTRAITEMDATA *Global_EID_Ptr; +extern int *Global_EID_IPtr; +extern int ScanDrawMode; +extern int ZBufferMode; +extern int NormalFrameTime; + +extern SHAPEHEADER *Global_ShapeHeaderPtr; +extern int *Global_ShapePoints; +extern int **Global_ShapeItems; +extern int *Global_ShapeNormals; +extern int *Global_ShapeVNormals; +extern int **Global_ShapeTextures; + +extern MATRIXCH LToVMat; +extern EULER LToVMat_Euler; +extern MATRIXCH WToLMat; +extern VECTORCH LocalView; +extern VECTORCH LocalLightCH; + +extern int NumLightSourcesForObject; +extern LIGHTBLOCK *LightSourcesForObject[]; + +#if SupportMorphing +extern MORPHDISPLAY MorphDisplay; +#endif + +extern int VideoModeType; +extern int GlobalAmbience; +extern int NumActiveBlocks; + +extern DISPLAYBLOCK *ActiveBlockList[]; +extern SHAPEHEADER **mainshapelist; + +int MirroringActive=0; +int MirroringAxis=-149*2; + +VECTORCHF FogPosition; +float FogMagnitude; +#define VOLUMETRIC_FOG 0 +#define UNDERWATER 0 +#define SPATIAL_SHOCKWAVE 0 +float CameraZoomScale; + +int DrawFullBright; + +int TripTasticPhase; + +void SetupShapePipeline(void); +void ShapePipeline(SHAPEHEADER *shapePtr); + +static void GouraudPolygon_Construct(POLYHEADER *polyPtr); +static void GouraudPolygon_Output(POLYHEADER *inputPolyPtr, RENDERVERTEX *renderVerticesPtr); + +static void TexturedPolygon_Construct(POLYHEADER *polyPtr); +static void TexturedPolygon_Output(POLYHEADER *inputPolyPtr, RENDERVERTEX *renderVerticesPtr); + + +static void GouraudTexturedPolygon_Construct(POLYHEADER *polyPtr); + +static void (*VertexIntensity)(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_Hierarchical(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_PreLit(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_Pred_Thermal(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_Pred_SeeAliens(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_Pred_SeePredatorTech(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_ImageIntensifier(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_Standard(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_Alien_Sense(RENDERVERTEX *renderVertexPtr); + +static void VertexIntensity_Standard_Opt(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_FullBright(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_DiscoInferno(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_Underwater(RENDERVERTEX *renderVertexPtr); + + +extern void CreateTxAnimUVArray(int *txa_data, int *uv_array, int *shapeitemptr); + +void PredatorThermalVision_ShapePipeline(SHAPEHEADER *shapePtr); +void PredatorSeeAliensVision_ShapePipeline(SHAPEHEADER *shapePtr); +static void CloakedPolygon_Construct(POLYHEADER *polyPtr); +static void PredatorThermalVisionPolygon_Construct(POLYHEADER *polyPtr); +static void PredatorSeeAliensVisionPolygon_Construct(POLYHEADER *polyPtr); +void DoAlienEnergyView(DISPLAYBLOCK *dispPtr); +static void FindAlienEnergySource_Recursion(HMODELCONTROLLER *controllerPtr, SECTION_DATA *sectionDataPtr, unsigned int colour); +void SquishPoints(SHAPEINSTR *shapeinstrptr); +void MorphPoints(SHAPEINSTR *shapeinstrptr); +void TranslateShapeVertices(SHAPEINSTR *shapeinstrptr); +static void ParticlePolygon_Construct(PARTICLE *particlePtr); +void RenderMirroredDecal(DECAL *decalPtr); +static void DecalPolygon_Construct(DECAL *decalPtr); +void RenderShaftOfLight2(MODULE *modulePtr); +void FindIntersectionWithYPlane(VECTORCH *startPtr, VECTORCH *directionPtr, VECTORCH *intersectionPtr); +void FindZFromXYIntersection(VECTORCH *startPtr, VECTORCH *directionPtr, VECTORCH *intersectionPtr); +void AddToTranslucentPolyList(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr); +void DrawWaterFallPoly(VECTORCH *v); + +#if platform_pc +extern int sine[]; +extern int cosine[]; +#endif + + +//extern int ItemCount; + + +/*KJL************************************************************************************ +* N.B. All the following global variables have their first elements initialised so that * +* they will end up in high memory on the Saturn. * +************************************************************************************KJL*/ + +VECTORCH Global_LightVector={1,}; + +/* + Global variables and arrays +*/ + +VECTORCH RotatedPts[maxrotpts]={1,}; +int ItemColour=1; + + + +#if SupportMorphing + +#if (LazyEvaluationForMorphing == No) +VECTORCH MorphedPts[maxmorphPts]; +#endif + + +#endif /* SupportMorphing */ + + +#if Saturn +extern int PolygonSubdivideEntry(POLYHEADER* itemptr); +#endif + +static COLOURINTENSITIES ColourIntensityArray[maxrotpts]; + + + +RENDERPOLYGON RenderPolygon={1,}; +RENDERVERTEX VerticesBuffer[9]={1,}; +static RENDERVERTEX TriangleVerticesBuffer[3]={1,}; + +static int *VertexNumberPtr=(int*)1; + +extern struct KItem KItemList[maxpolyptrs]; +extern int *MorphedObjectPointsPtr; + +#define MAX_NO_OF_TRANSLUCENT_POLYGONS 1000 +RENDERPOLYGON TranslucentPolygons[MAX_NO_OF_TRANSLUCENT_POLYGONS]; +POLYHEADER TranslucentPolygonHeaders[MAX_NO_OF_TRANSLUCENT_POLYGONS]; +int CurrentNumberOfTranslucentPolygons; + +/* KJL 10:25:44 7/23/97 - this offset is used to push back the normal game gfx, +so that the HUD can be drawn over the top without sinking into walls, etc. */ +int HeadUpDisplayZOffset=0; + +extern int CloakingPhase; +static VECTORCH ObjectCentre; +static int HierarchicalObjectsLowestYValue; + +HEATSOURCE HeatSourceList[MAX_NUMBER_OF_HEAT_SOURCES]; +int NumberOfHeatSources; +int CloakingMode; +char CloakedPredatorIsMoving; +static VECTORCH LocalCameraZAxis; + +static int ObjectCounter; + +extern void InitialiseLightIntensityStamps(void) +{ + int i = maxrotpts; + do + { + i--; + ColourIntensityArray[i].Stamp=0; + } + while(i); + ObjectCounter = 0; + +} + + +void SetupShapePipeline(void) +{ + #if VOLUMETRIC_FOG + { +// VECTORCH v = {-30399, -1792, 1050}; // genshd1 +// VECTORCH v = {49937,-4000,-37709}; // hangar +// VECTORCH v = {-185,0,642}; +// VECTORCH v = {6894,469,-13203}; + VECTORCH v = {73608,3582,56211}; + TranslatePointIntoViewspace(&v); + FogPosition.vx = v.vx; + FogPosition.vy = v.vy; + FogPosition.vz = v.vz; + FogMagnitude = FogPosition.vx*FogPosition.vx+FogPosition.vy*FogPosition.vy+FogPosition.vz*FogPosition.vz; + } + #endif + + /* Set up these global pointers */ + Global_ShapePoints = *(Global_ShapeHeaderPtr->points); + Global_ShapeTextures = Global_ShapeHeaderPtr->sh_textures; + + if(Global_ODB_Ptr->ObEIDPtr) + { + Global_EID_Ptr = Global_ODB_Ptr->ObEIDPtr; + Global_EID_IPtr = (int *) Global_ODB_Ptr->ObEIDPtr; + } + else + { + Global_EID_Ptr = Global_ShapeHeaderPtr->sh_extraitemdata; + Global_EID_IPtr = (int *) Global_ShapeHeaderPtr->sh_extraitemdata; + } + + if(Global_ShapeHeaderPtr->sh_normals) + { + Global_ShapeNormals = *(Global_ShapeHeaderPtr->sh_normals); + } + else + { + Global_ShapeNormals = 0; + } + + if(Global_ShapeHeaderPtr->sh_vnormals) + { + Global_ShapeVNormals = *(Global_ShapeHeaderPtr->sh_vnormals); + } + else + { + Global_ShapeVNormals = 0; + } + + + // if((Global_ODB_Ptr->ObStrategyBlock)&&(Global_ODB_Ptr->ObStrategyBlock->I_SBtype == I_BehaviourQueenAlien)) +// Global_ODB_Ptr->ObFlags3 &= ObFlag3_NoLightDot; + + ObjectCounter++; + +} + +void ChooseLightingModel(DISPLAYBLOCK *dispPtr) +{ + LOCALASSERT(dispPtr); + LOCALASSERT(dispPtr->ObShapeData); + + if (DrawFullBright) + { + VertexIntensity = VertexIntensity_FullBright; + } + else if (DISCOINFERNO_CHEATMODE || TRIPTASTIC_CHEATMODE) + { + VertexIntensity = VertexIntensity_DiscoInferno; + } + else if (UNDERWATER_CHEATMODE) + { + VertexIntensity = VertexIntensity_Underwater; + } + else + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + VertexIntensity = VertexIntensity_Standard_Opt; + break; + } + case VISION_MODE_ALIEN_SENSE: + { + VertexIntensity = VertexIntensity_Alien_Sense; + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + VertexIntensity = VertexIntensity_ImageIntensifier; + break; + } + case VISION_MODE_PRED_THERMAL: + { + VertexIntensity = VertexIntensity_Pred_Thermal; + break; + } + case VISION_MODE_PRED_SEEALIENS: + { + VertexIntensity = VertexIntensity_Pred_SeeAliens; + break; + } + case VISION_MODE_PRED_SEEPREDTECH: + { + VertexIntensity = VertexIntensity_Pred_SeePredatorTech; + break; + } + } + } +} + + + +/*KJL********************************************************************************** +* ShapePipeline() - this function processes a shape for rendering by considering each * +* polygon (item) in turn. * +**********************************************************************************KJL*/ +void ShapePipeline(SHAPEHEADER *shapePtr) +{ + int numitems= shapePtr->numitems; + int **itemArrayPtr = shapePtr->items; + #if 0 + char objectCompletelyInView; + #endif + LOCALASSERT(numitems); + + switch(CurrentVisionMode) + { + case VISION_MODE_PRED_THERMAL: + { + /* if we have an object with heat sources, draw it as such */ + if (NumberOfHeatSources)//||((Global_ODB_Ptr->ObStrategyBlock)&&(Global_ODB_Ptr->ObStrategyBlock->I_SBtype == I_BehaviourAlien))) + { + PredatorThermalVision_ShapePipeline(shapePtr); + return; + } + break; + } + case VISION_MODE_PRED_SEEALIENS: + { + STRATEGYBLOCK *sbPtr = Global_ODB_Ptr->ObStrategyBlock; + if(sbPtr) + { + int useVision=0; + switch (sbPtr->I_SBtype) + { + case I_BehaviourAutoGun: + case I_BehaviourAlien: + case I_BehaviourQueenAlien: + case I_BehaviourFaceHugger: + case I_BehaviourPredatorAlien: + case I_BehaviourXenoborg: + { + useVision=1; + break; + } + case I_BehaviourMarine: + { + MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + GLOBALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) + { + useVision=1; + } + break; + } + + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)Global_ODB_Ptr->ObStrategyBlock->SBdataptr; + + if (ghostDataPtr->type==I_BehaviourAlienPlayer || ghostDataPtr->type==I_BehaviourAlien + || (ghostDataPtr->type==I_BehaviourNetCorpse&&ghostDataPtr->subtype==I_BehaviourAlienPlayer) ) + { + useVision=1; + } + break; + } + + case I_BehaviourNetCorpse: + { + NETCORPSEDATABLOCK *corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + if (corpseDataPtr->Android || corpseDataPtr->Type==I_BehaviourAlienPlayer || corpseDataPtr->Type==I_BehaviourAlien) + { + useVision=1; + } + break; + } + case I_BehaviourHierarchicalFragment: + { + HDEBRIS_BEHAV_BLOCK *debrisDataPtr = (HDEBRIS_BEHAV_BLOCK *)sbPtr->SBdataptr; + if (debrisDataPtr->Type==I_BehaviourAlien + ||debrisDataPtr->Type==I_BehaviourQueenAlien + ||debrisDataPtr->Type==I_BehaviourPredatorAlien + ||debrisDataPtr->Type==I_BehaviourAutoGun + ||debrisDataPtr->Android) + { + useVision=1; + } + break; + } + case I_BehaviourSpeargunBolt: + { + SPEAR_BEHAV_BLOCK *spearDataPtr = (SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr; + if (spearDataPtr->SpearThroughFragment) // more flags required! + if (spearDataPtr->Type==I_BehaviourAlien + ||spearDataPtr->Type==I_BehaviourPredatorAlien + ||spearDataPtr->Type==I_BehaviourAutoGun) + { + useVision=1; + } + break; + } + default: + break; + } + + if (useVision) + { + PredatorSeeAliensVision_ShapePipeline(shapePtr); + return; + } + } + break; + } + case VISION_MODE_PRED_SEEPREDTECH: + { + STRATEGYBLOCK *sbPtr = Global_ODB_Ptr->ObStrategyBlock; + if(sbPtr) + { + int useVision=0; + switch (sbPtr->I_SBtype) + { + case I_BehaviourPredator: + { + PREDATOR_STATUS_BLOCK *predData = (PREDATOR_STATUS_BLOCK *)Global_ODB_Ptr->ObStrategyBlock->SBdataptr; + + if (!predData->CloakingEffectiveness) + { + useVision=1; + } + break; + } + case I_BehaviourNPCPredatorDisc: + case I_BehaviourPredatorDisc_SeekTrack: + { + useVision=1; + break; + } + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)Global_ODB_Ptr->ObStrategyBlock->SBdataptr; + + if((ghostDataPtr->CloakingEffectiveness == 0) + && (ghostDataPtr->type==I_BehaviourPredatorPlayer || ghostDataPtr->type==I_BehaviourPredator + || (ghostDataPtr->type==I_BehaviourInanimateObject&&ghostDataPtr->IOType==IOT_Ammo&&ghostDataPtr->subtype==AMMO_PRED_DISC) + || (ghostDataPtr->type==I_BehaviourPredatorDisc_SeekTrack) + || (ghostDataPtr->type==I_BehaviourNetCorpse&&ghostDataPtr->subtype==I_BehaviourPredatorPlayer) )) + { + useVision=1; + } + break; + } + + case I_BehaviourNetCorpse: + { + NETCORPSEDATABLOCK *corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + if (corpseDataPtr->Type==I_BehaviourPredatorPlayer || corpseDataPtr->Type==I_BehaviourPredator) + { + useVision=1; + } + break; + } + case I_BehaviourHierarchicalFragment: + { + HDEBRIS_BEHAV_BLOCK *debrisDataPtr = (HDEBRIS_BEHAV_BLOCK *)sbPtr->SBdataptr; + if (debrisDataPtr->Type==I_BehaviourPredator) + { + useVision=1; + } + break; + } + case I_BehaviourInanimateObject: + { + INANIMATEOBJECT_STATUSBLOCK* objStatPtr = (INANIMATEOBJECT_STATUSBLOCK*) sbPtr->SBdataptr; + + switch(objStatPtr->typeId) + { + case IOT_FieldCharge: + { + useVision = 1; + break; + } + case IOT_Ammo: + { + if (objStatPtr->subType == AMMO_PRED_RIFLE || objStatPtr->subType == AMMO_PRED_DISC) + { + useVision = 1; + } + break; + } + default: + break; + } + break; + } + + default: + break; + } + + if (useVision) + { + PredatorSeeAliensVision_ShapePipeline(shapePtr); + return; + } + } + else if (!Global_ODB_Ptr->ObMyModule) + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + if (!(playerStatusPtr->cloakOn||playerStatusPtr->CloakingEffectiveness!=0)) + { + PredatorSeeAliensVision_ShapePipeline(shapePtr); + return; + } + } + break; + } + default: + break; + } + +// if((Global_ODB_Ptr->ObStrategyBlock)&&(Global_ODB_Ptr->ObStrategyBlock->I_SBtype == I_BehaviourAlien)) + //textprint("shape alien\n"); + #if 0 + objectCompletelyInView = ObjectCompletelyWithinFrustrum(Global_ODB_Ptr); + if(!objectCompletelyInView) TestVerticesWithFrustrum(); + #else + TestVerticesWithFrustrum(); + #endif + + #if 1 + /* interesting hack for predator cloaking */ + if(Global_ODB_Ptr->ObStrategyBlock) + { + PRED_CLOAKSTATE cloakingStatus = PCLOAK_Off; + + if(Global_ODB_Ptr->ObStrategyBlock->I_SBtype == I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)Global_ODB_Ptr->ObStrategyBlock->SBdataptr; + + if(ghostData->CloakingEffectiveness) + { + cloakingStatus = PCLOAK_On; + CloakingMode = ONE_FIXED*5/4-ghostData->CloakingEffectiveness; + } + } + if(Global_ODB_Ptr->ObStrategyBlock->I_SBtype == I_BehaviourPredator) + { + PREDATOR_STATUS_BLOCK *predData = (PREDATOR_STATUS_BLOCK *)Global_ODB_Ptr->ObStrategyBlock->SBdataptr; + + if (predData->CloakingEffectiveness) + { + cloakingStatus = PCLOAK_On; + CloakingMode = ONE_FIXED*5/4-predData->CloakingEffectiveness;//32768; + } + } + + if (cloakingStatus == PCLOAK_On) + { + do + { + POLYHEADER *polyPtr = (POLYHEADER*) (*itemArrayPtr++); + int pif; + #if 0 + if (objectCompletelyInView) + { + pif = PolygonShouldBeDrawn(polyPtr); + } + else + { + pif = PolygonWithinFrustrum(polyPtr); + } + #else + pif = PolygonWithinFrustrum(polyPtr); + #endif + if(pif) + { + + #if 1 + switch(polyPtr->PolyItemType) + { + case I_ZB_Gouraud3dTexturedPolygon: + case I_ZB_Gouraud2dTexturedPolygon: + CloakedPolygon_Construct(polyPtr); + if (pif!=2) + { + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedCloakedPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + else D3D_ZBufferedCloakedPolygon_Output(polyPtr,VerticesBuffer); + break; + default: + textprint("found polygon of type %d\n",polyPtr->PolyItemType); + break; + } + #else + { + CloakedTexturedPolygon_Construct(polyPtr); + if (pif!=2) + { + TexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + TexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + TexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + TexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + TexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_CloakedPredatorPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + else D3D_CloakedPredatorPolygon_Output(polyPtr,VerticesBuffer); + } + #endif + } + } + while(--numitems); + return; + } + } + else if (!Global_ODB_Ptr->ObMyModule) + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + if (playerStatusPtr->cloakOn||playerStatusPtr->CloakingEffectiveness!=0) + { + int a = GetSin(CloakingPhase&4095); + a = MUL_FIXED(a,a); + CloakingMode = ONE_FIXED*5/4-playerStatusPtr->CloakingEffectiveness;//32768; + do + { + POLYHEADER *polyPtr = (POLYHEADER*) (*itemArrayPtr++); + int pif; + pif = PolygonWithinFrustrum(polyPtr); + if(pif) + { + switch(polyPtr->PolyItemType) + { + case I_ZB_Gouraud3dTexturedPolygon: + case I_ZB_Gouraud2dTexturedPolygon: + CloakedPolygon_Construct(polyPtr); + if (pif!=2) + { + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedCloakedPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + else D3D_ZBufferedCloakedPolygon_Output(polyPtr,VerticesBuffer); + break; + default: + textprint("found polygon of type %d\n",polyPtr->PolyItemType); + break; + } + } + } + while(--numitems); + return; + } + + } + #endif + #if 0 +// if (Global_ODB_Ptr->ObStrategyBlock && !Global_ODB_Ptr->ObMyModule) + { + do + { + POLYHEADER *polyPtr = (POLYHEADER*) (*itemArrayPtr++); + int pif; + + pif = PolygonWithinFrustrum(polyPtr); + + if (pif) + { + GouraudPolygon_Construct(polyPtr); + + if (pif!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudPolygon_Output(polyPtr,RenderPolygon.Vertices); + + } + else D3D_ZBufferedGouraudPolygon_Output(polyPtr,VerticesBuffer); + } + } + while(--numitems); + return; + } + #endif + do + { + POLYHEADER *polyPtr = (POLYHEADER*) (*itemArrayPtr++); + int pif; + #if 0 + if (objectCompletelyInView) + { + pif = PolygonShouldBeDrawn(polyPtr); + } + else + { + pif = PolygonWithinFrustrum(polyPtr); + } + #else + pif = PolygonWithinFrustrum(polyPtr); + #endif + + if (pif) + { + switch(polyPtr->PolyItemType) + { + #if debug + case I_Polyline: + case I_FilledPolyline: + case I_Wireframe: + + /* NB This is intended to fall through to the GouraudPolygon case */ + #endif +// case I_Gouraud3dTexturedPolygon: + case I_GouraudPolygon: + case I_Gouraud2dTexturedPolygon: + case I_Gouraud3dTexturedPolygon: + case I_2dTexturedPolygon: + case I_3dTexturedPolygon: + case I_ZB_2dTexturedPolygon: + case I_ZB_3dTexturedPolygon: + { + + // LOCALASSERT(0); + break; + } + case I_ZB_GouraudPolygon: + { +// break; + // LOCALASSERT(0); + GouraudPolygon_Construct(polyPtr); + + if (pif!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudPolygon_Output(polyPtr,RenderPolygon.Vertices); + + } + else D3D_ZBufferedGouraudPolygon_Output(polyPtr,VerticesBuffer); + break; + } + case I_ZB_Gouraud3dTexturedPolygon: + case I_ZB_Gouraud2dTexturedPolygon: + { + GouraudTexturedPolygon_Construct(polyPtr); + if (pif!=2) + { + /* if this polygon is a quad, split it into two */ + if(RenderPolygon.NumberOfVertices==4) + { + RenderPolygon.NumberOfVertices=3; + TriangleVerticesBuffer[0] = VerticesBuffer[0]; + TriangleVerticesBuffer[1] = VerticesBuffer[2]; + TriangleVerticesBuffer[2] = VerticesBuffer[3]; + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) goto SecondTriangle; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) goto SecondTriangle; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) goto SecondTriangle; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) goto SecondTriangle; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) goto SecondTriangle; + + if (polyPtr->PolyFlags & iflag_transparent) + { + AddToTranslucentPolyList(polyPtr,RenderPolygon.Vertices); + } + else + { + D3D_ZBufferedGouraudTexturedPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + + SecondTriangle: + RenderPolygon.NumberOfVertices=3; + VerticesBuffer[0] = TriangleVerticesBuffer[0]; + VerticesBuffer[1] = TriangleVerticesBuffer[1]; + VerticesBuffer[2] = TriangleVerticesBuffer[2]; + } + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + +// polyPtr->PolyFlags |= iflag_transparent; + if (polyPtr->PolyFlags & iflag_transparent) + { + AddToTranslucentPolyList(polyPtr,RenderPolygon.Vertices); + } + else + { + D3D_ZBufferedGouraudTexturedPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + + } + else + { +// polyPtr->PolyFlags |= iflag_transparent; + if (polyPtr->PolyFlags & iflag_transparent) + { + AddToTranslucentPolyList(polyPtr,VerticesBuffer); + } + else + { + D3D_ZBufferedGouraudTexturedPolygon_Output(polyPtr,VerticesBuffer); + } + } + break; + } + default: + break; + } + } + } + while(--numitems); +} + +void PredatorThermalVision_ShapePipeline(SHAPEHEADER *shapePtr) +{ + int numitems= shapePtr->numitems; + int **itemArrayPtr = shapePtr->items; + + LOCALASSERT(numitems); + + TestVerticesWithFrustrum(); + do + { + POLYHEADER *polyPtr = (POLYHEADER*) (*itemArrayPtr++); + + int pif = PolygonWithinFrustrum(polyPtr); + + if (pif) + { + PredatorThermalVisionPolygon_Construct(polyPtr); + + if (pif!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + + D3D_PredatorThermalVisionPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + else D3D_PredatorThermalVisionPolygon_Output(polyPtr,VerticesBuffer); + } + } + while(--numitems); +} +void PredatorSeeAliensVision_ShapePipeline(SHAPEHEADER *shapePtr) +{ + int numitems= shapePtr->numitems; + int **itemArrayPtr = shapePtr->items; + + LOCALASSERT(numitems); + + TestVerticesWithFrustrum(); + do + { + POLYHEADER *polyPtr = (POLYHEADER*) (*itemArrayPtr++); + + switch (polyPtr->PolyItemType) + { + case I_ZB_Gouraud3dTexturedPolygon: + case I_ZB_Gouraud2dTexturedPolygon: + { + int pif = PolygonWithinFrustrum(polyPtr); + + if (pif) + { + PredatorSeeAliensVisionPolygon_Construct(polyPtr); + + #if 0 + if (pif!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + + D3D_PredatorSeeAliensVisionPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + else D3D_PredatorSeeAliensVisionPolygon_Output(polyPtr,VerticesBuffer); + #else + if (pif!=2) + { + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudTexturedPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudTexturedPolygon_Output(polyPtr,VerticesBuffer); + #endif + } + break; + } + default: + break; + } + } + while(--numitems); +} + + +/* CLOAKED POLYGONS */ +static void CloakedPolygon_Construct(POLYHEADER *polyPtr) +{ + int *texture_defn_ptr; + RENDERVERTEX *renderVerticesPtr = VerticesBuffer; + int i = RenderPolygon.NumberOfVertices; + + /* get ptr to uv coords for this polygon */ + { + int texture_defn_index = (polyPtr->PolyColour >> TxDefn); + texture_defn_ptr = Global_ShapeTextures[texture_defn_index]; + } + + VertexNumberPtr = &polyPtr->Poly1stPt; + + /* If this texture is animated the UV array must be calculated */ + if(polyPtr->PolyFlags & iflag_txanim) + { + /* Create the UV array */ + int uv_array[maxpolypts * 2]; + CreateTxAnimUVArray(texture_defn_ptr, uv_array, (int*)polyPtr); + texture_defn_ptr = uv_array; + + do + { + VECTORCH *vertexPtr = &(RotatedPts[*VertexNumberPtr]); + renderVerticesPtr->X = vertexPtr->vx; + renderVerticesPtr->Y = vertexPtr->vy; + renderVerticesPtr->Z = vertexPtr->vz; + renderVerticesPtr->U = texture_defn_ptr[0]; + renderVerticesPtr->V = texture_defn_ptr[1]; + + VertexIntensity(renderVerticesPtr); + { + VECTORCH mag; + int alpha; + mag.vx = vertexPtr->vx - Global_ODB_Ptr->ObView.vx; + mag.vy = vertexPtr->vy - Global_ODB_Ptr->ObView.vy; + mag.vz = vertexPtr->vz - Global_ODB_Ptr->ObView.vz; + + + if (mag.vx<0) mag.vx = -mag.vx; + if (mag.vy<0) mag.vy = -mag.vy; + if (mag.vz<0) mag.vz = -mag.vz; + alpha = GetSin(((mag.vx+mag.vy+mag.vz)*3+CloakingPhase)&4095); + + renderVerticesPtr->A = MUL_FIXED(alpha,alpha)>>10; + + if(renderVerticesPtr->A==255) + { + renderVerticesPtr->R = 255; + renderVerticesPtr->G = 255; + renderVerticesPtr->B = 255; + } + + } + renderVerticesPtr++; + VertexNumberPtr++; + + texture_defn_ptr += 2; + } + while(--i); + } + else + { + do + { + VECTORCH *vertexPtr = &(RotatedPts[*VertexNumberPtr]); + renderVerticesPtr->X = vertexPtr->vx; + renderVerticesPtr->Y = vertexPtr->vy; + renderVerticesPtr->Z = vertexPtr->vz; + renderVerticesPtr->U = texture_defn_ptr[0] << 16; + renderVerticesPtr->V = texture_defn_ptr[1] << 16; + + VertexIntensity(renderVerticesPtr); + { + VECTORCH mag; + int alpha; + + mag.vx = vertexPtr->vx - ObjectCentre.vx; + mag.vy = vertexPtr->vy - MUL_FIXED(ObjectCentre.vy,87381); + mag.vz = vertexPtr->vz - ObjectCentre.vz; + + if (mag.vx<0) mag.vx = -mag.vx; + if (mag.vy<0) mag.vy = -mag.vy; + if (mag.vz<0) mag.vz = -mag.vz; + alpha = GetSin(((mag.vx+mag.vy+mag.vz)*8+CloakingPhase)&4095); + + alpha=MUL_FIXED(alpha,alpha); + if (alpha>CloakingMode) + { + alpha=CloakingMode; + } + alpha/=256; + if (alpha>255) alpha = 255; + renderVerticesPtr->A = alpha; + + if(CloakingMode>ONE_FIXED) + { + alpha = GetSin(((mag.vx+mag.vy+mag.vz)+CloakingPhase)&4095); + alpha = MUL_FIXED(alpha,alpha)>>8; + if(alpha==255) + { + renderVerticesPtr->A = 255; + renderVerticesPtr->G = 128; + renderVerticesPtr->B = 255; + } + } + } + renderVerticesPtr++; + VertexNumberPtr++; + + texture_defn_ptr += 2; + } + while(--i); + } + +} + +static void PredatorThermalVisionPolygon_Construct(POLYHEADER *polyPtr) +{ + RENDERVERTEX *renderVerticesPtr = VerticesBuffer; + int i = RenderPolygon.NumberOfVertices; + + VertexNumberPtr = &polyPtr->Poly1stPt; + + do + { + VECTORCH *vertexPtr = &(RotatedPts[*VertexNumberPtr]); + renderVerticesPtr->X = vertexPtr->vx; + renderVerticesPtr->Y = vertexPtr->vy; + renderVerticesPtr->Z = vertexPtr->vz; + + { + int alpha; + if (Global_ODB_Ptr->SpecialFXFlags&SFXFLAG_ISAFFECTEDBYHEAT) + { + int distanceFromHeatSource = 100000; + int sourceNumber=NumberOfHeatSources; + while(sourceNumber--) + { + VECTORCH mag; + int m; + mag.vx = vertexPtr->vx - HeatSourceList[sourceNumber].Position.vx; + mag.vy = vertexPtr->vy - HeatSourceList[sourceNumber].Position.vy; + mag.vz = vertexPtr->vz - HeatSourceList[sourceNumber].Position.vz; + + m = Approximate3dMagnitude(&mag)*64; + + if(m>3); + if (alpha>65536) alpha = 65536; + } + else + { + alpha = 65536; + } + + { + int brightness = MUL_FIXED(MUL_FIXED(alpha,alpha),1275); + + if (brightness<256) + { + renderVerticesPtr->R=255; + renderVerticesPtr->G=brightness; + renderVerticesPtr->B=0; + } + else if (brightness<255+256) + { + int b=brightness-255; + renderVerticesPtr->R=(255-b); + renderVerticesPtr->G=255; + renderVerticesPtr->B=0; + } + else if (brightness<255*2+256) + { + int b=brightness-255*2; + renderVerticesPtr->R=0; + renderVerticesPtr->G=255; + renderVerticesPtr->B=b; + } + else if (brightness<255*3+256) + { + int b=brightness-255*3; + renderVerticesPtr->R=0; + renderVerticesPtr->G=255-b; + renderVerticesPtr->B=255; + } + else + { + int b=brightness-255*4; + renderVerticesPtr->R=0; + renderVerticesPtr->G=0; + renderVerticesPtr->B=255-b/2; + } + } + } + renderVerticesPtr++; + VertexNumberPtr++; + } + while(--i); +} + +static void PredatorSeeAliensVisionPolygon_Construct(POLYHEADER *polyPtr) +{ + int *texture_defn_ptr; + RENDERVERTEX *renderVerticesPtr = VerticesBuffer; + int i = RenderPolygon.NumberOfVertices; + int alpha; + + VertexNumberPtr = &polyPtr->Poly1stPt; + + { + { + int texture_defn_index = (polyPtr->PolyColour >> TxDefn); + texture_defn_ptr = Global_ShapeTextures[texture_defn_index]; + } + + /* get ptr to uv coords for this polygon */ + if(polyPtr->PolyFlags & iflag_txanim) + { + /* Create the UV array */ + int uv_array[maxpolypts * 2]; + CreateTxAnimUVArray(texture_defn_ptr, uv_array, (int*)polyPtr); + texture_defn_ptr = uv_array; + } + + if( (Global_ODB_Ptr->SpecialFXFlags & SFXFLAG_MELTINGINTOGROUND) + &&(Global_ODB_Ptr->ObFlags2 < ONE_FIXED) ) + { + alpha = Global_ODB_Ptr->ObFlags2 >> 8; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + else + { + alpha = 0; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_OFF; + } + + do + { + VECTORCH *vertexPtr = &(RotatedPts[*VertexNumberPtr]); + + if(polyPtr->PolyFlags & iflag_txanim) + { + renderVerticesPtr->U = texture_defn_ptr[0]; + renderVerticesPtr->V = texture_defn_ptr[1]; + } + else + { + renderVerticesPtr->U = texture_defn_ptr[0] << 16; + renderVerticesPtr->V = texture_defn_ptr[1] << 16; + } + + + renderVerticesPtr->X = vertexPtr->vx; + renderVerticesPtr->Y = vertexPtr->vy; + renderVerticesPtr->Z = vertexPtr->vz; + { + VECTORCH mag = RotatedPts[*VertexNumberPtr];//*(((VECTORCH *)Global_ShapeVNormals) + *VertexNumberPtr); + int colour; + mag.vx = vertexPtr->vx - Global_ODB_Ptr->ObView.vx; + mag.vy = vertexPtr->vy - Global_ODB_Ptr->ObView.vy; + mag.vz = vertexPtr->vz - Global_ODB_Ptr->ObView.vz; + + colour = GetSin(((mag.vx+mag.vy+mag.vz)*8+CloakingPhase)&4095); + colour = MUL_FIXED(colour,colour); + renderVerticesPtr->B = MUL_FIXED(colour,255); + renderVerticesPtr->R = renderVerticesPtr->B/2; + renderVerticesPtr->G = renderVerticesPtr->B/2; + + colour = MUL_FIXED(colour,colour); + colour = MUL_FIXED(colour,colour); + + renderVerticesPtr->SpecularR = colour/1024; + renderVerticesPtr->SpecularG = colour/1024; + renderVerticesPtr->SpecularB = colour/1024; + renderVerticesPtr->A = alpha; + } + + texture_defn_ptr += 2; + renderVerticesPtr++; + VertexNumberPtr++; + } + while(--i); + } +} + +/* GOURAUD POLYGONS */ +static void GouraudPolygon_Construct(POLYHEADER *polyPtr) +{ + RENDERVERTEX *renderVerticesPtr = VerticesBuffer; + int i = RenderPolygon.NumberOfVertices; + VertexNumberPtr = &polyPtr->Poly1stPt; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_OFF; + + do + { + int i; + renderVerticesPtr->X = RotatedPts[*VertexNumberPtr].vx; + renderVerticesPtr->Y = RotatedPts[*VertexNumberPtr].vy; + renderVerticesPtr->Z = RotatedPts[*VertexNumberPtr].vz; + VertexIntensity(renderVerticesPtr); + i = (renderVerticesPtr->B+renderVerticesPtr->R+renderVerticesPtr->G)/3; + renderVerticesPtr->R = i; + renderVerticesPtr->G = i; + renderVerticesPtr->B = 0; + renderVerticesPtr++; + VertexNumberPtr++; + } + while(--i); + +} + + + + + + +/* GOURAUD TEXTURED POLYGONS */ +static void GouraudTexturedPolygon_Construct(POLYHEADER *polyPtr) +{ + int *texture_defn_ptr; + RENDERVERTEX *renderVerticesPtr = VerticesBuffer; + int i = RenderPolygon.NumberOfVertices; + + + /* get ptr to uv coords for this polygon */ + { + int texture_defn_index = (polyPtr->PolyColour >> TxDefn); + texture_defn_ptr = Global_ShapeTextures[texture_defn_index]; + } + + VertexNumberPtr = &polyPtr->Poly1stPt; + + /* If this texture is animated the UV array must be calculated */ + if(polyPtr->PolyFlags & iflag_txanim) + { + /* Create the UV array */ + int uv_array[maxpolypts * 2]; + CreateTxAnimUVArray(texture_defn_ptr, uv_array, (int*)polyPtr); + texture_defn_ptr = uv_array; + + do + { + VECTORCH *vertexPtr = &(RotatedPts[*VertexNumberPtr]); + if (TRIPTASTIC_CHEATMODE) + { + renderVerticesPtr->X = vertexPtr->vx+GetSin((CloakingPhase*2 +vertexPtr->vz)&4095)/1024; + renderVerticesPtr->Y = vertexPtr->vy+GetSin((CloakingPhase-3000 +vertexPtr->vx)&4095)/1024; + renderVerticesPtr->Z = vertexPtr->vz+GetSin((CloakingPhase*3+239+vertexPtr->vy)&4095)/1024; + } + else if (UNDERWATER_CHEATMODE) + { + renderVerticesPtr->X = vertexPtr->vx+(GetSin((CloakingPhase/2 +vertexPtr->vz)&4095))/1024; + renderVerticesPtr->Y = vertexPtr->vy+(GetSin((CloakingPhase-3000+vertexPtr->vx)&4095))/1024; + renderVerticesPtr->Z = vertexPtr->vz+(GetSin((CloakingPhase/3+239+vertexPtr->vy)&4095))/1024; + } + else + { + renderVerticesPtr->X = vertexPtr->vx; + renderVerticesPtr->Y = vertexPtr->vy; + renderVerticesPtr->Z = vertexPtr->vz; + } + renderVerticesPtr->U = texture_defn_ptr[0]; + renderVerticesPtr->V = texture_defn_ptr[1]; + + if( (Global_ODB_Ptr->SpecialFXFlags & SFXFLAG_MELTINGINTOGROUND) + &&(Global_ODB_Ptr->ObFlags2 < ONE_FIXED) ) + { + renderVerticesPtr->A = Global_ODB_Ptr->ObFlags2 >> 8; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + + } + else if (polyPtr->PolyFlags & iflag_transparent) + { + renderVerticesPtr->A = 128; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + else + { + if (TRIPTASTIC_CHEATMODE) + { + renderVerticesPtr->A = TripTasticPhase; + } + else if (MOTIONBLUR_CHEATMODE) + { + renderVerticesPtr->A = 128; + } + else + { + renderVerticesPtr->A = 255; + } + RenderPolygon.TranslucencyMode = TRANSLUCENCY_OFF; + } + + if (polyPtr->PolyFlags & iflag_nolight) + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + renderVerticesPtr->R = 255; + renderVerticesPtr->G = 255; + renderVerticesPtr->B = 255; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + renderVerticesPtr->R = 0; + renderVerticesPtr->G = 255; + renderVerticesPtr->B = 0; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_PRED_THERMAL: + { + renderVerticesPtr->R = 0; + renderVerticesPtr->G = 0; + renderVerticesPtr->B = 255; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_PRED_SEEALIENS: + { + renderVerticesPtr->R = 255; + renderVerticesPtr->G = 0; + renderVerticesPtr->B = 0; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_PRED_SEEPREDTECH: + { + renderVerticesPtr->R = 0; + renderVerticesPtr->G = 255; + renderVerticesPtr->B = 0; + renderVerticesPtr->SpecularR = 255; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 255; + break; + } + } + + } + else + { + VertexIntensity(renderVerticesPtr); + } + renderVerticesPtr++; + VertexNumberPtr++; + + texture_defn_ptr += 2; + } + while(--i); + } + else + { + do + { + VECTORCH *vertexPtr = &(RotatedPts[*VertexNumberPtr]); + #if UNDERWATER + renderVerticesPtr->X = vertexPtr->vx+GetSin((CloakingPhase*2 +vertexPtr->vz)&4095)/1024; + renderVerticesPtr->Y = vertexPtr->vy+GetSin((CloakingPhase-3000 +vertexPtr->vx)&4095)/1024; + renderVerticesPtr->Z = vertexPtr->vz+GetSin((CloakingPhase*3+239+vertexPtr->vy)&4095)/1024; + #elif SPATIAL_SHOCKWAVE + { + int d = Magnitude(vertexPtr); + int a = (CloakingPhase&16383)+4000; + int u = d-a; + int offset; + + if (u>0 && u<8192) + { + VECTORCH n = *vertexPtr; + Normalise(&n); + u<<=3; + offset = MUL_FIXED(MUL_FIXED(2*u,ONE_FIXED-u),8000) + MUL_FIXED(MUL_FIXED(u,u),8192 ); + LOCALASSERT(offset>=0 && offset<=8192); + renderVerticesPtr->X = MUL_FIXED(n.vx,d);//a+offset*2); + renderVerticesPtr->Y = MUL_FIXED(n.vy,d);//a+offset*2); + renderVerticesPtr->Z = MUL_FIXED(n.vz,a+offset); + + } + else + { + renderVerticesPtr->X = vertexPtr->vx; + renderVerticesPtr->Y = vertexPtr->vy; + renderVerticesPtr->Z = vertexPtr->vz; + } + + } + #else + if (TRIPTASTIC_CHEATMODE) + { + renderVerticesPtr->X = vertexPtr->vx+GetSin((CloakingPhase*2 +vertexPtr->vz)&4095)/1024; + renderVerticesPtr->Y = vertexPtr->vy+GetSin((CloakingPhase-3000 +vertexPtr->vx)&4095)/1024; + renderVerticesPtr->Z = vertexPtr->vz+GetSin((CloakingPhase*3+239+vertexPtr->vy)&4095)/1024; + } + else if (UNDERWATER_CHEATMODE) + { + renderVerticesPtr->X = vertexPtr->vx+(GetSin((CloakingPhase/2 +vertexPtr->vz)&4095))/1024; + renderVerticesPtr->Y = vertexPtr->vy+(GetSin((CloakingPhase-3000 +vertexPtr->vx)&4095))/1024; + renderVerticesPtr->Z = vertexPtr->vz+(GetSin((CloakingPhase/3+239+vertexPtr->vy)&4095))/1024; + } + else + { + renderVerticesPtr->X = vertexPtr->vx; + renderVerticesPtr->Y = vertexPtr->vy; + renderVerticesPtr->Z = vertexPtr->vz; + } + #endif + renderVerticesPtr->U = texture_defn_ptr[0] << 16; + renderVerticesPtr->V = texture_defn_ptr[1] << 16; + + if( (Global_ODB_Ptr->SpecialFXFlags & SFXFLAG_MELTINGINTOGROUND) + &&(Global_ODB_Ptr->ObFlags2 < ONE_FIXED) ) + { + renderVerticesPtr->A = Global_ODB_Ptr->ObFlags2 >> 8; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + + } + else if (polyPtr->PolyFlags & iflag_transparent) + { + renderVerticesPtr->A = 128; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + else + { + #if 0 + VECTORCH velocity; + int a; + velocity.vx = Player->ObStrategyBlock->DynPtr->Position.vx - Player->ObStrategyBlock->DynPtr->PrevPosition.vx; + velocity.vy = Player->ObStrategyBlock->DynPtr->Position.vy - Player->ObStrategyBlock->DynPtr->PrevPosition.vy; + velocity.vz = Player->ObStrategyBlock->DynPtr->Position.vz - Player->ObStrategyBlock->DynPtr->PrevPosition.vz; + a = DIV_FIXED(Magnitude(&velocity)*4,NormalFrameTime)/256; + if (a>192) a = 192; + renderVerticesPtr->A = a; + + #elif 1 + if (TRIPTASTIC_CHEATMODE) + { + renderVerticesPtr->A = TripTasticPhase; + } + else if (MOTIONBLUR_CHEATMODE) + { + renderVerticesPtr->A = 128; + } + else + { + renderVerticesPtr->A = 255; + } + #endif + + RenderPolygon.TranslucencyMode = TRANSLUCENCY_OFF; + } + + + if (polyPtr->PolyFlags & iflag_nolight) + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + renderVerticesPtr->R = 255; + renderVerticesPtr->G = 255; + renderVerticesPtr->B = 255; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + renderVerticesPtr->R = 0; + renderVerticesPtr->G = 255; + renderVerticesPtr->B = 0; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_PRED_THERMAL: + { + renderVerticesPtr->R = 0; + renderVerticesPtr->G = 0; + renderVerticesPtr->B = 255; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_PRED_SEEALIENS: + { + renderVerticesPtr->R = 255; + renderVerticesPtr->G = 0; + renderVerticesPtr->B = 0; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_PRED_SEEPREDTECH: + { + renderVerticesPtr->R = 0; + renderVerticesPtr->G = 255; + renderVerticesPtr->B = 0; + renderVerticesPtr->SpecularR = 255; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 255; + break; + } + } + + } + else + { + VertexIntensity(renderVerticesPtr); + } + renderVerticesPtr++; + VertexNumberPtr++; + + texture_defn_ptr += 2; + } + while(--i); + } + +} + + + + + +static void VertexIntensity_Pred_Thermal(RENDERVERTEX *renderVertexPtr) +{ + int redI,blueI,specular=0; + + int vertexNumber = *VertexNumberPtr; + + + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = ColourIntensityArray[vertexNumber].SpecularR; + renderVertexPtr->SpecularG = ColourIntensityArray[vertexNumber].SpecularG; + renderVertexPtr->SpecularB = ColourIntensityArray[vertexNumber].SpecularB; + return; + } + { + VECTORCH *vertexNormalPtr = ((VECTORCH *)Global_ShapeVNormals) + vertexNumber; + VECTORCH *vertexPtr = ((VECTORCH *)Global_ShapePoints)+vertexNumber; + LIGHTBLOCK **larrayptr; + LIGHTBLOCK *lptr; + int i; + + redI = 0; + + larrayptr = LightSourcesForObject; + + for(i = NumLightSourcesForObject; i!=0; i--) + { + + VECTORCH vertexToLight; + int distanceToLight; + + lptr = *larrayptr++; + + if (lptr->LightFlags & LFlag_PreLitSource) continue; + + vertexToLight.vx = lptr->LocalLP.vx - vertexPtr->vx; + vertexToLight.vy = lptr->LocalLP.vy - vertexPtr->vy; + vertexToLight.vz = lptr->LocalLP.vz - vertexPtr->vz; + + #if 0 + distanceToLight = Approximate3dMagnitude(&vertexToLight)/2; + #else + distanceToLight = Approximate3dMagnitude(&vertexToLight); + #endif + if(distanceToLight < lptr->LightRange) + { + int idot = MUL_FIXED(lptr->LightRange-distanceToLight,lptr->BrightnessOverRange); + + if( (distanceToLight>0) && (!(Global_ODB_Ptr->ObFlags3 & ObFlag3_NoLightDot)) ) + { + int dotproduct = MUL_FIXED(vertexNormalPtr->vx,vertexToLight.vx) + + MUL_FIXED(vertexNormalPtr->vy,vertexToLight.vy) + + MUL_FIXED(vertexNormalPtr->vz,vertexToLight.vz); + if(dotproduct>0) + { + idot = WideMulNarrowDiv(idot,dotproduct,distanceToLight); + } + else + { + idot = 0; + } + + idot = WideMulNarrowDiv(idot,dotproduct,distanceToLight); + } + + + redI += idot; + if (lptr->LightFlags&LFlag_Thermal) + { + specular += idot; + } + } + } + } + blueI = ONE_FIXED/2; + if (renderVertexPtr->Z>5000) + { + int a = (renderVertexPtr->Z-5000); + if (a>4096) blueI = (blueI*4096)/a; + } + + blueI >>= 8; + + if(redI >= ONE_FIXED) redI = (ONE_FIXED - 1); + redI >>=8; + + specular>>=6; + if (specular >= 255) specular = 255; + + /* KJL 12:41:54 05/10/98 - red/green swapped, whilst testing colours */ + renderVertexPtr->R = 0; + ColourIntensityArray[vertexNumber].R = 0; + renderVertexPtr->B = blueI; + ColourIntensityArray[vertexNumber].B = blueI; + renderVertexPtr->G = redI/2; + ColourIntensityArray[vertexNumber].G = redI/2; + + + renderVertexPtr->SpecularR = specular;//specularR; + ColourIntensityArray[vertexNumber].SpecularR = specular;//specularR; + + renderVertexPtr->SpecularG = specular; + ColourIntensityArray[vertexNumber].SpecularG = specular; + + renderVertexPtr->SpecularB = specular;//specularB; + ColourIntensityArray[vertexNumber].SpecularB = specular;//specularB; + + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; +} +static void VertexIntensity_Pred_SeeAliens(RENDERVERTEX *renderVertexPtr) +{ + int redI,blueI,specular=0; + + int vertexNumber = *VertexNumberPtr; + + + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = ColourIntensityArray[vertexNumber].SpecularR; + renderVertexPtr->SpecularG = ColourIntensityArray[vertexNumber].SpecularG; + renderVertexPtr->SpecularB = ColourIntensityArray[vertexNumber].SpecularB; + return; + } + + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; + + { + VECTORCH *vertexPtr = ((VECTORCH *)Global_ShapePoints)+vertexNumber; + LIGHTBLOCK **larrayptr; + LIGHTBLOCK *lptr; + int i; + + redI = 0; + + larrayptr = LightSourcesForObject; + + for(i = NumLightSourcesForObject; i!=0; i--) + { + + VECTORCH vertexToLight; + int distanceToLight; + + lptr = *larrayptr++; + + if (lptr->LightFlags & LFlag_PreLitSource) continue; + + vertexToLight.vx = lptr->LocalLP.vx - vertexPtr->vx; + vertexToLight.vy = lptr->LocalLP.vy - vertexPtr->vy; + vertexToLight.vz = lptr->LocalLP.vz - vertexPtr->vz; + + distanceToLight = Approximate3dMagnitude(&vertexToLight); + if(distanceToLight < lptr->LightRange) + { + int idot = MUL_FIXED(lptr->LightRange-distanceToLight,lptr->BrightnessOverRange); + + redI += idot; + if(lptr->LightFlags&LFlag_Electrical) + { + specular += idot; + } + } + } + } + redI >>=11; + if(redI > 255) redI = 255; + renderVertexPtr->G = redI; + ColourIntensityArray[vertexNumber].G = redI; + + + blueI = ONE_FIXED/2; + if (renderVertexPtr->Z>5000) + { + int a = (renderVertexPtr->Z-5000); + if (a>4096) blueI = (blueI*4096)/a; + } + /* KJL 12:41:54 05/10/98 - red/green swapped, whilst testing colours */ + blueI >>= 9; + renderVertexPtr->R = blueI; + ColourIntensityArray[vertexNumber].R = blueI; + renderVertexPtr->B = 0; + ColourIntensityArray[vertexNumber].B = 0; + + specular >>=10; + if(specular>255) specular = 255; + renderVertexPtr->SpecularR = specular;//specularR; + ColourIntensityArray[vertexNumber].SpecularR = specular;//specularR; + renderVertexPtr->SpecularG = specular; + ColourIntensityArray[vertexNumber].SpecularG = specular; + renderVertexPtr->SpecularB = specular;//specularB; + ColourIntensityArray[vertexNumber].SpecularB = specular;//specularB; +} +static void VertexIntensity_Pred_SeePredatorTech(RENDERVERTEX *renderVertexPtr) +{ + int redI,blueI; + + int vertexNumber = *VertexNumberPtr; + + + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = ColourIntensityArray[vertexNumber].SpecularR; + renderVertexPtr->SpecularG = ColourIntensityArray[vertexNumber].SpecularG; + renderVertexPtr->SpecularB = ColourIntensityArray[vertexNumber].SpecularB; + return; + } + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; + { + VECTORCH *vertexPtr = ((VECTORCH *)Global_ShapePoints)+vertexNumber; + LIGHTBLOCK **larrayptr; + LIGHTBLOCK *lptr; + int i; + + redI = 0; + + larrayptr = LightSourcesForObject; + + for(i = NumLightSourcesForObject; i!=0; i--) + { + + VECTORCH vertexToLight; + int distanceToLight; + + lptr = *larrayptr++; + + if (lptr->LightFlags & LFlag_PreLitSource) continue; + + vertexToLight.vx = lptr->LocalLP.vx - vertexPtr->vx; + vertexToLight.vy = lptr->LocalLP.vy - vertexPtr->vy; + vertexToLight.vz = lptr->LocalLP.vz - vertexPtr->vz; + + distanceToLight = Approximate3dMagnitude(&vertexToLight); + if(distanceToLight < lptr->LightRange) + { + int idot = MUL_FIXED(lptr->LightRange-distanceToLight,lptr->BrightnessOverRange); + + redI += idot; + } + } + } + blueI = ONE_FIXED-1; + if (renderVertexPtr->Z>5000) + { + int a = (renderVertexPtr->Z-5000); + if (a>4096) blueI = (blueI*4096)/a; + } + + blueI >>=8; + + redI >>=9; + if (redI>255) redI=255; + + /* KJL 12:41:54 05/10/98 - red/green swapped, whilst testing colours */ + renderVertexPtr->R = 255; + ColourIntensityArray[vertexNumber].R = 255; + renderVertexPtr->B = 255; + ColourIntensityArray[vertexNumber].B = 255; + renderVertexPtr->G = blueI; + ColourIntensityArray[vertexNumber].G = blueI; + + + renderVertexPtr->SpecularR = 255;//specularR; + ColourIntensityArray[vertexNumber].SpecularR = 255;//specularR; + + renderVertexPtr->SpecularG = redI; + ColourIntensityArray[vertexNumber].SpecularG = redI; + + renderVertexPtr->SpecularB = 255;//specularB; + ColourIntensityArray[vertexNumber].SpecularB = 255;//specularB; + +} +static void VertexIntensity_ImageIntensifier(RENDERVERTEX *renderVertexPtr) +{ + int greenI; + int specular; + + int vertexNumber = *VertexNumberPtr; + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = ColourIntensityArray[vertexNumber].SpecularR; + renderVertexPtr->SpecularG = ColourIntensityArray[vertexNumber].SpecularG; + renderVertexPtr->SpecularB = ColourIntensityArray[vertexNumber].SpecularB; + return; + } + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; + + { + VECTORCH *vertexNormalPtr = ((VECTORCH *)Global_ShapeVNormals) + vertexNumber; + VECTORCH *vertexPtr = ((VECTORCH *)Global_ShapePoints)+vertexNumber; + + LIGHTBLOCK **larrayptr; + LIGHTBLOCK *lptr; + int i; + + greenI = 0; + specular = 0; + + larrayptr = LightSourcesForObject; + + for(i = NumLightSourcesForObject; i!=0; i--) + { + + VECTORCH vertexToLight; + int distanceToLight; + + lptr = *larrayptr++; + + vertexToLight.vx = lptr->LocalLP.vx - vertexPtr->vx; + vertexToLight.vy = lptr->LocalLP.vy - vertexPtr->vy; + vertexToLight.vz = lptr->LocalLP.vz - vertexPtr->vz; + { + int dx,dy,dz; + + dx = vertexToLight.vx; + if (dx<0) dx = -dx; + + dy = vertexToLight.vy; + if (dy<0) dy = -dy; + + dz = vertexToLight.vz; + if (dz<0) dz = -dz; + + + if (dx>dy) + { + if (dx>dz) + { + distanceToLight = dx + ((dy+dz)>>2); + } + else + { + distanceToLight = dz + ((dy+dx)>>2); + } + } + else + { + if (dy>dz) + { + distanceToLight = dy + ((dx+dz)>>2); + } + else + { + distanceToLight = dz + ((dx+dy)>>2); + } + } + } + + if(distanceToLight < lptr->LightRange) + { + int idot = MUL_FIXED(lptr->LightRange-distanceToLight,lptr->BrightnessOverRange); + + if(distanceToLight>0) + { + int dotproduct = MUL_FIXED(vertexNormalPtr->vx,vertexToLight.vx) + + MUL_FIXED(vertexNormalPtr->vy,vertexToLight.vy) + + MUL_FIXED(vertexNormalPtr->vz,vertexToLight.vz); + + if(dotproduct>0) + { + idot = (WideMulNarrowDiv(idot,dotproduct,distanceToLight)+idot/4); + } + else + { + idot /= 4; + } + } + if(idot<0) + { + LOCALASSERT(idot>=0); + } + specular += idot; + } + } + } + + greenI = 255; + if (renderVertexPtr->Z>5000) + { + int a = (renderVertexPtr->Z-5000); + if (a>4096) greenI = (greenI*4096)/a; + } + renderVertexPtr->G = greenI; + ColourIntensityArray[vertexNumber].G = greenI; + + renderVertexPtr->R = 0; + ColourIntensityArray[vertexNumber].R = 0; + renderVertexPtr->B = 0; + ColourIntensityArray[vertexNumber].B = 0; + + specular>>=7; + if (specular>254) specular=254; + LOCALASSERT(specular>=0 && specular<=254); + renderVertexPtr->SpecularR = specular; + ColourIntensityArray[vertexNumber].SpecularR = specular; + renderVertexPtr->SpecularG = specular; + ColourIntensityArray[vertexNumber].SpecularG = specular; + renderVertexPtr->SpecularB = specular; + ColourIntensityArray[vertexNumber].SpecularB = specular; + +} + +static void VertexIntensity_Alien_Sense(RENDERVERTEX *renderVertexPtr) +{ + int intensity; + int vertexNumber = *VertexNumberPtr; + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = 0; + renderVertexPtr->SpecularG = 0; + renderVertexPtr->SpecularB = 0; + return; + } + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; + + intensity = 255; + if (renderVertexPtr->Z>5000) + { + int a = (renderVertexPtr->Z-5000); + if (a>1024) intensity = (intensity*1024)/a; + } + + renderVertexPtr->R = intensity; + ColourIntensityArray[vertexNumber].R = intensity; + + renderVertexPtr->G = intensity; + ColourIntensityArray[vertexNumber].G = intensity; + + renderVertexPtr->B = intensity; + ColourIntensityArray[vertexNumber].B = intensity; + + renderVertexPtr->SpecularR = 0; + renderVertexPtr->SpecularG = 0; + renderVertexPtr->SpecularB = 0; + +} + + + +static void VertexIntensity_Standard_Opt(RENDERVERTEX *renderVertexPtr) +{ + int redI,greenI,blueI; + int specularR,specularG,specularB; + + int vertexNumber = *VertexNumberPtr; + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = ColourIntensityArray[vertexNumber].SpecularR; + renderVertexPtr->SpecularG = ColourIntensityArray[vertexNumber].SpecularG; + renderVertexPtr->SpecularB = ColourIntensityArray[vertexNumber].SpecularB; + return; + } + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; + { + VECTORCH *vertexNormalPtr = ((VECTORCH *)Global_ShapeVNormals) + vertexNumber; + VECTORCH *vertexPtr = ((VECTORCH *)Global_ShapePoints)+vertexNumber; + + LIGHTBLOCK **larrayptr; + LIGHTBLOCK *lptr; + int i; + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_PreLit) + { + unsigned int packedI = Global_EID_IPtr[vertexNumber]; + blueI = (packedI&255)*257; + + packedI >>=8; + greenI = (packedI&255)*257; + + packedI >>=8; + redI = (packedI&255)*257; + } + else + { + redI = 0; + greenI = 0; + blueI = 0; + } + + specularR = 0; + specularG = 0; + specularB = 0; + + + + larrayptr = LightSourcesForObject; + + for(i = NumLightSourcesForObject; i!=0; i--) + { + + VECTORCH vertexToLight; + int distanceToLight; + + lptr = *larrayptr++; + + vertexToLight.vx = lptr->LocalLP.vx - vertexPtr->vx; + vertexToLight.vy = lptr->LocalLP.vy - vertexPtr->vy; + vertexToLight.vz = lptr->LocalLP.vz - vertexPtr->vz; + { + int dx,dy,dz; + + dx = vertexToLight.vx; + if (dx<0) dx = -dx; + + dy = vertexToLight.vy; + if (dy<0) dy = -dy; + + dz = vertexToLight.vz; + if (dz<0) dz = -dz; + + + if (dx>dy) + { + if (dx>dz) + { + distanceToLight = dx + ((dy+dz)>>2); + } + else + { + distanceToLight = dz + ((dy+dx)>>2); + } + } + else + { + if (dy>dz) + { + distanceToLight = dy + ((dx+dz)>>2); + } + else + { + distanceToLight = dz + ((dx+dy)>>2); + } + } + } + + if(distanceToLight < lptr->LightRange) + { + int idot = MUL_FIXED(lptr->LightRange-distanceToLight,lptr->BrightnessOverRange); + int r,g,b; + + if(distanceToLight>0) + { + int dotproduct = MUL_FIXED(vertexNormalPtr->vx,vertexToLight.vx) + + MUL_FIXED(vertexNormalPtr->vy,vertexToLight.vy) + + MUL_FIXED(vertexNormalPtr->vz,vertexToLight.vz); + + if(dotproduct>0) + { + idot = (WideMulNarrowDiv(idot,dotproduct,distanceToLight)+idot/4)/2; + } + else + { + idot /= 8; + } + } + + r = MUL_FIXED(idot,lptr->RedScale); + g = MUL_FIXED(idot,lptr->GreenScale); + b = MUL_FIXED(idot,lptr->BlueScale); + + redI += r; + greenI += g; + blueI += b; + + if( !(lptr->LightFlags & LFlag_PreLitSource) + && !(lptr->LightFlags & LFlag_NoSpecular) ) + { + specularR += r; + specularG += g; + specularB += b; + } + } + } + } + + if(Global_ODB_Ptr->SpecialFXFlags & SFXFLAG_ONFIRE) + { + specularR>>=2; + specularG>>=2; + specularB>>=2; + + redI>>=1; + greenI>>=1; + blueI>>=1; + } + + /* Intensity for Textures */ + redI >>= 8; + if(redI > 255) redI = 255; + renderVertexPtr->R = redI; + ColourIntensityArray[vertexNumber].R = redI; + + greenI >>= 8; + if(greenI > 255) greenI = 255; + renderVertexPtr->G = greenI; + ColourIntensityArray[vertexNumber].G = greenI; + + blueI >>= 8; + if(blueI > 255) blueI = 255; + renderVertexPtr->B = blueI; + ColourIntensityArray[vertexNumber].B = blueI; + + specularR >>= 10; + if(specularR > 255) specularR = 255; + renderVertexPtr->SpecularR = specularR; + ColourIntensityArray[vertexNumber].SpecularR = specularR; + + specularG >>= 10; + if(specularG > 255) specularG = 255; + renderVertexPtr->SpecularG = specularG; + ColourIntensityArray[vertexNumber].SpecularG = specularG; + + specularB >>= 10; + if(specularB > 255) specularB = 255; + renderVertexPtr->SpecularB = specularB; + ColourIntensityArray[vertexNumber].SpecularB = specularB; + +} +static void VertexIntensity_FullBright(RENDERVERTEX *renderVertexPtr) +{ + int vertexNumber = *VertexNumberPtr; + renderVertexPtr->R = 255; + ColourIntensityArray[vertexNumber].R = 255; + renderVertexPtr->G = 255; + ColourIntensityArray[vertexNumber].G = 255; + renderVertexPtr->B = 255; + ColourIntensityArray[vertexNumber].B = 255; + + renderVertexPtr->SpecularR = 0; + ColourIntensityArray[vertexNumber].SpecularR = 0; + renderVertexPtr->SpecularG = 0; + ColourIntensityArray[vertexNumber].SpecularG = 0; + renderVertexPtr->SpecularB = 0; + ColourIntensityArray[vertexNumber].SpecularB = 0; +} + +static void VertexIntensity_DiscoInferno(RENDERVERTEX *renderVertexPtr) +{ + int redI,greenI,blueI; + int specularR,specularG,specularB; + + int vertexNumber = *VertexNumberPtr; + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = ColourIntensityArray[vertexNumber].SpecularR; + renderVertexPtr->SpecularG = ColourIntensityArray[vertexNumber].SpecularG; + renderVertexPtr->SpecularB = ColourIntensityArray[vertexNumber].SpecularB; + return; + } + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; + { + VECTORCH *vertexNormalPtr = ((VECTORCH *)Global_ShapeVNormals) + vertexNumber; + VECTORCH *vertexPtr = ((VECTORCH *)Global_ShapePoints)+vertexNumber; + + LIGHTBLOCK **larrayptr; + LIGHTBLOCK *lptr; + int i; + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_PreLit) + { + unsigned int packedI = Global_EID_IPtr[vertexNumber]; + blueI = (packedI&255)*257; + + packedI >>=8; + greenI = (packedI&255)*257; + + packedI >>=8; + redI = (packedI&255)*257; + } + else + { + redI = 0; + greenI = 0; + blueI = 0; + } + + specularR = 0; + specularG = 0; + specularB = 0; + + + + larrayptr = LightSourcesForObject; + + for(i = NumLightSourcesForObject; i!=0; i--) + { + + VECTORCH vertexToLight; + int distanceToLight; + + lptr = *larrayptr++; + + vertexToLight.vx = lptr->LocalLP.vx - vertexPtr->vx; + vertexToLight.vy = lptr->LocalLP.vy - vertexPtr->vy; + vertexToLight.vz = lptr->LocalLP.vz - vertexPtr->vz; + { + int dx,dy,dz; + + dx = vertexToLight.vx; + if (dx<0) dx = -dx; + + dy = vertexToLight.vy; + if (dy<0) dy = -dy; + + dz = vertexToLight.vz; + if (dz<0) dz = -dz; + + + if (dx>dy) + { + if (dx>dz) + { + distanceToLight = dx + ((dy+dz)>>2); + } + else + { + distanceToLight = dz + ((dy+dx)>>2); + } + } + else + { + if (dy>dz) + { + distanceToLight = dy + ((dx+dz)>>2); + } + else + { + distanceToLight = dz + ((dx+dy)>>2); + } + } + } + + if(distanceToLight < lptr->LightRange) + { + int idot = MUL_FIXED(lptr->LightRange-distanceToLight,lptr->BrightnessOverRange); + int r,g,b; + + if(distanceToLight>0) + { + int dotproduct = MUL_FIXED(vertexNormalPtr->vx,vertexToLight.vx) + + MUL_FIXED(vertexNormalPtr->vy,vertexToLight.vy) + + MUL_FIXED(vertexNormalPtr->vz,vertexToLight.vz); + + if(dotproduct>0) + { + idot = (WideMulNarrowDiv(idot,dotproduct,distanceToLight)+idot/4)/2; + } + else + { + idot /= 8; + } + } + + r = MUL_FIXED(idot,lptr->RedScale); + g = MUL_FIXED(idot,lptr->GreenScale); + b = MUL_FIXED(idot,lptr->BlueScale); + + redI += r; + greenI += g; + blueI += b; + + if( !(lptr->LightFlags & LFlag_PreLitSource) + && !(lptr->LightFlags & LFlag_NoSpecular) ) + { + specularR += r; + specularG += g; + specularB += b; + } + } + } + } + + if(Global_ODB_Ptr->SpecialFXFlags & SFXFLAG_ONFIRE) + { + specularR>>=2; + specularG>>=2; + specularB>>=2; + + redI>>=1; + greenI>>=1; + blueI>>=1; + } + + { + int i = (redI+greenI+blueI); + int si = (specularR+specularG+specularB); + + VECTORCH vertex = *(((VECTORCH *)Global_ShapePoints)+vertexNumber); + int r,g,b; + vertex.vx += Global_ODB_Ptr->ObWorld.vx; + vertex.vy += Global_ODB_Ptr->ObWorld.vy; + vertex.vz += Global_ODB_Ptr->ObWorld.vz; + + r = GetSin((vertex.vx+CloakingPhase)&4095); + r = MUL_FIXED(r,r); + redI = MUL_FIXED(r,i); + specularR = MUL_FIXED(r,si); + + g = GetSin((vertex.vy+CloakingPhase/2)&4095); + g = MUL_FIXED(g,g); + greenI = MUL_FIXED(g,i); + specularG = MUL_FIXED(g,si); + + b = GetSin((vertex.vz+CloakingPhase*3)&4095); + b = MUL_FIXED(b,b); + blueI = MUL_FIXED(b,i); + specularB = MUL_FIXED(b,si); + + } + + + + /* Intensity for Textures */ + redI >>= 8; + if(redI > 255) redI = 255; + renderVertexPtr->R = redI; + ColourIntensityArray[vertexNumber].R = redI; + + greenI >>= 8; + if(greenI > 255) greenI = 255; + renderVertexPtr->G = greenI; + ColourIntensityArray[vertexNumber].G = greenI; + + blueI >>= 8; + if(blueI > 255) blueI = 255; + renderVertexPtr->B = blueI; + ColourIntensityArray[vertexNumber].B = blueI; + + specularR >>= 10; + if(specularR > 255) specularR = 255; + renderVertexPtr->SpecularR = specularR; + ColourIntensityArray[vertexNumber].SpecularR = specularR; + + specularG >>= 10; + if(specularG > 255) specularG = 255; + renderVertexPtr->SpecularG = specularG; + ColourIntensityArray[vertexNumber].SpecularG = specularG; + + specularB >>= 10; + if(specularB > 255) specularB = 255; + renderVertexPtr->SpecularB = specularB; + ColourIntensityArray[vertexNumber].SpecularB = specularB; + + +} +static void VertexIntensity_Underwater(RENDERVERTEX *renderVertexPtr) +{ + int redI,greenI,blueI; + int specularR,specularG,specularB; + + int vertexNumber = *VertexNumberPtr; + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = ColourIntensityArray[vertexNumber].SpecularR; + renderVertexPtr->SpecularG = ColourIntensityArray[vertexNumber].SpecularG; + renderVertexPtr->SpecularB = ColourIntensityArray[vertexNumber].SpecularB; + return; + } + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; + { + VECTORCH *vertexNormalPtr = ((VECTORCH *)Global_ShapeVNormals) + vertexNumber; + VECTORCH *vertexPtr = ((VECTORCH *)Global_ShapePoints)+vertexNumber; + + LIGHTBLOCK **larrayptr; + LIGHTBLOCK *lptr; + int i; + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_PreLit) + { + unsigned int packedI = Global_EID_IPtr[vertexNumber]; + blueI = (packedI&255)*257; + + packedI >>=8; + greenI = (packedI&255)*257; + + packedI >>=8; + redI = (packedI&255)*257; + } + else + { + redI = 0; + greenI = 0; + blueI = 0; + } + + specularR = 0; + specularG = 0; + specularB = 0; + + + + larrayptr = LightSourcesForObject; + + for(i = NumLightSourcesForObject; i!=0; i--) + { + + VECTORCH vertexToLight; + int distanceToLight; + + lptr = *larrayptr++; + + vertexToLight.vx = lptr->LocalLP.vx - vertexPtr->vx; + vertexToLight.vy = lptr->LocalLP.vy - vertexPtr->vy; + vertexToLight.vz = lptr->LocalLP.vz - vertexPtr->vz; + { + int dx,dy,dz; + + dx = vertexToLight.vx; + if (dx<0) dx = -dx; + + dy = vertexToLight.vy; + if (dy<0) dy = -dy; + + dz = vertexToLight.vz; + if (dz<0) dz = -dz; + + + if (dx>dy) + { + if (dx>dz) + { + distanceToLight = dx + ((dy+dz)>>2); + } + else + { + distanceToLight = dz + ((dy+dx)>>2); + } + } + else + { + if (dy>dz) + { + distanceToLight = dy + ((dx+dz)>>2); + } + else + { + distanceToLight = dz + ((dx+dy)>>2); + } + } + } + + if(distanceToLight < lptr->LightRange) + { + int idot = MUL_FIXED(lptr->LightRange-distanceToLight,lptr->BrightnessOverRange); + int r,g,b; + + if(distanceToLight>0) + { + int dotproduct = MUL_FIXED(vertexNormalPtr->vx,vertexToLight.vx) + + MUL_FIXED(vertexNormalPtr->vy,vertexToLight.vy) + + MUL_FIXED(vertexNormalPtr->vz,vertexToLight.vz); + + if(dotproduct>0) + { + idot = (WideMulNarrowDiv(idot,dotproduct,distanceToLight)+idot/4)/2; + } + else + { + idot /= 8; + } + } + + r = MUL_FIXED(idot,lptr->RedScale); + g = MUL_FIXED(idot,lptr->GreenScale); + b = MUL_FIXED(idot,lptr->BlueScale); + + redI += r; + greenI += g; + blueI += b; + + if( !(lptr->LightFlags & LFlag_PreLitSource) + && !(lptr->LightFlags & LFlag_NoSpecular) ) + { + specularR += r; + specularG += g; + specularB += b; + } + } + } + } + + if(Global_ODB_Ptr->SpecialFXFlags & SFXFLAG_ONFIRE) + { + specularR>>=2; + specularG>>=2; + specularB>>=2; + + redI>>=1; + greenI>>=1; + blueI>>=1; + } + + { + if (specularBZ*4) + specularB = renderVertexPtr->Z*4; + + } + + + + /* Intensity for Textures */ + redI >>= 8; + if(redI > 255) redI = 255; + renderVertexPtr->R = redI; + ColourIntensityArray[vertexNumber].R = redI; + + greenI >>= 8; + if(greenI > 255) greenI = 255; + renderVertexPtr->G = greenI; + ColourIntensityArray[vertexNumber].G = greenI; + + blueI >>= 8; + if(blueI > 255) blueI = 255; + renderVertexPtr->B = blueI; + ColourIntensityArray[vertexNumber].B = blueI; + + specularR >>= 10; + if(specularR > 255) specularR = 255; + renderVertexPtr->SpecularR = specularR; + ColourIntensityArray[vertexNumber].SpecularR = specularR; + + specularG >>= 10; + if(specularG > 255) specularG = 255; + renderVertexPtr->SpecularG = specularG; + ColourIntensityArray[vertexNumber].SpecularG = specularG; + + specularB >>= 10; + if(specularB > 255) specularB = 255; + renderVertexPtr->SpecularB = specularB; + ColourIntensityArray[vertexNumber].SpecularB = specularB; + + + } + +/*KJL*********************************************************************** +* The following functions have been transplanted from the old shape.c, and * +* will probably be found a new home at some point in the future. * +***********************************************************************KJL*/ + +/* + + Texture Animation + +*/ + +int* GetTxAnimArrayZ(int shape, int item) + +{ + + SHAPEHEADER *sptr; + int **item_array_ptr; + int **shape_textures; + int *item_ptr; + POLYHEADER *pheader; + int texture_defn_index; + + + sptr = GetShapeData(shape); + + if(sptr && sptr->sh_textures && sptr->items) { + + item_array_ptr = sptr->items; + shape_textures = sptr->sh_textures; + + item_ptr = item_array_ptr[item]; + pheader = (POLYHEADER *) item_ptr; + + texture_defn_index = (pheader->PolyColour >> TxDefn); + + if(pheader->PolyFlags & iflag_txanim) { + + return (int*) shape_textures[texture_defn_index]; + + } + + else return 0; + + } + + else return 0; + +} + + +TXANIMHEADER* GetTxAnimDataZ(int shape, int item, int sequence) + +{ + + SHAPEHEADER *sptr; + TXANIMHEADER **txah_ptr; + TXANIMHEADER *txah; + int **item_array_ptr; + int **shape_textures; + int *item_ptr; + POLYHEADER *pheader; + int texture_defn_index; + + + sptr = GetShapeData(shape); + + if(sptr && sptr->sh_textures && sptr->items) { + + item_array_ptr = sptr->items; + shape_textures = sptr->sh_textures; + + item_ptr = item_array_ptr[item]; + pheader = (POLYHEADER *) item_ptr; + + texture_defn_index = (pheader->PolyColour >> TxDefn); + + if(pheader->PolyFlags & iflag_txanim) { + + txah_ptr = (TXANIMHEADER **) shape_textures[texture_defn_index]; + txah_ptr++; /* Skip sequence shadow */ + + txah = txah_ptr[sequence]; + + return txah; + + } + + else return 0; + + } + + else return 0; + +} + + + + +/* + + For some animated textures each sequence will represent a different view + of a sprite. When each sequence has the same number of frames there is no + problem transferring the value from one "txa_currentframe" to the other. + However if the new sequence has a different number of frames a scaling must + be done. + +*/ + +void ChangeSequence(TXANIMHEADER *txah_old, TXANIMHEADER *txah_new) + +{ + + if(txah_new->txa_numframes == txah_old->txa_numframes) { + + txah_new->txa_currentframe = txah_old->txa_currentframe; + + } + + else { + + txah_new->txa_currentframe = + + WideMulNarrowDiv(txah_old->txa_currentframe, + txah_new->txa_maxframe, + txah_old->txa_maxframe); + + } +} + + +/* + + This function copies the TXANIMHEADER from the shape data item sequence + selected by the TXACTRLBLK to the TXANIMHEADER in the TXACTRLBLK + +*/ + +TXANIMHEADER* GetTxAnimHeaderFromShape(TXACTRLBLK *taptr, int shape) + +{ + + TXANIMHEADER *txah = 0; + + + { + + txah = GetTxAnimDataZ(shape, taptr->tac_item, taptr->tac_sequence); + + } + + if(txah) { + + taptr->tac_txah.txa_flags = txah->txa_flags; + taptr->tac_txah.txa_state = txah->txa_state; + taptr->tac_txah.txa_numframes = txah->txa_numframes; + taptr->tac_txah.txa_framedata = txah->txa_framedata; + taptr->tac_txah.txa_currentframe = txah->txa_currentframe; + taptr->tac_txah.txa_maxframe = txah->txa_maxframe; + taptr->tac_txah.txa_speed = txah->txa_speed; + + } + + return txah; + +} + + +/* + + Texture Animation Control Blocks are used to update animation. At the start + of "AddShape()" the relevant control block values are copied across to the + item TXANIMHEADER. + +*/ + +void UpdateTxAnim(TXANIMHEADER *txah) + +{ + + int UpdateRate; + + + if(txah->txa_flags & txa_flag_play) { + + /* How fast do we go? */ + + if(txah->txa_flags & txa_flag_quantiseframetime) { + + /* This option is still being designed and tested */ + + UpdateRate = txah->txa_speed & (~4096); /* 1/16th */ + if(UpdateRate < 4096) UpdateRate = 4096; + UpdateRate = MUL_FIXED(NormalFrameTime, txah->txa_speed); + + } + + else UpdateRate = MUL_FIXED(NormalFrameTime, txah->txa_speed); + + + /* Update the current frame */ + + if(txah->txa_flags & txa_flag_reverse) { + + txah->txa_currentframe -= UpdateRate; + + if(txah->txa_currentframe < 0) { + + if(txah->txa_flags & txa_flag_noloop) { + + txah->txa_currentframe = 0; + + } + + else { + + txah->txa_currentframe += txah->txa_maxframe; + + } + + } + + } + + else { + + txah->txa_currentframe += UpdateRate; + + if(txah->txa_currentframe >= txah->txa_maxframe) { + + if(txah->txa_flags & txa_flag_noloop) { + + txah->txa_currentframe = txah->txa_maxframe - 1; + + } + + else { + + txah->txa_currentframe -= txah->txa_maxframe; + + } + + } + + } + + } + +} + + +/* + + Display block TXACTRLBLKS pass their data on to shape TXANIMHEADERs + +*/ + +void ControlTextureAnimation(DISPLAYBLOCK *dptr) +{ + + TXACTRLBLK *taptr; + TXANIMHEADER *txah; + int *iptr; + + + taptr = dptr->ObTxAnimCtrlBlks; + + while(taptr) + { + /* Update animation for the display block TXACTRLBLK */ + LOCALASSERT(&(taptr->tac_txah)); + UpdateTxAnim(&taptr->tac_txah); + + /* Get the TXANIMHEADER from the shape data */ + + txah = taptr->tac_txah_s; + + /* Copy across the current frame */ + LOCALASSERT(txah); + txah->txa_currentframe = taptr->tac_txah.txa_currentframe; + + iptr = taptr->tac_txarray; + LOCALASSERT(iptr); + *iptr = taptr->tac_sequence; + + taptr = taptr->tac_next; + } +} + +void CreateTxAnimUVArray(int *txa_data, int *uv_array, int *shapeitemptr) +{ + TXANIMHEADER **txah_ptr; + TXANIMHEADER *txah; + TXANIMFRAME *txaf; + TXANIMFRAME *txaf0; + TXANIMFRAME *txaf1; + int *txaf0_uv; + int *txaf1_uv; + int CurrentFrame, NextFrame, Alpha, OneMinusAlpha; + int i; + int *iptr; + int Orient, Scale; + int OrientX, OrientY; + int ScaleX, ScaleY; + int sin, cos; + int x, y; + int x1, y1; + int o1, o2, od; + POLYHEADER *pheader = (POLYHEADER*) shapeitemptr; + int sequence; + int *txf_imageptr; + + + /* The sequence # will have been copied across by the control block */ + + sequence = *txa_data++; + + #if 0 + textprint("sequence = %d\n", sequence); + #endif + + txah_ptr = (TXANIMHEADER **) txa_data; + txah = txah_ptr[sequence]; + txaf = txah->txa_framedata; + + + /* Because the current frame can be set from outside, clamp it first */ + + if(txah->txa_currentframe < 0) { + + txah->txa_currentframe = 0; + + } + + if(txah->txa_currentframe >= txah->txa_maxframe) { + + txah->txa_currentframe = txah->txa_maxframe - 1; + + } + + + /* Frame # */ + + CurrentFrame = txah->txa_currentframe >> 16; + Alpha = txah->txa_currentframe - (CurrentFrame << 16); + OneMinusAlpha = ONE_FIXED - Alpha; + + + /* Start and End Frame */ + + NextFrame = CurrentFrame + 1; + if(NextFrame >= txah->txa_numframes) NextFrame = 0; + + txaf0 = &txaf[CurrentFrame]; + txaf1 = &txaf[NextFrame]; + + + /* + + Write the image index back to the item by overwriting the shape data. + This is not elegant but it is one of the kind of things you expect to + have happen when a major new feature is retro-fitted to a system. + + */ + + pheader->PolyColour &= ClrTxIndex; + + + /* Multi-View Sprites need to select an image from the array */ + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_MultiViewSprite) { + + int **txf_uvarrayptr0 = (int **) txaf0->txf_uvdata; + int **txf_uvarrayptr1 = (int **) txaf1->txf_uvdata; + int index; + + + index = GetMVSIndex(txah, <oVMat_Euler); + + /*textprint("index = %d\n", index);*/ + + + txf_imageptr = (int *) txaf0->txf_image; + pheader->PolyColour |= txf_imageptr[index]; + + + /* Get the uv data */ + + txaf0_uv = txf_uvarrayptr0[index]; + txaf1_uv = txf_uvarrayptr1[index]; + + } + + + /* Single-View Sprites have just one image per frame */ + + else { + + pheader->PolyColour |= txaf0->txf_image; + + txaf0_uv = txaf0->txf_uvdata; + txaf1_uv = txaf1->txf_uvdata; + + } + + + /* Calculate UVs */ + + iptr = uv_array; + + if(txah->txa_flags & txa_flag_interpolate_uvs) { + + for(i = txaf0->txf_numuvs; i!=0; i--) { + + iptr[0] = MUL_FIXED(txaf0_uv[0], OneMinusAlpha) + + MUL_FIXED(txaf1_uv[0], Alpha); + + iptr[1] = MUL_FIXED(txaf0_uv[1], OneMinusAlpha) + + MUL_FIXED(txaf1_uv[1], Alpha); + + /*textprint("%d, %d\n", iptr[0] >> 16, iptr[1] >> 16);*/ + + txaf0_uv += 2; + txaf1_uv += 2; + iptr += 2; + + } + + } + + else { + + for(i = txaf0->txf_numuvs; i!=0; i--) { + + iptr[0] = txaf0_uv[0]; + iptr[1] = txaf0_uv[1]; + + /*textprint("%d, %d\n", iptr[0] >> 16, iptr[1] >> 16);*/ + + txaf0_uv += 2; + iptr += 2; + + } + + } + + + /* Interpolate Orient and Scale */ + + o1 = txaf0->txf_orient; + o2 = txaf1->txf_orient; + + if(o1 == o2) { + + Orient = o1; + + } + + else { + + od = o1 - o2; + if(od < 0) od = -od; + + if(od >= deg180) { + + o1 <<= (32 - 12); + o1 >>= (32 - 12); + o2 <<= (32 - 12); + o2 >>= (32 - 12); + + } + + Orient = MUL_FIXED(o1, OneMinusAlpha) + MUL_FIXED(o2, Alpha); + Orient &= wrap360; + + } + + + if(txaf0->txf_scale == txaf1->txf_scale) { + + Scale = txaf0->txf_scale; + + } + + else { + + Scale = WideMul2NarrowDiv(txaf0->txf_scale, OneMinusAlpha, + txaf1->txf_scale, Alpha, ONE_FIXED); + + } + + + /* Interpolate Orient and Scale Origins */ + + if(txaf0->txf_orientx == txaf1->txf_orientx) { + + OrientX = txaf0->txf_orientx; + + } + + else { + + OrientX = MUL_FIXED(txaf0->txf_orientx, OneMinusAlpha) + + MUL_FIXED(txaf1->txf_orientx, Alpha); + + } + + + if(txaf0->txf_orienty == txaf1->txf_orienty) { + + OrientY = txaf0->txf_orienty; + + } + + else { + + OrientY = MUL_FIXED(txaf0->txf_orienty, OneMinusAlpha) + + MUL_FIXED(txaf1->txf_orienty, Alpha); + + } + + + if(txaf0->txf_scalex == txaf1->txf_scalex) { + + ScaleX = txaf0->txf_scalex; + + } + + else { + + ScaleX = MUL_FIXED(txaf0->txf_scalex, OneMinusAlpha) + + MUL_FIXED(txaf1->txf_scalex, Alpha); + + } + + + if(txaf0->txf_scaley == txaf1->txf_scaley) { + + ScaleY = txaf0->txf_scaley; + + } + + else { + + ScaleY = MUL_FIXED(txaf0->txf_scaley, OneMinusAlpha) + + MUL_FIXED(txaf1->txf_scaley, Alpha); + + } + + + + #if 0 + textprint("Alpha = %d\n", Alpha); + textprint("OneMinusAlpha = %d\n", OneMinusAlpha); + textprint("Orient = %d\n", Orient); + textprint("txaf0->txf_scale = %d\n", txaf0->txf_scale); + textprint("txaf1->txf_scale = %d\n", txaf1->txf_scale); + textprint("Scale = %d\n", Scale); + #endif + + /*WaitForReturn();*/ + + + +#if 1 + + + /* Rotate UV Array */ + + if(Orient) { + + sin = GetSin(Orient); + cos = GetCos(Orient); + + iptr = uv_array; + + for(i = txaf0->txf_numuvs; i!=0; i--) { + + x = iptr[0] - OrientX; + y = iptr[1] - OrientY; + + x1 = MUL_FIXED(x, cos) - MUL_FIXED(y, sin); + y1 = MUL_FIXED(x, sin) + MUL_FIXED(y, cos); + + iptr[0] = x1 + OrientX; + iptr[1] = y1 + OrientY; + + iptr += 2; + + } + + } + + + /* Scale UV Array */ + + if(Scale != ONE_FIXED) { + + iptr = uv_array; + + for(i = txaf0->txf_numuvs; i!=0; i--) { + + x = iptr[0] - ScaleX; + y = iptr[1] - ScaleY; + + x = MUL_FIXED(x, Scale); + y = MUL_FIXED(y, Scale); + + iptr[0] = x + ScaleX; + iptr[1] = y + ScaleY; + + iptr += 2; + + } + + } + + +#endif + + + + + + + #if 0 + textprint("Current Frame = %d\n", txah->txa_currentframe); + textprint("Current Frame = %d\n", CurrentFrame); + textprint("Next Frame = %d\n", NextFrame); + textprint("Alpha = %d\n", Alpha); + #endif + + + /*textprint("Leaving CreateTxAnimUVArray\n");*/ + /*WaitForReturn();*/ + +} + + + + + + + + + + + + + +/* + + Shape Points for Unrotated Sprites + +*/ + +void ShapeSpritePointsInstr(SHAPEINSTR *shapeinstrptr) + +{ + + int **shapeitemarrayptr = shapeinstrptr->sh_instr_data; + int *shapeitemptr = *shapeitemarrayptr; + VECTORCH *rotptsptr = RotatedPts; + int numitems; + + + for(numitems = shapeinstrptr->sh_numitems; numitems!=0; numitems--) { + + rotptsptr->vx = shapeitemptr[ix]; + rotptsptr->vx += Global_ODB_Ptr->ObView.vx; + + rotptsptr->vy = shapeitemptr[iy]; + rotptsptr->vy += Global_ODB_Ptr->ObView.vy; + + rotptsptr->vz = shapeitemptr[iz]; + rotptsptr->vz += Global_ODB_Ptr->ObView.vz; + + shapeitemptr += vsize; + rotptsptr++; + + } + +} + + +/* + + Shape Points for Rotated Sprites + +*/ + + +//I've put my alterations to the sprite rotation +//in the #else part.Richard +#define UseKevinsModifiedSSRPI No + + +#if UseKevinsModifiedSSRPI + + + +#define ssrpi_kill_py Yes + +void ShapeSpriteRPointsInstr(SHAPEINSTR *shapeinstrptr) + +{ + + int **shapeitemarrayptr = shapeinstrptr->sh_instr_data; + int *shapeitemptr = *shapeitemarrayptr; + VECTORCH *rotptsptr = RotatedPts; + int numitems; + int x,y,z; + MATRIXCH m; + #if ssrpi_kill_py + EULER e; + char flipX=0; + #endif + /* + + Sprite Resizing + + If this shape is a sprite and is using sprite resizing, there will be a transformed + copy of the polygon points array (XY only) to copy back to the shape. + + WARNING! + + This function and data structure ASSUME that the sprite shape is using an item array, + that there is just the one item, and that the world and UV space coordinates are in the + form of "TL, BL, BR, TR". It also assumes that the sprite polygon is in the XY plane. + + If ANY of these is not true for your sprite, DON'T attempt to use resizing! + + */ + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_Sprite && + Global_ShapeHeaderPtr->shapeflags & ShapeFlag_SpriteResizing) { + + int *ShapePoints; + int **item_array_ptr; + int *item_ptr; + POLYHEADER *pheader; + int *mypolystart; + int texture_defn_index; + int *texture_defn_ptr; + TXANIMHEADER **txah_ptr; + TXANIMHEADER *txah; + TXANIMFRAME *txaf; + TXANIMFRAME *txaf0; + int CurrentFrame, sequence; + int *iptr; + + ShapePoints = *(Global_ShapeHeaderPtr->points); + + /* Item */ + + item_array_ptr = Global_ShapeHeaderPtr->items; /* Assume item array */ + item_ptr = item_array_ptr[0]; /* Assume only one polygon */ + pheader = (POLYHEADER *) item_ptr; + + /* Texture Animation */ + + texture_defn_index = (pheader->PolyColour >> TxDefn); + texture_defn_ptr = Global_ShapeTextures[texture_defn_index]; + + sequence = *texture_defn_ptr++; + + txah_ptr = (TXANIMHEADER **) texture_defn_ptr; + txah = txah_ptr[sequence]; + txaf = txah->txa_framedata; + + /* Because the current frame can be set from outside, clamp it first */ + + if(txah->txa_currentframe < 0) + txah->txa_currentframe = 0; + if(txah->txa_currentframe >= txah->txa_maxframe) + txah->txa_currentframe = txah->txa_maxframe - 1; + + CurrentFrame = txah->txa_currentframe >> 16; + + txaf0 = &txaf[CurrentFrame]; + + /* UV array */ + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_Sprite) { + + int **uvarrayptr = (int **) txaf0->txf_uvdata; + iptr = uvarrayptr[GetMVSIndex(txah, <oVMat_Euler)]; + + } + + else { + + iptr = txaf0->txf_uvdata; + + } + + iptr += (txaf0->txf_numuvs * 2); + + /* Redefine the Shape Points */ + + mypolystart = &pheader->Poly1stPt; + + while(*mypolystart != Term) { + + /*textprint("copying point %d\n", *mypolystart / vsize);*/ + + *(ShapePoints + *mypolystart + ix) = iptr[0]; + *(ShapePoints + *mypolystart + iy) = iptr[1]; + + mypolystart++; + iptr += 2; + + } + + } + + + #if ssrpi_kill_py + + + /* Make a copy of the object matrix */ + + CopyMatrix(&Global_ODB_Ptr->ObMat, &m); + + + + /* Combine it with the view matrix */ + + MatrixMultiply(&Global_VDB_Ptr->VDB_SpriteMat, &m, &m); + + /* Extract the Euler Angles */ + MatrixToEuler(&m, &e); + + #if 0 + textprint("X: %d\n", e.EulerX); + textprint("Y: %d\n", e.EulerY); + textprint("Z: %d\n", e.EulerZ); + #endif + + + /* Knock out the pitch and yaw */ + + /* KJL 17:23:22 01/09/97 - If the sprite is turned away from you, flip along the + x-axis so that you get the mirror image of the sprite */ + if (e.EulerY<1024 || e.EulerY>3072) flipX = 1; + e.EulerY=0; + e.EulerX=0; + + + /* Turn it back into a matrix */ + CreateEulerMatrix(&e, &m); + TransposeMatrixCH(&m); + + #else /* ssrpi_kill_py */ + + + MatrixMultiply(&Global_VDB_Ptr->VDB_SpriteMat, &Global_ODB_Ptr->ObMat, &m); + + + #endif /* ssrpi_kill_py */ + + + for(numitems = shapeinstrptr->sh_numitems; numitems!=0; numitems--) { + + x = shapeitemptr[ix]; + y = shapeitemptr[iy]; + z = shapeitemptr[iz]; + + rotptsptr->vx = MUL_FIXED(m.mat11, x); + rotptsptr->vx += MUL_FIXED(m.mat21, y); + rotptsptr->vx += MUL_FIXED(m.mat31, z); + #if ssrpi_kill_py + if (flipX) rotptsptr->vx = - rotptsptr->vx; + #endif + rotptsptr->vx += Global_ODB_Ptr->ObView.vx; + + rotptsptr->vy = MUL_FIXED(m.mat12, x); + rotptsptr->vy += MUL_FIXED(m.mat22, y); + rotptsptr->vy += MUL_FIXED(m.mat32, z); + rotptsptr->vy += Global_ODB_Ptr->ObView.vy; + + rotptsptr->vz = MUL_FIXED(m.mat13, x); + rotptsptr->vz += MUL_FIXED(m.mat23, y); + rotptsptr->vz += MUL_FIXED(m.mat33, z); + rotptsptr->vz += Global_ODB_Ptr->ObView.vz; + + shapeitemptr += vsize; + rotptsptr++; + + } + +} + + + + +#else /* UseKevinsModifiedSSRPI */ + + + + +#define ssrpi_kill_py No + +void ShapeSpriteRPointsInstr(SHAPEINSTR *shapeinstrptr) + +{ + + int **shapeitemarrayptr = shapeinstrptr->sh_instr_data; + int *shapeitemptr = *shapeitemarrayptr; + VECTORCH *rotptsptr = RotatedPts; + int numitems; + int x,y; + VECTORCH vectx,vecty; + #if ssrpi_kill_py + MATRIXCH m2; + EULER e; + #endif + + + /* + + Sprite Resizing + + If this shape is a sprite and is using sprite resizing, there will be a transformed + copy of the polygon points array (XY only) to copy back to the shape. + + WARNING! + + This function and data structure ASSUME that the sprite shape is using an item array, + that there is just the one item, and that the world and UV space coordinates are in the + form of "TL, BL, BR, TR". It also assumes that the sprite polygon is in the XY plane. + + If ANY of these is not true for your sprite, DON'T attempt to use resizing! + + */ + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_Sprite && + Global_ShapeHeaderPtr->shapeflags & ShapeFlag_SpriteResizing) { + + int *ShapePoints; + int **item_array_ptr; + int *item_ptr; + POLYHEADER *pheader; + int *mypolystart; + int texture_defn_index; + int *texture_defn_ptr; + TXANIMHEADER **txah_ptr; + TXANIMHEADER *txah; + TXANIMFRAME *txaf; + TXANIMFRAME *txaf0; + int CurrentFrame, sequence; + int *iptr; + + ShapePoints = *(Global_ShapeHeaderPtr->points); + + /* Item */ + + item_array_ptr = Global_ShapeHeaderPtr->items; /* Assume item array */ + item_ptr = item_array_ptr[0]; /* Assume only one polygon */ + pheader = (POLYHEADER *) item_ptr; + + /* Texture Animation */ + + texture_defn_index = (pheader->PolyColour >> TxDefn); + texture_defn_ptr = Global_ShapeTextures[texture_defn_index]; + + sequence = *texture_defn_ptr++; + + txah_ptr = (TXANIMHEADER **) texture_defn_ptr; + txah = txah_ptr[sequence]; + txaf = txah->txa_framedata; + + /* Because the current frame can be set from outside, clamp it first */ + + if(txah->txa_currentframe < 0) + txah->txa_currentframe = 0; + if(txah->txa_currentframe >= txah->txa_maxframe) + txah->txa_currentframe = txah->txa_maxframe - 1; + + CurrentFrame = txah->txa_currentframe >> 16; + + txaf0 = &txaf[CurrentFrame]; + + + /* UV array */ + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_Sprite) { + + int **uvarrayptr = (int **) txaf0->txf_uvdata; + iptr = uvarrayptr[GetMVSIndex(txah, <oVMat_Euler)]; + + } + + else { + + iptr = txaf0->txf_uvdata; + + } + + iptr += (txaf0->txf_numuvs * 2); + + + /* Redefine the Shape Points */ + + mypolystart = &pheader->Poly1stPt; + + while(*mypolystart != Term) { + + /*textprint("copying point %d\n", *mypolystart / vsize);*/ + + ((VECTORCH *)ShapePoints)[*mypolystart].vx = iptr[0]; + ((VECTORCH *)ShapePoints)[*mypolystart].vy = iptr[1]; + + /*textprint("x, y = %d, %d\n", iptr[0], iptr[1]);*/ + + mypolystart++; + iptr += 2; + + } + + } + + //project the object's y vector onto the screen. + //then rotate the sprite's points according to the vector's orintation + //relative to the screen's y vector. + vecty=*(VECTORCH*)&Global_ODB_Ptr->ObMat.mat21; + + RotateVector(&vecty,&Global_VDB_Ptr->VDB_Mat); + if(Global_VDB_Ptr->VDB_ProjX!=Global_VDB_Ptr->VDB_ProjY) + { + vecty.vx=MUL_FIXED(vecty.vx,Global_VDB_Ptr->VDB_ProjX); + vecty.vy=MUL_FIXED(vecty.vy,Global_VDB_Ptr->VDB_ProjY); + } + vecty.vz=0; + if(!vecty.vx && !vecty.vy)vecty.vy=ONE_FIXED; + Normalise(&vecty); + vectx.vx=-vecty.vy; + vectx.vy=vecty.vx; + vectx.vz=0; + + for(numitems = shapeinstrptr->sh_numitems; numitems!=0; numitems--) { + + x = -shapeitemptr[ix]; + y = shapeitemptr[iy]; + + rotptsptr->vx = MUL_FIXED(vectx.vx, x); + rotptsptr->vx += MUL_FIXED(vectx.vy, y); + rotptsptr->vx += Global_ODB_Ptr->ObView.vx; + + rotptsptr->vy = MUL_FIXED(vecty.vx, x); + rotptsptr->vy += MUL_FIXED(vecty.vy, y); + rotptsptr->vy += Global_ODB_Ptr->ObView.vy; + + rotptsptr->vz = Global_ODB_Ptr->ObView.vz; + + shapeitemptr += vsize; + rotptsptr++; + + } + + +} + + + +#endif /* UseKevinsModifiedSSRPI */ + +int GetMVSIndex(TXANIMHEADER + *txah, EULER* e ) +{ + int EulerXIndex, EulerYIndex; + int theta,phi; //angles in spherical polar coordinates + //phi goes from 0 (top) to deg180 (bottom) + VECTORCH v; + + MakeVectorLocal(&Global_ODB_Ptr->ObWorld,&v,&Global_VDB_Ptr->VDB_World,&Global_ODB_Ptr->ObMat); + Normalise(&v); + phi=-ArcSin(v.vy); + phi+=deg90; + phi&=wrap360; + if(phi==deg180)phi--; + if(!v.vx && !v.vz) + { + theta=0; + } + else + { + v.vy=0; + Normalise(&v); + if(v.vz > Cosine45 || -v.vz>Cosine45) { + + theta = ArcSin(-v.vx); + + if(v.vz < 0) { + theta &= wrap360; + } + else + { + theta+=deg180; + theta =-theta; + theta &= wrap360; + } + } + + else { + + theta = ArcCos(v.vz); + + if(v.vx < 0) { + theta = -theta; + } + theta+=deg180; + theta &= wrap360; + + } + } + + EulerYIndex = theta; + EulerYIndex >>= txah->txa_euleryshift; + + + EulerYIndex <<= (11 - txah->txa_eulerxshift); + + EulerXIndex = phi; + EulerXIndex >>= txah->txa_eulerxshift; + + GLOBALASSERT((EulerXIndex+EulerYIndex)txa_num_mvs_images); + + return (EulerXIndex + EulerYIndex); + +} + + +void AddShape(DISPLAYBLOCK *dptr, VIEWDESCRIPTORBLOCK *VDB_Ptr) +{ + SHAPEHEADER *shapeheaderptr; + + if (!dptr->ObShape && dptr->SfxPtr) + { +// DrawSfxObject(dptr); + return; + } + /* KJL 12:42:38 18/05/98 - check to see if object is on fire */ + if (dptr->ObStrategyBlock) + { + if(dptr->ObStrategyBlock->SBDamageBlock.IsOnFire) + { + dptr->SpecialFXFlags |= SFXFLAG_ONFIRE; + } + else + { + dptr->SpecialFXFlags &= ~SFXFLAG_ONFIRE; + } + + } + + /* is object a morphing one? */ + if(dptr->ObMorphCtrl) + { + LOCALASSERT(dptr->ObMorphCtrl->ObMorphHeader); + if(dptr->ObMorphCtrl->ObMorphHeader) + { + GetMorphDisplay(&MorphDisplay, dptr); + dptr->ObShape = MorphDisplay.md_shape1; + dptr->ObShapeData = MorphDisplay.md_sptr1; + shapeheaderptr = MorphDisplay.md_sptr1; + } + } + else + { + shapeheaderptr = GetShapeData(dptr->ObShape); + + /* It is important to pass this SHAPEHEADER* on to the display block */ + dptr->ObShapeData = shapeheaderptr; + + // I've put this inside the else so that it does + // not conflict with morphing !!! + // make sure dptr->ObShapeData is up to date before + // doing CopyAnimationFrameToShape + + if (dptr->ShapeAnimControlBlock) + { + if (!(dptr->ShapeAnimControlBlock->current.empty)) + { + CopyAnimationFrameToShape (&dptr->ShapeAnimControlBlock->current, dptr); + } + } + } + + + ChooseLightingModel(dptr); + /* hierarchical object? */ + #if 0 + if (dptr->HModelControlBlock && !dptr->ObStrategyBlock) + { + DoHModel(dptr->HModelControlBlock,dptr); + return; + } + #endif + + + + /* Texture Animation Control */ + + if(dptr->ObTxAnimCtrlBlks) ControlTextureAnimation(dptr); + + /* Global Variables */ + Global_VDB_Ptr = VDB_Ptr; + Global_ODB_Ptr = dptr; + Global_ShapeHeaderPtr = shapeheaderptr; + + /* Shape Language Specific Setup */ + SetupShapePipeline(); + + /* + + Create the Local -> View Matrix + + LToVMat = VDB_Mat * ObMat + + "Get the points into View Space, then apply the Local Transformation" + + */ + + MatrixMultiply(&VDB_Ptr->VDB_Mat, &dptr->ObMat, <oVMat); + MatrixToEuler(<oVMat, <oVMat_Euler); + + /* + + Create the World -> Local Matrix + + WToLMat = Transposed Local Matrix + + */ + + CopyMatrix(&dptr->ObMat, &WToLMat); + TransposeMatrixCH(&WToLMat); + + + /* + + Transform the View World Location to Local Space + + -> Make the View Loc. relative to the Object View Space Centre + -> Rotate this vector using WToLMat + + */ + + + MakeVector(&VDB_Ptr->VDB_World, &dptr->ObWorld, &LocalView); + RotateVector(&LocalView, &WToLMat); + + #if 0 + { + LocalCameraZAxis.vx = - dptr->ObWorld.vx; + LocalCameraZAxis.vy = - dptr->ObWorld.vy; + LocalCameraZAxis.vz = - dptr->ObWorld.vz; + + RotateVector(&LocalCameraZAxis, &WToLMat); + } + #endif + + NumberOfHeatSources=0; + if (dptr->HModelControlBlock) + { + ObjectCentre = dptr->ObView; + + if (dptr->ObStrategyBlock) + { + HierarchicalObjectsLowestYValue = dptr->ObStrategyBlock->DynPtr->ObjectVertices[0].vy; + if (CurrentVisionMode == VISION_MODE_NORMAL && AvP.PlayerType==I_Alien) + { + DoAlienEnergyView(dptr); + } + /* + else if (CurrentVisionMode == VISION_MODE_PRED_SEEALIENS && dptr->ObStrategyBlock->I_SBtype == I_BehaviourAlien) + { + DoAlienEnergyView(dptr); + } + */ + } + + if (CurrentVisionMode == VISION_MODE_PRED_THERMAL) + { + FindHeatSourcesInHModel(dptr); + } + DoHModel(dptr->HModelControlBlock,dptr); + return; + } + // return; + + + /* Find out which light sources are in range of of the object */ + LightSourcesInRangeOfObject(dptr); + + /* Shape Language Execution Shell */ + { + SHAPEINSTR *shapeinstrptr = shapeheaderptr->sh_instruction; + + /* setup the rotated points array */ + switch (shapeinstrptr->sh_instr) + { + default: + case I_ShapePoints: + { + if(Global_ODB_Ptr->ObMorphCtrl) + { + MorphPoints(shapeinstrptr); + } + else + { + TranslateShapeVertices(shapeinstrptr); + } + break; + } + } + } + /* call polygon pipeline */ + ShapePipeline(shapeheaderptr); + /* call sfx code */ + HandleSfxForObject(dptr); + if (dptr->ObStrategyBlock) + { + if (dptr->ObStrategyBlock->I_SBtype==I_BehaviourInanimateObject) + { + INANIMATEOBJECT_STATUSBLOCK* objStatPtr = dptr->ObStrategyBlock->SBdataptr; + if(objStatPtr->typeId==IOT_FieldCharge) + { + + int i; + D3D_DecalSystem_Setup(); + for(i=0; i<63; i++) + { + PARTICLE particle; + + particle.Position.vy = -280+i-GetCos((CloakingPhase/16*i + i*64+particle.Position.vz)&4095)/1024; + + particle.Position.vx = GetCos((CloakingPhase +i*64+particle.Position.vy)&4095)/512; + particle.Position.vz = GetSin((CloakingPhase +i*64+particle.Position.vy)&4095)/512; + RotateVector(&particle.Position,&dptr->ObMat); + particle.Position.vx += dptr->ObWorld.vx; + particle.Position.vy += dptr->ObWorld.vy; + particle.Position.vz += dptr->ObWorld.vz; + + particle.ParticleID=PARTICLE_MUZZLEFLASH; + particle.Colour = 0xff00007f+(FastRandom()&0x7f7f7f); + particle.Size = 40; + RenderParticle(&particle); + } + D3D_DecalSystem_End(); + + } + + } + } +} +void DoAlienEnergyView(DISPLAYBLOCK *dispPtr) +{ + HMODELCONTROLLER *controllerPtr = dispPtr->HModelControlBlock; + unsigned int colour = MARINES_LIFEFORCE_GLOW_COLOUR; + + LOCALASSERT(controllerPtr); + + + + /* KJL 16:36:25 10/02/98 - process model */ + { + STRATEGYBLOCK *sbPtr = Global_ODB_Ptr->ObStrategyBlock; + if(sbPtr) + { + switch (sbPtr->I_SBtype) + { + case I_BehaviourAlien: + { + colour = ALIENS_LIFEFORCE_GLOW_COLOUR; + break; + } + case I_BehaviourPredator: + { + colour = PREDATORS_LIFEFORCE_GLOW_COLOUR; + break; + } + case I_BehaviourMarine: + case I_BehaviourSeal: + { + MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + GLOBALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) + { + return; + } + colour = MARINES_LIFEFORCE_GLOW_COLOUR; + } + + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)Global_ODB_Ptr->ObStrategyBlock->SBdataptr; + + if (ghostDataPtr->type==I_BehaviourAlienPlayer || ghostDataPtr->type==I_BehaviourAlien + || (ghostDataPtr->type==I_BehaviourNetCorpse&&ghostDataPtr->subtype==I_BehaviourAlienPlayer) ) + { + colour = ALIENS_LIFEFORCE_GLOW_COLOUR; + } + else if (ghostDataPtr->type==I_BehaviourPredatorPlayer || ghostDataPtr->type==I_BehaviourPredator + || (ghostDataPtr->type==I_BehaviourNetCorpse&&ghostDataPtr->subtype==I_BehaviourPredatorPlayer) ) + { + colour = PREDATORS_LIFEFORCE_GLOW_COLOUR; + } + + break; + } + + case I_BehaviourNetCorpse: + { + NETCORPSEDATABLOCK *corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + + if (corpseDataPtr->Android) + { + return; + } + + if (corpseDataPtr->Type==I_BehaviourAlienPlayer || corpseDataPtr->Type==I_BehaviourAlien) + { + colour = ALIENS_LIFEFORCE_GLOW_COLOUR; + } + else if (corpseDataPtr->Type==I_BehaviourPredatorPlayer || corpseDataPtr->Type==I_BehaviourPredator) + { + colour = PREDATORS_LIFEFORCE_GLOW_COLOUR; + } + break; + } + case I_BehaviourHierarchicalFragment: + { + HDEBRIS_BEHAV_BLOCK *debrisDataPtr = (HDEBRIS_BEHAV_BLOCK *)sbPtr->SBdataptr; + if(debrisDataPtr->Type==I_BehaviourAutoGun || debrisDataPtr->Android) + { + return; + } + else if(debrisDataPtr->Type==I_BehaviourAlien) + { + colour = ALIENS_LIFEFORCE_GLOW_COLOUR; + } + else if (debrisDataPtr->Type==I_BehaviourPredator) + { + colour = PREDATORS_LIFEFORCE_GLOW_COLOUR; + } + else if ((debrisDataPtr->Type==I_BehaviourMarine)||(debrisDataPtr->Type==I_BehaviourSeal)) + { + colour = MARINES_LIFEFORCE_GLOW_COLOUR; + } + else return; + break; + } + + case I_BehaviourAutoGun: + { + /* KJL 19:31:53 25/01/99 - organics only, please */ + return; + break; + } + default: + break; + } + } + } + if( (Global_ODB_Ptr->SpecialFXFlags & SFXFLAG_MELTINGINTOGROUND) + &&(Global_ODB_Ptr->ObFlags2 < ONE_FIXED) ) + { + unsigned int alpha = MUL_FIXED(Global_ODB_Ptr->ObFlags2,colour >> 24); + colour = (colour&0xffffff)+(alpha<<24); + } + + /* KJL 16:36:12 10/02/98 - check positions are up to date */ + ProveHModel(controllerPtr,dispPtr); + + D3D_DecalSystem_Setup(); + + FindAlienEnergySource_Recursion(controllerPtr,controllerPtr->section_data,colour); + + D3D_DecalSystem_End(); +} + +static void FindAlienEnergySource_Recursion(HMODELCONTROLLER *controllerPtr, SECTION_DATA *sectionDataPtr, unsigned int colour) +{ + /* KJL 16:29:40 10/02/98 - Recurse through hmodel */ + if ((sectionDataPtr->First_Child!=NULL)&&(!(sectionDataPtr->flags§ion_data_terminate_here))) + { + SECTION_DATA *childSectionPtr = sectionDataPtr->First_Child; + + while (childSectionPtr!=NULL) + { + LOCALASSERT(childSectionPtr->My_Parent==sectionDataPtr); + + FindAlienEnergySource_Recursion(controllerPtr,childSectionPtr,colour); + childSectionPtr=childSectionPtr->Next_Sibling; + } + } + if(sectionDataPtr->Shape && sectionDataPtr->Shape->shaperadius>LocalDetailLevels.AlienEnergyViewThreshold) + { + PARTICLE particle; + + particle.Position = sectionDataPtr->World_Offset; + particle.ParticleID=PARTICLE_MUZZLEFLASH; + particle.Colour = colour;//0x208080ff; +// particle.Colour = 0x20ff8080; +// particle.Size = sectionDataPtr->Shape->shaperadius*3; +// particle.Colour = 0x20ffffff; + particle.Size = sectionDataPtr->Shape->shaperadius*2; + RenderParticle(&particle); + } +} + +void AddHierarchicalShape(DISPLAYBLOCK *dptr, VIEWDESCRIPTORBLOCK *VDB_Ptr) +{ + + SHAPEHEADER *shapeheaderptr; + SHAPEINSTR *shapeinstrptr; + + GLOBALASSERT(!dptr->HModelControlBlock); + if(!ObjectWithinFrustrum(dptr)) return; + + + #if 0 + shapeheaderptr = GetShapeData(dptr->ObShape); + + /* It is important to pass this SHAPEHEADER* on to the display block */ + + dptr->ObShapeData = shapeheaderptr; + #else + shapeheaderptr = dptr->ObShapeData; + #endif + + + /* Texture Animation Control */ + if(dptr->ObTxAnimCtrlBlks) ControlTextureAnimation(dptr); + + /* Global Variables */ + Global_VDB_Ptr = VDB_Ptr; + Global_ODB_Ptr = dptr; + Global_ShapeHeaderPtr = shapeheaderptr; + +// if((Global_ODB_Ptr->ObStrategyBlock)&&(Global_ODB_Ptr->ObStrategyBlock->I_SBtype == I_BehaviourAlien)) + // textprint("hier alien part\n"); + + /* Shape Language Specific Setup */ + SetupShapePipeline(); + + /* + + Create the Local -> View Matrix + + LToVMat = VDB_Mat * ObMat + + "Get the points into View Space, then apply the Local Transformation" + + */ + + MatrixMultiply(&VDB_Ptr->VDB_Mat, &dptr->ObMat, <oVMat); + MatrixToEuler(<oVMat, <oVMat_Euler); + + /* + + Create the World -> Local Matrix + + WToLMat = Transposed Local Matrix + + */ + + CopyMatrix(&dptr->ObMat, &WToLMat); + TransposeMatrixCH(&WToLMat); + + + /* + + Transform the View World Location to Local Space + + -> Make the View Loc. relative to the Object View Space Centre + -> Rotate this vector using WToLMat + + */ + + + MakeVector(&VDB_Ptr->VDB_World, &dptr->ObWorld, &LocalView); + RotateVector(&LocalView, &WToLMat); + + if (!(PIPECLEANER_CHEATMODE||BALLSOFFIRE_CHEATMODE) || !dptr->ObStrategyBlock) + { + /* Find out which light sources are in range of of the object */ + LightSourcesInRangeOfObject(dptr); + + /* Shape Language Execution Shell */ + shapeinstrptr = shapeheaderptr->sh_instruction; + + /* setup the rotated points array */ + if( (dptr->SpecialFXFlags & SFXFLAG_MELTINGINTOGROUND) + &&(dptr->ObFlags2 <= ONE_FIXED) ) + { + SquishPoints(shapeinstrptr); + } + else + { + TranslateShapeVertices(shapeinstrptr); + } + + /* call polygon pipeline */ + ShapePipeline(shapeheaderptr); + } + + if (BALLSOFFIRE_CHEATMODE && dptr->ObStrategyBlock) + { + HandleObjectOnFire(dptr); + } + + /* call sfx code */ + HandleSfxForObject(dptr); + +} + + +float ViewMatrix[12]; +float ObjectViewMatrix[12]; +float Source[3]; +float Dest[3]; + +extern void TranslationSetup(void) +{ + VECTORCH v = Global_VDB_Ptr->VDB_World; + extern int PredatorVisionChangeCounter; + float p = PredatorVisionChangeCounter/65536.0f; + float o = 1.0f; + p = 1.0f+p; + + if (NAUSEA_CHEATMODE) + { + p = (GetSin((CloakingPhase/3)&4095))/65536.0f; + p = 1.0f + p*p; + + o = (GetCos((CloakingPhase/5)&4095))/65536.0f; + o = 1.0f + o*o; + } + + #if 1 + ViewMatrix[0+0*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat11)/65536.0f*o; + ViewMatrix[1+0*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat21)/65536.0f*o; + ViewMatrix[2+0*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat31)/65536.0f*o; + #else + ViewMatrix[0+0*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat11)/65536.0f; + ViewMatrix[1+0*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat21)/65536.0f; + ViewMatrix[2+0*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat31)/65536.0f; + #endif + + #if 1 + ViewMatrix[0+1*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat12)*4.0f/(65536.0f*3.0f)*p; + ViewMatrix[1+1*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat22)*4.0f/(65536.0f*3.0f)*p; + ViewMatrix[2+1*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat32)*4.0f/(65536.0f*3.0f)*p; + #else + ViewMatrix[0+1*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat12)/(65536.0f); + ViewMatrix[1+1*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat22)/(65536.0f); + ViewMatrix[2+1*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat32)/(65536.0f); + #endif + ViewMatrix[0+2*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat13)/65536.0f*CameraZoomScale; + ViewMatrix[1+2*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat23)/65536.0f*CameraZoomScale; + ViewMatrix[2+2*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat33)/65536.0f*CameraZoomScale; + + RotateVector(&v,&Global_VDB_Ptr->VDB_Mat); + + ViewMatrix[3+0*4] = ((float)-v.vx)*o; + ViewMatrix[3+1*4] = ((float)-v.vy)*4.0f/3.0f*p; + ViewMatrix[3+2*4] = ((float)-v.vz)*CameraZoomScale; + + if (MIRROR_CHEATMODE) + { + ViewMatrix[0+0*4] = -ViewMatrix[0+0*4]; + ViewMatrix[1+0*4] = -ViewMatrix[1+0*4]; + ViewMatrix[2+0*4] = -ViewMatrix[2+0*4]; + + ViewMatrix[3+0*4] = -ViewMatrix[3+0*4]; + } +} + + +#if ifndef _MSC_VER +void TranslatePoint(int *source, int *dest, int *matrix); +#pragma aux TranslatePoint = \ +"fld DWORD PTR [esi]"\ +"fmul DWORD PTR [edi]"\ +"fld DWORD PTR [esi+4]"\ +"fmul DWORD PTR [edi+4]"\ +"fld DWORD PTR [esi+8]"\ +"fmul DWORD PTR [edi+8]"\ +"fxch st(1)"\ +"faddp st(2),st"\ +"fld DWORD PTR [esi]"\ +"fmul DWORD PTR [edi+16]"\ +"fxch st(1)"\ +"faddp st(2),st"\ +"fld DWORD PTR [esi+4]"\ +"fmul DWORD PTR [edi+20]"\ +"fld DWORD PTR [esi+8]"\ +"fmul DWORD PTR [edi+24]"\ +"fxch st(1)"\ +"faddp st(2),st"\ +"fld DWORD PTR [esi]"\ +"fmul DWORD PTR [edi+32]"\ +"fxch st(1)"\ +"faddp st(2),st"\ +"fld DWORD PTR [esi+4]"\ +"fmul DWORD PTR [edi+36]"\ +"fld DWORD PTR [esi+8]"\ +"fmul DWORD PTR [edi+40]"\ +"fxch st(1)"\ +"faddp st(2),st"\ +"fxch st(3)"\ +"fadd DWORD PTR [edi+12]"\ +"fxch st(1)"\ +"faddp st(3),st"\ +"fxch st(1)"\ +"fadd DWORD PTR [edi+28]"\ +"fxch st(2)"\ +"fadd DWORD PTR [edi+44]"\ +"fxch st(1)"\ +"fstp DWORD PTR [ebx]"\ +"fxch st(1)"\ +"fstp DWORD PTR [ebx+4]"\ +"fstp DWORD PTR [ebx+8]"\ +parm[esi] [ebx] [edi]; + +#else +void TranslatePoint(int *source, int *dest, int *matrix) +{ + __asm + { + mov esi,source + mov ebx,dest + mov edi,matrix + fld DWORD PTR [esi] + fmul DWORD PTR [edi] + fld DWORD PTR [esi+4] + fmul DWORD PTR [edi+4] + fld DWORD PTR [esi+8] + fmul DWORD PTR [edi+8] + fxch st(1) + faddp st(2),st + fld DWORD PTR [esi] + fmul DWORD PTR [edi+16] + fxch st(1) + faddp st(2),st + fld DWORD PTR [esi+4] + fmul DWORD PTR [edi+20] + fld DWORD PTR [esi+8] + fmul DWORD PTR [edi+24] + fxch st(1) + faddp st(2),st + fld DWORD PTR [esi] + fmul DWORD PTR [edi+32] + fxch st(1) + faddp st(2),st + fld DWORD PTR [esi+4] + fmul DWORD PTR [edi+36] + fld DWORD PTR [esi+8] + fmul DWORD PTR [edi+40] + fxch st(1) + faddp st(2),st + fxch st(3) + fadd DWORD PTR [edi+12] + fxch st(1) + faddp st(3),st + fxch st(1) + fadd DWORD PTR [edi+28] + fxch st(2) + fadd DWORD PTR [edi+44] + fxch st(1) + fstp DWORD PTR [ebx] + fxch st(1) + fstp DWORD PTR [ebx+4] + fstp DWORD PTR [ebx+8] + } +} + +#endif + +void TranslatePointIntoViewspace(VECTORCH *pointPtr) +{ + + Source[0] = pointPtr->vx; + Source[1] = pointPtr->vy; + Source[2] = pointPtr->vz; + + TranslatePoint((int*)&Source,(int*)&Dest,(int*)&ViewMatrix); + + f2i(pointPtr->vx,Dest[0]); + f2i(pointPtr->vy,Dest[1]); + f2i(pointPtr->vz,Dest[2]); +} +void SquishPoints(SHAPEINSTR *shapeinstrptr) +{ + int **shapeitemarrayptr = shapeinstrptr->sh_instr_data; + VECTORCH *shapePts = (VECTORCH*)*shapeitemarrayptr; + { + int i; + int scale = Global_ODB_Ptr->ObFlags2; + + for (i=0; inumpoints; i++) + { + VECTORCH point = shapePts[i]; + + RotateVector(&point,&Global_ODB_Ptr->ObMat); + + point.vx = MUL_FIXED(point.vx,ONE_FIXED*3/2 - scale/2); + point.vx += Global_ODB_Ptr->ObWorld.vx; + + point.vz = MUL_FIXED(point.vz,ONE_FIXED*3/2 - scale/2); + point.vz += Global_ODB_Ptr->ObWorld.vz; + + point.vy += Global_ODB_Ptr->ObWorld.vy; + point.vy = HierarchicalObjectsLowestYValue + MUL_FIXED(point.vy-HierarchicalObjectsLowestYValue, scale); + + Source[0] = point.vx; + Source[1] = point.vy; + Source[2] = point.vz; + + TranslatePoint((int*)&Source,(int*)&Dest,(int*)&ViewMatrix); + + f2i(RotatedPts[i].vx,Dest[0]); + f2i(RotatedPts[i].vy,Dest[1]); + f2i(RotatedPts[i].vz,Dest[2]); + } + } +} + +void MorphPoints(SHAPEINSTR *shapeinstrptr) +{ + VECTORCH *srcPtr; + { + SHAPEHEADER *shape1Ptr; + VECTORCH *shape1PointsPtr; + VECTORCH *shape2PointsPtr; + + /* Set up the morph data */ + GetMorphDisplay(&MorphDisplay, Global_ODB_Ptr); + + shape1Ptr = MorphDisplay.md_sptr1; + + if(MorphDisplay.md_lerp == 0x0000) + { + + srcPtr = (VECTORCH *)*shape1Ptr->points; + } + else if(MorphDisplay.md_lerp == 0xffff) + { + SHAPEHEADER *shape2Ptr; + shape2Ptr = MorphDisplay.md_sptr2; + + srcPtr = (VECTORCH *)*shape2Ptr->points; + Global_ShapePoints = *(shape2Ptr->points); + + } + else + { + SHAPEHEADER *shape2Ptr; + shape2Ptr = MorphDisplay.md_sptr2; + + shape1PointsPtr = (VECTORCH *)(*shape1Ptr->points); + shape2PointsPtr = (VECTORCH *)(*shape2Ptr->points); + + { + int numberOfPoints = shape1Ptr->numpoints; + VECTORCH *morphedPointsPtr = (VECTORCH *) MorphedPts; + + while(numberOfPoints--) + { + VECTORCH vertex1 = *shape1PointsPtr; + VECTORCH vertex2 = *shape2PointsPtr; + + if( (vertex1.vx == vertex2.vx && vertex1.vy == vertex2.vy && vertex1.vz == vertex2.vz) ) + { + *morphedPointsPtr = vertex1; + } + else + { + /* KJL 15:27:20 05/22/97 - I've changed this to speed things up, If a vertex + component has a magnitude greater than 32768 things will go wrong. */ + morphedPointsPtr->vx = vertex1.vx + (((vertex2.vx-vertex1.vx)*MorphDisplay.md_lerp)>>16); + morphedPointsPtr->vy = vertex1.vy + (((vertex2.vy-vertex1.vy)*MorphDisplay.md_lerp)>>16); + morphedPointsPtr->vz = vertex1.vz + (((vertex2.vz-vertex1.vz)*MorphDisplay.md_lerp)>>16); + } + + shape1PointsPtr++; + shape2PointsPtr++; + morphedPointsPtr++; + } + } + + Global_ShapePoints = (int*)MorphedPts; + srcPtr = (VECTORCH *)MorphedPts; + } + } + { + VECTORCH *destPtr = RotatedPts; + int i; + for(i = shapeinstrptr->sh_numitems; i!=0; i--) + { + Source[0] = srcPtr->vx+Global_ODB_Ptr->ObWorld.vx; + Source[1] = srcPtr->vy+Global_ODB_Ptr->ObWorld.vy; + Source[2] = srcPtr->vz+Global_ODB_Ptr->ObWorld.vz; + + TranslatePoint((int*)&Source,(int*)&Dest,(int*)&ViewMatrix); + + f2i(destPtr->vx,Dest[0]); + f2i(destPtr->vy,Dest[1]); + f2i(destPtr->vz,Dest[2]); + srcPtr++; + destPtr++; + } + } + +} + +void TranslateShapeVertices(SHAPEINSTR *shapeinstrptr) +{ + VECTORCH *destPtr = RotatedPts; + int **shapeitemarrayptr; + VECTORCH *srcPtr; + int i; +// MNormalise(<oVMat); + shapeitemarrayptr = shapeinstrptr->sh_instr_data; + srcPtr = (VECTORCH*)*shapeitemarrayptr; + if (Global_ODB_Ptr->ObFlags & ObFlag_ArbRot) + { + for(i = shapeinstrptr->sh_numitems; i!=0; i--) + { + destPtr->vx = (srcPtr->vx+Global_ODB_Ptr->ObView.vx); + destPtr->vy = ((srcPtr->vy+Global_ODB_Ptr->ObView.vy)*4)/3; + destPtr->vz = (srcPtr->vz+Global_ODB_Ptr->ObView.vz); + + srcPtr++; + destPtr++; + + } + } + else + { + ObjectViewMatrix[0+0*4] = (float)(Global_ODB_Ptr->ObMat.mat11)/65536.0f; + ObjectViewMatrix[1+0*4] = (float)(Global_ODB_Ptr->ObMat.mat21)/65536.0f; + ObjectViewMatrix[2+0*4] = (float)(Global_ODB_Ptr->ObMat.mat31)/65536.0f; + + ObjectViewMatrix[0+1*4] = (float)(Global_ODB_Ptr->ObMat.mat12)/(65536.0f); + ObjectViewMatrix[1+1*4] = (float)(Global_ODB_Ptr->ObMat.mat22)/(65536.0f); + ObjectViewMatrix[2+1*4] = (float)(Global_ODB_Ptr->ObMat.mat32)/(65536.0f); + + ObjectViewMatrix[0+2*4] = (float)(Global_ODB_Ptr->ObMat.mat13)/65536.0f; + ObjectViewMatrix[1+2*4] = (float)(Global_ODB_Ptr->ObMat.mat23)/65536.0f; + ObjectViewMatrix[2+2*4] = (float)(Global_ODB_Ptr->ObMat.mat33)/65536.0f; + + ObjectViewMatrix[3+0*4] = Global_ODB_Ptr->ObWorld.vx; + ObjectViewMatrix[3+1*4] = Global_ODB_Ptr->ObWorld.vy; + ObjectViewMatrix[3+2*4] = Global_ODB_Ptr->ObWorld.vz; + for(i = shapeinstrptr->sh_numitems; i!=0; i--) + { + Source[0] = srcPtr->vx; + Source[1] = srcPtr->vy; + Source[2] = srcPtr->vz; + + TranslatePoint((int*)&Source,(int*)&Dest,(int*)&ObjectViewMatrix); + TranslatePoint((int*)&Dest,(int*)&Source,(int*)&ViewMatrix); + + f2i(destPtr->vx,Source[0]); + f2i(destPtr->vy,Source[1]); + f2i(destPtr->vz,Source[2]); + srcPtr++; + destPtr++; + } + } +} + +void RenderDecal(DECAL *decalPtr) +{ + /* translate decal into view space */ + { + VECTORCH translatedPosition = decalPtr->Vertices[0]; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[0].X = translatedPosition.vx; + VerticesBuffer[0].Y = translatedPosition.vy; + VerticesBuffer[0].Z = translatedPosition.vz; + } + { + VECTORCH translatedPosition = decalPtr->Vertices[1]; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[1].X = translatedPosition.vx; + VerticesBuffer[1].Y = translatedPosition.vy; + VerticesBuffer[1].Z = translatedPosition.vz; + } + { + VECTORCH translatedPosition = decalPtr->Vertices[2]; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[2].X = translatedPosition.vx; + VerticesBuffer[2].Y = translatedPosition.vy; + VerticesBuffer[2].Z = translatedPosition.vz; + } + { + VECTORCH translatedPosition = decalPtr->Vertices[3]; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[3].X = translatedPosition.vx; + VerticesBuffer[3].Y = translatedPosition.vy; + VerticesBuffer[3].Z = translatedPosition.vz; + } + { + int outcode = DecalWithinFrustrum(decalPtr); + + if (outcode) + { + switch(decalPtr->DecalID) + { + default: + case DECAL_SCORCHED: + { + DecalPolygon_Construct(decalPtr); + + if (outcode!=2) + { + TexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_Decal_Output(decalPtr,RenderPolygon.Vertices); + + } + else D3D_Decal_Output(decalPtr,VerticesBuffer); + break; + } + } + } + } + #if MIRRORING_ON + if (MirroringActive) RenderMirroredDecal(decalPtr); + #endif +} +void RenderParticle(PARTICLE *particlePtr) +{ +// PARTICLE_DESC *particleDescPtr = &ParticleDescription[particlePtr->ParticleID]; + int particleSize = particlePtr->Size; + + { + VECTORCH translatedPosition = particlePtr->Position; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[0].X = translatedPosition.vx; + VerticesBuffer[3].X = translatedPosition.vx; + VerticesBuffer[0].Y = translatedPosition.vy; + VerticesBuffer[3].Y = translatedPosition.vy; + VerticesBuffer[0].Z = translatedPosition.vz; + VerticesBuffer[3].Z = translatedPosition.vz; + } + + if ((particlePtr->ParticleID == PARTICLE_EXPLOSIONFIRE) + ||(particlePtr->ParticleID == PARTICLE_RICOCHET_SPARK) + ||(particlePtr->ParticleID == PARTICLE_SPARK) + ||(particlePtr->ParticleID == PARTICLE_ORANGE_SPARK) + ||(particlePtr->ParticleID == PARTICLE_ORANGE_PLASMA) + ||(particlePtr->ParticleID == PARTICLE_ALIEN_BLOOD) + ||(particlePtr->ParticleID == PARTICLE_PREDATOR_BLOOD) + ||(particlePtr->ParticleID == PARTICLE_HUMAN_BLOOD) + ||(particlePtr->ParticleID == PARTICLE_WATERFALLSPRAY) + ||(particlePtr->ParticleID == PARTICLE_LASERBEAM) + ||(particlePtr->ParticleID == PARTICLE_PLASMABEAM) + ||(particlePtr->ParticleID == PARTICLE_TRACER) + ||(particlePtr->ParticleID == PARTICLE_PREDPISTOL_FLECHETTE) + ||(particlePtr->ParticleID == PARTICLE_PREDPISTOL_FLECHETTE_NONDAMAGING) + ) + { + VECTORCH translatedPosition = particlePtr->Offset; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[1].X = translatedPosition.vx; + VerticesBuffer[2].X = translatedPosition.vx; + VerticesBuffer[1].Y = translatedPosition.vy; + VerticesBuffer[2].Y = translatedPosition.vy; + VerticesBuffer[1].Z = translatedPosition.vz; + VerticesBuffer[2].Z = translatedPosition.vz; + + { + int deltaX = VerticesBuffer[1].X - VerticesBuffer[0].X; + int deltaY = VerticesBuffer[1].Y - VerticesBuffer[0].Y; + int splitY = 0; + + if (deltaX>=0) + { + if (deltaY>=0) + { + if (deltaX>deltaY) + { + splitY = 1; + } + } + else if (deltaX>-deltaY) + { + splitY = 1; + } + } + else + { + if (deltaY>=0) + { + if (-deltaX>deltaY) + { + splitY = 1; + } + } + else if (-deltaX>-deltaY) + { + splitY = 1; + } + } + if (splitY) + { + if (deltaX>0) + { + /* 1 & 2 are more +ve in X */ + VerticesBuffer[0].X -= particleSize; + VerticesBuffer[0].Y -= MUL_FIXED(particleSize,87381); + VerticesBuffer[1].X += particleSize; + VerticesBuffer[1].Y -= MUL_FIXED(particleSize,87381); + VerticesBuffer[2].X += particleSize; + VerticesBuffer[2].Y += MUL_FIXED(particleSize,87381); + VerticesBuffer[3].X -= particleSize; + VerticesBuffer[3].Y += MUL_FIXED(particleSize,87381); + } + else + { + /* 1 & 2 are more -ve in X */ + VerticesBuffer[0].X += particleSize; + VerticesBuffer[0].Y -= MUL_FIXED(particleSize,87381); + VerticesBuffer[1].X -= particleSize; + VerticesBuffer[1].Y -= MUL_FIXED(particleSize,87381); + VerticesBuffer[2].X -= particleSize; + VerticesBuffer[2].Y += MUL_FIXED(particleSize,87381); + VerticesBuffer[3].X += particleSize; + VerticesBuffer[3].Y += MUL_FIXED(particleSize,87381); + } + + } + else + { + if (deltaY>0) + { + /* 1 & 2 are more +ve in Y */ + VerticesBuffer[0].X -= particleSize; + VerticesBuffer[0].Y -= MUL_FIXED(particleSize,87381); + VerticesBuffer[1].X -= particleSize; + VerticesBuffer[1].Y += MUL_FIXED(particleSize,87381); + VerticesBuffer[2].X += particleSize; + VerticesBuffer[2].Y += MUL_FIXED(particleSize,87381); + VerticesBuffer[3].X += particleSize; + VerticesBuffer[3].Y -= MUL_FIXED(particleSize,87381); + } + else + { + /* 1 & 2 are more -ve in Y */ + VerticesBuffer[0].X -= particleSize; + VerticesBuffer[0].Y += MUL_FIXED(particleSize,87381); + VerticesBuffer[1].X -= particleSize; + VerticesBuffer[1].Y -= MUL_FIXED(particleSize,87381); + VerticesBuffer[2].X += particleSize; + VerticesBuffer[2].Y -= MUL_FIXED(particleSize,87381); + VerticesBuffer[3].X += particleSize; + VerticesBuffer[3].Y += MUL_FIXED(particleSize,87381); + } + + } + } + } + else + { + VECTOR2D offset[4]; + VerticesBuffer[1].X = VerticesBuffer[0].X; + VerticesBuffer[2].X = VerticesBuffer[0].X; + VerticesBuffer[1].Y = VerticesBuffer[0].Y; + VerticesBuffer[2].Y = VerticesBuffer[0].Y; + VerticesBuffer[1].Z = VerticesBuffer[0].Z; + VerticesBuffer[2].Z = VerticesBuffer[0].Z; + + offset[0].vx = -particleSize; + offset[0].vy = -particleSize; + + offset[1].vx = +particleSize; + offset[1].vy = -particleSize; + + offset[2].vx = +particleSize; + offset[2].vy = +particleSize; + + offset[3].vx = -particleSize; + offset[3].vy = +particleSize; + + if ((particlePtr->ParticleID == PARTICLE_MUZZLEFLASH) ) + { + extern void RotateVertex(VECTOR2D *vertexPtr, int theta); + int theta = FastRandom()&4095; + RotateVertex(&offset[0],theta); + RotateVertex(&offset[1],theta); + RotateVertex(&offset[2],theta); + RotateVertex(&offset[3],theta); + } + else if ((particlePtr->ParticleID == PARTICLE_SMOKECLOUD) + ||(particlePtr->ParticleID == PARTICLE_GUNMUZZLE_SMOKE) + ||(particlePtr->ParticleID == PARTICLE_PARGEN_FLAME) + ||(particlePtr->ParticleID == PARTICLE_FLAME)) + { + extern void RotateVertex(VECTOR2D *vertexPtr, int theta); + int theta = (particlePtr->Offset.vx+MUL_FIXED(CloakingPhase,particlePtr->Offset.vy))&4095; + RotateVertex(&offset[0],theta); + RotateVertex(&offset[1],theta); + RotateVertex(&offset[2],theta); + RotateVertex(&offset[3],theta); + } + VerticesBuffer[0].X += offset[0].vx; + VerticesBuffer[0].Y += MUL_FIXED(offset[0].vy,87381); + + VerticesBuffer[1].X += offset[1].vx; + VerticesBuffer[1].Y += MUL_FIXED(offset[1].vy,87381); + + VerticesBuffer[2].X += offset[2].vx; + VerticesBuffer[2].Y += MUL_FIXED(offset[2].vy,87381); + + VerticesBuffer[3].X += offset[3].vx; + VerticesBuffer[3].Y += MUL_FIXED(offset[3].vy,87381); + + } + + { + int outcode = QuadWithinFrustrum(); + + if (outcode) + { + ParticlePolygon_Construct(particlePtr); + + if (outcode!=2) + { + TexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_Particle_Output(particlePtr,RenderPolygon.Vertices); + + } + else D3D_Particle_Output(particlePtr,VerticesBuffer); + } + } +} + +extern void RenderFlechetteParticle(PARTICLE *particlePtr) +{ + VECTORCH vertices[5]; + MATRIXCH mat; + + MakeMatrixFromDirection(&particlePtr->Velocity,&mat); + + mat.mat11 >>= 12; + mat.mat12 >>= 12; + mat.mat13 >>= 12; + mat.mat21 >>= 12; + mat.mat22 >>= 12; + mat.mat23 >>= 12; + mat.mat31 >>= 9; + mat.mat32 >>= 9; + mat.mat33 >>= 9; + + + vertices[0].vx = particlePtr->Position.vx-mat.mat31+mat.mat11; + vertices[0].vy = particlePtr->Position.vy-mat.mat32+mat.mat12; + vertices[0].vz = particlePtr->Position.vz-mat.mat33+mat.mat13; + + vertices[1].vx = particlePtr->Position.vx-mat.mat31-mat.mat11; + vertices[1].vy = particlePtr->Position.vy-mat.mat32-mat.mat12; + vertices[1].vz = particlePtr->Position.vz-mat.mat33-mat.mat13; + + vertices[2] = particlePtr->Position; + + vertices[3].vx = particlePtr->Position.vx-mat.mat31+mat.mat21; + vertices[3].vy = particlePtr->Position.vy-mat.mat32+mat.mat22; + vertices[3].vz = particlePtr->Position.vz-mat.mat33+mat.mat23; + + vertices[4].vx = particlePtr->Position.vx-mat.mat31-mat.mat21; + vertices[4].vy = particlePtr->Position.vy-mat.mat32-mat.mat22; + vertices[4].vz = particlePtr->Position.vz-mat.mat33-mat.mat23; + + TranslatePointIntoViewspace(&vertices[0]); + TranslatePointIntoViewspace(&vertices[1]); + TranslatePointIntoViewspace(&vertices[2]); + TranslatePointIntoViewspace(&vertices[3]); + TranslatePointIntoViewspace(&vertices[4]); + + { + int i; + for (i=0; i<3; i++) + { + VerticesBuffer[i].X = vertices[i].vx; + VerticesBuffer[i].Y = vertices[i].vy; + VerticesBuffer[i].Z = vertices[i].vz; + + VerticesBuffer[i].A = (particlePtr->Colour>>24)&255; + VerticesBuffer[i].R = (particlePtr->Colour>>16)&255; + VerticesBuffer[i].G = (particlePtr->Colour>>8)&255; + VerticesBuffer[i].B = (particlePtr->Colour)&255; + } + RenderPolygon.NumberOfVertices=3; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + { + int outcode = TriangleWithinFrustrum(); + POLYHEADER fakeHeader; + fakeHeader.PolyFlags = iflag_transparent; + + do + { + if (outcode) + { + if (outcode!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,VerticesBuffer); + } + } + while(0); + } + { + int i; + for (i=0; i<3; i++) + { + VerticesBuffer[i].X = vertices[i+2].vx; + VerticesBuffer[i].Y = vertices[i+2].vy; + VerticesBuffer[i].Z = vertices[i+2].vz; + + VerticesBuffer[i].A = (particlePtr->Colour>>24)&255; + VerticesBuffer[i].R = (particlePtr->Colour>>16)&255; + VerticesBuffer[i].G = (particlePtr->Colour>>8)&255; + VerticesBuffer[i].B = (particlePtr->Colour)&255; + } + RenderPolygon.NumberOfVertices=3; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + { + int outcode = TriangleWithinFrustrum(); + POLYHEADER fakeHeader; + fakeHeader.PolyFlags = iflag_transparent; + + do + { + if (outcode) + { + if (outcode!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,VerticesBuffer); + } + } + while(0); + } + +} + +static void ParticlePolygon_Construct(PARTICLE *particlePtr) +{ + PARTICLE_DESC *particleDescPtr = &ParticleDescription[particlePtr->ParticleID]; + RenderPolygon.NumberOfVertices=4; + + VerticesBuffer[0].U = particleDescPtr->StartU; + VerticesBuffer[0].V = particleDescPtr->StartV; + + VerticesBuffer[1].U = particleDescPtr->EndU; + VerticesBuffer[1].V = particleDescPtr->StartV; + + VerticesBuffer[2].U = particleDescPtr->EndU; + VerticesBuffer[2].V = particleDescPtr->EndV; + + VerticesBuffer[3].U = particleDescPtr->StartU; + VerticesBuffer[3].V = particleDescPtr->EndV; + +} + +void RenderMirroredDecal(DECAL *decalPtr) +{ + /* translate decal into view space */ + { + VECTORCH translatedPosition = decalPtr->Vertices[0]; + translatedPosition.vx = MirroringAxis - translatedPosition.vx; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[0].X = translatedPosition.vx; + VerticesBuffer[0].Y = translatedPosition.vy; + VerticesBuffer[0].Z = translatedPosition.vz; + } + { + VECTORCH translatedPosition = decalPtr->Vertices[1]; + translatedPosition.vx = MirroringAxis - translatedPosition.vx; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[1].X = translatedPosition.vx; + VerticesBuffer[1].Y = translatedPosition.vy; + VerticesBuffer[1].Z = translatedPosition.vz; + } + { + VECTORCH translatedPosition = decalPtr->Vertices[2]; + translatedPosition.vx = MirroringAxis - translatedPosition.vx; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[2].X = translatedPosition.vx; + VerticesBuffer[2].Y = translatedPosition.vy; + VerticesBuffer[2].Z = translatedPosition.vz; + } + { + VECTORCH translatedPosition = decalPtr->Vertices[3]; + translatedPosition.vx = MirroringAxis - translatedPosition.vx; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[3].X = translatedPosition.vx; + VerticesBuffer[3].Y = translatedPosition.vy; + VerticesBuffer[3].Z = translatedPosition.vz; + } + { + int outcode = DecalWithinFrustrum(decalPtr); + + if (outcode) + { + switch(decalPtr->DecalID) + { + default: + case DECAL_SCORCHED: + { + DecalPolygon_Construct(decalPtr); + + if (outcode!=2) + { + TexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_Decal_Output(decalPtr,RenderPolygon.Vertices); + + } + else D3D_Decal_Output(decalPtr,VerticesBuffer); + break; + } + } + } + } +} + + +static void DecalPolygon_Construct(DECAL *decalPtr) +{ + DECAL_DESC *decalDescPtr = &DecalDescription[decalPtr->DecalID]; + RenderPolygon.NumberOfVertices=4; + + VerticesBuffer[0].U = decalDescPtr->StartU+decalPtr->UOffset; + VerticesBuffer[0].V = decalDescPtr->StartV; + + VerticesBuffer[1].U = decalDescPtr->EndU+decalPtr->UOffset; + VerticesBuffer[1].V = decalDescPtr->StartV; + + VerticesBuffer[2].U = decalDescPtr->EndU+decalPtr->UOffset; + VerticesBuffer[2].V = decalDescPtr->EndV; + + VerticesBuffer[3].U = decalDescPtr->StartU+decalPtr->UOffset; + VerticesBuffer[3].V = decalDescPtr->EndV; + +} + +#if 0 + int polys[][4] = + { + {1,3,5,7}, + {1,3,9,11}, + {2,3,5,4}, + {2,3,9,8}, + + {0,2,4,6}, + {0,2,8,10}, + {0,1,7,6}, + {0,1,11,10}, + + {12,13,15,14}, + {4,5,7,6}, + + {8,9,5,4}, + {6,7,11,10}, + {8,4,6,10}, + {5,9,11,7}, + +// {8,2,4,4}, +// {9,3,5,5}, +// {10,0,6,6}, +// {7,1,11,11} + }; + int alphaValue[]={64,64,64,64, 16,16,16,16, 0,0,0,0, 128,128,128,128}; + +//void RenderShaftOfLight(SHAFTOFLIGHT *shaftPtr) +void RenderShaftOfLight(MODULE *modulePtr) +{ + /* translate shaft into view space */ + +// suitable for invasion2 + VECTORCH shaftVertices[]= + { + {-5500,9000,9822}, + {-4500,9000,9822}, + {-5500,10000,9822}, + {-4500,10000,9822}, + + {-6000,15900,13000}, + {-4000,15900,13000}, + {-6000,15900,15500}, + {-4000,15900,15500}, + + {-6500,15900,12500}, + {-3500,15900,12500}, + {-6500,15900,16000}, + {-3500,15900,16000}, + }; + /* + VECTORCH shaftVertices[]= + { + {0, 0, 0}, + {0, 0, 1139}, + {-1338, 7113, 0}, + {-1338, 7113, 1139}, + + + {,1948,} + + {26002+ -1700, 7781 , -25328+ -800}, + {26002+ -900, 7781 , -25328+ +800}, + {26002+ 1700, 7781 , -25328+ -800}, + {26002+ 1700, 7781 , -25328+ +800}, + + {26002+ -1100, 7781 , -25328+ -1000}, + {26002+ -1100, 7781 , -25328+ +1000}, + {26002+ 2000, 7781 , -25328+ -1000}, + {26002+ 2000, 7781 , -25328+ +1000}, + + }; + */ + VECTORCH translatedPts[12]; + + POLYHEADER fakeHeader; + DECAL fakeDecal; + int polyNumber; + + fakeDecal.ModuleIndex=148; +// fakeDecal.ModuleIndex=17; + fakeHeader.PolyFlags = iflag_transparent; + + { + int i = 11; + do + { + translatedPts[i] = shaftVertices[i]; +// translatedPts[i].vx+=10712; +// translatedPts[i].vy+=-6480; +// translatedPts[i].vz+=-25898; + TranslatePointIntoViewspace(&translatedPts[i]); + } + while(i--); + } + + for(polyNumber=0; polyNumber<10; polyNumber++) + { + { + int i; + for (i=0; i<4; i++) + { + int v = polys[polyNumber][i]; + VerticesBuffer[i].A = alphaValue[v]; + if (v>11) + { + VerticesBuffer[i].X = translatedPts[v-12].vx; + VerticesBuffer[i].Y = translatedPts[v-12].vy; + VerticesBuffer[i].Z = translatedPts[v-12].vz; + } + else + { + VerticesBuffer[i].X = translatedPts[v].vx; + VerticesBuffer[i].Y = translatedPts[v].vy; + VerticesBuffer[i].Z = translatedPts[v].vz; + } + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 192; + } + RenderPolygon.NumberOfVertices=4; + } + { + int outcode = DecalWithinFrustrum(&fakeDecal); + + if (outcode) + { + if (outcode!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,VerticesBuffer); + } + } + } +} +#else + int polys[][4] = + { + {0,1,3,2}, + {2,3,5,4}, + {4,5,7,6}, + + {1,3,5,7}, + {0,2,4,6}, + {6,8,10,0}, + {7,9,11,1}, + + {0,1,11,10}, + {6,7,9,8}, + + + }; + int alphaValue[]={32,32,32,32, 28,28,28,28, 4,4,4,4, 128,128,128,128}; +// int alphaValue[]={16,16,16,16, 14,14,14,14, 2,2,2,2, 128,128,128,128}; + VECTORCH shaftVertices[]= + { + {0, 0, 0}, + {0, 0, 1956}, + {-1492, 7969, 0}, + {-1492, 7969, 1956}, + +// {0, 0, 0}, +// {0, 0, 1139}, +// {-1338, 7113, 0}, +// {-1338, 7113, 1139}, + + {0, 8840, 0}, + {0, 8840, 0}, + {3138, 8850, 0}, + {3138, 8850, 0}, + + {0, 14500, 0}, + {0, 14500, 0}, + {0, 14500, 0}, + {0, 14500, 0}, + + + }; + +void RenderShaftOfLight(MODULE *modulePtr) +{ + /* translate shaft into view space */ + #define NUM_OF_SHAFT_VERTICES 12 + VECTORCH translatedPts[NUM_OF_SHAFT_VERTICES]; + + POLYHEADER fakeHeader; + DECAL fakeDecal; + int polyNumber; + VECTORCH lightDirection1 = {29309,29309,-2000}; + VECTORCH lightDirection2 = {29309,29309,2000}; + +// return; + { + int offset = GetSin((CloakingPhase/16)&4095); + if (offset<0) offset=-offset; + offset = MUL_FIXED(offset,offset); + offset = MUL_FIXED(offset,offset); + offset=MUL_FIXED(offset,4000); + lightDirection1.vz += offset; + lightDirection2.vz += offset; + } + Normalise(&lightDirection1); + Normalise(&lightDirection2); +// textprint("light shaft active"); + fakeDecal.ModuleIndex=modulePtr->m_index; + fakeHeader.PolyFlags = iflag_transparent; + + + FindIntersectionWithYPlane(&shaftVertices[2],&lightDirection1,&shaftVertices[4]); + FindIntersectionWithYPlane(&shaftVertices[3],&lightDirection2,&shaftVertices[5]); + FindZFromXYIntersection(&shaftVertices[2],&lightDirection1,&shaftVertices[6]); + FindZFromXYIntersection(&shaftVertices[3],&lightDirection2,&shaftVertices[7]); + FindIntersectionWithYPlane(&shaftVertices[0],&lightDirection1,&shaftVertices[10]); + FindIntersectionWithYPlane(&shaftVertices[1],&lightDirection2,&shaftVertices[11]); + FindIntersectionWithYPlane(&shaftVertices[6],&lightDirection1,&shaftVertices[8]); + FindIntersectionWithYPlane(&shaftVertices[7],&lightDirection2,&shaftVertices[9]); + + { + + int i = NUM_OF_SHAFT_VERTICES-1; + do + { + translatedPts[i] = shaftVertices[i]; + translatedPts[i].vx+=11762; + translatedPts[i].vy+=-6919; + translatedPts[i].vz+=-26312; +// translatedPts[i].vx+=10712; +// translatedPts[i].vy+=-6480; +// translatedPts[i].vz+=-25898; + TranslatePointIntoViewspace(&translatedPts[i]); + } + while(i--); + } + + + for(polyNumber=0; polyNumber<9; polyNumber++) + { + { + int i; + for (i=0; i<4; i++) + { + int v = polys[polyNumber][i]; + VerticesBuffer[i].A = alphaValue[v]; + VerticesBuffer[i].X = translatedPts[v].vx; + VerticesBuffer[i].Y = translatedPts[v].vy; + VerticesBuffer[i].Z = translatedPts[v].vz; + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 192; + } + RenderPolygon.NumberOfVertices=4; + } + { + int outcode = DecalWithinFrustrum(&fakeDecal); + + if (outcode) + { + if (outcode!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,VerticesBuffer); + } + } + } + RenderShaftOfLight2(modulePtr); +} +void RenderShaftOfLight2(MODULE *modulePtr) +{ + /* translate shaft into view space */ + #define NUM_OF_SHAFT_VERTICES 12 + VECTORCH translatedPts[NUM_OF_SHAFT_VERTICES]; + + POLYHEADER fakeHeader; + DECAL fakeDecal; + int polyNumber; + VECTORCH lightDirection1 = {29309+1000,29309,-3000}; + VECTORCH lightDirection2 = {29309+1000,29309,3000}; + VECTORCH lightDirection3 = {29309-1000,29309,-3000}; + VECTORCH lightDirection4 = {29309-1000,29309,3000}; + { + int offset = GetSin((CloakingPhase/16)&4095); + if (offset<0) offset=-offset; + offset = MUL_FIXED(offset,offset); + offset = MUL_FIXED(offset,offset); + offset=MUL_FIXED(offset,4000); + lightDirection1.vz += offset; + lightDirection2.vz += offset; + lightDirection3.vz += offset; + lightDirection4.vz += offset; + } + Normalise(&lightDirection1); + Normalise(&lightDirection2); + Normalise(&lightDirection3); + Normalise(&lightDirection4); + + fakeDecal.ModuleIndex=modulePtr->m_index; + fakeHeader.PolyFlags = iflag_transparent; + + + FindIntersectionWithYPlane(&shaftVertices[2],&lightDirection1,&shaftVertices[4]); + FindIntersectionWithYPlane(&shaftVertices[3],&lightDirection2,&shaftVertices[5]); + FindZFromXYIntersection(&shaftVertices[2],&lightDirection3,&shaftVertices[6]); + FindZFromXYIntersection(&shaftVertices[3],&lightDirection4,&shaftVertices[7]); + FindIntersectionWithYPlane(&shaftVertices[0],&lightDirection1,&shaftVertices[10]); + FindIntersectionWithYPlane(&shaftVertices[1],&lightDirection2,&shaftVertices[11]); + FindIntersectionWithYPlane(&shaftVertices[6],&lightDirection3,&shaftVertices[8]); + FindIntersectionWithYPlane(&shaftVertices[7],&lightDirection4,&shaftVertices[9]); + + + { + + int i = NUM_OF_SHAFT_VERTICES-1; + do + { + translatedPts[i] = shaftVertices[i]; + translatedPts[i].vx+=11762; + translatedPts[i].vy+=-6919; + translatedPts[i].vz+=-26312; +// translatedPts[i].vx+=10712; +// translatedPts[i].vy+=-6480; +// translatedPts[i].vz+=-25898; + TranslatePointIntoViewspace(&translatedPts[i]); + } + while(i--); + } + + + for(polyNumber=0; polyNumber<9; polyNumber++) + { + { + int i; + for (i=0; i<4; i++) + { + int v = polys[polyNumber][i]; + VerticesBuffer[i].A = alphaValue[v]/2; + VerticesBuffer[i].X = translatedPts[v].vx; + VerticesBuffer[i].Y = translatedPts[v].vy; + VerticesBuffer[i].Z = translatedPts[v].vz; + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 192; + } + RenderPolygon.NumberOfVertices=4; + } + { + int outcode = DecalWithinFrustrum(&fakeDecal); + + if (outcode) + { + if (outcode!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,VerticesBuffer); + } + } + } +} + +void FindIntersectionWithYPlane(VECTORCH *startPtr, VECTORCH *directionPtr, VECTORCH *intersectionPtr) +{ + int lambda = DIV_FIXED(intersectionPtr->vy - startPtr->vy,directionPtr->vy); + + intersectionPtr->vx = startPtr->vx + MUL_FIXED(directionPtr->vx,lambda); + intersectionPtr->vz = startPtr->vz + MUL_FIXED(directionPtr->vz,lambda); +// textprint("%d %d %d\n",intersectionPtr->vx,intersectionPtr->vy,intersectionPtr->vz); +} +void FindZFromXYIntersection(VECTORCH *startPtr, VECTORCH *directionPtr, VECTORCH *intersectionPtr) +{ + float a = intersectionPtr->vx - startPtr->vx; + + a/=directionPtr->vx; + + intersectionPtr->vz = startPtr->vz + (directionPtr->vz*a); +// textprint("%d %d %d\n",intersectionPtr->vx,intersectionPtr->vy,intersectionPtr->vz); +} + +#endif + + + + + + + + + + + + +void ClearTranslucentPolyList(void) +{ + CurrentNumberOfTranslucentPolygons=0; +} + +void AddToTranslucentPolyList(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr) +{ + /* copy the data to the list for processing later */ + int i = RenderPolygon.NumberOfVertices; + int maxZ = 0; + RENDERVERTEX *vertexPtr = TranslucentPolygons[CurrentNumberOfTranslucentPolygons].Vertices; + + TranslucentPolygons[CurrentNumberOfTranslucentPolygons].NumberOfVertices = i; + + do + { + if (maxZZ) + maxZ = renderVerticesPtr->Z; + *vertexPtr++ = *renderVerticesPtr++; + } + while(--i); + TranslucentPolygons[CurrentNumberOfTranslucentPolygons].MaxZ = maxZ; + TranslucentPolygonHeaders[CurrentNumberOfTranslucentPolygons] = *inputPolyPtr; + + /* increment counter */ + CurrentNumberOfTranslucentPolygons++; + LOCALASSERT(CurrentNumberOfTranslucentPolygonsTranslucentPolygons[maxFound].MaxZ) + { + maxFound = k; + } + } + + RenderAllParticlesFurtherAwayThan(TranslucentPolygons[maxFound].MaxZ); + + RenderPolygon.NumberOfVertices = TranslucentPolygons[maxFound].NumberOfVertices; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + D3D_ZBufferedGouraudTexturedPolygon_Output(&TranslucentPolygonHeaders[maxFound],TranslucentPolygons[maxFound].Vertices); + TranslucentPolygons[maxFound].MaxZ=0; + } + + RenderAllParticlesFurtherAwayThan(-0x7fffffff); + +} + + + + +#if 0 +int CuboidPolyVertexList[][4] = +{ + {0,1,2,3}, //+ve x + {0,3,7,4}, //+ve y + {6,7,3,2}, //+ve z + + {6,7,4,5}, //-ve x + {6,5,1,2}, //-ve y + {0,1,5,4}, //-ve z +}; +EULER CubeOrient = {0,0,0}; +void CubeOMatic(void) +{ + #define CUBESCALE 128 + VECTORCH vertices[8]= + { + {+CUBESCALE,+CUBESCALE,-CUBESCALE}, + {+CUBESCALE,-CUBESCALE,-CUBESCALE}, + {+CUBESCALE,-CUBESCALE,+CUBESCALE}, + {+CUBESCALE,+CUBESCALE,+CUBESCALE}, + {-CUBESCALE,+CUBESCALE,-CUBESCALE}, + {-CUBESCALE,-CUBESCALE,-CUBESCALE}, + {-CUBESCALE,-CUBESCALE,+CUBESCALE}, + {-CUBESCALE,+CUBESCALE,+CUBESCALE}, + }; + VECTORCH translatedPts[8]; + + POLYHEADER fakeHeader; + int polyNumber; + MATRIXCH matrix; + CreateEulerMatrix(&CubeOrient,&matrix); + TransposeMatrixCH(&matrix); + + CubeOrient.EulerX += MUL_FIXED(NormalFrameTime,128*4); + CubeOrient.EulerX &=4095; + CubeOrient.EulerY += MUL_FIXED(NormalFrameTime,256*4); + CubeOrient.EulerY &=4095; + CubeOrient.EulerZ += MUL_FIXED(NormalFrameTime,128*4); + CubeOrient.EulerZ &=4095; + + fakeHeader.PolyFlags = iflag_transparent; + + { + + int i = 7; + do + { + translatedPts[i] = vertices[i]; + RotateVector(&translatedPts[i],&matrix); + translatedPts[i].vy = MUL_FIXED(translatedPts[i].vy,87381); + } + while(i--); + } + + + for(polyNumber=0; polyNumber<6; polyNumber++) + { + { + int i; + for (i=0; i<4; i++) + { + int v = CuboidPolyVertexList[polyNumber][i]; + VerticesBuffer[i].A = 128; + VerticesBuffer[i].X = translatedPts[v].vx-400; + VerticesBuffer[i].Y = translatedPts[v].vy+300; + VerticesBuffer[i].Z = translatedPts[v].vz+900; + VerticesBuffer[i].Y = MUL_FIXED(VerticesBuffer[i].Y,87381); + + { + int brightness = -(translatedPts[v].vz*2); + + if (brightness<0) brightness=0; + if (brightness>255) brightness=255; + VerticesBuffer[i].R = brightness; + } + VerticesBuffer[i].G = 0; + VerticesBuffer[i].B = 0; + } + RenderPolygon.NumberOfVertices=4; + } + { + int outcode = QuadWithinFrustrum(); + + if (outcode) + { + if (outcode!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,VerticesBuffer); + } + } + } +} +#endif +int CuboidPolyVertexList[][4] = +{ + {0,3,7,4}, //+ve y +#if 0 + {0,1,2,3}, //+ve x + {0,1,5,4}, //-ve z + + {6,7,4,5}, //-ve x + {6,7,3,2}, //+ve z +#else + {6,7,3,2}, //+ve z + {6,7,4,5}, //-ve x + + {0,1,5,4}, //-ve z + {0,1,2,3}, //+ve x +#endif +}; +EULER CubeOrient = {0,0,0}; +int CuboidPolyVertexU[][4] = +{ + {1,1,1,1}, + + {127,127,0,0}, + {128,128,255,255}, + + {127,127,0,0}, + {128,128,255,255}, +}; +int CuboidPolyVertexV[][4] = +{ + {1,1,1,1}, + + {127,0,0,127}, + {127,0,0,127}, + {128,255,255,128}, + {128,255,255,128}, +}; + +#include "chnktexi.h" + +void CubeSky(void) +{ + #define CUBESCALE 1024 + VECTORCH vertices[8]= + { + #if 0 + {+CUBESCALE,-CUBESCALE,-CUBESCALE}, + {+CUBESCALE,CUBESCALE,-CUBESCALE}, + {+CUBESCALE,CUBESCALE,+CUBESCALE}, + {+CUBESCALE,-CUBESCALE,+CUBESCALE}, + {-CUBESCALE,-CUBESCALE,-CUBESCALE}, + {-CUBESCALE,CUBESCALE,-CUBESCALE}, + {-CUBESCALE,CUBESCALE,+CUBESCALE}, + {-CUBESCALE,-CUBESCALE,+CUBESCALE}, + #else + {+CUBESCALE,-CUBESCALE*2,-CUBESCALE}, + {+CUBESCALE,0,-CUBESCALE}, + {+CUBESCALE,0,+CUBESCALE}, + {+CUBESCALE,-CUBESCALE*2,+CUBESCALE}, + {-CUBESCALE,-CUBESCALE*2,-CUBESCALE}, + {-CUBESCALE,0,-CUBESCALE}, + {-CUBESCALE,0,+CUBESCALE}, + {-CUBESCALE,-CUBESCALE*2,+CUBESCALE}, + #endif + }; + VECTORCH translatedPts[8]; + + POLYHEADER fakeHeader; + int polyNumber; + + #if 1 + { + extern int BackdropImage; + fakeHeader.PolyFlags = 0; + fakeHeader.PolyColour =BackdropImage; + } + + { + + int i = 7; + do + { + translatedPts[i] = vertices[i]; + RotateVector(&translatedPts[i],&(Global_VDB_Ptr->VDB_Mat)); + translatedPts[i].vy = MUL_FIXED(translatedPts[i].vy,87381); + } + while(i--); + } + #endif + + for(polyNumber=0; polyNumber<5; polyNumber++) + { + { + int i; + for (i=0; i<4; i++) + { + int v = CuboidPolyVertexList[polyNumber][i]; + VerticesBuffer[i].A = 0; + VerticesBuffer[i].X = translatedPts[v].vx; + VerticesBuffer[i].Y = translatedPts[v].vy; + VerticesBuffer[i].Z = translatedPts[v].vz; + VerticesBuffer[i].U = CuboidPolyVertexU[polyNumber][i]<<16; + VerticesBuffer[i].V = CuboidPolyVertexV[polyNumber][i]<<16; + + + VerticesBuffer[i].R = 127; + VerticesBuffer[i].G = 127; + VerticesBuffer[i].B = 127; + } + RenderPolygon.NumberOfVertices=4; + } + { + int outcode = QuadWithinFrustrum(); + + if (outcode) + { + if (outcode!=2) + { + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_BackdropPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_BackdropPolygon_Output(&fakeHeader,VerticesBuffer); + } + } + } +} + + +void RenderMirrorSurface(void) +{ + VECTORCH translatedPts[4] = + { + {-5596,-932,-1872}, + {-5596,-932,-702}, + {-5596,1212,-702}, + {-5596,1212,-1872}, + + }; + int mirrorUV[]= + { 0,0, 127<<16,0, 127<<16,127<<16, 0,127<<16}; + POLYHEADER fakeHeader; + + + { + extern int CloudyImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = CloudyImageNumber; + } + + { + int i; + for (i=0; i<4; i++) + { + VerticesBuffer[i].A = 128; + + TranslatePointIntoViewspace(&translatedPts[i]); + VerticesBuffer[i].X = translatedPts[i].vx; + VerticesBuffer[i].Y = translatedPts[i].vy; + VerticesBuffer[i].Z = translatedPts[i].vz; + VerticesBuffer[i].U = mirrorUV[i*2]; + VerticesBuffer[i].V = mirrorUV[i*2+1]; + + + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 255; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + + } + RenderPolygon.NumberOfVertices=4; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_COLOUR; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); +} +void RenderMirrorSurface2(void) +{ + VECTORCH translatedPts[4] = + { + {-5596,-592,562}, + {-5596,-592,1344}, + {-5596,140,1344}, + {-5596,140,562}, + + }; + int mirrorUV[]= + { 0,0, 127<<16,0, 127<<16,127<<16, 0,127<<16}; + POLYHEADER fakeHeader; + + + { + extern int CloudyImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = CloudyImageNumber; + } + + { + int i; + for (i=0; i<4; i++) + { + VerticesBuffer[i].A = 128; + + TranslatePointIntoViewspace(&translatedPts[i]); + VerticesBuffer[i].X = translatedPts[i].vx; + VerticesBuffer[i].Y = translatedPts[i].vy; + VerticesBuffer[i].Z = translatedPts[i].vz; + VerticesBuffer[i].U = mirrorUV[i*2]; + VerticesBuffer[i].V = mirrorUV[i*2+1]; + + + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 255; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + + } + RenderPolygon.NumberOfVertices=4; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_COLOUR; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); +} +void RenderSmokeTest(void) +{ + int mirrorUV[]= + { + 64<<16, 0, + 64<<16, 31<<16, + 95<<16, 31<<16, + 95<<16, 0 + }; + POLYHEADER fakeHeader; + int a = GetSin(CloakingPhase&4095); + int image; + + a = MUL_FIXED(MUL_FIXED(a,a),255); + { + extern int SpecialFXImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = SpecialFXImageNumber; + } + + for (image = 0; image<=1; image++) + { + { + VECTORCH translatedPts[4] = + { + {45300,0+-1000, 26000+-1000}, + {45300,0+-1000, 26000+ 1000}, + {45300,0+ 1000, 26000+ 1000}, + {45300,0+ 1000, 26000+-1000}, + + }; + extern int CurrentLightAtPlayer; + int i; + + if (image) a = 255-a; + for (i=0; i<4; i++) + { + VerticesBuffer[i].A = a/2; + + TranslatePointIntoViewspace(&translatedPts[i]); + VerticesBuffer[i].X = translatedPts[i].vx; + VerticesBuffer[i].Y = translatedPts[i].vy; + VerticesBuffer[i].Z = translatedPts[i].vz; + VerticesBuffer[i].U = mirrorUV[i*2]; + VerticesBuffer[i].V = mirrorUV[i*2+1]+image*(32<<16); + + + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 255; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + + } + RenderPolygon.NumberOfVertices=4; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_GLOWING; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } +} +#if 1 +#define OCTAVES 3 +int u[OCTAVES]; +int v[OCTAVES]; +int du[OCTAVES]; +int dv[OCTAVES]; +int setup=0; + +int SkyColour_R=200; +int SkyColour_G=200; +int SkyColour_B=200; +void RenderSky(void) +{ + POLYHEADER fakeHeader; + int x,z,o; + if(!setup) + { + int i; + setup=1; + for(i=0;iVDB_World.vx*7)/8; + translatedPts[i].vz += 2048*z;//+(Global_VDB_Ptr->VDB_World.vz*7)/8; +// RotateVector(&translatedPts[i],&(Global_VDB_Ptr->VDB_Mat)); +// translatedPts[i].vy = MUL_FIXED(translatedPts[i].vy,87381); + translatedPts[i].vx += Global_VDB_Ptr->VDB_World.vx; + translatedPts[i].vy += Global_VDB_Ptr->VDB_World.vy; + translatedPts[i].vz += Global_VDB_Ptr->VDB_World.vz; + TranslatePointIntoViewspace(&translatedPts[i]); + VerticesBuffer[i].X = translatedPts[i].vx; + VerticesBuffer[i].Y = translatedPts[i].vy; + VerticesBuffer[i].Z = translatedPts[i].vz; + + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + VerticesBuffer[i].R = SkyColour_R; + VerticesBuffer[i].G = SkyColour_G; + VerticesBuffer[i].B = SkyColour_B; + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + VerticesBuffer[i].R = 0; + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 0; + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + VerticesBuffer[i].R = 0; + VerticesBuffer[i].G = 0; + VerticesBuffer[i].B = 255; + break; + } + } + + } + VerticesBuffer[0].U = (u[o]+size*x); + VerticesBuffer[0].V = (v[o]+size*z); + VerticesBuffer[1].U = (u[o]+size*x); + VerticesBuffer[1].V = (v[o]+size*(z+1)); + VerticesBuffer[2].U = (u[o]+size*(x+1)); + VerticesBuffer[2].V = (v[o]+size*(z+1)); + VerticesBuffer[3].U = (u[o]+size*(x+1)); + VerticesBuffer[3].V = (v[o]+size*z); + + + RenderPolygon.NumberOfVertices=4; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices>=3) + { + D3D_SkyPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + } + } + } + } + t/=2; + size*=2; + } + } + } +} +#endif +void RenderWaterFall(int xOrigin, int yOrigin, int zOrigin) +{ + int i,z; + VECTORCH v[4]; + + { + int waterfallX[9]; + int waterfallY[9]; + int waterfallZ[9]; + int waterfallZScale[9]; + for (i=0; i<9; i++) + { + + int u = (i*65536)/8; + + int b = MUL_FIXED(2*u,(65536-u)); + int c = MUL_FIXED(u,u); + int y3 = (4742-yOrigin); + int x3 = 2000; + int y2 = 2000; + int x2 = 1500; + + waterfallX[i] = MUL_FIXED(b,x2)+MUL_FIXED(c,x3); + waterfallY[i] = yOrigin+MUL_FIXED(b,y2)+MUL_FIXED(c,y3); + waterfallZ[i] = zOrigin+MUL_FIXED((66572-zOrigin),u); + waterfallZScale[i] = ONE_FIXED+b/2-c; + if (i!=8) + { + waterfallZScale[i]+=(FastRandom()&8191); + waterfallY[i]-=(FastRandom()&127); + } + + } + for (z=0; z<8; z++) + for (i=0; i<8; i++) + { + v[0].vx = xOrigin+MUL_FIXED(waterfallX[i],waterfallZScale[z]); + v[1].vx = xOrigin+MUL_FIXED(waterfallX[i],waterfallZScale[z+1]); + v[2].vx = xOrigin+MUL_FIXED(waterfallX[i+1],waterfallZScale[z+1]); + v[3].vx = xOrigin+MUL_FIXED(waterfallX[i+1],waterfallZScale[z]); + v[0].vy = waterfallY[i]; + v[1].vy = waterfallY[i]; + v[2].vy = waterfallY[i+1]; + v[3].vy = waterfallY[i+1]; + + + v[0].vz = waterfallZ[z]; + v[1].vz = waterfallZ[z+1]; + v[2].vz = v[1].vz; + v[3].vz = v[0].vz; + + DrawWaterFallPoly(v); + } + for (z=0; z<3; z++) + { + v[0].vx = xOrigin+MUL_FIXED(waterfallX[8],waterfallZScale[z+1]); + v[1].vx = xOrigin+MUL_FIXED(waterfallX[8],waterfallZScale[z]); + v[2].vx = 179450; + v[3].vx = 179450; + + v[0].vy = 4742; + v[1].vy = 4742; + v[2].vy = 4742; + v[3].vy = 4742; + + v[0].vz = waterfallZ[z]; + v[1].vz = waterfallZ[z+1]; + v[2].vz = v[1].vz; + v[3].vz = v[0].vz; + + DrawWaterFallPoly(v); + } + + for (z=0; z<8; z++) + for (i=0; i<16; i++) + { + int xOffset,xOffset2; + if (z<3) xOffset = 179450; + else xOffset = xOrigin+MUL_FIXED(waterfallX[8],waterfallZScale[z]); + if (z<2) xOffset2 = 179450; + else xOffset2 = xOrigin+MUL_FIXED(waterfallX[8],waterfallZScale[z+1]); + + v[0].vx = xOffset; + v[1].vx = xOffset2; + v[2].vx = xOffset2; + v[3].vx = xOffset; + + v[0].vy = 4742+i*4096; + v[1].vy = 4742+i*4096; + v[2].vy = 4742+(i+1)*4096; + v[3].vy = 4742+(i+1)*4096; + + + v[0].vz = waterfallZ[z]; + v[1].vz = waterfallZ[z+1]; + v[2].vz = v[1].vz; + v[3].vz = v[0].vz; + + DrawWaterFallPoly(v); + } + + } +} + +void DrawWaterFallPoly(VECTORCH *v) +{ + POLYHEADER fakeHeader; + + { + extern int CloudyImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = CloudyImageNumber; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + { + static wv=0; + unsigned int a; + for (a=0; a<4; a++) + { + VerticesBuffer[a].A = 128; + VerticesBuffer[a].U = (v[a].vz)<<11; + VerticesBuffer[a].V = (v[a].vy<<10)-wv; + + TranslatePointIntoViewspace(&v[a]); + VerticesBuffer[a].X = v[a].vx; + VerticesBuffer[a].Y = v[a].vy; + VerticesBuffer[a].Z = v[a].vz; + VerticesBuffer[a].R = 200; + VerticesBuffer[a].G = 200; + VerticesBuffer[a].B = 255; + VerticesBuffer[a].SpecularR = 0; + VerticesBuffer[a].SpecularG = 0; + VerticesBuffer[a].SpecularB = 0; + + + } + wv+=NormalFrameTime*2; + RenderPolygon.NumberOfVertices=4; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices>=3) + { + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + } + } + } + } +} +void RenderPredatorTargetingSegment(int theta, int scale, int drawInRed) +{ + VECTOR2D offset[4]; + POLYHEADER fakeHeader; + int centreX,centreY; + int z = ONE_FIXED-scale; + z = MUL_FIXED(MUL_FIXED(z,z),2048); + { + extern int SmartTargetSightX, SmartTargetSightY; + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + centreY = MUL_FIXED( (SmartTargetSightY-(ScreenDescriptorBlock.SDB_Height<<15)) /Global_VDB_Ptr->VDB_ProjY,z); + if (MIRROR_CHEATMODE) + { + centreX = MUL_FIXED( ( - (SmartTargetSightX-(ScreenDescriptorBlock.SDB_Width<<15))) /Global_VDB_Ptr->VDB_ProjX,z); + } + else + { + centreX = MUL_FIXED( (SmartTargetSightX-(ScreenDescriptorBlock.SDB_Width<<15)) /Global_VDB_Ptr->VDB_ProjX,z); + } + } + z = (float)z*CameraZoomScale; + + { + int a = 160; + int b = 40; + + /* tan(30) = 1/sqrt(3), & 65536/(sqrt(3)) = 37837 */ + + int y = MUL_FIXED(37837,a+20); + + offset[0].vx = -a+MUL_FIXED(113512,b); + offset[0].vy = y-b; + + offset[1].vx = -offset[0].vx; + offset[1].vy = y-b; + + offset[2].vx = a; + offset[2].vy = y; + + offset[3].vx = -a; + offset[3].vy = y; + + if (theta) + { + extern void RotateVertex(VECTOR2D *vertexPtr, int theta); + + RotateVertex(&offset[0],theta); + RotateVertex(&offset[1],theta); + RotateVertex(&offset[2],theta); + RotateVertex(&offset[3],theta); + } + + if (MIRROR_CHEATMODE) + { + offset[0].vx = -offset[0].vx; + offset[1].vx = -offset[1].vx; + offset[2].vx = -offset[2].vx; + offset[3].vx = -offset[3].vx; + } + VerticesBuffer[0].X = offset[0].vx+centreX; + VerticesBuffer[0].Y = MUL_FIXED(offset[0].vy,87381)+centreY; + + VerticesBuffer[1].X = offset[1].vx+centreX; + VerticesBuffer[1].Y = MUL_FIXED(offset[1].vy,87381)+centreY; + + VerticesBuffer[2].X = offset[2].vx+centreX; + VerticesBuffer[2].Y = MUL_FIXED(offset[2].vy,87381)+centreY; + + VerticesBuffer[3].X = offset[3].vx+centreX; + VerticesBuffer[3].Y = MUL_FIXED(offset[3].vy,87381)+centreY; + } + fakeHeader.PolyFlags = iflag_transparent; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_GLOWING; + + + { + int i; + for (i=0; i<4; i++) + { + VerticesBuffer[i].A = 128; + + VerticesBuffer[i].Z = z; + + VerticesBuffer[i].R = 255; + + if (drawInRed) + { + VerticesBuffer[i].G = 0; + VerticesBuffer[i].B = 0; + } + else + { + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 255; + } + + } + RenderPolygon.NumberOfVertices=4; + } + + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + + if (drawInRed) + { + VerticesBuffer[0].X = MUL_FIXED(offset[3].vx,scale*8)+centreX; + VerticesBuffer[0].Y = MUL_FIXED(MUL_FIXED(offset[3].vy,scale*8),87381)+centreY; + + VerticesBuffer[1].X = MUL_FIXED(offset[2].vx,scale*8)+centreX; + VerticesBuffer[1].Y = MUL_FIXED(MUL_FIXED(offset[2].vy,scale*8),87381)+centreY; + + VerticesBuffer[2].X = offset[2].vx+centreX; + VerticesBuffer[2].Y = MUL_FIXED(offset[2].vy,87381)+centreY; + + VerticesBuffer[3].X = offset[3].vx+centreX; + VerticesBuffer[3].Y = MUL_FIXED(offset[3].vy,87381)+centreY; + { + int i; + for (i=0; i<2; i++) + { + VerticesBuffer[i].A = 0; + VerticesBuffer[i].Z = z; + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 0; + VerticesBuffer[i].B = 0; + } + for (i=2; i<4; i++) + { + VerticesBuffer[i].A = 128; + VerticesBuffer[i].Z = z; + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 0; + VerticesBuffer[i].B = 0; + } + RenderPolygon.NumberOfVertices=4; + } + + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } +} +void RenderPredatorPlasmaCasterCharge(int value, VECTORCH *worldOffsetPtr, MATRIXCH *orientationPtr) +{ + POLYHEADER fakeHeader; + VECTORCH translatedPts[4]; + int halfWidth = 100; + int halfHeight = 4; + int z = -1; + translatedPts[0].vx = -halfWidth; + translatedPts[0].vy = z; + translatedPts[0].vz = -halfHeight-4; + + translatedPts[1].vx = -halfWidth+MUL_FIXED(value,2*halfWidth-10); + translatedPts[1].vy = z; + translatedPts[1].vz = -halfHeight-4; + + translatedPts[2].vx = -halfWidth+MUL_FIXED(value,2*halfWidth-10); + translatedPts[2].vy = z; + translatedPts[2].vz = halfHeight-4; + + translatedPts[3].vx = -halfWidth; + translatedPts[3].vy = z; + translatedPts[3].vz = halfHeight-4; + + fakeHeader.PolyFlags = iflag_transparent; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_GLOWING; + + + { + int i; + for (i=0; i<4; i++) + { + VerticesBuffer[i].A = 255; + + RotateVector(&(translatedPts[i]),orientationPtr); + translatedPts[i].vx += worldOffsetPtr->vx; + translatedPts[i].vy += worldOffsetPtr->vy; + translatedPts[i].vz += worldOffsetPtr->vz; + TranslatePointIntoViewspace(&translatedPts[i]); + + VerticesBuffer[i].X = translatedPts[i].vx; + VerticesBuffer[i].Y = translatedPts[i].vy; + VerticesBuffer[i].Z = translatedPts[i].vz; + + VerticesBuffer[i].R = 32; + VerticesBuffer[i].G = 0; + VerticesBuffer[i].B = 0; + } + RenderPolygon.NumberOfVertices=4; + } + { + int outcode = QuadWithinFrustrum(); + + if (outcode) + { + if (outcode!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,VerticesBuffer); + } + } +} + + + + + +int LightFlareAlpha = 65535; +void RenderLightFlare(VECTORCH *positionPtr, unsigned int colour) +{ + int centreX,centreY,sizeX,sizeY,z; + PARTICLE particle; +// VECTORCH point = {-20947,-8216,2244}; + VECTORCH point = *positionPtr; + + + #if 0 + if (IsThisObjectVisibleFromThisPosition(Player,&point,ONE_FIXED)) + { + LightFlareAlpha+=NormalFrameTime*8; + if (LightFlareAlpha > 65535) LightFlareAlpha = 65535; + textprint("FLARE VIS\n"); + } + else + { + LightFlareAlpha-=NormalFrameTime*8; + if (LightFlareAlpha < 0) LightFlareAlpha = 0; + textprint("FLARE INVIS\n"); + } + #endif + TranslatePointIntoViewspace(&point); + if(point.vz<64) return; + + #if 0 + { + int alpha = ONE_FIXED - point.vz*2; + if (alpha<0) return; + + alpha = MUL_FIXED(LightFlareAlpha,alpha)>>8; + + particle.ParticleID = PARTICLE_MUZZLEFLASH; + particle.Colour = 0xffffff+((alpha)<<24); + } + #else + particle.ParticleID = PARTICLE_LIGHTFLARE; +// particle.Colour = 0xffffff+((LightFlareAlpha>>8)<<24); + particle.Colour = colour; + #endif +// textprint("render fn %d %d %d\n",positionPtr->vx,positionPtr->vy,positionPtr->vz); +// PARTICLE_DESC *particleDescPtr = &ParticleDescription[particlePtr->ParticleID]; +// int particleSize = particlePtr->Size; + z=ONE_FIXED; + { + extern int SmartTargetSightX, SmartTargetSightY; + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + centreX = DIV_FIXED(point.vx,point.vz); + centreY = DIV_FIXED(point.vy,point.vz); + sizeX = (ScreenDescriptorBlock.SDB_Width<<13)/Global_VDB_Ptr->VDB_ProjX; + sizeY = MUL_FIXED(ScreenDescriptorBlock.SDB_Height<<13,87381)/Global_VDB_Ptr->VDB_ProjY; + } + + VerticesBuffer[0].X = centreX - sizeX; + VerticesBuffer[0].Y = centreY - sizeY; + VerticesBuffer[0].Z = z; + VerticesBuffer[1].X = centreX + sizeX; + VerticesBuffer[1].Y = centreY - sizeY; + VerticesBuffer[1].Z = z; + VerticesBuffer[2].X = centreX + sizeX; + VerticesBuffer[2].Y = centreY + sizeY; + VerticesBuffer[2].Z = z; + VerticesBuffer[3].X = centreX - sizeX; + VerticesBuffer[3].Y = centreY + sizeY; + VerticesBuffer[3].Z = z; + + { + int outcode = QuadWithinFrustrum(); + + if (outcode) + { + RenderPolygon.NumberOfVertices=4; + +// textprint("On Screen!\n"); + VerticesBuffer[0].U = 192<<16; + VerticesBuffer[0].V = 0; + + VerticesBuffer[1].U = 255<<16; + VerticesBuffer[1].V = 0; + + VerticesBuffer[2].U = 255<<16; + VerticesBuffer[2].V = 63<<16; + + VerticesBuffer[3].U = 192<<16; + VerticesBuffer[3].V = 63<<16; + + if (outcode!=2) + { + TexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_Particle_Output(&particle,RenderPolygon.Vertices); + + } + else D3D_Particle_Output(&particle,VerticesBuffer); + } + } +} + +#if VOLUMETRIC_FOG + +int FogValue(VECTORCH *vertexPtr) +{ + float a,b,c,d, lMax,lMin; + VECTORCHF v; + v.vx = vertexPtr->vx; + v.vy = vertexPtr->vy; + v.vz = vertexPtr->vz; + + a = (v.vx*v.vx + v.vy*v.vy + v.vz*v.vz)*2.0; + b = -2.0*(v.vx*FogPosition.vx+v.vy*FogPosition.vy+v.vz*FogPosition.vz); + { +// float s = MUL_FIXED(GetSin(CloakingPhase&4095),GetSin(CloakingPhase&4095)); + c = FogMagnitude - 10000.0*10000.0; + } + d = b*b-2.0*a*c; + if (d<0) return 0; + + d = sqrt(d); + + lMin = (-b-d)/(a); + if (lMin>1.0) return 0; + + lMax = (-b+d)/(a); + + if (lMax<0.0) + { + return 0; + } + else if (lMax>1.0) + { + if (lMin>0.0) + { + float m; + int f; + m = Approximate3dMagnitude(vertexPtr); + f2i(f,(lMax-lMin)*m); + return f; + } + else return Approximate3dMagnitude(vertexPtr); + } + else //(lMax<1.0) + { + if (lMin>0.0) + { + float m; + int f; + m = Approximate3dMagnitude(vertexPtr); + f2i(f,(lMax-lMin)*m); + return f; + } + else + { + float m; + int f; + m = Approximate3dMagnitude(vertexPtr); + f2i(f,(lMax)*m); + return f; + } + + } +} +#endif +#if 0 +int SphereGenerated=0; +void RenderSphere(void) +{ + if(!SphereGenerated) + { + Generate_Sphere(); + SphereGenerated=1; + } +// EvolveSphere(); + { + int f; + POLYHEADER fakeHeader; + MATRIXCH mat = (Global_VDB_Ptr->VDB_Mat); + VECTORCH *vSphere = SphereRotatedVertex; + VECTORCH *v2 = SphereAtmosRotatedVertex; + VECTORCH d; + { + fakeHeader.PolyFlags = 0; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_OFF; + } + { + MATRIXCH m2; + EULER e; + e.EulerX =0; + e.EulerY =(CloakingPhase/32)&4095; + e.EulerZ =0; + CreateEulerMatrix(&e,&m2); + TransposeMatrixCH(&m2); + MatrixMultiply(&mat,&m2,&mat); + d.vx = -3316 - Global_VDB_Ptr->VDB_World.vx; + d.vy = -50000 -Global_VDB_Ptr->VDB_World.vy; + d.vz = 26926 -Global_VDB_Ptr->VDB_World.vz; + + RotateVector(&d,&(Global_VDB_Ptr->VDB_Mat)); + + } + for (f=0; f0) radius += h; + *vSphere = SphereVertex[f]; + + RotateVector(vSphere,&mat); + v2->vx = MUL_FIXED(vSphere->vx,4096+300); + v2->vy = MUL_FIXED(vSphere->vy,4096+300); + v2->vz = MUL_FIXED(vSphere->vz,4096+300); + v2++; + vSphere->vx = MUL_FIXED(vSphere->vx,radius); + vSphere->vy = MUL_FIXED(vSphere->vy,radius); + vSphere->vz = MUL_FIXED(vSphere->vz,radius); + vSphere++; + } + #if 0 + for (f=0; fONE_FIXED) l = ONE_FIXED; + if (l<0) l = 0; + + v[i].vx += d.vx; + v[i].vy += d.vy; + v[i].vz += d.vz; + v[i].vy = MUL_FIXED(v[i].vy,87381); + + VerticesBuffer[i].X = v[i].vx; + VerticesBuffer[i].Y = v[i].vy; + VerticesBuffer[i].Z = v[i].vz; + + VerticesBuffer[i].A = 0; + if (h<=0) + { + VerticesBuffer[i].R = 0; + VerticesBuffer[i].G = 255+h; + VerticesBuffer[i].B = 255; + } + else if (h>128) + { + VerticesBuffer[i].R = MUL_FIXED(255,h*256); + VerticesBuffer[i].G = MUL_FIXED(200,h*256); + VerticesBuffer[i].B = MUL_FIXED(150,h*256); + } + else + { + VerticesBuffer[i].R = 0; + VerticesBuffer[i].G = 96-h/2; + VerticesBuffer[i].B = 0; + } + VerticesBuffer[i].R = MUL_FIXED(VerticesBuffer[i].R,l); + VerticesBuffer[i].G = MUL_FIXED(VerticesBuffer[i].G,l); + VerticesBuffer[i].B = MUL_FIXED(VerticesBuffer[i].B,l); + } + RenderPolygon.NumberOfVertices=3; + } + + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices>=3) + { + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + } + } + } + } + + } + #endif + { + extern int CloudyImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = CloudyImageNumber; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_OFF; + } + for (f=0; fONE_FIXED) l = ONE_FIXED; + if (l<0) l = 0; + + vertex[i].vx += d.vx; + vertex[i].vy += d.vy; + vertex[i].vz += d.vz; + vertex[i].vy = MUL_FIXED(vertex[i].vy,87381); + + VerticesBuffer[i].X = vertex[i].vx; + VerticesBuffer[i].Y = vertex[i].vy; + VerticesBuffer[i].Z = vertex[i].vz; + VerticesBuffer[i].U = SphereAtmosU[n];//+u[0]; + VerticesBuffer[i].V = SphereAtmosV[n];//+v[0]; + + VerticesBuffer[i].A = 255; + VerticesBuffer[i].R = l; + VerticesBuffer[i].G = l/2; + VerticesBuffer[i].B = 0; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + } + RenderPolygon.NumberOfVertices=3; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices>=3) + { + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + } + } + } + } + } + } + +} +void RenderBoom(void) +{ + VECTORCH d; + if(!SphereGenerated) + { + Generate_Sphere(); + SphereGenerated=1; + } + d.vx = 0; + d.vy = 0; + d.vz = 0; + + RenderBoomSphere(&d,4096); + +} +void RenderBoomSphere(VECTORCH *position, int radius) +{ + int Alpha[SPHERE_VERTICES]; + extern D3DTEXTUREHANDLE FMVTextureHandle[]; + + { + int f; + POLYHEADER fakeHeader; + VECTORCH *vSphere = SphereRotatedVertex; + static int o=0; + o++; + + { + extern int CloudyImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = CloudyImageNumber; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + for (f=0; fvx = MUL_FIXED(vSphere->vx,r); + vSphere->vy = MUL_FIXED(vSphere->vy,r); + vSphere->vz = MUL_FIXED(vSphere->vz,r); + + vSphere->vx += position->vx; + vSphere->vy += position->vy; + vSphere->vz += position->vz; + TranslatePointIntoViewspace(vSphere); + vSphere++; + + } + + for (f=0; f(128*3+64)*65536) + { + if (d1>0) i2=1; + else i1=1; + } + if (ad2>(128*3+64)*65536) + { + if (d2>0) i3=1; + else i1=1; + } + if (ad3>(128*3+64)*65536) + { + if (d3>0) i3=1; + else i2=1; + } + + if(i1) VerticesBuffer[0].U+=128*65536*4; + if(i2) VerticesBuffer[1].U+=128*65536*4; + if(i3) VerticesBuffer[2].U+=128*65536*4; + } + + VerticesBuffer[i].A = 128+Alpha[n]; + VerticesBuffer[i].R = 0; + VerticesBuffer[i].G = 128; + VerticesBuffer[i].B = 255; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + } + RenderPolygon.NumberOfVertices=3; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices>=3) + { + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); +// D3D_FMVParticle_Output(RenderPolygon.Vertices); + } + } + } + } + } + } + } + +} + + +#endif +int Alpha[SPHERE_VERTICES]; +void RenderExplosionSurface(VOLUMETRIC_EXPLOSION *explosionPtr) +{ + extern D3DTEXTUREHANDLE FMVTextureHandle[]; + int red,green,blue; + + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + red = 255; + green = 255; + blue = 255; + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + red = 0; + green = 255; + blue = 0; + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + red = 255; + green = 0; + blue = 255; + break; + } + } + { + int f; + POLYHEADER fakeHeader; + VECTORCH *vSphere = SphereRotatedVertex; + static int o=0; + o++; + + if (explosionPtr->ExplosionPhase) + { + extern int BurningImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = BurningImageNumber; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + else + { + extern int CloudyImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = CloudyImageNumber; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_INVCOLOUR; + red = explosionPtr->LifeTime/256; + green = explosionPtr->LifeTime/256; + blue = explosionPtr->LifeTime/256; + } + + for (f=0; fPosition[f]; + + TranslatePointIntoViewspace(vSphere); + vSphere++; + } + + for (f=0; fLifeTime)*128*2; +// SphereAtmosU[0]=MUL_FIXED(SphereAtmosU[0],u); +// SphereAtmosV[0]=MUL_FIXED(SphereAtmosV[0],u); + VerticesBuffer[i].U = (SphereAtmosU[n]);//+u[0]; + VerticesBuffer[i].V = (SphereAtmosV[n]+u);//+v[0]; + } + { + int d1 = VerticesBuffer[0].U-VerticesBuffer[1].U; + int d2 = VerticesBuffer[0].U-VerticesBuffer[2].U; + int d3 = VerticesBuffer[1].U-VerticesBuffer[2].U; + + int ad1=d1,ad2=d2,ad3=d3; + int i1=0,i2=0,i3=0; + + if (ad1<0) ad1=-ad1; + if (ad2<0) ad2=-ad2; + if (ad3<0) ad3=-ad3; + + if (ad1>(128*(SPHERE_TEXTURE_WRAP-1)+64)*65536) + { + if (d1>0) i2=1; + else i1=1; + } + if (ad2>(128*(SPHERE_TEXTURE_WRAP-1)+64)*65536) + { + if (d2>0) i3=1; + else i1=1; + } + if (ad3>(128*(SPHERE_TEXTURE_WRAP-1)+64)*65536) + { + if (d3>0) i3=1; + else i2=1; + } + + if(i1) VerticesBuffer[0].U+=128*65536*SPHERE_TEXTURE_WRAP; + if(i2) VerticesBuffer[1].U+=128*65536*SPHERE_TEXTURE_WRAP; + if(i3) VerticesBuffer[2].U+=128*65536*SPHERE_TEXTURE_WRAP; + } + + VerticesBuffer[i].A = explosionPtr->LifeTime/256; + VerticesBuffer[i].R = red; + VerticesBuffer[i].G = green; + VerticesBuffer[i].B = blue; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + + } + RenderPolygon.NumberOfVertices=3; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices>=3) + { + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); +// D3D_FMVParticle_Output(RenderPolygon.Vertices); + } + } + } + } + } + } + } +} +void RenderInsideAlienTongue(int offset) +{ + #define TONGUE_SCALE 1024 + int TonguePolyVertexList[4][4] = + { + {0,3,7,4}, //+ve y + {1,2,3,0}, //+ve x + {5,6,7,4}, //-ve x + {1,2,6,5}, //-ve y + }; + VECTORCH vertices[8]= + { + {+TONGUE_SCALE,-TONGUE_SCALE,0}, + {+TONGUE_SCALE,+TONGUE_SCALE,0}, + {+TONGUE_SCALE,+TONGUE_SCALE,+TONGUE_SCALE*4}, + {+TONGUE_SCALE,-TONGUE_SCALE,+TONGUE_SCALE*4}, + + {-TONGUE_SCALE,-TONGUE_SCALE,0}, + {-TONGUE_SCALE,+TONGUE_SCALE,0}, + {-TONGUE_SCALE,+TONGUE_SCALE,+TONGUE_SCALE*4}, + {-TONGUE_SCALE,-TONGUE_SCALE,+TONGUE_SCALE*4}, + }; + VECTORCH translatedPts[8]; + + POLYHEADER fakeHeader; + int polyNumber; + + #if 1 + { + + int i = 7; + do + { + translatedPts[i] = vertices[i]; + translatedPts[i].vz -= (ONE_FIXED-offset)/16; +// TranslatePointIntoViewspace(&translatedPts[i]); + } + while(i--); + } + #endif + { + extern int AlienTongueImageNumber; + fakeHeader.PolyFlags = 0; + fakeHeader.PolyColour = AlienTongueImageNumber; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_GLOWING; + } + + for(polyNumber=0; polyNumber<4; polyNumber++) + { + { + int i; + for (i=0; i<4; i++) + { + int v = TonguePolyVertexList[polyNumber][i]; + VerticesBuffer[i].A = 255; + VerticesBuffer[i].X = translatedPts[v].vx; + VerticesBuffer[i].Y = translatedPts[v].vy; + VerticesBuffer[i].Z = translatedPts[v].vz; + VerticesBuffer[i].U = CuboidPolyVertexU[3][i]<<16; + VerticesBuffer[i].V = CuboidPolyVertexV[3][i]<<16; + + + VerticesBuffer[i].R = offset/2048; + VerticesBuffer[i].G = offset/2048; + VerticesBuffer[i].B = offset/2048; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + + } + RenderPolygon.NumberOfVertices=4; + } + { + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + + } + } +} + + + +#define NO_OF_STARS 500 +typedef struct +{ + VECTORCH Position; + int Colour; + int Frequency; + int Phase; + +} STARDESC; +static STARDESC StarArray[NO_OF_STARS]; + +void CreateStarArray(void) +{ + int i; + + SetSeededFastRandom(FastRandom()); + for (i=0; iVDB_World.vx; + position.vy += Global_VDB_Ptr->VDB_World.vy; + position.vz += Global_VDB_Ptr->VDB_World.vz; + + TranslatePointIntoViewspace(&position); + #endif +// RotateVector(&position,&(Global_VDB_Ptr->VDB_Mat)); + + + VerticesBuffer[0].X = position.vx - sizeX; + VerticesBuffer[0].Y = position.vy - sizeY; + VerticesBuffer[0].Z = position.vz; + VerticesBuffer[1].X = position.vx + sizeX; + VerticesBuffer[1].Y = position.vy - sizeY; + VerticesBuffer[1].Z = position.vz; + VerticesBuffer[2].X = position.vx + sizeX; + VerticesBuffer[2].Y = position.vy + sizeY; + VerticesBuffer[2].Z = position.vz; + VerticesBuffer[3].X = position.vx - sizeX; + VerticesBuffer[3].Y = position.vy + sizeY; + VerticesBuffer[3].Z = position.vz; + + { + int outcode = QuadWithinFrustrum(); + + if (outcode) + { + RenderPolygon.NumberOfVertices=4; + + // textprint("On Screen!\n"); + VerticesBuffer[0].U = 192<<16; + VerticesBuffer[0].V = 0; + + VerticesBuffer[1].U = 255<<16; + VerticesBuffer[1].V = 0; + + VerticesBuffer[2].U = 255<<16; + VerticesBuffer[2].V = 63<<16; + + VerticesBuffer[3].U = 192<<16; + VerticesBuffer[3].V = 63<<16; + + if (outcode!=2) + { + TexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_Particle_Output(&particle,RenderPolygon.Vertices); + + } + else D3D_Particle_Output(&particle,VerticesBuffer); + } + } + } +} + + + + + + +#if 0 +/* KJL 17:07:52 07/11/98 - experiment! */ +extern unsigned char DebouncedKeyboardInput[]; +#include "dungeon\angband.h" +char array[MAX_WID+1][MAX_HGT+1]; +extern cave_type cave[MAX_HGT][MAX_WID]; +void RenderDungeon(void) +{ + int x,y; + int maxX=MAX_WID-1,maxY=MAX_HGT-1; + static int notMade=1; + + if (notMade || DebouncedKeyboardInput[KEY_G]) + { + for (x=0; x<=maxX; x++) + for (y=0; y<=maxY; y++) + { + cave[y][x].feat = FEAT_WALL_OUTER; + } + generate_cave(); + for (x=0; x<=maxX; x++) + for (y=0; y<=maxY; y++) + { + array[x][y] = 1; + if (cave[y][x].feat == FEAT_FLOOR) + array[x][y] = 0; + } + notMade = 0; + } + for (x=0; x<=maxX; x++) + for (y=0; y<=maxY; y++) + { + if (!array[x][y]) + { + + if (x>0) + { + if (array[x-1][y]) RenderWallY(x,y); + } + else + { + RenderWallY(0,y); + } + if (x0) + { + if (array[x][y-1]) RenderWallX(x,y); + } + else + { + RenderWallX(x,0); + } + if (yPolyPtr = outputPolyPtr; + + { + int maxZ = smallint; + int minZ = bigint; + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + int z = vertices->Z; + + if(z > maxZ) maxZ = z; + if(z < minZ) minZ = z; + vertices++; + } + while(--i); + + if (inputPolyPtr->PolyFlags & iflag_sortnearz) currentItemPtr->SortKey = minZ; + else if (inputPolyPtr->PolyFlags & iflag_sortfarz) currentItemPtr->SortKey = maxZ +10; + else currentItemPtr->SortKey = maxZ; + } + + ItemCount++; + + /* Write out the Item Header */ + outputPolyPtr->PolyItemType = I_ZB_2dTexturedPolygon; + outputPolyPtr->PolyNormalIndex = inputPolyPtr->PolyNormalIndex; + outputPolyPtr->PolyFlags = inputPolyPtr->PolyFlags; + if(Global_ShapeNormals) + outputPolyPtr->PolyColour = OldLightingModelForFlatShading((int *)inputPolyPtr); + else + outputPolyPtr->PolyColour = 0; + + /* Write out the Item Points Array */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + itemDataPtr = &outputPolyPtr->Poly1stPt; + + do + { + *itemDataPtr++ = ProjectedAndClampedX(vertices); + *itemDataPtr++ = ProjectedAndClampedY(vertices); + *itemDataPtr++ = vertices->U; + *itemDataPtr++ = vertices->V; + { + float *fDataPtr = (float*)itemDataPtr; + *fDataPtr = 1.0/((float)(vertices->Z)); + itemDataPtr++; + } + vertices++; + } + while(--i); + } + /* Write out the Item Terminator */ + *itemDataPtr = Term; + } +} +/* TEXTURED POLYGONS */ +static void TexturedPolygon_Construct(POLYHEADER *polyPtr) +{ + int *texture_defn_ptr; + RENDERVERTEX *renderVerticesPtr = VerticesBuffer; + int i = RenderPolygon.NumberOfVertices; + + + /* get ptr to uv coords for this polygon */ + { + int texture_defn_index = (polyPtr->PolyColour >> TxDefn); + texture_defn_ptr = Global_ShapeTextures[texture_defn_index]; + } + + VertexNumberPtr = &polyPtr->Poly1stPt; + + /* If this texture is animated the UV array must be calculated */ + if(polyPtr->PolyFlags & iflag_txanim) + { + /* Create the UV array */ + int uv_array[maxpolypts * 2]; + CreateTxAnimUVArray(texture_defn_ptr, uv_array, (int*)polyPtr); + texture_defn_ptr = uv_array; + + do + { + renderVerticesPtr->X = RotatedPts[*VertexNumberPtr].vx; + renderVerticesPtr->Y = RotatedPts[*VertexNumberPtr].vy; + renderVerticesPtr->Z = RotatedPts[*VertexNumberPtr].vz; + + renderVerticesPtr->U = texture_defn_ptr[0]; + renderVerticesPtr->V = texture_defn_ptr[1]; + + renderVerticesPtr++; + VertexNumberPtr++; + + texture_defn_ptr += 2; + } + while(--i); + } + else + { + do + { + renderVerticesPtr->X = RotatedPts[*VertexNumberPtr].vx; + renderVerticesPtr->Y = RotatedPts[*VertexNumberPtr].vy; + renderVerticesPtr->Z = RotatedPts[*VertexNumberPtr].vz; + + renderVerticesPtr->U = texture_defn_ptr[0] << 16; + renderVerticesPtr->V = texture_defn_ptr[1] << 16; + + renderVerticesPtr++; + VertexNumberPtr++; + + texture_defn_ptr += 2; + } + while(--i); + } + +} +static void TexturedPolygon_Output(POLYHEADER *inputPolyPtr, RENDERVERTEX *renderVerticesPtr) +{ + int *itemDataPtr; + + itemDataPtr = AllocateItemData(IHdrSize + RenderPolygon.NumberOfVertices*4 + ITrmSize); + + if(itemDataPtr) + { + POLYHEADER *outputPolyPtr = (POLYHEADER*) itemDataPtr; + struct KItem * const currentItemPtr = &KItemList[ItemCount]; + + currentItemPtr->PolyPtr = outputPolyPtr; + + { + int maxZ = smallint; + int minZ = bigint; + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + int z = vertices->Z; + + if(z > maxZ) maxZ = z; + if(z < minZ) minZ = z; + vertices++; + } + while(--i); + + if (inputPolyPtr->PolyFlags & iflag_sortnearz) currentItemPtr->SortKey = minZ; + else if (inputPolyPtr->PolyFlags & iflag_sortfarz) currentItemPtr->SortKey = maxZ +10; + else currentItemPtr->SortKey = maxZ; + } + + ItemCount++; + + /* Write out the Item Header */ + outputPolyPtr->PolyItemType = I_2dTexturedPolygon; + outputPolyPtr->PolyNormalIndex = inputPolyPtr->PolyNormalIndex; + outputPolyPtr->PolyFlags = inputPolyPtr->PolyFlags; + if(Global_ShapeNormals) + outputPolyPtr->PolyColour = OldLightingModelForFlatShading((int *)inputPolyPtr); + else + outputPolyPtr->PolyColour = 0; + + /* Write out the Item Points Array */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + itemDataPtr = &outputPolyPtr->Poly1stPt; + + do + { + *itemDataPtr++ = ProjectedAndClampedX(vertices); + *itemDataPtr++ = ProjectedAndClampedY(vertices); + *itemDataPtr++ = vertices->U; + *itemDataPtr++ = vertices->V; + vertices++; + } + while(--i); + } + /* Write out the Item Terminator */ + *itemDataPtr = Term; + } +} +static void ZBufferedGouraudTexturedPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr) +{ + POLYHEADER *outputPolyPtr; + int *itemDataPtr; + + struct KItem * const currentItemPtr = &KItemList[ItemCount]; + + { + int maxZ = smallint; + int minZ = bigint; + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + int z = vertices->Z; + + if(z > maxZ) maxZ = z; + if(z < minZ) minZ = z; + vertices++; + } + while(--i); + + if (inputPolyPtr->PolyFlags & iflag_sortnearz) currentItemPtr->SortKey = minZ; + else if (inputPolyPtr->PolyFlags & iflag_sortfarz) currentItemPtr->SortKey = maxZ +10; + else currentItemPtr->SortKey = maxZ; + } + + /* draw in 3d */ + { + itemDataPtr = AllocateItemData(IHdrSize + RenderPolygon.NumberOfVertices*6 + ITrmSize); + outputPolyPtr = (POLYHEADER*) itemDataPtr; + + /* Write out the Item Header */ + outputPolyPtr->PolyItemType = I_ZB_Gouraud3dTexturedPolygon; + + /* Write out the Item Points Array */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + itemDataPtr = &outputPolyPtr->Poly1stPt; + + do + #if 1 + { + float oneOverZ; + oneOverZ = (1.0)/vertices->Z; + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + *itemDataPtr++=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + *itemDataPtr++=y; + } + { + float *fDataPtr = (float*)itemDataPtr; + + *fDataPtr++ = (float)(vertices->U>>16); + *fDataPtr++ = (float)(vertices->V>>16); + *fDataPtr++ = oneOverZ; + itemDataPtr = (int*)fDataPtr; + } + *itemDataPtr++ = vertices->I; + vertices++; + } + #else + { + *itemDataPtr++ = ProjectedAndClampedX(vertices); + *itemDataPtr++ = ProjectedAndClampedY(vertices); + { + float uf,vf,zf; + float *fDataPtr = (float*)itemDataPtr; + + zf = (vertices->Z); + + uf = vertices->U>>16; + *fDataPtr++ = uf; + + vf = vertices->V>>16; + *fDataPtr++ = vf; + zf = 1.0/zf; + *fDataPtr++ = zf; + itemDataPtr = (int*)fDataPtr; + } + *itemDataPtr++ = vertices->I; + vertices++; + } + #endif + while(--i); + } + } + + /* Write out the Item Terminator */ + *itemDataPtr = Term; + + currentItemPtr->PolyPtr = outputPolyPtr; + + outputPolyPtr->PolyNormalIndex = inputPolyPtr->PolyNormalIndex; + outputPolyPtr->PolyFlags = inputPolyPtr->PolyFlags; + outputPolyPtr->PolyColour = inputPolyPtr->PolyColour; + + ItemCount++; +} +static void GouraudPolygon_Output(POLYHEADER *inputPolyPtr, RENDERVERTEX *renderVerticesPtr) +{ + int *itemDataPtr; + + itemDataPtr = AllocateItemData(IHdrSize + RenderPolygon.NumberOfVertices*3 + ITrmSize); + + if(itemDataPtr) + { + POLYHEADER *outputPolyPtr = (POLYHEADER*) itemDataPtr; + struct KItem * const currentItemPtr = &KItemList[ItemCount]; + + currentItemPtr->PolyPtr = outputPolyPtr; + + { + + int maxZ = smallint; + int minZ = bigint; + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + int z = vertices->Z; + + if(z > maxZ) maxZ = z; + if(z < minZ) minZ = z; + vertices++; + } + while(--i); + + if (inputPolyPtr->PolyFlags & iflag_sortnearz) currentItemPtr->SortKey = minZ; + else if (inputPolyPtr->PolyFlags & iflag_sortfarz) currentItemPtr->SortKey = maxZ +10; + else currentItemPtr->SortKey = maxZ; + } + + ItemCount++; + + /* Write out the Item Header */ + outputPolyPtr->PolyItemType = I_GouraudPolygon; + outputPolyPtr->PolyNormalIndex = inputPolyPtr->PolyNormalIndex; + outputPolyPtr->PolyFlags = inputPolyPtr->PolyFlags; + + #if 1//debug + if (inputPolyPtr->PolyItemType != I_GouraudPolygon) + { + int c = GetSin((inputPolyPtr->PolyColour>>5)&4095); + if (c<0) c=-c; + + inputPolyPtr->PolyColour+=NormalFrameTime; + + if (VideoModeType==VideoModeType_8) c<<=6; + + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + vertices->I = c; + vertices++; + } + while(--i); + } + + outputPolyPtr->PolyColour = 0xff; + } + else + #endif + outputPolyPtr->PolyColour = inputPolyPtr->PolyColour; + + /* Write out the Item Points Array */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + itemDataPtr = &outputPolyPtr->Poly1stPt; + + do + { + *itemDataPtr++ = ProjectedAndClampedX(vertices); + *itemDataPtr++ = ProjectedAndClampedY(vertices); + *itemDataPtr++ = vertices->I; + vertices++; + } + while(--i); + } + /* Write out the Item Terminator */ + *itemDataPtr = Term; + } +} +static void CloakedTexturedPolygon_Construct(POLYHEADER *polyPtr) +{ + int cloakedU[] = { 248-8,256-8,256-8,248-8 }; + int cloakedV[] = { 1,1,8,8 }; + + int *texture_defn_ptr; + RENDERVERTEX *renderVerticesPtr = VerticesBuffer; + int i = RenderPolygon.NumberOfVertices; + + + /* get ptr to uv coords for this polygon */ + { + int texture_defn_index = (polyPtr->PolyColour >> TxDefn); + texture_defn_ptr = Global_ShapeTextures[texture_defn_index]; + } + + VertexNumberPtr = &polyPtr->Poly1stPt; + + while(i--) + { + renderVerticesPtr->X = RotatedPts[*VertexNumberPtr].vx; + renderVerticesPtr->Y = RotatedPts[*VertexNumberPtr].vy; + renderVerticesPtr->Z = RotatedPts[*VertexNumberPtr].vz; + + renderVerticesPtr->U = cloakedU[i]; + renderVerticesPtr->V = cloakedV[i]; + + renderVerticesPtr++; + VertexNumberPtr++; + } +} + void GouraudTexturedPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr) +{ + POLYHEADER *outputPolyPtr; + int *itemDataPtr; + int drawIn2D; + + struct KItem * const currentItemPtr = &KItemList[ItemCount]; + + { + int maxZ = smallint; + int minZ = bigint; + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + int z = vertices->Z; + + if(z > maxZ) maxZ = z; + if(z < minZ) minZ = z; + vertices++; + } + while(--i); + + if (inputPolyPtr->PolyFlags & iflag_sortnearz) currentItemPtr->SortKey = minZ; + else if (inputPolyPtr->PolyFlags & iflag_sortfarz) currentItemPtr->SortKey = maxZ +10; + else currentItemPtr->SortKey = maxZ; + + drawIn2D = (maxZ*4 < minZ*5); + } + + #if !Saturn + /* KJL 15:49:56 07/04/97 - draw all in 3D will become an option */ + if ((ScanDrawMode == ScanDrawDirectDraw) && (drawIn2D)) + #endif + { + itemDataPtr = AllocateItemData(IHdrSize + RenderPolygon.NumberOfVertices*5 + ITrmSize); + outputPolyPtr = (POLYHEADER*) itemDataPtr; + + /* Write out the Item Header */ + outputPolyPtr->PolyItemType = I_Gouraud2dTexturedPolygon; + + /* Write out the Item Points Array */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + itemDataPtr = &outputPolyPtr->Poly1stPt; + + do + { + #if 1 + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + *itemDataPtr++=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + *itemDataPtr++=y; + } + #endif + #if Saturn + *itemDataPtr++ = vertices->R; + *itemDataPtr++ = vertices->G; + *itemDataPtr++ = vertices->B; + #else + *itemDataPtr++ = vertices->U; + *itemDataPtr++ = vertices->V; + *itemDataPtr++ = vertices->I; + #endif + vertices++; + } + while(--i); + } + } + #if !Saturn + else /* draw in 3d */ + { + itemDataPtr = AllocateItemData(IHdrSize + RenderPolygon.NumberOfVertices*6 + ITrmSize); + outputPolyPtr = (POLYHEADER*) itemDataPtr; + + /* Write out the Item Header */ + outputPolyPtr->PolyItemType = I_Gouraud3dTexturedPolygon; + + /* Write out the Item Points Array */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + itemDataPtr = &outputPolyPtr->Poly1stPt; + + do + { + float oneOverZ,uf,vf; + uf = vertices->U>>16; + vf = vertices->V>>16; + + oneOverZ = (1.0)/vertices->Z; + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + *itemDataPtr++=x; + } + uf = uf*oneOverZ; + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + *itemDataPtr++=y; + } + vf = vf*oneOverZ; + { + float *fDataPtr = (float*)itemDataPtr; + + *fDataPtr++ = uf; + *fDataPtr++ = vf; + *fDataPtr++ = oneOverZ; + itemDataPtr = (int*)fDataPtr; + } + *itemDataPtr++ = vertices->I; + vertices++; + } + while(--i); + } + } + #endif + /* Write out the Item Terminator */ + *itemDataPtr = Term; + + currentItemPtr->PolyPtr = outputPolyPtr; + + outputPolyPtr->PolyNormalIndex = inputPolyPtr->PolyNormalIndex; + outputPolyPtr->PolyFlags = inputPolyPtr->PolyFlags; + outputPolyPtr->PolyColour = inputPolyPtr->PolyColour; + + ItemCount++; +} + +#endif \ No newline at end of file diff --git a/3dc/Kshape.c b/3dc/Kshape.c new file mode 100644 index 0000000..6f6ef94 --- /dev/null +++ b/3dc/Kshape.c @@ -0,0 +1,8501 @@ +/*KJL************************************************************************************ +* kshape.c - replacement for all the pipeline stuff previously done in shape.c & clip.c * +************************************************************************************KJL*/ +#include "3dc.h" +#include +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" + +#include "kshape.h" +#include "kzsort.h" +#include "frustrum.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "equipmnt.h" +#include "bh_pred.h" +#include "bh_marin.h" +#include "bh_corpse.h" +#include "bh_debri.h" +#include "bh_weap.h" +#include "bh_types.h" +#include "pldghost.h" +#include "particle.h" +#include "vision.h" +#include "sfx.h" +#include "d3d_render.h" +#include "avpview.h" +#include "sphere.h" +#include "detaillevels.h" +#include "avp_userprofile.h" + +#if SOFTWARE_RENDERER +#define D3D_ZBufferedGouraudTexturedPolygon_Output Software_ZBufferedGouraudTexturedPolygon_Output +#endif +#define ALIENS_LIFEFORCE_GLOW_COLOUR 0x20ff8080 +#define MARINES_LIFEFORCE_GLOW_COLOUR 0x208080ff +#define PREDATORS_LIFEFORCE_GLOW_COLOUR 0x2080ff80 + +/* KJL 15:02:50 05/14/97 - new max lighting intensity */ +#define MAX_INTENSITY (65536*4-1) + +extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; +extern DISPLAYBLOCK *Global_ODB_Ptr; +extern EXTRAITEMDATA *Global_EID_Ptr; +extern int *Global_EID_IPtr; +extern int ScanDrawMode; +extern int ZBufferMode; +extern int NormalFrameTime; + +extern SHAPEHEADER *Global_ShapeHeaderPtr; +extern int *Global_ShapePoints; +extern int **Global_ShapeItems; +extern int *Global_ShapeNormals; +extern int *Global_ShapeVNormals; +extern int **Global_ShapeTextures; + +extern MATRIXCH LToVMat; +extern EULER LToVMat_Euler; +extern MATRIXCH WToLMat; +extern VECTORCH LocalView; +extern VECTORCH LocalLightCH; + +extern int NumLightSourcesForObject; +extern LIGHTBLOCK *LightSourcesForObject[]; + +#if SupportMorphing +extern MORPHDISPLAY MorphDisplay; +#endif + +extern int VideoModeType; +extern int GlobalAmbience; +extern int NumActiveBlocks; + +extern DISPLAYBLOCK *ActiveBlockList[]; +extern SHAPEHEADER **mainshapelist; + +int MirroringActive=0; +int MirroringAxis=-149*2; + +VECTORCHF FogPosition; +float FogMagnitude; +#define VOLUMETRIC_FOG 0 +#define UNDERWATER 0 +#define SPATIAL_SHOCKWAVE 0 +float CameraZoomScale; + +int DrawFullBright; + +int TripTasticPhase; + +void SetupShapePipeline(void); +void ShapePipeline(SHAPEHEADER *shapePtr); + +static void GouraudPolygon_Construct(POLYHEADER *polyPtr); +static void GouraudPolygon_Output(POLYHEADER *inputPolyPtr, RENDERVERTEX *renderVerticesPtr); + +static void TexturedPolygon_Construct(POLYHEADER *polyPtr); +static void TexturedPolygon_Output(POLYHEADER *inputPolyPtr, RENDERVERTEX *renderVerticesPtr); + + +static void GouraudTexturedPolygon_Construct(POLYHEADER *polyPtr); + +static void (*VertexIntensity)(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_Hierarchical(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_PreLit(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_Pred_Thermal(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_Pred_SeeAliens(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_Pred_SeePredatorTech(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_ImageIntensifier(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_Standard(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_Alien_Sense(RENDERVERTEX *renderVertexPtr); + +static void VertexIntensity_Standard_Opt(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_FullBright(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_DiscoInferno(RENDERVERTEX *renderVertexPtr); +static void VertexIntensity_Underwater(RENDERVERTEX *renderVertexPtr); + + +extern void CreateTxAnimUVArray(int *txa_data, int *uv_array, int *shapeitemptr); + +void PredatorThermalVision_ShapePipeline(SHAPEHEADER *shapePtr); +void PredatorSeeAliensVision_ShapePipeline(SHAPEHEADER *shapePtr); +static void CloakedPolygon_Construct(POLYHEADER *polyPtr); +static void PredatorThermalVisionPolygon_Construct(POLYHEADER *polyPtr); +static void PredatorSeeAliensVisionPolygon_Construct(POLYHEADER *polyPtr); +void DoAlienEnergyView(DISPLAYBLOCK *dispPtr); +static void FindAlienEnergySource_Recursion(HMODELCONTROLLER *controllerPtr, SECTION_DATA *sectionDataPtr, unsigned int colour); +void SquishPoints(SHAPEINSTR *shapeinstrptr); +void MorphPoints(SHAPEINSTR *shapeinstrptr); +void TranslateShapeVertices(SHAPEINSTR *shapeinstrptr); +static void ParticlePolygon_Construct(PARTICLE *particlePtr); +void RenderMirroredDecal(DECAL *decalPtr); +static void DecalPolygon_Construct(DECAL *decalPtr); +void RenderShaftOfLight2(MODULE *modulePtr); +void FindIntersectionWithYPlane(VECTORCH *startPtr, VECTORCH *directionPtr, VECTORCH *intersectionPtr); +void FindZFromXYIntersection(VECTORCH *startPtr, VECTORCH *directionPtr, VECTORCH *intersectionPtr); +void AddToTranslucentPolyList(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr); +void DrawWaterFallPoly(VECTORCH *v); + +#if platform_pc +extern int sine[]; +extern int cosine[]; +#endif + + +//extern int ItemCount; + + +/*KJL************************************************************************************ +* N.B. All the following global variables have their first elements initialised so that * +* they will end up in high memory on the Saturn. * +************************************************************************************KJL*/ + +VECTORCH Global_LightVector={1,}; + +/* + Global variables and arrays +*/ + +VECTORCH RotatedPts[maxrotpts]={1,}; +int ItemColour=1; + + + +#if SupportMorphing + +#if (LazyEvaluationForMorphing == No) +VECTORCH MorphedPts[maxmorphPts]; +#endif + + +#endif /* SupportMorphing */ + + +#if Saturn +extern int PolygonSubdivideEntry(POLYHEADER* itemptr); +#endif + +static COLOURINTENSITIES ColourIntensityArray[maxrotpts]; + + + +RENDERPOLYGON RenderPolygon={1,}; +RENDERVERTEX VerticesBuffer[9]={1,}; +static RENDERVERTEX TriangleVerticesBuffer[3]={1,}; + +static int *VertexNumberPtr=(int*)1; + +extern struct KItem KItemList[maxpolyptrs]; +extern int *MorphedObjectPointsPtr; + +#define MAX_NO_OF_TRANSLUCENT_POLYGONS 1000 +RENDERPOLYGON TranslucentPolygons[MAX_NO_OF_TRANSLUCENT_POLYGONS]; +POLYHEADER TranslucentPolygonHeaders[MAX_NO_OF_TRANSLUCENT_POLYGONS]; +int CurrentNumberOfTranslucentPolygons; + +/* KJL 10:25:44 7/23/97 - this offset is used to push back the normal game gfx, +so that the HUD can be drawn over the top without sinking into walls, etc. */ +int HeadUpDisplayZOffset=0; + +extern int CloakingPhase; +static VECTORCH ObjectCentre; +static int HierarchicalObjectsLowestYValue; + +HEATSOURCE HeatSourceList[MAX_NUMBER_OF_HEAT_SOURCES]; +int NumberOfHeatSources; +int CloakingMode; +char CloakedPredatorIsMoving; +static VECTORCH LocalCameraZAxis; + +static int ObjectCounter; + +extern void InitialiseLightIntensityStamps(void) +{ + int i = maxrotpts; + do + { + i--; + ColourIntensityArray[i].Stamp=0; + } + while(i); + ObjectCounter = 0; + +} + + +void SetupShapePipeline(void) +{ + #if VOLUMETRIC_FOG + { +// VECTORCH v = {-30399, -1792, 1050}; // genshd1 +// VECTORCH v = {49937,-4000,-37709}; // hangar +// VECTORCH v = {-185,0,642}; +// VECTORCH v = {6894,469,-13203}; + VECTORCH v = {73608,3582,56211}; + TranslatePointIntoViewspace(&v); + FogPosition.vx = v.vx; + FogPosition.vy = v.vy; + FogPosition.vz = v.vz; + FogMagnitude = FogPosition.vx*FogPosition.vx+FogPosition.vy*FogPosition.vy+FogPosition.vz*FogPosition.vz; + } + #endif + + /* Set up these global pointers */ + Global_ShapePoints = *(Global_ShapeHeaderPtr->points); + Global_ShapeTextures = Global_ShapeHeaderPtr->sh_textures; + + if(Global_ODB_Ptr->ObEIDPtr) + { + Global_EID_Ptr = Global_ODB_Ptr->ObEIDPtr; + Global_EID_IPtr = (int *) Global_ODB_Ptr->ObEIDPtr; + } + else + { + Global_EID_Ptr = Global_ShapeHeaderPtr->sh_extraitemdata; + Global_EID_IPtr = (int *) Global_ShapeHeaderPtr->sh_extraitemdata; + } + + if(Global_ShapeHeaderPtr->sh_normals) + { + Global_ShapeNormals = *(Global_ShapeHeaderPtr->sh_normals); + } + else + { + Global_ShapeNormals = 0; + } + + if(Global_ShapeHeaderPtr->sh_vnormals) + { + Global_ShapeVNormals = *(Global_ShapeHeaderPtr->sh_vnormals); + } + else + { + Global_ShapeVNormals = 0; + } + + + // if((Global_ODB_Ptr->ObStrategyBlock)&&(Global_ODB_Ptr->ObStrategyBlock->I_SBtype == I_BehaviourQueenAlien)) +// Global_ODB_Ptr->ObFlags3 &= ObFlag3_NoLightDot; + + ObjectCounter++; + +} + +void ChooseLightingModel(DISPLAYBLOCK *dispPtr) +{ + LOCALASSERT(dispPtr); + LOCALASSERT(dispPtr->ObShapeData); + + if (DrawFullBright) + { + VertexIntensity = VertexIntensity_FullBright; + } + else if (DISCOINFERNO_CHEATMODE || TRIPTASTIC_CHEATMODE) + { + VertexIntensity = VertexIntensity_DiscoInferno; + } + else if (UNDERWATER_CHEATMODE) + { + VertexIntensity = VertexIntensity_Underwater; + } + else + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + VertexIntensity = VertexIntensity_Standard_Opt; + break; + } + case VISION_MODE_ALIEN_SENSE: + { + VertexIntensity = VertexIntensity_Alien_Sense; + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + VertexIntensity = VertexIntensity_ImageIntensifier; + break; + } + case VISION_MODE_PRED_THERMAL: + { + VertexIntensity = VertexIntensity_Pred_Thermal; + break; + } + case VISION_MODE_PRED_SEEALIENS: + { + VertexIntensity = VertexIntensity_Pred_SeeAliens; + break; + } + case VISION_MODE_PRED_SEEPREDTECH: + { + VertexIntensity = VertexIntensity_Pred_SeePredatorTech; + break; + } + } + } +} + + + +/*KJL********************************************************************************** +* ShapePipeline() - this function processes a shape for rendering by considering each * +* polygon (item) in turn. * +**********************************************************************************KJL*/ +void ShapePipeline(SHAPEHEADER *shapePtr) +{ + int numitems= shapePtr->numitems; + int **itemArrayPtr = shapePtr->items; + #if 0 + char objectCompletelyInView; + #endif + LOCALASSERT(numitems); + + switch(CurrentVisionMode) + { + case VISION_MODE_PRED_THERMAL: + { + /* if we have an object with heat sources, draw it as such */ + if (NumberOfHeatSources)//||((Global_ODB_Ptr->ObStrategyBlock)&&(Global_ODB_Ptr->ObStrategyBlock->I_SBtype == I_BehaviourAlien))) + { + PredatorThermalVision_ShapePipeline(shapePtr); + return; + } + break; + } + case VISION_MODE_PRED_SEEALIENS: + { + STRATEGYBLOCK *sbPtr = Global_ODB_Ptr->ObStrategyBlock; + if(sbPtr) + { + int useVision=0; + switch (sbPtr->I_SBtype) + { + case I_BehaviourAutoGun: + case I_BehaviourAlien: + case I_BehaviourQueenAlien: + case I_BehaviourFaceHugger: + case I_BehaviourPredatorAlien: + case I_BehaviourXenoborg: + { + useVision=1; + break; + } + case I_BehaviourMarine: + { + MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + GLOBALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) + { + useVision=1; + } + break; + } + + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)Global_ODB_Ptr->ObStrategyBlock->SBdataptr; + + if (ghostDataPtr->type==I_BehaviourAlienPlayer || ghostDataPtr->type==I_BehaviourAlien + || (ghostDataPtr->type==I_BehaviourNetCorpse&&ghostDataPtr->subtype==I_BehaviourAlienPlayer) ) + { + useVision=1; + } + break; + } + + case I_BehaviourNetCorpse: + { + NETCORPSEDATABLOCK *corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + if (corpseDataPtr->Android || corpseDataPtr->Type==I_BehaviourAlienPlayer || corpseDataPtr->Type==I_BehaviourAlien) + { + useVision=1; + } + break; + } + case I_BehaviourHierarchicalFragment: + { + HDEBRIS_BEHAV_BLOCK *debrisDataPtr = (HDEBRIS_BEHAV_BLOCK *)sbPtr->SBdataptr; + if (debrisDataPtr->Type==I_BehaviourAlien + ||debrisDataPtr->Type==I_BehaviourQueenAlien + ||debrisDataPtr->Type==I_BehaviourPredatorAlien + ||debrisDataPtr->Type==I_BehaviourAutoGun + ||debrisDataPtr->Android) + { + useVision=1; + } + break; + } + case I_BehaviourSpeargunBolt: + { + SPEAR_BEHAV_BLOCK *spearDataPtr = (SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr; + if (spearDataPtr->SpearThroughFragment) // more flags required! + if (spearDataPtr->Type==I_BehaviourAlien + ||spearDataPtr->Type==I_BehaviourPredatorAlien + ||spearDataPtr->Type==I_BehaviourAutoGun) + { + useVision=1; + } + break; + } + default: + break; + } + + if (useVision) + { + PredatorSeeAliensVision_ShapePipeline(shapePtr); + return; + } + } + break; + } + case VISION_MODE_PRED_SEEPREDTECH: + { + STRATEGYBLOCK *sbPtr = Global_ODB_Ptr->ObStrategyBlock; + if(sbPtr) + { + int useVision=0; + switch (sbPtr->I_SBtype) + { + case I_BehaviourPredator: + { + PREDATOR_STATUS_BLOCK *predData = (PREDATOR_STATUS_BLOCK *)Global_ODB_Ptr->ObStrategyBlock->SBdataptr; + + if (!predData->CloakingEffectiveness) + { + useVision=1; + } + break; + } + case I_BehaviourNPCPredatorDisc: + case I_BehaviourPredatorDisc_SeekTrack: + { + useVision=1; + break; + } + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)Global_ODB_Ptr->ObStrategyBlock->SBdataptr; + + if((ghostDataPtr->CloakingEffectiveness == 0) + && (ghostDataPtr->type==I_BehaviourPredatorPlayer || ghostDataPtr->type==I_BehaviourPredator + || (ghostDataPtr->type==I_BehaviourInanimateObject&&ghostDataPtr->IOType==IOT_Ammo&&ghostDataPtr->subtype==AMMO_PRED_DISC) + || (ghostDataPtr->type==I_BehaviourPredatorDisc_SeekTrack) + || (ghostDataPtr->type==I_BehaviourNetCorpse&&ghostDataPtr->subtype==I_BehaviourPredatorPlayer) )) + { + useVision=1; + } + break; + } + + case I_BehaviourNetCorpse: + { + NETCORPSEDATABLOCK *corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + if (corpseDataPtr->Type==I_BehaviourPredatorPlayer || corpseDataPtr->Type==I_BehaviourPredator) + { + useVision=1; + } + break; + } + case I_BehaviourHierarchicalFragment: + { + HDEBRIS_BEHAV_BLOCK *debrisDataPtr = (HDEBRIS_BEHAV_BLOCK *)sbPtr->SBdataptr; + if (debrisDataPtr->Type==I_BehaviourPredator) + { + useVision=1; + } + break; + } + case I_BehaviourInanimateObject: + { + INANIMATEOBJECT_STATUSBLOCK* objStatPtr = (INANIMATEOBJECT_STATUSBLOCK*) sbPtr->SBdataptr; + + switch(objStatPtr->typeId) + { + case IOT_FieldCharge: + { + useVision = 1; + break; + } + case IOT_Ammo: + { + if (objStatPtr->subType == AMMO_PRED_RIFLE || objStatPtr->subType == AMMO_PRED_DISC) + { + useVision = 1; + } + break; + } + default: + break; + } + break; + } + + default: + break; + } + + if (useVision) + { + PredatorSeeAliensVision_ShapePipeline(shapePtr); + return; + } + } + else if (!Global_ODB_Ptr->ObMyModule) + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + if (!(playerStatusPtr->cloakOn||playerStatusPtr->CloakingEffectiveness!=0)) + { + PredatorSeeAliensVision_ShapePipeline(shapePtr); + return; + } + } + break; + } + default: + break; + } + +// if((Global_ODB_Ptr->ObStrategyBlock)&&(Global_ODB_Ptr->ObStrategyBlock->I_SBtype == I_BehaviourAlien)) + //textprint("shape alien\n"); + #if 0 + objectCompletelyInView = ObjectCompletelyWithinFrustrum(Global_ODB_Ptr); + if(!objectCompletelyInView) TestVerticesWithFrustrum(); + #else + TestVerticesWithFrustrum(); + #endif + + #if 1 + /* interesting hack for predator cloaking */ + if(Global_ODB_Ptr->ObStrategyBlock) + { + PRED_CLOAKSTATE cloakingStatus = PCLOAK_Off; + + if(Global_ODB_Ptr->ObStrategyBlock->I_SBtype == I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)Global_ODB_Ptr->ObStrategyBlock->SBdataptr; + + if(ghostData->CloakingEffectiveness) + { + cloakingStatus = PCLOAK_On; + CloakingMode = ONE_FIXED*5/4-ghostData->CloakingEffectiveness; + } + } + if(Global_ODB_Ptr->ObStrategyBlock->I_SBtype == I_BehaviourPredator) + { + PREDATOR_STATUS_BLOCK *predData = (PREDATOR_STATUS_BLOCK *)Global_ODB_Ptr->ObStrategyBlock->SBdataptr; + + if (predData->CloakingEffectiveness) + { + cloakingStatus = PCLOAK_On; + CloakingMode = ONE_FIXED*5/4-predData->CloakingEffectiveness;//32768; + } + } + + if (cloakingStatus == PCLOAK_On) + { + do + { + POLYHEADER *polyPtr = (POLYHEADER*) (*itemArrayPtr++); + int pif; + #if 0 + if (objectCompletelyInView) + { + pif = PolygonShouldBeDrawn(polyPtr); + } + else + { + pif = PolygonWithinFrustrum(polyPtr); + } + #else + pif = PolygonWithinFrustrum(polyPtr); + #endif + if(pif) + { + + #if 1 + switch(polyPtr->PolyItemType) + { + case I_ZB_Gouraud3dTexturedPolygon: + case I_ZB_Gouraud2dTexturedPolygon: + CloakedPolygon_Construct(polyPtr); + if (pif!=2) + { + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedCloakedPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + else D3D_ZBufferedCloakedPolygon_Output(polyPtr,VerticesBuffer); + break; + default: + textprint("found polygon of type %d\n",polyPtr->PolyItemType); + break; + } + #else + { + CloakedTexturedPolygon_Construct(polyPtr); + if (pif!=2) + { + TexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + TexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + TexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + TexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + TexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_CloakedPredatorPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + else D3D_CloakedPredatorPolygon_Output(polyPtr,VerticesBuffer); + } + #endif + } + } + while(--numitems); + return; + } + } + else if (!Global_ODB_Ptr->ObMyModule) + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + if (playerStatusPtr->cloakOn||playerStatusPtr->CloakingEffectiveness!=0) + { + int a = GetSin(CloakingPhase&4095); + a = MUL_FIXED(a,a); + CloakingMode = ONE_FIXED*5/4-playerStatusPtr->CloakingEffectiveness;//32768; + do + { + POLYHEADER *polyPtr = (POLYHEADER*) (*itemArrayPtr++); + int pif; + pif = PolygonWithinFrustrum(polyPtr); + if(pif) + { + switch(polyPtr->PolyItemType) + { + case I_ZB_Gouraud3dTexturedPolygon: + case I_ZB_Gouraud2dTexturedPolygon: + CloakedPolygon_Construct(polyPtr); + if (pif!=2) + { + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedCloakedPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + else D3D_ZBufferedCloakedPolygon_Output(polyPtr,VerticesBuffer); + break; + default: + textprint("found polygon of type %d\n",polyPtr->PolyItemType); + break; + } + } + } + while(--numitems); + return; + } + + } + #endif + #if 0 +// if (Global_ODB_Ptr->ObStrategyBlock && !Global_ODB_Ptr->ObMyModule) + { + do + { + POLYHEADER *polyPtr = (POLYHEADER*) (*itemArrayPtr++); + int pif; + + pif = PolygonWithinFrustrum(polyPtr); + + if (pif) + { + GouraudPolygon_Construct(polyPtr); + + if (pif!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudPolygon_Output(polyPtr,RenderPolygon.Vertices); + + } + else D3D_ZBufferedGouraudPolygon_Output(polyPtr,VerticesBuffer); + } + } + while(--numitems); + return; + } + #endif + do + { + POLYHEADER *polyPtr = (POLYHEADER*) (*itemArrayPtr++); + int pif; + #if 0 + if (objectCompletelyInView) + { + pif = PolygonShouldBeDrawn(polyPtr); + } + else + { + pif = PolygonWithinFrustrum(polyPtr); + } + #else + pif = PolygonWithinFrustrum(polyPtr); + #endif + + if (pif) + { + switch(polyPtr->PolyItemType) + { + #if debug + case I_Polyline: + case I_FilledPolyline: + case I_Wireframe: + + /* NB This is intended to fall through to the GouraudPolygon case */ + #endif +// case I_Gouraud3dTexturedPolygon: + case I_GouraudPolygon: + case I_Gouraud2dTexturedPolygon: + case I_Gouraud3dTexturedPolygon: + case I_2dTexturedPolygon: + case I_3dTexturedPolygon: + case I_ZB_2dTexturedPolygon: + case I_ZB_3dTexturedPolygon: + { + + // LOCALASSERT(0); + break; + } + case I_ZB_GouraudPolygon: + { +// break; + // LOCALASSERT(0); + GouraudPolygon_Construct(polyPtr); + + if (pif!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudPolygon_Output(polyPtr,RenderPolygon.Vertices); + + } + else D3D_ZBufferedGouraudPolygon_Output(polyPtr,VerticesBuffer); + break; + } + case I_ZB_Gouraud3dTexturedPolygon: + case I_ZB_Gouraud2dTexturedPolygon: + { + GouraudTexturedPolygon_Construct(polyPtr); + if (pif!=2) + { + /* if this polygon is a quad, split it into two */ + if(RenderPolygon.NumberOfVertices==4) + { + RenderPolygon.NumberOfVertices=3; + TriangleVerticesBuffer[0] = VerticesBuffer[0]; + TriangleVerticesBuffer[1] = VerticesBuffer[2]; + TriangleVerticesBuffer[2] = VerticesBuffer[3]; + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) goto SecondTriangle; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) goto SecondTriangle; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) goto SecondTriangle; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) goto SecondTriangle; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) goto SecondTriangle; + + if (polyPtr->PolyFlags & iflag_transparent) + { + AddToTranslucentPolyList(polyPtr,RenderPolygon.Vertices); + } + else + { + D3D_ZBufferedGouraudTexturedPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + + SecondTriangle: + RenderPolygon.NumberOfVertices=3; + VerticesBuffer[0] = TriangleVerticesBuffer[0]; + VerticesBuffer[1] = TriangleVerticesBuffer[1]; + VerticesBuffer[2] = TriangleVerticesBuffer[2]; + } + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + +// polyPtr->PolyFlags |= iflag_transparent; + if (polyPtr->PolyFlags & iflag_transparent) + { + AddToTranslucentPolyList(polyPtr,RenderPolygon.Vertices); + } + else + { + D3D_ZBufferedGouraudTexturedPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + + } + else + { +// polyPtr->PolyFlags |= iflag_transparent; + if (polyPtr->PolyFlags & iflag_transparent) + { + AddToTranslucentPolyList(polyPtr,VerticesBuffer); + } + else + { + D3D_ZBufferedGouraudTexturedPolygon_Output(polyPtr,VerticesBuffer); + } + } + break; + } + default: + break; + } + } + } + while(--numitems); +} + +void PredatorThermalVision_ShapePipeline(SHAPEHEADER *shapePtr) +{ + int numitems= shapePtr->numitems; + int **itemArrayPtr = shapePtr->items; + + LOCALASSERT(numitems); + + TestVerticesWithFrustrum(); + do + { + POLYHEADER *polyPtr = (POLYHEADER*) (*itemArrayPtr++); + + int pif = PolygonWithinFrustrum(polyPtr); + + if (pif) + { + PredatorThermalVisionPolygon_Construct(polyPtr); + + if (pif!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + + D3D_PredatorThermalVisionPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + else D3D_PredatorThermalVisionPolygon_Output(polyPtr,VerticesBuffer); + } + } + while(--numitems); +} +void PredatorSeeAliensVision_ShapePipeline(SHAPEHEADER *shapePtr) +{ + int numitems= shapePtr->numitems; + int **itemArrayPtr = shapePtr->items; + + LOCALASSERT(numitems); + + TestVerticesWithFrustrum(); + do + { + POLYHEADER *polyPtr = (POLYHEADER*) (*itemArrayPtr++); + + switch (polyPtr->PolyItemType) + { + case I_ZB_Gouraud3dTexturedPolygon: + case I_ZB_Gouraud2dTexturedPolygon: + { + int pif = PolygonWithinFrustrum(polyPtr); + + if (pif) + { + PredatorSeeAliensVisionPolygon_Construct(polyPtr); + + #if 0 + if (pif!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + + D3D_PredatorSeeAliensVisionPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + else D3D_PredatorSeeAliensVisionPolygon_Output(polyPtr,VerticesBuffer); + #else + if (pif!=2) + { + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudTexturedPolygon_Output(polyPtr,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudTexturedPolygon_Output(polyPtr,VerticesBuffer); + #endif + } + break; + } + default: + break; + } + } + while(--numitems); +} + + +/* CLOAKED POLYGONS */ +static void CloakedPolygon_Construct(POLYHEADER *polyPtr) +{ + int *texture_defn_ptr; + RENDERVERTEX *renderVerticesPtr = VerticesBuffer; + int i = RenderPolygon.NumberOfVertices; + + /* get ptr to uv coords for this polygon */ + { + int texture_defn_index = (polyPtr->PolyColour >> TxDefn); + texture_defn_ptr = Global_ShapeTextures[texture_defn_index]; + } + + VertexNumberPtr = &polyPtr->Poly1stPt; + + /* If this texture is animated the UV array must be calculated */ + if(polyPtr->PolyFlags & iflag_txanim) + { + /* Create the UV array */ + int uv_array[maxpolypts * 2]; + CreateTxAnimUVArray(texture_defn_ptr, uv_array, (int*)polyPtr); + texture_defn_ptr = uv_array; + + do + { + VECTORCH *vertexPtr = &(RotatedPts[*VertexNumberPtr]); + renderVerticesPtr->X = vertexPtr->vx; + renderVerticesPtr->Y = vertexPtr->vy; + renderVerticesPtr->Z = vertexPtr->vz; + renderVerticesPtr->U = texture_defn_ptr[0]; + renderVerticesPtr->V = texture_defn_ptr[1]; + + VertexIntensity(renderVerticesPtr); + { + VECTORCH mag; + int alpha; + mag.vx = vertexPtr->vx - Global_ODB_Ptr->ObView.vx; + mag.vy = vertexPtr->vy - Global_ODB_Ptr->ObView.vy; + mag.vz = vertexPtr->vz - Global_ODB_Ptr->ObView.vz; + + + if (mag.vx<0) mag.vx = -mag.vx; + if (mag.vy<0) mag.vy = -mag.vy; + if (mag.vz<0) mag.vz = -mag.vz; + alpha = GetSin(((mag.vx+mag.vy+mag.vz)*3+CloakingPhase)&4095); + + renderVerticesPtr->A = MUL_FIXED(alpha,alpha)>>10; + + if(renderVerticesPtr->A==255) + { + renderVerticesPtr->R = 255; + renderVerticesPtr->G = 255; + renderVerticesPtr->B = 255; + } + + } + renderVerticesPtr++; + VertexNumberPtr++; + + texture_defn_ptr += 2; + } + while(--i); + } + else + { + do + { + VECTORCH *vertexPtr = &(RotatedPts[*VertexNumberPtr]); + renderVerticesPtr->X = vertexPtr->vx; + renderVerticesPtr->Y = vertexPtr->vy; + renderVerticesPtr->Z = vertexPtr->vz; + renderVerticesPtr->U = texture_defn_ptr[0] << 16; + renderVerticesPtr->V = texture_defn_ptr[1] << 16; + + VertexIntensity(renderVerticesPtr); + { + VECTORCH mag; + int alpha; + + mag.vx = vertexPtr->vx - ObjectCentre.vx; + mag.vy = vertexPtr->vy - MUL_FIXED(ObjectCentre.vy,87381); + mag.vz = vertexPtr->vz - ObjectCentre.vz; + + if (mag.vx<0) mag.vx = -mag.vx; + if (mag.vy<0) mag.vy = -mag.vy; + if (mag.vz<0) mag.vz = -mag.vz; + alpha = GetSin(((mag.vx+mag.vy+mag.vz)*8+CloakingPhase)&4095); + + alpha=MUL_FIXED(alpha,alpha); + if (alpha>CloakingMode) + { + alpha=CloakingMode; + } + alpha/=256; + if (alpha>255) alpha = 255; + renderVerticesPtr->A = alpha; + + if(CloakingMode>ONE_FIXED) + { + alpha = GetSin(((mag.vx+mag.vy+mag.vz)+CloakingPhase)&4095); + alpha = MUL_FIXED(alpha,alpha)>>8; + if(alpha==255) + { + renderVerticesPtr->A = 255; + renderVerticesPtr->G = 128; + renderVerticesPtr->B = 255; + } + } + } + renderVerticesPtr++; + VertexNumberPtr++; + + texture_defn_ptr += 2; + } + while(--i); + } + +} + +static void PredatorThermalVisionPolygon_Construct(POLYHEADER *polyPtr) +{ + RENDERVERTEX *renderVerticesPtr = VerticesBuffer; + int i = RenderPolygon.NumberOfVertices; + + VertexNumberPtr = &polyPtr->Poly1stPt; + + do + { + VECTORCH *vertexPtr = &(RotatedPts[*VertexNumberPtr]); + renderVerticesPtr->X = vertexPtr->vx; + renderVerticesPtr->Y = vertexPtr->vy; + renderVerticesPtr->Z = vertexPtr->vz; + + { + int alpha; + if (Global_ODB_Ptr->SpecialFXFlags&SFXFLAG_ISAFFECTEDBYHEAT) + { + int distanceFromHeatSource = 100000; + int sourceNumber=NumberOfHeatSources; + while(sourceNumber--) + { + VECTORCH mag; + int m; + mag.vx = vertexPtr->vx - HeatSourceList[sourceNumber].Position.vx; + mag.vy = vertexPtr->vy - HeatSourceList[sourceNumber].Position.vy; + mag.vz = vertexPtr->vz - HeatSourceList[sourceNumber].Position.vz; + + m = Approximate3dMagnitude(&mag)*64; + + if(m>3); + if (alpha>65536) alpha = 65536; + } + else + { + alpha = 65536; + } + + { + int brightness = MUL_FIXED(MUL_FIXED(alpha,alpha),1275); + + if (brightness<256) + { + renderVerticesPtr->R=255; + renderVerticesPtr->G=brightness; + renderVerticesPtr->B=0; + } + else if (brightness<255+256) + { + int b=brightness-255; + renderVerticesPtr->R=(255-b); + renderVerticesPtr->G=255; + renderVerticesPtr->B=0; + } + else if (brightness<255*2+256) + { + int b=brightness-255*2; + renderVerticesPtr->R=0; + renderVerticesPtr->G=255; + renderVerticesPtr->B=b; + } + else if (brightness<255*3+256) + { + int b=brightness-255*3; + renderVerticesPtr->R=0; + renderVerticesPtr->G=255-b; + renderVerticesPtr->B=255; + } + else + { + int b=brightness-255*4; + renderVerticesPtr->R=0; + renderVerticesPtr->G=0; + renderVerticesPtr->B=255-b/2; + } + } + } + renderVerticesPtr++; + VertexNumberPtr++; + } + while(--i); +} + +static void PredatorSeeAliensVisionPolygon_Construct(POLYHEADER *polyPtr) +{ + int *texture_defn_ptr; + RENDERVERTEX *renderVerticesPtr = VerticesBuffer; + int i = RenderPolygon.NumberOfVertices; + int alpha; + + VertexNumberPtr = &polyPtr->Poly1stPt; + + { + { + int texture_defn_index = (polyPtr->PolyColour >> TxDefn); + texture_defn_ptr = Global_ShapeTextures[texture_defn_index]; + } + + /* get ptr to uv coords for this polygon */ + if(polyPtr->PolyFlags & iflag_txanim) + { + /* Create the UV array */ + int uv_array[maxpolypts * 2]; + CreateTxAnimUVArray(texture_defn_ptr, uv_array, (int*)polyPtr); + texture_defn_ptr = uv_array; + } + + if( (Global_ODB_Ptr->SpecialFXFlags & SFXFLAG_MELTINGINTOGROUND) + &&(Global_ODB_Ptr->ObFlags2 < ONE_FIXED) ) + { + alpha = Global_ODB_Ptr->ObFlags2 >> 8; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + else + { + alpha = 0; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_OFF; + } + + do + { + VECTORCH *vertexPtr = &(RotatedPts[*VertexNumberPtr]); + + if(polyPtr->PolyFlags & iflag_txanim) + { + renderVerticesPtr->U = texture_defn_ptr[0]; + renderVerticesPtr->V = texture_defn_ptr[1]; + } + else + { + renderVerticesPtr->U = texture_defn_ptr[0] << 16; + renderVerticesPtr->V = texture_defn_ptr[1] << 16; + } + + + renderVerticesPtr->X = vertexPtr->vx; + renderVerticesPtr->Y = vertexPtr->vy; + renderVerticesPtr->Z = vertexPtr->vz; + { + VECTORCH mag = RotatedPts[*VertexNumberPtr];//*(((VECTORCH *)Global_ShapeVNormals) + *VertexNumberPtr); + int colour; + mag.vx = vertexPtr->vx - Global_ODB_Ptr->ObView.vx; + mag.vy = vertexPtr->vy - Global_ODB_Ptr->ObView.vy; + mag.vz = vertexPtr->vz - Global_ODB_Ptr->ObView.vz; + + colour = GetSin(((mag.vx+mag.vy+mag.vz)*8+CloakingPhase)&4095); + colour = MUL_FIXED(colour,colour); + renderVerticesPtr->B = MUL_FIXED(colour,255); + renderVerticesPtr->R = renderVerticesPtr->B/2; + renderVerticesPtr->G = renderVerticesPtr->B/2; + + colour = MUL_FIXED(colour,colour); + colour = MUL_FIXED(colour,colour); + + renderVerticesPtr->SpecularR = colour/1024; + renderVerticesPtr->SpecularG = colour/1024; + renderVerticesPtr->SpecularB = colour/1024; + renderVerticesPtr->A = alpha; + } + + texture_defn_ptr += 2; + renderVerticesPtr++; + VertexNumberPtr++; + } + while(--i); + } +} + +/* GOURAUD POLYGONS */ +static void GouraudPolygon_Construct(POLYHEADER *polyPtr) +{ + RENDERVERTEX *renderVerticesPtr = VerticesBuffer; + int i = RenderPolygon.NumberOfVertices; + VertexNumberPtr = &polyPtr->Poly1stPt; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_OFF; + + do + { + int i; + renderVerticesPtr->X = RotatedPts[*VertexNumberPtr].vx; + renderVerticesPtr->Y = RotatedPts[*VertexNumberPtr].vy; + renderVerticesPtr->Z = RotatedPts[*VertexNumberPtr].vz; + VertexIntensity(renderVerticesPtr); + i = (renderVerticesPtr->B+renderVerticesPtr->R+renderVerticesPtr->G)/3; + renderVerticesPtr->R = i; + renderVerticesPtr->G = i; + renderVerticesPtr->B = 0; + renderVerticesPtr++; + VertexNumberPtr++; + } + while(--i); + +} + + + + + + +/* GOURAUD TEXTURED POLYGONS */ +static void GouraudTexturedPolygon_Construct(POLYHEADER *polyPtr) +{ + int *texture_defn_ptr; + RENDERVERTEX *renderVerticesPtr = VerticesBuffer; + int i = RenderPolygon.NumberOfVertices; + + + /* get ptr to uv coords for this polygon */ + { + int texture_defn_index = (polyPtr->PolyColour >> TxDefn); + texture_defn_ptr = Global_ShapeTextures[texture_defn_index]; + } + + VertexNumberPtr = &polyPtr->Poly1stPt; + + /* If this texture is animated the UV array must be calculated */ + if(polyPtr->PolyFlags & iflag_txanim) + { + /* Create the UV array */ + int uv_array[maxpolypts * 2]; + CreateTxAnimUVArray(texture_defn_ptr, uv_array, (int*)polyPtr); + texture_defn_ptr = uv_array; + + do + { + VECTORCH *vertexPtr = &(RotatedPts[*VertexNumberPtr]); + if (TRIPTASTIC_CHEATMODE) + { + renderVerticesPtr->X = vertexPtr->vx+GetSin((CloakingPhase*2 +vertexPtr->vz)&4095)/1024; + renderVerticesPtr->Y = vertexPtr->vy+GetSin((CloakingPhase-3000 +vertexPtr->vx)&4095)/1024; + renderVerticesPtr->Z = vertexPtr->vz+GetSin((CloakingPhase*3+239+vertexPtr->vy)&4095)/1024; + } + else if (UNDERWATER_CHEATMODE) + { + renderVerticesPtr->X = vertexPtr->vx+(GetSin((CloakingPhase/2 +vertexPtr->vz)&4095))/1024; + renderVerticesPtr->Y = vertexPtr->vy+(GetSin((CloakingPhase-3000+vertexPtr->vx)&4095))/1024; + renderVerticesPtr->Z = vertexPtr->vz+(GetSin((CloakingPhase/3+239+vertexPtr->vy)&4095))/1024; + } + else + { + renderVerticesPtr->X = vertexPtr->vx; + renderVerticesPtr->Y = vertexPtr->vy; + renderVerticesPtr->Z = vertexPtr->vz; + } + renderVerticesPtr->U = texture_defn_ptr[0]; + renderVerticesPtr->V = texture_defn_ptr[1]; + + if( (Global_ODB_Ptr->SpecialFXFlags & SFXFLAG_MELTINGINTOGROUND) + &&(Global_ODB_Ptr->ObFlags2 < ONE_FIXED) ) + { + renderVerticesPtr->A = Global_ODB_Ptr->ObFlags2 >> 8; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + + } + else if (polyPtr->PolyFlags & iflag_transparent) + { + renderVerticesPtr->A = 128; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + else + { + if (TRIPTASTIC_CHEATMODE) + { + renderVerticesPtr->A = TripTasticPhase; + } + else if (MOTIONBLUR_CHEATMODE) + { + renderVerticesPtr->A = 128; + } + else + { + renderVerticesPtr->A = 255; + } + RenderPolygon.TranslucencyMode = TRANSLUCENCY_OFF; + } + + if (polyPtr->PolyFlags & iflag_nolight) + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + renderVerticesPtr->R = 255; + renderVerticesPtr->G = 255; + renderVerticesPtr->B = 255; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + renderVerticesPtr->R = 0; + renderVerticesPtr->G = 255; + renderVerticesPtr->B = 0; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_PRED_THERMAL: + { + renderVerticesPtr->R = 0; + renderVerticesPtr->G = 0; + renderVerticesPtr->B = 255; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_PRED_SEEALIENS: + { + renderVerticesPtr->R = 255; + renderVerticesPtr->G = 0; + renderVerticesPtr->B = 0; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_PRED_SEEPREDTECH: + { + renderVerticesPtr->R = 0; + renderVerticesPtr->G = 255; + renderVerticesPtr->B = 0; + renderVerticesPtr->SpecularR = 255; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 255; + break; + } + } + + } + else + { + VertexIntensity(renderVerticesPtr); + } + renderVerticesPtr++; + VertexNumberPtr++; + + texture_defn_ptr += 2; + } + while(--i); + } + else + { + do + { + VECTORCH *vertexPtr = &(RotatedPts[*VertexNumberPtr]); + #if UNDERWATER + renderVerticesPtr->X = vertexPtr->vx+GetSin((CloakingPhase*2 +vertexPtr->vz)&4095)/1024; + renderVerticesPtr->Y = vertexPtr->vy+GetSin((CloakingPhase-3000 +vertexPtr->vx)&4095)/1024; + renderVerticesPtr->Z = vertexPtr->vz+GetSin((CloakingPhase*3+239+vertexPtr->vy)&4095)/1024; + #elif SPATIAL_SHOCKWAVE + { + int d = Magnitude(vertexPtr); + int a = (CloakingPhase&16383)+4000; + int u = d-a; + int offset; + + if (u>0 && u<8192) + { + VECTORCH n = *vertexPtr; + Normalise(&n); + u<<=3; + offset = MUL_FIXED(MUL_FIXED(2*u,ONE_FIXED-u),8000) + MUL_FIXED(MUL_FIXED(u,u),8192 ); + LOCALASSERT(offset>=0 && offset<=8192); + renderVerticesPtr->X = MUL_FIXED(n.vx,d);//a+offset*2); + renderVerticesPtr->Y = MUL_FIXED(n.vy,d);//a+offset*2); + renderVerticesPtr->Z = MUL_FIXED(n.vz,a+offset); + + } + else + { + renderVerticesPtr->X = vertexPtr->vx; + renderVerticesPtr->Y = vertexPtr->vy; + renderVerticesPtr->Z = vertexPtr->vz; + } + + } + #else + if (TRIPTASTIC_CHEATMODE) + { + renderVerticesPtr->X = vertexPtr->vx+GetSin((CloakingPhase*2 +vertexPtr->vz)&4095)/1024; + renderVerticesPtr->Y = vertexPtr->vy+GetSin((CloakingPhase-3000 +vertexPtr->vx)&4095)/1024; + renderVerticesPtr->Z = vertexPtr->vz+GetSin((CloakingPhase*3+239+vertexPtr->vy)&4095)/1024; + } + else if (UNDERWATER_CHEATMODE) + { + renderVerticesPtr->X = vertexPtr->vx+(GetSin((CloakingPhase/2 +vertexPtr->vz)&4095))/1024; + renderVerticesPtr->Y = vertexPtr->vy+(GetSin((CloakingPhase-3000 +vertexPtr->vx)&4095))/1024; + renderVerticesPtr->Z = vertexPtr->vz+(GetSin((CloakingPhase/3+239+vertexPtr->vy)&4095))/1024; + } + else + { + renderVerticesPtr->X = vertexPtr->vx; + renderVerticesPtr->Y = vertexPtr->vy; + renderVerticesPtr->Z = vertexPtr->vz; + } + #endif + renderVerticesPtr->U = texture_defn_ptr[0] << 16; + renderVerticesPtr->V = texture_defn_ptr[1] << 16; + + if( (Global_ODB_Ptr->SpecialFXFlags & SFXFLAG_MELTINGINTOGROUND) + &&(Global_ODB_Ptr->ObFlags2 < ONE_FIXED) ) + { + renderVerticesPtr->A = Global_ODB_Ptr->ObFlags2 >> 8; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + + } + else if (polyPtr->PolyFlags & iflag_transparent) + { + renderVerticesPtr->A = 128; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + else + { + #if 0 + VECTORCH velocity; + int a; + velocity.vx = Player->ObStrategyBlock->DynPtr->Position.vx - Player->ObStrategyBlock->DynPtr->PrevPosition.vx; + velocity.vy = Player->ObStrategyBlock->DynPtr->Position.vy - Player->ObStrategyBlock->DynPtr->PrevPosition.vy; + velocity.vz = Player->ObStrategyBlock->DynPtr->Position.vz - Player->ObStrategyBlock->DynPtr->PrevPosition.vz; + a = DIV_FIXED(Magnitude(&velocity)*4,NormalFrameTime)/256; + if (a>192) a = 192; + renderVerticesPtr->A = a; + + #elif 1 + if (TRIPTASTIC_CHEATMODE) + { + renderVerticesPtr->A = TripTasticPhase; + } + else if (MOTIONBLUR_CHEATMODE) + { + renderVerticesPtr->A = 128; + } + else + { + renderVerticesPtr->A = 255; + } + #endif + + RenderPolygon.TranslucencyMode = TRANSLUCENCY_OFF; + } + + + if (polyPtr->PolyFlags & iflag_nolight) + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + renderVerticesPtr->R = 255; + renderVerticesPtr->G = 255; + renderVerticesPtr->B = 255; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + renderVerticesPtr->R = 0; + renderVerticesPtr->G = 255; + renderVerticesPtr->B = 0; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_PRED_THERMAL: + { + renderVerticesPtr->R = 0; + renderVerticesPtr->G = 0; + renderVerticesPtr->B = 255; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_PRED_SEEALIENS: + { + renderVerticesPtr->R = 255; + renderVerticesPtr->G = 0; + renderVerticesPtr->B = 0; + renderVerticesPtr->SpecularR = 0; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 0; + break; + } + case VISION_MODE_PRED_SEEPREDTECH: + { + renderVerticesPtr->R = 0; + renderVerticesPtr->G = 255; + renderVerticesPtr->B = 0; + renderVerticesPtr->SpecularR = 255; + renderVerticesPtr->SpecularG = 0; + renderVerticesPtr->SpecularB = 255; + break; + } + } + + } + else + { + VertexIntensity(renderVerticesPtr); + } + renderVerticesPtr++; + VertexNumberPtr++; + + texture_defn_ptr += 2; + } + while(--i); + } + +} + + + + + +static void VertexIntensity_Pred_Thermal(RENDERVERTEX *renderVertexPtr) +{ + int redI,blueI,specular=0; + + int vertexNumber = *VertexNumberPtr; + + + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = ColourIntensityArray[vertexNumber].SpecularR; + renderVertexPtr->SpecularG = ColourIntensityArray[vertexNumber].SpecularG; + renderVertexPtr->SpecularB = ColourIntensityArray[vertexNumber].SpecularB; + return; + } + { + VECTORCH *vertexNormalPtr = ((VECTORCH *)Global_ShapeVNormals) + vertexNumber; + VECTORCH *vertexPtr = ((VECTORCH *)Global_ShapePoints)+vertexNumber; + LIGHTBLOCK **larrayptr; + LIGHTBLOCK *lptr; + int i; + + redI = 0; + + larrayptr = LightSourcesForObject; + + for(i = NumLightSourcesForObject; i!=0; i--) + { + + VECTORCH vertexToLight; + int distanceToLight; + + lptr = *larrayptr++; + + if (lptr->LightFlags & LFlag_PreLitSource) continue; + + vertexToLight.vx = lptr->LocalLP.vx - vertexPtr->vx; + vertexToLight.vy = lptr->LocalLP.vy - vertexPtr->vy; + vertexToLight.vz = lptr->LocalLP.vz - vertexPtr->vz; + + #if 0 + distanceToLight = Approximate3dMagnitude(&vertexToLight)/2; + #else + distanceToLight = Approximate3dMagnitude(&vertexToLight); + #endif + if(distanceToLight < lptr->LightRange) + { + int idot = MUL_FIXED(lptr->LightRange-distanceToLight,lptr->BrightnessOverRange); + + if( (distanceToLight>0) && (!(Global_ODB_Ptr->ObFlags3 & ObFlag3_NoLightDot)) ) + { + int dotproduct = MUL_FIXED(vertexNormalPtr->vx,vertexToLight.vx) + + MUL_FIXED(vertexNormalPtr->vy,vertexToLight.vy) + + MUL_FIXED(vertexNormalPtr->vz,vertexToLight.vz); + if(dotproduct>0) + { + idot = WideMulNarrowDiv(idot,dotproduct,distanceToLight); + } + else + { + idot = 0; + } + + idot = WideMulNarrowDiv(idot,dotproduct,distanceToLight); + } + + + redI += idot; + if (lptr->LightFlags&LFlag_Thermal) + { + specular += idot; + } + } + } + } + blueI = ONE_FIXED/2; + if (renderVertexPtr->Z>5000) + { + int a = (renderVertexPtr->Z-5000); + if (a>4096) blueI = (blueI*4096)/a; + } + + blueI >>= 8; + + if(redI >= ONE_FIXED) redI = (ONE_FIXED - 1); + redI >>=8; + + specular>>=6; + if (specular >= 255) specular = 255; + + /* KJL 12:41:54 05/10/98 - red/green swapped, whilst testing colours */ + renderVertexPtr->R = 0; + ColourIntensityArray[vertexNumber].R = 0; + renderVertexPtr->B = blueI; + ColourIntensityArray[vertexNumber].B = blueI; + renderVertexPtr->G = redI/2; + ColourIntensityArray[vertexNumber].G = redI/2; + + + renderVertexPtr->SpecularR = specular;//specularR; + ColourIntensityArray[vertexNumber].SpecularR = specular;//specularR; + + renderVertexPtr->SpecularG = specular; + ColourIntensityArray[vertexNumber].SpecularG = specular; + + renderVertexPtr->SpecularB = specular;//specularB; + ColourIntensityArray[vertexNumber].SpecularB = specular;//specularB; + + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; +} +static void VertexIntensity_Pred_SeeAliens(RENDERVERTEX *renderVertexPtr) +{ + int redI,blueI,specular=0; + + int vertexNumber = *VertexNumberPtr; + + + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = ColourIntensityArray[vertexNumber].SpecularR; + renderVertexPtr->SpecularG = ColourIntensityArray[vertexNumber].SpecularG; + renderVertexPtr->SpecularB = ColourIntensityArray[vertexNumber].SpecularB; + return; + } + + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; + + { + VECTORCH *vertexPtr = ((VECTORCH *)Global_ShapePoints)+vertexNumber; + LIGHTBLOCK **larrayptr; + LIGHTBLOCK *lptr; + int i; + + redI = 0; + + larrayptr = LightSourcesForObject; + + for(i = NumLightSourcesForObject; i!=0; i--) + { + + VECTORCH vertexToLight; + int distanceToLight; + + lptr = *larrayptr++; + + if (lptr->LightFlags & LFlag_PreLitSource) continue; + + vertexToLight.vx = lptr->LocalLP.vx - vertexPtr->vx; + vertexToLight.vy = lptr->LocalLP.vy - vertexPtr->vy; + vertexToLight.vz = lptr->LocalLP.vz - vertexPtr->vz; + + distanceToLight = Approximate3dMagnitude(&vertexToLight); + if(distanceToLight < lptr->LightRange) + { + int idot = MUL_FIXED(lptr->LightRange-distanceToLight,lptr->BrightnessOverRange); + + redI += idot; + if(lptr->LightFlags&LFlag_Electrical) + { + specular += idot; + } + } + } + } + redI >>=11; + if(redI > 255) redI = 255; + renderVertexPtr->G = redI; + ColourIntensityArray[vertexNumber].G = redI; + + + blueI = ONE_FIXED/2; + if (renderVertexPtr->Z>5000) + { + int a = (renderVertexPtr->Z-5000); + if (a>4096) blueI = (blueI*4096)/a; + } + /* KJL 12:41:54 05/10/98 - red/green swapped, whilst testing colours */ + blueI >>= 9; + renderVertexPtr->R = blueI; + ColourIntensityArray[vertexNumber].R = blueI; + renderVertexPtr->B = 0; + ColourIntensityArray[vertexNumber].B = 0; + + specular >>=10; + if(specular>255) specular = 255; + renderVertexPtr->SpecularR = specular;//specularR; + ColourIntensityArray[vertexNumber].SpecularR = specular;//specularR; + renderVertexPtr->SpecularG = specular; + ColourIntensityArray[vertexNumber].SpecularG = specular; + renderVertexPtr->SpecularB = specular;//specularB; + ColourIntensityArray[vertexNumber].SpecularB = specular;//specularB; +} +static void VertexIntensity_Pred_SeePredatorTech(RENDERVERTEX *renderVertexPtr) +{ + int redI,blueI; + + int vertexNumber = *VertexNumberPtr; + + + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = ColourIntensityArray[vertexNumber].SpecularR; + renderVertexPtr->SpecularG = ColourIntensityArray[vertexNumber].SpecularG; + renderVertexPtr->SpecularB = ColourIntensityArray[vertexNumber].SpecularB; + return; + } + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; + { + VECTORCH *vertexPtr = ((VECTORCH *)Global_ShapePoints)+vertexNumber; + LIGHTBLOCK **larrayptr; + LIGHTBLOCK *lptr; + int i; + + redI = 0; + + larrayptr = LightSourcesForObject; + + for(i = NumLightSourcesForObject; i!=0; i--) + { + + VECTORCH vertexToLight; + int distanceToLight; + + lptr = *larrayptr++; + + if (lptr->LightFlags & LFlag_PreLitSource) continue; + + vertexToLight.vx = lptr->LocalLP.vx - vertexPtr->vx; + vertexToLight.vy = lptr->LocalLP.vy - vertexPtr->vy; + vertexToLight.vz = lptr->LocalLP.vz - vertexPtr->vz; + + distanceToLight = Approximate3dMagnitude(&vertexToLight); + if(distanceToLight < lptr->LightRange) + { + int idot = MUL_FIXED(lptr->LightRange-distanceToLight,lptr->BrightnessOverRange); + + redI += idot; + } + } + } + blueI = ONE_FIXED-1; + if (renderVertexPtr->Z>5000) + { + int a = (renderVertexPtr->Z-5000); + if (a>4096) blueI = (blueI*4096)/a; + } + + blueI >>=8; + + redI >>=9; + if (redI>255) redI=255; + + /* KJL 12:41:54 05/10/98 - red/green swapped, whilst testing colours */ + renderVertexPtr->R = 255; + ColourIntensityArray[vertexNumber].R = 255; + renderVertexPtr->B = 255; + ColourIntensityArray[vertexNumber].B = 255; + renderVertexPtr->G = blueI; + ColourIntensityArray[vertexNumber].G = blueI; + + + renderVertexPtr->SpecularR = 255;//specularR; + ColourIntensityArray[vertexNumber].SpecularR = 255;//specularR; + + renderVertexPtr->SpecularG = redI; + ColourIntensityArray[vertexNumber].SpecularG = redI; + + renderVertexPtr->SpecularB = 255;//specularB; + ColourIntensityArray[vertexNumber].SpecularB = 255;//specularB; + +} +static void VertexIntensity_ImageIntensifier(RENDERVERTEX *renderVertexPtr) +{ + int greenI; + int specular; + + int vertexNumber = *VertexNumberPtr; + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = ColourIntensityArray[vertexNumber].SpecularR; + renderVertexPtr->SpecularG = ColourIntensityArray[vertexNumber].SpecularG; + renderVertexPtr->SpecularB = ColourIntensityArray[vertexNumber].SpecularB; + return; + } + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; + + { + VECTORCH *vertexNormalPtr = ((VECTORCH *)Global_ShapeVNormals) + vertexNumber; + VECTORCH *vertexPtr = ((VECTORCH *)Global_ShapePoints)+vertexNumber; + + LIGHTBLOCK **larrayptr; + LIGHTBLOCK *lptr; + int i; + + greenI = 0; + specular = 0; + + larrayptr = LightSourcesForObject; + + for(i = NumLightSourcesForObject; i!=0; i--) + { + + VECTORCH vertexToLight; + int distanceToLight; + + lptr = *larrayptr++; + + vertexToLight.vx = lptr->LocalLP.vx - vertexPtr->vx; + vertexToLight.vy = lptr->LocalLP.vy - vertexPtr->vy; + vertexToLight.vz = lptr->LocalLP.vz - vertexPtr->vz; + { + int dx,dy,dz; + + dx = vertexToLight.vx; + if (dx<0) dx = -dx; + + dy = vertexToLight.vy; + if (dy<0) dy = -dy; + + dz = vertexToLight.vz; + if (dz<0) dz = -dz; + + + if (dx>dy) + { + if (dx>dz) + { + distanceToLight = dx + ((dy+dz)>>2); + } + else + { + distanceToLight = dz + ((dy+dx)>>2); + } + } + else + { + if (dy>dz) + { + distanceToLight = dy + ((dx+dz)>>2); + } + else + { + distanceToLight = dz + ((dx+dy)>>2); + } + } + } + + if(distanceToLight < lptr->LightRange) + { + int idot = MUL_FIXED(lptr->LightRange-distanceToLight,lptr->BrightnessOverRange); + + if(distanceToLight>0) + { + int dotproduct = MUL_FIXED(vertexNormalPtr->vx,vertexToLight.vx) + + MUL_FIXED(vertexNormalPtr->vy,vertexToLight.vy) + + MUL_FIXED(vertexNormalPtr->vz,vertexToLight.vz); + + if(dotproduct>0) + { + idot = (WideMulNarrowDiv(idot,dotproduct,distanceToLight)+idot/4); + } + else + { + idot /= 4; + } + } + if(idot<0) + { + LOCALASSERT(idot>=0); + } + specular += idot; + } + } + } + + greenI = 255; + if (renderVertexPtr->Z>5000) + { + int a = (renderVertexPtr->Z-5000); + if (a>4096) greenI = (greenI*4096)/a; + } + renderVertexPtr->G = greenI; + ColourIntensityArray[vertexNumber].G = greenI; + + renderVertexPtr->R = 0; + ColourIntensityArray[vertexNumber].R = 0; + renderVertexPtr->B = 0; + ColourIntensityArray[vertexNumber].B = 0; + + specular>>=7; + if (specular>254) specular=254; + LOCALASSERT(specular>=0 && specular<=254); + renderVertexPtr->SpecularR = specular; + ColourIntensityArray[vertexNumber].SpecularR = specular; + renderVertexPtr->SpecularG = specular; + ColourIntensityArray[vertexNumber].SpecularG = specular; + renderVertexPtr->SpecularB = specular; + ColourIntensityArray[vertexNumber].SpecularB = specular; + +} + +static void VertexIntensity_Alien_Sense(RENDERVERTEX *renderVertexPtr) +{ + int intensity; + int vertexNumber = *VertexNumberPtr; + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = 0; + renderVertexPtr->SpecularG = 0; + renderVertexPtr->SpecularB = 0; + return; + } + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; + + intensity = 255; + if (renderVertexPtr->Z>5000) + { + int a = (renderVertexPtr->Z-5000); + if (a>1024) intensity = (intensity*1024)/a; + } + + renderVertexPtr->R = intensity; + ColourIntensityArray[vertexNumber].R = intensity; + + renderVertexPtr->G = intensity; + ColourIntensityArray[vertexNumber].G = intensity; + + renderVertexPtr->B = intensity; + ColourIntensityArray[vertexNumber].B = intensity; + + renderVertexPtr->SpecularR = 0; + renderVertexPtr->SpecularG = 0; + renderVertexPtr->SpecularB = 0; + +} + + + +static void VertexIntensity_Standard_Opt(RENDERVERTEX *renderVertexPtr) +{ + int redI,greenI,blueI; + int specularR,specularG,specularB; + + int vertexNumber = *VertexNumberPtr; + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = ColourIntensityArray[vertexNumber].SpecularR; + renderVertexPtr->SpecularG = ColourIntensityArray[vertexNumber].SpecularG; + renderVertexPtr->SpecularB = ColourIntensityArray[vertexNumber].SpecularB; + return; + } + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; + { + VECTORCH *vertexNormalPtr = ((VECTORCH *)Global_ShapeVNormals) + vertexNumber; + VECTORCH *vertexPtr = ((VECTORCH *)Global_ShapePoints)+vertexNumber; + + LIGHTBLOCK **larrayptr; + LIGHTBLOCK *lptr; + int i; + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_PreLit) + { + unsigned int packedI = Global_EID_IPtr[vertexNumber]; + blueI = (packedI&255)*257; + + packedI >>=8; + greenI = (packedI&255)*257; + + packedI >>=8; + redI = (packedI&255)*257; + } + else + { + redI = 0; + greenI = 0; + blueI = 0; + } + + specularR = 0; + specularG = 0; + specularB = 0; + + + + larrayptr = LightSourcesForObject; + + for(i = NumLightSourcesForObject; i!=0; i--) + { + + VECTORCH vertexToLight; + int distanceToLight; + + lptr = *larrayptr++; + + vertexToLight.vx = lptr->LocalLP.vx - vertexPtr->vx; + vertexToLight.vy = lptr->LocalLP.vy - vertexPtr->vy; + vertexToLight.vz = lptr->LocalLP.vz - vertexPtr->vz; + { + int dx,dy,dz; + + dx = vertexToLight.vx; + if (dx<0) dx = -dx; + + dy = vertexToLight.vy; + if (dy<0) dy = -dy; + + dz = vertexToLight.vz; + if (dz<0) dz = -dz; + + + if (dx>dy) + { + if (dx>dz) + { + distanceToLight = dx + ((dy+dz)>>2); + } + else + { + distanceToLight = dz + ((dy+dx)>>2); + } + } + else + { + if (dy>dz) + { + distanceToLight = dy + ((dx+dz)>>2); + } + else + { + distanceToLight = dz + ((dx+dy)>>2); + } + } + } + + if(distanceToLight < lptr->LightRange) + { + int idot = MUL_FIXED(lptr->LightRange-distanceToLight,lptr->BrightnessOverRange); + int r,g,b; + + if(distanceToLight>0) + { + int dotproduct = MUL_FIXED(vertexNormalPtr->vx,vertexToLight.vx) + + MUL_FIXED(vertexNormalPtr->vy,vertexToLight.vy) + + MUL_FIXED(vertexNormalPtr->vz,vertexToLight.vz); + + if(dotproduct>0) + { + idot = (WideMulNarrowDiv(idot,dotproduct,distanceToLight)+idot/4)/2; + } + else + { + idot /= 8; + } + } + + r = MUL_FIXED(idot,lptr->RedScale); + g = MUL_FIXED(idot,lptr->GreenScale); + b = MUL_FIXED(idot,lptr->BlueScale); + + redI += r; + greenI += g; + blueI += b; + + if( !(lptr->LightFlags & LFlag_PreLitSource) + && !(lptr->LightFlags & LFlag_NoSpecular) ) + { + specularR += r; + specularG += g; + specularB += b; + } + } + } + } + + if(Global_ODB_Ptr->SpecialFXFlags & SFXFLAG_ONFIRE) + { + specularR>>=2; + specularG>>=2; + specularB>>=2; + + redI>>=1; + greenI>>=1; + blueI>>=1; + } + + /* Intensity for Textures */ + redI >>= 8; + if(redI > 255) redI = 255; + renderVertexPtr->R = redI; + ColourIntensityArray[vertexNumber].R = redI; + + greenI >>= 8; + if(greenI > 255) greenI = 255; + renderVertexPtr->G = greenI; + ColourIntensityArray[vertexNumber].G = greenI; + + blueI >>= 8; + if(blueI > 255) blueI = 255; + renderVertexPtr->B = blueI; + ColourIntensityArray[vertexNumber].B = blueI; + + specularR >>= 10; + if(specularR > 255) specularR = 255; + renderVertexPtr->SpecularR = specularR; + ColourIntensityArray[vertexNumber].SpecularR = specularR; + + specularG >>= 10; + if(specularG > 255) specularG = 255; + renderVertexPtr->SpecularG = specularG; + ColourIntensityArray[vertexNumber].SpecularG = specularG; + + specularB >>= 10; + if(specularB > 255) specularB = 255; + renderVertexPtr->SpecularB = specularB; + ColourIntensityArray[vertexNumber].SpecularB = specularB; + +} +static void VertexIntensity_FullBright(RENDERVERTEX *renderVertexPtr) +{ + int vertexNumber = *VertexNumberPtr; + renderVertexPtr->R = 255; + ColourIntensityArray[vertexNumber].R = 255; + renderVertexPtr->G = 255; + ColourIntensityArray[vertexNumber].G = 255; + renderVertexPtr->B = 255; + ColourIntensityArray[vertexNumber].B = 255; + + renderVertexPtr->SpecularR = 0; + ColourIntensityArray[vertexNumber].SpecularR = 0; + renderVertexPtr->SpecularG = 0; + ColourIntensityArray[vertexNumber].SpecularG = 0; + renderVertexPtr->SpecularB = 0; + ColourIntensityArray[vertexNumber].SpecularB = 0; +} + +static void VertexIntensity_DiscoInferno(RENDERVERTEX *renderVertexPtr) +{ + int redI,greenI,blueI; + int specularR,specularG,specularB; + + int vertexNumber = *VertexNumberPtr; + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = ColourIntensityArray[vertexNumber].SpecularR; + renderVertexPtr->SpecularG = ColourIntensityArray[vertexNumber].SpecularG; + renderVertexPtr->SpecularB = ColourIntensityArray[vertexNumber].SpecularB; + return; + } + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; + { + VECTORCH *vertexNormalPtr = ((VECTORCH *)Global_ShapeVNormals) + vertexNumber; + VECTORCH *vertexPtr = ((VECTORCH *)Global_ShapePoints)+vertexNumber; + + LIGHTBLOCK **larrayptr; + LIGHTBLOCK *lptr; + int i; + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_PreLit) + { + unsigned int packedI = Global_EID_IPtr[vertexNumber]; + blueI = (packedI&255)*257; + + packedI >>=8; + greenI = (packedI&255)*257; + + packedI >>=8; + redI = (packedI&255)*257; + } + else + { + redI = 0; + greenI = 0; + blueI = 0; + } + + specularR = 0; + specularG = 0; + specularB = 0; + + + + larrayptr = LightSourcesForObject; + + for(i = NumLightSourcesForObject; i!=0; i--) + { + + VECTORCH vertexToLight; + int distanceToLight; + + lptr = *larrayptr++; + + vertexToLight.vx = lptr->LocalLP.vx - vertexPtr->vx; + vertexToLight.vy = lptr->LocalLP.vy - vertexPtr->vy; + vertexToLight.vz = lptr->LocalLP.vz - vertexPtr->vz; + { + int dx,dy,dz; + + dx = vertexToLight.vx; + if (dx<0) dx = -dx; + + dy = vertexToLight.vy; + if (dy<0) dy = -dy; + + dz = vertexToLight.vz; + if (dz<0) dz = -dz; + + + if (dx>dy) + { + if (dx>dz) + { + distanceToLight = dx + ((dy+dz)>>2); + } + else + { + distanceToLight = dz + ((dy+dx)>>2); + } + } + else + { + if (dy>dz) + { + distanceToLight = dy + ((dx+dz)>>2); + } + else + { + distanceToLight = dz + ((dx+dy)>>2); + } + } + } + + if(distanceToLight < lptr->LightRange) + { + int idot = MUL_FIXED(lptr->LightRange-distanceToLight,lptr->BrightnessOverRange); + int r,g,b; + + if(distanceToLight>0) + { + int dotproduct = MUL_FIXED(vertexNormalPtr->vx,vertexToLight.vx) + + MUL_FIXED(vertexNormalPtr->vy,vertexToLight.vy) + + MUL_FIXED(vertexNormalPtr->vz,vertexToLight.vz); + + if(dotproduct>0) + { + idot = (WideMulNarrowDiv(idot,dotproduct,distanceToLight)+idot/4)/2; + } + else + { + idot /= 8; + } + } + + r = MUL_FIXED(idot,lptr->RedScale); + g = MUL_FIXED(idot,lptr->GreenScale); + b = MUL_FIXED(idot,lptr->BlueScale); + + redI += r; + greenI += g; + blueI += b; + + if( !(lptr->LightFlags & LFlag_PreLitSource) + && !(lptr->LightFlags & LFlag_NoSpecular) ) + { + specularR += r; + specularG += g; + specularB += b; + } + } + } + } + + if(Global_ODB_Ptr->SpecialFXFlags & SFXFLAG_ONFIRE) + { + specularR>>=2; + specularG>>=2; + specularB>>=2; + + redI>>=1; + greenI>>=1; + blueI>>=1; + } + + { + int i = (redI+greenI+blueI); + int si = (specularR+specularG+specularB); + + VECTORCH vertex = *(((VECTORCH *)Global_ShapePoints)+vertexNumber); + int r,g,b; + vertex.vx += Global_ODB_Ptr->ObWorld.vx; + vertex.vy += Global_ODB_Ptr->ObWorld.vy; + vertex.vz += Global_ODB_Ptr->ObWorld.vz; + + r = GetSin((vertex.vx+CloakingPhase)&4095); + r = MUL_FIXED(r,r); + redI = MUL_FIXED(r,i); + specularR = MUL_FIXED(r,si); + + g = GetSin((vertex.vy+CloakingPhase/2)&4095); + g = MUL_FIXED(g,g); + greenI = MUL_FIXED(g,i); + specularG = MUL_FIXED(g,si); + + b = GetSin((vertex.vz+CloakingPhase*3)&4095); + b = MUL_FIXED(b,b); + blueI = MUL_FIXED(b,i); + specularB = MUL_FIXED(b,si); + + } + + + + /* Intensity for Textures */ + redI >>= 8; + if(redI > 255) redI = 255; + renderVertexPtr->R = redI; + ColourIntensityArray[vertexNumber].R = redI; + + greenI >>= 8; + if(greenI > 255) greenI = 255; + renderVertexPtr->G = greenI; + ColourIntensityArray[vertexNumber].G = greenI; + + blueI >>= 8; + if(blueI > 255) blueI = 255; + renderVertexPtr->B = blueI; + ColourIntensityArray[vertexNumber].B = blueI; + + specularR >>= 10; + if(specularR > 255) specularR = 255; + renderVertexPtr->SpecularR = specularR; + ColourIntensityArray[vertexNumber].SpecularR = specularR; + + specularG >>= 10; + if(specularG > 255) specularG = 255; + renderVertexPtr->SpecularG = specularG; + ColourIntensityArray[vertexNumber].SpecularG = specularG; + + specularB >>= 10; + if(specularB > 255) specularB = 255; + renderVertexPtr->SpecularB = specularB; + ColourIntensityArray[vertexNumber].SpecularB = specularB; + + +} +static void VertexIntensity_Underwater(RENDERVERTEX *renderVertexPtr) +{ + int redI,greenI,blueI; + int specularR,specularG,specularB; + + int vertexNumber = *VertexNumberPtr; + + if(ColourIntensityArray[vertexNumber].Stamp==ObjectCounter) + { + renderVertexPtr->R = ColourIntensityArray[vertexNumber].R; + renderVertexPtr->G = ColourIntensityArray[vertexNumber].G; + renderVertexPtr->B = ColourIntensityArray[vertexNumber].B; + renderVertexPtr->SpecularR = ColourIntensityArray[vertexNumber].SpecularR; + renderVertexPtr->SpecularG = ColourIntensityArray[vertexNumber].SpecularG; + renderVertexPtr->SpecularB = ColourIntensityArray[vertexNumber].SpecularB; + return; + } + ColourIntensityArray[vertexNumber].Stamp=ObjectCounter; + { + VECTORCH *vertexNormalPtr = ((VECTORCH *)Global_ShapeVNormals) + vertexNumber; + VECTORCH *vertexPtr = ((VECTORCH *)Global_ShapePoints)+vertexNumber; + + LIGHTBLOCK **larrayptr; + LIGHTBLOCK *lptr; + int i; + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_PreLit) + { + unsigned int packedI = Global_EID_IPtr[vertexNumber]; + blueI = (packedI&255)*257; + + packedI >>=8; + greenI = (packedI&255)*257; + + packedI >>=8; + redI = (packedI&255)*257; + } + else + { + redI = 0; + greenI = 0; + blueI = 0; + } + + specularR = 0; + specularG = 0; + specularB = 0; + + + + larrayptr = LightSourcesForObject; + + for(i = NumLightSourcesForObject; i!=0; i--) + { + + VECTORCH vertexToLight; + int distanceToLight; + + lptr = *larrayptr++; + + vertexToLight.vx = lptr->LocalLP.vx - vertexPtr->vx; + vertexToLight.vy = lptr->LocalLP.vy - vertexPtr->vy; + vertexToLight.vz = lptr->LocalLP.vz - vertexPtr->vz; + { + int dx,dy,dz; + + dx = vertexToLight.vx; + if (dx<0) dx = -dx; + + dy = vertexToLight.vy; + if (dy<0) dy = -dy; + + dz = vertexToLight.vz; + if (dz<0) dz = -dz; + + + if (dx>dy) + { + if (dx>dz) + { + distanceToLight = dx + ((dy+dz)>>2); + } + else + { + distanceToLight = dz + ((dy+dx)>>2); + } + } + else + { + if (dy>dz) + { + distanceToLight = dy + ((dx+dz)>>2); + } + else + { + distanceToLight = dz + ((dx+dy)>>2); + } + } + } + + if(distanceToLight < lptr->LightRange) + { + int idot = MUL_FIXED(lptr->LightRange-distanceToLight,lptr->BrightnessOverRange); + int r,g,b; + + if(distanceToLight>0) + { + int dotproduct = MUL_FIXED(vertexNormalPtr->vx,vertexToLight.vx) + + MUL_FIXED(vertexNormalPtr->vy,vertexToLight.vy) + + MUL_FIXED(vertexNormalPtr->vz,vertexToLight.vz); + + if(dotproduct>0) + { + idot = (WideMulNarrowDiv(idot,dotproduct,distanceToLight)+idot/4)/2; + } + else + { + idot /= 8; + } + } + + r = MUL_FIXED(idot,lptr->RedScale); + g = MUL_FIXED(idot,lptr->GreenScale); + b = MUL_FIXED(idot,lptr->BlueScale); + + redI += r; + greenI += g; + blueI += b; + + if( !(lptr->LightFlags & LFlag_PreLitSource) + && !(lptr->LightFlags & LFlag_NoSpecular) ) + { + specularR += r; + specularG += g; + specularB += b; + } + } + } + } + + if(Global_ODB_Ptr->SpecialFXFlags & SFXFLAG_ONFIRE) + { + specularR>>=2; + specularG>>=2; + specularB>>=2; + + redI>>=1; + greenI>>=1; + blueI>>=1; + } + + { + if (specularBZ*4) + specularB = renderVertexPtr->Z*4; + + } + + + + /* Intensity for Textures */ + redI >>= 8; + if(redI > 255) redI = 255; + renderVertexPtr->R = redI; + ColourIntensityArray[vertexNumber].R = redI; + + greenI >>= 8; + if(greenI > 255) greenI = 255; + renderVertexPtr->G = greenI; + ColourIntensityArray[vertexNumber].G = greenI; + + blueI >>= 8; + if(blueI > 255) blueI = 255; + renderVertexPtr->B = blueI; + ColourIntensityArray[vertexNumber].B = blueI; + + specularR >>= 10; + if(specularR > 255) specularR = 255; + renderVertexPtr->SpecularR = specularR; + ColourIntensityArray[vertexNumber].SpecularR = specularR; + + specularG >>= 10; + if(specularG > 255) specularG = 255; + renderVertexPtr->SpecularG = specularG; + ColourIntensityArray[vertexNumber].SpecularG = specularG; + + specularB >>= 10; + if(specularB > 255) specularB = 255; + renderVertexPtr->SpecularB = specularB; + ColourIntensityArray[vertexNumber].SpecularB = specularB; + + + } + +/*KJL*********************************************************************** +* The following functions have been transplanted from the old shape.c, and * +* will probably be found a new home at some point in the future. * +***********************************************************************KJL*/ + +/* + + Texture Animation + +*/ + +int* GetTxAnimArrayZ(int shape, int item) + +{ + + SHAPEHEADER *sptr; + int **item_array_ptr; + int **shape_textures; + int *item_ptr; + POLYHEADER *pheader; + int texture_defn_index; + + + sptr = GetShapeData(shape); + + if(sptr && sptr->sh_textures && sptr->items) { + + item_array_ptr = sptr->items; + shape_textures = sptr->sh_textures; + + item_ptr = item_array_ptr[item]; + pheader = (POLYHEADER *) item_ptr; + + texture_defn_index = (pheader->PolyColour >> TxDefn); + + if(pheader->PolyFlags & iflag_txanim) { + + return (int*) shape_textures[texture_defn_index]; + + } + + else return 0; + + } + + else return 0; + +} + + +TXANIMHEADER* GetTxAnimDataZ(int shape, int item, int sequence) + +{ + + SHAPEHEADER *sptr; + TXANIMHEADER **txah_ptr; + TXANIMHEADER *txah; + int **item_array_ptr; + int **shape_textures; + int *item_ptr; + POLYHEADER *pheader; + int texture_defn_index; + + + sptr = GetShapeData(shape); + + if(sptr && sptr->sh_textures && sptr->items) { + + item_array_ptr = sptr->items; + shape_textures = sptr->sh_textures; + + item_ptr = item_array_ptr[item]; + pheader = (POLYHEADER *) item_ptr; + + texture_defn_index = (pheader->PolyColour >> TxDefn); + + if(pheader->PolyFlags & iflag_txanim) { + + txah_ptr = (TXANIMHEADER **) shape_textures[texture_defn_index]; + txah_ptr++; /* Skip sequence shadow */ + + txah = txah_ptr[sequence]; + + return txah; + + } + + else return 0; + + } + + else return 0; + +} + + + + +/* + + For some animated textures each sequence will represent a different view + of a sprite. When each sequence has the same number of frames there is no + problem transferring the value from one "txa_currentframe" to the other. + However if the new sequence has a different number of frames a scaling must + be done. + +*/ + +void ChangeSequence(TXANIMHEADER *txah_old, TXANIMHEADER *txah_new) + +{ + + if(txah_new->txa_numframes == txah_old->txa_numframes) { + + txah_new->txa_currentframe = txah_old->txa_currentframe; + + } + + else { + + txah_new->txa_currentframe = + + WideMulNarrowDiv(txah_old->txa_currentframe, + txah_new->txa_maxframe, + txah_old->txa_maxframe); + + } +} + + +/* + + This function copies the TXANIMHEADER from the shape data item sequence + selected by the TXACTRLBLK to the TXANIMHEADER in the TXACTRLBLK + +*/ + +TXANIMHEADER* GetTxAnimHeaderFromShape(TXACTRLBLK *taptr, int shape) + +{ + + TXANIMHEADER *txah = 0; + + + { + + txah = GetTxAnimDataZ(shape, taptr->tac_item, taptr->tac_sequence); + + } + + if(txah) { + + taptr->tac_txah.txa_flags = txah->txa_flags; + taptr->tac_txah.txa_state = txah->txa_state; + taptr->tac_txah.txa_numframes = txah->txa_numframes; + taptr->tac_txah.txa_framedata = txah->txa_framedata; + taptr->tac_txah.txa_currentframe = txah->txa_currentframe; + taptr->tac_txah.txa_maxframe = txah->txa_maxframe; + taptr->tac_txah.txa_speed = txah->txa_speed; + + } + + return txah; + +} + + +/* + + Texture Animation Control Blocks are used to update animation. At the start + of "AddShape()" the relevant control block values are copied across to the + item TXANIMHEADER. + +*/ + +void UpdateTxAnim(TXANIMHEADER *txah) + +{ + + int UpdateRate; + + + if(txah->txa_flags & txa_flag_play) { + + /* How fast do we go? */ + + if(txah->txa_flags & txa_flag_quantiseframetime) { + + /* This option is still being designed and tested */ + + UpdateRate = txah->txa_speed & (~4096); /* 1/16th */ + if(UpdateRate < 4096) UpdateRate = 4096; + UpdateRate = MUL_FIXED(NormalFrameTime, txah->txa_speed); + + } + + else UpdateRate = MUL_FIXED(NormalFrameTime, txah->txa_speed); + + + /* Update the current frame */ + + if(txah->txa_flags & txa_flag_reverse) { + + txah->txa_currentframe -= UpdateRate; + + if(txah->txa_currentframe < 0) { + + if(txah->txa_flags & txa_flag_noloop) { + + txah->txa_currentframe = 0; + + } + + else { + + txah->txa_currentframe += txah->txa_maxframe; + + } + + } + + } + + else { + + txah->txa_currentframe += UpdateRate; + + if(txah->txa_currentframe >= txah->txa_maxframe) { + + if(txah->txa_flags & txa_flag_noloop) { + + txah->txa_currentframe = txah->txa_maxframe - 1; + + } + + else { + + txah->txa_currentframe -= txah->txa_maxframe; + + } + + } + + } + + } + +} + + +/* + + Display block TXACTRLBLKS pass their data on to shape TXANIMHEADERs + +*/ + +void ControlTextureAnimation(DISPLAYBLOCK *dptr) +{ + + TXACTRLBLK *taptr; + TXANIMHEADER *txah; + int *iptr; + + + taptr = dptr->ObTxAnimCtrlBlks; + + while(taptr) + { + /* Update animation for the display block TXACTRLBLK */ + LOCALASSERT(&(taptr->tac_txah)); + UpdateTxAnim(&taptr->tac_txah); + + /* Get the TXANIMHEADER from the shape data */ + + txah = taptr->tac_txah_s; + + /* Copy across the current frame */ + LOCALASSERT(txah); + txah->txa_currentframe = taptr->tac_txah.txa_currentframe; + + iptr = taptr->tac_txarray; + LOCALASSERT(iptr); + *iptr = taptr->tac_sequence; + + taptr = taptr->tac_next; + } +} + +void CreateTxAnimUVArray(int *txa_data, int *uv_array, int *shapeitemptr) +{ + TXANIMHEADER **txah_ptr; + TXANIMHEADER *txah; + TXANIMFRAME *txaf; + TXANIMFRAME *txaf0; + TXANIMFRAME *txaf1; + int *txaf0_uv; + int *txaf1_uv; + int CurrentFrame, NextFrame, Alpha, OneMinusAlpha; + int i; + int *iptr; + int Orient, Scale; + int OrientX, OrientY; + int ScaleX, ScaleY; + int sin, cos; + int x, y; + int x1, y1; + int o1, o2, od; + POLYHEADER *pheader = (POLYHEADER*) shapeitemptr; + int sequence; + int *txf_imageptr; + + + /* The sequence # will have been copied across by the control block */ + + sequence = *txa_data++; + + #if 0 + textprint("sequence = %d\n", sequence); + #endif + + txah_ptr = (TXANIMHEADER **) txa_data; + txah = txah_ptr[sequence]; + txaf = txah->txa_framedata; + + + /* Because the current frame can be set from outside, clamp it first */ + + if(txah->txa_currentframe < 0) { + + txah->txa_currentframe = 0; + + } + + if(txah->txa_currentframe >= txah->txa_maxframe) { + + txah->txa_currentframe = txah->txa_maxframe - 1; + + } + + + /* Frame # */ + + CurrentFrame = txah->txa_currentframe >> 16; + Alpha = txah->txa_currentframe - (CurrentFrame << 16); + OneMinusAlpha = ONE_FIXED - Alpha; + + + /* Start and End Frame */ + + NextFrame = CurrentFrame + 1; + if(NextFrame >= txah->txa_numframes) NextFrame = 0; + + txaf0 = &txaf[CurrentFrame]; + txaf1 = &txaf[NextFrame]; + + + /* + + Write the image index back to the item by overwriting the shape data. + This is not elegant but it is one of the kind of things you expect to + have happen when a major new feature is retro-fitted to a system. + + */ + + pheader->PolyColour &= ClrTxIndex; + + + /* Multi-View Sprites need to select an image from the array */ + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_MultiViewSprite) { + + int **txf_uvarrayptr0 = (int **) txaf0->txf_uvdata; + int **txf_uvarrayptr1 = (int **) txaf1->txf_uvdata; + int index; + + + index = GetMVSIndex(txah, <oVMat_Euler); + + /*textprint("index = %d\n", index);*/ + + + txf_imageptr = (int *) txaf0->txf_image; + pheader->PolyColour |= txf_imageptr[index]; + + + /* Get the uv data */ + + txaf0_uv = txf_uvarrayptr0[index]; + txaf1_uv = txf_uvarrayptr1[index]; + + } + + + /* Single-View Sprites have just one image per frame */ + + else { + + pheader->PolyColour |= txaf0->txf_image; + + txaf0_uv = txaf0->txf_uvdata; + txaf1_uv = txaf1->txf_uvdata; + + } + + + /* Calculate UVs */ + + iptr = uv_array; + + if(txah->txa_flags & txa_flag_interpolate_uvs) { + + for(i = txaf0->txf_numuvs; i!=0; i--) { + + iptr[0] = MUL_FIXED(txaf0_uv[0], OneMinusAlpha) + + MUL_FIXED(txaf1_uv[0], Alpha); + + iptr[1] = MUL_FIXED(txaf0_uv[1], OneMinusAlpha) + + MUL_FIXED(txaf1_uv[1], Alpha); + + /*textprint("%d, %d\n", iptr[0] >> 16, iptr[1] >> 16);*/ + + txaf0_uv += 2; + txaf1_uv += 2; + iptr += 2; + + } + + } + + else { + + for(i = txaf0->txf_numuvs; i!=0; i--) { + + iptr[0] = txaf0_uv[0]; + iptr[1] = txaf0_uv[1]; + + /*textprint("%d, %d\n", iptr[0] >> 16, iptr[1] >> 16);*/ + + txaf0_uv += 2; + iptr += 2; + + } + + } + + + /* Interpolate Orient and Scale */ + + o1 = txaf0->txf_orient; + o2 = txaf1->txf_orient; + + if(o1 == o2) { + + Orient = o1; + + } + + else { + + od = o1 - o2; + if(od < 0) od = -od; + + if(od >= deg180) { + + o1 <<= (32 - 12); + o1 >>= (32 - 12); + o2 <<= (32 - 12); + o2 >>= (32 - 12); + + } + + Orient = MUL_FIXED(o1, OneMinusAlpha) + MUL_FIXED(o2, Alpha); + Orient &= wrap360; + + } + + + if(txaf0->txf_scale == txaf1->txf_scale) { + + Scale = txaf0->txf_scale; + + } + + else { + + Scale = WideMul2NarrowDiv(txaf0->txf_scale, OneMinusAlpha, + txaf1->txf_scale, Alpha, ONE_FIXED); + + } + + + /* Interpolate Orient and Scale Origins */ + + if(txaf0->txf_orientx == txaf1->txf_orientx) { + + OrientX = txaf0->txf_orientx; + + } + + else { + + OrientX = MUL_FIXED(txaf0->txf_orientx, OneMinusAlpha) + + MUL_FIXED(txaf1->txf_orientx, Alpha); + + } + + + if(txaf0->txf_orienty == txaf1->txf_orienty) { + + OrientY = txaf0->txf_orienty; + + } + + else { + + OrientY = MUL_FIXED(txaf0->txf_orienty, OneMinusAlpha) + + MUL_FIXED(txaf1->txf_orienty, Alpha); + + } + + + if(txaf0->txf_scalex == txaf1->txf_scalex) { + + ScaleX = txaf0->txf_scalex; + + } + + else { + + ScaleX = MUL_FIXED(txaf0->txf_scalex, OneMinusAlpha) + + MUL_FIXED(txaf1->txf_scalex, Alpha); + + } + + + if(txaf0->txf_scaley == txaf1->txf_scaley) { + + ScaleY = txaf0->txf_scaley; + + } + + else { + + ScaleY = MUL_FIXED(txaf0->txf_scaley, OneMinusAlpha) + + MUL_FIXED(txaf1->txf_scaley, Alpha); + + } + + + + #if 0 + textprint("Alpha = %d\n", Alpha); + textprint("OneMinusAlpha = %d\n", OneMinusAlpha); + textprint("Orient = %d\n", Orient); + textprint("txaf0->txf_scale = %d\n", txaf0->txf_scale); + textprint("txaf1->txf_scale = %d\n", txaf1->txf_scale); + textprint("Scale = %d\n", Scale); + #endif + + /*WaitForReturn();*/ + + + +#if 1 + + + /* Rotate UV Array */ + + if(Orient) { + + sin = GetSin(Orient); + cos = GetCos(Orient); + + iptr = uv_array; + + for(i = txaf0->txf_numuvs; i!=0; i--) { + + x = iptr[0] - OrientX; + y = iptr[1] - OrientY; + + x1 = MUL_FIXED(x, cos) - MUL_FIXED(y, sin); + y1 = MUL_FIXED(x, sin) + MUL_FIXED(y, cos); + + iptr[0] = x1 + OrientX; + iptr[1] = y1 + OrientY; + + iptr += 2; + + } + + } + + + /* Scale UV Array */ + + if(Scale != ONE_FIXED) { + + iptr = uv_array; + + for(i = txaf0->txf_numuvs; i!=0; i--) { + + x = iptr[0] - ScaleX; + y = iptr[1] - ScaleY; + + x = MUL_FIXED(x, Scale); + y = MUL_FIXED(y, Scale); + + iptr[0] = x + ScaleX; + iptr[1] = y + ScaleY; + + iptr += 2; + + } + + } + + +#endif + + + + + + + #if 0 + textprint("Current Frame = %d\n", txah->txa_currentframe); + textprint("Current Frame = %d\n", CurrentFrame); + textprint("Next Frame = %d\n", NextFrame); + textprint("Alpha = %d\n", Alpha); + #endif + + + /*textprint("Leaving CreateTxAnimUVArray\n");*/ + /*WaitForReturn();*/ + +} + + + + + + + + + + + + + +/* + + Shape Points for Unrotated Sprites + +*/ + +void ShapeSpritePointsInstr(SHAPEINSTR *shapeinstrptr) + +{ + + int **shapeitemarrayptr = shapeinstrptr->sh_instr_data; + int *shapeitemptr = *shapeitemarrayptr; + VECTORCH *rotptsptr = RotatedPts; + int numitems; + + + for(numitems = shapeinstrptr->sh_numitems; numitems!=0; numitems--) { + + rotptsptr->vx = shapeitemptr[ix]; + rotptsptr->vx += Global_ODB_Ptr->ObView.vx; + + rotptsptr->vy = shapeitemptr[iy]; + rotptsptr->vy += Global_ODB_Ptr->ObView.vy; + + rotptsptr->vz = shapeitemptr[iz]; + rotptsptr->vz += Global_ODB_Ptr->ObView.vz; + + shapeitemptr += vsize; + rotptsptr++; + + } + +} + + +/* + + Shape Points for Rotated Sprites + +*/ + + +//I've put my alterations to the sprite rotation +//in the #else part.Richard +#define UseKevinsModifiedSSRPI No + + +#if UseKevinsModifiedSSRPI + + + +#define ssrpi_kill_py Yes + +void ShapeSpriteRPointsInstr(SHAPEINSTR *shapeinstrptr) + +{ + + int **shapeitemarrayptr = shapeinstrptr->sh_instr_data; + int *shapeitemptr = *shapeitemarrayptr; + VECTORCH *rotptsptr = RotatedPts; + int numitems; + int x,y,z; + MATRIXCH m; + #if ssrpi_kill_py + EULER e; + char flipX=0; + #endif + /* + + Sprite Resizing + + If this shape is a sprite and is using sprite resizing, there will be a transformed + copy of the polygon points array (XY only) to copy back to the shape. + + WARNING! + + This function and data structure ASSUME that the sprite shape is using an item array, + that there is just the one item, and that the world and UV space coordinates are in the + form of "TL, BL, BR, TR". It also assumes that the sprite polygon is in the XY plane. + + If ANY of these is not true for your sprite, DON'T attempt to use resizing! + + */ + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_Sprite && + Global_ShapeHeaderPtr->shapeflags & ShapeFlag_SpriteResizing) { + + int *ShapePoints; + int **item_array_ptr; + int *item_ptr; + POLYHEADER *pheader; + int *mypolystart; + int texture_defn_index; + int *texture_defn_ptr; + TXANIMHEADER **txah_ptr; + TXANIMHEADER *txah; + TXANIMFRAME *txaf; + TXANIMFRAME *txaf0; + int CurrentFrame, sequence; + int *iptr; + + ShapePoints = *(Global_ShapeHeaderPtr->points); + + /* Item */ + + item_array_ptr = Global_ShapeHeaderPtr->items; /* Assume item array */ + item_ptr = item_array_ptr[0]; /* Assume only one polygon */ + pheader = (POLYHEADER *) item_ptr; + + /* Texture Animation */ + + texture_defn_index = (pheader->PolyColour >> TxDefn); + texture_defn_ptr = Global_ShapeTextures[texture_defn_index]; + + sequence = *texture_defn_ptr++; + + txah_ptr = (TXANIMHEADER **) texture_defn_ptr; + txah = txah_ptr[sequence]; + txaf = txah->txa_framedata; + + /* Because the current frame can be set from outside, clamp it first */ + + if(txah->txa_currentframe < 0) + txah->txa_currentframe = 0; + if(txah->txa_currentframe >= txah->txa_maxframe) + txah->txa_currentframe = txah->txa_maxframe - 1; + + CurrentFrame = txah->txa_currentframe >> 16; + + txaf0 = &txaf[CurrentFrame]; + + /* UV array */ + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_Sprite) { + + int **uvarrayptr = (int **) txaf0->txf_uvdata; + iptr = uvarrayptr[GetMVSIndex(txah, <oVMat_Euler)]; + + } + + else { + + iptr = txaf0->txf_uvdata; + + } + + iptr += (txaf0->txf_numuvs * 2); + + /* Redefine the Shape Points */ + + mypolystart = &pheader->Poly1stPt; + + while(*mypolystart != Term) { + + /*textprint("copying point %d\n", *mypolystart / vsize);*/ + + *(ShapePoints + *mypolystart + ix) = iptr[0]; + *(ShapePoints + *mypolystart + iy) = iptr[1]; + + mypolystart++; + iptr += 2; + + } + + } + + + #if ssrpi_kill_py + + + /* Make a copy of the object matrix */ + + CopyMatrix(&Global_ODB_Ptr->ObMat, &m); + + + + /* Combine it with the view matrix */ + + MatrixMultiply(&Global_VDB_Ptr->VDB_SpriteMat, &m, &m); + + /* Extract the Euler Angles */ + MatrixToEuler(&m, &e); + + #if 0 + textprint("X: %d\n", e.EulerX); + textprint("Y: %d\n", e.EulerY); + textprint("Z: %d\n", e.EulerZ); + #endif + + + /* Knock out the pitch and yaw */ + + /* KJL 17:23:22 01/09/97 - If the sprite is turned away from you, flip along the + x-axis so that you get the mirror image of the sprite */ + if (e.EulerY<1024 || e.EulerY>3072) flipX = 1; + e.EulerY=0; + e.EulerX=0; + + + /* Turn it back into a matrix */ + CreateEulerMatrix(&e, &m); + TransposeMatrixCH(&m); + + #else /* ssrpi_kill_py */ + + + MatrixMultiply(&Global_VDB_Ptr->VDB_SpriteMat, &Global_ODB_Ptr->ObMat, &m); + + + #endif /* ssrpi_kill_py */ + + + for(numitems = shapeinstrptr->sh_numitems; numitems!=0; numitems--) { + + x = shapeitemptr[ix]; + y = shapeitemptr[iy]; + z = shapeitemptr[iz]; + + rotptsptr->vx = MUL_FIXED(m.mat11, x); + rotptsptr->vx += MUL_FIXED(m.mat21, y); + rotptsptr->vx += MUL_FIXED(m.mat31, z); + #if ssrpi_kill_py + if (flipX) rotptsptr->vx = - rotptsptr->vx; + #endif + rotptsptr->vx += Global_ODB_Ptr->ObView.vx; + + rotptsptr->vy = MUL_FIXED(m.mat12, x); + rotptsptr->vy += MUL_FIXED(m.mat22, y); + rotptsptr->vy += MUL_FIXED(m.mat32, z); + rotptsptr->vy += Global_ODB_Ptr->ObView.vy; + + rotptsptr->vz = MUL_FIXED(m.mat13, x); + rotptsptr->vz += MUL_FIXED(m.mat23, y); + rotptsptr->vz += MUL_FIXED(m.mat33, z); + rotptsptr->vz += Global_ODB_Ptr->ObView.vz; + + shapeitemptr += vsize; + rotptsptr++; + + } + +} + + + + +#else /* UseKevinsModifiedSSRPI */ + + + + +#define ssrpi_kill_py No + +void ShapeSpriteRPointsInstr(SHAPEINSTR *shapeinstrptr) + +{ + + int **shapeitemarrayptr = shapeinstrptr->sh_instr_data; + int *shapeitemptr = *shapeitemarrayptr; + VECTORCH *rotptsptr = RotatedPts; + int numitems; + int x,y; + VECTORCH vectx,vecty; + #if ssrpi_kill_py + MATRIXCH m2; + EULER e; + #endif + + + /* + + Sprite Resizing + + If this shape is a sprite and is using sprite resizing, there will be a transformed + copy of the polygon points array (XY only) to copy back to the shape. + + WARNING! + + This function and data structure ASSUME that the sprite shape is using an item array, + that there is just the one item, and that the world and UV space coordinates are in the + form of "TL, BL, BR, TR". It also assumes that the sprite polygon is in the XY plane. + + If ANY of these is not true for your sprite, DON'T attempt to use resizing! + + */ + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_Sprite && + Global_ShapeHeaderPtr->shapeflags & ShapeFlag_SpriteResizing) { + + int *ShapePoints; + int **item_array_ptr; + int *item_ptr; + POLYHEADER *pheader; + int *mypolystart; + int texture_defn_index; + int *texture_defn_ptr; + TXANIMHEADER **txah_ptr; + TXANIMHEADER *txah; + TXANIMFRAME *txaf; + TXANIMFRAME *txaf0; + int CurrentFrame, sequence; + int *iptr; + + ShapePoints = *(Global_ShapeHeaderPtr->points); + + /* Item */ + + item_array_ptr = Global_ShapeHeaderPtr->items; /* Assume item array */ + item_ptr = item_array_ptr[0]; /* Assume only one polygon */ + pheader = (POLYHEADER *) item_ptr; + + /* Texture Animation */ + + texture_defn_index = (pheader->PolyColour >> TxDefn); + texture_defn_ptr = Global_ShapeTextures[texture_defn_index]; + + sequence = *texture_defn_ptr++; + + txah_ptr = (TXANIMHEADER **) texture_defn_ptr; + txah = txah_ptr[sequence]; + txaf = txah->txa_framedata; + + /* Because the current frame can be set from outside, clamp it first */ + + if(txah->txa_currentframe < 0) + txah->txa_currentframe = 0; + if(txah->txa_currentframe >= txah->txa_maxframe) + txah->txa_currentframe = txah->txa_maxframe - 1; + + CurrentFrame = txah->txa_currentframe >> 16; + + txaf0 = &txaf[CurrentFrame]; + + + /* UV array */ + + if(Global_ShapeHeaderPtr->shapeflags & ShapeFlag_Sprite) { + + int **uvarrayptr = (int **) txaf0->txf_uvdata; + iptr = uvarrayptr[GetMVSIndex(txah, <oVMat_Euler)]; + + } + + else { + + iptr = txaf0->txf_uvdata; + + } + + iptr += (txaf0->txf_numuvs * 2); + + + /* Redefine the Shape Points */ + + mypolystart = &pheader->Poly1stPt; + + while(*mypolystart != Term) { + + /*textprint("copying point %d\n", *mypolystart / vsize);*/ + + ((VECTORCH *)ShapePoints)[*mypolystart].vx = iptr[0]; + ((VECTORCH *)ShapePoints)[*mypolystart].vy = iptr[1]; + + /*textprint("x, y = %d, %d\n", iptr[0], iptr[1]);*/ + + mypolystart++; + iptr += 2; + + } + + } + + //project the object's y vector onto the screen. + //then rotate the sprite's points according to the vector's orintation + //relative to the screen's y vector. + vecty=*(VECTORCH*)&Global_ODB_Ptr->ObMat.mat21; + + RotateVector(&vecty,&Global_VDB_Ptr->VDB_Mat); + if(Global_VDB_Ptr->VDB_ProjX!=Global_VDB_Ptr->VDB_ProjY) + { + vecty.vx=MUL_FIXED(vecty.vx,Global_VDB_Ptr->VDB_ProjX); + vecty.vy=MUL_FIXED(vecty.vy,Global_VDB_Ptr->VDB_ProjY); + } + vecty.vz=0; + if(!vecty.vx && !vecty.vy)vecty.vy=ONE_FIXED; + Normalise(&vecty); + vectx.vx=-vecty.vy; + vectx.vy=vecty.vx; + vectx.vz=0; + + for(numitems = shapeinstrptr->sh_numitems; numitems!=0; numitems--) { + + x = -shapeitemptr[ix]; + y = shapeitemptr[iy]; + + rotptsptr->vx = MUL_FIXED(vectx.vx, x); + rotptsptr->vx += MUL_FIXED(vectx.vy, y); + rotptsptr->vx += Global_ODB_Ptr->ObView.vx; + + rotptsptr->vy = MUL_FIXED(vecty.vx, x); + rotptsptr->vy += MUL_FIXED(vecty.vy, y); + rotptsptr->vy += Global_ODB_Ptr->ObView.vy; + + rotptsptr->vz = Global_ODB_Ptr->ObView.vz; + + shapeitemptr += vsize; + rotptsptr++; + + } + + +} + + + +#endif /* UseKevinsModifiedSSRPI */ + +int GetMVSIndex(TXANIMHEADER + *txah, EULER* e ) +{ + int EulerXIndex, EulerYIndex; + int theta,phi; //angles in spherical polar coordinates + //phi goes from 0 (top) to deg180 (bottom) + VECTORCH v; + + MakeVectorLocal(&Global_ODB_Ptr->ObWorld,&v,&Global_VDB_Ptr->VDB_World,&Global_ODB_Ptr->ObMat); + Normalise(&v); + phi=-ArcSin(v.vy); + phi+=deg90; + phi&=wrap360; + if(phi==deg180)phi--; + if(!v.vx && !v.vz) + { + theta=0; + } + else + { + v.vy=0; + Normalise(&v); + if(v.vz > Cosine45 || -v.vz>Cosine45) { + + theta = ArcSin(-v.vx); + + if(v.vz < 0) { + theta &= wrap360; + } + else + { + theta+=deg180; + theta =-theta; + theta &= wrap360; + } + } + + else { + + theta = ArcCos(v.vz); + + if(v.vx < 0) { + theta = -theta; + } + theta+=deg180; + theta &= wrap360; + + } + } + + EulerYIndex = theta; + EulerYIndex >>= txah->txa_euleryshift; + + + EulerYIndex <<= (11 - txah->txa_eulerxshift); + + EulerXIndex = phi; + EulerXIndex >>= txah->txa_eulerxshift; + + GLOBALASSERT((EulerXIndex+EulerYIndex)txa_num_mvs_images); + + return (EulerXIndex + EulerYIndex); + +} + + +void AddShape(DISPLAYBLOCK *dptr, VIEWDESCRIPTORBLOCK *VDB_Ptr) +{ + SHAPEHEADER *shapeheaderptr; + + if (!dptr->ObShape && dptr->SfxPtr) + { +// DrawSfxObject(dptr); + return; + } + /* KJL 12:42:38 18/05/98 - check to see if object is on fire */ + if (dptr->ObStrategyBlock) + { + if(dptr->ObStrategyBlock->SBDamageBlock.IsOnFire) + { + dptr->SpecialFXFlags |= SFXFLAG_ONFIRE; + } + else + { + dptr->SpecialFXFlags &= ~SFXFLAG_ONFIRE; + } + + } + + /* is object a morphing one? */ + if(dptr->ObMorphCtrl) + { + LOCALASSERT(dptr->ObMorphCtrl->ObMorphHeader); + if(dptr->ObMorphCtrl->ObMorphHeader) + { + GetMorphDisplay(&MorphDisplay, dptr); + dptr->ObShape = MorphDisplay.md_shape1; + dptr->ObShapeData = MorphDisplay.md_sptr1; + shapeheaderptr = MorphDisplay.md_sptr1; + } + } + else + { + shapeheaderptr = GetShapeData(dptr->ObShape); + + /* It is important to pass this SHAPEHEADER* on to the display block */ + dptr->ObShapeData = shapeheaderptr; + + // I've put this inside the else so that it does + // not conflict with morphing !!! + // make sure dptr->ObShapeData is up to date before + // doing CopyAnimationFrameToShape + + if (dptr->ShapeAnimControlBlock) + { + if (!(dptr->ShapeAnimControlBlock->current.empty)) + { + CopyAnimationFrameToShape (&dptr->ShapeAnimControlBlock->current, dptr); + } + } + } + + + ChooseLightingModel(dptr); + /* hierarchical object? */ + #if 0 + if (dptr->HModelControlBlock && !dptr->ObStrategyBlock) + { + DoHModel(dptr->HModelControlBlock,dptr); + return; + } + #endif + + + + /* Texture Animation Control */ + + if(dptr->ObTxAnimCtrlBlks) ControlTextureAnimation(dptr); + + /* Global Variables */ + Global_VDB_Ptr = VDB_Ptr; + Global_ODB_Ptr = dptr; + Global_ShapeHeaderPtr = shapeheaderptr; + + /* Shape Language Specific Setup */ + SetupShapePipeline(); + + /* + + Create the Local -> View Matrix + + LToVMat = VDB_Mat * ObMat + + "Get the points into View Space, then apply the Local Transformation" + + */ + + MatrixMultiply(&VDB_Ptr->VDB_Mat, &dptr->ObMat, <oVMat); + MatrixToEuler(<oVMat, <oVMat_Euler); + + /* + + Create the World -> Local Matrix + + WToLMat = Transposed Local Matrix + + */ + + CopyMatrix(&dptr->ObMat, &WToLMat); + TransposeMatrixCH(&WToLMat); + + + /* + + Transform the View World Location to Local Space + + -> Make the View Loc. relative to the Object View Space Centre + -> Rotate this vector using WToLMat + + */ + + + MakeVector(&VDB_Ptr->VDB_World, &dptr->ObWorld, &LocalView); + RotateVector(&LocalView, &WToLMat); + + #if 0 + { + LocalCameraZAxis.vx = - dptr->ObWorld.vx; + LocalCameraZAxis.vy = - dptr->ObWorld.vy; + LocalCameraZAxis.vz = - dptr->ObWorld.vz; + + RotateVector(&LocalCameraZAxis, &WToLMat); + } + #endif + + NumberOfHeatSources=0; + if (dptr->HModelControlBlock) + { + ObjectCentre = dptr->ObView; + + if (dptr->ObStrategyBlock) + { + HierarchicalObjectsLowestYValue = dptr->ObStrategyBlock->DynPtr->ObjectVertices[0].vy; + if (CurrentVisionMode == VISION_MODE_NORMAL && AvP.PlayerType==I_Alien) + { + DoAlienEnergyView(dptr); + } + /* + else if (CurrentVisionMode == VISION_MODE_PRED_SEEALIENS && dptr->ObStrategyBlock->I_SBtype == I_BehaviourAlien) + { + DoAlienEnergyView(dptr); + } + */ + } + + if (CurrentVisionMode == VISION_MODE_PRED_THERMAL) + { + FindHeatSourcesInHModel(dptr); + } + DoHModel(dptr->HModelControlBlock,dptr); + return; + } + // return; + + + /* Find out which light sources are in range of of the object */ + LightSourcesInRangeOfObject(dptr); + + /* Shape Language Execution Shell */ + { + SHAPEINSTR *shapeinstrptr = shapeheaderptr->sh_instruction; + + /* setup the rotated points array */ + switch (shapeinstrptr->sh_instr) + { + default: + case I_ShapePoints: + { + if(Global_ODB_Ptr->ObMorphCtrl) + { + MorphPoints(shapeinstrptr); + } + else + { + TranslateShapeVertices(shapeinstrptr); + } + break; + } + } + } + /* call polygon pipeline */ + ShapePipeline(shapeheaderptr); + /* call sfx code */ + HandleSfxForObject(dptr); + if (dptr->ObStrategyBlock) + { + if (dptr->ObStrategyBlock->I_SBtype==I_BehaviourInanimateObject) + { + INANIMATEOBJECT_STATUSBLOCK* objStatPtr = dptr->ObStrategyBlock->SBdataptr; + if(objStatPtr->typeId==IOT_FieldCharge) + { + + int i; + D3D_DecalSystem_Setup(); + for(i=0; i<63; i++) + { + PARTICLE particle; + + particle.Position.vy = -280+i-GetCos((CloakingPhase/16*i + i*64+particle.Position.vz)&4095)/1024; + + particle.Position.vx = GetCos((CloakingPhase +i*64+particle.Position.vy)&4095)/512; + particle.Position.vz = GetSin((CloakingPhase +i*64+particle.Position.vy)&4095)/512; + RotateVector(&particle.Position,&dptr->ObMat); + particle.Position.vx += dptr->ObWorld.vx; + particle.Position.vy += dptr->ObWorld.vy; + particle.Position.vz += dptr->ObWorld.vz; + + particle.ParticleID=PARTICLE_MUZZLEFLASH; + particle.Colour = 0xff00007f+(FastRandom()&0x7f7f7f); + particle.Size = 40; + RenderParticle(&particle); + } + D3D_DecalSystem_End(); + + } + + } + } +} +void DoAlienEnergyView(DISPLAYBLOCK *dispPtr) +{ + HMODELCONTROLLER *controllerPtr = dispPtr->HModelControlBlock; + unsigned int colour = MARINES_LIFEFORCE_GLOW_COLOUR; + + LOCALASSERT(controllerPtr); + + + + /* KJL 16:36:25 10/02/98 - process model */ + { + STRATEGYBLOCK *sbPtr = Global_ODB_Ptr->ObStrategyBlock; + if(sbPtr) + { + switch (sbPtr->I_SBtype) + { + case I_BehaviourAlien: + { + colour = ALIENS_LIFEFORCE_GLOW_COLOUR; + break; + } + case I_BehaviourPredator: + { + colour = PREDATORS_LIFEFORCE_GLOW_COLOUR; + break; + } + case I_BehaviourMarine: + case I_BehaviourSeal: + { + MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + GLOBALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) + { + return; + } + colour = MARINES_LIFEFORCE_GLOW_COLOUR; + } + + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)Global_ODB_Ptr->ObStrategyBlock->SBdataptr; + + if (ghostDataPtr->type==I_BehaviourAlienPlayer || ghostDataPtr->type==I_BehaviourAlien + || (ghostDataPtr->type==I_BehaviourNetCorpse&&ghostDataPtr->subtype==I_BehaviourAlienPlayer) ) + { + colour = ALIENS_LIFEFORCE_GLOW_COLOUR; + } + else if (ghostDataPtr->type==I_BehaviourPredatorPlayer || ghostDataPtr->type==I_BehaviourPredator + || (ghostDataPtr->type==I_BehaviourNetCorpse&&ghostDataPtr->subtype==I_BehaviourPredatorPlayer) ) + { + colour = PREDATORS_LIFEFORCE_GLOW_COLOUR; + } + + break; + } + + case I_BehaviourNetCorpse: + { + NETCORPSEDATABLOCK *corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + + if (corpseDataPtr->Android) + { + return; + } + + if (corpseDataPtr->Type==I_BehaviourAlienPlayer || corpseDataPtr->Type==I_BehaviourAlien) + { + colour = ALIENS_LIFEFORCE_GLOW_COLOUR; + } + else if (corpseDataPtr->Type==I_BehaviourPredatorPlayer || corpseDataPtr->Type==I_BehaviourPredator) + { + colour = PREDATORS_LIFEFORCE_GLOW_COLOUR; + } + break; + } + case I_BehaviourHierarchicalFragment: + { + HDEBRIS_BEHAV_BLOCK *debrisDataPtr = (HDEBRIS_BEHAV_BLOCK *)sbPtr->SBdataptr; + if(debrisDataPtr->Type==I_BehaviourAutoGun || debrisDataPtr->Android) + { + return; + } + else if(debrisDataPtr->Type==I_BehaviourAlien) + { + colour = ALIENS_LIFEFORCE_GLOW_COLOUR; + } + else if (debrisDataPtr->Type==I_BehaviourPredator) + { + colour = PREDATORS_LIFEFORCE_GLOW_COLOUR; + } + else if ((debrisDataPtr->Type==I_BehaviourMarine)||(debrisDataPtr->Type==I_BehaviourSeal)) + { + colour = MARINES_LIFEFORCE_GLOW_COLOUR; + } + else return; + break; + } + + case I_BehaviourAutoGun: + { + /* KJL 19:31:53 25/01/99 - organics only, please */ + return; + break; + } + default: + break; + } + } + } + if( (Global_ODB_Ptr->SpecialFXFlags & SFXFLAG_MELTINGINTOGROUND) + &&(Global_ODB_Ptr->ObFlags2 < ONE_FIXED) ) + { + unsigned int alpha = MUL_FIXED(Global_ODB_Ptr->ObFlags2,colour >> 24); + colour = (colour&0xffffff)+(alpha<<24); + } + + /* KJL 16:36:12 10/02/98 - check positions are up to date */ + ProveHModel(controllerPtr,dispPtr); + + D3D_DecalSystem_Setup(); + + FindAlienEnergySource_Recursion(controllerPtr,controllerPtr->section_data,colour); + + D3D_DecalSystem_End(); +} + +static void FindAlienEnergySource_Recursion(HMODELCONTROLLER *controllerPtr, SECTION_DATA *sectionDataPtr, unsigned int colour) +{ + /* KJL 16:29:40 10/02/98 - Recurse through hmodel */ + if ((sectionDataPtr->First_Child!=NULL)&&(!(sectionDataPtr->flags§ion_data_terminate_here))) + { + SECTION_DATA *childSectionPtr = sectionDataPtr->First_Child; + + while (childSectionPtr!=NULL) + { + LOCALASSERT(childSectionPtr->My_Parent==sectionDataPtr); + + FindAlienEnergySource_Recursion(controllerPtr,childSectionPtr,colour); + childSectionPtr=childSectionPtr->Next_Sibling; + } + } + if(sectionDataPtr->Shape && sectionDataPtr->Shape->shaperadius>LocalDetailLevels.AlienEnergyViewThreshold) + { + PARTICLE particle; + + particle.Position = sectionDataPtr->World_Offset; + particle.ParticleID=PARTICLE_MUZZLEFLASH; + particle.Colour = colour;//0x208080ff; +// particle.Colour = 0x20ff8080; +// particle.Size = sectionDataPtr->Shape->shaperadius*3; +// particle.Colour = 0x20ffffff; + particle.Size = sectionDataPtr->Shape->shaperadius*2; + RenderParticle(&particle); + } +} + +void AddHierarchicalShape(DISPLAYBLOCK *dptr, VIEWDESCRIPTORBLOCK *VDB_Ptr) +{ + + SHAPEHEADER *shapeheaderptr; + SHAPEINSTR *shapeinstrptr; + + GLOBALASSERT(!dptr->HModelControlBlock); + if(!ObjectWithinFrustrum(dptr)) return; + + + #if 0 + shapeheaderptr = GetShapeData(dptr->ObShape); + + /* It is important to pass this SHAPEHEADER* on to the display block */ + + dptr->ObShapeData = shapeheaderptr; + #else + shapeheaderptr = dptr->ObShapeData; + #endif + + + /* Texture Animation Control */ + if(dptr->ObTxAnimCtrlBlks) ControlTextureAnimation(dptr); + + /* Global Variables */ + Global_VDB_Ptr = VDB_Ptr; + Global_ODB_Ptr = dptr; + Global_ShapeHeaderPtr = shapeheaderptr; + +// if((Global_ODB_Ptr->ObStrategyBlock)&&(Global_ODB_Ptr->ObStrategyBlock->I_SBtype == I_BehaviourAlien)) + // textprint("hier alien part\n"); + + /* Shape Language Specific Setup */ + SetupShapePipeline(); + + /* + + Create the Local -> View Matrix + + LToVMat = VDB_Mat * ObMat + + "Get the points into View Space, then apply the Local Transformation" + + */ + + MatrixMultiply(&VDB_Ptr->VDB_Mat, &dptr->ObMat, <oVMat); + MatrixToEuler(<oVMat, <oVMat_Euler); + + /* + + Create the World -> Local Matrix + + WToLMat = Transposed Local Matrix + + */ + + CopyMatrix(&dptr->ObMat, &WToLMat); + TransposeMatrixCH(&WToLMat); + + + /* + + Transform the View World Location to Local Space + + -> Make the View Loc. relative to the Object View Space Centre + -> Rotate this vector using WToLMat + + */ + + + MakeVector(&VDB_Ptr->VDB_World, &dptr->ObWorld, &LocalView); + RotateVector(&LocalView, &WToLMat); + + if (!(PIPECLEANER_CHEATMODE||BALLSOFFIRE_CHEATMODE) || !dptr->ObStrategyBlock) + { + /* Find out which light sources are in range of of the object */ + LightSourcesInRangeOfObject(dptr); + + /* Shape Language Execution Shell */ + shapeinstrptr = shapeheaderptr->sh_instruction; + + /* setup the rotated points array */ + if( (dptr->SpecialFXFlags & SFXFLAG_MELTINGINTOGROUND) + &&(dptr->ObFlags2 <= ONE_FIXED) ) + { + SquishPoints(shapeinstrptr); + } + else + { + TranslateShapeVertices(shapeinstrptr); + } + + /* call polygon pipeline */ + ShapePipeline(shapeheaderptr); + } + + if (BALLSOFFIRE_CHEATMODE && dptr->ObStrategyBlock) + { + HandleObjectOnFire(dptr); + } + + /* call sfx code */ + HandleSfxForObject(dptr); + +} + + +float ViewMatrix[12]; +float ObjectViewMatrix[12]; +float Source[3]; +float Dest[3]; + +extern void TranslationSetup(void) +{ + VECTORCH v = Global_VDB_Ptr->VDB_World; + extern int PredatorVisionChangeCounter; + float p = PredatorVisionChangeCounter/65536.0f; + float o = 1.0f; + p = 1.0f+p; + + if (NAUSEA_CHEATMODE) + { + p = (GetSin((CloakingPhase/3)&4095))/65536.0f; + p = 1.0f + p*p; + + o = (GetCos((CloakingPhase/5)&4095))/65536.0f; + o = 1.0f + o*o; + } + + #if 1 + ViewMatrix[0+0*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat11)/65536.0f*o; + ViewMatrix[1+0*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat21)/65536.0f*o; + ViewMatrix[2+0*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat31)/65536.0f*o; + #else + ViewMatrix[0+0*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat11)/65536.0f; + ViewMatrix[1+0*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat21)/65536.0f; + ViewMatrix[2+0*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat31)/65536.0f; + #endif + + #if 1 + ViewMatrix[0+1*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat12)*4.0f/(65536.0f*3.0f)*p; + ViewMatrix[1+1*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat22)*4.0f/(65536.0f*3.0f)*p; + ViewMatrix[2+1*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat32)*4.0f/(65536.0f*3.0f)*p; + #else + ViewMatrix[0+1*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat12)/(65536.0f); + ViewMatrix[1+1*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat22)/(65536.0f); + ViewMatrix[2+1*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat32)/(65536.0f); + #endif + ViewMatrix[0+2*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat13)/65536.0f*CameraZoomScale; + ViewMatrix[1+2*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat23)/65536.0f*CameraZoomScale; + ViewMatrix[2+2*4] = (float)(Global_VDB_Ptr->VDB_Mat.mat33)/65536.0f*CameraZoomScale; + + RotateVector(&v,&Global_VDB_Ptr->VDB_Mat); + + ViewMatrix[3+0*4] = ((float)-v.vx)*o; + ViewMatrix[3+1*4] = ((float)-v.vy)*4.0f/3.0f*p; + ViewMatrix[3+2*4] = ((float)-v.vz)*CameraZoomScale; + + if (MIRROR_CHEATMODE) + { + ViewMatrix[0+0*4] = -ViewMatrix[0+0*4]; + ViewMatrix[1+0*4] = -ViewMatrix[1+0*4]; + ViewMatrix[2+0*4] = -ViewMatrix[2+0*4]; + + ViewMatrix[3+0*4] = -ViewMatrix[3+0*4]; + } +} + + +#ifndef _MSC_VER +void TranslatePoint(int *source, int *dest, int *matrix); +#pragma aux TranslatePoint = \ +"fld DWORD PTR [esi]"\ +"fmul DWORD PTR [edi]"\ +"fld DWORD PTR [esi+4]"\ +"fmul DWORD PTR [edi+4]"\ +"fld DWORD PTR [esi+8]"\ +"fmul DWORD PTR [edi+8]"\ +"fxch st(1)"\ +"faddp st(2),st"\ +"fld DWORD PTR [esi]"\ +"fmul DWORD PTR [edi+16]"\ +"fxch st(1)"\ +"faddp st(2),st"\ +"fld DWORD PTR [esi+4]"\ +"fmul DWORD PTR [edi+20]"\ +"fld DWORD PTR [esi+8]"\ +"fmul DWORD PTR [edi+24]"\ +"fxch st(1)"\ +"faddp st(2),st"\ +"fld DWORD PTR [esi]"\ +"fmul DWORD PTR [edi+32]"\ +"fxch st(1)"\ +"faddp st(2),st"\ +"fld DWORD PTR [esi+4]"\ +"fmul DWORD PTR [edi+36]"\ +"fld DWORD PTR [esi+8]"\ +"fmul DWORD PTR [edi+40]"\ +"fxch st(1)"\ +"faddp st(2),st"\ +"fxch st(3)"\ +"fadd DWORD PTR [edi+12]"\ +"fxch st(1)"\ +"faddp st(3),st"\ +"fxch st(1)"\ +"fadd DWORD PTR [edi+28]"\ +"fxch st(2)"\ +"fadd DWORD PTR [edi+44]"\ +"fxch st(1)"\ +"fstp DWORD PTR [ebx]"\ +"fxch st(1)"\ +"fstp DWORD PTR [ebx+4]"\ +"fstp DWORD PTR [ebx+8]"\ +parm[esi] [ebx] [edi]; + +#else +void TranslatePoint(int *source, int *dest, int *matrix) +{ + __asm + { + mov esi,source + mov ebx,dest + mov edi,matrix + fld DWORD PTR [esi] + fmul DWORD PTR [edi] + fld DWORD PTR [esi+4] + fmul DWORD PTR [edi+4] + fld DWORD PTR [esi+8] + fmul DWORD PTR [edi+8] + fxch st(1) + faddp st(2),st + fld DWORD PTR [esi] + fmul DWORD PTR [edi+16] + fxch st(1) + faddp st(2),st + fld DWORD PTR [esi+4] + fmul DWORD PTR [edi+20] + fld DWORD PTR [esi+8] + fmul DWORD PTR [edi+24] + fxch st(1) + faddp st(2),st + fld DWORD PTR [esi] + fmul DWORD PTR [edi+32] + fxch st(1) + faddp st(2),st + fld DWORD PTR [esi+4] + fmul DWORD PTR [edi+36] + fld DWORD PTR [esi+8] + fmul DWORD PTR [edi+40] + fxch st(1) + faddp st(2),st + fxch st(3) + fadd DWORD PTR [edi+12] + fxch st(1) + faddp st(3),st + fxch st(1) + fadd DWORD PTR [edi+28] + fxch st(2) + fadd DWORD PTR [edi+44] + fxch st(1) + fstp DWORD PTR [ebx] + fxch st(1) + fstp DWORD PTR [ebx+4] + fstp DWORD PTR [ebx+8] + } +} + +#endif + +void TranslatePointIntoViewspace(VECTORCH *pointPtr) +{ + + Source[0] = pointPtr->vx; + Source[1] = pointPtr->vy; + Source[2] = pointPtr->vz; + + TranslatePoint((int*)&Source,(int*)&Dest,(int*)&ViewMatrix); + + f2i(pointPtr->vx,Dest[0]); + f2i(pointPtr->vy,Dest[1]); + f2i(pointPtr->vz,Dest[2]); +} +void SquishPoints(SHAPEINSTR *shapeinstrptr) +{ + int **shapeitemarrayptr = shapeinstrptr->sh_instr_data; + VECTORCH *shapePts = (VECTORCH*)*shapeitemarrayptr; + { + int i; + int scale = Global_ODB_Ptr->ObFlags2; + + for (i=0; inumpoints; i++) + { + VECTORCH point = shapePts[i]; + + RotateVector(&point,&Global_ODB_Ptr->ObMat); + + point.vx = MUL_FIXED(point.vx,ONE_FIXED*3/2 - scale/2); + point.vx += Global_ODB_Ptr->ObWorld.vx; + + point.vz = MUL_FIXED(point.vz,ONE_FIXED*3/2 - scale/2); + point.vz += Global_ODB_Ptr->ObWorld.vz; + + point.vy += Global_ODB_Ptr->ObWorld.vy; + point.vy = HierarchicalObjectsLowestYValue + MUL_FIXED(point.vy-HierarchicalObjectsLowestYValue, scale); + + Source[0] = point.vx; + Source[1] = point.vy; + Source[2] = point.vz; + + TranslatePoint((int*)&Source,(int*)&Dest,(int*)&ViewMatrix); + + f2i(RotatedPts[i].vx,Dest[0]); + f2i(RotatedPts[i].vy,Dest[1]); + f2i(RotatedPts[i].vz,Dest[2]); + } + } +} + +void MorphPoints(SHAPEINSTR *shapeinstrptr) +{ + VECTORCH *srcPtr; + { + SHAPEHEADER *shape1Ptr; + VECTORCH *shape1PointsPtr; + VECTORCH *shape2PointsPtr; + + /* Set up the morph data */ + GetMorphDisplay(&MorphDisplay, Global_ODB_Ptr); + + shape1Ptr = MorphDisplay.md_sptr1; + + if(MorphDisplay.md_lerp == 0x0000) + { + + srcPtr = (VECTORCH *)*shape1Ptr->points; + } + else if(MorphDisplay.md_lerp == 0xffff) + { + SHAPEHEADER *shape2Ptr; + shape2Ptr = MorphDisplay.md_sptr2; + + srcPtr = (VECTORCH *)*shape2Ptr->points; + Global_ShapePoints = *(shape2Ptr->points); + + } + else + { + SHAPEHEADER *shape2Ptr; + shape2Ptr = MorphDisplay.md_sptr2; + + shape1PointsPtr = (VECTORCH *)(*shape1Ptr->points); + shape2PointsPtr = (VECTORCH *)(*shape2Ptr->points); + + { + int numberOfPoints = shape1Ptr->numpoints; + VECTORCH *morphedPointsPtr = (VECTORCH *) MorphedPts; + + while(numberOfPoints--) + { + VECTORCH vertex1 = *shape1PointsPtr; + VECTORCH vertex2 = *shape2PointsPtr; + + if( (vertex1.vx == vertex2.vx && vertex1.vy == vertex2.vy && vertex1.vz == vertex2.vz) ) + { + *morphedPointsPtr = vertex1; + } + else + { + /* KJL 15:27:20 05/22/97 - I've changed this to speed things up, If a vertex + component has a magnitude greater than 32768 things will go wrong. */ + morphedPointsPtr->vx = vertex1.vx + (((vertex2.vx-vertex1.vx)*MorphDisplay.md_lerp)>>16); + morphedPointsPtr->vy = vertex1.vy + (((vertex2.vy-vertex1.vy)*MorphDisplay.md_lerp)>>16); + morphedPointsPtr->vz = vertex1.vz + (((vertex2.vz-vertex1.vz)*MorphDisplay.md_lerp)>>16); + } + + shape1PointsPtr++; + shape2PointsPtr++; + morphedPointsPtr++; + } + } + + Global_ShapePoints = (int*)MorphedPts; + srcPtr = (VECTORCH *)MorphedPts; + } + } + { + VECTORCH *destPtr = RotatedPts; + int i; + for(i = shapeinstrptr->sh_numitems; i!=0; i--) + { + Source[0] = srcPtr->vx+Global_ODB_Ptr->ObWorld.vx; + Source[1] = srcPtr->vy+Global_ODB_Ptr->ObWorld.vy; + Source[2] = srcPtr->vz+Global_ODB_Ptr->ObWorld.vz; + + TranslatePoint((int*)&Source,(int*)&Dest,(int*)&ViewMatrix); + + f2i(destPtr->vx,Dest[0]); + f2i(destPtr->vy,Dest[1]); + f2i(destPtr->vz,Dest[2]); + srcPtr++; + destPtr++; + } + } + +} + +void TranslateShapeVertices(SHAPEINSTR *shapeinstrptr) +{ + VECTORCH *destPtr = RotatedPts; + int **shapeitemarrayptr; + VECTORCH *srcPtr; + int i; +// MNormalise(<oVMat); + shapeitemarrayptr = shapeinstrptr->sh_instr_data; + srcPtr = (VECTORCH*)*shapeitemarrayptr; + if (Global_ODB_Ptr->ObFlags & ObFlag_ArbRot) + { + for(i = shapeinstrptr->sh_numitems; i!=0; i--) + { + destPtr->vx = (srcPtr->vx+Global_ODB_Ptr->ObView.vx); + destPtr->vy = ((srcPtr->vy+Global_ODB_Ptr->ObView.vy)*4)/3; + destPtr->vz = (srcPtr->vz+Global_ODB_Ptr->ObView.vz); + + srcPtr++; + destPtr++; + + } + } + else + { + ObjectViewMatrix[0+0*4] = (float)(Global_ODB_Ptr->ObMat.mat11)/65536.0f; + ObjectViewMatrix[1+0*4] = (float)(Global_ODB_Ptr->ObMat.mat21)/65536.0f; + ObjectViewMatrix[2+0*4] = (float)(Global_ODB_Ptr->ObMat.mat31)/65536.0f; + + ObjectViewMatrix[0+1*4] = (float)(Global_ODB_Ptr->ObMat.mat12)/(65536.0f); + ObjectViewMatrix[1+1*4] = (float)(Global_ODB_Ptr->ObMat.mat22)/(65536.0f); + ObjectViewMatrix[2+1*4] = (float)(Global_ODB_Ptr->ObMat.mat32)/(65536.0f); + + ObjectViewMatrix[0+2*4] = (float)(Global_ODB_Ptr->ObMat.mat13)/65536.0f; + ObjectViewMatrix[1+2*4] = (float)(Global_ODB_Ptr->ObMat.mat23)/65536.0f; + ObjectViewMatrix[2+2*4] = (float)(Global_ODB_Ptr->ObMat.mat33)/65536.0f; + + ObjectViewMatrix[3+0*4] = Global_ODB_Ptr->ObWorld.vx; + ObjectViewMatrix[3+1*4] = Global_ODB_Ptr->ObWorld.vy; + ObjectViewMatrix[3+2*4] = Global_ODB_Ptr->ObWorld.vz; + for(i = shapeinstrptr->sh_numitems; i!=0; i--) + { + Source[0] = srcPtr->vx; + Source[1] = srcPtr->vy; + Source[2] = srcPtr->vz; + + TranslatePoint((int*)&Source,(int*)&Dest,(int*)&ObjectViewMatrix); + TranslatePoint((int*)&Dest,(int*)&Source,(int*)&ViewMatrix); + + f2i(destPtr->vx,Source[0]); + f2i(destPtr->vy,Source[1]); + f2i(destPtr->vz,Source[2]); + srcPtr++; + destPtr++; + } + } +} + +void RenderDecal(DECAL *decalPtr) +{ + /* translate decal into view space */ + { + VECTORCH translatedPosition = decalPtr->Vertices[0]; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[0].X = translatedPosition.vx; + VerticesBuffer[0].Y = translatedPosition.vy; + VerticesBuffer[0].Z = translatedPosition.vz; + } + { + VECTORCH translatedPosition = decalPtr->Vertices[1]; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[1].X = translatedPosition.vx; + VerticesBuffer[1].Y = translatedPosition.vy; + VerticesBuffer[1].Z = translatedPosition.vz; + } + { + VECTORCH translatedPosition = decalPtr->Vertices[2]; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[2].X = translatedPosition.vx; + VerticesBuffer[2].Y = translatedPosition.vy; + VerticesBuffer[2].Z = translatedPosition.vz; + } + { + VECTORCH translatedPosition = decalPtr->Vertices[3]; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[3].X = translatedPosition.vx; + VerticesBuffer[3].Y = translatedPosition.vy; + VerticesBuffer[3].Z = translatedPosition.vz; + } + { + int outcode = DecalWithinFrustrum(decalPtr); + + if (outcode) + { + switch(decalPtr->DecalID) + { + default: + case DECAL_SCORCHED: + { + DecalPolygon_Construct(decalPtr); + + if (outcode!=2) + { + TexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_Decal_Output(decalPtr,RenderPolygon.Vertices); + + } + else D3D_Decal_Output(decalPtr,VerticesBuffer); + break; + } + } + } + } + #if MIRRORING_ON + if (MirroringActive) RenderMirroredDecal(decalPtr); + #endif +} +void RenderParticle(PARTICLE *particlePtr) +{ +// PARTICLE_DESC *particleDescPtr = &ParticleDescription[particlePtr->ParticleID]; + int particleSize = particlePtr->Size; + + { + VECTORCH translatedPosition = particlePtr->Position; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[0].X = translatedPosition.vx; + VerticesBuffer[3].X = translatedPosition.vx; + VerticesBuffer[0].Y = translatedPosition.vy; + VerticesBuffer[3].Y = translatedPosition.vy; + VerticesBuffer[0].Z = translatedPosition.vz; + VerticesBuffer[3].Z = translatedPosition.vz; + } + + if ((particlePtr->ParticleID == PARTICLE_EXPLOSIONFIRE) + ||(particlePtr->ParticleID == PARTICLE_RICOCHET_SPARK) + ||(particlePtr->ParticleID == PARTICLE_SPARK) + ||(particlePtr->ParticleID == PARTICLE_ORANGE_SPARK) + ||(particlePtr->ParticleID == PARTICLE_ORANGE_PLASMA) + ||(particlePtr->ParticleID == PARTICLE_ALIEN_BLOOD) + ||(particlePtr->ParticleID == PARTICLE_PREDATOR_BLOOD) + ||(particlePtr->ParticleID == PARTICLE_HUMAN_BLOOD) + ||(particlePtr->ParticleID == PARTICLE_WATERFALLSPRAY) + ||(particlePtr->ParticleID == PARTICLE_LASERBEAM) + ||(particlePtr->ParticleID == PARTICLE_PLASMABEAM) + ||(particlePtr->ParticleID == PARTICLE_TRACER) + ||(particlePtr->ParticleID == PARTICLE_PREDPISTOL_FLECHETTE) + ||(particlePtr->ParticleID == PARTICLE_PREDPISTOL_FLECHETTE_NONDAMAGING) + ) + { + VECTORCH translatedPosition = particlePtr->Offset; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[1].X = translatedPosition.vx; + VerticesBuffer[2].X = translatedPosition.vx; + VerticesBuffer[1].Y = translatedPosition.vy; + VerticesBuffer[2].Y = translatedPosition.vy; + VerticesBuffer[1].Z = translatedPosition.vz; + VerticesBuffer[2].Z = translatedPosition.vz; + + { + int deltaX = VerticesBuffer[1].X - VerticesBuffer[0].X; + int deltaY = VerticesBuffer[1].Y - VerticesBuffer[0].Y; + int splitY = 0; + + if (deltaX>=0) + { + if (deltaY>=0) + { + if (deltaX>deltaY) + { + splitY = 1; + } + } + else if (deltaX>-deltaY) + { + splitY = 1; + } + } + else + { + if (deltaY>=0) + { + if (-deltaX>deltaY) + { + splitY = 1; + } + } + else if (-deltaX>-deltaY) + { + splitY = 1; + } + } + if (splitY) + { + if (deltaX>0) + { + /* 1 & 2 are more +ve in X */ + VerticesBuffer[0].X -= particleSize; + VerticesBuffer[0].Y -= MUL_FIXED(particleSize,87381); + VerticesBuffer[1].X += particleSize; + VerticesBuffer[1].Y -= MUL_FIXED(particleSize,87381); + VerticesBuffer[2].X += particleSize; + VerticesBuffer[2].Y += MUL_FIXED(particleSize,87381); + VerticesBuffer[3].X -= particleSize; + VerticesBuffer[3].Y += MUL_FIXED(particleSize,87381); + } + else + { + /* 1 & 2 are more -ve in X */ + VerticesBuffer[0].X += particleSize; + VerticesBuffer[0].Y -= MUL_FIXED(particleSize,87381); + VerticesBuffer[1].X -= particleSize; + VerticesBuffer[1].Y -= MUL_FIXED(particleSize,87381); + VerticesBuffer[2].X -= particleSize; + VerticesBuffer[2].Y += MUL_FIXED(particleSize,87381); + VerticesBuffer[3].X += particleSize; + VerticesBuffer[3].Y += MUL_FIXED(particleSize,87381); + } + + } + else + { + if (deltaY>0) + { + /* 1 & 2 are more +ve in Y */ + VerticesBuffer[0].X -= particleSize; + VerticesBuffer[0].Y -= MUL_FIXED(particleSize,87381); + VerticesBuffer[1].X -= particleSize; + VerticesBuffer[1].Y += MUL_FIXED(particleSize,87381); + VerticesBuffer[2].X += particleSize; + VerticesBuffer[2].Y += MUL_FIXED(particleSize,87381); + VerticesBuffer[3].X += particleSize; + VerticesBuffer[3].Y -= MUL_FIXED(particleSize,87381); + } + else + { + /* 1 & 2 are more -ve in Y */ + VerticesBuffer[0].X -= particleSize; + VerticesBuffer[0].Y += MUL_FIXED(particleSize,87381); + VerticesBuffer[1].X -= particleSize; + VerticesBuffer[1].Y -= MUL_FIXED(particleSize,87381); + VerticesBuffer[2].X += particleSize; + VerticesBuffer[2].Y -= MUL_FIXED(particleSize,87381); + VerticesBuffer[3].X += particleSize; + VerticesBuffer[3].Y += MUL_FIXED(particleSize,87381); + } + + } + } + } + else + { + VECTOR2D offset[4]; + VerticesBuffer[1].X = VerticesBuffer[0].X; + VerticesBuffer[2].X = VerticesBuffer[0].X; + VerticesBuffer[1].Y = VerticesBuffer[0].Y; + VerticesBuffer[2].Y = VerticesBuffer[0].Y; + VerticesBuffer[1].Z = VerticesBuffer[0].Z; + VerticesBuffer[2].Z = VerticesBuffer[0].Z; + + offset[0].vx = -particleSize; + offset[0].vy = -particleSize; + + offset[1].vx = +particleSize; + offset[1].vy = -particleSize; + + offset[2].vx = +particleSize; + offset[2].vy = +particleSize; + + offset[3].vx = -particleSize; + offset[3].vy = +particleSize; + + if ((particlePtr->ParticleID == PARTICLE_MUZZLEFLASH) ) + { + extern void RotateVertex(VECTOR2D *vertexPtr, int theta); + int theta = FastRandom()&4095; + RotateVertex(&offset[0],theta); + RotateVertex(&offset[1],theta); + RotateVertex(&offset[2],theta); + RotateVertex(&offset[3],theta); + } + else if ((particlePtr->ParticleID == PARTICLE_SMOKECLOUD) + ||(particlePtr->ParticleID == PARTICLE_GUNMUZZLE_SMOKE) + ||(particlePtr->ParticleID == PARTICLE_PARGEN_FLAME) + ||(particlePtr->ParticleID == PARTICLE_FLAME)) + { + extern void RotateVertex(VECTOR2D *vertexPtr, int theta); + int theta = (particlePtr->Offset.vx+MUL_FIXED(CloakingPhase,particlePtr->Offset.vy))&4095; + RotateVertex(&offset[0],theta); + RotateVertex(&offset[1],theta); + RotateVertex(&offset[2],theta); + RotateVertex(&offset[3],theta); + } + VerticesBuffer[0].X += offset[0].vx; + VerticesBuffer[0].Y += MUL_FIXED(offset[0].vy,87381); + + VerticesBuffer[1].X += offset[1].vx; + VerticesBuffer[1].Y += MUL_FIXED(offset[1].vy,87381); + + VerticesBuffer[2].X += offset[2].vx; + VerticesBuffer[2].Y += MUL_FIXED(offset[2].vy,87381); + + VerticesBuffer[3].X += offset[3].vx; + VerticesBuffer[3].Y += MUL_FIXED(offset[3].vy,87381); + + } + + { + int outcode = QuadWithinFrustrum(); + + if (outcode) + { + ParticlePolygon_Construct(particlePtr); + + if (outcode!=2) + { + TexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_Particle_Output(particlePtr,RenderPolygon.Vertices); + + } + else D3D_Particle_Output(particlePtr,VerticesBuffer); + } + } +} + +extern void RenderFlechetteParticle(PARTICLE *particlePtr) +{ + VECTORCH vertices[5]; + MATRIXCH mat; + + MakeMatrixFromDirection(&particlePtr->Velocity,&mat); + + mat.mat11 >>= 12; + mat.mat12 >>= 12; + mat.mat13 >>= 12; + mat.mat21 >>= 12; + mat.mat22 >>= 12; + mat.mat23 >>= 12; + mat.mat31 >>= 9; + mat.mat32 >>= 9; + mat.mat33 >>= 9; + + + vertices[0].vx = particlePtr->Position.vx-mat.mat31+mat.mat11; + vertices[0].vy = particlePtr->Position.vy-mat.mat32+mat.mat12; + vertices[0].vz = particlePtr->Position.vz-mat.mat33+mat.mat13; + + vertices[1].vx = particlePtr->Position.vx-mat.mat31-mat.mat11; + vertices[1].vy = particlePtr->Position.vy-mat.mat32-mat.mat12; + vertices[1].vz = particlePtr->Position.vz-mat.mat33-mat.mat13; + + vertices[2] = particlePtr->Position; + + vertices[3].vx = particlePtr->Position.vx-mat.mat31+mat.mat21; + vertices[3].vy = particlePtr->Position.vy-mat.mat32+mat.mat22; + vertices[3].vz = particlePtr->Position.vz-mat.mat33+mat.mat23; + + vertices[4].vx = particlePtr->Position.vx-mat.mat31-mat.mat21; + vertices[4].vy = particlePtr->Position.vy-mat.mat32-mat.mat22; + vertices[4].vz = particlePtr->Position.vz-mat.mat33-mat.mat23; + + TranslatePointIntoViewspace(&vertices[0]); + TranslatePointIntoViewspace(&vertices[1]); + TranslatePointIntoViewspace(&vertices[2]); + TranslatePointIntoViewspace(&vertices[3]); + TranslatePointIntoViewspace(&vertices[4]); + + { + int i; + for (i=0; i<3; i++) + { + VerticesBuffer[i].X = vertices[i].vx; + VerticesBuffer[i].Y = vertices[i].vy; + VerticesBuffer[i].Z = vertices[i].vz; + + VerticesBuffer[i].A = (particlePtr->Colour>>24)&255; + VerticesBuffer[i].R = (particlePtr->Colour>>16)&255; + VerticesBuffer[i].G = (particlePtr->Colour>>8)&255; + VerticesBuffer[i].B = (particlePtr->Colour)&255; + } + RenderPolygon.NumberOfVertices=3; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + { + int outcode = TriangleWithinFrustrum(); + POLYHEADER fakeHeader; + fakeHeader.PolyFlags = iflag_transparent; + + do + { + if (outcode) + { + if (outcode!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,VerticesBuffer); + } + } + while(0); + } + { + int i; + for (i=0; i<3; i++) + { + VerticesBuffer[i].X = vertices[i+2].vx; + VerticesBuffer[i].Y = vertices[i+2].vy; + VerticesBuffer[i].Z = vertices[i+2].vz; + + VerticesBuffer[i].A = (particlePtr->Colour>>24)&255; + VerticesBuffer[i].R = (particlePtr->Colour>>16)&255; + VerticesBuffer[i].G = (particlePtr->Colour>>8)&255; + VerticesBuffer[i].B = (particlePtr->Colour)&255; + } + RenderPolygon.NumberOfVertices=3; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + { + int outcode = TriangleWithinFrustrum(); + POLYHEADER fakeHeader; + fakeHeader.PolyFlags = iflag_transparent; + + do + { + if (outcode) + { + if (outcode!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,VerticesBuffer); + } + } + while(0); + } + +} + +static void ParticlePolygon_Construct(PARTICLE *particlePtr) +{ + PARTICLE_DESC *particleDescPtr = &ParticleDescription[particlePtr->ParticleID]; + RenderPolygon.NumberOfVertices=4; + + VerticesBuffer[0].U = particleDescPtr->StartU; + VerticesBuffer[0].V = particleDescPtr->StartV; + + VerticesBuffer[1].U = particleDescPtr->EndU; + VerticesBuffer[1].V = particleDescPtr->StartV; + + VerticesBuffer[2].U = particleDescPtr->EndU; + VerticesBuffer[2].V = particleDescPtr->EndV; + + VerticesBuffer[3].U = particleDescPtr->StartU; + VerticesBuffer[3].V = particleDescPtr->EndV; + +} + +void RenderMirroredDecal(DECAL *decalPtr) +{ + /* translate decal into view space */ + { + VECTORCH translatedPosition = decalPtr->Vertices[0]; + translatedPosition.vx = MirroringAxis - translatedPosition.vx; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[0].X = translatedPosition.vx; + VerticesBuffer[0].Y = translatedPosition.vy; + VerticesBuffer[0].Z = translatedPosition.vz; + } + { + VECTORCH translatedPosition = decalPtr->Vertices[1]; + translatedPosition.vx = MirroringAxis - translatedPosition.vx; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[1].X = translatedPosition.vx; + VerticesBuffer[1].Y = translatedPosition.vy; + VerticesBuffer[1].Z = translatedPosition.vz; + } + { + VECTORCH translatedPosition = decalPtr->Vertices[2]; + translatedPosition.vx = MirroringAxis - translatedPosition.vx; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[2].X = translatedPosition.vx; + VerticesBuffer[2].Y = translatedPosition.vy; + VerticesBuffer[2].Z = translatedPosition.vz; + } + { + VECTORCH translatedPosition = decalPtr->Vertices[3]; + translatedPosition.vx = MirroringAxis - translatedPosition.vx; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[3].X = translatedPosition.vx; + VerticesBuffer[3].Y = translatedPosition.vy; + VerticesBuffer[3].Z = translatedPosition.vz; + } + { + int outcode = DecalWithinFrustrum(decalPtr); + + if (outcode) + { + switch(decalPtr->DecalID) + { + default: + case DECAL_SCORCHED: + { + DecalPolygon_Construct(decalPtr); + + if (outcode!=2) + { + TexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_Decal_Output(decalPtr,RenderPolygon.Vertices); + + } + else D3D_Decal_Output(decalPtr,VerticesBuffer); + break; + } + } + } + } +} + + +static void DecalPolygon_Construct(DECAL *decalPtr) +{ + DECAL_DESC *decalDescPtr = &DecalDescription[decalPtr->DecalID]; + RenderPolygon.NumberOfVertices=4; + + VerticesBuffer[0].U = decalDescPtr->StartU+decalPtr->UOffset; + VerticesBuffer[0].V = decalDescPtr->StartV; + + VerticesBuffer[1].U = decalDescPtr->EndU+decalPtr->UOffset; + VerticesBuffer[1].V = decalDescPtr->StartV; + + VerticesBuffer[2].U = decalDescPtr->EndU+decalPtr->UOffset; + VerticesBuffer[2].V = decalDescPtr->EndV; + + VerticesBuffer[3].U = decalDescPtr->StartU+decalPtr->UOffset; + VerticesBuffer[3].V = decalDescPtr->EndV; + +} + +#if 0 + int polys[][4] = + { + {1,3,5,7}, + {1,3,9,11}, + {2,3,5,4}, + {2,3,9,8}, + + {0,2,4,6}, + {0,2,8,10}, + {0,1,7,6}, + {0,1,11,10}, + + {12,13,15,14}, + {4,5,7,6}, + + {8,9,5,4}, + {6,7,11,10}, + {8,4,6,10}, + {5,9,11,7}, + +// {8,2,4,4}, +// {9,3,5,5}, +// {10,0,6,6}, +// {7,1,11,11} + }; + int alphaValue[]={64,64,64,64, 16,16,16,16, 0,0,0,0, 128,128,128,128}; + +//void RenderShaftOfLight(SHAFTOFLIGHT *shaftPtr) +void RenderShaftOfLight(MODULE *modulePtr) +{ + /* translate shaft into view space */ + +// suitable for invasion2 + VECTORCH shaftVertices[]= + { + {-5500,9000,9822}, + {-4500,9000,9822}, + {-5500,10000,9822}, + {-4500,10000,9822}, + + {-6000,15900,13000}, + {-4000,15900,13000}, + {-6000,15900,15500}, + {-4000,15900,15500}, + + {-6500,15900,12500}, + {-3500,15900,12500}, + {-6500,15900,16000}, + {-3500,15900,16000}, + }; + /* + VECTORCH shaftVertices[]= + { + {0, 0, 0}, + {0, 0, 1139}, + {-1338, 7113, 0}, + {-1338, 7113, 1139}, + + + {,1948,} + + {26002+ -1700, 7781 , -25328+ -800}, + {26002+ -900, 7781 , -25328+ +800}, + {26002+ 1700, 7781 , -25328+ -800}, + {26002+ 1700, 7781 , -25328+ +800}, + + {26002+ -1100, 7781 , -25328+ -1000}, + {26002+ -1100, 7781 , -25328+ +1000}, + {26002+ 2000, 7781 , -25328+ -1000}, + {26002+ 2000, 7781 , -25328+ +1000}, + + }; + */ + VECTORCH translatedPts[12]; + + POLYHEADER fakeHeader; + DECAL fakeDecal; + int polyNumber; + + fakeDecal.ModuleIndex=148; +// fakeDecal.ModuleIndex=17; + fakeHeader.PolyFlags = iflag_transparent; + + { + int i = 11; + do + { + translatedPts[i] = shaftVertices[i]; +// translatedPts[i].vx+=10712; +// translatedPts[i].vy+=-6480; +// translatedPts[i].vz+=-25898; + TranslatePointIntoViewspace(&translatedPts[i]); + } + while(i--); + } + + for(polyNumber=0; polyNumber<10; polyNumber++) + { + { + int i; + for (i=0; i<4; i++) + { + int v = polys[polyNumber][i]; + VerticesBuffer[i].A = alphaValue[v]; + if (v>11) + { + VerticesBuffer[i].X = translatedPts[v-12].vx; + VerticesBuffer[i].Y = translatedPts[v-12].vy; + VerticesBuffer[i].Z = translatedPts[v-12].vz; + } + else + { + VerticesBuffer[i].X = translatedPts[v].vx; + VerticesBuffer[i].Y = translatedPts[v].vy; + VerticesBuffer[i].Z = translatedPts[v].vz; + } + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 192; + } + RenderPolygon.NumberOfVertices=4; + } + { + int outcode = DecalWithinFrustrum(&fakeDecal); + + if (outcode) + { + if (outcode!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,VerticesBuffer); + } + } + } +} +#else + int polys[][4] = + { + {0,1,3,2}, + {2,3,5,4}, + {4,5,7,6}, + + {1,3,5,7}, + {0,2,4,6}, + {6,8,10,0}, + {7,9,11,1}, + + {0,1,11,10}, + {6,7,9,8}, + + + }; + int alphaValue[]={32,32,32,32, 28,28,28,28, 4,4,4,4, 128,128,128,128}; +// int alphaValue[]={16,16,16,16, 14,14,14,14, 2,2,2,2, 128,128,128,128}; + VECTORCH shaftVertices[]= + { + {0, 0, 0}, + {0, 0, 1956}, + {-1492, 7969, 0}, + {-1492, 7969, 1956}, + +// {0, 0, 0}, +// {0, 0, 1139}, +// {-1338, 7113, 0}, +// {-1338, 7113, 1139}, + + {0, 8840, 0}, + {0, 8840, 0}, + {3138, 8850, 0}, + {3138, 8850, 0}, + + {0, 14500, 0}, + {0, 14500, 0}, + {0, 14500, 0}, + {0, 14500, 0}, + + + }; + +void RenderShaftOfLight(MODULE *modulePtr) +{ + /* translate shaft into view space */ + #define NUM_OF_SHAFT_VERTICES 12 + VECTORCH translatedPts[NUM_OF_SHAFT_VERTICES]; + + POLYHEADER fakeHeader; + DECAL fakeDecal; + int polyNumber; + VECTORCH lightDirection1 = {29309,29309,-2000}; + VECTORCH lightDirection2 = {29309,29309,2000}; + +// return; + { + int offset = GetSin((CloakingPhase/16)&4095); + if (offset<0) offset=-offset; + offset = MUL_FIXED(offset,offset); + offset = MUL_FIXED(offset,offset); + offset=MUL_FIXED(offset,4000); + lightDirection1.vz += offset; + lightDirection2.vz += offset; + } + Normalise(&lightDirection1); + Normalise(&lightDirection2); +// textprint("light shaft active"); + fakeDecal.ModuleIndex=modulePtr->m_index; + fakeHeader.PolyFlags = iflag_transparent; + + + FindIntersectionWithYPlane(&shaftVertices[2],&lightDirection1,&shaftVertices[4]); + FindIntersectionWithYPlane(&shaftVertices[3],&lightDirection2,&shaftVertices[5]); + FindZFromXYIntersection(&shaftVertices[2],&lightDirection1,&shaftVertices[6]); + FindZFromXYIntersection(&shaftVertices[3],&lightDirection2,&shaftVertices[7]); + FindIntersectionWithYPlane(&shaftVertices[0],&lightDirection1,&shaftVertices[10]); + FindIntersectionWithYPlane(&shaftVertices[1],&lightDirection2,&shaftVertices[11]); + FindIntersectionWithYPlane(&shaftVertices[6],&lightDirection1,&shaftVertices[8]); + FindIntersectionWithYPlane(&shaftVertices[7],&lightDirection2,&shaftVertices[9]); + + { + + int i = NUM_OF_SHAFT_VERTICES-1; + do + { + translatedPts[i] = shaftVertices[i]; + translatedPts[i].vx+=11762; + translatedPts[i].vy+=-6919; + translatedPts[i].vz+=-26312; +// translatedPts[i].vx+=10712; +// translatedPts[i].vy+=-6480; +// translatedPts[i].vz+=-25898; + TranslatePointIntoViewspace(&translatedPts[i]); + } + while(i--); + } + + + for(polyNumber=0; polyNumber<9; polyNumber++) + { + { + int i; + for (i=0; i<4; i++) + { + int v = polys[polyNumber][i]; + VerticesBuffer[i].A = alphaValue[v]; + VerticesBuffer[i].X = translatedPts[v].vx; + VerticesBuffer[i].Y = translatedPts[v].vy; + VerticesBuffer[i].Z = translatedPts[v].vz; + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 192; + } + RenderPolygon.NumberOfVertices=4; + } + { + int outcode = DecalWithinFrustrum(&fakeDecal); + + if (outcode) + { + if (outcode!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,VerticesBuffer); + } + } + } + RenderShaftOfLight2(modulePtr); +} +void RenderShaftOfLight2(MODULE *modulePtr) +{ + /* translate shaft into view space */ + #define NUM_OF_SHAFT_VERTICES 12 + VECTORCH translatedPts[NUM_OF_SHAFT_VERTICES]; + + POLYHEADER fakeHeader; + DECAL fakeDecal; + int polyNumber; + VECTORCH lightDirection1 = {29309+1000,29309,-3000}; + VECTORCH lightDirection2 = {29309+1000,29309,3000}; + VECTORCH lightDirection3 = {29309-1000,29309,-3000}; + VECTORCH lightDirection4 = {29309-1000,29309,3000}; + { + int offset = GetSin((CloakingPhase/16)&4095); + if (offset<0) offset=-offset; + offset = MUL_FIXED(offset,offset); + offset = MUL_FIXED(offset,offset); + offset=MUL_FIXED(offset,4000); + lightDirection1.vz += offset; + lightDirection2.vz += offset; + lightDirection3.vz += offset; + lightDirection4.vz += offset; + } + Normalise(&lightDirection1); + Normalise(&lightDirection2); + Normalise(&lightDirection3); + Normalise(&lightDirection4); + + fakeDecal.ModuleIndex=modulePtr->m_index; + fakeHeader.PolyFlags = iflag_transparent; + + + FindIntersectionWithYPlane(&shaftVertices[2],&lightDirection1,&shaftVertices[4]); + FindIntersectionWithYPlane(&shaftVertices[3],&lightDirection2,&shaftVertices[5]); + FindZFromXYIntersection(&shaftVertices[2],&lightDirection3,&shaftVertices[6]); + FindZFromXYIntersection(&shaftVertices[3],&lightDirection4,&shaftVertices[7]); + FindIntersectionWithYPlane(&shaftVertices[0],&lightDirection1,&shaftVertices[10]); + FindIntersectionWithYPlane(&shaftVertices[1],&lightDirection2,&shaftVertices[11]); + FindIntersectionWithYPlane(&shaftVertices[6],&lightDirection3,&shaftVertices[8]); + FindIntersectionWithYPlane(&shaftVertices[7],&lightDirection4,&shaftVertices[9]); + + + { + + int i = NUM_OF_SHAFT_VERTICES-1; + do + { + translatedPts[i] = shaftVertices[i]; + translatedPts[i].vx+=11762; + translatedPts[i].vy+=-6919; + translatedPts[i].vz+=-26312; +// translatedPts[i].vx+=10712; +// translatedPts[i].vy+=-6480; +// translatedPts[i].vz+=-25898; + TranslatePointIntoViewspace(&translatedPts[i]); + } + while(i--); + } + + + for(polyNumber=0; polyNumber<9; polyNumber++) + { + { + int i; + for (i=0; i<4; i++) + { + int v = polys[polyNumber][i]; + VerticesBuffer[i].A = alphaValue[v]/2; + VerticesBuffer[i].X = translatedPts[v].vx; + VerticesBuffer[i].Y = translatedPts[v].vy; + VerticesBuffer[i].Z = translatedPts[v].vz; + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 192; + } + RenderPolygon.NumberOfVertices=4; + } + { + int outcode = DecalWithinFrustrum(&fakeDecal); + + if (outcode) + { + if (outcode!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,VerticesBuffer); + } + } + } +} + +void FindIntersectionWithYPlane(VECTORCH *startPtr, VECTORCH *directionPtr, VECTORCH *intersectionPtr) +{ + int lambda = DIV_FIXED(intersectionPtr->vy - startPtr->vy,directionPtr->vy); + + intersectionPtr->vx = startPtr->vx + MUL_FIXED(directionPtr->vx,lambda); + intersectionPtr->vz = startPtr->vz + MUL_FIXED(directionPtr->vz,lambda); +// textprint("%d %d %d\n",intersectionPtr->vx,intersectionPtr->vy,intersectionPtr->vz); +} +void FindZFromXYIntersection(VECTORCH *startPtr, VECTORCH *directionPtr, VECTORCH *intersectionPtr) +{ + float a = intersectionPtr->vx - startPtr->vx; + + a/=directionPtr->vx; + + intersectionPtr->vz = startPtr->vz + (directionPtr->vz*a); +// textprint("%d %d %d\n",intersectionPtr->vx,intersectionPtr->vy,intersectionPtr->vz); +} + +#endif + + + + + + + + + + + + +void ClearTranslucentPolyList(void) +{ + CurrentNumberOfTranslucentPolygons=0; +} + +void AddToTranslucentPolyList(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr) +{ + /* copy the data to the list for processing later */ + int i = RenderPolygon.NumberOfVertices; + int maxZ = 0; + RENDERVERTEX *vertexPtr = TranslucentPolygons[CurrentNumberOfTranslucentPolygons].Vertices; + + TranslucentPolygons[CurrentNumberOfTranslucentPolygons].NumberOfVertices = i; + + do + { + if (maxZZ) + maxZ = renderVerticesPtr->Z; + *vertexPtr++ = *renderVerticesPtr++; + } + while(--i); + TranslucentPolygons[CurrentNumberOfTranslucentPolygons].MaxZ = maxZ; + TranslucentPolygonHeaders[CurrentNumberOfTranslucentPolygons] = *inputPolyPtr; + + /* increment counter */ + CurrentNumberOfTranslucentPolygons++; + LOCALASSERT(CurrentNumberOfTranslucentPolygonsTranslucentPolygons[maxFound].MaxZ) + { + maxFound = k; + } + } + + RenderAllParticlesFurtherAwayThan(TranslucentPolygons[maxFound].MaxZ); + + RenderPolygon.NumberOfVertices = TranslucentPolygons[maxFound].NumberOfVertices; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + D3D_ZBufferedGouraudTexturedPolygon_Output(&TranslucentPolygonHeaders[maxFound],TranslucentPolygons[maxFound].Vertices); + TranslucentPolygons[maxFound].MaxZ=0; + } + + RenderAllParticlesFurtherAwayThan(-0x7fffffff); + +} + + + + +#if 0 +int CuboidPolyVertexList[][4] = +{ + {0,1,2,3}, //+ve x + {0,3,7,4}, //+ve y + {6,7,3,2}, //+ve z + + {6,7,4,5}, //-ve x + {6,5,1,2}, //-ve y + {0,1,5,4}, //-ve z +}; +EULER CubeOrient = {0,0,0}; +void CubeOMatic(void) +{ + #define CUBESCALE 128 + VECTORCH vertices[8]= + { + {+CUBESCALE,+CUBESCALE,-CUBESCALE}, + {+CUBESCALE,-CUBESCALE,-CUBESCALE}, + {+CUBESCALE,-CUBESCALE,+CUBESCALE}, + {+CUBESCALE,+CUBESCALE,+CUBESCALE}, + {-CUBESCALE,+CUBESCALE,-CUBESCALE}, + {-CUBESCALE,-CUBESCALE,-CUBESCALE}, + {-CUBESCALE,-CUBESCALE,+CUBESCALE}, + {-CUBESCALE,+CUBESCALE,+CUBESCALE}, + }; + VECTORCH translatedPts[8]; + + POLYHEADER fakeHeader; + int polyNumber; + MATRIXCH matrix; + CreateEulerMatrix(&CubeOrient,&matrix); + TransposeMatrixCH(&matrix); + + CubeOrient.EulerX += MUL_FIXED(NormalFrameTime,128*4); + CubeOrient.EulerX &=4095; + CubeOrient.EulerY += MUL_FIXED(NormalFrameTime,256*4); + CubeOrient.EulerY &=4095; + CubeOrient.EulerZ += MUL_FIXED(NormalFrameTime,128*4); + CubeOrient.EulerZ &=4095; + + fakeHeader.PolyFlags = iflag_transparent; + + { + + int i = 7; + do + { + translatedPts[i] = vertices[i]; + RotateVector(&translatedPts[i],&matrix); + translatedPts[i].vy = MUL_FIXED(translatedPts[i].vy,87381); + } + while(i--); + } + + + for(polyNumber=0; polyNumber<6; polyNumber++) + { + { + int i; + for (i=0; i<4; i++) + { + int v = CuboidPolyVertexList[polyNumber][i]; + VerticesBuffer[i].A = 128; + VerticesBuffer[i].X = translatedPts[v].vx-400; + VerticesBuffer[i].Y = translatedPts[v].vy+300; + VerticesBuffer[i].Z = translatedPts[v].vz+900; + VerticesBuffer[i].Y = MUL_FIXED(VerticesBuffer[i].Y,87381); + + { + int brightness = -(translatedPts[v].vz*2); + + if (brightness<0) brightness=0; + if (brightness>255) brightness=255; + VerticesBuffer[i].R = brightness; + } + VerticesBuffer[i].G = 0; + VerticesBuffer[i].B = 0; + } + RenderPolygon.NumberOfVertices=4; + } + { + int outcode = QuadWithinFrustrum(); + + if (outcode) + { + if (outcode!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,VerticesBuffer); + } + } + } +} +#endif +int CuboidPolyVertexList[][4] = +{ + {0,3,7,4}, //+ve y +#if 0 + {0,1,2,3}, //+ve x + {0,1,5,4}, //-ve z + + {6,7,4,5}, //-ve x + {6,7,3,2}, //+ve z +#else + {6,7,3,2}, //+ve z + {6,7,4,5}, //-ve x + + {0,1,5,4}, //-ve z + {0,1,2,3}, //+ve x +#endif +}; +EULER CubeOrient = {0,0,0}; +int CuboidPolyVertexU[][4] = +{ + {1,1,1,1}, + + {127,127,0,0}, + {128,128,255,255}, + + {127,127,0,0}, + {128,128,255,255}, +}; +int CuboidPolyVertexV[][4] = +{ + {1,1,1,1}, + + {127,0,0,127}, + {127,0,0,127}, + {128,255,255,128}, + {128,255,255,128}, +}; + +#include "chnktexi.h" + +void CubeSky(void) +{ + #define CUBESCALE 1024 + VECTORCH vertices[8]= + { + #if 0 + {+CUBESCALE,-CUBESCALE,-CUBESCALE}, + {+CUBESCALE,CUBESCALE,-CUBESCALE}, + {+CUBESCALE,CUBESCALE,+CUBESCALE}, + {+CUBESCALE,-CUBESCALE,+CUBESCALE}, + {-CUBESCALE,-CUBESCALE,-CUBESCALE}, + {-CUBESCALE,CUBESCALE,-CUBESCALE}, + {-CUBESCALE,CUBESCALE,+CUBESCALE}, + {-CUBESCALE,-CUBESCALE,+CUBESCALE}, + #else + {+CUBESCALE,-CUBESCALE*2,-CUBESCALE}, + {+CUBESCALE,0,-CUBESCALE}, + {+CUBESCALE,0,+CUBESCALE}, + {+CUBESCALE,-CUBESCALE*2,+CUBESCALE}, + {-CUBESCALE,-CUBESCALE*2,-CUBESCALE}, + {-CUBESCALE,0,-CUBESCALE}, + {-CUBESCALE,0,+CUBESCALE}, + {-CUBESCALE,-CUBESCALE*2,+CUBESCALE}, + #endif + }; + VECTORCH translatedPts[8]; + + POLYHEADER fakeHeader; + int polyNumber; + + #if 1 + { + extern int BackdropImage; + fakeHeader.PolyFlags = 0; + fakeHeader.PolyColour =BackdropImage; + } + + { + + int i = 7; + do + { + translatedPts[i] = vertices[i]; + RotateVector(&translatedPts[i],&(Global_VDB_Ptr->VDB_Mat)); + translatedPts[i].vy = MUL_FIXED(translatedPts[i].vy,87381); + } + while(i--); + } + #endif + + for(polyNumber=0; polyNumber<5; polyNumber++) + { + { + int i; + for (i=0; i<4; i++) + { + int v = CuboidPolyVertexList[polyNumber][i]; + VerticesBuffer[i].A = 0; + VerticesBuffer[i].X = translatedPts[v].vx; + VerticesBuffer[i].Y = translatedPts[v].vy; + VerticesBuffer[i].Z = translatedPts[v].vz; + VerticesBuffer[i].U = CuboidPolyVertexU[polyNumber][i]<<16; + VerticesBuffer[i].V = CuboidPolyVertexV[polyNumber][i]<<16; + + + VerticesBuffer[i].R = 127; + VerticesBuffer[i].G = 127; + VerticesBuffer[i].B = 127; + } + RenderPolygon.NumberOfVertices=4; + } + { + int outcode = QuadWithinFrustrum(); + + if (outcode) + { + if (outcode!=2) + { + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_BackdropPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_BackdropPolygon_Output(&fakeHeader,VerticesBuffer); + } + } + } +} + + +void RenderMirrorSurface(void) +{ + VECTORCH translatedPts[4] = + { + {-5596,-932,-1872}, + {-5596,-932,-702}, + {-5596,1212,-702}, + {-5596,1212,-1872}, + + }; + int mirrorUV[]= + { 0,0, 127<<16,0, 127<<16,127<<16, 0,127<<16}; + POLYHEADER fakeHeader; + + + { + extern int CloudyImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = CloudyImageNumber; + } + + { + int i; + for (i=0; i<4; i++) + { + VerticesBuffer[i].A = 128; + + TranslatePointIntoViewspace(&translatedPts[i]); + VerticesBuffer[i].X = translatedPts[i].vx; + VerticesBuffer[i].Y = translatedPts[i].vy; + VerticesBuffer[i].Z = translatedPts[i].vz; + VerticesBuffer[i].U = mirrorUV[i*2]; + VerticesBuffer[i].V = mirrorUV[i*2+1]; + + + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 255; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + + } + RenderPolygon.NumberOfVertices=4; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_COLOUR; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); +} +void RenderMirrorSurface2(void) +{ + VECTORCH translatedPts[4] = + { + {-5596,-592,562}, + {-5596,-592,1344}, + {-5596,140,1344}, + {-5596,140,562}, + + }; + int mirrorUV[]= + { 0,0, 127<<16,0, 127<<16,127<<16, 0,127<<16}; + POLYHEADER fakeHeader; + + + { + extern int CloudyImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = CloudyImageNumber; + } + + { + int i; + for (i=0; i<4; i++) + { + VerticesBuffer[i].A = 128; + + TranslatePointIntoViewspace(&translatedPts[i]); + VerticesBuffer[i].X = translatedPts[i].vx; + VerticesBuffer[i].Y = translatedPts[i].vy; + VerticesBuffer[i].Z = translatedPts[i].vz; + VerticesBuffer[i].U = mirrorUV[i*2]; + VerticesBuffer[i].V = mirrorUV[i*2+1]; + + + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 255; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + + } + RenderPolygon.NumberOfVertices=4; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_COLOUR; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); +} +void RenderSmokeTest(void) +{ + int mirrorUV[]= + { + 64<<16, 0, + 64<<16, 31<<16, + 95<<16, 31<<16, + 95<<16, 0 + }; + POLYHEADER fakeHeader; + int a = GetSin(CloakingPhase&4095); + int image; + + a = MUL_FIXED(MUL_FIXED(a,a),255); + { + extern int SpecialFXImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = SpecialFXImageNumber; + } + + for (image = 0; image<=1; image++) + { + { + VECTORCH translatedPts[4] = + { + {45300,0+-1000, 26000+-1000}, + {45300,0+-1000, 26000+ 1000}, + {45300,0+ 1000, 26000+ 1000}, + {45300,0+ 1000, 26000+-1000}, + + }; + extern int CurrentLightAtPlayer; + int i; + + if (image) a = 255-a; + for (i=0; i<4; i++) + { + VerticesBuffer[i].A = a/2; + + TranslatePointIntoViewspace(&translatedPts[i]); + VerticesBuffer[i].X = translatedPts[i].vx; + VerticesBuffer[i].Y = translatedPts[i].vy; + VerticesBuffer[i].Z = translatedPts[i].vz; + VerticesBuffer[i].U = mirrorUV[i*2]; + VerticesBuffer[i].V = mirrorUV[i*2+1]+image*(32<<16); + + + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 255; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + + } + RenderPolygon.NumberOfVertices=4; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_GLOWING; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } +} +#if 1 +#define OCTAVES 3 +int u[OCTAVES]; +int v[OCTAVES]; +int du[OCTAVES]; +int dv[OCTAVES]; +int setup=0; + +int SkyColour_R=200; +int SkyColour_G=200; +int SkyColour_B=200; +void RenderSky(void) +{ + POLYHEADER fakeHeader; + int x,z,o; + if(!setup) + { + int i; + setup=1; + for(i=0;iVDB_World.vx*7)/8; + translatedPts[i].vz += 2048*z;//+(Global_VDB_Ptr->VDB_World.vz*7)/8; +// RotateVector(&translatedPts[i],&(Global_VDB_Ptr->VDB_Mat)); +// translatedPts[i].vy = MUL_FIXED(translatedPts[i].vy,87381); + translatedPts[i].vx += Global_VDB_Ptr->VDB_World.vx; + translatedPts[i].vy += Global_VDB_Ptr->VDB_World.vy; + translatedPts[i].vz += Global_VDB_Ptr->VDB_World.vz; + TranslatePointIntoViewspace(&translatedPts[i]); + VerticesBuffer[i].X = translatedPts[i].vx; + VerticesBuffer[i].Y = translatedPts[i].vy; + VerticesBuffer[i].Z = translatedPts[i].vz; + + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + VerticesBuffer[i].R = SkyColour_R; + VerticesBuffer[i].G = SkyColour_G; + VerticesBuffer[i].B = SkyColour_B; + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + VerticesBuffer[i].R = 0; + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 0; + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + VerticesBuffer[i].R = 0; + VerticesBuffer[i].G = 0; + VerticesBuffer[i].B = 255; + break; + } + } + + } + VerticesBuffer[0].U = (u[o]+size*x); + VerticesBuffer[0].V = (v[o]+size*z); + VerticesBuffer[1].U = (u[o]+size*x); + VerticesBuffer[1].V = (v[o]+size*(z+1)); + VerticesBuffer[2].U = (u[o]+size*(x+1)); + VerticesBuffer[2].V = (v[o]+size*(z+1)); + VerticesBuffer[3].U = (u[o]+size*(x+1)); + VerticesBuffer[3].V = (v[o]+size*z); + + + RenderPolygon.NumberOfVertices=4; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices>=3) + { + D3D_SkyPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + } + } + } + } + t/=2; + size*=2; + } + } + } +} +#endif +void RenderWaterFall(int xOrigin, int yOrigin, int zOrigin) +{ + int i,z; + VECTORCH v[4]; + + { + int waterfallX[9]; + int waterfallY[9]; + int waterfallZ[9]; + int waterfallZScale[9]; + for (i=0; i<9; i++) + { + + int u = (i*65536)/8; + + int b = MUL_FIXED(2*u,(65536-u)); + int c = MUL_FIXED(u,u); + int y3 = (4742-yOrigin); + int x3 = 2000; + int y2 = 2000; + int x2 = 1500; + + waterfallX[i] = MUL_FIXED(b,x2)+MUL_FIXED(c,x3); + waterfallY[i] = yOrigin+MUL_FIXED(b,y2)+MUL_FIXED(c,y3); + waterfallZ[i] = zOrigin+MUL_FIXED((66572-zOrigin),u); + waterfallZScale[i] = ONE_FIXED+b/2-c; + if (i!=8) + { + waterfallZScale[i]+=(FastRandom()&8191); + waterfallY[i]-=(FastRandom()&127); + } + + } + for (z=0; z<8; z++) + for (i=0; i<8; i++) + { + v[0].vx = xOrigin+MUL_FIXED(waterfallX[i],waterfallZScale[z]); + v[1].vx = xOrigin+MUL_FIXED(waterfallX[i],waterfallZScale[z+1]); + v[2].vx = xOrigin+MUL_FIXED(waterfallX[i+1],waterfallZScale[z+1]); + v[3].vx = xOrigin+MUL_FIXED(waterfallX[i+1],waterfallZScale[z]); + v[0].vy = waterfallY[i]; + v[1].vy = waterfallY[i]; + v[2].vy = waterfallY[i+1]; + v[3].vy = waterfallY[i+1]; + + + v[0].vz = waterfallZ[z]; + v[1].vz = waterfallZ[z+1]; + v[2].vz = v[1].vz; + v[3].vz = v[0].vz; + + DrawWaterFallPoly(v); + } + for (z=0; z<3; z++) + { + v[0].vx = xOrigin+MUL_FIXED(waterfallX[8],waterfallZScale[z+1]); + v[1].vx = xOrigin+MUL_FIXED(waterfallX[8],waterfallZScale[z]); + v[2].vx = 179450; + v[3].vx = 179450; + + v[0].vy = 4742; + v[1].vy = 4742; + v[2].vy = 4742; + v[3].vy = 4742; + + v[0].vz = waterfallZ[z]; + v[1].vz = waterfallZ[z+1]; + v[2].vz = v[1].vz; + v[3].vz = v[0].vz; + + DrawWaterFallPoly(v); + } + + for (z=0; z<8; z++) + for (i=0; i<16; i++) + { + int xOffset,xOffset2; + if (z<3) xOffset = 179450; + else xOffset = xOrigin+MUL_FIXED(waterfallX[8],waterfallZScale[z]); + if (z<2) xOffset2 = 179450; + else xOffset2 = xOrigin+MUL_FIXED(waterfallX[8],waterfallZScale[z+1]); + + v[0].vx = xOffset; + v[1].vx = xOffset2; + v[2].vx = xOffset2; + v[3].vx = xOffset; + + v[0].vy = 4742+i*4096; + v[1].vy = 4742+i*4096; + v[2].vy = 4742+(i+1)*4096; + v[3].vy = 4742+(i+1)*4096; + + + v[0].vz = waterfallZ[z]; + v[1].vz = waterfallZ[z+1]; + v[2].vz = v[1].vz; + v[3].vz = v[0].vz; + + DrawWaterFallPoly(v); + } + + } +} + +void DrawWaterFallPoly(VECTORCH *v) +{ + POLYHEADER fakeHeader; + + { + extern int CloudyImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = CloudyImageNumber; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + { + static wv=0; + unsigned int a; + for (a=0; a<4; a++) + { + VerticesBuffer[a].A = 128; + VerticesBuffer[a].U = (v[a].vz)<<11; + VerticesBuffer[a].V = (v[a].vy<<10)-wv; + + TranslatePointIntoViewspace(&v[a]); + VerticesBuffer[a].X = v[a].vx; + VerticesBuffer[a].Y = v[a].vy; + VerticesBuffer[a].Z = v[a].vz; + VerticesBuffer[a].R = 200; + VerticesBuffer[a].G = 200; + VerticesBuffer[a].B = 255; + VerticesBuffer[a].SpecularR = 0; + VerticesBuffer[a].SpecularG = 0; + VerticesBuffer[a].SpecularB = 0; + + + } + wv+=NormalFrameTime*2; + RenderPolygon.NumberOfVertices=4; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices>=3) + { + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + } + } + } + } +} +void RenderPredatorTargetingSegment(int theta, int scale, int drawInRed) +{ + VECTOR2D offset[4]; + POLYHEADER fakeHeader; + int centreX,centreY; + int z = ONE_FIXED-scale; + z = MUL_FIXED(MUL_FIXED(z,z),2048); + { + extern int SmartTargetSightX, SmartTargetSightY; + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + centreY = MUL_FIXED( (SmartTargetSightY-(ScreenDescriptorBlock.SDB_Height<<15)) /Global_VDB_Ptr->VDB_ProjY,z); + if (MIRROR_CHEATMODE) + { + centreX = MUL_FIXED( ( - (SmartTargetSightX-(ScreenDescriptorBlock.SDB_Width<<15))) /Global_VDB_Ptr->VDB_ProjX,z); + } + else + { + centreX = MUL_FIXED( (SmartTargetSightX-(ScreenDescriptorBlock.SDB_Width<<15)) /Global_VDB_Ptr->VDB_ProjX,z); + } + } + z = (float)z*CameraZoomScale; + + { + int a = 160; + int b = 40; + + /* tan(30) = 1/sqrt(3), & 65536/(sqrt(3)) = 37837 */ + + int y = MUL_FIXED(37837,a+20); + + offset[0].vx = -a+MUL_FIXED(113512,b); + offset[0].vy = y-b; + + offset[1].vx = -offset[0].vx; + offset[1].vy = y-b; + + offset[2].vx = a; + offset[2].vy = y; + + offset[3].vx = -a; + offset[3].vy = y; + + if (theta) + { + extern void RotateVertex(VECTOR2D *vertexPtr, int theta); + + RotateVertex(&offset[0],theta); + RotateVertex(&offset[1],theta); + RotateVertex(&offset[2],theta); + RotateVertex(&offset[3],theta); + } + + if (MIRROR_CHEATMODE) + { + offset[0].vx = -offset[0].vx; + offset[1].vx = -offset[1].vx; + offset[2].vx = -offset[2].vx; + offset[3].vx = -offset[3].vx; + } + VerticesBuffer[0].X = offset[0].vx+centreX; + VerticesBuffer[0].Y = MUL_FIXED(offset[0].vy,87381)+centreY; + + VerticesBuffer[1].X = offset[1].vx+centreX; + VerticesBuffer[1].Y = MUL_FIXED(offset[1].vy,87381)+centreY; + + VerticesBuffer[2].X = offset[2].vx+centreX; + VerticesBuffer[2].Y = MUL_FIXED(offset[2].vy,87381)+centreY; + + VerticesBuffer[3].X = offset[3].vx+centreX; + VerticesBuffer[3].Y = MUL_FIXED(offset[3].vy,87381)+centreY; + } + fakeHeader.PolyFlags = iflag_transparent; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_GLOWING; + + + { + int i; + for (i=0; i<4; i++) + { + VerticesBuffer[i].A = 128; + + VerticesBuffer[i].Z = z; + + VerticesBuffer[i].R = 255; + + if (drawInRed) + { + VerticesBuffer[i].G = 0; + VerticesBuffer[i].B = 0; + } + else + { + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 255; + } + + } + RenderPolygon.NumberOfVertices=4; + } + + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + + if (drawInRed) + { + VerticesBuffer[0].X = MUL_FIXED(offset[3].vx,scale*8)+centreX; + VerticesBuffer[0].Y = MUL_FIXED(MUL_FIXED(offset[3].vy,scale*8),87381)+centreY; + + VerticesBuffer[1].X = MUL_FIXED(offset[2].vx,scale*8)+centreX; + VerticesBuffer[1].Y = MUL_FIXED(MUL_FIXED(offset[2].vy,scale*8),87381)+centreY; + + VerticesBuffer[2].X = offset[2].vx+centreX; + VerticesBuffer[2].Y = MUL_FIXED(offset[2].vy,87381)+centreY; + + VerticesBuffer[3].X = offset[3].vx+centreX; + VerticesBuffer[3].Y = MUL_FIXED(offset[3].vy,87381)+centreY; + { + int i; + for (i=0; i<2; i++) + { + VerticesBuffer[i].A = 0; + VerticesBuffer[i].Z = z; + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 0; + VerticesBuffer[i].B = 0; + } + for (i=2; i<4; i++) + { + VerticesBuffer[i].A = 128; + VerticesBuffer[i].Z = z; + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 0; + VerticesBuffer[i].B = 0; + } + RenderPolygon.NumberOfVertices=4; + } + + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } +} +void RenderPredatorPlasmaCasterCharge(int value, VECTORCH *worldOffsetPtr, MATRIXCH *orientationPtr) +{ + POLYHEADER fakeHeader; + VECTORCH translatedPts[4]; + int halfWidth = 100; + int halfHeight = 4; + int z = -1; + translatedPts[0].vx = -halfWidth; + translatedPts[0].vy = z; + translatedPts[0].vz = -halfHeight-4; + + translatedPts[1].vx = -halfWidth+MUL_FIXED(value,2*halfWidth-10); + translatedPts[1].vy = z; + translatedPts[1].vz = -halfHeight-4; + + translatedPts[2].vx = -halfWidth+MUL_FIXED(value,2*halfWidth-10); + translatedPts[2].vy = z; + translatedPts[2].vz = halfHeight-4; + + translatedPts[3].vx = -halfWidth; + translatedPts[3].vy = z; + translatedPts[3].vz = halfHeight-4; + + fakeHeader.PolyFlags = iflag_transparent; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_GLOWING; + + + { + int i; + for (i=0; i<4; i++) + { + VerticesBuffer[i].A = 255; + + RotateVector(&(translatedPts[i]),orientationPtr); + translatedPts[i].vx += worldOffsetPtr->vx; + translatedPts[i].vy += worldOffsetPtr->vy; + translatedPts[i].vz += worldOffsetPtr->vz; + TranslatePointIntoViewspace(&translatedPts[i]); + + VerticesBuffer[i].X = translatedPts[i].vx; + VerticesBuffer[i].Y = translatedPts[i].vy; + VerticesBuffer[i].Z = translatedPts[i].vz; + + VerticesBuffer[i].R = 32; + VerticesBuffer[i].G = 0; + VerticesBuffer[i].B = 0; + } + RenderPolygon.NumberOfVertices=4; + } + { + int outcode = QuadWithinFrustrum(); + + if (outcode) + { + if (outcode!=2) + { + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + else D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,VerticesBuffer); + } + } +} + + + + + +int LightFlareAlpha = 65535; +void RenderLightFlare(VECTORCH *positionPtr, unsigned int colour) +{ + int centreX,centreY,sizeX,sizeY,z; + PARTICLE particle; +// VECTORCH point = {-20947,-8216,2244}; + VECTORCH point = *positionPtr; + + + #if 0 + if (IsThisObjectVisibleFromThisPosition(Player,&point,ONE_FIXED)) + { + LightFlareAlpha+=NormalFrameTime*8; + if (LightFlareAlpha > 65535) LightFlareAlpha = 65535; + textprint("FLARE VIS\n"); + } + else + { + LightFlareAlpha-=NormalFrameTime*8; + if (LightFlareAlpha < 0) LightFlareAlpha = 0; + textprint("FLARE INVIS\n"); + } + #endif + TranslatePointIntoViewspace(&point); + if(point.vz<64) return; + + #if 0 + { + int alpha = ONE_FIXED - point.vz*2; + if (alpha<0) return; + + alpha = MUL_FIXED(LightFlareAlpha,alpha)>>8; + + particle.ParticleID = PARTICLE_MUZZLEFLASH; + particle.Colour = 0xffffff+((alpha)<<24); + } + #else + particle.ParticleID = PARTICLE_LIGHTFLARE; +// particle.Colour = 0xffffff+((LightFlareAlpha>>8)<<24); + particle.Colour = colour; + #endif +// textprint("render fn %d %d %d\n",positionPtr->vx,positionPtr->vy,positionPtr->vz); +// PARTICLE_DESC *particleDescPtr = &ParticleDescription[particlePtr->ParticleID]; +// int particleSize = particlePtr->Size; + z=ONE_FIXED; + { + extern int SmartTargetSightX, SmartTargetSightY; + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + centreX = DIV_FIXED(point.vx,point.vz); + centreY = DIV_FIXED(point.vy,point.vz); + sizeX = (ScreenDescriptorBlock.SDB_Width<<13)/Global_VDB_Ptr->VDB_ProjX; + sizeY = MUL_FIXED(ScreenDescriptorBlock.SDB_Height<<13,87381)/Global_VDB_Ptr->VDB_ProjY; + } + + VerticesBuffer[0].X = centreX - sizeX; + VerticesBuffer[0].Y = centreY - sizeY; + VerticesBuffer[0].Z = z; + VerticesBuffer[1].X = centreX + sizeX; + VerticesBuffer[1].Y = centreY - sizeY; + VerticesBuffer[1].Z = z; + VerticesBuffer[2].X = centreX + sizeX; + VerticesBuffer[2].Y = centreY + sizeY; + VerticesBuffer[2].Z = z; + VerticesBuffer[3].X = centreX - sizeX; + VerticesBuffer[3].Y = centreY + sizeY; + VerticesBuffer[3].Z = z; + + { + int outcode = QuadWithinFrustrum(); + + if (outcode) + { + RenderPolygon.NumberOfVertices=4; + +// textprint("On Screen!\n"); + VerticesBuffer[0].U = 192<<16; + VerticesBuffer[0].V = 0; + + VerticesBuffer[1].U = 255<<16; + VerticesBuffer[1].V = 0; + + VerticesBuffer[2].U = 255<<16; + VerticesBuffer[2].V = 63<<16; + + VerticesBuffer[3].U = 192<<16; + VerticesBuffer[3].V = 63<<16; + + if (outcode!=2) + { + TexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_Particle_Output(&particle,RenderPolygon.Vertices); + + } + else D3D_Particle_Output(&particle,VerticesBuffer); + } + } +} + +#if VOLUMETRIC_FOG + +int FogValue(VECTORCH *vertexPtr) +{ + float a,b,c,d, lMax,lMin; + VECTORCHF v; + v.vx = vertexPtr->vx; + v.vy = vertexPtr->vy; + v.vz = vertexPtr->vz; + + a = (v.vx*v.vx + v.vy*v.vy + v.vz*v.vz)*2.0; + b = -2.0*(v.vx*FogPosition.vx+v.vy*FogPosition.vy+v.vz*FogPosition.vz); + { +// float s = MUL_FIXED(GetSin(CloakingPhase&4095),GetSin(CloakingPhase&4095)); + c = FogMagnitude - 10000.0*10000.0; + } + d = b*b-2.0*a*c; + if (d<0) return 0; + + d = sqrt(d); + + lMin = (-b-d)/(a); + if (lMin>1.0) return 0; + + lMax = (-b+d)/(a); + + if (lMax<0.0) + { + return 0; + } + else if (lMax>1.0) + { + if (lMin>0.0) + { + float m; + int f; + m = Approximate3dMagnitude(vertexPtr); + f2i(f,(lMax-lMin)*m); + return f; + } + else return Approximate3dMagnitude(vertexPtr); + } + else //(lMax<1.0) + { + if (lMin>0.0) + { + float m; + int f; + m = Approximate3dMagnitude(vertexPtr); + f2i(f,(lMax-lMin)*m); + return f; + } + else + { + float m; + int f; + m = Approximate3dMagnitude(vertexPtr); + f2i(f,(lMax)*m); + return f; + } + + } +} +#endif +#if 0 +int SphereGenerated=0; +void RenderSphere(void) +{ + if(!SphereGenerated) + { + Generate_Sphere(); + SphereGenerated=1; + } +// EvolveSphere(); + { + int f; + POLYHEADER fakeHeader; + MATRIXCH mat = (Global_VDB_Ptr->VDB_Mat); + VECTORCH *vSphere = SphereRotatedVertex; + VECTORCH *v2 = SphereAtmosRotatedVertex; + VECTORCH d; + { + fakeHeader.PolyFlags = 0; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_OFF; + } + { + MATRIXCH m2; + EULER e; + e.EulerX =0; + e.EulerY =(CloakingPhase/32)&4095; + e.EulerZ =0; + CreateEulerMatrix(&e,&m2); + TransposeMatrixCH(&m2); + MatrixMultiply(&mat,&m2,&mat); + d.vx = -3316 - Global_VDB_Ptr->VDB_World.vx; + d.vy = -50000 -Global_VDB_Ptr->VDB_World.vy; + d.vz = 26926 -Global_VDB_Ptr->VDB_World.vz; + + RotateVector(&d,&(Global_VDB_Ptr->VDB_Mat)); + + } + for (f=0; f0) radius += h; + *vSphere = SphereVertex[f]; + + RotateVector(vSphere,&mat); + v2->vx = MUL_FIXED(vSphere->vx,4096+300); + v2->vy = MUL_FIXED(vSphere->vy,4096+300); + v2->vz = MUL_FIXED(vSphere->vz,4096+300); + v2++; + vSphere->vx = MUL_FIXED(vSphere->vx,radius); + vSphere->vy = MUL_FIXED(vSphere->vy,radius); + vSphere->vz = MUL_FIXED(vSphere->vz,radius); + vSphere++; + } + #if 0 + for (f=0; fONE_FIXED) l = ONE_FIXED; + if (l<0) l = 0; + + v[i].vx += d.vx; + v[i].vy += d.vy; + v[i].vz += d.vz; + v[i].vy = MUL_FIXED(v[i].vy,87381); + + VerticesBuffer[i].X = v[i].vx; + VerticesBuffer[i].Y = v[i].vy; + VerticesBuffer[i].Z = v[i].vz; + + VerticesBuffer[i].A = 0; + if (h<=0) + { + VerticesBuffer[i].R = 0; + VerticesBuffer[i].G = 255+h; + VerticesBuffer[i].B = 255; + } + else if (h>128) + { + VerticesBuffer[i].R = MUL_FIXED(255,h*256); + VerticesBuffer[i].G = MUL_FIXED(200,h*256); + VerticesBuffer[i].B = MUL_FIXED(150,h*256); + } + else + { + VerticesBuffer[i].R = 0; + VerticesBuffer[i].G = 96-h/2; + VerticesBuffer[i].B = 0; + } + VerticesBuffer[i].R = MUL_FIXED(VerticesBuffer[i].R,l); + VerticesBuffer[i].G = MUL_FIXED(VerticesBuffer[i].G,l); + VerticesBuffer[i].B = MUL_FIXED(VerticesBuffer[i].B,l); + } + RenderPolygon.NumberOfVertices=3; + } + + GouraudPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices>=3) + { + D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + } + } + } + } + + } + #endif + { + extern int CloudyImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = CloudyImageNumber; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_OFF; + } + for (f=0; fONE_FIXED) l = ONE_FIXED; + if (l<0) l = 0; + + vertex[i].vx += d.vx; + vertex[i].vy += d.vy; + vertex[i].vz += d.vz; + vertex[i].vy = MUL_FIXED(vertex[i].vy,87381); + + VerticesBuffer[i].X = vertex[i].vx; + VerticesBuffer[i].Y = vertex[i].vy; + VerticesBuffer[i].Z = vertex[i].vz; + VerticesBuffer[i].U = SphereAtmosU[n];//+u[0]; + VerticesBuffer[i].V = SphereAtmosV[n];//+v[0]; + + VerticesBuffer[i].A = 255; + VerticesBuffer[i].R = l; + VerticesBuffer[i].G = l/2; + VerticesBuffer[i].B = 0; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + } + RenderPolygon.NumberOfVertices=3; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices>=3) + { + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + } + } + } + } + } + } + +} +void RenderBoom(void) +{ + VECTORCH d; + if(!SphereGenerated) + { + Generate_Sphere(); + SphereGenerated=1; + } + d.vx = 0; + d.vy = 0; + d.vz = 0; + + RenderBoomSphere(&d,4096); + +} +void RenderBoomSphere(VECTORCH *position, int radius) +{ + int Alpha[SPHERE_VERTICES]; + extern D3DTEXTUREHANDLE FMVTextureHandle[]; + + { + int f; + POLYHEADER fakeHeader; + VECTORCH *vSphere = SphereRotatedVertex; + static int o=0; + o++; + + { + extern int CloudyImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = CloudyImageNumber; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + for (f=0; fvx = MUL_FIXED(vSphere->vx,r); + vSphere->vy = MUL_FIXED(vSphere->vy,r); + vSphere->vz = MUL_FIXED(vSphere->vz,r); + + vSphere->vx += position->vx; + vSphere->vy += position->vy; + vSphere->vz += position->vz; + TranslatePointIntoViewspace(vSphere); + vSphere++; + + } + + for (f=0; f(128*3+64)*65536) + { + if (d1>0) i2=1; + else i1=1; + } + if (ad2>(128*3+64)*65536) + { + if (d2>0) i3=1; + else i1=1; + } + if (ad3>(128*3+64)*65536) + { + if (d3>0) i3=1; + else i2=1; + } + + if(i1) VerticesBuffer[0].U+=128*65536*4; + if(i2) VerticesBuffer[1].U+=128*65536*4; + if(i3) VerticesBuffer[2].U+=128*65536*4; + } + + VerticesBuffer[i].A = 128+Alpha[n]; + VerticesBuffer[i].R = 0; + VerticesBuffer[i].G = 128; + VerticesBuffer[i].B = 255; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + } + RenderPolygon.NumberOfVertices=3; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices>=3) + { + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); +// D3D_FMVParticle_Output(RenderPolygon.Vertices); + } + } + } + } + } + } + } + +} + + +#endif +int Alpha[SPHERE_VERTICES]; +void RenderExplosionSurface(VOLUMETRIC_EXPLOSION *explosionPtr) +{ + extern D3DTEXTUREHANDLE FMVTextureHandle[]; + int red,green,blue; + + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + red = 255; + green = 255; + blue = 255; + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + red = 0; + green = 255; + blue = 0; + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + red = 255; + green = 0; + blue = 255; + break; + } + } + { + int f; + POLYHEADER fakeHeader; + VECTORCH *vSphere = SphereRotatedVertex; + static int o=0; + o++; + + if (explosionPtr->ExplosionPhase) + { + extern int BurningImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = BurningImageNumber; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + } + else + { + extern int CloudyImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = CloudyImageNumber; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_INVCOLOUR; + red = explosionPtr->LifeTime/256; + green = explosionPtr->LifeTime/256; + blue = explosionPtr->LifeTime/256; + } + + for (f=0; fPosition[f]; + + TranslatePointIntoViewspace(vSphere); + vSphere++; + } + + for (f=0; fLifeTime)*128*2; +// SphereAtmosU[0]=MUL_FIXED(SphereAtmosU[0],u); +// SphereAtmosV[0]=MUL_FIXED(SphereAtmosV[0],u); + VerticesBuffer[i].U = (SphereAtmosU[n]);//+u[0]; + VerticesBuffer[i].V = (SphereAtmosV[n]+u);//+v[0]; + } + { + int d1 = VerticesBuffer[0].U-VerticesBuffer[1].U; + int d2 = VerticesBuffer[0].U-VerticesBuffer[2].U; + int d3 = VerticesBuffer[1].U-VerticesBuffer[2].U; + + int ad1=d1,ad2=d2,ad3=d3; + int i1=0,i2=0,i3=0; + + if (ad1<0) ad1=-ad1; + if (ad2<0) ad2=-ad2; + if (ad3<0) ad3=-ad3; + + if (ad1>(128*(SPHERE_TEXTURE_WRAP-1)+64)*65536) + { + if (d1>0) i2=1; + else i1=1; + } + if (ad2>(128*(SPHERE_TEXTURE_WRAP-1)+64)*65536) + { + if (d2>0) i3=1; + else i1=1; + } + if (ad3>(128*(SPHERE_TEXTURE_WRAP-1)+64)*65536) + { + if (d3>0) i3=1; + else i2=1; + } + + if(i1) VerticesBuffer[0].U+=128*65536*SPHERE_TEXTURE_WRAP; + if(i2) VerticesBuffer[1].U+=128*65536*SPHERE_TEXTURE_WRAP; + if(i3) VerticesBuffer[2].U+=128*65536*SPHERE_TEXTURE_WRAP; + } + + VerticesBuffer[i].A = explosionPtr->LifeTime/256; + VerticesBuffer[i].R = red; + VerticesBuffer[i].G = green; + VerticesBuffer[i].B = blue; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + + } + RenderPolygon.NumberOfVertices=3; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices>=3) + { + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices>=3) + { + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); +// D3D_FMVParticle_Output(RenderPolygon.Vertices); + } + } + } + } + } + } + } +} +void RenderInsideAlienTongue(int offset) +{ + #define TONGUE_SCALE 1024 + int TonguePolyVertexList[4][4] = + { + {0,3,7,4}, //+ve y + {1,2,3,0}, //+ve x + {5,6,7,4}, //-ve x + {1,2,6,5}, //-ve y + }; + VECTORCH vertices[8]= + { + {+TONGUE_SCALE,-TONGUE_SCALE,0}, + {+TONGUE_SCALE,+TONGUE_SCALE,0}, + {+TONGUE_SCALE,+TONGUE_SCALE,+TONGUE_SCALE*4}, + {+TONGUE_SCALE,-TONGUE_SCALE,+TONGUE_SCALE*4}, + + {-TONGUE_SCALE,-TONGUE_SCALE,0}, + {-TONGUE_SCALE,+TONGUE_SCALE,0}, + {-TONGUE_SCALE,+TONGUE_SCALE,+TONGUE_SCALE*4}, + {-TONGUE_SCALE,-TONGUE_SCALE,+TONGUE_SCALE*4}, + }; + VECTORCH translatedPts[8]; + + POLYHEADER fakeHeader; + int polyNumber; + + #if 1 + { + + int i = 7; + do + { + translatedPts[i] = vertices[i]; + translatedPts[i].vz -= (ONE_FIXED-offset)/16; +// TranslatePointIntoViewspace(&translatedPts[i]); + } + while(i--); + } + #endif + { + extern int AlienTongueImageNumber; + fakeHeader.PolyFlags = 0; + fakeHeader.PolyColour = AlienTongueImageNumber; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_GLOWING; + } + + for(polyNumber=0; polyNumber<4; polyNumber++) + { + { + int i; + for (i=0; i<4; i++) + { + int v = TonguePolyVertexList[polyNumber][i]; + VerticesBuffer[i].A = 255; + VerticesBuffer[i].X = translatedPts[v].vx; + VerticesBuffer[i].Y = translatedPts[v].vy; + VerticesBuffer[i].Z = translatedPts[v].vz; + VerticesBuffer[i].U = CuboidPolyVertexU[3][i]<<16; + VerticesBuffer[i].V = CuboidPolyVertexV[3][i]<<16; + + + VerticesBuffer[i].R = offset/2048; + VerticesBuffer[i].G = offset/2048; + VerticesBuffer[i].B = offset/2048; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + + } + RenderPolygon.NumberOfVertices=4; + } + { + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + + } + } +} + + + +#define NO_OF_STARS 500 +typedef struct +{ + VECTORCH Position; + int Colour; + int Frequency; + int Phase; + +} STARDESC; +static STARDESC StarArray[NO_OF_STARS]; + +void CreateStarArray(void) +{ + int i; + + SetSeededFastRandom(FastRandom()); + for (i=0; iVDB_World.vx; + position.vy += Global_VDB_Ptr->VDB_World.vy; + position.vz += Global_VDB_Ptr->VDB_World.vz; + + TranslatePointIntoViewspace(&position); + #endif +// RotateVector(&position,&(Global_VDB_Ptr->VDB_Mat)); + + + VerticesBuffer[0].X = position.vx - sizeX; + VerticesBuffer[0].Y = position.vy - sizeY; + VerticesBuffer[0].Z = position.vz; + VerticesBuffer[1].X = position.vx + sizeX; + VerticesBuffer[1].Y = position.vy - sizeY; + VerticesBuffer[1].Z = position.vz; + VerticesBuffer[2].X = position.vx + sizeX; + VerticesBuffer[2].Y = position.vy + sizeY; + VerticesBuffer[2].Z = position.vz; + VerticesBuffer[3].X = position.vx - sizeX; + VerticesBuffer[3].Y = position.vy + sizeY; + VerticesBuffer[3].Z = position.vz; + + { + int outcode = QuadWithinFrustrum(); + + if (outcode) + { + RenderPolygon.NumberOfVertices=4; + + // textprint("On Screen!\n"); + VerticesBuffer[0].U = 192<<16; + VerticesBuffer[0].V = 0; + + VerticesBuffer[1].U = 255<<16; + VerticesBuffer[1].V = 0; + + VerticesBuffer[2].U = 255<<16; + VerticesBuffer[2].V = 63<<16; + + VerticesBuffer[3].U = 192<<16; + VerticesBuffer[3].V = 63<<16; + + if (outcode!=2) + { + TexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_Particle_Output(&particle,RenderPolygon.Vertices); + + } + else D3D_Particle_Output(&particle,VerticesBuffer); + } + } + } +} + + + + + + +#if 0 +/* KJL 17:07:52 07/11/98 - experiment! */ +extern unsigned char DebouncedKeyboardInput[]; +#include "dungeon\angband.h" +char array[MAX_WID+1][MAX_HGT+1]; +extern cave_type cave[MAX_HGT][MAX_WID]; +void RenderDungeon(void) +{ + int x,y; + int maxX=MAX_WID-1,maxY=MAX_HGT-1; + static int notMade=1; + + if (notMade || DebouncedKeyboardInput[KEY_G]) + { + for (x=0; x<=maxX; x++) + for (y=0; y<=maxY; y++) + { + cave[y][x].feat = FEAT_WALL_OUTER; + } + generate_cave(); + for (x=0; x<=maxX; x++) + for (y=0; y<=maxY; y++) + { + array[x][y] = 1; + if (cave[y][x].feat == FEAT_FLOOR) + array[x][y] = 0; + } + notMade = 0; + } + for (x=0; x<=maxX; x++) + for (y=0; y<=maxY; y++) + { + if (!array[x][y]) + { + + if (x>0) + { + if (array[x-1][y]) RenderWallY(x,y); + } + else + { + RenderWallY(0,y); + } + if (x0) + { + if (array[x][y-1]) RenderWallX(x,y); + } + else + { + RenderWallX(x,0); + } + if (yPolyPtr = outputPolyPtr; + + { + int maxZ = smallint; + int minZ = bigint; + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + int z = vertices->Z; + + if(z > maxZ) maxZ = z; + if(z < minZ) minZ = z; + vertices++; + } + while(--i); + + if (inputPolyPtr->PolyFlags & iflag_sortnearz) currentItemPtr->SortKey = minZ; + else if (inputPolyPtr->PolyFlags & iflag_sortfarz) currentItemPtr->SortKey = maxZ +10; + else currentItemPtr->SortKey = maxZ; + } + + ItemCount++; + + /* Write out the Item Header */ + outputPolyPtr->PolyItemType = I_ZB_2dTexturedPolygon; + outputPolyPtr->PolyNormalIndex = inputPolyPtr->PolyNormalIndex; + outputPolyPtr->PolyFlags = inputPolyPtr->PolyFlags; + if(Global_ShapeNormals) + outputPolyPtr->PolyColour = OldLightingModelForFlatShading((int *)inputPolyPtr); + else + outputPolyPtr->PolyColour = 0; + + /* Write out the Item Points Array */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + itemDataPtr = &outputPolyPtr->Poly1stPt; + + do + { + *itemDataPtr++ = ProjectedAndClampedX(vertices); + *itemDataPtr++ = ProjectedAndClampedY(vertices); + *itemDataPtr++ = vertices->U; + *itemDataPtr++ = vertices->V; + { + float *fDataPtr = (float*)itemDataPtr; + *fDataPtr = 1.0/((float)(vertices->Z)); + itemDataPtr++; + } + vertices++; + } + while(--i); + } + /* Write out the Item Terminator */ + *itemDataPtr = Term; + } +} +/* TEXTURED POLYGONS */ +static void TexturedPolygon_Construct(POLYHEADER *polyPtr) +{ + int *texture_defn_ptr; + RENDERVERTEX *renderVerticesPtr = VerticesBuffer; + int i = RenderPolygon.NumberOfVertices; + + + /* get ptr to uv coords for this polygon */ + { + int texture_defn_index = (polyPtr->PolyColour >> TxDefn); + texture_defn_ptr = Global_ShapeTextures[texture_defn_index]; + } + + VertexNumberPtr = &polyPtr->Poly1stPt; + + /* If this texture is animated the UV array must be calculated */ + if(polyPtr->PolyFlags & iflag_txanim) + { + /* Create the UV array */ + int uv_array[maxpolypts * 2]; + CreateTxAnimUVArray(texture_defn_ptr, uv_array, (int*)polyPtr); + texture_defn_ptr = uv_array; + + do + { + renderVerticesPtr->X = RotatedPts[*VertexNumberPtr].vx; + renderVerticesPtr->Y = RotatedPts[*VertexNumberPtr].vy; + renderVerticesPtr->Z = RotatedPts[*VertexNumberPtr].vz; + + renderVerticesPtr->U = texture_defn_ptr[0]; + renderVerticesPtr->V = texture_defn_ptr[1]; + + renderVerticesPtr++; + VertexNumberPtr++; + + texture_defn_ptr += 2; + } + while(--i); + } + else + { + do + { + renderVerticesPtr->X = RotatedPts[*VertexNumberPtr].vx; + renderVerticesPtr->Y = RotatedPts[*VertexNumberPtr].vy; + renderVerticesPtr->Z = RotatedPts[*VertexNumberPtr].vz; + + renderVerticesPtr->U = texture_defn_ptr[0] << 16; + renderVerticesPtr->V = texture_defn_ptr[1] << 16; + + renderVerticesPtr++; + VertexNumberPtr++; + + texture_defn_ptr += 2; + } + while(--i); + } + +} +static void TexturedPolygon_Output(POLYHEADER *inputPolyPtr, RENDERVERTEX *renderVerticesPtr) +{ + int *itemDataPtr; + + itemDataPtr = AllocateItemData(IHdrSize + RenderPolygon.NumberOfVertices*4 + ITrmSize); + + if(itemDataPtr) + { + POLYHEADER *outputPolyPtr = (POLYHEADER*) itemDataPtr; + struct KItem * const currentItemPtr = &KItemList[ItemCount]; + + currentItemPtr->PolyPtr = outputPolyPtr; + + { + int maxZ = smallint; + int minZ = bigint; + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + int z = vertices->Z; + + if(z > maxZ) maxZ = z; + if(z < minZ) minZ = z; + vertices++; + } + while(--i); + + if (inputPolyPtr->PolyFlags & iflag_sortnearz) currentItemPtr->SortKey = minZ; + else if (inputPolyPtr->PolyFlags & iflag_sortfarz) currentItemPtr->SortKey = maxZ +10; + else currentItemPtr->SortKey = maxZ; + } + + ItemCount++; + + /* Write out the Item Header */ + outputPolyPtr->PolyItemType = I_2dTexturedPolygon; + outputPolyPtr->PolyNormalIndex = inputPolyPtr->PolyNormalIndex; + outputPolyPtr->PolyFlags = inputPolyPtr->PolyFlags; + if(Global_ShapeNormals) + outputPolyPtr->PolyColour = OldLightingModelForFlatShading((int *)inputPolyPtr); + else + outputPolyPtr->PolyColour = 0; + + /* Write out the Item Points Array */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + itemDataPtr = &outputPolyPtr->Poly1stPt; + + do + { + *itemDataPtr++ = ProjectedAndClampedX(vertices); + *itemDataPtr++ = ProjectedAndClampedY(vertices); + *itemDataPtr++ = vertices->U; + *itemDataPtr++ = vertices->V; + vertices++; + } + while(--i); + } + /* Write out the Item Terminator */ + *itemDataPtr = Term; + } +} +static void ZBufferedGouraudTexturedPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr) +{ + POLYHEADER *outputPolyPtr; + int *itemDataPtr; + + struct KItem * const currentItemPtr = &KItemList[ItemCount]; + + { + int maxZ = smallint; + int minZ = bigint; + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + int z = vertices->Z; + + if(z > maxZ) maxZ = z; + if(z < minZ) minZ = z; + vertices++; + } + while(--i); + + if (inputPolyPtr->PolyFlags & iflag_sortnearz) currentItemPtr->SortKey = minZ; + else if (inputPolyPtr->PolyFlags & iflag_sortfarz) currentItemPtr->SortKey = maxZ +10; + else currentItemPtr->SortKey = maxZ; + } + + /* draw in 3d */ + { + itemDataPtr = AllocateItemData(IHdrSize + RenderPolygon.NumberOfVertices*6 + ITrmSize); + outputPolyPtr = (POLYHEADER*) itemDataPtr; + + /* Write out the Item Header */ + outputPolyPtr->PolyItemType = I_ZB_Gouraud3dTexturedPolygon; + + /* Write out the Item Points Array */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + itemDataPtr = &outputPolyPtr->Poly1stPt; + + do + #if 1 + { + float oneOverZ; + oneOverZ = (1.0)/vertices->Z; + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + *itemDataPtr++=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + *itemDataPtr++=y; + } + { + float *fDataPtr = (float*)itemDataPtr; + + *fDataPtr++ = (float)(vertices->U>>16); + *fDataPtr++ = (float)(vertices->V>>16); + *fDataPtr++ = oneOverZ; + itemDataPtr = (int*)fDataPtr; + } + *itemDataPtr++ = vertices->I; + vertices++; + } + #else + { + *itemDataPtr++ = ProjectedAndClampedX(vertices); + *itemDataPtr++ = ProjectedAndClampedY(vertices); + { + float uf,vf,zf; + float *fDataPtr = (float*)itemDataPtr; + + zf = (vertices->Z); + + uf = vertices->U>>16; + *fDataPtr++ = uf; + + vf = vertices->V>>16; + *fDataPtr++ = vf; + zf = 1.0/zf; + *fDataPtr++ = zf; + itemDataPtr = (int*)fDataPtr; + } + *itemDataPtr++ = vertices->I; + vertices++; + } + #endif + while(--i); + } + } + + /* Write out the Item Terminator */ + *itemDataPtr = Term; + + currentItemPtr->PolyPtr = outputPolyPtr; + + outputPolyPtr->PolyNormalIndex = inputPolyPtr->PolyNormalIndex; + outputPolyPtr->PolyFlags = inputPolyPtr->PolyFlags; + outputPolyPtr->PolyColour = inputPolyPtr->PolyColour; + + ItemCount++; +} +static void GouraudPolygon_Output(POLYHEADER *inputPolyPtr, RENDERVERTEX *renderVerticesPtr) +{ + int *itemDataPtr; + + itemDataPtr = AllocateItemData(IHdrSize + RenderPolygon.NumberOfVertices*3 + ITrmSize); + + if(itemDataPtr) + { + POLYHEADER *outputPolyPtr = (POLYHEADER*) itemDataPtr; + struct KItem * const currentItemPtr = &KItemList[ItemCount]; + + currentItemPtr->PolyPtr = outputPolyPtr; + + { + + int maxZ = smallint; + int minZ = bigint; + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + int z = vertices->Z; + + if(z > maxZ) maxZ = z; + if(z < minZ) minZ = z; + vertices++; + } + while(--i); + + if (inputPolyPtr->PolyFlags & iflag_sortnearz) currentItemPtr->SortKey = minZ; + else if (inputPolyPtr->PolyFlags & iflag_sortfarz) currentItemPtr->SortKey = maxZ +10; + else currentItemPtr->SortKey = maxZ; + } + + ItemCount++; + + /* Write out the Item Header */ + outputPolyPtr->PolyItemType = I_GouraudPolygon; + outputPolyPtr->PolyNormalIndex = inputPolyPtr->PolyNormalIndex; + outputPolyPtr->PolyFlags = inputPolyPtr->PolyFlags; + + #if 1//debug + if (inputPolyPtr->PolyItemType != I_GouraudPolygon) + { + int c = GetSin((inputPolyPtr->PolyColour>>5)&4095); + if (c<0) c=-c; + + inputPolyPtr->PolyColour+=NormalFrameTime; + + if (VideoModeType==VideoModeType_8) c<<=6; + + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + vertices->I = c; + vertices++; + } + while(--i); + } + + outputPolyPtr->PolyColour = 0xff; + } + else + #endif + outputPolyPtr->PolyColour = inputPolyPtr->PolyColour; + + /* Write out the Item Points Array */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + itemDataPtr = &outputPolyPtr->Poly1stPt; + + do + { + *itemDataPtr++ = ProjectedAndClampedX(vertices); + *itemDataPtr++ = ProjectedAndClampedY(vertices); + *itemDataPtr++ = vertices->I; + vertices++; + } + while(--i); + } + /* Write out the Item Terminator */ + *itemDataPtr = Term; + } +} +static void CloakedTexturedPolygon_Construct(POLYHEADER *polyPtr) +{ + int cloakedU[] = { 248-8,256-8,256-8,248-8 }; + int cloakedV[] = { 1,1,8,8 }; + + int *texture_defn_ptr; + RENDERVERTEX *renderVerticesPtr = VerticesBuffer; + int i = RenderPolygon.NumberOfVertices; + + + /* get ptr to uv coords for this polygon */ + { + int texture_defn_index = (polyPtr->PolyColour >> TxDefn); + texture_defn_ptr = Global_ShapeTextures[texture_defn_index]; + } + + VertexNumberPtr = &polyPtr->Poly1stPt; + + while(i--) + { + renderVerticesPtr->X = RotatedPts[*VertexNumberPtr].vx; + renderVerticesPtr->Y = RotatedPts[*VertexNumberPtr].vy; + renderVerticesPtr->Z = RotatedPts[*VertexNumberPtr].vz; + + renderVerticesPtr->U = cloakedU[i]; + renderVerticesPtr->V = cloakedV[i]; + + renderVerticesPtr++; + VertexNumberPtr++; + } +} + void GouraudTexturedPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr) +{ + POLYHEADER *outputPolyPtr; + int *itemDataPtr; + int drawIn2D; + + struct KItem * const currentItemPtr = &KItemList[ItemCount]; + + { + int maxZ = smallint; + int minZ = bigint; + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + int z = vertices->Z; + + if(z > maxZ) maxZ = z; + if(z < minZ) minZ = z; + vertices++; + } + while(--i); + + if (inputPolyPtr->PolyFlags & iflag_sortnearz) currentItemPtr->SortKey = minZ; + else if (inputPolyPtr->PolyFlags & iflag_sortfarz) currentItemPtr->SortKey = maxZ +10; + else currentItemPtr->SortKey = maxZ; + + drawIn2D = (maxZ*4 < minZ*5); + } + + #if !Saturn + /* KJL 15:49:56 07/04/97 - draw all in 3D will become an option */ + if ((ScanDrawMode == ScanDrawDirectDraw) && (drawIn2D)) + #endif + { + itemDataPtr = AllocateItemData(IHdrSize + RenderPolygon.NumberOfVertices*5 + ITrmSize); + outputPolyPtr = (POLYHEADER*) itemDataPtr; + + /* Write out the Item Header */ + outputPolyPtr->PolyItemType = I_Gouraud2dTexturedPolygon; + + /* Write out the Item Points Array */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + itemDataPtr = &outputPolyPtr->Poly1stPt; + + do + { + #if 1 + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + *itemDataPtr++=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + *itemDataPtr++=y; + } + #endif + #if Saturn + *itemDataPtr++ = vertices->R; + *itemDataPtr++ = vertices->G; + *itemDataPtr++ = vertices->B; + #else + *itemDataPtr++ = vertices->U; + *itemDataPtr++ = vertices->V; + *itemDataPtr++ = vertices->I; + #endif + vertices++; + } + while(--i); + } + } + #if !Saturn + else /* draw in 3d */ + { + itemDataPtr = AllocateItemData(IHdrSize + RenderPolygon.NumberOfVertices*6 + ITrmSize); + outputPolyPtr = (POLYHEADER*) itemDataPtr; + + /* Write out the Item Header */ + outputPolyPtr->PolyItemType = I_Gouraud3dTexturedPolygon; + + /* Write out the Item Points Array */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + itemDataPtr = &outputPolyPtr->Poly1stPt; + + do + { + float oneOverZ,uf,vf; + uf = vertices->U>>16; + vf = vertices->V>>16; + + oneOverZ = (1.0)/vertices->Z; + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + *itemDataPtr++=x; + } + uf = uf*oneOverZ; + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + *itemDataPtr++=y; + } + vf = vf*oneOverZ; + { + float *fDataPtr = (float*)itemDataPtr; + + *fDataPtr++ = uf; + *fDataPtr++ = vf; + *fDataPtr++ = oneOverZ; + itemDataPtr = (int*)fDataPtr; + } + *itemDataPtr++ = vertices->I; + vertices++; + } + while(--i); + } + } + #endif + /* Write out the Item Terminator */ + *itemDataPtr = Term; + + currentItemPtr->PolyPtr = outputPolyPtr; + + outputPolyPtr->PolyNormalIndex = inputPolyPtr->PolyNormalIndex; + outputPolyPtr->PolyFlags = inputPolyPtr->PolyFlags; + outputPolyPtr->PolyColour = inputPolyPtr->PolyColour; + + ItemCount++; +} + +#endif \ No newline at end of file diff --git a/3dc/Language.txt b/3dc/Language.txt new file mode 100644 index 0000000..6166646 Binary files /dev/null and b/3dc/Language.txt differ diff --git a/3dc/MAP.C b/3dc/MAP.C new file mode 100644 index 0000000..c926cbd --- /dev/null +++ b/3dc/MAP.C @@ -0,0 +1,246 @@ +#include "3dc.h" + +#include "inline.h" +#include "module.h" +#include "stratdef.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + + +/* + externs for commonly used global variables and arrays +*/ + + +extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + +/* + Global Variables +*/ + +DISPLAYBLOCK *dptr_last; +DISPLAYBLOCK *Player; + + +/* + Map Reading Functions + Read the map data passed and create the objects on the map + The map header contains an array of pointers to the different map data + structures +*/ + + +DISPLAYBLOCK* ReadMap(MAPHEADER *mapheader) +{ + MAPBLOCK8 *mapblock8ptr; + DISPLAYBLOCK *dblockptr = 0; + + + /* Set up pointers to the map arrays */ + mapblock8ptr = mapheader->MapType8Objects; + + + /* Map Type #8 Structure */ + if(mapblock8ptr) { + + while(mapblock8ptr->MapType != MapType_Term) { + + dblockptr = CreateActiveObject(); + + if(dblockptr) + { + dblockptr->ObShape = mapblock8ptr->MapShape; + + CopyLocation(&mapblock8ptr->MapWorld, &dblockptr->ObWorld); + CopyEuler(&mapblock8ptr->MapEuler, &dblockptr->ObEuler); + + dblockptr->ObFlags = mapblock8ptr->MapFlags; + dblockptr->ObFlags2 = mapblock8ptr->MapFlags2; + dblockptr->ObFlags3 = mapblock8ptr->MapFlags3; + + if (mapblock8ptr->MapType == MapType_Player) + { + Player = dblockptr; + } + else + { + dblockptr->ObLightType = LightType_PerVertex; + dblockptr->ObFlags |= ObFlag_MultLSrc; + } + +/* KJL 16:55:57 06/05/97 - removing camera stuff */ + if(mapblock8ptr->MapVDBData) + MapSetVDB(dblockptr, mapblock8ptr->MapVDBData); + + dblockptr->ObLightType = mapblock8ptr->MapLightType; + +/* KJL 15:23:52 06/07/97 - removed */ +// CopyVector(&mapblock8ptr->MapOrigin, &dblockptr->ObOrigin); +// dblockptr->ObSimShapes = mapblock8ptr->MapSimShapes; +// dblockptr->ObViewType = mapblock8ptr->MapViewType; + + MapBlockInit(dblockptr); + + CreateEulerMatrix(&dblockptr->ObEuler,&dblockptr->ObMat); + TransposeMatrixCH(&dblockptr->ObMat); + + MapPostProcessing(dblockptr); + } + + dptr_last = dblockptr; + + mapblock8ptr++; + + } + + } + return dblockptr; +} + + + +/* + + Some objects might require a certain amount of general processing after + all the other map functions have been called + +*/ + +void MapPostProcessing(DISPLAYBLOCK *dptr) +{ + if(dptr) + { + /* + + Make sure that objects requesting multiple light sources are at + least set to "LightType_PerObject" + + */ + if(dptr->ObFlags & ObFlag_MultLSrc) + { + if(dptr->ObLightType == LightType_Infinite) + dptr->ObLightType = LightType_PerObject; + } + } +} + + +void MapSetVDB(DISPLAYBLOCK *dptr, MAPSETVDB *mapvdbdata) +{ + + VIEWDESCRIPTORBLOCK *vdb; + + /* TEST */ + /*LIGHTBLOCK *lptr;*/ + + + + /* Allocate a VDB */ + + vdb = CreateActiveVDB(); + + if(vdb) { + + dptr->ObVDBPtr = vdb; /* Object Block ptr to VDB */ + + vdb->VDB_ViewObject = dptr; /* VDB ptr to Object Block */ + + + /* VDB Setup */ + + SetVDB( + + vdb, + + mapvdbdata->SVDB_Flags, + mapvdbdata->SVDB_ViewType, + + mapvdbdata->SVDB_Depth, + + mapvdbdata->SVDB_CentreX, + mapvdbdata->SVDB_CentreY, + + mapvdbdata->SVDB_ProjX, + mapvdbdata->SVDB_ProjY, + mapvdbdata->SVDB_MaxProj, + + mapvdbdata->SVDB_ClipLeft, + mapvdbdata->SVDB_ClipRight, + mapvdbdata->SVDB_ClipUp, + mapvdbdata->SVDB_ClipDown, + + mapvdbdata->SVDB_H1, + mapvdbdata->SVDB_H2, + mapvdbdata->SVDB_HColour, + + mapvdbdata->SVDB_Ambience + + ); + + PlatformSpecificVDBInit(vdb); + + #if ProjectSpecificVDBs + ProjectSpecificVDBInit(vdb); + #endif + + + } + +} + + + + + + + +/* + + Standard Initialisation for Map Objects + +*/ + +void MapBlockInit(DISPLAYBLOCK *dptr) +{ + SHAPEHEADER *sptr; + + /* Get the shape header ptr */ + + sptr = GetShapeData(dptr->ObShape); + + + /* Augmented Z */ + + if(sptr->shapeflags & ShapeFlag_AugZ) dptr->ObFlags2 |= ObFlag2_AugZ; + + + /* Pass address of the shape data header back to the block for others */ + + dptr->ObShapeData = sptr; + + + /* Does this shape use a BSP tree or a Z Sort ? */ + + dptr->ObFlags |= ObFlag_TypeZ; + + + /* Copy shape radius to ODB */ + + dptr->ObRadius = sptr->shaperadius; + + /* Copy shape xyz extents to ODB */ + + dptr->ObMaxX = sptr->shapemaxx; + dptr->ObMinX = sptr->shapeminx; + + dptr->ObMaxY = sptr->shapemaxy; + dptr->ObMinY = sptr->shapeminy; + + dptr->ObMaxZ = sptr->shapemaxz; + dptr->ObMinZ = sptr->shapeminz; + + + +} + diff --git a/3dc/MEM3DCPP.CPP b/3dc/MEM3DCPP.CPP new file mode 100644 index 0000000..906b589 --- /dev/null +++ b/3dc/MEM3DCPP.CPP @@ -0,0 +1,48 @@ +#include "mem3dc.h" + +#if DBGMALLOC + +#if 1 + +// try and turn C++ new/delete tracking on such that +// we can do a malloc dump when the global objects +// with associated memory allocated is recored, the +// deallocation is recored, and then a malloc dump +// is done + +// note that some global objects wont have their memory +// allocations/deallocations in the constructor/destructor +// tracked through record_malloc/record_free, but since +// global objects are deconstructed in the reverse order +// from construction, the deallocation type in the destructor +// will correspond to the allocation type in the constructor + +int __cpp_new_recording = 0; + +class DebugObject +{ +public: + DebugObject(); + ~DebugObject(); +}; + +DebugObject::DebugObject() +{ + __cpp_new_recording = 1; +} + +DebugObject::~DebugObject() +{ + __cpp_new_recording = 0; + DumpMallocInfo(DUMPTOFILE); +} + +static DebugObject dbo; + +#else + +int __cpp_new_recording = 1; + +#endif + +#endif diff --git a/3dc/MODULE.C b/3dc/MODULE.C new file mode 100644 index 0000000..cd973c0 --- /dev/null +++ b/3dc/MODULE.C @@ -0,0 +1,1131 @@ +#include "3dc.h" + +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "bh_types.h" +#include "pvisible.h" +#include "pfarlocs.h" +#include "avpview.h" +#include "ourasert.h" +#include "pldghost.h" + +#if SupportModules + +/* imported externs */ + +extern SCENE Global_Scene; +extern int NumActiveBlocks; +extern DISPLAYBLOCK *ActiveBlockList[]; +extern DISPLAYBLOCK *dptr_last; +extern unsigned char KeyASCII; + +/**** Protos ****/ + +void FindVisibleModules(VMODULE *vptr,int flag); + +/**** Statics ****/ + +static MODULE **Global_ModuleArrayPtr; + +void AllNewModuleHandler(void) +{ + { + int i; + SCENEMODULE *smptr; + smptr = Global_ModulePtr[Global_Scene]; + Global_ModuleArrayPtr = smptr->sm_marray; + + for(i = 0; i < ModuleArraySize; i++) + { + ModuleCurrVisArray[i] = 0; + } + } + + /* handle dynamic module objects */ + { + int numberOfObjects = NumActiveBlocks; + + while (numberOfObjects--) + { + DISPLAYBLOCK* objectPtr = ActiveBlockList[numberOfObjects]; + + if(objectPtr->ObFlags3 & ObFlag3_DynamicModuleObject) + { + STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock; + + sbPtr->containingModule = (ModuleFromPosition(&(objectPtr->ObWorld), sbPtr->containingModule)); + if (sbPtr->containingModule) + if (ModuleIsPhysical(sbPtr->containingModule)) + { + ModuleCurrVisArray[sbPtr->containingModule->m_index] = 1; + if(sbPtr->containingModule->m_vmptr) FindVisibleModules(sbPtr->containingModule->m_vmptr,1); + } + } + } + } + + /*If this is an network game , and this machine is the ai server , then need to check if + there are any aliens near to other players*/ + if(AvP.Network!=I_No_Network && AvP.NetworkAIServer) + { + /* go through the strategy blocks looking for players*/ + int sbIndex; + for(sbIndex=0;sbIndexI_SBtype!=I_BehaviourNetGhost) continue; + ghostData = (NETGHOSTDATABLOCK *)playerSbPtr->SBdataptr; + + if(ghostData->type==I_BehaviourAlienPlayer || + ghostData->type==I_BehaviourMarinePlayer || + ghostData->type==I_BehaviourPredatorPlayer) + { + int sbIndex2; + //found one of the players + if(!playerSbPtr->containingModule) continue; + + /*now search through the strategy blocks , to see if any aliens are + visible from the player's location*/ + for(sbIndex2=0;sbIndex2I_SBtype!=I_BehaviourAlien) continue; + if(!alienSbPtr->containingModule) continue; + + if(IsModuleVisibleFromModule(playerSbPtr->containingModule,alienSbPtr->containingModule)) + { + /*The player can see the alien , so link in all modules that the + player can see*/ + if (ModuleIsPhysical(playerSbPtr->containingModule)) + { + ModuleCurrVisArray[playerSbPtr->containingModule->m_index] = 1; + if(playerSbPtr->containingModule->m_vmptr) FindVisibleModules(playerSbPtr->containingModule->m_vmptr,1); + } + + /*Since all modules visible by this player have now been linked , don't need + to check for any more aliens for this player*/ + break; + + } + + } + + } + } + } + + /* handle player visibilities */ + { + extern MODULE * playerPherModule; + playerPherModule = (ModuleFromPosition(&(Global_VDB_Ptr->VDB_World), playerPherModule)); + + if(!playerPherModule) + { + playerPherModule = (ModuleFromPosition(&(Player->ObWorld), playerPherModule)); + } + + if (playerPherModule) + { + ModuleCurrVisArray[playerPherModule->m_index] = 2; + if(playerPherModule->m_vmptr) FindVisibleModules(playerPherModule->m_vmptr,2); + } + } + + + + /* handle AIMODULE visibility stuff */ + { + int i; + for(i = 0; i < ModuleArraySize; i++) + { + if (ModuleCurrVisArray[i] == 2) + { + AIMODULE *aiModulePtr = Global_ModuleArrayPtr[i]->m_aimodule; + if (aiModulePtr) + { + MODULE **modulelistPtr = aiModulePtr->m_module_ptrs; + while(*modulelistPtr) + { + int index = (*modulelistPtr)->m_index; + if (!ModuleCurrVisArray[index]) ModuleCurrVisArray[index]=1; + modulelistPtr++; + } + } + } + } + } + /* update active block list */ + { + int i; + + for(i = 0; i < ModuleArraySize; i++) + { + MODULE *mptr = Global_ModuleArrayPtr[i]; + + if(ModuleCurrVisArray[i]) + { + if(mptr->m_dptr == 0 && ((mptr->m_flags & m_flag_dormant) == 0)) + { + AllocateModuleObject(mptr); + } + + } + else + { + if(mptr->m_dptr) DeallocateModuleObject(mptr); + } + + } + + } + + /* call Patrick's code */ + DoObjectVisibilities(); +} + + +void FindVisibleModules(VMODULE *vptr,int flag) +{ + while(vptr->vmod_type != vmtype_term) + { + MODULE *mptr; + + /* Add this module to the visible array */ + if(vptr->vmod_mref.mref_ptr) + { + mptr = vptr->vmod_mref.mref_ptr; + ModuleCurrVisArray[mptr->m_index] = flag; + } + + /* VMODULE instructions */ + switch(vptr->vmod_instr) + { + case vmodi_null: + vptr++; + break; + + case vmodi_bra_vc: + /* If the door/viewport is closed... */ + /* Branch to this vptr */ + /* else vptr++; */ + if(mptr) + { + if(mptr->m_flags & m_flag_open) vptr++; + else vptr = vptr->vmod_data.vmodidata_ptr; + } + break; + } + } +} + + +int ThisObjectIsInAModuleVisibleFromCurrentlyVisibleModules(STRATEGYBLOCK *sbPtr) +{ + VMODULE *vPtr; + + GLOBALASSERT(sbPtr); + GLOBALASSERT(sbPtr->containingModule); + + vPtr = sbPtr->containingModule->m_vmptr; + GLOBALASSERT(vPtr); + + if(ModuleCurrVisArray[sbPtr->containingModule->m_index] == 2) + { + return 1; + } + + while(vPtr->vmod_type != vmtype_term) + { + MODULE *mptr; + + /* consider this module */ + if(vPtr->vmod_mref.mref_ptr) + { + mptr = vPtr->vmod_mref.mref_ptr; + if(ModuleCurrVisArray[mptr->m_index] == 2) + { + if(vPtr->vmod_instr==vmodi_bra_vc) + { + if(mptr->m_flags & m_flag_open) return 1; + } + else + { + return 1; + } + } + } + + /* VMODULE instructions */ + switch(vPtr->vmod_instr) + { + case vmodi_null: + vPtr++; + break; + + case vmodi_bra_vc: + /* If the door/viewport is closed... */ + /* Branch to this vPtr */ + /* else vPtr++; */ + if(mptr) + { + if(mptr->m_flags & m_flag_open) vPtr++; + else vPtr = vPtr->vmod_data.vmodidata_ptr; + } + break; + } + } + + return 0; +} + + + + + +void ModuleFunctions(MODULE *mptr, MFUNCTION mf) +{ + switch(mf) + { + case mfun_null: + break; + } +} + + +void AllocateModuleObject(MODULE *mptr) +{ + + DISPLAYBLOCK *dptr; + MODULEMAPBLOCK *mapblockptr; + STRATEGYBLOCK *sb = 0; + + #if SupportMorphing + MORPHCTRL *mc; + #endif + + dptr_last = 0; + + mptr->m_dptr = 0; + + if(mptr == 0) return; /* Whoops! */ + + if(mptr->m_mapptr == 0) return; /* Not all modules have maps */ + + + dptr = CreateActiveObject(); + + + if(dptr) { + + + /* Tell the module we exist */ + + mptr->m_dptr = dptr; + + /* Tell the object who its module is */ + + dptr->ObMyModule = mptr; + + /* Get the strategy block, if it exists */ + + if(mptr->m_sbptr) sb = mptr->m_sbptr; + + /* If there is a STRATEGYBLOCK, tell it we exist */ + + if(sb) { + + dptr->ObStrategyBlock = sb; + sb->SBdptr = dptr; + + } + + + /* Read the map */ + + mapblockptr = mptr->m_mapptr; + + dptr->ObShape = mapblockptr->MapShape; + + + + CopyLocation(&mapblockptr->MapWorld, &dptr->ObWorld); + CopyEuler(&mapblockptr->MapEuler, &dptr->ObEuler); + + dptr->ObFlags = mapblockptr->MapFlags; + dptr->ObFlags2 = mapblockptr->MapFlags2; + dptr->ObFlags3 = mapblockptr->MapFlags3; + + + + + #if SupportMorphing + + /* If there is a strategy block, see if it has a MORPHCTRL structure */ + + if(sb) { + + if(sb->SBmorphctrl) { + + /* Pass MORPHCTRL to dptr */ + + dptr->ObMorphCtrl = sb->SBmorphctrl; + + /* Copy the morph pointer from the map to the dptr */ + + mc = dptr->ObMorphCtrl; + + mc->ObMorphHeader = mapblockptr->MapMorphHeader; + + /* OLD TEST - These values are now set elsewhere */ + #if 0 + if(mc->ObMorphHeader) { + mc->ObMorphCurrFrame = 0; + mc->ObMorphFlags = mph_flag_play/* | mph_flag_noloop | mph_flag_reverse*/; + mc->ObMorphSpeed = ONE_FIXED; + } + #endif + + } + + } + + #endif /* Support Morphing */ + + + #if InterfaceEngine + dbptr->o_chunk = mapblockptr->o_chunk; + #endif + + dptr->ObLightType = LightType_PerVertex; + dptr->ObFlags |= ObFlag_MultLSrc; + + + if(mapblockptr->MapVDBData) + MapSetVDB(dptr, mapblockptr->MapVDBData); + + dptr->ObLightType = mapblockptr->MapLightType; + + + MapBlockInit(dptr); + + /* KJL 14:15:34 04/19/97 - their used to be lots of maths here + to calculate orientation, but in AvP all modules are aligned to + the world space axes... */ + { + extern MATRIXCH IdentityMatrix; + dptr->ObMat = IdentityMatrix; + } + + + /* + + Module lights + + There is an option for a pointer to an array of lights in a module + structure. These lights are transferred to the display block and + flagged as "LFlag_WasNotAllocated" so that "DeallocateLightBlock()" + knows to ignore them. + + The number of lights in the array is "m_numlights" and the pointer + is called "m_lightarray". + + The addition of non-allocated does not need to be a module specific + option. + + Non-allocated lights can co-exist peacefully with the other lights. + + */ + + if(mptr->m_numlights && mptr->m_lightarray) { + + LIGHTBLOCK *lptr_array = mptr->m_lightarray; + int i; + + for(i = mptr->m_numlights; i!=0; i--) { + + /* Make sure the light is flagged correctly */ + + lptr_array->LightFlags |= LFlag_WasNotAllocated; + + /* Add the light */ + + AddLightBlock(dptr, lptr_array); + + /* Next light from the array */ + + lptr_array++; + + } + + } + + + + + /* + + As with shared points, extra item data for prelighting is also + copied from the module to the display block. + + WARNING: + + Allocation and deallocation of this pointer is the responsibility + of the user! + + */ + + dptr->ObEIDPtr = mptr->m_extraitemdata; + + /* Added Name to DISPLAYBLOCK */ + + #if SupportWindows95 + dptr->name = mptr->name; + #endif + + MapPostProcessing(dptr); + + + ModuleObjectJustAllocated(mptr); /* Project Function */ + + /* Bug Fix */ + + if (dptr->ObStrategyBlock) { + + STRATEGYBLOCK *sbptr=dptr->ObStrategyBlock; + + if (sbptr->I_SBtype==I_BehaviourSimpleAnimation) { + + SIMPLE_ANIM_BEHAV_BLOCK *sanimbhv; + + sanimbhv = (SIMPLE_ANIM_BEHAV_BLOCK*)(sbptr->SBdataptr); + + GLOBALASSERT(sanimbhv->bhvr_type == I_BehaviourSimpleAnimation); + GLOBALASSERT (dptr == sbptr->SBdptr); + + if(!dptr->ObTxAnimCtrlBlks) { + dptr->ObTxAnimCtrlBlks = sanimbhv->tacbSimple; + } + + } + + } + + } + + dptr_last = dptr; + +} + + +void DeallocateModuleObject(MODULE *mptr) + +{ + + DISPLAYBLOCK *dptr; + STRATEGYBLOCK *sb; + + + if(mptr->m_dptr) { + + ModuleObjectAboutToBeDeallocated(mptr); /* Project Function */ + + dptr = mptr->m_dptr; + + DestroyActiveObject(dptr); + + /* Clear module reference to dptr */ + + mptr->m_dptr = 0; + + /* If there is a STRATEGYBLOCK, clear that reference too */ + + if(mptr->m_sbptr) { + + sb = mptr->m_sbptr; + sb->SBdptr = 0; + + } + + } + +} + + +/* + + The Module Preprocessor + + Pass the array of pointers to modules. + This function creates module indices and converts names into pointers. + +*/ + +/* + temp patch to match current chunk + loader configuration +*/ + +void PreprocessAllModules(void) +{ + + SCENEMODULE **sm_array_ptr; + SCENEMODULE *sm_ptr; + + + if(Global_ModulePtr == 0) return; + + sm_array_ptr = Global_ModulePtr; + + while(*sm_array_ptr) + { + sm_ptr = *sm_array_ptr; + + PreprocessModuleArray(sm_ptr->sm_marray); + + sm_array_ptr++; + } +} + + + +/* + + A special function to deallocate the module visibility arrays + +*/ + +void DeallocateModuleVisArrays(void) + +{ + + if(ModuleCurrVisArray) { + + DeallocateMem(ModuleCurrVisArray); + ModuleCurrVisArray = 0; + + } + +} + + +/* + + Allocate the two arrays used to keep track of module visibility from + frame to frame. The function uses the global scene variable to access the + appropriate SCENEMODULE and find out how many modules are present. It also + deallocates the previous arrays if they exist. + +*/ + +int GetModuleVisArrays(void) + +{ + + SCENEMODULE *sm_ptr; + MODULE **m_array_ptr; + MODULE *m_ptr; + int index, i; + + + if(Global_ModulePtr == 0) return No; + + DeallocateModuleVisArrays(); + + sm_ptr = Global_ModulePtr[Global_Scene]; + + m_array_ptr = sm_ptr->sm_marray; + index = smallint; + + while(*m_array_ptr) { + + m_ptr = *m_array_ptr++; + if(m_ptr->m_index > index) index = m_ptr->m_index; + + } + + ModuleArraySize = index + 1; + + + ModuleCurrVisArray = AllocateMem(ModuleArraySize); + + if(ModuleCurrVisArray) + { + + for(i = 0; i < ModuleArraySize; i++) + { + + ModuleCurrVisArray[i] = 0; + } + + #if 0 + textprint("visibility arrays ok, size %d\n", ModuleArraySize); + #endif + + return Yes; + + } + + else return No; + +} + + + + +#define ppma_print No + + +#if 1 + + +void PreprocessModuleArray(MODULE **m_array_ptr) +{ + MODULE **m_array = m_array_ptr; + MODULE *m_ptr; + int index; + + + #if ppma_print + textprint("PreprocessModuleArray %u\n", m_array_ptr); + #endif + + + index = 0; + + while(*m_array) { + + /* Get the module pointer */ + + m_ptr = *m_array; + + + /* Assign the module an index */ + + m_ptr->m_index = index++; + + + #if ppma_print + textprint("\nModule %u, ", m_ptr); + PrintName(&m_ptr->m_name); + textprint(", index %d\n", m_ptr->m_index); + textprint(" (vptr = "); + PrintName(&m_ptr->m_vptr.mref_name); + textprint(")\n"); + #endif + + + /* Convert module references from names to pointers */ + + if(!(m_ptr->m_flags & m_flag_gotptrs)) { + + #if 0 + /* Vertical Pointer */ + + ConvertModuleNameToPointer(&m_ptr->m_vptr, m_array_ptr); + + + /* Extent Pointer */ + + ConvertModuleNameToPointer(&m_ptr->m_ext, m_array_ptr); + + + /* Function Pointer */ + + ConvertModuleNameToPointer(&m_ptr->m_funref, m_array_ptr); + + + // Hack by John to make the m_link pointers work + + if (m_ptr->m_link_ptrs) + { + MREF * m_link_ptr = m_ptr->m_link_ptrs; + + while (m_link_ptr->mref_ptr) + { + ConvertModuleNameToPointer(m_link_ptr++, m_array_ptr); + } + + } + #endif + /* VMODULE Array */ + + if(m_ptr->m_vmptr) { + + /* Convert VMODIDATA names to pointers */ + + PreprocessVMODIDATA(m_ptr->m_vmptr); + + /* Convert MREF names to pointers */ + /* + v_ptr = m_ptr->m_vmptr; + + while(v_ptr->vmod_type != vmtype_term) { + + ConvertModuleNameToPointer(&v_ptr->vmod_mref, m_array_ptr); + + v_ptr++; + + } + */ + } + + + /* Tell the module that its names are now pointers */ + + m_ptr->m_flags |= m_flag_gotptrs; + + } + + + /* Calculate module extents */ + + //I'll set the extents and world position in the loaders -Richard. + //GetModuleMapData(m_ptr); + + + /* Next module array entry */ + + m_array++; + + } + + /*WaitForReturn();*/ + +} + + +#else + + + + +#endif + + +/* + + VMODIDATA is the data associated with VMODI, the VMODULE instruction. Some + of the data items are names which need to be converted to pointers. + +*/ + +void PreprocessVMODIDATA(VMODULE *v_ptr) + +{ + + VMODULE *v_array_ptr = v_ptr; + + + while(v_ptr->vmod_type != vmtype_term) { + + if(!(v_ptr->vmod_flags & vm_flag_gotptrs)) { + + switch(v_ptr->vmod_instr) { + + case vmodi_null: + break; + + case vmodi_bra_vc: + ConvertVModuleNameToPointer(&v_ptr->vmod_data, v_array_ptr); + break; + + } + + v_ptr->vmod_flags |= vm_flag_gotptrs; + + } + + v_ptr++; + + } + +} + + +/* + + Convert MREF name to MREF pointer + +*/ + + +#define cmntp_print No + + +void ConvertModuleNameToPointer(MREF *mref_ptr, MODULE **m_array_ptr) + +{ + + MODULE *m_ptr; + int StillSearching; + + + #if cmntp_print + textprint("ConvertModuleNameToPointer\n"); + #endif + + + /* Set "null" names to null pointers */ + + if(CompareName((char *)&mref_ptr->mref_name, "null")) { + + #if cmntp_print + textprint("making ptr null\n"); + #endif + + mref_ptr->mref_ptr = 0; + return; + + } + + + /* Search for the module with the same name */ + + #if cmntp_print + textprint("Searching for name...\n"); + #endif + + StillSearching = Yes; + + while(*m_array_ptr && StillSearching) { + + m_ptr = *m_array_ptr; + + if(CompareName((char *)&mref_ptr->mref_name, (char *)&m_ptr->m_name)) { + + #if cmntp_print + textprint(" found name "); + PrintName(&m_ptr->m_name); + textprint(", ptr %u\n", m_ptr); + #endif + + mref_ptr->mref_ptr = m_ptr; + StillSearching = No; + + } + + m_array_ptr++; + + } + + + /* If the name was not found, make this a null pointer */ + + if(StillSearching) mref_ptr->mref_ptr = 0; + +} + + +/* + + Convert VMODIDATA.vmodidata_label names to VMODIDATA.vmodidata_ptr + +*/ + + +#define cvmntp_print No + + +void ConvertVModuleNameToPointer(VMODIDATA *vmodidata_ptr, VMODULE *v_array_ptr) + +{ + + int StillSearching; + + + #if cvmntp_print + textprint("ConvertVModuleNameToPointer\n"); + #endif + + + /* Set "null" names to null pointers */ + + if(CompareName((char *)&vmodidata_ptr->vmodidata_label, "null")) { + + #if cvmntp_print + textprint(" making vmodidata_ptr null\n"); + #endif + + vmodidata_ptr->vmodidata_ptr = 0; + return; + + } + + + /* Search for the VMODULE with the same name */ + + #if cvmntp_print + textprint(" Searching for name...\n"); + #endif + + StillSearching = Yes; + + while((v_array_ptr->vmod_type != vmtype_term) && StillSearching) { + + if(CompareName((char *)&vmodidata_ptr->vmodidata_label, (char *)&v_array_ptr->vmod_name)) { + + #if cmntp_print + textprint(" found name "); + PrintName(&v_array_ptr->vmod_name); + textprint(", ptr %u\n", v_array_ptr); + #endif + + vmodidata_ptr->vmodidata_ptr = v_array_ptr; + StillSearching = No; + + } + + v_array_ptr++; + + } + + + /* If the name was not found, make this a null pointer */ + + if(StillSearching) + { + if(v_array_ptr->vmod_type == vmtype_term) + { + vmodidata_ptr->vmodidata_ptr = v_array_ptr; + } + else + { + vmodidata_ptr->vmodidata_ptr = 0; + } + } + + +} + + + + +int CompareName(char *name1, char *name2) + +{ + + int i; + + + for(i = 4; i!=0; i--) { + + if(*name1++ != *name2++) return No; + + } + + return Yes; + +} + + +void PrintName(char *name) + +{ + + char m_name[5]; + + + m_name[0] = name[0]; + m_name[1] = name[1]; + m_name[2] = name[2]; + m_name[3] = name[3]; + m_name[4] = 0; + textprint(m_name); + +} + + +int IsModuleVisibleFromModule(MODULE *source, MODULE *target) { + + VMODULE *vptr; + MODULE *mptr; + int gotit; + + vptr=source->m_vmptr; + gotit=0; + + if ((source==NULL)||(target==NULL)) return(0); + if (source==target) return(1); + + while(! ((vptr->vmod_type == vmtype_term)||(gotit)) ) { + + /* Add this module to the visible array */ + + if(vptr->vmod_mref.mref_ptr) { + + mptr = vptr->vmod_mref.mref_ptr; + + if (mptr==target) gotit=1; + + } + + /* VMODULE instructions */ + + switch(vptr->vmod_instr) { + + case vmodi_null: + + vptr++; + + break; + + case vmodi_bra_vc: + + /* NYD */ + + /* If the door/viewport is closed... */ + + /* Branch to this vptr */ + + if(mptr) + { + if(mptr->m_flags & m_flag_open) + vptr++; + else + vptr = vptr->vmod_data.vmodidata_ptr; + } + + + + /* else vptr++; */ + + break; + + } + + } + + return(gotit); + +} + +int IsAIModuleVisibleFromAIModule(AIMODULE *source,AIMODULE *target) { + + if ((source==NULL)||(target==NULL)) return(0); + if (source==target) return(1); + + { + MODULE **targetModulelistPtr; + MODULE **sourceModulelistPtr = source->m_module_ptrs; + while(*sourceModulelistPtr) { + + targetModulelistPtr=target->m_module_ptrs; + while(*targetModulelistPtr) { + if (IsModuleVisibleFromModule(*sourceModulelistPtr,*targetModulelistPtr)) { + return(1); + } + targetModulelistPtr++; + } + sourceModulelistPtr++; + } + } + + return(0); +} + +#endif + + diff --git a/3dc/MORPH.C b/3dc/MORPH.C new file mode 100644 index 0000000..d868a50 --- /dev/null +++ b/3dc/MORPH.C @@ -0,0 +1,322 @@ +#include "3dc.h" + +#include "inline.h" + + +/* + externs for commonly used global variables and arrays +*/ + + extern MORPHDISPLAY MorphDisplay; + extern int NormalFrameTime; + + +/* + + Global Variables + +*/ + + + + + +/* + + Update Morphing Animation Control Block + +*/ + +void UpdateMorphing(MORPHCTRL *mcptr) + +{ + + MORPHHEADER *mhdr = mcptr->ObMorphHeader; + int UpdateRate; + + + /*textprint("UpdateMorphing\n");*/ + + + if(mcptr->ObMorphFlags & mph_flag_play) { + + /* How fast? */ + + if(mcptr->ObMorphSpeed == ONE_FIXED) { + + UpdateRate = NormalFrameTime; + + } + + else { + + UpdateRate = MUL_FIXED(NormalFrameTime, mcptr->ObMorphSpeed); + + } + + + /* Update the current frame */ + + if(mcptr->ObMorphFlags & mph_flag_reverse) { + + mcptr->ObMorphCurrFrame -= UpdateRate; + + if(mcptr->ObMorphCurrFrame < 0) { + + if(mcptr->ObMorphFlags & mph_flag_noloop) { + + mcptr->ObMorphCurrFrame = 0; + + /* The sequence has finished and we are at the start */ + + mcptr->ObMorphFlags |= (mph_flag_finished | mph_flag_start); + + } + + else { + + mcptr->ObMorphCurrFrame += mhdr->mph_maxframes; + + /* The sequence has looped and we are back at the end */ + + mcptr->ObMorphFlags |= (mph_flag_looped | mph_flag_end); + + } + + } + + } + + else { + + mcptr->ObMorphCurrFrame += UpdateRate; + + if(mcptr->ObMorphCurrFrame >= mhdr->mph_maxframes) { + + if(mcptr->ObMorphFlags & mph_flag_noloop) { + + /* The sequence has finished and we are at the end */ + + mcptr->ObMorphFlags |= (mph_flag_finished | mph_flag_end); + + mcptr->ObMorphCurrFrame = mhdr->mph_maxframes - 1; + + } + + else { + + mcptr->ObMorphCurrFrame -= mhdr->mph_maxframes; + + /* The sequence has looped and we are back at the start */ + + mcptr->ObMorphFlags |= (mph_flag_looped | mph_flag_start); + + } + + } + + } + + } + +} + + + +/* + + Update the Morphing Animation for this object + +*/ + +void UpdateMorphingDptr(DISPLAYBLOCK *dptr) + +{ + + SHAPEHEADER *sptr1; + SHAPEHEADER *sptr2; + + + /* Update object radius and extents */ + + GetMorphDisplay(&MorphDisplay, dptr); + + sptr1 = MorphDisplay.md_sptr1; + sptr2 = MorphDisplay.md_sptr2; + + #if 0 + textprint("sptr1->shaperadius = %d\n", sptr1->shaperadius); + textprint("sptr2->shaperadius = %d\n", sptr2->shaperadius); + #endif + + + /* Radius */ + + if(sptr1->shaperadius == sptr2->shaperadius) { + + dptr->ObRadius = sptr1->shaperadius; + + } + + else { + + dptr->ObRadius = WideMul2NarrowDiv(sptr1->shaperadius, + MorphDisplay.md_one_minus_lerp, + sptr2->shaperadius, + MorphDisplay.md_lerp, ONE_FIXED); + + } + + + /* X Extent */ + + if(sptr1->shapemaxx == sptr2->shapemaxx) { + + dptr->ObMaxX = sptr1->shapemaxx; + + } + + else { + + dptr->ObMaxX = WideMul2NarrowDiv(sptr1->shapemaxx, + MorphDisplay.md_one_minus_lerp, + sptr2->shapemaxx, + MorphDisplay.md_lerp, ONE_FIXED); + + } + + if(sptr1->shapeminx == sptr2->shapeminx) { + + dptr->ObMinX = sptr1->shapeminx; + + } + + else { + + dptr->ObMinX = WideMul2NarrowDiv(sptr1->shapeminx, + MorphDisplay.md_one_minus_lerp, + sptr2->shapeminx, + MorphDisplay.md_lerp, ONE_FIXED); + + } + + + /* Y Extent */ + + if(sptr1->shapemaxy == sptr2->shapemaxy) { + + dptr->ObMaxY = sptr1->shapemaxy; + + } + + else { + + dptr->ObMaxY = WideMul2NarrowDiv(sptr1->shapemaxy, + MorphDisplay.md_one_minus_lerp, + sptr2->shapemaxy, + MorphDisplay.md_lerp, ONE_FIXED); + + } + + if(sptr1->shapeminy == sptr2->shapeminy) { + + dptr->ObMinY = sptr1->shapeminy; + + } + + else { + + dptr->ObMinY = WideMul2NarrowDiv(sptr1->shapeminy, + MorphDisplay.md_one_minus_lerp, + sptr2->shapeminy, + MorphDisplay.md_lerp, ONE_FIXED); + + } + + + /* Z Extent */ + + if(sptr1->shapemaxz == sptr2->shapemaxz) { + + dptr->ObMaxZ = sptr1->shapemaxz; + + } + + else { + + dptr->ObMaxZ = WideMul2NarrowDiv(sptr1->shapemaxz, + MorphDisplay.md_one_minus_lerp, + sptr2->shapemaxz, + MorphDisplay.md_lerp, ONE_FIXED); + + } + + if(sptr1->shapeminz == sptr2->shapeminz) { + + dptr->ObMinZ = sptr1->shapeminz; + + } + + else { + + dptr->ObMinZ = WideMul2NarrowDiv(sptr1->shapeminz, + MorphDisplay.md_one_minus_lerp, + sptr2->shapeminz, + MorphDisplay.md_lerp, ONE_FIXED); + + } + + #if 0 + textprint("dptr->ObRadius = %d\n", dptr->ObRadius); + #endif + +} + + + +/* + + Using the current frame, calculate the lerp values and find out which two + shapes to interpolate between. + + Write this information back to a MORPHDISPLAY structure. + +*/ + +void GetMorphDisplay(MORPHDISPLAY *md, DISPLAYBLOCK *dptr) + +{ + + MORPHFRAME *mdata; + MORPHCTRL *mc = dptr->ObMorphCtrl; + MORPHHEADER *mhdr = mc->ObMorphHeader; + + + md->md_lerp = mc->ObMorphCurrFrame & 0xffff; + md->md_one_minus_lerp = ONE_FIXED - md->md_lerp; + + mdata = mhdr->mph_frames; + mdata = &mdata[mc->ObMorphCurrFrame >> 16]; + + md->md_shape1 = mdata->mf_shape1; + md->md_shape2 = mdata->mf_shape2; + + md->md_sptr1 = GetShapeData(md->md_shape1); + md->md_sptr2 = GetShapeData(md->md_shape2); + +} + + +void CopyMorphCtrl(MORPHCTRL *src, MORPHCTRL *dst) + +{ + + dst->ObMorphCurrFrame = src->ObMorphCurrFrame; + dst->ObMorphFlags = src->ObMorphFlags; + dst->ObMorphSpeed = src->ObMorphSpeed; + dst->ObMorphHeader = src->ObMorphHeader; + +} + + + \ No newline at end of file diff --git a/3dc/MSLHAND.C b/3dc/MSLHAND.C new file mode 100644 index 0000000..fe1e8ca --- /dev/null +++ b/3dc/MSLHAND.C @@ -0,0 +1,187 @@ +#include "3dc.h" + +#include "mslhand.h" + +#if PSX +#include "psx_inc.h" +#endif + +#define UseLocalAssert 1 +#include "ourasert.h" + +extern SHAPEHEADER * mainshapelist[]; + +static int begins[ MSLS_MAXSECTIONS ]; +static int ends[ MSLS_MAXSECTIONS ]; + +static int autodelete[ maxobjects ]; + +#define MSS_FREE (-1) + +static void EnsureInitialized(void) +{ + static int initialized = 0; + + if (!initialized) + { + int i; + + initialized = 1; + + for (i=0; i=0 ? ends[i] : 0; + } + + blockstart = ends[sect]; + /* can use a local assert here to fail on a mainshapelist overflow, otherwise return error code */ + LOCALASSERT(ends[sect] + num_shapes <= maxend); + if (ends[sect] + num_shapes > maxend ) return MSL_OVERFLOW; + ends[sect] += num_shapes; + + for (i=blockstart; ipoints) + { + if (*shp->points) free(*shp->points); + free(shp->points); + } + if (shp->sh_normals) + { + if (*shp->sh_normals) free(*shp->sh_normals); + free(shp->sh_normals); + } + if (shp->sh_vnormals) + { + if (*shp->sh_vnormals) free(*shp->sh_vnormals); + free(shp->sh_vnormals); + } + if (shp->sh_extraitemdata) + free(shp->sh_extraitemdata); + /* the items are allocated in one big bunch + // 9 int's per item (to make bsp simple) + // this should be changed if it is to be done + // a different way + */ + if (shp->items) + { + for (i=0; inumitems; i++) + { + if (shp->items[i][0] == 5 || shp->items[i][0] == 6) + { + int UVIndex = (shp->items[i][3] &0xffff0000) >> 16; + max_num_texs = max (max_num_texs, shp->items[i][3] &0x7fff); + if(shp->items[i][2]& iflag_txanim) + { + int j; + TXANIMHEADER** thlist=(TXANIMHEADER**)shp->sh_textures[UVIndex]; + for(j=1;thlist[j]!=0;j++) + { + int k; + TXANIMHEADER* th=thlist[j]; + for(k=0;ktxa_numframes;k++) + { + free(th->txa_framedata[k].txf_uvdata); + } + free (th->txa_framedata); + free (th); + } + free (thlist); + shp->sh_textures[UVIndex]=0; + } + else + { + free(shp->sh_textures[UVIndex]); + } + } + } + + free (*shp->items); + free (shp->items); + } + + if (shp->sh_textures) + { + free (shp->sh_textures); + } + + if (shp->sh_localtextures) + { + for (i=0; i<(max_num_texs+1); i++) + { + free (shp->sh_localtextures[i]); + } + free (shp->sh_localtextures); + } + + if (shp->sh_instruction) + free(shp->sh_instruction); + + free(shp); + } + mainshapelist[i]=0; + autodelete[i]=0; + } + + begins[sect]=MSS_FREE; + ends[sect]=MSS_FREE; + +#else + +printf("\nDo NOT call this function!\n"); +//GLOBALASSERT(1==0); + +#endif + +} diff --git a/3dc/MSLHAND.H b/3dc/MSLHAND.H new file mode 100644 index 0000000..bb08334 --- /dev/null +++ b/3dc/MSLHAND.H @@ -0,0 +1,28 @@ +#ifndef _included_mslhand_h_ +#define _included_mslhand_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum MSL_Section +{ + MSLS_COMPILEDIN, + MSLS_CHARACTER, + MSLS_ENVIRONMENT, + + MSLS_MAXSECTIONS + +} MSL_SECTION; + +#define MSL_OVERFLOW (-1) + +int GetNextMSLEntry(MSL_SECTION, unsigned int num_shapes, int auto_delete); + +void FlushMSLSection(MSL_SECTION); + +#ifdef __cplusplus +} +#endif + +#endif /* !_included_mslhand_h_ */ diff --git a/3dc/Maths.c b/3dc/Maths.c new file mode 100644 index 0000000..5cd3f49 --- /dev/null +++ b/3dc/Maths.c @@ -0,0 +1,2944 @@ + +#if PSX +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "3dc.h" +#include "inline.h" + +#define UseTimsPinp Yes + +#define trip_debugger No + +#if trip_debugger +int testa = 0; +int testb = 100; +int testc = 0; +#endif + + +/* + + externs for commonly used global variables and arrays + +*/ + + #if platform_pc + extern int sine[]; + extern int cosine[]; + #endif + + extern short ArcCosTable[]; + extern short ArcSineTable[]; + extern short ArcTanTable[]; + + extern LONGLONGCH ll_zero; + + extern int NormalFrameTime; + + +#if PSX +extern unsigned long *scratchp; +#endif + +/* + + Globals + +*/ + + MATRIXCH IdentityMatrix = { + + ONE_FIXED, 0, 0, + 0, ONE_FIXED, 0, + 0, 0, ONE_FIXED + + }; + + + +/* + + Maths functions used by the system + +*/ + + + +#if PSX +inline void ch2psx(MATRIXCH *chm, MATRIX *psxm) +{ + psxm->m[0][0] = chm->mat11 >> 4; + psxm->m[0][1] = chm->mat21 >> 4; + psxm->m[0][2] = chm->mat31 >> 4; + psxm->m[1][0] = chm->mat12 >> 4; + psxm->m[1][1] = chm->mat22 >> 4; + psxm->m[1][2] = chm->mat32 >> 4; + psxm->m[2][0] = chm->mat13 >> 4; + psxm->m[2][1] = chm->mat23 >> 4; + psxm->m[2][2] = chm->mat33 >> 4; +} + +inline void psx2ch(MATRIX *psxm, MATRIXCH *chm) +{ + + chm->mat11 = psxm->m[0][0] << 4; + chm->mat21 = psxm->m[0][1] << 4; + chm->mat31 = psxm->m[0][2] << 4; + chm->mat12 = psxm->m[1][0] << 4; + chm->mat22 = psxm->m[1][1] << 4; + chm->mat32 = psxm->m[1][2] << 4; + chm->mat13 = psxm->m[2][0] << 4; + chm->mat23 = psxm->m[2][1] << 4; + chm->mat33 = psxm->m[2][2] << 4; +} + +#endif + +/* One over sin functions - CDF 4/2/98 */ + +extern int oneoversin[4096]; + +void ConstructOneOverSinTable(void) { + + int a,sin; + + for (a=0; a<4096; a++) { + sin=GetSin(a); + + if (sin!=0) { + oneoversin[a]=DIV_FIXED(ONE_FIXED,sin); + } else { + sin=100; + oneoversin[a]=DIV_FIXED(ONE_FIXED,sin); + } + } + +} + +int GetOneOverSin(int a) { + + int b; + + b=a&wrap360; + + return(oneoversin[b]); + +} + +/* + + Dot Product Function + + It accepts two pointers to vectors and returns an int result + +*/ + +int _DotProduct(VECTORCH *vptr1, VECTORCH *vptr2) + +{ + + int dp; + + dp = MUL_FIXED(vptr1->vx, vptr2->vx); + dp += MUL_FIXED(vptr1->vy, vptr2->vy); + dp += MUL_FIXED(vptr1->vz, vptr2->vz); + + return(dp); + +} + + +int DotProduct2d(VECTOR2D *vptr1, VECTOR2D *vptr2) + +{ + + int dp; + + + dp = MUL_FIXED(vptr1->vx, vptr2->vx); + dp += MUL_FIXED(vptr1->vy, vptr2->vy); + + return dp; + +} + + +/* + + This function returns the distance between two vectors + +*/ + +int VectorDistance(VECTORCH *v1, VECTORCH *v2) + +{ + + VECTORCH v; + + + v.vx = v1->vx - v2->vx; + v.vy = v1->vy - v2->vy; + v.vz = v1->vz - v2->vz; + + return Magnitude(&v); + +} + + +/* + + This function compares the distance between two vectors along each of + the major axes and returns Yes or No if they are within the cube defined + by the argument passed. + +*/ + +int OutcodeVectorDistance(VECTORCH *v1, VECTORCH *v2, int d) + +{ + + int i; + + + i = v1->vx - v2->vx; + if(i < 0) i = -i; + + if(i >= d) return No; + + i = v1->vy - v2->vy; + if(i < 0) i = -i; + + if(i >= d) return No; + + i = v1->vz - v2->vz; + if(i < 0) i = -i; + + if(i >= d) return No; + + return Yes; + +} + + +/* + + Subtract one VECTORCH from another and return the result as a normal + + v3 = Normal(v1 - v2) + +*/ + +void GetNormalVector(VECTORCH *v1, VECTORCH *v2, VECTORCH *v3) + +{ + + v3->vx = v1->vx - v2->vx; + v3->vy = v1->vy - v2->vy; + v3->vz = v1->vz - v2->vz; + + Normalise(v3); + +} + + +/* + + Normalise a vector close to, but less than, unit length + +*/ + +void Renormalise(VECTORCH *nvector) + +{ + + int m; + int xsq, ysq, zsq; + + +/* Scale x, y and z */ + + nvector->vx >>= 2; + nvector->vy >>= 2; + nvector->vz >>= 2; + + +/* Normalise */ + + xsq = nvector->vx * nvector->vx; + ysq = nvector->vy * nvector->vy; + zsq = nvector->vz * nvector->vz; + + m = SqRoot32(xsq + ysq + zsq); + + if(m == 0) m = 1; /* Just in case */ + + nvector->vx = (nvector->vx * ONE_FIXED) / m; + nvector->vy = (nvector->vy * ONE_FIXED) / m; + nvector->vz = (nvector->vz * ONE_FIXED) / m; + +} + + + + + + + + + +/* + + Return the shift value required to get one value LTE the other value + +*/ + +int FindShift32(int value, int limit) + +{ + + int shift = 0; + + + /*if(limit == 0) exit(0xfa11fa11);*/ + + + if(value < 0) value = -value; + + while(value > limit) { + + #if trip_debugger + if(shift > 32) { + testa = testb / testc; + } + #endif + + shift++; + + value >>= 1; + + } + + return shift; + +} + + +/* + + Return the largest value of an int array + +*/ + +int MaxInt(int *iarray, int iarraysize) + +{ + + int imax = smallint; + int i; + + for(i = iarraysize; i!=0; i--) { + + if(imax < *iarray) imax = *iarray; + + iarray++; + + } + + return imax; + +} + + +/* + + Return the smallest value of an int array + +*/ + +int MinInt(int *iarray, int iarraysize) + +{ + + int imin = bigint; + int i; + + for(i = iarraysize; i!=0; i--) { + + if(imin > *iarray) imin = *iarray; + + iarray++; + + } + + return imin; + +} + + + +/* + + Create Matrix from Euler Angles + + It requires a pointer to some euler angles and a pointer to a matrix + + Construct the matrix elements using the following formula + + Formula for ZXY Matrix + + m11 = cy*cz + sx*sy*sz m12 = -cy*sz + sx*sy*cz m13 = cx*sy + m21 = cx*sz m22 = cx*cz m23 = -sx + m31 = -sy*cz + sx*cy*sz m32 = sy*sz + sx*cy*cz m33 = cx*cy + +*/ + +void CreateEulerMatrix(e, m1) + + EULER *e; + MATRIXCH *m1; + +{ + +#if 0 + + SVECTOR eulers; + + eulers.vx=(e->EulerX)&4095; + eulers.vy=(e->EulerY)&4095; + eulers.vz=(e->EulerZ)&4095; + + RotMatrix(&eulers,(MATRIX *)scratchp); + + psx2ch((MATRIX *)scratchp,m1); + +#else + + int t, sx, sy, sz, cx, cy, cz; + + + sx = GetSin(e->EulerX); + sy = GetSin(e->EulerY); + sz = GetSin(e->EulerZ); + + cx = GetCos(e->EulerX); + cy = GetCos(e->EulerY); + cz = GetCos(e->EulerZ); + + + #if 0 + textprint("Euler Matrix Sines & Cosines\n"); + textprint("%d, %d, %d\n", sx, sy, sz); + textprint("%d, %d, %d\n", cx, cy, cz); + #endif + + +/* m11 = cy*cz + sx*sy*sz */ + + m1->mat11 = MUL_FIXED(cy, cz); /* cy*cz */ + t = MUL_FIXED(sx, sy); /* sx*sy */ + t = MUL_FIXED(t, sz); /* *sz */ + m1->mat11 += t; + + +/* m12 = -cy*sz + sx*sy*cz */ + + m1->mat12=MUL_FIXED(-cy,sz); + t=MUL_FIXED(sx,sy); + t=MUL_FIXED(t,cz); + m1->mat12+=t; + + +/* m13 = cx*sy */ + + m1->mat13=MUL_FIXED(cx,sy); + + +/* m21 = cx*sz */ + + m1->mat21=MUL_FIXED(cx,sz); + + +/* m22 = cx*cz */ + + m1->mat22=MUL_FIXED(cx,cz); + + +/* m23 = -sx */ + + m1->mat23=-sx; + + +/* m31 = -sy*cz + sx*cy*sz */ + + m1->mat31=MUL_FIXED(-sy,cz); + t=MUL_FIXED(sx,cy); + t=MUL_FIXED(t,sz); + m1->mat31+=t; + + +/* m32 = sy*sz + sx*cy*cz */ + + m1->mat32=MUL_FIXED(sy,sz); + t=MUL_FIXED(sx,cy); + t=MUL_FIXED(t,cz); + m1->mat32+=t; + + +/* m33 = cx*cy */ + + m1->mat33=MUL_FIXED(cx,cy); + +#endif + +} + + +/* + + Create a Unit Vector from three Euler Angles + +*/ + +void CreateEulerVector(EULER *e, VECTORCH *v) + +{ + + int t, sx, sy, sz, cx, cy, cz; + + + sx = GetSin(e->EulerX); + sy = GetSin(e->EulerY); + sz = GetSin(e->EulerZ); + + cx = GetCos(e->EulerX); + cy = GetCos(e->EulerY); + cz = GetCos(e->EulerZ); + + + /* x = -sy*cz + sx*cy*sz */ + + v->vx = MUL_FIXED(-sy, cz); + t = MUL_FIXED(sx, cy); + t = MUL_FIXED(t, sz); + v->vx += t; + + + /* y = sy*sz + sx*cy*cz */ + + v->vy = MUL_FIXED(sy, sz); + t = MUL_FIXED(sx, cy); + t = MUL_FIXED(t, cz); + v->vy += t; + + + /* z = cx*cy */ + + v->vz = MUL_FIXED(cx,cy); + +} + + + +/* + + Matrix Multiply Function + + A 3x3 Matrix is represented here as + + m11 m12 m13 + m21 m22 m23 + m31 m32 m33 + + Row #1 (r1) of the matrix is m11 m12 m13 + Column #1 (c1) of the matrix is m11 m32 m31 + + Under multiplication + + m'' = m x m' + + where + + m11'' = c1.r1' + m12'' = c2.r1' + m13'' = c3.r1' + + m21'' = c1.r2' + m22'' = c2.r2' + m23'' = c3.r2' + + m31'' = c1.r3' + m32'' = c2.r3' + m33'' = c3.r3' + +*/ + +void MatrixMultiply(m1, m2, m3) + + struct matrixch *m1, *m2, *m3; + +{ + + #if 0 + + PushMatrix(); + + ch2psx(m1,(MATRIX *)scratchp); + ch2psx(m2,(MATRIX *)(scratchp+(sizeof(MATRIX)))); + + MulMatrix0((MATRIX *)scratchp,(MATRIX *)(scratchp+(sizeof(MATRIX))),(MATRIX *)(scratchp+((sizeof(MATRIX)<<1)))); + + psx2ch((MATRIX *)(scratchp+((sizeof(MATRIX)<<1))),m3); + + PopMatrix(); + + #else + + MATRIXCH TmpMat; + +/* m11'' = c1.r1' */ + + TmpMat.mat11=MUL_FIXED(m1->mat11,m2->mat11); + TmpMat.mat11+=MUL_FIXED(m1->mat21,m2->mat12); + TmpMat.mat11+=MUL_FIXED(m1->mat31,m2->mat13); + +/* m12'' = c2.r1' */ + + TmpMat.mat12=MUL_FIXED(m1->mat12,m2->mat11); + TmpMat.mat12+=MUL_FIXED(m1->mat22,m2->mat12); + TmpMat.mat12+=MUL_FIXED(m1->mat32,m2->mat13); + +/* m13'' = c3.r1' */ + + TmpMat.mat13=MUL_FIXED(m1->mat13,m2->mat11); + TmpMat.mat13+=MUL_FIXED(m1->mat23,m2->mat12); + TmpMat.mat13+=MUL_FIXED(m1->mat33,m2->mat13); + +/* m21'' = c1.r2' */ + + TmpMat.mat21=MUL_FIXED(m1->mat11,m2->mat21); + TmpMat.mat21+=MUL_FIXED(m1->mat21,m2->mat22); + TmpMat.mat21+=MUL_FIXED(m1->mat31,m2->mat23); + +/* m22'' = c2.r2' */ + + TmpMat.mat22=MUL_FIXED(m1->mat12,m2->mat21); + TmpMat.mat22+=MUL_FIXED(m1->mat22,m2->mat22); + TmpMat.mat22+=MUL_FIXED(m1->mat32,m2->mat23); + +/* m23'' = c3.r2' */ + + TmpMat.mat23=MUL_FIXED(m1->mat13,m2->mat21); + TmpMat.mat23+=MUL_FIXED(m1->mat23,m2->mat22); + TmpMat.mat23+=MUL_FIXED(m1->mat33,m2->mat23); + +/* m31'' = c1.r3' */ + + TmpMat.mat31=MUL_FIXED(m1->mat11,m2->mat31); + TmpMat.mat31+=MUL_FIXED(m1->mat21,m2->mat32); + TmpMat.mat31+=MUL_FIXED(m1->mat31,m2->mat33); + +/* m32'' = c2.r3' */ + + TmpMat.mat32=MUL_FIXED(m1->mat12,m2->mat31); + TmpMat.mat32+=MUL_FIXED(m1->mat22,m2->mat32); + TmpMat.mat32+=MUL_FIXED(m1->mat32,m2->mat33); + +/* m33'' = c3.r3' */ + + TmpMat.mat33=MUL_FIXED(m1->mat13,m2->mat31); + TmpMat.mat33+=MUL_FIXED(m1->mat23,m2->mat32); + TmpMat.mat33+=MUL_FIXED(m1->mat33,m2->mat33); + +/* Finally, copy TmpMat to m3 */ + + CopyMatrix(&TmpMat, m3); + + #endif + +} + + +void PSXAccurateMatrixMultiply(m1, m2, m3) + + struct matrixch *m1, *m2, *m3; + +{ + + MATRIXCH TmpMat; + +/* m11'' = c1.r1' */ + + TmpMat.mat11=MUL_FIXED(m1->mat11,m2->mat11); + TmpMat.mat11+=MUL_FIXED(m1->mat21,m2->mat12); + TmpMat.mat11+=MUL_FIXED(m1->mat31,m2->mat13); + +/* m12'' = c2.r1' */ + + TmpMat.mat12=MUL_FIXED(m1->mat12,m2->mat11); + TmpMat.mat12+=MUL_FIXED(m1->mat22,m2->mat12); + TmpMat.mat12+=MUL_FIXED(m1->mat32,m2->mat13); + +/* m13'' = c3.r1' */ + + TmpMat.mat13=MUL_FIXED(m1->mat13,m2->mat11); + TmpMat.mat13+=MUL_FIXED(m1->mat23,m2->mat12); + TmpMat.mat13+=MUL_FIXED(m1->mat33,m2->mat13); + +/* m21'' = c1.r2' */ + + TmpMat.mat21=MUL_FIXED(m1->mat11,m2->mat21); + TmpMat.mat21+=MUL_FIXED(m1->mat21,m2->mat22); + TmpMat.mat21+=MUL_FIXED(m1->mat31,m2->mat23); + +/* m22'' = c2.r2' */ + + TmpMat.mat22=MUL_FIXED(m1->mat12,m2->mat21); + TmpMat.mat22+=MUL_FIXED(m1->mat22,m2->mat22); + TmpMat.mat22+=MUL_FIXED(m1->mat32,m2->mat23); + +/* m23'' = c3.r2' */ + + TmpMat.mat23=MUL_FIXED(m1->mat13,m2->mat21); + TmpMat.mat23+=MUL_FIXED(m1->mat23,m2->mat22); + TmpMat.mat23+=MUL_FIXED(m1->mat33,m2->mat23); + +/* m31'' = c1.r3' */ + + TmpMat.mat31=MUL_FIXED(m1->mat11,m2->mat31); + TmpMat.mat31+=MUL_FIXED(m1->mat21,m2->mat32); + TmpMat.mat31+=MUL_FIXED(m1->mat31,m2->mat33); + +/* m32'' = c2.r3' */ + + TmpMat.mat32=MUL_FIXED(m1->mat12,m2->mat31); + TmpMat.mat32+=MUL_FIXED(m1->mat22,m2->mat32); + TmpMat.mat32+=MUL_FIXED(m1->mat32,m2->mat33); + +/* m33'' = c3.r3' */ + + TmpMat.mat33=MUL_FIXED(m1->mat13,m2->mat31); + TmpMat.mat33+=MUL_FIXED(m1->mat23,m2->mat32); + TmpMat.mat33+=MUL_FIXED(m1->mat33,m2->mat33); + +/* Finally, copy TmpMat to m3 */ + + CopyMatrix(&TmpMat, m3); + +} + + + + + +/* + + Transpose Matrix + +*/ + +void TransposeMatrixCH(m1) + + MATRIXCH *m1; + +{ + + int t; + + t=m1->mat12; + m1->mat12=m1->mat21; + m1->mat21=t; + + t=m1->mat13; + m1->mat13=m1->mat31; + m1->mat31=t; + + t=m1->mat23; + m1->mat23=m1->mat32; + m1->mat32=t; + +} + + +/* + + Copy Vector + +*/ + +void CopyVector(VECTORCH *v1, VECTORCH *v2) + +{ + +/* Copy VECTORCH v1 -> VECTORCH v2 */ + + v2->vx=v1->vx; + v2->vy=v1->vy; + v2->vz=v1->vz; + +} + + +/* + + Copy Location + +*/ + +void CopyLocation(VECTORCH *v1, VECTORCH *v2) + +{ + +/* Copy VECTORCH v1 -> VECTORCH v2 */ + + v2->vx=v1->vx; + v2->vy=v1->vy; + v2->vz=v1->vz; + +} + + + + + +/* + + Copy Euler + +*/ + +void CopyEuler(EULER *e1, EULER *e2) + +{ + +/* Copy EULER e1 -> EULER e2 */ + + e2->EulerX=e1->EulerX; + e2->EulerY=e1->EulerY; + e2->EulerZ=e1->EulerZ; + +} + + +/* + + Copy Matrix + +*/ + +void CopyMatrix(MATRIXCH *m1, MATRIXCH *m2) + +{ + +/* Copy MATRIXCH m1 -> MATRIXCH m2 */ + + m2->mat11=m1->mat11; + m2->mat12=m1->mat12; + m2->mat13=m1->mat13; + + m2->mat21=m1->mat21; + m2->mat22=m1->mat22; + m2->mat23=m1->mat23; + + m2->mat31=m1->mat31; + m2->mat32=m1->mat32; + m2->mat33=m1->mat33; + +} + + +/* + + Make a Vector. + + v3 = v1 - v2 + +*/ + +void MakeVector(VECTORCH *v1, VECTORCH *v2, VECTORCH *v3) + +{ + + v3->vx = v1->vx - v2->vx; + v3->vy = v1->vy - v2->vy; + v3->vz = v1->vz - v2->vz; + +} + + +/* + + Add a Vector. + + v2 = v2 + v1 + +*/ + +void AddVector(VECTORCH *v1, VECTORCH *v2) + +{ + + v2->vx += v1->vx; + v2->vy += v1->vy; + v2->vz += v1->vz; + +} + + +/* + + Subtract a Vector. + + v2 = v2 - v1 + +*/ + +void SubVector(VECTORCH *v1, VECTORCH *v2) + +{ + + v2->vx -= v1->vx; + v2->vy -= v1->vy; + v2->vz -= v1->vz; + +} + + + +/* + + Matrix Rotatation of a Vector + + Overwrite the Source Vector with the Rotated Vector + + x' = v.c1 + y' = v.c2 + z' = v.c3 + +*/ + +void _RotateVector(VECTORCH *v, MATRIXCH* m) +{ + + int x, y, z; + + + x = MUL_FIXED(m->mat11, v->vx); + x += MUL_FIXED(m->mat21, v->vy); + x += MUL_FIXED(m->mat31, v->vz); + + y = MUL_FIXED(m->mat12, v->vx); + y += MUL_FIXED(m->mat22, v->vy); + y += MUL_FIXED(m->mat32, v->vz); + + z = MUL_FIXED(m->mat13, v->vx); + z += MUL_FIXED(m->mat23, v->vy); + z += MUL_FIXED(m->mat33, v->vz); + + v->vx = x; + v->vy = y; + v->vz = z; +} + + +/* + + Matrix Rotation of a Source Vector using a Matrix + Copying to a Destination Vector + + x' = v.c1 + y' = v.c2 + z' = v.c3 + +*/ + +void _RotateAndCopyVector(v1, v2, m) + + VECTORCH *v1; + VECTORCH *v2; + MATRIXCH *m; + +{ + + v2->vx=MUL_FIXED(m->mat11,v1->vx); + v2->vx+=MUL_FIXED(m->mat21,v1->vy); + v2->vx+=MUL_FIXED(m->mat31,v1->vz); + + v2->vy=MUL_FIXED(m->mat12,v1->vx); + v2->vy+=MUL_FIXED(m->mat22,v1->vy); + v2->vy+=MUL_FIXED(m->mat32,v1->vz); + + v2->vz=MUL_FIXED(m->mat13,v1->vx); + v2->vz+=MUL_FIXED(m->mat23,v1->vy); + v2->vz+=MUL_FIXED(m->mat33,v1->vz); + +} + + + + + + +/* + + Matrix to Euler Angles + + Maths overflow is a real problem for this function. To prevent overflows + the matrix Sines and Cosines are calculated using values scaled down by 4. + + + sinx = -M23 + + cosx = sqr ( 1 - sinx^2 ) + + + siny = M13 / cosx + + cosy = M33 / cosx + + + sinz = M21 / cosx + + cosz = M22 / cosx + + +*/ + + +#define m2e_scale 2 +#define ONE_FIXED_S ((ONE_FIXED >> m2e_scale) - 1) +#define m2e_shift 14 + +#define j_and_r_change Yes + + +void MatrixToEuler(MATRIXCH *m, EULER *e) + +{ + + int x, sinx, cosx, siny, cosy, sinz, cosz; + int abs_cosx, abs_cosy, abs_cosz; + int SineMatrixPitch, SineMatrixYaw, SineMatrixRoll; + int CosMatrixPitch, CosMatrixYaw, CosMatrixRoll; + + + + + #if 0 + textprint("CosMatrixPitch = %d\n", CosMatrixPitch); + /* WaitForReturn(); */ + #endif + + + if(m->mat32 >-65500 && m->mat32<65500) + { + /* Yaw */ + + /* Pitch */ + + #if j_and_r_change + SineMatrixPitch = -m->mat32; + #else + SineMatrixPitch = -m->mat23; + #endif + + SineMatrixPitch >>= m2e_scale; + + #if 0 + textprint("SineMatrixPitch = %d\n", SineMatrixPitch); + /* WaitForReturn(); */ + #endif + + CosMatrixPitch = SineMatrixPitch * SineMatrixPitch; + CosMatrixPitch >>= m2e_shift; + + CosMatrixPitch = -CosMatrixPitch; + CosMatrixPitch += ONE_FIXED_S; + CosMatrixPitch *= ONE_FIXED_S; + CosMatrixPitch = SqRoot32(CosMatrixPitch); + + if(CosMatrixPitch) { + + if(CosMatrixPitch > ONE_FIXED_S) CosMatrixPitch = ONE_FIXED_S; + else if(CosMatrixPitch < -ONE_FIXED_S) CosMatrixPitch = -ONE_FIXED_S; + + } + + else CosMatrixPitch = 1; + + SineMatrixYaw = WideMulNarrowDiv( + #if j_and_r_change + m->mat31 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); + #else + m->mat13 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); + #endif + + #if 0 + textprint("SineMatrixYaw = %d\n", SineMatrixYaw); + /* WaitForReturn(); */ + #endif + + CosMatrixYaw = WideMulNarrowDiv( + m->mat33 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); + + #if 0 + textprint("CosMatrixYaw = %d\n", CosMatrixYaw); + /* WaitForReturn(); */ + #endif + + + /* Roll */ + + SineMatrixRoll = WideMulNarrowDiv( + #if j_and_r_change + m->mat12 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); + #else + m->mat21 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); + #endif + + #if 0 + textprint("SineMatrixRoll = %d\n", SineMatrixRoll); + /* WaitForReturn(); */ + #endif + + CosMatrixRoll = WideMulNarrowDiv( + m->mat22 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); + + #if 0 + textprint("CosMatrixRoll = %d\n", CosMatrixRoll); + /* WaitForReturn(); */ + #endif + + /* Tables are for values +- 2^16 */ + + sinx = SineMatrixPitch << m2e_scale; + siny = SineMatrixYaw << m2e_scale; + sinz = SineMatrixRoll << m2e_scale; + + cosx = CosMatrixPitch << m2e_scale; + cosy = CosMatrixYaw << m2e_scale; + cosz = CosMatrixRoll << m2e_scale; + + #if 0 + textprint("sines = %d, %d, %d\n", sinx, siny, sinz); + textprint("cos's = %d, %d, %d\n", cosx, cosy, cosz); + /* WaitForReturn(); */ + #endif + + /* Absolute Cosines */ + + abs_cosx = cosx; + if(abs_cosx < 0) abs_cosx = -abs_cosx; + + abs_cosy = cosy; + if(abs_cosy < 0) abs_cosy = -abs_cosy; + + abs_cosz = cosz; + if(abs_cosz < 0) abs_cosz = -abs_cosz; + + + /* Euler X */ + + if(abs_cosx > Cosine45) { + + x = ArcSin(sinx); + + if(cosx < 0) { + x = -x; + x += deg180; + x &= wrap360; + } + } + + else { + + x = ArcCos(cosx); + + if(sinx < 0) { + x = -x; + x &= wrap360; + } + } + + #if (j_and_r_change == No) + x = -x; + x &= wrap360; + #endif + + e->EulerX = x; + + + /* Euler Y */ + + if(abs_cosy > Cosine45) { + + x = ArcSin(siny); + + if(cosy < 0) { + x = -x; + x += deg180; + x &= wrap360; + } + + } + + else { + + x = ArcCos(cosy); + + if(siny < 0) { + x = -x; + x &= wrap360; + } + + } + + #if (j_and_r_change == No) + x = -x; + x &= wrap360; + #endif + + e->EulerY = x; + + + /* Euler Z */ + + if(abs_cosz > Cosine45) { + + x = ArcSin(sinz); + + if(cosz < 0) { + x = -x; + x += deg180; + x &= wrap360; + } + } + + else { + + x = ArcCos(cosz); + + if(sinz < 0) { + x = -x; + x &= wrap360; + } + } + + #if (j_and_r_change == No) + x = -x; + x &= wrap360; + #endif + + e->EulerZ = x; + } + else //singularity case + { + + if(m->mat32>0) + e->EulerX = 3072; + else + e->EulerX = 1024; + + e->EulerZ=0; + + + + /* Yaw */ + + siny = -m->mat13 ; + + cosy = m->mat11 ; + + abs_cosy = cosy; + if(abs_cosy < 0) abs_cosy = -abs_cosy; + + + if(abs_cosy > Cosine45) { + + x = ArcSin(siny); + + if(cosy < 0) { + x = -x; + x += deg180; + x &= wrap360; + } + + } + + else { + + x = ArcCos(cosy); + + if(siny < 0) { + x = -x; + x &= wrap360; + } + + } + + #if (j_and_r_change == No) + x = -x; + x &= wrap360; + #endif + + e->EulerY = x; + + } + + + + + #if 0 + textprint("\nEuler from VDB Matrix is:\n%d\n%d\n%d\n", + e->EulerX, + e->EulerY, + e->EulerZ + ); + /* WaitForReturn(); */ + #endif + +} + + + +#if 1 + + + + +#define j_and_r_change_2 Yes + +void MatrixToEuler2(MATRIXCH *m, EULER *e) + +{ + + int x, sinx, cosx, siny, cosy, sinz, cosz; + int abs_cosx, abs_cosy, abs_cosz; + int SineMatrixPitch, SineMatrixYaw, SineMatrixRoll; + int CosMatrixPitch, CosMatrixYaw, CosMatrixRoll; + + + /* Pitch */ + + #if j_and_r_change_2 + SineMatrixPitch = -m->mat32; + #else + SineMatrixPitch = -m->mat23; + #endif + + SineMatrixPitch >>= m2e_scale; + + #if 0 + textprint("SineMatrixPitch = %d\n", SineMatrixPitch); + /* WaitForReturn(); */ + #endif + + CosMatrixPitch = SineMatrixPitch * SineMatrixPitch; + CosMatrixPitch >>= m2e_shift; + + CosMatrixPitch = -CosMatrixPitch; + CosMatrixPitch += ONE_FIXED_S; + CosMatrixPitch *= ONE_FIXED_S; + CosMatrixPitch = SqRoot32(CosMatrixPitch); + + if(CosMatrixPitch) { + + if(CosMatrixPitch > ONE_FIXED_S) CosMatrixPitch = ONE_FIXED_S; + else if(CosMatrixPitch < -ONE_FIXED_S) CosMatrixPitch = -ONE_FIXED_S; + + } + + else CosMatrixPitch = 1; + + + #if 0 + textprint("CosMatrixPitch = %d\n", CosMatrixPitch); + /* WaitForReturn(); */ + #endif + + + /* Yaw */ + + SineMatrixYaw = WideMulNarrowDiv( + #if j_and_r_change_2 + m->mat31 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); + #else + m->mat13 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); + #endif + + #if 0 + textprint("SineMatrixYaw = %d\n", SineMatrixYaw); + /* WaitForReturn(); */ + #endif + + CosMatrixYaw = WideMulNarrowDiv( + m->mat33 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); + + #if 0 + textprint("CosMatrixYaw = %d\n", CosMatrixYaw); + /* WaitForReturn(); */ + #endif + + + /* Roll */ + + SineMatrixRoll = WideMulNarrowDiv( + #if j_and_r_change_2 + m->mat12 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); + #else + m->mat21 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); + #endif + + #if 0 + textprint("SineMatrixRoll = %d\n", SineMatrixRoll); + /* WaitForReturn(); */ + #endif + + CosMatrixRoll = WideMulNarrowDiv( + m->mat22 >> m2e_scale, ONE_FIXED_S, CosMatrixPitch); + + #if 0 + textprint("CosMatrixRoll = %d\n", CosMatrixRoll); + /* WaitForReturn(); */ + #endif + + + /* Tables are for values +- 2^16 */ + + sinx = SineMatrixPitch << m2e_scale; + siny = SineMatrixYaw << m2e_scale; + sinz = SineMatrixRoll << m2e_scale; + + cosx = CosMatrixPitch << m2e_scale; + cosy = CosMatrixYaw << m2e_scale; + cosz = CosMatrixRoll << m2e_scale; + + #if 0 + textprint("sines = %d, %d, %d\n", sinx, siny, sinz); + textprint("cos's = %d, %d, %d\n", cosx, cosy, cosz); + /* WaitForReturn(); */ + #endif + + /* Absolute Cosines */ + + abs_cosx = cosx; + if(abs_cosx < 0) abs_cosx = -abs_cosx; + + abs_cosy = cosy; + if(abs_cosy < 0) abs_cosy = -abs_cosy; + + abs_cosz = cosz; + if(abs_cosz < 0) abs_cosz = -abs_cosz; + + + /* Euler X */ + + if(abs_cosx > Cosine45) { + + x = ArcSin(sinx); + + if(cosx < 0) { + x = -x; + x += deg180; + x &= wrap360; + } + } + + else { + + x = ArcCos(cosx); + + if(sinx < 0) { + x = -x; + x &= wrap360; + } + } + + #if (j_and_r_change_2 == No) + x = -x; + x &= wrap360; + #endif + + e->EulerX = x; + + + /* Euler Y */ + + if(abs_cosy > Cosine45) { + + x = ArcSin(siny); + + if(cosy < 0) { + x = -x; + x += deg180; + x &= wrap360; + } + + } + + else { + + x = ArcCos(cosy); + + if(siny < 0) { + x = -x; + x &= wrap360; + } + + } + + #if (j_and_r_change_2 == No) + x = -x; + x &= wrap360; + #endif + + e->EulerY = x; + + + /* Euler Z */ + + if(abs_cosz > Cosine45) { + + x = ArcSin(sinz); + + if(cosz < 0) { + x = -x; + x += deg180; + x &= wrap360; + } + } + + else { + + x = ArcCos(cosz); + + if(sinz < 0) { + x = -x; + x &= wrap360; + } + } + + #if (j_and_r_change_2 == No) + x = -x; + x &= wrap360; + #endif + + e->EulerZ = x; + + + #if 0 + textprint("\nEuler from VDB Matrix is:\n%d\n%d\n%d\n", + e->EulerX, + e->EulerY, + e->EulerZ + ); + /* WaitForReturn(); */ + #endif + +} + + + +#endif + + + +/* + + Normalise a Matrix + + Dot the three vectors together (XY, XZ, YZ) and take the two nearest to + 90ø from each other. Cross them to create a new third vector, then cross + the first and third to create a new second. + +*/ + +void MNormalise(MATRIXCH *m) + +{ + + VECTORCH *x = (VECTORCH *) &m->mat11; + VECTORCH *y = (VECTORCH *) &m->mat21; + VECTORCH *z = (VECTORCH *) &m->mat31; + int dotxy = Dot(x, y); + int dotxz = Dot(x, z); + int dotyz = Dot(y, z); + VECTORCH *s; + VECTORCH *t; + VECTORCH u; + VECTORCH v; + VECTORCH zero = {0, 0, 0}; + + + #if 0 + textprint("dotxy = %d\n", dotxy); + textprint("dotxz = %d\n", dotxz); + textprint("dotyz = %d\n", dotyz); + #endif + + #if 0 + /* TEST */ + dotxy = 0; + dotxz = 0; + dotyz = 1; + #endif + + + #if 0 + textprint("%d %d %d\n", + x->vx, + x->vy, + x->vz + ); + + textprint("%d %d %d\n", + y->vx, + y->vy, + y->vz + ); + + textprint("%d %d %d\n", + z->vx, + z->vy, + z->vz + ); + #endif + + + /* Find the two vectors nearest 90ø */ + + if(dotxy > dotxz && dotxy > dotyz) { + + /* xy are the closest to 90ø */ + + /*textprint("xy\n");*/ + + s = x; + t = y; + + MakeNormal(&zero, s, t, &u); /* Cross them for a new 3rd vector */ + + MakeNormal(&zero, s, &u, &v); /* Cross 1st & 3rd for a new 2nd */ + v.vx = -v.vx; + v.vy = -v.vy; + v.vz = -v.vz; + + CopyVector(&u, z); + CopyVector(&v, y); + + } + + else if(dotxz > dotxy && dotxz > dotyz) { + + /* xz are the closest to 90ø */ + + /*textprint("xz\n");*/ + + s = x; + t = z; + + MakeNormal(&zero, s, t, &u); /* Cross them for a new 3rd vector */ + u.vx = -u.vx; + u.vy = -u.vy; + u.vz = -u.vz; + + MakeNormal(&zero, s, &u, &v); /* Cross 1st & 3rd for a new 2nd */ + + CopyVector(&u, y); + CopyVector(&v, z); + + } + + else { + + /* yz are the closest to 90ø */ + + /*textprint("yz\n");*/ + + s = y; + t = z; + + MakeNormal(&zero, s, t, &u); /* Cross them for a new 3rd vector */ + + MakeNormal(&zero, s, &u, &v); /* Cross 1st & 3rd for a new 2nd */ + v.vx = -v.vx; + v.vy = -v.vy; + v.vz = -v.vz; + + CopyVector(&u, x); + CopyVector(&v, z); + + } + + + #if 0 + textprint("%d %d %d\n", + x->vx, + x->vy, + x->vz + ); + + textprint("%d %d %d\n", + y->vx, + y->vy, + y->vz + ); + + textprint("%d %d %d\n", + z->vx, + z->vy, + z->vz + ); + #endif + + #if 0 + textprint("mag. x = %d\n", Magnitude(x)); + textprint("mag. y = %d\n", Magnitude(y)); + textprint("mag. z = %d\n", Magnitude(z)); + #endif + + /*WaitForReturn();*/ + + +} + + + + +/* + + ArcCos + + In: COS value as -65,536 -> +65,536. + Out: Angle in 0 -> 4095 form. + + Notes: + + The angle returned is in the range 0 -> 2,047 since the sign of SIN + is not known. + + ArcSin(x) = ArcTan ( x, sqr ( 1-x*x ) ) + ArcCos(x) = ArcTan ( sqr ( 1-x*x ), x) + + -65,536 = 180 Degrees + 0 = 90 Degrees + +65,536 = 0 Degrees + + The table has 4,096 entries. + +*/ + +int ArcCos(int c) + +{ + + short acos; + + if(c < (-(ONE_FIXED - 1))) c = -(ONE_FIXED - 1); + else if(c > (ONE_FIXED - 1)) c = ONE_FIXED - 1; + + #if 0 + c = c >> 5; /* -64k -> +64k becomes -2k -> +2k */ + c += 2048; /* -2k -> +2k becomes 0 -> 4k */ + #endif + + acos = ArcCosTable[(c >> 5) + 2048]; + + return (int) (acos & wrap360); + +} + + +/* + + ArcSin + + In: SIN value in ax as -65,536 -> +65,536. + Out: Angle in 0 -> 4095 form in ax. + + Notes: + + The angle returned is in the range -1,024 -> 1,023 since the sign of COS + is not known. + + ArcSin(x) = ArcTan ( x, sqr ( 1-x*x ) ) + ArcCos(x) = ArcTan ( sqr ( 1-x*x ), x) + + -65,536 = 270 Degrees + 0 = 0 Degrees + +65,536 = 90 Degrees + + The table has 4,096 entries. + +*/ + +int ArcSin(int s) + +{ + + short asin; + + + if(s < (-(ONE_FIXED - 1))) s = -(ONE_FIXED - 1); + else if(s > (ONE_FIXED - 1)) s = ONE_FIXED - 1; + + #if 0 + s = s >> 5; /* -64k -> +64k becomes -2k -> +2k */ + s += 2048; /* -2k -> +2k becomes 0 -> 4k */ + #endif + + asin = ArcSineTable[(s >> 5) + 2048]; + + return (int) (asin & wrap360); + +} + + +/* + + ArcTan + + Pass (x,z) + + And ATN(x/z) is returned such that: + + 000ø is Map North + 090ø is Map East + 180ø is Map South + 270ø is Map West + +*/ + +int ArcTan(height_x, width_z) + + int height_x,width_z; + +{ + + int abs_height_x, abs_width_z, angle, sign, signsame, temp; + + sign=0; + + if((height_x<0 && width_z<0) || (height_x>=0 && width_z>=0)) + signsame=Yes; + else + signsame=No; + + abs_height_x=height_x; + if(abs_height_x<0) abs_height_x=-abs_height_x; + + abs_width_z=width_z; + if(abs_width_z<0) abs_width_z=-abs_width_z; + +/* + + Find ATN + +*/ + + if(width_z==0) angle=-deg90; + + else if(abs_width_z==abs_height_x) + angle=deg45; + + else { + + if(abs_width_z>abs_height_x) { + temp=abs_width_z; + abs_width_z=abs_height_x; + abs_height_x=temp; + sign=-1; + } + + if(abs_height_x!=0) + + /* angle = (abs_width_z << 8) / abs_height_x; */ + + + + angle = DIV_INT((abs_width_z << 8), abs_height_x); + + + + + + else + angle=deg22pt5; + + angle=ArcTanTable[angle]; + + if(sign>=0) { + angle=-angle; + angle+=deg90; + } + + } + + if(signsame==No) angle=-angle; + + if(width_z<=0) angle+=deg180; + + angle&=wrap360; + + return(angle); + +} + + +/* + + Matrix from Z-Vector + +*/ + +void MatrixFromZVector(VECTORCH *v, MATRIXCH *m) + +{ + + VECTORCH XVector; + VECTORCH YVector; + + VECTORCH zero = {0, 0, 0}; + + + XVector.vx = v->vz; + XVector.vy = 0; + XVector.vz = -v->vx; + + Normalise(&XVector); + + MakeNormal(&zero, &XVector, v, &YVector); + + m->mat11 = XVector.vx; + m->mat12 = XVector.vy; + m->mat13 = XVector.vz; + + m->mat21 = -YVector.vx; + m->mat22 = -YVector.vy; + m->mat23 = -YVector.vz; + + m->mat31 = v->vx; + m->mat32 = v->vy; + m->mat33 = v->vz; + +} + + + + + + + + + + +/* + + Distance Functions + +*/ + + +/* + + Foley and Van Dam 2d distance function + + WARNING! Returns distance x 3 + + Here is the F & VD distance function: + + x + z + (max(x,z) * 2) + ---------------------- + 3 + +*/ + +int FandVD_Distance_2d(VECTOR2D *v0, VECTOR2D *v1) + +{ + + int max; + int d; + + + int dx = v1->vx - v0->vx; + int dy = v1->vy - v0->vy; + + if(dx < 0) dx = -dx; + if(dy < 0) dy = -dy; + + if(dx > dy) max = dx; + else max = dy; + + d = (dx + dy + (max * 2)); + + return d; + +} + + +/* + + Foley and Van Dam 3d distance function + + WARNING! Returns distance x 9 + + For a 3d version, calculate (f(f(x,y), y*3))/9 + +*/ + +int FandVD_Distance_3d(VECTORCH *v0, VECTORCH *v1) + +{ + + int dxy, max; + + int dz = v1->vz - v0->vz; + + if(dz < 0) dz = -dz; + + dz *= 3; + + dxy = FandVD_Distance_2d((VECTOR2D *) v0, (VECTOR2D *) v1); + + if(dxy > dz) max = dxy; + else max = dz; + + return (dxy + dz + (max * 2)); + +} + + +/* + + NextLowPower2() returns the next lowest power of 2 of the passed value. + + e.g. 18 is returned as 16. + +*/ + +int NextLowPower2(int i) + +{ + + int n = 1; + + + while(n <= i) + n <<= 1; + + return n >> 1; + +} + + +/* + + Transform a world location into the local space of the passed matrix and + location. + + Vector v1 is transformed to v2 + It is made relative to vector v3 and rotated using matrix m transposed + + A possible use is the transformation of world points into the local space + of a display block + + e.g. + + MakeVectorLocal(&v1, &v2, &dptr->ObWorld, &dptr->ObMat); + + This would place vector v2 into the local space of display block dptr + +*/ + +void MakeVectorLocal(VECTORCH *v1, VECTORCH *v2, VECTORCH *v3, MATRIXCH *m) + +{ + + MATRIXCH transmat; + + + CopyMatrix(m, &transmat); + TransposeMatrixCH(&transmat); + + v2->vx = v1->vx - v3->vx; + v2->vy = v1->vy - v3->vy; + v2->vz = v1->vz - v3->vz; + + RotateVector(v2, &transmat); + +} + + + + + +/* + + Returns "Yes" if "point" is inside "polygon" + + + ************************************************** + + WARNING!! Point and Polygon Data are OVERWRITTEN!! + + ************************************************** + + + The function requires point to be an integer array containing a single + XY pair. The number of points must be passed too. + + Pass the size of the polygon point e.g. A Gouraud polygon has points X,Y,I + so its point size would be 3. + + + Item Polygon Point Size + ---- ------------------ + + I_Polygon 2 + I_GouraudPolygon 3 + I_2dTexturedPolygon 4 + I_3dTexturedPolygon, 5 + I_Gouraud2dTexturedPolygon 5 + I_Polygon_ZBuffer 3 + I_GouraudPolygon_ZBuffer 4 + + + PASS ONLY POSITIVE COORDINATES! + +*/ + +int PointInPolygon(int *point, int *polygon, int c, int ppsize) + +{ + + + #if UseTimsPinp + + + /* Tim's New Point In Polygon test-- hopefully much faster, */ + /* certainly much smaller. */ + /* Uses Half-Line test for point-in-2D-polygon test */ + /* Tests the half-line going from the point in the direction of positive z */ + + int x, z; /* point */ + int sx, sz; /* vertex 1 */ + int *polyp; /* vertex 2 pointer */ + int t; + int dx, dz; /* ABS(vertex 2 - vertex 1) */ + int sgnx; /* going left or going right */ + int intersects; /* number of intersections so far discovered */ + LONGLONGCH a_ll, b_ll; + + /* reject lines and points */ + if (c < 3) return(No); + + intersects = 0; + + x = point[ix]; + z = point[iy]; /* ! */ + + /* get last point */ + polyp = polygon + ((c - 1) * ppsize); + sx = polyp[0]; + sz = polyp[1]; + + /* go back to first point */ + polyp = polygon; + + /* for each point */ + while (0 != c) + { + /* is this line straddling the x co-ordinate of the point? */ + /* if not it is not worth testing for intersection with the half-line */ + /* we must be careful to get the strict and non-stict inequalities */ + /* correct, or we may count intersections with vertices the wrong number */ + /* of times. */ + sgnx = 0; + if (sx < x && x <= polyp[0]) + { + /* going right */ + sgnx = 1; + dx = polyp[0] - sx; + } + if (polyp[0] < x && x <= sx) + { + /* going left */ + sgnx = -1; + dx = sx - polyp[0]; + } + + /* if sgnx is zero then neither of the above conditions are true, */ + /* hence the line does not straddle the point in x */ + if (0 != sgnx) + { + /* next do trivial cases of line totally above or below point */ + if (z < sz && z < polyp[1]) + { + /* line totally above point -- intersection */ + intersects++; + } + else if (z <= sz || z <= polyp[1]) + { + /* line straddles point in both x and z -- we must do interpolation */ + + /* get absolute differences between line end z co-ordinates */ + dz = (sz < polyp[1])?(polyp[1] - sz):(sz - polyp[1]); + + /* B504 is the square root of 7FFFFFFF */ + if (0xB504L < dx || 0xB504L < dz) + { + /* LARGE line -- use 64-bit values */ + /* interpolate z */ + MUL_I_WIDE(polyp[1] - sz, x - sx, &a_ll); + MUL_I_WIDE(polyp[0] - sx, z - sz, &b_ll); + if(CMP_LL(&a_ll, &b_ll) == sgnx) + { + /* we have an intersection */ + intersects++; + } + } + else + { + /* small line -- use 32-bit values */ + /* interpolate z */ + t = (polyp[1] - sz) * (x - sx) - (polyp[0] - sx) * (z - sz); + if (t < 0 && sgnx < 0 || 0 < t && 0 < sgnx) + { + /* we have an intersection */ + intersects++; + } + } + } /* (if line straddles point in z) */ + } /* (if line straddles point in x) */ + + /* get next line : */ + /* new vertex 1 is old vertex 2 */ + sx = polyp[0]; + sz = polyp[1]; + + /* new vertex 2 is next point */ + polyp += ppsize; + + /* next vertex */ + c--; + } + + if (intersects & 1) + { + /* Odd number of intersections -- point is inside polygon */ + return(Yes); + } + else + { + /* even number of intersections -- point is outside polygon */ + return(No); + } + + + +#else + + + int i; + int si, ti; + int s0, t0; + int s1, t1; + int *v0; + int *v1; + int ivdot, ivdotcnt, sgn_currivdot, sgn_ivdot, ivstate; + int ns, nt; + int x_scale, y_scale; + int DotNudge; + + int x, z; + LONGLONGCH xx; + LONGLONGCH zz; + LONGLONGCH xx_tmp; + LONGLONGCH zz_tmp; + VECTORCH PolyAvgPt; + + + /* Reject points and lines */ + + if(c < 3) return No; + + + /* Find the average point */ + + v0 = polygon; + + EQUALS_LL(&xx, &ll_zero); + EQUALS_LL(&zz, &ll_zero); + + for(i = c; i!=0; i--) { + + x = v0[0]; + z = v0[1]; + + IntToLL(&xx_tmp, &x); /* xx_tmp = (long long)x */ + IntToLL(&zz_tmp, &z); /* zz_tmp = (long long)z */ + + ADD_LL_PP(&xx, &xx_tmp); /* xx += xx_tmp */ + ADD_LL_PP(&zz, &zz_tmp); /* zz += zz_tmp */ + + v0 += ppsize; + + } + + PolyAvgPt.vx = NarrowDivide(&xx, c); + PolyAvgPt.vz = NarrowDivide(&zz, c); + + + /* Centre the polygon */ + + v0 = polygon; + + for(i = c; i!=0; i--) { + + v0[0] -= PolyAvgPt.vx; + v0[1] -= PolyAvgPt.vz; + + v0 += ppsize; + + } + + + /* Centre the test point */ + + point[0] -= PolyAvgPt.vx; + point[1] -= PolyAvgPt.vz; + + + /* Scale to avoid maths overflow */ + + v0 = polygon; + + s0 = 0; + t0 = 0; + + for(i = c; i!=0; i--) { + + si = v0[0]; if(si < 0) si = -si; + if(si > s0) s0 = si; + + ti = v0[1]; if(ti < 0) ti = -ti; + if(ti > t0) t0 = ti; + + v0 += ppsize; + + } + + si = point[ix]; if(si < 0) si = -si; + if(si > s0) s0 = si; + + ti = point[iy]; if(ti < 0) ti = -ti; + if(ti > t0) t0 = ti; + + + #if 0 + textprint("\nmax x = %d\n", s0); + textprint("max y = %d\n", t0); + #endif + + + x_scale = FindShift32(s0, 16383); + y_scale = FindShift32(t0, 16383); + + + #if 0 + textprint("scales = %d, %d\n", x_scale, y_scale); + #endif + + + v0 = polygon; + + for(i = c; i!=0; i--) { + + v0[0] >>= x_scale; + v0[1] >>= y_scale; + + /*textprint("(%d, %d)\n", v0[0], v0[1]);*/ + + v0 += ppsize; + + } + + point[ix] >>= x_scale; + point[iy] >>= y_scale; + + + + +#if 1 + + /* Clockwise or Anti-Clockwise? */ + + ns = -(polygon[iy + ppsize] - polygon[iy]); + nt = (polygon[ix + ppsize] - polygon[ix]); + + si = polygon[(ppsize*2) + ix] - polygon[ix]; + ti = polygon[(ppsize*2) + iy] - polygon[iy]; + + ivdot = (ns * si) + (nt * ti); + + if(ivdot < 0) DotNudge = -1; + else DotNudge = 1; + +#endif + + + + #if 0 + if(ivdot < 0) textprint("Clockwise\n"); + WaitForReturn(); + #endif + + + /* Point to test */ + + si = point[ix]; + ti = point[iy]; + + + #if 0 + textprint("p_test %d, %d\n", si, ti); + #endif + + + /* Polygon Vector pointers */ + + v0 = polygon; + v1 = v0 + ppsize; + + + /* Dot result monitor */ + + ivdotcnt = 0; + ivstate = Yes; /* assume inside */ + + + /* Test v(s, t) against the vectors */ + + for(i = c; i!=0 && ivstate == Yes; i--) { + + + /* second vector pointer wraps once */ + + if(i == 1) v1 = polygon; + + + /* get the vector */ + + s0 = v0[ix]; + t0 = v0[iy]; + + s1 = v1[ix]; + t1 = v1[iy]; + + + #if 0 + textprint("%d,%d; %d,%d\n", s0, t0, s1, t1); + #endif + + + /* get the vector normal */ + + ns = -(t1 - t0); /* s -> -t */ + nt = s1 - s0; /* t -> s */ + + + /* Dot with intersection point */ + + ivdot = (ns * (si - s0)) + (nt * (ti - t0)); + + + /* TEST */ + ivdot += DotNudge; + + + sgn_ivdot = 1; + if(ivdot < 0) sgn_ivdot = -1; + + + /* only continue if current dot is same as last, else quit */ + + if(ivdotcnt == 0) sgn_currivdot = sgn_ivdot; + + else { + + if(sgn_ivdot != sgn_currivdot) ivstate = No; + sgn_currivdot = sgn_ivdot; + + } + + v0 += ppsize; + v1 += ppsize; + + ivdotcnt++; + + } + + if(ivstate) return Yes; + else return No; + + +#endif + + +} + + + + + + + +/* + + #defines and statics required for Jamie's Most Excellent + random number generator + +*/ + +#define DEG_3 31 +#define SEP_3 3 + +static long table [DEG_3] = +{ + -851904987, -43806228, -2029755270, 1390239686, -1912102820, + -485608943, 1969813258, -1590463333, -1944053249, 455935928, + 508023712, -1714531963, 1800685987, -2015299881, 654595283, + -1149023258, -1470005550, -1143256056, -1325577603, -1568001885, + 1275120390, -607508183, -205999574, -1696891592, 1492211999, + -1528267240, -952028296, -189082757, 362343714, 1424981831, + 2039449641 +}; + +#define TABLE_END (table + sizeof (table) / sizeof (table [0])) + +static long * front_ptr = table + SEP_3; +static long * rear_ptr = table; + + +/* + This code (FastRandom and SetFastRandom) stolen from Jamie Lokier + September 95. The original version was part of a C library + implementation +*/ + + +/* This is derived from the GNU C library source, which is in turn + derived from Berkeley source. The algorithm, the polynomial, and the + initial numbers are the same, but the code has been reworked for the + needs of this version. + + This version doesn't support different types of random number + generators, or saving and restoring the state. It is fast, short and + as simple as it can be while still generating numbers as good as the + Berkeley one. The basic algorithm is to have a linear-feedback shift + register, whose bits are the least significant bits of each word in + the `table' array. The higher-order bits are generated by carries + from the arithmetic on the shift register bits, and have an even + longer period than the shift register. */ + +/* x**31 + x**3 + 1. */ + +void SetSeededFastRandom(int seed); +void SetFastRandom(void) + +{ + + int i; + long number = GetTickCount(); + + + for(i = 0; i < DEG_3; ++i) { + + number = 1103515145 * number + 12345; + table[i] = number; + + } + + front_ptr = table + SEP_3; + rear_ptr = table; + + for(i = 0; i < 10 * DEG_3; ++i) + (void) FastRandom (); + + SetSeededFastRandom(FastRandom()); + +} + + +int FastRandom(void) + +{ + + long i; + + /* + + Discard least random bit. + Shift as unsigned to avoid replicating sign bit. + Faster than masking. + + */ + + *front_ptr += *rear_ptr; + i = (long) ((unsigned long) *front_ptr >> 1); + + /* `front_ptr' and `rear_ptr' can't wrap at the same time. */ + + ++front_ptr; + + if(front_ptr < TABLE_END) { + + ++rear_ptr; + + if (rear_ptr < TABLE_END) return i; + + rear_ptr = table; + + } + + else { /* front_ptr >= TABLE_END */ + + front_ptr = table; + ++rear_ptr; + + } + + return (int) i; + +} + +/*a second copy of the random number generator for getting random numbers from a single seed*/ + +#define SEEDED_DEG_3 13 +#define SEEDED_SEP_3 3 + +static long seeded_table [SEEDED_DEG_3]; + +#define SEEDED_TABLE_END (seeded_table + sizeof (seeded_table) / sizeof (seeded_table [0])) + +static long * seeded_front_ptr = seeded_table + SEEDED_SEP_3; +static long * seeded_rear_ptr = seeded_table; + + + +int SeededFastRandom(void) + +{ + + long i; + + /* + + Discard least random bit. + Shift as unsigned to avoid replicating sign bit. + Faster than masking. + + */ + + *seeded_front_ptr += *seeded_rear_ptr; + i = (long) ((unsigned long) *seeded_front_ptr >> 1); + + /* `front_ptr' and `rear_ptr' can't wrap at the same time. */ + + ++seeded_front_ptr; + + if(seeded_front_ptr < SEEDED_TABLE_END) { + + ++seeded_rear_ptr; + + if (seeded_rear_ptr < SEEDED_TABLE_END) return i; + + seeded_rear_ptr = seeded_table; + + } + + else { /* front_ptr >= TABLE_END */ + + seeded_front_ptr = seeded_table; + ++seeded_rear_ptr; + + } + + return (int) i; + +} + +void SetSeededFastRandom(int seed) + +{ + + int i; + long number = seed; + + + for(i = 0; i < SEEDED_DEG_3; ++i) { + + number = 1103515145 * number + 12345; + seeded_table[i] = number; + + } + + seeded_front_ptr = seeded_table + SEEDED_SEP_3; + seeded_rear_ptr = seeded_table; + + for(i = 0; i < 2 * SEEDED_DEG_3; ++i) + (void) SeededFastRandom (); + +} + +#if StandardShapeLanguage + +/* + + Calculate the average point on this polygon + +*/ + +void PolyAveragePoint(POLYHEADER *pheader, int *spts, VECTORCH *apt) + +{ + + int x, y, z; + LONGLONGCH xx; + LONGLONGCH yy; + LONGLONGCH zz; + LONGLONGCH xx_tmp; + LONGLONGCH yy_tmp; + LONGLONGCH zz_tmp; + int *mypolystart = &pheader->Poly1stPt; + int numpolypts; + + + /* Find the average point */ + + EQUALS_LL(&xx, &ll_zero); + EQUALS_LL(&yy, &ll_zero); + EQUALS_LL(&zz, &ll_zero); + + numpolypts = 0; + + while(*mypolystart != Term) { + + x = *(spts + *mypolystart + ix); + y = *(spts + *mypolystart + iy); + z = *(spts + *mypolystart + iz); + + IntToLL(&xx_tmp, &x); /* xx_tmp = (long long)x */ + IntToLL(&yy_tmp, &y); /* yy_tmp = (long long)y */ + IntToLL(&zz_tmp, &z); /* zz_tmp = (long long)z */ + + ADD_LL_PP(&xx, &xx_tmp); /* xx += xx_tmp */ + ADD_LL_PP(&yy, &yy_tmp); /* yy += yy_tmp */ + ADD_LL_PP(&zz, &zz_tmp); /* zz += zz_tmp */ + + numpolypts++; + mypolystart++; + + } + + apt->vx = NarrowDivide(&xx, numpolypts); + apt->vy = NarrowDivide(&yy, numpolypts); + apt->vz = NarrowDivide(&zz, numpolypts); + +} + +#endif /* StandardShapeLanguage */ + + + + + + +/* KJL 15:07:39 01/08/97 - Returns the magnitude of the + cross product of two vectors a and b. */ +int MagnitudeOfCrossProduct(VECTORCH *a, VECTORCH *b) + +{ + VECTORCH c; + + c.vx = MUL_FIXED(a->vy,b->vz) - MUL_FIXED(a->vz,b->vy); + c.vy = MUL_FIXED(a->vz,b->vx) - MUL_FIXED(a->vx,b->vz); + c.vz = MUL_FIXED(a->vx,b->vy) - MUL_FIXED(a->vy,b->vx); + + return Magnitude(&c); +} + +/* KJL 15:08:01 01/08/97 - sets the vector c to be the + cross product of the vectors a and b. */ +void CrossProduct(VECTORCH *a, VECTORCH *b, VECTORCH *c) + +{ + c->vx = MUL_FIXED(a->vy,b->vz) - MUL_FIXED(a->vz,b->vy); + c->vy = MUL_FIXED(a->vz,b->vx) - MUL_FIXED(a->vx,b->vz); + c->vz = MUL_FIXED(a->vx,b->vy) - MUL_FIXED(a->vy,b->vx); +} + + + +/* KJL 12:01:08 7/16/97 - returns the magnitude of a vector - max error about 13%, though average error +less than half this. Very fast compared to other approaches. */ +int Approximate3dMagnitude(VECTORCH *v) +{ + int dx,dy,dz; + + dx = v->vx; + if (dx<0) dx = -dx; + + dy = v->vy; + if (dy<0) dy = -dy; + + dz = v->vz; + if (dz<0) dz = -dz; + + + if (dx>dy) + { + if (dx>dz) + { + return dx + ((dy+dz)>>2); + } + else + { + return dz + ((dy+dx)>>2); + } + } + else + { + if (dy>dz) + { + return dy + ((dx+dz)>>2); + } + else + { + return dz + ((dx+dy)>>2); + } + } +} + + +/* + + Quaternion to Matrix + + This is the column(row) matrix that is produced. Our matrices are + row(column) and so are a transpose of this. + + 1 - 2yy - 2zz 2xy + 2wz 2xz - 2wy + + 2xy - 2wz 1 - 2xx - 2zz 2yz + 2wx + + 2xz + 2wy 2yz - 2wx 1 - 2xx - 2yy + +*/ + +void QuatToMat(QUAT *q,MATRIXCH *m) +{ + + int q_w, q_x, q_y, q_z; + + int q_2x, q_2y, q_2z; + + int q_2xw; + int q_2xx; + int q_2xy; + int q_2xz; + int q_2yw; + int q_2yy; + int q_2yz; + int q_2zw; + int q_2zz; + +/* + + The most efficient way to create the matrix is as follows + + 1/ Double x, y & z + +*/ + + q_w=q->quatw; + q_x=q->quatx; + q_y=q->quaty; + q_z=q->quatz; + + q_2x=q_x*2; + q_2y=q_y*2; + q_2z=q_z*2; + +/* + + 2/ Form their products with w, x, y & z + These are + + (2x)w (2y)w (2z)w + (2x)x + (2x)y (2y)y + (2x)z (2y)z (2z)z + +*/ + + q_2xw=MUL_FIXED(q_2x,q_w); + q_2yw=MUL_FIXED(q_2y,q_w); + q_2zw=MUL_FIXED(q_2z,q_w); + + q_2xx=MUL_FIXED(q_2x,q_x); + + q_2xy=MUL_FIXED(q_2x,q_y); + q_2yy=MUL_FIXED(q_2y,q_y); + + q_2xz=MUL_FIXED(q_2x,q_z); + q_2yz=MUL_FIXED(q_2y,q_z); + q_2zz=MUL_FIXED(q_2z,q_z); + + +/* mat11 = 1 - 2y^2 - 2z^2 */ + + m->mat11=ONE_FIXED-q_2yy-q_2zz; + +/* mat12 = 2xy - 2wz */ + + m->mat12=q_2xy-q_2zw; + +/* mat13 = 2xz + 2wy */ + + m->mat13=q_2xz+q_2yw; + +/* mat21 = 2xy + 2wz */ + + m->mat21=q_2xy+q_2zw; + +/* mat22 = 1 - 2x^2 - 2z^2 */ + + m->mat22=ONE_FIXED-q_2xx-q_2zz; + +/* mat23 = 2yz - 2wx */ + + m->mat23=q_2yz-q_2xw; + +/* mat31 = 2xz - 2wy */ + + m->mat31=q_2xz-q_2yw; + +/* mat32 = 2yz + 2wx */ + + m->mat32=q_2yz+q_2xw; + +/* mat33 = 1 - 2x^2 - 2y^2 */ + + m->mat33=ONE_FIXED-q_2xx-q_2yy; + +} + diff --git a/3dc/OBJECT.C b/3dc/OBJECT.C new file mode 100644 index 0000000..de494a3 --- /dev/null +++ b/3dc/OBJECT.C @@ -0,0 +1,613 @@ + +#include "3dc.h" +#include "module.h" + +#include "stratdef.h" +#include "sfx.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + + +/* globals for export */ + +int NumActiveBlocks; +DISPLAYBLOCK *ActiveBlockList[maxobjects]; + + + + +/* + Object Block Lists et al +*/ + +static int NumFreeBlocks; +static DISPLAYBLOCK *FreeBlockList[maxobjects]; +static DISPLAYBLOCK **FreeBlockListPtr = &FreeBlockList[maxobjects-1]; +static DISPLAYBLOCK FreeBlockData[maxobjects]; +static DISPLAYBLOCK **ActiveBlockListPtr = &ActiveBlockList[0]; + + +/* + Texture Animation Block Extensions +*/ + +static int NumFreeTxAnimBlocks; +static TXACTRLBLK *FreeTxAnimBlockList[maxTxAnimblocks]; +static TXACTRLBLK **FreeTxAnimBlockListPtr = &FreeTxAnimBlockList[maxTxAnimblocks-1]; +static TXACTRLBLK FreeTxAnimBlockData[maxTxAnimblocks]; + + + +/* + Light Block Extensions +*/ + +static int NumFreeLightBlocks; +static LIGHTBLOCK *FreeLightBlockList[maxlightblocks]; +static LIGHTBLOCK **FreeLightBlockListPtr = &FreeLightBlockList[maxlightblocks-1]; +static LIGHTBLOCK FreeLightBlockData[maxlightblocks]; + + + +/* + + To create the free block list, pointers to "FreeBlockData[]" must be copied + to "FreeBlockList[]". + + Also: + + "NumFreeBlocks" must be updated as "FreeBlockList[]" is created. + "NumActiveBlocks" must be initialised to zero. + +*/ +void InitialiseObjectBlocks(void) +{ + + DISPLAYBLOCK *FreeBlkPtr = &FreeBlockData[0]; + + NumActiveBlocks = 0; + + FreeBlockListPtr = &FreeBlockList[maxobjects-1]; + ActiveBlockListPtr = &ActiveBlockList[0]; + + for(NumFreeBlocks = 0; NumFreeBlocksObVDBPtr); /* Checks for null */ + + if(dblockptr->ObNumLights) { + for(light = dblockptr->ObNumLights - 1; light != -1; light--) + DeleteLightBlock(dblockptr->ObLights[light], dblockptr); + } + + /* If no SB, deallocate any Texture Animation Blocks */ + + if(dblockptr->ObStrategyBlock == 0) { + + if(dblockptr->ObTxAnimCtrlBlks) { + + taptr = dblockptr->ObTxAnimCtrlBlks; + + while(taptr) { + + DeallocateTxAnimBlock(taptr); + + taptr = taptr->tac_next; + + } + + } + + } + + + /* Deallocate the Lazy Morphed Points Array Pointer */ + + #if (SupportMorphing && LazyEvaluationForMorphing) + if(dblockptr->ObMorphedPts) { + DeallocateMem(dblockptr->ObMorphedPts); + dblockptr->ObMorphedPts = 0; + } + #endif + + /* KJL 16:52:43 06/01/98 - dealloc sfx block if one exists */ + if(dblockptr->SfxPtr) + { + DeallocateSfxBlock(dblockptr->SfxPtr); + } + + DeallocateObjectBlock(dblockptr); /* Back to Free List */ + + /* If this is the current landscape, clear the pointer */ + + return 0; + } + } + } + + return -1; +} + + + + +/* + + Support Functions for Texture Animation Blocks + +*/ + +void InitialiseTxAnimBlocks(void) + +{ + + TXACTRLBLK *FreeBlkPtr = &FreeTxAnimBlockData[0]; + + + FreeTxAnimBlockListPtr = &FreeTxAnimBlockList[maxTxAnimblocks-1]; + + for(NumFreeTxAnimBlocks=0; NumFreeTxAnimBlocks < maxTxAnimblocks; NumFreeTxAnimBlocks++) { + + FreeTxAnimBlockList[NumFreeTxAnimBlocks] = FreeBlkPtr; + + FreeBlkPtr++; + + } + +} + + +/* + + Allocate a Texture Animation Block + +*/ + +TXACTRLBLK* AllocateTxAnimBlock(void) + +{ + + TXACTRLBLK *FreeBlkPtr = 0; /* Default to null ptr */ + int *sptr; + int i; + + + if(NumFreeTxAnimBlocks) { + + FreeBlkPtr = *FreeTxAnimBlockListPtr--; + + NumFreeTxAnimBlocks--; /* One less free block */ + + /* Clear the block */ + + sptr = (int *)FreeBlkPtr; + for(i = sizeof(TXACTRLBLK)/4; i!=0; i--) + *sptr++ = 0; + + } + + return FreeBlkPtr; + +} + + +/* + + Deallocate a Texture Animation Block + +*/ + +void DeallocateTxAnimBlock(TXACTRLBLK *TxAnimblockptr) + +{ + + FreeTxAnimBlockListPtr++; + + *FreeTxAnimBlockListPtr = TxAnimblockptr; + + NumFreeTxAnimBlocks++; /* One more free block */ + +} + + +/* + + Add a Texture Animation Block to a Display Block + +*/ + +void AddTxAnimBlock(DISPLAYBLOCK *dptr, TXACTRLBLK *taptr) + +{ + + TXACTRLBLK *taptr_tmp; + + + if(dptr->ObTxAnimCtrlBlks) { + + taptr_tmp = dptr->ObTxAnimCtrlBlks; + + while(taptr_tmp->tac_next) + taptr_tmp = taptr_tmp->tac_next; + + taptr_tmp->tac_next = taptr; + + } + + else dptr->ObTxAnimCtrlBlks = taptr; + +} + + + + + +/* + + Support functions for Light Blocks + +*/ + +void InitialiseLightBlocks(void) + +{ + + LIGHTBLOCK *FreeBlkPtr = &FreeLightBlockData[0]; + + + FreeLightBlockListPtr = &FreeLightBlockList[maxlightblocks-1]; + + for(NumFreeLightBlocks=0; NumFreeLightBlocks < maxlightblocks; NumFreeLightBlocks++) { + + FreeLightBlockList[NumFreeLightBlocks] = FreeBlkPtr; + + FreeBlkPtr++; + + } + +} + + +LIGHTBLOCK* AllocateLightBlock(void) + +{ + + LIGHTBLOCK *FreeBlkPtr = 0; /* Default to null ptr */ + int *lptr; + int i; + + + if(NumFreeLightBlocks) { + + FreeBlkPtr = *FreeLightBlockListPtr--; + + NumFreeLightBlocks--; /* One less free block */ + + /* Clear the block */ + + lptr = (int *)FreeBlkPtr; + for(i = sizeof(LIGHTBLOCK)/4; i!=0; i--) + *lptr++ = 0; + + } + + return(FreeBlkPtr); + +} + + +void DeallocateLightBlock(LIGHTBLOCK *lptr) + +{ + + /* Not all lights come from the free light list */ + + if(lptr->LightFlags & LFlag_WasNotAllocated) return; + + + /* Make sure that this light IS from the free light list */ + + GLOBALASSERT( + (lptr >= FreeLightBlockData) && + (lptr < &FreeLightBlockData[maxlightblocks]) + ); + + + /* Ok to return the light */ + + FreeLightBlockListPtr++; + + *FreeLightBlockListPtr = lptr; + + NumFreeLightBlocks++; /* One more free block */ + +} + + +/* + + See if there are any free slots in the dptr light block array. + If there are, allocate a light block, place it in the list and return + the pointer to the caller. + + A late addition is the passing of a light block (from somewhere, it does + not matter where). This light block is then added rather than one being + allocated from the free light block list. + +*/ + +LIGHTBLOCK* AddLightBlock(DISPLAYBLOCK *dptr, LIGHTBLOCK *lptr_to_add) + +{ + + LIGHTBLOCK **larrayptr; + LIGHTBLOCK **freelarrayptr; + LIGHTBLOCK *lptr = 0; + int i, lfree; + + + /* Are there any free slots? */ + + lfree = No; + + larrayptr = &dptr->ObLights[0]; + + for(i = MaxObjectLights; i!=0 && lfree == No; i--) { + + if(*larrayptr == 0) { + + freelarrayptr = larrayptr; + lfree = Yes; + + } + + larrayptr++; + + } + + if(lfree) { + + if(lptr_to_add) { + + lptr = lptr_to_add; + + } + + else { + + lptr = AllocateLightBlock(); + + } + + if(lptr) + { + *freelarrayptr = lptr; + dptr->ObNumLights++; + } + + } + + return lptr; + +} + + +/* + + To delete a light block, copy the end block to the new free slot and + reduce the count by one. Make sure the end block array entry is cleared. + +*/ + +void DeleteLightBlock(LIGHTBLOCK *lptr, DISPLAYBLOCK *dptr) +{ + + int i, larrayi; + + DeallocateLightBlock(lptr); + + /* What is lptr's array index? */ + + larrayi = -1; /* null value */ + + for(i = 0; i < dptr->ObNumLights; i++) + if(dptr->ObLights[i] == lptr) larrayi = i; + + + + /* Proceed only if lptr has been found in the array */ + + if(larrayi != -1) { + + /* Copy the end block to that of lptr */ + + dptr->ObLights[larrayi] = dptr->ObLights[dptr->ObNumLights - 1]; + + /* Clear the end block array entry */ + + dptr->ObLights[dptr->ObNumLights - 1] = 0; + + /* One less light in the dptr list */ + + dptr->ObNumLights--; + + } +} + + + + +/* + + When running the parallel strategies, display and light block deallocation + must only be done at the end of the frame, AFTER processor synchronisation + and BEFORE the shadow copy. + +*/ + +int DisplayAndLightBlockDeallocation(void) +{ + + DISPLAYBLOCK **activeblocksptr; + DISPLAYBLOCK *dptr; + int i, j; + LIGHTBLOCK *lptr; + + if(NumActiveBlocks) { + + activeblocksptr = &ActiveBlockList[NumActiveBlocks - 1]; + + for(i = NumActiveBlocks; i!=0; i--) { + + dptr = *activeblocksptr--; + + /* Deallocate Object? */ + + if(dptr->ObFlags2 & ObFlag2_Deallocate) { + + DestroyActiveObject(dptr); + + } + + + /* Deallocate any Lights? */ + + else { + + if(dptr->ObNumLights) { + + for(j = dptr->ObNumLights - 1; j > -1; j--) { + + lptr = dptr->ObLights[j]; + + if(lptr->LightFlags & LFlag_Deallocate) { + + DeleteLightBlock(dptr->ObLights[j], dptr); + + } + + } + + } + + } + + } + + } + return 0; +} diff --git a/3dc/SMACKW32.DLL b/3dc/SMACKW32.DLL new file mode 100644 index 0000000..7ea8871 Binary files /dev/null and b/3dc/SMACKW32.DLL differ diff --git a/3dc/SMACKW32.LIB b/3dc/SMACKW32.LIB new file mode 100644 index 0000000..4747792 Binary files /dev/null and b/3dc/SMACKW32.LIB differ diff --git a/3dc/TABLES.C b/3dc/TABLES.C new file mode 100644 index 0000000..f3f1efd --- /dev/null +++ b/3dc/TABLES.C @@ -0,0 +1,16460 @@ +#include "system.h" + +/* + + SIN and COS tables. The table starts with SIN and overlaps with COS. + 360 degrees = 4,096 angles to index the table. Values are shifted up + 16 times i.e. x 65,536. + + Also ARCCOS, ARCSIN and ARCTAN + +*/ + +#if PSX + int sine[]={}; + int cosine[]={}; +#else +int oneoversin[4096]; + +int sine[]={ + + 0, + 100, + 201, + 301, + 402, + 502, + 603, + 703, + 804, + 904, + 1005, + 1105, + 1206, + 1306, + 1407, + 1507, + 1608, + 1708, + 1809, + 1909, + 2010, + 2110, + 2211, + 2311, + 2412, + 2512, + 2613, + 2713, + 2814, + 2914, + 3014, + 3115, + 3215, + 3316, + 3416, + 3516, + 3617, + 3717, + 3818, + 3918, + 4018, + 4119, + 4219, + 4319, + 4420, + 4520, + 4620, + 4720, + 4821, + 4921, + 5021, + 5121, + 5222, + 5322, + 5422, + 5522, + 5622, + 5722, + 5823, + 5923, + 6023, + 6123, + 6223, + 6323, + 6423, + 6523, + 6623, + 6723, + 6823, + 6923, + 7023, + 7123, + 7223, + 7323, + 7423, + 7523, + 7623, + 7722, + 7822, + 7922, + 8022, + 8122, + 8221, + 8321, + 8421, + 8520, + 8620, + 8720, + 8819, + 8919, + 9019, + 9118, + 9218, + 9317, + 9417, + 9516, + 9616, + 9715, + 9814, + 9914, + 10013, + 10113, + 10212, + 10311, + 10410, + 10510, + 10609, + 10708, + 10807, + 10906, + 11006, + 11105, + 11204, + 11303, + 11402, + 11501, + 11600, + 11699, + 11797, + 11896, + 11995, + 12094, + 12193, + 12292, + 12390, + 12489, + 12588, + 12686, + 12785, + 12884, + 12982, + 13081, + 13179, + 13278, + 13376, + 13474, + 13573, + 13671, + 13769, + 13868, + 13966, + 14064, + 14162, + 14260, + 14359, + 14457, + 14555, + 14653, + 14751, + 14849, + 14946, + 15044, + 15142, + 15240, + 15338, + 15435, + 15533, + 15631, + 15728, + 15826, + 15923, + 16021, + 16118, + 16216, + 16313, + 16411, + 16508, + 16605, + 16702, + 16800, + 16897, + 16994, + 17091, + 17188, + 17285, + 17382, + 17479, + 17576, + 17672, + 17769, + 17866, + 17963, + 18059, + 18156, + 18253, + 18349, + 18446, + 18542, + 18638, + 18735, + 18831, + 18927, + 19024, + 19120, + 19216, + 19312, + 19408, + 19504, + 19600, + 19696, + 19792, + 19888, + 19983, + 20079, + 20175, + 20270, + 20366, + 20461, + 20557, + 20652, + 20748, + 20843, + 20938, + 21034, + 21129, + 21224, + 21319, + 21414, + 21509, + 21604, + 21699, + 21794, + 21889, + 21983, + 22078, + 22173, + 22267, + 22362, + 22456, + 22551, + 22645, + 22739, + 22833, + 22928, + 23022, + 23116, + 23210, + 23304, + 23398, + 23492, + 23586, + 23679, + 23773, + 23867, + 23960, + 24054, + 24147, + 24241, + 24334, + 24427, + 24521, + 24614, + 24707, + 24800, + 24893, + 24986, + 25079, + 25172, + 25265, + 25357, + 25450, + 25543, + 25635, + 25728, + 25820, + 25913, + 26005, + 26097, + 26189, + 26281, + 26373, + 26465, + 26557, + 26649, + 26741, + 26833, + 26925, + 27016, + 27108, + 27199, + 27291, + 27382, + 27473, + 27565, + 27656, + 27747, + 27838, + 27929, + 28020, + 28111, + 28201, + 28292, + 28383, + 28473, + 28564, + 28654, + 28745, + 28835, + 28925, + 29015, + 29105, + 29196, + 29285, + 29375, + 29465, + 29555, + 29645, + 29734, + 29824, + 29913, + 30003, + 30092, + 30181, + 30271, + 30360, + 30449, + 30538, + 30627, + 30715, + 30804, + 30893, + 30982, + 31070, + 31159, + 31247, + 31335, + 31424, + 31512, + 31600, + 31688, + 31776, + 31864, + 31952, + 32039, + 32127, + 32215, + 32302, + 32390, + 32477, + 32564, + 32651, + 32738, + 32826, + 32912, + 32999, + 33086, + 33173, + 33260, + 33346, + 33433, + 33519, + 33605, + 33692, + 33778, + 33864, + 33950, + 34036, + 34122, + 34208, + 34293, + 34379, + 34465, + 34550, + 34635, + 34721, + 34806, + 34891, + 34976, + 35061, + 35146, + 35231, + 35316, + 35400, + 35485, + 35569, + 35654, + 35738, + 35822, + 35906, + 35990, + 36074, + 36158, + 36242, + 36326, + 36409, + 36493, + 36576, + 36660, + 36743, + 36826, + 36909, + 36992, + 37075, + 37158, + 37241, + 37324, + 37406, + 37489, + 37571, + 37653, + 37736, + 37818, + 37900, + 37982, + 38064, + 38146, + 38227, + 38309, + 38390, + 38472, + 38553, + 38634, + 38716, + 38797, + 38878, + 38958, + 39039, + 39120, + 39201, + 39281, + 39362, + 39442, + 39522, + 39602, + 39682, + 39762, + 39842, + 39922, + 40002, + 40081, + 40161, + 40240, + 40319, + 40399, + 40478, + 40557, + 40636, + 40714, + 40793, + 40872, + 40950, + 41029, + 41107, + 41185, + 41263, + 41342, + 41419, + 41497, + 41575, + 41653, + 41730, + 41808, + 41885, + 41962, + 42040, + 42117, + 42194, + 42271, + 42347, + 42424, + 42501, + 42577, + 42653, + 42730, + 42806, + 42882, + 42958, + 43034, + 43110, + 43185, + 43261, + 43336, + 43412, + 43487, + 43562, + 43637, + 43712, + 43787, + 43862, + 43936, + 44011, + 44085, + 44160, + 44234, + 44308, + 44382, + 44456, + 44530, + 44603, + 44677, + 44750, + 44824, + 44897, + 44970, + 45043, + 45116, + 45189, + 45262, + 45335, + 45407, + 45480, + 45552, + 45624, + 45696, + 45768, + 45840, + 45912, + 45984, + 46055, + 46127, + 46198, + 46269, + 46340, + 46411, + 46482, + 46553, + 46624, + 46695, + 46765, + 46835, + 46906, + 46976, + 47046, + 47116, + 47186, + 47255, + 47325, + 47394, + 47464, + 47533, + 47602, + 47671, + 47740, + 47809, + 47878, + 47946, + 48015, + 48083, + 48151, + 48219, + 48288, + 48355, + 48423, + 48491, + 48558, + 48626, + 48693, + 48760, + 48828, + 48895, + 48961, + 49028, + 49095, + 49161, + 49228, + 49294, + 49360, + 49426, + 49492, + 49558, + 49624, + 49690, + 49755, + 49820, + 49886, + 49951, + 50016, + 50081, + 50146, + 50210, + 50275, + 50339, + 50403, + 50468, + 50532, + 50596, + 50660, + 50723, + 50787, + 50850, + 50914, + 50977, + 51040, + 51103, + 51166, + 51229, + 51291, + 51354, + 51416, + 51478, + 51541, + 51603, + 51665, + 51726, + 51788, + 51850, + 51911, + 51972, + 52033, + 52095, + 52155, + 52216, + 52277, + 52338, + 52398, + 52458, + 52518, + 52579, + 52639, + 52698, + 52758, + 52818, + 52877, + 52936, + 52996, + 53055, + 53114, + 53172, + 53231, + 53290, + 53348, + 53407, + 53465, + 53523, + 53581, + 53639, + 53696, + 53754, + 53811, + 53869, + 53926, + 53983, + 54040, + 54097, + 54153, + 54210, + 54266, + 54323, + 54379, + 54435, + 54491, + 54546, + 54602, + 54658, + 54713, + 54768, + 54823, + 54879, + 54933, + 54988, + 55043, + 55097, + 55152, + 55206, + 55260, + 55314, + 55368, + 55422, + 55475, + 55529, + 55582, + 55635, + 55688, + 55741, + 55794, + 55847, + 55899, + 55952, + 56004, + 56056, + 56108, + 56160, + 56212, + 56263, + 56315, + 56366, + 56417, + 56468, + 56519, + 56570, + 56621, + 56671, + 56722, + 56772, + 56822, + 56872, + 56922, + 56972, + 57022, + 57071, + 57120, + 57170, + 57219, + 57268, + 57316, + 57365, + 57414, + 57462, + 57510, + 57558, + 57606, + 57654, + 57702, + 57750, + 57797, + 57844, + 57892, + 57939, + 57986, + 58032, + 58079, + 58125, + 58172, + 58218, + 58264, + 58310, + 58356, + 58402, + 58447, + 58493, + 58538, + 58583, + 58628, + 58673, + 58718, + 58762, + 58807, + 58851, + 58895, + 58939, + 58983, + 59027, + 59070, + 59114, + 59157, + 59200, + 59243, + 59286, + 59329, + 59372, + 59414, + 59457, + 59499, + 59541, + 59583, + 59625, + 59666, + 59708, + 59749, + 59790, + 59831, + 59872, + 59913, + 59954, + 59994, + 60035, + 60075, + 60115, + 60155, + 60195, + 60235, + 60274, + 60313, + 60353, + 60392, + 60431, + 60470, + 60508, + 60547, + 60585, + 60624, + 60662, + 60700, + 60737, + 60775, + 60813, + 60850, + 60887, + 60924, + 60961, + 60998, + 61035, + 61071, + 61108, + 61144, + 61180, + 61216, + 61252, + 61288, + 61323, + 61359, + 61394, + 61429, + 61464, + 61499, + 61533, + 61568, + 61602, + 61637, + 61671, + 61705, + 61738, + 61772, + 61805, + 61839, + 61872, + 61905, + 61938, + 61971, + 62003, + 62036, + 62068, + 62100, + 62133, + 62164, + 62196, + 62228, + 62259, + 62291, + 62322, + 62353, + 62384, + 62414, + 62445, + 62475, + 62506, + 62536, + 62566, + 62596, + 62625, + 62655, + 62684, + 62714, + 62743, + 62772, + 62800, + 62829, + 62858, + 62886, + 62914, + 62942, + 62970, + 62998, + 63026, + 63053, + 63080, + 63108, + 63135, + 63162, + 63188, + 63215, + 63241, + 63268, + 63294, + 63320, + 63346, + 63371, + 63397, + 63422, + 63447, + 63473, + 63498, + 63522, + 63547, + 63571, + 63596, + 63620, + 63644, + 63668, + 63692, + 63715, + 63739, + 63762, + 63785, + 63808, + 63831, + 63854, + 63876, + 63899, + 63921, + 63943, + 63965, + 63987, + 64009, + 64030, + 64051, + 64073, + 64094, + 64115, + 64135, + 64156, + 64176, + 64197, + 64217, + 64237, + 64257, + 64276, + 64296, + 64315, + 64334, + 64353, + 64372, + 64391, + 64410, + 64428, + 64447, + 64465, + 64483, + 64501, + 64518, + 64536, + 64553, + 64571, + 64588, + 64605, + 64622, + 64638, + 64655, + 64671, + 64687, + 64703, + 64719, + 64735, + 64751, + 64766, + 64781, + 64796, + 64811, + 64826, + 64841, + 64855, + 64870, + 64884, + 64898, + 64912, + 64926, + 64939, + 64953, + 64966, + 64979, + 64992, + 65005, + 65018, + 65030, + 65043, + 65055, + 65067, + 65079, + 65091, + 65102, + 65114, + 65125, + 65136, + 65147, + 65158, + 65169, + 65179, + 65190, + 65200, + 65210, + 65220, + 65230, + 65239, + 65249, + 65258, + 65267, + 65276, + 65285, + 65294, + 65302, + 65311, + 65319, + 65327, + 65335, + 65343, + 65350, + 65358, + 65365, + 65372, + 65379, + 65386, + 65393, + 65400, + 65406, + 65412, + 65418, + 65424, + 65430, + 65436, + 65441, + 65446, + 65452, + 65457, + 65461, + 65466, + 65471, + 65475, + 65479, + 65483, + 65487, + 65491, + 65495, + 65498, + 65501, + 65505, + 65508, + 65511, + 65513, + 65516, + 65518, + 65520, + 65522, + 65524, + 65526, + 65528, + 65529, + 65531, + 65532, + 65533, + 65534, + 65534, + 65535, + 65535, + 65535, + 65535, + 65535, + 65535, + 65535, + 65534, + 65534, + 65533, + 65532, + 65531, + 65529, + 65528, + 65526, + 65524, + 65522, + 65520, + 65518, + 65516, + 65513, + 65511, + 65508, + 65505, + 65501, + 65498, + 65495, + 65491, + 65487, + 65483, + 65479, + 65475, + 65471, + 65466, + 65461, + 65457, + 65452, + 65446, + 65441, + 65436, + 65430, + 65424, + 65418, + 65412, + 65406, + 65400, + 65393, + 65386, + 65379, + 65372, + 65365, + 65358, + 65350, + 65343, + 65335, + 65327, + 65319, + 65311, + 65302, + 65294, + 65285, + 65276, + 65267, + 65258, + 65249, + 65239, + 65230, + 65220, + 65210, + 65200, + 65190, + 65179, + 65169, + 65158, + 65147, + 65136, + 65125, + 65114, + 65102, + 65091, + 65079, + 65067, + 65055, + 65043, + 65030, + 65018, + 65005, + 64992, + 64979, + 64966, + 64953, + 64939, + 64926, + 64912, + 64898, + 64884, + 64870, + 64855, + 64841, + 64826, + 64811, + 64796, + 64781, + 64766, + 64751, + 64735, + 64719, + 64703, + 64687, + 64671, + 64655, + 64638, + 64622, + 64605, + 64588, + 64571, + 64553, + 64536, + 64518, + 64501, + 64483, + 64465, + 64447, + 64428, + 64410, + 64391, + 64372, + 64353, + 64334, + 64315, + 64296, + 64276, + 64257, + 64237, + 64217, + 64197, + 64176, + 64156, + 64135, + 64115, + 64094, + 64073, + 64051, + 64030, + 64009, + 63987, + 63965, + 63943, + 63921, + 63899, + 63876, + 63854, + 63831, + 63808, + 63785, + 63762, + 63739, + 63715, + 63692, + 63668, + 63644, + 63620, + 63596, + 63571, + 63547, + 63522, + 63498, + 63473, + 63447, + 63422, + 63397, + 63371, + 63346, + 63320, + 63294, + 63268, + 63241, + 63215, + 63188, + 63162, + 63135, + 63108, + 63080, + 63053, + 63026, + 62998, + 62970, + 62942, + 62914, + 62886, + 62858, + 62829, + 62800, + 62772, + 62743, + 62714, + 62684, + 62655, + 62625, + 62596, + 62566, + 62536, + 62506, + 62475, + 62445, + 62414, + 62384, + 62353, + 62322, + 62291, + 62259, + 62228, + 62196, + 62164, + 62133, + 62100, + 62068, + 62036, + 62003, + 61971, + 61938, + 61905, + 61872, + 61839, + 61805, + 61772, + 61738, + 61705, + 61671, + 61637, + 61602, + 61568, + 61533, + 61499, + 61464, + 61429, + 61394, + 61359, + 61323, + 61288, + 61252, + 61216, + 61180, + 61144, + 61108, + 61071, + 61035, + 60998, + 60961, + 60924, + 60887, + 60850, + 60813, + 60775, + 60737, + 60700, + 60662, + 60624, + 60585, + 60547, + 60508, + 60470, + 60431, + 60392, + 60353, + 60313, + 60274, + 60235, + 60195, + 60155, + 60115, + 60075, + 60035, + 59994, + 59954, + 59913, + 59872, + 59831, + 59790, + 59749, + 59708, + 59666, + 59625, + 59583, + 59541, + 59499, + 59457, + 59414, + 59372, + 59329, + 59286, + 59243, + 59200, + 59157, + 59114, + 59070, + 59027, + 58983, + 58939, + 58895, + 58851, + 58807, + 58762, + 58718, + 58673, + 58628, + 58583, + 58538, + 58493, + 58447, + 58402, + 58356, + 58310, + 58264, + 58218, + 58172, + 58125, + 58079, + 58032, + 57986, + 57939, + 57892, + 57844, + 57797, + 57750, + 57702, + 57654, + 57606, + 57558, + 57510, + 57462, + 57414, + 57365, + 57316, + 57268, + 57219, + 57170, + 57120, + 57071, + 57022, + 56972, + 56922, + 56872, + 56822, + 56772, + 56722, + 56671, + 56621, + 56570, + 56519, + 56468, + 56417, + 56366, + 56315, + 56263, + 56212, + 56160, + 56108, + 56056, + 56004, + 55952, + 55899, + 55847, + 55794, + 55741, + 55688, + 55635, + 55582, + 55529, + 55475, + 55422, + 55368, + 55314, + 55260, + 55206, + 55152, + 55097, + 55043, + 54988, + 54933, + 54879, + 54823, + 54768, + 54713, + 54658, + 54602, + 54546, + 54491, + 54435, + 54379, + 54323, + 54266, + 54210, + 54153, + 54097, + 54040, + 53983, + 53926, + 53869, + 53811, + 53754, + 53696, + 53639, + 53581, + 53523, + 53465, + 53407, + 53348, + 53290, + 53231, + 53172, + 53114, + 53055, + 52996, + 52936, + 52877, + 52818, + 52758, + 52698, + 52639, + 52579, + 52518, + 52458, + 52398, + 52338, + 52277, + 52216, + 52155, + 52095, + 52033, + 51972, + 51911, + 51850, + 51788, + 51726, + 51665, + 51603, + 51541, + 51478, + 51416, + 51354, + 51291, + 51229, + 51166, + 51103, + 51040, + 50977, + 50914, + 50850, + 50787, + 50723, + 50660, + 50596, + 50532, + 50468, + 50403, + 50339, + 50275, + 50210, + 50146, + 50081, + 50016, + 49951, + 49886, + 49820, + 49755, + 49690, + 49624, + 49558, + 49492, + 49426, + 49360, + 49294, + 49228, + 49161, + 49095, + 49028, + 48961, + 48895, + 48828, + 48760, + 48693, + 48626, + 48558, + 48491, + 48423, + 48355, + 48288, + 48219, + 48151, + 48083, + 48015, + 47946, + 47878, + 47809, + 47740, + 47671, + 47602, + 47533, + 47464, + 47394, + 47325, + 47255, + 47186, + 47116, + 47046, + 46976, + 46906, + 46835, + 46765, + 46695, + 46624, + 46553, + 46482, + 46411, + 46340, + 46269, + 46198, + 46127, + 46055, + 45984, + 45912, + 45840, + 45768, + 45696, + 45624, + 45552, + 45480, + 45407, + 45335, + 45262, + 45189, + 45116, + 45043, + 44970, + 44897, + 44824, + 44750, + 44677, + 44603, + 44530, + 44456, + 44382, + 44308, + 44234, + 44160, + 44085, + 44011, + 43936, + 43862, + 43787, + 43712, + 43637, + 43562, + 43487, + 43412, + 43336, + 43261, + 43185, + 43110, + 43034, + 42958, + 42882, + 42806, + 42730, + 42653, + 42577, + 42501, + 42424, + 42347, + 42271, + 42194, + 42117, + 42040, + 41962, + 41885, + 41808, + 41730, + 41653, + 41575, + 41497, + 41419, + 41342, + 41263, + 41185, + 41107, + 41029, + 40950, + 40872, + 40793, + 40714, + 40636, + 40557, + 40478, + 40399, + 40319, + 40240, + 40161, + 40081, + 40002, + 39922, + 39842, + 39762, + 39682, + 39602, + 39522, + 39442, + 39362, + 39281, + 39201, + 39120, + 39039, + 38958, + 38878, + 38797, + 38716, + 38634, + 38553, + 38472, + 38390, + 38309, + 38227, + 38146, + 38064, + 37982, + 37900, + 37818, + 37736, + 37653, + 37571, + 37489, + 37406, + 37324, + 37241, + 37158, + 37075, + 36992, + 36909, + 36826, + 36743, + 36660, + 36576, + 36493, + 36409, + 36326, + 36242, + 36158, + 36074, + 35990, + 35906, + 35822, + 35738, + 35654, + 35569, + 35485, + 35400, + 35316, + 35231, + 35146, + 35061, + 34976, + 34891, + 34806, + 34721, + 34635, + 34550, + 34465, + 34379, + 34293, + 34208, + 34122, + 34036, + 33950, + 33864, + 33778, + 33692, + 33605, + 33519, + 33433, + 33346, + 33260, + 33173, + 33086, + 32999, + 32912, + 32826, + 32738, + 32651, + 32564, + 32477, + 32390, + 32302, + 32215, + 32127, + 32039, + 31952, + 31864, + 31776, + 31688, + 31600, + 31512, + 31424, + 31335, + 31247, + 31159, + 31070, + 30982, + 30893, + 30804, + 30715, + 30627, + 30538, + 30449, + 30360, + 30271, + 30181, + 30092, + 30003, + 29913, + 29824, + 29734, + 29645, + 29555, + 29465, + 29375, + 29285, + 29196, + 29105, + 29015, + 28925, + 28835, + 28745, + 28654, + 28564, + 28473, + 28383, + 28292, + 28201, + 28111, + 28020, + 27929, + 27838, + 27747, + 27656, + 27565, + 27473, + 27382, + 27291, + 27199, + 27108, + 27016, + 26925, + 26833, + 26741, + 26649, + 26557, + 26465, + 26373, + 26281, + 26189, + 26097, + 26005, + 25913, + 25820, + 25728, + 25635, + 25543, + 25450, + 25357, + 25265, + 25172, + 25079, + 24986, + 24893, + 24800, + 24707, + 24614, + 24521, + 24427, + 24334, + 24241, + 24147, + 24054, + 23960, + 23867, + 23773, + 23679, + 23586, + 23492, + 23398, + 23304, + 23210, + 23116, + 23022, + 22928, + 22833, + 22739, + 22645, + 22551, + 22456, + 22362, + 22267, + 22173, + 22078, + 21983, + 21889, + 21794, + 21699, + 21604, + 21509, + 21414, + 21319, + 21224, + 21129, + 21034, + 20938, + 20843, + 20748, + 20652, + 20557, + 20461, + 20366, + 20270, + 20175, + 20079, + 19983, + 19888, + 19792, + 19696, + 19600, + 19504, + 19408, + 19312, + 19216, + 19120, + 19024, + 18927, + 18831, + 18735, + 18638, + 18542, + 18446, + 18349, + 18253, + 18156, + 18059, + 17963, + 17866, + 17769, + 17672, + 17576, + 17479, + 17382, + 17285, + 17188, + 17091, + 16994, + 16897, + 16800, + 16702, + 16605, + 16508, + 16411, + 16313, + 16216, + 16118, + 16021, + 15923, + 15826, + 15728, + 15631, + 15533, + 15435, + 15338, + 15240, + 15142, + 15044, + 14946, + 14849, + 14751, + 14653, + 14555, + 14457, + 14359, + 14260, + 14162, + 14064, + 13966, + 13868, + 13769, + 13671, + 13573, + 13474, + 13376, + 13278, + 13179, + 13081, + 12982, + 12884, + 12785, + 12686, + 12588, + 12489, + 12390, + 12292, + 12193, + 12094, + 11995, + 11896, + 11797, + 11699, + 11600, + 11501, + 11402, + 11303, + 11204, + 11105, + 11006, + 10906, + 10807, + 10708, + 10609, + 10510, + 10410, + 10311, + 10212, + 10113, + 10013, + 9914, + 9814, + 9715, + 9616, + 9516, + 9417, + 9317, + 9218, + 9118, + 9019, + 8919, + 8819, + 8720, + 8620, + 8520, + 8421, + 8321, + 8221, + 8122, + 8022, + 7922, + 7822, + 7722, + 7623, + 7523, + 7423, + 7323, + 7223, + 7123, + 7023, + 6923, + 6823, + 6723, + 6623, + 6523, + 6423, + 6323, + 6223, + 6123, + 6023, + 5923, + 5823, + 5722, + 5622, + 5522, + 5422, + 5322, + 5222, + 5121, + 5021, + 4921, + 4821, + 4720, + 4620, + 4520, + 4420, + 4319, + 4219, + 4119, + 4018, + 3918, + 3818, + 3717, + 3617, + 3516, + 3416, + 3316, + 3215, + 3115, + 3014, + 2914, + 2814, + 2713, + 2613, + 2512, + 2412, + 2311, + 2211, + 2110, + 2010, + 1909, + 1809, + 1708, + 1608, + 1507, + 1407, + 1306, + 1206, + 1105, + 1005, + 904, + 804, + 703, + 603, + 502, + 402, + 301, + 201, + 100, + 0, + -101, + -202, + -302, + -403, + -503, + -604, + -704, + -805, + -905, + -1006, + -1106, + -1207, + -1307, + -1408, + -1508, + -1609, + -1709, + -1810, + -1910, + -2011, + -2111, + -2212, + -2312, + -2413, + -2513, + -2614, + -2714, + -2814, + -2915, + -3015, + -3116, + -3216, + -3317, + -3417, + -3517, + -3618, + -3718, + -3819, + -3919, + -4019, + -4120, + -4220, + -4320, + -4421, + -4521, + -4621, + -4721, + -4822, + -4922, + -5022, + -5122, + -5223, + -5323, + -5423, + -5523, + -5623, + -5723, + -5824, + -5924, + -6024, + -6124, + -6224, + -6324, + -6424, + -6524, + -6624, + -6724, + -6824, + -6924, + -7024, + -7124, + -7224, + -7324, + -7424, + -7524, + -7624, + -7723, + -7823, + -7923, + -8023, + -8123, + -8222, + -8322, + -8422, + -8521, + -8621, + -8721, + -8820, + -8920, + -9020, + -9119, + -9219, + -9318, + -9418, + -9517, + -9617, + -9716, + -9815, + -9915, + -10014, + -10114, + -10213, + -10312, + -10411, + -10511, + -10610, + -10709, + -10808, + -10907, + -11007, + -11106, + -11205, + -11304, + -11403, + -11502, + -11601, + -11700, + -11798, + -11897, + -11996, + -12095, + -12194, + -12293, + -12391, + -12490, + -12589, + -12687, + -12786, + -12885, + -12983, + -13082, + -13180, + -13279, + -13377, + -13475, + -13574, + -13672, + -13770, + -13869, + -13967, + -14065, + -14163, + -14261, + -14360, + -14458, + -14556, + -14654, + -14752, + -14850, + -14947, + -15045, + -15143, + -15241, + -15339, + -15436, + -15534, + -15632, + -15729, + -15827, + -15924, + -16022, + -16119, + -16217, + -16314, + -16412, + -16509, + -16606, + -16703, + -16801, + -16898, + -16995, + -17092, + -17189, + -17286, + -17383, + -17480, + -17577, + -17673, + -17770, + -17867, + -17964, + -18060, + -18157, + -18254, + -18350, + -18447, + -18543, + -18639, + -18736, + -18832, + -18928, + -19025, + -19121, + -19217, + -19313, + -19409, + -19505, + -19601, + -19697, + -19793, + -19889, + -19984, + -20080, + -20176, + -20271, + -20367, + -20462, + -20558, + -20653, + -20749, + -20844, + -20939, + -21035, + -21130, + -21225, + -21320, + -21415, + -21510, + -21605, + -21700, + -21795, + -21889, + -21984, + -22079, + -22174, + -22268, + -22363, + -22457, + -22552, + -22646, + -22740, + -22834, + -22929, + -23023, + -23117, + -23211, + -23305, + -23399, + -23493, + -23587, + -23680, + -23774, + -23868, + -23961, + -24055, + -24148, + -24242, + -24335, + -24428, + -24522, + -24615, + -24708, + -24801, + -24894, + -24987, + -25080, + -25173, + -25266, + -25358, + -25451, + -25544, + -25636, + -25729, + -25821, + -25914, + -26006, + -26098, + -26190, + -26282, + -26374, + -26466, + -26558, + -26650, + -26742, + -26834, + -26926, + -27017, + -27109, + -27200, + -27292, + -27383, + -27474, + -27566, + -27657, + -27748, + -27839, + -27930, + -28021, + -28112, + -28202, + -28293, + -28384, + -28474, + -28565, + -28655, + -28746, + -28836, + -28926, + -29016, + -29106, + -29197, + -29286, + -29376, + -29466, + -29556, + -29646, + -29735, + -29825, + -29914, + -30004, + -30093, + -30182, + -30272, + -30361, + -30450, + -30539, + -30628, + -30716, + -30805, + -30894, + -30983, + -31071, + -31160, + -31248, + -31336, + -31425, + -31513, + -31601, + -31689, + -31777, + -31865, + -31953, + -32040, + -32128, + -32216, + -32303, + -32391, + -32478, + -32565, + -32652, + -32739, + -32827, + -32913, + -33000, + -33087, + -33174, + -33261, + -33347, + -33434, + -33520, + -33606, + -33693, + -33779, + -33865, + -33951, + -34037, + -34123, + -34209, + -34294, + -34380, + -34466, + -34551, + -34636, + -34722, + -34807, + -34892, + -34977, + -35062, + -35147, + -35232, + -35317, + -35401, + -35486, + -35570, + -35655, + -35739, + -35823, + -35907, + -35991, + -36075, + -36159, + -36243, + -36327, + -36410, + -36494, + -36577, + -36661, + -36744, + -36827, + -36910, + -36993, + -37076, + -37159, + -37242, + -37325, + -37407, + -37490, + -37572, + -37654, + -37737, + -37819, + -37901, + -37983, + -38065, + -38147, + -38228, + -38310, + -38391, + -38473, + -38554, + -38635, + -38717, + -38798, + -38879, + -38959, + -39040, + -39121, + -39202, + -39282, + -39362, + -39443, + -39523, + -39603, + -39683, + -39763, + -39843, + -39923, + -40003, + -40082, + -40162, + -40241, + -40320, + -40400, + -40479, + -40558, + -40637, + -40715, + -40794, + -40873, + -40951, + -41030, + -41108, + -41186, + -41264, + -41343, + -41420, + -41498, + -41576, + -41654, + -41731, + -41809, + -41886, + -41963, + -42041, + -42118, + -42195, + -42272, + -42348, + -42425, + -42502, + -42578, + -42654, + -42731, + -42807, + -42883, + -42959, + -43035, + -43111, + -43186, + -43262, + -43337, + -43413, + -43488, + -43563, + -43638, + -43713, + -43788, + -43863, + -43937, + -44012, + -44086, + -44161, + -44235, + -44309, + -44383, + -44457, + -44531, + -44604, + -44678, + -44751, + -44825, + -44898, + -44971, + -45044, + -45117, + -45190, + -45263, + -45336, + -45408, + -45481, + -45553, + -45625, + -45697, + -45769, + -45841, + -45913, + -45985, + -46056, + -46128, + -46199, + -46270, + -46341, + -46412, + -46483, + -46554, + -46625, + -46696, + -46766, + -46836, + -46907, + -46977, + -47047, + -47117, + -47187, + -47256, + -47326, + -47395, + -47465, + -47534, + -47603, + -47672, + -47741, + -47810, + -47879, + -47947, + -48016, + -48084, + -48152, + -48220, + -48289, + -48356, + -48424, + -48492, + -48559, + -48627, + -48694, + -48761, + -48829, + -48896, + -48962, + -49029, + -49096, + -49162, + -49229, + -49295, + -49361, + -49427, + -49493, + -49559, + -49625, + -49691, + -49756, + -49821, + -49887, + -49952, + -50017, + -50082, + -50146, + -50211, + -50276, + -50340, + -50404, + -50469, + -50533, + -50597, + -50661, + -50724, + -50788, + -50851, + -50915, + -50978, + -51041, + -51104, + -51167, + -51230, + -51292, + -51355, + -51417, + -51479, + -51542, + -51604, + -51666, + -51727, + -51789, + -51851, + -51912, + -51973, + -52034, + -52096, + -52156, + -52217, + -52278, + -52339, + -52399, + -52459, + -52519, + -52580, + -52640, + -52699, + -52759, + -52819, + -52878, + -52937, + -52997, + -53056, + -53115, + -53173, + -53232, + -53291, + -53349, + -53408, + -53466, + -53524, + -53582, + -53640, + -53697, + -53755, + -53812, + -53870, + -53927, + -53984, + -54041, + -54098, + -54154, + -54211, + -54267, + -54324, + -54380, + -54436, + -54492, + -54547, + -54603, + -54659, + -54714, + -54769, + -54824, + -54880, + -54934, + -54989, + -55044, + -55098, + -55153, + -55207, + -55261, + -55315, + -55369, + -55423, + -55476, + -55530, + -55583, + -55636, + -55689, + -55742, + -55795, + -55848, + -55900, + -55953, + -56005, + -56057, + -56109, + -56161, + -56213, + -56264, + -56316, + -56367, + -56418, + -56469, + -56520, + -56571, + -56622, + -56672, + -56723, + -56773, + -56823, + -56873, + -56923, + -56973, + -57023, + -57072, + -57121, + -57171, + -57220, + -57269, + -57317, + -57366, + -57415, + -57463, + -57511, + -57559, + -57607, + -57655, + -57703, + -57751, + -57798, + -57845, + -57893, + -57940, + -57987, + -58033, + -58080, + -58126, + -58173, + -58219, + -58265, + -58311, + -58357, + -58403, + -58448, + -58494, + -58539, + -58584, + -58629, + -58674, + -58719, + -58763, + -58808, + -58852, + -58896, + -58940, + -58984, + -59028, + -59071, + -59115, + -59158, + -59201, + -59244, + -59287, + -59330, + -59373, + -59415, + -59458, + -59500, + -59542, + -59584, + -59626, + -59667, + -59709, + -59750, + -59791, + -59832, + -59873, + -59914, + -59955, + -59995, + -60036, + -60076, + -60116, + -60156, + -60196, + -60236, + -60275, + -60314, + -60354, + -60393, + -60432, + -60471, + -60509, + -60548, + -60586, + -60625, + -60663, + -60701, + -60738, + -60776, + -60814, + -60851, + -60888, + -60925, + -60962, + -60999, + -61036, + -61072, + -61109, + -61145, + -61181, + -61217, + -61253, + -61289, + -61324, + -61360, + -61395, + -61430, + -61465, + -61500, + -61534, + -61569, + -61603, + -61638, + -61672, + -61706, + -61739, + -61773, + -61806, + -61840, + -61873, + -61906, + -61939, + -61972, + -62004, + -62037, + -62069, + -62101, + -62134, + -62165, + -62197, + -62229, + -62260, + -62292, + -62323, + -62354, + -62385, + -62415, + -62446, + -62476, + -62507, + -62537, + -62567, + -62597, + -62626, + -62656, + -62685, + -62715, + -62744, + -62773, + -62801, + -62830, + -62859, + -62887, + -62915, + -62943, + -62971, + -62999, + -63027, + -63054, + -63081, + -63109, + -63136, + -63163, + -63189, + -63216, + -63242, + -63269, + -63295, + -63321, + -63347, + -63372, + -63398, + -63423, + -63448, + -63474, + -63499, + -63523, + -63548, + -63572, + -63597, + -63621, + -63645, + -63669, + -63693, + -63716, + -63740, + -63763, + -63786, + -63809, + -63832, + -63855, + -63877, + -63900, + -63922, + -63944, + -63966, + -63988, + -64010, + -64031, + -64052, + -64074, + -64095, + -64116, + -64136, + -64157, + -64177, + -64198, + -64218, + -64238, + -64258, + -64277, + -64297, + -64316, + -64335, + -64354, + -64373, + -64392, + -64411, + -64429, + -64448, + -64466, + -64484, + -64502, + -64519, + -64537, + -64554, + -64572, + -64589, + -64606, + -64623, + -64639, + -64656, + -64672, + -64688, + -64704, + -64720, + -64736, + -64752, + -64767, + -64782, + -64797, + -64812, + -64827, + -64842, + -64856, + -64871, + -64885, + -64899, + -64913, + -64927, + -64940, + -64954, + -64967, + -64980, + -64993, + -65006, + -65019, + -65031, + -65044, + -65056, + -65068, + -65080, + -65092, + -65103, + -65115, + -65126, + -65137, + -65148, + -65159, + -65170, + -65180, + -65191, + -65201, + -65211, + -65221, + -65231, + -65240, + -65250, + -65259, + -65268, + -65277, + -65286, + -65295, + -65303, + -65312, + -65320, + -65328, + -65336, + -65344, + -65351, + -65359, + -65366, + -65373, + -65380, + -65387, + -65394, + -65401, + -65407, + -65413, + -65419, + -65425, + -65431, + -65437, + -65442, + -65447, + -65453, + -65458, + -65462, + -65467, + -65472, + -65476, + -65480, + -65484, + -65488, + -65492, + -65496, + -65499, + -65502, + -65506, + -65509, + -65512, + -65514, + -65517, + -65519, + -65521, + -65523, + -65525, + -65527, + -65529, + -65530, + -65532, + -65533, + -65534, + -65535, + -65535, + -65536, + -65536, + -65536, + -65536, + -65536, + -65536, + -65536, + -65535, + -65535, + -65534, + -65533, + -65532, + -65530, + -65529, + -65527, + -65525, + -65523, + -65521, + -65519, + -65517, + -65514, + -65512, + -65509, + -65506, + -65502, + -65499, + -65496, + -65492, + -65488, + -65484, + -65480, + -65476, + -65472, + -65467, + -65462, + -65458, + -65453, + -65447, + -65442, + -65437, + -65431, + -65425, + -65419, + -65413, + -65407, + -65401, + -65394, + -65387, + -65380, + -65373, + -65366, + -65359, + -65351, + -65344, + -65336, + -65328, + -65320, + -65312, + -65303, + -65295, + -65286, + -65277, + -65268, + -65259, + -65250, + -65240, + -65231, + -65221, + -65211, + -65201, + -65191, + -65180, + -65170, + -65159, + -65148, + -65137, + -65126, + -65115, + -65103, + -65092, + -65080, + -65068, + -65056, + -65044, + -65031, + -65019, + -65006, + -64993, + -64980, + -64967, + -64954, + -64940, + -64927, + -64913, + -64899, + -64885, + -64871, + -64856, + -64842, + -64827, + -64812, + -64797, + -64782, + -64767, + -64752, + -64736, + -64720, + -64704, + -64688, + -64672, + -64656, + -64639, + -64623, + -64606, + -64589, + -64572, + -64554, + -64537, + -64519, + -64502, + -64484, + -64466, + -64448, + -64429, + -64411, + -64392, + -64373, + -64354, + -64335, + -64316, + -64297, + -64277, + -64258, + -64238, + -64218, + -64198, + -64177, + -64157, + -64136, + -64116, + -64095, + -64074, + -64052, + -64031, + -64010, + -63988, + -63966, + -63944, + -63922, + -63900, + -63877, + -63855, + -63832, + -63809, + -63786, + -63763, + -63740, + -63716, + -63693, + -63669, + -63645, + -63621, + -63597, + -63572, + -63548, + -63523, + -63499, + -63474, + -63448, + -63423, + -63398, + -63372, + -63347, + -63321, + -63295, + -63269, + -63242, + -63216, + -63189, + -63163, + -63136, + -63109, + -63081, + -63054, + -63027, + -62999, + -62971, + -62943, + -62915, + -62887, + -62859, + -62830, + -62801, + -62773, + -62744, + -62715, + -62685, + -62656, + -62626, + -62597, + -62567, + -62537, + -62507, + -62476, + -62446, + -62415, + -62385, + -62354, + -62323, + -62292, + -62260, + -62229, + -62197, + -62165, + -62134, + -62101, + -62069, + -62037, + -62004, + -61972, + -61939, + -61906, + -61873, + -61840, + -61806, + -61773, + -61739, + -61706, + -61672, + -61638, + -61603, + -61569, + -61534, + -61500, + -61465, + -61430, + -61395, + -61360, + -61324, + -61289, + -61253, + -61217, + -61181, + -61145, + -61109, + -61072, + -61036, + -60999, + -60962, + -60925, + -60888, + -60851, + -60814, + -60776, + -60738, + -60701, + -60663, + -60625, + -60586, + -60548, + -60509, + -60471, + -60432, + -60393, + -60354, + -60314, + -60275, + -60236, + -60196, + -60156, + -60116, + -60076, + -60036, + -59995, + -59955, + -59914, + -59873, + -59832, + -59791, + -59750, + -59709, + -59667, + -59626, + -59584, + -59542, + -59500, + -59458, + -59415, + -59373, + -59330, + -59287, + -59244, + -59201, + -59158, + -59115, + -59071, + -59028, + -58984, + -58940, + -58896, + -58852, + -58808, + -58763, + -58719, + -58674, + -58629, + -58584, + -58539, + -58494, + -58448, + -58403, + -58357, + -58311, + -58265, + -58219, + -58173, + -58126, + -58080, + -58033, + -57987, + -57940, + -57893, + -57845, + -57798, + -57751, + -57703, + -57655, + -57607, + -57559, + -57511, + -57463, + -57415, + -57366, + -57317, + -57269, + -57220, + -57171, + -57121, + -57072, + -57023, + -56973, + -56923, + -56873, + -56823, + -56773, + -56723, + -56672, + -56622, + -56571, + -56520, + -56469, + -56418, + -56367, + -56316, + -56264, + -56213, + -56161, + -56109, + -56057, + -56005, + -55953, + -55900, + -55848, + -55795, + -55742, + -55689, + -55636, + -55583, + -55530, + -55476, + -55423, + -55369, + -55315, + -55261, + -55207, + -55153, + -55098, + -55044, + -54989, + -54934, + -54880, + -54824, + -54769, + -54714, + -54659, + -54603, + -54547, + -54492, + -54436, + -54380, + -54324, + -54267, + -54211, + -54154, + -54098, + -54041, + -53984, + -53927, + -53870, + -53812, + -53755, + -53697, + -53640, + -53582, + -53524, + -53466, + -53408, + -53349, + -53291, + -53232, + -53173, + -53115, + -53056, + -52997, + -52937, + -52878, + -52819, + -52759, + -52699, + -52640, + -52580, + -52519, + -52459, + -52399, + -52339, + -52278, + -52217, + -52156, + -52096, + -52034, + -51973, + -51912, + -51851, + -51789, + -51727, + -51666, + -51604, + -51542, + -51479, + -51417, + -51355, + -51292, + -51230, + -51167, + -51104, + -51041, + -50978, + -50915, + -50851, + -50788, + -50724, + -50661, + -50597, + -50533, + -50469, + -50404, + -50340, + -50276, + -50211, + -50147, + -50082, + -50017, + -49952, + -49887, + -49821, + -49756, + -49691, + -49625, + -49559, + -49493, + -49427, + -49361, + -49295, + -49229, + -49162, + -49096, + -49029, + -48962, + -48896, + -48829, + -48761, + -48694, + -48627, + -48559, + -48492, + -48424, + -48356, + -48289, + -48220, + -48152, + -48084, + -48016, + -47947, + -47879, + -47810, + -47741, + -47672, + -47603, + -47534, + -47465, + -47395, + -47326, + -47256, + -47187, + -47117, + -47047, + -46977, + -46907, + -46836, + -46766, + -46696, + -46625, + -46554, + -46483, + -46412, + -46341, + -46270, + -46199, + -46128, + -46056, + -45985, + -45913, + -45841, + -45769, + -45697, + -45625, + -45553, + -45481, + -45408, + -45336, + -45263, + -45190, + -45117, + -45044, + -44971, + -44898, + -44825, + -44751, + -44678, + -44604, + -44531, + -44457, + -44383, + -44309, + -44235, + -44161, + -44086, + -44012, + -43937, + -43863, + -43788, + -43713, + -43638, + -43563, + -43488, + -43413, + -43337, + -43262, + -43186, + -43111, + -43035, + -42959, + -42883, + -42807, + -42731, + -42654, + -42578, + -42502, + -42425, + -42348, + -42272, + -42195, + -42118, + -42041, + -41963, + -41886, + -41809, + -41731, + -41654, + -41576, + -41498, + -41420, + -41343, + -41264, + -41186, + -41108, + -41030, + -40951, + -40873, + -40794, + -40715, + -40637, + -40558, + -40479, + -40400, + -40320, + -40241, + -40162, + -40082, + -40003, + -39923, + -39843, + -39763, + -39683, + -39603, + -39523, + -39443, + -39363, + -39282, + -39202, + -39121, + -39040, + -38959, + -38879, + -38798, + -38717, + -38635, + -38554, + -38473, + -38391, + -38310, + -38228, + -38147, + -38065, + -37983, + -37901, + -37819, + -37737, + -37654, + -37572, + -37490, + -37407, + -37325, + -37242, + -37159, + -37076, + -36993, + -36910, + -36827, + -36744, + -36661, + -36577, + -36494, + -36410, + -36327, + -36243, + -36159, + -36075, + -35991, + -35907, + -35823, + -35739, + -35655, + -35570, + -35486, + -35401, + -35317, + -35232, + -35147, + -35062, + -34977, + -34892, + -34807, + -34722, + -34636, + -34551, + -34466, + -34380, + -34294, + -34209, + -34123, + -34037, + -33951, + -33865, + -33779, + -33693, + -33606, + -33520, + -33434, + -33347, + -33261, + -33174, + -33087, + -33000, + -32914, + -32827, + -32739, + -32652, + -32565, + -32478, + -32391, + -32303, + -32216, + -32128, + -32040, + -31953, + -31865, + -31777, + -31689, + -31601, + -31513, + -31425, + -31336, + -31248, + -31160, + -31071, + -30983, + -30894, + -30805, + -30716, + -30628, + -30539, + -30450, + -30361, + -30272, + -30182, + -30093, + -30004, + -29914, + -29825, + -29735, + -29646, + -29556, + -29466, + -29376, + -29287, + -29197, + -29106, + -29016, + -28926, + -28836, + -28746, + -28655, + -28565, + -28474, + -28384, + -28293, + -28202, + -28112, + -28021, + -27930, + -27839, + -27748, + -27657, + -27566, + -27474, + -27383, + -27292, + -27200, + -27109, + -27017, + -26926, + -26834, + -26742, + -26650, + -26558, + -26466, + -26374, + -26282, + -26190, + -26098, + -26006, + -25914, + -25821, + -25729, + -25636, + -25544, + -25451, + -25358, + -25266, + -25173, + -25080, + -24987, + -24894, + -24801, + -24708, + -24615, + -24522, + -24428, + -24335, + -24242, + -24148, + -24055, + -23961, + -23868, + -23774, + -23680, + -23587, + -23493, + -23399, + -23305, + -23211, + -23117, + -23023, + -22929, + -22834, + -22740, + -22646, + -22552, + -22457, + -22363, + -22268, + -22174, + -22079, + -21984, + -21890, + -21795, + -21700, + -21605, + -21510, + -21415, + -21320, + -21225, + -21130, + -21035, + -20939, + -20844, + -20749, + -20653, + -20558, + -20462, + -20367, + -20271, + -20176, + -20080, + -19984, + -19889, + -19793, + -19697, + -19601, + -19505, + -19409, + -19313, + -19217, + -19121, + -19025, + -18928, + -18832, + -18736, + -18639, + -18543, + -18447, + -18350, + -18254, + -18157, + -18060, + -17964, + -17867, + -17770, + -17673, + -17577, + -17480, + -17383, + -17286, + -17189, + -17092, + -16995, + -16898, + -16801, + -16703, + -16606, + -16509, + -16412, + -16314, + -16217, + -16119, + -16022, + -15924, + -15827, + -15729, + -15632, + -15534, + -15436, + -15339, + -15241, + -15143, + -15045, + -14947, + -14850, + -14752, + -14654, + -14556, + -14458, + -14360, + -14261, + -14163, + -14065, + -13967, + -13869, + -13770, + -13672, + -13574, + -13475, + -13377, + -13279, + -13180, + -13082, + -12983, + -12885, + -12786, + -12687, + -12589, + -12490, + -12391, + -12293, + -12194, + -12095, + -11996, + -11897, + -11798, + -11700, + -11601, + -11502, + -11403, + -11304, + -11205, + -11106, + -11007, + -10907, + -10808, + -10709, + -10610, + -10511, + -10411, + -10312, + -10213, + -10114, + -10014, + -9915, + -9815, + -9716, + -9617, + -9517, + -9418, + -9318, + -9219, + -9119, + -9020, + -8920, + -8820, + -8721, + -8621, + -8521, + -8422, + -8322, + -8222, + -8123, + -8023, + -7923, + -7823, + -7723, + -7624, + -7524, + -7424, + -7324, + -7224, + -7124, + -7024, + -6924, + -6824, + -6724, + -6624, + -6524, + -6424, + -6324, + -6224, + -6124, + -6024, + -5924, + -5824, + -5723, + -5623, + -5523, + -5423, + -5323, + -5223, + -5122, + -5022, + -4922, + -4822, + -4721, + -4621, + -4521, + -4421, + -4320, + -4220, + -4120, + -4019, + -3919, + -3819, + -3718, + -3618, + -3517, + -3417, + -3317, + -3216, + -3116, + -3015, + -2915, + -2815, + -2714, + -2614, + -2513, + -2413, + -2312, + -2212, + -2111, + -2011, + -1910, + -1810, + -1709, + -1609, + -1508, + -1408, + -1307, + -1207, + -1106, + -1006, + -905, + -805, + -704, + -604, + -503, + -403, + -302, + -202, + -101 + +}; + +int cosine[]={ + + 65536, + 65535, + 65535, + 65535, + 65534, + 65534, + 65533, + 65532, + 65531, + 65529, + 65528, + 65526, + 65524, + 65522, + 65520, + 65518, + 65516, + 65513, + 65511, + 65508, + 65505, + 65501, + 65498, + 65495, + 65491, + 65487, + 65483, + 65479, + 65475, + 65471, + 65466, + 65461, + 65457, + 65452, + 65446, + 65441, + 65436, + 65430, + 65424, + 65418, + 65412, + 65406, + 65400, + 65393, + 65386, + 65379, + 65372, + 65365, + 65358, + 65350, + 65343, + 65335, + 65327, + 65319, + 65311, + 65302, + 65294, + 65285, + 65276, + 65267, + 65258, + 65249, + 65239, + 65230, + 65220, + 65210, + 65200, + 65190, + 65179, + 65169, + 65158, + 65147, + 65136, + 65125, + 65114, + 65102, + 65091, + 65079, + 65067, + 65055, + 65043, + 65030, + 65018, + 65005, + 64992, + 64979, + 64966, + 64953, + 64939, + 64926, + 64912, + 64898, + 64884, + 64870, + 64855, + 64841, + 64826, + 64811, + 64796, + 64781, + 64766, + 64751, + 64735, + 64719, + 64703, + 64687, + 64671, + 64655, + 64638, + 64622, + 64605, + 64588, + 64571, + 64553, + 64536, + 64518, + 64501, + 64483, + 64465, + 64447, + 64428, + 64410, + 64391, + 64372, + 64353, + 64334, + 64315, + 64296, + 64276, + 64257, + 64237, + 64217, + 64197, + 64176, + 64156, + 64135, + 64115, + 64094, + 64073, + 64051, + 64030, + 64009, + 63987, + 63965, + 63943, + 63921, + 63899, + 63876, + 63854, + 63831, + 63808, + 63785, + 63762, + 63739, + 63715, + 63692, + 63668, + 63644, + 63620, + 63596, + 63571, + 63547, + 63522, + 63498, + 63473, + 63447, + 63422, + 63397, + 63371, + 63346, + 63320, + 63294, + 63268, + 63241, + 63215, + 63188, + 63162, + 63135, + 63108, + 63080, + 63053, + 63026, + 62998, + 62970, + 62942, + 62914, + 62886, + 62858, + 62829, + 62800, + 62772, + 62743, + 62714, + 62684, + 62655, + 62625, + 62596, + 62566, + 62536, + 62506, + 62475, + 62445, + 62414, + 62384, + 62353, + 62322, + 62291, + 62259, + 62228, + 62196, + 62164, + 62133, + 62100, + 62068, + 62036, + 62003, + 61971, + 61938, + 61905, + 61872, + 61839, + 61805, + 61772, + 61738, + 61705, + 61671, + 61637, + 61602, + 61568, + 61533, + 61499, + 61464, + 61429, + 61394, + 61359, + 61323, + 61288, + 61252, + 61216, + 61180, + 61144, + 61108, + 61071, + 61035, + 60998, + 60961, + 60924, + 60887, + 60850, + 60813, + 60775, + 60737, + 60700, + 60662, + 60624, + 60585, + 60547, + 60508, + 60470, + 60431, + 60392, + 60353, + 60313, + 60274, + 60235, + 60195, + 60155, + 60115, + 60075, + 60035, + 59994, + 59954, + 59913, + 59872, + 59831, + 59790, + 59749, + 59708, + 59666, + 59625, + 59583, + 59541, + 59499, + 59457, + 59414, + 59372, + 59329, + 59286, + 59243, + 59200, + 59157, + 59114, + 59070, + 59027, + 58983, + 58939, + 58895, + 58851, + 58807, + 58762, + 58718, + 58673, + 58628, + 58583, + 58538, + 58493, + 58447, + 58402, + 58356, + 58310, + 58264, + 58218, + 58172, + 58125, + 58079, + 58032, + 57986, + 57939, + 57892, + 57844, + 57797, + 57750, + 57702, + 57654, + 57606, + 57558, + 57510, + 57462, + 57414, + 57365, + 57316, + 57268, + 57219, + 57170, + 57120, + 57071, + 57022, + 56972, + 56922, + 56872, + 56822, + 56772, + 56722, + 56671, + 56621, + 56570, + 56519, + 56468, + 56417, + 56366, + 56315, + 56263, + 56212, + 56160, + 56108, + 56056, + 56004, + 55952, + 55899, + 55847, + 55794, + 55741, + 55688, + 55635, + 55582, + 55529, + 55475, + 55422, + 55368, + 55314, + 55260, + 55206, + 55152, + 55097, + 55043, + 54988, + 54933, + 54879, + 54823, + 54768, + 54713, + 54658, + 54602, + 54546, + 54491, + 54435, + 54379, + 54323, + 54266, + 54210, + 54153, + 54097, + 54040, + 53983, + 53926, + 53869, + 53811, + 53754, + 53696, + 53639, + 53581, + 53523, + 53465, + 53407, + 53348, + 53290, + 53231, + 53172, + 53114, + 53055, + 52996, + 52936, + 52877, + 52818, + 52758, + 52698, + 52639, + 52579, + 52518, + 52458, + 52398, + 52338, + 52277, + 52216, + 52155, + 52095, + 52033, + 51972, + 51911, + 51850, + 51788, + 51726, + 51665, + 51603, + 51541, + 51478, + 51416, + 51354, + 51291, + 51229, + 51166, + 51103, + 51040, + 50977, + 50914, + 50850, + 50787, + 50723, + 50660, + 50596, + 50532, + 50468, + 50403, + 50339, + 50275, + 50210, + 50146, + 50081, + 50016, + 49951, + 49886, + 49820, + 49755, + 49690, + 49624, + 49558, + 49492, + 49426, + 49360, + 49294, + 49228, + 49161, + 49095, + 49028, + 48961, + 48895, + 48828, + 48760, + 48693, + 48626, + 48558, + 48491, + 48423, + 48355, + 48288, + 48219, + 48151, + 48083, + 48015, + 47946, + 47878, + 47809, + 47740, + 47671, + 47602, + 47533, + 47464, + 47394, + 47325, + 47255, + 47186, + 47116, + 47046, + 46976, + 46906, + 46835, + 46765, + 46695, + 46624, + 46553, + 46482, + 46411, + 46340, + 46269, + 46198, + 46127, + 46055, + 45984, + 45912, + 45840, + 45768, + 45696, + 45624, + 45552, + 45480, + 45407, + 45335, + 45262, + 45189, + 45116, + 45043, + 44970, + 44897, + 44824, + 44750, + 44677, + 44603, + 44530, + 44456, + 44382, + 44308, + 44234, + 44160, + 44085, + 44011, + 43936, + 43862, + 43787, + 43712, + 43637, + 43562, + 43487, + 43412, + 43336, + 43261, + 43185, + 43110, + 43034, + 42958, + 42882, + 42806, + 42730, + 42653, + 42577, + 42501, + 42424, + 42347, + 42271, + 42194, + 42117, + 42040, + 41962, + 41885, + 41808, + 41730, + 41653, + 41575, + 41497, + 41419, + 41342, + 41263, + 41185, + 41107, + 41029, + 40950, + 40872, + 40793, + 40714, + 40636, + 40557, + 40478, + 40399, + 40319, + 40240, + 40161, + 40081, + 40002, + 39922, + 39842, + 39762, + 39682, + 39602, + 39522, + 39442, + 39362, + 39281, + 39201, + 39120, + 39039, + 38958, + 38878, + 38797, + 38716, + 38634, + 38553, + 38472, + 38390, + 38309, + 38227, + 38146, + 38064, + 37982, + 37900, + 37818, + 37736, + 37653, + 37571, + 37489, + 37406, + 37324, + 37241, + 37158, + 37075, + 36992, + 36909, + 36826, + 36743, + 36660, + 36576, + 36493, + 36409, + 36326, + 36242, + 36158, + 36074, + 35990, + 35906, + 35822, + 35738, + 35654, + 35569, + 35485, + 35400, + 35316, + 35231, + 35146, + 35061, + 34976, + 34891, + 34806, + 34721, + 34635, + 34550, + 34465, + 34379, + 34293, + 34208, + 34122, + 34036, + 33950, + 33864, + 33778, + 33692, + 33605, + 33519, + 33433, + 33346, + 33260, + 33173, + 33086, + 32999, + 32912, + 32826, + 32738, + 32651, + 32564, + 32477, + 32390, + 32302, + 32215, + 32127, + 32039, + 31952, + 31864, + 31776, + 31688, + 31600, + 31512, + 31424, + 31335, + 31247, + 31159, + 31070, + 30982, + 30893, + 30804, + 30715, + 30627, + 30538, + 30449, + 30360, + 30271, + 30181, + 30092, + 30003, + 29913, + 29824, + 29734, + 29645, + 29555, + 29465, + 29375, + 29285, + 29196, + 29105, + 29015, + 28925, + 28835, + 28745, + 28654, + 28564, + 28473, + 28383, + 28292, + 28201, + 28111, + 28020, + 27929, + 27838, + 27747, + 27656, + 27565, + 27473, + 27382, + 27291, + 27199, + 27108, + 27016, + 26925, + 26833, + 26741, + 26649, + 26557, + 26465, + 26373, + 26281, + 26189, + 26097, + 26005, + 25913, + 25820, + 25728, + 25635, + 25543, + 25450, + 25357, + 25265, + 25172, + 25079, + 24986, + 24893, + 24800, + 24707, + 24614, + 24521, + 24427, + 24334, + 24241, + 24147, + 24054, + 23960, + 23867, + 23773, + 23679, + 23586, + 23492, + 23398, + 23304, + 23210, + 23116, + 23022, + 22928, + 22833, + 22739, + 22645, + 22551, + 22456, + 22362, + 22267, + 22173, + 22078, + 21983, + 21889, + 21794, + 21699, + 21604, + 21509, + 21414, + 21319, + 21224, + 21129, + 21034, + 20938, + 20843, + 20748, + 20652, + 20557, + 20461, + 20366, + 20270, + 20175, + 20079, + 19983, + 19888, + 19792, + 19696, + 19600, + 19504, + 19408, + 19312, + 19216, + 19120, + 19024, + 18927, + 18831, + 18735, + 18638, + 18542, + 18446, + 18349, + 18253, + 18156, + 18059, + 17963, + 17866, + 17769, + 17672, + 17576, + 17479, + 17382, + 17285, + 17188, + 17091, + 16994, + 16897, + 16800, + 16702, + 16605, + 16508, + 16411, + 16313, + 16216, + 16118, + 16021, + 15923, + 15826, + 15728, + 15631, + 15533, + 15435, + 15338, + 15240, + 15142, + 15044, + 14946, + 14849, + 14751, + 14653, + 14555, + 14457, + 14359, + 14260, + 14162, + 14064, + 13966, + 13868, + 13769, + 13671, + 13573, + 13474, + 13376, + 13278, + 13179, + 13081, + 12982, + 12884, + 12785, + 12686, + 12588, + 12489, + 12390, + 12292, + 12193, + 12094, + 11995, + 11896, + 11797, + 11699, + 11600, + 11501, + 11402, + 11303, + 11204, + 11105, + 11006, + 10906, + 10807, + 10708, + 10609, + 10510, + 10410, + 10311, + 10212, + 10113, + 10013, + 9914, + 9814, + 9715, + 9616, + 9516, + 9417, + 9317, + 9218, + 9118, + 9019, + 8919, + 8819, + 8720, + 8620, + 8520, + 8421, + 8321, + 8221, + 8122, + 8022, + 7922, + 7822, + 7722, + 7623, + 7523, + 7423, + 7323, + 7223, + 7123, + 7023, + 6923, + 6823, + 6723, + 6623, + 6523, + 6423, + 6323, + 6223, + 6123, + 6023, + 5923, + 5823, + 5722, + 5622, + 5522, + 5422, + 5322, + 5222, + 5121, + 5021, + 4921, + 4821, + 4720, + 4620, + 4520, + 4420, + 4319, + 4219, + 4119, + 4018, + 3918, + 3818, + 3717, + 3617, + 3516, + 3416, + 3316, + 3215, + 3115, + 3014, + 2914, + 2814, + 2713, + 2613, + 2512, + 2412, + 2311, + 2211, + 2110, + 2010, + 1909, + 1809, + 1708, + 1608, + 1507, + 1407, + 1306, + 1206, + 1105, + 1005, + 904, + 804, + 703, + 603, + 502, + 402, + 301, + 201, + 100, + 0, + -101, + -202, + -302, + -403, + -503, + -604, + -704, + -805, + -905, + -1006, + -1106, + -1207, + -1307, + -1408, + -1508, + -1609, + -1709, + -1810, + -1910, + -2011, + -2111, + -2212, + -2312, + -2413, + -2513, + -2614, + -2714, + -2814, + -2915, + -3015, + -3116, + -3216, + -3317, + -3417, + -3517, + -3618, + -3718, + -3819, + -3919, + -4019, + -4120, + -4220, + -4320, + -4421, + -4521, + -4621, + -4721, + -4822, + -4922, + -5022, + -5122, + -5223, + -5323, + -5423, + -5523, + -5623, + -5723, + -5824, + -5924, + -6024, + -6124, + -6224, + -6324, + -6424, + -6524, + -6624, + -6724, + -6824, + -6924, + -7024, + -7124, + -7224, + -7324, + -7424, + -7524, + -7624, + -7723, + -7823, + -7923, + -8023, + -8123, + -8222, + -8322, + -8422, + -8521, + -8621, + -8721, + -8820, + -8920, + -9020, + -9119, + -9219, + -9318, + -9418, + -9517, + -9617, + -9716, + -9815, + -9915, + -10014, + -10114, + -10213, + -10312, + -10411, + -10511, + -10610, + -10709, + -10808, + -10907, + -11007, + -11106, + -11205, + -11304, + -11403, + -11502, + -11601, + -11700, + -11798, + -11897, + -11996, + -12095, + -12194, + -12293, + -12391, + -12490, + -12589, + -12687, + -12786, + -12885, + -12983, + -13082, + -13180, + -13279, + -13377, + -13475, + -13574, + -13672, + -13770, + -13869, + -13967, + -14065, + -14163, + -14261, + -14360, + -14458, + -14556, + -14654, + -14752, + -14850, + -14947, + -15045, + -15143, + -15241, + -15339, + -15436, + -15534, + -15632, + -15729, + -15827, + -15924, + -16022, + -16119, + -16217, + -16314, + -16412, + -16509, + -16606, + -16703, + -16801, + -16898, + -16995, + -17092, + -17189, + -17286, + -17383, + -17480, + -17577, + -17673, + -17770, + -17867, + -17964, + -18060, + -18157, + -18254, + -18350, + -18447, + -18543, + -18639, + -18736, + -18832, + -18928, + -19025, + -19121, + -19217, + -19313, + -19409, + -19505, + -19601, + -19697, + -19793, + -19889, + -19984, + -20080, + -20176, + -20271, + -20367, + -20462, + -20558, + -20653, + -20749, + -20844, + -20939, + -21035, + -21130, + -21225, + -21320, + -21415, + -21510, + -21605, + -21700, + -21795, + -21889, + -21984, + -22079, + -22174, + -22268, + -22363, + -22457, + -22552, + -22646, + -22740, + -22834, + -22929, + -23023, + -23117, + -23211, + -23305, + -23399, + -23493, + -23587, + -23680, + -23774, + -23868, + -23961, + -24055, + -24148, + -24242, + -24335, + -24428, + -24522, + -24615, + -24708, + -24801, + -24894, + -24987, + -25080, + -25173, + -25266, + -25358, + -25451, + -25544, + -25636, + -25729, + -25821, + -25914, + -26006, + -26098, + -26190, + -26282, + -26374, + -26466, + -26558, + -26650, + -26742, + -26834, + -26926, + -27017, + -27109, + -27200, + -27292, + -27383, + -27474, + -27566, + -27657, + -27748, + -27839, + -27930, + -28021, + -28112, + -28202, + -28293, + -28384, + -28474, + -28565, + -28655, + -28746, + -28836, + -28926, + -29016, + -29106, + -29197, + -29286, + -29376, + -29466, + -29556, + -29646, + -29735, + -29825, + -29914, + -30004, + -30093, + -30182, + -30272, + -30361, + -30450, + -30539, + -30628, + -30716, + -30805, + -30894, + -30983, + -31071, + -31160, + -31248, + -31336, + -31425, + -31513, + -31601, + -31689, + -31777, + -31865, + -31953, + -32040, + -32128, + -32216, + -32303, + -32391, + -32478, + -32565, + -32652, + -32739, + -32827, + -32913, + -33000, + -33087, + -33174, + -33261, + -33347, + -33434, + -33520, + -33606, + -33693, + -33779, + -33865, + -33951, + -34037, + -34123, + -34209, + -34294, + -34380, + -34466, + -34551, + -34636, + -34722, + -34807, + -34892, + -34977, + -35062, + -35147, + -35232, + -35317, + -35401, + -35486, + -35570, + -35655, + -35739, + -35823, + -35907, + -35991, + -36075, + -36159, + -36243, + -36327, + -36410, + -36494, + -36577, + -36661, + -36744, + -36827, + -36910, + -36993, + -37076, + -37159, + -37242, + -37325, + -37407, + -37490, + -37572, + -37654, + -37737, + -37819, + -37901, + -37983, + -38065, + -38147, + -38228, + -38310, + -38391, + -38473, + -38554, + -38635, + -38717, + -38798, + -38879, + -38959, + -39040, + -39121, + -39202, + -39282, + -39362, + -39443, + -39523, + -39603, + -39683, + -39763, + -39843, + -39923, + -40003, + -40082, + -40162, + -40241, + -40320, + -40400, + -40479, + -40558, + -40637, + -40715, + -40794, + -40873, + -40951, + -41030, + -41108, + -41186, + -41264, + -41343, + -41420, + -41498, + -41576, + -41654, + -41731, + -41809, + -41886, + -41963, + -42041, + -42118, + -42195, + -42272, + -42348, + -42425, + -42502, + -42578, + -42654, + -42731, + -42807, + -42883, + -42959, + -43035, + -43111, + -43186, + -43262, + -43337, + -43413, + -43488, + -43563, + -43638, + -43713, + -43788, + -43863, + -43937, + -44012, + -44086, + -44161, + -44235, + -44309, + -44383, + -44457, + -44531, + -44604, + -44678, + -44751, + -44825, + -44898, + -44971, + -45044, + -45117, + -45190, + -45263, + -45336, + -45408, + -45481, + -45553, + -45625, + -45697, + -45769, + -45841, + -45913, + -45985, + -46056, + -46128, + -46199, + -46270, + -46341, + -46412, + -46483, + -46554, + -46625, + -46696, + -46766, + -46836, + -46907, + -46977, + -47047, + -47117, + -47187, + -47256, + -47326, + -47395, + -47465, + -47534, + -47603, + -47672, + -47741, + -47810, + -47879, + -47947, + -48016, + -48084, + -48152, + -48220, + -48289, + -48356, + -48424, + -48492, + -48559, + -48627, + -48694, + -48761, + -48829, + -48896, + -48962, + -49029, + -49096, + -49162, + -49229, + -49295, + -49361, + -49427, + -49493, + -49559, + -49625, + -49691, + -49756, + -49821, + -49887, + -49952, + -50017, + -50082, + -50147, + -50211, + -50276, + -50340, + -50404, + -50469, + -50533, + -50597, + -50661, + -50724, + -50788, + -50851, + -50915, + -50978, + -51041, + -51104, + -51167, + -51230, + -51292, + -51355, + -51417, + -51479, + -51542, + -51604, + -51666, + -51727, + -51789, + -51851, + -51912, + -51973, + -52034, + -52096, + -52156, + -52217, + -52278, + -52339, + -52399, + -52459, + -52519, + -52580, + -52640, + -52699, + -52759, + -52819, + -52878, + -52937, + -52997, + -53056, + -53115, + -53173, + -53232, + -53291, + -53349, + -53408, + -53466, + -53524, + -53582, + -53640, + -53697, + -53755, + -53812, + -53870, + -53927, + -53984, + -54041, + -54098, + -54154, + -54211, + -54267, + -54324, + -54380, + -54436, + -54492, + -54547, + -54603, + -54659, + -54714, + -54769, + -54824, + -54880, + -54934, + -54989, + -55044, + -55098, + -55153, + -55207, + -55261, + -55315, + -55369, + -55423, + -55476, + -55530, + -55583, + -55636, + -55689, + -55742, + -55795, + -55848, + -55900, + -55953, + -56005, + -56057, + -56109, + -56161, + -56213, + -56264, + -56316, + -56367, + -56418, + -56469, + -56520, + -56571, + -56622, + -56672, + -56723, + -56773, + -56823, + -56873, + -56923, + -56973, + -57023, + -57072, + -57121, + -57171, + -57220, + -57269, + -57317, + -57366, + -57415, + -57463, + -57511, + -57559, + -57607, + -57655, + -57703, + -57751, + -57798, + -57845, + -57893, + -57940, + -57987, + -58033, + -58080, + -58126, + -58173, + -58219, + -58265, + -58311, + -58357, + -58403, + -58448, + -58494, + -58539, + -58584, + -58629, + -58674, + -58719, + -58763, + -58808, + -58852, + -58896, + -58940, + -58984, + -59028, + -59071, + -59115, + -59158, + -59201, + -59244, + -59287, + -59330, + -59373, + -59415, + -59458, + -59500, + -59542, + -59584, + -59626, + -59667, + -59709, + -59750, + -59791, + -59832, + -59873, + -59914, + -59955, + -59995, + -60036, + -60076, + -60116, + -60156, + -60196, + -60236, + -60275, + -60314, + -60354, + -60393, + -60432, + -60471, + -60509, + -60548, + -60586, + -60625, + -60663, + -60701, + -60738, + -60776, + -60814, + -60851, + -60888, + -60925, + -60962, + -60999, + -61036, + -61072, + -61109, + -61145, + -61181, + -61217, + -61253, + -61289, + -61324, + -61360, + -61395, + -61430, + -61465, + -61500, + -61534, + -61569, + -61603, + -61638, + -61672, + -61706, + -61739, + -61773, + -61806, + -61840, + -61873, + -61906, + -61939, + -61972, + -62004, + -62037, + -62069, + -62101, + -62134, + -62165, + -62197, + -62229, + -62260, + -62292, + -62323, + -62354, + -62385, + -62415, + -62446, + -62476, + -62507, + -62537, + -62567, + -62597, + -62626, + -62656, + -62685, + -62715, + -62744, + -62773, + -62801, + -62830, + -62859, + -62887, + -62915, + -62943, + -62971, + -62999, + -63027, + -63054, + -63081, + -63109, + -63136, + -63163, + -63189, + -63216, + -63242, + -63269, + -63295, + -63321, + -63347, + -63372, + -63398, + -63423, + -63448, + -63474, + -63499, + -63523, + -63548, + -63572, + -63597, + -63621, + -63645, + -63669, + -63693, + -63716, + -63740, + -63763, + -63786, + -63809, + -63832, + -63855, + -63877, + -63900, + -63922, + -63944, + -63966, + -63988, + -64010, + -64031, + -64052, + -64074, + -64095, + -64116, + -64136, + -64157, + -64177, + -64198, + -64218, + -64238, + -64258, + -64277, + -64297, + -64316, + -64335, + -64354, + -64373, + -64392, + -64411, + -64429, + -64448, + -64466, + -64484, + -64502, + -64519, + -64537, + -64554, + -64572, + -64589, + -64606, + -64623, + -64639, + -64656, + -64672, + -64688, + -64704, + -64720, + -64736, + -64752, + -64767, + -64782, + -64797, + -64812, + -64827, + -64842, + -64856, + -64871, + -64885, + -64899, + -64913, + -64927, + -64940, + -64954, + -64967, + -64980, + -64993, + -65006, + -65019, + -65031, + -65044, + -65056, + -65068, + -65080, + -65092, + -65103, + -65115, + -65126, + -65137, + -65148, + -65159, + -65170, + -65180, + -65191, + -65201, + -65211, + -65221, + -65231, + -65240, + -65250, + -65259, + -65268, + -65277, + -65286, + -65295, + -65303, + -65312, + -65320, + -65328, + -65336, + -65344, + -65351, + -65359, + -65366, + -65373, + -65380, + -65387, + -65394, + -65401, + -65407, + -65413, + -65419, + -65425, + -65431, + -65437, + -65442, + -65447, + -65453, + -65458, + -65462, + -65467, + -65472, + -65476, + -65480, + -65484, + -65488, + -65492, + -65496, + -65499, + -65502, + -65506, + -65509, + -65512, + -65514, + -65517, + -65519, + -65521, + -65523, + -65525, + -65527, + -65529, + -65530, + -65532, + -65533, + -65534, + -65535, + -65535, + -65536, + -65536, + -65536, + -65536, + -65536, + -65536, + -65536, + -65535, + -65535, + -65534, + -65533, + -65532, + -65530, + -65529, + -65527, + -65525, + -65523, + -65521, + -65519, + -65517, + -65514, + -65512, + -65509, + -65506, + -65502, + -65499, + -65496, + -65492, + -65488, + -65484, + -65480, + -65476, + -65472, + -65467, + -65462, + -65458, + -65453, + -65447, + -65442, + -65437, + -65431, + -65425, + -65419, + -65413, + -65407, + -65401, + -65394, + -65387, + -65380, + -65373, + -65366, + -65359, + -65351, + -65344, + -65336, + -65328, + -65320, + -65312, + -65303, + -65295, + -65286, + -65277, + -65268, + -65259, + -65250, + -65240, + -65231, + -65221, + -65211, + -65201, + -65191, + -65180, + -65170, + -65159, + -65148, + -65137, + -65126, + -65115, + -65103, + -65092, + -65080, + -65068, + -65056, + -65044, + -65031, + -65019, + -65006, + -64993, + -64980, + -64967, + -64954, + -64940, + -64927, + -64913, + -64899, + -64885, + -64871, + -64856, + -64842, + -64827, + -64812, + -64797, + -64782, + -64767, + -64752, + -64736, + -64720, + -64704, + -64688, + -64672, + -64656, + -64639, + -64623, + -64606, + -64589, + -64572, + -64554, + -64537, + -64519, + -64502, + -64484, + -64466, + -64448, + -64429, + -64411, + -64392, + -64373, + -64354, + -64335, + -64316, + -64297, + -64277, + -64258, + -64238, + -64218, + -64198, + -64177, + -64157, + -64136, + -64116, + -64095, + -64074, + -64052, + -64031, + -64010, + -63988, + -63966, + -63944, + -63922, + -63900, + -63877, + -63855, + -63832, + -63809, + -63786, + -63763, + -63740, + -63716, + -63693, + -63669, + -63645, + -63621, + -63597, + -63572, + -63548, + -63523, + -63499, + -63474, + -63448, + -63423, + -63398, + -63372, + -63347, + -63321, + -63295, + -63269, + -63242, + -63216, + -63189, + -63163, + -63136, + -63109, + -63081, + -63054, + -63027, + -62999, + -62971, + -62943, + -62915, + -62887, + -62859, + -62830, + -62801, + -62773, + -62744, + -62715, + -62685, + -62656, + -62626, + -62597, + -62567, + -62537, + -62507, + -62476, + -62446, + -62415, + -62385, + -62354, + -62323, + -62292, + -62260, + -62229, + -62197, + -62165, + -62134, + -62101, + -62069, + -62037, + -62004, + -61972, + -61939, + -61906, + -61873, + -61840, + -61806, + -61773, + -61739, + -61706, + -61672, + -61638, + -61603, + -61569, + -61534, + -61500, + -61465, + -61430, + -61395, + -61360, + -61324, + -61289, + -61253, + -61217, + -61181, + -61145, + -61109, + -61072, + -61036, + -60999, + -60962, + -60925, + -60888, + -60851, + -60814, + -60776, + -60738, + -60701, + -60663, + -60625, + -60586, + -60548, + -60509, + -60471, + -60432, + -60393, + -60354, + -60314, + -60275, + -60236, + -60196, + -60156, + -60116, + -60076, + -60036, + -59995, + -59955, + -59914, + -59873, + -59832, + -59791, + -59750, + -59709, + -59667, + -59626, + -59584, + -59542, + -59500, + -59458, + -59415, + -59373, + -59330, + -59287, + -59244, + -59201, + -59158, + -59115, + -59071, + -59028, + -58984, + -58940, + -58896, + -58852, + -58808, + -58763, + -58719, + -58674, + -58629, + -58584, + -58539, + -58494, + -58448, + -58403, + -58357, + -58311, + -58265, + -58219, + -58173, + -58126, + -58080, + -58033, + -57987, + -57940, + -57893, + -57845, + -57798, + -57751, + -57703, + -57655, + -57607, + -57559, + -57511, + -57463, + -57415, + -57366, + -57317, + -57269, + -57220, + -57171, + -57121, + -57072, + -57023, + -56973, + -56923, + -56873, + -56823, + -56773, + -56723, + -56672, + -56622, + -56571, + -56520, + -56469, + -56418, + -56367, + -56316, + -56264, + -56213, + -56161, + -56109, + -56057, + -56005, + -55953, + -55900, + -55848, + -55795, + -55742, + -55689, + -55636, + -55583, + -55530, + -55476, + -55423, + -55369, + -55315, + -55261, + -55207, + -55153, + -55098, + -55044, + -54989, + -54934, + -54880, + -54824, + -54769, + -54714, + -54659, + -54603, + -54547, + -54492, + -54436, + -54380, + -54324, + -54267, + -54211, + -54154, + -54098, + -54041, + -53984, + -53927, + -53870, + -53812, + -53755, + -53697, + -53640, + -53582, + -53524, + -53466, + -53408, + -53349, + -53291, + -53232, + -53173, + -53115, + -53056, + -52997, + -52937, + -52878, + -52819, + -52759, + -52699, + -52640, + -52580, + -52519, + -52459, + -52399, + -52339, + -52278, + -52217, + -52156, + -52096, + -52034, + -51973, + -51912, + -51851, + -51789, + -51727, + -51666, + -51604, + -51542, + -51479, + -51417, + -51355, + -51292, + -51230, + -51167, + -51104, + -51041, + -50978, + -50915, + -50851, + -50788, + -50724, + -50661, + -50597, + -50533, + -50469, + -50404, + -50340, + -50276, + -50211, + -50147, + -50082, + -50017, + -49952, + -49887, + -49821, + -49756, + -49691, + -49625, + -49559, + -49493, + -49427, + -49361, + -49295, + -49229, + -49162, + -49096, + -49029, + -48962, + -48896, + -48829, + -48761, + -48694, + -48627, + -48559, + -48492, + -48424, + -48356, + -48289, + -48220, + -48152, + -48084, + -48016, + -47947, + -47879, + -47810, + -47741, + -47672, + -47603, + -47534, + -47465, + -47395, + -47326, + -47256, + -47187, + -47117, + -47047, + -46977, + -46907, + -46836, + -46766, + -46696, + -46625, + -46554, + -46483, + -46412, + -46341, + -46270, + -46199, + -46128, + -46056, + -45985, + -45913, + -45841, + -45769, + -45697, + -45625, + -45553, + -45481, + -45408, + -45336, + -45263, + -45190, + -45117, + -45044, + -44971, + -44898, + -44825, + -44751, + -44678, + -44604, + -44531, + -44457, + -44383, + -44309, + -44235, + -44161, + -44086, + -44012, + -43937, + -43863, + -43788, + -43713, + -43638, + -43563, + -43488, + -43413, + -43337, + -43262, + -43186, + -43111, + -43035, + -42959, + -42883, + -42807, + -42731, + -42654, + -42578, + -42502, + -42425, + -42348, + -42272, + -42195, + -42118, + -42041, + -41963, + -41886, + -41809, + -41731, + -41654, + -41576, + -41498, + -41420, + -41343, + -41264, + -41186, + -41108, + -41030, + -40951, + -40873, + -40794, + -40715, + -40637, + -40558, + -40479, + -40400, + -40320, + -40241, + -40162, + -40082, + -40003, + -39923, + -39843, + -39763, + -39683, + -39603, + -39523, + -39443, + -39363, + -39282, + -39202, + -39121, + -39040, + -38959, + -38879, + -38798, + -38717, + -38635, + -38554, + -38473, + -38391, + -38310, + -38228, + -38147, + -38065, + -37983, + -37901, + -37819, + -37737, + -37654, + -37572, + -37490, + -37407, + -37325, + -37242, + -37159, + -37076, + -36993, + -36910, + -36827, + -36744, + -36661, + -36577, + -36494, + -36410, + -36327, + -36243, + -36159, + -36075, + -35991, + -35907, + -35823, + -35739, + -35655, + -35570, + -35486, + -35401, + -35317, + -35232, + -35147, + -35062, + -34977, + -34892, + -34807, + -34722, + -34636, + -34551, + -34466, + -34380, + -34294, + -34209, + -34123, + -34037, + -33951, + -33865, + -33779, + -33693, + -33606, + -33520, + -33434, + -33347, + -33261, + -33174, + -33087, + -33000, + -32914, + -32827, + -32739, + -32652, + -32565, + -32478, + -32391, + -32303, + -32216, + -32128, + -32040, + -31953, + -31865, + -31777, + -31689, + -31601, + -31513, + -31425, + -31336, + -31248, + -31160, + -31071, + -30983, + -30894, + -30805, + -30716, + -30628, + -30539, + -30450, + -30361, + -30272, + -30182, + -30093, + -30004, + -29914, + -29825, + -29735, + -29646, + -29556, + -29466, + -29376, + -29287, + -29197, + -29106, + -29016, + -28926, + -28836, + -28746, + -28655, + -28565, + -28474, + -28384, + -28293, + -28202, + -28112, + -28021, + -27930, + -27839, + -27748, + -27657, + -27566, + -27474, + -27383, + -27292, + -27200, + -27109, + -27017, + -26926, + -26834, + -26742, + -26650, + -26558, + -26466, + -26374, + -26282, + -26190, + -26098, + -26006, + -25914, + -25821, + -25729, + -25636, + -25544, + -25451, + -25358, + -25266, + -25173, + -25080, + -24987, + -24894, + -24801, + -24708, + -24615, + -24522, + -24428, + -24335, + -24242, + -24148, + -24055, + -23961, + -23868, + -23774, + -23680, + -23587, + -23493, + -23399, + -23305, + -23211, + -23117, + -23023, + -22929, + -22834, + -22740, + -22646, + -22552, + -22457, + -22363, + -22268, + -22174, + -22079, + -21984, + -21890, + -21795, + -21700, + -21605, + -21510, + -21415, + -21320, + -21225, + -21130, + -21035, + -20939, + -20844, + -20749, + -20653, + -20558, + -20462, + -20367, + -20271, + -20176, + -20080, + -19984, + -19889, + -19793, + -19697, + -19601, + -19505, + -19409, + -19313, + -19217, + -19121, + -19025, + -18928, + -18832, + -18736, + -18639, + -18543, + -18447, + -18350, + -18254, + -18157, + -18060, + -17964, + -17867, + -17770, + -17673, + -17577, + -17480, + -17383, + -17286, + -17189, + -17092, + -16995, + -16898, + -16801, + -16703, + -16606, + -16509, + -16412, + -16314, + -16217, + -16119, + -16022, + -15924, + -15827, + -15729, + -15632, + -15534, + -15436, + -15339, + -15241, + -15143, + -15045, + -14947, + -14850, + -14752, + -14654, + -14556, + -14458, + -14360, + -14261, + -14163, + -14065, + -13967, + -13869, + -13770, + -13672, + -13574, + -13475, + -13377, + -13279, + -13180, + -13082, + -12983, + -12885, + -12786, + -12687, + -12589, + -12490, + -12391, + -12293, + -12194, + -12095, + -11996, + -11897, + -11798, + -11700, + -11601, + -11502, + -11403, + -11304, + -11205, + -11106, + -11007, + -10907, + -10808, + -10709, + -10610, + -10511, + -10411, + -10312, + -10213, + -10114, + -10014, + -9915, + -9815, + -9716, + -9617, + -9517, + -9418, + -9318, + -9219, + -9119, + -9020, + -8920, + -8820, + -8721, + -8621, + -8521, + -8422, + -8322, + -8222, + -8123, + -8023, + -7923, + -7823, + -7723, + -7624, + -7524, + -7424, + -7324, + -7224, + -7124, + -7024, + -6924, + -6824, + -6724, + -6624, + -6524, + -6424, + -6324, + -6224, + -6124, + -6024, + -5924, + -5824, + -5723, + -5623, + -5523, + -5423, + -5323, + -5223, + -5122, + -5022, + -4922, + -4822, + -4721, + -4621, + -4521, + -4421, + -4320, + -4220, + -4120, + -4019, + -3919, + -3819, + -3718, + -3618, + -3517, + -3417, + -3317, + -3216, + -3116, + -3015, + -2915, + -2815, + -2714, + -2614, + -2513, + -2413, + -2312, + -2212, + -2111, + -2011, + -1910, + -1810, + -1709, + -1609, + -1508, + -1408, + -1307, + -1207, + -1106, + -1006, + -905, + -805, + -704, + -604, + -503, + -403, + -302, + -202, + -101, + -1, + 100, + 201, + 301, + 402, + 502, + 603, + 703, + 804, + 904, + 1005, + 1105, + 1206, + 1306, + 1407, + 1507, + 1608, + 1708, + 1809, + 1909, + 2010, + 2110, + 2211, + 2311, + 2412, + 2512, + 2613, + 2713, + 2813, + 2914, + 3014, + 3115, + 3215, + 3316, + 3416, + 3516, + 3617, + 3717, + 3818, + 3918, + 4018, + 4119, + 4219, + 4319, + 4419, + 4520, + 4620, + 4720, + 4821, + 4921, + 5021, + 5121, + 5222, + 5322, + 5422, + 5522, + 5622, + 5722, + 5823, + 5923, + 6023, + 6123, + 6223, + 6323, + 6423, + 6523, + 6623, + 6723, + 6823, + 6923, + 7023, + 7123, + 7223, + 7323, + 7423, + 7523, + 7623, + 7722, + 7822, + 7922, + 8022, + 8122, + 8221, + 8321, + 8421, + 8520, + 8620, + 8720, + 8819, + 8919, + 9019, + 9118, + 9218, + 9317, + 9417, + 9516, + 9616, + 9715, + 9814, + 9914, + 10013, + 10113, + 10212, + 10311, + 10410, + 10510, + 10609, + 10708, + 10807, + 10906, + 11005, + 11105, + 11204, + 11303, + 11402, + 11501, + 11600, + 11699, + 11797, + 11896, + 11995, + 12094, + 12193, + 12292, + 12390, + 12489, + 12588, + 12686, + 12785, + 12884, + 12982, + 13081, + 13179, + 13278, + 13376, + 13474, + 13573, + 13671, + 13769, + 13868, + 13966, + 14064, + 14162, + 14260, + 14359, + 14457, + 14555, + 14653, + 14751, + 14849, + 14946, + 15044, + 15142, + 15240, + 15338, + 15435, + 15533, + 15631, + 15728, + 15826, + 15923, + 16021, + 16118, + 16216, + 16313, + 16411, + 16508, + 16605, + 16702, + 16800, + 16897, + 16994, + 17091, + 17188, + 17285, + 17382, + 17479, + 17576, + 17672, + 17769, + 17866, + 17963, + 18059, + 18156, + 18253, + 18349, + 18446, + 18542, + 18638, + 18735, + 18831, + 18927, + 19024, + 19120, + 19216, + 19312, + 19408, + 19504, + 19600, + 19696, + 19792, + 19888, + 19983, + 20079, + 20175, + 20270, + 20366, + 20461, + 20557, + 20652, + 20748, + 20843, + 20938, + 21034, + 21129, + 21224, + 21319, + 21414, + 21509, + 21604, + 21699, + 21794, + 21888, + 21983, + 22078, + 22173, + 22267, + 22362, + 22456, + 22551, + 22645, + 22739, + 22833, + 22928, + 23022, + 23116, + 23210, + 23304, + 23398, + 23492, + 23586, + 23679, + 23773, + 23867, + 23960, + 24054, + 24147, + 24241, + 24334, + 24427, + 24521, + 24614, + 24707, + 24800, + 24893, + 24986, + 25079, + 25172, + 25265, + 25357, + 25450, + 25543, + 25635, + 25728, + 25820, + 25913, + 26005, + 26097, + 26189, + 26281, + 26373, + 26465, + 26557, + 26649, + 26741, + 26833, + 26925, + 27016, + 27108, + 27199, + 27291, + 27382, + 27473, + 27565, + 27656, + 27747, + 27838, + 27929, + 28020, + 28111, + 28201, + 28292, + 28383, + 28473, + 28564, + 28654, + 28745, + 28835, + 28925, + 29015, + 29105, + 29196, + 29285, + 29375, + 29465, + 29555, + 29645, + 29734, + 29824, + 29913, + 30003, + 30092, + 30181, + 30271, + 30360, + 30449, + 30538, + 30627, + 30715, + 30804, + 30893, + 30982, + 31070, + 31159, + 31247, + 31335, + 31424, + 31512, + 31600, + 31688, + 31776, + 31864, + 31952, + 32039, + 32127, + 32215, + 32302, + 32390, + 32477, + 32564, + 32651, + 32738, + 32826, + 32912, + 32999, + 33086, + 33173, + 33260, + 33346, + 33433, + 33519, + 33605, + 33692, + 33778, + 33864, + 33950, + 34036, + 34122, + 34208, + 34293, + 34379, + 34465, + 34550, + 34635, + 34721, + 34806, + 34891, + 34976, + 35061, + 35146, + 35231, + 35316, + 35400, + 35485, + 35569, + 35654, + 35738, + 35822, + 35906, + 35990, + 36074, + 36158, + 36242, + 36326, + 36409, + 36493, + 36576, + 36660, + 36743, + 36826, + 36909, + 36992, + 37075, + 37158, + 37241, + 37324, + 37406, + 37489, + 37571, + 37653, + 37736, + 37818, + 37900, + 37982, + 38064, + 38146, + 38227, + 38309, + 38390, + 38472, + 38553, + 38634, + 38716, + 38797, + 38878, + 38958, + 39039, + 39120, + 39201, + 39281, + 39361, + 39442, + 39522, + 39602, + 39682, + 39762, + 39842, + 39922, + 40002, + 40081, + 40161, + 40240, + 40319, + 40399, + 40478, + 40557, + 40636, + 40714, + 40793, + 40872, + 40950, + 41029, + 41107, + 41185, + 41263, + 41342, + 41419, + 41497, + 41575, + 41653, + 41730, + 41808, + 41885, + 41962, + 42040, + 42117, + 42194, + 42271, + 42347, + 42424, + 42501, + 42577, + 42653, + 42730, + 42806, + 42882, + 42958, + 43034, + 43110, + 43185, + 43261, + 43336, + 43412, + 43487, + 43562, + 43637, + 43712, + 43787, + 43862, + 43936, + 44011, + 44085, + 44160, + 44234, + 44308, + 44382, + 44456, + 44530, + 44603, + 44677, + 44750, + 44824, + 44897, + 44970, + 45043, + 45116, + 45189, + 45262, + 45335, + 45407, + 45480, + 45552, + 45624, + 45696, + 45768, + 45840, + 45912, + 45984, + 46055, + 46127, + 46198, + 46269, + 46340, + 46411, + 46482, + 46553, + 46624, + 46695, + 46765, + 46835, + 46906, + 46976, + 47046, + 47116, + 47186, + 47255, + 47325, + 47394, + 47464, + 47533, + 47602, + 47671, + 47740, + 47809, + 47878, + 47946, + 48015, + 48083, + 48151, + 48219, + 48288, + 48355, + 48423, + 48491, + 48558, + 48626, + 48693, + 48760, + 48828, + 48895, + 48961, + 49028, + 49095, + 49161, + 49228, + 49294, + 49360, + 49426, + 49492, + 49558, + 49624, + 49690, + 49755, + 49820, + 49886, + 49951, + 50016, + 50081, + 50145, + 50210, + 50275, + 50339, + 50403, + 50468, + 50532, + 50596, + 50660, + 50723, + 50787, + 50850, + 50914, + 50977, + 51040, + 51103, + 51166, + 51229, + 51291, + 51354, + 51416, + 51478, + 51541, + 51603, + 51665, + 51726, + 51788, + 51850, + 51911, + 51972, + 52033, + 52095, + 52155, + 52216, + 52277, + 52338, + 52398, + 52458, + 52518, + 52579, + 52639, + 52698, + 52758, + 52818, + 52877, + 52936, + 52996, + 53055, + 53114, + 53172, + 53231, + 53290, + 53348, + 53407, + 53465, + 53523, + 53581, + 53639, + 53696, + 53754, + 53811, + 53869, + 53926, + 53983, + 54040, + 54097, + 54153, + 54210, + 54266, + 54323, + 54379, + 54435, + 54491, + 54546, + 54602, + 54658, + 54713, + 54768, + 54823, + 54879, + 54933, + 54988, + 55043, + 55097, + 55152, + 55206, + 55260, + 55314, + 55368, + 55422, + 55475, + 55529, + 55582, + 55635, + 55688, + 55741, + 55794, + 55847, + 55899, + 55952, + 56004, + 56056, + 56108, + 56160, + 56212, + 56263, + 56315, + 56366, + 56417, + 56468, + 56519, + 56570, + 56621, + 56671, + 56722, + 56772, + 56822, + 56872, + 56922, + 56972, + 57022, + 57071, + 57120, + 57170, + 57219, + 57268, + 57316, + 57365, + 57414, + 57462, + 57510, + 57558, + 57606, + 57654, + 57702, + 57750, + 57797, + 57844, + 57892, + 57939, + 57986, + 58032, + 58079, + 58125, + 58172, + 58218, + 58264, + 58310, + 58356, + 58402, + 58447, + 58493, + 58538, + 58583, + 58628, + 58673, + 58718, + 58762, + 58807, + 58851, + 58895, + 58939, + 58983, + 59027, + 59070, + 59114, + 59157, + 59200, + 59243, + 59286, + 59329, + 59372, + 59414, + 59457, + 59499, + 59541, + 59583, + 59625, + 59666, + 59708, + 59749, + 59790, + 59831, + 59872, + 59913, + 59954, + 59994, + 60035, + 60075, + 60115, + 60155, + 60195, + 60235, + 60274, + 60313, + 60353, + 60392, + 60431, + 60470, + 60508, + 60547, + 60585, + 60624, + 60662, + 60700, + 60737, + 60775, + 60813, + 60850, + 60887, + 60924, + 60961, + 60998, + 61035, + 61071, + 61108, + 61144, + 61180, + 61216, + 61252, + 61288, + 61323, + 61359, + 61394, + 61429, + 61464, + 61499, + 61533, + 61568, + 61602, + 61637, + 61671, + 61705, + 61738, + 61772, + 61805, + 61839, + 61872, + 61905, + 61938, + 61971, + 62003, + 62036, + 62068, + 62100, + 62133, + 62164, + 62196, + 62228, + 62259, + 62291, + 62322, + 62353, + 62384, + 62414, + 62445, + 62475, + 62506, + 62536, + 62566, + 62596, + 62625, + 62655, + 62684, + 62714, + 62743, + 62772, + 62800, + 62829, + 62858, + 62886, + 62914, + 62942, + 62970, + 62998, + 63026, + 63053, + 63080, + 63108, + 63135, + 63162, + 63188, + 63215, + 63241, + 63268, + 63294, + 63320, + 63346, + 63371, + 63397, + 63422, + 63447, + 63473, + 63498, + 63522, + 63547, + 63571, + 63596, + 63620, + 63644, + 63668, + 63692, + 63715, + 63739, + 63762, + 63785, + 63808, + 63831, + 63854, + 63876, + 63899, + 63921, + 63943, + 63965, + 63987, + 64009, + 64030, + 64051, + 64073, + 64094, + 64115, + 64135, + 64156, + 64176, + 64197, + 64217, + 64237, + 64257, + 64276, + 64296, + 64315, + 64334, + 64353, + 64372, + 64391, + 64410, + 64428, + 64447, + 64465, + 64483, + 64501, + 64518, + 64536, + 64553, + 64571, + 64588, + 64605, + 64622, + 64638, + 64655, + 64671, + 64687, + 64703, + 64719, + 64735, + 64751, + 64766, + 64781, + 64796, + 64811, + 64826, + 64841, + 64855, + 64870, + 64884, + 64898, + 64912, + 64926, + 64939, + 64953, + 64966, + 64979, + 64992, + 65005, + 65018, + 65030, + 65043, + 65055, + 65067, + 65079, + 65091, + 65102, + 65114, + 65125, + 65136, + 65147, + 65158, + 65169, + 65179, + 65190, + 65200, + 65210, + 65220, + 65230, + 65239, + 65249, + 65258, + 65267, + 65276, + 65285, + 65294, + 65302, + 65311, + 65319, + 65327, + 65335, + 65343, + 65350, + 65358, + 65365, + 65372, + 65379, + 65386, + 65393, + 65400, + 65406, + 65412, + 65418, + 65424, + 65430, + 65436, + 65441, + 65446, + 65452, + 65457, + 65461, + 65466, + 65471, + 65475, + 65479, + 65483, + 65487, + 65491, + 65495, + 65498, + 65501, + 65505, + 65508, + 65511, + 65513, + 65516, + 65518, + 65520, + 65522, + 65524, + 65526, + 65528, + 65529, + 65531, + 65532, + 65533, + 65534, + 65534, + 65535, + 65535, + 65535 + +}; + +#endif + +short ArcCosTable[]={ + + 2047, + 2027, + 2019, + 2012, + 2007, + 2002, + 1998, + 1994, + 1990, + 1986, + 1983, + 1980, + 1977, + 1974, + 1971, + 1969, + 1966, + 1963, + 1961, + 1959, + 1956, + 1954, + 1952, + 1950, + 1948, + 1946, + 1944, + 1942, + 1940, + 1938, + 1936, + 1934, + 1932, + 1930, + 1929, + 1927, + 1925, + 1923, + 1922, + 1920, + 1918, + 1917, + 1915, + 1914, + 1912, + 1911, + 1909, + 1908, + 1906, + 1905, + 1903, + 1902, + 1900, + 1899, + 1897, + 1896, + 1895, + 1893, + 1892, + 1891, + 1889, + 1888, + 1887, + 1885, + 1884, + 1883, + 1882, + 1880, + 1879, + 1878, + 1877, + 1875, + 1874, + 1873, + 1872, + 1871, + 1869, + 1868, + 1867, + 1866, + 1865, + 1864, + 1862, + 1861, + 1860, + 1859, + 1858, + 1857, + 1856, + 1855, + 1854, + 1852, + 1851, + 1850, + 1849, + 1848, + 1847, + 1846, + 1845, + 1844, + 1843, + 1842, + 1841, + 1840, + 1839, + 1838, + 1837, + 1836, + 1835, + 1834, + 1833, + 1832, + 1831, + 1830, + 1829, + 1828, + 1827, + 1826, + 1825, + 1824, + 1823, + 1822, + 1821, + 1820, + 1819, + 1819, + 1818, + 1817, + 1816, + 1815, + 1814, + 1813, + 1812, + 1811, + 1810, + 1809, + 1809, + 1808, + 1807, + 1806, + 1805, + 1804, + 1803, + 1802, + 1802, + 1801, + 1800, + 1799, + 1798, + 1797, + 1796, + 1796, + 1795, + 1794, + 1793, + 1792, + 1791, + 1791, + 1790, + 1789, + 1788, + 1787, + 1786, + 1786, + 1785, + 1784, + 1783, + 1782, + 1782, + 1781, + 1780, + 1779, + 1778, + 1778, + 1777, + 1776, + 1775, + 1774, + 1774, + 1773, + 1772, + 1771, + 1771, + 1770, + 1769, + 1768, + 1768, + 1767, + 1766, + 1765, + 1764, + 1764, + 1763, + 1762, + 1761, + 1761, + 1760, + 1759, + 1758, + 1758, + 1757, + 1756, + 1756, + 1755, + 1754, + 1753, + 1753, + 1752, + 1751, + 1750, + 1750, + 1749, + 1748, + 1748, + 1747, + 1746, + 1745, + 1745, + 1744, + 1743, + 1743, + 1742, + 1741, + 1740, + 1740, + 1739, + 1738, + 1738, + 1737, + 1736, + 1736, + 1735, + 1734, + 1734, + 1733, + 1732, + 1731, + 1731, + 1730, + 1729, + 1729, + 1728, + 1727, + 1727, + 1726, + 1725, + 1725, + 1724, + 1723, + 1723, + 1722, + 1721, + 1721, + 1720, + 1719, + 1719, + 1718, + 1717, + 1717, + 1716, + 1715, + 1715, + 1714, + 1713, + 1713, + 1712, + 1712, + 1711, + 1710, + 1710, + 1709, + 1708, + 1708, + 1707, + 1706, + 1706, + 1705, + 1705, + 1704, + 1703, + 1703, + 1702, + 1701, + 1701, + 1700, + 1699, + 1699, + 1698, + 1698, + 1697, + 1696, + 1696, + 1695, + 1694, + 1694, + 1693, + 1693, + 1692, + 1691, + 1691, + 1690, + 1690, + 1689, + 1688, + 1688, + 1687, + 1687, + 1686, + 1685, + 1685, + 1684, + 1684, + 1683, + 1682, + 1682, + 1681, + 1681, + 1680, + 1679, + 1679, + 1678, + 1678, + 1677, + 1676, + 1676, + 1675, + 1675, + 1674, + 1673, + 1673, + 1672, + 1672, + 1671, + 1671, + 1670, + 1669, + 1669, + 1668, + 1668, + 1667, + 1666, + 1666, + 1665, + 1665, + 1664, + 1664, + 1663, + 1662, + 1662, + 1661, + 1661, + 1660, + 1660, + 1659, + 1658, + 1658, + 1657, + 1657, + 1656, + 1656, + 1655, + 1655, + 1654, + 1653, + 1653, + 1652, + 1652, + 1651, + 1651, + 1650, + 1649, + 1649, + 1648, + 1648, + 1647, + 1647, + 1646, + 1646, + 1645, + 1645, + 1644, + 1643, + 1643, + 1642, + 1642, + 1641, + 1641, + 1640, + 1640, + 1639, + 1639, + 1638, + 1637, + 1637, + 1636, + 1636, + 1635, + 1635, + 1634, + 1634, + 1633, + 1633, + 1632, + 1632, + 1631, + 1630, + 1630, + 1629, + 1629, + 1628, + 1628, + 1627, + 1627, + 1626, + 1626, + 1625, + 1625, + 1624, + 1624, + 1623, + 1623, + 1622, + 1621, + 1621, + 1620, + 1620, + 1619, + 1619, + 1618, + 1618, + 1617, + 1617, + 1616, + 1616, + 1615, + 1615, + 1614, + 1614, + 1613, + 1613, + 1612, + 1612, + 1611, + 1611, + 1610, + 1610, + 1609, + 1609, + 1608, + 1608, + 1607, + 1607, + 1606, + 1605, + 1605, + 1604, + 1604, + 1603, + 1603, + 1602, + 1602, + 1601, + 1601, + 1600, + 1600, + 1599, + 1599, + 1598, + 1598, + 1597, + 1597, + 1596, + 1596, + 1595, + 1595, + 1594, + 1594, + 1593, + 1593, + 1592, + 1592, + 1591, + 1591, + 1590, + 1590, + 1589, + 1589, + 1589, + 1588, + 1588, + 1587, + 1587, + 1586, + 1586, + 1585, + 1585, + 1584, + 1584, + 1583, + 1583, + 1582, + 1582, + 1581, + 1581, + 1580, + 1580, + 1579, + 1579, + 1578, + 1578, + 1577, + 1577, + 1576, + 1576, + 1575, + 1575, + 1574, + 1574, + 1573, + 1573, + 1573, + 1572, + 1572, + 1571, + 1571, + 1570, + 1570, + 1569, + 1569, + 1568, + 1568, + 1567, + 1567, + 1566, + 1566, + 1565, + 1565, + 1564, + 1564, + 1563, + 1563, + 1563, + 1562, + 1562, + 1561, + 1561, + 1560, + 1560, + 1559, + 1559, + 1558, + 1558, + 1557, + 1557, + 1556, + 1556, + 1556, + 1555, + 1555, + 1554, + 1554, + 1553, + 1553, + 1552, + 1552, + 1551, + 1551, + 1550, + 1550, + 1550, + 1549, + 1549, + 1548, + 1548, + 1547, + 1547, + 1546, + 1546, + 1545, + 1545, + 1544, + 1544, + 1544, + 1543, + 1543, + 1542, + 1542, + 1541, + 1541, + 1540, + 1540, + 1539, + 1539, + 1539, + 1538, + 1538, + 1537, + 1537, + 1536, + 1536, + 1535, + 1535, + 1535, + 1534, + 1534, + 1533, + 1533, + 1532, + 1532, + 1531, + 1531, + 1530, + 1530, + 1530, + 1529, + 1529, + 1528, + 1528, + 1527, + 1527, + 1526, + 1526, + 1526, + 1525, + 1525, + 1524, + 1524, + 1523, + 1523, + 1523, + 1522, + 1522, + 1521, + 1521, + 1520, + 1520, + 1519, + 1519, + 1519, + 1518, + 1518, + 1517, + 1517, + 1516, + 1516, + 1515, + 1515, + 1515, + 1514, + 1514, + 1513, + 1513, + 1512, + 1512, + 1512, + 1511, + 1511, + 1510, + 1510, + 1509, + 1509, + 1509, + 1508, + 1508, + 1507, + 1507, + 1506, + 1506, + 1505, + 1505, + 1505, + 1504, + 1504, + 1503, + 1503, + 1502, + 1502, + 1502, + 1501, + 1501, + 1500, + 1500, + 1499, + 1499, + 1499, + 1498, + 1498, + 1497, + 1497, + 1497, + 1496, + 1496, + 1495, + 1495, + 1494, + 1494, + 1494, + 1493, + 1493, + 1492, + 1492, + 1491, + 1491, + 1491, + 1490, + 1490, + 1489, + 1489, + 1488, + 1488, + 1488, + 1487, + 1487, + 1486, + 1486, + 1486, + 1485, + 1485, + 1484, + 1484, + 1483, + 1483, + 1483, + 1482, + 1482, + 1481, + 1481, + 1481, + 1480, + 1480, + 1479, + 1479, + 1478, + 1478, + 1478, + 1477, + 1477, + 1476, + 1476, + 1476, + 1475, + 1475, + 1474, + 1474, + 1473, + 1473, + 1473, + 1472, + 1472, + 1471, + 1471, + 1471, + 1470, + 1470, + 1469, + 1469, + 1469, + 1468, + 1468, + 1467, + 1467, + 1466, + 1466, + 1466, + 1465, + 1465, + 1464, + 1464, + 1464, + 1463, + 1463, + 1462, + 1462, + 1462, + 1461, + 1461, + 1460, + 1460, + 1460, + 1459, + 1459, + 1458, + 1458, + 1458, + 1457, + 1457, + 1456, + 1456, + 1456, + 1455, + 1455, + 1454, + 1454, + 1453, + 1453, + 1453, + 1452, + 1452, + 1451, + 1451, + 1451, + 1450, + 1450, + 1449, + 1449, + 1449, + 1448, + 1448, + 1447, + 1447, + 1447, + 1446, + 1446, + 1445, + 1445, + 1445, + 1444, + 1444, + 1443, + 1443, + 1443, + 1442, + 1442, + 1441, + 1441, + 1441, + 1440, + 1440, + 1440, + 1439, + 1439, + 1438, + 1438, + 1438, + 1437, + 1437, + 1436, + 1436, + 1436, + 1435, + 1435, + 1434, + 1434, + 1434, + 1433, + 1433, + 1432, + 1432, + 1432, + 1431, + 1431, + 1430, + 1430, + 1430, + 1429, + 1429, + 1428, + 1428, + 1428, + 1427, + 1427, + 1427, + 1426, + 1426, + 1425, + 1425, + 1425, + 1424, + 1424, + 1423, + 1423, + 1423, + 1422, + 1422, + 1421, + 1421, + 1421, + 1420, + 1420, + 1420, + 1419, + 1419, + 1418, + 1418, + 1418, + 1417, + 1417, + 1416, + 1416, + 1416, + 1415, + 1415, + 1414, + 1414, + 1414, + 1413, + 1413, + 1413, + 1412, + 1412, + 1411, + 1411, + 1411, + 1410, + 1410, + 1409, + 1409, + 1409, + 1408, + 1408, + 1408, + 1407, + 1407, + 1406, + 1406, + 1406, + 1405, + 1405, + 1405, + 1404, + 1404, + 1403, + 1403, + 1403, + 1402, + 1402, + 1401, + 1401, + 1401, + 1400, + 1400, + 1400, + 1399, + 1399, + 1398, + 1398, + 1398, + 1397, + 1397, + 1397, + 1396, + 1396, + 1395, + 1395, + 1395, + 1394, + 1394, + 1394, + 1393, + 1393, + 1392, + 1392, + 1392, + 1391, + 1391, + 1390, + 1390, + 1390, + 1389, + 1389, + 1389, + 1388, + 1388, + 1387, + 1387, + 1387, + 1386, + 1386, + 1386, + 1385, + 1385, + 1384, + 1384, + 1384, + 1383, + 1383, + 1383, + 1382, + 1382, + 1381, + 1381, + 1381, + 1380, + 1380, + 1380, + 1379, + 1379, + 1379, + 1378, + 1378, + 1377, + 1377, + 1377, + 1376, + 1376, + 1376, + 1375, + 1375, + 1374, + 1374, + 1374, + 1373, + 1373, + 1373, + 1372, + 1372, + 1371, + 1371, + 1371, + 1370, + 1370, + 1370, + 1369, + 1369, + 1369, + 1368, + 1368, + 1367, + 1367, + 1367, + 1366, + 1366, + 1366, + 1365, + 1365, + 1364, + 1364, + 1364, + 1363, + 1363, + 1363, + 1362, + 1362, + 1362, + 1361, + 1361, + 1360, + 1360, + 1360, + 1359, + 1359, + 1359, + 1358, + 1358, + 1358, + 1357, + 1357, + 1356, + 1356, + 1356, + 1355, + 1355, + 1355, + 1354, + 1354, + 1353, + 1353, + 1353, + 1352, + 1352, + 1352, + 1351, + 1351, + 1351, + 1350, + 1350, + 1349, + 1349, + 1349, + 1348, + 1348, + 1348, + 1347, + 1347, + 1347, + 1346, + 1346, + 1346, + 1345, + 1345, + 1344, + 1344, + 1344, + 1343, + 1343, + 1343, + 1342, + 1342, + 1342, + 1341, + 1341, + 1340, + 1340, + 1340, + 1339, + 1339, + 1339, + 1338, + 1338, + 1338, + 1337, + 1337, + 1337, + 1336, + 1336, + 1335, + 1335, + 1335, + 1334, + 1334, + 1334, + 1333, + 1333, + 1333, + 1332, + 1332, + 1331, + 1331, + 1331, + 1330, + 1330, + 1330, + 1329, + 1329, + 1329, + 1328, + 1328, + 1328, + 1327, + 1327, + 1327, + 1326, + 1326, + 1325, + 1325, + 1325, + 1324, + 1324, + 1324, + 1323, + 1323, + 1323, + 1322, + 1322, + 1322, + 1321, + 1321, + 1320, + 1320, + 1320, + 1319, + 1319, + 1319, + 1318, + 1318, + 1318, + 1317, + 1317, + 1317, + 1316, + 1316, + 1316, + 1315, + 1315, + 1314, + 1314, + 1314, + 1313, + 1313, + 1313, + 1312, + 1312, + 1312, + 1311, + 1311, + 1311, + 1310, + 1310, + 1310, + 1309, + 1309, + 1308, + 1308, + 1308, + 1307, + 1307, + 1307, + 1306, + 1306, + 1306, + 1305, + 1305, + 1305, + 1304, + 1304, + 1304, + 1303, + 1303, + 1303, + 1302, + 1302, + 1301, + 1301, + 1301, + 1300, + 1300, + 1300, + 1299, + 1299, + 1299, + 1298, + 1298, + 1298, + 1297, + 1297, + 1297, + 1296, + 1296, + 1296, + 1295, + 1295, + 1294, + 1294, + 1294, + 1293, + 1293, + 1293, + 1292, + 1292, + 1292, + 1291, + 1291, + 1291, + 1290, + 1290, + 1290, + 1289, + 1289, + 1289, + 1288, + 1288, + 1288, + 1287, + 1287, + 1286, + 1286, + 1286, + 1285, + 1285, + 1285, + 1284, + 1284, + 1284, + 1283, + 1283, + 1283, + 1282, + 1282, + 1282, + 1281, + 1281, + 1281, + 1280, + 1280, + 1280, + 1279, + 1279, + 1279, + 1278, + 1278, + 1278, + 1277, + 1277, + 1276, + 1276, + 1276, + 1275, + 1275, + 1275, + 1274, + 1274, + 1274, + 1273, + 1273, + 1273, + 1272, + 1272, + 1272, + 1271, + 1271, + 1271, + 1270, + 1270, + 1270, + 1269, + 1269, + 1269, + 1268, + 1268, + 1268, + 1267, + 1267, + 1267, + 1266, + 1266, + 1266, + 1265, + 1265, + 1265, + 1264, + 1264, + 1263, + 1263, + 1263, + 1262, + 1262, + 1262, + 1261, + 1261, + 1261, + 1260, + 1260, + 1260, + 1259, + 1259, + 1259, + 1258, + 1258, + 1258, + 1257, + 1257, + 1257, + 1256, + 1256, + 1256, + 1255, + 1255, + 1255, + 1254, + 1254, + 1254, + 1253, + 1253, + 1253, + 1252, + 1252, + 1252, + 1251, + 1251, + 1251, + 1250, + 1250, + 1250, + 1249, + 1249, + 1249, + 1248, + 1248, + 1248, + 1247, + 1247, + 1247, + 1246, + 1246, + 1245, + 1245, + 1245, + 1244, + 1244, + 1244, + 1243, + 1243, + 1243, + 1242, + 1242, + 1242, + 1241, + 1241, + 1241, + 1240, + 1240, + 1240, + 1239, + 1239, + 1239, + 1238, + 1238, + 1238, + 1237, + 1237, + 1237, + 1236, + 1236, + 1236, + 1235, + 1235, + 1235, + 1234, + 1234, + 1234, + 1233, + 1233, + 1233, + 1232, + 1232, + 1232, + 1231, + 1231, + 1231, + 1230, + 1230, + 1230, + 1229, + 1229, + 1229, + 1228, + 1228, + 1228, + 1227, + 1227, + 1227, + 1226, + 1226, + 1226, + 1225, + 1225, + 1225, + 1224, + 1224, + 1224, + 1223, + 1223, + 1223, + 1222, + 1222, + 1222, + 1221, + 1221, + 1221, + 1220, + 1220, + 1220, + 1219, + 1219, + 1219, + 1218, + 1218, + 1218, + 1217, + 1217, + 1217, + 1216, + 1216, + 1216, + 1215, + 1215, + 1215, + 1214, + 1214, + 1214, + 1213, + 1213, + 1213, + 1212, + 1212, + 1212, + 1211, + 1211, + 1211, + 1210, + 1210, + 1210, + 1209, + 1209, + 1209, + 1208, + 1208, + 1208, + 1207, + 1207, + 1207, + 1206, + 1206, + 1206, + 1205, + 1205, + 1205, + 1204, + 1204, + 1204, + 1203, + 1203, + 1203, + 1202, + 1202, + 1202, + 1201, + 1201, + 1201, + 1200, + 1200, + 1200, + 1199, + 1199, + 1199, + 1198, + 1198, + 1198, + 1197, + 1197, + 1197, + 1196, + 1196, + 1196, + 1195, + 1195, + 1195, + 1194, + 1194, + 1194, + 1193, + 1193, + 1193, + 1192, + 1192, + 1192, + 1192, + 1191, + 1191, + 1191, + 1190, + 1190, + 1190, + 1189, + 1189, + 1189, + 1188, + 1188, + 1188, + 1187, + 1187, + 1187, + 1186, + 1186, + 1186, + 1185, + 1185, + 1185, + 1184, + 1184, + 1184, + 1183, + 1183, + 1183, + 1182, + 1182, + 1182, + 1181, + 1181, + 1181, + 1180, + 1180, + 1180, + 1179, + 1179, + 1179, + 1178, + 1178, + 1178, + 1177, + 1177, + 1177, + 1176, + 1176, + 1176, + 1175, + 1175, + 1175, + 1174, + 1174, + 1174, + 1173, + 1173, + 1173, + 1172, + 1172, + 1172, + 1172, + 1171, + 1171, + 1171, + 1170, + 1170, + 1170, + 1169, + 1169, + 1169, + 1168, + 1168, + 1168, + 1167, + 1167, + 1167, + 1166, + 1166, + 1166, + 1165, + 1165, + 1165, + 1164, + 1164, + 1164, + 1163, + 1163, + 1163, + 1162, + 1162, + 1162, + 1161, + 1161, + 1161, + 1160, + 1160, + 1160, + 1159, + 1159, + 1159, + 1158, + 1158, + 1158, + 1157, + 1157, + 1157, + 1157, + 1156, + 1156, + 1156, + 1155, + 1155, + 1155, + 1154, + 1154, + 1154, + 1153, + 1153, + 1153, + 1152, + 1152, + 1152, + 1151, + 1151, + 1151, + 1150, + 1150, + 1150, + 1149, + 1149, + 1149, + 1148, + 1148, + 1148, + 1147, + 1147, + 1147, + 1146, + 1146, + 1146, + 1145, + 1145, + 1145, + 1145, + 1144, + 1144, + 1144, + 1143, + 1143, + 1143, + 1142, + 1142, + 1142, + 1141, + 1141, + 1141, + 1140, + 1140, + 1140, + 1139, + 1139, + 1139, + 1138, + 1138, + 1138, + 1137, + 1137, + 1137, + 1136, + 1136, + 1136, + 1135, + 1135, + 1135, + 1134, + 1134, + 1134, + 1134, + 1133, + 1133, + 1133, + 1132, + 1132, + 1132, + 1131, + 1131, + 1131, + 1130, + 1130, + 1130, + 1129, + 1129, + 1129, + 1128, + 1128, + 1128, + 1127, + 1127, + 1127, + 1126, + 1126, + 1126, + 1125, + 1125, + 1125, + 1124, + 1124, + 1124, + 1124, + 1123, + 1123, + 1123, + 1122, + 1122, + 1122, + 1121, + 1121, + 1121, + 1120, + 1120, + 1120, + 1119, + 1119, + 1119, + 1118, + 1118, + 1118, + 1117, + 1117, + 1117, + 1116, + 1116, + 1116, + 1115, + 1115, + 1115, + 1115, + 1114, + 1114, + 1114, + 1113, + 1113, + 1113, + 1112, + 1112, + 1112, + 1111, + 1111, + 1111, + 1110, + 1110, + 1110, + 1109, + 1109, + 1109, + 1108, + 1108, + 1108, + 1107, + 1107, + 1107, + 1106, + 1106, + 1106, + 1106, + 1105, + 1105, + 1105, + 1104, + 1104, + 1104, + 1103, + 1103, + 1103, + 1102, + 1102, + 1102, + 1101, + 1101, + 1101, + 1100, + 1100, + 1100, + 1099, + 1099, + 1099, + 1098, + 1098, + 1098, + 1098, + 1097, + 1097, + 1097, + 1096, + 1096, + 1096, + 1095, + 1095, + 1095, + 1094, + 1094, + 1094, + 1093, + 1093, + 1093, + 1092, + 1092, + 1092, + 1091, + 1091, + 1091, + 1090, + 1090, + 1090, + 1090, + 1089, + 1089, + 1089, + 1088, + 1088, + 1088, + 1087, + 1087, + 1087, + 1086, + 1086, + 1086, + 1085, + 1085, + 1085, + 1084, + 1084, + 1084, + 1083, + 1083, + 1083, + 1082, + 1082, + 1082, + 1082, + 1081, + 1081, + 1081, + 1080, + 1080, + 1080, + 1079, + 1079, + 1079, + 1078, + 1078, + 1078, + 1077, + 1077, + 1077, + 1076, + 1076, + 1076, + 1075, + 1075, + 1075, + 1074, + 1074, + 1074, + 1074, + 1073, + 1073, + 1073, + 1072, + 1072, + 1072, + 1071, + 1071, + 1071, + 1070, + 1070, + 1070, + 1069, + 1069, + 1069, + 1068, + 1068, + 1068, + 1067, + 1067, + 1067, + 1067, + 1066, + 1066, + 1066, + 1065, + 1065, + 1065, + 1064, + 1064, + 1064, + 1063, + 1063, + 1063, + 1062, + 1062, + 1062, + 1061, + 1061, + 1061, + 1060, + 1060, + 1060, + 1059, + 1059, + 1059, + 1059, + 1058, + 1058, + 1058, + 1057, + 1057, + 1057, + 1056, + 1056, + 1056, + 1055, + 1055, + 1055, + 1054, + 1054, + 1054, + 1053, + 1053, + 1053, + 1052, + 1052, + 1052, + 1052, + 1051, + 1051, + 1051, + 1050, + 1050, + 1050, + 1049, + 1049, + 1049, + 1048, + 1048, + 1048, + 1047, + 1047, + 1047, + 1046, + 1046, + 1046, + 1045, + 1045, + 1045, + 1045, + 1044, + 1044, + 1044, + 1043, + 1043, + 1043, + 1042, + 1042, + 1042, + 1041, + 1041, + 1041, + 1040, + 1040, + 1040, + 1039, + 1039, + 1039, + 1038, + 1038, + 1038, + 1038, + 1037, + 1037, + 1037, + 1036, + 1036, + 1036, + 1035, + 1035, + 1035, + 1034, + 1034, + 1034, + 1033, + 1033, + 1033, + 1032, + 1032, + 1032, + 1031, + 1031, + 1031, + 1031, + 1030, + 1030, + 1030, + 1029, + 1029, + 1029, + 1028, + 1028, + 1028, + 1027, + 1027, + 1027, + 1026, + 1026, + 1026, + 1025, + 1025, + 1025, + 1024, + 1024, + 1024, + 1024, + 1023, + 1023, + 1023, + 1022, + 1022, + 1022, + 1021, + 1021, + 1021, + 1020, + 1020, + 1020, + 1019, + 1019, + 1019, + 1018, + 1018, + 1018, + 1017, + 1017, + 1017, + 1016, + 1016, + 1016, + 1016, + 1015, + 1015, + 1015, + 1014, + 1014, + 1014, + 1013, + 1013, + 1013, + 1012, + 1012, + 1012, + 1011, + 1011, + 1011, + 1010, + 1010, + 1010, + 1009, + 1009, + 1009, + 1009, + 1008, + 1008, + 1008, + 1007, + 1007, + 1007, + 1006, + 1006, + 1006, + 1005, + 1005, + 1005, + 1004, + 1004, + 1004, + 1003, + 1003, + 1003, + 1002, + 1002, + 1002, + 1002, + 1001, + 1001, + 1001, + 1000, + 1000, + 1000, + 999, + 999, + 999, + 998, + 998, + 998, + 997, + 997, + 997, + 996, + 996, + 996, + 995, + 995, + 995, + 995, + 994, + 994, + 994, + 993, + 993, + 993, + 992, + 992, + 992, + 991, + 991, + 991, + 990, + 990, + 990, + 989, + 989, + 989, + 988, + 988, + 988, + 988, + 987, + 987, + 987, + 986, + 986, + 986, + 985, + 985, + 985, + 984, + 984, + 984, + 983, + 983, + 983, + 982, + 982, + 982, + 981, + 981, + 981, + 980, + 980, + 980, + 980, + 979, + 979, + 979, + 978, + 978, + 978, + 977, + 977, + 977, + 976, + 976, + 976, + 975, + 975, + 975, + 974, + 974, + 974, + 973, + 973, + 973, + 973, + 972, + 972, + 972, + 971, + 971, + 971, + 970, + 970, + 970, + 969, + 969, + 969, + 968, + 968, + 968, + 967, + 967, + 967, + 966, + 966, + 966, + 965, + 965, + 965, + 965, + 964, + 964, + 964, + 963, + 963, + 963, + 962, + 962, + 962, + 961, + 961, + 961, + 960, + 960, + 960, + 959, + 959, + 959, + 958, + 958, + 958, + 957, + 957, + 957, + 957, + 956, + 956, + 956, + 955, + 955, + 955, + 954, + 954, + 954, + 953, + 953, + 953, + 952, + 952, + 952, + 951, + 951, + 951, + 950, + 950, + 950, + 949, + 949, + 949, + 949, + 948, + 948, + 948, + 947, + 947, + 947, + 946, + 946, + 946, + 945, + 945, + 945, + 944, + 944, + 944, + 943, + 943, + 943, + 942, + 942, + 942, + 941, + 941, + 941, + 941, + 940, + 940, + 940, + 939, + 939, + 939, + 938, + 938, + 938, + 937, + 937, + 937, + 936, + 936, + 936, + 935, + 935, + 935, + 934, + 934, + 934, + 933, + 933, + 933, + 932, + 932, + 932, + 932, + 931, + 931, + 931, + 930, + 930, + 930, + 929, + 929, + 929, + 928, + 928, + 928, + 927, + 927, + 927, + 926, + 926, + 926, + 925, + 925, + 925, + 924, + 924, + 924, + 923, + 923, + 923, + 923, + 922, + 922, + 922, + 921, + 921, + 921, + 920, + 920, + 920, + 919, + 919, + 919, + 918, + 918, + 918, + 917, + 917, + 917, + 916, + 916, + 916, + 915, + 915, + 915, + 914, + 914, + 914, + 913, + 913, + 913, + 913, + 912, + 912, + 912, + 911, + 911, + 911, + 910, + 910, + 910, + 909, + 909, + 909, + 908, + 908, + 908, + 907, + 907, + 907, + 906, + 906, + 906, + 905, + 905, + 905, + 904, + 904, + 904, + 903, + 903, + 903, + 902, + 902, + 902, + 902, + 901, + 901, + 901, + 900, + 900, + 900, + 899, + 899, + 899, + 898, + 898, + 898, + 897, + 897, + 897, + 896, + 896, + 896, + 895, + 895, + 895, + 894, + 894, + 894, + 893, + 893, + 893, + 892, + 892, + 892, + 891, + 891, + 891, + 890, + 890, + 890, + 890, + 889, + 889, + 889, + 888, + 888, + 888, + 887, + 887, + 887, + 886, + 886, + 886, + 885, + 885, + 885, + 884, + 884, + 884, + 883, + 883, + 883, + 882, + 882, + 882, + 881, + 881, + 881, + 880, + 880, + 880, + 879, + 879, + 879, + 878, + 878, + 878, + 877, + 877, + 877, + 876, + 876, + 876, + 875, + 875, + 875, + 875, + 874, + 874, + 874, + 873, + 873, + 873, + 872, + 872, + 872, + 871, + 871, + 871, + 870, + 870, + 870, + 869, + 869, + 869, + 868, + 868, + 868, + 867, + 867, + 867, + 866, + 866, + 866, + 865, + 865, + 865, + 864, + 864, + 864, + 863, + 863, + 863, + 862, + 862, + 862, + 861, + 861, + 861, + 860, + 860, + 860, + 859, + 859, + 859, + 858, + 858, + 858, + 857, + 857, + 857, + 856, + 856, + 856, + 855, + 855, + 855, + 855, + 854, + 854, + 854, + 853, + 853, + 853, + 852, + 852, + 852, + 851, + 851, + 851, + 850, + 850, + 850, + 849, + 849, + 849, + 848, + 848, + 848, + 847, + 847, + 847, + 846, + 846, + 846, + 845, + 845, + 845, + 844, + 844, + 844, + 843, + 843, + 843, + 842, + 842, + 842, + 841, + 841, + 841, + 840, + 840, + 840, + 839, + 839, + 839, + 838, + 838, + 838, + 837, + 837, + 837, + 836, + 836, + 836, + 835, + 835, + 835, + 834, + 834, + 834, + 833, + 833, + 833, + 832, + 832, + 832, + 831, + 831, + 831, + 830, + 830, + 830, + 829, + 829, + 829, + 828, + 828, + 828, + 827, + 827, + 827, + 826, + 826, + 826, + 825, + 825, + 825, + 824, + 824, + 824, + 823, + 823, + 823, + 822, + 822, + 822, + 821, + 821, + 821, + 820, + 820, + 820, + 819, + 819, + 819, + 818, + 818, + 818, + 817, + 817, + 817, + 816, + 816, + 816, + 815, + 815, + 815, + 814, + 814, + 814, + 813, + 813, + 813, + 812, + 812, + 812, + 811, + 811, + 811, + 810, + 810, + 810, + 809, + 809, + 809, + 808, + 808, + 808, + 807, + 807, + 807, + 806, + 806, + 806, + 805, + 805, + 805, + 804, + 804, + 804, + 803, + 803, + 803, + 802, + 802, + 802, + 801, + 801, + 800, + 800, + 800, + 799, + 799, + 799, + 798, + 798, + 798, + 797, + 797, + 797, + 796, + 796, + 796, + 795, + 795, + 795, + 794, + 794, + 794, + 793, + 793, + 793, + 792, + 792, + 792, + 791, + 791, + 791, + 790, + 790, + 790, + 789, + 789, + 789, + 788, + 788, + 788, + 787, + 787, + 787, + 786, + 786, + 786, + 785, + 785, + 785, + 784, + 784, + 784, + 783, + 783, + 782, + 782, + 782, + 781, + 781, + 781, + 780, + 780, + 780, + 779, + 779, + 779, + 778, + 778, + 778, + 777, + 777, + 777, + 776, + 776, + 776, + 775, + 775, + 775, + 774, + 774, + 774, + 773, + 773, + 773, + 772, + 772, + 772, + 771, + 771, + 771, + 770, + 770, + 769, + 769, + 769, + 768, + 768, + 768, + 767, + 767, + 767, + 766, + 766, + 766, + 765, + 765, + 765, + 764, + 764, + 764, + 763, + 763, + 763, + 762, + 762, + 762, + 761, + 761, + 761, + 760, + 760, + 759, + 759, + 759, + 758, + 758, + 758, + 757, + 757, + 757, + 756, + 756, + 756, + 755, + 755, + 755, + 754, + 754, + 754, + 753, + 753, + 753, + 752, + 752, + 751, + 751, + 751, + 750, + 750, + 750, + 749, + 749, + 749, + 748, + 748, + 748, + 747, + 747, + 747, + 746, + 746, + 746, + 745, + 745, + 744, + 744, + 744, + 743, + 743, + 743, + 742, + 742, + 742, + 741, + 741, + 741, + 740, + 740, + 740, + 739, + 739, + 739, + 738, + 738, + 737, + 737, + 737, + 736, + 736, + 736, + 735, + 735, + 735, + 734, + 734, + 734, + 733, + 733, + 733, + 732, + 732, + 731, + 731, + 731, + 730, + 730, + 730, + 729, + 729, + 729, + 728, + 728, + 728, + 727, + 727, + 727, + 726, + 726, + 725, + 725, + 725, + 724, + 724, + 724, + 723, + 723, + 723, + 722, + 722, + 722, + 721, + 721, + 720, + 720, + 720, + 719, + 719, + 719, + 718, + 718, + 718, + 717, + 717, + 717, + 716, + 716, + 716, + 715, + 715, + 714, + 714, + 714, + 713, + 713, + 713, + 712, + 712, + 712, + 711, + 711, + 710, + 710, + 710, + 709, + 709, + 709, + 708, + 708, + 708, + 707, + 707, + 707, + 706, + 706, + 705, + 705, + 705, + 704, + 704, + 704, + 703, + 703, + 703, + 702, + 702, + 701, + 701, + 701, + 700, + 700, + 700, + 699, + 699, + 699, + 698, + 698, + 698, + 697, + 697, + 696, + 696, + 696, + 695, + 695, + 695, + 694, + 694, + 694, + 693, + 693, + 692, + 692, + 692, + 691, + 691, + 691, + 690, + 690, + 689, + 689, + 689, + 688, + 688, + 688, + 687, + 687, + 687, + 686, + 686, + 685, + 685, + 685, + 684, + 684, + 684, + 683, + 683, + 683, + 682, + 682, + 681, + 681, + 681, + 680, + 680, + 680, + 679, + 679, + 678, + 678, + 678, + 677, + 677, + 677, + 676, + 676, + 676, + 675, + 675, + 674, + 674, + 674, + 673, + 673, + 673, + 672, + 672, + 671, + 671, + 671, + 670, + 670, + 670, + 669, + 669, + 668, + 668, + 668, + 667, + 667, + 667, + 666, + 666, + 666, + 665, + 665, + 664, + 664, + 664, + 663, + 663, + 663, + 662, + 662, + 661, + 661, + 661, + 660, + 660, + 660, + 659, + 659, + 658, + 658, + 658, + 657, + 657, + 657, + 656, + 656, + 655, + 655, + 655, + 654, + 654, + 653, + 653, + 653, + 652, + 652, + 652, + 651, + 651, + 650, + 650, + 650, + 649, + 649, + 649, + 648, + 648, + 647, + 647, + 647, + 646, + 646, + 646, + 645, + 645, + 644, + 644, + 644, + 643, + 643, + 642, + 642, + 642, + 641, + 641, + 641, + 640, + 640, + 639, + 639, + 639, + 638, + 638, + 638, + 637, + 637, + 636, + 636, + 636, + 635, + 635, + 634, + 634, + 634, + 633, + 633, + 633, + 632, + 632, + 631, + 631, + 631, + 630, + 630, + 629, + 629, + 629, + 628, + 628, + 627, + 627, + 627, + 626, + 626, + 626, + 625, + 625, + 624, + 624, + 624, + 623, + 623, + 622, + 622, + 622, + 621, + 621, + 620, + 620, + 620, + 619, + 619, + 619, + 618, + 618, + 617, + 617, + 617, + 616, + 616, + 615, + 615, + 615, + 614, + 614, + 613, + 613, + 613, + 612, + 612, + 611, + 611, + 611, + 610, + 610, + 609, + 609, + 609, + 608, + 608, + 607, + 607, + 607, + 606, + 606, + 606, + 605, + 605, + 604, + 604, + 604, + 603, + 603, + 602, + 602, + 602, + 601, + 601, + 600, + 600, + 600, + 599, + 599, + 598, + 598, + 598, + 597, + 597, + 596, + 596, + 596, + 595, + 595, + 594, + 594, + 594, + 593, + 593, + 592, + 592, + 591, + 591, + 591, + 590, + 590, + 589, + 589, + 589, + 588, + 588, + 587, + 587, + 587, + 586, + 586, + 585, + 585, + 585, + 584, + 584, + 583, + 583, + 583, + 582, + 582, + 581, + 581, + 581, + 580, + 580, + 579, + 579, + 578, + 578, + 578, + 577, + 577, + 576, + 576, + 576, + 575, + 575, + 574, + 574, + 574, + 573, + 573, + 572, + 572, + 571, + 571, + 571, + 570, + 570, + 569, + 569, + 569, + 568, + 568, + 567, + 567, + 566, + 566, + 566, + 565, + 565, + 564, + 564, + 564, + 563, + 563, + 562, + 562, + 561, + 561, + 561, + 560, + 560, + 559, + 559, + 559, + 558, + 558, + 557, + 557, + 556, + 556, + 556, + 555, + 555, + 554, + 554, + 553, + 553, + 553, + 552, + 552, + 551, + 551, + 550, + 550, + 550, + 549, + 549, + 548, + 548, + 548, + 547, + 547, + 546, + 546, + 545, + 545, + 545, + 544, + 544, + 543, + 543, + 542, + 542, + 542, + 541, + 541, + 540, + 540, + 539, + 539, + 538, + 538, + 538, + 537, + 537, + 536, + 536, + 535, + 535, + 535, + 534, + 534, + 533, + 533, + 532, + 532, + 532, + 531, + 531, + 530, + 530, + 529, + 529, + 528, + 528, + 528, + 527, + 527, + 526, + 526, + 525, + 525, + 524, + 524, + 524, + 523, + 523, + 522, + 522, + 521, + 521, + 521, + 520, + 520, + 519, + 519, + 518, + 518, + 517, + 517, + 517, + 516, + 516, + 515, + 515, + 514, + 514, + 513, + 513, + 512, + 512, + 512, + 511, + 511, + 510, + 510, + 509, + 509, + 508, + 508, + 508, + 507, + 507, + 506, + 506, + 505, + 505, + 504, + 504, + 503, + 503, + 503, + 502, + 502, + 501, + 501, + 500, + 500, + 499, + 499, + 498, + 498, + 497, + 497, + 497, + 496, + 496, + 495, + 495, + 494, + 494, + 493, + 493, + 492, + 492, + 491, + 491, + 491, + 490, + 490, + 489, + 489, + 488, + 488, + 487, + 487, + 486, + 486, + 485, + 485, + 484, + 484, + 484, + 483, + 483, + 482, + 482, + 481, + 481, + 480, + 480, + 479, + 479, + 478, + 478, + 477, + 477, + 476, + 476, + 475, + 475, + 474, + 474, + 474, + 473, + 473, + 472, + 472, + 471, + 471, + 470, + 470, + 469, + 469, + 468, + 468, + 467, + 467, + 466, + 466, + 465, + 465, + 464, + 464, + 463, + 463, + 462, + 462, + 461, + 461, + 460, + 460, + 459, + 459, + 458, + 458, + 458, + 457, + 457, + 456, + 456, + 455, + 455, + 454, + 454, + 453, + 453, + 452, + 452, + 451, + 451, + 450, + 450, + 449, + 449, + 448, + 448, + 447, + 447, + 446, + 446, + 445, + 445, + 444, + 444, + 443, + 443, + 442, + 442, + 441, + 440, + 440, + 439, + 439, + 438, + 438, + 437, + 437, + 436, + 436, + 435, + 435, + 434, + 434, + 433, + 433, + 432, + 432, + 431, + 431, + 430, + 430, + 429, + 429, + 428, + 428, + 427, + 427, + 426, + 426, + 425, + 424, + 424, + 423, + 423, + 422, + 422, + 421, + 421, + 420, + 420, + 419, + 419, + 418, + 418, + 417, + 417, + 416, + 415, + 415, + 414, + 414, + 413, + 413, + 412, + 412, + 411, + 411, + 410, + 410, + 409, + 408, + 408, + 407, + 407, + 406, + 406, + 405, + 405, + 404, + 404, + 403, + 402, + 402, + 401, + 401, + 400, + 400, + 399, + 399, + 398, + 398, + 397, + 396, + 396, + 395, + 395, + 394, + 394, + 393, + 392, + 392, + 391, + 391, + 390, + 390, + 389, + 389, + 388, + 387, + 387, + 386, + 386, + 385, + 385, + 384, + 383, + 383, + 382, + 382, + 381, + 381, + 380, + 379, + 379, + 378, + 378, + 377, + 376, + 376, + 375, + 375, + 374, + 374, + 373, + 372, + 372, + 371, + 371, + 370, + 369, + 369, + 368, + 368, + 367, + 366, + 366, + 365, + 365, + 364, + 363, + 363, + 362, + 362, + 361, + 360, + 360, + 359, + 359, + 358, + 357, + 357, + 356, + 356, + 355, + 354, + 354, + 353, + 353, + 352, + 351, + 351, + 350, + 349, + 349, + 348, + 348, + 347, + 346, + 346, + 345, + 344, + 344, + 343, + 342, + 342, + 341, + 341, + 340, + 339, + 339, + 338, + 337, + 337, + 336, + 335, + 335, + 334, + 334, + 333, + 332, + 332, + 331, + 330, + 330, + 329, + 328, + 328, + 327, + 326, + 326, + 325, + 324, + 324, + 323, + 322, + 322, + 321, + 320, + 320, + 319, + 318, + 318, + 317, + 316, + 316, + 315, + 314, + 313, + 313, + 312, + 311, + 311, + 310, + 309, + 309, + 308, + 307, + 307, + 306, + 305, + 304, + 304, + 303, + 302, + 302, + 301, + 300, + 299, + 299, + 298, + 297, + 297, + 296, + 295, + 294, + 294, + 293, + 292, + 291, + 291, + 290, + 289, + 289, + 288, + 287, + 286, + 286, + 285, + 284, + 283, + 283, + 282, + 281, + 280, + 279, + 279, + 278, + 277, + 276, + 276, + 275, + 274, + 273, + 273, + 272, + 271, + 270, + 269, + 269, + 268, + 267, + 266, + 265, + 265, + 264, + 263, + 262, + 261, + 261, + 260, + 259, + 258, + 257, + 256, + 256, + 255, + 254, + 253, + 252, + 251, + 251, + 250, + 249, + 248, + 247, + 246, + 245, + 245, + 244, + 243, + 242, + 241, + 240, + 239, + 238, + 238, + 237, + 236, + 235, + 234, + 233, + 232, + 231, + 230, + 229, + 228, + 228, + 227, + 226, + 225, + 224, + 223, + 222, + 221, + 220, + 219, + 218, + 217, + 216, + 215, + 214, + 213, + 212, + 211, + 210, + 209, + 208, + 207, + 206, + 205, + 204, + 203, + 202, + 201, + 200, + 199, + 198, + 197, + 196, + 195, + 193, + 192, + 191, + 190, + 189, + 188, + 187, + 186, + 185, + 183, + 182, + 181, + 180, + 179, + 178, + 176, + 175, + 174, + 173, + 172, + 170, + 169, + 168, + 167, + 165, + 164, + 163, + 162, + 160, + 159, + 158, + 156, + 155, + 154, + 152, + 151, + 150, + 148, + 147, + 145, + 144, + 142, + 141, + 139, + 138, + 136, + 135, + 133, + 132, + 130, + 129, + 127, + 125, + 124, + 122, + 120, + 118, + 117, + 115, + 113, + 111, + 109, + 107, + 105, + 103, + 101, + 99, + 97, + 95, + 93, + 91, + 88, + 86, + 84, + 81, + 78, + 76, + 73, + 70, + 67, + 64, + 61, + 57, + 53, + 49, + 45, + 40, + 35, + 28, + 0 + +}; + +short ArcSineTable[]={ + + -1023, + -1004, + -996, + -989, + -984, + -979, + -975, + -971, + -967, + -963, + -960, + -957, + -954, + -951, + -948, + -946, + -943, + -940, + -938, + -936, + -933, + -931, + -929, + -927, + -925, + -923, + -921, + -919, + -917, + -915, + -913, + -911, + -909, + -907, + -906, + -904, + -902, + -900, + -899, + -897, + -895, + -894, + -892, + -891, + -889, + -888, + -886, + -885, + -883, + -882, + -880, + -879, + -877, + -876, + -874, + -873, + -872, + -870, + -869, + -868, + -866, + -865, + -864, + -862, + -861, + -860, + -859, + -857, + -856, + -855, + -854, + -852, + -851, + -850, + -849, + -848, + -846, + -845, + -844, + -843, + -842, + -841, + -839, + -838, + -837, + -836, + -835, + -834, + -833, + -832, + -831, + -829, + -828, + -827, + -826, + -825, + -824, + -823, + -822, + -821, + -820, + -819, + -818, + -817, + -816, + -815, + -814, + -813, + -812, + -811, + -810, + -809, + -808, + -807, + -806, + -805, + -804, + -803, + -802, + -801, + -800, + -799, + -798, + -797, + -796, + -796, + -795, + -794, + -793, + -792, + -791, + -790, + -789, + -788, + -787, + -786, + -786, + -785, + -784, + -783, + -782, + -781, + -780, + -779, + -779, + -778, + -777, + -776, + -775, + -774, + -773, + -773, + -772, + -771, + -770, + -769, + -768, + -768, + -767, + -766, + -765, + -764, + -763, + -763, + -762, + -761, + -760, + -759, + -759, + -758, + -757, + -756, + -755, + -755, + -754, + -753, + -752, + -751, + -751, + -750, + -749, + -748, + -748, + -747, + -746, + -745, + -745, + -744, + -743, + -742, + -741, + -741, + -740, + -739, + -738, + -738, + -737, + -736, + -735, + -735, + -734, + -733, + -733, + -732, + -731, + -730, + -730, + -729, + -728, + -727, + -727, + -726, + -725, + -725, + -724, + -723, + -722, + -722, + -721, + -720, + -720, + -719, + -718, + -717, + -717, + -716, + -715, + -715, + -714, + -713, + -713, + -712, + -711, + -711, + -710, + -709, + -708, + -708, + -707, + -706, + -706, + -705, + -704, + -704, + -703, + -702, + -702, + -701, + -700, + -700, + -699, + -698, + -698, + -697, + -696, + -696, + -695, + -694, + -694, + -693, + -692, + -692, + -691, + -690, + -690, + -689, + -689, + -688, + -687, + -687, + -686, + -685, + -685, + -684, + -683, + -683, + -682, + -682, + -681, + -680, + -680, + -679, + -678, + -678, + -677, + -676, + -676, + -675, + -675, + -674, + -673, + -673, + -672, + -671, + -671, + -670, + -670, + -669, + -668, + -668, + -667, + -667, + -666, + -665, + -665, + -664, + -664, + -663, + -662, + -662, + -661, + -661, + -660, + -659, + -659, + -658, + -658, + -657, + -656, + -656, + -655, + -655, + -654, + -653, + -653, + -652, + -652, + -651, + -650, + -650, + -649, + -649, + -648, + -648, + -647, + -646, + -646, + -645, + -645, + -644, + -643, + -643, + -642, + -642, + -641, + -641, + -640, + -639, + -639, + -638, + -638, + -637, + -637, + -636, + -635, + -635, + -634, + -634, + -633, + -633, + -632, + -632, + -631, + -630, + -630, + -629, + -629, + -628, + -628, + -627, + -626, + -626, + -625, + -625, + -624, + -624, + -623, + -623, + -622, + -622, + -621, + -620, + -620, + -619, + -619, + -618, + -618, + -617, + -617, + -616, + -616, + -615, + -614, + -614, + -613, + -613, + -612, + -612, + -611, + -611, + -610, + -610, + -609, + -609, + -608, + -607, + -607, + -606, + -606, + -605, + -605, + -604, + -604, + -603, + -603, + -602, + -602, + -601, + -601, + -600, + -600, + -599, + -598, + -598, + -597, + -597, + -596, + -596, + -595, + -595, + -594, + -594, + -593, + -593, + -592, + -592, + -591, + -591, + -590, + -590, + -589, + -589, + -588, + -588, + -587, + -587, + -586, + -586, + -585, + -585, + -584, + -584, + -583, + -582, + -582, + -581, + -581, + -580, + -580, + -579, + -579, + -578, + -578, + -577, + -577, + -576, + -576, + -575, + -575, + -574, + -574, + -573, + -573, + -572, + -572, + -571, + -571, + -570, + -570, + -569, + -569, + -568, + -568, + -567, + -567, + -566, + -566, + -566, + -565, + -565, + -564, + -564, + -563, + -563, + -562, + -562, + -561, + -561, + -560, + -560, + -559, + -559, + -558, + -558, + -557, + -557, + -556, + -556, + -555, + -555, + -554, + -554, + -553, + -553, + -552, + -552, + -551, + -551, + -550, + -550, + -550, + -549, + -549, + -548, + -548, + -547, + -547, + -546, + -546, + -545, + -545, + -544, + -544, + -543, + -543, + -542, + -542, + -541, + -541, + -540, + -540, + -540, + -539, + -539, + -538, + -538, + -537, + -537, + -536, + -536, + -535, + -535, + -534, + -534, + -533, + -533, + -533, + -532, + -532, + -531, + -531, + -530, + -530, + -529, + -529, + -528, + -528, + -527, + -527, + -527, + -526, + -526, + -525, + -525, + -524, + -524, + -523, + -523, + -522, + -522, + -521, + -521, + -521, + -520, + -520, + -519, + -519, + -518, + -518, + -517, + -517, + -516, + -516, + -516, + -515, + -515, + -514, + -514, + -513, + -513, + -512, + -512, + -512, + -511, + -511, + -510, + -510, + -509, + -509, + -508, + -508, + -507, + -507, + -507, + -506, + -506, + -505, + -505, + -504, + -504, + -503, + -503, + -503, + -502, + -502, + -501, + -501, + -500, + -500, + -500, + -499, + -499, + -498, + -498, + -497, + -497, + -496, + -496, + -496, + -495, + -495, + -494, + -494, + -493, + -493, + -492, + -492, + -492, + -491, + -491, + -490, + -490, + -489, + -489, + -489, + -488, + -488, + -487, + -487, + -486, + -486, + -486, + -485, + -485, + -484, + -484, + -483, + -483, + -482, + -482, + -482, + -481, + -481, + -480, + -480, + -479, + -479, + -479, + -478, + -478, + -477, + -477, + -476, + -476, + -476, + -475, + -475, + -474, + -474, + -474, + -473, + -473, + -472, + -472, + -471, + -471, + -471, + -470, + -470, + -469, + -469, + -468, + -468, + -468, + -467, + -467, + -466, + -466, + -465, + -465, + -465, + -464, + -464, + -463, + -463, + -463, + -462, + -462, + -461, + -461, + -460, + -460, + -460, + -459, + -459, + -458, + -458, + -458, + -457, + -457, + -456, + -456, + -455, + -455, + -455, + -454, + -454, + -453, + -453, + -453, + -452, + -452, + -451, + -451, + -450, + -450, + -450, + -449, + -449, + -448, + -448, + -448, + -447, + -447, + -446, + -446, + -446, + -445, + -445, + -444, + -444, + -443, + -443, + -443, + -442, + -442, + -441, + -441, + -441, + -440, + -440, + -439, + -439, + -439, + -438, + -438, + -437, + -437, + -437, + -436, + -436, + -435, + -435, + -435, + -434, + -434, + -433, + -433, + -433, + -432, + -432, + -431, + -431, + -430, + -430, + -430, + -429, + -429, + -428, + -428, + -428, + -427, + -427, + -426, + -426, + -426, + -425, + -425, + -424, + -424, + -424, + -423, + -423, + -422, + -422, + -422, + -421, + -421, + -420, + -420, + -420, + -419, + -419, + -418, + -418, + -418, + -417, + -417, + -417, + -416, + -416, + -415, + -415, + -415, + -414, + -414, + -413, + -413, + -413, + -412, + -412, + -411, + -411, + -411, + -410, + -410, + -409, + -409, + -409, + -408, + -408, + -407, + -407, + -407, + -406, + -406, + -405, + -405, + -405, + -404, + -404, + -404, + -403, + -403, + -402, + -402, + -402, + -401, + -401, + -400, + -400, + -400, + -399, + -399, + -398, + -398, + -398, + -397, + -397, + -397, + -396, + -396, + -395, + -395, + -395, + -394, + -394, + -393, + -393, + -393, + -392, + -392, + -391, + -391, + -391, + -390, + -390, + -390, + -389, + -389, + -388, + -388, + -388, + -387, + -387, + -386, + -386, + -386, + -385, + -385, + -385, + -384, + -384, + -383, + -383, + -383, + -382, + -382, + -382, + -381, + -381, + -380, + -380, + -380, + -379, + -379, + -378, + -378, + -378, + -377, + -377, + -377, + -376, + -376, + -375, + -375, + -375, + -374, + -374, + -374, + -373, + -373, + -372, + -372, + -372, + -371, + -371, + -371, + -370, + -370, + -369, + -369, + -369, + -368, + -368, + -367, + -367, + -367, + -366, + -366, + -366, + -365, + -365, + -364, + -364, + -364, + -363, + -363, + -363, + -362, + -362, + -361, + -361, + -361, + -360, + -360, + -360, + -359, + -359, + -358, + -358, + -358, + -357, + -357, + -357, + -356, + -356, + -356, + -355, + -355, + -354, + -354, + -354, + -353, + -353, + -353, + -352, + -352, + -351, + -351, + -351, + -350, + -350, + -350, + -349, + -349, + -348, + -348, + -348, + -347, + -347, + -347, + -346, + -346, + -346, + -345, + -345, + -344, + -344, + -344, + -343, + -343, + -343, + -342, + -342, + -341, + -341, + -341, + -340, + -340, + -340, + -339, + -339, + -339, + -338, + -338, + -337, + -337, + -337, + -336, + -336, + -336, + -335, + -335, + -335, + -334, + -334, + -333, + -333, + -333, + -332, + -332, + -332, + -331, + -331, + -330, + -330, + -330, + -329, + -329, + -329, + -328, + -328, + -328, + -327, + -327, + -326, + -326, + -326, + -325, + -325, + -325, + -324, + -324, + -324, + -323, + -323, + -323, + -322, + -322, + -321, + -321, + -321, + -320, + -320, + -320, + -319, + -319, + -319, + -318, + -318, + -317, + -317, + -317, + -316, + -316, + -316, + -315, + -315, + -315, + -314, + -314, + -314, + -313, + -313, + -312, + -312, + -312, + -311, + -311, + -311, + -310, + -310, + -310, + -309, + -309, + -308, + -308, + -308, + -307, + -307, + -307, + -306, + -306, + -306, + -305, + -305, + -305, + -304, + -304, + -304, + -303, + -303, + -302, + -302, + -302, + -301, + -301, + -301, + -300, + -300, + -300, + -299, + -299, + -299, + -298, + -298, + -297, + -297, + -297, + -296, + -296, + -296, + -295, + -295, + -295, + -294, + -294, + -294, + -293, + -293, + -293, + -292, + -292, + -291, + -291, + -291, + -290, + -290, + -290, + -289, + -289, + -289, + -288, + -288, + -288, + -287, + -287, + -287, + -286, + -286, + -285, + -285, + -285, + -284, + -284, + -284, + -283, + -283, + -283, + -282, + -282, + -282, + -281, + -281, + -281, + -280, + -280, + -280, + -279, + -279, + -278, + -278, + -278, + -277, + -277, + -277, + -276, + -276, + -276, + -275, + -275, + -275, + -274, + -274, + -274, + -273, + -273, + -273, + -272, + -272, + -271, + -271, + -271, + -270, + -270, + -270, + -269, + -269, + -269, + -268, + -268, + -268, + -267, + -267, + -267, + -266, + -266, + -266, + -265, + -265, + -265, + -264, + -264, + -263, + -263, + -263, + -262, + -262, + -262, + -261, + -261, + -261, + -260, + -260, + -260, + -259, + -259, + -259, + -258, + -258, + -258, + -257, + -257, + -257, + -256, + -256, + -256, + -255, + -255, + -255, + -254, + -254, + -253, + -253, + -253, + -252, + -252, + -252, + -251, + -251, + -251, + -250, + -250, + -250, + -249, + -249, + -249, + -248, + -248, + -248, + -247, + -247, + -247, + -246, + -246, + -246, + -245, + -245, + -245, + -244, + -244, + -244, + -243, + -243, + -243, + -242, + -242, + -242, + -241, + -241, + -240, + -240, + -240, + -239, + -239, + -239, + -238, + -238, + -238, + -237, + -237, + -237, + -236, + -236, + -236, + -235, + -235, + -235, + -234, + -234, + -234, + -233, + -233, + -233, + -232, + -232, + -232, + -231, + -231, + -231, + -230, + -230, + -230, + -229, + -229, + -229, + -228, + -228, + -228, + -227, + -227, + -227, + -226, + -226, + -226, + -225, + -225, + -225, + -224, + -224, + -224, + -223, + -223, + -222, + -222, + -222, + -221, + -221, + -221, + -220, + -220, + -220, + -219, + -219, + -219, + -218, + -218, + -218, + -217, + -217, + -217, + -216, + -216, + -216, + -215, + -215, + -215, + -214, + -214, + -214, + -213, + -213, + -213, + -212, + -212, + -212, + -211, + -211, + -211, + -210, + -210, + -210, + -209, + -209, + -209, + -208, + -208, + -208, + -207, + -207, + -207, + -206, + -206, + -206, + -205, + -205, + -205, + -204, + -204, + -204, + -203, + -203, + -203, + -202, + -202, + -202, + -201, + -201, + -201, + -200, + -200, + -200, + -199, + -199, + -199, + -198, + -198, + -198, + -197, + -197, + -197, + -196, + -196, + -196, + -195, + -195, + -195, + -194, + -194, + -194, + -193, + -193, + -193, + -192, + -192, + -192, + -191, + -191, + -191, + -190, + -190, + -190, + -189, + -189, + -189, + -188, + -188, + -188, + -187, + -187, + -187, + -186, + -186, + -186, + -185, + -185, + -185, + -184, + -184, + -184, + -183, + -183, + -183, + -182, + -182, + -182, + -181, + -181, + -181, + -180, + -180, + -180, + -179, + -179, + -179, + -178, + -178, + -178, + -177, + -177, + -177, + -176, + -176, + -176, + -175, + -175, + -175, + -174, + -174, + -174, + -173, + -173, + -173, + -172, + -172, + -172, + -171, + -171, + -171, + -170, + -170, + -170, + -169, + -169, + -169, + -169, + -168, + -168, + -168, + -167, + -167, + -167, + -166, + -166, + -166, + -165, + -165, + -165, + -164, + -164, + -164, + -163, + -163, + -163, + -162, + -162, + -162, + -161, + -161, + -161, + -160, + -160, + -160, + -159, + -159, + -159, + -158, + -158, + -158, + -157, + -157, + -157, + -156, + -156, + -156, + -155, + -155, + -155, + -154, + -154, + -154, + -153, + -153, + -153, + -152, + -152, + -152, + -151, + -151, + -151, + -150, + -150, + -150, + -149, + -149, + -149, + -149, + -148, + -148, + -148, + -147, + -147, + -147, + -146, + -146, + -146, + -145, + -145, + -145, + -144, + -144, + -144, + -143, + -143, + -143, + -142, + -142, + -142, + -141, + -141, + -141, + -140, + -140, + -140, + -139, + -139, + -139, + -138, + -138, + -138, + -137, + -137, + -137, + -136, + -136, + -136, + -135, + -135, + -135, + -134, + -134, + -134, + -134, + -133, + -133, + -133, + -132, + -132, + -132, + -131, + -131, + -131, + -130, + -130, + -130, + -129, + -129, + -129, + -128, + -128, + -128, + -127, + -127, + -127, + -126, + -126, + -126, + -125, + -125, + -125, + -124, + -124, + -124, + -123, + -123, + -123, + -122, + -122, + -122, + -122, + -121, + -121, + -121, + -120, + -120, + -120, + -119, + -119, + -119, + -118, + -118, + -118, + -117, + -117, + -117, + -116, + -116, + -116, + -115, + -115, + -115, + -114, + -114, + -114, + -113, + -113, + -113, + -112, + -112, + -112, + -111, + -111, + -111, + -111, + -110, + -110, + -110, + -109, + -109, + -109, + -108, + -108, + -108, + -107, + -107, + -107, + -106, + -106, + -106, + -105, + -105, + -105, + -104, + -104, + -104, + -103, + -103, + -103, + -102, + -102, + -102, + -101, + -101, + -101, + -101, + -100, + -100, + -100, + -99, + -99, + -99, + -98, + -98, + -98, + -97, + -97, + -97, + -96, + -96, + -96, + -95, + -95, + -95, + -94, + -94, + -94, + -93, + -93, + -93, + -92, + -92, + -92, + -92, + -91, + -91, + -91, + -90, + -90, + -90, + -89, + -89, + -89, + -88, + -88, + -88, + -87, + -87, + -87, + -86, + -86, + -86, + -85, + -85, + -85, + -84, + -84, + -84, + -83, + -83, + -83, + -83, + -82, + -82, + -82, + -81, + -81, + -81, + -80, + -80, + -80, + -79, + -79, + -79, + -78, + -78, + -78, + -77, + -77, + -77, + -76, + -76, + -76, + -75, + -75, + -75, + -75, + -74, + -74, + -74, + -73, + -73, + -73, + -72, + -72, + -72, + -71, + -71, + -71, + -70, + -70, + -70, + -69, + -69, + -69, + -68, + -68, + -68, + -67, + -67, + -67, + -67, + -66, + -66, + -66, + -65, + -65, + -65, + -64, + -64, + -64, + -63, + -63, + -63, + -62, + -62, + -62, + -61, + -61, + -61, + -60, + -60, + -60, + -59, + -59, + -59, + -59, + -58, + -58, + -58, + -57, + -57, + -57, + -56, + -56, + -56, + -55, + -55, + -55, + -54, + -54, + -54, + -53, + -53, + -53, + -52, + -52, + -52, + -51, + -51, + -51, + -51, + -50, + -50, + -50, + -49, + -49, + -49, + -48, + -48, + -48, + -47, + -47, + -47, + -46, + -46, + -46, + -45, + -45, + -45, + -44, + -44, + -44, + -44, + -43, + -43, + -43, + -42, + -42, + -42, + -41, + -41, + -41, + -40, + -40, + -40, + -39, + -39, + -39, + -38, + -38, + -38, + -37, + -37, + -37, + -36, + -36, + -36, + -36, + -35, + -35, + -35, + -34, + -34, + -34, + -33, + -33, + -33, + -32, + -32, + -32, + -31, + -31, + -31, + -30, + -30, + -30, + -29, + -29, + -29, + -29, + -28, + -28, + -28, + -27, + -27, + -27, + -26, + -26, + -26, + -25, + -25, + -25, + -24, + -24, + -24, + -23, + -23, + -23, + -22, + -22, + -22, + -22, + -21, + -21, + -21, + -20, + -20, + -20, + -19, + -19, + -19, + -18, + -18, + -18, + -17, + -17, + -17, + -16, + -16, + -16, + -15, + -15, + -15, + -15, + -14, + -14, + -14, + -13, + -13, + -13, + -12, + -12, + -12, + -11, + -11, + -11, + -10, + -10, + -10, + -9, + -9, + -9, + -8, + -8, + -8, + -8, + -7, + -7, + -7, + -6, + -6, + -6, + -5, + -5, + -5, + -4, + -4, + -4, + -3, + -3, + -3, + -2, + -2, + -2, + -1, + -1, + -1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 2, + 2, + 2, + 3, + 3, + 3, + 4, + 4, + 4, + 5, + 5, + 5, + 6, + 6, + 6, + 7, + 7, + 7, + 7, + 8, + 8, + 8, + 9, + 9, + 9, + 10, + 10, + 10, + 11, + 11, + 11, + 12, + 12, + 12, + 13, + 13, + 13, + 14, + 14, + 14, + 14, + 15, + 15, + 15, + 16, + 16, + 16, + 17, + 17, + 17, + 18, + 18, + 18, + 19, + 19, + 19, + 20, + 20, + 20, + 21, + 21, + 21, + 21, + 22, + 22, + 22, + 23, + 23, + 23, + 24, + 24, + 24, + 25, + 25, + 25, + 26, + 26, + 26, + 27, + 27, + 27, + 28, + 28, + 28, + 28, + 29, + 29, + 29, + 30, + 30, + 30, + 31, + 31, + 31, + 32, + 32, + 32, + 33, + 33, + 33, + 34, + 34, + 34, + 35, + 35, + 35, + 35, + 36, + 36, + 36, + 37, + 37, + 37, + 38, + 38, + 38, + 39, + 39, + 39, + 40, + 40, + 40, + 41, + 41, + 41, + 42, + 42, + 42, + 43, + 43, + 43, + 43, + 44, + 44, + 44, + 45, + 45, + 45, + 46, + 46, + 46, + 47, + 47, + 47, + 48, + 48, + 48, + 49, + 49, + 49, + 50, + 50, + 50, + 50, + 51, + 51, + 51, + 52, + 52, + 52, + 53, + 53, + 53, + 54, + 54, + 54, + 55, + 55, + 55, + 56, + 56, + 56, + 57, + 57, + 57, + 58, + 58, + 58, + 58, + 59, + 59, + 59, + 60, + 60, + 60, + 61, + 61, + 61, + 62, + 62, + 62, + 63, + 63, + 63, + 64, + 64, + 64, + 65, + 65, + 65, + 66, + 66, + 66, + 66, + 67, + 67, + 67, + 68, + 68, + 68, + 69, + 69, + 69, + 70, + 70, + 70, + 71, + 71, + 71, + 72, + 72, + 72, + 73, + 73, + 73, + 74, + 74, + 74, + 74, + 75, + 75, + 75, + 76, + 76, + 76, + 77, + 77, + 77, + 78, + 78, + 78, + 79, + 79, + 79, + 80, + 80, + 80, + 81, + 81, + 81, + 82, + 82, + 82, + 82, + 83, + 83, + 83, + 84, + 84, + 84, + 85, + 85, + 85, + 86, + 86, + 86, + 87, + 87, + 87, + 88, + 88, + 88, + 89, + 89, + 89, + 90, + 90, + 90, + 91, + 91, + 91, + 91, + 92, + 92, + 92, + 93, + 93, + 93, + 94, + 94, + 94, + 95, + 95, + 95, + 96, + 96, + 96, + 97, + 97, + 97, + 98, + 98, + 98, + 99, + 99, + 99, + 100, + 100, + 100, + 100, + 101, + 101, + 101, + 102, + 102, + 102, + 103, + 103, + 103, + 104, + 104, + 104, + 105, + 105, + 105, + 106, + 106, + 106, + 107, + 107, + 107, + 108, + 108, + 108, + 109, + 109, + 109, + 110, + 110, + 110, + 110, + 111, + 111, + 111, + 112, + 112, + 112, + 113, + 113, + 113, + 114, + 114, + 114, + 115, + 115, + 115, + 116, + 116, + 116, + 117, + 117, + 117, + 118, + 118, + 118, + 119, + 119, + 119, + 120, + 120, + 120, + 121, + 121, + 121, + 121, + 122, + 122, + 122, + 123, + 123, + 123, + 124, + 124, + 124, + 125, + 125, + 125, + 126, + 126, + 126, + 127, + 127, + 127, + 128, + 128, + 128, + 129, + 129, + 129, + 130, + 130, + 130, + 131, + 131, + 131, + 132, + 132, + 132, + 133, + 133, + 133, + 133, + 134, + 134, + 134, + 135, + 135, + 135, + 136, + 136, + 136, + 137, + 137, + 137, + 138, + 138, + 138, + 139, + 139, + 139, + 140, + 140, + 140, + 141, + 141, + 141, + 142, + 142, + 142, + 143, + 143, + 143, + 144, + 144, + 144, + 145, + 145, + 145, + 146, + 146, + 146, + 147, + 147, + 147, + 148, + 148, + 148, + 148, + 149, + 149, + 149, + 150, + 150, + 150, + 151, + 151, + 151, + 152, + 152, + 152, + 153, + 153, + 153, + 154, + 154, + 154, + 155, + 155, + 155, + 156, + 156, + 156, + 157, + 157, + 157, + 158, + 158, + 158, + 159, + 159, + 159, + 160, + 160, + 160, + 161, + 161, + 161, + 162, + 162, + 162, + 163, + 163, + 163, + 164, + 164, + 164, + 165, + 165, + 165, + 166, + 166, + 166, + 167, + 167, + 167, + 168, + 168, + 168, + 168, + 169, + 169, + 169, + 170, + 170, + 170, + 171, + 171, + 171, + 172, + 172, + 172, + 173, + 173, + 173, + 174, + 174, + 174, + 175, + 175, + 175, + 176, + 176, + 176, + 177, + 177, + 177, + 178, + 178, + 178, + 179, + 179, + 179, + 180, + 180, + 180, + 181, + 181, + 181, + 182, + 182, + 182, + 183, + 183, + 183, + 184, + 184, + 184, + 185, + 185, + 185, + 186, + 186, + 186, + 187, + 187, + 187, + 188, + 188, + 188, + 189, + 189, + 189, + 190, + 190, + 190, + 191, + 191, + 191, + 192, + 192, + 192, + 193, + 193, + 193, + 194, + 194, + 194, + 195, + 195, + 195, + 196, + 196, + 196, + 197, + 197, + 197, + 198, + 198, + 198, + 199, + 199, + 199, + 200, + 200, + 200, + 201, + 201, + 201, + 202, + 202, + 202, + 203, + 203, + 203, + 204, + 204, + 204, + 205, + 205, + 205, + 206, + 206, + 206, + 207, + 207, + 207, + 208, + 208, + 208, + 209, + 209, + 209, + 210, + 210, + 210, + 211, + 211, + 211, + 212, + 212, + 212, + 213, + 213, + 213, + 214, + 214, + 214, + 215, + 215, + 215, + 216, + 216, + 216, + 217, + 217, + 217, + 218, + 218, + 218, + 219, + 219, + 219, + 220, + 220, + 220, + 221, + 221, + 221, + 222, + 222, + 223, + 223, + 223, + 224, + 224, + 224, + 225, + 225, + 225, + 226, + 226, + 226, + 227, + 227, + 227, + 228, + 228, + 228, + 229, + 229, + 229, + 230, + 230, + 230, + 231, + 231, + 231, + 232, + 232, + 232, + 233, + 233, + 233, + 234, + 234, + 234, + 235, + 235, + 235, + 236, + 236, + 236, + 237, + 237, + 237, + 238, + 238, + 238, + 239, + 239, + 239, + 240, + 240, + 241, + 241, + 241, + 242, + 242, + 242, + 243, + 243, + 243, + 244, + 244, + 244, + 245, + 245, + 245, + 246, + 246, + 246, + 247, + 247, + 247, + 248, + 248, + 248, + 249, + 249, + 249, + 250, + 250, + 250, + 251, + 251, + 251, + 252, + 252, + 252, + 253, + 253, + 254, + 254, + 254, + 255, + 255, + 255, + 256, + 256, + 256, + 257, + 257, + 257, + 258, + 258, + 258, + 259, + 259, + 259, + 260, + 260, + 260, + 261, + 261, + 261, + 262, + 262, + 262, + 263, + 263, + 264, + 264, + 264, + 265, + 265, + 265, + 266, + 266, + 266, + 267, + 267, + 267, + 268, + 268, + 268, + 269, + 269, + 269, + 270, + 270, + 270, + 271, + 271, + 272, + 272, + 272, + 273, + 273, + 273, + 274, + 274, + 274, + 275, + 275, + 275, + 276, + 276, + 276, + 277, + 277, + 277, + 278, + 278, + 279, + 279, + 279, + 280, + 280, + 280, + 281, + 281, + 281, + 282, + 282, + 282, + 283, + 283, + 283, + 284, + 284, + 284, + 285, + 285, + 286, + 286, + 286, + 287, + 287, + 287, + 288, + 288, + 288, + 289, + 289, + 289, + 290, + 290, + 290, + 291, + 291, + 292, + 292, + 292, + 293, + 293, + 293, + 294, + 294, + 294, + 295, + 295, + 295, + 296, + 296, + 296, + 297, + 297, + 298, + 298, + 298, + 299, + 299, + 299, + 300, + 300, + 300, + 301, + 301, + 301, + 302, + 302, + 303, + 303, + 303, + 304, + 304, + 304, + 305, + 305, + 305, + 306, + 306, + 306, + 307, + 307, + 307, + 308, + 308, + 309, + 309, + 309, + 310, + 310, + 310, + 311, + 311, + 311, + 312, + 312, + 313, + 313, + 313, + 314, + 314, + 314, + 315, + 315, + 315, + 316, + 316, + 316, + 317, + 317, + 318, + 318, + 318, + 319, + 319, + 319, + 320, + 320, + 320, + 321, + 321, + 322, + 322, + 322, + 323, + 323, + 323, + 324, + 324, + 324, + 325, + 325, + 325, + 326, + 326, + 327, + 327, + 327, + 328, + 328, + 328, + 329, + 329, + 329, + 330, + 330, + 331, + 331, + 331, + 332, + 332, + 332, + 333, + 333, + 334, + 334, + 334, + 335, + 335, + 335, + 336, + 336, + 336, + 337, + 337, + 338, + 338, + 338, + 339, + 339, + 339, + 340, + 340, + 340, + 341, + 341, + 342, + 342, + 342, + 343, + 343, + 343, + 344, + 344, + 345, + 345, + 345, + 346, + 346, + 346, + 347, + 347, + 347, + 348, + 348, + 349, + 349, + 349, + 350, + 350, + 350, + 351, + 351, + 352, + 352, + 352, + 353, + 353, + 353, + 354, + 354, + 355, + 355, + 355, + 356, + 356, + 356, + 357, + 357, + 357, + 358, + 358, + 359, + 359, + 359, + 360, + 360, + 360, + 361, + 361, + 362, + 362, + 362, + 363, + 363, + 363, + 364, + 364, + 365, + 365, + 365, + 366, + 366, + 366, + 367, + 367, + 368, + 368, + 368, + 369, + 369, + 370, + 370, + 370, + 371, + 371, + 371, + 372, + 372, + 373, + 373, + 373, + 374, + 374, + 374, + 375, + 375, + 376, + 376, + 376, + 377, + 377, + 377, + 378, + 378, + 379, + 379, + 379, + 380, + 380, + 381, + 381, + 381, + 382, + 382, + 382, + 383, + 383, + 384, + 384, + 384, + 385, + 385, + 385, + 386, + 386, + 387, + 387, + 387, + 388, + 388, + 389, + 389, + 389, + 390, + 390, + 390, + 391, + 391, + 392, + 392, + 392, + 393, + 393, + 394, + 394, + 394, + 395, + 395, + 396, + 396, + 396, + 397, + 397, + 397, + 398, + 398, + 399, + 399, + 399, + 400, + 400, + 401, + 401, + 401, + 402, + 402, + 403, + 403, + 403, + 404, + 404, + 404, + 405, + 405, + 406, + 406, + 406, + 407, + 407, + 408, + 408, + 408, + 409, + 409, + 410, + 410, + 410, + 411, + 411, + 412, + 412, + 412, + 413, + 413, + 414, + 414, + 414, + 415, + 415, + 416, + 416, + 416, + 417, + 417, + 417, + 418, + 418, + 419, + 419, + 419, + 420, + 420, + 421, + 421, + 421, + 422, + 422, + 423, + 423, + 423, + 424, + 424, + 425, + 425, + 425, + 426, + 426, + 427, + 427, + 427, + 428, + 428, + 429, + 429, + 429, + 430, + 430, + 431, + 431, + 432, + 432, + 432, + 433, + 433, + 434, + 434, + 434, + 435, + 435, + 436, + 436, + 436, + 437, + 437, + 438, + 438, + 438, + 439, + 439, + 440, + 440, + 440, + 441, + 441, + 442, + 442, + 442, + 443, + 443, + 444, + 444, + 445, + 445, + 445, + 446, + 446, + 447, + 447, + 447, + 448, + 448, + 449, + 449, + 449, + 450, + 450, + 451, + 451, + 452, + 452, + 452, + 453, + 453, + 454, + 454, + 454, + 455, + 455, + 456, + 456, + 457, + 457, + 457, + 458, + 458, + 459, + 459, + 459, + 460, + 460, + 461, + 461, + 462, + 462, + 462, + 463, + 463, + 464, + 464, + 464, + 465, + 465, + 466, + 466, + 467, + 467, + 467, + 468, + 468, + 469, + 469, + 470, + 470, + 470, + 471, + 471, + 472, + 472, + 473, + 473, + 473, + 474, + 474, + 475, + 475, + 475, + 476, + 476, + 477, + 477, + 478, + 478, + 478, + 479, + 479, + 480, + 480, + 481, + 481, + 481, + 482, + 482, + 483, + 483, + 484, + 484, + 485, + 485, + 485, + 486, + 486, + 487, + 487, + 488, + 488, + 488, + 489, + 489, + 490, + 490, + 491, + 491, + 491, + 492, + 492, + 493, + 493, + 494, + 494, + 495, + 495, + 495, + 496, + 496, + 497, + 497, + 498, + 498, + 499, + 499, + 499, + 500, + 500, + 501, + 501, + 502, + 502, + 502, + 503, + 503, + 504, + 504, + 505, + 505, + 506, + 506, + 506, + 507, + 507, + 508, + 508, + 509, + 509, + 510, + 510, + 511, + 511, + 511, + 512, + 512, + 513, + 513, + 514, + 514, + 515, + 515, + 515, + 516, + 516, + 517, + 517, + 518, + 518, + 519, + 519, + 520, + 520, + 520, + 521, + 521, + 522, + 522, + 523, + 523, + 524, + 524, + 525, + 525, + 526, + 526, + 526, + 527, + 527, + 528, + 528, + 529, + 529, + 530, + 530, + 531, + 531, + 532, + 532, + 532, + 533, + 533, + 534, + 534, + 535, + 535, + 536, + 536, + 537, + 537, + 538, + 538, + 539, + 539, + 539, + 540, + 540, + 541, + 541, + 542, + 542, + 543, + 543, + 544, + 544, + 545, + 545, + 546, + 546, + 547, + 547, + 548, + 548, + 549, + 549, + 549, + 550, + 550, + 551, + 551, + 552, + 552, + 553, + 553, + 554, + 554, + 555, + 555, + 556, + 556, + 557, + 557, + 558, + 558, + 559, + 559, + 560, + 560, + 561, + 561, + 562, + 562, + 563, + 563, + 564, + 564, + 565, + 565, + 565, + 566, + 566, + 567, + 567, + 568, + 568, + 569, + 569, + 570, + 570, + 571, + 571, + 572, + 572, + 573, + 573, + 574, + 574, + 575, + 575, + 576, + 576, + 577, + 577, + 578, + 578, + 579, + 579, + 580, + 580, + 581, + 581, + 582, + 583, + 583, + 584, + 584, + 585, + 585, + 586, + 586, + 587, + 587, + 588, + 588, + 589, + 589, + 590, + 590, + 591, + 591, + 592, + 592, + 593, + 593, + 594, + 594, + 595, + 595, + 596, + 596, + 597, + 597, + 598, + 599, + 599, + 600, + 600, + 601, + 601, + 602, + 602, + 603, + 603, + 604, + 604, + 605, + 605, + 606, + 606, + 607, + 608, + 608, + 609, + 609, + 610, + 610, + 611, + 611, + 612, + 612, + 613, + 613, + 614, + 615, + 615, + 616, + 616, + 617, + 617, + 618, + 618, + 619, + 619, + 620, + 621, + 621, + 622, + 622, + 623, + 623, + 624, + 624, + 625, + 625, + 626, + 627, + 627, + 628, + 628, + 629, + 629, + 630, + 631, + 631, + 632, + 632, + 633, + 633, + 634, + 634, + 635, + 636, + 636, + 637, + 637, + 638, + 638, + 639, + 640, + 640, + 641, + 641, + 642, + 642, + 643, + 644, + 644, + 645, + 645, + 646, + 647, + 647, + 648, + 648, + 649, + 649, + 650, + 651, + 651, + 652, + 652, + 653, + 654, + 654, + 655, + 655, + 656, + 657, + 657, + 658, + 658, + 659, + 660, + 660, + 661, + 661, + 662, + 663, + 663, + 664, + 664, + 665, + 666, + 666, + 667, + 667, + 668, + 669, + 669, + 670, + 670, + 671, + 672, + 672, + 673, + 674, + 674, + 675, + 675, + 676, + 677, + 677, + 678, + 679, + 679, + 680, + 681, + 681, + 682, + 682, + 683, + 684, + 684, + 685, + 686, + 686, + 687, + 688, + 688, + 689, + 689, + 690, + 691, + 691, + 692, + 693, + 693, + 694, + 695, + 695, + 696, + 697, + 697, + 698, + 699, + 699, + 700, + 701, + 701, + 702, + 703, + 703, + 704, + 705, + 705, + 706, + 707, + 707, + 708, + 709, + 710, + 710, + 711, + 712, + 712, + 713, + 714, + 714, + 715, + 716, + 716, + 717, + 718, + 719, + 719, + 720, + 721, + 721, + 722, + 723, + 724, + 724, + 725, + 726, + 726, + 727, + 728, + 729, + 729, + 730, + 731, + 732, + 732, + 733, + 734, + 734, + 735, + 736, + 737, + 737, + 738, + 739, + 740, + 740, + 741, + 742, + 743, + 744, + 744, + 745, + 746, + 747, + 747, + 748, + 749, + 750, + 750, + 751, + 752, + 753, + 754, + 754, + 755, + 756, + 757, + 758, + 758, + 759, + 760, + 761, + 762, + 762, + 763, + 764, + 765, + 766, + 767, + 767, + 768, + 769, + 770, + 771, + 772, + 772, + 773, + 774, + 775, + 776, + 777, + 778, + 778, + 779, + 780, + 781, + 782, + 783, + 784, + 785, + 785, + 786, + 787, + 788, + 789, + 790, + 791, + 792, + 793, + 794, + 795, + 795, + 796, + 797, + 798, + 799, + 800, + 801, + 802, + 803, + 804, + 805, + 806, + 807, + 808, + 809, + 810, + 811, + 812, + 813, + 814, + 815, + 816, + 817, + 818, + 819, + 820, + 821, + 822, + 823, + 824, + 825, + 826, + 827, + 828, + 830, + 831, + 832, + 833, + 834, + 835, + 836, + 837, + 838, + 840, + 841, + 842, + 843, + 844, + 845, + 847, + 848, + 849, + 850, + 851, + 853, + 854, + 855, + 856, + 858, + 859, + 860, + 861, + 863, + 864, + 865, + 867, + 868, + 869, + 871, + 872, + 873, + 875, + 876, + 878, + 879, + 881, + 882, + 884, + 885, + 887, + 888, + 890, + 891, + 893, + 894, + 896, + 898, + 899, + 901, + 903, + 905, + 906, + 908, + 910, + 912, + 914, + 916, + 918, + 920, + 922, + 924, + 926, + 928, + 930, + 932, + 935, + 937, + 939, + 942, + 945, + 947, + 950, + 953, + 956, + 959, + 962, + 966, + 970, + 974, + 978, + 983, + 988, + 995, + 1023 + +}; + +short ArcTanTable[]={ + + 0,2,5,7,10,12,15,17, + 20,22,25,27,30,33,35,38, + 40,43,45,48,50,53,55,58, + 60,63,65,68,71,73,76,78, + 81,83,86,88,91,93,96,98, + 101,103,106,108,110,113,115,118, + 120,123,125,128,130,133,135,137, + 140,142,145,147,150,152,154,157, + 159,162,164,166,169,171,173,176, + 178,181,183,185,188,190,192,195, + 197,199,202,204,206,208,211,213, + 215,218,220,222,224,227,229,231, + 233,236,238,240,242,244,247,249, + 251,253,255,258,260,262,264,266, + 268,270,273,275,277,279,281,283, + 285,287,289,291,294,296,298,300, + 302,304,306,308,310,312,314,316, + 318,320,322,324,326,328,330,332, + 334,335,337,339,341,343,345,347, + 349,351,353,354,356,358,360,362, + 364,365,367,369,371,373,375,376, + 378,380,382,383,385,387,389,390, + 392,394,396,397,399,401,402,404, + 406,407,409,411,412,414,416,417, + 419,421,422,424,425,427,429,430, + 432,433,435,437,438,440,441,443, + 444,446,447,449,450,452,453,455, + 456,458,459,461,462,464,465,467, + 468,470,471,472,474,475,477,478, + 479,481,482,484,485,486,488,489, + 490,492,493,495,496,497,499,500, + 501,502,504,505,506,508,509,510 + +}; diff --git a/3dc/VDB.C b/3dc/VDB.C new file mode 100644 index 0000000..983497f --- /dev/null +++ b/3dc/VDB.C @@ -0,0 +1,779 @@ + +#include "3dc.h" +#include "inline.h" + + + +/* + + externs for commonly used global variables and arrays + +*/ + + #if platform_pc + extern int sine[]; + extern int cosine[]; + #endif + + #if SupportWindows95 + extern int ScanDrawMode; + #endif + + +/* + + General System Globals + +*/ + +SCENE Global_Scene = 0; + + + + +/* + + Screen Descriptor Block + +*/ + +SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + + +/* + + View Descriptor Blocks + +*/ + + int NumFreeVDBs; + VIEWDESCRIPTORBLOCK *FreeVDBList[maxvdbs]; + static VIEWDESCRIPTORBLOCK **FreeVDBListPtr = &FreeVDBList[maxvdbs-1]; + + int NumActiveVDBs; + VIEWDESCRIPTORBLOCK *ActiveVDBList[maxvdbs]; + static VIEWDESCRIPTORBLOCK **ActiveVDBListPtr = &ActiveVDBList[0]; + + static VIEWDESCRIPTORBLOCK FreeVDBData[maxvdbs]; + + +/* Clip Plane Block */ + + static CLIPPLANEPOINTS ClipPlanePoints; + + + +extern int GlobalAmbience; + +/* + + Support Functions + +*/ + + +/* + + Calculate View Volume Planes from the Clip Boundaries for a VDB + + Before doing this, check that the requested boundaries are within those of + the physical sceen. If any boundary transgresses, truncate it and set the + appropriate flag bit. + +*/ + +void VDBClipPlanes(VIEWDESCRIPTORBLOCK *vdb) + +{ + + +/* Check Clip Boundaries against the Physical Screen */ + + + /* Check Left Boundary */ + + if(vdb->VDB_ClipLeft < ScreenDescriptorBlock.SDB_ClipLeft) { + + vdb->VDB_ClipLeft = ScreenDescriptorBlock.SDB_ClipLeft; + vdb->VDB_Flags |= ViewDB_Flag_LTrunc; + + } + + /* Check Right Boundary */ + + if(vdb->VDB_ClipRight > ScreenDescriptorBlock.SDB_ClipRight) { + + vdb->VDB_ClipRight = ScreenDescriptorBlock.SDB_ClipRight; + vdb->VDB_Flags |= ViewDB_Flag_RTrunc; + + } + + /* Check Up boundary */ + + if(vdb->VDB_ClipUp < ScreenDescriptorBlock.SDB_ClipUp) { + + vdb->VDB_ClipUp = ScreenDescriptorBlock.SDB_ClipUp; + vdb->VDB_Flags |= ViewDB_Flag_UTrunc; + + } + + /* Check Down boundary */ + + if(vdb->VDB_ClipDown > ScreenDescriptorBlock.SDB_ClipDown) { + + vdb->VDB_ClipDown = ScreenDescriptorBlock.SDB_ClipDown; + vdb->VDB_Flags |= ViewDB_Flag_DTrunc; + + } + + +/* Calculate Width and Height */ + + /* textprint("current wh = %d, %d\n", vdb->VDB_Width, vdb->VDB_Height); */ + + /* Width */ + + vdb->VDB_Width = vdb->VDB_ClipRight - vdb->VDB_ClipLeft; + + /* Height */ + + vdb->VDB_Height = vdb->VDB_ClipDown - vdb->VDB_ClipUp; + + #if 0 + textprint("new wh = %d, %d\n", vdb->VDB_Width, vdb->VDB_Height); + WaitForReturn(); + #endif + + +/* Set up the Clip Planes */ + + + /* Clip Left */ + + ClipPlanePoints.cpp1.vx = vdb->VDB_ClipLeft; + ClipPlanePoints.cpp1.vy = vdb->VDB_ClipUp; + ClipPlanePoints.cpp1.vz = NearZ; + + ClipPlanePoints.cpp2.vx = vdb->VDB_ClipLeft; + ClipPlanePoints.cpp2.vy = (vdb->VDB_ClipUp + vdb->VDB_ClipDown) / 2; + ClipPlanePoints.cpp2.vz = FarZ; + + ClipPlanePoints.cpp3.vx = vdb->VDB_ClipLeft; + ClipPlanePoints.cpp3.vy = vdb->VDB_ClipDown; + ClipPlanePoints.cpp3.vz = NearZ; + + MakeClipPlane(vdb, &vdb->VDB_ClipLeftPlane, &ClipPlanePoints); + + + /* Clip Right */ + + ClipPlanePoints.cpp1.vx = vdb->VDB_ClipRight; + ClipPlanePoints.cpp1.vy = vdb->VDB_ClipUp; + ClipPlanePoints.cpp1.vz = NearZ; + + ClipPlanePoints.cpp2.vx = vdb->VDB_ClipRight; + ClipPlanePoints.cpp2.vy = vdb->VDB_ClipDown; + ClipPlanePoints.cpp2.vz = NearZ; + + ClipPlanePoints.cpp3.vx = vdb->VDB_ClipRight; + ClipPlanePoints.cpp3.vy = (vdb->VDB_ClipUp + vdb->VDB_ClipDown) / 2; + ClipPlanePoints.cpp3.vz = FarZ; + + MakeClipPlane(vdb, &vdb->VDB_ClipRightPlane, &ClipPlanePoints); + + + /* Clip Up */ + + ClipPlanePoints.cpp1.vx = vdb->VDB_ClipLeft; + ClipPlanePoints.cpp1.vy = vdb->VDB_ClipUp; + ClipPlanePoints.cpp1.vz = NearZ; + + ClipPlanePoints.cpp2.vx = vdb->VDB_ClipRight; + ClipPlanePoints.cpp2.vy = vdb->VDB_ClipUp; + ClipPlanePoints.cpp2.vz = NearZ; + + ClipPlanePoints.cpp3.vx = (vdb->VDB_ClipLeft + vdb->VDB_ClipRight) / 2; + ClipPlanePoints.cpp3.vy = vdb->VDB_ClipUp; + ClipPlanePoints.cpp3.vz = FarZ; + + MakeClipPlane(vdb, &vdb->VDB_ClipUpPlane, &ClipPlanePoints); + + + /* Clip Down */ + + ClipPlanePoints.cpp1.vx = vdb->VDB_ClipLeft; + ClipPlanePoints.cpp1.vy = vdb->VDB_ClipDown; + ClipPlanePoints.cpp1.vz = NearZ; + + ClipPlanePoints.cpp2.vx = (vdb->VDB_ClipLeft + vdb->VDB_ClipRight) / 2; + ClipPlanePoints.cpp2.vy = vdb->VDB_ClipDown; + ClipPlanePoints.cpp2.vz = FarZ; + + ClipPlanePoints.cpp3.vx = vdb->VDB_ClipRight; + ClipPlanePoints.cpp3.vy = vdb->VDB_ClipDown; + ClipPlanePoints.cpp3.vz = NearZ; + + MakeClipPlane(vdb, &vdb->VDB_ClipDownPlane, &ClipPlanePoints); + + +/* Clip Z */ + + vdb->VDB_ClipZPlane.CPB_Normal.vx = 0; + vdb->VDB_ClipZPlane.CPB_Normal.vy = 0; + vdb->VDB_ClipZPlane.CPB_Normal.vz = -ONE_FIXED; + + vdb->VDB_ClipZPlane.CPB_POP.vx = 0; + vdb->VDB_ClipZPlane.CPB_POP.vy = 0; + vdb->VDB_ClipZPlane.CPB_POP.vz = vdb->VDB_ClipZ; + +} + + +/* + + Make a Clip Plane. + + Reverse Project the three Clip Points (overwrite their struct). + + Use the first Clip Point as the POP, writing this to the CPB. + + Pass the three Clip Points to MakeNormal() specifying the CPB Normal as + the destination. + + NOTES + + The vdb is passed for the reverse projection. + +*/ + +void MakeClipPlane( + +VIEWDESCRIPTORBLOCK *vdb, +CLIPPLANEBLOCK *cpb, +CLIPPLANEPOINTS *cpp) + +{ + + int x, y; + +/* Reverse Project the Clip Points */ + + +/* cpp1 */ + +/* x */ + + x=cpp->cpp1.vx; + x-=vdb->VDB_CentreX; + x*=cpp->cpp1.vz; + x/=vdb->VDB_ProjX; + cpp->cpp1.vx=x; + +/* y */ + + y=cpp->cpp1.vy; + y-=vdb->VDB_CentreY; + y*=cpp->cpp1.vz; + y/=vdb->VDB_ProjY; + cpp->cpp1.vy=y; + + +/* cpp2 */ + +/* x */ + + x=cpp->cpp2.vx; + x-=vdb->VDB_CentreX; + x*=cpp->cpp2.vz; + x/=vdb->VDB_ProjX; + cpp->cpp2.vx=x; + +/* y */ + + y=cpp->cpp2.vy; + y-=vdb->VDB_CentreY; + y*=cpp->cpp2.vz; + y/=vdb->VDB_ProjY; + cpp->cpp2.vy=y; + + +/* cpp3 */ + +/* x */ + + x=cpp->cpp3.vx; + x-=vdb->VDB_CentreX; + x*=cpp->cpp3.vz; + x/=vdb->VDB_ProjX; + cpp->cpp3.vx=x; + +/* y */ + + y=cpp->cpp3.vy; + y-=vdb->VDB_CentreY; + y*=cpp->cpp3.vz; + y/=vdb->VDB_ProjY; + cpp->cpp3.vy=y; + +/* The 1st Clip Point can be the POP */ + + cpb->CPB_POP.vx=cpp->cpp1.vx; + cpb->CPB_POP.vy=cpp->cpp1.vy; + cpb->CPB_POP.vz=cpp->cpp1.vz; + +/* Make CPB_Normal */ + + MakeNormal(&cpp->cpp1, &cpp->cpp2, &cpp->cpp3, &cpb->CPB_Normal); + +} + + +#if pc_backdrops + +/* + + Create the projector array used for cylindrically projected backdrops + + The array looks like this + + unsigned short VDB_ProjectorXOffsets[MaxScreenWidth]; + + For each centre relative x there is a projector. Using just the x and z + components of the projector an angular offset from the centre (0) can be + calculated using ArcTan(). + + To calculate a projector one must reverse project each x value at a given + z value. Rather than go on to create the normalised projector vector we can + go straight to the ArcTan() to find the angular offset. + +*/ + +static void CreateProjectorArray(VIEWDESCRIPTORBLOCK *vdb) + +{ + + int sx, x, vx, vz, i, ao; + + + vz = ONE_FIXED; + + sx = vdb->VDB_ClipLeft; + + i = 0; + + while(sx < vdb->VDB_ClipRight) { + + x = sx - vdb->VDB_CentreX; + + vx = (x * vz) / vdb->VDB_ProjX; + + ao = ArcTan(vx, vz); + + vdb->VDB_ProjectorXOffsets[i] = ao; + + #if 0 + textprint("Pr. Offset %d = %u\n", i, vdb->VDB_ProjectorXOffsets[i]); + WaitForReturn(); + #endif + + sx++; i++; + + } + +} + +#endif + + + + + + +/* + + SetVDB requires a VIEWDESCRIPTORBLOCK + + See the actual function code for what each parameter is + +*/ + +void SetVDB(vdb, fl, ty, d, cx,cy, prx,pry, mxp, cl,cr,cu,cd, h1,h2,hc, amb) + + VIEWDESCRIPTORBLOCK *vdb; + + int fl; + int ty; + + int d; + + int cx; + int cy; + + int prx; + int pry; + int mxp; + + int cl; + int cr; + int cu; + int cd; + + int h1; + int h2; + int hc; + + int amb; + +{ + + + + /* Initial setup */ + + vdb->VDB_Flags = fl; + vdb->VDB_ViewType = ty; + + + /* Ambience */ + + vdb->VDB_Ambience = amb; + /* KJL 14:30:57 05/14/97 - set globalAmbience here as well */ + GlobalAmbience = amb; + + /* Width and Height are set by the Clip Boundaries */ + + if(vdb->VDB_Flags & ViewDB_Flag_FullSize) { + + vdb->VDB_Depth = ScreenDescriptorBlock.SDB_Depth; + + #if SupportWindows95 + vdb->VDB_ScreenDepth = ScreenDescriptorBlock.SDB_ScreenDepth; + #endif + + vdb->VDB_CentreX = ScreenDescriptorBlock.SDB_CentreX; + vdb->VDB_CentreY = ScreenDescriptorBlock.SDB_CentreY; + + vdb->VDB_ProjX = ScreenDescriptorBlock.SDB_ProjX; + vdb->VDB_ProjY = ScreenDescriptorBlock.SDB_ProjY; + vdb->VDB_MaxProj = ScreenDescriptorBlock.SDB_MaxProj; + + vdb->VDB_ClipLeft = ScreenDescriptorBlock.SDB_ClipLeft; + vdb->VDB_ClipRight = ScreenDescriptorBlock.SDB_ClipRight; + vdb->VDB_ClipUp = ScreenDescriptorBlock.SDB_ClipUp; + vdb->VDB_ClipDown = ScreenDescriptorBlock.SDB_ClipDown; + + } + + else { + + #if SupportWindows95 + if (ScanDrawMode == ScanDrawDirectDraw) + vdb->VDB_Depth = d; + else + vdb->VDB_Depth = VideoModeType_24; + + vdb->VDB_ScreenDepth = ScreenDescriptorBlock.SDB_ScreenDepth; + #else + vdb->VDB_Depth = d; + #endif + + vdb->VDB_CentreX = cx; + vdb->VDB_CentreY = cy; + + vdb->VDB_ProjX = prx; + vdb->VDB_ProjY = pry; + vdb->VDB_MaxProj = mxp; + + vdb->VDB_ClipLeft = cl; + vdb->VDB_ClipRight = cr; + vdb->VDB_ClipUp = cu; + vdb->VDB_ClipDown = cd; + + if(vdb->VDB_Flags & ViewDB_Flag_AdjustScale) { + + vdb->VDB_CentreX = + WideMulNarrowDiv( + vdb->VDB_CentreX, + ScreenDescriptorBlock.SDB_Width, + 320); + + vdb->VDB_CentreY = + WideMulNarrowDiv( + vdb->VDB_CentreY, + ScreenDescriptorBlock.SDB_Height, + 200); + + + vdb->VDB_ProjX = + WideMulNarrowDiv( + vdb->VDB_ProjX, + ScreenDescriptorBlock.SDB_Width, + 320); + + vdb->VDB_ProjY = + WideMulNarrowDiv( + vdb->VDB_ProjY, + ScreenDescriptorBlock.SDB_Height, + 200); + + vdb->VDB_MaxProj = + WideMulNarrowDiv( + vdb->VDB_MaxProj, + ScreenDescriptorBlock.SDB_Width, + 320); + + + vdb->VDB_ClipLeft = + WideMulNarrowDiv( + vdb->VDB_ClipLeft, + ScreenDescriptorBlock.SDB_Width, + 320); + + vdb->VDB_ClipRight = + WideMulNarrowDiv( + vdb->VDB_ClipRight, + ScreenDescriptorBlock.SDB_Width, + 320); + + vdb->VDB_ClipUp = + WideMulNarrowDiv( + vdb->VDB_ClipUp, + ScreenDescriptorBlock.SDB_Height, + 200); + + vdb->VDB_ClipDown = + WideMulNarrowDiv( + vdb->VDB_ClipDown, + ScreenDescriptorBlock.SDB_Height, + 200); + + } + + } + + + /* Create the clip planes */ + + /* KJL 10:41:13 04/09/97 - set to constant so the same for all screen sizes! */ + vdb->VDB_ClipZ = 64;//vdb->VDB_MaxProj; /* Safe */ + + VDBClipPlanes(vdb); + + #if 0 + /* View Angle */ + + if(vdb->VDB_CentreX > vdb->VDB_CentreY) s = vdb->VDB_CentreX; + else s = vdb->VDB_CentreY; + + z = vdb->VDB_MaxProj * 100; + + x = (s * z) / vdb->VDB_MaxProj; + + vdb->VDB_ViewAngle = ArcTan(x, z); + + vdb->VDB_ViewAngleCos = GetCos(vdb->VDB_ViewAngle); + + + #if 0 + textprint("View Angle = %d\n", vdb->VDB_ViewAngle); + WaitForReturn(); + #endif + + + #if pc_backdrops + + /* Projector Array */ + + CreateProjectorArray(vdb); + + #endif + + + /* Hazing & Background Colour */ + + vdb->VDB_H1 = h1; + vdb->VDB_H2 = h2; + vdb->VDB_HInterval = h2 - h1; + vdb->VDB_HColour = hc; + #endif +} + + + + +/* + + Initialise the Free VDB List + +*/ + +void InitialiseVDBs(void) + +{ + + VIEWDESCRIPTORBLOCK *FreeVDBPtr = &FreeVDBData[0]; + + NumActiveVDBs = 0; + + for(NumFreeVDBs = 0; NumFreeVDBs < maxvdbs; NumFreeVDBs++) { + + FreeVDBList[NumFreeVDBs] = FreeVDBPtr; + + FreeVDBPtr++; + + } + + FreeVDBListPtr = &FreeVDBList[maxvdbs-1]; + ActiveVDBListPtr = &ActiveVDBList[0]; + +} + + +/* + + Get a VDB from the Free VDB list + +*/ + +VIEWDESCRIPTORBLOCK* AllocateVDB(void) + +{ + + VIEWDESCRIPTORBLOCK *FreeVDBPtr = 0; /* Default to null ptr */ + int *i_src; + int i; + + + if(NumFreeVDBs) { + + FreeVDBPtr = *FreeVDBListPtr--; + + NumFreeVDBs -= 1; /* One less free block */ + + /* Clear the block */ + + i_src = (int *) FreeVDBPtr; + for(i = sizeof(VIEWDESCRIPTORBLOCK)/4; i!=0; i--) + *i_src++ = 0; + + } + + return(FreeVDBPtr); + +} + + +/* + + Return a VDB to the Free VDB list + +*/ + +void DeallocateVDB(VIEWDESCRIPTORBLOCK *vdb) + +{ + + FreeVDBListPtr++; + *FreeVDBListPtr = vdb; + + NumFreeVDBs++; /* One more free block */ + +} + + +/* + + Allocate a VDB and make it active + +*/ + +VIEWDESCRIPTORBLOCK* CreateActiveVDB(void) + +{ + + VIEWDESCRIPTORBLOCK *vdb; + VIEWDESCRIPTORBLOCK *vdb_tmp; + VIEWDESCRIPTORBLOCK **v_src; + + int v; + int p = -1; + + + vdb = AllocateVDB(); + + if(vdb) { + + /* Find the next "VDB_Priority" */ + + if(NumActiveVDBs) { + + v_src = &ActiveVDBList[0]; + + for(v = NumActiveVDBs; v!=0; v--) { + + vdb_tmp = *v_src++; + + if(vdb_tmp->VDB_Priority > p) p = vdb_tmp->VDB_Priority; + + } + + } + + /* Set the VDB priority */ + + vdb->VDB_Priority = (p + 1); + + /* Update the active VDB list */ + + *ActiveVDBListPtr++ = vdb; + + NumActiveVDBs++; + + } + + return vdb; + +} + + +/* + + Deallocate an active VDB + +*/ + +int DestroyActiveVDB(dblockptr) + + VIEWDESCRIPTORBLOCK *dblockptr; + +{ + + int j = -1; + int i; + + + /* If the VDB ptr is OK, search the Active VDB List */ + + if(dblockptr) { + + for(i = 0; i < NumActiveVDBs && j!=0; i++) { + + if(ActiveVDBList[i] == dblockptr) { + + #if ProjectSpecificVDBs + ProjectSpecificVDBDestroy(dblockptr); + #endif + + ActiveVDBList[i] = ActiveVDBList[NumActiveVDBs - 1]; + NumActiveVDBs--; + ActiveVDBListPtr--; + DeallocateVDB(dblockptr); /* Return VDB to Free List */ + j = 0; /* Flag OK */ + + } + } + } + + return(j); + +} diff --git a/3dc/avp.ico b/3dc/avp.ico new file mode 100644 index 0000000..d4d5f0d Binary files /dev/null and b/3dc/avp.ico differ diff --git a/3dc/avp.rc b/3dc/avp.rc new file mode 100644 index 0000000..20027ce --- /dev/null +++ b/3dc/avp.rc @@ -0,0 +1 @@ +AVPICON ICON AvP.ICO \ No newline at end of file diff --git a/3dc/avp/AI_Sight.c b/3dc/avp/AI_Sight.c new file mode 100644 index 0000000..a1815ef --- /dev/null +++ b/3dc/avp/AI_Sight.c @@ -0,0 +1,198 @@ +/*KJL***************************************** +* AI_Sight.c handles the NPC's visual senses * +*****************************************KJL*/ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "dynblock.h" +#include "dynamics.h" +#include "los.h" +#include "ShowCmds.h" +#include "equipmnt.h" +#include "bh_marin.h" +#include "bh_xeno.h" +#include "targeting.h" +#include "bh_weap.h" + +#include "AI_Sight.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +extern int MarineSight_FrustrumReject(STRATEGYBLOCK *sbPtr,VECTORCH *localOffset,STRATEGYBLOCK *target); +extern int FrisbeeSight_FrustrumReject(STRATEGYBLOCK *sbPtr,VECTORCH *localOffset,STRATEGYBLOCK *target); + +int NPCCanSeeTarget(STRATEGYBLOCK *sbPtr, STRATEGYBLOCK *target, int viewRange) +{ + int frustrum_test; + /* connect eyeposition to head */ + VECTORCH eyePosition = {0,-1500,0}; + + LOCALASSERT(target); + LOCALASSERT(sbPtr); + + if (target->containingModule==NULL) { + return(0); + } + + if (sbPtr->containingModule==NULL) { + return(0); + } + + if ((target->SBdptr==NULL)||(sbPtr->SBdptr==NULL)) { + if ((IsModuleVisibleFromModule(target->containingModule,sbPtr->containingModule))) { + return(1); + } else { + return(0); + } + } else { + + switch (sbPtr->I_SBtype) { + case I_BehaviourFrisbee: + { + MATRIXCH WtoL; + VECTORCH offset, sourcepos, targetpos; + FRISBEE_BEHAV_BLOCK *frisbeeStatusPointer; + SECTION_DATA *disc_sec; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + frisbeeStatusPointer = (FRISBEE_BEHAV_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(frisbeeStatusPointer); + /* Arc reject. */ + + disc_sec=GetThisSectionData(frisbeeStatusPointer->HModelController.section_data,"Mdisk"); + + if (disc_sec) { + WtoL=disc_sec->SecMat; + sourcepos=disc_sec->World_Offset; + } else { + WtoL=sbPtr->DynPtr->OrientMat; + GetTargetingPointOfObject_Far(sbPtr,&sourcepos); + } + + GetTargetingPointOfObject_Far(target,&targetpos); + + offset.vx=sourcepos.vx-targetpos.vx; + offset.vy=sourcepos.vy-targetpos.vy; + offset.vz=sourcepos.vz-targetpos.vz; + + TransposeMatrixCH(&WtoL); + RotateVector(&offset,&WtoL); + + frustrum_test=FrisbeeSight_FrustrumReject(sbPtr,&offset,target); + } + break; + case I_BehaviourMarine: + case I_BehaviourSeal: + { + MATRIXCH WtoL; + VECTORCH offset, sourcepos, targetpos; + MARINE_STATUS_BLOCK *marineStatusPointer; + SECTION_DATA *head_sec; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + /* Arc reject. */ + + head_sec=GetThisSectionData(marineStatusPointer->HModelController.section_data,"head"); + + if (head_sec) { + WtoL=head_sec->SecMat; + sourcepos=head_sec->World_Offset; + } else { + WtoL=sbPtr->DynPtr->OrientMat; + GetTargetingPointOfObject_Far(sbPtr,&sourcepos); + } + + GetTargetingPointOfObject_Far(target,&targetpos); + + offset.vx=sourcepos.vx-targetpos.vx; + offset.vy=sourcepos.vy-targetpos.vy; + offset.vz=sourcepos.vz-targetpos.vz; + + TransposeMatrixCH(&WtoL); + RotateVector(&offset,&WtoL); + + frustrum_test=MarineSight_FrustrumReject(sbPtr,&offset,target); + } + break; + case I_BehaviourXenoborg: + { + MATRIXCH WtoL; + VECTORCH offset, sourcepos, targetpos; + XENO_STATUS_BLOCK *xenoStatusPointer; + SECTION_DATA *head_sec; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + /* Arc reject. */ + + head_sec=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"head"); + + if (head_sec) { + WtoL=head_sec->SecMat; + sourcepos=head_sec->World_Offset; + } else { + WtoL=sbPtr->DynPtr->OrientMat; + GetTargetingPointOfObject_Far(sbPtr,&sourcepos); + } + + GetTargetingPointOfObject_Far(target,&targetpos); + + offset.vx=sourcepos.vx-targetpos.vx; + offset.vy=sourcepos.vy-targetpos.vy; + offset.vz=sourcepos.vz-targetpos.vz; + + TransposeMatrixCH(&WtoL); + RotateVector(&offset,&WtoL); + + frustrum_test=XenoSight_FrustrumReject(sbPtr,&offset); + } + break; + case I_BehaviourAutoGun: + { + /* Less pretentious, based on the SB. */ + MATRIXCH WtoL; + VECTORCH offset, sourcepos, targetpos; + /* Arc reject. */ + + WtoL=sbPtr->DynPtr->OrientMat; + GetTargetingPointOfObject_Far(sbPtr,&sourcepos); + GetTargetingPointOfObject_Far(target,&targetpos); + + offset.vx=sourcepos.vx-targetpos.vx; + offset.vy=sourcepos.vy-targetpos.vy; + offset.vz=sourcepos.vz-targetpos.vz; + + TransposeMatrixCH(&WtoL); + RotateVector(&offset,&WtoL); + + frustrum_test=AGunSight_FrustrumReject(&offset); + } + break; + default: + frustrum_test=1; + break; + } + + if (frustrum_test) { + + RotateVector(&eyePosition,&(sbPtr->DynPtr->OrientMat)); + + eyePosition.vx += sbPtr->DynPtr->Position.vx; + eyePosition.vy += sbPtr->DynPtr->Position.vy; + eyePosition.vz += sbPtr->DynPtr->Position.vz; + + return IsThisObjectVisibleFromThisPosition_WithIgnore(target->SBdptr,sbPtr->SBdptr,&eyePosition,NPC_MAX_VIEWRANGE); + } + } + + return(0); +} diff --git a/3dc/avp/AI_Sight.h b/3dc/avp/AI_Sight.h new file mode 100644 index 0000000..089bc83 --- /dev/null +++ b/3dc/avp/AI_Sight.h @@ -0,0 +1,3 @@ +#define NPC_MAX_VIEWRANGE (50000) + +extern int NPCCanSeeTarget(STRATEGYBLOCK *sbptr, STRATEGYBLOCK *target, int viewRange); diff --git a/3dc/avp/AVPVIEW.H b/3dc/avp/AVPVIEW.H new file mode 100644 index 0000000..d9a5420 --- /dev/null +++ b/3dc/avp/AVPVIEW.H @@ -0,0 +1,7 @@ +/* KJL 10:49:41 04/21/97 - avpview.h */ +extern void AvpShowViews(void); +extern void InitCameraValues(void); +extern void LightSourcesInRangeOfObject(DISPLAYBLOCK *dptr); + + +extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; diff --git a/3dc/avp/Avpview.c b/3dc/avp/Avpview.c new file mode 100644 index 0000000..e522bca --- /dev/null +++ b/3dc/avp/Avpview.c @@ -0,0 +1,1019 @@ +#include "3dc.h" + +#include "inline.h" +#include "module.h" +#include "gamedef.h" +#include "stratdef.h" +#include "dynblock.h" +#include "bh_types.h" +#include "avpview.h" + +#include "kshape.h" +#include "kzsort.h" +#include "frustrum.h" +#include "krender.h" +#include "vision.h" +#include "lighting.h" +#include "weapons.h" +#include "sfx.h" +#include "smacker.h" +/* character extents data so you know where the player's eyes are */ +#include "extents.h" +#include "avp_userprofile.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +/* KJL 13:59:05 04/19/97 - avpview.c + * + * This is intended to be an AvP-specific streamlined version of view.c. + */ + +extern void AllNewModuleHandler(void); +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + +DISPLAYBLOCK *OnScreenBlockList[maxobjects]; +int NumOnScreenBlocks; + +extern DISPLAYBLOCK *ActiveBlockList[]; +extern int NumActiveBlocks; + +extern int ScanDrawMode; +/* JH 13/5/97 */ +extern int DrawMode; +extern int ZBufferMode; + +extern DPID MultiplayerObservedPlayer; + +#if SupportMorphing +MORPHDISPLAY MorphDisplay; +#endif + +#if SupportModules +SCENEMODULE **Global_ModulePtr = 0; +MODULE *Global_MotherModule; +char *ModuleCurrVisArray = 0; +char *ModulePrevVisArray = 0; +char *ModuleTempArray = 0; +char *ModuleLocalVisArray = 0; +int ModuleArraySize = 0; +#endif + +/* KJL 11:12:10 06/06/97 - orientation */ +MATRIXCH LToVMat; +EULER LToVMat_Euler; +MATRIXCH WToLMat = {1,}; +VECTORCH LocalView; + +/* KJL 11:16:37 06/06/97 - lights */ +VECTORCH LocalLightCH; +int NumLightSourcesForObject; +LIGHTBLOCK *LightSourcesForObject[MaxLightsPerObject]; +int GlobalAmbience; +int LightScale=ONE_FIXED; +int DrawingAReflection; + +int *Global_ShapePoints; +int **Global_ShapeItems; +int *Global_ShapeNormals; +int *Global_ShapeVNormals; +int **Global_ShapeTextures; +VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; +DISPLAYBLOCK *Global_ODB_Ptr; +SHAPEHEADER *Global_ShapeHeaderPtr; +EXTRAITEMDATA *Global_EID_Ptr; +int *Global_EID_IPtr; + + +extern float CameraZoomScale; +extern int CameraZoomLevel; +extern int AlienBiteAttackInProgress=0; + +/* phase for cloaked objects */ +int CloakingPhase; +extern int NormalFrameTime; +extern int cosine[]; +extern int sine[]; + +int LeanScale; +EULER deathTargetOrientation={0,0,0}; + +extern int GetSingleColourForPrimary(int Colour); +extern void ColourFillBackBuffer(int FillColour); + +static void ModifyHeadOrientation(void); + + + +void UpdateRunTimeLights(void) +{ + extern int NumActiveBlocks; + extern DISPLAYBLOCK *ActiveBlockList[]; + int numberOfObjects = NumActiveBlocks; + + while (numberOfObjects--) + { + DISPLAYBLOCK *dispPtr = ActiveBlockList[numberOfObjects]; + + if( (dispPtr->SpecialFXFlags & SFXFLAG_ONFIRE) + ||((dispPtr->ObStrategyBlock)&&(dispPtr->ObStrategyBlock->SBDamageBlock.IsOnFire)) ) + AddLightingEffectToObject(dispPtr,LFX_OBJECTONFIRE); + + UpdateObjectLights(dispPtr); + } + + HandleLightElementSystem(); +} +void LightSourcesInRangeOfObject(DISPLAYBLOCK *dptr) +{ + + DISPLAYBLOCK **aptr; + DISPLAYBLOCK *dptr2; + LIGHTBLOCK *lptr; + VECTORCH llocal; + int i, j; + + + aptr = ActiveBlockList; + + + NumLightSourcesForObject = 0; + + + /* + + Light Sources attached to other objects + + */ + + for(i = NumActiveBlocks; + i!=0 && NumLightSourcesForObject < MaxLightsPerObject; i--) { + + dptr2 = *aptr++; + + if(dptr2->ObNumLights) { + + for(j = 0; j < dptr2->ObNumLights + && NumLightSourcesForObject < MaxLightsPerObject; j++) { + + lptr = dptr2->ObLights[j]; + + if (!lptr->LightBright || !(lptr->RedScale||lptr->GreenScale||lptr->BlueScale)) + { + continue; + } + + if ((CurrentVisionMode == VISION_MODE_IMAGEINTENSIFIER) && (lptr->LightFlags & LFlag_PreLitSource)) + continue; +// lptr->LightFlags |= LFlag_NoSpecular; + + if(!(dptr->ObFlags3 & ObFlag3_PreLit && + lptr->LightFlags & LFlag_PreLitSource)) + { + { + VECTORCH vertexToLight; + int distanceToLight; + + if (DrawingAReflection) + { + vertexToLight.vx = (MirroringAxis - lptr->LightWorld.vx) - dptr->ObWorld.vx; + } + else + { + vertexToLight.vx = lptr->LightWorld.vx - dptr->ObWorld.vx; + } + vertexToLight.vy = lptr->LightWorld.vy - dptr->ObWorld.vy; + vertexToLight.vz = lptr->LightWorld.vz - dptr->ObWorld.vz; + + distanceToLight = Approximate3dMagnitude(&vertexToLight); + + #if 0 + if (CurrentVisionMode == VISION_MODE_IMAGEINTENSIFIER) + distanceToLight /= 2; + #endif + + if(distanceToLight < (lptr->LightRange + dptr->ObRadius) ) + { + + LightSourcesForObject[NumLightSourcesForObject] = lptr; + NumLightSourcesForObject++; + + /* Transform the light position to local space */ + + llocal = vertexToLight; + + RotateAndCopyVector(&llocal, &lptr->LocalLP, &WToLMat); + + } + + + } + + } + + } + + } + + } + + { + extern LIGHTELEMENT LightElementStorage[]; + extern int NumActiveLightElements; + int i = NumActiveLightElements; + LIGHTELEMENT *lightElementPtr = LightElementStorage; + while(i--) + { + LIGHTBLOCK *lptr = &(lightElementPtr->LightBlock); + VECTORCH vertexToLight; + int distanceToLight; + + vertexToLight.vx = lptr->LightWorld.vx - dptr->ObWorld.vx; + vertexToLight.vy = lptr->LightWorld.vy - dptr->ObWorld.vy; + vertexToLight.vz = lptr->LightWorld.vz - dptr->ObWorld.vz; + + distanceToLight = Approximate3dMagnitude(&vertexToLight); + + #if 0 + if (CurrentVisionMode == VISION_MODE_IMAGEINTENSIFIER) + distanceToLight /= 2; + #endif + + if(distanceToLight < (lptr->LightRange + dptr->ObRadius) ) + { + + LightSourcesForObject[NumLightSourcesForObject] = lptr; + NumLightSourcesForObject++; + + /* Transform the light position to local space */ + llocal = vertexToLight; + RotateAndCopyVector(&llocal, &lptr->LocalLP, &WToLMat); + + } + + lightElementPtr++; + } + } + + +} + +EULER HeadOrientation = {0,0,0}; + +static void ModifyHeadOrientation(void) +{ + extern int NormalFrameTime; + #define TILT_THRESHOLD 128 + PLAYER_STATUS *playerStatusPtr; + + /* get the player status block ... */ + playerStatusPtr = (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + if (!playerStatusPtr->IsAlive && !MultiplayerObservedPlayer) + { + int decay = NormalFrameTime>>6; + + HeadOrientation.EulerX &= 4095; + HeadOrientation.EulerX -= decay; + if(HeadOrientation.EulerX < 3072) + HeadOrientation.EulerX = 3072; + + } + else + { + int decay = NormalFrameTime>>8; + if(HeadOrientation.EulerX > 2048) + { + if (HeadOrientation.EulerX < 4096 - TILT_THRESHOLD) + HeadOrientation.EulerX = 4096 - TILT_THRESHOLD; + + HeadOrientation.EulerX += decay; + if(HeadOrientation.EulerX > 4095) + HeadOrientation.EulerX =0; + } + else + { + if (HeadOrientation.EulerX > TILT_THRESHOLD) + HeadOrientation.EulerX = TILT_THRESHOLD; + + HeadOrientation.EulerX -= decay; + if(HeadOrientation.EulerX < 0) + HeadOrientation.EulerX =0; + } + + if(HeadOrientation.EulerY > 2048) + { + if (HeadOrientation.EulerY < 4096 - TILT_THRESHOLD) + HeadOrientation.EulerY = 4096 - TILT_THRESHOLD; + + HeadOrientation.EulerY += decay; + if(HeadOrientation.EulerY > 4095) + HeadOrientation.EulerY =0; + } + else + { + if (HeadOrientation.EulerY > TILT_THRESHOLD) + HeadOrientation.EulerY = TILT_THRESHOLD; + + HeadOrientation.EulerY -= decay; + if(HeadOrientation.EulerY < 0) + HeadOrientation.EulerY =0; + } + + if(HeadOrientation.EulerZ > 2048) + { + if (HeadOrientation.EulerZ < 4096 - TILT_THRESHOLD) + HeadOrientation.EulerZ = 4096 - TILT_THRESHOLD; + + HeadOrientation.EulerZ += decay; + if(HeadOrientation.EulerZ > 4095) + HeadOrientation.EulerZ =0; + } + else + { + if (HeadOrientation.EulerZ > TILT_THRESHOLD) + HeadOrientation.EulerZ = TILT_THRESHOLD; + + HeadOrientation.EulerZ -= decay; + if(HeadOrientation.EulerZ < 0) + HeadOrientation.EulerZ =0; + } + } +} + +void InteriorType_Body() +{ + DISPLAYBLOCK *subjectPtr = Player; + extern int NormalFrameTime; + + static int verticalSpeed = 0; + static int zAxisTilt=0; + STRATEGYBLOCK *sbPtr; + DYNAMICSBLOCK *dynPtr; + + sbPtr = subjectPtr->ObStrategyBlock; + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + ModifyHeadOrientation(); + { + /* eye offset */ + VECTORCH ioff; + COLLISION_EXTENTS *extentsPtr = 0; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); + + switch(AvP.PlayerType) + { + case I_Marine: + extentsPtr = &CollisionExtents[CE_MARINE]; + break; + + case I_Alien: + extentsPtr = &CollisionExtents[CE_ALIEN]; + break; + + case I_Predator: + extentsPtr = &CollisionExtents[CE_PREDATOR]; + break; + } + + /* set player state */ + if (playerStatusPtr->ShapeState == PMph_Standing) + { + ioff.vy = extentsPtr->StandingTop; + } + else + { + ioff.vy = extentsPtr->CrouchingTop; + } + + if (LANDOFTHEGIANTS_CHEATMODE) + { + ioff.vy/=4; + } + if (!playerStatusPtr->IsAlive && !MultiplayerObservedPlayer) + { + extern int deathFadeLevel; + + ioff.vy = MUL_FIXED(deathFadeLevel*4-3*ONE_FIXED,ioff.vy); + + if (ioff.vy>-100) + { + ioff.vy = -100; + } + } + + + ioff.vx = 0; + ioff.vz = 0;//-extentsPtr->CollisionRadius*2; + ioff.vy += verticalSpeed/16+200; + + RotateVector(&ioff, &subjectPtr->ObMat); + AddVector(&ioff, &Global_VDB_Ptr->VDB_World); + + #if 0 + { + static int i=-10; + i=-i; + ioff.vx = MUL_FIXED(GetSin((CloakingPhase/5)&4095),i); + ioff.vy = MUL_FIXED(GetCos((CloakingPhase/3)&4095),i); + ioff.vz = 0; + + RotateVector(&ioff, &subjectPtr->ObMat); + AddVector(&ioff, &Global_VDB_Ptr->VDB_World); + + + } + #endif + } + { + EULER orientation; + MATRIXCH matrix; + + orientation = HeadOrientation; + + orientation.EulerZ += (zAxisTilt>>8); + orientation.EulerZ &= 4095; + + if (NAUSEA_CHEATMODE) + { + orientation.EulerZ = (orientation.EulerZ+GetSin((CloakingPhase/2)&4095)/256)&4095; + orientation.EulerX = (orientation.EulerX+GetSin((CloakingPhase/2+500)&4095)/512)&4095; + orientation.EulerY = (orientation.EulerY+GetSin((CloakingPhase/3+800)&4095)/512)&4095; + } + // The next test drops the matrix multiply if the orientation is close to zero + // There is an inaccuracy problem with the Z angle at this point + + if (orientation.EulerX != 0 || orientation.EulerY != 0 || + (orientation.EulerZ > 1 && orientation.EulerZ < 4095)) + { + CreateEulerMatrix(&orientation, &matrix); + MatrixMultiply(&Global_VDB_Ptr->VDB_Mat, &matrix, &Global_VDB_Ptr->VDB_Mat); + } + + } + + { + VECTORCH relativeVelocity; + + /* get subject's total velocity */ + { + MATRIXCH worldToLocalMatrix; + + /* make world to local matrix */ + worldToLocalMatrix = subjectPtr->ObMat; + TransposeMatrixCH(&worldToLocalMatrix); + + relativeVelocity.vx = dynPtr->Position.vx - dynPtr->PrevPosition.vx; + relativeVelocity.vy = dynPtr->Position.vy - dynPtr->PrevPosition.vy; + relativeVelocity.vz = dynPtr->Position.vz - dynPtr->PrevPosition.vz; + /* rotate into object space */ + + RotateVector(&relativeVelocity,&worldToLocalMatrix); + } + + { + int targetingSpeed = 10*NormalFrameTime; + + /* KJL 14:08:50 09/20/96 - the targeting is FRI, but care has to be taken + at very low frame rates to ensure that you can't overshoot */ + if (targetingSpeed > 65536) targetingSpeed=65536; + + zAxisTilt += MUL_FIXED + ( + DIV_FIXED + ( + MUL_FIXED(relativeVelocity.vx,LeanScale), + NormalFrameTime + )-zAxisTilt, + targetingSpeed + ); + + { + static int previousVerticalSpeed = 0; + int difference; + + if (relativeVelocity.vy >= 0) + { + difference = DIV_FIXED + ( + previousVerticalSpeed - relativeVelocity.vy, + NormalFrameTime + ); + } + else difference = 0; + + if (verticalSpeed < difference) verticalSpeed = difference; + + if(verticalSpeed > 150*16) verticalSpeed = 150*16; + + verticalSpeed -= NormalFrameTime>>2; + if (verticalSpeed < 0) verticalSpeed = 0; + + previousVerticalSpeed = relativeVelocity.vy; + } + } + } +} + +void UpdateCamera(void) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + int cos = GetCos(playerStatusPtr->ViewPanX); + int sin = GetSin(playerStatusPtr->ViewPanX); + MATRIXCH mat; + DISPLAYBLOCK *dptr_s = Player; + + Global_VDB_Ptr->VDB_World = dptr_s->ObWorld; + Global_VDB_Ptr->VDB_Mat = dptr_s->ObMat; + + mat.mat11 = ONE_FIXED; + mat.mat12 = 0; + mat.mat13 = 0; + mat.mat21 = 0; + mat.mat22 = cos; + mat.mat23 = -sin; + mat.mat31 = 0; + mat.mat32 = sin; + mat.mat33 = cos; + MatrixMultiply(&Global_VDB_Ptr->VDB_Mat,&mat,&Global_VDB_Ptr->VDB_Mat); + + + InteriorType_Body(); +} + +void AVPGetInViewVolumeList(VIEWDESCRIPTORBLOCK *VDB_Ptr) +{ + DISPLAYBLOCK **activeblocksptr; + int t; + #if (SupportModules && SupportMultiCamModules) + int MVis; + #endif + + /* Initialisation */ + NumOnScreenBlocks = 0; + + /* Scan the Active Blocks List */ + activeblocksptr = &ActiveBlockList[0]; + + for(t = NumActiveBlocks; t!=0; t--) + { + DISPLAYBLOCK *dptr = *activeblocksptr++; + + if (dptr==Player) continue; + MVis = Yes; + if(dptr->ObMyModule) + { + MODULE *mptr = dptr->ObMyModule; + if(ModuleCurrVisArray[mptr->m_index] != 2) MVis = No; + else + { + extern int NumberOfLandscapePolygons; + SHAPEHEADER *shapePtr = GetShapeData(dptr->ObShape); + NumberOfLandscapePolygons+=shapePtr->numitems; + } + + } + if (!(dptr->ObFlags&ObFlag_NotVis) && MVis) + { + MakeVector(&dptr->ObWorld, &VDB_Ptr->VDB_World, &dptr->ObView); + RotateVector(&dptr->ObView, &VDB_Ptr->VDB_Mat); + + /* Screen Test */ + #if MIRRORING_ON + if (MirroringActive || dptr->HModelControlBlock || dptr->SfxPtr) + { + OnScreenBlockList[NumOnScreenBlocks++] = dptr; + } + else if (ObjectWithinFrustrum(dptr)) + { + OnScreenBlockList[NumOnScreenBlocks++] = dptr; + } + #else + if(dptr->SfxPtr || dptr->HModelControlBlock || ObjectWithinFrustrum(dptr)) + { + OnScreenBlockList[NumOnScreenBlocks++] = dptr; + } + else + { + if(dptr->HModelControlBlock) + { + DoHModelTimer(dptr->HModelControlBlock); + } + } + #endif + } + + } +} + +void ReflectObject(DISPLAYBLOCK *dPtr) +{ + dPtr->ObWorld.vx = MirroringAxis - dPtr->ObWorld.vx; + dPtr->ObMat.mat11 = -dPtr->ObMat.mat11; + dPtr->ObMat.mat21 = -dPtr->ObMat.mat21; + dPtr->ObMat.mat31 = -dPtr->ObMat.mat31; +} + +void CheckIfMirroringIsRequired(void); +void AvpShowViews(void) +{ + #if SOFTWARE_RENDERER + FlushSoftwareZBuffer(); + #else + FlushD3DZBuffer(); + #endif + + UpdateAllFMVTextures(); + + + /* Update attached object positions and orientations etc. */ + UpdateCamera(); + + /* Initialise the global VMA */ +// GlobalAmbience=655; +// textprint("Global Ambience: %d\n",GlobalAmbience); + + #if PSX + // For PSX, GlobalAmbience is used in the render files + GlobalAmbience = Global_VDB_Ptr->VDB_Ambience >> 8; + #endif + + /* Prepare the View Descriptor Block for use in ShowView() */ + + PrepareVDBForShowView(Global_VDB_Ptr); + PlatformSpecificShowViewEntry(Global_VDB_Ptr, &ScreenDescriptorBlock); + TranslationSetup(); + + { + extern void ThisFramesRenderingHasBegun(void); + ThisFramesRenderingHasBegun(); + D3D_DrawBackdrop(); + } + + /* Now we know where the camera is, update the modules */ + + #if SupportModules + AllNewModuleHandler(); +// ModuleHandler(Global_VDB_Ptr); + #endif + + #if MIRRORING_ON + CheckIfMirroringIsRequired(); + #endif + + /* Do lights */ + UpdateRunTimeLights(); + if (AvP.PlayerType==I_Alien) + { + MakeLightElement(&Player->ObWorld,LIGHTELEMENT_ALIEN_TEETH); + MakeLightElement(&Player->ObWorld,LIGHTELEMENT_ALIEN_TEETH2); + } + +// GlobalAmbience=ONE_FIXED/4; + /* Find out which objects are in the View Volume */ + AVPGetInViewVolumeList(Global_VDB_Ptr); + + if (AlienBiteAttackInProgress) + { + CameraZoomScale += (float)NormalFrameTime/65536.0f; + if (CameraZoomScale > 1.0f) + { + AlienBiteAttackInProgress = 0; + CameraZoomScale = 1.0f; + } + } + + /* update players weapon */ + UpdateWeaponStateMachine(); + /* lights associated with the player may have changed */ + UpdateObjectLights(Player); + + + if(NumOnScreenBlocks) + { + /* KJL 12:13:26 02/05/97 - divert rendering for AvP */ + KRenderItems(Global_VDB_Ptr); + } + #if 0 + RenderDungeon(); + #endif + + PlatformSpecificShowViewExit(Global_VDB_Ptr, &ScreenDescriptorBlock); + + #if (SupportWindows95 && SupportZBuffering) + if ((ScanDrawMode != ScanDrawDirectDraw) && (ZBufferMode != ZBufferOff)) + { + /* KJL 10:25:44 7/23/97 - this offset is used to push back the normal game gfx, + so that the HUD can be drawn over the top without sinking into walls, etc. */ + HeadUpDisplayZOffset = 0; + } + #endif +} + + +void InitCameraValues(void) +{ + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + Global_VDB_Ptr = ActiveVDBList[0]; + + HeadOrientation.EulerX = 0; + HeadOrientation.EulerY = 0; + HeadOrientation.EulerZ = 0; + + CameraZoomScale = 1.0f; + CameraZoomLevel=0; +} + + + +/* + + Prepare the View Descriptor Block for use in ShowView() and others. + + If there is a display block attached to the view, update the view location + and orientation. + +*/ + +void PrepareVDBForShowView(VIEWDESCRIPTORBLOCK *VDB_Ptr) +{ + EULER e; + + + /* Get the View Object Matrix, transposed */ + TransposeMatrixCH(&VDB_Ptr->VDB_Mat); + + /* Get the Matrix Euler Angles */ + MatrixToEuler(&VDB_Ptr->VDB_Mat, &VDB_Ptr->VDB_MatrixEuler); + + /* Get the Matrix Euler Angles */ + MatrixToEuler(&VDB_Ptr->VDB_Mat, &e); + + /* Create the "sprite" matrix" */ + e.EulerX = 0; + e.EulerY = 0; + e.EulerZ = (-e.EulerZ) & wrap360; + + CreateEulerMatrix(&e, &VDB_Ptr->VDB_SpriteMat); +} + + +/* + + This function updates the position and orientation of the lights attached + to an object. + + It must be called after the object has completed its movements in a frame, + prior to the call to the renderer. + +*/ + +void UpdateObjectLights(DISPLAYBLOCK *dptr) +{ + + int i; + LIGHTBLOCK *lptr; + LIGHTBLOCK **larrayptr = &dptr->ObLights[0]; + + + for(i = dptr->ObNumLights; i!=0; i--) + { + /* Get a light */ + lptr = *larrayptr++; + + /* Calculate the light's location */ + if(!(lptr->LightFlags & LFlag_AbsPos)) + { + CopyVector(&dptr->ObWorld, &lptr->LightWorld); + } + LOCALASSERT(lptr->LightRange!=0); + lptr->BrightnessOverRange = DIV_FIXED(MUL_FIXED(lptr->LightBright,LightScale),lptr->LightRange); + } + + +} + + + + + + + + + + + + + + +/****************************************************************************/ + +/* + + Find out which light sources are in range of the object. + +*/ + + + + +/* + + Initialise the Renderer + +*/ + +void InitialiseRenderer(void) +{ + InitialiseObjectBlocks(); + InitialiseStrategyBlocks(); + + InitialiseTxAnimBlocks(); + + InitialiseLightBlocks(); + InitialiseVDBs(); + + /* KJL 14:46:42 09/09/98 */ + InitialiseLightIntensityStamps(); +} + + + + + +/* + + General View Volume Test for Objects and Sub-Object Trees + + This function returns returns "Yes" / "True" for an if() + +*/ + +int AVPViewVolumeTest(VIEWDESCRIPTORBLOCK *VDB_Ptr, DISPLAYBLOCK *dblockptr) +{ + int or = dblockptr->ObRadius; + + /* Perform the view volume plane tests */ + + if( + AVPViewVolumePlaneTest(&VDB_Ptr->VDB_ClipZPlane, dblockptr, or) && + AVPViewVolumePlaneTest(&VDB_Ptr->VDB_ClipLeftPlane, dblockptr, or) && + AVPViewVolumePlaneTest(&VDB_Ptr->VDB_ClipRightPlane, dblockptr, or) && + AVPViewVolumePlaneTest(&VDB_Ptr->VDB_ClipUpPlane, dblockptr, or) && + AVPViewVolumePlaneTest(&VDB_Ptr->VDB_ClipDownPlane, dblockptr, or)) + return Yes; + + else + return No; + +} +/* + + View Volume Plane Test + + Make the ODB VSL relative to the VDB Clip Plane POP and dot the resultant + vector with the Clip Plane Normal. + +*/ + +int AVPViewVolumePlaneTest(CLIPPLANEBLOCK *cpb, DISPLAYBLOCK *dblockptr, int or) +{ + VECTORCH POPRelObView; + + MakeVector(&dblockptr->ObView, &cpb->CPB_POP, &POPRelObView); + + if(DotProduct(&POPRelObView, &cpb->CPB_Normal) < or) return Yes; + else return No; +} + + +#if MIRRORING_ON +void CheckIfMirroringIsRequired(void) +{ + extern char LevelName[]; + extern MODULE * playerPherModule; + + MirroringActive = 0; + #if 0 + if ( (!stricmp(LevelName,"e3demo")) || (!stricmp(LevelName,"e3demosp")) ) + { + int numOfObjects = NumActiveBlocks; + + while(numOfObjects) + { + DISPLAYBLOCK *objectPtr = ActiveBlockList[--numOfObjects]; + MODULE *modulePtr = objectPtr->ObMyModule; + + /* if it's a module, which isn't inside another module */ + if (modulePtr && modulePtr->name) + { + if(!stricmp(modulePtr->name,"marine01b")) + { + if(ModuleCurrVisArray[modulePtr->m_index] == 2) + { + MirroringActive = 1; + MirroringAxis = -149*2; + break; + } + } + } + } + + if (playerPherModule && playerPherModule->name) + { + textprint("<%s>\n",playerPherModule->name); + if((!stricmp(playerPherModule->name,"predator")) + ||(!stricmp(playerPherModule->name,"predator01")) + ||(!stricmp(playerPherModule->name,"predator03")) + ||(!stricmp(playerPherModule->name,"predator02")) ) + { + MirroringActive = 1; + MirroringAxis = -7164*2; + } + } + } + else + #endif + #if 1 + if (!stricmp(LevelName,"derelict")) + { + if (playerPherModule && playerPherModule->name) + { + if((!stricmp(playerPherModule->name,"start")) + ||(!stricmp(playerPherModule->name,"start-en01")) ) + { + MirroringActive = 1; + MirroringAxis = -5596*2; + } + } + } + #endif +} +#endif + +#define MinChangeInXSize 8 +void MakeViewingWindowSmaller(void) +{ + extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + int MinChangeInYSize = (ScreenDescriptorBlock.SDB_Height*MinChangeInXSize)/ScreenDescriptorBlock.SDB_Width; + + if (Global_VDB_Ptr->VDB_ClipLeftVDB_ClipLeft +=MinChangeInXSize; + Global_VDB_Ptr->VDB_ClipRight -=MinChangeInXSize; + Global_VDB_Ptr->VDB_ClipUp +=MinChangeInYSize; + Global_VDB_Ptr->VDB_ClipDown -=MinChangeInYSize; + } + if(AvP.PlayerType == I_Alien) + { + Global_VDB_Ptr->VDB_ProjX = (Global_VDB_Ptr->VDB_ClipRight - Global_VDB_Ptr->VDB_ClipLeft)/4; + Global_VDB_Ptr->VDB_ProjY = (Global_VDB_Ptr->VDB_ClipDown - Global_VDB_Ptr->VDB_ClipUp)/4; + } + else + { + Global_VDB_Ptr->VDB_ProjX = (Global_VDB_Ptr->VDB_ClipRight - Global_VDB_Ptr->VDB_ClipLeft)/2; + Global_VDB_Ptr->VDB_ProjY = (Global_VDB_Ptr->VDB_ClipDown - Global_VDB_Ptr->VDB_ClipUp)/2; + } + //BlankScreen(); +} + +void MakeViewingWindowLarger(void) +{ + extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + int MinChangeInYSize = (ScreenDescriptorBlock.SDB_Height*MinChangeInXSize)/ScreenDescriptorBlock.SDB_Width; + + if (Global_VDB_Ptr->VDB_ClipLeft>0) + { + Global_VDB_Ptr->VDB_ClipLeft -=MinChangeInXSize; + Global_VDB_Ptr->VDB_ClipRight +=MinChangeInXSize; + Global_VDB_Ptr->VDB_ClipUp -=MinChangeInYSize; + Global_VDB_Ptr->VDB_ClipDown +=MinChangeInYSize; + } + if(AvP.PlayerType == I_Alien) + { + Global_VDB_Ptr->VDB_ProjX = (Global_VDB_Ptr->VDB_ClipRight - Global_VDB_Ptr->VDB_ClipLeft)/4; + Global_VDB_Ptr->VDB_ProjY = (Global_VDB_Ptr->VDB_ClipDown - Global_VDB_Ptr->VDB_ClipUp)/4; + } + else + { + Global_VDB_Ptr->VDB_ProjX = (Global_VDB_Ptr->VDB_ClipRight - Global_VDB_Ptr->VDB_ClipLeft)/2; + Global_VDB_Ptr->VDB_ProjY = (Global_VDB_Ptr->VDB_ClipDown - Global_VDB_Ptr->VDB_ClipUp)/2; + } +} + + +extern void AlienBiteAttackHasHappened(void) +{ + extern int AlienTongueOffset; + extern int AlienTeethOffset; + + AlienBiteAttackInProgress = 1; + + CameraZoomScale = 0.25f; + AlienTongueOffset = ONE_FIXED; + AlienTeethOffset = 0; +} + diff --git a/3dc/avp/BH_ALIEN.C b/3dc/avp/BH_ALIEN.C new file mode 100644 index 0000000..ea3cc6d --- /dev/null +++ b/3dc/avp/BH_ALIEN.C @@ -0,0 +1,2496 @@ +/*------------------------Patrick 6/11/96----------------------------- + Source file for alien AI behaviour functions.... + --------------------------------------------------------------------*/ +#include "3dc.h" + +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "dynblock.h" +#include "dynamics.h" +#include "comp_shp.h" +#include "load_shp.h" +#include "bh_types.h" +#include "bh_debri.h" +#include "bh_far.h" +#include "bh_near.h" +#include "bh_gener.h" +#include "bh_pred.h" +#include "bh_alien.h" +#include "bh_marin.h" +#include "weapons.h" +#include "pheromon.h" +#include "pfarlocs.h" +#include "pvisible.h" +#include "psnd.h" +#include "psndplat.h" +#include "extents.h" +#include "huddefs.h" +#include "pldghost.h" +#include "bh_corpse.h" +#include "bh_dummy.h" +#include "game_statistics.h" +#include "scream.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "pldnet.h" +#include "AvP_UserProfile.h" + +/* external global variables used in this file */ +extern int ModuleArraySize; +extern char *ModuleCurrVisArray; +extern int NormalFrameTime; +extern unsigned char Null_Name[8]; +extern ACTIVESOUNDSAMPLE ActiveSounds[]; + +extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); +extern void StartAlienAttackSequence(STRATEGYBLOCK *sbPtr); + +extern int NearAliens; +extern int Alt_NearAliens; +extern int FarAliens; +extern int Alt_FarAliens; +extern int ShowHiveState; + +/* prototypes for this file */ + +void KillAlien(STRATEGYBLOCK *sbPtr, int wounds, DAMAGE_PROFILE *damage, int multiple,VECTORCH *incoming); +void Execute_Alien_Dying(STRATEGYBLOCK *sbPtr); +STRATEGYBLOCK *Alien_GetNewTarget(VECTORCH *alienpos, STRATEGYBLOCK *me); +void CreateAlienBot(VECTORCH *Position,int type); + +/*----------------------Patrick 15/11/96----------------------------- + Alien's map: used to generate display blocks for aliens when they + come into view + +--------------------------------------------------------------------*/ +/* KJL 17:16:34 11/25/96 - I've wrapped the necessary fields in the +mapblock with #if StandardStrategyAndCollisions */ + +MODULEMAPBLOCK AlienDefaultMap = +{ + MapType_Sprite, + I_ShapeCube, /* default value */ + 0,0,0, + 0,0,0, + ObFlag_NoInfLSrc|ObFlag_MultLSrc, + 0, + 0, + 0, + 0, + 0, + 0,0,0, + 0, + 0, + 0,0,0, +}; + +/* CDF 12/2/98 */ + +void CastAlienBot(void) { + + #define BOTRANGE 2000 + + VECTORCH position; + #if 0 + if (AvP.Network!=I_No_Network) { + NewOnScreenMessage("NO ALIENBOTS IN MULTIPLAYER MODE"); + return; + } + #endif + position=Player->ObStrategyBlock->DynPtr->Position; + position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE); + position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE); + position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE); + + CreateAlienBot(&position,0); + +} + +void CastPredAlienBot(void) { + + #define BOTRANGE 2000 + + VECTORCH position; + #if 0 + if (AvP.Network!=I_No_Network) { + NewOnScreenMessage("NO ALIENBOTS IN MULTIPLAYER MODE"); + return; + } + #endif + position=Player->ObStrategyBlock->DynPtr->Position; + position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE); + position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE); + position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE); + + CreateAlienBot(&position,1); + +} + +void CastPraetorianBot(void) { + + #define BOTRANGE 2000 + + VECTORCH position; + #if 0 + if (AvP.Network!=I_No_Network) { + NewOnScreenMessage("NO ALIENBOTS IN MULTIPLAYER MODE"); + return; + } + #endif + position=Player->ObStrategyBlock->DynPtr->Position; + position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE); + position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE); + position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE); + + CreateAlienBot(&position,2); + +} + +void CreateAlienBot(VECTORCH *Position,int type) +{ + STRATEGYBLOCK* sbPtr; + + /* create and initialise a strategy block */ + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) { + NewOnScreenMessage("FAILED TO CREATE BOT: SB CREATION FAILURE"); + return; /* failure */ + } + InitialiseSBValues(sbPtr); + + sbPtr->I_SBtype = I_BehaviourAlien; + + AssignNewSBName(sbPtr); + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ALIEN_NPC); + if(sbPtr->DynPtr) + { + EULER zeroEuler = {0,0,0}; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + dynPtr->PrevPosition = dynPtr->Position = *Position; + dynPtr->OrientEuler = zeroEuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + } + else + { + /* dynamics block allocation failed... */ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: DYNBLOCK CREATION FAILURE"); + return; + } + + sbPtr->shapeIndex = 0; + + sbPtr->maintainVisibility = 1; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0); + + /* create, initialise and attach an alien data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(ALIEN_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + SECTION *root_section; + ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr; + int i; + + NPC_InitMovementData(&(alienStatus->moveData)); + NPC_InitWanderData(&(alienStatus->wanderData)); + switch (type) { + case 0: + default: + alienStatus->Type = AT_Standard; + break; + case 1: + alienStatus->Type = AT_Predalien; + break; + case 2: + alienStatus->Type = AT_Praetorian; + break; + } + + /* Initialise alien's stats */ + { + NPC_DATA *NpcData; + + switch (alienStatus->Type) { + case AT_Standard: + NpcData=GetThisNpcData(I_NPC_Alien); + alienStatus->MaxSpeed=ALIEN_FORWARDVELOCITY; + alienStatus->EnableWaypoints=1; + alienStatus->PreferToCrouch=0; + sbPtr->DynPtr->Mass = ALIEN_MASS; + break; + case AT_Predalien: + NpcData=GetThisNpcData(I_NPC_PredatorAlien); + alienStatus->MaxSpeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,PREDALIEN_SPEED_FACTOR); + alienStatus->EnableWaypoints=1; + alienStatus->PreferToCrouch=0; + sbPtr->DynPtr->Mass = PREDALIEN_MASS; + break; + case AT_Praetorian: + NpcData=GetThisNpcData(I_NPC_PraetorianGuard); + alienStatus->MaxSpeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,MUL_FIXED(PRAETORIAN_WALKSPEED_FACTOR,PRAETORIAN_SPEED_FACTOR)); + alienStatus->EnableWaypoints=0; + alienStatus->PreferToCrouch=0; + sbPtr->DynPtr->Mass = PRAETORIAN_MASS; + break; + default: + GLOBALASSERT(0); + break; + } + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + + + alienStatus->Health = ALIEN_STARTING_HEALTH; + alienStatus->GibbFactor=0; + alienStatus->Wounds=0; + alienStatus->last_anim_length=ONE_FIXED; + sbPtr->integrity = alienStatus->Health; + alienStatus->BehaviourState = ABS_Hunt; + alienStatus->current_attack=NULL; + + alienStatus->Target=NULL; + COPY_NAME(alienStatus->Target_SBname,Null_Name); + alienStatus->Mission=AM_Hunt; /* Was GlobalHunt... */ + + alienStatus->my_containing_module=NULL; + alienStatus->huntingModule=NULL; + + Initialise_AvoidanceManager(sbPtr,&alienStatus->avoidanceManager); + InitWaypointManager(&alienStatus->waypointManager); + + alienStatus->CurveRadius = 0; + alienStatus->CurveLength = 0; + alienStatus->CurveTimeOut = 0; + alienStatus->FarStateTimer = ALIEN_FAR_MOVE_TIME; + alienStatus->NearStateTimer = 0; + alienStatus->IAmCrouched = 0; + + alienStatus->soundHandle = SOUND_NOACTIVEINDEX; + alienStatus->soundHandle2 = SOUND_NOACTIVEINDEX; + + alienStatus->incidentFlag=0; + alienStatus->incidentTimer=0; + + //alien created by generator won't have a death target + for(i=0;ideath_target_ID[i] =0; + alienStatus->death_target_sbptr=0; + + //this alien wasn't produced by a generator + alienStatus->generator_sbptr=0; + + + alienStatus->HModelController.section_data=NULL; + alienStatus->HModelController.Deltas=NULL; + + switch (alienStatus->Type) { + case AT_Standard: + root_section=GetNamedHierarchyFromLibrary("hnpcalien","alien"); + break; + case AT_Predalien: + root_section=GetNamedHierarchyFromLibrary("hnpcpred_alien","TEMPLATE"); + break; + case AT_Praetorian: + root_section=GetNamedHierarchyFromLibrary("hnpcpretorian","Template"); + break; + default: + GLOBALASSERT(0); + break; + } + + if (!root_section) { + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: NO HMODEL"); + return; + } + Create_HModel(&alienStatus->HModelController,root_section); + InitHModelSequence(&alienStatus->HModelController,0,0,ONE_FIXED); + + if (SLUGTRAIL_MODE) { + SECTION_DATA *leg; + /* Blow off a leg? */ + leg=GetThisSectionData(alienStatus->HModelController.section_data,"left thigh"); + if (leg) { + Prune_HModel_Virtual(leg); + alienStatus->Wounds|=section_flag_left_leg; + alienStatus->Wounds|=section_flag_left_foot; + + sbPtr->SBDamageBlock.Health-=(20<HModelController,(int)HMSQT_AlienStand,(int)ASSS_Hit_Right)) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&alienStatus->HModelController,"HitDelta",(int)HMSQT_AlienStand,(int)ASSS_Hit_Right,-1); + GLOBALASSERT(delta); + delta->Playing=0; + } + + /* Containment test NOW! */ + if(!(sbPtr->containingModule)) + { + /* no containing module can be found... abort*/ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: MODULE CONTAINMENT FAILURE"); + return; + } + LOCALASSERT(sbPtr->containingModule); + + if (HModelSequence_Exists(&alienStatus->HModelController,HMSQT_AlienRun,ARSS_Jump)) { + alienStatus->JumpDetected=1; + } else { + alienStatus->JumpDetected=0; + } + + if (GetAlienPounceAttack(&alienStatus->HModelController,0,1)) { + /* Pounce will be unset eventually. */ + alienStatus->PounceDetected=1; + alienStatus->EnablePounce=1; + } else { + alienStatus->PounceDetected=0; + alienStatus->EnablePounce=0; + } + + alienStatus->aliensIgniterId=NULL; + + MakeAlienNear(sbPtr); + + NewOnScreenMessage("ALIENBOT CREATED"); + + } + else + { + /* no data block can be allocated */ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: MALLOC FAILURE"); + return; + } + +} + + +/*----------------------Patrick 15/11/96----------------------------- +This function is called by the alien generators, to dynamically +create a new alien, during the game. The alien is initialised +as invisible. + +1. create a new strategy block (no diplay block) +2. attach a dynamics block +3. attach an alien data block +4. initialise for far behaviour + +NB the strategyblock passed here is a reference to the generator sb +--------------------------------------------------------------------*/ +void CreateAlienDynamic(STRATEGYBLOCK *Generator, ALIEN_TYPE type_of_alien) +{ + STRATEGYBLOCK* sbPtr; + //int i; + + + /* create and initialise a strategy block */ + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) return; /* failure */ + InitialiseSBValues(sbPtr); + + sbPtr->I_SBtype = I_BehaviourAlien; + + AssignNewSBName(sbPtr); + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ALIEN_NPC); + if(sbPtr->DynPtr) + { + EULER zeroEuler = {0,0,0}; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + dynPtr->PrevPosition = dynPtr->Position = ((GENERATOR_BLOCK* )Generator->SBdataptr)->Position; + dynPtr->OrientEuler = zeroEuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + } + else + { + /* dynamics block allocation failed... */ + RemoveBehaviourStrategy(sbPtr); + return; + } + + sbPtr->shapeIndex = Generator->shapeIndex; + + sbPtr->maintainVisibility = 1; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0); + LOCALASSERT(sbPtr->containingModule); + if(!(sbPtr->containingModule)) + { + /* no containing module can be found... abort*/ + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* assert alien is starting as invisible */ + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)] == 0); + + /* create, initialise and attach an alien data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(ALIEN_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + SECTION *root_section; + ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr; + int i; + + NPC_InitMovementData(&(alienStatus->moveData)); + NPC_InitWanderData(&(alienStatus->wanderData)); + + alienStatus->Type = type_of_alien; + + /* Initialise alien's stats */ + { + NPC_DATA *NpcData; + + switch (alienStatus->Type) { + case AT_Standard: + NpcData=GetThisNpcData(I_NPC_Alien); + alienStatus->MaxSpeed=ALIEN_FORWARDVELOCITY; + alienStatus->EnableWaypoints=1; + alienStatus->PreferToCrouch=0; + sbPtr->DynPtr->Mass = ALIEN_MASS; + break; + case AT_Predalien: + NpcData=GetThisNpcData(I_NPC_PredatorAlien); + alienStatus->MaxSpeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,PREDALIEN_SPEED_FACTOR); + alienStatus->EnableWaypoints=1; + alienStatus->PreferToCrouch=0; + sbPtr->DynPtr->Mass = PREDALIEN_MASS; + break; + case AT_Praetorian: + NpcData=GetThisNpcData(I_NPC_PraetorianGuard); + alienStatus->MaxSpeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,MUL_FIXED(PRAETORIAN_WALKSPEED_FACTOR,PRAETORIAN_SPEED_FACTOR)); + alienStatus->EnableWaypoints=0; + alienStatus->PreferToCrouch=0; + sbPtr->DynPtr->Mass = PRAETORIAN_MASS; + break; + default: + GLOBALASSERT(0); + break; + } + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + + + alienStatus->Health = ALIEN_STARTING_HEALTH; + alienStatus->GibbFactor=0; + alienStatus->Wounds=0; + alienStatus->last_anim_length=ONE_FIXED; + sbPtr->integrity = alienStatus->Health; + alienStatus->BehaviourState = ABS_Hunt; + alienStatus->current_attack=NULL; + alienStatus->Wounds=0; + + alienStatus->Target=NULL; + COPY_NAME(alienStatus->Target_SBname,Null_Name); + alienStatus->Mission=AM_Hunt; + + alienStatus->my_containing_module=NULL; + alienStatus->huntingModule=NULL; + + alienStatus->CurveRadius = 0; + alienStatus->CurveLength = 0; + alienStatus->CurveTimeOut = 0; + alienStatus->FarStateTimer = ALIEN_FAR_MOVE_TIME; + alienStatus->NearStateTimer = 0; + alienStatus->IAmCrouched = 0; + + Initialise_AvoidanceManager(sbPtr,&alienStatus->avoidanceManager); + InitWaypointManager(&alienStatus->waypointManager); + + alienStatus->soundHandle = SOUND_NOACTIVEINDEX; + alienStatus->soundHandle2 = SOUND_NOACTIVEINDEX; + + alienStatus->incidentFlag=0; + alienStatus->incidentTimer=0; + + //alien created by generator won't have a death target + for(i=0;ideath_target_ID[i] =0; + alienStatus->death_target_sbptr=0; + + //note the generator that produced this alien + alienStatus->generator_sbptr=Generator; + + switch (alienStatus->Type) { + case AT_Standard: + root_section=GetNamedHierarchyFromLibrary("hnpcalien","alien"); + break; + case AT_Predalien: + root_section=GetNamedHierarchyFromLibrary("hnpcpred_alien","TEMPLATE"); + break; + case AT_Praetorian: + root_section=GetNamedHierarchyFromLibrary("hnpcpretorian","Template"); + break; + default: + GLOBALASSERT(0); + break; + } + + Create_HModel(&alienStatus->HModelController,root_section); + InitHModelSequence(&alienStatus->HModelController,0,0,ONE_FIXED); + + if (SLUGTRAIL_MODE) { + SECTION_DATA *leg; + /* Blow off a leg? */ + leg=GetThisSectionData(alienStatus->HModelController.section_data,"left thigh"); + if (leg) { + Prune_HModel_Virtual(leg); + alienStatus->Wounds|=section_flag_left_leg; + alienStatus->Wounds|=section_flag_left_foot; + + sbPtr->SBDamageBlock.Health-=(20<HModelController,(int)HMSQT_AlienStand,(int)ASSS_Hit_Right)) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&alienStatus->HModelController,"HitDelta",(int)HMSQT_AlienStand,(int)ASSS_Hit_Right,-1); + GLOBALASSERT(delta); + delta->Playing=0; + } + + ProveHModel_Far(&alienStatus->HModelController,sbPtr); + + if (HModelSequence_Exists(&alienStatus->HModelController,HMSQT_AlienRun,ARSS_Jump)) { + alienStatus->JumpDetected=1; + } else { + alienStatus->JumpDetected=0; + } + + if (GetAlienPounceAttack(&alienStatus->HModelController,0,1)) { + /* Pounce will be unset eventually. */ + alienStatus->PounceDetected=1; + alienStatus->EnablePounce=1; + } else { + alienStatus->PounceDetected=0; + alienStatus->EnablePounce=0; + } + alienStatus->aliensIgniterId=NULL; + + } + else + { + /* no data block can be allocated */ + RemoveBehaviourStrategy(sbPtr); + return; + } +} + +/*----------------------Patrick 7/11/96----------------------------- +This function is used to initialise a riff-loaded in alien. +-------------------------------------------------------------------*/ +void InitAlienBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr) +{ + TOOLS_DATA_ALIEN *toolsData = (TOOLS_DATA_ALIEN *)bhdata; + int i; + + /* check we're not in a net game */ + if(AvP.Network != I_No_Network && !AvP.NetworkAIServer) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* strategy block should be initialised to general default values: + I_behaviourAlien, shapeIndex, and everything else 0.... + + NB it is necessary that placed aliens are initialised without a + displayblock, otherwise far aliens will be re-initialised by + MakeAlienFar() to a hunting state instead of a wait state....*/ + LOCALASSERT(!(sbPtr->SBdptr)); + + /* strategy block initialisation */ + sbPtr->shapeIndex = toolsData->shapeIndex; + + if(AvP.Network==I_No_Network) + { + for(i=0;iSBname[i] = toolsData->nameID[i]; + } + else + { + //in a network game , generate a new sb name (so that it gets a reasonably low value) + AssignNewSBName(sbPtr); + } + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ALIEN_NPC); + if(sbPtr->DynPtr) + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + dynPtr->PrevPosition = dynPtr->Position = toolsData->position; + dynPtr->OrientEuler = toolsData->starteuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + } + else + { + /* no dynamics block can be allocated */ + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* create, initialise and attach an alien data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(ALIEN_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + SECTION *root_section; + ALIEN_STATUS_BLOCK * alienStatus = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr; + + NPC_InitMovementData(&(alienStatus->moveData)); + NPC_InitWanderData(&(alienStatus->wanderData)); + + alienStatus->Type = toolsData->type; + + /* Initialise alien's stats */ + { + NPC_DATA *NpcData; + + switch (alienStatus->Type) { + case AT_Standard: + NpcData=GetThisNpcData(I_NPC_Alien); + alienStatus->MaxSpeed=ALIEN_FORWARDVELOCITY; + alienStatus->EnableWaypoints=1; + alienStatus->PreferToCrouch=0; + sbPtr->DynPtr->Mass = ALIEN_MASS; + break; + case AT_Predalien: + NpcData=GetThisNpcData(I_NPC_PredatorAlien); + alienStatus->MaxSpeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,PREDALIEN_SPEED_FACTOR); + alienStatus->EnableWaypoints=1; + alienStatus->PreferToCrouch=0; + sbPtr->DynPtr->Mass = PREDALIEN_MASS; + break; + case AT_Praetorian: + NpcData=GetThisNpcData(I_NPC_PraetorianGuard); + alienStatus->MaxSpeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,MUL_FIXED(PRAETORIAN_WALKSPEED_FACTOR,PRAETORIAN_SPEED_FACTOR)); + alienStatus->EnableWaypoints=0; + alienStatus->PreferToCrouch=0; + sbPtr->DynPtr->Mass = PRAETORIAN_MASS; + break; + default: + GLOBALASSERT(0); + break; + } + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + + alienStatus->Health = ALIEN_STARTING_HEALTH; + sbPtr->integrity = alienStatus->Health; + alienStatus->GibbFactor=0; + alienStatus->Wounds=0; + alienStatus->last_anim_length=ONE_FIXED; + + if (toolsData->start_inactive) { + alienStatus->BehaviourState = ABS_Dormant; + } else { + alienStatus->BehaviourState = ABS_Wait; + } + + alienStatus->current_attack=NULL; + alienStatus->Wounds=0; + + alienStatus->Target=NULL; + COPY_NAME(alienStatus->Target_SBname,Null_Name); + alienStatus->Mission=AM_Hunt; + + alienStatus->my_containing_module=NULL; + alienStatus->huntingModule=NULL; + + alienStatus->CurveRadius = 0; + alienStatus->CurveLength = 0; + alienStatus->CurveTimeOut = 0; + alienStatus->FarStateTimer = ALIEN_FAR_MOVE_TIME; + alienStatus->NearStateTimer = 0; + alienStatus->IAmCrouched = 0; + + Initialise_AvoidanceManager(sbPtr,&alienStatus->avoidanceManager); + InitWaypointManager(&alienStatus->waypointManager); + + alienStatus->soundHandle = SOUND_NOACTIVEINDEX; + alienStatus->soundHandle2 = SOUND_NOACTIVEINDEX; + + alienStatus->incidentFlag=0; + alienStatus->incidentTimer=0; + + for(i=0;ideath_target_ID[i] = toolsData->death_target_ID[i]; + alienStatus->death_target_sbptr=0; + + //this alien wasn't produced by a generator + alienStatus->generator_sbptr=0; + + + switch (alienStatus->Type) { + case AT_Standard: + root_section=GetNamedHierarchyFromLibrary("hnpcalien","alien"); + break; + case AT_Predalien: + root_section=GetNamedHierarchyFromLibrary("hnpcpred_alien","TEMPLATE"); + break; + case AT_Praetorian: + root_section=GetNamedHierarchyFromLibrary("hnpcpretorian","Template"); + break; + default: + GLOBALASSERT(0); + break; + } + + Create_HModel(&alienStatus->HModelController,root_section); + + if (toolsData->start_inactive) { + if (HModelSequence_Exists(&alienStatus->HModelController,HMSQT_AlienStand,ASSS_Dormant)) { + InitHModelSequence(&alienStatus->HModelController,HMSQT_AlienStand,ASSS_Dormant,-1); + } else { + InitHModelSequence(&alienStatus->HModelController,HMSQT_AlienStand,ASSS_Standard,ONE_FIXED); + } + } else { + InitHModelSequence(&alienStatus->HModelController,0,0,ONE_FIXED); + } + + if (SLUGTRAIL_MODE) { + SECTION_DATA *leg; + /* Blow off a leg? */ + leg=GetThisSectionData(alienStatus->HModelController.section_data,"left thigh"); + if (leg) { + Prune_HModel_Virtual(leg); + alienStatus->Wounds|=section_flag_left_leg; + alienStatus->Wounds|=section_flag_left_foot; + + sbPtr->SBDamageBlock.Health-=(20<HModelController,(int)HMSQT_AlienStand,(int)ASSS_Hit_Right)) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&alienStatus->HModelController,"HitDelta",(int)HMSQT_AlienStand,(int)ASSS_Hit_Right,-1); + GLOBALASSERT(delta); + delta->Playing=0; + } + + ProveHModel_Far(&alienStatus->HModelController,sbPtr); + + if (HModelSequence_Exists(&alienStatus->HModelController,HMSQT_AlienRun,ARSS_Jump)) { + alienStatus->JumpDetected=1; + } else { + alienStatus->JumpDetected=0; + } + + if (GetAlienPounceAttack(&alienStatus->HModelController,0,1)) { + /* Pounce will be unset eventually. */ + alienStatus->PounceDetected=1; + alienStatus->EnablePounce=1; + } else { + alienStatus->PounceDetected=0; + alienStatus->EnablePounce=0; + } + + alienStatus->aliensIgniterId=NULL; + + } + else + { + /* no data block can be allocated */ + RemoveBehaviourStrategy(sbPtr); + return; + } +} + + +static BOOL PlayerIsDeadAndNoLivingNetghosts() +{ + if(AvP.Network == I_No_Network) + { + //just need to check for the only player we have + return NPC_IsDead(Player->ObStrategyBlock); + + } + else + { + int sbIndex; + //first check the host player + if(!NPC_IsDead(Player->ObStrategyBlock)) return FALSE; + + /* go through the strategy blocks looking for players*/ + for(sbIndex=0;sbIndexI_SBtype!=I_BehaviourNetGhost) continue; + ghostData = (NETGHOSTDATABLOCK *)playerSbPtr->SBdataptr; + + if(ghostData->type==I_BehaviourMarinePlayer || + ghostData->type==I_BehaviourPredatorPlayer) + { + //found a nethost of a player + return FALSE; + } + } + } + //Dead, all dead. + return TRUE; +} + +/*----------------------Patrick 7/11/96----------------------------- +AI alien behaviour execution shell: + +1. patch to trap aliens who's current module is not set (and set it). +2. call the visibility checking function. +3. select either near or far behaviour functions. + +NB the visibility checking function initialises near/far behaviour and +allocates/deallocates displayblock based on changes in visibility +for the alien's module. This will, in due course, be invoked by a +call back function from the module handler. +--------------------------------------------------------------------*/ + +void AlienBehaviour(STRATEGYBLOCK *sbPtr) +{ + /* get the alien's status block */ + ALIEN_STATUS_BLOCK *alienStatusPointer; + int alienIsNear; + + LOCALASSERT(sbPtr); + alienStatusPointer= (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + /* test if we've got a containing module: if we haven't, do nothing. + This is important as the alien could have been marked for deletion by the visibility + management system...*/ + if(!sbPtr->containingModule) + { + DestroyAnyStrategyBlock(sbPtr); /* just to make sure */ + return; + } + + if(sbPtr->SBdptr) { + alienIsNear=1; + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]); + } else { + alienIsNear=0; + } + + /* Unset incident flag. */ + alienStatusPointer->incidentFlag=0; + + alienStatusPointer->incidentTimer-=NormalFrameTime; + + if (alienStatusPointer->incidentTimer<0) { + alienStatusPointer->incidentFlag=1; + alienStatusPointer->incidentTimer=32767+(FastRandom()&65535); + } + + if(alienStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(alienStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + + if (sbPtr->SBDamageBlock.IsOnFire) { + + if (alienStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + if (ActiveSounds[alienStatusPointer->soundHandle].soundIndex!=SID_FIRE) { + Sound_Stop(alienStatusPointer->soundHandle); + Sound_Play(SID_FIRE,"dlev",&(sbPtr->DynPtr->Position),&alienStatusPointer->soundHandle,127); + } + } else { + Sound_Play(SID_FIRE,"dlev",&(sbPtr->DynPtr->Position),&alienStatusPointer->soundHandle,127); + } + //for multiplayer games it is necessary to say who is doing this damage + //(that would be the person who set the alien on fire in the first place) + { + extern DPID myNetworkKillerId; + extern DPID AVPDPNetID; + + myNetworkKillerId=alienStatusPointer->aliensIgniterId; + CauseDamageToObject(sbPtr,&firedamage,NormalFrameTime,NULL); + myNetworkKillerId=AVPDPNetID; + } + if (sbPtr->I_SBtype==I_BehaviourNetCorpse) { + /* Gettin' out of here... */ + return; + } + } else { + if (alienStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + if (ActiveSounds[alienStatusPointer->soundHandle].soundIndex==SID_FIRE) { + Sound_Stop(alienStatusPointer->soundHandle); + } + } + } + + if (alienStatusPointer->GibbFactor) { + /* If you're gibbed, you're dead. */ + sbPtr->SBDamageBlock.Health = 0; + } + + /* check if we've been killed */ + if ( (sbPtr->SBDamageBlock.Health <= 0)&&(alienStatusPointer->BehaviourState!=ABS_Dying) ) + { + textprint("Zombie Alien!!! State is %d.\n",alienStatusPointer->BehaviourState); + return; + } + + if ((alienStatusPointer->BehaviourState!=ABS_Dying) + &&(alienStatusPointer->BehaviourState!=ABS_Dormant) + &&(alienStatusPointer->BehaviourState!=ABS_Awakening)) { + + /* Target handling. */ + if (Validate_Target(alienStatusPointer->Target,alienStatusPointer->Target_SBname)==0) { + + /* Target must be dead... */ + alienStatusPointer->Target=NULL; + /* Now try to get a new target. */ + } + + if ((alienIsNear)||(alienStatusPointer->incidentFlag)) { + if (alienStatusPointer->Target==NULL) { + + alienStatusPointer->Target=Alien_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr); + + if (alienStatusPointer->Target!=NULL) { + textprint("Alien gets new target.\n"); + + COPY_NAME(alienStatusPointer->Target_SBname,alienStatusPointer->Target->SBname); + + if (alienStatusPointer->BehaviourState!=ABS_Wait) { + alienStatusPointer->BehaviourState=ABS_Hunt; + } + alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME; + alienStatusPointer->NearStateTimer = 0; + + } else { + textprint("Alien found no target!\n"); + if (alienStatusPointer->BehaviourState!=ABS_Wait) { + AIMODULE *targetModule; + /* Hunt or wander? */ + if ((AvP.PlayerType==I_Alien)||(Observer)) { + /* Eew! What a nasty hack! Eeeww! */ + targetModule = FarNPC_GetTargetAIModuleForGlobalHunt(sbPtr); + } else { + /* This just makes them hunt a bit more... */ + targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr,1); + } + + if ((!targetModule)||(PlayerIsDeadAndNoLivingNetghosts())) { + if (alienStatusPointer->BehaviourState!=ABS_Wander) { + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME; + alienStatusPointer->NearStateTimer = 0; + } + alienStatusPointer->BehaviourState=ABS_Wander; + } else { + if (alienStatusPointer->BehaviourState!=ABS_Hunt) { + alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME; + alienStatusPointer->NearStateTimer = 0; + } + alienStatusPointer->BehaviourState=ABS_Hunt; + } + } + } + } + } + } + + if(sbPtr->SBdptr) + { + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]); + #if 0/*SupportWindows95 */ + textprint("Near Alien in module %s \n",sbPtr->containingModule->name); + #endif + NearAlienBehaviour(sbPtr); + Alt_NearAliens++; + } + else + { + /* NB if this assert fires, we may just have run out of displayblocks */ + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)] == 0); + #if 0/*SupportWindows95 */ + textprint("Far Alien in module %s \n",sbPtr->containingModule->name); + #endif + FarAlienBehaviour(sbPtr); + Alt_FarAliens++; + } + + /* if we have actually died, we need to remove the strategyblock... so + do this here */ + if((alienStatusPointer->BehaviourState == ABS_Dying)&&(alienStatusPointer->NearStateTimer <= 0)) { + + if(alienStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(alienStatusPointer->soundHandle); + if(alienStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) Sound_Stop(alienStatusPointer->soundHandle2); + DestroyAnyStrategyBlock(sbPtr); + } + + /* Update containing module? */ + if (sbPtr->containingModule!=alienStatusPointer->my_containing_module) { + /* This is to slow down new hunting target computation. */ + alienStatusPointer->my_containing_module=sbPtr->containingModule; + } + + /* Update delta playing flag. */ + { + DELTA_CONTROLLER *hitdelta; + + hitdelta=Get_Delta_Sequence(&alienStatusPointer->HModelController,"HitDelta"); + + if (hitdelta) { + if (DeltaAnimation_IsFinished(hitdelta)) { + hitdelta->Playing=0; + } + } + } +} + + + +/*----------------------Patrick 7/11/96----------------------------- +This pair of functions handle the alien visibility switching.... +Note that the ai-pheromone system is maintained by these functions. +--------------------------------------------------------------------*/ +void MakeAlienNear(STRATEGYBLOCK *sbPtr) +{ + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + ALIEN_STATUS_BLOCK *alienStatusPointer= (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + LOCALASSERT(sbPtr->SBdptr == NULL); + + /* first of all, see how many aliens are currently near: if there are too many, + destroy this alien, and try to force a generator to make a replacement */ + if(NumGeneratorNPCsVisible() >= MAX_VISIBLEGENERATORNPCS) + { + DestroyAnyStrategyBlock(sbPtr); + ForceAGenerator(); + } + + AlienDefaultMap.MapShape = sbPtr->shapeIndex; + tempModule.m_mapptr = &AlienDefaultMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 0; + tempModule.m_lightarray = (struct lightblock *)0; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr=NULL; + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) return; /* cannot create displayblock: leave alien far */ + + sbPtr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbPtr; + dPtr->ObMyModule = NULL; + + + /*Copy extents from the collision extents in extents.c*/ + dPtr->ObMinX=-CollisionExtents[CE_ALIEN].CollisionRadius; + dPtr->ObMaxX=CollisionExtents[CE_ALIEN].CollisionRadius; + dPtr->ObMinZ=-CollisionExtents[CE_ALIEN].CollisionRadius; + dPtr->ObMaxZ=CollisionExtents[CE_ALIEN].CollisionRadius; + dPtr->ObMinY=CollisionExtents[CE_ALIEN].CrouchingTop; + dPtr->ObMaxY=CollisionExtents[CE_ALIEN].Bottom; + dPtr->ObRadius = 1000; + /* also need to initialise positional information in the new display block, + from the existing dynamics block. + NB this necessary because this function is (usually) called between the + dynamics and rendering systems so it is not initialised by the dynamics + system the first frame it is drawn. */ + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + + /* init state timers */ + alienStatusPointer->NearStateTimer = 0; + alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME; + alienStatusPointer->CurveRadius = 0; + alienStatusPointer->CurveLength = 0; + alienStatusPointer->CurveTimeOut = 0; + + /* zero linear velocity in dynamics block */ + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + + /* initialise our sequence data */ + //dPtr->ShapeAnimControlBlock = &alienStatusPointer->ShpAnimCtrl; + dPtr->HModelControlBlock=&alienStatusPointer->HModelController; + + ProveHModel(dPtr->HModelControlBlock,dPtr); + + if(AlienShouldBeCrawling(sbPtr)) alienStatusPointer->IAmCrouched = 1; + else alienStatusPointer->IAmCrouched = 0; + + RecomputeAlienSpeed(sbPtr); + + InitWaypointManager(&alienStatusPointer->waypointManager); + + /* initialise our near state and specific sequence */ + if ((alienStatusPointer->BehaviourState == ABS_Dying) + ||(alienStatusPointer->BehaviourState == ABS_Dormant) + ||(alienStatusPointer->BehaviourState == ABS_Awakening)) { + /* Do nothing. */ + } else if(alienStatusPointer->BehaviourState == ABS_Wait) { + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Wait; + if(alienStatusPointer->IAmCrouched) SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienCrouch,(int)ACrSS_Standard,ONE_FIXED); + else SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienStand,(int)ASSS_Standard,ONE_FIXED); + } else if(AlienIsAwareOfTarget(sbPtr)) { + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + if(alienStatusPointer->IAmCrouched) SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienCrawl,(int)ACSS_Standard,ONE_FIXED>>1); + else SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienRun,(int)ARSS_Standard,ONE_FIXED>>1); + } else { + NPC_InitMovementData(&(alienStatusPointer->moveData)); + /* Was Wander, now Hunt. Hunt should kick in wander if needed. */ + alienStatusPointer->BehaviourState = ABS_Hunt; + if(alienStatusPointer->IAmCrouched) SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienCrawl,(int)ACSS_Standard,ONE_FIXED>>1); + else SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienRun,(int)ARSS_Standard,ONE_FIXED>>1); + } +} + +void MakeAlienFar(STRATEGYBLOCK *sbPtr) +{ + /* get the alien's status block */ + ALIEN_STATUS_BLOCK *alienStatusPointer; + int i; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + LOCALASSERT(sbPtr->SBdptr != NULL); + + /* get rid of the displayblock */ + if(sbPtr->SBdptr) + { + i = DestroyActiveObject(sbPtr->SBdptr); + LOCALASSERT(i==0); + sbPtr->SBdptr = NULL; + } + + if(alienStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(alienStatusPointer->soundHandle); + if(alienStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) Sound_Stop(alienStatusPointer->soundHandle2); + + /* initialise our far state */ + if ((alienStatusPointer->BehaviourState!=ABS_Dying) + &&(alienStatusPointer->BehaviourState!=ABS_Dormant) + &&(alienStatusPointer->BehaviourState!=ABS_Awakening)) { + /* No zombie aliens here! */ + if(AlienIsAwareOfTarget(sbPtr)) + { + alienStatusPointer->BehaviourState = ABS_Hunt; + } + else + { + alienStatusPointer->BehaviourState = ABS_Wander; + } + } + + NPC_InitWanderData(&(alienStatusPointer->wanderData)); + /* init state timers */ + alienStatusPointer->NearStateTimer = 0; + alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME; + + /* zero linear velocity in dynamics block */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; +} + + +static void DoAlienAIHiss(STRATEGYBLOCK *sbPtr) { + + DYNAMICSBLOCK *dynPtr; + int pitch = (FastRandom() & 255) - 128; + SOUNDINDEX soundIndex; + ALIEN_STATUS_BLOCK *alienStatusPointer; + + GLOBALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + GLOBALASSERT(alienStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX); + + /* This one is for ALIEN DAMAGE SCREAM. */ + + soundIndex=SID_NOSOUND; + + if (alienStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + PlayAlienSound((int)alienStatusPointer->Type,ASC_Scream_Hurt,pitch, + &alienStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + + if (AvP.Network != I_No_Network) + { + AddNetMsg_SpotAlienSound(ASC_Scream_Hurt,(int)alienStatusPointer->Type,pitch,&dynPtr->Position); + } + + } + + +} + +static void DoAlienDeathScream(STRATEGYBLOCK *sbPtr) { + + DYNAMICSBLOCK *dynPtr; + SOUNDINDEX soundIndex; + ALIEN_STATUS_BLOCK *alienStatusPointer; + + GLOBALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + GLOBALASSERT(alienStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX); + + soundIndex=SID_NOSOUND; + + /* This one is for ALIEN DEATH SCREAM. */ + + soundIndex=SID_NOSOUND; + + if (alienStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + PlayAlienSound((int)alienStatusPointer->Type,ASC_Scream_Dying,0, + &alienStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + + if (AvP.Network != I_No_Network) + { + AddNetMsg_SpotAlienSound((int)ASC_Scream_Dying,(int)alienStatusPointer->Type,0,&dynPtr->Position); + } + } + + +} + +static void DoAlienDeathSound(STRATEGYBLOCK *sbPtr) { + + DYNAMICSBLOCK *dynPtr; + SOUNDINDEX soundIndex; + ALIEN_STATUS_BLOCK *alienStatusPointer; + + GLOBALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + soundIndex=SID_NOSOUND; + + /* This one is for ALIEN DEATH SOUND. */ + + soundIndex=SID_NOSOUND; + + PlayAlienSound((int)alienStatusPointer->Type,ASC_Death,0, + NULL,&sbPtr->DynPtr->Position); + + #if 0 + if (AvP.Network != I_No_Network) + { + soundIndex=ActiveSounds[alienStatusPointer->soundHandle2].soundIndex; + if (soundIndex!=SID_NOSOUND) { + AddNetMsg_SpotAlienSound(soundIndex,pitch,&dynPtr->Position); + } + } + #endif + +} + +extern void DoAlienLimbLossSound(VECTORCH *position) { + + /* This one is for ALIEN LIMBLOSS SOUND. */ + + PlayAlienSound(0,ASC_LimbLoss,0,NULL,position); + +} + +/*----------------------Patrick 7/11/96----------------------------- +Handle weapon impact on an alien +--------------------------------------------------------------------*/ +/* KJL 11:46:43 12/17/96 - rewritten */ + +// JB 16/6/97 rewritten +// Patrick 29/7/97 rewritten again. again. +// ChrisF 16/9/97 rewritten again again, again. +// ChrisF 26/11/97 rewritten again, again, again, again. +// ChrisF 1/4/98 rewritten again again again again again. Okay, 'modified' then. Added directional parameter. +// ChrisF 20/11/98 rewritten again again again again again again, added hit delta support. +// ChrisF 15/2/99 rewritten again again again again again again again, added fragging noise. + +void AlienIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,SECTION_DATA *Section,VECTORCH *incoming, DISPLAYBLOCK *frag) +{ + + int tkd; + ALIEN_STATUS_BLOCK *alienStatusPointer; + GLOBALASSERT(sbPtr); + + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + LOCALASSERT(sbPtr); + + alienStatusPointer->Wounds|=wounds; + + if (incoming) { + textprint("Alien hit from %d %d %d\n",incoming->vx,incoming->vy,incoming->vz); + /* Knockback effects? */ + } + + if (frag) { + DoAlienLimbLossSound(&sbPtr->DynPtr->Position); + } + +#if 0 + ALIEN_STATUS_BLOCK *alienStatusPointer; + GLOBALASSERT(sbPtr); + + /* reduce alien health */ + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + if(alienStatusPointer->Health>0) (alienStatusPointer->Health) -= damage; +#endif + /* Perhaps I'd better explain... I now handle damage + for you. These functions now are only for special effects, + and if you need to do anything when damage happens. */ + + if (alienStatusPointer->BehaviourState==ABS_Dormant) { + Alien_Awaken(sbPtr); + } + + /* Speaking of which... */ + { + + /* reduce alien health */ + + if (sbPtr->SBDamageBlock.Health <= 0) { + + /* Oh yes, kill them, too. */ + if (alienStatusPointer->BehaviourState!=ABS_Dying) + { + if (AvP.PlayerType!=I_Alien) { + CurrentGameStats_CreatureKilled(sbPtr,Section); + } + KillAlien(sbPtr,wounds,damage,multiple,incoming); + } + + } else { + #if WOUNDING_SPEED_EFFECTS + /* Alien wounding effects? */ + int factor; + int changespeed; + + RecomputeAlienSpeed(sbPtr); + + /* Now, get anim speed. */ + factor=GetAlienSpeedFactor(sbPtr); + changespeed=0; + + switch (alienStatusPointer->Type) { + case AT_Standard: + if (factor!=ONE_FIXED) { + changespeed=1; + } + break; + case AT_Predalien: + if (factor!=PREDALIEN_SPEED_FACTOR) { + changespeed=1; + } + break; + case AT_Praetorian: + if (factor!=PRAETORIAN_SPEED_FACTOR) { + changespeed=1; + } + break; + default: + GLOBALASSERT(0); + break; + } + + if (changespeed) { + int newspeed; + /* ONE_FIXED implies we're playing an invariant length anim. */ + newspeed=DIV_FIXED(alienStatusPointer->last_anim_length,factor); + + HModel_ChangeSpeed(&alienStatusPointer->HModelController,newspeed); + } + #endif + + /* If you got here, you should still be alive. */ + + if ((alienStatusPointer->BehaviourState!=ABS_Dying)&&(alienStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX)) { + DoAlienAIHiss(sbPtr); + } + + tkd=TotalKineticDamage(damage); + + if (tkd>=10) { + /* If not dead, play a hit delta. */ + DELTA_CONTROLLER *hitdelta; + int frontback; + + hitdelta=Get_Delta_Sequence(&alienStatusPointer->HModelController,"HitDelta"); + + if (incoming) { + if (incoming->vz>=0) { + frontback=0; + } else { + frontback=1; + } + } else { + /* Default to front. */ + frontback=1; + } + + /* Only do it from the front. */ + if ((hitdelta)&&(frontback)) { + if (hitdelta->Playing==0) { + /* A hierarchy with hit deltas! */ + int CrouchSubSequence; + int StandSubSequence; + + if (Section==NULL) { + if ((FastRandom()&65535)<32767) { + CrouchSubSequence=ACrSS_Hit_Left; + StandSubSequence=ASSS_Hit_Left; + } else { + CrouchSubSequence=ACrSS_Hit_Right; + StandSubSequence=ASSS_Hit_Right; + } + } else if ((Section->sempai->flags§ion_flag_left_arm) + ||(Section->sempai->flags§ion_flag_left_hand)) { + + CrouchSubSequence=ACrSS_Hit_Left; + StandSubSequence=ASSS_Hit_Left; + } else if ((Section->sempai->flags§ion_flag_right_arm) + ||(Section->sempai->flags§ion_flag_right_hand)) { + + CrouchSubSequence=ACrSS_Hit_Right; + StandSubSequence=ASSS_Hit_Right; + + } else { + /* Chest or misc. hit. */ + if ((FastRandom()&65535)<32767) { + CrouchSubSequence=ACrSS_Hit_Left; + StandSubSequence=ASSS_Hit_Left; + } else { + CrouchSubSequence=ACrSS_Hit_Right; + StandSubSequence=ASSS_Hit_Right; + } + } + + + if(alienStatusPointer->IAmCrouched) { + if (HModelSequence_Exists(&alienStatusPointer->HModelController,(int)HMSQT_AlienCrouch,CrouchSubSequence)) { + Start_Delta_Sequence(hitdelta,(int)HMSQT_AlienCrouch,CrouchSubSequence,-1); + } + } else { + if (HModelSequence_Exists(&alienStatusPointer->HModelController,(int)HMSQT_AlienStand,StandSubSequence)) { + Start_Delta_Sequence(hitdelta,(int)HMSQT_AlienStand,StandSubSequence,-1); + } + } + hitdelta->Playing=1; + /* Not looped. */ + if (alienStatusPointer->BehaviourState==ABS_Attack) { + StartAlienAttackSequence(sbPtr); + alienStatusPointer->NearStateTimer = ALIEN_ATTACKTIME; + } + } + } + } + } + } + +} + +/* patrick 29/7/97 ----------------------------------- +This function to be called only from behaviour +-- ChrisF 1/4/98 What a stupid idea. This function --- +-- to be called only from AlienIsDamaged. ------------ +------------------------------------------------------*/ +void KillAlien(STRATEGYBLOCK *sbPtr,int wounds,DAMAGE_PROFILE *damage, int multiple,VECTORCH *incoming) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + int tkd,deathtype; + SECTION_DATA *head; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + + + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + /* make a sound. Just this once without a check. */ + + DoAlienDeathSound(sbPtr); + + /*If alien has a death target ,send a request*/ + if(alienStatusPointer->death_target_sbptr) + { + RequestState(alienStatusPointer->death_target_sbptr,1, 0); + } + + /* Set up gibb factor. */ + + tkd=TotalKineticDamage(damage); + deathtype=0; + + if (damage->ExplosivePower==1) { + /* Explosion case. */ + if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) { + /* Okay, you can gibb now. */ + alienStatusPointer->GibbFactor=ONE_FIXED>>1; + deathtype=2; + } + } else if ((tkd<40)&&((multiple>>16)>1)) { + int newmult; + + newmult=DIV_FIXED(multiple,NormalFrameTime); + if (MUL_FIXED(tkd,newmult)>700) { + /* Excessive bullets case 1. */ + alienStatusPointer->GibbFactor=ONE_FIXED>>2; + deathtype=2; + } else if (MUL_FIXED(tkd,newmult)>250) { + /* Excessive bullets case 2. */ + alienStatusPointer->GibbFactor=ONE_FIXED>>3; + deathtype=1; + } + } + + /* Predaliens and preatorians only gibb for sadars. */ + if (alienStatusPointer->Type!=AT_Standard) { + alienStatusPointer->GibbFactor=0; + /* But retain deathtype. */ + } + + if ((damage->ExplosivePower==2)||(damage->ExplosivePower==6)) { + /* Basically SADARS only. */ + if (alienStatusPointer->Type==AT_Standard) { + alienStatusPointer->GibbFactor=ONE_FIXED; + } else { + alienStatusPointer->GibbFactor=ONE_FIXED>>2; + } + deathtype=3; + } + + if (damage->ForceBoom) { + deathtype+=damage->ForceBoom; + } + + if ( (damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire!=0) + &&(damage->Electrical==0) + &&(damage->Acid==0)) + { + /* that sounds like the flamethrower... */ + alienStatusPointer->GibbFactor=ONE_FIXED>>2; + /* Gibb just a little for now. */ + } + + if (damage->Id==AMMO_PREDPISTOL_STRIKE) { + /* Blow up if hit by the bolt. */ + alienStatusPointer->GibbFactor=ONE_FIXED>>3; + } else if (damage->Id==AMMO_FLECHETTE_POSTMAX) { + alienStatusPointer->GibbFactor=ONE_FIXED>>2; + } + + { + SECTION_DATA *chest=GetThisSectionData(alienStatusPointer->HModelController.section_data,"chest"); + + if (chest==NULL) { + /* I'm impressed. */ + deathtype+=2; + } else if ((chest->flags§ion_data_notreal) + &&(chest->flags§ion_data_terminate_here)) { + /* That's gotta hurt. */ + deathtype++; + } + } + + /* Gibb noise? */ + if (alienStatusPointer->GibbFactor) { + DoAlienLimbLossSound(&sbPtr->DynPtr->Position); + } else { + /* make a sound... if you have a head. */ + head=GetThisSectionData(alienStatusPointer->HModelController.section_data,"head"); + + /* Is it still attached? */ + if (head) { + if (head->flags§ion_data_notreal) { + head=NULL; + } + } + + if ((alienStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX)&&(head)) { + DoAlienDeathScream(sbPtr); + } + } + + /* More restrained death than before... */ + { + + + DEATH_DATA *this_death; + HIT_FACING facing; + int electrical; + + facing.Front=0; + facing.Back=0; + facing.Left=0; + facing.Right=0; + + if (incoming) { + if (incoming->vz>0) { + facing.Back=1; + } else { + facing.Front=1; + } + if (incoming->vx>0) { + facing.Right=1; + } else { + facing.Left=1; + } + } + + if ((damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire==0) + &&(damage->Electrical>0) + &&(damage->Acid==0) + ) { + electrical=1; + } else { + electrical=0; + } + + this_death=GetAlienDeathSequence(&alienStatusPointer->HModelController,NULL,alienStatusPointer->Wounds,alienStatusPointer->Wounds, + deathtype,&facing,0,alienStatusPointer->IAmCrouched,electrical); + + #if 0 + GLOBALASSERT(this_death); + + SetAlienShapeAnimSequence_Core(sbPtr,this_death->Sequence_Type,this_death->Sub_Sequence, + this_death->Sequence_Length,this_death->TweeningTime); + + alienStatusPointer->NearStateTimer=ALIEN_DYINGTIME; + alienStatusPointer->HModelController.Looped=0; + alienStatusPointer->HModelController.LoopAfterTweening=0; + /* switch state */ + alienStatusPointer->BehaviourState=ABS_Dying; + + /* stop sound, if we have one */ + if(alienStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(alienStatusPointer->soundHandle); + + /* stop motion */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->Friction = 400000; + sbPtr->DynPtr->LinImpulse.vx+=sbPtr->DynPtr->LinVelocity.vx; + sbPtr->DynPtr->LinImpulse.vy+=sbPtr->DynPtr->LinVelocity.vy; + sbPtr->DynPtr->LinImpulse.vz+=sbPtr->DynPtr->LinVelocity.vz; + sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; + sbPtr->DynPtr->IgnoreSameObjectsAsYou = 1; + /* Experiment... */ + sbPtr->DynPtr->UseStandardGravity=1; + sbPtr->DynPtr->Mass = 160; + /* Okay... */ + #else + Convert_Alien_To_Corpse(sbPtr,this_death,damage); + #endif + } +} + +void Execute_Alien_Dying(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + + LOCALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + //sbPtr->DynPtr->LinVelocity.vx = 0; + //sbPtr->DynPtr->LinVelocity.vy = 0; + //sbPtr->DynPtr->LinVelocity.vz = 0; + + //sbPtr->DynPtr->LinImpulse.vx = 0; + //sbPtr->DynPtr->LinImpulse.vy = 0; + //sbPtr->DynPtr->LinImpulse.vz = 0; + + { + DISPLAYBLOCK *dispPtr = sbPtr->SBdptr; + /* do we have a displayblock? */ + if (dispPtr) + { + dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND; + dispPtr->ObFlags2 = alienStatusPointer->NearStateTimer/2; + + } + } + alienStatusPointer->NearStateTimer -= NormalFrameTime; +} + +void RecomputeAlienSpeed(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + int factor,basespeed; + + LOCALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + /* Change max speed. */ + factor=GetAlienSpeedFactor_ForSequence(sbPtr,HMSQT_AlienRun,(int)ARSS_Standard); + + switch (alienStatusPointer->Type) { + case AT_Standard: + default: + basespeed=ALIEN_FORWARDVELOCITY; + break; + case AT_Predalien: + basespeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,PREDALIEN_SPEED_FACTOR); + break; + case AT_Praetorian: + /* Could this be dependent on crouching? */ + if (alienStatusPointer->IAmCrouched) { + basespeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,MUL_FIXED(PRAETORIAN_CRAWLSPEED_FACTOR,PRAETORIAN_SPEED_FACTOR)); + } else { + basespeed=MUL_FIXED(ALIEN_FORWARDVELOCITY,MUL_FIXED(PRAETORIAN_WALKSPEED_FACTOR,PRAETORIAN_SPEED_FACTOR)); + } + break; + } + + alienStatusPointer->MaxSpeed=MUL_FIXED(factor,basespeed); + +} + +/* Wounding effect function... */ + +int GetAlienSpeedFactor(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + HMODEL_SEQUENCE_TYPES sequence_type; + int subsequence; + + LOCALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + sequence_type=(HMODEL_SEQUENCE_TYPES)alienStatusPointer->HModelController.Sequence_Type; + subsequence=alienStatusPointer->HModelController.Sub_Sequence; + /* That is what the controller thinks the shape is playing. */ + + return(GetAlienSpeedFactor_ForSequence(sbPtr,sequence_type,subsequence)); + +} + +int GetAlienSpeedFactor_ForSequence(STRATEGYBLOCK *sbPtr, HMODEL_SEQUENCE_TYPES sequence_type,int subsequence) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + int factor,factortype; + + LOCALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + factortype=-1; + + switch (sequence_type) { + + case HMSQT_AlienRun: + switch ((ALIENRUN_SUBSEQUENCES)subsequence) { + case ARSS_Standard: + factortype=2; + break; + case ARSS_Attack_Swipe: + case ARSS_Jump: + factortype=1; + break; + case ARSS_Dies: + factortype=0; + break; + default: + GLOBALASSERT(0); + break; + } + break; + case HMSQT_AlienCrawl: + switch ((ALIENCRAWL_SUBSEQUENCES)subsequence) { + case ACSS_Standard: + case ACSS_Crawl_Hurt: + case ACSS_Scamper: + factortype=2; + break; + case ACSS_Attack_Bite: + case ACSS_Attack_Tail: + factortype=1; + break; + case ACSS_Dies: + case ACSS_Pain_Fall_Fwd: + case ACSS_Pain_Fall_Back: + case ACSS_Pain_Fall_Left: + case ACSS_Pain_Fall_Right: + case ACSS_Boom_Fall_Fwd: + case ACSS_Boom_Fall_Back: + case ACSS_Boom_Fall_Left: + case ACSS_Boom_Fall_Right: + factortype=0; + break; + default: + GLOBALASSERT(0); + break; + } + break; + case HMSQT_AlienStand: + switch ((ALIENSTAND_SUBSEQUENCES)subsequence) { + case ASSS_Taunt: + case ASSS_Taunt2: + case ASSS_Taunt3: + case ASSS_Fear: + case ASSS_Standard: + case ASSS_FidgetA: + case ASSS_FidgetB: + case ASSS_Attack_Right_Swipe_In: + case ASSS_Attack_Left_Swipe_In: + case ASSS_Attack_Both_In: + case ASSS_Attack_Both_Down: + case ASSS_Attack_Bite: + case ASSS_Attack_Tail: + case ASSS_Attack_Low_Left_Swipe: + case ASSS_Attack_Low_Right_Swipe: + case ASSS_Feed: + case ASSS_Unfurl: + case ASSS_Dormant: + factortype=1; + break; + case ASSS_Dies: + case ASSS_Pain_Fall_Fwd: + case ASSS_Pain_Fall_Back: + case ASSS_Pain_Fall_Left: + case ASSS_Pain_Fall_Right: + case ASSS_Boom_Fall_Fwd: + case ASSS_Boom_Fall_Back: + case ASSS_Boom_Fall_Left: + case ASSS_Boom_Fall_Right: + case ASSS_Spin_Clockwise: + case ASSS_Spin_Anticlockwise: + case ASSS_BurningDeath: + factortype=0; + break; + default: + GLOBALASSERT(0); + break; + } + break; + case HMSQT_AlienCrouch: + switch ((ALIENCROUCH_SUBSEQUENCES)subsequence) { + case ACrSS_Standard: + factortype=2; + break; + case ACrSS_Attack_Bite: + case ACrSS_Attack_Tail: + case ACrSS_Attack_Swipe: + case ACrSS_Pounce: + case ACrSS_Taunt: + factortype=1; + break; + case ACrSS_Dies: + case ACrSS_Dies_Thrash: + factortype=0; + break; + default: + GLOBALASSERT(0); + break; + } + break; + case HMSQT_Hugger: + default: + /* Nooooo! */ + GLOBALASSERT(0); + break; + } + + LOCALASSERT(factortype!=-1); + + switch (factortype) { + case 0: + return(ONE_FIXED); + break; + case 1: + { + /* Affected by alien type. */ + int prefactor; + + switch (alienStatusPointer->Type) { + case AT_Standard: + prefactor=ONE_FIXED; + break; + case AT_Predalien: + prefactor=PREDALIEN_SPEED_FACTOR; + break; + case AT_Praetorian: + prefactor=PRAETORIAN_SPEED_FACTOR; + break; + default: + GLOBALASSERT(0); + break; + } + + return(prefactor); + + } + break; + case 2: + { + /* More complex. Affected by alien type and health. */ + NPC_DATA *NpcData; + int prefactor; + + switch (alienStatusPointer->Type) { + case AT_Standard: + NpcData=GetThisNpcData(I_NPC_Alien); + prefactor=ONE_FIXED; + break; + case AT_Predalien: + NpcData=GetThisNpcData(I_NPC_PredatorAlien); + prefactor=PREDALIEN_SPEED_FACTOR; + break; + case AT_Praetorian: + NpcData=GetThisNpcData(I_NPC_PraetorianGuard); + prefactor=PRAETORIAN_SPEED_FACTOR; + break; + default: + GLOBALASSERT(0); + break; + } + + LOCALASSERT(NpcData); + + factor=sbPtr->SBDamageBlock.Health/NpcData->StartingStats.Health; + /* ONE_FIXED shift already included. */ + LOCALASSERT(factor<=ONE_FIXED); + + factor+=ONE_FIXED; + factor>>=1; + + /* Wounding effects. */ + if (alienStatusPointer->Wounds&(section_flag_left_leg|section_flag_right_leg)) { + /* Missing a leg. */ + factor-=(ONE_FIXED/3); + } else if ((alienStatusPointer->Wounds§ion_flag_left_foot) + &&(alienStatusPointer->Wounds§ion_flag_right_foot)) { + /* Missing both feet. */ + factor-=(ONE_FIXED>>2); + } else if ((alienStatusPointer->Wounds§ion_flag_left_foot) + ||(alienStatusPointer->Wounds§ion_flag_right_foot)) { + /* Missing one foot. */ + factor-=(ONE_FIXED>>3); + } + + if (factor<(ONE_FIXED>>3)) { + factor=(ONE_FIXED>>3); + } + + if (prefactor!=ONE_FIXED) { + factor=MUL_FIXED(prefactor,factor); + } + + return(factor); + } + break; + default: + GLOBALASSERT(0); + break; + } + + return(0); + +} + +int Alien_TargetFilter(STRATEGYBLOCK *candidate) { + + switch (candidate->I_SBtype) { + case I_BehaviourAlienPlayer: + case I_BehaviourMarinePlayer: + case I_BehaviourPredatorPlayer: + { + if (Observer) { + return(0); + } + + if(AvP.Network != I_No_Network) + { + //In multiplayer games we don't want the aliens to be going after + //the host once he's dead. + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (candidate->SBdataptr); + if(!playerStatusPtr->IsAlive) + { + return(0); + } + } + + switch(AvP.PlayerType) + { + case I_Marine: + case I_Predator: + return(1); + break; + case I_Alien: + return(0); + break; + default: + GLOBALASSERT(0); + return(0); + break; + } + break; + } + case I_BehaviourDummy: + { + DUMMY_STATUS_BLOCK *dummyStatusPointer; + dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(candidate->SBdataptr); + LOCALASSERT(dummyStatusPointer); + switch (dummyStatusPointer->PlayerType) { + case I_Marine: + case I_Predator: + return(1); + break; + case I_Alien: + return(0); + break; + default: + GLOBALASSERT(0); + return(0); + break; + } + break; + } + case I_BehaviourQueenAlien: + case I_BehaviourFaceHugger: + case I_BehaviourAlien: + { + return(0); + break; + } + case I_BehaviourPredator: + case I_BehaviourXenoborg: + case I_BehaviourMarine: + case I_BehaviourSeal: + case I_BehaviourPredatorAlien: + /* Valid. */ + return(1); + break; + #if SupportWindows95 + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *dataptr; + dataptr=candidate->SBdataptr; + switch (dataptr->type) { + case I_BehaviourMarinePlayer: + case I_BehaviourPredatorPlayer: + return(1); + //return(0); + break; + case I_BehaviourAlienPlayer: + default: + return(0); + break; + } + } + break; + #endif + default: + return(0); + break; + } + +} + +STRATEGYBLOCK *Alien_GetNewTarget(VECTORCH *alienpos, STRATEGYBLOCK *me) { + + int neardist; + STRATEGYBLOCK *nearest; + int a; + STRATEGYBLOCK *candidate; + MODULE *dmod; + + dmod=ModuleFromPosition(alienpos,playerPherModule); + + LOCALASSERT(dmod); + + nearest=NULL; + neardist=ONE_FIXED; + + for (a=0; aDynPtr) { + if (Alien_TargetFilter(candidate)) { + VECTORCH offset; + int dist; + + offset.vx=alienpos->vx-candidate->DynPtr->Position.vx; + offset.vy=alienpos->vy-candidate->DynPtr->Position.vy; + offset.vz=alienpos->vz-candidate->DynPtr->Position.vz; + + dist=Approximate3dMagnitude(&offset); + /* Preferentially ignore predators? */ + if (candidate->I_SBtype==I_BehaviourPredator) { + dist<<=2; + } + + if (distSBdptr) { + if (!NPC_IsDead(candidate)) { + if ((IsModuleVisibleFromModule(dmod,candidate->containingModule))) { + nearest=candidate; + neardist=dist; + } + } + //} + } + } + } + } + } + + #if 0 + if (nearest==NULL) { + if (Alien_TargetFilter(Player->ObStrategyBlock)) { + nearest=Player->ObStrategyBlock; + } else { + nearest=NULL; /* Erk! */ + } + } + #endif + + return(nearest); + +} + +void Alien_Awaken(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + + LOCALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + alienStatusPointer->BehaviourState = ABS_Awakening; + + if(HModelSequence_Exists(&alienStatusPointer->HModelController,HMSQT_AlienStand,ASSS_Unfurl)) { + SetAlienShapeAnimSequence_Core(sbPtr,HMSQT_AlienStand,ASSS_Unfurl,-1,(ONE_FIXED>>2)); + } else { + SetAlienShapeAnimSequence_Core(sbPtr,HMSQT_AlienStand,ASSS_Standard,(ONE_FIXED),(ONE_FIXED>>2)); + } + alienStatusPointer->HModelController.LoopAfterTweening=0; + +} + + +void Alien_GoToApproach(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + + LOCALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + InitWaypointManager(&alienStatusPointer->waypointManager); + if(alienStatusPointer->IAmCrouched) { + SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienCrawl,(int)ACSS_Standard,ONE_FIXED>>1); + } else { + SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienRun,(int)ARSS_Standard,ONE_FIXED>>1); + } + RecomputeAlienSpeed(sbPtr); + alienStatusPointer->CurveTimeOut = 0; + alienStatusPointer->NearStateTimer = 0; + +} + +int AlienIsCrawling(STRATEGYBLOCK *sbPtr) { + + /* For external calls. */ + + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + if (sbPtr->I_SBtype!=I_BehaviourAlien) { + return(0); + } + + if (dynPtr->UseStandardGravity!=0) { + return(0); + } else { + return(1); + } +} + + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" +typedef struct alien_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + ALIEN_TYPE Type; + signed char Health; + int GibbFactor; + int Wounds; + int last_anim_length; + ALIEN_BHSTATE BehaviourState; + int PounceDetected; + int JumpDetected; + int EnablePounce; + + + int incidentFlag; + int incidentTimer; + + ALIEN_MISSION Mission; + + int CurveRadius; + int CurveLength; + int CurveTimeOut; + int FarStateTimer; + int NearStateTimer; + int IAmCrouched; + + + int huntingModuleIndex; + int currentAttackCode; +// NPC_MOVEMENTDATA moveData; + NPC_WANDERDATA wanderData; + +// HMODELCONTROLLER HModelController; + +// STRATEGYBLOCK* generator_sbptr;//0 unless created by a generator + + char Target_SBname[SB_NAME_LENGTH]; + + char Generator_SBname[SB_NAME_LENGTH]; + + //strategyblock stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; + DYNAMICSBLOCK dynamics; +}ALIEN_SAVE_BLOCK; + + + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV alienStatusPointer + + +void LoadStrategy_Alien(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + ALIEN_STATUS_BLOCK* alienStatusPointer; + ALIEN_SAVE_BLOCK* block = (ALIEN_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + + if(sbPtr) + { + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourAlien) return; + } + else + { + //we will have to generate an alien then + TOOLS_DATA_ALIEN tda; + + //make sure the alien is in a module + if(!ModuleFromPosition(&block->dynamics.Position,NULL)) return; + + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) return; + + sbPtr->I_SBtype = I_BehaviourAlien; + sbPtr->shapeIndex = 0; + sbPtr->maintainVisibility = 1; + COPY_NAME(sbPtr->SBname,block->header.SBname); + + //create using a fake tools data + tda.position = block->dynamics.Position; + tda.shapeIndex = 0; + COPY_NAME(tda.nameID,block->header.SBname); + COPY_NAME(tda.death_target_ID,Null_Name); + tda.type = block->Type; + tda.start_inactive = 0; + + tda.starteuler.EulerX = 0; + tda.starteuler.EulerY = 0; + tda.starteuler.EulerZ = 0; + + EnableBehaviourType(sbPtr,I_BehaviourAlien , &tda ); + + } + + + alienStatusPointer = (ALIEN_STATUS_BLOCK*)sbPtr->SBdataptr; + + //start copying stuff + + COPYELEMENT_LOAD(Type) + COPYELEMENT_LOAD(Health) + COPYELEMENT_LOAD(GibbFactor) + COPYELEMENT_LOAD(Wounds) + COPYELEMENT_LOAD(last_anim_length) + COPYELEMENT_LOAD(BehaviourState) + COPYELEMENT_LOAD(PounceDetected) + COPYELEMENT_LOAD(JumpDetected) + COPYELEMENT_LOAD(EnablePounce) + COPYELEMENT_LOAD(incidentFlag) + COPYELEMENT_LOAD(incidentTimer) + COPYELEMENT_LOAD(Mission) + COPYELEMENT_LOAD(CurveRadius) + COPYELEMENT_LOAD(CurveLength) + COPYELEMENT_LOAD(CurveTimeOut) + COPYELEMENT_LOAD(FarStateTimer) + COPYELEMENT_LOAD(NearStateTimer) + COPYELEMENT_LOAD(IAmCrouched) + COPYELEMENT_LOAD(wanderData) + + //load target + COPY_NAME(alienStatusPointer->Target_SBname,block->Target_SBname); + alienStatusPointer->Target = FindSBWithName(alienStatusPointer->Target_SBname); + + //load hunting module + if(block->huntingModuleIndex>=0 && block->huntingModuleIndex< AIModuleArraySize) + { + alienStatusPointer->huntingModule = &AIModuleArray[block->huntingModuleIndex]; + } + else + { + alienStatusPointer->huntingModule = NULL; + } + + //get the alien's attack from the attack code + alienStatusPointer->current_attack = GetThisAttack_FromUniqueCode(block->currentAttackCode); + + *sbPtr->DynPtr = block->dynamics; + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + + //find the alien's generator + alienStatusPointer->generator_sbptr = FindSBWithName(block->Generator_SBname); + + //load the aliens hierarchy + { + SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); + if(hier_header) + { + LoadHierarchy(hier_header,&alienStatusPointer->HModelController); + } + } + + Load_SoundState(&alienStatusPointer->soundHandle); + Load_SoundState(&alienStatusPointer->soundHandle2); +} + + +void SaveStrategy_Alien(STRATEGYBLOCK* sbPtr) +{ + ALIEN_SAVE_BLOCK *block; + ALIEN_STATUS_BLOCK* alienStatusPointer; + + + alienStatusPointer = (ALIEN_STATUS_BLOCK*)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + + COPYELEMENT_SAVE(Type) + COPYELEMENT_SAVE(Health) + COPYELEMENT_SAVE(GibbFactor) + COPYELEMENT_SAVE(Wounds) + COPYELEMENT_SAVE(last_anim_length) + COPYELEMENT_SAVE(BehaviourState) + COPYELEMENT_SAVE(PounceDetected) + COPYELEMENT_SAVE(JumpDetected) + COPYELEMENT_SAVE(EnablePounce) + COPYELEMENT_SAVE(incidentFlag) + COPYELEMENT_SAVE(incidentTimer) + COPYELEMENT_SAVE(Mission) + COPYELEMENT_SAVE(CurveRadius) + COPYELEMENT_SAVE(CurveLength) + COPYELEMENT_SAVE(CurveTimeOut) + COPYELEMENT_SAVE(FarStateTimer) + COPYELEMENT_SAVE(NearStateTimer) + COPYELEMENT_SAVE(IAmCrouched) + COPYELEMENT_SAVE(wanderData) + + + //save target + COPY_NAME(block->Target_SBname,alienStatusPointer->Target_SBname); + + //save hunting module + if(alienStatusPointer->huntingModule) + { + block->huntingModuleIndex = alienStatusPointer->huntingModule->m_index; + } + else + { + block->huntingModuleIndex = -1; + } + + //save attack code + if(alienStatusPointer->current_attack) + { + block->currentAttackCode = alienStatusPointer->current_attack->Unique_Code; + } + else + { + block->currentAttackCode = -1; + } + + //save the alien's generator name + if(alienStatusPointer->generator_sbptr) + { + COPY_NAME(block->Generator_SBname,alienStatusPointer->generator_sbptr->SBname); + } + else + { + COPY_NAME(block->Generator_SBname,Null_Name); + } + + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; + + //save the aliens hierarchy + SaveHierarchy(&alienStatusPointer->HModelController); + + Save_SoundState(&alienStatusPointer->soundHandle); + Save_SoundState(&alienStatusPointer->soundHandle2); +} diff --git a/3dc/avp/BH_ALIEN.H b/3dc/avp/BH_ALIEN.H new file mode 100644 index 0000000..647c64a --- /dev/null +++ b/3dc/avp/BH_ALIEN.H @@ -0,0 +1,260 @@ +/*--------------Patrick 7/11/96---------------- + Header file for Alien AI support functions + ---------------------------------------------*/ + +#ifndef _bhalien_h_ + #define _bhalien_h_ 1 + + + #ifdef __cplusplus + + extern "C" { + + #endif + +#include "bh_pred.h" + + /*-------------------------------------------- + Enum of alien behaviour states + --------------------------------------------*/ + + typedef enum AlienBhState + { + ABS_Wait, + ABS_Approach, + ABS_Hunt, + ABS_Wander, + ABS_Retreat, + ABS_Attack, + ABS_Avoidance, + ABS_Dying, + ABS_Pounce, + ABS_Jump, + ABS_Dormant, + ABS_Awakening, + ABS_Taunting, + }ALIEN_BHSTATE; + + /*-------------------------------------------- + Enum of alien animation sequences + --------------------------------------------*/ + + typedef enum AlienSequence + { + ASQ_Run, + ASQ_StandingAttack_Claw, + ASQ_Crawl, + ASQ_Stand, + ASQ_Crouch, + ASQ_CrouchedAttack_Claw, + ASQ_CrawlingAttack_Claw, + ASQ_RunningAttack_Claw, + ASQ_Pain, + ASQ_Jump, + /* Additions by ChrisF, 20/4/98 */ + ASQ_StandingTailPoise, + ASQ_StandingTailStrike, + ASQ_CrouchedTailPoise, + ASQ_CrouchedTailStrike, + ASQ_RunningTailPoise, + ASQ_RunningTailStrike, + ASQ_CrawlingTailPoise, + ASQ_CrawlingTailStrike, + ASQ_Eat, + ASQ_Pounce, + ASQ_JumpingTailPoise, + ASQ_JumpingTailStrike, + ASQ_Taunt, + ASQ_CrouchEat, + ASQ_Scamper, + /* More additions for reversing, 8/5/98 */ + ASQ_Run_Backwards, + ASQ_Crawl_Backwards, + ASQ_RunningAttack_Claw_Backwards, + ASQ_RunningTailPoise_Backwards, + ASQ_RunningTailStrike_Backwards, + ASQ_CrawlingTailPoise_Backwards, + ASQ_CrawlingTailStrike_Backwards, + ASQ_CrawlingAttack_Claw_Backwards, + ASQ_Scamper_Backwards, + }ALIEN_SEQUENCE; + + #include "sequnces.h" + + typedef enum AlienMissions { + AM_UndefinedBehaviour, // Should do nothing. + AM_Hunt, + AM_GlobalHunt, + } ALIEN_MISSION; + + typedef enum AlienType { + AT_Standard=0, + AT_Predalien, + AT_Praetorian, + } ALIEN_TYPE; + + /*-------------------------------------------- + Alien behaviour data block + --------------------------------------------*/ + typedef struct alienStatusBlock + { + ALIEN_TYPE Type; + signed char Health; + int GibbFactor; + int MaxSpeed; + int Wounds; + int last_anim_length; + ALIEN_BHSTATE BehaviourState; + ATTACK_DATA *current_attack; + int PounceDetected; + int JumpDetected; + int EnablePounce; + int EnableWaypoints; + int PreferToCrouch; + + MODULE *my_containing_module; + AIMODULE *huntingModule; + + int incidentFlag; + int incidentTimer; + + STRATEGYBLOCK *Target; + char Target_SBname[SB_NAME_LENGTH]; + ALIEN_MISSION Mission; + + int CurveRadius; + int CurveLength; + int CurveTimeOut; + int FarStateTimer; + int NearStateTimer; + int IAmCrouched; + NPC_MOVEMENTDATA moveData; + NPC_WANDERDATA wanderData; + + NPC_AVOIDANCEMANAGER avoidanceManager; + WAYPOINT_MANAGER waypointManager; + + HMODELCONTROLLER HModelController; + + char death_target_ID[SB_NAME_LENGTH]; //another strategy can be notified of the alien's death + STRATEGYBLOCK* death_target_sbptr; + + STRATEGYBLOCK* generator_sbptr;//0 unless created by a generator + + DPID aliensIgniterId;//Which player in a multiplayer game toasted this poor beast? + + int soundHandle; + int soundHandle2; + + /*The following three values are used by the extrapolation code for network games. + It doesn't particularly matter if they aren't initialised*/ + int timeOfLastSend; + VECTORCH lastFacingSent; + VECTORCH lastVelocitySent; + + }ALIEN_STATUS_BLOCK; + + + /*-------------------------------------------- + Tools data template + --------------------------------------------*/ + typedef struct tools_data_alien + { + struct vectorch position; + int shapeIndex; + char nameID[SB_NAME_LENGTH]; + char death_target_ID[SB_NAME_LENGTH]; + ALIEN_TYPE type; + int start_inactive; + struct euler starteuler; + }TOOLS_DATA_ALIEN; + + + +/*-------------------------------------------- + Defines + --------------------------------------------*/ + + #define ULTRAVIOLENCE 0 + #define ALIEN_STATE_PRINT 0 + #define WOUNDING_SPEED_EFFECTS 1 + + #define ALIEN_STARTING_HEALTH (30) + #if PSX||Saturn + #define NO_OF_FRAGMENTS_FROM_DEAD_ALIEN (5) + #else + #define NO_OF_FRAGMENTS_FROM_DEAD_ALIEN (10) + #endif + /* random time between 1.5 and 2 seconds,in fixed point, with granularity 1/32th second */ + #if ULTRAVIOLENCE + #define ALIEN_FAR_MOVE_TIME ((48+(FastRandom()&0xF))*(ONE_FIXED>>7)) + #else + #define ALIEN_FAR_MOVE_TIME ((48+(FastRandom()&0xF))*(ONE_FIXED>>5)) + #endif + /* random time between 1.5 and 2 seconds,in fixed point, with granularity 1/32th second */ + #define ALIEN_FAR_RETREAT_TIME ((48+(FastRandom()&0xF))*(ONE_FIXED>>5)) + #define ALIEN_JUMPVELOCITY (8000) + #define ALIEN_FORWARDVELOCITY (12000) + #define ALIEN_CURVEDISTANCE (8000) + #define ALIEN_ATTACKDISTANCE_MIN (2000) + /* Above (1500) for Ken: reduced from 2000 */ + /* 1/6/98, changed back to 2000. It was well bust. */ + #define ALIEN_ATTACKDISTANCE_MAX (4000) + #define ALIEN_ATTACKRANGE (3000) + /* Range check for damage validity. */ + #define ALIEN_ATTACKTIME (ONE_FIXED>>1) + /* random time between 1 and 2 seconds,in fixed point,with granularity 1/8th second */ + #define ALIEN_NEARWAITTIME (ONE_FIXED+((FastRandom()&0x7)*(ONE_FIXED>>3))) + + #define PREDALIEN_SPEED_FACTOR ((ONE_FIXED*8)/10) + #define PRAETORIAN_SPEED_FACTOR ((ONE_FIXED*8)/10) + #define PRAETORIAN_WALKSPEED_FACTOR ((ONE_FIXED*6)/5) + #define PRAETORIAN_CRAWLSPEED_FACTOR (ONE_FIXED*2) + + #define ALIEN_POUNCE_MAXRANGE (12000) + #define ALIEN_POUNCE_STARTMAXRANGE (8000) + #define ALIEN_POUNCE_MINRANGE (3000) + #define ALIEN_JUMP_SPEED (25000) + #define PREDALIEN_JUMP_SPEED (25000) + #define PRAETORIAN_JUMP_SPEED (25000) + + #define ALIEN_JUMPINESS (13106) + #define PREDALIEN_JUMPINESS (13106) + #define PRAETORIAN_JUMPINESS (13106) + + #define ALIEN_MASS (160) + #define PREDALIEN_MASS (200) + #define PRAETORIAN_MASS (250) + + #define ALL_NEW_AVOIDANCE_ALIEN 0 + +/*-------------------------------------------- + Prototypes + --------------------------------------------*/ + + void CreateAlienDynamic(STRATEGYBLOCK *Generator , ALIEN_TYPE type_of_alien); + void InitAlienBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr); + void AlienBehaviour(STRATEGYBLOCK *sbPtr); + void AlienIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,SECTION_DATA *Section,VECTORCH *incoming,DISPLAYBLOCK *frag); + void MakeAlienNear(STRATEGYBLOCK *sbPtr); + void MakeAlienFar(STRATEGYBLOCK *sbPtr); + int AlienShouldBeCrawling(STRATEGYBLOCK *sbPtr); + void SetAlienShapeAnimSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length); + void SetAlienShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime); + int AlienIsAwareOfTarget(STRATEGYBLOCK *sbPtr); + int AlienHasPathToOfTarget(STRATEGYBLOCK *sbPtr); + int GetAlienSpeedFactor(STRATEGYBLOCK *sbPtr); + int GetAlienSpeedFactor_ForSequence(STRATEGYBLOCK *sbPtr, HMODEL_SEQUENCE_TYPES sequence_type,int subsequence); + void RecomputeAlienSpeed(STRATEGYBLOCK *sbPtr); + void Alien_GoToApproach(STRATEGYBLOCK *sbPtr); + void Alien_Awaken(STRATEGYBLOCK *sbPtr); + int AlienIsCrawling(STRATEGYBLOCK *sbPtr); + + #ifdef __cplusplus + + } + + #endif + + +#endif \ No newline at end of file diff --git a/3dc/avp/BH_BINSW.C b/3dc/avp/BH_BINSW.C new file mode 100644 index 0000000..9c5028f --- /dev/null +++ b/3dc/avp/BH_BINSW.C @@ -0,0 +1,932 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "bh_binsw.h" +#include "dynblock.h" +#include "dynamics.h" +#include "pldghost.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +#include "pmove.h" +#include "pvisible.h" +#include "plat_shp.h" +#include "psnd.h" + +extern int NormalFrameTime; +extern int RealFrameTime; +extern int ReturnPlayerSecurityClearance(STRATEGYBLOCK *sbPtr, unsigned int securityLevel); + +/*********************** SWITCH INIT *****************************/ + +void* BinarySwitchBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr) +{ + BINARY_SWITCH_BEHAV_BLOCK *bs_bhv; + BIN_SWITCH_TOOLS_TEMPLATE *bs_tt; + int i; + + GLOBALASSERT(sbptr); + bs_bhv = (BINARY_SWITCH_BEHAV_BLOCK*)AllocateMem(sizeof(BINARY_SWITCH_BEHAV_BLOCK)); + if (!bs_bhv) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + + bs_bhv->bhvr_type = I_BehaviourBinarySwitch; + + // from loaders + // 1 rest_state - on or off + // 2 mode + // 3 timer switch - time for reset + // 4 security clerance to operate + // 5 copy the target name + + bs_tt = (BIN_SWITCH_TOOLS_TEMPLATE*)bhdata; + + sbptr->shapeIndex = bs_tt->shape_num; + COPY_NAME(sbptr->SBname, bs_tt->nameID); + + bs_bhv->bs_mode = bs_tt->mode; + bs_bhv->time_for_reset = bs_tt->time_for_reset; + bs_bhv->security_clerance = bs_tt->security_clearance; + + bs_bhv->trigger_volume_min=bs_tt->trigger_volume_min; + bs_bhv->trigger_volume_max=bs_tt->trigger_volume_max; + bs_bhv->switch_flags=bs_tt->switch_flags; + + + bs_bhv->num_targets = bs_tt->num_targets; + if(bs_tt->num_targets) + { + bs_bhv->target_names = (SBNAMEBLOCK *)AllocateMem(sizeof(SBNAMEBLOCK) * bs_tt->num_targets); + if (!bs_bhv->target_names) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + bs_bhv->request_messages = (int *)AllocateMem(sizeof(int) * bs_tt->num_targets); + if (!bs_bhv->request_messages) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + + bs_bhv->bs_targets = (STRATEGYBLOCK **)AllocateMem(sizeof(STRATEGYBLOCK *) * bs_tt->num_targets); + if (!bs_bhv->bs_targets) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + } + else + { + bs_bhv->target_names=0; + bs_bhv->request_messages=0; + bs_bhv->bs_targets=0; + } + for (i=0; inum_targets; i++) + { + COPY_NAME(bs_bhv->target_names[i].name, bs_tt->target_names[i].name); + bs_bhv->request_messages[i]=bs_tt->request_messages[i]; + bs_bhv->bs_targets[i] = 0; + } + if(sbptr->DynPtr) //there may be no shape + { + sbptr->DynPtr->Position = sbptr->DynPtr->PrevPosition = bs_tt->position; + sbptr->DynPtr->OrientEuler = bs_tt->orientation; + CreateEulerMatrix(&sbptr->DynPtr->OrientEuler, &sbptr->DynPtr->OrientMat); + TransposeMatrixCH(&sbptr->DynPtr->OrientMat); + } + // set up the animation control + if(sbptr->shapeIndex!=-1) + { + int item_num; + TXACTRLBLK **pptxactrlblk; + int shape_num = bs_tt->shape_num; + SHAPEHEADER *shptr = GetShapeData(shape_num); + + SetupPolygonFlagAccessForShape(shptr); + + pptxactrlblk = &bs_bhv->bs_tac; + + for(item_num = 0; item_num < shptr->numitems; item_num ++) + { + POLYHEADER *poly = (POLYHEADER*)(shptr->items[item_num]); + LOCALASSERT(poly); + + if((Request_PolyFlags((void *)poly)) & iflag_txanim) + { + TXACTRLBLK *pnew_txactrlblk; + int num_seq = 0; + + pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK)); + if (pnew_txactrlblk) + { + pnew_txactrlblk->tac_flags = 0; + pnew_txactrlblk->tac_item = item_num; + pnew_txactrlblk->tac_sequence = bs_tt->starts_on; + pnew_txactrlblk->tac_node = 0; + pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shape_num, item_num); + pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shape_num); + + while(pnew_txactrlblk->tac_txarray[num_seq+1])num_seq++; + + // Assert does not work at this point so + GLOBALASSERT(num_seq==2); + + /* set the flags in the animation header */ + // we only ever have one frame of animation per sequence - + // nb this can change talk to richard - one sequence with two frames + // or mutliple sequences??? + + pnew_txactrlblk->tac_txah.txa_flags |= txa_flag_play; + + /* change the value held in pptxactrlblk + which point to the previous structures "next" + pointer*/ + + *pptxactrlblk = pnew_txactrlblk; + pptxactrlblk = &pnew_txactrlblk->tac_next; + } + else + { + memoryInitialisationFailure = 1; + } + } + } + *pptxactrlblk=0; + } + else + { + //no shape - so there won't be any animation + bs_bhv->bs_tac=0; + } + + bs_bhv->bs_dtype = binswitch_no_display; + + + + if (bs_bhv->bs_tac) + { + bs_bhv->bs_dtype = binswitch_animate_me; + } + + bs_bhv->bs_track=bs_tt->track; + + if (bs_bhv->bs_track) + { + bs_bhv->bs_track->sbptr=sbptr; + + if (bs_bhv->bs_dtype == binswitch_animate_me) + { + bs_bhv->bs_dtype = binswitch_animate_and_move_me; + } + else + { + bs_bhv->bs_dtype = binswitch_move_me; + } + } + +#if !Saturn +// GLOBALASSERT(bs_bhv->bs_dtype != binswitch_no_display); +#endif + + // fill in the rest ourselves + + bs_bhv->request = 0; + bs_bhv->state = bs_tt->starts_on; + bs_bhv->timer = 0; + bs_bhv->switch_off_message_same=bs_tt->switch_off_message_same; + bs_bhv->switch_off_message_none=bs_tt->switch_off_message_none; + + bs_bhv->soundHandle = SOUND_NOACTIVEINDEX; + bs_bhv->triggered_last = No; + + if(bs_bhv->bs_mode==I_bswitch_time_delay_autoexec) + { + //set request and then treat as normal time delay switch + bs_bhv->bs_mode=I_bswitch_time_delay; + bs_bhv->request=I_request_on; + } + + if(bs_bhv->state) + { + bs_bhv->timer=bs_bhv->time_for_reset; + if(bs_bhv->bs_track) + { + //set the track to the end position + bs_bhv->bs_track->current_section=(bs_bhv->bs_track->num_sections-1); + bs_bhv->bs_track->timer=bs_bhv->bs_track->sections[bs_bhv->bs_track->current_section].time_for_section; + bs_bhv->bs_track->playing=1; + Update_Track_Position(bs_bhv->bs_track); + + } + } + + bs_bhv->TimeUntilNetSynchAllowed=0; + + return((void*)bs_bhv); +} + + + +void BinarySwitchBehaveFun(STRATEGYBLOCK* sbptr) +{ + BINARY_SWITCH_BEHAV_BLOCK *bs_bhv; + DISPLAYBLOCK* dptr; + int oldState; + GLOBALASSERT(sbptr); + bs_bhv = (BINARY_SWITCH_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((bs_bhv->bhvr_type == I_BehaviourBinarySwitch)); + dptr = sbptr->SBdptr; + + /* + if(AvP.Network!=I_No_Network) return; + */ + + /****** + What I need to do - check to see if we have + a request - requests have different effects depending on + the mode - so we have to switch on the mode + *****/ + + + if (bs_bhv->bs_dtype == binswitch_animate_me || bs_bhv->bs_dtype == binswitch_animate_and_move_me) + { + if(dptr) + dptr->ObTxAnimCtrlBlks = bs_bhv->bs_tac; + } + + if (!ReturnPlayerSecurityClearance(0,bs_bhv->security_clerance) && bs_bhv->security_clerance) + { + bs_bhv->request = I_no_request; + return; + + } + + if(AvP.Network != I_No_Network) + { + /* + Every time a switch is updated there is a time delay of 5 seconds before the + switch can next be changed by the host sending synch messages. + This prevents the host machine from resetting a switch before it learns that + it has been pressed + */ + if(bs_bhv->request == I_no_request) + { + bs_bhv->TimeUntilNetSynchAllowed-=RealFrameTime; + if(bs_bhv->TimeUntilNetSynchAllowed<0) + { + bs_bhv->TimeUntilNetSynchAllowed=0; + } + } + else + { + bs_bhv->TimeUntilNetSynchAllowed=5*ONE_FIXED; + } + } + + if(bs_bhv->switch_flags && SwitchFlag_UseTriggerVolume) + { + /*See if switch has been set off*/ + int i; + for (i=0; iDynPtr) + { + if (sbPtr->SBdptr == Player) + { + needToTest = 1; + } + else if (sbPtr->I_SBtype == I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + if ((ghostData->type == I_BehaviourMarinePlayer) + ||(ghostData->type == I_BehaviourAlienPlayer) + ||(ghostData->type == I_BehaviourPredatorPlayer)) + needToTest = 1; + } + } + + if(needToTest&& + sbPtr->DynPtr->Position.vx > bs_bhv->trigger_volume_min.vx && + sbPtr->DynPtr->Position.vx < bs_bhv->trigger_volume_max.vx && + sbPtr->DynPtr->Position.vy > bs_bhv->trigger_volume_min.vy && + sbPtr->DynPtr->Position.vy < bs_bhv->trigger_volume_max.vy && + sbPtr->DynPtr->Position.vz > bs_bhv->trigger_volume_min.vz && + sbPtr->DynPtr->Position.vz < bs_bhv->trigger_volume_max.vz) + { + bs_bhv->request=I_request_on; + break; + } + } + } + + if (bs_bhv->request == I_request_on) + { + if (bs_bhv->triggered_last) + { + bs_bhv->request = I_no_request; + } + else + { + bs_bhv->triggered_last = Yes; + } + } + else + { + bs_bhv->triggered_last = No; + } + + + switch(bs_bhv->bs_mode) + { + case I_bswitch_timer: + { + if(bs_bhv->request == I_request_on && !bs_bhv->state) + { + + bs_bhv->timer = bs_bhv->time_for_reset; + + if(sbptr->shapeIndex!=-1)//don't play a sound if there is no shape + { + if(!bs_bhv->bs_track || !bs_bhv->bs_track->sound) + { + if (bs_bhv->soundHandle == SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_SWITCH1,"eh",&bs_bhv->soundHandle); + } + } + } + + if (bs_bhv->bs_dtype == binswitch_move_me || bs_bhv->bs_dtype == binswitch_animate_and_move_me) + { + // moving switch + bs_bhv->new_state = 1; + bs_bhv->new_request = 1; + bs_bhv->bs_track->reverse=0; + Start_Track_Playing(bs_bhv->bs_track); + bs_bhv->mode_store = bs_bhv->bs_mode; + bs_bhv->bs_mode = I_bswitch_moving; + } + else + { + int i; + for (i=0; inum_targets; i++) + { + if (bs_bhv->bs_targets[i]) + { + RequestState(bs_bhv->bs_targets[i],bs_bhv->request_messages[i], sbptr); + + } + } + bs_bhv->state = 1; + } + + + // swap sequence + if(bs_bhv->bs_tac) + { + bs_bhv->bs_tac->tac_sequence = 1; + bs_bhv->bs_tac->tac_txah_s = GetTxAnimHeaderFromShape(bs_bhv->bs_tac, (sbptr->shapeIndex)); + } + + + } + else if(bs_bhv->timer > 0) + { + bs_bhv->timer -= NormalFrameTime; + if(bs_bhv->timer <= 0) + { + if(AvP.Network != I_No_Network) + { + bs_bhv->TimeUntilNetSynchAllowed=5*ONE_FIXED; + } + + if(sbptr->shapeIndex!=-1)//don't play a sound if there is no shape + { + if (bs_bhv->soundHandle == SOUND_NOACTIVEINDEX) + { + if(!bs_bhv->bs_track || !bs_bhv->bs_track->sound) + { + Sound_Play(SID_SWITCH2,"eh",&bs_bhv->soundHandle); + } + } + } + bs_bhv->state = 0; + + if (bs_bhv->bs_dtype == binswitch_move_me || bs_bhv->bs_dtype == binswitch_animate_and_move_me) + { + // moving switch + bs_bhv->new_state = 0; + bs_bhv->new_request = -1; //the 'off' message will be sent as soon as the timer finishes + bs_bhv->bs_track->reverse=1; + Start_Track_Playing(bs_bhv->bs_track); + bs_bhv->mode_store = bs_bhv->bs_mode; + bs_bhv->bs_mode = I_bswitch_moving; + } + + if(!bs_bhv->switch_off_message_none) + { + //send the 'off' message + int i; + for (i=0; inum_targets; i++) + { + if (bs_bhv->bs_targets[i]) + { + RequestState(bs_bhv->bs_targets[i],bs_bhv->request_messages[i]^(!bs_bhv->switch_off_message_same), sbptr); + } + } + + } + + if(bs_bhv->bs_tac) + { + bs_bhv->bs_tac->tac_sequence = 0; + bs_bhv->bs_tac->tac_txah_s = GetTxAnimHeaderFromShape(bs_bhv->bs_tac, (sbptr->shapeIndex)); + } + + } + } + break; + } + + case I_bswitch_toggle: + { + if(bs_bhv->request == I_no_request) + return; + + /* change the state and request the new state in + the target */ + + if(sbptr->shapeIndex!=-1)//don't play a sound if there is no shape + { + if (bs_bhv->soundHandle == SOUND_NOACTIVEINDEX) + { + if(!bs_bhv->bs_track || !bs_bhv->bs_track->sound) + { + Sound_Play(SID_SWITCH1,"eh",&bs_bhv->soundHandle); + } + } + } + if(bs_bhv->bs_dtype == binswitch_move_me || bs_bhv->bs_dtype == binswitch_animate_and_move_me) + { + // moving switch + bs_bhv->new_state = !bs_bhv->state; + if(bs_bhv->new_state) + { + bs_bhv->new_request = 1; + } + else + { + //check to see what the switch off request is + if(bs_bhv->switch_off_message_same) + bs_bhv->new_request=1; + else if(bs_bhv->switch_off_message_none) + bs_bhv->new_request=-1; + else + bs_bhv->new_request=0; + + } + bs_bhv->mode_store = bs_bhv->bs_mode; + bs_bhv->bs_mode = I_bswitch_moving; + bs_bhv->bs_track->reverse=bs_bhv->state; + Start_Track_Playing(bs_bhv->bs_track); + } + else + { + bs_bhv->state = !bs_bhv->state; + { + int i; + for (i=0; inum_targets; i++) + { + if (bs_bhv->bs_targets[i]) + { + if(bs_bhv->state) + { + RequestState(bs_bhv->bs_targets[i], bs_bhv->request_messages[i], sbptr); + } + else + { + if(!bs_bhv->switch_off_message_none) + { + RequestState(bs_bhv->bs_targets[i], bs_bhv->request_messages[i]^(!bs_bhv->switch_off_message_same), sbptr); + } + } + } + } + } + } + if(bs_bhv->bs_tac) + { + bs_bhv->bs_tac->tac_sequence = bs_bhv->state ; + bs_bhv->bs_tac->tac_txah_s = GetTxAnimHeaderFromShape(bs_bhv->bs_tac, (sbptr->shapeIndex)); + } + + + break; + } + case I_bswitch_wait: + { + if(bs_bhv->request == I_no_request) + return; + + + oldState = bs_bhv->state; + + if(bs_bhv->request == I_request_on) + { + if(bs_bhv->state) + break;//switch cannot be activated again until it is reset + + if(bs_bhv->bs_dtype == binswitch_move_me || bs_bhv->bs_dtype == binswitch_animate_and_move_me) + { + + // moving switch + bs_bhv->new_state = 1; + bs_bhv->new_request = 1; + bs_bhv->mode_store = bs_bhv->bs_mode; + bs_bhv->bs_mode = I_bswitch_moving; + bs_bhv->bs_track->reverse=0; + Start_Track_Playing(bs_bhv->bs_track); + } + else + { + int i; + bs_bhv->state = 1; + for (i=0; inum_targets; i++) + { + if (bs_bhv->bs_targets[i]) + { + RequestState(bs_bhv->bs_targets[i],bs_bhv->request_messages[i] , sbptr); + + } + } + } + } + else + { + if(!bs_bhv->state) break; //can only be deactivated if currently on + if(bs_bhv->bs_dtype == binswitch_move_me || bs_bhv->bs_dtype == binswitch_animate_and_move_me) + { + + // moving switch + bs_bhv->new_state = 0; + + //check to see what the switch off request is + if(bs_bhv->switch_off_message_same) + bs_bhv->new_request=1; + else if(bs_bhv->switch_off_message_none) + bs_bhv->new_request=-1; + else + bs_bhv->new_request=0; + + bs_bhv->mode_store = bs_bhv->bs_mode; + bs_bhv->bs_mode = I_bswitch_moving; + bs_bhv->bs_track->reverse=1; + Start_Track_Playing(bs_bhv->bs_track); + } + else + { + int i; + + bs_bhv->state = 0; + if(!bs_bhv->switch_off_message_none) + { + for (i=0; inum_targets; i++) + { + if (bs_bhv->bs_targets[i]) + { + RequestState(bs_bhv->bs_targets[i],bs_bhv->request_messages[i]^(!bs_bhv->switch_off_message_same), sbptr); + + } + } + } + } + } + + if(sbptr->shapeIndex!=-1)//don't play a sound if there is no shape + { + if (oldState == bs_bhv->state) + { + if (bs_bhv->soundHandle == SOUND_NOACTIVEINDEX) + { + if(!bs_bhv->bs_track || !bs_bhv->bs_track->sound) + { + Sound_Play(SID_SWITCH2,"eh",&bs_bhv->soundHandle); + } + } + } + else + { + if (bs_bhv->soundHandle == SOUND_NOACTIVEINDEX) + { + if(!bs_bhv->bs_track || !bs_bhv->bs_track->sound) + { + Sound_Play(SID_SWITCH1,"eh",&bs_bhv->soundHandle); + } + } + } + } + if(bs_bhv->bs_tac) + { + bs_bhv->bs_tac->tac_sequence = bs_bhv->state ? 1 : 0; + bs_bhv->bs_tac->tac_txah_s = GetTxAnimHeaderFromShape(bs_bhv->bs_tac, (sbptr->shapeIndex)); + } + + break; + } + case I_bswitch_moving: + { + Update_Track_Position(bs_bhv->bs_track); + if(!bs_bhv->bs_track->playing) + { + bs_bhv->bs_mode = bs_bhv->mode_store; + bs_bhv->state = bs_bhv->new_state; + if(bs_bhv->bs_tac) + { + bs_bhv->bs_tac->tac_sequence = bs_bhv->state ? 1 : 0; + bs_bhv->bs_tac->tac_txah_s = GetTxAnimHeaderFromShape(bs_bhv->bs_tac, (sbptr->shapeIndex)); + } + if (bs_bhv->new_request != -1) + { + int i; + for (i=0; inum_targets; i++) + { + if (bs_bhv->bs_targets[i]) + { + if(bs_bhv->new_request) + RequestState(bs_bhv->bs_targets[i],bs_bhv->request_messages[i] , sbptr); + else + RequestState(bs_bhv->bs_targets[i],bs_bhv->request_messages[i]^1, sbptr); + } + } + } + } + + + } + break; + case I_bswitch_time_delay : + { + if(bs_bhv->timer>0) + { + bs_bhv->timer-=NormalFrameTime; + if(bs_bhv->timer<=0 || bs_bhv->request == I_request_off) + { + //time to send the request + int i; + bs_bhv->timer=0; + + //only send message if we got here through the time running out + if(bs_bhv->request != I_request_off) + { + for (i=0; inum_targets; i++) + { + if (bs_bhv->bs_targets[i]) + { + RequestState(bs_bhv->bs_targets[i],bs_bhv->request_messages[i] , sbptr); + } + } + } + bs_bhv->state = 0; + + // swap sequence + if(bs_bhv->bs_tac) + { + bs_bhv->bs_tac->tac_sequence = 0; + bs_bhv->bs_tac->tac_txah_s = GetTxAnimHeaderFromShape(bs_bhv->bs_tac, (sbptr->shapeIndex)); + } + + if(AvP.Network != I_No_Network) + { + bs_bhv->TimeUntilNetSynchAllowed=5*ONE_FIXED; + } + + } + } + else + { + if(bs_bhv->request == I_request_on && bs_bhv->state == 0) + { + bs_bhv->timer = bs_bhv->time_for_reset; + if(sbptr->shapeIndex!=-1)//don't play a sound if there is no shape + { + if (bs_bhv->soundHandle == SOUND_NOACTIVEINDEX) + { + if(!bs_bhv->bs_track || !bs_bhv->bs_track->sound) + { + Sound_Play(SID_SWITCH1,"eh",&bs_bhv->soundHandle); + } + } + } + bs_bhv->state = 1; + + // swap sequence + if(bs_bhv->bs_tac) + { + bs_bhv->bs_tac->tac_sequence = 1; + bs_bhv->bs_tac->tac_txah_s = GetTxAnimHeaderFromShape(bs_bhv->bs_tac, (sbptr->shapeIndex)); + } + + } + } + } + break; + default: + GLOBALASSERT(2<1); + } + + bs_bhv->request = I_no_request; +} + + +#define BINARYSWITCHSYNCH_ON 0 +#define BINARYSWITCHSYNCH_OFF 1 +#define BINARYSWITCHSYNCH_IGNORE 2 + +int BinarySwitchGetSynchData(STRATEGYBLOCK* sbPtr) +{ + BINARY_SWITCH_BEHAV_BLOCK *bs_bhv; + GLOBALASSERT(sbPtr); + bs_bhv = (BINARY_SWITCH_BEHAV_BLOCK*)sbPtr->SBdataptr; + GLOBALASSERT((bs_bhv->bhvr_type == I_BehaviourBinarySwitch)); + + //don't try to synch moving switches + if(bs_bhv->bs_mode==I_bswitch_moving) + { + return BINARYSWITCHSYNCH_IGNORE; + } + + if(bs_bhv->state) + return BINARYSWITCHSYNCH_ON; + else + return BINARYSWITCHSYNCH_OFF; +} + + +void BinarySwitchSetSynchData(STRATEGYBLOCK* sbPtr,int status) +{ + BINARY_SWITCH_BEHAV_BLOCK *bs_bhv; + GLOBALASSERT(sbPtr); + bs_bhv = (BINARY_SWITCH_BEHAV_BLOCK*)sbPtr->SBdataptr; + GLOBALASSERT((bs_bhv->bhvr_type == I_BehaviourBinarySwitch)); + + if(bs_bhv->TimeUntilNetSynchAllowed>0) + { + //ignore this attempt to synch the switch + return; + } + + //don't try to synch moving switches + if(bs_bhv->bs_mode==I_bswitch_moving) + { + return; + } + + + switch(status) + { + case BINARYSWITCHSYNCH_ON : + if(!bs_bhv->state) + { + //this switch should be on + RequestState(sbPtr,1,0); + } + break; + + case BINARYSWITCHSYNCH_OFF : + if(bs_bhv->state) + { + //this switch should be off + RequestState(sbPtr,0,0); + } + break; + } +} + + + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" +typedef struct binary_switch_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + BINARY_SWITCH_REQUEST_STATE request; + BOOL state; + BSWITCH_MODE bs_mode; + int timer; + + BSWITCH_MODE mode_store; + + BOOL new_state; + int new_request; + + BOOL triggered_last; + + int txanim_sequence; + +}BINARY_SWITCH_SAVE_BLOCK; + + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV bs_bhv + +void LoadStrategy_BinarySwitch(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + BINARY_SWITCH_BEHAV_BLOCK *bs_bhv; + BINARY_SWITCH_SAVE_BLOCK* block = (BINARY_SWITCH_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourBinarySwitch) return; + + bs_bhv = (BINARY_SWITCH_BEHAV_BLOCK*)sbPtr->SBdataptr; + + //start copying stuff + + COPYELEMENT_LOAD(request) + COPYELEMENT_LOAD(state) + COPYELEMENT_LOAD(bs_mode) + COPYELEMENT_LOAD(timer) + COPYELEMENT_LOAD(mode_store) + COPYELEMENT_LOAD(new_state) + COPYELEMENT_LOAD(new_request) + COPYELEMENT_LOAD(triggered_last) + + //set the texture animation sequence + if(bs_bhv->bs_tac) + { + bs_bhv->bs_tac->tac_sequence = block->txanim_sequence; + bs_bhv->bs_tac->tac_txah_s = GetTxAnimHeaderFromShape(bs_bhv->bs_tac, (sbPtr->shapeIndex)); + } + + //load the track position , if the switch has one + if(bs_bhv->bs_track) + { + SAVE_BLOCK_HEADER* track_header = GetNextBlockIfOfType(SaveBlock_Track); + if(track_header) + { + LoadTrackPosition(track_header,bs_bhv->bs_track); + } + } + +} + +void SaveStrategy_BinarySwitch(STRATEGYBLOCK* sbPtr) +{ + BINARY_SWITCH_SAVE_BLOCK *block; + BINARY_SWITCH_BEHAV_BLOCK *bs_bhv; + bs_bhv = (BINARY_SWITCH_BEHAV_BLOCK*)sbPtr->SBdataptr; + + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + + COPYELEMENT_SAVE(request) + COPYELEMENT_SAVE(state) + COPYELEMENT_SAVE(bs_mode) + COPYELEMENT_SAVE(timer) + COPYELEMENT_SAVE(mode_store) + COPYELEMENT_SAVE(new_state) + COPYELEMENT_SAVE(new_request) + COPYELEMENT_SAVE(triggered_last) + + //get the animation sequence + if(bs_bhv->bs_tac) + { + block->txanim_sequence = bs_bhv->bs_tac->tac_sequence; + } + else + { + block->txanim_sequence = 0; + } + + //save the track position , if the switch has one + if(bs_bhv->bs_track) + { + SaveTrackPosition(bs_bhv->bs_track); + } + +} diff --git a/3dc/avp/BH_BINSW.H b/3dc/avp/BH_BINSW.H new file mode 100644 index 0000000..695aa5d --- /dev/null +++ b/3dc/avp/BH_BINSW.H @@ -0,0 +1,152 @@ +#ifndef _bh_binsw_h_ +#define _bh_binsw_h_ 1 + +#include "3dc.h" +#include "track.h" + +#ifdef __cplusplus + + extern "C" { + +#endif + + +extern void* BinarySwitchBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr); +extern void BinarySwitchBehaveFun(STRATEGYBLOCK* sbptr); + +extern int BinarySwitchGetSynchData(STRATEGYBLOCK* sbptr); +extern void BinarySwitchSetSynchData(STRATEGYBLOCK* sbptr,int status); + +/******************** BinarySwitch ***********************/ + +// enum to decxribe how the switch works +// action is always dependent on the SB block of the target + +typedef enum binary_switch_mode +{ + I_bswitch_timer, + I_bswitch_wait, + I_bswitch_toggle, + I_bswitch_moving, + I_bswitch_time_delay, + I_bswitch_time_delay_autoexec,//timer starts as soon as game starts + +} BSWITCH_MODE; + +typedef enum binary_switch_req_states +{ + I_no_request, + I_request_on, + I_request_off, +}BINARY_SWITCH_REQUEST_STATE; + +typedef enum bswitch_display_types +{ + binswitch_no_display, + binswitch_animate_me, + binswitch_move_me, + binswitch_animate_and_move_me, +} BSWITCH_DISPLAY_TYPES; + +typedef enum bs_move_dir +{ + bs_start_to_end, + bs_end_to_start, +} BS_MOVE_DIR; + +// require three states for rest fso we can ignore + + +#define SwitchFlag_UseTriggerVolume 0x00000001 //switch triggered by walking into trigger volume + +typedef struct binary_switch +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + BINARY_SWITCH_REQUEST_STATE request; + BOOL state; + BSWITCH_MODE bs_mode; + + int num_targets; + SBNAMEBLOCK * target_names; + int * request_messages; + + STRATEGYBLOCK ** bs_targets; + + + int time_for_reset; // constant + int timer; + + // stuff for showing how the switch displays its state + + BSWITCH_DISPLAY_TYPES bs_dtype; + + TXACTRLBLK *bs_tac; // animations + + + TRACK_CONTROLLER* bs_track; + // or positions + + + BSWITCH_MODE mode_store; + + BOOL new_state; + int new_request; + + int security_clerance; // what the plyer has to be to use this switch + + int switch_flags; + VECTORCH trigger_volume_min;//for switches that can be set off by walking + VECTORCH trigger_volume_max;//into a given area + + int soundHandle; + + BOOL triggered_last; + + unsigned int switch_off_message_same:1; + unsigned int switch_off_message_none:1; + + int TimeUntilNetSynchAllowed; + + +}BINARY_SWITCH_BEHAV_BLOCK; + +typedef struct bin_switch_tools_template +{ + VECTORCH position; + EULER orientation; + + int mode; + int time_for_reset; + int security_clearance; + + int num_targets; + SBNAMEBLOCK * target_names; + int* request_messages; + + int shape_num; + + char nameID[SB_NAME_LENGTH]; + + TRACK_CONTROLLER* track; + + int switch_flags; + VECTORCH trigger_volume_min;//for switches that can be set off by walking + VECTORCH trigger_volume_max;//into a given area + + unsigned int starts_on:1; + unsigned int switch_off_message_same:1; + unsigned int switch_off_message_none:1; + + +} BIN_SWITCH_TOOLS_TEMPLATE; + + + +#ifdef __cplusplus + + }; + +#endif + + +#endif diff --git a/3dc/avp/BH_FAR.H b/3dc/avp/BH_FAR.H new file mode 100644 index 0000000..622d362 --- /dev/null +++ b/3dc/avp/BH_FAR.H @@ -0,0 +1,63 @@ + +/*------------------------Patrick 26/11/96----------------------------- + Header file for FAR AI alien behaviour + --------------------------------------------------------------------*/ + +#ifndef _bhfar_h_ +#define _bhfar_h_ 1 + +#ifdef __cplusplus + extern "C" { +#endif + + +/* enum for far alien target module status */ +typedef enum fnpc_targetmodulestatus +{ + NPCTM_NoEntryPoint, + NPCTM_NormalRoom, + NPCTM_AirDuct, + NPCTM_LiftTeleport, + NPCTM_ProxDoorOpen, + NPCTM_ProxDoorNotOpen, + NPCTM_LiftDoorOpen, + NPCTM_LiftDoorNotOpen, + NPCTM_SecurityDoorOpen, + NPCTM_SecurityDoorNotOpen, + + +} NPC_TARGETMODULESTATUS; + +/* prototypes */ +extern void FarAlienBehaviour(STRATEGYBLOCK *sbPtr); +extern void BuildFarModuleLocs(void); +extern void KillFarModuleLocs(void); + +extern void LocateFarNPCInModule(STRATEGYBLOCK *sbPtr, MODULE *targetModule); +extern void LocateFarNPCInAIModule(STRATEGYBLOCK *sbPtr, AIMODULE *targetModule); +extern NPC_TARGETMODULESTATUS GetTargetAIModuleStatus(STRATEGYBLOCK *sbPtr, AIMODULE *targetModule, int alien); + +extern AIMODULE *FarNPC_GetTargetAIModuleForHunt(STRATEGYBLOCK *sbPtr,int alien); +extern AIMODULE *FarNPC_GetTargetAIModuleForGlobalHunt(STRATEGYBLOCK *sbPtr); +extern AIMODULE *FarNPC_GetTargetAIModuleForWander(STRATEGYBLOCK *sbPtr, AIMODULE *exception, int alien); +extern AIMODULE *FarNPC_GetTargetAIModuleForRetreat(STRATEGYBLOCK *sbPtr); +extern AIMODULE *FarNPC_GetTargetAIModuleForMarineRespond(STRATEGYBLOCK *sbPtr); +extern void FarNpc_FlipAround(STRATEGYBLOCK *sbPtr); + +/* this define to help stop aliens coagulating in the environment */ +#if SupportWindows95 + #define MAX_GENERATORNPCSPERMODULE 5 + #define MAX_VISIBLEGENERATORNPCS 8 //12 +#else + /* PSX & Saturn*/ + #define MAX_GENERATORNPCSPERMODULE 5 + #define MAX_VISIBLEGENERATORNPCS 6 +#endif + + + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/3dc/avp/BH_FHUG.C b/3dc/avp/BH_FHUG.C new file mode 100644 index 0000000..fb0ddcc --- /dev/null +++ b/3dc/avp/BH_FHUG.C @@ -0,0 +1,1335 @@ +/* Patrick 9/7/97 ---------------------------------------------------- + Source file for Facehugger AI behaviour functions.... + --------------------------------------------------------------------*/ +#include "3dc.h" + +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "dynblock.h" +#include "dynamics.h" +#include "comp_shp.h" +#include "bh_types.h" +#include "bh_pred.h" +#include "bh_fhug.h" +#include "bh_debri.h" +#include "pfarlocs.h" +#include "pvisible.h" +#include "weapons.h" +#include "psnd.h" +#include "psndplat.h" +#include "targeting.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "ShowCmds.h" +#include "sfx.h" + +#define HUGGER_STATE_PRINT 0 + +/* external global variables used in this file */ +extern int ModuleArraySize; +extern char *ModuleCurrVisArray; +extern int NormalFrameTime; +extern int cosine[], sine[]; + +extern ACTIVESOUNDSAMPLE ActiveSounds[]; + +/* prototypes for this file */ +static void Execute_FHNS_Approach(STRATEGYBLOCK *sbPtr); +static void Execute_FHNS_Attack(STRATEGYBLOCK *sbPtr); +static void Execute_FHNS_Wait(STRATEGYBLOCK *sbPtr); +static void Execute_FHNS_Avoidance(STRATEGYBLOCK *sbPtr); +static void Execute_FHNS_Dying(STRATEGYBLOCK *sbPtr); +static void Execute_FHNS_Float(STRATEGYBLOCK *sbPtr); +static void Execute_FHNS_Jumping(STRATEGYBLOCK *sbPtr); +static void Execute_FHNS_AboutToJump(STRATEGYBLOCK *sbPtr); + +void Wake_Hugger(STRATEGYBLOCK *sbPtr); + +static int HuggerShouldAttackPlayer(void); +static void SetHuggerAnimationSequence(STRATEGYBLOCK *sbPtr, HUGGER_SUBSEQUENCES seq, int length); +static void KillFaceHugger(STRATEGYBLOCK *sbPtr,DAMAGE_PROFILE *damage); + +static int InContactWithPlayer(DYNAMICSBLOCK *dynPtr); +static void JumpAtPlayer(STRATEGYBLOCK *sbPtr); + +extern SECTION *GetHierarchyFromLibrary(const char *rif_name); + +/* ------------------------------------------------------------------- + Initilaiser, damage, and visibility functions + behaviour shell + --------------------------------------------------------------------*/ +void InitFacehuggerBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr) +{ + TOOLS_DATA_FACEHUGGER *toolsData; + int i; + + LOCALASSERT(bhdata); + LOCALASSERT(sbPtr); + toolsData = (TOOLS_DATA_FACEHUGGER *)bhdata; + + /* check we're not in a net game */ + if(AvP.Network != I_No_Network) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* make the assumption that the loader has initialised the strategy block sensibly... + so just set the shapeIndex from the tools data & copy the name id*/ + sbPtr->shapeIndex = toolsData->shapeIndex; + for(i=0;iSBname[i] = toolsData->nameID[i]; + + sbPtr->SBdptr=NULL; + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ALIEN_NPC); + if(sbPtr->DynPtr) + { + EULER zeroEuler = {0,0,0}; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + dynPtr->PrevPosition = dynPtr->Position = toolsData->position; + dynPtr->OrientEuler = zeroEuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + /* zero linear velocity in dynamics block */ + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + dynPtr->Mass=10; + } + else + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* Initialise hugger's stats */ + { + NPC_DATA *NpcData; + + NpcData=GetThisNpcData(I_NPC_FaceHugger); + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + /* create, initialise and attach a facehugger data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(FACEHUGGER_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + SECTION *root_section; + FACEHUGGER_STATUS_BLOCK *facehuggerStatus = (FACEHUGGER_STATUS_BLOCK *)sbPtr->SBdataptr; + + NPC_InitMovementData(&(facehuggerStatus->moveData)); + facehuggerStatus->health = FACEHUGGER_STARTING_HEALTH; + sbPtr->integrity = facehuggerStatus->health; + facehuggerStatus->stateTimer = 0; + facehuggerStatus->DoomTimer = 0; + facehuggerStatus->CurveRadius = 0; + facehuggerStatus->CurveLength = 0; + facehuggerStatus->CurveTimeOut = 0; + facehuggerStatus->jumping = 0; + + root_section=GetHierarchyFromLibrary("hnpchugger"); + Create_HModel(&facehuggerStatus->HModelController,root_section); + InitHModelSequence(&facehuggerStatus->HModelController,0,0,ONE_FIXED); + ProveHModel_Far(&facehuggerStatus->HModelController,sbPtr); + + if (toolsData->startInactive==0) { + facehuggerStatus->nearBehaviourState = FHNS_Approach; + SetHuggerAnimationSequence(sbPtr,HSS_Stand,ONE_FIXED); + } else { + facehuggerStatus->nearBehaviourState = FHNS_Floating; + SetHuggerAnimationSequence(sbPtr,HSS_Floats,(ONE_FIXED<<1)); + sbPtr->DynPtr->GravityOn=0; + } + + facehuggerStatus->soundHandle = SOUND_NOACTIVEINDEX; + facehuggerStatus->soundHandle2 = SOUND_NOACTIVEINDEX; + + for(i=0;ideath_target_ID[i] = toolsData->death_target_ID[i]; + facehuggerStatus->death_target_sbptr=0; + facehuggerStatus->death_target_request=toolsData->death_target_request; + } + else + { + RemoveBehaviourStrategy(sbPtr); + return; + } + +} + +void FacehuggerBehaviour(STRATEGYBLOCK *sbPtr) +{ + FACEHUGGER_STATUS_BLOCK *facehuggerStatusPointer; + + LOCALASSERT(sbPtr); + facehuggerStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(facehuggerStatusPointer); + + /* test if we've got a containing module: if we haven't, do nothing. + This is important as the object could have been marked for deletion by the visibility + management system...*/ + if(!sbPtr->containingModule) + { + if (facehuggerStatusPointer->soundHandle2 != SOUND_NOACTIVEINDEX) { + Sound_Stop(facehuggerStatusPointer->soundHandle2); + } + DestroyAnyStrategyBlock(sbPtr); /* just to make sure */ + return; + } + + /* set velocity to zero */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if (sbPtr->SBDamageBlock.IsOnFire) { + + CauseDamageToObject(sbPtr,&firedamage,NormalFrameTime,NULL); + + if (facehuggerStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + Sound_Play(SID_FIRE,"dlev",&(sbPtr->DynPtr->Position),&facehuggerStatusPointer->soundHandle2,127); + } else { + if (ActiveSounds[facehuggerStatusPointer->soundHandle2].soundIndex!=SID_FIRE) { + Sound_Stop(facehuggerStatusPointer->soundHandle2); + } else { + Sound_Update3d(facehuggerStatusPointer->soundHandle2,&(sbPtr->DynPtr->Position)); + } + } + } else { + Sound_Stop(facehuggerStatusPointer->soundHandle2); + } + + /* No far behaviour for facehuggerss */ + if(sbPtr->SBdptr) + { + if(sbPtr->maintainVisibility) LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]); + switch(facehuggerStatusPointer->nearBehaviourState) + { + case(FHNS_Approach): + { + #if HUGGER_STATE_PRINT + PrintDebuggingText("Hugger Approaching...\n"); + #endif + Execute_FHNS_Approach(sbPtr); + break; + } + case(FHNS_Attack): + { + #if HUGGER_STATE_PRINT + PrintDebuggingText("Hugger Attacking...\n"); + #endif + Execute_FHNS_Attack(sbPtr); + break; + } + case(FHNS_Wait): + { + #if HUGGER_STATE_PRINT + PrintDebuggingText("Hugger Waiting...\n"); + #endif + Execute_FHNS_Wait(sbPtr); + break; + } + case(FHNS_Avoidance): + { + #if HUGGER_STATE_PRINT + PrintDebuggingText("Hugger Avoiding...\n"); + #endif + Execute_FHNS_Avoidance(sbPtr); + break; + } + case(FHNS_Dying): + { + #if HUGGER_STATE_PRINT + PrintDebuggingText("Hugger Dying...\n"); + #endif + Execute_FHNS_Dying(sbPtr); + break; + } + case(FHNS_Floating): + { + #if HUGGER_STATE_PRINT + PrintDebuggingText("Hugger Floating...\n"); + #endif + Execute_FHNS_Float(sbPtr); + break; + } + case(FHNS_Jumping): + { + #if HUGGER_STATE_PRINT + PrintDebuggingText("Hugger Jumping...\n"); + #endif + Execute_FHNS_Jumping(sbPtr); + break; + } + case(FHNS_AboutToJump): + { + #if HUGGER_STATE_PRINT + PrintDebuggingText("Hugger AboutToJump...\n"); + #endif + Execute_FHNS_AboutToJump(sbPtr); + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + } + + if((facehuggerStatusPointer->nearBehaviourState == FHNS_Dying)&&(facehuggerStatusPointer->stateTimer <= 0)) { + if (facehuggerStatusPointer->soundHandle2 != SOUND_NOACTIVEINDEX) { + Sound_Stop(facehuggerStatusPointer->soundHandle2); + } + DestroyAnyStrategyBlock(sbPtr); + } else if (facehuggerStatusPointer->DoomTimer>(ONE_FIXED*FACEHUGGER_EXPIRY_TIME)) { + /* Kill facehugger */ + sbPtr->SBDamageBlock.Health=0; + if (facehuggerStatusPointer->nearBehaviourState != FHNS_Dying) { + KillFaceHugger(sbPtr,NULL); + } + } + +} + +void MakeFacehuggerNear(STRATEGYBLOCK *sbPtr) +{ + extern MODULEMAPBLOCK AlienDefaultMap; + + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr; + FACEHUGGER_STATUS_BLOCK *facehuggerStatusPointer; + + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + facehuggerStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(facehuggerStatusPointer); + LOCALASSERT(dynPtr); + LOCALASSERT(sbPtr->SBdptr == NULL); + + AlienDefaultMap.MapShape = sbPtr->shapeIndex; + tempModule.m_mapptr = &AlienDefaultMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 0; + tempModule.m_lightarray = (struct lightblock *)0; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr = NULL; + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) return; /* cannot create displayblock, so leave far */ + + sbPtr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbPtr; + dPtr->ObMyModule = NULL; + + /* need to initialise positional information in the new display block */ + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + + /* zero linear velocity in dynamics block */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* facehugger data block init */ + facehuggerStatusPointer->stateTimer = 0; + facehuggerStatusPointer->CurveRadius = 0; + facehuggerStatusPointer->CurveLength = 0; + facehuggerStatusPointer->CurveTimeOut = 0; + facehuggerStatusPointer->jumping = 0; + + /* state and sequence init */ + //dPtr->ShapeAnimControlBlock = &facehuggerStatusPointer->ShpAnimCtrl; + dPtr->HModelControlBlock=&facehuggerStatusPointer->HModelController; + if ((facehuggerStatusPointer->nearBehaviourState!=FHNS_Floating) + &&(facehuggerStatusPointer->nearBehaviourState!=FHNS_Dying)) { + if(HuggerShouldAttackPlayer()) + { + NPC_InitMovementData(&(facehuggerStatusPointer->moveData)); + facehuggerStatusPointer->nearBehaviourState = FHNS_Approach; + SetHuggerAnimationSequence(sbPtr,HSS_Run,(ONE_FIXED*2)/3); + } + else + { + NPC_InitMovementData(&(facehuggerStatusPointer->moveData)); + facehuggerStatusPointer->nearBehaviourState = FHNS_Wait; + SetHuggerAnimationSequence(sbPtr,HSS_Stand,ONE_FIXED); + } + } + ProveHModel(dPtr->HModelControlBlock,dPtr); + +} + +void MakeFacehuggerFar(STRATEGYBLOCK *sbPtr) +{ + int i; + LOCALASSERT(sbPtr->SBdptr != NULL); + /* get rid of the displayblock */ + i = DestroyActiveObject(sbPtr->SBdptr); + LOCALASSERT(i==0); + sbPtr->SBdptr = NULL; + /* zero linear velocity in dynamics block */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; +} + +void FacehuggerIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple) +{ + FACEHUGGER_STATUS_BLOCK *facehuggerStatusPointer; + + LOCALASSERT(sbPtr); + //Sound_Play(SID_ACID_SPRAY,"dp",&(sbPtr->DynPtr->Position),(FastRandom() & 255) - 128); + + facehuggerStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(facehuggerStatusPointer); + + #if 0 + /* reduce facehugger health */ + if(facehuggerStatusPointer->health>0) facehuggerStatusPointer->health -= damage; + #endif + + if (facehuggerStatusPointer->nearBehaviourState==FHNS_Floating) { + Wake_Hugger(sbPtr); + } + + /* check if we've been killed */ + if ( (sbPtr->SBDamageBlock.Health <= 0)&&(facehuggerStatusPointer->nearBehaviourState!=FHNS_Dying) ) + { + CurrentGameStats_CreatureKilled(sbPtr,NULL); + KillFaceHugger(sbPtr,damage); + return; + } + +} + +static void KillFaceHugger(STRATEGYBLOCK *sbPtr,DAMAGE_PROFILE *damage) +{ + FACEHUGGER_STATUS_BLOCK *fhugStatusPointer; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + fhugStatusPointer=(FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr=sbPtr->DynPtr; + LOCALASSERT(fhugStatusPointer); + LOCALASSERT(dynPtr); + + fhugStatusPointer->nearBehaviourState=FHNS_Dying; + fhugStatusPointer->stateTimer=FACEHUGGER_DYINGTIME<<1; + + /* Stop any hugger sound if playing */ + if (fhugStatusPointer->soundHandle != SOUND_NOACTIVEINDEX) + { + Sound_Stop(fhugStatusPointer->soundHandle); + } + + //Sound_Play(SID_BUGDIE3,"d",&(dynPtr->Position)); + + #if 1 + { + PLAYER_STATUS *playerStatusPointer= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + if (playerStatusPointer->MyFaceHugger==sbPtr) { + /* You cheater! */ + playerStatusPointer->MyFaceHugger=NULL; + } + } + #endif + + /*If face hugger has a death target ,send a request*/ + if(fhugStatusPointer->death_target_sbptr) + { + RequestState(fhugStatusPointer->death_target_sbptr,fhugStatusPointer->death_target_request, 0); + } + + /* More restrained death. */ + { + /* switch sequence */ + if (damage) { + if ( (damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire!=0) + &&(damage->Electrical==0) + &&(damage->Acid==0)) + { + SetHuggerAnimationSequence(sbPtr,HSS_DieOnFire,FACEHUGGER_DYINGTIME>>3); + } else { + SetHuggerAnimationSequence(sbPtr,HSS_Dies,FACEHUGGER_DYINGTIME>>3); + } + } else { + SetHuggerAnimationSequence(sbPtr,HSS_Dies,FACEHUGGER_DYINGTIME>>3); + } + fhugStatusPointer->HModelController.Looped=0; + fhugStatusPointer->HModelController.LoopAfterTweening=0; + /* switch state */ + fhugStatusPointer->nearBehaviourState=FHNS_Dying; + fhugStatusPointer->stateTimer=FACEHUGGER_DYINGTIME; + + /* stop motion */ + LOCALASSERT(sbPtr->DynPtr); + dynPtr->Friction = 400000; + dynPtr->LinImpulse.vx=sbPtr->DynPtr->LinVelocity.vx; + dynPtr->LinImpulse.vy=sbPtr->DynPtr->LinVelocity.vy; + dynPtr->LinImpulse.vz=sbPtr->DynPtr->LinVelocity.vz; + dynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; + /* Okay... */ + + } +} + + +/* ------------------------------------------------------------------- + Behaviour state functions + --------------------------------------------------------------------*/ + +static void Execute_FHNS_Approach(STRATEGYBLOCK *sbPtr) +{ + FACEHUGGER_STATUS_BLOCK *fhugStatusPointer; + DYNAMICSBLOCK *dynPtr; + VECTORCH targetPos; + //int approachingAirDuct = 0; + + LOCALASSERT(sbPtr); + fhugStatusPointer=(FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr=sbPtr->DynPtr; + LOCALASSERT(fhugStatusPointer); + LOCALASSERT(dynPtr); + + /* Stop any hugger attack sound if playing */ + if (fhugStatusPointer->soundHandle != SOUND_NOACTIVEINDEX && + ActiveSounds[fhugStatusPointer->soundHandle].soundIndex != SID_FHUG_MOVE) + { + Sound_Stop(fhugStatusPointer->soundHandle); + } + + /* Start the hugger movement sound if needed */ + if (fhugStatusPointer->soundHandle == SOUND_NOACTIVEINDEX) + { + + Sound_Play(SID_FHUG_MOVE,"ed",&fhugStatusPointer->soundHandle,&dynPtr->Position); + } + + /* do climb on walls, etc */ + dynPtr->UseStandardGravity=1; + /* If you think I'm going to let facehuggers climb on walls for * + * ONE SECOND, you are INSANE, Jack!!! */ + + /* target acquisition ? */ + { + extern DISPLAYBLOCK *Player; + if (sbPtr->SBDamageBlock.IsOnFire==0) { + targetPos=Player->ObStrategyBlock->DynPtr->Position; + } else { + targetPos=Player->ObStrategyBlock->DynPtr->Position; + + targetPos.vx+=((FastRandom()&8191)-4096); + targetPos.vy+=((FastRandom()&8191)-4096); + targetPos.vz+=((FastRandom()&8191)-4096); + } + } + + /* translate target into hugger local space */ + { + MATRIXCH toLocalSpaceMatrix = dynPtr->OrientMat; + TransposeMatrixCH(&toLocalSpaceMatrix); + + targetPos.vx -= dynPtr->Position.vx; + targetPos.vy -= dynPtr->Position.vy; + targetPos.vz -= dynPtr->Position.vz; + RotateVector(&targetPos,&toLocalSpaceMatrix); + } + + /* Fix vy. */ + targetPos.vy=0; + + /* tracking movement */ + { + int distanceToTarget = Magnitude(&targetPos); + if (dynPtr->IsInContactWithFloor) + { + int offset; + + if (fhugStatusPointer->CurveTimeOut<=0) + { + fhugStatusPointer->CurveLength = distanceToTarget; + fhugStatusPointer->CurveRadius = ((FastRandom()&16383)-8192)*2; + fhugStatusPointer->CurveTimeOut= ONE_FIXED*3; + } else { + fhugStatusPointer->CurveTimeOut-=NormalFrameTime; + } + + offset = + MUL_FIXED + ( + fhugStatusPointer->CurveRadius, + GetCos((1024*(distanceToTarget)/fhugStatusPointer->CurveLength)&4095) + ); + + dynPtr->LinVelocity.vx = + WideMulNarrowDiv + ( + FACEHUGGER_NEAR_SPEED, + targetPos.vx, + distanceToTarget + ) + -WideMulNarrowDiv + ( + offset, + targetPos.vz, + distanceToTarget + ); + + + dynPtr->LinVelocity.vz = + WideMulNarrowDiv + ( + FACEHUGGER_NEAR_SPEED, + targetPos.vz, + distanceToTarget + )+ + WideMulNarrowDiv + ( + offset, + targetPos.vx, + distanceToTarget + ); + + RotateVector(&dynPtr->LinVelocity,&dynPtr->OrientMat); + /* align to velocity */ + + NPCOrientateToVector(sbPtr,&dynPtr->LinVelocity,NPC_TURNRATE,NULL); + + /* within test for in contact with floor: test if + jump flag is set- if so switch anim back to run... */ + if(fhugStatusPointer->jumping==1) + { + fhugStatusPointer->jumping = 0; + SetHuggerAnimationSequence(sbPtr,HSS_Run,(ONE_FIXED*2)/3); + } + } + } + + /* check for state changes: + firstly, are we in contact with the player? */ + #if 0 + if(InContactWithPlayer(dynPtr)&&HuggerShouldAttackPlayer()) + { + fhugStatusPointer->nearBehaviourState = FHNS_Attack; + fhugStatusPointer->stateTimer = FACEHUGGER_NEARATTACKTIME; + SetHuggerAnimationSequence(sbPtr,HSS_Attack,ONE_FIXED); + dynPtr->DynamicsType = DYN_TYPE_NO_COLLISIONS; /* turn off collisons */ + dynPtr->GravityOn = 0; /* turn off gravity */ + sbPtr->maintainVisibility = 0; /* turn off visibility support- be carefull! */ + + /* Attach to player! */ + { + PLAYER_STATUS *playerStatusPointer= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + playerStatusPointer->MyFaceHugger=sbPtr; + } + return; + } + #endif + + /* is player visible?: if not, go to wait */ + if(!HuggerShouldAttackPlayer()) + { + fhugStatusPointer->nearBehaviourState = FHNS_Wait; + fhugStatusPointer->stateTimer = 0; + return; + } + + #if 1 + /* should we jump at the player? */ + if (sbPtr->SBDamageBlock.IsOnFire==0) { + int distanceToPlayer = VectorDistance(&(dynPtr->Position),&(Player->ObStrategyBlock->DynPtr->Position)); + if((distanceToPlayer<=FACEHUGGER_JUMPDISTANCE)&&(dynPtr->IsInContactWithFloor)) + { + #if 0 + JumpAtPlayer(sbPtr); + #else + fhugStatusPointer->nearBehaviourState = FHNS_AboutToJump; + fhugStatusPointer->stateTimer = 0; + #endif + return; + } + } + #endif + + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_OBSTRUCTIONREPORT obstruction; + NPC_IsObstructed(sbPtr,&(fhugStatusPointer->moveData),&obstruction,&destructableObject); + if(obstruction.environment) + { + /* go to avoidance */ + NPC_InitMovementData(&(fhugStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(fhugStatusPointer->moveData.avoidanceDirn),&obstruction); + fhugStatusPointer->nearBehaviourState = FHNS_Avoidance; + fhugStatusPointer->stateTimer = NPC_AVOIDTIME; + /* no sequence change required */ + return; + } + if(obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_ALIEN_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + + } + } + + { + VECTORCH velocityDirection = dynPtr->LinVelocity; + Normalise(&velocityDirection); + + if(NPC_CannotReachTarget(&(fhugStatusPointer->moveData), &targetPos, &velocityDirection)) + { + /* go to avoidance */ + NPC_OBSTRUCTIONREPORT obstruction = {1,0,0}; + NPC_InitMovementData(&(fhugStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(fhugStatusPointer->moveData.avoidanceDirn),&obstruction); + fhugStatusPointer->nearBehaviourState = FHNS_Avoidance; + fhugStatusPointer->stateTimer = NPC_AVOIDTIME; + /* no sequence change required */ + return; + } + } +} + +void PlotFaceHugger(STRATEGYBLOCK *sbPtr) { + + extern void RenderThisDisplayblock(DISPLAYBLOCK *dbPtr); + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + DYNAMICSBLOCK *dynPtr; + FACEHUGGER_STATUS_BLOCK *facehuggerStatusPointer; + + LOCALASSERT(sbPtr); + dynPtr=sbPtr->DynPtr; + facehuggerStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(facehuggerStatusPointer); + LOCALASSERT(dynPtr); + LOCALASSERT(sbPtr->SBdptr); + + + { + VECTORCH x,y,z; + + x.vx = -VDBPtr->VDB_Mat.mat11; + x.vy = -VDBPtr->VDB_Mat.mat21; + x.vz = -VDBPtr->VDB_Mat.mat31; + y.vx = -VDBPtr->VDB_Mat.mat13; + y.vy = -VDBPtr->VDB_Mat.mat23; + y.vz = -VDBPtr->VDB_Mat.mat33; + z.vx = -VDBPtr->VDB_Mat.mat12; + z.vy = -VDBPtr->VDB_Mat.mat22; + z.vz = -VDBPtr->VDB_Mat.mat32; + + Normalise(&x); + Normalise(&y); + Normalise(&z); + + dynPtr->OrientMat.mat11 = x.vx; + dynPtr->OrientMat.mat12 = x.vy; + dynPtr->OrientMat.mat13 = x.vz; + dynPtr->OrientMat.mat21 = y.vx; + dynPtr->OrientMat.mat22 = y.vy; + dynPtr->OrientMat.mat23 = y.vz; + dynPtr->OrientMat.mat31 = z.vx; + dynPtr->OrientMat.mat32 = z.vy; + dynPtr->OrientMat.mat33 = z.vz; + } + + /* set position */ + dynPtr->Position.vx = 0; + dynPtr->Position.vz = FACEHUGGER_ATTACKZOFFSET/4; + dynPtr->Position.vy = FACEHUGGER_ATTACKYOFFSET; + { + MATRIXCH myMat = VDBPtr->VDB_Mat; + TransposeMatrixCH(&myMat); + RotateVector(&(dynPtr->Position), &(myMat)); + } + + dynPtr->Position.vx += VDBPtr->VDB_World.vx; + dynPtr->Position.vy += VDBPtr->VDB_World.vy; + dynPtr->Position.vz += VDBPtr->VDB_World.vz; + sbPtr->SBdptr->ObFlags&=~ObFlag_NotVis; + + sbPtr->SBdptr->ObWorld = dynPtr->Position; + sbPtr->SBdptr->ObMat = dynPtr->OrientMat; + + ProveHModel(sbPtr->SBdptr->HModelControlBlock,sbPtr->SBdptr); + RenderThisDisplayblock(sbPtr->SBdptr); + + sbPtr->SBdptr->ObFlags|=ObFlag_NotVis; + +} + +static void Execute_FHNS_Attack(STRATEGYBLOCK *sbPtr) +{ + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + + DYNAMICSBLOCK *dynPtr; + FACEHUGGER_STATUS_BLOCK *facehuggerStatusPointer; + + LOCALASSERT(sbPtr); + dynPtr=sbPtr->DynPtr; + facehuggerStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(facehuggerStatusPointer); + LOCALASSERT(dynPtr); + LOCALASSERT(sbPtr->SBdptr); + + /* Play the hugger attack loop sound */ + if (facehuggerStatusPointer->soundHandle == SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_FHUG_ATTACKLOOP,"edl",&facehuggerStatusPointer->soundHandle,&dynPtr->Position); + } + + textprint("face hugger attack \n"); + + /* Make not vis */ + + sbPtr->SBdptr->ObFlags|=ObFlag_NotVis; + + /* do damage */ + facehuggerStatusPointer->DoomTimer += NormalFrameTime; + facehuggerStatusPointer->stateTimer -= NormalFrameTime; + if(facehuggerStatusPointer->stateTimer <= 0) + { + facehuggerStatusPointer->stateTimer = FACEHUGGER_NEARATTACKTIME; + CauseDamageToObject(Player->ObStrategyBlock, &TemplateAmmo[AMMO_FACEHUGGER].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + /* FRI? */ + } + +} + +static void Execute_FHNS_Wait(STRATEGYBLOCK *sbPtr) +{ + FACEHUGGER_STATUS_BLOCK *facehuggerStatusPointer; + + LOCALASSERT(sbPtr); + facehuggerStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(facehuggerStatusPointer); + + if(HuggerShouldAttackPlayer()) + { + NPC_InitMovementData(&(facehuggerStatusPointer->moveData)); + facehuggerStatusPointer->nearBehaviourState = FHNS_Approach; + facehuggerStatusPointer->stateTimer = 0; + facehuggerStatusPointer->CurveTimeOut = 0; + SetHuggerAnimationSequence(sbPtr,HSS_Run,(ONE_FIXED*2)/3); + } +} + +static void Execute_FHNS_Avoidance(STRATEGYBLOCK *sbPtr) +{ + int terminateState = 0; + FACEHUGGER_STATUS_BLOCK *fhugStatusPointer; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + fhugStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr=sbPtr->DynPtr; + LOCALASSERT(fhugStatusPointer); + LOCALASSERT(dynPtr); + + /* Stop any hugger attack sound if playing */ + if (fhugStatusPointer->soundHandle != SOUND_NOACTIVEINDEX && + ActiveSounds[fhugStatusPointer->soundHandle].soundIndex != SID_FHUG_MOVE) + { + Sound_Stop(fhugStatusPointer->soundHandle); + } + + /* Start the hugger movement sound if needed */ + if (fhugStatusPointer->soundHandle == SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_FHUG_MOVE,"ed",&fhugStatusPointer->soundHandle,&dynPtr->Position); + } + + /* set velocity */ + LOCALASSERT((fhugStatusPointer->moveData.avoidanceDirn.vx!=0)|| + (fhugStatusPointer->moveData.avoidanceDirn.vy!=0)|| + (fhugStatusPointer->moveData.avoidanceDirn.vz!=0)); + NPCSetVelocity(sbPtr, &(fhugStatusPointer->moveData.avoidanceDirn), (FACEHUGGER_NEAR_SPEED)); + + /* next, decrement state timer */ + fhugStatusPointer->stateTimer -= NormalFrameTime; + if(fhugStatusPointer->stateTimer <= 0) terminateState = 1; + + /* and check for an impeding collision */ + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_OBSTRUCTIONREPORT obstruction; + NPC_IsObstructed(sbPtr,&(fhugStatusPointer->moveData),&obstruction,&destructableObject); + if(obstruction.anySingleObstruction) + { + terminateState = 1; + } + } + + if(terminateState) + { + if(HuggerShouldAttackPlayer()) + { + /* switch to approach */ + NPC_InitMovementData(&(fhugStatusPointer->moveData)); + fhugStatusPointer->nearBehaviourState = FHNS_Approach; + fhugStatusPointer->stateTimer = 0; + /* no sequence change required */ + } + else + { + /* switch to wait */ + NPC_InitMovementData(&(fhugStatusPointer->moveData)); + fhugStatusPointer->nearBehaviourState = FHNS_Wait; + fhugStatusPointer->stateTimer = 0; + /* no sequence change required */ + } + } +} + +/* ------------------------------------------------------------------- +FaceHugger behaviour support functions + --------------------------------------------------------------------*/ +static void SetHuggerAnimationSequence(STRATEGYBLOCK *sbPtr, HUGGER_SUBSEQUENCES seq, int length) +{ + + FACEHUGGER_STATUS_BLOCK *fhugStatus=(FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + + InitHModelTweening(&fhugStatus->HModelController,(ONE_FIXED>>3),(int)HMSQT_Hugger,(int)seq,length,1); + + if (seq==HSS_Jump) fhugStatus->HModelController.LoopAfterTweening=0; + +} + +static int HuggerShouldAttackPlayer(void) +{ + /* test for player being cloaked */ + { + PLAYER_STATUS *playerStatusPointer= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPointer); + + if((playerStatusPointer->cloakOn==1)&&(playerStatusPointer->cloakPositionGivenAway==0)) { + + return 1; + /* Was '0'. */ + } + + if (playerStatusPointer->MyFaceHugger!=NULL) return(0); + } + + /* test for player being an alien */ + if(AvP.PlayerType==I_Alien) return 0; + + return 1; +} + +static int InContactWithPlayer(DYNAMICSBLOCK *dynPtr) +{ + struct collisionreport *nextReport; + + LOCALASSERT(dynPtr); + nextReport = dynPtr->CollisionReportPtr; + + /* walk the collision report list, looking for collisions against the player */ + while(nextReport) + { + if(nextReport->ObstacleSBPtr == Player->ObStrategyBlock) return 1; + nextReport = nextReport->NextCollisionReportPtr; + } + + return 0; +} + +static void JumpAtPlayer(STRATEGYBLOCK *sbPtr) +{ + + FACEHUGGER_STATUS_BLOCK *fhugStatusPointer=(FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + /* Set up jump! */ + + if (sbPtr->DynPtr->IsInContactWithFloor==0) { + /* Jump Not! */ + return; + } + + /* set animation */ + SetHuggerAnimationSequence(sbPtr, HSS_Jump, (ONE_FIXED)); + fhugStatusPointer->jumping = 1; + fhugStatusPointer->CurveTimeOut = 0; + + fhugStatusPointer->HModelController.Looped=0; + fhugStatusPointer->HModelController.LoopAfterTweening=0; + + fhugStatusPointer->nearBehaviourState = FHNS_Jumping; + fhugStatusPointer->stateTimer=0; + +} + +static void FHugApplyPounceImpulse(STRATEGYBLOCK *sbPtr) { + + FACEHUGGER_STATUS_BLOCK *fhugStatusPointer; + DYNAMICSBLOCK *dynPtr; + VECTORCH pounceVector,targetPoint; + int dist,speed; + + LOCALASSERT(sbPtr); + fhugStatusPointer=(FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(fhugStatusPointer); + LOCALASSERT(dynPtr); + + GetTargetingPointOfObject(Player,&targetPoint); + + dist = VectorDistance(&(dynPtr->Position),&targetPoint); + + /* Apply a correction based on range. */ + targetPoint.vy-=(dist>>3); + + pounceVector.vx=targetPoint.vx-dynPtr->Position.vx; + pounceVector.vy=targetPoint.vy-dynPtr->Position.vy; + pounceVector.vz=targetPoint.vz-dynPtr->Position.vz; + + Normalise(&pounceVector); + /* Must jump at least a little bit upwards. */ + if (pounceVector.vy>-10000) { + pounceVector.vy=-10000; + } + + speed=FACEHUGGER_JUMP_SPEED; + + pounceVector.vx=MUL_FIXED(speed,pounceVector.vx); + pounceVector.vy=MUL_FIXED(speed,pounceVector.vy); + pounceVector.vz=MUL_FIXED(speed,pounceVector.vz); + + sbPtr->DynPtr->LinImpulse=pounceVector; + +} + +static void Execute_FHNS_Jumping(STRATEGYBLOCK *sbPtr) +{ + FACEHUGGER_STATUS_BLOCK *fhugStatusPointer; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + fhugStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr=sbPtr->DynPtr; + LOCALASSERT(fhugStatusPointer); + LOCALASSERT(dynPtr); + + /* don't climb on walls, etc */ + dynPtr->UseStandardGravity=1; + + /* Firstly, are we actually pouncing yet? */ + /* NearStateTimer is a status flag. */ + + if (fhugStatusPointer->stateTimer!=2) { + /* Still tweening? */ + + if (fhugStatusPointer->HModelController.keyframe_flags) { + /* We have the flag. */ + fhugStatusPointer->HModelController.Playing=0; + fhugStatusPointer->stateTimer=1; + } + + if (fhugStatusPointer->stateTimer==1) { + /* We've finished! Are we facing right? */ + VECTORCH orientationDirn; + int i; + + orientationDirn.vx = Player->ObWorld.vx - dynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = Player->ObWorld.vz - dynPtr->Position.vz; + i = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE<<2,NULL); + + if (i==0) { + /* Still not right! Wait for proper facing. */ + fhugStatusPointer->HModelController.Playing=0; + //CheckPounceIntegrity(sbPtr); + return; + } else { + /* Okay, pounce! */ + + FHugApplyPounceImpulse(sbPtr); + + fhugStatusPointer->HModelController.Playing=1; + fhugStatusPointer->stateTimer=2; + } + } else { + /* Yup, still tweening. Check state validity? */ + //CheckPounceIntegrity(sbPtr); + } + } else { + /* We must be in the jump. Can't break out of this until we hit something. */ + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + + while (reportPtr) + { + STRATEGYBLOCK *hitSbPtr = reportPtr->ObstacleSBPtr; + /* You know what? Just did! */ + + fhugStatusPointer->nearBehaviourState=FHNS_Approach; + fhugStatusPointer->stateTimer = 0; + fhugStatusPointer->CurveTimeOut = 0; + + if (hitSbPtr) { + if ((hitSbPtr->SBdptr==Player)&&(sbPtr->SBDamageBlock.IsOnFire==0)) { + /* Got him, My Precious, we've Got Him! */ + + Sound_Play(SID_ED_FACEHUGGERSLAP,"h"); + + /* Test for attach, or merely bite? */ + fhugStatusPointer->nearBehaviourState = FHNS_Attack; + fhugStatusPointer->stateTimer = FACEHUGGER_NEARATTACKTIME; + SetHuggerAnimationSequence(sbPtr,HSS_Attack,ONE_FIXED); + dynPtr->DynamicsType = DYN_TYPE_NO_COLLISIONS; /* turn off collisons */ + dynPtr->GravityOn = 0; /* turn off gravity */ + sbPtr->maintainVisibility = 0; /* turn off visibility support- be carefull! */ + + /* Attach to player! */ + { + PLAYER_STATUS *playerStatusPointer= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + playerStatusPointer->MyFaceHugger=sbPtr; + } + return; + + } + } + + reportPtr = reportPtr->NextCollisionReportPtr; + } + + } + +} + +static void Execute_FHNS_Dying(STRATEGYBLOCK *sbPtr) +{ + FACEHUGGER_STATUS_BLOCK *huggerStatusPointer; + DISPLAYBLOCK *dispPtr; + + LOCALASSERT(sbPtr); + huggerStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(huggerStatusPointer); + + huggerStatusPointer->stateTimer -= NormalFrameTime; + + dispPtr=sbPtr->SBdptr; + + if (dispPtr) + { + dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND; + dispPtr->ObFlags2 = huggerStatusPointer->stateTimer/2; + } +} + +static void Execute_FHNS_Float(STRATEGYBLOCK *sbPtr) +{ + FACEHUGGER_STATUS_BLOCK *facehuggerStatusPointer; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + facehuggerStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr=sbPtr->DynPtr; + LOCALASSERT(facehuggerStatusPointer); + LOCALASSERT(dynPtr); + + dynPtr->LinVelocity.vx=0; + dynPtr->LinVelocity.vy=0; + dynPtr->LinVelocity.vz=0; + + dynPtr->LinImpulse.vx=0; + dynPtr->LinImpulse.vy=0; + dynPtr->LinImpulse.vz=0; + + dynPtr->GravityOn=0; + + /* Just float there... */ +} + +void Wake_Hugger(STRATEGYBLOCK *sbPtr) +{ + FACEHUGGER_STATUS_BLOCK *facehuggerStatusPointer; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + facehuggerStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr=sbPtr->DynPtr; + LOCALASSERT(facehuggerStatusPointer); + LOCALASSERT(dynPtr); + + if (facehuggerStatusPointer->nearBehaviourState==FHNS_Floating) { + facehuggerStatusPointer->nearBehaviourState = FHNS_Approach; + dynPtr->GravityOn=1; + SetHuggerAnimationSequence(sbPtr,HSS_Run,(ONE_FIXED*2)/3); + } +} + +static void Execute_FHNS_AboutToJump(STRATEGYBLOCK *sbPtr) +{ + FACEHUGGER_STATUS_BLOCK *fhugStatusPointer; + DYNAMICSBLOCK *dynPtr; + + /* Should still be playing Walk. */ + + LOCALASSERT(sbPtr); + fhugStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr=sbPtr->DynPtr; + LOCALASSERT(fhugStatusPointer); + LOCALASSERT(dynPtr); + + /* don't climb on walls, etc */ + dynPtr->UseStandardGravity=1; + + { + /* Orientate to target. */ + VECTORCH orientationDirn; + int i; + + orientationDirn.vx = Player->ObWorld.vx - dynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = Player->ObWorld.vz - dynPtr->Position.vz; + i = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + if (i==0) { + /* Still not right! Wait for proper facing. */ + return; + } else { + /* Okay, pounce! */ + int distanceToPlayer = VectorDistance(&(dynPtr->Position),&(Player->ObStrategyBlock->DynPtr->Position)); + if((distanceToPlayer<=FACEHUGGER_JUMPDISTANCE)&&(dynPtr->IsInContactWithFloor) + &&(sbPtr->SBDamageBlock.IsOnFire==0)) { + JumpAtPlayer(sbPtr); + return; + } else { + /* Return to approach. */ + NPC_InitMovementData(&(fhugStatusPointer->moveData)); + fhugStatusPointer->nearBehaviourState = FHNS_Approach; + fhugStatusPointer->stateTimer = 0; + /* no sequence change required */ + } + } + } +} + + + + + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" + +typedef struct face_hugger_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + signed int health; + FACEHUGGER_NEAR_BHSTATE nearBehaviourState; + int stateTimer; + int DoomTimer; + int CurveRadius; + int CurveLength; + int CurveTimeOut; + BOOL jumping; + + + //strategyblock stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; + DYNAMICSBLOCK dynamics; +}FACE_HUGGER_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV huggerStatusPointer + +void LoadStrategy_FaceHugger(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + FACEHUGGER_STATUS_BLOCK* huggerStatusPointer; + FACE_HUGGER_SAVE_BLOCK* block = (FACE_HUGGER_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourFaceHugger) return; + + huggerStatusPointer = (FACEHUGGER_STATUS_BLOCK*)sbPtr->SBdataptr; + + //start copying stuff + COPYELEMENT_LOAD(health) + COPYELEMENT_LOAD(nearBehaviourState) + COPYELEMENT_LOAD(stateTimer) + COPYELEMENT_LOAD(DoomTimer) + COPYELEMENT_LOAD(CurveRadius) + COPYELEMENT_LOAD(CurveLength) + COPYELEMENT_LOAD(CurveTimeOut) + COPYELEMENT_LOAD(jumping) + + //copy strategy block stuff + *sbPtr->DynPtr = block->dynamics; + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + + + //load the hierarchy + { + SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); + if(hier_header) + { + LoadHierarchy(hier_header,&huggerStatusPointer->HModelController); + } + } + Load_SoundState(&huggerStatusPointer->soundHandle); + Load_SoundState(&huggerStatusPointer->soundHandle2); +} + +void SaveStrategy_FaceHugger(STRATEGYBLOCK* sbPtr) +{ + FACE_HUGGER_SAVE_BLOCK* block; + FACEHUGGER_STATUS_BLOCK* huggerStatusPointer; + + huggerStatusPointer = (FACEHUGGER_STATUS_BLOCK*)sbPtr->SBdataptr; + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + COPYELEMENT_SAVE(health) + COPYELEMENT_SAVE(nearBehaviourState) + COPYELEMENT_SAVE(stateTimer) + COPYELEMENT_SAVE(DoomTimer) + COPYELEMENT_SAVE(CurveRadius) + COPYELEMENT_SAVE(CurveLength) + COPYELEMENT_SAVE(CurveTimeOut) + COPYELEMENT_SAVE(jumping) + + //save strategy block stuff + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; + + //save the hierarchy + SaveHierarchy(&huggerStatusPointer->HModelController); + + Save_SoundState(&huggerStatusPointer->soundHandle); + Save_SoundState(&huggerStatusPointer->soundHandle2); + +} \ No newline at end of file diff --git a/3dc/avp/BH_FHUG.H b/3dc/avp/BH_FHUG.H new file mode 100644 index 0000000..b8d3211 --- /dev/null +++ b/3dc/avp/BH_FHUG.H @@ -0,0 +1,112 @@ +/* Patrick 27/2/97 -------------------------------------------- + Header file for facehugger support functions + -------------------------------------------------------------*/ + +#ifndef _bhfhug_h_ +#define _bhfhug_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "bh_pred.h" + +/* ------------------------------------------------------------ + Some enums + -------------------------------------------------------------*/ +typedef enum FhugSequence +{ + FhSQ_Run, + FhSQ_Attack, + FhSQ_Stand, + FhSQ_Jump, +}FHUG_SEQUENCE; + +typedef enum FhugHModelSequence { + FhSSQ_Stand = 0, + FhSSQ_Run, + FhSSQ_Dies, + FhSSQ_Jump, + FhSSQ_Attack, +} FHUG_HMODEL_SEQUENCE; + +#include "sequnces.h" + +typedef enum facehugger_near_bhstate +{ + FHNS_Approach, + FHNS_Attack, + FHNS_Wait, + FHNS_Avoidance, + FHNS_Dying, + FHNS_Floating, + FHNS_Jumping, + FHNS_AboutToJump, +}FACEHUGGER_NEAR_BHSTATE; + +/* ------------------------------------------------------------ + Some structures + -------------------------------------------------------------*/ +typedef struct facehuggerStatusBlock +{ + signed int health; + FACEHUGGER_NEAR_BHSTATE nearBehaviourState; + int stateTimer; + int DoomTimer; + int CurveRadius; + int CurveLength; + int CurveTimeOut; + unsigned int jumping :1; + NPC_MOVEMENTDATA moveData; + HMODELCONTROLLER HModelController; + int soundHandle; + int soundHandle2; + + char death_target_ID[SB_NAME_LENGTH]; + STRATEGYBLOCK* death_target_sbptr; + int death_target_request; +}FACEHUGGER_STATUS_BLOCK; + +typedef struct tools_data_facehugger +{ + struct vectorch position; + int shapeIndex; + char nameID[SB_NAME_LENGTH]; + int startInactive; + + char death_target_ID[SB_NAME_LENGTH]; + int death_target_request; +}TOOLS_DATA_FACEHUGGER; + +/* ------------------------------------------------------------ + Some structures + -------------------------------------------------------------*/ +#define FACEHUGGER_STARTING_HEALTH 5 +#define NO_OF_FRAGMENTS_FROM_DEAD_FHUGA 10 +#define FACEHUGGER_NEAR_SPEED 4000/* 8000 */ +#define FACEHUGGER_JUMPSPEED 6000/* 10000 */ +#define FACEHUGGER_JUMPDISTANCE 3000 +#define FACEHUGGER_ATTACKYOFFSET (-300)/*300*/ +#define FACEHUGGER_ATTACKZOFFSET (325)/*2000*/ +#define FACEHUGGER_NEARATTACKTIME (ONE_FIXED>>2) +#define FACEHUGGER_NEARATTACKDAMAGE 10 +#define FACEHUGGER_DYINGTIME (ONE_FIXED<<2) +#define FACEHUGGER_EXPIRY_TIME 5 +#define FACEHUGGER_JUMP_SPEED (15000) + +/* ------------------------------------------------------------ + Some prototypes + -------------------------------------------------------------*/ +void InitFacehuggerBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr); +void FacehuggerBehaviour(STRATEGYBLOCK *sbPtr); +void MakeFacehuggerNear(STRATEGYBLOCK *sbPtr); +void MakeFacehuggerFar(STRATEGYBLOCK *sbPtr); +void FacehuggerIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple); +void Wake_Hugger(STRATEGYBLOCK *sbPtr); + + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/3dc/avp/BH_GENER.C b/3dc/avp/BH_GENER.C new file mode 100644 index 0000000..bfb02d7 --- /dev/null +++ b/3dc/avp/BH_GENER.C @@ -0,0 +1,1372 @@ +/*----------------Patrick 15/11/96------------------- + Source for NPC generator behavior + ----------------------------------------------------*/ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" + +#include "bh_alien.h" +#include "bh_marin.h" +#include "pfarlocs.h" +#include "bh_gener.h" +#include "pvisible.h" +#include "pheromon.h" +#include "bh_far.h" +#include "bh_marin.h" +#include "pldghost.h" + +#include "load_shp.h" +#define UseLocalAssert Yes +#include "ourasert.h" + +#include "huddefs.h" +#include "ShowCmds.h" + +/* externs for this file */ +extern int NormalFrameTime; +extern char *ModuleCurrVisArray; + +extern void CreateMarineDynamic(STRATEGYBLOCK* Generator,MARINE_NPC_WEAPONS weapon_for_marine); + +/* globals for this file */ +HIVE_DATA NPCHive; + +//generator details that are initialised with in setup_generators in the rif load +HIVELEVELPARAMS LoadedHiveData; +static int TypeOfNPCGenerated; + +/* prototypes for this file */ +static void ResetGeneratorTimer(GENERATOR_BLOCK *genBlock); +static void InitGeneratorTimer(GENERATOR_BLOCK *genBlock); +static void ResetHiveStateTime(void); +int NumNPCsFromThisGenerator(STRATEGYBLOCK* gen_sbptr); + +int SlackTotal; +int SlackSize; +int ShowSlack=0; + +int NearAliens; +int Alt_NearAliens; +int FarAliens; +int Alt_FarAliens; +int ShowHiveState=0; + +/* for testing */ +#define logGenData 0 +#if logGenData +FILE *logFile; +#endif + +/* load generator parameters: pc only*/ +//paramaters now got from rif file +#define LOAD_PC_GENERATORPARAMS 0 +#if LOAD_PC_GENERATORPARAMS + static void LoadGeneratorParams(void); + + +/* Level hive/generator parameters ----------------------------- + +Format: max npcs, initial npcs per minute, + change in npcs per minute (per minute, approx) +--------------------------------------------------------------*/ +HIVELEVELPARAMS hiveLevelData[] = +{ +{25,4,2,(ONE_FIXED*60)}, /* gen 1 : */ +{25,4,2,(ONE_FIXED*90)}, /* gen 2 : */ +{25,4,2,(ONE_FIXED*120)}, /* gen 3 : */ +{25,4,2,(ONE_FIXED*60)}, /* gen 4 : */ +{25,4,2,(ONE_FIXED*60)}, /* Medlab : */ +{25,4,2,(ONE_FIXED*60)}, /* cmc 1 : */ +{25,4,2,(ONE_FIXED*60)}, /* cmc 2 : */ +{25,4,2,(ONE_FIXED*60)}, /* cmc 3 : */ +{25,4,2,(ONE_FIXED*120)}, /* cmc 4 : */ +{25,4,2,(ONE_FIXED*60)}, /* cmc 5 : */ +{25,4,2,(ONE_FIXED*90)}, /* cmc 6 : */ +{25,4,2,(ONE_FIXED*60)}, /* sp 1 : */ +{25,4,2,(ONE_FIXED*60)}, /* sp 2 : */ +{25,4,2,(ONE_FIXED*60)}, /* sp 3 : */ +{25,4,2,(ONE_FIXED*60)}, /* r&d 1 : */ +{25,4,2,(ONE_FIXED*60)}, /* r&d 2 : */ +{25,4,2,(ONE_FIXED*60)}, /* r&d 3 : */ +{25,4,2,(ONE_FIXED*90)}, /* r&d 4 : */ +{25,4,2,(ONE_FIXED*60)}, /* mps 1 : */ +{25,4,2,(ONE_FIXED*120)}, /* mps 2 : */ +{25,4,2,(ONE_FIXED*60)}, /* mps 3 : */ +{25,4,2,(ONE_FIXED*120)}, /* mps 4 : */ +{25,4,2,(ONE_FIXED*60)}, /* surface : */ +{25,2,1,(ONE_FIXED*120)}, /* entrance : */ +}; +#endif + + +/* +Stuff for adjusting difficulty level according to player's performance +*/ +static void GeneratorBalance_Init(); +static void GeneratorBalance_PerFrameMaintenance(); +static int GeneratorBalance_GlobalLimit(); +static int GeneratorBalance_LocalLimit(int normal_limit); + +BOOL UseGeneratorBalance = FALSE; +struct +{ + + int Timer; + + int AIScore; + int PlayerScore; + + int PlayerValue; + + int RateMultiplier; + int MaxAIShift; + + int Counter; + + int MaxOwnSettingNpc; +}GeneratorBalance; + +void ZapSlack(void) { + + SlackTotal=0; + SlackSize=0; + +} + +/*----------------Patrick 15/11/96------------------- + Initialise a generator. + ----------------------------------------------------*/ +void InitGenerator(void *bhdata, STRATEGYBLOCK *sbPtr) +{ + + GENERATOR_BLOCK *toolsData = (GENERATOR_BLOCK *)bhdata; + GENERATOR_BLOCK *genBlock = (GENERATOR_BLOCK *)AllocateMem(sizeof(GENERATOR_BLOCK)); + if (!genBlock) + { + memoryInitialisationFailure = 1; + return; + } + + *genBlock=*toolsData; + + genBlock->Timer = 0; + genBlock->RateIncreaseTimer=60*ONE_FIXED; + if(genBlock->GenerationRate<=0) + genBlock->GenerationRate=1; + + sbPtr->SBdataptr = (void *)genBlock; + sbPtr->maintainVisibility = 0; + sbPtr->containingModule = NULL; + + + sbPtr->shapeIndex=0; //shape index not relevant when using hierarchical models + + if(UseGeneratorBalance && genBlock->use_own_max_npc) + { + GeneratorBalance.MaxOwnSettingNpc+=genBlock->MaxGenNPCs; + } +} + + +/*----------------Patrick 22/1/97------------------- + Generator Behaviour function. + ----------------------------------------------------*/ +void GeneratorBehaviour(STRATEGYBLOCK *sbPtr) +{ + GENERATOR_BLOCK *genBlock = (GENERATOR_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(genBlock); + + /* don't do this for a net game */ +// textprint("GenBeh\n"); + if(AvP.Network != I_No_Network && AvP.NetworkAIServer==0) return; +// textprint("GenBeh ok\n"); + + /* if our number of generators/minute is not > 0, the generator system is + effectively turned off... */ + if(!(NPCHive.generatorNPCsPerMinute>0)) return; + + /*see whether this generator is active*/ + if(!genBlock->Active)return; + + /*if generator is using its own rate values , check for rate increase */ + if(genBlock->use_own_rate_values) + { + genBlock->RateIncreaseTimer-=NormalFrameTime; + if(genBlock->RateIncreaseTimer<0) + { + genBlock->RateIncreaseTimer=ONE_FIXED*60; + genBlock->GenerationRate+=genBlock->GenerationRateIncrease; + genBlock->GenerationRate=min(genBlock->GenerationRate,GENSPERMINUTE_MAX*100); + genBlock->GenerationRate=max(genBlock->GenerationRate,GENSPERMINUTE_MIN*100); + } + } + + /* check the timer */ + if(UseGeneratorBalance && AvP.Network != I_No_Network) + { + genBlock->Timer -= MUL_FIXED(NormalFrameTime,GeneratorBalance.RateMultiplier); + } + else + { + genBlock->Timer -= NormalFrameTime; + } + if(genBlock->Timer > 0) return; + + /* reset the timer */ + ResetGeneratorTimer(genBlock); + + /* at this point, we have reset the timer, and are set to + generate a new npc: however, some things can still + prevent this: eg if the module is visible, or there are too + many generator npcs in the environment */ + + /* if generator is visible, do not create a new NPC */ + if(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]) + { + #if logGenData + { + logFile = fopen("D:/PATRICK/GENLOG.TXT","a"); + fprintf(logFile, "generator: I am visible \n \n"); + fclose(logFile); + } + #endif + return; + } + + /*If in a network game , must also make sure the module isn't visible by other players*/ + if(AvP.Network!=I_No_Network) + { + /* go through the strategy blocks looking for players*/ + int sbIndex; + for(sbIndex=0;sbIndexI_SBtype!=I_BehaviourNetGhost) continue; + ghostData = (NETGHOSTDATABLOCK *)playerSbPtr->SBdataptr; + + if(ghostData->type==I_BehaviourAlienPlayer || + ghostData->type==I_BehaviourMarinePlayer || + ghostData->type==I_BehaviourPredatorPlayer) + { + /*this is another player*/ + if(playerSbPtr->containingModule) + { + if(IsModuleVisibleFromModule(playerSbPtr->containingModule,sbPtr->containingModule)) + { + /*Another player can see this generator's module*/ + return; + } + } + } + } + } + + /* if there are too many NPCs in the module, do not create a new one */ + if(PherAi_Buf[(sbPtr->containingModule->m_aimodule->m_index)] >= MAX_GENERATORNPCSPERMODULE) + { + #if logGenData + { + logFile = fopen("D:/PATRICK/GENLOG.TXT","a"); + fprintf(logFile, "generator: too many aliens in my module \n \n"); + fclose(logFile); + } + #endif + return; + } + /* if there are too many npcs in the env, do not create a new one */ + if(UseGeneratorBalance && AvP.Network != I_No_Network) + { + if(genBlock->use_own_max_npc) + { + //check npcs from this generator + if (NumNPCsFromThisGenerator(sbPtr) >= GeneratorBalance_LocalLimit(genBlock->MaxGenNPCs)) + return; + + } + else + { + //check global npc limit + if (NumGeneratorNPCsInEnv() >= GeneratorBalance_GlobalLimit()) + return; + } + } + else + { + if(genBlock->use_own_max_npc) + { + //check npcs from this generator + if (NumNPCsFromThisGenerator(sbPtr) >= genBlock->MaxGenNPCs) + return; + + } + else + { + //check global npc limit + if (NumGeneratorNPCsInEnv() >= NPCHive.maxGeneratorNPCs) + return; + } + } + /* ok... create an NPC, then */ + GLOBALASSERT(genBlock->WeightingTotal); + { + int random=FastRandom()%genBlock->WeightingTotal; + if(random<0) random=-random; + + //pulse rifle marine + if(randomPulseMarine_Wt) + { + CreateMarineDynamic(sbPtr,MNPCW_PulseRifle); + return; + } + random-=genBlock->PulseMarine_Wt; + + //pistol marine + if(randomPistolMarine_Wt) + { + CreateMarineDynamic(sbPtr,MNPCW_PistolMarine); + return; + } + random-=genBlock->PistolMarine_Wt; + + //flamer marine + if(randomFlameMarine_Wt) + { + CreateMarineDynamic(sbPtr,MNPCW_Flamethrower); + return; + } + random-=genBlock->FlameMarine_Wt; + + //smartgun marine + if(randomSmartMarine_Wt) + { + CreateMarineDynamic(sbPtr,MNPCW_Smartgun); + return; + } + random-=genBlock->SmartMarine_Wt; + + //sadar marine + if(randomSadarMarine_Wt) + { + CreateMarineDynamic(sbPtr,MNPCW_SADAR); + return; + } + random-=genBlock->SadarMarine_Wt; + + //grenade marine + if(randomGrenadeMarine_Wt) + { + CreateMarineDynamic(sbPtr,MNPCW_GrenadeLauncher); + return; + } + random-=genBlock->GrenadeMarine_Wt; + + + //minigun marine + if(randomMinigunMarine_Wt) + { + CreateMarineDynamic(sbPtr,MNPCW_Minigun); + return; + } + random-=genBlock->MinigunMarine_Wt; + + //shotgun civilian + if(randomShotgunCiv_Wt) + { + CreateMarineDynamic(sbPtr,MNPCW_MShotgun); + return; + } + random-=genBlock->ShotgunCiv_Wt; + + //pistol civilian + if(randomPistolCiv_Wt) + { + CreateMarineDynamic(sbPtr,MNPCW_MPistol); + return; + } + random-=genBlock->PistolCiv_Wt; + + //flamer civilian + if(randomFlameCiv_Wt) + { + CreateMarineDynamic(sbPtr,MNPCW_MFlamer); + return; + } + random-=genBlock->FlameCiv_Wt; + + //unarmed civilian + if(randomUnarmedCiv_Wt) + { + CreateMarineDynamic(sbPtr,MNPCW_MUnarmed); + return; + } + random-=genBlock->UnarmedCiv_Wt; + + //molotov civilian + if(randomMolotovCiv_Wt) + { + CreateMarineDynamic(sbPtr,MNPCW_MMolotov); + return; + } + random-=genBlock->MolotovCiv_Wt; + + //alien + if(randomAlien_Wt) + { + CreateAlienDynamic(sbPtr,AT_Standard); + return; + } + random-=genBlock->Alien_Wt; + + //predator alien + if(randomPredAlien_Wt) + { + CreateAlienDynamic(sbPtr,AT_Predalien); + return; + } + random-=genBlock->PredAlien_Wt; + + //praetorian + if(randomPraetorian_Wt) + { + CreateAlienDynamic(sbPtr,AT_Praetorian); + return; + } + random-=genBlock->Praetorian_Wt; + + GLOBALASSERT(0=="Failed to select generator badguy"); + + } + +} + + +/*----------------Patrick 21/1/97------------------- + Initialise the hive + ----------------------------------------------------*/ +void InitHive(void) +{ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + int sbIndex = 0; + STRATEGYBLOCK *sbPtr; + + GeneratorBalance_Init(); + + /* initialise the hive data */ + NPCHive.currentState = HS_Attack; + NPCHive.numGenerators = 0; + + NPCHive.hiveStateTimer = 0; + NPCHive.genRateTimer = 0; + NPCHive.maxGeneratorNPCs = 0; + NPCHive.generatorNPCsPerMinute = 0; + NPCHive.deltaGeneratorNPCsPerMinute = 0; + + NPCHive.AliensCanBeGenerated = FALSE; + NPCHive.PredAliensCanBeGenerated = FALSE; + NPCHive.PraetoriansCanBeGenerated = FALSE; + + SlackTotal=0; + SlackSize=0; + + NearAliens=0; + Alt_NearAliens=0; + FarAliens=0; + Alt_FarAliens=0; + + /* don't do any more for a net game */ + /* actually, do - Richard */ +// if(AvP.Network != I_No_Network && AvP.NetworkAIServer==0) return; +// if(AvP.Network != I_No_Network) return; + + + + + /* set the level parameters */ +// NPCHive.maxGeneratorNPCs = hiveLevelData[AvP.CurrentEnv].maxGeneratorNPCs; +// NPCHive.generatorNPCsPerMinute = hiveLevelData[AvP.CurrentEnv].generatorNPCsPerMinute; +// NPCHive.deltaGeneratorNPCsPerMinute = hiveLevelData[AvP.CurrentEnv].deltaGeneratorNPCsPerMinute; +// NPCHive.genRateTimer = (ONE_FIXED*60); +// +// /* validate these parameters */ +// if(NPCHive.maxGeneratorNPCs > MAXGENNPCS_MAX) +// NPCHive.maxGeneratorNPCs = MAXGENNPCS_MAX; +// if(NPCHive.maxGeneratorNPCs < MAXGENNPCS_MIN) +// NPCHive.maxGeneratorNPCs = MAXGENNPCS_MIN; +// if(NPCHive.generatorNPCsPerMinute > GENSPERMINUTE_MAX) +// NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MAX; +// if(NPCHive.generatorNPCsPerMinute < GENSPERMINUTE_MIN) +// NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MIN; +// if(NPCHive.deltaGeneratorNPCsPerMinute > INCREASEGENSPERMINUTE_MAX) +// NPCHive.deltaGeneratorNPCsPerMinute = INCREASEGENSPERMINUTE_MAX; +// if(NPCHive.deltaGeneratorNPCsPerMinute < INCREASEGENSPERMINUTE_MIN) +// NPCHive.deltaGeneratorNPCsPerMinute = INCREASEGENSPERMINUTE_MIN; +// +// /* init the hive timer */ +// ResetHiveStateTime(); + + /* Now in ActivateHive. */ + + /* Some futher generator initialisations: work out what modules the generators are + in, and how many generators there are. + */ + sbIndex = 0; + while(sbIndex < NumActiveStBlocks) + { + sbPtr = ActiveStBlockList[sbIndex++]; + if(sbPtr->I_SBtype == I_BehaviourGenerator) + { + GENERATOR_BLOCK *genBlock = (GENERATOR_BLOCK *)sbPtr->SBdataptr; + sbPtr->containingModule = ModuleFromPosition(&genBlock->Position, (MODULE *)0); + LOCALASSERT(sbPtr->containingModule); + NPCHive.numGenerators++; + /* init generator times to something quite small... + so that we get some npcs in the env quickly */ + genBlock->Timer = ONE_FIXED; + + //work out which types of alien can be generated on this level (for multiplayer) + if(genBlock->Alien_Wt) NPCHive.AliensCanBeGenerated = TRUE; + if(genBlock->PredAlien_Wt) NPCHive.PredAliensCanBeGenerated = TRUE; + if(genBlock->Praetorian_Wt) NPCHive.PraetoriansCanBeGenerated = TRUE; + } + } + + #if logGenData + { + logFile = fopen("D:/PATRICK/GENLOG.TXT","w"); + fprintf(logFile, "GENERATOR/HIVE DATA LOG \n \n"); + fprintf(logFile, "num Geners: %d \n",NPCHive.numGenerators); + fprintf(logFile, "hive timer: %d \n",NPCHive.hiveStateTimer); + fprintf(logFile, "max npcs: %d \n",NPCHive.maxGeneratorNPCs); + fprintf(logFile, "npcs per min: %d \n",NPCHive.generatorNPCsPerMinute); + fprintf(logFile, "change in npcs per min: %d \n \n",NPCHive.deltaGeneratorNPCsPerMinute); + fclose(logFile); + } + #endif + + ActivateHive(); + +} + +void ActivateHive(void) { + + /* Placed in for Jules's level... CDF 1/12/97, Deadline day! */ + + NPCHive.maxGeneratorNPCs=LoadedHiveData.maxGeneratorNPCs; + NPCHive.generatorNPCsPerMinute=LoadedHiveData.generatorNPCsPerMinute; + NPCHive.deltaGeneratorNPCsPerMinute=LoadedHiveData.deltaGeneratorNPCsPerMinute; + NPCHive.genRateTimer=60*ONE_FIXED; + + /* validate these parameters */ + if(NPCHive.maxGeneratorNPCs > MAXGENNPCS_MAX) + NPCHive.maxGeneratorNPCs = MAXGENNPCS_MAX; + if(NPCHive.maxGeneratorNPCs < MAXGENNPCS_MIN) + NPCHive.maxGeneratorNPCs = MAXGENNPCS_MIN; + if(NPCHive.generatorNPCsPerMinute > GENSPERMINUTE_MAX) + NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MAX; + if(NPCHive.generatorNPCsPerMinute < GENSPERMINUTE_MIN) + NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MIN; + if(NPCHive.deltaGeneratorNPCsPerMinute > INCREASEGENSPERMINUTE_MAX) + NPCHive.deltaGeneratorNPCsPerMinute = INCREASEGENSPERMINUTE_MAX; + if(NPCHive.deltaGeneratorNPCsPerMinute < INCREASEGENSPERMINUTE_MIN) + NPCHive.deltaGeneratorNPCsPerMinute = INCREASEGENSPERMINUTE_MIN; + + /* init the hive timer */ + ResetHiveStateTime(); + +} + +void DeActivateHive(void) { + + NPCHive.genRateTimer = 0; + NPCHive.maxGeneratorNPCs = 0; + NPCHive.generatorNPCsPerMinute = 0; + NPCHive.deltaGeneratorNPCsPerMinute = 0; + + /* validate these parameters */ + if(NPCHive.maxGeneratorNPCs > MAXGENNPCS_MAX) + NPCHive.maxGeneratorNPCs = MAXGENNPCS_MAX; + if(NPCHive.maxGeneratorNPCs < MAXGENNPCS_MIN) + NPCHive.maxGeneratorNPCs = MAXGENNPCS_MIN; + if(NPCHive.generatorNPCsPerMinute > GENSPERMINUTE_MAX) + NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MAX; + if(NPCHive.generatorNPCsPerMinute < GENSPERMINUTE_MIN) + NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MIN; + if(NPCHive.deltaGeneratorNPCsPerMinute > INCREASEGENSPERMINUTE_MAX) + NPCHive.deltaGeneratorNPCsPerMinute = INCREASEGENSPERMINUTE_MAX; + if(NPCHive.deltaGeneratorNPCsPerMinute < INCREASEGENSPERMINUTE_MIN) + NPCHive.deltaGeneratorNPCsPerMinute = INCREASEGENSPERMINUTE_MIN; + + /* init the hive timer */ + ResetHiveStateTime(); + +} + +/*---------------------Patrick 21/1/97------------------------ + Do hive management: + generator time is decreased at the start of an attack phase + ------------------------------------------------------------*/ +void DoHive(void) +{ + /* don't do this for a net game */ + if(AvP.Network != I_No_Network && AvP.NetworkAIServer==0) return; +// if(AvP.Network != I_No_Network) return; + + if(AvP.Network != I_No_Network) + { + GeneratorBalance_PerFrameMaintenance(); + } + + NearAliens=Alt_NearAliens; + Alt_NearAliens=0; + FarAliens=Alt_FarAliens; + Alt_FarAliens=0; + + /* chack hive state timer */ + NPCHive.hiveStateTimer -= NormalFrameTime; + if(NPCHive.hiveStateTimer <= 0) + { + /* state change */ + if(NPCHive.currentState == HS_Attack) + { + #if ULTRAVIOLENCE + /* Hackery. An experiment. CDF 2/12/97. Ha. */ + NPCHive.currentState = HS_Attack; + #else + /* switch to regroup */ + NPCHive.currentState = HS_Regroup; + #endif + } + else + { + /* switch to attack */ + #if ULTRAVIOLENCE + #else + LOCALASSERT(NPCHive.currentState == HS_Regroup); + #endif + NPCHive.currentState = HS_Attack; + } + ResetHiveStateTime(); + } + + /* check gen rate timer */ + NPCHive.genRateTimer -= NormalFrameTime; + if(NPCHive.genRateTimer <= 0) + { + /* increase frequency */ + NPCHive.generatorNPCsPerMinute += NPCHive.deltaGeneratorNPCsPerMinute; + /* validate this value */ + if(NPCHive.generatorNPCsPerMinute > GENSPERMINUTE_MAX) + NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MAX; + if(NPCHive.generatorNPCsPerMinute < GENSPERMINUTE_MIN) + NPCHive.generatorNPCsPerMinute = GENSPERMINUTE_MIN; + + NPCHive.genRateTimer = (ONE_FIXED*60); + } + + /* Print hive state. */ + + if(NPCHive.currentState == HS_Attack) { + if (ShowHiveState) { + PrintDebuggingText("Hive Attacking %d...\n",NPCHive.hiveStateTimer); + } + } else { + if (ShowHiveState) { + PrintDebuggingText("Hive Retreating %d...\n",NPCHive.hiveStateTimer); + } + } + + if (ShowHiveState) { + PrintDebuggingText("Near Aliens = %d\nFar Aliens = %d\n",NearAliens,FarAliens); + } + + if ((SlackSize)&&(ShowSlack)) { + int Slack; + + Slack=(SlackTotal/SlackSize); + PrintDebuggingText("Average Slack %d\n",Slack); + } +} + + +/*----------------Patrick 22/1/97------------------- + Timer functions + ----------------------------------------------------*/ +static void ResetGeneratorTimer(GENERATOR_BLOCK *genBlock) +{ + LOCALASSERT(genBlock); + + /* shouldn't be doing this for a net game */ +// LOCALASSERT(AvP.Network == I_No_Network); + + if(genBlock->use_own_rate_values) + { + LOCALASSERT(genBlock->GenerationRate); + genBlock->Timer = (60 * ONE_FIXED *100)/genBlock->GenerationRate; + } + else + { + /* if we get here, there must be at least one generator, and some kind of generator rate */ + LOCALASSERT(NPCHive.numGenerators>0); + LOCALASSERT(NPCHive.generatorNPCsPerMinute>0); + + /* set the timer */ + genBlock->Timer = (((60 * ONE_FIXED)/(NPCHive.generatorNPCsPerMinute))*NPCHive.numGenerators); + } + /* randomise +- an eighth */ + { + int baseTime = genBlock->Timer; + genBlock->Timer = ((baseTime*7)/8) + (FastRandom()%(baseTime/4)); + } + /* clamp */ + if(genBlock->Timer>GENERATORTIME_MAX) genBlock->Timer=GENERATORTIME_MAX; + if(genBlock->TimerTimer=GENERATORTIME_MIN; + + #if logGenData + { + logFile = fopen("D:/PATRICK/GENLOG.TXT","a"); + fprintf(logFile, "Reset Gen Timer \n"); + fprintf(logFile, "gen timer to: %d seconds \n \n",genBlock->Timer); + fclose(logFile); + } + #endif +} + +static void ResetHiveStateTime(void) +{ + int baseTime; + + /* shouldn't be doing this for a net game */ +// LOCALASSERT(AvP.Network == I_No_Network); + + /* set the timer, +- an eighth */ + baseTime = LoadedHiveData.hiveStateBaseTime; + NPCHive.hiveStateTimer = ((baseTime*7)/8) + (FastRandom()%(baseTime/4)); + + #if logGenData + { + logFile = fopen("D:/PATRICK/GENLOG.TXT","a"); + fprintf(logFile, "Reset Hive Timer \n"); + fprintf(logFile, "hive timer to: %d seconds \n \n",NPCHive.hiveStateTimer); + fclose(logFile); + } + #endif +} + + +/* Patrick 11/8/97 --------------------------------------------------- + A couple of useful functions + -------------------------------------------------------------------*/ +int NumGeneratorNPCsInEnv(void) +{ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + int sbIndex = 0; + STRATEGYBLOCK *sbPtr; + int numOfNPCs = 0; + + while(sbIndex < NumActiveStBlocks) + { + sbPtr = ActiveStBlockList[sbIndex++]; + if((sbPtr->I_SBtype == I_BehaviourAlien)||(sbPtr->I_SBtype == I_BehaviourMarine)) + { + //All placed bad guys will have the last character of the sbname as 0 + //generated badguys shoud have a non-zero last character. + if(sbPtr->SBname[SB_NAME_LENGTH-1]) + { + numOfNPCs++; + } + } + } + + #if logGenData + { + logFile = fopen("D:/PATRICK/GENLOG.TXT","a"); + fprintf(logFile, "current num gener npcs: %d \n \n",numOfNPCs); + fclose(logFile); + } + #endif + return numOfNPCs; +} +int NumNPCsFromThisGenerator(STRATEGYBLOCK* gen_sbptr) +{ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + int sbIndex = 0; + STRATEGYBLOCK *sbPtr; + int numOfNPCs = 0; + + while(sbIndex < NumActiveStBlocks) + { + sbPtr = ActiveStBlockList[sbIndex++]; + switch(sbPtr->I_SBtype) + { + case I_BehaviourAlien : + { + ALIEN_STATUS_BLOCK* status_block=(ALIEN_STATUS_BLOCK*)sbPtr->SBdataptr; + GLOBALASSERT(status_block); + + if(status_block->generator_sbptr==gen_sbptr) + { + //this alien was produced by this generator + numOfNPCs++; + } + } + break; + + case I_BehaviourMarine : + { + MARINE_STATUS_BLOCK* status_block=(MARINE_STATUS_BLOCK*)sbPtr->SBdataptr; + GLOBALASSERT(status_block); + + if(status_block->generator_sbptr==gen_sbptr) + { + //this marine was produced by this generator + numOfNPCs++; + } + } + break; + + //default - do nothing + } + + } + + return numOfNPCs; +} + + +int NumGeneratorNPCsVisible(void) +{ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + int sbIndex = 0; + STRATEGYBLOCK *sbPtr; + int numOfVisNPCs = 0; + + while(sbIndex < NumActiveStBlocks) + { + sbPtr = ActiveStBlockList[sbIndex++]; + if((sbPtr->I_SBtype == I_BehaviourAlien)||(sbPtr->I_SBtype == I_BehaviourMarine)) + { + if(sbPtr->SBdptr)numOfVisNPCs++; + } + } + #if logGenData + { + logFile = fopen("D:/PATRICK/GENLOG.TXT","a"); + fprintf(logFile, "current num visible npcs: %d \n \n",numOfVisNPCs); + fclose(logFile); + } + #endif + return numOfVisNPCs; +} + +void ForceAGenerator_Shell(void) { + + NewOnScreenMessage("FORCING...\n"); + ForceAGenerator(); +} + +void ForceAGenerator(void) +{ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + int sbIndex = 0; + STRATEGYBLOCK *sbPtr; + #if logGenData + { + logFile = fopen("D:/PATRICK/GENLOG.TXT","a"); + fprintf(logFile, "forcing a generator... \n"); + fclose(logFile); + } + #endif + + while(sbIndex < NumActiveStBlocks) + { + sbPtr = ActiveStBlockList[sbIndex++]; + if(sbPtr->I_SBtype == I_BehaviourGenerator) + { + GENERATOR_BLOCK *genBlock = (GENERATOR_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(genBlock); + + if(genBlock->Timer>0) + { + /* found a generator with timer>0, so set it to zero and return */ + genBlock->Timer = 0; + #if logGenData + { + logFile = fopen("D:/PATRICK/GENLOG.TXT","a"); + fprintf(logFile, "... forced generator ref %d \n \n",sbIndex); + fclose(logFile); + } + #endif + return; + } + } + } + #if logGenData + { + logFile = fopen("D:/PATRICK/GENLOG.TXT","a"); + fprintf(logFile, "... didn't find one to force \n \n"); + fclose(logFile); + } + #endif + +} + + +#if (SupportWindows95 && LOAD_PC_GENERATORPARAMS) +static char genFileLine[128]; +static void LoadGeneratorParams(void) +{ + FILE* genParamsFile; + int numValsRead = 0; + + genParamsFile = fopen("GENPARAM.TXT","r"); + + /* do nothing if we can't load the file */ + if(!genParamsFile) return; + + while(fgets((char*)genFileLine,128,genParamsFile)) + { + if(!(strncmp((char*)genFileLine,"#",1))) continue; /* a comment line */ + if(strlen((char*)genFileLine) > 4) continue; /* too long */ + + /* should be a data line... + convert to an int and set appropriate value in hiveData[] */ + { + int thisValue; + I_AVP_ENVIRONMENTS thisLevel = 0; + + thisValue = atoi(genFileLine); + switch(numValsRead/3) + { + case(0): + { + thisLevel = I_Gen1; + break; + } + case(1): + { + thisLevel = I_Gen2; + break; + } + case(2): + { + thisLevel = I_Gen3; + break; + } + case(3): + { + thisLevel = I_Medlab; + break; + } + case(4): + { + thisLevel = I_Cmc2; + break; + } + case(5): + { + thisLevel = I_Cmc4; + break; + } + case(6): + { + thisLevel = I_Cmc6; + break; + } + case(7): + { + thisLevel = I_Sp2; + break; + } + case(8): + { + thisLevel = I_Sp3; + break; + } + case(9): + { + thisLevel = I_Rnd2; + break; + } + case(10): + { + thisLevel = I_Rnd3; + break; + } + case(11): + { + thisLevel = I_Rnd4; + break; + } + case(12): + { + thisLevel = I_Mps2; + break; + } + case(13): + { + thisLevel = I_Mps4; + break; + } + case(14): + { + thisLevel = I_Surface; + break; + } + case(15): + { + thisLevel = I_Entrance; + break; + } + default: + { + /* there should only be 16 levels in the file */ + LOCALASSERT(1==0); + continue; + break; + } + } + + switch(numValsRead%3) + { + case(0): + { + hiveLevelData[thisLevel].maxGeneratorNPCs = thisValue; + break; + } + case(1): + { + hiveLevelData[thisLevel].generatorNPCsPerMinute = thisValue; + break; + } + case(2): + { + hiveLevelData[thisLevel].deltaGeneratorNPCsPerMinute = thisValue; + break; + } + default: + { + /* there should only be 16 levels in the file */ + LOCALASSERT(1==0); + break; + } + } + } + numValsRead++; + } + fclose(genParamsFile); +} +#endif + + + +void SetHiveParamaters(int enemytype,int max,int genpermin,int deltagenpermin,int time) +{ + LoadedHiveData.maxGeneratorNPCs=max; + LoadedHiveData.generatorNPCsPerMinute=genpermin; + LoadedHiveData.deltaGeneratorNPCsPerMinute=deltagenpermin; + LoadedHiveData.hiveStateBaseTime=time; + + TypeOfNPCGenerated=enemytype; +} + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" +typedef struct generator_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int Timer; + int Active; + + int GenerationRate; //scaled up by 100 + int RateIncreaseTimer; +}GENERATOR_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV genBlock + + +void LoadStrategy_Generator(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + GENERATOR_BLOCK *genBlock; + GENERATOR_SAVE_BLOCK* block = (GENERATOR_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourGenerator) return; + + genBlock = (GENERATOR_BLOCK*)sbPtr->SBdataptr; + + //start copying stuff + + COPYELEMENT_LOAD(Timer) + COPYELEMENT_LOAD(Active) + COPYELEMENT_LOAD(GenerationRate) + COPYELEMENT_LOAD(RateIncreaseTimer) + +} + +void SaveStrategy_Generator(STRATEGYBLOCK* sbPtr) +{ + GENERATOR_SAVE_BLOCK *block; + GENERATOR_BLOCK *genBlock; + genBlock = (GENERATOR_BLOCK*)sbPtr->SBdataptr; + + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + + COPYELEMENT_SAVE(Timer) + COPYELEMENT_SAVE(Active) + COPYELEMENT_SAVE(GenerationRate) + COPYELEMENT_SAVE(RateIncreaseTimer) + +} + + +/*----------------------------------** +** And now the global hive settings ** +**----------------------------------*/ + + +typedef struct hive_save_block +{ + SAVE_BLOCK_HEADER header; + + HIVE_STATE currentState; + int hiveStateTimer; + int genRateTimer; + int generatorNPCsPerMinute; + +}HIVE_SAVE_BLOCK; + +#undef SAVELOAD_BLOCK +#undef SAVELOAD_BEHAV +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV (&NPCHive) + +void LoadHiveSettings(SAVE_BLOCK_HEADER* header) +{ + HIVE_SAVE_BLOCK* block = (HIVE_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + COPYELEMENT_LOAD(currentState) + COPYELEMENT_LOAD(hiveStateTimer) + COPYELEMENT_LOAD(genRateTimer) + COPYELEMENT_LOAD(generatorNPCsPerMinute) + +} + +void SaveHiveSettings() +{ + HIVE_SAVE_BLOCK* block; + GET_SAVE_BLOCK_POINTER(block); + + //fill in the header + block->header.type = SaveBlock_GlobalHive; + block->header.size = sizeof(*block); + + + COPYELEMENT_SAVE(currentState) + COPYELEMENT_SAVE(hiveStateTimer) + COPYELEMENT_SAVE(genRateTimer) + COPYELEMENT_SAVE(generatorNPCsPerMinute) +} + + + + + + + + +int GeneratorBalance_PlayerScoreValue = 0; + +#define GENERATOR_BALANCE_DECAY (ONE_FIXED * .01) +#define GENERATOR_BALANCE_THRESHHOLD (100000) + +static void GeneratorBalance_Init() +{ + GeneratorBalance.PlayerValue = GeneratorBalance_PlayerScoreValue*100; + + GeneratorBalance.Timer = 0; + GeneratorBalance.AIScore = 0; + GeneratorBalance.PlayerScore = 0; + + GeneratorBalance.RateMultiplier = ONE_FIXED; + GeneratorBalance.MaxAIShift = 0; + GeneratorBalance.Counter = GENERATOR_BALANCE_THRESHHOLD/2; + + GeneratorBalance.MaxOwnSettingNpc = 0; + +} + +void GeneratorBalance_NotePlayerDeath() +{ + if(!UseGeneratorBalance) return; + + GeneratorBalance.PlayerScore += GeneratorBalance.PlayerValue; +} + +void GeneratorBalance_NoteAIDeath() +{ + if(!UseGeneratorBalance) return; + + GeneratorBalance.AIScore+=100; +} + +static void GeneratorBalance_PerFrameMaintenance() +{ + if(GeneratorBalance.PlayerValue!=GeneratorBalance_PlayerScoreValue*100) + { + GeneratorBalance.PlayerValue=GeneratorBalance_PlayerScoreValue*100; + UseGeneratorBalance = (GeneratorBalance.PlayerValue>0); + } + + if(!UseGeneratorBalance) return; + + +// PrintDebuggingText("\n\n\n\n\nAI : %d\n",GeneratorBalance.AIScore); +// PrintDebuggingText("Player : %d\n",GeneratorBalance.PlayerScore); +// PrintDebuggingText("Counter : %d\n",GeneratorBalance.Counter); + PrintDebuggingText("\n\n\nAi Limit Shift : %d\n",GeneratorBalance.MaxAIShift); + + + GeneratorBalance.Timer += NormalFrameTime; + + if(GeneratorBalance.Timer > 10 * ONE_FIXED) + { + GeneratorBalance.Timer-= 10 * ONE_FIXED; + + if(GeneratorBalance.PlayerScore>0 || GeneratorBalance.AIScore>0) + { + + if(GeneratorBalance.PlayerScore>GeneratorBalance.AIScore) + { + //make things easier + int ratio = DIV_FIXED(GeneratorBalance.PlayerScore+GeneratorBalance.PlayerValue,GeneratorBalance.AIScore+GeneratorBalance.PlayerValue); + +/* + if(ratio > (ONE_FIXED*1.1)) + { + GeneratorBalance.RateMultiplier = DIV_FIXED(GeneratorBalance.RateMultiplier,ONE_FIXED *1.1); + } +*/ + { + int decrement = ratio - ONE_FIXED; + if(GeneratorBalance.MaxAIShift < 0) + { + decrement /= (-GeneratorBalance.MaxAIShift)+1; + } + + GeneratorBalance.Counter-=decrement; + if(GeneratorBalance.Counter<0) + { + GeneratorBalance.Counter = GENERATOR_BALANCE_THRESHHOLD/2; + GeneratorBalance.MaxAIShift--; + GeneratorBalance.PlayerScore = GeneratorBalance.AIScore; + + } + + } + } + else + { + //make things harder + int ratio = DIV_FIXED(GeneratorBalance.AIScore+GeneratorBalance.PlayerValue,GeneratorBalance.PlayerScore+GeneratorBalance.PlayerValue); + /* + if(ratio > (ONE_FIXED*1.1)) + { + GeneratorBalance.RateMultiplier = MUL_FIXED(GeneratorBalance.RateMultiplier,ONE_FIXED *1.1); + } +*/ + + + { + int increment = ratio - ONE_FIXED; + if(GeneratorBalance.MaxAIShift > 0) + { + increment /= GeneratorBalance.MaxAIShift+1; + } + + GeneratorBalance.Counter+=increment; + if(GeneratorBalance.Counter>GENERATOR_BALANCE_THRESHHOLD) + { + GeneratorBalance.Counter = GENERATOR_BALANCE_THRESHHOLD/2; + GeneratorBalance.MaxAIShift++; + GeneratorBalance.AIScore = GeneratorBalance.PlayerScore; + + } + + } + } + GeneratorBalance.AIScore -= MUL_FIXED(GENERATOR_BALANCE_DECAY,GeneratorBalance.AIScore); + GeneratorBalance.PlayerScore -= MUL_FIXED(GENERATOR_BALANCE_DECAY,GeneratorBalance.PlayerScore); + } + + if(GeneratorBalance.RateMultiplier > 4*ONE_FIXED) GeneratorBalance.RateMultiplier = 4*ONE_FIXED; + if(GeneratorBalance.RateMultiplier < ONE_FIXED/4) GeneratorBalance.RateMultiplier = ONE_FIXED/4; + + + + + } +} + + +static int GeneratorBalance_GlobalLimit() +{ + int limit = NPCHive.maxGeneratorNPCs + GeneratorBalance.MaxAIShift; + + if(limit < 2) limit = 2; + if(limit > NPCHive.maxGeneratorNPCs +4) limit = NPCHive.maxGeneratorNPCs +4; + return(limit); +} + +static int GeneratorBalance_LocalLimit(int normal_limit) +{ + if(GeneratorBalance.MaxAIShift == 0) return(normal_limit); + + if(GeneratorBalance.MaxAIShift < 0) + { + int limit = GeneratorBalance.MaxOwnSettingNpc + GeneratorBalance.MaxAIShift; + + if(limit < 2) limit = 2; + + if(NumGeneratorNPCsInEnv() >= limit) return(0); + return(normal_limit); + } + else + { + int shift = min(GeneratorBalance.MaxAIShift,4); + int limit = GeneratorBalance.MaxOwnSettingNpc + shift; + int alien_shortfall = limit - NumGeneratorNPCsInEnv(); + + return(normal_limit + min(alien_shortfall,shift)); + + } +} diff --git a/3dc/avp/BH_GENER.H b/3dc/avp/BH_GENER.H new file mode 100644 index 0000000..0cb48e2 --- /dev/null +++ b/3dc/avp/BH_GENER.H @@ -0,0 +1,131 @@ +/*----------------Patrick 15/11/96------------------- + Header for NPC generators + ----------------------------------------------------*/ + +#ifndef _bhgenerator_h_ + #define _bhgenerator_h_ 1 + + #ifdef __cplusplus + extern "C" { + #endif + + + /*----------------Patrick 15/11/96------------------- + Generator behaviour data block. NB generators + have their own module ptr, as they are not included + in the visibility system. + ----------------------------------------------------*/ + typedef struct generatorblock + { + int PulseMarine_Wt; + int FlameMarine_Wt; + int SmartMarine_Wt; + int SadarMarine_Wt; + int GrenadeMarine_Wt; + int MinigunMarine_Wt; + int ShotgunCiv_Wt; + int PistolCiv_Wt; + int FlameCiv_Wt; + int UnarmedCiv_Wt; + int MolotovCiv_Wt; + + int Alien_Wt; + int PredAlien_Wt; + int Praetorian_Wt; + + int PistolMarine_Wt; + + int WeightingTotal; + + /* Pathfinder parameters */ + /* If these values aren't -1 , then the generator produces path following creatures*/ + int path; + int stepnumber; + + + struct vectorch Position; + int Timer; + /* generator can be switched on and off via the request state function */ + int Active; + + int GenerationRate; //scaled up by 100 + int GenerationRateIncrease; //scaled up by 100 + int RateIncreaseTimer; + int MaxGenNPCs;//limit for this generator + + /*if use_own_rate_values is false then the generator will use the global + generation rates*/ + unsigned int use_own_rate_values :1; + unsigned int use_own_max_npc :1; + } GENERATOR_BLOCK; + + + /*----------------Patrick 22/1/97------------------- + Hive enums and data structure. + Note that only one hive exists in the game. + ----------------------------------------------------*/ + typedef enum hive_state + { + HS_Attack, + HS_Regroup, + + }HIVE_STATE; + + typedef struct hive_data + { + HIVE_STATE currentState; + int numGenerators; + int hiveStateTimer; + int genRateTimer; + int maxGeneratorNPCs; + int generatorNPCsPerMinute; + int deltaGeneratorNPCsPerMinute; + + BOOL AliensCanBeGenerated; + BOOL PredAliensCanBeGenerated; + BOOL PraetoriansCanBeGenerated; + + } HIVE_DATA; + + typedef struct hivelevelparams + { + int maxGeneratorNPCs; + int generatorNPCsPerMinute; + int deltaGeneratorNPCsPerMinute; + int hiveStateBaseTime; + } HIVELEVELPARAMS; + + extern int ShowSlack; + /* prototypes */ + extern void InitGenerator(void *posn, STRATEGYBLOCK *sbPtr); + extern void GeneratorBehaviour(STRATEGYBLOCK *sbPtr); + extern void InitHive(void); + extern void DoHive(void); + extern int NumGeneratorNPCsInEnv(void); + extern int NumGeneratorNPCsVisible(void); + extern void ForceAGenerator(void); + extern void ActivateHive(void); + + /* defines */ + #define DEFAULTHIVESTATETIME (60*ONE_FIXED) + + #define MAXGENNPCS_MAX (255) + #define MAXGENNPCS_MIN (0) + #define GENSPERMINUTE_MAX (255) + #define GENSPERMINUTE_MIN (0) + #define INCREASEGENSPERMINUTE_MAX (255) + #define INCREASEGENSPERMINUTE_MIN (0) + + #define GENERATORTIME_MAX (120*ONE_FIXED) + #define GENERATORTIME_MIN (3*ONE_FIXED) + + /* globals */ + extern HIVE_DATA NPCHive; + + #ifdef __cplusplus + } + #endif + +extern void GeneratorBalance_NoteAIDeath(); +extern void GeneratorBalance_NotePlayerDeath(); +#endif \ No newline at end of file diff --git a/3dc/avp/BH_LNKSW.C b/3dc/avp/BH_LNKSW.C new file mode 100644 index 0000000..d3f602b --- /dev/null +++ b/3dc/avp/BH_LNKSW.C @@ -0,0 +1,863 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" + +#include "bh_lnksw.h" + +#include "dynblock.h" +#include "dynamics.h" +#include "pldghost.h" + +#define UseLocalAssert Yes + +#include "ourasert.h" + +#include "pmove.h" +#include "pvisible.h" +#include "bh_binsw.h" +#include "plat_shp.h" +#include "psnd.h" +#include "inventry.h" + +extern int NormalFrameTime; +extern int RealFrameTime; + +static BOOL check_link_switch_states (LINK_SWITCH_BEHAV_BLOCK * lsbb) +{ + int i=0; + LSWITCH_ITEM * lsi = lsbb->lswitch_list; + +// textprint ("Checking link states\n"); + + if (!lsbb->state) + return(No); + +// textprint ("Link switch OK\n"); + + while (i < lsbb->num_linked_switches) + { + if(lsi[i].bswitch->I_SBtype==I_BehaviourBinarySwitch) + { + BINARY_SWITCH_BEHAV_BLOCK * bsbb = ((BINARY_SWITCH_BEHAV_BLOCK *)lsi[i].bswitch->SBdataptr); + + // if it's off return No + if (!bsbb->state) + return(No); +// textprint ("Switch %d OK\n", i); + + } + else if(lsi[i].bswitch->I_SBtype==I_BehaviourLinkSwitch) + { + LINK_SWITCH_BEHAV_BLOCK * linked_lsbb = ((LINK_SWITCH_BEHAV_BLOCK *)lsi[i].bswitch->SBdataptr); + + // if the system state is off return No + if (!linked_lsbb->system_state) + return(No); + } + else + { + GLOBALASSERT(0=="Switch should only have links to link switches and binary switches"); + } + i++; + } + +// textprint ("Link switchs activated\n"); + + return(Yes); +} + +#if 0 +static void set_link_switch_states_off (LINK_SWITCH_BEHAV_BLOCK * lsbb) +{ + int i=0; + LSWITCH_ITEM * lsi = lsbb->lswitch_list; + + while (lsi[i].bswitch && i < MAX_SWITCHES_FOR_LINK) + { + BINARY_SWITCH_BEHAV_BLOCK * bsbb = ((BINARY_SWITCH_BEHAV_BLOCK *)lsi[i].bswitch->SBdataptr); + + // if it's on, tell it to go off + + if (! ((bsbb->state && bsbb->rest_state) || (!bsbb->state && !bsbb->rest_state)) ) + RequestState (lsi->bswitch, 0, 0); + i++; + } +} +#endif + +void* LinkSwitchBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr) +{ + LINK_SWITCH_BEHAV_BLOCK *ls_bhv; + LINK_SWITCH_TOOLS_TEMPLATE *ls_tt; + int i; + + GLOBALASSERT(sbptr); + ls_bhv = (LINK_SWITCH_BEHAV_BLOCK*)AllocateMem(sizeof(LINK_SWITCH_BEHAV_BLOCK)); + if(!ls_bhv) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + + ls_bhv->bhvr_type = I_BehaviourLinkSwitch; + + // from loaders + // 1 rest_state - on or off + // 2 mode + // 3 timer switch - time for reset + // 4 security clerance to operate + // 5 copy the target name + + ls_tt = (LINK_SWITCH_TOOLS_TEMPLATE*)bhdata; + + sbptr->shapeIndex = ls_tt->shape_num; + COPY_NAME(sbptr->SBname, ls_tt->nameID); + + + if (ls_tt->mode == I_lswitch_SELFDESTRUCT) + { + ls_bhv->ls_mode = I_lswitch_timer; + ls_bhv->IS_SELF_DESTRUCT = Yes; + } + else + { + ls_bhv->ls_mode = ls_tt->mode; + ls_bhv->IS_SELF_DESTRUCT = No; + } + + ls_bhv->num_targets=ls_tt->num_targets; + if(ls_bhv->num_targets) + { + ls_bhv->ls_targets = (LINK_SWITCH_TARGET*)AllocateMem(sizeof(LINK_SWITCH_TARGET) * ls_tt->num_targets); + if (!ls_bhv->ls_targets) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + } + else + { + ls_bhv->ls_targets=0; + } + for (i=0; inum_targets; i++) + { + ls_bhv->ls_targets[i]=ls_tt->targets[i]; + ls_bhv->ls_targets[i].sbptr = 0; + } + + + + ls_bhv->time_for_reset = ls_tt->time_for_reset; + ls_bhv->security_clerance = ls_tt->security_clearance; + + ls_bhv->switch_flags=ls_tt->switch_flags; + ls_bhv->trigger_volume_min=ls_tt->trigger_volume_min; + ls_bhv->trigger_volume_max=ls_tt->trigger_volume_max; + + ls_bhv->switch_always_on = ls_tt->switch_always_on; + ls_bhv->switch_off_message_same=ls_tt->switch_off_message_same; + ls_bhv->switch_off_message_none=ls_tt->switch_off_message_none; + + if(sbptr->DynPtr) //there may be no shape + { + sbptr->DynPtr->Position = sbptr->DynPtr->PrevPosition = ls_tt->position; + sbptr->DynPtr->OrientEuler = ls_tt->orientation; + CreateEulerMatrix(&sbptr->DynPtr->OrientEuler, &sbptr->DynPtr->OrientMat); + TransposeMatrixCH(&sbptr->DynPtr->OrientMat); + } + // set up the animation control + if(sbptr->shapeIndex!=-1) + { + int item_num; + TXACTRLBLK **pptxactrlblk; + int shape_num = ls_tt->shape_num; + SHAPEHEADER *shptr = GetShapeData(shape_num); + + SetupPolygonFlagAccessForShape(shptr); + + pptxactrlblk = &ls_bhv->ls_tac; + + for(item_num = 0; item_num < shptr->numitems; item_num ++) + { + POLYHEADER *poly = (POLYHEADER*)(shptr->items[item_num]); + LOCALASSERT(poly); + + if((Request_PolyFlags((void *)poly)) & iflag_txanim) + { + TXACTRLBLK *pnew_txactrlblk; + int num_seq = 0; + + pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK)); + if (pnew_txactrlblk) + { + + pnew_txactrlblk->tac_flags = 0; + pnew_txactrlblk->tac_item = item_num; + pnew_txactrlblk->tac_sequence = ls_tt->rest_state; + pnew_txactrlblk->tac_node = 0; + pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shape_num, item_num); + pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shape_num); + + while(pnew_txactrlblk->tac_txarray[num_seq+1])num_seq++; + + // Assert does not work at this point so + GLOBALASSERT(num_seq==2); + + /* set the flags in the animation header */ + // we only ever have one frame of animation per sequence - + // nb this can change talk to richard - one sequence with two frames + // or mutliple sequences??? + + //Now two sequences with an arbitrary number of frames - Richard + + pnew_txactrlblk->tac_txah.txa_flags |= txa_flag_play; + + /* change the value held in pptxactrlblk + which point to the previous structures "next" + pointer*/ + + *pptxactrlblk = pnew_txactrlblk; + pptxactrlblk = &pnew_txactrlblk->tac_next; + } + else + { + memoryInitialisationFailure = 1; + } + } + } + *pptxactrlblk=0; + } + else + { + //no shape - so there won't be any animation + ls_bhv->ls_tac=0; + } + + + ls_bhv->ls_dtype = linkswitch_no_display; + + + if (ls_bhv->ls_tac) + { + ls_bhv->ls_dtype = linkswitch_animate_me; + } + ls_bhv->ls_track=ls_tt->track; + + if (ls_bhv->ls_track) + { + ls_bhv->ls_track->sbptr=sbptr; + + if (ls_bhv->ls_dtype == linkswitch_animate_me) + { + ls_bhv->ls_dtype = linkswitch_animate_and_move_me; + } + else + { + ls_bhv->ls_dtype = linkswitch_move_me; + } + } + + // fill in the rest ourselves + + ls_bhv->request = 0; + ls_bhv->state = ls_tt->rest_state; + ls_bhv->timer = 0; + ls_bhv->system_state = 0; + + ls_bhv->soundHandle = SOUND_NOACTIVEINDEX; + + ls_bhv->num_linked_switches=ls_tt->num_linked_switches; + if(ls_tt->num_linked_switches) + ls_bhv->lswitch_list=(LSWITCH_ITEM*)AllocateMem(sizeof(LSWITCH_ITEM)*ls_bhv->num_linked_switches); + else + ls_bhv->lswitch_list=0; + + for (i=0; inum_linked_switches; i++) + { + COPY_NAME (ls_bhv->lswitch_list[i].bs_name, ls_tt->switchIDs[i].name); + } + + if(ls_bhv->state) + { + ls_bhv->timer=ls_bhv->time_for_reset; + if(ls_bhv->ls_track) + { + //set the track to the end position + ls_bhv->ls_track->current_section=(ls_bhv->ls_track->num_sections-1); + ls_bhv->ls_track->timer=ls_bhv->ls_track->sections[ls_bhv->ls_track->current_section].time_for_section; + ls_bhv->ls_track->playing=1; + Update_Track_Position(ls_bhv->ls_track); + + } + } + + ls_bhv->TimeUntilNetSynchAllowed=0; + + return((void*)ls_bhv); +} + +void LinkSwitchBehaveFun(STRATEGYBLOCK* sbptr) +{ + LINK_SWITCH_BEHAV_BLOCK *ls_bhv; + DISPLAYBLOCK* dptr; + int i; + + GLOBALASSERT(sbptr); + ls_bhv = (LINK_SWITCH_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((ls_bhv->bhvr_type == I_BehaviourLinkSwitch)); + dptr = sbptr->SBdptr; + +// if(AvP.Network!=I_No_Network) return; /* disable for network game */ + + /****** + What I need to do - check to see if we have + a request - requests have different effects depending on + the mode - so we have to switch on the mode + *****/ + + if (ls_bhv->ls_dtype == linkswitch_animate_me || ls_bhv->ls_dtype == linkswitch_animate_and_move_me) + { + if(dptr) + dptr->ObTxAnimCtrlBlks = ls_bhv->ls_tac; + } + + if (!ReturnPlayerSecurityClearance(0,ls_bhv->security_clerance) && ls_bhv->security_clerance) + { + ls_bhv->request = I_no_request; + return; + } + + if(ls_bhv->switch_flags && SwitchFlag_UseTriggerVolume) + { + /*See if switch has been set off*/ + int i; + for (i=0; iDynPtr) + { + if (sbPtr->SBdptr == Player) + { + needToTest = 1; + } + else if (sbPtr->I_SBtype == I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + if ((ghostData->type == I_BehaviourMarinePlayer) + ||(ghostData->type == I_BehaviourAlienPlayer) + ||(ghostData->type == I_BehaviourPredatorPlayer)) + needToTest = 1; + } + } + + if(needToTest&& + sbPtr->DynPtr->Position.vx > ls_bhv->trigger_volume_min.vx && + sbPtr->DynPtr->Position.vx < ls_bhv->trigger_volume_max.vx && + sbPtr->DynPtr->Position.vy > ls_bhv->trigger_volume_min.vy && + sbPtr->DynPtr->Position.vy < ls_bhv->trigger_volume_max.vy && + sbPtr->DynPtr->Position.vz > ls_bhv->trigger_volume_min.vz && + sbPtr->DynPtr->Position.vz < ls_bhv->trigger_volume_max.vz) + { + ls_bhv->request=I_request_on; + break; + } + } + } + + if (ls_bhv->request == I_request_on) + { + if (ls_bhv->triggered_last) + { + ls_bhv->request = I_no_request; + } + else + { + ls_bhv->triggered_last = Yes; + } + } + else + { + ls_bhv->triggered_last = No; + } + + if(ls_bhv->switch_always_on) + { + ls_bhv->request=I_no_request; + ls_bhv->state=1; + + } + + if(AvP.Network != I_No_Network) + { + /* + Every time a switch is updated there is a time delay of 5 seconds before the + switch can next be changed by the host sending synch messages. + This prevents the host machine from resetting a switch before it learns that + it has been pressed + */ + if(ls_bhv->request == I_no_request) + { + ls_bhv->TimeUntilNetSynchAllowed-=RealFrameTime; + if(ls_bhv->TimeUntilNetSynchAllowed<0) + { + ls_bhv->TimeUntilNetSynchAllowed=0; + } + } + else + { + ls_bhv->TimeUntilNetSynchAllowed=5*ONE_FIXED; + } + } + + switch(ls_bhv->ls_mode) + { + case I_lswitch_timer: + { + + if(ls_bhv->request == I_request_on && !ls_bhv->state) + { + if(sbptr->shapeIndex!=-1)//don't play a sound if there is no shape + { + if(!ls_bhv->ls_track || !ls_bhv->ls_track->sound) + { + if (ls_bhv->soundHandle == SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_SWITCH1,"eh",&ls_bhv->soundHandle); + } + } + } + + ls_bhv->timer = ls_bhv->time_for_reset; + + if (ls_bhv->ls_dtype == binswitch_move_me || ls_bhv->ls_dtype == binswitch_animate_and_move_me) + { + // moving switch + ls_bhv->new_state = 1; + ls_bhv->new_request = -1; + ls_bhv->ls_track->reverse=0; + Start_Track_Playing(ls_bhv->ls_track); + ls_bhv->mode_store = ls_bhv->ls_mode; + ls_bhv->ls_mode = I_lswitch_moving; + } + else + { + ls_bhv->state = 1; + } + + + if(ls_bhv->ls_tac) + { + ls_bhv->ls_tac->tac_sequence = 1; + ls_bhv->ls_tac->tac_txah_s = GetTxAnimHeaderFromShape(ls_bhv->ls_tac, (sbptr->shapeIndex)); + } + } + else if(ls_bhv->timer > 0) + { + ls_bhv->timer -= NormalFrameTime; + if(ls_bhv->timer <= 0) + { + + if(sbptr->shapeIndex!=-1)//don't play a sound if there is no shape + { + if(!ls_bhv->ls_track || !ls_bhv->ls_track->sound) + { + if (ls_bhv->soundHandle == SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_SWITCH2,"eh",&ls_bhv->soundHandle); + } + } + } + + ls_bhv->state = 0; + + if (ls_bhv->ls_dtype == binswitch_move_me || ls_bhv->ls_dtype == binswitch_animate_and_move_me) + { + // moving switch + ls_bhv->new_state = 0; + ls_bhv->new_request = -1; + ls_bhv->ls_track->reverse=1; + Start_Track_Playing(ls_bhv->ls_track); + ls_bhv->mode_store = ls_bhv->ls_mode; + ls_bhv->ls_mode = I_lswitch_moving; + } + + + if(ls_bhv->ls_tac) + { + ls_bhv->ls_tac->tac_sequence = 0; + ls_bhv->ls_tac->tac_txah_s = GetTxAnimHeaderFromShape(ls_bhv->ls_tac, (sbptr->shapeIndex)); + } + } + } + break; + } + + case I_lswitch_toggle: + { + // if it's off and no request then we can return + + if (!ls_bhv->state) + if(ls_bhv->request == I_no_request) + return; + + /* change the state and request the new state in + the target */ + + if(ls_bhv->request != I_no_request) + { + if(ls_bhv->ls_dtype == binswitch_move_me || ls_bhv->ls_dtype == binswitch_animate_and_move_me) + { + // moving switch + ls_bhv->new_state = !ls_bhv->state; + ls_bhv->new_request = -1; + ls_bhv->mode_store = ls_bhv->ls_mode; + ls_bhv->ls_mode = I_lswitch_moving; + ls_bhv->ls_track->reverse=ls_bhv->state; + Start_Track_Playing(ls_bhv->ls_track); + } + else + { + ls_bhv->state = !ls_bhv->state; + } + + if(sbptr->shapeIndex!=-1)//don't play a sound if there is no shape + { + if(!ls_bhv->ls_track || !ls_bhv->ls_track->sound) + { + if (ls_bhv->soundHandle == SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_SWITCH1,"eh",&ls_bhv->soundHandle); + } + } + } + + if(ls_bhv->ls_tac) + { + ls_bhv->ls_tac->tac_sequence = ls_bhv->state ? 1 : 0; + ls_bhv->ls_tac->tac_txah_s = GetTxAnimHeaderFromShape(ls_bhv->ls_tac, (sbptr->shapeIndex)); + } + + } + + + break; + } + case I_lswitch_wait: + { + // if it's off and no request then we can return + + if (!ls_bhv->state) + if(ls_bhv->request == I_no_request) + return; + + if(ls_bhv->request == I_request_on) + { + if(!ls_bhv->state)//can only be switched on if currently off + { + if(!ls_bhv->ls_track || !ls_bhv->ls_track->sound) + { + Sound_Play(SID_SWITCH2,"eh",&ls_bhv->soundHandle); + } + if(ls_bhv->ls_dtype == binswitch_move_me || ls_bhv->ls_dtype == binswitch_animate_and_move_me) + { + + // moving switch + ls_bhv->new_state = 1; + ls_bhv->new_request = -1; + ls_bhv->ls_track->reverse=0; + Start_Track_Playing(ls_bhv->ls_track); + ls_bhv->mode_store = ls_bhv->ls_mode; + ls_bhv->ls_mode = I_lswitch_moving; + } + else + { + ls_bhv->state = 1; + } + } + } + else if (ls_bhv->request == I_request_off) + { + if(ls_bhv->state)//can only be switched off if currently on + { + if(!ls_bhv->ls_track || !ls_bhv->ls_track->sound) + { + Sound_Play(SID_SWITCH1,"eh",&ls_bhv->soundHandle); + } + if(ls_bhv->ls_dtype == binswitch_move_me || ls_bhv->ls_dtype == binswitch_animate_and_move_me) + { + + // moving switch + ls_bhv->new_state = 0; + ls_bhv->new_request = -1; + ls_bhv->ls_track->reverse=1; + Start_Track_Playing(ls_bhv->ls_track); + ls_bhv->mode_store = ls_bhv->ls_mode; + ls_bhv->ls_mode = I_lswitch_moving; + } + else + { + ls_bhv->state = 0; + } + } + + + } + + if(ls_bhv->ls_tac) + { + ls_bhv->ls_tac->tac_sequence = ls_bhv->state ? 1 : 0; + ls_bhv->ls_tac->tac_txah_s = GetTxAnimHeaderFromShape(ls_bhv->ls_tac, (sbptr->shapeIndex)); + } + + + + break; + } + case I_lswitch_moving: + { + textprint ("moving\n"); + Update_Track_Position(ls_bhv->ls_track); + + if (!ls_bhv->ls_track->playing) + { + ls_bhv->ls_mode = ls_bhv->mode_store; + ls_bhv->state = ls_bhv->new_state; + + if(ls_bhv->ls_tac) + { + ls_bhv->ls_tac->tac_sequence = ls_bhv->state ? 1 : 0; + ls_bhv->ls_tac->tac_txah_s = GetTxAnimHeaderFromShape(ls_bhv->ls_tac, (sbptr->shapeIndex)); + } + } + + } + break; + default: + GLOBALASSERT(2<1); + } + + ls_bhv->request = I_no_request; + + //check to see if the system state has changed + + if (ls_bhv->system_state) + { + if (!check_link_switch_states(ls_bhv)) + { + ls_bhv->system_state = No; + + //link switch system state is turning off + if(!ls_bhv->switch_off_message_none) + { + for(i=0;inum_targets;i++) + { + RequestState(ls_bhv->ls_targets[i].sbptr,ls_bhv->ls_targets[i].request_message^(!ls_bhv->switch_off_message_same), sbptr); + } + } + } + } + else + { + if (check_link_switch_states(ls_bhv)) + { + ls_bhv->system_state = Yes; + //link switch system state is turning on + for(i=0;inum_targets;i++) + { + RequestState(ls_bhv->ls_targets[i].sbptr,ls_bhv->ls_targets[i].request_message, sbptr); + } + } + + } + + +} + + +#define LINKSWITCHSYNCH_ON 0 +#define LINKSWITCHSYNCH_OFF 1 +#define LINKSWITCHSYNCH_IGNORE 2 + +int LinkSwitchGetSynchData(STRATEGYBLOCK* sbPtr) +{ + LINK_SWITCH_BEHAV_BLOCK *ls_bhv; + GLOBALASSERT(sbPtr); + ls_bhv = (LINK_SWITCH_BEHAV_BLOCK*)sbPtr->SBdataptr; + GLOBALASSERT((ls_bhv->bhvr_type == I_BehaviourLinkSwitch)); + + //don't try to synch moving switches + if(ls_bhv->ls_mode==I_lswitch_moving) + { + return LINKSWITCHSYNCH_IGNORE; + } + + if(ls_bhv->state) + return LINKSWITCHSYNCH_ON; + else + return LINKSWITCHSYNCH_OFF; +} + + +void LinkSwitchSetSynchData(STRATEGYBLOCK* sbPtr,int status) +{ + LINK_SWITCH_BEHAV_BLOCK *ls_bhv; + GLOBALASSERT(sbPtr); + ls_bhv = (LINK_SWITCH_BEHAV_BLOCK*)sbPtr->SBdataptr; + GLOBALASSERT((ls_bhv->bhvr_type == I_BehaviourLinkSwitch)); + + if(ls_bhv->TimeUntilNetSynchAllowed>0) + { + //ignore this attempt to synch the switch + return; + } + + //don't try to synch moving switches + if(ls_bhv->ls_mode==I_lswitch_moving) + { + return; + } + + + switch(status) + { + case LINKSWITCHSYNCH_ON : + if(!ls_bhv->state) + { + //this switch should be on + RequestState(sbPtr,1,0); + } + break; + + case LINKSWITCHSYNCH_OFF : + if(ls_bhv->state) + { + //this switch should be off + RequestState(sbPtr,0,0); + } + break; + } +} + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" +typedef struct link_switch_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + BINARY_SWITCH_REQUEST_STATE request; + BOOL system_state; + BOOL state; + + LSWITCH_MODE ls_mode; + int timer; + + BOOL new_state; + int new_request; + + LSWITCH_MODE mode_store; + + BOOL triggered_last; + + int txanim_sequence; + +}LINK_SWITCH_SAVE_BLOCK; + + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV ls_bhv + +void LoadStrategy_LinkSwitch(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + LINK_SWITCH_BEHAV_BLOCK *ls_bhv; + LINK_SWITCH_SAVE_BLOCK* block = (LINK_SWITCH_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourLinkSwitch) return; + + ls_bhv = (LINK_SWITCH_BEHAV_BLOCK*)sbPtr->SBdataptr; + + //start copying stuff + + COPYELEMENT_LOAD(request) + COPYELEMENT_LOAD(system_state) + COPYELEMENT_LOAD(state) + COPYELEMENT_LOAD(ls_mode) + COPYELEMENT_LOAD(timer) + COPYELEMENT_LOAD(new_state) + COPYELEMENT_LOAD(new_request) + COPYELEMENT_LOAD(mode_store) + COPYELEMENT_LOAD(triggered_last) + + //set the texture animation sequence + if(ls_bhv->ls_tac) + { + ls_bhv->ls_tac->tac_sequence = block->txanim_sequence; + ls_bhv->ls_tac->tac_txah_s = GetTxAnimHeaderFromShape(ls_bhv->ls_tac, (sbPtr->shapeIndex)); + } + + //load the track position , if the switch has one + if(ls_bhv->ls_track) + { + SAVE_BLOCK_HEADER* track_header = GetNextBlockIfOfType(SaveBlock_Track); + if(track_header) + { + LoadTrackPosition(track_header,ls_bhv->ls_track); + } + } + +} + +void SaveStrategy_LinkSwitch(STRATEGYBLOCK* sbPtr) +{ + LINK_SWITCH_SAVE_BLOCK *block; + LINK_SWITCH_BEHAV_BLOCK *ls_bhv; + ls_bhv = (LINK_SWITCH_BEHAV_BLOCK*)sbPtr->SBdataptr; + + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + COPYELEMENT_SAVE(request) + COPYELEMENT_SAVE(system_state) + COPYELEMENT_SAVE(state) + COPYELEMENT_SAVE(ls_mode) + COPYELEMENT_SAVE(timer) + COPYELEMENT_SAVE(new_state) + COPYELEMENT_SAVE(new_request) + COPYELEMENT_SAVE(mode_store) + COPYELEMENT_SAVE(triggered_last) + + + //get the animation sequence + if(ls_bhv->ls_tac) + { + block->txanim_sequence = ls_bhv->ls_tac->tac_sequence; + } + else + { + block->txanim_sequence = 0; + } + + //save the track position , if the switch has one + if(ls_bhv->ls_track) + { + SaveTrackPosition(ls_bhv->ls_track); + } + +} diff --git a/3dc/avp/BH_LNKSW.H b/3dc/avp/BH_LNKSW.H new file mode 100644 index 0000000..79cfee4 --- /dev/null +++ b/3dc/avp/BH_LNKSW.H @@ -0,0 +1,163 @@ +#ifndef _bhlnksw_h_ +#define _bhlnksw_h_ 1 + +#include "track.h" + +#ifdef __cplusplus + + extern "C" { + +#endif + + +void* LinkSwitchBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr); +void LinkSwitchBehaveFun(STRATEGYBLOCK* sbptr); + +extern int LinkSwitchGetSynchData(STRATEGYBLOCK* sbptr); +extern void LinkSwitchSetSynchData(STRATEGYBLOCK* sbptr,int status); + +typedef enum link_switch_mode +{ + I_lswitch_timer, + I_lswitch_wait, + I_lswitch_toggle, + I_lswitch_moving, + I_lswitch_SELFDESTRUCT, + +} LSWITCH_MODE; + +typedef enum link_switch_req_states +{ + linkswitch_no_request, + linkswitch_request_on, + linkswitch_request_off, +}LINK_SWITCH_REQUEST_STATE; + +typedef enum lswitch_display_types +{ + linkswitch_no_display, + linkswitch_animate_me, + linkswitch_move_me, + linkswitch_animate_and_move_me, +} LSWITCH_DISPLAY_TYPES; + +typedef enum ls_move_dir +{ + ls_start_to_end, + ls_end_to_start, +} LS_MOVE_DIR; + + +typedef struct lswitch_item +{ + STRATEGYBLOCK * bswitch; + char bs_name [SB_NAME_LENGTH]; + +} LSWITCH_ITEM; + +typedef struct link_switch_target +{ + char name[SB_NAME_LENGTH]; + int request_message; + STRATEGYBLOCK* sbptr; +}LINK_SWITCH_TARGET; + +typedef struct link_switch +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + LINK_SWITCH_REQUEST_STATE request; + + BOOL system_state; + + BOOL state; + LSWITCH_MODE ls_mode; + + int num_targets; + + LINK_SWITCH_TARGET* ls_targets; + + int time_for_reset; // constant + int timer; + + int security_clerance; // what the plyer has to be to use this switch + + int num_linked_switches; + LSWITCH_ITEM* lswitch_list ; + + // stuff for showing how the switch displays its state + + LSWITCH_DISPLAY_TYPES ls_dtype; + + TXACTRLBLK *ls_tac; // animations + + // or track + TRACK_CONTROLLER* ls_track; + + + BOOL new_state; + int new_request; + + LSWITCH_MODE mode_store; + + // SELF DESTRUCT SEQUENCE STUFF + + BOOL IS_SELF_DESTRUCT; + + int soundHandle; + + BOOL triggered_last; + + int switch_flags; + VECTORCH trigger_volume_min;//for switches that can be set off by walking + VECTORCH trigger_volume_max;//into a given area + + unsigned int switch_always_on:1; + unsigned int switch_off_message_same:1; + unsigned int switch_off_message_none:1; + + int TimeUntilNetSynchAllowed; + +}LINK_SWITCH_BEHAV_BLOCK; + +typedef struct link_switch_tools_template +{ + VECTORCH position; + EULER orientation; + + + BOOL rest_state; + int mode; + int time_for_reset; + int security_clearance; + + int num_targets; + LINK_SWITCH_TARGET * targets; + + int shape_num; + + TRACK_CONTROLLER* track; + + + char nameID[SB_NAME_LENGTH]; + + int num_linked_switches; + SBNAMEBLOCK* switchIDs; + + int switch_flags; + VECTORCH trigger_volume_min;//for switches that can be set off by walking + VECTORCH trigger_volume_max;//into a given area + + unsigned int switch_always_on:1; + unsigned int switch_off_message_same:1; + unsigned int switch_off_message_none:1; +} LINK_SWITCH_TOOLS_TEMPLATE; + + +#ifdef __cplusplus + + }; + +#endif + + +#endif diff --git a/3dc/avp/BH_MARIN.H b/3dc/avp/BH_MARIN.H new file mode 100644 index 0000000..93e749c --- /dev/null +++ b/3dc/avp/BH_MARIN.H @@ -0,0 +1,412 @@ +/*--------------Patrick 14/2/97---------------- + Header file for marine support functions + ---------------------------------------------*/ + +#ifndef _bhmarin_h_ + #define _bhmarin_h_ 1 + + + #ifdef __cplusplus + + extern "C" { + + #endif + + + #include "bh_pred.h" + #include "psndproj.h" + #include "sfx.h" + /*-------------------------------------------- + enums of marine far and near behaviour states + --------------------------------------------*/ + typedef enum marine_bhstate + { + MBS_Waiting, + /* Waiting - stand and do nothing, + until you get a call, see an enemy, + or begin to fidget. */ + MBS_Wandering, + /* Go from module to module around the environment. */ + MBS_Retreating, + MBS_Sentry, + MBS_Approaching, + MBS_Firing, + MBS_Avoidance, + MBS_Dying, + MBS_Responding, + MBS_Returning, + MBS_Pathfinding, + MBS_Taunting, + MBS_PanicFire, + MBS_Reloading, + MBS_PumpAction, + MBS_GetWeapon, + MBS_PanicReloading, + MBS_AcidAvoidance, + } MARINE_BHSTATE; + + typedef enum marine_movement_style { + MMS_Stationary=0, + MMS_Bored, + MMS_Alert, + MMS_Combat, + MMS_Sprint, + } MARINE_MOVEMENT_STYLE; + + typedef enum state_return_condition { + SRC_No_Change, + SRC_Request_Approach, + SRC_Request_Fire, + SRC_Request_Wander, + SRC_Request_Avoidance, + SRC_Request_Wait, + SRC_Request_Retreat, + SRC_Request_Respond, + SRC_Request_Return, + SRC_Request_Taunt, + SRC_Request_PanicFire, + SRC_Request_Reload, + SRC_Request_PumpAction, + SRC_Request_PullPistol, + SRC_Request_PanicReload, + } STATE_RETURN_CONDITION; + + /*-------------------------------------------- + Enum of marine animation sequences + --------------------------------------------*/ + + typedef enum MarineSequence + { + MSQ_Walk, + MSQ_StandDieFront, + MSQ_StandDieBack, + MSQ_StartStandingFire, + MSQ_StandingFire, + MSQ_StandDeadFront, + MSQ_StandDeadBack, + MSQ_Crawl, + MSQ_CrouchDie, + MSQ_CrouchDead, + MSQ_RunningFire, + MSQ_Crouch, + MSQ_Stand, + MSQ_Jump, + MSQ_Taunt, + MSQ_Walk_Backwards, + MSQ_Crawl_Backwards, + MSQ_RunningFire_Backwards, + + MSQ_StandingFireSecondary, + MSQ_RunningFireSecondary, + MSQ_RunningFireSecondary_Backwards, + + MSQ_BaseOfCudgelAttacks=40, + }MARINE_SEQUENCE; + + typedef enum MarineMissions { + MM_Wait_Then_Wander, // Should do nothing until visible. + MM_Wander, + MM_Guard, + MM_LocalGuard, + MM_NonCom, + MM_Pathfinder, + MM_RunAroundOnFire, + }MARINE_MISSION; + + /***** Marine squad command state *****/ + + typedef struct squadcommand { + int alertStatus; + int responseLevel; + AIMODULE *alertZone; + int alertPriority; + + int Squad_Suspicion; + VECTORCH squad_suspect_point; + + /* Now some stats. */ + int RespondingMarines; + int Alt_RespondingMarines; + + int NearUnpanickedMarines; + int Alt_NearUnpanickedMarines; + + int NearPanickedMarines; + int Alt_NearPanickedMarines; + + int NearBurningMarines; + int Alt_NearBurningMarines; + + int Squad_Delta_Morale; + int Nextframe_Squad_Delta_Morale; + + } SQUAD_COMMAND_STATE; + + /*-------------------------------------------- + Data for civilian accoutement stuff + --------------------------------------------*/ + + struct hierarchy_shape_replacement; + typedef struct hierarchy_variant_data + { + struct hierarchy_shape_replacement * replacements; + int voice; + unsigned int female :1; + } HIERARCHY_VARIANT_DATA; + + /*-------------------------------------------- + Marine behaviour data block + --------------------------------------------*/ + typedef struct marineStatusBlock + { + signed int health; + signed int volleySize; + signed int primaryWeaponDamage; + + MARINE_BHSTATE behaviourState; + MARINE_BHSTATE lastState; + + STRATEGYBLOCK *Target; + MARINE_MISSION Mission; + char Target_SBname[SB_NAME_LENGTH]; + + char death_target_ID[SB_NAME_LENGTH]; //another strategy can be notified of the marine's death + STRATEGYBLOCK* death_target_sbptr; + int death_target_request; + + STRATEGYBLOCK* generator_sbptr;//0 unless created by a generator + + AIMODULE *lastmodule; + AIMODULE *destinationmodule; + AIMODULE *missionmodule; + AIMODULE *fearmodule; + VECTORCH my_spot; + VECTORCH my_facing_point; + /* Movement data. */ + signed int nearSpeed; + int acceleration; + int speedConstant; + int accelerationConstant; + /* Sense data */ + int mtracker_timer; + VECTORCH suspect_point; + int suspicious; + int previous_suspicion; + int using_squad_suspicion; + int sawlastframe; + int gotapoint; + int lastframe_fallingspeed; + /* Pathfinder parameters */ + int path; + int stepnumber; + /* Pathfinder parameters */ + int stateTimer; + int internalState; + HMODELCONTROLLER HModelController; + VECTORCH weaponTarget; /* position for firing weapon at */ + DISPLAYBLOCK *myGunFlash; + int soundHandle; + int soundHandle2; + NPC_OBSTRUCTIONREPORT obstruction; + NPC_MOVEMENTDATA moveData; + NPC_WANDERDATA wanderData; + int IAmCrouched; + /* CDF 15/12/97 */ + struct marine_weapon_data *My_Weapon; + SECTION_DATA *My_Gunflash_Section; + SECTION_DATA *My_Elevation_Section; /* For elevation computation. */ + int lastroundhit; + SECTION_DATA *lasthitsection; + + int GibbFactor; + int Wounds; + + int incidentFlag; + int incidentTimer; + + int weapon_variable; + int weapon_variable2; + int clipammo; + int roundsForThisTarget; + + int Female; + int Android; + int Skill; + int Courage; + int Voice; + int VoicePitch; + + int FiringAnim; + int Expression; + int Target_Expression; + int Blink; + int SpotFlag; + + NPC_AVOIDANCEMANAGER avoidanceManager; + WAYPOINT_MANAGER waypointManager; + + }MARINE_STATUS_BLOCK; + + typedef enum marine_npc_weapons { + + MNPCW_PulseRifle, + MNPCW_Flamethrower, + MNPCW_Smartgun, + MNPCW_SADAR, + MNPCW_GrenadeLauncher, + MNPCW_Minigun, + MNPCW_MShotgun, + MNPCW_MPistol, + MNPCW_MFlamer, + MNPCW_MUnarmed, + MNPCW_MMolotov, + MNPCW_PistolMarine, + MNPCW_Android, + MNPCW_AndroidSpecial, + MNPCW_Android_Pistol_Special, + MNPCW_Scientist_A, + MNPCW_Scientist_B, + MNPCW_TwoPistols, + MNPCW_Skeeter, + MNPCW_End, + + } MARINE_NPC_WEAPONS; + + /*-------------------------------------------- + Tools data template + --------------------------------------------*/ + typedef struct tools_data_marine + { + struct vectorch position; + struct vectorch facing_point; + int shapeIndex; + char nameID[SB_NAME_LENGTH]; + MARINE_MISSION Mission; + char death_target_ID[SB_NAME_LENGTH]; + int death_target_request; + + enum marine_npc_weapons marine_type; + + int path; + int stepnumber; + + int textureID; + + }TOOLS_DATA_MARINE; + + /*-------------------------------------------- + Weapon Behaviour Type. + --------------------------------------------*/ + + + typedef struct marine_weapon_data { + + MARINE_NPC_WEAPONS id; + enum SFX_ID SfxID; + STATE_RETURN_CONDITION (*WeaponFireFunction)(STRATEGYBLOCK *); + void (*WeaponMisfireFunction)(SECTION_DATA *, int *); + STATE_RETURN_CONDITION (*WeaponPanicFireFunction)(STRATEGYBLOCK *); + char *Riffname; + char *HierarchyName; + char *GunflashName; + char *ElevationSection; + char *HitLocationTableName; + char *TemplateName; + char *ClipName; + int MinRange; + int ForceFireRange; + int MaxRange; + int Accuracy; + int FiringRate; + int FiringTime; + int MinimumBurstSize; + enum AMMO_ID Ammo_Type; + int clip_size; + int Reload_Sequence; + int TargetCallibrationShift; + SOUNDINDEX StartSound; + SOUNDINDEX LoopSound; + SOUNDINDEX EndSound; + unsigned int EnableGrenades :1; + unsigned int UseElevation :1; + unsigned int EnableTracker :1; + unsigned int ARealMarine :1; + unsigned int Android :1; + + }MARINE_WEAPON_DATA; + + /*-------------------------------------------- + Some defines.... + --------------------------------------------*/ + #define MARINE_STATE_PRINT 0 + #define MARINE_STARTING_HEALTH 30 + #define NO_OF_FRAGMENTS_FROM_DEAD_MARINE 10 +// #define MARINE_NEAR_SPEED 6000 /* mm/s */ + /* Experiment. Can they take the ramps? */ + #define MARINE_NEAR_SPEED 6000 /* mm/s */ + #define MARINE_NEAR_VIEW_WIDTH 500 /* mm */ + #define MARINE_WEAPON_DAMAGE 5 + #define MARINE_CLOSE_APPROACH_DISTANCE 3000 /* mm */ + #define MARINE_FIRINGPOINT_INFRONT 3000 /* 900 mm */ + #define MARINE_FIRINGPOINT_ACROSS 300 /* 300 mm */ + #define MARINE_FIRINGPOINT_UP 200 /* 200 mm */ + #define MARINE_FIRINGPOINT_INFRONT_CROUCHED 900 /* mm */ + #define MARINE_FIRINGPOINT_ACROSS_CROUCHED 200 /* mm */ + #define MARINE_FIRINGPOINT_UP_CROUCHED 100 /* mm */ + #define MARINE_WEAPON_VOLLEYSIZE (1+(FastRandom()&0x02)) /* 1,2 or 3 1/4 second bursts */ + #define MARINE_CHANCEOFGRENADE (3) + #define MARINE_TOO_CLOSE_TO_GRENADE_FOOL 3000 + #define MARINE_PARANOIA_TIME (ONE_FIXED*10) + #define MARINE_PANIC_TIME (ONE_FIXED*120) + #define SQUAD_PARANOIA_TIME (ONE_FIXED) + + /* 1.5-2 seconds in 1/16 second. NB DO NOT INCREASE THIS */ + #define MARINE_FAR_MOVE_TIME ((24+(FastRandom()&0x07))*(ONE_FIXED>>4)) + /* 1-2 seconds in 1/8ths of a second */ + #define MARINE_NEAR_TIMEBETWEENFIRING ((8+(FastRandom()&0x07))*(ONE_FIXED>>3)) +// #define MARINE_NEAR_FIRE_TIME (ONE_FIXED>>2) /* 1/4 second */ + #define MARINE_NEAR_FIRE_TIME (ONE_FIXED) /* 1 second */ + /* random time between 1 and 2 seconds,in fixed point,with granularity 1/8th second */ + #define MARINE_NEARWAITTIME (ONE_FIXED+((FastRandom()&0x7)*(ONE_FIXED>>3))) + + #define SEAL_NEAR_SPEED 7000 + #define SEAL_WEAPON_DAMAGE 15 + #define SEAL_STARTING_HEALTH 150 + + //#define MINIGUN_IDLE_SPEED (ONE_FIXED>>2) + #define MINIGUN_IDLE_SPEED (0) + #define MINIGUN_MAX_SPEED (ONE_FIXED*20) + #define MINIGUN_MINIMUM_BURST (25) + + /*-------------------------------------------- + Some prototypes... + --------------------------------------------*/ + void InitMarineBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr); + void InitSealBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr); + void SendRequestToMarine(STRATEGYBLOCK* sbPtr,BOOL state,int extended_data); + void MarineBehaviour(STRATEGYBLOCK *sbPtr); + void MakeMarineNear(STRATEGYBLOCK *sbPtr); + void MakeMarineFar(STRATEGYBLOCK *sbPtr); + void MarineIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,SECTION_DATA *Section, VECTORCH *incoming); + void WarnMarineOfAttack(STRATEGYBLOCK *marine,STRATEGYBLOCK *attacker); + + DISPLAYBLOCK* AddNPCGunFlashEffect(VECTORCH *position, MATRIXCH* orientation, enum SFX_ID sfxID); + void RemoveNPCGunFlashEffect(DISPLAYBLOCK* dPtr); + void MaintainNPCGunFlashEffect(DISPLAYBLOCK* dPtr, VECTORCH *position, MATRIXCH* orientation); + + int Validate_Target(STRATEGYBLOCK *target,char *SBname); + int Validate_Strategy(STRATEGYBLOCK *target,char *SBname); + AIMODULE *NearNPC_GetTargetAIModuleForRetreat(STRATEGYBLOCK *sbPtr, NPC_MOVEMENTDATA *moveData); + extern void InitSquad(void); + extern void DoSquad(void); + extern void ZoneAlert(int level,AIMODULE *targetModule); + extern void Marine_CorpseSightingTest(STRATEGYBLOCK *corpse); + + #ifdef __cplusplus + + } + + #endif + + +#endif \ No newline at end of file diff --git a/3dc/avp/BH_NEAR.H b/3dc/avp/BH_NEAR.H new file mode 100644 index 0000000..1b66ba9 --- /dev/null +++ b/3dc/avp/BH_NEAR.H @@ -0,0 +1,2 @@ + +extern void NearAlienBehaviour(STRATEGYBLOCK *sbPtr); diff --git a/3dc/avp/BH_PAQ.C b/3dc/avp/BH_PAQ.C new file mode 100644 index 0000000..382a85f --- /dev/null +++ b/3dc/avp/BH_PAQ.C @@ -0,0 +1,1196 @@ +/*------------------------Patrick 18/2/97----------------------------- + Source file for Predator-Alien and Queen AI behaviour functions.... + --------------------------------------------------------------------*/ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "comp_shp.h" +#include "dynblock.h" +#include "dynamics.h" +#include "pfarlocs.h" +#include "pvisible.h" +#include "pheromon.h" +#include "bh_far.h" +#include "bh_pred.h" +#include "bh_paq.h" +#include "bh_debri.h" +#define UseLocalAssert Yes +#include "ourasert.h" +#include "psnd.h" +#include "weapons.h" + +/* external global variables used in this file */ +extern int ModuleArraySize; +extern char *ModuleCurrVisArray; +extern int NormalFrameTime; + +/* prototypes for this file */ +static void Execute_PAQNS_Wait(STRATEGYBLOCK *sbPtr); +static void Execute_PAQNS_Approach(STRATEGYBLOCK *sbPtr); +static void Execute_PAQNS_Attack(STRATEGYBLOCK *sbPtr); +static void Execute_PAQNS_Avoidance(STRATEGYBLOCK *sbPtr); +static void Execute_PAQNS_Wander(STRATEGYBLOCK *sbPtr); +static void Execute_Dying(STRATEGYBLOCK *sbPtr); + +static void Execute_PAQFS_Wait(STRATEGYBLOCK *sbPtr); +static void Execute_PAQFS_Hunt(STRATEGYBLOCK *sbPtr); +static void Execute_PAQFS_Wander(STRATEGYBLOCK *sbPtr); +static void ProcessFarPAQTargetModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule); + +static void SetPAQAnimationSequence(STRATEGYBLOCK *sbPtr, PAQ_SEQUENCE seq, int rate); +static int PAQShouldAttackPlayer(void); + +/*------------------------Patrick 18/2/97----------------------------- + Predator-Alien & Queen behaviour shell functions + --------------------------------------------------------------------*/ + +void InitPredAlBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr) +{ + TOOLS_DATA_PAQ *toolsData; + int i; + + LOCALASSERT(sbPtr); + LOCALASSERT(bhdata); + toolsData = (TOOLS_DATA_PAQ *)bhdata; + + /* check we're not in a net game */ + if(AvP.Network != I_No_Network) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* make the assumption that the loader has initialised the strategy + block sensibly... + so just set the shapeIndex from the tools data & copy the name id*/ + sbPtr->shapeIndex = toolsData->shapeIndex; + for(i=0;iSBname[i] = toolsData->nameID[i]; + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC); + if(sbPtr->DynPtr) + { + EULER zeroEuler = {0,0,0}; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + dynPtr->PrevPosition = dynPtr->Position = toolsData->position; + dynPtr->OrientEuler = zeroEuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + /* zero linear velocity in dynamics block */ + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + } + else + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* Initialise alien's stats */ + { + NPC_DATA *NpcData; + + NpcData=GetThisNpcData(I_NPC_PredatorAlien); + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + /* create, initialise and attach a predator-alien/queen data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(PAQ_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + PAQ_STATUS_BLOCK *paqStatus = (PAQ_STATUS_BLOCK *)sbPtr->SBdataptr; + NPC_InitMovementData(&(paqStatus->moveData)); + NPC_InitWanderData(&(paqStatus->wanderData)); + paqStatus->health = PRAL_STARTING_HEALTH; + paqStatus->nearSpeed = PRAL_NEAR_SPEED; + paqStatus->damageInflicted = PRAL_NEAR_DAMAGE; + sbPtr->integrity = paqStatus->health; + paqStatus->FarBehaviourState = PAQFS_Wait; + paqStatus->NearBehaviourState = PAQNS_Wait; + paqStatus->stateTimer = 0; + InitShapeAnimationController(&paqStatus->ShpAnimCtrl, GetShapeData(sbPtr->shapeIndex)); + } + else + { + RemoveBehaviourStrategy(sbPtr); + return; + } +} + +void PAQBehaviour(STRATEGYBLOCK *sbPtr) +{ + /* get the paq status block */ + PAQ_STATUS_BLOCK *paqStatusPointer; + + LOCALASSERT(sbPtr); + paqStatusPointer = (PAQ_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(paqStatusPointer); + + /* test if we've got a containing module: if we haven't, do nothing. + This is important as the object could have been marked for deletion by the visibility + management system...*/ + if(!sbPtr->containingModule) + { + DestroyAnyStrategyBlock(sbPtr); /* just to make sure */ + return; + } + + /* zero our velocity */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + InitWaypointSystem(0); + + if(sbPtr->SBdptr) + { + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]); + switch(paqStatusPointer->NearBehaviourState) + { + case(PAQNS_Wait): + { + Execute_PAQNS_Wait(sbPtr); + break; + } + case(PAQNS_Approach): + { + Execute_PAQNS_Approach(sbPtr); + break; + } + case(PAQNS_Attack): + { + Execute_PAQNS_Attack(sbPtr); + break; + } + case(PAQNS_Avoidance): + { + textprint("paq avoidance \n"); + Execute_PAQNS_Avoidance(sbPtr); + break; + } + case(PAQNS_Wander): + { + Execute_PAQNS_Wander(sbPtr); + break; + } + case(PAQNS_Dying): + { + Execute_Dying(sbPtr); + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + } + else + { + /* NB if this assert fires, may have just run out of displayblocks */ + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)] == 0); + switch(paqStatusPointer->FarBehaviourState) + { + case(PAQFS_Wait): + { + Execute_PAQFS_Wait(sbPtr); + break; + } + case(PAQFS_Hunt): + { + Execute_PAQFS_Hunt(sbPtr); + break; + } + case(PAQFS_Wander): + { + Execute_PAQFS_Wander(sbPtr); + break; + } + case(PAQFS_Dying): + { + Execute_Dying(sbPtr); + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + + /* check here to see if paq is in a proximity door - if so, trigger it to open. */ + { + MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule); + + if(doorType == MDT_ProxDoor) + ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->alienTrigger = 1; + } + /* lastly, do a containment test: to make sure that we are inside a module. */ + #if UseLocalAssert + { + VECTORCH localCoords; + MODULE *thisModule = sbPtr->containingModule; + + LOCALASSERT(thisModule); + + localCoords = sbPtr->DynPtr->Position; + localCoords.vx -= thisModule->m_world.vx; + localCoords.vy -= thisModule->m_world.vy; + localCoords.vz -= thisModule->m_world.vz; + + if(PointIsInModule(thisModule, &localCoords)==0) + { + #if (!PSX) + textprint("PAQ MODULE CONTAINMENT FAILURE \n"); + LOCALASSERT(1==0); + #endif + } + } + #endif + } + + /* test here to see if the paq is dead: if so, remove it */ + if((paqStatusPointer->NearBehaviourState == PAQNS_Dying)&&(paqStatusPointer->stateTimer <= 0)) + DestroyAnyStrategyBlock(sbPtr); +} + +void MakePAQNear(STRATEGYBLOCK *sbPtr) +{ + extern MODULEMAPBLOCK AlienDefaultMap; + + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr; + PAQ_STATUS_BLOCK *paqStatusPointer; + + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + paqStatusPointer = (PAQ_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(paqStatusPointer); + LOCALASSERT(dynPtr); + LOCALASSERT(sbPtr->SBdptr == NULL); + + AlienDefaultMap.MapShape = sbPtr->shapeIndex; + tempModule.m_mapptr = &AlienDefaultMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 0; + tempModule.m_lightarray = (struct lightblock *)0; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr = NULL; + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) return; /* if cannot allocate displayblock, leave far */ + + sbPtr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbPtr; + dPtr->ObMyModule = NULL; + + /* need to initialise positional information in the new display block */ + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + + /* pa-q data block init */ + paqStatusPointer->stateTimer = 0; + + /* zero linear velocity in dynamics block */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* set up starting state and sequence */ + dPtr->ShapeAnimControlBlock = &paqStatusPointer->ShpAnimCtrl; + if(PAQShouldAttackPlayer()) + { + NPC_InitMovementData(&(paqStatusPointer->moveData)); + NPC_InitWanderData(&(paqStatusPointer->wanderData)); + paqStatusPointer->NearBehaviourState = PAQNS_Approach; + paqStatusPointer->stateTimer = 0; + SetPAQAnimationSequence(sbPtr,PaqSQ_Run,10); + } + else + { + NPC_InitMovementData(&(paqStatusPointer->moveData)); + NPC_InitWanderData(&(paqStatusPointer->wanderData)); + paqStatusPointer->NearBehaviourState = PAQNS_Wait; + paqStatusPointer->stateTimer = PAQ_NEARWAITTIME; + SetPAQAnimationSequence(sbPtr,PaqSQ_Stand,10); + } +} + +void MakePAQFar(STRATEGYBLOCK *sbPtr) +{ + PAQ_STATUS_BLOCK *paqStatusPointer; + int i; + + LOCALASSERT(sbPtr); + paqStatusPointer = (PAQ_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(paqStatusPointer); + LOCALASSERT(sbPtr->SBdptr != NULL); + + /* get rid of the displayblock */ + i = DestroyActiveObject(sbPtr->SBdptr); + LOCALASSERT(i==0); + sbPtr->SBdptr = NULL; + + /* zero linear velocity in dynamics block */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + NPC_InitWanderData(&(paqStatusPointer->wanderData)); + + /* set up starting state and sequence */ + if(paqStatusPointer->NearBehaviourState==PAQNS_Dying) + { + DestroyAnyStrategyBlock(sbPtr); + return; + } + + if(PAQShouldAttackPlayer()) + { + paqStatusPointer->FarBehaviourState = PAQFS_Hunt; + paqStatusPointer->stateTimer = PAQ_FAR_MOVE_TIME; + } + else + { + paqStatusPointer->FarBehaviourState = PAQFS_Wander; + paqStatusPointer->stateTimer = PAQ_FAR_MOVE_TIME; + } +} + +void PAQIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple) +{ + int rand = FastRandom(); + int pitch = (rand & 255) - 128; + + PAQ_STATUS_BLOCK *paqStatusPointer; + + LOCALASSERT(sbPtr); + paqStatusPointer = (PAQ_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(paqStatusPointer); + LOCALASSERT(sbPtr->containingModule); + + /* if we're dying, do nothing */ + if(paqStatusPointer->NearBehaviourState==PAQNS_Dying) + { + /* PAQFS should be dying, too */ + return; + } + + if(!(sbPtr->SBdptr)) + { + DestroyAnyStrategyBlock(sbPtr); + return; + } + + #define QUEEN_PITCH_CHANGE 150 + #define PREDALIEN_PITCH_CHANGE 300 + + if (sbPtr->I_SBtype == I_BehaviourQueenAlien) + { + switch (rand % 5) + { + case 0: + Sound_Play(SID_ALIEN_SCREAM,"dp",&(sbPtr->DynPtr->Position),QUEEN_PITCH_CHANGE + pitch); + break; + case 1: + Sound_Play(SID_ALIEN_HIT,"dp",&(sbPtr->DynPtr->Position),QUEEN_PITCH_CHANGE + pitch); + break; + case 2: + Sound_Play(SID_ALIEN_HIT2,"dp",&(sbPtr->DynPtr->Position),QUEEN_PITCH_CHANGE + pitch); + break; + case 3: + Sound_Play(SID_ALIEN_HISS1,"dp",&(sbPtr->DynPtr->Position),QUEEN_PITCH_CHANGE + pitch); + break; + default: + Sound_Play(SID_ALIEN_HISS,"dp",&(sbPtr->DynPtr->Position),QUEEN_PITCH_CHANGE + pitch); + break; + } + } + else + { + switch (rand % 7) + { + case 0: + Sound_Play(SID_PRED_SNARL,"dp",&(sbPtr->DynPtr->Position),pitch); + break; + case 1: + Sound_Play(SID_PRED_HISS,"dp",&(sbPtr->DynPtr->Position),pitch); + break; + case 2: + Sound_Play(SID_PRED_SHORTROAR,"dp",&(sbPtr->DynPtr->Position),pitch); + break; + case 3: + Sound_Play(SID_PRED_SCREAM1,"dp",&(sbPtr->DynPtr->Position),pitch); + break; + case 4: + Sound_Play(SID_RIP,"dp",&(sbPtr->DynPtr->Position),pitch); + break; + case 5: + Sound_Play(SID_PRED_SLASH,"dp",&(sbPtr->DynPtr->Position),pitch); + break; + default: + Sound_Play(SID_HIT_FLESH,"dp",&(sbPtr->DynPtr->Position),pitch); + break; + } + + switch ((rand >> 4) % 5) + { + case 0: + Sound_Play(SID_ALIEN_SCREAM,"dp",&(sbPtr->DynPtr->Position),-PREDALIEN_PITCH_CHANGE+pitch); + break; + case 1: + Sound_Play(SID_ALIEN_HIT,"dp",&(sbPtr->DynPtr->Position),-PREDALIEN_PITCH_CHANGE+pitch); + break; + case 2: + Sound_Play(SID_ALIEN_HIT2,"dp",&(sbPtr->DynPtr->Position),-PREDALIEN_PITCH_CHANGE+pitch); + break; + case 3: + Sound_Play(SID_ALIEN_HISS1,"dp",&(sbPtr->DynPtr->Position),-PREDALIEN_PITCH_CHANGE+pitch); + break; + default: + Sound_Play(SID_ALIEN_HISS,"dp",&(sbPtr->DynPtr->Position),-PREDALIEN_PITCH_CHANGE+pitch); + break; + } + } + + /* reduce pa-q health */ + //paqStatusPointer->health -= damage; + if(sbPtr->SBDamageBlock.Health > 0) return; + + /* we have been killed... */ + paqStatusPointer->NearBehaviourState=PAQNS_Dying; + paqStatusPointer->FarBehaviourState=PAQFS_Dying; + paqStatusPointer->stateTimer=PAQ_DIETIME; + SetPAQAnimationSequence(sbPtr,PaqSQ_Dying,10); + + /* stop motion */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; + /* turn off collisions */ + if(sbPtr->DynPtr) + { + sbPtr->DynPtr->IsStatic = 1; + sbPtr->DynPtr->DynamicsType = DYN_TYPE_NO_COLLISIONS; + sbPtr->DynPtr->GravityOn = 0; + } +} + + + +/*------------------------Patrick 18/2/97----------------------------- + Predator-Alien & Queen far state behaviour functions + --------------------------------------------------------------------*/ + +static void Execute_PAQFS_Wait(STRATEGYBLOCK *sbPtr) +{ + /* do absolutely nothing at all */ +} + +static void Execute_PAQFS_Hunt(STRATEGYBLOCK *sbPtr) +{ + PAQ_STATUS_BLOCK *paqStatusPointer; + AIMODULE *targetModule = 0; + + LOCALASSERT(sbPtr); + paqStatusPointer = (PAQ_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(paqStatusPointer); + + paqStatusPointer->stateTimer -= NormalFrameTime; + if(paqStatusPointer->stateTimer > 0) return; + + /* check for state changes */ + if(!PAQShouldAttackPlayer()) + { + /* we should be wandering */ + paqStatusPointer->FarBehaviourState = PAQFS_Wander; + paqStatusPointer->stateTimer = 0; /* forces execution of new state next frame */ + return; + } + + /* get the target */ + targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr); + if(!targetModule) + { + paqStatusPointer->stateTimer = PAQ_FAR_MOVE_TIME; + return; + } + + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + ProcessFarPAQTargetModule(sbPtr, targetModule); + /* reset timer */ + paqStatusPointer->stateTimer = PAQ_FAR_MOVE_TIME; +} + +static void Execute_PAQFS_Wander(STRATEGYBLOCK *sbPtr) +{ + PAQ_STATUS_BLOCK *paqStatusPointer; + AIMODULE *targetModule = 0; + + LOCALASSERT(sbPtr); + paqStatusPointer = (PAQ_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(paqStatusPointer); + + paqStatusPointer->stateTimer -= NormalFrameTime; + if(paqStatusPointer->stateTimer > 0) return; + + /* check for state changes */ + if(!PAQShouldAttackPlayer()) + { + /* we should be wandering */ + paqStatusPointer->FarBehaviourState = PAQFS_Hunt; + paqStatusPointer->stateTimer = 0; /* forces execution of new state next frame */ + return; + } + + /* get the target */ + targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr,NULL); + + if(!targetModule) + { + paqStatusPointer->stateTimer = PAQ_FAR_MOVE_TIME; + return; + } + + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + ProcessFarPAQTargetModule(sbPtr, targetModule); + /* reset timer */ + paqStatusPointer->stateTimer = PAQ_FAR_MOVE_TIME; +} + + + +static void ProcessFarPAQTargetModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule) +{ + NPC_TARGETMODULESTATUS targetStatus; + PAQ_STATUS_BLOCK *paqStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(targetModule); + LOCALASSERT((sbPtr->I_SBtype == I_BehaviourPredatorAlien)||(sbPtr->I_SBtype == I_BehaviourQueenAlien)); + paqStatusPointer = (PAQ_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(paqStatusPointer); + + targetStatus = GetTargetAIModuleStatus(sbPtr, targetModule); + switch(targetStatus) + { + case(NPCTM_NoEntryPoint): + { + /* do nothing */ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_NormalRoom): + { + /* locate to target */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_AirDuct): + { + /* do nothing - pa-q's can't go in air ducts */ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_LiftTeleport): + { + /* do nothing - pa-q's can't go into lifts */ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_ProxDoorOpen): + { + /* locate to target: don't need to move thro'quick, as door is constantly retriggered */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_ProxDoorNotOpen): + { + MODULE *renderModule; + renderModule=*(targetModule->m_module_ptrs); + /* trigger the door, and set timer to quick so we can catch the door when it's open */ + ((PROXDOOR_BEHAV_BLOCK *)renderModule->m_sbptr->SBdataptr)->alienTrigger = 1; + break; + } + case(NPCTM_LiftDoorOpen): + { + /* do nothing - can't use lifts */ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_LiftDoorNotOpen): + { + /* do nothing - can't open lift doors */ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_SecurityDoorOpen): + { + /* locate to target, and move thro' quick as we can't retrigger */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_SecurityDoorNotOpen): + { + MODULE *renderModule; + renderModule=*(targetModule->m_module_ptrs); + /* do some door opening stuff here. Door should stay open for long enough + for us to catch it open next time */ + RequestState((renderModule->m_sbptr),1,0); + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } +} + + +/*------------------------Patrick 18/2/97----------------------------- + Predator-Alien & Queen near state behaviour functions + --------------------------------------------------------------------*/ + +static void Execute_PAQNS_Wait(STRATEGYBLOCK *sbPtr) +{ + PAQ_STATUS_BLOCK *paqStatusPointer; + + LOCALASSERT(sbPtr); + paqStatusPointer = (PAQ_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(paqStatusPointer); + + /* test for attack */ + if(PAQShouldAttackPlayer()) + { + NPC_InitMovementData(&(paqStatusPointer->moveData)); + paqStatusPointer->NearBehaviourState = PAQNS_Approach; + SetPAQAnimationSequence(sbPtr,PaqSQ_Run,10); + paqStatusPointer->stateTimer = 0; + return; + } + + /* still waiting: decrement timer */ + paqStatusPointer->stateTimer-=NormalFrameTime; + + if(paqStatusPointer->stateTimer<=0) + { + /* waiting has expired: go to wander */ + NPC_InitMovementData(&(paqStatusPointer->moveData)); + NPC_InitWanderData(&(paqStatusPointer->wanderData)); + paqStatusPointer->NearBehaviourState = PAQNS_Wander; + SetPAQAnimationSequence(sbPtr,PaqSQ_Run,10); + paqStatusPointer->stateTimer = 0; + } +} + +static void Execute_PAQNS_Approach(STRATEGYBLOCK *sbPtr) +{ + PAQ_STATUS_BLOCK *paqStatusPointer; + VECTORCH velocityDirection = {0,0,0}; + DYNAMICSBLOCK *dynPtr; + VECTORCH targetPosition; + int targetIsAirduct = 0; + + LOCALASSERT(sbPtr); + paqStatusPointer = (PAQ_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(paqStatusPointer); + LOCALASSERT(sbPtr->DynPtr); + + dynPtr = sbPtr->DynPtr; + + /* check for state changes... */ + if(!(PAQShouldAttackPlayer())) + { + paqStatusPointer->NearBehaviourState = PAQNS_Wait; + paqStatusPointer->stateTimer = PAQ_NEARWAITTIME; + SetPAQAnimationSequence(sbPtr,PaqSQ_Stand,10); + return; + } + + /* check if we want to close-attack */ + if(VectorDistance((&Player->ObStrategyBlock->DynPtr->Position),(&sbPtr->DynPtr->Position)) < PAQ_CLOSE_ATTACK_RANGE) + { + paqStatusPointer->NearBehaviourState = PAQNS_Attack; + paqStatusPointer->stateTimer = PAQ_NEAR_CLOSEATTACK_TIME; + + /* choice of two animations for pred-alien */ + if(sbPtr->I_SBtype==I_BehaviourPredatorAlien) + { + if(FastRandom()&0x01) SetPAQAnimationSequence(sbPtr,PaqSQ_Attack,10); + else SetPAQAnimationSequence(sbPtr,PaqSQ_Attack2,10); + } + else SetPAQAnimationSequence(sbPtr,PaqSQ_Attack,10); + + return; + } + + /* Do some approach sound */ + { + unsigned int random=FastRandom(); + + switch (random & 255) + { + case 0: + { + Sound_Play(SID_ALIEN_SCREAM,"d",&dynPtr->Position); + break; + } + case 1: + { + Sound_Play(SID_ALIEN_HISS,"d",&dynPtr->Position); + break; + } + case 2: + { + Sound_Play(SID_ALIEN_HISS1,"d",&dynPtr->Position); + break; + } + case 3: + { + Sound_Play(SID_ALIEN_HIT,"d",&dynPtr->Position); + break; + } + case 4: + { + Sound_Play(SID_ALIEN_HIT2,"d",&dynPtr->Position); + break; + } + + default: + { + break; + } + } + + if(sbPtr->I_SBtype==I_BehaviourPredatorAlien) + { + switch ((random >> 8) & 255) + { + case 0: + { + Sound_Play(SID_PRED_SNARL,"d",&dynPtr->Position); + break; + } + case 1: + { + Sound_Play(SID_PRED_SCREAM1,"d",&dynPtr->Position); + break; + } + case 2: + { + Sound_Play(SID_PRED_LOUDROAR,"d",&dynPtr->Position); + break; + } + case 3: + { + Sound_Play(SID_PRED_SHORTROAR,"d",&dynPtr->Position); + break; + } + default: + { + break; + } + } + } + } + + + /*still approaching then... first, find point to aim for*/ + NPCGetMovementTarget(sbPtr, Player->ObStrategyBlock, &targetPosition, &targetIsAirduct); + NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,1); + NPCSetVelocity(sbPtr, &velocityDirection, paqStatusPointer->nearSpeed); + + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_OBSTRUCTIONREPORT obstruction; + NPC_IsObstructed(sbPtr,&(paqStatusPointer->moveData),&obstruction,&destructableObject); + if(obstruction.environment) + { + /* go to avoidance */ + NPC_InitMovementData(&(paqStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(paqStatusPointer->moveData.avoidanceDirn),&obstruction); + paqStatusPointer->NearBehaviourState = PAQNS_Avoidance; + paqStatusPointer->stateTimer = NPC_AVOIDTIME; + /* no sequence change required */ + return; + } + if(obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage, ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(paqStatusPointer->moveData), &targetPosition, &velocityDirection)) + { + /* go to avoidance */ + NPC_OBSTRUCTIONREPORT obstruction = {1,0,0}; + NPC_InitMovementData(&(paqStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(paqStatusPointer->moveData.avoidanceDirn),&obstruction); + paqStatusPointer->NearBehaviourState = PAQNS_Avoidance; + paqStatusPointer->stateTimer = NPC_AVOIDTIME; + /* no sequence change required */ + return; + } +} + +static void Execute_PAQNS_Attack(STRATEGYBLOCK *sbPtr) +{ + VECTORCH orientationDirn; + PAQ_STATUS_BLOCK *paqStatusPointer; + DYNAMICSBLOCK *dynPtr; + int i; + + LOCALASSERT(sbPtr); + paqStatusPointer = (PAQ_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(paqStatusPointer); + LOCALASSERT(sbPtr->DynPtr); + + dynPtr = sbPtr->DynPtr; + + /* Orientate towards player, just to make sure we're facing */ + orientationDirn.vx = Player->ObWorld.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = Player->ObWorld.vz - sbPtr->DynPtr->Position.vz; + i = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + if(VectorDistance(&(sbPtr->DynPtr->Position), &(Player->ObStrategyBlock->DynPtr->Position)) > PAQ_CLOSE_ATTACK_RANGE) + { + /* switch to approach state: don't need to directly test if we should switch to wander, + as approach state will do this anyway... */ + NPC_InitMovementData(&(paqStatusPointer->moveData)); + paqStatusPointer->NearBehaviourState = PAQNS_Approach; + paqStatusPointer->stateTimer = 0; + SetPAQAnimationSequence(sbPtr,PaqSQ_Run,10); + return; + } + + /* Make the attack sound */ + if (paqStatusPointer->stateTimer == PAQ_NEAR_CLOSEATTACK_TIME) + { + + if(sbPtr->I_SBtype==I_BehaviourPredatorAlien) + { + #define PREDALIEN_ATTACK_PITCH 350 + + unsigned int rand=FastRandom(); + + switch (rand & 7) + { + case 0: + { + Sound_Play(SID_SWIPE,"dp",&dynPtr->Position,(rand&255)-128-PREDALIEN_ATTACK_PITCH); + break; + } + case 1: + { + Sound_Play(SID_SWIPE2,"dp",&dynPtr->Position,(rand&255)-128-PREDALIEN_ATTACK_PITCH); + break; + } + case 2: + { + Sound_Play(SID_SWIPE3,"dp",&dynPtr->Position,(rand&255)-128-PREDALIEN_ATTACK_PITCH); + break; + } + case 3: + { + Sound_Play(SID_TAIL,"dp",&dynPtr->Position,(rand & 255)-PREDALIEN_ATTACK_PITCH); + break; + } + case 4: + { + Sound_Play(SID_PRED_SLASH,"dp",&dynPtr->Position,(rand&255)-128); + break; + } + case 5: + { + Sound_Play(SID_RIP,"dp",&dynPtr->Position,(rand&255)-128); + break; + } + case 6: + { + Sound_Play(SID_SWISH,"dp",&dynPtr->Position,-(rand & 255)-PREDALIEN_ATTACK_PITCH); + break; + } + case 7: + { + Sound_Play(SID_ALIEN_HISS,"dp",&dynPtr->Position,-(rand & 255)-PREDALIEN_ATTACK_PITCH); + break; + } + default: + { + break; + } + } + } + else + { + unsigned int rand=FastRandom(); + + switch (rand & 7) + { + case 0: + { + Sound_Play(SID_SWIPE,"dp",&dynPtr->Position,(rand&255)-128); + break; + } + case 1: + { + Sound_Play(SID_SWIPE2,"dp",&dynPtr->Position,(rand&255)-128); + break; + } + case 2: + { + Sound_Play(SID_SWIPE3,"dp",&dynPtr->Position,(rand&255)-128); + break; + } + case 3: + { + Sound_Play(SID_TAIL,"dp",&dynPtr->Position,-(rand & 255)); + break; + } + case 4: + { + Sound_Play(SID_ALIEN_HISS1,"dp",&dynPtr->Position,(rand&255)-128); + break; + } + case 5: + { + Sound_Play(SID_ALIEN_SCREAM,"dp",&dynPtr->Position,(rand&255)-128); + break; + } + case 6: + { + Sound_Play(SID_SWISH,"dp",&dynPtr->Position,-(rand & 255)); + break; + } + case 7: + { + Sound_Play(SID_ALIEN_HISS,"dp",&dynPtr->Position,-(rand & 255)); + break; + } + default: + { + break; + } + } + } + } + + /* Decrement the near state timer */ + paqStatusPointer->stateTimer -= NormalFrameTime; + if(paqStatusPointer->stateTimer > 0) + { + /* DAMAGE PLAYER HERE: NB USE STATUS BLOCK DAMAGEINFLICTED*/ + CauseDamageToObject(Player->ObStrategyBlock,&TemplateAmmo[AMMO_NPC_PAQ_CLAW].MaxDamage, ONE_FIXED,NULL); + /* Note, might want to personalise this more. * + * I'd love to use a #warning here. */ + paqStatusPointer->stateTimer = PAQ_NEAR_CLOSEATTACK_TIME; + } +} + +static void Execute_PAQNS_Avoidance(STRATEGYBLOCK *sbPtr) +{ + int terminateState = 0; + PAQ_STATUS_BLOCK *paqStatusPointer; + + LOCALASSERT(sbPtr); + paqStatusPointer = (PAQ_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(paqStatusPointer); + + /* set velocity */ + LOCALASSERT((paqStatusPointer->moveData.avoidanceDirn.vx!=0)|| + (paqStatusPointer->moveData.avoidanceDirn.vy!=0)|| + (paqStatusPointer->moveData.avoidanceDirn.vz!=0)); + NPCSetVelocity(sbPtr, &(paqStatusPointer->moveData.avoidanceDirn), (paqStatusPointer->nearSpeed)); + + /* next, decrement state timer */ + paqStatusPointer->stateTimer -= NormalFrameTime; + if(paqStatusPointer->stateTimer <= 0) terminateState = 1; + + /* and check for an impeding collision */ + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_OBSTRUCTIONREPORT obstruction; + NPC_IsObstructed(sbPtr,&(paqStatusPointer->moveData),&obstruction,&destructableObject); + if(obstruction.anySingleObstruction) + { + terminateState = 1; + } + } + + if(terminateState) + { + if(PAQShouldAttackPlayer()) + { + /* switch to approach */ + NPC_InitMovementData(&(paqStatusPointer->moveData)); + paqStatusPointer->NearBehaviourState = PAQNS_Approach; + paqStatusPointer->stateTimer = 0; + /* no sequence change required */ + } + else + { + /* switch to wander */ + NPC_InitMovementData(&(paqStatusPointer->moveData)); + NPC_InitWanderData(&(paqStatusPointer->wanderData)); + paqStatusPointer->NearBehaviourState = PAQNS_Wander; + paqStatusPointer->stateTimer = 0; + /* no sequence change required */ + } + } +} + +static void Execute_PAQNS_Wander(STRATEGYBLOCK *sbPtr) +{ + PAQ_STATUS_BLOCK *paqStatusPointer; + VECTORCH velocityDirection = {0,0,0}; + + LOCALASSERT(sbPtr); + paqStatusPointer = (PAQ_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(paqStatusPointer); + + /* should we change to approach state? */ + if(PAQShouldAttackPlayer()) + { + /* doesn't require a sequence change */ + NPC_InitMovementData(&(paqStatusPointer->moveData)); + paqStatusPointer->NearBehaviourState = PAQNS_Approach; + SetPAQAnimationSequence(sbPtr,PaqSQ_Run,10); + paqStatusPointer->stateTimer = 0; + return; + } + + /* wander target aquisition: if no target, or moved module */ + LOCALASSERT(sbPtr->containingModule); + if(paqStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_InitMovementData(&(paqStatusPointer->moveData)); + NPC_FindAIWanderTarget(sbPtr,&(paqStatusPointer->wanderData),&(paqStatusPointer->moveData)); + } + else if(paqStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_index) + { + NPC_FindAIWanderTarget(sbPtr,&(paqStatusPointer->wanderData),&(paqStatusPointer->moveData)); + } + + /* if we still haven't got one, go to wait */ + if(paqStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + paqStatusPointer->NearBehaviourState = PAQNS_Wait; + paqStatusPointer->stateTimer = PAQ_NEARWAITTIME; + SetPAQAnimationSequence(sbPtr,PaqSQ_Stand,10); + return; + } + + + /* ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(paqStatusPointer->wanderData.worldPosition),1); + NPCSetVelocity(sbPtr, &velocityDirection, paqStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_OBSTRUCTIONREPORT obstruction; + NPC_IsObstructed(sbPtr,&(paqStatusPointer->moveData),&obstruction,&destructableObject); + if((obstruction.environment)||(obstruction.otherCharacter)) + { + /* go to avoidance */ + NPC_InitMovementData(&(paqStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(paqStatusPointer->moveData.avoidanceDirn),&obstruction); + paqStatusPointer->NearBehaviourState = PAQNS_Avoidance; + paqStatusPointer->stateTimer = NPC_AVOIDTIME; + /* no sequence change required */ + return; + } + if(obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage, ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(paqStatusPointer->moveData), &(paqStatusPointer->wanderData.worldPosition), &velocityDirection)) + { + NPC_OBSTRUCTIONREPORT obstruction = {1,0,0}; + /* go to avoidance */ + NPC_InitMovementData(&(paqStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(paqStatusPointer->moveData.avoidanceDirn),&obstruction); + paqStatusPointer->NearBehaviourState = PAQNS_Avoidance; + paqStatusPointer->stateTimer = NPC_AVOIDTIME; + /* no sequence change required */ + return; + } +} + +static void Execute_Dying(STRATEGYBLOCK *sbPtr) +{ + PAQ_STATUS_BLOCK *paqStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + paqStatusPointer = (PAQ_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(paqStatusPointer); + + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + sbPtr->DynPtr->LinImpulse.vx = 0; + sbPtr->DynPtr->LinImpulse.vy = 0; + sbPtr->DynPtr->LinImpulse.vz = 0; + + paqStatusPointer->stateTimer -= NormalFrameTime; +} + +/* Patrick 7/7/97 ---------------------------------------------------- +PAQ beaviour support functions +----------------------------------------------------------------------*/ +static void SetPAQAnimationSequence(STRATEGYBLOCK *sbPtr, PAQ_SEQUENCE seq, int rate) +{ + SHAPEANIMATIONCONTROLDATA sacd; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->SBdptr); + + InitShapeAnimationControlData(&sacd); + sacd.seconds_per_frame = ONE_FIXED/rate; + sacd.sequence_no = seq; + sacd.default_start_and_end_frames = 1; + sacd.reversed = 0; + if(seq==PaqSQ_Dying) sacd.stop_at_end = 1; + else sacd.stop_at_end = 0; + + SetShapeAnimationSequence(sbPtr->SBdptr, &sacd); + + /* add follow on sequence ... */ + if(seq==PaqSQ_Dying) + { + sacd.sequence_no = PaqSQ_Dead; + sacd.stop_at_end = 1; + SetNextShapeAnimationSequence(sbPtr->SBdptr, &sacd); + } +} + +static int PAQShouldAttackPlayer(void) +{ + /* test for player being cloaked */ + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + if((playerStatusPtr->cloakOn==1)&&(playerStatusPtr->cloakPositionGivenAway==0)) + return 0; + } + + return 1; +} diff --git a/3dc/avp/BH_PAQ.H b/3dc/avp/BH_PAQ.H new file mode 100644 index 0000000..547e951 --- /dev/null +++ b/3dc/avp/BH_PAQ.H @@ -0,0 +1,103 @@ +/* Patrick 18/2/97 ------------------------------------------------ + Header file for alien queen and predator-alien support functions + -----------------------------------------------------------------*/ + +#ifndef _bhpaq_h_ +#define _bhpaq_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "bh_pred.h" + +/* Patrick 18/2/97 ------------------------------------------------ + Some enumerations +-----------------------------------------------------------------*/ +typedef enum PaqSequence +{ + PaqSQ_Run, + PaqSQ_Attack, + PaqSQ_Stand, + PaqSQ_Dying, + PaqSQ_Dead, + PaqSQ_Attack2, +}PAQ_SEQUENCE; + +typedef enum paq_far_bhstate +{ + PAQFS_Wait, + PAQFS_Hunt, + PAQFS_Wander, + PAQFS_Dying, +}PAQ_FAR_BHSTATE; + +typedef enum paq_near_bhstate +{ + PAQNS_Wait, + PAQNS_Approach, + PAQNS_Attack, + PAQNS_Wander, + PAQNS_Avoidance, + PAQNS_Dying, +}PAQ_NEAR_BHSTATE; + +/* Patrick 18/2/97 ------------------------------------------------ + Some structures +-----------------------------------------------------------------*/ +typedef struct paqStatusBlock +{ + signed int health; + signed int nearSpeed; + signed int damageInflicted; + PAQ_FAR_BHSTATE FarBehaviourState; + PAQ_NEAR_BHSTATE NearBehaviourState; + int stateTimer; + SHAPEANIMATIONCONTROLLER ShpAnimCtrl; + HMODELCONTROLLER HModelController; + NPC_MOVEMENTDATA moveData; + NPC_WANDERDATA wanderData; +}PAQ_STATUS_BLOCK; + +typedef struct tools_data_paq +{ + struct vectorch position; + int shapeIndex; + char nameID[SB_NAME_LENGTH]; +}TOOLS_DATA_PAQ; + +/* Patrick 18/2/97 ------------------------------------------------ + Some defines +-----------------------------------------------------------------*/ +#define PRAL_STARTING_HEALTH 700 +#define QUEEN_STARTING_HEALTH 1400 +#define NO_OF_FRAGMENTS_FROM_DEAD_PAQ 10 +#define PRAL_NEAR_SPEED 10000 /* mm/s */ +#define QUEEN_NEAR_SPEED 12000 /* mm/s */ +#define PRAL_NEAR_DAMAGE 20 /* mm/s */ +#define QUEEN_NEAR_DAMAGE 40 /* mm/s */ +#define PAQ_CLOSE_ATTACK_RANGE 1500 /* mm */ +#define PAQ_NEAR_VIEW_WIDTH 500 /* mm */ +/* 1-1.5 seconds in 16ths of a second */ +#define PAQ_FAR_MOVE_TIME ((16+(FastRandom()&0x07))*(ONE_FIXED>>4)) +#define PAQ_NEAR_CLOSEATTACK_TIME (ONE_FIXED>>1) /* 1/2 second */ +/* random time between 1 and 2 seconds,in fixed point,with granularity 1/8th second */ +#define PAQ_NEARWAITTIME (ONE_FIXED+((FastRandom()&0x7)*(ONE_FIXED>>3))) +#define PAQ_DIETIME (ONE_FIXED<<4) + +/* Patrick 18/2/97 ------------------------------------------------ + Some prototypes +-----------------------------------------------------------------*/ +void InitPredAlBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr); +void InitQueenBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr); +void PAQBehaviour(STRATEGYBLOCK *sbPtr); +void MakePAQNear(STRATEGYBLOCK *sbPtr); +void MakePAQFar(STRATEGYBLOCK *sbPtr); +void PAQIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple); + + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/3dc/avp/BH_PRED.H b/3dc/avp/BH_PRED.H new file mode 100644 index 0000000..9095f10 --- /dev/null +++ b/3dc/avp/BH_PRED.H @@ -0,0 +1,261 @@ +/*--------------Patrick 21/1/97----------------------- + Header file for predator AI & NPC support functions + ---------------------------------------------------*/ + +#ifndef _bhpred_h_ +#define _bhpred_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "bh_ais.h" +#include "decal.h" + +/*----------------------------- +Predator Specific Support +-------------------------------*/ +/* predator animation sequences */ +typedef enum predatorsequence +{ + PredSQ_Run=0, + PredSQ_Crawl, + PredSQ_Stand, + PredSQ_Crouch, + PredSQ_StandDie, + PredSQ_StandDead, + PredSQ_CrouchDie, + PredSQ_CrouchDead, + PredSQ_StandingSwipe, + PredSQ_CrouchedSwipe, + PredSQ_RunningSwipe, + PredSQ_CrawlingSwipe, + PredSQ_Jump, + PredSQ_Taunt, + PredSQ_Run_Backwards, + PredSQ_Crawl_Backwards, + PredSQ_RunningSwipe_Backwards, + PredSQ_CrawlingSwipe_Backwards, + PredSQ_BaseOfStaffAttacks=20, + PredSQ_BaseOfWristbladeAttacks=40, +}PREDATOR_SEQUENCE; + +typedef enum pred_bhstate { + PBS_Wandering, + PBS_Hunting, + PBS_Avoidance, + PBS_Withdrawing, + PBS_Dying, + PBS_Recovering, + PBS_SwapWeapon, + PBS_Engaging, + PBS_Attacking, + PBS_Pathfinding, + PBS_Returning, + PBS_Taunting, + PBS_SelfDestruct, +} PRED_BHSTATE; + +typedef enum pred_return_condition { + PRC_No_Change, + PRC_Request_Engage, + PRC_Request_Attack, + PRC_Request_Wander, + PRC_Request_Avoidance, + PRC_Request_Hunt, + PRC_Request_Withdraw, + PRC_Request_Recover, + PRC_Request_Swap, + PRC_Request_Return, + PRC_Request_Pathfind, + PRC_Request_Taunt, + PRC_Request_SelfDestruct, +} PRED_RETURN_CONDITION; + +/* cloaking states */ +typedef enum pred_cloakstate +{ + PCLOAK_Off, + PCLOAK_Activating, + PCLOAK_On, + PCLOAK_Deactivating, +}PRED_CLOAKSTATE; + +typedef struct predatorPersonalParameters +{ + int startingHealth; /* initial health */ + int speed; /* running speed */ + int defenceHealth; /* health level below which defensive behaviour is used */ + int useShoulderCannon; /* 1 = shouldercannon, 0 = disc */ + int timeBetweenRangedAttacks; + int maxShotsPerRangedAttack; + int timeBetweenShots; + int closeAttackDamage; + int regenerationUnit; /* health recovered when made visible */ + int chanceOfCloaking; /* 0-8, chance in 8 */ +} PREDATOR_PERSONALPARAMETERS; + +typedef enum predator_npc_weapons { + + PNPCW_Pistol, + PNPCW_Wristblade, + PNPCW_PlasmaCaster, + PNPCW_Staff, + PNPCW_Medicomp, + PNPCW_Speargun, + PNPCW_SeriousPlasmaCaster, + PNPCW_End, + +} PREDATOR_NPC_WEAPONS; + +typedef struct predator_weapon_data { + + PREDATOR_NPC_WEAPONS id; + PRED_RETURN_CONDITION (*WeaponFireFunction)(STRATEGYBLOCK *); + PRED_RETURN_CONDITION (*WeaponEngageFunction)(STRATEGYBLOCK *); + char *Riffname; + char *HierarchyName; + char *GunName; + char *ElevationName; + char *HitLocationTableName; + int MinRange; + int ForceFireRange; + int MaxRange; + int FiringRate; + int VolleySize; + int SwappingTime; + int UseElevation :1; + +}PREDATOR_WEAPON_DATA; + +typedef struct predatorStatusBlock +{ + signed int health; + PRED_BHSTATE behaviourState; + PRED_BHSTATE lastState; + + int stateTimer; + int internalState; + int patience; + int enableSwap; + int enableTaunt; + VECTORCH weaponTarget; /* target position for firing weapon at */ + int volleySize; /* used for weapon control */ + NPC_OBSTRUCTIONREPORT obstruction; + NPC_MOVEMENTDATA moveData; + NPC_WANDERDATA wanderData; + + NPC_AVOIDANCEMANAGER avoidanceManager; + WAYPOINT_MANAGER waypointManager; + + int IAmCrouched; + int personalNumber; /* for predator personalisation */ + int nearSpeed; + int GibbFactor; + + int incidentFlag; + int incidentTimer; + + PREDATOR_WEAPON_DATA *Selected_Weapon; + PREDATOR_NPC_WEAPONS PrimaryWeapon; + PREDATOR_NPC_WEAPONS SecondaryWeapon; + PREDATOR_NPC_WEAPONS ChangeToWeapon; + ATTACK_DATA *current_attack; + + STRATEGYBLOCK *Target; + char Target_SBname[SB_NAME_LENGTH]; + int soundHandle; + + HMODELCONTROLLER HModelController; + SECTION_DATA *My_Gun_Section; /* For template computation. */ + SECTION_DATA *My_Elevation_Section; /* For elevation computation. */ + + /* these are for cloaking... */ + PRED_CLOAKSTATE CloakStatus; + int CloakingEffectiveness; + int CloakTimer; + + /* And these for the laser dots. */ + THREE_LASER_DOT_DESC Pred_Laser_Sight; + int Pred_Laser_On :1; + int Explode :1; + /* Pathfinder parameters */ + int path; + int stepnumber; + AIMODULE *missionmodule; + AIMODULE *fearmodule; + /* Pathfinder parameters */ + + char death_target_ID[SB_NAME_LENGTH]; //another strategy can be notified of the marine's death + STRATEGYBLOCK* death_target_sbptr; + int death_target_request; + +}PREDATOR_STATUS_BLOCK; + +typedef struct dormantPredatorStatusBlock +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + void* toolsData; +}DORMANT_PREDATOR_STATUS_BLOCK; + +/* Tools data template */ +typedef struct tools_data_predator +{ + struct vectorch position; + int shapeIndex; + int predator_number; + char nameID[SB_NAME_LENGTH]; + PREDATOR_NPC_WEAPONS primary; + PREDATOR_NPC_WEAPONS secondary; + int path; + int stepnumber; + + char death_target_ID[SB_NAME_LENGTH]; + int death_target_request; + +}TOOLS_DATA_PREDATOR; + +#define PRED_SELF_DESTRUCT_TIMER (ONE_FIXED*3) +#define PRED_WALKING_SPEED_MAX (5000) +#define PRED_WALKING_SPEED_MIN (3000) +#define PRED_PATIENCE_TIME (6*ONE_FIXED) +#define PRED_REGEN_TIME (10*ONE_FIXED) +#define PRED_MAXIDENTITY (4) +#define NO_OF_FRAGMENTS_FROM_DEAD_PREDATOR (10) +#define PRED_CLOSE_ATTACK_RANGE (1500) /* mm */ +#define PRED_STAFF_ATTACK_RANGE (2000) /* mm */ +#define PRED_NEAR_VIEW_WIDTH (500) /* mm */ +#define PRED_FPPLASMA_INFRONT (600) /* mm */ +#define PRED_FPPLASMA_ACROSS (-500) /* mm */ +#define PRED_FPPLASMA_UP (900) /* mm */ +#define PRED_FPPLASMA_INFRONTCROUCH (600) /* mm */ +#define PRED_FPPLASMA_ACROSSCROUCH (-500) /* mm */ +#define PRED_FPPLASMA_UPCROUCH (400) /* mm */ +#define PRED_FPDISC_INFRONT (600) /* mm */ +#define PRED_FPDISC_ACROSS (500) /* mm */ +#define PRED_FPDISC_UP (500) /* mm */ +#define PRED_FPDISC_INFRONTCROUCH (600) /* mm */ +#define PRED_FPDISC_ACROSSCROUCH (500) /* mm */ +#define PRED_FPDISC_UPCROUCH (200) /* mm */ +#define PRED_PLASBOLTSPEED (22000) /* mm/s */ +#define PRED_PLASBOLTDAMAGE (50) +/* 1.5-2 seconds in 1/16 second. NB DO NOT INCREASE THIS */ +#define PRED_FAR_MOVE_TIME ((24+(FastRandom()&0x07))*(ONE_FIXED>>4)) +#define PRED_NEAR_CLOSEATTACK_TIME ONE_FIXED /* 1 second */ + +extern void InitPredatorBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr); +extern void InitDormantPredatorBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr); +extern void PredatorBehaviour(STRATEGYBLOCK *sbPtr); +extern void MakePredatorNear(STRATEGYBLOCK *sbPtr); +extern void MakePredatorFar(STRATEGYBLOCK *sbPtr); +extern void PredatorIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple,SECTION_DATA *Section, VECTORCH *incoming); +extern void ActivateDormantPredator(STRATEGYBLOCK *sbPtr); +extern int NPCPredatorIsCloaked(STRATEGYBLOCK *sbPtr); +extern void StartPredatorSelfDestructExplosion(STRATEGYBLOCK *sbPtr); + +#ifdef __cplusplus +} +#endif + + +#endif \ No newline at end of file diff --git a/3dc/avp/BH_SWDOR.C b/3dc/avp/BH_SWDOR.C new file mode 100644 index 0000000..92fe54c --- /dev/null +++ b/3dc/avp/BH_SWDOR.C @@ -0,0 +1,350 @@ +/*------------------------------Patrick 12/3/97----------------------------------- + Source for Switch Operated Doors + --------------------------------------------------------------------------------*/ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "triggers.h" +#include "mslhand.h" +#include "psnd.h" + +#define UseLocalAssert Yes + +#include "ourasert.h" +#include "pvisible.h" +#include "bh_swdor.h" +#include "savegame.h" + +/* external stuff */ + +extern int NormalFrameTime; + +/*---------------------Patrick 12/3/97------------------------- + Initialisation of a switch door.... + NB asumes that all switch doors start in a 'closed' state + -------------------------------------------------------------*/ +void InitialiseSwitchDoor(void* bhdata, STRATEGYBLOCK* sbPtr) +{ + SWITCH_DOOR_BEHAV_BLOCK *switchDoorBehaviourPtr; + SWITCH_DOOR_TOOLS_TEMPLATE *switchDoorToolsData; + MORPHCTRL *morphCtrl; + MORPHHEADER *morphHeader; + MORPHFRAME *morphFrame; + + /* create a switch door data block */ + switchDoorBehaviourPtr = (SWITCH_DOOR_BEHAV_BLOCK*)AllocateMem(sizeof(SWITCH_DOOR_BEHAV_BLOCK)); + if (!switchDoorBehaviourPtr) + { + memoryInitialisationFailure = 1; + return; + } + + switchDoorBehaviourPtr->myBehaviourType = I_BehaviourSwitchDoor; + sbPtr->SBdataptr = (void *)switchDoorBehaviourPtr; + /* cast the tools data for access */ + switchDoorToolsData = (SWITCH_DOOR_TOOLS_TEMPLATE *)bhdata; + + /* Set up a new Morph Control */ + morphFrame = (MORPHFRAME*)AllocateMem(sizeof(MORPHFRAME)); + if (!morphFrame) + { + memoryInitialisationFailure = 1; + return; + } + morphFrame->mf_shape1 = switchDoorToolsData->shapeOpen; + morphFrame->mf_shape2 = switchDoorToolsData->shapeClosed; + morphHeader = (MORPHHEADER*)AllocateMem(sizeof(MORPHHEADER)); + if (!morphHeader) + { + memoryInitialisationFailure = 1; + return; + } + morphHeader->mph_numframes = 1; + morphHeader->mph_maxframes = ONE_FIXED; + morphHeader->mph_frames = morphFrame; + morphCtrl = (MORPHCTRL*)AllocateMem(sizeof(MORPHCTRL)); + if (!morphCtrl) + { + memoryInitialisationFailure = 1; + return; + } + morphCtrl->ObMorphCurrFrame = 0; + morphCtrl->ObMorphFlags = 0; + morphCtrl->ObMorphSpeed = 0; + morphCtrl->ObMorphHeader = morphHeader; + switchDoorBehaviourPtr->morfControl = sbPtr->SBmorphctrl = morphCtrl; + + /* set up my module, and it's morph controls */ + COPY_NAME(sbPtr->SBname, switchDoorToolsData->nameID); + { + MREF mref=switchDoorToolsData->myModule; + ConvertModuleNameToPointer(&mref, MainSceneArray[0]->sm_marray); + GLOBALASSERT(mref.mref_ptr); + GLOBALASSERT(mref.mref_ptr->m_mapptr); + mref.mref_ptr->m_sbptr = sbPtr; + sbPtr->SBmoptr = mref.mref_ptr; + } + sbPtr->SBmomptr = sbPtr->SBmoptr->m_mapptr; + sbPtr->SBmomptr->MapMorphHeader = sbPtr->SBmorphctrl->ObMorphHeader; + sbPtr->SBmoptr->m_flags &= ~m_flag_open; + + /* set up some other behaviour block stuff */ + COPY_NAME(switchDoorBehaviourPtr->linkedDoorName, switchDoorToolsData->linkedDoorName); + switchDoorBehaviourPtr->doorState = I_door_closed; + switchDoorBehaviourPtr->linkedDoorPtr = (STRATEGYBLOCK *)0; + switchDoorBehaviourPtr->requestOpen = 0; + switchDoorBehaviourPtr->requestClose = 0; + switchDoorBehaviourPtr->openTimer = 0; + switchDoorBehaviourPtr->SoundHandle = SOUND_NOACTIVEINDEX; + CloseDoor(sbPtr->SBmorphctrl, DOOR_CLOSEFASTSPEED); + + { + // Work out the door sound pitch + + int maxX,maxY,maxZ,doorSize; + + maxX=mainshapelist[morphFrame->mf_shape2]->shapemaxx; + maxY=mainshapelist[morphFrame->mf_shape2]->shapemaxy; + maxZ=mainshapelist[morphFrame->mf_shape2]->shapemaxz; + + doorSize = maxX + maxY + maxZ; + if (doorSize < 3000) doorSize = 3000; + else if (doorSize > 8000) doorSize = 8000; + + doorSize = (3000 - doorSize) >> 4; + + switchDoorBehaviourPtr->doorType = doorSize; + + } + +} + + + +/*---------------------Patrick 13/3/97------------------------- + Switch door behaviour function. + -------------------------------------------------------------*/ +void SwitchDoorBehaviour(STRATEGYBLOCK* sbPtr) +{ + SWITCH_DOOR_BEHAV_BLOCK *doorBehaviour; + MORPHCTRL *mCtrl; + MODULE *mPtr; + int linkedDoorIsClosed = 1; + + GLOBALASSERT(sbPtr); + doorBehaviour = (SWITCH_DOOR_BEHAV_BLOCK*)sbPtr->SBdataptr; + GLOBALASSERT(doorBehaviour); + mCtrl = doorBehaviour->morfControl; + GLOBALASSERT(mCtrl); + mPtr = sbPtr->SBmoptr; + GLOBALASSERT(mPtr); + + /* update morphing.... */ + UpdateMorphing(mCtrl); + + /* get state of linked door: if there isn't a linked door, 'linkeddoorisclosed' + remains true so that there is no obstruction to operation of this door. + + NB can't use 'GetState' here, as it returns true only if the door is fully open + (used by the NPC's). Here, we need to determine if the door is closed (which is + not the same as !open) */ + if(doorBehaviour->linkedDoorPtr) + { + if(((SWITCH_DOOR_BEHAV_BLOCK *)doorBehaviour->linkedDoorPtr->SBdataptr)->doorState != I_door_closed) linkedDoorIsClosed = 0; + } + + switch(doorBehaviour->doorState) + { + case I_door_opening: + { + /* LOCALASSERT(linkedDoorIsClosed); */ + /* check if we've got a close request */ + if(doorBehaviour->requestClose && !AnythingInMyModule(sbPtr->SBmoptr)) + { + if(sbPtr->SBdptr) CloseDoor(mCtrl, DOOR_CLOSESLOWSPEED); + else CloseDoor(mCtrl, DOOR_CLOSEFASTSPEED); + doorBehaviour->doorState = I_door_closing; + } + /* already opening, so just allow the door to continue... */ + else if(mCtrl->ObMorphFlags & mph_flag_finished) + { + //door has finished opening + doorBehaviour->doorState = I_door_open; + doorBehaviour->openTimer = DOOR_FAROPENTIME; + + if (doorBehaviour->SoundHandle!=SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_DOOREND,"dp",&mPtr->m_world,doorBehaviour->doorType); + Sound_Stop(doorBehaviour->SoundHandle); + } + + } + break; + } + case I_door_closing: + { + /* LOCALASSERT(linkedDoorIsClosed); */ + /* check if we've got an open request, or anything has jumped in */ + if((doorBehaviour->requestOpen)||(AnythingInMyModule(sbPtr->SBmoptr))) + { + //have to start opening again + if(sbPtr->SBdptr) OpenDoor(mCtrl, DOOR_OPENSLOWSPEED); + else OpenDoor(mCtrl, DOOR_OPENFASTSPEED); + doorBehaviour->doorState = I_door_opening; + + Sound_Play(SID_DOORSTART,"dp",&mPtr->m_world,doorBehaviour->doorType); + Sound_Play(SID_DOORMID,"delp",&mPtr->m_world,&doorBehaviour->SoundHandle,doorBehaviour->doorType); + + } + /* check if we've finished closing */ + else if(mCtrl->ObMorphFlags & mph_flag_finished) + { + doorBehaviour->doorState = I_door_closed; + mPtr->m_flags &= ~m_flag_open; + + if (doorBehaviour->SoundHandle!=SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_DOOREND,"dp",&mPtr->m_world,doorBehaviour->doorType); + Sound_Stop(doorBehaviour->SoundHandle); + } + + } + break; + } + case I_door_open: + { + /* LOCALASSERT(linkedDoorIsClosed); */ + /*if we've got a close request , set the open timer to 0 + so the door will start closing*/ + if(doorBehaviour->requestClose) + { + doorBehaviour->openTimer=0; + } + /* check our timer to see if it's time to close*/ + if(doorBehaviour->openTimer <= 0) + { + /* make sure there's nothing inside the door module before closing */ + if(AnythingInMyModule(sbPtr->SBmoptr)==0) + { + if(sbPtr->SBdptr) CloseDoor(mCtrl, DOOR_CLOSESLOWSPEED); + else CloseDoor(mCtrl, DOOR_CLOSEFASTSPEED); + doorBehaviour->doorState = I_door_closing; + doorBehaviour->openTimer = 0; + + Sound_Play(SID_DOORSTART,"dp",&mPtr->m_world,doorBehaviour->doorType); + Sound_Play(SID_DOORMID,"delp",&mPtr->m_world,&doorBehaviour->SoundHandle,doorBehaviour->doorType); + } + } + else doorBehaviour->openTimer -= NormalFrameTime; + break; + } + case I_door_closed: + { + if((doorBehaviour->requestOpen)&&(linkedDoorIsClosed)) + { + /* just open the door */ + if(sbPtr->SBdptr) OpenDoor(mCtrl, DOOR_OPENSLOWSPEED); + else OpenDoor(mCtrl, DOOR_OPENFASTSPEED); + doorBehaviour->doorState = I_door_opening; + mPtr->m_flags |= m_flag_open; + + Sound_Play(SID_DOORSTART,"dp",&mPtr->m_world,doorBehaviour->doorType); + Sound_Play(SID_DOORMID,"delp",&mPtr->m_world,&doorBehaviour->SoundHandle,doorBehaviour->doorType); + + } + } + } + + /* must reset this every frame */ + doorBehaviour->requestOpen = 0; + doorBehaviour->requestClose = 0; +} + + + + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +typedef struct switch_door_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + DOOR_STATES doorState; + int openTimer; + unsigned int requestOpen :1; + unsigned int requestClose :1; + + //from the morph control + int ObMorphCurrFrame; + int ObMorphFlags; + int ObMorphSpeed; + +}SWITCH_DOOR_SAVE_BLOCK; + + + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV doorbhv + +void LoadStrategy_SwitchDoor(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + SWITCH_DOOR_BEHAV_BLOCK *doorbhv; + SWITCH_DOOR_SAVE_BLOCK* block = (SWITCH_DOOR_SAVE_BLOCK*) header; + + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourSwitchDoor) return; + + doorbhv = (SWITCH_DOOR_BEHAV_BLOCK*)sbPtr->SBdataptr; + + COPYELEMENT_LOAD(doorState) + COPYELEMENT_LOAD(openTimer) + COPYELEMENT_LOAD(requestOpen) + COPYELEMENT_LOAD(requestClose) + + COPYELEMENT_LOAD_EXT(block->ObMorphCurrFrame,doorbhv->morfControl->ObMorphCurrFrame) + COPYELEMENT_LOAD_EXT(block->ObMorphFlags , doorbhv->morfControl->ObMorphFlags) + COPYELEMENT_LOAD_EXT(block->ObMorphSpeed , doorbhv->morfControl->ObMorphSpeed) + + Load_SoundState(&doorbhv->SoundHandle); +} + +void SaveStrategy_SwitchDoor(STRATEGYBLOCK* sbPtr) +{ + SWITCH_DOOR_SAVE_BLOCK *block; + SWITCH_DOOR_BEHAV_BLOCK *doorbhv ; + + doorbhv = (SWITCH_DOOR_BEHAV_BLOCK*)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + COPYELEMENT_SAVE(doorState) + COPYELEMENT_SAVE(openTimer) + COPYELEMENT_SAVE(requestOpen) + COPYELEMENT_SAVE(requestClose) + + COPYELEMENT_SAVE_EXT(block->ObMorphCurrFrame,doorbhv->morfControl->ObMorphCurrFrame) + COPYELEMENT_SAVE_EXT(block->ObMorphFlags , doorbhv->morfControl->ObMorphFlags) + COPYELEMENT_SAVE_EXT(block->ObMorphSpeed , doorbhv->morfControl->ObMorphSpeed) + + Save_SoundState(&doorbhv->SoundHandle); + +} + + + + + + diff --git a/3dc/avp/BH_SWDOR.H b/3dc/avp/BH_SWDOR.H new file mode 100644 index 0000000..2ff8216 --- /dev/null +++ b/3dc/avp/BH_SWDOR.H @@ -0,0 +1,40 @@ +/*------------------------------Patrick 12/3/97----------------------------------- + Header for Switch Operated Doors + --------------------------------------------------------------------------------*/ + +typedef struct switch_door_behaviour_type +{ + AVP_BEHAVIOUR_TYPE myBehaviourType; /* just for testing system integrity */ + DOOR_STATES doorState; + MORPHCTRL *morfControl; + char linkedDoorName[SB_NAME_LENGTH]; + STRATEGYBLOCK* linkedDoorPtr; + int openTimer; + unsigned int requestOpen :1; + unsigned int requestClose :1; + int SoundHandle; + int doorType; // Used to determine door sound type + +} SWITCH_DOOR_BEHAV_BLOCK; + +typedef struct switch_door_tools_template +{ + BOOL state; + MREF myModule; + int shapeOpen; + int shapeClosed; + char linkedDoorName[SB_NAME_LENGTH]; + char nameID[SB_NAME_LENGTH]; +} SWITCH_DOOR_TOOLS_TEMPLATE; + +#define DOOR_OPENSLOWSPEED (1<<16) +#define DOOR_OPENFASTSPEED (1<<20) +#define DOOR_CLOSESLOWSPEED (1<<17) +#define DOOR_CLOSEFASTSPEED (1<<20) +#define DOOR_FAROPENTIME (ONE_FIXED<<2) /* 4 seconds: DO NOT CHANGE THIS OR AI MAY NOT WORK*/ +#define DOOR_OPENDISTANCE (5000) /* mm */ + +extern void InitialiseSwitchDoor(void* bhdata, STRATEGYBLOCK* sbptr); +extern void SwitchDoorBehaviour(STRATEGYBLOCK* sbptr); +extern void OpenDoor(MORPHCTRL *mctrl, int speed); +extern void CloseDoor(MORPHCTRL *mctrl, int speed); diff --git a/3dc/avp/BH_TYPES.C b/3dc/avp/BH_TYPES.C new file mode 100644 index 0000000..1bcf185 --- /dev/null +++ b/3dc/avp/BH_TYPES.C @@ -0,0 +1,3723 @@ +#define DB_LEVEL 3 + +#include "3dc.h" +#include "inline.h" +#include "module.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" + +#include "weapons.h" +#include "comp_shp.h" +#include "inventry.h" +#include "triggers.h" +#include "mslhand.h" + +#include "dynblock.h" +#include "dynamics.h" + +#define UseLocalAssert Yes + +#include "ourasert.h" + +#include "pmove.h" +#include "bh_alien.h" +#include "bh_gener.h" +#include "pvisible.h" +#include "bh_pred.h" +#include "bh_xeno.h" +#include "bh_paq.h" +#include "bh_queen.h" +#include "bh_marin.h" +#include "bh_fhug.h" +#include "bh_swdor.h" +#include "bh_ldoor.h" +#include "bh_plift.h" +#include "load_shp.h" +#include "bh_weap.h" +#include "bh_debri.h" +#include "lighting.h" +#include "bh_lnksw.h" +#include "bh_binsw.h" +#include "bh_spcl.h" +#include "bh_agun.h" +#include "bh_lift.h" +#include "bh_ltfx.h" +#include "bh_snds.h" +#include "bh_mission.h" +#include "bh_track.h" +#include "bh_fan.h" +#include "bh_rubberduck.h" +#include "bh_plachier.h" +#include "bh_light.h" +#include "bh_cable.h" +#include "bh_deathvol.h" +#include "bh_selfdest.h" +#include "bh_dummy.h" +#include "bh_pargen.h" +#include "bh_videoscreen.h" + +#include "psnd.h" +#include "plat_shp.h" +#include "savegame.h" + +#include "db.h" + +#if SupportWindows95 +/* for win95 net game support */ +#include "pldghost.h" +#endif +#include "bh_corpse.h" + +/* + our functions for doing stuff to objects + can be called in two different ways, call the function + that processes the list (ObjectBehaviours) or call + ExecuteBehaviour with the strategyblock +*/ + + +/**** extern globals ****/ + +extern int NormalFrameTime; + +// Standard Behaviours - note others are in relevent files + +static void* DoorProxBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr); +static void DoorProxBehaveFun(STRATEGYBLOCK* sbptr); +static void* SimpleAnimationBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr); +static void SimpleAnimBehaveFun(STRATEGYBLOCK* sbptr); +static void* InitDatabase(void* bhdata, STRATEGYBLOCK* sbptr); + +// support functions - others are extened in bh_types.h + +static int AnythingNearProxDoor(MODULE *doorModulePtr,PROXDOOR_BEHAV_BLOCK *doorbhv); +//static void CountToDeallocateTemporaryObject(STRATEGYBLOCK *); + +/***** extern functions *****/ + +extern void SmokeGeneratorBehaviour(STRATEGYBLOCK *sptr); +extern void InitPlayer(STRATEGYBLOCK* sbPtr, int sb_type); +extern void AlienFragFun(STRATEGYBLOCK* sptr); +extern void SetupSimpleAnimation(int counter, STRATEGYBLOCK *sbPtr); +extern void HierarchicalFragmentBehaviour(STRATEGYBLOCK *sptr); + +extern void Xeno_Enter_PowerUp_State(STRATEGYBLOCK *sbPtr); +extern void Xeno_Enter_PowerDown_State(STRATEGYBLOCK *sbPtr); + +/************************ FUNCTIONS TO FILL OUT SBS ***************/ +/* essentially these are the old entity type functions ******/ + +/* IMPORTANT IMPORTANT!!! + + If you write an allocater for a behaviour that AllocatesMem BESIDES + that for the BehaviourBlock e.g. the simpleanimations generates a + linked list of texture animation control blocks, one for every item + with an animation, THEN YOU MUST ALWAYS WRITE A SPECIFIC DEALLOCATER +*/ + + +static NPC_DATA NpcDataList[I_NPC_End]= { + { + I_NPC_Civilian, + { + 20, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_NPC_FaceHugger, + { + 5, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 1, /* Electric Sensitive */ + 3, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_NPC_ChestBurster, + { + 15, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 1, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_NPC_Alien, + { + 30, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 1, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_NPC_Xenoborg, + { + 750,/* Health */ + 120,/* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_NPC_Marine, + { + 25, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_NPC_PredatorAlien, + { + 200, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 1, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_NPC_SFMarine, + { + 40, /* Health */ + 10, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_NPC_Predator, + { + 450, /* Health */ + 200, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_NPC_PraetorianGuard, + { + 150, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 1, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_NPC_AlienQueen, + { + 4000, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_NPC_DefaultInanimate, + { + 10, /* Health */ + 2, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 1, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_PC_Alien_Easy, + { + 90, /* Health */ + 30, /* Armour (was 6) */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ /* Disabled, CDF 28/7/98 */ + 1, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_PC_Marine_Easy, + { + 100, /* Health */ + 20, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_PC_Predator_Easy, + { + 450, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_PC_Alien_Medium, + { + 90, /* Health */ + 30, /* Armour (was 6) */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ /* Disabled, CDF 28/7/98 */ + 1, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_PC_Marine_Medium, + { + 100, /* Health */ + 20, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_PC_Predator_Medium, + { + 450, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_PC_Alien_Hard, + { + 90, /* Health */ + 30, /* Armour (was 6) */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ /* Disabled, CDF 28/7/98 */ + 1, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_PC_Marine_Hard, + { + 100, /* Health */ + 20, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_PC_Predator_Hard, + { + 450, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_PC_Alien_Impossible, + { + 30, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 1, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_PC_Marine_Impossible, + { + 25, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_PC_Predator_Impossible, + { + 450, /* Health */ + 200, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_PC_Alien_MaxStats, + { + 180, /* Health */ + 30, /* Armour (was 6) */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ /* Disabled, CDF 28/7/98 */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_NPC_SentryGun, + { + 50, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, + { + I_NPC_Android, + { + 40, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 1, /* Combustability */ + 0, /* Indestructable */ + }, + }, + }, +}; + +/* Interface Function! */ + +NPC_DATA *GetThisNpcData(NPC_TYPES NpcType) { +int a; + +for (a=0; aSBdptr; + GLOBALASSERT(dptr); + + dptr->ObShape = I_ShapeCube; + + InitPlayer(sbptr, I_BehaviourMarinePlayer); +} + +#if Saturn || PSX + +int SetUpDoor(int shape1, int shape2, MODULE* mptr) +{ + DISPLAYBLOCK* dptr = mptr->m_dptr; + MODULEMAPBLOCK* momptr = mptr->m_mapptr; + MORPHCTRL* morphctrl; + MORPHHEADER* morphheader; + MORPHFRAME* morphframe; + STRATEGYBLOCK* sbptr; + + GLOBALASSERT(dptr); + GLOBALASSERT(momptr); + + sbptr = AttachNewStratBlock(mptr, momptr, dptr); + + // this code causes a memory leak + + morphctrl = (MORPHCTRL*)AllocateMem(sizeof(MORPHCTRL)); + if(!morphctrl) + { + memoryInitialisationFailure = 1; + return 0; + } + + morphheader = (MORPHHEADER*)AllocateMem(sizeof(MORPHHEADER)); + if(!morphheader) + { + memoryInitialisationFailure = 1; + return 0; + } + + morphframe = (MORPHFRAME*)AllocateMem(sizeof(MORPHFRAME)); + if(!morphframe) + { + memoryInitialisationFailure = 1; + return 0; + } + + #if Saturn + morphframe->mf_shape1 = shape2; + morphframe->mf_shape2 = shape1; + #else + morphframe->mf_shape1 = shape1; + morphframe->mf_shape2 = shape2; + #endif + + dptr->ObShapeData = GetShapeData(shape1); + + morphheader->mph_numframes = 1; + morphheader->mph_maxframes = ONE_FIXED; + morphheader->mph_frames = morphframe; + + morphctrl->ObMorphCurrFrame = 0; + morphctrl->ObMorphFlags = 0; + morphctrl->ObMorphSpeed = 0; + morphctrl->ObMorphHeader = morphheader; + + EnableBehaviourType(sbptr, I_BehaviourProximityDoor, (void*)morphctrl); + + return 0; +} + +#endif /*SupportSaturn*/ + + + +/*---------------------------------------------------------------------- + Use this function to initialise binary loaded objects + ----------------------------------------------------------------------*/ + +void EnableBehaviourType(STRATEGYBLOCK* sbptr, AVP_BEHAVIOUR_TYPE sb_type, void *bhdata) +{ + + GLOBALASSERT(sbptr); + + sbptr->I_SBtype = sb_type; + + switch(sb_type) + { + case I_BehaviourAlien: + InitAlienBehaviour(bhdata, sbptr); + break; + + case I_BehaviourFaceHugger: + InitFacehuggerBehaviour(bhdata, sbptr); + break; + + case I_BehaviourPredator: + InitPredatorBehaviour(bhdata, sbptr); + break; + + case I_BehaviourDormantPredator: + InitDormantPredatorBehaviour(bhdata, sbptr); + break; + + case I_BehaviourXenoborg: + InitXenoborgBehaviour(bhdata, sbptr); + break; + + case I_BehaviourQueenAlien: + InitQueenBehaviour(bhdata, sbptr); + break; + + case I_BehaviourPredatorAlien: + GLOBALASSERT(0); + //InitPredAlBehaviour(bhdata, sbptr); + break; + + case I_BehaviourMarine: + InitMarineBehaviour(bhdata, sbptr); + break; + + case I_BehaviourSeal: + InitSealBehaviour(bhdata, sbptr); + break; + + case I_BehaviourProximityDoor: + sbptr->SBdataptr = DoorProxBehaveInit(bhdata, sbptr); + sbptr->SBmoptr->m_flags &= ~m_flag_open; + break; + + case I_BehaviourLiftDoor: + sbptr->SBdataptr = LiftDoorBehaveInit(bhdata, sbptr); + break; + + case I_BehaviourSwitchDoor: + InitialiseSwitchDoor(bhdata, sbptr); + break; + + case I_BehaviourPlatform: + InitialisePlatformLift(bhdata, sbptr); + break; + + case I_BehaviourBinarySwitch: + if(sbptr->shapeIndex!=-1)/*Allow for switches that have no shape*/ + { + sbptr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); + } + sbptr->SBdataptr = BinarySwitchBehaveInit(bhdata, sbptr); + break; + + case I_BehaviourLinkSwitch: + if(sbptr->shapeIndex!=-1)/*Allow for switches that have no shape*/ + { + sbptr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); + } + sbptr->SBdataptr = LinkSwitchBehaveInit(bhdata, sbptr); + break; + + case I_BehaviourLift: + sbptr->SBdataptr = LiftBehaveInit(bhdata, sbptr); + break; + + case I_BehaviourSimpleAnimation: + sbptr->SBdataptr = SimpleAnimationBehaveInit(bhdata, sbptr); + break; + + case I_BehaviourGenerator: + InitGenerator(bhdata, sbptr); + break; + + case I_BehaviourAutoGun: + AutoGunBehaveInit(bhdata, sbptr); + break; + + case I_BehaviourInanimateObject: + InitInanimateObject(bhdata, sbptr); + break; + + case I_BehaviourDatabase: + sbptr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); + sbptr->SBdataptr = InitDatabase(bhdata, sbptr); + break; + + case I_BehaviourXenoborgMorphRoom: + sbptr->SBdataptr = InitXenoMorphRoom (bhdata, sbptr); + break; + + case I_BehaviourLightFX: + { + sbptr->SBdataptr = LightFXBehaveInit (bhdata, sbptr); + break; + } + + case I_BehaviourPlacedSound: + { + sbptr->SBdataptr = SoundBehaveInit (bhdata, sbptr); + break; + } + + case I_BehaviourMissionComplete: + { + sbptr->SBdataptr = MissionCompleteBehaveInit (bhdata, sbptr); + break; + } + case I_BehaviourMessage: + { + sbptr->SBdataptr = MessageBehaveInit (bhdata, sbptr); + break; + } + case I_BehaviourTrackObject: + { + sbptr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); + sbptr->SBdataptr = TrackObjectBehaveInit(bhdata, sbptr); + break; + } + case I_BehaviourFan: + { + sbptr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); + sbptr->SBdataptr = FanBehaveInit(bhdata, sbptr); + break; + } + case I_BehaviourPlacedHierarchy: + { + sbptr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); + sbptr->SBdataptr = PlacedHierarchyBehaveInit(bhdata, sbptr); + break; + } + + case I_BehaviourPlacedLight: + InitPlacedLight(bhdata, sbptr); + break; + + case I_BehaviourVideoScreen: + InitVideoScreen(bhdata, sbptr); + break; + + case I_BehaviourPowerCable : + sbptr->SBdataptr = PowerCableBehaveInit(bhdata, sbptr); + break; + + case I_BehaviourDeathVolume : + sbptr->SBdataptr = DeathVolumeBehaveInit(bhdata, sbptr); + break; + + case I_BehaviourSelfDestruct : + sbptr->SBdataptr = SelfDestructBehaveInit(bhdata, sbptr); + break; + + case I_BehaviourParticleGenerator : + sbptr->SBdataptr = ParticleGeneratorBehaveInit(bhdata, sbptr); + break; + default: + break; + } +} + + + + + +/****************** DOOR INIT ***************************/ + + +/* (these shift values are passed to the open/close prox door fn's, +and control the morphing speed) */ + + +static void* DoorProxBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr) +{ + PROXDOOR_BEHAV_BLOCK *doorbhv; + PROX_DOOR_TOOLS_TEMPLATE *doortt; + MORPHCTRL* morphctrl; + MORPHHEADER* morphheader; + MORPHFRAME* morphframe; + MODULE * my_mod; + + GLOBALASSERT(sbptr); + doorbhv = (PROXDOOR_BEHAV_BLOCK*)AllocateMem(sizeof(PROXDOOR_BEHAV_BLOCK)); + + if(!doorbhv) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + + doorbhv->bhvr_type = I_BehaviourProximityDoor; + + // Who is doing the deallocation for this - the unloaders + // should CHECK THIS. + + doortt = (PROX_DOOR_TOOLS_TEMPLATE*)bhdata; + + + // Set up a new Morph Control + morphctrl = (MORPHCTRL*)AllocateMem(sizeof(MORPHCTRL)); + if(!morphctrl) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + morphheader = (MORPHHEADER*)AllocateMem(sizeof(MORPHHEADER)); + if(!morphheader) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + morphframe = (MORPHFRAME*)AllocateMem(sizeof(MORPHFRAME)); + if(!morphframe) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + + morphframe->mf_shape1 = doortt->shape_open; + morphframe->mf_shape2 = doortt->shape_closed; + + morphheader->mph_numframes = 1; + morphheader->mph_maxframes = ONE_FIXED; + morphheader->mph_frames = morphframe; + + morphctrl->ObMorphCurrFrame = 0; + morphctrl->ObMorphFlags = 0; + morphctrl->ObMorphSpeed = 0; + morphctrl->ObMorphHeader = morphheader; + + + // Copy the name over + COPY_NAME (sbptr->SBname, doortt->nameID); + + + // Setup module ref + { + MREF mref=doortt->my_module; + ConvertModuleNameToPointer (&mref, MainSceneArray[0]->sm_marray); + my_mod = mref.mref_ptr; + } + GLOBALASSERT (my_mod); + + my_mod->m_sbptr = sbptr; + sbptr->SBmoptr = my_mod; + sbptr->SBmomptr = my_mod->m_mapptr; + sbptr->SBflags.no_displayblock = 1; + + + doorbhv->PDmctrl = morphctrl; + doorbhv->lockable_door = doortt->has_lock_target; + + doorbhv->door_opening_speed=doortt->door_opening_speed; + doorbhv->door_closing_speed=doortt->door_closing_speed; + + if(doortt->has_lock_target) + { + COPY_NAME(doorbhv->target_name, doortt->target_name); + } + + sbptr->SBmorphctrl = doorbhv->PDmctrl; + sbptr->SBmorphctrl->ObMorphCurrFrame = 1; /* this should be closed*/ + + doorbhv->door_state = I_door_closed; + CloseDoor(sbptr->SBmorphctrl, DOOR_CLOSEFASTSPEED); + + if(sbptr->SBmoptr) + { + sbptr->SBmoptr->m_flags |= m_flag_open; + } + if(sbptr->SBmomptr) + { + sbptr->SBmomptr->MapMorphHeader = sbptr->SBmorphctrl->ObMorphHeader; + } + + /*-----------Patrick 9/12/96-------------- + a little addition... + -----------------------------------------*/ + doorbhv->alienTrigger = 0; + doorbhv->marineTrigger = 0; + doorbhv->triggeredByMarine = 0; + doorbhv->alienTimer = 0; + doorbhv->door_locked = doortt->door_is_locked; + + /* Andy 10/6/97 -------------------------- + sound stuff... + ----------------------------------------*/ + doorbhv->SoundHandle = SOUND_NOACTIVEINDEX; + + { + // Work out the door sound pitch + + int maxX,maxY,maxZ,doorSize; + + maxX=mainshapelist[morphframe->mf_shape2]->shapemaxx; + maxY=mainshapelist[morphframe->mf_shape2]->shapemaxy; + maxZ=mainshapelist[morphframe->mf_shape2]->shapemaxz; + + doorSize = maxX + maxY + maxZ; + if (doorSize < 3000) doorSize = 3000; + else if (doorSize > 8000) doorSize = 8000; + + doorSize = (3000 - doorSize) >> 4; + + doorbhv->doorType = doorSize; + + } + + return((void*)doorbhv); +} + + + + + + +/******************** ANIMATION INIT *************************/ + + +static void* SimpleAnimationBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr) +{ + /**RWH 10/12/96 *************************************** + + Simple Animation intialistation. This will set up an array + of texture control blocks. Each textures controlblock will animate only + one sequence per polygon. + + ***********************************************************/ + + SIMPLE_ANIM_BEHAV_BLOCK *sabhv; + int item_num; + TXACTRLBLK **pptxactrlblk; + SIMPLE_ANIM_TOOLS_TEMPLATE * satt = (SIMPLE_ANIM_TOOLS_TEMPLATE *)bhdata; + int shape_num = satt->shape_num; + SHAPEHEADER *shptr = GetShapeData(shape_num); + MODULE * my_mod; + + + GLOBALASSERT(shptr); + GLOBALASSERT(shptr->numitems > 0); + + SetupPolygonFlagAccessForShape(shptr); + + sabhv = (SIMPLE_ANIM_BEHAV_BLOCK*)AllocateMem(sizeof(SIMPLE_ANIM_BEHAV_BLOCK)); + if(!sabhv) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + + sabhv->bhvr_type = I_BehaviourSimpleAnimation; + + // Copy the name over + COPY_NAME (sbptr->SBname, satt->nameID); + + // Setup module ref + + if (*((int *)satt->my_module.mref_name)) + { + { + MREF mref=satt->my_module; + ConvertModuleNameToPointer (&mref, MainSceneArray[0]->sm_marray); + my_mod = mref.mref_ptr; + } + GLOBALASSERT (my_mod); + + my_mod->m_sbptr = sbptr; + sbptr->SBmoptr = my_mod; + sbptr->SBmomptr = my_mod->m_mapptr; + sbptr->SBflags.no_displayblock = 1; + } + + + /* we need to reserve the address of where we + are going to place the new animation ctrl block. + + this is so that we can call the texture animation builder + in the below loop + */ + + pptxactrlblk = &sabhv->tacbSimple; + + /* + the bhdata is a ptr to the SHAPEHEADER each + animating polygon has an array of sequences, in + this case thers is only onr sequence per array + */ + + for(item_num = 0; item_num < shptr->numitems; item_num ++) + { + POLYHEADER *poly = (POLYHEADER*)(shptr->items[item_num]); + LOCALASSERT(poly); + + if((Request_PolyFlags((void *)poly)) & iflag_txanim) + { + TXACTRLBLK *pnew_txactrlblk; + + pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK)); + if (pnew_txactrlblk) + { + pnew_txactrlblk->tac_flags = 0; + pnew_txactrlblk->tac_item = item_num; + pnew_txactrlblk->tac_sequence = 0; + pnew_txactrlblk->tac_node = 0; + pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shape_num, item_num); + pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shape_num); + + /* set the flags in the animation header */ + + /* KJL 17:00:38 04/04/97 - ChrisF complained about the next line, so + I've turned it off to see if anything happens. */ + /*pnew_txactrlblk->tac_txah.txa_flags = txa_flag_play; */ + + /* change the value held in pptxactrlblk + which point to the previous structures "next" + pointer*/ + + *pptxactrlblk = pnew_txactrlblk; + pptxactrlblk = &pnew_txactrlblk->tac_next; + } + else + { + memoryInitialisationFailure = 1; + } + } + } + *pptxactrlblk=0; + + return((void*)sabhv); +} + + + +static void* InitDatabase(void* bhdata, STRATEGYBLOCK* sbptr) +{ + DATABASE_BLOCK *db; + DATABASE_TOOLS_TEMPLATE *dbtt; + + GLOBALASSERT(sbptr); + GLOBALASSERT(bhdata); + dbtt = (DATABASE_TOOLS_TEMPLATE*)bhdata; + + db = (DATABASE_BLOCK*)AllocateMem(sizeof(DATABASE_BLOCK)); + if(!db) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + + db->bhvr_type=I_BehaviourDatabase; + + db->num = dbtt->num; + + sbptr->DynPtr->Position = sbptr->DynPtr->PrevPosition = dbtt->position; + sbptr->DynPtr->OrientEuler = dbtt->orientation; + CreateEulerMatrix(&sbptr->DynPtr->OrientEuler, &sbptr->DynPtr->OrientMat); + TransposeMatrixCH(&sbptr->DynPtr->OrientMat); + + sbptr->shapeIndex = dbtt->shape_num; + + return(void*)db; +} + + + + + +/********************************************************************* +******************************** ASSIGN SB Names ********************/ + + +void AssignAllSBNames() +{ + + int stratblock = NumActiveStBlocks; + GLOBALASSERT(stratblock>=0); + + while(--stratblock >= 0) + { + STRATEGYBLOCK* sbptr = ActiveStBlockList[stratblock]; + GLOBALASSERT(sbptr); + + switch (sbptr->I_SBtype) + { + case I_BehaviourBinarySwitch: + { + BINARY_SWITCH_BEHAV_BLOCK *bs_bhv; + int i; + bs_bhv = (BINARY_SWITCH_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((bs_bhv->bhvr_type == I_BehaviourBinarySwitch)); + for (i=0; inum_targets; i++) + { + bs_bhv->bs_targets[i] = FindSBWithName(bs_bhv->target_names[i].name); + } + break; + } + case I_BehaviourLinkSwitch: + { + LINK_SWITCH_BEHAV_BLOCK *ls_bhv; + int i=0; + ls_bhv = (LINK_SWITCH_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((ls_bhv->bhvr_type == I_BehaviourLinkSwitch)); + + for(i=0;inum_linked_switches;i++) + { + ls_bhv->lswitch_list[i].bswitch = FindSBWithName(ls_bhv->lswitch_list[i].bs_name); + } + + for(i=0;inum_targets;i++) + { + ls_bhv->ls_targets[i].sbptr=FindSBWithName(ls_bhv->ls_targets[i].name); + } + + break; + } + case I_BehaviourSwitchDoor: + { + SWITCH_DOOR_BEHAV_BLOCK *switchDoorBehaviourPtr = (SWITCH_DOOR_BEHAV_BLOCK *)sbptr->SBdataptr; + if(*((int *)switchDoorBehaviourPtr->linkedDoorName) + *( ((int *)switchDoorBehaviourPtr->linkedDoorName)+1 ) ) + switchDoorBehaviourPtr->linkedDoorPtr = FindSBWithName(switchDoorBehaviourPtr->linkedDoorName); + /* may or may not be linked to another door */ + if(switchDoorBehaviourPtr->linkedDoorPtr) + { + GLOBALASSERT(switchDoorBehaviourPtr->linkedDoorPtr->I_SBtype == I_BehaviourSwitchDoor); + } + break; + } + case I_BehaviourProximityDoor: + { + PROXDOOR_BEHAV_BLOCK *doorbhv; + doorbhv = (PROXDOOR_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((doorbhv->bhvr_type == I_BehaviourProximityDoor)); + if(doorbhv->lockable_door) + { + doorbhv->door_lock_target = FindSBWithName(doorbhv->target_name); + } + break; + } + case I_BehaviourLift: + { + LIFT_BEHAV_BLOCK *lift_bhv; + LIFT_STATION *curr_stn; + lift_bhv = (LIFT_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((lift_bhv->bhvr_type == I_BehaviourLift)); + curr_stn = &lift_bhv->lift_station; + GLOBALASSERT(curr_stn); + curr_stn->lift_call_switch = FindSBWithName(curr_stn->lift_call_switch_name); + if((*(int*)&curr_stn->lift_floor_switch_name[0]) || (*(int*)&curr_stn->lift_floor_switch_name[4])) + curr_stn->lift_floor_switch = FindSBWithName(curr_stn->lift_floor_switch_name); //lifts with switches that don't teleport,don't know about their floor switches + curr_stn->lift_door = FindSBWithName(curr_stn->lift_door_name); + + // find my module pointer + + { + STRATEGYBLOCK *my_sb; + my_sb = FindSBWithName(curr_stn->my_sb_name); + if(my_sb) + curr_stn->lift_module = my_sb->SBmoptr; + + } + + // find the controlling lift behave block + lift_bhv->control_sb = FindSBWithName(lift_bhv->control_sb_name); + + GLOBALASSERT(lift_bhv->control_sb); + + { + LIFT_STATION **lift_array; + LIFT_BEHAV_BLOCK *cont_bhv = lift_bhv->control_sb->SBdataptr; + + lift_bhv->lift_control = cont_bhv->lift_control; + lift_array = cont_bhv->lift_control->lift_stations; + + lift_array[curr_stn->num_floor] = curr_stn; + } + + if(curr_stn->starting_station) + { + // the door on this floor is open + // therefore, since we are all perfect + // i can say + + GLOBALASSERT(lift_bhv->lift_control->curr_station == -1); + + lift_bhv->lift_control->curr_station = curr_stn->num_floor; + if(curr_stn->env == AvP.CurrentEnv) + { + if(curr_stn->lift_call_switch) + { + // turn on the floor lights + RequestState(curr_stn->lift_call_switch, 1, 0); + if((*(int*)&curr_stn->lift_floor_switch_name[0]) || (*(int*)&curr_stn->lift_floor_switch_name[4])) + RequestState(curr_stn->lift_floor_switch, 1, 0); + } + } + + + } + + + + break; + } + + case I_BehaviourXenoborgMorphRoom: + { + XENO_MORPH_ROOM_DATA * xmrd = (XENO_MORPH_ROOM_DATA *)sbptr->SBdataptr; + + GLOBALASSERT (xmrd->bhvr_type == I_BehaviourXenoborgMorphRoom); + + xmrd->DoorToRoom = FindSBWithName(xmrd->doorID); + break; + } + + default: + break; + + case I_BehaviourAlien: + { + ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)sbptr->SBdataptr; + alienStatus->death_target_sbptr = FindSBWithName(alienStatus->death_target_ID); + + break; + } + case I_BehaviourMarine: + { + MARINE_STATUS_BLOCK *marineStatus = (MARINE_STATUS_BLOCK *)sbptr->SBdataptr; + marineStatus->death_target_sbptr = FindSBWithName(marineStatus->death_target_ID); + + break; + } + case I_BehaviourPredator: + { + PREDATOR_STATUS_BLOCK *predatorStatus = (PREDATOR_STATUS_BLOCK *)sbptr->SBdataptr; + predatorStatus->death_target_sbptr = FindSBWithName(predatorStatus->death_target_ID); + + break; + } + case I_BehaviourXenoborg: + { + XENO_STATUS_BLOCK *xenoStatus = (XENO_STATUS_BLOCK *)sbptr->SBdataptr; + xenoStatus->death_target_sbptr = FindSBWithName(xenoStatus->death_target_ID); + + break; + } + case I_BehaviourAutoGun: + { + AUTOGUN_STATUS_BLOCK *agunStatus = (AUTOGUN_STATUS_BLOCK *)sbptr->SBdataptr; + agunStatus->death_target_sbptr = FindSBWithName(agunStatus->death_target_ID); + + break; + } + case I_BehaviourQueenAlien: + { + QUEEN_STATUS_BLOCK *queenStatus = (QUEEN_STATUS_BLOCK *)sbptr->SBdataptr; + queenStatus->death_target_sbptr = FindSBWithName(queenStatus->death_target_ID); + + break; + } + case I_BehaviourFaceHugger: + { + FACEHUGGER_STATUS_BLOCK *facehuggerStatus = (FACEHUGGER_STATUS_BLOCK *)sbptr->SBdataptr; + facehuggerStatus->death_target_sbptr = FindSBWithName(facehuggerStatus->death_target_ID); + + break; + } + case I_BehaviourTrackObject: + { + int i; + TRACK_OBJECT_BEHAV_BLOCK *to_bhv = (TRACK_OBJECT_BEHAV_BLOCK *)sbptr->SBdataptr; + for(i=0;inum_special_track_points;i++) + { + int j; + SPECIAL_TRACK_POINT* stp=&to_bhv->special_track_points[i]; + for(j=0;jnum_targets;j++) + { + stp->targets[j].target_sbptr=FindSBWithName(stp->targets[j].target_name); + } + } + + to_bhv->destruct_target_sbptr=FindSBWithName(to_bhv->destruct_target_ID); + + break; + } + case I_BehaviourPlacedHierarchy: + { + int i; + PLACED_HIERARCHY_BEHAV_BLOCK *ph_bhv = (PLACED_HIERARCHY_BEHAV_BLOCK *)sbptr->SBdataptr; + for(i=0;inum_special_track_points;i++) + { + int j; + SPECIAL_TRACK_POINT* stp=&ph_bhv->special_track_points[i]; + for(j=0;jnum_targets;j++) + { + stp->targets[j].target_sbptr=FindSBWithName(stp->targets[j].target_name); + } + } + + break; + } + + case I_BehaviourInanimateObject: + { + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr=(INANIMATEOBJECT_STATUSBLOCK*)sbptr->SBdataptr; + if(objectstatusptr) + { + if(objectstatusptr->event_target) + { + objectstatusptr->event_target->event_target_sbptr=FindSBWithName(objectstatusptr->event_target->event_target_ID); + } + } + break; + + } + + case I_BehaviourPlacedLight: + { + PLACED_LIGHT_BEHAV_BLOCK* pl_bhv=(PLACED_LIGHT_BEHAV_BLOCK*)sbptr->SBdataptr; + if(pl_bhv) + { + pl_bhv->destruct_target_sbptr=FindSBWithName(pl_bhv->destruct_target_ID); + + } + break; + + } + case I_BehaviourVideoScreen: + { + VIDEO_SCREEN_BEHAV_BLOCK* videoScreen=(VIDEO_SCREEN_BEHAV_BLOCK*)sbptr->SBdataptr; + if(videoScreen) + { + videoScreen->destruct_target_sbptr=FindSBWithName(videoScreen->destruct_target_ID); + + } + break; + + } + } + } +} + + +/**************************************************************************************/ +/******************************* STUFF TO DO BEHAVIOURS *******************************/ + + +void ObjectBehaviours(void) +{ + int i; + +#if SupportWindows95 + +#ifdef AVP_DEBUG_VERSION + for (i=0; iSBdptr) + { + int j = i+1; + + for (; jSBdptr == ActiveStBlockList[j]->SBdptr) + { + GLOBALASSERT (0); + } + } + } + } +#endif + +#endif + + RequestEnvChangeViaLift = 0; + + i = 0; + + while(i < NumActiveStBlocks) + { + ExecuteBehaviour(ActiveStBlockList[i++]); + } + +} + + +void ExecuteBehaviour(STRATEGYBLOCK* sbptr) +{ + GLOBALASSERT(sbptr); + + switch(sbptr->I_SBtype) + { + case I_BehaviourInanimateObject: + InanimateObjectBehaviour(sbptr); + break; + + case I_BehaviourProximityDoor: + DoorProxBehaveFun(sbptr); + break; + + case I_BehaviourBinarySwitch: + BinarySwitchBehaveFun(sbptr); + break; + + case I_BehaviourLiftDoor: + LiftDoorBehaveFun(sbptr); + break; + + case I_BehaviourLift: + LiftBehaveFun(sbptr); + break; + + case I_BehaviourGenerator: + GeneratorBehaviour(sbptr); + break; + + case I_BehaviourMarinePlayer: + PlayerBehaviour(sbptr); + break; + + case I_BehaviourAlien: + AlienBehaviour(sbptr); + break; + + case I_BehaviourSwitchDoor: + SwitchDoorBehaviour(sbptr); + break; + + case I_BehaviourLinkSwitch: + LinkSwitchBehaveFun(sbptr); + break; + + case I_BehaviourPlatform: + PlatformLiftBehaviour(sbptr); + break; + + case I_BehaviourSimpleAnimation: + SimpleAnimBehaveFun(sbptr); + break; + + case I_BehaviourAutoGun: + AutoGunBehaveFun(sbptr); + break; + + + case I_BehaviourFragmentationGrenade: + case I_BehaviourGrenade: + GrenadeBehaviour(sbptr); + break; + case I_BehaviourMolotov: + MolotovBehaviour(sbptr); + break; + + case I_BehaviourProximityGrenade: + ProximityGrenadeBehaviour(sbptr); + break; + + case I_BehaviourFlareGrenade: + FlareGrenadeBehaviour(sbptr); + break; + + case I_BehaviourClusterGrenade: + ClusterGrenadeBehaviour(sbptr); + break; + + case I_BehaviourFrisbee: + FrisbeeBehaviour(sbptr); + break; + + case I_BehaviourRocket: + RocketBehaviour(sbptr); + break; + + case I_BehaviourPulseGrenade: + PulseGrenadeBehaviour(sbptr); + break; + + case I_BehaviourFaceHugger: + FacehuggerBehaviour(sbptr); + break; + + case I_BehaviourPredator: + PredatorBehaviour(sbptr); + break; + + case I_BehaviourXenoborg: + XenoborgBehaviour(sbptr); + break; + + case I_BehaviourQueenAlien: + QueenBehaviour(sbptr); + break; + + case I_BehaviourPredatorAlien: + GLOBALASSERT(0); + //PAQBehaviour(sbptr); + break; + + case I_BehaviourMarine: + MarineBehaviour(sbptr); + break; + + case I_BehaviourSeal: + MarineBehaviour(sbptr); + break; + + + case I_BehaviourHierarchicalFragment: + { + #if 0 + HDEBRIS_BEHAV_BLOCK *hbbptr=(HDEBRIS_BEHAV_BLOCK *)sbptr->SBdataptr; + LOCALASSERT(hbbptr); + if (hbbptr->HModelController.Root_Section->flags§ion_sprays_acid) { + AlienFragFun(sbptr); + } else { + OneShotBehaveFun(sbptr); + } + #else + HierarchicalFragmentBehaviour(sbptr); + #endif + } + break; + case I_BehaviourAlienFragment: + AlienFragFun(sbptr); + break; + + case I_BehaviourFragment: + case I_BehaviourAutoGunMuzzleFlash: + OneShotBehaveFun(sbptr); + break; + + case I_BehaviourOneShotAnim: + OneShot_Anim_BehaveFun(sbptr); + break; + + case I_BehaviourPPPlasmaBolt: + PPPlasmaBoltBehaviour(sbptr); + break; + + case I_BehaviourSpeargunBolt: + SpeargunBoltBehaviour(sbptr); + break; + + case I_BehaviourPredatorEnergyBolt: + PredatorEnergyBoltBehaviour(sbptr); + break; + + case I_BehaviourFrisbeeEnergyBolt: + FrisbeeEnergyBoltBehaviour(sbptr); + break; + + case I_BehaviourXenoborgEnergyBolt: + XenoborgEnergyBoltBehaviour(sbptr); + break; + + case I_BehaviourAlienSpit: + AlienSpitBehaviour(sbptr); + break; + + case I_BehaviourNPCPredatorDisc: + NPCDiscBehaviour(sbptr); + break; + + case I_BehaviourPredatorDisc_SeekTrack: + DiscBehaviour_SeekTrack(sbptr); + break; + + #if 0 + /* KJL 17:07:53 02/24/97 - I've turned these off for now since they + always seem to cause crashes. */ + case I_BehaviourFlameProjectile: + FlameProjectileFunction(sbptr); + break; + #endif + + case I_BehaviourDatabase: + /* KJL 16:30:21 03/13/97 - no behaviour required */ + break; + + case I_BehaviourNetGhost: + NetGhostBehaviour(sbptr); + break; + + case I_BehaviourSmokeGenerator: + SmokeGeneratorBehaviour(sbptr); + break; + + case I_BehaviourXenoborgMorphRoom: + XenoMorphRoomBehaviour (sbptr); + break; + + case I_BehaviourLightFX: + LightFXBehaveFun (sbptr); + break; + + case I_BehaviourPlacedSound: + { + SoundBehaveFun (sbptr); + break; + } + case I_BehaviourTrackObject: + { + TrackObjectBehaveFun (sbptr); + break; + } + case I_BehaviourFan: + { + FanBehaveFun (sbptr); + break; + } + case I_BehaviourNetCorpse: + { + CorpseBehaveFun(sbptr); + break; + } + case I_BehaviourRubberDuck: + { + RubberDuckBehaviour(sbptr); + break; + } + case I_BehaviourPlacedHierarchy : + { + PlacedHierarchyBehaveFun(sbptr); + break; + } + + case I_BehaviourPlacedLight: + PlacedLightBehaviour(sbptr); + break; + + case I_BehaviourVideoScreen: + VideoScreenBehaviour(sbptr); + break; + + case I_BehaviourPowerCable: + PowerCableBehaveFun(sbptr); + break; + + case I_BehaviourDeathVolume: + DeathVolumeBehaveFun(sbptr); + break; + + case I_BehaviourSelfDestruct: + SelfDestructBehaveFun(sbptr); + break; + + case I_BehaviourGrapplingHook: + GrapplingHookBehaviour(sbptr); + break; + + case I_BehaviourDummy: + DummyBehaviour(sbptr); + break; + + case I_BehaviourParticleGenerator: + ParticleGeneratorBehaveFun(sbptr); + break; + default: + break; + } +} + + + + + +/********************** OTHER FUNCTIONS **********************/ + + + + + +/************************** DOOR FUNCTIONS *************************/ + + + + +/*------------Patrick 6/1/97-------------------- + I have made some significant modifications to + the proximity door behaviour function, to + facilitate opening and closing by 'far'aliens + ----------------------------------------------*/ + +void UnlockThisProxdoor(STRATEGYBLOCK* sbptr) +{ + PROXDOOR_BEHAV_BLOCK *doorbhv; + MORPHCTRL *mctrl; + DISPLAYBLOCK* dptr; + MODULE *mptr; + + GLOBALASSERT(sbptr); + doorbhv = (PROXDOOR_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((doorbhv->bhvr_type == I_BehaviourProximityDoor)); + mctrl = doorbhv->PDmctrl; + GLOBALASSERT(mctrl); + mptr = sbptr->SBmoptr; + GLOBALASSERT(mptr); + dptr = sbptr->SBdptr; + + /* Unlock door! */ + doorbhv->door_locked = 0; + +} + +static void DoorProxBehaveFun(STRATEGYBLOCK* sbptr) +{ + PROXDOOR_BEHAV_BLOCK *doorbhv; + MORPHCTRL *mctrl; + DISPLAYBLOCK* dptr; + MODULE *mptr; + BOOL open_door = No; + + GLOBALASSERT(sbptr); + doorbhv = (PROXDOOR_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((doorbhv->bhvr_type == I_BehaviourProximityDoor)); + mctrl = doorbhv->PDmctrl; + GLOBALASSERT(mctrl); + mptr = sbptr->SBmoptr; + GLOBALASSERT(mptr); + dptr = sbptr->SBdptr; + + + /* update morphing.... */ + UpdateMorphing(mctrl); + + /*-----------------Patrick 29/4/97------------------------- + Little patch for networking: doors should run the + AnythingNearProxDoor() test even when they are not visible + ----------------------------------------------------------*/ + + if(AvP.Network==I_No_Network) + { + /* if door is visible check for proximity of player, aliens, and whatever... */ + if(dptr) open_door = AnythingNearProxDoor(mptr,doorbhv); + } + else open_door = AnythingNearProxDoor(mptr,doorbhv); + + + + /* check for an alien trigger: + NB Door could be either visible or not when triggered */ + if ((doorbhv->alienTrigger == 1)||((doorbhv->marineTrigger == 1))) + { + open_door = Yes; + if (doorbhv->marineTrigger==1) { + doorbhv->triggeredByMarine = 1; + } + doorbhv->alienTimer = DOOR_FAROPENTIME; + doorbhv->alienTrigger = 0; + doorbhv->marineTrigger = 0; + } + + if (doorbhv->door_locked) + { + open_door = No; + } + + switch(doorbhv->door_state) + { + case I_door_opening: + { + mptr->m_flags |= m_flag_open; + if(mctrl->ObMorphFlags & mph_flag_finished) + { + if (doorbhv->SoundHandle!=SOUND_NOACTIVEINDEX) + { + if (doorbhv->triggeredByMarine) { + Sound_Play(SID_DOOREND,"dpm",&mptr->m_world,doorbhv->doorType); + } else { + Sound_Play(SID_DOOREND,"dp",&mptr->m_world,doorbhv->doorType); + } + Sound_Stop(doorbhv->SoundHandle); + } + + doorbhv->door_state = I_door_open; + } + break; + } + + case I_door_closing: + { + if(open_door) + { + + if(dptr) + { + OpenDoor(mctrl, doorbhv->door_opening_speed); + if (doorbhv->SoundHandle==SOUND_NOACTIVEINDEX) + { + if (doorbhv->triggeredByMarine) { + Sound_Play(SID_DOORSTART,"dpm",&mptr->m_world,doorbhv->doorType); + Sound_Play(SID_DOORMID,"delpm",&mptr->m_world,&doorbhv->SoundHandle,doorbhv->doorType); + } else { + Sound_Play(SID_DOORSTART,"dp",&mptr->m_world,doorbhv->doorType); + Sound_Play(SID_DOORMID,"delp",&mptr->m_world,&doorbhv->SoundHandle,doorbhv->doorType); + } + } + } + else + { + OpenDoor(mctrl, DOOR_OPENFASTSPEED); + } + + doorbhv->door_state = I_door_opening; + } + else if(mctrl->ObMorphFlags & mph_flag_finished) + { + if (doorbhv->SoundHandle!=SOUND_NOACTIVEINDEX) + { + if (doorbhv->triggeredByMarine) { + Sound_Play(SID_DOOREND,"dpm",&mptr->m_world,doorbhv->doorType); + } else { + Sound_Play(SID_DOOREND,"dp",&mptr->m_world,doorbhv->doorType); + } + Sound_Stop(doorbhv->SoundHandle); + } + + doorbhv->door_state = I_door_closed; + mptr->m_flags &= ~m_flag_open; + } + + break; + } + + case I_door_open: + { + mptr->m_flags |= m_flag_open; + if(!open_door) + { + + if(dptr) + { + if (doorbhv->triggeredByMarine) { + Sound_Play(SID_DOORSTART,"dpm",&mptr->m_world,doorbhv->doorType); + Sound_Play(SID_DOORMID,"delpm",&mptr->m_world,&doorbhv->SoundHandle,doorbhv->doorType); + } else { + Sound_Play(SID_DOORSTART,"dp",&mptr->m_world,doorbhv->doorType); + Sound_Play(SID_DOORMID,"delp",&mptr->m_world,&doorbhv->SoundHandle,doorbhv->doorType); + } + doorbhv->alienTimer = 0; + CloseDoor(mctrl,doorbhv->door_closing_speed); + doorbhv->door_state = I_door_closing; + } + else + { + doorbhv->alienTimer -= NormalFrameTime; + if(!(doorbhv->alienTimer>0)) + { + doorbhv->alienTimer = 0; + CloseDoor(mctrl, DOOR_CLOSEFASTSPEED); + doorbhv->door_state = I_door_closing; + } + } + } + + break; + } + + case I_door_closed: + { + mptr->m_flags &= ~m_flag_open; + if(open_door) + { + if(dptr) + { + if (doorbhv->triggeredByMarine) { + Sound_Play(SID_DOORSTART,"dpm",&mptr->m_world,doorbhv->doorType); + Sound_Play(SID_DOORMID,"delpm",&mptr->m_world,&doorbhv->SoundHandle,doorbhv->doorType); + } else { + Sound_Play(SID_DOORSTART,"dp",&mptr->m_world,doorbhv->doorType); + Sound_Play(SID_DOORMID,"delp",&mptr->m_world,&doorbhv->SoundHandle,doorbhv->doorType); + } + OpenDoor(mctrl,doorbhv->door_opening_speed); + } + else OpenDoor(mctrl, DOOR_OPENFASTSPEED); + doorbhv->door_state = I_door_opening; + mptr->m_flags |= m_flag_open; + } else { + doorbhv->triggeredByMarine = 0; + } + + break; + } + + default: + LOCALASSERT(1==0); + } +} + + +void OpenDoor(MORPHCTRL *mctrl, int speed) +{ + LOCALASSERT(mctrl); + + mctrl->ObMorphFlags = mph_flag_play; + mctrl->ObMorphFlags |= mph_flag_noloop; + mctrl->ObMorphFlags |= mph_flag_reverse; + mctrl->ObMorphSpeed = speed; +} + + +void CloseDoor(MORPHCTRL *mctrl, int speed) +{ + LOCALASSERT(mctrl); + + mctrl->ObMorphFlags = mph_flag_play; + mctrl->ObMorphFlags |= mph_flag_noloop; + mctrl->ObMorphFlags &= ~mph_flag_reverse; + mctrl->ObMorphSpeed = speed; +} + +/*---------------Patrick 6/1/97------------------- + Sorry, but I can't think of anything better than + searching the entire sb list for any object that + might trigger a door.... + ------------------------------------------------*/ +static int AnythingNearProxDoor(MODULE *doorModulePtr,PROXDOOR_BEHAV_BLOCK *doorbhv) +{ + /* KJL 18:06:59 19/02/98 - I've rewritten this check so that it can cope with very tall doors. */ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + + int sbIndex = 0; + STRATEGYBLOCK *sbPtr; + DYNAMICSBLOCK *dynPtr; + DISPLAYBLOCK *dPtr; + int retval; + + int maxY; + int minY; + int maxX; + int minX; + int maxZ; + int minZ; + + if (doorModulePtr->m_flags & MODULEFLAG_HORIZONTALDOOR) + { + maxY = doorModulePtr->m_world.vy + DOOR_OPENDISTANCE/2; + minY = doorModulePtr->m_world.vy - DOOR_OPENDISTANCE/2; + maxX = doorModulePtr->m_world.vx + doorModulePtr->m_maxx + DOOR_OPENDISTANCE/2; + minX = doorModulePtr->m_world.vx + doorModulePtr->m_minx - DOOR_OPENDISTANCE/2; + maxZ = doorModulePtr->m_world.vz + doorModulePtr->m_maxz + DOOR_OPENDISTANCE/2; + minZ = doorModulePtr->m_world.vz + doorModulePtr->m_minz - DOOR_OPENDISTANCE/2; + } + else + { + maxY = doorModulePtr->m_world.vy + doorModulePtr->m_maxy; + minY = doorModulePtr->m_world.vy + doorModulePtr->m_miny; + maxX = doorModulePtr->m_world.vx + DOOR_OPENDISTANCE; + minX = doorModulePtr->m_world.vx - DOOR_OPENDISTANCE; + maxZ = doorModulePtr->m_world.vz + DOOR_OPENDISTANCE; + minZ = doorModulePtr->m_world.vz - DOOR_OPENDISTANCE; + } + /* loop thro' the strategy block list... + looking for triggerable objects (please feel free to add any + sensible object types) */ + retval=No; + + while(sbIndex < NumActiveStBlocks) + { + sbPtr = ActiveStBlockList[sbIndex++]; + dynPtr = sbPtr->DynPtr; + dPtr = sbPtr->SBdptr; + + if( (dynPtr)&&(dPtr)&& + ((sbPtr->I_SBtype == I_BehaviourAlien)|| + (sbPtr->I_SBtype == I_BehaviourMarinePlayer)|| + (sbPtr->I_SBtype == I_BehaviourPredatorPlayer)|| + (sbPtr->I_SBtype == I_BehaviourAlienPlayer)|| + (sbPtr->I_SBtype == I_BehaviourPredator)|| + (sbPtr->I_SBtype == I_BehaviourXenoborg)|| + (sbPtr->I_SBtype == I_BehaviourMarine)|| + (sbPtr->I_SBtype == I_BehaviourSeal)|| + (sbPtr->I_SBtype == I_BehaviourQueenAlien)|| + (sbPtr->I_SBtype == I_BehaviourPredatorAlien)|| + (sbPtr->I_SBtype == I_BehaviourFaceHugger)|| + (sbPtr->I_SBtype == I_BehaviourGrenade)|| + (sbPtr->I_SBtype == I_BehaviourRocket)|| + (sbPtr->I_SBtype == I_BehaviourFrisbee)|| + (sbPtr->I_SBtype == I_BehaviourPulseGrenade)|| + (sbPtr->I_SBtype == I_BehaviourProximityGrenade)|| + (sbPtr->I_SBtype == I_BehaviourNetGhost)|| +// (sbPtr->I_SBtype == I_BehaviourFlareGrenade)|| + (sbPtr->I_SBtype == I_BehaviourFragmentationGrenade)|| + (sbPtr->I_SBtype == I_BehaviourPredatorDisc_SeekTrack)|| + (sbPtr->I_SBtype == I_BehaviourNetCorpse)|| + (sbPtr->I_SBtype == I_BehaviourHierarchicalFragment)|| + (sbPtr->I_SBtype == I_BehaviourNPCPredatorDisc)) + ) + { + if (dynPtr->Position.vy > minY && dynPtr->Position.vy < maxY) + { + if (dynPtr->Position.vx > minX && dynPtr->Position.vx < maxX) + { + if (dynPtr->Position.vz > minZ && dynPtr->Position.vz < maxZ) + { + if ((sbPtr->I_SBtype==I_BehaviourMarine) + ||(sbPtr->I_SBtype==I_BehaviourSeal)) { + doorbhv->triggeredByMarine = 1; + } + retval=Yes; + } + } + } + } + } + + return(retval); + +} + + + +static void SimpleAnimBehaveFun(STRATEGYBLOCK* sbptr) +{ + /* this just copie the SB taccontrol into the + display bloxk if it didnt already have one*/ + + SIMPLE_ANIM_BEHAV_BLOCK *sanimbhv; + DISPLAYBLOCK* dptr; + + sanimbhv = (SIMPLE_ANIM_BEHAV_BLOCK*)(sbptr->SBdataptr); + + GLOBALASSERT(sanimbhv->bhvr_type == I_BehaviourSimpleAnimation); + + dptr = sbptr->SBdptr; + + if(dptr) + { + if(!dptr->ObTxAnimCtrlBlks) + { + dptr->ObTxAnimCtrlBlks = sanimbhv->tacbSimple; + } + } +} + + +/********************* SUPPORT FUNCTION ***********************/ +/* + these set the reqest state in a strategy block +*/ + +void RequestState(STRATEGYBLOCK* sbptr, int message, STRATEGYBLOCK * SBRequester) +{ + //lowest bit of message corresponds to old on/off state + //the rest is extended information ,the interpretation of which depends on the receiving strategy + BOOL state=message & 1; + if(!sbptr) + { + return; + } + //GLOBALASSERT(sbptr); + + if(sbptr->SBflags.destroyed_but_preserved) + { + //target doesn't exist anymore so ignore request. + return; + } + + #if DB_LEVEL >=3 + { + //add details of request to logfile + extern int GlobalFrameCounter; + const char* name1=0; + const char* name2="ANON"; + if(sbptr) name1=sbptr->name; + if(SBRequester) name2=SBRequester->name; + db_logf3(("Frame %d : %s sent %s message to %s%s",GlobalFrameCounter,name2, state ? "'on'" : "'off'",name1,(message>>1)? " with extra message data" : "")); + } + #endif + + + switch (sbptr->I_SBtype) + { + case I_BehaviourNetCorpse: + /* Ulp... */ + break; + case I_BehaviourBinarySwitch: + { + // 0 = rest state + // 1 = unusual state + + BINARY_SWITCH_BEHAV_BLOCK *bs_bhv; + bs_bhv = (BINARY_SWITCH_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((bs_bhv->bhvr_type == I_BehaviourBinarySwitch)); + + if(state) + bs_bhv->request = I_request_on; + else + bs_bhv->request = I_request_off; + + break; + } + + case I_BehaviourLinkSwitch: + { + LINK_SWITCH_BEHAV_BLOCK *bs_bhv; + + // 0 = rest state + // 1 = unusual state + + bs_bhv = (LINK_SWITCH_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((bs_bhv->bhvr_type == I_BehaviourLinkSwitch)); + + if (SBRequester) if (SBRequester->I_SBtype == I_BehaviourBinarySwitch || + SBRequester->I_SBtype == I_BehaviourLinkSwitch) + { + //if the request has come from one of the linked switches , ignore it + int i; + for(i=0;inum_linked_switches;i++) + { + if(bs_bhv->lswitch_list[i].bswitch==SBRequester) + { + break; + } + } + if(inum_linked_switches) + { + break; + } + } + + + if(state) + bs_bhv->request = I_request_on; + else + bs_bhv->request = I_request_off; + + break; + } + + case I_BehaviourProximityDoor: + { + PROXDOOR_BEHAV_BLOCK *door_bhv; + MORPHCTRL *mctrl; + + door_bhv = (PROXDOOR_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((door_bhv->bhvr_type == I_BehaviourProximityDoor)); + mctrl = door_bhv->PDmctrl; + GLOBALASSERT(mctrl); + + //request previously open and closed door.Now it locks or unlocks it. + if(state == 1) + { + door_bhv->door_locked = 0; + } + else + { + door_bhv->door_locked = 1; + } + break; + } + + case I_BehaviourLiftDoor: + { + LIFT_DOOR_BEHAV_BLOCK *door_bhv; + door_bhv = (LIFT_DOOR_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((door_bhv->bhvr_type == I_BehaviourLiftDoor)); + + if(state == 1) + door_bhv->request_state = I_door_open; + else + door_bhv->request_state = I_door_closed; + + break; + } + + case I_BehaviourSwitchDoor: + { + SWITCH_DOOR_BEHAV_BLOCK *door_bhv; + door_bhv = (SWITCH_DOOR_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((door_bhv->myBehaviourType == I_BehaviourSwitchDoor)); + + if(state == 1) door_bhv->requestOpen = 1; + else door_bhv->requestClose = 1; + break; + } + + case I_BehaviourLift: + { + LIFT_BEHAV_BLOCK *lift_bhv; + LIFT_STATION *lift_stn; + GLOBALASSERT(sbptr); + lift_bhv = (LIFT_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((lift_bhv->bhvr_type == I_BehaviourLift)); + lift_stn = &lift_bhv->lift_station; + GLOBALASSERT(lift_stn); + + if(state == 1) + lift_stn->called = 1; + else + lift_stn->called = 0; + + break; + } + + case I_BehaviourPlatform: + { + + ((PLATFORMLIFT_BEHAVIOUR_BLOCK*)sbptr->SBdataptr)->Enabled = state; + + break; + } + + case I_BehaviourAutoGun: + { + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + agunStatusPointer = (AUTOGUN_STATUS_BLOCK*)sbptr->SBdataptr; + + if ((agunStatusPointer->behaviourState==I_inactive)&&(state==1)) { + agunStatusPointer->behaviourState=I_tracking; + } else if ((agunStatusPointer->behaviourState==I_tracking)&&(state==0)) { + agunStatusPointer->behaviourState=I_inactive; + Sound_Play(SID_SENTRYGUN_SHUTDOWN,"d",&sbptr->DynPtr->Position); + } + + break; + } + + case I_BehaviourGenerator: + { + ((GENERATOR_BLOCK*)sbptr->SBdataptr)->Active = state; + break; + } + + case I_BehaviourLightFX: + { + LIGHT_FX_BEHAV_BLOCK * lfxbb = (LIGHT_FX_BEHAV_BLOCK *)sbptr->SBdataptr; + + if (lfxbb->type == LFX_Switch) + { + switch (lfxbb->current_state) + { + + case LFXS_LightOn: + { + if(state==0) + { + lfxbb->current_state = LFXS_LightFadingDown; + lfxbb->timer = 0; + } + break; + } + + case LFXS_LightOff: + { + if(state==1) + { + lfxbb->current_state = LFXS_LightFadingUp; + lfxbb->timer = 0; + } + break; + } + + case LFXS_LightFadingUp: + { + if(state==0) + { + lfxbb->timer = ONE_FIXED - lfxbb->timer; + lfxbb->current_state = LFXS_LightFadingDown; + } + break; + } + + case LFXS_LightFadingDown: + { + if(state==1) + { + lfxbb->timer = ONE_FIXED - lfxbb->timer; + lfxbb->current_state = LFXS_LightFadingUp; + } + break; + } + + default: + { + GLOBALASSERT (0 == "Light FX state not supported"); + break; + } + } + } + else if (lfxbb->type == LFX_FlickySwitch) + { + switch (lfxbb->current_state) + { + + case LFXS_LightOn: + { + if(state==0) + { + lfxbb->current_state = LFXS_LightFadingDown; + lfxbb->timer = 0; + } + break; + } + + case LFXS_LightOff: + { + if(state==1) + { + lfxbb->current_state = LFXS_LightFadingUp; + lfxbb->timer = 0; + } + break; + } + + case LFXS_LightFadingUp: + { + if(state==0) + { + lfxbb->multiplier = lfxbb->timer; + lfxbb->timer = ONE_FIXED - lfxbb->timer; + lfxbb->current_state = LFXS_LightFadingDown; + } + break; + } + + case LFXS_LightFadingDown: + { + if(state==1) + { + lfxbb->timer = ONE_FIXED - lfxbb->timer; + lfxbb->current_state = LFXS_LightFadingUp; + } + break; + } + + default: + { + GLOBALASSERT (0 == "Light FX state not supported"); + break; + } + } + } + else if(lfxbb->type==LFX_RandomFlicker) + { + switch (lfxbb->current_state) + { + case LFXS_Flicking: + case LFXS_NotFlicking: + if(state==0) + { + //switch light off + lfxbb->current_state = LFXS_LightOff; + } + break; + + case LFXS_LightOff : + if(state==1) + { + //switch light on + lfxbb->current_state = LFXS_Flicking; + } + break; + + + + } + } + + + break; + } + case I_BehaviourMissionComplete: + { + SendRequestToMissionStrategy(sbptr,state,message>>1); + + break; + } + case I_BehaviourMessage: + { + SendRequestToMessageStrategy(sbptr,state,message>>1); + + break; + } + + case I_BehaviourTrackObject: + { + + TRACK_OBJECT_BEHAV_BLOCK *to_bhv; + to_bhv = (TRACK_OBJECT_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((to_bhv->bhvr_type == I_BehaviourTrackObject)); + + if(state) + { + switch(message>>1) + { + case 0: + to_bhv->request = track_request_start; + break; + case 1: + to_bhv->request = track_request_startforward; + break; + case 2: + to_bhv->request = track_request_startbackward; + break; + } + } + else + to_bhv->request = track_request_stop; + + break; + } + + case I_BehaviourFan: + { + + FAN_BEHAV_BLOCK *f_bhv; + f_bhv = (FAN_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((f_bhv->bhvr_type == I_BehaviourFan)); + + if(state) + f_bhv->state = fan_state_go; + else + f_bhv->state = fan_state_stop; + + break; + } + + case I_BehaviourPlacedSound: + { + if(state) + StartPlacedSoundPlaying(sbptr); + else + StopPlacedSoundPlaying(sbptr); + break; + } + + case I_BehaviourInanimateObject: + { + SendRequestToInanimateObject(sbptr,state,message>>1); + break; + } + + case I_BehaviourPlacedHierarchy : + { + SendRequestToPlacedHierarchy(sbptr,state,message>>1); + } + break; + + case I_BehaviourPlacedLight: + { + SendRequestToPlacedLight(sbptr,state,message>>1); + + break; + } + case I_BehaviourAlien: + { + ALIEN_STATUS_BLOCK *alienStatusPointer; + alienStatusPointer = (ALIEN_STATUS_BLOCK*)sbptr->SBdataptr; + + if (alienStatusPointer->BehaviourState==ABS_Dormant) { + Alien_Awaken(sbptr); + } + break; + } + case I_BehaviourFaceHugger: + { + FACEHUGGER_STATUS_BLOCK *facehuggerStatusPointer; + + facehuggerStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbptr->SBdataptr); + LOCALASSERT(facehuggerStatusPointer); + + if (facehuggerStatusPointer->nearBehaviourState==FHNS_Floating) { + Wake_Hugger(sbptr); + } + break; + } + case I_BehaviourXenoborg: + { + XENO_STATUS_BLOCK *xenoStatusPointer; + xenoStatusPointer = (XENO_STATUS_BLOCK*)sbptr->SBdataptr; + + if (state) { + if (xenoStatusPointer->behaviourState==XS_Inactive) { + Xeno_Enter_PowerUp_State(sbptr); + } + } else { + if (xenoStatusPointer->behaviourState!=XS_Inactive) { + Xeno_Enter_PowerDown_State(sbptr); + } + } + break; + } + + case I_BehaviourDormantPredator : + { + if(state) + { + ActivateDormantPredator(sbptr); + } + break; + } + case I_BehaviourPredator : + //do nothing + //can't assert for this one since it might previously have been a dormant predator + break; + + case I_BehaviourMarine : + { + SendRequestToMarine(sbptr,state,message>>1); + } + break; + + case I_BehaviourDeathVolume: + { + + DEATH_VOLUME_BEHAV_BLOCK *dv_bhv; + dv_bhv = (DEATH_VOLUME_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((dv_bhv->bhvr_type == I_BehaviourDeathVolume)); + + dv_bhv->active=state; + + break; + } + case I_BehaviourSelfDestruct: + { + + SELF_DESTRUCT_BEHAV_BLOCK *sd_bhv; + sd_bhv = (SELF_DESTRUCT_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((sd_bhv->bhvr_type == I_BehaviourSelfDestruct)); + + sd_bhv->active=state; + + break; + } + case I_BehaviourParticleGenerator: + { + SendRequestToParticleGenerator(sbptr,state,message>>1); + + break; + } + default: + { + GLOBALASSERT(2<1); + } + } +} + + +BOOL GetState(STRATEGYBLOCK* sbptr) +{ + GLOBALASSERT(sbptr); + + switch (sbptr->I_SBtype) + { + case I_BehaviourBinarySwitch: + { + // 0 = rest state + // 1 = unusual state + + BINARY_SWITCH_BEHAV_BLOCK *bs_bhv; + bs_bhv = (BINARY_SWITCH_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((bs_bhv->bhvr_type == I_BehaviourBinarySwitch)); + + return((BOOL)bs_bhv->state); + + break; + } + case I_BehaviourLinkSwitch: + { + // 0 = rest state + // 1 = unusual state + + LINK_SWITCH_BEHAV_BLOCK *bs_bhv; + bs_bhv = (LINK_SWITCH_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((bs_bhv->bhvr_type == I_BehaviourLinkSwitch)); + + return((BOOL)bs_bhv->state); + + break; + } + case I_BehaviourProximityDoor: + { + PROXDOOR_BEHAV_BLOCK *door_bhv; + door_bhv = (PROXDOOR_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((door_bhv->bhvr_type == I_BehaviourProximityDoor)); + + // returns true only when fully open + + if(door_bhv->door_state == I_door_open) + return((BOOL)1); + else + return((BOOL)0); + + break; + } + case I_BehaviourSwitchDoor: + { + /* returns true if fully open (DO NOT CHANGE THIS) */ + SWITCH_DOOR_BEHAV_BLOCK *door_bhv; + door_bhv = (SWITCH_DOOR_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT(door_bhv->myBehaviourType == I_BehaviourSwitchDoor); + + if(door_bhv->doorState == I_door_open) return((BOOL)1); + else return((BOOL)0); + break; + } + case I_BehaviourLiftDoor: + { + LIFT_DOOR_BEHAV_BLOCK *door_bhv; + door_bhv = (LIFT_DOOR_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((door_bhv->bhvr_type == I_BehaviourLiftDoor)); + + // returns true only when fully open so that the lift + // dosn't start to move when we can still see out + + if(door_bhv->door_state == I_door_closed) + return((BOOL)0); + else + return((BOOL)1); + + break; + } + case I_BehaviourLift: + { + LIFT_BEHAV_BLOCK *lift_bhv; + LIFT_STATION *lift_stn; + GLOBALASSERT(sbptr); + lift_bhv = (LIFT_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((lift_bhv->bhvr_type == I_BehaviourLift)); + lift_stn = &lift_bhv->lift_station; + GLOBALASSERT(lift_stn); + + return(lift_stn->called); + + break; + } + default: + GLOBALASSERT(2<1); + } + + return((BOOL)0); +} + + + + +DISPLAYBLOCK *MakeObject(AVP_BEHAVIOUR_TYPE bhvr, VECTORCH *positionPtr) +{ + // This function creates the specified object, fully + // initialized, WITHOUT a modulemapblock into which + // we can collapse it again if required, and a valid + // strategyblock, + + extern int NumActiveBlocks; + + DISPLAYBLOCK *dptr; + STRATEGYBLOCK *sptr; + MODULEMAPBLOCK *mmbptr; + MODULE m_temp; + //TXACTRLBLK *taPtr; + + if (NumActiveBlocks >= maxobjects) return (DISPLAYBLOCK *)NULL; + if (NumActiveStBlocks >= maxstblocks) return (DISPLAYBLOCK *)NULL; + + // 1. Set up shape data BEFORE making the displayblock, + // since "AllocateModuleObject()" will fill in shapeheader + // information and extent data + + mmbptr = &TempModuleMap; + + switch (bhvr) + { + case I_BehaviourAutoGunMuzzleFlash: + { + CreateShapeInstance(mmbptr,"Sntrymuz"); + break; + } + + case I_BehaviourRocket: + { + CreateShapeInstance(mmbptr,"missile"); + break; + } + + case I_BehaviourFrisbee: + case I_BehaviourNPCPredatorDisc: + case I_BehaviourPredatorDisc_SeekTrack: + { + //CreateShapeInstance(mmbptr,"disk@hnpcpredator"); + CreateShapeInstance(mmbptr,"Shell"); + break; + } + + case I_BehaviourPulseGrenade: /* need a new shape */ + case I_BehaviourGrenade: + { + CreateShapeInstance(mmbptr,"Shell"); + break; + } + case I_BehaviourFragmentationGrenade: + { + CreateShapeInstance(mmbptr,"Frag"); + break; + } + case I_BehaviourClusterGrenade: + { + CreateShapeInstance(mmbptr,"Cluster"); + break; + } + case I_BehaviourProximityGrenade: + { + CreateShapeInstance(mmbptr,"Proxmine"); + break; + } + + + case I_BehaviourFlareGrenade: + { + CreateShapeInstance(mmbptr,"Flare"); + break; + } + + case I_BehaviourSpeargunBolt: + { + CreateShapeInstance(mmbptr,"spear"); + break; + } + case I_BehaviourPPPlasmaBolt: + case I_BehaviourFrisbeeEnergyBolt: + case I_BehaviourPredatorEnergyBolt: + case I_BehaviourXenoborgEnergyBolt: + { + //uses special effect instead of a shape + mmbptr->MapShape = 0; + mmbptr->MapType = MapType_Default; +// CreateShapeInstance(mmbptr,"Plasbolt"); + CreateShapeInstance(mmbptr,"Shell"); + + break; + } + case I_BehaviourAlienSpit: + { + CreateShapeInstance(mmbptr,"Spit"); + break; + } + + case I_BehaviourTest: + default: + { + // Don't call this function for undefined types + GLOBALASSERT (1 == 0); + break; + } + } + + // And allocate the modulemapblock object + + m_temp.m_numlights = 0; + m_temp.m_lightarray = NULL; + m_temp.m_mapptr = mmbptr; + m_temp.m_sbptr = (STRATEGYBLOCK*)NULL; + AllocateModuleObject(&m_temp); + + dptr = m_temp.m_dptr; + + if (dptr == 0) return(DISPLAYBLOCK*)NULL; + + dptr->ObMyModule = NULL; /* Module that created us */ + dptr->ObWorld = *positionPtr; + + sptr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dptr); + + if (sptr == 0) return(DISPLAYBLOCK*)NULL; + + // 2. NOW set up the strategyblock-specific fields for + // the new displayblock. We won't go through the "AttachNew + // StrategyBlock" and "AssignRunTimeBehaviours" pair, since + // the first switches on ObShape and the second on bhvr; + // but, in this case, there isn't a particular connection + // between them. + + sptr->I_SBtype = bhvr; + + switch (bhvr) + { + case I_BehaviourAutoGunMuzzleFlash: + // but soon it will be an animated sequence + { + sptr->SBdataptr = (ONE_SHOT_BEHAV_BLOCK *) AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK )); + + if (sptr->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(sptr); + return (DISPLAYBLOCK*)NULL; + } + + ((ONE_SHOT_BEHAV_BLOCK * ) sptr->SBdataptr)->counter = ONE_FIXED/10; + + /* KJL 17:23:22 11/26/96 - here's a little something to give a random orientation */ + { + EULER orientation; + orientation.EulerX = 0; + orientation.EulerY = 0; + orientation.EulerZ = FastRandom()&4095; + + CreateEulerMatrix(&orientation, &dptr->ObMat); + TransposeMatrixCH(&dptr->ObMat); + } + + AddLightingEffectToObject(dptr,LFX_MUZZLEFLASH); + + break; + } + + + case I_BehaviourFrisbee: + case I_BehaviourRocket: + case I_BehaviourPulseGrenade: + case I_BehaviourGrenade: + case I_BehaviourFlareGrenade: + case I_BehaviourFragmentationGrenade: + case I_BehaviourClusterGrenade: + case I_BehaviourProximityGrenade: + case I_BehaviourSpeargunBolt: + case I_BehaviourPPPlasmaBolt: + case I_BehaviourFrisbeeEnergyBolt: + case I_BehaviourPredatorEnergyBolt: + case I_BehaviourXenoborgEnergyBolt: + case I_BehaviourAlienSpit: + case I_BehaviourNPCPredatorDisc: + case I_BehaviourPredatorDisc_SeekTrack: + { + AssignNewSBName(sptr); + break; + } + + case I_BehaviourTest: + break; + + default: + + // Don't call this function for undefined + // types + + GLOBALASSERT (1 == 0); + break; + } + return dptr; +} + + +// this is seperate so that it can be called during env changes +void RemoveBehaviourStrategy(STRATEGYBLOCK* sbptr) +{ + GLOBALASSERT(sbptr); + + /* Andy 16/8/97 - Updated to cope with partially allocated strategy blocks + We need to check that each allocation has been completed before + trying to deallocate */ + + /* CDF 12/11/96 - Destroys ANY strategyblock. * + * Please maintain... */ + + // this is to check for the sb destroy flag + // only destroy sbs if DoNotRemoveSB = 0 + // and the destroy flag is set + + // first check to see if we need the SB in the next env + // if we do we need to preserve the contents + + if(SBNeededForNextEnv(sbptr)) + { + //we take a copy and preserve everything except our + //ActiveStBlockList copy + + DestroyActiveStrategyBlock(sbptr); + return; + } + + // this notifies the game flow system that an object has been destroyed + + + switch(sbptr->I_SBtype) + { + case I_BehaviourProximityDoor: + { + { + /* patrick 7/7/97: remove sound handle, if we have one*/ + PROXDOOR_BEHAV_BLOCK *doorbhv = (PROXDOOR_BEHAV_BLOCK *)(sbptr->SBdataptr); + if(doorbhv && doorbhv->SoundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(doorbhv->SoundHandle); + } + // Deallocater for the doors hack + if (sbptr->SBmorphctrl && + sbptr->SBmorphctrl->ObMorphHeader && + sbptr->SBmorphctrl->ObMorphHeader->mph_frames) + DeallocateMem( sbptr->SBmorphctrl->ObMorphHeader->mph_frames); + + if (sbptr->SBmorphctrl && + sbptr->SBmorphctrl->ObMorphHeader) + DeallocateMem( sbptr->SBmorphctrl->ObMorphHeader); + + if (sbptr->SBmorphctrl) + DeallocateMem( sbptr->SBmorphctrl); + + break; + } + case I_BehaviourLiftDoor: + { + // Deallocater for the doors hack + { + /* patrick 7/7/97: remove sound handle, if we have one*/ + LIFT_DOOR_BEHAV_BLOCK *doorbhv = (LIFT_DOOR_BEHAV_BLOCK *)(sbptr->SBdataptr); + if(doorbhv && doorbhv->SoundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(doorbhv->SoundHandle); + } + + if (sbptr->SBmorphctrl && + sbptr->SBmorphctrl->ObMorphHeader && + sbptr->SBmorphctrl->ObMorphHeader->mph_frames) + DeallocateMem( sbptr->SBmorphctrl->ObMorphHeader->mph_frames); + + if (sbptr->SBmorphctrl && + sbptr->SBmorphctrl->ObMorphHeader) + DeallocateMem( sbptr->SBmorphctrl->ObMorphHeader); + + if (sbptr->SBmorphctrl) + DeallocateMem( sbptr->SBmorphctrl); + + break; + } + case I_BehaviourSwitchDoor: + { + { + /* patrick 7/7/97: remove sound handle, if we have one*/ + SWITCH_DOOR_BEHAV_BLOCK *doorbhv = (SWITCH_DOOR_BEHAV_BLOCK *)(sbptr->SBdataptr); + if(doorbhv && doorbhv->SoundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(doorbhv->SoundHandle); + } + + if (sbptr->SBmorphctrl && + sbptr->SBmorphctrl->ObMorphHeader && + sbptr->SBmorphctrl->ObMorphHeader->mph_frames) + DeallocateMem( sbptr->SBmorphctrl->ObMorphHeader->mph_frames); + + if (sbptr->SBmorphctrl && + sbptr->SBmorphctrl->ObMorphHeader) + DeallocateMem( sbptr->SBmorphctrl->ObMorphHeader); + + if (sbptr->SBmorphctrl) + DeallocateMem( sbptr->SBmorphctrl); + + break; + } + case I_BehaviourSimpleAnimation: + { + + SIMPLE_ANIM_BEHAV_BLOCK *sanimbhv; + TXACTRLBLK *txactrl; + TXACTRLBLK *txactrl_next; + + sanimbhv = (SIMPLE_ANIM_BEHAV_BLOCK*)(sbptr->SBdataptr); + if (sanimbhv) + { + GLOBALASSERT(sanimbhv->bhvr_type == I_BehaviourSimpleAnimation); + + txactrl_next = sanimbhv->tacbSimple; + while(txactrl_next) + { + txactrl = txactrl_next; + txactrl_next = txactrl->tac_next; + DeallocateMem((void*)txactrl); + } + } + break; + } + case I_BehaviourBinarySwitch: + { + BINARY_SWITCH_BEHAV_BLOCK *bs_bhv; + TXACTRLBLK *txactrl; + TXACTRLBLK *txactrl_next; + + bs_bhv = (BINARY_SWITCH_BEHAV_BLOCK*)(sbptr->SBdataptr); + if (bs_bhv) + { + GLOBALASSERT(bs_bhv->bhvr_type == I_BehaviourBinarySwitch); + + /* Andy 20/8/97: remove sound handle, if we have one*/ + if(bs_bhv->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(bs_bhv->soundHandle); + + if(bs_bhv->bs_track) + { + Reset_Track(bs_bhv->bs_track); + } + + txactrl_next = bs_bhv->bs_tac; + while(txactrl_next) + { + txactrl = txactrl_next; + txactrl_next = txactrl->tac_next; + DeallocateMem((void*)txactrl); + } + if (bs_bhv->target_names) DeallocateMem ((void *)bs_bhv->target_names); + if (bs_bhv->bs_targets) DeallocateMem ((void *)bs_bhv->bs_targets); + if (bs_bhv->request_messages) DeallocateMem ((void *)bs_bhv->request_messages); + + } + break; + } + case I_BehaviourLinkSwitch: + { + LINK_SWITCH_BEHAV_BLOCK *bs_bhv; + TXACTRLBLK *txactrl; + TXACTRLBLK *txactrl_next; + + bs_bhv = (LINK_SWITCH_BEHAV_BLOCK*)(sbptr->SBdataptr); + if (bs_bhv) + { + GLOBALASSERT(bs_bhv->bhvr_type == I_BehaviourLinkSwitch); + + /* Andy 20/8/97: remove sound handle, if we have one*/ + if(bs_bhv->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(bs_bhv->soundHandle); + + if(bs_bhv->ls_track) + { + Reset_Track(bs_bhv->ls_track); + } + + + txactrl_next = bs_bhv->ls_tac; + while(txactrl_next) + { + txactrl = txactrl_next; + txactrl_next = txactrl->tac_next; + DeallocateMem((void*)txactrl); + } + + + if (bs_bhv->ls_targets) DeallocateMem ((void *)bs_bhv->ls_targets); + if (bs_bhv->lswitch_list) DeallocateMem ((void *)bs_bhv->lswitch_list); + } + break; + } + case I_BehaviourLift: + { + LIFT_BEHAV_BLOCK *lift_bhv; + lift_bhv = (LIFT_BEHAV_BLOCK*)(sbptr->SBdataptr); + + if (lift_bhv) + { + GLOBALASSERT(lift_bhv->bhvr_type == I_BehaviourLift); + + /* patrick 7/7//97*/ + if(lift_bhv->lift_control) + { + if(lift_bhv->lift_control->SoundHandle!=SOUND_NOACTIVEINDEX) + Sound_Stop(lift_bhv->lift_control->SoundHandle); + } + + if(lift_bhv->controller) + { + if (lift_bhv->lift_control && lift_bhv->lift_control->lift_stations) + DeallocateMem(lift_bhv->lift_control->lift_stations); + if (lift_bhv->lift_control) + DeallocateMem(lift_bhv->lift_control); + } + } + break; + } + case I_BehaviourAutoGun: + { + AUTOGUN_STATUS_BLOCK *ag_bhv; + + ag_bhv = (AUTOGUN_STATUS_BLOCK*)(sbptr->SBdataptr); + if (ag_bhv) + { + /* patrick 7/7/97*/ + if(ag_bhv->soundHandle!=SOUND_NOACTIVEINDEX) + { + Sound_Stop(ag_bhv->soundHandle); + } + Dispel_HModel(&ag_bhv->HModelController); + + } + break; + } + case I_BehaviourAlien: + { + ALIEN_STATUS_BLOCK *asb; + asb=(ALIEN_STATUS_BLOCK *)(sbptr->SBdataptr); + Dispel_HModel(&asb->HModelController); + } + break; + case I_BehaviourGenerator: + { + break; + } + + case I_BehaviourMarine: + case I_BehaviourSeal: + { + MARINE_STATUS_BLOCK *marineStatusPointer; + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbptr->SBdataptr); + if(marineStatusPointer) + { + Dispel_HModel(&marineStatusPointer->HModelController); + + if(marineStatusPointer->myGunFlash) DestroyActiveObject(marineStatusPointer->myGunFlash); + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(marineStatusPointer->soundHandle); + } + break; + } + case I_BehaviourDummy: + { + DUMMY_STATUS_BLOCK *dummyStatusPointer; + dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(sbptr->SBdataptr); + if(dummyStatusPointer) + { + Dispel_HModel(&dummyStatusPointer->HModelController); + } + break; + } + case I_BehaviourPredatorDisc_SeekTrack: + { + PC_PRED_DISC_BEHAV_BLOCK *bblk; + bblk = (PC_PRED_DISC_BEHAV_BLOCK *)(sbptr->SBdataptr); + if(bblk) + { + if (bblk->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(bblk->soundHandle); + } + + Dispel_HModel(&bblk->HModelController); + + } + break; + } + case I_BehaviourPredatorEnergyBolt: + case I_BehaviourFrisbeeEnergyBolt: + { + CASTER_BOLT_BEHAV_BLOCK *bblk; + bblk = (CASTER_BOLT_BEHAV_BLOCK *)(sbptr->SBdataptr); + if(bblk) + { + if (bblk->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(bblk->soundHandle); + } + } + break; + } + case I_BehaviourFrisbee: + { + FRISBEE_BEHAV_BLOCK *fblk; + fblk = (FRISBEE_BEHAV_BLOCK *)(sbptr->SBdataptr); + if(fblk) + { + if (fblk->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(fblk->soundHandle); + } + + Dispel_HModel(&fblk->HModelController); + + } + break; + } + + case I_BehaviourFaceHugger: + { + FACEHUGGER_STATUS_BLOCK *fhugStatusPointer; + fhugStatusPointer = (FACEHUGGER_STATUS_BLOCK *)(sbptr->SBdataptr); + if(fhugStatusPointer) + { + if(fhugStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(fhugStatusPointer->soundHandle); + } + Dispel_HModel(&fhugStatusPointer->HModelController); + break; + } + + case I_BehaviourXenoborg: + { + /* need to get rid of the animations...*/ + XENO_STATUS_BLOCK *xenoStatus; + + xenoStatus = (XENO_STATUS_BLOCK*)(sbptr->SBdataptr); + if(xenoStatus) + { + Dispel_HModel(&xenoStatus->HModelController); + /* Zounds! */ + if(xenoStatus->soundHandle1!=SOUND_NOACTIVEINDEX) Sound_Stop(xenoStatus->soundHandle1); + if(xenoStatus->soundHandle2!=SOUND_NOACTIVEINDEX) Sound_Stop(xenoStatus->soundHandle2); + if(xenoStatus->head_whirr!=SOUND_NOACTIVEINDEX) Sound_Stop(xenoStatus->head_whirr); + if(xenoStatus->left_arm_whirr!=SOUND_NOACTIVEINDEX) Sound_Stop(xenoStatus->left_arm_whirr); + if(xenoStatus->right_arm_whirr!=SOUND_NOACTIVEINDEX) Sound_Stop(xenoStatus->right_arm_whirr); + if(xenoStatus->torso_whirr!=SOUND_NOACTIVEINDEX) Sound_Stop(xenoStatus->torso_whirr); + + } + break; + } + case I_BehaviourPredator: + { + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbptr->SBdataptr); + if(predatorStatusPointer) + { + Dispel_HModel(&predatorStatusPointer->HModelController); + + if(predatorStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(predatorStatusPointer->soundHandle); + } + break; + } + case I_BehaviourQueenAlien: + { + QUEEN_STATUS_BLOCK *queenStatusPointer; + queenStatusPointer = (QUEEN_STATUS_BLOCK *)(sbptr->SBdataptr); + if(queenStatusPointer) + { + Dispel_HModel(&queenStatusPointer->HModelController); + } + //stop any sound the queen is making + if(queenStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(queenStatusPointer->soundHandle); + + break; + } + case I_BehaviourNetGhost: + { + #if SupportWindows95 + { + NETGHOSTDATABLOCK *ghostData; + ghostData = (NETGHOSTDATABLOCK *)(sbptr->SBdataptr); + if(ghostData) + { + if(ghostData->myGunFlash) DestroyActiveObject(ghostData->myGunFlash); + if(ghostData->SoundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + if(ghostData->SoundHandle2!=SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle2); + if(ghostData->SoundHandle3!=SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle3); + Dispel_HModel(&ghostData->HModelController); + } + } + #endif + break; + } + + case I_BehaviourXenoborgMorphRoom: + { + XENO_MORPH_ROOM_DATA * xmrd = (XENO_MORPH_ROOM_DATA *)sbptr->SBdataptr; + + if (sbptr->SBmorphctrl && + sbptr->SBmorphctrl->ObMorphHeader && + sbptr->SBmorphctrl->ObMorphHeader->mph_frames) + DeallocateMem( sbptr->SBmorphctrl->ObMorphHeader->mph_frames); + + if (sbptr->SBmorphctrl && + sbptr->SBmorphctrl->ObMorphHeader) + DeallocateMem( sbptr->SBmorphctrl->ObMorphHeader); + + if (sbptr->SBmorphctrl) + DeallocateMem( sbptr->SBmorphctrl); + + if (xmrd) + { + if (xmrd->tacb) + { + TXACTRLBLK *txactrl; + TXACTRLBLK *txactrl_next; + + txactrl_next = xmrd->tacb; + + while(txactrl_next) + { + txactrl = txactrl_next; + txactrl_next = txactrl->tac_next; + DeallocateMem((void*)txactrl); + } + } + } + break; + } + case I_BehaviourInanimateObject : + { + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr=(INANIMATEOBJECT_STATUSBLOCK*)sbptr->SBdataptr; + TXACTRLBLK *txactrl; + TXACTRLBLK *txactrl_next; + + + if (objectstatusptr) + { + if(objectstatusptr->event_target) + { + DeallocateMem(objectstatusptr->event_target); + } + + if(!objectstatusptr->inan_tac) break; + txactrl_next = objectstatusptr->inan_tac; + + while(txactrl_next) + { + txactrl = txactrl_next; + txactrl_next = txactrl->tac_next; + DeallocateMem((void*)txactrl); + } + } + break; + } + case I_BehaviourVideoScreen : + { + VIDEO_SCREEN_BEHAV_BLOCK* videoScreen=(VIDEO_SCREEN_BEHAV_BLOCK*)sbptr->SBdataptr; + TXACTRLBLK *txactrl; + TXACTRLBLK *txactrl_next; + + + if (videoScreen) + { + + if(!videoScreen->inan_tac) break; + txactrl_next = videoScreen->inan_tac; + + while(txactrl_next) + { + txactrl = txactrl_next; + txactrl_next = txactrl->tac_next; + DeallocateMem((void*)txactrl); + } + } + break; + } + + case I_BehaviourPlacedLight : + { + PLACED_LIGHT_BEHAV_BLOCK* pl_bhv=(PLACED_LIGHT_BEHAV_BLOCK*)sbptr->SBdataptr; + TXACTRLBLK *txactrl; + TXACTRLBLK *txactrl_next; + + if (pl_bhv) + { + if(sbptr->SBdptr) + { + //set num lights to zero so it doesn't attempt to deallocate the light + sbptr->SBdptr->ObNumLights=0; + } + //reset vaules in lightblock + pl_bhv->light->LightBright=pl_bhv->light->LightBrightStore; + pl_bhv->light->RedScale=pl_bhv->colour_red; + pl_bhv->light->GreenScale=pl_bhv->colour_green; + pl_bhv->light->BlueScale=pl_bhv->colour_blue; + + if(!pl_bhv->inan_tac) break; + txactrl_next = pl_bhv->inan_tac; + + while(txactrl_next) + { + txactrl = txactrl_next; + txactrl_next = txactrl->tac_next; + DeallocateMem((void*)txactrl); + } + } + break; + } + case I_BehaviourHierarchicalFragment: + { + HDEBRIS_BEHAV_BLOCK *hdbblk=(HDEBRIS_BEHAV_BLOCK *)sbptr->SBdataptr; + + Dispel_HModel(&hdbblk->HModelController); + } + break; + + case I_BehaviourPlacedSound: + { + SoundBehaveDestroy (sbptr); + break; + } + + case I_BehaviourMissionComplete: + { + MISSION_COMPLETE_BEHAV_BLOCK *mc_bhv; + mc_bhv = (MISSION_COMPLETE_BEHAV_BLOCK*)sbptr->SBdataptr; + if(mc_bhv) + { + GLOBALASSERT((mc_bhv->bhvr_type == I_BehaviourMissionComplete)); + ResetMission(mc_bhv->mission_objective_ptr); + + } + break; + } + + case I_BehaviourTrackObject: + { + TRACK_OBJECT_BEHAV_BLOCK *to_bhv; + TXACTRLBLK *txactrl; + TXACTRLBLK *txactrl_next; + + to_bhv = (TRACK_OBJECT_BEHAV_BLOCK*)(sbptr->SBdataptr); + if (to_bhv) + { + GLOBALASSERT(to_bhv->bhvr_type == I_BehaviourTrackObject); + + if(to_bhv->to_track) + { + Reset_Track(to_bhv->to_track); + } + + txactrl_next = to_bhv->to_tac; + while(txactrl_next) + { + txactrl = txactrl_next; + txactrl_next = txactrl->tac_next; + DeallocateMem((void*)txactrl); + } + } + break; + case I_BehaviourPlacedHierarchy: + { + PLACED_HIERARCHY_BEHAV_BLOCK *ph_bhv; + + ph_bhv = (PLACED_HIERARCHY_BEHAV_BLOCK*)(sbptr->SBdataptr); + if (ph_bhv) + { + GLOBALASSERT(ph_bhv->bhvr_type == I_BehaviourPlacedHierarchy); + DeletePlacedHierarchy(ph_bhv); + } + break; + } + case I_BehaviourNetCorpse: + { + #if SupportWindows95 + { + NETCORPSEDATABLOCK *corpseData; + corpseData = (NETCORPSEDATABLOCK *)(sbptr->SBdataptr); + if(corpseData) + { + if(corpseData->SoundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(corpseData->SoundHandle); + Dispel_HModel(&corpseData->HModelController); + } + } + #endif + break; + } + + case I_BehaviourLightFX : + { + LIGHT_FX_BEHAV_BLOCK * lfxbb; + TXACTRLBLK *txactrl; + TXACTRLBLK *txactrl_next; + + lfxbb = (LIGHT_FX_BEHAV_BLOCK *)sbptr->SBdataptr; + if(lfxbb) + { + txactrl_next = lfxbb->anim_control; + while(txactrl_next) + { + txactrl = txactrl_next; + txactrl_next = txactrl->tac_next; + DeallocateMem((void*)txactrl); + } + } + break; + + } + + case I_BehaviourFan : + { + FAN_BEHAV_BLOCK* f_bhv=(FAN_BEHAV_BLOCK*)sbptr->SBdataptr; + if(f_bhv->track) + { + Reset_Track(f_bhv->track); + } + break; + + + } + case I_BehaviourSpeargunBolt: + { + SPEAR_BEHAV_BLOCK *sbblk=(SPEAR_BEHAV_BLOCK *)sbptr->SBdataptr; + + if (sbblk->SpearThroughFragment) { + /* There's a hierarchy to dispel. */ + Dispel_HModel(&sbblk->HierarchicalFragment); + } + break; + } + case I_BehaviourPlatform : + { + PLATFORMLIFT_BEHAVIOUR_BLOCK* pl_bhv=(PLATFORMLIFT_BEHAVIOUR_BLOCK*)sbptr->SBdataptr; + if(pl_bhv->sound) + { + Stop_Track_Sound(pl_bhv->sound); + } + if(pl_bhv->start_sound) + { + Stop_Track_Sound(pl_bhv->start_sound); + } + if(pl_bhv->end_sound) + { + Stop_Track_Sound(pl_bhv->end_sound); + } + break; + } + case I_BehaviourParticleGenerator : + { + PARTICLE_GENERATOR_BEHAV_BLOCK* pargen=(PARTICLE_GENERATOR_BEHAV_BLOCK*)sbptr->SBdataptr; + if(pargen->sound) + { + Stop_Track_Sound(pargen->sound); + } + break; + } + + } + default: + { + break; + } + } + + + /* destroy the behaviour block BUT not if I am the player */ + + if((sbptr->I_SBtype != I_BehaviourMarinePlayer)&&(sbptr->I_SBtype != I_BehaviourAlienPlayer)&&(sbptr->I_SBtype != I_BehaviourPredatorPlayer)) + { + /* patrick: 23/7/97 I am adding a test for SBdataptr before deallocating it- */ + if(sbptr->SBdataptr) + { + DeallocateMem(sbptr->SBdataptr); + #if debug + //I dont do a full initialisation with debug because + //we dont want to hide switch on Behaviour type bugs + // I just do this to trap the bastard + sbptr->SBdataptr = NULL; + #endif + } + } + + /* remove DYNBLOCK and DisplayBlock*/ + if (sbptr->SBdptr) + { + DestroyActiveObject(sbptr->SBdptr); + } + if (sbptr->DynPtr) + { + DeallocateDynamicsBlock(sbptr->DynPtr); + } + + #if !debug + // ull SB init + if(!sbptr->SBflags.preserve_until_end_of_level) + { + InitialiseSBValues(sbptr); + } + #endif + /* Finally remove the StrategyBlock*/ + DestroyActiveStrategyBlock(sbptr); +} + + + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +typedef struct prox_door_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int door_state; + BOOL door_locked; + + //from the morph control + int ObMorphCurrFrame; + int ObMorphFlags; + int ObMorphSpeed; + + BOOL triggeredByMarine; + +}PROX_DOOR_SAVE_BLOCK; + +void LoadStrategy_ProxDoor(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + PROXDOOR_BEHAV_BLOCK *doorbhv; + PROX_DOOR_SAVE_BLOCK* block = (PROX_DOOR_SAVE_BLOCK*) header; + + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(block->header.SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourProximityDoor) return; + + doorbhv = (PROXDOOR_BEHAV_BLOCK*)sbPtr->SBdataptr; + + doorbhv->door_state = block->door_state; + doorbhv->door_locked = block->door_locked; + doorbhv->triggeredByMarine = block->triggeredByMarine; + doorbhv->PDmctrl->ObMorphCurrFrame = block->ObMorphCurrFrame; + doorbhv->PDmctrl->ObMorphFlags = block->ObMorphFlags; + doorbhv->PDmctrl->ObMorphSpeed = block->ObMorphSpeed; + + + Load_SoundState(&doorbhv->SoundHandle); + +} + +void SaveStrategy_ProxDoor(STRATEGYBLOCK* sbPtr) +{ + PROX_DOOR_SAVE_BLOCK *block; + PROXDOOR_BEHAV_BLOCK *doorbhv ; + doorbhv = (PROXDOOR_BEHAV_BLOCK*)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + + block->door_state = doorbhv->door_state; + block->door_locked = doorbhv->door_locked; + block->triggeredByMarine = doorbhv->triggeredByMarine; + block->ObMorphCurrFrame = doorbhv->PDmctrl->ObMorphCurrFrame; + block->ObMorphFlags = doorbhv->PDmctrl->ObMorphFlags; + block->ObMorphSpeed = doorbhv->PDmctrl->ObMorphSpeed; + + Save_SoundState(&doorbhv->SoundHandle); +} + + +/*---------------------------** +** End of loading and saving ** +**---------------------------*/ diff --git a/3dc/avp/BH_TYPES.H b/3dc/avp/BH_TYPES.H new file mode 100644 index 0000000..46df080 --- /dev/null +++ b/3dc/avp/BH_TYPES.H @@ -0,0 +1,516 @@ +#ifndef _bhtypes_h_ +#define _bhtypes_h_ 1 + +#ifndef _equipmnt_h_ +#include "equipmnt.h" +#endif + +#include "gameflow.h" + +#include "pmove.h" + + +#ifdef __cplusplus + + extern "C" { + +#endif + + + +/* + I think I am going to devide the behaviour of objects into two different forms + + In terms of emulating 3d we need to think of multiple cluster of sprite sequences to + descibe any one motion. In this respect I am going to have a list of capabilities for + objects. If you supply One animation sequence that allows a capabiltity the animation capability + language will allow that capabiltiy. If it is a front walk, the object will walk + but it will always display the one type of sequence even if it is walking away from + you. When we load up a sprite sequence we include an enum that tells us what capabiltiy_type + these sequence is part of. The animation capabiltity language and capabiltiy_type can refer + to morphing equally as to sprites (morphing is some what easier as the object will always look + right + + + Other objects are rather dull and the above capability system is too complex. A module + playing a TV does not need such a comple behaviour. These objects have much simpler + strategies and we will have specfifc low level functions to deal with them. + +*/ + + +typedef enum actor_capability_types +{ + BHTypeWalk, /* gen movement */ + BHTypeCrawl, /* gen movement */ + BHTypeRun, /* gen movement */ + BHTypeFly, /* gen movement */ + BHTypeStandUp, + BHTypeSitDown, + BHTypeKneelDown, + BHTypeCroach, + BHTypeAttack1, + BHTypeAttack2, + BHTypeAttack3, + BHTypeRangedAttack1, + BHTypeRangedAttack2, + BHTypeRangedAttack3, + BHTypeHit, + BHTypeDying, + BHTypeDead, + BHTypeJump +} ACTOR_CAPABILITY_TYPES; + + + + +/* ****************** STRATEGY BLOCK Behaviour DESCRIPTION ************ */ + + +typedef struct CapabilityDescription +{ + int num_animating_items; + int **item_animations; + +} CAPABILITY_DESCRIPTION; + + +/* the item_animations are specific to each animating +item the have no formal description interms of a type +the theyare listed as. + +int item_num +seq_des1 +seq_des2 +seq_des3 +seq_des4 +term + +the list of void* pointers points to the initial +item_num for the following sequences +*/ + +typedef struct sequence_descriptor +{ + ACTOR_CAPABILITY_TYPES cap_type; + TXANIMHEADER* txanim_header; + int view_angle; + int view_azimuth; +} SEQUENCE_DESCRIPTOR; + + +typedef struct SuicideTimer +{ + int time_left; /*agrgggghhh*****/ + +}SUICIDE_TIMER; + + + + +/**************************** SPECIFIC BEHAVIOUR TYPES ************************/ + + +// ENUM now in Stratdef.h + + +/*-------------Patrick 21/10/96 -------------------- + This structure is used in Player Status to represent + the various player input requests. It consists + of single bit fields, which are used as a bit-mask + for recording key-combo sequences for special moves. + for the purposes of bit-masking, it is implemented as + a union with an unsigned int... + + NB it is easier to add new fields towards the end, + as otherwise you may have to change the special + move input bitmasks + --------------------------------------------------*/ +typedef struct player_input_requests +{ + unsigned int Rqst_Forward :1; + unsigned int Rqst_Backward :1; + unsigned int Rqst_TurnLeft :1; + unsigned int Rqst_TurnRight :1; + unsigned int Rqst_LookUp :1; + unsigned int Rqst_LookDown :1; + unsigned int Rqst_FirePrimaryWeapon :1; + unsigned int Rqst_Faster :1; + unsigned int Rqst_SideStepLeft :1; + unsigned int Rqst_SideStepRight :1; + unsigned int Rqst_Strafe :1; + unsigned int Rqst_Crouch :1; + unsigned int Rqst_Jump :1; + /* NB Lie Down is set by special moves only (ie doesn't require a user input, configuration entry, etc) */ + unsigned int Rqst_Operate :1; + unsigned int Rqst_CentreView :1; + unsigned int Rqst_NextWeapon :1; + unsigned int Rqst_PreviousWeapon :1; + unsigned int Rqst_WeaponNo :4; + unsigned int Rqst_QuitGame :1; + unsigned int Rqst_PauseGame :1; + + /* KJL 16:58:37 04/11/98 - Change vision does a variety of things, dependent on the player's + character. */ + unsigned int Rqst_ChangeVision :1; + unsigned int Rqst_FireSecondaryWeapon :1; + + /* Predator Specific */ + unsigned int Rqst_CycleVisionMode :1; + unsigned int Rqst_ZoomIn :1; + unsigned int Rqst_ZoomOut :1; + unsigned int Rqst_GrapplingHook :1; + + /* Alien Specific */ + unsigned int Rqst_Spit :1; + + /* Marine Specific */ + unsigned int Rqst_ThrowFlare :1; + unsigned int Rqst_Jetpack :1; + + unsigned int :0; + +}PLAYER_INPUT_REQUESTS; + +/*-------------Patrick 23/10/96 -------------------- + Some defines for key combo bit masks + these should correspond to the above request flags. + --------------------------------------------------*/ +#define INPUT_BITMASK_FORWARD 0x00000001 +#define INPUT_BITMASK_BACKWARD 0x00000002 +#define INPUT_BITMASK_LEFT 0x00000004 +#define INPUT_BITMASK_RIGHT 0x00000008 +#define INPUT_BITMASK_FIRE 0x00000040 +#define INPUT_BITMASK_FASTER 0x00000080 +#define INPUT_BITMASK_STRAFE 0x00000100 +#define INPUT_BITMASK_CROUCH 0x00000200 +#define INPUT_BITMASK_JUMP 0x00000400 + + + +/* KJL 14:16:52 09/20/96 - the new player status type + modified by patrick */ +typedef struct player_status +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + + /* player's weapons */ + PLAYER_WEAPON_DATA WeaponSlot[MAX_NO_OF_WEAPON_SLOTS]; + enum WEAPON_SLOT SelectedWeaponSlot; + enum WEAPON_SLOT SwapToWeaponSlot; + enum WEAPON_SLOT PreviouslySelectedWeaponSlot; + + int Health; /* in 16.16 */ + int Energy; /* in 16.16 */ + int Armour; /* in 16.16 */ + + /* general info */ + /* KJL 17:28:20 09/19/96 - not yet used + + int ArmourType; + int HealingRate; + int CloakingType; + int VisionType; + */ + + /*-----Patrick 15/10/96--------- + Player movement bits... + ------------------------------*/ + enum player_morph_state ShapeState; /* for controlling morphing */ + + /* and these are for free (ie normal) movement, + and should be set by the (platform dependant) input + device reading function */ + unsigned char Mvt_DeviceType; + signed int Mvt_MotionIncrement; /* 65536 (Forward) to -65536 (Backward) */ + signed int Mvt_TurnIncrement; /* 65536 (Right) to -65536 (Left)*/ + signed int Mvt_PitchIncrement; /* 65536 to -65536 */ + signed int Mvt_SideStepIncrement; /* 65536 to -65536 */ + + /* KJL 10:48:33 03/26/97 - inertia data */ + signed int ForwardInertia; + signed int StrafeInertia; + signed int TurnInertia; + + int ViewPanX; /* the looking up/down value that used to be in displayblock */ + + union Mvt_InputRequests + { + unsigned int Mask; + unsigned int Mask2; + PLAYER_INPUT_REQUESTS Flags; + }Mvt_InputRequests; + + /* security clearances */ + unsigned int securityClearances; + /* useful flags */ + unsigned int IsAlive :1; + unsigned int IsImmortal :1; + unsigned int Mvt_AnalogueTurning :1; + unsigned int Mvt_AnaloguePitching :1; + unsigned int Absolute_Pitching :1; + unsigned int SwappingIsDebounced :1; + unsigned int DemoMode :1; + unsigned int IHaveAPlacedAutogun :1; + unsigned int IsMovingInWater :1; + unsigned int JetpackEnabled :1; + unsigned int GrapplingHookEnabled :1; + + unsigned int MTrackerType; + + /* Patrick: 1/7/97 : for predator-type cloaking stuff */ + unsigned int cloakOn :1; + unsigned int cloakPositionGivenAway :1; + int FieldCharge; + int cloakPositionGivenAwayTimer; + int PlasmaCasterCharge; + /* KJL 99/2/3 - Cloaking Effectiveness + ranges from 0 (useless) to ONE_FIXED (practically invisible) */ + int CloakingEffectiveness; + + // John 28/7/97 Game Flow stuff + PLAYERMISSION CurrentMission; + unsigned long StateChangeObjectFlags; + + /* Encumberance */ + ENCUMBERANCE_STATE Encumberance; + STRATEGYBLOCK *MyFaceHugger; + STRATEGYBLOCK *MyCorpse; + int tauntTimer; + int soundHandle; + /* Why no 2, you ask? */ + int soundHandle3; + /* Because '3' is always crackling fire, for * + * netghosts and corpses. Really, 2 should be* + * the voice and 1 should be weapon use. */ + int soundHandle4; + /* For the splash. */ + int soundHandle5; + /* For the jetpack. */ + + int soundHandleForPredatorCloakDamaged; + /* the above seemed better than soundHandle5 :) */ + + HMODELCONTROLLER HModelController; + int incidentFlag; + int incidentTimer; + int fireTimer; + int invulnerabilityTimer; + +} PLAYER_STATUS; + +#define TAUNT_LENGTH (ONE_FIXED<<1) +#define PLAYER_ON_FIRE_TIME (ONE_FIXED*20) + +#define STARTOFGAME_MARINE_HEALTH (100*65536) /* ie. 100 in 16.16 notation */ +#define STARTOFGAME_MARINE_ENERGY (100*65536) /* ie. 100 in 16.16 notation */ +#define STARTOFGAME_MARINE_ARMOUR (100*65536) /* ie. 100 in 16.16 notation */ + +/* Patrick 22/8/97------------------------------------------------ +Cloaking stuff +------------------------------------------------------------------*/ + +#define PLAYERCLOAK_MAXENERGY (30*ONE_FIXED) /* fixed point seconds */ +#define PLAYERCLOAK_RECHARGEFACTOR (4) /* ... times slower than discharge */ +#define PLAYERCLOAK_POSTIONGIVENAWAYTIME (ONE_FIXED>>2) /*(2*ONE_FIXED) fixed point seconds */ +#define PLAYERCLOAK_THRESHOLD (5*ONE_FIXED) +#define PLAYERCLOAK_POWERON_DRAIN (2*ONE_FIXED) +#define PLAYERCLOAK_DRAIN_FACTOR (4) + +/* Moved mere from player.c, CDF 23/4/98 */ + +extern PLAYER_STATUS* PlayerStatusPtr; + + +/******************** SIMPLE ANIMATIONS ********************/ + +typedef struct simpleanimbehaviour +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + TXACTRLBLK *tacbSimple; + +}SIMPLE_ANIM_BEHAV_BLOCK; + +typedef struct simple_anim_tools_template +{ + int shape_num; + MREF my_module; + char nameID[SB_NAME_LENGTH]; +} SIMPLE_ANIM_TOOLS_TEMPLATE; + + +/**********************************************************/ +/**********************DOORS*******************************/ + +typedef enum{ /* this may be flags*/ + I_door_opening, + I_door_closing, + I_door_open, + I_door_closed, + +} DOOR_STATES; + + + + +/******************** PROXIMITY DOORS ********************/ + + + +typedef struct ProxDoorBehaviourType +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + int door_state; + MORPHCTRL *PDmctrl; + + /*---- Patrick 1/1/97 ----- + added for far ai stratgies + --------------------------*/ + int alienTimer; + unsigned int alienTrigger :1; + unsigned int marineTrigger :1; + unsigned int triggeredByMarine :1; + + /*---- Roxby 1/1/97 ----- + Added so that another door can lock + this door closed + --------------------------*/ + + BOOL lockable_door; + BOOL door_locked; + char target_name[SB_NAME_LENGTH]; + STRATEGYBLOCK* door_lock_target; + int SoundHandle; + int doorType; // Used to determine door sound type + + int door_opening_speed; + int door_closing_speed; +} PROXDOOR_BEHAV_BLOCK; + +typedef struct prox_door_tools_template +{ + BOOL has_lock_target; + char target_name [SB_NAME_LENGTH]; + MREF my_module; + int shape_open; + int shape_closed; + char nameID[SB_NAME_LENGTH]; + BOOL door_is_locked; + + int door_opening_speed; + int door_closing_speed; +} PROX_DOOR_TOOLS_TEMPLATE; + + + + +/* Structures for Stat Initialisation */ + +typedef enum { + I_NPC_Civilian=0, + I_NPC_FaceHugger, + I_NPC_ChestBurster, + I_NPC_Alien, + I_NPC_Xenoborg, + I_NPC_Marine, + I_NPC_PredatorAlien, + I_NPC_SFMarine, + I_NPC_Predator, + I_NPC_PraetorianGuard, + I_NPC_AlienQueen, + I_NPC_DefaultInanimate, + I_PC_Alien_Easy, + I_PC_Marine_Easy, + I_PC_Predator_Easy, + I_PC_Alien_Medium, + I_PC_Marine_Medium, + I_PC_Predator_Medium, + I_PC_Alien_Hard, + I_PC_Marine_Hard, + I_PC_Predator_Hard, + I_PC_Alien_Impossible, + I_PC_Marine_Impossible, + I_PC_Predator_Impossible, + I_PC_Alien_MaxStats, + I_NPC_SentryGun, + I_NPC_Android, + I_NPC_End, +} NPC_TYPES; + +typedef struct { + NPC_TYPES Type; + //int StartingHealth; + //int StartingArmour; + //SBHEALTHFLAGS SB_H_flags; + DAMAGEBLOCK StartingStats; +} NPC_DATA; + +/* Interface function! */ + +extern NPC_DATA *GetThisNpcData(NPC_TYPES NpcType); + +/********************************************************/ +/******************* Database behaviour************/ + +/* + we will need to include an enum into another menu + graphic which contains the text to overlay onto + the menugraphics +*/ + +typedef struct database +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + int num; +}DATABASE_BLOCK; + +typedef struct database_template +{ + int num; + VECTORCH position; + EULER orientation; + int shape_num; +} DATABASE_TOOLS_TEMPLATE; + +extern void DatabaseMenus(DATABASE_BLOCK* db); + +/***********************************************************/ +/****************** externs for bh_types.c ******************/ +/* functions*/ + +extern void AssignAllSBNames(); +extern void AssignRunTimeBehaviours(STRATEGYBLOCK* sbptr); +extern void EnableBehaviourType(STRATEGYBLOCK* sbptr, AVP_BEHAVIOUR_TYPE sb_type, void *bhdata); +extern void ExecuteBehaviour(STRATEGYBLOCK* sbptr); +extern void ObjectBehaviours(void); +extern void RequestState(STRATEGYBLOCK* sb, int message, STRATEGYBLOCK * SBRequester); +extern BOOL GetState(STRATEGYBLOCK* sb); +extern void RemoveBehaviourStrategy(STRATEGYBLOCK* sbptr); + +extern void UnlockThisProxdoor(STRATEGYBLOCK* sbptr); + +extern void FindMaxZXandYAverages(VECTORCH* vect, SHAPEHEADER* shapeptr); + +extern DISPLAYBLOCK *MakeObject(AVP_BEHAVIOUR_TYPE bhvr, VECTORCH *positionPtr); + +extern void SetupPlayerAutoGun(); + +#ifdef __cplusplus + + }; + +#endif + + +#endif + + + + + + + + + + + diff --git a/3dc/avp/BH_XENO.H b/3dc/avp/BH_XENO.H new file mode 100644 index 0000000..2e60b63 --- /dev/null +++ b/3dc/avp/BH_XENO.H @@ -0,0 +1,234 @@ +/* Patrick 4/7/97------------------------------ + Header file for xenoborg support functions + + ChrisF 6/7/98 Well, sort of. + ---------------------------------------------*/ + +#ifndef _bhxeno_h_ + #define _bhxeno_h_ 1 + + + #ifdef __cplusplus + + extern "C" { + + #endif + +/* KJL 16:57:28 16/07/98 - particle.h is needed for LASER_BEAM_DESC */ +#include "particle.h" +#include "bh_ais.h" +/* Patrick 4/7/97------------------------------ + Enumerations of sequences and states + ---------------------------------------------*/ + + typedef enum xeno_bhstate + { + XS_ActiveWait, + XS_TurnToFace, + XS_Following, + XS_Returning, + XS_Inactive, + XS_Activating, + XS_Deactivating, + XS_Avoidance, + XS_Regenerating, + XS_Dying, + XS_ShootingTheRoof, + + }XENO_BHSTATE; + +/* Patrick 4/7/97------------------------------ + Structures for behaviour data & tools data + ---------------------------------------------*/ + typedef struct xenoStatusBlock + { + signed int health; + XENO_BHSTATE behaviourState; + XENO_BHSTATE lastState; + int stateTimer; + NPC_MOVEMENTDATA moveData; + NPC_WANDERDATA wanderData; + NPC_OBSTRUCTIONREPORT obstruction; + AIMODULE *my_module; + VECTORCH my_spot_therin; + VECTORCH my_orientdir_therin; + int module_range; + int UpTime; + int GibbFactor; + int Wounds; + + HMODELCONTROLLER HModelController; + DELTA_CONTROLLER *head_pan; + DELTA_CONTROLLER *head_tilt; + DELTA_CONTROLLER *left_arm_pan; + DELTA_CONTROLLER *left_arm_tilt; + DELTA_CONTROLLER *right_arm_pan; + DELTA_CONTROLLER *right_arm_tilt; + DELTA_CONTROLLER *torso_twist; + + STRATEGYBLOCK *Target; + char Target_SBname[SB_NAME_LENGTH]; + + VECTORCH targetTrackPos; + + int Head_Pan; + int Head_Tilt; + int Left_Arm_Pan; + int Left_Arm_Tilt; + int Right_Arm_Pan; + int Right_Arm_Tilt; + int Torso_Twist; + + int Old_Head_Pan; + int Old_Head_Tilt; + int Old_Left_Arm_Pan; + int Old_Left_Arm_Tilt; + int Old_Right_Arm_Pan; + int Old_Right_Arm_Tilt; + int Old_Torso_Twist; + + /* KJL 12:23:24 09/12/98 - muzzleflashes replaced by + beam weapon thingies */ + LASER_BEAM_DESC LeftMainBeam; + LASER_BEAM_DESC RightMainBeam; + + /* KJL 16:56:38 16/07/98 */ + LASER_BEAM_DESC TargetingLaser[3]; + + unsigned int headpandir :1; + unsigned int headtiltdir :1; + unsigned int leftarmpandir :1; + unsigned int leftarmtiltdir :1; + unsigned int rightarmpandir :1; + unsigned int rightarmtiltdir :1; + unsigned int torsotwistdir :1; + + unsigned int headLock :1; + unsigned int leftArmLock :1; + unsigned int rightArmLock :1; + unsigned int targetSightTest :1; + unsigned int IAmFar :1; + unsigned int ShotThisFrame :1; + + unsigned int FiringLeft :1; + unsigned int FiringRight :1; + + unsigned int UseHeadLaser :1; + unsigned int UseLALaser :1; + unsigned int UseRALaser :1; + + unsigned int HeadLaserOnTarget :1; + unsigned int LALaserOnTarget :1; + unsigned int RALaserOnTarget :1; + + unsigned int head_moving :1; + unsigned int la_moving :1; + unsigned int ra_moving :1; + unsigned int torso_moving :1; + + int soundHandle1; + int soundHandle2; + + int incidentFlag; + int incidentTimer; + + int head_whirr; + int left_arm_whirr; + int right_arm_whirr; + int torso_whirr; + + char death_target_ID[SB_NAME_LENGTH]; + STRATEGYBLOCK* death_target_sbptr; + int death_target_request; + + WAYPOINT_MANAGER waypointManager; + + }XENO_STATUS_BLOCK; + + typedef struct tools_data_xeno + { + struct vectorch position; + int shapeIndex; + char nameID[SB_NAME_LENGTH]; + char death_target_ID[SB_NAME_LENGTH]; + int death_target_request; + struct euler starteuler; + int UpTime; /* Default to '20' */ + int ModuleRange; /* Default to '7' */ + }TOOLS_DATA_XENO; + +/* Patrick 4/7/97------------------------------ + Some defines + ---------------------------------------------*/ + #define XENO_STARTING_HEALTH 600 + #define XENO_NEAR_SPEED 1000 /* mm/s */ + #define XENO_NEAR_ACCURACY 5 /* mm per m max deviation */ + #define XENO_NEAR_VIEW_WIDTH 500 /* mm */ + #define XENO_CLOSE_APPROACH_DISTANCE 3000 /* mm */ + #define XENO_FIRINGPOINT_INFRONT 1000 /* mm */ + #define XENO_FIRINGPOINT_ACROSS 300 /* mm */ + #define XENO_FIRINGPOINT_UP 100 /* mm */ + #define XENO_PROJECTILESPEED 20000 /* mm/s */ + #define XENO_PROJECTILEDAMAGE 10 + #define XENO_SENTRY_SENSITIVITY 1500 + #define XENO_FAR_MOVE_TIME ((24+(FastRandom()&0x07))*(ONE_FIXED>>4)) + + /* 1-2 seconds in 1/8ths of a second */ + #define XENO_NEAR_TIMEBETWEENFIRING ((8+(FastRandom()&0x07))*(ONE_FIXED>>3)) + #define XENO_RECOILTIME (ONE_FIXED>>1) /* 1/2 seconds */ + #define XENO_ACTIVATION_TIME (ONE_FIXED) /* 1 second */ + #define XENO_DEACTIVATION_TIME (ONE_FIXED) /* 1 second */ + #define XENO_REGEN_TIME (ONE_FIXED*5) + #define XENO_POWERDOWN_TIME (ONE_FIXED*5) + + /* 2,3 or 4*/ + #define XENO_VOLLEYSIZE (2+(FastRandom()%3)) + + #define XENO_HEADPAN_GIMBALL (1024) + #define XENO_HEADTILT_GIMBALL (512) + #define XENO_TORSO_GIMBALL (1195) + + #define XENO_LEFTARM_CW_GIMBALL (626) + #define XENO_LEFTARM_ACW_GIMBALL (910) + #define XENO_RIGHTARM_CW_GIMBALL (910) + #define XENO_RIGHTARM_ACW_GIMBALL (626) + + #define XENO_ARM_PITCH_GIMBALL (1024) + + #if 0 + /* Original values. */ + #define XENO_HEAD_LOCK_RATE (2) /* Was 0 */ + #define XENO_HEAD_SCAN_RATE (3) + #define XENO_TORSO_TWIST_RATE (3) + #define XENO_ARM_LOCK_RATE (4) + #define XENO_FOOT_TURN_RATE (3) + + #else + /* Let's slow everything down a wee bit. */ + #define XENO_HEAD_LOCK_RATE (2) /* Was 0 */ + #define XENO_HEAD_SCAN_RATE (4) + #define XENO_TORSO_TWIST_RATE (5) + #define XENO_ARM_LOCK_RATE (5) + #define XENO_FOOT_TURN_RATE (5) + + #endif + +/* Patrick 4/7/97------------------------------ + Some prototypes + ---------------------------------------------*/ + void InitXenoborgBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr); + void XenoborgBehaviour(STRATEGYBLOCK *sbPtr); + void MakeXenoborgNear(STRATEGYBLOCK *sbPtr); + void MakeXenoborgFar(STRATEGYBLOCK *sbPtr); + void XenoborgIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,VECTORCH *incoming); + int XenoSight_FrustrumReject(STRATEGYBLOCK *sbtr,VECTORCH *localOffset); + + + #ifdef __cplusplus + + } + + #endif + + +#endif \ No newline at end of file diff --git a/3dc/avp/Bh_debri.c b/3dc/avp/Bh_debri.c new file mode 100644 index 0000000..6705437 --- /dev/null +++ b/3dc/avp/Bh_debri.c @@ -0,0 +1,1867 @@ +/* KJL 15:01:53 02/25/97 - bh_debri.c */ +#include "3dc.h" +#include "module.h" +#include "inline.h" +#include "stratdef.h" +#include "gamedef.h" +#include "dynblock.h" +#include "dynamics.h" +#include "comp_shp.h" +#include "load_shp.h" +#include "bh_types.h" +#include "bh_debri.h" +#include "bh_weap.h" +#include "inventry.h" +#include "psnd.h" +#include "plat_shp.h" +#include "particle.h" +#include "jsndsup.h" +#include "bh_alien.h" +#include "bh_marin.h" +#include "bh_corpse.h" + +#define UseLocalAssert Yes + +#include "ourasert.h" + +#include "weapons.h" +#include "lighting.h" +#include "sfx.h" +#if SupportWindows95 +/* for win95 net game support */ +#include "pldghost.h" +#endif + +#include "AvP_UserProfile.h" +#include "savegame.h" + +#include + +#define HDEBRIS_BLEEDING_TIME (ONE_FIXED*2) + +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ +void MakeFleshRippingNoises(VECTORCH *positionPtr); + +/*KJL**************************************************************************************** +* G L O B A L S * +****************************************************************************************KJL*/ +extern int NormalFrameTime; +void SetupSimpleAnimation(int counter, STRATEGYBLOCK *sbPtr); +extern int NumActiveBlocks; +extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); +extern void MakeBloodExplosion(VECTORCH *originPtr, int creationRadius, VECTORCH *blastPositionPtr, int noOfParticles, enum PARTICLE_ID particleID); +extern enum PARTICLE_ID GetBloodType(STRATEGYBLOCK *sbPtr); +extern int SBIsEnvironment(STRATEGYBLOCK *sbPtr); +extern void DoAlienLimbLossSound(VECTORCH *position); + + + +extern MATRIXCH Identity_RotMat; /* From HModel.c */ + +int NextAlienFragmentToProduce; + +static char *ShapeNameOfAlienFragment[] = +{ + "AlFrga", + "AlFrgb", + "AlFrgc", + "AlFrgd", + "AlFrge", + "AlFrgf", + "AlFrgg", + "AlFrgh", + "AlFrgi", + "AlFrgj", +}; +#define NO_OF_DIFFERENT_ALIEN_FRAGS 10 + +/*KJL**************************************************************************************** +* F U N C T I O N S * +****************************************************************************************KJL*/ +DISPLAYBLOCK *MakeDebris(AVP_BEHAVIOUR_TYPE bhvr, VECTORCH *positionPtr) +{ + + DISPLAYBLOCK *dispPtr; + STRATEGYBLOCK *sbPtr; + MODULEMAPBLOCK *mmbptr; + MODULE m_temp; + + if( (NumActiveBlocks > maxobjects-5) || (NumActiveStBlocks > maxstblocks-5)) return NULL; + + // 1. Set up shape data BEFORE making the displayblock, + // since "AllocateModuleObject()" will fill in shapeheader + // information and extent data + + mmbptr = &TempModuleMap; + + switch (bhvr) + { + /* KJL 12:45:30 03/20/97 - fragments + switch on object which is going to be destroyed and create the correct fragments */ + case I_BehaviourAlien: + { + if( (NextAlienFragmentToProduce<0) || (NextAlienFragmentToProduce>=NO_OF_DIFFERENT_ALIEN_FRAGS)) + NextAlienFragmentToProduce=0; + + /* cycle through the available body parts */ + CreateShapeInstance(mmbptr,ShapeNameOfAlienFragment[NextAlienFragmentToProduce++]); + + /* 50/50 chance that it's an acid generator */ + if (FastRandom()&256) + { + bhvr = I_BehaviourAlienFragment; + } + else + { + bhvr = I_BehaviourFragment; + } + break; + } + + case I_BehaviourPredator: + { + int randomNumber = FastRandom()&65535; + + if (randomNumber>43691) + { + CreateShapeInstance(mmbptr,"Bodprt1"); + } + else if (randomNumber>21845) + { + CreateShapeInstance(mmbptr,"Bodprt2"); + } + else + { + CreateShapeInstance(mmbptr,"Bodprt3"); + } + bhvr = I_BehaviourFragment; + break; + } + + default: + { + // Don't call this function for undefined types + GLOBALASSERT (1 == 0); + break; + } + } + + // And allocate the modulemapblock object + + m_temp.m_numlights = 0; + m_temp.m_lightarray = NULL; + m_temp.m_mapptr = mmbptr; + m_temp.m_sbptr = (STRATEGYBLOCK*)NULL; + m_temp.m_dptr = NULL; + AllocateModuleObject(&m_temp); + dispPtr = m_temp.m_dptr; + if(dispPtr==NULL) return (DISPLAYBLOCK *)0; /* patrick: cannot create displayblock, so just return 0 */ + + dispPtr->ObMyModule = NULL; /* Module that created us */ + dispPtr->ObWorld = *positionPtr; + + sbPtr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dispPtr); + + if (sbPtr == 0) return (DISPLAYBLOCK *)0; // Failed to allocate a strategy block + + // 2. NOW set up the strategyblock-specific fields for + // the new displayblock. We won't go through the "AttachNew + // StrategyBlock" and "AssignRunTimeBehaviours" pair, since + // the first switches on ObShape and the second on bhvr; + // but, in this case, there isn't a particular connection + // between them. + + sbPtr->I_SBtype = bhvr; + + switch (bhvr) + { + case I_BehaviourAlienFragment: + { + DYNAMICSBLOCK *dynPtr; + + sbPtr->SBdataptr = (SMOKEGEN_BEHAV_BLOCK *) AllocateMem(sizeof(SMOKEGEN_BEHAV_BLOCK)); + if (sbPtr->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(sbPtr); + return (DISPLAYBLOCK*)NULL; + } + + ((SMOKEGEN_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = ALIEN_DYINGTIME; + ((SMOKEGEN_BEHAV_BLOCK * ) sbPtr->SBdataptr)->smokes=0; + + dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ALIEN_DEBRIS); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(sbPtr); + return (DISPLAYBLOCK*)NULL; + } + + dynPtr->Position = *positionPtr; + + // Give explosion fragments an angular velocity + dynPtr->AngVelocity.EulerX = (FastRandom()&2047)-1024; + dynPtr->AngVelocity.EulerY = (FastRandom()&2047)-1024; + dynPtr->AngVelocity.EulerZ = (FastRandom()&2047)-1024; + + { + int random = (FastRandom()&1023) - 512; + if (random>0) dynPtr->LinImpulse.vx=(random+100)<<4; + else dynPtr->LinImpulse.vx=(random-100)<<4; + } + { + int random = (FastRandom()&1023) - 768; + if (random>0) dynPtr->LinImpulse.vy=(random+100)<<4; + else dynPtr->LinImpulse.vy=(random-100)<<4; + } + { + int random = (FastRandom()&1023) - 512; + if (random>0) dynPtr->LinImpulse.vz=(random+100)<<4; + else dynPtr->LinImpulse.vz=(random-100)<<4; + } + break; + } + case I_BehaviourFragment: + { + DYNAMICSBLOCK *dynPtr; + + sbPtr->SBdataptr = (ONE_SHOT_BEHAV_BLOCK *) AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK )); + if (sbPtr->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(sbPtr); + return(DISPLAYBLOCK*)NULL; + } + + + ((ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = ALIEN_DYINGTIME; + + dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEBRIS); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(sbPtr); + return(DISPLAYBLOCK*)NULL; + } + + dynPtr->Position = *positionPtr; + + // Give explosion fragments an angular velocity + dynPtr->AngVelocity.EulerX = (FastRandom()&2047)-1024; + dynPtr->AngVelocity.EulerY = (FastRandom()&2047)-1024; + dynPtr->AngVelocity.EulerZ = (FastRandom()&2047)-1024; + + { + int random = (FastRandom()&1023) - 512; + if (random>0) dynPtr->LinImpulse.vx=(random+100)<<4; + else dynPtr->LinImpulse.vx=(random-100)<<4; + } + { + int random = (FastRandom()&1023) - 768; + if (random>0) dynPtr->LinImpulse.vy=(random+100)<<4; + else dynPtr->LinImpulse.vy=(random-100)<<4; + } + { + int random = (FastRandom()&1023) - 512; + if (random>0) dynPtr->LinImpulse.vz=(random+100)<<4; + else dynPtr->LinImpulse.vz=(random-100)<<4; + } + break; + } + + + default: + { + GLOBALASSERT (1 == 0); + } + } + + + return dispPtr; + +} + + + +void CreateShapeInstance(MODULEMAPBLOCK *mmbptr, char *shapeNamePtr) +{ + int shapenum; + shapenum = GetLoadedShapeMSL(shapeNamePtr); + #if debug + if (shapenum<=0) + { + textprint("Unable to display shape:%s\n",shapeNamePtr); + LOCALASSERT(0); + } + #endif + + mmbptr->MapShape = shapenum; + mmbptr->MapType = MapType_Default; +} + + + + +void OneShotBehaveFun(STRATEGYBLOCK *sptr) +{ + + // This fn. will have been called from "Execute Behaviour", + // as a consequence of "ObjectBehaviours" running each + // frame. It simply decrements the counter of the specified + // temporary object, and destroys it if that counter hits + // zero + + + ONE_SHOT_BEHAV_BLOCK *osbhv; + GLOBALASSERT(sptr); + osbhv = (ONE_SHOT_BEHAV_BLOCK * ) sptr->SBdataptr; + GLOBALASSERT(sptr->SBdptr); + + if (osbhv->counter < 0) + { + DestroyAnyStrategyBlock(sptr); + return; + } + + { + DISPLAYBLOCK *dispPtr = sptr->SBdptr; + /* do we have a displayblock? */ + if (dispPtr) + { + dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND; + dispPtr->ObFlags2 = osbhv->counter/2; + + } + } + osbhv->counter -= NormalFrameTime; + + + { + DYNAMICSBLOCK *dynPtr = sptr->DynPtr; + + if (dynPtr) + { + if (dynPtr->IsInContactWithFloor==0) + { + DynamicallyRotateObject(dynPtr); + } + } + } +} + + +void OneShot_Anim_BehaveFun(STRATEGYBLOCK *sptr) +{ + + // This fn. will have been called from "Execute Behaviour", + // as a consequence of "ObjectBehaviours" running each + // frame. It simply decrements the counter of the specified + // temporary object, and destroys it if that counter hits + // zero + + + ONESHOT_ANIM_BEHAV_BLOCK *osbhv; + DISPLAYBLOCK* dptr; + + GLOBALASSERT(sptr); + GLOBALASSERT(sptr->SBdptr); + + osbhv = (ONESHOT_ANIM_BEHAV_BLOCK * ) sptr->SBdataptr; + + if (osbhv->counter < 0) + { + DestroyAnyStrategyBlock(sptr); + return; + } + + osbhv->counter -= NormalFrameTime; + + { + DYNAMICSBLOCK *dynPtr = sptr->DynPtr; + + if (dynPtr) + { + if (dynPtr->IsInContactWithFloor==0) + { + DynamicallyRotateObject(dynPtr); + } + } + } + + dptr = sptr->SBdptr; + + if(dptr) + { + if(!dptr->ObTxAnimCtrlBlks) + { + dptr->ObTxAnimCtrlBlks = osbhv->tac_os; + } + } +} + + + +void SetupSimpleAnimation(int counter, STRATEGYBLOCK *sbPtr) +{ + TXACTRLBLK **pptxactrlblk; + int item_num; + SHAPEHEADER* shptr; + ONESHOT_ANIM_BEHAV_BLOCK* osab; + DISPLAYBLOCK *dispPtr = sbPtr->SBdptr; + int shape_num; + + sbPtr->SBdataptr = (ONESHOT_ANIM_BEHAV_BLOCK *) AllocateMem(sizeof(ONESHOT_ANIM_BEHAV_BLOCK )); + + if (sbPtr->SBdataptr == 0) return; // Failed to allocate an sb data ptr + + osab = ((ONESHOT_ANIM_BEHAV_BLOCK * ) sbPtr->SBdataptr); + + osab->counter = counter; + + shape_num = dispPtr->ObShape; + shptr = GetShapeData(shape_num); + pptxactrlblk = &osab->tac_os; + + SetupPolygonFlagAccessForShape(shptr); + + /* + the bhdata is a ptr to the SHAPEHEADER each + animating polygon has an array of sequences, in + this case thers is only onr sequence per array + */ + + for(item_num = 0; item_num < shptr->numitems; item_num ++) + { + POLYHEADER *poly = (POLYHEADER*)(shptr->items[item_num]); + LOCALASSERT(poly); + + if((Request_PolyFlags((void *)poly)) & iflag_txanim) + { + TXACTRLBLK *pnew_txactrlblk; + + pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK)); + + if (pnew_txactrlblk) + { + // We have allocated the new tx anim control block so initialise it + + pnew_txactrlblk->tac_flags = 0; + pnew_txactrlblk->tac_item = item_num; + pnew_txactrlblk->tac_sequence = 0; + pnew_txactrlblk->tac_node = 0; + pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shape_num, item_num); + pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shape_num); + + pnew_txactrlblk->tac_txah.txa_currentframe = 0; + pnew_txactrlblk->tac_txah.txa_flags = txa_flag_play|txa_flag_noloop; + + /* change the value held in pptxactrlblk + which point to the previous structures "next" + pointer*/ + + *pptxactrlblk = pnew_txactrlblk; + pptxactrlblk = &pnew_txactrlblk->tac_next; + } + } + } + dispPtr->ObTxAnimCtrlBlks = osab->tac_os; + + *pptxactrlblk=0; +} + +void AlienFragFun(STRATEGYBLOCK *sptr) +{ + int a; + DYNAMICSBLOCK *dynptr; + COLLISIONREPORT *reportptr; + SMOKEGEN_BEHAV_BLOCK *sgbhv; + GLOBALASSERT(sptr); + sgbhv = (SMOKEGEN_BEHAV_BLOCK * ) sptr->SBdataptr; + GLOBALASSERT(sptr->SBdptr); + + dynptr=sptr->DynPtr; + + GLOBALASSERT(dynptr); + + reportptr=dynptr->CollisionReportPtr; + + if (sgbhv->counter < 0) + { + DestroyAnyStrategyBlock(sptr); + return; + } + + { + DISPLAYBLOCK *dispPtr = sptr->SBdptr; + /* do we have a displayblock? */ + if (dispPtr) + { + dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND; + dispPtr->ObFlags2 = sgbhv->counter/2; + + } + } + sgbhv->counter -= NormalFrameTime; + + a=0; + + while (reportptr) { + + if (reportptr->ObstacleSBPtr==NULL) { + #if 0 + if (a==0) { + a=1; + sgbhv->counter=1; + sptr->I_SBtype=I_BehaviourSmokeGenerator; + } + #endif + } + else if (reportptr->ObstacleSBPtr->SBdptr==Player) + { + + CauseDamageToObject(Player->ObStrategyBlock,&TemplateAmmo[AMMO_ALIEN_FRAG].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + reportptr=reportptr->NextCollisionReportPtr; + } + + { + DYNAMICSBLOCK *dynPtr = sptr->DynPtr; + + if (dynPtr) { + if (dynPtr->IsInContactWithFloor==0) { + DynamicallyRotateObject(dynPtr); + } else { + dynPtr->AngVelocity.EulerX=0; + dynPtr->AngVelocity.EulerY=0; + dynPtr->AngVelocity.EulerZ=0; + } + } + } + +} + +void SmokeGeneratorBehaviour(STRATEGYBLOCK *sptr) { + + // This fn. will have been called from "Execute Behaviour", + // as a consequence of "ObjectBehaviours" running each + // frame. It simply decrements the counter of the specified + // temporary object, and destroys it if that counter hits + // zero + + DYNAMICSBLOCK *dynptr; + COLLISIONREPORT *reportptr; + SMOKEGEN_BEHAV_BLOCK *sgbhv; + GLOBALASSERT(sptr); + sgbhv = (SMOKEGEN_BEHAV_BLOCK * ) sptr->SBdataptr; + GLOBALASSERT(sptr->SBdptr); + + dynptr=sptr->DynPtr; + reportptr=dynptr->CollisionReportPtr; + + if (sgbhv->counter < 0) sgbhv->counter=ONE_FIXED<<2; + + if (sgbhv->counter > (ONE_FIXED<<1)) + { + DestroyAnyStrategyBlock(sptr); + return; + } + + sgbhv->counter += NormalFrameTime; + + if ((sgbhv->counter>>15)>sgbhv->smokes) + { + { + VECTORCH velocity={0,0,0}; + MakeParticle(&(dynptr->Position),&(velocity),PARTICLE_BLACKSMOKE); + } + sgbhv->smokes++; + } + + #if 0 + { + DYNAMICSBLOCK *dynPtr = sptr->DynPtr; + if (dynPtr) DynamicallyRotateObject(dynPtr); + } + #endif + + while (reportptr) { + if (reportptr->ObstacleSBPtr) { + if (reportptr->ObstacleSBPtr->SBdptr==Player) { + CauseDamageToObject(Player->ObStrategyBlock,&TemplateAmmo[AMMO_ALIEN_FRAG].MaxDamage[AvP.Difficulty], NormalFrameTime,NULL); + } + } + reportptr=reportptr->NextCollisionReportPtr; + } + +} + +int generate_random_between (int first, int second) +{ + int diff = second - first; + int absdiff; + int rand_no; + + if (diff == 0) + { + return(first); + } + + absdiff = abs (diff); + rand_no = FastRandom () % absdiff; + + if (diff < 0) + { + return (second + rand_no); + } + else + { + return (first + rand_no); + } + +} + +void MakeFragments (STRATEGYBLOCK * sbptr) +{ + extern int NumActiveBlocks; + DISPLAYBLOCK *dispPtr; + STRATEGYBLOCK *sbPtr; + MODULEMAPBLOCK *mmbptr; + MODULE m_temp; + int i=0; + VECTORCH * posPtr; + VECTORCH diff; + int massfact; + + #if SupportWindows95 + int mslpos; + SHAPEFRAGMENT * frags; + SHAPEFRAGMENTDESC * fragdesc; + #else + int frags = 0; + #endif + + if( (NumActiveBlocks > maxobjects-5) + || (NumActiveStBlocks > maxstblocks-5)) + return; + + if (!sbptr) + return; + + if (!sbptr->DynPtr) + return; + + if (!sbptr->SBdptr) + return; + + memset(&m_temp,0,sizeof(MODULE)); + + posPtr = &(sbptr->DynPtr->Position); + + +#if SupportWindows95 + mmbptr = &TempModuleMap; + + mslpos = sbptr->shapeIndex; + + if (mslpos < 0) + return; + + fragdesc = mainshapelist[mslpos]->sh_fragdesc; + + if(!fragdesc || !fragdesc->sh_fragsound) + { + Sound_Play(SID_EXPLOSION,"d",posPtr); + } + else + { + SHAPEFRAGMENTSOUND * fragsound=fragdesc->sh_fragsound; + if(fragsound->sound_loaded) + { + SOUND3DDATA s3d; + s3d.position = *posPtr; + s3d.inner_range = fragsound->inner_range; + s3d.outer_range = fragsound->outer_range; + s3d.velocity.vx = 0; + s3d.velocity.vy = 0; + s3d.velocity.vz = 0; + Sound_Play ((SOUNDINDEX)fragsound->sound_loaded->sound_num, "nvp", &s3d,fragsound->max_volume,fragsound->pitch); + //Sound_Play((SOUNDINDEX)fragsound->sound_loaded->sound_num,"d",posPtr); + } + } + + if (!fragdesc) + { + return; + } + frags=fragdesc->sh_frags; + massfact = ((ONE_FIXED / sbptr->DynPtr->Mass)>>2) + ((ONE_FIXED>>2)*3); + + + while (frags->ShapeIndex > 0) + { + mmbptr->MapShape = frags->ShapeIndex; + mmbptr->MapType = MapType_Default; + + for (i=0; iNumFrags; i++) + { + DYNAMICSBLOCK *dynPtr; + VECTORCH offset; + + m_temp.m_numlights = 0; + m_temp.m_lightarray = NULL; + m_temp.m_mapptr = mmbptr; + m_temp.m_sbptr = (STRATEGYBLOCK*)NULL; + m_temp.m_dptr = NULL; + AllocateModuleObject(&m_temp); + if(m_temp.m_dptr==NULL) return; /* patrick: cannot create displayblock, so just return (?) */ + + dispPtr = m_temp.m_dptr; + + dispPtr->ObMyModule = NULL; /* Module that created us */ + + offset.vx = frags->x_offset; + offset.vy = frags->y_offset; + offset.vz = frags->z_offset; + + if (offset.vx == 0 && offset.vy == 0 && offset.vz == 0) + { + // place the fragment randomly within the bounding box of the parent + offset.vx = generate_random_between (mainshapelist[mslpos]->shapemaxx, + mainshapelist[mslpos]->shapeminx); + + offset.vy = generate_random_between (mainshapelist[mslpos]->shapemaxy, + mainshapelist[mslpos]->shapeminy); + + offset.vz = generate_random_between (mainshapelist[mslpos]->shapemaxz, + mainshapelist[mslpos]->shapeminz); + } + + sbPtr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dispPtr); + if (sbPtr == 0) return; // Failed to allocate a strategy block + + sbPtr->I_SBtype = I_BehaviourFragment; + + sbPtr->SBdataptr = (ONE_SHOT_BEHAV_BLOCK *) AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK )); + + if (sbPtr->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(sbPtr); + return; + } + + ((ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = ((FastRandom()&32768)<<2) + 65535; + + dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEBRIS); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(sbPtr); + return; + } + + RotateVector (&offset, &(sbptr->DynPtr->OrientMat)); + + + if (sbptr->containingModule) + { + + if (frags->x_offset || frags->y_offset || frags->z_offset) + { + diff.vx = offset.vx; + diff.vy = offset.vy; + diff.vz = offset.vz; + } + else + { + diff.vx = sbptr->containingModule->m_mapptr->MapWorld.vx - posPtr->vx; + diff.vy = sbptr->containingModule->m_mapptr->MapWorld.vy - posPtr->vy; + diff.vz = sbptr->containingModule->m_mapptr->MapWorld.vz - posPtr->vz; + } + + + Normalise (&diff); + } + else + { + diff.vx = 0; + diff.vy = ONE_FIXED; + diff.vz = 0; + } + + + { + /*give fragment an impulse roughly in the direction of its offset*/ + VECTORCH impulse=offset; + + if(impulse.vx || impulse.vy || impulse.vz) + { + Normalise(&impulse); + + impulse.vx/=generate_random_between(5,10); + // impulse.vy/=generate_random_between(5,10); + impulse.vz/=generate_random_between(5,10); + } + dynPtr->LinImpulse=impulse; + } + + diff.vx = (diff.vx>>4); + diff.vy = (diff.vy>>4); + diff.vz = (diff.vz>>4); + + + offset.vx += posPtr->vx; + offset.vy += posPtr->vy; + offset.vz += posPtr->vz; + + dispPtr->ObWorld = offset; + dispPtr->ObMat = sbptr->DynPtr->OrientMat; + dispPtr->ObEuler = sbptr->DynPtr->OrientEuler; + + dynPtr->Position = offset; + + dynPtr->OrientMat = sbptr->DynPtr->OrientMat; + dynPtr->PrevOrientMat = sbptr->DynPtr->PrevOrientMat; + + dynPtr->OrientEuler = sbptr->DynPtr->OrientEuler; + dynPtr->PrevOrientEuler = sbptr->DynPtr->PrevOrientEuler; + + + + { + dynPtr->AngVelocity.EulerX = (((FastRandom()&2047)-1023))<<2; + dynPtr->AngVelocity.EulerY = (((FastRandom()&2047)-1023))<<2; + dynPtr->AngVelocity.EulerZ = (((FastRandom()&2047)-1023))<<2; + + dynPtr->LinImpulse.vy = - (FastRandom()&1023)<<2; + + /* Look to see if object has only one polygon in it; + if so it's probably a glass fragment, so don't bother + giving it collisions */ + if (dispPtr->ObShape) + { + SHAPEHEADER *shapePtr = GetShapeData(dispPtr->ObShape); + + if (shapePtr) + { + if (shapePtr->numitems!=1) + { + dynPtr->DynamicsType = DYN_TYPE_NRBB_COLLISIONS; + } + } + } + } + + } + + frags++; + } +#endif + +} + +DISPLAYBLOCK *MakeHierarchicalDebris(STRATEGYBLOCK *parent_sbPtr,SECTION_DATA *root, VECTORCH *positionPtr, MATRIXCH *orientation, int *wounds, int speed) +{ + + DISPLAYBLOCK *dispPtr; + STRATEGYBLOCK *sbPtr; + DYNAMICSBLOCK *dynPtr; + MODULEMAPBLOCK *mmbptr; + MODULE m_temp; + AVP_BEHAVIOUR_TYPE bhvr; + int woundflags; + + /* KJL 16:53:22 28/02/98 - this seems to happen a lot in multiplayer */ + if(positionPtr->vx>1000000 || positionPtr->vx<-1000000) + return NULL; + if(positionPtr->vy>1000000 || positionPtr->vy<-1000000) + return NULL; + if(positionPtr->vz>1000000 || positionPtr->vz<-1000000) + return NULL; + + if( (NumActiveBlocks > maxobjects-5) || (NumActiveStBlocks > maxstblocks-5)) return NULL; + + /* Right away, try to intercept all molotov cocktails! */ + GLOBALASSERT(root); + if ((root->flags§ion_data_notreal)==0) { + if (strcmp(root->sempai->Section_Name,"bottle")==0) { + /* Got one. */ + dispPtr=SpawnMolotovCocktail(root,orientation); + /* Correct speed. */ + if (dispPtr) { + dynPtr=dispPtr->ObStrategyBlock->DynPtr; + + /* This code CnP'd from further down! */ + dynPtr->AngVelocity.EulerX = (FastRandom()&2047)-1024; + dynPtr->AngVelocity.EulerY = (FastRandom()&2047)-1024; + dynPtr->AngVelocity.EulerZ = (FastRandom()&2047)-1024; + + { + int random = (FastRandom()&1023) - 512; + if (random>0) dynPtr->LinImpulse.vx=(random+100)<LinImpulse.vx=(random-100)<0) dynPtr->LinImpulse.vy=(random+100)<LinImpulse.vy=(random-100)<0) dynPtr->LinImpulse.vz=(random+100)<LinImpulse.vz=(random-100)<sempai->ShapeName); + CreateShapeInstance(mmbptr,"Shell"); + + bhvr = I_BehaviourHierarchicalFragment; + + // And allocate the modulemapblock object + + m_temp.m_numlights = 0; + m_temp.m_lightarray = NULL; + m_temp.m_mapptr = mmbptr; + m_temp.m_sbptr = (STRATEGYBLOCK*)NULL; + m_temp.m_dptr = NULL; + AllocateModuleObject(&m_temp); + dispPtr = m_temp.m_dptr; + if(dispPtr==NULL) return (DISPLAYBLOCK *)0; /* patrick: cannot create displayblock, so just return 0 */ + + dispPtr->ObMyModule = NULL; /* Module that created us */ + dispPtr->ObWorld = *positionPtr; + + sbPtr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dispPtr); + + if (sbPtr == 0) return (DISPLAYBLOCK *)0; // Failed to allocate a strategy block + + // 2. NOW set up the strategyblock-specific fields for + // the new displayblock. We won't go through the "AttachNew + // StrategyBlock" and "AssignRunTimeBehaviours" pair, since + // the first switches on ObShape and the second on bhvr; + // but, in this case, there isn't a particular connection + // between them. + + sbPtr->I_SBtype = bhvr; + + GLOBALASSERT(root); + + { + + sbPtr->SBdataptr = (HDEBRIS_BEHAV_BLOCK *) AllocateMem(sizeof(HDEBRIS_BEHAV_BLOCK)); + if (sbPtr->SBdataptr == 0) { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(sbPtr); + return (DISPLAYBLOCK*)NULL; + } + + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = HDEBRIS_LIFETIME; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->smokes=0; + + if (root->sempai->flags§ion_flag_gibbwhenfragged) { + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->GibbFactor=(ONE_FIXED>>1); + } else { + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->GibbFactor=0; + } + + /* Inheritance of android flag. */ + if (GetBloodType(parent_sbPtr)==PARTICLE_ANDROID_BLOOD) { + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Android=1; + } else { + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Android=0; + } + + woundflags=Splice_HModels(&(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),root); + + + if (parent_sbPtr) + { + /* Inherit fire! */ + if (parent_sbPtr->SBDamageBlock.IsOnFire) { + sbPtr->SBDamageBlock.IsOnFire=1; + } + /* KJL 11:28:27 14/10/98 - this is set so we can later know what the debris was part of */ + /* CDF 3/3/99 put it in the switch statement, to deal with complex cases */ + /* Creature specific code! */ + switch (parent_sbPtr->I_SBtype) { + case I_BehaviourAlien: + { + ALIEN_STATUS_BLOCK *alienStatusPointer; + /* See if we can strip to template. */ + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(parent_sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + /* Just go to spasm. */ + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_AlienStand,ASSS_Spasm,-1,1); + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = I_BehaviourAlien; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = alienStatusPointer->Type; + root->SecMat=*orientation; + + DoAlienLimbLossSound(positionPtr); + /* Last as long as a dead alien. */ + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = ALIEN_DYINGTIME; + break; + } + case I_BehaviourMarine: + { + SECTION *template_root; + SECTION *template_sempai; + MARINE_STATUS_BLOCK *marineStatusPointer; + /* See if we can strip to template. */ + marineStatusPointer = (MARINE_STATUS_BLOCK *)(parent_sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + template_root=GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,marineStatusPointer->My_Weapon->TemplateName); + /* Now, find the section that matches. */ + template_sempai=Get_Corresponding_Section_Recursive(template_root,(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController).Root_Section->Section_Name); + + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = I_BehaviourMarine; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = marineStatusPointer->My_Weapon->ARealMarine; + + if (template_sempai) { + /* We have a match! */ + Transmogrify_HModels(sbPtr,&(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController), + template_sempai, 1, 0,0); + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_MarineStand,MSSS_Spasm,-1,1); + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1; + //((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootRotation=1; + root->SecMat=*orientation; + MakeFleshRippingNoises(positionPtr); + } else { + /* Forget it. Must be a disembodied weapon, or something. */ + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0); + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1; + //((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootRotation=1; + + //dispPtr->ObMat=*orientation; + /* Below is an alternative... */ + root->SecMat=*orientation; + } + /* Since we're dealing with a marine, consider expressions. */ + { + TXACTRLBLK *tacb; + SECTION_DATA *head; + + head=GetThisSectionData(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.section_data,"head"); + if (head) { + if ((head->flags§ion_data_notreal)==0) { + + tacb=head->tac_ptr; + + while (tacb) { + tacb->tac_sequence = 4; + tacb->tac_txah_s = GetTxAnimHeaderFromShape(tacb, head->ShapeNum); + + tacb=tacb->tac_next; + } + } + } + } + /* Last as long as a dead marine. */ + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = MARINE_DYINGTIME; + } + break; + case I_BehaviourPredator: + { + SECTION *template_root; + SECTION *template_sempai; + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + /* See if we can strip to template. */ + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(parent_sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + template_root=GetNamedHierarchyFromLibrary("hnpcpredator","Template"); + /* Now, find the section that matches. */ + template_sempai=Get_Corresponding_Section_Recursive(template_root,(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController).Root_Section->Section_Name); + + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = I_BehaviourPredator; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = 0; + + if (template_sempai) { + /* We have a match! */ + Transmogrify_HModels(sbPtr,&(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController), + template_sempai, 1, 0,0); + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_PredatorStand,PSSS_Spasm,-1,1); + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1; + root->SecMat=*orientation; + } else { + /* Forget it. Must be a disembodied weapon, or something. */ + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0); + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1; + root->SecMat=*orientation; + } + /* Just freeze for now! */ + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.Playing=0; + /* Last as long as a dead predator. */ + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = PRED_DIETIME; + } + break; + + case I_BehaviourNetCorpse: + { + NETCORPSEDATABLOCK *corpseDataPtr = (NETCORPSEDATABLOCK *)parent_sbPtr->SBdataptr; + switch (corpseDataPtr->Type) { + case I_BehaviourAlien: + { + DoAlienLimbLossSound(positionPtr); + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_AlienStand,ASSS_Spasm,-1,1); + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = corpseDataPtr->subtype; + break; + } + case I_BehaviourMarine: + { + SECTION *template_root; + SECTION *template_sempai; + template_root=corpseDataPtr->TemplateRoot; + /* Now, find the section that matches. */ + template_sempai=Get_Corresponding_Section_Recursive(template_root,(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController).Root_Section->Section_Name); + + if (template_sempai) { + MakeFleshRippingNoises(positionPtr); + } + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_MarineStand,MSSS_Spasm,-1,1); + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = corpseDataPtr->ARealMarine; + break; + } + case I_BehaviourPredator: + { + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_PredatorStand,PSSS_Spasm,-1,1); + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = corpseDataPtr->subtype; + break; + } + default: + { + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0); + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = corpseDataPtr->subtype; + break; + } + } + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1; + root->SecMat=*orientation; + + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = corpseDataPtr->Type; + /* Inherit counter from parent corpse. */ + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = corpseDataPtr->timer; + break; + } + case I_BehaviourHierarchicalFragment: + { + HDEBRIS_BEHAV_BLOCK *debrisDataPtr = (HDEBRIS_BEHAV_BLOCK *)parent_sbPtr->SBdataptr; + switch (debrisDataPtr->Type) { + case I_BehaviourAlien: + { + DoAlienLimbLossSound(positionPtr); + /* Sound should be the same for all types of alien! */ + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_AlienStand,ASSS_Spasm,-1,1); + break; + } + case I_BehaviourMarine: + { + MakeFleshRippingNoises(positionPtr); + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_MarineStand,MSSS_Spasm,-1,1); + break; + } + case I_BehaviourPredator: + { + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_PredatorStand,PSSS_Spasm,-1,1); + break; + } + default: + { + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0); + break; + } + } + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1; + root->SecMat=*orientation; + + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = debrisDataPtr->Type; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = debrisDataPtr->SubType; + /* Inherit counter from parent debris. */ + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = debrisDataPtr->counter; + break; + } + + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *dataptr; + dataptr=parent_sbPtr->SBdataptr; + switch (dataptr->type) { + case I_BehaviourAlien: + { + DoAlienLimbLossSound(positionPtr); + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_AlienStand,ASSS_Spasm,-1,1); + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1; + root->SecMat=*orientation; + + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = I_BehaviourAlien; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = dataptr->subtype; + break; + } + case I_BehaviourNetCorpse: + { + switch (dataptr->subtype) { + case I_BehaviourAlien: + { + DoAlienLimbLossSound(positionPtr); + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_AlienStand,ASSS_Spasm,-1,1); + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1; + root->SecMat=*orientation; + + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = I_BehaviourAlien; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = dataptr->IOType; + break; + } + default: + { + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0); + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1; + root->SecMat=*orientation; + + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = parent_sbPtr->I_SBtype; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = 0; + break; + } + } + break; + } + default: + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0); + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1; + root->SecMat=*orientation; + + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = parent_sbPtr->I_SBtype; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = 0; + break; + } + } + break; + + default: + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0); + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1; + root->SecMat=*orientation; + + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = parent_sbPtr->I_SBtype; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = 0; + break; + } + } + else + { + /* KJL 11:27:54 14/10/98 - set behaviour type to null to avoid confusion */ + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = I_BehaviourNull; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = 0; + InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0); + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1; + //((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootRotation=1; + root->SecMat=*orientation; + } + + if (wounds) { + *wounds=woundflags; + } + + dispPtr->HModelControlBlock=&(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController); + + dispPtr->ObWorld=*positionPtr; + //dispPtr->ObMat=*orientation; + dispPtr->ObMat=Identity_RotMat; + + LOCALASSERT(dispPtr->ObWorld.vx<1000000 && dispPtr->ObWorld.vx>-1000000); + LOCALASSERT(dispPtr->ObWorld.vy<1000000 && dispPtr->ObWorld.vy>-1000000); + LOCALASSERT(dispPtr->ObWorld.vz<1000000 && dispPtr->ObWorld.vz>-1000000); + + dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ALIEN_DEBRIS); + + if (dynPtr == 0) { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(sbPtr); + return (DISPLAYBLOCK*)NULL; + } + + dynPtr->Position = *positionPtr; + + dynPtr->OrientMat=*orientation; + + dynPtr->UseDisplacement=0; + + dynPtr->LinVelocity.vx=0; + dynPtr->LinVelocity.vy=0; + dynPtr->LinVelocity.vz=0; + + dynPtr->Mass=50; + + #if 1 + // Give explosion fragments an angular velocity + dynPtr->AngVelocity.EulerX = (FastRandom()&2047)-1024; + dynPtr->AngVelocity.EulerY = (FastRandom()&2047)-1024; + dynPtr->AngVelocity.EulerZ = (FastRandom()&2047)-1024; + + { + int random = (FastRandom()&1023) - 512; + if (random>0) dynPtr->LinImpulse.vx=(random+100)<LinImpulse.vx=(random-100)<0) dynPtr->LinImpulse.vy=(random+100)<LinImpulse.vy=(random-100)<0) dynPtr->LinImpulse.vz=(random+100)<LinImpulse.vz=(random-100)<AngVelocity.EulerX = 0; + dynPtr->AngVelocity.EulerY = 0; + dynPtr->AngVelocity.EulerZ = 0; + + dynPtr->LinImpulse.vx=0; + dynPtr->LinImpulse.vy=0; + dynPtr->LinImpulse.vz=0; + #endif + + /* Set up default here for neatness. */ + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_NOSOUND; + /* Consider the bounce sound, by section name. */ + if (strcmp(root->sempai->Section_Name,"SADAR")==0) { + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_ED_LARGEWEAPONDROP; + dynPtr->Elasticity=(ONE_FIXED>>3); + } else if (strcmp(root->sempai->Section_Name,"gren stock")==0) { + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_ED_LARGEWEAPONDROP; + /* Grenade launchers aren't very bouncy. */ + } else if (strcmp(root->sempai->Section_Name,"flamer")==0) { + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_ED_LARGEWEAPONDROP; + } else if (strcmp(root->sempai->Section_Name,"spring one")==0) { + /* This is a smartgun! */ + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_ED_LARGEWEAPONDROP; + /* Whilst we're here... */ + dispPtr->ObMat=*orientation; + root->SecMat=Identity_RotMat; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootRotation=1; + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.Playing=0; + } else if (strcmp(root->sempai->Section_Name,"mini gun")==0) { + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_ED_LARGEWEAPONDROP; + } else if (strcmp(root->sempai->Section_Name,"flame thrower")==0) { + /* Civvie flamer... */ + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_ED_LARGEWEAPONDROP; + } else if (strcmp(root->sempai->Section_Name,"pulse mag")==0) { + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_NOSOUND; + /* Don't have a 'tink' yet... */ + dynPtr->Elasticity=(ONE_FIXED>>1); + } + + if (parent_sbPtr) { + if (parent_sbPtr->I_SBtype==I_BehaviourAutoGun) { + /* Always make a thump. */ + ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_ED_LARGEWEAPONDROP; + } + } + + ProveHModel(dispPtr->HModelControlBlock,dispPtr); + + } + + LOCALASSERT(dispPtr->ObWorld.vx<1000000 && dispPtr->ObWorld.vx>-1000000); + LOCALASSERT(dispPtr->ObWorld.vy<1000000 && dispPtr->ObWorld.vy>-1000000); + LOCALASSERT(dispPtr->ObWorld.vz<1000000 && dispPtr->ObWorld.vz>-1000000); + + return dispPtr; + +} +/* KJL 16:35:13 08/01/99 - make body ripping noises */ +void MakeFleshRippingNoises(VECTORCH *positionPtr) +{ + int s = FastRandom()%5; + + Sound_Play(SID_BODY_BEING_HACKED_UP_0+s,"d",positionPtr); +} + + +void Pop_Section(STRATEGYBLOCK *sbPtr,SECTION_DATA *section_data, VECTORCH *blastcentre, int *wounds) { + + int temp_wounds=0; + enum PARTICLE_ID blood_type; + /* 'Explode' this section, then frag off all it's children! */ + + GLOBALASSERT(section_data); + GLOBALASSERT(blastcentre); + + if ((section_data->sempai->flags§ion_sprays_anything)==0) { + blood_type=PARTICLE_NULL; + } else { + if (section_data->sempai->flags§ion_sprays_blood) { + blood_type=GetBloodType(sbPtr); + } else if (section_data->sempai->flags§ion_sprays_acid) { + blood_type=PARTICLE_ALIEN_BLOOD; + } else if (section_data->sempai->flags§ion_sprays_predoblood) { + blood_type=PARTICLE_PREDATOR_BLOOD; + } else if (section_data->sempai->flags§ion_sprays_sparks) { + blood_type=PARTICLE_SPARK; + } else { + blood_type=PARTICLE_NULL; + } + } + /* Right, should have a blood type set. Now, trim off the extra bits... */ + + if ((section_data->First_Child!=NULL) + &&( (section_data->flags§ion_data_terminate_here)==0)) { + + SECTION_DATA *child_ptr; + + child_ptr=section_data->First_Child; + + while (child_ptr!=NULL) { + + LOCALASSERT(child_ptr->My_Parent==section_data); + /* Please work! */ + MakeHierarchicalDebris(sbPtr,child_ptr,&child_ptr->World_Offset,&child_ptr->SecMat,&temp_wounds,2); + + (*wounds)|=temp_wounds; + + child_ptr=child_ptr->Next_Sibling; + } + + } + /* Okay. Now, call the explosion of blood. */ + + if ((section_data->sempai->Shape)&&(blood_type!=PARTICLE_NULL)) { + if (SUPERGORE_MODE) { + MakeBloodExplosion(§ion_data->World_Offset,section_data->sempai->Shape->shaperadius, + blastcentre,500,blood_type); + } else { + MakeBloodExplosion(§ion_data->World_Offset,section_data->sempai->Shape->shaperadius, + blastcentre,100,blood_type); + } + } + + /* Now trim off THIS bit, permanently. */ + + (*wounds)|=section_data->sempai->flags§ion_flags_wounding; + + section_data->flags|=section_data_notreal; + section_data->flags|=section_data_terminate_here; + /* ~Fin~ */ +} + +void HierarchicalFragmentBehaviour(STRATEGYBLOCK *sptr) +{ + /* CDF 5/3/99 A new function for all Hierarchical Fragments. */ + int a; + COLLISIONREPORT *reportptr; + HDEBRIS_BEHAV_BLOCK *hdbhv; + DYNAMICSBLOCK *dynPtr; + int bounce=0; + + GLOBALASSERT(sptr); + hdbhv = (HDEBRIS_BEHAV_BLOCK * ) sptr->SBdataptr; + GLOBALASSERT(sptr->SBdptr); + + dynPtr=sptr->DynPtr; + + GLOBALASSERT(dynPtr); + + reportptr=dynPtr->CollisionReportPtr; + + if (hdbhv->counter < 0) + { + DestroyAnyStrategyBlock(sptr); + return; + } + + { + DISPLAYBLOCK *dispPtr = sptr->SBdptr; + /* do we have a displayblock? */ + if (dispPtr) + { + dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND; + dispPtr->ObFlags2 = hdbhv->counter/2; + + } + } + + { + /* CDF 8/3/99 Added this on request... */ + if (hdbhv->counter<(HDEBRIS_LIFETIME-HDEBRIS_BLEEDING_TIME)) { + hdbhv->HModelController.DisableBleeding=1; + } + } + + hdbhv->counter -= NormalFrameTime; + + a=0; + + if (reportptr==NULL) { + hdbhv->bouncelastframe=0; + } + + while (reportptr) { + + if (SBIsEnvironment(reportptr->ObstacleSBPtr)) { + /* Hit environment. */ + bounce=1; + } + else if (reportptr->ObstacleSBPtr->SBdptr==Player) + { + /* Hurt the player on collision? */ + if (hdbhv->HModelController.Root_Section->flags§ion_sprays_acid) { + /* That's the test that used to be used... */ + CauseDamageToObject(Player->ObStrategyBlock,&TemplateAmmo[AMMO_ALIEN_FRAG].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + reportptr=reportptr->NextCollisionReportPtr; + } + + if (bounce&&(hdbhv->bouncelastframe==0)) { + if (hdbhv->Bounce_Sound!=SID_NOSOUND) { + Sound_Play(hdbhv->Bounce_Sound,"dp",&(dynPtr->Position),((FastRandom()&511)-255)); + } + hdbhv->bouncelastframe=1; + } + + { + if (dynPtr->IsInContactWithFloor==0) { + DynamicallyRotateObject(dynPtr); + } else { + dynPtr->AngVelocity.EulerX=0; + dynPtr->AngVelocity.EulerY=0; + dynPtr->AngVelocity.EulerZ=0; + } + } + +} + + + +/*-------------------------------** +** Load/Save hierarchical debris ** +**-------------------------------*/ + +typedef struct hier_debris_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + +//behaviour block stuff + int counter; + int smokes; + int GibbFactor; + int Android; + + AVP_BEHAVIOUR_TYPE Type; + int SubType; + + int bouncelastframe; + enum soundindex Bounce_Sound; + +//strategy block stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; + DYNAMICSBLOCK dynamics; +}HIER_DEBRIS_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV hdebrisStatusPointer + +void LoadStrategy_HierarchicalDebris(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + HIER_DEBRIS_SAVE_BLOCK* block = (HIER_DEBRIS_SAVE_BLOCK*) header; + HDEBRIS_BEHAV_BLOCK* hdebrisStatusPointer; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //We need to create the debris then. + { + MODULEMAPBLOCK *mmbptr; + MODULE m_temp; + DISPLAYBLOCK* dispPtr; + + // 1. Set up shape data BEFORE making the displayblock, + // since "AllocateModuleObject()" will fill in shapeheader + // information and extent data + + mmbptr = &TempModuleMap; + + /* Doesn't really matter what shape gets generated... */ + //CreateShapeInstance(mmbptr,root->sempai->ShapeName); + CreateShapeInstance(mmbptr,"Shell"); + + + // And allocate the modulemapblock object + + m_temp.m_numlights = 0; + m_temp.m_lightarray = NULL; + m_temp.m_mapptr = mmbptr; + m_temp.m_sbptr = (STRATEGYBLOCK*)NULL; + m_temp.m_dptr = NULL; + AllocateModuleObject(&m_temp); + dispPtr = m_temp.m_dptr; + if(dispPtr==NULL) return ; /* patrick: cannot create displayblock, so just return 0 */ + + dispPtr->ObMyModule = NULL; /* Module that created us */ + + sbPtr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dispPtr); + if (sbPtr == 0) return; // Failed to allocate a strategy block + sbPtr->I_SBtype = I_BehaviourHierarchicalFragment; + + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ALIEN_DEBRIS); + + //allocate behaviour block memory + sbPtr->SBdataptr = (HDEBRIS_BEHAV_BLOCK *) AllocateMem(sizeof(HDEBRIS_BEHAV_BLOCK)); + hdebrisStatusPointer = (HDEBRIS_BEHAV_BLOCK *) sbPtr->SBdataptr; + + memset(hdebrisStatusPointer,0,sizeof(*hdebrisStatusPointer)); + dispPtr->HModelControlBlock=&hdebrisStatusPointer->HModelController; + + } + + + //start copying stuff + + COPYELEMENT_LOAD(counter) + COPYELEMENT_LOAD(smokes) + COPYELEMENT_LOAD(GibbFactor) + COPYELEMENT_LOAD(Android) + COPYELEMENT_LOAD(Type) + COPYELEMENT_LOAD(SubType) + COPYELEMENT_LOAD(bouncelastframe) + COPYELEMENT_LOAD(Bounce_Sound) + + //copy strategy block stuff + *sbPtr->DynPtr = block->dynamics; + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + + //load hierarchy + { + SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); + if(hier_header) + { + LoadHierarchy(hier_header,&hdebrisStatusPointer->HModelController); + } + } + +} + +void SaveStrategy_HierarchicalDebris(STRATEGYBLOCK* sbPtr) +{ + HDEBRIS_BEHAV_BLOCK* hdebrisStatusPointer; + HIER_DEBRIS_SAVE_BLOCK* block; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + hdebrisStatusPointer = (HDEBRIS_BEHAV_BLOCK*) sbPtr->SBdataptr; + + //start copying stuff + + COPYELEMENT_SAVE(counter) + COPYELEMENT_SAVE(smokes) + COPYELEMENT_SAVE(GibbFactor) + COPYELEMENT_SAVE(Android) + COPYELEMENT_SAVE(Type) + COPYELEMENT_SAVE(SubType) + COPYELEMENT_SAVE(bouncelastframe) + COPYELEMENT_SAVE(Bounce_Sound) + + //save strategy block stuff + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; + + //save the hierarchy + SaveHierarchy(&hdebrisStatusPointer->HModelController); + +} + + + +/*------------------** +** Load/Save Debris ** +**------------------*/ +#include "savegame.h" + +typedef struct debris_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int counter; + + BOOL dynamicModuleObject; + + int shapeIndex; + int shapeNumPoints; + int shapeNumItems; + int shapeRadius; + + +//strategy block stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; + DYNAMICSBLOCK dynamics; + +}DEBRIS_SAVE_BLOCK; + + +STRATEGYBLOCK* MakeDebrisForLoad(int shapeIndex,int counter,BOOL dynamicModuleObject) +{ + DISPLAYBLOCK *dispPtr; + STRATEGYBLOCK *sbPtr; + MODULEMAPBLOCK *mmbptr; + MODULE m_temp; + + DYNAMICSBLOCK *dynPtr; + + if( (NumActiveBlocks > maxobjects-5) + || (NumActiveStBlocks > maxstblocks-5)) + return NULL; + + + memset(&m_temp,0,sizeof(MODULE)); + + mmbptr = &TempModuleMap; + + + mmbptr->MapShape = shapeIndex; + mmbptr->MapType = MapType_Default; + + + m_temp.m_numlights = 0; + m_temp.m_lightarray = NULL; + m_temp.m_mapptr = mmbptr; + m_temp.m_sbptr = (STRATEGYBLOCK*)NULL; + m_temp.m_dptr = NULL; + AllocateModuleObject(&m_temp); + if(m_temp.m_dptr==NULL) return NULL; /* patrick: cannot create displayblock, so just return (?) */ + + dispPtr = m_temp.m_dptr; + + dispPtr->ObMyModule = NULL; /* Module that created us */ + + + sbPtr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dispPtr); + if (sbPtr == 0) return NULL; // Failed to allocate a strategy block + + sbPtr->I_SBtype = I_BehaviourFragment; + + sbPtr->SBdataptr = (ONE_SHOT_BEHAV_BLOCK *) AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK )); + + if (sbPtr->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(sbPtr); + return NULL; + } + + ((ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = counter; + + dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEBRIS); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(sbPtr); + return NULL; + } + + if(dynamicModuleObject) + { + dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + } + return sbPtr; +} + + +void LoadStrategy_Debris(SAVE_BLOCK_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + DEBRIS_SAVE_BLOCK* block = (DEBRIS_SAVE_BLOCK*)header; + + //check the size + if(block->header.size != sizeof(*block)) return; + + { + SHAPEHEADER* shp = GetShapeData(block->shapeIndex); + + //check that the shape at shapeIndex is correct + if(!shp) return; + + if(shp->numitems!=block->shapeNumItems) return; + if(shp->numpoints!=block->shapeNumPoints) return; + if(shp->shaperadius!=block->shapeRadius) return; + + sbPtr = MakeDebrisForLoad(block->shapeIndex,block->counter,block->dynamicModuleObject); + if(!sbPtr) return; + } + +//strategy block stuff + *sbPtr->DynPtr = block->dynamics; + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + + +} + +void SaveStrategy_Debris(STRATEGYBLOCK* sbPtr) +{ + SHAPEHEADER* shp; + DEBRIS_SAVE_BLOCK* block; + ONE_SHOT_BEHAV_BLOCK* behav = (ONE_SHOT_BEHAV_BLOCK*)sbPtr->SBdataptr; + + if(!sbPtr->SBdptr) return; + if(!sbPtr->SBdptr->ObShapeData) return; + shp = sbPtr->SBdptr->ObShapeData; + + + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + block->counter = behav->counter; + block->shapeIndex = sbPtr->SBdptr->ObShape; + block->dynamicModuleObject = (sbPtr->SBdptr->ObFlags3 & ObFlag3_DynamicModuleObject)!=0; + + block->shapeNumPoints = shp->numpoints; + block->shapeNumItems = shp->numitems; + block->shapeRadius = shp->shaperadius; + + +//strategy block stuff + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; + +} \ No newline at end of file diff --git a/3dc/avp/Bh_marin.c b/3dc/avp/Bh_marin.c new file mode 100644 index 0000000..5a9d21f --- /dev/null +++ b/3dc/avp/Bh_marin.c @@ -0,0 +1,19113 @@ +/*------------------------Patrick 2/7/97----------------------------- + Source file for Marine and Seal AI behaviour functions.... + --------------------------------------------------------------------*/ +#include "3dc.h" + +#include "inline.h" +#include "module.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "comp_shp.h" +#include "dynblock.h" +#include "dynamics.h" +#include "lighting.h" + +#include "pfarlocs.h" +#include "pvisible.h" +#include "pheromon.h" +#include "bh_gener.h" +#include "bh_far.h" +#include "bh_pred.h" +#include "bh_marin.h" +#include "bh_weap.h" +#include "bh_debri.h" +#include "bh_alien.h" +#include "psnd.h" +#include "weapons.h" +#include "load_shp.h" +#include "particle.h" +#include "sfx.h" +#include "huddefs.h" +#include "pldghost.h" +#include "pldnet.h" +#include "psndplat.h" +#include "AI_Sight.h" +#include "los.h" +#include "bh_corpse.h" +#include "bh_dummy.h" +#include "scream.h" + +#include "dxlog.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +#include "sequnces.h" +#include "ShowCmds.h" +#include "extents.h" +#include "AvP_UserProfile.h" + +#define ALL_PULSERIFLES 0 +#define MOTIONTRACKERS 0 +#define ANARCHY 0 +#define PISTOL_CLIP_SIZE 8 +#define SENTRY_SENSITIVITY 1500 +#define MARINE_AUTODETECT_RANGE 2500 + +#define SUSPECT_SENSITIVITY 2100 +/* Ten centimetres. It can make a lot of difference. */ + +#define ALL_NEW_AVOIDANCE (1) +#define TWO_PISTOL_GUY (1) + +/* external global variables used in this file */ +extern int ModuleArraySize; +extern char *ModuleCurrVisArray; +extern int NormalFrameTime; +extern unsigned char Null_Name[8]; +extern ACTIVESOUNDSAMPLE ActiveSounds[]; +extern int CurrentLightAtPlayer; + +extern int AIModuleArraySize; +extern AIMODULE *AIModuleArray; +extern DAMAGE_PROFILE FallingDamage; + +extern enum PARTICLE_ID GetBloodType(STRATEGYBLOCK *sbPtr); +extern HIERARCHY_SHAPE_REPLACEMENT* GetHierarchyAlternateShapeSetFromLibrary(const char* rif_name,const char* shape_set_name); +extern HIERARCHY_VARIANT_DATA* GetHierarchyAlternateShapeSetCollectionFromLibrary(const char* rif_name,int collection_index); +extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); +extern STRATEGYBLOCK* CreateGrenadeKernel(AVP_BEHAVIOUR_TYPE behaviourID, VECTORCH *position, MATRIXCH *orient,int fromplayer); +extern STRATEGYBLOCK* CreateRocketKernel(VECTORCH *position, MATRIXCH *orient,int fromplayer); +extern STRATEGYBLOCK* CreateFrisbeeKernel(VECTORCH *position, MATRIXCH *orient, int fromplayer); +extern int AlienPCIsCurrentlyVisible(int checktime,STRATEGYBLOCK *sbPtr); +extern int ObjectShouldAppearOnMotionTracker(STRATEGYBLOCK *sbPtr); +extern int SBIsEnvironment(STRATEGYBLOCK *sbPtr); +void Marine_SwitchExpression(STRATEGYBLOCK *sbPtr,int state); + +extern void PrintSpottedNumber(void); + +/* prototypes for this file */ +static STATE_RETURN_CONDITION Execute_MFS_Wait(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MFS_Hunt(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MFS_Wander(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MFS_Approach(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MFS_Firing(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MFS_Return(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MFS_Pathfinder(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MFS_Avoidance(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MFS_SentryMode(STRATEGYBLOCK *sbPtr); + +static STATE_RETURN_CONDITION Execute_MNS_Approach(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_Avoidance(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_Wander(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_Wait(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_DischargeLOSWeapon(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_DischargeShotgun(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_DischargePistol(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_DischargeGL(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_DischargeSADAR(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_DischargeFlamethrower(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_ThrowMolotov(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_DischargeMinigun(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_SentryMode(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_Hunt(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_Respond(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_Retreat(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_Return(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_Pathfinder(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_Taunting(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_Reloading(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_GetWeapon(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_NewDischargeGL(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_DischargeSmartgun(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_PanicReloading(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_DischargeTwoPistols(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_DischargeSkeeter(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_AcidAvoidance(STRATEGYBLOCK *sbPtr); + +static void MarineMisfireFlameThrower(SECTION_DATA *muzzle, int *timer); +static STATE_RETURN_CONDITION Execute_MNS_NullPanicFire(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_PanicFireLOSWeapon(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_PanicFireFlamethrower(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_PanicFireGL(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_PanicFireMinigun(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_PanicFirePistol(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_PanicFireShotgun(STRATEGYBLOCK *sbPtr); +static STATE_RETURN_CONDITION Execute_MNS_PanicFireUnarmed(STRATEGYBLOCK *sbPtr); + +void NPC_Maintain_Minigun(STRATEGYBLOCK *sbPtr, DELTA_CONTROLLER *mgd); +void Marine_AssumePanicExpression(STRATEGYBLOCK *sbPtr); + +static void Execute_Dying(STRATEGYBLOCK *sbPtr); /* used for near and far */ + +static void ProcessFarMarineTargetModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule); +static void LobAGrenade(STRATEGYBLOCK *sbPtr); +static void CreateMarineGunFlash(STRATEGYBLOCK *sbPtr); + +static void MarineFireFlameThrower(STRATEGYBLOCK *sbPtr); + +static void Marine_ConsiderFallingDamage(STRATEGYBLOCK *sbPtr); +static void Marine_MirrorSuspectPoint(STRATEGYBLOCK *sbPtr); +static int MarineCanSeeTarget(STRATEGYBLOCK *sbPtr); +static int MarineCanSeeObject(STRATEGYBLOCK *sbPtr,STRATEGYBLOCK *target); +static int MarineIsAwareOfTarget(STRATEGYBLOCK *sbPtr); +static int MarineShouldBeCrawling(STRATEGYBLOCK *sbPtr); +static int MarineRetreatsInTheFaceOfDanger(STRATEGYBLOCK *sbPtr); +static void SetMarineAnimationSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweening); +static void SetMarineAnimationSequence_Null(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweening); +void Marine_Enter_Respond_State(STRATEGYBLOCK *sbPtr); + +int SpeedRangeMods(VECTORCH *range,VECTORCH *speed); +STRATEGYBLOCK *Marine_GetNewTarget(VECTORCH *marinepos, STRATEGYBLOCK *me); +void FakeTrackerWheepGenerator(VECTORCH *marinepos, STRATEGYBLOCK *me); + +void InitMission(STRATEGYBLOCK *sbPtr,MARINE_MISSION mission); + +void WanderMission_Control(STRATEGYBLOCK *sbPtr); +void PathfinderMission_Control(STRATEGYBLOCK *sbPtr); +void GuardMission_Control(STRATEGYBLOCK *sbPtr); +void LocalGuardMission_Control(STRATEGYBLOCK *sbPtr); +void LoiterMission_Control(STRATEGYBLOCK *sbPtr); +void RunAroundOnFireMission_Control(STRATEGYBLOCK *sbPtr); + +void WanderMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result); +void PathfinderMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result); +void GuardMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result); +void LocalGuardMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result); +void LoiterMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result); + +void Marine_Enter_SentryMode_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_Wait_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_Firing_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_Avoidance_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_Wander_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_Approach_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_Hunt_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_Retreat_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_Return_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_Pathfinder_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_Taunt_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_PanicFire_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_Reload_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_PumpAction_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_PullPistol_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_OneArmShotgun_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_OneArmPistol_State(STRATEGYBLOCK *sbPtr); +void Marine_Enter_PanicReload_State(STRATEGYBLOCK *sbPtr); + +void Marine_Activate_AcidAvoidance_State(STRATEGYBLOCK *sbPtr, VECTORCH *incidence); + +void Marine_QueueNeutralExpression(STRATEGYBLOCK *sbPtr); +void Marine_QueueGrimaceExpression(STRATEGYBLOCK *sbPtr); +void Marine_QueuePanicExpression(STRATEGYBLOCK *sbPtr); +void Marine_QueueWink1Expression(STRATEGYBLOCK *sbPtr); +void Marine_QueueWink2Expression(STRATEGYBLOCK *sbPtr); +int Marine_HasHisMouthOpen(STRATEGYBLOCK *sbPtr); +void Marine_UpdateFace(STRATEGYBLOCK *sbPtr); + +void Marine_MuteVoice(STRATEGYBLOCK *sbPtr); +void Marine_WoundedScream(STRATEGYBLOCK *sbPtr); +void Marine_AcidScream(STRATEGYBLOCK *sbPtr); +void Marine_BurningScream(STRATEGYBLOCK *sbPtr); +void Marine_DeathScream(STRATEGYBLOCK *sbPtr); +void Marine_ElectrocutionScream(STRATEGYBLOCK *sbPtr); +void Marine_BurningDeathScream(STRATEGYBLOCK *sbPtr); +void Marine_AngryScream(STRATEGYBLOCK *sbPtr); +void Marine_PanicScream(STRATEGYBLOCK *sbPtr); +void Marine_OoophSound(STRATEGYBLOCK *sbPtr); +void Marine_SurpriseSound(STRATEGYBLOCK *sbPtr); +void Marine_Sobbing(STRATEGYBLOCK *sbPtr); +void Marine_TauntShout(STRATEGYBLOCK *sbPtr); + +void NPC_GetBimbleTarget(STRATEGYBLOCK *sbPtr,VECTORCH *output); +void CreateMarineBot(VECTORCH *Position,int weapon); +void Convert_To_RunningOnFire(STRATEGYBLOCK *sbPtr); +void GetPointToFaceMarineTowards(STRATEGYBLOCK *sbPtr,VECTORCH *output); +void DoMarineHearing(STRATEGYBLOCK *sbPtr); + +static void HandleWaitingAnimations(STRATEGYBLOCK *sbPtr); +static void HandleMovingAnimations(STRATEGYBLOCK *sbPtr); +int MakeModifiedTargetNum(int targetnum,int dist); + + +/* Console Variables */ + +int Marine_Skill=20000; +int Marine_Terminal_Velocity=20000; + +/* Console Variables */ + +MARINE_WEAPON_DATA NPC_Marine_Weapons[] = { + { + MNPCW_PulseRifle, /* ID */ + SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */ + + Execute_MNS_DischargeLOSWeapon, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_PanicFireLOSWeapon, /* WeaponPanicFireFunction */ + "hnpcmarine", /* Riffname */ + "marine with pulse rifle", /* HierarchyName */ + "dum flash", /* GunflashName */ + "pulse rifle", /* ElevationSection */ + "marine with pulse rifle", /* HitLocationTableName */ + "Template", /* TemplateName */ + "pulse mag", /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 0, /* Accuracy */ + 1000*65536/60, /* Firing Rate */ + MARINE_NEAR_FIRE_TIME, /* Firing Time */ + 10, /* MinimumBurstSize */ + AMMO_10MM_CULW_NPC, /* Ammo profile */ + 99, /* clip_size */ + MSSS_Reload, /* Reload_Sequence */ + 300, /* TargetCallibrationShift */ + SID_NOSOUND, /* StartSound */ + SID_PULSE_LOOP, /* LoopSound */ + SID_NOSOUND, /* EndSound */ + 1, /* Enable Grenades */ + 1, /* UseElevation */ + 1, /* EnableTracker */ + 1, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_Flamethrower, /* ID */ + SFX_NONE, /* enum SFX_ID SfxID; */ + Execute_MNS_DischargeFlamethrower, /* Func. */ + MarineMisfireFlameThrower, /* Misfire func. */ + Execute_MNS_PanicFireFlamethrower, /* WeaponPanicFireFunction */ + "hnpcmarine", /* Riffname */ + "marine with flame thrower", /* HierarchyName */ + "dum flash", /* GunflashName */ + "flamer", /* ElevationSection */ + "marine with flame thrower", /* HitLocationTableName */ + "Template", /* TemplateName */ + "flamer mag", /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + 5000, /* ForceFireRange (Fire if closer) */ + 10000, /* MaxRange (Don't fire if further) */ + ONE_FIXED, /* Accuracy */ + 200, /* Firing Rate */ + MARINE_NEAR_FIRE_TIME<<2, /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_FLAMETHROWER, /* Ammo profile */ + (ONE_FIXED*3), /* clip_size */ + MSSS_Reload, /* Reload_Sequence */ + 0, /* TargetCallibrationShift */ + SID_INCIN_START, /* StartSound */ + SID_INCIN_LOOP, /* LoopSound */ + SID_INCIN_END, /* EndSound */ + 0, /* Enable Grenades */ + 1, /* UseElevation */ + 1, /* EnableTracker */ + 1, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_Smartgun, /* ID */ + SFX_MUZZLE_FLASH_SMARTGUN, /* enum SFX_ID SfxID; */ + Execute_MNS_DischargeSmartgun, /* Func. Changed from DischargeLOSWeapon! */ + NULL, /* Misfire func. */ + Execute_MNS_PanicFireLOSWeapon, /* WeaponPanicFireFunction */ + "hnpcmarine", /* Riffname */ + "marine with smart gun", /* HierarchyName */ + "dum flash", /* GunflashName */ + "smart gun", /* ElevationSection */ + "marine with smart gun", /* HitLocationTableName */ + "Template", /* TemplateName */ + "smart mag", /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + 36000, /* MaxRange (Don't fire if further) */ + ONE_FIXED, /* Accuracy */ + 50*65536, /* Firing Rate */ + MARINE_NEAR_FIRE_TIME, /* Firing Time */ + 50, /* MinimumBurstSize */ + AMMO_SMARTGUN_NPC, /* Ammo profile */ + 300, /* clip_size */ + MSSS_Reload, /* Reload_Sequence */ + 0, /* TargetCallibrationShift */ + SID_NOSOUND, /* StartSound */ + SID_SMART1, /* LoopSound */ + SID_NOSOUND, /* EndSound */ + 0, /* Enable Grenades */ + 1, /* UseElevation */ + 1, /* EnableTracker */ + 1, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_SADAR, /* ID */ + SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */ + + Execute_MNS_DischargeSADAR, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_NullPanicFire, /* WeaponPanicFireFunction */ + "hnpcmarine", /* Riffname */ + "marine with SADAR", /* HierarchyName */ + "dum flame", /* GunflashName */ + "SADAR Tube", /* ElevationSection */ + "marine with pulse rifle", /* HitLocationTableName */ + "Template", /* TemplateName */ + "SADAR", /* ClipName */ + 5000, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 0, /* Accuracy */ + 1000*65536/60, /* Firing Rate */ + MARINE_NEAR_FIRE_TIME, /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_10MM_CULW, /* Ammo profile */ + 1, /* clip_size */ + MSSS_Reload, /* Reload_Sequence */ + 300, /* TargetCallibrationShift */ + SID_ROCKFIRE, /* StartSound */ + SID_NOSOUND, /* LoopSound */ + SID_NOSOUND, /* EndSound */ + 1, /* Enable Grenades */ + 1, /* UseElevation */ + 1, /* EnableTracker */ + 1, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_GrenadeLauncher, /* ID */ + SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */ + + Execute_MNS_NewDischargeGL, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_PanicFireGL, /* WeaponPanicFireFunction */ + "hnpcmarine", /* Riffname */ + "marine + grenade launcher", /* HierarchyName */ + "dum flash", /* GunflashName */ + "gren stock", /* ElevationSection */ + "marine with pulse rifle", /* HitLocationTableName */ + "Template", /* TemplateName */ + "gren mag", /* ClipName */ + 9000, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 0, /* Accuracy */ + 1000*65536/60, /* Firing Rate */ + MARINE_NEAR_FIRE_TIME, /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_10MM_CULW, /* Ammo profile */ + 6, /* clip_size */ + MSSS_Reload, /* Reload_Sequence */ + 0, /* TargetCallibrationShift */ + SID_ROCKFIRE, /* StartSound */ + SID_NOSOUND, /* LoopSound */ + SID_NOSOUND, /* EndSound */ + 1, /* Enable Grenades */ + 1, /* UseElevation */ + 1, /* EnableTracker */ + 1, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_Minigun, /* ID */ + SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */ + + Execute_MNS_DischargeMinigun, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_PanicFireMinigun, /* WeaponPanicFireFunction */ + "hnpcmarine", /* Riffname */ + "Marine with Mini Gun", /* HierarchyName */ + "dum flash", /* GunflashName */ + "mini gun", /* ElevationSection */ + "marine with pulse rifle", /* HitLocationTableName */ + "Template", /* TemplateName */ + "mini mag", /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 0, /* Accuracy */ + 100*65536, /* Firing Rate */ + MARINE_NEAR_FIRE_TIME, /* Firing Time */ + MINIGUN_MINIMUM_BURST, /* MinimumBurstSize */ + AMMO_MINIGUN_NPC, /* Ammo profile */ + 500, /* clip_size */ + MSSS_Reload, /* Reload_Sequence */ + 0, /* TargetCallibrationShift */ + SID_NOSOUND, /* StartSound */ + SID_MINIGUN_LOOP, /* LoopSound */ + SID_MINIGUN_END, /* EndSound */ + 0, /* Enable Grenades */ + 1, /* UseElevation */ + 1, /* EnableTracker */ + 1, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_PistolMarine, /* ID */ + SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */ + + Execute_MNS_DischargePistol, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_PanicFirePistol, /* WeaponPanicFireFunction */ + "hnpcmarine", /* Riffname */ + "PISTOL", /* HierarchyName */ + "dum flash", /* GunflashName */ + "Rbicep", /* ElevationSection */ + "marine with pulse rifle", /* HitLocationTableName */ + "Template", /* TemplateName */ + NULL, /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 30000, /* Accuracy */ + 1, /* Firing Rate */ + MARINE_NEAR_FIRE_TIME, /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_MARINE_PISTOL, /* Ammo profile */ + 12, /* clip_size */ + MSSS_Reload, /* Reload_Sequence */ + 250, /* TargetCallibrationShift */ + SID_SHOTGUN, /* StartSound */ + SID_NOSOUND, /* LoopSound */ + SID_NOSOUND, /* EndSound */ + 0, /* Enable Grenades */ + 1, /* UseElevation */ + 0, /* EnableTracker */ + 1, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_MShotgun, /* ID */ + SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */ + + Execute_MNS_DischargeShotgun, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_PanicFireShotgun, /* WeaponPanicFireFunction */ + "hnpc_civvie", /* Riffname */ + "male_shotgun", /* HierarchyName */ + "flash dummy", /* GunflashName */ + "shot gun", /* ElevationSection */ + "male civvie", /* HitLocationTableName */ + "TEMPLATE", /* TemplateName */ + NULL, /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 0, /* Accuracy */ + 1, /* Firing Rate */ + -1, /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_SHOTGUN, /* Ammo profile */ + 8, /* clip_size */ + MSSS_Reload, /* Reload_Sequence */ + 0, /* TargetCallibrationShift */ + SID_SHOTGUN, /* StartSound */ + SID_NOSOUND, /* LoopSound */ + SID_NOSOUND, /* EndSound */ + 0, /* Enable Grenades */ + 1, /* UseElevation */ + 0, /* EnableTracker */ + 0, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_MPistol, /* ID */ + SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */ + + Execute_MNS_DischargePistol, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_PanicFirePistol, /* WeaponPanicFireFunction */ + "hnpc_civvie", /* Riffname */ + "male_pistol", /* HierarchyName */ + "flash dummy", /* GunflashName */ + "male right bicep", /* ElevationSection */ + "male civvie", /* HitLocationTableName */ + "TEMPLATE", /* TemplateName */ + NULL, /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 10000, /* Accuracy */ + 1, /* Firing Rate */ + MARINE_NEAR_FIRE_TIME, /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_10MM_CULW_NPC, /* Ammo profile */ + PISTOL_CLIP_SIZE, /* clip_size */ + MSSS_Reload, /* Reload_Sequence */ + 0, /* TargetCallibrationShift */ + SID_SHOTGUN, /* StartSound */ + SID_NOSOUND, /* LoopSound */ + SID_NOSOUND, /* EndSound */ + 0, /* Enable Grenades */ + 1, /* UseElevation */ + 0, /* EnableTracker */ + 0, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_MFlamer, /* ID */ + SFX_NONE, /* enum SFX_ID SfxID; */ + Execute_MNS_DischargeFlamethrower, /* Func. */ + MarineMisfireFlameThrower, /* Misfire func. */ + Execute_MNS_PanicFireFlamethrower, /* WeaponPanicFireFunction */ + "hnpc_civvie", /* Riffname */ + "male_flamer", /* HierarchyName */ + "flash dummy", /* GunflashName */ + "male right bicep", /* ElevationSection */ + "male civvie", /* HitLocationTableName */ + "TEMPLATE", /* TemplateName */ + "flame canaster", /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + 5000, /* ForceFireRange (Fire if closer) */ + 10000, /* MaxRange (Don't fire if further) */ + ONE_FIXED, /* Accuracy */ + 200, /* Firing Rate */ + MARINE_NEAR_FIRE_TIME<<2, /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_FLAMETHROWER, /* Ammo profile */ + (ONE_FIXED*2), /* clip_size */ + MSSS_Reload, /* Reload_Sequence */ + 0, /* TargetCallibrationShift */ + SID_INCIN_START, /* StartSound */ + SID_INCIN_LOOP, /* LoopSound */ + SID_INCIN_END, /* EndSound */ + 0, /* Enable Grenades */ + 1, /* UseElevation */ + 0, /* EnableTracker */ + 0, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_MUnarmed, /* ID */ + SFX_NONE, /* enum SFX_ID SfxID; */ + + NULL, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_PanicFireUnarmed, /* WeaponPanicFireFunction */ + "hnpc_civvie", /* Riffname */ + "male_unarmed", /* HierarchyName */ + NULL, /* GunflashName */ + NULL, /* ElevationSection */ + "male civvie", /* HitLocationTableName */ + "TEMPLATE", /* TemplateName */ + NULL, /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 0, /* Accuracy */ + 1, /* Firing Rate */ + MARINE_NEAR_FIRE_TIME, /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_NONE, /* Ammo profile */ + -1, /* clip_size */ + MSSS_Standard, /* Reload_Sequence */ + 0, /* TargetCallibrationShift */ + SID_NOSOUND, /* StartSound */ + SID_NOSOUND, /* LoopSound */ + SID_NOSOUND, /* EndSound */ + 0, /* Enable Grenades */ + 0, /* UseElevation */ + 0, /* EnableTracker */ + 0, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_MMolotov, /* ID */ + SFX_NONE, /* enum SFX_ID SfxID; */ + + Execute_MNS_ThrowMolotov, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_NullPanicFire, /* WeaponPanicFireFunction */ + "hnpc_civvie", /* Riffname */ + "male_bottle", /* HierarchyName */ + "bottle", /* GunflashName */ + NULL, /* ElevationSection */ + "male civvie", /* HitLocationTableName */ + "TEMPLATE", /* TemplateName */ + NULL, /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + 10000, /* MaxRange (Don't fire if further) */ + -10000, /* Accuracy */ + 1, /* Firing Rate */ + MARINE_NEAR_FIRE_TIME, /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_10MM_CULW, /* Ammo profile */ + -1, /* clip_size */ + MSSS_Standard, /* Reload_Sequence */ + 0, /* TargetCallibrationShift */ + SID_NOSOUND, /* StartSound */ + SID_NOSOUND, /* LoopSound */ + SID_NOSOUND, /* EndSound */ + 0, /* Enable Grenades */ + 0, /* UseElevation */ + 0, /* EnableTracker */ + 0, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_Android, /* ID */ + SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */ + + Execute_MNS_DischargeShotgun, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_PanicFireShotgun, /* WeaponPanicFireFunction */ + "hnpc_civvie", /* Riffname */ + "Android shotgun", /* HierarchyName */ + "flash dummy", /* GunflashName */ + "shot gun", /* ElevationSection */ + "male civvie", /* HitLocationTableName */ + "Android template", /* TemplateName */ + NULL, /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 0, /* Accuracy */ + 1, /* Firing Rate */ + -1, /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_SHOTGUN, /* Ammo profile */ + 8, /* clip_size */ + MSSS_Reload, /* Reload_Sequence */ + 0, /* TargetCallibrationShift */ + SID_SHOTGUN, /* StartSound */ + SID_NOSOUND, /* LoopSound */ + SID_NOSOUND, /* EndSound */ + 0, /* Enable Grenades */ + 1, /* UseElevation */ + 0, /* EnableTracker */ + 0, /* ARealMarine */ + 1, /* Android */ + }, + { + MNPCW_AndroidSpecial, /* ID */ + SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */ + + Execute_MNS_DischargeShotgun, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_PanicFireShotgun, /* WeaponPanicFireFunction */ + "hnpc_civvie", /* Riffname */ + "Android Shotgun Special", /* HierarchyName */ + "flash dummy", /* GunflashName */ + "male right bicep", /* ElevationSection */ + "male civvie", /* HitLocationTableName */ + "Android template", /* TemplateName */ + NULL, /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 0, /* Accuracy */ + 1, /* Firing Rate */ + -1, /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_SHOTGUN, /* Ammo profile */ + 8, /* clip_size */ + MSSS_Reload, /* Reload_Sequence */ + 0, /* TargetCallibrationShift */ + SID_SHOTGUN, /* StartSound */ + SID_NOSOUND, /* LoopSound */ + SID_NOSOUND, /* EndSound */ + 0, /* Enable Grenades */ + 1, /* UseElevation */ + 0, /* EnableTracker */ + 0, /* ARealMarine */ + 1, /* Android */ + }, + { + MNPCW_Android_Pistol_Special, /* ID */ + SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */ + + Execute_MNS_DischargePistol, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_PanicFirePistol, /* WeaponPanicFireFunction */ + "hnpc_civvie", /* Riffname */ + "Android Pistol Special", /* HierarchyName */ + "flash dummy", /* GunflashName */ + "male right bicep", /* ElevationSection */ + "male civvie", /* HitLocationTableName */ + "Android template", /* TemplateName */ + NULL, /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 10000, /* Accuracy */ + 1, /* Firing Rate */ + MARINE_NEAR_FIRE_TIME, /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_10MM_CULW_NPC, /* Ammo profile */ + PISTOL_CLIP_SIZE, /* clip_size */ + MSSS_Reload, /* Reload_Sequence */ + 0, /* TargetCallibrationShift */ + SID_SHOTGUN, /* StartSound */ + SID_NOSOUND, /* LoopSound */ + SID_NOSOUND, /* EndSound */ + 0, /* Enable Grenades */ + 1, /* UseElevation */ + 0, /* EnableTracker */ + 0, /* ARealMarine */ + 1, /* Android */ + }, + { + MNPCW_TwoPistols, /* ID */ + SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */ + + Execute_MNS_DischargeTwoPistols, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_PanicFirePistol, /* WeaponPanicFireFunction */ + "hnpcmarine", /* Riffname */ + "Two Pistol", /* HierarchyName */ + "dum flash", /* GunflashName */ + "Rbicep", /* ElevationSection */ + "marine with pulse rifle", /* HitLocationTableName */ + "Template", /* TemplateName */ + NULL, /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 30000, /* Accuracy */ + 12, /* Firing Rate */ + (MARINE_NEAR_FIRE_TIME>>2), /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_MARINE_PISTOL, /* Ammo profile */ + 24, /* clip_size */ + MSSS_Reload, /* Reload_Sequence */ + 250, /* TargetCallibrationShift */ + SID_SHOTGUN, /* StartSound */ + SID_NOSOUND, /* LoopSound */ + SID_NOSOUND, /* EndSound */ + 0, /* Enable Grenades */ + 1, /* UseElevation */ + 0, /* EnableTracker */ + 1, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_Skeeter, /* ID */ + SFX_MUZZLE_FLASH_SKEETER, /* enum SFX_ID SfxID; */ + + Execute_MNS_DischargeSkeeter, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_NullPanicFire, /* WeaponPanicFireFunction */ + "hnpcmarine", /* Riffname */ + "skeeter", /* HierarchyName */ + "dum flash", /* GunflashName */ + "Skeeter Tube", /* ElevationSection */ + "marine with pulse rifle", /* HitLocationTableName */ + "Template", /* TemplateName */ + "Skeeter", /* ClipName */ + 5000, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 0, /* Accuracy */ + ONE_FIXED, /* Firing Rate */ + 1625*65536/2000, /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_10MM_CULW, /* Ammo profile */ + 1, /* clip_size */ + MSSS_Reload, /* Reload_Sequence */ + 300, /* TargetCallibrationShift */ + SID_ED_SKEETERCHARGE, /* StartSound */ + SID_NOSOUND, /* LoopSound */ + SID_ED_SKEETERLAUNCH, /* EndSound */ + 1, /* Enable Grenades */ + 1, /* UseElevation */ + 1, /* EnableTracker */ + 1, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_Scientist_A, /* ID */ + SFX_NONE, /* enum SFX_ID SfxID; */ + + NULL, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_NullPanicFire, /* WeaponPanicFireFunction */ + "scientist", /* Riffname */ + "clip", /* HierarchyName */ + "clip board", /* GunflashName */ + NULL, /* ElevationSection */ + "bub with molotov", /* HitLocationTableName */ + "Template", /* TemplateName */ + NULL, /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + 10000, /* MaxRange (Don't fire if further) */ + -10000, /* Accuracy */ + 1, /* Firing Rate */ + MARINE_NEAR_FIRE_TIME, /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_10MM_CULW, /* Ammo profile */ + -1, /* clip_size */ + MSSS_Standard, /* Reload_Sequence */ + 0, /* TargetCallibrationShift */ + SID_NOSOUND, /* StartSound */ + SID_NOSOUND, /* LoopSound */ + SID_NOSOUND, /* EndSound */ + 0, /* Enable Grenades */ + 0, /* UseElevation */ + 0, /* EnableTracker */ + 0, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_Scientist_B, /* ID */ + SFX_NONE, /* enum SFX_ID SfxID; */ + + NULL, /* Func. */ + NULL, /* Misfire func. */ + Execute_MNS_NullPanicFire, /* WeaponPanicFireFunction */ + "scientist", /* Riffname */ + "testtube", /* HierarchyName */ + "test tube", /* GunflashName */ + NULL, /* ElevationSection */ + "bub with molotov", /* HitLocationTableName */ + "Template", /* TemplateName */ + NULL, /* ClipName */ + 0, /* MinRange (Don't fire when closer) */ + MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */ + 10000, /* MaxRange (Don't fire if further) */ + -10000, /* Accuracy */ + 1, /* Firing Rate */ + MARINE_NEAR_FIRE_TIME, /* Firing Time */ + 0, /* MinimumBurstSize */ + AMMO_10MM_CULW, /* Ammo profile */ + -1, /* clip_size */ + MSSS_Standard, /* Reload_Sequence */ + 0, /* TargetCallibrationShift */ + SID_NOSOUND, /* StartSound */ + SID_NOSOUND, /* LoopSound */ + SID_NOSOUND, /* EndSound */ + 0, /* Enable Grenades */ + 0, /* UseElevation */ + 0, /* EnableTracker */ + 0, /* ARealMarine */ + 0, /* Android */ + }, + { + MNPCW_End, + SFX_NONE, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + MAX_NO_OF_AMMO_TEMPLATES, + -1, + MSSS_Standard, + 0, + SID_NOSOUND, + SID_NOSOUND, + SID_NOSOUND, + 0, + 0, + 0, + 0, + 0, + }, +}; + +VECTORCH ShotgunBlast[] = { + {0,0,400,}, + {100,0,400,}, + {-100,0,400,}, + {50,0,400,}, + {-50,0,400,}, + {-1,-1,-1,}, +}; + +SQUAD_COMMAND_STATE NpcSquad; +int ShowSquadState=0; +int ShowNearSquad=0; +extern SCENE Global_Scene; +static MODULE **Global_ModuleArrayPtr; +extern int ModuleArraySize; +static char tempstring[256]; +static int tracker_noise; + +void ForceCaps(char *input) { + char *p; + p=input; + while (*p!=0) { + if ( (*p>=97) && (*p<=122) ) { + /* Force Caps */ + *p-=32; + } + p++; + } +} + +/* Squad functions, CDF 27/5/98 */ + +void InitSquad(void) { + + /* Maybe level specific later? */ + + NpcSquad.alertStatus=0; + NpcSquad.responseLevel=0; + NpcSquad.alertZone=NULL; + NpcSquad.alertPriority=0; + + NpcSquad.Squad_Suspicion=0; + NpcSquad.squad_suspect_point.vx=0; + NpcSquad.squad_suspect_point.vy=0; + NpcSquad.squad_suspect_point.vz=0; + + NpcSquad.RespondingMarines=0; + NpcSquad.Alt_RespondingMarines=0; + + NpcSquad.NearUnpanickedMarines=0; + NpcSquad.Alt_NearUnpanickedMarines=0; + + NpcSquad.NearPanickedMarines=0; + NpcSquad.Alt_NearPanickedMarines=0; + + NpcSquad.NearBurningMarines=0; + NpcSquad.Alt_NearBurningMarines=0; + + NpcSquad.Squad_Delta_Morale=0; + NpcSquad.Nextframe_Squad_Delta_Morale=0; +} + +void DoSquad(void) { + + /* Maintain squad level stuff. */ + + if (NpcSquad.alertZone!=NULL) { + MaintainMarineTargetZone(NpcSquad.alertZone); + } + + /* Maintain squad suspicion. */ + if (NpcSquad.Squad_Suspicion>0) { + NpcSquad.Squad_Suspicion-=NormalFrameTime; + if (NpcSquad.Squad_Suspicion<0) { + NpcSquad.Squad_Suspicion=0; + } + } + + /* Maintain stats. */ + NpcSquad.RespondingMarines=NpcSquad.Alt_RespondingMarines; + NpcSquad.Alt_RespondingMarines=0; + + NpcSquad.NearUnpanickedMarines=NpcSquad.Alt_NearUnpanickedMarines; + NpcSquad.Alt_NearUnpanickedMarines=0; + + NpcSquad.NearPanickedMarines=NpcSquad.Alt_NearPanickedMarines; + NpcSquad.Alt_NearPanickedMarines=0; + + NpcSquad.NearBurningMarines=NpcSquad.Alt_NearBurningMarines; + NpcSquad.Alt_NearBurningMarines=0; + + NpcSquad.Squad_Delta_Morale=NpcSquad.Nextframe_Squad_Delta_Morale; + NpcSquad.Nextframe_Squad_Delta_Morale=0; + + /* Update morale. */ + NpcSquad.Nextframe_Squad_Delta_Morale+=MUL_FIXED(NormalFrameTime,(NpcSquad.NearUnpanickedMarines*50)); + NpcSquad.Nextframe_Squad_Delta_Morale-=MUL_FIXED(NormalFrameTime,(NpcSquad.NearPanickedMarines*1000)); + NpcSquad.Nextframe_Squad_Delta_Morale-=MUL_FIXED(NormalFrameTime,(NpcSquad.NearBurningMarines*3000)); + + if (TERROR_MODE) { + NpcSquad.Nextframe_Squad_Delta_Morale=-100000000; + } + + /* Status display. */ + if (ShowSquadState) { + PrintDebuggingText("Marine Alert Status = %d\n",NpcSquad.alertStatus); + PrintDebuggingText("Marine Alert Priority = %d\n",NpcSquad.alertPriority); + PrintDebuggingText("Responding Marines = %d\n",NpcSquad.RespondingMarines); + PrintDebuggingText("NearPanicked Marines = %d\n",NpcSquad.NearPanickedMarines); + PrintDebuggingText("NearUnpanicked Marines = %d\n",NpcSquad.NearUnpanickedMarines); + PrintDebuggingText("NearBurning Marines = %d\n",NpcSquad.NearBurningMarines); + PrintDebuggingText("Marine Outstanding Response Level = %d\n",NpcSquad.responseLevel); + if (NpcSquad.alertZone==NULL) { + PrintDebuggingText("Marine Alert Zone = NULL\n"); + } else { + MODULE *sampleModule; + + sampleModule=*(NpcSquad.alertZone->m_module_ptrs); + if (sampleModule==NULL) { + PrintDebuggingText("Marine Alert Zone = Totally Farped! %d\n",NpcSquad.alertZone->m_index); + } else { + PrintDebuggingText("Marine Alert Zone = %d, '%s'\n",sampleModule->m_index,sampleModule->name); + } + } + PrintDebuggingText("Squad Suspicion = %d\n",NpcSquad.Squad_Suspicion); + PrintDebuggingText("Squad Suspect Point = %d %d %d\n",NpcSquad.squad_suspect_point.vx, + NpcSquad.squad_suspect_point.vy,NpcSquad.squad_suspect_point.vz); + } + + /* And now just for me... :-) */ + PrintSpottedNumber(); + +} + +void ZoneAlert(int level,AIMODULE *targetModule) { + + int idealResponse; + /* Bad stuff is going down. */ + + /* Switch to this one if it has a higher level than the current priority. */ + + if (level=NpcSquad.alertStatus) { + NpcSquad.alertStatus=level; + } + + NpcSquad.alertPriority=level; + NpcSquad.alertZone=targetModule; + switch (NpcSquad.alertStatus) { + case 0: + /* Can this ever happen? */ + idealResponse=1; + break; + case 1: + idealResponse=1; + break; + case 2: + idealResponse=3; + break; + case 3: + idealResponse=5; + break; + default: + idealResponse=1; + break; + } + + if (NpcSquad.RespondingMarinesm_aimodule); + +} + +void DeprioritiseAlert(AIMODULE *aimodule) { + + /* Parameterised, to make sure we're doing it right. */ + + if (aimodule==NpcSquad.alertZone) { + NpcSquad.alertPriority=0; + } +} + +void Console_ZoneAlert(int input) { + + MODULE *target; + SCENEMODULE *smptr; + + smptr = Global_ModulePtr[Global_Scene]; + Global_ModuleArrayPtr = smptr->sm_marray; + + if ((input==0)||(input>=ModuleArraySize)) { + target=playerPherModule; + } else { + target=Global_ModuleArrayPtr[input]; + } + + sprintf(tempstring,"NEW ZONE ALERT IN %d, '%s'\n",target->m_index,target->name); + ForceCaps(tempstring); + NewOnScreenMessage(tempstring); + + ZoneAlert(3,target->m_aimodule); +} + +/* Interface function - 15/12/97 */ + +MARINE_WEAPON_DATA *GetThisNPCMarineWeapon(MARINE_NPC_WEAPONS this_id) { + + int a; + + a=0; + while (NPC_Marine_Weapons[a].id!=MNPCW_End) { + if (NPC_Marine_Weapons[a].id==this_id) { + return(&NPC_Marine_Weapons[a]); + } + a++; + } + + return(NULL); + +} + +MARINE_NPC_WEAPONS GetThisManAWeapon(void) { + + int a; + MARINE_NPC_WEAPONS thisweap; + + a=FastRandom()&65535; + + if (a<(ONE_FIXED>>3)) { + /* 1/8: Smartgun. */ + thisweap=(MNPCW_Smartgun); + } else if (a<(ONE_FIXED/3)) { + /* 5/24: Flamethrower. */ + thisweap=(MNPCW_Flamethrower); + } else if (a<((2*ONE_FIXED)/3)) { + thisweap=(MNPCW_PulseRifle); + //thisweap=(MNPCW_SADAR); + } else { + thisweap=(MNPCW_MShotgun); + } + + /* Check... */ + { + MARINE_WEAPON_DATA *tempweap; + SECTION *root_section; + + tempweap=GetThisNPCMarineWeapon(thisweap); + root_section=GetNamedHierarchyFromLibrary(tempweap->Riffname,tempweap->HierarchyName); + if (!root_section) { + thisweap=MNPCW_PulseRifle; + } + } + + return(thisweap); +} + +void ChangeToAlternateAccoutrementSet(STRATEGYBLOCK *sbPtr, int index) { + + HIERARCHY_VARIANT_DATA* variant_data; + HIERARCHY_SHAPE_REPLACEMENT* replacement_array; + MARINE_STATUS_BLOCK *marineStatusPointer; + int a; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + variant_data=GetHierarchyAlternateShapeSetCollectionFromLibrary(marineStatusPointer->My_Weapon->Riffname,index); + + if (variant_data==NULL) { + return; + } + + marineStatusPointer->Female=variant_data->female; + marineStatusPointer->Voice=variant_data->voice; + + replacement_array=(HIERARCHY_SHAPE_REPLACEMENT*)variant_data->replacements; + + if (replacement_array==NULL) { + return; + } + + + a=0; + + while (replacement_array[a].replaced_section_name!=NULL) { + SECTION_DATA *target_section; + + target_section=GetThisSectionData(marineStatusPointer->HModelController.section_data, + replacement_array[a].replaced_section_name); + if (target_section) { + target_section->Shape=replacement_array[a].replacement_shape; + #if 1 + target_section->ShapeNum=replacement_array[a].replacement_shape_index; + #endif + target_section->replacement_id = replacement_array[a].replacement_id; + + Setup_Texture_Animation_For_Section(target_section); + + } + a++; + } + +} + +void ChangeToAlternateShapeSet(STRATEGYBLOCK *sbPtr, char *setname) { + + HIERARCHY_SHAPE_REPLACEMENT* replacement_array; + MARINE_STATUS_BLOCK *marineStatusPointer; + int a; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + replacement_array=GetHierarchyAlternateShapeSetFromLibrary(marineStatusPointer->My_Weapon->Riffname,setname); + + if (replacement_array==NULL) { + return; + } + + a=0; + + while (replacement_array[a].replaced_section_name!=NULL) { + SECTION_DATA *target_section; + + target_section=GetThisSectionData(marineStatusPointer->HModelController.section_data, + replacement_array[a].replaced_section_name); + if (target_section) { + target_section->Shape=replacement_array[a].replacement_shape; + #if 1 + target_section->ShapeNum=replacement_array[a].replacement_shape_index; + #endif + + Setup_Texture_Animation_For_Section(target_section); + } + a++; + } +} + +/* CDF 3/4/98 */ + +void CastMarineBot(int weapon) { + + #define BOTRANGE 2000 + + VECTORCH position; + + if (AvP.Network!=I_No_Network) { + NewOnScreenMessage("NO MARINEBOTS IN MULTIPLAYER MODE"); + return; + } + + position=Player->ObStrategyBlock->DynPtr->Position; + position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE); + position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE); + position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE); + + CreateMarineBot(&position, weapon); + +} + +void CreateMarineBot(VECTORCH *Position, int weapon) +{ + STRATEGYBLOCK* sbPtr; + + /* create and initialise a strategy block */ + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) { + NewOnScreenMessage("FAILED TO CREATE BOT: SB CREATION FAILURE"); + return; /* failure */ + } + InitialiseSBValues(sbPtr); + + sbPtr->I_SBtype = I_BehaviourMarine; + + AssignNewSBName(sbPtr); + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC); + if(sbPtr->DynPtr) + { + EULER zeroEuler = {0,0,0}; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + GLOBALASSERT(dynPtr); + dynPtr->PrevPosition = dynPtr->Position = *Position; + dynPtr->OrientEuler = zeroEuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + } + else + { + /* dynamics block allocation failed... */ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: DYNBLOCK CREATION FAILURE"); + return; + } + + sbPtr->shapeIndex = 0; + + sbPtr->maintainVisibility = 1; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0); + + /* create, initialise and attach a marine data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(MARINE_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + SECTION *root_section; + MARINE_STATUS_BLOCK *marineStatus = (MARINE_STATUS_BLOCK *)sbPtr->SBdataptr; + GLOBALASSERT(marineStatus); + + NPC_InitMovementData(&(marineStatus->moveData)); + NPC_InitWanderData(&(marineStatus->wanderData)); + marineStatus->health = MARINE_STARTING_HEALTH; + sbPtr->integrity = marineStatus->health; + marineStatus->volleySize = 0; + + marineStatus->primaryWeaponDamage = MARINE_WEAPON_DAMAGE; + marineStatus->stateTimer = MARINE_FAR_MOVE_TIME; + marineStatus->weaponTarget.vx = marineStatus->weaponTarget.vy = marineStatus->weaponTarget.vz = 0; + marineStatus->myGunFlash = (DISPLAYBLOCK *)0; + marineStatus->soundHandle = SOUND_NOACTIVEINDEX; + marineStatus->soundHandle2 = SOUND_NOACTIVEINDEX; + + marineStatus->obstruction.environment=0; + marineStatus->obstruction.destructableObject=0; + marineStatus->obstruction.otherCharacter=0; + marineStatus->obstruction.anySingleObstruction=0; + + Initialise_AvoidanceManager(sbPtr,&marineStatus->avoidanceManager); + InitWaypointManager(&marineStatus->waypointManager); + + marineStatus->IAmCrouched = 0; + marineStatus->lastroundhit=0; + marineStatus->lasthitsection=NULL; + + marineStatus->weapon_variable=0; + marineStatus->weapon_variable2=0; + + marineStatus->Skill=Marine_Skill; + marineStatus->Courage=ONE_FIXED; + + marineStatus->FiringAnim=0; + marineStatus->SpotFlag=0; + + //a generated marine won't have a death target + { + int i; + for(i=0;ideath_target_ID[i] =0; + marineStatus->death_target_request=0; + marineStatus->death_target_sbptr=0; + } + + //this marine wasn't produced by a generator + marineStatus->generator_sbptr=0; + + + marineStatus->Target=NULL; //Player->ObStrategyBlock; + if ( (weapon<=0)||(weapon>(int)MNPCW_End)) { + marineStatus->My_Weapon=GetThisNPCMarineWeapon(GetThisManAWeapon()); + } else { + #if (TWO_PISTOL_GUY==0) + if (weapon>=MNPCW_TwoPistols) { + marineStatus->My_Weapon=GetThisNPCMarineWeapon(GetThisManAWeapon()); + } else { + marineStatus->My_Weapon=GetThisNPCMarineWeapon(weapon-1); + } + #else + marineStatus->My_Weapon=GetThisNPCMarineWeapon(weapon-1); + #endif + } + + /* Initialise marine's stats */ + { + NPC_DATA *NpcData; + + if (marineStatus->My_Weapon->Android) { + NpcData=GetThisNpcData(I_NPC_Android); + } else if (marineStatus->My_Weapon->ARealMarine) { + NpcData=GetThisNpcData(I_NPC_Marine); + } else { + NpcData=GetThisNpcData(I_NPC_Civilian); + } + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + + { + MOVEMENT_DATA *movementData; + + marineStatus->speedConstant=(ONE_FIXED-8192)+(FastRandom()&16383); + marineStatus->accelerationConstant=(ONE_FIXED-8192)+(FastRandom()&16383); + + if (marineStatus->My_Weapon->ARealMarine) { + movementData=GetThisMovementData(MDI_Marine_Combat); + } else { + movementData=GetThisMovementData(MDI_Civilian_Combat); + } + GLOBALASSERT(movementData); + marineStatus->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatus->speedConstant); + marineStatus->acceleration = MUL_FIXED(movementData->acceleration,marineStatus->accelerationConstant); + } + COPY_NAME(marineStatus->Target_SBname,Null_Name); + marineStatus->lastmodule=NULL; + marineStatus->destinationmodule=NULL; + marineStatus->missionmodule=NULL; + marineStatus->fearmodule=NULL; + marineStatus->my_facing_point=sbPtr->DynPtr->Position; + marineStatus->path=-1; + marineStatus->stepnumber=-1; + marineStatus->sawlastframe=0; + marineStatus->gotapoint=0; + marineStatus->lastframe_fallingspeed=0; + marineStatus->suspicious=0; + marineStatus->previous_suspicion=0; + marineStatus->using_squad_suspicion=0; + marineStatus->suspect_point.vx=0; + marineStatus->suspect_point.vy=0; + marineStatus->suspect_point.vz=0; + marineStatus->internalState=0; + #if MOTIONTRACKERS + if (marineStatus->My_Weapon->EnableTracker) { + if ((FastRandom()&65535)<(ONE_FIXED>>2)) { + marineStatus->mtracker_timer=FastRandom()&65535; + } else { + marineStatus->mtracker_timer=-1; + } + } else { + marineStatus->mtracker_timer=-1; + } + #else + marineStatus->mtracker_timer=-1; + #endif + marineStatus->GibbFactor=0; + marineStatus->Wounds=0; + + marineStatus->incidentFlag=0; + marineStatus->incidentTimer=0; + + if (marineStatus->My_Weapon->id==MNPCW_MPistol) { + /* Special case for pistols? */ + marineStatus->lastroundhit=PISTOL_CLIP_SIZE; + } + marineStatus->clipammo=marineStatus->My_Weapon->clip_size; + marineStatus->roundsForThisTarget=0; + + marineStatus->HModelController.section_data=NULL; + marineStatus->HModelController.Deltas=NULL; + /* In case we need to deallocate it. */ + root_section=GetNamedHierarchyFromLibrary(marineStatus->My_Weapon->Riffname,marineStatus->My_Weapon->HierarchyName); + if (!root_section) { + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: NO HMODEL"); + return; + } + Create_HModel(&marineStatus->HModelController,root_section); + InitHModelSequence(&marineStatus->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Standard,ONE_FIXED); + + if (marineStatus->My_Weapon->UseElevation) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&marineStatus->HModelController,"Elevation",(int)HMSQT_MarineStand,(int)MSSS_Elevation,0); + GLOBALASSERT(delta); + delta->timer=32767; + } + + if (marineStatus->My_Weapon->id==MNPCW_Minigun) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&marineStatus->HModelController,"Minigun",(int)HMSQT_MarineStand,(int)MSSS_Minigun_Delta,(ONE_FIXED>>3)); + GLOBALASSERT(delta); + delta->Playing=0; + delta->Looped=1; + } + + /* Create blank hit delta sequence. */ + if (strcmp("hnpcmarine",marineStatus->My_Weapon->Riffname)==0) + { + if (HModelSequence_Exists(&marineStatus->HModelController,(int)HMSQT_MarineStand,(int)MSSS_HitChestFront)) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&marineStatus->HModelController,"HitDelta",(int)HMSQT_MarineStand,(int)MSSS_HitChestFront,(ONE_FIXED>>2)); + GLOBALASSERT(delta); + delta->Playing=0; + } + } + + marineStatus->My_Gunflash_Section=GetThisSectionData(marineStatus->HModelController.section_data,marineStatus->My_Weapon->GunflashName); + marineStatus->My_Elevation_Section=GetThisSectionData(marineStatus->HModelController.section_data,marineStatus->My_Weapon->ElevationSection); + + //initialise female to 0.. + //may be changed by ChangeToAlternateAccoutrementSet + marineStatus->Female=0; + marineStatus->Voice=0; + marineStatus->Android=marineStatus->My_Weapon->Android; + + //use accoutement set for both marine and civilian + #if 0 + if (strcmp("hnpcmarine",marineStatus->My_Weapon->Riffname)==0) { + int dice=FastRandom()&65535; + if (dice<16384) { + ChangeToAlternateShapeSet(sbPtr, "Face Four"); + } else if (dice<32768) { + ChangeToAlternateShapeSet(sbPtr, "Face Three"); + } + } else if (strcmp("hnpc_civvie",marineStatus->My_Weapon->Riffname)==0) { + #if 0 + int dice=FastRandom()&65535; + if (dice<32767) { + ChangeToAlternateShapeSet(sbPtr, "MedicalGuy"); + } else if (dice<49152) { + ChangeToAlternateShapeSet(sbPtr, "CompanyGuy"); + } + #else + ChangeToAlternateAccoutrementSet(sbPtr, 0); + #endif + } + #else + //pick a random texture id rather than using 0 , so that we can get + //texture ids not normally allowed by the level + ChangeToAlternateAccoutrementSet(sbPtr, FastRandom()); + #endif + marineStatus->VoicePitch = (FastRandom() & 255) - 128; + + Marine_SwitchExpression(sbPtr,0); + marineStatus->Target_Expression=0; + marineStatus->Blink=-1; + + ProveHModel_Far(&marineStatus->HModelController,sbPtr); + + if(!(sbPtr->containingModule)) + { + /* no containing module can be found... abort*/ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: MODULE CONTAINMENT FAILURE"); + return; + } + LOCALASSERT(sbPtr->containingModule); + + if (marineStatus->My_Weapon->WeaponFireFunction==NULL) { + InitMission(sbPtr,MM_NonCom); + } else { + InitMission(sbPtr,MM_Wander); + } + + MakeMarineNear(sbPtr); + + NewOnScreenMessage("MARINEBOT CREATED"); + } + else + { + /* no data block can be allocated */ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: MALLOC FAILURE"); + return; + } +} + +/*------------------------Patrick 24/2/97----------------------------- + Marine/Seal behaviour shell functions + --------------------------------------------------------------------*/ + +void InitMarineBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr) +{ + TOOLS_DATA_MARINE *toolsData = (TOOLS_DATA_MARINE *)bhdata; + int i; + + LOCALASSERT(sbPtr); + + /* check we're not in a net game */ + if(AvP.Network != I_No_Network) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* make the assumption that the loader has initialised the strategy block sensibly... + so just set the shapeIndex from the tools data & copy the name id*/ + sbPtr->shapeIndex = toolsData->shapeIndex; + for(i=0;iSBname[i] = toolsData->nameID[i]; + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC); + if(sbPtr->DynPtr) + { + EULER zeroEuler = {0,0,0}; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + GLOBALASSERT(dynPtr); + dynPtr->PrevPosition = dynPtr->Position = toolsData->position; + dynPtr->OrientEuler = zeroEuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + + /* zero linear velocity in dynamics block */ + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + + sbPtr->containingModule=ModuleFromPosition(&dynPtr->Position,NULL); + + GLOBALASSERT(sbPtr->containingModule); + } + else + { + /* allocation failed */ + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* create, initialise and attach a marine data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(MARINE_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + SECTION *root_section; + MARINE_STATUS_BLOCK *marineStatus = (MARINE_STATUS_BLOCK *)sbPtr->SBdataptr; + GLOBALASSERT(marineStatus); + + NPC_InitMovementData(&(marineStatus->moveData)); + NPC_InitWanderData(&(marineStatus->wanderData)); + marineStatus->health = MARINE_STARTING_HEALTH; + sbPtr->integrity = marineStatus->health; + marineStatus->volleySize = 0; + marineStatus->primaryWeaponDamage = MARINE_WEAPON_DAMAGE; + marineStatus->stateTimer = MARINE_FAR_MOVE_TIME; + marineStatus->weaponTarget.vx = marineStatus->weaponTarget.vy = marineStatus->weaponTarget.vz = 0; + marineStatus->myGunFlash = (DISPLAYBLOCK *)0; + marineStatus->soundHandle = SOUND_NOACTIVEINDEX; + marineStatus->soundHandle2 = SOUND_NOACTIVEINDEX; + + marineStatus->obstruction.environment=0; + marineStatus->obstruction.destructableObject=0; + marineStatus->obstruction.otherCharacter=0; + marineStatus->obstruction.anySingleObstruction=0; + + Initialise_AvoidanceManager(sbPtr,&marineStatus->avoidanceManager); + InitWaypointManager(&marineStatus->waypointManager); + + marineStatus->IAmCrouched = 0; + marineStatus->lastroundhit=0; + marineStatus->lasthitsection=NULL; + + marineStatus->weapon_variable=0; + marineStatus->weapon_variable2=0; + + marineStatus->Skill=Marine_Skill; + marineStatus->Courage=ONE_FIXED; + + marineStatus->FiringAnim=0; + marineStatus->SpotFlag=0; + + marineStatus->Target=NULL; //Player->ObStrategyBlock; + + marineStatus->my_spot=sbPtr->DynPtr->Position; + + #if ALL_PULSERIFLES + marineStatus->My_Weapon=GetThisNPCMarineWeapon(MNPCW_PulseRifle); + #else + marineStatus->My_Weapon=GetThisNPCMarineWeapon(toolsData->marine_type); + #endif + + /* Initialise marine's stats */ + { + NPC_DATA *NpcData; + + if (marineStatus->My_Weapon->Android) { + NpcData=GetThisNpcData(I_NPC_Android); + } else if (marineStatus->My_Weapon->ARealMarine) { + NpcData=GetThisNpcData(I_NPC_Marine); + } else { + NpcData=GetThisNpcData(I_NPC_Civilian); + } + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + + if (toolsData->Mission==MM_NonCom) { + marineStatus->My_Weapon=GetThisNPCMarineWeapon(MNPCW_MUnarmed); + } + + if (marineStatus->My_Weapon->id==MNPCW_MPistol) { + /* Special case for pistols? */ + marineStatus->lastroundhit=PISTOL_CLIP_SIZE; + } + marineStatus->clipammo=marineStatus->My_Weapon->clip_size; + marineStatus->roundsForThisTarget=0; + + { + MOVEMENT_DATA *movementData; + + marineStatus->speedConstant=(ONE_FIXED-8192)+(FastRandom()&16383); + marineStatus->accelerationConstant=(ONE_FIXED-8192)+(FastRandom()&16383); + + if (marineStatus->My_Weapon->ARealMarine) { + movementData=GetThisMovementData(MDI_Marine_Combat); + } else { + movementData=GetThisMovementData(MDI_Civilian_Combat); + } + GLOBALASSERT(movementData); + marineStatus->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatus->speedConstant); + marineStatus->acceleration = MUL_FIXED(movementData->acceleration,marineStatus->accelerationConstant); + } + COPY_NAME(marineStatus->Target_SBname,Null_Name); + marineStatus->lastmodule=NULL; + marineStatus->destinationmodule=NULL; + marineStatus->missionmodule=NULL; + marineStatus->fearmodule=NULL; + marineStatus->my_facing_point=toolsData->facing_point; + marineStatus->path=toolsData->path; + marineStatus->stepnumber=toolsData->stepnumber; + marineStatus->sawlastframe=0; + marineStatus->gotapoint=0; + marineStatus->lastframe_fallingspeed=0; + marineStatus->suspicious=0; + marineStatus->previous_suspicion=0; + marineStatus->using_squad_suspicion=0; + marineStatus->suspect_point.vx=0; + marineStatus->suspect_point.vy=0; + marineStatus->suspect_point.vz=0; + marineStatus->internalState=0; + #if MOTIONTRACKERS + if (marineStatus->My_Weapon->EnableTracker) { + if ((FastRandom()&65535)<(ONE_FIXED>>2)) { + marineStatus->mtracker_timer=FastRandom()&65535; + } else { + marineStatus->mtracker_timer=-1; + } + } else { + marineStatus->mtracker_timer=-1; + } + #else + marineStatus->mtracker_timer=-1; + #endif + marineStatus->GibbFactor=0; + marineStatus->Wounds=0; + + marineStatus->incidentFlag=0; + marineStatus->incidentTimer=0; + + //InitShapeAnimationController(&marineStatus->ShpAnimCtrl, GetShapeData(sbPtr->shapeIndex)); + + GLOBALASSERT(marineStatus->My_Weapon->HierarchyName); + + root_section=GetNamedHierarchyFromLibrary(marineStatus->My_Weapon->Riffname,marineStatus->My_Weapon->HierarchyName); + + Create_HModel(&marineStatus->HModelController,root_section); + InitHModelSequence(&marineStatus->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Standard,ONE_FIXED); + + if (marineStatus->My_Weapon->UseElevation) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&marineStatus->HModelController,"Elevation",(int)HMSQT_MarineStand,(int)MSSS_Elevation,0); + GLOBALASSERT(delta); + delta->timer=32767; + } + + /* Create blank hit delta sequence. */ + if (strcmp("hnpcmarine",marineStatus->My_Weapon->Riffname)==0) + { + if (HModelSequence_Exists(&marineStatus->HModelController,(int)HMSQT_MarineStand,(int)MSSS_HitChestFront)) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&marineStatus->HModelController,"HitDelta",(int)HMSQT_MarineStand,(int)MSSS_HitChestFront,(ONE_FIXED>>2)); + GLOBALASSERT(delta); + delta->Playing=0; + } + } + + marineStatus->My_Gunflash_Section=GetThisSectionData(marineStatus->HModelController.section_data,marineStatus->My_Weapon->GunflashName); + marineStatus->My_Elevation_Section=GetThisSectionData(marineStatus->HModelController.section_data,marineStatus->My_Weapon->ElevationSection); + + for(i=0;ideath_target_ID[i] = toolsData->death_target_ID[i]; + marineStatus->death_target_request=toolsData->death_target_request; + marineStatus->death_target_sbptr=0; + + //this marine wasn't produced by a generator + marineStatus->generator_sbptr=0; + + //initialise female to 0.. + //may be changed by ChangeToAlternateAccoutrementSet + marineStatus->Female=0; + marineStatus->Voice=0; + marineStatus->Android=marineStatus->My_Weapon->Android; + + //use accoutement set for both marine and civilian + #if 0 + if (strcmp("hnpcmarine",marineStatus->My_Weapon->Riffname)==0) { + /* Normal marine. */ + if ((toolsData->textureID==0)||(toolsData->textureID>4)) { + /* Random. */ + int dice=FastRandom()&65535; + if (dice<16384) { + ChangeToAlternateShapeSet(sbPtr, "Face Four"); + } else if (dice<32768) { + ChangeToAlternateShapeSet(sbPtr, "Face Three"); + } + } else { + switch (toolsData->textureID) { + case 1: + default: + /* No change. */ + break; + case 2: + ChangeToAlternateShapeSet(sbPtr, "Face Four"); + break; + case 3: + ChangeToAlternateShapeSet(sbPtr, "Face Three"); + break; + } + } + } else if (strcmp("hnpc_civvie",marineStatus->My_Weapon->Riffname)==0) { + /* Civvies. */ + #if 0 + if ((toolsData->textureID==0)||(toolsData->textureID>3)) { + int dice=FastRandom()&65535; + if (dice<32767) { + ChangeToAlternateShapeSet(sbPtr, "MedicalGuy"); + } else if (dice<49152) { + ChangeToAlternateShapeSet(sbPtr, "CompanyGuy"); + } + } else { + switch (toolsData->textureID) { + case 1: + default: + /* No change. */ + break; + case 2: + ChangeToAlternateShapeSet(sbPtr, "MedicalGuy"); + break; + case 3: + ChangeToAlternateShapeSet(sbPtr, "CompanyGuy"); + break; + } + } + #else + /* Gonna need a different handler for this? */ + ChangeToAlternateAccoutrementSet(sbPtr, toolsData->textureID); + #endif + } + #else + ChangeToAlternateAccoutrementSet(sbPtr, toolsData->textureID); + #endif + marineStatus->VoicePitch = (FastRandom() & 255) - 128; + + Marine_SwitchExpression(sbPtr,0); + marineStatus->Target_Expression=0; + marineStatus->Blink=-1; + + ProveHModel_Far(&marineStatus->HModelController,sbPtr); + + if (marineStatus->My_Weapon->WeaponFireFunction==NULL) { + InitMission(sbPtr,MM_NonCom); + } else { + InitMission(sbPtr,toolsData->Mission); + } + } + else + { + /* allocation failed */ + RemoveBehaviourStrategy(sbPtr); + return; + } +} + +void InitSealBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr) +{ + /* Die, superfluous function!!! */ + InitMarineBehaviour(bhdata,sbPtr); + +} + +void CreateMarineDynamic(STRATEGYBLOCK *Generator,MARINE_NPC_WEAPONS weapon_for_marine) +{ + STRATEGYBLOCK* sbPtr; + GENERATOR_BLOCK *generatorBlock; + + generatorBlock=Generator->SBdataptr; + GLOBALASSERT(generatorBlock); + + /* check we're not in a net game */ + if(AvP.Network != I_No_Network) + { + return; + } + + /* create and initialise a strategy block */ + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) + { + /* allocation failed */ + return; + } + + InitialiseSBValues(sbPtr); + sbPtr->I_SBtype = I_BehaviourMarine; + + /* Old way. * + for(i = 0; i < SB_NAME_LENGTH; i++) { + sbPtr->SBname[i] = '\0'; + } + * CDF - 9/9/97 */ + AssignNewSBName(sbPtr); + /* New way. */ + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC); + if(sbPtr->DynPtr) + { + EULER zeroEuler = {0,0,0}; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + GLOBALASSERT(dynPtr); + dynPtr->PrevPosition = dynPtr->Position = ((GENERATOR_BLOCK* )Generator->SBdataptr)->Position; + dynPtr->OrientEuler = zeroEuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + } + else + { + /* allocation failed */ + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* set the shape */ + sbPtr->shapeIndex = Generator->shapeIndex; + + sbPtr->maintainVisibility = 1; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0); + LOCALASSERT(sbPtr->containingModule); + if(!(sbPtr->containingModule)) + { + /* no containing module can be found... abort*/ + DestroyAnyStrategyBlock(sbPtr); + return; + } + + /* assert marine is starting as invisible */ + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)] == 0); + + /* create, initialise and attach a marine data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(MARINE_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + SECTION *root_section; + MARINE_STATUS_BLOCK *marineStatus = (MARINE_STATUS_BLOCK *)sbPtr->SBdataptr; + GLOBALASSERT(marineStatus); + + NPC_InitMovementData(&(marineStatus->moveData)); + NPC_InitWanderData(&(marineStatus->wanderData)); + marineStatus->health = MARINE_STARTING_HEALTH; + sbPtr->integrity = marineStatus->health; + marineStatus->volleySize = 0; + marineStatus->nearSpeed = MARINE_NEAR_SPEED; + marineStatus->primaryWeaponDamage = MARINE_WEAPON_DAMAGE; + marineStatus->stateTimer = MARINE_FAR_MOVE_TIME; + marineStatus->weaponTarget.vx = marineStatus->weaponTarget.vy = marineStatus->weaponTarget.vz = 0; + marineStatus->myGunFlash = (DISPLAYBLOCK *)0; + marineStatus->soundHandle = SOUND_NOACTIVEINDEX; + marineStatus->soundHandle2 = SOUND_NOACTIVEINDEX; + + marineStatus->obstruction.environment=0; + marineStatus->obstruction.destructableObject=0; + marineStatus->obstruction.otherCharacter=0; + marineStatus->obstruction.anySingleObstruction=0; + + Initialise_AvoidanceManager(sbPtr,&marineStatus->avoidanceManager); + InitWaypointManager(&marineStatus->waypointManager); + + marineStatus->IAmCrouched = 0; + marineStatus->lastroundhit=0; + marineStatus->lasthitsection=NULL; + + marineStatus->weapon_variable=0; + marineStatus->weapon_variable2=0; + + marineStatus->Skill=Marine_Skill; + marineStatus->Courage=ONE_FIXED; + + marineStatus->FiringAnim=0; + marineStatus->SpotFlag=0; + + //a generated marine won't have a death target + { + int i; + for(i=0;ideath_target_ID[i] =0; + marineStatus->death_target_request=0; + marineStatus->death_target_sbptr=0; + } + + //note the generator that produced this marine + marineStatus->generator_sbptr=Generator; + + marineStatus->Target=NULL; //Player->ObStrategyBlock; + + marineStatus->My_Weapon=GetThisNPCMarineWeapon(weapon_for_marine); + + /* Initialise marine's stats */ + { + NPC_DATA *NpcData; + + if (marineStatus->My_Weapon->Android) { + NpcData=GetThisNpcData(I_NPC_Android); + } else if (marineStatus->My_Weapon->ARealMarine) { + NpcData=GetThisNpcData(I_NPC_Marine); + } else { + NpcData=GetThisNpcData(I_NPC_Civilian); + } + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + + { + MOVEMENT_DATA *movementData; + + marineStatus->speedConstant=(ONE_FIXED-8192)+(FastRandom()&16383); + marineStatus->accelerationConstant=(ONE_FIXED-8192)+(FastRandom()&16383); + + if (marineStatus->My_Weapon->ARealMarine) { + movementData=GetThisMovementData(MDI_Marine_Combat); + } else { + movementData=GetThisMovementData(MDI_Civilian_Combat); + } + GLOBALASSERT(movementData); + marineStatus->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatus->speedConstant); + marineStatus->acceleration = MUL_FIXED(movementData->acceleration,marineStatus->accelerationConstant); + } + + COPY_NAME(marineStatus->Target_SBname,Null_Name); + marineStatus->lastmodule=NULL; + marineStatus->destinationmodule=NULL; + marineStatus->missionmodule=NULL; + marineStatus->fearmodule=NULL; + marineStatus->my_facing_point=sbPtr->DynPtr->Position; + + marineStatus->path=generatorBlock->path; + marineStatus->stepnumber=generatorBlock->stepnumber; + + marineStatus->sawlastframe=0; + marineStatus->gotapoint=0; + marineStatus->lastframe_fallingspeed=0; + marineStatus->suspicious=0; + marineStatus->previous_suspicion=0; + marineStatus->using_squad_suspicion=0; + marineStatus->suspect_point.vx=0; + marineStatus->suspect_point.vy=0; + marineStatus->suspect_point.vz=0; + marineStatus->internalState=0; + #if MOTIONTRACKERS + if (marineStatus->My_Weapon->EnableTracker) { + if ((FastRandom()&65535)<(ONE_FIXED>>2)) { + marineStatus->mtracker_timer=FastRandom()&65535; + } else { + marineStatus->mtracker_timer=-1; + } + } else { + marineStatus->mtracker_timer=-1; + } + #else + marineStatus->mtracker_timer=-1; + #endif + marineStatus->GibbFactor=0; + marineStatus->Wounds=0; + + marineStatus->incidentFlag=0; + marineStatus->incidentTimer=0; + + if (marineStatus->My_Weapon->id==MNPCW_MPistol) { + /* Special case for pistols? */ + marineStatus->lastroundhit=PISTOL_CLIP_SIZE; + } + marineStatus->clipammo=marineStatus->My_Weapon->clip_size; + marineStatus->roundsForThisTarget=0; + + //InitShapeAnimationController(&marineStatus->ShpAnimCtrl, GetShapeData(sbPtr->shapeIndex)); + + root_section=GetNamedHierarchyFromLibrary(marineStatus->My_Weapon->Riffname,marineStatus->My_Weapon->HierarchyName); + Create_HModel(&marineStatus->HModelController,root_section); + InitHModelSequence(&marineStatus->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Standard,ONE_FIXED); + + if (marineStatus->My_Weapon->UseElevation) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&marineStatus->HModelController,"Elevation",(int)HMSQT_MarineStand,(int)MSSS_Elevation,0); + GLOBALASSERT(delta); + delta->timer=32767; + } + + /* Create blank hit delta sequence. */ + if (strcmp("hnpcmarine",marineStatus->My_Weapon->Riffname)==0) + { + if (HModelSequence_Exists(&marineStatus->HModelController,(int)HMSQT_MarineStand,(int)MSSS_HitChestFront)) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&marineStatus->HModelController,"HitDelta",(int)HMSQT_MarineStand,(int)MSSS_HitChestFront,(ONE_FIXED>>2)); + GLOBALASSERT(delta); + delta->Playing=0; + } + } + + marineStatus->My_Gunflash_Section=GetThisSectionData(marineStatus->HModelController.section_data,marineStatus->My_Weapon->GunflashName); + marineStatus->My_Elevation_Section=GetThisSectionData(marineStatus->HModelController.section_data,marineStatus->My_Weapon->ElevationSection); + + //initialise female to 0.. + //may be changed by ChangeToAlternateAccoutrementSet + marineStatus->Female=0; + marineStatus->Voice=0; + marineStatus->Android=marineStatus->My_Weapon->Android; + + //use accoutement set for both marine and civilian + #if 0 + if (strcmp("hnpcmarine",marineStatus->My_Weapon->Riffname)==0) { + int dice=FastRandom()&65535; + if (dice<16384) { + ChangeToAlternateShapeSet(sbPtr, "Face Four"); + } else if (dice<32768) { + ChangeToAlternateShapeSet(sbPtr, "Face Three"); + } + } else if (strcmp("hnpc_civvie",marineStatus->My_Weapon->Riffname)==0) { + #if 0 + int dice=FastRandom()&65535; + if (dice<32767) { + ChangeToAlternateShapeSet(sbPtr, "MedicalGuy"); + } else if (dice<49152) { + ChangeToAlternateShapeSet(sbPtr, "CompanyGuy"); + } + #else + ChangeToAlternateAccoutrementSet(sbPtr, 0); + #endif + } + #else + //texture id 0 picks random one out of those allowed by the level + ChangeToAlternateAccoutrementSet(sbPtr, 0); + #endif + marineStatus->VoicePitch = (FastRandom() & 255) - 128; + + Marine_SwitchExpression(sbPtr,0); + marineStatus->Target_Expression=0; + marineStatus->Blink=-1; + + ProveHModel_Far(&marineStatus->HModelController,sbPtr); + + if (marineStatus->My_Weapon->WeaponFireFunction==NULL) { + InitMission(sbPtr,MM_NonCom); + } else if ( (marineStatus->path!=-1)&&(marineStatus->stepnumber!=-1)) { + InitMission(sbPtr,MM_Pathfinder); + } else { + InitMission(sbPtr,MM_Wander); + } + + } + else + { + /* allocation failed */ + RemoveBehaviourStrategy(sbPtr); + return; + } +} + +void SetMarineElevation(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + int offsetx,offsety,offsetz,offseta,angle1; + DELTA_CONTROLLER *elevation_controller; + VECTORCH *gunpos; + + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + + if (marineStatusPointer->My_Weapon->UseElevation==0) { + /* Non elevating weapon. */ + return; + } + + if (marineStatusPointer->My_Elevation_Section) { + gunpos=&marineStatusPointer->My_Elevation_Section->World_Offset; + } else { + gunpos=&sbPtr->DynPtr->Position; + } + /* Aim at weaponTarget. */ + + offsetx=(marineStatusPointer->weaponTarget.vx)-(gunpos->vx); + offsety=(marineStatusPointer->weaponTarget.vz)-(gunpos->vz); + offseta=-((marineStatusPointer->weaponTarget.vy)-(gunpos->vy)); + + while( (offsetx>(ONE_FIXED>>2)) + ||(offsety>(ONE_FIXED>>2)) + ||(offseta>(ONE_FIXED>>2)) + ||(offsetx<-(ONE_FIXED>>2)) + ||(offsety<-(ONE_FIXED>>2)) + ||(offseta<-(ONE_FIXED>>2))) { + + offsetx>>=1; + offsety>>=1; + offseta>>=1; + + } + + offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety)); + angle1=ArcTan(offseta,offsetz); + + if (angle1>=3072) angle1-=4096; + if (angle1>=2048) angle1=angle1-3072; + if (angle1>1024) angle1=2048-angle1; + + GLOBALASSERT(angle1>=-1024); + GLOBALASSERT(angle1<=1024); + + + elevation_controller=Get_Delta_Sequence(&marineStatusPointer->HModelController,"Elevation"); + GLOBALASSERT(elevation_controller); + + if (marineStatusPointer->IAmCrouched) { + elevation_controller->sequence_type=HMSQT_MarineCrouch; + elevation_controller->sub_sequence=MCrSS_Elevation; + } else { + if (marineStatusPointer->FiringAnim==1) { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=MSSS_Hip_Fire_Elevation; + } else { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=MSSS_Elevation; + } + } + + { + int fake_timer; + + fake_timer=1024-angle1; + fake_timer<<=5; + if (fake_timer==65536) fake_timer=65535; + + GLOBALASSERT(fake_timer>=0); + GLOBALASSERT(fake_timer<65536); + + elevation_controller->timer=fake_timer; + + } + + /* Unless you're a reloading pistol. */ + if (marineStatusPointer->My_Weapon->id==MNPCW_MPistol) { + if (marineStatusPointer->lastroundhit==-1) { + elevation_controller->timer=32767; + } + } + /* Or a firing grenade launcher or shotgun in state 1. */ + if ((marineStatusPointer->My_Weapon->id==MNPCW_GrenadeLauncher)||(marineStatusPointer->My_Weapon->id==MNPCW_MShotgun) + ||(marineStatusPointer->My_Weapon->id==MNPCW_Android) + ||(marineStatusPointer->My_Weapon->id==MNPCW_AndroidSpecial)) { + if ((marineStatusPointer->behaviourState==MBS_Firing)&&(marineStatusPointer->internalState)) { + elevation_controller->timer=32767; + } + } +} + +void CentreMarineElevation(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + DELTA_CONTROLLER *elevation_controller; + + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + + if (marineStatusPointer->My_Weapon->UseElevation==0) { + /* Non elevating weapon. */ + return; + } + + elevation_controller=Get_Delta_Sequence(&marineStatusPointer->HModelController,"Elevation"); + GLOBALASSERT(elevation_controller); + + if (marineStatusPointer->IAmCrouched) { + elevation_controller->sequence_type=HMSQT_MarineCrouch; + elevation_controller->sub_sequence=MCrSS_Elevation; + } else { + if (marineStatusPointer->FiringAnim==1) { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=MSSS_Hip_Fire_Elevation; + } else { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=MSSS_Elevation; + } + } + + elevation_controller->timer=32767; + +} + +void MarineBehaviour(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + int marineIsNear; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* test if we've got a containing module: if we haven't, do nothing. + This is important as the object could have been marked for deletion by the visibility + management system...*/ + if(!sbPtr->containingModule) + { + DestroyAnyStrategyBlock(sbPtr); /* just to make sure */ + return; + } else if (marineStatusPointer->behaviourState!=MBS_Dying) { + #if SUPER_PHEROMONE_SYSTEM + AddMarinePheromones(sbPtr->containingModule->m_aimodule); + #endif + } + + if(sbPtr->SBdptr) { + marineIsNear=1; + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]); + } else { + marineIsNear=0; + } + + if (ShowSlack) { + int synthSpeed,setSpeed,slack; + VECTORCH offset; + extern int SlackTotal; + extern int SlackSize; + + offset.vx=(sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx); + offset.vy=(sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy); + offset.vz=(sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz); + + synthSpeed=Magnitude(&offset); + synthSpeed=DIV_FIXED(synthSpeed,NormalFrameTime); + setSpeed=Magnitude(&sbPtr->DynPtr->LinVelocity); + + if (setSpeed) { + slack=(ONE_FIXED-(DIV_FIXED(synthSpeed,setSpeed))); + SlackTotal+=slack; + SlackSize++; + } + #if 0 + PrintDebuggingText("MaxSpeed = %d, SynthSpeed = %d, SetSpeed = %d, Slack %d\n",alienStatusPointer->MaxSpeed,synthSpeed,setSpeed,slack); + #endif + } + + GLOBALASSERT(marineStatusPointer->My_Weapon->WeaponPanicFireFunction); + + InitWaypointSystem(0); + + if ((Validate_Target(marineStatusPointer->Target,marineStatusPointer->Target_SBname)==0) + &&((marineStatusPointer->Target!=Player->ObStrategyBlock)||(Observer))) { + marineStatusPointer->Target=NULL; + /* Were you suspicious of something before? */ + if (marineStatusPointer->previous_suspicion) { + marineStatusPointer->suspicious=marineStatusPointer->previous_suspicion; + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + } + } + + /* unset suspicion? */ + + if (marineStatusPointer->suspicious!=0) { + if ((marineStatusPointer->behaviourState!=MBS_Approaching) + &&(marineStatusPointer->behaviourState!=MBS_Responding)) { + marineStatusPointer->suspicious-=NormalFrameTime; + /* To fix the next trap... */ + if (marineStatusPointer->suspicious==0) { + marineStatusPointer->suspicious=-1; + } + } + if (marineStatusPointer->suspicious<0) { + marineStatusPointer->suspicious=0; + /* Set to zero on natural timeout, too. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + if ((marineStatusPointer->behaviourState==MBS_Waiting) + ||(marineStatusPointer->behaviourState==MBS_Sentry)) { + /* We might concievably want to do this for all states. */ + marineStatusPointer->gotapoint=0; + } + } + /* Approaching marines remain suspicious. */ + } else { + /* Not suspicious. */ + if (marineStatusPointer->Target) { + if (!MarineCanSeeTarget(sbPtr)) { + /* Oh well, forget it, then. */ + marineStatusPointer->Target=NULL; + } + } + } + /* Squad level suspicion? */ + if (((marineStatusPointer->suspicious==0)||(marineStatusPointer->using_squad_suspicion)) + &&(NpcSquad.Squad_Suspicion!=0) + &&(sbPtr->SBdptr) + &&(marineStatusPointer->behaviourState!=MBS_Approaching) + &&(marineStatusPointer->behaviourState!=MBS_Firing) + &&(marineStatusPointer->behaviourState!=MBS_Dying)) { + /* Use squad suspicion. */ + marineStatusPointer->suspicious=MARINE_PARANOIA_TIME; + marineStatusPointer->suspect_point=NpcSquad.squad_suspect_point; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=1; + } + + if (marineStatusPointer->sawlastframe==2) { + marineStatusPointer->sawlastframe=0; + } + + /* Unset incident flag. */ + marineStatusPointer->incidentFlag=0; + + marineStatusPointer->incidentTimer-=NormalFrameTime; + + if (marineStatusPointer->incidentTimer<0) { + marineStatusPointer->incidentFlag=1; + marineStatusPointer->incidentTimer=32767+(FastRandom()&65535); + } + + /* Run Motion Tracker. */ + + tracker_noise=0; + + if (marineStatusPointer->mtracker_timer>=0) { + marineStatusPointer->mtracker_timer+=NormalFrameTime; + } + /* Negative timer means no tracker. */ + if (marineStatusPointer->mtracker_timer>ONE_FIXED) { + marineStatusPointer->mtracker_timer=0; + tracker_noise=1; + } + + if ((marineStatusPointer->Target==NULL) + #if ANARCHY + || (marineStatusPointer->lastmodule!=sbPtr->containingModule->m_aimodule) + || (marineStatusPointer->Target==Player->ObStrategyBlock) + #endif + ) { + + if ((marineIsNear)||(marineStatusPointer->incidentFlag)) { + /* Get new target. */ + marineStatusPointer->roundsForThisTarget=0; + marineStatusPointer->sawlastframe=0; + marineStatusPointer->Target=Marine_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr); + + if (marineStatusPointer->Target) { + #if MARINE_STATE_PRINT + textprint("Marine gets new target.\n"); + #endif + COPY_NAME(marineStatusPointer->Target_SBname,marineStatusPointer->Target->SBname); + + /* Remember your suspicion... */ + marineStatusPointer->previous_suspicion=marineStatusPointer->suspicious; + marineStatusPointer->suspicious=0; + + /* Do stats. */ + if (marineStatusPointer->Target==Player->ObStrategyBlock) { + if (marineStatusPointer->SpotFlag==0) { + CurrentGameStats_Spotted(); + marineStatusPointer->SpotFlag=1; + } + } + + /* New Enemy! */ + + if (NpcSquad.alertStatus==0) { + NpcSquad.alertStatus=1; + } + if (marineStatusPointer->Target->containingModule) { + ZoneAlert(2,marineStatusPointer->Target->containingModule->m_aimodule); + } else { + ZoneAlert(2,sbPtr->containingModule->m_aimodule); + } + + } else { + #if 0 + PrintDebuggingText("Marine found no target!\n"); + #endif + } + } + } else if (marineStatusPointer->mtracker_timer==0) { + /* Fake sweep for wheeps. */ + FakeTrackerWheepGenerator(&sbPtr->DynPtr->Position,sbPtr); + + if (marineStatusPointer->Target->SBdptr) { + if (NpcSquad.Squad_Suspicion!=SQUAD_PARANOIA_TIME) { + if (MarineCanSeeTarget(sbPtr)) { + /* Hey, guys! */ + GLOBALASSERT(marineStatusPointer->Target->DynPtr); + NpcSquad.Squad_Suspicion=SQUAD_PARANOIA_TIME; + NpcSquad.squad_suspect_point=marineStatusPointer->Target->DynPtr->Position; + } + } + } + } + + /* Brushing Test. */ + + { + struct collisionreport *nextReport; + nextReport = sbPtr->DynPtr->CollisionReportPtr; + + while(nextReport) + { + if(nextReport->ObstacleSBPtr) + { + if((nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourAlien)|| + ((nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourMarinePlayer) + &&(AvP.PlayerType!=I_Marine))|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourAlienPlayer)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourPredatorPlayer)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourNetGhost)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourXenoborg)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourPredatorAlien)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourQueenAlien)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourFaceHugger)) + { + marineStatusPointer->suspicious=MARINE_PARANOIA_TIME; + marineStatusPointer->suspect_point=nextReport->ObstacleSBPtr->DynPtr->Position; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + if (marineStatusPointer->Android==0) { + marineStatusPointer->Courage-=(NormalFrameTime>>1); + } + } + } + nextReport = nextReport->NextCollisionReportPtr; + } + } + + /* Blinking! */ + if (marineStatusPointer->behaviourState!=MBS_Dying) { + if (marineStatusPointer->Expression<3) { + if (marineStatusPointer->incidentFlag) { + if ((FastRandom()&65535)<24000) { + switch (marineStatusPointer->Expression) { + default: + GLOBALASSERT(0); + break; + case 0: + Marine_SwitchExpression(sbPtr,3); + break; + case 1: + Marine_SwitchExpression(sbPtr,4); + break; + case 2: + Marine_SwitchExpression(sbPtr,5); + break; + } + marineStatusPointer->Blink=0; + } + } + } else if (marineStatusPointer->Expression>=3) { + if (marineStatusPointer->Blink>=0) { + marineStatusPointer->Blink+=NormalFrameTime; + if (marineStatusPointer->Blink>(ONE_FIXED/7)) { + switch (marineStatusPointer->Expression) { + default: + GLOBALASSERT(0); + break; + case 3: + Marine_SwitchExpression(sbPtr,0); + break; + case 4: + Marine_SwitchExpression(sbPtr,1); + break; + case 5: + Marine_SwitchExpression(sbPtr,2); + break; + } + } + } + } + } + + /* Now hearing. */ + + DoMarineHearing(sbPtr); + + /* That was senses. Now courage. */ + if (marineStatusPointer->Android==0) { + + if ((marineStatusPointer->Target==NULL)&&(marineStatusPointer->suspicious==0)) { + marineStatusPointer->Courage+=MUL_FIXED(NormalFrameTime,300); + } + + marineStatusPointer->Courage+=NpcSquad.Squad_Delta_Morale; + + if (marineStatusPointer->Courage>=(ONE_FIXED<<1)) { + marineStatusPointer->Courage=(ONE_FIXED<<1); + } else if (marineStatusPointer->Courage<0) { + marineStatusPointer->Courage=0; + } + } else { + marineStatusPointer->Courage=ONE_FIXED; + } + + /* Dead yet? */ + + if (marineStatusPointer->GibbFactor) { + /* If you're gibbed, you're dead. */ + sbPtr->SBDamageBlock.Health = 0; + } + + if (sbPtr->SBDamageBlock.IsOnFire) { + + CauseDamageToObject(sbPtr,&firedamage,NormalFrameTime,NULL); + + if (sbPtr->I_SBtype==I_BehaviourNetCorpse) { + /* Gettin' out of here... */ + return; + } + + if (marineStatusPointer->Mission!=MM_RunAroundOnFire) { + if (marineStatusPointer->Android==0) { + Convert_To_RunningOnFire(sbPtr); + } else { + /* Handle sound for an android. */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + } else { + if (ActiveSounds[marineStatusPointer->soundHandle].soundIndex!=SID_FIRE) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(SID_FIRE,"dlev",&(sbPtr->DynPtr->Position),&marineStatusPointer->soundHandle,127); + } + } + } + } + + } + + /* Mission Control! */ + + if ((ShowSquadState)||((sbPtr->SBdptr)&&(ShowNearSquad))) { + if (sbPtr->name) { + PrintDebuggingText("%s: ",sbPtr->name); + } else { + PrintDebuggingText("Unnamed: "); + } + if (marineStatusPointer->suspicious) { + PrintDebuggingText("Suspicious %d ",marineStatusPointer->suspicious); + } + } + + if ((marineStatusPointer->Mission!=MM_NonCom)&&(marineStatusPointer->Mission!=MM_RunAroundOnFire)) { + if (marineStatusPointer->My_Weapon->WeaponFireFunction==NULL) { + LOGDXFMT(("Marine Weapon ID = %d\n",marineStatusPointer->My_Weapon->id)); + LOGDXFMT(("Mission %d\n",marineStatusPointer->Mission)); + } + GLOBALASSERT(marineStatusPointer->My_Weapon->WeaponFireFunction); + } + + switch (marineStatusPointer->Mission) { + case (MM_Wait_Then_Wander): + case (MM_Wander): + { + WanderMission_Control(sbPtr); + break; + } + case (MM_Guard): + { + GuardMission_Control(sbPtr); + break; + } + case (MM_LocalGuard): + { + LocalGuardMission_Control(sbPtr); + break; + } + case (MM_NonCom): + { + LoiterMission_Control(sbPtr); + break; + } + case (MM_Pathfinder): + { + PathfinderMission_Control(sbPtr); + break; + } + case (MM_RunAroundOnFire): + { + RunAroundOnFireMission_Control(sbPtr); + break; + } + default: + { + GLOBALASSERT(0); + break; + } + } + + if (TERROR_MODE) { + if ((marineStatusPointer->behaviourState!=MBS_PanicFire) + &&(marineStatusPointer->behaviourState!=MBS_PanicReloading) + &&(marineStatusPointer->behaviourState!=MBS_Retreating) + &&(marineStatusPointer->behaviourState!=MBS_Approaching) + &&(marineStatusPointer->behaviourState!=MBS_GetWeapon) + &&(marineStatusPointer->behaviourState!=MBS_Taunting) + &&(marineStatusPointer->behaviourState!=MBS_Avoidance) + &&(marineStatusPointer->behaviourState!=MBS_Dying) + ) { + Marine_Enter_Retreat_State(sbPtr); + } + } + + if (marineStatusPointer->My_Weapon->id==MNPCW_Minigun) { + DELTA_CONTROLLER *mgd=Get_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun"); + if (mgd) { + NPC_Maintain_Minigun(sbPtr,mgd); + } + } + + /* if we have actually died, we need to remove the strategyblock... so + do this here */ + if((marineStatusPointer->behaviourState == MBS_Dying)&&(marineStatusPointer->stateTimer <= 0)) { + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(marineStatusPointer->soundHandle); + if(marineStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) Sound_Stop(marineStatusPointer->soundHandle2); + + DestroyAnyStrategyBlock(sbPtr); + } + + marineStatusPointer->lastmodule=sbPtr->containingModule->m_aimodule; + + if (sbPtr->SBdptr) { + /* I reckon only near trackers wheep. */ + if (tracker_noise==1) { + Sound_Play(SID_TRACKER_CLICK,"d",&sbPtr->DynPtr->Position); + } else if (tracker_noise==2) { + Sound_Play(SID_TRACKER_WHEEP,"d",&sbPtr->DynPtr->Position); + } + } + + /* Update squad stats. */ + if ((marineStatusPointer->behaviourState==MBS_Responding) + ||((marineStatusPointer->behaviourState==MBS_Avoidance) + &&(marineStatusPointer->lastState==MBS_Responding))) { + + NpcSquad.Alt_RespondingMarines++; + } + + if ((marineStatusPointer->Mission==MM_RunAroundOnFire) + &&(sbPtr->SBdptr)) { + + NpcSquad.Alt_NearBurningMarines++; + } + + if ((sbPtr->SBdptr)&&( + (marineStatusPointer->behaviourState==MBS_Retreating) + ||(marineStatusPointer->Mission==MM_RunAroundOnFire) + )) { + /* Burning marines are considered panicked, too. */ + + NpcSquad.Alt_NearPanickedMarines++; + } + + if ((sbPtr->SBdptr)&&(marineStatusPointer->My_Weapon->ARealMarine)&&( + (marineStatusPointer->behaviourState!=MBS_Retreating) + &&(marineStatusPointer->behaviourState!=MBS_Dying) + )) { + + NpcSquad.Alt_NearUnpanickedMarines++; + } + + /* Make marines heal, really slowly? */ + HModel_Regen(&marineStatusPointer->HModelController,(120*ONE_FIXED)); + /* Two minutes. Only heals sections, too. */ + + /* Change the face if we can... */ + Marine_UpdateFace(sbPtr); + + /* And finally, update lastframe flag. */ + Marine_ConsiderFallingDamage(sbPtr); + +} + +void EndMarineMuzzleFlash(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + +} + +void InitMission(STRATEGYBLOCK *sbPtr,MARINE_MISSION mission) { + + MARINE_STATUS_BLOCK *marineStatus; + + marineStatus = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatus); + + switch (mission) { + case MM_RunAroundOnFire: + marineStatus->Mission=MM_RunAroundOnFire; + marineStatus->behaviourState = MBS_Wandering; + marineStatus->lastState = MBS_Waiting; + /* Shouldn't need a sequence force. */ + break; + case MM_Guard: + marineStatus->Mission=MM_Guard; + marineStatus->behaviourState = MBS_Sentry; + marineStatus->lastState = MBS_Waiting; + Marine_Enter_SentryMode_State(sbPtr); + break; + case MM_LocalGuard: + marineStatus->Mission=MM_LocalGuard; + marineStatus->behaviourState = MBS_Waiting; + marineStatus->lastState = MBS_Waiting; + Marine_Enter_Wait_State(sbPtr); + break; + case MM_NonCom: + marineStatus->Mission=MM_NonCom; + marineStatus->behaviourState = MBS_Waiting; + marineStatus->lastState = MBS_Waiting; + Marine_Enter_Wait_State(sbPtr); + break; + case MM_Wait_Then_Wander: + marineStatus->Mission=MM_Wait_Then_Wander; + marineStatus->behaviourState = MBS_Waiting; + marineStatus->lastState = MBS_Waiting; + Marine_Enter_Wait_State(sbPtr); + break; + case MM_Pathfinder: + marineStatus->Mission=MM_Pathfinder; + marineStatus->behaviourState = MBS_Pathfinding; + marineStatus->lastState = MBS_Waiting; + Marine_Enter_Pathfinder_State(sbPtr); + break; + case MM_Wander: + default: + marineStatus->Mission=MM_Wander; + marineStatus->behaviourState = MBS_Approaching; + marineStatus->lastState = MBS_Waiting; + Marine_Enter_Approach_State(sbPtr); + break; + } + +} + +void WanderMission_Control(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + STATE_RETURN_CONDITION state_result; + int marineIsNear; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + + /* Current Behaviour. */ + + if(sbPtr->SBdptr) { + marineIsNear=1; + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]); + } else { + marineIsNear=0; + } + + { + + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + if (marineStatusPointer->Mission==MM_Wait_Then_Wander) { + /* A bit of a cheat. */ + PrintDebuggingText("Wait Then "); + } + } + + switch(marineStatusPointer->behaviourState) + { + case(MBS_Approaching): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine approach in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_Approach(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Approach(sbPtr); + } + WanderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Firing): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=(*marineStatusPointer->My_Weapon->WeaponFireFunction)(sbPtr); + SetMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Firing(sbPtr); + } + WanderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_PumpAction): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine pump action in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_PumpAction(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_PumpAction(sbPtr); + } + WanderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_PanicFire): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine panic firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=(*marineStatusPointer->My_Weapon->WeaponPanicFireFunction)(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Firing(sbPtr); + } + WanderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Avoidance): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine "); + switch (marineStatusPointer->avoidanceManager.substate) { + default: + case AvSS_FreeMovement: + PrintDebuggingText("Avoidance Level 0"); + break; + case AvSS_FirstAvoidance: + PrintDebuggingText("Avoidance Level 1"); + break; + case AvSS_SecondAvoidance: + PrintDebuggingText("Avoidance Level 2"); + break; + case AvSS_ThirdAvoidance: + PrintDebuggingText("Avoidance Level 3"); + break; + } + PrintDebuggingText(" in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + if(marineIsNear) { + state_result=Execute_MNS_Avoidance(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Avoidance(sbPtr); + } + WanderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Wandering): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine wander in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Wander(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wander(sbPtr); + } + WanderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Responding): + { + /* Closest to hunt. */ + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine responding in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Respond(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Respond(sbPtr); + } + WanderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Retreating): + { + /* Real men never retreat! */ + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine Retreating in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Retreat(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Retreat(sbPtr); + } + WanderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Waiting): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine wait in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Wait(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wait(sbPtr); + } + WanderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Sentry): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine sentry in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + GLOBALASSERT(0); + if(marineIsNear) { + state_result=Execute_MNS_SentryMode(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wait(sbPtr); + } + WanderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Dying): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine dying in %s\n",sbPtr->containingModule->name); + } + if (marineIsNear) { + Execute_Dying(sbPtr); + } else { + Execute_Dying(sbPtr); + } + break; + } + case(MBS_Taunting): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine taunt in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_Taunting(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_Taunting(sbPtr); + } + WanderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Reloading): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_Reloading(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_Reloading(sbPtr); + } + WanderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_PanicReloading): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine panic reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_PanicReloading(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_PanicReloading(sbPtr); + } + WanderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_GetWeapon): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine get weapon in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_GetWeapon(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_GetWeapon(sbPtr); + } + WanderMission_SwitchState(sbPtr,state_result); + break; + } + case MBS_Returning: + case MBS_Pathfinding: + { + /* How the hell did you get here?!? */ + Marine_Enter_Wander_State(sbPtr); + break; + } + case(MBS_AcidAvoidance): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Wander marine acid avoidance in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_AcidAvoidance(sbPtr); + CentreMarineElevation(sbPtr); + } else { + Marine_Enter_Wait_State(sbPtr); + break; + } + WanderMission_SwitchState(sbPtr,state_result); + break; + } + default: + { + LOGDXFMT(("Marine in unsupported state %d!\n",marineStatusPointer->behaviourState)); + LOCALASSERT(1==0); + } + } + } + + if (!marineIsNear) { + + /* check here to see if marine is in a proximity door - if so, trigger it to open. */ + { + MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule); + + if(doorType == MDT_ProxDoor) + ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->marineTrigger = 1; + } + + /* lastly, do a containment test: to make sure that we are inside a module. */ + #if UseLocalAssert + { + VECTORCH localCoords; + MODULE *thisModule = sbPtr->containingModule; + + LOCALASSERT(thisModule); + + localCoords = sbPtr->DynPtr->Position; + localCoords.vx -= thisModule->m_world.vx; + localCoords.vy -= thisModule->m_world.vy; + localCoords.vz -= thisModule->m_world.vz; + + if(PointIsInModule(thisModule, &localCoords)==0) + { + #if (!PSX) + textprint("FAR MARINE MODULE CONTAINMENT FAILURE \n"); + LOCALASSERT(1==0); + #endif + } + } + #endif + } + +} + +void PathfinderMission_Control(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + STATE_RETURN_CONDITION state_result; + int marineIsNear; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + + /* Current Behaviour. */ + + if(sbPtr->SBdptr) { + marineIsNear=1; + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]); + } else { + marineIsNear=0; + } + + { + + switch(marineStatusPointer->behaviourState) + { + case(MBS_Approaching): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine approach in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_Approach(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Approach(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Firing): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=(*marineStatusPointer->My_Weapon->WeaponFireFunction)(sbPtr); + SetMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Firing(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_PumpAction): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine pump action in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_PumpAction(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_PumpAction(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_PanicFire): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine panic firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=(*marineStatusPointer->My_Weapon->WeaponPanicFireFunction)(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Firing(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Avoidance): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine "); + switch (marineStatusPointer->avoidanceManager.substate) { + default: + case AvSS_FreeMovement: + PrintDebuggingText("Avoidance Level 0"); + break; + case AvSS_FirstAvoidance: + PrintDebuggingText("Avoidance Level 1"); + break; + case AvSS_SecondAvoidance: + PrintDebuggingText("Avoidance Level 2"); + break; + case AvSS_ThirdAvoidance: + PrintDebuggingText("Avoidance Level 3"); + break; + } + PrintDebuggingText(" in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + if(marineIsNear) { + state_result=Execute_MNS_Avoidance(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Avoidance(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Wandering): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine wander in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Wander(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wander(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Responding): + { + /* Closest to hunt. */ + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine responding in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Respond(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Respond(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Retreating): + { + /* Real men never retreat! */ + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine retreating in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Retreat(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Retreat(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Waiting): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine wait in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Wait(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wait(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Sentry): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine sentry in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + GLOBALASSERT(0); + if(marineIsNear) { + state_result=Execute_MNS_SentryMode(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wait(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Dying): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine dying in %s\n",sbPtr->containingModule->name); + } + if (marineIsNear) { + Execute_Dying(sbPtr); + } else { + Execute_Dying(sbPtr); + } + break; + } + case(MBS_Pathfinding): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine pathfinding in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Pathfinder(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Pathfinder(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Taunting): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine taunt in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_Taunting(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_Taunting(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Returning): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine returning in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Return(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Return(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Reloading): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_Reloading(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_Reloading(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_PanicReloading): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine panic reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_PanicReloading(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_PanicReloading(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_GetWeapon): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Pathfinder marine get weapon in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_GetWeapon(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_GetWeapon(sbPtr); + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_AcidAvoidance): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Prahfinder marine acid avoidance in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_AcidAvoidance(sbPtr); + CentreMarineElevation(sbPtr); + } else { + Marine_Enter_Wait_State(sbPtr); + break; + } + PathfinderMission_SwitchState(sbPtr,state_result); + break; + } + default: + { + LOGDXFMT(("Marine in unsupported state %d!\n",marineStatusPointer->behaviourState)); + LOCALASSERT(1==0); + } + } + } + + if (!marineIsNear) { + + /* check here to see if marine is in a proximity door - if so, trigger it to open. */ + { + MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule); + + if(doorType == MDT_ProxDoor) + ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->marineTrigger = 1; + } + + /* lastly, do a containment test: to make sure that we are inside a module. */ + #if UseLocalAssert + { + VECTORCH localCoords; + MODULE *thisModule = sbPtr->containingModule; + + LOCALASSERT(thisModule); + + localCoords = sbPtr->DynPtr->Position; + localCoords.vx -= thisModule->m_world.vx; + localCoords.vy -= thisModule->m_world.vy; + localCoords.vz -= thisModule->m_world.vz; + + if(PointIsInModule(thisModule, &localCoords)==0) + { + #if (!PSX) + textprint("FAR MARINE MODULE CONTAINMENT FAILURE \n"); + LOCALASSERT(1==0); + #endif + } + } + #endif + } + +} + +void GuardMission_Control(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + STATE_RETURN_CONDITION state_result; + int marineIsNear; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Firstly, fix missionmodule. */ + + if (marineStatusPointer->missionmodule==NULL) { + marineStatusPointer->missionmodule=sbPtr->containingModule->m_aimodule; + marineStatusPointer->my_spot=sbPtr->DynPtr->Position; + } + + if(sbPtr->SBdptr) { + marineIsNear=1; + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]); + } else { + marineIsNear=0; + } + + { + + switch(marineStatusPointer->behaviourState) + { + case(MBS_Approaching): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Guard marine approaching in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + GLOBALASSERT(0); + if (marineIsNear) { + state_result=Execute_MNS_Approach(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wander(sbPtr); + } + GuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Firing): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Guard marine firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=(*marineStatusPointer->My_Weapon->WeaponFireFunction)(sbPtr); + SetMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Firing(sbPtr); + } + GuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_PumpAction): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Guard marine pump action in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_PumpAction(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_PumpAction(sbPtr); + } + GuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_PanicFire): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Guard marine panic firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=(*marineStatusPointer->My_Weapon->WeaponPanicFireFunction)(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Firing(sbPtr); + } + GuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Avoidance): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Guard marine "); + switch (marineStatusPointer->avoidanceManager.substate) { + default: + case AvSS_FreeMovement: + PrintDebuggingText("Avoidance Level 0"); + break; + case AvSS_FirstAvoidance: + PrintDebuggingText("Avoidance Level 1"); + break; + case AvSS_SecondAvoidance: + PrintDebuggingText("Avoidance Level 2"); + break; + case AvSS_ThirdAvoidance: + PrintDebuggingText("Avoidance Level 3"); + break; + } + PrintDebuggingText(" in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Avoidance(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Avoidance(sbPtr); + } + GuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Wandering): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Guard marine wandering in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Wander(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wait(sbPtr); + } + GuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Retreating): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Guard marine retreating in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + /* Real men never retreat! */ + if (marineIsNear) { + state_result=Execute_MNS_Retreat(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Retreat(sbPtr); + } + GuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Waiting): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Guard marine waiting in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_SentryMode(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_SentryMode(sbPtr); + } + state_result=SRC_Request_Wait; /* Go back to sentry. */ + GuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Responding): + case(MBS_Sentry): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Guard marine sentry in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_SentryMode(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_SentryMode(sbPtr); + } + GuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Dying): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Guard marine dying in %s\n",sbPtr->containingModule->name); + } + + if (marineIsNear) { + Execute_Dying(sbPtr); + } else { + Execute_Dying(sbPtr); + } + break; + } + case(MBS_Taunting): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Guard marine taunt in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_Taunting(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_Taunting(sbPtr); + } + GuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Reloading): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Guard marine reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_Reloading(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_Reloading(sbPtr); + } + GuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_PanicReloading): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Guard marine panic reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_PanicReloading(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_PanicReloading(sbPtr); + } + GuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_GetWeapon): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Guard marine get weapon in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_GetWeapon(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_GetWeapon(sbPtr); + } + GuardMission_SwitchState(sbPtr,state_result); + break; + } + case MBS_Returning: + case MBS_Pathfinding: + { + /* How the hell did you get here?!? */ + Marine_Enter_Wander_State(sbPtr); + break; + } + case(MBS_AcidAvoidance): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Guard marine acid avoidance in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_AcidAvoidance(sbPtr); + CentreMarineElevation(sbPtr); + } else { + Marine_Enter_Wait_State(sbPtr); + break; + } + GuardMission_SwitchState(sbPtr,state_result); + break; + } + default: + { + LOGDXFMT(("Guard marine in unsupported state %d!\n",marineStatusPointer->behaviourState)); + LOCALASSERT(1==0); + } + } + } + + if (!marineIsNear) { + + /* check here to see if marine is in a proximity door - if so, trigger it to open. */ + { + MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule); + + if(doorType == MDT_ProxDoor) + ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->marineTrigger = 1; + } + + /* lastly, do a containment test: to make sure that we are inside a module. */ + #if UseLocalAssert + { + VECTORCH localCoords; + MODULE *thisModule = sbPtr->containingModule; + + LOCALASSERT(thisModule); + + localCoords = sbPtr->DynPtr->Position; + localCoords.vx -= thisModule->m_world.vx; + localCoords.vy -= thisModule->m_world.vy; + localCoords.vz -= thisModule->m_world.vz; + + if(PointIsInModule(thisModule, &localCoords)==0) + { + #if (!PSX) + textprint("FAR MARINE MODULE CONTAINMENT FAILURE \n"); + LOCALASSERT(1==0); + #endif + } + } + #endif + } + +} + +void LocalGuardMission_Control(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + STATE_RETURN_CONDITION state_result; + int marineIsNear; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Firstly, fix missionmodule. */ + + if (marineStatusPointer->missionmodule==NULL) { + marineStatusPointer->missionmodule=sbPtr->containingModule->m_aimodule; + } + + if(sbPtr->SBdptr) { + marineIsNear=1; + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]); + } else { + marineIsNear=0; + } + + { + + switch(marineStatusPointer->behaviourState) + { + case(MBS_Approaching): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine approaching in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Approach(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wander(sbPtr); + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Firing): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=(*marineStatusPointer->My_Weapon->WeaponFireFunction)(sbPtr); + SetMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Firing(sbPtr); + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_PumpAction): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine pump action in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_PumpAction(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_PumpAction(sbPtr); + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_PanicFire): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine panic firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=(*marineStatusPointer->My_Weapon->WeaponPanicFireFunction)(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Firing(sbPtr); + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Avoidance): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine "); + switch (marineStatusPointer->avoidanceManager.substate) { + default: + case AvSS_FreeMovement: + PrintDebuggingText("Avoidance Level 0"); + break; + case AvSS_FirstAvoidance: + PrintDebuggingText("Avoidance Level 1"); + break; + case AvSS_SecondAvoidance: + PrintDebuggingText("Avoidance Level 2"); + break; + case AvSS_ThirdAvoidance: + PrintDebuggingText("Avoidance Level 3"); + break; + } + PrintDebuggingText(" in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Avoidance(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Avoidance(sbPtr); + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Wandering): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine wandering in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Wander(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wait(sbPtr); + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Retreating): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine retreating in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + /* Real men never retreat! */ + if (marineIsNear) { + state_result=Execute_MNS_Retreat(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Retreat(sbPtr); + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Waiting): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine waiting in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Wait(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wait(sbPtr); + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Responding): + { + /* Well, it *might* happen... */ + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine responding in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Respond(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Respond(sbPtr); + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Returning): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine returning in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Return(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Return(sbPtr); + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Sentry): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine sentry in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_SentryMode(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wait(sbPtr); + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Taunting): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine taunt in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_Taunting(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_Taunting(sbPtr); + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Reloading): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_Reloading(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_Reloading(sbPtr); + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_PanicReloading): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine panic reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_PanicReloading(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_PanicReloading(sbPtr); + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Dying): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine dying in %s\n",sbPtr->containingModule->name); + } + + if (marineIsNear) { + Execute_Dying(sbPtr); + } else { + Execute_Dying(sbPtr); + } + break; + } + case(MBS_GetWeapon): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine get weapon in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_GetWeapon(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_GetWeapon(sbPtr); + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + case MBS_Pathfinding: + { + /* How the hell did you get here?!? */ + Marine_Enter_Return_State(sbPtr); + break; + } + case(MBS_AcidAvoidance): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Local Guard marine acid avoidance in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_AcidAvoidance(sbPtr); + CentreMarineElevation(sbPtr); + } else { + Marine_Enter_Wait_State(sbPtr); + break; + } + LocalGuardMission_SwitchState(sbPtr,state_result); + break; + } + default: + { + LOGDXFMT(("Local Guard marine in unsupported state %d!\n",marineStatusPointer->behaviourState)); + LOCALASSERT(1==0); + } + } + } + + if (!marineIsNear) { + + /* check here to see if marine is in a proximity door - if so, trigger it to open. */ + { + MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule); + + if(doorType == MDT_ProxDoor) + ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->marineTrigger = 1; + } + + /* lastly, do a containment test: to make sure that we are inside a module. */ + #if UseLocalAssert + { + VECTORCH localCoords; + MODULE *thisModule = sbPtr->containingModule; + + LOCALASSERT(thisModule); + + localCoords = sbPtr->DynPtr->Position; + localCoords.vx -= thisModule->m_world.vx; + localCoords.vy -= thisModule->m_world.vy; + localCoords.vz -= thisModule->m_world.vz; + + if(PointIsInModule(thisModule, &localCoords)==0) + { + #if (!PSX) + textprint("FAR MARINE MODULE CONTAINMENT FAILURE \n"); + LOCALASSERT(1==0); + #endif + } + } + #endif + } + +} + +void LoiterMission_Control(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + STATE_RETURN_CONDITION state_result; + int marineIsNear; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Fleeing Behaviour. */ + + if(sbPtr->SBdptr) { + marineIsNear=1; + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]); + } else { + marineIsNear=0; + } + + { + + switch(marineStatusPointer->behaviourState) + { + case(MBS_Approaching): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Noncombatant approaching in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Approach(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wait(sbPtr); + } + LoiterMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Firing): + { + + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Noncombatant firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + GLOBALASSERT(0); + state_result=(*marineStatusPointer->My_Weapon->WeaponFireFunction)(sbPtr); + SetMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Firing(sbPtr); + } + LoiterMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_PumpAction): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Noncombatant marine pump action in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_PumpAction(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_PumpAction(sbPtr); + } + LoiterMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_PanicFire): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Noncombatant panic firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=(*marineStatusPointer->My_Weapon->WeaponPanicFireFunction)(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Firing(sbPtr); + } + LoiterMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Avoidance): + { + + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Noncombatant "); + switch (marineStatusPointer->avoidanceManager.substate) { + default: + case AvSS_FreeMovement: + PrintDebuggingText("Avoidance Level 0"); + break; + case AvSS_FirstAvoidance: + PrintDebuggingText("Avoidance Level 1"); + break; + case AvSS_SecondAvoidance: + PrintDebuggingText("Avoidance Level 2"); + break; + case AvSS_ThirdAvoidance: + PrintDebuggingText("Avoidance Level 3"); + break; + } + PrintDebuggingText(" in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Avoidance(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Avoidance(sbPtr); + } + LoiterMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Responding): + case(MBS_Wandering): + { + + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Noncombatant wandering in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Wander(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wander(sbPtr); + } + LoiterMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Retreating): + { + + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Noncombatant retreating in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + /* Wusses, now: they retreat. */ + if (marineIsNear) { + state_result=Execute_MNS_Retreat(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Retreat(sbPtr); + } + LoiterMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Waiting): + { + + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Noncombatant waiting in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_Wait(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wait(sbPtr); + } + LoiterMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Sentry): + { + GLOBALASSERT(0); + + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Noncombatant sentry in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_SentryMode(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MFS_Wait(sbPtr); + } + LoiterMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Reloading): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Noncombatant reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_Reloading(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_Reloading(sbPtr); + } + LoiterMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_PanicReloading): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Noncombatant panic reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if(marineIsNear) { + state_result=Execute_MNS_PanicReloading(sbPtr); + CentreMarineElevation(sbPtr); + } else { + state_result=Execute_MNS_PanicReloading(sbPtr); + } + LoiterMission_SwitchState(sbPtr,state_result); + break; + } + case(MBS_Dying): + { + + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Noncombatant dying in %s\n",sbPtr->containingModule->name); + } + + if (marineIsNear) { + Execute_Dying(sbPtr); + } else { + Execute_Dying(sbPtr); + } + break; + } + case MBS_Returning: + case MBS_Pathfinding: + { + /* How the hell did you get here?!? */ + Marine_Enter_Wander_State(sbPtr); + break; + } + case(MBS_AcidAvoidance): + { + if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) { + PrintDebuggingText("Noncombatant acid avoidance in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage); + } + + if (marineIsNear) { + state_result=Execute_MNS_AcidAvoidance(sbPtr); + CentreMarineElevation(sbPtr); + } else { + Marine_Enter_Wait_State(sbPtr); + break; + } + LoiterMission_SwitchState(sbPtr,state_result); + break; + } + default: + { + /* NonComs can't taunt. */ + LOGDXFMT(("Marine in unsupported state %d!\n",marineStatusPointer->behaviourState)); + LOCALASSERT(1==0); + } + } + } + + if (!marineIsNear) { + + /* check here to see if marine is in a proximity door - if so, trigger it to open. */ + { + MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule); + + if(doorType == MDT_ProxDoor) + ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->marineTrigger = 1; + } + + /* lastly, do a containment test: to make sure that we are inside a module. */ + #if UseLocalAssert + { + VECTORCH localCoords; + MODULE *thisModule = sbPtr->containingModule; + + LOCALASSERT(thisModule); + + localCoords = sbPtr->DynPtr->Position; + localCoords.vx -= thisModule->m_world.vx; + localCoords.vy -= thisModule->m_world.vy; + localCoords.vz -= thisModule->m_world.vz; + + if(PointIsInModule(thisModule, &localCoords)==0) + { + #if (!PSX) + textprint("FAR MARINE MODULE CONTAINMENT FAILURE \n"); + LOCALASSERT(1==0); + #endif + } + } + #endif + } + +} + +void WanderMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result) { + + STATE_RETURN_CONDITION real_state_result; + /* Experiment: override result? */ + switch (state_result) { + case (SRC_Request_Fire): + case (SRC_Request_Approach): + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + real_state_result=SRC_Request_Retreat; + EndMarineMuzzleFlash(sbPtr); + } else { + real_state_result=state_result; + } + break; + default: + real_state_result=state_result; + break; + } + + switch (real_state_result) { + case (SRC_No_Change): + { + /* No action. */ + break; + } + case (SRC_Request_Taunt): + { + Marine_Enter_Taunt_State(sbPtr); + break; + } + case (SRC_Request_Wait): + { + Marine_Enter_Wait_State(sbPtr); + break; + } + case (SRC_Request_Fire): + { + Marine_Enter_Firing_State(sbPtr); + break; + } + case (SRC_Request_PanicFire): + { + Marine_Enter_PanicFire_State(sbPtr); + break; + } + case (SRC_Request_Avoidance): + { + Marine_Enter_Avoidance_State(sbPtr); + break; + } + case (SRC_Request_Approach): + { + Marine_Enter_Approach_State(sbPtr); + break; + } + case (SRC_Request_Wander): + { + Marine_Enter_Wander_State(sbPtr); + break; + } + case (SRC_Request_Retreat): + { + Marine_Enter_Retreat_State(sbPtr); + break; + } + case (SRC_Request_Respond): + { + Marine_Enter_Respond_State(sbPtr); + break; + } + case (SRC_Request_Reload): + { + Marine_Enter_Reload_State(sbPtr); + break; + } + case (SRC_Request_PanicReload): + { + Marine_Enter_PanicReload_State(sbPtr); + break; + } + case (SRC_Request_PumpAction): + { + Marine_Enter_PumpAction_State(sbPtr); + break; + } + case (SRC_Request_PullPistol): + { + Marine_Enter_PullPistol_State(sbPtr); + break; + } + default: + { + /* How did we end up here? */ + GLOBALASSERT(0); + break; + } + +} + +} + +void PathfinderMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result) { + + STATE_RETURN_CONDITION real_state_result; + /* Experiment: override result? */ + switch (state_result) { + case (SRC_Request_Fire): + case (SRC_Request_Approach): + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + real_state_result=SRC_Request_Retreat; + EndMarineMuzzleFlash(sbPtr); + } else { + real_state_result=state_result; + } + break; + default: + real_state_result=state_result; + break; + } + + switch (real_state_result) { + case (SRC_No_Change): + { + /* No action. */ + break; + } + case (SRC_Request_Taunt): + { + Marine_Enter_Taunt_State(sbPtr); + break; + } + case (SRC_Request_Wait): + { + Marine_Enter_Pathfinder_State(sbPtr); + break; + } + case (SRC_Request_Fire): + { + Marine_Enter_Firing_State(sbPtr); + break; + } + case (SRC_Request_PanicFire): + { + Marine_Enter_PanicFire_State(sbPtr); + break; + } + case (SRC_Request_Avoidance): + { + Marine_Enter_Avoidance_State(sbPtr); + break; + } + case (SRC_Request_Approach): + { + Marine_Enter_Approach_State(sbPtr); + break; + } + case (SRC_Request_Wander): + { + Marine_Enter_Wander_State(sbPtr); + break; + } + case (SRC_Request_Retreat): + { + Marine_Enter_Retreat_State(sbPtr); + break; + } + case (SRC_Request_Respond): + { + Marine_Enter_Respond_State(sbPtr); + break; + } + case (SRC_Request_Return): + { + Marine_Enter_Return_State(sbPtr); + break; + } + case (SRC_Request_Reload): + { + Marine_Enter_Reload_State(sbPtr); + break; + } + case (SRC_Request_PanicReload): + { + Marine_Enter_PanicReload_State(sbPtr); + break; + } + case (SRC_Request_PumpAction): + { + Marine_Enter_PumpAction_State(sbPtr); + break; + } + case (SRC_Request_PullPistol): + { + Marine_Enter_PullPistol_State(sbPtr); + break; + } + default: + { + /* How did we end up here? */ + GLOBALASSERT(0); + break; + } + +} + +} + +void GuardMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result) { + + STATE_RETURN_CONDITION real_state_result; + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Experiment: override result? */ + switch (state_result) { + case (SRC_Request_Fire): + case (SRC_Request_Approach): + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + real_state_result=SRC_Request_PanicFire; + EndMarineMuzzleFlash(sbPtr); + } else { + real_state_result=state_result; + } + break; + default: + real_state_result=state_result; + break; + } + + switch (real_state_result) { + case (SRC_No_Change): + { + /* No action. */ + break; + } + case (SRC_Request_Taunt): + { + Marine_Enter_Taunt_State(sbPtr); + break; + } + case (SRC_Request_Wait): + { + Marine_Enter_SentryMode_State(sbPtr); + break; + } + case (SRC_Request_Fire): + { + Marine_Enter_Firing_State(sbPtr); + break; + } + case (SRC_Request_PanicFire): + { + Marine_Enter_PanicFire_State(sbPtr); + break; + } + case (SRC_Request_Avoidance): + { + Marine_Enter_SentryMode_State(sbPtr); + break; + } + case (SRC_Request_Approach): + { + Marine_Enter_SentryMode_State(sbPtr); + break; + } + case (SRC_Request_Wander): + { + Marine_Enter_SentryMode_State(sbPtr); + break; + } + case (SRC_Request_Retreat): + { + Marine_Enter_Retreat_State(sbPtr); + break; + } + case (SRC_Request_Reload): + { + Marine_Enter_Reload_State(sbPtr); + break; + } + case (SRC_Request_PanicReload): + { + Marine_Enter_PanicReload_State(sbPtr); + break; + } + case (SRC_Request_PumpAction): + { + Marine_Enter_PumpAction_State(sbPtr); + break; + } + case (SRC_Request_PullPistol): + { + Marine_Enter_PullPistol_State(sbPtr); + break; + } + default: + { + /* How did we end up here? */ + GLOBALASSERT(0); + break; + } + +} + +} + +void LocalGuardMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result) { + + STATE_RETURN_CONDITION real_state_result; + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Experiment: override result? */ + switch (state_result) { + case (SRC_Request_Fire): + case (SRC_Request_Approach): + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + real_state_result=SRC_Request_Retreat; + EndMarineMuzzleFlash(sbPtr); + } else { + real_state_result=state_result; + } + break; + default: + real_state_result=state_result; + break; + } + + switch (real_state_result) { + case (SRC_No_Change): + { + /* No action. */ + break; + } + case (SRC_Request_Taunt): + { + Marine_Enter_Taunt_State(sbPtr); + break; + } + case (SRC_Request_Wait): + { + if (marineStatusPointer->missionmodule==sbPtr->containingModule->m_aimodule) { + Marine_Enter_Wait_State(sbPtr); + } else { + Marine_Enter_Return_State(sbPtr); + } + break; + } + case (SRC_Request_Fire): + { + Marine_Enter_Firing_State(sbPtr); + break; + } + case (SRC_Request_PanicFire): + { + Marine_Enter_PanicFire_State(sbPtr); + break; + } + case (SRC_Request_Avoidance): + { + Marine_Enter_Avoidance_State(sbPtr); + break; + } + case (SRC_Request_Approach): + { + Marine_Enter_Approach_State(sbPtr); + break; + } + case (SRC_Request_Wander): + { + Marine_Enter_Wander_State(sbPtr); + break; + } + case (SRC_Request_Retreat): + { + Marine_Enter_Retreat_State(sbPtr); + break; + } + case (SRC_Request_Return): + { + Marine_Enter_Return_State(sbPtr); + break; + } + case (SRC_Request_Reload): + { + Marine_Enter_Reload_State(sbPtr); + break; + } + case (SRC_Request_PanicReload): + { + Marine_Enter_PanicReload_State(sbPtr); + break; + } + case (SRC_Request_PumpAction): + { + Marine_Enter_PumpAction_State(sbPtr); + break; + } + case (SRC_Request_PullPistol): + { + Marine_Enter_PullPistol_State(sbPtr); + break; + } + default: + { + /* How did we end up here? */ + GLOBALASSERT(0); + break; + } + +} + +} + +void LoiterMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result) { + + STATE_RETURN_CONDITION real_state_result; + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Experiment: override result? */ + switch (state_result) { + case (SRC_Request_Fire): + case (SRC_Request_Approach): + if ((MarineRetreatsInTheFaceOfDanger(sbPtr))&&(marineStatusPointer->Target)) { + real_state_result=SRC_Request_Retreat; + EndMarineMuzzleFlash(sbPtr); + } else { + real_state_result=state_result; + } + break; + default: + real_state_result=state_result; + break; + } + + switch (real_state_result) { + case (SRC_No_Change): + { + /* No action. */ + break; + } + case (SRC_Request_Taunt): + { + Marine_Enter_Taunt_State(sbPtr); + break; + } + case (SRC_Request_Wait): + { + Marine_Enter_Wait_State(sbPtr); + break; + } + case (SRC_Request_Fire): + case (SRC_Request_Reload): + case (SRC_Request_PanicReload): + case (SRC_Request_PumpAction): + { + Marine_Enter_Retreat_State(sbPtr); + break; + } + case (SRC_Request_Avoidance): + { + Marine_Enter_Avoidance_State(sbPtr); + break; + } + case (SRC_Request_Approach): + { + if (marineStatusPointer->Target) { + /* Approach? You must be mad! */ + Marine_Enter_Retreat_State(sbPtr); + } else { + /* We must be just suspicious. */ + Marine_Enter_Approach_State(sbPtr); + } + break; + } + case (SRC_Request_Retreat): + { + Marine_Enter_Retreat_State(sbPtr); + break; + } + case (SRC_Request_Wander): + { + Marine_Enter_Wander_State(sbPtr); + break; + } + case (SRC_Request_PanicFire): + { + Marine_Enter_PanicFire_State(sbPtr); + break; + } + default: + { + /* How did we end up here? */ + GLOBALASSERT(0); + break; + } + +} + +} + +void MakeMarineNear(STRATEGYBLOCK *sbPtr) +{ + extern MODULEMAPBLOCK AlienDefaultMap; + + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr; + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->SBdptr == NULL); + dynPtr = sbPtr->DynPtr; + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + LOCALASSERT(dynPtr); + + /* first of all, see how many marines are currently near: if there are too many, + destroy this one, and try to force a generator to make a replacement */ + if(sbPtr->I_SBtype==I_BehaviourMarine) + { + if(NumGeneratorNPCsVisible() >= MAX_VISIBLEGENERATORNPCS) + { + DestroyAnyStrategyBlock(sbPtr); + ForceAGenerator(); + } + } + + AlienDefaultMap.MapShape = sbPtr->shapeIndex; + tempModule.m_mapptr = &AlienDefaultMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 0; + tempModule.m_lightarray = (struct lightblock *)0; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr = NULL; + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) return; /* cannot allocate displayblock, so leave far */ + + sbPtr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbPtr; + dPtr->ObMyModule = NULL; + + /* need to initialise positional information in the new display block */ + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + + /* marine data block init */ + marineStatusPointer->weaponTarget.vx = marineStatusPointer->weaponTarget.vy = marineStatusPointer->weaponTarget.vz = 0; + + /* zero linear velocity in dynamics block */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* state and sequence initialisation */ + //dPtr->ShapeAnimControlBlock = &marineStatusPointer->ShpAnimCtrl; + + dPtr->HModelControlBlock=&marineStatusPointer->HModelController; + + /* Just in case. */ + CentreMarineElevation(sbPtr); + InitWaypointManager(&marineStatusPointer->waypointManager); + + ProveHModel(dPtr->HModelControlBlock,dPtr); + + if(MarineShouldBeCrawling(sbPtr)) marineStatusPointer->IAmCrouched = 1; + else marineStatusPointer->IAmCrouched = 0; + + if (marineStatusPointer->behaviourState==MBS_Firing) { + Marine_Enter_Firing_State(sbPtr); + /* To avoid negative volleys */ + } + + /*Copy extents from the collision extents in extents.c*/ + dPtr->ObMinX=-CollisionExtents[CE_MARINE].CollisionRadius; + dPtr->ObMaxX=CollisionExtents[CE_MARINE].CollisionRadius; + dPtr->ObMinZ=-CollisionExtents[CE_MARINE].CollisionRadius; + dPtr->ObMaxZ=CollisionExtents[CE_MARINE].CollisionRadius; + dPtr->ObMinY=CollisionExtents[CE_MARINE].CrouchingTop; + dPtr->ObMaxY=CollisionExtents[CE_MARINE].Bottom; + dPtr->ObRadius = 1000; + + marineStatusPointer->gotapoint=0; + + /* Once they become near, Wait_Then_Hunt marines become Wander marines. */ + + if (marineStatusPointer->Mission==MM_Wait_Then_Wander) { + marineStatusPointer->Mission=MM_Wander; + } + + /* And force pathfinders to get a new module? */ + if (marineStatusPointer->Mission==MM_Pathfinder) { + if (marineStatusPointer->behaviourState==MBS_Pathfinding) { + marineStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE; + } + } + + marineStatusPointer->lastframe_fallingspeed=-1; +} + +void MakeMarineFar(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + int i; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->SBdptr != NULL); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* get rid of the displayblock */ + i = DestroyActiveObject(sbPtr->SBdptr); + LOCALASSERT(i==0); + sbPtr->SBdptr = NULL; + + marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME; + + /* zero linear velocity in dynamics block */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* if we have a gun flash, get rid of it */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* stop sound, if we have one */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(marineStatusPointer->soundHandle); + if(marineStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) Sound_Stop(marineStatusPointer->soundHandle2); + + /* set the correct state(s) or remove, if we're dying */ + if(marineStatusPointer->behaviourState == MBS_Dying) + { + /* if we're dying, we can be removed at this point */ + DestroyAnyStrategyBlock(sbPtr); + return; + } + +} + +void KillMarine(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,SECTION_DATA *Section,VECTORCH *incoming) { + + int deathtype,gibbFactor; + int a; + STRATEGYBLOCK *candidate; + + MARINE_STATUS_BLOCK *marineStatusPointer; + SECTION_DATA *head; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Morale. */ + if (marineStatusPointer->My_Weapon->ARealMarine) { + /* Only marine deaths get 'spotted' everywhere, by the APC guy! */ + NpcSquad.Nextframe_Squad_Delta_Morale-=10000; + /* So, warn the squad? */ + ZoneAlert(3,sbPtr->containingModule->m_aimodule); + } + + Marine_MuteVoice(sbPtr); + + /*notify death target ,if marine has one*/ + if(marineStatusPointer->death_target_sbptr) + { + RequestState(marineStatusPointer->death_target_sbptr,marineStatusPointer->death_target_request, 0); + } + + /* get rid of the gun flash, if we've got it */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + /* stop sound, if we have one, and it's not the fire */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + if (ActiveSounds[marineStatusPointer->soundHandle].soundIndex!=SID_FIRE) { + Sound_Stop(marineStatusPointer->soundHandle); + } + } + + /* Set GibbFactor */ + gibbFactor=0; + { + int tkd; + + tkd=TotalKineticDamage(damage); + deathtype=0; + + if (damage->ExplosivePower==1) { + if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) { + /* Okay, you can gibb now. */ + marineStatusPointer->GibbFactor=ONE_FIXED>>1; + marineStatusPointer->mtracker_timer=-1; + deathtype=2; + } + } else if ((tkd>60)&&((multiple>>16)>1)) { + int newmult; + + newmult=DIV_FIXED(multiple,NormalFrameTime); + if (MUL_FIXED(tkd,newmult)>(500)) { + /* Loadsabullets! */ + marineStatusPointer->GibbFactor=-(ONE_FIXED>>2); + marineStatusPointer->mtracker_timer=-1; + deathtype=2; + } + } + + if ((damage->ExplosivePower==2)||(damage->ExplosivePower==6)) { + /* Basically SADARS only. */ + marineStatusPointer->GibbFactor=ONE_FIXED; + marineStatusPointer->mtracker_timer=-1; + deathtype=3; + } + } + gibbFactor=marineStatusPointer->GibbFactor; + + if (damage->ForceBoom) { + deathtype+=damage->ForceBoom; + } + + { + SECTION_DATA *chest; + + chest=GetThisSectionData(marineStatusPointer->HModelController.section_data,"chest"); + + if (chest==NULL) { + /* I'm impressed. */ + deathtype+=2; + } else if ((chest->flags§ion_data_notreal) + &&(chest->flags§ion_data_terminate_here)) { + /* That's gotta hurt. */ + deathtype++; + } + } + + /* make a sound... if you have a head. */ + head=GetThisSectionData(marineStatusPointer->HModelController.section_data,"head"); + + /* Is it still attached? */ + if (head) { + if (head->flags§ion_data_notreal) { + head=NULL; + } + } + + if (marineStatusPointer->GibbFactor) { + /* Probably want to make some sort of splatting noise... */ + } else if (head) { + if (marineStatusPointer->Expression!=3) { + /* Expression 3 just looks too peaceful. */ + if (marineStatusPointer->Mission==MM_RunAroundOnFire) { + /* More burning screams. */ + Marine_BurningDeathScream(sbPtr); + } else if ((damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire==0) + &&(damage->Electrical>0) + &&(damage->Acid==0) + ) { + Marine_ElectrocutionScream(sbPtr); + } else if ((Section)&&(damage->Id==AMMO_PRED_RIFLE)) { + /* Hit in the chest or pelvis by a speargun? */ + if( (strcmp(Section->sempai->Section_Name,"pelvis")==0) + ||(strcmp(Section->sempai->Section_Name,"pelvis presley")==0) + ||(strcmp(Section->sempai->Section_Name,"chest")==0) ){ + Marine_OoophSound(sbPtr); + } else { + Marine_DeathScream(sbPtr); + } + } else { + Marine_DeathScream(sbPtr); + } + } + } + + /* Now final stage. */ + { + DEATH_DATA *this_death; + HIT_FACING facing; + SECTION *root; + int burning,electrical; + + root=GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,marineStatusPointer->My_Weapon->TemplateName); + + facing.Front=0; + facing.Back=0; + facing.Left=0; + facing.Right=0; + + if (incoming) { + if (incoming->vz>0) { + facing.Back=1; + } else { + facing.Front=1; + } + if (incoming->vx>0) { + facing.Right=1; + } else { + facing.Left=1; + } + } + + if ((marineStatusPointer->Mission==MM_RunAroundOnFire) + &&(damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire>0) + &&(damage->Electrical==0) + &&(damage->Acid==0) + ) { + burning=1; + } else { + burning=0; + } + + if ((damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire==0) + &&(damage->Electrical>0) + &&(damage->Acid==0) + ) { + electrical=1; + } else { + electrical=0; + } + + this_death=GetMarineDeathSequence(&marineStatusPointer->HModelController,root,marineStatusPointer->Wounds,marineStatusPointer->Wounds, + deathtype,&facing,burning,marineStatusPointer->IAmCrouched,electrical); + + GLOBALASSERT(this_death); + + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"Elevation"); + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta"); + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun"); + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + + Convert_Marine_To_Corpse(sbPtr,this_death); + } + + /* See if anyone saw that? */ + for (a=0; aI_SBtype==I_BehaviourMarine) { + /* Are you already suspicious? */ + marineStatusPointer = (MARINE_STATUS_BLOCK *)(candidate->SBdataptr); + + /* Did you see that? */ + if (NPCCanSeeTarget(candidate,sbPtr,MARINE_NEAR_VIEW_WIDTH)) { + + if (marineStatusPointer->Android==0) { + if (gibbFactor) { + marineStatusPointer->Courage-=20000; + } else if (head==NULL) { + marineStatusPointer->Courage-=15000; + } else { + marineStatusPointer->Courage-=10000; + } + } + + if ((marineStatusPointer->suspicious==0)||(marineStatusPointer->using_squad_suspicion)) { + /* Okay, react. */ + marineStatusPointer->suspicious=MARINE_PARANOIA_TIME; + marineStatusPointer->suspect_point=sbPtr->DynPtr->Position; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + } + } + } + } +} + +void MarineIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,SECTION_DATA *Section,VECTORCH *incoming) +{ + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* if we're dying, do nothing */ + if(marineStatusPointer->behaviourState==MBS_Dying) + { + /* MFS should be dying, too */ + return; + } + + if(!(sbPtr->SBdptr)) + { + DestroyAnyStrategyBlock(sbPtr); + return; + } + + marineStatusPointer->Wounds|=wounds; + + if (sbPtr->SBDamageBlock.Health > 0) { + + if (marineStatusPointer->Mission==MM_RunAroundOnFire) { + Marine_BurningScream(sbPtr); + } else if ((damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire==0) + &&(damage->Electrical==0) + &&(damage->Acid>0) + ) { + Marine_AcidScream(sbPtr); + if ((marineStatusPointer->behaviourState!=MBS_AcidAvoidance) + &&(marineStatusPointer->behaviourState!=MBS_Firing) + &&(marineStatusPointer->behaviourState!=MBS_Avoidance) + &&(marineStatusPointer->behaviourState!=MBS_Dying) + &&(marineStatusPointer->behaviourState!=MBS_PanicFire) + &&(marineStatusPointer->behaviourState!=MBS_Reloading) + &&(marineStatusPointer->behaviourState!=MBS_PumpAction) + &&(marineStatusPointer->behaviourState!=MBS_GetWeapon) + &&(marineStatusPointer->behaviourState!=MBS_PanicReloading)) + { + Marine_Activate_AcidAvoidance_State(sbPtr,incoming); + } + } else { + Marine_WoundedScream(sbPtr); + } + /* Open the mouth? */ + Marine_AssumePanicExpression(sbPtr); + } + + /* Might want to get a new target? */ + + marineStatusPointer->Target=NULL; + + if (marineStatusPointer->Android) { + /* Kill non-functional androids. */ + if ((marineStatusPointer->Wounds§ion_flag_left_hand) + &&(marineStatusPointer->Wounds§ion_flag_right_hand)) { + sbPtr->SBDamageBlock.Health=0; + } + } + + /* reduce marine health */ + if(sbPtr->SBDamageBlock.Health <= 0) { + /* marine experiences death */ + int dice=FastRandom()&65535; + #if 0 + if ((dice<16384)||(marineStatusPointer->Android)) { + #else + if (marineStatusPointer->Android) { + #endif + Marine_SwitchExpression(sbPtr,3); + } else if (dice<32768) { + Marine_SwitchExpression(sbPtr,5); + } else { + Marine_SwitchExpression(sbPtr,4); + } + if (AvP.PlayerType!=I_Marine) { + CurrentGameStats_CreatureKilled(sbPtr,Section); + } + KillMarine(sbPtr,damage,multiple,wounds,Section,incoming); + } else { + /* If not dead, play a hit delta. */ + DELTA_CONTROLLER *hitdelta; + int frontback; + + hitdelta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta"); + + if (incoming) { + if (incoming->vz>=0) { + frontback=0; + } else { + frontback=1; + } + } else { + /* Default to front. */ + frontback=1; + } + + if (hitdelta) { + /* A hierarchy with hit deltas! */ + int CrouchSubSequence; + int StandSubSequence; + + if (Section==NULL) { + if (frontback==0) { + CrouchSubSequence=MCrSS_HitChestBack; + StandSubSequence=MSSS_HitChestBack; + } else { + CrouchSubSequence=MCrSS_HitChestFront; + StandSubSequence=MSSS_HitChestFront; + } + } else if (Section->sempai->flags§ion_flag_head) { + if (frontback==0) { + CrouchSubSequence=MCrSS_HitHeadBack; + StandSubSequence=MSSS_HitHeadBack; + } else { + CrouchSubSequence=MCrSS_HitHeadFront; + StandSubSequence=MSSS_HitHeadFront; + } + } else if ((Section->sempai->flags§ion_flag_left_arm) + ||(Section->sempai->flags§ion_flag_left_hand)) { + if (frontback==0) { + CrouchSubSequence=MCrSS_HitRightArm; + StandSubSequence=MSSS_HitRightArm; + } else { + CrouchSubSequence=MCrSS_HitLeftArm; + StandSubSequence=MSSS_HitLeftArm; + } + } else if ((Section->sempai->flags§ion_flag_right_arm) + ||(Section->sempai->flags§ion_flag_right_hand)) { + if (frontback==0) { + CrouchSubSequence=MCrSS_HitLeftArm; + StandSubSequence=MSSS_HitLeftArm; + } else { + CrouchSubSequence=MCrSS_HitRightArm; + StandSubSequence=MSSS_HitRightArm; + } + } else if ((Section->sempai->flags§ion_flag_left_leg) + ||(Section->sempai->flags§ion_flag_left_foot)) { + if (frontback==0) { + CrouchSubSequence=MCrSS_HitRightLeg; + StandSubSequence=MSSS_HitRightLeg; + } else { + CrouchSubSequence=MCrSS_HitLeftLeg; + StandSubSequence=MSSS_HitLeftLeg; + } + } else if ((Section->sempai->flags§ion_flag_right_leg) + ||(Section->sempai->flags§ion_flag_right_foot)) { + if (frontback==0) { + CrouchSubSequence=MCrSS_HitLeftLeg; + StandSubSequence=MSSS_HitLeftLeg; + } else { + CrouchSubSequence=MCrSS_HitRightLeg; + StandSubSequence=MSSS_HitRightLeg; + } + } else { + /* Chest or misc. hit. */ + if (frontback==0) { + CrouchSubSequence=MCrSS_HitChestBack; + StandSubSequence=MSSS_HitChestBack; + } else { + CrouchSubSequence=MCrSS_HitChestFront; + StandSubSequence=MSSS_HitChestFront; + } + } + + + if(marineStatusPointer->IAmCrouched) { + if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineCrouch,CrouchSubSequence)) { + Start_Delta_Sequence(hitdelta,(int)HMSQT_MarineCrouch,CrouchSubSequence,-1); /* Was (ONE_FIXED>>2) */ + } + } else { + if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,StandSubSequence)) { + Start_Delta_Sequence(hitdelta,(int)HMSQT_MarineStand,StandSubSequence,-1); /* Was (ONE_FIXED>>2) */ + } + } + hitdelta->Playing=1; + /* Not looped. */ + + } + + /* Finally, warn the squad. */ + ZoneAlert(3,sbPtr->containingModule->m_aimodule); + /* And become suspicious. */ + marineStatusPointer->suspicious=MARINE_PARANOIA_TIME; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + if (incoming) { + marineStatusPointer->suspect_point=*incoming; + /* Flip it round! */ + marineStatusPointer->suspect_point.vx=-marineStatusPointer->suspect_point.vx; + marineStatusPointer->suspect_point.vy=-marineStatusPointer->suspect_point.vy; + marineStatusPointer->suspect_point.vz=-marineStatusPointer->suspect_point.vz; + Normalise(&marineStatusPointer->suspect_point); + marineStatusPointer->suspect_point.vx>>=5; + marineStatusPointer->suspect_point.vy>>=5; + marineStatusPointer->suspect_point.vz>>=5; + } else { + marineStatusPointer->suspect_point.vx=0; + marineStatusPointer->suspect_point.vy=0; + marineStatusPointer->suspect_point.vz=-2000; + } + RotateVector(&marineStatusPointer->suspect_point,&sbPtr->DynPtr->OrientMat); + + marineStatusPointer->suspect_point.vx+=sbPtr->DynPtr->Position.vx; + marineStatusPointer->suspect_point.vy+=sbPtr->DynPtr->Position.vy; + marineStatusPointer->suspect_point.vz+=sbPtr->DynPtr->Position.vz; + + /* Switch wounded androids into an appropriate state. */ + if (marineStatusPointer->Android) { + if (marineStatusPointer->Wounds§ion_flag_left_hand) { + if (marineStatusPointer->My_Weapon->id!=MNPCW_AndroidSpecial) { + Marine_Enter_OneArmShotgun_State(sbPtr); + } + } else if (marineStatusPointer->Wounds§ion_flag_right_hand) { + if (marineStatusPointer->My_Weapon->id!=MNPCW_Android_Pistol_Special) { + Marine_Enter_OneArmPistol_State(sbPtr); + } + } + + } + + } + +} + + + +/*------------------------Patrick 24/2/97----------------------------- + Marine far state behaviour functions + --------------------------------------------------------------------*/ + +static STATE_RETURN_CONDITION Execute_MFS_Firing(STRATEGYBLOCK *sbPtr) +{ + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* I can't deal with this right now. Better wait instead. */ + + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + return(SRC_Request_Wait); + +} + +static STATE_RETURN_CONDITION Execute_MFS_Avoidance(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* High on the list of Things Not To Be Doing. */ + + #if ALL_NEW_AVOIDANCE + Initialise_AvoidanceManager(sbPtr,&marineStatusPointer->avoidanceManager); + #endif + + switch (marineStatusPointer->lastState) { + case MBS_Retreating: + return(SRC_Request_Retreat); + break; + case MBS_Returning: + return(SRC_Request_Return); + break; + case MBS_Responding: + return(SRC_Request_Respond); + break; + case MBS_Approaching: + /* Go directly to approach. Do not pass GO. Do not collect 200 zorkmids. */ + return(SRC_Request_Approach); + break; + default: + return(SRC_Request_Wander); + break; + } + /* Still here? */ + return(SRC_Request_Wander); + +} + +static STATE_RETURN_CONDITION Execute_MFS_Wait(STRATEGYBLOCK *sbPtr) +{ + + MARINE_STATUS_BLOCK *marineStatusPointer; + AIMODULE *targetModule=0; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->suspicious) { + int correctlyOrientated; + VECTORCH orientationDirn; + + orientationDirn.vx = marineStatusPointer->suspect_point.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->suspect_point.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + marineStatusPointer->gotapoint=0; + } + + /* Might want to spin on the spot. */ + if (marineStatusPointer->gotapoint==1) { + + VECTORCH orientationDirn; + int correctlyOrientated; + + orientationDirn.vx = marineStatusPointer->wanderData.worldPosition.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->wanderData.worldPosition.vz - sbPtr->DynPtr->Position.vz; + + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,ONE_FIXED,NULL); + + if (correctlyOrientated) { + marineStatusPointer->gotapoint=2; + /* Done. */ + } + + } else if (marineStatusPointer->gotapoint==0) { + GetPointToFaceMarineTowards(sbPtr,&marineStatusPointer->wanderData.worldPosition); + } + + + /* See if you're allowed to respond. */ + + if ( + (marineStatusPointer->Mission==MM_Wait_Then_Wander) + ||(marineStatusPointer->Mission==MM_Guard) + ) { + return(SRC_No_Change); + } + + /* Possible response? LocalGuarders are allowed to wander. */ + + if ((NpcSquad.alertZone)&&(marineStatusPointer->Mission!=MM_LocalGuard) + &&(marineStatusPointer->Mission!=MM_NonCom)) { + if (sbPtr->containingModule->m_aimodule!=NpcSquad.alertZone) { + if (NpcSquad.responseLevel>0) { + /* Picked up a target. Can we move to respond? */ + targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr); + if (targetModule) { + NpcSquad.responseLevel--; + return(SRC_Request_Respond); + } + } + } + } + + /* Decrement the Far state timer */ + marineStatusPointer->stateTimer -= NormalFrameTime; + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(marineStatusPointer->stateTimer > 0) return(SRC_No_Change); + + /* Might want to wander. */ + + if ((FastRandom()&65535)<2048) + { + /* we should be wandering... we're bored of waiting. */ + return(SRC_Request_Wander); + } + + /* reset timer */ + marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME; + return(SRC_No_Change); + +} + +static STATE_RETURN_CONDITION Execute_MFS_SentryMode(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + AIMODULE *targetModule = 0; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Okay, so you're a Sentry who's been pushed off his spot. */ + + if ((sbPtr->containingModule->m_aimodule==marineStatusPointer->missionmodule) + ||(marineStatusPointer->missionmodule==NULL)) { + + if (marineStatusPointer->missionmodule!=NULL) { + int dist; + VECTORCH offset; + /* Relocate? */ + + offset.vx=sbPtr->DynPtr->Position.vx-marineStatusPointer->my_spot.vx; + offset.vy=sbPtr->DynPtr->Position.vy-marineStatusPointer->my_spot.vy; + offset.vz=sbPtr->DynPtr->Position.vz-marineStatusPointer->my_spot.vz; + /* Fix for midair start points, grrrr. */ + offset.vy>>=2; + + dist=Approximate3dMagnitude(&offset); + + if (dist>SENTRY_SENSITIVITY) { + sbPtr->DynPtr->Position=marineStatusPointer->my_spot; + sbPtr->containingModule = (ModuleFromPosition(&(sbPtr->DynPtr->Position), sbPtr->containingModule)); + + } + } + + if (marineStatusPointer->suspicious) { + int correctlyOrientated; + VECTORCH orientationDirn; + + orientationDirn.vx = marineStatusPointer->suspect_point.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->suspect_point.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + marineStatusPointer->gotapoint=0; + } + + /* Might want to spin on the spot. */ + if (marineStatusPointer->gotapoint==1) { + + VECTORCH orientationDirn; + int correctlyOrientated; + + orientationDirn.vx = marineStatusPointer->wanderData.worldPosition.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->wanderData.worldPosition.vz - sbPtr->DynPtr->Position.vz; + + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,ONE_FIXED,NULL); + + if (correctlyOrientated) { + marineStatusPointer->gotapoint=2; + /* Done. */ + } + + } else if (marineStatusPointer->gotapoint==0) { + GetPointToFaceMarineTowards(sbPtr,&marineStatusPointer->wanderData.worldPosition); + } + + } else { + + /* Decrement the Far state timer */ + marineStatusPointer->stateTimer -= NormalFrameTime; + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(marineStatusPointer->stateTimer > 0) return(SRC_No_Change); + + /* Never engage, and ignore alerts. */ + + if (sbPtr->containingModule->m_aimodule==marineStatusPointer->missionmodule) { + /* Same state next frame. */ + return(SRC_No_Change); + } + + /* get the target module... */ + + targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,marineStatusPointer->missionmodule,7,0); + + /* If there is no target module, we're way out there. Better wander a bit more. */ + if(!targetModule) + { + targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr,marineStatusPointer->lastmodule,0); + } + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + ProcessFarMarineTargetModule(sbPtr, targetModule); + /* reset timer */ + marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME; + } + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MFS_Hunt(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + AIMODULE *targetModule = 0; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Decrement the Far state timer */ + marineStatusPointer->stateTimer -= NormalFrameTime; + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(marineStatusPointer->stateTimer > 0) return(SRC_No_Change); + + /* check for state changes */ + + if ((!MarineIsAwareOfTarget(sbPtr)) + ||(marineStatusPointer->Target!=Player->ObStrategyBlock)) + { + /* we should be wandering... can't hunt other NPCs */ + return(SRC_Request_Wander); + } + + /* get the target module... */ + targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr,0); + + /* if there is no target module, it means that the pred is trapped in an + unlinked module. In this case, reset the timer and return. */ + if(!targetModule) + { + marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME; + return(SRC_Request_Wait); + } + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + ProcessFarMarineTargetModule(sbPtr, targetModule); + /* reset timer */ + marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME; + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MFS_Approach(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + AIMODULE *targetModule = 0; + MODULE *tcm; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (!MarineIsAwareOfTarget(sbPtr)) + { + /* we should be wandering... can't hunt other NPCs */ + return(SRC_Request_Wander); + } + + /* See if we can fire? */ + + if (marineStatusPointer->Target) { + if (marineStatusPointer->Target->containingModule) { + if (IsModuleVisibleFromModule(marineStatusPointer->Target->containingModule,sbPtr->containingModule)) { + /* Take the shot? */ + return(SRC_Request_Fire); + } + } + } + + /* Can't fire. We want to get closer, then. */ + + if (marineStatusPointer->Target->containingModule) { + tcm=marineStatusPointer->Target->containingModule; + } else { + tcm=ModuleFromPosition(&marineStatusPointer->Target->DynPtr->Position,sbPtr->containingModule); + } + + if (tcm) { + targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,tcm->m_aimodule,7,0); + } + + if (targetModule) { + /* We have somewhere to go. */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + ProcessFarMarineTargetModule(sbPtr, targetModule); + /* reset timer */ + marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME; + marineStatusPointer->destinationmodule=targetModule; + return(SRC_No_Change); + } + + /* Can't do nothin. Better wait, then. Everything else will see to itself. */ + if (marineStatusPointer->Mission==MM_Pathfinder) { + return(SRC_Request_Return); + } else { + return(SRC_Request_Wait); + } +} + + +static STATE_RETURN_CONDITION Execute_MFS_Respond(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + AIMODULE *targetModule = 0; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Decrement the Far state timer */ + marineStatusPointer->stateTimer -= NormalFrameTime; + + if (ShowSquadState) { + if (marineStatusPointer->destinationmodule==NULL) { + PrintDebuggingText("Target module is NULL\n"); + } else { + PrintDebuggingText("Target module is %s\n",(*(marineStatusPointer->destinationmodule->m_module_ptrs))->name); + } + } + + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(marineStatusPointer->stateTimer > 0) { + return(SRC_No_Change); + } + + /* check for state changes */ + + if (MarineIsAwareOfTarget(sbPtr)) { + /* Picked up a target. */ + return(SRC_Request_Approach); + } + + /* get the target module... */ + targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr); + + if (targetModule==sbPtr->containingModule->m_aimodule) { + /* We've arrived. */ + DeprioritiseAlert(sbPtr->containingModule->m_aimodule); + /* Hey, if it's real, there'll be a new one soon enough. */ + return(SRC_Request_Wait); + } + + /* if there is no target module, it means that the pred is trapped in an + unlinked module. In this case, reset the timer and return. */ + if(!targetModule) + { + /* We can't do it. */ + return(SRC_Request_Wait); + } + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + ProcessFarMarineTargetModule(sbPtr, targetModule); + /* reset timer */ + marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME; + marineStatusPointer->destinationmodule=targetModule; + return(SRC_No_Change); + +} + +static STATE_RETURN_CONDITION Execute_MFS_Wander(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + AIMODULE *targetModule = 0; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Decrement the Far state timer */ + marineStatusPointer->stateTimer -= NormalFrameTime; + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(marineStatusPointer->stateTimer > 0) { + return(SRC_No_Change); + } + + /* check for state changes */ + if(MarineIsAwareOfTarget(sbPtr)) + /* Hack! */ + { + /* we should be hunting */ + return(SRC_Request_Approach); + } + + /* New alert? */ + if ((NpcSquad.alertZone)&&(marineStatusPointer->Mission!=MM_LocalGuard) + &&(marineStatusPointer->Mission!=MM_NonCom)) { + if (sbPtr->containingModule->m_aimodule!=NpcSquad.alertZone) { + if (NpcSquad.responseLevel>0) { + /* Picked up a target. Can we move to respond? */ + targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr); + if (targetModule) { + NpcSquad.responseLevel--; + return(SRC_Request_Respond); + } + } + } + } + + /* Bored of wandering? How about we wait a while? */ + if ((FastRandom()&65535)<2048) + { + /* we should be wandering... we're bored of waiting. */ + return(SRC_Request_Wait); + } + + /* get the target module... */ + targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr,marineStatusPointer->lastmodule,0); + + /* if there is no target module, it means that the pred is trapped in an + unlinked module. In this case, reset the timer and return. */ + if(!targetModule) + { + marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME; + return(SRC_No_Change); + } + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + ProcessFarMarineTargetModule(sbPtr, targetModule); + /* reset timer */ + marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME; + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MFS_Return(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + AIMODULE *targetModule = 0; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Okay, so you're a LocalGuard or Pathfinder who's gotten lost. */ + + /* Decrement the Far state timer */ + marineStatusPointer->stateTimer -= NormalFrameTime; + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(marineStatusPointer->stateTimer > 0) return(SRC_No_Change); + + /* check for state changes */ + if(MarineIsAwareOfTarget(sbPtr)) + /* Hack! */ + { + /* we should be engaging */ + return(SRC_Request_Approach); + } + + /* Ignore alerts? */ + #if 0 + if ((NpcSquad.alertZone)&&(marineStatusPointer->Mission!=MM_LocalGuard) + &&(marineStatusPointer->Mission!=MM_NonCom)) { + if (sbPtr->containingModule->m_aimodule!=NpcSquad.alertZone) { + if (NpcSquad.responseLevel>0) { + /* Picked up a target. Can we move to respond? */ + targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr); + if (targetModule) { + NpcSquad.responseLevel--; + return(SRC_Request_Respond); + } + } + } + } + #endif + + /* Never break out of return unless your life is in danger! */ + + /* Or unless we're back. */ + + if (sbPtr->containingModule->m_aimodule==marineStatusPointer->missionmodule) { + return(SRC_Request_Wait); + } + + /* get the target module... */ + + targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,marineStatusPointer->missionmodule,7,0); + + /* If there is no target module, we're way out there. Better wander a bit more. */ + if(!targetModule) + { + targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr,marineStatusPointer->lastmodule,0); + } + /* Examine target, and decide what to do */ + if (AIModuleIsPhysical(targetModule)==0) { + #if 0 + /* No longer a straight assert: not it's breakpointable. */ + GLOBALASSERT(0); + #else + /* We're probably fubared. Change to Wander. */ + if (marineStatusPointer->Mission!=MM_NonCom) { + /* Dunno what a NonCom is doing here, but Code Defensively! */ + marineStatusPointer->Mission=MM_Wander; + } + return(SRC_Request_Wait); + #endif + } + ProcessFarMarineTargetModule(sbPtr, targetModule); + /* reset timer */ + marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME; + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MFS_Pathfinder(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + AIMODULE *targetModule = 0; + int nextModuleIndex; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Okay, so you're a LocalGuard or Pathfinder who's gotten lost. */ + + /* Decrement the Far state timer */ + marineStatusPointer->stateTimer -= NormalFrameTime; + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(marineStatusPointer->stateTimer > 0) return(SRC_No_Change); + + /* check for state changes */ + if(MarineIsAwareOfTarget(sbPtr)) + /* Hack! */ + { + /* we should be engaging */ + return(SRC_Request_Approach); + } + + /* Ignore alerts. */ + + /* Never break out of pathfinder unless your life is in danger! */ + + /* Okay, so where are we exactly? */ + + if ((marineStatusPointer->stepnumber<0)||(marineStatusPointer->path<0)) { + /* Get OUT! */ + return(SRC_Request_Wander); + } + + targetModule = TranslatePathIndex(marineStatusPointer->stepnumber,marineStatusPointer->path); + + if (targetModule==NULL) { + /* Oh, to heck with this. Try to wander. */ + return(SRC_Request_Wander); + } + + /* Right, so there is a somewhere to get to. */ + + if (targetModule!=sbPtr->containingModule->m_aimodule) { + /* But we're nowhere near it. Geeze... */ + marineStatusPointer->missionmodule=targetModule; + return(SRC_Request_Return); + } + + /* Okay, so now we need to know where to go now. */ + + nextModuleIndex=GetNextModuleInPath(marineStatusPointer->stepnumber,marineStatusPointer->path); + GLOBALASSERT(nextModuleIndex>=0); + /* If that fires, it's Richard's fault. */ + targetModule=TranslatePathIndex(nextModuleIndex,marineStatusPointer->path); + GLOBALASSERT(targetModule); + /* Ditto. */ + marineStatusPointer->stepnumber=nextModuleIndex; + + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + ProcessFarMarineTargetModule(sbPtr, targetModule); + /* reset timer */ + marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME; + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MFS_Retreat(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + AIMODULE *targetModule = 0; + AIMODULE *old_fearmod; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Decrement the Far state timer */ + marineStatusPointer->stateTimer -= (NormalFrameTime<<1); + /* Double speed, remember? */ + + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(marineStatusPointer->stateTimer > 0) { + return(SRC_No_Change); + } + + old_fearmod=marineStatusPointer->fearmodule; + + /* From where am I running? */ + if(MarineIsAwareOfTarget(sbPtr)) { + marineStatusPointer->fearmodule=marineStatusPointer->Target->containingModule->m_aimodule; + } else if (marineStatusPointer->fearmodule==NULL) { + marineStatusPointer->fearmodule=sbPtr->containingModule->m_aimodule; + } + + if (marineStatusPointer->fearmodule!=old_fearmod) { + marineStatusPointer->destinationmodule = General_GetAIModuleForRetreat(sbPtr,marineStatusPointer->fearmodule,5); + } + + targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,marineStatusPointer->destinationmodule,6,0); + + if(!targetModule) + { + /* We can't do it. */ + return(SRC_Request_Wait); + } + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + ProcessFarMarineTargetModule(sbPtr, targetModule); + /* reset timer */ + marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME; + marineStatusPointer->destinationmodule=targetModule; + return(SRC_No_Change); + +} + +static void ProcessFarMarineTargetModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule) +{ + NPC_TARGETMODULESTATUS targetStatus; + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(targetModule); + LOCALASSERT(sbPtr->I_SBtype == I_BehaviourMarine); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + targetStatus = GetTargetAIModuleStatus(sbPtr, targetModule,0); + switch(targetStatus) + { + case(NPCTM_NoEntryPoint): + { + /* do nothing */ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_NormalRoom): + { + /* locate to target */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_AirDuct): + { + /* loacate to target */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_LiftTeleport): + { + /* do nothing */ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_ProxDoorOpen): + { + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_ProxDoorNotOpen): + { + MODULE *renderModule; + renderModule=*(targetModule->m_module_ptrs); + /* trigger the door, and set timer to quick so we can catch the door when it's open */ + ((PROXDOOR_BEHAV_BLOCK *)renderModule->m_sbptr->SBdataptr)->marineTrigger = 1; + break; + } + case(NPCTM_LiftDoorOpen): + { + ///* do nothing - can't use lifts */ + //FarNpc_FlipAround(sbPtr); + /* What the hell!!! */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_LiftDoorNotOpen): + { + /* do nothing - can't open lift doors */ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_SecurityDoorOpen): + { + /* locate to target, and move thro' quick as we can't retrigger */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_SecurityDoorNotOpen): + { + MODULE *renderModule; + renderModule=*(targetModule->m_module_ptrs); + /* do some door opening stuff here. Door should stay open for long enough + for us to catch it open next time */ + RequestState((renderModule->m_sbptr),1,0); + break; + } + default: + { + LOCALASSERT(1==0); + } + } +} + + +/*------------------------Patrick 24/2/97----------------------------- + Marine near state behaviour functions + --------------------------------------------------------------------*/ + +void Marine_Enter_SentryMode_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->gotapoint=0; + + marineStatusPointer->volleySize = 0; + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_Sentry; + marineStatusPointer->stateTimer = ONE_FIXED; /* Ignored anyway... */ + + Marine_QueueNeutralExpression(sbPtr); + + #if 0 + if(marineStatusPointer->IAmCrouched) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrouch,MCSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + if (marineStatusPointer->suspicious) { + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_Wait_Alert)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Wait_Alert,(ONE_FIXED<<2),(ONE_FIXED>>3)); + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } + #else + HandleWaitingAnimations(sbPtr); + #endif + + GetPointToFaceMarineTowards(sbPtr,&marineStatusPointer->wanderData.worldPosition); + +} + +void Marine_Enter_Wait_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->gotapoint=0; + + marineStatusPointer->internalState=0; + marineStatusPointer->volleySize = 0; + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_Waiting; + marineStatusPointer->stateTimer = MARINE_NEARWAITTIME; + + Marine_QueueNeutralExpression(sbPtr); + + #if 0 + if(marineStatusPointer->IAmCrouched) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrouch,MCSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Stand_To_Fidget)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Stand_To_Fidget,((ONE_FIXED*3)/2),(ONE_FIXED>>3)); + marineStatusPointer->HModelController.LoopAfterTweening=0; + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } + #else + HandleWaitingAnimations(sbPtr); + #endif + + GetPointToFaceMarineTowards(sbPtr,&marineStatusPointer->wanderData.worldPosition); + +} + +void Marine_Enter_Firing_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + int range; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->gotapoint=0; + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_Firing; + marineStatusPointer->volleySize = 0; + + if (marineStatusPointer->My_Weapon->id!=MNPCW_MPistol) { + marineStatusPointer->lastroundhit=0; + } + if ((marineStatusPointer->My_Weapon->id==MNPCW_Flamethrower)|| + (marineStatusPointer->My_Weapon->id==MNPCW_MFlamer)) { + marineStatusPointer->weapon_variable=0; + } + + marineStatusPointer->lasthitsection=NULL; + marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime; + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + + { + DELTA_CONTROLLER *delta; + /* There should be NO head turn delta. */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + } + } + + /* Arbitrarily decide to crouch? */ + if (marineStatusPointer->Android) { + marineStatusPointer->IAmCrouched=0; + } else { + int prob; + + prob=20000; + + if (range<6000) { + prob+=10000; + } + + if ((marineStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy)>3000) { + prob+=20000; + } + + if ((FastRandom()&65535)IAmCrouched=1; + } + } + + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_FireFromHips)) { + int target; + + target=(marineStatusPointer->Courage>>1); + if (marineStatusPointer->Mission==MM_Guard) { + target+=32767; + } + + if ((FastRandom()&((ONE_FIXED<<1)-1))>target) { + marineStatusPointer->FiringAnim=1; + } else { + marineStatusPointer->FiringAnim=0; + } + } else { + marineStatusPointer->FiringAnim=0; + } + + if(marineStatusPointer->IAmCrouched) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrouch,MCrSS_Attack_Primary,-1,(ONE_FIXED>>3)); + } else { + if (marineStatusPointer->FiringAnim==1) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_FireFromHips,-1,(ONE_FIXED>>3)); + } else { + if (marineStatusPointer->My_Weapon->id!=MNPCW_TwoPistols) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Attack_Primary,-1,(ONE_FIXED>>3)); + } else { + /* Two Pistols uses Stand Standard. */ + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Standard,-1,(ONE_FIXED>>3)); + } + } + } + + if (marineStatusPointer->My_Weapon->id==MNPCW_PulseRifle) { + if ((marineStatusPointer->FiringAnim==0)&&(marineStatusPointer->IAmCrouched==0)) { + /* Wink 2. */ + Marine_QueueWink2Expression(sbPtr); + } else { + Marine_QueueGrimaceExpression(sbPtr); + } + } else { + Marine_QueueGrimaceExpression(sbPtr); + } + + /* This next for firing only! */ + marineStatusPointer->HModelController.StopAfterTweening=1; + + if (marineStatusPointer->My_Weapon->id==MNPCW_GrenadeLauncher) { + /* Why do we need internalState 1 here again? */ + marineStatusPointer->internalState=1; + marineStatusPointer->HModelController.Looped=0; + marineStatusPointer->HModelController.LoopAfterTweening=0; + + /* Put loft in now? */ + { + int range; + range=VectorDistance((&marineStatusPointer->weaponTarget),(&sbPtr->DynPtr->Position)); + + marineStatusPointer->weaponTarget.vy-=(range/8); + } + } + + if ((marineStatusPointer->My_Weapon->id==MNPCW_MShotgun) + ||(marineStatusPointer->My_Weapon->id==MNPCW_Android) + ||(marineStatusPointer->My_Weapon->id==MNPCW_AndroidSpecial)) { + marineStatusPointer->internalState=1; + marineStatusPointer->HModelController.Looped=0; + marineStatusPointer->HModelController.LoopAfterTweening=0; + } + +} + +void Marine_Enter_Avoidance_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Make sure obstruction is set! */ + + marineStatusPointer->gotapoint=0; + + NPC_InitMovementData(&(marineStatusPointer->moveData)); + InitWaypointManager(&marineStatusPointer->waypointManager); + NPCGetAvoidanceDirection(sbPtr, &(marineStatusPointer->moveData.avoidanceDirn),&marineStatusPointer->obstruction); + marineStatusPointer->volleySize = 0; + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_Avoidance; + marineStatusPointer->stateTimer = NPC_AVOIDTIME; + + #if 0 + if(marineStatusPointer->IAmCrouched) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + #else + HandleMovingAnimations(sbPtr); + #endif + + /* Don't interfere with expression... */ + +} + +void Marine_Enter_Wander_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->gotapoint=0; + + NPC_InitMovementData(&(marineStatusPointer->moveData)); + NPC_InitWanderData(&(marineStatusPointer->wanderData)); + InitWaypointManager(&marineStatusPointer->waypointManager); + marineStatusPointer->volleySize = 0; + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_Wandering; + marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING; + + Marine_QueueNeutralExpression(sbPtr); + + #if 0 + if(marineStatusPointer->IAmCrouched) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineRun,MRSS_Mooch_Bored)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Mooch_Bored,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } + #else + HandleMovingAnimations(sbPtr); + #endif + +} + +void Marine_Enter_Approach_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->gotapoint=0; + + marineStatusPointer->volleySize = 0; + NPC_InitMovementData(&(marineStatusPointer->moveData)); + InitWaypointManager(&marineStatusPointer->waypointManager); + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_Approaching; + + marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING; + + /* Neutral??? */ + Marine_QueueNeutralExpression(sbPtr); + + #if 0 + if(marineStatusPointer->IAmCrouched) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + if (marineStatusPointer->Target==NULL) { + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineRun,MRSS_Mooch_Alert)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Mooch_Alert,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } + #else + HandleMovingAnimations(sbPtr); + #endif + + marineStatusPointer->destinationmodule=NULL; + +} + +void Marine_Enter_Hunt_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->gotapoint=0; + + marineStatusPointer->volleySize = 0; + NPC_InitMovementData(&(marineStatusPointer->moveData)); + InitWaypointManager(&marineStatusPointer->waypointManager); + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_Wandering; /* CHANGE ME!!! */ + + marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING; + + /* This really shouldn't be called, should it? */ + Marine_QueueNeutralExpression(sbPtr); + + if(marineStatusPointer->IAmCrouched) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + +} + +void Marine_Enter_Respond_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->gotapoint=0; + + marineStatusPointer->volleySize = 0; + NPC_InitMovementData(&(marineStatusPointer->moveData)); + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_Responding; + + if (NpcSquad.responseLevel) { + NpcSquad.responseLevel--; + } + + marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING; + + /* Determined! */ + Marine_QueueNeutralExpression(sbPtr); + + /* We must now be suspicious. */ + marineStatusPointer->suspicious=MARINE_PARANOIA_TIME; + marineStatusPointer->suspect_point=NpcSquad.squad_suspect_point; + /* That'll do as a default. */ + if (NpcSquad.alertZone) { + /* Gotta have a point. */ + marineStatusPointer->suspect_point=NpcSquad.alertZone->m_world; + } + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=1; + + #if 0 + if(marineStatusPointer->IAmCrouched) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + #else + HandleMovingAnimations(sbPtr); + #endif + +} + +void Marine_Enter_Return_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->gotapoint=0; + + marineStatusPointer->volleySize = 0; + NPC_InitMovementData(&(marineStatusPointer->moveData)); + InitWaypointManager(&marineStatusPointer->waypointManager); + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_Returning; + + marineStatusPointer->destinationmodule=NULL; + + marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING; + + Marine_QueueNeutralExpression(sbPtr); + + #if 0 + if(marineStatusPointer->IAmCrouched) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + #else + HandleMovingAnimations(sbPtr); + #endif + +} + +void Marine_Enter_Pathfinder_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->gotapoint=0; + + marineStatusPointer->volleySize = 0; + NPC_InitMovementData(&(marineStatusPointer->moveData)); + InitWaypointManager(&marineStatusPointer->waypointManager); + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_Pathfinding; + + marineStatusPointer->destinationmodule=NULL; + + marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING; + + Marine_QueueNeutralExpression(sbPtr); + + #if 0 + if(marineStatusPointer->IAmCrouched) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + #else + HandleMovingAnimations(sbPtr); + #endif + +} + +void Marine_Enter_Retreat_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->gotapoint=0; + + marineStatusPointer->volleySize = 0; + NPC_InitMovementData(&(marineStatusPointer->moveData)); + InitWaypointManager(&marineStatusPointer->waypointManager); + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_Retreating; + + marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING; + + marineStatusPointer->fearmodule=NULL; + /* It'll get set on state execution. */ + + if ((FastRandom()&65535)<32767) { + Marine_QueuePanicExpression(sbPtr); + Marine_PanicScream(sbPtr); + } else { + Marine_QueueGrimaceExpression(sbPtr); + } + + #if 0 + if(marineStatusPointer->IAmCrouched) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + #endif + /* Actually, sequence change is done in the function now. */ + +} + +void Marine_Enter_Taunt_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + { + DELTA_CONTROLLER *delta; + /* There should be NO head turn delta. */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + } + } + + if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Taunt_One)) { + + marineStatusPointer->gotapoint=0; + marineStatusPointer->internalState=0; + marineStatusPointer->volleySize = 0; + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_Taunting; + marineStatusPointer->stateTimer = MARINE_NEARWAITTIME; + + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Taunt_One,-1,(ONE_FIXED>>3)); + marineStatusPointer->HModelController.LoopAfterTweening=0; + } else { + /* Aw, forget it. */ + Marine_Enter_Wait_State(sbPtr); + return; + } + + if ((FastRandom()&65535)<32767) { + Marine_QueueWink1Expression(sbPtr); + } + + Marine_TauntShout(sbPtr); + +} + +void Marine_Enter_Reload_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + GLOBALASSERT(HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,marineStatusPointer->My_Weapon->Reload_Sequence)); + + marineStatusPointer->gotapoint=0; + marineStatusPointer->internalState=0; + marineStatusPointer->volleySize = 0; + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_Reloading; + marineStatusPointer->stateTimer = MARINE_NEARWAITTIME; + + { + DELTA_CONTROLLER *delta; + /* There should be NO head turn delta. */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + } + } + + /* Dunno if this is right. */ + Marine_QueueGrimaceExpression(sbPtr); + + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,marineStatusPointer->My_Weapon->Reload_Sequence,-1,(ONE_FIXED>>3)); + marineStatusPointer->HModelController.LoopAfterTweening=0; + +} + +void Marine_Enter_PanicReload_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + GLOBALASSERT(HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,marineStatusPointer->My_Weapon->Reload_Sequence)); + + marineStatusPointer->gotapoint=0; + marineStatusPointer->internalState=0; + marineStatusPointer->volleySize = 0; + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_PanicReloading; + marineStatusPointer->stateTimer = MARINE_NEARWAITTIME; + + { + DELTA_CONTROLLER *delta; + /* There should be NO head turn delta. */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + } + } + + if ((FastRandom()&65535)<32767) { + Marine_QueuePanicExpression(sbPtr); + if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) { + Marine_PanicScream(sbPtr); + } else { + Marine_AngryScream(sbPtr); + } + } else { + Marine_QueueGrimaceExpression(sbPtr); + } + + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,MSSS_Panic_Reload)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Panic_Reload,-1,(ONE_FIXED>>3)); + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,marineStatusPointer->My_Weapon->Reload_Sequence,-1,(ONE_FIXED>>3)); + } + marineStatusPointer->HModelController.LoopAfterTweening=0; + +} + +void Marine_Enter_PumpAction_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + GLOBALASSERT(HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,MSSS_PumpAction)); + + /* Maintain many things from fire. */ + marineStatusPointer->gotapoint=0; + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_PumpAction; + + { + DELTA_CONTROLLER *delta; + /* There should be NO head turn delta. */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + } + } + + /* Dunno if this is right. */ + Marine_QueueGrimaceExpression(sbPtr); + + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + if (marineStatusPointer->IAmCrouched) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrouch,MCrSS_PumpAction,-1,(ONE_FIXED>>5)); + marineStatusPointer->HModelController.LoopAfterTweening=0; + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_PumpAction,-1,(ONE_FIXED>>5)); + marineStatusPointer->HModelController.LoopAfterTweening=0; + } + +} + +void Marine_Enter_PanicFire_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->gotapoint=0; + + { + DELTA_CONTROLLER *delta; + /* There should be NO head turn delta. */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + } + } + + if (marineStatusPointer->My_Weapon->id==MNPCW_SADAR) { + #if 0 + if (marineStatusPointer->Target) { + Marine_Enter_Firing_State(sbPtr); + return; + } else { + Marine_Enter_Wait_State(sbPtr); + return; + } + #else + Marine_Enter_PullPistol_State(sbPtr); + return; + #endif + } else if (marineStatusPointer->My_Weapon->id==MNPCW_Skeeter) { + Marine_Enter_PullPistol_State(sbPtr); + return; + } else if (marineStatusPointer->My_Weapon->id==MNPCW_MMolotov) { + if (marineStatusPointer->Target) { + Marine_Enter_Firing_State(sbPtr); + return; + } else { + Marine_Enter_Wait_State(sbPtr); + return; + } + } + + marineStatusPointer->internalState=0; + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_PanicFire; + marineStatusPointer->volleySize = 0; + + if (marineStatusPointer->My_Weapon->id!=MNPCW_MPistol) { + marineStatusPointer->lastroundhit=0; + } + if ((marineStatusPointer->My_Weapon->id==MNPCW_Flamethrower)|| + (marineStatusPointer->My_Weapon->id==MNPCW_MFlamer)) { + marineStatusPointer->weapon_variable=0; + } + + marineStatusPointer->lasthitsection=NULL; + marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime; + if (marineStatusPointer->Target) { + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + } + + if ((FastRandom()&65535)<32767) { + Marine_QueuePanicExpression(sbPtr); + if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) { + Marine_PanicScream(sbPtr); + } else { + Marine_AngryScream(sbPtr); + } + } else { + Marine_QueueGrimaceExpression(sbPtr); + } + + if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_WildFire_0)) { + /* *can* enter wild fire... */ + #if 0 + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3)); + marineStatusPointer->HModelController.LoopAfterTweening=1; + #endif + /* Sequence will be set in the function. */ + } else { + /* Aw, forget it. */ + Marine_Enter_Retreat_State(sbPtr); + marineStatusPointer->suspicious=MARINE_PANIC_TIME; + } + +} + +void Marine_Enter_PullPistol_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + SECTION *root; + MARINE_WEAPON_DATA *pistol_data; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + GLOBALASSERT(marineStatusPointer->My_Weapon->ARealMarine); + + marineStatusPointer->gotapoint=0; + marineStatusPointer->internalState=0; + marineStatusPointer->volleySize = 0; + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_GetWeapon; + marineStatusPointer->stateTimer = MARINE_NEARWAITTIME; + + { + DELTA_CONTROLLER *delta; + /* There should be NO head turn delta... */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + } + /* ...and NO Minigun delta... */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun"); + } + /* ...and strip out HitDelta for now, too. */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta"); + } + } + + /* Now, try to be clever... */ + /* Turn into a pistol guy! */ + pistol_data=GetThisNPCMarineWeapon(MNPCW_PistolMarine); + GLOBALASSERT(pistol_data); + + root=GetNamedHierarchyFromLibrary(pistol_data->Riffname,pistol_data->HierarchyName); + GLOBALASSERT(root); + + marineStatusPointer->HModelController.Sequence_Type=HMSQT_MarineStand; + marineStatusPointer->HModelController.Sub_Sequence=MSSS_Get_Weapon; + /* That's to put the pistol in the right place... */ + Transmogrify_HModels(sbPtr,&marineStatusPointer->HModelController,root, 1, 1,0); + marineStatusPointer->My_Weapon=pistol_data; + marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->GunflashName); + marineStatusPointer->My_Elevation_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ElevationSection); + /* Start loaded! */ + marineStatusPointer->clipammo=marineStatusPointer->My_Weapon->clip_size; + + /* Dunno if this is right. */ + Marine_QueueGrimaceExpression(sbPtr); + + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Get_Weapon,-1,(ONE_FIXED>>3)); + marineStatusPointer->HModelController.LoopAfterTweening=0; + + /* Attempt to put the hitdelta back? */ + if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_HitChestFront)) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta",(int)HMSQT_MarineStand,(int)MSSS_HitChestFront,(ONE_FIXED>>2)); + GLOBALASSERT(delta); + delta->Playing=0; + } + + DeInitialise_HModel(&marineStatusPointer->HModelController); + ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr); + +} + +void Marine_Enter_OneArmShotgun_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + SECTION *root; + MARINE_WEAPON_DATA *pistol_data; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + GLOBALASSERT(marineStatusPointer->Android); + + marineStatusPointer->gotapoint=0; + marineStatusPointer->internalState=0; + marineStatusPointer->volleySize = 0; + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_Waiting; + marineStatusPointer->stateTimer = MARINE_NEARWAITTIME; + + { + DELTA_CONTROLLER *delta; + /* There should be NO head turn delta... */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + } + /* ...and NO Minigun delta... */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun"); + } + /* ...and strip out HitDelta for now, too. */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta"); + } + } + + /* Now, try to be clever... */ + /* Turn into an Android Special! */ + pistol_data=GetThisNPCMarineWeapon(MNPCW_AndroidSpecial); + GLOBALASSERT(pistol_data); + + root=GetNamedHierarchyFromLibrary(pistol_data->Riffname,pistol_data->HierarchyName); + GLOBALASSERT(root); + + marineStatusPointer->HModelController.Sequence_Type=HMSQT_MarineStand; + marineStatusPointer->HModelController.Sub_Sequence=MSSS_Standard; + /* That's to put the pistol in the right place... */ + Transmogrify_HModels(sbPtr,&marineStatusPointer->HModelController,root, 1, 1,0); + marineStatusPointer->My_Weapon=pistol_data; + marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->GunflashName); + marineStatusPointer->My_Elevation_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ElevationSection); + + /* Retain clipammo from the old shotgun. */ + + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Standard,-1,(ONE_FIXED>>3)); + marineStatusPointer->HModelController.LoopAfterTweening=0; + + /* Attempt to put the hitdelta back? */ + if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_HitChestFront)) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta",(int)HMSQT_MarineStand,(int)MSSS_HitChestFront,(ONE_FIXED>>2)); + GLOBALASSERT(delta); + delta->Playing=0; + } + + DeInitialise_HModel(&marineStatusPointer->HModelController); + ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr); + +} + +void Marine_Enter_OneArmPistol_State(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + SECTION *root; + MARINE_WEAPON_DATA *pistol_data; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + GLOBALASSERT(marineStatusPointer->Android); + + marineStatusPointer->gotapoint=0; + marineStatusPointer->internalState=0; + marineStatusPointer->volleySize = 0; + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_GetWeapon; + marineStatusPointer->stateTimer = MARINE_NEARWAITTIME; + + { + DELTA_CONTROLLER *delta; + /* There should be NO head turn delta... */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + } + /* ...and NO Minigun delta... */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun"); + } + /* ...and strip out HitDelta for now, too. */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta"); + } + } + + /* Now, try to be clever... */ + /* Turn into an Android Special! */ + pistol_data=GetThisNPCMarineWeapon(MNPCW_Android_Pistol_Special); + GLOBALASSERT(pistol_data); + + root=GetNamedHierarchyFromLibrary(pistol_data->Riffname,pistol_data->HierarchyName); + GLOBALASSERT(root); + + marineStatusPointer->HModelController.Sequence_Type=HMSQT_MarineStand; + marineStatusPointer->HModelController.Sub_Sequence=MSSS_Get_Weapon; + /* That's to put the pistol in the right place... */ + Transmogrify_HModels(sbPtr,&marineStatusPointer->HModelController,root, 1, 1,0); + marineStatusPointer->My_Weapon=pistol_data; + marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->GunflashName); + marineStatusPointer->My_Elevation_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ElevationSection); + /* Start loaded! */ + marineStatusPointer->clipammo=marineStatusPointer->My_Weapon->clip_size; + + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Get_Weapon,-1,(ONE_FIXED>>3)); + marineStatusPointer->HModelController.LoopAfterTweening=0; + + /* Attempt to put the hitdelta back? */ + if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_HitChestFront)) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta",(int)HMSQT_MarineStand,(int)MSSS_HitChestFront,(ONE_FIXED>>2)); + GLOBALASSERT(delta); + delta->Playing=0; + } + + DeInitialise_HModel(&marineStatusPointer->HModelController); + ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr); + +} + +static STATE_RETURN_CONDITION Execute_MNS_Approach(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH velocityDirection = {0,0,0}; + VECTORCH targetPosition; + int targetIsAirduct = 0; + int range; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + HandleMovingAnimations(sbPtr); + + /* now check for state changes... firstly, if we can no longer attack the target, go + to wander */ + if(!(MarineIsAwareOfTarget(sbPtr))) + { + if (marineStatusPointer->suspicious==0) { + /* Return to wait. Nothing to worry about. */ + return(SRC_Request_Wait); + } + + } else { + + /* We have a target that we are aware of. */ + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + /* if we are close... go directly to firing */ + if(range < marineStatusPointer->My_Weapon->ForceFireRange) + { + /* switch directly to firing, at this distance */ + + return(SRC_Request_Fire); + } + + /* if our state timer has run out in approach state, see if we can fire*/ + if(marineStatusPointer->stateTimer > 0) marineStatusPointer->stateTimer -= NormalFrameTime; + if(marineStatusPointer->stateTimer <= 0) + { + /* it is time to fire, if we can see the target */ + if((MarineCanSeeTarget(sbPtr)) + &&((marineStatusPointer->My_Weapon->MaxRange==-1) + ||(rangeMy_Weapon->MaxRange))) { + + /* we are going to fire then */ + + return(SRC_Request_Fire); + } + else + { + /* renew approach state */ + marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING; + + } + } + } + + /* Kick them out of the stupid state? */ + + /* See which way we want to go. */ + if ((marineStatusPointer->destinationmodule==sbPtr->containingModule->m_aimodule) + ||(marineStatusPointer->destinationmodule==NULL)) { + + AIMODULE *targetModule; + MODULE *tcm; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + + if (marineStatusPointer->Target==NULL) { + /* Must be approaching a suspect point. */ + GLOBALASSERT(marineStatusPointer->suspicious); + tcm=ModuleFromPosition(&marineStatusPointer->suspect_point,sbPtr->containingModule); + } else { + if (marineStatusPointer->Target->containingModule) { + tcm=marineStatusPointer->Target->containingModule; + } else { + tcm=ModuleFromPosition(&marineStatusPointer->Target->DynPtr->Position,sbPtr->containingModule); + } + } + + if (tcm) { + targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,tcm->m_aimodule,7,0); + } else { + targetModule=NULL; + } + + if (targetModule==sbPtr->containingModule->m_aimodule) { + /* Try going for it, we still can't see them. */ + if (marineStatusPointer->Target) { + NPCGetMovementTarget(sbPtr, marineStatusPointer->Target, &targetPosition, &targetIsAirduct,0); + } else { + int range2; + VECTORCH relTargetPosition; + /* Just use the target point? */ + targetPosition=marineStatusPointer->suspect_point; + + #if 0 + range2=VectorDistance(&targetPosition,(&sbPtr->DynPtr->Position)); + #else + + relTargetPosition=targetPosition; + + relTargetPosition.vx-=sbPtr->DynPtr->Position.vx; + relTargetPosition.vy-=sbPtr->DynPtr->Position.vy; + relTargetPosition.vz-=sbPtr->DynPtr->Position.vz; + + /* Let's try doing this. */ + relTargetPosition.vy>>=2; + + range2=Approximate3dMagnitude(&relTargetPosition); + #endif + + if (range2suspicious=MARINE_PARANOIA_TIME; + /* Used to unset suspicion at that point. */ + if (marineStatusPointer->Mission==MM_Pathfinder) { + /* Get back to business! */ + return(SRC_Request_Return); + } else { + return(SRC_Request_Wait); + } + } + + } + NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&marineStatusPointer->waypointManager); + } else if (!targetModule) { + /* Must be inaccessible. Time out suspicion. */ + marineStatusPointer->suspicious-=NormalFrameTime; + /* To fix the next trap... */ + if (marineStatusPointer->suspicious==0) { + marineStatusPointer->suspicious=-1; + } + if (marineStatusPointer->suspicious<0) { + marineStatusPointer->suspicious=0; + /* Set to zero on natural timeout, too. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + if ((marineStatusPointer->behaviourState==MBS_Waiting) + ||(marineStatusPointer->behaviourState==MBS_Sentry)) { + /* We might concievably want to do this for all states. */ + marineStatusPointer->gotapoint=0; + } + } + + if (ShowSquadState) { + if (marineStatusPointer->Target) { + if (marineStatusPointer->Target->containingModule) { + PrintDebuggingText("I can see you, but I can't get there!\n"); + } else { + PrintDebuggingText("Hey, you've got no Containing Module!\n"); + } + } else { + PrintDebuggingText("Can't get to the suspect point!\n"); + /* Yuck. Stop it. */ + #if 0 + marineStatusPointer->suspicious=MARINE_PARANOIA_TIME; + /* Used to unset suspicion at that point. */ + #else + marineStatusPointer->suspicious=1; + /* Just this once, let's unset it... We can't do anything about it. */ + #endif + return(SRC_Request_Wait); + } + } + return(SRC_No_Change); + } else { + + thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); + if (!thisEp) { + LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.", + (*(targetModule->m_module_ptrs))->name, + sbPtr->containingModule->name)); + //LOGDXFMT(("This assert is a busted adjacency!")); + GLOBALASSERT(thisEp); + } + /* If that fired, there's a farped adjacency. */ + GLOBALASSERT(thisEp->alien_only==0); + /* If that fired, GetNextModuleForLink went wrong. */ + + marineStatusPointer->wanderData.worldPosition=thisEp->position; + marineStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx; + marineStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy; + marineStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz; + + NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager); + + } + + } else if (marineStatusPointer->destinationmodule!=NULL) { + /* Go towards next module. */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager); + } else { + /* we are still in approach state: target the target, and move */ + if (marineStatusPointer->Target) { + NPCGetMovementTarget(sbPtr, marineStatusPointer->Target, &targetPosition, &targetIsAirduct,0); + } else { + /* How did we get here, anyway? */ + targetPosition=marineStatusPointer->suspect_point; + } + NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&marineStatusPointer->waypointManager); + } + + /* Should have a velocity set now. */ + + NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE + { + if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(SRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + + NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject); + if(marineStatusPointer->obstruction.environment) + { + /* go to avoidance */ + return(SRC_Request_Avoidance); + } + if(marineStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &targetPosition, &velocityDirection)) + { + + marineStatusPointer->obstruction.environment=1; + marineStatusPointer->obstruction.destructableObject=0; + marineStatusPointer->obstruction.otherCharacter=0; + marineStatusPointer->obstruction.anySingleObstruction=0; + + return(SRC_Request_Avoidance); + } + #endif + + return(SRC_No_Change); +} + + +/* this function is specifically for marines, and creates a gun flash +pointing in the direction of the target point */ +static void MaintainMarineGunFlash(STRATEGYBLOCK *sbPtr) +{ + VECTORCH firingDirn,firingPoint; + MARINE_STATUS_BLOCK *marineStatusPointer; + int firingOffsetUp; + int firingOffsetInfront; + int firingOffsetAcross; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + GLOBALASSERT(marineStatusPointer->My_Gunflash_Section); + + /* get the firing point offsets:*/ + if(marineStatusPointer->IAmCrouched) + { + firingOffsetUp = MARINE_FIRINGPOINT_UP; + firingOffsetInfront = MARINE_FIRINGPOINT_INFRONT; + firingOffsetAcross = MARINE_FIRINGPOINT_ACROSS; + } + else + { + firingOffsetUp = MARINE_FIRINGPOINT_UP_CROUCHED; + firingOffsetInfront = MARINE_FIRINGPOINT_INFRONT_CROUCHED; + firingOffsetAcross = MARINE_FIRINGPOINT_ACROSS_CROUCHED; + } + + /* find the firing direction */ + firingDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + firingDirn.vy = marineStatusPointer->weaponTarget.vy - sbPtr->DynPtr->Position.vy; + firingDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + Normalise(&firingDirn); + { + VECTORCH yNormal = {0,-65536,0}; + VECTORCH tempDirn; + VECTORCH acrossDirn; + + /* now find firing point (conceptually, the end of the weapon muzzle)... */ + firingPoint = sbPtr->DynPtr->Position; + firingPoint.vx += MUL_FIXED(firingDirn.vx,firingOffsetInfront); + firingPoint.vz += MUL_FIXED(firingDirn.vz,firingOffsetInfront); + + tempDirn = firingDirn; + tempDirn.vy = 0; + Normalise(&tempDirn); + CrossProduct(&tempDirn,&yNormal,&acrossDirn); + Normalise(&acrossDirn); + firingPoint.vx += MUL_FIXED(tempDirn.vx,firingOffsetAcross); + firingPoint.vz += MUL_FIXED(tempDirn.vz,firingOffsetAcross); + firingPoint.vy += MUL_FIXED(yNormal.vy,firingOffsetUp); + } + LOCALASSERT(marineStatusPointer->myGunFlash!=NULL); + + MaintainNPCGunFlashEffect(marineStatusPointer->myGunFlash,&marineStatusPointer->My_Gunflash_Section->World_Offset, + &marineStatusPointer->My_Gunflash_Section->SecMat); +} + +/* NB this shouldn't be called if : +1. we are close to the target +2. we are crouched */ +static void LobAGrenade(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + //VECTORCH firingPoint; + //VECTORCH firingDirn; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* first, find the firing direction */ + //firingDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + //firingDirn.vy = marineStatusPointer->weaponTarget.vy - sbPtr->DynPtr->Position.vz; + //firingDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + //Normalise(&firingDirn); + + if((sbPtr->DynPtr->Position.vy - marineStatusPointer->weaponTarget.vy) > 2500) + { + /* too high */ + return; + } + + #if 0 + { + VECTORCH yNormal = {0,-65536,0}; + VECTORCH tempDirn; + VECTORCH acrossDirn; + + /* now find firing point (conceptually, the end of the weapon muzzle + a bit)... */ + firingPoint = sbPtr->DynPtr->Position; + firingPoint.vx += MUL_FIXED(firingDirn.vx,(MARINE_FIRINGPOINT_INFRONT+400)); + firingPoint.vz += MUL_FIXED(firingDirn.vz,(MARINE_FIRINGPOINT_INFRONT+400)); + + tempDirn = firingDirn; + tempDirn.vy = 0; + Normalise(&tempDirn); + CrossProduct(&tempDirn,&yNormal,&acrossDirn); + Normalise(&acrossDirn); + firingPoint.vx += MUL_FIXED(tempDirn.vx,MARINE_FIRINGPOINT_ACROSS); + firingPoint.vz += MUL_FIXED(tempDirn.vz,MARINE_FIRINGPOINT_ACROSS); + firingPoint.vy += MUL_FIXED(yNormal.vy,MARINE_FIRINGPOINT_UP); + } + #endif + + /* this bit nicked from player grenade creation fn. in bh_weap.c : + actually, it is now a pulse rifle grenade */ + { + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + + dispPtr = MakeObject(I_BehaviourPulseGrenade,&marineStatusPointer->My_Gunflash_Section->World_Offset); + if(!dispPtr) return; + LOCALASSERT(dispPtr->ObStrategyBlock); + AddLightingEffectToObject(dispPtr,LFX_ROCKETJET); + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + if(!dynPtr) + { + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(PREDPISTOL_BEHAV_BLOCK)); + if(!dispPtr->ObStrategyBlock->SBdataptr) + { + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED; + ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->player = 0; + + GLOBALASSERT(marineStatusPointer->My_Gunflash_Section); + + #define PULSEGRENADE_SPEED 100000 // Was 30000 + dynPtr->Position = marineStatusPointer->My_Gunflash_Section->World_Offset; + dynPtr->OrientMat = marineStatusPointer->My_Gunflash_Section->SecMat; + dynPtr->PrevOrientMat = dynPtr->OrientMat; /* stops mis-alignment if dynamics problem */ + + dynPtr->LinVelocity.vx = dynPtr->OrientMat.mat31; + dynPtr->LinVelocity.vy = dynPtr->OrientMat.mat32; + dynPtr->LinVelocity.vz = dynPtr->OrientMat.mat33; + + dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx, PULSEGRENADE_SPEED); + dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy, PULSEGRENADE_SPEED); + dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz, PULSEGRENADE_SPEED); + + //dynPtr->LinImpulse.vx = MUL_FIXED(firingDirn.vx,PULSEGRENADE_SPEED); + //dynPtr->LinImpulse.vy = MUL_FIXED(firingDirn.vy,PULSEGRENADE_SPEED); + //dynPtr->LinImpulse.vz = MUL_FIXED(firingDirn.vz,PULSEGRENADE_SPEED); + } +} + +/*NB avoidance state behaviour function probabaly doesn't need to check +for crouching, or for target becoming cloaked. Only when we exit the state +do we need to check these behaviour parameters to pick a new state and sequence*/ +static STATE_RETURN_CONDITION Execute_MNS_Avoidance(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + int terminateState = 0; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + #if 1 + HandleMovingAnimations(sbPtr); + #endif + + #if ALL_NEW_AVOIDANCE + /* New avoidance kernel. */ + + NPCSetVelocity(sbPtr, &(marineStatusPointer->avoidanceManager.avoidanceDirection), (marineStatusPointer->nearSpeed)); + /* Velocity CANNOT be zero, unless deliberately so! */ + { + AVOIDANCE_RETURN_CONDITION rc; + + rc=AllNewAvoidanceKernel(sbPtr,&marineStatusPointer->avoidanceManager); + + if (rc!=AvRC_Avoidance) { + terminateState=1; + } + /* Should put in a test for AvRC_Failure here. */ + } + + #if 0 + { + VECTORCH point; + /* Wacky test. */ + GetTargetingPointOfObject_Far(sbPtr,&point); + MakeParticle(&point,&sbPtr->DynPtr->LinVelocity,PARTICLE_NONCOLLIDINGFLAME); + + MakeParticle(&point,&(marineStatusPointer->avoidanceManager.avoidanceDirection),PARTICLE_PREDATOR_BLOOD); + MakeParticle(&point,&(marineStatusPointer->avoidanceManager.aggregateNormal),PARTICLE_ALIEN_BLOOD); + + } + #endif + + #else + /* set velocity */ + LOCALASSERT((marineStatusPointer->moveData.avoidanceDirn.vx!=0)|| + (marineStatusPointer->moveData.avoidanceDirn.vy!=0)|| + (marineStatusPointer->moveData.avoidanceDirn.vz!=0)); + NPCSetVelocity(sbPtr, &(marineStatusPointer->moveData.avoidanceDirn), (marineStatusPointer->nearSpeed)); + + /* decrement state timer */ + marineStatusPointer->stateTimer -= NormalFrameTime; + if(marineStatusPointer->stateTimer <= 0) terminateState = 1; + + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_OBSTRUCTIONREPORT obstruction; + NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&obstruction,&destructableObject); + if(obstruction.anySingleObstruction) + { + terminateState = 1; + } + } + #endif + + if(terminateState) + { + /* switch to approach */ + if(MarineIsAwareOfTarget(sbPtr)) + { + /* go to approach */ + + return(SRC_Request_Approach); + /* Was fire! */ + } + else + { + /* go to an appropriate state */ + switch (marineStatusPointer->lastState) { + case MBS_Retreating: + return(SRC_Request_Retreat); + break; + case MBS_Returning: + return(SRC_Request_Return); + break; + case MBS_Responding: + return(SRC_Request_Respond); + break; + case MBS_Approaching: + /* Go directly to approach. Do not pass GO. Do not collect 200 zorkmids. */ + return(SRC_Request_Approach); + break; + case MBS_Sentry: + /* Go back to sentry. */ + return(SRC_Request_Wait); + break; + default: + return(SRC_Request_Wander); + break; + } + /* Still here? */ + return(SRC_Request_Wander); + } + } + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MNS_Wander(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + DYNAMICSBLOCK *dynPtr; + VECTORCH velocityDirection = {0,0,0}; + + LOCALASSERT(sbPtr); + marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(marineStatusPointer); + LOCALASSERT(dynPtr); + + HandleMovingAnimations(sbPtr); + + /* should we change to approach state? */ + if ((MarineIsAwareOfTarget(sbPtr))||(marineStatusPointer->suspicious)) + { + /* doesn't require a sequence change */ + return(SRC_Request_Approach); + } + + /* Is there a new alert? */ + if ((NpcSquad.alertZone)&&(marineStatusPointer->Mission!=MM_LocalGuard) + &&(marineStatusPointer->Mission!=MM_NonCom)) { + /* Are we already there? */ + if (sbPtr->containingModule->m_aimodule!=NpcSquad.alertZone) { + if (NpcSquad.responseLevel>0) { + /* Picked up a target. Can we move to respond? */ + AIMODULE *targetModule=0; + targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr); + if (targetModule) { + return(SRC_Request_Respond); + } + } + } + } + + /* Are we bored of wandering yet? */ + + marineStatusPointer->stateTimer-=NormalFrameTime; + + if (marineStatusPointer->stateTimer<=0) { + /* Time to make a decision. */ + marineStatusPointer->stateTimer = MARINE_NEARWAITTIME; + if ((FastRandom()&65535)<8192) + { + /* This is too tiring... let's just wait around a while. */ + return(SRC_Request_Wait); + } + } + + /* Are we using bimble rules? */ + + if (marineStatusPointer->wanderData.currentModule==NPC_BIMBLINGINMODULE) { + + int range; + + /* Range to target... */ + + range=VectorDistance((&marineStatusPointer->wanderData.worldPosition),(&sbPtr->DynPtr->Position)); + + if (range<2000) { + + /* Reset system, try again. */ + marineStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE; + marineStatusPointer->moveData.lastModule=NULL; + + } + + } else { + + /* wander target aquisition: if no target, or moved module */ + LOCALASSERT(sbPtr->containingModule); + if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_InitMovementData(&(marineStatusPointer->moveData)); + marineStatusPointer->moveData.lastModule=marineStatusPointer->lastmodule; + NPC_FindAIWanderTarget(sbPtr,&(marineStatusPointer->wanderData),&(marineStatusPointer->moveData),0); + + } + else if(marineStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_aimodule->m_index) + { + NPC_FindAIWanderTarget(sbPtr,&(marineStatusPointer->wanderData),&(marineStatusPointer->moveData),0); + + } + + /* if we still haven't got one, bimble about in this one for a bit. */ + if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_GetBimbleTarget(sbPtr,&marineStatusPointer->wanderData.worldPosition); + marineStatusPointer->wanderData.currentModule=NPC_BIMBLINGINMODULE; + + } + + } + + /* ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE + { + if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(SRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject); + if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter)) + { + /* go to avoidance */ + return(SRC_Request_Avoidance); + } + if(marineStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &(marineStatusPointer->wanderData.worldPosition), &velocityDirection)) + { + /* go to avoidance */ + /* no sequence change required */ + + marineStatusPointer->obstruction.environment=1; + marineStatusPointer->obstruction.destructableObject=0; + marineStatusPointer->obstruction.otherCharacter=0; + marineStatusPointer->obstruction.anySingleObstruction=0; + + return(SRC_Request_Avoidance); + } + #endif + + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MNS_Return(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + DYNAMICSBLOCK *dynPtr; + AIMODULE *targetModule; + VECTORCH velocityDirection = {0,0,0}; + + LOCALASSERT(sbPtr); + marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(marineStatusPointer); + LOCALASSERT(dynPtr); + + HandleMovingAnimations(sbPtr); + + /* should we change to approach state? */ + if(MarineIsAwareOfTarget(sbPtr)) + { + /* doesn't require a sequence change */ + return(SRC_Request_Approach); + } + + #if 0 + /* Ignore alerts. */ + if ((NpcSquad.alertZone)&&(marineStatusPointer->Mission!=MM_LocalGuard) + &&(marineStatusPointer->Mission!=MM_NonCom)) { + /* Are we already there? */ + if (sbPtr->containingModule->m_aimodule!=NpcSquad.alertZone) { + if (NpcSquad.responseLevel>0) { + /* Picked up a target. Can we move to respond? */ + AIMODULE *targetModule=0; + targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr); + if (targetModule) { + return(SRC_Request_Respond); + } + } + } + } + #endif + + marineStatusPointer->stateTimer-=NormalFrameTime; + + /* Are we there yet? */ + if (sbPtr->containingModule->m_aimodule==marineStatusPointer->missionmodule) { + return(SRC_Request_Wait); + } + + /* Target module aquisition. */ + + LOCALASSERT(sbPtr->containingModule); + + if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_InitMovementData(&(marineStatusPointer->moveData)); + } + if ((marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + ||(marineStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_aimodule->m_index)) { + + targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,marineStatusPointer->missionmodule,7,0); + + if (targetModule) { + FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule); + if(thisEp) { + /* aha. an ep!... */ + VECTORCH thisEpWorld = thisEp->position; + + thisEpWorld.vx += targetModule->m_world.vx; + thisEpWorld.vy += targetModule->m_world.vy; + thisEpWorld.vz += targetModule->m_world.vz; + + marineStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index; + marineStatusPointer->wanderData.worldPosition = thisEpWorld; + + GLOBALASSERT(thisEp->alien_only==0); + /* If that fired, GetNextModuleForLink went wrong. */ + } else { + /* Failure case. */ + marineStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE; + } + + } else { + /* Another failure case. */ + marineStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE; + } + } + + /* if we still haven't got one, bimble about in this one for a bit. */ + if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_InitMovementData(&(marineStatusPointer->moveData)); + marineStatusPointer->moveData.lastModule=marineStatusPointer->lastmodule; + NPC_FindAIWanderTarget(sbPtr,&(marineStatusPointer->wanderData),&(marineStatusPointer->moveData),0); + } + + if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) { + /* STILL broken! Okay, just... wander, then. */ + return(SRC_Request_Wander); + } + + /* ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE + { + if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(SRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject); + if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter)) + { + /* go to avoidance */ + return(SRC_Request_Avoidance); + } + if(marineStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &(marineStatusPointer->wanderData.worldPosition), &velocityDirection)) + { + /* go to avoidance */ + /* no sequence change required */ + + marineStatusPointer->obstruction.environment=1; + marineStatusPointer->obstruction.destructableObject=0; + marineStatusPointer->obstruction.otherCharacter=0; + marineStatusPointer->obstruction.anySingleObstruction=0; + + return(SRC_Request_Avoidance); + } + #endif + + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MNS_Pathfinder(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + DYNAMICSBLOCK *dynPtr; + AIMODULE *targetModule; + VECTORCH velocityDirection = {0,0,0}; + + LOCALASSERT(sbPtr); + marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(marineStatusPointer); + LOCALASSERT(dynPtr); + + #if 0 + /* check if we should be crouched or standing up */ + if(marineStatusPointer->IAmCrouched) + { + /* curently crouched */ + if(!(MarineShouldBeCrawling(sbPtr))) + { + /* should be running*/ + marineStatusPointer->IAmCrouched = 0; + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } + else + { + /* currently standing */ + if(MarineShouldBeCrawling(sbPtr)) + { + /* should be crawling */ + marineStatusPointer->IAmCrouched = 1; + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } + #else + HandleMovingAnimations(sbPtr); + #endif + + /* should we change to approach state? */ + if(MarineIsAwareOfTarget(sbPtr)) + { + /* doesn't require a sequence change */ + return(SRC_Request_Approach); + } + + if (marineStatusPointer->suspicious) { + MODULE *targetModule; + /* Are we allowed to check it out? */ + targetModule=ModuleFromPosition(&marineStatusPointer->suspect_point,sbPtr->containingModule); + if (targetModule) { + if (IsModuleVisibleFromModule(targetModule,sbPtr->containingModule)) { + /* I suppose we'd better go, then. */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + return(SRC_Request_Wait); + } else { + return(SRC_Request_Approach); + } + } + } + } + + /* Ignore alerts. */ + + marineStatusPointer->stateTimer-=NormalFrameTime; + + if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_InitMovementData(&(marineStatusPointer->moveData)); + } + if ((marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + ||(marineStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_aimodule->m_index)) { + + FARENTRYPOINT *thisEp; + int nextModuleIndex; + /* Okay, so where are we exactly? */ + + if ((marineStatusPointer->stepnumber<0)||(marineStatusPointer->path<0)) { + /* Get OUT! */ + return(SRC_Request_Wander); + } + + targetModule = TranslatePathIndex(marineStatusPointer->stepnumber,marineStatusPointer->path); + + if (targetModule==NULL) { + /* Oh, to heck with this. Try to wander. */ + return(SRC_Request_Wander); + } + + /* Right, so there is a somewhere to get to. */ + + if (targetModule!=sbPtr->containingModule->m_aimodule) { + /* But we're nowhere near it. Geeze... */ + marineStatusPointer->missionmodule=targetModule; + return(SRC_Request_Return); + } + + /* Okay, so now we need to know where to go now. */ + + nextModuleIndex=GetNextModuleInPath(marineStatusPointer->stepnumber,marineStatusPointer->path); + GLOBALASSERT(nextModuleIndex>=0); + /* If that fires, it's Richard's fault. */ + targetModule=TranslatePathIndex(nextModuleIndex,marineStatusPointer->path); + GLOBALASSERT(targetModule); + /* Ditto. */ + marineStatusPointer->stepnumber=nextModuleIndex; + + thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule); + if(thisEp) { + /* aha. an ep!... */ + VECTORCH thisEpWorld = thisEp->position; + + thisEpWorld.vx += targetModule->m_world.vx; + thisEpWorld.vy += targetModule->m_world.vy; + thisEpWorld.vz += targetModule->m_world.vz; + + marineStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index; + marineStatusPointer->wanderData.worldPosition = thisEpWorld; + GLOBALASSERT(thisEp->alien_only==0); + /* If that fired, the path goes through an alien-only link. */ + + } else { + /* Failure case. */ + marineStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE; + } + + } + + /* if we still haven't got one, wander for a bit. */ + if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_InitMovementData(&(marineStatusPointer->moveData)); + marineStatusPointer->moveData.lastModule=marineStatusPointer->lastmodule; + NPC_FindAIWanderTarget(sbPtr,&(marineStatusPointer->wanderData),&(marineStatusPointer->moveData),0); + } + + if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) { + /* STILL broken! Okay, just... wander forever, then. */ + return(SRC_Request_Wander); + } + + /* ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE + { + if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(SRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject); + if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter)) + { + /* go to avoidance */ + return(SRC_Request_Avoidance); + } + if(marineStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &(marineStatusPointer->wanderData.worldPosition), &velocityDirection)) + { + /* go to avoidance */ + /* no sequence change required */ + + marineStatusPointer->obstruction.environment=1; + marineStatusPointer->obstruction.destructableObject=0; + marineStatusPointer->obstruction.otherCharacter=0; + marineStatusPointer->obstruction.anySingleObstruction=0; + + return(SRC_Request_Avoidance); + } + #endif + + return(SRC_No_Change); +} + +void NPC_GetBimbleTarget(STRATEGYBLOCK *sbPtr,VECTORCH *output) { + + MODULE *my_module; + VECTORCH alternate; + int success; + + /* Get a random position in the same module. */ + + my_module=sbPtr->containingModule; + success=0; + + while (success==0) { + + do { + output->vx=FastRandom()&65535; + output->vx+=my_module->m_minx; + } while (!( (output->vx>my_module->m_minx)&&(output->vxm_maxx) )); + + do { + output->vz=FastRandom()&65535; + output->vz+=my_module->m_minz; + } while (!( (output->vz>my_module->m_minz)&&(output->vzm_maxz) )); + + output->vy=sbPtr->DynPtr->Position.vy; + output->vy-=my_module->m_world.vy; + + if (!( (output->vy>my_module->m_miny)&&(output->vym_maxy) )) { + do { + output->vy=FastRandom()&65535; + output->vy+=my_module->m_miny; + } while (!( (output->vy>my_module->m_miny)&&(output->vym_maxy) )); + } + + GLOBALASSERT(PointIsInModule(my_module,output)); + + output->vx+=my_module->m_world.vx; + output->vy+=my_module->m_world.vy; + output->vz+=my_module->m_world.vz; + + /* Check for waypoints? */ + + if (my_module->m_waypoints) { + if (GetPositionValidity(my_module,output,&alternate)==NULL) { + /* Failure! */ + success=0; + } else { + if ( (alternate.vx!=output->vx) + || (alternate.vy!=output->vy) + || (alternate.vz!=output->vz) ) { + *output=alternate; + /* Success! */ + success=1; + } else { + /* Success! */ + success=1; + } + } + } else { + /* Success! */ + success=1; + } + + } + +} + +static void HandleFidgetAnimations(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* A sub function for simplicity. */ + + if(marineStatusPointer->IAmCrouched) { + /* No crouch fidget yet. */ + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineCrouch) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MCrSS_Standard)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrouch,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } else { + /* Are we in some sort of fidget anim? */ + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)||( + (marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Stand_To_Fidget) + &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Fidget_A) + &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Fidget_B) + &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Fidget_C) + )) { + + if ((marineStatusPointer->HModelController.Sequence_Type==HMSQT_MarineRun) + &&(marineStatusPointer->HModelController.Sub_Sequence==MRSS_Mooch_Bored)) { + /* Mooch bored does not require Stand_To_Fidget - go directly to Fidget_A. */ + if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Fidget_A)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Fidget_A,ONE_FIXED<<3,(ONE_FIXED>>3)); + marineStatusPointer->internalState=0; + } else { + /* No fidgets at all! */ + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } else if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Stand_To_Fidget)) { + /* Not in any kind of fidget anim: run Stand_To_Fidget if poss. */ + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Stand_To_Fidget,((ONE_FIXED*3)/2),(ONE_FIXED>>3)); + marineStatusPointer->HModelController.LoopAfterTweening=0; + } else if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Fidget_A)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Fidget_A,ONE_FIXED<<3,(ONE_FIXED>>3)); + } else { + /* No fidgets at all! */ + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + + } else { + if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Stand_To_Fidget)) { + /* We must have gone through StandToFidget, or at least be in it. */ + if (((marineStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(marineStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1)) + &&(marineStatusPointer->HModelController.Looped==0)) + ||((marineStatusPointer->HModelController.keyframe_flags)&&(marineStatusPointer->internalState))) { + /* End of old sequence. */ + /* Go back to normal. */ + if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Fidget_A)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Fidget_A,ONE_FIXED<<3,(ONE_FIXED>>3)); + marineStatusPointer->internalState=0; + } + } else if (marineStatusPointer->HModelController.keyframe_flags) { + if ((FastRandom()&65535)<21846) { + if ((FastRandom()&65535)<32767) { + if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Fidget_B)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Fidget_B,-1,(ONE_FIXED>>3)); + marineStatusPointer->HModelController.LoopAfterTweening=0; + marineStatusPointer->internalState=1; + } else if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Fidget_C)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Fidget_C,-1,(ONE_FIXED>>3)); + marineStatusPointer->HModelController.LoopAfterTweening=0; + marineStatusPointer->internalState=2; + } + } else { + if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Fidget_C)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Fidget_C,-1,(ONE_FIXED>>3)); + marineStatusPointer->HModelController.LoopAfterTweening=0; + marineStatusPointer->internalState=2; + } else if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Fidget_B)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Fidget_B,-1,(ONE_FIXED>>3)); + marineStatusPointer->HModelController.LoopAfterTweening=0; + marineStatusPointer->internalState=1; + } + } + } + /* Else do nothing, I guess. */ + } + } else { + /* No stand to fidget. */ + } + } + } + +} + +static void HandleWaitingAnimations(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + int tweeningtime; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + #if 0 + /* If you get here, you look stationary, so BE stationary! */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + #endif + + { + DELTA_CONTROLLER *delta; + /* There should be NO head turn delta. */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + } + } + + /* First test to see if we're in midair. */ + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_Jump)) { + if (!sbPtr->DynPtr->IsInContactWithFloor) { + VECTORCH offset; + + offset.vx=sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx; + offset.vy=sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy; + offset.vz=sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz; + + if ((offset.vx!=0)||(offset.vy!=0)||(offset.vz!=0)) { + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Jump)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Jump,-1,(ONE_FIXED>>4)); + } + } + } + } + + /* Get a random tweening time... */ + + tweeningtime=((FastRandom()&65535)+32767)>>3; + + /* Figure out what we should be playing, and do it. */ + + if (MarineShouldBeCrawling(sbPtr)) { + marineStatusPointer->IAmCrouched=1; + } else { + marineStatusPointer->IAmCrouched=0; + } + + if(marineStatusPointer->IAmCrouched) { + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineCrouch) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MCSS_Standard)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrouch,MCSS_Standard,ONE_FIXED,tweeningtime); + } + } else { + if (marineStatusPointer->suspicious) { + /* Go directly to wait alert, if you can. */ + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_Wait_Alert)) { + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Wait_Alert)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Wait_Alert,(MUL_FIXED((ONE_FIXED<<2),((FastRandom()&32767)+65536))),tweeningtime); + } + } else { + HandleFidgetAnimations(sbPtr); + } + } else { + HandleFidgetAnimations(sbPtr); + } + } +} + +static void HandleMovingAnimations(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + MARINE_MOVEMENT_STYLE style; + MARINE_BHSTATE baseState; + MOVEMENT_DATA *movementData; + VECTORCH offset; + int can_mooch_bored; + int can_mooch_alert; + int can_sprint; + int speed,animfactor; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + style=-1; + + /* First test to see if we're in midair. */ + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_Jump)) { + if (!sbPtr->DynPtr->IsInContactWithFloor) { + VECTORCH offset; + + offset.vx=sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx; + offset.vy=sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy; + offset.vz=sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz; + + if ((offset.vx!=0)||(offset.vy!=0)||(offset.vz!=0)) { + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Jump)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Jump,-1,(ONE_FIXED>>4)); + } + } + } + } + + can_mooch_bored=HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineRun,MRSS_Mooch_Bored); + can_mooch_alert=HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineRun,MRSS_Mooch_Alert); + can_sprint=HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineRun,MRSS_Sprint); + + /* Figure out what we should be playing... */ + + if (marineStatusPointer->behaviourState==MBS_Avoidance) { + baseState=marineStatusPointer->lastState; + } else { + baseState=marineStatusPointer->behaviourState; + } + + switch (baseState) { + case MBS_Waiting: + /* Why am I here? */ + style=MMS_Alert; + break; + case MBS_Wandering: + style=MMS_Bored; + break; + case MBS_Retreating: + style=MMS_Sprint; + break; + case MBS_Sentry: + case MBS_Returning: + case MBS_Pathfinding: + if (marineStatusPointer->Target==NULL) { + if (marineStatusPointer->suspicious) { + style=MMS_Alert; + } else { + style=MMS_Bored; + } + } else { + style=MMS_Combat; + } + case MBS_Approaching: + case MBS_Responding: + if (marineStatusPointer->Target==NULL) { + style=MMS_Alert; + } else { + style=MMS_Combat; + } + break; + case MBS_Firing: + /* Shouldn't really be here. */ + style=MMS_Combat; + break; + case MBS_Avoidance: + case MBS_Dying: + /* Definitely shouldn't be here! */ + GLOBALASSERT(0); + break; + default: + /* Shouldn't really be here. */ + style=MMS_Combat; + break; + } + + /* Finally... */ + offset.vx=sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx; + offset.vy=sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy; + offset.vz=sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz; + { + #if 0 + int dist; + /* ...compute speed factor... */ + speed=Approximate3dMagnitude(&sbPtr->DynPtr->LinVelocity); + dist=Approximate3dMagnitude(&offset); + if (dist<(MUL_FIXED(NormalFrameTime,100))) { + /* Not moving much, are we? */ + style=MMS_Stationary; + } + #else + /* ...compute speed factor... */ + speed=Magnitude(&offset); + if (speed<(MUL_FIXED(NormalFrameTime,50))) { + /* Not moving much, are we? */ + style=MMS_Stationary; + } + speed=DIV_FIXED(speed,NormalFrameTime); + #endif + } + + /* Fix crouching. */ + if(marineStatusPointer->IAmCrouched) + { + /* currently crouched */ + if(!(MarineShouldBeCrawling(sbPtr))) { + marineStatusPointer->IAmCrouched=0; + } + } else { + /* currently standing */ + if(MarineShouldBeCrawling(sbPtr)) { + marineStatusPointer->IAmCrouched=1; + } + } + + /* Now, pre-emptive reject of unavailable cases. */ + if (style==MMS_Bored) { + if (!can_mooch_bored) { + style=MMS_Combat; + } + } + + if (style==MMS_Alert) { + if (!can_mooch_alert) { + style=MMS_Combat; + } + } + + if (style==MMS_Sprint) { + #if 1 + if (!can_sprint) { + #else + if (1) { + #endif + style=MMS_Combat; + } + } + + if (speed==0) { + style=MMS_Stationary; + animfactor=ONE_FIXED; + } else { + animfactor=DIV_FIXED(625,speed); // Was 512! Difference to correct for rounding down... + } + GLOBALASSERT(animfactor>0); + + /* ...and do it. */ + switch (style) { + + case -1: + /* Whoops! */ + GLOBALASSERT(0); + break; + case MMS_Stationary: + { + /* Ouch. */ + HandleWaitingAnimations(sbPtr); + } + break; + case MMS_Bored: + { + if(marineStatusPointer->IAmCrouched) { + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineCrawl) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MCSS_Standard)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCSS_Standard,ONE_FIXED,(ONE_FIXED>>4)); + } + + if (marineStatusPointer->My_Weapon->ARealMarine) { + movementData=GetThisMovementData(MDI_Marine_Combat); + } else { + movementData=GetThisMovementData(MDI_Civilian_Combat); + } + GLOBALASSERT(movementData); + marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant); + marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant); + + } else { + /* If we're here, we must be able to mooch bored. */ + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineRun) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MRSS_Mooch_Bored)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Mooch_Bored,((ONE_FIXED*7)/5),(ONE_FIXED>>4)); + } + + if (marineStatusPointer->My_Weapon->ARealMarine) { + movementData=GetThisMovementData(MDI_Marine_Mooch_Bored); + } else { + movementData=GetThisMovementData(MDI_Civilian_Mooch_Bored); + } + GLOBALASSERT(movementData); + marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant); + marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant); + + //marineStatusPointer->nearSpeed=MARINE_NEAR_SPEED>>2; + } + } + break; + case MMS_Alert: + { + if(marineStatusPointer->IAmCrouched) { + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineCrawl) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MCSS_Standard)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCSS_Standard,ONE_FIXED,(ONE_FIXED>>4)); + } + + if (marineStatusPointer->My_Weapon->ARealMarine) { + movementData=GetThisMovementData(MDI_Marine_Combat); + } else { + movementData=GetThisMovementData(MDI_Civilian_Combat); + } + GLOBALASSERT(movementData); + marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant); + marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant); + } else { + /* If we're here, we must be able to mooch alert. */ + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineRun) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MRSS_Mooch_Alert)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Mooch_Alert,((ONE_FIXED*23)/10),(ONE_FIXED>>4)); + } + if (marineStatusPointer->My_Weapon->ARealMarine) { + movementData=GetThisMovementData(MDI_Marine_Mooch_Alert); + } else { + movementData=GetThisMovementData(MDI_Civilian_Mooch_Alert); + } + GLOBALASSERT(movementData); + marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant); + marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant); + } + } + break; + case MMS_Sprint: + { + if(marineStatusPointer->IAmCrouched) { + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineCrawl) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MCSS_Standard)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCSS_Standard,ONE_FIXED,(ONE_FIXED>>4)); + } + if (marineStatusPointer->My_Weapon->ARealMarine) { + movementData=GetThisMovementData(MDI_Marine_Combat); + } else { + movementData=GetThisMovementData(MDI_Civilian_Combat); + } + GLOBALASSERT(movementData); + marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant); + marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant); + } else { + /* If we're here, we must be able to sprint. */ + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineRun) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MRSS_Sprint)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Sprint,((ONE_FIXED*7)/10),(ONE_FIXED>>4)); + } + if (marineStatusPointer->My_Weapon->ARealMarine) { + movementData=GetThisMovementData(MDI_Marine_Sprint); + } else { + movementData=GetThisMovementData(MDI_Civilian_Sprint); + } + GLOBALASSERT(movementData); + marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant); + marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant); + } + } + break; + case MMS_Combat: + default: + { + if(marineStatusPointer->IAmCrouched) { + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineCrawl) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MCSS_Standard)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCSS_Standard,ONE_FIXED,(ONE_FIXED>>4)); + } + if (marineStatusPointer->My_Weapon->ARealMarine) { + movementData=GetThisMovementData(MDI_Marine_Combat); + } else { + movementData=GetThisMovementData(MDI_Civilian_Combat); + } + GLOBALASSERT(movementData); + marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant); + marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant); + } else { + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineRun) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MRSS_Standard)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>4)); + } + if (marineStatusPointer->My_Weapon->ARealMarine) { + movementData=GetThisMovementData(MDI_Marine_Combat); + } else { + movementData=GetThisMovementData(MDI_Civilian_Combat); + } + GLOBALASSERT(movementData); + marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant); + marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant); + } + } + break; + + } + if (marineStatusPointer->HModelController.Tweening==0) { + HModel_SetToolsRelativeSpeed(&marineStatusPointer->HModelController,animfactor); + } + + /* Finally, civilians sprinting away look over their shoulders... */ + { + int crs; + DELTA_CONTROLLER *delta; + + crs=0; + + if (marineStatusPointer->My_Weapon->ARealMarine==0) { + if (style==MMS_Sprint) { + if (marineStatusPointer->IAmCrouched==0) { + if (marineStatusPointer->behaviourState==MBS_Retreating) { + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineRun,MRSS_SprintHeadDelta)) { + crs=1; + } + } + } + } + } + + if (crs) { + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + if (!delta) { + /* Add it. */ + delta=Add_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta",(int)HMSQT_MarineRun,(int)MRSS_SprintHeadDelta,-1); + GLOBALASSERT(delta); + delta->Playing=0; + delta->Looped=0; + } + /* Now we must have it... */ + if (delta->Playing==0) { + if (marineStatusPointer->incidentFlag) { + /* Start it. */ + Start_Delta_Sequence(delta,(int)HMSQT_MarineRun,(int)MRSS_SprintHeadDelta,-1); + delta->Playing=1; + } + } else { + if (DeltaAnimation_IsFinished(delta)) { + delta->Playing=0; + } + } + } else { + /* There should be NO such delta. */ + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + } + } + } +} + +static STATE_RETURN_CONDITION Execute_MNS_SentryMode(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn,offset,velocityDirection; + int correctlyOrientated,range; + int dist; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + offset.vx=sbPtr->DynPtr->Position.vx-marineStatusPointer->my_spot.vx; + offset.vy=sbPtr->DynPtr->Position.vy-marineStatusPointer->my_spot.vy; + offset.vz=sbPtr->DynPtr->Position.vz-marineStatusPointer->my_spot.vz; + /* Fix for midair start points, grrrr. */ + offset.vy>>=2; + + /* Find distance off spot. */ + dist=Approximate3dMagnitude(&offset); + + if ((distcontainingModule->m_aimodule==marineStatusPointer->missionmodule)) { + + /* On the spot. */ + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + HandleWaitingAnimations(sbPtr); + + correctlyOrientated=0; + + if(MarineIsAwareOfTarget(sbPtr)) { + + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + } else if (marineStatusPointer->suspicious) { + /* Orientate to suspect point? */ + orientationDirn.vx = marineStatusPointer->suspect_point.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->suspect_point.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + if (correctlyOrientated) { + /* Please don't be staring at a wall... */ + SECTION_DATA *head_sec; + VECTORCH sight_vec; + + head_sec=GetThisSectionData(marineStatusPointer->HModelController.section_data,"head"); + GLOBALASSERT(head_sec); + + sight_vec.vx=sbPtr->DynPtr->OrientMat.mat31; + sight_vec.vy=sbPtr->DynPtr->OrientMat.mat32; + sight_vec.vz=sbPtr->DynPtr->OrientMat.mat33; + + FindPolygonInLineOfSight(&sight_vec,&head_sec->World_Offset,0,sbPtr->SBdptr); + if (LOS_ObjectHitPtr) { + if (SBIsEnvironment(LOS_ObjectHitPtr->ObStrategyBlock)) { + if (LOS_Lambda<2000) { + Marine_MirrorSuspectPoint(sbPtr); + } + } + } + } + marineStatusPointer->gotapoint=0; + } else { + if (marineStatusPointer->gotapoint) { + VECTORCH orientationDirn; + int correctlyOrientated; + + orientationDirn.vx = marineStatusPointer->wanderData.worldPosition.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->wanderData.worldPosition.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + } else { + GetPointToFaceMarineTowards(sbPtr,&marineStatusPointer->wanderData.worldPosition); + } + } + + if(!correctlyOrientated) { + + return(SRC_No_Change); + + } + + if (marineStatusPointer->Target==NULL) { + /* Must be suspicious? */ + if (marineStatusPointer->suspicious) { + return(SRC_No_Change); + } + /* Else drop through? */ + } else { + /* We have a target, and should be correctly orientated. */ + + if (MarineCanSeeTarget(sbPtr)) { + /* I can see! */ + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + if ((marineStatusPointer->My_Weapon->MaxRange==-1) || + (rangeMy_Weapon->MaxRange)) { + + return(SRC_Request_Fire); + + } + } else { + /* Eh? */ + if (marineStatusPointer->suspicious) { + return(SRC_No_Change); + } + } + } + + /* Well, we're stuck with sentrymode. */ + if (marineStatusPointer->gotapoint) { + + VECTORCH orientationDirn; + int correctlyOrientated; + + orientationDirn.vx = marineStatusPointer->wanderData.worldPosition.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->wanderData.worldPosition.vz - sbPtr->DynPtr->Position.vz; + + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + } else { + GetPointToFaceMarineTowards(sbPtr,&marineStatusPointer->wanderData.worldPosition); + } + + return(SRC_No_Change); + + } + + /* If you got here, you're lost. */ + + if (marineStatusPointer->missionmodule==NULL) { + /* Fused! */ + return(SRC_No_Change); + } + + HandleMovingAnimations(sbPtr); + + if (sbPtr->containingModule->m_aimodule!=marineStatusPointer->missionmodule) { + + AIMODULE *targetModule; + /* Not even in the same module! */ + + if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_InitMovementData(&(marineStatusPointer->moveData)); + } + if ((marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + ||(marineStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_aimodule->m_index)) { + + targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,marineStatusPointer->missionmodule,7,0); + + if (targetModule) { + FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule); + if(thisEp) { + /* aha. an ep!... */ + VECTORCH thisEpWorld = thisEp->position; + + thisEpWorld.vx += targetModule->m_world.vx; + thisEpWorld.vy += targetModule->m_world.vy; + thisEpWorld.vz += targetModule->m_world.vz; + + marineStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index; + marineStatusPointer->wanderData.worldPosition = thisEpWorld; + + GLOBALASSERT(thisEp->alien_only==0); + /* If that fired, GetNextModuleForLink went wrong. */ + + } else { + /* Failure case. */ + marineStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE; + } + + } else { + /* Another failure case. */ + marineStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE; + } + } + + /* if we still haven't got one, bimble about in this one for a bit. */ + if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_InitMovementData(&(marineStatusPointer->moveData)); + marineStatusPointer->moveData.lastModule=marineStatusPointer->lastmodule; + NPC_FindAIWanderTarget(sbPtr,&(marineStatusPointer->wanderData),&(marineStatusPointer->moveData),0); + } + + if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) { + /* STILL broken! We're in a lot of trouble. */ + return(SRC_No_Change); + } + + /* Should have a legal target. */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager); + + } else { + /* Same module, wrong place. Just go for it. */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->my_spot),&marineStatusPointer->waypointManager); + + } + + NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE + { + if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(SRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject); + if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter)) + { + /* go to avoidance */ + return(SRC_Request_Avoidance); + } + if(marineStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &(marineStatusPointer->wanderData.worldPosition), &velocityDirection)) + { + /* go to avoidance */ + /* no sequence change required */ + + marineStatusPointer->obstruction.environment=1; + marineStatusPointer->obstruction.destructableObject=0; + marineStatusPointer->obstruction.otherCharacter=0; + marineStatusPointer->obstruction.anySingleObstruction=0; + + return(SRC_Request_Avoidance); + } + #endif + + return(SRC_No_Change); + + +} + +static STATE_RETURN_CONDITION Execute_MNS_Wait(STRATEGYBLOCK *sbPtr) +{ + /* wait until near state timer runs out, then wander: + alternatively, if we can attack the target, go straight to approach */ + MARINE_STATUS_BLOCK *marineStatusPointer; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(marineStatusPointer); + LOCALASSERT(dynPtr); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* test for attack */ + if (MarineIsAwareOfTarget(sbPtr)) + { + if ((FastRandom()&65535)<32767) { + return(SRC_Request_Approach); + } else { + return(SRC_Request_Fire); + } + } + + if (marineStatusPointer->suspicious) { + int range; + + #if 0 + range=VectorDistance(&marineStatusPointer->suspect_point,(&sbPtr->DynPtr->Position)); + #else + VECTORCH targetPosition; + + targetPosition=marineStatusPointer->suspect_point; + + targetPosition.vx-=sbPtr->DynPtr->Position.vx; + targetPosition.vy-=sbPtr->DynPtr->Position.vy; + targetPosition.vz-=sbPtr->DynPtr->Position.vz; + + /* Let's try doing this. */ + targetPosition.vy>>=2; + + range=Approximate3dMagnitude(&targetPosition); + #endif + + if (range>SUSPECT_SENSITIVITY) { + /* Too far away! */ + marineStatusPointer->suspicious=MARINE_PARANOIA_TIME; + /* Used to unset suspicion at that point. */ + return(SRC_Request_Approach); + } else { + /* We could at least turn to face it. */ + VECTORCH orientationDirn; + int correctlyOrientated; + + orientationDirn.vx = marineStatusPointer->suspect_point.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->suspect_point.vz - sbPtr->DynPtr->Position.vz; + + if (sbPtr->SBDamageBlock.IsOnFire) { + /* Can't handle 'suspect points' stuck to them! */ + correctlyOrientated = 1; + } else { + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + } + + /* For when suspicion times out. */ + marineStatusPointer->gotapoint=0; + + if (correctlyOrientated) { + /* Please don't be staring at a wall... */ + SECTION_DATA *head_sec; + VECTORCH sight_vec; + + head_sec=GetThisSectionData(marineStatusPointer->HModelController.section_data,"head"); + GLOBALASSERT(head_sec); + + sight_vec.vx=sbPtr->DynPtr->OrientMat.mat31; + sight_vec.vy=sbPtr->DynPtr->OrientMat.mat32; + sight_vec.vz=sbPtr->DynPtr->OrientMat.mat33; + + FindPolygonInLineOfSight(&sight_vec,&head_sec->World_Offset,0,sbPtr->SBdptr); + if (LOS_ObjectHitPtr) { + if (SBIsEnvironment(LOS_ObjectHitPtr->ObStrategyBlock)) { + if (LOS_Lambda<2000) { + Marine_MirrorSuspectPoint(sbPtr); + } + } + } + } + + } + + } + + /* Think Sequences. */ + + HandleWaitingAnimations(sbPtr); + + if ((NpcSquad.alertZone)&&(marineStatusPointer->Mission!=MM_LocalGuard) + &&(marineStatusPointer->Mission!=MM_NonCom)) { + /* Are we already there? */ + if (sbPtr->containingModule->m_aimodule!=NpcSquad.alertZone) { + if (NpcSquad.responseLevel>0) { + /* Picked up a target. Can we move to respond? */ + AIMODULE *targetModule=0; + targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr); + if (targetModule) { + return(SRC_Request_Respond); + } + } + } + } + + /* still waiting: decrement timer */ + marineStatusPointer->stateTimer-=NormalFrameTime; + + if(marineStatusPointer->stateTimer<=0) + { + + /* Might want to wander. */ + + if ((FastRandom()&65535)<2048) + { + /* we should be wandering... we're bored of waiting. */ + return(SRC_Request_Wander); + } + + /* No, I'm happy waiting. */ + marineStatusPointer->stateTimer=MARINE_NEARWAITTIME; + return(SRC_No_Change); + } + + /* Well, we're stuck with waiting. */ + + if (marineStatusPointer->suspicious) { + /* Stay facing the suspect point. */ + return(SRC_No_Change); + } + + if (marineStatusPointer->gotapoint) { + + VECTORCH orientationDirn; + int correctlyOrientated; + + orientationDirn.vx = marineStatusPointer->wanderData.worldPosition.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->wanderData.worldPosition.vz - sbPtr->DynPtr->Position.vz; + + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + } else { + GetPointToFaceMarineTowards(sbPtr,&marineStatusPointer->wanderData.worldPosition); + } + + return(SRC_No_Change); +} + +/*----------------------- Patrick 16/6/97 ------------------------ + Special state for dying: + NB once we have entered this state, we are locked into it until + we are dead. + ----------------------------------------------------------------*/ +static void Execute_Dying(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + #if 0 + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + sbPtr->DynPtr->LinImpulse.vx = 0; + sbPtr->DynPtr->LinImpulse.vy = 0; + sbPtr->DynPtr->LinImpulse.vz = 0; + #endif + + { + DISPLAYBLOCK *dispPtr = sbPtr->SBdptr; + /* do we have a displayblock? */ + if (dispPtr) + { + dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND; + dispPtr->ObFlags2 = marineStatusPointer->stateTimer/2; + + } + } + + marineStatusPointer->stateTimer -= NormalFrameTime; + + #if 0 + if ( (sbPtr->DynPtr->Position.vx=sbPtr->DynPtr->PrevPosition.vx) + || (sbPtr->DynPtr->Position.vx=sbPtr->DynPtr->PrevPosition.vy) + || (sbPtr->DynPtr->Position.vx=sbPtr->DynPtr->PrevPosition.vz)) { + + /* Now, turn off collisions? */ + if(sbPtr->DynPtr) + { + sbPtr->DynPtr->IsStatic = 1; + sbPtr->DynPtr->DynamicsType = DYN_TYPE_NO_COLLISIONS; + sbPtr->DynPtr->GravityOn = 0; + } + + } + #endif + + + /* Did marine die with the trigger held down? */ + if (marineStatusPointer->lastroundhit==-2) { + /* Is there a gunflash? */ + if(marineStatusPointer->My_Gunflash_Section) { + /* But is it still attached? */ + if (marineStatusPointer->My_Gunflash_Section->my_controller==&(marineStatusPointer->HModelController)) { + /* Keep firing! */ + LOCALASSERT(marineStatusPointer->My_Weapon->WeaponMisfireFunction); + /* Shouldn't be doing this without knowing why. */ + (*marineStatusPointer->My_Weapon->WeaponMisfireFunction)(marineStatusPointer->My_Gunflash_Section,&marineStatusPointer->weapon_variable); + } + } + } + + /* Do we want to trim off the weapons? */ + + if (marineStatusPointer->HModelController.keyframe_flags) { + SECTION *root; + + root=GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,marineStatusPointer->My_Weapon->TemplateName); + + TrimToTemplate(sbPtr,&marineStatusPointer->HModelController, + root, 1); + } + +} + +static void MarineFireFlameThrower(STRATEGYBLOCK *sbPtr) { + + VECTORCH null_vec; + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + null_vec.vx=0; + null_vec.vy=0; + null_vec.vz=0; + + GLOBALASSERT(marineStatusPointer->My_Gunflash_Section); + + FireFlameThrower(&marineStatusPointer->My_Gunflash_Section->World_Offset,&null_vec, + &marineStatusPointer->My_Gunflash_Section->SecMat,0,&marineStatusPointer->weapon_variable); + +} + +void MarineMisfireFlameThrower(SECTION_DATA *muzzle, int *timer) { + + VECTORCH null_vec; + + null_vec.vx=0; + null_vec.vy=0; + null_vec.vz=0; + + FireFlameThrower(&muzzle->World_Offset,&null_vec,&muzzle->SecMat,0,timer); + +} + +/*----------------------- Patrick 18/4/97 ------------------------ + Support for gunflash objects. These are for use by AI marines + and also network ghosted players + ----------------------------------------------------------------*/ + +/* this function is specifically for marines, and creates a gun flash +pointing in the direction of the target point */ +static void CreateMarineGunFlash(STRATEGYBLOCK *sbPtr) +{ + VECTORCH firingDirn,firingPoint; + MARINE_STATUS_BLOCK *marineStatusPointer; + int firingOffsetUp,firingOffsetInfront,firingOffsetAcross; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* get the firing point offsets:*/ + if(marineStatusPointer->IAmCrouched) + { + firingOffsetUp = MARINE_FIRINGPOINT_UP; + firingOffsetInfront = MARINE_FIRINGPOINT_INFRONT; + firingOffsetAcross = MARINE_FIRINGPOINT_ACROSS; + } + else + { + firingOffsetUp = MARINE_FIRINGPOINT_UP_CROUCHED; + firingOffsetInfront = MARINE_FIRINGPOINT_INFRONT_CROUCHED; + firingOffsetAcross = MARINE_FIRINGPOINT_ACROSS_CROUCHED; + } + + /* find the firing direction */ + firingDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + firingDirn.vy = marineStatusPointer->weaponTarget.vy - sbPtr->DynPtr->Position.vy; + firingDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + Normalise(&firingDirn); + { + VECTORCH yNormal = {0,-65536,0}; + VECTORCH tempDirn; + VECTORCH acrossDirn; + + /* now find firing point (conceptually, the end of the weapon muzzle)... */ + firingPoint = sbPtr->DynPtr->Position; + firingPoint.vx += MUL_FIXED(firingDirn.vx,firingOffsetInfront); + firingPoint.vz += MUL_FIXED(firingDirn.vz,firingOffsetInfront); + + tempDirn = firingDirn; + tempDirn.vy = 0; + Normalise(&tempDirn); + CrossProduct(&tempDirn,&yNormal,&acrossDirn); + Normalise(&acrossDirn); + firingPoint.vx += MUL_FIXED(tempDirn.vx,firingOffsetAcross); + firingPoint.vz += MUL_FIXED(tempDirn.vz,firingOffsetAcross); + firingPoint.vy += MUL_FIXED(yNormal.vy,firingOffsetUp); + } + + + LOCALASSERT(marineStatusPointer->myGunFlash==NULL); + GLOBALASSERT(marineStatusPointer->My_Gunflash_Section); + marineStatusPointer->myGunFlash = AddNPCGunFlashEffect + ( + &marineStatusPointer->My_Gunflash_Section->World_Offset, + &marineStatusPointer->My_Gunflash_Section->SecMat, + marineStatusPointer->My_Weapon->SfxID + ); +} + +/* Add a gun flash at the given position & orientation */ +DISPLAYBLOCK* AddNPCGunFlashEffect(VECTORCH *position, MATRIXCH* orientation, enum SFX_ID sfxID) +{ + DISPLAYBLOCK *dPtr; + + dPtr = CreateSFXObject(sfxID); + + if(dPtr) + { + dPtr->ObMyModule = NULL; + dPtr->ObWorld = *position; + dPtr->ObMat = *orientation; + //CreateEulerMatrix(orientation, &dPtr->ObMat); + //TransposeMatrixCH(&dPtr->ObMat); + AddLightingEffectToObject(dPtr,LFX_MUZZLEFLASH); + GLOBALASSERT(dPtr->SfxPtr); + dPtr->SfxPtr->EffectDrawnLastFrame=0; + } + return dPtr; +} + +/* Remove the gunflash */ +void RemoveNPCGunFlashEffect(DISPLAYBLOCK* dPtr) +{ + DestroyActiveObject(dPtr); +} + +/* Update the gunflash effect given a new position and orientation */ +void MaintainNPCGunFlashEffect(DISPLAYBLOCK* dPtr, VECTORCH *position, MATRIXCH* orientation) +{ + dPtr->ObWorld = *position; + dPtr->ObMat = *orientation; + + /* oh, oh, and re-add the lighting effect */ + AddLightingEffectToObject(dPtr,LFX_MUZZLEFLASH); +} + + + +/* Patrick: 2/7/97 -------------------------------------------------------- + Some marine support functions + -------------------------------------------------------------------------*/ +static void SetMarineAnimationSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweening) +{ + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + GLOBALASSERT(length!=0); + + if (tweening<=0) { + InitHModelSequence(&marineStatusPointer->HModelController,(int)type,subtype,length); + } else { + InitHModelTweening(&marineStatusPointer->HModelController, tweening, (int)type,subtype,length, 1); + } + + ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr); +} + +static void SetMarineAnimationSequence_Null(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweening) { + /* Ha! */ + #if (NEW_ANIM_SYSTEM==0) + SetMarineAnimationSequence(sbPtr,type,subtype,length,tweening); + #endif + +} + +static int MarineCanSeeTarget(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + int targetIsCloaked,targetTaunted; + VECTORCH offset; + int dist; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Target==NULL) { + /* You can't see nothin. */ + return(0); + } + + targetIsCloaked=0; + targetTaunted=0; + + if (marineStatusPointer->Target==Player->ObStrategyBlock) { + /* test for player being cloaked */ + LOCALASSERT(playerStatusPtr); + if (AvP.PlayerType==I_Predator) { + + if((playerStatusPtr->cloakOn==1)&&(playerStatusPtr->cloakPositionGivenAway==0)) { + targetIsCloaked=1; + } + } + if (playerStatusPtr->tauntTimer) { + /* Idiot. */ + targetIsCloaked=0; + /* On the other hand, */ + targetTaunted=1; + } + + } else { + /* Test for NPC predators being cloaked, or aliens hiding? */ + if (marineStatusPointer->Target->I_SBtype==I_BehaviourPredator) { + PREDATOR_STATUS_BLOCK *predStatus=(PREDATOR_STATUS_BLOCK *)marineStatusPointer->Target->SBdataptr; + GLOBALASSERT(predStatus); + if (predStatus->CloakStatus==PCLOAK_On) { + targetIsCloaked=1; + } + } + } + + offset.vx=sbPtr->DynPtr->Position.vx-marineStatusPointer->Target->DynPtr->Position.vx; + offset.vy=sbPtr->DynPtr->Position.vy-marineStatusPointer->Target->DynPtr->Position.vy; + offset.vz=sbPtr->DynPtr->Position.vz-marineStatusPointer->Target->DynPtr->Position.vz; + dist=Approximate3dMagnitude(&offset); + + /* If a marine is suspicious, and the target is within 2m of the suspect_point... */ + if (marineStatusPointer->suspicious) { + /* Detect on the incidentFlag? */ + if (marineStatusPointer->incidentFlag) { + int dice,targetnum; + + dice=(FastRandom()&65535); + targetnum=(marineStatusPointer->Skill); + + targetnum=MakeModifiedTargetNum(targetnum,dist); + + if (marineStatusPointer->Target==Player->ObStrategyBlock) { + if (AvP.PlayerType==I_Predator) { + if (playerStatusPtr->cloakOn==1) { + dice=MUL_FIXED(dice,playerStatusPtr->CloakingEffectiveness); + } + } + } else if (marineStatusPointer->Target->I_SBtype==I_BehaviourPredator) { + PREDATOR_STATUS_BLOCK *predStatus=(PREDATOR_STATUS_BLOCK *)marineStatusPointer->Target->SBdataptr; + GLOBALASSERT(predStatus); + if (predStatus->CloakStatus==PCLOAK_On) { + dice=MUL_FIXED(dice,predStatus->CloakingEffectiveness); + } + } + + if (diceTarget==Player->ObStrategyBlock) { + /* Alien test is now here, since it uses probability differently. */ + if (AvP.PlayerType==I_Alien) { + if (!AlienPCIsCurrentlyVisible(marineStatusPointer->incidentFlag,sbPtr)) { + if (playerStatusPtr->tauntTimer) { + /* Idiot. */ + targetIsCloaked=0; + /* Taunted flag should already be set. */ + } else { + targetIsCloaked=1; + } + } + } + } + + if (marineStatusPointer->sawlastframe) { + if (marineStatusPointer->incidentFlag) { + /* Chance of losing target. */ + VECTORCH offset; + int speed; + + offset.vx=marineStatusPointer->Target->DynPtr->Position.vx-marineStatusPointer->Target->DynPtr->PrevPosition.vx; + offset.vy=marineStatusPointer->Target->DynPtr->Position.vy-marineStatusPointer->Target->DynPtr->PrevPosition.vy; + offset.vz=marineStatusPointer->Target->DynPtr->Position.vz-marineStatusPointer->Target->DynPtr->PrevPosition.vz; + + /* ...compute speed factor... */ + speed=Magnitude(&offset); + speed=DIV_FIXED(speed,NormalFrameTime); + + if (speed>50) { + /* The faster you move, the more likely to be lost. */ + speed<<=1; + if ((FastRandom()&65535)>speed) { + /* Retain target! */ + targetIsCloaked=0; + } + } else { + /* Can't lose them if they're still. */ + targetIsCloaked=0; + } + } else { + targetIsCloaked=0; + } + } + + if (marineStatusPointer->Target->SBDamageBlock.IsOnFire) { + /* Oh come ON. */ + targetIsCloaked=0; + } + + if(!(NPCCanSeeTarget(sbPtr,marineStatusPointer->Target, MARINE_NEAR_VIEW_WIDTH))) { + if (marineStatusPointer->sawlastframe) { + marineStatusPointer->sawlastframe=2; + /* I'm suspicious now. */ + marineStatusPointer->suspicious=MARINE_PARANOIA_TIME; + marineStatusPointer->suspect_point=marineStatusPointer->Target->DynPtr->Position; + /* And unset previous_suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + } + return(0); + } + + if (targetIsCloaked) { + return(0); + } + marineStatusPointer->sawlastframe=1; + + if ((targetTaunted)&&(marineStatusPointer->Target)&&(marineStatusPointer->Android==0)) { + + if (dist<16834) { + dist=16384-dist; + dist<<=2; + marineStatusPointer->Courage-=MUL_FIXED((NormalFrameTime<<1),dist); + } + } + return(1); +} + +static int MarineCanSeeObject(STRATEGYBLOCK *sbPtr,STRATEGYBLOCK *target) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + int targetIsCloaked, targetTaunted, targetWasCloaked; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + VECTORCH offset; + int dist; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (target==NULL) { + /* You can't see nothin. */ + return(0); + } + + targetIsCloaked=0; + targetTaunted=0; + targetWasCloaked=0; + + if (target==Player->ObStrategyBlock) { + /* test for player being cloaked */ + LOCALASSERT(playerStatusPtr); + if (AvP.PlayerType==I_Predator) { + + if((playerStatusPtr->cloakOn==1)&&(playerStatusPtr->cloakPositionGivenAway==0)) { + targetIsCloaked=1; + targetWasCloaked=1; + } + } + if (playerStatusPtr->tauntTimer) { + /* Idiot. */ + targetIsCloaked=0; + /* On the other hand, */ + targetTaunted=1; + } + + } else { + /* Test for NPC predators being cloaked, or aliens hiding? */ + if (target->I_SBtype==I_BehaviourPredator) { + PREDATOR_STATUS_BLOCK *predStatus=(PREDATOR_STATUS_BLOCK *)target->SBdataptr; + GLOBALASSERT(predStatus); + if (predStatus->CloakStatus==PCLOAK_On) { + targetIsCloaked=1; + targetWasCloaked=1; + } + } + } + + offset.vx=sbPtr->DynPtr->Position.vx-target->DynPtr->Position.vx; + offset.vy=sbPtr->DynPtr->Position.vy-target->DynPtr->Position.vy; + offset.vz=sbPtr->DynPtr->Position.vz-target->DynPtr->Position.vz; + dist=Approximate3dMagnitude(&offset); + + /* If a marine is suspicious, and the target is within 2m of the suspect_point... */ + if (marineStatusPointer->suspicious) { + /* Detect on the incidentFlag? */ + if (marineStatusPointer->incidentFlag) { + int dice,targetnum; + + dice=(FastRandom()&65535); + targetnum=(marineStatusPointer->Skill); + + targetnum=MakeModifiedTargetNum(targetnum,dist); + + if (target==Player->ObStrategyBlock) { + if (AvP.PlayerType==I_Predator) { + if (playerStatusPtr->cloakOn==1) { + dice=MUL_FIXED(dice,playerStatusPtr->CloakingEffectiveness); + } + } + } else if (target->I_SBtype==I_BehaviourPredator) { + PREDATOR_STATUS_BLOCK *predStatus=(PREDATOR_STATUS_BLOCK *)target->SBdataptr; + GLOBALASSERT(predStatus); + if (predStatus->CloakStatus==PCLOAK_On) { + dice=MUL_FIXED(dice,predStatus->CloakingEffectiveness); + } + } + + if (diceObStrategyBlock) { + /* Alien test is now here, since it uses probability differently. */ + if (AvP.PlayerType==I_Alien) { + if (!AlienPCIsCurrentlyVisible(marineStatusPointer->incidentFlag,sbPtr)) { + if (playerStatusPtr->tauntTimer) { + /* Idiot. */ + targetIsCloaked=0; + /* Taunted flag should already be set. */ + } else { + targetIsCloaked=1; + targetWasCloaked=1; + } + } + } + } + + if (marineStatusPointer->sawlastframe) { + if (marineStatusPointer->incidentFlag) { + /* Chance of losing target. */ + VECTORCH offset; + int speed; + + offset.vx=target->DynPtr->Position.vx-target->DynPtr->PrevPosition.vx; + offset.vy=target->DynPtr->Position.vy-target->DynPtr->PrevPosition.vy; + offset.vz=target->DynPtr->Position.vz-target->DynPtr->PrevPosition.vz; + + /* ...compute speed factor... */ + speed=Magnitude(&offset); + speed=DIV_FIXED(speed,NormalFrameTime); + + if (speed>50) { + /* The faster you move, the more likely to be lost. */ + speed<<=1; + if ((FastRandom()&65535)>speed) { + /* Retain target! */ + targetIsCloaked=0; + } + } else { + /* Can't lose them if they're still. */ + targetIsCloaked=0; + } + } else { + targetIsCloaked=0; + } + } + + if (target->SBDamageBlock.IsOnFire) { + /* Oh come ON. */ + targetIsCloaked=0; + } + + /* NO saw last frame usage! */ + + if (targetIsCloaked) { + return(0); + } + + if(!(NPCCanSeeTarget(sbPtr,target, MARINE_NEAR_VIEW_WIDTH))) { + return(0); + } + + if ((targetWasCloaked)&&(marineStatusPointer->Target==NULL)) { + /* Exhibit suprise? */ + if ((FastRandom()&65535)<16384) { + Marine_SurpriseSound(sbPtr); + } + } + + if ((targetTaunted)&&(marineStatusPointer->Target)&&(marineStatusPointer->Android==0)) { + /* It must be the player. */ + if (dist<16834) { + dist=16384-dist; + dist<<=2; + marineStatusPointer->Courage-=MUL_FIXED((NormalFrameTime<<1),dist); + } + } + return(1); +} + +void WarnMarineOfAttack(STRATEGYBLOCK *marine,STRATEGYBLOCK *attacker) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + GLOBALASSERT(marine); + + GLOBALASSERT(marine->I_SBtype==I_BehaviourMarine); + + marineStatusPointer = (MARINE_STATUS_BLOCK *)(marine->SBdataptr); + GLOBALASSERT(marineStatusPointer); + + GLOBALASSERT(attacker); + + /* Test? */ + + if(MarineCanSeeObject(marine,attacker)) { + + /* Remember your suspicion! */ + marineStatusPointer->previous_suspicion=marineStatusPointer->suspicious; + marineStatusPointer->suspicious=1; /* It's right there! */ + marineStatusPointer->Target=attacker; + + COPY_NAME(marineStatusPointer->Target_SBname,marineStatusPointer->Target->SBname); + + PointAlert(2,&attacker->DynPtr->Position); + } + +} + +static int MarineIsAwareOfTarget(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + int targetIsCloaked; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + VECTORCH offset; + int dist; + + /* Like MarineCanSeeTarget, but the 'Far' version: should it hunt? */ + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Target!=NULL) { + + /* Okay, let's try this sense malarky. */ + + /* Motion tracker, only when scanning. */ + + if (marineStatusPointer->mtracker_timer==0) { + if (marineStatusPointer->Target->DynPtr) { + DYNAMICSBLOCK *tDynPtr; + MATRIXCH WtoL; + VECTORCH offset; + /* Arc reject. */ + + tDynPtr=marineStatusPointer->Target->DynPtr; + + offset.vx=sbPtr->DynPtr->Position.vx-marineStatusPointer->Target->DynPtr->Position.vx; + offset.vy=sbPtr->DynPtr->Position.vy-marineStatusPointer->Target->DynPtr->Position.vy; + offset.vz=sbPtr->DynPtr->Position.vz-marineStatusPointer->Target->DynPtr->Position.vz; + + WtoL=sbPtr->DynPtr->OrientMat; + TransposeMatrixCH(&WtoL); + RotateVector(&offset,&WtoL); + + if (offset.vz<=0) { + #if 0 + if ( + (tDynPtr->Position.vx!=tDynPtr->PrevPosition.vx) + ||(tDynPtr->Position.vx!=tDynPtr->PrevPosition.vx) + ||(tDynPtr->Position.vx!=tDynPtr->PrevPosition.vx) + ) { + #else + if (ObjectShouldAppearOnMotionTracker(marineStatusPointer->Target)) { + #endif + int range; + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + if (range<=MOTIONTRACKER_RANGE) { + marineStatusPointer->suspicious=MARINE_PARANOIA_TIME; /* It might be there. */ + marineStatusPointer->suspect_point=marineStatusPointer->Target->DynPtr->Position; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + tracker_noise=2; /* Wheep! */ + return(1); + } + } + } + } + } + + /* So, there's nothing on the scanner. */ + + targetIsCloaked=0; + + /* Far visibility. */ + + if (marineStatusPointer->Target==Player->ObStrategyBlock) { + /* test for player being cloaked */ + LOCALASSERT(playerStatusPtr); + if (AvP.PlayerType==I_Predator) { + + if((playerStatusPtr->cloakOn==1)&&(playerStatusPtr->cloakPositionGivenAway==0)) { + targetIsCloaked=1; + } + } + if (playerStatusPtr->tauntTimer) { + /* Idiot. */ + targetIsCloaked=0; + } + + } else { + /* Test for NPC predators being cloaked, or aliens hiding? */ + if (marineStatusPointer->Target->I_SBtype==I_BehaviourPredator) { + PREDATOR_STATUS_BLOCK *predStatus=(PREDATOR_STATUS_BLOCK *)marineStatusPointer->Target->SBdataptr; + GLOBALASSERT(predStatus); + if (predStatus->CloakStatus==PCLOAK_On) { + targetIsCloaked=1; + } + } + } + + offset.vx=sbPtr->DynPtr->Position.vx-marineStatusPointer->Target->DynPtr->Position.vx; + offset.vy=sbPtr->DynPtr->Position.vy-marineStatusPointer->Target->DynPtr->Position.vy; + offset.vz=sbPtr->DynPtr->Position.vz-marineStatusPointer->Target->DynPtr->Position.vz; + dist=Approximate3dMagnitude(&offset); + + /* If a marine is suspicious, and the target is within 2m of the suspect_point... */ + if (marineStatusPointer->suspicious) { + /* Detect on the incidentFlag? */ + if (marineStatusPointer->incidentFlag) { + int dice,targetnum; + + dice=(FastRandom()&65535); + targetnum=(marineStatusPointer->Skill); + + targetnum=MakeModifiedTargetNum(targetnum,dist); + + if (marineStatusPointer->Target==Player->ObStrategyBlock) { + if (AvP.PlayerType==I_Predator) { + if (playerStatusPtr->cloakOn==1) { + dice=MUL_FIXED(dice,playerStatusPtr->CloakingEffectiveness); + } + } + } else if (marineStatusPointer->Target->I_SBtype==I_BehaviourPredator) { + PREDATOR_STATUS_BLOCK *predStatus=(PREDATOR_STATUS_BLOCK *)marineStatusPointer->Target->SBdataptr; + GLOBALASSERT(predStatus); + if (predStatus->CloakStatus==PCLOAK_On) { + dice=MUL_FIXED(dice,predStatus->CloakingEffectiveness); + } + } + + if (diceTarget==Player->ObStrategyBlock) { + /* Alien test is now here, since it uses probability differently. */ + if (AvP.PlayerType==I_Alien) { + if (!AlienPCIsCurrentlyVisible(marineStatusPointer->incidentFlag,sbPtr)) { + if (playerStatusPtr->tauntTimer) { + /* Idiot. */ + targetIsCloaked=0; + } else { + targetIsCloaked=1; + } + } + } + } + + if (marineStatusPointer->sawlastframe) { + if (marineStatusPointer->incidentFlag) { + /* Chance of losing target. */ + VECTORCH offset; + int speed; + + offset.vx=marineStatusPointer->Target->DynPtr->Position.vx-marineStatusPointer->Target->DynPtr->PrevPosition.vx; + offset.vy=marineStatusPointer->Target->DynPtr->Position.vy-marineStatusPointer->Target->DynPtr->PrevPosition.vy; + offset.vz=marineStatusPointer->Target->DynPtr->Position.vz-marineStatusPointer->Target->DynPtr->PrevPosition.vz; + + /* ...compute speed factor... */ + speed=Magnitude(&offset); + speed=DIV_FIXED(speed,NormalFrameTime); + + if (speed>50) { + /* The faster you move, the more likely to be lost. */ + speed<<=1; + if ((FastRandom()&65535)>speed) { + /* Retain target! */ + targetIsCloaked=0; + } + } else { + /* Can't lose them if they're still. */ + targetIsCloaked=0; + } + } else { + targetIsCloaked=0; + } + } + + if (marineStatusPointer->Target->SBDamageBlock.IsOnFire) { + /* Oh come ON. */ + targetIsCloaked=0; + } + + if (targetIsCloaked==0) { + if (!sbPtr->SBdptr) { + if (marineStatusPointer->Target->containingModule) { + if (IsModuleVisibleFromModule(marineStatusPointer->Target->containingModule,sbPtr->containingModule)) { + /* Remember your suspicion! */ + marineStatusPointer->previous_suspicion=marineStatusPointer->suspicious; + /* Seen, unset suspicion. */ + marineStatusPointer->suspicious=1; + return(1); + } + } + } else { + if (MarineCanSeeTarget(sbPtr)) { + /* Remember your suspicion! */ + marineStatusPointer->previous_suspicion=marineStatusPointer->suspicious; + /* Near visibility - seen target, unset suspicion. */ + marineStatusPointer->suspicious=1; + return(1); + } + } + } + } + + /* Lastly, is there something we want to investigate? */ + + if (marineStatusPointer->suspicious) { + if (!sbPtr->SBdptr) { + MODULE *targetModule; + /* Far case. */ + targetModule=ModuleFromPosition(&marineStatusPointer->suspect_point,sbPtr->containingModule); + /* Target isn't guaranteed, is it? */ + if (targetModule) { + if (IsModuleVisibleFromModule(targetModule,sbPtr->containingModule)) { + /* Seen the point, unset suspicion? Maybe not. */ + #if 0 + /* Remember your suspicion! */ + marineStatusPointer->previous_suspicion=marineStatusPointer->suspicious; + marineStatusPointer->suspicious=1; + /* Just let it time out instead. */ + #endif + /* Shouldn't have a target now. */ + marineStatusPointer->Target=NULL; + return(0); + /* If there was something there, we should have picked it up by now. */ + } + } + /* Still suspicious. */ + } else { + /* Near case. */ + VECTORCH offset; + MATRIXCH WtoL; + /* Arc reject. */ + + offset.vx=sbPtr->DynPtr->Position.vx-marineStatusPointer->suspect_point.vx; + offset.vy=sbPtr->DynPtr->Position.vy-marineStatusPointer->suspect_point.vy; + offset.vz=sbPtr->DynPtr->Position.vz-marineStatusPointer->suspect_point.vz; + + WtoL=sbPtr->DynPtr->OrientMat; + TransposeMatrixCH(&WtoL); + RotateVector(&offset,&WtoL); + /* Do reject. */ + if (MarineSight_FrustrumReject(sbPtr,&offset,NULL)) { + if (IsThisObjectVisibleFromThisPosition(sbPtr->SBdptr,&marineStatusPointer->suspect_point,NPC_MAX_VIEWRANGE)) { + /* I know what you're going to say. That's backwards. */ + #if 0 + /* Remember your suspicion! */ + marineStatusPointer->previous_suspicion=marineStatusPointer->suspicious; + marineStatusPointer->suspicious=1; /* Flag for unsetting nicely. */ + /* Now, let's try just timing it out. */ + #endif + /* By this point I would have thought there's no valid target. */ + marineStatusPointer->Target=NULL; + return(0); + /* Well, show me 'IsThisPositionVisibleFromThisObject' and I'll be happy to change it. */ + } + } + } + } + + return(0); +} + +static int MarineShouldBeCrawling(STRATEGYBLOCK *sbPtr) +{ + if(sbPtr->containingModule->m_flags & MODULEFLAG_AIRDUCT) return 1; + return 0; +} + +static STATE_RETURN_CONDITION Execute_MNS_DischargeFlamethrower(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn; + int correctlyOrientated; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->HModelController.Playing=1; + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* look after the gun flash */ + if(marineStatusPointer->myGunFlash) { + /* No gunflash, neither. */ + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + } + + /* first of all, validate this state: if the target suddenly becomes cloaked, then + we should switch immediately to wait state*/ + if(!MarineCanSeeTarget(sbPtr)) + { + + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_Request_Wait); + } + + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + /* Fix weapon target! */ + if (marineStatusPointer->My_Weapon->TargetCallibrationShift) { + marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + } + + /* Here we must have a target. Renew suspicion for new arrivals. */ + if (NpcSquad.Squad_Suspicion==0) { + PointAlert(2,&marineStatusPointer->weaponTarget); + } + + /* Are we out of range? */ + { + int range; + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + if ((marineStatusPointer->My_Weapon->MaxRange!=-1) && + (range>=marineStatusPointer->My_Weapon->MaxRange)) { + + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_Request_Approach); + + } + } + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* I have a cunning plan... */ + { + DELTA_CONTROLLER *delta; + + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta"); + if (delta) { + if (!(DeltaAnimation_IsFinished(delta))) { + correctlyOrientated=0; + } + } + } + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing*/ + + if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) { + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + } + return(SRC_No_Change); + } + + if (marineStatusPointer->clipammo==0) { + return(SRC_Request_Reload); + } + + /* at this point we are correctly orientated: if we have no gunflash yet, + and our state timer is set to marine_near_firetime then we have either + just started firing, or have become dis-orienated between bursts. This is a good + time to consider firing a grenade... */ + + /* No grenades with FT. */ + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + else + { + /* SID_INCIN_LOOP? */ + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position)); + Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + + marineStatusPointer->stateTimer -= NormalFrameTime; + + MarineFireFlameThrower(sbPtr); + + /* Lighting? */ + if (sbPtr->SBdptr) { + AddLightingEffectToObject(sbPtr->SBdptr,LFX_MUZZLEFLASH); + } + + if (marineStatusPointer->clipammo>0) { + marineStatusPointer->clipammo-=NormalFrameTime; + if (marineStatusPointer->clipammo<0) { + marineStatusPointer->clipammo=0; + } + } + + if(marineStatusPointer->stateTimer > 0) return(SRC_No_Change); + + + { + /* we are far enough away, so return to approach */ + + /* ... and remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_Request_Approach); + } +} + +static void DischargeLOSWeapon_Core(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH relPos,relPos2; + int mod,hitroll,range,volleytime,volleyrounds; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Snipped from DischargeLOSWeapon. */ + + if (marineStatusPointer->Target) { + relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz); + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + } else { + /* Just a number. */ + range=10000; + } + + /* look after the gun flash */ + if(marineStatusPointer->myGunFlash) { + MaintainMarineGunFlash(sbPtr); + } else { + CreateMarineGunFlash(sbPtr); + } + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + else + { + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position)); + Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + + marineStatusPointer->stateTimer -= NormalFrameTime; + + /* Volleysize is now rounds fired this state. */ + + volleytime=marineStatusPointer->My_Weapon->FiringTime-marineStatusPointer->stateTimer; + /* It was that or reverse the state timer for this state. */ + volleyrounds=MUL_FIXED(volleytime,marineStatusPointer->My_Weapon->FiringRate); + volleyrounds>>=ONE_FIXED_SHIFT; + + volleyrounds-=marineStatusPointer->volleySize; + marineStatusPointer->volleySize+=volleyrounds; + + LOCALASSERT(volleyrounds>=0); + + if (marineStatusPointer->clipammo!=-1) { + /* We're counting ammo. */ + if (volleyrounds>marineStatusPointer->clipammo) { + volleyrounds=marineStatusPointer->clipammo; + } + marineStatusPointer->clipammo-=volleyrounds; + LOCALASSERT(marineStatusPointer->clipammo>=0); + } + + marineStatusPointer->roundsForThisTarget+=volleyrounds; + + /* Now hit the target with volleyrounds bullets. */ + + mod=SpeedRangeMods(&relPos,&relPos2); + + hitroll=marineStatusPointer->Skill; /* Marine skill... */ + if (marineStatusPointer->Target==Player->ObStrategyBlock) { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + if ( (AvP.PlayerType==I_Alien) + ||((AvP.PlayerType==I_Predator)&&(playerStatusPtr->cloakOn==1))) { + /* Vs the player, lighting effects on aliens and cloaked preds. */ + hitroll=MUL_FIXED(hitroll,((CurrentLightAtPlayer>>1)+32767)); + } + } + hitroll-=mod; + hitroll+=marineStatusPointer->My_Weapon->Accuracy; + + /* Here we go... */ + { + #define SUSTAINMOD (ONE_FIXED>>3) + int a,hits; + + hits=0; + + for (a=0; alastroundhit) { + realhitroll=hitroll+SUSTAINMOD; + } else { + realhitroll=hitroll; + } + + if (marineStatusPointer->Target) { + if (marineStatusPointer->lasthitsection) { + /* Verify this section is valid? */ + HMODELCONTROLLER *tctrl=NULL; + + if (marineStatusPointer->Target->SBdptr) { + tctrl=marineStatusPointer->Target->SBdptr->HModelControlBlock; + } + + if ((marineStatusPointer->lasthitsection->flags§ion_data_notreal) + || (marineStatusPointer->lasthitsection->flags§ion_data_terminate_here) + || ( (tctrl!=NULL)&&(tctrl!=marineStatusPointer->lasthitsection->my_controller)) ) { + /* Invalid. */ + marineStatusPointer->lasthitsection=NULL; + } + } + + if ( (marineStatusPointer->lastroundhit==0)||(marineStatusPointer->lasthitsection==NULL)) { + marineStatusPointer->lasthitsection=HitLocationRoll(marineStatusPointer->Target,sbPtr); + } + } + + if ((FastRandom()&65535)lastroundhit=1; + } else { + marineStatusPointer->lastroundhit=0; + } + + if (marineStatusPointer->Target==NULL) { + hits=0; + } + } + + /* Handle Damage. */ + { + VECTORCH attack_dir,rel_pos; + VECTORCH shotvector; + + shotvector.vx=0; + shotvector.vy=0; + shotvector.vz=65535; + RotateVector(&shotvector,&marineStatusPointer->My_Gunflash_Section->SecMat); + + /* DO DAMAGE TO TARGET HERE */ + #if MARINE_STATE_PRINT + textprint("Hits = %d\n",hits); + #endif + + if (hits!=0) { + + int range2; + + GLOBALASSERT(marineStatusPointer->Target); + + rel_pos.vx=marineStatusPointer->Target->DynPtr->Position.vx-sbPtr->DynPtr->Position.vx; + rel_pos.vy=marineStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy; + rel_pos.vz=marineStatusPointer->Target->DynPtr->Position.vz-sbPtr->DynPtr->Position.vz; + range2=Approximate3dMagnitude(&rel_pos); + + if (VerifyHitShot(sbPtr,marineStatusPointer->Target,&marineStatusPointer->My_Gunflash_Section->World_Offset,&shotvector, marineStatusPointer->My_Weapon->Ammo_Type, hits,range2)) { + /* If 0, hits have been dealt with. */ + GetDirectionOfAttack(marineStatusPointer->Target,&rel_pos,&attack_dir); + + if (marineStatusPointer->lasthitsection) { + CauseDamageToHModel(marineStatusPointer->lasthitsection->my_controller, marineStatusPointer->Target,&TemplateAmmo[marineStatusPointer->My_Weapon->Ammo_Type].MaxDamage[AvP.Difficulty], ONE_FIXED*hits, marineStatusPointer->lasthitsection,&attack_dir,NULL,0); + } else { + CauseDamageToObject(marineStatusPointer->Target,&TemplateAmmo[marineStatusPointer->My_Weapon->Ammo_Type].MaxDamage[AvP.Difficulty], ONE_FIXED*hits,&attack_dir); + } + } + + } + + if ((volleyrounds-hits)>0) { + GLOBALASSERT(marineStatusPointer->My_Gunflash_Section); + + if (marineStatusPointer->Target) { + ProjectNPCShot(sbPtr, marineStatusPointer->Target, &marineStatusPointer->My_Gunflash_Section->World_Offset,&marineStatusPointer->My_Gunflash_Section->SecMat, marineStatusPointer->My_Weapon->Ammo_Type, (volleyrounds-hits)); + } else { + /* Like a miss, so it's inaccurate. */ + CastLOSProjectile(sbPtr,&marineStatusPointer->My_Gunflash_Section->World_Offset,&shotvector, marineStatusPointer->My_Weapon->Ammo_Type, volleyrounds,1); + } + } + + } + + } + +} + +static STATE_RETURN_CONDITION Execute_MNS_DischargeLOSWeapon(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn,relPos,relPos2; + int correctlyOrientated,range; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->HModelController.Playing=1; + + #if MARINE_STATE_PRINT + textprint("Marine firing... "); + #endif + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* first of all, validate this state: if the target suddenly becomes cloaked, then + we should switch immediately to wait state*/ + if (marineStatusPointer->volleySizeMy_Weapon->MinimumBurstSize) { + /* Keep firing! */ + } else { + if(!MarineCanSeeTarget(sbPtr)) + { + #if 1 + EndMarineMuzzleFlash(sbPtr); + #else + /* ... and remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #endif + + #if MARINE_STATE_PRINT + textprint("Returning no target.\n"); + #endif + marineStatusPointer->lastroundhit=0; + marineStatusPointer->lasthitsection=NULL; + return(SRC_Request_Wait); + } + } + + if (marineStatusPointer->clipammo==0) { + /* Reload here. */ + EndMarineMuzzleFlash(sbPtr); + return(SRC_Request_Reload); + } + + + if (marineStatusPointer->Target) { + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + /* Fix weapon target! */ + if (marineStatusPointer->My_Weapon->TargetCallibrationShift) { + marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + } + + /* Here we must have a target. Renew suspicion for new arrivals. */ + if (NpcSquad.Squad_Suspicion==0) { + PointAlert(2,&marineStatusPointer->weaponTarget); + } + } + /* Otherwise, stay facing the same way. */ + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* I have a cunning plan... */ + { + DELTA_CONTROLLER *delta; + + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta"); + if (delta) { + if (!(DeltaAnimation_IsFinished(delta))) { + correctlyOrientated=0; + } + } + } + /* I have another cunning plan... */ + if ((marineStatusPointer->volleySize>0)&& + (marineStatusPointer->volleySizeMy_Weapon->MinimumBurstSize)) { + correctlyOrientated=1; + } + + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing*/ + if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) { + + /* stop visual and audio cues: technically, we're not firing at this moment */ + #if 1 + EndMarineMuzzleFlash(sbPtr); + #else + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #endif + + #if MARINE_STATE_PRINT + textprint("Turning to face.\n"); + #endif + marineStatusPointer->lastroundhit=0; + marineStatusPointer->lasthitsection=NULL; + return(SRC_No_Change); + } + + if (marineStatusPointer->Target) { + relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz); + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + } + + /* Test for grenading! */ + if ((marineStatusPointer->myGunFlash==NULL)&&(marineStatusPointer->stateTimer == MARINE_NEAR_FIRE_TIME) + &&(marineStatusPointer->Target)) + { + + /* NB don't fire grenades in air ducts */ + if ((FastRandom()&MARINE_CHANCEOFGRENADE) == 0) { + if (!(marineStatusPointer->IAmCrouched)) { + if (range > MARINE_TOO_CLOSE_TO_GRENADE_FOOL) { + if (marineStatusPointer->My_Weapon->EnableGrenades) { + + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + LobAGrenade(sbPtr); + marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING; + marineStatusPointer->volleySize = 0; + + + #if MARINE_STATE_PRINT + textprint("fired a grenade.\n"); + #endif + + return(SRC_Request_Approach); + } + } + } + } + } + + DischargeLOSWeapon_Core(sbPtr); + + if (marineStatusPointer->Target==NULL) { + /* Getting out of here! */ + return(SRC_No_Change); + } + + /* Did we get him? */ + if ((NPC_IsDead(marineStatusPointer->Target)) + &&(marineStatusPointer->volleySize>=marineStatusPointer->My_Weapon->MinimumBurstSize)) { + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + if (Marine_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr)==NULL) { + /* Huzzah! */ + #if 1 + EndMarineMuzzleFlash(sbPtr); + #else + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #endif + marineStatusPointer->lastroundhit=0; + marineStatusPointer->lasthitsection=NULL; + return(SRC_Request_Taunt); + } + } + } + + if(marineStatusPointer->stateTimer > 0) { + #if MARINE_STATE_PRINT + textprint("Returning continue at range %d.\n",range); + #endif + return(SRC_No_Change); + } + + if(range < MARINE_CLOSE_APPROACH_DISTANCE) + { + /* renew firing, as we are still too close to approach */ + marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime; + marineStatusPointer->volleySize = 0; + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + #if MARINE_STATE_PRINT + textprint("Returning too close renewal at range %d.\n",range); + #endif + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + #if 1 + EndMarineMuzzleFlash(sbPtr); + #else + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #endif + #endif + + if (marineStatusPointer->Android==0) { + marineStatusPointer->Courage-=(ONE_FIXED>>3); + } + return(SRC_Request_Fire); + } + else + { + /* we are far enough away, so return to approach */ + + #if 1 + /* ... and remove the gunflash */ + #if 1 + EndMarineMuzzleFlash(sbPtr); + #else + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #endif + #endif + + #if MARINE_STATE_PRINT + textprint("Returning too far termination at range %d.\n",range); + #endif + return(SRC_Request_Approach); + } + return(SRC_No_Change); +} + +int SpeedRangeMods(VECTORCH *range,VECTORCH *speed) { + + int dot,theta,sinthet,rmod; + int magrange,magspeed; + + /* Should return between 0 and ONE_FIXED... */ + + magrange=Approximate3dMagnitude(range); + rmod=magrange>>2; + + magspeed=Approximate3dMagnitude(speed); + dot=DotProduct(range,speed); + if (dot<0) dot=-dot; + { + int ab=MUL_FIXED(magrange,magspeed); + ab<<=1; + + if (ab==0) dot=0; else dot=DIV_FIXED(dot,ab); + + if (dot>ONE_FIXED) { + dot=ONE_FIXED; + /* Well, I suppose it could happen. */ + /* Accuracy errors... */ + LOCALASSERT(dot<=ONE_FIXED); + } + + theta=ArcCos(dot); + sinthet=GetSin(theta); + + dot=WideMulNarrowDiv(sinthet,magspeed,magrange); + + } + dot<<=3; + + return(dot+rmod); + +} + +int Validate_Target(STRATEGYBLOCK *target,char *SBname) { + /* General purpose function. */ + + if (target==NULL) return(0); + + if (target==Player->ObStrategyBlock) { + if (Observer) { + return(0); + } + } + + if (!NAME_ISEQUAL(target->SBname,SBname)) { + return(0); + } else { + if (NPC_IsDead(target)) { + return(0); + } else { + return(1); + } + } +} + +int Validate_Strategy(STRATEGYBLOCK *target,char *SBname) { + /* General purpose function Too. */ + + if (target==NULL) return(0); + + if (target==Player->ObStrategyBlock) { + if (Observer) { + return(0); + } + } + + if (!NAME_ISEQUAL(target->SBname,SBname)) { + return(0); + } else { + return(1); + } +} + +int Marine_TargetFilter(STRATEGYBLOCK *candidate) { + + switch (candidate->I_SBtype) { + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + { + if (Observer) { + return(0); + } + + switch(AvP.PlayerType) + { + case I_Alien: + case I_Predator: + return(1); + break; + case I_Marine: + return(0); + break; + default: + GLOBALASSERT(0); + return(0); + break; + } + break; + } + case I_BehaviourDummy: + { + DUMMY_STATUS_BLOCK *dummyStatusPointer; + dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(candidate->SBdataptr); + LOCALASSERT(dummyStatusPointer); + switch (dummyStatusPointer->PlayerType) { + case I_Alien: + case I_Predator: + return(1); + break; + case I_Marine: + return(0); + break; + default: + GLOBALASSERT(0); + return(0); + break; + } + break; + } + case I_BehaviourAlien: + { + ALIEN_STATUS_BLOCK *alienStatusPointer; + LOCALASSERT(candidate); + LOCALASSERT(candidate->DynPtr); + + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(candidate->SBdataptr); + + if (NPC_IsDead(candidate)) { + return(0); + } else { + if ((alienStatusPointer->BehaviourState==ABS_Dormant)|| + (alienStatusPointer->BehaviourState==ABS_Awakening)) { + return(0); + } else { + return(1); + } + } + break; + } + case I_BehaviourQueenAlien: + case I_BehaviourFaceHugger: + case I_BehaviourPredator: + case I_BehaviourXenoborg: + case I_BehaviourSeal: + case I_BehaviourPredatorAlien: + /* Valid. */ + return(1); + break; + case I_BehaviourMarine: + #if ANARCHY + return(1); + #else + return(0); + #endif + break; + #if SupportWindows95 + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *dataptr; + dataptr=candidate->SBdataptr; + switch (dataptr->type) { + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + //return(1); + return(0); + break; + default: + return(0); + break; + } + } + break; + #endif + default: + return(0); + break; + } + +} + + +STRATEGYBLOCK *Marine_GetNewTarget(VECTORCH *marinepos, STRATEGYBLOCK *me) { + + int neardist, newblip; + STRATEGYBLOCK *nearest; + #if 1 + int a; + STRATEGYBLOCK *candidate; + #endif + MODULE *dmod; + MARINE_STATUS_BLOCK *marineStatusPointer; + int dist; + VECTORCH offset; + + LOCALASSERT(me); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(me->SBdataptr); + LOCALASSERT(marineStatusPointer); + + dmod=ModuleFromPosition(marinepos,playerPherModule); + + LOCALASSERT(dmod); + + nearest=NULL; + neardist=ONE_FIXED; + newblip=0; + + //#if ANARCHY + #if 1 + for (a=0; aDynPtr) { + /* Arc reject. */ + MATRIXCH WtoL; + + offset.vx=marinepos->vx-candidate->DynPtr->Position.vx; + offset.vy=marinepos->vy-candidate->DynPtr->Position.vy; + offset.vz=marinepos->vz-candidate->DynPtr->Position.vz; + + WtoL=me->DynPtr->OrientMat; + TransposeMatrixCH(&WtoL); + RotateVector(&offset,&WtoL); + + if (offset.vz<=0) { + + /* It'll wheep, anyway. */ + if (marineStatusPointer->mtracker_timer==0) { + #if 0 + if ( + (candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx) + ||(candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx) + ||(candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx) + ) { + #else + if (ObjectShouldAppearOnMotionTracker(candidate)) { + #endif + + dist=Approximate3dMagnitude(&offset); + if (distSBdptr)&&(me->SBdptr)) { + /* Near case. */ + if ((!NPC_IsDead(candidate)) + ||(candidate->I_SBtype==I_BehaviourMarinePlayer) + ||(candidate->I_SBtype==I_BehaviourDummy)) { + if ((MarineCanSeeObject(me,candidate))) { + nearest=candidate; + neardist=dist; + } + } + } else { + if ((!NPC_IsDead(candidate)) + ||(candidate->I_SBtype==I_BehaviourMarinePlayer) + ||(candidate->I_SBtype==I_BehaviourDummy)) { + if ((IsModuleVisibleFromModule(dmod,candidate->containingModule))) { + nearest=candidate; + neardist=dist; + } + } + } + + if (marineStatusPointer->mtracker_timer==0) { + /* Hey, the tracker's on. */ + if (distDynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx) + ||(candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx) + ||(candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx) + ) { + #else + if (ObjectShouldAppearOnMotionTracker(candidate)) { + #endif + newblip=1; + marineStatusPointer->suspect_point=candidate->DynPtr->Position; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + } + } + } + } + } + } + } + } + } + #endif + + if (nearest==NULL) { + if (newblip) { + marineStatusPointer->suspicious=MARINE_PARANOIA_TIME; + tracker_noise=2; + PointAlert(1,&marineStatusPointer->suspect_point); + } + } else { + PointAlert(2,&nearest->DynPtr->Position); + } + + if (nearest) { + /* Must have seen them. */ + marineStatusPointer->roundsForThisTarget=0; + marineStatusPointer->sawlastframe=1; + + if (((marineStatusPointer->suspicious==0)&&((FastRandom()&65535)<16384)) + ||(neardist<((FastRandom()&4095)+1000))) { + /* Exhibit suprise? */ + Marine_SurpriseSound(me); + } + } + + return(nearest); + +} + +void FakeTrackerWheepGenerator(VECTORCH *marinepos, STRATEGYBLOCK *me) { + + int a,dist; + STRATEGYBLOCK *candidate; + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH offset; + + LOCALASSERT(me); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(me->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->mtracker_timer==0) { + for (a=0; aDynPtr) { + /* Arc reject. */ + MATRIXCH WtoL; + + offset.vx=marinepos->vx-candidate->DynPtr->Position.vx; + offset.vy=marinepos->vy-candidate->DynPtr->Position.vy; + offset.vz=marinepos->vz-candidate->DynPtr->Position.vz; + + WtoL=me->DynPtr->OrientMat; + TransposeMatrixCH(&WtoL); + RotateVector(&offset,&WtoL); + + if (offset.vz<=0) { + /* It'll wheep, anyway. */ + #if 0 + if ( + (candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx) + ||(candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx) + ||(candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx) + ) { + #else + if (ObjectShouldAppearOnMotionTracker(candidate)) { + #endif + dist=Approximate3dMagnitude(&offset); + if (distSBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(marineStatusPointer); + LOCALASSERT(dynPtr); + + /* check if we should be crouched or standing up */ + if(marineStatusPointer->IAmCrouched) + { + /* curently crouched */ + if(!(MarineShouldBeCrawling(sbPtr))) + { + /* should be running*/ + marineStatusPointer->IAmCrouched = 0; + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } + else + { + /* currently standing */ + if(MarineShouldBeCrawling(sbPtr)) + { + /* should be crawling */ + marineStatusPointer->IAmCrouched = 1; + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } + + /* should we change to approach state? */ + if(MarineCanSeeTarget(sbPtr)) + { + return(SRC_Request_Approach); + } else if(!(MarineIsAwareOfTarget(sbPtr))) { + return(SRC_Request_Wait); + } + + { + AIMODULE *targetModule; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + + targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr,0); + + if (targetModule) { + // textprint("Target module is %s\n",targetModule->name); + #if MARINE_STATE_PRINT + textprint("Target module is... an AI module...\n"); + #endif + } else { + #if MARINE_STATE_PRINT + textprint("Target module is NULL!\n"); + #endif + } + + if (targetModule==sbPtr->containingModule->m_aimodule) { + /* Hey, it'll drop through. */ + return(SRC_Request_Approach); + } + + if (!targetModule) { + #if 1 + /* Must be sealed off. */ + return(SRC_Request_Wait); + #else + extern MODULE *playerPherModule; + + LOGDXFMT(("Jules's bug: marine is in %s, player is in %s",sbPtr->containingModule->name,playerPherModule->name)); + GLOBALASSERT(targetModule); + #endif + } + + thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); + if (!thisEp) { + //LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.",targetModule->name,sbPtr->containingModule->name)); + LOGDXFMT(("This assert is a busted adjacency!")); + GLOBALASSERT(thisEp); + } + /* If that fired, there's a farped adjacency. */ + GLOBALASSERT(thisEp->alien_only==0); + /* If that fired, Get...ModuleForHunt went wrong. */ + + marineStatusPointer->wanderData.worldPosition=thisEp->position; + marineStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx; + marineStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy; + marineStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz; + + } + + /* ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE + { + if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(SRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + + NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject); + if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter)) + { + return(SRC_Request_Avoidance); + } + if(marineStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &(marineStatusPointer->wanderData.worldPosition), &velocityDirection)) + { + /* go to avoidance */ + /* no sequence change required */ + + marineStatusPointer->obstruction.environment=1; + marineStatusPointer->obstruction.destructableObject=0; + marineStatusPointer->obstruction.otherCharacter=0; + marineStatusPointer->obstruction.anySingleObstruction=0; + + return(SRC_Request_Avoidance); + } + #endif + + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MNS_Respond(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + DYNAMICSBLOCK *dynPtr; + VECTORCH velocityDirection = {0,0,0}; + + /* Your mission: to advance into the alert zone, even if near. */ + + LOCALASSERT(sbPtr); + marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(marineStatusPointer); + LOCALASSERT(dynPtr); + + #if 0 + /* check if we should be crouched or standing up */ + if(marineStatusPointer->IAmCrouched) + { + /* curently crouched */ + if(!(MarineShouldBeCrawling(sbPtr))) + { + /* should be running*/ + marineStatusPointer->IAmCrouched = 0; + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } + else + { + /* currently standing */ + if(MarineShouldBeCrawling(sbPtr)) + { + /* should be crawling */ + marineStatusPointer->IAmCrouched = 1; + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } + #else + HandleMovingAnimations(sbPtr); + #endif + + /* should we change to approach state? */ + if((MarineIsAwareOfTarget(sbPtr))) { + return(SRC_Request_Approach); + } + /* If we've picked up a new target, go for it. */ + + if (sbPtr->containingModule->m_aimodule==NpcSquad.alertZone) { + /* We're here! */ + DeprioritiseAlert(sbPtr->containingModule->m_aimodule); + /* Hey, if it's real, there'll be a new one soon enough. */ + return(SRC_Request_Approach); + } + + { + AIMODULE *targetModule; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + + targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr); + + if (targetModule) { + // textprint("Target module is %s\n",targetModule->name); + #if MARINE_STATE_PRINT + textprint("Target module is... an AI module...\n"); + #endif + } else { + #if MARINE_STATE_PRINT + textprint("Target module is NULL!\n"); + #endif + } + + if (targetModule==sbPtr->containingModule->m_aimodule) { + /* Looks like we've arrived. */ + /* Hey, it'll drop through. */ + return(SRC_Request_Approach); + } + + if (!targetModule) { + #if 1 + /* Must be sealed off. */ + return(SRC_Request_Wait); + #else + extern MODULE *playerPherModule; + + LOGDXFMT(("Jules's bug: marine is in %s, player is in %s",sbPtr->containingModule->name,playerPherModule->name)); + GLOBALASSERT(targetModule); + #endif + } + + thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); + if (!thisEp) { + //LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.",targetModule->name,sbPtr->containingModule->name)); + LOGDXFMT(("This assert is a busted adjacency!")); + GLOBALASSERT(thisEp); + } + /* If that fired, there's a farped adjacency. */ + GLOBALASSERT(thisEp->alien_only==0); + /* If that fired, GetNextModuleForLink went wrong. */ + + marineStatusPointer->wanderData.worldPosition=thisEp->position; + marineStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx; + marineStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy; + marineStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz; + + } + + /* ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE + { + if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(SRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + + NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject); + if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter)) + { + return(SRC_Request_Avoidance); + } + if(marineStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &(marineStatusPointer->wanderData.worldPosition), &velocityDirection)) + { + /* go to avoidance */ + /* no sequence change required */ + + marineStatusPointer->obstruction.environment=1; + marineStatusPointer->obstruction.destructableObject=0; + marineStatusPointer->obstruction.otherCharacter=0; + marineStatusPointer->obstruction.anySingleObstruction=0; + + return(SRC_Request_Avoidance); + } + #endif + + return(SRC_No_Change); +} + +static int MarineRetreatsInTheFaceOfDanger(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* This depends on mission, armament, and whether he's cornered. */ + + if (marineStatusPointer->Android) { + return(0); + } + + switch (marineStatusPointer->Mission) { + case MM_NonCom: + #if 0 + /* Err... runferrit! */ + return(1); + break; + #endif + case MM_Guard: + case MM_Wander: + case MM_Wait_Then_Wander: + case MM_LocalGuard: + case MM_Pathfinder: + { + if ((FastRandom()&65535)>marineStatusPointer->Courage) { + return(1); + } else { + return(0); + } + break; + } + default: + return(0); + break; + } + + return(0); +} + +static STATE_RETURN_CONDITION Execute_MNS_Retreat(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + DYNAMICSBLOCK *dynPtr; + VECTORCH velocityDirection = {0,0,0}; + AIMODULE *old_fearmod; + + /* Your mission: to advance out of trouble, even if near. */ + + LOCALASSERT(sbPtr); + marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(marineStatusPointer); + LOCALASSERT(dynPtr); + + old_fearmod=marineStatusPointer->fearmodule; + + /* From where am I running? */ + if(MarineIsAwareOfTarget(sbPtr)) { + marineStatusPointer->fearmodule=marineStatusPointer->Target->containingModule->m_aimodule; + } else if (marineStatusPointer->fearmodule==NULL) { + marineStatusPointer->fearmodule=sbPtr->containingModule->m_aimodule; + + if (TERROR_MODE) { + /* Better correct... */ + marineStatusPointer->fearmodule=Player->ObStrategyBlock->containingModule->m_aimodule; + } + } + + if (marineStatusPointer->fearmodule!=old_fearmod) { + marineStatusPointer->destinationmodule = General_GetAIModuleForRetreat(sbPtr,marineStatusPointer->fearmodule,5); + } + + { + AIMODULE *targetModule; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + + targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,marineStatusPointer->destinationmodule,6,0); + + #if 0 + if (targetModule) { + //textprint("Target module is %s\n",targetModule->name); + #if MARINE_STATE_PRINT + textprint("Target AI module found.\n"); + #endif + } else { + #if MARINE_STATE_PRINT + textprint("Target module is NULL!\n"); + #endif + return(SRC_Request_Wait); + } + #endif + + if ((targetModule==sbPtr->containingModule->m_aimodule) + || (targetModule==NULL)) { + /* There's no-where to run! */ + if (marineStatusPointer->Target) { + return(SRC_Request_PanicFire); + } else { + return(SRC_Request_Wait); + } + } + + GLOBALASSERT(targetModule); + + thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); + if (!thisEp) { + //LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.",targetModule->name,sbPtr->containingModule->name)); + LOGDXFMT(("This assert is a busted adjacency!")); + GLOBALASSERT(thisEp); + } + /* If that fired, there's a farped adjacency. */ + GLOBALASSERT(thisEp->alien_only==0); + /* If that fired, GetNextModuleForLink went wrong. */ + + marineStatusPointer->wanderData.worldPosition=thisEp->position; + marineStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx; + marineStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy; + marineStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz; + + } + + /* Ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager); + if (marineStatusPointer->Target) { + int dp; + VECTORCH vectotarget; + /* Are we running in a stupid direction? */ + vectotarget.vx=marineStatusPointer->Target->DynPtr->Position.vx-sbPtr->DynPtr->Position.vx; + vectotarget.vy=marineStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy; + vectotarget.vz=marineStatusPointer->Target->DynPtr->Position.vz-sbPtr->DynPtr->Position.vz; + Normalise(&vectotarget); + + dp=DotProduct(&vectotarget,&velocityDirection); + + if (dp>55000) { + /* Argh! He's in the way! */ + return(SRC_Request_PanicFire); + } + } + NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed); + + HandleMovingAnimations(sbPtr); + /* ...so we must be here for the duration. */ + + /* Scream handling. */ + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + if (marineStatusPointer->incidentFlag) { + if (Marine_HasHisMouthOpen(sbPtr)) { + if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) { + Marine_PanicScream(sbPtr); + } + } + } + } + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE + { + if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(SRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + + NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject); + if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter)) + { + return(SRC_Request_Avoidance); + } + if(marineStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + #if 1 + if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &(marineStatusPointer->wanderData.worldPosition), &velocityDirection)) + { + /* go to avoidance */ + /* no sequence change required */ + + marineStatusPointer->obstruction.environment=1; + marineStatusPointer->obstruction.destructableObject=0; + marineStatusPointer->obstruction.otherCharacter=0; + marineStatusPointer->obstruction.anySingleObstruction=0; + + return(SRC_Request_Avoidance); + } + #endif + #endif + + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MNS_DischargeShotgun(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn,relPos,relPos2; + int correctlyOrientated,range; + int hitroll; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + #if MARINE_STATE_PRINT + textprint("Firing shotgun... "); + #endif + + /* first of all, validate this state: if the target suddenly becomes cloaked, then + we should switch immediately to wait state.*/ + + if(!MarineCanSeeTarget(sbPtr)) + { + + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_Request_Wait); + } + + if (marineStatusPointer->clipammo==0) { + return(SRC_Request_Reload); + } + + /* Here we must have a target. Renew suspicion for new arrivals. */ + if (NpcSquad.Squad_Suspicion==0) { + PointAlert(2,&marineStatusPointer->weaponTarget); + } + + /* Deal with tweening part. */ + if (marineStatusPointer->internalState) { + if (marineStatusPointer->HModelController.Tweening==Controller_NoTweening) { + marineStatusPointer->HModelController.Playing=0; + marineStatusPointer->HModelController.sequence_timer=0; + marineStatusPointer->internalState=0; + } + return(SRC_No_Change); + } + + #if 0 + if ((marineStatusPointer->HModelController.keyframe_flags) + ||(marineStatusPointer->HModelController.Playing==0)) { + + marineStatusPointer->HModelController.Playing=0; + #else + if (marineStatusPointer->HModelController.Playing==0) { + #endif + + /* Only terminate if you haven't fired yet... */ + if(!MarineCanSeeTarget(sbPtr)) + { + + /* ... and remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + #if MARINE_STATE_PRINT + textprint("Returning no target.\n"); + #endif + return(SRC_Request_Wait); + } + + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + /* Fix weapon target! */ + if (marineStatusPointer->My_Weapon->TargetCallibrationShift) { + marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + } + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing*/ + if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) { + + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #if MARINE_STATE_PRINT + textprint("Turning to face.\n"); + #endif + return(SRC_No_Change); + } + + /* If you are correctly oriented, you can now fire! */ + + marineStatusPointer->HModelController.Playing=1; + marineStatusPointer->HModelController.sequence_timer=0; + + relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz); + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + /* at this point we are correctly orientated: if we have no gunflash yet, + and our state timer is set to marine_near_firetime then we have either + just started firing, or have become dis-orienated between bursts. This is a good + time to consider firing a grenade... */ + + /* look after the gun flash */ + if(marineStatusPointer->myGunFlash) { + MaintainMarineGunFlash(sbPtr); + } else { + CreateMarineGunFlash(sbPtr); + } + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + else + { + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position)); + Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + + /* Now hit the target with a shotgun blast. */ + + hitroll=0; + + while (ShotgunBlast[hitroll].vz>0) { + VECTORCH world_vec; + + RotateAndCopyVector(&ShotgunBlast[hitroll],&world_vec,&marineStatusPointer->My_Gunflash_Section->SecMat); + CastLOSProjectile(sbPtr,&marineStatusPointer->My_Gunflash_Section->World_Offset,&world_vec, marineStatusPointer->My_Weapon->Ammo_Type, 1,0); + + hitroll++; + } + if (marineStatusPointer->clipammo>0) { + marineStatusPointer->clipammo--; + } + + } else { + + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + } + + marineStatusPointer->stateTimer -= NormalFrameTime; + + /* You must have fired already. */ + #if 1 + GLOBALASSERT(marineStatusPointer->HModelController.Looped==0); + if (HModelAnimation_IsFinished(&marineStatusPointer->HModelController)) { + return(SRC_Request_PumpAction); + } + return(SRC_No_Change); + #else + if(marineStatusPointer->stateTimer > 0) { + #if MARINE_STATE_PRINT + textprint("Returning continue at range %d.\n",range); + #endif + return(SRC_No_Change); + } + + if(range < MARINE_CLOSE_APPROACH_DISTANCE) + { + /* renew firing, as we are still too close to approach */ + marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime; + marineStatusPointer->volleySize = 0; + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + #if MARINE_STATE_PRINT + textprint("Returning too close renewal at range %d.\n",range); + #endif + if (marineStatusPointer->Android==0) { + marineStatusPointer->Courage-=(ONE_FIXED>>3); + } + return(SRC_No_Change); + } + else + { + /* we are far enough away, so return to approach */ + + #if MARINE_STATE_PRINT + textprint("Returning too far termination at range %d.\n",range); + #endif + return(SRC_Request_Approach); + } + return(SRC_No_Change); + #endif +} + +#define PISTOL_RELOAD_TIME 65536 + +static STATE_RETURN_CONDITION Execute_MNS_DischargePistol(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn,relPos,relPos2; + int correctlyOrientated,range; + int mod,hitroll; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + LOCALASSERT((marineStatusPointer->My_Weapon->id==MNPCW_MPistol) + ||(marineStatusPointer->My_Weapon->id==MNPCW_PistolMarine) + ||(marineStatusPointer->My_Weapon->id==MNPCW_Android_Pistol_Special)); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if(!MarineCanSeeTarget(sbPtr)) + { + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_Request_Wait); + } + + if (marineStatusPointer->clipammo==0) { + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + return(SRC_Request_Reload); + } + + #if MARINE_STATE_PRINT + textprint("Firing pistol... "); + #endif + + /* Here we must have a target. Renew suspicion for new arrivals. */ + if (NpcSquad.Squad_Suspicion==0) { + PointAlert(2,&marineStatusPointer->weaponTarget); + } + + relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz); + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + /* first of all, validate this state: if the target suddenly becomes cloaked, then + we should switch immediately to wait state.*/ + + if ((marineStatusPointer->HModelController.keyframe_flags) + ||(marineStatusPointer->HModelController.Playing==0)) { + + marineStatusPointer->HModelController.Playing=0; + marineStatusPointer->HModelController.sequence_timer=0; + + /* Only terminate if you haven't fired yet... */ + if(!MarineCanSeeTarget(sbPtr)) + { + #if 1 + /* ... and remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + #if MARINE_STATE_PRINT + textprint("Returning no target.\n"); + #endif + return(SRC_Request_Wait); + } + + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + /* Fix weapon target! */ + if (marineStatusPointer->My_Weapon->TargetCallibrationShift) { + marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + } + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing*/ + if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening==Controller_Tweening)) { + + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #if MARINE_STATE_PRINT + textprint("Turning to face.\n"); + #endif + return(SRC_No_Change); + } + + /* If you are correctly oriented, you can now fire! */ + + marineStatusPointer->HModelController.Playing=1; + if (marineStatusPointer->clipammo>0) { + marineStatusPointer->clipammo--; + } + marineStatusPointer->roundsForThisTarget++; + + /* at this point we are correctly orientated: if we have no gunflash yet, + and our state timer is set to marine_near_firetime then we have either + just started firing, or have become dis-orienated between bursts. This is a good + time to consider firing a grenade... */ + + #if 1 + /* look after the gun flash */ + if(marineStatusPointer->myGunFlash) MaintainMarineGunFlash(sbPtr); + else CreateMarineGunFlash(sbPtr); + #else + /* KJL 15:50:48 05/01/98 - draw muzzleflash */ + GLOBALASSERT(marineStatusPointer->My_Gunflash_Section); + { + VECTORCH direction; + + direction.vx = marineStatusPointer->My_Gunflash_Section->SecMat.mat31; + direction.vy = marineStatusPointer->My_Gunflash_Section->SecMat.mat32; + direction.vz = marineStatusPointer->My_Gunflash_Section->SecMat.mat33; + + DrawMuzzleFlash(&marineStatusPointer->My_Gunflash_Section->World_Offset,&direction,MUZZLE_FLASH_AMORPHOUS); + } + #endif + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + else + { + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position)); + Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + + /* Now hit the target with one bullet. */ + + mod=SpeedRangeMods(&relPos,&relPos2); + + hitroll=marineStatusPointer->Skill; /* Marine skill... */ + if (marineStatusPointer->Target==Player->ObStrategyBlock) { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + if ( (AvP.PlayerType==I_Alien) + ||((AvP.PlayerType==I_Predator)&&(playerStatusPtr->cloakOn==1))) { + /* Vs the player, lighting effects on aliens and cloaked preds. */ + hitroll=MUL_FIXED(hitroll,((CurrentLightAtPlayer>>1)+32767)); + } + } + hitroll-=mod; + hitroll+=marineStatusPointer->My_Weapon->Accuracy; + + { + + /* Handle Damage. */ + if ((FastRandom()&65535)My_Gunflash_Section->SecMat); + + rel_pos.vx=marineStatusPointer->Target->DynPtr->Position.vx-sbPtr->DynPtr->Position.vx; + rel_pos.vy=marineStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy; + rel_pos.vz=marineStatusPointer->Target->DynPtr->Position.vz-sbPtr->DynPtr->Position.vz; + + dist=Approximate3dMagnitude(&rel_pos); + + if (VerifyHitShot(sbPtr,marineStatusPointer->Target,&marineStatusPointer->My_Gunflash_Section->World_Offset,&shotvector, marineStatusPointer->My_Weapon->Ammo_Type, 1,dist)) { + + GetDirectionOfAttack(marineStatusPointer->Target,&rel_pos,&attack_dir); + /* Get hit location? */ + + marineStatusPointer->lasthitsection=HitLocationRoll(marineStatusPointer->Target,sbPtr); + + if (marineStatusPointer->lasthitsection) { + CauseDamageToHModel(marineStatusPointer->lasthitsection->my_controller, marineStatusPointer->Target,&TemplateAmmo[marineStatusPointer->My_Weapon->Ammo_Type].MaxDamage[AvP.Difficulty], ONE_FIXED, marineStatusPointer->lasthitsection,&attack_dir,NULL,0); + } else { + CauseDamageToObject(marineStatusPointer->Target,&TemplateAmmo[marineStatusPointer->My_Weapon->Ammo_Type].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir); + } + } + } else { + GLOBALASSERT(marineStatusPointer->My_Gunflash_Section); + ProjectNPCShot(sbPtr, marineStatusPointer->Target, &marineStatusPointer->My_Gunflash_Section->World_Offset,&marineStatusPointer->My_Gunflash_Section->SecMat, marineStatusPointer->My_Weapon->Ammo_Type, 1); + } + + /* Did we get him? */ + if ((NPC_IsDead(marineStatusPointer->Target))&&(marineStatusPointer->My_Weapon->ARealMarine)) { + /* Only real marines taunt. */ + if ((marineStatusPointer->roundsForThisTarget==1)||(MarineRetreatsInTheFaceOfDanger(sbPtr))) { + if (Marine_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr)==NULL) { + /* Huzzah! */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + marineStatusPointer->lastroundhit=0; + marineStatusPointer->lasthitsection=NULL; + return(SRC_Request_Taunt); + } + } + } + } + } else { + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + } + + marineStatusPointer->stateTimer -= NormalFrameTime; + + /* You must have fired already. */ + + if(marineStatusPointer->stateTimer > 0) { + #if MARINE_STATE_PRINT + textprint("Returning continue at range %d.\n",range); + #endif + return(SRC_No_Change); + } + + if ((range < MARINE_CLOSE_APPROACH_DISTANCE)||(marineStatusPointer->Android)) + { + /* renew firing, as we are still too close to approach */ + marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime; + marineStatusPointer->volleySize = 0; + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + #if MARINE_STATE_PRINT + textprint("Returning too close renewal at range %d.\n",range); + #endif + if (marineStatusPointer->Android==0) { + marineStatusPointer->Courage-=(ONE_FIXED>>3); + } + return(SRC_No_Change); + } + else + { + /* we are far enough away, so return to approach */ + + #if MARINE_STATE_PRINT + textprint("Returning too far termination at range %d.\n",range); + #endif + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + return(SRC_Request_Approach); + } + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MNS_ThrowMolotov(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn; + int correctlyOrientated; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* first of all, validate this state: if the target suddenly becomes cloaked, then + we should switch immediately to wait state.*/ + + if (marineStatusPointer->stateTimer==marineStatusPointer->My_Weapon->FiringTime) { + marineStatusPointer->HModelController.Playing=0; + marineStatusPointer->HModelController.sequence_timer=0; + marineStatusPointer->stateTimer--; + } + + { + if (marineStatusPointer->Target) { + /* Only terminate if you haven't fired yet... */ + if(!MarineCanSeeTarget(sbPtr)) + { + + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + #if MARINE_STATE_PRINT + textprint("Returning no target.\n"); + #endif + return(SRC_Request_Wait); + } + + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + /* Fix weapon target! */ + if (marineStatusPointer->My_Weapon->TargetCallibrationShift) { + marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + } + + /* Here we must have a target. Renew suspicion for new arrivals. */ + if (NpcSquad.Squad_Suspicion==0) { + PointAlert(2,&marineStatusPointer->weaponTarget); + } + + } + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing*/ + if(!correctlyOrientated) + { + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #if MARINE_STATE_PRINT + textprint("Turning to face.\n"); + #endif + return(SRC_No_Change); + } + + /* If you are correctly oriented, you can now fire! */ + + marineStatusPointer->HModelController.Playing=1; + + /* at this point we are correctly orientated: if we have no gunflash yet, + and our state timer is set to marine_near_firetime then we have either + just started firing, or have become dis-orienated between bursts. This is a good + time to consider firing a grenade... */ + + /* No muzzle flash. */ + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + else + { + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position)); + Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + + if(marineStatusPointer->My_Gunflash_Section) { + + if (marineStatusPointer->HModelController.keyframe_flags) { + + SECTION *root; + MARINE_WEAPON_DATA *noncom; + + /* Throw! */ + SpawnMolotovCocktail(marineStatusPointer->My_Gunflash_Section, &sbPtr->DynPtr->OrientMat); + marineStatusPointer->My_Gunflash_Section=NULL; + marineStatusPointer->Mission=MM_NonCom; + /* Turn into a noncom! */ + + { + /* Remove hitdelta, if there is one. */ + DELTA_CONTROLLER *delta; + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta"); + if (delta) { + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta"); + } + } + + noncom=GetThisNPCMarineWeapon(MNPCW_MUnarmed); + + root=GetNamedHierarchyFromLibrary(noncom->Riffname,noncom->HierarchyName); + Transmogrify_HModels(sbPtr,&marineStatusPointer->HModelController,root, 1, 0,0); + marineStatusPointer->My_Weapon=noncom; + + /* Attempt to put the hitdelta back? */ + if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_HitChestFront)) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta",(int)HMSQT_MarineStand,(int)MSSS_HitChestFront,(ONE_FIXED>>2)); + GLOBALASSERT(delta); + delta->Playing=0; + } + + return(SRC_Request_Retreat); + } + } + } + + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MNS_DischargeGL(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn,relPos,relPos2; + int correctlyOrientated,range; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + #if MARINE_STATE_PRINT + textprint("Firing grenade launcher... "); + #endif + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* first of all, validate this state: if the target suddenly becomes cloaked, then + we should switch immediately to wait state.*/ + + if (marineStatusPointer->HModelController.keyframe_flags&2) { + marineStatusPointer->internalState=1; + } + if (marineStatusPointer->HModelController.keyframe_flags&1) { + marineStatusPointer->internalState=0; + } + + if(!MarineCanSeeTarget(sbPtr)) + { + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_Request_Wait); + } + + if (marineStatusPointer->clipammo==0) { + /* Reload here. */ + return(SRC_Request_Reload); + } + + /* Here we must have a target. Renew suspicion for new arrivals. */ + if (NpcSquad.Squad_Suspicion==0) { + PointAlert(2,&marineStatusPointer->weaponTarget); + } + + if (marineStatusPointer->stateTimer==marineStatusPointer->My_Weapon->FiringTime) { + + if (marineStatusPointer->HModelController.Tweening==Controller_NoTweening) { + marineStatusPointer->HModelController.Playing=0; + } + + /* Only terminate if you haven't fired yet... */ + if(!MarineCanSeeTarget(sbPtr)) + { + #if 1 + /* ... and remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + #if MARINE_STATE_PRINT + textprint("Returning no target.\n"); + #endif + return(SRC_Request_Wait); + } + + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + /* Fix weapon target! */ + if (marineStatusPointer->My_Weapon->TargetCallibrationShift) { + marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + } + + /* Aim up a little? */ + range=VectorDistance((&marineStatusPointer->weaponTarget),(&sbPtr->DynPtr->Position)); + + marineStatusPointer->weaponTarget.vy-=(range/6); + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing*/ + if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) { + + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #if MARINE_STATE_PRINT + textprint("Turning to face.\n"); + #endif + return(SRC_No_Change); + } + + /* If you are correctly oriented, you can now fire! */ + + marineStatusPointer->HModelController.Playing=1; + marineStatusPointer->HModelController.sequence_timer=0; + + #if 0 + /* Can't afford to have the jam! */ + if (marineStatusPointer->internalState!=0) { + /* Just in case. */ + return(SRC_No_Change); + } + #endif + + relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz); + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + /* Are they, by some chance, really close? */ + if (rangeMy_Weapon->MinRange) { + if (!(MarineRetreatsInTheFaceOfDanger(sbPtr))) { + /* Stay cool. */ + return(SRC_Request_PullPistol); + } else { + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + /* Fail twice, then flee... else continue. */ + return(SRC_Request_Retreat); + } + } + } + + #if 1 + /* look after the gun flash */ + if(marineStatusPointer->myGunFlash) MaintainMarineGunFlash(sbPtr); + else CreateMarineGunFlash(sbPtr); + #else + /* KJL 15:50:48 05/01/98 - draw muzzleflash */ + GLOBALASSERT(marineStatusPointer->My_Gunflash_Section); + { + VECTORCH direction; + + direction.vx = marineStatusPointer->My_Gunflash_Section->SecMat.mat31; + direction.vy = marineStatusPointer->My_Gunflash_Section->SecMat.mat32; + direction.vz = marineStatusPointer->My_Gunflash_Section->SecMat.mat33; + + DrawMuzzleFlash(&marineStatusPointer->My_Gunflash_Section->World_Offset,&direction,MUZZLE_FLASH_AMORPHOUS); + } + #endif + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + else + { + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position)); + Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + + /* Now fire a grenade. */ + + + { + LOCALASSERT(marineStatusPointer->My_Gunflash_Section); + //LOCALASSERT(marineStatusPointer->internalState==0); + + CreateGrenadeKernel(I_BehaviourGrenade, &marineStatusPointer->My_Gunflash_Section->World_Offset, &marineStatusPointer->My_Gunflash_Section->SecMat,0); + + if (marineStatusPointer->clipammo>0) { + marineStatusPointer->clipammo--; + } + } + } + + if (marineStatusPointer->stateTimerMy_Weapon->FiringTime) { + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + } + + marineStatusPointer->stateTimer -= NormalFrameTime; + + /* You must have fired already. */ + + if(marineStatusPointer->stateTimer > 0) { + #if MARINE_STATE_PRINT + textprint("Returning continue at range %d.\n",range); + #endif + return(SRC_No_Change); + } + + if(range < MARINE_CLOSE_APPROACH_DISTANCE) + { + /* renew firing, as we are still too close to approach */ + marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime; + marineStatusPointer->volleySize = 0; + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + #if MARINE_STATE_PRINT + textprint("Returning too close renewal at range %d.\n",range); + #endif + return(SRC_No_Change); + } + else + { + /* we are far enough away, so return to approach */ + + #if MARINE_STATE_PRINT + textprint("Returning too far termination at range %d.\n",range); + #endif + return(SRC_Request_Approach); + } + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MNS_NewDischargeGL(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn,relPos,relPos2; + int correctlyOrientated,range; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* first of all, validate this state: if the target suddenly becomes cloaked, then + we should switch immediately to wait state.*/ + + if(!MarineCanSeeTarget(sbPtr)) + { + + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_Request_Wait); + } + + if (marineStatusPointer->clipammo==0) { + return(SRC_Request_Reload); + } + + /* Here we must have a target. Renew suspicion for new arrivals. */ + if (NpcSquad.Squad_Suspicion==0) { + PointAlert(2,&marineStatusPointer->weaponTarget); + } + + /* Deal with tweening part. */ + if (marineStatusPointer->internalState) { + if (marineStatusPointer->HModelController.Tweening==Controller_NoTweening) { + marineStatusPointer->HModelController.Playing=0; + marineStatusPointer->HModelController.sequence_timer=0; + marineStatusPointer->internalState=0; + } + return(SRC_No_Change); + } + + if (marineStatusPointer->HModelController.Playing==0) { + + /* Only terminate if you haven't fired yet... */ + if(!MarineCanSeeTarget(sbPtr)) + { + + /* ... and remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + #if MARINE_STATE_PRINT + textprint("Returning no target.\n"); + #endif + return(SRC_Request_Wait); + } + + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + /* Fix weapon target! */ + if (marineStatusPointer->My_Weapon->TargetCallibrationShift) { + marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + } + + /* Aim up a little? */ + range=VectorDistance((&marineStatusPointer->weaponTarget),(&sbPtr->DynPtr->Position)); + + marineStatusPointer->weaponTarget.vy-=(range/8); + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing*/ + if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) { + + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #if MARINE_STATE_PRINT + textprint("Turning to face.\n"); + #endif + return(SRC_No_Change); + } + + /* If you are correctly oriented, you can now fire! */ + + marineStatusPointer->HModelController.Playing=1; + marineStatusPointer->HModelController.sequence_timer=0; + + relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz); + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + /* Are they, by some chance, really close? */ + if (rangeMy_Weapon->MinRange) { + if (!(MarineRetreatsInTheFaceOfDanger(sbPtr))) { + /* Stay cool. */ + return(SRC_Request_PullPistol); + } else { + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + /* Fail twice, then flee... else continue. */ + return(SRC_Request_Retreat); + } + } + } + + /* at this point we are correctly orientated: if we have no gunflash yet, + and our state timer is set to marine_near_firetime then we have either + just started firing, or have become dis-orienated between bursts. This is a good + time to consider firing a grenade... */ + + /* look after the gun flash */ + if(marineStatusPointer->myGunFlash) { + MaintainMarineGunFlash(sbPtr); + } else { + CreateMarineGunFlash(sbPtr); + } + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + else + { + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position)); + Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + + /* Now fire a grenade. */ + { + LOCALASSERT(marineStatusPointer->My_Gunflash_Section); + + CreateGrenadeKernel(I_BehaviourGrenade, &marineStatusPointer->My_Gunflash_Section->World_Offset, &marineStatusPointer->My_Gunflash_Section->SecMat,0); + + if (marineStatusPointer->clipammo>0) { + marineStatusPointer->clipammo--; + } + } + + } else { + + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + } + + marineStatusPointer->stateTimer -= NormalFrameTime; + + /* You must have fired already. */ + + GLOBALASSERT(marineStatusPointer->HModelController.Looped==0); + if (HModelAnimation_IsFinished(&marineStatusPointer->HModelController)) { + return(SRC_Request_PumpAction); + } + return(SRC_No_Change); + +} + +static STATE_RETURN_CONDITION Execute_MNS_DischargeSADAR(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn,relPos,relPos2; + int correctlyOrientated,range; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + #if MARINE_STATE_PRINT + textprint("Firing SADAR... "); + #endif + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* first of all, validate this state: if the target suddenly becomes cloaked, then + we should switch immediately to wait state.*/ + + if(!MarineCanSeeTarget(sbPtr)) + { + + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_Request_Wait); + } + + if (marineStatusPointer->clipammo==0) { + /* Reload here. */ + return(SRC_Request_Reload); + } + + /* Here we must have a target. Renew suspicion for new arrivals. */ + if (NpcSquad.Squad_Suspicion==0) { + PointAlert(2,&marineStatusPointer->weaponTarget); + } + + if (marineStatusPointer->stateTimer==marineStatusPointer->My_Weapon->FiringTime) { + + if (marineStatusPointer->HModelController.Tweening==Controller_NoTweening) { + marineStatusPointer->HModelController.Playing=0; + } + + /* Only terminate if you haven't fired yet... */ + if(!MarineCanSeeTarget(sbPtr)) + { + #if 1 + /* ... and remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + #if MARINE_STATE_PRINT + textprint("Returning no target.\n"); + #endif + return(SRC_Request_Wait); + } + + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + /* Fix weapon target! */ + if (marineStatusPointer->My_Weapon->TargetCallibrationShift) { + marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + } + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing*/ + if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) { + + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #if MARINE_STATE_PRINT + textprint("Turning to face.\n"); + #endif + return(SRC_No_Change); + } + + /* If you are correctly oriented, you can now fire! */ + + marineStatusPointer->HModelController.Playing=1; + marineStatusPointer->HModelController.sequence_timer=0; + + relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz); + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + /* Are they, by some chance, really close? */ + if (rangeMy_Weapon->MinRange) { + if (!(MarineRetreatsInTheFaceOfDanger(sbPtr))) { + /* Stay cool. */ + return(SRC_Request_PullPistol); + } else { + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + /* Fail twice, then flee... else continue. */ + return(SRC_Request_Retreat); + } + } + } + + /* at this point we are correctly orientated: if we have no gunflash yet, + and our state timer is set to marine_near_firetime then we have either + just started firing, or have become dis-orienated between bursts. This is a good + time to consider firing a grenade... */ + + #if 1 + /* look after the gun flash */ + if(marineStatusPointer->myGunFlash) MaintainMarineGunFlash(sbPtr); + else CreateMarineGunFlash(sbPtr); + #else + /* KJL 15:50:48 05/01/98 - draw muzzleflash */ + GLOBALASSERT(marineStatusPointer->My_Gunflash_Section); + { + VECTORCH direction; + + direction.vx = marineStatusPointer->My_Gunflash_Section->SecMat.mat31; + direction.vy = marineStatusPointer->My_Gunflash_Section->SecMat.mat32; + direction.vz = marineStatusPointer->My_Gunflash_Section->SecMat.mat33; + + DrawMuzzleFlash(&marineStatusPointer->My_Gunflash_Section->World_Offset,&direction,MUZZLE_FLASH_AMORPHOUS); + } + #endif + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + else + { + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position)); + Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + + /* Now fire a rocket. */ + + { + SECTION_DATA *rocket_section; + + rocket_section=GetThisSectionData(marineStatusPointer->HModelController.section_data,"dum flash"); + + LOCALASSERT(rocket_section); + + CreateRocketKernel(&rocket_section->World_Offset, &rocket_section->SecMat,0); + + if (marineStatusPointer->clipammo>0) { + marineStatusPointer->clipammo--; + } + } + } + + if (marineStatusPointer->stateTimerMy_Weapon->FiringTime) { + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + } + + marineStatusPointer->stateTimer -= NormalFrameTime; + + /* You must have fired already. */ + + if(marineStatusPointer->stateTimer > 0) { + #if MARINE_STATE_PRINT + textprint("Returning continue at range %d.\n",range); + #endif + return(SRC_No_Change); + } + + if(range < MARINE_CLOSE_APPROACH_DISTANCE) + { + /* renew firing, as we are still too close to approach */ + marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime; + marineStatusPointer->volleySize = 0; + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + #if MARINE_STATE_PRINT + textprint("Returning too close renewal at range %d.\n",range); + #endif + return(SRC_No_Change); + } + else + { + /* we are far enough away, so return to approach */ + + #if MARINE_STATE_PRINT + textprint("Returning too far termination at range %d.\n",range); + #endif + return(SRC_Request_Approach); + } + return(SRC_No_Change); +} + +void GetNewRandomDirection(MARINE_STATUS_BLOCK *marineStatusPointer) { + + int rnum; + + rnum=FastRandom()&65535; + + marineStatusPointer->lastroundhit&=65535; + marineStatusPointer->lastroundhit|=(rnum<<16); + +} + +void GetFirstRandomDirection(MARINE_STATUS_BLOCK *marineStatusPointer,VECTORCH *output) { + + int rnum; + MATRIXCH tempmat; + EULER tempeul; + VECTORCH tempvec; + + rnum=FastRandom()&65535; + + rnum>>=4; + + tempeul.EulerX=0; + tempeul.EulerY=rnum; + tempeul.EulerZ=0; + + CreateEulerMatrix(&tempeul,&tempmat); + + tempvec.vx=0; + tempvec.vy=0; + tempvec.vz=65535; + + RotateAndCopyVector(&tempvec,output,&tempmat); + + marineStatusPointer->lastroundhit=(rnum<<20)+(rnum<<4); + +} + +void TurnToFaceRandomDirection(MARINE_STATUS_BLOCK *marineStatusPointer,VECTORCH *output) { + + int currentangle,targetangle,deltaangle,deltaangle2; + MATRIXCH tempmat; + EULER tempeul; + VECTORCH tempvec; + + currentangle=(marineStatusPointer->lastroundhit)&(65535); + targetangle=(marineStatusPointer->lastroundhit>>16)&(65535); + + deltaangle=targetangle-currentangle; + deltaangle2=deltaangle; + if (deltaangle<0) deltaangle+=65536; + + if (deltaangle>32767) { + currentangle-=(NormalFrameTime>>1); + if (currentangle<0) currentangle+=65536; + } else { + currentangle+=(NormalFrameTime>>1); + if (currentangle>65535) currentangle-=65536; + } + /* Overshoot test. */ + deltaangle=targetangle-currentangle; + if ((deltaangle*deltaangle2)<=0) { + currentangle=targetangle; + } + + LOCALASSERT(currentangle<65536); + marineStatusPointer->lastroundhit&=~65535; + marineStatusPointer->lastroundhit|=currentangle; + + currentangle>>=4; + + tempeul.EulerX=0; + tempeul.EulerY=currentangle; + tempeul.EulerZ=0; + + CreateEulerMatrix(&tempeul,&tempmat); + + tempvec.vx=0; + tempvec.vy=0; + tempvec.vz=65535; + + RotateAndCopyVector(&tempvec,output,&tempmat); + +} + +void Convert_To_RunningOnFire(STRATEGYBLOCK *sbPtr) { + + SECTION *root; + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Burn off tracker. */ + marineStatusPointer->mtracker_timer=-1; + + /* Grimace. */ + Marine_SwitchExpression(sbPtr,5); + + if (marineStatusPointer->behaviourState == MBS_Dying) { + /* Just die. */ + return; + } + + /* get rid of the gun flash, if we've got it */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + /* Switch to template. */ + root=GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,marineStatusPointer->My_Weapon->TemplateName); + + /* Remove all deltas. */ + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"Elevation"); + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta"); + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun"); + Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta"); + + Transmogrify_HModels(sbPtr,&marineStatusPointer->HModelController, + root, 1, 0,0); + + SetMarineAnimationSequence(sbPtr,HMSQT_MarineRun,MRSS_Tem_Run_On_Fire, + (ONE_FIXED*3),(ONE_FIXED>>2)); + + GetFirstRandomDirection(marineStatusPointer,&(marineStatusPointer->wanderData.worldPosition)); + /* Hey, it's a spare vector. */ + marineStatusPointer->nearSpeed=MARINE_NEAR_SPEED>>1; + NPCSetVelocity(sbPtr, &(marineStatusPointer->wanderData.worldPosition), marineStatusPointer->nearSpeed); + + InitMission(sbPtr,MM_RunAroundOnFire); + + marineStatusPointer->stateTimer=(ONE_FIXED); + + /* Add crackling sound. */ + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(marineStatusPointer->soundHandle); + + Sound_Play(SID_FIRE,"dlev",&(sbPtr->DynPtr->Position),&marineStatusPointer->soundHandle,127); + +} + +static STATE_RETURN_CONDITION Execute_MNS_RunAroundOnFire(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(marineStatusPointer); + LOCALASSERT(dynPtr); + + if (sbPtr->SBDamageBlock.IsOnFire==0) { + /* Stay on fire! */ + sbPtr->SBDamageBlock.IsOnFire=1; + } + + /* check if we should be crouched or standing up */ + if(marineStatusPointer->IAmCrouched) + { + /* curently crouched */ + if(!(MarineShouldBeCrawling(sbPtr))) + { + /* should be running*/ + marineStatusPointer->IAmCrouched = 0; + SetMarineAnimationSequence(sbPtr,HMSQT_MarineRun,MRSS_Tem_Run_On_Fire,ONE_FIXED,(ONE_FIXED>>3)); + } + } + else + { + /* currently standing */ + if(MarineShouldBeCrawling(sbPtr)) + { + /* should be crawling, I guess... */ + marineStatusPointer->IAmCrouched = 1; + SetMarineAnimationSequence(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } + + /* Set velocity for this frame. */ + marineStatusPointer->stateTimer-=NormalFrameTime; + if (marineStatusPointer->stateTimer<0) { + marineStatusPointer->stateTimer=0; + //if (FastRandom()&15==0) + { + GetNewRandomDirection(marineStatusPointer); + marineStatusPointer->stateTimer=(ONE_FIXED); + } + } + TurnToFaceRandomDirection(marineStatusPointer,&(marineStatusPointer->wanderData.worldPosition)); + NPCSetVelocity(sbPtr, &(marineStatusPointer->wanderData.worldPosition), marineStatusPointer->nearSpeed); + + /* Handle sound... */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE + { + if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(SRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + + NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject); + if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter)) + { + /* go to avoidance */ + GetNewRandomDirection(marineStatusPointer); + TurnToFaceRandomDirection(marineStatusPointer,&(marineStatusPointer->wanderData.worldPosition)); + NPCSetVelocity(sbPtr, &(marineStatusPointer->wanderData.worldPosition), marineStatusPointer->nearSpeed); + return(SRC_Request_Avoidance); + } + if(marineStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + #endif + + return(SRC_No_Change); +} + +void RunAroundOnFireMission_Control(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + STATE_RETURN_CONDITION state_result; + int marineIsNear; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Current Behaviour. */ + + if(sbPtr->SBdptr) { + marineIsNear=1; + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]); + } else { + marineIsNear=0; + } + + { + + switch(marineStatusPointer->behaviourState) + { + case(MBS_Dying): + { + if ((ShowSquadState)||((sbPtr->SBdptr)&&(ShowNearSquad))) { + PrintDebuggingText("RAOF marine dying in %s\n",sbPtr->containingModule->name); + } + + if (marineIsNear) { + Execute_Dying(sbPtr); + } else { + Execute_Dying(sbPtr); + } + break; + } + default: + { + if ((ShowSquadState)||((sbPtr->SBdptr)&&(ShowNearSquad))) { + PrintDebuggingText("RAOF marine running in %s\n",sbPtr->containingModule->name); + } + + if (marineIsNear) { + state_result=Execute_MNS_RunAroundOnFire(sbPtr); + } else { + Execute_MFS_Wait(sbPtr); + } + break; + } + } + } + + if (!marineIsNear) { + + /* check here to see if marine is in a proximity door - if so, trigger it to open. */ + { + MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule); + + if(doorType == MDT_ProxDoor) + ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->marineTrigger = 1; + } + + /* lastly, do a containment test: to make sure that we are inside a module. */ + #if UseLocalAssert + { + VECTORCH localCoords; + MODULE *thisModule = sbPtr->containingModule; + + LOCALASSERT(thisModule); + + localCoords = sbPtr->DynPtr->Position; + localCoords.vx -= thisModule->m_world.vx; + localCoords.vy -= thisModule->m_world.vy; + localCoords.vz -= thisModule->m_world.vz; + + if(PointIsInModule(thisModule, &localCoords)==0) + { + #if (!PSX) + textprint("FAR MARINE MODULE CONTAINMENT FAILURE \n"); + LOCALASSERT(1==0); + #endif + } + } + #endif + } + +} + +void GetPointToFaceMarineTowards(STRATEGYBLOCK *sbPtr,VECTORCH *output) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + AIMODULE *targetModule; + AIMODULE **AdjModuleRefPtr; + AIMODULE* chosenModule = NULL; + VECTORCH chosenEpWorld; + int numFound = 0; + + LOCALASSERT(sbPtr); + if (sbPtr->containingModule==NULL) { + return; + } + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* First trap... are you suspicious? */ + if (marineStatusPointer->suspicious) { + MODULE *suspect_module; + + suspect_module=ModuleFromPosition(&marineStatusPointer->suspect_point,sbPtr->containingModule); + + if (suspect_module==NULL) { + /* Gordon Bennet. */ + *output = marineStatusPointer->suspect_point; + marineStatusPointer->gotapoint=1; + /* Congratulations. */ + return; + } + + /* In the same module? */ + if (sbPtr->containingModule->m_aimodule==suspect_module->m_aimodule) { + *output = marineStatusPointer->suspect_point; + marineStatusPointer->gotapoint=1; + /* Congratulations. */ + return; + } + + /* Can you see the suspect point? */ + if (sbPtr->SBdptr!=NULL) { + if (IsThisObjectVisibleFromThisPosition(sbPtr->SBdptr,&marineStatusPointer->suspect_point,NPC_MAX_VIEWRANGE)) { + *output = marineStatusPointer->suspect_point; + marineStatusPointer->gotapoint=1; + /* Congratulations. */ + return; + } + } + + { + /* Try to face towards the most appropriate EP. */ + targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,suspect_module->m_aimodule,7,0); + if ((targetModule==NULL)||(targetModule==sbPtr->containingModule->m_aimodule)) { + *output = marineStatusPointer->suspect_point; + marineStatusPointer->gotapoint=1; + /* Congratulations. */ + return; + } else { + /* Get the EP. */ + FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule); + if(thisEp) { + VECTORCH thisEpWorld = thisEp->position; + + thisEpWorld.vx += targetModule->m_world.vx; + thisEpWorld.vy += targetModule->m_world.vy; + thisEpWorld.vz += targetModule->m_world.vz; + + *output = thisEpWorld; + marineStatusPointer->gotapoint=1; + /* Congratulations. */ + return; + + } + /* Still here? Can't you get anything right? */ + *output = marineStatusPointer->suspect_point; + marineStatusPointer->gotapoint=1; + /* Congratulations. */ + return; + } + } + } + + /* We know your module, don't we? */ + + marineStatusPointer->gotapoint=0; + targetModule=NULL; + + /* Okay. If you're a guard, do your job. */ + if (marineStatusPointer->Mission==MM_Guard) { + + *output = marineStatusPointer->my_facing_point; + marineStatusPointer->gotapoint=1; + /* Congratulations. */ + return; + } + + if (NpcSquad.alertZone) { + /* Might want to face towards trouble. */ + if (sbPtr->containingModule->m_aimodule!=NpcSquad.alertZone) { + AIMODULE *targetModule=0; + targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr); + } + } + + /* Did that work? */ + + if (targetModule) { + FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule); + if(thisEp) { + VECTORCH thisEpWorld = thisEp->position; + + thisEpWorld.vx += targetModule->m_world.vx; + thisEpWorld.vy += targetModule->m_world.vy; + thisEpWorld.vz += targetModule->m_world.vz; + + *output = thisEpWorld; + marineStatusPointer->gotapoint=1; + /* Congratulations. */ + return; + + } + } + + AdjModuleRefPtr = sbPtr->containingModule->m_aimodule->m_link_ptrs; + /* check if there is a module adjacency list */ + if(!AdjModuleRefPtr) { + /* Just be random, then. */ + return; + } + + if(!(*AdjModuleRefPtr)) { + /* Just be random, then. */ + return; + } + + while(*AdjModuleRefPtr != 0) + { + AIMODULE *nextAdjModule = *AdjModuleRefPtr; + if (((*(nextAdjModule->m_module_ptrs))->m_flags&MODULEFLAG_AIRDUCT)==0) + { + /* Overlook airducts :-) */ + FARENTRYPOINT *thisEp = GetAIModuleEP(nextAdjModule, sbPtr->containingModule->m_aimodule); + if(thisEp) + { + if (thisEp->alien_only==0) { + /* aha. an ep!... */ + VECTORCH thisEpWorld = thisEp->position; + + thisEpWorld.vx += nextAdjModule->m_world.vx; + thisEpWorld.vy += nextAdjModule->m_world.vy; + thisEpWorld.vz += nextAdjModule->m_world.vz; + + numFound++; + if(FastRandom()%numFound==0) + { + /* take this one */ + chosenModule = nextAdjModule; + chosenEpWorld = thisEpWorld; + } + } + } + } + AdjModuleRefPtr++; + } + + if(chosenModule) + { + LOCALASSERT(numFound>=1); + *output = chosenEpWorld; + marineStatusPointer->gotapoint=1; + /* Congratulations. */ + return; + } + + /* else... return? */ + + return; +} + +int MarineSight_FrustrumReject(STRATEGYBLOCK *sbPtr,VECTORCH *localOffset,STRATEGYBLOCK *target) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Target==NULL) { + /* Chop off the top 45 degrees. */ + if ( (localOffset->vz <0) && ( + ((localOffset->vy-100)>=0)||(((localOffset->vy-100)<0)&&((-(localOffset->vy-100)) < (-localOffset->vz))) + )) { + /* 180 horizontal, 180 vertical. */ + return(1); + } else { + return(0); + } + } else if (marineStatusPointer->Target!=target) { + + if ( (localOffset->vz <0) + // && (localOffset->vz < (localOffset->vy+500)) + // && (localOffset->vz > -(localOffset->vy+500)) + ) { + /* 180 horizontal, 180 vertical. */ + return(1); + } else { + return(0); + } + } else { + /* Slightly different now, for error correction. */ + if (localOffset->vz <0) { + return(1); + } else { + /* 270 horizontal, 180 vertical. */ + if ( ((localOffset->vx>0)&&(localOffset->vxvz)) + ||((localOffset->vx<0)&&((-localOffset->vx)vz)) ) { + return(0); + } else { + return(1); + } + } + } +} + +int Marine_SoundInterest(SOUNDINDEX soundIndex) { + + /* Returns 0->ONE_FIXED scale. 0 is ignored. Otherwise, larger value means + lower priority. */ + + switch (soundIndex) { + case SID_ALIEN_HISS: + case SID_ALIEN_HISS1: + case SID_ALIEN_SCREAM: + case SID_SWIPE: + case SID_SWISH: + case SID_TAIL: + case SID_PRED_LAUNCHER: + case SID_PRED_FRISBEE: + case SID_PRED_PISTOL: + case SID_PRED_SNARL: + case SID_PRED_SCREAM1: + case SID_PRED_LASER: + case SID_SWIPE2: + case SID_SWIPE3: + case SID_SWIPE4: + case SID_PRED_HISS: + case SID_HIT_FLESH: + case SID_ALIEN_HIT: + case SID_ALIEN_KILL: + case SID_FHUG_ATTACKLOOP: + case SID_FHUG_MOVE: + case SID_BUGDIE1: + case SID_BUGDIE2: + case SID_BUGDIE3: + case SID_MARINE_DEATH1: + case SID_MARINE_DEATH2: + case SID_PRED_LOUDROAR: + case SID_MARINE_HIT: + case SID_ALIEN_HIT2: + case SID_PRED_SHORTROAR: + case SID_PRED_SLASH: + case SID_RIP: + case SID_PRED_NEWROAR: + case SID_PLASMABOLT_DISSIPATE: + case SID_PLASMABOLT_HIT: + case SID_ALIEN_JAW_ATTACK: + case SID_BODY_BEING_HACKED_UP_0: + case SID_BODY_BEING_HACKED_UP_1: + case SID_BODY_BEING_HACKED_UP_2: + case SID_BODY_BEING_HACKED_UP_3: + case SID_BODY_BEING_HACKED_UP_4: + case SID_PREDATOR_PICKUP_FIELDCHARGE: + case SID_PREDATOR_PICKUP_WEAPON: + case SID_PREDATOR_CLOAKING_ACTIVE: + case SID_PREDATOR_CLOAKING_DAMAGED: + case SID_PREDATOR_SPEARGUN_EMPTY: + case SID_PREDATOR_PLASMACASTER_TARGET_FOUND: + case SID_PREDATOR_PLASMACASTER_TARGET_LOCKED: + case SID_PREDATOR_PLASMACASTER_TARGET_LOST: + case SID_PREDATOR_PLASMACASTER_CHARGING: + case SID_PREDATOR_PLASMACASTER_EMPTY: + case SID_PREDATOR_DISK_TARGET_LOCKED: + case SID_PREDATOR_DISK_FLYING: + case SID_PREDATOR_DISK_HITTING_TARGET: + case SID_PREDATOR_DISK_HITTING_WALL: + case SID_PREDATOR_DISK_BEING_CAUGHT: + case SID_PREDATOR_DISK_RECOVERED: + case SID_PREDATOR_VOCAL_SNARL_1: + case SID_PREDATOR_VOCAL_SNARL_2: + case SID_ALIEN_TAILUNFURL: + case SID_ALIEN_TAUNT_1: + case SID_ALIEN_TAUNT_2: + case SID_PRED_JUMP_START_1: + case SID_PRED_JUMP_START_2: + case SID_PRED_JUMP_START_3: + case SID_PRED_CLOAKON: + case SID_PRED_CLOAKOFF: + case SID_PRED_SMALLLANDING: + case SID_ED_FACEHUGGERSLAP: + case SID_GRAPPLE_HIT_WALL: + case SID_GRAPPLE_THROW: + case SID_ED_ELEC_DEATH: + /* Enemy sounds. */ + return(ONE_FIXED>>2); + break; + case SID_SWITCH1: + case SID_SWITCH2: + case SID_PULSE_START: + case SID_PULSE_LOOP: + case SID_PULSE_END: + case SID_LIFT_START: + case SID_LIFT_LOOP: + case SID_LIFT_END: + case SID_VISION_ON: + case SID_VISION_LOOP: + case SID_FIRE: + case SID_PICKUP: + case SID_SPLASH1: + case SID_SPLASH2: + case SID_SPLASH3: + case SID_SPLASH4: + case SID_POWERUP: + case SID_POWERDN: + case SID_ACID_SPRAY: + case SID_DOORSTART: + case SID_DOORMID: + case SID_DOOREND: + case SID_BORGON: + case SID_SPARKS: + case SID_STOMP: + case SID_LOADMOVE: + case SID_NOAMMO: + case SID_LONGLOAD: + case SID_NADELOAD: + case SID_NADEFIRE: + case SID_NADEEXPLODE: + case SID_SHRTLOAD: + case SID_INCIN_START: + case SID_INCIN_LOOP: + case SID_INCIN_END: + case SID_ROCKFIRE: + case SID_SHOTGUN: + case SID_SMART1: + case SID_SMART2: + case SID_SMART3: + case SID_SENTRY_GUN: + case SID_SENTRY_END: + case SID_NICE_EXPLOSION: + case SID_EXPLOSION: + case SID_MINIGUN_END: + case SID_MINIGUN_LOOP: + case SID_FRAG_RICOCHETS: + case SID_SPEARGUN_HITTING_WALL: + case SID_DISC_STICKSINWALL: + case SID_PREDATOR_PLASMACASTER_REDTRIANGLES: + case SID_WIL_PRED_PISTOL_EXPLOSION: + case SID_PROX_GRENADE_READYTOBLOW: + case SID_PROX_GRENADE_ACTIVE: + case SID_ED_GRENADE_EXPLOSION: + case SID_ED_GRENADE_PROXEXPLOSION: + case SID_ED_MOLOTOV_EXPLOSION: + case SID_SENTRYGUNDEST: + return(ONE_FIXED); + break; + case SID_ARMSTART: + case SID_ARMMID: + case SID_ARMEND: + case SID_TRACKER_CLICK: + case SID_TRACKER_WHEEP: + case SID_RICOCH1: + case SID_RICOCH2: + case SID_RICOCH3: + case SID_RICOCH4: + case SID_TELETEXT: + case SID_TRACKER_WHEEP_HIGH: + case SID_TRACKER_WHEEP_LOW: + case SID_PULSE_RIFLE_FIRING_EMPTY: + case SID_THROW_FLARE: + case SID_CONSOLE_ACTIVATES: + case SID_CONSOLE_DEACTIVATES: + case SID_CONSOLE_MARINEMESSAGE: + case SID_CONSOLE_ALIENMESSAGE: + case SID_CONSOLE_PREDATORMESSAGE: + case SID_MINIGUN_READY: + case SID_MINIGUN_EMPTY: + case SID_SMART_MODESWITCH: + case SID_GRENADE_BOUNCE: + case SID_BURNING_FLARE: + case SID_FLAMETHROWER_PILOT_LIGHT: + case SID_MARINE_JUMP_START: + case SID_MARINE_JUMP_END: + case SID_MARINE_PICKUP_WEAPON: + case SID_MARINE_PICKUP_AMMO: + case SID_MARINE_PICKUP_ARMOUR: + case SID_SENTRYGUN_LOCK: + case SID_SENTRYGUN_SHUTDOWN: + case SID_WIL_MINIGUN_READY: + case SID_SADAR_FIRE: + case SID_MARINE_JUMP_START_2: + case SID_MARINE_JUMP_START_3: + case SID_MARINE_JUMP_START_4: + case SID_ED_LARGEWEAPONDROP: + case SID_MENUS_SELECT_ITEM: + case SID_MENUS_CHANGE_ITEM: + case SID_PRED_ZOOM_IN: + case SID_PRED_ZOOM_OUT: + case SID_MARINE_SMALLLANDING: + case SID_LIGHT_FLICKER_ON: + case SID_ED_SENTRYTURN01: + case SID_PULSE_SWIPE01: + case SID_PULSE_SWIPE02: + case SID_PULSE_SWIPE03: + case SID_PULSE_SWIPE04: + case SID_ED_JETPACK_START: + case SID_ED_JETPACK_MID: + case SID_ED_JETPACK_END: + case SID_IMAGE: + case SID_IMAGE_OFF: + /* Basic marine sounds, and the sentrygun. */ + return(0); + break; + case SID_STARTOF_LOADSLOTS: + case SID_UNUSED_125: + case SID_UNUSED_126: + case SID_UNUSED_127: + case SID_UNUSED_128: + case SID_UNUSED_129: + case SID_UNUSED_130: + case SID_UNUSED_131: + case SID_UNUSED_132: + case SID_UNUSED_133: + case SID_UNUSED_134: + case SID_UNUSED_135: + case SID_UNUSED_136: + case SID_UNUSED_137: + case SID_UNUSED_138: + case SID_UNUSED_139: + case SID_UNUSED_140: + case SID_UNUSED_141: + case SID_UNUSED_142: + case SID_UNUSED_143: + case SID_UNUSED_144: + case SID_UNUSED_145: + case SID_UNUSED_146: + case SID_UNUSED_147: + case SID_UNUSED_148: + case SID_UNUSED_149: + case SID_ENDOF_LOADSLOTS: + /* Environment sounds. */ + return(ONE_FIXED<<1); + break; + default: + /* Eh? Could be a scream... */ + return(ONE_FIXED<<1); + break; + } + +} + +int Marine_SoundCourageBonus(SOUNDINDEX soundIndex) { + + /* Returns a FRI value. + is GOOD! */ + + switch (soundIndex) { + case SID_ALIEN_HISS: + case SID_ALIEN_HISS1: + case SID_ALIEN_SCREAM: + case SID_SWIPE: + case SID_SWISH: + case SID_TAIL: + case SID_PRED_LAUNCHER: + case SID_PRED_FRISBEE: + case SID_PRED_PISTOL: + case SID_PRED_SNARL: + case SID_PRED_SCREAM1: + case SID_PRED_LASER: + case SID_SWIPE2: + case SID_SWIPE3: + case SID_SWIPE4: + case SID_PRED_HISS: + case SID_HIT_FLESH: + case SID_ALIEN_HIT: + case SID_ALIEN_KILL: + case SID_FHUG_ATTACKLOOP: + case SID_FHUG_MOVE: + case SID_BUGDIE1: + case SID_BUGDIE2: + case SID_BUGDIE3: + case SID_MARINE_DEATH1: + case SID_MARINE_DEATH2: + case SID_PRED_LOUDROAR: + case SID_MARINE_HIT: + case SID_ALIEN_HIT2: + case SID_PRED_SHORTROAR: + case SID_PRED_SLASH: + case SID_RIP: + case SID_PRED_NEWROAR: + case SID_PLASMABOLT_DISSIPATE: + case SID_PLASMABOLT_HIT: + case SID_ALIEN_JAW_ATTACK: + case SID_BODY_BEING_HACKED_UP_0: + case SID_BODY_BEING_HACKED_UP_1: + case SID_BODY_BEING_HACKED_UP_2: + case SID_BODY_BEING_HACKED_UP_3: + case SID_BODY_BEING_HACKED_UP_4: + case SID_PREDATOR_PICKUP_FIELDCHARGE: + case SID_PREDATOR_PICKUP_WEAPON: + case SID_PREDATOR_CLOAKING_ACTIVE: + case SID_PREDATOR_CLOAKING_DAMAGED: + case SID_PREDATOR_SPEARGUN_EMPTY: + case SID_PREDATOR_PLASMACASTER_TARGET_FOUND: + case SID_PREDATOR_PLASMACASTER_TARGET_LOCKED: + case SID_PREDATOR_PLASMACASTER_TARGET_LOST: + case SID_PREDATOR_PLASMACASTER_CHARGING: + case SID_PREDATOR_PLASMACASTER_EMPTY: + case SID_PREDATOR_DISK_TARGET_LOCKED: + case SID_PREDATOR_DISK_FLYING: + case SID_PREDATOR_DISK_HITTING_TARGET: + case SID_PREDATOR_DISK_HITTING_WALL: + case SID_PREDATOR_DISK_BEING_CAUGHT: + case SID_PREDATOR_DISK_RECOVERED: + case SID_PREDATOR_VOCAL_SNARL_1: + case SID_PREDATOR_VOCAL_SNARL_2: + case SID_ALIEN_TAILUNFURL: + case SID_ALIEN_TAUNT_1: + case SID_ALIEN_TAUNT_2: + case SID_PRED_JUMP_START_1: + case SID_PRED_JUMP_START_2: + case SID_PRED_JUMP_START_3: + case SID_PRED_CLOAKON: + case SID_PRED_CLOAKOFF: + case SID_PRED_SMALLLANDING: + case SID_ED_FACEHUGGERSLAP: + case SID_GRAPPLE_HIT_WALL: + case SID_GRAPPLE_THROW: + case SID_ED_ELEC_DEATH: + /* Enemy sounds! */ + return(MUL_FIXED(NormalFrameTime,-3000)); + break; + case SID_MINIGUN_END: + case SID_MINIGUN_LOOP: + case SID_INCIN_START: + case SID_INCIN_LOOP: + case SID_INCIN_END: + case SID_ROCKFIRE: + case SID_PULSE_START: + case SID_PULSE_LOOP: + case SID_PULSE_END: + case SID_SHOTGUN: + case SID_SMART1: + case SID_SMART2: + case SID_SMART3: + case SID_TRACKER_WHEEP_HIGH: + case SID_TRACKER_WHEEP_LOW: + case SID_PULSE_RIFLE_FIRING_EMPTY: + case SID_THROW_FLARE: + case SID_CONSOLE_ACTIVATES: + case SID_CONSOLE_DEACTIVATES: + case SID_CONSOLE_MARINEMESSAGE: + case SID_CONSOLE_ALIENMESSAGE: + case SID_CONSOLE_PREDATORMESSAGE: + case SID_MINIGUN_READY: + case SID_MINIGUN_EMPTY: + case SID_SMART_MODESWITCH: + case SID_GRENADE_BOUNCE: + case SID_BURNING_FLARE: + case SID_FLAMETHROWER_PILOT_LIGHT: + case SID_MARINE_JUMP_START: + case SID_MARINE_JUMP_END: + case SID_MARINE_PICKUP_WEAPON: + case SID_MARINE_PICKUP_AMMO: + case SID_MARINE_PICKUP_ARMOUR: + case SID_SENTRYGUN_LOCK: + case SID_SENTRYGUN_SHUTDOWN: + case SID_WIL_MINIGUN_READY: + case SID_SADAR_FIRE: + case SID_MARINE_JUMP_START_2: + case SID_MARINE_JUMP_START_3: + case SID_MARINE_JUMP_START_4: + case SID_ED_GRENADE_EXPLOSION: + case SID_ED_GRENADE_PROXEXPLOSION: + case SID_ED_MOLOTOV_EXPLOSION: + case SID_ED_LARGEWEAPONDROP: + case SID_MENUS_SELECT_ITEM: + case SID_MENUS_CHANGE_ITEM: + case SID_IMAGE: + case SID_IMAGE_OFF: + /* Marine type sounds. */ + return(MUL_FIXED(NormalFrameTime,300)); + break; + case SID_SWITCH1: + case SID_SWITCH2: + case SID_LIFT_START: + case SID_LIFT_LOOP: + case SID_LIFT_END: + case SID_VISION_ON: + case SID_VISION_LOOP: + case SID_FIRE: + case SID_PICKUP: + case SID_SPLASH1: + case SID_SPLASH2: + case SID_SPLASH3: + case SID_SPLASH4: + case SID_POWERUP: + case SID_POWERDN: + case SID_ACID_SPRAY: + case SID_DOORSTART: + case SID_DOORMID: + case SID_DOOREND: + case SID_BORGON: + case SID_SPARKS: + case SID_STOMP: + case SID_LOADMOVE: + case SID_NOAMMO: + case SID_LONGLOAD: + case SID_NADELOAD: + case SID_NADEFIRE: + case SID_NADEEXPLODE: + case SID_SHRTLOAD: + case SID_SENTRY_GUN: + case SID_SENTRY_END: + case SID_NICE_EXPLOSION: + case SID_EXPLOSION: + case SID_FRAG_RICOCHETS: + case SID_SPEARGUN_HITTING_WALL: + case SID_DISC_STICKSINWALL: + case SID_PREDATOR_PLASMACASTER_REDTRIANGLES: + case SID_WIL_PRED_PISTOL_EXPLOSION: + case SID_PROX_GRENADE_READYTOBLOW: + case SID_PROX_GRENADE_ACTIVE: + case SID_SENTRYGUNDEST: + /* Weird sounds. */ + return(ONE_FIXED); + break; + case SID_ARMSTART: + case SID_ARMMID: + case SID_ARMEND: + case SID_TRACKER_CLICK: + case SID_TRACKER_WHEEP: + case SID_TELETEXT: + case SID_RICOCH1: + case SID_RICOCH2: + case SID_RICOCH3: + case SID_RICOCH4: + case SID_NOSOUND: + case SID_PRED_ZOOM_IN: + case SID_PRED_ZOOM_OUT: + case SID_MARINE_SMALLLANDING: + case SID_LIGHT_FLICKER_ON: + case SID_ED_SENTRYTURN01: + case SID_PULSE_SWIPE01: + case SID_PULSE_SWIPE02: + case SID_PULSE_SWIPE03: + case SID_PULSE_SWIPE04: + case SID_ED_JETPACK_START: + case SID_ED_JETPACK_MID: + case SID_ED_JETPACK_END: + /* Basic marine sounds, and the sentrygun. */ + return(0); + break; + case SID_STARTOF_LOADSLOTS: + case SID_UNUSED_125: + case SID_UNUSED_126: + case SID_UNUSED_127: + case SID_UNUSED_128: + case SID_UNUSED_129: + case SID_UNUSED_130: + case SID_UNUSED_131: + case SID_UNUSED_132: + case SID_UNUSED_133: + case SID_UNUSED_134: + case SID_UNUSED_135: + case SID_UNUSED_136: + case SID_UNUSED_137: + case SID_UNUSED_138: + case SID_UNUSED_139: + case SID_UNUSED_140: + case SID_UNUSED_141: + case SID_UNUSED_142: + case SID_UNUSED_143: + case SID_UNUSED_144: + case SID_UNUSED_145: + case SID_UNUSED_146: + case SID_UNUSED_147: + case SID_UNUSED_148: + case SID_UNUSED_149: + case SID_ENDOF_LOADSLOTS: + /* Environment sounds. */ + return(MUL_FIXED(NormalFrameTime,-300)); + break; + default: + /* Eh? Could be a scream... */ + return(MUL_FIXED(NormalFrameTime,-1500)); + break; + } + +} + +void DoMarineHearing(STRATEGYBLOCK *sbPtr) { + + int a,nearest,neardist,dist,priority; + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH offset; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + #if 0 + /* Hearing is low priority. */ + if (marineStatusPointer->suspicious) { + return; + } + #endif + + nearest=-1; + neardist=10000000; + /* Hence, if you're still interested in something else, return. */ + + for(a=0;aAndroid==0) { + marineStatusPointer->Courage+=Marine_SoundCourageBonus(ActiveSounds[a].soundIndex); + } + if (priority) { + int test_dist; + /* Interesting sound... */ + offset.vx=sbPtr->DynPtr->Position.vx-ActiveSounds[a].threedeedata.position.vx; + offset.vy=sbPtr->DynPtr->Position.vy-ActiveSounds[a].threedeedata.position.vy; + offset.vz=sbPtr->DynPtr->Position.vz-ActiveSounds[a].threedeedata.position.vz; + + dist=Approximate3dMagnitude(&offset); + + if (ActiveSounds[a].threedeedata.outer_range==-1) { + test_dist=100000; + /* 100 m. */ + } else { + test_dist=ActiveSounds[a].threedeedata.outer_range; + } + + if (dist<=test_dist) { + /* In range. Modify by priority. */ + dist=MUL_FIXED(dist,priority); + + if (distDynPtr->Position.vx-Player->ObStrategyBlock->DynPtr->Position.vx; + offset.vy=sbPtr->DynPtr->Position.vy-Player->ObStrategyBlock->DynPtr->Position.vy; + offset.vz=sbPtr->DynPtr->Position.vz-Player->ObStrategyBlock->DynPtr->Position.vz; + + dist=Approximate3dMagnitude(&offset); + + if (dist<=100000) { + /* In range. Assume priority is ONE_FIXED. */ + if (distsuspicious=MARINE_PARANOIA_TIME; + marineStatusPointer->suspect_point=Player->ObStrategyBlock->DynPtr->Position; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + + level=2; + + } else { + + marineStatusPointer->suspicious=MARINE_PARANOIA_TIME; + marineStatusPointer->suspect_point=ActiveSounds[nearest].threedeedata.position; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + + priority=Marine_SoundInterest(ActiveSounds[nearest].soundIndex); + if (priority>ONE_FIXED) { + level=1; + } else if (prioritysuspect_point); + } + +} + +static STATE_RETURN_CONDITION Execute_MNS_Taunting(STRATEGYBLOCK *sbPtr) +{ + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if (!sbPtr->SBdptr) { + /* We're far... do the timer! */ + ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr); + } + + if (HModelAnimation_IsFinished(&marineStatusPointer->HModelController)) { + return(SRC_Request_Wait); + } else { + return(SRC_No_Change); + } + +} + +static STATE_RETURN_CONDITION Execute_MNS_Reloading(STRATEGYBLOCK *sbPtr) +{ + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if (!sbPtr->SBdptr) { + /* We're far... do the timer! */ + ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr); + } + + /* Clip management. */ + if (marineStatusPointer->My_Weapon->ClipName) { + SECTION_DATA *clip; + clip=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ClipName); + if (clip) { + /* Now, check keyframe flags. */ + if (marineStatusPointer->HModelController.keyframe_flags&4) { + /* Vanish it. */ + clip->flags|=(section_data_terminate_here|section_data_notreal); + } + + if (marineStatusPointer->HModelController.keyframe_flags&1) { + /* Trim it off. */ + MakeHierarchicalDebris(NULL,clip, &clip->World_Offset, &clip->SecMat,NULL,0); + } + + if (marineStatusPointer->HModelController.keyframe_flags&2) { + /* Put it back. */ + if ((marineStatusPointer->My_Weapon->id==MNPCW_SADAR) + ||(marineStatusPointer->My_Weapon->id==MNPCW_Skeeter)) { + SECTION *root_section; + /* Heaven help us. */ + clip->flags&=(~(section_data_terminate_here|section_data_notreal)); + + root_section=GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,marineStatusPointer->My_Weapon->HierarchyName); + GLOBALASSERT(root_section); + + Transmogrify_HModels(sbPtr,&marineStatusPointer->HModelController,root_section,0,1,1); + ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr); + marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->GunflashName); + marineStatusPointer->My_Elevation_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ElevationSection); + } else { + clip->flags&=(~(section_data_terminate_here|section_data_notreal)); + } + } + } + } + + if (HModelAnimation_IsFinished(&marineStatusPointer->HModelController)) { + marineStatusPointer->clipammo=marineStatusPointer->My_Weapon->clip_size; + return(SRC_Request_Approach); + } else { + return(SRC_No_Change); + } + +} + +static STATE_RETURN_CONDITION Execute_MNS_PanicReloading(STRATEGYBLOCK *sbPtr) +{ + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if (!sbPtr->SBdptr) { + /* We're far... do the timer! */ + ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr); + } + + /* Scream handling. */ + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + if (marineStatusPointer->incidentFlag) { + if (Marine_HasHisMouthOpen(sbPtr)) { + if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) { + Marine_PanicScream(sbPtr); + } else { + Marine_AngryScream(sbPtr); + } + } else { + /* Scream anyway? */ + Marine_PanicScream(sbPtr); + /* Open the mouth? */ + Marine_AssumePanicExpression(sbPtr); + } + } + } + + /* Clip management. */ + if (marineStatusPointer->My_Weapon->ClipName) { + SECTION_DATA *clip; + clip=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ClipName); + if (clip) { + /* Now, check keyframe flags. */ + if (marineStatusPointer->HModelController.keyframe_flags&4) { + /* Vanish it. */ + clip->flags|=(section_data_terminate_here|section_data_notreal); + } + + if (marineStatusPointer->HModelController.keyframe_flags&1) { + /* Trim it off. */ + MakeHierarchicalDebris(NULL,clip, &clip->World_Offset, &clip->SecMat,NULL,0); + } + + if (marineStatusPointer->HModelController.keyframe_flags&2) { + /* Put it back. */ + if (marineStatusPointer->My_Weapon->id==MNPCW_SADAR) { + SECTION *root_section; + /* Heaven help us. */ + clip->flags&=(~(section_data_terminate_here|section_data_notreal)); + + root_section=GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,marineStatusPointer->My_Weapon->HierarchyName); + GLOBALASSERT(root_section); + + Transmogrify_HModels(sbPtr,&marineStatusPointer->HModelController,root_section,0,1,1); + ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr); + marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->GunflashName); + marineStatusPointer->My_Elevation_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ElevationSection); + } else { + clip->flags&=(~(section_data_terminate_here|section_data_notreal)); + } + } + } + } + + if (HModelAnimation_IsFinished(&marineStatusPointer->HModelController)) { + marineStatusPointer->clipammo=marineStatusPointer->My_Weapon->clip_size; + return(SRC_Request_Approach); + } else { + return(SRC_No_Change); + } + +} + +static STATE_RETURN_CONDITION Execute_MNS_GetWeapon(STRATEGYBLOCK *sbPtr) +{ + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if (!sbPtr->SBdptr) { + /* We're far... do the timer! */ + ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr); + } + + if (HModelAnimation_IsFinished(&marineStatusPointer->HModelController)) { + return(SRC_Request_Wait); + } else { + return(SRC_No_Change); + } + +} + +int NPCFireMinigun_Core(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->weapon_variable+=(NormalFrameTime<<7); + + if (marineStatusPointer->weapon_variable>=MINIGUN_MAX_SPEED) { + + marineStatusPointer->weapon_variable=MINIGUN_MAX_SPEED; + + /* Fire! */ + DischargeLOSWeapon_Core(sbPtr); + + return(1); + } + + /* Maintain_Minigun called anyway. */ + + return(0); + +} + + +void NPC_Maintain_Minigun(STRATEGYBLOCK *sbPtr, DELTA_CONTROLLER *mgd) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (mgd==NULL) { + return; + } + + if ((marineStatusPointer->behaviourState!=MBS_Firing) + ||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening) + ||(marineStatusPointer->HModelController.Playing==0)) { + /* Not firing. */ + marineStatusPointer->weapon_variable-=(NormalFrameTime<<3); + if (marineStatusPointer->weapon_variableweapon_variable=MINIGUN_IDLE_SPEED; + } + } + + if (marineStatusPointer->weapon_variable!=marineStatusPointer->weapon_variable2) { + int hmspinrate; + + if (marineStatusPointer->weapon_variable) { + + hmspinrate=DIV_FIXED(ONE_FIXED,marineStatusPointer->weapon_variable); + + Delta_Sequence_ChangeSpeed(mgd,hmspinrate); + mgd->Playing=1; + } else { + mgd->Playing=0; + } + } + + marineStatusPointer->weapon_variable2=marineStatusPointer->weapon_variable; + +} + +static STATE_RETURN_CONDITION Execute_MNS_DischargeMinigun(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn,relPos,relPos2; + int correctlyOrientated,range; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + marineStatusPointer->HModelController.Playing=1; + + #if MARINE_STATE_PRINT + textprint("Marine firing... "); + #endif + + /* first of all, validate this state: if the target suddenly becomes cloaked, then + we should switch immediately to wait state*/ + + if (marineStatusPointer->volleySizeMy_Weapon->MinimumBurstSize) { + /* Keep firing! */ + } else { + + if(!MarineCanSeeTarget(sbPtr)) + { + + /* ... and remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + #if MARINE_STATE_PRINT + textprint("Returning no target.\n"); + #endif + marineStatusPointer->lastroundhit=0; + marineStatusPointer->lasthitsection=NULL; + return(SRC_Request_Wait); + } + } + + if (marineStatusPointer->Target) { + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + /* Fix weapon target! */ + if (marineStatusPointer->My_Weapon->TargetCallibrationShift) { + marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + } + + /* Here we must have a target. Renew suspicion for new arrivals. */ + if (NpcSquad.Squad_Suspicion==0) { + PointAlert(2,&marineStatusPointer->weaponTarget); + } + } + /* Otherwise, stay facing the same way. */ + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* I have a cunning plan... */ + { + DELTA_CONTROLLER *delta; + + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta"); + if (delta) { + if (!(DeltaAnimation_IsFinished(delta))) { + correctlyOrientated=0; + } + } + } + /* I have another cunning plan... */ + if ((marineStatusPointer->volleySize>0)&& + (marineStatusPointer->volleySizeMy_Weapon->MinimumBurstSize)) { + correctlyOrientated=1; + } + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing */ + if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) { + + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #if MARINE_STATE_PRINT + textprint("Turning to face.\n"); + #endif + marineStatusPointer->lastroundhit=0; + marineStatusPointer->lasthitsection=NULL; + return(SRC_No_Change); + } + + NPCFireMinigun_Core(sbPtr); + + if (marineStatusPointer->Target==NULL) { + /* Getting out of here! */ + return(SRC_No_Change); + } + + relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz); + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + /* Did we get him? */ + if ((NPC_IsDead(marineStatusPointer->Target)) + &&(marineStatusPointer->volleySize>=marineStatusPointer->My_Weapon->MinimumBurstSize)) { + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + if (Marine_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr)==NULL) { + /* Huzzah! */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + marineStatusPointer->lastroundhit=0; + marineStatusPointer->lasthitsection=NULL; + return(SRC_Request_Taunt); + } + } + } + + if(marineStatusPointer->stateTimer > 0) { + #if MARINE_STATE_PRINT + textprint("Returning continue at range %d.\n",range); + #endif + return(SRC_No_Change); + } + + if(range < MARINE_CLOSE_APPROACH_DISTANCE) + { + /* renew firing, as we are still too close to approach */ + marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime; + marineStatusPointer->volleySize = 0; + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + #if MARINE_STATE_PRINT + textprint("Returning too close renewal at range %d.\n",range); + #endif + + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + if (marineStatusPointer->Android==0) { + marineStatusPointer->Courage-=(ONE_FIXED>>3); + } + return(SRC_Request_Fire); + } + else + { + /* we are far enough away, so return to approach */ + + /* ... and remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #if MARINE_STATE_PRINT + textprint("Returning too far termination at range %d.\n",range); + #endif + return(SRC_Request_Approach); + } + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MNS_NullPanicFire(STRATEGYBLOCK *sbPtr) { + + /* This MUST exist to redirect weapons with no panic fire. */ + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + return(SRC_Request_Wait); + +} + +static STATE_RETURN_CONDITION Execute_MNS_PanicFireLOSWeapon(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn; + int correctlyOrientated; + int volleytime,volleyrounds; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->HModelController.Playing=1; + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + #if MARINE_STATE_PRINT + textprint("Marine panic firing... "); + #endif + + /* Stabilise sequence. */ + if (marineStatusPointer->Target==NULL) { + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) { + + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3)); + } + } else { + int offsetx,offsety,offsetz,offseta,angle1; + VECTORCH *gunpos; + int sequence=0; + /* Pick a sequence based on angle. */ + + if (marineStatusPointer->My_Elevation_Section) { + gunpos=&marineStatusPointer->My_Elevation_Section->World_Offset; + } else { + gunpos=&sbPtr->DynPtr->Position; + } + /* Aim at Target. */ + + offsetx=(marineStatusPointer->Target->DynPtr->Position.vx)-(gunpos->vx); + offsety=(marineStatusPointer->Target->DynPtr->Position.vz)-(gunpos->vz); + offseta=-((marineStatusPointer->Target->DynPtr->Position.vy)-(gunpos->vy)); + + while( (offsetx>(ONE_FIXED>>2)) + ||(offsety>(ONE_FIXED>>2)) + ||(offseta>(ONE_FIXED>>2)) + ||(offsetx<-(ONE_FIXED>>2)) + ||(offsety<-(ONE_FIXED>>2)) + ||(offseta<-(ONE_FIXED>>2))) { + + offsetx>>=1; + offsety>>=1; + offseta>>=1; + + } + + offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety)); + angle1=ArcTan(offseta,offsetz); + + if (angle1>=3072) angle1-=4096; + if (angle1>=2048) angle1=angle1-3072; + if (angle1>1024) angle1=2048-angle1; + + GLOBALASSERT(angle1>=-1024); + GLOBALASSERT(angle1<=1024); + + sequence=0; + /* Now correct for hysteresis... */ + { + int threshold22,threshold45,threshold67,threshold90,ideal_sequence; + + if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_90) { + threshold22=70; + threshold45=220; + threshold67=490; + threshold90=730; + } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_67) { + threshold22=70; + threshold45=220; + threshold67=490; + threshold90=768; + } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_45) { + threshold22=70; + threshold45=220; + threshold67=512; + threshold90=768; + } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_22) { + threshold22=70; + threshold45=256; + threshold67=512; + threshold90=768; + } else { + threshold22=90; + threshold45=256; + threshold67=512; + threshold90=768; + } + + if (angle1>threshold90) { + ideal_sequence=4; + } else if (angle1>threshold67) { + ideal_sequence=3; + } else if (angle1>threshold45) { + ideal_sequence=2; + } else if (angle1>threshold22) { + ideal_sequence=1; + } else { + ideal_sequence=0; + } + + sequence=-1; + while (sequence==-1) { + switch (ideal_sequence) { + case 0: + default: + sequence=0; + break; + case 1: + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_22)) { + sequence=1; + } else { + ideal_sequence=0; + } + break; + case 2: + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_45)) { + sequence=2; + } else { + ideal_sequence=1; + } + break; + case 3: + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_67)) { + sequence=3; + } else { + ideal_sequence=2; + } + break; + case 4: + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_90)) { + sequence=4; + } else { + ideal_sequence=3; + } + break; + } + } + } + + switch (sequence) { + case 4: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_90)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_90,-1,(ONE_FIXED>>3)); + } + break; + case 3: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_67)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_67,-1,(ONE_FIXED>>3)); + } + break; + case 2: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_45)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_45,-1,(ONE_FIXED>>3)); + } + break; + case 1: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_22)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_22,-1,(ONE_FIXED>>3)); + } + break; + case 0: + default: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3)); + } + break; + } + } + + if (marineStatusPointer->clipammo==0) { + return(SRC_Request_PanicReload); + } + + /* Scream handling. */ + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + if (marineStatusPointer->incidentFlag) { + if (Marine_HasHisMouthOpen(sbPtr)) { + if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) { + Marine_AngryScream(sbPtr); + } + } + } + } + + if (marineStatusPointer->Target==NULL) { + if (marineStatusPointer->incidentFlag) { + /* Courage roll to stop. */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) { + /* Okay, calm down a bit. */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + /* Try to be suspicious? */ + marineStatusPointer->suspicious=MARINE_PANIC_TIME; + marineStatusPointer->suspect_point=marineStatusPointer->weaponTarget; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + + return(SRC_Request_Wait); + } + } + } else { + GLOBALASSERT(marineStatusPointer->Target); + + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + if (correctlyOrientated) { + if (MarineCanSeeTarget(sbPtr)) { + /* Lost target... */ + marineStatusPointer->Target=NULL; + } + } + } + + if (NpcSquad.Squad_Suspicion==0) { + if (marineStatusPointer->Target) { + /* Here we must have a target. Renew suspicion for new arrivals. */ + PointAlert(2,&marineStatusPointer->weaponTarget); + } else { + PointAlert(1,&sbPtr->DynPtr->Position); + } + } + + /* Wait for end of tweening before we proceed. */ + if (marineStatusPointer->HModelController.Tweening!=Controller_NoTweening) { + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_No_Change); + } + + /* Right. Correctly orientated or not, we blaze away. */ + + /* look after the gun flash */ + if(marineStatusPointer->myGunFlash) { + MaintainMarineGunFlash(sbPtr); + } else { + CreateMarineGunFlash(sbPtr); + } + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + else + { + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position)); + Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + + marineStatusPointer->stateTimer -= NormalFrameTime; + + /* Volleysize is now rounds fired this state. */ + + volleytime=marineStatusPointer->My_Weapon->FiringTime-marineStatusPointer->stateTimer; + /* It was that or reverse the state timer for this state. */ + volleyrounds=MUL_FIXED(volleytime,marineStatusPointer->My_Weapon->FiringRate); + volleyrounds>>=ONE_FIXED_SHIFT; + + volleyrounds-=marineStatusPointer->volleySize; + marineStatusPointer->volleySize+=volleyrounds; + + LOCALASSERT(volleyrounds>=0); + + if (marineStatusPointer->clipammo!=-1) { + /* We're counting ammo. */ + if (volleyrounds>marineStatusPointer->clipammo) { + volleyrounds=marineStatusPointer->clipammo; + } + marineStatusPointer->clipammo-=volleyrounds; + LOCALASSERT(marineStatusPointer->clipammo>=0); + } + + /* Now fire volleyrounds bullets. */ + if (volleyrounds>0) { + VECTORCH shotvector; + + shotvector.vx=0; + shotvector.vy=0; + shotvector.vz=65535; + RotateVector(&shotvector,&marineStatusPointer->My_Gunflash_Section->SecMat); + + CastLOSProjectile(sbPtr,&marineStatusPointer->My_Gunflash_Section->World_Offset,&shotvector, marineStatusPointer->My_Weapon->Ammo_Type, volleyrounds,1); + + } + + /* Now, consider termination. */ + + if (marineStatusPointer->incidentFlag) { + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + /* Two consecutive tests... */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_Request_Retreat); + } + } + } + + return(SRC_No_Change); + +} + +static STATE_RETURN_CONDITION Execute_MNS_PanicFireFlamethrower(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn; + int correctlyOrientated; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->HModelController.Playing=1; + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + #if MARINE_STATE_PRINT + textprint("Marine panic firing... "); + #endif + + /* Stabilise sequence. */ + if (marineStatusPointer->Target==NULL) { + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) { + + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3)); + } + } else { + int offsetx,offsety,offsetz,offseta,angle1; + VECTORCH *gunpos; + int sequence=0; + /* Pick a sequence based on angle. */ + + if (marineStatusPointer->My_Elevation_Section) { + gunpos=&marineStatusPointer->My_Elevation_Section->World_Offset; + } else { + gunpos=&sbPtr->DynPtr->Position; + } + /* Aim at Target. */ + + offsetx=(marineStatusPointer->Target->DynPtr->Position.vx)-(gunpos->vx); + offsety=(marineStatusPointer->Target->DynPtr->Position.vz)-(gunpos->vz); + offseta=-((marineStatusPointer->Target->DynPtr->Position.vy)-(gunpos->vy)); + + while( (offsetx>(ONE_FIXED>>2)) + ||(offsety>(ONE_FIXED>>2)) + ||(offseta>(ONE_FIXED>>2)) + ||(offsetx<-(ONE_FIXED>>2)) + ||(offsety<-(ONE_FIXED>>2)) + ||(offseta<-(ONE_FIXED>>2))) { + + offsetx>>=1; + offsety>>=1; + offseta>>=1; + + } + + offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety)); + angle1=ArcTan(offseta,offsetz); + + if (angle1>=3072) angle1-=4096; + if (angle1>=2048) angle1=angle1-3072; + if (angle1>1024) angle1=2048-angle1; + + GLOBALASSERT(angle1>=-1024); + GLOBALASSERT(angle1<=1024); + + sequence=0; + /* Now correct for hysteresis... */ + { + int highthreshold,topthreshold; + + if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_90) { + highthreshold=90; + topthreshold=(1024-300); + } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_45) { + highthreshold=90; + topthreshold=(1024-256); + } else { + highthreshold=128; + topthreshold=(1024-256); + } + + if (angle1>topthreshold) { + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_90)) { + sequence=2; + } else { + sequence=0; + } + } else if (angle1>highthreshold) { //Was 256! + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_45)) { + sequence=1; + } else { + sequence=0; + } + } else { + sequence=0; + } + } + + switch (sequence) { + case 2: + /* Escape for civvie flamethrower here? */ + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_90)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_90,-1,(ONE_FIXED>>3)); + } + break; + case 1: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_45)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_45,-1,(ONE_FIXED>>3)); + } + break; + case 0: + default: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3)); + } + break; + } + } + + if (marineStatusPointer->Target==NULL) { + if (marineStatusPointer->incidentFlag) { + /* Courage roll to stop. */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) { + /* Okay, calm down a bit. */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + /* Try to be suspicious? */ + marineStatusPointer->suspicious=MARINE_PANIC_TIME; + marineStatusPointer->suspect_point=marineStatusPointer->weaponTarget; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + + return(SRC_Request_Wait); + } + } + } else { + GLOBALASSERT(marineStatusPointer->Target); + + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + if (correctlyOrientated) { + if (MarineCanSeeTarget(sbPtr)) { + /* Lost target... */ + marineStatusPointer->Target=NULL; + } + } + } + + if (marineStatusPointer->clipammo==0) { + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + if (marineStatusPointer->My_Weapon->ARealMarine) { + return(SRC_Request_PullPistol); + } else { + return(SRC_Request_PanicReload); + } + } else { + return(SRC_Request_PanicReload); + } + } + + /* Scream handling. */ + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + if (marineStatusPointer->incidentFlag) { + if (Marine_HasHisMouthOpen(sbPtr)) { + if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) { + Marine_AngryScream(sbPtr); + } + } + } + } + + if (NpcSquad.Squad_Suspicion==0) { + if (marineStatusPointer->Target) { + /* Here we must have a target. Renew suspicion for new arrivals. */ + PointAlert(2,&marineStatusPointer->weaponTarget); + } else { + PointAlert(1,&sbPtr->DynPtr->Position); + } + } + + /* Wait for end of tweening before we proceed. */ + if (marineStatusPointer->HModelController.Tweening!=Controller_NoTweening) { + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_No_Change); + } + + /* Right. Correctly orientated or not, we blaze away. */ + + /* look after the gun flash */ + if(marineStatusPointer->myGunFlash) { + /* No gunflash, neither. */ + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + } + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + else + { + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position)); + Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + + marineStatusPointer->stateTimer -= NormalFrameTime; + + MarineFireFlameThrower(sbPtr); + + /* Lighting? */ + if (sbPtr->SBdptr) { + AddLightingEffectToObject(sbPtr->SBdptr,LFX_MUZZLEFLASH); + } + + if (marineStatusPointer->clipammo>0) { + marineStatusPointer->clipammo-=NormalFrameTime; + if (marineStatusPointer->clipammo<0) { + marineStatusPointer->clipammo=0; + } + } + + /* Now, consider termination. */ + + if (marineStatusPointer->incidentFlag) { + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + /* Two consecutive tests... */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_Request_Retreat); + } + } + } + + return(SRC_No_Change); + +} + +void Marine_SwitchExpression(STRATEGYBLOCK *sbPtr,int state) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + SECTION_DATA *head; + TXACTRLBLK *tacb; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + head=GetThisSectionData(marineStatusPointer->HModelController.section_data,"head"); + + marineStatusPointer->Expression=state; + marineStatusPointer->Blink=-1; + + if (head) { + if ((head->flags§ion_data_notreal)==0) { + + tacb=head->tac_ptr; + + while (tacb) { + tacb->tac_sequence = state ; + tacb->tac_txah_s = GetTxAnimHeaderFromShape(tacb, head->ShapeNum); + + tacb=tacb->tac_next; + } + } + } +} + +static STATE_RETURN_CONDITION Execute_MNS_PanicFireGL(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn; + int correctlyOrientated; + int keyframeflags,a; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + marineStatusPointer->HModelController.Playing=1; + + #if MARINE_STATE_PRINT + textprint("Marine panic firing... "); + #endif + + /* Stabilise sequence. */ + if (marineStatusPointer->Target==NULL) { + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) { + + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3)); + } + } else { + int offsetx,offsety,offsetz,offseta,angle1; + VECTORCH *gunpos; + int sequence=0; + /* Pick a sequence based on angle. */ + + if (marineStatusPointer->My_Elevation_Section) { + gunpos=&marineStatusPointer->My_Elevation_Section->World_Offset; + } else { + gunpos=&sbPtr->DynPtr->Position; + } + /* Aim at Target. */ + + offsetx=(marineStatusPointer->Target->DynPtr->Position.vx)-(gunpos->vx); + offsety=(marineStatusPointer->Target->DynPtr->Position.vz)-(gunpos->vz); + offseta=-((marineStatusPointer->Target->DynPtr->Position.vy)-(gunpos->vy)); + + while( (offsetx>(ONE_FIXED>>2)) + ||(offsety>(ONE_FIXED>>2)) + ||(offseta>(ONE_FIXED>>2)) + ||(offsetx<-(ONE_FIXED>>2)) + ||(offsety<-(ONE_FIXED>>2)) + ||(offseta<-(ONE_FIXED>>2))) { + + offsetx>>=1; + offsety>>=1; + offseta>>=1; + + } + + offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety)); + angle1=ArcTan(offseta,offsetz); + + if (angle1>=3072) angle1-=4096; + if (angle1>=2048) angle1=angle1-3072; + if (angle1>1024) angle1=2048-angle1; + + GLOBALASSERT(angle1>=-1024); + GLOBALASSERT(angle1<=1024); + + sequence=0; + /* Now correct for hysteresis... */ + { + int highthreshold,topthreshold; + + if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_90) { + highthreshold=90; + topthreshold=(1024-300); + } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_45) { + highthreshold=90; + topthreshold=(1024-256); + } else { + highthreshold=128; + topthreshold=(1024-256); + } + + if (angle1>topthreshold) { + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_90)) { + sequence=2; + } else { + sequence=0; + } + } else if (angle1>highthreshold) { //Was 256! + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_45)) { + sequence=1; + } else { + sequence=0; + } + } else { + sequence=0; + } + } + + switch (sequence) { + case 2: + /* Escape for civvie flamethrower here? */ + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_90)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_90,-1,(ONE_FIXED>>3)); + } + break; + case 1: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_45)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_45,-1,(ONE_FIXED>>3)); + } + break; + case 0: + default: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3)); + } + break; + } + } + + if (marineStatusPointer->Target==NULL) { + if (marineStatusPointer->incidentFlag) { + /* Courage roll to stop. */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) { + /* Okay, calm down a bit. */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + /* Try to be suspicious? */ + marineStatusPointer->suspicious=MARINE_PANIC_TIME; + marineStatusPointer->suspect_point=marineStatusPointer->weaponTarget; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + + return(SRC_Request_Wait); + } + } + } else { + GLOBALASSERT(marineStatusPointer->Target); + + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + if (correctlyOrientated) { + if (MarineCanSeeTarget(sbPtr)) { + /* Lost target... */ + marineStatusPointer->Target=NULL; + } + } + } + + if (marineStatusPointer->clipammo==0) { + /* Reload here. */ + return(SRC_Request_PanicReload); + } + + /* Scream handling. */ + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + if (marineStatusPointer->incidentFlag) { + if (Marine_HasHisMouthOpen(sbPtr)) { + if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) { + Marine_AngryScream(sbPtr); + } + } + } + } + + if (NpcSquad.Squad_Suspicion==0) { + if (marineStatusPointer->Target) { + /* Here we must have a target. Renew suspicion for new arrivals. */ + PointAlert(2,&marineStatusPointer->weaponTarget); + } else { + PointAlert(1,&sbPtr->DynPtr->Position); + } + } + + /* Wait for end of tweening before we proceed. */ + if (marineStatusPointer->HModelController.Tweening!=Controller_NoTweening) { + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_No_Change); + } + + /* Stop cues anyway? */ + if(marineStatusPointer->myGunFlash) { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + if (marineStatusPointer->Target) { + int range; + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + /* Are they, by some chance, really close? */ + if (rangeMy_Weapon->MinRange) { + if (!(MarineRetreatsInTheFaceOfDanger(sbPtr))) { + /* Stay cool. */ + return(SRC_Request_PullPistol); + } + /* Probably can't flee... :-) */ + } + } + + /* Right. Correctly orientated or not, we blaze away. */ + + keyframeflags=marineStatusPointer->HModelController.keyframe_flags>>1; + + /* I know there are only four firing points... */ + for (a=0; a<4; a++) { + if (keyframeflags&1) { + /* Fire a grenade! */ + + /* look after the gun flash */ + if(marineStatusPointer->myGunFlash) MaintainMarineGunFlash(sbPtr); + else CreateMarineGunFlash(sbPtr); + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + else { + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position)); + Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + + LOCALASSERT(marineStatusPointer->My_Gunflash_Section); + CreateGrenadeKernel(I_BehaviourGrenade, &marineStatusPointer->My_Gunflash_Section->World_Offset, &marineStatusPointer->My_Gunflash_Section->SecMat,0); + if (marineStatusPointer->clipammo>0) { + marineStatusPointer->clipammo--; + } + } + keyframeflags>>=1; + } + /* ...and they are all identical. */ + + /* Now, consider termination. */ + + if (marineStatusPointer->incidentFlag) { + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + /* Two consecutive tests... */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_Request_Retreat); + } + } + } + + return(SRC_No_Change); + +} + +static STATE_RETURN_CONDITION Execute_MNS_PanicFireMinigun(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn; + int correctlyOrientated; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->HModelController.Playing=1; + + #if MARINE_STATE_PRINT + textprint("Marine panic firing... "); + #endif + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* Stabilise sequence. */ + if (marineStatusPointer->Target==NULL) { + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) { + + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3)); + } + } else { + int offsetx,offsety,offsetz,offseta,angle1; + VECTORCH *gunpos; + int sequence=0; + /* Pick a sequence based on angle. */ + + if (marineStatusPointer->My_Elevation_Section) { + gunpos=&marineStatusPointer->My_Elevation_Section->World_Offset; + } else { + gunpos=&sbPtr->DynPtr->Position; + } + /* Aim at Target. */ + + offsetx=(marineStatusPointer->Target->DynPtr->Position.vx)-(gunpos->vx); + offsety=(marineStatusPointer->Target->DynPtr->Position.vz)-(gunpos->vz); + offseta=-((marineStatusPointer->Target->DynPtr->Position.vy)-(gunpos->vy)); + + while( (offsetx>(ONE_FIXED>>2)) + ||(offsety>(ONE_FIXED>>2)) + ||(offseta>(ONE_FIXED>>2)) + ||(offsetx<-(ONE_FIXED>>2)) + ||(offsety<-(ONE_FIXED>>2)) + ||(offseta<-(ONE_FIXED>>2))) { + + offsetx>>=1; + offsety>>=1; + offseta>>=1; + + } + + offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety)); + angle1=ArcTan(offseta,offsetz); + + if (angle1>=3072) angle1-=4096; + if (angle1>=2048) angle1=angle1-3072; + if (angle1>1024) angle1=2048-angle1; + + GLOBALASSERT(angle1>=-1024); + GLOBALASSERT(angle1<=1024); + + sequence=0; + /* Now correct for hysteresis... */ + { + int highthreshold,topthreshold; + + if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_90) { + highthreshold=90; + topthreshold=(1024-300); + } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_45) { + highthreshold=90; + topthreshold=(1024-256); + } else { + highthreshold=128; + topthreshold=(1024-256); + } + + if (angle1>topthreshold) { + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_90)) { + sequence=2; + } else { + sequence=0; + } + } else if (angle1>highthreshold) { //Was 256! + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_45)) { + sequence=1; + } else { + sequence=0; + } + } else { + sequence=0; + } + } + + switch (sequence) { + case 2: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_90)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_90,-1,(ONE_FIXED>>3)); + } + break; + case 1: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_45)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_45,-1,(ONE_FIXED>>3)); + } + break; + case 0: + default: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3)); + } + break; + } + } + + if (marineStatusPointer->clipammo==0) { + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + return(SRC_Request_PullPistol); + } else { + return(SRC_Request_PanicReload); + } + } + + /* Scream handling. */ + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + if (marineStatusPointer->incidentFlag) { + if (Marine_HasHisMouthOpen(sbPtr)) { + if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) { + Marine_AngryScream(sbPtr); + } + } + } + } + + if ((marineStatusPointer->Target==NULL)&&(marineStatusPointer->volleySize>=marineStatusPointer->My_Weapon->MinimumBurstSize)) { + if (marineStatusPointer->incidentFlag) { + /* Courage roll to stop. */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) { + /* Okay, calm down a bit. */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + /* Try to be suspicious? */ + marineStatusPointer->suspicious=MARINE_PANIC_TIME; + marineStatusPointer->suspect_point=marineStatusPointer->weaponTarget; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + + return(SRC_Request_Wait); + } + } + } else { + if (marineStatusPointer->Target) { + + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + if (correctlyOrientated) { + if (MarineCanSeeTarget(sbPtr)) { + /* Lost target... */ + marineStatusPointer->Target=NULL; + } + } + } else { + /* Who cares! */ + correctlyOrientated=1; + } + } + + if (NpcSquad.Squad_Suspicion==0) { + if (marineStatusPointer->Target) { + /* Here we must have a target. Renew suspicion for new arrivals. */ + PointAlert(2,&marineStatusPointer->weaponTarget); + } else { + PointAlert(1,&sbPtr->DynPtr->Position); + } + } + + /* Wait for end of tweening before we proceed. */ + if (marineStatusPointer->HModelController.Tweening!=Controller_NoTweening) { + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_No_Change); + } + + /* Right. Correctly orientated or not, we blaze away. */ + + NPCFireMinigun_Core(sbPtr); + + /* Now, consider termination. */ + + if (marineStatusPointer->volleySizeincidentFlag) { + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + /* Two consecutive tests... */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_Request_Retreat); + } + } + } + + return(SRC_No_Change); + +} + +static STATE_RETURN_CONDITION Execute_MNS_PanicFirePistol(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn; + int correctlyOrientated; + int a,keyframeflags; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->HModelController.Playing=1; + + #if MARINE_STATE_PRINT + textprint("Marine panic firing... "); + #endif + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* Stabilise sequence. */ + if (marineStatusPointer->Target==NULL) { + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) { + + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3)); + } + } else { + int offsetx,offsety,offsetz,offseta,angle1; + VECTORCH *gunpos; + int sequence=0; + /* Pick a sequence based on angle. */ + + if (marineStatusPointer->My_Elevation_Section) { + gunpos=&marineStatusPointer->My_Elevation_Section->World_Offset; + } else { + gunpos=&sbPtr->DynPtr->Position; + } + /* Aim at Target. */ + + offsetx=(marineStatusPointer->Target->DynPtr->Position.vx)-(gunpos->vx); + offsety=(marineStatusPointer->Target->DynPtr->Position.vz)-(gunpos->vz); + offseta=-((marineStatusPointer->Target->DynPtr->Position.vy)-(gunpos->vy)); + + while( (offsetx>(ONE_FIXED>>2)) + ||(offsety>(ONE_FIXED>>2)) + ||(offseta>(ONE_FIXED>>2)) + ||(offsetx<-(ONE_FIXED>>2)) + ||(offsety<-(ONE_FIXED>>2)) + ||(offseta<-(ONE_FIXED>>2))) { + + offsetx>>=1; + offsety>>=1; + offseta>>=1; + + } + + offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety)); + angle1=ArcTan(offseta,offsetz); + + if (angle1>=3072) angle1-=4096; + if (angle1>=2048) angle1=angle1-3072; + if (angle1>1024) angle1=2048-angle1; + + GLOBALASSERT(angle1>=-1024); + GLOBALASSERT(angle1<=1024); + + sequence=0; + /* Now correct for hysteresis... */ + { + int highthreshold,topthreshold; + + if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_90) { + highthreshold=90; + topthreshold=(1024-300); + } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_45) { + highthreshold=90; + topthreshold=(1024-256); + } else { + highthreshold=128; + topthreshold=(1024-256); + } + + if (angle1>topthreshold) { + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_90)) { + sequence=2; + } else { + sequence=0; + } + } else if (angle1>highthreshold) { //Was 256! + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_45)) { + sequence=1; + } else { + sequence=0; + } + } else { + sequence=0; + } + } + + switch (sequence) { + case 2: + /* Escape for civvie flamethrower here? */ + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_90)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_90,-1,(ONE_FIXED>>3)); + } + break; + case 1: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_45)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_45,-1,(ONE_FIXED>>3)); + } + break; + case 0: + default: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3)); + } + break; + } + } + + if (marineStatusPointer->clipammo==0) { + return(SRC_Request_PanicReload); + } + + /* Scream handling. */ + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + if (marineStatusPointer->incidentFlag) { + if (Marine_HasHisMouthOpen(sbPtr)) { + if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) { + Marine_AngryScream(sbPtr); + } + } + } + } + + if (marineStatusPointer->Target==NULL) { + if (marineStatusPointer->incidentFlag) { + /* Courage roll to stop. */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) { + /* Okay, calm down a bit. */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + /* Try to be suspicious? */ + marineStatusPointer->suspicious=MARINE_PANIC_TIME; + marineStatusPointer->suspect_point=marineStatusPointer->weaponTarget; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + + return(SRC_Request_Wait); + } + } + } else { + GLOBALASSERT(marineStatusPointer->Target); + + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + /* Fix weapon target! */ + if (marineStatusPointer->My_Weapon->TargetCallibrationShift) { + marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + } + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + if (correctlyOrientated) { + if (MarineCanSeeTarget(sbPtr)) { + /* Lost target... */ + marineStatusPointer->Target=NULL; + } + } + } + + if (NpcSquad.Squad_Suspicion==0) { + if (marineStatusPointer->Target) { + /* Here we must have a target. Renew suspicion for new arrivals. */ + PointAlert(2,&marineStatusPointer->weaponTarget); + } else { + PointAlert(1,&sbPtr->DynPtr->Position); + } + } + + /* Wait for end of tweening before we proceed. */ + if (marineStatusPointer->HModelController.Tweening!=Controller_NoTweening) { + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_No_Change); + } + + /* Stop cues anyway? */ + if(marineStatusPointer->myGunFlash) { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + /* Right. Correctly orientated or not, we blaze away. */ + + keyframeflags=marineStatusPointer->HModelController.keyframe_flags>>1; + + /* I know there are only six possible firing points... */ + for (a=0; a<6; a++) { + if ((keyframeflags&1)||((a==0)&&(marineStatusPointer->HModelController.Tweening==Controller_EndTweening))) { + /* Fire a shot. */ + + /* look after the gun flash */ + if(marineStatusPointer->myGunFlash) MaintainMarineGunFlash(sbPtr); + else CreateMarineGunFlash(sbPtr); + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + else { + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position)); + Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + + { + VECTORCH shotvector; + + shotvector.vx=0; + shotvector.vy=0; + shotvector.vz=65535; + RotateVector(&shotvector,&marineStatusPointer->My_Gunflash_Section->SecMat); + + CastLOSProjectile(sbPtr,&marineStatusPointer->My_Gunflash_Section->World_Offset,&shotvector, marineStatusPointer->My_Weapon->Ammo_Type, 1,1); + if (marineStatusPointer->clipammo>0) { + marineStatusPointer->clipammo--; + } + } + } + keyframeflags>>=1; + } + /* ...and they are all identical. */ + + /* Now, consider termination. */ + + if (marineStatusPointer->incidentFlag) { + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + /* Two consecutive tests... */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_Request_Retreat); + } + } + } + + return(SRC_No_Change); + +} + +static STATE_RETURN_CONDITION Execute_MNS_PanicFireShotgun(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn; + int correctlyOrientated; + int keyframeflags,a,b; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->HModelController.Playing=1; + + #if MARINE_STATE_PRINT + textprint("Marine panic firing... "); + #endif + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* Stabilise sequence. */ + if (marineStatusPointer->Target==NULL) { + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) { + + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3)); + } + } else { + int offsetx,offsety,offsetz,offseta,angle1; + VECTORCH *gunpos; + int sequence=0; + /* Pick a sequence based on angle. */ + + if (marineStatusPointer->My_Elevation_Section) { + gunpos=&marineStatusPointer->My_Elevation_Section->World_Offset; + } else { + gunpos=&sbPtr->DynPtr->Position; + } + /* Aim at Target. */ + + offsetx=(marineStatusPointer->Target->DynPtr->Position.vx)-(gunpos->vx); + offsety=(marineStatusPointer->Target->DynPtr->Position.vz)-(gunpos->vz); + offseta=-((marineStatusPointer->Target->DynPtr->Position.vy)-(gunpos->vy)); + + while( (offsetx>(ONE_FIXED>>2)) + ||(offsety>(ONE_FIXED>>2)) + ||(offseta>(ONE_FIXED>>2)) + ||(offsetx<-(ONE_FIXED>>2)) + ||(offsety<-(ONE_FIXED>>2)) + ||(offseta<-(ONE_FIXED>>2))) { + + offsetx>>=1; + offsety>>=1; + offseta>>=1; + + } + + offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety)); + angle1=ArcTan(offseta,offsetz); + + if (angle1>=3072) angle1-=4096; + if (angle1>=2048) angle1=angle1-3072; + if (angle1>1024) angle1=2048-angle1; + + GLOBALASSERT(angle1>=-1024); + GLOBALASSERT(angle1<=1024); + + sequence=0; + /* Now correct for hysteresis... */ + { + int highthreshold,topthreshold; + + if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_90) { + highthreshold=90; + topthreshold=(1024-300); + } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_45) { + highthreshold=90; + topthreshold=(1024-256); + } else { + highthreshold=128; + topthreshold=(1024-256); + } + + if (angle1>topthreshold) { + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_90)) { + sequence=2; + } else { + sequence=0; + } + } else if (angle1>highthreshold) { //Was 256! + if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_45)) { + sequence=1; + } else { + sequence=0; + } + } else { + sequence=0; + } + } + + switch (sequence) { + case 2: + /* Escape for civvie flamethrower here? */ + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_90)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_90,-1,(ONE_FIXED>>3)); + } + break; + case 1: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_45)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_45,-1,(ONE_FIXED>>3)); + } + break; + case 0: + default: + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3)); + } + break; + } + } + + if (marineStatusPointer->clipammo==0) { + return(SRC_Request_PanicReload); + } + + /* Scream handling. */ + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + if (marineStatusPointer->incidentFlag) { + if (Marine_HasHisMouthOpen(sbPtr)) { + if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) { + Marine_AngryScream(sbPtr); + } + } + } + } + + if (marineStatusPointer->Target==NULL) { + if (marineStatusPointer->incidentFlag) { + /* Courage roll to stop. */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) { + /* Okay, calm down a bit. */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + /* Try to be suspicious? */ + marineStatusPointer->suspicious=MARINE_PANIC_TIME; + marineStatusPointer->suspect_point=marineStatusPointer->weaponTarget; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + + return(SRC_Request_Wait); + } + } + } else { + GLOBALASSERT(marineStatusPointer->Target); + + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + if (correctlyOrientated) { + if (MarineCanSeeTarget(sbPtr)) { + /* Lost target... */ + marineStatusPointer->Target=NULL; + } + } + } + + if (NpcSquad.Squad_Suspicion==0) { + if (marineStatusPointer->Target) { + /* Here we must have a target. Renew suspicion for new arrivals. */ + PointAlert(2,&marineStatusPointer->weaponTarget); + } else { + PointAlert(1,&sbPtr->DynPtr->Position); + } + } + + /* Wait for end of tweening before we proceed. */ + if (marineStatusPointer->HModelController.Tweening!=Controller_NoTweening) { + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_No_Change); + } + + /* Stop cues anyway? */ + if(marineStatusPointer->myGunFlash) { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + /* Right. Correctly orientated or not, we blaze away. */ + + keyframeflags=marineStatusPointer->HModelController.keyframe_flags>>1; + + /* I know there are only three firing points... */ + for (a=0; a<3; a++) { + if (keyframeflags&1) { + + /* look after the gun flash */ + if(marineStatusPointer->myGunFlash) MaintainMarineGunFlash(sbPtr); + else CreateMarineGunFlash(sbPtr); + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + else { + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position)); + Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + + /* Now hit the target with a shotgun blast. */ + + b=0; + + while (ShotgunBlast[b].vz>0) { + VECTORCH world_vec; + + RotateAndCopyVector(&ShotgunBlast[b],&world_vec,&marineStatusPointer->My_Gunflash_Section->SecMat); + CastLOSProjectile(sbPtr,&marineStatusPointer->My_Gunflash_Section->World_Offset,&world_vec, marineStatusPointer->My_Weapon->Ammo_Type, 1,0); + + b++; + } + if (marineStatusPointer->clipammo>0) { + marineStatusPointer->clipammo--; + } + } + keyframeflags>>=1; + } + /* ...and they are all identical. */ + + /* Now, consider termination. */ + + if (marineStatusPointer->incidentFlag) { + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + /* Two consecutive tests... */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_Request_Retreat); + } + } + } + + return(SRC_No_Change); + +} + +static void Marine_EnterExtremePanicAnimation(STRATEGYBLOCK *sbPtr) { + + if ((FastRandom()&65535)<21845) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_90,-1,(ONE_FIXED>>1)); + } else if ((FastRandom()&65535)<21845) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_45,-1,(ONE_FIXED>>1)); + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>1)); + } + +} + +static void Marine_EnterLesserPanicAnimation(STRATEGYBLOCK *sbPtr) { + + if ((FastRandom()&65535)<32767) { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Panic_One,-1,(ONE_FIXED>>1)); + } else { + SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Panic_Two,-1,(ONE_FIXED>>1)); + } + +} + +static STATE_RETURN_CONDITION Execute_MNS_PanicFireUnarmed(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn; + + /* Also known as... gibber in terror. */ + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->HModelController.Playing=1; + + #if MARINE_STATE_PRINT + textprint("Marine panic firing... "); + #endif + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* Firstly, are we trying to retreat? */ + if (marineStatusPointer->internalState==1) { + /* Wait for tweening to finish... */ + if (marineStatusPointer->HModelController.Tweening==Controller_NoTweening) { + /* Then the first incidentFlag we get, we're outta here. */ + if (marineStatusPointer->incidentFlag) { + return(SRC_Request_Retreat); + } + } + return(SRC_No_Change); + } + + /* Stabilise sequence. */ + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||((marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) + &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_45) + &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_90)) { + + /* If we're not in one of the 'extreme panic' animations, are we in one of the others? */ + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||((marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Panic_One)) + &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Panic_Two)) { + /* No, we're not. See which level of panic to go into... */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + /* It's PaNiC tImE! */ + Marine_EnterExtremePanicAnimation(sbPtr); + } else { + /* Just look worried. */ + Marine_EnterLesserPanicAnimation(sbPtr); + } + } else { + /* Yes, we are. Is it getting worse? */ + int range; + STRATEGYBLOCK *threat; + + if (marineStatusPointer->incidentFlag) { + + threat=Marine_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr); + if (threat) { + range=VectorDistance(&sbPtr->DynPtr->Position,&threat->DynPtr->Position); + } else { + range=100000; + } + + if ((MarineRetreatsInTheFaceOfDanger(sbPtr))||(range<3000)) { + if (range<3000) { + if (marineStatusPointer->Android==0) { + marineStatusPointer->Courage-=5000; + } + } + Marine_EnterExtremePanicAnimation(sbPtr); + } else { + /* Feeling really brave? */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) { + Marine_QueueGrimaceExpression(sbPtr); + } + } + } + /* Else remain as you were. */ + } + } else { + /* We are in extreme panic. Is it getting better? */ + if (marineStatusPointer->incidentFlag) { + if ((FastRandom()&65535)<13107) { + if (!(MarineRetreatsInTheFaceOfDanger(sbPtr))) { + if (!(MarineRetreatsInTheFaceOfDanger(sbPtr))) { + /* Two consecutive tests. */ + Marine_EnterLesserPanicAnimation(sbPtr); + } + } + } + } + /* Enforce panic expression, too. */ + Marine_QueuePanicExpression(sbPtr); + } + + if (marineStatusPointer->Target==NULL) { + /* Civvies with courage 0 get a bonus to shut up... */ + if (marineStatusPointer->Courage==0) { + /* No reason to block this for Androids. */ + marineStatusPointer->Courage=5000; + } + + if (marineStatusPointer->incidentFlag) { + /* Courage roll to stop. */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) { + /* Okay, calm down a bit. */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + /* Try to be suspicious? */ + marineStatusPointer->suspicious=MARINE_PANIC_TIME; + marineStatusPointer->suspect_point=marineStatusPointer->weaponTarget; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||((marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Panic_One)) + &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Panic_Two)) { + Marine_EnterLesserPanicAnimation(sbPtr); + return(SRC_No_Change); + } else { + return(SRC_Request_Wait); + } + } + } + } else { + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + + /* May as well keep an eye out. */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + #if 0 + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + #endif + } + + /* Scream handling. */ + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + if (marineStatusPointer->incidentFlag) { + if (Marine_HasHisMouthOpen(sbPtr)) { + Marine_Sobbing(sbPtr); + } else { + /* Start yelling again? */ + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + Marine_QueuePanicExpression(sbPtr); + } + } + } + } + + if (NpcSquad.Squad_Suspicion==0) { + if (marineStatusPointer->Target) { + /* Here we must have a target. Renew suspicion for new arrivals. */ + PointAlert(2,&marineStatusPointer->weaponTarget); + } else { + PointAlert(1,&sbPtr->DynPtr->Position); + } + } + + /* Wait for end of tweening before we proceed. */ + if (marineStatusPointer->HModelController.Tweening!=Controller_NoTweening) { + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_No_Change); + } + + /* No functionality in here... */ + + marineStatusPointer->stateTimer -= NormalFrameTime; + + /* Now, consider termination. */ + + if (marineStatusPointer->incidentFlag) { + if ((FastRandom()&65535)<13107) { + if ((!(MarineRetreatsInTheFaceOfDanger(sbPtr))) + ||(!(MarineRetreatsInTheFaceOfDanger(sbPtr)))) { + /* Two chances... */ + + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand) + ||((marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Panic_One)) + &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Panic_Two)) { + Marine_EnterLesserPanicAnimation(sbPtr); + marineStatusPointer->internalState=1; + /* This is a bit pre-emptive, but never mind. */ + if (marineStatusPointer->Android==0) { + marineStatusPointer->Courage-=5000; + } + return(SRC_No_Change); + } else { + return(SRC_Request_Retreat); + } + } + } + } + + return(SRC_No_Change); + +} + +void Marine_AssumeNeutralExpression(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if ((marineStatusPointer->Expression>2)&&(marineStatusPointer->Expression<6)) { + /* In a blink. */ + Marine_SwitchExpression(sbPtr,3); + if (marineStatusPointer->Blink<0) { + /* Dunno why, but you never know. */ + marineStatusPointer->Blink=0; + } + } else { + /* Not in a blink. */ + Marine_SwitchExpression(sbPtr,0); + } + +} + +void Marine_AssumeGrimaceExpression(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if ((marineStatusPointer->Expression>2)&&(marineStatusPointer->Expression<6)) { + /* In a blink. */ + Marine_SwitchExpression(sbPtr,4); + if (marineStatusPointer->Blink<0) { + /* Dunno why, but you never know. */ + marineStatusPointer->Blink=0; + } + } else { + /* Not in a blink. */ + Marine_SwitchExpression(sbPtr,1); + } + +} + +void Marine_AssumePanicExpression(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if ((marineStatusPointer->Expression>2)&&(marineStatusPointer->Expression<6)) { + /* In a blink. */ + Marine_SwitchExpression(sbPtr,5); + if (marineStatusPointer->Blink<0) { + /* Dunno why, but you never know. */ + marineStatusPointer->Blink=0; + } + } else { + /* Not in a blink. */ + Marine_SwitchExpression(sbPtr,2); + } + +} + +void Marine_AssumeWink1Expression(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Who cares about blinking? */ + Marine_SwitchExpression(sbPtr,6); + marineStatusPointer->Blink=-1; + +} + +void Marine_AssumeWink2Expression(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* Who cares about blinking? */ + Marine_SwitchExpression(sbPtr,7); + marineStatusPointer->Blink=-1; + +} + +static STATE_RETURN_CONDITION Execute_MNS_PumpAction(STRATEGYBLOCK *sbPtr) +{ + + MARINE_STATUS_BLOCK *marineStatusPointer; + int range; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if (!sbPtr->SBdptr) { + /* We're far... do the timer! */ + ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr); + } + + if (!(HModelAnimation_IsFinished(&marineStatusPointer->HModelController))) { + return(SRC_No_Change); + } + + /* Exit procedure... same as firing was. */ + + if (marineStatusPointer->Target==NULL) { + return(SRC_Request_Wait); + } + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + /* State timer should be continuous from fire state. */ + if(marineStatusPointer->stateTimer > 0) { + #if MARINE_STATE_PRINT + textprint("Returning firing at range %d.\n",range); + #endif + return(SRC_Request_Fire); + } + + if(range < MARINE_CLOSE_APPROACH_DISTANCE) + { + /* renew firing, as we are still too close to approach */ + marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime; + marineStatusPointer->volleySize = 0; + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + #if MARINE_STATE_PRINT + textprint("Returning too close firing at range %d.\n",range); + #endif + return(SRC_Request_Fire); + } + else + { + /* we are far enough away, so return to approach */ + + if (marineStatusPointer->Android) { + return(SRC_Request_Fire); + } else { + #if MARINE_STATE_PRINT + textprint("Returning too far termination at range %d.\n",range); + #endif + return(SRC_Request_Approach); + } + } + return(SRC_Request_Fire); + +} + +void Marine_CorpseSightingTest(STRATEGYBLOCK *corpse) { + + int a; + STRATEGYBLOCK *candidate; + MARINE_STATUS_BLOCK *marineStatusPointer; + + /* This is called from CORPSE behaviour. */ + for (a=0; aI_SBtype==I_BehaviourMarine) { + /* Are you already suspicious? */ + marineStatusPointer = (MARINE_STATUS_BLOCK *)(candidate->SBdataptr); + + if (((marineStatusPointer->suspicious==0)||(marineStatusPointer->using_squad_suspicion)) + /* As if we'd care... */ + &&(marineStatusPointer->Target==NULL) + /* To make the tests a bit rarer. */ + &&(marineStatusPointer->incidentFlag)) { + /* Did you see that? */ + if (NPCCanSeeTarget(candidate,corpse,MARINE_NEAR_VIEW_WIDTH)) { + /* Okay, react. */ + marineStatusPointer->suspicious=MARINE_PARANOIA_TIME; + marineStatusPointer->suspect_point=corpse->DynPtr->Position; + /* Set this to zero when you get a *new* suspicion. */ + marineStatusPointer->previous_suspicion=0; + marineStatusPointer->using_squad_suspicion=0; + } + } + } + } +} + +void Marine_MuteVoice(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if(marineStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) { + /* Cut them off! */ + Sound_Stop(marineStatusPointer->soundHandle2); + } + +} + +void Marine_OoophSound(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) { + return; + } + + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + PlayMarineScream(marineStatusPointer->Voice,SC_Oooph,marineStatusPointer->VoicePitch, + &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + } +} + +void Marine_SurpriseSound(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) { + return; + } + + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + PlayMarineScream(marineStatusPointer->Voice,SC_Surprise,marineStatusPointer->VoicePitch, + &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + if (marineStatusPointer->Android==0) { + marineStatusPointer->Courage-=5000; + } + } + + /* Open the mouth? */ + Marine_AssumePanicExpression(sbPtr); + +} + +void Marine_WoundedScream(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) { + return; + } + + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + PlayMarineScream(marineStatusPointer->Voice,SC_Pain,marineStatusPointer->VoicePitch, + &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + } +} + +void Marine_AcidScream(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) { + return; + } + + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + PlayMarineScream(marineStatusPointer->Voice,SC_Acid,marineStatusPointer->VoicePitch, + &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + } +} + +void Marine_BurningScream(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) { + return; + } + + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + PlayMarineScream(marineStatusPointer->Voice,SC_OnFire,marineStatusPointer->VoicePitch, + &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + } + /* Urgh, that was really grim. */ + +} + +void Marine_DeathScream(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) { + return; + } + + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + /* I figure if you're screaming already, forget it. */ + PlayMarineScream(marineStatusPointer->Voice,SC_Death,marineStatusPointer->VoicePitch, + &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + } + +} + +void Marine_ElectrocutionScream(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) { + return; + } + + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + /* I figure if you're screaming already, forget it. */ + PlayMarineScream(marineStatusPointer->Voice,SC_Electrocution,marineStatusPointer->VoicePitch, + &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + } + +} + +void Marine_BurningDeathScream(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) { + return; + } + + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + /* I figure if you're screaming already, forget it. */ + PlayMarineScream(marineStatusPointer->Voice,SC_OnFire,marineStatusPointer->VoicePitch, + &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + } + /* That too was really quite unpleasant. */ + +} + +void Marine_AngryScream(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) { + return; + } + + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + PlayMarineScream(marineStatusPointer->Voice,SC_Angry,marineStatusPointer->VoicePitch, + &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + } +} + +void Marine_PanicScream(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) { + return; + } + + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + PlayMarineScream(marineStatusPointer->Voice,SC_Panic,marineStatusPointer->VoicePitch, + &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + } +} + +void Marine_Sobbing(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) { + return; + } + + /* This is getting quite upsetting... */ + + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + PlayMarineScream(marineStatusPointer->Voice,SC_Sobbing,marineStatusPointer->VoicePitch, + &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + } +} + +void Marine_TauntShout(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) { + return; + } + + if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + PlayMarineScream(marineStatusPointer->Voice,SC_Taunt,marineStatusPointer->VoicePitch, + &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + } +} + +int Marine_HasHisMouthOpen(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if ((marineStatusPointer->Expression==2)||(marineStatusPointer->Expression==5)) { + /* yeah, okay, it's hard coded. */ + return(1); + } else { + return(0); + } + +} + +void Marine_QueueNeutralExpression(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->Target_Expression=0; + +} + +void Marine_QueueGrimaceExpression(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->Target_Expression=1; + +} + +void Marine_QueuePanicExpression(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->Target_Expression=2; + +} + +void Marine_QueueWink1Expression(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->Target_Expression=6; + +} + +void Marine_QueueWink2Expression(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->Target_Expression=7; + +} + +void Marine_UpdateFace(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Expression!=marineStatusPointer->Target_Expression) { + /* Right, consider this. */ + if (Marine_HasHisMouthOpen(sbPtr)) { + /* Does the target expression also have it's mouth open? */ + if (!((marineStatusPointer->Target_Expression==2)||(marineStatusPointer->Target_Expression==5))) { + /* Are we screaming? */ + if (marineStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) { + /* Can't close our mouth yet. */ + return; + } + } + } + } + /* Also ignore if you're in the wink counterpart of the target. */ + switch (marineStatusPointer->Target_Expression) { + case 0: + if (marineStatusPointer->Expression==3) { + return; + } + break; + case 1: + if (marineStatusPointer->Expression==4) { + return; + } + break; + case 2: + if (marineStatusPointer->Expression==5) { + return; + } + break; + default: + break; + } + /* Exit if current==target? */ + if (marineStatusPointer->Expression==marineStatusPointer->Target_Expression) { + return; + } + + /* If we got here, it must be okay... but do it properly! */ + switch (marineStatusPointer->Target_Expression) { + case 0: + case 3: + Marine_AssumeNeutralExpression(sbPtr); + break; + case 1: + case 4: + Marine_AssumeGrimaceExpression(sbPtr); + break; + case 2: + case 5: + Marine_AssumePanicExpression(sbPtr); + break; + case 6: + Marine_AssumeWink1Expression(sbPtr); + break; + case 7: + Marine_AssumeWink2Expression(sbPtr); + break; + default: + GLOBALASSERT(0); + break; + } +} + +static void Marine_MirrorSuspectPoint(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + { + VECTORCH offset; + + offset.vx=marineStatusPointer->suspect_point.vx-sbPtr->DynPtr->Position.vx; + offset.vy=marineStatusPointer->suspect_point.vy-sbPtr->DynPtr->Position.vy; + offset.vz=marineStatusPointer->suspect_point.vz-sbPtr->DynPtr->Position.vz; + + marineStatusPointer->suspect_point.vx=sbPtr->DynPtr->Position.vx-offset.vx; + marineStatusPointer->suspect_point.vy=sbPtr->DynPtr->Position.vy-offset.vy; + marineStatusPointer->suspect_point.vz=sbPtr->DynPtr->Position.vz-offset.vz; + } + +} + + + +void SendRequestToMarine(STRATEGYBLOCK* sbPtr,BOOL state,int extended_data) +{ + //handle RequestState (from switches etc.) + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if(extended_data & 1) + { + //change mission type + MARINE_MISSION new_mission=MM_Wait_Then_Wander; + int new_path=-1; + int new_stepnumber=-1; + //state must be 1 + if(!state) return; + + //can't change mission type if non-combatant or if on fire + if(marineStatusPointer->Mission==MM_NonCom || + marineStatusPointer->Mission==MM_RunAroundOnFire) + return; + + switch((extended_data>>7)&0xff) + { + case 0: + new_mission=MM_Wait_Then_Wander; + break; + case 1: + new_mission=MM_Wander; + break; + case 2: + new_mission=MM_Guard; + //need to cacluculate mission module from 'myspot' guard location + { + MODULE* module=ModuleFromPosition(&marineStatusPointer->my_spot,0); + GLOBALASSERT(module); + marineStatusPointer->missionmodule=module->m_aimodule; + } + break; + case 3: + new_mission=MM_LocalGuard; + break; + case 4: + new_mission=MM_Pathfinder; + break; + + } + if(new_mission==MM_Pathfinder) + { + //find the path and stepnumber + new_path=(extended_data>>15)&0xff; + new_stepnumber=GetClosestStepInPath(new_path,sbPtr->containingModule); + } + + marineStatusPointer->path=new_path; + marineStatusPointer->stepnumber=new_stepnumber; + InitMission(sbPtr,new_mission); + + } + +} + +static void Marine_ConsiderFallingDamage(STRATEGYBLOCK *sbPtr) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (sbPtr->DynPtr->IsInContactWithFloor) { + if (marineStatusPointer->lastframe_fallingspeed>0) { + + if (marineStatusPointer->lastframe_fallingspeed>Marine_Terminal_Velocity) { + VECTORCH point,point2; + enum PARTICLE_ID blood_type; + + /* Kill marine... */ + CauseDamageToObject(sbPtr,&FallingDamage, (50*ONE_FIXED), NULL); + /* Experiment with blood. */ + GetTargetingPointOfObject_Far(sbPtr,&point); + point2=sbPtr->DynPtr->Position; + point2.vy-=200; + blood_type=GetBloodType(sbPtr); + MakeBloodExplosion(&point2,127,&point,50,blood_type); + /* Crunching sound optional. */ + } + } + marineStatusPointer->lastframe_fallingspeed=0; + } else { + /* Compute falling speed. */ + if (marineStatusPointer->lastframe_fallingspeed>=0) { + int offset; + + offset=sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy; + + marineStatusPointer->lastframe_fallingspeed=DIV_FIXED(offset,NormalFrameTime); + if (marineStatusPointer->lastframe_fallingspeed<0) { + marineStatusPointer->lastframe_fallingspeed=0; + } + } else { + marineStatusPointer->lastframe_fallingspeed=0; + } + } +} + +static STATE_RETURN_CONDITION Execute_MNS_DischargeSmartgun(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn,relPos,relPos2; + int correctlyOrientated,range; + + /* Alternative smartgun function? */ + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->HModelController.Playing=1; + + #if MARINE_STATE_PRINT + textprint("Marine firing... "); + #endif + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* first of all, validate this state: if the target suddenly becomes cloaked, then + we should switch immediately to wait state*/ + if (marineStatusPointer->volleySizeMy_Weapon->MinimumBurstSize) { + /* Keep firing! */ + } else { + if(!MarineCanSeeTarget(sbPtr)) + { + + /* ... and remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + #if MARINE_STATE_PRINT + textprint("Returning no target.\n"); + #endif + marineStatusPointer->lastroundhit=0; + marineStatusPointer->lasthitsection=NULL; + return(SRC_Request_Wait); + } + } + + if (marineStatusPointer->clipammo==0) { + /* Reload here. */ + return(SRC_Request_Reload); + } + + + if (marineStatusPointer->Target) { + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + /* Fix weapon target! */ + if (marineStatusPointer->My_Weapon->TargetCallibrationShift) { + marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + } + + /* Here we must have a target. Renew suspicion for new arrivals. */ + if (NpcSquad.Squad_Suspicion==0) { + PointAlert(2,&marineStatusPointer->weaponTarget); + } + } + /* Otherwise, stay facing the same way. */ + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* I have a cunning plan... */ + { + DELTA_CONTROLLER *delta; + + delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta"); + if (delta) { + if (!(DeltaAnimation_IsFinished(delta))) { + correctlyOrientated=0; + } + } + } + /* I have another cunning plan... */ + if ((marineStatusPointer->volleySize>0)&& + (marineStatusPointer->volleySizeMy_Weapon->MinimumBurstSize)) { + correctlyOrientated=1; + } + + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing*/ + if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) { + + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #if MARINE_STATE_PRINT + textprint("Turning to face.\n"); + #endif + marineStatusPointer->lastroundhit=0; + marineStatusPointer->lasthitsection=NULL; + return(SRC_No_Change); + } + + if (marineStatusPointer->Target) { + relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz); + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + } + + #if 0 + DischargeLOSWeapon_Core(sbPtr); + #else + { + int volleytime,volleyrounds; + + /* look after the gun flash */ + if(marineStatusPointer->myGunFlash) { + MaintainMarineGunFlash(sbPtr); + } else { + CreateMarineGunFlash(sbPtr); + } + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + else + { + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position)); + Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + + marineStatusPointer->stateTimer -= NormalFrameTime; + + /* Volleysize is now rounds fired this state. */ + + volleytime=marineStatusPointer->My_Weapon->FiringTime-marineStatusPointer->stateTimer; + /* It was that or reverse the state timer for this state. */ + volleyrounds=MUL_FIXED(volleytime,marineStatusPointer->My_Weapon->FiringRate); + volleyrounds>>=ONE_FIXED_SHIFT; + + volleyrounds-=marineStatusPointer->volleySize; + marineStatusPointer->volleySize+=volleyrounds; + + LOCALASSERT(volleyrounds>=0); + + if (marineStatusPointer->clipammo!=-1) { + /* We're counting ammo. */ + if (volleyrounds>marineStatusPointer->clipammo) { + volleyrounds=marineStatusPointer->clipammo; + } + marineStatusPointer->clipammo-=volleyrounds; + LOCALASSERT(marineStatusPointer->clipammo>=0); + } + + marineStatusPointer->roundsForThisTarget+=volleyrounds; + + /* Now hit the target with volleyrounds bullets. */ + + { + VECTORCH shotvector; + + shotvector.vx=0; + shotvector.vy=0; + shotvector.vz=65535; + RotateVector(&shotvector,&marineStatusPointer->My_Gunflash_Section->SecMat); + + CastLOSProjectile(sbPtr,&marineStatusPointer->My_Gunflash_Section->World_Offset,&shotvector, marineStatusPointer->My_Weapon->Ammo_Type, volleyrounds,1); + } + } + #endif + + if (marineStatusPointer->Target==NULL) { + /* Getting out of here! */ + return(SRC_No_Change); + } + + /* Did we get him? */ + if ((NPC_IsDead(marineStatusPointer->Target)) + &&(marineStatusPointer->volleySize>=marineStatusPointer->My_Weapon->MinimumBurstSize)) { + if (MarineRetreatsInTheFaceOfDanger(sbPtr)) { + if (Marine_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr)==NULL) { + /* Huzzah! */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + marineStatusPointer->lastroundhit=0; + marineStatusPointer->lasthitsection=NULL; + return(SRC_Request_Taunt); + } + } + } + + if(marineStatusPointer->stateTimer > 0) { + #if MARINE_STATE_PRINT + textprint("Returning continue at range %d.\n",range); + #endif + return(SRC_No_Change); + } + + if(range < MARINE_CLOSE_APPROACH_DISTANCE) + { + /* renew firing, as we are still too close to approach */ + marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime; + marineStatusPointer->volleySize = 0; + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + #if MARINE_STATE_PRINT + textprint("Returning too close renewal at range %d.\n",range); + #endif + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + if (marineStatusPointer->Android==0) { + marineStatusPointer->Courage-=(ONE_FIXED>>3); + } + return(SRC_Request_Fire); + } + else + { + /* we are far enough away, so return to approach */ + + #if 1 + /* ... and remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #if MARINE_STATE_PRINT + textprint("Returning too far termination at range %d.\n",range); + #endif + return(SRC_Request_Approach); + } + return(SRC_No_Change); +} + +int MakeModifiedTargetNum(int targetnum,int dist) { + + /* Adjust targetnum by range? */ + if (dist>10000) { + int factor,tdist; + + tdist=dist-10000; + if (tdist>100000) { + tdist=100000; + } + factor=DIV_FIXED(tdist,100000); + factor=ONE_FIXED-factor; + if (factor<(ONE_FIXED>>3)) { + factor=(ONE_FIXED>>3); + } + + return(MUL_FIXED(factor,targetnum)); + } + return(targetnum); +} + + + + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" +typedef struct marine_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + //from marine status block + signed int health; + signed int volleySize; + signed int primaryWeaponDamage; + + MARINE_BHSTATE behaviourState; + MARINE_BHSTATE lastState; + + MARINE_MISSION Mission; + + VECTORCH my_spot; + VECTORCH my_facing_point; + + /* Movement data. */ + signed int nearSpeed; + int acceleration; + int speedConstant; + int accelerationConstant; + /* Sense data */ + int mtracker_timer; + VECTORCH suspect_point; + int suspicious; + int previous_suspicion; + int using_squad_suspicion; + int sawlastframe; + int gotapoint; + int lastframe_fallingspeed; + /* Pathfinder parameters */ + int path; + int stepnumber; + /* Pathfinder parameters */ + int stateTimer; + int internalState; + + VECTORCH weaponTarget; /* position for firing weapon at */ + + NPC_OBSTRUCTIONREPORT obstruction; + NPC_WANDERDATA wanderData; + + int IAmCrouched; + + int lastroundhit; + + int GibbFactor; + int Wounds; + + int incidentFlag; + int incidentTimer; + + int weapon_variable; + int weapon_variable2; + int clipammo; + int roundsForThisTarget; + + int Female; + int Android; + int Skill; + int Courage; + int Voice; + int VoicePitch; + + int FiringAnim; + int Expression; + int Target_Expression; + int Blink; + int SpotFlag; + + +//annoying pointer related things + int lastmodule_index; + int destinationmodule_index; + int missionmodule_index; + int fearmodule_index; + + + char Target_SBname[SB_NAME_LENGTH]; + char Generator_SBname[SB_NAME_LENGTH]; + + int weapon_id; + + //strategyblock stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; + DYNAMICSBLOCK dynamics; +}MARINE_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV marineStatusPointer + + +void LoadStrategy_Marine(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + MARINE_STATUS_BLOCK* marineStatusPointer; + MARINE_SAVE_BLOCK* block = (MARINE_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + + if(sbPtr) + { + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourMarine) return; + } + else + { + //we will have to generate an alien then + TOOLS_DATA_MARINE tdm; + + //make sure the marine is in a module + if(!ModuleFromPosition(&block->dynamics.Position,NULL)) return; + + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) return; + + sbPtr->I_SBtype = I_BehaviourMarine; + sbPtr->shapeIndex = 0; + sbPtr->maintainVisibility = 1; + COPY_NAME(sbPtr->SBname,block->header.SBname); + + //create using a fake tools data + memset(&tdm,0,sizeof(TOOLS_DATA_MARINE)); + + tdm.position = block->dynamics.Position; + COPY_NAME(tdm.nameID,block->header.SBname); + tdm. marine_type = block->weapon_id; + + EnableBehaviourType(sbPtr,I_BehaviourMarine , &tdm ); + + } + + + marineStatusPointer = (MARINE_STATUS_BLOCK*) sbPtr->SBdataptr; + + //start copying stuff + + COPYELEMENT_LOAD(health) + COPYELEMENT_LOAD(volleySize) + COPYELEMENT_LOAD(primaryWeaponDamage) + COPYELEMENT_LOAD(behaviourState) + COPYELEMENT_LOAD(lastState) + COPYELEMENT_LOAD(Mission) + COPYELEMENT_LOAD(my_spot) + COPYELEMENT_LOAD(my_facing_point) + COPYELEMENT_LOAD(nearSpeed) + COPYELEMENT_LOAD(acceleration) + COPYELEMENT_LOAD(speedConstant) + COPYELEMENT_LOAD(accelerationConstant) + COPYELEMENT_LOAD(mtracker_timer) + COPYELEMENT_LOAD(suspect_point) + COPYELEMENT_LOAD(suspicious) + COPYELEMENT_LOAD(previous_suspicion) + COPYELEMENT_LOAD(using_squad_suspicion) + COPYELEMENT_LOAD(sawlastframe) + COPYELEMENT_LOAD(gotapoint) + COPYELEMENT_LOAD(lastframe_fallingspeed) + COPYELEMENT_LOAD(path) + COPYELEMENT_LOAD(stepnumber) + COPYELEMENT_LOAD(stateTimer) + COPYELEMENT_LOAD(internalState) + COPYELEMENT_LOAD(weaponTarget) /* position for firing weapon at */ + COPYELEMENT_LOAD(obstruction) + COPYELEMENT_LOAD(wanderData) + COPYELEMENT_LOAD(IAmCrouched) + COPYELEMENT_LOAD(lastroundhit) + COPYELEMENT_LOAD(GibbFactor) + COPYELEMENT_LOAD(Wounds) + + COPYELEMENT_LOAD(incidentFlag) + COPYELEMENT_LOAD(incidentTimer) + + COPYELEMENT_LOAD(weapon_variable) + COPYELEMENT_LOAD(weapon_variable2) + COPYELEMENT_LOAD(clipammo) + COPYELEMENT_LOAD(roundsForThisTarget) + + COPYELEMENT_LOAD(Female) + COPYELEMENT_LOAD(Android) + COPYELEMENT_LOAD(Skill) + COPYELEMENT_LOAD(Courage) + COPYELEMENT_LOAD(Voice) + COPYELEMENT_LOAD(VoicePitch) + + COPYELEMENT_LOAD(FiringAnim) + COPYELEMENT_LOAD(Expression) + COPYELEMENT_LOAD(Target_Expression) + COPYELEMENT_LOAD(Blink) + COPYELEMENT_LOAD(SpotFlag) + + + //load ai module pointers + marineStatusPointer->lastmodule = GetPointerFromAIModuleIndex(block->lastmodule_index); + marineStatusPointer->destinationmodule = GetPointerFromAIModuleIndex(block->destinationmodule_index); + marineStatusPointer->missionmodule = GetPointerFromAIModuleIndex(block->missionmodule_index); + marineStatusPointer->fearmodule = GetPointerFromAIModuleIndex(block->fearmodule_index); + + //load target + COPY_NAME(marineStatusPointer->Target_SBname,block->Target_SBname); + marineStatusPointer->Target = FindSBWithName(marineStatusPointer->Target_SBname); + + + //find the marine's generator + marineStatusPointer->generator_sbptr = FindSBWithName(block->Generator_SBname); + + //get marine's weapon + marineStatusPointer->My_Weapon = GetThisNPCMarineWeapon(block->weapon_id); + + //copy strategy block stuff + *sbPtr->DynPtr = block->dynamics; + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + + //load hierarchy + { + SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); + if(hier_header) + { + LoadHierarchy(hier_header,&marineStatusPointer->HModelController); + } + } + + //get section data pointers + if(marineStatusPointer->My_Weapon) + { + marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->GunflashName); + marineStatusPointer->My_Elevation_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ElevationSection); + } + + Load_SoundState(&marineStatusPointer->soundHandle); + Load_SoundState(&marineStatusPointer->soundHandle2); +} + +void SaveStrategy_Marine(STRATEGYBLOCK* sbPtr) +{ + MARINE_SAVE_BLOCK *block; + MARINE_STATUS_BLOCK* marineStatusPointer; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK*) sbPtr->SBdataptr; + + //start copying stuff + + COPYELEMENT_SAVE(health) + COPYELEMENT_SAVE(volleySize) + COPYELEMENT_SAVE(primaryWeaponDamage) + COPYELEMENT_SAVE(behaviourState) + COPYELEMENT_SAVE(lastState) + COPYELEMENT_SAVE(Mission) + COPYELEMENT_SAVE(my_spot) + COPYELEMENT_SAVE(my_facing_point) + COPYELEMENT_SAVE(nearSpeed) + COPYELEMENT_SAVE(acceleration) + COPYELEMENT_SAVE(speedConstant) + COPYELEMENT_SAVE(accelerationConstant) + COPYELEMENT_SAVE(mtracker_timer) + COPYELEMENT_SAVE(suspect_point) + COPYELEMENT_SAVE(suspicious) + COPYELEMENT_SAVE(previous_suspicion) + COPYELEMENT_SAVE(using_squad_suspicion) + COPYELEMENT_SAVE(sawlastframe) + COPYELEMENT_SAVE(gotapoint) + COPYELEMENT_SAVE(lastframe_fallingspeed) + COPYELEMENT_SAVE(path) + COPYELEMENT_SAVE(stepnumber) + COPYELEMENT_SAVE(stateTimer) + COPYELEMENT_SAVE(internalState) + COPYELEMENT_SAVE(weaponTarget) /* position for firing weapon at */ + COPYELEMENT_SAVE(obstruction) + COPYELEMENT_SAVE(wanderData) + COPYELEMENT_SAVE(IAmCrouched) + COPYELEMENT_SAVE(lastroundhit) + COPYELEMENT_SAVE(GibbFactor) + COPYELEMENT_SAVE(Wounds) + + COPYELEMENT_SAVE(incidentFlag) + COPYELEMENT_SAVE(incidentTimer) + + COPYELEMENT_SAVE(weapon_variable) + COPYELEMENT_SAVE(weapon_variable2) + COPYELEMENT_SAVE(clipammo) + COPYELEMENT_SAVE(roundsForThisTarget) + + COPYELEMENT_SAVE(Female) + COPYELEMENT_SAVE(Android) + COPYELEMENT_SAVE(Skill) + COPYELEMENT_SAVE(Courage) + COPYELEMENT_SAVE(Voice) + COPYELEMENT_SAVE(VoicePitch) + + COPYELEMENT_SAVE(FiringAnim) + COPYELEMENT_SAVE(Expression) + COPYELEMENT_SAVE(Target_Expression) + COPYELEMENT_SAVE(Blink) + COPYELEMENT_SAVE(SpotFlag) + + //save ai module pointers + block->lastmodule_index = GetIndexFromAIModulePointer(marineStatusPointer->lastmodule); + block->destinationmodule_index = GetIndexFromAIModulePointer(marineStatusPointer->destinationmodule); + block->missionmodule_index = GetIndexFromAIModulePointer(marineStatusPointer->missionmodule); + block->fearmodule_index = GetIndexFromAIModulePointer(marineStatusPointer->fearmodule); + + //save target + COPY_NAME(block->Target_SBname,marineStatusPointer->Target_SBname); + + //save the marine's generator name + if(marineStatusPointer->generator_sbptr) + { + COPY_NAME(block->Generator_SBname,marineStatusPointer->generator_sbptr->SBname); + } + else + { + COPY_NAME(block->Generator_SBname,Null_Name); + } + + //save marine's weapon + if(marineStatusPointer->My_Weapon) + block->weapon_id = marineStatusPointer->My_Weapon->id; + else + block->weapon_id = -1; + + //copy strategy block stuff + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; + + //save the hierarchy + SaveHierarchy(&marineStatusPointer->HModelController); + + Save_SoundState(&marineStatusPointer->soundHandle); + Save_SoundState(&marineStatusPointer->soundHandle2); + +} + + + +/*----------------------------** +** And now the squad state... ** +**----------------------------*/ + + +typedef struct marine_squad_save_block +{ + SAVE_BLOCK_HEADER header; + + int alertStatus; + int responseLevel; + int alertPriority; + + int Squad_Suspicion; + VECTORCH squad_suspect_point; + + /* Now some stats. */ + int RespondingMarines; + int Alt_RespondingMarines; + + int NearUnpanickedMarines; + int Alt_NearUnpanickedMarines; + + int NearPanickedMarines; + int Alt_NearPanickedMarines; + + int NearBurningMarines; + int Alt_NearBurningMarines; + + int Squad_Delta_Morale; + int Nextframe_Squad_Delta_Morale; + + int alertZone_index; + +}MARINE_SQUAD_SAVE_BLOCK; + +#undef SAVELOAD_BEHAV +//defines for load/save macros +#define SAVELOAD_BEHAV (&NpcSquad) + + +void LoadMarineSquadState(SAVE_BLOCK_HEADER* header) +{ + MARINE_SQUAD_SAVE_BLOCK *block = (MARINE_SQUAD_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //copy stuff + + COPYELEMENT_LOAD(alertStatus) + COPYELEMENT_LOAD(responseLevel) + COPYELEMENT_LOAD(alertPriority) + COPYELEMENT_LOAD(Squad_Suspicion) + COPYELEMENT_LOAD(squad_suspect_point) + COPYELEMENT_LOAD(RespondingMarines) + COPYELEMENT_LOAD(Alt_RespondingMarines) + COPYELEMENT_LOAD(NearUnpanickedMarines) + COPYELEMENT_LOAD(Alt_NearUnpanickedMarines) + COPYELEMENT_LOAD(NearPanickedMarines) + COPYELEMENT_LOAD(Alt_NearPanickedMarines) + COPYELEMENT_LOAD(NearBurningMarines) + COPYELEMENT_LOAD(Alt_NearBurningMarines) + COPYELEMENT_LOAD(Squad_Delta_Morale) + COPYELEMENT_LOAD(Nextframe_Squad_Delta_Morale) + + //and an aimodule + NpcSquad.alertZone = GetPointerFromAIModuleIndex(block->alertZone_index); + +} + +void SaveMarineSquadState() +{ + MARINE_SQUAD_SAVE_BLOCK * block; + + GET_SAVE_BLOCK_POINTER(block); + + //fill in the header + block->header.type = SaveBlock_MarineSquad; + block->header.size = sizeof(*block); + + //copy stuff + + COPYELEMENT_SAVE(alertStatus) + COPYELEMENT_SAVE(responseLevel) + COPYELEMENT_SAVE(alertPriority) + COPYELEMENT_SAVE(Squad_Suspicion) + COPYELEMENT_SAVE(squad_suspect_point) + COPYELEMENT_SAVE(RespondingMarines) + COPYELEMENT_SAVE(Alt_RespondingMarines) + COPYELEMENT_SAVE(NearUnpanickedMarines) + COPYELEMENT_SAVE(Alt_NearUnpanickedMarines) + COPYELEMENT_SAVE(NearPanickedMarines) + COPYELEMENT_SAVE(Alt_NearPanickedMarines) + COPYELEMENT_SAVE(NearBurningMarines) + COPYELEMENT_SAVE(Alt_NearBurningMarines) + COPYELEMENT_SAVE(Squad_Delta_Morale) + COPYELEMENT_SAVE(Nextframe_Squad_Delta_Morale) + + //and an aimodule + block->alertZone_index = GetIndexFromAIModulePointer(NpcSquad.alertZone); +} + +static STATE_RETURN_CONDITION Execute_MNS_DischargeTwoPistols(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn,relPos,relPos2; + int correctlyOrientated,range; + int mod,hitroll; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + LOCALASSERT(marineStatusPointer->My_Weapon->id==MNPCW_TwoPistols); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if(!MarineCanSeeTarget(sbPtr)) + { + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + return(SRC_Request_Wait); + } + + if (marineStatusPointer->clipammo==0) { + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + return(SRC_Request_Reload); + } + + #if MARINE_STATE_PRINT + textprint("Firing pistol... "); + #endif + + /* Here we must have a target. Renew suspicion for new arrivals. */ + if (NpcSquad.Squad_Suspicion==0) { + PointAlert(2,&marineStatusPointer->weaponTarget); + } + + /* first of all, validate this state: if the target suddenly becomes cloaked, then + we should switch immediately to wait state.*/ + + //if ((marineStatusPointer->HModelController.keyframe_flags) + // ||(marineStatusPointer->HModelController.Playing==0)) { + + relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz); + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + if (marineStatusPointer->volleySize==0) { + + //marineStatusPointer->HModelController.Playing=0; + //marineStatusPointer->HModelController.sequence_timer=0; + + /* Only terminate if you haven't fired yet... */ + if(!MarineCanSeeTarget(sbPtr)) + { + #if 1 + /* ... and remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + #if MARINE_STATE_PRINT + textprint("Returning no target.\n"); + #endif + return(SRC_Request_Wait); + } + + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + /* Fix weapon target! */ + if (marineStatusPointer->My_Weapon->TargetCallibrationShift) { + marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + } + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing*/ + //if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening==Controller_Tweening)) { + if (!correctlyOrientated) { + + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + #if MARINE_STATE_PRINT + textprint("Turning to face.\n"); + #endif + return(SRC_No_Change); + } + + /* If you are correctly oriented, you can now fire! */ + + marineStatusPointer->volleySize++; + marineStatusPointer->HModelController.Playing=1; + if (marineStatusPointer->clipammo>0) { + marineStatusPointer->clipammo--; + } + marineStatusPointer->roundsForThisTarget++; + + /* Alternate gun flash. */ + if (strcmp(marineStatusPointer->My_Gunflash_Section->sempai->Section_Name,"dum flash")==0) { + marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,"dum L flash"); + } else { + marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,"dum flash"); + } + + /* look after the gun flash */ + if(marineStatusPointer->myGunFlash) MaintainMarineGunFlash(sbPtr); + else CreateMarineGunFlash(sbPtr); + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + else + { + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position)); + Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + + /* Now hit the target with one bullet. */ + + mod=SpeedRangeMods(&relPos,&relPos2); + + hitroll=marineStatusPointer->Skill; /* Marine skill... */ + if (marineStatusPointer->Target==Player->ObStrategyBlock) { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + if ( (AvP.PlayerType==I_Alien) + ||((AvP.PlayerType==I_Predator)&&(playerStatusPtr->cloakOn==1))) { + /* Vs the player, lighting effects on aliens and cloaked preds. */ + hitroll=MUL_FIXED(hitroll,((CurrentLightAtPlayer>>1)+32767)); + } + } + hitroll-=mod; + hitroll+=marineStatusPointer->My_Weapon->Accuracy; + + { + + /* Handle Damage. */ + if ((FastRandom()&65535)My_Gunflash_Section->SecMat); + + rel_pos.vx=marineStatusPointer->Target->DynPtr->Position.vx-sbPtr->DynPtr->Position.vx; + rel_pos.vy=marineStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy; + rel_pos.vz=marineStatusPointer->Target->DynPtr->Position.vz-sbPtr->DynPtr->Position.vz; + + dist=Approximate3dMagnitude(&rel_pos); + + if (VerifyHitShot(sbPtr,marineStatusPointer->Target,&marineStatusPointer->My_Gunflash_Section->World_Offset,&shotvector, marineStatusPointer->My_Weapon->Ammo_Type, 1,dist)) { + + GetDirectionOfAttack(marineStatusPointer->Target,&rel_pos,&attack_dir); + /* Get hit location? */ + + marineStatusPointer->lasthitsection=HitLocationRoll(marineStatusPointer->Target,sbPtr); + + if (marineStatusPointer->lasthitsection) { + CauseDamageToHModel(marineStatusPointer->lasthitsection->my_controller, marineStatusPointer->Target,&TemplateAmmo[marineStatusPointer->My_Weapon->Ammo_Type].MaxDamage[AvP.Difficulty], ONE_FIXED, marineStatusPointer->lasthitsection,&attack_dir,NULL,0); + } else { + CauseDamageToObject(marineStatusPointer->Target,&TemplateAmmo[marineStatusPointer->My_Weapon->Ammo_Type].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir); + } + } + } else { + GLOBALASSERT(marineStatusPointer->My_Gunflash_Section); + ProjectNPCShot(sbPtr, marineStatusPointer->Target, &marineStatusPointer->My_Gunflash_Section->World_Offset,&marineStatusPointer->My_Gunflash_Section->SecMat, marineStatusPointer->My_Weapon->Ammo_Type, 1); + } + + /* Did we get him? */ + if ((NPC_IsDead(marineStatusPointer->Target))&&(marineStatusPointer->My_Weapon->ARealMarine)) { + /* Only real marines taunt. */ + if ((marineStatusPointer->roundsForThisTarget==1)||(MarineRetreatsInTheFaceOfDanger(sbPtr))) { + if (Marine_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr)==NULL) { + /* Huzzah! */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + marineStatusPointer->lastroundhit=0; + marineStatusPointer->lasthitsection=NULL; + return(SRC_Request_Taunt); + } + } + } + } + } else { + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + } + + marineStatusPointer->stateTimer -= (NormalFrameTime); + + /* You must have fired already. */ + + if(marineStatusPointer->stateTimer > 0) { + #if MARINE_STATE_PRINT + textprint("Returning continue at range %d.\n",range); + #endif + return(SRC_No_Change); + } + + if ((range < MARINE_CLOSE_APPROACH_DISTANCE)||(marineStatusPointer->Android) + //||(marineStatusPointer->volleySizeMy_Weapon->MinimumBurstSize)) + ) + { + /* renew firing, as we are still too close to approach */ + marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime; + marineStatusPointer->volleySize = 0; + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + #if MARINE_STATE_PRINT + textprint("Returning too close renewal at range %d.\n",range); + #endif + if (marineStatusPointer->Android==0) { + // marineStatusPointer->Courage-=(ONE_FIXED>>3); + } + return(SRC_No_Change); + } + else + { + /* we are far enough away, so return to approach */ + + #if MARINE_STATE_PRINT + textprint("Returning too far termination at range %d.\n",range); + #endif + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + marineStatusPointer->volleySize = 0; + return(SRC_Request_Approach); + } + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MNS_DischargeSkeeter(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + VECTORCH orientationDirn,relPos,relPos2; + int correctlyOrientated,range; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + #if MARINE_STATE_PRINT + textprint("Firing Skeeter... "); + #endif + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* If a skeeter launcher has started firing, he can't stop! */ + + if (marineStatusPointer->clipammo==0) { + /* Reload here. */ + return(SRC_Request_Reload); + } + + if (marineStatusPointer->Target) { + /* Here we must have a target. Renew suspicion for new arrivals. */ + if (NpcSquad.Squad_Suspicion==0) { + PointAlert(2,&marineStatusPointer->weaponTarget); + } + } + + if (marineStatusPointer->stateTimer==marineStatusPointer->My_Weapon->FiringTime) { + + /* First cycle. */ + if (marineStatusPointer->HModelController.Tweening==Controller_NoTweening) { + marineStatusPointer->HModelController.Playing=0; + } + + /* Only terminate if you haven't begun firing yet... */ + + if (marineStatusPointer->Target==NULL) { + #if MARINE_STATE_PRINT + textprint("Returning no target.\n"); + #endif + return(SRC_Request_Wait); + } + + if(!MarineCanSeeTarget(sbPtr)) + { + #if 1 + /* ... and remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + #endif + + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + #if MARINE_STATE_PRINT + textprint("Returning no target.\n"); + #endif + return(SRC_Request_Wait); + } + + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + /* Fix weapon target! */ + if (marineStatusPointer->My_Weapon->TargetCallibrationShift) { + marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + } + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* Consider range. */ + + relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz); + + range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + /* Are they, by some chance, really close? */ + if (rangeMy_Weapon->MinRange) { + /* Even a complete idiot wouldn't fire this thing by reflex. */ + return(SRC_Request_PullPistol); + } + + if (correctlyOrientated) { + /* If you are correctly oriented, you can now fire! */ + marineStatusPointer->HModelController.Playing=1; + marineStatusPointer->HModelController.sequence_timer=0; + marineStatusPointer->stateTimer-=NormalFrameTime; + + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + } + if(marineStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) { + Sound_Play(marineStatusPointer->My_Weapon->StartSound,"de",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle)); + } + } + return(SRC_No_Change); + } else if (marineStatusPointer->stateTimer>0) { + + /* We must be in the build up. */ + if (marineStatusPointer->Target) { + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + /* Fix weapon target! */ + if (marineStatusPointer->My_Weapon->TargetCallibrationShift) { + marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + marineStatusPointer->My_Weapon->TargetCallibrationShift); + } + + /* orientate to firing point first */ + orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + } else { + /* Tough! */ + correctlyOrientated = 1; + } + + /* look after the gun flash */ + if(marineStatusPointer->myGunFlash) { + MaintainMarineGunFlash(sbPtr); + } else { + CreateMarineGunFlash(sbPtr); + } + + /* look after the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position)); + } + + marineStatusPointer->stateTimer -= NormalFrameTime; + + #if MARINE_STATE_PRINT + textprint("Turning to face.\n"); + #endif + return(SRC_No_Change); + + } else { + /* Now fire a skeeter. */ + + /* Remove the gunflash */ + if(marineStatusPointer->myGunFlash) + { + RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash); + marineStatusPointer->myGunFlash = NULL; + } + /* .... and stop the sound */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position)); + } + + { + SECTION_DATA *rocket_section; + + rocket_section=GetThisSectionData(marineStatusPointer->HModelController.section_data,"dum flash"); + + LOCALASSERT(rocket_section); + + CreateFrisbeeKernel(&rocket_section->World_Offset, &rocket_section->SecMat,0); + + if (marineStatusPointer->clipammo>0) { + marineStatusPointer->clipammo--; + } + } + + /* You must have fired already. */ + + if(range < MARINE_CLOSE_APPROACH_DISTANCE) + { + /* renew firing, as we are still too close to approach */ + marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime; + marineStatusPointer->volleySize = 0; + GLOBALASSERT(marineStatusPointer->Target); + NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target); + #if MARINE_STATE_PRINT + textprint("Returning too close renewal at range %d.\n",range); + #endif + return(SRC_No_Change); + } + else + { + /* we are far enough away, so return to approach */ + + #if MARINE_STATE_PRINT + textprint("Returning too far termination at range %d.\n",range); + #endif + return(SRC_Request_Approach); + } + + } + + return(SRC_No_Change); +} + +static STATE_RETURN_CONDITION Execute_MNS_AcidAvoidance(STRATEGYBLOCK *sbPtr) +{ + MARINE_STATUS_BLOCK *marineStatusPointer; + DYNAMICSBLOCK *dynPtr; + VECTORCH velocityDirection = {0,0,0}; + + /* Your mission: to advance out of the acid. */ + + LOCALASSERT(sbPtr); + marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(marineStatusPointer); + LOCALASSERT(dynPtr); + + /* Where are we going? */ + + marineStatusPointer->stateTimer-=NormalFrameTime; + if (marineStatusPointer->stateTimer<0) { + return(SRC_Request_Approach); + } + + /* Ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed); + HandleMovingAnimations(sbPtr); + + if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(SRC_Request_Avoidance); + } + return(SRC_No_Change); + +} + +void Marine_Activate_AcidAvoidance_State(STRATEGYBLOCK *sbPtr, VECTORCH *incidence) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + marineStatusPointer->gotapoint=0; + + NPC_InitMovementData(&(marineStatusPointer->moveData)); + NPC_InitWanderData(&(marineStatusPointer->wanderData)); + InitWaypointManager(&marineStatusPointer->waypointManager); + marineStatusPointer->volleySize = 0; + marineStatusPointer->lastState=marineStatusPointer->behaviourState; + marineStatusPointer->behaviourState = MBS_AcidAvoidance; + marineStatusPointer->stateTimer = ONE_FIXED; + + /* Get a destination. */ + { + VECTORCH dest; + if (incidence) { + dest=*incidence; + } else { + /* Boo. */ + dest.vx=sbPtr->DynPtr->OrientMat.mat11; + dest.vy=sbPtr->DynPtr->OrientMat.mat12; + dest.vy=sbPtr->DynPtr->OrientMat.mat13; + } + AlignVelocityToGravity(sbPtr,&dest); + if (Approximate3dMagnitude(&dest)==0) { + /* Boo. */ + dest.vx=sbPtr->DynPtr->OrientMat.mat11; + dest.vy=sbPtr->DynPtr->OrientMat.mat12; + dest.vy=sbPtr->DynPtr->OrientMat.mat13; + } + marineStatusPointer->wanderData.worldPosition=sbPtr->DynPtr->Position; + + marineStatusPointer->wanderData.worldPosition.vx+=(dest.vx>>6); + marineStatusPointer->wanderData.worldPosition.vy+=(dest.vy>>6); + marineStatusPointer->wanderData.worldPosition.vz+=(dest.vz>>6); + + } + + /* Not sure we need an expression for this one. */ + #if 0 + Marine_QueueNeutralExpression(sbPtr); + #endif + + HandleMovingAnimations(sbPtr); + +} diff --git a/3dc/avp/Bh_near.c b/3dc/avp/Bh_near.c new file mode 100644 index 0000000..6d05976 --- /dev/null +++ b/3dc/avp/Bh_near.c @@ -0,0 +1,3049 @@ +#include "3dc.h" + +#include "inline.h" +#include "module.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" + +#include "dynblock.h" + +#include "pheromon.h" +#include "bh_pred.h" +#include "bh_alien.h" +#include "bh_near.h" +#include "bh_far.h" +#include "bh_marin.h" +#include "pfarlocs.h" +#include "targeting.h" +#include "weapons.h" +#define UseLocalAssert Yes +#include "ourasert.h" + +#include "psnd.h" +#include "psndplat.h" +#include "dxlog.h" +#include "ShowCmds.h" +#include "AI_Sight.h" +#include "los.h" +#include "bh_gener.h" +#include "pldnet.h" +#include "particle.h" +#include "scream.h" + +extern int cosine[], sine[]; +extern int NormalFrameTime; +extern int ShowHiveState; +extern ACTIVESOUNDSAMPLE ActiveSounds[]; + +/* Patrick 27/6/97 ********************************* +Prototypes for behaviour functions +****************************************************/ +static void AlienNearState_Approach(STRATEGYBLOCK *sbPtr); +static void AlienNearState_Attack(STRATEGYBLOCK *sbPtr); +static void AlienNearState_Wander(STRATEGYBLOCK *sbPtr); +static void AlienNearState_Wait(STRATEGYBLOCK *sbPtr); +static void AlienNearState_Avoidance(STRATEGYBLOCK *sbPtr); +static void AlienNearState_Hunt(STRATEGYBLOCK *sbPtr); +static void AlienNearState_Retreat(STRATEGYBLOCK *sbPtr); +static void AlienNearState_Pounce(STRATEGYBLOCK *sbPtr); +static void AlienNearState_Jump(STRATEGYBLOCK *sbPtr); +void AlienNearState_Taunting(STRATEGYBLOCK *sbPtr); +void AlienNearState_Dormant(STRATEGYBLOCK *sbPtr); +void AlienNearState_Awakening(STRATEGYBLOCK *sbPtr); +static int GoToJump(STRATEGYBLOCK *sbPtr); +int TargetIsFiringFlamethrowerAtAlien(STRATEGYBLOCK *sbPtr); +static int StartAlienTaunt(STRATEGYBLOCK *sbPtr); +void StartAlienMovementSequence(STRATEGYBLOCK *sbPtr); + +extern void Execute_Alien_Dying(STRATEGYBLOCK *sbPtr); + +int AlienIsAbleToClimb(STRATEGYBLOCK *sbPtr); +int AlienIsAbleToStand(STRATEGYBLOCK *sbPtr); + +extern ATTACK_DATA Alien_Special_Gripping_Attack; + +/* Patrick 27/6/97 ********************************* +Functions... +****************************************************/ + +int AlienStandingTauntList[] = { + (int)ASSS_Taunt, + (int)ASSS_Taunt2, + (int)ASSS_Taunt3, + (int)ASSS_Fear, + -1, +}; + +void Alien_ElectToCrawl(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + + LOCALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + switch(alienStatusPointer->Type) { + case AT_Standard: + default: + if ((FastRandom()%65535)<16384) { + alienStatusPointer->PreferToCrouch=1; + } else { + alienStatusPointer->PreferToCrouch=0; + } + break; + case AT_Predalien: + alienStatusPointer->PreferToCrouch=0; + break; + case AT_Praetorian: + if ((FastRandom()%65535)<16384) { + alienStatusPointer->PreferToCrouch=~alienStatusPointer->PreferToCrouch; + } + break; + } + +} + +void Alien_ElectToPounce(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + + LOCALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + if (alienStatusPointer->PounceDetected==0) { + /* Can't pounce, won't pounce. */ + alienStatusPointer->EnablePounce=0; + return; + } + + switch(alienStatusPointer->Type) { + case AT_Standard: + default: + if ((FastRandom()%65535)<16384) { + alienStatusPointer->EnablePounce=1; + } else { + alienStatusPointer->EnablePounce=0; + } + break; + case AT_Predalien: + if ((FastRandom()%65535)<16384) { + alienStatusPointer->EnablePounce=0; + } else { + alienStatusPointer->EnablePounce=1; + } + break; + case AT_Praetorian: + if (alienStatusPointer->PreferToCrouch) { + /* Why not? */ + alienStatusPointer->EnablePounce=1; + } else if ((FastRandom()%65535)<16384) { + alienStatusPointer->EnablePounce=0; + } else { + alienStatusPointer->EnablePounce=1; + } + break; + } +} + +void NearAlienBehaviour(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + char *descriptor; + + LOCALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + if (ShowSlack) { + int synthSpeed,setSpeed,slack; + VECTORCH offset; + extern int SlackTotal; + extern int SlackSize; + + offset.vx=(sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx); + offset.vy=(sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy); + offset.vz=(sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz); + + synthSpeed=Magnitude(&offset); + synthSpeed=DIV_FIXED(synthSpeed,NormalFrameTime); + setSpeed=Magnitude(&sbPtr->DynPtr->LinVelocity); + + if (setSpeed) { + slack=(ONE_FIXED-(DIV_FIXED(synthSpeed,setSpeed))); + SlackTotal+=slack; + SlackSize++; + } + #if 0 + PrintDebuggingText("MaxSpeed = %d, SynthSpeed = %d, SetSpeed = %d, Slack %d\n",alienStatusPointer->MaxSpeed,synthSpeed,setSpeed,slack); + #endif + } + + /* zero alien's velocity */ + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + dynPtr->LinVelocity.vx = dynPtr->LinVelocity.vy = dynPtr->LinVelocity.vz = 0; + } + + InitWaypointSystem(alienStatusPointer->EnableWaypoints); + + if (alienStatusPointer->incidentFlag) { + Alien_ElectToPounce(sbPtr); + Alien_ElectToCrawl(sbPtr); + } + + switch (alienStatusPointer->BehaviourState) + { + case ABS_Wait: + { + AlienNearState_Wait(sbPtr); + descriptor="Waiting"; + break; + } + case ABS_Approach: + { + AlienNearState_Approach(sbPtr); + descriptor="Approaching"; + break; + } + case ABS_Jump: + { + AlienNearState_Jump(sbPtr); + descriptor="Jumping"; + break; + } + case ABS_Hunt: + { + AlienNearState_Hunt(sbPtr); + descriptor="Hunting"; + break; + } + case ABS_Wander: + { + AlienNearState_Wander(sbPtr); + descriptor="Wandering"; + break; + } + case ABS_Retreat: + { + AlienNearState_Retreat(sbPtr); + descriptor="Retreating"; + break; + } + case ABS_Attack: + { + AlienNearState_Attack(sbPtr); + descriptor="Attacking"; + break; + } + case ABS_Pounce: + { + AlienNearState_Pounce(sbPtr); + descriptor="Pouncing"; + break; + } + case ABS_Avoidance: + { + AlienNearState_Avoidance(sbPtr); + descriptor="Avoiding"; + break; + } + case ABS_Dying: + { + Execute_Alien_Dying(sbPtr); + descriptor="Dying"; + break; + } + case ABS_Dormant: + { + AlienNearState_Dormant(sbPtr); + descriptor="Dormant"; + break; + } + case ABS_Awakening: + { + AlienNearState_Awakening(sbPtr); + descriptor="Awakening"; + break; + } + case ABS_Taunting: + { + AlienNearState_Taunting(sbPtr); + descriptor="Taunting"; + break; + } + default: + { + GLOBALASSERT(1==0); + break; + } + } + + if (ShowHiveState) { + /* Alien position print. */ + + MODULE *thisModule = sbPtr->containingModule; + + LOCALASSERT(thisModule); + + PrintDebuggingText("Near %s alien is in module %d, %s\n",descriptor,thisModule->m_index,thisModule->name); + + } + + #if 0 + //now dealt with in AddPlayerAndObjectUpdateMessages + /* */ + if (AvP.Network != I_No_Network) + { + AddNetMsg_AlienAIState(sbPtr); + } + /* */ + #endif +} + +int GetAlienCrawlMode(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + /* Are we on a ceiling or wall? */ + if(sbPtr->DynPtr->OrientMat.mat22<63000) { + return((int)ACSS_Standard); + } + + /* Wounding! */ + /* Crawl Hurt if you've lost any leg sections, or both feet. */ + if ((alienStatusPointer->Wounds&(section_flag_left_leg|section_flag_right_leg)) + ||((alienStatusPointer->Wounds§ion_flag_left_foot) + &&(alienStatusPointer->Wounds§ion_flag_right_foot))) { + + if (HModelSequence_Exists(&alienStatusPointer->HModelController,HMSQT_AlienCrawl,ACSS_Crawl_Hurt)) { + return((int)ACSS_Crawl_Hurt); + } else { + return((int)ACSS_Standard); + } + } + /* Else, try to scamper. */ + + if (HModelSequence_Exists(&alienStatusPointer->HModelController,HMSQT_AlienCrawl,ACSS_Scamper)) { + return((int)ACSS_Scamper); + } else { + return((int)ACSS_Standard); + } + +} + +void AlienHandleStandingAnimation(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + /* Make sure we're playing a 'standing still' sequence. */ + + if (alienStatusPointer->IAmCrouched) { + if ((alienStatusPointer->HModelController.Sequence_Type!=HMSQT_AlienCrouch) + ||(alienStatusPointer->HModelController.Sub_Sequence!=ACSS_Standard)) { + SetAlienShapeAnimSequence_Core(sbPtr,HMSQT_AlienCrouch,ACSS_Standard,-1,(ONE_FIXED>>3)); + } + } else { + if ((alienStatusPointer->HModelController.Sequence_Type!=HMSQT_AlienStand) + ||(alienStatusPointer->HModelController.Sub_Sequence!=ASSS_Standard)) { + SetAlienShapeAnimSequence_Core(sbPtr,HMSQT_AlienStand,ASSS_Standard,-1,(ONE_FIXED>>3)); + } + } + +} + +void AlienHandleMovingAnimation(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + VECTORCH offset; + int crawlMode,speed; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + /* Make sure we're playing a 'moving' sequence, if we're actually moving. */ + + offset.vx=sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx; + offset.vy=sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy; + offset.vz=sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz; + + /* ...compute speed factor... */ + speed=Magnitude(&offset); + if (speed<(MUL_FIXED(NormalFrameTime,100))) { + /* Not moving much, are we? */ + AlienHandleStandingAnimation(sbPtr); + return; + } + speed=DIV_FIXED(speed,NormalFrameTime); + /* Right, now play the correct sort of sequence. */ + + if(alienStatusPointer->IAmCrouched) { + crawlMode=GetAlienCrawlMode(sbPtr); + if ((alienStatusPointer->HModelController.Sequence_Type!=HMSQT_AlienCrawl) + ||(alienStatusPointer->HModelController.Sub_Sequence!=crawlMode)) { + /* Replace this when I implement speed properly! */ + StartAlienMovementSequence(sbPtr); + } + } else { + if ((alienStatusPointer->HModelController.Sequence_Type!=HMSQT_AlienRun) + ||(alienStatusPointer->HModelController.Sub_Sequence!=ARSS_Standard)) { + /* Replace this when I implement speed properly! */ + StartAlienMovementSequence(sbPtr); + } + } + +} + +void StartAlienMovementSequence(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + int crawlMode; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + if(alienStatusPointer->IAmCrouched) { + crawlMode=GetAlienCrawlMode(sbPtr); + SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienCrawl,crawlMode,ONE_FIXED>>2); + } else { + SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienRun,(int)ARSS_Standard,ONE_FIXED>>1); + } + RecomputeAlienSpeed(sbPtr); + +} + +void Force_Alien_Running_Sequence(STRATEGYBLOCK *sbPtr) { + + int redo; + ALIEN_STATUS_BLOCK *alienStatusPointer; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + redo=0; + + switch(alienStatusPointer->HModelController.Sequence_Type) { + case ((int)HMSQT_AlienCrawl): + { + int crawlMode; + + crawlMode=GetAlienCrawlMode(sbPtr); + + if (alienStatusPointer->HModelController.Sub_Sequence!=crawlMode) { + redo=1; + } + break; + } + case ((int)HMSQT_AlienRun): + { + if (alienStatusPointer->HModelController.Sub_Sequence!=(int)ARSS_Standard) { + redo=1; + } + break; + } + case ((int)HMSQT_AlienStand): + { + //if (alienStatusPointer->HModelController.Sub_Sequence!=(int)ASSS_Standard) { + redo=1; + //} + break; + } + case ((int)HMSQT_AlienCrouch): + { + //if (alienStatusPointer->HModelController.Sub_Sequence!=(int)ACrSS_Standard) { + redo=1; + //} + break; + } + default: + { + GLOBALASSERT(0); + break; + } + } + + if (redo) { + + StartAlienMovementSequence(sbPtr); + + } + + GLOBALASSERT(alienStatusPointer->HModelController.Playing); + +} + +void StartAlienAttackSequence(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + ATTACK_DATA *thisAttack; + int collidingWithTarget; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + LOCALASSERT(alienStatusPointer->Target); + + /* Test for gripping attack! */ + collidingWithTarget=0; + { + struct collisionreport *nextReport; + nextReport = sbPtr->DynPtr->CollisionReportPtr; + + while(nextReport) + { + if(nextReport->ObstacleSBPtr) + { + if (nextReport->ObstacleSBPtr==alienStatusPointer->Target) { + collidingWithTarget=1; + } + } + nextReport = nextReport->NextCollisionReportPtr; + } + } + + if (HModelSequence_Exists(&alienStatusPointer->HModelController,Alien_Special_Gripping_Attack.Sequence_Type, + Alien_Special_Gripping_Attack.Sub_Sequence)) { + VECTORCH offset,mypos; + int dot; + + GetTargetingPointOfObject_Far(alienStatusPointer->Target,&offset); + GetTargetingPointOfObject_Far(sbPtr,&mypos); + offset.vx-=mypos.vx; + offset.vy-=mypos.vy; + offset.vz-=mypos.vz; + Normalise(&offset); + + if (sbPtr->DynPtr->UseStandardGravity) { + sbPtr->DynPtr->GravityDirection.vx=0; + sbPtr->DynPtr->GravityDirection.vy=65536; + sbPtr->DynPtr->GravityDirection.vz=0; + } + + dot=DotProduct(&offset,&sbPtr->DynPtr->GravityDirection); + + if ((dot>16962)&&(collidingWithTarget)) { /* 75 degs... */ + thisAttack=&Alien_Special_Gripping_Attack; + } else { + thisAttack=GetAlienAttackSequence(&alienStatusPointer->HModelController,alienStatusPointer->Wounds, + alienStatusPointer->IAmCrouched); + } + } else { + thisAttack=GetAlienAttackSequence(&alienStatusPointer->HModelController,alienStatusPointer->Wounds, + alienStatusPointer->IAmCrouched); + } + + GLOBALASSERT(thisAttack); + + SetAlienShapeAnimSequence_Core(sbPtr,thisAttack->Sequence_Type,thisAttack->Sub_Sequence, + thisAttack->Sequence_Length,thisAttack->TweeningTime); + + alienStatusPointer->current_attack=thisAttack; + +} + +static enum AMMO_ID GetAttackDamageType(STRATEGYBLOCK *sbPtr,int flagnum) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + if (alienStatusPointer->current_attack==NULL) { + return(AMMO_NONE); + } + + /* Fix praetorian damage here! */ + + switch (alienStatusPointer->Type) { + case AT_Standard: + default: + /* No change. */ + return(alienStatusPointer->current_attack->flag_damage[flagnum]); + break; + case AT_Predalien: + { + switch (alienStatusPointer->current_attack->flag_damage[flagnum]) { + case AMMO_NPC_ALIEN_CLAW: + default: + return(AMMO_NPC_PREDALIEN_CLAW); + break; + case AMMO_NPC_ALIEN_TAIL: + return(AMMO_NPC_PREDALIEN_TAIL); + break; + case AMMO_NPC_ALIEN_BITE: + return(AMMO_NPC_PREDALIEN_BITE); + break; + } + } + break; + case AT_Praetorian: + { + switch (alienStatusPointer->current_attack->flag_damage[flagnum]) { + case AMMO_NPC_ALIEN_CLAW: + default: + return(AMMO_NPC_PRAETORIAN_CLAW); + break; + case AMMO_NPC_ALIEN_TAIL: + return(AMMO_NPC_PRAETORIAN_TAIL); + break; + case AMMO_NPC_ALIEN_BITE: + return(AMMO_NPC_PRAETORIAN_BITE); + break; + } + } + break; + } + + /* What? */ + return(AMMO_NONE); + +} + +static void DoAlienAIAttackSound(STRATEGYBLOCK *sbPtr) { + + DYNAMICSBLOCK *dynPtr; + SOUNDINDEX soundIndex; + ALIEN_STATUS_BLOCK *alienStatusPointer; + + GLOBALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + /* This one is for ALIEN SWIPE SOUND. */ + + soundIndex=SID_NOSOUND; + + PlayAlienSound((int)alienStatusPointer->Type,ASC_Swipe,0, + NULL,&sbPtr->DynPtr->Position); + + #if 0 + if (AvP.Network != I_No_Network) + { + soundIndex=ActiveSounds[alienStatusPointer->soundHandle2].soundIndex; + if (soundIndex!=SID_NOSOUND) { + AddNetMsg_SpotAlienSound(soundIndex,pitch,&dynPtr->Position); + } + } + #endif + +} + +static void DoAlienAIRandomHiss(STRATEGYBLOCK *sbPtr) { + + DYNAMICSBLOCK *dynPtr; + SOUNDINDEX soundIndex; + ALIEN_STATUS_BLOCK *alienStatusPointer; + + GLOBALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + soundIndex=SID_NOSOUND; + + /* This one is for ALIEN GENERAL SCREAM. */ + + soundIndex=SID_NOSOUND; + + if (alienStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + PlayAlienSound((int)alienStatusPointer->Type,ASC_Scream_General,0, + &alienStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + + if (AvP.Network != I_No_Network) + { + AddNetMsg_SpotAlienSound((int)ASC_Scream_General,(int)alienStatusPointer->Type,0,&dynPtr->Position); + } + } + +} + +static void DoAlienAITauntHiss(STRATEGYBLOCK *sbPtr) { + + DYNAMICSBLOCK *dynPtr; + SOUNDINDEX soundIndex; + ALIEN_STATUS_BLOCK *alienStatusPointer; + + GLOBALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + soundIndex=SID_NOSOUND; + + /* This one is for ALIEN TAUNT. */ + + soundIndex=SID_NOSOUND; + + if (alienStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + PlayAlienSound((int)alienStatusPointer->Type,ASC_Taunt,0, + &alienStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + + if (AvP.Network != I_No_Network) + { + AddNetMsg_SpotAlienSound((int)ASC_Taunt,(int)alienStatusPointer->Type,0,&dynPtr->Position); + } + } +} + + +static void AlienNearDamageShell(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + int workingflags,flagnum,a; + int dist,dodamage; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + + /* Damage shell! */ + workingflags=alienStatusPointer->HModelController.keyframe_flags>>1; + flagnum=0; + + dist = VectorDistance(&(dynPtr->Position),&(alienStatusPointer->Target->DynPtr->Position)); + if (distTarget->SBdptr) { + VECTORCH rel_pos,attack_dir; + + rel_pos.vx=alienStatusPointer->Target->DynPtr->Position.vx-sbPtr->DynPtr->Position.vx; + rel_pos.vy=alienStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy; + rel_pos.vz=alienStatusPointer->Target->DynPtr->Position.vz-sbPtr->DynPtr->Position.vz; + + GetDirectionOfAttack(alienStatusPointer->Target,&rel_pos,&attack_dir); + + if (alienStatusPointer->Target->SBdptr->HModelControlBlock) { + HtoHDamageToHModel(alienStatusPointer->Target,&TemplateAmmo[GetAttackDamageType(sbPtr,flagnum)].MaxDamage[AvP.Difficulty], ONE_FIXED, sbPtr, &attack_dir); + } else { + + CauseDamageToObject(alienStatusPointer->Target,&TemplateAmmo[GetAttackDamageType(sbPtr,flagnum)].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir); + } + } else { + VECTORCH rel_pos,attack_dir; + + rel_pos.vx=alienStatusPointer->Target->DynPtr->Position.vx-sbPtr->DynPtr->Position.vx; + rel_pos.vy=alienStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy; + rel_pos.vz=alienStatusPointer->Target->DynPtr->Position.vz-sbPtr->DynPtr->Position.vz; + + GetDirectionOfAttack(alienStatusPointer->Target,&rel_pos,&attack_dir); + + CauseDamageToObject(alienStatusPointer->Target,&TemplateAmmo[GetAttackDamageType(sbPtr,flagnum)].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir); + } + } + } + /* Prepare next flag. */ + workingflags>>=1; + flagnum++; + } + +} + +int Alien_Special_Pounce_Condition(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr=sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + LOCALASSERT(alienStatusPointer->Target); + + if (sbPtr->containingModule->m_aimodule->m_waypoints==NULL) { + /* If in an unwaypointed module... */ + if ((alienStatusPointer->Target->DynPtr->Position.vy-dynPtr->Position.vy)<(-2000)) { + /* And the target is directly above us... */ + return(1); + } + } + + return(0); +} + +#define ALIEN_CURVETOPLAYERDIST 8000 +static void AlienNearState_Approach(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + VECTORCH targetPos; + int approachingAirDuct = 0; + int curveToPlayer = 0; + int distanceToPlayer; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr=sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + + distanceToPlayer = VectorDistance(&(dynPtr->Position),&(alienStatusPointer->Target->DynPtr->Position)); + + if (alienStatusPointer->Target==NULL) { + /* Approach what? */ + AlienHandleMovingAnimation(sbPtr); + alienStatusPointer->BehaviourState = ABS_Hunt; + InitWaypointManager(&alienStatusPointer->waypointManager); + alienStatusPointer->NearStateTimer = ALIEN_NEARWAITTIME; + return; + } + + /* Update sequence! */ + AlienHandleMovingAnimation(sbPtr); + + /* target acquisition ? */ + { + extern DISPLAYBLOCK *Player; + if(VectorDistance(&(alienStatusPointer->Target->DynPtr->Position),&(dynPtr->Position)) < ALIEN_CURVETOPLAYERDIST) + { + curveToPlayer = 1; + //targetPos = alienStatusPointer->Target->DynPtr->Position; + GetTargetingPointOfObject_Far(alienStatusPointer->Target, &targetPos); + /* do climb on walls, etc */ + if (AlienIsAbleToClimb(sbPtr)) { + dynPtr->UseStandardGravity=0; + } else { + dynPtr->UseStandardGravity=1; + } + } + else + { + curveToPlayer = 0; + NPCGetMovementTarget(sbPtr, alienStatusPointer->Target, &targetPos, &approachingAirDuct,1); + /* don't climb on walls, etc */ + dynPtr->UseStandardGravity=1; + } + } + + if (sbPtr->containingModule->m_aimodule->m_waypoints!=NULL) { + /* Never curve in a waypoint module, you might hurt yourself. */ + curveToPlayer=0; + } + + if(curveToPlayer) + { + /* curve to the player... */ + /* translate target into alien's local space */ + + //textprint("curving alien \n"); + + { + MATRIXCH toLocalSpaceMatrix = dynPtr->OrientMat; + TransposeMatrixCH(&toLocalSpaceMatrix); + + targetPos.vx -= dynPtr->Position.vx; + targetPos.vy -= dynPtr->Position.vy; + targetPos.vz -= dynPtr->Position.vz; + RotateVector(&targetPos,&toLocalSpaceMatrix); + } + + /* tracking movement */ + { + int distanceToTarget = Magnitude(&targetPos); + + if (dynPtr->IsInContactWithFloor) + { + int offset; + + if (alienStatusPointer->CurveTimeOut<=0) + { + alienStatusPointer->CurveLength = distanceToTarget; + alienStatusPointer->CurveRadius = ((FastRandom()&16383)-8192)*2; + alienStatusPointer->CurveTimeOut= ONE_FIXED*3; + } + else alienStatusPointer->CurveTimeOut-=NormalFrameTime; + + offset = + MUL_FIXED + ( + alienStatusPointer->CurveRadius, + GetCos((1024*(distanceToTarget)/alienStatusPointer->CurveLength)&4095) + ); + + dynPtr->LinVelocity.vx = + WideMulNarrowDiv + ( + alienStatusPointer->MaxSpeed, + targetPos.vx, + distanceToTarget + ) + -WideMulNarrowDiv + ( + offset, + targetPos.vz, + distanceToTarget + ); + + + dynPtr->LinVelocity.vz = + WideMulNarrowDiv + ( + alienStatusPointer->MaxSpeed, + targetPos.vz, + distanceToTarget + )+ + WideMulNarrowDiv + ( + offset, + targetPos.vx, + distanceToTarget + ); + #if 0 + if ( (targetPos.vy < -ALIEN_ATTACKDISTANCE_MIN) + &&(targetPos.vx*targetPos.vx+targetPos.vz*targetPos.vz < 2*ALIEN_ATTACKDISTANCE_MIN*ALIEN_ATTACKDISTANCE_MIN) + &&(DotProduct(&dynPtr->GravityDirection,(VECTORCH*)&dynPtr->OrientMat.mat21)>64500) + &&(sbPtr->containingModule==playerPherModule)) + #else + if ((dynPtr->UseStandardGravity==0)&&(sbPtr->containingModule==playerPherModule)) { + int dot; + //VECTORCH velocityDirection=dynPtr->LinVelocity; + VECTORCH velocityDirection; + GetTargetingPointOfObject_Far(alienStatusPointer->Target, &velocityDirection); + velocityDirection.vx -= dynPtr->Position.vx; + velocityDirection.vy -= dynPtr->Position.vy; + velocityDirection.vz -= dynPtr->Position.vz; + + Normalise(&velocityDirection); + dot=DotProduct(&dynPtr->GravityDirection,&velocityDirection); + if (dot<-60000) + #endif + { + /* patrick 29/7/97: I have added the extra condition of not being in the same module as + the player, so that alien does not jump at entry-points */ + dynPtr->TimeNotInContactWithFloor = 0; + dynPtr->UseStandardGravity=1; + dynPtr->LinImpulse.vx -= MUL_FIXED(dynPtr->GravityDirection.vx,ALIEN_JUMPVELOCITY); + dynPtr->LinImpulse.vy -= MUL_FIXED(dynPtr->GravityDirection.vy,ALIEN_JUMPVELOCITY); + dynPtr->LinImpulse.vz -= MUL_FIXED(dynPtr->GravityDirection.vz,ALIEN_JUMPVELOCITY); + } + #if 1 + } + #endif + RotateVector(&dynPtr->LinVelocity,&dynPtr->OrientMat); + + /* align to velocity */ + NPCOrientateToVector(sbPtr,&dynPtr->LinVelocity,NPC_TURNRATE,NULL); + } + } + } + else + { + /* use standard NPC direction finding... */ + VECTORCH velocityDirection = {0,0,0}; + + //textprint("non curving alien \n"); + + NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPos,&alienStatusPointer->waypointManager); + if (AlienIsEncouragedToCrawl()&&(alienStatusPointer->EnableWaypoints)) { + if (AlienIsAbleToClimb(sbPtr)) { + dynPtr->UseStandardGravity=0; + } else { + dynPtr->UseStandardGravity=1; + } + } + NPCSetVelocity(sbPtr, &velocityDirection, alienStatusPointer->MaxSpeed); + alienStatusPointer->CurveTimeOut=0; /* forces curve init next time curving is used */ + + /* Consider ripping off the wall. */ + if ((dynPtr->UseStandardGravity==0)&&(sbPtr->containingModule==playerPherModule)) { + int dot; + + dot=DotProduct(&dynPtr->GravityDirection,&velocityDirection); + + if (dot<-60000) { + + dynPtr->TimeNotInContactWithFloor = 0; + dynPtr->UseStandardGravity=1; + dynPtr->LinImpulse.vx -= MUL_FIXED(dynPtr->GravityDirection.vx,ALIEN_JUMPVELOCITY); + dynPtr->LinImpulse.vy -= MUL_FIXED(dynPtr->GravityDirection.vy,ALIEN_JUMPVELOCITY); + dynPtr->LinImpulse.vz -= MUL_FIXED(dynPtr->GravityDirection.vz,ALIEN_JUMPVELOCITY); + } + } + } + + + /* state change and sequence change tests must go here, because they test the approaching + airduct flag, which is set during target aquisition */ + + /* check if we should be crouched or standing up */ + { + int redo=0; + + if(alienStatusPointer->IAmCrouched) + { + /* curently crouched */ + if((!approachingAirDuct)&&(!AlienShouldBeCrawling(sbPtr))) + { + /* should be running*/ + alienStatusPointer->IAmCrouched = 0; + redo=1; + } + } + else + { + /* currently standing */ + if((approachingAirDuct)||(AlienShouldBeCrawling(sbPtr))) + { + /* should be crawling */ + alienStatusPointer->IAmCrouched = 1; + redo=1; + } + } + + if (redo) { + StartAlienMovementSequence(sbPtr); + } + } + + /* Hang on, should we be doing this? */ + if (sbPtr->SBDamageBlock.IsOnFire==0) { + if ((distanceToPlayer<30000) + &&(sbPtr->DynPtr->OrientMat.mat22>=63000) + &&(sbPtr->DynPtr->IsInContactWithFloor) + ) { + + /* 150% flamethrower 'range'. */ + if (TargetIsFiringFlamethrowerAtAlien(sbPtr)) { + /* Pause and taunt. */ + if (StartAlienTaunt(sbPtr)) { + /* My work is done. */ + return; + } + } + } + } + + /* should we change back to attack, maybe? */ + { + + if ((distanceToPlayer<=ALIEN_POUNCE_STARTMAXRANGE) + &&(distanceToPlayer>=ALIEN_POUNCE_MINRANGE)) { + /* Might want to pounce. */ + if ((alienStatusPointer->EnablePounce)||(Alien_Special_Pounce_Condition(sbPtr))) { + if (StartAlienPounce(sbPtr)) { + /* Success. */ + return; + } + } + } else if (distanceToPlayer>ALIEN_POUNCE_STARTMAXRANGE) { + if (alienStatusPointer->incidentFlag) { + int prob; + + switch (alienStatusPointer->Type) { + case AT_Standard: + default: + prob=ALIEN_JUMPINESS; + break; + case AT_Predalien: + prob=PREDALIEN_JUMPINESS; + break; + case AT_Praetorian: + prob=PRAETORIAN_JUMPINESS; + break; + } + + if ((FastRandom()&65535)BehaviourState = ABS_Attack; + alienStatusPointer->NearStateTimer=ALIEN_ATTACKTIME; + /* Can alien stand up? */ + if(alienStatusPointer->IAmCrouched) { + if (!AlienShouldBeCrawling(sbPtr)) { + /* Better stand up now then. */ + alienStatusPointer->IAmCrouched = 0; + } + } + /* Now, */ + + StartAlienAttackSequence(sbPtr); + + /* this is because we have already set a velocity this frame */ + dynPtr->LinVelocity.vx = dynPtr->LinVelocity.vy = dynPtr->LinVelocity.vz = 0; + return; + } + } + } + + /* is player visible?: if not, go to timed wait... */ + if(!AlienIsAwareOfTarget(sbPtr)) + { + alienStatusPointer->BehaviourState = ABS_Wait; + alienStatusPointer->NearStateTimer = ALIEN_NEARWAITTIME; + InitWaypointManager(&alienStatusPointer->waypointManager); + if(alienStatusPointer->IAmCrouched) SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienCrouch,(int)ACrSS_Standard,ONE_FIXED>>1); + else SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienStand,(int)ASSS_Standard,ONE_FIXED>>1); + /* this is because we have already set a velocity this frame */ + dynPtr->LinVelocity.vx = dynPtr->LinVelocity.vy = dynPtr->LinVelocity.vz = 0; + return; + } else if (!AlienHasPathToTarget(sbPtr)) { + /* Go to hunt. */ + alienStatusPointer->BehaviourState = ABS_Hunt; + alienStatusPointer->NearStateTimer = ALIEN_NEARWAITTIME; + InitWaypointManager(&alienStatusPointer->waypointManager); + } + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE_ALIEN + { + if (New_NPC_IsObstructed(sbPtr,&alienStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + alienStatusPointer->BehaviourState = ABS_Avoidance; + alienStatusPointer->NearStateTimer = NPC_AVOIDTIME; + InitWaypointManager(&alienStatusPointer->waypointManager); + return; + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_OBSTRUCTIONREPORT obstruction; + NPC_IsObstructed(sbPtr,&(alienStatusPointer->moveData),&obstruction,&destructableObject); + if(obstruction.environment) + { + #if 1 + NPC_InitMovementData(&(alienStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(alienStatusPointer->moveData.avoidanceDirn),&obstruction); + alienStatusPointer->BehaviourState = ABS_Avoidance; + alienStatusPointer->NearStateTimer = NPC_AVOIDTIME; + return; + #endif + } else if(obstruction.destructableObject) { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_ALIEN_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } else if ((obstruction.anySingleObstruction)&&(!obstruction.otherCharacter)) { + /* Try for a nearer target? */ + alienStatusPointer->Target=NULL; + } + } + + { + VECTORCH velocityDirection = dynPtr->LinVelocity; + Normalise(&velocityDirection); + + if(NPC_CannotReachTarget(&(alienStatusPointer->moveData), &targetPos, &velocityDirection)) + { + /* go to avoidance */ + NPC_OBSTRUCTIONREPORT obstruction = {1,0,0}; + NPC_InitMovementData(&(alienStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(alienStatusPointer->moveData.avoidanceDirn),&obstruction); + alienStatusPointer->BehaviourState = ABS_Avoidance; + alienStatusPointer->NearStateTimer = NPC_AVOIDTIME; + /* no sequence change required */ + return; + } + } + #endif + + /* still here?... make some noise */ + if ((FastRandom()&127)<20) { + DoAlienAIRandomHiss(sbPtr); + } +} + +static void AlienNearState_Attack(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + + /* The following should be #if 0, but I'll not check that in until the player is unclimbable. */ + #if 1 + /* don't climb on walls, etc */ + dynPtr->UseStandardGravity=1; + #endif + /* Nowadays, other things can be stuck to walls... sigh. */ + + if (alienStatusPointer->Target==NULL) { + /* Attack what? */ + alienStatusPointer->BehaviourState = ABS_Hunt; + alienStatusPointer->NearStateTimer = ALIEN_NEARWAITTIME; + InitWaypointManager(&alienStatusPointer->waypointManager); + return; + } + + /* patrick 13/6/97: a little addition: + Orientate towards player, just to make sure we're facing */ + if (dynPtr->UseStandardGravity) { + VECTORCH orientationDirn; + int i; + orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; + i = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + } else { + /* Replace this! */ + VECTORCH orientationDirn; + int i,dot; + orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = alienStatusPointer->Target->DynPtr->Position.vy - sbPtr->DynPtr->Position.vy; + orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; + + dot = -(DotProduct(&dynPtr->GravityDirection,&orientationDirn)); + /* Hold that thought. */ + orientationDirn.vx -= MUL_FIXED(dot,dynPtr->GravityDirection.vx); + orientationDirn.vy -= MUL_FIXED(dot,dynPtr->GravityDirection.vy); + orientationDirn.vz -= MUL_FIXED(dot,dynPtr->GravityDirection.vz); + + #if 0 + { + VECTORCH point; + /* Wacky test. */ + GetTargetingPointOfObject_Far(sbPtr,&point); + Normalise(&orientationDirn); + MakeParticle(&point,&orientationDirn,PARTICLE_PREDATOR_BLOOD); + + } + #endif + + i = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + } + + /* change back to approach?: don't need to directly test if we should go to wander, as + approach state will do this... */ + { + int distanceToPlayer = VectorDistance(&(dynPtr->Position),&(alienStatusPointer->Target->DynPtr->Position)); + if((distanceToPlayer>ALIEN_ATTACKDISTANCE_MAX)) + { + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + + StartAlienMovementSequence(sbPtr); + InitWaypointManager(&alienStatusPointer->waypointManager); + + alienStatusPointer->NearStateTimer = 0; + alienStatusPointer->CurveTimeOut = 0; + return; + } + } + + /* Fall over check? */ + + if(!(alienStatusPointer->IAmCrouched)) { + if (AlienShouldBeCrawling(sbPtr)) { + /* Something has changed. Fall over. */ + + /* That implies going back to approach, btw. */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + + StartAlienMovementSequence(sbPtr); + InitWaypointManager(&alienStatusPointer->waypointManager); + + alienStatusPointer->NearStateTimer = 0; + alienStatusPointer->CurveTimeOut = 0; + return; + } + } + + /* alien can inflict nastiness on the target */ + alienStatusPointer->NearStateTimer-=NormalFrameTime; + + AlienNearDamageShell(sbPtr); + + if (alienStatusPointer->HModelController.keyframe_flags&1) { + + /* Retest for moving closer? */ + int distanceToPlayer = VectorDistance(&(dynPtr->Position),&(alienStatusPointer->Target->DynPtr->Position)); + if((distanceToPlayer>ALIEN_ATTACKDISTANCE_MIN)) + { + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + + StartAlienMovementSequence(sbPtr); + InitWaypointManager(&alienStatusPointer->waypointManager); + + alienStatusPointer->NearStateTimer = 0; + alienStatusPointer->CurveTimeOut = 0; + return; + } + + StartAlienAttackSequence(sbPtr); + alienStatusPointer->NearStateTimer = ALIEN_ATTACKTIME; + /* Shrug. */ + } + + if ((FastRandom()&127)<20) { + DoAlienAIRandomHiss(sbPtr); + } + +} + + +static void AlienNearState_Wander(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + int approachingAirDuct = 0; + VECTORCH velocityDirection = {0,0,0}; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + + /* don't climb on walls, etc */ + dynPtr->UseStandardGravity=1; + + /* check if we should be crouched or standing up */ + + /* Update sequence! */ + AlienHandleMovingAnimation(sbPtr); + + /* Do something else? */ + + #if 0 + if (alienStatusPointer->Mission==AM_GlobalHunt) { + + alienStatusPointer->BehaviourState = ABS_Hunt; + alienStatusPointer->NearStateTimer = 0; + InitWaypointManager(&alienStatusPointer->waypointManager); + /* no sequence change required */ + return; + + } + #endif + + /* should we change to approach state? */ + if(AlienHasPathToTarget(sbPtr)) + { + /* doesn't require a sequence change */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + alienStatusPointer->CurveTimeOut = 0; + InitWaypointManager(&alienStatusPointer->waypointManager); + if (alienStatusPointer->Target->I_SBtype==I_BehaviourMarine) { + WarnMarineOfAttack(alienStatusPointer->Target,sbPtr); + } + return; + } else if (AlienIsAwareOfTarget(sbPtr)) { + /* Go to hunt. */ + alienStatusPointer->BehaviourState = ABS_Hunt; + alienStatusPointer->NearStateTimer = ALIEN_NEARWAITTIME; + InitWaypointManager(&alienStatusPointer->waypointManager); + } + + /* Try to reaquire target? */ + alienStatusPointer->Target=NULL; + + /* wander target aquisition: if no target, or moved module */ + LOCALASSERT(sbPtr->containingModule); + if(alienStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_InitMovementData(&(alienStatusPointer->moveData)); + NPC_FindAIWanderTarget(sbPtr,&(alienStatusPointer->wanderData),&(alienStatusPointer->moveData),1); + } + else if(alienStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_aimodule->m_index) + { + NPC_FindAIWanderTarget(sbPtr,&(alienStatusPointer->wanderData),&(alienStatusPointer->moveData),1); + } + + /* if we still haven't got one, go to wait */ + if(alienStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + alienStatusPointer->BehaviourState = ABS_Wait; + alienStatusPointer->NearStateTimer = ALIEN_NEARWAITTIME; + if(alienStatusPointer->IAmCrouched) SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienCrouch,(int)ACrSS_Standard,ONE_FIXED>>1); + else SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienStand,(int)ASSS_Standard,ONE_FIXED>>1); + } + + /* ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(alienStatusPointer->wanderData.worldPosition),&alienStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, alienStatusPointer->MaxSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE_ALIEN + { + if (New_NPC_IsObstructed(sbPtr,&alienStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + alienStatusPointer->BehaviourState = ABS_Avoidance; + alienStatusPointer->NearStateTimer = NPC_AVOIDTIME; + InitWaypointManager(&alienStatusPointer->waypointManager); + return; + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_OBSTRUCTIONREPORT obstruction; + NPC_IsObstructed(sbPtr,&(alienStatusPointer->moveData),&obstruction,&destructableObject); + if((obstruction.environment)||(obstruction.otherCharacter)) + { + #if 1 + /* go to avoidance */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(alienStatusPointer->moveData.avoidanceDirn),&obstruction); + alienStatusPointer->BehaviourState = ABS_Avoidance; + alienStatusPointer->NearStateTimer = NPC_AVOIDTIME; + /* no sequence change required */ + return; + #endif + } + if(obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_ALIEN_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(alienStatusPointer->moveData), &(alienStatusPointer->wanderData.worldPosition), &velocityDirection)) + { + /* go to avoidance */ + NPC_OBSTRUCTIONREPORT obstruction = {1,0,0}; + NPC_InitMovementData(&(alienStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(alienStatusPointer->moveData.avoidanceDirn),&obstruction); + alienStatusPointer->BehaviourState = ABS_Avoidance; + alienStatusPointer->NearStateTimer = NPC_AVOIDTIME; + /* no sequence change required */ + return; + } + #endif +} + +static void AlienNearState_Wait(STRATEGYBLOCK *sbPtr) +{ + /* wait until near state timer runs out, then wander: + alternatively, if we can attack the player, go straight to approach */ + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + + /* do climb on walls, etc */ + if (AlienIsAbleToClimb(sbPtr)) { + dynPtr->UseStandardGravity=0; + } else { + dynPtr->UseStandardGravity=1; + } + + AlienHandleStandingAnimation(sbPtr); + + /* test for attack */ + if(AlienHasPathToTarget(sbPtr)) + { + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + InitWaypointManager(&alienStatusPointer->waypointManager); + + StartAlienMovementSequence(sbPtr); + + alienStatusPointer->CurveTimeOut = 0; + alienStatusPointer->NearStateTimer = 0; + if (alienStatusPointer->Target->I_SBtype==I_BehaviourMarine) { + WarnMarineOfAttack(alienStatusPointer->Target,sbPtr); + } + return; + } else if (AlienIsAwareOfTarget(sbPtr)) { + /* Go to hunt. */ + alienStatusPointer->BehaviourState = ABS_Hunt; + alienStatusPointer->NearStateTimer = ALIEN_NEARWAITTIME; + InitWaypointManager(&alienStatusPointer->waypointManager); + } + + /* still waiting: decrement timer */ + alienStatusPointer->NearStateTimer-=NormalFrameTime; + + if(alienStatusPointer->NearStateTimer<=0) + { + /* waiting has expired: go to wander */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + NPC_InitWanderData(&(alienStatusPointer->wanderData)); + alienStatusPointer->BehaviourState = ABS_Wander; + InitWaypointManager(&alienStatusPointer->waypointManager); + + StartAlienMovementSequence(sbPtr); + + alienStatusPointer->NearStateTimer = 0; + } +} + +static void AlienNearState_Avoidance(STRATEGYBLOCK *sbPtr) +{ + int terminateState = 0; + ALIEN_STATUS_BLOCK *alienStatusPointer; + + LOCALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + #if ALL_NEW_AVOIDANCE_ALIEN + /* New avoidance kernel. */ + + /* Update sequence! */ + AlienHandleMovingAnimation(sbPtr); + + NPCSetVelocity(sbPtr, &(alienStatusPointer->avoidanceManager.avoidanceDirection), (alienStatusPointer->MaxSpeed)); + /* Velocity CANNOT be zero, unless deliberately so! */ + { + AVOIDANCE_RETURN_CONDITION rc; + + rc=AllNewAvoidanceKernel(sbPtr,&alienStatusPointer->avoidanceManager); + + if (rc!=AvRC_Avoidance) { + terminateState=1; + } + } + #else + /* set velocity */ + LOCALASSERT((alienStatusPointer->moveData.avoidanceDirn.vx!=0)|| + (alienStatusPointer->moveData.avoidanceDirn.vy!=0)|| + (alienStatusPointer->moveData.avoidanceDirn.vz!=0)); + + NPCSetVelocity(sbPtr, &(alienStatusPointer->moveData.avoidanceDirn), (alienStatusPointer->MaxSpeed)); + + /* Update sequence! */ + AlienHandleMovingAnimation(sbPtr); + + /* next, decrement state timer */ + alienStatusPointer->NearStateTimer -= NormalFrameTime; + if(alienStatusPointer->NearStateTimer <= 0) terminateState = 1; + /* and check for an impeding collision */ + { + STRATEGYBLOCK *destructableObject; + NPC_OBSTRUCTIONREPORT obstruction; + NPC_IsObstructed(sbPtr,&(alienStatusPointer->moveData),&obstruction,&destructableObject); + if(obstruction.anySingleObstruction) + { + /* return to approach */ + terminateState = 1; + } + } + #endif + + if(terminateState) + { + if(AlienHasPathToTarget(sbPtr)) + { + /* switch to approach */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + InitWaypointManager(&alienStatusPointer->waypointManager); + alienStatusPointer->NearStateTimer = 0; + if (alienStatusPointer->Target->I_SBtype==I_BehaviourMarine) { + WarnMarineOfAttack(alienStatusPointer->Target,sbPtr); + } + /* no sequence change required */ + } else if (AlienIsAwareOfTarget(sbPtr)) { + /* Go to hunt. */ + alienStatusPointer->BehaviourState = ABS_Hunt; + InitWaypointManager(&alienStatusPointer->waypointManager); + alienStatusPointer->NearStateTimer = ALIEN_NEARWAITTIME; + } + else + { + /* switch to wander */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + NPC_InitWanderData(&(alienStatusPointer->wanderData)); + alienStatusPointer->BehaviourState = ABS_Wander; + alienStatusPointer->NearStateTimer = 0; + InitWaypointManager(&alienStatusPointer->waypointManager); + /* no sequence change required */ + } + } +} + +static void AlienNearState_Retreat(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + int approachingAirDuct = 0; + VECTORCH velocityDirection = {0,0,0}; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + + /* don't climb on walls, etc */ + dynPtr->UseStandardGravity=1; + + /* check if we should be crouched or standing up */ + + /* Update sequence! */ + AlienHandleMovingAnimation(sbPtr); + + /* should we change to approach state? */ + if(AlienIsAwareOfTarget(sbPtr)) + { + /* doesn't require a sequence change */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + InitWaypointManager(&alienStatusPointer->waypointManager); + alienStatusPointer->CurveTimeOut = 0; + if (alienStatusPointer->Target->I_SBtype==I_BehaviourMarine) { + WarnMarineOfAttack(alienStatusPointer->Target,sbPtr); + } + /* Bloodthirsty, these aliens... */ + return; + } + + /* Retreat target aquisition. */ + { + AIMODULE *targetModule; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + + targetModule = NearNPC_GetTargetAIModuleForRetreat(sbPtr, &(alienStatusPointer->moveData)); + + if (targetModule) { + //textprint("Target module is %s\n",targetModule->name); + textprint("Target AI module found, %x.\n",(int)targetModule); + } else { + textprint("Target module is NULL!\n"); + } + + if ((targetModule==sbPtr->containingModule->m_aimodule) + || (targetModule==NULL)) { + /* Hey, it'll drop through. */ + alienStatusPointer->BehaviourState = ABS_Hunt; + alienStatusPointer->CurveTimeOut = 0; + InitWaypointManager(&alienStatusPointer->waypointManager); + return; + } + + GLOBALASSERT(targetModule); + + thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); + if (!thisEp) { + //LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.",targetModule->name,sbPtr->containingModule->name)); + LOGDXFMT(("This assert is a busted adjacency!")); + GLOBALASSERT(thisEp); + } + /* If that fired, there's a farped adjacency. */ + + alienStatusPointer->wanderData.worldPosition=thisEp->position; + alienStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx; + alienStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy; + alienStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz; + + } + + /* ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(alienStatusPointer->wanderData.worldPosition),&alienStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, alienStatusPointer->MaxSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE_ALIEN + { + if (New_NPC_IsObstructed(sbPtr,&alienStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + alienStatusPointer->BehaviourState = ABS_Avoidance; + alienStatusPointer->NearStateTimer = NPC_AVOIDTIME; + InitWaypointManager(&alienStatusPointer->waypointManager); + return; + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_OBSTRUCTIONREPORT obstruction; + NPC_IsObstructed(sbPtr,&(alienStatusPointer->moveData),&obstruction,&destructableObject); + if((obstruction.environment)||(obstruction.otherCharacter)) + { + #if 1 + /* go to avoidance */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(alienStatusPointer->moveData.avoidanceDirn),&obstruction); + alienStatusPointer->BehaviourState = ABS_Avoidance; + alienStatusPointer->NearStateTimer = NPC_AVOIDTIME; + /* no sequence change required */ + return; + #endif + } + if(obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_ALIEN_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(alienStatusPointer->moveData), &(alienStatusPointer->wanderData.worldPosition), &velocityDirection)) + { + /* go to avoidance */ + NPC_OBSTRUCTIONREPORT obstruction = {1,0,0}; + NPC_InitMovementData(&(alienStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(alienStatusPointer->moveData.avoidanceDirn),&obstruction); + alienStatusPointer->BehaviourState = ABS_Avoidance; + alienStatusPointer->NearStateTimer = NPC_AVOIDTIME; + /* no sequence change required */ + return; + } + #endif +} + +static void AlienNearState_Hunt(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + int approachingAirDuct = 0; + VECTORCH velocityDirection = {0,0,0}; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + + /* don't climb on walls, etc */ + dynPtr->UseStandardGravity=1; + + /* check if we should be crouched or standing up */ + + { + int redo=0; + + if(alienStatusPointer->IAmCrouched) + { + /* curently crouched */ + if((!approachingAirDuct)&&(!AlienShouldBeCrawling(sbPtr))) + { + /* should be running*/ + alienStatusPointer->IAmCrouched = 0; + redo=1; + } + } + else + { + /* currently standing */ + if((approachingAirDuct)||(AlienShouldBeCrawling(sbPtr))) + { + /* should be crawling */ + alienStatusPointer->IAmCrouched = 1; + redo=1; + } + } + + if (redo) { + StartAlienMovementSequence(sbPtr); + } + } + + AlienHandleMovingAnimation(sbPtr); + + if (alienStatusPointer->IAmCrouched) { + /* Are we climbing? */ + if (AlienIsAbleToClimb(sbPtr)) { + dynPtr->UseStandardGravity=0; + } else { + dynPtr->UseStandardGravity=1; + } + } else { + dynPtr->UseStandardGravity=1; + } + + /* should we change to approach state? */ + if(AlienHasPathToTarget(sbPtr)) + { + /* doesn't require a sequence change */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + InitWaypointManager(&alienStatusPointer->waypointManager); + alienStatusPointer->CurveTimeOut = 0; + if (alienStatusPointer->Target->I_SBtype==I_BehaviourMarine) { + WarnMarineOfAttack(alienStatusPointer->Target,sbPtr); + } + /* Bloodthirsty, these aliens... */ + return; + } + + /* Hunting target aquisition. */ + if (sbPtr->containingModule!=alienStatusPointer->my_containing_module) { + alienStatusPointer->huntingModule=NULL; + } + /* Check again. */ + if (alienStatusPointer->huntingModule!=NULL) { + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + + thisEp=GetAIModuleEP(alienStatusPointer->huntingModule,sbPtr->containingModule->m_aimodule); + if (!thisEp) { + alienStatusPointer->huntingModule=NULL; + } + } + + if (alienStatusPointer->huntingModule==NULL) { + AIMODULE *targetModule; + + if (alienStatusPointer->Mission==AM_GlobalHunt) { + targetModule = FarNPC_GetTargetAIModuleForGlobalHunt(sbPtr); + } else { + targetModule = FarNPC_GetTargetAIModuleForGlobalHunt(sbPtr); + } + + if (targetModule) { + //textprint("Target module is %s\n",targetModule->name); + textprint("Target AI module for hunt found, %x.\n",(int)targetModule); + } else { + textprint("Target module is NULL!\n"); + } + + if (targetModule==NULL) { + /* Better have a handler for this. */ + #if 0 + alienStatusPointer->BehaviourState = ABS_Dormant; + alienStatusPointer->CurveTimeOut = 0; + if (HModelSequence_Exists(&alienStatusPointer->HModelController,HMSQT_AlienStand,ASSS_Dormant)) { + SetAlienShapeAnimSequence_Core(sbPtr,HMSQT_AlienStand,ASSS_Dormant,-1,ONE_FIXED); + } else { + SetAlienShapeAnimSequence_Core(sbPtr,HMSQT_AlienStand,ASSS_Standard,ONE_FIXED,(ONE_FIXED>>2)); + } + #else + alienStatusPointer->BehaviourState = ABS_Wander; + alienStatusPointer->CurveTimeOut = 0; + #endif + return; + } + + if (targetModule==sbPtr->containingModule->m_aimodule) { + /* We should have arrived - get a new target? */ + if (alienStatusPointer->Target==NULL) { + /* Oops - nobody about. */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + NPC_InitWanderData(&(alienStatusPointer->wanderData)); + alienStatusPointer->BehaviourState = ABS_Wander; + alienStatusPointer->CurveTimeOut = 0; + InitWaypointManager(&alienStatusPointer->waypointManager); + } else { + alienStatusPointer->Target=NULL; + alienStatusPointer->BehaviourState = ABS_Hunt; + InitWaypointManager(&alienStatusPointer->waypointManager); + alienStatusPointer->CurveTimeOut = 0; + } + return; + } + + GLOBALASSERT(targetModule); + + alienStatusPointer->huntingModule=targetModule; + } + + { + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + + thisEp=GetAIModuleEP(alienStatusPointer->huntingModule,sbPtr->containingModule->m_aimodule); + if (!thisEp) { + LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.",(*(alienStatusPointer->huntingModule->m_module_ptrs))->name,sbPtr->containingModule->name)); + //LOGDXFMT(("This assert is a busted adjacency!")); + GLOBALASSERT(thisEp); + } + /* If that fired, there's a farped adjacency. */ + + alienStatusPointer->wanderData.worldPosition=thisEp->position; + alienStatusPointer->wanderData.worldPosition.vx+=alienStatusPointer->huntingModule->m_world.vx; + alienStatusPointer->wanderData.worldPosition.vy+=alienStatusPointer->huntingModule->m_world.vy; + alienStatusPointer->wanderData.worldPosition.vz+=alienStatusPointer->huntingModule->m_world.vz; + + } + + /* ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(alienStatusPointer->wanderData.worldPosition),&alienStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, alienStatusPointer->MaxSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE_ALIEN + { + if (New_NPC_IsObstructed(sbPtr,&alienStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + alienStatusPointer->BehaviourState = ABS_Avoidance; + alienStatusPointer->NearStateTimer = NPC_AVOIDTIME; + InitWaypointManager(&alienStatusPointer->waypointManager); + return; + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_OBSTRUCTIONREPORT obstruction; + NPC_IsObstructed(sbPtr,&(alienStatusPointer->moveData),&obstruction,&destructableObject); + if((obstruction.environment)||(obstruction.otherCharacter)) + { + #if 1 + /* go to avoidance */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(alienStatusPointer->moveData.avoidanceDirn),&obstruction); + alienStatusPointer->BehaviourState = ABS_Avoidance; + alienStatusPointer->NearStateTimer = NPC_AVOIDTIME; + /* no sequence change required */ + return; + #endif + } + if(obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_ALIEN_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(alienStatusPointer->moveData), &(alienStatusPointer->wanderData.worldPosition), &velocityDirection)) + { + /* go to avoidance */ + NPC_OBSTRUCTIONREPORT obstruction = {1,0,0}; + NPC_InitMovementData(&(alienStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(alienStatusPointer->moveData.avoidanceDirn),&obstruction); + alienStatusPointer->BehaviourState = ABS_Avoidance; + alienStatusPointer->NearStateTimer = NPC_AVOIDTIME; + /* no sequence change required */ + return; + } + #endif +} + +/* Patrick 27/6/97 ********************************* +Some support functions for the alien: +Hopefully, these are fairly obvious... +****************************************************/ +void SetAlienShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime) +{ + + ALIEN_STATUS_BLOCK *alienStatus=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(length!=0); + + alienStatus->last_anim_length=length; + if (alienStatus->last_anim_length==-1) { + /* Stops divisions by zero. */ + alienStatus->last_anim_length=ONE_FIXED; + } + + /* Consider wounding. */ + #if WOUNDING_SPEED_EFFECTS + { + int factor; + + factor=GetAlienSpeedFactor_ForSequence(sbPtr,type,subtype); + + if (factor!=ONE_FIXED) { + length=DIV_FIXED(length,factor); + } + + } + #endif + + if (tweeningtime<=0) { + InitHModelSequence(&alienStatus->HModelController,(int)type,subtype,length); + } else { + InitHModelTweening(&alienStatus->HModelController, tweeningtime, (int)type,subtype,length, 1); + } + + if (AvP.Network != I_No_Network) + { + AddNetMsg_AlienAISeqChange(sbPtr,type,subtype,length,tweeningtime); + } + + alienStatus->HModelController.Playing=1; + /* Might be unset... */ +} + +void SetAlienShapeAnimSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length) { + + SetAlienShapeAnimSequence_Core(sbPtr,type,subtype,length,(ONE_FIXED>>2)); + +} + +int AlienHasNoArms(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatus=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + /* Check wounds. */ + + /* Crawl if you've lost both arm sections. */ + if (alienStatus->Wounds&(section_flag_left_arm)) { + if (alienStatus->Wounds&(section_flag_right_arm)) { + return(1); + } + } + return(0); +} + +int AlienIsAbleToStand(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatus=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + /* Check wounds. */ + + /* Crawl if you've lost any leg sections. */ + if (alienStatus->Wounds&(section_flag_left_leg|section_flag_right_leg)) return(0); + /* Also crawl if you've lost both feet. */ + if ((alienStatus->Wounds§ion_flag_left_foot) + &&(alienStatus->Wounds§ion_flag_right_foot)) return(0); + + return(1); +} + +int AlienShouldBeCrawling(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatus=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + if(sbPtr->DynPtr->OrientMat.mat22<63000) return 1; + if(sbPtr->containingModule->m_flags & MODULEFLAG_AIRDUCT) return 1; + /* Wounding! */ + + if (AlienIsAbleToStand(sbPtr)==0) { + return(1); + } + + if (alienStatus->BehaviourState==ABS_Attack) { + return(0); + /* Second lowest priority. */ + } + + /* New thing, 22/6/99 CDF. */ + if (AlienHasNoArms(sbPtr)) { + /* This just looks silly. */ + return(0); + } + + if ((AlienIsEncouragedToCrawl())&&(alienStatus->EnableWaypoints)) { + return(1); + } + + /* Does a praetorian just feel like it? */ + if (alienStatus->PreferToCrouch) { + return(1); + } + + return(0); +} + +int AlienIsAbleToClimb(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatus=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + if (alienStatus->Type==AT_Praetorian) { + /* Praetorian Guard can't climb. Sorry. */ + return(0); + } + + /* Can only climb if alien has both hands... */ + if ((alienStatus->Wounds§ion_flag_left_hand) + ||(alienStatus->Wounds§ion_flag_right_hand)) { + return(0); + } + + return 1; + +} + +int AlienIsAwareOfTarget(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(sbPtr->containingModule); + /* test for player being cloaked */ + if (alienStatusPointer->Target==Player->ObStrategyBlock) + { + GLOBALASSERT(alienStatusPointer->Target->containingModule); + #if 0 + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + if((playerStatusPtr->cloakOn==1)&&(playerStatusPtr->cloakPositionGivenAway==0)) { + return 0; + } + } + #endif + /* test for player being an alien */ + if(AvP.PlayerType==I_Alien) { + return 0; + } + #if 0 + /* Expensive path test? */ + if (GetNextModuleForLink_Core(sbPtr->containingModule->m_aimodule, + alienStatusPointer->Target->containingModule->m_aimodule,4,1,1)) { + return(1); + } else { + return(0); + } + #endif + } else { + /* NPCs test... */ + if (alienStatusPointer->Target==NULL) { + /* Can't be aware of nothing! */ + return 0; + } else { + GLOBALASSERT(alienStatusPointer->Target->containingModule); + /* Module visibility test? */ + #if 1 + if ((IsModuleVisibleFromModule(sbPtr->containingModule, + alienStatusPointer->Target->containingModule))) { + return(1); + } else { + return(0); + } + #else + if (GetNextModuleForLink_Core(sbPtr->containingModule->m_aimodule, + alienStatusPointer->Target->containingModule->m_aimodule,4,1,1)) { + return(1); + } else { + return(0); + } + #endif + } + } + + return 1; +} + +int AlienHasPathToTarget(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(sbPtr->containingModule); + /* test for player being cloaked */ + if (alienStatusPointer->Target==Player->ObStrategyBlock) + { + GLOBALASSERT(alienStatusPointer->Target->containingModule); + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + #if 0 + if((playerStatusPtr->cloakOn==1)&&(playerStatusPtr->cloakPositionGivenAway==0)) { + return 0; + } + #endif + } + /* test for player being an alien */ + if(AvP.PlayerType==I_Alien) { + return 0; + } + /* Expensive path test? */ + if (GetNextModuleForLink_Core(sbPtr->containingModule->m_aimodule, + alienStatusPointer->Target->containingModule->m_aimodule,4,1,1)) { + return(1); + } else { + return(0); + } + + } else { + /* NPCs test... */ + if (alienStatusPointer->Target==NULL) { + /* Can't be aware of nothing! */ + return 0; + } else { + GLOBALASSERT(alienStatusPointer->Target->containingModule); + /* Module visibility test? */ + #if 0 + if ((IsModuleVisibleFromModule(sbPtr->containingModule, + alienStatusPointer->Target->containingModule))) { + return(1); + } else { + return(0); + } + #else + if (GetNextModuleForLink_Core(sbPtr->containingModule->m_aimodule, + alienStatusPointer->Target->containingModule->m_aimodule,4,1,1)) { + return(1); + } else { + return(0); + } + #endif + } + } + + return 1; +} + +ATTACK_DATA *AlienIsAbleToPounce(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + ATTACK_DATA *thisAttack; + VECTORCH targetPoint; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + /* First rule. Must be on a flat floor. */ + if(sbPtr->DynPtr->OrientMat.mat22<63000) { + return(NULL); + } + if(sbPtr->DynPtr->IsInContactWithFloor==0) { + return(NULL); + } + /* And not in an airduct. */ + if(sbPtr->containingModule->m_flags & MODULEFLAG_AIRDUCT) { + return(NULL); + } + /* Wounding! */ + + /* Can't pounce if you've lost any leg sections. */ + if (alienStatusPointer->Wounds&(section_flag_left_leg|section_flag_right_leg)) { + return(NULL); + } + /* Also not if you've lost both feet. */ + if ((alienStatusPointer->Wounds§ion_flag_left_foot) + &&(alienStatusPointer->Wounds§ion_flag_right_foot)) { + return(NULL); + } + + /* Also not if you're badly hurt. */ + { + int factor; + + factor=GetAlienSpeedFactor_ForSequence(sbPtr,HMSQT_AlienRun,(int)ARSS_Standard); + + if (factor<((ONE_FIXED*3)/4)) { + return(NULL); + } + } + /* Status of target? */ + if (alienStatusPointer->Target==NULL) { + /* Don't waste my time. */ + return(NULL); + } + if (alienStatusPointer->Target->SBdptr==NULL) { + /* Ditto. Target is far. */ + return(NULL); + } + + GetTargetingPointOfObject(alienStatusPointer->Target->SBdptr,&targetPoint); + + /* Do we have a clear line of sight? */ + + if (!(IsThisObjectVisibleFromThisPosition_WithIgnore(sbPtr->SBdptr,alienStatusPointer->Target->SBdptr,&targetPoint,NPC_MAX_VIEWRANGE))) { + return(NULL); + } + + + /* Finally, test the sequence. */ + thisAttack=GetAlienPounceAttack(&alienStatusPointer->HModelController,alienStatusPointer->Wounds, + alienStatusPointer->IAmCrouched); + + if ((thisAttack==NULL)&&(alienStatusPointer->IAmCrouched==0)) { + /* Try again crouched. Pook. */ + thisAttack=GetAlienPounceAttack(&alienStatusPointer->HModelController,alienStatusPointer->Wounds, + 1); + } + + return(thisAttack); + +} + +static int StartAlienPounce(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + ATTACK_DATA *thisAttack; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + /* Check validity, and do it. */ + + thisAttack=AlienIsAbleToPounce(sbPtr); + + if (thisAttack==NULL) { + /* Can't do it. */ + return(0); + } + + SetAlienShapeAnimSequence_Core(sbPtr,thisAttack->Sequence_Type,thisAttack->Sub_Sequence, + thisAttack->Sequence_Length,thisAttack->TweeningTime); + + alienStatusPointer->HModelController.Looped=0; + alienStatusPointer->HModelController.LoopAfterTweening=0; + + alienStatusPointer->current_attack=thisAttack; + + alienStatusPointer->BehaviourState = ABS_Pounce; + alienStatusPointer->NearStateTimer=0; + + return(1); +} + +static void CheckPounceIntegrity(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + VECTORCH targetPoint; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + + if (alienStatusPointer->Target==NULL) { + /* Attack what? */ + alienStatusPointer->BehaviourState = ABS_Hunt; + alienStatusPointer->NearStateTimer = ALIEN_NEARWAITTIME; + return; + } + + if ((alienStatusPointer->Target->SBdptr==NULL) + ||((alienStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy)>1000)) { + + /* Yuck. Target is far, or too far below you. */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + + StartAlienMovementSequence(sbPtr); + + alienStatusPointer->NearStateTimer = 0; + alienStatusPointer->CurveTimeOut = 0; + return; + } + + GetTargetingPointOfObject(alienStatusPointer->Target->SBdptr,&targetPoint); + + /* Do we have a clear line of sight? */ + + if (!(IsThisObjectVisibleFromThisPosition_WithIgnore(sbPtr->SBdptr,alienStatusPointer->Target->SBdptr,&targetPoint,NPC_MAX_VIEWRANGE))) { + /* Can't see! */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + + StartAlienMovementSequence(sbPtr); + + alienStatusPointer->NearStateTimer = 0; + alienStatusPointer->CurveTimeOut = 0; + return; + } + + + /* Orientate towards player, just to make sure we're facing */ + { + VECTORCH orientationDirn; + int i; + orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; + i = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + if (i==0) { + /* Still not right. Be careful. */ + alienStatusPointer->HModelController.StopAfterTweening=1; + } else { + /* Okay for the moment. */ + alienStatusPointer->HModelController.StopAfterTweening=0; + } + + } + + /* change back to approach?: don't need to directly test if we should go to wander, as + approach state will do this... */ + { + int distanceToPlayer = VectorDistance(&(dynPtr->Position),&(alienStatusPointer->Target->DynPtr->Position)); + if((distanceToPlayer>ALIEN_POUNCE_MAXRANGE)) { + + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + + StartAlienMovementSequence(sbPtr); + + alienStatusPointer->NearStateTimer = 0; + alienStatusPointer->CurveTimeOut = 0; + return; + } + } + + /* Are we still able to pounce? */ + + /* Not if you've lost any leg sections. */ + if ( (alienStatusPointer->Wounds&(section_flag_left_leg|section_flag_right_leg)) + /* Also not if you've lost both feet. */ + || ((alienStatusPointer->Wounds§ion_flag_left_foot) + &&(alienStatusPointer->Wounds§ion_flag_right_foot)) ) { + + /* Can't stand either. Fall over. */ + /* That implies going back to approach, btw. */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + + StartAlienMovementSequence(sbPtr); + + alienStatusPointer->NearStateTimer = 0; + alienStatusPointer->CurveTimeOut = 0; + } + +} + +static void ApplyPounceImpulse(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + VECTORCH pounceVector,targetPoint; + int dist,speed,factor; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + LOCALASSERT(alienStatusPointer->Target); + + GetTargetingPointOfObject(alienStatusPointer->Target->SBdptr,&targetPoint); + + dist = VectorDistance(&(dynPtr->Position),&targetPoint); + + /* Apply a correction based on range. */ + targetPoint.vy-=(dist>>3); + + pounceVector.vx=targetPoint.vx-dynPtr->Position.vx; + pounceVector.vy=targetPoint.vy-dynPtr->Position.vy; + pounceVector.vz=targetPoint.vz-dynPtr->Position.vz; + + Normalise(&pounceVector); + /* Must jump at least a little bit upwards. */ + if (pounceVector.vy>-10000) { + pounceVector.vy=-10000; + } + + switch (alienStatusPointer->Type) { + case AT_Standard: + default: + speed=ALIEN_JUMP_SPEED; + break; + case AT_Predalien: + speed=PREDALIEN_JUMP_SPEED; + break; + case AT_Praetorian: + speed=PRAETORIAN_JUMP_SPEED; + break; + } + + factor=GetAlienSpeedFactor_ForSequence(sbPtr,HMSQT_AlienRun,(int)ARSS_Standard); + speed=MUL_FIXED(speed,factor); + + pounceVector.vx=MUL_FIXED(speed,pounceVector.vx); + pounceVector.vy=MUL_FIXED(speed,pounceVector.vy); + pounceVector.vz=MUL_FIXED(speed,pounceVector.vz); + + sbPtr->DynPtr->LinImpulse=pounceVector; + +} + +static void AlienNearState_Pounce(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + + /* don't climb on walls, etc */ + dynPtr->UseStandardGravity=1; + + /* Firstly, are we actually pouncing yet? */ + /* NearStateTimer is a status flag. */ + + if (alienStatusPointer->NearStateTimer==0) { + /* Still tweening? */ + if (alienStatusPointer->HModelController.Tweening==Controller_NoTweening) { + /* We've finished! Are we facing right? */ + VECTORCH orientationDirn; + int i; + + orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; + i = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + if (i==0) { + /* Still not right! Wait for proper facing. */ + alienStatusPointer->HModelController.Playing=0; + CheckPounceIntegrity(sbPtr); + return; + } else { + /* Okay, pounce! */ + + ApplyPounceImpulse(sbPtr); + + alienStatusPointer->HModelController.Playing=1; + alienStatusPointer->NearStateTimer=1; + } + } else { + /* Yup, still tweening. Check state validity. */ + CheckPounceIntegrity(sbPtr); + } + } else { + /* We must be in the pounce. Can't break out of this until the anim finishes. */ + + if ((alienStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(alienStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) { + /* You know what? Just did! */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + + StartAlienMovementSequence(sbPtr); + InitWaypointManager(&alienStatusPointer->waypointManager); + + alienStatusPointer->NearStateTimer = 0; + alienStatusPointer->CurveTimeOut = 0; + /* Choose whether to pounce again. */ + Alien_ElectToPounce(sbPtr); + return; + + } + + AlienNearDamageShell(sbPtr); + + } + +} + +static int CheckJumpingAbility(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + if (alienStatusPointer->JumpDetected==0) { + /* No jump sequence. Always a bad start. */ + return(0); + } + + /* Must be upright. */ + if(sbPtr->DynPtr->OrientMat.mat22<63000) { + return(0); + } + + /* Only the leg test here, so far. */ + if ( (alienStatusPointer->Wounds&(section_flag_left_leg|section_flag_right_leg)) + || ((alienStatusPointer->Wounds§ion_flag_left_foot) + &&(alienStatusPointer->Wounds§ion_flag_right_foot)) ) { + return(0); + } else { + return(1); + } + +} + +static int GoToJump(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + int speed,factor; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + + if (CheckJumpingAbility(sbPtr)==0) { + /* bleah. */ + return(0); + } + + /* Should be able to jump now! */ + + dynPtr->LinVelocity.vx=0; + dynPtr->LinVelocity.vy=0; + dynPtr->LinVelocity.vz=0; + + dynPtr->LinImpulse.vx=0; + dynPtr->LinImpulse.vy=-10000; + dynPtr->LinImpulse.vz=20000; + + RotateVector(&dynPtr->LinImpulse,&dynPtr->OrientMat); + Normalise(&dynPtr->LinImpulse); + + switch (alienStatusPointer->Type) { + case AT_Standard: + default: + speed=ALIEN_JUMP_SPEED; + break; + case AT_Predalien: + speed=PREDALIEN_JUMP_SPEED; + break; + case AT_Praetorian: + speed=PRAETORIAN_JUMP_SPEED; + break; + } + factor=GetAlienSpeedFactor_ForSequence(sbPtr,HMSQT_AlienRun,(int)ARSS_Standard); + speed=MUL_FIXED(speed,factor); + + dynPtr->LinImpulse.vx=MUL_FIXED(speed,dynPtr->LinImpulse.vx); + dynPtr->LinImpulse.vy=MUL_FIXED(speed,dynPtr->LinImpulse.vy); + dynPtr->LinImpulse.vz=MUL_FIXED(speed,dynPtr->LinImpulse.vz); + + alienStatusPointer->BehaviourState = ABS_Jump; + alienStatusPointer->NearStateTimer = 0; + SetAlienShapeAnimSequence(sbPtr,HMSQT_AlienRun,(int)ARSS_Jump,ONE_FIXED>>1); + + return(1); +} + +static void AlienNearState_Jump(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + struct collisionreport *nextReport; + int terminateState=0; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + nextReport = dynPtr->CollisionReportPtr; + + /* Pretty simple one, this. Just fly through the air, until you hit something. */ + + dynPtr->UseStandardGravity=1; + /* Just to be on the safe side. */ + + while(nextReport) + { + if (nextReport->ObstacleSBPtr==NULL) { + /* This is the environment. */ + terminateState=1; + } else { + switch (nextReport->ObstacleSBPtr->I_SBtype) { + /* Futureproofing. */ + default: + /* Oh, what the heck. */ + terminateState=1; + break; + } + } + nextReport = nextReport->NextCollisionReportPtr; + } + + if (dynPtr->IsInContactWithFloor) { + terminateState=1; + } + + if (terminateState) { + /* should be crawling. */ + alienStatusPointer->IAmCrouched = 1; + + StartAlienMovementSequence(sbPtr); + InitWaypointManager(&alienStatusPointer->waypointManager); + + /* Hang on for dear life... */ + if (AlienIsAbleToClimb(sbPtr)) { + dynPtr->UseStandardGravity=0; + } else { + dynPtr->UseStandardGravity=1; + } + /* And change back to approach. */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + alienStatusPointer->NearStateTimer = 0; + alienStatusPointer->CurveTimeOut = 0; + return; + + } +} + +void AlienNearState_Dormant(STRATEGYBLOCK *sbPtr) +{ + /* wait until near state timer runs out, then wander: + alternatively, if we can attack the player, go straight to approach */ + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + + /* Also used for FAR! */ + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + + /* don't climb on walls, etc */ + dynPtr->UseStandardGravity=1; + /* Zero velocity. */ + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + + if (!sbPtr->SBdptr) { + if (alienStatusPointer->HModelController.Playing) { + /* Try to call this as little as possible. */ + ProveHModel_Far(&alienStatusPointer->HModelController,sbPtr); + if (alienStatusPointer->HModelController.Tweening==0) { + alienStatusPointer->HModelController.Playing=0; + } + } + } else { + alienStatusPointer->HModelController.Playing=1; + } + + /* Brushing Test. */ + { + struct collisionreport *nextReport; + nextReport = sbPtr->DynPtr->CollisionReportPtr; + + while(nextReport) + { + if(nextReport->ObstacleSBPtr) + { + if((nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourMarine)|| + ((nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourMarinePlayer) + &&(AvP.PlayerType!=I_Alien))|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourAlienPlayer)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourPredatorPlayer)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourNetGhost)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourXenoborg)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourPredatorAlien)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourQueenAlien)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourFaceHugger)) + { + Alien_Awaken(sbPtr); + } + } + nextReport = nextReport->NextCollisionReportPtr; + } + } + + +} + +void AlienNearState_Awakening(STRATEGYBLOCK *sbPtr) +{ + /* wait until near state timer runs out, then wander: + alternatively, if we can attack the player, go straight to approach */ + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + + /* Also used for FAR! */ + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + + if (!sbPtr->SBdptr) { + ProveHModel_Far(&alienStatusPointer->HModelController,sbPtr); + } + + /* don't climb on walls, etc */ + dynPtr->UseStandardGravity=1; + /* Zero velocity. */ + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + + if ((alienStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(alienStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) { + + Alien_GoToApproach(sbPtr); + } + + +} + +void AlienNearState_Taunting(STRATEGYBLOCK *sbPtr) +{ + + ALIEN_STATUS_BLOCK *alienStatusPointer; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr=sbPtr->DynPtr; + LOCALASSERT(alienStatusPointer); + LOCALASSERT(dynPtr); + + if (!sbPtr->SBdptr) { + ProveHModel_Far(&alienStatusPointer->HModelController,sbPtr); + } + + /* Orientate towards target, to avoid looking stupid */ + if (alienStatusPointer->Target) { + + VECTORCH orientationDirn; + orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; + NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + } + + /* If finished, exit. If on fire, go mental. */ + if ((HModelAnimation_IsFinished(&alienStatusPointer->HModelController)) + ||(sbPtr->SBDamageBlock.IsOnFire)) { + /* Exit state somehow. */ + InitWaypointManager(&alienStatusPointer->waypointManager); + + if(AlienHasPathToTarget(sbPtr)) + { + /* Go to approach. */ + StartAlienMovementSequence(sbPtr); + NPC_InitMovementData(&(alienStatusPointer->moveData)); + alienStatusPointer->BehaviourState = ABS_Approach; + alienStatusPointer->CurveTimeOut = 0; + if (alienStatusPointer->Target->I_SBtype==I_BehaviourMarine) { + WarnMarineOfAttack(alienStatusPointer->Target,sbPtr); + } + return; + } else if (AlienIsAwareOfTarget(sbPtr)) { + /* Go to hunt. */ + StartAlienMovementSequence(sbPtr); + alienStatusPointer->BehaviourState = ABS_Hunt; + alienStatusPointer->NearStateTimer = ALIEN_NEARWAITTIME; + return; + } else { + + /* Go to wander */ + NPC_InitMovementData(&(alienStatusPointer->moveData)); + NPC_InitWanderData(&(alienStatusPointer->wanderData)); + alienStatusPointer->BehaviourState = ABS_Wander; + + StartAlienMovementSequence(sbPtr); + + alienStatusPointer->NearStateTimer = 0; + return; + } + } else { + return; + } + +} + +int TargetIsFiringFlamethrowerAtAlien(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + + LOCALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + if (alienStatusPointer->Target==NULL) { + return(0); + } + + /* First, let's see what the target is. */ + if (alienStatusPointer->Target->I_SBtype==I_BehaviourMarinePlayer) { + /* Is the player firing a flamethrower? */ + PLAYER_WEAPON_DATA *weaponPtr; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + if (AvP.PlayerType!=I_Marine) { + return(0); + } + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + + if (weaponPtr->WeaponIDNumber != WEAPON_FLAMETHROWER) { + return(0); + } + if (weaponPtr->CurrentState != WEAPONSTATE_FIRING_PRIMARY) { + return(0); + } + } else if (alienStatusPointer->Target->I_SBtype==I_BehaviourMarine) { + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(alienStatusPointer->Target->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if ((marineStatusPointer->My_Weapon->id!=MNPCW_Flamethrower) + &&(marineStatusPointer->My_Weapon->id!=MNPCW_MFlamer)) { + return(0); + } + if (marineStatusPointer->behaviourState!=MBS_Firing) { + return(0); + } + } else { + /* Gotta insert a case for netghosts. */ + return(0); + } + + /* Next, let's see if the alien and the target are both in the other's front arc. */ + + { + + VECTORCH sourcepos,targetpos,offset; + MATRIXCH WtoL; + + WtoL=sbPtr->DynPtr->OrientMat; + GetTargetingPointOfObject_Far(sbPtr,&sourcepos); + GetTargetingPointOfObject_Far(alienStatusPointer->Target,&targetpos); + + offset.vx=sourcepos.vx-targetpos.vx; + offset.vy=sourcepos.vy-targetpos.vy; + offset.vz=sourcepos.vz-targetpos.vz; + + TransposeMatrixCH(&WtoL); + RotateVector(&offset,&WtoL); + + if ( (offset.vz <0) + && (offset.vz < offset.vx) + && (offset.vz < -offset.vx) + && (offset.vz < offset.vy) + && (offset.vz < -offset.vy) ) { + + /* 90 horizontal, 90 vertical... continue. */ + } else { + return(0); + } + + /* Now test it for the other way round. */ + + WtoL=alienStatusPointer->Target->DynPtr->OrientMat; + GetTargetingPointOfObject_Far(alienStatusPointer->Target,&sourcepos); + GetTargetingPointOfObject_Far(sbPtr,&targetpos); + + offset.vx=sourcepos.vx-targetpos.vx; + offset.vy=sourcepos.vy-targetpos.vy; + offset.vz=sourcepos.vz-targetpos.vz; + + TransposeMatrixCH(&WtoL); + RotateVector(&offset,&WtoL); + + if ( (offset.vz <0) + && (offset.vz < offset.vx) + && (offset.vz < -offset.vx) + && (offset.vz < offset.vy) + && (offset.vz < -offset.vy) ) { + + /* 90 horizontal, 90 vertical... continue. */ + } else { + return(0); + } + + } + + /* If here, then it must be true! */ + return(1); +} + +static int StartAlienTaunt(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + int a,b,numTaunts,sub_sequence; + + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + /* Check validity, and do it. */ + + if ((AlienIsAbleToStand(sbPtr))==0) { + /* First the crouch case. */ + if (HModelSequence_Exists(&alienStatusPointer->HModelController,(int)HMSQT_AlienCrouch,ACrSS_Taunt)) { + SetAlienShapeAnimSequence_Core(sbPtr,(int)HMSQT_AlienCrouch,ACrSS_Taunt,-1,(ONE_FIXED>>3)); + + alienStatusPointer->HModelController.Looped=0; + alienStatusPointer->HModelController.LoopAfterTweening=0; + + alienStatusPointer->BehaviourState = ABS_Taunting; + alienStatusPointer->NearStateTimer=0; + + if ((FastRandom()&127)<10) { + DoAlienAITauntHiss(sbPtr); + } + return(1); + } else { + /* No sequence - can't do it. */ + return(0); + } + } + + /* By this point, we must be able to stand. */ + numTaunts=0; + + /* How many taunts are there? */ + + a=0; + while (AlienStandingTauntList[a]!=-1) { + if (HModelSequence_Exists(&alienStatusPointer->HModelController,(int)HMSQT_AlienStand,AlienStandingTauntList[a])) { + numTaunts++; + } + a++; + } + + if (numTaunts<1) { + /* Can't do it. */ + return(0); + } + + b=FastRandom()%numTaunts; + sub_sequence=-1; + a=0; + + while (sub_sequence==-1) { + if (HModelSequence_Exists(&alienStatusPointer->HModelController,(int)HMSQT_AlienStand,AlienStandingTauntList[a])) { + if (b==0) { + /* This one! */ + sub_sequence=AlienStandingTauntList[a]; + } else { + b--; + } + } + a++; + GLOBALASSERT(AlienStandingTauntList[a]!=-1); + GLOBALASSERT(b>=0); + } + /* The things I do for transparent code... */ + + SetAlienShapeAnimSequence_Core(sbPtr,(int)HMSQT_AlienStand,sub_sequence,-1,(ONE_FIXED>>3)); + + alienStatusPointer->HModelController.Looped=0; + alienStatusPointer->HModelController.LoopAfterTweening=0; + + alienStatusPointer->BehaviourState = ABS_Taunting; + alienStatusPointer->NearStateTimer=0; + + if ((FastRandom()&127)<10) { + DoAlienAITauntHiss(sbPtr); + } + + return(1); +} diff --git a/3dc/avp/Bh_pred.c b/3dc/avp/Bh_pred.c new file mode 100644 index 0000000..ab03b7d --- /dev/null +++ b/3dc/avp/Bh_pred.c @@ -0,0 +1,7208 @@ +/* Patrick 4/7/97 --------------------------------------------------- +Source file for predator AI +---------------------------------------------------------------------*/ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "comp_shp.h" +#include "dynblock.h" +#include "dynamics.h" +#include "pfarlocs.h" +#include "pheromon.h" +#include "bh_types.h" +#include "pvisible.h" +#include "bh_far.h" +#include "bh_debri.h" +#include "bh_pred.h" +#include "bh_paq.h" +#include "bh_queen.h" +#include "bh_marin.h" +#include "bh_alien.h" +#include "lighting.h" +#include "bh_weap.h" +#include "weapons.h" +#include "psnd.h" +#include "equipmnt.h" +#include "los.h" +#include "AI_Sight.h" +#include "targeting.h" +#include "dxlog.h" +#include "ShowCmds.h" +#include "huddefs.h" +#include "pldghost.h" +#include "bh_gener.h" +#include "bh_corpse.h" +#include "bh_dummy.h" +#include "bh_agun.h" +#include "scream.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "extents.h" + +#define ALL_NEW_AVOIDANCE_PRED 1 +#define PREDATOR_HIT_DELTAS 1 + +/* external global variables used in this file */ +extern int ModuleArraySize; +extern char *ModuleCurrVisArray; +extern int NormalFrameTime; +extern SECTION_DATA* LOS_HModel_Section; /* Section of HModel hit */ +extern void HandleWeaponImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *section_pointer); +extern void HandleSpearImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *this_section_data); +extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); +extern int GlobalFrameCounter; +extern int RouteFinder_CallsThisFrame; +extern int ShowPredoStats; +extern unsigned char Null_Name[8]; +extern DEATH_DATA Predator_Special_SelfDestruct_Death; + +static DAMAGE_PROFILE Pred_Weapon_Damage; + +extern void NPC_GetBimbleTarget(STRATEGYBLOCK *sbPtr,VECTORCH *output); +extern STRATEGYBLOCK* InitialiseEnergyBoltBehaviourKernel(VECTORCH *position,MATRIXCH *orient, int player, DAMAGE_PROFILE *damage, int factor); +extern STRATEGYBLOCK* CreatePPPlasmaBoltKernel(VECTORCH *position,MATRIXCH *orient, int player); +extern DISPLAYBLOCK *HtoHDamageToHModel(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, STRATEGYBLOCK *source, VECTORCH *attack_dir); + +/* prototypes for this file */ +static void ProcessFarPredatorTargetAIModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule); + +static PRED_RETURN_CONDITION Execute_PFS_Wander(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PFS_Hunt(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PFS_Retreat(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PFS_Avoidance(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PFS_Pathfinder(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PFS_Return(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PFS_Engage(STRATEGYBLOCK *sbPtr); + +static PRED_RETURN_CONDITION Execute_PNS_Approach(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_Avoidance(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_StandGround(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_Wander(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_Hunt(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_Retreat(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_EngageWithPistol(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_DischargePistol(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_EngageWithPlasmaCaster(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_AttackWithPlasmaCaster(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_EngageWithWristblade(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_AttackWithWristblade(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_SwapWeapon(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_EngageWithStaff(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_AttackWithStaff(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_Pathfinder(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_Return(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_Recover(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_Taunting(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_DischargeSpeargun(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_AttackBrutallyWithPlasmaCaster(STRATEGYBLOCK *sbPtr); +static PRED_RETURN_CONDITION Execute_PNS_NewDischargePistol(STRATEGYBLOCK *sbPtr); + +static PRED_RETURN_CONDITION Predator_ThreatAnalysis(STRATEGYBLOCK *sbPtr); + +static void Execute_Dying(STRATEGYBLOCK *sbPtr); + +static void CreateNPCPredatorPlasBolt(VECTORCH *startingPosition, VECTORCH *targetDirection); +static void CreateNPCPredatorDisc(VECTORCH *startingPosition, VECTORCH *targetDirection); +static void SetPredatorAnimationSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweening); +static int PredatorShouldBeCrawling(STRATEGYBLOCK *sbPtr); +static int PredatorShouldAttackPlayer(STRATEGYBLOCK *sbPtr); + +static void InitPredatorCloak(PREDATOR_STATUS_BLOCK *predStatus); +static void PredatorCloakOn(PREDATOR_STATUS_BLOCK *predStatus); +static void PredatorCloakOff(PREDATOR_STATUS_BLOCK *predStatus); +static void DoPredatorCloak(PREDATOR_STATUS_BLOCK *predStatus,DYNAMICSBLOCK *dynPtr); + +static int PredatorCanSeeTarget(STRATEGYBLOCK *sbPtr); +static int PredatorCanSeeObject(STRATEGYBLOCK *sbPtr,STRATEGYBLOCK *target); +static int PredatorIsAwareOfTarget(STRATEGYBLOCK *sbPtr); + +void Predator_Enter_Swapping_State(STRATEGYBLOCK *sbPtr); +void Predator_Enter_Avoidance_State(STRATEGYBLOCK *sbPtr); +void Predator_Enter_Attacking_State(STRATEGYBLOCK *sbPtr); +void Predator_Enter_Engaged_State(STRATEGYBLOCK *sbPtr); +void Predator_Enter_Withdrawal_State(STRATEGYBLOCK *sbPtr); +void Predator_Enter_Recover_State(STRATEGYBLOCK *sbPtr); +void Predator_Enter_Wander_State(STRATEGYBLOCK *sbPtr); +void Predator_Enter_Hunt_State(STRATEGYBLOCK *sbPtr); +void Predator_Enter_Return_State(STRATEGYBLOCK *sbPtr); +void Predator_Enter_Pathfinder_State(STRATEGYBLOCK *sbPtr); +void Predator_Enter_Taunt_State(STRATEGYBLOCK *sbPtr); + +void Predator_SwitchState(STRATEGYBLOCK *sbPtr,PRED_RETURN_CONDITION state_result); +STRATEGYBLOCK *Predator_GetNewTarget(STRATEGYBLOCK *me); +int DoPredatorLaserTargeting(STRATEGYBLOCK *sbPtr); +void PredatorHandleMovingAnimation(STRATEGYBLOCK *sbPtr); +void DoPredatorHitSound(STRATEGYBLOCK *sbPtr); +void DoPredatorAcidSound(STRATEGYBLOCK *sbPtr); +void DoPredatorRandomSound(STRATEGYBLOCK *sbPtr); +void DoPredatorTauntSound(STRATEGYBLOCK *sbPtr); +void DoPredatorDeathSound(STRATEGYBLOCK *sbPtr); +void DoPredatorAISwipeSound(STRATEGYBLOCK *sbPtr); + +void CreatePredoBot(VECTORCH *position, int weapon); +void Predator_Enter_SelfDestruct_State(STRATEGYBLOCK *sbPtr); +/* Patrick 21/8/97 -------------------------------------------------- +Predator personalisation parameters: +format: health,speed,defenceHealth,useShoulderCannon, +timebetweenRangedAttacks,maxShotsPerRangedAttack, +timeBetweenEachShot,closeAttackDamage,chanceOfCloaking(1-8) +---------------------------------------------------------------------*/ +static PREDATOR_PERSONALPARAMETERS predatorCV[] = +{ + {800,8000,200,1,(2*ONE_FIXED),3,(ONE_FIXED),25,200,2}, + {1000,7000,500,0,(ONE_FIXED),1,(ONE_FIXED>>1),20,400,4}, + {600,10000,10,1,(4*ONE_FIXED),2,(ONE_FIXED>>1),50,300,8}, + {600,8000,200,0,(2*ONE_FIXED),2,(ONE_FIXED),25,500,2}, + {1000,9000,100,1,(ONE_FIXED),1,(ONE_FIXED>>1),35,400,6}, +}; + +PREDATOR_WEAPON_DATA NPC_Predator_Weapons[] = { + { + PNPCW_Pistol, /* ID */ + Execute_PNS_DischargePistol, /* Fire Func. */ + Execute_PNS_EngageWithPistol, /* Engage Func. */ + "hnpcpredator", /* Riffname */ + "pred + pistol", /* HierarchyName */ + "pistol", /* GunName */ + "R shoulder", /* ElevationName */ + "predator", /* HitLocationTableName */ + 1000, /* MinRange (Don't fire when closer) */ + PRED_CLOSE_ATTACK_RANGE, /* ForceFireRange (Fire if closer) */ + 20000, /* MaxRange (Don't fire if further) */ + //65536>>3, /* Firing Rate */ + 65536, /* Firing Rate */ + 8, /* VolleySize */ + 65536>>1, /* SwappingTime */ + 1, /* UseElevation */ + }, + { + PNPCW_Wristblade, /* ID */ + Execute_PNS_AttackWithWristblade, /* Fire Func. */ + Execute_PNS_EngageWithWristblade, /* Engage Func. */ + "hnpcpredator", /* Riffname */ + "pred with wristblade", /* HierarchyName */ + NULL, /* GunName */ + "R shoulder", /* ElevationName */ + "predator", /* HitLocationTableName */ + 0, /* MinRange (Don't fire when closer) */ + PRED_CLOSE_ATTACK_RANGE, /* ForceFireRange (Fire if closer) */ + PRED_CLOSE_ATTACK_RANGE, /* MaxRange (Don't fire if further) */ + 65536<<1, /* Firing Rate */ + 1, /* VolleySize */ + 65536>>1, /* SwappingTime */ + 1, /* UseElevation */ + }, + { + PNPCW_PlasmaCaster, /* ID */ + Execute_PNS_AttackWithPlasmaCaster, /* Fire Func. */ + Execute_PNS_EngageWithPlasmaCaster, /* Engage Func. */ + "hnpcpredator", /* Riffname */ + "pred with Plasma Caster", /* HierarchyName */ + "Plasma caster", /* GunName */ + "Plasma caster", /* ElevationName */ + "predator", /* HitLocationTableName */ + 0, /* MinRange (Don't fire when closer) */ + PRED_CLOSE_ATTACK_RANGE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 65536, /* Firing Rate */ + 1, /* VolleySize */ + 65536, /* SwappingTime */ + 1, /* UseElevation */ + }, + { + PNPCW_Staff, /* ID */ + Execute_PNS_AttackWithStaff, /* Fire Func. */ + Execute_PNS_EngageWithStaff, /* Engage Func. */ + "hnpcpredator", /* Riffname */ + "pred with staff", /* HierarchyName */ + NULL, /* GunName */ + "R shoulder", /* ElevationName */ + "predator", /* HitLocationTableName */ + 0, /* MinRange (Don't fire when closer) */ + PRED_CLOSE_ATTACK_RANGE, /* ForceFireRange (Fire if closer) */ + PRED_CLOSE_ATTACK_RANGE, /* MaxRange (Don't fire if further) */ + 65536<<1, /* Firing Rate */ + 1, /* VolleySize */ + 65536>>1, /* SwappingTime */ + 0, /* UseElevation */ + }, + { + PNPCW_Medicomp, /* ID */ + Execute_PNS_DischargePistol, /* Fire Func. */ + Execute_PNS_EngageWithPistol, /* Engage Func. */ + "hnpcpredator", /* Riffname */ + "medicomp", /* HierarchyName */ + "P caster box", /* GunName */ + "R shoulder", /* ElevationName */ + "predator", /* HitLocationTableName */ + 0, /* MinRange (Don't fire when closer) */ + 0, /* ForceFireRange (Fire if closer) */ + 0, /* MaxRange (Don't fire if further) */ + 65536>>3, /* Firing Rate */ + 8, /* VolleySize */ + 65536>>1, /* SwappingTime */ + 1, /* UseElevation */ + }, + { + PNPCW_Speargun, /* ID */ + Execute_PNS_DischargeSpeargun, /* Fire Func. */ + Execute_PNS_EngageWithPistol, /* Engage Func. */ + "hnpcpredator", /* Riffname */ + "Speargun", /* HierarchyName */ + "staff gun root", /* GunName */ + "R shoulder", /* ElevationName */ + "predator", /* HitLocationTableName */ + 0, /* MinRange (Don't fire when closer) */ + PRED_CLOSE_ATTACK_RANGE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 65536>>2, /* Firing Rate */ + 1, /* VolleySize */ + 65536>>1, /* SwappingTime */ + 1, /* UseElevation */ + }, + { + PNPCW_SeriousPlasmaCaster, /* ID */ + Execute_PNS_AttackBrutallyWithPlasmaCaster, /* Fire Func. */ + Execute_PNS_EngageWithPlasmaCaster, /* Engage Func. */ + "hnpcpredator", /* Riffname */ + "pred with Plasma Caster", /* HierarchyName */ + "Plasma caster", /* GunName */ + "Plasma caster", /* ElevationName */ + "predator", /* HitLocationTableName */ + 0, /* MinRange (Don't fire when closer) */ + PRED_CLOSE_ATTACK_RANGE, /* ForceFireRange (Fire if closer) */ + -1, /* MaxRange (Don't fire if further) */ + 65536>>2, /* Firing Rate */ + 1, /* VolleySize */ + 65536, /* SwappingTime */ + 1, /* UseElevation */ + }, + { + PNPCW_End, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }, +}; + +PREDATOR_WEAPON_DATA *GetThisNPCPredatorWeapon(PREDATOR_NPC_WEAPONS this_id) { + + int a; + + a=0; + while (NPC_Predator_Weapons[a].id!=PNPCW_End) { + if (NPC_Predator_Weapons[a].id==this_id) { + return(&NPC_Predator_Weapons[a]); + } + a++; + } + + return(NULL); + +} + +static enum AMMO_ID GetPredatorAttackDamageType(STRATEGYBLOCK *sbPtr,int flagnum) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + if (predatorStatusPointer->current_attack==NULL) { + return(AMMO_NONE); + } + + /* No different types of predators! */ + return(predatorStatusPointer->current_attack->flag_damage[flagnum]); + +} + +static void PredatorNearDamageShell(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + DYNAMICSBLOCK *dynPtr; + int workingflags,flagnum,a; + int dist,dodamage; + + LOCALASSERT(sbPtr); + predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(predatorStatusPointer); + LOCALASSERT(dynPtr); + + /* Damage shell! */ + workingflags=predatorStatusPointer->HModelController.keyframe_flags>>1; + flagnum=0; + + dist = VectorDistance(&(dynPtr->Position),&(predatorStatusPointer->Target->DynPtr->Position)); + if (distSelected_Weapon->id==PNPCW_Staff)&&(distPosition,(rand&255)-128); + break; + } + case 1: + { + Sound_Play(SID_SWIPE2,"dp",&dynPtr->Position,(rand&255)-128); + break; + } + case 2: + { + Sound_Play(SID_SWIPE3,"dp",&dynPtr->Position,(rand&255)-128); + break; + } + case 3: + { + Sound_Play(SID_SWIPE4,"dp",&dynPtr->Position,(rand&255)-128); + break; + } + default: + { + break; + } + } + #else + DoPredatorAISwipeSound(sbPtr); + #endif + /* Oops, check range first. */ + if (dodamage) { + + if (predatorStatusPointer->Target->SBdptr) { + VECTORCH rel_pos,attack_dir; + + rel_pos.vx=predatorStatusPointer->Target->DynPtr->Position.vx-sbPtr->DynPtr->Position.vx; + rel_pos.vy=predatorStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy; + rel_pos.vz=predatorStatusPointer->Target->DynPtr->Position.vz-sbPtr->DynPtr->Position.vz; + + GetDirectionOfAttack(predatorStatusPointer->Target,&rel_pos,&attack_dir); + + if (predatorStatusPointer->Target->SBdptr->HModelControlBlock) { + HtoHDamageToHModel(predatorStatusPointer->Target,&TemplateAmmo[GetPredatorAttackDamageType(sbPtr,flagnum)].MaxDamage[AvP.Difficulty], ONE_FIXED, sbPtr, &attack_dir); + } else { + CauseDamageToObject(predatorStatusPointer->Target,&TemplateAmmo[GetPredatorAttackDamageType(sbPtr,flagnum)].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir); + } + } else { + VECTORCH rel_pos,attack_dir; + + rel_pos.vx=predatorStatusPointer->Target->DynPtr->Position.vx-sbPtr->DynPtr->Position.vx; + rel_pos.vy=predatorStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy; + rel_pos.vz=predatorStatusPointer->Target->DynPtr->Position.vz-sbPtr->DynPtr->Position.vz; + + GetDirectionOfAttack(predatorStatusPointer->Target,&rel_pos,&attack_dir); + + CauseDamageToObject(predatorStatusPointer->Target,&TemplateAmmo[GetPredatorAttackDamageType(sbPtr,flagnum)].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir); + } + } + } + /* Prepare next flag. */ + workingflags>>=1; + flagnum++; + } + +} + +static void StartWristbladeAttackSequence(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + ATTACK_DATA *thisAttack; + + LOCALASSERT(sbPtr); + predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + thisAttack=GetWristbladeAttackSequence(&predatorStatusPointer->HModelController,0, + predatorStatusPointer->IAmCrouched); + + GLOBALASSERT(thisAttack); + + SetPredatorAnimationSequence(sbPtr,thisAttack->Sequence_Type,thisAttack->Sub_Sequence, + thisAttack->Sequence_Length,thisAttack->TweeningTime); + + predatorStatusPointer->current_attack=thisAttack; + +} + +static void StartPredStaffAttackSequence(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + ATTACK_DATA *thisAttack; + + LOCALASSERT(sbPtr); + predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + thisAttack=GetPredStaffAttackSequence(&predatorStatusPointer->HModelController,0, + predatorStatusPointer->IAmCrouched); + + GLOBALASSERT(thisAttack); + + SetPredatorAnimationSequence(sbPtr,thisAttack->Sequence_Type,thisAttack->Sub_Sequence, + thisAttack->Sequence_Length,thisAttack->TweeningTime); + + predatorStatusPointer->current_attack=thisAttack; + +} + +/* ChrisF 11/6/98 - Bot functions. */ + +void CastPredoBot(int weapon) { + + #define BOTRANGE 2000 + + VECTORCH position; + + if (AvP.Network!=I_No_Network) { + NewOnScreenMessage("NO PREDOBOTS IN MULTIPLAYER MODE"); + return; + } + + position=Player->ObStrategyBlock->DynPtr->Position; + position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE); + position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE); + position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE); + + CreatePredoBot(&position, weapon); + +} + +void CreatePredoBot(VECTORCH *position, int weapon) +{ + + STRATEGYBLOCK* sbPtr; + + /* create and initialise a strategy block */ + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) { + NewOnScreenMessage("FAILED TO CREATE BOT: SB CREATION FAILURE"); + return; /* failure */ + } + InitialiseSBValues(sbPtr); + + sbPtr->I_SBtype = I_BehaviourPredator; + + AssignNewSBName(sbPtr); + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC); + if(sbPtr->DynPtr) + { + EULER zeroEuler = {0,0,0}; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + dynPtr->PrevPosition = dynPtr->Position = *position; + dynPtr->OrientEuler = zeroEuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + + /* zero linear velocity in dynamics block */ + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + } + else + { + /* allocation failure */ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: DYNBLOCK CREATION FAILURE"); + return; + } + + sbPtr->shapeIndex = 0; + + sbPtr->maintainVisibility = 1; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0); + + /* Initialise predator's stats */ + { + NPC_DATA *NpcData; + + + NpcData=GetThisNpcData(I_NPC_Predator); + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + + /* create, initialise and attach a predator data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(PREDATOR_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + SECTION *root_section; + PREDATOR_STATUS_BLOCK *predatorStatus = (PREDATOR_STATUS_BLOCK *)sbPtr->SBdataptr; + + memset(predatorStatus,0,sizeof(*predatorStatus)); + + predatorStatus->personalNumber = 0; + if(predatorStatus->personalNumber<0) + { + predatorStatus->personalNumber=0; + LOCALASSERT(1==0); + } + if(predatorStatus->personalNumber>PRED_MAXIDENTITY) + { + predatorStatus->personalNumber=PRED_MAXIDENTITY; + LOCALASSERT(1==0); + } + + NPC_InitMovementData(&(predatorStatus->moveData)); + NPC_InitWanderData(&(predatorStatus->wanderData)); + predatorStatus->health = predatorCV[predatorStatus->personalNumber].startingHealth; + sbPtr->integrity = predatorStatus->health; + predatorStatus->behaviourState = PBS_Wandering; + predatorStatus->stateTimer = PRED_FAR_MOVE_TIME; + predatorStatus->internalState=0; + predatorStatus->weaponTarget.vx = predatorStatus->weaponTarget.vy = predatorStatus->weaponTarget.vz = 0; + predatorStatus->volleySize = 0; + predatorStatus->IAmCrouched = 0; + predatorStatus->nearSpeed = predatorCV[predatorStatus->personalNumber].speed; + predatorStatus->GibbFactor=0; + predatorStatus->current_attack=NULL; + + predatorStatus->incidentFlag=0; + predatorStatus->incidentTimer=0; + predatorStatus->patience=PRED_PATIENCE_TIME; + predatorStatus->enableSwap=0; + predatorStatus->enableTaunt=0; + predatorStatus->Explode=0; + + switch( weapon ) + { + case 0: + default: + predatorStatus->PrimaryWeapon=PNPCW_Wristblade; + break; + + case 1: + predatorStatus->PrimaryWeapon=PNPCW_PlasmaCaster; + break; + } + + predatorStatus->SecondaryWeapon=PNPCW_Staff; + predatorStatus->ChangeToWeapon=PNPCW_End; + predatorStatus->Selected_Weapon=GetThisNPCPredatorWeapon(predatorStatus->PrimaryWeapon); + + predatorStatus->obstruction.environment=0; + predatorStatus->obstruction.destructableObject=0; + predatorStatus->obstruction.otherCharacter=0; + predatorStatus->obstruction.anySingleObstruction=0; + + Initialise_AvoidanceManager(sbPtr,&predatorStatus->avoidanceManager); + InitWaypointManager(&predatorStatus->waypointManager); + + predatorStatus->Target=NULL; //Player->ObStrategyBlock; + COPY_NAME(predatorStatus->Target_SBname,Null_Name); + + predatorStatus->soundHandle = SOUND_NOACTIVEINDEX; + + predatorStatus->Pred_Laser_On=0; + + predatorStatus->missionmodule=NULL; + predatorStatus->fearmodule=NULL; + predatorStatus->path=-1; + predatorStatus->stepnumber=-1; + + //a generated predator won't have a death target + { + int i; + for(i=0;ideath_target_ID[i] =0; + predatorStatus->death_target_request=0; + predatorStatus->death_target_sbptr=0; + } + + + root_section=GetNamedHierarchyFromLibrary(predatorStatus->Selected_Weapon->Riffname,predatorStatus->Selected_Weapon->HierarchyName); + if (!root_section) { + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: NO HMODEL"); + return; + } + Create_HModel(&predatorStatus->HModelController,root_section); + InitHModelSequence(&predatorStatus->HModelController,0,0,ONE_FIXED); + + if (predatorStatus->Selected_Weapon->UseElevation) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&predatorStatus->HModelController,"Elevation",(int)HMSQT_PredatorStand,(int)PSSS_Elevation,0); + GLOBALASSERT(delta); + delta->timer=32767; + } + + predatorStatus->My_Gun_Section=GetThisSectionData(predatorStatus->HModelController.section_data,predatorStatus->Selected_Weapon->GunName); + predatorStatus->My_Elevation_Section=GetThisSectionData(predatorStatus->HModelController.section_data,predatorStatus->Selected_Weapon->ElevationName); + + #if PREDATOR_HIT_DELTAS + if (HModelSequence_Exists(&predatorStatus->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront)) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&predatorStatus->HModelController,"HitDelta",(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront,-1); + GLOBALASSERT(delta); + delta->Playing=0; + } + #endif + + ProveHModel_Far(&predatorStatus->HModelController,sbPtr); + + InitPredatorCloak(predatorStatus); + + if(!(sbPtr->containingModule)) + { + /* no containing module can be found... abort*/ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: MODULE CONTAINMENT FAILURE"); + return; + } + LOCALASSERT(sbPtr->containingModule); + + MakePredatorNear(sbPtr); + + NewOnScreenMessage("PREDOBOT CREATED"); + + } + else + { + /* allocation failure */ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: MALLOC FAILURE"); + return; + } +} + +/* Patrick 4/7/97 -------------------------------------------------- +Basic NPC functions for predator: +Initialiser, visibility management,behaviour shell, and damage functions +---------------------------------------------------------------------*/ +void InitPredatorBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr) +{ + TOOLS_DATA_PREDATOR *toolsData; + int i; + + LOCALASSERT(sbPtr); + LOCALASSERT(bhdata); + toolsData = (TOOLS_DATA_PREDATOR *)bhdata; + + /* check we're not in a net game */ + if(AvP.Network != I_No_Network) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* make the assumption that the loader has initialised the strategy + block sensibly... + so just set the shapeIndex from the tools data & copy the name id*/ + sbPtr->shapeIndex = toolsData->shapeIndex; + for(i=0;iSBname[i] = toolsData->nameID[i]; + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC); + if(sbPtr->DynPtr) + { + EULER zeroEuler = {0,0,0}; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + dynPtr->PrevPosition = dynPtr->Position = toolsData->position; + dynPtr->OrientEuler = zeroEuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + + /* zero linear velocity in dynamics block */ + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + } + else + { + /* allocation failure */ + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* Initialise predator's stats */ + { + NPC_DATA *NpcData; + + + NpcData=GetThisNpcData(I_NPC_Predator); + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + + /* create, initialise and attach a predator data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(PREDATOR_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + SECTION *root_section; + PREDATOR_STATUS_BLOCK *predatorStatus = (PREDATOR_STATUS_BLOCK *)sbPtr->SBdataptr; + + predatorStatus->personalNumber = toolsData->predator_number; + if(predatorStatus->personalNumber<0) + { + predatorStatus->personalNumber=0; + LOCALASSERT(1==0); + } + if(predatorStatus->personalNumber>PRED_MAXIDENTITY) + { + predatorStatus->personalNumber=PRED_MAXIDENTITY; + LOCALASSERT(1==0); + } + + NPC_InitMovementData(&(predatorStatus->moveData)); + NPC_InitWanderData(&(predatorStatus->wanderData)); + predatorStatus->health = predatorCV[predatorStatus->personalNumber].startingHealth; + sbPtr->integrity = predatorStatus->health; + predatorStatus->behaviourState = PBS_Wandering; + predatorStatus->stateTimer = PRED_FAR_MOVE_TIME; + predatorStatus->internalState=0; + predatorStatus->weaponTarget.vx = predatorStatus->weaponTarget.vy = predatorStatus->weaponTarget.vz = 0; + predatorStatus->volleySize = 0; + predatorStatus->IAmCrouched = 0; + predatorStatus->nearSpeed = predatorCV[predatorStatus->personalNumber].speed; + predatorStatus->GibbFactor=0; + predatorStatus->current_attack=NULL; + + predatorStatus->incidentFlag=0; + predatorStatus->incidentTimer=0; + predatorStatus->patience=PRED_PATIENCE_TIME; + predatorStatus->enableSwap=0; + predatorStatus->enableTaunt=0; + predatorStatus->Explode=0; + + #if 0 + predatorStatus->PrimaryWeapon=PNPCW_Pistol; + predatorStatus->SecondaryWeapon=PNPCW_Wristblade; + #else + predatorStatus->PrimaryWeapon=toolsData->primary; + predatorStatus->SecondaryWeapon=toolsData->secondary; + #endif + predatorStatus->ChangeToWeapon=PNPCW_End; + predatorStatus->Selected_Weapon=GetThisNPCPredatorWeapon(predatorStatus->PrimaryWeapon); + + predatorStatus->obstruction.environment=0; + predatorStatus->obstruction.destructableObject=0; + predatorStatus->obstruction.otherCharacter=0; + predatorStatus->obstruction.anySingleObstruction=0; + + Initialise_AvoidanceManager(sbPtr,&predatorStatus->avoidanceManager); + InitWaypointManager(&predatorStatus->waypointManager); + + predatorStatus->Target=NULL; //Player->ObStrategyBlock; + COPY_NAME(predatorStatus->Target_SBname,Null_Name); + + predatorStatus->soundHandle = SOUND_NOACTIVEINDEX; + + predatorStatus->Pred_Laser_On=0; + + predatorStatus->missionmodule=NULL; + predatorStatus->fearmodule=NULL; + predatorStatus->path=toolsData->path; + predatorStatus->stepnumber=toolsData->stepnumber; + if ((predatorStatus->path!=-1)&&(predatorStatus->stepnumber!=-1)) { + predatorStatus->behaviourState = PBS_Pathfinding; + } + + for(i=0;ideath_target_ID[i] = toolsData->death_target_ID[i]; + predatorStatus->death_target_request=toolsData->death_target_request; + predatorStatus->death_target_sbptr=0; + + + root_section=GetNamedHierarchyFromLibrary(predatorStatus->Selected_Weapon->Riffname,predatorStatus->Selected_Weapon->HierarchyName); + GLOBALASSERT(root_section); + Create_HModel(&predatorStatus->HModelController,root_section); + InitHModelSequence(&predatorStatus->HModelController,0,0,ONE_FIXED); + + if (predatorStatus->Selected_Weapon->UseElevation) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&predatorStatus->HModelController,"Elevation",(int)HMSQT_PredatorStand,(int)PSSS_Elevation,0); + GLOBALASSERT(delta); + delta->timer=32767; + } + + predatorStatus->My_Gun_Section=GetThisSectionData(predatorStatus->HModelController.section_data,predatorStatus->Selected_Weapon->GunName); + predatorStatus->My_Elevation_Section=GetThisSectionData(predatorStatus->HModelController.section_data,predatorStatus->Selected_Weapon->ElevationName); + + #if PREDATOR_HIT_DELTAS + if (HModelSequence_Exists(&predatorStatus->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront)) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&predatorStatus->HModelController,"HitDelta",(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront,-1); + GLOBALASSERT(delta); + delta->Playing=0; + } + #endif + + ProveHModel_Far(&predatorStatus->HModelController,sbPtr); + + InitPredatorCloak(predatorStatus); + } + else + { + /* allocation failure */ + RemoveBehaviourStrategy(sbPtr); + return; + } +} + +void InitDormantPredatorBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr) +{ + DORMANT_PREDATOR_STATUS_BLOCK* pred_bhv; + GLOBALASSERT(sbPtr); + pred_bhv=(DORMANT_PREDATOR_STATUS_BLOCK*)AllocateMem(sizeof(DORMANT_PREDATOR_STATUS_BLOCK)); + + pred_bhv->bhvr_type=I_BehaviourDormantPredator; + pred_bhv->toolsData=bhdata; + + sbPtr->SBdataptr=(void*) pred_bhv; + +} + +void ActivateDormantPredator(STRATEGYBLOCK* sbPtr) +{ + DORMANT_PREDATOR_STATUS_BLOCK* pred_bhv; + void* toolsData; + + GLOBALASSERT(sbPtr); + GLOBALASSERT(sbPtr->SBdataptr); + pred_bhv = (DORMANT_PREDATOR_STATUS_BLOCK*)sbPtr->SBdataptr; + toolsData=pred_bhv->toolsData; + + //convert this strategyblock to a predator + DeallocateMem(pred_bhv); + InitialiseSBValues(sbPtr); + sbPtr->I_SBtype = I_BehaviourPredator; + EnableBehaviourType(sbPtr,I_BehaviourPredator ,toolsData ); + + //find strategyblock of death target + { + PREDATOR_STATUS_BLOCK *predatorStatus = (PREDATOR_STATUS_BLOCK *)sbPtr->SBdataptr; + predatorStatus->death_target_sbptr = FindSBWithName(predatorStatus->death_target_ID); + } + + sbPtr->maintainVisibility = 1; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0); + + +} + + +void SetPredatorElevation(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + int offsetx,offsety,offsetz,offseta,angle1; + DELTA_CONTROLLER *elevation_controller; + VECTORCH gunpos; + + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + + if (predatorStatusPointer->Selected_Weapon->UseElevation==0) { + /* Non elevating weapon. */ + return; + } + + /* Get gun position? */ + + if (predatorStatusPointer->My_Elevation_Section) { + gunpos=predatorStatusPointer->My_Elevation_Section->World_Offset; + } else { + GetTargetingPointOfObject_Far(sbPtr,&gunpos); + } + + /* Aim at weaponTarget. */ + + offsetx=(predatorStatusPointer->weaponTarget.vx)-(gunpos.vx); + offsety=(predatorStatusPointer->weaponTarget.vz)-(gunpos.vz); + offseta=-((predatorStatusPointer->weaponTarget.vy)-(gunpos.vy)); + + while( (offsetx>(ONE_FIXED>>2)) + ||(offsety>(ONE_FIXED>>2)) + ||(offseta>(ONE_FIXED>>2)) + ||(offsetx<-(ONE_FIXED>>2)) + ||(offsety<-(ONE_FIXED>>2)) + ||(offseta<-(ONE_FIXED>>2))) { + + offsetx>>=1; + offsety>>=1; + offseta>>=1; + + } + + offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety)); + angle1=ArcTan(offseta,offsetz); + + if (angle1>=3072) angle1-=4096; + if (angle1>=2048) angle1=angle1-3072; + if (angle1>1024) angle1=2048-angle1; + + GLOBALASSERT(angle1>=-1024); + GLOBALASSERT(angle1<=1024); + + elevation_controller=Get_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation"); + GLOBALASSERT(elevation_controller); + { + int fake_timer; + + fake_timer=1024-angle1; + fake_timer<<=5; + if (fake_timer==65536) fake_timer=65535; + + GLOBALASSERT(fake_timer>=0); + GLOBALASSERT(fake_timer<65536); + + elevation_controller->timer=fake_timer; + + } + +} + +void CentrePredatorElevation(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + DELTA_CONTROLLER *elevation_controller; + + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + + if (predatorStatusPointer->Selected_Weapon->UseElevation==0) { + /* Non elevating weapon. */ + return; + } + + elevation_controller=Get_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation"); + if (elevation_controller) { + /* You can't be too careful with swap weapon stuff...? */ + elevation_controller->timer=32767; + } + +} + +void PredatorBehaviour(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + int predatorIsNear; + char *descriptor; + PRED_RETURN_CONDITION state_result; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* test if we've got a containing module: if we haven't, do nothing. + This is important as the object could have been marked for deletion by the visibility + management system...*/ + if(!sbPtr->containingModule) + { + DestroyAnyStrategyBlock(sbPtr); /* just to make sure */ + return; + } + + if(sbPtr->SBdptr) + { + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]); + predatorIsNear=1; + } else { + predatorIsNear=0; + } + + if (ShowSlack) { + int synthSpeed,setSpeed,slack; + VECTORCH offset; + extern int SlackTotal; + extern int SlackSize; + + offset.vx=(sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx); + offset.vy=(sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy); + offset.vz=(sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz); + + synthSpeed=Magnitude(&offset); + synthSpeed=DIV_FIXED(synthSpeed,NormalFrameTime); + setSpeed=Magnitude(&sbPtr->DynPtr->LinVelocity); + + if (setSpeed) { + slack=(ONE_FIXED-(DIV_FIXED(synthSpeed,setSpeed))); + SlackTotal+=slack; + SlackSize++; + } + #if 0 + PrintDebuggingText("MaxSpeed = %d, SynthSpeed = %d, SetSpeed = %d, Slack %d\n",alienStatusPointer->MaxSpeed,synthSpeed,setSpeed,slack); + #endif + } + + InitWaypointSystem(0); + predatorStatusPointer->Pred_Laser_On=0; + + if (Validate_Target(predatorStatusPointer->Target,predatorStatusPointer->Target_SBname)==0) { + predatorStatusPointer->Target=NULL; + } + + /* Consider changing target? */ + if (predatorStatusPointer->behaviourState==PBS_Engaging) { + if (predatorStatusPointer->incidentFlag) { + if ((FastRandom()&65535)<32767) { + predatorStatusPointer->Target=NULL; + } + } + } + + if (predatorStatusPointer->Target==NULL) { + if ((predatorIsNear)||(predatorStatusPointer->incidentFlag)) { + /* Get new target. */ + predatorStatusPointer->Target=Predator_GetNewTarget(sbPtr); + + if (predatorStatusPointer->Target) { + #if 0 + textprint("Predator gets new target.\n"); + #endif + COPY_NAME(predatorStatusPointer->Target_SBname,predatorStatusPointer->Target->SBname); + + } else { + #if 0 + PrintDebuggingText("Predator found no target!\n"); + #endif + } + } + } + + /* first of all, look after our cloaking device */ + DoPredatorCloak(predatorStatusPointer,sbPtr->DynPtr); + + /* Unset incident flag. */ + predatorStatusPointer->incidentFlag=0; + + predatorStatusPointer->incidentTimer-=NormalFrameTime; + + if (predatorStatusPointer->incidentTimer<0) { + predatorStatusPointer->incidentFlag=1; + predatorStatusPointer->incidentTimer=32767+(FastRandom()&65535); + } + + if (predatorStatusPointer->GibbFactor) { + /* If you're gibbed, you're dead. */ + sbPtr->SBDamageBlock.Health = 0; + } + + if (sbPtr->SBDamageBlock.IsOnFire) { + + CauseDamageToObject(sbPtr,&firedamage,NormalFrameTime,NULL); + + if (sbPtr->I_SBtype==I_BehaviourNetCorpse) { + /* Gettin' out of here... */ + return; + } + + if (predatorStatusPointer->incidentFlag) { + if ((FastRandom()&65535)<32767) { + sbPtr->SBDamageBlock.IsOnFire=0; + } + } + + } + + if (predatorStatusPointer->behaviourState!=PBS_Dying) { + HModel_Regen(&predatorStatusPointer->HModelController,PRED_REGEN_TIME); + } + + /* now execute behaviour state */ + switch(predatorStatusPointer->behaviourState) + { + case (PBS_Wandering): + { + descriptor="Wandering"; + if (predatorIsNear) { + state_result=Execute_PNS_Wander(sbPtr); + CentrePredatorElevation(sbPtr); + } else { + state_result=Execute_PFS_Wander(sbPtr); + } + break; + } + case (PBS_Hunting): + { + descriptor="Hunting"; + if (predatorIsNear) { + state_result=Execute_PNS_Hunt(sbPtr); + CentrePredatorElevation(sbPtr); + } else { + state_result=Execute_PFS_Hunt(sbPtr); + } + break; + } + case (PBS_Avoidance): + { + switch (predatorStatusPointer->avoidanceManager.substate) { + default: + case AvSS_FreeMovement: + descriptor="Avoidance Level 0"; + break; + case AvSS_FirstAvoidance: + descriptor="Avoidance Level 1"; + break; + case AvSS_SecondAvoidance: + descriptor="Avoidance Level 2"; + break; + case AvSS_ThirdAvoidance: + descriptor="Avoidance Level 3"; + break; + } + if (predatorIsNear) { + state_result=Execute_PNS_Avoidance(sbPtr); + CentrePredatorElevation(sbPtr); + } else { + state_result=Execute_PFS_Avoidance(sbPtr); + } + break; + } + case (PBS_Dying): + { + descriptor="Dying"; + if (predatorIsNear) { + Execute_Dying(sbPtr); + } else { + Execute_Dying(sbPtr); + } + state_result=PRC_No_Change; + break; + } + case (PBS_Withdrawing): + { + descriptor="Withdrawing"; + if (predatorIsNear) { + state_result=Execute_PNS_Retreat(sbPtr); + CentrePredatorElevation(sbPtr); + } else { + state_result=Execute_PFS_Retreat(sbPtr); + } + break; + } + case (PBS_Recovering): + { + descriptor="Recovering"; + if (predatorIsNear) { + state_result=Execute_PNS_Recover(sbPtr); + CentrePredatorElevation(sbPtr); + } else { + state_result=Execute_PNS_Recover(sbPtr); + } + break; + } + case (PBS_SwapWeapon): + { + descriptor="Swapping"; + if (predatorIsNear) { + state_result=Execute_PNS_SwapWeapon(sbPtr); + CentrePredatorElevation(sbPtr); + } else { + /* Oooh! */ + state_result=Execute_PNS_SwapWeapon(sbPtr); + ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr); + } + break; + } + case (PBS_Engaging): + { + descriptor="Engaging"; + if (predatorIsNear) { + state_result=(*predatorStatusPointer->Selected_Weapon->WeaponEngageFunction)(sbPtr); + } else { + state_result=Execute_PFS_Engage(sbPtr); + } + break; + } + case (PBS_Attacking): + { + descriptor="Attacking"; + if (predatorIsNear) { + state_result=(*predatorStatusPointer->Selected_Weapon->WeaponFireFunction)(sbPtr); + SetPredatorElevation(sbPtr); + } else { + state_result=Execute_PFS_Engage(sbPtr); + } + break; + } + case (PBS_Returning): + { + descriptor="Returning"; + if (predatorIsNear) { + state_result=Execute_PNS_Return(sbPtr); + CentrePredatorElevation(sbPtr); + } else { + state_result=Execute_PFS_Return(sbPtr); + } + break; + } + case (PBS_Pathfinding): + { + descriptor="Pathfinding"; + if (predatorIsNear) { + state_result=Execute_PNS_Pathfinder(sbPtr); + CentrePredatorElevation(sbPtr); + } else { + state_result=Execute_PFS_Pathfinder(sbPtr); + } + break; + } + case (PBS_Taunting): + { + descriptor="Taunting"; + if (predatorIsNear) { + state_result=Execute_PNS_Taunting(sbPtr); + CentrePredatorElevation(sbPtr); + } else { + state_result=Execute_PNS_Taunting(sbPtr); + } + break; + } + case (PBS_SelfDestruct): + { + descriptor="Self Destructing"; + if (predatorIsNear) { + state_result=Execute_PNS_SelfDestruct(sbPtr); + /* No elevation should be present. */ + } else { + state_result=Execute_PNS_SelfDestruct(sbPtr); + } + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + + if (ShowPredoStats) { + switch (predatorStatusPointer->CloakStatus) { + case PCLOAK_Off: + PrintDebuggingText("DeCloaked "); + break; + case PCLOAK_On: + PrintDebuggingText("Cloaked "); + break; + case PCLOAK_Activating: + PrintDebuggingText("Cloaking (%d) ",predatorStatusPointer->CloakTimer); + break; + case PCLOAK_Deactivating: + PrintDebuggingText("DeCloaking (%d) ",predatorStatusPointer->CloakTimer); + break; + default: + GLOBALASSERT(0); + break; + } + PrintDebuggingText("%s Predator in %s: %d,%d\n",descriptor,sbPtr->containingModule->name, + (sbPtr->SBDamageBlock.Health>>ONE_FIXED_SHIFT),(sbPtr->SBDamageBlock.Armour>>ONE_FIXED_SHIFT)); + } + + Predator_SwitchState(sbPtr,state_result); + + if (!predatorIsNear) { + + /* check here to see if predator is in a proximity door - if so, trigger it to open. */ + { + MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule); + + if(doorType == MDT_ProxDoor) + ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->alienTrigger = 1; + } + + /* lastly, do a containment test: to make sure that we are inside a module. */ + #if UseLocalAssert + { + VECTORCH localCoords; + MODULE *thisModule = sbPtr->containingModule; + + LOCALASSERT(thisModule); + + localCoords = sbPtr->DynPtr->Position; + localCoords.vx -= thisModule->m_world.vx; + localCoords.vy -= thisModule->m_world.vy; + localCoords.vz -= thisModule->m_world.vz; + + if(PointIsInModule(thisModule, &localCoords)==0) + { + #if (!PSX) + textprint("FAR PREDATOR MODULE CONTAINMENT FAILURE \n"); + LOCALASSERT(1==0); + #endif + } + } + #endif + } + + /* if we have actually died, we need to remove the strategyblock... so do this here */ + if((predatorStatusPointer->behaviourState == PBS_Dying)&& + (predatorStatusPointer->stateTimer <= 0)) { + DestroyAnyStrategyBlock(sbPtr); + } + + #if 0 + /* Now, right at the end, fix animation speed. */ + if ((predatorStatusPointer->HModelController.Sub_Sequence==PRSS_Standard) + ||(predatorStatusPointer->HModelController.Sub_Sequence==PCSS_Standard)) { + + int speed,animfactor; + /* ...compute speed factor... */ + speed=Approximate3dMagnitude(&sbPtr->DynPtr->LinVelocity); + if (speed==0) { + animfactor=ONE_FIXED; + } else { + animfactor=DIV_FIXED(625,speed); // Was 512! Difference to correct for rounding down... + } + GLOBALASSERT(animfactor>0); + if (ShowPredoStats) { + PrintDebuggingText("Anim Factor %d, Tweening %d\n",animfactor,predatorStatusPointer->HModelController.Tweening); + } + if (predatorStatusPointer->HModelController.Tweening==0) { + HModel_SetToolsRelativeSpeed(&predatorStatusPointer->HModelController,animfactor); + } + } + #endif + + /* Update delta playing flag. */ + { + DELTA_CONTROLLER *hitdelta; + + hitdelta=Get_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta"); + + if (hitdelta) { + if (DeltaAnimation_IsFinished(hitdelta)) { + hitdelta->Playing=0; + } + } + } + + if (predatorStatusPointer->Explode) { + StartPredatorSelfDestructExplosion(sbPtr); + } +} + +void PredatorHandleMovingAnimation(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + VECTORCH offset; + int speed,animfactor,walking; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + offset.vx=sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx; + offset.vy=sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy; + offset.vz=sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz; + + /* ...compute speed factor... */ + speed=Magnitude(&offset); + if ((speed<(MUL_FIXED(NormalFrameTime,50))) + &&(predatorStatusPointer->HModelController.Tweening==0)) { + /* Not moving much, are we? Be stationary! */ + if (ShowPredoStats) + { + PrintDebuggingText("Forced stationary animation!\n"); + } + if(predatorStatusPointer->IAmCrouched) + { + if ((predatorStatusPointer->HModelController.Sequence_Type!=HMSQT_PredatorCrouch) + ||(predatorStatusPointer->HModelController.Sub_Sequence!=PCrSS_Standard)) + { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrouch,PCrSS_Standard,-1,(ONE_FIXED>>3)); + } + } + else + { + if ((predatorStatusPointer->HModelController.Sequence_Type!=HMSQT_PredatorStand) + ||(predatorStatusPointer->HModelController.Sub_Sequence!=PSSS_Standard)) + { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorStand,PSSS_Standard,-1,(ONE_FIXED>>3)); + // Alex: this is a bit of a fudge + (predatorStatusPointer->avoidanceManager.avoidanceDirection).vx = -(predatorStatusPointer->avoidanceManager.avoidanceDirection).vx; + (predatorStatusPointer->avoidanceManager.avoidanceDirection).vz = -(predatorStatusPointer->avoidanceManager.avoidanceDirection).vz; + } + } + return; + } + speed=DIV_FIXED(speed,NormalFrameTime); + + if (speed==0) { + animfactor=ONE_FIXED; + } else { + animfactor=DIV_FIXED(625,speed); // Was 512! Difference to correct for rounding down... + } + GLOBALASSERT(animfactor>0); + if (ShowPredoStats) { + PrintDebuggingText("Anim Factor %d, Tweening %d, Speed %d\n",animfactor,predatorStatusPointer->HModelController.Tweening,speed); + } + + walking=0; + + if (HModelSequence_Exists(&predatorStatusPointer->HModelController,HMSQT_PredatorRun,PRSS_Walk)) { + /* Are we currently walking? */ + if ((predatorStatusPointer->HModelController.Sequence_Type==HMSQT_PredatorRun) + &&(predatorStatusPointer->HModelController.Sub_Sequence==PRSS_Walk)) { + if (speedHModelController.Tweening==0) { + + /* If still tweening, probably best to leave it alone... */ + + if (PredatorShouldBeCrawling(sbPtr)) { + + predatorStatusPointer->IAmCrouched=1; + + /* Only one possible sequence here. */ + if ((predatorStatusPointer->HModelController.Sequence_Type!=HMSQT_PredatorCrawl) + ||(predatorStatusPointer->HModelController.Sub_Sequence!=PCSS_Standard)) { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + + } else if (walking==0) { + + predatorStatusPointer->IAmCrouched=0; + + /* Are we doing the right anim? */ + if ((predatorStatusPointer->HModelController.Sequence_Type!=HMSQT_PredatorRun) + ||(predatorStatusPointer->HModelController.Sub_Sequence!=PRSS_Standard)) { + + /* If we're currently walking, tween over. */ + if ((predatorStatusPointer->HModelController.Sequence_Type==HMSQT_PredatorRun) + &&(predatorStatusPointer->HModelController.Sub_Sequence==PRSS_Walk)) { + InitHModelTweening_ToTheMiddle(&predatorStatusPointer->HModelController, (ONE_FIXED>>3),HMSQT_PredatorRun, + PRSS_Standard,(ONE_FIXED<<1),((predatorStatusPointer->HModelController.sequence_timer+(ONE_FIXED>>3))&65535),1); + } else { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } + + } else { + + predatorStatusPointer->IAmCrouched=0; + + /* Are we doing the right anim? */ + if ((predatorStatusPointer->HModelController.Sequence_Type!=HMSQT_PredatorRun) + ||(predatorStatusPointer->HModelController.Sub_Sequence!=PRSS_Walk)) { + /* If we're currently running, tween over. */ + if ((predatorStatusPointer->HModelController.Sequence_Type==HMSQT_PredatorRun) + &&(predatorStatusPointer->HModelController.Sub_Sequence==PRSS_Standard)) { + InitHModelTweening_ToTheMiddle(&predatorStatusPointer->HModelController, (ONE_FIXED>>3),HMSQT_PredatorRun, + PRSS_Walk,(ONE_FIXED<<1),((predatorStatusPointer->HModelController.sequence_timer+(ONE_FIXED>>3))&65535),1); + } else { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Walk,ONE_FIXED,(ONE_FIXED>>3)); + } + } + + } + + } + + if (predatorStatusPointer->HModelController.Tweening==0) { + HModel_SetToolsRelativeSpeed(&predatorStatusPointer->HModelController,animfactor); + } + +} + +void MakePredatorNear(STRATEGYBLOCK *sbPtr) +{ + extern MODULEMAPBLOCK AlienDefaultMap; + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr; + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + LOCALASSERT(dynPtr); + LOCALASSERT(sbPtr->SBdptr == NULL); + + AlienDefaultMap.MapShape = sbPtr->shapeIndex; + tempModule.m_mapptr = &AlienDefaultMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 0; + tempModule.m_lightarray = (struct lightblock *)0; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr = NULL; + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) return; /* cannot allocate displayblock, so leave far */ + + sbPtr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbPtr; + dPtr->ObMyModule = NULL; + + /* need to initialise positional information in the new display block */ + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + + /* status block init */ + predatorStatusPointer->weaponTarget.vx = predatorStatusPointer->weaponTarget.vy = predatorStatusPointer->weaponTarget.vz = 0; + predatorStatusPointer->volleySize = 0; + InitPredatorCloak(predatorStatusPointer); + + /* regenerate health (before deciding whether to attack or defend) */ + if(predatorStatusPointer->health < predatorCV[predatorStatusPointer->personalNumber].startingHealth) + { + predatorStatusPointer->health += predatorCV[predatorStatusPointer->personalNumber].regenerationUnit; + + if(predatorStatusPointer->health > predatorCV[predatorStatusPointer->personalNumber].startingHealth) + predatorStatusPointer->health = predatorCV[predatorStatusPointer->personalNumber].startingHealth; + } + + /* zero linear velocity in dynamics block */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* initialise state and sequence... */ + + dPtr->HModelControlBlock=&predatorStatusPointer->HModelController; + + CentrePredatorElevation(sbPtr); + + ProveHModel(dPtr->HModelControlBlock,dPtr); + + /* LOCALASSERT(predatorStatusPointer->nearBehaviourState != PNS_Dying); */ + if(PredatorShouldBeCrawling(sbPtr)) predatorStatusPointer->IAmCrouched = 1; + else predatorStatusPointer->IAmCrouched = 0; + + /*Copy extents from the collision extents in extents.c*/ + dPtr->ObMinX=-CollisionExtents[CE_PREDATOR].CollisionRadius; + dPtr->ObMaxX=CollisionExtents[CE_PREDATOR].CollisionRadius; + dPtr->ObMinZ=-CollisionExtents[CE_PREDATOR].CollisionRadius; + dPtr->ObMaxZ=CollisionExtents[CE_PREDATOR].CollisionRadius; + dPtr->ObMinY=CollisionExtents[CE_PREDATOR].CrouchingTop; + dPtr->ObMaxY=CollisionExtents[CE_PREDATOR].Bottom; + dPtr->ObRadius = 1000; + InitWaypointManager(&predatorStatusPointer->waypointManager); + + if (predatorStatusPointer->behaviourState==PBS_Recovering) { + if(predatorStatusPointer->IAmCrouched) { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrouch,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorStand,PSSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } else if ((predatorStatusPointer->behaviourState!=PBS_SwapWeapon) + &&(predatorStatusPointer->behaviourState!=PBS_SelfDestruct)) { + if(predatorStatusPointer->IAmCrouched) { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + } + +} + +void MakePredatorFar(STRATEGYBLOCK *sbPtr) +{ + /* get the predator's status block */ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + int i; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + LOCALASSERT(sbPtr->SBdptr != NULL); + + /* get rid of the displayblock */ + i = DestroyActiveObject(sbPtr->SBdptr); + LOCALASSERT(i==0); + sbPtr->SBdptr = NULL; + + /* zero linear velocity in dynamics block */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* status block init */ + if ((predatorStatusPointer->behaviourState!=PBS_SwapWeapon) + &&(predatorStatusPointer->behaviourState!=PBS_SelfDestruct)) { + predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; + } + InitPredatorCloak(predatorStatusPointer); + + /* initialise state and sequence... */ + if(predatorStatusPointer->behaviourState == PBS_Dying) + { + DestroyAnyStrategyBlock(sbPtr); + return; + } + + #if 0 + if(PredatorShouldAttackPlayer(sbPtr)) + { + predatorStatusPointer->behaviourState = PBS_Hunting; + } + else + { + predatorStatusPointer->behaviourState = PBS_Withdrawing; + } + #endif +} + +void PredatorIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple,SECTION_DATA *Section, VECTORCH *incoming) +{ + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* if we're dying, do nothing */ + if(predatorStatusPointer->behaviourState==PBS_Dying) + { + /* PFS should be dying, too */ + return; + } + + if(!(sbPtr->SBdptr)) + { + DestroyAnyStrategyBlock(sbPtr); + return; + } + + /* Might want to get a new target? */ + + predatorStatusPointer->Target=NULL; + + if (predatorStatusPointer->behaviourState!=PBS_SelfDestruct) { + NPC_DATA *NpcData; + /* we are far enough away, so return to approach? */ + + NpcData=GetThisNpcData(I_NPC_Predator); + + if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-3))) + &&(sbPtr->SBDamageBlock.Health>0)) { + /* 12.5% health? */ + Predator_Enter_SelfDestruct_State(sbPtr); + return; + } + } + + #if 0 + { + int tkd; + VECTORCH origin,blast; + /* Make a blood splat? */ + tkd=TotalKineticDamage(damage); + tkd=MUL_FIXED(tkd,multiple); + + if (tkd) { + if (Section) { + origin=Section->World_Offset; + } else { + GetTargetingPointOfObject_Far(sbPtr,&origin); + } + if (incoming) { + blast=origin; + blast.vx+=incoming->vx; + blast.vy+=incoming->vy; + blast.vz+=incoming->vz; + } else { + blast=origin; + } + MakeBloodExplosion(&origin, 100, &blast, (tkd>>2), PARTICLE_PREDATOR_BLOOD); + } + } + #endif + + /* Do we really want to die? */ + if(sbPtr->SBDamageBlock.Health <= 0) { + if (predatorStatusPointer->behaviourState!=PBS_SelfDestruct) { + if (damage->Id==AMMO_ALIEN_TAIL) { + /* Actually, don't die just yet... */ + NPC_DATA *NpcData; + + NpcData=GetThisNpcData(I_NPC_Predator); + + sbPtr->SBDamageBlock.Health=(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-3)); + /* 12.5% health. */ + Predator_Enter_SelfDestruct_State(sbPtr); + return; + } + } + } + + if(sbPtr->SBDamageBlock.Health <= 0) + { + /* KILL PREDATOR! */ + int deathtype=0; + + if (AvP.PlayerType!=I_Predator) { + CurrentGameStats_CreatureKilled(sbPtr,Section); + } + + /*notify death target ,if predator has one*/ + if(predatorStatusPointer->death_target_sbptr) + { + RequestState(predatorStatusPointer->death_target_sbptr,predatorStatusPointer->death_target_request, 0); + } + + #if 0 + /* switch to dying-suicide state? */ + predatorStatusPointer->behaviourState = PBS_Dying; + predatorStatusPointer->stateTimer = PRED_DIETIME; + /* No longer need with corpses, and allows us to reference behaviourState later. */ + #endif + + /* Set deathtype */ + + { + int tkd; + + tkd=TotalKineticDamage(damage); + deathtype=0; + + if (damage->ExplosivePower==1) { + if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) { + /* Okay, you can... splat now. */ + predatorStatusPointer->GibbFactor=-(ONE_FIXED>>1); + deathtype=2; + } + } else if ((tkd<40)&&((multiple>>16)>1)) { + int newmult; + + newmult=DIV_FIXED(multiple,NormalFrameTime); + if (MUL_FIXED(tkd,newmult)>(500)) { + predatorStatusPointer->GibbFactor=-(ONE_FIXED>>2); + deathtype=2; + } + } + + if ((damage->ExplosivePower==2)||(damage->ExplosivePower==6)) { + /* Basically SADARS only. */ + predatorStatusPointer->GibbFactor=-(ONE_FIXED); + deathtype=3; + } + } + + if (damage->ForceBoom) { + deathtype+=damage->ForceBoom; + } + + { + SECTION_DATA *chest; + + chest=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"chest"); + + if (chest==NULL) { + /* I'm impressed. */ + deathtype+=2; + } else if ((chest->flags§ion_data_notreal) + &&(chest->flags§ion_data_terminate_here)) { + /* That's gotta hurt. */ + deathtype++; + } + } + + /* Gibb noise? */ + if (predatorStatusPointer->GibbFactor>0) { + /* This probably never happens... */ + } else { + SECTION_DATA *head; + /* make a sound... if you have a head. */ + head=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"head"); + + /* Is it still attached? */ + if (head) { + if (head->flags§ion_data_notreal) { + head=NULL; + } + } + + if ((predatorStatusPointer->soundHandle==SOUND_NOACTIVEINDEX)&&(head)) { + DoPredatorDeathSound(sbPtr); + } + } + + { + DEATH_DATA *this_death; + HIT_FACING facing; + SECTION *root; + int burning; + int wounds; + + root=GetNamedHierarchyFromLibrary("hnpcpredator","Template"); + + facing.Front=0; + facing.Back=0; + facing.Left=0; + facing.Right=0; + + if (incoming) { + if (incoming->vz>0) { + facing.Back=1; + } else { + facing.Front=1; + } + if (incoming->vx>0) { + facing.Right=1; + } else { + facing.Left=1; + } + } + + if ((damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire>0) + &&(damage->Electrical==0) + &&(damage->Acid==0) + ) { + burning=1; + } else { + burning=0; + } + + if (Section) { + wounds=(Section->flags§ion_flags_wounding); + } else { + wounds=0; + } + + //if (predatorStatusPointer->behaviourState==PBS_SelfDestruct) { + // this_death=&Predator_Special_SelfDestruct_Death; + //} else { + this_death=GetPredatorDeathSequence(&predatorStatusPointer->HModelController,root,wounds, + wounds,deathtype,&facing,burning,predatorStatusPointer->IAmCrouched,0); + //} + + GLOBALASSERT(this_death); + + Remove_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation"); + Remove_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta"); + + Convert_Predator_To_Corpse(sbPtr,this_death); + + return; + } + } else { + /* If not dead, play a hit delta. */ + DELTA_CONTROLLER *hitdelta; + int frontback; + + if ((damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire==0) + &&(damage->Electrical==0) + &&(damage->Acid>0) + ) { + DoPredatorAcidSound(sbPtr); + } else { + DoPredatorHitSound(sbPtr); + } + + hitdelta=Get_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta"); + + if (incoming) { + if (incoming->vz>=0) { + frontback=0; + } else { + frontback=1; + } + } else { + /* Default to front. */ + frontback=1; + } + + if (hitdelta) { + /* A hierarchy with hit deltas! */ + if (hitdelta->Playing==0) { + + int CrouchSubSequence; + int StandSubSequence; + + if (Section==NULL) { + if (frontback==0) { + CrouchSubSequence=PCrSS_HitChestBack; + StandSubSequence=PSSS_HitChestBack; + } else { + CrouchSubSequence=PCrSS_HitChestFront; + StandSubSequence=PSSS_HitChestFront; + } + } else if (Section->sempai->flags§ion_flag_head) { + if (frontback==0) { + CrouchSubSequence=PCrSS_HitHeadBack; + StandSubSequence=PSSS_HitHeadBack; + } else { + CrouchSubSequence=PCrSS_HitHeadFront; + StandSubSequence=PSSS_HitHeadFront; + } + } else if ((Section->sempai->flags§ion_flag_left_arm) + ||(Section->sempai->flags§ion_flag_left_hand)) { + if (frontback==0) { + CrouchSubSequence=PCrSS_HitRightArm; + StandSubSequence=PSSS_HitRightArm; + } else { + CrouchSubSequence=PCrSS_HitLeftArm; + StandSubSequence=PSSS_HitLeftArm; + } + } else if ((Section->sempai->flags§ion_flag_right_arm) + ||(Section->sempai->flags§ion_flag_right_hand)) { + if (frontback==0) { + CrouchSubSequence=PCrSS_HitLeftArm; + StandSubSequence=PSSS_HitLeftArm; + } else { + CrouchSubSequence=PCrSS_HitRightArm; + StandSubSequence=PSSS_HitRightArm; + } + } else if ((Section->sempai->flags§ion_flag_left_leg) + ||(Section->sempai->flags§ion_flag_left_foot)) { + if (frontback==0) { + CrouchSubSequence=PCrSS_HitRightLeg; + StandSubSequence=PSSS_HitRightLeg; + } else { + CrouchSubSequence=PCrSS_HitLeftLeg; + StandSubSequence=PSSS_HitLeftLeg; + } + } else if ((Section->sempai->flags§ion_flag_right_leg) + ||(Section->sempai->flags§ion_flag_right_foot)) { + if (frontback==0) { + CrouchSubSequence=PCrSS_HitLeftLeg; + StandSubSequence=PSSS_HitLeftLeg; + } else { + CrouchSubSequence=PCrSS_HitRightLeg; + StandSubSequence=PSSS_HitRightLeg; + } + } else { + /* Chest or misc. hit. */ + if (frontback==0) { + CrouchSubSequence=PCrSS_HitChestBack; + StandSubSequence=PSSS_HitChestBack; + } else { + CrouchSubSequence=PCrSS_HitChestFront; + StandSubSequence=PSSS_HitChestFront; + } + } + + + if(predatorStatusPointer->IAmCrouched) { + if (HModelSequence_Exists(&predatorStatusPointer->HModelController,(int)HMSQT_PredatorCrouch,CrouchSubSequence)) { + Start_Delta_Sequence(hitdelta,(int)HMSQT_PredatorCrouch,CrouchSubSequence,-1); + } + } else { + if (HModelSequence_Exists(&predatorStatusPointer->HModelController,(int)HMSQT_PredatorStand,StandSubSequence)) { + Start_Delta_Sequence(hitdelta,(int)HMSQT_PredatorStand,StandSubSequence,-1); + } + } + hitdelta->Playing=1; + /* Not looped. */ + } + } + + /* Break out of recover. */ + if (predatorStatusPointer->behaviourState==PBS_Recovering) { + Predator_Enter_Swapping_State(sbPtr); + } + + } +} + +/* Patrick 4/7/97 -------------------------------------------------- + The various far state behaviour execution functions for predator... + + 1. Wandering is the initial far state, to which the predator never + returns: after becoming visible for the first time, it will use only + hunt and retreat + 2. Hunting is used if the predator feels confident enough to engage + the player. + 3. Retreating is used if the predator is not confident +---------------------------------------------------------------------*/ +static PRED_RETURN_CONDITION Execute_PFS_Wander(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + AIMODULE *targetModule = 0; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* Decrement the Far state timer */ + predatorStatusPointer->stateTimer -= NormalFrameTime; + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(predatorStatusPointer->stateTimer > 0) { + return(PRC_No_Change); + } + + /* check for state changes */ + if(PredatorIsAwareOfTarget(sbPtr)) + { + /* we should be hunting */ + return(PRC_Request_Engage); + } + + /* Preds NEVER camp. I mean, get tired of wandering. */ + + /* timer has timed-out in roving mode */ + targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr,NULL,0); + + /* if there is no target module, it means that the pred is trapped in an + unlinked module. In this case, reset the timer and return. */ + if(!targetModule) + { + predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; + return(PRC_No_Change); + } + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + ProcessFarPredatorTargetAIModule(sbPtr, targetModule); + /* reset timer */ + predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PFS_Hunt(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + AIMODULE *targetModule = 0; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* Decrement the Far state timer */ + predatorStatusPointer->stateTimer -= NormalFrameTime; + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(predatorStatusPointer->stateTimer > 0) { + return(PRC_No_Change); + } + + if ((!PredatorIsAwareOfTarget(sbPtr)) + ||(predatorStatusPointer->Target!=Player->ObStrategyBlock)) + { + /* I have a bad feeling about this. */ + return(PRC_Request_Wander); + } + + /* timer has timed-out in hunting mode: */ + targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr,0); + + /* if there is no target module, it means that the pred is trapped in an + unlinked module. In this case, reset the timer and return. */ + if(!targetModule) + { + predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; + return(PRC_No_Change); + } + + /* NB don't need to check for state changes... will regen health on makenear */ + + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + ProcessFarPredatorTargetAIModule(sbPtr, targetModule); + /* reset timer */ + predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PFS_Engage(STRATEGYBLOCK *sbPtr) +{ + /* If we're far, we should be hunting, surely? */ + + return(PRC_Request_Hunt); + +} + +static PRED_RETURN_CONDITION Execute_PFS_Retreat(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + AIMODULE *targetModule = 0; + AIMODULE *old_fearmodule; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + old_fearmodule=predatorStatusPointer->fearmodule; + + /* Decrement the state timer */ + predatorStatusPointer->stateTimer -= NormalFrameTime; + + if(!(PredatorIsAwareOfTarget(sbPtr))) { + /* What am I running from? */ + return(PRC_Request_Recover); + } + + /* check for state changes: randomly decide to switch to recover... */ + + if (predatorStatusPointer->incidentFlag) { + if (!(PredatorCanSeeTarget(sbPtr))) { + return(PRC_Request_Recover); + } + } + + if(predatorStatusPointer->stateTimer > 0) { + return(PRC_No_Change); + } + + /* timer has timed-out in retreat mode: */ + + /* Yeah, from where _am_ I running? */ + if(PredatorIsAwareOfTarget(sbPtr)) { + predatorStatusPointer->fearmodule=predatorStatusPointer->Target->containingModule->m_aimodule; + } else if (predatorStatusPointer->fearmodule==NULL) { + predatorStatusPointer->fearmodule=sbPtr->containingModule->m_aimodule; + } + + if ((predatorStatusPointer->missionmodule==NULL)||(predatorStatusPointer->fearmodule!=old_fearmodule)) { + + /* Recompute mission module. */ + if (predatorStatusPointer->fearmodule) { + predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->fearmodule,5); + } else { + predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,Player->ObStrategyBlock->containingModule->m_aimodule,5); + } + + } + + if (predatorStatusPointer->missionmodule==NULL) { + /* Hey, it'll drop through. */ + return(PRC_Request_Recover); + } + + targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,predatorStatusPointer->missionmodule,6,0); + + if(!targetModule) + { + predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; + return(PRC_Request_Recover); + } + + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + ProcessFarPredatorTargetAIModule(sbPtr, targetModule); + /* reset timer */ + predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PFS_Avoidance(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* High on the list of Things Not To Be Doing. */ + + #if ALL_NEW_AVOIDANCE_PRED + Initialise_AvoidanceManager(sbPtr,&predatorStatusPointer->avoidanceManager); + #endif + + switch (predatorStatusPointer->lastState) { + case PBS_Recovering: + return(PRC_Request_Recover); + break; + case PBS_Hunting: + return(PRC_Request_Hunt); + break; + case PBS_Engaging: + /* Go directly to approach. Do not pass GO. Do not collect 200 zorkmids. */ + return(PRC_Request_Engage); + break; + default: + return(PRC_Request_Wander); + break; + } + /* Still here? */ + return(PRC_Request_Wander); + +} + +static void ProcessFarPredatorTargetAIModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule) +{ + NPC_TARGETMODULESTATUS targetStatus; + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(targetModule); + LOCALASSERT(sbPtr->I_SBtype == I_BehaviourPredator); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + targetStatus = GetTargetAIModuleStatus(sbPtr, targetModule,0); + switch(targetStatus) + { + case(NPCTM_NoEntryPoint): + { + /* do nothing: can't get in. reset lastVisitedModule to avoid getting + stuck in a conceptual dead end (?)*/ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_NormalRoom): + { + /* locate to target */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_AirDuct): + { + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_LiftTeleport): + { + /* do nothing - predators can't go into lifts */ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_ProxDoorOpen): + { + /* locate to target: don't need to move thro'quick, as door is constantly retriggered */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_ProxDoorNotOpen): + { + /* trigger the door, and set timer to quick so we can catch the door when it's open */ + MODULE *renderModule; + renderModule=*(targetModule->m_module_ptrs); + /* trigger the door, and set timer to quick so we can catch the door when it's open */ + ((PROXDOOR_BEHAV_BLOCK *)renderModule->m_sbptr->SBdataptr)->alienTrigger = 1; + break; + } + case(NPCTM_LiftDoorOpen): + { + /* do nothing - can't use lifts */ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_LiftDoorNotOpen): + { + /* do nothing - can't open lift doors */ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_SecurityDoorOpen): + { + /* locate to target, and move thro' quick as we can't retrigger */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_SecurityDoorNotOpen): + { + MODULE *renderModule; + renderModule=*(targetModule->m_module_ptrs); + /* do some door opening stuff here. Door should stay open for long enough + for us to catch it open next time */ + RequestState((renderModule->m_sbptr),1,0); + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } +} + +static PRED_RETURN_CONDITION Execute_PNS_DischargePistol(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + VECTORCH orientationDirn,relPos,relPos2; + int correctlyOrientated,range; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* zero linear velocity in dynamics block */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if (predatorStatusPointer->Target==NULL) { + /* Bomb out. */ + return(PRC_Request_Wander); + } + + /* Always turn to face... */ + GLOBALASSERT(predatorStatusPointer->Target); + NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target); + + /* Fix weapon target! */ + { + predatorStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + 200); + predatorStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + 200); + predatorStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + 200); + } + /* Aim up a little? */ + range=VectorDistance((&predatorStatusPointer->weaponTarget),(&sbPtr->DynPtr->Position)); + + if (range>3000) { + predatorStatusPointer->weaponTarget.vy-=(range/6); + } else { + /* I'm afraid it just won't work. */ + return(PRC_Request_Swap); + } + /* Out of range? */ + if(range > predatorStatusPointer->Selected_Weapon->MaxRange) + { + /* Return to approach... */ + return(PRC_Request_Engage); + } + + /* orientate to firing point first */ + if (predatorStatusPointer->My_Elevation_Section) { + /* Assume range large w.r.t. half shoulder width... */ + orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx; + orientationDirn.vy = 0; + orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz; + } else { + orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + } + /* Target shift? */ + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* Decloaking? */ + if (predatorStatusPointer->CloakStatus==PCLOAK_On) { + PredatorCloakOff(predatorStatusPointer); + } + + /* If still tweening, pause. */ + if (predatorStatusPointer->HModelController.Tweening!=Controller_NoTweening) { + return(PRC_No_Change); + } + + if (predatorStatusPointer->stateTimer==predatorStatusPointer->Selected_Weapon->FiringRate) { + + predatorStatusPointer->HModelController.Playing=0; + + /* Only terminate if you haven't fired yet... */ + if(!PredatorCanSeeTarget(sbPtr)) + { + #if 1 + /* ... and remove the gunflash */ + #endif + + return(PRC_Request_Engage); + } + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing*/ + if((!correctlyOrientated)||(predatorStatusPointer->CloakStatus!=PCLOAK_Off)) + { + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + #endif + return(PRC_No_Change); + } + + /* If you are correctly oriented, you can now fire! */ + + predatorStatusPointer->HModelController.Playing=1; + predatorStatusPointer->HModelController.sequence_timer=0; + + relPos.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vz); + + range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + #if 1 + /* look after the gun flash */ + #endif + + /* look after the sound */ + Sound_Play(SID_PRED_PISTOL,"d",&(sbPtr->DynPtr->Position)); + + /* Now fire a bolt. */ + + { + SECTION_DATA *muzzle; + + muzzle=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"dum flash"); + + CreatePPPlasmaBoltKernel(&muzzle->World_Offset, &muzzle->SecMat,0); + predatorStatusPointer->volleySize++; + } + + if (predatorStatusPointer->volleySize>3) { + predatorStatusPointer->enableSwap=1; + } + } + + predatorStatusPointer->stateTimer -= NormalFrameTime; + + /* You must have fired already. */ + + if(predatorStatusPointer->stateTimer > 0) { + return(PRC_No_Change); + } + + if(range < predatorStatusPointer->Selected_Weapon->MinRange) + { + /* renew firing, as we are still too close to approach */ + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + predatorStatusPointer->volleySize = 0; + return(PRC_No_Change); + } + else + { + NPC_DATA *NpcData; + /* we are far enough away, so return to approach? */ + + NpcData=GetThisNpcData(I_NPC_Predator); + + if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-1))) + &&(sbPtr->SBDamageBlock.Health>0)) { + /* 50% health? */ + if (General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->Target->containingModule->m_aimodule,5)) { + return(PRC_Request_Withdraw); + } else { + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + return(PRC_No_Change); + } + } + + if (predatorStatusPointer->volleySize>=predatorStatusPointer->Selected_Weapon->VolleySize) { + if (((FastRandom()&65535)>32767)&&(predatorStatusPointer->enableSwap)) { + /* Change weapon! */ + return(PRC_Request_Swap); + } else { + return(PRC_Request_Engage); + } + } else { + /* And another! */ + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + return(PRC_No_Change); + } + } + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_AttackWithPlasmaCaster(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + VECTORCH orientationDirn,relPos,relPos2; + int correctlyOrientated,range,onTarget; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* zero linear velocity in dynamics block */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if (predatorStatusPointer->Target==NULL) { + /* Bomb out. */ + return(PRC_Request_Wander); + } + + if (predatorStatusPointer->internalState==0) { + if (predatorStatusPointer->HModelController.Tweening==Controller_NoTweening) { + predatorStatusPointer->HModelController.Playing=0; + } + } + + /* Always turn to face... */ + GLOBALASSERT(predatorStatusPointer->Target); + NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target); + + /* orientate to firing point first */ + if (predatorStatusPointer->My_Elevation_Section) { + /* Assume range large w.r.t. half shoulder width... */ + orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx; + orientationDirn.vy = 0; + orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz; + } else { + orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + } + /* Target shift? */ + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* Decloaking? */ + if (predatorStatusPointer->CloakStatus==PCLOAK_On) { + PredatorCloakOff(predatorStatusPointer); + } + + /* Project three dots? */ + onTarget=DoPredatorLaserTargeting(sbPtr); + + if (predatorStatusPointer->Target->I_SBtype==I_BehaviourAutoGun) { + predatorStatusPointer->stateTimer -= (NormalFrameTime<<2); + } else { + predatorStatusPointer->stateTimer -= NormalFrameTime; + } + + /* Only terminate if you haven't fired yet... */ + if(!PredatorCanSeeTarget(sbPtr)) + { + #if 1 + /* ... and remove the gunflash */ + #endif + + return(PRC_Request_Engage); + } + + if (predatorStatusPointer->internalState==1) { + /* Using stateTimer, thanks! */ + } else if(predatorStatusPointer->stateTimer > 0) { + return(PRC_No_Change); + } + + /* State timed out - try to fire! */ + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing*/ + if((!correctlyOrientated)||(predatorStatusPointer->CloakStatus!=PCLOAK_Off)) + { + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + #endif + return(PRC_No_Change); + } + + if (correctlyOrientated&&(predatorStatusPointer->internalState!=2)) { + if (predatorStatusPointer->internalState!=1) { + predatorStatusPointer->internalState=1; + /* Pausing. */ + predatorStatusPointer->stateTimer=(ONE_FIXED); + } + } + + range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + if ((predatorStatusPointer->internalState==1)&&(predatorStatusPointer->stateTimer<=0)) { + if (onTarget) { + + /* If you are correctly oriented, you can now fire! Or taunt instead? */ + + if (((FastRandom()&65535)<32767)&&(predatorStatusPointer->enableTaunt) + &&(predatorStatusPointer->Target->I_SBtype!=I_BehaviourAutoGun)) { + /* Suprise! */ + return(PRC_Request_Taunt); + } + /* Fire at least once! */ + predatorStatusPointer->enableTaunt=1; + + predatorStatusPointer->HModelController.Playing=1; + predatorStatusPointer->HModelController.Looped=0; + predatorStatusPointer->HModelController.sequence_timer=0; + predatorStatusPointer->internalState=2; + + relPos.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vz); + + #if 1 + /* look after the gun flash */ + #endif + + /* look after the sound */ + Sound_Play(SID_PRED_LAUNCHER,"d",&(sbPtr->DynPtr->Position)); + + /* Now fire a bolt. */ + + { + SECTION_DATA *muzzle; + + muzzle=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"dum flash"); + + InitialiseEnergyBoltBehaviourKernel(&muzzle->World_Offset, &muzzle->SecMat,0,&TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty],65536); + predatorStatusPointer->volleySize++; + } + predatorStatusPointer->stateTimer=(ONE_FIXED); + predatorStatusPointer->enableSwap=1; + return(SRC_No_Change); + } else { + /* You think you're correctly orientated - but you're still not hitting. */ + if (predatorStatusPointer->stateTimer<=0) { + /* Oh, just give up. */ + predatorStatusPointer->HModelController.Playing=1; + predatorStatusPointer->HModelController.Looped=0; + predatorStatusPointer->HModelController.sequence_timer=0; + predatorStatusPointer->internalState=2; + } + } + } + + if (predatorStatusPointer->internalState==2) { + + /* After shot. */ + + if (predatorStatusPointer->HModelController.sequence_timer<(ONE_FIXED-1)) { + /* Still playing. */ + return(PRC_No_Change); + } + + if(range < predatorStatusPointer->Selected_Weapon->MinRange) + { + /* renew firing, as we are still too close to approach */ + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + predatorStatusPointer->volleySize = 0; + predatorStatusPointer->internalState=0; + return(PRC_No_Change); + } + else + { + NPC_DATA *NpcData; + /* we are far enough away, so return to approach? */ + + NpcData=GetThisNpcData(I_NPC_Predator); + + if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-1))) + &&(sbPtr->SBDamageBlock.Health>0)) { + /* 50% health? */ + if (General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->Target->containingModule->m_aimodule,5)) { + return(PRC_Request_Withdraw); + } else { + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + predatorStatusPointer->internalState=0; + return(PRC_No_Change); + } + } + + if (predatorStatusPointer->volleySize>=predatorStatusPointer->Selected_Weapon->VolleySize) { + if ((range52000)) { + /* Change weapon! */ + return(PRC_Request_Swap); + } else { + return(PRC_Request_Engage); + } + } else { + /* And another! */ + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + predatorStatusPointer->internalState=0; + return(PRC_No_Change); + } + } + + } + + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_Avoidance(STRATEGYBLOCK *sbPtr) +{ + int terminateState = 0; + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* first check for a close attack... */ + if(VectorDistance((&Player->ObStrategyBlock->DynPtr->Position),(&sbPtr->DynPtr->Position)) < PRED_CLOSE_ATTACK_RANGE) + { + return(PRC_Request_Attack); + } + + /* New avoidance kernel. */ + + NPCSetVelocity(sbPtr, &(predatorStatusPointer->avoidanceManager.avoidanceDirection), (predatorStatusPointer->nearSpeed)); + /* Velocity CANNOT be zero, unless deliberately so! */ + { + AVOIDANCE_RETURN_CONDITION rc; + + rc=AllNewAvoidanceKernel(sbPtr,&predatorStatusPointer->avoidanceManager); + + if (rc!=AvRC_Avoidance) { + terminateState=1; + } + } + + PredatorHandleMovingAnimation(sbPtr); + + if(terminateState) + { + /* Better exit. */ + switch (predatorStatusPointer->lastState) { + case PBS_Avoidance: + default: + /* switch to approach */ + if(PredatorShouldAttackPlayer(sbPtr)) + { + /* go to approach */ + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + return(PRC_Request_Engage); + } + else + { + /* go to retreat */ + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + return(PRC_Request_Withdraw); + } + break; + case PBS_Wandering: + return(PRC_Request_Wander); + break; + case PBS_Hunting: + return(PRC_Request_Hunt); + break; + case PBS_Withdrawing: + return(PRC_Request_Withdraw); + break; + case PBS_Engaging: + case PBS_Attacking: + return(PRC_Request_Engage); + break; + case PBS_Returning: + return(PRC_Request_Return); + break; + case PBS_Pathfinding: + return(PRC_Request_Pathfind); + break; + } + } + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_Approach(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + VECTORCH velocityDirection = {0,0,0}; + VECTORCH targetPosition; + int targetIsAirduct = 0; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + LOCALASSERT(sbPtr->DynPtr); + + GLOBALASSERT(0); + /* Function unused! */ + + /* Make some noise if not cloaked */ + if (predatorStatusPointer->CloakStatus == PCLOAK_Off) + { + #if 0 + unsigned int random=FastRandom() & 127; + switch (random) + { + case 0: + { + Sound_Play(SID_PRED_SNARL,"d",&sbPtr->DynPtr->Position); + break; + } + case 1: + { + Sound_Play(SID_PRED_SCREAM1,"d",&sbPtr->DynPtr->Position); + break; + } + case 2: + { + Sound_Play(SID_PRED_LOUDROAR,"d",&sbPtr->DynPtr->Position); + break; + } + case 3: + { + Sound_Play(SID_PRED_SHORTROAR,"d",&sbPtr->DynPtr->Position); + break; + } + default: + { + break; + } + } + #else + DoPredatorRandomSound(sbPtr); + #endif + } + + PredatorHandleMovingAnimation(sbPtr); + + /* check for state changes...*/ + + /* now check if we want to close-attack */ + if(VectorDistance((&Player->ObStrategyBlock->DynPtr->Position),(&sbPtr->DynPtr->Position)) < PRED_CLOSE_ATTACK_RANGE) + { + return(PRC_Request_Attack); + } + + /* now check if we should stand ground */ + if(!(PredatorShouldAttackPlayer(sbPtr))) + { + return(PRC_Request_Withdraw); + } + + + /* decrement the state timer if it is > 0. When this timer expires, predator + will fire at player when it can next see him (or her) */ + if(predatorStatusPointer->stateTimer > 0) predatorStatusPointer->stateTimer -= NormalFrameTime; + if(predatorStatusPointer->stateTimer <= 0) + { + /* if we can see the player, switch to fire */ + if(NPCCanSeeTarget(sbPtr,Player->ObStrategyBlock, PRED_NEAR_VIEW_WIDTH)) + { + return(PRC_Request_Attack); + } + else + { + /* reset the timer if we couldn't fire */ + predatorStatusPointer->stateTimer = predatorCV[predatorStatusPointer->personalNumber].timeBetweenRangedAttacks; + } + + } + + /* get and set approach velocity */ + NPCGetMovementTarget(sbPtr, Player->ObStrategyBlock, &targetPosition, &targetIsAirduct,0); + NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&predatorStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + { + if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(PRC_Request_Avoidance); + } + } + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_EngageWithPistol(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + VECTORCH velocityDirection = {0,0,0}; + VECTORCH targetPosition; + int targetIsAirduct = 0; + int range; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + PredatorHandleMovingAnimation(sbPtr); + + /* now check for state changes... firstly, if we can no longer attack the target, go + to wander */ + if(!(PredatorIsAwareOfTarget(sbPtr))) + { + return(PRC_Request_Hunt); + /* Drop out null targets. */ + } else { + + /* We have a target that we are aware of. */ + + range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + /* Wanna Cloak? */ + if (predatorStatusPointer->CloakStatus==PCLOAK_Off) { + PredatorCloakOn(predatorStatusPointer); + } + + /* if we are close... go directly to firing */ + if(range < PRED_CLOSE_ATTACK_RANGE) + { + /* switch directly to firing, at this distance */ + + return(PRC_Request_Attack); + } + + /* if our state timer has run out in approach state, see if we can fire*/ + if(predatorStatusPointer->stateTimer > 0) predatorStatusPointer->stateTimer -= NormalFrameTime; + if(predatorStatusPointer->stateTimer <= 0) + { + /* it is time to fire, if we can see the target */ + if(PredatorCanSeeTarget(sbPtr)) + { + /* we are going to fire then */ + + return(PRC_Request_Attack); + } + else + { + /* renew approach state */ + predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; + /* Whatever. */ + } + } + } + + /* See which way we want to go. */ + { + + AIMODULE *targetModule; + MODULE *tcm; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + + GLOBALASSERT(predatorStatusPointer->Target!=NULL); + + if (predatorStatusPointer->Target->containingModule) { + tcm=predatorStatusPointer->Target->containingModule; + } else { + tcm=ModuleFromPosition(&predatorStatusPointer->Target->DynPtr->Position,sbPtr->containingModule); + } + + if (tcm) { + targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,tcm->m_aimodule,7,0); + } else { + targetModule=NULL; + } + + if (targetModule==sbPtr->containingModule->m_aimodule) { + /* Try going for it, we still can't see them. */ + NPCGetMovementTarget(sbPtr, predatorStatusPointer->Target, &targetPosition, &targetIsAirduct,0); + NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&predatorStatusPointer->waypointManager); + } else if (!targetModule) { + /* Must be inaccessible. */ + if (ShowPredoStats) { + if (predatorStatusPointer->Target->containingModule) { + PrintDebuggingText("I can see you, but I can't get there!\n"); + } else { + PrintDebuggingText("Hey, you've got no Containing Module!\n"); + } + } + return(PRC_No_Change); + } else { + + thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); + if (!thisEp) { + LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.", + (*(targetModule->m_module_ptrs))->name, + sbPtr->containingModule->name)); + GLOBALASSERT(thisEp); + } + /* If that fired, there's a farped adjacency. */ + + predatorStatusPointer->wanderData.worldPosition=thisEp->position; + predatorStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx; + predatorStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy; + predatorStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz; + + NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager); + } + + } + + /* Should have a velocity set now. */ + + NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE_PRED + { + if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(PRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + + NPC_IsObstructed(sbPtr,&(predatorStatusPointer->moveData),&predatorStatusPointer->obstruction,&destructableObject); + if(predatorStatusPointer->obstruction.environment) + { + /* go to avoidance */ + return(PRC_Request_Avoidance); + } + if(predatorStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(predatorStatusPointer->moveData), &targetPosition, &velocityDirection)) + { + + predatorStatusPointer->obstruction.environment=1; + predatorStatusPointer->obstruction.destructableObject=0; + predatorStatusPointer->obstruction.otherCharacter=0; + predatorStatusPointer->obstruction.anySingleObstruction=0; + + return(PRC_Request_Avoidance); + } + #endif + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_EngageWithPlasmaCaster(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + VECTORCH velocityDirection = {0,0,0}; + VECTORCH targetPosition; + int targetIsAirduct = 0; + int range; + + /* For the moment, the same as the pistol. */ + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + PredatorHandleMovingAnimation(sbPtr); + + predatorStatusPointer->patience-=NormalFrameTime; + /* Have we become impatient? */ + if (predatorStatusPointer->patience<=0) { + return(PRC_Request_Swap); + } + + /* now check for state changes... firstly, if we can no longer attack the target, go + to wander */ + if(!(PredatorIsAwareOfTarget(sbPtr))) + { + return(PRC_Request_Hunt); + /* Drop out null targets. */ + } else { + + /* We have a target that we are aware of. */ + + range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + /* if we are close... go directly to firing */ + if(range < PRED_CLOSE_ATTACK_RANGE) + { + /* switch directly to firing, at this distance */ + + return(PRC_Request_Attack); + } else { + + /* Wanna Cloak? */ + if (predatorStatusPointer->CloakStatus==PCLOAK_Off) { + PredatorCloakOn(predatorStatusPointer); + } + + } + + /* if our state timer has run out in approach state, see if we can fire*/ + if(predatorStatusPointer->stateTimer > 0) predatorStatusPointer->stateTimer -= NormalFrameTime; + if(predatorStatusPointer->stateTimer <= 0) + { + /* it is time to fire, if we can see the target */ + if(PredatorCanSeeTarget(sbPtr)) + { + /* we are going to fire then */ + + return(PRC_Request_Attack); + } + else + { + /* renew approach state */ + predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; + /* Whatever. */ + } + } + } + + /* See which way we want to go. */ + { + + AIMODULE *targetModule; + MODULE *tcm; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + + GLOBALASSERT(predatorStatusPointer->Target!=NULL); + + if (predatorStatusPointer->Target->containingModule) { + tcm=predatorStatusPointer->Target->containingModule; + } else { + tcm=ModuleFromPosition(&predatorStatusPointer->Target->DynPtr->Position,sbPtr->containingModule); + } + + if (tcm) { + targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,tcm->m_aimodule,7,0); + } else { + targetModule=NULL; + } + + if (targetModule==sbPtr->containingModule->m_aimodule) { + /* Try going for it, we still can't see them. */ + NPCGetMovementTarget(sbPtr, predatorStatusPointer->Target, &targetPosition, &targetIsAirduct,0); + NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&predatorStatusPointer->waypointManager); + } else if (!targetModule) { + /* Must be inaccessible. */ + if (ShowPredoStats) { + if (predatorStatusPointer->Target->containingModule) { + PrintDebuggingText("I can see you, but I can't get there!\n"); + } else { + PrintDebuggingText("Hey, you've got no Containing Module!\n"); + } + } + return(PRC_No_Change); + } else { + + thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); + if (!thisEp) { + LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.", + (*(targetModule->m_module_ptrs))->name, + sbPtr->containingModule->name)); + GLOBALASSERT(thisEp); + } + /* If that fired, there's a farped adjacency. */ + + predatorStatusPointer->wanderData.worldPosition=thisEp->position; + predatorStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx; + predatorStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy; + predatorStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz; + + NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager); + } + + } + + /* Should have a velocity set now. */ + + NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE_PRED + { + if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(PRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + + NPC_IsObstructed(sbPtr,&(predatorStatusPointer->moveData),&predatorStatusPointer->obstruction,&destructableObject); + if(predatorStatusPointer->obstruction.environment) + { + /* go to avoidance */ + return(PRC_Request_Avoidance); + } + if(predatorStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(predatorStatusPointer->moveData), &targetPosition, &velocityDirection)) + { + + predatorStatusPointer->obstruction.environment=1; + predatorStatusPointer->obstruction.destructableObject=0; + predatorStatusPointer->obstruction.otherCharacter=0; + predatorStatusPointer->obstruction.anySingleObstruction=0; + + return(PRC_Request_Avoidance); + } + #endif + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_EngageWithWristblade(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + VECTORCH velocityDirection = {0,0,0}; + VECTORCH targetPosition; + int targetIsAirduct = 0; + int range; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + PredatorHandleMovingAnimation(sbPtr); + + predatorStatusPointer->patience-=NormalFrameTime; + /* Have we become impatient? */ + if (predatorStatusPointer->patience<=0) { + return(PRC_Request_Swap); + } + + /* now check for state changes... firstly, if we can no longer attack the target, go + to wander */ + if(!(PredatorIsAwareOfTarget(sbPtr))) + { + return(PRC_Request_Hunt); + /* Drop out null targets. */ + } else { + + /* We have a target that we are aware of. */ + + range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + /* Wanna Cloak? */ + if (range<5000) { + /* Decloak when close. */ + PredatorCloakOff(predatorStatusPointer); + } else if (predatorStatusPointer->CloakStatus==PCLOAK_Off) { + PredatorCloakOn(predatorStatusPointer); + } + + /* if we are close... go directly to firing */ + if(range < PRED_CLOSE_ATTACK_RANGE) + { + /* switch directly to firing, at this distance */ + + return(PRC_Request_Attack); + } + + /* if our state timer has run out in approach state, see if we can fire*/ + if(predatorStatusPointer->stateTimer > 0) { + predatorStatusPointer->stateTimer -= NormalFrameTime; + } + + if(predatorStatusPointer->stateTimer <= 0) + { + /* A moment of decision... */ + /* Might want to withdraw. */ + if(!PredatorCanSeeTarget(sbPtr)) + { + /* Lost sight of him! */ + + return(PRC_Request_Hunt); + } + else + { + /* renew approach state */ + predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; + /* Whatever. */ + } + } + } + + /* See which way we want to go. */ + { + + AIMODULE *targetModule; + MODULE *tcm; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + + GLOBALASSERT(predatorStatusPointer->Target!=NULL); + + if (predatorStatusPointer->Target->containingModule) { + tcm=predatorStatusPointer->Target->containingModule; + } else { + tcm=ModuleFromPosition(&predatorStatusPointer->Target->DynPtr->Position,sbPtr->containingModule); + } + + if (tcm) { + targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,tcm->m_aimodule,7,0); + } else { + targetModule=NULL; + } + + if (targetModule==sbPtr->containingModule->m_aimodule) { + /* Try going for it, we still can't see them. */ + NPCGetMovementTarget(sbPtr, predatorStatusPointer->Target, &targetPosition, &targetIsAirduct,0); + NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&predatorStatusPointer->waypointManager); + } else if (!targetModule) { + /* Must be inaccessible. */ + if (ShowPredoStats) { + if (predatorStatusPointer->Target->containingModule) { + PrintDebuggingText("I can see you, but I can't get there!\n"); + } else { + PrintDebuggingText("Hey, you've got no Containing Module!\n"); + } + } + return(PRC_No_Change); + } else { + + thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); + if (!thisEp) { + LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.", + (*(targetModule->m_module_ptrs))->name, + sbPtr->containingModule->name)); + GLOBALASSERT(thisEp); + } + /* If that fired, there's a farped adjacency. */ + + predatorStatusPointer->wanderData.worldPosition=thisEp->position; + predatorStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx; + predatorStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy; + predatorStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz; + + NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager); + } + + } + + /* Should have a velocity set now. */ + + NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE_PRED + { + if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(PRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + + NPC_IsObstructed(sbPtr,&(predatorStatusPointer->moveData),&predatorStatusPointer->obstruction,&destructableObject); + if(predatorStatusPointer->obstruction.environment) + { + /* go to avoidance */ + return(PRC_Request_Avoidance); + } + if(predatorStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(predatorStatusPointer->moveData), &targetPosition, &velocityDirection)) + { + + predatorStatusPointer->obstruction.environment=1; + predatorStatusPointer->obstruction.destructableObject=0; + predatorStatusPointer->obstruction.otherCharacter=0; + predatorStatusPointer->obstruction.anySingleObstruction=0; + + predatorStatusPointer->patience-=ONE_FIXED; + + return(PRC_Request_Avoidance); + } + #endif + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_AttackWithWristblade(STRATEGYBLOCK *sbPtr) +{ + VECTORCH orientationDirn; + int i; + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + LOCALASSERT (sbPtr->DynPtr); + + /* zero linear velocity in dynamics block */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + dynPtr = sbPtr->DynPtr; + + if (predatorStatusPointer->Target==NULL) { + /* Bomb out. */ + return(PRC_Request_Wander); + } + + /* De-cloak. */ + if(predatorStatusPointer->CloakStatus==PCLOAK_On) + { + PredatorCloakOff(predatorStatusPointer); + } + + GLOBALASSERT(predatorStatusPointer->Target); + NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target); + + /* check for state changes: */ + if(VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)) > PRED_CLOSE_ATTACK_RANGE) + { + if (((FastRandom()&65535)>32767)&&(predatorStatusPointer->enableSwap)) { + /* Change weapon! */ + return(PRC_Request_Swap); + } else { + /* switch back to engage. */ + GLOBALASSERT(predatorStatusPointer->Target); + NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target); + return(PRC_Request_Engage); + } + } + + /* Orientate towards player, just to make sure we're facing */ + orientationDirn.vx = predatorStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = predatorStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; + i = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* Decrement the near state timer */ + predatorStatusPointer->stateTimer -= NormalFrameTime; + + PredatorNearDamageShell(sbPtr); + + if (predatorStatusPointer->HModelController.keyframe_flags&1) { + + predatorStatusPointer->enableSwap=1; + StartWristbladeAttackSequence(sbPtr); + predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME; + /* Shrug. */ + } + return(PRC_No_Change); + +} + +static PRED_RETURN_CONDITION Execute_PNS_StandGround(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* basically just stand there and fire... */ + + /* zero linear velocity in dynamics block */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* check if we want to close-attack */ + if(VectorDistance((&Player->ObStrategyBlock->DynPtr->Position),(&sbPtr->DynPtr->Position)) < PRED_CLOSE_ATTACK_RANGE) + { + return(PRC_Request_Attack); + } + + /* decrement the state timer if it is > 0. When this timer expires, predator + will fire at player when it can next see him (or her) */ + if(predatorStatusPointer->stateTimer > 0) predatorStatusPointer->stateTimer -= NormalFrameTime; + if(predatorStatusPointer->stateTimer <= 0) + { + /* if we can see the player, switch to fire */ + if(NPCCanSeeTarget(sbPtr,Player->ObStrategyBlock, PRED_NEAR_VIEW_WIDTH)) + { + return(PRC_Request_Attack); + } + else + { + /* reset the timer if we couldn't fire */ + predatorStatusPointer->stateTimer = predatorCV[predatorStatusPointer->personalNumber].timeBetweenRangedAttacks; + } + } + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_SwapWeapon(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* zero linear velocity in dynamics block */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if (predatorStatusPointer->ChangeToWeapon==PNPCW_End) { + /* Rubbish! */ + return(PRC_Request_Hunt); + } + + Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, + "Predator Swap Weapon Start"); + + if (predatorStatusPointer->stateTimer==0) { + /* Haven't started yet. */ + if (predatorStatusPointer->ChangeToWeapon==predatorStatusPointer->Selected_Weapon->id) { + /* Stop wasting my time! */ + return(PRC_Request_Hunt); + } + + if (ShowPredoStats) { + PrintDebuggingText("Part one "); + } + + /* Decloak. */ + if (predatorStatusPointer->CloakStatus!=PCLOAK_Off) { + /* Sorry, I want to see this. */ + return(PRC_No_Change); + } + + /* Right. Is there a 'deselect' anim? */ + if (predatorStatusPointer->IAmCrouched) { + if (HModelSequence_Exists(&predatorStatusPointer->HModelController, + (int)HMSQT_PredatorCrouch,(int)PCrSS_Get_Weapon)) { + /* It's there! */ + if (predatorStatusPointer->Selected_Weapon->SwappingTime!=0) { + /* Valid swap time, too. */ + InitHModelTweening_Backwards(&predatorStatusPointer->HModelController, + (ONE_FIXED>>2),(int)HMSQT_PredatorCrouch,(int)PCrSS_Get_Weapon, + predatorStatusPointer->Selected_Weapon->SwappingTime,0); + predatorStatusPointer->HModelController.Looped=0; + predatorStatusPointer->stateTimer=1; /* Swapping Out. */ + return(PRC_No_Change); + } + } + } else { + if (HModelSequence_Exists(&predatorStatusPointer->HModelController, + (int)HMSQT_PredatorStand,(int)PSSS_Get_Weapon)) { + /* It's there! */ + if (predatorStatusPointer->Selected_Weapon->SwappingTime!=0) { + /* Valid swap time, too. */ + InitHModelTweening_Backwards(&predatorStatusPointer->HModelController, + (ONE_FIXED>>2),(int)HMSQT_PredatorStand,(int)PSSS_Get_Weapon, + predatorStatusPointer->Selected_Weapon->SwappingTime,0); + predatorStatusPointer->HModelController.Looped=0; + predatorStatusPointer->stateTimer=1; /* Swapping Out. */ + return(PRC_No_Change); + } + } + } + /* If you're still here, there must be no swapping out sequence. */ + predatorStatusPointer->stateTimer=2; + /* Ah well, go directly to the middle. */ + return(PRC_No_Change); + } else if (predatorStatusPointer->stateTimer==1) { + /* You are in the process of swapping out. */ + + if (ShowPredoStats) { + PrintDebuggingText("Part two "); + } + + if (HModelAnimation_IsFinished(&predatorStatusPointer->HModelController)) { + /* Right, you've finished! */ + predatorStatusPointer->stateTimer=2; + return(PRC_No_Change); + } else { + GLOBALASSERT(predatorStatusPointer->HModelController.Looped==0); + return(PRC_No_Change); + } + } else if (predatorStatusPointer->stateTimer==2) { + /* In the middle! */ + PREDATOR_WEAPON_DATA *targetWeapon; + SECTION *root_section; + + if (ShowPredoStats) { + PrintDebuggingText("Part three "); + } + + targetWeapon=GetThisNPCPredatorWeapon(predatorStatusPointer->ChangeToWeapon); + if (!targetWeapon) { + /* We're screwed. Stay with the old one! */ + predatorStatusPointer->ChangeToWeapon=PNPCW_End; + return(PRC_Request_Hunt); + } + predatorStatusPointer->Selected_Weapon=targetWeapon; + root_section=GetNamedHierarchyFromLibrary(predatorStatusPointer->Selected_Weapon->Riffname,predatorStatusPointer->Selected_Weapon->HierarchyName); + GLOBALASSERT(root_section); + + /* Strip out HitDelta for now, if any... */ + { + DELTA_CONTROLLER *delta; + delta=Get_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta"); + if (delta) { + Remove_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta"); + } + } + + /* Strip off elevation too. */ + { + DELTA_CONTROLLER *delta; + delta=Get_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation"); + if (delta) { + Remove_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation"); + } + } + + Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, + "Predator Swap Weapon Two"); + + /* In the interests of getting the new sections right... */ + predatorStatusPointer->HModelController.Sequence_Type=(int)HMSQT_PredatorStand; + predatorStatusPointer->HModelController.Sub_Sequence=(int)PSSS_Get_Weapon; + + Transmogrify_HModels(sbPtr,&predatorStatusPointer->HModelController,root_section,0,1,0); + + #if PREDATOR_HIT_DELTAS + if (HModelSequence_Exists(&predatorStatusPointer->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront)) { + /* This ritual in case _one_ of the hierarchies doesn't have hitdeltas. */ + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta",(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront,-1); + GLOBALASSERT(delta); + delta->Playing=0; + } + #endif + + /* Replace elevation. */ + if (predatorStatusPointer->Selected_Weapon->UseElevation) { + if (Get_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation")==NULL) { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation",(int)HMSQT_PredatorStand,(int)PSSS_Elevation,0); + GLOBALASSERT(delta); + delta->timer=32767; + } + } else { + /* Better make sure it's gone... */ + Remove_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation"); + } + + Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, + "Predator Swap Weapon Two A"); + + DeInitialise_HModel(&predatorStatusPointer->HModelController); + ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr); + + Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, + "Predator Swap Weapon Three"); + + predatorStatusPointer->My_Gun_Section=GetThisSectionData(predatorStatusPointer->HModelController.section_data,predatorStatusPointer->Selected_Weapon->GunName); + predatorStatusPointer->My_Elevation_Section=GetThisSectionData(predatorStatusPointer->HModelController.section_data,predatorStatusPointer->Selected_Weapon->ElevationName); + + /* Now go for the Get_Weapon sequence. */ + if (predatorStatusPointer->IAmCrouched) { + if (HModelSequence_Exists(&predatorStatusPointer->HModelController, + (int)HMSQT_PredatorCrouch,(int)PCrSS_Get_Weapon)) { + /* It's there! */ + if (predatorStatusPointer->Selected_Weapon->SwappingTime!=0) { + /* Valid swap time, too. */ + predatorStatusPointer->HModelController.Sequence_Type=(int)HMSQT_PredatorCrouch; + predatorStatusPointer->HModelController.Sub_Sequence=(int)PCrSS_Get_Weapon; + predatorStatusPointer->HModelController.Seconds_For_Sequence=predatorStatusPointer->Selected_Weapon->SwappingTime; + /* That to get the new sections right. */ + InitHModelTweening(&predatorStatusPointer->HModelController, + (ONE_FIXED>>2),(int)HMSQT_PredatorCrouch,(int)PCrSS_Get_Weapon, + predatorStatusPointer->Selected_Weapon->SwappingTime,0); + predatorStatusPointer->HModelController.Looped=0; + predatorStatusPointer->stateTimer=3; /* Swapping In. */ + + Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, + "Predator Swap Weapon Three A"); + + ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr); + + Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, + "Predator Swap Weapon Four"); + + return(PRC_No_Change); + } + } + } else { + if (HModelSequence_Exists(&predatorStatusPointer->HModelController, + (int)HMSQT_PredatorStand,(int)PSSS_Get_Weapon)) { + /* It's there! */ + if (predatorStatusPointer->Selected_Weapon->SwappingTime!=0) { + /* Valid swap time, too. */ + predatorStatusPointer->HModelController.Sequence_Type=(int)HMSQT_PredatorStand; + predatorStatusPointer->HModelController.Sub_Sequence=(int)PSSS_Get_Weapon; + predatorStatusPointer->HModelController.Seconds_For_Sequence=predatorStatusPointer->Selected_Weapon->SwappingTime; + /* That to get the new sections right. */ + InitHModelTweening(&predatorStatusPointer->HModelController, + (ONE_FIXED>>2),(int)HMSQT_PredatorStand,(int)PSSS_Get_Weapon, + predatorStatusPointer->Selected_Weapon->SwappingTime,0); + predatorStatusPointer->HModelController.Looped=0; + predatorStatusPointer->stateTimer=3; /* Swapping In. */ + + Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, + "Predator Swap Weapon Four A"); + + ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr); + + Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, + "Predator Swap Weapon Five"); + + return(PRC_No_Change); + } + } + } + + /* If you're still here, there must be no swapping in sequence. */ + predatorStatusPointer->stateTimer=4; + /* Ah well, go directly to the end. */ + + Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, + "Predator Swap Weapon Six"); + + return(PRC_No_Change); + + } else if (predatorStatusPointer->stateTimer==3) { + /* You are in the process of swapping in. */ + + if (ShowPredoStats) { + PrintDebuggingText("Part four "); + } + + if (HModelAnimation_IsFinished(&predatorStatusPointer->HModelController)) { + /* Right, you've finished! */ + predatorStatusPointer->stateTimer=4; + return(PRC_No_Change); + } else { + GLOBALASSERT(predatorStatusPointer->HModelController.Looped==0); + return(PRC_No_Change); + } + } else if (predatorStatusPointer->stateTimer==4) { + /* All (valid) conclusions arrive here. */ + + if (ShowPredoStats) { + PrintDebuggingText("Part five "); + } + + predatorStatusPointer->ChangeToWeapon=PNPCW_End; + if (predatorStatusPointer->Selected_Weapon->id==PNPCW_Medicomp) { + return(PRC_Request_Recover); + } else { + return(PRC_Request_Attack); + } + } + + if (ShowPredoStats) { + PrintDebuggingText("No Part %d ",predatorStatusPointer->stateTimer); + } + + return(PRC_No_Change); + +} + +static PRED_RETURN_CONDITION Execute_PNS_Wander(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + DYNAMICSBLOCK *dynPtr; + VECTORCH velocityDirection = {0,0,0}; + + LOCALASSERT(sbPtr); + predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(predatorStatusPointer); + LOCALASSERT(dynPtr); + + PredatorHandleMovingAnimation(sbPtr); + + /* should we change to approach state? */ + if (PredatorIsAwareOfTarget(sbPtr)) + { + /* doesn't require a sequence change */ + return(PRC_Request_Engage); + } + + /* Are we using bimble rules? */ + + if (predatorStatusPointer->wanderData.currentModule==NPC_BIMBLINGINMODULE) { + + int range; + + /* Range to target... */ + + range=VectorDistance((&predatorStatusPointer->wanderData.worldPosition),(&sbPtr->DynPtr->Position)); + + if (range<2000) { + + /* Reset system, try again. */ + predatorStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE; + + } + + } + else + { + /* wander target aquisition: if no target, or moved module */ + LOCALASSERT(sbPtr->containingModule); + if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPC_FindAIWanderTarget(sbPtr,&(predatorStatusPointer->wanderData),&(predatorStatusPointer->moveData),0); + } + else if(predatorStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_aimodule->m_index) + { + NPC_FindAIWanderTarget(sbPtr,&(predatorStatusPointer->wanderData),&(predatorStatusPointer->moveData),0); + } + + /* if we still haven't got one, bimble about in this one for a bit. */ + if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_GetBimbleTarget(sbPtr,&predatorStatusPointer->wanderData.worldPosition); + predatorStatusPointer->wanderData.currentModule=NPC_BIMBLINGINMODULE; + } + + } + + /* ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) + { + /* Go to all new avoidance. */ + return(PRC_Request_Avoidance); + } + + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_Hunt(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + DYNAMICSBLOCK *dynPtr; + VECTORCH velocityDirection = {0,0,0}; + + /* Your mission: to advance into the players module, even if near. */ + + LOCALASSERT(sbPtr); + predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(predatorStatusPointer); + LOCALASSERT(dynPtr); + + PredatorHandleMovingAnimation(sbPtr); + + /* should we change to approach state? */ + if(PredatorCanSeeTarget(sbPtr)) + { + return(PRC_Request_Engage); + } else if(!(PredatorIsAwareOfTarget(sbPtr))) { + /* I have a bad feeling about this, too. */ + //return(PRC_No_Change); + /* Might just be in a non-vis module now... */ + } + + { + AIMODULE *targetModule; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + + targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr,0); + + if (targetModule) { + if (ShowPredoStats) { + PrintDebuggingText("Target Module %s.\n",(*(targetModule->m_module_ptrs))->name); + } + } else { + if (ShowPredoStats) { + PrintDebuggingText("Target Module NULL.\n"); + } + } + + if (targetModule==sbPtr->containingModule->m_aimodule) { + /* Hey, it'll drop through. */ + if (predatorStatusPointer->Target==NULL) { + return(PRC_Request_Wander); + } else { + return(PRC_Request_Engage); + } + } + + if (!targetModule) { + #if 1 + /* Must be sealed off. */ + return(PRC_Request_Recover); + #else + extern MODULE *playerPherModule; + + LOGDXFMT(("Jules's bug: predator is in %s, player is in %s",sbPtr->containingModule->name,playerPherModule->name)); + GLOBALASSERT(targetModule); + #endif + } + + thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); + if (!thisEp) { + LOGDXFMT(("This assert is a busted adjacency!")); + GLOBALASSERT(thisEp); + } + /* If that fired, there's a farped adjacency. */ + + predatorStatusPointer->wanderData.worldPosition=thisEp->position; + predatorStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx; + predatorStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy; + predatorStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz; + + } + + /* ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE_PRED + { + if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(PRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + + NPC_IsObstructed(sbPtr,&(predatorStatusPointer->moveData),&predatorStatusPointer->obstruction,&destructableObject); + if((predatorStatusPointer->obstruction.environment)||(predatorStatusPointer->obstruction.otherCharacter)) + { + return(PRC_Request_Avoidance); + } + if(predatorStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(predatorStatusPointer->moveData), &(predatorStatusPointer->wanderData.worldPosition), &velocityDirection)) + { + /* go to avoidance */ + /* no sequence change required */ + + predatorStatusPointer->obstruction.environment=1; + predatorStatusPointer->obstruction.destructableObject=0; + predatorStatusPointer->obstruction.otherCharacter=0; + predatorStatusPointer->obstruction.anySingleObstruction=0; + + return(PRC_Request_Avoidance); + } + #endif + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_Retreat(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + DYNAMICSBLOCK *dynPtr; + VECTORCH velocityDirection = {0,0,0}; + AIMODULE *old_fearmodule; + + /* Your mission: to advance out of trouble, even if near. */ + + LOCALASSERT(sbPtr); + predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(predatorStatusPointer); + LOCALASSERT(dynPtr); + + PredatorHandleMovingAnimation(sbPtr); + + old_fearmodule=predatorStatusPointer->fearmodule; + + if(!(PredatorIsAwareOfTarget(sbPtr))) { + /* What am I running from? */ + return(PRC_Request_Recover); + } + + #if 0 + if (predatorStatusPointer->incidentFlag) { + /* Need a better test here. */ + if (!(PredatorCanSeeTarget(sbPtr))) { + return(PRC_Request_Recover); + } + } + #endif + + /* Yeah, from where _am_ I running? */ + if(PredatorIsAwareOfTarget(sbPtr)) { + predatorStatusPointer->fearmodule=predatorStatusPointer->Target->containingModule->m_aimodule; + } else if (predatorStatusPointer->fearmodule==NULL) { + predatorStatusPointer->fearmodule=sbPtr->containingModule->m_aimodule; + } + + if ((predatorStatusPointer->missionmodule==NULL)||(predatorStatusPointer->fearmodule!=old_fearmodule)) { + + /* Recompute mission module. */ + if (predatorStatusPointer->fearmodule) { + predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->fearmodule,5); + } else { + predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,Player->ObStrategyBlock->containingModule->m_aimodule,5); + } + + } + + { + AIMODULE *targetModule; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + + if (predatorStatusPointer->missionmodule==NULL) { + /* Hey, it'll drop through. */ + return(PRC_Request_Recover); + } + + if (ShowPredoStats) { + PrintDebuggingText("Target Module %s.\n",(*(predatorStatusPointer->missionmodule->m_module_ptrs))->name); + } + + targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,predatorStatusPointer->missionmodule,6,0); + + if (targetModule) { + if (ShowPredoStats) { + PrintDebuggingText("Next Module is %s.\n",(*(targetModule->m_module_ptrs))->name); + } + } else { + if (ShowPredoStats) { + PrintDebuggingText("Next Module is NULL!\n"); + } + } + + if ((targetModule==sbPtr->containingModule->m_aimodule) + || (targetModule==NULL)) { + /* Hey, it'll drop through. */ + return(PRC_Request_Recover); + } + + GLOBALASSERT(targetModule); + + thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); + if (!thisEp) { + LOGDXFMT(("This assert is a busted adjacency!")); + GLOBALASSERT(thisEp); + } + /* If that fired, there's a farped adjacency. */ + + predatorStatusPointer->wanderData.worldPosition=thisEp->position; + predatorStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx; + predatorStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy; + predatorStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz; + + } + + /* ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE_PRED + { + if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(PRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + + NPC_IsObstructed(sbPtr,&(predatorStatusPointer->moveData),&predatorStatusPointer->obstruction,&destructableObject); + if((predatorStatusPointer->obstruction.environment)||(predatorStatusPointer->obstruction.otherCharacter)) + { + return(PRC_Request_Avoidance); + } + if(predatorStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + #if 1 + if(NPC_CannotReachTarget(&(predatorStatusPointer->moveData), &(predatorStatusPointer->wanderData.worldPosition), &velocityDirection)) + { + /* go to avoidance */ + /* no sequence change required */ + + predatorStatusPointer->obstruction.environment=1; + predatorStatusPointer->obstruction.destructableObject=0; + predatorStatusPointer->obstruction.otherCharacter=0; + predatorStatusPointer->obstruction.anySingleObstruction=0; + + return(PRC_Request_Avoidance); + } + #endif + #endif + return(PRC_No_Change); +} + +static void Execute_Dying(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + predStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predStatusPointer); + + /* make sure we're not cloaked... if activating, ignore until fully on */ + if(predStatusPointer->CloakStatus==PCLOAK_On) + { + PredatorCloakOff(predStatusPointer); + Sound_Play(SID_VISION_ON,"d",&sbPtr->DynPtr->Position); + } + + sbPtr->DynPtr->LinImpulse.vx = 0; + sbPtr->DynPtr->LinImpulse.vy = 0; + sbPtr->DynPtr->LinImpulse.vz = 0; + + predStatusPointer->stateTimer -= NormalFrameTime; +} + +/* Patrick 4/7/97 -------------------------------------------------- +Behaviour support functions +---------------------------------------------------------------------*/ +#define PRED_PLASMASPEED 30000 +#define PRED_DISCSPEED 30000 +static void CreateNPCPredatorPlasBolt(VECTORCH *startingPosition, VECTORCH *targetDirection) +{ + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr; + + /* make displayblock with correct shape, etc */ + dPtr = MakeObject(I_BehaviourPredatorEnergyBolt,startingPosition); + if(!dPtr) return; + LOCALASSERT(dPtr->ObStrategyBlock); + + /* add lighting effect */ + AddLightingEffectToObject(dPtr,LFX_ROCKETJET); + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + if(!dynPtr) + { + RemoveBehaviourStrategy(dPtr->ObStrategyBlock); + return; + } + + dPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* give projectile a maximum lifetime */ + dPtr->ObStrategyBlock->SBdataptr = AllocateMem(sizeof(CASTER_BOLT_BEHAV_BLOCK)); + if(!dPtr->ObStrategyBlock->SBdataptr) + { + RemoveBehaviourStrategy(dPtr->ObStrategyBlock); + return; + } + + ((CASTER_BOLT_BEHAV_BLOCK *)dPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED; + ((CASTER_BOLT_BEHAV_BLOCK *)dPtr->ObStrategyBlock->SBdataptr)->damage = TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty]; + ((CASTER_BOLT_BEHAV_BLOCK *)dPtr->ObStrategyBlock->SBdataptr)->blast_radius = 2000; + /* align projectile to launcher */ + dynPtr->Position = *startingPosition; + dynPtr->PrevPosition=dynPtr->Position; + MakeMatrixFromDirection(targetDirection, &(dynPtr->OrientMat)); + dynPtr->PrevOrientMat = dynPtr->OrientMat; /* stops mis-alignment if dynamics problem */ + + /* set velocity */ + dynPtr->LinVelocity.vx = MUL_FIXED(targetDirection->vx,PRED_PLASMASPEED); + dynPtr->LinVelocity.vy = MUL_FIXED(targetDirection->vy,PRED_PLASMASPEED); + dynPtr->LinVelocity.vz = MUL_FIXED(targetDirection->vz,PRED_PLASMASPEED); +} + +static void CreateNPCPredatorDisc(VECTORCH *startingPosition, VECTORCH *targetDirection) +{ + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr; + + /* make displayblock with correct shape, etc */ + dPtr = MakeObject(I_BehaviourNPCPredatorDisc,startingPosition); + if(!dPtr) return; + LOCALASSERT(dPtr->ObStrategyBlock); + + /* add lighting effect */ + dPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + if(!dynPtr) + { + RemoveBehaviourStrategy(dPtr->ObStrategyBlock); + return; + } + + dPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* give projectile a maximum lifetime */ + dPtr->ObStrategyBlock->SBdataptr = AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK)); + if(!dPtr->ObStrategyBlock->SBdataptr) + { + RemoveBehaviourStrategy(dPtr->ObStrategyBlock); + return; + } + + ((ONE_SHOT_BEHAV_BLOCK *)dPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED; + /* align projectile to launcher */ + dynPtr->Position = *startingPosition; + MakeMatrixFromDirection(targetDirection, &(dynPtr->OrientMat)); + dynPtr->PrevOrientMat = dynPtr->OrientMat; /* stops mis-alignment if dynamics problem */ + + /* set velocity */ + dynPtr->LinVelocity.vx = MUL_FIXED(targetDirection->vx,PRED_DISCSPEED); + dynPtr->LinVelocity.vy = MUL_FIXED(targetDirection->vy,PRED_DISCSPEED); + dynPtr->LinVelocity.vz = MUL_FIXED(targetDirection->vz,PRED_DISCSPEED); +} + +static void SetPredatorAnimationSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweening) +{ + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + GLOBALASSERT(length!=0); + + if (tweening<=0) { + InitHModelSequence(&predatorStatusPointer->HModelController,(int)type,subtype,length); + } else { + InitHModelTweening(&predatorStatusPointer->HModelController, tweening, (int)type,subtype,length, 1); + } +} + +static int PredatorShouldAttackPlayer(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + predStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predStatusPointer); + + if(predStatusPointer->health > predatorCV[predStatusPointer->personalNumber].defenceHealth) + return 1; + else + return 0; +} + +static int PredatorShouldBeCrawling(STRATEGYBLOCK *sbPtr) +{ + if(sbPtr->containingModule->m_flags & MODULEFLAG_AIRDUCT) return 1; + return 0; +} + +/* Patrick 21/8/97 ---------------------------------------------------- +Predator cloak interface functions... +-----------------------------------------------------------------------*/ +static void InitPredatorCloak(PREDATOR_STATUS_BLOCK *predStatus) +{ + predStatus->CloakStatus = PCLOAK_Off; + predStatus->CloakingEffectiveness = 0; + predStatus->CloakTimer = 0; +} + +static void PredatorCloakOn(PREDATOR_STATUS_BLOCK *predStatus) +{ + LOCALASSERT(predStatus); + + #if 0 + /* Temp! */ + return; + #else + if (predStatus->CloakStatus==PCLOAK_On) { + return; + } else if (predStatus->CloakStatus==PCLOAK_Deactivating) { + /* Don't reset timer. */ + predStatus->CloakStatus = PCLOAK_Activating; + return; + } else if (predStatus->CloakStatus==PCLOAK_Activating) { + /* Okay, okay! */ + return; + } else { + /* Cloak ust be Off. */ + predStatus->CloakStatus = PCLOAK_Activating; + predStatus->CloakTimer = ONE_FIXED-1; + } + #endif +} + +static void PredatorCloakOff(PREDATOR_STATUS_BLOCK *predStatus) +{ + LOCALASSERT(predStatus); + + if (predStatus->CloakStatus==PCLOAK_Off) { + return; + } else if (predStatus->CloakStatus==PCLOAK_Activating) { + /* Don't reset timer. */ + predStatus->CloakStatus = PCLOAK_Deactivating; + return; + } else if (predStatus->CloakStatus==PCLOAK_Deactivating) { + /* Okay, okay! */ + return; + } else { + /* Cloak must be On. */ + predStatus->CloakStatus = PCLOAK_Deactivating; + predStatus->CloakTimer = 0; /* Was predStatus->PredShimmer. */ + } +} + + +static void DoPredatorCloak(PREDATOR_STATUS_BLOCK *predStatus,DYNAMICSBLOCK *dynPtr) +{ + LOCALASSERT(predStatus); + switch(predStatus->CloakStatus) + { + case(PCLOAK_Off): + { + /* do nothing */ + break; + } + case(PCLOAK_Activating): + { + predStatus->CloakTimer -= (NormalFrameTime); + if(predStatus->CloakTimer<=0) + { + predStatus->CloakTimer=0; + predStatus->CloakStatus=PCLOAK_On; + } + break; + } + case(PCLOAK_On): + { + break; + } + case(PCLOAK_Deactivating): + { + predStatus->CloakTimer += (NormalFrameTime); + if(predStatus->CloakTimer>=(ONE_FIXED)) + { + predStatus->CloakTimer=0; + predStatus->CloakStatus=PCLOAK_Off; + } + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + + /* KJL - cloaking effectiveness */ + if(predStatus->CloakStatus!=PCLOAK_Off) + { + int maxPossibleEffectiveness; + VECTORCH velocity; + + velocity.vx = dynPtr->Position.vx - dynPtr->PrevPosition.vx; + velocity.vy = dynPtr->Position.vy - dynPtr->PrevPosition.vy; + velocity.vz = dynPtr->Position.vz - dynPtr->PrevPosition.vz; + + maxPossibleEffectiveness = ONE_FIXED - DIV_FIXED(Magnitude(&velocity)*4,NormalFrameTime); + + if (maxPossibleEffectiveness<0) maxPossibleEffectiveness = 0; + + predStatus->CloakingEffectiveness += NormalFrameTime; + if (predStatus->CloakingEffectiveness>maxPossibleEffectiveness) + { + predStatus->CloakingEffectiveness = maxPossibleEffectiveness; + } + } + else + { + predStatus->CloakingEffectiveness -= NormalFrameTime; + if (predStatus->CloakingEffectiveness<0) + { + predStatus->CloakingEffectiveness=0; + } + } +// PrintDebuggingText("cloaking effectiveness %d\n",predStatus->CloakingEffectiveness); + +} + +int NPCPredatorIsCloaked(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* For external calls. */ + + switch(predatorStatusPointer->CloakStatus) + { + case(PCLOAK_Off): + case(PCLOAK_Activating): + case(PCLOAK_Deactivating): + { + return(0); + break; + } + case(PCLOAK_On): + { + return(1); + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + + return(0); +} + +static int PredatorCanSeeTarget(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + int targetIsCloaked; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + if (predatorStatusPointer->Target==NULL) { + /* You can't see nothin. */ + return(0); + } + + /* Predators see... well, anything. */ + + targetIsCloaked=0; + + if (predatorStatusPointer->Target==Player->ObStrategyBlock) { + /* test for player hiding? */ + + } else { + /* Test for NPC aliens hiding? */ + } + + if(!(NPCCanSeeTarget(sbPtr,predatorStatusPointer->Target, 1000000))) { + return(0); + } + + if (targetIsCloaked) { + return(0); + } + + return(1); +} + +static int PredatorCanSeeObject(STRATEGYBLOCK *sbPtr,STRATEGYBLOCK *target) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + int targetIsCloaked; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + if (target==NULL) { + /* You can't see nothin. */ + return(0); + } + + /* Predators see... well, anything. */ + + targetIsCloaked=0; + + if (target==Player->ObStrategyBlock) { + /* test for player hiding? */ + + } else { + /* Test for NPC aliens hiding? */ + } + + if(!(NPCCanSeeTarget(sbPtr,target, 1000000))) { + return(0); + } + + if (targetIsCloaked) { + return(0); + } + + return(1); +} + +static int PredatorIsAwareOfTarget(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + if (predatorStatusPointer->Target==NULL) { + /* You can't see nothin. */ + return(0); + } + + /* Okay, let's cut to the chase. */ + + /* Slightly more restrictive now... */ + if ((IsModuleVisibleFromModule(sbPtr->containingModule, + predatorStatusPointer->Target->containingModule))) { + return(1); + } else { + return(0); + } + + return(1); +} + +void Predator_Enter_Wander_State(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPC_InitWanderData(&(predatorStatusPointer->wanderData)); + InitWaypointManager(&predatorStatusPointer->waypointManager); + predatorStatusPointer->volleySize = 0; + predatorStatusPointer->lastState=predatorStatusPointer->behaviourState; + predatorStatusPointer->behaviourState = PBS_Wandering; + predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME; + predatorStatusPointer->Pred_Laser_On=0; + + #if 0 + if(predatorStatusPointer->IAmCrouched) { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + #endif + +} + +void Predator_Enter_Hunt_State(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPC_InitWanderData(&(predatorStatusPointer->wanderData)); + InitWaypointManager(&predatorStatusPointer->waypointManager); + predatorStatusPointer->volleySize = 0; + predatorStatusPointer->lastState=predatorStatusPointer->behaviourState; + predatorStatusPointer->behaviourState = PBS_Hunting; + predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME; + predatorStatusPointer->Pred_Laser_On=0; + + #if 0 + if(predatorStatusPointer->IAmCrouched) { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + #endif + +} + +void Predator_Enter_Recover_State(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + if (predatorStatusPointer->Selected_Weapon->id!=PNPCW_Medicomp) { + /* Change to it. */ + predatorStatusPointer->ChangeToWeapon=PNPCW_Medicomp; + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPC_InitWanderData(&(predatorStatusPointer->wanderData)); + InitWaypointManager(&predatorStatusPointer->waypointManager); + predatorStatusPointer->volleySize = 0; + predatorStatusPointer->lastState=predatorStatusPointer->behaviourState; + predatorStatusPointer->behaviourState = PBS_SwapWeapon; + predatorStatusPointer->stateTimer = 0; /* Just starting. */ + predatorStatusPointer->Pred_Laser_On=0; + + /* Deal with sequence in a bit. */ + PredatorCloakOff(predatorStatusPointer); + return; + } + + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPC_InitWanderData(&(predatorStatusPointer->wanderData)); + InitWaypointManager(&predatorStatusPointer->waypointManager); + predatorStatusPointer->volleySize = 0; + predatorStatusPointer->lastState=predatorStatusPointer->behaviourState; + predatorStatusPointer->behaviourState = PBS_Recovering; + predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME; + predatorStatusPointer->Pred_Laser_On=0; + + if(predatorStatusPointer->IAmCrouched) { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrouch,PCrSS_Attack_Primary,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorStand,PSSS_Attack_Primary,ONE_FIXED,(ONE_FIXED>>3)); + } + +} + +void Predator_Enter_Withdrawal_State(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPC_InitWanderData(&(predatorStatusPointer->wanderData)); + InitWaypointManager(&predatorStatusPointer->waypointManager); + predatorStatusPointer->volleySize = 0; + predatorStatusPointer->lastState=predatorStatusPointer->behaviourState; + predatorStatusPointer->behaviourState = PBS_Withdrawing; + predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME; + predatorStatusPointer->Pred_Laser_On=0; + + /* Force re-evaluation of priorities. */ + predatorStatusPointer->missionmodule=NULL; + predatorStatusPointer->fearmodule=NULL; + + #if 0 + if(predatorStatusPointer->IAmCrouched) { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + #endif + +} + +void Predator_Enter_Engaged_State(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPC_InitWanderData(&(predatorStatusPointer->wanderData)); + InitWaypointManager(&predatorStatusPointer->waypointManager); + predatorStatusPointer->volleySize = 0; + predatorStatusPointer->lastState=predatorStatusPointer->behaviourState; + predatorStatusPointer->behaviourState = PBS_Engaging; + predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME; + predatorStatusPointer->Pred_Laser_On=0; + + #if 0 + if(predatorStatusPointer->IAmCrouched) { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + #endif + +} + +void Predator_Enter_Attacking_State(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPC_InitWanderData(&(predatorStatusPointer->wanderData)); + InitWaypointManager(&predatorStatusPointer->waypointManager); + predatorStatusPointer->volleySize = 0; + predatorStatusPointer->lastState=predatorStatusPointer->behaviourState; + predatorStatusPointer->behaviourState = PBS_Attacking; + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + predatorStatusPointer->Pred_Laser_On=0; + predatorStatusPointer->internalState=0; + /* Become patient again. */ + predatorStatusPointer->patience=PRED_PATIENCE_TIME; + + if (predatorStatusPointer->Selected_Weapon->id==PNPCW_Wristblade) { + StartWristbladeAttackSequence(sbPtr); + } else if (predatorStatusPointer->Selected_Weapon->id==PNPCW_Staff) { + StartPredStaffAttackSequence(sbPtr); + } else { + if(predatorStatusPointer->IAmCrouched) { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrouch,PCrSS_Attack_Primary,-1,(ONE_FIXED>>3)); + } else { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorStand,PSSS_Attack_Primary,-1,(ONE_FIXED>>3)); + } + } +} + +void Predator_Enter_Avoidance_State(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(predatorStatusPointer->moveData.avoidanceDirn),&predatorStatusPointer->obstruction); + InitWaypointManager(&predatorStatusPointer->waypointManager); + predatorStatusPointer->volleySize = 0; + predatorStatusPointer->lastState=predatorStatusPointer->behaviourState; + predatorStatusPointer->behaviourState = PBS_Avoidance; + predatorStatusPointer->stateTimer = NPC_AVOIDTIME; + predatorStatusPointer->Pred_Laser_On=0; + + /* zero linear velocity in dynamics block */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + #if 0 + if(predatorStatusPointer->IAmCrouched) { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + #endif + +} + +void Predator_Enter_Swapping_State(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* What are we swapping to? */ + if (predatorStatusPointer->ChangeToWeapon==PNPCW_End) { + /* Use default. */ + if (predatorStatusPointer->Selected_Weapon->id==predatorStatusPointer->PrimaryWeapon) { + /* Using primary - change to secondary. */ + predatorStatusPointer->ChangeToWeapon=predatorStatusPointer->SecondaryWeapon; + } else { + /* Using secondary or other - change to primary. */ + predatorStatusPointer->ChangeToWeapon=predatorStatusPointer->PrimaryWeapon; + } + } + + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPC_InitWanderData(&(predatorStatusPointer->wanderData)); + InitWaypointManager(&predatorStatusPointer->waypointManager); + predatorStatusPointer->volleySize = 0; + predatorStatusPointer->lastState=predatorStatusPointer->behaviourState; + predatorStatusPointer->behaviourState = PBS_SwapWeapon; + predatorStatusPointer->stateTimer = 0; /* Just starting. */ + predatorStatusPointer->Pred_Laser_On=0; + predatorStatusPointer->patience=PRED_PATIENCE_TIME; + + predatorStatusPointer->enableSwap=0; + + /* Deal with sequence in a bit. */ + PredatorCloakOff(predatorStatusPointer); +} + +void Predator_Enter_Return_State(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + GLOBALASSERT(predatorStatusPointer->path!=-1); + GLOBALASSERT(predatorStatusPointer->stepnumber!=-1); + + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPC_InitWanderData(&(predatorStatusPointer->wanderData)); + InitWaypointManager(&predatorStatusPointer->waypointManager); + predatorStatusPointer->volleySize = 0; + predatorStatusPointer->lastState=predatorStatusPointer->behaviourState; + predatorStatusPointer->behaviourState = PBS_Returning; + predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME; + predatorStatusPointer->Pred_Laser_On=0; + + #if 0 + if(predatorStatusPointer->IAmCrouched) { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + #endif + +} + +void Predator_Enter_Pathfinder_State(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + GLOBALASSERT(predatorStatusPointer->path!=-1); + GLOBALASSERT(predatorStatusPointer->stepnumber!=-1); + + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPC_InitWanderData(&(predatorStatusPointer->wanderData)); + InitWaypointManager(&predatorStatusPointer->waypointManager); + predatorStatusPointer->volleySize = 0; + predatorStatusPointer->lastState=predatorStatusPointer->behaviourState; + predatorStatusPointer->behaviourState = PBS_Pathfinding; + predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME; + predatorStatusPointer->Pred_Laser_On=0; + + #if 0 + if(predatorStatusPointer->IAmCrouched) { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } else { + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); + } + #endif + +} + +void Predator_Enter_Taunt_State(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + if (HModelSequence_Exists(&predatorStatusPointer->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_Taunt_One)) { + + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(predatorStatusPointer->moveData.avoidanceDirn),&predatorStatusPointer->obstruction); + InitWaypointManager(&predatorStatusPointer->waypointManager); + predatorStatusPointer->volleySize = 0; + predatorStatusPointer->lastState=predatorStatusPointer->behaviourState; + predatorStatusPointer->behaviourState = PBS_Taunting; + predatorStatusPointer->stateTimer = NPC_AVOIDTIME; + predatorStatusPointer->Pred_Laser_On=0; + /* Become patient again. */ + predatorStatusPointer->patience=PRED_PATIENCE_TIME; + predatorStatusPointer->enableTaunt=0; + + SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorStand,PSSS_Taunt_One,-1,(ONE_FIXED>>3)); + predatorStatusPointer->HModelController.LoopAfterTweening=0; + + #if 0 + Sound_Play(SID_PRED_NEWROAR,"d",&sbPtr->DynPtr->Position); + #else + DoPredatorTauntSound(sbPtr); + #endif + + } else { + /* Yuck. */ + Predator_Enter_Engaged_State(sbPtr); + } + +} + +void Predator_Enter_SelfDestruct_State(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + SECTION *root; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* Switch to template. */ + root=GetNamedHierarchyFromLibrary("hnpcpredator","Template"); + GLOBALASSERT(root); + RemoveAllDeltas(&predatorStatusPointer->HModelController); + /* Set 'new' sequence. */ + predatorStatusPointer->HModelController.Sequence_Type=HMSQT_PredatorCrouch; + predatorStatusPointer->HModelController.Sub_Sequence=PCrSS_Det_Prog; + Transmogrify_HModels(sbPtr,&predatorStatusPointer->HModelController,root, 1, 0,0); + ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr); + + InitHModelTweening(&predatorStatusPointer->HModelController, (ONE_FIXED>>3), + HMSQT_PredatorCrouch,PCrSS_Det_Prog,-1,0); + + /* Init stats. */ + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPC_InitWanderData(&(predatorStatusPointer->wanderData)); + InitWaypointManager(&predatorStatusPointer->waypointManager); + predatorStatusPointer->volleySize = 0; + predatorStatusPointer->lastState=predatorStatusPointer->behaviourState; + predatorStatusPointer->behaviourState = PBS_SelfDestruct; + predatorStatusPointer->stateTimer = 0; + predatorStatusPointer->Pred_Laser_On=0; + predatorStatusPointer->internalState=0; /* Not yet primed. */ + predatorStatusPointer->IAmCrouched = 1; + +} + +void Predator_SwitchState(STRATEGYBLOCK *sbPtr,PRED_RETURN_CONDITION state_result) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + switch (state_result) { + case (PRC_No_Change): + { + /* No action. */ + break; + } + case (PRC_Request_Engage): + { + Predator_Enter_Engaged_State(sbPtr); + break; + } + case (PRC_Request_Attack): + { + Predator_Enter_Attacking_State(sbPtr); + break; + } + case (PRC_Request_Wander): + { + if ((predatorStatusPointer->path!=-1)&& + (predatorStatusPointer->stepnumber!=-1)) { + /* Pathfinding mission. */ + if ((predatorStatusPointer->behaviourState==PBS_Returning) + ||(predatorStatusPointer->behaviourState==PBS_Pathfinding)) { + /* A real order. */ + Predator_Enter_Wander_State(sbPtr); + } else { + /* Pathfind instead. */ + Predator_Enter_Pathfinder_State(sbPtr); + } + } else { + Predator_Enter_Wander_State(sbPtr); + } + break; + } + case (PRC_Request_Avoidance): + { + Predator_Enter_Avoidance_State(sbPtr); + break; + } + case (PRC_Request_Hunt): + { + Predator_Enter_Hunt_State(sbPtr); + break; + } + case (PRC_Request_Withdraw): + { + Predator_Enter_Withdrawal_State(sbPtr); + break; + } + case (PRC_Request_Recover): + { + Predator_Enter_Recover_State(sbPtr); + break; + } + case (PRC_Request_Swap): + { + Predator_Enter_Swapping_State(sbPtr); + break; + } + case (PRC_Request_Pathfind): + { + Predator_Enter_Pathfinder_State(sbPtr); + break; + } + case (PRC_Request_Return): + { + Predator_Enter_Return_State(sbPtr); + break; + } + case (PRC_Request_Taunt): + { + Predator_Enter_Taunt_State(sbPtr); + break; + } + default: + { + /* No action? */ + break; + } + +} + +} + +int Predator_TargetFilter(STRATEGYBLOCK *candidate) { + + switch (candidate->I_SBtype) { + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + { + if (Observer) { + return(0); + } + + switch(AvP.PlayerType) + { + case I_Alien: + case I_Marine: + return(1); + break; + case I_Predator: + /* Just this once. */ + return(0); + break; + default: + GLOBALASSERT(0); + return(0); + break; + } + break; + } + case I_BehaviourDummy: + { + DUMMY_STATUS_BLOCK *dummyStatusPointer; + dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(candidate->SBdataptr); + LOCALASSERT(dummyStatusPointer); + switch (dummyStatusPointer->PlayerType) { + case I_Marine: + case I_Alien: + return(1); + break; + case I_Predator: + return(0); + break; + default: + GLOBALASSERT(0); + return(0); + break; + } + break; + } + case I_BehaviourAlien: + { + ALIEN_STATUS_BLOCK *alienStatusPointer; + LOCALASSERT(candidate); + LOCALASSERT(candidate->DynPtr); + + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(candidate->SBdataptr); + + if (NPC_IsDead(candidate)) { + return(0); + } else { + return(1); + } + break; + } + case I_BehaviourAutoGun: + if (NPC_IsDead(candidate)) { + return(0); + } else { + AUTOGUN_STATUS_BLOCK *autogunStatusPointer; + autogunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(candidate->SBdataptr); + LOCALASSERT(autogunStatusPointer); + + if (autogunStatusPointer->behaviourState==I_inactive) { + return(0); + } else { + return(1); + } + } + break; + case I_BehaviourQueenAlien: + case I_BehaviourFaceHugger: + case I_BehaviourMarine: + case I_BehaviourXenoborg: + case I_BehaviourSeal: + case I_BehaviourPredatorAlien: + /* Valid. */ + return(1); + break; + case I_BehaviourPredator: + #if ANARCHY + return(1); + #else + return(0); + #endif + break; + #if SupportWindows95 + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *dataptr; + dataptr=candidate->SBdataptr; + switch (dataptr->type) { + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + //return(1); + return(0); + break; + default: + return(0); + break; + } + } + break; + #endif + default: + return(0); + break; + } + +} + + +STRATEGYBLOCK *Predator_GetNewTarget(STRATEGYBLOCK *sbPtr) { + + #if 0 + /* Here's the simple one, for testing purposes. */ + return(Player->ObStrategyBlock); + #else + + int neardist, newblip; + STRATEGYBLOCK *nearest; + + int a; + STRATEGYBLOCK *candidate; + MODULE *dmod; + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + int dist; + VECTORCH offset; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + dmod=ModuleFromPosition(&sbPtr->DynPtr->Position,playerPherModule); + + LOCALASSERT(dmod); + + nearest=NULL; + neardist=ONE_FIXED; + newblip=0; + + for (a=0; aDynPtr) { + /* Arc reject. */ + MATRIXCH WtoL; + + offset.vx=sbPtr->DynPtr->Position.vx-candidate->DynPtr->Position.vx; + offset.vy=sbPtr->DynPtr->Position.vy-candidate->DynPtr->Position.vy; + offset.vz=sbPtr->DynPtr->Position.vz-candidate->DynPtr->Position.vz; + + WtoL=sbPtr->DynPtr->OrientMat; + TransposeMatrixCH(&WtoL); + RotateVector(&offset,&WtoL); + + if (offset.vz<=0) { + + if (Predator_TargetFilter(candidate)) { + + dist=Approximate3dMagnitude(&offset); + + if (distSBdptr) { + /* Near case. */ + if (!NPC_IsDead(candidate)) { + if ((PredatorCanSeeObject(sbPtr,candidate))) { + nearest=candidate; + neardist=dist; + } + } + } else { + if (!NPC_IsDead(candidate)) { + if ((IsModuleVisibleFromModule(dmod,candidate->containingModule))) { + nearest=candidate; + neardist=dist; + } + } + } + } + } + } + } + } + } + + return(nearest); + #endif + +} + +int DoPredatorLaserTargeting(STRATEGYBLOCK *sbPtr) { + + int i,hits; + MATRIXCH matrix; + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + SECTION_DATA *plasma_muzzle; + VECTORCH offset[3] = + { + {0,-50,0}, + {43,25,0}, + {-43,25,0}, + }; + STRATEGYBLOCK *laserhits[3]; + STRATEGYBLOCK *consensus; + VECTORCH z_vec; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + predatorStatusPointer->Pred_Laser_On=0; + /* Reset it at the end! */ + + plasma_muzzle=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"dum flash"); + if (plasma_muzzle==NULL) { + return(0); + } + + matrix = plasma_muzzle->SecMat; + + z_vec.vx=matrix.mat31; + z_vec.vy=matrix.mat32; + z_vec.vz=matrix.mat33; + + TransposeMatrixCH(&matrix); + + predatorStatusPointer->Pred_Laser_Sight.LightSource=plasma_muzzle->World_Offset; + predatorStatusPointer->Pred_Laser_Sight.DotIsOnPlayer=0; + + i=2; + hits=0; + + do { + VECTORCH position = offset[i]; + + RotateVector(&position,&matrix); + position.vx += plasma_muzzle->World_Offset.vx; + position.vy += plasma_muzzle->World_Offset.vy; + position.vz += plasma_muzzle->World_Offset.vz; + FindPolygonInLineOfSight(&z_vec, &position, 0,sbPtr->SBdptr); + + predatorStatusPointer->Pred_Laser_Sight.Normal[i] = LOS_ObjectNormal; + predatorStatusPointer->Pred_Laser_Sight.Position[i] = LOS_Point; + + if (LOS_ObjectHitPtr==Player) { + predatorStatusPointer->Pred_Laser_Sight.DotIsOnPlayer=1; + } + + if (LOS_ObjectHitPtr) { + laserhits[i]=LOS_ObjectHitPtr->ObStrategyBlock; + } else { + laserhits[i]=NULL; + } + + if (laserhits[i]) { + hits++; + } + } while(i--); + + /* Now, what have we hit? */ + + consensus=NULL; + + switch (hits) { + case 0: + default: + consensus=NULL; + break; + case 1: + i=2; + do { + if (laserhits[i]!=NULL) { + consensus=laserhits[i]; + } + } while (i--); + break; + case 2: + i=2; + do { + if (laserhits[i]!=NULL) { + if (consensus==NULL) { + consensus=laserhits[i]; + } else { + if (laserhits[i]!=consensus) { + consensus=NULL; + } + } + } + } while (i--); + break; + case 3: + if ((laserhits[0]==laserhits[1])||(laserhits[0]==laserhits[2])) { + consensus=laserhits[0]; + } else if (laserhits[1]==laserhits[2]) { + consensus=laserhits[1]; + } else { + consensus=NULL; + } + break; + } + + predatorStatusPointer->Pred_Laser_On=1; + + if (predatorStatusPointer->Target==NULL) { + return(0); + } + + if (consensus==predatorStatusPointer->Target) { + return(1); + } else { + return(0); + } + +} + +static PRED_RETURN_CONDITION Execute_PNS_EngageWithStaff(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + VECTORCH velocityDirection = {0,0,0}; + VECTORCH targetPosition; + int targetIsAirduct = 0; + int range; + + /* Same as wristblade version. */ + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + PredatorHandleMovingAnimation(sbPtr); + + predatorStatusPointer->patience-=NormalFrameTime; + /* Have we become impatient? */ + if (predatorStatusPointer->patience<=0) { + return(PRC_Request_Swap); + } + + /* now check for state changes... firstly, if we can no longer attack the target, go + to wander */ + if(!(PredatorIsAwareOfTarget(sbPtr))) + { + return(PRC_Request_Hunt); + /* Drop out null targets. */ + } else { + + /* We have a target that we are aware of. */ + + range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + /* Wanna Cloak? */ + if (range<10000) { + /* Decloak when close. */ + PredatorCloakOff(predatorStatusPointer); + } else if (predatorStatusPointer->CloakStatus==PCLOAK_Off) { + PredatorCloakOn(predatorStatusPointer); + } + + /* if we are close... go directly to firing */ + if(range < PRED_STAFF_ATTACK_RANGE) + { + /* switch directly to firing, at this distance */ + + return(PRC_Request_Attack); + } + + /* if our state timer has run out in approach state, see if we can fire*/ + if(predatorStatusPointer->stateTimer > 0) { + predatorStatusPointer->stateTimer -= NormalFrameTime; + } + + if(predatorStatusPointer->stateTimer <= 0) + { + /* A moment of decision... */ + /* Might want to withdraw. */ + if(!PredatorCanSeeTarget(sbPtr)) + { + /* Lost sight of him! */ + + return(PRC_Request_Hunt); + } + else + { + /* renew approach state */ + predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; + /* Whatever. */ + } + } + } + + /* See which way we want to go. */ + { + + AIMODULE *targetModule; + MODULE *tcm; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + + GLOBALASSERT(predatorStatusPointer->Target!=NULL); + + if (predatorStatusPointer->Target->containingModule) { + tcm=predatorStatusPointer->Target->containingModule; + } else { + tcm=ModuleFromPosition(&predatorStatusPointer->Target->DynPtr->Position,sbPtr->containingModule); + } + + if (tcm) { + targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,tcm->m_aimodule,7,0); + } else { + targetModule=NULL; + } + + if (targetModule==sbPtr->containingModule->m_aimodule) { + /* Try going for it, we still can't see them. */ + NPCGetMovementTarget(sbPtr, predatorStatusPointer->Target, &targetPosition, &targetIsAirduct,0); + NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&predatorStatusPointer->waypointManager); + } else if (!targetModule) { + /* Must be inaccessible. */ + if (ShowPredoStats) { + if (predatorStatusPointer->Target->containingModule) { + PrintDebuggingText("I can see you, but I can't get there!\n"); + } else { + PrintDebuggingText("Hey, you've got no Containing Module!\n"); + } + } + return(PRC_No_Change); + } else { + + thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); + if (!thisEp) { + LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.", + (*(targetModule->m_module_ptrs))->name, + sbPtr->containingModule->name)); + GLOBALASSERT(thisEp); + } + + /* If that fired, there's a farped adjacency. */ + predatorStatusPointer->wanderData.worldPosition=thisEp->position; + predatorStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx; + predatorStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy; + predatorStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz; + + NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager); + } + + } + + /* Should have a velocity set now. */ + NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) + { + /* Go to all new avoidance. */ + return(PRC_Request_Avoidance); + } + + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_AttackWithStaff(STRATEGYBLOCK *sbPtr) +{ + VECTORCH orientationDirn; + int i; + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + LOCALASSERT (sbPtr->DynPtr); + + /* zero linear velocity in dynamics block */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + dynPtr = sbPtr->DynPtr; + + if (predatorStatusPointer->Target==NULL) { + /* Bomb out. */ + return(PRC_Request_Wander); + } + + /* De-cloak. */ + if(predatorStatusPointer->CloakStatus==PCLOAK_On) + { + PredatorCloakOff(predatorStatusPointer); + } + + GLOBALASSERT(predatorStatusPointer->Target); + NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target); + + /* check for state changes: */ + if(VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)) > PRED_STAFF_ATTACK_RANGE) + { + if (((FastRandom()&65535)>40000)&&(predatorStatusPointer->enableSwap)) { + /* Quite like the staff. */ + return(PRC_Request_Swap); + } else { + /* switch back to engage. */ + GLOBALASSERT(predatorStatusPointer->Target); + NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target); + return(PRC_Request_Engage); + } + } + + /* Orientate towards player, just to make sure we're facing */ + orientationDirn.vx = predatorStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = predatorStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; + /* Fudge? */ + orientationDirn.vx+=(predatorStatusPointer->Target->DynPtr->OrientMat.mat11>>8); + orientationDirn.vz+=(predatorStatusPointer->Target->DynPtr->OrientMat.mat13>>8); + i = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* Decrement the near state timer */ + predatorStatusPointer->stateTimer -= NormalFrameTime; + + PredatorNearDamageShell(sbPtr); + + #if 0 + /* Staff damage. */ + { + SECTION_DATA *tip1,*mid,*tip2; + + tip1=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"staff a blade"); + mid=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"staff center"); + tip2=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"staff b blade"); + + GLOBALASSERT(tip1); + GLOBALASSERT(mid); + GLOBALASSERT(tip2); + + Staff_Manager(&TemplateAmmo[AMMO_NPC_PRED_STAFF].MaxDamage[AvP.Difficulty],tip1,mid,tip2,sbPtr); + + } + #endif + + if (predatorStatusPointer->HModelController.keyframe_flags&1) { + + //predatorStatusPointer->enableSwap=1; + StartPredStaffAttackSequence(sbPtr); + predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME; + /* Shrug. */ + } + + return(PRC_No_Change); + +} + +static PRED_RETURN_CONDITION Execute_PFS_Pathfinder(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + AIMODULE *targetModule = 0; + int nextModuleIndex; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* Okay, so you're a LocalGuard or Pathfinder who's gotten lost. */ + + /* Decrement the Far state timer */ + predatorStatusPointer->stateTimer -= NormalFrameTime; + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(predatorStatusPointer->stateTimer > 0) return(PRC_No_Change); + + /* check for state changes */ + if(PredatorIsAwareOfTarget(sbPtr)) + /* Hack! */ + { + /* we should be engaging */ + return(PRC_Request_Engage); + } + + /* Ignore alerts. */ + + /* Never break out of pathfinder unless your life is in danger! */ + + /* Okay, so where are we exactly? */ + + if ((predatorStatusPointer->stepnumber<0)||(predatorStatusPointer->path<0)) { + /* Get OUT! */ + return(PRC_Request_Wander); + } + + targetModule = TranslatePathIndex(predatorStatusPointer->stepnumber,predatorStatusPointer->path); + + if (targetModule==NULL) { + /* Oh, to heck with this. Try to wander. */ + return(PRC_Request_Wander); + } + + /* Right, so there is a somewhere to get to. */ + + if (targetModule!=sbPtr->containingModule->m_aimodule) { + /* But we're nowhere near it. Geeze... */ + predatorStatusPointer->missionmodule=targetModule; + return(PRC_Request_Return); + } + + /* Okay, so now we need to know where to go now. */ + + nextModuleIndex=GetNextModuleInPath(predatorStatusPointer->stepnumber,predatorStatusPointer->path); + GLOBALASSERT(nextModuleIndex>=0); + /* If that fires, it's Richard's fault. */ + targetModule=TranslatePathIndex(nextModuleIndex,predatorStatusPointer->path); + GLOBALASSERT(targetModule); + /* Ditto. */ + predatorStatusPointer->stepnumber=nextModuleIndex; + + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + ProcessFarPredatorTargetAIModule(sbPtr, targetModule); + /* reset timer */ + predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_Pathfinder(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + DYNAMICSBLOCK *dynPtr; + AIMODULE *targetModule; + VECTORCH velocityDirection = {0,0,0}; + + LOCALASSERT(sbPtr); + predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(predatorStatusPointer); + LOCALASSERT(dynPtr); + + PredatorHandleMovingAnimation(sbPtr); + + /* should we change to approach state? */ + if(PredatorIsAwareOfTarget(sbPtr)) + { + /* doesn't require a sequence change */ + return(PRC_Request_Engage); + } + + predatorStatusPointer->stateTimer-=NormalFrameTime; + + if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + } + if ((predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + ||(predatorStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_aimodule->m_index)) { + + FARENTRYPOINT *thisEp; + int nextModuleIndex; + /* Okay, so where are we exactly? */ + + if ((predatorStatusPointer->stepnumber<0)||(predatorStatusPointer->path<0)) { + /* Get OUT! */ + return(PRC_Request_Wander); + } + + targetModule = TranslatePathIndex(predatorStatusPointer->stepnumber,predatorStatusPointer->path); + + if (targetModule==NULL) { + /* Oh, to heck with this. Try to wander. */ + return(PRC_Request_Wander); + } + + /* Right, so there is a somewhere to get to. */ + + if (targetModule!=sbPtr->containingModule->m_aimodule) { + /* But we're nowhere near it. Geeze... */ + predatorStatusPointer->missionmodule=targetModule; + return(PRC_Request_Return); + } + + /* Okay, so now we need to know where to go now. */ + + nextModuleIndex=GetNextModuleInPath(predatorStatusPointer->stepnumber,predatorStatusPointer->path); + GLOBALASSERT(nextModuleIndex>=0); + /* If that fires, it's Richard's fault. */ + targetModule=TranslatePathIndex(nextModuleIndex,predatorStatusPointer->path); + GLOBALASSERT(targetModule); + /* Ditto. */ + predatorStatusPointer->stepnumber=nextModuleIndex; + + thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule); + if(thisEp) { + /* aha. an ep!... */ + VECTORCH thisEpWorld = thisEp->position; + + thisEpWorld.vx += targetModule->m_world.vx; + thisEpWorld.vy += targetModule->m_world.vy; + thisEpWorld.vz += targetModule->m_world.vz; + + predatorStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index; + predatorStatusPointer->wanderData.worldPosition = thisEpWorld; + + } else { + /* Failure case. */ + predatorStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE; + } + + } + + /* if we still haven't got one, wander for a bit. */ + if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPC_FindAIWanderTarget(sbPtr,&(predatorStatusPointer->wanderData),&(predatorStatusPointer->moveData),0); + } + + if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) { + /* STILL broken! Okay, just... wander forever, then. */ + return(PRC_Request_Wander); + } + + /* ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE_PRED + { + if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(PRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_IsObstructed(sbPtr,&(predatorStatusPointer->moveData),&predatorStatusPointer->obstruction,&destructableObject); + if((predatorStatusPointer->obstruction.environment)||(predatorStatusPointer->obstruction.otherCharacter)) + { + /* go to avoidance */ + return(PRC_Request_Avoidance); + } + if(predatorStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(predatorStatusPointer->moveData), &(predatorStatusPointer->wanderData.worldPosition), &velocityDirection)) + { + /* go to avoidance */ + /* no sequence change required */ + + predatorStatusPointer->obstruction.environment=1; + predatorStatusPointer->obstruction.destructableObject=0; + predatorStatusPointer->obstruction.otherCharacter=0; + predatorStatusPointer->obstruction.anySingleObstruction=0; + + return(PRC_Request_Avoidance); + } + #endif + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PFS_Return(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + AIMODULE *targetModule = 0; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* Decrement the Far state timer */ + predatorStatusPointer->stateTimer -= NormalFrameTime; + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(predatorStatusPointer->stateTimer > 0) return(SRC_No_Change); + + /* check for state changes */ + if(PredatorIsAwareOfTarget(sbPtr)) + /* Hack! */ + { + /* we should be engaging */ + return(PRC_Request_Engage); + } + + if (sbPtr->containingModule->m_aimodule==predatorStatusPointer->missionmodule) { + return(PRC_Request_Pathfind); + } + + /* get the target module... */ + + targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,predatorStatusPointer->missionmodule,7,0); + + /* If there is no target module, we're way out there. Better wander a bit more. */ + if(!targetModule) + { + targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr,NULL,0); + } + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + ProcessFarPredatorTargetAIModule(sbPtr, targetModule); + /* reset timer */ + predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_Return(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + DYNAMICSBLOCK *dynPtr; + AIMODULE *targetModule; + VECTORCH velocityDirection = {0,0,0}; + + LOCALASSERT(sbPtr); + predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(predatorStatusPointer); + LOCALASSERT(dynPtr); + + PredatorHandleMovingAnimation(sbPtr); + + /* should we change to approach state? */ + if(PredatorIsAwareOfTarget(sbPtr)) + { + /* doesn't require a sequence change */ + return(PRC_Request_Engage); + } + + predatorStatusPointer->stateTimer-=NormalFrameTime; + + /* Are we there yet? */ + if (sbPtr->containingModule->m_aimodule==predatorStatusPointer->missionmodule) { + return(PRC_Request_Pathfind); + } + + /* Target module aquisition. */ + + LOCALASSERT(sbPtr->containingModule); + + if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + } + if ((predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + ||(predatorStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_aimodule->m_index)) { + + targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,predatorStatusPointer->missionmodule,7,0); + + if (targetModule) { + FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule); + if(thisEp) { + /* aha. an ep!... */ + VECTORCH thisEpWorld = thisEp->position; + + thisEpWorld.vx += targetModule->m_world.vx; + thisEpWorld.vy += targetModule->m_world.vy; + thisEpWorld.vz += targetModule->m_world.vz; + + predatorStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index; + predatorStatusPointer->wanderData.worldPosition = thisEpWorld; + + } else { + /* Failure case. */ + predatorStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE; + } + + } else { + /* Another failure case. */ + predatorStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE; + } + } + + /* if we still haven't got one, bimble about in this one for a bit. */ + if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) + { + NPC_InitMovementData(&(predatorStatusPointer->moveData)); + NPC_FindAIWanderTarget(sbPtr,&(predatorStatusPointer->wanderData),&(predatorStatusPointer->moveData),0); + } + + if(predatorStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) { + /* STILL broken! Okay, just... wander, then. */ + return(PRC_Request_Wander); + } + + /* ok: should have a current target at this stage... */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &(predatorStatusPointer->wanderData.worldPosition),&predatorStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); + + /* test here for impeding collisions, and not being able to reach target... */ + #if ALL_NEW_AVOIDANCE_PRED + { + if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) { + /* Go to all new avoidance. */ + return(PRC_Request_Avoidance); + } + } + #else + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_IsObstructed(sbPtr,&(predatorStatusPointer->moveData),&predatorStatusPointer->obstruction,&destructableObject); + if((predatorStatusPointer->obstruction.environment)||(predatorStatusPointer->obstruction.otherCharacter)) + { + /* go to avoidance */ + return(PRC_Request_Avoidance); + } + if(predatorStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(predatorStatusPointer->moveData), &(predatorStatusPointer->wanderData.worldPosition), &velocityDirection)) + { + /* go to avoidance */ + /* no sequence change required */ + + predatorStatusPointer->obstruction.environment=1; + predatorStatusPointer->obstruction.destructableObject=0; + predatorStatusPointer->obstruction.otherCharacter=0; + predatorStatusPointer->obstruction.anySingleObstruction=0; + + return(PRC_Request_Avoidance); + } + #endif + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_Recover(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + NPC_DATA *NpcData; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* zero linear velocity in dynamics block */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if (!sbPtr->SBdptr) { + /* We're far... do the timer! */ + ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr); + } + + /* Stay where you are and regain health. */ + + NpcData=GetThisNpcData(I_NPC_Predator); + + if (sbPtr->SBDamageBlock.Health>0) { + int health_increment; + + health_increment=DIV_FIXED((NpcData->StartingStats.Health*NormalFrameTime),PRED_REGEN_TIME); + sbPtr->SBDamageBlock.Health+=health_increment; + + if (sbPtr->SBDamageBlock.Health>(NpcData->StartingStats.Health<SBDamageBlock.Health=(NpcData->StartingStats.Health<HModelController,PRED_REGEN_TIME); + } + + /* Are we fully healed? */ + if (sbPtr->SBDamageBlock.Health==(NpcData->StartingStats.Health<SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* zero linear velocity in dynamics block */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + #if 0 + if (predatorStatusPointer->HModelController.keyframe_flags) { + #if 0 + Sound_Play(SID_PRED_NEWROAR,"d",&sbPtr->DynPtr->Position); + #else + DoPredatorTauntSound(sbPtr); + #endif + } + #endif + + if (!sbPtr->SBdptr) { + /* We're far... do the timer! */ + ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr); + } + + if (HModelAnimation_IsFinished(&predatorStatusPointer->HModelController)) { + return(PRC_Request_Engage); + } else { + return(PRC_No_Change); + } + +} + +static PRED_RETURN_CONDITION Execute_PNS_DischargeSpeargun(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + VECTORCH orientationDirn,relPos,relPos2; + int correctlyOrientated,range; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* zero linear velocity in dynamics block */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if (predatorStatusPointer->Target==NULL) { + /* Bomb out. */ + return(PRC_Request_Wander); + } + + /* Always turn to face... */ + GLOBALASSERT(predatorStatusPointer->Target); + NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target); + + /* Fix weapon target! */ + { + predatorStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat21, + 300); + predatorStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat22, + 300); + predatorStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat23, + 300); + } + + /* orientate to firing point first */ + if (predatorStatusPointer->My_Elevation_Section) { + /* Assume range large w.r.t. half shoulder width... */ + orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx; + orientationDirn.vy = 0; + orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz; + } else { + orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + } + /* Target shift? */ + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* Decloaking? */ + if (predatorStatusPointer->CloakStatus==PCLOAK_On) { + PredatorCloakOff(predatorStatusPointer); + } + + /* If still tweening, pause. */ + if (predatorStatusPointer->HModelController.Tweening!=Controller_NoTweening) { + return(PRC_No_Change); + } + + if (predatorStatusPointer->stateTimer==predatorStatusPointer->Selected_Weapon->FiringRate) { + + predatorStatusPointer->HModelController.Playing=0; + + /* Only terminate if you haven't fired yet... */ + if(!PredatorCanSeeTarget(sbPtr)) + { + #if 1 + /* ... and remove the gunflash */ + #endif + + return(PRC_Request_Engage); + } + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing*/ + if((!correctlyOrientated)||(predatorStatusPointer->CloakStatus!=PCLOAK_Off)) + { + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + #endif + return(PRC_No_Change); + } + + /* If you are correctly oriented, you can now fire! */ + + predatorStatusPointer->HModelController.Playing=1; + predatorStatusPointer->HModelController.sequence_timer=0; + + relPos.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vz); + + range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + #if 1 + /* look after the gun flash */ + #endif + + /* look after the sound */ + Sound_Play(SID_PRED_LASER,"d",&(sbPtr->DynPtr->Position)); + + /* Now fire a spear... */ + + { + SECTION_DATA *muzzle; + VECTORCH shotVector; + + muzzle=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"dum flash"); + + shotVector.vx=muzzle->SecMat.mat31; + shotVector.vy=muzzle->SecMat.mat32; + shotVector.vz=muzzle->SecMat.mat33; + + FindPolygonInLineOfSight(&shotVector,&muzzle->World_Offset,0,sbPtr->SBdptr); + + /* Now deal with LOS_ObjectHitPtr. */ + if (LOS_ObjectHitPtr) { + if (LOS_HModel_Section) { + if (LOS_ObjectHitPtr->ObStrategyBlock) { + if (LOS_ObjectHitPtr->ObStrategyBlock->SBdptr) { + GLOBALASSERT(LOS_ObjectHitPtr->ObStrategyBlock->SBdptr->HModelControlBlock==LOS_HModel_Section->my_controller); + } + } + } + HandleSpearImpact(&LOS_Point,LOS_ObjectHitPtr->ObStrategyBlock,AMMO_PRED_RIFLE,&shotVector, 1, LOS_HModel_Section); + } + + predatorStatusPointer->volleySize++; + } + + if (predatorStatusPointer->volleySize>0) { /* Was 3 for pistol. */ + predatorStatusPointer->enableSwap=1; + } + } + + predatorStatusPointer->stateTimer -= NormalFrameTime; + + /* You must have fired already. */ + + if(predatorStatusPointer->stateTimer > 0) { + return(PRC_No_Change); + } + + if(range < predatorStatusPointer->Selected_Weapon->MinRange) + { + /* renew firing, as we are still too close to approach */ + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + predatorStatusPointer->volleySize = 0; + return(PRC_No_Change); + } + else + { + NPC_DATA *NpcData; + /* we are far enough away, so return to approach? */ + + NpcData=GetThisNpcData(I_NPC_Predator); + + if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-1))) + &&(sbPtr->SBDamageBlock.Health>0)) { + /* 50% health? */ + if (General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->Target->containingModule->m_aimodule,5)) { + return(PRC_Request_Withdraw); + } else { + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + return(PRC_No_Change); + } + } + + if (predatorStatusPointer->volleySize>=predatorStatusPointer->Selected_Weapon->VolleySize) { + if (((FastRandom()&65535)>32767)&&(predatorStatusPointer->enableSwap)) { + /* Change weapon! */ + return(PRC_Request_Swap); + } else { + return(PRC_Request_Engage); + } + } else { + /* And another! */ + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + return(PRC_No_Change); + } + } + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_AttackBrutallyWithPlasmaCaster(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + VECTORCH orientationDirn,relPos,relPos2; + int correctlyOrientated,range,onTarget; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* zero linear velocity in dynamics block */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if (predatorStatusPointer->Target==NULL) { + /* Bomb out. */ + return(PRC_Request_Wander); + } + + /* No messing, no taunting, no decloaking. */ + + if (predatorStatusPointer->internalState==0) { + if (predatorStatusPointer->HModelController.Tweening==Controller_NoTweening) { + predatorStatusPointer->HModelController.Playing=0; + } + } + + /* Always turn to face... */ + GLOBALASSERT(predatorStatusPointer->Target); + NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target); + + /* orientate to firing point first */ + if (predatorStatusPointer->My_Elevation_Section) { + /* Assume range large w.r.t. half shoulder width... */ + orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx; + orientationDirn.vy = 0; + orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz; + } else { + orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + } + /* Target shift? */ + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* Cloaking? */ + if (predatorStatusPointer->CloakStatus==PCLOAK_Off) { + /* Stay unfair. */ + PredatorCloakOn(predatorStatusPointer); + } + + /* Project three dots? */ + onTarget=DoPredatorLaserTargeting(sbPtr); + + predatorStatusPointer->stateTimer -= NormalFrameTime; + + /* Only terminate if you haven't fired yet... */ + if(!PredatorCanSeeTarget(sbPtr)) + { + #if 1 + /* ... and remove the gunflash */ + #endif + + return(PRC_Request_Engage); + } + + if (predatorStatusPointer->internalState==1) { + /* Using stateTimer, thanks! */ + } else if(predatorStatusPointer->stateTimer > 0) { + return(PRC_No_Change); + } + + /* State timed out - try to fire! */ + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing*/ + if (!correctlyOrientated) + { + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + #endif + return(PRC_No_Change); + } + + /* Ready to fire... */ + + if (correctlyOrientated&&(predatorStatusPointer->internalState!=2)) { + if (predatorStatusPointer->internalState!=1) { + predatorStatusPointer->internalState=1; + /* Disable pausing... */ + predatorStatusPointer->stateTimer=0; + } + } + + range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + if ((predatorStatusPointer->internalState==1)&&(predatorStatusPointer->stateTimer<=0)) { + if (onTarget) { + + /* If you are correctly oriented, you can now fire! */ + + predatorStatusPointer->enableTaunt=0; + /* No taunting here, we're busy. */ + + predatorStatusPointer->HModelController.Playing=1; + predatorStatusPointer->HModelController.Looped=0; + predatorStatusPointer->HModelController.sequence_timer=0; + predatorStatusPointer->internalState=2; + + relPos.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vz); + + #if 1 + /* look after the gun flash */ + #endif + + /* look after the sound */ + Sound_Play(SID_PRED_LAUNCHER,"d",&(sbPtr->DynPtr->Position)); + + /* Now fire a bolt. */ + + { + SECTION_DATA *muzzle; + + muzzle=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"dum flash"); + + Pred_Weapon_Damage=TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty]; + + Pred_Weapon_Damage.Impact =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Impact ,10000); + Pred_Weapon_Damage.Cutting =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Cutting ,10000); + Pred_Weapon_Damage.Penetrative =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Penetrative,10000); + Pred_Weapon_Damage.Fire =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Fire ,10000); + Pred_Weapon_Damage.Electrical =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Electrical ,10000); + Pred_Weapon_Damage.Acid =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Acid ,10000); + + Pred_Weapon_Damage.BlowUpSections=1; + Pred_Weapon_Damage.Special=0; + + InitialiseEnergyBoltBehaviourKernel(&muzzle->World_Offset, &muzzle->SecMat,0,&Pred_Weapon_Damage,65536); + predatorStatusPointer->volleySize++; + } + predatorStatusPointer->enableSwap=1; + return(SRC_No_Change); + } else { + + /* You think you're correctly orientated - but you're still not hitting. */ + if (predatorStatusPointer->stateTimer<=0) { + /* Oh, just give up. */ + predatorStatusPointer->HModelController.Playing=1; + predatorStatusPointer->HModelController.Looped=0; + predatorStatusPointer->HModelController.sequence_timer=0; + predatorStatusPointer->internalState=2; + } + } + } + + if (predatorStatusPointer->internalState==2) { + + /* After shot. */ + + #if 0 + if (!(HModelAnimation_IsFinished(&predatorStatusPointer->HModelController))) { + /* Still playing. */ + return(PRC_No_Change); + } + #endif + + if(range < predatorStatusPointer->Selected_Weapon->MinRange) + { + /* renew firing, as we are still too close to approach */ + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + predatorStatusPointer->volleySize = 0; + predatorStatusPointer->internalState=0; + return(PRC_No_Change); + } + else + { + NPC_DATA *NpcData; + /* we are far enough away, so return to approach? */ + + NpcData=GetThisNpcData(I_NPC_Predator); + + if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-1))) + &&(sbPtr->SBDamageBlock.Health>0)) { + /* 50% health? */ + if (General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->Target->containingModule->m_aimodule,5)) { + return(PRC_Request_Withdraw); + } else { + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + predatorStatusPointer->internalState=0; + return(PRC_No_Change); + } + } + + if (predatorStatusPointer->volleySize>=predatorStatusPointer->Selected_Weapon->VolleySize) { + if (rangestateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + predatorStatusPointer->internalState=0; + return(PRC_No_Change); + #endif + } + } else { + /* And another! */ + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + predatorStatusPointer->internalState=0; + return(PRC_No_Change); + } + } + + } + + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Predator_ThreatAnalysis(STRATEGYBLOCK *sbPtr) { + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* A bit of an experimental function. */ + if (predatorStatusPointer->Target==NULL) { + /* There ain't no threat! */ + NPC_DATA *NpcData; + + NpcData=GetThisNpcData(I_NPC_Predator); + + if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-1))) + &&(sbPtr->SBDamageBlock.Health>0)) { + /* 50% health? */ + return(PRC_Request_Withdraw); + } else { + return(PRC_Request_Wander); + } + } + + GLOBALASSERT(predatorStatusPointer->Target); + /* Now, what manner of threat do we face? */ + + /* Frankly, this needs discussing before I do anything major. */ + + return(PRC_Request_Swap); + +} + +static PRED_RETURN_CONDITION Execute_PNS_NewDischargePistol(STRATEGYBLOCK *sbPtr) +{ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + VECTORCH orientationDirn,relPos,relPos2; + int correctlyOrientated,range; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* zero linear velocity in dynamics block */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if (predatorStatusPointer->Target==NULL) { + /* Bomb out. */ + return(PRC_Request_Wander); + } + + /* Always turn to face... */ + GLOBALASSERT(predatorStatusPointer->Target); + NPCGetTargetPosition(&(predatorStatusPointer->weaponTarget),predatorStatusPointer->Target); + + /* Fix weapon target! */ + { + predatorStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, + 200); + predatorStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, + 200); + predatorStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, + 200); + } + + /* orientate to firing point first */ + if (predatorStatusPointer->My_Elevation_Section) { + /* Assume range large w.r.t. half shoulder width... */ + orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx; + orientationDirn.vy = 0; + orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz; + } else { + orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; + } + /* Target shift? */ + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL); + + /* Decloaking? */ + if (predatorStatusPointer->CloakStatus==PCLOAK_On) { + PredatorCloakOff(predatorStatusPointer); + } + + /* If still tweening, pause. */ + if (predatorStatusPointer->HModelController.Tweening!=Controller_NoTweening) { + return(PRC_No_Change); + } + + //if (predatorStatusPointer->stateTimer==predatorStatusPointer->Selected_Weapon->FiringRate) + { + + //predatorStatusPointer->HModelController.Playing=0; + + /* Only terminate if you haven't fired yet... */ + if(!PredatorCanSeeTarget(sbPtr)) + { + #if 1 + /* ... and remove the gunflash */ + #endif + + return(PRC_Request_Engage); + } + + /* we are not correctly orientated to the target: this could happen because we have + just entered this state, or the target has moved during firing*/ + if((!correctlyOrientated)||(predatorStatusPointer->CloakStatus!=PCLOAK_Off)) + { + #if 1 + /* stop visual and audio cues: technically, we're not firing at this moment */ + #endif + return(PRC_No_Change); + } + + /* If you are correctly oriented, you can now fire! */ + + //predatorStatusPointer->HModelController.Playing=1; + //predatorStatusPointer->HModelController.sequence_timer=0; + + relPos.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx); + relPos.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy); + relPos.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz); + + relPos2.vx=(predatorStatusPointer->Target->DynPtr->Position.vx)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vx); + relPos2.vy=(predatorStatusPointer->Target->DynPtr->Position.vy)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vy); + relPos2.vz=(predatorStatusPointer->Target->DynPtr->Position.vz)-(predatorStatusPointer->Target->DynPtr->PrevPosition.vz); + + range=VectorDistance((&predatorStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + #if 1 + /* look after the gun flash */ + #endif + + /* look after the sound */ + Sound_Play(SID_PRED_PISTOL,"d",&(sbPtr->DynPtr->Position)); + + /* Now fire a volley... */ + + { + SECTION_DATA *muzzle; + VECTORCH null_vec; + + muzzle=GetThisSectionData(predatorStatusPointer->HModelController.section_data,"dum flash"); + + null_vec.vx=0; + null_vec.vy=0; + null_vec.vz=0; + + GLOBALASSERT(muzzle); + + FirePredPistolFlechettes(&muzzle->World_Offset,&null_vec,&muzzle->SecMat,0,&predatorStatusPointer->internalState,TRUE); + + } + + //if (predatorStatusPointer->volleySize>3) { + // predatorStatusPointer->enableSwap=1; + //} + } + + predatorStatusPointer->stateTimer -= NormalFrameTime; + + /* Alex: I changed this 28/01/99 - it makes the Predator a bit easier, but also + a bit more interesting - it hopefully makes the end of Earthbound a bit more fun. */ + if(range < predatorStatusPointer->Selected_Weapon->MinRange) + { + predatorStatusPointer->enableSwap=1; + return(PRC_Request_Swap); + } + + /* You must have fired already. */ + + if(predatorStatusPointer->stateTimer > 0) { + return(PRC_No_Change); + } + + /* Enable swap after a full burst. */ +// predatorStatusPointer->enableSwap=1; + + #if 0 + { + /* renew firing, as we are still too close to approach */ + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + predatorStatusPointer->volleySize = 0; + return(PRC_No_Change); + } + else + { + NPC_DATA *NpcData; + /* we are far enough away, so return to approach? */ + + NpcData=GetThisNpcData(I_NPC_Predator); + + if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-1))) + &&(sbPtr->SBDamageBlock.Health>0)) { + /* 50% health? */ + if (General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->Target->containingModule->m_aimodule,5)) { + return(PRC_Request_Withdraw); + } else { + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + return(PRC_No_Change); + } + } + + if (predatorStatusPointer->volleySize>=predatorStatusPointer->Selected_Weapon->VolleySize) { + if (((FastRandom()&65535)>32767)&&(predatorStatusPointer->enableSwap)) { + /* Change weapon! */ + return(PRC_Request_Swap); + } else { + return(PRC_Request_Engage); + } + } else { + /* And another! */ + predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; + return(PRC_No_Change); + } + } + #endif + return(PRC_No_Change); +} + +static PRED_RETURN_CONDITION Execute_PNS_SelfDestruct(STRATEGYBLOCK *sbPtr) +{ + + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + /* zero linear velocity in dynamics block */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if (!sbPtr->SBdptr) { + /* We're far... do the timer! */ + ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr); + } + + if (predatorStatusPointer->HModelController.Sub_Sequence==PCrSS_Det_Prog) { + if (HModelAnimation_IsFinished(&predatorStatusPointer->HModelController)) { + InitHModelTweening(&predatorStatusPointer->HModelController,(ONE_FIXED>>2), + HMSQT_PredatorCrouch,PCrSS_Det_Laugh,-1,1); + } + } + + /* And if we're playing Laugh, we'd better laugh... */ + + if (predatorStatusPointer->internalState==0) { + /* Not yet activated. */ + if (predatorStatusPointer->HModelController.keyframe_flags&1) { + predatorStatusPointer->stateTimer=PRED_SELF_DESTRUCT_TIMER; + predatorStatusPointer->internalState=1; + } + } else if (predatorStatusPointer->internalState==1) { + predatorStatusPointer->stateTimer-=NormalFrameTime; + if (predatorStatusPointer->stateTimer<=0) { + /* Kaboom. */ + predatorStatusPointer->internalState=2; + /* And kill the pred, for good measure? */ + #if 0 + predatorStatusPointer->GibbFactor=ONE_FIXED; + CauseDamageToObject(sbPtr,&certainDeath,ONE_FIXED,NULL); + StartPredatorSelfDestructExplosion(sbPtr); + /* So as not to confuse the corpse. */ + #else + predatorStatusPointer->GibbFactor=ONE_FIXED; + predatorStatusPointer->Explode=1; + #endif + } + } + + /* There's no escape from this other than death! */ + return(PRC_No_Change); + +} + +void StartPredatorSelfDestructExplosion(STRATEGYBLOCK *sbPtr) { + + /* So it can be easily altered. Also referenced by bh_corpse.c. */ + #if 0 + HandleEffectsOfExplosion + ( + sbPtr, + &(sbPtr->DynPtr->Position), + TemplateAmmo[AMMO_SADAR_BLAST].MaxRange, + &TemplateAmmo[AMMO_SADAR_BLAST].MaxDamage[AvP.Difficulty], + TemplateAmmo[AMMO_SADAR_BLAST].ExplosionIsFlat + ); + Sound_Play(SID_NICE_EXPLOSION,"d",&(sbPtr->DynPtr->Position)); + #else + /* Copied from SelfDestructBehavFun. */ + int i; + + /* KJL 16:20:57 27/08/98 - let's do some pyrotechnics */ + Sound_Play(SID_NICE_EXPLOSION,"d",&(Player->ObWorld)); + MakeVolumetricExplosionAt(&Player->ObWorld,EXPLOSION_HUGE); + Player->ObStrategyBlock->SBDamageBlock.IsOnFire=1; + + //blow up everone + for (i=0; iI_SBtype==I_BehaviourAlien || + SbPtr->I_SBtype==I_BehaviourQueenAlien || + SbPtr->I_SBtype==I_BehaviourFaceHugger || + SbPtr->I_SBtype==I_BehaviourPredator || + SbPtr->I_SBtype==I_BehaviourXenoborg || + SbPtr->I_SBtype==I_BehaviourMarine || + SbPtr->I_SBtype==I_BehaviourSeal || + SbPtr->I_SBtype==I_BehaviourPredatorAlien || + SbPtr->I_SBtype==I_BehaviourAlien || + SbPtr->I_SBtype==I_BehaviourMarinePlayer || + SbPtr->I_SBtype==I_BehaviourPredatorPlayer || + SbPtr->I_SBtype==I_BehaviourAlienPlayer) + { + { + //kill the creature/player + VECTORCH direction={0,-ONE_FIXED,0}; + CauseDamageToObject(SbPtr,&certainDeath,ONE_FIXED,&direction); + + } + } + } + #endif +} + +void DoPredatorHitSound(STRATEGYBLOCK *sbPtr) { + + DYNAMICSBLOCK *dynPtr; + int rand = FastRandom(); + int pitch = (rand & 255) - 128; + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + GLOBALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + if (predatorStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + return; + } + + /* This one is for PREDATOR DAMAGE SCREAM. */ + + if (predatorStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) { + PlayPredatorSound(0,PSC_Scream_Hurt,pitch, + &predatorStatusPointer->soundHandle,&sbPtr->DynPtr->Position); + } + +} + +void DoPredatorAcidSound(STRATEGYBLOCK *sbPtr) { + + DYNAMICSBLOCK *dynPtr; + int rand = FastRandom(); + int pitch = (rand & 255) - 128; + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + GLOBALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + if (predatorStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + return; + } + + /* This one is for PREDATOR ACID DAMAGE SCREAM. */ + + if (predatorStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) { + PlayPredatorSound(0,PSC_Acid,pitch, + &predatorStatusPointer->soundHandle,&sbPtr->DynPtr->Position); + } + +} + +void DoPredatorDeathSound(STRATEGYBLOCK *sbPtr) { + + DYNAMICSBLOCK *dynPtr; + int rand = FastRandom(); + int pitch = (rand & 255) - 128; + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + GLOBALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + if (predatorStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + return; + } + + /* This one is for PREDATOR DEATH SCREAM. */ + + if (predatorStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) { + PlayPredatorSound(0,PSC_Scream_Dying,pitch, + &predatorStatusPointer->soundHandle,&sbPtr->DynPtr->Position); + } + +} + +void DoPredatorRandomSound(STRATEGYBLOCK *sbPtr) { + + DYNAMICSBLOCK *dynPtr; + int rand = FastRandom(); + int pitch = (rand & 255) - 128; + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + GLOBALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + if (predatorStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + return; + } + + /* This one is for PREDATOR GENERAL SCREAM. */ + + if (predatorStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) { + PlayPredatorSound(0,PSC_Scream_General,pitch, + &predatorStatusPointer->soundHandle,&sbPtr->DynPtr->Position); + } + +} + +void DoPredatorTauntSound(STRATEGYBLOCK *sbPtr) { + + DYNAMICSBLOCK *dynPtr; + int rand = FastRandom(); + int pitch = (rand & 255) - 128; + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + GLOBALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + if (predatorStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + return; + } + + /* This one is for PREDATOR TAUNT. */ + + if (predatorStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) { + PlayPredatorSound(0,PSC_Taunt,pitch, + &predatorStatusPointer->soundHandle,&sbPtr->DynPtr->Position); + } + +} + +void DoPredatorAISwipeSound(STRATEGYBLOCK *sbPtr) { + + DYNAMICSBLOCK *dynPtr; + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + GLOBALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + /* This one is for PREDATOR SWIPE SOUND. */ + + PlayPredatorSound(0,PSC_Swipe,0,NULL,&sbPtr->DynPtr->Position); + +} + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" +typedef struct predator_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + +//behaviour block stuff + signed int health; + PRED_BHSTATE behaviourState; + PRED_BHSTATE lastState; + + int stateTimer; + int internalState; + int patience; + int enableSwap; + int enableTaunt; + VECTORCH weaponTarget; /* target position for firing weapon at */ + int volleySize; /* used for weapon control */ + NPC_OBSTRUCTIONREPORT obstruction; + NPC_WANDERDATA wanderData; + + int IAmCrouched; + int personalNumber; /* for predator personalisation */ + int nearSpeed; + int GibbFactor; + + int incidentFlag; + int incidentTimer; + + PREDATOR_NPC_WEAPONS PrimaryWeapon; + PREDATOR_NPC_WEAPONS SecondaryWeapon; + PREDATOR_NPC_WEAPONS ChangeToWeapon; + + /* these are for cloaking... */ + PRED_CLOAKSTATE CloakStatus; + int CloakingEffectiveness; + int CloakTimer; + + /* And these for the laser dots. */ + THREE_LASER_DOT_DESC Pred_Laser_Sight; + int Pred_Laser_On :1; + int Explode :1; + + int path; + int stepnumber; + + +//annoying pointer related things + + int weapon_id; + int currentAttackCode; + char Target_SBname[SB_NAME_LENGTH]; + + int missionmodule_index; + int fearmodule_index; + +//strategyblock stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; + DYNAMICSBLOCK dynamics; + +}PREDATOR_SAVE_BLOCK; + + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV predatorStatusPointer + +void LoadStrategy_Predator(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + PREDATOR_STATUS_BLOCK* predatorStatusPointer; + PREDATOR_SAVE_BLOCK* block = (PREDATOR_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + /* + Check the strategy type. + Slight complication here , since it might be a dormant predator + (assuming that they are actually used in any of the levels) + */ + + if(sbPtr->I_SBtype == I_BehaviourDormantPredator) + { + //best make it un-dormant then + ActivateDormantPredator(sbPtr); + } + else if(sbPtr->I_SBtype != I_BehaviourPredator) + { + return; + } + + predatorStatusPointer = (PREDATOR_STATUS_BLOCK*) sbPtr->SBdataptr; + + + //start copying stuff + + COPYELEMENT_LOAD(health) + COPYELEMENT_LOAD(behaviourState) + COPYELEMENT_LOAD(lastState) + COPYELEMENT_LOAD(stateTimer) + COPYELEMENT_LOAD(internalState) + COPYELEMENT_LOAD(patience) + COPYELEMENT_LOAD(enableSwap) + COPYELEMENT_LOAD(enableTaunt) + COPYELEMENT_LOAD(weaponTarget) /* target position for firing weapon at */ + COPYELEMENT_LOAD(volleySize) /* used for weapon control */ + COPYELEMENT_LOAD(obstruction) + COPYELEMENT_LOAD(wanderData) + COPYELEMENT_LOAD(IAmCrouched) + COPYELEMENT_LOAD(personalNumber) /* for predator personalisation */ + COPYELEMENT_LOAD(nearSpeed) + COPYELEMENT_LOAD(GibbFactor) + COPYELEMENT_LOAD(incidentFlag) + COPYELEMENT_LOAD(incidentTimer) + COPYELEMENT_LOAD(PrimaryWeapon) + COPYELEMENT_LOAD(SecondaryWeapon) + COPYELEMENT_LOAD(ChangeToWeapon) + COPYELEMENT_LOAD(CloakStatus) + COPYELEMENT_LOAD(CloakingEffectiveness) + COPYELEMENT_LOAD(CloakTimer) + COPYELEMENT_LOAD(Pred_Laser_Sight) + COPYELEMENT_LOAD(Pred_Laser_On) + COPYELEMENT_LOAD(Explode) + COPYELEMENT_LOAD(path) + COPYELEMENT_LOAD(stepnumber) + + //load ai module pointers + predatorStatusPointer->missionmodule = GetPointerFromAIModuleIndex(block->missionmodule_index); + predatorStatusPointer->fearmodule = GetPointerFromAIModuleIndex(block->fearmodule_index); + + //load target + COPY_NAME(predatorStatusPointer->Target_SBname,block->Target_SBname); + predatorStatusPointer->Target = FindSBWithName(predatorStatusPointer->Target_SBname); + + //get the predator's attack from the attack code + predatorStatusPointer->current_attack = GetThisAttack_FromUniqueCode(block->currentAttackCode); + + //get marine's weapon + predatorStatusPointer->Selected_Weapon = GetThisNPCPredatorWeapon(block->weapon_id); + + //copy strategy block stuff + *sbPtr->DynPtr = block->dynamics; + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + + //load hierarchy + { + SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); + if(hier_header) + { + LoadHierarchy(hier_header,&predatorStatusPointer->HModelController); + } + } + + + //sort out section pointers + predatorStatusPointer->My_Gun_Section=GetThisSectionData(predatorStatusPointer->HModelController.section_data,predatorStatusPointer->Selected_Weapon->GunName); + predatorStatusPointer->My_Elevation_Section=GetThisSectionData(predatorStatusPointer->HModelController.section_data,predatorStatusPointer->Selected_Weapon->ElevationName); + + + Load_SoundState(&predatorStatusPointer->soundHandle); + +} + +void SaveStrategy_Predator(STRATEGYBLOCK* sbPtr) +{ + PREDATOR_SAVE_BLOCK *block; + PREDATOR_STATUS_BLOCK* predatorStatusPointer; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK*) sbPtr->SBdataptr; + + + //start copying stuff + + COPYELEMENT_SAVE(health) + COPYELEMENT_SAVE(behaviourState) + COPYELEMENT_SAVE(lastState) + COPYELEMENT_SAVE(stateTimer) + COPYELEMENT_SAVE(internalState) + COPYELEMENT_SAVE(patience) + COPYELEMENT_SAVE(enableSwap) + COPYELEMENT_SAVE(enableTaunt) + COPYELEMENT_SAVE(weaponTarget) /* target position for firing weapon at */ + COPYELEMENT_SAVE(volleySize) /* used for weapon control */ + COPYELEMENT_SAVE(obstruction) + COPYELEMENT_SAVE(wanderData) + COPYELEMENT_SAVE(IAmCrouched) + COPYELEMENT_SAVE(personalNumber) /* for predator personalisation */ + COPYELEMENT_SAVE(nearSpeed) + COPYELEMENT_SAVE(GibbFactor) + COPYELEMENT_SAVE(incidentFlag) + COPYELEMENT_SAVE(incidentTimer) + COPYELEMENT_SAVE(PrimaryWeapon) + COPYELEMENT_SAVE(SecondaryWeapon) + COPYELEMENT_SAVE(ChangeToWeapon) + COPYELEMENT_SAVE(CloakStatus) + COPYELEMENT_SAVE(CloakingEffectiveness) + COPYELEMENT_SAVE(CloakTimer) + COPYELEMENT_SAVE(Pred_Laser_Sight) + COPYELEMENT_SAVE(Pred_Laser_On) + COPYELEMENT_SAVE(Explode) + COPYELEMENT_SAVE(path) + COPYELEMENT_SAVE(stepnumber) + + //save ai module pointers + block->missionmodule_index = GetIndexFromAIModulePointer(predatorStatusPointer->missionmodule); + block->fearmodule_index = GetIndexFromAIModulePointer(predatorStatusPointer->fearmodule); + + //save target + COPY_NAME(block->Target_SBname,predatorStatusPointer->Target_SBname); + + //save attack code + if(predatorStatusPointer->current_attack) + { + block->currentAttackCode = predatorStatusPointer->current_attack->Unique_Code; + } + else + { + block->currentAttackCode = -1; + } + + //save predator's weapon + if(predatorStatusPointer->Selected_Weapon) + block->weapon_id = predatorStatusPointer->Selected_Weapon->id; + else + block->weapon_id = -1; + + //copy strategy block stuff + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; + + //save the hierarchy + SaveHierarchy(&predatorStatusPointer->HModelController); + + Save_SoundState(&predatorStatusPointer->soundHandle); +} diff --git a/3dc/avp/Bh_xeno.c b/3dc/avp/Bh_xeno.c new file mode 100644 index 0000000..53ab42c --- /dev/null +++ b/3dc/avp/Bh_xeno.c @@ -0,0 +1,5308 @@ +/* Patrick 4/7/97 ---------------------------------------------------- + Source file for Xenoborg AI behaviour functions.... + --------------------------------------------------------------------*/ + +/* ChrisF 6/7/98. Hopeless. I'll have to take off and nuke the + entire site from orbit. */ +#include "3dc.h" + +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "comp_shp.h" +#include "dynblock.h" +#include "dynamics.h" +#include "pfarlocs.h" +#include "pvisible.h" +#include "bh_pred.h" +#include "bh_xeno.h" +#include "lighting.h" +#include "bh_weap.h" +#include "weapons.h" +#include "bh_debri.h" +#include "plat_shp.h" +#include "particle.h" +#include "AI_Sight.h" +#include "sequnces.h" +#include "huddefs.h" +#include "ShowCmds.h" +#include "sfx.h" +#include "bh_marin.h" +#include "bh_far.h" +#include "pldghost.h" +#include "pheromon.h" +#include "targeting.h" +#include "dxlog.h" +#include "los.h" +#include "bh_alien.h" +#include "bh_corpse.h" +#include "bh_dummy.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +#include "psnd.h" + +#define XENO_SENTRYTIME (20) +#define FAR_XENO_ACTIVITY 0 +#define FAR_XENO_FIRING 0 + +#define XENO_WALKING_ANIM_SPEED (ONE_FIXED<<1) +#define XENO_TURNING_ANIM_SPEED (ONE_FIXED<<1) + +/* external global variables used in this file */ +extern int ModuleArraySize; +extern char *ModuleCurrVisArray; +extern int NormalFrameTime; +extern unsigned char Null_Name[8]; + +VECTORCH null_vec={0,0,0}; + +extern HIERARCHY_SHAPE_REPLACEMENT* GetHierarchyAlternateShapeSetFromLibrary(const char* rif_name,const char* shape_set_name); +extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); +extern void HandleWeaponImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *section_pointer); + +int ShowXenoStats=0; + +int RATweak=40; + +void EnforceXenoborgShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime); +void SetXenoborgShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime); +void SetXenoborgShapeAnimSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length); +void XenoborgHandleMovingAnimation(STRATEGYBLOCK *sbPtr); + +static void ComputeDeltaValues(STRATEGYBLOCK *sbPtr); +static void KillXeno(STRATEGYBLOCK *sbPtr,int wounds,DAMAGE_PROFILE *damage, int multiple,VECTORCH *incoming); +void CreateXenoborg(VECTORCH *Position,int type); +void Xenoborg_ActivateAllDeltas(STRATEGYBLOCK *sbPtr); +void Xenoborg_DeactivateAllDeltas(STRATEGYBLOCK *sbPtr); +STRATEGYBLOCK *Xenoborg_GetNewTarget(VECTORCH *xenopos, STRATEGYBLOCK *me); +void Xenoborg_GetRelativeAngles(STRATEGYBLOCK *sbPtr, int *anglex, int *angley, VECTORCH *pivotPoint); +void Xeno_UpdateTargetTrackPos(STRATEGYBLOCK *sbPtr); +int Xeno_Activation_Test(STRATEGYBLOCK *sbPtr); + +void Xeno_HeadMovement_ScanLeftRight(STRATEGYBLOCK *sbPtr,int rate); +void Xeno_HeadMovement_ScanUpDown(STRATEGYBLOCK *sbPtr,int rate); +void Xeno_LeftArmMovement_TrackLeftRight(STRATEGYBLOCK *sbPtr,int rate); +void Xeno_LeftArmMovement_TrackUpDown(STRATEGYBLOCK *sbPtr,int rate); +void Xeno_RightArmMovement_TrackLeftRight(STRATEGYBLOCK *sbPtr,int rate); +void Xeno_RightArmMovement_TrackUpDown(STRATEGYBLOCK *sbPtr,int rate); +void Xeno_TorsoMovement_TrackLeftRight(STRATEGYBLOCK *sbPtr,int rate); +void Xeno_LeftArmMovement_WaveUp(STRATEGYBLOCK *sbPtr,int rate); +void Xeno_RightArmMovement_WaveUp(STRATEGYBLOCK *sbPtr,int rate); +void Xeno_TorsoMovement_TrackToAngle(STRATEGYBLOCK *sbPtr,int rate,int in_anglex); + +void Xenoborg_MaintainLeftGun(STRATEGYBLOCK *sbPtr); +void Xenoborg_MaintainRightGun(STRATEGYBLOCK *sbPtr); +void Xeno_MaintainLasers(STRATEGYBLOCK *sbPtr); +void Xeno_SwitchLED(STRATEGYBLOCK *sbPtr,int state); +void Xeno_Stomp(STRATEGYBLOCK *sbPtr); +void Xeno_MaintainSounds(STRATEGYBLOCK *sbPtr); + +int Xeno_HeadMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley); +void Xeno_TorsoMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex); +int Xeno_LeftArmMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley); +int Xeno_RightArmMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley); +void Xeno_TorsoMovement_Centre(STRATEGYBLOCK *sbPtr,int rate); +void Xeno_LeftArmMovement_Centre(STRATEGYBLOCK *sbPtr,int rate); +void Xeno_RightArmMovement_Centre(STRATEGYBLOCK *sbPtr,int rate); +void Xeno_Limbs_ShootTheRoof(STRATEGYBLOCK *sbPtr); + +void Xeno_Enter_PowerUp_State(STRATEGYBLOCK *sbPtr); +void Xeno_Enter_PowerDown_State(STRATEGYBLOCK *sbPtr); +void Xeno_Enter_ActiveWait_State(STRATEGYBLOCK *sbPtr); +void Xeno_Enter_Dormant_State(STRATEGYBLOCK *sbPtr); +void Xeno_Enter_TurnToFace_State(STRATEGYBLOCK *sbPtr); +void Xeno_Enter_Following_State(STRATEGYBLOCK *sbPtr); +void Xeno_Enter_Returning_State(STRATEGYBLOCK *sbPtr); +void Xeno_Enter_ShootingTheRoof_State(STRATEGYBLOCK *sbPtr); + +void Execute_Xeno_Dying(STRATEGYBLOCK *sbPtr); +void Execute_Xeno_Inactive(STRATEGYBLOCK *sbPtr); +void Execute_Xeno_PowerUp(STRATEGYBLOCK *sbPtr); +void Execute_Xeno_PowerDown(STRATEGYBLOCK *sbPtr); +void Execute_Xeno_ActiveWait(STRATEGYBLOCK *sbPtr); +void Execute_Xeno_TurnToFace(STRATEGYBLOCK *sbPtr); +void Execute_Xeno_Follow(STRATEGYBLOCK *sbPtr); +void Execute_Xeno_Return(STRATEGYBLOCK *sbPtr); +void Execute_Xeno_Avoidance(STRATEGYBLOCK *sbPtr); +void Execute_Xeno_ShootTheRoof(STRATEGYBLOCK *sbPtr); + +void Execute_Xeno_ActiveWait_Far(STRATEGYBLOCK *sbPtr); +void Execute_Xeno_TurnToFace_Far(STRATEGYBLOCK *sbPtr); +void Execute_Xeno_Follow_Far(STRATEGYBLOCK *sbPtr); +void Execute_Xeno_Return_Far(STRATEGYBLOCK *sbPtr); +void Execute_Xeno_Avoidance_Far(STRATEGYBLOCK *sbPtr); + +int XenoActivation_FrustrumReject(VECTORCH *localOffset); + +/* Begin Code! */ + +void CastXenoborg(void) { + + #define BOTRANGE 2000 + + VECTORCH position; + + if (AvP.Network!=I_No_Network) { + NewOnScreenMessage("NO XENOBORGS IN MULTIPLAYER MODE"); + return; + } + + position=Player->ObStrategyBlock->DynPtr->Position; + position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE); + position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE); + position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE); + + CreateXenoborg(&position, 0); + +} + +void CreateXenoborg(VECTORCH *Position,int type) +{ + STRATEGYBLOCK* sbPtr; + int i; + + /* create and initialise a strategy block */ + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) { + NewOnScreenMessage("FAILED TO CREATE BOT: SB CREATION FAILURE"); + return; /* failure */ + } + InitialiseSBValues(sbPtr); + + sbPtr->I_SBtype = I_BehaviourXenoborg; + + AssignNewSBName(sbPtr); + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC); + if(sbPtr->DynPtr) + { + EULER zeroEuler = {0,0,0}; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + GLOBALASSERT(dynPtr); + dynPtr->PrevPosition = dynPtr->Position = *Position; + dynPtr->OrientEuler = zeroEuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + + dynPtr->Mass=500; /* As opposed to 160. */ + } + else + { + /* dynamics block allocation failed... */ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: DYNBLOCK CREATION FAILURE"); + return; + } + + sbPtr->shapeIndex = 0; + + sbPtr->maintainVisibility = 1; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0); + + /* create, initialise and attach an alien data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(XENO_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + SECTION *root_section; + XENO_STATUS_BLOCK *xenoStatus = (XENO_STATUS_BLOCK *)sbPtr->SBdataptr; + + NPC_InitMovementData(&(xenoStatus->moveData)); + NPC_InitWanderData(&(xenoStatus->wanderData)); + InitWaypointManager(&xenoStatus->waypointManager); + + /* Initialise xenoborg's stats */ + { + NPC_DATA *NpcData; + + NpcData=GetThisNpcData(I_NPC_Xenoborg); + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + + xenoStatus->behaviourState=XS_Inactive; + xenoStatus->lastState=XS_Inactive; + xenoStatus->Target=NULL; + COPY_NAME(xenoStatus->Target_SBname,Null_Name); + xenoStatus->targetTrackPos.vx=0; + xenoStatus->targetTrackPos.vy=0; + xenoStatus->targetTrackPos.vz=0; + + xenoStatus->Wounds=0; + xenoStatus->GibbFactor=0; + xenoStatus->stateTimer=XENO_POWERDOWN_TIME; + xenoStatus->my_module=sbPtr->containingModule->m_aimodule; + xenoStatus->my_spot_therin=sbPtr->DynPtr->Position; + { + /* Pull out my_orientdir_therin. */ + xenoStatus->my_orientdir_therin.vx=0; + xenoStatus->my_orientdir_therin.vx=0; + xenoStatus->my_orientdir_therin.vz=1000; + + RotateVector(&xenoStatus->my_orientdir_therin,&sbPtr->DynPtr->OrientMat); + } + xenoStatus->module_range=7; + xenoStatus->UpTime=XENO_SENTRYTIME*ONE_FIXED; + xenoStatus->Head_Pan=0; + xenoStatus->Head_Tilt=0; + xenoStatus->Left_Arm_Pan=0; + xenoStatus->Left_Arm_Tilt=0; + xenoStatus->Right_Arm_Pan=0; + xenoStatus->Right_Arm_Tilt=0; + xenoStatus->Torso_Twist=0; + + xenoStatus->headpandir=0; + xenoStatus->headtiltdir=0; + xenoStatus->leftarmpandir=0; + xenoStatus->leftarmtiltdir=0; + xenoStatus->rightarmpandir=0; + xenoStatus->rightarmtiltdir=0; + xenoStatus->torsotwistdir=0; + + xenoStatus->Old_Head_Pan=0; + xenoStatus->Old_Head_Tilt=0; + xenoStatus->Old_Left_Arm_Pan=0; + xenoStatus->Old_Left_Arm_Tilt=0; + xenoStatus->Old_Right_Arm_Pan=0; + xenoStatus->Old_Right_Arm_Tilt=0; + xenoStatus->Old_Torso_Twist=0; + + xenoStatus->headLock=0; + xenoStatus->leftArmLock=0; + xenoStatus->rightArmLock=0; + xenoStatus->targetSightTest=0; + xenoStatus->IAmFar=1; + xenoStatus->ShotThisFrame=0; + + xenoStatus->obstruction.environment=0; + xenoStatus->obstruction.destructableObject=0; + xenoStatus->obstruction.otherCharacter=0; + xenoStatus->obstruction.anySingleObstruction=0; + + /* Init beams. */ + xenoStatus->LeftMainBeam.BeamIsOn = 0; + xenoStatus->RightMainBeam.BeamIsOn = 0; + xenoStatus->TargetingLaser[0].SourcePosition=null_vec; + xenoStatus->TargetingLaser[0].TargetPosition=null_vec; + xenoStatus->TargetingLaser[0].BeamHasHitPlayer=0; + xenoStatus->TargetingLaser[0].BeamIsOn=0; + + xenoStatus->TargetingLaser[1].SourcePosition=null_vec; + xenoStatus->TargetingLaser[1].TargetPosition=null_vec; + xenoStatus->TargetingLaser[1].BeamHasHitPlayer=0; + xenoStatus->TargetingLaser[1].BeamIsOn=0; + + xenoStatus->TargetingLaser[2].SourcePosition=null_vec; + xenoStatus->TargetingLaser[2].TargetPosition=null_vec; + xenoStatus->TargetingLaser[2].BeamHasHitPlayer=0; + xenoStatus->TargetingLaser[2].BeamIsOn=0; + + xenoStatus->FiringLeft=0; + xenoStatus->FiringRight=0; + + xenoStatus->UseHeadLaser=0; + xenoStatus->UseLALaser=0; + xenoStatus->UseRALaser=0; + + xenoStatus->head_moving=0; + xenoStatus->la_moving=0; + xenoStatus->ra_moving=0; + xenoStatus->torso_moving=0; + + xenoStatus->HeadLaserOnTarget=0; + xenoStatus->LALaserOnTarget=0; + xenoStatus->RALaserOnTarget=0; + + xenoStatus->soundHandle1=SOUND_NOACTIVEINDEX; + xenoStatus->soundHandle2=SOUND_NOACTIVEINDEX; + + xenoStatus->incidentFlag=0; + xenoStatus->incidentTimer=0; + + xenoStatus->head_whirr=SOUND_NOACTIVEINDEX; + xenoStatus->left_arm_whirr=SOUND_NOACTIVEINDEX; + xenoStatus->right_arm_whirr=SOUND_NOACTIVEINDEX; + xenoStatus->torso_whirr=SOUND_NOACTIVEINDEX; + + xenoStatus->HModelController.section_data=NULL; + xenoStatus->HModelController.Deltas=NULL; + + for(i=0;ideath_target_ID[i] =0; + xenoStatus->death_target_sbptr=0; + xenoStatus->death_target_request=0; + + root_section=GetNamedHierarchyFromLibrary("hnpc_xenoborg","xenobasic"); + + if (!root_section) { + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: NO HMODEL"); + return; + } + Create_HModel(&xenoStatus->HModelController,root_section); + InitHModelSequence(&xenoStatus->HModelController,HMSQT_Xenoborg,XBSS_Powered_Down_Standard,ONE_FIXED); + + { + DELTA_CONTROLLER *delta; + + delta=Add_Delta_Sequence(&xenoStatus->HModelController,"HeadTilt",(int)HMSQT_Xenoborg,(int)XBSS_Head_Vertical_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + delta=Add_Delta_Sequence(&xenoStatus->HModelController,"HeadPan",(int)HMSQT_Xenoborg,(int)XBSS_Head_Horizontal_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + delta=Add_Delta_Sequence(&xenoStatus->HModelController,"LeftArmTilt",(int)HMSQT_Xenoborg,(int)XBSS_LeftArm_Vertical_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + delta=Add_Delta_Sequence(&xenoStatus->HModelController,"LeftArmPan",(int)HMSQT_Xenoborg,(int)XBSS_LeftArm_Horizontal_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + delta=Add_Delta_Sequence(&xenoStatus->HModelController,"RightArmTilt",(int)HMSQT_Xenoborg,(int)XBSS_RightArm_Vertical_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + delta=Add_Delta_Sequence(&xenoStatus->HModelController,"RightArmPan",(int)HMSQT_Xenoborg,(int)XBSS_RightArm_Horizontal_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + delta=Add_Delta_Sequence(&xenoStatus->HModelController,"TorsoTwist",(int)HMSQT_Xenoborg,(int)XBSS_Torso_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + } + + /* Containment test NOW! */ + if(!(sbPtr->containingModule)) + { + /* no containing module can be found... abort*/ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: MODULE CONTAINMENT FAILURE"); + return; + } + LOCALASSERT(sbPtr->containingModule); + Xeno_SwitchLED(sbPtr,0); + + MakeXenoborgNear(sbPtr); + + NewOnScreenMessage("XENOBORG CREATED"); + } + else + { + /* no data block can be allocated */ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE BOT: MALLOC FAILURE"); + return; + } +} + +static void VerifyDeltaControllers(STRATEGYBLOCK *sbPtr) { + + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Nothing has deltas like a xenoborg does. */ + + xenoStatusPointer->head_pan=Get_Delta_Sequence(&xenoStatusPointer->HModelController,"HeadPan"); + GLOBALASSERT(xenoStatusPointer->head_pan); + + xenoStatusPointer->head_tilt=Get_Delta_Sequence(&xenoStatusPointer->HModelController,"HeadTilt"); + GLOBALASSERT(xenoStatusPointer->head_tilt); + + xenoStatusPointer->left_arm_pan=Get_Delta_Sequence(&xenoStatusPointer->HModelController,"LeftArmPan"); + GLOBALASSERT(xenoStatusPointer->left_arm_pan); + + xenoStatusPointer->left_arm_tilt=Get_Delta_Sequence(&xenoStatusPointer->HModelController,"LeftArmTilt"); + GLOBALASSERT(xenoStatusPointer->left_arm_tilt); + + xenoStatusPointer->right_arm_pan=Get_Delta_Sequence(&xenoStatusPointer->HModelController,"RightArmPan"); + GLOBALASSERT(xenoStatusPointer->right_arm_pan); + + xenoStatusPointer->right_arm_tilt=Get_Delta_Sequence(&xenoStatusPointer->HModelController,"RightArmTilt"); + GLOBALASSERT(xenoStatusPointer->right_arm_tilt); + + xenoStatusPointer->torso_twist=Get_Delta_Sequence(&xenoStatusPointer->HModelController,"TorsoTwist"); + GLOBALASSERT(xenoStatusPointer->torso_twist); + +} + +/* Patrick 4/7/97 ---------------------------------------------------- + Xenoborg initialiser, visibility management, behaviour shell, and + damage functions + + ChrisF 6/7/98. I don't think so... + --------------------------------------------------------------------*/ +void InitXenoborgBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr) +{ + TOOLS_DATA_XENO *toolsData; + int i; + + LOCALASSERT(bhdata); + toolsData = (TOOLS_DATA_XENO *)bhdata; + LOCALASSERT(sbPtr); + + /* check we're not in a net game */ + if(AvP.Network != I_No_Network) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* make the assumption that the loader has initialised the strategy block sensibly... + so just set the shapeIndex from the tools data & copy the name id*/ + sbPtr->shapeIndex = toolsData->shapeIndex; + for(i=0;iSBname[i] = toolsData->nameID[i]; + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC); + if(sbPtr->DynPtr) + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + GLOBALASSERT(dynPtr); + dynPtr->PrevPosition = dynPtr->Position = toolsData->position; + dynPtr->OrientEuler = toolsData->starteuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + + dynPtr->Mass=1000; /* As opposed to 160. */ + } + else + { + /* dynamics block allocation failed... */ + RemoveBehaviourStrategy(sbPtr); + return; + } + + sbPtr->maintainVisibility = 1; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0); + + /* create, initialise and attach a xeno data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(XENO_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + SECTION *root_section; + XENO_STATUS_BLOCK *xenoStatus = (XENO_STATUS_BLOCK *)sbPtr->SBdataptr; + + NPC_InitMovementData(&(xenoStatus->moveData)); + NPC_InitWanderData(&(xenoStatus->wanderData)); + InitWaypointManager(&xenoStatus->waypointManager); + + /* Initialise xenoborg's stats */ + { + NPC_DATA *NpcData; + + NpcData=GetThisNpcData(I_NPC_Xenoborg); + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + + xenoStatus->behaviourState=XS_Inactive; + xenoStatus->lastState=XS_Inactive; + xenoStatus->Target=NULL; + COPY_NAME(xenoStatus->Target_SBname,Null_Name); + xenoStatus->targetTrackPos.vx=0; + xenoStatus->targetTrackPos.vy=0; + xenoStatus->targetTrackPos.vz=0; + + xenoStatus->Wounds=0; + xenoStatus->GibbFactor=0; + xenoStatus->stateTimer=XENO_POWERDOWN_TIME; + xenoStatus->my_module=sbPtr->containingModule->m_aimodule; + xenoStatus->my_spot_therin=sbPtr->DynPtr->Position; + { + /* Pull out my_orientdir_therin. */ + xenoStatus->my_orientdir_therin.vx=0; + xenoStatus->my_orientdir_therin.vx=0; + xenoStatus->my_orientdir_therin.vz=1000; + + RotateVector(&xenoStatus->my_orientdir_therin,&sbPtr->DynPtr->OrientMat); + } + xenoStatus->module_range=toolsData->ModuleRange; + xenoStatus->UpTime=toolsData->UpTime*ONE_FIXED; + xenoStatus->Head_Pan=0; + xenoStatus->Head_Tilt=0; + xenoStatus->Left_Arm_Pan=0; + xenoStatus->Left_Arm_Tilt=0; + xenoStatus->Right_Arm_Pan=0; + xenoStatus->Right_Arm_Tilt=0; + xenoStatus->Torso_Twist=0; + + xenoStatus->headpandir=0; + xenoStatus->headtiltdir=0; + xenoStatus->leftarmpandir=0; + xenoStatus->leftarmtiltdir=0; + xenoStatus->rightarmpandir=0; + xenoStatus->rightarmtiltdir=0; + xenoStatus->torsotwistdir=0; + + xenoStatus->Old_Head_Pan=0; + xenoStatus->Old_Head_Tilt=0; + xenoStatus->Old_Left_Arm_Pan=0; + xenoStatus->Old_Left_Arm_Tilt=0; + xenoStatus->Old_Right_Arm_Pan=0; + xenoStatus->Old_Right_Arm_Tilt=0; + xenoStatus->Old_Torso_Twist=0; + + xenoStatus->headLock=0; + xenoStatus->leftArmLock=0; + xenoStatus->rightArmLock=0; + xenoStatus->targetSightTest=0; + xenoStatus->IAmFar=1; + xenoStatus->ShotThisFrame=0; + + xenoStatus->obstruction.environment=0; + xenoStatus->obstruction.destructableObject=0; + xenoStatus->obstruction.otherCharacter=0; + xenoStatus->obstruction.anySingleObstruction=0; + + /* Init beams. */ + xenoStatus->LeftMainBeam.BeamIsOn = 0; + xenoStatus->RightMainBeam.BeamIsOn = 0; + xenoStatus->TargetingLaser[0].SourcePosition=null_vec; + xenoStatus->TargetingLaser[0].TargetPosition=null_vec; + xenoStatus->TargetingLaser[0].BeamHasHitPlayer=0; + xenoStatus->TargetingLaser[0].BeamIsOn=0; + + xenoStatus->TargetingLaser[1].SourcePosition=null_vec; + xenoStatus->TargetingLaser[1].TargetPosition=null_vec; + xenoStatus->TargetingLaser[1].BeamHasHitPlayer=0; + xenoStatus->TargetingLaser[1].BeamIsOn=0; + + xenoStatus->TargetingLaser[2].SourcePosition=null_vec; + xenoStatus->TargetingLaser[2].TargetPosition=null_vec; + xenoStatus->TargetingLaser[2].BeamHasHitPlayer=0; + xenoStatus->TargetingLaser[2].BeamIsOn=0; + + xenoStatus->FiringLeft=0; + xenoStatus->FiringRight=0; + + xenoStatus->UseHeadLaser=0; + xenoStatus->UseLALaser=0; + xenoStatus->UseRALaser=0; + + xenoStatus->head_moving=0; + xenoStatus->la_moving=0; + xenoStatus->ra_moving=0; + xenoStatus->torso_moving=0; + + xenoStatus->HeadLaserOnTarget=0; + xenoStatus->LALaserOnTarget=0; + xenoStatus->RALaserOnTarget=0; + + + xenoStatus->soundHandle1=SOUND_NOACTIVEINDEX; + xenoStatus->soundHandle2=SOUND_NOACTIVEINDEX; + + xenoStatus->incidentFlag=0; + xenoStatus->incidentTimer=0; + + xenoStatus->head_whirr=SOUND_NOACTIVEINDEX; + xenoStatus->left_arm_whirr=SOUND_NOACTIVEINDEX; + xenoStatus->right_arm_whirr=SOUND_NOACTIVEINDEX; + xenoStatus->torso_whirr=SOUND_NOACTIVEINDEX; + + xenoStatus->HModelController.section_data=NULL; + xenoStatus->HModelController.Deltas=NULL; + + for(i=0;ideath_target_ID[i] = toolsData->death_target_ID[i]; + xenoStatus->death_target_sbptr=0; + xenoStatus->death_target_request=toolsData->death_target_request; + + root_section=GetNamedHierarchyFromLibrary("hnpc_xenoborg","xenobasic"); + + GLOBALASSERT(root_section); + + Create_HModel(&xenoStatus->HModelController,root_section); + InitHModelSequence(&xenoStatus->HModelController,HMSQT_Xenoborg,XBSS_Powered_Down_Standard,ONE_FIXED); + + { + DELTA_CONTROLLER *delta; + + delta=Add_Delta_Sequence(&xenoStatus->HModelController,"HeadTilt",(int)HMSQT_Xenoborg,(int)XBSS_Head_Vertical_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + delta=Add_Delta_Sequence(&xenoStatus->HModelController,"HeadPan",(int)HMSQT_Xenoborg,(int)XBSS_Head_Horizontal_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + delta=Add_Delta_Sequence(&xenoStatus->HModelController,"LeftArmTilt",(int)HMSQT_Xenoborg,(int)XBSS_LeftArm_Vertical_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + delta=Add_Delta_Sequence(&xenoStatus->HModelController,"LeftArmPan",(int)HMSQT_Xenoborg,(int)XBSS_LeftArm_Horizontal_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + delta=Add_Delta_Sequence(&xenoStatus->HModelController,"RightArmTilt",(int)HMSQT_Xenoborg,(int)XBSS_RightArm_Vertical_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + delta=Add_Delta_Sequence(&xenoStatus->HModelController,"RightArmPan",(int)HMSQT_Xenoborg,(int)XBSS_RightArm_Horizontal_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + delta=Add_Delta_Sequence(&xenoStatus->HModelController,"TorsoTwist",(int)HMSQT_Xenoborg,(int)XBSS_Torso_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + } + + /* Containment test NOW! */ + GLOBALASSERT(sbPtr->containingModule); + Xeno_SwitchLED(sbPtr,0); + + } + else + { + /* no data block can be allocated */ + RemoveBehaviourStrategy(sbPtr); + return; + } + +} + +void XenoborgBehaviour(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + NPC_DATA *NpcData; + int xenoborgIsNear; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + NpcData=GetThisNpcData(I_NPC_Xenoborg); + + /* test if we've got a containing module: if we haven't, do nothing. + This is important as the object could have been marked for deletion by the visibility + management system...*/ + if(!sbPtr->containingModule) + { + DestroyAnyStrategyBlock(sbPtr); /* just to make sure */ + return; + } + + if(sbPtr->SBdptr) { + xenoborgIsNear=1; + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]); + } else { + xenoborgIsNear=0; + } + + VerifyDeltaControllers(sbPtr); + + #if 0 + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + #endif + + InitWaypointSystem(0); + + if (sbPtr->SBdptr) { + xenoStatusPointer->IAmFar=0; + } else { + xenoStatusPointer->IAmFar=1; + } + + /* Store angles. */ + xenoStatusPointer->Old_Head_Pan =xenoStatusPointer->Head_Pan; + xenoStatusPointer->Old_Head_Tilt =xenoStatusPointer->Head_Tilt; + xenoStatusPointer->Old_Left_Arm_Pan =xenoStatusPointer->Left_Arm_Pan; + xenoStatusPointer->Old_Left_Arm_Tilt =xenoStatusPointer->Left_Arm_Tilt; + xenoStatusPointer->Old_Right_Arm_Pan =xenoStatusPointer->Right_Arm_Pan; + xenoStatusPointer->Old_Right_Arm_Tilt =xenoStatusPointer->Right_Arm_Tilt; + xenoStatusPointer->Old_Torso_Twist =xenoStatusPointer->Torso_Twist; + + xenoStatusPointer->head_moving=0; + xenoStatusPointer->la_moving=0; + xenoStatusPointer->ra_moving=0; + xenoStatusPointer->torso_moving=0; + + /* Target handling. */ + if (Validate_Target(xenoStatusPointer->Target,xenoStatusPointer->Target_SBname)==0) { + xenoStatusPointer->Target=NULL; + } + + xenoStatusPointer->FiringLeft=0; + xenoStatusPointer->FiringRight=0; + + xenoStatusPointer->UseHeadLaser=0; + xenoStatusPointer->UseLALaser=0; + xenoStatusPointer->UseRALaser=0; + + xenoStatusPointer->LeftMainBeam.BeamIsOn = 0; + xenoStatusPointer->RightMainBeam.BeamIsOn = 0; + xenoStatusPointer->TargetingLaser[0].BeamIsOn=0; + xenoStatusPointer->TargetingLaser[1].BeamIsOn=0; + xenoStatusPointer->TargetingLaser[2].BeamIsOn=0; + + if (xenoStatusPointer->Target==NULL) { + if ((xenoborgIsNear)||(xenoStatusPointer->incidentFlag)) { + /* Get new target. */ + xenoStatusPointer->Target=Xenoborg_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr); + xenoStatusPointer->targetSightTest=0; + if (xenoStatusPointer->Target) { + COPY_NAME(xenoStatusPointer->Target_SBname,xenoStatusPointer->Target->SBname); + xenoStatusPointer->targetSightTest=1; + } + Xeno_UpdateTargetTrackPos(sbPtr); + xenoStatusPointer->headLock=0; + xenoStatusPointer->leftArmLock=0; + xenoStatusPointer->rightArmLock=0; + } + } else if (NPCCanSeeTarget(sbPtr,xenoStatusPointer->Target,XENO_NEAR_VIEW_WIDTH)) { + Xeno_UpdateTargetTrackPos(sbPtr); + xenoStatusPointer->targetSightTest=1; + } else { + /* We have a target that we can't see. */ + xenoStatusPointer->headLock=0; + xenoStatusPointer->leftArmLock=0; + xenoStatusPointer->rightArmLock=0; + xenoStatusPointer->targetSightTest=0; + } + + if (xenoStatusPointer->GibbFactor) { + /* If you're gibbed, you're dead. */ + sbPtr->SBDamageBlock.Health = 0; + } + + /* Unset incident flag. */ + xenoStatusPointer->incidentFlag=0; + + xenoStatusPointer->incidentTimer-=NormalFrameTime; + + if (xenoStatusPointer->incidentTimer<0) { + xenoStatusPointer->incidentFlag=1; + xenoStatusPointer->incidentTimer=32767+(FastRandom()&65535); + } + + if (sbPtr->SBDamageBlock.IsOnFire) { + + /* Why not? */ + CauseDamageToObject(sbPtr,&firedamage,NormalFrameTime,NULL); + + if (sbPtr->I_SBtype==I_BehaviourNetCorpse) { + /* Gettin' out of here... */ + return; + } + + if (xenoStatusPointer->incidentFlag) { + if ((FastRandom()&65535)<32767) { + sbPtr->SBDamageBlock.IsOnFire=0; + } + } + + } + + /* Now, switch by state. */ + + switch (xenoStatusPointer->behaviourState) { + case XS_ActiveWait: + if (xenoStatusPointer->IAmFar) { + Execute_Xeno_ActiveWait_Far(sbPtr); + } else { + Execute_Xeno_ActiveWait(sbPtr); + } + break; + case XS_TurnToFace: + if (xenoStatusPointer->IAmFar) { + Execute_Xeno_TurnToFace_Far(sbPtr); + } else { + Execute_Xeno_TurnToFace(sbPtr); + } + break; + case XS_Following: + if (xenoStatusPointer->IAmFar) { + Execute_Xeno_Follow_Far(sbPtr); + } else { + Execute_Xeno_Follow(sbPtr); + } + break; + case XS_Returning: + if (xenoStatusPointer->IAmFar) { + Execute_Xeno_Return_Far(sbPtr); + } else { + Execute_Xeno_Return(sbPtr); + } + break; + case XS_Avoidance: + if (xenoStatusPointer->IAmFar) { + Execute_Xeno_Avoidance_Far(sbPtr); + } else { + Execute_Xeno_Avoidance(sbPtr); + } + break; + case XS_Inactive: + Execute_Xeno_Inactive(sbPtr); + break; + case XS_Activating: + Execute_Xeno_PowerUp(sbPtr); + break; + case XS_Deactivating: + Execute_Xeno_PowerDown(sbPtr); + break; + case XS_Regenerating: + break; + case XS_Dying: + Execute_Xeno_Dying(sbPtr); + break; + case XS_ShootingTheRoof: + if (xenoStatusPointer->IAmFar) { + Execute_Xeno_ShootTheRoof(sbPtr); + } else { + Execute_Xeno_ShootTheRoof(sbPtr); + } + break; + default: + /* No action? */ + break; + } + + /* if we have actually died, we need to remove the strategyblock... so + do this here */ + if((xenoStatusPointer->behaviourState == XS_Dying)&&(xenoStatusPointer->stateTimer <= 0)) { + + DestroyAnyStrategyBlock(sbPtr); + } + + if ((xenoStatusPointer->behaviourState!=XS_Dying) + &&(xenoStatusPointer->behaviourState!=XS_Inactive) + &&(xenoStatusPointer->behaviourState!=XS_Activating) + &&(xenoStatusPointer->behaviourState!=XS_Deactivating)) { + /* Time to regenerate? */ + if ((sbPtr->SBDamageBlock.Health<(NpcData->StartingStats.Health<<(ONE_FIXED_SHIFT-2))) + &&(sbPtr->SBDamageBlock.Health>0)) { + /* 25% health or less. */ + Xeno_Enter_PowerDown_State(sbPtr); + } + } + + ComputeDeltaValues(sbPtr); + + ProveHModel_Far(&xenoStatusPointer->HModelController,sbPtr); + + #if (FAR_XENO_FIRING==0) + if (xenoStatusPointer->IAmFar) { + xenoStatusPointer->FiringLeft=0; + xenoStatusPointer->FiringRight=0; + } + #endif + + /* Now lets deal with the sounds. */ + Xeno_MaintainSounds(sbPtr); + + if (xenoStatusPointer->IAmFar) { + /* No lasers if far. */ + xenoStatusPointer->UseHeadLaser=0; + xenoStatusPointer->UseLALaser=0; + xenoStatusPointer->UseRALaser=0; + } + + /* Now consider the lasers. */ + Xeno_MaintainLasers(sbPtr); + Xeno_Stomp(sbPtr); + + /* Now, are we firing? */ + Xenoborg_MaintainLeftGun(sbPtr); + Xenoborg_MaintainRightGun(sbPtr); + + /* Unset shot flag. */ + xenoStatusPointer->ShotThisFrame=0; +} + +void MakeXenoborgNear(STRATEGYBLOCK *sbPtr) +{ + extern MODULEMAPBLOCK AlienDefaultMap; + + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr; + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + LOCALASSERT(dynPtr); + LOCALASSERT(sbPtr->SBdptr == NULL); + + AlienDefaultMap.MapShape = sbPtr->shapeIndex; + tempModule.m_mapptr = &AlienDefaultMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 0; + tempModule.m_lightarray = (struct lightblock *)0; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr = NULL; + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) return; /* if cannot create displayblock, leave far */ + + sbPtr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbPtr; + dPtr->ObMyModule = NULL; + + /* need to initialise positional information in the new display block */ + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + /* zero linear velocity in dynamics block */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* state and sequence init */ + NPC_InitMovementData(&(xenoStatusPointer->moveData)); + InitWaypointManager(&xenoStatusPointer->waypointManager); + + dPtr->ShapeAnimControlBlock = NULL; + dPtr->ObTxAnimCtrlBlks = NULL; + + dPtr->HModelControlBlock=&xenoStatusPointer->HModelController; + + ProveHModel(dPtr->HModelControlBlock,dPtr); + + xenoStatusPointer->IAmFar=0; + + /* make a sound */ + //Sound_Play(SID_ALIEN_HISS,"d",&sbPtr->DynPtr->Position); +} + +void MakeXenoborgFar(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + int i; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + LOCALASSERT(sbPtr->SBdptr != NULL); + + /* get rid of the displayblock */ + i = DestroyActiveObject(sbPtr->SBdptr); + LOCALASSERT(i==0); + sbPtr->SBdptr = NULL; + + /* xenoborg data block init */ + if(xenoStatusPointer->behaviourState != XS_Dying) { + xenoStatusPointer->stateTimer=0; + } + + /* zero linear velocity in dynamics block */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + xenoStatusPointer->IAmFar=1; + +} + +void Xenoborg_ActivateAllDeltas(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + if (xenoStatusPointer->head_pan) { + xenoStatusPointer->head_pan->Active=1; + } + + if (xenoStatusPointer->head_tilt) { + xenoStatusPointer->head_tilt->Active=1; + } + + if (xenoStatusPointer->left_arm_pan) { + xenoStatusPointer->left_arm_pan->Active=1; + } + + if (xenoStatusPointer->left_arm_tilt) { + xenoStatusPointer->left_arm_tilt->Active=1; + } + + if (xenoStatusPointer->right_arm_pan) { + xenoStatusPointer->right_arm_pan->Active=1; + } + + if (xenoStatusPointer->right_arm_tilt) { + xenoStatusPointer->right_arm_tilt->Active=1; + } + + if (xenoStatusPointer->torso_twist) { + xenoStatusPointer->torso_twist->Active=1; + } + +} + +void Xenoborg_DeactivateAllDeltas(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + if (xenoStatusPointer->head_pan) { + xenoStatusPointer->head_pan->Active=0; + } + xenoStatusPointer->Head_Pan=0; + + if (xenoStatusPointer->head_tilt) { + xenoStatusPointer->head_tilt->Active=0; + } + xenoStatusPointer->Head_Tilt=0; + + if (xenoStatusPointer->left_arm_pan) { + xenoStatusPointer->left_arm_pan->Active=0; + } + xenoStatusPointer->Left_Arm_Pan=0; + + if (xenoStatusPointer->left_arm_tilt) { + xenoStatusPointer->left_arm_tilt->Active=0; + } + xenoStatusPointer->Left_Arm_Tilt=0; + + if (xenoStatusPointer->right_arm_pan) { + xenoStatusPointer->right_arm_pan->Active=0; + } + xenoStatusPointer->Right_Arm_Pan=0; + + if (xenoStatusPointer->right_arm_tilt) { + xenoStatusPointer->right_arm_tilt->Active=0; + } + xenoStatusPointer->Right_Arm_Tilt=0; + + if (xenoStatusPointer->torso_twist) { + xenoStatusPointer->torso_twist->Active=0; + } + xenoStatusPointer->Torso_Twist=0; + +} + +void XenoborgIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,VECTORCH *incoming) +{ + + XENO_STATUS_BLOCK *xenoStatusPointer; + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + xenoStatusPointer->Wounds|=wounds; + xenoStatusPointer->ShotThisFrame=1; + + if (sbPtr->SBDamageBlock.Health <= 0) { + + /* Oh yes, kill them, too. */ + if (xenoStatusPointer->behaviourState!=XS_Dying) { + CurrentGameStats_CreatureKilled(sbPtr,NULL); + KillXeno(sbPtr,wounds,damage,multiple,incoming); + } + } + + if (xenoStatusPointer->behaviourState==XS_Inactive) { + if (xenoStatusPointer->stateTimer>=XENO_POWERDOWN_TIME) { + /* Ow, that hurt. */ + Xeno_Enter_PowerUp_State(sbPtr); + } + } + + xenoStatusPointer->Target=NULL; +} + +/* patrick 29/7/97 ----------------------------------- +Thess functions to be called only from behaviour +------------------------------------------------------*/ +static void KillXeno(STRATEGYBLOCK *sbPtr,int wounds,DAMAGE_PROFILE *damage, int multiple,VECTORCH *incoming) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + int deathtype,tkd; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* make an explosion sound */ + Sound_Play(SID_SENTRYGUNDEST,"d",&sbPtr->DynPtr->Position); + + xenoStatusPointer->stateTimer=XENO_DYINGTIME; + xenoStatusPointer->HModelController.Looped=0; + xenoStatusPointer->HModelController.LoopAfterTweening=0; + /* switch state */ + xenoStatusPointer->behaviourState=XS_Dying; + + Xenoborg_DeactivateAllDeltas(sbPtr); + Xeno_SwitchLED(sbPtr,0); + + if(xenoStatusPointer->death_target_sbptr) + { + RequestState(xenoStatusPointer->death_target_sbptr,xenoStatusPointer->death_target_request, 0); + } + + + if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->soundHandle1); + } + if (xenoStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->soundHandle2); + } + if (xenoStatusPointer->head_whirr!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->head_whirr); + } + if (xenoStatusPointer->left_arm_whirr!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->left_arm_whirr); + } + if (xenoStatusPointer->right_arm_whirr!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->right_arm_whirr); + } + if (xenoStatusPointer->torso_whirr!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->torso_whirr); + } + + /* Set up gibb factor. */ + + tkd=TotalKineticDamage(damage); + deathtype=0; + + if (tkd>40) { + /* Explosion case. */ + if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) { + /* Okay, you can gibb now. */ + xenoStatusPointer->GibbFactor=-(ONE_FIXED>>3); + deathtype=2; + } + } else if ( (multiple>>16)>1 ) { + int newmult; + + newmult=DIV_FIXED(multiple,NormalFrameTime); + if (MUL_FIXED(tkd,newmult)>700) { + /* Excessive bullets case 1. */ + xenoStatusPointer->GibbFactor=-(ONE_FIXED>>5); + deathtype=2; + } else if (MUL_FIXED(tkd,newmult)>250) { + /* Excessive bullets case 2. */ + //xenoStatusPointer->GibbFactor=ONE_FIXED>>6; + deathtype=1; + } + } + + if (tkd>200) { + /* Basically SADARS only. */ + xenoStatusPointer->GibbFactor=-(ONE_FIXED>>2); + + deathtype=3; + } + + /* No gibbing for flamethrower. */ + + { + SECTION_DATA *chest=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"chest"); + + if (chest==NULL) { + /* I'm impressed. */ + deathtype+=2; + } else if ((chest->flags§ion_data_notreal) + &&(chest->flags§ion_data_terminate_here)) { + /* That's gotta hurt. */ + deathtype++; + } + } + + + { + DEATH_DATA *this_death; + HIT_FACING facing; + + facing.Front=0; + facing.Back=0; + facing.Left=0; + facing.Right=0; + + if (incoming) { + if (incoming->vz>0) { + facing.Back=1; + } else { + facing.Front=1; + } + if (incoming->vx>0) { + facing.Right=1; + } else { + facing.Left=1; + } + } + + this_death=GetXenoborgDeathSequence(&xenoStatusPointer->HModelController,NULL, + xenoStatusPointer->Wounds,(xenoStatusPointer->Wounds&( + section_flag_left_leg|section_flag_right_leg|section_flag_left_foot|section_flag_right_foot)), + deathtype,&facing,0,0,0); + + GLOBALASSERT(this_death); + + Convert_Xenoborg_To_Corpse(sbPtr,this_death); + } + +} + +void Execute_Xeno_Dying(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + { + DISPLAYBLOCK *dispPtr = sbPtr->SBdptr; + /* do we have a displayblock? */ + if (dispPtr) + { + dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND; + dispPtr->ObFlags2 = xenoStatusPointer->stateTimer/2; + if (dispPtr->ObFlags2HModelController.DisableBleeding=1; + } + } + } + xenoStatusPointer->stateTimer -= NormalFrameTime; +} + +void EnforceXenoborgShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime) { + + XENO_STATUS_BLOCK *xenoStatus; + + xenoStatus=(XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + + if ((xenoStatus->HModelController.Sequence_Type==type) + &&(xenoStatus->HModelController.Sub_Sequence==subtype)) { + return; + } else { + SetXenoborgShapeAnimSequence_Core(sbPtr,type,subtype,length,tweeningtime); + } +} + +void SetXenoborgShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime) +{ + + XENO_STATUS_BLOCK *xenoStatus=(XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(length!=0); + + if (tweeningtime<=0) { + InitHModelSequence(&xenoStatus->HModelController,(int)type,subtype,length); + } else { + InitHModelTweening(&xenoStatus->HModelController, tweeningtime, (int)type,subtype,length, 1); + //xenoStatus->HModelController.ElevationTweening=1; + } + + xenoStatus->HModelController.Playing=1; + /* Might be unset... */ +} + +void SetXenoborgShapeAnimSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length) { + + SetXenoborgShapeAnimSequence_Core(sbPtr,type,subtype,length,(ONE_FIXED>>2)); + +} + +void Xenoborg_GetRelativeAngles(STRATEGYBLOCK *sbPtr, int *anglex, int *angley, VECTORCH *pivotPoint) { + + XENO_STATUS_BLOCK *xenoStatusPointer; + MATRIXCH WtoL; + VECTORCH targetPos; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* First, extract relative angle. */ + + WtoL=sbPtr->DynPtr->OrientMat; + TransposeMatrixCH(&WtoL); + targetPos=xenoStatusPointer->targetTrackPos; + targetPos.vx-=pivotPoint->vx; + targetPos.vy-=pivotPoint->vy; + targetPos.vz-=pivotPoint->vz; + RotateVector(&targetPos,&WtoL); + + /* Now... */ + { + int offsetx,offsety,offsetz,offseta; + + offsetx=(targetPos.vx); + offsety=(targetPos.vz); + offseta=-(targetPos.vy); + + while( (offsetx>(ONE_FIXED>>2)) + ||(offsety>(ONE_FIXED>>2)) + ||(offseta>(ONE_FIXED>>2)) + ||(offsetx<-(ONE_FIXED>>2)) + ||(offsety<-(ONE_FIXED>>2)) + ||(offseta<-(ONE_FIXED>>2))) { + + offsetx>>=1; + offsety>>=1; + offseta>>=1; + + } + + offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety)); + + if (angley) { + (*angley)=ArcTan(offseta,offsetz); + + if ((*angley)>=3072) (*angley)-=4096; + if ((*angley)>=2048) (*angley)=(*angley)-3072; + if ((*angley)> 1024) (*angley)=2048-(*angley); + + } + if (anglex) { + (*anglex)=ArcTan(offsetx,offsety); + + if ((*anglex)>=3072) (*anglex)-=4096; + if ((*anglex)>=2048) (*anglex)=(*anglex)-4096; + + } + } + +} + +void Execute_Xeno_Inactive(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + NPC_DATA *NpcData; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + NpcData=GetThisNpcData(I_NPC_Xenoborg); + + if (ShowXenoStats) { + PrintDebuggingText("In Inactive.\n"); + } + + if (!sbPtr->SBdptr) { + /* We're far... do the timer! */ + ProveHModel_Far(&xenoStatusPointer->HModelController,sbPtr); + } + + /* Regenerate a bit? */ + + if (sbPtr->SBDamageBlock.Health>0) { + int health_increment; + + health_increment=DIV_FIXED((NpcData->StartingStats.Health*NormalFrameTime),XENO_REGEN_TIME); + sbPtr->SBDamageBlock.Health+=health_increment; + + if (sbPtr->SBDamageBlock.Health>(NpcData->StartingStats.Health<SBDamageBlock.Health=(NpcData->StartingStats.Health<HModelController,XENO_REGEN_TIME); + } + + if (xenoStatusPointer->stateTimerstateTimer+=NormalFrameTime; + } else { + /* Tum te tum te tum. */ + + if (Xeno_Activation_Test(sbPtr)) { + /* Oh well, orange alert. */ + Xeno_Enter_PowerUp_State(sbPtr); + } + } +} + +void Xeno_Enter_PowerUp_State(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + if (xenoStatusPointer->behaviourState!=XS_Inactive) { + /* Ha! */ + return; + } + + xenoStatusPointer->Target=NULL; + xenoStatusPointer->stateTimer=0; + xenoStatusPointer->behaviourState=XS_Activating; + + GLOBALASSERT(xenoStatusPointer->HModelController.Sequence_Type==HMSQT_Xenoborg); + GLOBALASSERT(xenoStatusPointer->HModelController.Sub_Sequence==XBSS_Powered_Down_Standard); + + SetXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Power_Up,(ONE_FIXED*4),(ONE_FIXED>>2)); + + xenoStatusPointer->HModelController.LoopAfterTweening=0; + + Xenoborg_ActivateAllDeltas(sbPtr); + Xeno_SwitchLED(sbPtr,1); + + /* Now play with a sound. */ + + if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->soundHandle1); + } + if (xenoStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->soundHandle2); + } + Sound_Play(SID_POWERUP,"de",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1); +} + +void Xeno_Enter_PowerDown_State(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + if (xenoStatusPointer->behaviourState==XS_Inactive) { + /* Ha! */ + return; + } + + xenoStatusPointer->Target=NULL; + xenoStatusPointer->stateTimer=0; + xenoStatusPointer->behaviourState=XS_Deactivating; + + SetXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Power_Down,ONE_FIXED,(ONE_FIXED>>2)); + + xenoStatusPointer->HModelController.LoopAfterTweening=0; + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + Xenoborg_DeactivateAllDeltas(sbPtr); + Xeno_SwitchLED(sbPtr,0); + + if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->soundHandle1); + } + if (xenoStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) { + /* Stop BorgOn. */ + Sound_Stop(xenoStatusPointer->soundHandle2); + } + Sound_Play(SID_POWERDN,"de",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1); + +} + +void Xeno_Enter_ActiveWait_State(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + xenoStatusPointer->stateTimer=0; + xenoStatusPointer->behaviourState=XS_ActiveWait; + + SetXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED,(ONE_FIXED>>2)); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->soundHandle1); + } + +} + +void Xeno_Enter_TurnToFace_State(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + xenoStatusPointer->stateTimer=0; + xenoStatusPointer->behaviourState=XS_TurnToFace; + + /* Sequence handled in the behaviour. */ + + if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->soundHandle1); + } + Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + +} + +void Xeno_Enter_Following_State(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + xenoStatusPointer->stateTimer=0; + xenoStatusPointer->behaviourState=XS_Following; + InitWaypointManager(&xenoStatusPointer->waypointManager); + + /* Sequence handled in the behaviour. */ + + if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->soundHandle1); + } + Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1); + +} + +void Xeno_Enter_Returning_State(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + xenoStatusPointer->stateTimer=0; + xenoStatusPointer->behaviourState=XS_Returning; + InitWaypointManager(&xenoStatusPointer->waypointManager); + + /* Sequence handled in the behaviour. */ + + xenoStatusPointer->Target=NULL; + /* Forget your target, too. */ + + if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->soundHandle1); + } + Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1); + +} + +void Xeno_Enter_Dormant_State(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + xenoStatusPointer->stateTimer=0; + xenoStatusPointer->behaviourState=XS_Inactive; + + SetXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Down_Standard,ONE_FIXED,(ONE_FIXED>>2)); + + if (xenoStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->soundHandle2); + } + /* soundHandle1 might be still powering down. */ + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + +} + +void Xeno_Enter_Avoidance_State(STRATEGYBLOCK *sbPtr) { + + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Make sure obstruction is set! */ + + NPC_InitMovementData(&(xenoStatusPointer->moveData)); + NPCGetAvoidanceDirection(sbPtr, &(xenoStatusPointer->moveData.avoidanceDirn),&xenoStatusPointer->obstruction); + xenoStatusPointer->lastState=xenoStatusPointer->behaviourState; + xenoStatusPointer->behaviourState = XS_Avoidance; + xenoStatusPointer->stateTimer = NPC_AVOIDTIME; + InitWaypointManager(&xenoStatusPointer->waypointManager); + + if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->soundHandle1); + } + Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1); + +} + +void Xeno_Enter_ShootingTheRoof_State(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + xenoStatusPointer->stateTimer=0; + xenoStatusPointer->behaviourState=XS_ShootingTheRoof; + + /* Sequence handled in the behaviour. */ + + if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->soundHandle1); + } + Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + +} + +void Xeno_CopeWithLossOfHome(STRATEGYBLOCK *sbPtr) { + + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Ooh, yuck. */ + + xenoStatusPointer->my_module=sbPtr->containingModule->m_aimodule; + xenoStatusPointer->my_spot_therin=sbPtr->DynPtr->Position; + +} + +void Execute_Xeno_PowerUp(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Wait to finish, I guess... */ + + if (ShowXenoStats) { + PrintDebuggingText("In PowerUp.\n"); + } + + if (!sbPtr->SBdptr) { + /* We're far... do the timer! */ + ProveHModel_Far(&xenoStatusPointer->HModelController,sbPtr); + } + + xenoStatusPointer->Target=NULL; + xenoStatusPointer->stateTimer+=NormalFrameTime; + + if (xenoStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) { + if (xenoStatusPointer->stateTimer>((ONE_FIXED*5)/2)) { + /* Time to start the BorgOn sound. */ + Sound_Play(SID_BORGON,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle2); + } + } + if ((xenoStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(xenoStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) { + + Xeno_Enter_ActiveWait_State(sbPtr); + } + + +} + +void Execute_Xeno_PowerDown(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + if (ShowXenoStats) { + PrintDebuggingText("In PowerDown.\n"); + } + + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Power_Down,ONE_FIXED,(ONE_FIXED>>2)); + xenoStatusPointer->HModelController.LoopAfterTweening=0; + xenoStatusPointer->HModelController.Looped=0; + + if (!sbPtr->SBdptr) { + /* We're far... do the timer! */ + ProveHModel_Far(&xenoStatusPointer->HModelController,sbPtr); + } + + /* Wait to finish, I guess... */ + + xenoStatusPointer->Target=NULL; + + if ((xenoStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(xenoStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) { + + Xeno_Enter_Dormant_State(sbPtr); + } + + +} + +void Xeno_TurnAndTarget(STRATEGYBLOCK *sbPtr, int *ref_anglex,int *ref_angley) { + + XENO_STATUS_BLOCK *xenoStatusPointer; + int anglex,angley; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + { + SECTION_DATA *head_section; + + head_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"neck"); + GLOBALASSERT(head_section); + + Xenoborg_GetRelativeAngles(sbPtr,&anglex,&angley,&head_section->World_Offset); + + } + + *ref_anglex=anglex; + *ref_angley=angley; + + /* Start turning / targeting procedure. */ + #if 0 + if ((xenoStatusPointer->headLock) + ||(anglex>((((xenoStatusPointer->Torso_Twist>>4)+XENO_HEADPAN_GIMBALL)*7)/8)) + ||(anglex<((((xenoStatusPointer->Torso_Twist>>4)-XENO_HEADPAN_GIMBALL)*7)/8))) { + + Xeno_TorsoMovement_TrackToAngle(sbPtr,XENO_TORSO_TWIST_RATE,anglex); + + } + #else + /* Always torso twist. */ + Xeno_TorsoMovement_TrackToAngle(sbPtr,XENO_TORSO_TWIST_RATE,anglex); + #endif + xenoStatusPointer->headLock=Xeno_HeadMovement_TrackToAngles(sbPtr,XENO_HEAD_LOCK_RATE,anglex,angley); + + /* Now the arm. */ + + if ((xenoStatusPointer->headLock) + &&((anglex-XENO_LEFTARM_CW_GIMBALL))) { + + SECTION_DATA *this_section; + int arm_anglex,arm_angley; + + this_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"left bicep"); + if (this_section) { + Xenoborg_GetRelativeAngles(sbPtr,&arm_anglex,NULL,&this_section->World_Offset); + } else { + arm_anglex=0; + } + + this_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"left forearm"); + if (this_section) { + Xenoborg_GetRelativeAngles(sbPtr,NULL,&arm_angley,&this_section->World_Offset); + } else { + arm_angley=0; + } + + xenoStatusPointer->leftArmLock=Xeno_LeftArmMovement_TrackToAngles(sbPtr,XENO_ARM_LOCK_RATE,arm_anglex,arm_angley); + } + + if ((xenoStatusPointer->headLock) + &&((anglex-XENO_RIGHTARM_CW_GIMBALL))) { + + SECTION_DATA *this_section; + int arm_anglex,arm_angley; + + this_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"right bicep"); + if (this_section) { + Xenoborg_GetRelativeAngles(sbPtr,&arm_anglex,NULL,&this_section->World_Offset); + } else { + arm_anglex=0; + } + + this_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"right forearm"); + if (this_section) { + Xenoborg_GetRelativeAngles(sbPtr,NULL,&arm_angley,&this_section->World_Offset); + } else { + arm_angley=0; + } + xenoStatusPointer->rightArmLock=Xeno_RightArmMovement_TrackToAngles(sbPtr,XENO_ARM_LOCK_RATE,arm_anglex,arm_angley); + } + xenoStatusPointer->UseHeadLaser=1; +} + +void Xeno_Limbs_ShootTheRoof(STRATEGYBLOCK *sbPtr) { + + XENO_STATUS_BLOCK *xenoStatusPointer; + int anglex,angley; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + + Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); + Xeno_LeftArmMovement_WaveUp(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_LeftArmMovement_TrackLeftRight(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_RightArmMovement_WaveUp(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_RightArmMovement_TrackLeftRight(sbPtr,XENO_ARM_LOCK_RATE); + #if 0 + Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); + Xeno_HeadMovement_ScanUpDown(sbPtr,XENO_HEAD_SCAN_RATE+2); + #else + Xeno_HeadMovement_TrackToAngles(sbPtr,XENO_HEAD_SCAN_RATE,0,XENO_HEADTILT_GIMBALL); + #endif + xenoStatusPointer->UseHeadLaser=0; + xenoStatusPointer->UseRALaser=1; + xenoStatusPointer->UseLALaser=1; + xenoStatusPointer->FiringLeft=1; + xenoStatusPointer->FiringRight=1; + +} + +void Execute_Xeno_ActiveWait(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + int anglex,angley,correctlyOrientated; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* What to do? Do we have a target? */ + + if (ShowXenoStats) { + PrintDebuggingText("In ActiveWait.\n"); + } + + if (xenoStatusPointer->Target==NULL) { + /* Let's wave the head around. */ + Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); + Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); + Xeno_HeadMovement_ScanUpDown(sbPtr,XENO_HEAD_SCAN_RATE+2); + xenoStatusPointer->UseHeadLaser=1; + /* Are we at home? */ + if (sbPtr->containingModule->m_aimodule!=xenoStatusPointer->my_module) { + Xeno_Enter_Returning_State(sbPtr); + return; + } + /* Are we facing the right way? */ + + correctlyOrientated = NPCOrientateToVector(sbPtr, &xenoStatusPointer->my_orientdir_therin,(NPC_TURNRATE>>XENO_FOOT_TURN_RATE),NULL); + + if (!correctlyOrientated) { + + SECTION_DATA *master_section; + + master_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"pelvis presley"); + GLOBALASSERT(master_section); + + Xenoborg_GetRelativeAngles(sbPtr,&anglex,&angley,&master_section->World_Offset); + + if (anglex>0) { + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Right,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); + } else { + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Left,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); + } + if (xenoStatusPointer->soundHandle1==SOUND_NOACTIVEINDEX) { + Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1); + } + + } else { + + /* Otherwise just wait? */ + if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->soundHandle1); + } + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED,(ONE_FIXED>>2)); + xenoStatusPointer->stateTimer+=NormalFrameTime; + if (xenoStatusPointer->stateTimer>xenoStatusPointer->UpTime) { + Xeno_Enter_PowerDown_State(sbPtr); + /* Voluntary powerdown! */ + xenoStatusPointer->stateTimer=XENO_POWERDOWN_TIME; + } + } + return; + } + + GLOBALASSERT(xenoStatusPointer->Target); + xenoStatusPointer->stateTimer=0; + /* Now we have a target. Can we see it? */ + if (xenoStatusPointer->targetSightTest==0) { + /* Can't see them. Are we out of range? */ + if (GetNextModuleForLink(sbPtr->containingModule->m_aimodule, + xenoStatusPointer->my_module,(xenoStatusPointer->module_range)-1,0)==NULL) { + Xeno_Enter_Returning_State(sbPtr); + } else { + Xeno_Enter_Following_State(sbPtr); + } + return; + } + + Xeno_TurnAndTarget(sbPtr,&anglex,&angley); + + #if 0 + if ((anglex>(((XENO_HEADPAN_GIMBALL)*7)/8)) + ||(anglex<-(((XENO_HEADPAN_GIMBALL)*7)/8))) { + + Xeno_Enter_TurnToFace_State(sbPtr); + + } + #else + /* Always turn to face too? */ + Xeno_Enter_TurnToFace_State(sbPtr); + #endif + +} + +void Execute_Xeno_TurnToFace(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + int correctlyOrientated; + int anglex,angley; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Do we have a target? */ + + if (ShowXenoStats) { + PrintDebuggingText("In Turn To Face.\n"); + } + + if (xenoStatusPointer->Target==NULL) { + Xeno_Enter_ActiveWait_State(sbPtr); + /* Otherwise just wait? */ + return; + } + + /* Now we have a target. */ + GLOBALASSERT(xenoStatusPointer->Target); + + /* Set up animation... Which Way? */ + { + SECTION_DATA *master_section; + VECTORCH orientationDirn; + + master_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"pelvis presley"); + GLOBALASSERT(master_section); + + Xenoborg_GetRelativeAngles(sbPtr,&anglex,&angley,&master_section->World_Offset); + + if (anglex>0) { + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Right,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); + } else { + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Left,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); + } + + /* Then turn to face it, of course. */ + + orientationDirn.vx = xenoStatusPointer->targetTrackPos.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = xenoStatusPointer->targetTrackPos.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,(NPC_TURNRATE>>XENO_FOOT_TURN_RATE),NULL); + + } + + Xeno_TurnAndTarget(sbPtr,&anglex,&angley); + + if (angley>=XENO_HEADTILT_GIMBALL) { + Xeno_Enter_ShootingTheRoof_State(sbPtr); + return; + } + + if (correctlyOrientated) { + Xeno_Enter_ActiveWait_State(sbPtr); + } + +} + +void Execute_Xeno_ShootTheRoof(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + int correctlyOrientated; + int anglex,angley; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Do we have a target? */ + + if (ShowXenoStats) { + PrintDebuggingText("In Shoot The Roof.\n"); + } + + if ((xenoStatusPointer->Target==NULL)||(xenoStatusPointer->IAmFar)) { + Xeno_Enter_ActiveWait_State(sbPtr); + /* Otherwise just wait? */ + return; + } + + /* Now we have a target. */ + GLOBALASSERT(xenoStatusPointer->Target); + + /* Set up animation... Which Way? Keep TurnToFace functionality? */ + { + SECTION_DATA *master_section; + VECTORCH orientationDirn; + + master_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"pelvis presley"); + GLOBALASSERT(master_section); + + Xenoborg_GetRelativeAngles(sbPtr,&anglex,&angley,&master_section->World_Offset); + + anglex=512; + + if (anglex>0) { + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Right,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); + } else { + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Left,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); + } + + #if 0 + /* Then turn to face it, of course. */ + + orientationDirn.vx = xenoStatusPointer->targetTrackPos.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = xenoStatusPointer->targetTrackPos.vz - sbPtr->DynPtr->Position.vz; + #else + /* Synthesize a new orientationDirn. */ + orientationDirn.vx=sbPtr->DynPtr->OrientMat.mat11; + orientationDirn.vy=sbPtr->DynPtr->OrientMat.mat12; + orientationDirn.vz=sbPtr->DynPtr->OrientMat.mat13; + #endif + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,(NPC_TURNRATE>>XENO_FOOT_TURN_RATE),NULL); + + } + + Xeno_Limbs_ShootTheRoof(sbPtr); + + if (angleySBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* In theory, we're following the target, and can't see it. */ + + if (ShowXenoStats) { + PrintDebuggingText("In Follow.\n"); + } + + if (xenoStatusPointer->Target==NULL) { + /* Let's wave the head around. */ + Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); + /* Do we want to do this? */ + Xeno_HeadMovement_ScanUpDown(sbPtr,XENO_HEAD_SCAN_RATE+2); + xenoStatusPointer->UseHeadLaser=1; + /* And return to my module. */ + Xeno_Enter_Returning_State(sbPtr); + return; + } + + GLOBALASSERT(xenoStatusPointer->Target); + /* Now we know have a target. Can we see it yet? */ + + if (xenoStatusPointer->targetSightTest==0) { + + AIMODULE *targetModule; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + + /* Can't see them. Never mind. Go to the next module? */ + if (xenoStatusPointer->Target->containingModule==NULL) { + /* Fall through for now. */ + targetModule=NULL; + } else if (GetNextModuleForLink(sbPtr->containingModule->m_aimodule, + xenoStatusPointer->my_module,(xenoStatusPointer->module_range)-1,0)==NULL) { + /* Too Far! */ + Xeno_Enter_ActiveWait_State(sbPtr); + return; + } else { + /* Still in range: keep going. */ + targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule, + xenoStatusPointer->Target->containingModule->m_aimodule,xenoStatusPointer->module_range,0); + + } + + if (targetModule==NULL) { + /* They're way away. */ + Xeno_Enter_Returning_State(sbPtr); + return; + } + + if (targetModule==sbPtr->containingModule->m_aimodule) { + /* Good Grief, Penfold! He's right there, but I can't see him! */ + NPCGetMovementDirection(sbPtr, &velocityDirection, &xenoStatusPointer->targetTrackPos,&xenoStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, XENO_NEAR_SPEED); + targetPosition=xenoStatusPointer->targetTrackPos; + if (ShowXenoStats) { + PrintDebuggingText("Direct movement - no LOS.\n"); + } + /* Oh, well. Go to last known position? */ + } else { + thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); + if (!thisEp) { + LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.", + (*(targetModule->m_module_ptrs))->name, + sbPtr->containingModule->name)); + GLOBALASSERT(thisEp); + } + /* If that fired, there's a farped adjacency. */ + + xenoStatusPointer->wanderData.worldPosition=thisEp->position; + xenoStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx; + xenoStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy; + xenoStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz; + + NPCGetMovementDirection(sbPtr, &velocityDirection, &(xenoStatusPointer->wanderData.worldPosition),&xenoStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, XENO_NEAR_SPEED); + targetPosition=xenoStatusPointer->wanderData.worldPosition; + } + } else { + /* Re-aquired! Get a bit closer? */ + int range; + + if (GetNextModuleForLink(sbPtr->containingModule->m_aimodule, + xenoStatusPointer->my_module,(xenoStatusPointer->module_range)-1,0)==NULL) { + /* Too Far! */ + Xeno_Enter_ActiveWait_State(sbPtr); + return; + } + + range=VectorDistance((&xenoStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position)); + + if (range>XENO_CLOSE_APPROACH_DISTANCE) { + NPCGetMovementTarget(sbPtr, xenoStatusPointer->Target, &targetPosition, &targetIsAirduct,0); + NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&xenoStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, XENO_NEAR_SPEED); + if (ShowXenoStats) { + PrintDebuggingText("Direct movement - LOS Okay.\n"); + } + } else { + /* Return to ActiveWait. */ + Xeno_Enter_ActiveWait_State(sbPtr); + return; + } + + } + + #if 0 + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Walking,XENO_WALKING_ANIM_SPEED,(ONE_FIXED>>2)); + #else + XenoborgHandleMovingAnimation(sbPtr); + #endif + + if (xenoStatusPointer->targetSightTest==0) { + Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); + Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); + xenoStatusPointer->UseHeadLaser=1; + } else { + Xeno_TurnAndTarget(sbPtr,&anglex,&angley); + } + + /* test here for impeding collisions, and not being able to reach target... */ + { + STRATEGYBLOCK *destructableObject = NULL; + + NPC_IsObstructed(sbPtr,&(xenoStatusPointer->moveData),&xenoStatusPointer->obstruction,&destructableObject); + #if 1 + if(xenoStatusPointer->obstruction.environment) + { + /* go to avoidance */ + Xeno_Enter_Avoidance_State(sbPtr); + return; + } + #endif + if(xenoStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(xenoStatusPointer->moveData), &targetPosition, &velocityDirection)) + { + + xenoStatusPointer->obstruction.environment=1; + xenoStatusPointer->obstruction.destructableObject=0; + xenoStatusPointer->obstruction.otherCharacter=0; + xenoStatusPointer->obstruction.anySingleObstruction=0; + + Xeno_Enter_Avoidance_State(sbPtr); + return; + } + +} + +void Execute_Xeno_Return(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + VECTORCH velocityDirection = {0,0,0}; + VECTORCH *targetPosition=NULL; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* In theory, we're following the target, and can't see it. */ + + if (ShowXenoStats) { + PrintDebuggingText("In Return.\n"); + } + + if (xenoStatusPointer->Target!=NULL) { + /* Saw something! */ + /* Go to active wait. */ + Xeno_Enter_ActiveWait_State(sbPtr); + return; + } + + GLOBALASSERT(xenoStatusPointer->Target==NULL); + /* Find our way home. */ + + { + + AIMODULE *targetModule; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + + /* Go to the next module. */ + targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule, + xenoStatusPointer->my_module,xenoStatusPointer->module_range+2,0); + /* Just to be on the safe side. */ + + if (targetModule==NULL) { + /* Emergency! */ + targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule, + xenoStatusPointer->my_module,xenoStatusPointer->module_range+5,0); + if (targetModule==NULL) { + /* Totally broken. Stay here. */ + Xeno_CopeWithLossOfHome(sbPtr); + return; + } + } + + if (targetModule!=sbPtr->containingModule->m_aimodule) { + + thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); + if (!thisEp) { + LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.", + (*(targetModule->m_module_ptrs))->name, + sbPtr->containingModule->name)); + GLOBALASSERT(thisEp); + } + /* If that fired, there's a farped adjacency. */ + + xenoStatusPointer->wanderData.worldPosition=thisEp->position; + xenoStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx; + xenoStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy; + xenoStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz; + + NPCGetMovementDirection(sbPtr, &velocityDirection, &(xenoStatusPointer->wanderData.worldPosition),&xenoStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, XENO_NEAR_SPEED); + targetPosition=&(xenoStatusPointer->wanderData.worldPosition); + } else { + VECTORCH offset; + int dist; + /* In our own home module! */ + + offset.vx=sbPtr->DynPtr->Position.vx-xenoStatusPointer->my_spot_therin.vx; + offset.vy=sbPtr->DynPtr->Position.vy-xenoStatusPointer->my_spot_therin.vy; + offset.vz=sbPtr->DynPtr->Position.vz-xenoStatusPointer->my_spot_therin.vz; + /* Fix for midair start points, grrrr. */ + offset.vy>>=2; + + /* Find distance off spot. */ + dist=Approximate3dMagnitude(&offset); + + if (distmy_spot_therin),&xenoStatusPointer->waypointManager); + NPCSetVelocity(sbPtr, &velocityDirection, XENO_NEAR_SPEED); + targetPosition=&(xenoStatusPointer->my_spot_therin); + } + } + } + + #if 0 + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Walking,XENO_WALKING_ANIM_SPEED,(ONE_FIXED>>2)); + #else + XenoborgHandleMovingAnimation(sbPtr); + #endif + + Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); + Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); + xenoStatusPointer->UseHeadLaser=1; + + /* test here for impeding collisions, and not being able to reach target... */ + { + STRATEGYBLOCK *destructableObject = NULL; + + NPC_IsObstructed(sbPtr,&(xenoStatusPointer->moveData),&xenoStatusPointer->obstruction,&destructableObject); + #if 1 + if(xenoStatusPointer->obstruction.environment) + { + /* go to avoidance */ + Xeno_Enter_Avoidance_State(sbPtr); + return; + } + #endif + if(xenoStatusPointer->obstruction.destructableObject) + { + LOCALASSERT(destructableObject); + CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + if(NPC_CannotReachTarget(&(xenoStatusPointer->moveData), targetPosition, &velocityDirection)) + { + + xenoStatusPointer->obstruction.environment=1; + xenoStatusPointer->obstruction.destructableObject=0; + xenoStatusPointer->obstruction.otherCharacter=0; + xenoStatusPointer->obstruction.anySingleObstruction=0; + + Xeno_Enter_Avoidance_State(sbPtr); + return; + } + +} + +void Execute_Xeno_Avoidance(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + int terminateState = 0; + int anglex,angley; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + if (ShowXenoStats) { + PrintDebuggingText("In Avoidance.\n"); + } + + /* Sequences... */ + #if 0 + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Walking,XENO_WALKING_ANIM_SPEED,(ONE_FIXED>>2)); + #else + XenoborgHandleMovingAnimation(sbPtr); + #endif + + if (xenoStatusPointer->targetSightTest==0) { + Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); + Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); + xenoStatusPointer->UseHeadLaser=1; + } else { + Xeno_TurnAndTarget(sbPtr,&anglex,&angley); + } + + /* set velocity */ + LOCALASSERT((xenoStatusPointer->moveData.avoidanceDirn.vx!=0)|| + (xenoStatusPointer->moveData.avoidanceDirn.vy!=0)|| + (xenoStatusPointer->moveData.avoidanceDirn.vz!=0)); + NPCSetVelocity(sbPtr, &(xenoStatusPointer->moveData.avoidanceDirn), (XENO_NEAR_SPEED)); + + /* decrement state timer */ + xenoStatusPointer->stateTimer -= NormalFrameTime; + if(xenoStatusPointer->stateTimer <= 0) terminateState = 1; + + { + STRATEGYBLOCK *destructableObject = NULL; + NPC_OBSTRUCTIONREPORT obstruction; + NPC_IsObstructed(sbPtr,&(xenoStatusPointer->moveData),&obstruction,&destructableObject); + if(obstruction.anySingleObstruction) + { + terminateState = 1; + } + } + + if(terminateState) + { + + /* go to an appropriate state */ + switch (xenoStatusPointer->lastState) { + case XS_Returning: + Xeno_Enter_Returning_State(sbPtr); + return; + break; + case XS_Following: + Xeno_Enter_Following_State(sbPtr); + return; + break; + default: + Xeno_Enter_ActiveWait_State(sbPtr); + return; + break; + } + /* Still here? */ + return; + + } + return; +} + +int Xenoborg_TargetFilter(STRATEGYBLOCK *candidate) { + + /* Let's face it, Xenos shoot everything but other xenos. */ + switch (candidate->I_SBtype) { + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + { + if (Observer) { + return(0); + } + + switch(AvP.PlayerType) + { + case I_Alien: + case I_Predator: + case I_Marine: + return(1); + break; + default: + GLOBALASSERT(0); + return(0); + break; + } + break; + } + case I_BehaviourDummy: + { + DUMMY_STATUS_BLOCK *dummyStatusPointer; + dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(candidate->SBdataptr); + LOCALASSERT(dummyStatusPointer); + switch (dummyStatusPointer->PlayerType) { + case I_Marine: + case I_Predator: + case I_Alien: + return(1); + break; + default: + GLOBALASSERT(0); + return(0); + break; + } + break; + } + case I_BehaviourAlien: + { + if (NPC_IsDead(candidate)) { + return(0); + } else { + /* Are we inactive? */ + ALIEN_STATUS_BLOCK *asb=(ALIEN_STATUS_BLOCK *)candidate->SBdataptr; + GLOBALASSERT(asb); + if (asb->BehaviourState==ABS_Dormant) { + return(0); + } else { + return(1); + } + } + break; + } + case I_BehaviourQueenAlien: + case I_BehaviourFaceHugger: + case I_BehaviourPredator: + case I_BehaviourSeal: + case I_BehaviourPredatorAlien: + case I_BehaviourMarine: + { + if (NPC_IsDead(candidate)) { + return(0); + } else { + return(1); + } + break; + } + case I_BehaviourXenoborg: + return(0); + break; + #if SupportWindows95 + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *dataptr; + dataptr=candidate->SBdataptr; + switch (dataptr->type) { + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + return(1); + break; + default: + return(1); + break; + } + } + break; + #endif + default: + return(0); + break; + } + +} + +STRATEGYBLOCK *Xenoborg_GetNewTarget(VECTORCH *xenopos, STRATEGYBLOCK *me) { + + int neardist; + STRATEGYBLOCK *nearest; + int a; + STRATEGYBLOCK *candidate; + MODULE *dmod; + + dmod=ModuleFromPosition(xenopos,playerPherModule); + + LOCALASSERT(dmod); + + nearest=NULL; + neardist=ONE_FIXED; + + for (a=0; aDynPtr) { + if (Xenoborg_TargetFilter(candidate)) { + VECTORCH offset; + int dist; + + offset.vx=xenopos->vx-candidate->DynPtr->Position.vx; + offset.vy=xenopos->vy-candidate->DynPtr->Position.vy; + offset.vz=xenopos->vz-candidate->DynPtr->Position.vz; + + dist=Approximate3dMagnitude(&offset); + + if (distcontainingModule))) { + nearest=candidate; + } + } + } + } + } + } + } + } + + #if 0 + if (nearest==NULL) { + if (Xenoborg_TargetFilter(Player->ObStrategyBlock)) { + nearest=Player->ObStrategyBlock; + } else { + nearest=NULL; /* Erk! */ + } + } + #endif + + return(nearest); + +} + +static void ComputeDeltaValues(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + int angle; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Interpret all status block values, and apply to deltas. */ + /* Head Pan first. */ + + angle=xenoStatusPointer->Head_Pan>>4; + + if (angle>=3072) angle-=4096; + if (angle>=2048) angle=angle-4096; + + /* Now, we have an angle. */ + + if (angle>XENO_HEADPAN_GIMBALL) { + angle=XENO_HEADPAN_GIMBALL; + } else if (angle<-XENO_HEADPAN_GIMBALL) { + angle=-XENO_HEADPAN_GIMBALL; + } + + #if 0 + angle=angle*2; + + GLOBALASSERT(xenoStatusPointer->head_pan); + + { + int fake_timer; + + fake_timer=1024-angle; + fake_timer<<=5; + if (fake_timer==65536) fake_timer=65535; + #else + GLOBALASSERT(xenoStatusPointer->head_pan); + + { + int fake_timer; + + fake_timer=DIV_FIXED(angle,(XENO_HEADPAN_GIMBALL<<1)); + fake_timer+=32767; + fake_timer=65536-fake_timer; + if (fake_timer>=65536) fake_timer=65535; + if (fake_timer<=0) fake_timer=0; + + #endif + + GLOBALASSERT(fake_timer>=0); + GLOBALASSERT(fake_timer<65536); + + xenoStatusPointer->head_pan->timer=fake_timer; + + } + + /* Head tilt next. */ + angle=xenoStatusPointer->Head_Tilt>>4; + + if (angle>=3072) angle-=4096; + if (angle>=2048) angle=angle-3072; + if (angle> 1024) angle=2048-angle; + + /* Now, we have an angle. */ + + if (angle>XENO_HEADTILT_GIMBALL) { + angle=XENO_HEADTILT_GIMBALL; + } else if (angle<-XENO_HEADTILT_GIMBALL) { + angle=-XENO_HEADTILT_GIMBALL; + } + + angle=angle*2; + + GLOBALASSERT(angle>=-1024); + GLOBALASSERT(angle<=1024); + + GLOBALASSERT(xenoStatusPointer->head_tilt); + + { + int fake_timer; + + fake_timer=1024-angle; + fake_timer<<=5; + if (fake_timer==65536) fake_timer=65535; + + GLOBALASSERT(fake_timer>=0); + GLOBALASSERT(fake_timer<65536); + + xenoStatusPointer->head_tilt->timer=fake_timer; + + } + + /* Left Arm Pan now. */ + + angle=xenoStatusPointer->Left_Arm_Pan>>4; + + if (angle>=3072) angle-=4096; + if (angle>=2048) angle=angle-4096; + + GLOBALASSERT(xenoStatusPointer->left_arm_pan); + + /* Now, we have an angle. */ + + if (angle>XENO_LEFTARM_ACW_GIMBALL) { + angle=XENO_LEFTARM_ACW_GIMBALL; + } else if (angle<-XENO_LEFTARM_CW_GIMBALL) { + angle=-XENO_LEFTARM_CW_GIMBALL; + } + + { + int fake_timer; + + if (angle>0) { + + fake_timer=DIV_FIXED(angle,(XENO_LEFTARM_ACW_GIMBALL<<1)); + fake_timer+=32767; + fake_timer=65536-fake_timer; + if (fake_timer>=65536) fake_timer=65535; + if (fake_timer<=0) fake_timer=0; + + } else { + + fake_timer=DIV_FIXED(angle,(XENO_LEFTARM_CW_GIMBALL<<1)); + fake_timer+=32767; + fake_timer=65536-fake_timer; + if (fake_timer>=65536) fake_timer=65535; + if (fake_timer<=0) fake_timer=0; + + } + + GLOBALASSERT(fake_timer>=0); + GLOBALASSERT(fake_timer<65536); + + xenoStatusPointer->left_arm_pan->timer=fake_timer; + + } + + /* Left Arm Tilt... */ + + angle=xenoStatusPointer->Left_Arm_Tilt>>4; + + if (angle>=3072) angle-=4096; + if (angle>=2048) angle=angle-3072; + if (angle> 1024) angle=2048-angle; + + GLOBALASSERT(xenoStatusPointer->left_arm_tilt); + + /* Now, we have an angle. */ + + if (angle>XENO_ARM_PITCH_GIMBALL) { + angle=XENO_ARM_PITCH_GIMBALL; + } else if (angle<-XENO_ARM_PITCH_GIMBALL) { + angle=-XENO_ARM_PITCH_GIMBALL; + } + + GLOBALASSERT(angle>=-1024); + GLOBALASSERT(angle<=1024); + + { + int fake_timer; + + fake_timer=1024-angle; + fake_timer<<=5; + if (fake_timer==65536) fake_timer=65535; + + GLOBALASSERT(fake_timer>=0); + GLOBALASSERT(fake_timer<65536); + + xenoStatusPointer->left_arm_tilt->timer=fake_timer; + + } + + /* Right Arm Pan now. */ + + angle=xenoStatusPointer->Right_Arm_Pan>>4; + + if (angle>=3072) angle-=4096; + if (angle>=2048) angle=angle-4096; + + GLOBALASSERT(xenoStatusPointer->right_arm_pan); + + /* Now, we have an angle. */ + + if (angle>XENO_RIGHTARM_ACW_GIMBALL) { + angle=XENO_RIGHTARM_ACW_GIMBALL; + } else if (angle<-XENO_RIGHTARM_CW_GIMBALL) { + angle=-XENO_RIGHTARM_CW_GIMBALL; + } + + { + int fake_timer; + + if (angle>0) { + + fake_timer=DIV_FIXED(angle,(XENO_RIGHTARM_ACW_GIMBALL<<1)); + fake_timer+=32767; + if (fake_timer>=65536) fake_timer=65535; + + } else { + + fake_timer=DIV_FIXED(angle,(XENO_RIGHTARM_CW_GIMBALL<<1)); + fake_timer+=32767; + if (fake_timer<=0) fake_timer=0; + + } + + GLOBALASSERT(fake_timer>=0); + GLOBALASSERT(fake_timer<65536); + + xenoStatusPointer->right_arm_pan->timer=fake_timer; + + } + + /* Right Arm Tilt... */ + + angle=xenoStatusPointer->Right_Arm_Tilt>>4; + + if (angle>=3072) angle-=4096; + if (angle>=2048) angle=angle-3072; + if (angle> 1024) angle=2048-angle; + + GLOBALASSERT(xenoStatusPointer->right_arm_pan); + + /* Now, we have an angle. */ + + if (angle>XENO_ARM_PITCH_GIMBALL) { + angle=XENO_ARM_PITCH_GIMBALL; + } else if (angle<-XENO_ARM_PITCH_GIMBALL) { + angle=-XENO_ARM_PITCH_GIMBALL; + } + + GLOBALASSERT(angle>=-1024); + GLOBALASSERT(angle<=1024); + + { + int fake_timer; + + fake_timer=1024-angle; + fake_timer<<=5; + if (fake_timer==65536) fake_timer=65535; + + GLOBALASSERT(fake_timer>=0); + GLOBALASSERT(fake_timer<65536); + + xenoStatusPointer->right_arm_tilt->timer=fake_timer; + + } + + /* ... and Torso Twist. */ + + angle=xenoStatusPointer->Torso_Twist>>4; + + if (angle>=3072) angle-=4096; + if (angle>=2048) angle=angle-4096; + + GLOBALASSERT(xenoStatusPointer->torso_twist); + + /* Now, we have an angle. */ + + if (angle>XENO_TORSO_GIMBALL) { + angle=XENO_TORSO_GIMBALL; + } else if (angle<-XENO_TORSO_GIMBALL) { + angle=-XENO_TORSO_GIMBALL; + } + + { + int fake_timer; + + if (angle>0) { + + fake_timer=DIV_FIXED(angle,(XENO_TORSO_GIMBALL<<1)); + fake_timer+=32767; + if (fake_timer>=65536) fake_timer=65535; + + } else { + + fake_timer=DIV_FIXED(angle,(XENO_TORSO_GIMBALL<<1)); + fake_timer+=32767; + if (fake_timer<=0) fake_timer=0; + + } + + GLOBALASSERT(fake_timer>=0); + GLOBALASSERT(fake_timer<65536); + + xenoStatusPointer->torso_twist->timer=fake_timer; + + } + +} + +void Xeno_HeadMovement_ScanLeftRight(STRATEGYBLOCK *sbPtr,int rate) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Let's wave the head around. */ + if (xenoStatusPointer->headpandir) { + xenoStatusPointer->Head_Pan+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Head_Pan>(XENO_HEADPAN_GIMBALL<<4)) { + xenoStatusPointer->Head_Pan=(XENO_HEADPAN_GIMBALL<<4); + xenoStatusPointer->headpandir=0; + } else { + xenoStatusPointer->head_moving=1; + } + } else { + xenoStatusPointer->Head_Pan-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Head_Pan<-(XENO_HEADPAN_GIMBALL<<4)) { + xenoStatusPointer->Head_Pan=-(XENO_HEADPAN_GIMBALL<<4); + xenoStatusPointer->headpandir=1; + } else { + xenoStatusPointer->head_moving=1; + } + } + if (xenoStatusPointer->head_pan) { + xenoStatusPointer->head_pan->Active=1; + } + +} + +void Xeno_HeadMovement_ScanUpDown(STRATEGYBLOCK *sbPtr,int rate) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Let's wave the head around. */ + if (xenoStatusPointer->headtiltdir) { + xenoStatusPointer->Head_Tilt+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Head_Tilt>(XENO_HEADTILT_GIMBALL<<4)) { + xenoStatusPointer->Head_Tilt=(XENO_HEADTILT_GIMBALL<<4); + xenoStatusPointer->headtiltdir=0; + } else { + xenoStatusPointer->head_moving=1; + } + } else { + xenoStatusPointer->Head_Tilt-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Head_Tilt<-(XENO_HEADTILT_GIMBALL<<4)) { + xenoStatusPointer->Head_Tilt=-(XENO_HEADTILT_GIMBALL<<4); + xenoStatusPointer->headtiltdir=1; + } else { + xenoStatusPointer->head_moving=1; + } + } + if (xenoStatusPointer->head_tilt) { + xenoStatusPointer->head_tilt->Active=1; + } + +} + +void Xeno_LeftArmMovement_TrackLeftRight(STRATEGYBLOCK *sbPtr,int rate) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Let's wave the left arm around. */ + if (xenoStatusPointer->leftarmpandir) { + xenoStatusPointer->Left_Arm_Pan+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Left_Arm_Pan>(XENO_LEFTARM_ACW_GIMBALL<<4)) { + xenoStatusPointer->Left_Arm_Pan=(XENO_LEFTARM_ACW_GIMBALL<<4); + xenoStatusPointer->leftarmpandir=0; + } else { + xenoStatusPointer->la_moving=1; + } + } else { + xenoStatusPointer->Left_Arm_Pan-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Left_Arm_Pan<-(XENO_LEFTARM_CW_GIMBALL<<4)) { + xenoStatusPointer->Left_Arm_Pan=-(XENO_LEFTARM_CW_GIMBALL<<4); + xenoStatusPointer->leftarmpandir=1; + } else { + xenoStatusPointer->la_moving=1; + } + } + + if (xenoStatusPointer->left_arm_pan) { + xenoStatusPointer->left_arm_pan->Active=1; + } + +} + +void Xeno_LeftArmMovement_TrackUpDown(STRATEGYBLOCK *sbPtr,int rate) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Let's wave the left arm around. */ + if (xenoStatusPointer->leftarmtiltdir) { + xenoStatusPointer->Left_Arm_Tilt+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Left_Arm_Tilt>(XENO_ARM_PITCH_GIMBALL<<4)) { + xenoStatusPointer->Left_Arm_Tilt=(XENO_ARM_PITCH_GIMBALL<<4); + xenoStatusPointer->leftarmtiltdir=0; + } else { + xenoStatusPointer->la_moving=1; + } + } else { + xenoStatusPointer->Left_Arm_Tilt-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Left_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) { + xenoStatusPointer->Left_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4); + xenoStatusPointer->leftarmtiltdir=1; + } else { + xenoStatusPointer->la_moving=1; + } + } + + if (xenoStatusPointer->left_arm_tilt) { + xenoStatusPointer->left_arm_tilt->Active=1; + } + +} + +void Xeno_LeftArmMovement_WaveUp(STRATEGYBLOCK *sbPtr,int rate) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Let's wave the left arm around. */ + if (xenoStatusPointer->leftarmtiltdir) { + xenoStatusPointer->Left_Arm_Tilt+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Left_Arm_Tilt>-(XENO_HEADTILT_GIMBALL<<4)) { + xenoStatusPointer->Left_Arm_Tilt=-(XENO_HEADTILT_GIMBALL<<4); + xenoStatusPointer->leftarmtiltdir=0; + } else { + xenoStatusPointer->la_moving=1; + } + } else { + xenoStatusPointer->Left_Arm_Tilt-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Left_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) { + xenoStatusPointer->Left_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4); + xenoStatusPointer->leftarmtiltdir=1; + } else { + xenoStatusPointer->la_moving=1; + } + } + + if (xenoStatusPointer->left_arm_tilt) { + xenoStatusPointer->left_arm_tilt->Active=1; + } + +} + +void Xeno_RightArmMovement_TrackLeftRight(STRATEGYBLOCK *sbPtr,int rate) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Let's wave the Right arm around. */ + if (xenoStatusPointer->rightarmpandir) { + xenoStatusPointer->Right_Arm_Pan+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Right_Arm_Pan>(XENO_RIGHTARM_ACW_GIMBALL<<4)) { + xenoStatusPointer->Right_Arm_Pan=(XENO_RIGHTARM_ACW_GIMBALL<<4); + xenoStatusPointer->rightarmpandir=0; + } else { + xenoStatusPointer->ra_moving=1; + } + } else { + xenoStatusPointer->Right_Arm_Pan-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Right_Arm_Pan<-(XENO_RIGHTARM_CW_GIMBALL<<4)) { + xenoStatusPointer->Right_Arm_Pan=-(XENO_RIGHTARM_CW_GIMBALL<<4); + xenoStatusPointer->rightarmpandir=1; + } else { + xenoStatusPointer->ra_moving=1; + } + } + + if (xenoStatusPointer->right_arm_pan) { + xenoStatusPointer->right_arm_pan->Active=1; + } + +} + +void Xeno_RightArmMovement_TrackUpDown(STRATEGYBLOCK *sbPtr,int rate) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Let's wave the Right arm around. */ + if (xenoStatusPointer->rightarmtiltdir) { + xenoStatusPointer->Right_Arm_Tilt+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Right_Arm_Tilt>(XENO_ARM_PITCH_GIMBALL<<4)) { + xenoStatusPointer->Right_Arm_Tilt=(XENO_ARM_PITCH_GIMBALL<<4); + xenoStatusPointer->rightarmtiltdir=0; + } else { + xenoStatusPointer->ra_moving=1; + } + } else { + xenoStatusPointer->Right_Arm_Tilt-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Right_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) { + xenoStatusPointer->Right_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4); + xenoStatusPointer->rightarmtiltdir=1; + } else { + xenoStatusPointer->ra_moving=1; + } + } + + if (xenoStatusPointer->right_arm_tilt) { + xenoStatusPointer->right_arm_tilt->Active=1; + } + +} + +void Xeno_RightArmMovement_WaveUp(STRATEGYBLOCK *sbPtr,int rate) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Let's wave the Right arm around. */ + if (xenoStatusPointer->rightarmtiltdir) { + xenoStatusPointer->Right_Arm_Tilt+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Right_Arm_Tilt>-(XENO_HEADTILT_GIMBALL<<4)) { + xenoStatusPointer->Right_Arm_Tilt=-(XENO_HEADTILT_GIMBALL<<4); + xenoStatusPointer->rightarmtiltdir=0; + } else { + xenoStatusPointer->ra_moving=1; + } + } else { + xenoStatusPointer->Right_Arm_Tilt-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Right_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) { + xenoStatusPointer->Right_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4); + xenoStatusPointer->rightarmtiltdir=1; + } else { + xenoStatusPointer->ra_moving=1; + } + } + + if (xenoStatusPointer->right_arm_tilt) { + xenoStatusPointer->right_arm_tilt->Active=1; + } + +} + +void Xeno_TorsoMovement_TrackLeftRight(STRATEGYBLOCK *sbPtr,int rate) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Let's twist the torso. */ + if (xenoStatusPointer->torsotwistdir) { + xenoStatusPointer->Torso_Twist+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Torso_Twist>(XENO_TORSO_GIMBALL<<4)) { + xenoStatusPointer->Torso_Twist=(XENO_TORSO_GIMBALL<<4); + xenoStatusPointer->torsotwistdir=0; + } else { + xenoStatusPointer->torso_moving=1; + } + } else { + xenoStatusPointer->Torso_Twist-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Torso_Twist<-(XENO_TORSO_GIMBALL<<4)) { + xenoStatusPointer->Torso_Twist=-(XENO_TORSO_GIMBALL<<4); + xenoStatusPointer->torsotwistdir=1; + } else { + xenoStatusPointer->torso_moving=1; + } + } + + if (xenoStatusPointer->right_arm_tilt) { + xenoStatusPointer->right_arm_tilt->Active=1; + } + +} + +int Xeno_HeadMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + int real_anglex,angley,online; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Turn the head to face a certain way. */ + + real_anglex=in_anglex-(xenoStatusPointer->Torso_Twist>>4); + angley=in_angley; + online=0; + + /* Now fix multiples. */ + while ((real_anglex>4095)||(real_anglex<0)) { + if (real_anglex<0) { + real_anglex+=4096; + } else if (real_anglex>4095) { + real_anglex-=4096; + } + } + + if (real_anglex>=3072) real_anglex-=4096; + if (real_anglex>=2048) real_anglex=real_anglex-3072; + if (real_anglex> 1024) real_anglex=2048-real_anglex; + + if (angley>=3072) angley-=4096; + if (angley>=2048) angley=angley-3072; + if (angley> 1024) angley=2048-angley; + + GLOBALASSERT((real_anglex<=1024)&&(real_anglex>=-1024)); + GLOBALASSERT((angley<=1024)&&(angley>=-1024)); + + if (ShowXenoStats) { + PrintDebuggingText("Target head angles: %d %d\n",real_anglex,angley); + } + + real_anglex<<=4; + angley<<=4; + + if (xenoStatusPointer->Head_PanHead_Pan+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Head_Pan>(XENO_HEADPAN_GIMBALL<<4)) { + xenoStatusPointer->Head_Pan=(XENO_HEADPAN_GIMBALL<<4); + } else if (xenoStatusPointer->Head_Pan>real_anglex) { + xenoStatusPointer->Head_Pan=real_anglex; + online++; + } + } else if (xenoStatusPointer->Head_Pan>real_anglex) { + xenoStatusPointer->Head_Pan-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Head_Pan<-(XENO_HEADPAN_GIMBALL<<4)) { + xenoStatusPointer->Head_Pan=-(XENO_HEADPAN_GIMBALL<<4); + } else if (xenoStatusPointer->Head_PanHead_Pan=real_anglex; + online++; + } + } else { + online++; + } + + if (xenoStatusPointer->head_pan) { + xenoStatusPointer->head_pan->Active=1; + } + + /* Now y. */ + angley=-angley; + /* Oops. */ + + if (xenoStatusPointer->Head_TiltHead_Tilt+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Head_Tilt>(XENO_HEADTILT_GIMBALL<<4)) { + xenoStatusPointer->Head_Tilt=(XENO_HEADTILT_GIMBALL<<4); + } else if (xenoStatusPointer->Head_Tilt>angley) { + xenoStatusPointer->Head_Tilt=angley; + online++; + } + } else if (xenoStatusPointer->Head_Tilt>angley) { + xenoStatusPointer->Head_Tilt-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Head_Tilt<-(XENO_HEADTILT_GIMBALL<<4)) { + xenoStatusPointer->Head_Tilt=-(XENO_HEADTILT_GIMBALL<<4); + } else if (xenoStatusPointer->Head_TiltHead_Tilt=angley; + online++; + } + } else { + online++; + } + + if (xenoStatusPointer->head_tilt) { + xenoStatusPointer->head_tilt->Active=1; + } + + if (online<=1) { + /* Still moving! */ + xenoStatusPointer->head_moving=1; + } + + if (xenoStatusPointer->HeadLaserOnTarget) { + online=2; + } + + if (online>1) { + return(1); + } else { + return(0); + } +} + +void Xeno_TorsoMovement_TrackToAngle(STRATEGYBLOCK *sbPtr,int rate,int in_anglex) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + int anglex; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Turn the torso to face a certain way. No angley here. */ + + anglex=in_anglex; + + if (anglex>=3072) anglex-=4096; + if (anglex>=2048) anglex=anglex-3072; + if (anglex> 1024) anglex=2048-anglex; + + anglex<<=4; + + if (xenoStatusPointer->Torso_TwistTorso_Twist+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Torso_Twist>(XENO_TORSO_GIMBALL<<4)) { + xenoStatusPointer->Torso_Twist=(XENO_TORSO_GIMBALL<<4); + } else if (xenoStatusPointer->Torso_Twist>anglex) { + xenoStatusPointer->Torso_Twist=anglex; + } else { + xenoStatusPointer->torso_moving=1; + } + } else if (xenoStatusPointer->Torso_Twist>anglex) { + xenoStatusPointer->Torso_Twist-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Torso_Twist<-(XENO_TORSO_GIMBALL<<4)) { + xenoStatusPointer->Torso_Twist=-(XENO_TORSO_GIMBALL<<4); + } else if (xenoStatusPointer->Torso_TwistTorso_Twist=anglex; + } else { + xenoStatusPointer->torso_moving=1; + } + } + + if (xenoStatusPointer->torso_twist) { + xenoStatusPointer->torso_twist->Active=1; + } + +} + +void Xeno_TorsoMovement_Centre(STRATEGYBLOCK *sbPtr,int rate) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Turn the torso to face a certain way. No angley here. */ + + if (xenoStatusPointer->Torso_Twist<0) { + xenoStatusPointer->Torso_Twist+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Torso_Twist>(XENO_TORSO_GIMBALL<<4)) { + xenoStatusPointer->Torso_Twist=(XENO_TORSO_GIMBALL<<4); + } else if (xenoStatusPointer->Torso_Twist>0) { + xenoStatusPointer->Torso_Twist=0; + } else { + xenoStatusPointer->torso_moving=1; + } + } else if (xenoStatusPointer->Torso_Twist>0) { + xenoStatusPointer->Torso_Twist-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Torso_Twist<-(XENO_TORSO_GIMBALL<<4)) { + xenoStatusPointer->Torso_Twist=-(XENO_TORSO_GIMBALL<<4); + } else if (xenoStatusPointer->Torso_Twist<0) { + xenoStatusPointer->Torso_Twist=0; + } else { + xenoStatusPointer->torso_moving=1; + } + } + + if (xenoStatusPointer->torso_twist) { + xenoStatusPointer->torso_twist->Active=1; + } + +} + +int Xeno_LeftArmMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + int real_anglex,angley,online; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Aim the Left Arm at a point. */ + + real_anglex=in_anglex-(xenoStatusPointer->Torso_Twist>>4); + angley=in_angley; + online=0; + + /* Now fix multiples. */ + while ((real_anglex>4095)||(real_anglex<0)) { + if (real_anglex<0) { + real_anglex+=4096; + } else if (real_anglex>4095) { + real_anglex-=4096; + } + } + + if (real_anglex>=3072) real_anglex-=4096; + if (real_anglex>=2048) real_anglex=real_anglex-3072; + if (real_anglex> 1024) real_anglex=2048-real_anglex; + + if (angley>=3072) angley-=4096; + if (angley>=2048) angley=angley-3072; + if (angley> 1024) angley=2048-angley; + + real_anglex<<=4; + angley<<=4; + + if (xenoStatusPointer->Left_Arm_PanLeft_Arm_Pan+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Left_Arm_Pan>(XENO_LEFTARM_ACW_GIMBALL<<4)) { + xenoStatusPointer->Left_Arm_Pan=(XENO_LEFTARM_ACW_GIMBALL<<4); + } else if (xenoStatusPointer->Left_Arm_Pan>real_anglex) { + xenoStatusPointer->Left_Arm_Pan=real_anglex; + online++; + } + } else if (xenoStatusPointer->Left_Arm_Pan>real_anglex) { + xenoStatusPointer->Left_Arm_Pan-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Left_Arm_Pan<-(XENO_LEFTARM_CW_GIMBALL<<4)) { + xenoStatusPointer->Left_Arm_Pan=-(XENO_LEFTARM_CW_GIMBALL<<4); + } else if (xenoStatusPointer->Left_Arm_PanLeft_Arm_Pan=real_anglex; + online++; + } + } else { + online++; + } + + if (xenoStatusPointer->left_arm_pan) { + xenoStatusPointer->left_arm_pan->Active=1; + } + + /* Now y. */ + angley=-angley; + /* Oops. */ + + if (xenoStatusPointer->Left_Arm_TiltLeft_Arm_Tilt+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Left_Arm_Tilt>(XENO_ARM_PITCH_GIMBALL<<4)) { + xenoStatusPointer->Left_Arm_Tilt=(XENO_ARM_PITCH_GIMBALL<<4); + } else if (xenoStatusPointer->Left_Arm_Tilt>angley) { + xenoStatusPointer->Left_Arm_Tilt=angley; + online++; + } + } else if (xenoStatusPointer->Left_Arm_Tilt>angley) { + xenoStatusPointer->Left_Arm_Tilt-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Left_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) { + xenoStatusPointer->Left_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4); + } else if (xenoStatusPointer->Left_Arm_TiltLeft_Arm_Tilt=angley; + online++; + } + } else { + online++; + } + + if (xenoStatusPointer->left_arm_tilt) { + xenoStatusPointer->left_arm_tilt->Active=1; + } + + if (online<=1) { + /* Still going! */ + xenoStatusPointer->la_moving=1; + } + + if (xenoStatusPointer->HeadLaserOnTarget) { + xenoStatusPointer->UseLALaser=1; + } + + if (xenoStatusPointer->LALaserOnTarget) { + online=2; + } + + if (online>1) { + if (xenoStatusPointer->Target) { + /* What the heck! */ + xenoStatusPointer->FiringLeft=1; + } + return(1); + } else { + return(0); + } + +} + +void Xeno_LeftArmMovement_Centre(STRATEGYBLOCK *sbPtr,int rate) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Centre the Left Arm. */ + + if (xenoStatusPointer->Left_Arm_Pan<0) { + xenoStatusPointer->Left_Arm_Pan+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Left_Arm_Pan>(XENO_LEFTARM_ACW_GIMBALL<<4)) { + xenoStatusPointer->Left_Arm_Pan=(XENO_LEFTARM_ACW_GIMBALL<<4); + } else if (xenoStatusPointer->Left_Arm_Pan>0) { + xenoStatusPointer->Left_Arm_Pan=0; + } else { + xenoStatusPointer->la_moving=1; + } + } else if (xenoStatusPointer->Left_Arm_Pan>0) { + xenoStatusPointer->Left_Arm_Pan-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Left_Arm_Pan<-(XENO_LEFTARM_CW_GIMBALL<<4)) { + xenoStatusPointer->Left_Arm_Pan=-(XENO_LEFTARM_CW_GIMBALL<<4); + } else if (xenoStatusPointer->Left_Arm_Pan<0) { + xenoStatusPointer->Left_Arm_Pan=0; + } else { + xenoStatusPointer->la_moving=1; + } + } + + if (xenoStatusPointer->left_arm_pan) { + xenoStatusPointer->left_arm_pan->Active=1; + } + + /* Now y. */ + + if (xenoStatusPointer->Left_Arm_Tilt<0) { + xenoStatusPointer->Left_Arm_Tilt+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Left_Arm_Tilt>(XENO_ARM_PITCH_GIMBALL<<4)) { + xenoStatusPointer->Left_Arm_Tilt=(XENO_ARM_PITCH_GIMBALL<<4); + } else if (xenoStatusPointer->Left_Arm_Tilt>0) { + xenoStatusPointer->Left_Arm_Tilt=0; + } else { + xenoStatusPointer->la_moving=1; + } + } else if (xenoStatusPointer->Left_Arm_Tilt>0) { + xenoStatusPointer->Left_Arm_Tilt-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Left_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) { + xenoStatusPointer->Left_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4); + } else if (xenoStatusPointer->Left_Arm_Tilt<0) { + xenoStatusPointer->Left_Arm_Tilt=0; + } else { + xenoStatusPointer->la_moving=1; + } + } + + if (xenoStatusPointer->left_arm_tilt) { + xenoStatusPointer->left_arm_tilt->Active=1; + } + + return; + +} + +int Xeno_RightArmMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + int real_anglex,angley,online; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Aim the Right Arm at a point. */ + + real_anglex=in_anglex-(xenoStatusPointer->Torso_Twist>>4)+RATweak; + angley=in_angley; + online=0; + + /* Now fix multiples. */ + while ((real_anglex>4095)||(real_anglex<0)) { + if (real_anglex<0) { + real_anglex+=4096; + } else if (real_anglex>4095) { + real_anglex-=4096; + } + } + + if (real_anglex>=3072) real_anglex-=4096; + if (real_anglex>=2048) real_anglex=real_anglex-3072; + if (real_anglex> 1024) real_anglex=2048-real_anglex; + + if (angley>=3072) angley-=4096; + if (angley>=2048) angley=angley-3072; + if (angley> 1024) angley=2048-angley; + + real_anglex<<=4; + angley<<=4; + + if (xenoStatusPointer->Right_Arm_PanRight_Arm_Pan+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Right_Arm_Pan>(XENO_RIGHTARM_ACW_GIMBALL<<4)) { + xenoStatusPointer->Right_Arm_Pan=(XENO_RIGHTARM_ACW_GIMBALL<<4); + } else if (xenoStatusPointer->Right_Arm_Pan>real_anglex) { + xenoStatusPointer->Right_Arm_Pan=real_anglex; + online++; + } + } else if (xenoStatusPointer->Right_Arm_Pan>real_anglex) { + xenoStatusPointer->Right_Arm_Pan-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Right_Arm_Pan<-(XENO_RIGHTARM_CW_GIMBALL<<4)) { + xenoStatusPointer->Right_Arm_Pan=-(XENO_RIGHTARM_CW_GIMBALL<<4); + } else if (xenoStatusPointer->Right_Arm_PanRight_Arm_Pan=real_anglex; + online++; + } + } else { + online++; + } + + if (xenoStatusPointer->right_arm_pan) { + xenoStatusPointer->right_arm_pan->Active=1; + } + + /* Now y. */ + angley=-angley; + /* Oops. */ + + if (xenoStatusPointer->Right_Arm_TiltRight_Arm_Tilt+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Right_Arm_Tilt>(XENO_ARM_PITCH_GIMBALL<<4)) { + xenoStatusPointer->Right_Arm_Tilt=(XENO_ARM_PITCH_GIMBALL<<4); + } else if (xenoStatusPointer->Right_Arm_Tilt>angley) { + xenoStatusPointer->Right_Arm_Tilt=angley; + online++; + } + } else if (xenoStatusPointer->Right_Arm_Tilt>angley) { + xenoStatusPointer->Right_Arm_Tilt-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Right_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) { + xenoStatusPointer->Right_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4); + } else if (xenoStatusPointer->Right_Arm_TiltRight_Arm_Tilt=angley; + online++; + } + } else { + online++; + } + + if (xenoStatusPointer->right_arm_tilt) { + xenoStatusPointer->right_arm_tilt->Active=1; + } + + if (online<=1) { + /* Still moving! */ + xenoStatusPointer->ra_moving=1; + } + + if (xenoStatusPointer->HeadLaserOnTarget) { + xenoStatusPointer->UseRALaser=1; + } + + if (xenoStatusPointer->RALaserOnTarget) { + online=2; + } + + if (online>1) { + if (xenoStatusPointer->Target) { + /* What the heck! */ + xenoStatusPointer->FiringRight=1; + } + return(1); + } else { + return(0); + } + +} + +void Xeno_RightArmMovement_Centre(STRATEGYBLOCK *sbPtr,int rate) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Centre the Right Arm. */ + + if (xenoStatusPointer->Right_Arm_Pan<0) { + xenoStatusPointer->Right_Arm_Pan+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Right_Arm_Pan>(XENO_RIGHTARM_ACW_GIMBALL<<4)) { + xenoStatusPointer->Right_Arm_Pan=(XENO_RIGHTARM_ACW_GIMBALL<<4); + } else if (xenoStatusPointer->Right_Arm_Pan>0) { + xenoStatusPointer->Right_Arm_Pan=0; + } else { + xenoStatusPointer->ra_moving=1; + } + } else if (xenoStatusPointer->Right_Arm_Pan>0) { + xenoStatusPointer->Right_Arm_Pan-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Right_Arm_Pan<-(XENO_RIGHTARM_CW_GIMBALL<<4)) { + xenoStatusPointer->Right_Arm_Pan=-(XENO_RIGHTARM_CW_GIMBALL<<4); + } else if (xenoStatusPointer->Right_Arm_Pan<0) { + xenoStatusPointer->Right_Arm_Pan=0; + } else { + xenoStatusPointer->ra_moving=1; + } + } + + if (xenoStatusPointer->right_arm_pan) { + xenoStatusPointer->right_arm_pan->Active=1; + } + + /* Now y. */ + + if (xenoStatusPointer->Right_Arm_Tilt<0) { + xenoStatusPointer->Right_Arm_Tilt+=(NormalFrameTime>>rate); + if (xenoStatusPointer->Right_Arm_Tilt>(XENO_ARM_PITCH_GIMBALL<<4)) { + xenoStatusPointer->Right_Arm_Tilt=(XENO_ARM_PITCH_GIMBALL<<4); + } else if (xenoStatusPointer->Right_Arm_Tilt>0) { + xenoStatusPointer->Right_Arm_Tilt=0; + } else { + xenoStatusPointer->ra_moving=1; + } + } else if (xenoStatusPointer->Right_Arm_Tilt>0) { + xenoStatusPointer->Right_Arm_Tilt-=(NormalFrameTime>>rate); + if (xenoStatusPointer->Right_Arm_Tilt<-(XENO_ARM_PITCH_GIMBALL<<4)) { + xenoStatusPointer->Right_Arm_Tilt=-(XENO_ARM_PITCH_GIMBALL<<4); + } else if (xenoStatusPointer->Right_Arm_Tilt<0) { + xenoStatusPointer->Right_Arm_Tilt=0; + } else { + xenoStatusPointer->ra_moving=1; + } + } + + if (xenoStatusPointer->right_arm_tilt) { + xenoStatusPointer->right_arm_tilt->Active=1; + } + + return; + +} + +int XenoActivation_FrustrumReject(VECTORCH *localOffset) { + + if ( (localOffset->vz <0) + && (localOffset->vz < localOffset->vx) + && (localOffset->vz < -localOffset->vx) + && (localOffset->vz < localOffset->vy) + && (localOffset->vz < -localOffset->vy) ) { + + /* 90 horizontal, 90 vertical. */ + return(1); + } else { + return(0); + } + +} + +int XenoSight_FrustrumReject(STRATEGYBLOCK *sbPtr,VECTORCH *localOffset) { + + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + if ( (localOffset->vx>0) ) { + /* 180 horizontal, 180 vertical. */ + return(1); + } else { + if ((xenoStatusPointer->Target)||(xenoStatusPointer->ShotThisFrame)) { + return(1); + } else { + return(0); + } + } + +} + +void Xeno_UpdateTargetTrackPos(STRATEGYBLOCK *sbPtr) { + + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + if (xenoStatusPointer->Target==NULL) { + xenoStatusPointer->targetTrackPos.vx=0; + xenoStatusPointer->targetTrackPos.vy=0; + xenoStatusPointer->targetTrackPos.vz=0; + return; + } + + GetTargetingPointOfObject_Far(xenoStatusPointer->Target,&xenoStatusPointer->targetTrackPos); + +} + +static void ProcessFarXenoborgTargetModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule) +{ + NPC_TARGETMODULESTATUS targetStatus; + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(targetModule); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + targetStatus = GetTargetAIModuleStatus(sbPtr, targetModule,0); + switch(targetStatus) + { + case(NPCTM_NoEntryPoint): + { + /* do nothing */ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_NormalRoom): + { + /* locate to target */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_AirDuct): + { + /* loacate to target */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_LiftTeleport): + { + /* do nothing */ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_ProxDoorOpen): + { + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_ProxDoorNotOpen): + { + MODULE *renderModule; + renderModule=*(targetModule->m_module_ptrs); + /* trigger the door, and set timer to quick so we can catch the door when it's open */ + ((PROXDOOR_BEHAV_BLOCK *)renderModule->m_sbptr->SBdataptr)->alienTrigger = 1; + break; + } + case(NPCTM_LiftDoorOpen): + { + /* do nothing - can't use lifts */ + //FarNpc_FlipAround(sbPtr); + /* What the hell!!! */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_LiftDoorNotOpen): + { + /* do nothing - can't open lift doors */ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_SecurityDoorOpen): + { + /* locate to target, and move thro' quick as we can't retrigger */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_SecurityDoorNotOpen): + { + MODULE *renderModule; + renderModule=*(targetModule->m_module_ptrs); + /* do some door opening stuff here. Door should stay open for long enough + for us to catch it open next time */ + RequestState((renderModule->m_sbptr),1,0); + break; + } + default: + { + LOCALASSERT(1==0); + } + } +} + +void Execute_Xeno_ActiveWait_Far(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + int anglex,angley,correctlyOrientated; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* What to do? Do we have a target? */ + + if (ShowXenoStats) { + PrintDebuggingText("In ActiveWait Far.\n"); + } + + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED,(ONE_FIXED>>2)); + + if (xenoStatusPointer->Target==NULL) { + #if FAR_XENO_ACTIVITY + /* Let's wave the head around. */ + Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); + Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); + Xeno_HeadMovement_ScanUpDown(sbPtr,XENO_HEAD_SCAN_RATE+2); + #endif + + if (sbPtr->containingModule->m_aimodule!=xenoStatusPointer->my_module) { + Xeno_Enter_Returning_State(sbPtr); + return; + } + + xenoStatusPointer->stateTimer+=NormalFrameTime; + if (xenoStatusPointer->stateTimer>xenoStatusPointer->UpTime) { + Xeno_Enter_PowerDown_State(sbPtr); + } + + /* Are we at home? */ + if (sbPtr->containingModule->m_aimodule!=xenoStatusPointer->my_module) { + Xeno_Enter_Returning_State(sbPtr); + return; + } + /* Are we facing the right way? */ + + correctlyOrientated = NPCOrientateToVector(sbPtr, &xenoStatusPointer->my_orientdir_therin,ONE_FIXED,NULL); + + if (!correctlyOrientated) { + + SECTION_DATA *master_section; + + master_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"pelvis presley"); + GLOBALASSERT(master_section); + + Xenoborg_GetRelativeAngles(sbPtr,&anglex,&angley,&master_section->World_Offset); + + if (anglex>0) { + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Right,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); + } else { + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Left,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); + } + #if FAR_XENO_ACTIVITY + if (xenoStatusPointer->soundHandle1==SOUND_NOACTIVEINDEX) { + Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1); + } + #endif + } else { + + /* Otherwise just wait? */ + if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(xenoStatusPointer->soundHandle1); + } + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED,(ONE_FIXED>>2)); + xenoStatusPointer->stateTimer+=NormalFrameTime; + if (xenoStatusPointer->stateTimer>xenoStatusPointer->UpTime) { + Xeno_Enter_PowerDown_State(sbPtr); + } + } + return; + } + + GLOBALASSERT(xenoStatusPointer->Target); + /* Now we have a target. Can we see it? */ + if (xenoStatusPointer->targetSightTest==0) { + /* Can't see them. Are we out of range? */ + if (GetNextModuleForLink(sbPtr->containingModule->m_aimodule, + xenoStatusPointer->my_module,(xenoStatusPointer->module_range)-1,0)==NULL) { + Xeno_Enter_Returning_State(sbPtr); + } else { + Xeno_Enter_Following_State(sbPtr); + } + return; + } + + #if FAR_XENO_ACTIVITY + Xeno_TurnAndTarget(sbPtr,&anglex,&angley); + + if ((anglex>(((XENO_HEADPAN_GIMBALL)*7)/8)) + ||(anglex<-(((XENO_HEADPAN_GIMBALL)*7)/8))) { + + Xeno_Enter_TurnToFace_State(sbPtr); + + } + #endif + + if (ShowXenoStats) { + PrintDebuggingText("Targets in module....\n"); + } + +} + +void Execute_Xeno_TurnToFace_Far(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + int correctlyOrientated; + int anglex,angley; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* Do we have a target? */ + + if (ShowXenoStats) { + PrintDebuggingText("In Turn To Face Far.\n"); + } + + if (xenoStatusPointer->Target==NULL) { + Xeno_Enter_ActiveWait_State(sbPtr); + /* Otherwise just wait? */ + return; + } + + /* Now we have a target. */ + GLOBALASSERT(xenoStatusPointer->Target); + + /* Set up animation... Which Way? */ + { + SECTION_DATA *master_section; + VECTORCH orientationDirn; + + master_section=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"pelvis presley"); + GLOBALASSERT(master_section); + + Xenoborg_GetRelativeAngles(sbPtr,&anglex,&angley,&master_section->World_Offset); + + if (anglex<2048) { + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Right,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); + } else { + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Left,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); + } + + /* Then turn to face it, of course. */ + + orientationDirn.vx = xenoStatusPointer->targetTrackPos.vx - sbPtr->DynPtr->Position.vx; + orientationDirn.vy = 0; + orientationDirn.vz = xenoStatusPointer->targetTrackPos.vz - sbPtr->DynPtr->Position.vz; + correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,ONE_FIXED,NULL); + /* Spin FAST. */ + } + + #if FAR_XENO_ACTIVITY + Xeno_TurnAndTarget(sbPtr,&anglex,&angley); + #endif + + if (correctlyOrientated) { + Xeno_Enter_ActiveWait_State(sbPtr); + } + +} + +void Execute_Xeno_Follow_Far(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + int anglex,angley; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* In theory, we're following the target, and can't see it. */ + + if (ShowXenoStats) { + PrintDebuggingText("In Follow Far.\n"); + } + + if (xenoStatusPointer->Target==NULL) { + /* Let's wave the head around. */ + #if FAR_XENO_ACTIVITY + Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); + Xeno_HeadMovement_ScanUpDown(sbPtr,XENO_HEAD_SCAN_RATE+2); + #endif + /* And return to my module. */ + Xeno_Enter_Returning_State(sbPtr); + return; + } + + /* Increment the Far state timer */ + xenoStatusPointer->stateTimer += NormalFrameTime; + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(xenoStatusPointer->stateTimer < XENO_FAR_MOVE_TIME) { + #if FAR_XENO_ACTIVITY + Xeno_TurnAndTarget(sbPtr,&anglex,&angley); + #endif + return; + } + + GLOBALASSERT(xenoStatusPointer->Target); + /* Now we know have a target. Can we see it yet? */ + + if (xenoStatusPointer->targetSightTest==0) { + + AIMODULE *targetModule; + + /* Can't see them. Never mind. Go to the next module? */ + if (xenoStatusPointer->Target->containingModule==NULL) { + /* Fall through for now. */ + targetModule=NULL; + } else if (GetNextModuleForLink(sbPtr->containingModule->m_aimodule, + xenoStatusPointer->my_module,(xenoStatusPointer->module_range)-1,0)==NULL) { + /* Too Far! */ + Xeno_Enter_ActiveWait_State(sbPtr); + return; + } else { + /* Still in range: keep going. */ + targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule, + xenoStatusPointer->Target->containingModule->m_aimodule,xenoStatusPointer->module_range,0); + + } + + if (targetModule==NULL) { + /* They're way away. */ + Xeno_Enter_Returning_State(sbPtr); + return; + } + + if (targetModule!=xenoStatusPointer->Target->containingModule->m_aimodule) { + + GLOBALASSERT(targetModule); + ProcessFarXenoborgTargetModule(sbPtr,targetModule); + + } else { + /* In our target's module! */ + + Xeno_Enter_ActiveWait_State(sbPtr); + + } + + } else { + /* Re-aquired! */ + Xeno_Enter_ActiveWait_State(sbPtr); + return; + } + + xenoStatusPointer->stateTimer=0; + + #if 0 + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Walking,XENO_WALKING_ANIM_SPEED,(ONE_FIXED>>2)); + #else + XenoborgHandleMovingAnimation(sbPtr); + #endif + + #if FAR_XENO_ACTIVITY + if (xenoStatusPointer->targetSightTest==0) { + Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); + Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); + } else { + Xeno_TurnAndTarget(sbPtr,&anglex,&angley); + } + #endif + +} + +void Execute_Xeno_Return_Far(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* In theory, we're following the target, and can't see it. */ + + if (ShowXenoStats) { + PrintDebuggingText("In Return Far.\n"); + } + + if (xenoStatusPointer->Target!=NULL) { + /* Saw something! */ + /* Go to active wait. */ + Xeno_Enter_ActiveWait_State(sbPtr); + return; + } + + /* Increment the Far state timer */ + xenoStatusPointer->stateTimer += NormalFrameTime; + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(xenoStatusPointer->stateTimer < XENO_FAR_MOVE_TIME) { + #if FAR_XENO_ACTIVITY + Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); + Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); + Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + #endif + return; + } + + GLOBALASSERT(xenoStatusPointer->Target==NULL); + /* Find our way home. */ + + { + + AIMODULE *targetModule; + + /* Go to the next module. */ + targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule, + xenoStatusPointer->my_module,xenoStatusPointer->module_range+2,0); + /* Just to be on the safe side. */ + + if (targetModule==NULL) { + /* Emergency! */ + targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule, + xenoStatusPointer->my_module,xenoStatusPointer->module_range+5,0); + if (targetModule==NULL) { + /* Totally broken. Stay here. */ + Xeno_CopeWithLossOfHome(sbPtr); + return; + } + } + + if (targetModule!=sbPtr->containingModule->m_aimodule) { + + GLOBALASSERT(targetModule); + ProcessFarXenoborgTargetModule(sbPtr,targetModule); + + } else { + /* In our own home module! */ + + sbPtr->DynPtr->Position=xenoStatusPointer->my_spot_therin; + + Xeno_Enter_ActiveWait_State(sbPtr); + + } + } + + xenoStatusPointer->stateTimer=0; + + #if 0 + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Walking,XENO_WALKING_ANIM_SPEED,(ONE_FIXED>>2)); + #else + XenoborgHandleMovingAnimation(sbPtr); + #endif + + #if FAR_XENO_ACTIVITY + Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); + Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); + #endif + +} + +void Execute_Xeno_Avoidance_Far(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + int anglex,angley; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + if (ShowXenoStats) { + PrintDebuggingText("In Avoidance Far.\n"); + } + + /* Sequences... */ + #if 0 + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Walking,XENO_WALKING_ANIM_SPEED,(ONE_FIXED>>2)); + #else + XenoborgHandleMovingAnimation(sbPtr); + #endif + + #if FAR_XENO_ACTIVITY + if (xenoStatusPointer->targetSightTest==0) { + Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); + Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); + Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); + } else { + Xeno_TurnAndTarget(sbPtr,&anglex,&angley); + } + #endif + + { + + /* go to an appropriate state */ + switch (xenoStatusPointer->lastState) { + case XS_Returning: + Xeno_Enter_Returning_State(sbPtr); + return; + break; + case XS_Following: + Xeno_Enter_Following_State(sbPtr); + return; + break; + default: + Xeno_Enter_ActiveWait_State(sbPtr); + return; + break; + } + /* Still here? */ + return; + + } + return; +} + +#define FIRING_RATE_LEFT 25 + +void Xenoborg_MaintainLeftGun(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + SECTION_DATA *left_dum; + VECTORCH alpha; + VECTORCH beta; + int multiple; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + left_dum=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"flash dummy A"); + + if (xenoStatusPointer->Wounds§ion_flag_left_hand) { + xenoStatusPointer->FiringLeft=0; + } + + if ((xenoStatusPointer->FiringLeft==0)||(left_dum==NULL)||(xenoStatusPointer->IAmFar)) { + /* Not firing, go away. */ + xenoStatusPointer->LeftMainBeam.BeamIsOn = 0; + return; + } + + /* Okay, must be firing. Did we get anyone? */ + + multiple=FIRING_RATE_LEFT*NormalFrameTime; + + #if 0 + LOS_Lambda = NPC_MAX_VIEWRANGE; + LOS_ObjectHitPtr = 0; + LOS_HModel_Section=NULL; + { + extern int NumActiveBlocks; + extern DISPLAYBLOCK* ActiveBlockList[]; + int numberOfObjects = NumActiveBlocks; + + while (numberOfObjects--) + { + DISPLAYBLOCK* objectPtr = ActiveBlockList[numberOfObjects]; + + alpha = left_dum->World_Offset; + + beta.vx=left_dum->SecMat.mat31; + beta.vy=left_dum->SecMat.mat32; + beta.vz=left_dum->SecMat.mat33; + + GLOBALASSERT(objectPtr); + + if (objectPtr!=sbPtr->SBdptr) { + /* Can't hit self. */ + CheckForVectorIntersectionWith3dObject(objectPtr, &alpha, &beta,1); + } + } + } + #else + { + alpha = left_dum->World_Offset; + + beta.vx=left_dum->SecMat.mat31; + beta.vy=left_dum->SecMat.mat32; + beta.vz=left_dum->SecMat.mat33; + FindPolygonInLineOfSight(&beta,&alpha,0,sbPtr->SBdptr); + } + #endif + + /* Now deal with LOS_ObjectHitPtr. */ + if (LOS_ObjectHitPtr) { + if (LOS_HModel_Section) { + if (LOS_ObjectHitPtr->ObStrategyBlock) { + if (LOS_ObjectHitPtr->ObStrategyBlock->SBdptr) { + GLOBALASSERT(LOS_ObjectHitPtr->ObStrategyBlock->SBdptr->HModelControlBlock==LOS_HModel_Section->my_controller); + } + } + } + /* this fn needs updating to take amount of damage into account etc. */ + HandleWeaponImpact(&LOS_Point,LOS_ObjectHitPtr->ObStrategyBlock,AMMO_XENOBORG,&beta, multiple, LOS_HModel_Section); + } + + /* Cheat for killing far targets? */ + if (xenoStatusPointer->Target) { + if (xenoStatusPointer->Target->SBdptr==NULL) { + HandleWeaponImpact(&xenoStatusPointer->Target->DynPtr->Position,xenoStatusPointer->Target,AMMO_XENOBORG,&beta, multiple, NULL); + } + } + + /* update beam SFX data */ + xenoStatusPointer->LeftMainBeam.BeamIsOn = 1; + xenoStatusPointer->LeftMainBeam.SourcePosition = left_dum->World_Offset; + + if (LOS_ObjectHitPtr) { + xenoStatusPointer->LeftMainBeam.TargetPosition = LOS_Point; + } else { + /* Must be hitting nothing... */ + xenoStatusPointer->LeftMainBeam.TargetPosition=alpha; + xenoStatusPointer->LeftMainBeam.TargetPosition.vx+=(beta.vx>>3); + xenoStatusPointer->LeftMainBeam.TargetPosition.vy+=(beta.vy>>3); + xenoStatusPointer->LeftMainBeam.TargetPosition.vz+=(beta.vz>>3); + } + + if (LOS_ObjectHitPtr==Player) + { + xenoStatusPointer->LeftMainBeam.BeamHasHitPlayer = 1; + } + else + { + xenoStatusPointer->LeftMainBeam.BeamHasHitPlayer = 0; + } +} + +#define FIRING_RATE_RIGHT 25 + +void Xenoborg_MaintainRightGun(STRATEGYBLOCK *sbPtr) +{ + XENO_STATUS_BLOCK *xenoStatusPointer; + SECTION_DATA *right_dum; + VECTORCH alpha; + VECTORCH beta; + int multiple; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + right_dum=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"flash dummy B"); + + if (xenoStatusPointer->Wounds§ion_flag_right_hand) { + xenoStatusPointer->FiringRight=0; + } + + if ((xenoStatusPointer->FiringRight==0)||(right_dum==NULL)||(xenoStatusPointer->IAmFar)) { + /* Not firing, go away. */ + xenoStatusPointer->RightMainBeam.BeamIsOn = 0; + return; + } + + /* Okay, must be firing. Did we get anyone? */ + + multiple=FIRING_RATE_RIGHT*NormalFrameTime; + + #if 0 + LOS_Lambda = NPC_MAX_VIEWRANGE; + LOS_ObjectHitPtr = 0; + LOS_HModel_Section=NULL; + { + extern int NumActiveBlocks; + extern DISPLAYBLOCK* ActiveBlockList[]; + int numberOfObjects = NumActiveBlocks; + + while (numberOfObjects--) + { + DISPLAYBLOCK* objectPtr = ActiveBlockList[numberOfObjects]; + + alpha = right_dum->World_Offset; + + beta.vx=right_dum->SecMat.mat31; + beta.vy=right_dum->SecMat.mat32; + beta.vz=right_dum->SecMat.mat33; + + GLOBALASSERT(objectPtr); + + if (objectPtr!=sbPtr->SBdptr) { + /* Can't hit self. */ + CheckForVectorIntersectionWith3dObject(objectPtr, &alpha, &beta,1); + } + } + } + #else + { + alpha = right_dum->World_Offset; + + beta.vx=right_dum->SecMat.mat31; + beta.vy=right_dum->SecMat.mat32; + beta.vz=right_dum->SecMat.mat33; + FindPolygonInLineOfSight(&beta,&alpha,0,sbPtr->SBdptr); + } + #endif + /* Now deal with LOS_ObjectHitPtr. */ + if (LOS_ObjectHitPtr) { + if (LOS_HModel_Section) { + if (LOS_ObjectHitPtr->ObStrategyBlock) { + if (LOS_ObjectHitPtr->ObStrategyBlock->SBdptr) { + GLOBALASSERT(LOS_ObjectHitPtr->ObStrategyBlock->SBdptr->HModelControlBlock==LOS_HModel_Section->my_controller); + } + } + } + /* this fn needs updating to take amount of damage into account etc. */ + HandleWeaponImpact(&LOS_Point,LOS_ObjectHitPtr->ObStrategyBlock,AMMO_XENOBORG,&beta, multiple, LOS_HModel_Section); + } + + /* Cheat for killing far targets? */ + if (xenoStatusPointer->Target) { + if (xenoStatusPointer->Target->SBdptr==NULL) { + HandleWeaponImpact(&xenoStatusPointer->Target->DynPtr->Position,xenoStatusPointer->Target,AMMO_XENOBORG,&beta, multiple, NULL); + } + } + + /* update beam SFX data */ + xenoStatusPointer->RightMainBeam.BeamIsOn = 1; + xenoStatusPointer->RightMainBeam.SourcePosition = right_dum->World_Offset; + + if (LOS_ObjectHitPtr) { + xenoStatusPointer->RightMainBeam.TargetPosition = LOS_Point; + } else { + /* Must be hitting nothing... */ + xenoStatusPointer->RightMainBeam.TargetPosition=alpha; + xenoStatusPointer->RightMainBeam.TargetPosition.vx+=(beta.vx>>3); + xenoStatusPointer->RightMainBeam.TargetPosition.vy+=(beta.vy>>3); + xenoStatusPointer->RightMainBeam.TargetPosition.vz+=(beta.vz>>3); + } + + if (LOS_ObjectHitPtr==Player) + { + xenoStatusPointer->RightMainBeam.BeamHasHitPlayer = 1; + } + else + { + xenoStatusPointer->RightMainBeam.BeamHasHitPlayer = 0; + } + +} + +int Xeno_Activation_Test(STRATEGYBLOCK *sbPtr) { + + XENO_STATUS_BLOCK *xenoStatusPointer; + STRATEGYBLOCK *candidate; + MATRIXCH WtoL; + int a; + MODULE *dmod; + + dmod=ModuleFromPosition(&sbPtr->DynPtr->Position,playerPherModule); + + LOCALASSERT(dmod); + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + WtoL=sbPtr->DynPtr->OrientMat; + TransposeMatrixCH(&WtoL); + + for (a=0; aDynPtr) { + if (Xenoborg_TargetFilter(candidate)) { + VECTORCH offset; + + offset.vx=sbPtr->DynPtr->Position.vx-candidate->DynPtr->Position.vx; + offset.vy=sbPtr->DynPtr->Position.vy-candidate->DynPtr->Position.vy; + offset.vz=sbPtr->DynPtr->Position.vz-candidate->DynPtr->Position.vz; + + RotateVector(&offset,&WtoL); + + if (XenoActivation_FrustrumReject(&offset)) { + /* Check visibility? */ + if (NPCCanSeeTarget(sbPtr,candidate,XENO_NEAR_VIEW_WIDTH)) { + if (!NPC_IsDead(candidate)) { + if ((IsModuleVisibleFromModule(dmod,candidate->containingModule))) { + return(1); + } + } + } + } + } + } + } + } + return(0); +} + +void Xeno_MaintainLasers(STRATEGYBLOCK *sbPtr) { + + XENO_STATUS_BLOCK *xenoStatusPointer; + SECTION_DATA *dum; + VECTORCH alpha; + VECTORCH beta; + int a,uselaser; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + xenoStatusPointer->HeadLaserOnTarget=0; + xenoStatusPointer->LALaserOnTarget=0; + xenoStatusPointer->RALaserOnTarget=0; + + #if (FAR_XENO_ACTIVITY==0) + if (xenoStatusPointer->IAmFar) { + xenoStatusPointer->TargetingLaser[0].BeamIsOn=0; + xenoStatusPointer->TargetingLaser[1].BeamIsOn=0; + xenoStatusPointer->TargetingLaser[2].BeamIsOn=0; + return; + } + #endif + + for (a=0; a<3; a++) { + + xenoStatusPointer->TargetingLaser[a].BeamIsOn=0; + switch (a) { + case 0: + dum=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"flash dummyZ"); + if (xenoStatusPointer->UseHeadLaser) { + uselaser=1; + } else { + uselaser=0; + } + if (dum==NULL) { + uselaser=0; + } + break; + case 1: + dum=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"flash dummy C"); + if (xenoStatusPointer->UseLALaser) { + uselaser=1; + } else { + uselaser=0; + } + if (dum==NULL) { + uselaser=0; + } + break; + case 2: + dum=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"flash dummy D"); + if (xenoStatusPointer->UseRALaser) { + uselaser=1; + } else { + uselaser=0; + } + if (dum==NULL) { + uselaser=0; + } + break; + default: + GLOBALASSERT(0); + break; + } + + if (uselaser) { + + alpha = dum->World_Offset; + + beta.vx=dum->SecMat.mat31; + beta.vy=dum->SecMat.mat32; + beta.vz=dum->SecMat.mat33; + + FindPolygonInLineOfSight(&beta,&alpha,0,sbPtr->SBdptr); + + /* Now deal with LOS_ObjectHitPtr. */ + if (LOS_ObjectHitPtr==Player) { + xenoStatusPointer->TargetingLaser[a].BeamHasHitPlayer=1; + } else { + xenoStatusPointer->TargetingLaser[a].BeamHasHitPlayer=0; + } + + xenoStatusPointer->TargetingLaser[a].SourcePosition=alpha; + if (LOS_ObjectHitPtr) { + xenoStatusPointer->TargetingLaser[a].TargetPosition=LOS_Point; + } else { + /* Must be hitting nothing... */ + xenoStatusPointer->TargetingLaser[a].TargetPosition=alpha; + xenoStatusPointer->TargetingLaser[a].TargetPosition.vx+=(beta.vx>>3); + xenoStatusPointer->TargetingLaser[a].TargetPosition.vy+=(beta.vy>>3); + xenoStatusPointer->TargetingLaser[a].TargetPosition.vz+=(beta.vz>>3); + + } + xenoStatusPointer->TargetingLaser[a].BeamIsOn=1; + + if (LOS_ObjectHitPtr) { + if (LOS_ObjectHitPtr->ObStrategyBlock==xenoStatusPointer->Target) { + switch (a) { + case 0: + xenoStatusPointer->HeadLaserOnTarget=1; + break; + case 1: + xenoStatusPointer->LALaserOnTarget=1; + break; + case 2: + xenoStatusPointer->RALaserOnTarget=1; + break; + default: + GLOBALASSERT(0); + break; + } + } + } + } + } + +} + +void Xeno_SwitchLED(STRATEGYBLOCK *sbPtr,int state) { + + XENO_STATUS_BLOCK *xenoStatusPointer; + SECTION_DATA *led; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + led=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"led"); + + if (led) { + if (led->tac_ptr) { + led->tac_ptr->tac_sequence = state ; + led->tac_ptr->tac_txah_s = GetTxAnimHeaderFromShape(led->tac_ptr, led->ShapeNum); + } + } +} + +void Xeno_Stomp(STRATEGYBLOCK *sbPtr) { + + XENO_STATUS_BLOCK *xenoStatusPointer; + SECTION_DATA *foot; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + foot=NULL; + + if (xenoStatusPointer->HModelController.keyframe_flags&4) { + foot=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"right foot"); + } else if (xenoStatusPointer->HModelController.keyframe_flags&8) { + foot=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"left foot"); + } + + if (foot) { + Sound_Play(SID_STOMP,"d",&foot->World_Offset); + } + +} + +void Xeno_MaintainSounds(STRATEGYBLOCK *sbPtr) { + + XENO_STATUS_BLOCK *xenoStatusPointer; + SECTION_DATA *sec; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + /* First, the two big system sounds. */ + if (xenoStatusPointer->soundHandle1!=SOUND_NOACTIVEINDEX) { + Sound_Update3d(xenoStatusPointer->soundHandle1,&sbPtr->DynPtr->Position); + } + if (xenoStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) { + Sound_Update3d(xenoStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); + } + + /* Now, all the lesser sounds: */ + /* Head. */ + sec=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"head"); + if (sec==NULL) { + /* No sound. */ + if (xenoStatusPointer->head_whirr!=SOUND_NOACTIVEINDEX) { + Sound_Stop(xenoStatusPointer->head_whirr); + } + } else { + if (xenoStatusPointer->head_moving==0) { + /* Stationary. */ + if (xenoStatusPointer->head_whirr!=SOUND_NOACTIVEINDEX) { + Sound_Stop(xenoStatusPointer->head_whirr); + Sound_Play(SID_ARMEND,"d",&sec->World_Offset); + } + } else { + /* Moving! */ + if (xenoStatusPointer->head_whirr==SOUND_NOACTIVEINDEX) { + Sound_Play(SID_ARMSTART,"d",&sec->World_Offset); + Sound_Play(SID_ARMMID,"del",&sec->World_Offset,&xenoStatusPointer->head_whirr); + } else { + Sound_Update3d(xenoStatusPointer->head_whirr,&sec->World_Offset); + } + } + } + /* Left Arm. */ + sec=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"left bicep"); + if (sec==NULL) { + /* No sound. */ + if (xenoStatusPointer->left_arm_whirr!=SOUND_NOACTIVEINDEX) { + Sound_Stop(xenoStatusPointer->left_arm_whirr); + } + } else { + if (xenoStatusPointer->la_moving==0) { + /* Stationary. */ + if (xenoStatusPointer->left_arm_whirr!=SOUND_NOACTIVEINDEX) { + Sound_Stop(xenoStatusPointer->left_arm_whirr); + Sound_Play(SID_ARMEND,"d",&sec->World_Offset); + } + } else { + /* Moving! */ + if (xenoStatusPointer->left_arm_whirr==SOUND_NOACTIVEINDEX) { + Sound_Play(SID_ARMSTART,"d",&sec->World_Offset); + Sound_Play(SID_ARMMID,"del",&sec->World_Offset,&xenoStatusPointer->left_arm_whirr); + } else { + Sound_Update3d(xenoStatusPointer->left_arm_whirr,&sec->World_Offset); + } + } + } + /* Right Arm. */ + sec=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"right bicep"); + if (sec==NULL) { + /* No sound. */ + if (xenoStatusPointer->right_arm_whirr!=SOUND_NOACTIVEINDEX) { + Sound_Stop(xenoStatusPointer->right_arm_whirr); + } + } else { + if (xenoStatusPointer->ra_moving==0) { + /* Stationary. */ + if (xenoStatusPointer->right_arm_whirr!=SOUND_NOACTIVEINDEX) { + Sound_Stop(xenoStatusPointer->right_arm_whirr); + Sound_Play(SID_ARMEND,"d",&sec->World_Offset); + } + } else { + /* Moving! */ + if (xenoStatusPointer->right_arm_whirr==SOUND_NOACTIVEINDEX) { + Sound_Play(SID_ARMSTART,"d",&sec->World_Offset); + Sound_Play(SID_ARMMID,"del",&sec->World_Offset,&xenoStatusPointer->right_arm_whirr); + } else { + Sound_Update3d(xenoStatusPointer->right_arm_whirr,&sec->World_Offset); + } + } + } + /* Torso Twist. */ + sec=GetThisSectionData(xenoStatusPointer->HModelController.section_data,"chest"); + if (sec==NULL) { + /* No sound. */ + if (xenoStatusPointer->torso_whirr!=SOUND_NOACTIVEINDEX) { + Sound_Stop(xenoStatusPointer->torso_whirr); + } + } else { + if (xenoStatusPointer->torso_moving==0) { + /* Stationary. */ + if (xenoStatusPointer->torso_whirr!=SOUND_NOACTIVEINDEX) { + Sound_Stop(xenoStatusPointer->torso_whirr); + Sound_Play(SID_ARMEND,"d",&sec->World_Offset); + } + } else { + /* Moving! */ + if (xenoStatusPointer->torso_whirr==SOUND_NOACTIVEINDEX) { + Sound_Play(SID_ARMSTART,"d",&sec->World_Offset); + Sound_Play(SID_ARMMID,"del",&sec->World_Offset,&xenoStatusPointer->torso_whirr); + } else { + Sound_Update3d(xenoStatusPointer->torso_whirr,&sec->World_Offset); + } + } + } +} + +void XenoborgHandleMovingAnimation(STRATEGYBLOCK *sbPtr) { + + XENO_STATUS_BLOCK *xenoStatusPointer; + VECTORCH offset; + int speed,animfactor; + + LOCALASSERT(sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(xenoStatusPointer); + + offset.vx=sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx; + offset.vy=sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy; + offset.vz=sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz; + + /* ...compute speed factor... */ + speed=Magnitude(&offset); + if (speed<(MUL_FIXED(NormalFrameTime,50))) { + /* Not moving much, are we? Be stationary! */ + if (ShowXenoStats) { + PrintDebuggingText("Forced stationary animation!\n"); + } + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED,(ONE_FIXED>>2)); + return; + } + speed=DIV_FIXED(speed,NormalFrameTime); + + if (speed==0) { + animfactor=ONE_FIXED; + } else { + animfactor=DIV_FIXED(625,speed); // Was 512! Difference to correct for rounding down... + } + GLOBALASSERT(animfactor>0); + if (ShowXenoStats) { + PrintDebuggingText("Anim Factor %d, Tweening %d\n",animfactor,xenoStatusPointer->HModelController.Tweening); + } + + /* Start animation. */ + EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Walking,XENO_WALKING_ANIM_SPEED,(ONE_FIXED>>2)); + + if (xenoStatusPointer->HModelController.Tweening==0) { + HModel_SetToolsRelativeSpeed(&xenoStatusPointer->HModelController,animfactor); + } + +} + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" + +typedef struct xenoborg_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + +//behaviour block stuff + signed int health; + XENO_BHSTATE behaviourState; + XENO_BHSTATE lastState; + int stateTimer; + NPC_WANDERDATA wanderData; + NPC_OBSTRUCTIONREPORT obstruction; + VECTORCH my_spot_therin; + VECTORCH my_orientdir_therin; + int module_range; + int UpTime; + int GibbFactor; + int Wounds; + + + + VECTORCH targetTrackPos; + + int Head_Pan; + int Head_Tilt; + int Left_Arm_Pan; + int Left_Arm_Tilt; + int Right_Arm_Pan; + int Right_Arm_Tilt; + int Torso_Twist; + + int Old_Head_Pan; + int Old_Head_Tilt; + int Old_Left_Arm_Pan; + int Old_Left_Arm_Tilt; + int Old_Right_Arm_Pan; + int Old_Right_Arm_Tilt; + int Old_Torso_Twist; + + LASER_BEAM_DESC LeftMainBeam; + LASER_BEAM_DESC RightMainBeam; + LASER_BEAM_DESC TargetingLaser[3]; + + unsigned int headpandir :1; + unsigned int headtiltdir :1; + unsigned int leftarmpandir :1; + unsigned int leftarmtiltdir :1; + unsigned int rightarmpandir :1; + unsigned int rightarmtiltdir :1; + unsigned int torsotwistdir :1; + + unsigned int headLock :1; + unsigned int leftArmLock :1; + unsigned int rightArmLock :1; + unsigned int targetSightTest :1; + unsigned int IAmFar :1; + unsigned int ShotThisFrame :1; + + unsigned int FiringLeft :1; + unsigned int FiringRight :1; + + unsigned int UseHeadLaser :1; + unsigned int UseLALaser :1; + unsigned int UseRALaser :1; + + unsigned int HeadLaserOnTarget :1; + unsigned int LALaserOnTarget :1; + unsigned int RALaserOnTarget :1; + + unsigned int head_moving :1; + unsigned int la_moving :1; + unsigned int ra_moving :1; + unsigned int torso_moving :1; + + int incidentFlag; + int incidentTimer; + + int head_whirr; + int left_arm_whirr; + int right_arm_whirr; + int torso_whirr; + + +//annoying pointer related things + int my_module_index; + + char Target_SBname[SB_NAME_LENGTH]; + +//strategyblock stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; + DYNAMICSBLOCK dynamics; +}XENOBORG_SAVE_BLOCK; + + + + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV xenoStatusPointer + + +void LoadStrategy_Xenoborg(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + int i; + STRATEGYBLOCK* sbPtr; + XENO_STATUS_BLOCK* xenoStatusPointer; + XENOBORG_SAVE_BLOCK* block = (XENOBORG_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourXenoborg) return; + + xenoStatusPointer =(XENO_STATUS_BLOCK*) sbPtr->SBdataptr; + + + //start copying stuff + COPYELEMENT_LOAD(health) + COPYELEMENT_LOAD(behaviourState) + COPYELEMENT_LOAD(lastState) + COPYELEMENT_LOAD(stateTimer) + COPYELEMENT_LOAD(wanderData) + COPYELEMENT_LOAD(obstruction) + COPYELEMENT_LOAD(my_spot_therin) + COPYELEMENT_LOAD(my_orientdir_therin) + COPYELEMENT_LOAD(module_range) + COPYELEMENT_LOAD(UpTime) + COPYELEMENT_LOAD(GibbFactor) + COPYELEMENT_LOAD(Wounds) + COPYELEMENT_LOAD(targetTrackPos) + COPYELEMENT_LOAD(Head_Pan) + COPYELEMENT_LOAD(Head_Tilt) + COPYELEMENT_LOAD(Left_Arm_Pan) + COPYELEMENT_LOAD(Left_Arm_Tilt) + COPYELEMENT_LOAD(Right_Arm_Pan) + COPYELEMENT_LOAD(Right_Arm_Tilt) + COPYELEMENT_LOAD(Torso_Twist) + COPYELEMENT_LOAD(Old_Head_Pan) + COPYELEMENT_LOAD(Old_Head_Tilt) + COPYELEMENT_LOAD(Old_Left_Arm_Pan) + COPYELEMENT_LOAD(Old_Left_Arm_Tilt) + COPYELEMENT_LOAD(Old_Right_Arm_Pan) + COPYELEMENT_LOAD(Old_Right_Arm_Tilt) + COPYELEMENT_LOAD(Old_Torso_Twist) + COPYELEMENT_LOAD(LeftMainBeam) + COPYELEMENT_LOAD(RightMainBeam) + + + COPYELEMENT_LOAD(headpandir) + COPYELEMENT_LOAD(headtiltdir) + COPYELEMENT_LOAD(leftarmpandir) + COPYELEMENT_LOAD(leftarmtiltdir) + COPYELEMENT_LOAD(rightarmpandir) + COPYELEMENT_LOAD(rightarmtiltdir) + COPYELEMENT_LOAD(torsotwistdir) + + COPYELEMENT_LOAD(headLock) + COPYELEMENT_LOAD(leftArmLock) + COPYELEMENT_LOAD(rightArmLock) + COPYELEMENT_LOAD(targetSightTest) + COPYELEMENT_LOAD(IAmFar) + COPYELEMENT_LOAD(ShotThisFrame) + + COPYELEMENT_LOAD(FiringLeft) + COPYELEMENT_LOAD(FiringRight) + + COPYELEMENT_LOAD(UseHeadLaser) + COPYELEMENT_LOAD(UseLALaser) + COPYELEMENT_LOAD(UseRALaser) + + COPYELEMENT_LOAD(HeadLaserOnTarget) + COPYELEMENT_LOAD(LALaserOnTarget) + COPYELEMENT_LOAD(RALaserOnTarget) + + COPYELEMENT_LOAD(head_moving) + COPYELEMENT_LOAD(la_moving) + COPYELEMENT_LOAD(ra_moving) + COPYELEMENT_LOAD(torso_moving) + + COPYELEMENT_LOAD(incidentFlag) + COPYELEMENT_LOAD(incidentTimer) + + COPYELEMENT_LOAD(head_whirr) + COPYELEMENT_LOAD(left_arm_whirr) + COPYELEMENT_LOAD(right_arm_whirr) + COPYELEMENT_LOAD(torso_whirr) + + for(i=0;i<3;i++) + { + COPYELEMENT_LOAD(TargetingLaser[i]) + } + + //load ai module pointers + xenoStatusPointer->my_module = GetPointerFromAIModuleIndex(block->my_module_index); + + //load target + COPY_NAME(xenoStatusPointer->Target_SBname,block->Target_SBname); + xenoStatusPointer->Target = FindSBWithName(xenoStatusPointer->Target_SBname); + + //copy strategy block stuff + *sbPtr->DynPtr = block->dynamics; + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + + //load hierarchy + { + SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); + if(hier_header) + { + LoadHierarchy(hier_header,&xenoStatusPointer->HModelController); + } + } + + + //finally get the delta controller pointers + VerifyDeltaControllers(sbPtr); + + Load_SoundState(&xenoStatusPointer->soundHandle1); + Load_SoundState(&xenoStatusPointer->soundHandle2); +} + + +void SaveStrategy_Xenoborg(STRATEGYBLOCK* sbPtr) +{ + int i; + XENO_STATUS_BLOCK* xenoStatusPointer; + XENOBORG_SAVE_BLOCK* block; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + xenoStatusPointer = (XENO_STATUS_BLOCK*) sbPtr->SBdataptr; + + //start copying stuff + + COPYELEMENT_SAVE(health) + COPYELEMENT_SAVE(behaviourState) + COPYELEMENT_SAVE(lastState) + COPYELEMENT_SAVE(stateTimer) + COPYELEMENT_SAVE(wanderData) + COPYELEMENT_SAVE(obstruction) + COPYELEMENT_SAVE(my_spot_therin) + COPYELEMENT_SAVE(my_orientdir_therin) + COPYELEMENT_SAVE(module_range) + COPYELEMENT_SAVE(UpTime) + COPYELEMENT_SAVE(GibbFactor) + COPYELEMENT_SAVE(Wounds) + COPYELEMENT_SAVE(targetTrackPos) + COPYELEMENT_SAVE(Head_Pan) + COPYELEMENT_SAVE(Head_Tilt) + COPYELEMENT_SAVE(Left_Arm_Pan) + COPYELEMENT_SAVE(Left_Arm_Tilt) + COPYELEMENT_SAVE(Right_Arm_Pan) + COPYELEMENT_SAVE(Right_Arm_Tilt) + COPYELEMENT_SAVE(Torso_Twist) + COPYELEMENT_SAVE(Old_Head_Pan) + COPYELEMENT_SAVE(Old_Head_Tilt) + COPYELEMENT_SAVE(Old_Left_Arm_Pan) + COPYELEMENT_SAVE(Old_Left_Arm_Tilt) + COPYELEMENT_SAVE(Old_Right_Arm_Pan) + COPYELEMENT_SAVE(Old_Right_Arm_Tilt) + COPYELEMENT_SAVE(Old_Torso_Twist) + COPYELEMENT_SAVE(LeftMainBeam) + COPYELEMENT_SAVE(RightMainBeam) + + + COPYELEMENT_SAVE(headpandir) + COPYELEMENT_SAVE(headtiltdir) + COPYELEMENT_SAVE(leftarmpandir) + COPYELEMENT_SAVE(leftarmtiltdir) + COPYELEMENT_SAVE(rightarmpandir) + COPYELEMENT_SAVE(rightarmtiltdir) + COPYELEMENT_SAVE(torsotwistdir) + + COPYELEMENT_SAVE(headLock) + COPYELEMENT_SAVE(leftArmLock) + COPYELEMENT_SAVE(rightArmLock) + COPYELEMENT_SAVE(targetSightTest) + COPYELEMENT_SAVE(IAmFar) + COPYELEMENT_SAVE(ShotThisFrame) + + COPYELEMENT_SAVE(FiringLeft) + COPYELEMENT_SAVE(FiringRight) + + COPYELEMENT_SAVE(UseHeadLaser) + COPYELEMENT_SAVE(UseLALaser) + COPYELEMENT_SAVE(UseRALaser) + + COPYELEMENT_SAVE(HeadLaserOnTarget) + COPYELEMENT_SAVE(LALaserOnTarget) + COPYELEMENT_SAVE(RALaserOnTarget) + + COPYELEMENT_SAVE(head_moving) + COPYELEMENT_SAVE(la_moving) + COPYELEMENT_SAVE(ra_moving) + COPYELEMENT_SAVE(torso_moving) + + COPYELEMENT_SAVE(incidentFlag) + COPYELEMENT_SAVE(incidentTimer) + + COPYELEMENT_SAVE(head_whirr) + COPYELEMENT_SAVE(left_arm_whirr) + COPYELEMENT_SAVE(right_arm_whirr) + COPYELEMENT_SAVE(torso_whirr) + + for(i=0;i<3;i++) + { + COPYELEMENT_SAVE(TargetingLaser[i]) + } + + //load ai module pointers + block->my_module_index = GetIndexFromAIModulePointer(xenoStatusPointer->my_module); + + //save target + COPY_NAME(block->Target_SBname,xenoStatusPointer->Target_SBname); + + //save strategy block stuff + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; + + //save the hierarchy + SaveHierarchy(&xenoStatusPointer->HModelController); + + Save_SoundState(&xenoStatusPointer->soundHandle1); + Save_SoundState(&xenoStatusPointer->soundHandle2); +} \ No newline at end of file diff --git a/3dc/avp/BonusAbilities.c b/3dc/avp/BonusAbilities.c new file mode 100644 index 0000000..0fa09df --- /dev/null +++ b/3dc/avp/BonusAbilities.c @@ -0,0 +1,448 @@ +/* KJL 16:14:35 09/09/98 - BonusAbilities.c */ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" + +#include "weapons.h" +#include "dynblock.h" +#include "avpview.h" + +#include "load_shp.h" +#include "kzsort.h" +#include "kshape.h" + +#include "pfarlocs.h" +#include "pvisible.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + + +extern int NormalFrameTime; + + + +/* KJL 16:18:20 09/09/98 - Predator Grappling Hook */ +struct GrapplingHookData +{ + int IsEmbedded; + int IsEngaged; + int Tightness; + + VECTORCH Position; + MATRIXCH Orientation; + int ShapeIndex; + DISPLAYBLOCK *DispPtr; +}; + +static struct GrapplingHookData GrapplingHook; + +static DISPLAYBLOCK* CreateGrapplingHook(void); + + +extern void InitialiseGrapplingHook(void) +{ + GrapplingHook.IsEngaged = 0; + GrapplingHook.IsEmbedded = 0; + GrapplingHook.ShapeIndex = GetLoadedShapeMSL("spear"); + GrapplingHook.DispPtr = 0; + +} + +static void FireGrapplingHook(void); +void DisengageGrapplingHook(void); + +extern void ActivateGrapplingHook(void) +{ + if (GrapplingHook.IsEngaged) + { + DisengageGrapplingHook(); + } + else + { + FireGrapplingHook(); + } +} +static void FireGrapplingHook(void) +{ + GrapplingHook.DispPtr = CreateGrapplingHook(); + + if (GrapplingHook.DispPtr) + { + GrapplingHook.IsEngaged = 1; + GrapplingHook.IsEmbedded = 0; + GrapplingHook.Tightness = ONE_FIXED; + + /* CDF 14/4/99 Make a sound... */ + Sound_Play(SID_GRAPPLE_THROW,"h"); + + #if 0 + /* los */ + GrapplingHook.Position = PlayersTarget.Position; + GrapplingHook.Orientation = Global_VDB_Ptr->VDB_Mat; + TransposeMatrixCH(&GrapplingHook.Orientation); + #endif + } + +} + +static DISPLAYBLOCK* CreateGrapplingHook(void) +{ + STRATEGYBLOCK* sbPtr; + + /* create and initialise a strategy block */ + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) return NULL; /* failure */ + InitialiseSBValues(sbPtr); + + sbPtr->I_SBtype = I_BehaviourGrapplingHook; + + AssignNewSBName(sbPtr); + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + if(sbPtr->DynPtr) + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + dynPtr->PrevPosition = dynPtr->Position = Global_VDB_Ptr->VDB_World; + + GrapplingHook.Orientation = Global_VDB_Ptr->VDB_Mat; + TransposeMatrixCH(&GrapplingHook.Orientation); + dynPtr->OrientMat = GrapplingHook.Orientation; + + dynPtr->LinVelocity.vx = dynPtr->OrientMat.mat31; + dynPtr->LinVelocity.vy = dynPtr->OrientMat.mat32; + dynPtr->LinVelocity.vz = dynPtr->OrientMat.mat33; + } + else + { + /* dynamics block allocation failed... */ + RemoveBehaviourStrategy(sbPtr); + return NULL; + } + + sbPtr->shapeIndex = GetLoadedShapeMSL("spear"); + + sbPtr->maintainVisibility = 0; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), 0); + LOCALASSERT(sbPtr->containingModule); + if(!(sbPtr->containingModule)) + { + /* no containing module can be found... abort*/ + RemoveBehaviourStrategy(sbPtr); + return NULL; + } + { + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + VisibilityDefaultObjectMap.MapShape = sbPtr->shapeIndex; + tempModule.m_mapptr = &VisibilityDefaultObjectMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 0; + tempModule.m_lightarray = (struct lightblock *)0; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr = NULL; /* this is important */ + #if SupportWIndows95 + tempModule.name = NULL; /* this is important */ + #endif + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) + { + RemoveBehaviourStrategy(sbPtr); + return NULL; + } + + sbPtr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbPtr; + dPtr->ObMyModule = NULL; + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + + dPtr->ObRadius=10; + dPtr->ObMaxX=10; + dPtr->ObMinX=-10; + dPtr->ObMaxY=10; + dPtr->ObMinY=-10; + dPtr->ObMaxZ=10; + dPtr->ObMinZ=-10; + /* make displayblock a dynamic module object */ + dPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + +// sbPtr->SBDamageBlock.IsOnFire=1; + + return dPtr; + } + +} + +extern void GrapplingHookBehaviour(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + if (!GrapplingHook.IsEmbedded) + { + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + + if(reportPtr) + { + char stickWhereYouAre = 0; + + if (reportPtr->ObstacleSBPtr) + { + DISPLAYBLOCK *dispPtr = reportPtr->ObstacleSBPtr->SBdptr; + if (dispPtr) + if (dispPtr->ObMyModule && (!dispPtr->ObMorphCtrl)) + { + stickWhereYouAre=1; + } + } + else + { + stickWhereYouAre = 1; + } + + + if(stickWhereYouAre) + { + dynPtr->IsStatic=1; + dynPtr->PrevPosition=dynPtr->Position; + GrapplingHook.Position=dynPtr->Position; + GrapplingHook.IsEmbedded=1; + /* CDF 14/4/99 Make a sound. */ + Sound_Play(SID_GRAPPLE_HIT_WALL,"d",&dynPtr->Position); + return; + } + else + { + DisengageGrapplingHook(); + return; + } + } + } + else + { + GrapplingHook.Tightness -= NormalFrameTime*4; + if (GrapplingHook.Tightness<0) GrapplingHook.Tightness=0; + } +} + +extern void DisengageGrapplingHook(void) +{ + GrapplingHook.IsEngaged = 0; + GrapplingHook.IsEmbedded = 0; + if (GrapplingHook.DispPtr) + { + RemoveBehaviourStrategy(GrapplingHook.DispPtr->ObStrategyBlock); + GrapplingHook.DispPtr=NULL; + } +} + +extern void HandleGrapplingHookForces(void) +{ + if (GrapplingHook.IsEmbedded) + { + DYNAMICSBLOCK *dynPtr = Player->ObStrategyBlock->DynPtr; + VECTORCH direction = GrapplingHook.Position; + int distance; + + direction.vx -= dynPtr->Position.vx; + direction.vy -= dynPtr->Position.vy-1000; + direction.vz -= dynPtr->Position.vz; + + distance = Approximate3dMagnitude(&direction); + if (distance>4096+1024) + { + Normalise(&direction); + dynPtr->LinImpulse.vx += MUL_FIXED(direction.vx,NormalFrameTime); + dynPtr->LinImpulse.vy += MUL_FIXED(direction.vy,NormalFrameTime); + dynPtr->LinImpulse.vz += MUL_FIXED(direction.vz,NormalFrameTime); + } + else if (distance>1024) + { + int s = MUL_FIXED((distance-1024)*16,NormalFrameTime); + Normalise(&direction); + dynPtr->LinImpulse.vx += MUL_FIXED(direction.vx,s); + dynPtr->LinImpulse.vy += MUL_FIXED(direction.vy,s); + dynPtr->LinImpulse.vz += MUL_FIXED(direction.vz,s); + + dynPtr->LinImpulse.vx -= MUL_FIXED(dynPtr->LinImpulse.vx,NormalFrameTime/2); + dynPtr->LinImpulse.vy -= MUL_FIXED(dynPtr->LinImpulse.vy,NormalFrameTime/2); + dynPtr->LinImpulse.vz -= MUL_FIXED(dynPtr->LinImpulse.vz,NormalFrameTime/2); + } + + if (Approximate3dMagnitude(&dynPtr->LinImpulse)>ONE_FIXED) + { + Normalise(&dynPtr->LinImpulse); + } + } +} + +extern void RenderGrapplingHook(void) +{ + if (GrapplingHook.IsEngaged && GrapplingHook.DispPtr) + { + extern void D3D_DrawCable(VECTORCH *centrePtr, MATRIXCH *orientationPtr); + extern int CloakingPhase; + VECTORCH cable[46]; + int i; + { + MATRIXCH mat = Global_VDB_Ptr->VDB_Mat; + TransposeMatrixCH(&mat); + + cable[0].vx = Global_VDB_Ptr->VDB_World.vx-mat.mat31/128; + cable[0].vy = Global_VDB_Ptr->VDB_World.vy-mat.mat32/128+500; + cable[0].vz = Global_VDB_Ptr->VDB_World.vz-mat.mat33/128; + } +// cable[0].vx = Global_VDB_Ptr->VDB_World.vx; +// cable[0].vy = Global_VDB_Ptr->VDB_World.vy+500; +// cable[0].vz = Global_VDB_Ptr->VDB_World.vz; + + for (i=1; i<46; i++) + { + cable[i].vx = ((45-i)*cable[0].vx + (i)*GrapplingHook.DispPtr->ObStrategyBlock->DynPtr->Position.vx)/45; + cable[i].vy = ((45-i)*cable[0].vy + (i)*GrapplingHook.DispPtr->ObStrategyBlock->DynPtr->Position.vy)/45; + cable[i].vz = ((45-i)*cable[0].vz + (i)*GrapplingHook.DispPtr->ObStrategyBlock->DynPtr->Position.vz)/45; + + if (GrapplingHook.Tightness!=0) + { + int x = GetSin((302*i+CloakingPhase)&4095)/256; + int y = GetSin((502*i+200+CloakingPhase)&4095)/256; + int z = GetCos((302*i+100+CloakingPhase)&4095)/256; + int u = GetSin( ((4096*i)/45)&4095 ); + u = MUL_FIXED(MUL_FIXED(u,u),GrapplingHook.Tightness); + cable[i].vx += MUL_FIXED(u,x); + cable[i].vy += MUL_FIXED(u,y); + cable[i].vz += MUL_FIXED(u,z); + } + } + + { + MATRIXCH mat; + VECTORCH dir = cable[45]; + dir.vx -= cable[0].vx; + dir.vy -= cable[0].vy; + dir.vz -= cable[0].vz; + Normalise(&dir); + MakeMatrixFromDirection(&dir,&mat); + D3D_DrawCable(cable, &mat); + } + #if 0 + DISPLAYBLOCK displayblock; + displayblock.ObWorld=GrapplingHook.Position; + displayblock.ObMat=GrapplingHook.Orientation; + displayblock.ObShape=GrapplingHook.ShapeIndex; + displayblock.ObShapeData=GetShapeData(GrapplingHook.ShapeIndex); + + displayblock.name=NULL; + displayblock.ObEuler.EulerX=0; + displayblock.ObEuler.EulerY=0; + displayblock.ObEuler.EulerZ=0; + displayblock.ObFlags=0; + displayblock.ObFlags2=0; + displayblock.ObFlags3=0; + displayblock.ObNumLights=0; + displayblock.ObRadius=0; + displayblock.ObMaxX=0; + displayblock.ObMinX=0; + displayblock.ObMaxY=0; + displayblock.ObMinY=0; + displayblock.ObMaxZ=0; + displayblock.ObMinZ=0; + displayblock.ObTxAnimCtrlBlks=NULL; + displayblock.ObEIDPtr=NULL; + displayblock.ObMorphCtrl=NULL; + displayblock.ObStrategyBlock=NULL; + displayblock.ShapeAnimControlBlock=NULL; + displayblock.HModelControlBlock=NULL; + displayblock.ObMyModule=NULL; + displayblock.SpecialFXFlags = 0; + displayblock.SfxPtr=0; + + MakeVector(&displayblock.ObWorld, &Global_VDB_Ptr->VDB_World, &displayblock.ObView); + RotateVector(&displayblock.ObView, &Global_VDB_Ptr->VDB_Mat); + RenderThisDisplayblock(&displayblock); + { + PARTICLE particle; + particle.Colour = 0xffffffff; + particle.ParticleID = PARTICLE_LASERBEAM; + particle.Position = Player->ObStrategyBlock->DynPtr->Position; + particle.Position.vy-=1000; + particle.Offset = GrapplingHook.DispPtr->ObStrategyBlock->DynPtr->Position; + particle.Size = 20; + RenderParticle(&particle); + } + #endif + + } +} + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" + +typedef struct grapple_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int IsEmbedded; + int IsEngaged; + int Tightness; + + VECTORCH Position; + MATRIXCH Orientation; +//strategy block stuff + DYNAMICSBLOCK dynamics; +}GRAPPLE_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV (&GrapplingHook) + +void LoadStrategy_Grapple(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + GRAPPLE_SAVE_BLOCK* block = (GRAPPLE_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //create the grappling hook + GrapplingHook.DispPtr = CreateGrapplingHook(); + if(!GrapplingHook.DispPtr) return; + + //copy suff from the save block + COPYELEMENT_LOAD(IsEmbedded) + COPYELEMENT_LOAD(IsEngaged) + COPYELEMENT_LOAD(Tightness) + COPYELEMENT_LOAD(Position) + COPYELEMENT_LOAD(Orientation) + + *GrapplingHook.DispPtr->ObStrategyBlock->DynPtr = block->dynamics; +} + +void SaveStrategy_Grapple(STRATEGYBLOCK* sbPtr) +{ + GRAPPLE_SAVE_BLOCK* block; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //copy stuff to the save block + COPYELEMENT_SAVE(IsEmbedded) + COPYELEMENT_SAVE(IsEngaged) + COPYELEMENT_SAVE(Tightness) + COPYELEMENT_SAVE(Position) + COPYELEMENT_SAVE(Orientation) + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; +} \ No newline at end of file diff --git a/3dc/avp/BonusAbilities.h b/3dc/avp/BonusAbilities.h new file mode 100644 index 0000000..f701fae --- /dev/null +++ b/3dc/avp/BonusAbilities.h @@ -0,0 +1,8 @@ +/* KJL 12:09:35 10/09/98 - BonusAbilities.h */ + +/* KJL 12:09:43 10/09/98 - Grappling Hook */ +extern void InitialiseGrapplingHook(void); +extern void ActivateGrapplingHook(void); +extern void HandleGrapplingHookForces(void); +extern void RenderGrapplingHook(void); +extern void DisengageGrapplingHook(void); diff --git a/3dc/avp/CDTrackSelection.cpp b/3dc/avp/CDTrackSelection.cpp new file mode 100644 index 0000000..5b4887d --- /dev/null +++ b/3dc/avp/CDTrackSelection.cpp @@ -0,0 +1,225 @@ +extern "C" +{ +#include "3dc.h" +#include "ourasert.h" +#include "psndplat.h" +#include "dxlog.h" +#include "CD_player.h" +#include "avp_menus.h" +#include "gamedef.h" + +#include "AvP_EnvInfo.h" +#include "dxlog.h" +}; + +#include "list_tem.hpp" + +//lists of tracks for each level +List LevelCDTracks[AVP_ENVIRONMENT_END_OF_LIST]; + +//lists of tracks for each species in multiplayer games +List MultiplayerCDTracks[3]; + +static int LastTrackChosen=-1; + +extern "C" +{ + +void EmptyCDTrackList() +{ + for(int i=0;i & track_list) +{ + //search for a line starting with a # + while(*buffer) + { + if(*buffer=='#') break; + //search for next line + while(*buffer) + { + if(*buffer=='\n') + { + buffer++; + if(*buffer=='\r') buffer++; + break; + } + buffer++; + } + + } + + while(*buffer) + { + //search for a track number or comment + if(*buffer==';') + { + //comment , so no further info on this line + break; + } + else if(*buffer=='\n' || *buffer=='\r') + { + //reached end of line + break; + } + else if(*buffer>='0' && *buffer<='9') + { + int track=-1; + //find a number , add it to the list + sscanf(buffer,"%d",&track); + + if(track>=0) + { + track_list.add_entry(track); + } + + //skip to the next non numerical character + while(*buffer>='0' && *buffer<='9') buffer++; + } + else + { + *buffer++; + } + } + + //go to the next line + while(*buffer) + { + if(*buffer=='\n') + { + buffer++; + if(*buffer=='\r') buffer++; + break; + } + buffer++; + } + +} + +void LoadCDTrackList() +{ + //clear out the old list first + EmptyCDTrackList(); + + HANDLE file=CreateFile(CDTrackFileName,GENERIC_READ, 0, 0, OPEN_EXISTING,FILE_FLAG_RANDOM_ACCESS, 0); + if(file==INVALID_HANDLE_VALUE) + { + LOGDXFMT(("Failed to open %s",CDTrackFileName)); + return; + } + + char* buffer; + int file_size; + unsigned long bytes_read; + + //copy the file contents into a buffer + file_size= GetFileSize(file,0); + buffer=new char[file_size+1]; + ReadFile(file,buffer,file_size,&bytes_read,0); + CloseHandle(file); + + char* bufferptr=buffer; + + + //first extract the multiplayer tracks + for(int i=0;i<3;i++) + { + ExtractTracksForLevel(bufferptr,MultiplayerCDTracks[i]); + } + + //now the level tracks + for(i=0 ;i& track_list) +{ + //make sure we have some tracks in the list + if(!track_list.size()) return FALSE; + + //pick the next track in the list + unsigned int index=TrackSelectCounter % track_list.size(); + + TrackSelectCounter++; + + //play it + CDDA_Stop(); + CDDA_Play(track_list[index]); + + LastTrackChosen = track_list[index]; + return TRUE; +} + + +void CheckCDAndChooseTrackIfNeeded() +{ + static enum playertypes lastPlayerType; + + //are we bothering with cd tracks + if(!CDDA_IsOn()) return; + //is our current track still playing + if(CDDA_IsPlaying()) + { + //if in a multiplayer game see if we have changed character type + if(AvP.Network == I_No_Network || AvP.PlayerType==lastPlayerType) + return; + + //have changed character type , is the current track in the list for this character type + if(MultiplayerCDTracks[AvP.PlayerType].contains(LastTrackChosen)) + return; + + //Lets choose a new track then + } + + + if(AvP.Network == I_No_Network) + { + int level=NumberForCurrentLevel(); + if(level>=0 && level> */ + &BOB_header, + &BOB_header, + &BOB_header, + &BOBCROUCH_header, /* player crouch shape */ + &BOBLIE_header, /* player lying down shape */ + &BOB_header, /* Flamethrower shot - frame 1 */ + &BOB_header, /* Flamethrower shot - frame 2 */ + &BOB_header, + &BOB_header, /*Marine Weapons*/ + &AASHOTGUN_header, + &CANNISTERGUN_header, + &FTHROWER_header, + &SMARTGUN_header, + &PIG_header, + &LATW_header, + &PARTICLE_header, + &ROCKET_header, + &BOB_header, /* alien generator */ +}; +#else +// changed by John to get rid of all compiled in shapes + +SHAPEHEADER* MarineCompiledShapes[] = { + &CUBE_header, + &CUBE_header, + &CUBE_header, /*MarinePlayer*/ + &CUBE_header, /*PredatorPlayer*/ + &CUBE_header, /*AlienPlayer*/ + &CUBE_header, /* was &ALIEN_header, but the textures are no longer there. The old alien should be fully purged. << keywords: BUG FIXME OPTIMIZEME OPTIMISEME ERROR MISTAKE HACK >> */ + &CUBE_header, + &CUBE_header, + &CUBE_header, + &CUBE_header, /* player crouch shape */ + &CUBE_header, /* player lying down shape */ + &CUBE_header, + &CUBE_header, + &CUBE_header, + &CUBE_header, + &CUBE_header, + &CUBE_header, + &CUBE_header, + &CUBE_header, + &CUBE_header, + &CUBE_header, + &CUBE_header, + &CUBE_header, /* alien generator */ +}; +#endif + + +#define STARTOF_PRECOMPILEDSHAPES 0 +int load_precompiled_shapes(void) +{ + static int done = 0; + int i,j = 0; + + if(!mainshapelist) + { + maxshapes=750; + /*I'm not using AllocateMem because I'll have to realloc this later*/ + mainshapelist=(SHAPEHEADER**)malloc(sizeof(SHAPEHEADER*)*maxshapes); + LOCALASSERT(mainshapelist); + if(!mainshapelist) + { + ReleaseDirect3D(); + exit(0x74363); + } + for(i=0;i= NUMBER_OF_SPECIES) + { + *speciesPtr = 0; + } + } + else + { + if (*speciesPtr==0) + { + *speciesPtr = NUMBER_OF_SPECIES; + } + (*speciesPtr)--; + } + } +} + +static int ThereIsAnAllowedEnvironment(void) +{ + int i; + for (i=0; iLevelCompleted[0][environment]) return 1; + } + return 0; + } + case 1: + { + if (environment>=11 && environment<=21) + { + if(UserProfilePtr->LevelCompleted[1][environment-11]) return 1; + } + return 0; + } + case 2: + { + if (environment>=22) + { + if(UserProfilePtr->LevelCompleted[2][environment-22]) return 1; + } + return 0; + } + } +} +extern void CheatMode_GetNextAllowedEnvironment(int *environmentPtr, int searchForward) +{ + while(! (CheatModeDesc[CheatMode_Active].PlayableForEnvironment[*environmentPtr] + && EnvironmentPlayableBySpecies(*environmentPtr) ) ) + { + if (searchForward) + { + (*environmentPtr)++; + if (*environmentPtr>=NUMBER_OF_ENVIRONMENTS) + { + *environmentPtr = 0; + } + } + else + { + if (*environmentPtr==0) + { + *environmentPtr = NUMBER_OF_ENVIRONMENTS; + } + (*environmentPtr)--; + } + } +} + +extern void CheatMode_GetNextAllowedMode(int *cheatModePtr, int searchForward) +{ + while(! (UserProfilePtr->CheatMode[*cheatModePtr])) + { + if (searchForward) + { + (*cheatModePtr)++; + if (*cheatModePtr >= MAX_NUMBER_OF_CHEATMODES) + { + *cheatModePtr = 0; + } + } + else + { + if (*cheatModePtr==0) + { + *cheatModePtr = MAX_NUMBER_OF_CHEATMODES; + } + (*cheatModePtr)--; + } + } +} + +extern int AnyCheatModesAllowed(void) +{ + int i; + for (i=0; iCheatMode[i]) + { + return 1; + } + } + return 0; +} \ No newline at end of file diff --git a/3dc/avp/ConsoleLog.cpp b/3dc/avp/ConsoleLog.cpp new file mode 100644 index 0000000..3c212c4 --- /dev/null +++ b/3dc/avp/ConsoleLog.cpp @@ -0,0 +1,100 @@ +/* KJL 10:19:41 30/03/98 - ConsoleLog.cpp + + This file handles the mirroring of the console text + to a log file. + +*/ +#include +#include +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "gameplat.h" + +#include "debuglog.hpp" +#include "ConsoleLog.hpp" + +#include "bh_types.h" +#include "inventry.h" +#include "bh_alien.h" +#include "bh_pred.h" +#include "bh_xeno.h" +#include "bh_paq.h" +#include "bh_queen.h" +#include "bh_fhug.h" +#include "bh_marin.h" +#include "bh_debri.h" +#include "bh_weap.h" +#include "bh_agun.h" +#include "weapons.h" + +LogFile ConsoleLogFile("ConsoleLog.txt"); + +extern "C" +{ + int LogConsoleTextToFile; +extern void OutputBugReportToConsoleLogfile(char *messagePtr) +{ + extern MODULE *playerPherModule; + extern struct Target PlayersTarget; + + ConsoleLogFile.lprintf("\n*** AvP Automated Bug Report ****\n\n"); + ConsoleLogFile.lprintf("Comment: %s\n\n", (char const*)messagePtr); + + ConsoleLogFile.lprintf("Environment: %s\n", (char const*)Env_List[AvP.CurrentEnv]->main ); + ConsoleLogFile.lprintf("Game type: "); + + if (AvP.Network != I_No_Network) + { + ConsoleLogFile.lprintf("Multiplayer\n"); + } + else + { + ConsoleLogFile.lprintf("Single player\n"); + } + + + ConsoleLogFile.lprintf("Player's Species: "); + switch(AvP.PlayerType) + { + case I_Marine: + ConsoleLogFile.lprintf("Marine\n"); + break; + + case I_Alien: + ConsoleLogFile.lprintf("Alien\n"); + break; + + case I_Predator: + ConsoleLogFile.lprintf("Predator\n"); + break; + } + + ConsoleLogFile.lprintf("\nPlayer's Coords: %d,%d,%d\n",Player->ObWorld.vx,Player->ObWorld.vy,Player->ObWorld.vz); + ConsoleLogFile.lprintf("Player's Module: %d '%s'\n", playerPherModule->m_index,playerPherModule->name); + ConsoleLogFile.lprintf("Player's Module Coords: %d %d %d\n",playerPherModule->m_world.vx,playerPherModule->m_world.vy,playerPherModule->m_world.vz); + ConsoleLogFile.lprintf("Player's Target: %d %d %d\n",PlayersTarget.Position.vx,PlayersTarget.Position.vy,PlayersTarget.Position.vz); + ConsoleLogFile.lprintf("\n"); +} + +}; + +extern void OutputToConsoleLogfile(char *messagePtr) +{ + if(LogConsoleTextToFile) + { + ConsoleLogFile.lprintf("%s\n", (char const*)messagePtr); + } +} + + + + + + + + + \ No newline at end of file diff --git a/3dc/avp/ConsoleLog.hpp b/3dc/avp/ConsoleLog.hpp new file mode 100644 index 0000000..b9e2d03 --- /dev/null +++ b/3dc/avp/ConsoleLog.hpp @@ -0,0 +1,23 @@ +/* KJL 10:19:41 30/03/98 - ConsoleLog.hpp + + This file handles the mirroring of the console text + to a log file. + +*/ +#ifndef ConsoleLog_h_included +#define ConsoleLog_h_included + +extern void OutputToConsoleLogfile(char *messagePtr); + + + +#ifdef __cplusplus +extern "C" +{ +#endif + extern void OutputBugReportToConsoleLogfile(char *messagePtr); +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/3dc/avp/DATABASE.C b/3dc/avp/DATABASE.C new file mode 100644 index 0000000..8e51667 --- /dev/null +++ b/3dc/avp/DATABASE.C @@ -0,0 +1,602 @@ +#include "3dc.h" +#include "module.h" + +#include "stratdef.h" +#include "gamedef.h" + +#include "equipmnt.h" +#include "saveload.h" +#include "font.h" +#include "database.h" + +#include "svldplat.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +// extern old movement functions + +extern int IDemandGoForward(); +extern int IDemandSelect(); +extern int IDemandGoBackward(); +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + +extern void LoadDatabaseMessage(void); +extern void UnloadDatabaseMessage(void); +extern void WriteDatabaseMessage(void); + + +unsigned char *GetTextForMenuOption(enum DB_MENUOPTION_ID optionID); +#if 0 + +struct MenuOptionDescriptor MenuOptionData[MAX_NO_OF_DB_MENUOPTIONS] = +{ + {145,40,FJ_CENTRED}, /* DB_MENUOPTION_RESUME*/ + {145,60,FJ_CENTRED}, /* DB_MENUOPTION_OPTIONS*/ + {145,80,FJ_CENTRED}, /*DB_MENUOPTION_MISSION*/ + {145,100,FJ_CENTRED},/* DB_MENUOPTION_LOAD, */ + {145,120,FJ_CENTRED},/* DB_MENUOPTION_SAVE, */ + {145,140,FJ_CENTRED},/* DB_MENUOPTION_QUIT, */ + {145,80,FJ_CENTRED}, /*DB_MENUOPTION_YESQUIT*/ + {145,100,FJ_CENTRED},/*DB_MENUOPTION_NO*/ + {237,150,FJ_CENTRED},/* DB_MENUOPTION_GOBACK, */ + {125,90,FJ_CENTRED},/* DB_MENUOPTION_ACCESSDENIED */ + {30,30,FJ_LEFT_JUST},/*SLOT0*/ + {30,45,FJ_LEFT_JUST},/*SLOT1*/ + {30,60,FJ_LEFT_JUST},/*SLOT2*/ + {30,75,FJ_LEFT_JUST},/*SLOT3*/ + {30,90,FJ_LEFT_JUST},/*SLOT4*/ + {30,105,FJ_LEFT_JUST},/*SLOT5*/ + {30,120,FJ_LEFT_JUST},/*SLOT6*/ + {30,135,FJ_LEFT_JUST},/*SLOT7*/ +}; +#else +struct MenuOptionDescriptor MenuOptionData[MAX_NO_OF_DB_MENUOPTIONS] = +{ + {0,(ONE_FIXED*4)/32,FJ_CENTRED}, /* DB_MENUOPTION_RESUME*/ + {0,(ONE_FIXED*7)/32,FJ_CENTRED}, /* DB_MENUOPTION_OPTIONS*/ + {0,(ONE_FIXED*10)/32,FJ_CENTRED}, /* DB_MENUOPTION_MISSION*/ + {0,(ONE_FIXED*13)/32,FJ_CENTRED}, /* DB_MENUOPTION_LOAD, */ + {0,(ONE_FIXED*16)/32,FJ_CENTRED}, /* DB_MENUOPTION_SAVE, */ + {0,(ONE_FIXED*19)/32,FJ_CENTRED}, /* DB_MENUOPTION_QUIT, */ + {0,(ONE_FIXED*10)/32,FJ_CENTRED}, /* DB_MENUOPTION_YESQUIT*/ + {0,(ONE_FIXED*13)/32,FJ_CENTRED}, /* DB_MENUOPTION_NO*/ + {0,(ONE_FIXED*16)/32,FJ_CENTRED}, /* DB_MENUOPTION_STARTMENU*/ + {0,(ONE_FIXED*29)/32,FJ_CENTRED}, /* DB_MENUOPTION_GOBACK, */ + {0,(ONE_FIXED*16)/32,FJ_CENTRED}, /* DB_MENUOPTION_ACCESSDENIED */ + {(ONE_FIXED*1)/32,(ONE_FIXED*4)/32,FJ_LEFT_JUST}, /*SLOT0*/ + {(ONE_FIXED*1)/32,(ONE_FIXED*7)/32,FJ_LEFT_JUST}, /*SLOT1*/ + {(ONE_FIXED*1)/32,(ONE_FIXED*10)/32,FJ_LEFT_JUST}, /*SLOT2*/ + {(ONE_FIXED*1)/32,(ONE_FIXED*13)/32,FJ_LEFT_JUST}, /*SLOT3*/ + {(ONE_FIXED*1)/32,(ONE_FIXED*16)/32,FJ_LEFT_JUST}, /*SLOT4*/ + {(ONE_FIXED*1)/32,(ONE_FIXED*19)/32,FJ_LEFT_JUST}, /*SLOT5*/ + {(ONE_FIXED*1)/32,(ONE_FIXED*22)/32,FJ_LEFT_JUST}, /*SLOT6*/ + {(ONE_FIXED*1)/32,(ONE_FIXED*25)/32,FJ_LEFT_JUST}, /*SLOT7*/ +}; +#endif + + +/* KJL 13:09:25 03/17/97 - to be rewritten after alpha */ + +unsigned char *TestMenuOptionText[] = +{ +"RESUME", +"OPTIONS", +"MISSION", +"LOAD", +"SAVE", +"QUIT", +"QUIT TO WINDOWS", +"RESUME", +"QUIT TO START MENU", +"BACK", +"ACCESS DENIED", +"1:", +"2:", +"3:", +"4:", +"5:", +"6:", +"7:", +"8:", +}; + + + +static int NumberOfCurrentDbOptions; +static enum DB_MENUOPTION_ID CurrentDbOptions[MAX_NO_OF_DB_MENUOPTIONS]; +static struct DatabaseInput DatabaseInput={0,0,0}; + +static enum DB_STATE_ID CurrentState; +static int DBStateHasChanged; + +void SetupDatabaseState(enum DB_STATE_ID stateID); +void ClearMenuOptions(void); +void AddMenuOption(enum DB_MENUOPTION_ID optionID); +void ActUponChosenOption(enum DB_MENUOPTION_ID optionID); +enum DB_MENUOPTION_ID DisplayCurrentDatabaseState(enum DB_STATE_ID stateID); +void LoadGraphicsForDatabaseState(enum DB_STATE_ID stateID); +void UnloadGraphicsForDatabaseState(enum DB_STATE_ID stateID); +void DrawSpecialGraphicsForState(enum DB_STATE_ID stateID); + +/* fns that should be platform specific but aren't yet */ +void GetDatabaseInput(void); +void DrawDatabaseMenuOption(enum DB_MENUOPTION_ID optionID, int highlighted); +void DrawDatabaseTextString(unsigned char *textPtr, int x, int y, FONT_JUST justification, int highlighted); +unsigned char *GetTextForMenuOption(enum DB_MENUOPTION_ID optionID); + +void AccessDatabase(int databaseID) +{ + CurrentState = DB_STATE_MAINMENU; + + PlatformSpecificEnteringDatabase(); + + /* database main loop */ + while(CurrentState != DB_STATE_RESUME) + { + enum DB_MENUOPTION_ID chosenOption; + + /* load gfx and setup menu options for current state */ + SetupDatabaseState(CurrentState); + + /* display state and let user select option */ + chosenOption = DisplayCurrentDatabaseState(CurrentState); + + /* kill gfx for current state */ + UnloadGraphicsForDatabaseState(CurrentState); + + /* act upon chosen option, which usually changes state */ + ActUponChosenOption(chosenOption); + } + + PlatformSpecificExitingDatabase(); +} + +void SetupDatabaseState(enum DB_STATE_ID stateID) +{ + LoadGraphicsForDatabaseState(stateID); + + ClearMenuOptions(); + + switch (stateID) + { + case DB_STATE_MAINMENU: + { + AddMenuOption(DB_MENUOPTION_RESUME); + AddMenuOption(DB_MENUOPTION_OPTIONS); + AddMenuOption(DB_MENUOPTION_MISSION); + AddMenuOption(DB_MENUOPTION_LOAD); + AddMenuOption(DB_MENUOPTION_SAVE); + AddMenuOption(DB_MENUOPTION_QUIT); + break; + } + case DB_STATE_OPTIONS: + { + AddMenuOption(DB_MENUOPTION_GOBACK); + break; + } + case DB_STATE_QUIT: + { + AddMenuOption(DB_MENUOPTION_MAINMENU); + AddMenuOption(DB_MENUOPTION_YESQUIT); + AddMenuOption(DB_MENUOPTION_NO); + break; + } + case DB_STATE_MISSION: + { + AddMenuOption(DB_MENUOPTION_GOBACK); + break; + } + case DB_STATE_LOAD: + { + AddMenuOption(DB_MENUOPTION_SAVESLOT0); + AddMenuOption(DB_MENUOPTION_SAVESLOT1); + AddMenuOption(DB_MENUOPTION_SAVESLOT2); + AddMenuOption(DB_MENUOPTION_SAVESLOT3); + AddMenuOption(DB_MENUOPTION_SAVESLOT4); + AddMenuOption(DB_MENUOPTION_SAVESLOT5); + AddMenuOption(DB_MENUOPTION_SAVESLOT6); + AddMenuOption(DB_MENUOPTION_SAVESLOT7); + AddMenuOption(DB_MENUOPTION_GOBACK); + + break; + } + case DB_STATE_SAVE: + { + AddMenuOption(DB_MENUOPTION_SAVESLOT0); + AddMenuOption(DB_MENUOPTION_SAVESLOT1); + AddMenuOption(DB_MENUOPTION_SAVESLOT2); + AddMenuOption(DB_MENUOPTION_SAVESLOT3); + AddMenuOption(DB_MENUOPTION_SAVESLOT4); + AddMenuOption(DB_MENUOPTION_SAVESLOT5); + AddMenuOption(DB_MENUOPTION_SAVESLOT6); + AddMenuOption(DB_MENUOPTION_SAVESLOT7); + AddMenuOption(DB_MENUOPTION_GOBACK); + + break; + } + case DB_STATE_ACCESSDENIED: + { + AddMenuOption(DB_MENUOPTION_ACCESSDENIED); + break; + } + + + default: + { + /* not a valid state, assert */ + LOCALASSERT(0); + break; + } + } +} + + +void ClearMenuOptions(void) +{ + NumberOfCurrentDbOptions=0; +} + + +void AddMenuOption(enum DB_MENUOPTION_ID optionID) +{ + CurrentDbOptions[NumberOfCurrentDbOptions] = optionID; + NumberOfCurrentDbOptions++; +} + + +void ActUponChosenOption(enum DB_MENUOPTION_ID optionID) +{ + switch (optionID) + { + case DB_MENUOPTION_RESUME: + { + CurrentState = DB_STATE_RESUME; + DBStateHasChanged = 1; + break; + } + case DB_MENUOPTION_OPTIONS: + { + CurrentState = DB_STATE_ACCESSDENIED; + DBStateHasChanged = 1; + break; + } + case DB_MENUOPTION_MISSION: + { + CurrentState = DB_STATE_MISSION; + DBStateHasChanged = 1; + break; + } + case DB_MENUOPTION_LOAD: + { + CurrentState = DB_STATE_LOAD; +// LoadGameFromFile(); + break; + } + case DB_MENUOPTION_SAVE: + { + CurrentState = DB_STATE_SAVE; +// SaveGameToFile(); + break; + } + case DB_MENUOPTION_NO: + case DB_MENUOPTION_GOBACK: + case DB_MENUOPTION_ACCESSDENIED: + { + /* return to main menu */ + CurrentState = DB_STATE_MAINMENU; + DBStateHasChanged = 1; + break; + } + case DB_MENUOPTION_SAVESLOT0: + case DB_MENUOPTION_SAVESLOT1: + case DB_MENUOPTION_SAVESLOT2: + case DB_MENUOPTION_SAVESLOT3: + case DB_MENUOPTION_SAVESLOT4: + case DB_MENUOPTION_SAVESLOT5: + case DB_MENUOPTION_SAVESLOT6: + case DB_MENUOPTION_SAVESLOT7: + { + if(DB_STATE_LOAD == CurrentState) + { + LoadSaveSlot(optionID - DB_MENUOPTION_SAVESLOT0); + } + + if(DB_STATE_SAVE == CurrentState) + { + SaveSaveSlot(optionID - DB_MENUOPTION_SAVESLOT0); + } + + CurrentState = DB_STATE_RESUME; + break; + } + case DB_MENUOPTION_QUIT: + { + CurrentState = DB_STATE_QUIT; + DBStateHasChanged = 1; + break; + } + case DB_MENUOPTION_YESQUIT: + { + ExitSystem(); + exit(0); + } + case DB_MENUOPTION_MAINMENU: + { + AvP.MainLoopRunning = 0; + CurrentState = DB_STATE_RESUME; + break; + } + default: + { + /* invalid option */ + LOCALASSERT(0); + break; + } + } +} + + +static int selectedOption; + +enum DB_MENUOPTION_ID DisplayCurrentDatabaseState(enum DB_STATE_ID stateID) +{ + int selectionNotMade = 1; + + selectedOption = 0; + + LOCALASSERT(NumberOfCurrentDbOptions != 0); + + do + { + // JCWH 18/02/98: allow ALT+TAB + CheckForWindowsMessages(); + + /* draw background */ + DrawDatabaseBackground(); + + /* draw weapons, maps etc. as required */ + DrawSpecialGraphicsForState(stateID); + + /* draw all menu options */ + { + int o; + for (o=0; o 0) + { + *(game_name + i) = 0; + } + + i = NUM_SAVE_SLOTS; + + + while(i-- >0) + { + FONT_DESC packet; + int posx, posy; + AVP_FONTS font_num = DATABASE_FONT_DARK; + + + j = GAME_NAME_LENGTH; + + while(j-- > 0) + { + *(game_name + j) = 0; + } + + + ReadSaveSlotGameName(i, game_name); + + posx = ((MenuOptionData[i + DB_MENUOPTION_SAVESLOT0].X*ScreenDescriptorBlock.SDB_Width) >> 16) + 20; + posy = ((MenuOptionData[i + DB_MENUOPTION_SAVESLOT0].Y*ScreenDescriptorBlock.SDB_Height) >> 16); + + if(selectedOption == i) + { + font_num = DATABASE_FONT_LITE; + } + + + packet.fontnum = font_num; + packet.string = game_name; + packet.destx = posx; + packet.desty = posy; + packet.just = FJ_LEFT_JUST; + packet.width = ScreenDescriptorBlock.SDB_Width; + + BLTString(packet); + + } + } + +} + +/* platform specific fns */ + + + +static int debounced = 0; +void GetDatabaseInput(void) +{ + ReadUserInput(); + + DatabaseInput.RequestSelectItem = 0; + DatabaseInput.RequestPreviousItem = 0; + DatabaseInput.RequestNextItem = 0; + + if (IDemandSelect()) + { + if (debounced) + { + DatabaseInput.RequestSelectItem =1; + debounced = 0; + } + } + else if (IDemandGoBackward()) + { + if (debounced) + { + DatabaseInput.RequestNextItem =1; + debounced = 0; + } + } + else if (IDemandGoForward()) + { + if (debounced) + { + DatabaseInput.RequestPreviousItem =1; + debounced = 0; + } + } + else + { + debounced=1; + } + +} + +void DrawDatabaseMenuOption(enum DB_MENUOPTION_ID optionID, int highlighted) +{ + unsigned char *textPtr = GetTextForMenuOption(optionID); + + DrawDatabaseTextString + ( + textPtr, + MenuOptionData[optionID].X, + MenuOptionData[optionID].Y, + MenuOptionData[optionID].justification, + highlighted + ); +} + + +void DrawDatabaseTextString +( + unsigned char *textPtr, + int x, + int y, + FONT_JUST justification, + int highlighted) +{ + FONT_DESC packet; + if (highlighted) packet.fontnum = DATABASE_FONT_LITE; + else packet.fontnum = DATABASE_FONT_DARK; + + packet.string = textPtr; + packet.destx = (x*ScreenDescriptorBlock.SDB_Width) >>16; + packet.desty = (y*ScreenDescriptorBlock.SDB_Height) >>16; + packet.just = justification; + packet.width = ScreenDescriptorBlock.SDB_Width; + + BLTString(packet); +} + + + + + + + + + + +unsigned char *GetTextForMenuOption(enum DB_MENUOPTION_ID optionID) +{ + return TestMenuOptionText[optionID]; +} + + +int DatabaseStateChange() +{ + if(DBStateHasChanged) + { + DBStateHasChanged = 0; + + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/3dc/avp/DATABASE.H b/3dc/avp/DATABASE.H new file mode 100644 index 0000000..3a0ea7c --- /dev/null +++ b/3dc/avp/DATABASE.H @@ -0,0 +1,72 @@ + +#define NUM_SAVE_SLOTS 10 + +enum DB_STATE_ID +{ + DB_STATE_MAINMENU, + DB_STATE_QUIT, + DB_STATE_OPTIONS, + DB_STATE_MISSION, + DB_STATE_LOAD, + DB_STATE_SAVE, + DB_STATE_RESUME, + DB_STATE_ACCESSDENIED, + + MAX_NO_OF_DB_STATES +}; + +enum DB_MENUOPTION_ID +{ + DB_MENUOPTION_RESUME, + DB_MENUOPTION_OPTIONS, + DB_MENUOPTION_MISSION, + DB_MENUOPTION_LOAD, + DB_MENUOPTION_SAVE, + DB_MENUOPTION_QUIT, + DB_MENUOPTION_YESQUIT, + DB_MENUOPTION_NO, + DB_MENUOPTION_MAINMENU, + DB_MENUOPTION_GOBACK, + DB_MENUOPTION_ACCESSDENIED, + DB_MENUOPTION_SAVESLOT0, + DB_MENUOPTION_SAVESLOT1, + DB_MENUOPTION_SAVESLOT2, + DB_MENUOPTION_SAVESLOT3, + DB_MENUOPTION_SAVESLOT4, + DB_MENUOPTION_SAVESLOT5, + DB_MENUOPTION_SAVESLOT6, + DB_MENUOPTION_SAVESLOT7, + + MAX_NO_OF_DB_MENUOPTIONS +}; + + +struct DatabaseInput +{ + unsigned char RequestSelectItem :1; + unsigned char RequestPreviousItem :1; + unsigned char RequestNextItem :1; +}; + +struct MenuOptionDescriptor +{ + /* top-left coords */ + int X; + int Y; + FONT_JUST justification; +}; + + + + +extern void AccessDatabase(int databaseID); + +/* KJL 15:43:16 04/11/97 - platform specific */ +extern void PlatformSpecificEnteringDatabase(void); +extern void PlatformSpecificExitingDatabase(void); + +extern void DrawDatabaseBackground(void); + +extern void UpdateDatabaseScreen(void); + +extern int DatabaseStateChange(); \ No newline at end of file diff --git a/3dc/avp/DYNAMICS.H b/3dc/avp/DYNAMICS.H new file mode 100644 index 0000000..ca71b50 --- /dev/null +++ b/3dc/avp/DYNAMICS.H @@ -0,0 +1,57 @@ +#ifndef _dynamics_h_ /* KJL 17:23:01 11/05/96 - is this your first time? */ +#define _dynamics_h_ 1 +#include "particle.h" + +/*KJL************************************************************************ +* DYNAMICS.H * +* - this file contains prototypes for the functions in dynamics.c * +* which can be called externally. * +************************************************************************KJL*/ + + +/*KJL**************************************************************************************** +* S T R U C T U R E S * +****************************************************************************************KJL*/ +struct ColPolyTag +{ + int NumberOfVertices; + VECTORCH PolyPoint[4]; + VECTORCH PolyNormal; + DISPLAYBLOCK *ParentObject; +}; + + +/*KJL**************************************************************************************** +* P H Y S I C A L C O N S T A N T S * +****************************************************************************************KJL*/ + +#define GRAVITY_STRENGTH 25000 +#define TIME_BEFORE_GRAVITY_KICKS_IN 16384 + +#define MAXIMUM_STEP_HEIGHT 450 +#define MAX_ANG_VELOCITY 8192 +#define MAX_MOVES 4 + +//16384 + +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ +extern void ObjectDynamics(void); +extern void DynamicallyRotateObject(DYNAMICSBLOCK *dynPtr); + + +/* externs to shape access fns (platform specific) */ +extern int SetupPolygonAccess(DISPLAYBLOCK *objectPtr); +extern void AccessNextPolygon(void); +extern void GetPolygonVertices(struct ColPolyTag *polyPtr); +extern void GetPolygonNormal(struct ColPolyTag *polyPtr); + + + +/* extra camera movement */ +extern EULER HeadOrientation; + +extern int ParticleDynamics(PARTICLE *particlePtr, VECTORCH *obstacleNormalPtr, int *moduleIndexPtr); + +#endif /* end of preprocessor condition for file wrapping */ diff --git a/3dc/avp/DYNBLOCK.C b/3dc/avp/DYNBLOCK.C new file mode 100644 index 0000000..aed4cb0 --- /dev/null +++ b/3dc/avp/DYNBLOCK.C @@ -0,0 +1,801 @@ +#include "3dc.h" +#include "dynblock.h" + +#define UseLocalAssert No +#include "ourasert.h" + + +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ +void InitialiseDynamicsBlocks(void); +DYNAMICSBLOCK* AllocateDynamicsBlock(enum DYNAMICS_TEMPLATE_ID templateID); +void DeallocateDynamicsBlock(DYNAMICSBLOCK *dynPtr); + +void InitialiseCollisionReports(void); +COLLISIONREPORT* AllocateCollisionReport(DYNAMICSBLOCK* dynPtr); + +static DYNAMICSBLOCK DynBlockStorage[MAX_NO_OF_DYNAMICS_BLOCKS]; +static int NumFreeDynBlocks; +static DYNAMICSBLOCK *FreeDynBlockList[MAX_NO_OF_DYNAMICS_BLOCKS]; +static DYNAMICSBLOCK **FreeDynBlockListPtr; + +static COLLISIONREPORT CollisionReportStorage[MAX_NO_OF_COLLISION_REPORTS]; +int NumFreeCollisionReports; + +static DYNAMICSBLOCK DynamicsTemplate[]= +{ + /* DYNAMICS_TEMPLATE_MARINE_PLAYER */ + { + {0,0,0},/* EULER OrientEuler - Euler Orientation */ + {0,0,0,0,0,0,0,0,0},/* MATRIXCH OrientMat - Local -> World Orientation Matrix */ + {0,0,0},/* EULER PrevOrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH PrevOrientMat - Local -> World Orientation Matrix */ + + {0,0,0},/* VECTORCH Position */ + {0,0,0},/* VECTORCH PrevPosition */ + + {0,0,0},/* VECTORCH LinVelocity */ + {0,0,0},/* VECTORCH LinImpulse */ + + {0,0,0},/* EULER AngVelocity */ + {0,0,0},/* EULER AngImpulse */ + + NULL, /* struct collisionreport *CollisionReportPtr; */ + + {0,65536,0},/* VECTORCH GravityDirection */ + 0, /* int TimeNotInContactWithFloor */ + + 0,/* int Friction; */ + 0,/* int Elasticity; */ + 80*2, /* int Mass */ + + DYN_TYPE_NRBB_COLLISIONS, + TOPPLE_FORCE_NONE, + + 1,/* GravityOn :1; */ + 1,/* UseStandardGravity :1 - ie. in direction of increasing Y */ + 0,/* StopOnCollision :1; */ + 1,/* CanClimbStairs :1; */ + 0,/* IsStatic :1; */ + 0,/* OnlyCollideWithObjects :1; */ + 0,/* IsNetGhost :1; */ + 0,/* IgnoreSameObjectsAsYou :1; */ + 0,/* IgnoreThePlayer :1; */ + 0,/* UseDisplacement :1; */ + 0,/* OnlyCollideWithEnvironment :1; */ + + + 0,/* IsInContactWithFloor :1 */ + 0,/* IsInContactWithNearlyFlatFloor */ + 0,/* RequestsToStandUp :1 */ + 0,/* IsFloating :1 */ + 0,/* IsPickupObject :1 */ + 0,/* IsInanimate :1; */ + 0,/* IgnoresNotVisPolys :1; */ + }, + /* DYNAMICS_TEMPLATE_ALIEN_NPC */ + { + {0,0,0},/* EULER OrientEuler - Euler Orientation */ + {0,0,0,0,0,0,0,0,0},/* MATRIXCH OrientMat - Local -> World Orientation Matrix */ + {0,0,0},/* EULER PrevOrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH PrevOrientMat - Local -> World Orientation Matrix */ + + {0,0,0},/* VECTORCH Position */ + {0,0,0},/* VECTORCH PrevPosition */ + + {0,0,0},/* VECTORCH LinVelocity */ + {0,0,0},/* VECTORCH LinImpulse */ + + {0,0,0},/* EULER AngVelocity */ + {0,0,0},/* EULER AngImpulse */ + + NULL, /* struct collisionreport *CollisionReportPtr; */ + + {0,65536,0},/* VECTORCH GravityDirection */ + 0, /* int TimeNotInContactWithFloor */ + + 1,/* int Friction; */ + 0,/* int Elasticity; */ + 100, /* int Mass */ + + DYN_TYPE_NRBB_COLLISIONS, + TOPPLE_FORCE_ALIEN, + + 1,/* GravityOn :1; */ + 0,/* UseStandardGravity :1 - ie. in direction of increasing Y */ + 0,/* StopOnCollision :1; */ + 1,/* CanClimbStairs :1; */ + 0,/* IsStatic :1; */ + 0,/* OnlyCollideWithObjects :1; */ + 0,/* IsNetGhost :1; */ + 0,/* IgnoreSameObjectsAsYou :1; */ + 0,/* IgnoreThePlayer :1; */ + 0,/* UseDisplacement :1; */ + 0,/* OnlyCollideWithEnvironment :1; */ + + + 0,/* IsInContactWithFloor :1 */ + 0,/* IsInContactWithNearlyFlatFloor */ + 0,/* RequestsToStandUp :1 */ + 0,/* IsFloating :1 */ + 0,/* IsPickupObject :1 */ + 0,/* IsInanimate :1; */ + 0,/* IgnoresNotVisPolys :1; */ + }, + /* DYNAMICS_TEMPLATE_GRENADE */ + { + {0,0,0},/* EULER OrientEuler - Euler Orientation */ + {0,0,0,0,0,0,0,0,0},/* MATRIXCH OrientMat - Local -> World Orientation Matrix */ + {0,0,0},/* EULER PrevOrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH PrevOrientMat - Local -> World Orientation Matrix */ + + {0,0,0},/* VECTORCH Position */ + {0,0,0},/* VECTORCH PrevPosition */ + + {0,0,0},/* VECTORCH LinVelocity */ + {0,0,0},/* VECTORCH LinImpulse */ + + {0,0,0},/* EULER AngVelocity */ + {0,0,0},/* EULER AngImpulse */ + + NULL, /* struct collisionreport *CollisionReportPtr; */ + + {0,0,0},/* VECTORCH GravityDirection */ + 0, /* int TimeNotInContactWithFloor */ + + 0,/* int Friction; */ + 32768/2,/* int Elasticity; */ + 20, /* int Mass */ + + DYN_TYPE_NRBB_COLLISIONS, + TOPPLE_FORCE_FULL, + + 1,/* GravityOn :1; */ + 1,/* UseStandardGravity :1 - ie. in direction of increasing Y */ + 0,/* StopOnCollision :1; */ + 0,/* CanClimbStairs :1; */ + 0,/* IsStatic :1; */ + 0,/* OnlyCollideWithObjects :1; */ + 0,/* IsNetGhost :1; */ + 0,/* IgnoreSameObjectsAsYou :1; */ + 1,/* IgnoreThePlayer :1; */ + 0,/* UseDisplacement :1; */ + 0,/* OnlyCollideWithEnvironment :1; */ + + 0,/* IsInContactWithFloor :1 */ + 0,/* IsInContactWithNearlyFlatFloor */ + 0,/* RequestsToStandUp :1 */ + 0,/* IsFloating :1 */ + 0,/* IsPickupObject :1 */ + 0,/* IsInanimate :1; */ + 0,/* IgnoresNotVisPolys :1; */ + }, + /* DYNAMICS_TEMPLATE_ROCKET & predator disc weapon */ + { + {0,0,0},/* EULER OrientEuler - Euler Orientation */ + {0,0,0,0,0,0,0,0,0},/* MATRIXCH OrientMat - Local -> World Orientation Matrix */ + {0,0,0},/* EULER PrevOrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH PrevOrientMat - Local -> World Orientation Matrix */ + + {0,0,0},/* VECTORCH Position */ + {0,0,0},/* VECTORCH PrevPosition */ + + {0,0,0},/* VECTORCH LinVelocity */ + {0,0,0},/* VECTORCH LinImpulse */ + + {0,0,0},/* EULER AngVelocity */ + {0,0,0},/* EULER AngImpulse */ + + NULL, /* struct collisionreport *CollisionReportPtr; */ + + {0,0,0},/* VECTORCH GravityDirection */ + 0, /* int TimeNotInContactWithFloor */ + + 0,/* int Friction; */ + 65536,/* int Elasticity; */ + 40, /* int Mass */ + + DYN_TYPE_NRBB_COLLISIONS, + TOPPLE_FORCE_NONE, + + 0,/* GravityOn :1; */ + 0,/* UseStandardGravity :1 - ie. in direction of increasing Y */ + 1,/* StopOnCollision :1; */ + 0,/* CanClimbStairs :1; */ + 0,/* IsStatic :1; */ + 0,/* OnlyCollideWithObjects :1; */ + 0,/* IsNetGhost :1; */ + 0,/* IgnoreSameObjectsAsYou :1; */ + 1,/* IgnoreThePlayer :1; */ + 0,/* UseDisplacement :1; */ + 0,/* OnlyCollideWithEnvironment :1; */ + + 0,/* IsInContactWithFloor :1 */ + 0,/* IsInContactWithNearlyFlatFloor */ + 0,/* RequestsToStandUp :1 */ + 0,/* IsFloating :1 */ + 0,/* IsPickupObject :1 */ + 0,/* IsInanimate :1; */ + 0,/* IgnoresNotVisPolys :1; */ + }, + /* DYNAMICS_TEMPLATE_DEBRIS */ + { + {0,0,0},/* EULER OrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH OrientMat - Local -> World Orientation Matrix */ + {0,0,0},/* EULER PrevOrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH PrevOrientMat - Local -> World Orientation Matrix */ + + {0,0,0},/* VECTORCH Position */ + {0,0,0},/* VECTORCH PrevPosition */ + + {0,0,0},/* VECTORCH LinVelocity */ + {0,0,0},/* VECTORCH LinImpulse */ + + {0,0,0},/* EULER AngVelocity */ + {0,0,0},/* EULER AngImpulse */ + + NULL, /* struct collisionreport *CollisionReportPtr; */ + + {0,0,0},/* VECTORCH GravityDirection */ + 0, /* int TimeNotInContactWithFloor */ + + 0,/* int Friction; */ + 0,/* int Elasticity; */ + 30, /* int Mass */ + + DYN_TYPE_NO_COLLISIONS, + TOPPLE_FORCE_NONE, + + 1,/* GravityOn :1; */ + 1,/* UseStandardGravity :1 - ie. in direction of increasing Y */ + 0,/* StopOnCollision :1; */ + 0,/* CanClimbStairs :1; */ + 0,/* IsStatic :1; */ + 0,/* OnlyCollideWithObjects :1; */ + 0,/* IsNetGhost :1; */ + 0,/* IgnoreSameObjectsAsYou :1; */ + 0,/* IgnoreThePlayer :1; */ + 0,/* UseDisplacement :1; */ + 1,/* OnlyCollideWithEnvironment :1; */ + + 0,/* IsInContactWithFloor :1 */ + 0,/* IsInContactWithNearlyFlatFloor */ + 0,/* RequestsToStandUp :1 */ + 0,/* IsFloating :1 */ + 0,/* IsPickupObject :1 */ + 0,/* IsInanimate :1; */ + 0,/* IgnoresNotVisPolys :1; */ + }, + /* DYNAMICS_TEMPLATE_STATIC */ + { + {0,0,0},/* EULER OrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH OrientMat - Local -> World Orientation Matrix */ + {0,0,0},/* EULER PrevOrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH PrevOrientMat - Local -> World Orientation Matrix */ + + {0,0,0},/* VECTORCH Position */ + {0,0,0},/* VECTORCH PrevPosition */ + + {0,0,0},/* VECTORCH LinVelocity */ + {0,0,0},/* VECTORCH LinImpulse */ + + {0,0,0},/* EULER AngVelocity */ + {0,0,0},/* EULER AngImpulse */ + + NULL, /* struct collisionreport *CollisionReportPtr; */ + + {0,0,0},/* VECTORCH GravityDirection */ + 0, /* int TimeNotInContactWithFloor */ + + 0,/* int Friction; */ + 0,/* int Elasticity; */ + 100, /* int Mass */ + + DYN_TYPE_NRBB_COLLISIONS, + TOPPLE_FORCE_NONE, + + 1,/* GravityOn :1; */ + 1,/* UseStandardGravity :1 - ie. in direction of increasing Y */ + 0,/* StopOnCollision :1; */ + 0,/* CanClimbStairs :1; */ + 1,/* IsStatic :1; */ + 0,/* OnlyCollideWithObjects :1; */ + 0,/* IsNetGhost :1; */ + 0,/* IgnoreSameObjectsAsYou :1; */ + 0,/* IgnoreThePlayer :1; */ + 0,/* UseDisplacement :1; */ + 0,/* OnlyCollideWithEnvironment :1; */ + + 0,/* IsInContactWithFloor :1 */ + 0,/* IsInContactWithNearlyFlatFloor */ + 0,/* RequestsToStandUp :1 */ + 0,/* IsFloating :1 */ + 0,/* IsPickupObject :1 */ + 0,/* IsInanimate :1; */ + 0,/* IgnoresNotVisPolys :1; */ + }, + /* DYNAMICS_TEMPLATE_INANIMATE */ + { + {0,0,0},/* EULER OrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH OrientMat - Local -> World Orientation Matrix */ + {0,0,0},/* EULER PrevOrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH PrevOrientMat - Local -> World Orientation Matrix */ + + {0,0,0},/* VECTORCH Position */ + {0,0,0},/* VECTORCH PrevPosition */ + + {0,0,0},/* VECTORCH LinVelocity */ + {0,0,0},/* VECTORCH LinImpulse */ + + {0,0,0},/* EULER AngVelocity */ + {0,0,0},/* EULER AngImpulse */ + + NULL, /* struct collisionreport *CollisionReportPtr; */ + + {0,0,0},/* VECTORCH GravityDirection */ + 0, /* int TimeNotInContactWithFloor */ + + 1,/* int Friction; */ + 16384,/* int Elasticity; */ + 65536, /* int Mass */ + + DYN_TYPE_NRBB_COLLISIONS, + TOPPLE_FORCE_FULL, + + 1,/* GravityOn :1; */ + 1,/* UseStandardGravity :1 - ie. in direction of increasing Y */ + 0,/* StopOnCollision :1; */ + 0,/* CanClimbStairs :1; */ + 0,/* IsStatic :1; */ + 0,/* OnlyCollideWithObjects :1; */ + 0,/* IsNetGhost :1; */ + 0,/* IgnoreSameObjectsAsYou :1; */ + 0,/* IgnoreThePlayer :1; */ + 0,/* UseDisplacement :1; */ + 0,/* OnlyCollideWithEnvironment :1; */ + + 0,/* IsInContactWithFloor :1 */ + 0,/* IsInContactWithNearlyFlatFloor */ + 0,/* RequestsToStandUp :1 */ + 0,/* IsFloating :1 */ + 0,/* IsPickupObject :1 */ + 1,/* IsInanimate :1; */ + 0,/* IgnoresNotVisPolys :1; */ + }, + /* DYNAMICS_TEMPLATE_PICKUPOBJECT */ + { + {0,0,0},/* EULER OrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH OrientMat - Local -> World Orientation Matrix */ + {0,0,0},/* EULER PrevOrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH PrevOrientMat - Local -> World Orientation Matrix */ + + {0,0,0},/* VECTORCH Position */ + {0,0,0},/* VECTORCH PrevPosition */ + + {0,0,0},/* VECTORCH LinVelocity */ + {0,0,0},/* VECTORCH LinImpulse */ + + {0,0,0},/* EULER AngVelocity */ + {0,0,0},/* EULER AngImpulse */ + + NULL, /* struct collisionreport *CollisionReportPtr; */ + + {0,0,0},/* VECTORCH GravityDirection */ + 0, /* int TimeNotInContactWithFloor */ + + 0,/* int Friction; */ + 16384,/* int Elasticity; */ + 20, /* int Mass */ + + DYN_TYPE_NRBB_COLLISIONS, + TOPPLE_FORCE_FULL, + + 0,/* GravityOn :1; */ + 1,/* UseStandardGravity :1 - ie. in direction of increasing Y */ + 0,/* StopOnCollision :1; */ + 0,/* CanClimbStairs :1; */ + 0,/* IsStatic :1; */ + 0,/* OnlyCollideWithObjects :1; */ + 0,/* IsNetGhost :1; */ + 0,/* IgnoreSameObjectsAsYou :1; */ + 0,/* IgnoreThePlayer :1; */ + 0,/* UseDisplacement :1; */ + 0,/* OnlyCollideWithEnvironment :1; */ + + 0,/* IsInContactWithFloor :1 */ + 0,/* IsInContactWithNearlyFlatFloor */ + 0,/* RequestsToStandUp :1 */ + 0,/* IsFloating :1 */ + 1,/* IsPickupObject :1 */ + 0,/* IsInanimate :1; */ + 0,/* IgnoresNotVisPolys :1; */ + }, + /* DYNAMICS_TEMPLATE_SPRITE_NPC */ + { + {0,0,0},/* EULER OrientEuler - Euler Orientation */ + {0,0,0,0,0,0,0,0,0},/* MATRIXCH OrientMat - Local -> World Orientation Matrix */ + {0,0,0},/* EULER PrevOrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH PrevOrientMat - Local -> World Orientation Matrix */ + + {0,0,0},/* VECTORCH Position */ + {0,0,0},/* VECTORCH PrevPosition */ + + {0,0,0},/* VECTORCH LinVelocity */ + {0,0,0},/* VECTORCH LinImpulse */ + + {0,0,0},/* EULER AngVelocity */ + {0,0,0},/* EULER AngImpulse */ + + NULL, /* struct collisionreport *CollisionReportPtr; */ + + {0,65536,0},/* VECTORCH GravityDirection */ + 0, /* int TimeNotInContactWithFloor */ + + 1,/* int Friction; */ + 0,/* int Elasticity; */ + 80*2, /* int Mass */ + + DYN_TYPE_NRBB_COLLISIONS, + TOPPLE_FORCE_NONE, + + 1,/* GravityOn :1; */ + 1,/* UseStandardGravity :1 - ie. in direction of increasing Y */ + 0,/* StopOnCollision :1; */ + 1,/* CanClimbStairs :1; */ + 0,/* IsStatic :1; */ + 0,/* OnlyCollideWithObjects :1; */ + 0,/* IsNetGhost :1; */ + 0,/* IgnoreSameObjectsAsYou :1; */ + 0,/* IgnoreThePlayer :1; */ + 0,/* UseDisplacement :1; */ + 0,/* OnlyCollideWithEnvironment :1; */ + + 0,/* IsInContactWithFloor :1 */ + 0,/* IsInContactWithNearlyFlatFloor */ + 0,/* RequestsToStandUp :1 */ + 0,/* IsFloating :1 */ + 0,/* IsPickupObject :1 */ + 0,/* IsInanimate :1; */ + 0,/* IgnoresNotVisPolys :1; */ + }, + /* DYNAMICS_TEMPLATE_STATIC_SPRITE */ + { + {0,0,0},/* EULER OrientEuler - Euler Orientation */ + {0,0,0,0,0,0,0,0,0},/* MATRIXCH OrientMat - Local -> World Orientation Matrix */ + {0,0,0},/* EULER PrevOrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH PrevOrientMat - Local -> World Orientation Matrix */ + + {0,0,0},/* VECTORCH Position */ + {0,0,0},/* VECTORCH PrevPosition */ + + {0,0,0},/* VECTORCH LinVelocity */ + {0,0,0},/* VECTORCH LinImpulse */ + + {0,0,0},/* EULER AngVelocity */ + {0,0,0},/* EULER AngImpulse */ + + NULL, /* struct collisionreport *CollisionReportPtr; */ + + {0,65536,0},/* VECTORCH GravityDirection */ + 0, /* int TimeNotInContactWithFloor */ + + 1,/* int Friction; */ + 0,/* int Elasticity; */ + 80*2, /* int Mass */ + + DYN_TYPE_SPRITE_COLLISIONS, + TOPPLE_FORCE_NONE, + + 1,/* GravityOn :1; */ + 1,/* UseStandardGravity :1 - ie. in direction of increasing Y */ + 0,/* StopOnCollision :1; */ + 1,/* CanClimbStairs :1; */ + 1,/* IsStatic :1; */ + 0,/* OnlyCollideWithObjects :1; */ + 0,/* IsNetGhost :1; */ + 0,/* IgnoreSameObjectsAsYou :1; */ + 0,/* IgnoreThePlayer :1; */ + 0,/* UseDisplacement :1; */ + 0,/* OnlyCollideWithEnvironment :1; */ + + 0,/* IsInContactWithFloor :1 */ + 0,/* IsInContactWithNearlyFlatFloor */ + 0,/* RequestsToStandUp :1 */ + 0,/* IsFloating :1 */ + 0,/* IsPickupObject :1 */ + 0,/* IsInanimate :1; */ + 0,/* IgnoresNotVisPolys :1; */ + }, + /* DYNAMICS_TEMPLATE_PLATFORM_LIFT */ + { + {0,0,0},/* EULER OrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH OrientMat - Local -> World Orientation Matrix */ + {0,0,0},/* EULER PrevOrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH PrevOrientMat - Local -> World Orientation Matrix */ + + {0,0,0},/* VECTORCH Position */ + {0,0,0},/* VECTORCH PrevPosition */ + + {0,0,0},/* VECTORCH LinVelocity */ + {0,0,0},/* VECTORCH LinImpulse */ + + {0,0,0},/* EULER AngVelocity */ + {0,0,0},/* EULER AngImpulse */ + + NULL, /* struct collisionreport *CollisionReportPtr; */ + + {0,0,0},/* VECTORCH GravityDirection */ + 0, /* int TimeNotInContactWithFloor */ + + 0,/* int Friction; */ + 0,/* int Elasticity; */ + 1, /* int Mass */ + + DYN_TYPE_NRBB_COLLISIONS, + TOPPLE_FORCE_NONE, + + 0,/* GravityOn :1; */ + 1,/* UseStandardGravity :1 - ie. in direction of increasing Y */ + 1,/* StopOnCollision :1; */ + 0,/* CanClimbStairs :1; */ + 0,/* IsStatic :1; */ + 1,/* OnlyCollideWithObjects :1; */ + 0,/* IsNetGhost :1; */ + 0,/* IgnoreSameObjectsAsYou :1; */ + 0,/* IgnoreThePlayer :1; */ + 1,/* UseDisplacement :1; */ + 0,/* OnlyCollideWithEnvironment :1; */ + + 0,/* IsInContactWithFloor :1 */ + 0,/* IsInContactWithNearlyFlatFloor */ + 0,/* RequestsToStandUp :1 */ + 0,/* IsFloating :1 */ + 0,/* IsPickupObject :1 */ + 0,/* IsInanimate :1; */ + 0,/* IgnoresNotVisPolys :1; */ + }, + /* DYNAMICS_TEMPLATE_ALIEN_DEBRIS */ + { + {0,0,0},/* EULER OrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH OrientMat - Local -> World Orientation Matrix */ + {0,0,0},/* EULER PrevOrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH PrevOrientMat - Local -> World Orientation Matrix */ + + {0,0,0},/* VECTORCH Position */ + {0,0,0},/* VECTORCH PrevPosition */ + + {0,0,0},/* VECTORCH LinVelocity */ + {0,0,0},/* VECTORCH LinImpulse */ + + {0,0,0},/* EULER AngVelocity */ + {0,0,0},/* EULER AngImpulse */ + + NULL, /* struct collisionreport *CollisionReportPtr; */ + + {0,0,0},/* VECTORCH GravityDirection */ + 0, /* int TimeNotInContactWithFloor */ + + 0,/* int Friction; */ + 0,/* int Elasticity; */ + 1, /* int Mass */ + + DYN_TYPE_NRBB_COLLISIONS, + TOPPLE_FORCE_NONE, + + 1,/* GravityOn :1; */ + 1,/* UseStandardGravity :1 - ie. in direction of increasing Y */ + 0,/* StopOnCollision :1; */ + 0,/* CanClimbStairs :1; */ + 0,/* IsStatic :1; */ + 0,/* OnlyCollideWithObjects :1; */ + 0,/* IsNetGhost :1; */ + 1,/* IgnoreSameObjectsAsYou :1; */ + 0,/* IgnoreThePlayer :1; */ + 0,/* UseDisplacement :1; */ + 1,/* OnlyCollideWithEnvironment :1; */ + + 0,/* IsInContactWithFloor :1 */ + 0,/* IsInContactWithNearlyFlatFloor */ + 0,/* RequestsToStandUp :1 */ + 0,/* IsFloating :1 */ + 0,/* IsPickupObject :1 */ + 0,/* IsInanimate :1; */ + 0,/* IgnoresNotVisPolys :1; */ + }, + /* DYNAMICS_TEMPLATE_ACID_SMOKE */ + { + {0,0,0},/* EULER OrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH OrientMat - Local -> World Orientation Matrix */ + {0,0,0},/* EULER PrevOrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH PrevOrientMat - Local -> World Orientation Matrix */ + + {0,0,0},/* VECTORCH Position */ + {0,0,0},/* VECTORCH PrevPosition */ + + {0,0,0},/* VECTORCH LinVelocity */ + {0,0,0},/* VECTORCH LinImpulse */ + + {0,0,0},/* EULER AngVelocity */ + {0,0,0},/* EULER AngImpulse */ + + NULL, /* struct collisionreport *CollisionReportPtr; */ + + {0,-ONE_FIXED,0},/* VECTORCH GravityDirection */ + 0, /* int TimeNotInContactWithFloor */ + + 0,/* int Friction; */ + 0,/* int Elasticity; */ + 1, /* int Mass */ + + DYN_TYPE_NO_COLLISIONS, + TOPPLE_FORCE_NONE, + + 1,/* GravityOn :1; */ + 0,/* UseStandardGravity :1 - ie. in direction of increasing Y */ + 0,/* StopOnCollision :1; */ + 0,/* CanClimbStairs :1; */ + 0,/* IsStatic :1; */ + 0,/* OnlyCollideWithObjects :1; */ + 0,/* IsNetGhost :1; */ + 0,/* IgnoreSameObjectsAsYou :1; */ + 0,/* IgnoreThePlayer :1; */ + 0,/* UseDisplacement :1; */ + 0,/* OnlyCollideWithEnvironment :1; */ + + 0,/* IsInContactWithFloor :1 */ + 0,/* IsInContactWithNearlyFlatFloor */ + 0,/* RequestsToStandUp :1 */ + 0,/* IsFloating :1 */ + 0,/* IsPickupObject :1 */ + 0,/* IsInanimate :1; */ + 0,/* IgnoresNotVisPolys :1; */ + }, + /* DYNAMICS_TEMPLATE_NET_GHOST */ + { + {0,0,0},/* EULER OrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH OrientMat - Local -> World Orientation Matrix */ + {0,0,0},/* EULER PrevOrientEuler - Euler Orientation */ + {65536,0,0,0,65536,0,0,0,65536},/* MATRIXCH PrevOrientMat - Local -> World Orientation Matrix */ + + {0,0,0},/* VECTORCH Position */ + {0,0,0},/* VECTORCH PrevPosition */ + + {0,0,0},/* VECTORCH LinVelocity */ + {0,0,0},/* VECTORCH LinImpulse */ + + {0,0,0},/* EULER AngVelocity */ + {0,0,0},/* EULER AngImpulse */ + + NULL, /* struct collisionreport *CollisionReportPtr; */ + + {0,0,0},/* VECTORCH GravityDirection */ + 0, /* int TimeNotInContactWithFloor */ + + 0,/* int Friction; */ + 0,/* int Elasticity; */ + 100, /* int Mass */ + + DYN_TYPE_NRBB_COLLISIONS, + TOPPLE_FORCE_NONE, + + 1,/* GravityOn :1; */ + 1,/* UseStandardGravity :1 - ie. in direction of increasing Y */ + 0,/* StopOnCollision :1; */ + 0,/* CanClimbStairs :1; */ + 0,/* IsStatic :1; */ + 0,/* OnlyCollideWithObjects :1; */ + 1,/* IsNetGhost :1; */ + 0,/* IgnoreSameObjectsAsYou :1; */ + 0,/* IgnoreThePlayer :1; */ + 0,/* UseDisplacement :1; */ + 0,/* OnlyCollideWithEnvironment :1; */ + + 0,/* IsInContactWithFloor :1 */ + 0,/* IsInContactWithNearlyFlatFloor */ + 0,/* RequestsToStandUp :1 */ + 0,/* IsFloating :1 */ + 0,/* IsPickupObject :1 */ + 0,/* IsInanimate :1; */ + 0,/* IgnoresNotVisPolys :1; */ + }, + + + + +}; + + +/*KJL*************************************************************************** +* FUNCTIONS TO ALLOCATE AND DEALLOCATE DYNAMICS BLOCKS - KJL 12:02:14 11/13/96 * +***************************************************************************KJL*/ +void InitialiseDynamicsBlocks(void) +{ + DYNAMICSBLOCK *freeBlockPtr = DynBlockStorage; + int blk; + + for(blk=0; blk < MAX_NO_OF_DYNAMICS_BLOCKS; blk++) + { + FreeDynBlockList[blk] = freeBlockPtr++; + } + + FreeDynBlockListPtr = &FreeDynBlockList[MAX_NO_OF_DYNAMICS_BLOCKS-1]; + NumFreeDynBlocks = MAX_NO_OF_DYNAMICS_BLOCKS; +} + + +DYNAMICSBLOCK* AllocateDynamicsBlock(enum DYNAMICS_TEMPLATE_ID templateID) +{ + DYNAMICSBLOCK *dynPtr = 0; /* Default to null ptr */ + + if (NumFreeDynBlocks) + { + dynPtr = *FreeDynBlockListPtr--; + NumFreeDynBlocks--; + GLOBALASSERT(templateID>=0); + GLOBALASSERT(templateIDCollisionReportPtr) /* already some reports */ + { + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + + /* search for the last report */ + while(reportPtr->NextCollisionReportPtr) + reportPtr = reportPtr->NextCollisionReportPtr; + reportPtr->NextCollisionReportPtr = newReportPtr; + } + else /* object's first report */ + { + dynPtr->CollisionReportPtr = newReportPtr; + } + + /* make report the end of the list */ + newReportPtr->NextCollisionReportPtr=0; + } + else + { + /* unable to allocate a collision block I'm afraid */ + LOCALASSERT(1==0); + } + + return newReportPtr; +} + diff --git a/3dc/avp/DYNBLOCK.H b/3dc/avp/DYNBLOCK.H new file mode 100644 index 0000000..ad0f58a --- /dev/null +++ b/3dc/avp/DYNBLOCK.H @@ -0,0 +1,142 @@ +#ifndef _dynblock_h_ /* Is this your first time? */ +#define _dynblock_h_ 1 + +/*KJL**************************************************************************************** +* S T R U C T U R E S * +****************************************************************************************KJL*/ +enum DYN_TYPE +{ + DYN_TYPE_NO_COLLISIONS, + DYN_TYPE_SPRITE_COLLISIONS, + DYN_TYPE_SPHERE_COLLISIONS, + DYN_TYPE_NRBB_COLLISIONS, + DYN_TYPE_CUBOID_COLLISIONS, +}; + +enum TOPPLE_FORCE +{ + TOPPLE_FORCE_NONE, + TOPPLE_FORCE_ALIEN, + TOPPLE_FORCE_FULL +}; + +/* KJL 17:19:14 11/05/96 - my 'dynamicsblock'. I'll use the enginesque lower/upper case naming convention */ +typedef struct dynamicsblock +{ + /* representations of orientation of object */ + EULER OrientEuler; /* Euler Orientation */ + MATRIXCH OrientMat; /* Local -> World Orientation Matrix */ + EULER PrevOrientEuler; /* Euler Orientation */ + MATRIXCH PrevOrientMat; /* Local -> World Orientation Matrix */ + + /* position in World Space (units mm) */ + VECTORCH Position; + VECTORCH PrevPosition; + + /* component of velocity (in World Space, units mm per sec) due to internal forces + eg. a player walking forward, a rocket's thrust - set by strategies */ + VECTORCH LinVelocity; + /* component of velocity (in World Space, units mm per sec) due to external forces + eg. gravity, explosions, jumping - set by dynamics system & strategies */ + VECTORCH LinImpulse; + + /* angular velocity in World Space */ + EULER AngVelocity; + /* rotational effects due to external forces */ + EULER AngImpulse; + + /* pointer to report(s) on last frame's collisions (singly-linked list) */ + struct collisionreport *CollisionReportPtr; + + /* object's normalised gravity vector - used if UseStandardGravity is set to false */ + VECTORCH GravityDirection; + int TimeNotInContactWithFloor; + + /* physical constants */ + int Friction; /* difficult to set a scale as yet */ + int Elasticity; /* 0 = perfectly inelastic, 65536 = perfectly elastic */ + int Mass; /* integer in kg */ + + /* collision flags */ + /* eg. can go up steps, cuboid model etc */ + + enum DYN_TYPE DynamicsType; + enum TOPPLE_FORCE ToppleForce; + + unsigned int GravityOn :1; + unsigned int UseStandardGravity :1; /* ie. in direction of increasing Y */ + unsigned int StopOnCollision :1; /* eg. missiles stop as soon as bthey hit something; players don't */ + unsigned int CanClimbStairs :1; + unsigned int IsStatic :1; + unsigned int OnlyCollideWithObjects :1; + unsigned int IsNetGhost :1; + unsigned int IgnoreSameObjectsAsYou :1; /* don't collide with objects which have the same behaviour type */ + unsigned int IgnoreThePlayer :1; + unsigned int UseDisplacement :1; + unsigned int OnlyCollideWithEnvironment :1; + + unsigned int IsInContactWithFloor :1; + unsigned int IsInContactWithNearlyFlatFloor :1; + unsigned int RequestsToStandUp :1; + unsigned int IsFloating :1; + unsigned int IsPickupObject :1; + unsigned int IsInanimate :1; + unsigned int IgnoresNotVisPolys :1; + + + /* FOR INTERNAL USE ONLY */ + int CollisionRadius; + int DistanceLeftToMove; + VECTORCH Displacement; + VECTORCH ObjectVertices[8]; /* vertices of the cuboid which describes the object */ + +} DYNAMICSBLOCK; + + +enum DYNAMICS_TEMPLATE_ID +{ + DYNAMICS_TEMPLATE_MARINE_PLAYER, + DYNAMICS_TEMPLATE_ALIEN_NPC, + DYNAMICS_TEMPLATE_GRENADE, + DYNAMICS_TEMPLATE_ROCKET, + DYNAMICS_TEMPLATE_DEBRIS, + DYNAMICS_TEMPLATE_STATIC, + DYNAMICS_TEMPLATE_INANIMATE, + DYNAMICS_TEMPLATE_PICKUPOBJECT, + DYNAMICS_TEMPLATE_SPRITE_NPC, + DYNAMICS_TEMPLATE_STATIC_SPRITE, + DYNAMICS_TEMPLATE_PLATFORM_LIFT, + DYNAMICS_TEMPLATE_ALIEN_DEBRIS, + DYNAMICS_TEMPLATE_ACID_SMOKE, + DYNAMICS_TEMPLATE_NET_GHOST, + + MAX_NO_OF_DYNAMICS_TEMPLATES +}; + +typedef struct collisionreport +{ + /* strategy block of whatever you've hit - this is null if you've hit the landscape */ + struct strategyblock *ObstacleSBPtr; + + /* the normal of the obstacle's face which you've hit */ + VECTORCH ObstacleNormal; + VECTORCH ObstaclePoint; + + /* ptr to the next report, null if there isn't one */ + struct collisionreport *NextCollisionReportPtr; + +} COLLISIONREPORT; + +#define MAX_NO_OF_DYNAMICS_BLOCKS maxstblocks +#define MAX_NO_OF_COLLISION_REPORTS 400 +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ +extern void InitialiseDynamicsBlocks(void); +extern DYNAMICSBLOCK* AllocateDynamicsBlock(enum DYNAMICS_TEMPLATE_ID templateID); +extern void DeallocateDynamicsBlock(DYNAMICSBLOCK *dynPtr); + +extern void InitialiseCollisionReports(void); +extern COLLISIONREPORT* AllocateCollisionReport(DYNAMICSBLOCK* dynPtr); + +#endif /* end of preprocessor condition for file wrapping */ diff --git a/3dc/avp/DetailLevels.c b/3dc/avp/DetailLevels.c new file mode 100644 index 0000000..7fc88ef --- /dev/null +++ b/3dc/avp/DetailLevels.c @@ -0,0 +1,162 @@ +#include "DetailLevels.h" + +DETAIL_LEVELS LocalDetailLevels; +MENU_DETAIL_LEVEL_OPTIONS MenuDetailLevelOptions; + +extern int GlobalLevelOfDetail_Hierarchical; + + +extern void SetToDefaultDetailLevels(void) +{ +#if 0 + LocalDetailLevels.BloodCollidesWithEnvironment=1; + LocalDetailLevels.DrawLightCoronas=1; + LocalDetailLevels.DrawHierarchicalDecals=1; + LocalDetailLevels.ExplosionsDeformToEnvironment=1; + LocalDetailLevels.GhostFlameThrowerCollisions=0; + + LocalDetailLevels.MaximumAllowedNumberOfDecals = 1024; + LocalDetailLevels.AlienEnergyViewThreshold = 0; + LocalDetailLevels.NumberOfSmokeParticlesFromLargeExplosion=10; + LocalDetailLevels.NumberOfSmokeParticlesFromSmallExplosion=5; + + GlobalLevelOfDetail_Hierarchical = 65536; +#endif + + MenuDetailLevelOptions.DecalNumber = 3; + MenuDetailLevelOptions.LightCoronas = 1; + MenuDetailLevelOptions.DecalsOnCharacters = 1; + MenuDetailLevelOptions.DeformableExplosions = 1; + MenuDetailLevelOptions.CharacterComplexity = 3; + MenuDetailLevelOptions.ParticleComplexity = 1; + SetDetailLevelsFromMenu(); +} + +extern void SetToMinimalDetailLevels(void) +{ +#if 0 + LocalDetailLevels.BloodCollidesWithEnvironment=0; + LocalDetailLevels.DrawLightCoronas=0; + LocalDetailLevels.DrawHierarchicalDecals=0; + LocalDetailLevels.ExplosionsDeformToEnvironment=0; + LocalDetailLevels.GhostFlameThrowerCollisions=0; + + LocalDetailLevels.MaximumAllowedNumberOfDecals = 16; + LocalDetailLevels.AlienEnergyViewThreshold = 450; + LocalDetailLevels.NumberOfSmokeParticlesFromLargeExplosion=5; + LocalDetailLevels.NumberOfSmokeParticlesFromSmallExplosion=2; + + GlobalLevelOfDetail_Hierarchical = 128*65536; +#endif + + MenuDetailLevelOptions.DecalNumber = 0; + MenuDetailLevelOptions.LightCoronas = 0; + MenuDetailLevelOptions.DecalsOnCharacters = 0; + MenuDetailLevelOptions.DeformableExplosions = 0; + MenuDetailLevelOptions.CharacterComplexity = 0; + MenuDetailLevelOptions.ParticleComplexity = 0; + SetDetailLevelsFromMenu(); +} + + +extern void SetDetailLevelsFromMenu(void) +{ + switch (MenuDetailLevelOptions.DecalNumber) + { + default: + case 0: + { + LocalDetailLevels.MaximumAllowedNumberOfDecals = 16; + break; + } + case 1: + { + LocalDetailLevels.MaximumAllowedNumberOfDecals = 128; + break; + } + case 2: + { + LocalDetailLevels.MaximumAllowedNumberOfDecals = 512; + break; + } + case 3: + { + LocalDetailLevels.MaximumAllowedNumberOfDecals = 1024; + break; + } + } + + LocalDetailLevels.DrawLightCoronas = MenuDetailLevelOptions.LightCoronas; + LocalDetailLevels.DrawHierarchicalDecals = MenuDetailLevelOptions.DecalsOnCharacters; + LocalDetailLevels.ExplosionsDeformToEnvironment = MenuDetailLevelOptions.DeformableExplosions; + + switch (MenuDetailLevelOptions.CharacterComplexity) + { + default: + case 0: + { + GlobalLevelOfDetail_Hierarchical = 65536*128; + break; + } + case 1: + { + GlobalLevelOfDetail_Hierarchical = 65536*4; + break; + } + case 2: + { + GlobalLevelOfDetail_Hierarchical = 65536*2; + break; + } + case 3: + { + GlobalLevelOfDetail_Hierarchical = 65536; + break; + } + } + + switch (MenuDetailLevelOptions.ParticleComplexity) + { + default: + case 0: + { + LocalDetailLevels.BloodCollidesWithEnvironment=0; + LocalDetailLevels.AlienEnergyViewThreshold = 300; + LocalDetailLevels.NumberOfSmokeParticlesFromLargeExplosion=5; + LocalDetailLevels.NumberOfSmokeParticlesFromSmallExplosion=2; + LocalDetailLevels.GhostFlameThrowerCollisions=0; + break; + } + case 1: + { + LocalDetailLevels.BloodCollidesWithEnvironment=1; + LocalDetailLevels.AlienEnergyViewThreshold = 0; + LocalDetailLevels.NumberOfSmokeParticlesFromLargeExplosion=10; + LocalDetailLevels.NumberOfSmokeParticlesFromSmallExplosion=5; + LocalDetailLevels.GhostFlameThrowerCollisions=1; + break; + } + } + +} + + + + + + + + + + + + + + + + + + + + + diff --git a/3dc/avp/DetailLevels.h b/3dc/avp/DetailLevels.h new file mode 100644 index 0000000..bd170df --- /dev/null +++ b/3dc/avp/DetailLevels.h @@ -0,0 +1,38 @@ +#ifndef _detaillevels_h_ +#define _detaillevels_h_ 1 +typedef struct +{ + unsigned int MaximumAllowedNumberOfDecals; + unsigned int AlienEnergyViewThreshold; + unsigned int NumberOfSmokeParticlesFromLargeExplosion; + unsigned int NumberOfSmokeParticlesFromSmallExplosion; + + unsigned int BloodCollidesWithEnvironment :1; + unsigned int DrawLightCoronas :1; + unsigned int DrawHierarchicalDecals :1; + unsigned int ExplosionsDeformToEnvironment :1; + unsigned int GhostFlameThrowerCollisions :1; + +} DETAIL_LEVELS; + +extern DETAIL_LEVELS LocalDetailLevels; +typedef struct +{ + int DecalNumber; + int LightCoronas; + int DecalsOnCharacters; + int DeformableExplosions; + int CharacterComplexity; + int ParticleComplexity; + +} MENU_DETAIL_LEVEL_OPTIONS; + +extern MENU_DETAIL_LEVEL_OPTIONS MenuDetailLevelOptions; + + +extern void SetToDefaultDetailLevels(void); +extern void SetToMinimalDetailLevels(void); + +extern void SetDetailLevelsFromMenu(void); + +#endif \ No newline at end of file diff --git a/3dc/avp/Dynamics.c b/3dc/avp/Dynamics.c new file mode 100644 index 0000000..b05f067 --- /dev/null +++ b/3dc/avp/Dynamics.c @@ -0,0 +1,6444 @@ +/* KJL 12:42:43 29/12/98 - this is effectively Dynamics V4.0. If you think this code looks bad, +you should have seen the previous versions. */ + +#include "3dc.h" +#include "module.h" +#include "inline.h" +#include "stratdef.h" +#include "gamedef.h" +#include "dynblock.h" +#include "dynamics.h" + +#include "bh_types.h" +#include "comp_shp.h" +#include "avpview.h" +#include "pvisible.h" +#include "extents.h" + +#include "bh_marin.h" +#include "bh_pred.h" +#include "bh_alien.h" +#include "showcmds.h" +#include "pldghost.h" +#include "weapons.h" + +#include "bh_track.h" +#include "bh_fan.h" +#include "detaillevels.h" +#include "dxlog.h" +#include "avp_userprofile.h" +#include "pfarlocs.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +#define TELEPORT_IF_OUTSIDE_ENV 1 +#define MINIMUM_BOUNDINGBOX_EXTENT 25 + + +#define FLOOR_THRESHOLD 30000 +#define NEARLYFLATFLOOR_THRESHOLD 60000 + +#if 0 + extern int GlobalFrameCounter; + #define LogInfo LOGDXFMT +#else + #define LogInfo(args) (void)0 +#endif + +extern MORPHDISPLAY MorphDisplay; +extern VECTORCH MorphedPts[]; +extern VECTORCH *ShapePointsPtr; +extern int *ShapeNormalsPtr; +extern int *Shape2NormalsPtr; +extern char ShapeIsMorphed; +extern int **ItemArrayPtr; +extern POLYHEADER *PolyheaderPtr; +extern DAMAGE_PROFILE FlechetteDamage; +extern DAMAGE_PROFILE FallingDamage; +extern DAMAGE_PROFILE PredPistol_FlechetteDamage; + +#define AccessNextPolygon()\ +{\ + int *itemPtr = *(ItemArrayPtr++);\ + PolyheaderPtr = (POLYHEADER *) itemPtr;\ +} + +#define GetPolygonVertices(polyPtr)\ +{\ + int *vertexNumberPtr = &PolyheaderPtr->Poly1stPt;\ +\ + (polyPtr)->PolyPoint[0] = *(ShapePointsPtr + *vertexNumberPtr++);\ + (polyPtr)->PolyPoint[1] = *(ShapePointsPtr + *vertexNumberPtr++);\ + (polyPtr)->PolyPoint[2] = *(ShapePointsPtr + *vertexNumberPtr++);\ + \ + if (*vertexNumberPtr != Term)\ + {\ + (polyPtr)->PolyPoint[3] = *(ShapePointsPtr + *vertexNumberPtr);\ + (polyPtr)->NumberOfVertices=4; \ + }\ + else\ + {\ + (polyPtr)->NumberOfVertices=3; \ + }\ +} +#define GetPolygonNormal(polyPtr)\ +{ \ + if (ShapeIsMorphed)\ + {\ + VECTORCH n1Ptr = *(VECTORCH*)(ShapeNormalsPtr + PolyheaderPtr->PolyNormalIndex);\ + VECTORCH n2Ptr = *(VECTORCH*)(Shape2NormalsPtr + PolyheaderPtr->PolyNormalIndex);\ + \ + if( ((n1Ptr.vx == n2Ptr.vx)\ + && (n1Ptr.vy == n2Ptr.vy)\ + && (n1Ptr.vz == n2Ptr.vz))\ + || (MorphDisplay.md_lerp == 0) )\ + {\ + (polyPtr)->PolyNormal = n1Ptr;\ + }\ + else if(MorphDisplay.md_lerp == 0xffff)\ + {\ + (polyPtr)->PolyNormal = n2Ptr;\ + }\ + else\ + {\ + VECTORCH *pointPtr[3];\ + int *vertexNumPtr = &PolyheaderPtr->Poly1stPt;\ +\ + pointPtr[0] = (ShapePointsPtr + *vertexNumPtr++);\ + pointPtr[1] = (ShapePointsPtr + *vertexNumPtr++);\ + pointPtr[2] = (ShapePointsPtr + *vertexNumPtr);\ +\ + MakeNormal\ + (\ + pointPtr[0],\ + pointPtr[1],\ + pointPtr[2],\ + &(polyPtr)->PolyNormal\ + );\ + }\ + }\ + else /* not morphed */\ + {\ + (polyPtr)->PolyNormal = *(VECTORCH*)(ShapeNormalsPtr + PolyheaderPtr->PolyNormalIndex);\ + }\ +} +#define PolygonFlag (PolyheaderPtr->PolyFlags) + +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ +extern void ObjectDynamics(void); + +static void InitialiseDynamicObjectsList(void); +static void UpdateDisplayBlockData(STRATEGYBLOCK *sbPtr); + +static void ApplyGravity(DYNAMICSBLOCK *dynPtr); +static void AlignObjectToGravityDirection(DYNAMICSBLOCK *dynPtr); +static void AlignObjectToStandardGravityDirection(DYNAMICSBLOCK *dynPtr); +static void VectorHomingForSurfaceAlign(VECTORCH *currentPtr, VECTORCH *targetPtr, VECTORCH *perpendicularPtr); + +extern void DynamicallyRotateObject(DYNAMICSBLOCK *dynPtr); + +static void FindLandscapePolygonsInObjectsPath(STRATEGYBLOCK *sbPtr); +static void FindObjectsToRelocateAgainst(STRATEGYBLOCK *sbPtr); +static void FindObjectPolygonsInObjectsPath(STRATEGYBLOCK *sbPtr); + +static void MakeDynamicBoundingBoxForObject(STRATEGYBLOCK *sbPtr, VECTORCH *worldOffsetPtr); +static void TestShapeWithDynamicBoundingBox(DISPLAYBLOCK *objectPtr, DYNAMICSBLOCK *mainDynPtr); +static void TestObjectWithStaticBoundingBox(DISPLAYBLOCK *objectPtr); +static void TestShapeWithParticlesDynamicBoundingBox(DISPLAYBLOCK *objectPtr); + + +static void CreateSphereBBForObject(const STRATEGYBLOCK *sbPtr); +static signed int DistanceMovedBeforeSphereHitsPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove); +static int SphereProjectOntoPoly(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, VECTORCH *projectedPosition); +static void MakeStaticBoundingBoxForSphere(STRATEGYBLOCK *sbPtr); +static int RelocateSphere(STRATEGYBLOCK *sbPtr); + + +static void CreateNRBBForObject(const STRATEGYBLOCK *sbPtr); +static signed int DistanceMovedBeforeNRBBHitsPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove); +static int NRBBProjectsOntoPolygon(DYNAMICSBLOCK *dynPtr, int vertexToPlaneDist[], struct ColPolyTag *polyPtr, VECTORCH *projectionDirPtr); +static void MakeStaticBoundingBoxForNRBB(STRATEGYBLOCK *sbPtr); +static int RelocateNRBB(STRATEGYBLOCK *sbPtr); + +static void FindLandscapePolygonsInObjectsVicinity(STRATEGYBLOCK *sbPtr); +static signed int DistanceMovedBeforeNRBBHitsNegYPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove); +static signed int DistanceMovedBeforeNRBBHitsPosYPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove); +static signed int DistanceMovedBeforeNRBBHitsNegXPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove); +static signed int DistanceMovedBeforeNRBBHitsPosXPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove); +static signed int DistanceMovedBeforeNRBBHitsNegZPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove); +static signed int DistanceMovedBeforeNRBBHitsPosZPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove); +static void TestForValidMovement(STRATEGYBLOCK *sbPtr); +static int MoveObject(STRATEGYBLOCK *sbPtr); +static void TestForValidPlayerStandUp(STRATEGYBLOCK *sbPtr); +static int SteppingUpIsValid(STRATEGYBLOCK *sbPtr); +static void TestShapeWithStaticBoundingBox(DISPLAYBLOCK *objectPtr); +static int IsPolygonWithinDynamicBoundingBox(const struct ColPolyTag *polyPtr); +static int IsPolygonWithinStaticBoundingBox(const struct ColPolyTag *polyPtr); +static int WhichNRBBVertex(DYNAMICSBLOCK *dynPtr, VECTORCH *normalPtr); +static int DoesPolygonIntersectNRBB(struct ColPolyTag *polyPtr,VECTORCH *objectVertices); + + +static signed int (*DistanceMovedBeforeObjectHitsPolygon)(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove); +static void (*MakeStaticBoundingBoxForObject)(STRATEGYBLOCK *sbPtr); +static int (*RelocationIsValid)(STRATEGYBLOCK *sbPtr); + +static void MovePlatformLift(STRATEGYBLOCK *sbPtr); +static void FindLandscapePolygonsInParticlesPath(PARTICLE *particlePtr, VECTORCH *displacementPtr); +void AddEffectsOfForceGenerators(VECTORCH *positionPtr, VECTORCH *impulsePtr, int mass); + +VECTORCH *GetNearestModuleTeleportPoint(MODULE* thisModulePtr, VECTORCH* positionPtr); + +/*KJL**************************************************************************************** +* D E F I N E S * +****************************************************************************************KJL*/ + +#define AddVectorToVector(v2,v1)\ +{ \ + v1.vx += v2.vx; \ + v1.vy += v2.vy; \ + v1.vz += v2.vz; \ +} +#define SubVectorFromVector(v2,v1)\ +{ \ + v1.vx -= v2.vx; \ + v1.vy -= v2.vy; \ + v1.vz -= v2.vz; \ +} + +#define AddScaledVectorToVector(v2,s,v1) \ +{ \ + v1.vx += MUL_FIXED(v2.vx, s); \ + v1.vy += MUL_FIXED(v2.vy, s); \ + v1.vz += MUL_FIXED(v2.vz, s); \ +} +#define SubScaledVectorFromVector(v2,s,v1) \ +{ \ + v1.vx -= MUL_FIXED(v2.vx, s); \ + v1.vy -= MUL_FIXED(v2.vy, s); \ + v1.vz -= MUL_FIXED(v2.vz, s); \ +} + + + +/*KJL**************************************************************************************** +* G L O B A L S * +****************************************************************************************KJL*/ +extern int NumActiveStBlocks; +extern STRATEGYBLOCK *ActiveStBlockList[maxstblocks]; +extern int NormalFrameTime; + + +#define COLLISION_GRANULARITY 10 // 40 +#define RELOCATION_GRANULARITY 5 // 30 +#define GRAVITY_DISPLACEMENT (COLLISION_GRANULARITY+1) +#define MAXIMUM_NUMBER_OF_COLLISIONPOLYS 3000 +#define PLAYER_PICKUP_OBJECT_RADIUS 1600 + + +static STRATEGYBLOCK *DynamicObjectsList[MAX_NO_OF_DYNAMICS_BLOCKS]; +static int NumberOfDynamicObjects = 1; + +static int AccelDueToGravity; +static int DistanceToStepUp; +static VECTORCH DirectionOfTravel; + +static struct ColPolyTag CollisionPolysArray[MAXIMUM_NUMBER_OF_COLLISIONPOLYS]; +static struct ColPolyTag *CollisionPolysPtr; +static int NumberOfCollisionPolys; + +#define MAX_NUMBER_OF_INTERFERENCE_POLYGONS 100 +static struct ColPolyTag InterferencePolygons[MAX_NUMBER_OF_INTERFERENCE_POLYGONS]; +static int NumberOfInterferencePolygons = 0; + +/* global storage of bounding box */ +static int DBBMinX,DBBMaxX, DBBMinY,DBBMaxY, DBBMinZ,DBBMaxZ; +static int SBBMinX,SBBMaxX, SBBMinY,SBBMaxY, SBBMinZ,SBBMaxZ; + +const static int CuboidVertexList[]={0,1,5,4, 0,4,6,2, 0,2,3,1, 1,3,7,5, 4,5,7,6, 3,2,6,7}; +int PlanarGravity=1; + +static int PlayersFallingSpeed; +int PlayersMaxHeightWhilstNotInContactWithGround; +/*KJL**************************************************************************************** +* F U N C T I O N S * +****************************************************************************************KJL*/ + +/* Entry point to dynamics system - this function handles the movement of all objects */ +extern void ObjectDynamics(void) +{ + int i; + /* textprint("player Impulse at %d,%d,%d\n", + Player->ObStrategyBlock->DynPtr->LinImpulse.vx, + Player->ObStrategyBlock->DynPtr->LinImpulse.vy, + Player->ObStrategyBlock->DynPtr->LinImpulse.vz); + */ +// if (TICKERTAPE_CHEATMODE) +// PlayerPheromoneTrail(); + + if (FREEFALL_CHEATMODE) + { + PlanarGravity = 0; + } + else + { + PlanarGravity = 1; + } + /* clear previous frame's collision reports */ + InitialiseCollisionReports(); + + /* create ordered list of dynamic objects */ + InitialiseDynamicObjectsList(); + + { + DYNAMICSBLOCK *dynPtr = Player->ObStrategyBlock->DynPtr; + LogInfo + (( + "Dynamics Logging: frame %d\nDL: player's Position %d,%d,%d\nDL: player's Displacement %d,%d,%d\nDL: NormalFrameTime %d\n", + GlobalFrameCounter, + dynPtr->Position.vx,dynPtr->Position.vy,dynPtr->Position.vz, + dynPtr->Displacement.vx,dynPtr->Displacement.vy,dynPtr->Displacement.vz, + NormalFrameTime + )); + + } + + i = NumberOfDynamicObjects; + /* scan through objects */ + while(i--) + { + STRATEGYBLOCK *sbPtr = DynamicObjectsList[i]; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + GLOBALASSERT(dynPtr->Mass>0); + + if (dynPtr->IsNetGhost || (dynPtr->IsPickupObject && !dynPtr->GravityOn)) + { + #if 0 + dynPtr->Position.vx += MUL_FIXED(dynPtr->LinVelocity.vx, NormalFrameTime); + dynPtr->Position.vy += MUL_FIXED(dynPtr->LinVelocity.vy, NormalFrameTime); + dynPtr->Position.vz += MUL_FIXED(dynPtr->LinVelocity.vz, NormalFrameTime); + AlignObjectToStandardGravityDirection(dynPtr); + #endif + UpdateDisplayBlockData(sbPtr); + continue; + } + /* setup function pointers */ + switch(dynPtr->DynamicsType) + { + case DYN_TYPE_SPHERE_COLLISIONS: + { + DistanceMovedBeforeObjectHitsPolygon = DistanceMovedBeforeSphereHitsPolygon; + MakeStaticBoundingBoxForObject = MakeStaticBoundingBoxForSphere; + RelocationIsValid = RelocateSphere; + break; + } + case DYN_TYPE_NRBB_COLLISIONS: + { + DistanceMovedBeforeObjectHitsPolygon = DistanceMovedBeforeNRBBHitsPolygon; + MakeStaticBoundingBoxForObject = MakeStaticBoundingBoxForNRBB; + RelocationIsValid = RelocateNRBB; + break; + } + default: + { + /* oh dear, invalid collision shape */ + GLOBALASSERT(0); + break; + } + } + if ((sbPtr->SBdptr == Player) && dynPtr->RequestsToStandUp) + TestForValidPlayerStandUp(sbPtr); +#if 0 + if (dynPtr->OnlyCollideWithObjects) + { + /* initialise near polygons array */ + CollisionPolysPtr = &CollisionPolysArray[0]; + NumberOfCollisionPolys=0; + } + else + { + /* find which landscape polygons occupy the space + through which the object wishes to move */ + FindLandscapePolygonsInObjectsPath(sbPtr); + } +#endif + if (dynPtr->OnlyCollideWithObjects) + { + /* initialise near polygons array */ + CollisionPolysPtr = &CollisionPolysArray[0]; + NumberOfCollisionPolys=0; + MovePlatformLift(sbPtr); + } + else if (dynPtr->StopOnCollision) + { + if (dynPtr->OnlyCollideWithObjects) + { + /* initialise near polygons array */ + CollisionPolysPtr = &CollisionPolysArray[0]; + NumberOfCollisionPolys=0; + FindObjectPolygonsInObjectsPath(sbPtr); + } + else + { + /* find which landscape polygons occupy the space + through which the object wishes to move */ + FindLandscapePolygonsInObjectsPath(sbPtr); + if (!dynPtr->OnlyCollideWithEnvironment) + { + FindObjectPolygonsInObjectsPath(sbPtr); + } + } + while(dynPtr->DistanceLeftToMove && !MoveObject(sbPtr)); + } + else + { + int noOfMoves=4; + int maxMoveLimit=10; + + if (dynPtr->OnlyCollideWithObjects) + { + /* initialise near polygons array */ + CollisionPolysPtr = &CollisionPolysArray[0]; + NumberOfCollisionPolys=0; + FindObjectPolygonsInObjectsPath(sbPtr); + } + else + { + /* find which landscape polygons occupy the space + through which the object wishes to move */ + FindLandscapePolygonsInObjectsPath(sbPtr); + if (!dynPtr->OnlyCollideWithEnvironment) + { + FindObjectPolygonsInObjectsPath(sbPtr); + } + } + + while (dynPtr->DistanceLeftToMove && noOfMoves && maxMoveLimit) + { + int hitSomethingWhileMoving; + + if (ShowDebuggingText.Dynamics) PrintDebuggingText("Displacement:%d,%d,%d\n", + dynPtr->Displacement.vx, + dynPtr->Displacement.vy, + dynPtr->Displacement.vz); + + hitSomethingWhileMoving = MoveObject(sbPtr); + + if(hitSomethingWhileMoving||DistanceToStepUp) + { + if (dynPtr->OnlyCollideWithObjects) + { + /* initialise near polygons array */ + CollisionPolysPtr = &CollisionPolysArray[0]; + NumberOfCollisionPolys=0; + FindObjectPolygonsInObjectsPath(sbPtr); + } + else + { + /* find which landscape polygons occupy the space + through which the object wishes to move */ + FindLandscapePolygonsInObjectsPath(sbPtr); + if (!dynPtr->OnlyCollideWithEnvironment) + { + FindObjectPolygonsInObjectsPath(sbPtr); + } + } + } + if(hitSomethingWhileMoving&&!DistanceToStepUp) + { + noOfMoves--; + } + + maxMoveLimit--; + } + } + + /* friction */ + #if 0 + if (dynPtr->IsInContactWithFloor) + { + int scale = NormalFrameTime<<1; + if(scale>ONE_FIXED) scale = ONE_FIXED; + scale = ONE_FIXED; + dynPtr->LinImpulse.vx -= MUL_FIXED(scale,dynPtr->LinImpulse.vx); + dynPtr->LinImpulse.vz -= MUL_FIXED(scale,dynPtr->LinImpulse.vz); + } + #else + if (dynPtr->IsInContactWithFloor) + { + int k = NormalFrameTime<<1; + int dotted = DotProduct(&(dynPtr->LinImpulse),&(dynPtr->GravityDirection)); + + VECTORCH linParallel,linPerp; + + linParallel.vx = MUL_FIXED(dotted,dynPtr->GravityDirection.vx); + linParallel.vy = MUL_FIXED(dotted,dynPtr->GravityDirection.vy); + linParallel.vz = MUL_FIXED(dotted,dynPtr->GravityDirection.vz); + + linPerp.vx = dynPtr->LinImpulse.vx - linParallel.vx; + linPerp.vy = dynPtr->LinImpulse.vy - linParallel.vy; + linPerp.vz = dynPtr->LinImpulse.vz - linParallel.vz; + + if (dynPtr->IsInContactWithNearlyFlatFloor) + { + if (Approximate3dMagnitude(&linPerp)<3000) + { + k*=16; + if (k>ONE_FIXED) k = ONE_FIXED; + } + } + + dynPtr->LinImpulse.vx -= MUL_FIXED(k,linPerp.vx); + dynPtr->LinImpulse.vy -= MUL_FIXED(k,linPerp.vy); + dynPtr->LinImpulse.vz -= MUL_FIXED(k,linPerp.vz); + } + #endif + + #if 0 + if( (dynPtr->Position.vx != dynPtr->PrevPosition.vx) + ||(dynPtr->Position.vy != dynPtr->PrevPosition.vy) + ||(dynPtr->Position.vz != dynPtr->PrevPosition.vz)) + #endif + { +// FindObjectsToRelocateAgainst(sbPtr); +// TestForValidMovement(sbPtr); + } + // RelocatedDueToFallout(dynPtr); + UpdateDisplayBlockData(sbPtr); + } + #if TELEPORT_IF_OUTSIDE_ENV + { + extern MODULE *playerPherModule; + DYNAMICSBLOCK *dynPtr = Player->ObStrategyBlock->DynPtr; + MODULE *newModule = (ModuleFromPosition(&(dynPtr->Position), playerPherModule)); + + extern unsigned char KeyboardInput[]; + if (!newModule) + { + /* hmm, player isn't in a module */ + #if 0 + if (playerPherModule) + { + dynPtr->Position.vx = playerPherModule->m_world.vx; + dynPtr->Position.vy = playerPherModule->m_world.vy; + dynPtr->Position.vz = playerPherModule->m_world.vz; + PlayersMaxHeightWhilstNotInContactWithGround=dynPtr->Position.vy; + + dynPtr->PrevPosition = dynPtr->Position; + dynPtr->LinImpulse.vx = 0; + dynPtr->LinImpulse.vy = 0; + dynPtr->LinImpulse.vz = 0; + UpdateDisplayBlockData(Player->ObStrategyBlock); + } + else + #endif + { + if (playerPherModule) + { + VECTORCH newPosition = playerPherModule->m_aimodule->m_world; + VECTORCH *offsetPtr = GetNearestModuleTeleportPoint(playerPherModule, &dynPtr->Position); + if (offsetPtr) + { + newPosition.vx += offsetPtr->vx; + newPosition.vy += offsetPtr->vy; + newPosition.vz += offsetPtr->vz; + } + + dynPtr->Position = newPosition; + dynPtr->PrevPosition = newPosition; + } + PlayersMaxHeightWhilstNotInContactWithGround=dynPtr->Position.vy; + dynPtr->LinImpulse.vx = 0; + dynPtr->LinImpulse.vy = 0; + dynPtr->LinImpulse.vz = 0; + UpdateDisplayBlockData(Player->ObStrategyBlock); + //NewOnScreenMessage("Relocated Player"); + } + + } + } + #endif + /* KJL 18:50:17 10/11/98 - Falling Damage */ + if (AvP.PlayerType==I_Marine) + { + DYNAMICSBLOCK *dynPtr = Player->ObStrategyBlock->DynPtr; + if(dynPtr->IsInContactWithFloor) + { + #if 0 + int damage = (PlayersFallingSpeed-15000)*160; + if (damage>0) + { + CauseDamageToObject(Player->ObStrategyBlock,&FallingDamage,damage,NULL); + + } + //falling damage may be turned off in network games + BOOL fallingDamageDisabled = (!netGameData.fallingDamage && AvP.Network!=I_No_Network); + int damage = ((dynPtr->Position.vy - PlayersMaxHeightWhilstNotInContactWithGround - 4000))*256 + ; + if (damage>0 && !fallingDamageDisabled) + { + CauseDamageToObject(Player->ObStrategyBlock,&FallingDamage,damage,NULL); + } + /* CDF 8/4/99 - end of jump sound... */ + { + int distanceFallen = (dynPtr->Position.vy - PlayersMaxHeightWhilstNotInContactWithGround); + + if ((distanceFallen>500)&&(distanceFallen<4000 || fallingDamageDisabled)) { + /* Make a sound. */ + Sound_Play(SID_MARINE_SMALLLANDING,"h"); + if(AvP.Network!=I_No_Network) netGameData.landingNoise=1; + } + } + #endif + BOOL fallingDamageDisabled = (!netGameData.fallingDamage && AvP.Network!=I_No_Network); + int damage = (PlayersFallingSpeed-15000)*256; + int distanceFallen = (dynPtr->Position.vy - PlayersMaxHeightWhilstNotInContactWithGround); + + if (distanceFallen>5000 && damage>ONE_FIXED && !fallingDamageDisabled) + { + CauseDamageToObject(Player->ObStrategyBlock,&FallingDamage,damage,NULL); + } + else if (distanceFallen>1000) + { + Sound_Play(SID_MARINE_SMALLLANDING,"h"); + if(AvP.Network!=I_No_Network) netGameData.landingNoise=1; + } + + + + PlayersMaxHeightWhilstNotInContactWithGround=dynPtr->Position.vy; + } + else + { + if(dynPtr->LinImpulse.vy < 0) + { + PlayersMaxHeightWhilstNotInContactWithGround = 1000000; + } + else if(PlayersMaxHeightWhilstNotInContactWithGround>dynPtr->Position.vy) + { + PlayersMaxHeightWhilstNotInContactWithGround=dynPtr->Position.vy; + } + } + } else if (AvP.PlayerType==I_Predator) { + DYNAMICSBLOCK *dynPtr = Player->ObStrategyBlock->DynPtr; + + if(dynPtr->IsInContactWithFloor) + { + /* CDF 8/4/99 - end of jump sound... */ + { + int distanceFallen = (dynPtr->Position.vy - PlayersMaxHeightWhilstNotInContactWithGround); + + if (distanceFallen>1000) { + /* Make a sound. */ + Sound_Play(SID_PRED_SMALLLANDING,"h"); + if(AvP.Network!=I_No_Network) netGameData.landingNoise=1; + } + } + PlayersMaxHeightWhilstNotInContactWithGround=dynPtr->Position.vy; + } + else + { + if(dynPtr->LinImpulse.vy < 0) + { + PlayersMaxHeightWhilstNotInContactWithGround = 1000000; + } + else if(PlayersMaxHeightWhilstNotInContactWithGround>dynPtr->Position.vy) + { + PlayersMaxHeightWhilstNotInContactWithGround=dynPtr->Position.vy; + } + } + } + /* Check for object pickup */ + { + int i = NumberOfDynamicObjects; + DYNAMICSBLOCK *dynPtr = Player->ObStrategyBlock->DynPtr; + + while(i--) + { + STRATEGYBLOCK *obstaclePtr = DynamicObjectsList[i]; +// if((obstaclePtr->I_SBtype == I_BehaviourHierarchicalFragment)||(obstaclePtr->DynPtr->IsPickupObject)) + if(obstaclePtr->DynPtr->IsPickupObject) + { + VECTORCH disp; + disp.vx = dynPtr->Position.vx-obstaclePtr->DynPtr->Position.vx; + disp.vy = dynPtr->Position.vy-obstaclePtr->DynPtr->Position.vy; + disp.vz = dynPtr->Position.vz-obstaclePtr->DynPtr->Position.vz; + if (Approximate3dMagnitude(&disp)ObstacleSBPtr = obstaclePtr; + reportPtr->ObstacleNormal.vx = -dynPtr->GravityDirection.vx; + reportPtr->ObstacleNormal.vy = -dynPtr->GravityDirection.vy; + reportPtr->ObstacleNormal.vz = -dynPtr->GravityDirection.vz; + } + } + } + } + } + #if 0 + { + COLLISIONREPORT *reportPtr = Player->ObStrategyBlock->DynPtr->CollisionReportPtr; + + if (ShowDebuggingText.Dynamics) PrintDebuggingText("Player Impulse:%d,%d,%d\n", + Player->ObStrategyBlock->DynPtr->LinImpulse.vx, + Player->ObStrategyBlock->DynPtr->LinImpulse.vy, + Player->ObStrategyBlock->DynPtr->LinImpulse.vz); + + if (ShowDebuggingText.Dynamics) PrintDebuggingText("Player Position:%d,%d,%d\n", + Player->ObStrategyBlock->DynPtr->Position.vx, + Player->ObStrategyBlock->DynPtr->Position.vy, + Player->ObStrategyBlock->DynPtr->Position.vz); + + if (ShowDebuggingText.Dynamics) PrintDebuggingText("InContactWithFloor %d\n",Player->ObStrategyBlock->DynPtr->IsInContactWithFloor); + if (ShowDebuggingText.Dynamics) PrintDebuggingText("Player Gravity Direction:%d,%d,%d\n", + Player->ObStrategyBlock->DynPtr->GravityDirection.vx, + Player->ObStrategyBlock->DynPtr->GravityDirection.vy, + Player->ObStrategyBlock->DynPtr->GravityDirection.vz); + + while (reportPtr) /* while there is a valid report */ + { + if (ShowDebuggingText.Dynamics) PrintDebuggingText("Col Normal %d %d %d\n",reportPtr->ObstacleNormal.vx,reportPtr->ObstacleNormal.vy,reportPtr->ObstacleNormal.vz); + if (ShowDebuggingText.Dynamics) PrintDebuggingText("strategy ptr %p\n",reportPtr->ObstacleSBPtr); + + /* skip to next report */ + reportPtr = reportPtr->NextCollisionReportPtr; + } + PrintDebuggingText("€‚ƒ ©¸ä\n"); + if(!Player->ObStrategyBlock->DynPtr->IsInContactWithFloor) + NewOnScreenMessage("€‚ƒ word ©¸ä word €‚ƒ word ¸ä word\n"); + } + #endif + //NewTrailPoint(Player->ObStrategyBlock->DynPtr); +} + +static void InitialiseDynamicObjectsList(void) +{ + STRATEGYBLOCK *unsortedDynamicObjectsList[MAX_NO_OF_DYNAMICS_BLOCKS]; + signed int valueOnWhichToSort[MAX_NO_OF_DYNAMICS_BLOCKS]; + AccelDueToGravity = MUL_FIXED(GRAVITY_STRENGTH,NormalFrameTime); + + if (UNDERWATER_CHEATMODE) + { + AccelDueToGravity/=2; + } + + /* scan through list of strategy blocks looking for ones + with dynamics blocks and collisions on */ + { + int i = NumActiveStBlocks; + NumberOfDynamicObjects = 0; + while(i) + { + STRATEGYBLOCK *sbPtr = ActiveStBlockList[--i]; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + DISPLAYBLOCK *dispPtr = sbPtr->SBdptr; + + if (dynPtr && dispPtr) + { + /* skip static objects */ + if(dynPtr->IsStatic) + { + UpdateDisplayBlockData(sbPtr); +// CreateNRBBForObject(sbPtr); + } + /* should object simply move? */ + else if (dynPtr->DynamicsType == DYN_TYPE_NO_COLLISIONS) + { + /* Apply gravity */ + ApplyGravity(dynPtr); + + dynPtr->Position.vx += + MUL_FIXED(dynPtr->LinVelocity.vx+dynPtr->LinImpulse.vx, NormalFrameTime); + dynPtr->Position.vy += + MUL_FIXED(dynPtr->LinVelocity.vy+dynPtr->LinImpulse.vy, NormalFrameTime); + dynPtr->Position.vz += + MUL_FIXED(dynPtr->LinVelocity.vz+dynPtr->LinImpulse.vz, NormalFrameTime); + UpdateDisplayBlockData(sbPtr); + } + /* is it just static? */ + else /* have to consider it properly */ + { + /* Apply gravity */ + ApplyGravity(dynPtr); + AddEffectsOfForceGenerators(&dynPtr->Position,&dynPtr->LinImpulse,dynPtr->Mass); + /* create a bb that surrounds the object */ + // CreateExtentCuboidForObject(sbPtr); + switch(dynPtr->DynamicsType) + { + case DYN_TYPE_SPHERE_COLLISIONS: + { + dynPtr->CollisionRadius = 500; + + CreateSphereBBForObject(sbPtr); + break; + } + case DYN_TYPE_NRBB_COLLISIONS: + { + #if 0 + textprint + ( + "%d %d, %d %d, %d %d\n" + ,sbPtr->SBdptr->ObMaxX,sbPtr->SBdptr->ObMinX + ,sbPtr->SBdptr->ObMaxY,sbPtr->SBdptr->ObMinY + ,sbPtr->SBdptr->ObMaxZ,sbPtr->SBdptr->ObMinZ + ); + #endif + CreateNRBBForObject(sbPtr); + break; + } + default: + { + /* oh dear, invalid collision shape */ + GLOBALASSERT(0); + break; + } + } + + if (!dynPtr->IsNetGhost) + { + /* set previous position datum */ + dynPtr->PrevPosition = dynPtr->Position; + //dynPtr->PrevOrientMat = dynPtr->OrientMat; + + /* reset floor contact flag */ + dynPtr->IsInContactWithFloor = 0; + dynPtr->IsInContactWithNearlyFlatFloor = 0; + + /* calculate object's movement vector */ + if (!dynPtr->UseDisplacement) + { + dynPtr->Displacement.vx = 0; + dynPtr->Displacement.vy = 0; + dynPtr->Displacement.vz = 0; + } + + + if (dynPtr->OnlyCollideWithObjects) + { + dynPtr->Displacement.vx += MUL_FIXED(dynPtr->LinVelocity.vx, NormalFrameTime); + dynPtr->Displacement.vy += MUL_FIXED(dynPtr->LinVelocity.vy, NormalFrameTime); + dynPtr->Displacement.vz += MUL_FIXED(dynPtr->LinVelocity.vz, NormalFrameTime); + } + else + { + dynPtr->Displacement.vx += MUL_FIXED(dynPtr->LinVelocity.vx+dynPtr->LinImpulse.vx, NormalFrameTime); + dynPtr->Displacement.vy += MUL_FIXED(dynPtr->LinVelocity.vy+dynPtr->LinImpulse.vy, NormalFrameTime); + dynPtr->Displacement.vz += MUL_FIXED(dynPtr->LinVelocity.vz+dynPtr->LinImpulse.vz, NormalFrameTime); + + /* If moving in direction of gravity, add a little bit to make sure you will make contact + with the ground if your close */ + if (dynPtr->GravityOn) + { + if (dynPtr->UseStandardGravity&&PlanarGravity) /* ie. in direction of +ve Y-axis */ + { + if (dynPtr->Displacement.vy > 0) + dynPtr->Displacement.vy += GRAVITY_DISPLACEMENT; + } + else + { + if (DotProduct(&(dynPtr->Displacement),&(dynPtr->GravityDirection)) > 0) + dynPtr->Displacement.vx += MUL_FIXED(dynPtr->GravityDirection.vx, GRAVITY_DISPLACEMENT); + dynPtr->Displacement.vy += MUL_FIXED(dynPtr->GravityDirection.vy, GRAVITY_DISPLACEMENT); + dynPtr->Displacement.vz += MUL_FIXED(dynPtr->GravityDirection.vz, GRAVITY_DISPLACEMENT); + } + } + + /* KJL 12:00:29 25/11/98 - resolve against last frames normals */ + #if 0 + { + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + while (reportPtr) + { + int magOfPerpVel; +// if (! ((reportPtr->ObstacleNormal.vx < 100 && reportPtr->ObstacleNormal.vx > -100) +// &&(reportPtr->ObstacleNormal.vz < 100 && reportPtr->ObstacleNormal.vz > -100) )) + if(reportPtr->ObstaclePoint.vx == 0x7fffffff && + reportPtr->ObstaclePoint.vy == 0x7fffffff && + reportPtr->ObstaclePoint.vz == 0x7fffffff) + { + +// reportPtr->ObstacleNormal.vy = 0; +// Normalise(&reportPtr->ObstacleNormal); + magOfPerpVel = MUL_FIXED(66000,DotProduct(&reportPtr->ObstacleNormal,&(dynPtr->Displacement))); + + // SubScaledVectorFromVector(reportPtr->ObstacleNormal, magOfPerpVel, (dynPtr->Displacement)); + dynPtr->Displacement.vx -= MUL_FIXED(reportPtr->ObstacleNormal.vx,magOfPerpVel); + dynPtr->Displacement.vy -= MUL_FIXED(reportPtr->ObstacleNormal.vy,magOfPerpVel); + dynPtr->Displacement.vz -= MUL_FIXED(reportPtr->ObstacleNormal.vz,magOfPerpVel); + } + reportPtr = reportPtr->NextCollisionReportPtr; + } + } + #endif + + } + + dynPtr->DistanceLeftToMove = Magnitude(&dynPtr->Displacement); + + if (dynPtr->DistanceLeftToMove>ONE_FIXED/8) + { + dynPtr->DistanceLeftToMove = ONE_FIXED/8; + Normalise(&dynPtr->Displacement); + dynPtr->Displacement.vx /= 8; + dynPtr->Displacement.vy /= 8; + dynPtr->Displacement.vz /= 8; + } + } + + if(dynPtr->OnlyCollideWithObjects || dynPtr->IsNetGhost) + { + valueOnWhichToSort[NumberOfDynamicObjects] = 0x7fffffff; + } + else + { + valueOnWhichToSort[NumberOfDynamicObjects] = dynPtr->DistanceLeftToMove; + } + + unsortedDynamicObjectsList[NumberOfDynamicObjects] = sbPtr; + NumberOfDynamicObjects++; + + if (dispPtr == Player) + { + PlayersFallingSpeed = (dynPtr->LinVelocity.vy+dynPtr->LinImpulse.vy); + } + } + + /* wipe previous collision records */ + dynPtr->CollisionReportPtr =0; + } + } + } + /* possibly a good idea to sort objects so that the fastest is moved first */ + { + /* extremely simple (and inefficient) selection sort */ + int outer = NumberOfDynamicObjects; + while(outer > 0) + { + int inner = NumberOfDynamicObjects; + int highestValueFound = -1; + int indexOfFastestObject =0; + while(inner) + { + if (valueOnWhichToSort[--inner]>highestValueFound) + { + highestValueFound = valueOnWhichToSort[inner]; + indexOfFastestObject = inner; + } + } + + DynamicObjectsList[--outer] = unsortedDynamicObjectsList[indexOfFastestObject]; + valueOnWhichToSort[indexOfFastestObject] = -1; + } + } +} +static void UpdateDisplayBlockData(STRATEGYBLOCK *sbPtr) +{ + /* If the object associated with this strategyblock has a valid displayblock + then update the data which has been changed by the objects movement. */ + DISPLAYBLOCK *dispPtr = sbPtr->SBdptr; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + if (dispPtr) + { + dispPtr->ObWorld = dynPtr->Position; + + if (dynPtr->CollisionRadius) + { + int radius = dynPtr->CollisionRadius; + dispPtr->ObWorld.vy -= radius; + dispPtr->ObWorld.vx += MUL_FIXED(dynPtr->OrientMat.mat21,radius); + dispPtr->ObWorld.vy += MUL_FIXED(dynPtr->OrientMat.mat22,radius); + dispPtr->ObWorld.vz += MUL_FIXED(dynPtr->OrientMat.mat23,radius); + } + dispPtr->ObMat = dynPtr->OrientMat; + dispPtr->ObEuler = dynPtr->OrientEuler; + + if (TICKERTAPE_CHEATMODE) + { + if (sbPtr) + { + if (sbPtr->I_SBtype == I_BehaviourAlien) + PlayerPheromoneTrail(dynPtr); + } + } + } + dynPtr->PrevOrientMat = dynPtr->OrientMat; +} + + + + + + + + +/* gravity code */ +static void ApplyGravity(DYNAMICSBLOCK *dynPtr) +{ + if (dynPtr->GravityOn) + { + if (dynPtr->UseStandardGravity) + { + if (PlanarGravity) + { + /* ie. in direction of +ve Y-axis */ + dynPtr->LinImpulse.vy += AccelDueToGravity; + + /* KJL 11:47:04 03/26/97 - aliens need to be aligned */ + if (dynPtr->ToppleForce == TOPPLE_FORCE_ALIEN) + { + AlignObjectToStandardGravityDirection(dynPtr); + } + } + /* else if (RadialGravityModel) */ + else + { + extern int CloakingPhase; + dynPtr->GravityDirection.vx = GetSin((CloakingPhase/16)&4095); + dynPtr->GravityDirection.vy = GetCos((CloakingPhase/16)&4095); + dynPtr->GravityDirection.vz = GetCos((CloakingPhase/19+400)&4095); + Normalise(&(dynPtr->GravityDirection)); + AddScaledVectorToVector(dynPtr->GravityDirection,(AccelDueToGravity),dynPtr->LinImpulse); + AlignObjectToGravityDirection(dynPtr); + } + } + else + { + /* KJL 11:47:04 03/26/97 - aliens need to be aligned */ + if (dynPtr->ToppleForce == TOPPLE_FORCE_ALIEN) + { + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + VECTORCH averageNormal= {0,0,0}; + int normalsFound=0; + + if(dynPtr->TimeNotInContactWithFloor!=-1) + { + while (reportPtr) /* while there is a valid report */ + { + // if (reportPtr->ObstacleSBPtr == 0) + { + averageNormal.vx -= reportPtr->ObstacleNormal.vx; + averageNormal.vy -= reportPtr->ObstacleNormal.vy; + averageNormal.vz -= reportPtr->ObstacleNormal.vz; + normalsFound++; + } + /* skip to next report */ + reportPtr = reportPtr->NextCollisionReportPtr; + } + } + if (normalsFound) + { + //averageNormal.vx /= normalsFound; + //averageNormal.vy /= normalsFound; + //averageNormal.vz /= normalsFound; + if (averageNormal.vx==0 && averageNormal.vy==0 && averageNormal.vz==0) + { + // down boy down + averageNormal.vy = ONE_FIXED; + } + else + { + Normalise(&averageNormal); + } + dynPtr->GravityDirection = averageNormal; + dynPtr->TimeNotInContactWithFloor = TIME_BEFORE_GRAVITY_KICKS_IN; + } + else + { + if (dynPtr->TimeNotInContactWithFloor<=0) + { + if (PlanarGravity) + { + dynPtr->GravityDirection.vx = 0; + dynPtr->GravityDirection.vy = 65536; + dynPtr->GravityDirection.vz = 0; + } + /* else if (RadialGravityModel) */ + else + { + dynPtr->GravityDirection.vx = -dynPtr->Position.vx; + dynPtr->GravityDirection.vy = -dynPtr->Position.vy; + dynPtr->GravityDirection.vz = -dynPtr->Position.vz; + Normalise(&(dynPtr->GravityDirection)); + } + } + else if (dynPtr->TimeNotInContactWithFloor == TIME_BEFORE_GRAVITY_KICKS_IN) + { + if (dynPtr->LinVelocity.vx==0 && dynPtr->LinVelocity.vy==0 && dynPtr->LinVelocity.vz==0) + { +// dynPtr->GravityDirection.vx = 0; +// dynPtr->GravityDirection.vy = 65536; +// dynPtr->GravityDirection.vz = 0; + } + else + { + /* code to enable going round 270 degree corners */ + #if 1 + Normalise(&dynPtr->LinVelocity); + dynPtr->GravityDirection.vx -= (dynPtr->LinVelocity.vx*3)/4; + dynPtr->GravityDirection.vy -= (dynPtr->LinVelocity.vy*3)/4; + dynPtr->GravityDirection.vz -= (dynPtr->LinVelocity.vz*3)/4; + Normalise(&dynPtr->GravityDirection); + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + #endif + } + } + dynPtr->TimeNotInContactWithFloor-=NormalFrameTime; + if (dynPtr->TimeNotInContactWithFloor<0) + { + dynPtr->TimeNotInContactWithFloor = 0; + } + + } + AlignObjectToGravityDirection(dynPtr); + } + AddScaledVectorToVector(dynPtr->GravityDirection,AccelDueToGravity,dynPtr->LinImpulse); + } + } +} +static void AlignObjectToGravityDirection(DYNAMICSBLOCK *dynPtr) +{ + VECTORCH XVector; + VECTORCH YVector; + VECTORCH ZVector; + int staticAxis; + + { + int dotx = Dot((VECTORCH*)&dynPtr->OrientMat.mat11, &dynPtr->GravityDirection); + int doty = Dot((VECTORCH*)&dynPtr->OrientMat.mat21, &dynPtr->GravityDirection); + int dotz = Dot((VECTORCH*)&dynPtr->OrientMat.mat31, &dynPtr->GravityDirection); + + /* Get their absolute values */ + if(dotx < 0) dotx = -dotx; + if(doty < 0) doty = -doty; + if(dotz < 0) dotz = -dotz; + + if (dotxOrientMat.mat31); + YVector = *((VECTORCH*)&dynPtr->OrientMat.mat21); + VectorHomingForSurfaceAlign(&YVector, &dynPtr->GravityDirection,((VECTORCH*)&dynPtr->OrientMat.mat11)); + CrossProduct(&YVector, &ZVector, &XVector); + } + else if (staticAxis == ix) + { + XVector = *((VECTORCH*)&dynPtr->OrientMat.mat11); + YVector = *((VECTORCH*)&dynPtr->OrientMat.mat21); + VectorHomingForSurfaceAlign(&YVector, &dynPtr->GravityDirection,((VECTORCH*)&dynPtr->OrientMat.mat31)); + CrossProduct(&XVector, &YVector, &ZVector); + } + else if (staticAxis == iy) + { + XVector = *((VECTORCH*)&dynPtr->OrientMat.mat11); + YVector = *((VECTORCH*)&dynPtr->OrientMat.mat21); + VectorHomingForSurfaceAlign(&YVector, &dynPtr->GravityDirection,((VECTORCH*)&dynPtr->OrientMat.mat31)); + CrossProduct(&XVector, &YVector, &ZVector); + CrossProduct(&YVector, &ZVector, &XVector); + } + Normalise(&XVector); + Normalise(&YVector); + Normalise(&ZVector); + + dynPtr->OrientMat.mat11 = XVector.vx; + dynPtr->OrientMat.mat12 = XVector.vy; + dynPtr->OrientMat.mat13 = XVector.vz; + + dynPtr->OrientMat.mat21 = YVector.vx; + dynPtr->OrientMat.mat22 = YVector.vy; + dynPtr->OrientMat.mat23 = YVector.vz; + + dynPtr->OrientMat.mat31 = ZVector.vx; + dynPtr->OrientMat.mat32 = ZVector.vy; + dynPtr->OrientMat.mat33 = ZVector.vz; + + MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); +} +static void AlignObjectToStandardGravityDirection(DYNAMICSBLOCK *dynPtr) +{ + VECTORCH gravityDirection = {0,65536,0}; + VECTORCH XVector,YVector,ZVector; + int staticAxis; + + dynPtr->GravityDirection = gravityDirection; + + { + int dotx = dynPtr->OrientMat.mat12; + int doty = dynPtr->OrientMat.mat22; + int dotz = dynPtr->OrientMat.mat32; + + /* Get their absolute values */ + if(dotx < 0) dotx = -dotx; + if(doty < 0) doty = -doty; + if(dotz < 0) dotz = -dotz; + + if (dotxOrientMat.mat31); + YVector = *((VECTORCH*)&dynPtr->OrientMat.mat21); + VectorHomingForSurfaceAlign(&YVector, &gravityDirection,((VECTORCH*)&dynPtr->OrientMat.mat11)); + CrossProduct(&YVector, &ZVector, &XVector); + } + else if (staticAxis == ix) + { + XVector = *((VECTORCH*)&dynPtr->OrientMat.mat11); + YVector = *((VECTORCH*)&dynPtr->OrientMat.mat21); + VectorHomingForSurfaceAlign(&YVector, &gravityDirection,((VECTORCH*)&dynPtr->OrientMat.mat31)); + CrossProduct(&XVector, &YVector, &ZVector); + } + else if (staticAxis == iy) + { + XVector = *((VECTORCH*)&dynPtr->OrientMat.mat11); + YVector = *((VECTORCH*)&dynPtr->OrientMat.mat21); + VectorHomingForSurfaceAlign(&YVector, &gravityDirection,((VECTORCH*)&dynPtr->OrientMat.mat31)); + CrossProduct(&XVector, &YVector, &ZVector); + CrossProduct(&YVector, &ZVector, &XVector); + } + Normalise(&XVector); + Normalise(&YVector); + Normalise(&ZVector); + + dynPtr->OrientMat.mat11 = XVector.vx; + dynPtr->OrientMat.mat12 = XVector.vy; + dynPtr->OrientMat.mat13 = XVector.vz; + + dynPtr->OrientMat.mat21 = YVector.vx; + dynPtr->OrientMat.mat22 = YVector.vy; + dynPtr->OrientMat.mat23 = YVector.vz; + + dynPtr->OrientMat.mat31 = ZVector.vx; + dynPtr->OrientMat.mat32 = ZVector.vy; + dynPtr->OrientMat.mat33 = ZVector.vz; + + MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); +} +static void VectorHomingForSurfaceAlign(VECTORCH *currentPtr, VECTORCH *targetPtr, VECTORCH *perpendicularPtr) +{ + int cos = Dot(currentPtr, targetPtr); + + if (cos<=-65000) + { + int a1 = NormalFrameTime*4; + if (a1>ONE_FIXED) a1=ONE_FIXED; + else if (a1<1024) a1=1024; + + currentPtr->vx = currentPtr->vx+MUL_FIXED(perpendicularPtr->vx-currentPtr->vx, a1); + currentPtr->vy = currentPtr->vy+MUL_FIXED(perpendicularPtr->vy-currentPtr->vy, a1); + currentPtr->vz = currentPtr->vz+MUL_FIXED(perpendicularPtr->vz-currentPtr->vz, a1); + Normalise(currentPtr); + return; + } + else if (cos>=65500) /* if they're practically parallel just snap currentPtr to targetPtr */ + { + currentPtr->vx = targetPtr->vx; + currentPtr->vy = targetPtr->vy; + currentPtr->vz = targetPtr->vz; + return; + } + + if (cos<32768) cos = 32768; + + { + int a1 = MUL_FIXED(cos*8,NormalFrameTime); +// int a1 = NormalFrameTime*4; + if (a1>ONE_FIXED) a1=ONE_FIXED; + else if (a1<1024) a1=1024; + + currentPtr->vx = currentPtr->vx+MUL_FIXED(targetPtr->vx-currentPtr->vx, a1); + currentPtr->vy = currentPtr->vy+MUL_FIXED(targetPtr->vy-currentPtr->vy, a1); + currentPtr->vz = currentPtr->vz+MUL_FIXED(targetPtr->vz-currentPtr->vz, a1); + Normalise(currentPtr); + } + return; +} + + + + + + +extern void DynamicallyRotateObject(DYNAMICSBLOCK *dynPtr) +{ + extern int NormalFrameTime; + + MATRIXCH mat; + EULER euler; + euler.EulerX = MUL_FIXED(NormalFrameTime,dynPtr->AngVelocity.EulerX); + euler.EulerX &= wrap360; + + euler.EulerY = MUL_FIXED(NormalFrameTime,dynPtr->AngVelocity.EulerY); + euler.EulerY &= wrap360; + + euler.EulerZ = MUL_FIXED(NormalFrameTime,dynPtr->AngVelocity.EulerZ); + euler.EulerZ &= wrap360; + + CreateEulerMatrix(&euler, &mat); + TransposeMatrixCH(&mat); + + MatrixMultiply(&dynPtr->OrientMat,&mat,&dynPtr->OrientMat); + MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); +} + +/* Move an object. At this stage, we have a list of the polygons in the +environment with which the object the may collide. */ +static int MoveObject(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + int lowestBoundary = 0; + int highestBoundary = ONE_FIXED; + int testValue = ONE_FIXED; + int hitSomething = 0; + + DirectionOfTravel = dynPtr->Displacement; + Normalise(&DirectionOfTravel); + + { + int maxDistanceAllowed=dynPtr->ObjectVertices[0].vz-dynPtr->ObjectVertices[7].vz; + if (maxDistanceAllowed>dynPtr->ObjectVertices[0].vx-dynPtr->ObjectVertices[7].vx) + maxDistanceAllowed=dynPtr->ObjectVertices[0].vx-dynPtr->ObjectVertices[7].vx; + if (maxDistanceAllowed>dynPtr->ObjectVertices[0].vy-dynPtr->ObjectVertices[7].vy) + maxDistanceAllowed=dynPtr->ObjectVertices[0].vy-dynPtr->ObjectVertices[7].vy; + + if (maxDistanceAllowed<10) + { + LOCALASSERT("Object's bounding box is too small. Suspicious."==0); + } + + if (dynPtr->DistanceLeftToMove>maxDistanceAllowed) + { + testValue = DIV_FIXED(maxDistanceAllowed,dynPtr->DistanceLeftToMove); + highestBoundary = testValue; + } + } + + if (InterferenceAt(testValue,dynPtr)) + { + testValue /= 2; + do + { + if (InterferenceAt(testValue,dynPtr)) + { + highestBoundary = testValue; + testValue = (lowestBoundary+highestBoundary)/2; + } + else + { + lowestBoundary = testValue; + testValue = (lowestBoundary+highestBoundary)/2; + } + if (MUL_FIXED(highestBoundary-lowestBoundary,dynPtr->DistanceLeftToMove)<=16) + { + InterferenceAt(highestBoundary,dynPtr); + break; + } + } + while(1); + testValue = lowestBoundary; + hitSomething = 1; + } + + { + VECTORCH displacement; + displacement.vx = MUL_FIXED(dynPtr->Displacement.vx,testValue); + displacement.vy = MUL_FIXED(dynPtr->Displacement.vy,testValue); + displacement.vz = MUL_FIXED(dynPtr->Displacement.vz,testValue); + + AddVectorToVector(displacement, dynPtr->Position); + SubVectorFromVector(displacement, dynPtr->Displacement); + { + VECTORCH *vertexPtr = dynPtr->ObjectVertices; + int i=8; + do + { + vertexPtr->vx += displacement.vx; + vertexPtr->vy += displacement.vy; + vertexPtr->vz += displacement.vz; + vertexPtr++; + } + while(--i); + } + + } + + if (hitSomething) + { + int wentUpStep = 0; + VECTORCH obstacleNormal = {0,0,0}; + int n = NumberOfInterferencePolygons; + VECTORCH objectCentre = {0,0,0}; + int leastSoFar = 1000000; + struct ColPolyTag *polygonPtr=0; + + { + if (DirectionOfTravel.vx>0) + { + objectCentre.vx = dynPtr->ObjectVertices[0].vx-COLLISION_GRANULARITY; + } + else if (DirectionOfTravel.vx<0) + { + objectCentre.vx = dynPtr->ObjectVertices[7].vx+COLLISION_GRANULARITY; + } + else + { + objectCentre.vx = (dynPtr->ObjectVertices[0].vx+dynPtr->ObjectVertices[7].vx)/2; + } + #if 1 + if (DirectionOfTravel.vy>0) + { + objectCentre.vy = dynPtr->ObjectVertices[0].vy-COLLISION_GRANULARITY; + } + else if (DirectionOfTravel.vy<0) + { + objectCentre.vy = dynPtr->ObjectVertices[7].vy+COLLISION_GRANULARITY; + } + else + #endif + { + objectCentre.vy = (dynPtr->ObjectVertices[0].vy+dynPtr->ObjectVertices[7].vy)/2; + } + if (DirectionOfTravel.vz>0) + { + objectCentre.vz = dynPtr->ObjectVertices[0].vz-COLLISION_GRANULARITY; + } + else if (DirectionOfTravel.vz<0) + { + objectCentre.vz = dynPtr->ObjectVertices[7].vz+COLLISION_GRANULARITY; + } + else + { + objectCentre.vz = (dynPtr->ObjectVertices[0].vz+dynPtr->ObjectVertices[7].vz)/2; + } + + } + #if 0 + PrintDebuggingText("Test point %d,%d,%d\n",objectCentre.vx,objectCentre.vy,objectCentre.vz); + #endif + while(n--) + { + #if 1 + VECTORCH r; + int d; + + r.vx = objectCentre.vx - InterferencePolygons[n].PolyPoint[0].vx; + r.vy = objectCentre.vy - InterferencePolygons[n].PolyPoint[0].vy; + r.vz = objectCentre.vz - InterferencePolygons[n].PolyPoint[0].vz; + d = DotProduct(&r,&InterferencePolygons[n].PolyNormal); + + if (d<0) d+=1000000; + { + if (dDistanceLeftToMove = 0; + LOCALASSERT(0); + return 0; + } + else + { + #if 0 + PrintDebuggingText("POLY NORMAL IS %d %d %d\n",(polygonPtr->PolyNormal).vx,(polygonPtr->PolyNormal).vy,(polygonPtr->PolyNormal).vz); + PrintDebuggingText("POLY NO OF VERTICES %d\n",(polygonPtr->NumberOfVertices)); + PrintDebuggingText("POLY POINT[0] IS %d %d %d\n",(polygonPtr->PolyPoint[0]).vx,(polygonPtr->PolyPoint[0]).vy,(polygonPtr->PolyPoint[0]).vz); + PrintDebuggingText("POLY POINT[1] IS %d %d %d\n",(polygonPtr->PolyPoint[1]).vx,(polygonPtr->PolyPoint[1]).vy,(polygonPtr->PolyPoint[1]).vz); + PrintDebuggingText("POLY POINT[2] IS %d %d %d\n",(polygonPtr->PolyPoint[2]).vx,(polygonPtr->PolyPoint[2]).vy,(polygonPtr->PolyPoint[2]).vz); + #endif + } + /* test for a 'step' in front of object */ + if ( (dynPtr->CanClimbStairs) + /* check to see that polygon is vertical */ + &&(polygonPtr->PolyNormal.vy>-250) + &&(polygonPtr->PolyNormal.vy<250) ) + { + int heightOfStep,topOfStep; + { + int vertexNum=polygonPtr->NumberOfVertices-1; + + topOfStep = polygonPtr->PolyPoint[0].vy; + do + { + int y = polygonPtr->PolyPoint[vertexNum].vy; + + if (y < topOfStep) topOfStep = y; + } + while(--vertexNum); + } + + heightOfStep = dynPtr->ObjectVertices[0].vy - topOfStep; /* y-axis is +ve downwards, remember */ + //textprint("found step %d\n",heightOfStep); + if (heightOfStep>0 && heightOfStep < MAXIMUM_STEP_HEIGHT) /* we've hit a 'step' - move player upwards */ + { + DistanceToStepUp=heightOfStep+COLLISION_GRANULARITY; + wentUpStep = SteppingUpIsValid(sbPtr); + #if 0 + if (wentUpStep) + { + PrintDebuggingText("Found a valid step.\n"); + } + else + { + PrintDebuggingText("Found a step but couldn't go up it.\n"); + } + #endif + + } + } + + if (!wentUpStep) + { + STRATEGYBLOCK *obstacleSBPtr; + + if (polygonPtr->ParentObject) + if (polygonPtr->ParentObject->ObStrategyBlock) + { + obstacleSBPtr = polygonPtr->ParentObject->ObStrategyBlock; + } + else + { + obstacleSBPtr = 0; + } + + DistanceToStepUp = 0; + + /* resolve player's movement vector against the collision plane */ + /* awkward problem here to do with non-exact normals */ + { + // int magOfPerpVel = DotProduct(&obstacleNormal,&(dynPtr->Displacement)); + int magOfPerpVel = MUL_FIXED(66000,DotProduct(&obstacleNormal,&(dynPtr->Displacement))); + SubScaledVectorFromVector(obstacleNormal, magOfPerpVel, (dynPtr->Displacement)); + } + + /* collision - elasticity */ + { + int magOfPerpImp = MUL_FIXED + ( + DotProduct(&obstacleNormal,&dynPtr->LinImpulse), + 65536 + dynPtr->Elasticity + ); + SubScaledVectorFromVector(obstacleNormal, magOfPerpImp, dynPtr->LinImpulse); + } + /* momentum test */ + /* OnlyCollideWithObjects flag indicates a platform lift etc. which should not be involved with momentum transfer */ + if (obstacleSBPtr && (obstacleSBPtr->DynPtr)) + if (!(dynPtr->OnlyCollideWithObjects + ||obstacleSBPtr->DynPtr->OnlyCollideWithObjects + ||obstacleSBPtr->DynPtr->IsStatic + ||dynPtr->IsInanimate + ||obstacleSBPtr->DynPtr->IsInanimate)) + { + DYNAMICSBLOCK *obsDynPtr = obstacleSBPtr->DynPtr; + int totalMass = (obsDynPtr->Mass + dynPtr->Mass)*4; + int diffMass = (dynPtr->Mass-obsDynPtr->Mass)/2; + + obsDynPtr->LinImpulse.vx += + WideMulNarrowDiv + ( + dynPtr->LinImpulse.vx + dynPtr->LinVelocity.vx, + dynPtr->Mass, + totalMass + ); + obsDynPtr->LinImpulse.vy += + WideMulNarrowDiv + ( + dynPtr->LinImpulse.vy + dynPtr->LinVelocity.vy, + dynPtr->Mass, + totalMass + ); + obsDynPtr->LinImpulse.vz += + WideMulNarrowDiv + ( + dynPtr->LinImpulse.vz + dynPtr->LinVelocity.vz, + dynPtr->Mass, + totalMass + ); + + dynPtr->LinImpulse.vx += + WideMulNarrowDiv + ( + dynPtr->LinImpulse.vx + dynPtr->LinVelocity.vx, + diffMass, + totalMass + ); + dynPtr->LinImpulse.vy += + WideMulNarrowDiv + ( + dynPtr->LinImpulse.vy + dynPtr->LinVelocity.vy, + diffMass, + totalMass + ); + dynPtr->LinImpulse.vz += + WideMulNarrowDiv + ( + dynPtr->LinImpulse.vz + dynPtr->LinVelocity.vz, + diffMass, + totalMass + ); + + } + /* see if object has hit the 'floor' */ + if (dynPtr->GravityOn) + { + if (dynPtr->UseStandardGravity&&PlanarGravity) + { + if (obstacleNormal.vy < -FLOOR_THRESHOLD) + { + dynPtr->IsInContactWithFloor = 1; + if (obstacleNormal.vy < -NEARLYFLATFLOOR_THRESHOLD) dynPtr->IsInContactWithNearlyFlatFloor = 1; + } + } + else + { + int angle = DotProduct(&obstacleNormal,&dynPtr->GravityDirection); + if (angle < -FLOOR_THRESHOLD) + { + /* we've hit something that's against the direction of gravity */ + dynPtr->IsInContactWithFloor = 1; + if (angle < -NEARLYFLATFLOOR_THRESHOLD) dynPtr->IsInContactWithNearlyFlatFloor = 1; + } + } + } + + /* create a report about the collision */ + { + { + COLLISIONREPORT *reportPtr = AllocateCollisionReport(dynPtr); + if (reportPtr) + { + reportPtr->ObstacleSBPtr = obstacleSBPtr; + reportPtr->ObstacleNormal = obstacleNormal; + reportPtr->ObstaclePoint = dynPtr->Position; + } + } + if (obstacleSBPtr&&obstacleSBPtr->DynPtr) + { + COLLISIONREPORT *reportPtr = AllocateCollisionReport(obstacleSBPtr->DynPtr); + if (reportPtr) + { + reportPtr->ObstacleSBPtr = sbPtr; + reportPtr->ObstacleNormal.vx = -obstacleNormal.vx; + reportPtr->ObstacleNormal.vy = -obstacleNormal.vy; + reportPtr->ObstacleNormal.vz = -obstacleNormal.vz; + reportPtr->ObstaclePoint = dynPtr->Position; + } + } + } + } + dynPtr->DistanceLeftToMove = Magnitude(&dynPtr->Displacement); + if (dynPtr->DistanceLeftToMove<=16) + { + dynPtr->DistanceLeftToMove = 0; + } + return 1; + } + else + { + dynPtr->DistanceLeftToMove = Magnitude(&dynPtr->Displacement); + if (dynPtr->DistanceLeftToMove<=16) + { + dynPtr->DistanceLeftToMove = 0; + } + return 0; + } + +} + +static int InterferenceAt(int lambda, DYNAMICSBLOCK *dynPtr) +{ + VECTORCH objectVertices[8]; + int polysLeft; + struct ColPolyTag *polyPtr; + + { + int vertexNum=8; + + VECTORCH disp; + disp.vx = MUL_FIXED(dynPtr->Displacement.vx,lambda); + disp.vy = MUL_FIXED(dynPtr->Displacement.vy,lambda); + disp.vz = MUL_FIXED(dynPtr->Displacement.vz,lambda); + + do + { + vertexNum--; + objectVertices[vertexNum] = dynPtr->ObjectVertices[vertexNum]; + objectVertices[vertexNum].vx += disp.vx; + objectVertices[vertexNum].vy += disp.vy; + objectVertices[vertexNum].vz += disp.vz; + } + while(vertexNum); + } + + polysLeft = NumberOfCollisionPolys; + polyPtr = CollisionPolysArray; + + NumberOfInterferencePolygons = 0; + + while(polysLeft) + { + { + if(DotProduct(&DirectionOfTravel,&polyPtr->PolyNormal)<0) + if (DoesPolygonIntersectNRBB(polyPtr,objectVertices)) + { + InterferencePolygons[NumberOfInterferencePolygons++] = *polyPtr; + if (NumberOfInterferencePolygons==MAX_NUMBER_OF_INTERFERENCE_POLYGONS) break; + } + } + polyPtr++; + polysLeft--; + } + return NumberOfInterferencePolygons; +} + + + + + + +static void MovePlatformLift(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + int polysLeft; + struct ColPolyTag *nearPolysPtr; + int distanceToMove; + + VECTORCH obstacleNormal; + STRATEGYBLOCK *obstacleSBPtr = 0; + + DirectionOfTravel = dynPtr->Displacement; + Normalise(&DirectionOfTravel); + + /* ugh */ + distanceToMove = dynPtr->DistanceLeftToMove; + + /* make list of platform's polygons */ + { + VECTORCH zero = {0,0,0}; + MakeDynamicBoundingBoxForObject(sbPtr, &(dynPtr->Position)); + TestShapeWithDynamicBoundingBox(sbPtr->SBdptr,dynPtr); + MakeDynamicBoundingBoxForObject(sbPtr, &zero); + } + +// textprint("polys on lift %d\n",NumberOfCollisionPolys); + DirectionOfTravel.vx = -DirectionOfTravel.vx; + DirectionOfTravel.vy = -DirectionOfTravel.vy; + DirectionOfTravel.vz = -DirectionOfTravel.vz; + { + int i = NumberOfDynamicObjects; + while(i--) + { + + STRATEGYBLOCK *obstaclePtr = DynamicObjectsList[i]; + + /* check whether collision is even possible */ + { + if (sbPtr==obstaclePtr) + continue; + { + VECTORCH *objectVerticesPtr = obstaclePtr->DynPtr->ObjectVertices; + if (!( ( (DBBMaxX >= objectVerticesPtr[7].vx) && (DBBMinX <= objectVerticesPtr[0].vx) ) + &&( (DBBMaxY >= objectVerticesPtr[7].vy) && (DBBMinY <= objectVerticesPtr[0].vy) ) + &&( (DBBMaxZ >= objectVerticesPtr[7].vz) && (DBBMinZ <= objectVerticesPtr[0].vz) ) )) + continue; + } + } + + //textprint("found an object\n"); + + polysLeft = NumberOfCollisionPolys; + nearPolysPtr = CollisionPolysArray; + + distanceToMove = dynPtr->DistanceLeftToMove; + + /* check against the landscape */ + while(polysLeft) + { + signed int distanceToObstacle; + + distanceToObstacle = DistanceMovedBeforeObjectHitsPolygon(obstaclePtr->DynPtr,nearPolysPtr,distanceToMove); + + if (distanceToObstacle>=0) + { + + distanceToMove = distanceToObstacle; + obstacleNormal = nearPolysPtr->PolyNormal; + obstacleSBPtr = obstaclePtr; + } + nearPolysPtr++; + polysLeft--; + } + + if (distanceToMove!=dynPtr->DistanceLeftToMove) + { + if (dynPtr->Displacement.vy<0) + { + VECTORCH displacement; +// displacement.vx = -MUL_FIXED(DirectionOfTravel.vx, dynPtr->DistanceLeftToMove-distanceToMove+COLLISION_GRANULARITY); + displacement.vx = displacement.vz = 0; + displacement.vy = -(dynPtr->DistanceLeftToMove-distanceToMove+COLLISION_GRANULARITY); +// displacement.vz = -MUL_FIXED(DirectionOfTravel.vz, dynPtr->DistanceLeftToMove-distanceToMove+COLLISION_GRANULARITY); + AddVectorToVector(displacement, obstaclePtr->DynPtr->Position); + obstaclePtr->DynPtr->PrevPosition = obstaclePtr->DynPtr->Position; + { + VECTORCH *vertexPtr = obstaclePtr->DynPtr->ObjectVertices; + int i=8; + do + { + vertexPtr->vy += displacement.vy; + vertexPtr++; + } + while(--i); + } + if (obstaclePtr->SBdptr == Player) + { + /* look for polygons inside this volume */ + FindLandscapePolygonsInObjectsVicinity(obstaclePtr); + FindObjectsToRelocateAgainst(obstaclePtr); + + { + int polysLeft; + struct ColPolyTag *polyPtr; + + polysLeft = NumberOfCollisionPolys; + polyPtr = CollisionPolysArray; + + while(polysLeft) + { + if(DoesPolygonIntersectNRBB(polyPtr,obstaclePtr->DynPtr->ObjectVertices)) + { + int greatestDistance; + + { + VECTORCH vertex = obstaclePtr->DynPtr->ObjectVertices[WhichNRBBVertex(obstaclePtr->DynPtr,&(polyPtr->PolyNormal))]; + vertex.vx -= polyPtr->PolyPoint[0].vx; + vertex.vy -= polyPtr->PolyPoint[0].vy; + vertex.vz -= polyPtr->PolyPoint[0].vz; + greatestDistance = -DotProduct(&vertex,&(polyPtr->PolyNormal)); + } + + if (greatestDistance>0) + { + /* sorry, no room! */ + SubVectorFromVector(displacement, obstaclePtr->DynPtr->Position); + obstaclePtr->DynPtr->PrevPosition = obstaclePtr->DynPtr->Position; + { + VECTORCH *vertexPtr = obstaclePtr->DynPtr->ObjectVertices; + int i=8; + do + { + vertexPtr->vy -= displacement.vy; + vertexPtr++; + } + while(--i); + } + + return; + } + } + polyPtr++; + polysLeft--; + } + + } + } + if (obstaclePtr->DynPtr->Displacement.vy>0) + { + obstaclePtr->DynPtr->Displacement.vy=0; + obstaclePtr->DynPtr->DistanceLeftToMove = Magnitude(&obstaclePtr->DynPtr->Displacement); + } + if (obstaclePtr->DynPtr->LinImpulse.vy>0) + { + obstaclePtr->DynPtr->LinImpulse.vy=0; + } + + } + { + COLLISIONREPORT *reportPtr = AllocateCollisionReport(dynPtr); + + if (reportPtr) + { + reportPtr->ObstacleSBPtr = obstacleSBPtr; + reportPtr->ObstacleNormal.vx = -obstacleNormal.vx; + reportPtr->ObstacleNormal.vy = -obstacleNormal.vy; + reportPtr->ObstacleNormal.vz = -obstacleNormal.vz; + } + } + if (obstacleSBPtr) //&& !(obstacleSBPtr->DynPtr->StopOnCollision)) + /* give obstacle a report too */ + { + COLLISIONREPORT *reportPtr = AllocateCollisionReport(obstacleSBPtr->DynPtr); + + if (reportPtr) + { + reportPtr->ObstacleSBPtr = sbPtr; + reportPtr->ObstacleNormal.vx = obstacleNormal.vx; + reportPtr->ObstacleNormal.vy = obstacleNormal.vy; + reportPtr->ObstacleNormal.vz = obstacleNormal.vz; + } + /* see if object has hit the 'floor' */ + if (obstacleSBPtr->DynPtr->GravityOn) + { + if (obstacleSBPtr->DynPtr->UseStandardGravity&&PlanarGravity) + { + if (obstacleNormal.vy < -FLOOR_THRESHOLD) + { + obstacleSBPtr->DynPtr->IsInContactWithFloor = 1; + if (obstacleNormal.vy < -NEARLYFLATFLOOR_THRESHOLD) obstacleSBPtr->DynPtr->IsInContactWithNearlyFlatFloor = 1; + } + } + else + { + int angle = DotProduct(&obstacleNormal,&obstacleSBPtr->DynPtr->GravityDirection); + if (angle < -FLOOR_THRESHOLD) + { + /* we've hit something that's against the direction of gravity */ + obstacleSBPtr->DynPtr->IsInContactWithFloor = 1; + if (angle < -NEARLYFLATFLOOR_THRESHOLD) obstacleSBPtr->DynPtr->IsInContactWithNearlyFlatFloor = 1; + } + } + } + + } + } + } +// textprint("moving %d out of %d\n",distanceToMove,dynPtr->DistanceLeftToMove); + + /* move object */ + + // textprint("disp %d %d %d\n",displacement.vx,displacement.vy,displacement.vz); + + } + if (dynPtr->Displacement.vy>0 && dynPtr->CollisionReportPtr) + { + } + else + { + AddVectorToVector(dynPtr->Displacement, dynPtr->Position); + } + + #if 0 + if (distanceToMove!=dynPtr->DistanceLeftToMove) + { + /* create a report about the collision */ + { + COLLISIONREPORT *reportPtr = AllocateCollisionReport(dynPtr); + + if (reportPtr) + { + reportPtr->ObstacleSBPtr = obstacleSBPtr; + reportPtr->ObstacleNormal.vx = -obstacleNormal.vx; + reportPtr->ObstacleNormal.vy = -obstacleNormal.vy; + reportPtr->ObstacleNormal.vz = -obstacleNormal.vz; + } + } + + if (obstacleSBPtr) //&& !(obstacleSBPtr->DynPtr->StopOnCollision)) + /* give obstacle a report too */ + { + COLLISIONREPORT *reportPtr = AllocateCollisionReport(obstacleSBPtr->DynPtr); + + if (reportPtr) + { + reportPtr->ObstacleSBPtr = sbPtr; + reportPtr->ObstacleNormal.vx = obstacleNormal.vx; + reportPtr->ObstacleNormal.vy = obstacleNormal.vy; + reportPtr->ObstacleNormal.vz = obstacleNormal.vz; + } + } + } + #endif + + +} + + + + + +static void TestForValidPlayerStandUp(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + /* make a collision volume corresponding to a standing character */ + { + COLLISION_EXTENTS *extentsPtr = 0; + + switch(AvP.PlayerType) + { + default: + LOCALASSERT(0); + /* if no debug then fall through to marine */ + case I_Marine: + extentsPtr = &CollisionExtents[CE_MARINE]; + break; + + case I_Alien: + extentsPtr = &CollisionExtents[CE_ALIEN]; + break; + + case I_Predator: + extentsPtr = &CollisionExtents[CE_PREDATOR]; + break; + + } + + /* max X */ + dynPtr->ObjectVertices[0].vx = extentsPtr->CollisionRadius; + dynPtr->ObjectVertices[1].vx = extentsPtr->CollisionRadius; + dynPtr->ObjectVertices[2].vx = extentsPtr->CollisionRadius; + dynPtr->ObjectVertices[3].vx = extentsPtr->CollisionRadius; + + /* max Z */ + dynPtr->ObjectVertices[0].vz = extentsPtr->CollisionRadius; + dynPtr->ObjectVertices[2].vz = extentsPtr->CollisionRadius; + dynPtr->ObjectVertices[4].vz = extentsPtr->CollisionRadius; + dynPtr->ObjectVertices[6].vz = extentsPtr->CollisionRadius; + + /* min X */ + dynPtr->ObjectVertices[4].vx = -extentsPtr->CollisionRadius; + dynPtr->ObjectVertices[5].vx = -extentsPtr->CollisionRadius; + dynPtr->ObjectVertices[6].vx = -extentsPtr->CollisionRadius; + dynPtr->ObjectVertices[7].vx = -extentsPtr->CollisionRadius; + + /* min Z */ + dynPtr->ObjectVertices[1].vz = -extentsPtr->CollisionRadius; + dynPtr->ObjectVertices[3].vz = -extentsPtr->CollisionRadius; + dynPtr->ObjectVertices[5].vz = -extentsPtr->CollisionRadius; + dynPtr->ObjectVertices[7].vz = -extentsPtr->CollisionRadius; + + /* max Y */ + dynPtr->ObjectVertices[0].vy = extentsPtr->Bottom; + dynPtr->ObjectVertices[1].vy = extentsPtr->Bottom; + dynPtr->ObjectVertices[4].vy = extentsPtr->Bottom; + dynPtr->ObjectVertices[5].vy = extentsPtr->Bottom; + + /* min Y */ + dynPtr->ObjectVertices[2].vy = extentsPtr->StandingTop; + dynPtr->ObjectVertices[3].vy = extentsPtr->StandingTop; + dynPtr->ObjectVertices[6].vy = extentsPtr->StandingTop; + dynPtr->ObjectVertices[7].vy = extentsPtr->StandingTop; + + /* translate cuboid into world space */ + { + VECTORCH *vertexPtr = dynPtr->ObjectVertices; + + int vertexNum=8; + do + { + vertexPtr->vx += dynPtr->Position.vx; + vertexPtr->vy += dynPtr->Position.vy; + vertexPtr->vz += dynPtr->Position.vz; + vertexPtr++; + } + while(--vertexNum); + } + + } + + /* look for polygons inside this volume */ + FindLandscapePolygonsInObjectsVicinity(sbPtr); + FindObjectsToRelocateAgainst(sbPtr); + + + { + + int polysLeft; + struct ColPolyTag *polyPtr; + + polysLeft = NumberOfCollisionPolys; + polyPtr = CollisionPolysArray; + + while(polysLeft) + { + if(DoesPolygonIntersectNRBB(polyPtr,dynPtr->ObjectVertices)) + { + int greatestDistance; + + { + VECTORCH vertex = dynPtr->ObjectVertices[WhichNRBBVertex(dynPtr,&(polyPtr->PolyNormal))]; + vertex.vx -= polyPtr->PolyPoint[0].vx; + vertex.vy -= polyPtr->PolyPoint[0].vy; + vertex.vz -= polyPtr->PolyPoint[0].vz; + greatestDistance = -DotProduct(&vertex,&(polyPtr->PolyNormal)); + } + + if (greatestDistance>0) + { + /* sorry, no standing room */ + CreateNRBBForObject(sbPtr); + return; + } + } + polyPtr++; + polysLeft--; + } + + } + + /* standing up is ok */ + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); + + /* set player state */ + playerStatusPtr->ShapeState = PMph_Standing; + + /* if player is an alien, cancel his ability to walk on walls */ + if (AvP.PlayerType == I_Alien) + { + dynPtr->UseStandardGravity=1; + } + } + +} +static int SteppingUpIsValid(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + VECTORCH displacement; + + displacement.vx = MUL_FIXED(DirectionOfTravel.vx, COLLISION_GRANULARITY*2); + displacement.vy = - DistanceToStepUp; + displacement.vz = MUL_FIXED(DirectionOfTravel.vz, COLLISION_GRANULARITY*2); + + + + { + int i=8; + VECTORCH *vertexPtr = dynPtr->ObjectVertices; + do + { + vertexPtr->vx += displacement.vx; + vertexPtr->vy += displacement.vy; + vertexPtr->vz += displacement.vz; + vertexPtr++; + } + while(--i); + dynPtr->Position.vx += displacement.vx; + dynPtr->Position.vy += displacement.vy; + dynPtr->Position.vz += displacement.vz; + } + + /* look for polygons inside this volume */ + FindLandscapePolygonsInObjectsVicinity(sbPtr); + FindObjectsToRelocateAgainst(sbPtr); + + + { + + int polysLeft; + struct ColPolyTag *polyPtr; + + polysLeft = NumberOfCollisionPolys; + polyPtr = CollisionPolysArray; + + while(polysLeft) + { + if(DoesPolygonIntersectNRBB(polyPtr,dynPtr->ObjectVertices)) + { + #if 0 + int greatestDistance; + + { + VECTORCH vertex = dynPtr->ObjectVertices[WhichNRBBVertex(dynPtr,&(polyPtr->PolyNormal))]; + vertex.vx -= polyPtr->PolyPoint[0].vx; + vertex.vy -= polyPtr->PolyPoint[0].vy; + vertex.vz -= polyPtr->PolyPoint[0].vz; + greatestDistance = -DotProduct(&vertex,&(polyPtr->PolyNormal)); + } + + if (greatestDistance>0) + #endif + { + /* sorry, there's a polygon in the way */ + //textprint("no step %d\n",greatestDistance); + { + int i=8; + VECTORCH *vertexPtr = dynPtr->ObjectVertices; + do + { + vertexPtr->vx -= displacement.vx; + vertexPtr->vy -= displacement.vy; + vertexPtr->vz -= displacement.vz; + vertexPtr++; + } + while(--i); + dynPtr->Position.vx -= displacement.vx; + dynPtr->Position.vy -= displacement.vy; + dynPtr->Position.vz -= displacement.vz; + } + return 0; + } + } + polyPtr++; + polysLeft--; + } + + } + + /* steping up is ok */ + { + //textprint("step ok\n"); + return 1; + } + +} + +static void FindLandscapePolygonsInObjectsPath(STRATEGYBLOCK *sbPtr) +{ + extern int NumActiveBlocks; + extern DISPLAYBLOCK *ActiveBlockList[]; + + /* initialise near polygons array */ + CollisionPolysPtr = &CollisionPolysArray[0]; + NumberOfCollisionPolys=0; + + /* scan through ActiveBlockList for modules */ + { + int numberOfObjects = NumActiveBlocks; + while(numberOfObjects) + { + DISPLAYBLOCK* objectPtr = ActiveBlockList[--numberOfObjects]; + char isStaticObject=0; + + GLOBALASSERT(objectPtr); + if(objectPtr->ObStrategyBlock) + if(objectPtr->ObStrategyBlock->DynPtr) + { + if(((objectPtr->ObStrategyBlock->DynPtr->IsStatic) + ||(objectPtr->ObStrategyBlock->DynPtr->OnlyCollideWithObjects)) + &&(!objectPtr->ObStrategyBlock->DynPtr->OnlyCollideWithEnvironment)) + isStaticObject=1; + } + + if (objectPtr->ObMyModule) + { + MakeDynamicBoundingBoxForObject(sbPtr, &(objectPtr->ObWorld)); + + /* if the bounding box intersects with the object, investigate */ + if (( (DBBMaxX >= objectPtr->ObMinX) && (DBBMinX <= objectPtr->ObMaxX) ) + &&( (DBBMaxY >= objectPtr->ObMinY) && (DBBMinY <= objectPtr->ObMaxY) ) + &&( (DBBMaxZ >= objectPtr->ObMinZ) && (DBBMinZ <= objectPtr->ObMaxZ) )) + TestShapeWithDynamicBoundingBox(objectPtr,sbPtr->DynPtr); + } + else if (isStaticObject) + { + MakeDynamicBoundingBoxForObject(sbPtr, &(objectPtr->ObWorld)); + + /* if the bounding box intersects with the object, investigate */ + if (( (DBBMaxX >= -objectPtr->ObRadius) && (DBBMinX <= objectPtr->ObRadius) ) + &&( (DBBMaxY >= -objectPtr->ObRadius) && (DBBMinY <= objectPtr->ObRadius) ) + &&( (DBBMaxZ >= -objectPtr->ObRadius) && (DBBMinZ <= objectPtr->ObRadius) )) + TestShapeWithDynamicBoundingBox(objectPtr,sbPtr->DynPtr); + } + } + } +} +static void FindObjectPolygonsInObjectsPath(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr=sbPtr->DynPtr; + /* check against other objects */ + { + VECTORCH zero = {0,0,0}; + int i = NumberOfDynamicObjects; + MakeDynamicBoundingBoxForObject(sbPtr, &zero); + while(i--) + { + + STRATEGYBLOCK *obstaclePtr = DynamicObjectsList[i]; + VECTORCH *objectVerticesPtr = obstaclePtr->DynPtr->ObjectVertices; + + /* check whether collision is even possible */ + { + if (sbPtr==obstaclePtr) + continue; + + /* can it be seen? */ + if(obstaclePtr->SBdptr->ObFlags&ObFlag_NotVis) continue; + + /* two sprites */ + if((dynPtr->DynamicsType == DYN_TYPE_SPRITE_COLLISIONS) + &&(obstaclePtr->DynPtr->DynamicsType == DYN_TYPE_SPRITE_COLLISIONS) ) + continue; + + if ( (dynPtr->IgnoreSameObjectsAsYou || obstaclePtr->DynPtr->IgnoreSameObjectsAsYou) + &&(sbPtr->I_SBtype == obstaclePtr->I_SBtype) ) + continue; + + if (obstaclePtr->DynPtr->OnlyCollideWithObjects) + continue; + + if (obstaclePtr->DynPtr->OnlyCollideWithEnvironment) + continue; + + if ( ((obstaclePtr->SBdptr == Player) && dynPtr->IgnoreThePlayer) + ||((sbPtr->SBdptr == Player) && obstaclePtr->DynPtr->IgnoreThePlayer) ) + continue; + + if( (sbPtr->SBdptr==Player) + &&( (obstaclePtr->I_SBtype == I_BehaviourHierarchicalFragment) + ||(obstaclePtr->DynPtr->IsPickupObject)) + ) + { + continue; + } + + if (!( ( (DBBMaxX >= objectVerticesPtr[7].vx) && (DBBMinX <= objectVerticesPtr[0].vx) ) + &&( (DBBMaxY >= objectVerticesPtr[7].vy) && (DBBMinY <= objectVerticesPtr[0].vy) ) + &&( (DBBMaxZ >= objectVerticesPtr[7].vz) && (DBBMinZ <= objectVerticesPtr[0].vz) ) )) + continue; + } + + { + const int *vertexIndexPtr=&CuboidVertexList[0]; + int face=6; + + do + { + struct ColPolyTag poly; + poly.NumberOfVertices=4; + poly.ParentObject = obstaclePtr->SBdptr; + + poly.PolyPoint[0]=objectVerticesPtr[*vertexIndexPtr++]; + poly.PolyPoint[1]=objectVerticesPtr[*vertexIndexPtr++]; + poly.PolyPoint[2]=objectVerticesPtr[*vertexIndexPtr++]; + poly.PolyPoint[3]=objectVerticesPtr[*vertexIndexPtr++]; + + + if (IsPolygonWithinDynamicBoundingBox(&poly)) + { + { + switch(face) + { + case 6: /* all points are on max y face */ + { + poly.PolyNormal.vx = 0; + poly.PolyNormal.vy = ONE_FIXED; + poly.PolyNormal.vz = 0; + break; + } + case 5: /* all points are on max z face */ + { + poly.PolyNormal.vx = 0; + poly.PolyNormal.vy = 0; + poly.PolyNormal.vz = ONE_FIXED; + break; + } + case 4: /* all points are on max x face */ + { + poly.PolyNormal.vx = ONE_FIXED; + poly.PolyNormal.vy = 0; + poly.PolyNormal.vz = 0; + break; + } + case 3: /* all points are on min z face */ + { + poly.PolyNormal.vx = 0; + poly.PolyNormal.vy = 0; + poly.PolyNormal.vz = -ONE_FIXED; + break; + } + case 2: /* all points are on min x face */ + { + poly.PolyNormal.vx = -ONE_FIXED; + poly.PolyNormal.vy = 0; + poly.PolyNormal.vz = 0; + break; + } + case 1: /* all points are on min y face */ + { + poly.PolyNormal.vx = 0; + poly.PolyNormal.vy = -ONE_FIXED; + poly.PolyNormal.vz = 0; + break; + } + } + } + + #if 0 + polyDistance = DistanceMovedBeforeObjectHitsPolygon(dynPtr,&poly,distanceToMove); + if (polyDistance>=0) + { + /* If the player moves into a weapon/ammo/etc, report the collision but + don't stop the player. (ie. let him walk through it) */ + if( (sbPtr->SBdptr==Player) + &&( (obstaclePtr->I_SBtype == I_BehaviourHierarchicalFragment) + ||(obstaclePtr->DynPtr->IsPickupObject)) + ) + { + /* create a report about the collision */ + COLLISIONREPORT *reportPtr = AllocateCollisionReport(dynPtr); + if (reportPtr) + { + reportPtr->ObstacleSBPtr = obstaclePtr; + reportPtr->ObstacleNormal = poly.PolyNormal; + } + } + else + { + distanceToMove = polyDistance; + obstacleNormal = poly.PolyNormal; + obstaclePoint = poly.PolyPoint[0]; + obstacleSBPtr = obstaclePtr; + LOCALASSERT(obstaclePtr); + topOfStep = -2000000000; + } + } + #endif + *CollisionPolysPtr = poly; + + CollisionPolysPtr++; + NumberOfCollisionPolys++; + + } + face--; + } + while(face); + + } + } + } +} + +static void FindLandscapePolygonsInObjectsVicinity(STRATEGYBLOCK *sbPtr) +{ + extern int NumActiveBlocks; + extern DISPLAYBLOCK *ActiveBlockList[]; + + /* intialise near polygons array */ + CollisionPolysPtr = &CollisionPolysArray[0]; + NumberOfCollisionPolys=0; + + /* scan through ActiveBlockList for modules */ + { + int numberOfObjects = NumActiveBlocks; + while(numberOfObjects) + { + DISPLAYBLOCK* objectPtr = ActiveBlockList[--numberOfObjects]; + char isStaticObject=0; + + GLOBALASSERT(objectPtr); + if(objectPtr->ObStrategyBlock) + if(objectPtr->ObStrategyBlock->DynPtr) + { + if(((objectPtr->ObStrategyBlock->DynPtr->IsStatic) + ||(objectPtr->ObStrategyBlock->DynPtr->OnlyCollideWithObjects)) + &&(!objectPtr->ObStrategyBlock->DynPtr->OnlyCollideWithEnvironment)) + isStaticObject=1; + } + + if (objectPtr->ObMyModule) /* is object a module or static? */ + { + MakeStaticBoundingBoxForObject(sbPtr); + + /* translate SBB into space of landscape module */ + SBBMinX -= objectPtr->ObWorld.vx; + SBBMaxX -= objectPtr->ObWorld.vx; + + SBBMinY -= objectPtr->ObWorld.vy; + SBBMaxY -= objectPtr->ObWorld.vy; + + SBBMinZ -= objectPtr->ObWorld.vz; + SBBMaxZ -= objectPtr->ObWorld.vz; + + /* if the bounding box intersects with the object, investigate */ + if (( (SBBMaxX >= objectPtr->ObMinX) && (SBBMinX <= objectPtr->ObMaxX) ) + &&( (SBBMaxY >= objectPtr->ObMinY) && (SBBMinY <= objectPtr->ObMaxY) ) + &&( (SBBMaxZ >= objectPtr->ObMinZ) && (SBBMinZ <= objectPtr->ObMaxZ) )) + TestShapeWithStaticBoundingBox(objectPtr); + } + else if (isStaticObject) + { + MakeStaticBoundingBoxForObject(sbPtr); + + /* translate SBB into space of landscape module */ + SBBMinX -= objectPtr->ObWorld.vx; + SBBMaxX -= objectPtr->ObWorld.vx; + + SBBMinY -= objectPtr->ObWorld.vy; + SBBMaxY -= objectPtr->ObWorld.vy; + + SBBMinZ -= objectPtr->ObWorld.vz; + SBBMaxZ -= objectPtr->ObWorld.vz; + + /* if the bounding box intersects with the object, investigate */ + if (( (SBBMaxX >= objectPtr->ObMinX) && (SBBMinX <= objectPtr->ObMaxX) ) + &&( (SBBMaxY >= objectPtr->ObMinY) && (SBBMinY <= objectPtr->ObMaxY) ) + &&( (SBBMaxZ >= objectPtr->ObMinZ) && (SBBMinZ <= objectPtr->ObMaxZ) )) + TestShapeWithStaticBoundingBox(objectPtr); + } + + } + } +} + +static void FindObjectsToRelocateAgainst(STRATEGYBLOCK *sbPtr) +{ + MakeStaticBoundingBoxForObject(sbPtr); + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + int i = NumberOfDynamicObjects; + while(i--) + { + STRATEGYBLOCK *obstaclePtr = DynamicObjectsList[i]; + + /* check whether collision is even possible */ + if (sbPtr==obstaclePtr) + continue; + + /* ignore platform lifts */ + if(obstaclePtr->DynPtr->OnlyCollideWithObjects) + continue; + + /* ignore things that only collide with environment */ + if (obstaclePtr->DynPtr->OnlyCollideWithEnvironment) + continue; + + /* don't relocate against ammo and stuff */ + if (sbPtr->SBdptr==Player) + { + if(obstaclePtr->DynPtr->IsPickupObject) + { + continue; + } + } + + /* two sprites */ + if((dynPtr->DynamicsType == DYN_TYPE_SPRITE_COLLISIONS) + &&(obstaclePtr->DynPtr->DynamicsType == DYN_TYPE_SPRITE_COLLISIONS) ) + continue; + + if (dynPtr->IgnoreSameObjectsAsYou + &&(sbPtr->I_SBtype == obstaclePtr->I_SBtype) ) + continue; + + TestObjectWithStaticBoundingBox(obstaclePtr->SBdptr); + } + } +} + +static void MakeDynamicBoundingBoxForObject(STRATEGYBLOCK *sbPtr, VECTORCH *worldOffsetPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + DBBMaxX = dynPtr->ObjectVertices[0].vx - worldOffsetPtr->vx + COLLISION_GRANULARITY; + DBBMinX = dynPtr->ObjectVertices[7].vx - worldOffsetPtr->vx - COLLISION_GRANULARITY; + + DBBMaxY = dynPtr->ObjectVertices[0].vy - worldOffsetPtr->vy + COLLISION_GRANULARITY; + DBBMinY = dynPtr->ObjectVertices[7].vy - worldOffsetPtr->vy - COLLISION_GRANULARITY; + + DBBMaxZ = dynPtr->ObjectVertices[0].vz - worldOffsetPtr->vz + COLLISION_GRANULARITY; + DBBMinZ = dynPtr->ObjectVertices[7].vz - worldOffsetPtr->vz - COLLISION_GRANULARITY; + + if (dynPtr->Displacement.vx > 0) + { + DBBMaxX += dynPtr->Displacement.vx; + } + else + { + DBBMinX += dynPtr->Displacement.vx; + } + + if (dynPtr->Displacement.vy > 0) + { + DBBMaxY += dynPtr->Displacement.vy; + } + else + { + DBBMinY += dynPtr->Displacement.vy; + } + + if (dynPtr->Displacement.vz > 0) + { + DBBMaxZ += dynPtr->Displacement.vz; + } + else + { + DBBMinZ += dynPtr->Displacement.vz; + } + +} + +static void MakeStaticBoundingBoxForSphere(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + int objectSize = dynPtr->CollisionRadius+COLLISION_GRANULARITY; + + SBBMinX = dynPtr->Position.vx - objectSize; + SBBMaxX = dynPtr->Position.vx + objectSize; + SBBMinY = dynPtr->Position.vy - objectSize; + SBBMaxY = dynPtr->Position.vy + objectSize; + SBBMinZ = dynPtr->Position.vz - objectSize; + SBBMaxZ = dynPtr->Position.vz + objectSize; +} +static void MakeStaticBoundingBoxForNRBB(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + SBBMinX = dynPtr->ObjectVertices[7].vx - COLLISION_GRANULARITY*16; + SBBMaxX = dynPtr->ObjectVertices[0].vx + COLLISION_GRANULARITY*16; + + SBBMinY = dynPtr->ObjectVertices[7].vy - COLLISION_GRANULARITY*16; + SBBMaxY = dynPtr->ObjectVertices[0].vy + COLLISION_GRANULARITY*16; + + SBBMinZ = dynPtr->ObjectVertices[7].vz - COLLISION_GRANULARITY*16; + SBBMaxZ = dynPtr->ObjectVertices[0].vz + COLLISION_GRANULARITY*16; +} + +static void TestShapeWithDynamicBoundingBox(DISPLAYBLOCK *objectPtr, DYNAMICSBLOCK *mainDynPtr) +{ + int numberOfItems; + int needToRotate = 0; + + /* KJL 10:58:22 24/11/98 - If the object is a static object rather than a module, + we'll need to rotate the polygons into world-space */ + if (objectPtr->ObStrategyBlock) + { + DYNAMICSBLOCK *dynPtr = objectPtr->ObStrategyBlock->DynPtr; + + if (dynPtr) + { + if (dynPtr->IsStatic) + { + needToRotate = 1; + } + } + } + + + /* okay, let's setup the shape's data and access the first poly */ + numberOfItems = SetupPolygonAccess(objectPtr); + + /* go through polys looking for those which intersect with the bounding box */ + while(numberOfItems--) + { + AccessNextPolygon(); + + if (mainDynPtr->IgnoresNotVisPolys && (PolygonFlag & iflag_notvis) && !(PolygonFlag & iflag_mirror)) continue; + + GetPolygonVertices(CollisionPolysPtr); + + if (needToRotate) + { + int i = CollisionPolysPtr->NumberOfVertices; + VECTORCH *polyVertexPtr = CollisionPolysPtr->PolyPoint; + + + do + { + RotateVector(polyVertexPtr,&objectPtr->ObMat); + polyVertexPtr++; + } + while(--i); + } + + { + VECTORCH *vertices = CollisionPolysPtr->PolyPoint; + if (CollisionPolysPtr->NumberOfVertices==4) + { + if (vertices[0].vy < DBBMinY) + if (vertices[1].vy < DBBMinY) + if (vertices[2].vy < DBBMinY) + if (vertices[3].vy < DBBMinY) + continue; + + if (vertices[0].vx < DBBMinX) + if (vertices[1].vx < DBBMinX) + if (vertices[2].vx < DBBMinX) + if (vertices[3].vx < DBBMinX) + continue; + + if (vertices[0].vx > DBBMaxX) + if (vertices[1].vx > DBBMaxX) + if (vertices[2].vx > DBBMaxX) + if (vertices[3].vx > DBBMaxX) + continue; + + if (vertices[0].vz < DBBMinZ) + if (vertices[1].vz < DBBMinZ) + if (vertices[2].vz < DBBMinZ) + if (vertices[3].vz < DBBMinZ) + continue; + + if (vertices[0].vz > DBBMaxZ) + if (vertices[1].vz > DBBMaxZ) + if (vertices[2].vz > DBBMaxZ) + if (vertices[3].vz > DBBMaxZ) + continue; + + if (vertices[0].vy > DBBMaxY) + if (vertices[1].vy > DBBMaxY) + if (vertices[2].vy > DBBMaxY) + if (vertices[3].vy > DBBMaxY) + continue; + + } + else + { + if (vertices[0].vy < DBBMinY) + if (vertices[1].vy < DBBMinY) + if (vertices[2].vy < DBBMinY) + continue; + + if (vertices[0].vx < DBBMinX) + if (vertices[1].vx < DBBMinX) + if (vertices[2].vx < DBBMinX) + continue; + + if (vertices[0].vx > DBBMaxX) + if (vertices[1].vx > DBBMaxX) + if (vertices[2].vx > DBBMaxX) + continue; + + if (vertices[0].vz < DBBMinZ) + if (vertices[1].vz < DBBMinZ) + if (vertices[2].vz < DBBMinZ) + continue; + + if (vertices[0].vz > DBBMaxZ) + if (vertices[1].vz > DBBMaxZ) + if (vertices[2].vz > DBBMaxZ) + continue; + + if (vertices[0].vy > DBBMaxY) + if (vertices[1].vy > DBBMaxY) + if (vertices[2].vy > DBBMaxY) + continue; + + } + } + + /* add object's world space coords to vertices */ + { + int i = CollisionPolysPtr->NumberOfVertices; + VECTORCH *polyVertexPtr = CollisionPolysPtr->PolyPoint; + + + do + { + polyVertexPtr->vx += objectPtr->ObWorld.vx; + polyVertexPtr->vy += objectPtr->ObWorld.vy; + polyVertexPtr->vz += objectPtr->ObWorld.vz; + polyVertexPtr++; + } + while(--i); + } + + /* get the poly's normal */ + GetPolygonNormal(CollisionPolysPtr); + if (needToRotate) + { + RotateVector(&CollisionPolysPtr->PolyNormal,&objectPtr->ObMat); + } + CollisionPolysPtr->ParentObject = objectPtr; + + CollisionPolysPtr++; + NumberOfCollisionPolys++; + /* ran out of space? */ + LOCALASSERT(NumberOfCollisionPolys < MAXIMUM_NUMBER_OF_COLLISIONPOLYS); + + if (PolygonFlag & iflag_no_bfc) + { + CollisionPolysPtr->NumberOfVertices = (CollisionPolysPtr-1)->NumberOfVertices; + if(CollisionPolysPtr->NumberOfVertices==3) + { + CollisionPolysPtr->PolyPoint[0] = (CollisionPolysPtr-1)->PolyPoint[2]; + CollisionPolysPtr->PolyPoint[1] = (CollisionPolysPtr-1)->PolyPoint[1]; + CollisionPolysPtr->PolyPoint[2] = (CollisionPolysPtr-1)->PolyPoint[0]; + } + else + { + CollisionPolysPtr->PolyPoint[0] = (CollisionPolysPtr-1)->PolyPoint[3]; + CollisionPolysPtr->PolyPoint[1] = (CollisionPolysPtr-1)->PolyPoint[2]; + CollisionPolysPtr->PolyPoint[2] = (CollisionPolysPtr-1)->PolyPoint[1]; + CollisionPolysPtr->PolyPoint[3] = (CollisionPolysPtr-1)->PolyPoint[0]; + } + + CollisionPolysPtr->PolyNormal.vx = -(CollisionPolysPtr-1)->PolyNormal.vx; + CollisionPolysPtr->PolyNormal.vy = -(CollisionPolysPtr-1)->PolyNormal.vy; + CollisionPolysPtr->PolyNormal.vz = -(CollisionPolysPtr-1)->PolyNormal.vz; + CollisionPolysPtr->ParentObject = objectPtr; + + CollisionPolysPtr++; + NumberOfCollisionPolys++; + /* ran out of space? */ + LOCALASSERT(NumberOfCollisionPolys < MAXIMUM_NUMBER_OF_COLLISIONPOLYS); + } + } + + return; +} +static void TestShapeWithParticlesDynamicBoundingBox(DISPLAYBLOCK *objectPtr) +{ + int numberOfItems; + int needToRotate = 0; + + /* KJL 10:58:22 24/11/98 - If the object is a static object rather than a module, + we'll need to rotate the polygons into world-space */ + if (objectPtr->ObStrategyBlock) + { + DYNAMICSBLOCK *dynPtr = objectPtr->ObStrategyBlock->DynPtr; + + if (dynPtr) + { + if (dynPtr->IsStatic) + { + needToRotate = 1; + } + } + } + + + /* okay, let's setup the shape's data and access the first poly */ + numberOfItems = SetupPolygonAccess(objectPtr); + + /* go through polys looking for those which intersect with the bounding box */ + while(numberOfItems--) + { + AccessNextPolygon(); + + if (PolygonFlag & iflag_notvis) continue; + + GetPolygonVertices(CollisionPolysPtr); + if (needToRotate) + { + int i = CollisionPolysPtr->NumberOfVertices; + VECTORCH *polyVertexPtr = CollisionPolysPtr->PolyPoint; + + + do + { + RotateVector(polyVertexPtr,&objectPtr->ObMat); + polyVertexPtr++; + } + while(--i); + } + + { + VECTORCH *vertices = CollisionPolysPtr->PolyPoint; + if (CollisionPolysPtr->NumberOfVertices==4) + { + if (vertices[0].vy < DBBMinY) + if (vertices[1].vy < DBBMinY) + if (vertices[2].vy < DBBMinY) + if (vertices[3].vy < DBBMinY) + continue; + + if (vertices[0].vx < DBBMinX) + if (vertices[1].vx < DBBMinX) + if (vertices[2].vx < DBBMinX) + if (vertices[3].vx < DBBMinX) + continue; + + if (vertices[0].vx > DBBMaxX) + if (vertices[1].vx > DBBMaxX) + if (vertices[2].vx > DBBMaxX) + if (vertices[3].vx > DBBMaxX) + continue; + + if (vertices[0].vz < DBBMinZ) + if (vertices[1].vz < DBBMinZ) + if (vertices[2].vz < DBBMinZ) + if (vertices[3].vz < DBBMinZ) + continue; + + if (vertices[0].vz > DBBMaxZ) + if (vertices[1].vz > DBBMaxZ) + if (vertices[2].vz > DBBMaxZ) + if (vertices[3].vz > DBBMaxZ) + continue; + + if (vertices[0].vy > DBBMaxY) + if (vertices[1].vy > DBBMaxY) + if (vertices[2].vy > DBBMaxY) + if (vertices[3].vy > DBBMaxY) + continue; + + } + else + { + if (vertices[0].vy < DBBMinY) + if (vertices[1].vy < DBBMinY) + if (vertices[2].vy < DBBMinY) + continue; + + if (vertices[0].vx < DBBMinX) + if (vertices[1].vx < DBBMinX) + if (vertices[2].vx < DBBMinX) + continue; + + if (vertices[0].vx > DBBMaxX) + if (vertices[1].vx > DBBMaxX) + if (vertices[2].vx > DBBMaxX) + continue; + + if (vertices[0].vz < DBBMinZ) + if (vertices[1].vz < DBBMinZ) + if (vertices[2].vz < DBBMinZ) + continue; + + if (vertices[0].vz > DBBMaxZ) + if (vertices[1].vz > DBBMaxZ) + if (vertices[2].vz > DBBMaxZ) + continue; + + if (vertices[0].vy > DBBMaxY) + if (vertices[1].vy > DBBMaxY) + if (vertices[2].vy > DBBMaxY) + continue; + + } + } + + /* add object's world space coords to vertices */ + { + int i = CollisionPolysPtr->NumberOfVertices; + VECTORCH *polyVertexPtr = CollisionPolysPtr->PolyPoint; + + do + { + polyVertexPtr->vx += objectPtr->ObWorld.vx; + polyVertexPtr->vy += objectPtr->ObWorld.vy; + polyVertexPtr->vz += objectPtr->ObWorld.vz; + polyVertexPtr++; + } + while(--i); + } + + /* get the poly's normal */ + GetPolygonNormal(CollisionPolysPtr); + if (needToRotate) + { + RotateVector(&CollisionPolysPtr->PolyNormal,&objectPtr->ObMat); + } + CollisionPolysPtr->ParentObject = objectPtr; + + CollisionPolysPtr++; + NumberOfCollisionPolys++; + /* ran out of space? */ + LOCALASSERT(NumberOfCollisionPolys < MAXIMUM_NUMBER_OF_COLLISIONPOLYS); + + if (PolygonFlag & iflag_no_bfc) + { + CollisionPolysPtr->NumberOfVertices = (CollisionPolysPtr-1)->NumberOfVertices; + if(CollisionPolysPtr->NumberOfVertices==3) + { + CollisionPolysPtr->PolyPoint[0] = (CollisionPolysPtr-1)->PolyPoint[2]; + CollisionPolysPtr->PolyPoint[1] = (CollisionPolysPtr-1)->PolyPoint[1]; + CollisionPolysPtr->PolyPoint[2] = (CollisionPolysPtr-1)->PolyPoint[0]; + } + else + { + CollisionPolysPtr->PolyPoint[0] = (CollisionPolysPtr-1)->PolyPoint[3]; + CollisionPolysPtr->PolyPoint[1] = (CollisionPolysPtr-1)->PolyPoint[2]; + CollisionPolysPtr->PolyPoint[2] = (CollisionPolysPtr-1)->PolyPoint[1]; + CollisionPolysPtr->PolyPoint[3] = (CollisionPolysPtr-1)->PolyPoint[0]; + } + + CollisionPolysPtr->PolyNormal.vx = -(CollisionPolysPtr-1)->PolyNormal.vx; + CollisionPolysPtr->PolyNormal.vy = -(CollisionPolysPtr-1)->PolyNormal.vy; + CollisionPolysPtr->PolyNormal.vz = -(CollisionPolysPtr-1)->PolyNormal.vz; + CollisionPolysPtr->ParentObject = objectPtr; + + CollisionPolysPtr++; + NumberOfCollisionPolys++; + /* ran out of space? */ + LOCALASSERT(NumberOfCollisionPolys < MAXIMUM_NUMBER_OF_COLLISIONPOLYS); + } + } + + return; +} + +static void TestShapeWithStaticBoundingBox(DISPLAYBLOCK *objectPtr) +{ + int numberOfItems; + int needToRotate = 0; + + /* KJL 10:58:22 24/11/98 - If the object is a static object rather than a module, + we'll need to rotate the polygons into world-space */ + if (objectPtr->ObStrategyBlock) + { + DYNAMICSBLOCK *dynPtr = objectPtr->ObStrategyBlock->DynPtr; + + if (dynPtr) + { + if (dynPtr->IsStatic) + { + needToRotate = 1; + } + } + } + + /* okay, let's setup the shape's data and access the first poly */ + numberOfItems = SetupPolygonAccess(objectPtr); + + /* go through polys looking for those which intersect with the bounding box */ + while(numberOfItems--) + { + AccessNextPolygon(); + + // if (PolygonFlag & iflag_notvis) continue; + + GetPolygonVertices(CollisionPolysPtr); + if (needToRotate) + { + int i = CollisionPolysPtr->NumberOfVertices; + VECTORCH *polyVertexPtr = CollisionPolysPtr->PolyPoint; + + + do + { + RotateVector(polyVertexPtr,&objectPtr->ObMat); + polyVertexPtr++; + } + while(--i); + } + + if(IsPolygonWithinStaticBoundingBox(CollisionPolysPtr)) + { + /* add object's world space coords to vertices */ + { + int i = CollisionPolysPtr->NumberOfVertices; + VECTORCH *polyVertexPtr = CollisionPolysPtr->PolyPoint; + + do + { + polyVertexPtr->vx += objectPtr->ObWorld.vx; + polyVertexPtr->vy += objectPtr->ObWorld.vy; + polyVertexPtr->vz += objectPtr->ObWorld.vz; + polyVertexPtr++; + } + while(--i); + } + + /* get the poly's normal */ + GetPolygonNormal(CollisionPolysPtr); + if (needToRotate) + { + RotateVector(&CollisionPolysPtr->PolyNormal,&objectPtr->ObMat); + } + + CollisionPolysPtr++; + NumberOfCollisionPolys++; + + /* ran out of space? */ + LOCALASSERT(NumberOfCollisionPolys < MAXIMUM_NUMBER_OF_COLLISIONPOLYS); + if (PolygonFlag & iflag_no_bfc) + { + CollisionPolysPtr->NumberOfVertices = (CollisionPolysPtr-1)->NumberOfVertices; + if(CollisionPolysPtr->NumberOfVertices==3) + { + CollisionPolysPtr->PolyPoint[0] = (CollisionPolysPtr-1)->PolyPoint[2]; + CollisionPolysPtr->PolyPoint[1] = (CollisionPolysPtr-1)->PolyPoint[1]; + CollisionPolysPtr->PolyPoint[2] = (CollisionPolysPtr-1)->PolyPoint[0]; + } + else + { + CollisionPolysPtr->PolyPoint[0] = (CollisionPolysPtr-1)->PolyPoint[3]; + CollisionPolysPtr->PolyPoint[1] = (CollisionPolysPtr-1)->PolyPoint[2]; + CollisionPolysPtr->PolyPoint[2] = (CollisionPolysPtr-1)->PolyPoint[1]; + CollisionPolysPtr->PolyPoint[3] = (CollisionPolysPtr-1)->PolyPoint[0]; + } + + CollisionPolysPtr->PolyNormal.vx = -(CollisionPolysPtr-1)->PolyNormal.vx; + CollisionPolysPtr->PolyNormal.vy = -(CollisionPolysPtr-1)->PolyNormal.vy; + CollisionPolysPtr->PolyNormal.vz = -(CollisionPolysPtr-1)->PolyNormal.vz; + + CollisionPolysPtr++; + NumberOfCollisionPolys++; + /* ran out of space? */ + LOCALASSERT(NumberOfCollisionPolys < MAXIMUM_NUMBER_OF_COLLISIONPOLYS); + } + } + + } + + return; +} +static void TestObjectWithStaticBoundingBox(DISPLAYBLOCK *objectPtr) +{ + + DYNAMICSBLOCK *dynPtr = objectPtr->ObStrategyBlock->DynPtr; +// VECTORCH *objectPositionPtr = &(dynPtr->Position); + /* if the bounding box does not intersect with the object at all just return */ + VECTORCH *objectVerticesPtr = dynPtr->ObjectVertices; + + if (!( ( (SBBMaxX >= objectVerticesPtr[7].vx) && (SBBMinX <= objectVerticesPtr[0].vx) ) + &&( (SBBMaxY >= objectVerticesPtr[7].vy) && (SBBMinY <= objectVerticesPtr[0].vy) ) + &&( (SBBMaxZ >= objectVerticesPtr[7].vz) && (SBBMinZ <= objectVerticesPtr[0].vz) ) )) + return; + + /* okay, let's access the objects polys */ + { + const int *vertexIndexPtr=&CuboidVertexList[0]; + int face=6; + + do + { + CollisionPolysPtr->NumberOfVertices = 4; + CollisionPolysPtr->PolyPoint[0]=objectVerticesPtr[*vertexIndexPtr++]; + CollisionPolysPtr->PolyPoint[1]=objectVerticesPtr[*vertexIndexPtr++]; + CollisionPolysPtr->PolyPoint[2]=objectVerticesPtr[*vertexIndexPtr++]; + CollisionPolysPtr->PolyPoint[3]=objectVerticesPtr[*vertexIndexPtr++]; + + if(IsPolygonWithinStaticBoundingBox(CollisionPolysPtr)) + { + if(dynPtr->DynamicsType == DYN_TYPE_CUBOID_COLLISIONS) + { + switch(face) + { + case 6: /* all points are on max y face */ + { + CollisionPolysPtr->PolyNormal.vx = dynPtr->OrientMat.mat21; + CollisionPolysPtr->PolyNormal.vy = dynPtr->OrientMat.mat22; + CollisionPolysPtr->PolyNormal.vz = dynPtr->OrientMat.mat23; + break; + } + case 5: /* all points are on max z face */ + { + CollisionPolysPtr->PolyNormal.vx = dynPtr->OrientMat.mat31; + CollisionPolysPtr->PolyNormal.vy = dynPtr->OrientMat.mat32; + CollisionPolysPtr->PolyNormal.vz = dynPtr->OrientMat.mat33; + break; + } + case 4: /* all points are on max x face */ + { + CollisionPolysPtr->PolyNormal.vx = dynPtr->OrientMat.mat11; + CollisionPolysPtr->PolyNormal.vy = dynPtr->OrientMat.mat12; + CollisionPolysPtr->PolyNormal.vz = dynPtr->OrientMat.mat13; + break; + } + case 3: /* all points are on min z face */ + { + CollisionPolysPtr->PolyNormal.vx = -dynPtr->OrientMat.mat31; + CollisionPolysPtr->PolyNormal.vy = -dynPtr->OrientMat.mat32; + CollisionPolysPtr->PolyNormal.vz = -dynPtr->OrientMat.mat33; + break; + } + case 2: /* all points are on min x face */ + { + CollisionPolysPtr->PolyNormal.vx = -dynPtr->OrientMat.mat11; + CollisionPolysPtr->PolyNormal.vy = -dynPtr->OrientMat.mat12; + CollisionPolysPtr->PolyNormal.vz = -dynPtr->OrientMat.mat13; + break; + } + case 1: /* all points are on min y face */ + { + CollisionPolysPtr->PolyNormal.vx = -dynPtr->OrientMat.mat21; + CollisionPolysPtr->PolyNormal.vy = -dynPtr->OrientMat.mat22; + CollisionPolysPtr->PolyNormal.vz = -dynPtr->OrientMat.mat23; + break; + } + } + } + else + { + switch(face) + { + case 6: /* all points are on max y face */ + { + CollisionPolysPtr->PolyNormal.vx = 0; + CollisionPolysPtr->PolyNormal.vy = ONE_FIXED; + CollisionPolysPtr->PolyNormal.vz = 0; + break; + } + case 5: /* all points are on max z face */ + { + CollisionPolysPtr->PolyNormal.vx = 0; + CollisionPolysPtr->PolyNormal.vy = 0; + CollisionPolysPtr->PolyNormal.vz = ONE_FIXED; + break; + } + case 4: /* all points are on max x face */ + { + CollisionPolysPtr->PolyNormal.vx = ONE_FIXED; + CollisionPolysPtr->PolyNormal.vy = 0; + CollisionPolysPtr->PolyNormal.vz = 0; + break; + } + case 3: /* all points are on min z face */ + { + CollisionPolysPtr->PolyNormal.vx = 0; + CollisionPolysPtr->PolyNormal.vy = 0; + CollisionPolysPtr->PolyNormal.vz = -ONE_FIXED; + break; + } + case 2: /* all points are on min x face */ + { + CollisionPolysPtr->PolyNormal.vx = -ONE_FIXED; + CollisionPolysPtr->PolyNormal.vy = 0; + CollisionPolysPtr->PolyNormal.vz = 0; + break; + } + case 1: /* all points are on min y face */ + { + CollisionPolysPtr->PolyNormal.vx = 0; + CollisionPolysPtr->PolyNormal.vy = -ONE_FIXED; + CollisionPolysPtr->PolyNormal.vz = 0; + break; + } + } + } + CollisionPolysPtr++; + NumberOfCollisionPolys++; + + /* ran out of space? */ + LOCALASSERT(NumberOfCollisionPolys < MAXIMUM_NUMBER_OF_COLLISIONPOLYS); + } + } + while(--face); + + } + return; +} + + +static int IsPolygonWithinDynamicBoundingBox(const struct ColPolyTag *polyPtr) +{ + VECTORCH *vertices = polyPtr->PolyPoint; + + if (polyPtr->NumberOfVertices==4) + { + if (vertices[0].vy < DBBMinY) + if (vertices[1].vy < DBBMinY) + if (vertices[2].vy < DBBMinY) + if (vertices[3].vy < DBBMinY) + return 0; + + if (vertices[0].vx < DBBMinX) + if (vertices[1].vx < DBBMinX) + if (vertices[2].vx < DBBMinX) + if (vertices[3].vx < DBBMinX) + return 0; + + if (vertices[0].vx > DBBMaxX) + if (vertices[1].vx > DBBMaxX) + if (vertices[2].vx > DBBMaxX) + if (vertices[3].vx > DBBMaxX) + return 0; + + if (vertices[0].vz < DBBMinZ) + if (vertices[1].vz < DBBMinZ) + if (vertices[2].vz < DBBMinZ) + if (vertices[3].vz < DBBMinZ) + return 0; + + if (vertices[0].vz > DBBMaxZ) + if (vertices[1].vz > DBBMaxZ) + if (vertices[2].vz > DBBMaxZ) + if (vertices[3].vz > DBBMaxZ) + return 0; + + if (vertices[0].vy > DBBMaxY) + if (vertices[1].vy > DBBMaxY) + if (vertices[2].vy > DBBMaxY) + if (vertices[3].vy > DBBMaxY) + return 0; + + } + else + { + if (vertices[0].vy < DBBMinY) + if (vertices[1].vy < DBBMinY) + if (vertices[2].vy < DBBMinY) + return 0; + + if (vertices[0].vx < DBBMinX) + if (vertices[1].vx < DBBMinX) + if (vertices[2].vx < DBBMinX) + return 0; + + if (vertices[0].vx > DBBMaxX) + if (vertices[1].vx > DBBMaxX) + if (vertices[2].vx > DBBMaxX) + return 0; + + if (vertices[0].vz < DBBMinZ) + if (vertices[1].vz < DBBMinZ) + if (vertices[2].vz < DBBMinZ) + return 0; + + if (vertices[0].vz > DBBMaxZ) + if (vertices[1].vz > DBBMaxZ) + if (vertices[2].vz > DBBMaxZ) + return 0; + + if (vertices[0].vy > DBBMaxY) + if (vertices[1].vy > DBBMaxY) + if (vertices[2].vy > DBBMaxY) + return 0; + + } + + + return 1; +} + +static int IsPolygonWithinStaticBoundingBox(const struct ColPolyTag *polyPtr) +{ + VECTORCH *vertices = polyPtr->PolyPoint; + + if (polyPtr->NumberOfVertices==4) + { + if (vertices[0].vy < SBBMinY) + if (vertices[1].vy < SBBMinY) + if (vertices[2].vy < SBBMinY) + if (vertices[3].vy < SBBMinY) + return 0; + + if (vertices[0].vx < SBBMinX) + if (vertices[1].vx < SBBMinX) + if (vertices[2].vx < SBBMinX) + if (vertices[3].vx < SBBMinX) + return 0; + + if (vertices[0].vx > SBBMaxX) + if (vertices[1].vx > SBBMaxX) + if (vertices[2].vx > SBBMaxX) + if (vertices[3].vx > SBBMaxX) + return 0; + + if (vertices[0].vz < SBBMinZ) + if (vertices[1].vz < SBBMinZ) + if (vertices[2].vz < SBBMinZ) + if (vertices[3].vz < SBBMinZ) + return 0; + + if (vertices[0].vz > SBBMaxZ) + if (vertices[1].vz > SBBMaxZ) + if (vertices[2].vz > SBBMaxZ) + if (vertices[3].vz > SBBMaxZ) + return 0; + + if (vertices[0].vy > SBBMaxY) + if (vertices[1].vy > SBBMaxY) + if (vertices[2].vy > SBBMaxY) + if (vertices[3].vy > SBBMaxY) + return 0; + + } + else + { + if (vertices[0].vy < SBBMinY) + if (vertices[1].vy < SBBMinY) + if (vertices[2].vy < SBBMinY) + return 0; + + if (vertices[0].vx < SBBMinX) + if (vertices[1].vx < SBBMinX) + if (vertices[2].vx < SBBMinX) + return 0; + + if (vertices[0].vx > SBBMaxX) + if (vertices[1].vx > SBBMaxX) + if (vertices[2].vx > SBBMaxX) + return 0; + + if (vertices[0].vz < SBBMinZ) + if (vertices[1].vz < SBBMinZ) + if (vertices[2].vz < SBBMinZ) + return 0; + + if (vertices[0].vz > SBBMaxZ) + if (vertices[1].vz > SBBMaxZ) + if (vertices[2].vz > SBBMaxZ) + return 0; + + if (vertices[0].vy > SBBMaxY) + if (vertices[1].vy > SBBMaxY) + if (vertices[2].vy > SBBMaxY) + return 0; + + } + + + return 1; +} + + + + + + + + + + +/*KJL**************************************************************************** +* A function which takes a plane's normal and decides which axis to ignore when * +* projecting points on the plane into a 2D space. * +****************************************************************************KJL*/ +static int AxisToIgnore(VECTORCH *normal) +{ + VECTORCH absNormal = *normal; + if (absNormal.vx<0) absNormal.vx=-absNormal.vx; + if (absNormal.vy<0) absNormal.vy=-absNormal.vy; + if (absNormal.vz<0) absNormal.vz=-absNormal.vz; + + if (absNormal.vx > absNormal.vy) + { + if (absNormal.vx > absNormal.vz) + { + return ix; + } + else + { + return iz; + } + } + else + { + if (absNormal.vy > absNormal.vz) + { + return iy; + } + else + { + return iz; + } + } +} + + + + +static void TestForValidMovement(STRATEGYBLOCK *sbPtr) +{ + #if 1 + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + /* I'm a platform lift - leave me alone */ + if(dynPtr->OnlyCollideWithObjects) + return; + + if(RelocationIsValid(sbPtr)) + { + /* movement ok */ + } + else + { + /* cancel movement */ + //PrintDebuggingText("Relocate!"); + dynPtr->Position=dynPtr->PrevPosition; + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + } + #endif +} + +static int RelocateSphere(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + VECTORCH objectPosition = dynPtr->Position; + VECTORCH objectVertices[8]; + + int polysLeft; + struct ColPolyTag *polyPtr; + + polysLeft = NumberOfCollisionPolys; + polyPtr = CollisionPolysArray; + + { + int vertexNum=8; + do + { + vertexNum--; + objectVertices[vertexNum] = dynPtr->ObjectVertices[vertexNum]; + } + while(vertexNum); + } + + /* first pass relocate */ + while(polysLeft) + { + VECTORCH planeNormal = polyPtr->PolyNormal; + VECTORCH pointOnPlane = polyPtr->PolyPoint[0]; + int distance; + + { + VECTORCH planeToObject; + + planeToObject.vx = objectPosition.vx - pointOnPlane.vx; + planeToObject.vy = objectPosition.vy - pointOnPlane.vy; + planeToObject.vz = objectPosition.vz - pointOnPlane.vz; + + distance = dynPtr->CollisionRadius - Dot(&planeToObject,&planeNormal); + } + + if (distance>0 && DoesPolygonIntersectNRBB(polyPtr,objectVertices)) + { + VECTORCH displacement; + + displacement.vx = MUL_FIXED(planeNormal.vx,distance+RELOCATION_GRANULARITY); + displacement.vy = MUL_FIXED(planeNormal.vy,distance+RELOCATION_GRANULARITY); + displacement.vz = MUL_FIXED(planeNormal.vz,distance+RELOCATION_GRANULARITY); + + AddVectorToVector(displacement,objectPosition); + { + int vertexNum=8; + VECTORCH *vertexPtr = objectVertices; + + do + { + vertexPtr->vx += displacement.vx; + vertexPtr->vy += displacement.vy; + vertexPtr->vz += displacement.vz; + vertexPtr++; + } + while(--vertexNum); + } + + } + + polyPtr++; + polysLeft--; + } + + /* did we move at all? */ + if ( (objectPosition.vx == dynPtr->Position.vx) + &&(objectPosition.vy == dynPtr->Position.vy) + &&(objectPosition.vz == dynPtr->Position.vz) ) + return 1; + + /* pass test if okay */ + polysLeft = NumberOfCollisionPolys; + polyPtr = CollisionPolysArray; + + { + int stillIntersectingSomething = 0; + while(polysLeft) + { + { + VECTORCH planeNormal = polyPtr->PolyNormal; + VECTORCH pointOnPlane = polyPtr->PolyPoint[0]; + int distance; + + { + VECTORCH planeToObject; + + planeToObject.vx = objectPosition.vx - pointOnPlane.vx; + planeToObject.vy = objectPosition.vy - pointOnPlane.vy; + planeToObject.vz = objectPosition.vz - pointOnPlane.vz; + + distance = dynPtr->CollisionRadius - Dot(&planeToObject,&planeNormal); + } + + if (distance>0 && DoesPolygonIntersectNRBB(polyPtr,objectVertices)) + { + stillIntersectingSomething = 1; + } + } + polyPtr++; + polysLeft--; + } + + if (stillIntersectingSomething) + { + return 0; + } + else + { + int vertexNum=8; + do + { + vertexNum--; + dynPtr->ObjectVertices[vertexNum] = objectVertices[vertexNum]; + } + while(vertexNum); + dynPtr->Position = objectPosition; + return 1; + } + } +} + +static int RelocateNRBB(STRATEGYBLOCK *sbPtr) +{ + int noProblems = 1; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + VECTORCH objectPosition = dynPtr->Position; + VECTORCH objectVertices[8]; + int polysLeft; + struct ColPolyTag *polyPtr; + + polysLeft = NumberOfCollisionPolys; + polyPtr = CollisionPolysArray; + + { + int vertexNum=8; + do + { + vertexNum--; + objectVertices[vertexNum] = dynPtr->ObjectVertices[vertexNum]; + } + while(vertexNum); + } + + while(polysLeft) + { + VECTORCH planeNormal = polyPtr->PolyNormal; + VECTORCH pointOnPlane = polyPtr->PolyPoint[0]; + + { + VECTORCH planeToObject; + + planeToObject.vx = objectPosition.vx - pointOnPlane.vx; + planeToObject.vy = objectPosition.vy - pointOnPlane.vy; + planeToObject.vz = objectPosition.vz - pointOnPlane.vz; + + if (DotProduct(&planeToObject,&planeNormal) < 0) + { + polyPtr++; + polysLeft--; + continue; + } + } + { + int greatestDistance; + + { + VECTORCH vertex = objectVertices[WhichNRBBVertex(dynPtr,&planeNormal)]; + vertex.vx -= pointOnPlane.vx; + vertex.vy -= pointOnPlane.vy; + vertex.vz -= pointOnPlane.vz; + greatestDistance = -DotProduct(&vertex,&planeNormal); + } + + if ((greatestDistance>0) && DoesPolygonIntersectNRBB(polyPtr,objectVertices)) + { + #if 0 + VECTORCH displacement; + + displacement.vx = MUL_FIXED(planeNormal.vx,greatestDistance+RELOCATION_GRANULARITY); + displacement.vy = MUL_FIXED(planeNormal.vy,greatestDistance+RELOCATION_GRANULARITY); + displacement.vz = MUL_FIXED(planeNormal.vz,greatestDistance+RELOCATION_GRANULARITY); + + AddVectorToVector(displacement,objectPosition); + { + int vertexNum=8; + VECTORCH *vertexPtr = objectVertices; + + do + { + vertexPtr->vx += displacement.vx; + vertexPtr->vy += displacement.vy; + vertexPtr->vz += displacement.vz; + vertexPtr++; + } + while(--vertexNum); + } + #endif + /* create a report about the collision */ + { + COLLISIONREPORT *reportPtr = AllocateCollisionReport(dynPtr); + + if (reportPtr) + { + reportPtr->ObstacleSBPtr = 0;//obstacleSBPtr; + reportPtr->ObstacleNormal = planeNormal; + + reportPtr->ObstaclePoint = pointOnPlane; + // reportPtr->ObstaclePoint.vx = 0x7fffffff; + // reportPtr->ObstaclePoint.vy = 0x7fffffff; + // reportPtr->ObstaclePoint.vz = 0x7fffffff; + } + } + noProblems = 0; + + } + } + polyPtr++; + polysLeft--; + } + #if 0 + /* did we move at all? */ + if ( (objectPosition.vx == dynPtr->Position.vx) + &&(objectPosition.vy == dynPtr->Position.vy) + &&(objectPosition.vz == dynPtr->Position.vz) ) + return noProblems; + + + /* pass test if okay */ + polysLeft = NumberOfCollisionPolys; + polyPtr = CollisionPolysArray; + + { + while(polysLeft) + { + if(DoesPolygonIntersectNRBB(polyPtr,objectVertices)) + { + VECTORCH planeNormal = polyPtr->PolyNormal; + VECTORCH pointOnPlane = polyPtr->PolyPoint[0]; + int greatestDistance; + + { + VECTORCH vertex = objectVertices[WhichNRBBVertex(dynPtr,&planeNormal)]; + vertex.vx -= pointOnPlane.vx; + vertex.vy -= pointOnPlane.vy; + vertex.vz -= pointOnPlane.vz; + greatestDistance = -DotProduct(&vertex,&planeNormal); + } + + if (greatestDistance>0) + { + /* still intersecting something */ + return noProblems; + } + } + polyPtr++; + polysLeft--; + } + + { + int vertexNum=8; + do + { + vertexNum--; + dynPtr->ObjectVertices[vertexNum] = objectVertices[vertexNum]; + } + while(vertexNum); + dynPtr->Position = objectPosition; + return 1; + } + } + #endif + if (!noProblems) PrintDebuggingText("RECOMMEND RELOCATE\n"); + return noProblems; +} + + +static int DoesPolygonIntersectNRBB(struct ColPolyTag *polyPtr,VECTORCH *objectVertices) +{ + VECTORCH *minVertexPtr = &objectVertices[7]; + VECTORCH *vertices = polyPtr->PolyPoint; + + /* trivial rejection tests */ + if (polyPtr->NumberOfVertices==4) + { + if (vertices[0].vx < minVertexPtr->vx) + if (vertices[1].vx < minVertexPtr->vx) + if (vertices[2].vx < minVertexPtr->vx) + if (vertices[3].vx < minVertexPtr->vx) + return 0; + + if (vertices[0].vz < minVertexPtr->vz) + if (vertices[1].vz < minVertexPtr->vz) + if (vertices[2].vz < minVertexPtr->vz) + if (vertices[3].vz < minVertexPtr->vz) + return 0; + + if (vertices[0].vy < minVertexPtr->vy) + if (vertices[1].vy < minVertexPtr->vy) + if (vertices[2].vy < minVertexPtr->vy) + if (vertices[3].vy < minVertexPtr->vy) + return 0; + + + if (vertices[0].vx > objectVertices->vx) + if (vertices[1].vx > objectVertices->vx) + if (vertices[2].vx > objectVertices->vx) + if (vertices[3].vx > objectVertices->vx) + return 0; + + if (vertices[0].vz > objectVertices->vz) + if (vertices[1].vz > objectVertices->vz) + if (vertices[2].vz > objectVertices->vz) + if (vertices[3].vz > objectVertices->vz) + return 0; + + if (vertices[0].vy > objectVertices->vy) + if (vertices[1].vy > objectVertices->vy) + if (vertices[2].vy > objectVertices->vy) + if (vertices[3].vy > objectVertices->vy) + return 0; + + } + else + { + if (vertices[0].vx < minVertexPtr->vx) + if (vertices[1].vx < minVertexPtr->vx) + if (vertices[2].vx < minVertexPtr->vx) + return 0; + + if (vertices[0].vz < minVertexPtr->vz) + if (vertices[1].vz < minVertexPtr->vz) + if (vertices[2].vz < minVertexPtr->vz) + return 0; + + if (vertices[0].vy < minVertexPtr->vy) + if (vertices[1].vy < minVertexPtr->vy) + if (vertices[2].vy < minVertexPtr->vy) + return 0; + + + if (vertices[0].vx > objectVertices->vx) + if (vertices[1].vx > objectVertices->vx) + if (vertices[2].vx > objectVertices->vx) + return 0; + + if (vertices[0].vz > objectVertices->vz) + if (vertices[1].vz > objectVertices->vz) + if (vertices[2].vz > objectVertices->vz) + return 0; + + if (vertices[0].vy > objectVertices->vy) + if (vertices[1].vy > objectVertices->vy) + if (vertices[2].vy > objectVertices->vy) + return 0; + } + + /* are any of the poly's vertices inside the object's bounding box? */ + { + if (vertices[0].vy >= minVertexPtr->vy) + if (vertices[0].vy <= objectVertices->vy) + if (vertices[0].vx >= minVertexPtr->vx) + if (vertices[0].vx <= objectVertices->vx) + if (vertices[0].vz >= minVertexPtr->vz) + if (vertices[0].vz <= objectVertices->vz) + return 1; + if (vertices[1].vy >= minVertexPtr->vy) + if (vertices[1].vy <= objectVertices->vy) + if (vertices[1].vx >= minVertexPtr->vx) + if (vertices[1].vx <= objectVertices->vx) + if (vertices[1].vz >= minVertexPtr->vz) + if (vertices[1].vz <= objectVertices->vz) + return 1; + if (vertices[2].vy >= minVertexPtr->vy) + if (vertices[2].vy <= objectVertices->vy) + if (vertices[2].vx >= minVertexPtr->vx) + if (vertices[2].vx <= objectVertices->vx) + if (vertices[2].vz >= minVertexPtr->vz) + if (vertices[2].vz <= objectVertices->vz) + return 1; + } + if (polyPtr->NumberOfVertices==4) + { + if (vertices[3].vy >= minVertexPtr->vy) + if (vertices[3].vy <= objectVertices->vy) + if (vertices[3].vx >= minVertexPtr->vx) + if (vertices[3].vx <= objectVertices->vx) + if (vertices[3].vz >= minVertexPtr->vz) + if (vertices[3].vz <= objectVertices->vz) + return 1; + } + + /* okay, it's not that simple then. Let's see if any of the poly's edges + intersect the objects bounding box */ + { + int vertexA = polyPtr->NumberOfVertices; + do + { + VECTORCH alpha,beta; + int vertexB; + vertexA--; + vertexB = (vertexA+1)%(polyPtr->NumberOfVertices); + + alpha = vertices[vertexA]; + beta.vx = vertices[vertexB].vx - alpha.vx; + beta.vy = vertices[vertexB].vy - alpha.vy; + beta.vz = vertices[vertexB].vz - alpha.vz; + + /* edge is the line segment 'alpha + lambda*beta' where lambda is between 0 and 1 */ + if (beta.vy!=0) + { + { + /* box edge 1: y=minVertexPtr->vy; normal is (0,-1,0) */ + int lambda; + + f2i(lambda,(float)(minVertexPtr->vy - alpha.vy)/(float)beta.vy*65536.0f); + + /* eliminate the divides? */ + if (lambda>=0 && lambda <= 65536) + { + int intersectionX = alpha.vx + MUL_FIXED(lambda,beta.vx); + if (intersectionX >= minVertexPtr->vx && intersectionX <= objectVertices->vx) + { + int intersectionZ = alpha.vz + MUL_FIXED(lambda,beta.vz); + if (intersectionZ >= minVertexPtr->vz && intersectionZ <= objectVertices->vz) + return 1; + } + } + } + { + /* box edge 2: y=objectVertices->vy; normal is (0,1,0) */ + int lambda;// = DIV_FIXED(objectVertices->vy - (alpha.vy),(beta.vy) ); + f2i(lambda,(float)(objectVertices->vy - alpha.vy)/(float)beta.vy*65536.0f); + /* eliminate the divides? */ + if (lambda>=0 && lambda <= 65536) + { + int intersectionX = alpha.vx + MUL_FIXED(lambda,beta.vx); + if (intersectionX >= minVertexPtr->vx && intersectionX <= objectVertices->vx) + { + int intersectionZ = alpha.vz + MUL_FIXED(lambda,beta.vz); + if (intersectionZ >= minVertexPtr->vz && intersectionZ <= objectVertices->vz) + return 1; + } + } + } + } + if (beta.vx!=0) + { + { + /* box edge 3: x=minVertexPtr->vx; normal is (-1,0,0) */ + int lambda;// = DIV_FIXED(minVertexPtr->vx - (alpha.vx),(beta.vx) ); + f2i(lambda,(float)(minVertexPtr->vx - alpha.vx)/(float)beta.vx*65536.0f); + /* eliminate the divides? */ + if (lambda>=0 && lambda <= 65536) + { + int intersectionY = alpha.vy + MUL_FIXED(lambda,beta.vy); + if (intersectionY >= minVertexPtr->vy && intersectionY <= objectVertices->vy) + { + int intersectionZ = alpha.vz + MUL_FIXED(lambda,beta.vz); + if (intersectionZ >= minVertexPtr->vz && intersectionZ <= objectVertices->vz) + return 1; + } + } + } + { + /* box edge 4: x=objectVertices->vx; normal is (1,0,0) */ + int lambda;// = DIV_FIXED(objectVertices->vx - (alpha.vx),(beta.vx) ); + f2i(lambda,(float)(objectVertices->vx - alpha.vx)/(float)beta.vx*65536.0f); + /* eliminate the divides? */ + if (lambda>=0 && lambda <= 65536) + { + int intersectionY = alpha.vy + MUL_FIXED(lambda,beta.vy); + if (intersectionY >= minVertexPtr->vy && intersectionY <= objectVertices->vy) + { + int intersectionZ = alpha.vz + MUL_FIXED(lambda,beta.vz); + if (intersectionZ >= minVertexPtr->vz && intersectionZ <= objectVertices->vz) + return 1; + } + } + } + } + if (beta.vz!=0) + { + { + /* box edge 5: z=minVertexPtr->vz; normal is (0,0,-1) */ + int lambda;// = DIV_FIXED(minVertexPtr->vz - (alpha.vz),(beta.vz)); + f2i(lambda,(float)(minVertexPtr->vz - alpha.vz)/(float)beta.vz*65536.0f); + /* eliminate the divides? */ + if (lambda>=0 && lambda <= 65536) + { + int intersectionY = alpha.vy + MUL_FIXED(lambda,beta.vy); + if (intersectionY >= minVertexPtr->vy && intersectionY <= objectVertices->vy) + { + int intersectionX = alpha.vx + MUL_FIXED(lambda,beta.vx); + if (intersectionX >= minVertexPtr->vx && intersectionX <= objectVertices->vx) + return 1; + } + } + } + { + /* box edge 6: z=objectVertices->vz; normal is (0,0,1) */ + int lambda;// = DIV_FIXED(objectVertices->vz - (alpha.vz),(beta.vz)); + f2i(lambda,(float)(objectVertices->vz - alpha.vz)/(float)beta.vz*65536.0f); + /* eliminate the divides? */ + if (lambda>=0 && lambda <= 65536) + { + int intersectionY = alpha.vy + MUL_FIXED(lambda,beta.vy); + if (intersectionY >= minVertexPtr->vy && intersectionY <= objectVertices->vy) + { + int intersectionX = alpha.vx + MUL_FIXED(lambda,beta.vx); + if (intersectionX >= minVertexPtr->vx && intersectionX <= objectVertices->vx) + return 1; + } + } + } + } + + } + while(vertexA); + } + /* Still here? Damn. Okay, we'll have to check to see if a cuboid's diagonal intersect the polygon */ + { + VECTORCH alpha,beta; + int dottedNormals; + int lambda; + + if ((polyPtr->PolyNormal).vx > 0) + { + alpha.vx = minVertexPtr->vx; + beta.vx = objectVertices->vx - alpha.vx; + } + else + { + alpha.vx = objectVertices->vx; + beta.vx = minVertexPtr->vx - alpha.vx; + } + + if ((polyPtr->PolyNormal).vy > 0) + { + alpha.vy = minVertexPtr->vy; + beta.vy = objectVertices->vy - alpha.vy; + } + else + { + alpha.vy = objectVertices->vy; + beta.vy = minVertexPtr->vy - alpha.vy; + } + + if ((polyPtr->PolyNormal).vz > 0) + { + alpha.vz = minVertexPtr->vz; + beta.vz = objectVertices->vz - alpha.vz; + } + else + { + alpha.vz = objectVertices->vz; + beta.vz = minVertexPtr->vz - alpha.vz; + } + + dottedNormals = DotProduct(&(polyPtr->PolyNormal),&beta); + #if 1//debug + if (!dottedNormals) + { + #if 0 + char buffer[200]; + sprintf(buffer,"POLY NORMAL IS %d %d %d\n",(polyPtr->PolyNormal).vx,(polyPtr->PolyNormal).vy,(polyPtr->PolyNormal).vz); + NewOnScreenMessage(buffer); + sprintf(buffer,"POLY NO OF VERTICES %d\n",(polyPtr->NumberOfVertices)); + NewOnScreenMessage(buffer); + sprintf(buffer,"POLY POINT IS %d %d %d\n",(polyPtr->PolyPoint[0]).vx,(polyPtr->PolyPoint[0]).vy,(polyPtr->PolyPoint[0]).vz); + NewOnScreenMessage(buffer); + #endif + LOGDXFMT(( "POLY NORMAL IS %d %d %d\n",(polyPtr->PolyNormal).vx,(polyPtr->PolyNormal).vy,(polyPtr->PolyNormal).vz)); + LOGDXFMT(( "POLY NO OF VERTICES %d\n",polyPtr->NumberOfVertices)); + LOGDXFMT(( "POLY POINT IS %d %d %d\n",(polyPtr->PolyPoint[0]).vx,(polyPtr->PolyPoint[0]).vy,(polyPtr->PolyPoint[0]).vz )); + LOCALASSERT("Found normal which may be incorrect"==0); + return 0; + } + #endif + { + VECTORCH cornerToPlane; + cornerToPlane.vx = vertices[0].vx - alpha.vx; + cornerToPlane.vy = vertices[0].vy - alpha.vy; + cornerToPlane.vz = vertices[0].vz - alpha.vz; + lambda = DIV_FIXED + ( + DotProduct(&(polyPtr->PolyNormal),&cornerToPlane), + dottedNormals + ); + } + + if (lambda >= 0 && lambda <= 65536) + { + int axis1,axis2; + /* decide which 2d plane to project onto */ + { + VECTORCH absNormal = (polyPtr->PolyNormal); + if (absNormal.vx<0) absNormal.vx=-absNormal.vx; + if (absNormal.vy<0) absNormal.vy=-absNormal.vy; + if (absNormal.vz<0) absNormal.vz=-absNormal.vz; + + if (absNormal.vx > absNormal.vy) + { + if (absNormal.vx > absNormal.vz) + { + axis1=iy; + axis2=iz; + } + else + { + axis1=ix; + axis2=iy; + } + } + else + { + if (absNormal.vy > absNormal.vz) + { + axis1=ix; + axis2=iz; + } + else + { + axis1=ix; + axis2=iy; + } + } + } + + + { + int projectedPolyVertex[20]; + int projectedPointOnPlane[2]; + + projectedPointOnPlane[0]=*((int*)&alpha+axis1) + MUL_FIXED(lambda,*((int*)&beta+axis1)); + projectedPointOnPlane[1]=*((int*)&alpha+axis2) + MUL_FIXED(lambda,*((int*)&beta+axis2)); + + { + VECTORCH *vertexPtr = &vertices[0]; + int *projectedVertexPtr= &projectedPolyVertex[0]; + int noOfVertices = polyPtr->NumberOfVertices; + + do + { + *projectedVertexPtr++ = *((int*)vertexPtr + axis1); + *projectedVertexPtr++ = *((int*)vertexPtr + axis2); + + vertexPtr++; + } + while(--noOfVertices); + + } + + + if (PointInPolygon(&projectedPointOnPlane[0],&projectedPolyVertex[0],polyPtr->NumberOfVertices,2)) + return 1; + } + } + } + /* after all that we can be sure that the polygon isn't intersecting the object */ + return 0; +} + + +static int WhichNRBBVertex(DYNAMICSBLOCK *dynPtr, VECTORCH *normalPtr) +{ + VECTORCH dir; + + dir.vx = -normalPtr->vx; + dir.vy = -normalPtr->vy; + dir.vz = -normalPtr->vz; + + if (dir.vx>=0) + { + if (dir.vy>=0) + { + if (dir.vz>=0) + { + /* +ve x +ve y +ve z */ + return 0; + } + else + { + /* +ve x +ve y -ve z */ + return 1; + } + } + else + { + if (dir.vz>=0) + { + /* +ve x -ve y +ve z */ + return 2; + } + else + { + /* +ve x -ve y -ve z */ + return 3; + } + } + } + else + { + if (dir.vy>=0) + { + if (dir.vz>=0) + { + /* -ve x +ve y +ve z */ + return 4; + } + else + { + /* -ve x +ve y -ve z */ + return 5; + } + } + else + { + if (dir.vz>=0) + { + /* -ve x -ve y +ve z */ + return 6; + } + else + { + /* -ve x -ve y -ve z */ + return 7; + } + } + } +} + + + + + + + +static signed int DistanceMovedBeforeSphereHitsPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove) +{ + int dottedNormals; + int sphereToPolyDist; + + LOCALASSERT(polyPtr); + + dottedNormals = -DotProduct(&DirectionOfTravel,&(polyPtr->PolyNormal)); + + /* reject if polygon does not face against direction of sphere's travel */ + if (dottedNormals<=0) + { + return -1; + } + + /* calculate distance each vertex is from poly's plane along direction of motion */ + { + VECTORCH sphereToPoly; + + sphereToPoly.vx = dynPtr->Position.vx - polyPtr->PolyPoint[0].vx; + sphereToPoly.vy = dynPtr->Position.vy - polyPtr->PolyPoint[0].vy; + sphereToPoly.vz = dynPtr->Position.vz - polyPtr->PolyPoint[0].vz; + + sphereToPolyDist = DotProduct(&sphereToPoly,&(polyPtr->PolyNormal))-dynPtr->CollisionRadius; + } + /* reject if polygon is 'behind' sphere */ + if (sphereToPolyDist<0) + { + #if 0 + if (sphereToPolyDist>-dynPtr->CollisionRadius) + { + VECTORCH projectedPosition; + + projectedPosition.vx = dynPtr->Position.vx + MUL_FIXED(sphereToPolyDist,polyPtr->PolyNormal.vx); + projectedPosition.vy = dynPtr->Position.vy + MUL_FIXED(sphereToPolyDist,polyPtr->PolyNormal.vy); + projectedPosition.vz = dynPtr->Position.vz + MUL_FIXED(sphereToPolyDist,polyPtr->PolyNormal.vz); + + if (DoesSphereProjectOntoPoly(dynPtr, polyPtr, &projectedPosition)) + { + textprint("RELOCATION CASE\n"); + } + } + #endif + return -2; + } + + /* calculate distance along direction of travel */ + + sphereToPolyDist = DIV_FIXED(sphereToPolyDist,dottedNormals); + + if (sphereToPolyDist>=distanceToMove) + { + return -4; + } + + /* test if sphere's projected path intersect polygon */ + { + VECTORCH projectedPosition; + projectedPosition.vx = dynPtr->Position.vx + MUL_FIXED(DirectionOfTravel.vx, sphereToPolyDist) - MUL_FIXED(dynPtr->CollisionRadius,polyPtr->PolyNormal.vx); + projectedPosition.vy = dynPtr->Position.vy + MUL_FIXED(DirectionOfTravel.vy, sphereToPolyDist) - MUL_FIXED(dynPtr->CollisionRadius,polyPtr->PolyNormal.vy); + projectedPosition.vz = dynPtr->Position.vz + MUL_FIXED(DirectionOfTravel.vz, sphereToPolyDist) - MUL_FIXED(dynPtr->CollisionRadius,polyPtr->PolyNormal.vz); + + + if (SphereProjectOntoPoly(dynPtr, polyPtr, &projectedPosition)) + { + return sphereToPolyDist; + } + } + /* polygon not in way of sphere */ + return -5; +} + + +static int SphereProjectOntoPoly(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, VECTORCH *projectedPosition) +{ + /* decide which 2d plane to project onto */ + int axisToIgnore = AxisToIgnore(&polyPtr->PolyNormal); + + if (axisToIgnore!=ix) + { + int polyMax,polyMin; + + /* search x-coords of poly vertices for min and max */ + { + int vertexNum=polyPtr->NumberOfVertices; + + polyMax = polyMin = polyPtr->PolyPoint[0].vx; + do + { + int x; + vertexNum--; + x = polyPtr->PolyPoint[vertexNum].vx; + if (x > polyMax) polyMax = x; + else if (x < polyMin) polyMin = x; + } + while(vertexNum); + } + + /* test to see if object & polygon overlap */ + if (projectedPosition->vx+dynPtr->CollisionRadius < polyMin || projectedPosition->vx-dynPtr->CollisionRadius > polyMax) + return 0; + } + if (axisToIgnore!=iz) + { + int polyMax,polyMin; + + /* search z-coords of poly vertices for min and max */ + { + int vertexNum=polyPtr->NumberOfVertices; + + polyMax = polyMin = polyPtr->PolyPoint[0].vz; + do + { + int z; + vertexNum--; + z = polyPtr->PolyPoint[vertexNum].vz; + if (z > polyMax) polyMax = z; + else if (z < polyMin) polyMin = z; + } + while(vertexNum); + } + + /* test to see if object & polygon overlap */ + if (projectedPosition->vz+dynPtr->CollisionRadius < polyMin || projectedPosition->vz-dynPtr->CollisionRadius > polyMax) + return 0; + } + if (axisToIgnore!=iy) + { + int polyMax,polyMin; + + /* search y-coords of poly vertices for min and max */ + { + int vertexNum=polyPtr->NumberOfVertices; + + polyMax = polyMin = polyPtr->PolyPoint[0].vy; + do + { + int y; + vertexNum--; + + y = polyPtr->PolyPoint[vertexNum].vy; + if (y > polyMax) polyMax = y; + else if (y < polyMin) polyMin = y; + } + while(vertexNum); + } + + /* test to see if object & polygon overlap */ + if (projectedPosition->vy+dynPtr->CollisionRadius < polyMin || projectedPosition->vy-dynPtr->CollisionRadius > polyMax) + return 0; + + #if 1 + /* test for a 'step' in front of object */ + { + int heightOfStep = projectedPosition->vy+dynPtr->CollisionRadius - polyMin; /* y-axis is +ve downwards, remember */ + if (heightOfStep < MAXIMUM_STEP_HEIGHT) /* we've hit a 'step' - move player upwards */ + { + DistanceToStepUp=heightOfStep+COLLISION_GRANULARITY; + LOCALASSERT(heightOfStep>0); + } + } + #endif + } + + + return 1; +} + + +static signed int DistanceMovedBeforeNRBBHitsPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove) +{ + VECTORCH polyNormal; + int dottedNormals; + int obstacleDistance= 0x7fffffff; + int vertexToPlaneDist[8]; + + LOCALASSERT(polyPtr); + + polyNormal = polyPtr->PolyNormal; + + #if 0 + if (polyNormal.vy<=-65500) + return DistanceMovedBeforeNRBBHitsNegYPolygon(dynPtr, polyPtr, distanceToMove); + else if (polyNormal.vy>=65500) + return DistanceMovedBeforeNRBBHitsPosYPolygon(dynPtr, polyPtr, distanceToMove); + else if (polyNormal.vx>=65500) + return DistanceMovedBeforeNRBBHitsPosXPolygon(dynPtr, polyPtr, distanceToMove); + else if (polyNormal.vx<=-65500) + return DistanceMovedBeforeNRBBHitsNegXPolygon(dynPtr, polyPtr, distanceToMove); + else if (polyNormal.vz>=65500) + return DistanceMovedBeforeNRBBHitsPosZPolygon(dynPtr, polyPtr, distanceToMove); + else if (polyNormal.vz<=-65500) + return DistanceMovedBeforeNRBBHitsNegZPolygon(dynPtr, polyPtr, distanceToMove); + #endif + + dottedNormals = -DotProduct(&DirectionOfTravel,&polyNormal); + if (dottedNormals<=0) return -1; /* reject poly */ + + /* calculate distance each vertex is from poly's plane along direction of motion */ + { + VECTORCH polyPoint = polyPtr->PolyPoint[0]; + int originToPlaneDist = DotProduct(&polyPoint,&polyNormal); + + { + int vertexNum=8; + do + { + vertexNum--; + + vertexToPlaneDist[vertexNum] = + DotProduct(&dynPtr->ObjectVertices[vertexNum],&polyNormal) - originToPlaneDist; + + if (vertexToPlaneDist[vertexNum] < 0) return -1; + } + while(vertexNum); + } + + + { + int vertexNum=8; + int *distancePtr = vertexToPlaneDist; + do + { + *distancePtr = DIV_FIXED(*distancePtr,dottedNormals); + + if(*distancePtr < obstacleDistance) + obstacleDistance = *distancePtr; + + distancePtr++; + } + while(--vertexNum); + + } + } + if (obstacleDistance>=distanceToMove) + return -2; + + /* test if any vertices projected paths intersect polygons */ + if (NRBBProjectsOntoPolygon(dynPtr,vertexToPlaneDist,polyPtr,&DirectionOfTravel)) + { + return obstacleDistance; + } + + return -3; +} +#if 0 +static signed int DistanceMovedBeforeNRBBHitsNegYPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove) +{ + int dottedNormals; + int obstacleDistance= 0x7fffffff; + int vertexToPlaneDist[8]; + + LOCALASSERT(polyPtr); + + dottedNormals = DirectionOfTravel.vy; + if (dottedNormals<=0) return -1; /* reject poly */ + + /* calculate distance each vertex is from poly's plane along direction of motion */ + { + int originToPlaneDist = -polyPtr->PolyPoint[0].vy; + + { + int vertexNum=8; + do + { + vertexNum--; + + vertexToPlaneDist[vertexNum] = -dynPtr->ObjectVertices[vertexNum].vy - originToPlaneDist; + + if (vertexToPlaneDist[vertexNum] < 0) + { + return -1; + } + } + while(vertexNum); + } + + + { + int vertexNum=8; + int *distancePtr = vertexToPlaneDist; + do + { + *distancePtr = DIV_FIXED(*distancePtr,dottedNormals); + + if(*distancePtr < obstacleDistance) + obstacleDistance = *distancePtr; + + distancePtr++; + } + while(--vertexNum); + + } + } + if (obstacleDistance>=distanceToMove) + return -2; + + /* test if any vertices projected paths intersect polygons */ + if (NRBBProjectsOntoPolygon(dynPtr,vertexToPlaneDist,polyPtr,&DirectionOfTravel)) + { + return obstacleDistance; + } + + return -3; +} + +static signed int DistanceMovedBeforeNRBBHitsPosYPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove) +{ + int dottedNormals; + int obstacleDistance= 0x7fffffff; + int vertexToPlaneDist[8]; + + LOCALASSERT(polyPtr); + + dottedNormals = -DirectionOfTravel.vy; + if (dottedNormals<=0) return -1; /* reject poly */ + + /* calculate distance each vertex is from poly's plane along direction of motion */ + { + int originToPlaneDist = polyPtr->PolyPoint[0].vy; + + { + int vertexNum=8; + do + { + vertexNum--; + + vertexToPlaneDist[vertexNum] = dynPtr->ObjectVertices[vertexNum].vy - originToPlaneDist; + + if (vertexToPlaneDist[vertexNum] < 0) + { + return -1; + } + } + while(vertexNum); + } + + { + int vertexNum=8; + int *distancePtr = vertexToPlaneDist; + do + { + *distancePtr = DIV_FIXED(*distancePtr,dottedNormals); + + if(*distancePtr < obstacleDistance) + obstacleDistance = *distancePtr; + + distancePtr++; + } + while(--vertexNum); + + } + } + if (obstacleDistance>=distanceToMove) + return -2; + + /* test if any vertices projected paths intersect polygons */ + if (NRBBProjectsOntoPolygon(dynPtr,vertexToPlaneDist,polyPtr,&DirectionOfTravel)) + { + return obstacleDistance; + } + + return -3; +} +static signed int DistanceMovedBeforeNRBBHitsPosXPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove) +{ + int dottedNormals; + int obstacleDistance= 0x7fffffff; + int vertexToPlaneDist[8]; + + LOCALASSERT(polyPtr); + + dottedNormals = -DirectionOfTravel.vx; + if (dottedNormals<=0) return -1; /* reject poly */ + + /* calculate distance each vertex is from poly's plane along direction of motion */ + { + int originToPlaneDist = polyPtr->PolyPoint[0].vx; + + { + int vertexNum=8; + do + { + vertexNum--; + + vertexToPlaneDist[vertexNum] = dynPtr->ObjectVertices[vertexNum].vx - originToPlaneDist; + + if (vertexToPlaneDist[vertexNum] < 0) return -1; + } + while(vertexNum); + } + + + { + int vertexNum=8; + int *distancePtr = vertexToPlaneDist; + do + { + *distancePtr = DIV_FIXED(*distancePtr,dottedNormals); + + if(*distancePtr < obstacleDistance) + obstacleDistance = *distancePtr; + + distancePtr++; + } + while(--vertexNum); + + } + } + if (obstacleDistance>=distanceToMove) + return -2; + + /* test if any vertices projected paths intersect polygons */ + if (NRBBProjectsOntoPolygon(dynPtr,vertexToPlaneDist,polyPtr,&DirectionOfTravel)) + { + return obstacleDistance; + } + + return -3; +} +static signed int DistanceMovedBeforeNRBBHitsNegXPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove) +{ + int dottedNormals; + int obstacleDistance= 0x7fffffff; + int vertexToPlaneDist[8]; + + LOCALASSERT(polyPtr); + + dottedNormals = DirectionOfTravel.vx; + if (dottedNormals<=0) return -1; /* reject poly */ + + /* calculate distance each vertex is from poly's plane along direction of motion */ + { + int originToPlaneDist = -polyPtr->PolyPoint[0].vx; + + { + int vertexNum=8; + do + { + vertexNum--; + + vertexToPlaneDist[vertexNum] = -dynPtr->ObjectVertices[vertexNum].vx - originToPlaneDist; + + if (vertexToPlaneDist[vertexNum] < 0) return -1; + } + while(vertexNum); + } + + { + int vertexNum=8; + int *distancePtr = vertexToPlaneDist; + do + { + *distancePtr = DIV_FIXED(*distancePtr,dottedNormals); + + if(*distancePtr < obstacleDistance) + obstacleDistance = *distancePtr; + + distancePtr++; + } + while(--vertexNum); + + } + } + if (obstacleDistance>=distanceToMove) + return -2; + + /* test if any vertices projected paths intersect polygons */ + if (NRBBProjectsOntoPolygon(dynPtr,vertexToPlaneDist,polyPtr,&DirectionOfTravel)) + { + return obstacleDistance; + } + + return -3; +} +static signed int DistanceMovedBeforeNRBBHitsPosZPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove) +{ + int dottedNormals; + int obstacleDistance= 0x7fffffff; + int vertexToPlaneDist[8]; + + LOCALASSERT(polyPtr); + + dottedNormals = -DirectionOfTravel.vz; + if (dottedNormals<=0) return -1; /* reject poly */ + + /* calculate distance each vertex is from poly's plane along direction of motion */ + { + int originToPlaneDist = polyPtr->PolyPoint[0].vz; + + { + int vertexNum=8; + do + { + vertexNum--; + + vertexToPlaneDist[vertexNum] = dynPtr->ObjectVertices[vertexNum].vz - originToPlaneDist; + + if (vertexToPlaneDist[vertexNum] < 0) return -1; + } + while(vertexNum); + } + + { + int vertexNum=8; + int *distancePtr = vertexToPlaneDist; + do + { + *distancePtr = DIV_FIXED(*distancePtr,dottedNormals); + + if(*distancePtr < obstacleDistance) + obstacleDistance = *distancePtr; + + distancePtr++; + } + while(--vertexNum); + + } + } + if (obstacleDistance>=distanceToMove) + return -2; + + /* test if any vertices projected paths intersect polygons */ + if (NRBBProjectsOntoPolygon(dynPtr,vertexToPlaneDist,polyPtr,&DirectionOfTravel)) + { + return obstacleDistance; + } + + return -3; +} +static signed int DistanceMovedBeforeNRBBHitsNegZPolygon(DYNAMICSBLOCK *dynPtr, struct ColPolyTag *polyPtr, int distanceToMove) +{ + int dottedNormals; + int obstacleDistance= 0x7fffffff; + int vertexToPlaneDist[8]; + + LOCALASSERT(polyPtr); + + dottedNormals = DirectionOfTravel.vz; + if (dottedNormals<=0) return -1; /* reject poly */ + + /* calculate distance each vertex is from poly's plane along direction of motion */ + { + int originToPlaneDist = -polyPtr->PolyPoint[0].vz; + + { + int vertexNum=8; + do + { + vertexNum--; + + vertexToPlaneDist[vertexNum] = -dynPtr->ObjectVertices[vertexNum].vz - originToPlaneDist; + + if (vertexToPlaneDist[vertexNum] < 0) return -1; + } + while(vertexNum); + } + + + { + int vertexNum=8; + int *distancePtr = vertexToPlaneDist; + do + { + *distancePtr = DIV_FIXED(*distancePtr,dottedNormals); + + if(*distancePtr < obstacleDistance) + obstacleDistance = *distancePtr; + + distancePtr++; + } + while(--vertexNum); + + } + } + if (obstacleDistance>=distanceToMove) + return -2; + + /* test if any vertices projected paths intersect polygons */ + if (NRBBProjectsOntoPolygon(dynPtr,vertexToPlaneDist,polyPtr,&DirectionOfTravel)) + { + return obstacleDistance; + } + + return -3; +} +#endif +static int NRBBProjectsOntoPolygon(DYNAMICSBLOCK *dynPtr, int vertexToPlaneDist[], struct ColPolyTag *polyPtr, VECTORCH *projectionDirPtr) +{ + /* decide which 2d plane to project onto */ + int axisToIgnore = AxisToIgnore(&polyPtr->PolyNormal); + int objMaxX,objMinX,objMaxY,objMinY,objMaxZ,objMinZ; + + if (axisToIgnore!=ix) + { + int polyMax,polyMin; + + /* search x-coords of poly vertices for min and max */ + { + int vertexNum=polyPtr->NumberOfVertices; + + polyMax = polyMin = polyPtr->PolyPoint[0].vx; + do + { + int x; + vertexNum--; + x = polyPtr->PolyPoint[vertexNum].vx; + if (x > polyMax) polyMax = x; + else if (x < polyMin) polyMin = x; + } + while(vertexNum); + } + /* search x-coords of object vertices for min and max */ + { + int i=7; /* 8 vertices in a cuboid */ + + objMaxX = objMinX = dynPtr->ObjectVertices[0].vx + MUL_FIXED(vertexToPlaneDist[0],projectionDirPtr->vx); + do + { + int x; + x = dynPtr->ObjectVertices[i].vx + MUL_FIXED(vertexToPlaneDist[i],projectionDirPtr->vx); + if (x > objMaxX) objMaxX = x; + else if (x < objMinX) objMinX = x; + i--; + } + while(i); + } + + /* test to see if object & polygon overlap */ + if (objMaxX < polyMin || objMinX > polyMax) + return 0; + } + if (axisToIgnore!=iz) + { + int polyMax,polyMin; + + /* search z-coords of poly vertices for min and max */ + { + int vertexNum=polyPtr->NumberOfVertices; + + polyMax = polyMin = polyPtr->PolyPoint[0].vz; + do + { + int z; + vertexNum--; + z = polyPtr->PolyPoint[vertexNum].vz; + if (z > polyMax) polyMax = z; + else if (z < polyMin) polyMin = z; + } + while(vertexNum); + } + /* search z-coords of object vertices for min and max */ + { + int i=7; /* 8 vertices in a cuboid */ + + objMaxZ = objMinZ = dynPtr->ObjectVertices[0].vz + MUL_FIXED(vertexToPlaneDist[0],projectionDirPtr->vz); + do + { + int z; + z = dynPtr->ObjectVertices[i].vz + MUL_FIXED(vertexToPlaneDist[i],projectionDirPtr->vz); + if (z > objMaxZ) objMaxZ = z; + else if (z < objMinZ) objMinZ = z; + i--; + } + while(i); + } + + /* test to see if object & polygon overlap */ + if (objMaxZ < polyMin || objMinZ > polyMax) + return 0; + } + if (axisToIgnore!=iy) + { + int polyMax,polyMin; + + /* search y-coords of poly vertices for min and max */ + { + int vertexNum=polyPtr->NumberOfVertices; + + polyMax = polyMin = polyPtr->PolyPoint[0].vy; + do + { + int y; + vertexNum--; + + y = polyPtr->PolyPoint[vertexNum].vy; + if (y > polyMax) polyMax = y; + else if (y < polyMin) polyMin = y; + } + while(vertexNum); + } + /* search y-coords of object vertices for min and max */ + { + int i=7; /* 8 vertices in a cuboid */ + + objMaxY = objMinY = dynPtr->ObjectVertices[0].vy + MUL_FIXED(vertexToPlaneDist[0],projectionDirPtr->vy); + do + { + int y; + + y = dynPtr->ObjectVertices[i].vy + MUL_FIXED(vertexToPlaneDist[i],projectionDirPtr->vy); + if (y > objMaxY) objMaxY = y; + else if (y < objMinY) objMinY = y; + i--; + } + while(i); + } + + /* test to see if object & polygon overlap */ + if (objMaxY < polyMin || objMinY > polyMax) + return 0; + + } + + /* test for triangle/rectangle overlap */ + /* traingle vertices are stored anticlockwise! */ + if (polyPtr->NumberOfVertices == 3) + { + if(axisToIgnore==ix) + { + VECTORCH n; + + n.vy = (polyPtr->PolyPoint[1].vz-polyPtr->PolyPoint[0].vz); + n.vz = -(polyPtr->PolyPoint[1].vy-polyPtr->PolyPoint[0].vy); + if(polyPtr->PolyNormal.vx<0) + { + n.vy = -n.vy; + n.vz = -n.vz; + } + { + int d1,d2,d3,d4; + d1 = (objMaxY-polyPtr->PolyPoint[0].vy)*n.vy + (objMaxZ-polyPtr->PolyPoint[0].vz)*n.vz; + d2 = (objMaxY-polyPtr->PolyPoint[0].vy)*n.vy + (objMinZ-polyPtr->PolyPoint[0].vz)*n.vz; + d3 = (objMinY-polyPtr->PolyPoint[0].vy)*n.vy + (objMaxZ-polyPtr->PolyPoint[0].vz)*n.vz; + d4 = (objMinY-polyPtr->PolyPoint[0].vy)*n.vy + (objMinZ-polyPtr->PolyPoint[0].vz)*n.vz; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + n.vy = (polyPtr->PolyPoint[2].vz-polyPtr->PolyPoint[1].vz); + n.vz = -(polyPtr->PolyPoint[2].vy-polyPtr->PolyPoint[1].vy); + if(polyPtr->PolyNormal.vx<0) + { + n.vy = -n.vy; + n.vz = -n.vz; + } + { + int d1,d2,d3,d4; + d1 = (objMaxY-polyPtr->PolyPoint[1].vy)*n.vy + (objMaxZ-polyPtr->PolyPoint[1].vz)*n.vz; + d2 = (objMaxY-polyPtr->PolyPoint[1].vy)*n.vy + (objMinZ-polyPtr->PolyPoint[1].vz)*n.vz; + d3 = (objMinY-polyPtr->PolyPoint[1].vy)*n.vy + (objMaxZ-polyPtr->PolyPoint[1].vz)*n.vz; + d4 = (objMinY-polyPtr->PolyPoint[1].vy)*n.vy + (objMinZ-polyPtr->PolyPoint[1].vz)*n.vz; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + n.vy = (polyPtr->PolyPoint[0].vz-polyPtr->PolyPoint[2].vz); + n.vz = -(polyPtr->PolyPoint[0].vy-polyPtr->PolyPoint[2].vy); + if(polyPtr->PolyNormal.vx<0) + { + n.vy = -n.vy; + n.vz = -n.vz; + } + { + int d1,d2,d3,d4; + d1 = (objMaxY-polyPtr->PolyPoint[2].vy)*n.vy + (objMaxZ-polyPtr->PolyPoint[2].vz)*n.vz; + d2 = (objMaxY-polyPtr->PolyPoint[2].vy)*n.vy + (objMinZ-polyPtr->PolyPoint[2].vz)*n.vz; + d3 = (objMinY-polyPtr->PolyPoint[2].vy)*n.vy + (objMaxZ-polyPtr->PolyPoint[2].vz)*n.vz; + d4 = (objMinY-polyPtr->PolyPoint[2].vy)*n.vy + (objMinZ-polyPtr->PolyPoint[2].vz)*n.vz; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + } + else if(axisToIgnore==iy) + { + VECTORCH n; + + n.vx = (polyPtr->PolyPoint[1].vz-polyPtr->PolyPoint[0].vz); + n.vz = -(polyPtr->PolyPoint[1].vx-polyPtr->PolyPoint[0].vx); + if(polyPtr->PolyNormal.vy>0) + { + n.vx = -n.vx; + n.vz = -n.vz; + } + { + int d1,d2,d3,d4; + d1 = (objMaxX-polyPtr->PolyPoint[0].vx)*n.vx + (objMaxZ-polyPtr->PolyPoint[0].vz)*n.vz; + d2 = (objMaxX-polyPtr->PolyPoint[0].vx)*n.vx + (objMinZ-polyPtr->PolyPoint[0].vz)*n.vz; + d3 = (objMinX-polyPtr->PolyPoint[0].vx)*n.vx + (objMaxZ-polyPtr->PolyPoint[0].vz)*n.vz; + d4 = (objMinX-polyPtr->PolyPoint[0].vx)*n.vx + (objMinZ-polyPtr->PolyPoint[0].vz)*n.vz; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + n.vx = (polyPtr->PolyPoint[2].vz-polyPtr->PolyPoint[1].vz); + n.vz = -(polyPtr->PolyPoint[2].vx-polyPtr->PolyPoint[1].vx); + if(polyPtr->PolyNormal.vy>0) + { + n.vx = -n.vx; + n.vz = -n.vz; + } + { + int d1,d2,d3,d4; + d1 = (objMaxX-polyPtr->PolyPoint[1].vx)*n.vx + (objMaxZ-polyPtr->PolyPoint[1].vz)*n.vz; + d2 = (objMaxX-polyPtr->PolyPoint[1].vx)*n.vx + (objMinZ-polyPtr->PolyPoint[1].vz)*n.vz; + d3 = (objMinX-polyPtr->PolyPoint[1].vx)*n.vx + (objMaxZ-polyPtr->PolyPoint[1].vz)*n.vz; + d4 = (objMinX-polyPtr->PolyPoint[1].vx)*n.vx + (objMinZ-polyPtr->PolyPoint[1].vz)*n.vz; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + n.vx = (polyPtr->PolyPoint[0].vz-polyPtr->PolyPoint[2].vz); + n.vz = -(polyPtr->PolyPoint[0].vx-polyPtr->PolyPoint[2].vx); + if(polyPtr->PolyNormal.vy>0) + { + n.vx = -n.vx; + n.vz = -n.vz; + } + { + int d1,d2,d3,d4; + d1 = (objMaxX-polyPtr->PolyPoint[2].vx)*n.vx + (objMaxZ-polyPtr->PolyPoint[2].vz)*n.vz; + d2 = (objMaxX-polyPtr->PolyPoint[2].vx)*n.vx + (objMinZ-polyPtr->PolyPoint[2].vz)*n.vz; + d3 = (objMinX-polyPtr->PolyPoint[2].vx)*n.vx + (objMaxZ-polyPtr->PolyPoint[2].vz)*n.vz; + d4 = (objMinX-polyPtr->PolyPoint[2].vx)*n.vx + (objMinZ-polyPtr->PolyPoint[2].vz)*n.vz; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + } + else if(axisToIgnore==iz) + { + VECTORCH n; + + n.vx = (polyPtr->PolyPoint[1].vy-polyPtr->PolyPoint[0].vy); + n.vy = -(polyPtr->PolyPoint[1].vx-polyPtr->PolyPoint[0].vx); + if(polyPtr->PolyNormal.vz<0) + { + n.vx = -n.vx; + n.vy = -n.vy; + } + { + int d1,d2,d3,d4; + d1 = (objMaxX-polyPtr->PolyPoint[0].vx)*n.vx + (objMaxY-polyPtr->PolyPoint[0].vy)*n.vy; + d2 = (objMaxX-polyPtr->PolyPoint[0].vx)*n.vx + (objMinY-polyPtr->PolyPoint[0].vy)*n.vy; + d3 = (objMinX-polyPtr->PolyPoint[0].vx)*n.vx + (objMaxY-polyPtr->PolyPoint[0].vy)*n.vy; + d4 = (objMinX-polyPtr->PolyPoint[0].vx)*n.vx + (objMinY-polyPtr->PolyPoint[0].vy)*n.vy; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + n.vx = (polyPtr->PolyPoint[2].vy-polyPtr->PolyPoint[1].vy); + n.vy = -(polyPtr->PolyPoint[2].vx-polyPtr->PolyPoint[1].vx); + if(polyPtr->PolyNormal.vz<0) + { + n.vx = -n.vx; + n.vy = -n.vy; + } + { + int d1,d2,d3,d4; + d1 = (objMaxX-polyPtr->PolyPoint[1].vx)*n.vx + (objMaxY-polyPtr->PolyPoint[1].vy)*n.vy; + d2 = (objMaxX-polyPtr->PolyPoint[1].vx)*n.vx + (objMinY-polyPtr->PolyPoint[1].vy)*n.vy; + d3 = (objMinX-polyPtr->PolyPoint[1].vx)*n.vx + (objMaxY-polyPtr->PolyPoint[1].vy)*n.vy; + d4 = (objMinX-polyPtr->PolyPoint[1].vx)*n.vx + (objMinY-polyPtr->PolyPoint[1].vy)*n.vy; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + n.vx = (polyPtr->PolyPoint[0].vy-polyPtr->PolyPoint[2].vy); + n.vy = -(polyPtr->PolyPoint[0].vx-polyPtr->PolyPoint[2].vx); + if(polyPtr->PolyNormal.vz<0) + { + n.vx = -n.vx; + n.vy = -n.vy; + } + { + int d1,d2,d3,d4; + d1 = (objMaxX-polyPtr->PolyPoint[2].vx)*n.vx + (objMaxY-polyPtr->PolyPoint[2].vy)*n.vy; + d2 = (objMaxX-polyPtr->PolyPoint[2].vx)*n.vx + (objMinY-polyPtr->PolyPoint[2].vy)*n.vy; + d3 = (objMinX-polyPtr->PolyPoint[2].vx)*n.vx + (objMaxY-polyPtr->PolyPoint[2].vy)*n.vy; + d4 = (objMinX-polyPtr->PolyPoint[2].vx)*n.vx + (objMinY-polyPtr->PolyPoint[2].vy)*n.vy; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + } + } + else + { + if(axisToIgnore==ix) + { + VECTORCH n; + + n.vy = (polyPtr->PolyPoint[1].vz-polyPtr->PolyPoint[0].vz); + n.vz = -(polyPtr->PolyPoint[1].vy-polyPtr->PolyPoint[0].vy); + if(polyPtr->PolyNormal.vx<0) + { + n.vy = -n.vy; + n.vz = -n.vz; + } + { + int d1,d2,d3,d4; + d1 = (objMaxY-polyPtr->PolyPoint[0].vy)*n.vy + (objMaxZ-polyPtr->PolyPoint[0].vz)*n.vz; + d2 = (objMaxY-polyPtr->PolyPoint[0].vy)*n.vy + (objMinZ-polyPtr->PolyPoint[0].vz)*n.vz; + d3 = (objMinY-polyPtr->PolyPoint[0].vy)*n.vy + (objMaxZ-polyPtr->PolyPoint[0].vz)*n.vz; + d4 = (objMinY-polyPtr->PolyPoint[0].vy)*n.vy + (objMinZ-polyPtr->PolyPoint[0].vz)*n.vz; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + n.vy = (polyPtr->PolyPoint[2].vz-polyPtr->PolyPoint[1].vz); + n.vz = -(polyPtr->PolyPoint[2].vy-polyPtr->PolyPoint[1].vy); + if(polyPtr->PolyNormal.vx<0) + { + n.vy = -n.vy; + n.vz = -n.vz; + } + { + int d1,d2,d3,d4; + d1 = (objMaxY-polyPtr->PolyPoint[1].vy)*n.vy + (objMaxZ-polyPtr->PolyPoint[1].vz)*n.vz; + d2 = (objMaxY-polyPtr->PolyPoint[1].vy)*n.vy + (objMinZ-polyPtr->PolyPoint[1].vz)*n.vz; + d3 = (objMinY-polyPtr->PolyPoint[1].vy)*n.vy + (objMaxZ-polyPtr->PolyPoint[1].vz)*n.vz; + d4 = (objMinY-polyPtr->PolyPoint[1].vy)*n.vy + (objMinZ-polyPtr->PolyPoint[1].vz)*n.vz; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + n.vy = (polyPtr->PolyPoint[3].vz-polyPtr->PolyPoint[2].vz); + n.vz = -(polyPtr->PolyPoint[3].vy-polyPtr->PolyPoint[2].vy); + if(polyPtr->PolyNormal.vx<0) + { + n.vy = -n.vy; + n.vz = -n.vz; + } + { + int d1,d2,d3,d4; + d1 = (objMaxY-polyPtr->PolyPoint[2].vy)*n.vy + (objMaxZ-polyPtr->PolyPoint[2].vz)*n.vz; + d2 = (objMaxY-polyPtr->PolyPoint[2].vy)*n.vy + (objMinZ-polyPtr->PolyPoint[2].vz)*n.vz; + d3 = (objMinY-polyPtr->PolyPoint[2].vy)*n.vy + (objMaxZ-polyPtr->PolyPoint[2].vz)*n.vz; + d4 = (objMinY-polyPtr->PolyPoint[2].vy)*n.vy + (objMinZ-polyPtr->PolyPoint[2].vz)*n.vz; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + n.vy = (polyPtr->PolyPoint[0].vz-polyPtr->PolyPoint[3].vz); + n.vz = -(polyPtr->PolyPoint[0].vy-polyPtr->PolyPoint[3].vy); + if(polyPtr->PolyNormal.vx<0) + { + n.vy = -n.vy; + n.vz = -n.vz; + } + { + int d1,d2,d3,d4; + d1 = (objMaxY-polyPtr->PolyPoint[3].vy)*n.vy + (objMaxZ-polyPtr->PolyPoint[3].vz)*n.vz; + d2 = (objMaxY-polyPtr->PolyPoint[3].vy)*n.vy + (objMinZ-polyPtr->PolyPoint[3].vz)*n.vz; + d3 = (objMinY-polyPtr->PolyPoint[3].vy)*n.vy + (objMaxZ-polyPtr->PolyPoint[3].vz)*n.vz; + d4 = (objMinY-polyPtr->PolyPoint[3].vy)*n.vy + (objMinZ-polyPtr->PolyPoint[3].vz)*n.vz; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + } + else if(axisToIgnore==iy) + { + VECTORCH n; + + n.vx = (polyPtr->PolyPoint[1].vz-polyPtr->PolyPoint[0].vz); + n.vz = -(polyPtr->PolyPoint[1].vx-polyPtr->PolyPoint[0].vx); + if(polyPtr->PolyNormal.vy>0) + { + n.vx = -n.vx; + n.vz = -n.vz; + } + { + int d1,d2,d3,d4; + d1 = (objMaxX-polyPtr->PolyPoint[0].vx)*n.vx + (objMaxZ-polyPtr->PolyPoint[0].vz)*n.vz; + d2 = (objMaxX-polyPtr->PolyPoint[0].vx)*n.vx + (objMinZ-polyPtr->PolyPoint[0].vz)*n.vz; + d3 = (objMinX-polyPtr->PolyPoint[0].vx)*n.vx + (objMaxZ-polyPtr->PolyPoint[0].vz)*n.vz; + d4 = (objMinX-polyPtr->PolyPoint[0].vx)*n.vx + (objMinZ-polyPtr->PolyPoint[0].vz)*n.vz; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + n.vx = (polyPtr->PolyPoint[2].vz-polyPtr->PolyPoint[1].vz); + n.vz = -(polyPtr->PolyPoint[2].vx-polyPtr->PolyPoint[1].vx); + if(polyPtr->PolyNormal.vy>0) + { + n.vx = -n.vx; + n.vz = -n.vz; + } + { + int d1,d2,d3,d4; + d1 = (objMaxX-polyPtr->PolyPoint[1].vx)*n.vx + (objMaxZ-polyPtr->PolyPoint[1].vz)*n.vz; + d2 = (objMaxX-polyPtr->PolyPoint[1].vx)*n.vx + (objMinZ-polyPtr->PolyPoint[1].vz)*n.vz; + d3 = (objMinX-polyPtr->PolyPoint[1].vx)*n.vx + (objMaxZ-polyPtr->PolyPoint[1].vz)*n.vz; + d4 = (objMinX-polyPtr->PolyPoint[1].vx)*n.vx + (objMinZ-polyPtr->PolyPoint[1].vz)*n.vz; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + n.vx = (polyPtr->PolyPoint[3].vz-polyPtr->PolyPoint[2].vz); + n.vz = -(polyPtr->PolyPoint[3].vx-polyPtr->PolyPoint[2].vx); + if(polyPtr->PolyNormal.vy>0) + { + n.vx = -n.vx; + n.vz = -n.vz; + } + { + int d1,d2,d3,d4; + d1 = (objMaxX-polyPtr->PolyPoint[2].vx)*n.vx + (objMaxZ-polyPtr->PolyPoint[2].vz)*n.vz; + d2 = (objMaxX-polyPtr->PolyPoint[2].vx)*n.vx + (objMinZ-polyPtr->PolyPoint[2].vz)*n.vz; + d3 = (objMinX-polyPtr->PolyPoint[2].vx)*n.vx + (objMaxZ-polyPtr->PolyPoint[2].vz)*n.vz; + d4 = (objMinX-polyPtr->PolyPoint[2].vx)*n.vx + (objMinZ-polyPtr->PolyPoint[2].vz)*n.vz; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + n.vx = (polyPtr->PolyPoint[0].vz-polyPtr->PolyPoint[3].vz); + n.vz = -(polyPtr->PolyPoint[0].vx-polyPtr->PolyPoint[3].vx); + if(polyPtr->PolyNormal.vy>0) + { + n.vx = -n.vx; + n.vz = -n.vz; + } + { + int d1,d2,d3,d4; + d1 = (objMaxX-polyPtr->PolyPoint[3].vx)*n.vx + (objMaxZ-polyPtr->PolyPoint[3].vz)*n.vz; + d2 = (objMaxX-polyPtr->PolyPoint[3].vx)*n.vx + (objMinZ-polyPtr->PolyPoint[3].vz)*n.vz; + d3 = (objMinX-polyPtr->PolyPoint[3].vx)*n.vx + (objMaxZ-polyPtr->PolyPoint[3].vz)*n.vz; + d4 = (objMinX-polyPtr->PolyPoint[3].vx)*n.vx + (objMinZ-polyPtr->PolyPoint[3].vz)*n.vz; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + } + else if(axisToIgnore==iz) + { + VECTORCH n; + + n.vx = (polyPtr->PolyPoint[1].vy-polyPtr->PolyPoint[0].vy); + n.vy = -(polyPtr->PolyPoint[1].vx-polyPtr->PolyPoint[0].vx); + if(polyPtr->PolyNormal.vz<0) + { + n.vx = -n.vx; + n.vy = -n.vy; + } + { + int d1,d2,d3,d4; + d1 = (objMaxX-polyPtr->PolyPoint[0].vx)*n.vx + (objMaxY-polyPtr->PolyPoint[0].vy)*n.vy; + d2 = (objMaxX-polyPtr->PolyPoint[0].vx)*n.vx + (objMinY-polyPtr->PolyPoint[0].vy)*n.vy; + d3 = (objMinX-polyPtr->PolyPoint[0].vx)*n.vx + (objMaxY-polyPtr->PolyPoint[0].vy)*n.vy; + d4 = (objMinX-polyPtr->PolyPoint[0].vx)*n.vx + (objMinY-polyPtr->PolyPoint[0].vy)*n.vy; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + n.vx = (polyPtr->PolyPoint[2].vy-polyPtr->PolyPoint[1].vy); + n.vy = -(polyPtr->PolyPoint[2].vx-polyPtr->PolyPoint[1].vx); + if(polyPtr->PolyNormal.vz<0) + { + n.vx = -n.vx; + n.vy = -n.vy; + } + { + int d1,d2,d3,d4; + d1 = (objMaxX-polyPtr->PolyPoint[1].vx)*n.vx + (objMaxY-polyPtr->PolyPoint[1].vy)*n.vy; + d2 = (objMaxX-polyPtr->PolyPoint[1].vx)*n.vx + (objMinY-polyPtr->PolyPoint[1].vy)*n.vy; + d3 = (objMinX-polyPtr->PolyPoint[1].vx)*n.vx + (objMaxY-polyPtr->PolyPoint[1].vy)*n.vy; + d4 = (objMinX-polyPtr->PolyPoint[1].vx)*n.vx + (objMinY-polyPtr->PolyPoint[1].vy)*n.vy; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + n.vx = (polyPtr->PolyPoint[3].vy-polyPtr->PolyPoint[2].vy); + n.vy = -(polyPtr->PolyPoint[3].vx-polyPtr->PolyPoint[2].vx); + if(polyPtr->PolyNormal.vz<0) + { + n.vx = -n.vx; + n.vy = -n.vy; + } + { + int d1,d2,d3,d4; + d1 = (objMaxX-polyPtr->PolyPoint[2].vx)*n.vx + (objMaxY-polyPtr->PolyPoint[2].vy)*n.vy; + d2 = (objMaxX-polyPtr->PolyPoint[2].vx)*n.vx + (objMinY-polyPtr->PolyPoint[2].vy)*n.vy; + d3 = (objMinX-polyPtr->PolyPoint[2].vx)*n.vx + (objMaxY-polyPtr->PolyPoint[2].vy)*n.vy; + d4 = (objMinX-polyPtr->PolyPoint[2].vx)*n.vx + (objMinY-polyPtr->PolyPoint[2].vy)*n.vy; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + + n.vx = (polyPtr->PolyPoint[0].vy-polyPtr->PolyPoint[3].vy); + n.vy = -(polyPtr->PolyPoint[0].vx-polyPtr->PolyPoint[3].vx); + if(polyPtr->PolyNormal.vz<0) + { + n.vx = -n.vx; + n.vy = -n.vy; + } + { + int d1,d2,d3,d4; + d1 = (objMaxX-polyPtr->PolyPoint[3].vx)*n.vx + (objMaxY-polyPtr->PolyPoint[3].vy)*n.vy; + d2 = (objMaxX-polyPtr->PolyPoint[3].vx)*n.vx + (objMinY-polyPtr->PolyPoint[3].vy)*n.vy; + d3 = (objMinX-polyPtr->PolyPoint[3].vx)*n.vx + (objMaxY-polyPtr->PolyPoint[3].vy)*n.vy; + d4 = (objMinX-polyPtr->PolyPoint[3].vx)*n.vx + (objMinY-polyPtr->PolyPoint[3].vy)*n.vy; + + if (d1>0 && d2>0 && d3>0 && d4>0) return 0; + } + } + } + return 1; +} + +static void CreateNRBBForObject(const STRATEGYBLOCK *sbPtr) +{ + VECTORCH *objectVertices = sbPtr->DynPtr->ObjectVertices; + COLLISION_EXTENTS *extentsPtr = 0; + int objectIsCrouching = 0; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + dynPtr->CollisionRadius = 0; + + + switch (sbPtr->I_SBtype) + { + case I_BehaviourMarinePlayer: + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); + + /* set player state */ + objectIsCrouching = (playerStatusPtr->ShapeState != PMph_Standing); + + switch(AvP.PlayerType) + { + case I_Marine: + extentsPtr = &CollisionExtents[CE_MARINE]; + dynPtr->CollisionRadius = extentsPtr->CollisionRadius; + break; + + case I_Alien: + extentsPtr = &CollisionExtents[CE_ALIEN]; + dynPtr->CollisionRadius = extentsPtr->CollisionRadius; + break; + + case I_Predator: + extentsPtr = &CollisionExtents[CE_PREDATOR]; + dynPtr->CollisionRadius = extentsPtr->CollisionRadius; + break; + } + break; + } + + case I_BehaviourAlien: + { + ALIEN_STATUS_BLOCK *alienStatusPtr = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr; + objectIsCrouching = alienStatusPtr->IAmCrouched; + + extentsPtr = &CollisionExtents[CE_ALIEN]; + dynPtr->CollisionRadius = extentsPtr->CollisionRadius; + sbPtr->SBdptr->ObRadius = 2000; + break; + } + case I_BehaviourPredator: + { + PREDATOR_STATUS_BLOCK *predatorStatusPtr = (PREDATOR_STATUS_BLOCK *)sbPtr->SBdataptr; + objectIsCrouching = predatorStatusPtr->IAmCrouched; + + sbPtr->SBdptr->ObRadius = 2000; + extentsPtr = &CollisionExtents[CE_PREDATOR]; +// dynPtr->CollisionRadius = extentsPtr->CollisionRadius; + break; + } + case I_BehaviourMarine: + { + MARINE_STATUS_BLOCK *marineStatusPtr = (MARINE_STATUS_BLOCK *)sbPtr->SBdataptr; + objectIsCrouching = marineStatusPtr->IAmCrouched; + + sbPtr->SBdptr->ObRadius = 2000; + extentsPtr = &CollisionExtents[CE_MARINE]; +// dynPtr->CollisionRadius = extentsPtr->CollisionRadius; + break; + } + case I_BehaviourFaceHugger: + { + extentsPtr = &CollisionExtents[CE_FACEHUGGER]; + dynPtr->CollisionRadius = extentsPtr->CollisionRadius; + break; + } + case I_BehaviourXenoborg: + { + extentsPtr = &CollisionExtents[CE_XENOBORG]; + break; + } + case I_BehaviourPredatorAlien: + { + extentsPtr = &CollisionExtents[CE_PREDATORALIEN]; + break; + } + + case I_BehaviourQueenAlien: + extentsPtr = &CollisionExtents[CE_QUEEN]; + break; + case I_BehaviourSeal: + extentsPtr = &CollisionExtents[CE_MARINE]; + break; + + case I_BehaviourNetCorpse: + extentsPtr = &CollisionExtents[CE_CORPSE]; + sbPtr->SBdptr->ObRadius = 700; + break; + + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *ghostData; + + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + switch(ghostData->type) + { + case I_BehaviourAlienPlayer: + { + extentsPtr = &CollisionExtents[CE_ALIEN]; + dynPtr->CollisionRadius = extentsPtr->CollisionRadius; + sbPtr->SBdptr->ObRadius = 700; + break; + } + case I_BehaviourPredatorPlayer: + { + extentsPtr = &CollisionExtents[CE_PREDATOR]; + sbPtr->SBdptr->ObRadius = 700; + break; + } + case I_BehaviourMarinePlayer: + { + extentsPtr = &CollisionExtents[CE_MARINE]; + sbPtr->SBdptr->ObRadius = 700; + break; + } + + case I_BehaviourAlien: + { + #if 0 + ALIEN_STATUS_BLOCK *alienStatusPtr = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr; + objectIsCrouching = alienStatusPtr->IAmCrouched; + #endif + extentsPtr = &CollisionExtents[CE_ALIEN]; + dynPtr->CollisionRadius = extentsPtr->CollisionRadius; + sbPtr->SBdptr->ObRadius = 2000; + break; + } + + case I_BehaviourNetCorpse: + extentsPtr = &CollisionExtents[CE_MARINE]; + sbPtr->SBdptr->ObRadius = 700; + break; + default: + break; + } + } + + default: + break; + } + + if (extentsPtr) + { + /* max X */ + objectVertices[0].vx = extentsPtr->CollisionRadius; + objectVertices[1].vx = extentsPtr->CollisionRadius; + objectVertices[2].vx = extentsPtr->CollisionRadius; + objectVertices[3].vx = extentsPtr->CollisionRadius; + + /* max Z */ + objectVertices[0].vz = extentsPtr->CollisionRadius; + objectVertices[2].vz = extentsPtr->CollisionRadius; + objectVertices[4].vz = extentsPtr->CollisionRadius; + objectVertices[6].vz = extentsPtr->CollisionRadius; + + /* min X */ + objectVertices[4].vx = -extentsPtr->CollisionRadius; + objectVertices[5].vx = -extentsPtr->CollisionRadius; + objectVertices[6].vx = -extentsPtr->CollisionRadius; + objectVertices[7].vx = -extentsPtr->CollisionRadius; + + /* min Z */ + objectVertices[1].vz = -extentsPtr->CollisionRadius; + objectVertices[3].vz = -extentsPtr->CollisionRadius; + objectVertices[5].vz = -extentsPtr->CollisionRadius; + objectVertices[7].vz = -extentsPtr->CollisionRadius; + + /* max Y */ + objectVertices[0].vy = extentsPtr->Bottom; + objectVertices[1].vy = extentsPtr->Bottom; + objectVertices[4].vy = extentsPtr->Bottom; + objectVertices[5].vy = extentsPtr->Bottom; + + /* min Y */ + if(objectIsCrouching) + { + objectVertices[2].vy = extentsPtr->CrouchingTop; + objectVertices[3].vy = extentsPtr->CrouchingTop; + objectVertices[6].vy = extentsPtr->CrouchingTop; + objectVertices[7].vy = extentsPtr->CrouchingTop; + } + else + { + objectVertices[2].vy = extentsPtr->StandingTop; + objectVertices[3].vy = extentsPtr->StandingTop; + objectVertices[6].vy = extentsPtr->StandingTop; + objectVertices[7].vy = extentsPtr->StandingTop; + } + } + else + /* make a cuboid from the shape's extent data */ + { + { + int shapeMaxX = sbPtr->SBdptr->ObMaxX; + if (shapeMaxX < MINIMUM_BOUNDINGBOX_EXTENT) shapeMaxX = MINIMUM_BOUNDINGBOX_EXTENT; + objectVertices[0].vx = shapeMaxX; + objectVertices[1].vx = shapeMaxX; + objectVertices[2].vx = shapeMaxX; + objectVertices[3].vx = shapeMaxX; + } + { + int shapeMinX = sbPtr->SBdptr->ObMinX; + if (shapeMinX > -MINIMUM_BOUNDINGBOX_EXTENT) shapeMinX = -MINIMUM_BOUNDINGBOX_EXTENT; + objectVertices[4].vx = shapeMinX; + objectVertices[5].vx = shapeMinX; + objectVertices[6].vx = shapeMinX; + objectVertices[7].vx = shapeMinX; + } + { + int shapeMaxY = sbPtr->SBdptr->ObMaxY; + if (shapeMaxY < MINIMUM_BOUNDINGBOX_EXTENT) shapeMaxY = MINIMUM_BOUNDINGBOX_EXTENT; + objectVertices[0].vy = shapeMaxY; + objectVertices[1].vy = shapeMaxY; + objectVertices[4].vy = shapeMaxY; + objectVertices[5].vy = shapeMaxY; + } + { + int shapeMinY = sbPtr->SBdptr->ObMinY; + if (shapeMinY > -MINIMUM_BOUNDINGBOX_EXTENT) shapeMinY = -MINIMUM_BOUNDINGBOX_EXTENT; + objectVertices[2].vy = shapeMinY; + objectVertices[3].vy = shapeMinY; + objectVertices[6].vy = shapeMinY; + objectVertices[7].vy = shapeMinY; + } + { + int shapeMaxZ = sbPtr->SBdptr->ObMaxZ; + if (shapeMaxZ < MINIMUM_BOUNDINGBOX_EXTENT) shapeMaxZ = MINIMUM_BOUNDINGBOX_EXTENT; + objectVertices[0].vz = shapeMaxZ; + objectVertices[2].vz = shapeMaxZ; + objectVertices[4].vz = shapeMaxZ; + objectVertices[6].vz = shapeMaxZ; + } + { + int shapeMinZ = sbPtr->SBdptr->ObMinZ; + if (shapeMinZ > -MINIMUM_BOUNDINGBOX_EXTENT) shapeMinZ = -MINIMUM_BOUNDINGBOX_EXTENT; + objectVertices[1].vz = shapeMinZ; + objectVertices[3].vz = shapeMinZ; + objectVertices[5].vz = shapeMinZ; + objectVertices[7].vz = shapeMinZ; + } + } + + /* translate cuboid into world space */ + { + VECTORCH *vertexPtr = objectVertices; + VECTORCH objectPosition = sbPtr->DynPtr->Position; + + int vertexNum=8; + do + { + vertexPtr->vx += objectPosition.vx; + vertexPtr->vy += objectPosition.vy; + vertexPtr->vz += objectPosition.vz; + vertexPtr++; + } + while(--vertexNum); + + } +} +static void CreateSphereBBForObject(const STRATEGYBLOCK *sbPtr) +{ + VECTORCH *objectVertices = sbPtr->DynPtr->ObjectVertices; + /* make a cuboid from the sphere's radius */ + { + int radius = sbPtr->DynPtr->CollisionRadius; + + objectVertices[0].vx = radius; + objectVertices[1].vx = radius; + objectVertices[2].vx = radius; + objectVertices[3].vx = radius; + objectVertices[0].vy = radius; + objectVertices[1].vy = radius; + objectVertices[4].vy = radius; + objectVertices[5].vy = radius; + objectVertices[0].vz = radius; + objectVertices[2].vz = radius; + objectVertices[4].vz = radius; + objectVertices[6].vz = radius; + + radius = -radius; + + objectVertices[4].vx = radius; + objectVertices[5].vx = radius; + objectVertices[6].vx = radius; + objectVertices[7].vx = radius; + objectVertices[2].vy = radius; + objectVertices[3].vy = radius; + objectVertices[6].vy = radius; + objectVertices[7].vy = radius; + objectVertices[1].vz = radius; + objectVertices[3].vz = radius; + objectVertices[5].vz = radius; + objectVertices[7].vz = radius; + } + + /* translate cuboid into world space */ + { + VECTORCH *vertexPtr = objectVertices; + VECTORCH objectPosition = sbPtr->DynPtr->Position; + + int vertexNum=8; + do + { + vertexPtr->vx += objectPosition.vx; + vertexPtr->vy += objectPosition.vy; + vertexPtr->vz += objectPosition.vz; + vertexPtr++; + } + while(--vertexNum); + + } +} + + + + +#if 0 +static int RelocatedDueToFallout(DYNAMICSBLOCK *dynPtr) +{ + /* If the object is outside ALL of the modules in the + ActiveBlockList, move it back to its previous position. */ + + { + extern int NumActiveBlocks; + extern DISPLAYBLOCK *ActiveBlockList[]; + + /* scan through modules and stop if object is inside any of them */ + { + int objectInsideSomething = 0; + + int numberOfObjects = NumActiveBlocks; + while(numberOfObjects) + { + DISPLAYBLOCK* objectPtr = ActiveBlockList[--numberOfObjects]; + GLOBALASSERT(objectPtr); + if (objectPtr->ObMyModule) /* is object a module ? */ + { + VECTORCH position = dynPtr->Position; + position.vx -= objectPtr->ObWorld.vx; + position.vy -= objectPtr->ObWorld.vy; + position.vz -= objectPtr->ObWorld.vz; + + if (position.vx >= objectPtr->ObMinX) + if (position.vx <= objectPtr->ObMaxX) + if (position.vz >= objectPtr->ObMinZ) + if (position.vz <= objectPtr->ObMaxZ) + if (position.vy >= objectPtr->ObMinY) + if (position.vy <= objectPtr->ObMaxY) + { + objectInsideSomething = 1; + break; + } + } + } + + if (!objectInsideSomething) + { + dynPtr->Position=dynPtr->PrevPosition; +// NewOnScreenMessage("DEBUG: WENT OUTSIDE ENV"); + } + + return !objectInsideSomething; + } + } + +} +#endif + + + + + + +/* KJL 10:43:28 8/20/97 - stuff to add to bh_near.c */ +#if 0 + + textprint("alien vel %d %d %d\n",sbPtr->DynPtr->LinVelocity.vx,sbPtr->DynPtr->LinVelocity.vy,sbPtr->DynPtr->LinVelocity.vz); + #if 1 + if(alienStatusPtr->IAmCrouched) + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + dynPtr->DynamicsType = DYN_TYPE_SPHERE_COLLISIONS; + } + else + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + dynPtr->DynamicsType = DYN_TYPE_NRBB_COLLISIONS; + } + #endif +#endif + +#if 1 + +/*KJL**************** +* PARTICLE DYNAMICS * +****************KJL*/ + +int ParticleDynamics(PARTICLE *particlePtr, VECTORCH *obstacleNormalPtr, int *moduleIndexPtr) +{ + VECTORCH prevPosition = particlePtr->Position; + DISPLAYBLOCK *hitModule = 0; + int polysLeft; + struct ColPolyTag *nearPolysPtr; + int distanceToMove; + VECTORCH displacement; + int hitObstacle=0; + + displacement.vx = MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + displacement.vy = MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + displacement.vz = MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + distanceToMove = Magnitude(&displacement); + + if (distanceToMoveVelocity; + Normalise(&DirectionOfTravel); + + if (!LocalDetailLevels.BloodCollidesWithEnvironment + &&(particlePtr->ParticleID==PARTICLE_ALIEN_BLOOD + ||particlePtr->ParticleID==PARTICLE_HUMAN_BLOOD + ||particlePtr->ParticleID==PARTICLE_PREDATOR_BLOOD)) + { + CollisionPolysPtr = &CollisionPolysArray[0]; + NumberOfCollisionPolys=0; + } + else + { + FindLandscapePolygonsInParticlesPath(particlePtr, &displacement); + } + + polysLeft = NumberOfCollisionPolys; + nearPolysPtr = CollisionPolysArray; + + /* check against selected polys */ + while(polysLeft) + { + signed int distanceToObstacle; + + distanceToObstacle = DistanceMovedBeforeParticleHitsPolygon(particlePtr,nearPolysPtr,distanceToMove); + + if (distanceToObstacle>=0) + { + hitObstacle=1; + distanceToMove = distanceToObstacle; + *obstacleNormalPtr = nearPolysPtr->PolyNormal; + if ( (nearPolysPtr->ParentObject) + &&(nearPolysPtr->ParentObject->ObMyModule) ) + { + *moduleIndexPtr = nearPolysPtr->ParentObject->ObMyModule->m_index; + hitModule = nearPolysPtr->ParentObject; + } + else + { + *moduleIndexPtr = -1; + hitModule=0; + if (particlePtr->ParticleID==PARTICLE_FLECHETTE && nearPolysPtr->ParentObject) + { + if (nearPolysPtr->ParentObject->ObStrategyBlock) + { + CauseDamageToObject(nearPolysPtr->ParentObject->ObStrategyBlock,&FlechetteDamage,ONE_FIXED,&(particlePtr->Velocity)); + } + } else if (particlePtr->ParticleID==PARTICLE_PREDPISTOL_FLECHETTE && nearPolysPtr->ParentObject) + { + if (nearPolysPtr->ParentObject->ObStrategyBlock) + { + CauseDamageToObject(nearPolysPtr->ParentObject->ObStrategyBlock,&PredPistol_FlechetteDamage,ONE_FIXED,&(particlePtr->Velocity)); + } + } + + } + } + nearPolysPtr++; + polysLeft--; + } + + + if (distanceToMove>COLLISION_GRANULARITY) + { + distanceToMove-=COLLISION_GRANULARITY; + particlePtr->Position.vx += MUL_FIXED(DirectionOfTravel.vx,distanceToMove); + particlePtr->Position.vy += MUL_FIXED(DirectionOfTravel.vy,distanceToMove); + particlePtr->Position.vz += MUL_FIXED(DirectionOfTravel.vz,distanceToMove); + } + + if (hitObstacle) + { + int magOfPerpImp = DotProduct(obstacleNormalPtr,&(particlePtr->Velocity)); + int magnitude = Magnitude(&particlePtr->Velocity); + particlePtr->Velocity.vx -= MUL_FIXED(obstacleNormalPtr->vx, magOfPerpImp); + particlePtr->Velocity.vy -= MUL_FIXED(obstacleNormalPtr->vy, magOfPerpImp); + particlePtr->Velocity.vz -= MUL_FIXED(obstacleNormalPtr->vz, magOfPerpImp); + if(particlePtr->Velocity.vx || particlePtr->Velocity.vy || particlePtr->Velocity.vz) + { + Normalise(&particlePtr->Velocity); + particlePtr->Velocity.vx = MUL_FIXED(particlePtr->Velocity.vx,magnitude/2); + particlePtr->Velocity.vy = MUL_FIXED(particlePtr->Velocity.vy,magnitude/2); + particlePtr->Velocity.vz = MUL_FIXED(particlePtr->Velocity.vz,magnitude/2); + } + } + + /* test to see if you've hit any objects */ + { + int i = NumberOfDynamicObjects; + { + if (prevPosition.vx > particlePtr->Position.vx) + { + DBBMinX = particlePtr->Position.vx; + DBBMaxX = prevPosition.vx; + } + else + { + DBBMinX = prevPosition.vx; + DBBMaxX = particlePtr->Position.vx; + } + + if (prevPosition.vy > particlePtr->Position.vy) + { + DBBMinY = particlePtr->Position.vy; + DBBMaxY = prevPosition.vy; + } + else + { + DBBMinY = prevPosition.vy; + DBBMaxY = particlePtr->Position.vy; + } + + if (prevPosition.vz > particlePtr->Position.vz) + { + DBBMinZ = particlePtr->Position.vz; + DBBMaxZ = prevPosition.vz; + } + else + { + DBBMinZ = prevPosition.vz; + DBBMaxZ = particlePtr->Position.vz; + } + + } + /* scan through objects */ + while(i--) + { + STRATEGYBLOCK *sbPtr = DynamicObjectsList[i]; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + DISPLAYBLOCK *dispPtr = sbPtr->SBdptr; + + if (dispPtr) + if (DBBMinXObjectVertices[0].vx && DBBMaxX>dynPtr->ObjectVertices[7].vx) + if (DBBMinYObjectVertices[0].vy && DBBMaxY>dynPtr->ObjectVertices[7].vy) + if (DBBMinZObjectVertices[0].vz && DBBMaxZ>dynPtr->ObjectVertices[7].vz) + { + /* blam! particle hit something */ + if (particlePtr->ParticleID==PARTICLE_ALIEN_BLOOD) + { + if ((dispPtr==Player)||(sbPtr->I_SBtype==I_BehaviourMarine)) { + CauseDamageToObject(sbPtr,&TemplateAmmo[AMMO_ALIEN_FRAG].MaxDamage[AvP.Difficulty], NormalFrameTime,NULL); + } + } + else if (particlePtr->ParticleID==PARTICLE_FLAME + ||particlePtr->ParticleID==PARTICLE_PARGEN_FLAME + ||particlePtr->ParticleID==PARTICLE_MOLOTOVFLAME) + { + BOOL ignoreDamage = FALSE; + if ((dispPtr==Player)||(dispPtr->HModelControlBlock)) + { + + if(AvP.Network != I_No_Network) + { + //If friendly fire has been disabled , we may need to ignore this option + if(particlePtr->ParticleID==PARTICLE_FLAME) + { + if (netGameData.disableFriendlyFire && (netGameData.gameType==NGT_CoopDeathmatch || netGameData.gameType==NGT_Coop)) + { + //okay , friendly fire is off , so flamethrower particles , can't harm + //marines. + //in coop games it shouldn't harm predators either + if(sbPtr->I_SBtype==I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData=(NETGHOSTDATABLOCK *) sbPtr->SBdataptr; + GLOBALASSERT(ghostData); + if (ghostData->type==I_BehaviourMarinePlayer) + { + ignoreDamage = TRUE; + } + else if (ghostData->type==I_BehaviourPredatorPlayer && netGameData.gameType==NGT_Coop) + { + ignoreDamage = TRUE; + } + } + if(dispPtr==Player) + { + if(AvP.PlayerType == I_Marine) + { + ignoreDamage = TRUE; + } + else if (AvP.PlayerType == I_Predator && netGameData.gameType==NGT_Coop) + { + ignoreDamage = TRUE; + } + } + + } + } + + if(!ignoreDamage) + { + if(dispPtr==Player) + { + extern DPID myIgniterId; + myIgniterId=0; //the player hasn't been set alight by a network opponent + } + else if(sbPtr->I_SBtype==I_BehaviourAlien) + { + //note that the alien has been set on fire locally + ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr; + if(particlePtr->ParticleID==PARTICLE_FLAME) + { + extern DPID AVPDPNetID; + alienStatus->aliensIgniterId=AVPDPNetID; + } + else + { + //no credit for aliens killed by molotov particles , or + //particle generator particles. + alienStatus->aliensIgniterId=0; + } + } + } + } + if(!ignoreDamage) + { + if(sbPtr->I_SBtype==I_BehaviourNetGhost) + { + + /* + Don't let molotov particles damage netghosts. Each machine in a net game will be generating + its own molotov particles. + Similary for PARTICLE_PARGEN_FLAME + */ + if(particlePtr->ParticleID==PARTICLE_FLAME) + { + NETGHOSTDATABLOCK *ghostData=(NETGHOSTDATABLOCK *) sbPtr->SBdataptr; + GLOBALASSERT(ghostData); + + + //just add up the number of particles that have hit the ghost + //so the damage message can be sent in one block + ghostData->FlameHitCount++; + sbPtr->SBDamageBlock.IsOnFire = 1; + } + } + else + { + CauseDamageToObject(sbPtr,&TemplateAmmo[AMMO_FLAMETHROWER].MaxDamage[AvP.Difficulty], ONE_FIXED/400,NULL); + sbPtr->SBDamageBlock.IsOnFire = 1; + } + } + } + if (dispPtr==Player && !ignoreDamage) + { + PlayerStatusPtr->fireTimer=PLAYER_ON_FIRE_TIME; + } + } + else if (particlePtr->ParticleID==PARTICLE_FLECHETTE) + { + if(sbPtr->I_SBtype==I_BehaviourNetGhost) + { + //for net ghosts add up all the flechettes that hit it this frame , and send as one + //damage message + NETGHOSTDATABLOCK *ghostData=(NETGHOSTDATABLOCK *) sbPtr->SBdataptr; + GLOBALASSERT(ghostData); + ghostData->FlechetteHitCount++; + + } + else + { + CauseDamageToObject(sbPtr,&FlechetteDamage,ONE_FIXED,&(particlePtr->Velocity)); + } + } + else if (particlePtr->ParticleID==PARTICLE_PREDPISTOL_FLECHETTE) + { + CauseDamageToObject(sbPtr,&PredPistol_FlechetteDamage,particlePtr->LifeTime,&(particlePtr->Velocity)); + } + } + } + } + + if (*moduleIndexPtr != -1) + { + if(hitModule) + { + char stickWhereYouAre = 0; + + if (hitModule->ObStrategyBlock) + { + if (hitModule->ObMyModule && (!hitModule->ObMorphCtrl)) + { + stickWhereYouAre=1; + } + } + else + { + stickWhereYouAre = 1; + } + + if (!stickWhereYouAre) *moduleIndexPtr = -1; + + return hitObstacle; + } + return hitObstacle; + } + else return 0; +} + +static void FindLandscapePolygonsInParticlesPath(PARTICLE *particlePtr, VECTORCH *displacementPtr) +{ + extern int NumActiveBlocks; + extern DISPLAYBLOCK *ActiveBlockList[]; + + /* initialise near polygons array */ + CollisionPolysPtr = &CollisionPolysArray[0]; + NumberOfCollisionPolys=0; + + /* scan through ActiveBlockList for modules */ + { + int numberOfObjects = NumActiveBlocks; + while(numberOfObjects) + { + DISPLAYBLOCK* objectPtr = ActiveBlockList[--numberOfObjects]; + char isStaticObject=0; + + GLOBALASSERT(objectPtr); + if(objectPtr->ObStrategyBlock) + if(objectPtr->ObStrategyBlock->DynPtr) + { + if(((objectPtr->ObStrategyBlock->DynPtr->IsStatic) + ||(objectPtr->ObStrategyBlock->DynPtr->OnlyCollideWithObjects)) + &&(!objectPtr->ObStrategyBlock->DynPtr->OnlyCollideWithEnvironment)) + isStaticObject=1; + } + + if (objectPtr->ObMyModule) /* is object a module or static? */ + { + { + DBBMaxX = particlePtr->Position.vx - objectPtr->ObWorld.vx + COLLISION_GRANULARITY; + DBBMinX = particlePtr->Position.vx - objectPtr->ObWorld.vx - COLLISION_GRANULARITY; + + DBBMaxY = particlePtr->Position.vy - objectPtr->ObWorld.vy + COLLISION_GRANULARITY; + DBBMinY = particlePtr->Position.vy - objectPtr->ObWorld.vy - COLLISION_GRANULARITY; + + DBBMaxZ = particlePtr->Position.vz - objectPtr->ObWorld.vz + COLLISION_GRANULARITY; + DBBMinZ = particlePtr->Position.vz - objectPtr->ObWorld.vz - COLLISION_GRANULARITY; + + if (displacementPtr->vx > 0) + { + DBBMaxX += displacementPtr->vx; + } + else + { + DBBMinX += displacementPtr->vx; + } + + if (displacementPtr->vy > 0) + { + DBBMaxY += displacementPtr->vy; + } + else + { + DBBMinY += displacementPtr->vy; + } + + if (displacementPtr->vz > 0) + { + DBBMaxZ += displacementPtr->vz; + } + else + { + DBBMinZ += displacementPtr->vz; + } + + } + LOCALASSERT(NumberOfCollisionPolys < MAXIMUM_NUMBER_OF_COLLISIONPOLYS); + + /* if the bounding box intersects with the object, investigate */ + if (( (DBBMaxX >= objectPtr->ObMinX) && (DBBMinX <= objectPtr->ObMaxX) ) + &&( (DBBMaxY >= objectPtr->ObMinY) && (DBBMinY <= objectPtr->ObMaxY) ) + &&( (DBBMaxZ >= objectPtr->ObMinZ) && (DBBMinZ <= objectPtr->ObMaxZ) )) + TestShapeWithParticlesDynamicBoundingBox(objectPtr); + } + else if (isStaticObject) + { + { + DBBMaxX = particlePtr->Position.vx - objectPtr->ObWorld.vx + COLLISION_GRANULARITY; + DBBMinX = particlePtr->Position.vx - objectPtr->ObWorld.vx - COLLISION_GRANULARITY; + + DBBMaxY = particlePtr->Position.vy - objectPtr->ObWorld.vy + COLLISION_GRANULARITY; + DBBMinY = particlePtr->Position.vy - objectPtr->ObWorld.vy - COLLISION_GRANULARITY; + + DBBMaxZ = particlePtr->Position.vz - objectPtr->ObWorld.vz + COLLISION_GRANULARITY; + DBBMinZ = particlePtr->Position.vz - objectPtr->ObWorld.vz - COLLISION_GRANULARITY; + + if (displacementPtr->vx > 0) + { + DBBMaxX += displacementPtr->vx; + } + else + { + DBBMinX += displacementPtr->vx; + } + + if (displacementPtr->vy > 0) + { + DBBMaxY += displacementPtr->vy; + } + else + { + DBBMinY += displacementPtr->vy; + } + + if (displacementPtr->vz > 0) + { + DBBMaxZ += displacementPtr->vz; + } + else + { + DBBMinZ += displacementPtr->vz; + } + + } + LOCALASSERT(NumberOfCollisionPolys < MAXIMUM_NUMBER_OF_COLLISIONPOLYS); + + /* if the bounding box intersects with the object, investigate */ + if (( (DBBMaxX >= -objectPtr->ObRadius) && (DBBMinX <= objectPtr->ObRadius) ) + &&( (DBBMaxY >= -objectPtr->ObRadius) && (DBBMinY <= objectPtr->ObRadius) ) + &&( (DBBMaxZ >= -objectPtr->ObRadius) && (DBBMinZ <= objectPtr->ObRadius) )) + TestShapeWithParticlesDynamicBoundingBox(objectPtr); + + } + } + } +} + +static signed int DistanceMovedBeforeParticleHitsPolygon(PARTICLE *particlePtr, struct ColPolyTag *polyPtr, int distanceToMove) +{ + VECTORCH pointOnPlane; + int lambda; + int axis1; + int axis2; + + { + int normDotBeta = DotProduct(&(polyPtr->PolyNormal),&DirectionOfTravel); + + /* trivial rejection of poly if it is not facing LOS */ + if (normDotBeta>-500) + { + return -1; + } + + /* calculate coords of plane-line intersection */ + { + int d; + { + /* get a pt in the poly */ + VECTORCH pop=polyPtr->PolyPoint[0]; + pop.vx -= particlePtr->Position.vx; + pop.vy -= particlePtr->Position.vy; + pop.vz -= particlePtr->Position.vz; + + d = DotProduct(&(polyPtr->PolyNormal),&pop); + } + if (d>=0) + { + return -1; + } + lambda = DIV_FIXED(d,normDotBeta); + if (lambda>=distanceToMove) + { + return -1; + } + pointOnPlane.vx = particlePtr->Position.vx + MUL_FIXED(lambda,DirectionOfTravel.vx); + pointOnPlane.vy = particlePtr->Position.vy + MUL_FIXED(lambda,DirectionOfTravel.vy); + pointOnPlane.vz = particlePtr->Position.vz + MUL_FIXED(lambda,DirectionOfTravel.vz); + + } + + /* decide which 2d plane to project onto */ + + { + VECTORCH absNormal = (polyPtr->PolyNormal); + if (absNormal.vx<0) absNormal.vx=-absNormal.vx; + if (absNormal.vy<0) absNormal.vy=-absNormal.vy; + if (absNormal.vz<0) absNormal.vz=-absNormal.vz; + + if (absNormal.vx > absNormal.vy) + { + if (absNormal.vx > absNormal.vz) + { + axis1=iy; + axis2=iz; + } + else + { + axis1=ix; + axis2=iy; + } + } + else + { + if (absNormal.vy > absNormal.vz) + { + axis1=ix; + axis2=iz; + } + else + { + axis1=ix; + axis2=iy; + } + } + } + + } + { + int projectedPolyVertex[20]; + int projectedPointOnPlane[2]; + int *popPtr = &pointOnPlane.vx; + + projectedPointOnPlane[0]=*(popPtr+axis1); + projectedPointOnPlane[1]=*(popPtr+axis2); + + { + VECTORCH *vertexPtr = polyPtr->PolyPoint; + int *projectedVertexPtr= projectedPolyVertex; + int noOfVertices = polyPtr->NumberOfVertices; + + do + { + *projectedVertexPtr++ = *((int*)vertexPtr + axis1); + *projectedVertexPtr++ = *((int*)vertexPtr + axis2); + + vertexPtr++; + noOfVertices--; + } + while(noOfVertices); + + } + + + if (PointInPolygon(&projectedPointOnPlane[0],&projectedPolyVertex[0],polyPtr->NumberOfVertices,2)) + { + return lambda; + } + } + + return -1; +} + +void AddEffectsOfForceGenerators(VECTORCH *positionPtr, VECTORCH *impulsePtr, int mass) +{ + extern int NumActiveBlocks; + extern DISPLAYBLOCK *ActiveBlockList[]; + int numOfObjects = NumActiveBlocks; + while(numOfObjects) + { + DISPLAYBLOCK *objectPtr = ActiveBlockList[--numOfObjects]; + STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock; + + if (sbPtr && sbPtr->I_SBtype==I_BehaviourFan) + { + FAN_BEHAV_BLOCK *fanPtr; + fanPtr = (FAN_BEHAV_BLOCK*)sbPtr->SBdataptr; + + if (fanPtr->wind_speed) + { + int mag; + VECTORCH disp = sbPtr->DynPtr->Position; + disp.vx -= positionPtr->vx; + disp.vy -= positionPtr->vy; + disp.vz -= positionPtr->vz; + + mag = 16384 - Approximate3dMagnitude(&disp); + + if (mag<0) continue; + if(MagnitudeOfCrossProduct(&disp,&fanPtr->fan_wind_direction)>objectPtr->ObRadius+200) continue; + mag=MUL_FIXED(MUL_FIXED(mag*32*4*32,fanPtr->wind_speed),NormalFrameTime)/mass; + + impulsePtr->vx += MUL_FIXED(fanPtr->fan_wind_direction.vx,mag); + impulsePtr->vy += MUL_FIXED(fanPtr->fan_wind_direction.vy,mag); + impulsePtr->vz += MUL_FIXED(fanPtr->fan_wind_direction.vz,mag); + } +// PrintDebuggingText("Fan acting upon object %d\n",fanPtr->wind_speed); + } + } +} + +#endif + + + +VECTORCH *GetNearestModuleTeleportPoint(MODULE* thisModulePtr, VECTORCH* positionPtr) +{ + extern FARENTRYPOINTSHEADER *FALLP_EntryPoints; + int numEps; + FARENTRYPOINT *epList; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + int tmIndex = thisModulePtr->m_aimodule->m_index; + int distance = 0x7fffffff; + + numEps = FALLP_EntryPoints[tmIndex].numEntryPoints; + epList = FALLP_EntryPoints[tmIndex].entryPointsList; + + while((numEps>0)) + { + VECTORCH p = *positionPtr; + int d; + char buffer[100]; + + p.vx -= thisModulePtr->m_aimodule->m_world.vx + epList->position.vx; + p.vy -= thisModulePtr->m_aimodule->m_world.vy + epList->position.vy; + p.vz -= thisModulePtr->m_aimodule->m_world.vz + epList->position.vz; + + d = Approximate3dMagnitude(&p); + + if (dposition); + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/3dc/avp/EQUATES.H b/3dc/avp/EQUATES.H new file mode 100644 index 0000000..1012c57 --- /dev/null +++ b/3dc/avp/EQUATES.H @@ -0,0 +1,228 @@ +#ifndef EQUATES_INCLUDED + + +/* + + Equates & Enums for AVP + +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#define default_global_h1 5000000 +#define default_global_h2 (5000000 + (ONE_FIXED << 5)) +#define default_global_hs 5 + + +#define default_zratio_threshold 320 /* 1.25 */ + +#define MaxObjectLights 50 /* Sources attached to the object */ + +#define maxlightblocks 100 /* This ought to be MORE than enough */ + +#if PSX +#define MaxLightsPerObject 10 /* Sources lighting the object */ +#else +#define MaxLightsPerObject 100 /* Sources lighting the object */ +#endif + + +/* + + 3d Texture Scan Subdivision limits + +*/ + +#define lin_s_max 5 + +#if 0 + + #define lin_s_zthr 320 /* 1.25 */ + +#else + + #if 1 + + #define lin_s_zthr 281 /* 1.1 */ + + #else + + #define lin_s_zthr 260 /* 1.01 */ + + #endif + +#endif + + + +/* AH Table */ + + + + +#define RScale 2 +#define VScale (6 + 3) + +#define Wibble Yes + +#define GlobalScale 1 + + + + +/* + Scenes and View Types +*/ + + +typedef enum { + + AVP_Scene0, /* environments*/ + AVP_Scene1, + AVP_Scene2, + AVP_Scene3, + AVP_Scene4, + AVP_Scene5, + AVP_Scene6, + AVP_Scene7, + AVP_Scene8, + AVP_Scene9, + AVP_Scene10 + +} SCENE; + + +typedef enum { + + AVP_ViewType0, /* worlds within env*/ + +} VIEWTYPE; + +/* + + View Handler Function Array Indices + +*/ + +typedef enum { + + VState_Inside, + VState_RelativeRemote, + VState_RelativeYRemote, + VState_FixedRemote, + VState_FlyBy, + VState_LagRelRemote, + VState_TrackingRemote, + VState_LagRelYRemote, + + VState_Last + +} VIEWSTATES; + +#define CameraTrackingNormal 0x00000000 +#define CameraTrackingSlew 0x00000001 +#define CameraTrackingFollow 0x00000002 +#define CameraTrackingTrakBak 0x00000004 + +#define PanChange 128 + + +/* + + View Interior Types + +*/ + +typedef enum { + + IType_Default, + IType_Body, + IType_Car, + IType_Aircraft, + + IType_Last + +} ITYPES; + + +/* + + Shape enum for mainshapelist[] + + We don't need this except for compiled in + shapes. For pc riff loading the comipled in + shape enum is in cnkhmaps.c in avp\win95 + +*/ + +#if PSX +#if BinaryLoading +#else +typedef enum { + + Shape_bob, + Shape_Default, + Shape_Alien, + Shape_weapon, + Shape_terminal, + Shape_mmseg1, + Shape_Cube, + +} AVP_SHAPES; + +#endif +#endif + + +/* Map Types */ + +typedef enum { + + MapType_Default, + MapType_Player, + MapType_PlayerShipCamera, + MapType_Sprite, + MapType_Term + +} AVP_MAP_TYPES; + + +/* Strategies */ + +typedef enum { + + StrategyI_Null, + StrategyI_Camera, + StrategyI_Player, + StrategyI_Test, + StrategyI_NewtonTest, + StrategyI_HomingTest, + StrategyI_MissileTest, + StrategyI_GravityOnly, + StrategyI_Database, + StrategyI_DoorPROX, + StrategyI_Terminal, + StrategyI_Last /* Always the last */ + +} AVP_STRATEGIES; + + + + + + +#define MaxSint5SortArraySize 50 /* was 100, must be at least ml_shm_maxheights */ + + + +/***********end for C++************/ + +#ifdef __cplusplus +}; +#endif + +#define EQUATES_INCLUDED + +#endif diff --git a/3dc/avp/EQUIPMNT.C b/3dc/avp/EQUIPMNT.C new file mode 100644 index 0000000..785a9ba --- /dev/null +++ b/3dc/avp/EQUIPMNT.C @@ -0,0 +1,8238 @@ +/*****************************************************************************************************//*KJL***************************************************************************** +* Equipmnt.c - contains the data for all equipment that can be used in the game. * +* * +*****************************************************************************KJL*/ +#include "3dc.h" +#include "inline.h" +#include "module.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "equipmnt.h" +#include "hmodel.h" +#include "sequnces.h" +#include "weapons.h" + +#define USE_ENCUMBERANCE 0 + +/* Weapon Functions */ + +extern void AlienClawTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void AlienClawEndTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void MeleeWeaponNullTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void AlienTailTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PredDiscThrowTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PredWristbladeTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void ParticleBeamSwapping(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PulseRifleSwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PulseRifleSwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PulseRifleGrenadeRecoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PulseRifleReloadClip(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PulseRifleFidget(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void ParticleBeamReadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void ParticleBeamUnreadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void MinigunStartSpin(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void MinigunStopSpin(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void Maintain_Minigun(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GrenadeLauncherRecoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GrenadeLauncherIdle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GrenadeLauncherFidget(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GrenadeLauncherNull(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GrenadeLauncherReload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GrenadeLauncherReload_Change(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GrenadeLauncher_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GrenadeLauncher_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void WristBlade_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void WristBlade_Strike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void WristBlade_Strike_Secondary(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void WristBlade_Readying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void WristBlade_Unreadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PredPistol_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PredPistol_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PredPistol_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PredPistol_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void AlienClaw_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void AlienClaw_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void AlienClaw_Strike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void AlienClaw_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void AlienClaw_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void AlienTail_Poise(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void AlienTail_Strike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void AlienGrab_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void AlienGrab_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void AlienGrab_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void AlienGrab_Strike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PlasmaCaster_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void WristConsole_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void WristConsole_Use(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void TemplateHands_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void TemplateHands_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void WristConsole_Readying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void WristConsole_Unreadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void SADAR_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void SADAR_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void SADAR_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void SADAR_Fidget(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void SADAR_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void SADAR_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GenericMarineWeapon_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GenericMarineWeapon_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GenericMarineWeapon_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GenericMarineWeapon_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GenericMarineWeapon_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GenericPredatorWeapon_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GenericPredatorWeapon_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GenericPredatorWeapon_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GenericPredatorWeapon_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GenericPredatorWeapon_Firing_Secondary(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void GenericPredatorWeapon_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PredatorDisc_Throwing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PredatorDisc_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PredatorDisc_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void StaffAttack_Basic(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void Staff_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void Staff_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void Staff_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void PlasmaCaster_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void WristBlade_WindUp(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void WristBlade_WindUpStrike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void SpikeyThing_Use(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void Extinguisher_Use(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void Secondary_PlasmaCaster_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void Minigun_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void SpearGun_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void MarinePistol_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void MarinePistol_Fidget(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void MarinePistol_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void MarinePistol_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void MarinePistol_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void Cudgel_Strike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void MarineTwoPistols_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void MarineTwoPistols_SecondaryFiring(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void MarineTwoPistols_Fidget(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void MarineTwoPistols_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void MarineTwoPistols_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void MarineTwoPistols_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void Frisbee_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +extern void Frisbee_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); + +extern void GrenadeLauncherInit(PLAYER_WEAPON_DATA *weaponPtr); +extern int GrenadeLauncherFire(PLAYER_WEAPON_DATA *weaponPtr); + +extern void WeaponSetStartFrame(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); + +extern int FireBurstWeapon(PLAYER_WEAPON_DATA *weaponPtr); +extern int FireMinigun(PLAYER_WEAPON_DATA *weaponPtr); +extern int FireAutomaticWeapon(PLAYER_WEAPON_DATA *weaponPtr); +extern int FireNonAutomaticWeapon(PLAYER_WEAPON_DATA *weaponPtr); +extern int FireNonAutomaticSecondaryAmmo(PLAYER_WEAPON_DATA *weaponPtr); +extern int GrenadeLauncherChangeAmmo(PLAYER_WEAPON_DATA *weaponPtr); +extern int PredDiscChangeMode(PLAYER_WEAPON_DATA *weaponPtr); +extern int PredatorDisc_Prefiring(PLAYER_WEAPON_DATA *weaponPtr); +extern int SmartgunSecondaryFire(PLAYER_WEAPON_DATA *weaponPtr); +extern int DamageObjectInLineOfSight(PLAYER_WEAPON_DATA *weaponPtr); +extern int MeleeWeapon_180Degree_Front(PLAYER_WEAPON_DATA *weaponPtr); +extern int MeleeWeapon_90Degree_Front(PLAYER_WEAPON_DATA *weaponPtr); +extern int PlayerFireFlameThrower(PLAYER_WEAPON_DATA *weaponPtr); +extern int FirePCPlasmaCaster(PLAYER_WEAPON_DATA *weaponPtr); +extern int SecondaryFirePCPlasmaCaster(PLAYER_WEAPON_DATA *weaponPtr); +extern int FirePredPistol(PLAYER_WEAPON_DATA *weaponPtr); +extern int FireSpeargun(PLAYER_WEAPON_DATA *weaponPtr); +extern int FireSpikeyThing(PLAYER_WEAPON_DATA *weaponPtr); +extern int FireExtinguisher(PLAYER_WEAPON_DATA *weaponPtr); +extern int PlayerFirePredPistolFlechettes(PLAYER_WEAPON_DATA *weaponPtr); +extern int PredPistolSecondaryFire(PLAYER_WEAPON_DATA *weaponPtr); +extern int FireMarineTwoPistolsPrimary(PLAYER_WEAPON_DATA *weaponPtr); +extern int FireMarineTwoPistolsSecondary(PLAYER_WEAPON_DATA *weaponPtr); + +/*KJL**************************************************************************************** +* G L O B A L S * +****************************************************************************************KJL*/ +/* CDF 2/10/97 Key for weapons vs. slots... */ +enum WEAPON_ID MarineWeaponKey[MAX_NO_OF_WEAPON_SLOTS] = { + WEAPON_PULSERIFLE, + /* AUTOSHOTGUN removed, 4/3/98, CDF, By order of Al */ + WEAPON_SMARTGUN, + WEAPON_FLAMETHROWER, + WEAPON_SADAR, + WEAPON_GRENADELAUNCHER, + WEAPON_MINIGUN, + WEAPON_FRISBEE_LAUNCHER, + WEAPON_MARINE_PISTOL, + WEAPON_TWO_PISTOLS, + NULL_WEAPON, + #if 1 + WEAPON_CUDGEL + #else + NULL_WEAPON + #endif +}; + +enum WEAPON_ID PredatorWeaponKey[MAX_NO_OF_WEAPON_SLOTS] = { + WEAPON_PRED_WRISTBLADE, + WEAPON_PRED_RIFLE, + WEAPON_PRED_SHOULDERCANNON, + WEAPON_PRED_MEDICOMP, + WEAPON_PRED_PISTOL, + WEAPON_PRED_DISC, + NULL_WEAPON, + NULL_WEAPON, + NULL_WEAPON, + NULL_WEAPON, + NULL_WEAPON +}; + +enum WEAPON_ID AlienWeaponKey[MAX_NO_OF_WEAPON_SLOTS] = { + WEAPON_ALIEN_CLAW, + WEAPON_ALIEN_GRAB, + WEAPON_ALIEN_SPIT, + NULL_WEAPON, + NULL_WEAPON, + NULL_WEAPON, + NULL_WEAPON, + NULL_WEAPON, + NULL_WEAPON, + NULL_WEAPON, + NULL_WEAPON +}; + +/* KJL 10:45:56 09/20/96 - contains all the generic weapon info */ +TEMPLATE_WEAPON_DATA TemplateWeapon[MAX_NO_OF_WEAPON_TEMPLATES] = +{ + + /*KJL************** + * PULSE RIFLE * + **************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_10MM_CULW, + /* SecondaryAmmoID; */ + AMMO_PULSE_GRENADE, + + FireBurstWeapon, /* FirePrimaryFunction */ + FireNonAutomaticSecondaryAmmo, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536, /* WEAPONSTATE_IDLE */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + 65536, /* WEAPONSTATE_RELOAD_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + 65536, /* WEAPONSTATE_RECOIL_SECONDARY */ + 65536, /* WEAPONSTATE_RELOAD_SECONDARY */ + 65536*8, /* WEAPONSTATE_SWAPPING_IN */ + 65536*8, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + PulseRifleFidget, /* WEAPONSTATE_IDLE */ + WeaponSetStartFrame, /* WEAPONSTATE_FIRING_PRIMARY */ + NULL, /* WEAPONSTATE_RECOIL_PRIMARY */ + PulseRifleReloadClip, /* WEAPONSTATE_RELOAD_PRIMARY */ + WeaponSetStartFrame, /* WEAPONSTATE_FIRING_SECONDARY */ + PulseRifleGrenadeRecoil, /* WEAPONSTATE_RECOIL_SECONDARY */ + NULL, /* WEAPONSTATE_RELOAD_SECONDARY */ + PulseRifleSwapIn, /* WEAPONSTATE_SWAPPING_IN */ + PulseRifleSwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + NULL, /* WEAPONSTATE_JAMMED */ + NULL, /* WEAPONSTATE_WAITING */ + NULL, /* WEAPONSTATE_READYING */ + NULL, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 1000*65536/60, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius */ + 0, + /* RestPosition; */ + //{300,400,800}, + {0,0,0}, + + /* RecoilMaxZ; */ + 90, //0, //60, + /* RecoilMaxRandomZ; */ + 60, //0, //31, + /* RecoilMaxXTilt; */ + 30, //0, //31, + /* RecoilMaxYTilt; */ + 30, //0, //15, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_INGAME_PULSERIFLE, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + "MarineWeapons", + /* HierarchyName */ + "Pulse Rifle", + /* InitialSequenceType */ + (int)HMSQT_MarineHUD, + /* InitialSubSequence */ + (int)MHSS_Stationary, + + #if USE_ENCUMBERANCE + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #else + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #endif + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 1, + /* PrimaryIsAutomatic :1; */ + 1, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 1, + /* SecondaryMuzzleFlash */ + 1, + /* LogAccuracy */ + 1, + /* LogShots */ + 1, + }, + + /*KJL********************* + * WEAPON_AUTOSHOTGUN * + *********************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_SHOTGUN, + /* SecondaryAmmoID; */ + AMMO_NONE, + + FireNonAutomaticWeapon, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 0,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + 65536*8, /* WEAPONSTATE_RECOIL_PRIMARY */ + 65536*4, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536*8, /* WEAPONSTATE_SWAPPING_IN */ + 65536*8, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + NULL, /* WEAPONSTATE_IDLE */ + NULL, /* WEAPONSTATE_FIRING_PRIMARY */ + NULL, /* WEAPONSTATE_RECOIL_PRIMARY */ + NULL, /* WEAPONSTATE_RELOAD_PRIMARY */ + NULL, /* WEAPONSTATE_FIRING_SECONDARY */ + NULL, /* WEAPONSTATE_RECOIL_SECONDARY */ + NULL, /* WEAPONSTATE_RELOAD_SECONDARY */ + NULL, /* WEAPONSTATE_SWAPPING_IN */ + NULL, /* WEAPONSTATE_SWAPPING_OUT */ + NULL, /* WEAPONSTATE_JAMMED */ + NULL, /* WEAPONSTATE_WAITING */ + NULL, /* WEAPONSTATE_READYING */ + NULL, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 1*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 5500, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 80, + /* RecoilMaxRandomZ; */ + 31, + /* RecoilMaxXTilt; */ + -31, + /* RecoilMaxYTilt; */ + 15, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_BLANK, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + NULL, + /* HierarchyName */ + NULL, + /* InitialSequenceType */ + -1, + /* InitialSubSequence */ + -1, + + #if USE_ENCUMBERANCE + { /* Encum_Idle */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #else + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #endif + + /* UseStateMovement :1; */ + 1, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 0, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 1, + /* SecondaryMuzzleFlash */ + 1, + /* LogAccuracy */ + 0, + /* LogShots */ + 0, + }, + /*KJL****************** + * WEAPON_SMARTGUN * + ******************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_SMARTGUN, + /* SecondaryAmmoID; */ + AMMO_NONE, + + FireBurstWeapon, /* FirePrimaryFunction */ + SmartgunSecondaryFire, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + 65536, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536*4, /* WEAPONSTATE_SWAPPING_IN was 2/3? */ + 65536*4, /* WEAPONSTATE_SWAPPING_OUT was 2/3? */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + GenericMarineWeapon_Idle, /* WEAPONSTATE_IDLE */ + GenericMarineWeapon_Firing, /* WEAPONSTATE_FIRING_PRIMARY */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_RECOIL_PRIMARY */ + GenericMarineWeapon_Reload, /* WEAPONSTATE_RELOAD_PRIMARY */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_FIRING_SECONDARY */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_RECOIL_SECONDARY */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_RELOAD_SECONDARY */ + GenericMarineWeapon_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + GenericMarineWeapon_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_JAMMED */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_WAITING */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_READYING */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 50*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 55000, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 60, //60, + /* RecoilMaxRandomZ; */ + 31, //31, + /* RecoilMaxXTilt; */ + 15, //31, + /* RecoilMaxYTilt; */ + 15, //15, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_INGAME_SMARTGUN, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + "MarineWeapons", + /* HierarchyName */ + "Smart Gun", + /* InitialSequenceType */ + (int)HMSQT_MarineHUD, + /* InitialSubSequence */ + (int)MHSS_Stationary, + + #if USE_ENCUMBERANCE + { /* Encum_Idle */ + 3*ONE_FIXED/4, /* MovementMultiple */ + 3*ONE_FIXED/4, /* TurningMultiple */ + 3*ONE_FIXED/4, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED/2, /* MovementMultiple */ + ONE_FIXED/2, /* TurningMultiple */ + ONE_FIXED/2, /* JumpingMultiple */ + 1, /* CanCrouch */ + 0, /* CanRun */ + }, + { /* Encum_FireSec */ + 3*ONE_FIXED/4, /* MovementMultiple */ + 3*ONE_FIXED/4, /* TurningMultiple */ + 3*ONE_FIXED/4, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #else + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #endif + + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 1, + /* PrimaryIsRapidFire :1; */ + 1, + /* PrimaryIsAutomatic :1; */ + 1, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 1, + /* SecondaryMuzzleFlash */ + 0, + /* LogAccuracy */ + 1, + /* LogShots */ + 1, + }, + /*KJL********************** + * WEAPON_FLAMETHROWER * + **********************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_FLAMETHROWER, + /* SecondaryAmmoID; */ + AMMO_NONE, + + PlayerFireFlameThrower, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + 65536, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536, /* WEAPONSTATE_SWAPPING_IN */ + 65536, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + GenericMarineWeapon_Idle, /* WEAPONSTATE_IDLE */ + GenericMarineWeapon_Firing, /* WEAPONSTATE_FIRING_PRIMARY */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_RECOIL_PRIMARY */ + GenericMarineWeapon_Reload, /* WEAPONSTATE_RELOAD_PRIMARY */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_FIRING_SECONDARY */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_RECOIL_SECONDARY */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_RELOAD_SECONDARY */ + GenericMarineWeapon_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + GenericMarineWeapon_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_JAMMED */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_WAITING */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_READYING */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 15*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 0, + /* RestPosition; */ + {-350,0,0}, + + /* RecoilMaxZ; */ + 0, //60, + /* RecoilMaxRandomZ; */ + 0, //31, + /* RecoilMaxXTilt; */ + 0, //31, + /* RecoilMaxYTilt; */ + 0, //15, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_INGAME_FLAMETHROWER, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + NULL,/* ie. no muzzle flash */ + /* RiffName */ + "MarineWeapons", + /* HierarchyName */ + "Flamethrower", + /* InitialSequenceType */ + (int)HMSQT_MarineHUD, + /* InitialSubSequence */ + (int)MHSS_Stationary, + + #if USE_ENCUMBERANCE + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #else + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #endif + + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 1, + /* PrimaryIsAutomatic :1; */ + 1, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 1, + /* FireSecondaryLate */ + 1, + /* PrimaryMuzzleFlash */ + 1, + /* SecondaryMuzzleFlash */ + 1, + /* LogAccuracy */ + 0, + /* LogShots */ + 0, + }, + /*KJL******************* + * WEAPON_PLASMAGUN * + *******************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_PLASMA, + /* SecondaryAmmoID; */ + AMMO_NONE, + + NULL, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 0,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + 65536, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536, /* WEAPONSTATE_SWAPPING_IN */ + 65536, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + NULL, /* WEAPONSTATE_IDLE */ + NULL, /* WEAPONSTATE_FIRING_PRIMARY */ + NULL, /* WEAPONSTATE_RECOIL_PRIMARY */ + NULL, /* WEAPONSTATE_RELOAD_PRIMARY */ + NULL, /* WEAPONSTATE_FIRING_SECONDARY */ + NULL, /* WEAPONSTATE_RECOIL_SECONDARY */ + NULL, /* WEAPONSTATE_RELOAD_SECONDARY */ + NULL, /* WEAPONSTATE_SWAPPING_IN */ + NULL, /* WEAPONSTATE_SWAPPING_OUT */ + NULL, /* WEAPONSTATE_JAMMED */ + NULL, /* WEAPONSTATE_WAITING */ + NULL, /* WEAPONSTATE_READYING */ + NULL, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 1*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 5500, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 0, + /* RecoilMaxRandomZ; */ + 0, + /* RecoilMaxXTilt; */ + 0, + /* RecoilMaxYTilt; */ + 0, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_BLANK, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + NULL, + /* HierarchyName */ + NULL, + /* InitialSequenceType */ + -1, + /* InitialSubSequence */ + -1, + + #if USE_ENCUMBERANCE + { /* Encum_Idle */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #else + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #endif + + /* UseStateMovement :1; */ + 1, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 0, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 1, + /* SecondaryMuzzleFlash */ + 1, + /* LogAccuracy */ + 0, + /* LogShots */ + 0, + }, + /*KJ**************** + * WEAPON_SADAR * + ****************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_SADAR_TOW, + /* SecondaryAmmoID; */ + AMMO_NONE, + + FireNonAutomaticWeapon, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + 65536*6, /* WEAPONSTATE_RECOIL_PRIMARY */ + 65536*2/3, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536, /* WEAPONSTATE_SWAPPING_IN */ + 65536, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + SADAR_Fidget, /* WEAPONSTATE_IDLE */ + SADAR_Idle, /* WEAPONSTATE_FIRING_PRIMARY */ + SADAR_Recoil, /* WEAPONSTATE_RECOIL_PRIMARY */ + SADAR_Reload, /* WEAPONSTATE_RELOAD_PRIMARY */ + SADAR_Idle, /* WEAPONSTATE_FIRING_SECONDARY */ + SADAR_Idle, /* WEAPONSTATE_RECOIL_SECONDARY */ + SADAR_Idle, /* WEAPONSTATE_RELOAD_SECONDARY */ + SADAR_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + SADAR_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + SADAR_Idle, /* WEAPONSTATE_JAMMED */ + SADAR_Idle, /* WEAPONSTATE_WAITING */ + SADAR_Idle, /* WEAPONSTATE_READYING */ + SADAR_Idle, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 1*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 0, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 0, //200, + /* RecoilMaxRandomZ; */ + 0, //0, + /* RecoilMaxXTilt; */ + 0, //24, + /* RecoilMaxYTilt; */ + 0, //0, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_INGAME_SADAR, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + "MarineWeapons", + /* HierarchyName */ + "Rocket Launcher", + /* InitialSequenceType */ + (int)HMSQT_MarineHUD, + /* InitialSubSequence */ + (int)MHSS_Stationary, + + #if USE_ENCUMBERANCE + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 0, /* MovementMultiple */ + 0, /* TurningMultiple */ + 0, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #else + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #endif + + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 0, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 1, + /* SecondaryMuzzleFlash */ + 1, + /* LogAccuracy */ + 1, + /* LogShots */ + 1, + }, + /*KJL************************* + * WEAPON_GRENADELAUNCHER * + *************************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_GRENADE, + /* SecondaryAmmoID; */ + AMMO_NONE, + + GrenadeLauncherFire, /* FirePrimaryFunction */ + GrenadeLauncherChangeAmmo, /* FireSecondaryFunction */ + GrenadeLauncherInit, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + (65536*3)/4, // Was *6... /* WEAPONSTATE_RECOIL_PRIMARY */ + (65536*3)/4, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + (65536*3)/4, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536*4, /* WEAPONSTATE_SWAPPING_IN */ + 65536*4, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + GrenadeLauncherFidget, /* WEAPONSTATE_IDLE */ + GrenadeLauncherNull, /* WEAPONSTATE_FIRING_PRIMARY */ + GrenadeLauncherRecoil, /* WEAPONSTATE_RECOIL_PRIMARY */ + GrenadeLauncherReload, /* WEAPONSTATE_RELOAD_PRIMARY */ + NULL, /* WEAPONSTATE_FIRING_SECONDARY */ + GrenadeLauncherReload_Change, /* WEAPONSTATE_RECOIL_SECONDARY */ + GrenadeLauncherIdle, /* WEAPONSTATE_RELOAD_SECONDARY */ + GrenadeLauncher_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + GrenadeLauncher_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + GrenadeLauncherIdle, /* WEAPONSTATE_JAMMED */ + GrenadeLauncherIdle, /* WEAPONSTATE_WAITING */ + GrenadeLauncherIdle, /* WEAPONSTATE_READYING */ + GrenadeLauncherIdle, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 1*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 0, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 0, //60, + /* RecoilMaxRandomZ; */ + 0, //31, + /* RecoilMaxXTilt; */ + 0, //31, + /* RecoilMaxYTilt; */ + 0, //15, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_INGAME_GRENADELAUNCHER, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + "MarineWeapons", + /* HierarchyName */ + "Grenade Launcher", + /* InitialSequenceType */ + (int)HMSQT_MarineHUD, + /* InitialSubSequence */ + (int)MHSS_Stationary, + + #if USE_ENCUMBERANCE + { /* Encum_Idle */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 2*ONE_FIXED/3, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 2*ONE_FIXED/3, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 2*ONE_FIXED/3, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #else + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #endif + + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 0, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 1, + /* SecondaryMuzzleFlash */ + 0, + /* LogAccuracy */ + 0, + /* LogShots */ + 1, + }, + /*KJL***************** + * WEAPON_MINIGUN * + *****************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_MINIGUN, + /* SecondaryAmmoID; */ + AMMO_NONE, + + FireMinigun, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + 65536*2, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536*4, /* WEAPONSTATE_SWAPPING_IN */ + 65536*4, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + 65536, /* WEAPONSTATE_UNREADYING */ + + }, + { + Maintain_Minigun, /* WEAPONSTATE_IDLE */ + Maintain_Minigun, /* WEAPONSTATE_FIRING_PRIMARY */ + Maintain_Minigun, /* WEAPONSTATE_RECOIL_PRIMARY */ + Maintain_Minigun, /* WEAPONSTATE_RELOAD_PRIMARY */ + Maintain_Minigun, /* WEAPONSTATE_FIRING_SECONDARY */ + Maintain_Minigun, /* WEAPONSTATE_RECOIL_SECONDARY */ + Maintain_Minigun, /* WEAPONSTATE_RELOAD_SECONDARY */ + Minigun_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + NULL, /* WEAPONSTATE_SWAPPING_OUT */ + Maintain_Minigun, /* WEAPONSTATE_JAMMED */ + Maintain_Minigun, /* WEAPONSTATE_WAITING */ + MinigunStartSpin, /* WEAPONSTATE_READYING */ + MinigunStopSpin, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + //60*65536, + 100*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 0, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 60, //60, //0, + /* RecoilMaxRandomZ; */ + 31, //31, //0, + /* RecoilMaxXTilt; */ + 31, //31, //31, //0, + /* RecoilMaxYTilt; */ + 31, //15, //15, //0, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_INGAME_MINIGUN, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + "MarineWeapons", + /* HierarchyName */ + "Minigun", + /* InitialSequenceType */ + (int)HMSQT_MarineHUD, + /* InitialSubSequence */ + (int)MHSS_Stationary, + + #if USE_ENCUMBERANCE + { /* Encum_Idle */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 2*ONE_FIXED/3, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 0, /* MovementMultiple */ + 2*ONE_FIXED/3, /* TurningMultiple */ + 0, /* JumpingMultiple */ + 1, /* CanCrouch */ + 0, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 0, /* CanRun */ + }, + #else + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + #if FORCE_MINIGUN_STOP + 0, /* MovementMultiple */ + #else + 2*ONE_FIXED/3, /* MovementMultiple */ + #endif + 7*ONE_FIXED/8, /* TurningMultiple */ + #if FORCE_MINIGUN_STOP + 0, /* JumpingMultiple */ + #else + 2*ONE_FIXED/3, /* JumpingMultiple */ + #endif + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #endif + + /* UseStateMovement :1; */ + 1, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 1, + /* PrimaryIsAutomatic :1; */ + 1, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 1, + /* SecondaryMuzzleFlash */ + 1, + /* LogAccuracy */ + 1, + /* LogShots */ + 1, + }, + /*KJL********************* + * WEAPON_SONICCANNON * + *********************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_SONIC_PULSE, + /* SecondaryAmmoID; */ + AMMO_NONE, + + NULL, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 0,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + 65536*8, /* WEAPONSTATE_RECOIL_PRIMARY */ + 65536*2, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536, /* WEAPONSTATE_SWAPPING_IN */ + 65536, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + NULL, /* WEAPONSTATE_IDLE */ + NULL, /* WEAPONSTATE_FIRING_PRIMARY */ + NULL, /* WEAPONSTATE_RECOIL_PRIMARY */ + NULL, /* WEAPONSTATE_RELOAD_PRIMARY */ + NULL, /* WEAPONSTATE_FIRING_SECONDARY */ + NULL, /* WEAPONSTATE_RECOIL_SECONDARY */ + NULL, /* WEAPONSTATE_RELOAD_SECONDARY */ + NULL, /* WEAPONSTATE_SWAPPING_IN */ + NULL, /* WEAPONSTATE_SWAPPING_OUT */ + NULL, /* WEAPONSTATE_JAMMED */ + NULL, /* WEAPONSTATE_WAITING */ + NULL, /* WEAPONSTATE_READYING */ + NULL, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 1*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 5500, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 0, //60, + /* RecoilMaxRandomZ; */ + 0, //31, + /* RecoilMaxXTilt; */ + 0, //31, + /* RecoilMaxYTilt; */ + 0, //15, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_BLANK, + + /* WeaponShapeName; */ + "Hsonicg", + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + NULL, + /* HierarchyName */ + NULL, + /* InitialSequenceType */ + -1, + /* InitialSubSequence */ + -1, + + #if USE_ENCUMBERANCE + { /* Encum_Idle */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #else + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #endif + + /* UseStateMovement :1; */ + 1, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 0, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 1, + /* SecondaryMuzzleFlash */ + 1, + /* LogAccuracy */ + 0, + /* LogShots */ + 0, + }, + /*KJL******************** + * WEAPON_BEAMCANNON * + ********************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_PARTICLE_BEAM, + /* SecondaryAmmoID; */ + AMMO_NONE, + + FireAutomaticWeapon, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 0,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + 65536*2, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536, /* WEAPONSTATE_SWAPPING_IN */ + 65536, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + 65536, /* WEAPONSTATE_READYING */ + 65536, /* WEAPONSTATE_UNREADYING */ + + }, + { + NULL, /* WEAPONSTATE_IDLE */ + NULL, /* WEAPONSTATE_FIRING_PRIMARY */ + NULL, /* WEAPONSTATE_RECOIL_PRIMARY */ + NULL, /* WEAPONSTATE_RELOAD_PRIMARY */ + NULL, /* WEAPONSTATE_FIRING_SECONDARY */ + NULL, /* WEAPONSTATE_RECOIL_SECONDARY */ + NULL, /* WEAPONSTATE_RELOAD_SECONDARY */ + ParticleBeamSwapping, /* WEAPONSTATE_SWAPPING_IN */ + ParticleBeamSwapping, /* WEAPONSTATE_SWAPPING_OUT */ + NULL, /* WEAPONSTATE_JAMMED */ + NULL, /* WEAPONSTATE_WAITING */ + ParticleBeamReadying, /* WEAPONSTATE_READYING */ + ParticleBeamUnreadying, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 1000*65536/60, +// 40*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 5500, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 60, + /* RecoilMaxRandomZ; */ + 31, + /* RecoilMaxXTilt; */ + 5, + /* RecoilMaxYTilt; */ + 5, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_BLANK, + + /* WeaponShapeName; */ + //"Cpbhud", + "Shell",/*"CPBhudf",*/ + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + NULL, + /* HierarchyName */ + NULL, + /* InitialSequenceType */ + -1, + /* InitialSubSequence */ + -1, + + #if USE_ENCUMBERANCE + { /* Encum_Idle */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 2*ONE_FIXED/3, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 2*ONE_FIXED/3, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 2*ONE_FIXED/3, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #else + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #endif + + /* UseStateMovement :1; */ + 1, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 1, + /* PrimaryIsAutomatic :1; */ + 1, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0,/*1,*/ + /* HasTextureAnimation */ + 0,/*1,*/ + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 1, + /* SecondaryMuzzleFlash */ + 1, + /* LogAccuracy */ + 0, + /* LogShots */ + 0, + }, + /*KJL******************** + * WEAPON_MYSTERYGUN * + ********************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_SMARTGUN, + /* SecondaryAmmoID; */ + AMMO_PULSE_GRENADE, + + NULL, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 0,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + 65536, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + 65536*6, /* WEAPONSTATE_RECOIL_SECONDARY */ + 65536, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536*2, /* WEAPONSTATE_SWAPPING_IN */ + 65536*2, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + NULL, /* WEAPONSTATE_IDLE */ + NULL, /* WEAPONSTATE_FIRING_PRIMARY */ + NULL, /* WEAPONSTATE_RECOIL_PRIMARY */ + NULL, /* WEAPONSTATE_RELOAD_PRIMARY */ + NULL, /* WEAPONSTATE_FIRING_SECONDARY */ + NULL, /* WEAPONSTATE_RECOIL_SECONDARY */ + NULL, /* WEAPONSTATE_RELOAD_SECONDARY */ + NULL, /* WEAPONSTATE_SWAPPING_IN */ + NULL, /* WEAPONSTATE_SWAPPING_OUT */ + NULL, /* WEAPONSTATE_JAMMED */ + NULL, /* WEAPONSTATE_WAITING */ + NULL, /* WEAPONSTATE_READYING */ + NULL, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 2000*65536/60, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius */ + 55000, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 60, + /* RecoilMaxRandomZ; */ + 31, + /* RecoilMaxXTilt; */ + 31, + /* RecoilMaxYTilt; */ + 15, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_BLANK, + + /* WeaponShapeName; */ + "Hmystry", + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + NULL, + /* HierarchyName */ + NULL, + /* InitialSequenceType */ + -1, + /* InitialSubSequence */ + -1, + + #if USE_ENCUMBERANCE + { /* Encum_Idle */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #else + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #endif + + /* UseStateMovement :1; */ + 1, + /* IsSmartTarget :1; */ + 1, + /* PrimaryIsRapidFire :1; */ + 1, + /* PrimaryIsAutomatic :1; */ + 1, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 1, + /* SecondaryMuzzleFlash */ + 1, + /* LogAccuracy */ + 0, + /* LogShots */ + 0, + }, + + + /*KJL********************************** + * PPP RRR EEE DD A TTT OOO RRR * + * P P R R E D D A A T O O R R * + * PPP RRR EEE D D AAA T O O RRR * + * P RR E D D A A T O O RR * + * P R R EEE DD A A T OOO R R * + **********************************KJL*/ + + /*KJL************************* + * WEAPON_PRED_WRISTBLADE * + *************************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_PRED_WRISTBLADE, + /* SecondaryAmmoID; */ + AMMO_HEAVY_PRED_WRISTBLADE, + + //MeleeWeapon_90Degree_Front, /* FirePrimaryFunction */ + NULL, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + + 65536>>2, /* WEAPONSTATE_FIRING_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + 65536>>2, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536*3, /* WEAPONSTATE_SWAPPING_IN */ + 65536*3, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + 65536*2, /* WEAPONSTATE_READYING */ + 65536*2, /* WEAPONSTATE_UNREADYING */ + + }, + { + WristBlade_Idle, /* WEAPONSTATE_IDLE */ + WristBlade_Strike, /* WEAPONSTATE_FIRING_PRIMARY */ + WristBlade_Idle, /* WEAPONSTATE_RECOIL_PRIMARY */ + WristBlade_Idle, /* WEAPONSTATE_RELOAD_PRIMARY */ + WristBlade_WindUp, /* WEAPONSTATE_FIRING_SECONDARY */ + WristBlade_WindUpStrike, /* WEAPONSTATE_RECOIL_SECONDARY */ + WristBlade_Idle, /* WEAPONSTATE_RELOAD_SECONDARY */ + TemplateHands_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + TemplateHands_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + WristBlade_Idle, /* WEAPONSTATE_JAMMED */ + WristBlade_Idle, /* WEAPONSTATE_WAITING */ + WristBlade_Readying, /* WEAPONSTATE_READYING */ + WristBlade_Unreadying, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 0, + /* FiringRate; */ + 1*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 0, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 0, //-1024, + /* RecoilMaxRandomZ; */ + 0, //0, + /* RecoilMaxXTilt; */ + 0, //0, + /* RecoilMaxYTilt; */ + 0, //0, + + /* StrikePosition */ + {300,350,0}, + + /* Name; */ + TEXTSTRING_INGAME_WRISTBLADE, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + 0, + /* RiffName */ + "pred_HUD", + /* HierarchyName */ + "Template", + /* InitialSequenceType */ + (int)HMSQT_PredatorHUD, + /* InitialSubSequence */ + (int)PHSS_Come, + + { /* Encum_Idle */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 1, + /* PrimaryIsMeleeWeapon :1; */ + 1, + /* SecondaryIsRapidFire :1; */ + 1, + /* SecondaryIsAutomatic :1; */ + 1, + /* SecondaryIsMeleeWeapon :1; */ + 1, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 0, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 0, + /* SecondaryMuzzleFlash */ + 0, + /* LogAccuracy */ + 0, + /* LogShots */ + 0, + }, + + /*KJL********************* + * WEAPON_PRED_PISTOL * + *********************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_PRED_PISTOL, + /* SecondaryAmmoID; */ + AMMO_PRED_PISTOL, + + //FirePredPistol, /* FirePrimaryFunction */ + PredPistolSecondaryFire, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + //PlayerFirePredPistolFlechettes, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + (65536*2), /* WEAPONSTATE_RECOIL_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + 65536, /* WEAPONSTATE_RELOAD_SECONDARY */ + + ((65536*5)/6), /* WEAPONSTATE_SWAPPING_IN */ /* Was >>2 */ + ((65536*5)/6), /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + PredPistol_Idle, /* WEAPONSTATE_IDLE */ + PredPistol_Firing, /* WEAPONSTATE_FIRING_PRIMARY */ + PredPistol_Idle, /* WEAPONSTATE_RECOIL_PRIMARY */ + PredPistol_Idle, /* WEAPONSTATE_RELOAD_PRIMARY */ + PredPistol_Firing, /* WEAPONSTATE_FIRING_SECONDARY */ + PredPistol_Idle, /* WEAPONSTATE_RECOIL_SECONDARY */ + PredPistol_Idle, /* WEAPONSTATE_RELOAD_SECONDARY */ + GenericPredatorWeapon_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + GenericPredatorWeapon_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + PredPistol_Idle, /* WEAPONSTATE_JAMMED */ + PredPistol_Idle, /* WEAPONSTATE_WAITING */ + PredPistol_Idle, /* WEAPONSTATE_READYING */ + PredPistol_Idle, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 16*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 0, //55000, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 0, //31, + /* RecoilMaxRandomZ; */ + 0, //15, + /* RecoilMaxXTilt; */ + 0, //15, + /* RecoilMaxYTilt; */ + 0, //7, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_INGAME_PISTOL, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + "pred_HUD", + /* HierarchyName */ + "pistol", + /* InitialSequenceType */ + (int)HMSQT_PredatorHUD, + //-1, + /* InitialSubSequence */ + (int)PHSS_Stand, + //-1, + + { /* Encum_Idle */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 0, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 1, + /* SecondaryIsAutomatic :1; */ + 1, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 0, + /* FireInChangeVision */ + 0, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 1, + /* PrimaryMuzzleFlash */ + 1, + /* SecondaryMuzzleFlash */ + 1, + /* LogAccuracy */ + 1, + /* LogShots */ + 1, + }, + + /*KJL******************** + * WEAPON_PRED_RIFLE * + ********************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_PRED_RIFLE, + /* SecondaryAmmoID; */ + AMMO_NONE, + + FireSpeargun, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + #if 0 + 65536*2, /* WEAPONSTATE_FIRING_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + #else + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + 65536*2, /* WEAPONSTATE_RECOIL_PRIMARY */ + #endif + 65536*4, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536, /* WEAPONSTATE_SWAPPING_IN */ + 65536, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + GenericPredatorWeapon_Idle, /* WEAPONSTATE_IDLE */ + #if 0 + GenericPredatorWeapon_Firing, /* WEAPONSTATE_FIRING_PRIMARY */ + GenericPredatorWeapon_Idle, /* WEAPONSTATE_RECOIL_PRIMARY */ + #else + GenericPredatorWeapon_Idle, /* WEAPONSTATE_FIRING_PRIMARY */ + SpearGun_Recoil, /* WEAPONSTATE_RECOIL_PRIMARY */ + #endif + GenericPredatorWeapon_Reload, /* WEAPONSTATE_RELOAD_PRIMARY */ + GenericPredatorWeapon_Idle, /* WEAPONSTATE_FIRING_SECONDARY */ + GenericPredatorWeapon_Idle, /* WEAPONSTATE_RECOIL_SECONDARY */ + GenericPredatorWeapon_Idle, /* WEAPONSTATE_RELOAD_SECONDARY */ + GenericPredatorWeapon_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + GenericPredatorWeapon_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + GenericPredatorWeapon_Idle, /* WEAPONSTATE_JAMMED */ + GenericPredatorWeapon_Idle, /* WEAPONSTATE_WAITING */ + GenericPredatorWeapon_Idle, /* WEAPONSTATE_READYING */ + GenericPredatorWeapon_Idle, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 640, + /* SmartTargetRadius in pixels */ + 0, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 0, //80, + /* RecoilMaxRandomZ; */ + 0, //31, + /* RecoilMaxXTilt; */ + 0, //31, //-31? + /* RecoilMaxYTilt; */ + 0, //15, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_INGAME_RIFLE, + + /* WeaponShapeName; */ + "Shell", + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + "pred_HUD", + /* HierarchyName */ + "Speargun", + /* InitialSequenceType */ + (int)HMSQT_PredatorHUD, + /* InitialSubSequence */ + (int)PHSS_Stand, + + { /* Encum_Idle */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 1, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 0, + /* FireInChangeVision */ + 0, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 0, + /* SecondaryMuzzleFlash */ + 0, + /* LogAccuracy */ + 1, + /* LogShots */ + 1, + }, + /*KJL***************************** + * WEAPON_PRED_SHOULDERCANNON * + *****************************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_PRED_ENERGY_BOLT, + /* SecondaryAmmoID; */ + AMMO_NONE, + + //FirePCPlasmaCaster, /* FirePrimaryFunction */ + SecondaryFirePCPlasmaCaster, /* FirePrimaryFunction */ + SecondaryFirePCPlasmaCaster, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + 65536*8, /* WEAPONSTATE_RECOIL_PRIMARY */ + 65536*4, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + 65536*8, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536*3, /* WEAPONSTATE_SWAPPING_IN */ + 65536*3, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + 31208, /* (2.1s) */ /* WEAPONSTATE_READYING */ + 40960, /* (1.6s) */ /* WEAPONSTATE_UNREADYING */ + + }, + { + PlasmaCaster_Idle, /* WEAPONSTATE_IDLE */ + //WristConsole_Use, /* WEAPONSTATE_FIRING_PRIMARY */ + PlasmaCaster_Idle, /* WEAPONSTATE_FIRING_PRIMARY */ + PlasmaCaster_Recoil, /* WEAPONSTATE_RECOIL_PRIMARY */ + PlasmaCaster_Idle, /* WEAPONSTATE_RELOAD_PRIMARY */ + PlasmaCaster_Idle, /* WEAPONSTATE_FIRING_SECONDARY */ + Secondary_PlasmaCaster_Recoil, /* WEAPONSTATE_RECOIL_SECONDARY */ + PlasmaCaster_Idle, /* WEAPONSTATE_RELOAD_SECONDARY */ + TemplateHands_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + TemplateHands_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + PlasmaCaster_Idle, /* WEAPONSTATE_JAMMED */ + PlasmaCaster_Idle, /* WEAPONSTATE_WAITING */ + WristConsole_Readying, /* WEAPONSTATE_READYING */ + WristConsole_Unreadying, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 1*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 0, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 0, + /* SmartTargetRadius in pixels */ + 65000, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 0, //-1024, + /* RecoilMaxRandomZ; */ + 0, //0, + /* RecoilMaxXTilt; */ + 0, //0, + /* RecoilMaxYTilt; */ + 0, //0, + + /* StrikePosition */ + {300,350,0}, + /* Name; */ + TEXTSTRING_INGAME_SHOULDERCANNON, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + NULL,/* ie. no muzzle flash */ + /* RiffName */ + "pred_HUD", + /* HierarchyName */ + "Template", + /* InitialSequenceType */ + (int)HMSQT_PredatorHUD, + /* InitialSubSequence */ + (int)PHSS_Come, + + { /* Encum_Idle */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 1, + /* PrimaryIsRapidFire :1; */ + 1, //0 + /* PrimaryIsAutomatic :1; */ + 1, //0 + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 1, + /* SecondaryIsAutomatic :1; */ + 1, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 1, + /* FireSecondaryLate */ + 1, + /* PrimaryMuzzleFlash */ + 0, + /* SecondaryMuzzleFlash */ + 0, + /* LogAccuracy */ + 1, + /* LogShots */ + 1, + }, + + /*CDF******************* + * WEAPON_PRED_DISC * + *******************CDF*/ + { + /* PrimaryAmmoID; */ + AMMO_PRED_DISC, + /* SecondaryAmmoID; */ + AMMO_NONE, + + PredatorDisc_Prefiring, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + + 65536*2, /* WEAPONSTATE_FIRING_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + 65536*2, /* WEAPONSTATE_RELOAD_PRIMARY */ + + 65536*2, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536*8, /* WEAPONSTATE_SWAPPING_IN */ + 65536*8, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + GenericPredatorWeapon_Idle, /* WEAPONSTATE_IDLE */ + PredatorDisc_Throwing, /* WEAPONSTATE_FIRING_PRIMARY */ + PredatorDisc_Recoil, /* WEAPONSTATE_RECOIL_PRIMARY */ + PredatorDisc_Reload, /* WEAPONSTATE_RELOAD_PRIMARY */ + GenericPredatorWeapon_Idle, /* WEAPONSTATE_FIRING_SECONDARY */ + GenericPredatorWeapon_Idle, /* WEAPONSTATE_RECOIL_SECONDARY */ + GenericPredatorWeapon_Idle, /* WEAPONSTATE_RELOAD_SECONDARY */ + GenericPredatorWeapon_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + GenericPredatorWeapon_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + GenericPredatorWeapon_Idle, /* WEAPONSTATE_JAMMED */ + GenericPredatorWeapon_Idle, /* WEAPONSTATE_WAITING */ + GenericPredatorWeapon_Idle, /* WEAPONSTATE_READYING */ + GenericPredatorWeapon_Idle, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 0, + /* FiringRate; */ + 1*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 20000, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 0, //-1024, + /* RecoilMaxRandomZ; */ + 0, //0, + /* RecoilMaxXTilt; */ + 0, //0, + /* RecoilMaxYTilt; */ + 0, //0, + + /* StrikePosition */ + {300,350,0}, + + /* Name; */ + TEXTSTRING_INGAME_DISC, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + 0, + /* RiffName */ + "pred_HUD", + /* HierarchyName */ + "disk", + /* InitialSequenceType */ + (int)HMSQT_PredatorHUD, + /* InitialSubSequence */ + (int)PHSS_Stand, + + { /* Encum_Idle */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 1, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 0, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 0, + /* FireInChangeVision */ + 0, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 0, + /* SecondaryMuzzleFlash */ + 0, + /* LogAccuracy */ + 0, + /* LogShots */ + 0, + }, + /*KJL***************************** + * WEAPON_PRED_MEDICOMP * + *****************************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_NONE, + /* SecondaryAmmoID; */ + AMMO_NONE, + + FireSpikeyThing, /* FirePrimaryFunction */ + FireExtinguisher, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + + 65536>>2, /* WEAPONSTATE_FIRING_PRIMARY */ + //65536*2, /* WEAPONSTATE_FIRING_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_PRIMARY */ + + 65536>>2, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536*3, /* WEAPONSTATE_SWAPPING_IN */ + 65536*3, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + 31208, /* (2.1s) */ /* WEAPONSTATE_READYING */ + 40960, /* (1.6s) */ /* WEAPONSTATE_UNREADYING */ + + }, + { + WristConsole_Idle, /* WEAPONSTATE_IDLE */ + SpikeyThing_Use, /* WEAPONSTATE_FIRING_PRIMARY */ + WristConsole_Idle, /* WEAPONSTATE_RECOIL_PRIMARY */ + WristConsole_Idle, /* WEAPONSTATE_RELOAD_PRIMARY */ + Extinguisher_Use, /* WEAPONSTATE_FIRING_SECONDARY */ + WristConsole_Idle, /* WEAPONSTATE_RECOIL_SECONDARY */ + WristConsole_Idle, /* WEAPONSTATE_RELOAD_SECONDARY */ + TemplateHands_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + TemplateHands_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + WristConsole_Idle, /* WEAPONSTATE_JAMMED */ + WristConsole_Idle, /* WEAPONSTATE_WAITING */ + WristConsole_Readying, /* WEAPONSTATE_READYING */ + WristConsole_Unreadying, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 1*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 0, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 0, + /* SmartTargetRadius in pixels */ + 65000, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 0, //-1024, + /* RecoilMaxRandomZ; */ + 0, //0, + /* RecoilMaxXTilt; */ + 0, //0, + /* RecoilMaxYTilt; */ + 0, //0, + + /* StrikePosition */ + {300,350,0}, + /* Name; */ + TEXTSTRING_INGAME_MEDICOMP, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + NULL,/* ie. no muzzle flash */ + /* RiffName */ + "pred_HUD", + /* HierarchyName */ + "Template", + /* InitialSequenceType */ + (int)HMSQT_PredatorHUD, + /* InitialSubSequence */ + (int)PHSS_Come, + + { /* Encum_Idle */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 0, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 0, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 1, + /* FireSecondaryLate */ + 1, + /* PrimaryMuzzleFlash */ + 0, + /* SecondaryMuzzleFlash */ + 0, + /* LogAccuracy */ + 0, + /* LogShots */ + 0, + }, + /*KJL***************************** + * WEAPON_PRED_STAFF * + *****************************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_PRED_STAFF, + /* SecondaryAmmoID; */ + AMMO_NONE, + + NULL, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + + 65536>>2, /* WEAPONSTATE_FIRING_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536, /* WEAPONSTATE_SWAPPING_IN */ + 65536, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + 65536*2, /* WEAPONSTATE_READYING */ + 65536*2, /* WEAPONSTATE_UNREADYING */ + + }, + { + Staff_Idle, /* WEAPONSTATE_IDLE */ + StaffAttack_Basic, /* WEAPONSTATE_FIRING_PRIMARY */ + Staff_Idle, /* WEAPONSTATE_RECOIL_PRIMARY */ + Staff_Idle, /* WEAPONSTATE_RELOAD_PRIMARY */ + Staff_Idle, /* WEAPONSTATE_FIRING_SECONDARY */ + Staff_Idle, /* WEAPONSTATE_RECOIL_SECONDARY */ + Staff_Idle, /* WEAPONSTATE_RELOAD_SECONDARY */ + Staff_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + Staff_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + Staff_Idle, /* WEAPONSTATE_JAMMED */ + Staff_Idle, /* WEAPONSTATE_WAITING */ + Staff_Idle, /* WEAPONSTATE_READYING */ + Staff_Idle, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 0, + /* FiringRate; */ + 1*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 0, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 0, //-1024, + /* RecoilMaxRandomZ; */ + 0, //0, + /* RecoilMaxXTilt; */ + 0, //0, + /* RecoilMaxYTilt; */ + 0, //0, + + /* StrikePosition */ + {300,350,0}, + + /* Name; */ + TEXTSTRING_BLANK, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + 0, + /* RiffName */ + "pred_HUD", + /* HierarchyName */ + "staff", + /* InitialSequenceType */ + (int)HMSQT_PredatorHUD, + /* InitialSubSequence */ + (int)PHSS_Come, + + { /* Encum_Idle */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 1, + /* PrimaryIsAutomatic :1; */ + 0, + /* PrimaryIsMeleeWeapon :1; */ + 1, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 1, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 0, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 0, + /* SecondaryMuzzleFlash */ + 0, + /* LogAccuracy */ + 0, + /* LogShots */ + 0, + }, + + /*KJL******************** + * WEAPON_ALIEN_CLAW * + ********************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_ALIEN_CLAW, + /* SecondaryAmmoID; */ + AMMO_ALIEN_TAIL, + + //MeleeWeapon_180Degree_Front, /* FirePrimaryFunction */ + NULL, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 0,/* WEAPONSTATE_IDLE */ + + //65536*4, /* WEAPONSTATE_FIRING_PRIMARY */ + 65536*6, /* WEAPONSTATE_FIRING_PRIMARY */ + //65536*2, /* WEAPONSTATE_RECOIL_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + 65536*2, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_SWAPPING_IN */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_SWAPPING_OUT */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + AlienClaw_Idle, /* WEAPONSTATE_IDLE */ + AlienClaw_Strike, /* WEAPONSTATE_FIRING_PRIMARY */ + AlienClaw_Recoil, /* WEAPONSTATE_RECOIL_PRIMARY */ + AlienClaw_Idle, /* WEAPONSTATE_RELOAD_PRIMARY */ + AlienTail_Poise, /* WEAPONSTATE_FIRING_SECONDARY */ + AlienTail_Strike, /* WEAPONSTATE_RECOIL_SECONDARY */ + AlienClaw_Idle, /* WEAPONSTATE_RELOAD_SECONDARY */ + AlienClaw_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + AlienClaw_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + AlienClaw_Idle, /* WEAPONSTATE_JAMMED */ + AlienClaw_Idle, /* WEAPONSTATE_WAITING */ + AlienClaw_Idle, /* WEAPONSTATE_READYING */ + AlienClaw_Idle, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 0, + /* FiringRate; */ + 1*65536, + + ///* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + //4, + ///* GunCrosshairSpeed; integer, how fast the gun moves. */ + //160, + ///* SmartTargetRadius in pixels */ + //0, + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 0, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 1500, + /* SmartTargetRadius in pixels */ + 55000, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 0, //-1024, + /* RecoilMaxRandomZ; */ + 0, //0, + /* RecoilMaxXTilt; */ + 0, //0, + /* RecoilMaxYTilt; */ + 0, //0, + + /* StrikePosition */ + {600,-100,400}, + + /* Name; */ + TEXTSTRING_INGAME_CLAW, + + /* WeaponShapeName; */ + "Shell", + /* MuzzleFlashShapeName; */ + NULL, + /* RiffName */ + "alien_HUD", + /* HierarchyName */ + "claws", + /* InitialSequenceType */ + (int)HMSQT_AlienHUD, + /* InitialSubSequence */ + (int)AHSS_LeftSwipeDown, + + { /* Encum_Idle */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 1, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 1, + /* PrimaryIsMeleeWeapon :1; */ + 1, + /* SecondaryIsRapidFire :1; */ + 1, + /* SecondaryIsAutomatic :1; */ + 1, + /* SecondaryIsMeleeWeapon :1; */ + 1, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 0, + /* SecondaryMuzzleFlash */ + 0, + /* LogAccuracy */ + 0, + /* LogShots */ + 0, + }, + /*KJL******************** + * WEAPON_ALIEN_GRAB * + ********************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_ALIEN_TAIL, + /* SecondaryAmmoID; */ + AMMO_NONE, + + //MeleeWeapon_90Degree_Front, /* FirePrimaryFunction */ + NULL, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 0,/* WEAPONSTATE_IDLE */ + + 65536*6, /* WEAPONSTATE_FIRING_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + 65536*2, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_SWAPPING_IN */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_SWAPPING_OUT */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + AlienGrab_Idle, /* WEAPONSTATE_IDLE */ + AlienGrab_Strike, /* WEAPONSTATE_FIRING_PRIMARY */ + AlienGrab_Idle, /* WEAPONSTATE_RECOIL_PRIMARY */ + AlienGrab_Idle, /* WEAPONSTATE_RELOAD_PRIMARY */ + AlienGrab_Idle, /* WEAPONSTATE_FIRING_SECONDARY */ + AlienGrab_Idle, /* WEAPONSTATE_RECOIL_SECONDARY */ + AlienGrab_Idle, /* WEAPONSTATE_RELOAD_SECONDARY */ + AlienGrab_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + AlienGrab_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + AlienGrab_Idle, /* WEAPONSTATE_JAMMED */ + AlienGrab_Idle, /* WEAPONSTATE_WAITING */ + AlienGrab_Idle, /* WEAPONSTATE_READYING */ + AlienGrab_Idle, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 0, + /* FiringRate; */ + 1*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 0, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 0, //0, + /* RecoilMaxRandomZ; */ + 0, //0, + /* RecoilMaxXTilt; */ + 0, //0, + /* RecoilMaxYTilt; */ + 0, //0, + + /* StrikePosition */ + {300,0,500}, + + /* Name; */ + TEXTSTRING_INGAME_TAIL, + + /* WeaponShapeName; */ + "claw", + /* MuzzleFlashShapeName; */ + NULL, + /* RiffName */ + "alien_HUD", + /* HierarchyName */ + "eat", + /* InitialSequenceType */ + (int)HMSQT_AlienHUD, + /* InitialSubSequence */ + (int)AHSS_Eat, + + { /* Encum_Idle */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 1, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 0, + /* PrimaryIsMeleeWeapon :1; */ + 1, + /* SecondaryIsRapidFire :1; */ + 1, + /* SecondaryIsAutomatic :1; */ + 1, + /* SecondaryIsMeleeWeapon :1; */ + 1, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 0, + /* SecondaryMuzzleFlash */ + 0, + /* LogAccuracy */ + 0, + /* LogShots */ + 0, + }, + /*KJ********************* + * WEAPON_ALIEN_SPIT * + ********************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_ALIEN_SPIT, + /* SecondaryAmmoID; */ + AMMO_NONE, + + NULL, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 0,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + 65536*6, /* WEAPONSTATE_RECOIL_PRIMARY */ + 65536*2/3, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536, /* WEAPONSTATE_SWAPPING_IN */ + 65536, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + NULL, /* WEAPONSTATE_IDLE */ + NULL, /* WEAPONSTATE_FIRING_PRIMARY */ + NULL, /* WEAPONSTATE_RECOIL_PRIMARY */ + NULL, /* WEAPONSTATE_RELOAD_PRIMARY */ + NULL, /* WEAPONSTATE_FIRING_SECONDARY */ + NULL, /* WEAPONSTATE_RECOIL_SECONDARY */ + NULL, /* WEAPONSTATE_RELOAD_SECONDARY */ + NULL, /* WEAPONSTATE_SWAPPING_IN */ + NULL, /* WEAPONSTATE_SWAPPING_OUT */ + NULL, /* WEAPONSTATE_JAMMED */ + NULL, /* WEAPONSTATE_WAITING */ + NULL, /* WEAPONSTATE_READYING */ + NULL, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 1*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 55000, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 0, //200, + /* RecoilMaxRandomZ; */ + 0, //0, + /* RecoilMaxXTilt; */ + 0, //24, + /* RecoilMaxYTilt; */ + 0, //0, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_BLANK, + + /* WeaponShapeName; */ + NULL, + /* MuzzleFlashShapeName; */ + NULL, + /* RiffName */ + NULL, + /* HierarchyName */ + NULL, + /* InitialSequenceType */ + -1, + /* InitialSubSequence */ + -1, + + { /* Encum_Idle */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 1, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 0, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 0, + /* SecondaryMuzzleFlash */ + 0, + /* LogAccuracy */ + 0, + /* LogShots */ + 0, + }, + /*CDF************************* + * WEAPON_CUDGEL * + *************************CDF*/ + { + /* PrimaryAmmoID; */ + AMMO_CUDGEL, + /* SecondaryAmmoID; */ + AMMO_CUDGEL, + + //MeleeWeapon_90Degree_Front, /* FirePrimaryFunction */ + NULL, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + + 65536>>2, /* WEAPONSTATE_FIRING_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_PRIMARY */ + + 65536>>2, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536*3, /* WEAPONSTATE_SWAPPING_IN */ + 65536*3, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + 65536*2, /* WEAPONSTATE_READYING */ + 65536*2, /* WEAPONSTATE_UNREADYING */ + + }, + { + GenericMarineWeapon_Idle, /* WEAPONSTATE_IDLE */ + Cudgel_Strike, /* WEAPONSTATE_FIRING_PRIMARY */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_RECOIL_PRIMARY */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_RELOAD_PRIMARY */ + Cudgel_Strike, /* WEAPONSTATE_FIRING_SECONDARY */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_RECOIL_SECONDARY */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_RELOAD_SECONDARY */ + GenericMarineWeapon_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + GenericMarineWeapon_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_JAMMED */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_WAITING */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_READYING */ + GenericMarineWeapon_Idle, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 0, + /* FiringRate; */ + 1*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 0, + /* RestPosition; */ + {0,0,0}, + + /* RecoilMaxZ; */ + 0, //-1024, + /* RecoilMaxRandomZ; */ + 0, //0, + /* RecoilMaxXTilt; */ + 0, //0, + /* RecoilMaxYTilt; */ + 0, //0, + + /* StrikePosition */ + {0,0,0}, //{300,350,0}, ??? + + /* Name; */ + TEXTSTRING_INGAME_PULSERIFLE, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + 0, + /* RiffName */ + "MarineWeapons", + /* HierarchyName */ + "Cudgel", + /* InitialSequenceType */ + (int)HMSQT_MarineHUD, + /* InitialSubSequence */ + (int)MHSS_Stationary, + + #if USE_ENCUMBERANCE + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #else + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #endif + + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 1, + /* PrimaryIsMeleeWeapon :1; */ + 1, + /* SecondaryIsRapidFire :1; */ + 1, + /* SecondaryIsAutomatic :1; */ + 1, + /* SecondaryIsMeleeWeapon :1; */ + 1, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 0, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 0, + /* SecondaryMuzzleFlash */ + 0, + /* LogAccuracy */ + 0, + /* LogShots */ + 0, + }, + /*KJL************** + * MARINE PISTOL * + **************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_MARINE_PISTOL_PC, + /* SecondaryAmmoID; */ + AMMO_MARINE_PISTOL_PC, + + FireNonAutomaticWeapon, /* FirePrimaryFunction */ + FireNonAutomaticWeapon, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + (65536*5), /* WEAPONSTATE_RECOIL_PRIMARY */ + ((65536*2)/3), /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + (65536*5), /* WEAPONSTATE_RECOIL_SECONDARY */ + 65536, /* WEAPONSTATE_RELOAD_SECONDARY */ + + (65536), /* WEAPONSTATE_SWAPPING_IN */ /* Was >>2 */ + (65536), /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + MarinePistol_Fidget, /* WEAPONSTATE_IDLE */ + MarinePistol_Firing, /* WEAPONSTATE_FIRING_PRIMARY */ + NULL, /* WEAPONSTATE_RECOIL_PRIMARY */ + MarinePistol_Reload, /* WEAPONSTATE_RELOAD_PRIMARY */ + MarinePistol_Firing, /* WEAPONSTATE_FIRING_SECONDARY */ + NULL, /* WEAPONSTATE_RECOIL_SECONDARY */ + NULL, /* WEAPONSTATE_RELOAD_SECONDARY */ + MarinePistol_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + MarinePistol_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + NULL, /* WEAPONSTATE_JAMMED */ + NULL, /* WEAPONSTATE_WAITING */ + NULL, /* WEAPONSTATE_READYING */ + NULL, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + //1000*65536/60, + 12*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius */ + 0, + /* RestPosition; */ + //{300,400,800}, + {0,0,0}, + + /* RecoilMaxZ; */ + 90, //0, //60, + /* RecoilMaxRandomZ; */ + 60, //0, //31, + /* RecoilMaxXTilt; */ + 30, //0, //31, + /* RecoilMaxYTilt; */ + 30, //0, //15, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_INGAME_MARINE_PISTOL, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + "MarineWeapons", + /* HierarchyName */ + "Pistol", + /* InitialSequenceType */ + (int)HMSQT_MarineHUD, + /* InitialSubSequence */ + (int)MHSS_Stationary, + + #if USE_ENCUMBERANCE + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #else + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #endif + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 0, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 1, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 1, + /* SecondaryMuzzleFlash */ + 1, + /* LogAccuracy */ + 1, + /* LogShots */ + 1, + }, + /*CDF************************** + * WEAPON_FRISBEE_LAUNCHER * + **************************CDF*/ + { + /* PrimaryAmmoID; */ + AMMO_FRISBEE, + /* SecondaryAmmoID; */ + AMMO_NONE, + + PredatorDisc_Prefiring, /* FirePrimaryFunction. It's empty. */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + + //WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + //((65536*1000)/1625), /* WEAPONSTATE_FIRING_PRIMARY */ + ((65536*2000)/1625), /* WEAPONSTATE_FIRING_PRIMARY */ + (65000), /* WEAPONSTATE_RECOIL_PRIMARY */ + 65536*2/3, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536, /* WEAPONSTATE_SWAPPING_IN */ + 65536, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + SADAR_Fidget, /* WEAPONSTATE_IDLE */ + Frisbee_Firing, /* WEAPONSTATE_FIRING_PRIMARY */ + Frisbee_Recoil, /* WEAPONSTATE_RECOIL_PRIMARY */ + SADAR_Reload, /* WEAPONSTATE_RELOAD_PRIMARY */ + SADAR_Idle, /* WEAPONSTATE_FIRING_SECONDARY */ + SADAR_Idle, /* WEAPONSTATE_RECOIL_SECONDARY */ + SADAR_Idle, /* WEAPONSTATE_RELOAD_SECONDARY */ + SADAR_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + SADAR_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + SADAR_Idle, /* WEAPONSTATE_JAMMED */ + SADAR_Idle, /* WEAPONSTATE_WAITING */ + SADAR_Idle, /* WEAPONSTATE_READYING */ + SADAR_Idle, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 1*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 0, + /* RestPosition; */ + {200,0,0}, + + /* RecoilMaxZ; */ + 0, //200, + /* RecoilMaxRandomZ; */ + 0, //0, + /* RecoilMaxXTilt; */ + 0, //24, + /* RecoilMaxYTilt; */ + 0, //0, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_INGAME_SKEETER, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + "MarineWeapons", + /* HierarchyName */ + "SD", + /* InitialSequenceType */ + (int)HMSQT_MarineHUD, + /* InitialSubSequence */ + (int)MHSS_Stationary, + + #if USE_ENCUMBERANCE + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 0, /* MovementMultiple */ + 0, /* TurningMultiple */ + 0, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #else + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #endif + + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 0, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 1, + /* SecondaryMuzzleFlash */ + 1, + /* LogAccuracy */ + 1, + /* LogShots */ + 1, + }, + /*KJL************ + * TWO PISTOLS * + ************KJL*/ + { + /* PrimaryAmmoID; */ + AMMO_MARINE_PISTOL_PC, + /* SecondaryAmmoID; */ + AMMO_MARINE_PISTOL_PC, + + FireMarineTwoPistolsPrimary, /* FirePrimaryFunction */ + FireMarineTwoPistolsSecondary, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 65536,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + //(65536*5), /* WEAPONSTATE_RECOIL_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + ((65536)/3), /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + //(65536*5), /* WEAPONSTATE_RECOIL_SECONDARY */ + 65536, /* WEAPONSTATE_RELOAD_SECONDARY */ + + (65536), /* WEAPONSTATE_SWAPPING_IN */ /* Was >>2 */ + (65536), /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + MarineTwoPistols_Fidget, /* WEAPONSTATE_IDLE */ + MarineTwoPistols_Firing, /* WEAPONSTATE_FIRING_PRIMARY */ + NULL, /* WEAPONSTATE_RECOIL_PRIMARY */ + MarineTwoPistols_Reload, /* WEAPONSTATE_RELOAD_PRIMARY */ + MarineTwoPistols_SecondaryFiring, /* WEAPONSTATE_FIRING_SECONDARY */ + NULL, /* WEAPONSTATE_RECOIL_SECONDARY */ + NULL, /* WEAPONSTATE_RELOAD_SECONDARY */ + MarineTwoPistols_SwapIn, /* WEAPONSTATE_SWAPPING_IN */ + MarineTwoPistols_SwapOut, /* WEAPONSTATE_SWAPPING_OUT */ + NULL, /* WEAPONSTATE_JAMMED */ + NULL, /* WEAPONSTATE_WAITING */ + NULL, /* WEAPONSTATE_READYING */ + NULL, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + //1000*65536/60, + 12*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius */ + 0, + /* RestPosition; */ + //{300,400,800}, + {0,0,0}, + + /* RecoilMaxZ; */ + 90, //0, //60, + /* RecoilMaxRandomZ; */ + 60, //0, //31, + /* RecoilMaxXTilt; */ + 30, //0, //31, + /* RecoilMaxYTilt; */ + 30, //0, //15, + + /* StrikePosition */ + {0,0,0}, + + /* Name; */ + TEXTSTRING_INGAME_TWOPISTOLS, + + /* WeaponShapeName; */ + /* dummy shape*/ + "Shell", + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + "MarineWeapons", + /* HierarchyName */ + "Two pistol", + /* InitialSequenceType */ + (int)HMSQT_MarineHUD, + /* InitialSubSequence */ + (int)MHSS_Stationary, + + #if USE_ENCUMBERANCE + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #else + { /* Encum_Idle */ + 7*ONE_FIXED/8, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 7*ONE_FIXED/8, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + 2*ONE_FIXED/3, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED/2, /* MovementMultiple */ + 7*ONE_FIXED/8, /* TurningMultiple */ + 2*ONE_FIXED/3, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + #endif + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 0, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 1, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 1, + /* SecondaryMuzzleFlash */ + 1, + /* LogAccuracy */ + 1, + /* LogShots */ + 1, + }, + + #if 0 + /*KJL*********** + * TEMPLATE * + ***********KJL*/ + { + /* PrimaryAmmoID; */ + /* SecondaryAmmoID; */ + AMMO_NONE, + /* SecondaryAmmoID; */ + AMMO_NONE, + + NULL, /* FirePrimaryFunction */ + NULL, /* FireSecondaryFunction */ + NULL, /* WeaponInitFunction */ + + /* TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; in 16.16 */ + { + 0,/* WEAPONSTATE_IDLE */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_PRIMARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_PRIMARY */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_FIRING_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RECOIL_SECONDARY */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_RELOAD_SECONDARY */ + + 65536, /* WEAPONSTATE_SWAPPING_IN */ + 65536, /* WEAPONSTATE_SWAPPING_OUT */ + 65536, /* WEAPONSTATE_JAMMED */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_WAITING */ + + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_READYING */ + WEAPONSTATE_INSTANTTIMEOUT, /* WEAPONSTATE_UNREADYING */ + + }, + { + NULL, /* WEAPONSTATE_IDLE */ + NULL, /* WEAPONSTATE_FIRING_PRIMARY */ + NULL, /* WEAPONSTATE_RECOIL_PRIMARY */ + NULL, /* WEAPONSTATE_RELOAD_PRIMARY */ + NULL, /* WEAPONSTATE_FIRING_SECONDARY */ + NULL, /* WEAPONSTATE_RECOIL_SECONDARY */ + NULL, /* WEAPONSTATE_RELOAD_SECONDARY */ + NULL, /* WEAPONSTATE_SWAPPING_IN */ + NULL, /* WEAPONSTATE_SWAPPING_OUT */ + NULL, /* WEAPONSTATE_JAMMED */ + NULL, /* WEAPONSTATE_WAITING */ + NULL, /* WEAPONSTATE_READYING */ + NULL, /* WEAPONSTATE_UNREADYING */ + }, + /* ProbabilityOfJamming; */ + 32, + /* FiringRate; */ + 1*65536, + + /* SmartTargetSpeed; signed int, how fast the crosshair moves. */ + 4, + /* GunCrosshairSpeed; integer, how fast the gun moves. */ + 160, + /* SmartTargetRadius in pixels */ + 50, + /* RestPosition; */ + {300,400,800}, + + /* RecoilMaxZ; */ + 60, + /* RecoilMaxRandomZ; */ + 31, + /* RecoilMaxXTilt; */ + 31, + /* RecoilMaxYTilt; */ + 15, + + /* Name; */ + TEXTSTRING_INGAME_BLANK, + + /* WeaponShapeName; */ + "Plasma", + /* MuzzleFlashShapeName; */ + "Sntrymuz", + /* RiffName */ + NULL, + /* HierarchyName */ + NULL, + /* InitialSequenceType */ + -1, + /* InitialSubSequence */ + -1, + + { /* Encum_Idle */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FirePrime */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + { /* Encum_FireSec */ + ONE_FIXED, /* MovementMultiple */ + ONE_FIXED, /* TurningMultiple */ + ONE_FIXED, /* JumpingMultiple */ + 1, /* CanCrouch */ + 1, /* CanRun */ + }, + /* UseStateMovement :1; */ + 0, + /* IsSmartTarget :1; */ + 0, + /* PrimaryIsRapidFire :1; */ + 0, + /* PrimaryIsAutomatic :1; */ + 0, + /* PrimaryIsMeleeWeapon :1; */ + 0, + /* SecondaryIsRapidFire :1; */ + 0, + /* SecondaryIsAutomatic :1; */ + 0, + /* SecondaryIsMeleeWeapon :1; */ + 0, + /* HasShapeAnimation */ + 0, + /* HasTextureAnimation */ + 0, + /* FireWhenCloaked */ + 1, + /* FireInChangeVision */ + 1, + /* FirePrimaryLate */ + 0, + /* FireSecondaryLate */ + 0, + /* PrimaryMuzzleFlash */ + 0, + /* SecondaryMuzzleFlash */ + 0, + /* LogAccuracy */ + 0, + /* LogShots */ + 0, + }, + #endif +}; + +TEMPLATE_AMMO_DATA TemplateAmmo[MAX_NO_OF_AMMO_TEMPLATES] = +{ + /* AMMO_10MM_CULW */ + { + 99*65536, /* AmmoPerMagazine */ + { + { + 2,0,8,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_10MM_CULW, + }, + { + 2,0,8,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_10MM_CULW, + }, + { + 2,0,8,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_10MM_CULW, + }, + { + 2,0,8,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_10MM_CULW, + }, + }, + 0, /* MaxRange */ + TEXTSTRING_AMMO_SHORTNAME_10MM_CULW, /* ShortName */ + 0, /* CreatesProjectile */ + 0, + }, + /* AMMO_SHOTGUN */ + { + 20*65536, + { + { + 20,10,0,0,0,0, /* Impact point damage */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_SHOTGUN, + }, + { + 20,10,0,0,0,0, /* Impact point damage */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_SHOTGUN, + }, + { + 20,10,0,0,0,0, /* Impact point damage */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_SHOTGUN, + }, + { + 20,10,0,0,0,0, /* Impact point damage */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_SHOTGUN, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_SHOTGUN, /* ShortName */ + 0, + 0, + }, + /* AMMO_SMARTGUN */ + { + 500*65536, + { + //6,0,6,0,0,0, + { + 8,0,2,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_SMARTGUN, + }, + { + 8,0,2,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_SMARTGUN, + }, + { + 8,0,2,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_SMARTGUN, + }, + { + 8,0,2,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_SMARTGUN, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_SMARTGUN, /* ShortName */ + 0, + 0, + }, + /* AMMO_FLAMETHROWER */ + { + 100*65536, + { + { + 0,0,0,25,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FLAMETHROWER, + }, + { + 0,0,0,25,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FLAMETHROWER, + }, + { + 0,0,0,25,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FLAMETHROWER, + }, + { + 0,0,0,25,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FLAMETHROWER, + }, + }, + 500, + TEXTSTRING_AMMO_SHORTNAME_FLAMETHROWER, /* ShortName */ + 1, + 0, + }, + /* AMMO_PLASMA */ + { + 10*65536, /* AmmoPerMagazine */ + { + { + 0,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PLASMA, + }, + { + 0,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PLASMA, + }, + { + 0,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PLASMA, + }, + { + 0,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PLASMA, + }, + }, /* MaxDamage */ + 5000, /* MaxRange */ + TEXTSTRING_BLANK, /* ShortName */ + 1, /* CreatesProjectile */ + 0, + }, + /* AMMO_SADAR_TOW */ + { + 1*65536, + { + { + 0,0,500,0,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SADAR_TOW, + }, + { + 0,0,500,0,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SADAR_TOW, + }, + { + 0,0,500,0,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SADAR_TOW, + }, + { + 0,0,500,0,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SADAR_TOW, + }, + }, + 14000, //Was 7500, + TEXTSTRING_AMMO_SHORTNAME_SADAR_TOW, /* ShortName */ + 1, + 0 + }, + /* AMMO_GRENADE */ + { + 6*65536, + { + { + 110,0,1,5,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_GRENADE, + }, + { + 110,0,1,5,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_GRENADE, + }, + { + 110,0,1,5,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_GRENADE, + }, + { + 110,0,1,5,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_GRENADE, + }, + }, + 10000, + TEXTSTRING_AMMO_SHORTNAME_GRENADE, /* ShortName */ + 1, + 1 + }, + /* AMMO_MINIGUN */ + { + 800*65536, + { + //11,0,1,0,0,0, + { + 20,0,8,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MINIGUN, + }, + { + 20,0,8,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MINIGUN, + }, + { + 20,0,8,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MINIGUN, + }, + { + 20,0,8,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MINIGUN, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_MINIGUN, /* ShortName */ + 0, + 0 + }, + /* AMMO_PULSE_GRENADE */ + { + 5*65536, + { + { + 50,0,1,0,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PULSE_GRENADE, + }, + { + 50,0,1,0,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PULSE_GRENADE, + }, + { + 50,0,1,0,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PULSE_GRENADE, + }, + { + 50,0,1,0,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PULSE_GRENADE, + }, + }, + 5000, + TEXTSTRING_AMMO_SHORTNAME_PULSE_GRENADE, /* ShortName */ + 1, + 1 + }, + /* AMMO_FLARE_GRENADE */ + { + 6*65536, + { + { + 0,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FLARE_GRENADE, + }, + { + 0,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FLARE_GRENADE, + }, + { + 0,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FLARE_GRENADE, + }, + { + 0,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FLARE_GRENADE, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_FLARE_GRENADE, /* ShortName */ + 1, + 0 + }, + /* AMMO_FRAGMENTATION_GRENADE */ + { + 6*65536, + { + { + 40,10,1,10,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRAGMENTATION_GRENADE, + }, + { + 40,10,1,10,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRAGMENTATION_GRENADE, + }, + { + 40,10,1,10,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRAGMENTATION_GRENADE, + }, + { + 40,10,1,10,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRAGMENTATION_GRENADE, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_FRAGMENTATION_GRENADE, /* ShortName */ + 1, + 1 + }, + /* AMMO_PROXIMITY_GRENADE */ + { + 6*65536, + { + { + 40,0,1,5,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PROXIMITY_GRENADE, + }, + { + 40,0,1,5,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PROXIMITY_GRENADE, + }, + { + 40,0,1,5,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PROXIMITY_GRENADE, + }, + { + 40,0,1,5,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PROXIMITY_GRENADE, + }, + }, + 5000, + TEXTSTRING_AMMO_SHORTNAME_PROXIMITY_GRENADE, /* ShortName */ + 1, + 1 + }, + /* AMMO_PARTICLE_BEAM */ + { + 100*65536, + { + { + 0,0,0,0,15,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PARTICLE_BEAM, + }, + { + 0,0,0,0,15,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PARTICLE_BEAM, + }, + { + 0,0,0,0,15,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PARTICLE_BEAM, + }, + { + 0,0,0,0,15,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PARTICLE_BEAM, + }, + }, + 0, + TEXTSTRING_BLANK, /* ShortName */ + 0, + 0 + }, + /* AMMO_SONIC_PULSE */ + { + 100*65536, /* AmmoPerMagazine */ + { + { + 0,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SONIC_PULSE, + }, + { + 0,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SONIC_PULSE, + }, + { + 0,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SONIC_PULSE, + }, + { + 0,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SONIC_PULSE, + }, + }, /* MaxDamage */ + 0, /* MaxRange */ + TEXTSTRING_BLANK, /* ShortName */ + 1, /* CreatesProjectile */ + 0 + }, + + /* PREDATOR */ + + /* AMMO_PRED_WRISTBLADE */ + { + 0, + { + { + 0,10,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_WRISTBLADE, + }, + { + 0,10,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_WRISTBLADE, + }, + { + 0,10,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_WRISTBLADE, + }, + { + 0,10,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_WRISTBLADE, + }, + }, + 2500, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + #if 0 + /* AMMO_PRED_PISTOL */ + { + 100*65536, /* AmmoPerMagazine */ + { + { + 20,0,0,5,2,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_PISTOL, + }, + { + 20,0,0,5,2,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_PISTOL, + }, + { + 20,0,0,5,2,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_PISTOL, + }, + { + 20,0,0,5,2,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_PISTOL, + }, + }, /* MaxDamage */ + 5000, /* MaxRange */ + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, /* CreatesProjectile */ + 0 + }, + #else + /* AMMO_PRED_PISTOL */ + { + 100*65536, /* AmmoPerMagazine */ + { + { + 0,0,0,0,20,0, + 3, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_PISTOL, + }, + { + 0,0,0,0,20,0, + 3, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_PISTOL, + }, + { + 0,0,0,0,20,0, + 3, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_PISTOL, + }, + { + 0,0,0,0,20,0, + 3, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_PISTOL, + }, + }, /* MaxDamage */ + 5000, /* MaxRange */ + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, /* CreatesProjectile */ + 0 /* ExplosionIsFlat */ + }, + #endif + /* AMMO_PRED_RIFLE */ + { + 20*65536, /* AmmoPerMagazine */ + { + { + //0,0,40,0,10,0, //That's just wuss! + 0,0,200,0,20,0, + 0, /* ExplosivePower */ + 2, /* Slicing */ + 1, /* ProduceBlood */ + 1, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_PRED_RIFLE, + }, + { + 0,0,200,0,20,0, + 0, /* ExplosivePower */ + 2, /* Slicing */ + 1, /* ProduceBlood */ + 1, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_PRED_RIFLE, + }, + { + 0,0,200,0,20,0, + 0, /* ExplosivePower */ + 2, /* Slicing */ + 1, /* ProduceBlood */ + 1, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_PRED_RIFLE, + }, + { + 0,0,200,0,20,0, + 0, /* ExplosivePower */ + 2, /* Slicing */ + 1, /* ProduceBlood */ + 1, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_PRED_RIFLE, + }, + }, /* MaxDamage */ + 0, /* MaxRange */ + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, /* CreatesProjectile */ + 0 + }, + /* AMMO_PRED_ENERGY_BOLT */ + { + 99*65536, + { + { + 50,0,300,50,100,0, + 4, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_ENERGY_BOLT, + }, + { + 50,0,300,50,100,0, + 4, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_ENERGY_BOLT, + }, + { + 50,0,300,50,100,0, + 4, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_ENERGY_BOLT, + }, + { + 50,0,300,50,100,0, + 4, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_ENERGY_BOLT, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, + 0 + }, + /* AMMO_PRED_DISC */ + { + 1*65536, + { + { + 0,300,0,0,0,0, + 0, /* ExplosivePower */ + 3, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_DISC, + }, + { + 0,300,0,0,0,0, + 0, /* ExplosivePower */ + 3, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_DISC, + }, + { + 0,300,0,0,0,0, + 0, /* ExplosivePower */ + 3, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_DISC, + }, + { + 0,300,0,0,0,0, + 0, /* ExplosivePower */ + 3, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_DISC, + }, + }, + 1000, + TEXTSTRING_INGAME_DISC, +// TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, + 1 + }, + + + /* ALIEN */ + + /* AMMO_ALIEN_CLAW */ + { + 0, + { + { + 0,21,0,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_CLAW, + }, + { + 0,21,0,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_CLAW, + }, + { + 0,21,0,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_CLAW, + }, + { + 0,21,0,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_CLAW, + }, + }, + 4000, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_ALIEN_TAIL */ + { + 0, + { + { + 0,30,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_TAIL, + }, + { + 0,30,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_TAIL, + }, + { + 0,30,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_TAIL, + }, + { + 0,30,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_TAIL, + }, + }, + 5000, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_ALIEN_SPIT */ + { + 10, + { + { + 0,30,0,0,0,20, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_SPIT, + }, + { + 0,30,0,0,0,20, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_SPIT, + }, + { + 0,30,0,0,0,20, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_SPIT, + }, + { + 0,30,0,0,0,20, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_SPIT, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, + 0 + }, + + /* MISC AND OUT OF SEQUENCE THINGS */ + + /* AMMO_AUTOGUN */ + { + 0, + { + { + 2,0,8,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_AUTOGUN, + }, + { + 2,0,8,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_AUTOGUN, + }, + { + 2,0,8,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_AUTOGUN, + }, + { + 2,0,8,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_AUTOGUN, + }, + }, + 0, + TEXTSTRING_BLANK, /* ShortName */ + 0, + 0 + }, + /* AMMO_XENOBORG */ + { + 0, + { + { + 0,10,0,0,10,0, // A bit wuss. Placeholder. + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_XENOBORG, + }, + { + 0,10,0,0,10,0, // A bit wuss. Placeholder. + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_XENOBORG, + }, + { + 0,10,0,0,10,0, // A bit wuss. Placeholder. + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_XENOBORG, + }, + { + 0,10,0,0,10,0, // A bit wuss. Placeholder. + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_XENOBORG, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_FACEHUGGER */ + { + 0, + { + { + 0,40,0,0,0,20, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FACEHUGGER, + }, + { + 0,40,0,0,0,20, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FACEHUGGER, + }, + { + 0,40,0,0,0,20, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FACEHUGGER, + }, + { + 0,40,0,0,0,20, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FACEHUGGER, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_NPC_OBSTACLE_CLEAR */ + { + 0, + { + { + 0,30,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_OBSTACLE_CLEAR, + }, + { + 0,30,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_OBSTACLE_CLEAR, + }, + { + 0,30,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_OBSTACLE_CLEAR, + }, + { + 0,30,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_OBSTACLE_CLEAR, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_ALIEN_FRAG */ + { + 0, + { + { + 0,0,0,0,0,10, // Change me! + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_FRAG, + }, + { + 0,0,0,0,0,10, // Change me! + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_FRAG, + }, + { + 0,0,0,0,0,10, // Change me! + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_FRAG, + }, + { + 0,0,0,0,0,10, // Change me! + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_FRAG, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_ALIEN_DEATH */ + { + 0, + { + { + 0,0,0,0,0,10, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_DEATH, + }, + { + 0,0,0,0,0,10, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_DEATH, + }, + { + 0,0,0,0,0,10, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_DEATH, + }, + { + 0,0,0,0,0,10, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_DEATH, + }, + }, + 3000, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_SHOTGUN_BLAST */ + { + 20*65536, + { + { + 10,0,0,5,0,0, /* Blast damage */ + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SHOTGUN_BLAST, + }, + { + 10,0,0,5,0,0, /* Blast damage */ + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SHOTGUN_BLAST, + }, + { + 10,0,0,5,0,0, /* Blast damage */ + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SHOTGUN_BLAST, + }, + { + 10,0,0,5,0,0, /* Blast damage */ + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SHOTGUN_BLAST, + }, + }, + 5000, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_SADAR_BLAST */ + { + 1*65536, + { + { + 60,0,0,10,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SADAR_BLAST, + }, + { + 60,0,0,10,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SADAR_BLAST, + }, + { + 60,0,0,10,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SADAR_BLAST, + }, + { + 60,0,0,10,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_SADAR_BLAST, + }, + }, + 10000, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, + 0 + }, + /* AMMO_ALIEN_BITE_KILLSECTION */ + { + 1*65536, + { + /*Make the damage 501 instead of 500 , so it can be identified as different from all other damage types*/ + { + 0,0,501,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_BITE_KILLSECTION, + }, + { + 0,0,501,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_BITE_KILLSECTION, + }, + { + 0,0,501,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_BITE_KILLSECTION, + }, + { + 0,0,501,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_BITE_KILLSECTION, + }, + }, + 5000, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, + 0 + }, + + /* AMMO_PRED_DISC_PM */ + { + 1*65536, + { + { + 100,0,0,20,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_DISC_PM, + }, + { + 100,0,0,20,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_DISC_PM, + }, + { + 100,0,0,20,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_DISC_PM, + }, + { + 100,0,0,20,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_DISC_PM, + }, + }, + 12000, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, + 1 + }, + /* AMMO_NPC_ALIEN_CLAW */ + { + 0, + { + { + 0,10,0,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_ALIEN_CLAW, + }, + { + 0,10,0,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_ALIEN_CLAW, + }, + { + 0,10,0,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_ALIEN_CLAW, + }, + { + 0,10,0,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_ALIEN_CLAW, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_NPC_PAQ_CLAW */ + { + 0, + { + { + 0,70,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PAQ_CLAW, + }, + { + 0,70,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PAQ_CLAW, + }, + { + 0,70,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PAQ_CLAW, + }, + { + 0,70,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PAQ_CLAW, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_PULSE_GRENADE_STRIKE */ + { + 0, + { + { + 50,0,30,10,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PULSE_GRENADE_STRIKE, + }, + { + 50,0,30,10,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PULSE_GRENADE_STRIKE, + }, + { + 50,0,30,10,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PULSE_GRENADE_STRIKE, + }, + { + 50,0,30,10,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PULSE_GRENADE_STRIKE, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_NPC_ALIEN_TAIL */ + { + 0, + { + { + 0,10,30,0,0,2, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_ALIEN_TAIL, + }, + { + 0,10,30,0,0,2, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_ALIEN_TAIL, + }, + { + 0,10,30,0,0,2, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_ALIEN_TAIL, + }, + { + 0,10,30,0,0,2, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_ALIEN_TAIL, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_NPC_ALIEN_BITE */ + { + 0, + { + { + 0,20,10,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_ALIEN_BITE, + }, + { + 0,20,10,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_ALIEN_BITE, + }, + { + 0,20,10,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_ALIEN_BITE, + }, + { + 0,20,10,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_ALIEN_BITE, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_NPC_PREDALIEN_CLAW */ + { + 0, + { + { + 20,20,0,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PREDALIEN_CLAW, + }, + { + 20,20,0,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PREDALIEN_CLAW, + }, + { + 20,20,0,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PREDALIEN_CLAW, + }, + { + 20,20,0,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PREDALIEN_CLAW, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_NPC_PREDALIEN_BITE */ + { + 0, + { + { + 0,20,20,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PREDALIEN_BITE, + }, + { + 0,20,20,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PREDALIEN_BITE, + }, + { + 0,20,20,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PREDALIEN_BITE, + }, + { + 0,20,20,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PREDALIEN_BITE, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_NPC_PREDALIEN_TAIL */ + { + 0, + { + { + 10,10,40,0,0,2, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PREDALIEN_TAIL, + }, + { + 10,10,40,0,0,2, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PREDALIEN_TAIL, + }, + { + 10,10,40,0,0,2, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PREDALIEN_TAIL, + }, + { + 10,10,40,0,0,2, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PREDALIEN_TAIL, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_NPC_PRAETORIAN_CLAW */ + { + 0, + { + { + 0,20,20,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRAETORIAN_CLAW, + }, + { + 0,20,20,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRAETORIAN_CLAW, + }, + { + 0,20,20,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRAETORIAN_CLAW, + }, + { + 0,20,20,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRAETORIAN_CLAW, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_NPC_PRAETORIAN_BITE */ + { + 0, + { + { + 0,30,20,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRAETORIAN_BITE, + }, + { + 0,30,20,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRAETORIAN_BITE, + }, + { + 0,30,20,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRAETORIAN_BITE, + }, + { + 0,30,20,0,0,2, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRAETORIAN_BITE, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_NPC_PRAETORIAN_TAIL */ + { + 0, + { + { + 0,10,60,0,0,2, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRAETORIAN_TAIL, + }, + { + 0,10,60,0,0,2, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRAETORIAN_TAIL, + }, + { + 0,10,60,0,0,2, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRAETORIAN_TAIL, + }, + { + 0,10,60,0,0,2, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRAETORIAN_TAIL, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_PRED_STAFF */ + { + 0, + { + { + 0,120,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_STAFF, + }, + { + 0,120,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_STAFF, + }, + { + 0,120,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_STAFF, + }, + { + 0,120,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_STAFF, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_NPC_PRED_STAFF */ + { + 0, + { + { + 0,80,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRED_STAFF, + }, + { + 0,80,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRED_STAFF, + }, + { + 0,80,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRED_STAFF, + }, + { + 0,80,0,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_NPC_PRED_STAFF, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_PC_ALIEN_BITE */ + { + 0, + { + { + 0,0,45,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PC_ALIEN_BITE, + }, + { + 0,0,45,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PC_ALIEN_BITE, + }, + { + 0,0,45,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PC_ALIEN_BITE, + }, + { + 0,0,45,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PC_ALIEN_BITE, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_HEAVY_PRED_WRISTBLADE */ + { + 0, + { + { + 0,80,0,0,0,60, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_HEAVY_PRED_WRISTBLADE, + }, + { + 0,80,0,0,0,60, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_HEAVY_PRED_WRISTBLADE, + }, + { + 0,80,0,0,0,60, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_HEAVY_PRED_WRISTBLADE, + }, + { + 0,80,0,0,0,60, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_HEAVY_PRED_WRISTBLADE, + }, + }, + 2500, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_MARINE_PISTOL */ + { + 12*65536, /* AmmoPerMagazine */ + { + { + 4,0,16,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MARINE_PISTOL, + }, + { + 4,0,16,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MARINE_PISTOL, + }, + { + 4,0,16,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MARINE_PISTOL, + }, + { + 4,0,16,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MARINE_PISTOL, + }, + }, + 0, /* MaxRange */ + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, /* CreatesProjectile */ + 0 + }, + /* AMMO_PREDPISTOL_STRIKE */ + { + 100*65536, /* AmmoPerMagazine */ + { + { + 0,0,0,0,30,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PREDPISTOL_STRIKE, + }, + { + 0,0,0,0,30,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PREDPISTOL_STRIKE, + }, + { + 0,0,0,0,30,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PREDPISTOL_STRIKE, + }, + { + 0,0,0,0,30,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PREDPISTOL_STRIKE, + }, + }, /* MaxDamage */ + 5000, /* MaxRange */ + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, /* CreatesProjectile */ + 0 /* ExplosionIsFlat */ + }, + /* AMMO_PLASMACASTER_NPCKILL */ + { + 99*65536, + { + { + 0,0,12,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 4, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PLASMACASTER_NPCKILL, + }, + { + 0,0,12,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 4, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PLASMACASTER_NPCKILL, + }, + { + 0,0,12,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 4, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PLASMACASTER_NPCKILL, + }, + { + 0,0,12,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 4, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PLASMACASTER_NPCKILL, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, + 0 + }, + /* AMMO_PLASMACASTER_PCKILL */ + { + 99*65536, + { + { + 15,0,65,15,25,0, /* MaxDamage - I,C,P,F,E,A */ + 4, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PLASMACASTER_PCKILL, + }, + { + 15,0,65,15,25,0, /* MaxDamage - I,C,P,F,E,A */ + 4, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PLASMACASTER_PCKILL, + }, + { + 15,0,65,15,25,0, /* MaxDamage - I,C,P,F,E,A */ + 4, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PLASMACASTER_PCKILL, + }, + { + 15,0,65,15,25,0, /* MaxDamage - I,C,P,F,E,A */ + 4, /* ExplosivePower */ + 0, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PLASMACASTER_PCKILL, + }, + }, + 2000, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, + 0 + }, + /* AMMO_10MM_CULW_NPC */ + { + 99*65536, /* AmmoPerMagazine */ + { + { + 2,0,8,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_10MM_CULW_NPC, + }, + { + 2,0,8,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_10MM_CULW_NPC, + }, + { + 2,0,8,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_10MM_CULW_NPC, + }, + { + 2,0,8,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_10MM_CULW_NPC, + }, + }, + 0, /* MaxRange */ + TEXTSTRING_AMMO_SHORTNAME_10MM_CULW, /* ShortName */ + 0, /* CreatesProjectile */ + 0, + }, + /* AMMO_SMARTGUN_NPC */ + { + 500*65536, + { + //6,0,6,0,0,0, + { + 8,0,2,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_SMARTGUN_NPC, + }, + { + 8,0,2,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_SMARTGUN_NPC, + }, + { + 8,0,2,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_SMARTGUN_NPC, + }, + { + 8,0,2,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_SMARTGUN_NPC, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_SMARTGUN, /* ShortName */ + 0, + 0, + }, + /* AMMO_MINIGUN_NPC */ + { + 800*65536, + { + //11,0,1,0,0,0, + { + 20,0,8,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MINIGUN_NPC, + }, + { + 20,0,8,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MINIGUN_NPC, + }, + { + 20,0,8,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MINIGUN_NPC, + }, + { + 20,0,8,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MINIGUN_NPC, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_MINIGUN, /* ShortName */ + 0, + 0 + }, + /* AMMO_MOLOTOV */ + { + 6*65536, + { + { + 1,0,1,5,0,0, + 5, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_MOLOTOV, + }, + { + 1,0,1,5,0,0, + 5, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_MOLOTOV, + }, + { + 1,0,1,5,0,0, + 5, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_MOLOTOV, + }, + { + 1,0,1,5,0,0, + 5, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_MOLOTOV, + }, + }, + 5000, + TEXTSTRING_AMMO_SHORTNAME_GRENADE, /* ShortName */ + 1, + 1 + }, + /* AMMO_ALIEN_OBSTACLE_CLEAR */ + { + 0, + { + { + 0,30,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_OBSTACLE_CLEAR, + }, + { + 0,30,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_OBSTACLE_CLEAR, + }, + { + 0,30,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_OBSTACLE_CLEAR, + }, + { + 0,30,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_OBSTACLE_CLEAR, + }, + }, + 0, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_PRED_TROPHY_KILLSECTION */ + { + 1*65536, + { + /*Make the damage 501 instead of 500 , so it can be identified as different from all other damage types*/ + { + 0,0,501,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_TROPHY_KILLSECTION, + }, + { + 0,0,501,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_TROPHY_KILLSECTION, + }, + { + 0,0,501,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_TROPHY_KILLSECTION, + }, + { + 0,0,501,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_PRED_TROPHY_KILLSECTION, + }, + }, + 5000, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, + 0 + }, + /* AMMO_CUDGEL */ + { + 0, + { + { + 10,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_CUDGEL, + }, + { + 10,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_CUDGEL, + }, + { + 10,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_CUDGEL, + }, + { + 10,0,0,0,0,0, + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_CUDGEL, + }, + }, + 2500, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 0, + 0 + }, + /* AMMO_ALIEN_BITE_KILLSECTION_SUPER */ + { + 1*65536, + { + /*Make the damage 501 instead of 500 , so it can be identified as different from all other damage types*/ + { + 0,0,501,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_BITE_KILLSECTION, + }, + { + 0,0,501,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_BITE_KILLSECTION, + }, + { + 0,0,501,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_BITE_KILLSECTION, + }, + { + 0,0,501,0,0,0, + 0, /* ExplosivePower */ + 1, /* Slicing */ + 1, /* ProduceBlood */ + 0, /* ForceBoom */ + 1, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_ALIEN_BITE_KILLSECTION, + }, + }, + 5000, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, + 0 + }, + /* AMMO_MARINE_PISTOL_PC */ + { + 12*65536, /* AmmoPerMagazine */ + { + { + 4,0,16,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MARINE_PISTOL_PC, + }, + { + 4,0,16,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MARINE_PISTOL_PC, + }, + { + 4,0,16,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MARINE_PISTOL_PC, + }, + { + 4,0,16,0,0,0, /* MaxDamage - I,C,P,F,E,A */ + 0, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 1, /* MakeExitWounds */ + AMMO_MARINE_PISTOL_PC, + }, + }, + 0, /* MaxRange */ + TEXTSTRING_AMMO_SHORTNAME_MARINE_PISTOL, /* ShortName */ + 0, /* CreatesProjectile */ + 0 + }, + /* AMMO_FRISBEE */ + { + 1*65536, + { + { + 0,0,500,0,0,0, + 6, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRISBEE, + }, + { + 0,0,500,0,0,0, + 6, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRISBEE, + }, + { + 0,0,500,0,0,0, + 6, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRISBEE, + }, + { + 0,0,500,0,0,0, + 6, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRISBEE, + }, + }, + 14000, //Was 7500, + TEXTSTRING_AMMO_SHORTNAME_SKEETER, /* ShortName */ + 1, + 0 + }, + /* AMMO_FRISBEE_BLAST */ + { + 1*65536, + { + { + 60,0,0,10,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRISBEE_BLAST, + }, + { + 60,0,0,10,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRISBEE_BLAST, + }, + { + 60,0,0,10,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRISBEE_BLAST, + }, + { + 60,0,0,10,0,0, + 2, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRISBEE_BLAST, + }, + }, + 10000, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, + 0 + }, + /* AMMO_FRISBEE_FIRE */ + { + 5*65536, + { + { + 50,0,1,0,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRISBEE_FIRE, + }, + { + 50,0,1,0,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRISBEE_FIRE, + }, + { + 50,0,1,0,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRISBEE_FIRE, + }, + { + 50,0,1,0,0,0, + 1, /* ExplosivePower */ + 0, /* Slicing */ + 0, /* ProduceBlood */ + 0, /* ForceBoom */ + 0, /* BlowUpSections */ + 0, /* Special */ + 0, /* MakeExitWounds */ + AMMO_FRISBEE_FIRE, + }, + }, + 5000, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, /* ShortName */ + 1, + 1 + }, + +}; + +/* CDF 4/8/98 - placing these here to centralise all DAMAGE_PROFILEs */ + +DAMAGE_PROFILE certainDeath = {0,0,10000,0,0,0, 0,0,0,0,0,0,0,AMMO_NONE}; +DAMAGE_PROFILE console_nuke = {0,0,0,0,1000,0, 0,0,0,0,0,0,0,AMMO_NONE}; +DAMAGE_PROFILE firedamage = {0,0,0,5,0,0, 0,0,0,0,0,0,0,AMMO_FIREDAMAGE_POSTMAX}; + +//Deamage caused by placed objects that explode when destroyed +DAMAGE_PROFILE SmallExplosionDamage = {50,0,1,0,0,0, 1,0,0,0,0,0,AMMO_NONE}; +DAMAGE_PROFILE BigExplosionDamage = {60,0,10,0,0,0, 2,0,0,0,0,0,AMMO_NONE}; + +/* KJL 17:05:19 27/08/98 - Flechette damage */ +DAMAGE_PROFILE FlechetteDamage={0,10,0,0,0,0,0,0,0,0,0,0,1,AMMO_FLECHETTE_POSTMAX}; + +/* CDF 16:45 9/11/98 - Fan damage, from bh_fan.c */ +DAMAGE_PROFILE fan_damage={0,100,0,0,0,0,2,1,1,0,0,0,AMMO_NONE}; + +/* KJL 18:29:27 10/11/98 - Falling damage */ +/* CDF 17:52:00 22/2/99 Changed to Pen from Electrical, to fix NPC death selection */ +DAMAGE_PROFILE FallingDamage={0,0,1,0,0,0,0,0,0,0,0,0,0,AMMO_FALLING_POSTMAX}; + +/* CDF 7/12/98 Pred Pistol Flechette Damage */ +DAMAGE_PROFILE PredPistol_FlechetteDamage={0,0,0,0,1,0,0,0,0,0,0,0,1,AMMO_NONE}; + +/*Damage profiles related to queen level*/ +DAMAGE_PROFILE QueenButtDamage={40,0,0,0,0,0,0,0,0,0,0,0,AMMO_NONE}; +//the impact damage entry is filled in when the damage is done +DAMAGE_PROFILE QueenImpactDamage={0,0,0,0,0,0,0,0,0,0,0,0,AMMO_NONE}; +DAMAGE_PROFILE VacuumDamage={0,0,0,0,20,0,0,0,0,0,0,0,AMMO_NONE}; + + +//Damage for death volumes that do damage per second +DAMAGE_PROFILE DeathVolumeDamage={0,0,1,0,0,0,0,0,0,0,0,0,0,AMMO_NONE}; + +/* KJL 11:23:25 04/07/97 - hackette for the grenade launcher which has 4 ammo types */ +GRENADE_LAUNCHER_DATA GrenadeLauncherData; +PRED_DISC_MODES ThisDiscMode; +SMARTGUN_MODES SmartgunMode; +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ + +/*KJL**************************************************************************************** +* F U N C T I O N S * +****************************************************************************************KJL*/ + +/*KJL********************************************************** +* Initialise the generic data used for weapon templates, etc. * +**********************************************************KJL*/ +void InitialiseEquipment(void) +{ + #if 0 + int i = MAX_NO_OF_WEAPON_TEMPLATES; + + while(i--) + { + TemplateWeapon[i].RestPosition.vx = 0; + TemplateWeapon[i].RestPosition.vy = 0; + TemplateWeapon[i].RestPosition.vz = 0; + } + #endif + /* KJL 15:47:30 03/19/97 - not much happening here */ +} + + + + + +/* + 10 mm culw rounds (Ceramic - Ultra Light Weight) 0.05 Kg each. (1.5 oz!!) + 20 mm culw rounds (Ceramic - Ultra Light Weight) 0.08 Kg each. (1.5 oz!!) + standard grenades 0.2 Kg each . + Heavy grenades 0.4 Kg each. + shotgun rounds 0.1 each + + 0 standard grenade 1 Kg + 1 99x10 mm magizines of culw rounds. 5 Kg + 2 500x10 mm magazines of culw rounds. 25 Kg + 3 5xstandard grenades 1 Kg + 4 5 Heavy grenades HE 2 Kg + 5 5 Heavy grenades Napalm 2 Kg + 6 5 HEavy grenades Canister 2 Kg + 7 5 Heavy Grenades Cluster 2 Kg + 8 5 Heavy Grenades WP 2 Kg + 9 20x shotgun rounds 2 Kg + 10 20 litres of fuel 18 Kg + 11 500x20 mm magizines of culw rounds 40 Kg + 12 Sonic Gun Power Packs 5 Kg + + +*/ +#if 0 +/* Prototype HModel for minigun */ + +KEYFRAME_DATA Handle_First_Frame = { + {0,0,0}, /* Offset */ + {0,0,0}, /* Deltas */ + {ONE_FIXED,0,0,0}, /* Quat? */ + {0,0,0,0,}, /* Next quat */ + 0, /* Omega */ + 0, /* oneoversinomega */ + 0, /* oneoversequencelength */ + 65535, /* Time to next frame */ + NULL, /* Pointer to next frame */ +}; + +KEYFRAME_DATA Barrel_Second_Frame = { + {129,50,674}, /* Offset */ + {0,0,0}, /* Deltas */ + {ONE_FIXED>>1,0,0,56756}, /* Quat? */ + {0,0,0,0,}, /* Next quat */ + 0, /* Omega */ + 0, /* oneoversinomega */ + 0, /* oneoversequencelength */ + ONE_FIXED, /* Time to next frame */ + NULL, /* Pointer to next frame */ +}; + +KEYFRAME_DATA Barrel_First_Frame = { + {129,50,674}, /* Offset */ + {0,0,0}, /* Deltas */ + {ONE_FIXED,0,0,0}, /* Quat? */ + {0,0,0,0,}, /* Next quat */ + 0, /* Omega */ + 0, /* oneoversinomega */ + 0, /* oneoversequencelength */ + ONE_FIXED, /* Time to next frame */ + &Barrel_Second_Frame, /* Pointer to next frame */ +}; + +SEQUENCE Handle_Sequence = { + 0, + &Handle_First_Frame +}; + +SEQUENCE Barrel_Sequence = { + 0, + &Barrel_First_Frame +}; + +SECTION H_Minigun_Barrel = { + 0, + NULL, + "Hminibar", + "MinigunBarrel", + NULL, + 1, + &Barrel_Sequence, + { + 100, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 1, /* Fire Resistant */ + 1, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + }, + }, + {0,0,0,}, + 0 +}; + +SECTION *Handle_Branches[] = { + &H_Minigun_Barrel, + NULL +}; + +SECTION H_Minigun_Handle = { + 0, + NULL, + "Hminihan", + "MinigunHandle", + Handle_Branches, + 1, + &Handle_Sequence, + { + 100, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 1, /* Fire Resistant */ + 1, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + }, + }, + {0,0,0,}, + section_is_master_root +}; + +#endif + + + + +BOOL AreDamageProfilesEqual(DAMAGE_PROFILE* profile1,DAMAGE_PROFILE* profile2) +{ + if(!profile1) return FALSE; + if(!profile2) return FALSE; + + if(profile1->Impact==profile2->Impact && + profile1->Cutting==profile2->Cutting && + profile1->Penetrative==profile2->Penetrative && + profile1->Fire==profile2->Fire && + profile1->Electrical==profile2->Electrical && + profile1->Acid==profile2->Acid && + profile1->ExplosivePower==profile2->ExplosivePower && + profile1->Slicing==profile2->Slicing && + profile1->ProduceBlood==profile2->ProduceBlood && + profile1->ForceBoom==profile2->ForceBoom && + profile1->BlowUpSections==profile2->BlowUpSections && + profile1->Special==profile2->Special && + profile1->MakeExitWounds==profile2->MakeExitWounds && + profile1->Id==profile2->Id) + { + return TRUE; + } + else + { + return FALSE; + } +} \ No newline at end of file diff --git a/3dc/avp/EQUIPMNT.H b/3dc/avp/EQUIPMNT.H new file mode 100644 index 0000000..24720c8 --- /dev/null +++ b/3dc/avp/EQUIPMNT.H @@ -0,0 +1,579 @@ +#ifndef _equipmnt_h_ +#define _equipmnt_h_ 1 + +#ifdef __cplusplus + + extern "C" { + +#endif +#include "language.h" +/* has to come after gameplat.h in the setup*/ +#include "gamedef.h" + +/* KJL 12:34:46 09/18/96 - new stuff under development */ + +/* KJL 12:39:41 09/18/96 - + Okay, I think we should have two weapon structures: + + TEMPLATE_WEAPON_DATA: First the basic template for each weapon, which remains constant + during the game & contains the base description of a weapon eg. + ammo type, weight, graphics, etc. + + PLAYER_WEAPON_DATA: Second is the structure which describes a player's weapon + eg. a pointer to a TEMPLATE_WEAPON_DATA, ammo remaining, jam + status, and so on. + + eg. PLAYER_WEAPON_DATA PlayerWeapons[]; + +*/ +/* KJL 16:09:51 09/20/96 - Weapon States */ +enum WEAPON_STATE +{ + WEAPONSTATE_IDLE=0, + + WEAPONSTATE_FIRING_PRIMARY, + WEAPONSTATE_RECOIL_PRIMARY, + WEAPONSTATE_RELOAD_PRIMARY, + + WEAPONSTATE_FIRING_SECONDARY, + WEAPONSTATE_RECOIL_SECONDARY, + WEAPONSTATE_RELOAD_SECONDARY, + + WEAPONSTATE_SWAPPING_IN, + WEAPONSTATE_SWAPPING_OUT, + WEAPONSTATE_JAMMED, + + WEAPONSTATE_WAITING, + + WEAPONSTATE_READYING, + WEAPONSTATE_UNREADYING, + + MAX_NO_OF_WEAPON_STATES +}; +#define WEAPONSTATE_INITIALTIMEOUTCOUNT 65536 +#define WEAPONSTATE_INSTANTTIMEOUT 0 + +/* KJL 10:42:38 09/19/96 - Weapon Enumerations */ +enum WEAPON_ID +{ + /* USED TO DENOTE AN EMPTY SLOT */ + NULL_WEAPON=-1, + + /* MARINE WEAPONS */ + WEAPON_PULSERIFLE, + WEAPON_AUTOSHOTGUN, + WEAPON_SMARTGUN, + WEAPON_FLAMETHROWER, + WEAPON_PLASMAGUN, + WEAPON_SADAR, + WEAPON_GRENADELAUNCHER, + WEAPON_MINIGUN, + WEAPON_SONICCANNON, + WEAPON_BEAMCANNON, + WEAPON_MYSTERYGUN, + + /* PREDATOR WEAPONS */ + WEAPON_PRED_WRISTBLADE, + WEAPON_PRED_PISTOL, + WEAPON_PRED_RIFLE, + WEAPON_PRED_SHOULDERCANNON, + WEAPON_PRED_DISC, + WEAPON_PRED_MEDICOMP, + WEAPON_PRED_STAFF, + + /* ALIEN WEAPONS */ + WEAPON_ALIEN_CLAW, + WEAPON_ALIEN_GRAB, + WEAPON_ALIEN_SPIT, + + WEAPON_CUDGEL, + WEAPON_MARINE_PISTOL, + WEAPON_FRISBEE_LAUNCHER, + WEAPON_TWO_PISTOLS, + + MAX_NO_OF_WEAPON_TEMPLATES +}; + +enum WEAPON_SLOT +{ + WEAPON_SLOT_1=0, + WEAPON_SLOT_2, + WEAPON_SLOT_3, + WEAPON_SLOT_4, + WEAPON_SLOT_5, + WEAPON_SLOT_6, + WEAPON_SLOT_7, + WEAPON_SLOT_8, + WEAPON_SLOT_9, + WEAPON_SLOT_10, + WEAPON_SLOT_11, + MAX_NO_OF_WEAPON_SLOTS, + + WEAPON_FINISHED_SWAPPING +}; + + +enum AMMO_ID +{ + AMMO_NONE=-1, + AMMO_10MM_CULW=0, + AMMO_SHOTGUN, + AMMO_SMARTGUN, + AMMO_FLAMETHROWER, + AMMO_PLASMA, + AMMO_SADAR_TOW, + AMMO_GRENADE, + AMMO_MINIGUN, + AMMO_PULSE_GRENADE, + AMMO_FLARE_GRENADE, + AMMO_FRAGMENTATION_GRENADE, + AMMO_PROXIMITY_GRENADE, + AMMO_PARTICLE_BEAM, + AMMO_SONIC_PULSE, + + AMMO_PRED_WRISTBLADE, + AMMO_PRED_PISTOL, + AMMO_PRED_RIFLE, + AMMO_PRED_ENERGY_BOLT, + AMMO_PRED_DISC, + + AMMO_ALIEN_CLAW, + AMMO_ALIEN_TAIL, + AMMO_ALIEN_SPIT, + + AMMO_AUTOGUN, + AMMO_XENOBORG, + AMMO_FACEHUGGER, + AMMO_NPC_OBSTACLE_CLEAR, + AMMO_ALIEN_FRAG, + AMMO_ALIEN_DEATH, + + AMMO_SHOTGUN_BLAST, + AMMO_SADAR_BLAST, + AMMO_ALIEN_BITE_KILLSECTION, + AMMO_PRED_DISC_PM, + + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_PAQ_CLAW, + AMMO_PULSE_GRENADE_STRIKE, + AMMO_NPC_ALIEN_TAIL, + AMMO_NPC_ALIEN_BITE, + AMMO_NPC_PREDALIEN_CLAW, + AMMO_NPC_PREDALIEN_BITE, + AMMO_NPC_PREDALIEN_TAIL, + AMMO_NPC_PRAETORIAN_CLAW, + AMMO_NPC_PRAETORIAN_BITE, + AMMO_NPC_PRAETORIAN_TAIL, + AMMO_PRED_STAFF, + AMMO_NPC_PRED_STAFF, + AMMO_PC_ALIEN_BITE, + AMMO_HEAVY_PRED_WRISTBLADE, + AMMO_MARINE_PISTOL, + AMMO_PREDPISTOL_STRIKE, + AMMO_PLASMACASTER_NPCKILL, + AMMO_PLASMACASTER_PCKILL, + + AMMO_10MM_CULW_NPC, + AMMO_SMARTGUN_NPC, + AMMO_MINIGUN_NPC, + AMMO_MOLOTOV, + AMMO_ALIEN_OBSTACLE_CLEAR, + AMMO_PRED_TROPHY_KILLSECTION, + + AMMO_CUDGEL, + AMMO_ALIEN_BITE_KILLSECTION_SUPER, + AMMO_MARINE_PISTOL_PC, + AMMO_FRISBEE, + AMMO_FRISBEE_BLAST, + AMMO_FRISBEE_FIRE, + + MAX_NO_OF_AMMO_TEMPLATES, + AMMO_FLECHETTE_POSTMAX, + AMMO_FALLING_POSTMAX, + AMMO_FIREDAMAGE_POSTMAX + +}; + +/* CDF - 15/9/97 New Damage System */ + +typedef struct { + short Impact; + short Cutting; + short Penetrative; + short Fire; + short Electrical; + short Acid; + /* New additions, 4/8/98 */ + unsigned int ExplosivePower :3; + /* XP: 0 is nothing, 1 is little, 2 is big (SADAR), + 3 is pred pistol, 4 is plasmacaster, 5 is molotov, 6 is big with no collisions, + 7+ unused. */ + unsigned int Slicing :2; + unsigned int ProduceBlood :1; + unsigned int ForceBoom :2; + unsigned int BlowUpSections :1; + unsigned int Special :1; + unsigned int MakeExitWounds :1; + + enum AMMO_ID Id; + +} DAMAGE_PROFILE; + +/* CDF - 15/9/97 New Damage System */ + +typedef struct { + unsigned int MovementMultiple; + unsigned int TurningMultiple; + unsigned int JumpingMultiple; + unsigned int CanCrouch:1; + unsigned int CanRun:1; +} ENCUMBERANCE_STATE; + +typedef struct +{ + int AmmoPerMagazine; + + DAMAGE_PROFILE MaxDamage[I_MaxDifficulties]; + int MaxRange; + + enum TEXTSTRING_ID ShortName; + /* Added 20/11/97 by DHM: Abberviated name for ammo, to appear in HUD status panel */ + + /* ammo flags */ + unsigned int CreatesProjectile :1; + unsigned int ExplosionIsFlat:1; +} TEMPLATE_AMMO_DATA; + +typedef struct +{ + enum WEAPON_ID WeaponIDNumber; + /* eg.==MARINE_WEAPON_PULSE. This can be used to access the TemplateWeapon[] data, graphics, etc. */ + + enum WEAPON_STATE CurrentState; + + int StateTimeOutCounter; /* in 16.16 */ + + unsigned int PrimaryRoundsRemaining; /* in 'current' magazine */ + unsigned int SecondaryRoundsRemaining; /* in 'current' magazine */ + unsigned char PrimaryMagazinesRemaining; + unsigned char SecondaryMagazinesRemaining; + + VECTORCH PositionOffset; + EULER DirectionOffset; + + SHAPEANIMATIONCONTROLLER ShpAnimCtrl; + TXACTRLBLK *TxAnimCtrl; + + /* general flags */ + signed int Possessed :2; /* meaning you are carrying the weapon, not that an evil spirit etc etc. */ + +} PLAYER_WEAPON_DATA; + +typedef struct +{ + enum AMMO_ID PrimaryAmmoID; + enum AMMO_ID SecondaryAmmoID; + + int (*FirePrimaryFunction)(PLAYER_WEAPON_DATA *); + int (*FireSecondaryFunction)(PLAYER_WEAPON_DATA *); + void (*WeaponInitFunction)(PLAYER_WEAPON_DATA *); + + int TimeOutRateForState[MAX_NO_OF_WEAPON_STATES]; /* in 16.16 */ + void (*WeaponStateFunction[MAX_NO_OF_WEAPON_STATES])(void *, PLAYER_WEAPON_DATA *); // void * is for PLAYER_STATUS + int ProbabilityOfJamming; + int FiringRate; + + /* display stuff */ + signed int SmartTargetSpeed; /* how fast crosshair moves */ + unsigned int GunCrosshairSpeed; /* how fast the gun moves to catch up */ + unsigned int SmartTargetRadius; + VECTORCH RestPosition; + + int RecoilMaxZ; + int RecoilMaxRandomZ; + int RecoilMaxXTilt; + int RecoilMaxYTilt; + + VECTORCH StrikePosition; + + enum TEXTSTRING_ID Name; + + /* shape reference */ + char * WeaponShapeName; + char * MuzzleFlashShapeName; + char * RiffName; + char * HierarchyName; + int InitialSequenceType; + int InitialSubSequence; + + /* Encumberance */ + + ENCUMBERANCE_STATE Encum_Idle; + ENCUMBERANCE_STATE Encum_FirePrime; + ENCUMBERANCE_STATE Encum_FireSec; + + /* flags */ + unsigned int UseStateMovement :1; + unsigned int IsSmartTarget :1; + unsigned int PrimaryIsRapidFire :1; + unsigned int PrimaryIsAutomatic :1; + unsigned int PrimaryIsMeleeWeapon :1; + unsigned int SecondaryIsRapidFire :1; + unsigned int SecondaryIsAutomatic :1; + unsigned int SecondaryIsMeleeWeapon :1; + unsigned int HasShapeAnimation: 1; + unsigned int HasTextureAnimation: 1; + unsigned int FireWhenCloaked: 1; + unsigned int FireInChangeVision: 1; + unsigned int FirePrimaryLate: 1; + unsigned int FireSecondaryLate: 1; + unsigned int PrimaryMuzzleFlash: 1; + unsigned int SecondaryMuzzleFlash: 1; + unsigned int LogAccuracy: 1; + unsigned int LogShots: 1; + +} TEMPLATE_WEAPON_DATA; + + + + + +typedef struct +{ + enum AMMO_ID SelectedAmmo; + + unsigned int StandardRoundsRemaining; + unsigned char StandardMagazinesRemaining; + + unsigned int FlareRoundsRemaining; + unsigned char FlareMagazinesRemaining; + + unsigned int ProximityRoundsRemaining; + unsigned char ProximityMagazinesRemaining; + + unsigned int FragmentationRoundsRemaining; + unsigned char FragmentationMagazinesRemaining; + +} GRENADE_LAUNCHER_DATA; + +typedef enum Pred_Disc_Modes { + I_Seek_Track, + I_Search_Destroy, + I_Proximity_Mine, +} PRED_DISC_MODES; + +typedef enum Smartgun_Modes { + I_Track, + I_Free, +} SMARTGUN_MODES; + +extern PRED_DISC_MODES ThisDiscMode; +extern SMARTGUN_MODES SmartgunMode; + +extern TEMPLATE_WEAPON_DATA TemplateWeapon[]; +extern TEMPLATE_AMMO_DATA TemplateAmmo[]; +extern GRENADE_LAUNCHER_DATA GrenadeLauncherData; + +extern enum WEAPON_ID MarineWeaponKey[MAX_NO_OF_WEAPON_SLOTS]; +extern enum WEAPON_ID PredatorWeaponKey[MAX_NO_OF_WEAPON_SLOTS]; +extern enum WEAPON_ID AlienWeaponKey[MAX_NO_OF_WEAPON_SLOTS]; + +extern DAMAGE_PROFILE certainDeath; +extern DAMAGE_PROFILE console_nuke; +extern DAMAGE_PROFILE firedamage; + +extern DAMAGE_PROFILE SmallExplosionDamage; +extern DAMAGE_PROFILE BigExplosionDamage; + +extern void InitialiseEquipment(void); + +/*compare two damage profiles to see if they are the same*/ +extern BOOL AreDamageProfilesEqual(DAMAGE_PROFILE* profile1,DAMAGE_PROFILE* profile2); + + + +#ifdef __cplusplus + + }; + +#endif +#endif + + +/*KJL***************************************************************************************** +* Roxby's old stuff follows. I'm keeping it here 'cos it's very useful as reference material * +*****************************************************************************************KJL*/ + +#if 0 +/* + Hmmm. Weapons need to be treated differnetly to Other Objects + Such as AMMO and Tools. They have things like Info Screen data + (Text and schematics) range, damage, weight, incumberance, DM + status, Jam status, reliabilty, Vulnerablity. + + This contains the data sturcture and the weapons information + for the marine weapons - It may be extended to cover all + the predator weapons as well +*/ + +/* + The player can carry up to 100 kg.. Strong huh. + + encumberance - a measure of how `encumbering' the weapon may + actually be. It is an abstrcted measure of how much it slows + the player down - It shouldnt effect the players fatigue - and + how difficult it is to change to another weapon. + + To use a weapon it the players total `USING' encumberance has to + less than 50 in a normal corridor and less the 30 in an airduct + +*/ + + +/* Ammo + + Ammo - this is where the weight is.... + All this rounding... lets play + with integers only + + These are only the initial specs, I imagine dramatic alterations. + Partic if we want to swap to weights to use shifts rather than divs + + + 10 mm culw rounds (Ceramic - Ultra Light Weight) 0.05 Kg each. (1.5 oz!!) + 20 mm culw rounds (Ceramic - Ultra Light Weight) 0.08 Kg each. (1.5 oz!!) + standard grenades 0.2 Kg each . + Heavy grenades 0.4 Kg each. + shotgun rounds 0.1 each + + 0 standard grenade 1 Kg + 1 99x10 mm magizines of culw rounds. 5 Kg + 2 500x10 mm magazines of culw rounds. 25 Kg + 3 5xstandard grenades 1 Kg + 4 5 Heavy grenades HE 2 Kg + 5 5 Heavy grenades Napalm 2 Kg + 6 5 HEavy grenades Canister 2 Kg + 7 5 Heavy Grenades Cluster 2 Kg + 8 5 Heavy Grenades WP 2 Kg + 9 20x shotgun rounds 2 Kg + 10 20 litres of fuel 18 Kg + 11 500x20 mm magizines of culw rounds 40 Kg + 12 Sonic Gun Power Packs 5 Kg + + +*/ + +/* + Weapons Information + + Weight Kilos + Incumberance - Abstract use difficulty. + +*/ + +#define MAX_PLAYER_WEAPONS 10 +#define MAX_AMMO_TYPES 20 + +typedef struct ammo_data{ + unsigned char weight; /*in 10ths of KG*/ + unsigned char num_magazines; + unsigned short magazine_size; + unsigned short spread_radius; + unsigned short damage; + unsigned char damage_flags; + unsigned char flight_flags; +} AMMO_DATA; + + + +/*damage flags*/ + +#define DAMAGE_POINT 0x01 /*point pixel damage*/ +#define DAMAGE_SPREAD 0x02 /*Equal damage along radius*/ +#define DAMAGE_TAPER 0x04 /*Decreasing damge on radius*/ +#define DAMAGE_EXPLOSIVE1 0x08 /*explodes*/ +#define DAMAGE_EXPLOSIVE2 0x10 /*big explodes*/ +#define DAMAGE_DELAY 0x20 /*limpet*/ +#define DAMAGE_FLAME 0x40 /*sets things on fire*/ + + +/*Flight Flags*/ + +#define FLIGHT_HAND_GRENADE 0x01 +#define FLIGHT_BULLET 0x02 +#define FLIGHT_GRENADE_LNCH 0x04 + + +typedef struct weapon_ammo_attributes{ + unsigned char ammotype; + unsigned char remaining_ammo; + unsigned char targeting_flags; + unsigned char rate_of_fire; /*frames Between rounds */ + unsigned char magazine_reload_time; /*frames to reload magazine*/ + unsigned short failure_risk; /*0 - 2**16*/ + unsigned char failure_flags; + +} WEAP_AMMO_ATTR; + +/* WEapon data contains the data to maintain, draw weapons + generation of these objects comes via the entity*/ + +/* + *schematic --- for the data retrival + *hudata - for drawing the HUD graphic . Note that this is PLATFORM dependent + *descriptive text --- to print up in the data retrival +*/ + +typedef struct weapon_data{ + + char weapon_flags; + char name[8]; /* can be made into something else if ness*/ + /* YES the address of the platform spec data + structure*/ + void *schematic; /* these contain the file name before the */ + HUDGRAPHIC *huddata; /* graphic is loaded into here -- LPDDS*/ + + char *descriptivetext; + + unsigned char weight; /*in 10ths of KG*/ + unsigned char encumbrance; /*time it takes to swap the + weapon in pixels per sec*/ + + + WEAP_AMMO_ATTR primary; + WEAP_AMMO_ATTR secondary; + + #if Saturn + char* WDroxptr; + #endif + +} WEAPON_DATA; + + +/*weapon_flags */ + +/*targeting flags*/ + +#define TARGETING_MANUAL 0x01 +#define TARGETING_XHAIR 0x02 +#define TARGETING_SMART 0x04 +#define TARGETING_XTOS 0x08 /*targeting depends on equip*/ +#define TARGETING_FAF_TRACK 0x10 /*Fire and forget....!*/ +#define TARGETING_THROWN 0x20 + +/* failure flags */ + +#endif + + + + + + + + + + + + + diff --git a/3dc/avp/GAMEDEF.H b/3dc/avp/GAMEDEF.H new file mode 100644 index 0000000..e888635 --- /dev/null +++ b/3dc/avp/GAMEDEF.H @@ -0,0 +1,342 @@ +#ifndef GAMEDEF_INCLUDED + + + +/* + Contains game specific defininitions of structures +*/ + + +#ifdef __cplusplus + + extern "C" { + +#endif + +#include "module.h" + +/*********************************************** + + AVP game description stuff + +***********************************************/ + +/* game modes*/ + +typedef enum gamemode +{ + I_GM_Playing, + I_GM_DataBase, + I_GM_Menus, + I_GM_Paused, + +} I_GAME_MODE; + +typedef enum gamedrawmode +{ + I_GDM_GameOperations, + I_GDM_DrawWorld, + I_GDM_DrawHud, + I_GDM_Flippin, + +} I_GAMEDRAW_MODE; + + +/* Languages*/ + +typedef enum languages +{ + I_English, + I_French, + I_Spanish, + I_German, + I_Italian, + I_Swedish, + I_MAX_NO_OF_LANGUAGES + +}I_LANGUAGE; + +extern char* LanguageDirNames[]; + + +typedef enum playertypes +{ + I_Marine, + I_Predator, + I_Alien, + +}I_PLAYER_TYPE; + +extern char* PlayerNames[]; + + +typedef enum networktype +{ + I_No_Network, + I_Host, + I_Peer, + I_DedicatedServer, + +}I_NETWORK; + + +typedef enum gamedifficulty +{ + I_Easy = 0, + I_Medium, + I_Hard, + I_Impossible, + I_MaxDifficulties + +}I_HARDANUFF; + +typedef enum environments +{ + //#ifndef MPLAYER_DEMO + I_Gen1 = 0, + I_Gen2, + I_Gen3, + I_Gen4, + I_Medlab, // 5 + I_Cmc1, + I_Cmc2, + I_Cmc3, + I_Cmc4, + I_Cmc5, // 10 + I_Cmc6, + I_Sp1, + I_Sp2, + I_Sp3, + I_Rnd1, // 15 + I_Rnd2, + I_Rnd3, + I_Rnd4, + I_Mps1, + I_Mps2, // 20 + I_Mps3, + I_Mps4, + I_Surface, + I_Entrance, +#if PSX || Saturn +#else + I_Dml1, // 25- Vertigo.rif for Al + // #ifndef MPLAYER_DEMO + I_Dml2, // KJL 16:59:58 05/1/97 - fruitbat.rif for Al + I_Dml3, // KJL 16:59:58 05/19/97 - kipper.rif for George + I_Dml4, // KJL 16:59:58 05/19/97 - mu.rif for Jake + I_Dml5, // KJL 16:59:58 05/19/97 - mu.rif for Jake + I_Dml6, // 30- KJL 16:59:58 05/19/97 - mu.rif for Jake + I_Dml7, // KJL 16:59:58 05/19/97 - mu.rif for Jake + I_Dml8, // KJL 16:59:58 05/19/97 - mu.rif for Jake + I_Dml9, // KJL 16:59:58 05/19/97 - mu.rif for Jake + I_Dml10, // KJL 16:59:58 05/19/97 - mu.rif for Jake + // #endif +#endif + I_Num_Environments // 34 + +}I_AVP_ENVIRONMENTS; + +extern char* LevelNames[]; + + +#if SupportWindows95 +#define GAME_NAME_LENGTH 30 +#else +#define GAME_NAME_LENGTH 12 +#endif + + +typedef struct avpgamedesc{ + + I_LANGUAGE Language; + I_GAME_MODE GameMode; + I_GAMEDRAW_MODE GameDrawMode; + int DatabaseAccessNum; // to make it easier to pass this around + I_PLAYER_TYPE PlayerType; + I_NETWORK Network; + I_HARDANUFF Difficulty; + I_AVP_ENVIRONMENTS CurrentEnv; + I_AVP_ENVIRONMENTS StartingEnv; + char GameName[GAME_NAME_LENGTH]; + int GameVideoRequestMode; + int MenuVideoRequestMode; + int DestructTimer; + unsigned int ElapsedMinutes; + unsigned int ElapsedSeconds; + unsigned int ElapsedHours; + /* KJL 15:36:53 03/11/97 - set to zero + on death, pressing quit, etc. */ + unsigned char MainLoopRunning :1; + /* set to 1 when player dies*/ + unsigned char RestartLevel :1; + + /* set to 1 if you manage to complete the level */ + unsigned char LevelCompleted :1; + + /* If network game, disable generators if unset */ + unsigned char NetworkAIServer :1; + +}AVP_GAME_DESC; + + + + +extern AVP_GAME_DESC AvP; /*game.c*/ + +extern DISPLAYBLOCK *Player; + +/***************************************************************/ +/************************ AVP high level control **************/ + +extern RECT_AVP screenRect; + +/* KJL 15:42:23 10/02/96 - These two are mine. */ +extern void MaintainPlayer(void); +extern void MaintainHUD(void); + + +/*********************************************************/ +/*********************** PLAYER CONTROL STUFF ************/ +extern int AnyUserInput(); +extern int IDemandGoBackward(); +extern int IDemandGoForward(); +extern int IDemandTurnRight(); +extern int IDemandTurnLeft(); + +//extern int IDemandLookUp(void); +//extern int IDemandLookDown(void); +//extern int IDemandTurnLeft(void); +//extern int IDemandTurnRight(void); +//extern int IDemandGoForward(void); +//extern int IDemandGoBackward(void); +//extern int IDemandFaster(void); +//extern int IDemandSideStep(void); +//extern int IDemandStop(void); + +//extern int IDemandNextWeapon(void); /* KJL 11:45:40 10/07/96 */ +//extern int IDemandPreviousWeapon(void); /* KJL 11:45:44 10/07/96 */ + + +//extern int IDemandPickupItem(void); +//extern int IDemandDropItem(void); +//extern int IDemandOperate(void); +//extern int IDemandMenu(void); +//extern int IDemandChangeEnvironment(void); + + + + +/************************************************* +************* ENVIRONMENT STUFF +**************************************************/ + +/* some old funnier stuff*/ +// kept as this struct so we can compile in environmnet +// changes + + +typedef struct environment_list_object{ + char* main; +}ELO; + + +extern ELO* Env_List[]; +extern int EnvToLoad; + +extern void ChnageEnvironment(); +extern void ChangeEnvironmentToEnv(I_AVP_ENVIRONMENTS); +extern int Destroy_CurrentEnvironment(); +extern void LoadGameFromFile(); +extern void SaveGameToFile(); +extern void InitCharacter(); +/*************************************************************/ + +/* KJL 15:42:46 10/02/96 - Okay, I don't use HUDGRAPHIC on the PC anymore and I suggest +you don't use it on your platform either 'cos it's a mess. (Sorry Roxby, no offense...) */ + +/************ HUD GRAPHIC STUFF *********************/ + +typedef struct +{ + void* data; /* just about anything you feel like points to the file name*/ + char* filename; + int xdest, ydest; /*screen x y*/ + int width, height; /*depth and height of dest incase of shrink*/ + RECT_AVP *srcRect; + int hg_flags; + +}HUDGRAPHIC; + +/* where to put the grahic*/ + +#define HGflag_NotInVRAM 0x0000001 /*saturn only*/ +#define HGflag_LoadIntoVDP2 0x0000002 /*saturn only*/ +#define HGflag_LoadIntoVDP1 0x0000004 /*saturn only*/ + +/* how to get the graphic */ + +#define HGflag_AlwaysLoadOffDisk 0x00000200 /*cd or HD*/ +#define HGflag_LoadedIntoMemory 0x00000400 /*loaded into memory*/ + +/* source directory for the graphic */ + +#define HGflag_MenuDir 0x00010000 + + + +/********************************************************/ +/************************ Menu Code ***************/ + +extern void ChooseLanguage(void); +extern void CharacterChoice(void); + +extern void InitDataBaseMenus(void); +extern void DoMainMenu(void); + +extern int UsingDataBase; + +/* How many info screens will there be? */ +#define MAXINFOSCREENS 10 +/* How many different info screen backgrounds there may be*/ +#define MAXBACKGROUNDS 10 +/* How many overlay items can be in existence at a time */ +#define MAXSCREENITEMS 10 + +#define NUM_CREDIT_SCREENS 2 + +extern HUDGRAPHIC Menu[]; +extern HUDGRAPHIC CreditScreen[]; + +typedef enum +{ + UNLIT, + LITUP, + +} LIGHTSTATE; + +/****************** MISC Game Externs ****/ + +extern MODULEMAPBLOCK TempModuleMap; +extern SHAPEHEADER** mainshapelist; + +extern int memoryInitialisationFailure; + +/*******************MISC extern functions ***/ + +extern void DealWithElapsedTime(); +extern void FadeScreen(int colour, int screen, int rate); +extern volatile char StillFading; + + +#ifdef __cplusplus + + }; + +#endif + +#define GAMEDEF_INCLUDED + +#endif + + + diff --git a/3dc/avp/Game.c b/3dc/avp/Game.c new file mode 100644 index 0000000..503d128 --- /dev/null +++ b/3dc/avp/Game.c @@ -0,0 +1,870 @@ +#include "3dc.h" +#include +#include "inline.h" +#include "module.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "dynblock.h" +#include "dynamics.h" + +#include "bh_types.h" +#include "bh_alien.h" +#include "pheromon.h" +#include "pfarlocs.h" +#include "bh_gener.h" +#include "pvisible.h" +#include "lighting.h" +#include "bh_pred.h" +#include "bh_lift.h" +#include "avpview.h" +#include "psnd.h" +#include "psndplat.h" +#include "particle.h" +#include "sfx.h" +#include "version.h" +#include "bh_RubberDuck.h" +#include "bh_marin.h" +#include "dxlog.h" +#include "avp_menus.h" +#include "avp_userprofile.h" +#include "davehook.h" +#include "CDTrackSelection.h" +#include "savegame.h" + // Added 18/11/97 by DHM: all hooks for my code + +#define UseLocalAssert Yes +#include "ourasert.h" + +/* KJL 09:47:33 03/19/97 - vision stuff for marine and predator. +Currently PC only because it will probably be implemented in a completely +different way on the consoles, so I won't worry the PSX guys for now. +*/ +#if SupportWindows95 + +#include "vision.h" + +#include "cheat.h" +#include "pldnet.h" + +#endif + +#if SupportWindows95 || Saturn +#include "kshape.h" +#include "krender.h" +#endif + +/* KJL 16:00:13 11/22/96 - One of my evil experiments.... */ +#define PENTIUM_PROFILING_ON 0 + +#define PROFILING_ON 0 + +#if PENTIUM_PROFILING_ON +#include "pentime.h" +#else +#if SupportWindows95 +#define gProfileStart(); +#define ProfileStop(x); +#endif +#endif + +#define VERSION_DisableStartupMenus Yes +#define VERSION_DisableStartupCredits Yes +#include "avp_menus.h" + +/****************** +Extern Engine Varibles +******************/ + +extern void (*UpdateScreen[]) (void); +extern int VideoMode; + +#if PSX +#else +extern void (*SetVideoMode[]) (void); +#endif + +extern int FrameRate; +extern int NormalFrameTime; +extern int FrameRate; + +extern int HWAccel; +extern int Resolution; + +unsigned char Null_Name[8]; + +extern int PlaySounds; + +/******************************* +EXPORTED GLOBALS +*******************************/ + + +AVP_GAME_DESC AvP; /* game description */ + +char projectsubdirectory[] = {"avp/"}; +int SavedFrameRate; +int SavedNormalFrameTime; + + +/* Andy 13/10/97 + + This global is set by any initialisation routine if a call to AllocateMem fails. + It can be checked during debugging after all game and level initialisation to see + if we have run out of memory. +*/ +int memoryInitialisationFailure = 0; + + +/* start inits for the game*/ + +void ProcessSystemObjects(); + +void LevelSpecificChecks(void); + +/*runtime maintainance*/ + +void FindObjectOfFocus(); +void MaintainPlayer(void); + +extern void CheckCDStatus(void); + +/********************************************* + +Init Game and Start Game + +*********************************************/ + + +void InitGame(void) +{ + /* + RWH + InitGame is to be used only to set platform independent + varibles. It will be called ONCE only by the game + */ + + /***** Set up default game settings*/ + + AvP.Language = I_English; + AvP.GameMode = I_GM_Playing; + AvP.Network = I_No_Network; + AvP.Difficulty = I_Medium; + + // Modified by Edmond for Mplayer demo + #ifdef MPLAYER_DEMO + AvP.StartingEnv = I_Dml1; + #else + AvP.StartingEnv = I_Entrance; + #endif + AvP.CurrentEnv = AvP.StartingEnv; + AvP.PlayerType = I_Marine; + +#if SupportWindows95 + + AvP.GameVideoRequestMode = VideoMode_DX_320x200x8; /* ignored */ + if(HWAccel) + AvP.MenuVideoRequestMode = VideoMode_DX_640x480x15; + else + AvP.MenuVideoRequestMode = VideoMode_DX_640x480x8; + +#endif + + AvP.ElapsedSeconds = 0; + AvP.ElapsedMinutes = 0; + AvP.ElapsedHours = 0; + + AvP.NetworkAIServer = 0; + + + // Added by DHM 18/11/97: Hook for my initialisation code: + DAVEHOOK_Init(); + + /* KJL 15:17:35 28/01/98 - Initialise console variables */ + { + extern void CreateGameSpecificConsoleVariables(void); + extern void CreateGameSpecificConsoleCommands(void); + + extern void CreateMoreGameSpecificConsoleVariables(void); + + /* KJL 12:03:18 30/01/98 - Init console variables and commands */ + CreateGameSpecificConsoleVariables(); + CreateGameSpecificConsoleCommands(); + + /* Next one is CDF's */ + CreateMoreGameSpecificConsoleVariables(); + } + #if DEATHMATCH_DEMO + SetToMinimalDetailLevels(); + #else + SetToDefaultDetailLevels(); + #endif +} + +extern void create_strategies_from_list (); +extern void AssignAllSBNames(); +extern BOOL Current_Level_Requires_Mirror_Image(); + +void StartGame(void) +{ + /* called whenever we start a game (NOT when we change */ + /* environments - destroy anything from a previous game*/ + + /* + Temporarily disable sounds while loading. Largely to avoid + some irritating teletext sounds starting up + */ + int playSoundsStore=PlaySounds; + PlaySounds=0; + + //get the cd to start again at the beginning of the play list. + ResetCDPlayForLevel(); + + + ProcessSystemObjects(); + + create_strategies_from_list (); + AssignAllSBNames(); + + SetupVision(); + /*-------------- Patrick 11/1/97 ---------------- + Initialise visibility system and NPC behaviour + systems for new level. + -----------------------------------------------*/ + + InitObjectVisibilities(); + InitPheromoneSystem(); + BuildFarModuleLocs(); + InitHive(); + InitSquad(); + + InitialiseParticleSystem(); + InitialiseSfxBlocks(); + InitialiseLightElementSystem(); + + #if PSX + { + extern int RedOut; + RedOut=0; + } + #endif + AvP.DestructTimer=-1; + + // DHM 18/11/97: I've put hooks for screen mode changes here for the moment: + DAVEHOOK_ScreenModeChange_Setup(); + DAVEHOOK_ScreenModeChange_Cleanup(); + + /* KJL 11:46:42 30/03/98 - I thought it'd be nice to display the version details + when you start a game */ + #if PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO + #else +// GiveVersionDetails(); + #endif + + #if MIRRORING_ON + if(Current_Level_Requires_Mirror_Image()) + { + CreatePlayersImageInMirror(); + } + #endif + + /* KJL 16:13:30 01/05/98 - rubber ducks! */ + CreateRubberDucks(); + + CheckCDStatus(); + + { + extern int LeanScale; + if (AvP.PlayerType==I_Alien) + { + LeanScale=ONE_FIXED*3; + } + else + { + LeanScale=ONE_FIXED; + } + } + { + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + extern int MotionTrackerScale; + MotionTrackerScale = DIV_FIXED(ScreenDescriptorBlock.SDB_Width,640); + } + // BuildInvSqrtTable(); + + InitialiseTriggeredFMVs(); + CreateStarArray(); + + { + //check the containing modules for preplaced decals + void check_preplaced_decal_modules(); + check_preplaced_decal_modules(); + } + + CurrentGameStats_Initialise(); + MessageHistory_Initialise(); + + if (DISCOINFERNO_CHEATMODE || TRIPTASTIC_CHEATMODE) + { + MakeLightElement(&Player->ObWorld,LIGHTELEMENT_ROTATING); + } + + //restore the play sounds setting + PlaySounds=playSoundsStore; + + //make sure the visibilities are up to date + Global_VDB_Ptr->VDB_World = Player->ObWorld; + AllNewModuleHandler(); + DoObjectVisibilities(); +} + + +#define FIXED_MINUTE ONE_FIXED*60 + +void DealWithElapsedTime() +{ + AvP.ElapsedSeconds += NormalFrameTime; + + if(AvP.ElapsedSeconds >= FIXED_MINUTE) + { + AvP.ElapsedSeconds -= FIXED_MINUTE; + AvP.ElapsedMinutes ++; + } + + if(AvP.ElapsedMinutes >= 60) + { + AvP.ElapsedMinutes -= 60; + AvP.ElapsedHours ++; + } +} + + + +/********************************************** + + Main Loop Game Functions + +**********************************************/ +void UpdateGame(void) +{ + /* Read Keyboard, Keypad, Joystick etc. */ + ReadUserInput(); + + /* DHM 18/11/97: hook for my code */ + #if PENTIUM_PROFILING_ON + ProfileStart(); + #endif + DAVEHOOK_Maintain(); + #if PENTIUM_PROFILING_ON + ProfileStop("DAEMON"); + #endif + + /*-------------- Patrick 14/11/96 ---------------- + call the pheronome system maintainence functions + -------------------------------------------------*/ + #if PENTIUM_PROFILING_ON + ProfileStart(); + #endif + PlayerPheromoneSystem(); + AiPheromoneSystem(); + #if PENTIUM_PROFILING_ON + ProfileStop("PHEROMONE"); + #endif + + /*-------------- Patrick 11/1/97 ---------------- + Call the alien hive management function + -------------------------------------------------*/ + DoHive(); + DoSquad(); + + + #if PROFILING_ON + ProfileStart(); + #endif + ObjectBehaviours(); + #if PROFILING_ON + ProfileStop("BEHAVS"); + #endif + + /* KJL 10:32:55 09/24/96 - update player */ + #if PENTIUM_PROFILING_ON + ProfileStart(); + #endif + MaintainPlayer(); + #if PENTIUM_PROFILING_ON + ProfileStop("MNT PLYR"); + #endif + + /* KJL 12:54:08 21/04/98 - make sure the player's matrix is always normalised */ + #if PENTIUM_PROFILING_ON + ProfileStart(); + #endif + MNormalise(&(Player->ObStrategyBlock->DynPtr->OrientMat)); + #if PENTIUM_PROFILING_ON + ProfileStop("MNorm"); + #endif + + /* netgame support: it seems necessary to collect all our messages here, as some + things depend on the player's behaviour running before anything else... + including firing the player's weapon */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) NetCollectMessages(); + #endif + + RemoveDestroyedStrategyBlocks(); + + { + + if(SaveGameRequest != SAVELOAD_REQUEST_NONE) + { + SaveGame(); + } + else if(LoadGameRequest != SAVELOAD_REQUEST_NONE) + { + LoadSavedGame(); + } + } + + #if PENTIUM_PROFILING_ON + ProfileStart(); + #endif + ObjectDynamics(); + #if PENTIUM_PROFILING_ON + ProfileStop("DYNAMICS"); + #endif + + // now for the env teleports + + if(RequestEnvChangeViaLift) + { + CleanUpLiftControl(); + } + + #if 0 + Player->ObStrategyBlock->DynPtr->Position.vx = -71893; + Player->ObStrategyBlock->DynPtr->Position.vy = 36000; + Player->ObStrategyBlock->DynPtr->Position.vz = -52249; + Player->ObWorld.vx = -71893; + Player->ObWorld.vy = 36000; + Player->ObWorld.vz = -42249; + #endif + /* netgame support */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) NetSendMessages(); + + /* KJL 11:50:18 03/21/97 - cheat modes */ + HandleCheatModes(); + #endif + + #if PSX + HandleCheatModes(); + #endif + + /*------------Patrick 1/6/97--------------- + New sound system + -------------------------------------------*/ + #if PENTIUM_PROFILING_ON + ProfileStart(); + #endif + + if(playerPherModule) + { + PlatSetEnviroment(playerPherModule->m_sound_env_index,playerPherModule->m_sound_reverb); + } + SoundSys_Management(); + DoPlayerSounds(); + #if PENTIUM_PROFILING_ON + ProfileStop("SOUND SYS"); + #endif + + LevelSpecificChecks(); +// NormaliseTest(); + MessageHistory_Maintain(); + + if(AvP.LevelCompleted) + { + /* + If player is dead and has also completed level , then cancel + level completion. + */ + PLAYER_STATUS* PlayerStatusPtr = (PLAYER_STATUS*) Player->ObStrategyBlock->SBdataptr; + if(!PlayerStatusPtr->IsAlive) + { + AvP.LevelCompleted=0; + } + } + + if (TRIPTASTIC_CHEATMODE) + { + extern int TripTasticPhase; + extern int CloakingPhase; + int a = GetSin(CloakingPhase&4095); + TripTasticPhase = MUL_FIXED(MUL_FIXED(a,a),128)+64; + } + if (JOHNWOO_CHEATMODE) + { + extern int LeanScale; + extern int TimeScale; + TimeScaleThingy(); + + //in john woo mode leanscale is dependent on the TimeScale + if (AvP.PlayerType==I_Alien) + { + LeanScale=ONE_FIXED*3; + } + else + { + LeanScale=ONE_FIXED; + } + + LeanScale+=(ONE_FIXED-TimeScale)*5; + + } + + +} + + + + + +/* MODULE CALL BACK FUNCTIONS .... */ + + + +void ModuleObjectJustAllocated(MODULE *mptr) +{ +} + + +void ModuleObjectAboutToBeDeallocated(MODULE *mptr) +{ +} + + +void NewAndOldModules(int num_new, MODULE **m_new, int num_old, MODULE **m_old, char *m_currvis) +{ + + /* this is the important bit */ + DoObjectVisibilities(); + +} + + +void LevelSpecificChecks(void) +{ +/* ahem, level specific hacks might be more accurate */ +} + +extern void CheckCDStatus(void) +{ + #if PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO +// CDCommand_PlayLoop(2); + #endif +} + + + +void TimeStampedMessage(char *stringPtr) +{ +#if 0 + static int time=0; + int t=timeGetTime(); + LOGDXFMT(("%s %fs\n",stringPtr,(float)(t-time)/1000.0f )); + time = t; +#endif +} + + +#if 0 +/* KJL 14:24:34 01/05/98 - Interesting floating point experiments +(UpdateGame is a useful point at which to test things) */ + +#define IEEE_MANT_BITS 23 +#define IEEE_EXP_BITS 8 +#define IEEE_SIGN_BITS 1 +#define IEEE_EXP_BIAS 127 + +#define INVSQRT_TABLE_SEED_MANT_BITS 9 +#define INVSQRT_TABLE_SEED_EXP_BITS 1 +#define INVSQRT_TABLE_LENGTH_BITS (INVSQRT_TABLE_SEED_MANT_BITS + INVSQRT_TABLE_SEED_EXP_BITS) +#define INVSQRT_TABLE_NUM_ENTRIES (1 << INVSQRT_TABLE_LENGTH_BITS) +#define INVSQRT_TABLE_ENTRY_BITS 10 + +#define EXP_OF(x) (*(DWORD *)&(x) & 0x7f800000) + + +typedef struct _tab_in +{ +unsigned int mpad: ((IEEE_MANT_BITS + 1) - INVSQRT_TABLE_LENGTH_BITS); +unsigned int lookup: INVSQRT_TABLE_LENGTH_BITS; +unsigned int epad: 7; +unsigned int spad: 1; +} tab_in; + +typedef struct _tab_out +{ +unsigned int mpad: (IEEE_MANT_BITS - INVSQRT_TABLE_ENTRY_BITS); +unsigned int lookup: INVSQRT_TABLE_ENTRY_BITS; +unsigned int epad: 8; +unsigned int spad: 1; +} tab_out; + + +union myfp +{ +float fp; + +// used to build the lookup table +tab_in tab_in_; +tab_out tab_out_; +}; + + +unsigned int InvSqrtTab[INVSQRT_TABLE_NUM_ENTRIES]; + + +void +BuildInvSqrtTable() +{ + static int done = FALSE; + int i; + + if (done) return; + done = TRUE; + + for (i = 0; i < INVSQRT_TABLE_NUM_ENTRIES; i++) + { + union myfp fin, fout; + + fin.fp = 1.0F; + fin.tab_in_.lookup = i; + + // calculate the real value + fout.fp = 1.0F / (float)sqrt((double)fin.fp); + + // Add the value to the table. 1.0 is special. + if (fout.fp == 1.0F) + InvSqrtTab[i] = 0x3FF << (IEEE_MANT_BITS - INVSQRT_TABLE_ENTRY_BITS); + else + InvSqrtTab[i] = fout.tab_out_.lookup << (IEEE_MANT_BITS - + INVSQRT_TABLE_ENTRY_BITS); + } +} // BuildInvSqrtTable() + + +float __stdcall +InverseSquareRoot(float x) +{ +unsigned int index; +float r; +DWORD *dptr = (DWORD *)&r; + +*(DWORD *)&r = ((((3 * IEEE_EXP_BIAS - 1) << IEEE_MANT_BITS) - EXP_OF(x)) >> +1) & 0x7f800000; + +index = ((*(DWORD *)&x) >> (IEEE_MANT_BITS - INVSQRT_TABLE_ENTRY_BITS + 1)) +& (INVSQRT_TABLE_NUM_ENTRIES - 1); + +*dptr |= InvSqrtTab[index]; + +return r; +} // InverseSquareRoot() + + +void NormaliseTest(void) +{ + int i; + float d; + int outside; + #if 0 + i = 10000; + outside = 0; + ProfileStart(); + while(i--) + { + VECTORCH v; + v.vx = (FastRandom()&65535)+1; + v.vy = (FastRandom()&65535)+1; + v.vz = (FastRandom()&65535)+1; + + Normalise(&v); + { + int m = Magnitude(&v); + if (m<65530 || m>65540) + outside++; + } + } + ProfileStop("OLD NORM"); + textprint("Outside Range: %d\n",outside); + + i = 10000; + outside = 0; + ProfileStart(); + while(i--) + { + VECTORCH v; + v.vx = (FastRandom()&65535)+1; + v.vy = (FastRandom()&65535)+1; + v.vz = (FastRandom()&65535)+1; + + NewNormalise(&v); + { + int m = Magnitude(&v); + if (m<65536-50|| m>65536+50) + outside++; + } + } + ProfileStop("NEW NORM"); + textprint("Outside Range: %d\n",outside); + #endif + i = 10000; + d=0; + while(--i) + { + int m; + VECTORCH v; + v.vx = FastRandom()&65535; + v.vy = FastRandom()&65535; + v.vz = FastRandom()&65535; + m = InverseMagnitude(&v); + d+=m; + } + + #if 0 + textprint("%f\n",d); + i = 10000; + d=0; + ProfileStart(); + while(--i) + { + float m = sqrt((float)i); + d+=m; + } + ProfileStop("FSQRT"); + #endif + textprint("%f\n",d); + +} +static float fptmp; +static int itmp; + +void IntToFloat(void); +# pragma aux IntToFloat = \ +"fild itmp" \ +"fstp fptmp"; + +/* + + This macro makes usage of the above function easier and more elegant + +*/ + +#define i2f(a, b) { \ +itmp = (a); \ +IntToFloat(); \ +b = fptmp;} + +int InverseMagnitude(VECTORCH *v) +{ + int answer; + float m; + float mag; + { + float x,y,z; + x = v->vx; + y = v->vy; + z = v->vz; + mag = x*x+y*y+z*z; + } + { + unsigned int index; + float r; + DWORD *dptr = (DWORD *)&r; + + *(DWORD *)&r = ((((3 * IEEE_EXP_BIAS - 1) << IEEE_MANT_BITS) - EXP_OF(mag)) >> + 1) & 0x7f800000; + + index = ((*(DWORD *)&mag) >> (IEEE_MANT_BITS - INVSQRT_TABLE_ENTRY_BITS + 1)) + & (INVSQRT_TABLE_NUM_ENTRIES - 1); + + *dptr |= InvSqrtTab[index]; + + m = 65536.0*r; + } + + + f2i(answer,m); + return answer; +} + + +void CurrentQNormalise(QUAT *q) +{ + /* Normalise */ + double oos = 1.0/(65536.0*65536.0); + + double wsq = (double)q->quatw * (double)q->quatw * oos; + double xsq = (double)q->quatx * (double)q->quatx * oos; + double ysq = (double)q->quaty * (double)q->quaty * oos; + double zsq = (double)q->quatz * (double)q->quatz * oos; + + double m = sqrt(wsq + xsq + ysq + zsq); + + if(m == 0.0) m = 1.0; /* Just in case */ + m = 1.0 / m; + + q->quatw = (int) ((double)q->quatw * m); + q->quatx = (int) ((double)q->quatx * m); + q->quaty = (int) ((double)q->quaty * m); + q->quatz = (int) ((double)q->quatz * m); + +} + +void NewQNormalise(QUAT *q) +{ + float nw = q->quatw; + float nx = q->quatx; + float ny = q->quaty; + float nz = q->quatz; + + float m = sqrt(nw*nw+nx*nx+ny*ny+nz*nz); + + if (!m) return; + + m = 65536.0/m; + + f2i(q->quatw,nw * m); + f2i(q->quatx,nx * m); + f2i(q->quaty,ny * m); + f2i(q->quatz,nz * m); +} + +void QNormaliseTest(void) +{ + QUAT q,q2; + int i; + + for (i=0; i<10000; i++) + { + q.quatw = FastRandom()&65535; + q.quatx = FastRandom()&65535; + q.quaty = FastRandom()&65535; + q.quatz = FastRandom()&65535; + q2=q; + + NewQNormalise(&q); + CurrentQNormalise(&q2); + + if (q.quatw!=q2.quatw) + textprint("w%d ",q.quatw-q2.quatw); + if (q.quatx!=q2.quatx) + textprint("x%d ",q.quatx-q2.quatx); + if (q.quaty!=q2.quaty) + textprint("y%d ",q.quaty-q2.quaty); + if (q.quatz!=q2.quatz) + textprint("z%d ",q.quatz-q2.quatz); + } + +} +#endif + diff --git a/3dc/avp/HModel.c b/3dc/avp/HModel.c new file mode 100644 index 0000000..26a8b02 --- /dev/null +++ b/3dc/avp/HModel.c @@ -0,0 +1,5597 @@ +/***** HModel.c *****/ +/***** CDF 21/10/97 *****/ + +#include "3dc.h" + +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "comp_shp.h" +#include "dynblock.h" +#include "dynamics.h" +#include "pfarlocs.h" +#include "pheromon.h" +#include "bh_types.h" +#include "pvisible.h" +#include "bh_far.h" +#include "bh_debri.h" +#include "bh_pred.h" +#include "bh_paq.h" +#include "bh_queen.h" +#include "bh_marin.h" +#include "lighting.h" +#include "bh_weap.h" +#include "weapons.h" +#include "psnd.h" +#include "load_shp.h" +#include "plat_shp.h" +#include "avp_userprofile.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "particle.h" +#include "kshape.h" +#include "sfx.h" +#include "dxlog.h" +#include + +#define AUTODETECT 1 +#define ADD_ELEVATION_OFFSETS 1 +#define SPARKS_FOR_A_SPRAY 15 + +int Simplify_HModel_Rendering=0; + +extern enum PARTICLE_ID GetBloodType(STRATEGYBLOCK *sbPtr); +extern void DoShapeAnimation (DISPLAYBLOCK * dptr); +extern void RenderThisHierarchicalDisplayblock(DISPLAYBLOCK *dbPtr); +extern void MakeSprayOfSparks(MATRIXCH *orientationPtr, VECTORCH *positionPtr); +void MatToQuat (MATRIXCH *m, QUAT *quat); + +/* protos for this file */ +void New_Preprocess_Keyframe(KEYFRAME_DATA *this_keyframe, KEYFRAME_DATA *next_keyframe,int one); +void MulQuat(QUAT *q1,QUAT *q2,QUAT *output); +void Slerp(KEYFRAME_DATA *input,int lerp,QUAT *output); +void Analyse_Tweening_Data(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,int base_timer,VECTORCH *output_offset,MATRIXCH *output_matrix); +static void FindHeatSource_Recursion(HMODELCONTROLLER *controllerPtr, SECTION_DATA *sectionDataPtr); +void Budge_HModel(HMODELCONTROLLER *controller,VECTORCH *offset); + +/* external globals */ +extern int NormalFrameTime; +extern int sine[]; +extern int cosine[]; +extern int GlobalFrameCounter; +extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + +int GlobalGoreRate=NORMAL_GORE_RATE; +int incIDnum; /* Has to be global. */ +int GlobalLevelOfDetail_Hierarchical; + +STRATEGYBLOCK *Global_HModel_Sptr; +HMODELCONTROLLER *Global_Controller_Ptr; +static DISPLAYBLOCK *Global_HModel_DispPtr; + +DAMAGEBLOCK Default_Damageblock = { + 5, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, +}; + +MATRIXCH Identity_RotMat = { + ONE_FIXED,0,0, + 0,ONE_FIXED,0, + 0,0,ONE_FIXED, +}; + +void QNormalise(QUAT *q) +{ + float nw = q->quatw; + float nx = q->quatx; + float ny = q->quaty; + float nz = q->quatz; + + float m = sqrt(nw*nw+nx*nx+ny*ny+nz*nz); + + if (!m) return; + + m = 65536.0/m; + + f2i(q->quatw,nw * m); + f2i(q->quatx,nx * m); + f2i(q->quaty,ny * m); + f2i(q->quatz,nz * m); +} + + +int GetSequenceID(int sequence_type,int sub_sequence) { + return( (sub_sequence<<16)+sequence_type); +} + +SEQUENCE *GetSequencePointer(int sequence_type,int sub_sequence,SECTION *this_section) { + + int sequence_id,a; + SEQUENCE *sequence_pointer; + + sequence_id=GetSequenceID(sequence_type,sub_sequence); + + for (a=0; anum_sequences; a++) { + if (this_section->sequence_array[a].sequence_id==sequence_id) { + sequence_pointer=&(this_section->sequence_array[a]); + break; + } + } + + if (a==this_section->num_sequences) { + //textprint("Unknown HModel sequence! %d,%d\n",sequence_type,sub_sequence); + return(&(this_section->sequence_array[0])); + //GLOBALASSERT(0); + //return(NULL); + } + + return(sequence_pointer); + +} +#if 0 +void Preprocess_Keyframe(KEYFRAME_DATA *this_keyframe, KEYFRAME_DATA *next_keyframe,int one) { +{ + + New_Preprocess_Keyframe(this_keyframe,next_keyframe,one); +} +#endif +int QDot(QUAT *this_quat, QUAT *next_quat) { + + int qdot; + + qdot=( (MUL_FIXED(this_quat->quatx,next_quat->quatx)) + + (MUL_FIXED(this_quat->quaty,next_quat->quaty)) + + (MUL_FIXED(this_quat->quatz,next_quat->quatz)) + + (MUL_FIXED(this_quat->quatw,next_quat->quatw)) ); + + return(qdot); +} + +void New_Preprocess_Keyframe(KEYFRAME_DATA *this_keyframe, KEYFRAME_DATA *next_keyframe,int one) { + + int cosom; + QUAT_SHORT *this_quat, *next_quat; + + LOCALASSERT(this_keyframe); + LOCALASSERT(next_keyframe); + + this_quat=&this_keyframe->QOrient; + next_quat=&next_keyframe->QOrient; + + //QNormalise(this_quat); + //QNormalise(next_quat); + + + //cosom=QDot(this_quat,next_quat); + cosom=( (MUL_FIXED((int)this_quat->quatx,(int)next_quat->quatx)) + + (MUL_FIXED((int)this_quat->quaty,(int)next_quat->quaty)) + + (MUL_FIXED((int)this_quat->quatz,(int)next_quat->quatz)) + + (MUL_FIXED((int)this_quat->quatw,(int)next_quat->quatw)))<<1; + + if (cosom<0) { + this_keyframe->slerp_to_negative_quat=1; + cosom=-cosom; + } + else{ + this_keyframe->slerp_to_negative_quat=0; + } + + + this_keyframe->omega=(unsigned short)ArcCos(cosom); + + GLOBALASSERT(this_keyframe->Sequence_Length>0); + this_keyframe->oneoversequencelength=DIV_FIXED(one,(int)this_keyframe->Sequence_Length); + +} + +void Preprocess_Section(SECTION *this_section, char *riffname ,VECTORCH* offset_to_return) { + + KEYFRAME_DATA *this_keyframe; + VECTORCH cumulative_gore_direction; + VECTORCH next_one_down; + SECTION_ATTACHMENT *sec_att; + int a; + + if (this_section->ShapeName!=NULL) { + this_section->ShapeNum=GetLoadedShapeMSL(this_section->ShapeName); + if (this_section->ShapeNum==-1) { + textprint("\n\n\n\nShape has a name! %s\n",this_section->ShapeName); + GLOBALASSERT(0); + } + this_section->Shape=GetShapeData(this_section->ShapeNum); + } else { + /* Do nothing, as requested by John. */ + } + + /* Get section attachment... */ + + sec_att=GetThisSectionAttachment(riffname,this_section->Section_Name,this_section->Hierarchy_Name); + if (sec_att==NULL) { + /* Try for the general one. */ + sec_att=GetThisSectionAttachment(riffname,this_section->Section_Name,NULL); + } + + if (sec_att) { + this_section->StartingStats=sec_att->StartingStats; + this_section->flags&=~section_is_master_root; + this_section->flags|=sec_att->flags; + } else { + /* Default! */ + this_section->StartingStats=Default_Stats.StartingStats; + this_section->flags|=Default_Stats.flags; + } + + /* Now ID number. */ + + this_section->IDnumber=incIDnum; + incIDnum++; + + /* Okay. */ + + for (a=0; anum_sequences; a++) { + + int one=0; + + /* Pass through to find sequence length. */ + + this_keyframe=this_section->sequence_array[a].first_frame; + + while(1){ + + one+=this_keyframe->Sequence_Length; + + /*See if we have got to the end*/ + if(this_keyframe->last_frame) break; + /* Next frame */ + this_keyframe=this_keyframe->Next_Frame; + + } + + /* Second pass. */ + + this_keyframe=this_section->sequence_array[a].first_frame; + + while(1) { + + New_Preprocess_Keyframe(this_keyframe, this_keyframe->Next_Frame,one); + + + /*See if we have got to the end*/ + if(this_keyframe->last_frame) break; + /* Next frame */ + this_keyframe=this_keyframe->Next_Frame; + + } + + } + + cumulative_gore_direction.vx=0; + cumulative_gore_direction.vy=0; + cumulative_gore_direction.vz=0; + + /* Now call recursion... */ + + if (this_section->Children!=NULL) { + SECTION **child_list_ptr; + + child_list_ptr=this_section->Children; + + while (*child_list_ptr!=NULL) { + Preprocess_Section(*child_list_ptr,riffname,&next_one_down); + child_list_ptr++; + + cumulative_gore_direction.vx+=next_one_down.vx; + cumulative_gore_direction.vy+=next_one_down.vy; + cumulative_gore_direction.vz+=next_one_down.vz; + } + } + + if ( (cumulative_gore_direction.vx==0) + && (cumulative_gore_direction.vy==0) + && (cumulative_gore_direction.vz==0) ) { + /* Darn. Have a default. */ + cumulative_gore_direction.vx=4096; + } + + cumulative_gore_direction.vx=-cumulative_gore_direction.vx; + cumulative_gore_direction.vy=-cumulative_gore_direction.vy; + cumulative_gore_direction.vz=-cumulative_gore_direction.vz; + + Normalise(&cumulative_gore_direction); + + this_section->gore_spray_direction=cumulative_gore_direction; + + if(offset_to_return) + { + GetKeyFrameOffset(this_section->sequence_array[0].first_frame,offset_to_return); + } + +} + +void Preprocess_HModel(SECTION *root, char *riffname) { + /* One-time preprocessor, prerocesses the 'deltas' for all sequences. */ + + GLOBALASSERT(root); /* Stop messin' about... */ + + incIDnum=0; + /* Root can't spray gore... */ + Preprocess_Section(root,riffname,0); + root->gore_spray_direction.vx=0; + root->gore_spray_direction.vy=0; + root->gore_spray_direction.vz=0; + + /* Shouldn't this be set anyway? */ + root->flags|=section_is_master_root; + +} + +void Setup_Texture_Animation_For_Section(SECTION_DATA *this_section_data) +{ + GLOBALASSERT(this_section_data); + + if(this_section_data->tac_ptr) + { + //get rid of old animation control blocks + TXACTRLBLK *tac_next; + tac_next=this_section_data->tac_ptr; + while (tac_next) { + TXACTRLBLK *tac_temp; + + tac_temp=tac_next->tac_next; + DeallocateMem(tac_next); + tac_next=tac_temp; + + } + this_section_data->tac_ptr=0; + } + + if (this_section_data->Shape) { + if (this_section_data->Shape->shapeflags & ShapeFlag_HasTextureAnimation) { + + TXACTRLBLK **pptxactrlblk; + int item_num; + int shape_num = this_section_data->ShapeNum; + SHAPEHEADER *shptr = GetShapeData(shape_num); + pptxactrlblk = &this_section_data->tac_ptr; + for(item_num = 0; item_num < shptr->numitems; item_num ++) + { + POLYHEADER *poly = (POLYHEADER*)(shptr->items[item_num]); + LOCALASSERT(poly); + + SetupPolygonFlagAccessForShape(shptr); + + if((Request_PolyFlags((void *)poly)) & iflag_txanim) + { + TXACTRLBLK *pnew_txactrlblk; + + pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK)); + if(pnew_txactrlblk) + { + pnew_txactrlblk->tac_flags = 0; + pnew_txactrlblk->tac_item = item_num; + pnew_txactrlblk->tac_sequence = 0; + pnew_txactrlblk->tac_node = 0; + pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shape_num, item_num); + pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shape_num); + + *pptxactrlblk = pnew_txactrlblk; + pptxactrlblk = &pnew_txactrlblk->tac_next; + } + else *pptxactrlblk = NULL; + } + } + *pptxactrlblk=0; + } + } +} + +SECTION_DATA *Create_New_Section(SECTION *this_section) { + + SECTION_DATA *this_section_data; + int num_children; + + if (this_section->ShapeName!=NULL) { + this_section->ShapeNum=GetLoadedShapeMSL(this_section->ShapeName); + if (this_section->ShapeNum==-1) { + GLOBALASSERT(0); + } + this_section->Shape=GetShapeData(this_section->ShapeNum); + } else { + /* Do nothing, as requested by John. */ + } + + /* Create SECTION_DATA. */ + + this_section_data=(SECTION_DATA *)AllocateMem(sizeof(SECTION_DATA)); + GLOBALASSERT(this_section_data); + + this_section_data->sac_ptr=NULL; + this_section_data->tac_ptr=NULL; + this_section_data->sempai=this_section; + + this_section_data->current_damage.Health=this_section_data->sempai->StartingStats.Health<<16; + this_section_data->current_damage.Armour=this_section_data->sempai->StartingStats.Armour<<16; + this_section_data->current_damage.SB_H_flags=this_section_data->sempai->StartingStats.SB_H_flags; + + if (this_section_data->current_damage.Health<=0) { + /* Wrong! */ + + this_section_data->current_damage=Default_Damageblock; + } + + this_section_data->my_controller=Global_Controller_Ptr; + /* Note not initialised! */ + this_section_data->flags=0; + + /* KJL 17:04:41 31/07/98 - Decal support */ + this_section_data->NumberOfDecals = 0; + this_section_data->NextDecalToUse = 0; + + + this_section_data->ShapeNum=this_section->ShapeNum; + this_section_data->Shape=this_section->Shape; + + /* This just so it's not uninitialised. */ + this_section_data->Prev_Sibling=NULL; + this_section_data->My_Parent=NULL; + this_section_data->Next_Sibling=NULL; + + this_section_data->replacement_id=0; + + /* Init shape animations... */ + + #if AUTODETECT + if (this_section->Shape) { + if (this_section->Shape->animation_header) { + #else + if (this_section->flags§ion_has_shape_animation) { + #endif + + GLOBALASSERT(this_section->Shape->animation_header); + + this_section_data->sac_ptr=AllocateMem(sizeof(SHAPEANIMATIONCONTROLLER)); + + InitShapeAnimationController (this_section_data->sac_ptr, this_section->Shape); + + } + #if AUTODETECT + } + #endif + + /* Init texture animations. */ + this_section_data->tac_ptr=0; + Setup_Texture_Animation_For_Section(this_section_data); + + /* Now call recursion... */ + + num_children=0; + + if (this_section->Children!=NULL) { + SECTION **child_list_ptr; + SECTION_DATA *new_child_list_ptr; + + SECTION_DATA *last_child,*first_child; + + last_child=NULL; + first_child=NULL; + + /* Create subsections. */ + + child_list_ptr=this_section->Children; + + while (*child_list_ptr!=NULL) { + + (new_child_list_ptr)=Create_New_Section(*child_list_ptr); + + (new_child_list_ptr)->Prev_Sibling=last_child; + (new_child_list_ptr)->My_Parent=this_section_data; + (new_child_list_ptr)->Next_Sibling=NULL; /* For now... */ + + if (first_child==NULL) { + first_child=new_child_list_ptr; + } + + if (last_child) { + last_child->Next_Sibling=(new_child_list_ptr); + } + last_child=(new_child_list_ptr); + + child_list_ptr++; + } + (new_child_list_ptr)=NULL; + + this_section_data->First_Child=first_child; + } else { + this_section_data->First_Child=NULL; + } + + return(this_section_data); + +} + +void Create_HModel(HMODELCONTROLLER *controller,SECTION *root) { + + /* Connects sequence to controller and must generate + the list of section_data structures. */ + + GLOBALASSERT(root); /* Stop messin' about... */ + + Global_Controller_Ptr=controller; + + controller->Root_Section=root; /* That's a given. */ + controller->Seconds_For_Sequence=ONE_FIXED; + controller->timer_increment=ONE_FIXED; + /* Seconds_For_Sequence and timer_increment are dealt with elsewhere. */ + controller->sequence_timer=0; + + controller->FrameStamp=-1; + controller->View_FrameStamp=-1; + controller->Computed_Position.vx=0; + controller->Computed_Position.vy=0; + controller->Computed_Position.vz=0; + + controller->Playing=0; + controller->Reversed=0; + controller->Looped=0; + + controller->After_Tweening_Sequence_Type=-1; + controller->After_Tweening_Sub_Sequence=-1; + controller->AT_seconds_for_sequence=ONE_FIXED; + controller->AT_sequence_timer=0; + controller->Tweening=Controller_NoTweening; + controller->LoopAfterTweening=0; + controller->StopAfterTweening=0; + + controller->DisableBleeding=0; + controller->LockTopSection=0; + controller->ZeroRootDisplacement=0; + controller->ZeroRootRotation=0; + controller->DisableSounds=0; + + /* Controller elevation now removed. All done through delta sequences, 8/4/98. */ + controller->ElevationTweening=0; + + controller->Deltas=NULL; + + /* Every time a section is preprocessed, it must generate a section_data for + itself, and clip it to the last section_data that was generated. */ + + controller->section_data=Create_New_Section(controller->Root_Section); + + controller->section_data->Prev_Sibling=NULL; + controller->section_data->My_Parent=NULL; + controller->section_data->Next_Sibling=NULL; + + if (root->flags§ion_is_master_root) { + controller->section_data->flags|=section_data_master_root; + } + +} + +void Destructor_Recursion(SECTION_DATA *doomed_section_data) { + + /* Remove other bits. */ + + if (doomed_section_data->sac_ptr) { + DeallocateMem(doomed_section_data->sac_ptr); + } + + if (doomed_section_data->tac_ptr) { + TXACTRLBLK *tac_next; + tac_next=doomed_section_data->tac_ptr; + while (tac_next) { + TXACTRLBLK *tac_temp; + + tac_temp=tac_next->tac_next; + DeallocateMem(tac_next); + tac_next=tac_temp; + + } + } + + /* Recurse. */ + + if (doomed_section_data->First_Child!=NULL) { + + SECTION_DATA *child_list_ptr; + + child_list_ptr=doomed_section_data->First_Child; + + while (child_list_ptr!=NULL) { + /* Remove each child... */ + /* JH - 19/2/98 store the next sibling so that we don't access dealloced memory */ + SECTION_DATA * next_sibling_ptr = child_list_ptr->Next_Sibling; + Destructor_Recursion(child_list_ptr); + child_list_ptr=next_sibling_ptr; + } + + } + + /* Now remove the section... */ + + DeallocateMem(doomed_section_data); + +} + +void Prune_Section(SECTION_DATA *doomed_section_data) { + + GLOBALASSERT(doomed_section_data); + /* Destroys section, and all children. */ + + if (doomed_section_data->Prev_Sibling) { + GLOBALASSERT(doomed_section_data->Prev_Sibling->Next_Sibling==doomed_section_data); + doomed_section_data->Prev_Sibling->Next_Sibling=doomed_section_data->Next_Sibling; + } + + if (doomed_section_data->Next_Sibling) { + GLOBALASSERT(doomed_section_data->Next_Sibling->Prev_Sibling==doomed_section_data); + doomed_section_data->Next_Sibling->Prev_Sibling=doomed_section_data->Prev_Sibling; + } + + if (doomed_section_data->My_Parent) { + if (doomed_section_data->My_Parent->First_Child==doomed_section_data) { + doomed_section_data->My_Parent->First_Child=doomed_section_data->Next_Sibling; + } + } + + /* Now destroy. */ + Destructor_Recursion(doomed_section_data); + +} + +void Delete_Deltas_Recursion(DELTA_CONTROLLER *delta_controller) { + + if (delta_controller==NULL) { + return; + } + + if (delta_controller->next_controller) { + Delete_Deltas_Recursion(delta_controller->next_controller); + } + + DeallocateMem(delta_controller->id); + DeallocateMem(delta_controller); + +} + +void Dispel_HModel(HMODELCONTROLLER *controller) { + + /* For getting rid of the section_data. */ + + if (controller->section_data!=NULL) { + + Destructor_Recursion(controller->section_data); + + controller->section_data=NULL; + + } + + Delete_Deltas_Recursion(controller->Deltas); + +} + +void RemoveAllDeltas(HMODELCONTROLLER *controller) { + + /* Pretty self explainatory. */ + GLOBALASSERT(controller); + + Delete_Deltas_Recursion(controller->Deltas); + controller->Deltas=NULL; + +} + +/* SetElevationDeltas removed, 8.4.98. CDF. */ + +void Process_Delta_Controller(SECTION_DATA *this_section_data,DELTA_CONTROLLER *delta_controller,VECTORCH *output_offset,QUAT *output_quat) { + + SEQUENCE *delta_sequence; + int a; + int working_timer,lerp,lastframe_working_timer; + KEYFRAME_DATA *this_frame,*next_frame; + int sequence_type,sub_sequence,timer; + + if (delta_controller==NULL) { + return; + } + + sequence_type=delta_controller->sequence_type; + sub_sequence=delta_controller->sub_sequence; + timer=delta_controller->timer; + + GLOBALASSERT(sequence_type>-1); + GLOBALASSERT(sub_sequence>-1); + + delta_sequence=GetSequencePointer(sequence_type,sub_sequence,this_section_data->sempai); + + GLOBALASSERT(delta_sequence); + + /* Final Frame Correction. */ + + this_frame=delta_sequence->first_frame; + + a=0; + + while (!this_frame->last_frame) { + a+=this_frame->Sequence_Length; + this_frame=this_frame->Next_Frame; + } + + /* Now a is the 'real' sequence length. */ + + working_timer=MUL_FIXED(timer,a); + + lastframe_working_timer=delta_controller->lastframe_timer; + lastframe_working_timer=MUL_FIXED(lastframe_working_timer,a); + + /* Now do that thing. */ + + this_frame=delta_sequence->first_frame; + + a=0; /* Status flag... */ + + while (a==0) { + next_frame=this_frame->Next_Frame; + if (working_timer>=this_frame->Sequence_Length) { + /* We've gone beyond this frame: get next keyframe. */ + working_timer-=this_frame->Sequence_Length; + lastframe_working_timer-=this_frame->Sequence_Length; + + /* Have we looped? */ + if (this_frame->last_frame) { + /* Some deltas are really fast. */ + this_frame=delta_sequence->first_frame; + } + else{ + /* Advance frame... */ + this_frame=next_frame; + } + + if (lastframe_working_timer<=0) { + if(this_frame->frame_has_extended_data) + { + KEYFRAME_DATA_EXTENDED* this_frame_extended=(KEYFRAME_DATA_EXTENDED*) this_frame; + /* Check flags... */ + this_section_data->my_controller->keyframe_flags|=this_frame_extended->flags; + /* ...And keyframe sounds... */ + if (this_frame_extended->sound) { + if (this_section_data->my_controller->DisableSounds==0) { + PlayHierarchySound(this_frame_extended->sound,&this_section_data->Last_World_Offset); + } + } + } + } + + } else { + a=1; /* Exit loop with success. */ + } + /* Better make sure the last 'frame' has 65536 length... */ + } + + /* Now, this_frame and next_frame are set, and working_timerSequence_Length. */ + lerp=MUL_FIXED(working_timer,this_frame->oneoversequencelength); + + GetKeyFrameOffset(this_frame,output_offset); + if(next_frame->shift_offset) + { + VECTORCH next_offset; + GetKeyFrameOffset(next_frame,&next_offset); + output_offset->vx+=MUL_FIXED(next_offset.vx - output_offset->vx,lerp); + output_offset->vy+=MUL_FIXED(next_offset.vy - output_offset->vy,lerp); + output_offset->vz+=MUL_FIXED(next_offset.vz - output_offset->vz,lerp); + } + else + { + output_offset->vx+=MUL_FIXED((int)next_frame->Offset_x - output_offset->vx,lerp); + output_offset->vy+=MUL_FIXED((int)next_frame->Offset_y - output_offset->vy,lerp); + output_offset->vz+=MUL_FIXED((int)next_frame->Offset_z - output_offset->vz,lerp); + } + + + /* Now deal with orientation. */ + + + Slerp(this_frame,lerp,output_quat); + + delta_controller->lastframe_timer=delta_controller->timer; + +} + +void Handle_Section_Timer(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,KEYFRAME_DATA *input_frame,int base_timer, int *working_timer) { + + KEYFRAME_DATA *this_frame,*next_frame; + int a; + + if (this_section_data->freezeframe_timer!=-1) { + (*working_timer)=this_section_data->freezeframe_timer; + } else { + (*working_timer)=base_timer; + } + + if (this_section_data->accumulated_timer>(*working_timer)) { + /* We must have looped. Or be reversed.... ! */ + this_section_data->accumulated_timer=0; + this_section_data->current_keyframe=input_frame; + if(input_frame->frame_has_extended_data) + { + /* Check start flags... */ + KEYFRAME_DATA_EXTENDED* input_frame_extended=(KEYFRAME_DATA_EXTENDED*) input_frame; + controller->keyframe_flags|=input_frame_extended->flags; + /* And Keyframe Sounds. */ + if (input_frame_extended->sound) { + if (controller->DisableSounds==0) { + PlayHierarchySound(input_frame_extended->sound,&this_section_data->World_Offset); + } + } + } + } + + this_frame=this_section_data->current_keyframe; + (*working_timer)-=this_section_data->accumulated_timer; + + /* Now, a lot like the old way, but we shouldn't need to loop more than once. */ + /* If we do, we have a game framerate slower than the anim framerate. */ + + a=0; /* Status flag... */ + + while (a==0) { + if (this_frame==NULL) { + this_frame=input_frame; // Heaven help us. + } + if (this_frame->last_frame) { + /* Low framerate loop? */ + next_frame=input_frame; + } + else{ + next_frame=this_frame->Next_Frame; + } + + if ((*working_timer)>=this_frame->Sequence_Length) { + /* We've gone beyond this frame: get next keyframe. */ + (*working_timer)-=this_frame->Sequence_Length; + /* Add sequence length to accumulated_timer. */ + this_section_data->accumulated_timer+=this_frame->Sequence_Length; + /* Advance frame... */ + this_frame=next_frame; + if (controller->Reversed==0) { + if(this_frame->frame_has_extended_data) + { + KEYFRAME_DATA_EXTENDED* this_frame_extended=(KEYFRAME_DATA_EXTENDED*) this_frame; + /* Check flags... */ + controller->keyframe_flags|=this_frame_extended->flags; + /* ...And keyframe sounds... */ + if (this_frame_extended->sound) { + if (controller->DisableSounds==0) { + PlayHierarchySound(this_frame_extended->sound,&this_section_data->World_Offset); + } + } + } + } + /* Update current keyframe. */ + this_section_data->current_keyframe=this_frame; + } else { + a=1; /* Exit loop with success. */ + } + /* Better make sure the last 'frame' has 65536 length... */ + } + + if (controller->Reversed) { + /* Okay, maybe a bit cheesy. Trigger flags and sounds... */ + KEYFRAME_DATA *cthis_frame,*cnext_frame; + int b,rev_working_timer; + + rev_working_timer=this_section_data->lastframe_timer-this_section_data->accumulated_timer; + cthis_frame=this_frame; + b=0; + + while (b==0) { + if (cthis_frame==NULL) { + cthis_frame=input_frame; // Heaven help us. + } + if (cthis_frame->last_frame) { + /* Low framerate loop? */ + cnext_frame=input_frame; + } + else{ + cnext_frame=cthis_frame->Next_Frame; + } + if (rev_working_timer>=cthis_frame->Sequence_Length) { + /* We've gone beyond this frame: get next keyframe. */ + rev_working_timer-=cthis_frame->Sequence_Length; + /* Advance frame... */ + cthis_frame=cnext_frame; + /* Check flags... */ + if(this_frame->frame_has_extended_data) + { + KEYFRAME_DATA_EXTENDED* this_frame_extended=(KEYFRAME_DATA_EXTENDED*) this_frame; + controller->keyframe_flags|=this_frame_extended->flags; + /* ...And keyframe sounds... */ + if (this_frame_extended->sound) { + if (controller->DisableSounds==0) { + PlayHierarchySound(this_frame_extended->sound,&this_section_data->World_Offset); + } + } + } + } else { + b=1; /* Exit loop with success. */ + } + /* Better make sure the last 'frame' has 65536 length... */ + } + + } + + /* Check for looping? */ + if (this_frame->last_frame) { + if (controller->Looped==0) { + /* Stop at last frame. */ + (*working_timer)=0; + } + } + + this_section_data->lastframe_timer=base_timer; +} + +void New_Analyse_Keyframe_Data(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,KEYFRAME_DATA *input_frame,int base_timer,VECTORCH *output_offset,MATRIXCH *output_matrix) { + + KEYFRAME_DATA *this_frame; + QUAT output_quat; + int working_timer,lerp; + + /* This *should* never fire, should it? */ + + GLOBALASSERT(input_frame); + + /* Check the input is in a sensible place. */ + #if 0 //this can't occur anymore with the new way of storing offsets + if ( !( (input_frame->Offset.vx<1000000 && input_frame->Offset.vx>-1000000) + && (input_frame->Offset.vy<1000000 && input_frame->Offset.vy>-1000000) + && (input_frame->Offset.vz<1000000 && input_frame->Offset.vz>-1000000) + ) ) { + + LOGDXFMT(("First Tests in NEW_ANALYSE_KEYFRAME_DATA.\n")); + if (Global_HModel_Sptr) { + LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype)); + if (Global_HModel_Sptr->SBdptr) { + LOGDXFMT(("Object is Near.\n")); + } else { + LOGDXFMT(("Object is Far.\n")); + } + } else { + LOGDXFMT(("Misplaced object has no SBptr.\n")); + } + LOGDXFMT(("Name of section: %s\n",this_section_data->sempai->Section_Name)); + LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence)); + LOGDXFMT(("Sequence Timer = %d\n",controller->sequence_timer)); + LOGDXFMT(("Tweening flags %d\n",controller->Tweening)); + + if (this_section_data->My_Parent) { + LOGDXFMT(("Parent Position %d,%d,%d\n",this_section_data->My_Parent->World_Offset.vx,this_section_data->My_Parent->World_Offset.vy,this_section_data->My_Parent->World_Offset.vz)); + } else { + LOGDXFMT(("No parent.\n")); + } + LOGDXFMT(("This Position %d,%d,%d\n",this_section_data->World_Offset.vx,this_section_data->World_Offset.vy,this_section_data->World_Offset.vz)); + LOGDXFMT(("This Keyframe Position %d,%d,%d\n",input_frame->Offset.vx,input_frame->Offset.vy,input_frame->Offset.vz)); + + LOCALASSERT(input_frame->Offset.vx<1000000 && input_frame->Offset.vx>-1000000); + LOCALASSERT(input_frame->Offset.vy<1000000 && input_frame->Offset.vy>-1000000); + LOCALASSERT(input_frame->Offset.vz<1000000 && input_frame->Offset.vz>-1000000); + + } + #endif + + /* First find the current frame. */ + + if (input_frame->last_frame) { + /* This is rigid. */ + GetKeyFrameOffset(input_frame,output_offset); + + CopyShortQuatToInt(&input_frame->QOrient,&output_quat); + + /* Elevation gone! Now deltas? */ + + { + DELTA_CONTROLLER *dcon; + QUAT elevation_quat,temp_quat; + VECTORCH elevation_offset; + + dcon=controller->Deltas; + + while (dcon) { + if (dcon->Active) { + Process_Delta_Controller(this_section_data,dcon,&elevation_offset,&elevation_quat); + output_offset->vx+=elevation_offset.vx; + output_offset->vy+=elevation_offset.vy; + output_offset->vz+=elevation_offset.vz; + + temp_quat.quatw=output_quat.quatw; + temp_quat.quatx=output_quat.quatx; + temp_quat.quaty=output_quat.quaty; + temp_quat.quatz=output_quat.quatz; + + MulQuat(&elevation_quat,&temp_quat,&output_quat); + } + dcon=dcon->next_controller; + } + } + + QuatToMat(&output_quat,output_matrix); + + /* Check the output is in a sensible place. */ + if ( !( (output_offset->vx<1000000 && output_offset->vx>-1000000) + && (output_offset->vy<1000000 && output_offset->vy>-1000000) + && (output_offset->vz<1000000 && output_offset->vz>-1000000) + ) ) { + VECTORCH frame_offset; + GetKeyFrameOffset(input_frame,&frame_offset); + + LOGDXFMT(("Second Tests in NEW_ANALYSE_KEYFRAME_DATA.\n")); + if (Global_HModel_Sptr) { + LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype)); + if (Global_HModel_Sptr->SBdptr) { + LOGDXFMT(("Object is Near.\n")); + } else { + LOGDXFMT(("Object is Far.\n")); + } + } else { + LOGDXFMT(("Misplaced object has no SBptr.\n")); + } + LOGDXFMT(("Name of section: %s\n",this_section_data->sempai->Section_Name)); + LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence)); + LOGDXFMT(("Sequence Timer = %d\n",controller->sequence_timer)); + LOGDXFMT(("Tweening flags %d\n",controller->Tweening)); + + if (this_section_data->My_Parent) { + LOGDXFMT(("Parent Position %d,%d,%d\n",this_section_data->My_Parent->World_Offset.vx,this_section_data->My_Parent->World_Offset.vy,this_section_data->My_Parent->World_Offset.vz)); + } else { + LOGDXFMT(("No parent.\n")); + } + LOGDXFMT(("This Position %d,%d,%d\n",this_section_data->World_Offset.vx,this_section_data->World_Offset.vy,this_section_data->World_Offset.vz)); + LOGDXFMT(("This Keyframe Position %d,%d,%d\n",frame_offset.vx,frame_offset.vy,frame_offset.vz)); + LOGDXFMT(("Output Offset %d,%d,%d\n",output_offset->vx,output_offset->vy,output_offset->vz)); + + LOCALASSERT(output_offset->vx<1000000 && output_offset->vx>-1000000); + LOCALASSERT(output_offset->vy<1000000 && output_offset->vy>-1000000); + LOCALASSERT(output_offset->vz<1000000 && output_offset->vz>-1000000); + + } + + return; + } + + /* New way. */ + + Handle_Section_Timer(controller,this_section_data,input_frame,base_timer,&working_timer); + this_frame=this_section_data->current_keyframe; + + /* Now, this_frame and next_frame are set, and working_timerSequence_Length. */ + + + lerp=MUL_FIXED(working_timer,this_frame->oneoversequencelength); + + { + KEYFRAME_DATA* next_frame=this_frame->Next_Frame; + + GetKeyFrameOffset(this_frame,output_offset); + if(next_frame->shift_offset) + { + VECTORCH next_offset; + GetKeyFrameOffset(next_frame,&next_offset); + output_offset->vx+=MUL_FIXED(next_offset.vx - output_offset->vx,lerp); + output_offset->vy+=MUL_FIXED(next_offset.vy - output_offset->vy,lerp); + output_offset->vz+=MUL_FIXED(next_offset.vz - output_offset->vz,lerp); + } + else + { + output_offset->vx+=MUL_FIXED((int)next_frame->Offset_x - output_offset->vx,lerp); + output_offset->vy+=MUL_FIXED((int)next_frame->Offset_y - output_offset->vy,lerp); + output_offset->vz+=MUL_FIXED((int)next_frame->Offset_z - output_offset->vz,lerp); + } + } + /* Now deal with orientation. */ + + + Slerp(this_frame,lerp,&output_quat); + + /* Elevation gone! Now deltas? */ + { + DELTA_CONTROLLER *dcon; + QUAT elevation_quat,temp_quat; + VECTORCH elevation_offset; + + dcon=controller->Deltas; + + while (dcon) { + if (dcon->Active) { + Process_Delta_Controller(this_section_data,dcon,&elevation_offset,&elevation_quat); + output_offset->vx+=elevation_offset.vx; + output_offset->vy+=elevation_offset.vy; + output_offset->vz+=elevation_offset.vz; + + temp_quat.quatw=output_quat.quatw; + temp_quat.quatx=output_quat.quatx; + temp_quat.quaty=output_quat.quaty; + temp_quat.quatz=output_quat.quatz; + + MulQuat(&elevation_quat,&temp_quat,&output_quat); + } + dcon=dcon->next_controller; + } + } + + QuatToMat(&output_quat,output_matrix); + + /* Check the output is in a sensible place. */ + if ( !( (output_offset->vx<1000000 && output_offset->vx>-1000000) + && (output_offset->vy<1000000 && output_offset->vy>-1000000) + && (output_offset->vz<1000000 && output_offset->vz>-1000000) + ) ) { + + VECTORCH frame_offset; + GetKeyFrameOffset(input_frame,&frame_offset); + + LOGDXFMT(("Third Tests in NEW_ANALYSE_KEYFRAME_DATA.\n")); + if (Global_HModel_Sptr) { + LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype)); + if (Global_HModel_Sptr->SBdptr) { + LOGDXFMT(("Object is Near.\n")); + } else { + LOGDXFMT(("Object is Far.\n")); + } + } else { + LOGDXFMT(("Misplaced object has no SBptr.\n")); + } + LOGDXFMT(("Name of section: %s\n",this_section_data->sempai->Section_Name)); + LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence)); + LOGDXFMT(("Sequence Timer = %d\n",controller->sequence_timer)); + LOGDXFMT(("Tweening flags %d\n",controller->Tweening)); + + if (this_section_data->My_Parent) { + LOGDXFMT(("Parent Position %d,%d,%d\n",this_section_data->My_Parent->World_Offset.vx,this_section_data->My_Parent->World_Offset.vy,this_section_data->My_Parent->World_Offset.vz)); + } else { + LOGDXFMT(("No parent.\n")); + } + LOGDXFMT(("This Position %d,%d,%d\n",this_section_data->World_Offset.vx,this_section_data->World_Offset.vy,this_section_data->World_Offset.vz)); + LOGDXFMT(("This Keyframe Position %d,%d,%d\n",frame_offset.vx,frame_offset.vy,frame_offset.vz)); + LOGDXFMT(("Output Offset %d,%d,%d\n",output_offset->vx,output_offset->vy,output_offset->vz)); + + LOCALASSERT(output_offset->vx<1000000 && output_offset->vx>-1000000); + LOCALASSERT(output_offset->vy<1000000 && output_offset->vy>-1000000); + LOCALASSERT(output_offset->vz<1000000 && output_offset->vz>-1000000); + + } + +} + +SHAPEHEADER *Get_Degraded_Shape(SHAPEHEADER *base_shape) +{ + VECTORCH *worldposition,viewposition; + ADAPTIVE_DEGRADATION_DESC *array_ptr; + int lodScale; + extern float CameraZoomScale; + + if ((base_shape->shape_degradation_array==NULL)||(Global_HModel_Sptr==NULL)) { + return(base_shape); + } + + worldposition=&Global_HModel_Sptr->DynPtr->Position; + + MakeVector(worldposition, &Global_VDB_Ptr->VDB_World, &viewposition); + RotateVector(&viewposition, &Global_VDB_Ptr->VDB_Mat); + + + array_ptr=base_shape->shape_degradation_array; + + { + lodScale = (float)GlobalLevelOfDetail_Hierarchical*CameraZoomScale; + + } + /* Now walk array. */ + { + + int objectDistance = viewposition.vz; + + if (lodScale!=ONE_FIXED) + { + objectDistance = MUL_FIXED(objectDistance,lodScale); + } + if (objectDistance<=0) objectDistance=1; + f2i(viewposition.vz, viewposition.vz*CameraZoomScale); + + /* KJL 12:30:37 09/06/98 - the object distance is scaled by a global variable + so that the level of detail can be changed on the fly. + + N.B. The last distance stored in the shape_degradation_array is always zero, so that + the while loop below will always terminate. */ + if (!array_ptr->shapeCanBeUsedCloseUp) + { + if(array_ptr->distanceshape); + } + else + { + array_ptr++; + } + + } + while (array_ptr->distance>objectDistance) array_ptr++; + } + /* Should have a valid entry now. */ + return(array_ptr->shape); +} + +void Process_Section(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,VECTORCH *parent_position,MATRIXCH *parent_orientation,int frame_timer, int sequence_type, int subsequence, int render) { + + KEYFRAME_DATA *sequence_start; + SECTION *this_section; + SEQUENCE *this_sequence; + + VECTORCH diagnostic_vector; + int Use_GoreRate; + + /* Work out which SECTION to use. */ + + this_section=this_section_data->sempai; + + if (controller!=this_section_data->my_controller) { + LOGDXFMT(("Wrong Controller assert in PROCESS_SECTION.w\n")); + LOGDXFMT(("Name of section: %s\n",this_section_data->sempai->Section_Name)); + LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence)); + LOGDXFMT(("Sequence Timer = %d\n",controller->sequence_timer)); + LOGDXFMT(("Tweening flags %d\n",controller->Tweening)); + GLOBALASSERT(controller==this_section_data->my_controller); + } + + /* We can't just stop at a terminate_here, because that will + do over the section_data list. */ + + /* Well, actually, now we can. */ + + /* Put in a sequence switcher!!! */ + + /* There now is one. */ + + /* Quick auto-correction... */ + if (frame_timer<0) { + frame_timer=0; + } + + if (frame_timer>=65536) { + frame_timer=65535; + } + + diagnostic_vector.vx=0; + diagnostic_vector.vy=0; + diagnostic_vector.vz=0; + + if ((controller->FrameStamp!=GlobalFrameCounter) + ||((this_section_data->flags§ion_data_initialised)==0)) { + + int fake_frame_timer; + + /* Positions not computed yet this frame. */ + + this_sequence=GetSequencePointer(sequence_type,subsequence,this_section); + sequence_start=this_sequence->first_frame; + + if ((controller->LockTopSection)&&(this_section_data==controller->section_data)) { + fake_frame_timer=0; + } else { + fake_frame_timer=frame_timer; + } + + /* For this section, find the interpolated offset and eulers. */ + this_section_data->Last_World_Offset=this_section_data->World_Offset; + + if (this_section_data->Tweening) { + Analyse_Tweening_Data(controller,this_section_data,frame_timer,&(this_section_data->World_Offset),&(this_section_data->RelSecMat)); + } else { + New_Analyse_Keyframe_Data(controller,this_section_data,sequence_start,fake_frame_timer,&(this_section_data->World_Offset),&(this_section_data->RelSecMat)); + } + + if ((controller->ZeroRootDisplacement)&&(this_section_data==controller->section_data)) { + this_section_data->World_Offset.vx=0; + this_section_data->World_Offset.vy=0; + this_section_data->World_Offset.vz=0; + } + + if ((controller->ZeroRootRotation)&&(this_section_data==controller->section_data)) { + this_section_data->RelSecMat=Identity_RotMat; + } + + this_section_data->Offset=this_section_data->World_Offset; + + diagnostic_vector=this_section_data->World_Offset; + + /* The parent's position will be used with the offset value and rotation + matrix to determine the position of the new section. */ + + RotateVector(&this_section_data->World_Offset,parent_orientation); + AddVector(parent_position,&(this_section_data->World_Offset)); + + /* Create the absolute rotation matrix for this section. */ + MatrixMultiply(parent_orientation,&(this_section_data->RelSecMat),&(this_section_data->SecMat)); + + /* Set the initialised flag... */ + this_section_data->flags|=section_data_initialised; + } + + /* Check the object is in a sensible place. */ + if ( !( (this_section_data->World_Offset.vx<1000000 && this_section_data->World_Offset.vx>-1000000) + && (this_section_data->World_Offset.vy<1000000 && this_section_data->World_Offset.vy>-1000000) + && (this_section_data->World_Offset.vz<1000000 && this_section_data->World_Offset.vz>-1000000) + ) ) { + + LOGDXFMT(("Tests in PROCESS_SECTION.\n")); + if (Global_HModel_Sptr) { + LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype)); + if (Global_HModel_Sptr->SBdptr) { + LOGDXFMT(("Object is Near.\n")); + } else { + LOGDXFMT(("Object is Far.\n")); + } + } else { + LOGDXFMT(("Misplaced object has no SBptr.\n")); + } + LOGDXFMT(("Name of section: %s\n",this_section_data->sempai->Section_Name)); + LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence)); + LOGDXFMT(("Sequence Timer = %d\n",controller->sequence_timer)); + LOGDXFMT(("Tweening flags %d\n",controller->Tweening)); + + LOGDXFMT(("Diagnostic Vector %d,%d,%d\n",diagnostic_vector.vx,diagnostic_vector.vy,diagnostic_vector.vz)); + LOGDXFMT(("Parent Orientation Matrix: %d,%d,%d\n",parent_orientation->mat11,parent_orientation->mat12,parent_orientation->mat13)); + LOGDXFMT(("Parent Orientation Matrix: %d,%d,%d\n",parent_orientation->mat21,parent_orientation->mat22,parent_orientation->mat23)); + LOGDXFMT(("Parent Orientation Matrix: %d,%d,%d\n",parent_orientation->mat31,parent_orientation->mat32,parent_orientation->mat33)); + + LOGDXFMT(("Parent Position %d,%d,%d\n",parent_position->vx,parent_position->vy,parent_position->vz)); + LOGDXFMT(("This Position %d,%d,%d\n",this_section_data->World_Offset.vx,this_section_data->World_Offset.vy,this_section_data->World_Offset.vz)); + + LOCALASSERT(this_section_data->World_Offset.vx<1000000 && this_section_data->World_Offset.vx>-1000000); + LOCALASSERT(this_section_data->World_Offset.vy<1000000 && this_section_data->World_Offset.vy>-1000000); + LOCALASSERT(this_section_data->World_Offset.vz<1000000 && this_section_data->World_Offset.vz>-1000000); + + } + + /* Now call recursion... */ + + if ((this_section_data->First_Child!=NULL) + &&( (this_section_data->flags§ion_data_terminate_here)==0)) { + + SECTION_DATA *child_ptr; + + child_ptr=this_section_data->First_Child; + + while (child_ptr!=NULL) { + + LOCALASSERT(child_ptr->My_Parent==this_section_data); + + Process_Section(controller,child_ptr,&(this_section_data->World_Offset),&(this_section_data->SecMat),frame_timer,sequence_type,subsequence,render); + child_ptr=child_ptr->Next_Sibling; + } + + } + + /* Finally, if this section has a shape, and we are rendering, render it. */ + + if ((this_section_data->Shape!=NULL)&&((this_section_data->flags§ion_data_notreal)==0) + &&(render)) { + /* Unreal things don't get plotted, either. */ + + extern MATRIXCH IdentityMatrix; + + DISPLAYBLOCK dummy_displayblock; + SHAPEHEADER *shape_to_use; + + GLOBALASSERT(this_section_data->ShapeNum); + + /* Decide what shape to use. */ + + if (this_section_data->Shape) { + if (this_section_data->Shape->shape_degradation_array==NULL) { + shape_to_use=this_section_data->Shape; + } else { + shape_to_use=Get_Degraded_Shape(this_section_data->Shape); + } + } else { + shape_to_use=NULL; + } + + /* This really needs to be pre-zeroed, a static + in this file... but not yet. */ + + if (Simplify_HModel_Rendering) { + dummy_displayblock.ObShape=GetLoadedShapeMSL("Shell"); + dummy_displayblock.ObShapeData=GetShapeData(dummy_displayblock.ObShape); + } else { + dummy_displayblock.ObShape=this_section_data->ShapeNum; + dummy_displayblock.ObShapeData=shape_to_use; + } + dummy_displayblock.name=NULL; + dummy_displayblock.ObWorld=this_section_data->World_Offset; + dummy_displayblock.ObEuler.EulerX=0; + dummy_displayblock.ObEuler.EulerY=0; + dummy_displayblock.ObEuler.EulerZ=0; + dummy_displayblock.ObMat=this_section_data->SecMat; + dummy_displayblock.ObFlags=ObFlag_VertexHazing|ObFlag_MultLSrc; + dummy_displayblock.ObFlags2=Global_HModel_DispPtr->ObFlags2; + dummy_displayblock.ObFlags3=0; + dummy_displayblock.ObNumLights=0; + dummy_displayblock.ObVDBPtr=NULL; + if(shape_to_use) + dummy_displayblock.ObRadius=shape_to_use->shaperadius; + else + dummy_displayblock.ObRadius=0; + dummy_displayblock.ObMaxX=0; + dummy_displayblock.ObMinX=0; + dummy_displayblock.ObMaxY=0; + dummy_displayblock.ObMinY=0; + dummy_displayblock.ObMaxZ=0; + dummy_displayblock.ObMinZ=0; + dummy_displayblock.ObTxAnimCtrlBlks=this_section_data->tac_ptr; + dummy_displayblock.ObEIDPtr=NULL; + dummy_displayblock.ObMorphCtrl=NULL; + dummy_displayblock.ObStrategyBlock=Global_HModel_Sptr; + dummy_displayblock.ShapeAnimControlBlock=this_section_data->sac_ptr; + dummy_displayblock.HModelControlBlock=NULL; /* Don't even want to think about that. */ + dummy_displayblock.ObMyModule=NULL; + dummy_displayblock.SpecialFXFlags = Global_HModel_DispPtr->SpecialFXFlags; + + MakeVector(&dummy_displayblock.ObWorld, &Global_VDB_Ptr->VDB_World, &dummy_displayblock.ObView); + RotateVector(&dummy_displayblock.ObView, &Global_VDB_Ptr->VDB_Mat); + + /* Whilst we're here... */ + + this_section_data->View_Offset=dummy_displayblock.ObView; + this_section_data->flags|=section_data_view_init; + controller->View_FrameStamp=GlobalFrameCounter; + + /* Ho hum. */ + + if (dummy_displayblock.ShapeAnimControlBlock) { + DoShapeAnimation(&dummy_displayblock); + } + + if(this_section->flags&(section_flag_heatsource|section_flag_affectedbyheat)) + { + dummy_displayblock.SpecialFXFlags|=SFXFLAG_ISAFFECTEDBYHEAT; + } + + #if 1 + if (PIPECLEANER_CHEATMODE) + if (Global_HModel_Sptr) + if (Global_HModel_Sptr->SBdptr) + if (! ((Global_HModel_Sptr->SBdptr->ObWorld.vx == parent_position->vx) + &&(Global_HModel_Sptr->SBdptr->ObWorld.vy == parent_position->vy) + &&(Global_HModel_Sptr->SBdptr->ObWorld.vz == parent_position->vz)) ) + { + PARTICLE particle; + + particle.Colour = 0xffffffff; + particle.Size = 30; + + particle.ParticleID = PARTICLE_LASERBEAM; + particle.Position = this_section_data->World_Offset; + particle.Offset = *parent_position;; + + D3D_DecalSystem_Setup(); + RenderParticle(&particle); + + particle.ParticleID=PARTICLE_ANDROID_BLOOD; + + particle.Size = shape_to_use->shaperadius/8; + RenderParticle(&particle); + D3D_DecalSystem_End(); + + } + #endif + + RenderThisHierarchicalDisplayblock(&dummy_displayblock); + + } else if (controller->View_FrameStamp!=GlobalFrameCounter) { + this_section_data->flags&=(~section_data_view_init); + } + + /* Gore spray... */ + + if (GlobalGoreRate==0) return; + if (NumberOfBloodParticles>=MAX_NO_OF_BLOOD_PARTICLES) return; + if (controller->DisableBleeding) return; + + Use_GoreRate=GlobalGoreRate; + if (SUPERGORE_MODE) { + Use_GoreRate/=5; + } + + /* A terminator must spray (backwards) from the origin, to be the stump. */ + + if (this_section_data->flags§ion_data_terminate_here) { + if (this_section->flags§ion_sprays_anything) { + /* Check for non-zero spray direction... */ + if ( (this_section->gore_spray_direction.vx!=0) + || (this_section->gore_spray_direction.vy!=0) + || (this_section->gore_spray_direction.vz!=0) ) { + + this_section_data->gore_timer+=NormalFrameTime; + + /* New and Special Sparks Code! 16/7/98 */ + if (this_section->flags§ion_sprays_sparks) { + while (this_section_data->gore_timer>(GlobalGoreRate*SPARKS_FOR_A_SPRAY)) { + + VECTORCH final_spray_direction; + MATRIXCH spray_orient; + /* Spray is go! */ + + RotateAndCopyVector(&this_section->gore_spray_direction,&final_spray_direction,&this_section_data->SecMat); + + /* Reverse direction for stumps. */ + + final_spray_direction.vx=-final_spray_direction.vx; + final_spray_direction.vy=-final_spray_direction.vy; + final_spray_direction.vz=-final_spray_direction.vz; + + /* Scale down. */ + + final_spray_direction.vx>>=5; + final_spray_direction.vy>>=5; + final_spray_direction.vz>>=5; + + /* Add random element. */ + + final_spray_direction.vx+=( (FastRandom()&1023)-512); + final_spray_direction.vy+=( (FastRandom()&1023)-512); + final_spray_direction.vz+=( (FastRandom()&1023)-512); + + Normalise(&final_spray_direction); + /* Now convert back to a matrix. */ + MakeMatrixFromDirection(&final_spray_direction,&spray_orient); + + /* Call spray function. */ + + MakeSprayOfSparks(&spray_orient,&this_section_data->World_Offset); + + Sound_Play(SID_SPARKS,"d",&this_section_data->World_Offset); + + this_section_data->gore_timer-=(GlobalGoreRate*SPARKS_FOR_A_SPRAY); + } + GLOBALASSERT(this_section_data->gore_timer<=(GlobalGoreRate*SPARKS_FOR_A_SPRAY)); + } else { + while (this_section_data->gore_timer>Use_GoreRate) { + + VECTORCH final_spray_direction; + enum PARTICLE_ID blood_type; + /* Spray is go! */ + + RotateAndCopyVector(&this_section->gore_spray_direction,&final_spray_direction,&this_section_data->SecMat); + + /* Reverse direction for stumps. */ + + final_spray_direction.vx=-final_spray_direction.vx; + final_spray_direction.vy=-final_spray_direction.vy; + final_spray_direction.vz=-final_spray_direction.vz; + + /* Scale down. */ + + final_spray_direction.vx>>=5; + final_spray_direction.vy>>=5; + final_spray_direction.vz>>=5; + + /* Add random element. */ + + final_spray_direction.vx+=( (FastRandom()&1023)-512); + final_spray_direction.vy+=( (FastRandom()&1023)-512); + final_spray_direction.vz+=( (FastRandom()&1023)-512); + + if (SUPERGORE_MODE) { + final_spray_direction.vx<<=1; + final_spray_direction.vy<<=1; + final_spray_direction.vz<<=1; + } + + /* Identify spray type. */ + + if (this_section->flags§ion_sprays_blood) { + blood_type=GetBloodType(Global_HModel_Sptr); + /* Er... default? */ + } else if (this_section->flags§ion_sprays_acid) { + blood_type=PARTICLE_ALIEN_BLOOD; + } else if (this_section->flags§ion_sprays_predoblood) { + blood_type=PARTICLE_PREDATOR_BLOOD; + } else if (this_section->flags§ion_sprays_sparks) { + blood_type=PARTICLE_SPARK; + } else { + blood_type=PARTICLE_FLAME; + /* Distinctive. */ + } + + /* Call spray function. */ + + MakeParticle(&this_section_data->World_Offset, &final_spray_direction, blood_type); + + this_section_data->gore_timer-=Use_GoreRate; + } + } + } + } + } + + /* A false root must also spray from the origin... to be the missing part. */ + + if (this_section_data->flags§ion_data_false_root) { + if (this_section->flags§ion_sprays_anything) { + /* Check for non-zero spray direction... */ + if ( (this_section->gore_spray_direction.vx!=0) + || (this_section->gore_spray_direction.vy!=0) + || (this_section->gore_spray_direction.vz!=0) ) { + + this_section_data->gore_timer+=NormalFrameTime; + + /* I don't *think* a section can be both... */ + /* But if it is, we'll just have to live with it. */ + + /* New and Special Sparks Code! 16/7/98 */ + if (this_section->flags§ion_sprays_sparks) { + while (this_section_data->gore_timer>(GlobalGoreRate*SPARKS_FOR_A_SPRAY)) { + + VECTORCH final_spray_direction; + MATRIXCH spray_orient; + + /* Spray is go! */ + + RotateAndCopyVector(&this_section->gore_spray_direction,&final_spray_direction,&this_section_data->SecMat); + + /* Scale down. */ + + final_spray_direction.vx>>=5; + final_spray_direction.vy>>=5; + final_spray_direction.vz>>=5; + + /* Add random element. */ + + final_spray_direction.vx+=( (FastRandom()&1023)-512); + final_spray_direction.vy+=( (FastRandom()&1023)-512); + final_spray_direction.vz+=( (FastRandom()&1023)-512); + Normalise(&final_spray_direction); + + /* Now convert back to a matrix. */ + MakeMatrixFromDirection(&final_spray_direction,&spray_orient); + + /* Call spray function. */ + + MakeSprayOfSparks(&spray_orient,&this_section_data->World_Offset); + + Sound_Play(SID_SPARKS,"d",&this_section_data->World_Offset); + + this_section_data->gore_timer-=(GlobalGoreRate*SPARKS_FOR_A_SPRAY); + } + GLOBALASSERT(this_section_data->gore_timer<=(GlobalGoreRate*SPARKS_FOR_A_SPRAY)); + } else { + + while (this_section_data->gore_timer>Use_GoreRate) { + + enum PARTICLE_ID blood_type; + VECTORCH final_spray_direction; + /* Spray is go! */ + + RotateAndCopyVector(&this_section->gore_spray_direction,&final_spray_direction,&this_section_data->SecMat); + + /* Scale down. */ + + final_spray_direction.vx>>=5; + final_spray_direction.vy>>=5; + final_spray_direction.vz>>=5; + + /* Add random element. */ + + final_spray_direction.vx+=( (FastRandom()&1023)-512); + final_spray_direction.vy+=( (FastRandom()&1023)-512); + final_spray_direction.vz+=( (FastRandom()&1023)-512); + + if (SUPERGORE_MODE) { + final_spray_direction.vx<<=1; + final_spray_direction.vy<<=1; + final_spray_direction.vz<<=1; + } + + /* Identify spray type. */ + + if (this_section->flags§ion_sprays_blood) { + blood_type=GetBloodType(Global_HModel_Sptr); + /* Er... default? */ + } else if (this_section->flags§ion_sprays_acid) { + blood_type=PARTICLE_ALIEN_BLOOD; + } else if (this_section->flags§ion_sprays_predoblood) { + blood_type=PARTICLE_PREDATOR_BLOOD; + } else if (this_section->flags§ion_sprays_sparks) { + blood_type=PARTICLE_SPARK; + } else { + blood_type=PARTICLE_FLAME; + /* Distinctive. */ + } + + /* Call spray function. */ + + MakeParticle(&this_section_data->World_Offset, &final_spray_direction, blood_type); + + this_section_data->gore_timer-=Use_GoreRate; + } + } + } + } + } + + /* Part three... wounded section. */ + + if (this_section_data->current_damage.Health<(this_section->StartingStats.Health<flags§ion_sprays_anything) { + int bleeding_rate; + + if (this_section_data->current_damage.Health==0) { + /* Bleed a lot. */ + bleeding_rate=Use_GoreRate; + } else { + /* Just bleed a bit. */ + bleeding_rate=(Use_GoreRate<<1); + } + + /* Don't care about non-zero spray direction here. */ + + this_section_data->gore_timer+=NormalFrameTime; + + /* I don't *think* a section can be both... */ + /* But if it is, we'll just have to live with it. */ + + /* New and Special Sparks Code! 16/7/98 */ + if (this_section->flags§ion_sprays_sparks) { + while (this_section_data->gore_timer>(bleeding_rate*SPARKS_FOR_A_SPRAY)) { + + VECTORCH final_spray_direction; + MATRIXCH spray_orient; + + /* Spray is go! */ + + /* Zero base direction. */ + + final_spray_direction.vx=0; + final_spray_direction.vy=0; + final_spray_direction.vz=0; + + /* Add random element. */ + + while ( (final_spray_direction.vx==0) + &&(final_spray_direction.vy==0) + &&(final_spray_direction.vz==0)) { + final_spray_direction.vx+=( (FastRandom()&1023)-512); + final_spray_direction.vy+=( (FastRandom()&1023)-512); + final_spray_direction.vz+=( (FastRandom()&1023)-512); + } + Normalise(&final_spray_direction); + + /* Now convert back to a matrix. */ + MakeMatrixFromDirection(&final_spray_direction,&spray_orient); + + /* Call spray function. */ + + MakeSprayOfSparks(&spray_orient,&this_section_data->World_Offset); + + Sound_Play(SID_SPARKS,"d",&this_section_data->World_Offset); + + this_section_data->gore_timer-=(bleeding_rate*SPARKS_FOR_A_SPRAY); + } + GLOBALASSERT(this_section_data->gore_timer<=(bleeding_rate*SPARKS_FOR_A_SPRAY)); + } else { + + while (this_section_data->gore_timer>bleeding_rate) { + + enum PARTICLE_ID blood_type; + VECTORCH final_spray_direction; + /* Spray is go! */ + + /* Zero base direction. */ + + final_spray_direction.vx=0; + final_spray_direction.vy=0; + final_spray_direction.vz=0; + + /* Add random element. */ + + final_spray_direction.vx+=( (FastRandom()&1023)-512); + final_spray_direction.vy+=( (FastRandom()&1023)-512); + final_spray_direction.vz+=( (FastRandom()&1023)-512); + + /* Identify spray type. */ + + if (this_section->flags§ion_sprays_blood) { + blood_type=GetBloodType(Global_HModel_Sptr); + /* Er... default? */ + } else if (this_section->flags§ion_sprays_acid) { + blood_type=PARTICLE_ALIEN_BLOOD; + } else if (this_section->flags§ion_sprays_predoblood) { + blood_type=PARTICLE_PREDATOR_BLOOD; + } else if (this_section->flags§ion_sprays_sparks) { + blood_type=PARTICLE_SPARK; + } else { + blood_type=PARTICLE_FLAME; + /* Distinctive. */ + } + + /* Call spray function. */ + + MakeParticle(&this_section_data->World_Offset, &final_spray_direction, blood_type); + + this_section_data->gore_timer-=bleeding_rate; + } + GLOBALASSERT(this_section_data->gore_timer<=bleeding_rate); + } + } + } + +} + +void Init_Sequence_Recursion(SECTION_DATA *this_section_data, int sequence_type,int subsequence, int seconds_for_sequence) { + + SEQUENCE *sequence_ptr; + + sequence_ptr=GetSequencePointer(sequence_type,subsequence,this_section_data->sempai); + + /* Init fields. */ + + this_section_data->current_sequence=sequence_ptr; + this_section_data->current_keyframe=sequence_ptr->first_frame; + this_section_data->accumulated_timer=0; + this_section_data->freezeframe_timer=-1; + this_section_data->lastframe_timer=0; + this_section_data->gore_timer=0; /* As good a time as any. */ + + /* Zero last world offset, just for the record. */ + this_section_data->Last_World_Offset.vx=0; + this_section_data->Last_World_Offset.vy=0; + this_section_data->Last_World_Offset.vz=0; + + /* Deinit tweening. */ + + this_section_data->Tweening=0; + + /* Keyframe and Sound Flags. */ + if(sequence_ptr->first_frame->frame_has_extended_data) + { + KEYFRAME_DATA_EXTENDED* first_frame_extended=(KEYFRAME_DATA_EXTENDED*) sequence_ptr->first_frame; + this_section_data->my_controller->keyframe_flags|=first_frame_extended->flags; + if (first_frame_extended->sound) { + if (this_section_data->flags§ion_data_initialised) { + if (this_section_data->my_controller->DisableSounds==0) { + PlayHierarchySound(first_frame_extended->sound,&this_section_data->World_Offset); + } + } + } + } + /* Animation. */ + + if (this_section_data->sac_ptr) { + + SHAPEANIMATIONCONTROLDATA sacd ; + SHAPEANIMATIONSEQUENCE *sequence_pointer; + int num_frames,sequence; + + sequence=(sequence_type<<16)+subsequence; + + InitShapeAnimationControlData(&sacd); + /* Compute rate. */ + + sequence_pointer=this_section_data->sac_ptr->anim_header->anim_sequences; + GLOBALASSERT(sequencesac_ptr->anim_header->num_sequences); + num_frames=sequence_pointer[sequence].num_frames; + + sacd.seconds_per_frame = seconds_for_sequence/num_frames; + /* Okay. */ + sacd.sequence_no = sequence; + sacd.default_start_and_end_frames = 1; + sacd.reversed = 0; + sacd.stop_at_end = 0; + SetOrphanedShapeAnimationSequence (this_section_data->sac_ptr, &sacd); + + } + + /* Recurse. */ + + if ( (this_section_data->First_Child!=NULL) + &&( (this_section_data->flags§ion_data_terminate_here)==0)) { + /* Respect the terminator! */ + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + Init_Sequence_Recursion(child_list_ptr,sequence_type,subsequence,seconds_for_sequence); + child_list_ptr=child_list_ptr->Next_Sibling; + } + + } + +} + +void HModel_ChangeSpeed(HMODELCONTROLLER *controller, int seconds_for_sequence) { + + /* Simple enough... */ + + controller->Seconds_For_Sequence=seconds_for_sequence; + controller->timer_increment=DIV_FIXED(ONE_FIXED,controller->Seconds_For_Sequence); + +} + +void HModel_SetToolsRelativeSpeed(HMODELCONTROLLER *controller, int factor) { + + KEYFRAME_DATA *sequence_start; + SEQUENCE *this_sequence; + int real_time; + + GLOBALASSERT(controller); + GLOBALASSERT(factor>0); + /* Find the tools speed for this sequence... */ + + this_sequence=GetSequencePointer(controller->Sequence_Type,controller->Sub_Sequence,controller->Root_Section); + sequence_start=this_sequence->first_frame; + GLOBALASSERT(sequence_start); + + real_time=this_sequence->Time; + if (real_time<=0) { + real_time=ONE_FIXED; + /* Might want to assert here? */ + } + + real_time=MUL_FIXED(real_time,factor); + HModel_ChangeSpeed(controller,real_time); + +} + +void InitHModelSequence(HMODELCONTROLLER *controller, int sequence_type,int subsequence, int seconds_for_sequence) { + + KEYFRAME_DATA *sequence_start; + SEQUENCE *this_sequence; + int real_time; + + GLOBALASSERT(controller); + GLOBALASSERT(seconds_for_sequence); + + /* Check this sequence exists... */ + + this_sequence=GetSequencePointer(sequence_type,subsequence,controller->Root_Section); + sequence_start=this_sequence->first_frame; + GLOBALASSERT(sequence_start); + + if (seconds_for_sequence>0) { + real_time=seconds_for_sequence; + } else { + real_time=this_sequence->Time; + if (real_time<=0) { + real_time=ONE_FIXED; + /* Might want to assert here. */ + } + } + + /* Now set it up. */ + + controller->Sequence_Type=sequence_type; + controller->Sub_Sequence=subsequence; + controller->Seconds_For_Sequence=real_time; + controller->timer_increment=DIV_FIXED(ONE_FIXED,controller->Seconds_For_Sequence); + controller->sequence_timer=0; + controller->Playing=1; + controller->Reversed=0; + controller->Looped=1; + + controller->keyframe_flags=0; + + controller->After_Tweening_Sequence_Type=-1; + controller->After_Tweening_Sub_Sequence=-1; + controller->AT_seconds_for_sequence=ONE_FIXED; + controller->AT_sequence_timer=0; + controller->Tweening=Controller_NoTweening; + + /* Recurse though hierarchy, setting up all the section_data sequence stores? */ + + Init_Sequence_Recursion(controller->section_data, sequence_type, subsequence,seconds_for_sequence); + +} + +static void HMTimer_Kernel(HMODELCONTROLLER *controller) { + + /* Core of the timer code. */ + + if (controller->Tweening==Controller_EndTweening) { + int reversed, AT_sequence_timer; + + reversed=controller->Reversed; /* Remember this! */ + AT_sequence_timer=controller->AT_sequence_timer; /* Remember this, too! */ + + if (controller->AT_seconds_for_sequence==0) { + GLOBALASSERT(controller->AT_seconds_for_sequence); + } + + InitHModelSequence(controller,controller->After_Tweening_Sequence_Type, + controller->After_Tweening_Sub_Sequence,controller->AT_seconds_for_sequence); + + if (reversed) { + controller->Reversed=1; + #if 0 + controller->sequence_timer=(ONE_FIXED-1); + #endif + } + + /* This should now always be set, though InitHModelSequence zeros it (D'oh!). */ + controller->sequence_timer=AT_sequence_timer; + + if (controller->LoopAfterTweening) { + controller->Looped=1; + } else { + controller->Looped=0; + } + if (controller->StopAfterTweening) { + /* Hey ho. */ + controller->Playing=0; + } + controller->Tweening=Controller_NoTweening; + controller->ElevationTweening=0; + } + + if (controller->Playing) { + if (controller->Reversed) { + if (controller->Tweening!=Controller_NoTweening) { + GLOBALASSERT(controller->Tweening==Controller_Tweening); + /* Still tween forwards. */ + controller->sequence_timer+=MUL_FIXED(controller->timer_increment,NormalFrameTime); + if (controller->sequence_timer>=ONE_FIXED) { + controller->sequence_timer=ONE_FIXED; + controller->Tweening=Controller_EndTweening; + } + } else { + GLOBALASSERT(controller->Tweening==Controller_NoTweening); + controller->sequence_timer-=MUL_FIXED(controller->timer_increment,NormalFrameTime); + if (controller->Looped) { + while (controller->sequence_timer<0) { + /* Might lose count of how many times we've looped, but who's counting? */ + controller->sequence_timer+=ONE_FIXED; + } + } else { + if (controller->sequence_timer<0) { + controller->sequence_timer=0; + } + } + } + } else { + controller->sequence_timer+=MUL_FIXED(controller->timer_increment,NormalFrameTime); + + if (controller->Tweening!=Controller_NoTweening) { + GLOBALASSERT(controller->Tweening==Controller_Tweening); + if (controller->sequence_timer>=ONE_FIXED) { + controller->sequence_timer=ONE_FIXED; + controller->Tweening=Controller_EndTweening; + } + + } else if (controller->Looped) { + while (controller->sequence_timer>=ONE_FIXED) { + /* Might lose count of how many times we've looped, but who's counting? */ + controller->sequence_timer-=ONE_FIXED; + } + } else { + if (controller->sequence_timer>=ONE_FIXED) { + controller->sequence_timer=ONE_FIXED-1; + } + } + } + } + + /* Do delta timers, too. */ + + { + DELTA_CONTROLLER *dcon; + + dcon=controller->Deltas; + + while (dcon) { + + if ((dcon->seconds_for_sequence)&&(dcon->Playing)&&(dcon->Active)) { + dcon->timer+=MUL_FIXED(dcon->timer_increment,NormalFrameTime); + if (dcon->Looped) { + if (dcon->timer>=ONE_FIXED) dcon->timer-=ONE_FIXED; + } else { + if (dcon->timer>=ONE_FIXED) dcon->timer=ONE_FIXED-1; + } + } + + dcon=dcon->next_controller; + } + } + +} + +void DoHModel(HMODELCONTROLLER *controller, DISPLAYBLOCK *dptr) { + + extern int NormalFrameTime; + + GLOBALASSERT(controller); + GLOBALASSERT(dptr); + + Global_HModel_Sptr=dptr->ObStrategyBlock; + Global_HModel_DispPtr=dptr; + + /* Check the object is in a sensible place. */ + if ( !( (dptr->ObWorld.vx<1000000 && dptr->ObWorld.vx>-1000000) + && (dptr->ObWorld.vy<1000000 && dptr->ObWorld.vy>-1000000) + && (dptr->ObWorld.vz<1000000 && dptr->ObWorld.vz>-1000000) + ) ) { + + LOGDXFMT(("Tests in DOHMODEL.\n")); + if (Global_HModel_Sptr) { + LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype)); + } else { + LOGDXFMT(("Misplaced object has no SBptr.\n")); + } + LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence)); + + LOCALASSERT(dptr->ObWorld.vx<1000000 && dptr->ObWorld.vx>-1000000); + LOCALASSERT(dptr->ObWorld.vy<1000000 && dptr->ObWorld.vy>-1000000); + LOCALASSERT(dptr->ObWorld.vz<1000000 && dptr->ObWorld.vz>-1000000); + + } + + GLOBALASSERT(controller->section_data->my_controller==controller); + + /* Only do timer if you're out of date. */ + + if (controller->FrameStamp!=GlobalFrameCounter) { + + HMTimer_Kernel(controller); + + controller->keyframe_flags=0; + + } else { + VECTORCH offset; + /* Want to budge? */ + + offset.vx=dptr->ObWorld.vx-controller->Computed_Position.vx; + offset.vy=dptr->ObWorld.vy-controller->Computed_Position.vy; + offset.vz=dptr->ObWorld.vz-controller->Computed_Position.vz; + + if ((offset.vx!=0)||(offset.vy!=0)||(offset.vz!=0)) { + /* I reckon you'd be better off taking the budge. */ + Budge_HModel(controller,&offset); + } + + } + + /* That handled the timer. Now render it. */ + { + int render; + + if (dptr->ObFlags&ObFlag_NotVis) { + textprint("HModel NotVis!\n"); + render=0; + } else { + render=1; + } + Process_Section(controller,controller->section_data,&dptr->ObWorld,&dptr->ObMat,controller->sequence_timer,controller->Sequence_Type,controller->Sub_Sequence,render); + + } + /* Note braces! Process_Section is OUTSIDE, 'cos you might still want to render! */ + + /* Update frame stamp. */ + + controller->FrameStamp=GlobalFrameCounter; + controller->Computed_Position=dptr->ObWorld; + +} + +void DoHModelTimer_Recursion(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,int frame_timer, int sequence_type, int subsequence) { + + KEYFRAME_DATA *sequence_start; + SECTION *this_section; + SEQUENCE *this_sequence; + + /* Cut down Process_Section. */ + + this_section=this_section_data->sempai; + + if (controller->FrameStamp!=GlobalFrameCounter) { + + /* Positions not computed yet this frame. */ + + this_sequence=GetSequencePointer(sequence_type,subsequence,this_section); + sequence_start=this_sequence->first_frame; + + /* For this section, find the interpolated offset and eulers. */ + + if (this_section_data->Tweening) { + /* Err... do nothing. */ + } else { + int working_timer; + + Handle_Section_Timer(controller,this_section_data,sequence_start,frame_timer, &working_timer); + } + + } + + /* Now call recursion... */ + + if ((this_section_data->First_Child!=NULL) + &&( (this_section_data->flags§ion_data_terminate_here)==0)) { + + SECTION_DATA *child_ptr; + + child_ptr=this_section_data->First_Child; + + while (child_ptr!=NULL) { + + LOCALASSERT(child_ptr->My_Parent==this_section_data); + + DoHModelTimer_Recursion(controller,child_ptr,frame_timer,sequence_type,subsequence); + child_ptr=child_ptr->Next_Sibling; + } + + } + +} + +void DoHModelTimer(HMODELCONTROLLER *controller) { + + extern int NormalFrameTime; + + /* Be VERY careful with this function - it can put the timer and the + position computations out of step. Once you've called this, call NO + OTHER HMODEL FUNCTIONS on this model until the next frame! */ + + GLOBALASSERT(controller); + + if (controller->FrameStamp==GlobalFrameCounter) { + /* Done a timer this frame already! */ + return; + } + + controller->keyframe_flags=0; + + HMTimer_Kernel(controller); + + /* That handled the timer. No rendering this time. */ + + DoHModelTimer_Recursion(controller,controller->section_data,controller->sequence_timer,controller->Sequence_Type,controller->Sub_Sequence); + +} + +void ProveHModel(HMODELCONTROLLER *controller, DISPLAYBLOCK *dptr) { + + /* Simply to verify a new hmodel, and remove junk. */ + + GLOBALASSERT(controller); + GLOBALASSERT(dptr); + + Global_HModel_Sptr=dptr->ObStrategyBlock; + + /* Check the object is in a sensible place. */ + if ( !( (dptr->ObWorld.vx<1000000 && dptr->ObWorld.vx>-1000000) + && (dptr->ObWorld.vy<1000000 && dptr->ObWorld.vy>-1000000) + && (dptr->ObWorld.vz<1000000 && dptr->ObWorld.vz>-1000000) + ) ) { + + LOGDXFMT(("Tests in PROVEHMODEL.\n")); + if (Global_HModel_Sptr) { + LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype)); + } else { + LOGDXFMT(("Misplaced object has no SBptr.\n")); + } + LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence)); + + LOCALASSERT(dptr->ObWorld.vx<1000000 && dptr->ObWorld.vx>-1000000); + LOCALASSERT(dptr->ObWorld.vy<1000000 && dptr->ObWorld.vy>-1000000); + LOCALASSERT(dptr->ObWorld.vz<1000000 && dptr->ObWorld.vz>-1000000); + + } + + GLOBALASSERT(controller->section_data->my_controller==controller); + + if (controller->FrameStamp==GlobalFrameCounter) { + VECTORCH offset; + /* Want to budge? */ + + offset.vx=dptr->ObWorld.vx-controller->Computed_Position.vx; + offset.vy=dptr->ObWorld.vy-controller->Computed_Position.vy; + offset.vz=dptr->ObWorld.vz-controller->Computed_Position.vz; + + if ((offset.vx!=0)||(offset.vy!=0)||(offset.vz!=0)) { + /* I reckon you'd be better off taking the budge. */ + Budge_HModel(controller,&offset); + } + } + + if (controller->FrameStamp!=GlobalFrameCounter) { + controller->keyframe_flags=0; + HMTimer_Kernel(controller); + } + /* That handled the timer. Now update positions. */ + + Process_Section(controller,controller->section_data,&dptr->ObWorld,&dptr->ObMat,controller->sequence_timer,controller->Sequence_Type,controller->Sub_Sequence,0); + + controller->FrameStamp=GlobalFrameCounter; + controller->Computed_Position=dptr->ObWorld; + + GLOBALASSERT(controller->section_data->flags§ion_data_initialised); + +} + +void ProveHModel_Far(HMODELCONTROLLER *controller, STRATEGYBLOCK *sbPtr) { + + /* Simply to verify a new hmodel, and remove junk. */ + + GLOBALASSERT(controller); + GLOBALASSERT(sbPtr); + + Global_HModel_Sptr=sbPtr; + + GLOBALASSERT(sbPtr->DynPtr); + + /* Check the object is in a sensible place. */ + if ( !( (sbPtr->DynPtr->Position.vx<1000000 && sbPtr->DynPtr->Position.vx>-1000000) + && (sbPtr->DynPtr->Position.vy<1000000 && sbPtr->DynPtr->Position.vy>-1000000) + && (sbPtr->DynPtr->Position.vz<1000000 && sbPtr->DynPtr->Position.vz>-1000000) + ) ) { + + LOGDXFMT(("Tests in PROVEHMODEL_FAR.\n")); + if (Global_HModel_Sptr) { + LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype)); + } else { + LOGDXFMT(("Misplaced object has no SBptr.\n")); + } + LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence)); + + LOCALASSERT(sbPtr->DynPtr->Position.vx<1000000 && sbPtr->DynPtr->Position.vx>-1000000); + LOCALASSERT(sbPtr->DynPtr->Position.vy<1000000 && sbPtr->DynPtr->Position.vy>-1000000); + LOCALASSERT(sbPtr->DynPtr->Position.vz<1000000 && sbPtr->DynPtr->Position.vz>-1000000); + + } + + GLOBALASSERT(controller->section_data->my_controller==controller); + + if (controller->FrameStamp==GlobalFrameCounter) { + VECTORCH offset; + /* Want to budge? */ + + offset.vx=controller->Computed_Position.vx-sbPtr->DynPtr->Position.vx; + offset.vy=controller->Computed_Position.vy-sbPtr->DynPtr->Position.vy; + offset.vz=controller->Computed_Position.vz-sbPtr->DynPtr->Position.vz; + + if ((offset.vx!=0)||(offset.vy!=0)||(offset.vz!=0)) { + /* I reckon you'd be better off taking the budge. */ + Budge_HModel(controller,&offset); + } + } + + if (controller->FrameStamp!=GlobalFrameCounter) { + controller->keyframe_flags=0; + HMTimer_Kernel(controller); + } + /* That handled the timer. Now update positions. */ + + Process_Section(controller,controller->section_data,&sbPtr->DynPtr->Position,&sbPtr->DynPtr->OrientMat,controller->sequence_timer,controller->Sequence_Type,controller->Sub_Sequence,0); + + controller->FrameStamp=GlobalFrameCounter; + controller->Computed_Position=sbPtr->DynPtr->Position; + + GLOBALASSERT(controller->section_data->flags§ion_data_initialised); + +} + + +int Prune_Recursion_Virtual(SECTION_DATA *this_section_data) { + + int sol; + SECTION *this_section; + + /* Work out which SECTION_DATA to use. */ + + this_section=this_section_data->sempai; + + sol=0; + + if (this_section->flags§ion_has_sparkoflife) sol=1; + + this_section_data->flags|=section_data_notreal; + + + if ( (this_section_data->First_Child!=NULL) + &&( (this_section_data->flags§ion_data_terminate_here)==0)) { + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + if (Prune_Recursion_Virtual(child_list_ptr)) sol=1; + child_list_ptr=child_list_ptr->Next_Sibling; + } + + } + + return(sol); + +} + +int Prune_HModel_Virtual(SECTION_DATA *top_section) { + + SECTION *this_section; + int sol; + + /* To make top_section, and everything below it, unreal. */ + /* Must pass back up the recursion if any section pruned */ + /* has the spark of life. */ + + this_section=top_section->sempai; + sol=0; + + if (Prune_Recursion_Virtual(top_section)) sol=1; + top_section->flags|=section_data_terminate_here; + top_section->gore_timer=0; + + return(sol); + +} + +void Correlation_Recursion(SECTION_DATA *this_section_data, SECTION_DATA *alt_section_data) { + + /* Correlate existance. */ + + if (alt_section_data->flags§ion_data_notreal) { + this_section_data->flags|=section_data_notreal; + } + + if (alt_section_data->flags§ion_data_terminate_here) { + this_section_data->flags|=section_data_terminate_here; + this_section_data->gore_timer=0; /* As good a time as any. */ + } + + /* Now call recursion... */ + + if ((this_section_data->First_Child!=NULL) + &&( (this_section_data->flags§ion_data_terminate_here)==0)) { + + SECTION_DATA *child_list_ptr,*alt_child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + alt_child_list_ptr=alt_section_data->First_Child; + + while (child_list_ptr!=NULL) { + Correlation_Recursion(child_list_ptr,alt_child_list_ptr); + child_list_ptr=child_list_ptr->Next_Sibling; + alt_child_list_ptr=alt_child_list_ptr->Next_Sibling; + } + } +} + +void Correlate_HModel_Instances(SECTION_DATA *victim,SECTION_DATA *templat) { + + GLOBALASSERT(victim->sempai==templat->sempai); + + /* You'd better not be being silly. */ + + /* The top section must be a false root. */ + + victim->flags|=section_data_false_root; + + /* Start recursion. */ + + Correlation_Recursion(victim,templat); +} + +void MulQuat(QUAT *q1,QUAT *q2,QUAT *output) { + + VECTORCH v1,v2,v3; + int tw; + + /* Multiply quats... */ + + v1.vx=q1->quatx; + v1.vy=q1->quaty; + v1.vz=q1->quatz; + + v2.vx=q2->quatx; + v2.vy=q2->quaty; + v2.vz=q2->quatz; + + CrossProduct(&v1,&v2,&v3); + + tw=MUL_FIXED(q1->quatw,q2->quatw); + tw-=DotProduct(&v1,&v2); + + v3.vx+=MUL_FIXED(q1->quatw,v2.vx); + v3.vx+=MUL_FIXED(q2->quatw,v1.vx); + + v3.vy+=MUL_FIXED(q1->quatw,v2.vy); + v3.vy+=MUL_FIXED(q2->quatw,v1.vy); + + v3.vz+=MUL_FIXED(q1->quatw,v2.vz); + v3.vz+=MUL_FIXED(q2->quatw,v1.vz); + + output->quatw=tw; + output->quatx=v3.vx; + output->quaty=v3.vy; + output->quatz=v3.vz; + + QNormalise(output); + +} + +void Slerp(KEYFRAME_DATA *input,int lerp,QUAT *output) { + + int sclp,sclq; + int omega=input->omega; //probably faster copying to an int , rather than using the bitfield + KEYFRAME_DATA* next_frame=input->Next_Frame; + + /* First check for special case. */ + + if ((lerp<0)||(lerp>=65536)) { + GLOBALASSERT(lerp>=0); + GLOBALASSERT(lerp<65536); + } + + if (omega==2048) { + int t1,t2; + + output->quatx=((int)-input->QOrient.quaty)<<1; + output->quaty=((int)input->QOrient.quatx)<<1; + output->quatz=((int)-input->QOrient.quatw)<<1; + output->quatw=((int)input->QOrient.quatz)<<1; + + t1=MUL_FIXED((ONE_FIXED-lerp),1024); + sclp=GetSin(t1); + + t2=MUL_FIXED(lerp,1024); + sclq=GetSin(t2); + + //multiply sclp and sclq by 2 to make up for short quats + sclp<<=1; + sclq<<=1; + + output->quatx=(MUL_FIXED((int)input->QOrient.quatx,sclp))+(MUL_FIXED(output->quatx,sclq)); + output->quaty=(MUL_FIXED((int)input->QOrient.quaty,sclp))+(MUL_FIXED(output->quaty,sclq)); + output->quatz=(MUL_FIXED((int)input->QOrient.quatz,sclp))+(MUL_FIXED(output->quatz,sclq)); + output->quatw=(MUL_FIXED((int)input->QOrient.quatw,sclp))+(MUL_FIXED(output->quatw,sclq)); + + } else { + if (omega==0) { + sclp=ONE_FIXED-lerp; + sclq=lerp; + } else { + int t1,t2; + int oneoversinomega=GetOneOverSin(omega); + + t1=MUL_FIXED((ONE_FIXED-lerp),omega); + t2=GetSin(t1); + sclp=MUL_FIXED(t2,oneoversinomega); + + t1=MUL_FIXED(lerp,omega); + t2=GetSin(t1); + sclq=MUL_FIXED(t2,oneoversinomega); + + } + //multiply sclp and sclq by 2 to make up for short quats + sclp<<=1; + sclq<<=1; + + if(input->slerp_to_negative_quat) + { + //instead of actually negating the quaternion , negate sclq + sclq=-sclq; + } + + output->quatx=(MUL_FIXED((int)input->QOrient.quatx,sclp))+(MUL_FIXED((int)next_frame->QOrient.quatx,sclq)); + output->quaty=(MUL_FIXED((int)input->QOrient.quaty,sclp))+(MUL_FIXED((int)next_frame->QOrient.quaty,sclq)); + output->quatz=(MUL_FIXED((int)input->QOrient.quatz,sclp))+(MUL_FIXED((int)next_frame->QOrient.quatz,sclq)); + output->quatw=(MUL_FIXED((int)input->QOrient.quatw,sclp))+(MUL_FIXED((int)next_frame->QOrient.quatw,sclq)); + } + + QNormalise(output); + +} + +void Slerp2(SECTION_DATA *input,int lerp,QUAT *output) { + + /* Just a different input structure. */ + + int sclp,sclq; + + /* First check for special case. */ + + GLOBALASSERT(lerp>=0); + GLOBALASSERT(lerp<65536); + + if (input->omega==2048) { + int t1,t2; + + output->quatx=-input->stored_quat.quaty; + output->quaty=input->stored_quat.quatx; + output->quatz=-input->stored_quat.quatw; + output->quatw=input->stored_quat.quatz; + + t1=MUL_FIXED((ONE_FIXED-lerp),1024); + sclp=GetSin(t1); + + t2=MUL_FIXED(lerp,1024); + sclq=GetSin(t2); + + output->quatx=(MUL_FIXED(input->stored_quat.quatx,sclp))+(MUL_FIXED(output->quatx,sclq)); + output->quaty=(MUL_FIXED(input->stored_quat.quaty,sclp))+(MUL_FIXED(output->quaty,sclq)); + output->quatz=(MUL_FIXED(input->stored_quat.quatz,sclp))+(MUL_FIXED(output->quatz,sclq)); + output->quatw=(MUL_FIXED(input->stored_quat.quatw,sclp))+(MUL_FIXED(output->quatw,sclq)); + + } else { + if ( (input->omega==0) && (input->oneoversinomega==0) ) { + sclp=ONE_FIXED-lerp; + sclq=lerp; + } else { + int t1,t2; + + t1=MUL_FIXED((ONE_FIXED-lerp),input->omega); + t2=GetSin(t1); + sclp=MUL_FIXED(t2,input->oneoversinomega); + + t1=MUL_FIXED(lerp,input->omega); + t2=GetSin(t1); + sclq=MUL_FIXED(t2,input->oneoversinomega); + + } + + output->quatx=(MUL_FIXED(input->stored_quat.quatx,sclp))+(MUL_FIXED(input->target_quat.quatx,sclq)); + output->quaty=(MUL_FIXED(input->stored_quat.quaty,sclp))+(MUL_FIXED(input->target_quat.quaty,sclq)); + output->quatz=(MUL_FIXED(input->stored_quat.quatz,sclp))+(MUL_FIXED(input->target_quat.quatz,sclq)); + output->quatw=(MUL_FIXED(input->stored_quat.quatw,sclp))+(MUL_FIXED(input->target_quat.quatw,sclq)); + } + + QNormalise(output); + +} + +void Gibbing_Recursion(STRATEGYBLOCK *sbPtr,SECTION_DATA *this_section_data, int probability) { + + /* General gibbing function. */ + + + /* Recurse. */ + + if ( (this_section_data->First_Child!=NULL) + &&( (this_section_data->flags§ion_data_terminate_here)==0)) { + + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + + if ( (child_list_ptr->flags§ion_data_terminate_here)==0) { + + /* Right. Roll some dice... */ + if (((child_list_ptr->sempai->flags§ion_flag_never_frag)==0) + &&((SeededFastRandom()&65535)World_Offset, &child_list_ptr->SecMat,NULL,4); + /* Oh Dear! Every section below and including this one becomes... unreal. + And if any of them contain the spark of life, we need to know. */ + + /* Now, gibb the debris ;-) */ + + if ( (this_debris) && + ((this_debris->HModelControlBlock->section_data->sempai->flags§ion_flag_nofurthergibbing)==0) ) { + GLOBALASSERT(this_debris->HModelControlBlock); + GLOBALASSERT(this_debris->HModelControlBlock->section_data); + Gibbing_Recursion(sbPtr,this_debris->HModelControlBlock->section_data,probability); + } + + } else { + + Gibbing_Recursion(sbPtr,child_list_ptr,probability); + + } + } + child_list_ptr=child_list_ptr->Next_Sibling; + } + + } + +} + +void Extreme_Gibbing(STRATEGYBLOCK *sbPtr,SECTION_DATA *this_section_data, int probability) { + + /* Shell for gibbing. Do gibbing... */ + + Gibbing_Recursion(sbPtr,this_section_data,probability); + + /* Now frag the body off. */ + + if ( (SeededFastRandom()&65535)World_Offset, &this_section_data->SecMat,NULL,4); + } +} + +int Change_Controller_Recursion(HMODELCONTROLLER *new_controller,SECTION_DATA *this_section_data) { + + int wounds; + + this_section_data->my_controller=new_controller; + wounds=this_section_data->sempai->flags§ion_flags_wounding; + + /* Now call recursion... */ + + if (this_section_data->First_Child!=NULL) { + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + wounds|=Change_Controller_Recursion(new_controller,child_list_ptr); + child_list_ptr=child_list_ptr->Next_Sibling; + } + } + + return(wounds); + +} + +int Splice_HModels(HMODELCONTROLLER *new_controller,SECTION_DATA *top_section_data) { + + /* Real fragging. */ + int wounds; + SECTION_DATA *new_top_section; + + /* Init new controller. */ + + wounds=0; + Global_Controller_Ptr=new_controller; + + new_controller->Seconds_For_Sequence=ONE_FIXED; + new_controller->timer_increment=ONE_FIXED; + /* Seconds_For_Sequence and timer_increment are dealt with elsewhere. */ + new_controller->sequence_timer=0; + new_controller->Playing=0; + new_controller->Reversed=0; + new_controller->Looped=0; + + new_controller->FrameStamp=-1; + new_controller->View_FrameStamp=-1; + + if (top_section_data->my_controller) { + new_controller->DisableBleeding=top_section_data->my_controller->DisableBleeding; + new_controller->DisableSounds=top_section_data->my_controller->DisableSounds; + } else { + new_controller->DisableBleeding=0; + new_controller->DisableSounds=0; + } + /* Probably set on return, but never mind. */ + new_controller->LockTopSection=0; + new_controller->ZeroRootDisplacement=0; + new_controller->ZeroRootRotation=0; + new_controller->AT_sequence_timer=0; + + /* Copy them over, splice them over, or ignore BY HAND. */ + new_controller->Deltas=NULL; + + new_controller->keyframe_flags=0; + + /* Every time a section is preprocessed, it must generate a section_data for + itself, and clip it to the last section_data that was generated. */ + + /* Create a new top section... */ + + new_top_section=(SECTION_DATA *)AllocateMem(sizeof(SECTION_DATA)); + GLOBALASSERT(new_top_section); + + /* Now. Copy the old top_section_data into the new top section. */ + + *new_top_section=*top_section_data; + + top_section_data->tac_ptr=NULL; + + /* Correct for new parentage. */ + new_top_section->My_Parent=NULL; + + if (new_top_section->First_Child!=NULL) { + + SECTION_DATA *child_ptr; + + child_ptr=new_top_section->First_Child; + + while (child_ptr!=NULL) { + + child_ptr->My_Parent=new_top_section; + + child_ptr=child_ptr->Next_Sibling; + } + + } + + + /* ...and top_section_data gets no children. */ + + top_section_data->First_Child=NULL; + + /* Set flags. */ + + new_top_section->flags=top_section_data->flags&(~section_data_initialised); + top_section_data->flags|=section_data_terminate_here; + top_section_data->gore_timer=0; + top_section_data->flags|=section_data_notreal; + new_top_section->flags|=section_data_false_root; + new_top_section->gore_timer=0; + + /* Connect to controller. */ + + new_controller->section_data=new_top_section; + new_controller->Root_Section=new_top_section->sempai; + + wounds=Change_Controller_Recursion(new_controller,new_top_section); + + return(wounds); + +} + +SECTION_DATA *GetSectionData_Recursion(SECTION_DATA *this_section_data,char *name) { + + SECTION_DATA *sdptr; + + sdptr=NULL; + + if (strcmp(name,this_section_data->sempai->Section_Name)==0) { + /* We are that section! */ + return(this_section_data); + } + + /* Now call recursion... */ + + if (this_section_data->First_Child!=NULL) { + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + sdptr=GetSectionData_Recursion(child_list_ptr,name); + child_list_ptr=child_list_ptr->Next_Sibling; + + if (sdptr) { + return(sdptr); /* We got one! */ + } + } + } + + return(sdptr); + +} + +SECTION_DATA *GetThisSectionData(SECTION_DATA *root,char *name) { + + if ((root==NULL)||(name==NULL)) { + return(NULL); + } + + return(GetSectionData_Recursion(root,name)); + +} + +SECTION *GetSection_Recursion(SECTION *this_section,char *name) { + + SECTION *sptr; + + sptr=NULL; + + if (strcmp(name,this_section->Section_Name)==0) { + /* We are that section! */ + return(this_section); + } + + /* Now call recursion... */ + + if (this_section->Children!=NULL) { + + SECTION **child_list_ptr; + + child_list_ptr=this_section->Children; + + while (*child_list_ptr!=NULL) { + + sptr=GetSection_Recursion(*child_list_ptr,name); + child_list_ptr++; + + if (sptr) { + return(sptr); /* We got one! */ + } + } + } + + return(sptr); + +} + +SECTION *GetThisSection(SECTION *root,char *name) { + + if ((root==NULL)||(name==NULL)) { + return(NULL); + } + + return(GetSection_Recursion(root,name)); + +} + +void MatToQuat (MATRIXCH *m, QUAT *quat) +{ + const int X=0; + const int Y=1; + const int Z=2; + const int W=3; + + double mat[4][4]; + double q[4]; + + int i,j,k; + double tr,s; + + int const nxt[3] = + { + //Y,Z,X + 1,2,0 + }; + + // we could try transposing the matrix here + +// TransposeMatrixCH(m); + + mat[0][0] = (double) m->mat11 / ONE_FIXED; + mat[1][0] = (double) m->mat21 / ONE_FIXED; + mat[2][0] = (double) m->mat31 / ONE_FIXED; + mat[0][1] = (double) m->mat12 / ONE_FIXED; + mat[1][1] = (double) m->mat22 / ONE_FIXED; + mat[2][1] = (double) m->mat32 / ONE_FIXED; + mat[0][2] = (double) m->mat13 / ONE_FIXED; + mat[1][2] = (double) m->mat23 / ONE_FIXED; + mat[2][2] = (double) m->mat33 / ONE_FIXED; + + + + tr= mat[0][0]+mat[1][1]+mat[2][2]; + + if (tr>0.0) + { + s=sqrt(tr+1.0); + q[W] = s*0.5; + s = 0.5/s; + + q[X] = (mat[1][2] - mat[2][1])*s; + q[Y] = (mat[2][0] - mat[0][2])*s; + q[Z] = (mat[0][1] - mat[1][0])*s; + } + else + { + i = X; + if (mat[Y][Y] > mat[X][X]) i = Y; + if (mat[Z][Z] > mat[i][i]) i = Z; + j = nxt[i]; k = nxt[j]; + + s = sqrt((mat[i][i] - (mat[j][j]+mat[k][k])) + 1.0); + + q[i] = s*0.5; + s = 0.5/s; + q[W] = (mat[j][k] - mat[k][j])*s; + q[j] = (mat[i][j] + mat[j][i])*s; + q[k] = (mat[i][k] + mat[k][i])*s; + } + + quat->quatx = (int) ((double) q[X]*65536.0); + quat->quaty = (int) ((double) q[Y]*65536.0); + quat->quatz = (int) ((double) q[Z]*65536.0); + quat->quatw = (int) ((double) q[W]*65536.0); + + quat->quatw = -quat->quatw; + + QNormalise(quat); + +} + +void Init_Tweening_Recursion(SECTION_DATA *this_section_data, int target_sequence_type,int target_subsequence, int seconds_for_tweening, int backwards) { + + SEQUENCE *sequence_ptr; + + /* Firstly, store current state. */ + + this_section_data->stored_offset=this_section_data->Offset; + MatToQuat(&this_section_data->RelSecMat,&this_section_data->stored_quat); + + /* Now, get target state. */ + + sequence_ptr=GetSequencePointer(target_sequence_type,target_subsequence,this_section_data->sempai); + + if (backwards) { + KEYFRAME_DATA *current_frame; + /* Deduce last frame. */ + current_frame=sequence_ptr->last_frame; + + /* Must now have the last frame. */ + GetKeyFrameOffset(current_frame,&this_section_data->target_offset); + + CopyShortQuatToInt(¤t_frame->QOrient,&this_section_data->target_quat); + } else { + GetKeyFrameOffset(sequence_ptr->first_frame,&this_section_data->target_offset); + CopyShortQuatToInt(&sequence_ptr->first_frame->QOrient,&this_section_data->target_quat); + } + + /* Preprocess slerp values. */ + + { + + this_section_data->delta_offset.vx=this_section_data->target_offset.vx-this_section_data->stored_offset.vx; + this_section_data->delta_offset.vy=this_section_data->target_offset.vy-this_section_data->stored_offset.vy; + this_section_data->delta_offset.vz=this_section_data->target_offset.vz-this_section_data->stored_offset.vz; + + } + + { + int cosom,sinom; + QUAT *this_quat, *next_quat; + + this_quat=&this_section_data->stored_quat; + next_quat=&this_section_data->target_quat; + + + cosom=QDot(this_quat,next_quat); + + if (cosom<0) { + next_quat->quatx=-next_quat->quatx; + next_quat->quaty=-next_quat->quaty; + next_quat->quatz=-next_quat->quatz; + next_quat->quatw=-next_quat->quatw; + + cosom=-cosom; + } + + + this_section_data->omega=ArcCos(cosom); + sinom=GetSin(this_section_data->omega); + if (sinom) { + this_section_data->oneoversinomega=GetOneOverSin(this_section_data->omega); + } else { + /* Yuk. */ + this_section_data->omega=0; + this_section_data->oneoversinomega=0; + } + + GLOBALASSERT(seconds_for_tweening>0); + this_section_data->oneovertweeninglength=DIV_FIXED(ONE_FIXED,seconds_for_tweening); + + } + + /* Init fields... I guess. */ + + this_section_data->current_sequence=sequence_ptr; + this_section_data->current_keyframe=sequence_ptr->first_frame; + this_section_data->accumulated_timer=0; + this_section_data->freezeframe_timer=-1; + this_section_data->lastframe_timer=0; + this_section_data->gore_timer=0; /* As good a time as any. */ + + this_section_data->Tweening=1; + + /* Animation? */ + + /* Nah. */ + + /* Recurse. */ + + if ( (this_section_data->First_Child!=NULL) + &&( (this_section_data->flags§ion_data_terminate_here)==0)) { + /* Respect the terminator! */ + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + Init_Tweening_Recursion(child_list_ptr,target_sequence_type,target_subsequence,seconds_for_tweening,backwards); + child_list_ptr=child_list_ptr->Next_Sibling; + } + + } + +} + + +void InitHModelTweening(HMODELCONTROLLER *controller, int seconds_for_tweening, + int target_sequence_type, int target_subsequence, int target_seconds_for_sequence, int loop) { + + /* Just set it up... */ + GLOBALASSERT(target_seconds_for_sequence); + + controller->Sequence_Type=target_sequence_type; + controller->Sub_Sequence=target_subsequence; + controller->Seconds_For_Sequence=seconds_for_tweening; + controller->timer_increment=DIV_FIXED(ONE_FIXED,controller->Seconds_For_Sequence); + controller->sequence_timer=0; + controller->Playing=1; + controller->Reversed=0; + controller->Looped=1; + + controller->After_Tweening_Sequence_Type=target_sequence_type; + controller->After_Tweening_Sub_Sequence=target_subsequence; + controller->AT_seconds_for_sequence=target_seconds_for_sequence; + controller->AT_sequence_timer=0; + controller->Tweening=Controller_Tweening; + if (loop) { + controller->LoopAfterTweening=1; + } else { + controller->LoopAfterTweening=0; + } + controller->StopAfterTweening=0; + controller->ElevationTweening=0; + + /* Recurse though hierarchy, setting up all the section_data sequence stores? */ + + Init_Tweening_Recursion(controller->section_data, target_sequence_type, target_subsequence,seconds_for_tweening,0); + +} + +void InitHModelTweening_Backwards(HMODELCONTROLLER *controller, int seconds_for_tweening, + int target_sequence_type, int target_subsequence, int target_seconds_for_sequence, int loop) { + + /* Ooh, yuck. */ + GLOBALASSERT(target_seconds_for_sequence); + + controller->Sequence_Type=target_sequence_type; + controller->Sub_Sequence=target_subsequence; + controller->Seconds_For_Sequence=seconds_for_tweening; + controller->timer_increment=DIV_FIXED(ONE_FIXED,controller->Seconds_For_Sequence); + controller->sequence_timer=0; + controller->Playing=1; + controller->Reversed=1; + controller->Looped=1; + + controller->After_Tweening_Sequence_Type=target_sequence_type; + controller->After_Tweening_Sub_Sequence=target_subsequence; + controller->AT_seconds_for_sequence=target_seconds_for_sequence; + controller->AT_sequence_timer=(ONE_FIXED-1); + controller->Tweening=Controller_Tweening; + if (loop) { + controller->LoopAfterTweening=1; + } else { + controller->LoopAfterTweening=0; + } + controller->StopAfterTweening=0; + controller->ElevationTweening=0; + + /* Recurse though hierarchy, setting up all the section_data sequence stores? */ + + Init_Tweening_Recursion(controller->section_data, target_sequence_type, target_subsequence,seconds_for_tweening,1); + +} + +void ReSnap(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data, int elevation) { + + SEQUENCE *sequence_ptr; + /* In this procedure, we have to get the new target quat and offset. */ + + sequence_ptr=GetSequencePointer(controller->After_Tweening_Sequence_Type,controller->After_Tweening_Sub_Sequence,this_section_data->sempai); + + #if 0 + if (controller->Reversed) { + /* We're in a backwards tween. */ + KEYFRAME_DATA *current_frame; + /* Deduce last frame. */ + current_frame=sequence_ptr->last_frame; + + /* Must now have the last frame. */ + this_section_data->target_offset=current_frame->Offset; + CopyShortQuatToInt(¤t_frame->QOrient,&this_section_data->target_quat); + } else { + this_section_data->target_offset=sequence_ptr->first_frame->Offset; + CopyShortQuatToInt(&sequence_ptr->first_frame->QOrient,&this_section_data->target_quat); + } + #else + /* Now, irritatingly, we have to put our faith in AT_sequence_timer. */ + if (controller->AT_sequence_timer==(ONE_FIXED-1)) { + /* We're in a backwards tween. */ + KEYFRAME_DATA *current_frame; + /* Deduce last frame. */ + current_frame=sequence_ptr->last_frame; + + /* Must now have the last frame. */ + GetKeyFrameOffset(current_frame,&this_section_data->target_offset); + CopyShortQuatToInt(¤t_frame->QOrient,&this_section_data->target_quat); + } else if (controller->AT_sequence_timer==0) { + GetKeyFrameOffset(sequence_ptr->first_frame,&this_section_data->target_offset); + CopyShortQuatToInt(&sequence_ptr->first_frame->QOrient,&this_section_data->target_quat); + } else { + int a,working_timer,lerp; + KEYFRAME_DATA *this_frame,*next_frame; + + this_frame=sequence_ptr->first_frame; + GLOBALASSERT(this_frame); + working_timer=controller->AT_sequence_timer; + + a=0; /* Status flag... */ + + while (a==0) { + if (this_frame->last_frame) { + /* Low framerate loop? */ + next_frame=sequence_ptr->first_frame; + } + else{ + next_frame=this_frame->Next_Frame; + } + + if (working_timer>=this_frame->Sequence_Length) { + /* We've gone beyond this frame: get next keyframe. */ + working_timer-=this_frame->Sequence_Length; + /* Advance frame... */ + this_frame=next_frame; + } else { + a=1; /* Exit loop with success. */ + } + /* Better make sure the last 'frame' has 65536 length... */ + } + GLOBALASSERT(working_timer>=0); + /* Now we should have a frame and a timer. */ + + lerp=MUL_FIXED(working_timer,this_frame->oneoversequencelength); + + GetKeyFrameOffset(this_frame,&this_section_data->target_offset); + + if(next_frame->shift_offset) + { + VECTORCH next_offset; + GetKeyFrameOffset(next_frame,&next_offset); + this_section_data->target_offset.vx+=MUL_FIXED(next_offset.vx - this_section_data->target_offset.vx,lerp); + this_section_data->target_offset.vy+=MUL_FIXED(next_offset.vy - this_section_data->target_offset.vy,lerp); + this_section_data->target_offset.vz+=MUL_FIXED(next_offset.vz - this_section_data->target_offset.vz,lerp); + } + else + { + this_section_data->target_offset.vx+=MUL_FIXED((int)next_frame->Offset_x - this_section_data->target_offset.vx,lerp); + this_section_data->target_offset.vy+=MUL_FIXED((int)next_frame->Offset_y - this_section_data->target_offset.vy,lerp); + this_section_data->target_offset.vz+=MUL_FIXED((int)next_frame->Offset_z - this_section_data->target_offset.vz,lerp); + } + + /* Now deal with orientation. */ + + Slerp(this_frame,lerp,&this_section_data->target_quat); + + } + #endif + + if (elevation) { + + /* Elevation gone! Now deltas? */ + { + DELTA_CONTROLLER *dcon; + QUAT elevation_quat,temp_quat; + VECTORCH elevation_offset; + + dcon=controller->Deltas; + + while (dcon) { + if (dcon->Active) { + Process_Delta_Controller(this_section_data,dcon,&elevation_offset,&elevation_quat); + this_section_data->target_offset.vx+=elevation_offset.vx; + this_section_data->target_offset.vy+=elevation_offset.vy; + this_section_data->target_offset.vz+=elevation_offset.vz; + + temp_quat.quatw=this_section_data->target_quat.quatw; + temp_quat.quatx=this_section_data->target_quat.quatx; + temp_quat.quaty=this_section_data->target_quat.quaty; + temp_quat.quatz=this_section_data->target_quat.quatz; + + MulQuat(&elevation_quat,&temp_quat,&this_section_data->target_quat); + } + dcon=dcon->next_controller; + } + } + + } + + /* Now recompute values. */ + + { + + this_section_data->delta_offset.vx=this_section_data->target_offset.vx-this_section_data->stored_offset.vx; + this_section_data->delta_offset.vy=this_section_data->target_offset.vy-this_section_data->stored_offset.vy; + this_section_data->delta_offset.vz=this_section_data->target_offset.vz-this_section_data->stored_offset.vz; + + } + + { + int cosom,sinom; + QUAT *this_quat, *next_quat; + + this_quat=&this_section_data->stored_quat; + next_quat=&this_section_data->target_quat; + + + cosom=QDot(this_quat,next_quat); + + if (cosom<0) { + next_quat->quatx=-next_quat->quatx; + next_quat->quaty=-next_quat->quaty; + next_quat->quatz=-next_quat->quatz; + next_quat->quatw=-next_quat->quatw; + cosom=-cosom; + } + + + this_section_data->omega=ArcCos(cosom); + sinom=GetSin(this_section_data->omega); + if (sinom) { + this_section_data->oneoversinomega=GetOneOverSin(this_section_data->omega); + } else { + /* Yuk. */ + this_section_data->omega=0; + this_section_data->oneoversinomega=0; + } + + } + +} + +void Analyse_Tweening_Data(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,int base_timer,VECTORCH *output_offset,MATRIXCH *output_matrix) { + + QUAT output_quat; + int working_timer,lerp; + + /* Go go gadget tweening. */ + + /* There is only one frame. */ + + working_timer=base_timer; + /* Tests: can't be too careful. */ + if (working_timer>=65536) working_timer=65535; + if (working_timer<0) working_timer=0; + + /* Now, a lot like the old way, but we shouldn't need to loop more than once. */ + /* If we do, we have a game framerate slower than the anim framerate. */ + + if (controller->Deltas) { + /* Resnap with elevation. */ + ReSnap(controller,this_section_data,1); + + controller->ElevationTweening=1; + + } else if (controller->ElevationTweening) { + /* It's all messed up now. 'Resnap' WITHOUT elevation. */ + + ReSnap(controller,this_section_data,0); + + controller->ElevationTweening=0; + + } + + /* Now, this_frame and next_frame are set, and working_timerSequence_Length. */ + + output_offset->vx=(MUL_FIXED(this_section_data->delta_offset.vx,working_timer))+this_section_data->stored_offset.vx; + output_offset->vy=(MUL_FIXED(this_section_data->delta_offset.vy,working_timer))+this_section_data->stored_offset.vy; + output_offset->vz=(MUL_FIXED(this_section_data->delta_offset.vz,working_timer))+this_section_data->stored_offset.vz; + + /* Now deal with orientation. */ + + lerp=working_timer; + + Slerp2(this_section_data,lerp,&output_quat); + + /* NO elevation! */ + + QuatToMat(&output_quat,output_matrix); + + /* Just to make sure. */ + MNormalise(output_matrix); +} + + +/* KJL 16:51:20 10/02/98 - Heat source stuff */ + +int FindHeatSourcesInHModel(DISPLAYBLOCK *dispPtr) +{ + HMODELCONTROLLER *controllerPtr = dispPtr->HModelControlBlock; + + LOCALASSERT(controllerPtr); + + /* KJL 16:36:12 10/02/98 - check positions are up to date */ + ProveHModel(controllerPtr,dispPtr); + + NumberOfHeatSources=0; + + /* KJL 16:36:25 10/02/98 - process model */ + FindHeatSource_Recursion(controllerPtr,controllerPtr->section_data); + + return 0; +} + +static void FindHeatSource_Recursion(HMODELCONTROLLER *controllerPtr, SECTION_DATA *sectionDataPtr) +{ + /* KJL 16:29:40 10/02/98 - Recurse through hmodel */ + if ((sectionDataPtr->First_Child!=NULL)&&(!(sectionDataPtr->flags§ion_data_terminate_here))) + { + SECTION_DATA *childSectionPtr = sectionDataPtr->First_Child; + + while (childSectionPtr!=NULL) + { + LOCALASSERT(childSectionPtr->My_Parent==sectionDataPtr); + + FindHeatSource_Recursion(controllerPtr,childSectionPtr); + childSectionPtr=childSectionPtr->Next_Sibling; + } + } + + /* KJL 16:30:03 10/02/98 - record heat source */ + if (sectionDataPtr->sempai->flags§ion_flag_heatsource) + { + /* KJL 16:36:58 10/02/98 - currently just position; could have size, orientation, etc. */ + HeatSourceList[NumberOfHeatSources].Position.vx = sectionDataPtr->World_Offset.vx; + HeatSourceList[NumberOfHeatSources].Position.vy = sectionDataPtr->World_Offset.vy; + HeatSourceList[NumberOfHeatSources].Position.vz = sectionDataPtr->World_Offset.vz; + TranslatePointIntoViewspace(&(HeatSourceList[NumberOfHeatSources].Position)); + NumberOfHeatSources++; + } +} + +DELTA_CONTROLLER *Get_Delta_Sequence(HMODELCONTROLLER *controller,char *id) { + + DELTA_CONTROLLER *delta_controller; + + /* Get the controller that matches id. */ + + delta_controller=controller->Deltas; + + while (delta_controller) { + + if (strcmp(id,delta_controller->id)==0) { + break; + } + delta_controller=delta_controller->next_controller; + + } + return(delta_controller); +} + +void Remove_Delta_Sequence(HMODELCONTROLLER *controller,char *id) { + + DELTA_CONTROLLER *delta_controller; + DELTA_CONTROLLER **source; + + delta_controller=controller->Deltas; + source=&controller->Deltas; + + while (delta_controller) { + + if (strcmp(id,delta_controller->id)==0) { + break; + } + source=&delta_controller->next_controller; + delta_controller=delta_controller->next_controller; + + } + + if (delta_controller) { + /* Remove it. */ + *source=delta_controller->next_controller; + + DeallocateMem(delta_controller->id); + DeallocateMem(delta_controller); + } +} + +DELTA_CONTROLLER *Add_Delta_Sequence(HMODELCONTROLLER *controller,char *id,int sequence_type,int sub_sequence, int seconds_for_sequence) { + + KEYFRAME_DATA *sequence_start; + SEQUENCE *this_sequence; + DELTA_CONTROLLER *delta_controller; + + /* Create a new delta sequence. */ + + delta_controller=(DELTA_CONTROLLER *)AllocateMem(sizeof(DELTA_CONTROLLER)); + + GLOBALASSERT(delta_controller); + + delta_controller->next_controller=controller->Deltas; + controller->Deltas=delta_controller; + + delta_controller->id = AllocateMem(strlen(id)+1); + strcpy(delta_controller->id,id); + + delta_controller->sequence_type=sequence_type; + delta_controller->sub_sequence=sub_sequence; + delta_controller->timer=0; + delta_controller->lastframe_timer=-1; + delta_controller->Looped=0; + delta_controller->Playing=0; + delta_controller->Active=1; /* By default. */ + delta_controller->my_hmodel_controller=controller; + + this_sequence=GetSequencePointer(sequence_type,sub_sequence,delta_controller->my_hmodel_controller->Root_Section); + sequence_start=this_sequence->first_frame; + GLOBALASSERT(sequence_start); + + if (seconds_for_sequence>=0) { + delta_controller->seconds_for_sequence=seconds_for_sequence; // Special case, 0 is legal. + } else { + delta_controller->seconds_for_sequence=this_sequence->Time; + if (delta_controller->seconds_for_sequence<=0) { + delta_controller->seconds_for_sequence=ONE_FIXED; + /* Might want to assert here? */ + } + } + + if (delta_controller->seconds_for_sequence) { + delta_controller->timer_increment=DIV_FIXED(ONE_FIXED,delta_controller->seconds_for_sequence); + } else { + delta_controller->timer_increment=0; + } + + return(delta_controller); + +} + +void Start_Delta_Sequence(DELTA_CONTROLLER *delta_controller,int sequence_type,int sub_sequence,int seconds_for_sequence) { + + KEYFRAME_DATA *sequence_start; + SEQUENCE *this_sequence; + GLOBALASSERT(delta_controller); + + /* Again, you must start it and loop it by hand. */ + + delta_controller->sequence_type=sequence_type; + delta_controller->sub_sequence=sub_sequence; + delta_controller->timer=0; + delta_controller->Looped=0; + delta_controller->Playing=0; + + this_sequence=GetSequencePointer(sequence_type,sub_sequence,delta_controller->my_hmodel_controller->Root_Section); + sequence_start=this_sequence->first_frame; + GLOBALASSERT(sequence_start); + + if (seconds_for_sequence>=0) { + delta_controller->seconds_for_sequence=seconds_for_sequence; // Special case, 0 is legal. + } else { + delta_controller->seconds_for_sequence=this_sequence->Time; + if (delta_controller->seconds_for_sequence<=0) { + delta_controller->seconds_for_sequence=ONE_FIXED; + /* Might want to assert here? */ + } + } + + if (delta_controller->seconds_for_sequence) { + delta_controller->timer_increment=DIV_FIXED(ONE_FIXED,delta_controller->seconds_for_sequence); + } else { + delta_controller->timer_increment=0; + } + +} + +void Delta_Sequence_ChangeSpeed(DELTA_CONTROLLER *delta_controller,int seconds_for_sequence) { + + GLOBALASSERT(delta_controller); + + delta_controller->seconds_for_sequence=seconds_for_sequence; // Special case. + + if (delta_controller->seconds_for_sequence) { + delta_controller->timer_increment=DIV_FIXED(ONE_FIXED,delta_controller->seconds_for_sequence); + } else { + delta_controller->timer_increment=0; + } + +} + +SECTION *Get_Corresponding_Section(SECTION **List_Ptr,char *Name) { + + SECTION **child_list_ptr=List_Ptr; + + while (*child_list_ptr!=NULL) { + if (strcmp((*child_list_ptr)->Section_Name,Name)==0) { + break; + } + child_list_ptr++; + } + + return(*child_list_ptr); +} + +SECTION_DATA *GetThisSectionData_FromChildrenOnly(SECTION_DATA *parent,char *name) { + + SECTION_DATA *sdptr; + + if ((parent==NULL)||(name==NULL)) { + return(NULL); + } + + sdptr=NULL; + + if (parent->First_Child!=NULL) { + + SECTION_DATA *child_list_ptr; + + child_list_ptr=parent->First_Child; + + while (child_list_ptr!=NULL) { + + if (strcmp(name,child_list_ptr->sempai->Section_Name)==0) { + /* Got it. */ + return(child_list_ptr); + } + + child_list_ptr=child_list_ptr->Next_Sibling; + } + } + + return(sdptr); + +} + +void Transmogrification_Recursion(STRATEGYBLOCK *sbPtr,HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,SECTION *new_template, SECTION *old_template, int frag, int newsections, int regrowsections) { + + /* Doesn't really matter which tree we're walking... does it? */ + + GLOBALASSERT(new_template); + GLOBALASSERT(old_template); + GLOBALASSERT(strcmp(new_template->Section_Name,old_template->Section_Name)==0); + + GLOBALASSERT(this_section_data); + + if ( (new_template->Children!=NULL) && (old_template->Children!=NULL) ) { + /* Complex. I'd really like to walk both at the same time. */ + SECTION **new_child_list_ptr,**old_child_list_ptr; + + new_child_list_ptr=new_template->Children; + old_child_list_ptr=old_template->Children; + + /* First, let's walk the new template. */ + while (*new_child_list_ptr!=NULL) { + + SECTION *corresponding_section; + + corresponding_section=Get_Corresponding_Section(old_child_list_ptr,(*new_child_list_ptr)->Section_Name); + + if (corresponding_section!=NULL) { + /* Section also exists in old template. Deal with it and recurse. */ + SECTION_DATA *child_section_data; + + child_section_data=GetThisSectionData_FromChildrenOnly(this_section_data,(*new_child_list_ptr)->Section_Name); + + if (child_section_data) { + /* Hey, it might be fragged off. Now deal with it. */ + + child_section_data->sempai=*new_child_list_ptr; + + Transmogrification_Recursion(sbPtr,controller,child_section_data,*new_child_list_ptr, corresponding_section, frag, newsections, regrowsections); + } else if (regrowsections) { + /* If it is fragged off, put it back. */ + SECTION_DATA *new_child; + + new_child=Create_New_Section(*new_child_list_ptr); + + new_child->My_Parent=this_section_data; + new_child->Prev_Sibling=NULL; + new_child->Next_Sibling=this_section_data->First_Child; + if (this_section_data->First_Child) { + this_section_data->First_Child->Prev_Sibling=new_child; + } + this_section_data->First_Child=new_child; + Init_Sequence_Recursion(new_child, controller->Sequence_Type, controller->Sub_Sequence,controller->Seconds_For_Sequence); + /* Prove new positions. */ + Process_Section(controller,new_child,&(this_section_data->World_Offset),&(this_section_data->SecMat),0,controller->Sequence_Type,controller->Sub_Sequence,0); + } + + } else if (newsections) { + /* No corresponding old section: create a new bit. */ + SECTION_DATA *new_child; + + new_child=Create_New_Section(*new_child_list_ptr); + + new_child->My_Parent=this_section_data; + new_child->Prev_Sibling=NULL; + new_child->Next_Sibling=this_section_data->First_Child; + if (this_section_data->First_Child) { + this_section_data->First_Child->Prev_Sibling=new_child; + } + this_section_data->First_Child=new_child; + Init_Sequence_Recursion(new_child, controller->Sequence_Type, controller->Sub_Sequence,controller->Seconds_For_Sequence); + /* Prove new positions. */ + Process_Section(controller,new_child,&(this_section_data->World_Offset),&(this_section_data->SecMat),0,controller->Sequence_Type,controller->Sub_Sequence,0); + } + + new_child_list_ptr++; + } + /* Now, let's walk the old template. */ + new_child_list_ptr=new_template->Children; + while (*old_child_list_ptr!=NULL) { + + SECTION *corresponding_section; + + corresponding_section=Get_Corresponding_Section(new_child_list_ptr,(*old_child_list_ptr)->Section_Name); + + if (corresponding_section!=NULL) { + /* Section also exists in new template. Do nothing, it should already have been dealt with. */ + } else { + /* No corresponding new section: delete this branch. */ + SECTION_DATA *superfluous_section; + + superfluous_section=GetThisSectionData_FromChildrenOnly(this_section_data,(*old_child_list_ptr)->Section_Name); + if (superfluous_section) { + if (frag) { + MakeHierarchicalDebris(sbPtr,superfluous_section, &superfluous_section->World_Offset, &superfluous_section->SecMat,NULL,2); + Prune_Section(superfluous_section); + } else { + Prune_Section(superfluous_section); + } + + } + } + + old_child_list_ptr++; + } + + + } else if (new_template->Children!=NULL) { + + if (newsections) { + /* A whole lotta new branches. */ + SECTION_DATA *new_child; + SECTION **new_child_list_ptr; + + new_child_list_ptr=new_template->Children; + + while (*new_child_list_ptr!=NULL) { + + new_child=Create_New_Section(*new_child_list_ptr); + + new_child->My_Parent=this_section_data; + new_child->Prev_Sibling=NULL; + new_child->Next_Sibling=this_section_data->First_Child; + if (this_section_data->First_Child) { + this_section_data->First_Child->Prev_Sibling=new_child; + } + this_section_data->First_Child=new_child; + + Init_Sequence_Recursion(new_child, controller->Sequence_Type, controller->Sub_Sequence,controller->Seconds_For_Sequence); + + new_child_list_ptr++; + } + } + } else if (old_template->Children!=NULL) { + /* Remove all branches. */ + SECTION_DATA *data_child_ptr; + + data_child_ptr=this_section_data->First_Child; + + while (data_child_ptr!=NULL) { + + SECTION_DATA *next_one; + + LOCALASSERT(data_child_ptr->My_Parent==this_section_data); + next_one=data_child_ptr->Next_Sibling; + if (frag) { + MakeHierarchicalDebris(sbPtr,data_child_ptr, &data_child_ptr->World_Offset, &data_child_ptr->SecMat,NULL,2); + Prune_Section(data_child_ptr); + } else { + Prune_Section(data_child_ptr); + } + data_child_ptr=next_one; + } + + } else { + /* Null case. */ + } + +} + +void Transmogrify_HModels(STRATEGYBLOCK *sbPtr,HMODELCONTROLLER *controller,SECTION *new_template, int frag, int newsections, int regrowsections) { + + SECTION *old_template; + + /* Convert one HModel to another template... */ + Global_Controller_Ptr=controller; + + old_template=controller->Root_Section; + + /* Compare the two templates to each other. */ + + GLOBALASSERT(controller->section_data->sempai==old_template); + + controller->section_data->sempai=new_template; + + Transmogrification_Recursion(sbPtr,controller,controller->section_data,new_template,old_template,frag,newsections,regrowsections); + + controller->Root_Section=new_template; +} + +void TrimToTemplate_Recursion(STRATEGYBLOCK *sbPtr,HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,SECTION *new_template, SECTION *old_template, int frag) { + + /* Doesn't really matter which tree we're walking... does it? */ + + GLOBALASSERT(new_template); + GLOBALASSERT(old_template); + GLOBALASSERT(strcmp(new_template->Section_Name,old_template->Section_Name)==0); + + GLOBALASSERT(this_section_data); + + if ( (new_template->Children!=NULL) && (old_template->Children!=NULL) ) { + /* Complex. I'd really like to walk both at the same time. */ + SECTION **new_child_list_ptr,**old_child_list_ptr; + + new_child_list_ptr=new_template->Children; + old_child_list_ptr=old_template->Children; + + /* Let's walk the old template. */ + while (*old_child_list_ptr!=NULL) { + + SECTION *corresponding_section; + + corresponding_section=Get_Corresponding_Section(new_child_list_ptr,(*old_child_list_ptr)->Section_Name); + + if (corresponding_section!=NULL) { + /* Section also exists in new template. Recurse. */ + SECTION_DATA *child_section_data; + + child_section_data=GetThisSectionData_FromChildrenOnly(this_section_data,(*old_child_list_ptr)->Section_Name); + + if (child_section_data) { + /* Hey, it might be fragged off. Now deal with it. */ + + TrimToTemplate_Recursion(sbPtr,controller,child_section_data,corresponding_section,*old_child_list_ptr, frag); + } + } else { + /* No corresponding new section: delete this branch. */ + SECTION_DATA *superfluous_section; + + superfluous_section=GetThisSectionData_FromChildrenOnly(this_section_data,(*old_child_list_ptr)->Section_Name); + if (superfluous_section) { + if (frag) { + MakeHierarchicalDebris(sbPtr,superfluous_section, &superfluous_section->World_Offset, &superfluous_section->SecMat,NULL,2); + Prune_Section(superfluous_section); + } else { + Prune_Section(superfluous_section); + } + + } + } + + old_child_list_ptr++; + } + + } else if (old_template->Children!=NULL) { + /* Remove all branches. */ + SECTION_DATA *data_child_ptr; + + data_child_ptr=this_section_data->First_Child; + + while (data_child_ptr!=NULL) { + + SECTION_DATA *next_one; + + LOCALASSERT(data_child_ptr->My_Parent==this_section_data); + next_one=data_child_ptr->Next_Sibling; + if (frag) { + MakeHierarchicalDebris(sbPtr,data_child_ptr, &data_child_ptr->World_Offset, &data_child_ptr->SecMat,NULL,2); + Prune_Section(data_child_ptr); + } else { + Prune_Section(data_child_ptr); + } + data_child_ptr=next_one; + } + + } else { + /* Null case. */ + } + +} + +void TrimToTemplate(STRATEGYBLOCK *sbPtr,HMODELCONTROLLER *controller,SECTION *new_template, int frag) { + + SECTION *old_template; + + /* Convert one HModel to another template... */ + + old_template=controller->Root_Section; + + /* Compare the two templates to each other. */ + + GLOBALASSERT(controller->section_data->sempai==old_template); + if (strcmp(new_template->Section_Name,old_template->Section_Name)) { + GLOBALASSERT(strcmp(new_template->Section_Name,old_template->Section_Name)==0); + } + TrimToTemplate_Recursion(sbPtr,controller,controller->section_data,new_template,old_template,frag); + +} + +int HModelSequence_Exists(HMODELCONTROLLER *controller,int sequence_type,int sub_sequence) { + + int sequence_id,a; + SEQUENCE *sequence_pointer; + + sequence_id=GetSequenceID(sequence_type,sub_sequence); + + for (a=0; aRoot_Section->num_sequences; a++) { + if (controller->Root_Section->sequence_array[a].sequence_id==sequence_id) { + sequence_pointer=&(controller->Root_Section->sequence_array[a]); + break; + } + } + + if (a==controller->Root_Section->num_sequences) { + /* No such animal. */ + return(0); + } else { + return(1); + } + +} + +int HModelSequence_Exists_FromRoot(SECTION *root,int sequence_type,int sub_sequence) { + + int sequence_id,a; + SEQUENCE *sequence_pointer; + + if (!root) { + return(0); + } + + sequence_id=GetSequenceID(sequence_type,sub_sequence); + + for (a=0; anum_sequences; a++) { + if (root->sequence_array[a].sequence_id==sequence_id) { + sequence_pointer=&(root->sequence_array[a]); + break; + } + } + + if (a==root->num_sequences) { + /* No such animal. */ + return(0); + } else { + return(1); + } + +} + +void KRS_Recursion(SECTION_DATA *this_section_data, int probability) { + + /* General gibbing function. */ + + + /* Recurse. */ + + if ( (this_section_data->First_Child!=NULL) + &&( (this_section_data->flags§ion_data_terminate_here)==0)) { + + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + + if ( (child_list_ptr->flags§ion_data_terminate_here)==0) { + + /* Right. Roll some dice... */ + if ( (SeededFastRandom()&65535)current_damage.Health=0; + + KRS_Recursion(child_list_ptr,probability); + + } else { + + KRS_Recursion(child_list_ptr,probability); + + } + } + child_list_ptr=child_list_ptr->Next_Sibling; + } + + } + +} + +void KillRandomSections(SECTION_DATA *this_section_data, int probability) { + + /* A bit like gibbing, but less extreme. */ + + KRS_Recursion(this_section_data,probability); + +} + +void Budge_Recursion(SECTION_DATA *this_section_data,VECTORCH *offset) { + + SECTION_DATA *sdptr; + + sdptr=NULL; + + /* Budge! */ + this_section_data->World_Offset.vx+=offset->vx; + this_section_data->World_Offset.vy+=offset->vy; + this_section_data->World_Offset.vz+=offset->vz; + + /* Now call recursion... */ + + if (this_section_data->First_Child!=NULL) { + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + Budge_Recursion(child_list_ptr,offset); + child_list_ptr=child_list_ptr->Next_Sibling; + } + } + + return; + +} + +void Budge_HModel(HMODELCONTROLLER *controller,VECTORCH *offset) { + + /* Shift a model. */ + + if ((offset==NULL)||(controller==NULL)) { + return; + } + + /* */ + + Budge_Recursion(controller->section_data,offset); + +} + +void HModelRegen_Recursion(SECTION_DATA *this_section_data, int time) { + + SECTION_DATA *sdptr; + int health_increment; + + sdptr=NULL; + + /* Regenerate this section. */ + if (this_section_data->current_damage.Health>0) { + + health_increment=DIV_FIXED((this_section_data->sempai->StartingStats.Health*NormalFrameTime),time); + this_section_data->current_damage.Health+=health_increment; + + if (this_section_data->current_damage.Health>(this_section_data->sempai->StartingStats.Health<current_damage.Health=(this_section_data->sempai->StartingStats.Health<First_Child!=NULL) { + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + HModelRegen_Recursion(child_list_ptr,time); + child_list_ptr=child_list_ptr->Next_Sibling; + } + } + + return; + +} + +void HModel_Regen(HMODELCONTROLLER *controller,int time) { + + /* Regenerate sections. */ + + HModelRegen_Recursion(controller->section_data,time); + +} + +int HModelAnimation_IsFinished(HMODELCONTROLLER *controller) { + + /* This now gets used all over the place... */ + + if (controller->Tweening!=Controller_NoTweening) { + return(0); + } + if (controller->Looped) { + return(0); + } + if (controller->Reversed) { + if (controller->sequence_timer!=0) { + return(0); + } + } else { + if (controller->sequence_timer!=(ONE_FIXED-1)) { + return(0); + } + } + return(1); +} + +int DeltaAnimation_IsFinished(DELTA_CONTROLLER *controller) { + + if (controller->Looped) { + return(0); + } + if (controller->Playing==0) { + return(1); + } + if (controller->Active==0) { + return(1); + } + if (controller->timer!=(ONE_FIXED-1)) { + return(0); + } + return(1); +} + +SECTION_DATA *PointInHModel_Recursion(SECTION_DATA *this_section_data, VECTORCH *point) { + + SECTION_DATA *hit; + + hit=NULL; + + /* Test this section. */ + + /* Use shape data. */ + if (this_section_data->Shape!=NULL) { + VECTORCH offset; + int dist; + + offset.vx=this_section_data->World_Offset.vx-point->vx; + offset.vy=this_section_data->World_Offset.vy-point->vy; + offset.vz=this_section_data->World_Offset.vz-point->vz; + dist=Approximate3dMagnitude(&offset); + if (distShape->shaperadius) { + /* Hit! */ + hit=this_section_data; + } + } + + if (hit) { + return(hit); + } + + /* Now call recursion... */ + + if (this_section_data->First_Child!=NULL) { + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + hit=PointInHModel_Recursion(child_list_ptr,point); + child_list_ptr=child_list_ptr->Next_Sibling; + } + } + + return(hit); + +} + +SECTION_DATA *PointInHModel(HMODELCONTROLLER *controller,VECTORCH *point) { + + /* Test for point in model. */ + + return(PointInHModel_Recursion(controller->section_data,point)); + +} + +SECTION *Get_Corresponding_Section_Recursive(SECTION *this_section,char *Name) { + + SECTION **child_list_ptr; + + if (strcmp(this_section->Section_Name,Name)==0) { + return(this_section); + } + + /* Recurse. */ + child_list_ptr=this_section->Children; + + if (child_list_ptr) { + while (*child_list_ptr!=NULL) { + SECTION *cosec; + + cosec=Get_Corresponding_Section_Recursive(*child_list_ptr,Name); + if (cosec) { + /* Back out! */ + return(cosec); + } + child_list_ptr++; + } + } + + /* No luck. */ + return(NULL); +} + +SECTION_DATA *GetSectionFromID_Recursion(SECTION_DATA *this_section_data,int IDnumber) { + + SECTION_DATA *sdptr; + + sdptr=NULL; + + if (this_section_data->sempai->IDnumber==IDnumber) { + /* We are that section! */ + return(this_section_data); + } + + /* Now call recursion... */ + + if (this_section_data->First_Child!=NULL) { + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + sdptr=GetSectionFromID_Recursion(child_list_ptr,IDnumber); + child_list_ptr=child_list_ptr->Next_Sibling; + + if (sdptr) { + return(sdptr); /* We got one! */ + } + } + } + + return(sdptr); + +} + +SECTION_DATA *GetThisSectionData_FromID(SECTION_DATA *root,int IDnumber) { + + if (root==NULL) { + return(NULL); + } + + return(GetSectionFromID_Recursion(root,IDnumber)); + +} + +SECTION *GetThisSection_FromID(SECTION *this_section,int IDnumber) +{ + if (this_section==NULL) { + return(NULL); + } + + //is this the section that we're looking for + if(this_section->IDnumber == IDnumber) return this_section; + + //try this section's children then + if(this_section->Children) + { + SECTION **child_list_ptr = this_section->Children; + + while(*child_list_ptr) + { + SECTION* return_section = GetThisSection_FromID(*child_list_ptr,IDnumber); + if(return_section) return return_section; + child_list_ptr++; + } + } + + //out of luck + return NULL; +} + + +void PlayHierarchySound(HIERARCHY_SOUND* sound,VECTORCH* location) +{ + GLOBALASSERT(sound); + GLOBALASSERT(location); + + sound->s3d.position=*location; + + if (!Global_VDB_Ptr) { + return; + } + + /* Marine_ignore, to stop them getting alarmed by their own footsteps! */ + Sound_Play (sound->sound_index, "nvpm", &sound->s3d,sound->volume,sound->pitch); +} + +void Init_Tweening_ToTheMiddle_Recursion(SECTION_DATA *this_section_data, int target_sequence_type,int target_subsequence, int seconds_for_tweening, int target_sequence_timer, int backwards) { + + SEQUENCE *sequence_ptr; + + /* Firstly, store current state. */ + + this_section_data->stored_offset=this_section_data->Offset; + MatToQuat(&this_section_data->RelSecMat,&this_section_data->stored_quat); + + /* Now, get target state. */ + + sequence_ptr=GetSequencePointer(target_sequence_type,target_subsequence,this_section_data->sempai); + + /* Deduce target positions. Backwards flag is irrelevant... */ + + { + int a,working_timer,lerp; + KEYFRAME_DATA *this_frame,*next_frame; + + this_frame=sequence_ptr->first_frame; + GLOBALASSERT(this_frame); + working_timer=target_sequence_timer; + + a=0; /* Status flag... */ + + while (a==0) { + if (this_frame->last_frame) { + /* Low framerate loop? */ + next_frame=sequence_ptr->first_frame; + } + else{ + next_frame=this_frame->Next_Frame; + } + if (working_timer>=this_frame->Sequence_Length) { + /* We've gone beyond this frame: get next keyframe. */ + working_timer-=this_frame->Sequence_Length; + /* Advance frame... */ + this_frame=next_frame; + } else { + a=1; /* Exit loop with success. */ + } + /* Better make sure the last 'frame' has 65536 length... */ + } + GLOBALASSERT(working_timer>=0); + /* Now we should have a frame and a timer. */ + lerp=MUL_FIXED(working_timer,this_frame->oneoversequencelength); + + GetKeyFrameOffset(this_frame,&this_section_data->target_offset); + + if(next_frame->shift_offset) + { + VECTORCH next_offset; + GetKeyFrameOffset(next_frame,&next_offset); + this_section_data->target_offset.vx+=MUL_FIXED(next_offset.vx - this_section_data->target_offset.vx,lerp); + this_section_data->target_offset.vy+=MUL_FIXED(next_offset.vy - this_section_data->target_offset.vy,lerp); + this_section_data->target_offset.vz+=MUL_FIXED(next_offset.vz - this_section_data->target_offset.vz,lerp); + } + else + { + this_section_data->target_offset.vx+=MUL_FIXED((int)next_frame->Offset_x - this_section_data->target_offset.vx,lerp); + this_section_data->target_offset.vy+=MUL_FIXED((int)next_frame->Offset_y - this_section_data->target_offset.vy,lerp); + this_section_data->target_offset.vz+=MUL_FIXED((int)next_frame->Offset_z - this_section_data->target_offset.vz,lerp); + } + + /* Now deal with orientation. */ + + Slerp(this_frame,lerp,&this_section_data->target_quat); + + } + + /* Preprocess slerp values. */ + + { + + this_section_data->delta_offset.vx=this_section_data->target_offset.vx-this_section_data->stored_offset.vx; + this_section_data->delta_offset.vy=this_section_data->target_offset.vy-this_section_data->stored_offset.vy; + this_section_data->delta_offset.vz=this_section_data->target_offset.vz-this_section_data->stored_offset.vz; + + } + + { + int cosom,sinom; + QUAT *this_quat, *next_quat; + + this_quat=&this_section_data->stored_quat; + next_quat=&this_section_data->target_quat; + + + cosom=QDot(this_quat,next_quat); + + if (cosom<0) { + next_quat->quatx=-next_quat->quatx; + next_quat->quaty=-next_quat->quaty; + next_quat->quatz=-next_quat->quatz; + next_quat->quatw=-next_quat->quatw; + cosom=-cosom; + } + + + this_section_data->omega=ArcCos(cosom); + sinom=GetSin(this_section_data->omega); + if (sinom) { + this_section_data->oneoversinomega=GetOneOverSin(this_section_data->omega); + } else { + /* Yuk. */ + this_section_data->omega=0; + this_section_data->oneoversinomega=0; + } + + GLOBALASSERT(seconds_for_tweening>0); + this_section_data->oneovertweeninglength=DIV_FIXED(ONE_FIXED,seconds_for_tweening); + + } + + /* Init fields... I guess. */ + + this_section_data->current_sequence=sequence_ptr; + this_section_data->current_keyframe=sequence_ptr->first_frame; + this_section_data->accumulated_timer=0; + this_section_data->freezeframe_timer=-1; + this_section_data->lastframe_timer=0; + this_section_data->gore_timer=0; /* As good a time as any. */ + + this_section_data->Tweening=1; + + /* Animation? */ + + /* Nah. */ + + /* Recurse. */ + + if ( (this_section_data->First_Child!=NULL) + &&( (this_section_data->flags§ion_data_terminate_here)==0)) { + /* Respect the terminator! */ + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + Init_Tweening_ToTheMiddle_Recursion(child_list_ptr,target_sequence_type,target_subsequence,seconds_for_tweening,target_sequence_timer,backwards); + child_list_ptr=child_list_ptr->Next_Sibling; + } + + } + +} + + +void InitHModelTweening_ToTheMiddle(HMODELCONTROLLER *controller, int seconds_for_tweening, + int target_sequence_type, int target_subsequence, int target_seconds_for_sequence, int target_sequence_timer, int loop) { + + /* Just set it up... */ + GLOBALASSERT(target_seconds_for_sequence); + + controller->Sequence_Type=target_sequence_type; + controller->Sub_Sequence=target_subsequence; + controller->Seconds_For_Sequence=seconds_for_tweening; + controller->timer_increment=DIV_FIXED(ONE_FIXED,controller->Seconds_For_Sequence); + controller->sequence_timer=0; + controller->Playing=1; + controller->Reversed=0; + controller->Looped=1; + + controller->After_Tweening_Sequence_Type=target_sequence_type; + controller->After_Tweening_Sub_Sequence=target_subsequence; + controller->AT_seconds_for_sequence=target_seconds_for_sequence; + + controller->AT_sequence_timer=target_sequence_timer; + while (controller->AT_sequence_timer>=ONE_FIXED) { + controller->AT_sequence_timer-=ONE_FIXED; + } + + controller->Tweening=Controller_Tweening; + if (loop) { + controller->LoopAfterTweening=1; + } else { + controller->LoopAfterTweening=0; + } + controller->StopAfterTweening=0; + controller->ElevationTweening=0; + + /* Recurse though hierarchy, setting up all the section_data sequence stores? */ + + Init_Tweening_ToTheMiddle_Recursion(controller->section_data, target_sequence_type, target_subsequence,seconds_for_tweening,target_sequence_timer,0); + +} + +void Verify_Positions_Recursion(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,VECTORCH *parent_position,char *callCode) { + + /* Verify positions... */ + + if ( !( (this_section_data->World_Offset.vx<1000000 && this_section_data->World_Offset.vx>-1000000) + && (this_section_data->World_Offset.vy<1000000 && this_section_data->World_Offset.vy>-1000000) + && (this_section_data->World_Offset.vz<1000000 && this_section_data->World_Offset.vz>-1000000) + ) ) { + + LOGDXFMT(("Tests in VERIFY_POSITIONS_RECURSION.\n")); + if (callCode) { + LOGDXFMT(("Call code %s\n",callCode)); + } else { + LOGDXFMT(("No call code!\n")); + } + if (Global_HModel_Sptr) { + LOGDXFMT(("Misplaced object is of type %d\n",Global_HModel_Sptr->I_SBtype)); + if (Global_HModel_Sptr->SBdptr) { + LOGDXFMT(("Object is Near.\n")); + } else { + LOGDXFMT(("Object is Far.\n")); + } + } else { + LOGDXFMT(("Misplaced object has no SBptr.\n")); + } + LOGDXFMT(("Name of section: %s\n",this_section_data->sempai->Section_Name)); + LOGDXFMT(("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence)); + LOGDXFMT(("Sequence Timer = %d\n",controller->sequence_timer)); + LOGDXFMT(("Tweening flags %d\n",controller->Tweening)); + + LOGDXFMT(("Parent Position %d,%d,%d\n",parent_position->vx,parent_position->vy,parent_position->vz)); + LOGDXFMT(("This Position %d,%d,%d\n",this_section_data->World_Offset.vx,this_section_data->World_Offset.vy,this_section_data->World_Offset.vz)); + + LOCALASSERT(this_section_data->World_Offset.vx<1000000 && this_section_data->World_Offset.vx>-1000000); + LOCALASSERT(this_section_data->World_Offset.vy<1000000 && this_section_data->World_Offset.vy>-1000000); + LOCALASSERT(this_section_data->World_Offset.vz<1000000 && this_section_data->World_Offset.vz>-1000000); + + } + + /* Now call recursion... */ + + if (this_section_data->First_Child!=NULL) { + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + Verify_Positions_Recursion(controller,child_list_ptr,&this_section_data->World_Offset,callCode); + child_list_ptr=child_list_ptr->Next_Sibling; + } + } + + return; + +} + +void Verify_Positions_In_HModel(STRATEGYBLOCK *sbPtr,HMODELCONTROLLER *controller,char *callCode) { + + /* Verify position integrity. */ + + if ((controller==NULL)||(sbPtr==NULL)) { + return; + } + + /* */ + + Global_HModel_Sptr=sbPtr; + Global_Controller_Ptr=controller; + Global_HModel_DispPtr=sbPtr->SBdptr; + + Verify_Positions_Recursion(controller,controller->section_data,&sbPtr->DynPtr->Position,callCode); + +} + + + + +void CopyShortQuatToInt(QUAT_SHORT* qs,QUAT* q) +{ + q->quatx=((int)qs->quatx)<<1; + q->quaty=((int)qs->quaty)<<1; + q->quatz=((int)qs->quatz)<<1; + q->quatw=((int)qs->quatw)<<1; +} + + +void CopyIntQuatToShort(QUAT* q,QUAT_SHORT* qs) +{ + if(q->quatx>65535) qs->quatx=32767; + else if(q->quatx<-65536) qs->quatx=-32768; + else qs->quatx=q->quatx>>1; + + if(q->quaty>65535) qs->quaty=32767; + else if(q->quaty<-65536) qs->quaty=-32768; + else qs->quaty=q->quaty>>1; + + if(q->quatz>65535) qs->quatz=32767; + else if(q->quatz<-65536) qs->quatz=-32768; + else qs->quatz=q->quatz>>1; + + if(q->quatw>65535) qs->quatw=32767; + else if(q->quatw<-65536) qs->quatw=-32768; + else qs->quatw=q->quatw>>1; + +} + +void GetKeyFrameOffset(KEYFRAME_DATA* frame,VECTORCH* output_vector) +{ + if(frame->shift_offset) + { + output_vector->vx=((int)frame->Offset_x)<vy=((int)frame->Offset_y)<vz=((int)frame->Offset_z)<vx=(int)frame->Offset_x; + output_vector->vy=(int)frame->Offset_y; + output_vector->vz=(int)frame->Offset_z; + } +} + + +void SetKeyFrameOffset(KEYFRAME_DATA* frame,VECTORCH* input_vector) +{ + if(input_vector->vx>=-32768 && input_vector->vx<=32767 && + input_vector->vy>=-32768 && input_vector->vy<=32767 && + input_vector->vz>=-32768 && input_vector->vz<=32767) + { + frame->Offset_x=(short)input_vector->vx; + frame->Offset_y=(short)input_vector->vy; + frame->Offset_z=(short)input_vector->vz; + + frame->shift_offset=0; + } + else + { + frame->Offset_x=(short)(input_vector->vx >> KEYFRAME_VECTOR_SHIFT); + frame->Offset_y=(short)(input_vector->vy >> KEYFRAME_VECTOR_SHIFT); + frame->Offset_z=(short)(input_vector->vz >> KEYFRAME_VECTOR_SHIFT); + + frame->shift_offset=1; + + } +} + +int HModelDepthTest_Recursion(SECTION_DATA *this_section_data, SECTION_DATA *test_section_data,int depth) { + + SECTION_DATA *sdptr; + int totals; + + sdptr=NULL; + totals=0; + + /* Return if too deep. */ + if (depth<0) { + return(0); + } + + /* Test this section? */ + if (this_section_data==test_section_data) { + /* Success. */ + return(1); + } + + /* Now call recursion... */ + + if (this_section_data->First_Child!=NULL) { + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + totals+=HModelDepthTest_Recursion(child_list_ptr,test_section_data,depth-1); + child_list_ptr=child_list_ptr->Next_Sibling; + } + } + + return(totals); + +} + +int HModel_DepthTest(HMODELCONTROLLER *controller,SECTION_DATA *test_section_data,int depth) { + + /* Regenerate sections. */ + + return(HModelDepthTest_Recursion(controller->section_data,test_section_data,depth)); + +} + +void DeInitialise_Recursion(SECTION_DATA *this_section_data) { + + SECTION_DATA *sdptr; + + sdptr=NULL; + + this_section_data->flags=this_section_data->flags&(~section_data_initialised); + + /* Now call recursion... */ + + if (this_section_data->First_Child!=NULL) { + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + DeInitialise_Recursion(child_list_ptr); + child_list_ptr=child_list_ptr->Next_Sibling; + } + } + + return; + +} + +void DeInitialise_HModel(HMODELCONTROLLER *controller) { + + /* Recursively set all 'initialised' flags to zero. */ + + if (controller==NULL) { + return; + } + + DeInitialise_Recursion(controller->section_data); + +} + + +static void EnsureChildrenAreInAscendingIDOrder(SECTION_DATA* section) +{ + /* + This checks all the children of a section to make sure that they are placed in ascending Id order. + This is needed for the saving and loading process to work properly. + (In the majority of cases, sections will be in the right order , so this should be fairly quick) + */ + + SECTION_DATA* child_section = section->First_Child; + + if(!child_section) return; + + while(child_section->Next_Sibling) + { + SECTION_DATA* next_section = child_section->Next_Sibling; + if(next_section->sempai->IDnumbersempai->IDnumber) + { + /* + These two sections are out of order , so we need to swap them + */ + + + /*First correct the children before and adter the ones being swapped*/ + + if(child_section->Prev_Sibling) + { + child_section->Prev_Sibling->Next_Sibling = next_section; + } + if(next_section->Next_Sibling) + { + next_section->Next_Sibling->Prev_Sibling = child_section; + } + + /* + If we are swapping the first child , then we need to alter the parent's pointer + */ + if(section->First_Child == child_section) + { + section->First_Child = next_section; + } + + + /* + Give the sections being swapped the pointers to the sections before and after them + */ + child_section->Next_Sibling = next_section->Next_Sibling; + next_section->Prev_Sibling = child_section->Prev_Sibling; + + + child_section->Prev_Sibling = next_section; + next_section->Next_Sibling = child_section; + + + /*The next section we will have to consider is the one we have just swapped ealier in the list*/ + child_section = next_section; + + /* + If the section has a previous sibling then we need to look back at that one , since the previous sibling's + if could be higher than that of the section we have just swapped + */ + + if(child_section->Prev_Sibling) child_section = child_section->Prev_Sibling; + + } + else + { + //No problem with this section , go on to the next + child_section = child_section->Next_Sibling; + } + } +} + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" + +static void LoadHierarchySection(SECTION_DATA* section); +static void SaveHierarchySectionRecursion(SECTION_DATA* section); + +static void LoadHierarchySectionDecals(SAVE_BLOCK_HEADER* header,SECTION_DATA* section); +static void SaveHierarchySectionDecals(SECTION_DATA* section); + +static void LoadHierarchySectionTween(SAVE_BLOCK_HEADER* header,SECTION_DATA* section); +static void SaveHierarchySectionTween(SECTION_DATA* section); + +static void LoadHierarchyDelta(SAVE_BLOCK_HEADER* header,HMODELCONTROLLER* controller); +static void SaveHierarchyDelta(DELTA_CONTROLLER* delta); + +typedef struct hierarchy_save_block +{ + SAVE_BLOCK_HEADER header; + + int structure_size; + + int Seconds_For_Sequence; + int timer_increment; + int Sequence_Type; + int Sub_Sequence; + int sequence_timer; + int FrameStamp; + VECTORCH Computed_Position; + + int keyframe_flags; + + int After_Tweening_Sequence_Type; + int After_Tweening_Sub_Sequence; + int AT_seconds_for_sequence; + int AT_sequence_timer; + + unsigned int Playing:1; + unsigned int Reversed:1; + unsigned int Looped:1; + unsigned int Tweening:2; + unsigned int LoopAfterTweening:1; + unsigned int StopAfterTweening:1; + unsigned int ElevationTweening:1; + unsigned int DisableBleeding:1; + unsigned int LockTopSection:1; + unsigned int ZeroRootDisplacement:1; + unsigned int ZeroRootRotation:1; + unsigned int DisableSounds:1; + + int root_section_id; + +}HIERARCHY_SAVE_BLOCK; + + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV controller + + +void LoadHierarchy(SAVE_BLOCK_HEADER* header,HMODELCONTROLLER* controller) +{ + SECTION *root_section; + const char *Rif_Name; + const char *Hierarchy_Name; + HIERARCHY_SAVE_BLOCK* block = (HIERARCHY_SAVE_BLOCK*) header; + + //make sure the block is the correct size + if(block->structure_size != sizeof(*block)) return; + + //get the names from just after the block + { + char* buffer=(char*) header; + buffer+=sizeof(*block); + + Hierarchy_Name = buffer; + buffer+= strlen(Hierarchy_Name)+1; + Rif_Name = buffer; + } + + { + BOOL needToCreateHModel = FALSE; + + //make sure that the initial model has been set up , and is using the correct hierarchy + if(controller->Root_Section) + { + if(strcmp(Rif_Name,controller->Root_Section->Rif_Name) || strcmp(Hierarchy_Name,controller->Root_Section->Hierarchy_Name)) + { + needToCreateHModel = TRUE; + } + else if(controller->Root_Section->IDnumber != block->root_section_id) + { + needToCreateHModel = TRUE; + } + } + else + { + needToCreateHModel = TRUE; + } + + //check to see if we need to change hierarchy + if(needToCreateHModel) + { + extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); + + root_section = GetNamedHierarchyFromLibrary(Rif_Name,Hierarchy_Name); + if(!root_section) return; + + //may not want the 'real' root (hierarchical debris) + root_section = GetThisSection_FromID(root_section,block->root_section_id); + if(!root_section) return; + + + //reinitialise the hierarchy + Dispel_HModel(controller); + Create_HModel(controller,root_section); + } + } + + //copy the stuff for the controller + COPYELEMENT_LOAD(Seconds_For_Sequence) + COPYELEMENT_LOAD(timer_increment) + COPYELEMENT_LOAD(Sequence_Type) + COPYELEMENT_LOAD(Sub_Sequence) + COPYELEMENT_LOAD(sequence_timer) + COPYELEMENT_LOAD(FrameStamp) + COPYELEMENT_LOAD(Computed_Position) + COPYELEMENT_LOAD(keyframe_flags) + COPYELEMENT_LOAD(After_Tweening_Sequence_Type) + COPYELEMENT_LOAD(After_Tweening_Sub_Sequence) + COPYELEMENT_LOAD(AT_seconds_for_sequence) + COPYELEMENT_LOAD(AT_sequence_timer) + COPYELEMENT_LOAD(Playing) + COPYELEMENT_LOAD(Reversed) + COPYELEMENT_LOAD(Looped) + COPYELEMENT_LOAD(Tweening) + COPYELEMENT_LOAD(LoopAfterTweening) + COPYELEMENT_LOAD(StopAfterTweening) + COPYELEMENT_LOAD(ElevationTweening) + COPYELEMENT_LOAD(DisableBleeding) + COPYELEMENT_LOAD(LockTopSection) + COPYELEMENT_LOAD(ZeroRootDisplacement) + COPYELEMENT_LOAD(ZeroRootRotation) + COPYELEMENT_LOAD(DisableSounds); + + + //load the delta sequences + { + SAVE_BLOCK_HEADER* delta_header; + + while(delta_header = GetNextBlockIfOfType(SaveBlock_HierarchyDelta)) + { + LoadHierarchyDelta(delta_header,controller); + } + + } + + ///load the section data + LoadHierarchySection(controller->section_data); + +} + + +void SaveHierarchy(HMODELCONTROLLER* controller) +{ + HIERARCHY_SAVE_BLOCK* block; + if(!controller) return; + if(!controller->Root_Section) return; + + GET_SAVE_BLOCK_POINTER(block); + + //fill in header + block->header.type = SaveBlock_Hierarchy; + block->header.size = sizeof(*block); + block->structure_size =block->header.size; + + COPYELEMENT_SAVE(Seconds_For_Sequence) + COPYELEMENT_SAVE(timer_increment) + COPYELEMENT_SAVE(Sequence_Type) + COPYELEMENT_SAVE(Sub_Sequence) + COPYELEMENT_SAVE(sequence_timer) + COPYELEMENT_SAVE(FrameStamp) + COPYELEMENT_SAVE(Computed_Position) + COPYELEMENT_SAVE(keyframe_flags) + COPYELEMENT_SAVE(After_Tweening_Sequence_Type) + COPYELEMENT_SAVE(After_Tweening_Sub_Sequence) + COPYELEMENT_SAVE(AT_seconds_for_sequence) + COPYELEMENT_SAVE(AT_sequence_timer) + COPYELEMENT_SAVE(Playing) + COPYELEMENT_SAVE(Reversed) + COPYELEMENT_SAVE(Looped) + COPYELEMENT_SAVE(Tweening) + COPYELEMENT_SAVE(LoopAfterTweening) + COPYELEMENT_SAVE(StopAfterTweening) + COPYELEMENT_SAVE(ElevationTweening) + COPYELEMENT_SAVE(DisableBleeding) + COPYELEMENT_SAVE(LockTopSection) + COPYELEMENT_SAVE(ZeroRootDisplacement) + COPYELEMENT_SAVE(ZeroRootRotation) + COPYELEMENT_SAVE(DisableSounds); + + block->root_section_id = controller->Root_Section->IDnumber; + + { + char* buffer; + char* Hierarchy_Name = controller->Root_Section->Hierarchy_Name; + char* Rif_Name = controller->Root_Section->Rif_Name; + + //increase the block size by enough to hold these names + block->header.size+= strlen(Hierarchy_Name)+strlen(Rif_Name)+2; + + //alllocate memoey , and copy names; + buffer = GetPointerForSaveBlock(strlen(Hierarchy_Name)+1); + strcpy(buffer,Hierarchy_Name); + + buffer = GetPointerForSaveBlock(strlen(Rif_Name)+1); + strcpy(buffer,Rif_Name); + + } + + //save the delta sequences + { + DELTA_CONTROLLER* delta = controller->Deltas; + + while(delta) + { + SaveHierarchyDelta(delta); + delta=delta->next_controller; + } + } + + //now save the section data + SaveHierarchySectionRecursion(controller->section_data); +} + +typedef struct hierarchy_delta_save_block +{ + SAVE_BLOCK_HEADER header; + + int timer; + int lastframe_timer; + int sequence_type; + int sub_sequence; + int seconds_for_sequence; + int timer_increment; + int Looped:1; + int Playing:1; + int Active:1; + +}HIERARCHY_DELTA_SAVE_BLOCK; + +#undef SAVELOAD_BEHAV +//defines for load/save macros +#define SAVELOAD_BEHAV delta + +static void LoadHierarchyDelta(SAVE_BLOCK_HEADER* header,HMODELCONTROLLER* controller) +{ + DELTA_CONTROLLER* delta; + HIERARCHY_DELTA_SAVE_BLOCK* block = (HIERARCHY_DELTA_SAVE_BLOCK*) header; + char* name = (char*) (block+1); + + delta = Get_Delta_Sequence(controller,name); + if(!delta) + { + delta = Add_Delta_Sequence(controller,name,block->sequence_type,block->sub_sequence,block->seconds_for_sequence); + } + + + COPYELEMENT_LOAD(timer) + COPYELEMENT_LOAD(lastframe_timer) + COPYELEMENT_LOAD(timer_increment) + COPYELEMENT_LOAD(Looped) + COPYELEMENT_LOAD(Playing) + COPYELEMENT_LOAD(Active) + COPYELEMENT_LOAD(sequence_type) + COPYELEMENT_LOAD(sub_sequence) + COPYELEMENT_LOAD(seconds_for_sequence) + + + + +} + +static void SaveHierarchyDelta(DELTA_CONTROLLER* delta) +{ + HIERARCHY_DELTA_SAVE_BLOCK* block; + int size; + + //work out memory needed + size=sizeof(*block) + strlen(delta->id) +1; + block = (HIERARCHY_DELTA_SAVE_BLOCK*) GetPointerForSaveBlock(size); + + //fill in the header + block->header.size = size; + block->header.type = SaveBlock_HierarchyDelta; + + COPYELEMENT_SAVE(timer) + COPYELEMENT_SAVE(lastframe_timer) + COPYELEMENT_SAVE(timer_increment) + COPYELEMENT_SAVE(Looped) + COPYELEMENT_SAVE(Playing) + COPYELEMENT_SAVE(Active) + COPYELEMENT_SAVE(sequence_type) + COPYELEMENT_SAVE(sub_sequence) + COPYELEMENT_SAVE(seconds_for_sequence) + + //tack the name on the end + { + char* name = (char*)(block+1); + strcpy(name,delta->id); + } + + +} + + +typedef struct hierarchy_section_save_block +{ + SAVE_BLOCK_HEADER header; + +//from section + int IDnumber; + +//from section_data + VECTORCH Offset; + VECTORCH World_Offset; + VECTORCH Last_World_Offset; + MATRIXCH RelSecMat; + MATRIXCH SecMat; + + struct damageblock current_damage; + + int accumulated_timer; + int freezeframe_timer; + int lastframe_timer; + int gore_timer; + + int flags; + + int sequence_id; + int keyframe_time; + + + int replacement_id; + +}HIERARCHY_SECTION_SAVE_BLOCK; + + +#undef SAVELOAD_BEHAV +//defines for load/save macros +#define SAVELOAD_BEHAV section + +extern HIERARCHY_SHAPE_REPLACEMENT* GetHierarchyAlternateShapeFromId(const char* rif_name,int replacement_id,char* section_name); + + +static void LoadHierarchySection(SECTION_DATA* section) +{ + SAVE_BLOCK_HEADER* header; + SAVE_BLOCK_HEADER* decal_header; + SAVE_BLOCK_HEADER* tween_header; + + HIERARCHY_SECTION_SAVE_BLOCK* block; + + header=GetNextBlockIfOfType(SaveBlock_HierarchySection); + decal_header=GetNextBlockIfOfType(SaveBlock_HierarchyDecals); + tween_header=GetNextBlockIfOfType(SaveBlock_HierarchyTween); + + /* + In this bit we go through the hierechy section data , and saved section data in increasing + ID number order. Whenever we find any sections without saved data , we need to prunce them + (since they will have been blown off the original hierarchy) + */ + + while(header && section) + { + block = (HIERARCHY_SECTION_SAVE_BLOCK*) header; + + if(block->header.size!=sizeof(*block)) return; + + //compare section id numbers + if(block->IDnumber == section->sempai->IDnumber) + { + //copy stuff for this section then + COPYELEMENT_LOAD(Offset); + COPYELEMENT_LOAD(World_Offset); + COPYELEMENT_LOAD(Last_World_Offset); + COPYELEMENT_LOAD(RelSecMat); + COPYELEMENT_LOAD(SecMat); + + COPYELEMENT_LOAD(current_damage); + + COPYELEMENT_LOAD(accumulated_timer); + COPYELEMENT_LOAD(freezeframe_timer); + COPYELEMENT_LOAD(lastframe_timer); + COPYELEMENT_LOAD(gore_timer); + + COPYELEMENT_LOAD(flags); + COPYELEMENT_LOAD(replacement_id); + + + //see if this section is using an alternate shape set + { + int desiredShapeIndex = section->sempai->ShapeNum; + HIERARCHY_SHAPE_REPLACEMENT* replacement = GetHierarchyAlternateShapeFromId(section->sempai->Rif_Name,block->replacement_id,section->sempai->Section_Name); + + if(replacement) + { + desiredShapeIndex = replacement->replacement_shape_index; + } + + if(section->ShapeNum != desiredShapeIndex) + { + section->ShapeNum = desiredShapeIndex; + + if(desiredShapeIndex>=0) + { + section->Shape = mainshapelist[desiredShapeIndex]; + } + else + { + section->Shape = 0; + } + Setup_Texture_Animation_For_Section(section); + + } + } + + + //load decals + if(decal_header) + { + LoadHierarchySectionDecals(decal_header,section); + } + else + { + section->NumberOfDecals = 0; + section->NextDecalToUse = 0; + + } + + //load tweening data + if(tween_header) + { + LoadHierarchySectionTween(tween_header,section); + } + else + { + section->Tweening = 0; + } + + + //get the current sequence and frame + + { + int a; + int time; + SECTION* this_section = section->sempai; + section->current_sequence=&(this_section->sequence_array[0]); + + for (a=0; anum_sequences; a++) { + if (this_section->sequence_array[a].sequence_id==block->sequence_id) { + section->current_sequence=&(this_section->sequence_array[a]); + break; + } + } + + time = block->keyframe_time; + section->current_keyframe = section->current_sequence->first_frame; + + while(time>=section->current_keyframe->Sequence_Length) + { + time-= section->current_keyframe->Sequence_Length; + + if(section->current_keyframe->last_frame) + { + break; + } + else + { + section->current_keyframe = section->current_keyframe->Next_Frame; + } + } + + + + + + } + + //move to the next section data + if(section->First_Child) + { + section = section->First_Child; + } + else if (section->Next_Sibling) + { + section = section->Next_Sibling; + } + else + { + BOOL section_found=FALSE; + while(section && !section_found) + { + section = section->My_Parent; + if(section) + { + if(section->Next_Sibling) + { + section=section->Next_Sibling; + section_found = TRUE; + } + } + } + } + + //move to next saved section + header=GetNextBlockIfOfType(SaveBlock_HierarchySection); + decal_header=GetNextBlockIfOfType(SaveBlock_HierarchyDecals); + tween_header=GetNextBlockIfOfType(SaveBlock_HierarchyTween); + } + else if(block->IDnumber > section->sempai->IDnumber) + { + /* + There was no saved data for this section , so we will need to prune it + */ + + SECTION_DATA* pruned_section = section; + + if (section->Next_Sibling) + { + section = section->Next_Sibling; + } + else + { + BOOL section_found=FALSE; + while(section && !section_found) + { + section = section->My_Parent; + if(section) + { + if(section->Next_Sibling) + { + section=section->Next_Sibling; + section_found = TRUE; + } + } + } + } + Prune_Section(pruned_section); + + } + else + { + //move to next saved section (we will need to advance until the saved id number matches + //the section id number) + //Nb. This probably never happens anyway + header=GetNextBlockIfOfType(SaveBlock_HierarchySection); + decal_header=GetNextBlockIfOfType(SaveBlock_HierarchyDecals); + tween_header=GetNextBlockIfOfType(SaveBlock_HierarchyTween); + } + } + + //prune the remaining sections + while(section) + { + SECTION_DATA* pruned_section = section; + + if (section->Next_Sibling) + { + section = section->Next_Sibling; + } + else + { + BOOL section_found=FALSE; + while(section && !section_found) + { + section = section->My_Parent; + if(section) + { + if(section->Next_Sibling) + { + section=section->Next_Sibling; + section_found = TRUE; + } + } + } + } + Prune_Section(pruned_section); + } + +} + + +static void SaveHierarchySectionRecursion(SECTION_DATA* section) +{ + HIERARCHY_SECTION_SAVE_BLOCK* block; + + GET_SAVE_BLOCK_POINTER(block); + + //fill in header + block->header.type = SaveBlock_HierarchySection; + block->header.size = sizeof(*block); + + + block->IDnumber = section->sempai->IDnumber; + + //copy stuff + COPYELEMENT_SAVE(Offset); + COPYELEMENT_SAVE(World_Offset); + COPYELEMENT_SAVE(Last_World_Offset); + COPYELEMENT_SAVE(RelSecMat); + COPYELEMENT_SAVE(SecMat); + + COPYELEMENT_SAVE(current_damage); + + COPYELEMENT_SAVE(accumulated_timer); + COPYELEMENT_SAVE(freezeframe_timer); + COPYELEMENT_SAVE(lastframe_timer); + COPYELEMENT_SAVE(gore_timer); + + COPYELEMENT_SAVE(flags); + COPYELEMENT_SAVE(replacement_id); + + //get current sequence id + block->sequence_id = section->current_sequence->sequence_id; + + { + KEYFRAME_DATA* frame = section->current_sequence->first_frame; + int time=0; + + while(frame != section->current_keyframe) + { + time += frame->Sequence_Length; + + if(frame->last_frame) break; + + frame = frame->Next_Frame; + } + + block->keyframe_time = time; + + } + + + //save decals (if needed) + if(section->NumberOfDecals) + { + SaveHierarchySectionDecals(section); + } + + //save tweening (if needed) + if(section->Tweening) + { + SaveHierarchySectionTween(section); + } + + //recurse down hierarchy + if (section->First_Child!=NULL) { + + SECTION_DATA * child_section; + /* + Must make sure the children are in the right order before saving. + */ + EnsureChildrenAreInAscendingIDOrder(section); + + child_section = section->First_Child; + + while (child_section) + { + SaveHierarchySectionRecursion(child_section); + child_section = child_section->Next_Sibling; + } + } + + +} + + + +//section decal data +typedef struct hierarchy_decal_save_block +{ + SAVE_BLOCK_HEADER header; + + int NumberOfDecals; + int NextDecalToUse; + OBJECT_DECAL Decals[MAX_NO_OF_DECALS_PER_HIERARCHICAL_SECTION]; +}HIERARCHY_DECAL_SAVE_BLOCK; + + + + + +static void LoadHierarchySectionDecals(SAVE_BLOCK_HEADER* header,SECTION_DATA* section) +{ + int i; + + HIERARCHY_DECAL_SAVE_BLOCK* block = (HIERARCHY_DECAL_SAVE_BLOCK*) header; + + COPYELEMENT_LOAD(NumberOfDecals); + COPYELEMENT_LOAD(NextDecalToUse); + + for(i=0;iNumberOfDecals;i++) + { + COPYELEMENT_LOAD(Decals[i]); + } + +} + + +static void SaveHierarchySectionDecals(SECTION_DATA* section) +{ + HIERARCHY_DECAL_SAVE_BLOCK* block; + int i; + + //determine how much space is required for the decals present + int size = sizeof(HIERARCHY_DECAL_SAVE_BLOCK); + size -= (MAX_NO_OF_DECALS_PER_HIERARCHICAL_SECTION - section->NumberOfDecals) * sizeof(OBJECT_DECAL); + + block = (HIERARCHY_DECAL_SAVE_BLOCK*) GetPointerForSaveBlock(size); + + //fill in the header + block->header.type = SaveBlock_HierarchyDecals; + block->header.size = size; + + //copy the decals + + COPYELEMENT_SAVE(NumberOfDecals); + COPYELEMENT_SAVE(NextDecalToUse); + + for(i=0;iNumberOfDecals;i++) + { + COPYELEMENT_SAVE(Decals[i]); + } + + +} + + +//section tweening data +typedef struct hierarchy_tween_save_block +{ + SAVE_BLOCK_HEADER header; + + /* Tweening */ + VECTORCH stored_offset; + VECTORCH target_offset; + VECTORCH delta_offset; + QUAT stored_quat; + QUAT target_quat; + int omega; + int oneoversinomega; + int oneovertweeninglength; + unsigned int Tweening:1; + + +}HIERARCHY_TWEEN_SAVE_BLOCK; + +static void LoadHierarchySectionTween(SAVE_BLOCK_HEADER* header,SECTION_DATA* section) +{ + //see if this section has tweening data saved + HIERARCHY_TWEEN_SAVE_BLOCK* block = (HIERARCHY_TWEEN_SAVE_BLOCK*) header; + if(!block) return; + + COPYELEMENT_LOAD(stored_offset); + COPYELEMENT_LOAD(target_offset); + COPYELEMENT_LOAD(delta_offset); + COPYELEMENT_LOAD(stored_quat); + COPYELEMENT_LOAD(target_quat); + COPYELEMENT_LOAD(omega); + COPYELEMENT_LOAD(oneoversinomega); + COPYELEMENT_LOAD(oneovertweeninglength); + COPYELEMENT_LOAD(Tweening); +} + +static void SaveHierarchySectionTween(SECTION_DATA* section) +{ + HIERARCHY_TWEEN_SAVE_BLOCK* block; + + GET_SAVE_BLOCK_POINTER(block); + + //fill in the header + block->header.type = SaveBlock_HierarchyTween; + block->header.size = sizeof(*block); + + //copy stuff + + COPYELEMENT_SAVE(stored_offset); + COPYELEMENT_SAVE(target_offset); + COPYELEMENT_SAVE(delta_offset); + COPYELEMENT_SAVE(stored_quat); + COPYELEMENT_SAVE(target_quat); + COPYELEMENT_SAVE(omega); + COPYELEMENT_SAVE(oneoversinomega); + COPYELEMENT_SAVE(oneovertweeninglength); + COPYELEMENT_SAVE(Tweening); + +} diff --git a/3dc/avp/HUDDEFS.H b/3dc/avp/HUDDEFS.H new file mode 100644 index 0000000..16ce4df --- /dev/null +++ b/3dc/avp/HUDDEFS.H @@ -0,0 +1,258 @@ +/*KJL************************************************************************** +* HUDDEFS.H - * +* * +* this file contains all the prototypes of the platform-dependent functions * +* called in hud.c. * +**************************************************************************KJL*/ + +#ifndef _huddefs_h +#define _huddefs_h 1 + + #ifdef __cplusplus + extern "C" { + #endif + +/*KJL**************************************************************************************** +* D E F I N E S * +****************************************************************************************KJL*/ + +/*KJL************************************************************************************** +* Motion Tracker defines - Range is currently 30 metres. Don't worry about those casts to * +* floats, they're only there to ensure accuracy and are preprocessed away. For example, * +* 65536*65536 will probably cause an overflow in the preprocessor so I've used floats to * +* avoid this. * +**************************************************************************************KJL*/ +#define MOTIONTRACKER_RANGE ((int)((float)30000*(float)GlobalScale)) +#define MOTIONTRACKER_RANGE_SQUARED (MOTIONTRACKER_RANGE*MOTIONTRACKER_RANGE) +#define MOTIONTRACKER_SCALE (int)((65536.0*65536.0)/(float)MOTIONTRACKER_RANGE) +#define MOTIONTRACKER_SPEED (MUL_FIXED((65536*2),MotionTrackerSpeed)) +#define MOTIONTRACKER_MAXBLIPS 10 +#define MOTIONTRACKER_SMALLESTSCANLINESIZE 2200 + +typedef struct +{ + int X; + int Y; + int Brightness; +} BLIP_TYPE; +/*KJL************************************************* +* Speed at which gunsight moves when smart-targeting * +*************************************************KJL*/ +#define SMART_TARGETING_SPEED 4 + +#define SMART_TARGETING_RANGE 1000000 + + +/*KJL********************************************* +* Numerical digits which occur in the marine HUD * +*********************************************KJL*/ +enum MARINE_HUD_DIGIT +{ + MARINE_HUD_MOTIONTRACKER_UNITS=0, + MARINE_HUD_MOTIONTRACKER_TENS, + MARINE_HUD_MOTIONTRACKER_HUNDREDS, + MARINE_HUD_MOTIONTRACKER_THOUSANDS, + + MARINE_HUD_HEALTH_UNITS, + MARINE_HUD_HEALTH_TENS, + MARINE_HUD_HEALTH_HUNDREDS, + + MARINE_HUD_ENERGY_UNITS, + MARINE_HUD_ENERGY_TENS, + MARINE_HUD_ENERGY_HUNDREDS, + + MARINE_HUD_ARMOUR_UNITS, + MARINE_HUD_ARMOUR_TENS, + MARINE_HUD_ARMOUR_HUNDREDS, + + MARINE_HUD_PRIMARY_AMMO_ROUNDS_UNITS, + MARINE_HUD_PRIMARY_AMMO_ROUNDS_TENS, + MARINE_HUD_PRIMARY_AMMO_ROUNDS_HUNDREDS, + + MARINE_HUD_PRIMARY_AMMO_MAGAZINES_UNITS, + MARINE_HUD_PRIMARY_AMMO_MAGAZINES_TENS, + + MARINE_HUD_SECONDARY_AMMO_ROUNDS_UNITS, + MARINE_HUD_SECONDARY_AMMO_ROUNDS_TENS, + MARINE_HUD_SECONDARY_AMMO_ROUNDS_HUNDREDS, + + MARINE_HUD_SECONDARY_AMMO_MAGAZINES_UNITS, + MARINE_HUD_SECONDARY_AMMO_MAGAZINES_TENS, + + MAX_NO_OF_MARINE_HUD_DIGITS +}; +/*KJL*********************************************** +* Numerical digits which occur in the predator HUD * +***********************************************KJL*/ +enum PREDATOR_HUD_DIGIT +{ + PREDATOR_HUD_ARMOUR_1, + PREDATOR_HUD_ARMOUR_2, + PREDATOR_HUD_ARMOUR_3, + PREDATOR_HUD_ARMOUR_4, + PREDATOR_HUD_ARMOUR_5, + + PREDATOR_HUD_HEALTH_1, + PREDATOR_HUD_HEALTH_2, + PREDATOR_HUD_HEALTH_3, + PREDATOR_HUD_HEALTH_4, + PREDATOR_HUD_HEALTH_5, + + /* + PREDATOR_HUD_THREATDISPLAY_1, + PREDATOR_HUD_THREATDISPLAY_2, + PREDATOR_HUD_THREATDISPLAY_3, + PREDATOR_HUD_THREATDISPLAY_4, + PREDATOR_HUD_THREATDISPLAY_5, + PREDATOR_HUD_THREATDISPLAY_6, + PREDATOR_HUD_THREATDISPLAY_7, + PREDATOR_HUD_THREATDISPLAY_8, + */ + MAX_NO_OF_PREDATOR_HUD_DIGITS +}; + +enum ALIEN_HUD_DIGIT +{ + ALIEN_HUD_HEALTH_UNITS, + ALIEN_HUD_HEALTH_TENS, + ALIEN_HUD_HEALTH_HUNDREDS, + + MAX_NO_OF_ALIEN_HUD_DIGITS +}; + +extern char ValueOfHUDDigit[]; + +enum GUNSIGHT_SHAPE +{ + GUNSIGHT_CROSSHAIR=0, + GUNSIGHT_GREENBOX, + GUNSIGHT_REDBOX, + GUNSIGHT_REDDIAMOND, + + MAX_NO_OF_GUNSIGHT_SHAPES +}; + +enum COMMON_HUD_DIGIT_ID +{ + COMMON_HUD_DIGIT_HEALTH_UNITS, + COMMON_HUD_DIGIT_HEALTH_TENS, + COMMON_HUD_DIGIT_HEALTH_HUNDREDS, + + COMMON_HUD_DIGIT_ARMOUR_UNITS, + COMMON_HUD_DIGIT_ARMOUR_TENS, + COMMON_HUD_DIGIT_ARMOUR_HUNDREDS, + + MAX_NO_OF_COMMON_HUD_DIGITS +}; + +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ +extern void PlatformSpecificInitMarineHUD(void); +/*KJL**************************************************************************************** +* Okay. From now on everyone will call the fn above which loads and initialises ALL the gfx * +* required for a marine, eg. weapons, motion tracker stuff, gun sights, et al. * +* And sets up the riff mode RWH +****************************************************************************************KJL*/ +extern void PlatformSpecificInitPredatorHUD(void); +/*KJL****************** +* Ditto for predator. * +******************KJL*/ +extern void PlatformSpecificInitAlienHUD(void); +/*RWH***************** +* Ditto for alien. * +******************REH*/ +extern void PlatformSpecificExitingHUD(void); +/*KJL****************************************************************************************** +* This is for the PSX (& possibly Saturn). Use this to pass your list of graphics to be drawn * +* to your GPU. * +******************************************************************************************KJL*/ + +extern void PlatformSpecificEnteringHUD(void); +/*KJL************************************************** +* Made to complement PlatformSpecificExitingHUD() fn. * +**************************************************KJL*/ + +extern void BLTMotionTrackerToHUD(int scanLineSize); +/*KJL****************************************************************************************** +* draw motion tracker with its expanding scanline * +* 0 <= scanLineSize <= 65536 and denotes the scanline's on-screen radius (65536 = full size). * +******************************************************************************************KJL*/ + +extern void BLTMotionTrackerBlipToHUD(int x, int y, int brightness); +/*KJL******************************************************************** +* -65536 <= x <= 65536, 0 <= y <= 65536, 0 <= brightness <= 65536 * +* (x=0,y=0) refers to the motiontracker's centre. (ie. centre hotspot) * +* brightness=65536 means brightest blip, 0 means darkest blip * +********************************************************************KJL*/ + +extern void BLTMarineNumericsToHUD(enum MARINE_HUD_DIGIT digitsToDraw); +extern void BLTPredatorNumericsToHUD(void); +extern void BLTAlienNumericsToHUD(void); +/*KJL******************************************************************** +* Draws ALL the numeric digits (pertinent to the Marine) to the HUD. * +* * +* Ok, here's a quick explanation of how it's supposed to work: * +* * +* In hud.c there is a global array of chars called ValueOfHUDDigit[]. * +* The index of the array takes a value from the MARINE_HUD_DIGIT enum * +* which occurs later in this file, and each char in the array holds a * +* single digit, ie. a value from 0 to 9 inclusive. For example, * +* ValueOfHUDDigit[MARINE_HUD_HEALTH_TENS] holds the 'tens' digit of the * +* players health, say 5 if the players health was 152. So, the function * +* BLTMarineNumericsToHUD() simply goes through the array blitting each * +* digit to its correct position on screen. I do this by having another * +* array which holds the X,Y coords and font number for each digit, and * +* implementing a fn which takes the parameters (digit value,x,y,font) * +* and does the actual blitting. This is in avp/win95/ddplat.cpp. * +********************************************************************KJL*/ + +extern void BLTGunSightToScreen(int screenX, int screenY, enum GUNSIGHT_SHAPE gunsightShape); +/*KJL**************************************************************** +* screenX & screenY are in pixels (scaled to SDB so should be okay) * +* (centre hotspot) * +* gunsightShape determines which sight to blit to screen. * +****************************************************************KJL*/ + + +extern void InitHUD(void); + +extern void BLTAlienOverlayToHUD(void); +/*KJL************************** +* Draw simple graphic overlay * +**************************KJL*/ + +extern void BLTPredatorOverlayToHUD(void); +/*KJL************************** +* Draw simple graphic overlay * +**************************KJL*/ + + +extern void KillHUD(void); +/*KJL********************* +* Free memory of HUD gfx * +*********************KJL*/ + + + +/* KJL 11:00:22 05/20/97 - On-screen messaging system */ +#define ON_SCREEN_MESSAGE_LIFETIME (ONE_FIXED*2) + +extern void NewOnScreenMessage(unsigned char *messagePtr); +/*KJL******************************************************************** +* The text pointed to by the messagePtr will be displayed on screen for * +* the time defined in ON_SCREEN_MESSAGE_LIFETIME. Any previous message * +* still being displayed will be overwritten. * +********************************************************************KJL*/ + +extern void DrawOnScreenMessage(unsigned char *messagePtr); +/*KJL********************************************************************* +* This is a platform specific fn which draws the required message to the * +* screen. Implemented in ddplat.cpp on the PC. * +*********************************************************************KJL*/ + + #ifdef __cplusplus + }; /* end of C-Linkage spec */ + #endif + +#endif /* one-time only guard */ \ No newline at end of file diff --git a/3dc/avp/HUD_MAP.C b/3dc/avp/HUD_MAP.C new file mode 100644 index 0000000..01a10e1 --- /dev/null +++ b/3dc/avp/HUD_MAP.C @@ -0,0 +1,762 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "dynblock.h" +#include "dynamics.h" +#include "hud_map.h" +#include "gamedef.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +#define PENTIUM_PROFILING_ON 0 +#if PENTIUM_PROFILING_ON +#include "pentime.h" +#else +#define ProfileStart(); +#define ProfileStop(x); +#endif + + +#define CircleRadius 99 +#define DEFAULT_MAP_SCALE 400 +#define DEFAULT_MAP_RADIUS 80 + +#define MAP_MAX_ZOOM 2000 + +#if PSX + #define MAP_MIN_ZOOM 200 +#else + #define MAP_MIN_ZOOM 100 +#endif + +extern int sine[], cosine[]; /*Needed for GetSin and GetCos */ + +static void UpdateMapVisibilities(void); +static void DrawMapOverlay(void); +static void DrawPlayerArrow(void); +static int MapModuleCompletelyClipped(MODULE *modulePtr); +static void DrawMapModule(MODULE *modulePtr, enum MAP_COLOUR_ID colourID); + +#if !PSX +static int ClipLine(VECTOR2D vertex[]); +static void MakeCircleLookUpTable(void); +static int PointInsideCircle(int x, int y); +#endif + +static int IsHUDMapOn = 0; + +extern int SetupPolygonAccessFromShapeIndex(int shapeIndex); +extern void RotateVertex(VECTOR2D *vertexPtr, int theta); + +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; +extern DISPLAYBLOCK *Player; +extern int NormalFrameTime; + +static int MapScale = DEFAULT_MAP_SCALE; +static int MapRadius = DEFAULT_MAP_RADIUS; +static int ClipScale; +static int MapCentreX; +static int MapCentreY; + +static int MapMinX,MapMaxX; +static int MapMinY,MapMaxY; + +/* point in the environment which is the centre of the map */ +static VECTORCH MapWorldCentre; +static int MapOrientation; + +void InitHUDMap(void) +{ + #if !PSX + MakeCircleLookUpTable(); + #endif + + PlatformSpecificInitHUDMap(); + + #if PSX + + MapCentreX = 128; + MapCentreY = 64; + + #else + + if (AvP.PlayerType == I_Alien) + { + MapCentreX = ScreenDescriptorBlock.SDB_Width-MapRadius*2; + MapCentreY = ScreenDescriptorBlock.SDB_Height-MapRadius*2; + } + else if (AvP.PlayerType == I_Predator) + { + MapCentreX = ScreenDescriptorBlock.SDB_Width-MapRadius; + MapCentreY = ScreenDescriptorBlock.SDB_Height/2-MapRadius; + } + else + { + MapCentreX = ScreenDescriptorBlock.SDB_Width-MapRadius; + MapCentreY = ScreenDescriptorBlock.SDB_Height-MapRadius; + } + + #endif + +} + +void UpdateHUDMap(void) +{ + /* update which modules are visible on the map */ + UpdateMapVisibilities(); + + /* draw current map to screen */ + ProfileStart(); + if (IsHUDMapOn) DrawMapOverlay(); + ProfileStop("MAP"); +} + +void HUDMapOn(void) +{ + IsHUDMapOn=1; +} + +void HUDMapOff(void) +{ + IsHUDMapOn=0; +} + +void HUDMapZoomOut(void) +{ + MapScale-= (NormalFrameTime * MapScale) >> 17; + if (MapScale> 17; + if (MapScale>MAP_MAX_ZOOM) MapScale=MAP_MAX_ZOOM; +} + +void HUDMapSmaller(void) +{ + MapRadius-= NormalFrameTime>>10; + if (MapRadius<50) MapRadius=50; +} + +void HUDMapLarger(void) +{ + MapRadius+= NormalFrameTime>>10; + if (MapRadius>ScreenDescriptorBlock.SDB_Height/2) + MapRadius=ScreenDescriptorBlock.SDB_Height/2; + + /* check it fits on screen... */ + { + int allowedX = ScreenDescriptorBlock.SDB_Width - MapRadius; + + if (MapCentreX>allowedX) + MapCentreX=allowedX; + else if (MapCentreXallowedY) + MapCentreY=allowedY; + else if (MapCentreY>9; + + if (MapCentreX>9; + + if (MapCentreX>allowedX) + MapCentreX=allowedX; +} +void HUDMapUp(void) +{ + MapCentreY -= NormalFrameTime>>9; + + if (MapCentreY>9; + + if (MapCentreY>allowedY) + MapCentreY=allowedY; +} + +void HUDMapWorldCentreLeft(void) +{ + int mult = ((2000-MapScale) << 10)/500 + (1 << 10); + MapWorldCentre.vx -= (NormalFrameTime * mult) >> 19; + + HUDMapClamp(); +} +void HUDMapWorldCentreRight(void) +{ + int mult = ((2000-MapScale) << 10)/500 + (1 << 10); + MapWorldCentre.vx += (NormalFrameTime * mult) >> 19; + + HUDMapClamp(); +} +void HUDMapWorldCentreUp(void) +{ + int mult = ((2000-MapScale) << 10)/500 + (1 << 10); + MapWorldCentre.vy -= (NormalFrameTime * mult) >> 19; + + HUDMapClamp(); +} +void HUDMapWorldCentreDown(void) +{ + int mult = ((2000-MapScale) << 10)/500 + (1 << 10); + MapWorldCentre.vy += (NormalFrameTime * mult) >> 19; + + HUDMapClamp(); +} + +void HUDMapRotateRight(void) +{ + MapOrientation += NormalFrameTime>>6; + if (MapOrientation>4095) MapOrientation -= 4096; +} + +void HUDMapRotateLeft(void) +{ + MapOrientation -= NormalFrameTime>>6; + if (MapOrientation<0) MapOrientation += 4096; +} + +void HUDMapWorldForward(void) +{ + int mult = ((2000-MapScale) << 6)/500 + (1 << 6); + + MapWorldCentre.vx += (GetSin(MapOrientation) * mult) >> 16; + MapWorldCentre.vz += (GetCos(MapOrientation) * mult) >> 16; + + HUDMapClamp(); + +} + +void HUDMapWorldBackward(void) +{ + int mult = ((2000-MapScale) << 6)/500 + (1 << 6); + + MapWorldCentre.vx -= (GetSin(MapOrientation) * mult) >> 16; + MapWorldCentre.vz -= (GetCos(MapOrientation) * mult) >> 16; + + HUDMapClamp(); +} + +void HUDMapWorldSlideLeft(void) +{ + int mult = ((2000-MapScale) >> 2) + (1 << 6); + + MapWorldCentre.vx -= (GetCos(MapOrientation) * mult) >> 16; + MapWorldCentre.vz += (GetSin(MapOrientation) * mult) >> 16; + + HUDMapClamp(); +} + +void HUDMapWorldSlideRight(void) +{ + int mult = ((2000-MapScale) >> 2) + (1 << 6); + + MapWorldCentre.vx += (GetCos(MapOrientation) * mult) >> 16; + MapWorldCentre.vz -= (GetSin(MapOrientation) * mult) >> 16; + + HUDMapClamp(); +} + +void HUDMapClamp() +{ + if (MapWorldCentre.vx < MapMinX) MapWorldCentre.vx = MapMinX; + else if (MapWorldCentre.vx > MapMaxX) MapWorldCentre.vx = MapMaxX; + if (MapWorldCentre.vz < MapMinY) MapWorldCentre.vz = MapMinY; + else if (MapWorldCentre.vz > MapMaxY) MapWorldCentre.vz = MapMaxY; +} + +void HUDMapResetDefaults(void) +{ + MapWorldCentre = Player->ObWorld; + MapOrientation = Player->ObEuler.EulerY; + + MapScale = DEFAULT_MAP_SCALE; + MapRadius = DEFAULT_MAP_RADIUS; + + MapMaxX = Player->ObWorld.vx; + MapMinX = MapMaxX; + MapMaxY = Player->ObWorld.vz; + MapMinY = MapMaxY; +} + +static void UpdateMapVisibilities(void) +{ + extern int NumOnScreenBlocks; + extern DISPLAYBLOCK *OnScreenBlockList[]; + + int numberOfObjects = NumOnScreenBlocks; + + while (numberOfObjects--) + { + DISPLAYBLOCK *objectPtr = OnScreenBlockList[numberOfObjects]; + MODULE *modulePtr = objectPtr->ObMyModule; + + if (modulePtr) /* Is object a module ? */ + { + /* If module is not yet visible, flag it so that it is. */ + if (!(modulePtr->m_flags & m_flag_visible_on_map)) + modulePtr->m_flags |= m_flag_visible_on_map; + } + } +} + +static void DrawMapOverlay(void) +{ + extern SCENE Global_Scene; + extern int ModuleArraySize; + MODULE **moduleList; + + int i; + + PlatformSpecificEnteringHUDMap(); + moduleList = MainSceneArray[Global_Scene]->sm_marray; + ClipScale = (MapScale*CircleRadius)/MapRadius; + + #if !PSX + MapWorldCentre = Player->ObWorld; + MapOrientation = Player->ObEuler.EulerY; + #endif + + for(i = 0; i < ModuleArraySize; i++) + { + MODULE *modulePtr = moduleList[i]; + + if (modulePtr) + { + if (modulePtr->m_flags & m_flag_visible_on_map) + { + int yCoord = MapWorldCentre.vy-modulePtr->m_world.vy; + if (!MapModuleCompletelyClipped(modulePtr)) + { + if ((modulePtr->m_maxy < yCoord)||(modulePtr->m_miny > yCoord)) + { + DrawMapModule(modulePtr,MAP_COLOUR_GREY); + } + else + { + DrawMapModule(modulePtr,MAP_COLOUR_WHITE); + } + } + } + } + } + + DrawPlayerArrow(); + + PlatformSpecificExitingHUDMap(); + return; + +} + +static int MapModuleCompletelyClipped(MODULE *modulePtr) +{ + VECTOR2D offset; + + /* calculate offset to map space */ + offset.vx = modulePtr->m_world.vx-MapWorldCentre.vx; + offset.vy = modulePtr->m_world.vz-MapWorldCentre.vz; + + /* test simple bounding boxes */ + { + int maxX = MUL_FIXED(modulePtr->m_maxx + offset.vx,ClipScale); + if (maxX >= -CircleRadius) + { + int minX = MUL_FIXED(modulePtr->m_minx + offset.vx,ClipScale); + if (minX <= CircleRadius) + return 0; + } + } + { + int maxY = MUL_FIXED(modulePtr->m_maxy + offset.vy,ClipScale); + if (maxY >= -CircleRadius) + { + int minY = MUL_FIXED(modulePtr->m_miny + offset.vy,ClipScale); + if (minY <= CircleRadius) + return 0; + } + } + + + return 1; +} + +static void DrawMapModule(MODULE *modulePtr, enum MAP_COLOUR_ID colourID) +{ + MODULEMAPBLOCK *mapPtr = modulePtr->m_mapptr; + int numberOfItems; + VECTOR2D offset; + + offset.vx = mapPtr->MapWorld.vx; + offset.vy = mapPtr->MapWorld.vz; + /* okay, let's setup the shape's data and access the first poly */ + if (modulePtr->m_dptr) + { + numberOfItems = SetupPolygonAccess(modulePtr->m_dptr); + } + else if (mapPtr->MapMorphHeader) + { + numberOfItems = SetupPolygonAccessFromShapeIndex(mapPtr->MapMorphHeader->mph_frames->mf_shape2); + } + else + { + numberOfItems = SetupPolygonAccessFromShapeIndex(mapPtr->MapShape); + } + /* go through polys looking for those which intersect with the bounding box */ + while(numberOfItems) + { + struct ColPolyTag polyPtr; + AccessNextPolygon(); + + GetPolygonNormal(&polyPtr); + if (polyPtr.PolyNormal.vy>-20000 && polyPtr.PolyNormal.vy<20000) + { + VECTOR2D vertex[6]; + GetPolygonVertices(&polyPtr); + + { + int highestVertex=0; + int nextHighestVertex=0; + int highestY=0x7fffffff; + int nextHighestY=0x7fffffff; + + int v; + + v = polyPtr.NumberOfVertices; + do + { + v--; + if (polyPtr.PolyPoint[v].vy MapMaxX) MapMaxX = vertex[0].vx; + else if (vertex[0].vx < MapMinX) MapMinX = vertex[0].vx; + + if (vertex[0].vy > MapMaxY) MapMaxY = vertex[0].vy; + else if (vertex[0].vy < MapMinY) MapMinY = vertex[0].vy; + + if (vertex[1].vx > MapMaxX) MapMaxX = vertex[1].vx; + else if (vertex[1].vx < MapMinX) MapMinX = vertex[1].vx; + + if (vertex[1].vy > MapMaxY) MapMaxY = vertex[1].vy; + else if (vertex[1].vy < MapMinY) MapMinY = vertex[1].vy; + + vertex[0].vx -= MapWorldCentre.vx; + vertex[0].vy -= MapWorldCentre.vz; + + vertex[1].vx -= MapWorldCentre.vx; + vertex[1].vy -= MapWorldCentre.vz; + + } + + #if PSX + + // PSX has HUD map lines clipped to screen coordinates in DrawHUDMapLine + + RotateVertex(&vertex[0],MapOrientation); + vertex[0].vx = MUL_FIXED(vertex[0].vx,MapScale); + vertex[0].vy = MUL_FIXED(vertex[0].vy,MapScale); + vertex[0].vx = MapCentreX + vertex[0].vx; + vertex[0].vy = MapCentreY - vertex[0].vy; + + RotateVertex(&vertex[1],MapOrientation); + vertex[1].vx = MUL_FIXED(vertex[1].vx,MapScale); + vertex[1].vy = MUL_FIXED(vertex[1].vy,MapScale); + vertex[1].vx = MapCentreX + vertex[1].vx; + vertex[1].vy = MapCentreY - vertex[1].vy; + + DrawHUDMapLine(&vertex[0],&vertex[1],colourID); + + #else + + if (ClipLine(vertex)) + { + RotateVertex(&vertex[0],Player->ObEuler.EulerY); + vertex[0].vx = MUL_FIXED(vertex[0].vx,MapScale); + vertex[0].vy = MUL_FIXED(vertex[0].vy,MapScale); + vertex[0].vx = MapCentreX + vertex[0].vx; + vertex[0].vy = MapCentreY - vertex[0].vy; + + RotateVertex(&vertex[1],Player->ObEuler.EulerY); + vertex[1].vx = MUL_FIXED(vertex[1].vx,MapScale); + vertex[1].vy = MUL_FIXED(vertex[1].vy,MapScale); + vertex[1].vx = MapCentreX + vertex[1].vx; + vertex[1].vy = MapCentreY - vertex[1].vy; + + DrawHUDMapLine(&vertex[0],&vertex[1],colourID); + } + + #endif + + } + + numberOfItems--; + } +} + +static void DrawPlayerArrow(void) +{ + VECTOR2D vertex1,vertex2; + int arrowLength; + + #if PSX + VECTOR2D vertex3; + + arrowLength = 475; + + vertex1.vx = 0; + vertex1.vy = arrowLength; + RotateVertex(&vertex1,4096-Player->ObEuler.EulerY); + vertex1.vx += Player->ObWorld.vx - MapWorldCentre.vx; + vertex1.vy += Player->ObWorld.vz - MapWorldCentre.vz; + RotateVertex(&vertex1,MapOrientation); + vertex1.vx = MUL_FIXED(vertex1.vx,MapScale); + vertex1.vy = MUL_FIXED(vertex1.vy,MapScale); + vertex1.vx = MapCentreX + vertex1.vx; + vertex1.vy = MapCentreY - vertex1.vy; + + vertex3.vx = vertex1.vx; + vertex3.vy = vertex1.vy; + + vertex2.vx = 0; + vertex2.vy = -arrowLength; + RotateVertex(&vertex2,4096-Player->ObEuler.EulerY); + vertex2.vx += Player->ObWorld.vx - MapWorldCentre.vx; + vertex2.vy += Player->ObWorld.vz - MapWorldCentre.vz; + RotateVertex(&vertex2,MapOrientation); + vertex2.vx = MUL_FIXED(vertex2.vx,MapScale); + vertex2.vy = MUL_FIXED(vertex2.vy,MapScale); + vertex2.vx = MapCentreX + vertex2.vx; + vertex2.vy = MapCentreY - vertex2.vy; + + DrawHUDMapLine(&vertex1,&vertex2,MAP_COLOUR_RED); + + vertex2.vx = -arrowLength; + vertex2.vy = 0; + RotateVertex(&vertex2,4096-Player->ObEuler.EulerY); + vertex2.vx += Player->ObWorld.vx - MapWorldCentre.vx; + vertex2.vy += Player->ObWorld.vz - MapWorldCentre.vz; + RotateVertex(&vertex2,MapOrientation); + vertex2.vx = MUL_FIXED(vertex2.vx,MapScale); + vertex2.vy = MUL_FIXED(vertex2.vy,MapScale); + vertex2.vx = MapCentreX + vertex2.vx; + vertex2.vy = MapCentreY - vertex2.vy; + + vertex1.vx = vertex3.vx; + vertex1.vy = vertex3.vy; + + DrawHUDMapLine(&vertex1,&vertex2,MAP_COLOUR_RED); + + vertex2.vx = arrowLength; + vertex2.vy = 0; + RotateVertex(&vertex2,4096-Player->ObEuler.EulerY); + vertex2.vx += Player->ObWorld.vx - MapWorldCentre.vx; + vertex2.vy += Player->ObWorld.vz - MapWorldCentre.vz; + RotateVertex(&vertex2,MapOrientation); + vertex2.vx = MUL_FIXED(vertex2.vx,MapScale); + vertex2.vy = MUL_FIXED(vertex2.vy,MapScale); + vertex2.vx = MapCentreX + vertex2.vx; + vertex2.vy = MapCentreY - vertex2.vy; + + vertex1.vx = vertex3.vx; + vertex1.vy = vertex3.vy; + + DrawHUDMapLine(&vertex1,&vertex2,MAP_COLOUR_RED); + + vertex1.vx = MapCentreX; + vertex1.vy = MapCentreY; + + vertex2.vx = MapCentreX; + vertex2.vy = MapCentreY; + + DrawHUDMapLine (&vertex1,&vertex2,MAP_COLOUR_RED); + + #else + + arrowLength = MUL_FIXED(300,MapScale); + + vertex1.vx = MapCentreX; + vertex1.vy = MapCentreY - arrowLength; + + vertex2.vx = MapCentreX; + vertex2.vy = MapCentreY + arrowLength; + + DrawHUDMapLine(&vertex1,&vertex2,MAP_COLOUR_RED); + + vertex2.vx = MapCentreX - arrowLength; + vertex2.vy = MapCentreY; + + DrawHUDMapLine(&vertex1,&vertex2,MAP_COLOUR_RED); + + vertex2.vx = MapCentreX + arrowLength; + DrawHUDMapLine(&vertex1,&vertex2,MAP_COLOUR_RED); + + #endif +} + +#if !PSX +static int ClipLine(VECTOR2D vertex[]) +{ + int vertex0Inside=0,vertex1Inside=0; + + if (PointInsideCircle(vertex[0].vx,vertex[0].vy)) + vertex0Inside = 1; + if (PointInsideCircle(vertex[1].vx,vertex[1].vy)) + vertex1Inside = 1; + + /* line completely in */ + if (vertex0Inside && vertex1Inside) + return 1; + + /* line completely out */ + if (!vertex0Inside && !vertex1Inside) + return 0; + + /* crosses clipping boundary */ + { + VECTOR2D minBound,maxBound; + VECTOR2D newGuess; + int searchCounter = 10; + + if (vertex0Inside) + { + minBound = vertex[0]; + maxBound = vertex[1]; + } + else + { + minBound = vertex[1]; + maxBound = vertex[0]; + } + + do + { + int pointInside; + newGuess.vx = (minBound.vx + maxBound.vx)/2; + newGuess.vy = (minBound.vy + maxBound.vy)/2; + + pointInside = PointInsideCircle(newGuess.vx,newGuess.vy); + + if(pointInside == 0) + { + maxBound = newGuess; + } + else if (pointInside == -1) + { + minBound = newGuess; + } + else break; + } + while(searchCounter--); + + if (vertex0Inside) + { + vertex[1] = newGuess; + } + else + { + vertex[0] = newGuess; + } + } + return 1; +} + +static char CircleXCoord[CircleRadius+1]; + +static void MakeCircleLookUpTable(void) +{ + int y=CircleRadius; + extern unsigned char *ScreenBuffer; + do + { + CircleXCoord[y] = SqRoot32(CircleRadius*CircleRadius-y*y); + } + while(y--); +} + +static int PointInsideCircle(int x, int y) +{ + if (y<0) y=-y; + y = MUL_FIXED(y,ClipScale); + + if (y>CircleRadius) return 0; + + if (x<0) x=-x; + x = MUL_FIXED(x,ClipScale); + + if (CircleXCoord[y]>x) return -1; + if (CircleXCoord[y]ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + +// RenderSmokeTest(); + PlatformSpecificEnteringHUD(); + + if (ScanDrawMode != ScanDrawDirectDraw) + { + HandleParticleSystem(); + } + RenderGrapplingHook(); + + #if SOFTWARE_RENDERER + FlushSoftwareZBuffer(); + #else + SecondFlushD3DZBuffer(); + #endif + //DrawFontTest(); + if (Observer) + { + switch(AvP.PlayerType) + { + case I_Marine: + { + HandleMarineOVision(); + break; + } + case I_Predator: + { + HandlePredOVision(); + break; + } + case I_Alien: + { + HandleAlienOVision(); + break; + } + default: + break; + } + CheckWireFrameMode(0); + #if 1||!PREDATOR_DEMO + GADGET_Render(); + #endif + return; + } + +// GlobalAmbience=16384; + + /* KJL 18:46:04 03/10/97 - for now I've completely turned off the HUD if you die; this + can easily be changed */ + #if DRAW_HUD + if (playerStatusPtr->MyFaceHugger!=NULL) + { + /* YUCK! */ + extern void PlotFaceHugger(STRATEGYBLOCK *sbPtr); + PlotFaceHugger(playerStatusPtr->MyFaceHugger); + + } + else if (playerStatusPtr->IsAlive) + { + /* switch on player type */ + switch(AvP.PlayerType) + { + case I_Marine: + { + HandleMarineWeapon(); +// UpdateHUDMap(); + if (CurrentVisionMode==VISION_MODE_NORMAL) DoMotionTracker(); +// UpdateMarineStatusValues(); + CheckWireFrameMode(0); + //flash health if invulnerable + if((playerStatusPtr->invulnerabilityTimer/12000 %2)==0) + { + DisplayHealthAndArmour(); + } + DisplayMarinesAmmo(); + DrawMarineSights(); + + /* Paranoia check. */ + if(predHUDSoundHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(predHUDSoundHandle); + } + break; + } + case I_Predator: + { + HandlePredatorWeapon(); + CheckWireFrameMode(0); + //DrawPredatorEnergyBar(); + //DisplayHealthAndArmour(); + DrawWristDisplay(); + + HandlePredOVision(); + if (DrawScanlineOverlay) DrawScanlinesOverlay(ScanlineLevel); + + DrawPredatorSights(); + //flash health if invulnerable + if((playerStatusPtr->invulnerabilityTimer/12000 %2)==0) + { + DisplayPredatorHealthAndEnergy(); + } + + break; + } + case I_Alien: + { + DrawAlienTeeth(); + if (AlienTongueOffset) + { + RenderInsideAlienTongue(AlienTongueOffset); + AlienTongueOffset-=NormalFrameTime; + if (AlienTongueOffset<0) + AlienTongueOffset = 0; + } + SetFrustrumType(FRUSTRUM_TYPE_NORMAL); + Global_VDB_Ptr->VDB_ProjX = (Global_VDB_Ptr->VDB_ClipRight - Global_VDB_Ptr->VDB_ClipLeft)/2; + Global_VDB_Ptr->VDB_ProjY = (Global_VDB_Ptr->VDB_ClipDown - Global_VDB_Ptr->VDB_ClipUp)/2; + + HandleAlienWeapon(); + HandleAlienOVision(); + + SetFrustrumType(FRUSTRUM_TYPE_WIDE); + Global_VDB_Ptr->VDB_ProjX = (Global_VDB_Ptr->VDB_ClipRight - Global_VDB_Ptr->VDB_ClipLeft)/4; + Global_VDB_Ptr->VDB_ProjY = (Global_VDB_Ptr->VDB_ClipDown - Global_VDB_Ptr->VDB_ClipUp)/4; + + CheckWireFrameMode(0); + + //flash health if invulnerable + if((playerStatusPtr->invulnerabilityTimer/12000 %2)==0) + { + DisplayHealthAndArmour(); + } + /* Paranoia check. */ + if(predHUDSoundHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(predHUDSoundHandle); + } + break; + } + default: + LOCALASSERT(1==0); + break; + } + } + else // player is dead! + { + switch(AvP.PlayerType) + { + case I_Marine: + { + break; + } + case I_Predator: + { + HandlePredOVision(); + break; + } + case I_Alien: + { + HandleAlienOVision(); + break; + } + default: + break; + } + } + + #endif + + CheckWireFrameMode(0); + + { + extern int HeadUpDisplayZOffset; + HeadUpDisplayZOffset = 0; + + #if 1||!PREDATOR_DEMO + GADGET_Render(); + #endif + + switch(AvP.PlayerType) + { + case I_Marine: + { + HandleMarineOVision(); + break; + } + case I_Predator: + { + // HandlePredOVision(); + break; + } + default: + break; + } + + } + { + extern int AlienBiteAttackInProgress; + if (AlienBiteAttackInProgress) + { + extern void D3D_FadeDownScreen(int brightness, int colour); + int b; + if (CameraZoomScale!=0.25f) + { + f2i(b,CameraZoomScale*65536.0f); + if (b<32768) b=32768; + D3D_FadeDownScreen(b,0xff0000); + } + } + } + // burn baby burn? + if (Player->ObStrategyBlock->SBDamageBlock.IsOnFire) + { + D3D_PlayerOnFireOverlay(); + } + else + { + + extern int PlayerDamagedOverlayIntensity; + int intensity = PlayerDamagedOverlayIntensity>>12; +// if (intensity>255) intensity = 255; + if (intensity>128) intensity = 128; + + if (intensity) + { + D3D_PlayerDamagedOverlay(intensity); + } + + PlayerDamagedOverlayIntensity -= NormalFrameTime<<5; + if (PlayerDamagedOverlayIntensity<0) PlayerDamagedOverlayIntensity=0; + } + { + #if 0 + if(DrawCompanyLogos && LogosAlphaLevel) + { + extern void D3D_DrawRebellionLogo(unsigned int alpha); + + if (LogosAlphaLevelIsAlive) + { + if (AvP.Network==I_No_Network) + { + DoFailedLevelStatisticsScreen(); + } + else + { + // place multiplayer stuff here - e.g. full scores/frags et al + } + } + if(AvP.Network != I_No_Network) + { + DoMultiplayerSpecificHud(); + } +} + +extern void DoCompletedLevelStatisticsScreen(void) +{ + extern int DebouncedGotAnyKey; + extern unsigned char DebouncedKeyboardInput[]; + if (DebouncedKeyboardInput[KEY_ESCAPE]) + { + AvP.RestartLevel = 1; + } + else if (DebouncedGotAnyKey) + { + AvP.MainLoopRunning = 0; + } + D3D_FadeDownScreen(0,0); + DoStatisticsScreen(1); + RenderStringCentred(GetTextString(TEXTSTRING_COMPLETEDLEVEL_PRESSAKEY),ScreenDescriptorBlock.SDB_Width/2,ScreenDescriptorBlock.SDB_Height-20,0xffffffff); +} + + +/* This function scans through the active block list looking for dynamic objects + which are detectable by the Motion Tracker. +*/ +static void DoMotionTracker(void) +{ + static char distanceNotLocked=1; + static int distance=0; + + /* draw static motion tracker background, and the moving scanline */ + BLTMotionTrackerToHUD(MTScanLineSize); + + if(distanceNotLocked) /* if MT hasn't found any contacts this scan */ + { + int nearestDistance=DoMotionTrackerBlips(); + + if (nearestDistance=0); + panicFactor>>=8; // Scale to 0-256 + + PlatChangeSoundPitch(MTSoundHandle,panicFactor); + + } + #endif + + } + else if (NoOfMTBlips==0) /* if the MT is blank, cycle the distance digits */ + { + distance= MUL_FIXED(MTScanLineSize,MOTIONTRACKER_RANGE); + } + } + else DoMotionTrackerBlips(); + + /* evaluate the distance digits */ + { + int value=distance/10; + ValueOfHUDDigit[MARINE_HUD_MOTIONTRACKER_UNITS]=value%10; + + value/=10; + ValueOfHUDDigit[MARINE_HUD_MOTIONTRACKER_TENS]=value%10; + + value/=10; + ValueOfHUDDigit[MARINE_HUD_MOTIONTRACKER_HUNDREDS]=value%10; + + value/=10; + ValueOfHUDDigit[MARINE_HUD_MOTIONTRACKER_THOUSANDS]=value%10; + } + + if (MTDelayBetweenScans) + { + MTDelayBetweenScans-=NormalFrameTime; + if (MTDelayBetweenScans<0) + { + MTDelayBetweenScans=0; + + Sound_Play(SID_TRACKER_CLICK,"v",MOTIONTRACKERVOLUME); + + PreviousMTScanLineSize =MTScanLineSize=MOTIONTRACKER_SMALLESTSCANLINESIZE; + distanceNotLocked=1; /* allow MT to look for a new nearest contact distance */ + } + } + else + { + /* expand scanline or wrap it around */ + PreviousMTScanLineSize=MTScanLineSize; + + if (MTScanLineSize>=65536) + { + MTDelayBetweenScans=65536; + MTScanLineSize=0; + } + else if (MTScanLineSize>32768) + { + MTScanLineSize+= MUL_FIXED(MOTIONTRACKER_SPEED*2,NormalFrameTime); + } + else + { + MTScanLineSize+= MUL_FIXED(MOTIONTRACKER_SPEED,NormalFrameTime); + } + + if (MTScanLineSize>65536) + { + MTScanLineSize=65536; + } + } + + /* draw blips to HUD */ + { + DYNAMICSBLOCK *playerDynPtr = Player->ObStrategyBlock->DynPtr; + int phi = playerDynPtr->OrientEuler.EulerY; + int cosPhi = MUL_FIXED(GetCos(phi),MOTIONTRACKER_SCALE); + int sinPhi = MUL_FIXED(GetSin(phi),MOTIONTRACKER_SCALE); + int i; + /* made more awkward because we want to draw the brightest last */ + i=0; + + while(iPosition.vz; + int x = MotionTrackerBlips[i].X-playerDynPtr->Position.vx; + int y2 = MUL_FIXED(x,sinPhi) + MUL_FIXED(y,cosPhi); + + if (y2>=0) + { + x = MUL_FIXED(x,cosPhi) - MUL_FIXED(y,sinPhi); + + if(Fast2dMagnitude(x,y2)DynPtr; + + /* KJL 12:45:54 21/08/98 - objects which will never appear on the MT */ + if((sbPtr->I_SBtype == I_BehaviourInanimateObject) + ||(sbPtr->I_SBtype == I_BehaviourRubberDuck)) { + return 0; + } + + if (sbPtr->SBflags.not_on_motiontracker) { + return(0); + } + + /* KJL 12:46:28 21/08/98 - objects which need more checks */ + if (sbPtr->I_SBtype == I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData; + + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + if((ghostData->type == I_BehaviourAlienPlayer) + &&(objectDynPtr->Position.vx == objectDynPtr->PrevPosition.vx) + &&(objectDynPtr->Position.vy == objectDynPtr->PrevPosition.vy) + &&(objectDynPtr->Position.vz == objectDynPtr->PrevPosition.vz)) + return 0; + } + else if (sbPtr->I_SBtype == I_BehaviourAlien) + { + ALIEN_STATUS_BLOCK * statusPtr = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr; + + if(statusPtr->BehaviourState == ABS_Dormant) + return 0; + } + else if (sbPtr->I_SBtype == I_BehaviourPlatform) + { + if((objectDynPtr->Position.vx == objectDynPtr->PrevPosition.vx) + &&(objectDynPtr->Position.vy == objectDynPtr->PrevPosition.vy) + &&(objectDynPtr->Position.vz == objectDynPtr->PrevPosition.vz)) + return 0; + } + else if (sbPtr->I_SBtype == I_BehaviourProximityDoor) + { + PROXDOOR_BEHAV_BLOCK *doorbhv; + doorbhv = (PROXDOOR_BEHAV_BLOCK*)sbPtr->SBdataptr; + if (doorbhv->door_state == I_door_open || doorbhv->door_state == I_door_closed) + { + return 0; + } + } + + return 1; +} +static int DoMotionTrackerBlips(void) +{ + DYNAMICSBLOCK *playerDynPtr = Player->ObStrategyBlock->DynPtr; + int numberOfObjects = NumActiveStBlocks; + int cosPhi, sinPhi; + int nearestDistance=MOTIONTRACKER_RANGE; + { + int phi = playerDynPtr->OrientEuler.EulerY; + cosPhi = MUL_FIXED(GetCos(phi),MOTIONTRACKER_SCALE); + sinPhi = MUL_FIXED(GetSin(phi),MOTIONTRACKER_SCALE); + } + + while (numberOfObjects--) + { + STRATEGYBLOCK *objectPtr = ActiveStBlockList[numberOfObjects]; + DYNAMICSBLOCK *objectDynPtr = objectPtr->DynPtr; + + if (NoOfMTBlips==MOTIONTRACKER_MAXBLIPS) break; + + if ((objectDynPtr)&&(!objectDynPtr->IsStatic || objectDynPtr->IsNetGhost) + &&(ObjectShouldAppearOnMotionTracker(objectPtr))) + { + /* 2d vector from player to object */ + int dx = objectDynPtr->Position.vx-playerDynPtr->Position.vx; + int dz = objectDynPtr->Position.vz-playerDynPtr->Position.vz; + + { + int absdx=dx; + int absdz=dz; + if (absdx<0) absdx=-absdx; + if (absdz<0) absdz=-absdz; + + /* ignore objects past MT's detection distance */ + /* do quick box check */ + if (absdx>MOTIONTRACKER_RANGE || absdz>MOTIONTRACKER_RANGE) continue; + } + + { + int y = MUL_FIXED(dx,sinPhi) + MUL_FIXED(dz,cosPhi); + + /* ignore objects 'behind' MT */ + if (y>=0) + { +// int x = MUL_FIXED(dx,cosPhi) - MUL_FIXED(dz,sinPhi); + int dist = Fast2dMagnitude(dx,dz); + int radius = MUL_FIXED(dist,MOTIONTRACKER_SCALE); + + if (radius<=MTScanLineSize) + { + int prevRadius; + { + int dx = objectDynPtr->PrevPosition.vx-playerDynPtr->PrevPosition.vx; + int dz = objectDynPtr->PrevPosition.vz-playerDynPtr->PrevPosition.vz; + prevRadius = MUL_FIXED(Fast2dMagnitude(dx,dz),MOTIONTRACKER_SCALE); + } + + if ((radius>PreviousMTScanLineSize) + ||(radiusPreviousMTScanLineSize)) + { + /* remember distance for possible display on HUD */ + if (nearestDistance>dist) nearestDistance=dist; + + /* create new blip */ + // MotionTrackerBlips[NoOfMTBlips].X = x; + // MotionTrackerBlips[NoOfMTBlips].Y = y; + MotionTrackerBlips[NoOfMTBlips].X = objectDynPtr->Position.vx; + MotionTrackerBlips[NoOfMTBlips].Y = objectDynPtr->Position.vz; + MotionTrackerBlips[NoOfMTBlips].Brightness = 65536; + NoOfMTBlips++; + } + } + } + } + } + } + return nearestDistance; +} + +static void DisplayHealthAndArmour(void) +{ +// extern void D3D_RenderHUDString(char *stringPtr,int x,int y,int colour); + int health,armour; + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + NPC_DATA *NpcData; + + switch (AvP.PlayerType) + { + case I_Marine: + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Marine_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Marine_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Marine_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Marine_Impossible); + break; + } + break; + case I_Alien: + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Alien_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Alien_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Alien_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Alien_Impossible); + break; + } + break; + default: + LOCALASSERT(0); + } + GLOBALASSERT(playerStatusPtr); + + health=(PlayerStatusPtr->Health*100)/NpcData->StartingStats.Health; + armour=(PlayerStatusPtr->Armour*100)/NpcData->StartingStats.Armour; + + health = (health+65535)>>16; + armour = (armour+65535)>>16; + + if(PlayerStatusPtr->Health<(NpcData->StartingStats.Health<<16)) + { + //make sure health isn't displayed as 100 , if it is even slightly below. + //(ie round down 99.5 , even though health is rounded up normally) + health = min(health,99); + } + if(PlayerStatusPtr->Armour<(NpcData->StartingStats.Armour<<16)) + { + //similarly for armour + armour = min(armour,99); + } + + Render_HealthAndArmour(health,armour); + +} + +static void DisplayMarinesAmmo(void) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + int primaryRounds, secondaryRounds; + + /* init a pointer to the weapon's data */ + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + primaryRounds=weaponPtr->PrimaryRoundsRemaining>>16; + if ( (weaponPtr->PrimaryRoundsRemaining&0xffff) ) primaryRounds+=1; + secondaryRounds=weaponPtr->SecondaryRoundsRemaining>>16; + if ( (weaponPtr->SecondaryRoundsRemaining&0xffff) ) secondaryRounds+=1; + + if (primaryRounds>HUD_PrimaryRounds) + { + HUD_PrimaryRounds += NormalFrameTime/512; + } + if (primaryRoundsHUD_SecondaryRounds) + { + HUD_SecondaryRounds += NormalFrameTime/512; + } + if (secondaryRoundsWeaponIDNumber == WEAPON_GRENADELAUNCHER) + { + ammo = GrenadeLauncherData.SelectedAmmo; + } + else + { + ammo = twPtr->PrimaryAmmoID; + } + Render_MarineAmmo + ( + TemplateAmmo[ammo].ShortName, + TEXTSTRING_MAGAZINES, + weaponPtr->PrimaryMagazinesRemaining, + TEXTSTRING_ROUNDS, + HUD_PrimaryRounds, + 1 + ); + } + if (weaponPtr->WeaponIDNumber == WEAPON_PULSERIFLE) + { + Render_MarineAmmo + ( + TemplateAmmo[twPtr->SecondaryAmmoID].ShortName, + TEXTSTRING_MAGAZINES, + weaponPtr->SecondaryMagazinesRemaining, + TEXTSTRING_ROUNDS, + HUD_SecondaryRounds, + 0 + ); + } + + if (weaponPtr->WeaponIDNumber == WEAPON_TWO_PISTOLS) + { + Render_MarineAmmo + ( + TemplateAmmo[twPtr->SecondaryAmmoID].ShortName, + TEXTSTRING_MAGAZINES, + weaponPtr->SecondaryMagazinesRemaining, + TEXTSTRING_ROUNDS, + HUD_SecondaryRounds, + 0 + ); + } + +} +#if 0 +static void UpdateMarineStatusValues(void) +{ + PLAYER_WEAPON_DATA *weaponPtr; + + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + { + /* player's current weapon */ + GLOBALASSERT(playerStatusPtr->SelectedWeaponSlotWeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + } + + + { + int value=playerStatusPtr->Health>>16; /* stored in 16.16 so shift down */ + ValueOfHUDDigit[MARINE_HUD_HEALTH_UNITS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_HEALTH_TENS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_HEALTH_HUNDREDS]=value%10; + } + { + #if PC_E3DEMO + int value=playerStatusPtr->Energy>>16; /* stored in 16.16 so shift down */ + #else + extern int FrameRate; + int value=FrameRate; + #endif + ValueOfHUDDigit[MARINE_HUD_ENERGY_UNITS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_ENERGY_TENS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_ENERGY_HUNDREDS]=value%10; + } + { + int value=playerStatusPtr->Armour>>16; /* stored in 16.16 so shift down */ + ValueOfHUDDigit[MARINE_HUD_ARMOUR_UNITS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_ARMOUR_TENS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_ARMOUR_HUNDREDS]=value%10; + } + + { + int value=weaponPtr->PrimaryRoundsRemaining>>16; + /* ammo is in 16.16. we want the integer part, rounded up */ + if ( (weaponPtr->PrimaryRoundsRemaining&0xffff) ) value+=1; + + ValueOfHUDDigit[MARINE_HUD_PRIMARY_AMMO_ROUNDS_UNITS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_PRIMARY_AMMO_ROUNDS_TENS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_PRIMARY_AMMO_ROUNDS_HUNDREDS]=value%10; + } + { + int value=weaponPtr->PrimaryMagazinesRemaining; + ValueOfHUDDigit[MARINE_HUD_PRIMARY_AMMO_MAGAZINES_UNITS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_PRIMARY_AMMO_MAGAZINES_TENS]=value%10; + } + + /* KJL 14:54:39 03/26/97 - secondary ammo */ + if ( (weaponPtr->WeaponIDNumber == WEAPON_PULSERIFLE) + ||(weaponPtr->WeaponIDNumber == WEAPON_MYSTERYGUN) ) + { + int value=weaponPtr->SecondaryRoundsRemaining>>16; + /* ammo is in 16.16. we want the integer part, rounded up */ + if ( (weaponPtr->SecondaryRoundsRemaining&0xffff) ) value+=1; + + ValueOfHUDDigit[MARINE_HUD_SECONDARY_AMMO_ROUNDS_UNITS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_SECONDARY_AMMO_ROUNDS_TENS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_SECONDARY_AMMO_ROUNDS_HUNDREDS]=value%10; + + value=weaponPtr->SecondaryMagazinesRemaining; + ValueOfHUDDigit[MARINE_HUD_SECONDARY_AMMO_MAGAZINES_UNITS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_SECONDARY_AMMO_MAGAZINES_TENS]=value%10; + + BLTMarineNumericsToHUD(MARINE_HUD_SECONDARY_AMMO_MAGAZINES_TENS); + } + else if (weaponPtr->WeaponIDNumber == WEAPON_GRENADELAUNCHER) + { + /* KJL 11:46:57 04/09/97 - use to display your ammo type */ + int value; + switch(GrenadeLauncherData.SelectedAmmo) + { + case AMMO_GRENADE: + { + value=1; + break; + } + case AMMO_FLARE_GRENADE: + { + value=2; + break; + } + case AMMO_FRAGMENTATION_GRENADE: + { + value=3; + break; + } + case AMMO_PROXIMITY_GRENADE: + { + value=4; + break; + } + default: + { + LOCALASSERT(0); + break; + } + } + ValueOfHUDDigit[MARINE_HUD_SECONDARY_AMMO_ROUNDS_UNITS]=value; + BLTMarineNumericsToHUD(MARINE_HUD_SECONDARY_AMMO_ROUNDS_UNITS); + } + else + { + BLTMarineNumericsToHUD(MARINE_HUD_PRIMARY_AMMO_MAGAZINES_TENS); + } + +} +#endif +static void HandleMarineWeapon(void) +{ + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + { + /* player's current weapon */ + GLOBALASSERT(playerStatusPtr->SelectedWeaponSlotWeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + } + + /* draw 3d weapon */ + PositionPlayersWeapon(); + + + /* if there is no shape name then return */ + if (twPtr->WeaponShapeName == NULL) return; + RenderThisDisplayblock(&PlayersWeapon); + + if ((twPtr->MuzzleFlashShapeName != NULL) + &&(!twPtr->PrimaryIsMeleeWeapon) + &&( (weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + ||( (weaponPtr->WeaponIDNumber==WEAPON_MARINE_PISTOL)&&(weaponPtr->CurrentState == WEAPONSTATE_FIRING_SECONDARY) ) + ||( (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS)&&(weaponPtr->CurrentState == WEAPONSTATE_FIRING_SECONDARY) ) ) ) + PositionPlayersWeaponMuzzleFlash(); + + { + + + if ((twPtr->MuzzleFlashShapeName != NULL) + &&(!twPtr->PrimaryIsMeleeWeapon) + &&((weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + ||((weaponPtr->WeaponIDNumber==WEAPON_MARINE_PISTOL)&&(weaponPtr->CurrentState == WEAPONSTATE_FIRING_SECONDARY)) + ||((weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS)&&(weaponPtr->CurrentState == WEAPONSTATE_FIRING_SECONDARY) ))) + { + static int onThisFrame=1; + if(onThisFrame || !twPtr->PrimaryIsRapidFire) + { + VECTORCH direction; + + direction.vx = PlayersWeaponMuzzleFlash.ObMat.mat31; + direction.vy = PlayersWeaponMuzzleFlash.ObMat.mat32; + direction.vz = PlayersWeaponMuzzleFlash.ObMat.mat33; + + if (weaponPtr->WeaponIDNumber==WEAPON_SMARTGUN) + { + DrawMuzzleFlash(&PlayersWeaponMuzzleFlash.ObWorld,&direction,MUZZLE_FLASH_SMARTGUN); + } + else if (weaponPtr->WeaponIDNumber==WEAPON_FRISBEE_LAUNCHER) + { + DrawMuzzleFlash(&PlayersWeaponMuzzleFlash.ObWorld,&direction,MUZZLE_FLASH_SKEETER); + } + else + { + DrawMuzzleFlash(&PlayersWeaponMuzzleFlash.ObWorld,&direction,MUZZLE_FLASH_AMORPHOUS); + #if 0 + { + int i = 5; + VECTORCH velocity = direction; + velocity.vx >>= 9; + velocity.vy >>= 9; + velocity.vz >>= 9; + do + { + VECTORCH position = PlayersWeaponMuzzleFlash.ObWorld; + position.vx += (FastRandom()&15)-8; + position.vy += (FastRandom()&15)-8; + position.vz += (FastRandom()&15)-8; + MakeParticle(&position,&velocity,PARTICLE_GUNMUZZLE_SMOKE); + } + while(--i); + } + #endif + } + } + onThisFrame=!onThisFrame; + // RenderThisDisplayblock(&PlayersWeaponMuzzleFlash); + } + + } + + /* handle smart targeting */ + SmartTarget(twPtr->SmartTargetSpeed,0); + + /* aim gun sight */ + { + int aimingSpeed=twPtr->GunCrosshairSpeed * NormalFrameTime; + AimGunSight(aimingSpeed,twPtr); + } +} + +static void DrawMarineSights(void) +{ + /* draw standard crosshairs */ + if (MIRROR_CHEATMODE) + { + BLTGunSightToScreen(ScreenDescriptorBlock.SDB_Width - (GunMuzzleSightX>>16), GunMuzzleSightY>>16, GUNSIGHT_CROSSHAIR); + } + else + { + BLTGunSightToScreen(GunMuzzleSightX>>16, GunMuzzleSightY>>16, GUNSIGHT_CROSSHAIR); + } + + /* draw smart target sights if required */ + { + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + + if (TemplateWeapon[weaponPtr->WeaponIDNumber].IsSmartTarget) + { + if (MIRROR_CHEATMODE) + { + if (CurrentlySmartTargetingObject) /* tracking target so use the red box */ + { + BLTGunSightToScreen(ScreenDescriptorBlock.SDB_Width - (SmartTargetSightX>>16),SmartTargetSightY>>16,GUNSIGHT_REDBOX); + } + else /* not tracking anything, use green box */ + { + BLTGunSightToScreen(ScreenDescriptorBlock.SDB_Width - (SmartTargetSightX>>16),SmartTargetSightY>>16,GUNSIGHT_GREENBOX); + } + } + else + { + if (CurrentlySmartTargetingObject) /* tracking target so use the red box */ + { + BLTGunSightToScreen(SmartTargetSightX>>16,SmartTargetSightY>>16,GUNSIGHT_REDBOX); + } + else /* not tracking anything, use green box */ + { + BLTGunSightToScreen(SmartTargetSightX>>16,SmartTargetSightY>>16,GUNSIGHT_GREENBOX); + } + } + } + } +} + + + +/*KJL**************************************** +* ************** PREDATOR HUD ************* * +****************************************KJL*/ + +static void InitPredatorHUD(void) +{ + PlatformSpecificInitPredatorHUD(); + + SmartTarget_Object=NULL; + Old_SmartTarget_Object=NULL; + InitialiseGrapplingHook(); +} + +#if DO_PREDATOR_OVERLAY + +static void UpdatePredatorStatusValues(void) +{ + PLAYER_WEAPON_DATA *weaponPtr; + + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + { + /* player's current weapon */ + GLOBALASSERT(playerStatusPtr->SelectedWeaponSlotWeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + } + + + { + int value=WideMulNarrowDiv(playerStatusPtr->Health,45,6553600); + + if (value>=37) + { + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_5]= value-36; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_4]= 9; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_3]= 9; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_2]= 9; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_1]= 9; + } + else if (value>=28) + { + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_5]= 0; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_4]= value-27; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_3]= 9; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_2]= 9; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_1]= 9; + } + else if (value>=19) + { + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_5]= 0; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_4]= 0; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_3]= value-18; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_2]= 9; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_1]= 9; + } + else if (value>=10) + { + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_5]= 0; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_4]= 0; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_3]= 0; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_2]= value-9; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_1]= 9; + } + else + { + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_5]= 0; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_4]= 0; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_3]= 0; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_2]= 0; + ValueOfHUDDigit[PREDATOR_HUD_HEALTH_1]= value; + } + } + { + int value=WideMulNarrowDiv(playerStatusPtr->Armour,45,6553600); + + if (value>=37) + { + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_5]= value-36; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_4]= 9; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_3]= 9; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_2]= 9; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_1]= 9; + } + else if (value>=28) + { + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_5]= 0; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_4]= value-27; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_3]= 9; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_2]= 9; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_1]= 9; + } + else if (value>=19) + { + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_5]= 0; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_4]= 0; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_3]= value-18; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_2]= 9; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_1]= 9; + } + else if (value>=10) + { + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_5]= 0; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_4]= 0; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_3]= 0; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_2]= value-9; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_1]= 9; + } + else + { + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_5]= 0; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_4]= 0; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_3]= 0; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_2]= 0; + ValueOfHUDDigit[PREDATOR_HUD_ARMOUR_1]= value; + } + } + +#if 0 + { + int value=playerStatusPtr->Energy>>16; /* stored in 16.16 so shift down */ + ValueOfHUDDigit[MARINE_HUD_ENERGY_UNITS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_ENERGY_TENS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_ENERGY_HUNDREDS]=value%10; + } + { + int value=weaponPtr->RoundsRemaining>>16; + /* ammo is in 16.16. we want the integer part, rounded up */ + if ( (weaponPtr->RoundsRemaining&0xffff) ) value+=1; + + ValueOfHUDDigit[MARINE_HUD_AMMO_ROUNDS_UNITS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_AMMO_ROUNDS_TENS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_AMMO_ROUNDS_HUNDREDS]=value%10; + } + { + int value=weaponPtr->MagazinesRemaining; + ValueOfHUDDigit[MARINE_HUD_AMMO_MAGAZINES_UNITS]=value%10; + value/=10; + ValueOfHUDDigit[MARINE_HUD_AMMO_MAGAZINES_TENS]=value%10; + } +#endif + +} + +#endif + +void DisplayPredatorHealthAndEnergy(void) +{ + PLAYER_WEAPON_DATA *weaponPtr = &(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot]); + int value; + int i; + int scale = DIV_FIXED(ScreenDescriptorBlock.SDB_Width,640); + int size = MUL_FIXED(51,scale); + { + NPC_DATA *NpcData; + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Predator_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Predator_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Predator_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Predator_Impossible); + break; + } + LOCALASSERT(NpcData); + value=MUL_FIXED(PlayerStatusPtr->Health/NpcData->StartingStats.Health,59); + } + for (i=0; i<6; i++) + { + HUDCharDesc charDesc; + charDesc.X = 0; + charDesc.Y = i*size; + + charDesc.Red = 255; + charDesc.Green = 0; + charDesc.Blue = 0; + charDesc.Alpha= 255; + + { + int v=value-i*9; + if (v>9) v=9; + else if (v<0) v=0; + charDesc.Character=v; + } + + D3D_DrawHUDPredatorDigit(&charDesc,scale); + } + value= MUL_FIXED(DIV_FIXED(PlayerStatusPtr->FieldCharge,PLAYERCLOAK_MAXENERGY),59); + for (i=0; i<6; i++) + { + HUDCharDesc charDesc; + charDesc.X = ScreenDescriptorBlock.SDB_Width-size; + charDesc.Y = i*size; + + charDesc.Red = 0; + charDesc.Green = 255; + charDesc.Blue = 255; + charDesc.Alpha= 255; + + { + int v=value-i*9; + if (v>9) v=9; + else if (v<0) v=0; + charDesc.Character=v; + } + + D3D_DrawHUDPredatorDigit(&charDesc,scale); + } + if (weaponPtr->WeaponIDNumber == WEAPON_PRED_RIFLE) + { + value = weaponPtr->PrimaryRoundsRemaining>>16; + for (i=0; i<4; i++) + { + HUDCharDesc charDesc; + charDesc.X = i*size/2; + charDesc.Y = ScreenDescriptorBlock.SDB_Height-size/2; + + charDesc.Red = 0; + charDesc.Green = 0; + charDesc.Blue = 255; + charDesc.Alpha= 255; + + { + int v=value-i*9; + if (v>9) v=9; + else if (v<0) v=0; + charDesc.Character=v; + } + + D3D_DrawHUDPredatorDigit(&charDesc,scale/2); + } + } + +} +#if 0 +static void DoPredatorThreatDisplay(void) +{ + /* evaluate the distance digits */ + { + int value=WideMulNarrowDiv(FindPredatorThreats(),72,MOTIONTRACKER_RANGE); + + if (value>=64) + { + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_8]= value-63; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_7]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_6]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_5]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_4]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_3]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_2]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_1]= 9; + } + else if (value>=55) + { + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_8]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_7]= value-54; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_6]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_5]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_4]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_3]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_2]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_1]= 9; + } + else if (value>=46) + { + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_8]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_7]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_6]= value-45; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_5]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_4]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_3]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_2]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_1]= 9; + } + else if (value>=37) + { + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_8]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_7]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_6]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_5]= value-36; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_4]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_3]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_2]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_1]= 9; + } + else if (value>=28) + { + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_8]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_7]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_6]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_5]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_4]= value-27; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_3]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_2]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_1]= 9; + } + else if (value>=19) + { + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_8]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_7]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_6]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_5]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_4]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_3]= value-18; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_2]= 9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_1]= 9; + } + else if (value>=10) + { + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_8]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_7]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_6]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_5]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_4]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_3]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_2]= value-9; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_1]= 9; + } + else + { + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_8]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_7]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_6]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_5]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_4]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_3]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_2]= 0; + ValueOfHUDDigit[PREDATOR_HUD_THREATDISPLAY_1]= value; + } + } + + + return; +} + + +static int FindPredatorThreats(void) +{ + DYNAMICSBLOCK *playerDynPtr = Player->ObStrategyBlock->DynPtr; + int numberOfObjects = NumActiveStBlocks; + int nearestDistance=MOTIONTRACKER_RANGE; + + while (numberOfObjects--) + { + STRATEGYBLOCK *objectPtr = ActiveStBlockList[numberOfObjects]; + DYNAMICSBLOCK *objectDynPtr = objectPtr->DynPtr; + + if (objectPtr == Player->ObStrategyBlock) continue; + + if (objectDynPtr) + { + /* 2d vector from player to object */ + int dx = objectDynPtr->Position.vx-playerDynPtr->Position.vx; + int dz = objectDynPtr->Position.vz-playerDynPtr->Position.vz; + int dy = objectDynPtr->Position.vy-playerDynPtr->Position.vy; + + if (dy > -2000 || dy <2000) + { + int dist = Fast2dMagnitude(dx,dz); + /* remember distance for possible display on HUD */ + if (nearestDistance>dist) nearestDistance=dist; + + } + } + } + return nearestDistance; +} +#endif +static void HandlePredatorWeapon(void) +{ + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + { + /* player's current weapon */ + GLOBALASSERT(playerStatusPtr->SelectedWeaponSlotWeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + } + + //PositionPlayersWeapon(); + + { + extern void RenderThisDisplayblock(DISPLAYBLOCK *dbPtr); + + /* draw 3d muzzle flash */ + if ((twPtr->MuzzleFlashShapeName != NULL) + &&(!twPtr->PrimaryIsMeleeWeapon) + &&(weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) ) + RenderThisDisplayblock(&PlayersWeaponMuzzleFlash); + + /* draw 3d weapon */ + if (twPtr->WeaponShapeName != NULL) + RenderThisDisplayblock(&PlayersWeapon); + + } + if (twPtr->PrimaryIsMeleeWeapon) + { + GunMuzzleSightX = (ScreenDescriptorBlock.SDB_Width<<15); + GunMuzzleSightY = (ScreenDescriptorBlock.SDB_Height<<15); + } + else + { + SmartTarget(twPtr->SmartTargetSpeed,ONE_FIXED); + + /* aim gun sight */ + if (weaponPtr->WeaponIDNumber == WEAPON_PRED_SHOULDERCANNON) + { + if (PredSight_LockOnTime) + { + GunMuzzleSightX = (ScreenDescriptorBlock.SDB_Width<<15); + GunMuzzleSightY = (ScreenDescriptorBlock.SDB_Height<<15); + } + else + { + GunMuzzleSightX = SmartTargetSightX; + GunMuzzleSightY = SmartTargetSightY; + } + } + else + { + int aimingSpeed=twPtr->GunCrosshairSpeed * NormalFrameTime; + AimGunSight(aimingSpeed,twPtr); + } + } + +} + +static void DrawPredatorSights(void) +{ + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + + /* Enforce quiet unless we've got the plasmacaster. */ + if (weaponPtr->WeaponIDNumber!=WEAPON_PRED_SHOULDERCANNON) { + if(predHUDSoundHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(predHUDSoundHandle); + } + } else { + /* Think about plasmacaster HUD sounds! */ + textprint("PredSight_LockOnTime %d\n",PredSight_LockOnTime); + if ((PredSight_LockOnTime==0) + &&(weaponPtr->CurrentState!=WEAPONSTATE_SWAPPING_IN) + &&(weaponPtr->CurrentState!=WEAPONSTATE_READYING) + &&(SmartTarget_Object)) { + /* We must be locked on and steady. */ + if(predHUDSoundHandle != SOUND_NOACTIVEINDEX) { + if (ActiveSounds[predHUDSoundHandle].soundIndex!=SID_PREDATOR_PLASMACASTER_TARGET_LOCKED) { + Sound_Stop(predHUDSoundHandle); + } + } + if(predHUDSoundHandle == SOUND_NOACTIVEINDEX) { + Sound_Play(SID_PREDATOR_PLASMACASTER_TARGET_LOCKED,"elh",&predHUDSoundHandle); + } + } else { + /* Not locked on - don't be looping! */ + if(predHUDSoundHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(predHUDSoundHandle); + /* We were locked on... */ + Sound_Play(SID_PREDATOR_PLASMACASTER_TARGET_LOST,"h"); + } + } + } + + if (TemplateWeapon[weaponPtr->WeaponIDNumber].IsSmartTarget) + { + /* ChrisF 19/2/99 Changed this to prevent 'instant' re-targetting. */ + if ((SmartTarget_Object==NULL)||(SmartTarget_Object!=Old_SmartTarget_Object)) + { + PredSight_LockOnTime = PREDATOR_LOCK_ON_TIME; + PredSight_Angle = 0; + /* Think about sound... */ + if (SmartTarget_Object) { + Sound_Play(SID_PREDATOR_PLASMACASTER_REDTRIANGLES,"h"); + } + } + else + { + int segmentScale=PredSight_LockOnTime; + + + if (segmentScale<=ONE_FIXED) + { + RenderPredatorTargetingSegment((PredSight_Angle+1365*2)&4095, segmentScale, PredSight_LockOnTime); + } + + segmentScale -= PREDATOR_LOCK_ON_TIME/5; + if (segmentScale<0) segmentScale = 0; + if (segmentScale<=ONE_FIXED) + { + RenderPredatorTargetingSegment((PredSight_Angle+1365)&4095, segmentScale, PredSight_LockOnTime); + } + + segmentScale -= PREDATOR_LOCK_ON_TIME/5; + if (segmentScale<0) segmentScale = 0; + if (segmentScale>ONE_FIXED) segmentScale = ONE_FIXED; + + RenderPredatorTargetingSegment(PredSight_Angle, segmentScale, PredSight_LockOnTime); + + if (PredSight_LockOnTime>0) + { + PredSight_LockOnTime -= NormalFrameTime*PREDATOR_LOCK_ON_SPEED; + + if (PredSight_LockOnTime<0) + { + PredSight_LockOnTime = 0; + /* Locked on - play a sound. */ + if (weaponPtr->WeaponIDNumber==WEAPON_PRED_DISC) { + Sound_Play(SID_PREDATOR_DISK_TARGET_LOCKED,"h"); + } else if (weaponPtr->WeaponIDNumber==WEAPON_PRED_SHOULDERCANNON) { + Sound_Play(SID_PREDATOR_PLASMACASTER_TARGET_FOUND,"h"); + } + } + } + else + { + PredSight_Angle += (NormalFrameTime>>6); + PredSight_Angle &= 4095; + } + } + } + { + extern int HUDFontsImageNumber; + HUDImageDesc imageDesc; + + imageDesc.ImageNumber = HUDFontsImageNumber; + imageDesc.TopLeftX = (ScreenDescriptorBlock.SDB_Width-16)/2; + imageDesc.TopLeftY = (ScreenDescriptorBlock.SDB_Height-14)/2; + imageDesc.TopLeftU = 1; + imageDesc.TopLeftV = 51; + imageDesc.Height = 15; + imageDesc.Width = 17; + imageDesc.Scale = ONE_FIXED; + imageDesc.Translucency = 255; + imageDesc.Red = 255; + imageDesc.Green = 255; + imageDesc.Blue = 255; + + Draw_HUDImage(&imageDesc); + } +} +void DrawWristDisplay(void) +{ + extern HMODELCONTROLLER PlayersWeaponHModelController; + SECTION_DATA *sectionPtr; + int i; + + char *sectionName[]= {"Dum bar display","Dum 1 display","Dum 2 display","Dum 3 display","Dum 4 display"}; + + sectionPtr=GetThisSectionData(PlayersWeaponHModelController.section_data,sectionName[0]); + if (!sectionPtr) return; + + RenderPredatorPlasmaCasterCharge(PlayerStatusPtr->PlasmaCasterCharge, §ionPtr->World_Offset, §ionPtr->SecMat); + #if 0 + for (i=0; i<5; i++) + { + DECAL CurrentDecal; + extern MODULE *playerPherModule; + int z= 0,halfWidth=50,halfHeight=50; + + + sectionPtr=GetThisSectionData(PlayersWeaponHModelController.section_data,sectionName[i]); + if (!sectionPtr) return; + + CurrentDecal.DecalID = DECAL_PREDATOR_BLOOD; + + CurrentDecal.Vertices[0].vx = -halfWidth; + CurrentDecal.Vertices[0].vz = -halfHeight; + CurrentDecal.Vertices[0].vy = z; + RotateVector(&(CurrentDecal.Vertices[0]),§ionPtr->SecMat); + CurrentDecal.Vertices[0].vx += sectionPtr->World_Offset.vx; + CurrentDecal.Vertices[0].vy += sectionPtr->World_Offset.vy; + CurrentDecal.Vertices[0].vz += sectionPtr->World_Offset.vz; + + + CurrentDecal.Vertices[1].vx = halfWidth; + CurrentDecal.Vertices[1].vz = -halfHeight; + CurrentDecal.Vertices[1].vy = z; + RotateVector(&(CurrentDecal.Vertices[1]),§ionPtr->SecMat); + CurrentDecal.Vertices[1].vx += sectionPtr->World_Offset.vx; + CurrentDecal.Vertices[1].vy += sectionPtr->World_Offset.vy; + CurrentDecal.Vertices[1].vz += sectionPtr->World_Offset.vz; + + CurrentDecal.Vertices[2].vx = halfWidth; + CurrentDecal.Vertices[2].vz = halfHeight; + CurrentDecal.Vertices[2].vy = z; + RotateVector(&(CurrentDecal.Vertices[2]),§ionPtr->SecMat); + CurrentDecal.Vertices[2].vx += sectionPtr->World_Offset.vx; + CurrentDecal.Vertices[2].vy += sectionPtr->World_Offset.vy; + CurrentDecal.Vertices[2].vz += sectionPtr->World_Offset.vz; + + CurrentDecal.Vertices[3].vx = -halfWidth; + CurrentDecal.Vertices[3].vz = halfHeight; + CurrentDecal.Vertices[3].vy = z; + RotateVector(&(CurrentDecal.Vertices[3]),§ionPtr->SecMat); + CurrentDecal.Vertices[3].vx += sectionPtr->World_Offset.vx; + CurrentDecal.Vertices[3].vy += sectionPtr->World_Offset.vy; + CurrentDecal.Vertices[3].vz += sectionPtr->World_Offset.vz; + + CurrentDecal.ModuleIndex = playerPherModule->m_index; + + CurrentDecal.UOffset = 0; + + RenderDecal(&CurrentDecal); + } + #endif +} +void RotateVertex(VECTOR2D *vertexPtr, int theta) +{ + extern int sine[],cosine[]; + int vx,vy; + int sin = GetSin(theta); + int cos = GetCos(theta); + + vx = MUL_FIXED(vertexPtr->vx,cos) - MUL_FIXED(vertexPtr->vy,sin); + vy = MUL_FIXED(vertexPtr->vx,sin) + MUL_FIXED(vertexPtr->vy,cos); + + vertexPtr->vx = vx; + vertexPtr->vy = vy; +} + + + +/*KJL******** +* ALIEN HUD * +********KJL*/ + +static void HandleAlienWeapon(void) +{ + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + extern int Alien_Visible_Weapon; + + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + { + /* player's current weapon */ + GLOBALASSERT(playerStatusPtr->SelectedWeaponSlotWeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + } + + //PositionPlayersWeapon(); + + { + extern void RenderThisDisplayblock(DISPLAYBLOCK *dbPtr); + + /* draw 3d muzzle flash */ + if ((twPtr->MuzzleFlashShapeName != NULL) + &&(!twPtr->PrimaryIsMeleeWeapon) + &&(weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) ) + RenderThisDisplayblock(&PlayersWeaponMuzzleFlash); + + /* draw 3d weapon */ + /* if there is no shape name then return */ + if (twPtr->WeaponShapeName == NULL) return; + RenderThisDisplayblock(&PlayersWeapon); + + } + //if ((twPtr->PrimaryIsMeleeWeapon)&& + if ((weaponPtr->WeaponIDNumber == WEAPON_ALIEN_CLAW)&&(Alien_Visible_Weapon==0)) + { + GunMuzzleSightX = (ScreenDescriptorBlock.SDB_Width<<15); + GunMuzzleSightY = (ScreenDescriptorBlock.SDB_Height<<15); + } + else + { + SmartTarget(twPtr->SmartTargetSpeed,0); + /* aim gun sight */ + { + int aimingSpeed=twPtr->GunCrosshairSpeed * NormalFrameTime; + AimGunSight(aimingSpeed,twPtr); + } + } + +} + +#if DO_ALIEN_OVERLAY + +static void UpdateAlienStatusValues(void) +{ + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + { + int value=playerStatusPtr->Health>>16; /* stored in 16.16 so shift down */ + ValueOfHUDDigit[ALIEN_HUD_HEALTH_UNITS]=value%10; + value/=10; + ValueOfHUDDigit[ALIEN_HUD_HEALTH_TENS]=value%10; + value/=10; + ValueOfHUDDigit[ALIEN_HUD_HEALTH_HUNDREDS]=value%10; + } +} + +#endif + +static void DrawAlienTeeth(void) +{ + /* KJL 14:51:00 08/10/98 - test if bite attack is possible */ + { + extern STRATEGYBLOCK *GetBitingTarget(void); + if(GetBitingTarget()) + { + if (AlienTeethOffsetONE_FIXED) + { + AlienTeethOffset = ONE_FIXED; + } + } + else + { + if (AlienTeethOffset>0) + { + AlienTeethOffset -= NormalFrameTime; + } + if (AlienTeethOffset<0) + { + AlienTeethOffset = 0; + } + } + } + + if (AlienTeethOffset) + { + extern int CloakingPhase; + int offsetY; + + DISPLAYBLOCK displayblock; + + displayblock.ObMat=Global_VDB_Ptr->VDB_Mat; + TransposeMatrixCH(&displayblock.ObMat); + displayblock.name=NULL; + displayblock.ObEuler.EulerX=0; + displayblock.ObEuler.EulerY=0; + displayblock.ObEuler.EulerZ=0; + displayblock.ObFlags=ObFlag_ArbRot; + displayblock.ObFlags2=0; + displayblock.ObFlags3=0; + displayblock.ObNumLights=0; + displayblock.ObRadius=0; + displayblock.ObMaxX=0; + displayblock.ObMinX=0; + displayblock.ObMaxY=0; + displayblock.ObMinY=0; + displayblock.ObMaxZ=0; + displayblock.ObMinZ=0; + displayblock.ObTxAnimCtrlBlks=NULL; + displayblock.ObEIDPtr=NULL; + displayblock.ObMorphCtrl=NULL; + displayblock.ObStrategyBlock=NULL; + displayblock.ShapeAnimControlBlock=NULL; + displayblock.HModelControlBlock=NULL; + displayblock.ObMyModule=NULL; + displayblock.SpecialFXFlags = 0; + displayblock.SfxPtr=0; + + offsetY = MUL_FIXED(GetSin(AlienTeethOffset/64),80); + + + + displayblock.ObShape=GetLoadedShapeMSL("uppertuth@tongue"); + displayblock.ObWorld.vx = 0; + displayblock.ObWorld.vy = -200+offsetY; + displayblock.ObWorld.vz = 80; + displayblock.ObView = displayblock.ObWorld; + { + MATRIXCH myMat = Global_VDB_Ptr->VDB_Mat; + TransposeMatrixCH(&myMat); + RotateVector(&(displayblock.ObWorld), &(myMat)); + displayblock.ObWorld.vx += Global_VDB_Ptr->VDB_World.vx; + displayblock.ObWorld.vy += Global_VDB_Ptr->VDB_World.vy; + displayblock.ObWorld.vz += Global_VDB_Ptr->VDB_World.vz; + } + + RenderThisDisplayblock(&displayblock); + + displayblock.ObShape=GetLoadedShapeMSL("lowertuth@tongue"); + displayblock.ObWorld.vx = 0; + displayblock.ObWorld.vy = 200-offsetY; + displayblock.ObWorld.vz = 80; + displayblock.ObView = displayblock.ObWorld; + { + MATRIXCH myMat = Global_VDB_Ptr->VDB_Mat; + TransposeMatrixCH(&myMat); + RotateVector(&(displayblock.ObWorld), &(myMat)); + displayblock.ObWorld.vx += Global_VDB_Ptr->VDB_World.vx; + displayblock.ObWorld.vy += Global_VDB_Ptr->VDB_World.vy; + displayblock.ObWorld.vz += Global_VDB_Ptr->VDB_World.vz; + } + + RenderThisDisplayblock(&displayblock); + } + + +} + + + +/*KJL************** +* Some useful fns * +**************KJL*/ + +/* returns approx. magnitude */ +int Fast2dMagnitude(int dx, int dy) +{ + if (dx<0) dx = -dx; + if (dy<0) dy = -dy; + + if (dx>dy) + return dx+dy/3; + else + return dy+dx/3; +} + + + +/*KJL************************* +* On screen messaging system * +*************************KJL*/ + +extern void NewOnScreenMessage(unsigned char *messagePtr) +{ + #if SupportWindows95 + GADGET_NewOnScreenMessage( messagePtr ); + #endif +} + +static void AimGunSight(int aimingSpeed, TEMPLATE_WEAPON_DATA *twPtr) +{ + int dx,dy,mag; + int targetX,targetY; + int boundary = twPtr->SmartTargetRadius*(ScreenDescriptorBlock.SDB_Height/2); + + /* setup target */ + targetX = SmartTargetSightX; + targetY = SmartTargetSightY; + + /* restrict target to a bounding box */ + { + int leftBoundary = (ScreenDescriptorBlock.SDB_Width<<15) - boundary; + int rightBoundary = (ScreenDescriptorBlock.SDB_Width<<15) + boundary; + + if (targetXrightBoundary) targetX=rightBoundary; + } + { + int topBoundary = (ScreenDescriptorBlock.SDB_Height<<15) - boundary; + int bottomBoundary = (ScreenDescriptorBlock.SDB_Height<<15) + boundary; + + if (targetYbottomBoundary) targetY=bottomBoundary; + } + + dx = targetX-GunMuzzleSightX; + dy = targetY-GunMuzzleSightY; + mag = Fast2dMagnitude(dx,dy); + + /* return if no need to move sight */ + if (mag==0) return; + + /* move the sight */ + if (aimingSpeed) + { + dx = WideMulNarrowDiv(aimingSpeed,dx,mag); + dy = WideMulNarrowDiv(aimingSpeed,dy,mag); + GunMuzzleSightX += dx; + GunMuzzleSightY += dy; + + /* if overshoot target, move sight back */ + if ( (dx>0 && GunMuzzleSightX>targetX) || (dx<0 && GunMuzzleSightX0 && GunMuzzleSightY>targetY) || (dy<0 && GunMuzzleSightYvx; + if (dx<0) dx = -dx; + + dy = v->vy; + if (dy<0) dy = -dy; + + dz = v->vz*3; + if (dz<0) dz = -dz; + + { + int temp; + + if (dx>dy) + temp = 3*dx+dy; + else + temp = 3*dy+dx; + + if (temp>dz) + return 3*temp+dz; + else + return 3*dz+temp; + } +} + +#define ZOOM_SCALE_0 1.0f +#define ZOOM_SCALE_1 0.4f +#define ZOOM_SCALE_2 0.1f +#define ZOOM_SCALE_3 0.02f + +static int CurrentCameraZoomLevel=0; + +static float ZoomLevels[] = {1.0f,0.4f,0.1f,0.02f}; + +void MaintainZoomingLevel(void) +{ + int i; + float deltaZoom; + float requestedZoomScale; + + i = 0; + while (CameraZoomScale<=ZoomLevels[++i]); + + + deltaZoom = (ZoomLevels[i-1] - ZoomLevels[i])*(float)NormalFrameTime/32768.0f; +// textprint("deltaZoom %f, zone %d\n",deltaZoom,i); + + requestedZoomScale = ZoomLevels[CameraZoomLevel]; + + if (requestedZoomScaleCameraZoomScale) + { + #if 0 + CameraZoomScale += deltaZoom; + if (requestedZoomScaleObStrategyBlock->DynPtr; + struct collisionreport *nextReport; + + LOCALASSERT(dynPtr); + nextReport = dynPtr->CollisionReportPtr; + + /* walk the collision report list, looking for collisions against inanimate objects */ + while(nextReport) + { + STRATEGYBLOCK* collidedWith = nextReport->ObstacleSBPtr; + + /* check collison report for valid object */ + if((collidedWith) && (collidedWith->I_SBtype == I_BehaviourInanimateObject)) + { + INANIMATEOBJECT_STATUSBLOCK* objStatPtr = collidedWith->SBdataptr; + + /*Make sure the object hasn't already been picked up this frame*/ + if(collidedWith->SBflags.please_destroy_me==0 && objStatPtr->respawnTimer==0) + { + /* now test for inanimate objects we can pick up... */ + switch(objStatPtr->typeId) + { + case(IOT_Weapon): + { + if (AbleToPickupWeapon(objStatPtr->subType)) { + RemovePickedUpObject(collidedWith); + /*Message now done in able to pickup function*/ + // NewOnScreenMessage(GetTextString(TemplateWeapon[objStatPtr->subType].Name)); + } + break; + } + case(IOT_Ammo): + { + if (AbleToPickupAmmo(objStatPtr->subType)) { + RemovePickedUpObject(collidedWith); + NewOnScreenMessage(GetTextString(TemplateAmmo[objStatPtr->subType].ShortName)); + } + break; + } + case(IOT_Health): + { + if (AbleToPickupHealth(objStatPtr->subType)) { + RemovePickedUpObject(collidedWith); + NewOnScreenMessage(GetTextString(TEXTSTRING_INGAME_MEDIKIT)); + } + break; + } + case(IOT_Armour): + { + if (AbleToPickupArmour(objStatPtr->subType)) { + RemovePickedUpObject(collidedWith); + NewOnScreenMessage(GetTextString(TEXTSTRING_INGAME_ARMOUR)); + } + break; + } + case(IOT_Key): + { +// SetPlayerSecurityClearance(Player->ObStrategyBlock,objStatPtr->subType); + RemovePickedUpObject(collidedWith); + break; + } + case(IOT_BoxedSentryGun): + { + RemovePickedUpObject(collidedWith); + break; + } + case(IOT_IRGoggles): + { + RemovePickedUpObject(collidedWith); + break; + } + case(IOT_DataTape): + { + RemovePickedUpObject(collidedWith); + break; + } + case(IOT_MTrackerUpgrade): + { + if (AbleToPickupMTrackerUpgrade(objStatPtr->subType)) + RemovePickedUpObject(collidedWith); + break; + } + case(IOT_PheromonePod): + { + ((PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr))->MTrackerType++; + RemovePickedUpObject(collidedWith); + } + case IOT_SpecialPickupObject: + { + RemovePickedUpObject(collidedWith); + + break; + } + case IOT_FieldCharge: + { + if (AbleToPickupFieldCharge(objStatPtr->subType)) { + RemovePickedUpObject(collidedWith); + } + break; + } + + + } + } + } else if((collidedWith) && (collidedWith->I_SBtype == I_BehaviourNetGhost)) { + NETGHOSTDATABLOCK* ghostData = collidedWith->SBdataptr; + + if (collidedWith->SBflags.please_destroy_me==0) { + if (ghostData->type==I_BehaviourInanimateObject) { + if (ghostData->IOType==IOT_Ammo) { + if (AbleToPickupAmmo(ghostData->subtype)) { + AddNetMsg_LocalObjectDestroyed_Request(collidedWith); + ghostData->IOType=IOT_Non; + /* So it's not picked up again... */ + NewOnScreenMessage(GetTextString(TemplateAmmo[ghostData->subtype].ShortName)); + } + } + if (ghostData->IOType==IOT_Weapon) { + if (AbleToPickupWeapon(ghostData->subtype)) { + AddNetMsg_LocalObjectDestroyed_Request(collidedWith); + ghostData->IOType=IOT_Non; + /* So it's not picked up again... */ + /*Message now done in able to pickup function*/ + // NewOnScreenMessage(GetTextString(TemplateWeapon[ghostData->subtype].Name)); + } + } + } + } + } + + nextReport = nextReport->NextCollisionReportPtr; + } + +} + +void LoadAllWeapons(PLAYER_STATUS *playerStatusPtr) { + + int slot = MAX_NO_OF_WEAPON_SLOTS; + + /* Sorry, doesn't do pulse grenades yet. */ + + do { + PLAYER_WEAPON_DATA *wdPtr; + TEMPLATE_WEAPON_DATA *twPtr; + TEMPLATE_AMMO_DATA *templateAmmoPtr; + + wdPtr = &playerStatusPtr->WeaponSlot[--slot]; + twPtr = &TemplateWeapon[wdPtr->WeaponIDNumber]; + templateAmmoPtr = &TemplateAmmo[twPtr->PrimaryAmmoID]; + + if ((wdPtr->PrimaryRoundsRemaining==0) + &&(wdPtr->PrimaryMagazinesRemaining>0) + &&(twPtr->PrimaryAmmoID!=AMMO_NONE)) { + wdPtr->PrimaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine; + wdPtr->PrimaryMagazinesRemaining--; + } + + if ((wdPtr->SecondaryRoundsRemaining==0) + &&(wdPtr->SecondaryMagazinesRemaining>0) + &&(twPtr->SecondaryAmmoID!=AMMO_NONE)) { + TEMPLATE_AMMO_DATA *secondaryTemplateAmmoPtr; + + secondaryTemplateAmmoPtr = &TemplateAmmo[twPtr->SecondaryAmmoID]; + + wdPtr->SecondaryRoundsRemaining = secondaryTemplateAmmoPtr->AmmoPerMagazine; + wdPtr->SecondaryMagazinesRemaining--; + } + + } while(slot); + +} + +void InitialisePlayersInventory(PLAYER_STATUS *playerStatusPtr) +{ + PLAYER_WEAPON_DATA *weaponDataPtr = &playerStatusPtr->WeaponSlot[WEAPON_SLOT_1]; + + enum WEAPON_ID *PlayerWeaponKey; + + switch(AvP.PlayerType) { + case I_Marine: + PlayerWeaponKey=&MarineWeaponKey[0]; + break; + case I_Alien: + PlayerWeaponKey=&AlienWeaponKey[0]; + break; + case I_Predator: + PlayerWeaponKey=&PredatorWeaponKey[0]; + break; + } + + + { + int slot = MAX_NO_OF_WEAPON_SLOTS; + do + { + PLAYER_WEAPON_DATA *wdPtr = &playerStatusPtr->WeaponSlot[--slot]; + + //wdPtr->WeaponIDNumber = NULL_WEAPON; + wdPtr->WeaponIDNumber = PlayerWeaponKey[slot]; + + wdPtr->PrimaryRoundsRemaining=0; + wdPtr->PrimaryMagazinesRemaining=0; + wdPtr->SecondaryRoundsRemaining=0; + wdPtr->SecondaryMagazinesRemaining=0; + wdPtr->CurrentState = WEAPONSTATE_IDLE; + wdPtr->StateTimeOutCounter=0; + wdPtr->PositionOffset.vx = 0; + wdPtr->PositionOffset.vy = 0; + wdPtr->PositionOffset.vz = 0; + wdPtr->DirectionOffset.EulerX = 0; + wdPtr->DirectionOffset.EulerY = 0; + wdPtr->DirectionOffset.EulerZ = 0; + wdPtr->Possessed=0; + InitThisWeapon(wdPtr); // To set the null pointers. + } + while(slot); + } + + GrenadeLauncherData.StandardRoundsRemaining=0; + GrenadeLauncherData.StandardMagazinesRemaining=0; + GrenadeLauncherData.FlareRoundsRemaining=0; + GrenadeLauncherData.FlareMagazinesRemaining=0; + GrenadeLauncherData.ProximityRoundsRemaining=0; + GrenadeLauncherData.ProximityMagazinesRemaining=0; + GrenadeLauncherData.FragmentationRoundsRemaining=0; + GrenadeLauncherData.FragmentationMagazinesRemaining=0; + GrenadeLauncherData.SelectedAmmo = AMMO_GRENADE; + + /* 'swap' to weapon at beginning of game */ + playerStatusPtr->SelectedWeaponSlot = WEAPON_SLOT_1; + playerStatusPtr->PreviouslySelectedWeaponSlot = WEAPON_SLOT_1; + playerStatusPtr->SwapToWeaponSlot = WEAPON_SLOT_1; + weaponDataPtr->CurrentState = WEAPONSTATE_SWAPPING_IN; + weaponDataPtr->StateTimeOutCounter = 0; + + /* Set to initial motion tracker type */ + + playerStatusPtr->MTrackerType = 0; + + /* Initially not facehugged */ + + playerStatusPtr->MyFaceHugger=NULL; + + /* Nor dead. */ + + playerStatusPtr->MyCorpse=NULL; + + ThisDiscMode=I_Seek_Track; + SmartgunMode=I_Track; + + /* switch on player type */ + switch(AvP.PlayerType) + { + int a; + + case I_Marine: + { + /*if in a multiplayer game , check to see if player is a specialist marine*/ + if(AvP.Network != I_No_Network) + { + switch(netGameData.myCharacterSubType) + { + + case NGSCT_Smartgun : + if (SPECIALIST_PISTOLS) { + /* Conditional pistol! */ + a=SlotForThisWeapon(WEAPON_MARINE_PISTOL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=10; + } + a=SlotForThisWeapon(WEAPON_CUDGEL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=0; + } + } else { + a=SlotForThisWeapon(WEAPON_CUDGEL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + } + } + a=SlotForThisWeapon(WEAPON_SMARTGUN); + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=5; + playerStatusPtr->WeaponSlot[a].Possessed=1; + break; + + case NGSCT_Flamer : + if (SPECIALIST_PISTOLS) { + /* Conditional pistol! */ + a=SlotForThisWeapon(WEAPON_MARINE_PISTOL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=10; + } + a=SlotForThisWeapon(WEAPON_CUDGEL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=0; + } + } else { + a=SlotForThisWeapon(WEAPON_CUDGEL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + } + } + a=SlotForThisWeapon(WEAPON_FLAMETHROWER); + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=5; + playerStatusPtr->WeaponSlot[a].Possessed=1; + break; + + case NGSCT_Sadar : + if (SPECIALIST_PISTOLS) { + /* Conditional pistol! */ + a=SlotForThisWeapon(WEAPON_MARINE_PISTOL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=10; + } + a=SlotForThisWeapon(WEAPON_CUDGEL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=0; + } + } else { + a=SlotForThisWeapon(WEAPON_CUDGEL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + } + } + a=SlotForThisWeapon(WEAPON_SADAR); + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=10; + playerStatusPtr->WeaponSlot[a].Possessed=1; + break; + + case NGSCT_GrenadeLauncher : + if (SPECIALIST_PISTOLS) { + /* Conditional pistol! */ + a=SlotForThisWeapon(WEAPON_MARINE_PISTOL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=10; + } + a=SlotForThisWeapon(WEAPON_CUDGEL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=0; + } + } else { + a=SlotForThisWeapon(WEAPON_CUDGEL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + } + } + a=SlotForThisWeapon(WEAPON_GRENADELAUNCHER); + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=4; + GrenadeLauncherData.StandardMagazinesRemaining=4; + GrenadeLauncherData.FlareMagazinesRemaining=4; + GrenadeLauncherData.ProximityMagazinesRemaining=4; + GrenadeLauncherData.FragmentationMagazinesRemaining=4; + playerStatusPtr->WeaponSlot[a].Possessed=1; + break; + + case NGSCT_Minigun : + if (SPECIALIST_PISTOLS) { + /* Conditional pistol! */ + a=SlotForThisWeapon(WEAPON_MARINE_PISTOL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=10; + } + a=SlotForThisWeapon(WEAPON_CUDGEL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=0; + } + } else { + a=SlotForThisWeapon(WEAPON_CUDGEL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + } + } + a=SlotForThisWeapon(WEAPON_MINIGUN); + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=5; + playerStatusPtr->WeaponSlot[a].Possessed=1; + break; + + case NGSCT_PulseRifle : + if (SPECIALIST_PISTOLS) { + /* Conditional pistol! */ + a=SlotForThisWeapon(WEAPON_MARINE_PISTOL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=10; + } + } + /* Conditional cudgel! */ + a=SlotForThisWeapon(WEAPON_CUDGEL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + } + a=SlotForThisWeapon(WEAPON_PULSERIFLE); + //pulse rifle marines get more ammo + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=10; + playerStatusPtr->WeaponSlot[a].SecondaryRoundsRemaining=(ONE_FIXED*15); + playerStatusPtr->WeaponSlot[a].SecondaryMagazinesRemaining=0; + playerStatusPtr->WeaponSlot[a].Possessed=1; + + break; + case NGSCT_Frisbee : + if (SPECIALIST_PISTOLS) { + /* Conditional pistol! */ + a=SlotForThisWeapon(WEAPON_MARINE_PISTOL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=10; + } + a=SlotForThisWeapon(WEAPON_CUDGEL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=0; + } + } else { + a=SlotForThisWeapon(WEAPON_CUDGEL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + } + } + a=SlotForThisWeapon(WEAPON_FRISBEE_LAUNCHER); + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=5; + playerStatusPtr->WeaponSlot[a].Possessed=1; + break; + case NGSCT_Pistols : + a=SlotForThisWeapon(WEAPON_MARINE_PISTOL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=50; + } + a=SlotForThisWeapon(WEAPON_TWO_PISTOLS); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=25; + playerStatusPtr->WeaponSlot[a].SecondaryMagazinesRemaining=25; + } + break; + case NGSCT_General : + default : + /* Conditional cudgel! */ + a=SlotForThisWeapon(WEAPON_CUDGEL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + } + a=SlotForThisWeapon(WEAPON_PULSERIFLE); + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=5; + playerStatusPtr->WeaponSlot[a].SecondaryRoundsRemaining=(ONE_FIXED*5); + playerStatusPtr->WeaponSlot[a].SecondaryMagazinesRemaining=0; + playerStatusPtr->WeaponSlot[a].Possessed=1; + + break; + + } + + //make sure the player starts with his appropriate weapon selected +// playerStatusPtr->SelectedWeaponSlot = a; + playerStatusPtr->PreviouslySelectedWeaponSlot = a; + playerStatusPtr->SwapToWeaponSlot = a; + + } + else + { + a=SlotForThisWeapon(WEAPON_PULSERIFLE); + if (GRENADE_MODE) { + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=0; + playerStatusPtr->WeaponSlot[a].SecondaryRoundsRemaining=(ONE_FIXED*99); + playerStatusPtr->WeaponSlot[a].SecondaryMagazinesRemaining=0; + } else { + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=5; + playerStatusPtr->WeaponSlot[a].SecondaryRoundsRemaining=(ONE_FIXED*5); + playerStatusPtr->WeaponSlot[a].SecondaryMagazinesRemaining=0; + } + playerStatusPtr->WeaponSlot[a].Possessed=1; + /* Conditional cudgel! */ + a=SlotForThisWeapon(WEAPON_CUDGEL); + if (a!=-1) { + playerStatusPtr->WeaponSlot[a].Possessed=1; + } + } + #if 0 + /* Keep smartgun and flamer... for demo, lose SADAR, grenadelauncher and minigun. */ + a=SlotForThisWeapon(WEAPON_SADAR); + playerStatusPtr->WeaponSlot[a].Possessed=-1; + /* KJL 15:47:30 26/11/98 - grenade launched back in for multiplayer demo */ +// a=SlotForThisWeapon(WEAPON_GRENADELAUNCHER); +// playerStatusPtr->WeaponSlot[a].Possessed=-1; + a=SlotForThisWeapon(WEAPON_MINIGUN); + playerStatusPtr->WeaponSlot[a].Possessed=-1; + #endif + + a=SlotForThisWeapon(WEAPON_BEAMCANNON); + playerStatusPtr->WeaponSlot[a].Possessed=0; + + break; + } + case I_Predator: + { + a=SlotForThisWeapon(WEAPON_PRED_WRISTBLADE); + playerStatusPtr->WeaponSlot[a].Possessed=1; + + if(StartingEquipment.predator_pistol) + { + a=SlotForThisWeapon(WEAPON_PRED_PISTOL); + playerStatusPtr->WeaponSlot[a].PrimaryRoundsRemaining=ONE_FIXED; + playerStatusPtr->WeaponSlot[a].SecondaryRoundsRemaining=ONE_FIXED; + playerStatusPtr->WeaponSlot[a].Possessed=1; + } + if(StartingEquipment.predator_num_spears) + { + a=SlotForThisWeapon(WEAPON_PRED_RIFLE); + playerStatusPtr->WeaponSlot[a].PrimaryRoundsRemaining=(ONE_FIXED*StartingEquipment.predator_num_spears); + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=0; + playerStatusPtr->WeaponSlot[a].Possessed=1; + } + if(StartingEquipment.predator_plasmacaster) + { + a=SlotForThisWeapon(WEAPON_PRED_SHOULDERCANNON); + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=5; + playerStatusPtr->WeaponSlot[a].Possessed=1; + } + if(StartingEquipment.predator_disc) + { + a=SlotForThisWeapon(WEAPON_PRED_DISC); + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=1; + playerStatusPtr->WeaponSlot[a].Possessed=1; + } + if(StartingEquipment.predator_medicomp) + { + a=SlotForThisWeapon(WEAPON_PRED_MEDICOMP); + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=0; + playerStatusPtr->WeaponSlot[a].PrimaryRoundsRemaining=MEDICOMP_MAX_AMMO; + playerStatusPtr->WeaponSlot[a].Possessed=1; + } + a=SlotForThisWeapon(WEAPON_PRED_STAFF); + playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining=0; + playerStatusPtr->WeaponSlot[a].Possessed=0; + + break; + } + case I_Alien: + { + a=SlotForThisWeapon(WEAPON_ALIEN_CLAW); + playerStatusPtr->WeaponSlot[a].Possessed=1; + a=SlotForThisWeapon(WEAPON_ALIEN_GRAB); + playerStatusPtr->WeaponSlot[a].Possessed=0; + //a=SlotForThisWeapon(WEAPON_ALIEN_SPIT); + //playerStatusPtr->WeaponSlot[a].PrimaryRoundsRemaining=100*65536; + //playerStatusPtr->WeaponSlot[a].Possessed=1; + break; + } + default: + LOCALASSERT(1==0); + break; + + } + + /*check jetpack and grappling hook*/ + playerStatusPtr->JetpackEnabled = StartingEquipment.marine_jetpack; + playerStatusPtr->GrapplingHookEnabled = StartingEquipment.predator_grappling_hook; + + LoadAllWeapons(PlayerStatusPtr); +} + + +/* fn returns zero if unable to add ammo to inventory, + eg, of the wrong type */ + +static int AbleToPickupAmmo(enum AMMO_ID ammoID) +{ + int weaponSlot = -1; + + LOCALASSERT(ammoID>=0); + LOCALASSERT(ammoIDObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + /* init a pointer to the weapon's data */ + weaponPtr = &(playerStatusPtr->WeaponSlot[weaponSlot]); + + #if 0 + if(weaponPtr->SecondaryMagazinesRemaining == 99) + { + /* no room! */ + return 0; + } + else + { + weaponPtr->SecondaryMagazinesRemaining+=1; /* KJL 12:54:37 03/10/97 - need extra data field in ammo templates */ + + if(weaponPtr->SecondaryMagazinesRemaining > 99) + weaponPtr->SecondaryMagazinesRemaining = 99; + } + #else + if(weaponPtr->SecondaryRoundsRemaining == 99) + { + /* no room! */ + return 0; + } + + weaponPtr->SecondaryRoundsRemaining+=(5*ONE_FIXED); + if (weaponPtr->SecondaryRoundsRemaining>(99*ONE_FIXED)) { + weaponPtr->SecondaryRoundsRemaining=(99*ONE_FIXED); + } + #endif + } + /* successful */ + return 1; + break; + } + default: + break; + } + + break; + } + case I_Predator: + { + switch(ammoID) + { + case AMMO_PRED_RIFLE: + { + weaponSlot = SlotForThisWeapon(WEAPON_PRED_RIFLE); + break; + } + case AMMO_PRED_DISC: + { + PLAYER_WEAPON_DATA *weaponPtr; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + GLOBALASSERT(playerStatusPtr); + weaponSlot = SlotForThisWeapon(WEAPON_PRED_DISC); + + weaponPtr = &(playerStatusPtr->WeaponSlot[weaponSlot]); + + if ((weaponPtr->PrimaryMagazinesRemaining!=0) + ||(weaponPtr->PrimaryRoundsRemaining!=0)) { + /* You have a disc: you can't have another! */ + return(0); + } + break; + } + default: + break; + } + break; + } + case I_Alien: + { + break; + } + + default: + LOCALASSERT(1==0); + break; + } + + /* if unable to find the correct weapon slot for the ammo */ + if (weaponSlot == -1) return 0; + + { + PLAYER_WEAPON_DATA *weaponPtr; + + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + /* init a pointer to the weapon's data */ + weaponPtr = &(playerStatusPtr->WeaponSlot[weaponSlot]); + + if(weaponPtr->PrimaryMagazinesRemaining == 99) + { + /* no room! */ + return 0; + } + else + { + if (ammoID==AMMO_SADAR_TOW) { + weaponPtr->PrimaryMagazinesRemaining+=4; + } else if (ammoID==AMMO_MARINE_PISTOL_PC) { + if ((AvP.Network != I_No_Network)&&(PISTOL_INFINITE_AMMO)) { + weaponPtr->PrimaryMagazinesRemaining=10; + /* If you have Two Pistols, load that, too. */ + { + PLAYER_WEAPON_DATA *twoPistolPtr; + int twoPistolSlot; + + twoPistolSlot=SlotForThisWeapon(WEAPON_TWO_PISTOLS); + if (twoPistolSlot!=-1) { + twoPistolPtr=&(playerStatusPtr->WeaponSlot[twoPistolSlot]); + if (twoPistolPtr) { + twoPistolPtr->PrimaryMagazinesRemaining=5; + twoPistolPtr->SecondaryMagazinesRemaining=5; + } + } + } + } else { + weaponPtr->PrimaryMagazinesRemaining+=10; + /* If you have Two Pistols, load that, too. */ + { + PLAYER_WEAPON_DATA *twoPistolPtr; + int twoPistolSlot; + + twoPistolSlot=SlotForThisWeapon(WEAPON_TWO_PISTOLS); + if (twoPistolSlot!=-1) { + twoPistolPtr=&(playerStatusPtr->WeaponSlot[twoPistolSlot]); + if (twoPistolPtr) { + twoPistolPtr->PrimaryMagazinesRemaining+=5; + twoPistolPtr->SecondaryMagazinesRemaining+=5; + } + } + } + } + } else if (ammoID==AMMO_10MM_CULW) { + weaponPtr->PrimaryMagazinesRemaining+=5; + } else if (ammoID==AMMO_PRED_RIFLE) { + /* Add to Rounds. */ + weaponPtr->PrimaryRoundsRemaining+=(ONE_FIXED*SPEARS_PER_PICKUP); + if (weaponPtr->PrimaryRoundsRemaining>(ONE_FIXED*MAX_SPEARS)) { + weaponPtr->PrimaryRoundsRemaining=(ONE_FIXED*MAX_SPEARS); + } + } else if (ammoID==AMMO_PRED_DISC) { + /* Disc case... */ + if ((weaponPtr->PrimaryMagazinesRemaining==0) + && (weaponPtr->PrimaryRoundsRemaining==0)) { + weaponPtr->PrimaryRoundsRemaining+=ONE_FIXED; + /* Autoswap to disc here? */ + AutoSwapToDisc(); + } else { + weaponPtr->PrimaryMagazinesRemaining+=1; + } + } else { + weaponPtr->PrimaryMagazinesRemaining+=1; /* KJL 12:54:37 03/10/97 - need extra data field in ammo templates */ + } + + if(weaponPtr->PrimaryMagazinesRemaining > 99) + weaponPtr->PrimaryMagazinesRemaining = 99; + } + } + + /* successful */ + return 1; + +} + + +/* fn returns zero if unable to add weapon to inventory, + eg, of the wrong type */ + +static int AbleToPickupWeapon(enum WEAPON_ID weaponID) +{ + BOOL WillSwitchToThisWeapon = FALSE; + int weaponSlot = -1; + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + LOCALASSERT(weaponID>=0); + LOCALASSERT(weaponIDWeaponSlot[pistolSlot].Possessed==1) { + weaponSlot = SlotForThisWeapon(WEAPON_TWO_PISTOLS); + } else { + weaponSlot = SlotForThisWeapon(WEAPON_MARINE_PISTOL); + } + break; + } + default: + weaponSlot = SlotForThisWeapon(weaponID); + break; + } + + break; + } + case I_Predator: + { + weaponSlot = SlotForThisWeapon(weaponID); + break; + } + case I_Alien: + { + weaponSlot = SlotForThisWeapon(weaponID); + break; + } + + default: + LOCALASSERT(1==0); + break; + } + + + + /* if unable to find the correct weapon slot */ + if (weaponSlot == -1) return 0; + + { + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + + + /* init a pointer to the weapon's data */ + weaponPtr = &(playerStatusPtr->WeaponSlot[weaponSlot]); + + #if 0 + /* if weapon slot isn't empty, unable to pickup weapon */ + if (weaponPtr->Possessed!=0) return 0; + + /* add weapon to inventory */ + weaponPtr->Possessed = 1; + #else + + /* Select new weapons. */ + if (weaponPtr->Possessed==0) { + if(AutoWeaponChangeOn) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo=(weaponSlot+1); + WillSwitchToThisWeapon = TRUE; + } + } + + twPtr=&TemplateWeapon[weaponID]; + + if(weaponID==WEAPON_PULSERIFLE) //get some secondary ammo (grenades) as well + { + if (AbleToPickupAmmo(twPtr->SecondaryAmmoID)) { + /* AbleToPickupAmmo should load some grenades... */ + #if 0 + TEMPLATE_AMMO_DATA *templateAmmoPtr; + + /* Load weapon. */ + templateAmmoPtr = &TemplateAmmo[twPtr->SecondaryAmmoID]; + + if ((weaponPtr->SecondaryRoundsRemaining==0)&&(weaponPtr->SecondaryMagazinesRemaining>0)) { + weaponPtr->SecondaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine; + weaponPtr->SecondaryMagazinesRemaining--; + } + #endif + } + } + + if (twPtr->PrimaryAmmoID!=AMMO_NONE) { + + if (AbleToPickupAmmo(twPtr->PrimaryAmmoID)) { + TEMPLATE_AMMO_DATA *templateAmmoPtr; + + weaponPtr->Possessed = 1; + /* Load weapon. */ + templateAmmoPtr = &TemplateAmmo[twPtr->PrimaryAmmoID]; + + if ((weaponPtr->PrimaryRoundsRemaining==0)&&(weaponPtr->PrimaryMagazinesRemaining>0)) { + weaponPtr->PrimaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine; + weaponPtr->PrimaryMagazinesRemaining--; + } + if (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS) { + if ((weaponPtr->SecondaryRoundsRemaining==0)&&(weaponPtr->SecondaryMagazinesRemaining>0)) { + weaponPtr->SecondaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine; + weaponPtr->SecondaryMagazinesRemaining--; + } + } + if(!WillSwitchToThisWeapon) + { + /* + Only show pickup weapon message if this isn't a new weapon. + (To avoid message duplication when the automatic weapon switching is done) + */ + NewOnScreenMessage(GetTextString(TemplateWeapon[weaponID].Name)); + } + + return(1); + } else { + if (weaponPtr->Possessed==1) { + /* Get a weapon, but no ammo */ + weaponPtr->Possessed = 1; + if(!WillSwitchToThisWeapon) + { + /* + Only show pickup weapon message if this isn't a new weapon. + (To avoid message duplication when the automatic weapon switching is done) + */ + NewOnScreenMessage(GetTextString(TemplateWeapon[weaponID].Name)); + } + return(1); + } else { + return(0); + } + } + + } else { + /* if weapon slot isn't empty, unable to pickup weapon */ + if (weaponPtr->Possessed!=0) return 0; + /* add weapon to inventory */ + weaponPtr->Possessed = 1; + /* No ammo to load. */ + } + + #endif + + } + + if(!WillSwitchToThisWeapon) + { + /* + Only show pickup weapon message if this isn't a new weapon. + (To avoid message duplication when the automatic weapon switching is done) + */ + NewOnScreenMessage(GetTextString(TemplateWeapon[weaponID].Name)); + } + /* successful */ + return 1; + +} + +/* KJL 15:59:48 03/10/97 - enum for health pickups required */ +static int AbleToPickupHealth(int healthID) +{ + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + { + NPC_DATA *NpcData; + NPC_TYPES PlayerType; + + switch(AvP.PlayerType) + { + case(I_Marine): + { + switch (AvP.Difficulty) { + case I_Easy: + PlayerType=I_PC_Marine_Easy; + break; + default: + case I_Medium: + PlayerType=I_PC_Marine_Medium; + break; + case I_Hard: + PlayerType=I_PC_Marine_Hard; + break; + case I_Impossible: + PlayerType=I_PC_Marine_Impossible; + break; + } + break; + } + case(I_Predator): + { + /* KJL 17:25:18 28/11/98 - no medipacks for Predator! */ + return 0; + +// PlayerType=I_PC_Predator; + break; + } + case(I_Alien): + { + /* CDF 24/2/99 No medipacks for aliens, either! */ + return 0; + +// PlayerType=I_PC_Alien; + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + + NpcData=GetThisNpcData(PlayerType); + LOCALASSERT(NpcData); + + if (Player->ObStrategyBlock->SBDamageBlock.IsOnFire) { + Player->ObStrategyBlock->SBDamageBlock.IsOnFire=0; + } else if (Player->ObStrategyBlock->SBDamageBlock.Health==NpcData->StartingStats.Health<ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<Health=Player->ObStrategyBlock->SBDamageBlock.Health; + } + return 1; +} + +/* KJL 15:59:48 03/10/97 - enum for armour pickups required */ +static int AbleToPickupArmour(int armourID) +{ + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + { + NPC_DATA *NpcData; + NPC_TYPES PlayerType; + + switch(AvP.PlayerType) + { + case(I_Marine): + { + switch (AvP.Difficulty) { + case I_Easy: + PlayerType=I_PC_Marine_Easy; + break; + default: + case I_Medium: + PlayerType=I_PC_Marine_Medium; + break; + case I_Hard: + PlayerType=I_PC_Marine_Hard; + break; + case I_Impossible: + PlayerType=I_PC_Marine_Impossible; + break; + } + break; + } + case(I_Predator): + { + /* KJL 17:25:38 28/11/98 - no armour pickups for Predator! */ + // PlayerType=I_PC_Predator; + return 0; + break; + } + case(I_Alien): + { + /* CDF 24/2/99 ...or for the alien. */ + return(0); +// PlayerType=I_PC_Alien; + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + + NpcData=GetThisNpcData(PlayerType); + LOCALASSERT(NpcData); + + if (Player->ObStrategyBlock->SBDamageBlock.Armour==NpcData->StartingStats.Armour<ObStrategyBlock->SBDamageBlock.Armour=NpcData->StartingStats.Armour<Armour=Player->ObStrategyBlock->SBDamageBlock.Armour; + } + return 1; +} + +/* Andy 21/04/97 - enum for motion tracker upgrades required */ +static int AbleToPickupMTrackerUpgrade(int mtrackerID) +{ + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + /* For now, allow the player to pick up any type of upgrade */ + + playerStatusPtr->MTrackerType = mtrackerID; + return 1; +} + + + + +/*--------------------------Patrick 11/3/97--------------------------- + A couple of functions to set and check player's security clearances: + * The 'set' function takes the security level as an UNSIGNED INTEGER + parameter + * The 'Return' function also takes the security level as an UNSIGNED + INTEGER parameter, and returns 1 if the player has clearance to the + specified level, or 0 if not... + + NB valid security levels are 0 to 31. + --------------------------------------------------------------------*/ + +void SetPlayerSecurityClearance(STRATEGYBLOCK *sbPtr, unsigned int securityLevel) +{ + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + GLOBALASSERT(securityLevel<32); + + /* completely horrible hack: if you're the predator, and level 1 is passed, + you get all levels except for one. Of course. Obvious isn't it. */ + + if((AvP.PlayerType==I_Predator)&&(securityLevel==1)) + { + playerStatusPtr->securityClearances|=0xfffffffe; + } + else playerStatusPtr->securityClearances|=(1<ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + GLOBALASSERT(securityLevel<32); + + return(playerStatusPtr->securityClearances&(1<SBdataptr; + GLOBALASSERT(objectPtr->I_SBtype == I_BehaviourInanimateObject); + + /* patrick, for e3- add a sound effect to explosions */ + switch(objStatPtr->typeId) + { + case(IOT_Weapon): + switch (AvP.PlayerType) { + case I_Alien: + default: + Sound_Play(SID_PICKUP,NULL); + break; + case I_Marine: + Sound_Play(SID_MARINE_PICKUP_WEAPON,NULL); + break; + case I_Predator: + Sound_Play(SID_PREDATOR_PICKUP_WEAPON,NULL); + break; + } + break; + case(IOT_Ammo): + Sound_Play(SID_MARINE_PICKUP_AMMO,NULL); + break; + case(IOT_Armour): + Sound_Play(SID_MARINE_PICKUP_ARMOUR,NULL); + break; + case(IOT_FieldCharge): + Sound_Play(SID_PREDATOR_PICKUP_FIELDCHARGE,NULL); + break; + default: + Sound_Play(SID_PICKUP,NULL); + break; + } + + if (objStatPtr->ghosted_object) { + /* Must be a runtime pickup... */ + #if SupportWindows95 + AddNetMsg_LocalObjectDestroyed(objectPtr); + #endif + DestroyAnyStrategyBlock(objectPtr); + return; + } + + //see if object has a target that should be notified upon being picked up + if(objStatPtr->event_target) + { + if(objStatPtr->event_target->triggering_event & ObjectEventFlag_PickedUp) + { + RequestState(objStatPtr->event_target->event_target_sbptr,objStatPtr->event_target->request,0); + } + } + + if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(objectPtr); + else + { + #if SupportWindows95 + AddNetMsg_ObjectPickedUp(&objectPtr->SBname[0]); + #endif + KillInanimateObjectForRespawn(objectPtr); + } + +} + +int SlotForThisWeapon(enum WEAPON_ID weaponID) { + + PLAYER_STATUS *psptr; + int a; + + psptr=(PLAYER_STATUS *)Player->ObStrategyBlock->SBdataptr; + for (a=0; aWeaponSlot[a].WeaponIDNumber==weaponID) { + break; + } + } + if (a!=MAX_NO_OF_WEAPON_SLOTS) { + return(a); + } else { + return(-1); + } +} + +static int AbleToPickupFieldCharge(int chargeID) +{ + /* access the extra data hanging off the strategy block */ + NPC_TYPES PlayerType; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + switch(AvP.PlayerType) + { + case(I_Marine): + { + return(0); + break; + } + case(I_Predator): + { + switch (AvP.Difficulty) { + case I_Easy: + PlayerType=I_PC_Predator_Easy; + break; + default: + case I_Medium: + PlayerType=I_PC_Predator_Medium; + break; + case I_Hard: + PlayerType=I_PC_Predator_Hard; + break; + case I_Impossible: + PlayerType=I_PC_Predator_Impossible; + break; + } + break; + } + case(I_Alien): + { + return(0); + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + + { + int a; + /* Add a medicomp 'round'. */ + + a=SlotForThisWeapon(WEAPON_PRED_MEDICOMP); + if (playerStatusPtr->WeaponSlot[a].PrimaryRoundsRemaining<(MEDICOMP_MAX_AMMO)) { + playerStatusPtr->WeaponSlot[a].PrimaryRoundsRemaining+=(ONE_FIXED); + } + } + + if (playerStatusPtr->FieldCharge==PLAYERCLOAK_MAXENERGY) { + /* Got max already. */ + return(0); + } else { + playerStatusPtr->FieldCharge=PLAYERCLOAK_MAXENERGY; + return(1); + } +} + +void Convert_Disc_To_Pickup(STRATEGYBLOCK *sbPtr) { + + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + PC_PRED_DISC_BEHAV_BLOCK *bbPtr = (PC_PRED_DISC_BEHAV_BLOCK * ) sbPtr->SBdataptr; + SECTION_DATA *disc_section; + INANIMATEOBJECT_STATUSBLOCK* objectStatusPtr; + /* Transmogrify a disc behaviour to a disc ammo pickup! */ + + disc_section=GetThisSectionData(bbPtr->HModelController.section_data,"disk"); + GLOBALASSERT(disc_section); + + /* Sort out dynamics block */ + dynPtr->LinVelocity.vx=0; + dynPtr->LinVelocity.vy=0; + dynPtr->LinVelocity.vz=0; + + dynPtr->LinImpulse.vx=0; + dynPtr->LinImpulse.vy=0; + dynPtr->LinImpulse.vz=0; + + dynPtr->OrientMat=disc_section->SecMat; + dynPtr->Position=disc_section->World_Offset; + MatrixToEuler(&dynPtr->OrientMat,&dynPtr->OrientEuler); + + sbPtr->shapeIndex=disc_section->sempai->ShapeNum; + + if (sbPtr->SBdptr) { + sbPtr->SBdptr->ObShape=disc_section->sempai->ShapeNum; + sbPtr->SBdptr->ObShapeData=disc_section->sempai->Shape; + sbPtr->SBdptr->HModelControlBlock=NULL; + } + /* Create data block! */ + + objectStatusPtr = (void *)AllocateMem(sizeof(INANIMATEOBJECT_STATUSBLOCK)); + + objectStatusPtr->respawnTimer = 0; + + /* these should be loaded */ + objectStatusPtr->typeId = IOT_Ammo; + objectStatusPtr->subType = (int)AMMO_PRED_DISC; + + /* set default indestructibility */ + objectStatusPtr->Indestructable = Yes; + objectStatusPtr->event_target=NULL; + objectStatusPtr->fragments=NULL; + objectStatusPtr->num_frags=0; + objectStatusPtr->inan_tac=NULL; + objectStatusPtr->ghosted_object=1; + objectStatusPtr->explosionTimer=0; + objectStatusPtr->lifespanTimer=0; + + /* Now swap it round... */ + Sound_Stop(bbPtr->soundHandle); + Dispel_HModel(&bbPtr->HModelController); + DeallocateMem(bbPtr); + sbPtr->SBdataptr=(void *)objectStatusPtr; + sbPtr->I_SBtype=I_BehaviourInanimateObject; + +} + +int ObjectIsDiscPickup(STRATEGYBLOCK *sbPtr) { + + if (sbPtr->I_SBtype == I_BehaviourInanimateObject) { + + INANIMATEOBJECT_STATUSBLOCK* objStatPtr = sbPtr->SBdataptr; + + /* Make sure the object hasn't already been picked up this frame */ + if(sbPtr->SBflags.please_destroy_me==0 && objStatPtr->respawnTimer==0) + { + if (objStatPtr->typeId==IOT_Ammo) { + if (objStatPtr->subType==AMMO_PRED_DISC) { + return(1); + } + } + } + } else if (sbPtr->I_SBtype == I_BehaviourNetGhost) { + NETGHOSTDATABLOCK* ghostData = sbPtr->SBdataptr; + + if (sbPtr->SBflags.please_destroy_me==0) { + if (ghostData->type==I_BehaviourInanimateObject) { + if (ghostData->IOType==IOT_Ammo) { + if (ghostData->subtype==AMMO_PRED_DISC) { + return(1); + } + } + } + } + } + + return(0); + +} + +void Recall_Disc(void) { + + /* If you are a predator with NO discs, pick up the nearest one? */ + PLAYER_WEAPON_DATA *weaponPtr; + int weaponSlot = -1; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + if (AvP.PlayerType!=I_Predator) return; + + if (playerStatusPtr->FieldChargeWeaponSlot[weaponSlot]); + + if ((weaponPtr->PrimaryMagazinesRemaining==0) + && (weaponPtr->PrimaryRoundsRemaining==0)) { + + /* We have no discs: try to find a pickup. */ + STRATEGYBLOCK *nearest, *candidate; + int neardist,a; + + nearest=NULL; + neardist=10000000; + + for (a=0; aDynPtr) { + + /* Are we the right type? */ + if (ObjectIsDiscPickup(candidate)) { + VECTORCH offset; + int dist; + + offset.vx=Player->ObStrategyBlock->DynPtr->Position.vx-candidate->DynPtr->Position.vx; + offset.vy=Player->ObStrategyBlock->DynPtr->Position.vy-candidate->DynPtr->Position.vy; + offset.vz=Player->ObStrategyBlock->DynPtr->Position.vz-candidate->DynPtr->Position.vz; + + dist=Approximate3dMagnitude(&offset); + + if (distI_SBtype==I_BehaviourPredatorDisc_SeekTrack) { + VECTORCH offset; + int dist; + + offset.vx=Player->ObStrategyBlock->DynPtr->Position.vx-candidate->DynPtr->Position.vx; + offset.vy=Player->ObStrategyBlock->DynPtr->Position.vy-candidate->DynPtr->Position.vy; + offset.vz=Player->ObStrategyBlock->DynPtr->Position.vz-candidate->DynPtr->Position.vz; + + dist=Approximate3dMagnitude(&offset); + + if (distI_SBtype == I_BehaviourInanimateObject) { + + INANIMATEOBJECT_STATUSBLOCK* objStatPtr = nearest->SBdataptr; + + /* Make sure the object hasn't already been picked up this frame */ + GLOBALASSERT(nearest->SBflags.please_destroy_me==0 && objStatPtr->respawnTimer==0); + GLOBALASSERT(objStatPtr->typeId==IOT_Ammo); + GLOBALASSERT(objStatPtr->subType==AMMO_PRED_DISC); + + if (AbleToPickupAmmo(objStatPtr->subType)) { + RemovePickedUpObject(nearest); + playerStatusPtr->FieldCharge-=RecallDisc_Charge; + CurrentGameStats_ChargeUsed(RecallDisc_Charge); + #if 0 + NewOnScreenMessage("RECALLED DISC"); + #endif + Sound_Play(SID_PREDATOR_DISK_RECOVERED,"h"); + AutoSwapToDisc_OutOfSequence(); + } + + } else if (nearest->I_SBtype == I_BehaviourNetGhost) { + NETGHOSTDATABLOCK* ghostData = nearest->SBdataptr; + + GLOBALASSERT(nearest->SBflags.please_destroy_me==0); + GLOBALASSERT(ghostData->type==I_BehaviourInanimateObject); + GLOBALASSERT(ghostData->IOType==IOT_Ammo); + GLOBALASSERT(ghostData->subtype==AMMO_PRED_DISC); + + if (AbleToPickupAmmo(ghostData->subtype)) { + AddNetMsg_LocalObjectDestroyed_Request(nearest); + ghostData->IOType=IOT_Non; + /* So it's not picked up again... */ + playerStatusPtr->FieldCharge-=RecallDisc_Charge; + CurrentGameStats_ChargeUsed(RecallDisc_Charge); + #if 0 + NewOnScreenMessage("RECALLED DISC"); + #endif + Sound_Play(SID_PREDATOR_DISK_RECOVERED,"h"); + AutoSwapToDisc_OutOfSequence(); + } + + } else if (nearest->I_SBtype == I_BehaviourPredatorDisc_SeekTrack) { + + PC_PRED_DISC_BEHAV_BLOCK *bbPtr = (PC_PRED_DISC_BEHAV_BLOCK * ) nearest->SBdataptr; + + if (AbleToPickupAmmo(AMMO_PRED_DISC)) { + /* Pick it up. */ + + AutoSwapToDisc_OutOfSequence(); + + Sound_Stop(bbPtr->soundHandle); + Sound_Play(SID_PREDATOR_DISK_RECOVERED,"h"); + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(nearest); + #endif + DestroyAnyStrategyBlock(nearest); + + } + + } else { + GLOBALASSERT(0); + } + } else { + #if 0 + NewOnScreenMessage("FOUND NO DISCS"); + #endif + } + } +} + +int ObjectIsPlayersDisc(STRATEGYBLOCK *sbPtr) { + + if (sbPtr->I_SBtype == I_BehaviourInanimateObject) { + + INANIMATEOBJECT_STATUSBLOCK* objStatPtr = sbPtr->SBdataptr; + + /* Make sure the object hasn't already been picked up this frame */ + if(sbPtr->SBflags.please_destroy_me==0 && objStatPtr->respawnTimer==0) + { + if (objStatPtr->typeId==IOT_Ammo) { + if (objStatPtr->subType==AMMO_PRED_DISC) { + return(1); + } + } + } + } else if (sbPtr->I_SBtype==I_BehaviourPredatorDisc_SeekTrack) { + /* Erm... just return? */ + return(1); + } + + return(0); +} + +void RemoveAllThisPlayersDiscs(void) { + + STRATEGYBLOCK *candidate; + int a; + + /* All discs that are NOT ghosted must 'belong' to this player. */ + + for (a=0; aDynPtr) { + + /* Are we the right type? */ + if (ObjectIsPlayersDisc(candidate)) { + #if SupportWindows95 + AddNetMsg_LocalObjectDestroyed(candidate); + #endif + DestroyAnyStrategyBlock(candidate); + } + } + } +} diff --git a/3dc/avp/LANGUAGE.C b/3dc/avp/LANGUAGE.C new file mode 100644 index 0000000..e803daa --- /dev/null +++ b/3dc/avp/LANGUAGE.C @@ -0,0 +1,109 @@ +/*KJL*************************************** +* Language Internationalization Code * +***************************************KJL*/ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "gamedef.h" + + +#include "langenum.h" +#include "language.h" +#include "huffman.hpp" + +#if SupportWindows95 + // DHM 12 Nov 97: hooks for C++ string handling code: + #include "strtab.hpp" +#endif + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "avp_menus.h" + + +#ifdef AVP_DEBUG_VERSION + #define USE_LANGUAGE_TXT 0 +#else + #define USE_LANGUAGE_TXT 1 +#endif + +static char EmptyString[]=""; + +static char *TextStringPtr[MAX_NO_OF_TEXTSTRINGS]={&EmptyString,}; +static char *TextBufferPtr; + +void InitTextStrings(void) +{ + char *textPtr; + int i; + + /* language select here! */ + GLOBALASSERT(AvP.Language>=0); + GLOBALASSERT(AvP.LanguageLightBright = ONE_FIXED*4; + /* flags */ + lightPtr->LightFlags = LFlag_Omni; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + lightPtr->LightRange = EXPLOSION_LIGHT_RANGE; + + lightPtr->RedScale=255*256; + lightPtr->GreenScale=120*256; + lightPtr->BlueScale=0; + #if PSX + lightPtr->LightColour.r=255; + lightPtr->LightColour.g=120; + lightPtr->LightColour.b=0; + #endif + + break; + } + case LFX_BIGEXPLOSION: + { + /* brightness */ + lightPtr->LightBright = ONE_FIXED << 2; + /* flags */ + lightPtr->LightFlags = LFlag_Omni; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + lightPtr->LightRange = EXPLOSION_LIGHT_RANGE; + + lightPtr->RedScale=255*256; + lightPtr->GreenScale=120*256; + lightPtr->BlueScale=0; + #if PSX + lightPtr->LightColour.r=255; + lightPtr->LightColour.g=120; + lightPtr->LightColour.b=0; + #endif + + break; + } + + case LFX_MUZZLEFLASH: + { + /* brightness */ + lightPtr->LightBright = 65536 - (FastRandom()&32767); + /* flags */ + lightPtr->LightFlags = LFlag_Omni|LFlag_Deallocate; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + #if 0 + lightPtr->LightRange = 5000; /* ? */ + + lightPtr->RedScale=255*256; + lightPtr->GreenScale=192*256; + lightPtr->BlueScale=128*256; + #else + lightPtr->LightRange = 10000; /* ? */ + lightPtr->RedScale=255*256; + lightPtr->GreenScale=230*256; + lightPtr->BlueScale=200*256; + #endif + #if PSX + lightPtr->LightColour.r=255; + lightPtr->LightColour.g=192; + lightPtr->LightColour.b=128; + #endif + + break; + } + case LFX_PARTICLECANNON: + { + /* brightness */ + lightPtr->LightBright = 65536 - (FastRandom()&32767); + /* flags */ + lightPtr->LightFlags = LFlag_Omni|LFlag_Deallocate; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + lightPtr->LightRange = 10000; /* ? */ + + lightPtr->RedScale=255*256; + lightPtr->GreenScale=32*256; + lightPtr->BlueScale=0; + #if PSX + lightPtr->LightColour.r=255; + lightPtr->LightColour.g=32; + lightPtr->LightColour.b=0; + #endif + break; + } + case LFX_ROCKETJET: + { + /* brightness */ + lightPtr->LightBright = ONE_FIXED*3/4; + /* flags */ + lightPtr->LightFlags = LFlag_Omni|LFlag_CosAtten; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + lightPtr->LightRange = 5000; /* ? */ + + lightPtr->RedScale=255*256; + lightPtr->GreenScale=255*256; + lightPtr->BlueScale=128*256; + #if PSX + lightPtr->LightColour.r=255; + lightPtr->LightColour.g=255; + lightPtr->LightColour.b=128; + #endif + + break; + } + case LFX_FLARE: + { + /* brightness */ + lightPtr->LightBright = 0; + /* flags */ + lightPtr->LightFlags = LFlag_Omni; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + lightPtr->LightRange = 10000; /* ? */ + + lightPtr->RedScale=255*256; + lightPtr->GreenScale=200*256; + lightPtr->BlueScale=255*256; + #if PSX + lightPtr->LightColour.r=255; + lightPtr->LightColour.g=64; + lightPtr->LightColour.b=255; + #endif + + break; + } + case LFX_XENO_FIRING: + { + /* brightness */ + lightPtr->LightBright = 226100; + /* flags */ + lightPtr->LightFlags = LFlag_Omni|LFlag_Deallocate; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + lightPtr->LightRange = 5000; /* ? */ + + lightPtr->RedScale=255*256; + lightPtr->GreenScale=64*256; + lightPtr->BlueScale=255*256; + #if PSX + lightPtr->LightColour.r=64; + lightPtr->LightColour.g=64; + lightPtr->LightColour.b=255; + #endif + + break; + } + case LFX_PLASMA_BOLT: + { + /* brightness */ + lightPtr->LightBright = ONE_FIXED/4; + /* flags */ + lightPtr->LightFlags = LFlag_Omni|LFlag_CosAtten; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + lightPtr->LightRange = 10000; + + lightPtr->RedScale=200*256; + lightPtr->GreenScale=255*256; + lightPtr->BlueScale=255*256; + + break; + } + case LFX_OBJECTONFIRE: + { + /* brightness */ + lightPtr->LightBright = 16484 - (FastRandom()&4095); + /* flags */ + lightPtr->LightFlags = LFlag_Omni|LFlag_Deallocate|LFlag_Thermal; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + lightPtr->LightRange = 10000; + lightPtr->RedScale=255*256; + lightPtr->GreenScale=110*256; + lightPtr->BlueScale=50*256; + + break; + } + case LFX_SPEARGUNBOLT: + { + /* Just an experiment. */ + /* brightness */ + lightPtr->LightBright = ONE_FIXED/4; + /* flags */ + lightPtr->LightFlags = LFlag_Omni|LFlag_CosAtten; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + lightPtr->LightRange = 10000; + + lightPtr->RedScale=255*256; + lightPtr->GreenScale=255*256; + lightPtr->BlueScale=255*256; + + break; + } + } +} + + + +void LightBlockDeallocation(void) +{ + extern int NumActiveBlocks; + extern DISPLAYBLOCK *ActiveBlockList[]; + int numblocks = NumActiveBlocks; + + while(numblocks) + { + DISPLAYBLOCK *dptr = ActiveBlockList[--numblocks]; + + int numlights = dptr->ObNumLights; + while(numlights) + { + LIGHTBLOCK *lightPtr = dptr->ObLights[--numlights]; + if(lightPtr->LightFlags & LFlag_Deallocate) + DeleteLightBlock(lightPtr, dptr); + } + } + +} + +/*KJL****************************** +* * +* LIGHT ELEMENT CODE * +* * +******************************KJL*/ +#define MAX_NO_OF_LIGHTELEMENTS 500 +LIGHTELEMENT LightElementStorage[MAX_NO_OF_LIGHTELEMENTS]; +int NumActiveLightElements; + +void InitialiseLightElementSystem(void) +{ + NumActiveLightElements = 0; +} + +static LIGHTELEMENT* AllocateLightElement(void) +{ + LIGHTELEMENT *lightElementPtr = 0; /* Default to null ptr */ + + if (NumActiveLightElements != MAX_NO_OF_LIGHTELEMENTS) + { + lightElementPtr = &LightElementStorage[NumActiveLightElements]; + NumActiveLightElements++; + } + else + { + /* unable to allocate a lightElement */ + } + + return lightElementPtr; +} +static void DeallocateLightElement(LIGHTELEMENT *lightElementPtr) +{ + /* is pointer within array? */ + LOCALASSERT(lightElementPtr>=LightElementStorage); + LOCALASSERT(lightElementPtr<=&LightElementStorage[MAX_NO_OF_LIGHTELEMENTS-1]); + + NumActiveLightElements--; + *lightElementPtr = LightElementStorage[NumActiveLightElements]; +} + + +void MakeLightElement(VECTORCH *positionPtr, enum LIGHTELEMENT_BEHAVIOUR_ID behaviourID) +{ + LIGHTELEMENT *lightElementPtr = AllocateLightElement(); + LIGHTBLOCK *lightPtr = &(lightElementPtr->LightBlock); + + /* if we failed to make an element, get the hell out of here */ + if (!lightElementPtr) return; + + lightElementPtr->BehaviourID = behaviourID; + lightElementPtr->LightBlock.LightWorld = *positionPtr; + lightElementPtr->LifeTime=ONE_FIXED; + + switch (behaviourID) + { + case LIGHTELEMENT_ROTATING: + { + RotatingLightPosition = *positionPtr; + break; + } + case LIGHTELEMENT_ALIEN_TEETH: + { + lightPtr->LightBright = ONE_FIXED/2; + /* flags */ + lightPtr->LightFlags = LFlag_Omni; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + lightPtr->LightRange = 200; + + lightPtr->RedScale= ONE_FIXED; + lightPtr->GreenScale= ONE_FIXED; + lightPtr->BlueScale= ONE_FIXED; + + { + VECTORCH position; + position.vx = MUL_FIXED(200,GetSin((CloakingPhase)&4095)); + position.vy = MUL_FIXED(200,GetCos((CloakingPhase)&4095)); + position.vz = 80+MUL_FIXED(50,GetCos((CloakingPhase/2)&4095)); + { + MATRIXCH myMat = Global_VDB_Ptr->VDB_Mat; + TransposeMatrixCH(&myMat); + RotateVector(&(position), &(myMat)); + position.vx += Global_VDB_Ptr->VDB_World.vx; + position.vy += Global_VDB_Ptr->VDB_World.vy; + position.vz += Global_VDB_Ptr->VDB_World.vz; + } + lightElementPtr->LightBlock.LightWorld = position; + } + lightElementPtr->LifeTime = 0; + break; + } + case LIGHTELEMENT_ALIEN_TEETH2: + { + lightPtr->LightBright = ONE_FIXED/2; + /* flags */ + lightPtr->LightFlags = LFlag_Omni; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + lightPtr->LightRange = 200; + + lightPtr->RedScale= ONE_FIXED; + lightPtr->GreenScale= ONE_FIXED; + lightPtr->BlueScale= ONE_FIXED; + + { + VECTORCH position; + position.vx = MUL_FIXED(200,GetSin((CloakingPhase/3+2048)&4095)); + position.vy = MUL_FIXED(200,GetCos((CloakingPhase/3+2048)&4095)); + position.vz = 80+MUL_FIXED(50,GetCos((CloakingPhase/2+2048)&4095)); + { + MATRIXCH myMat = Global_VDB_Ptr->VDB_Mat; + TransposeMatrixCH(&myMat); + RotateVector(&(position), &(myMat)); + position.vx += Global_VDB_Ptr->VDB_World.vx; + position.vy += Global_VDB_Ptr->VDB_World.vy; + position.vz += Global_VDB_Ptr->VDB_World.vz; + } + lightElementPtr->LightBlock.LightWorld = position; + } + lightElementPtr->LifeTime = 0; + break; + } + } +} + + +void HandleLightElementSystem(void) +{ + int i = NumActiveLightElements; + LIGHTELEMENT *lightElementPtr = LightElementStorage; + + while(i--) + { + LIGHTBLOCK *lightPtr = &(lightElementPtr->LightBlock); + + switch(lightElementPtr->BehaviourID) + { + case LIGHTELEMENT_MOLTENMETAL: + { + + lightPtr->LightBright = ONE_FIXED/4; + /* flags */ + lightPtr->LightFlags = LFlag_Omni; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + lightPtr->LightRange = EXPLOSION_LIGHT_RANGE; + + lightPtr->RedScale= 255*256; + lightPtr->GreenScale= 120*256; + lightPtr->BlueScale= 0; + + break; + } + case LIGHTELEMENT_PLASMACASTERHIT: + { + /* flags */ + lightPtr->LightFlags = LFlag_Omni; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + lightPtr->LightRange = EXPLOSION_LIGHT_RANGE; + + if (lightElementPtr->LifeTime==ONE_FIXED) + { + lightPtr->LightBright = ONE_FIXED*4; + + lightPtr->RedScale= 0*256; + lightPtr->GreenScale= 255*256; + lightPtr->BlueScale= 255*256; + } + else + { + lightPtr->LightBright = lightElementPtr->LifeTime/2; + lightPtr->LightRange = 1+MUL_FIXED(EXPLOSION_LIGHT_RANGE,lightElementPtr->LifeTime); + + lightPtr->RedScale= 255*256; + lightPtr->GreenScale= 120*256; + lightPtr->BlueScale= 0*256; + } + + lightElementPtr->LifeTime-=NormalFrameTime*4; + + break; + }case LIGHTELEMENT_FROMFMV: + { + extern int FmvColourRed; + extern int FmvColourGreen; + extern int FmvColourBlue; + + lightPtr->LightBright = ONE_FIXED*4; + /* flags */ + lightPtr->LightFlags = LFlag_Omni; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + lightPtr->LightRange = 15000; + + lightPtr->RedScale= FmvColourRed; + lightPtr->GreenScale= FmvColourGreen; + lightPtr->BlueScale= FmvColourBlue; + + break; + } + case LIGHTELEMENT_EXPLOSION: + { + + /* flags */ + lightPtr->LightFlags = LFlag_Omni; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + + lightPtr->RedScale=255*256; + lightPtr->GreenScale=120*256; + lightPtr->BlueScale=0; + { + int scale = lightElementPtr->LifeTime*4; + + if (scale < ONE_FIXED) + { + lightPtr->LightRange = 1+MUL_FIXED(EXPLOSION_LIGHT_RANGE,scale); + lightPtr->LightBright = scale*8; + } + else + { + lightPtr->LightRange = EXPLOSION_LIGHT_RANGE; + lightPtr->LightBright = ONE_FIXED*8; + } + } + + + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + if (playerStatusPtr->IsAlive) + { + VECTORCH d = lightElementPtr->LightBlock.LightWorld; + int m; + d.vx -= Global_VDB_Ptr->VDB_World.vx; + d.vy -= Global_VDB_Ptr->VDB_World.vy; + d.vz -= Global_VDB_Ptr->VDB_World.vz; + m = Approximate3dMagnitude(&d); + + if (m>9,lightElementPtr->LifeTime); + int halfTilt = maxTilt/2; + if (maxTilt) + { + HeadOrientation.EulerX = (FastRandom()%maxTilt)-halfTilt; + HeadOrientation.EulerY = (FastRandom()%maxTilt)-halfTilt; + HeadOrientation.EulerZ = (FastRandom()%maxTilt)-halfTilt; + + if (HeadOrientation.EulerX < 0) HeadOrientation.EulerX += 4096; + if (HeadOrientation.EulerY < 0) HeadOrientation.EulerY += 4096; + if (HeadOrientation.EulerZ < 0) HeadOrientation.EulerZ += 4096; + } + } + } + } + lightElementPtr->LifeTime-=NormalFrameTime; + break; + } + case LIGHTELEMENT_ELECTRICAL_EXPLOSION: + { + int scale = ONE_FIXED*5/4-lightElementPtr->LifeTime; + + /* flags */ + lightPtr->LightFlags = LFlag_Omni|LFlag_Electrical; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + + if (scale>65536) scale = 65536; + scale = ONE_FIXED - scale; + + lightPtr->RedScale= scale; + lightPtr->GreenScale=ONE_FIXED; + lightPtr->BlueScale=ONE_FIXED; + lightPtr->LightRange = EXPLOSION_LIGHT_RANGE;// 1+MUL_FIXED(EXPLOSION_LIGHT_RANGE,scale); + lightPtr->LightBright = scale*16; + + lightElementPtr->LifeTime-=NormalFrameTime; + break; + } + case LIGHTELEMENT_ELECTRICAL_SPARKS: + { + int scale = lightElementPtr->LifeTime; + + /* flags */ + lightPtr->LightFlags = LFlag_Omni|LFlag_Electrical; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + + if (scale == ONE_FIXED) + { + lightPtr->RedScale=ONE_FIXED; + lightPtr->GreenScale=ONE_FIXED; + lightPtr->BlueScale=ONE_FIXED; + } + else + { + lightPtr->RedScale= 0; + lightPtr->GreenScale= scale/2; + lightPtr->BlueScale= scale; + } + lightPtr->LightRange = 4000;// 1+MUL_FIXED(EXPLOSION_LIGHT_RANGE,scale); + lightPtr->LightBright = scale; + + lightElementPtr->LifeTime-=NormalFrameTime*2; + break; + } + + case LIGHTELEMENT_ROTATING: + { + + lightPtr->LightBright = ONE_FIXED/2; + /* flags */ + lightPtr->LightFlags = LFlag_Omni; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + /* range */ + lightPtr->LightRange = 10000; + + lightPtr->RedScale= ONE_FIXED; + lightPtr->GreenScale= ONE_FIXED; + lightPtr->BlueScale= ONE_FIXED; + + lightElementPtr->LightBlock.LightWorld = Player->ObWorld;//RotatingLightPosition; +// lightElementPtr->LightBlock.LightWorld.vx += MUL_FIXED(2000,GetCos((CloakingPhase/2)&4095)); + lightElementPtr->LightBlock.LightWorld.vy -= 2200; +// lightElementPtr->LightBlock.LightWorld.vz += MUL_FIXED(2000,GetSin((CloakingPhase/2)&4095)); + #if 0 + { + + VECTORCH zero = {0,0,0}; + MakeParticle(&(lightElementPtr->LightBlock.LightWorld),&zero,PARTICLE_SPARK); + } + #endif + break; + } + case LIGHTELEMENT_ALIEN_TEETH: + case LIGHTELEMENT_ALIEN_TEETH2: + { + break; + } + + case LIGHTELEMENT_PARGEN_FLAME : + { + if(lightElementPtr->LifeTime == ONE_FIXED) + { + lightElementPtr->LifeTime = 1; + + /* flags */ + lightPtr->LightFlags = LFlag_Omni; + /* lightblock light type */ + lightPtr->LightType = LightType_PerVertex; + + //lightPtr->RedScale= 255*256; + //lightPtr->GreenScale= 120*256; + lightPtr->RedScale= 255*(200+(CloakingPhase%56)); + lightPtr->GreenScale= 120*(200+((CloakingPhase/8)%56)); + lightPtr->BlueScale= 0; + + lightPtr->LightRange = 6000; + lightPtr->LightBright = ONE_FIXED; + + } + else + { + lightElementPtr->LifeTime = 0; + } + } + break; + + default: + break; + } + + lightPtr->BrightnessOverRange = DIV_FIXED(MUL_FIXED(lightPtr->LightBright,LightScale),lightPtr->LightRange); + + if (lightElementPtr->LifeTime<=0) + { + DeallocateLightElement(lightElementPtr); + } + else + { + lightElementPtr++; + } + } +} + + +/*--------------------------** +** Load/Save Light Elements ** +**--------------------------*/ +#include "savegame.h" + +typedef struct light_element_save_block_header +{ + SAVE_BLOCK_HEADER header; + + int NumActiveLightElements; + + //followed by array of light elements +}LIGHT_ELEMENT_SAVE_BLOCK_HEADER; + +void Load_LightElements(SAVE_BLOCK_HEADER* header) +{ + int i; + LIGHT_ELEMENT_SAVE_BLOCK_HEADER* block = (LIGHT_ELEMENT_SAVE_BLOCK_HEADER*) header; + LIGHTELEMENT* saved_light_element = (LIGHTELEMENT*) (block+1); + int expected_size; + + //make sure the block is the correct size + expected_size = sizeof(*block); + expected_size += sizeof(LIGHTELEMENT) * block->NumActiveLightElements; + if(header->size != expected_size) return; + + + for(i=0;iNumActiveLightElements;i++) + { + LIGHTELEMENT* light_element = AllocateLightElement(); + if(light_element) + { + *light_element = *saved_light_element++; + } + } + +} + +void Save_LightElements() +{ + LIGHT_ELEMENT_SAVE_BLOCK_HEADER* block; + int i; + + if(!NumActiveLightElements) return; + + //get memory for header + GET_SAVE_BLOCK_POINTER(block); + + //fill in header + block->header.type = SaveBlock_LightElements; + block->header.size = sizeof(*block) + NumActiveLightElements * sizeof(LIGHTELEMENT); + + block->NumActiveLightElements = NumActiveLightElements; + + + //now save the light elements + for(i=0;iObLightType = LightType_PerVertex; + dptr->ObFlags |= ObFlag_MultLSrc; +} + + +static void Process_Player_MapType(DISPLAYBLOCK *dptr) +{ + Player = dptr; +} + + +static void Process_PlayerShipCamera_MapType(DISPLAYBLOCK *dptr) +{ +} + + + +static void Process_Sprite_MapType(DISPLAYBLOCK *dblockptr) +{ +} + + +static void Process_Term_MapType(DISPLAYBLOCK *dptr) +{} + + diff --git a/3dc/avp/MessageHistory.c b/3dc/avp/MessageHistory.c new file mode 100644 index 0000000..3ab3696 --- /dev/null +++ b/3dc/avp/MessageHistory.c @@ -0,0 +1,156 @@ +#include "3dc.h" +#include "3dc.h" +#include "module.h" +#include "inline.h" +#include "stratdef.h" +#include "gamedef.h" +#include "language.h" + +#define MAX_NO_OF_MESSAGES_IN_HISTORY 64 + +extern void NewOnScreenMessage(unsigned char *messagePtr); + +struct MessageHistory +{ + enum TEXTSTRING_ID StringID; + int Hours; + int Minutes; + int Seconds; +}; + +static struct MessageHistory MessageHistoryStore[MAX_NO_OF_MESSAGES_IN_HISTORY]; +static int NumberOfEntriesInMessageHistory; +static int EntryToNextShow; +static int MessageHistoryAccessedTimer; + +void MessageHistory_Initialise(void) +{ + NumberOfEntriesInMessageHistory=0; + EntryToNextShow=0; + MessageHistoryAccessedTimer=0; +} + +void MessageHistory_Add(enum TEXTSTRING_ID stringID) +{ + if (NumberOfEntriesInMessageHistoryNumberOfEntriesInMessageHistory; + if(header->size != expected_size) return; + + //load the stuff then + NumberOfEntriesInMessageHistory = block->NumberOfEntriesInMessageHistory; + EntryToNextShow = block->EntryToNextShow; + MessageHistoryAccessedTimer = block->MessageHistoryAccessedTimer; + + //load the message history + for(i=0;iNumberOfEntriesInMessageHistory;i++) + { + MessageHistoryStore[i] = *saved_message++; + } + + +} + +void Save_MessageHistory() +{ + MESSAGE_HISTORY_SAVE_BLOCK* block; + int i; + + //get memory for header + GET_SAVE_BLOCK_POINTER(block); + + //fill in header + block->header.type = SaveBlock_MessageHistory; + block->header.size = sizeof(*block) + NumberOfEntriesInMessageHistory * sizeof(struct MessageHistory); + + block->NumberOfEntriesInMessageHistory = NumberOfEntriesInMessageHistory; + block->EntryToNextShow = EntryToNextShow; + block->MessageHistoryAccessedTimer = MessageHistoryAccessedTimer; + + for(i=0;ism_marray; + } + + #if logFarLocData + logfile = fopen("E:/3DC/FARLOCS.TXT","w"); + fprintf(logfile, "MODULE FAR LOCATIONS DATA \n"); + fprintf(logfile, "ENV: %s \n", Env_List[AvP.CurrentEnv]->main); + fprintf(logfile, "************************* \n"); + fprintf(logfile, "number of modules: %d \n", ModuleArraySize); + fprintf(logfile, "grid size: %d \n", FAR_GRID_SIZE); + fprintf(logfile, "max locs stored per module: %d \n \n", FAR_MAX_LOCS); + fprintf(logfile, "alien box height: %d \n", FAR_BB_HEIGHT); + fprintf(logfile, "alien box width: %d \n", FAR_BB_WIDTH); + fprintf(logfile, "************************* \n \n"); + #endif + + /* initialise infinite module counter */ + numInfiniteModules = 0; + + /* allocate some temporary work spaces..*/ + auxLocsGrid = (FARVALIDATEDLOCATION *)AllocateMem(FAR_GRID_SIZE*FAR_GRID_SIZE*sizeof(FARVALIDATEDLOCATION)); + if(!auxLocsGrid) + { + memoryInitialisationFailure = 1; + return; + } + + /* Initialise the entry point list and auxilary location list. + NB entry points are are pre-allocated, since they are evaluated in pairs.*/ + InitFarLocDataAreas(moduleListPointer, ModuleArraySize); + + #if logFarLocData + fprintf(logfile, "********************************* \n"); + fprintf(logfile, "STARTING ENTRY POINTS.... \n"); + fprintf(logfile, "********************************* \n \n"); + #endif + + /* Now go through the module list, and calculate entry points. This step should + be done before auxilary locations, to be absolutely sure everything works out */ + #if 0 + //set up in projload now + for(moduleCounter = 0; moduleCounter < ModuleArraySize; moduleCounter++) + { + MODULE *thisModule; + int ThisModuleIndex; + + /* get a pointer to the next module, and it's index */ + thisModule = moduleListPointer[moduleCounter]; + LOCALASSERT(thisModule); + ThisModuleIndex = thisModule->m_index; + LOCALASSERT(ThisModuleIndex >= 0); + LOCALASSERT(ThisModuleIndex < ModuleArraySize); + + #if PSX + #ifndef CDEMUL + pollhost(); + #endif + #endif + + #if logFarLocData + fprintf(logfile, "********************************* \n"); + fprintf(logfile, "Module Index: %d %s\n", ThisModuleIndex,thisModule->name); + #endif + + /* reject modules that are not physical */ + if(ModuleIsPhysical(thisModule)) + BuildFM_EntryPoints(thisModule); + else + { + numInfiniteModules++; + #if logFarLocData + fprintf(logfile, "NO EPS COMPUTED: NOT PHYSICAL\n \n"); + #endif + } + } + #endif + + #if logFarLocData + fprintf(logfile, "********************************* \n"); + fprintf(logfile, "STARTING AUXILARY LOCATIONS.... \n"); + fprintf(logfile, "********************************* \n \n"); + #endif + + /* now go thro' each module calculating auxilary locations */ + for(moduleCounter = 0; moduleCounter < ModuleArraySize; moduleCounter++) + { + MODULE *thisModule; + int ThisModuleIndex; + + /* get a pointer to the next module, and it's index */ + thisModule = moduleListPointer[moduleCounter]; + LOCALASSERT(thisModule); + ThisModuleIndex = thisModule->m_index; + LOCALASSERT(ThisModuleIndex >= 0); + LOCALASSERT(ThisModuleIndex < ModuleArraySize); + + #if logFarLocData + fprintf(logfile, "********************************* \n"); + fprintf(logfile, "Module Index: %d \n", ThisModuleIndex); + fprintf(logfile, "Module X range: %d %d \n", thisModule->m_minx, thisModule->m_maxx); + fprintf(logfile, "Module Z range: %d %d \n \n", thisModule->m_minz, thisModule->m_maxz); + #endif + + #if PSX + #ifndef CDEMUL + pollhost(); + #endif + #endif + + /* check for entry points into this module if there aren't any, + don't bother with auxilary locations */ + + if(thisModule->m_aimodule) + BuildFM_AuxilaryLocs(thisModule); + /* + else + { + #if logFarLocData + fprintf(logfile, "NO AUXILARY LOCS COMPUTED: NO EPS \n \n"); + #endif + } + */ + } + + /* deallocate the temporary work spaces */ + if (auxLocsGrid) DeallocateMem(auxLocsGrid); + + #if logFarLocData + fprintf(logfile, "************************************* \n"); + fprintf(logfile, "FINISHED ! \n"); + fprintf(logfile, "NUM INFINITE MODULES/TERMINATORS: %d \n", numInfiniteModules); + fprintf(logfile, "************************************* \n"); + fclose(logfile); + #endif + + #if logFarLocPositions && 0 //this log will need to updated for the ai modules. + logfile2 = fopen("D:/PATRICK/FARLOCS2.TXT","w"); + fprintf(logfile2, "MODULE EPs AND AUXILARY LOCATIONS \n"); + fprintf(logfile2, "ENV: %s \n", Env_List[AvP.CurrentEnv]->main); + fprintf(logfile2, "************************* \n \n"); + + for(moduleCounter = 0; moduleCounter < ModuleArraySize; moduleCounter++) + { + int i; + fprintf(logfile2, "MODULE INDEX: %d \n",moduleCounter); + fprintf(logfile2, " EPs: \n"); + for(i=0;i0); + FALLP_AuxLocs = (FARLOCATIONSHEADER *)AllocateMem(numModules*sizeof(FARLOCATIONSHEADER)); + if(!FALLP_AuxLocs) + { + memoryInitialisationFailure = 1; + return; + } + + + FL_TotalNumAuxLocs = 0; + FL_AuxData = (VECTORCH *)0; + + /* work out the number of adjacent modules/auxilary locations for each module, + and add them up */ + for(moduleCounter=0;moduleCounterm_index; + LOCALASSERT(thisModuleIndex >= 0); + LOCALASSERT(thisModuleIndex < ModuleArraySize); + + if(ModuleIsPhysical(thisModule)) + { + FL_TotalNumAuxLocs += FAR_MAX_LOCS; + } + } + + /* allocate base data areas */ + LOCALASSERT(FL_TotalNumAuxLocs>0); + FL_AuxData = AllocateMem(FL_TotalNumAuxLocs*sizeof(VECTORCH));; + if(!FL_AuxData) + { + memoryInitialisationFailure = 1; + return; + } + + /* init header lists */ + { + VECTORCH *auxDataPtr = FL_AuxData; + + for(moduleCounter=0;moduleCounterm_index; + /* NB these pointers and indexes have been validated above */ + + FALLP_AuxLocs[thisModuleIndex].numLocations = 0; + FALLP_AuxLocs[thisModuleIndex].locationsList = (VECTORCH *)0; + + { + MODULE** modulearray=thisAIModule->m_module_ptrs; + if(modulearray) + { + FALLP_AuxLocs[thisModuleIndex].locationsList = auxDataPtr; + while(*modulearray) + { + modulearray++; + auxDataPtr += FAR_MAX_LOCS; + + } + } + } + } + + /* we can now validate this process... */ + LOCALASSERT(auxDataPtr==(FL_AuxData+FL_TotalNumAuxLocs)); + } +} + + +/*-----------------------Patrick 28/11/96--------------------------- +This function deallocates the location lists for each module, +and must be called at some point before the environment re-load +-------------------------------------------------------------------*/ +void KillFarModuleLocs(void) +{ + /* don't do this for a net game */ + //in fact do do it in net game + //if(AvP.Network != I_No_Network) return; + + LOCALASSERT(ModuleArraySize); + LOCALASSERT(AIModuleArraySize); + LOCALASSERT(FALLP_EntryPoints); + LOCALASSERT(FALLP_AuxLocs); + LOCALASSERT(FL_TotalNumAuxLocs>0); + LOCALASSERT(FL_AuxData); + + /* deallocate the base data area in one go, and re-init globals */ + if (FL_AuxData) DeallocateMem(FL_AuxData); + FL_TotalNumAuxLocs = 0; + FL_AuxData = (VECTORCH *)0; + + /* deallocate the list headers, and re-init globals */ + if (FALLP_AuxLocs) DeallocateMem(FALLP_AuxLocs); + FALLP_AuxLocs = (FARLOCATIONSHEADER *)0; + if (FALLP_EntryPoints) + { + int i; + for(i=0;im_sbptr) && (target->m_sbptr->I_SBtype == I_BehaviourProximityDoor)) + return MDT_ProxDoor; + if((target->m_sbptr) && (target->m_sbptr->I_SBtype == I_BehaviourLiftDoor)) + return MDT_LiftDoor; + if((target->m_sbptr) && (target->m_sbptr->I_SBtype == I_BehaviourSwitchDoor)) + return MDT_SecurityDoor; + + return MDT_NotADoor; +} + +MODULEDOORTYPE AIModuleIsADoor(AIMODULE* target) +{ + /* A bit rough and ready at this point. */ + int a; + MODULE **renderModule; + + GLOBALASSERT(target->m_module_ptrs); + + renderModule=target->m_module_ptrs; + a=0; + + while ((*renderModule)!=NULL) { + + if(((*renderModule)->m_sbptr) && ((*renderModule)->m_sbptr->I_SBtype == I_BehaviourProximityDoor)) + return MDT_ProxDoor; + if(((*renderModule)->m_sbptr) && ((*renderModule)->m_sbptr->I_SBtype == I_BehaviourLiftDoor)) + return MDT_LiftDoor; + if(((*renderModule)->m_sbptr) && ((*renderModule)->m_sbptr->I_SBtype == I_BehaviourSwitchDoor)) + return MDT_SecurityDoor; + + GLOBALASSERT(a<300); + + renderModule++; + a++; + } + + return MDT_NotADoor; +} + +/*-----------------------Patrick 20/12/96--------------------------- +Returns TRUE if a module is a physical part of the environment, +ie is not infinite or a terminator, etc... +-------------------------------------------------------------------*/ +int ModuleIsPhysical(MODULE* target) +{ + if(target->m_flags & m_flag_infinite) return 0; + if(target->m_type == mtype_term) return 0; + return 1; +} + +int AIModuleIsPhysical(AIMODULE* target) +{ + if (target==NULL) { + return(0); + } + GLOBALASSERT(target); + if(target->m_module_ptrs==NULL) return 0; + return 1; +} + +/*-----------------------Patrick 20/12/96--------------------------- +Takes 2 modules, and returns TRUE if the centre of the target module +is within the bounding box of the source; +-------------------------------------------------------------------*/ +int ModuleInModule(MODULE* source, MODULE* target) +{ + + if(target->m_world.vx < (source->m_world.vx + source->m_minx)) return 0; + if(target->m_world.vx > (source->m_world.vx + source->m_maxx)) return 0; + + if(target->m_world.vy < (source->m_world.vy + source->m_miny)) return 0; + if(target->m_world.vy > (source->m_world.vy + source->m_maxy)) return 0; + + if(target->m_world.vz < (source->m_world.vz + source->m_minz)) return 0; + if(target->m_world.vz > (source->m_world.vz + source->m_maxz)) return 0; + + return 1; +} + +/*-----------------------Patrick 20/12/96--------------------------- +Returns the number of entries in a given module's adjacency list +If there is no adjacency list, return 0. +-------------------------------------------------------------------*/ +int NumAdjacentModules(AIMODULE* target) +{ + AIMODULE **AdjAIModulePtr; + int counter = 0; + + AdjAIModulePtr = (target->m_link_ptrs); + if(AdjAIModulePtr) + { + while(*AdjAIModulePtr) + { + counter++; + AdjAIModulePtr++; + } + } + else return 0; + + return counter; +} + +/*-----------------------Patrick 20/12/96--------------------------- +Returns a pointer to an entry point in thisModule from fromModule, +or 0 if there isn't one. +-------------------------------------------------------------------*/ +FARENTRYPOINT *GetModuleEP(MODULE* thisModule, MODULE*fromModule) +{ + int numEps; + FARENTRYPOINT *epList; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + int tmIndex = fromModule->m_index; + + numEps = FALLP_EntryPoints[thisModule->m_index].numEntryPoints; + epList = FALLP_EntryPoints[thisModule->m_index].entryPointsList; + + while((numEps>0) && (thisEp == (FARENTRYPOINT *)0)) + { + if(epList->donorIndex == tmIndex) thisEp = epList; + epList++; + numEps--; + } + + return thisEp; +} + +FARENTRYPOINT *GetAIModuleEP(AIMODULE* thisModule, AIMODULE*fromModule) +{ + int numEps; + FARENTRYPOINT *epList; + FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0; + int tmIndex = fromModule->m_index; + + numEps = FALLP_EntryPoints[thisModule->m_index].numEntryPoints; + epList = FALLP_EntryPoints[thisModule->m_index].entryPointsList; + + while((numEps>0) && (thisEp == (FARENTRYPOINT *)0)) + { + if(epList->donorIndex == tmIndex) thisEp = epList; + epList++; + numEps--; + } + + return thisEp; +} + +/*-----------------------Patrick 20/12/96--------------------------- +Returns 1 if the given point is in a given module, or 0 otherwise. +The point is in module LOCAL space. + +NB the bizzare structure of this function produces optimum pentium +instructions... apparently. +-------------------------------------------------------------------*/ +int PointIsInModule(MODULE* thisModule, VECTORCH* thisPoint) +{ + /* + Allow tolerance level on module boundaries equivavlent to that used by + ModuleFromPosition_WithToleranace. + THis may be a bad plan , but I think this function only really gets used + for the purposes of asserts. + */ + if(thisPoint->vx <= thisModule->m_maxx + 50) + if(thisPoint->vx >= thisModule->m_minx - 50) + if(thisPoint->vy <= thisModule->m_maxy + 50) + if(thisPoint->vy >= thisModule->m_miny - 50) + if(thisPoint->vz <= thisModule->m_maxz + 50) + if(thisPoint->vz >= thisModule->m_minz - 50) + return 1; + return 0; +} + + + + + +/*-----------------------Patrick 20/12/96--------------------------- +LOCAL FUNCTIONS FOR MODULE ENTRY POINT SUPPORT +-------------------------------------------------------------------*/ + +/* a structure and globals for the entry point calculations */ +typedef struct epbbextents +{ + int maxX; + int minX; + int maxY; + int minY; + int maxZ; + int minZ; +} EPBBEXTENTS; + +static EPBBEXTENTS MI_Volume1; +static EPBBEXTENTS MI_Volume2; +static EPBBEXTENTS MI_Volume3; + +static int GetModulesIntersection(MODULE *thisModule, MODULE *targetModule); +static int GetModulePointBox(MODULE *thisModule, EPBBEXTENTS *extents); +static void AddModuleEP(MODULE* thisModule, MODULE*fromModule, VECTORCH *posn); + +/*-----------------------Patrick 16/12/96--------------------------- +This Function checks if a module has any adjacent modules, and if +so calls BuildFM_ASingleEntryEp for each one. +-------------------------------------------------------------------*/ +#if 0 +static void BuildFM_EntryPoints(MODULE *thisModule) +{ + int ThisModuleIndex; + MREF *AdjModuleRefPtr; + + LOCALASSERT(thisModule); + ThisModuleIndex = thisModule->m_index; + LOCALASSERT(ThisModuleIndex >= 0); + LOCALASSERT(ThisModuleIndex < ModuleArraySize); + + /* check that there is a list of adjacent modules */ + if(!(NumAdjacentModules(thisModule))) + { + #if logFarLocData + fprintf(logfile, "No adjacent modules found for this module \n"); + #endif + return; + } + + AdjModuleRefPtr = thisModule->m_link_ptrs; + + /* go through each adjacent module */ + while(AdjModuleRefPtr->mref_ptr != 0) + { + BuildFM_ASingleEP(thisModule, ((MODULE* )AdjModuleRefPtr->mref_ptr)); + AdjModuleRefPtr++; + } +} +#endif + +/*-----------------------Patrick 16/12/96--------------------------- +This Function builds a single entry point pair between two modules. +-------------------------------------------------------------------*/ +#if 0 +static void BuildFM_ASingleEP(MODULE *thisModule, MODULE *targetModule) +{ + VECTORCH thisModuleEP; + VECTORCH targetModuleEP; + int numpts1, numpts2; + + /* containment check */ + if(ModuleInModule(thisModule, targetModule)) + { + #if logFarLocData + fprintf(logfile, "Against module %d: containment failure \n",targetModule->m_index); + #endif + targetModule->m_flags |= m_flag_slipped_inside; + return; + } + if(ModuleInModule(targetModule, thisModule)) + { + #if logFarLocData + fprintf(logfile, "Against module %d: containment failure \n",targetModule->m_index); + #endif + thisModule->m_flags |= m_flag_slipped_inside; + return; + } + + /* check if entry point already exists... */ + if(GetModuleEP(thisModule, targetModule) != (FARENTRYPOINT *)0) + { + #if logFarLocData + fprintf(logfile, "Against module %d: ep already exists \n",targetModule->m_index); + #endif + return; + } + + /* at this stage we know that thisModule is physical.... + but it's a good idea to check the target module */ + if (!(ModuleIsPhysical(targetModule))) + { + #if logFarLocData + fprintf(logfile, "Against module %d: target is not physical \n",targetModule->m_index); + #endif + return; + } + + /* so go ahead and find the entry point pair... */ + #if logFarLocData + fprintf(logfile, "Calculating ep against module %d %s\n", targetModule->m_index,targetModule->name); + #endif + + /* compute the bounding box intersection between the modules */ + if(GetModulesIntersection(thisModule, targetModule) == 0) + { + #if logFarLocData + fprintf(logfile, "Against module %d: BBOX failure \n",targetModule->m_index); + #endif + return; + } + + /* get the bounding boxes defined by each module's points inside the intersection volume */ + + numpts1 = GetModulePointBox(thisModule, &MI_Volume2); + numpts2 = GetModulePointBox(targetModule, &MI_Volume3); + + if(numpts1<2 || numpts2<2) + { + int extentCentre; + + #if logFarLocData + fprintf(logfile, "Against module %d: not enough points in intersection \n",targetModule->m_index); + #endif + + /* Create one anyways. */ + + extentCentre=MI_Volume1.maxX + MI_Volume1.minX; + extentCentre>>=1; + thisModuleEP.vx = extentCentre; + targetModuleEP.vx = extentCentre; + + extentCentre=MI_Volume1.maxY + MI_Volume1.minY; + extentCentre>>=1; + thisModuleEP.vy = extentCentre; + targetModuleEP.vy = extentCentre; + + extentCentre=MI_Volume1.maxZ + MI_Volume1.minZ; + extentCentre>>=1; + thisModuleEP.vz = extentCentre; + targetModuleEP.vz = extentCentre; + + if( ((MI_Volume1.maxX - MI_Volume1.minX) < (MI_Volume1.maxY - MI_Volume1.minY))&& + ((MI_Volume1.maxX - MI_Volume1.minX) < (MI_Volume1.maxZ - MI_Volume1.minZ))) + { + /* x is smallest */ + if(thisModule->m_world.vx > targetModule->m_world.vx) + { + thisModuleEP.vx = MI_Volume2.maxX + EP_POSNDISP; + targetModuleEP.vx = MI_Volume3.minX - EP_POSNDISP; + } + else + { + thisModuleEP.vx = MI_Volume2.minX - EP_POSNDISP; + targetModuleEP.vx = MI_Volume3.maxX + EP_POSNDISP; + } + } + else if((MI_Volume1.maxZ - MI_Volume1.minZ) < (MI_Volume1.maxY - MI_Volume1.minY)) + { + /* z is smallest */ + + if(thisModule->m_world.vz > targetModule->m_world.vz) + { + thisModuleEP.vz = MI_Volume2.maxZ + EP_POSNDISP; + targetModuleEP.vz = MI_Volume3.minZ - EP_POSNDISP; + } + else + { + thisModuleEP.vz = MI_Volume2.minZ - EP_POSNDISP; + targetModuleEP.vz = MI_Volume3.maxZ + EP_POSNDISP; + } + } + else + { + /* y is smallest */ + if(thisModule->m_world.vy > targetModule->m_world.vy) + { + thisModuleEP.vy = MI_Volume2.maxY + EP_POSNDISP; + targetModuleEP.vy = MI_Volume3.minY - EP_POSNDISP; + } + else + { + thisModuleEP.vy = MI_Volume2.minY - EP_POSNDISP; + targetModuleEP.vy = MI_Volume3.maxY + EP_POSNDISP; + } + } + #if logFarLocData + fprintf(logfile, "Made one anyway.\n"); + #endif + + } else { + + /* Test the point bounding boxes, just to make sure */ + LOCALASSERT(MI_Volume2.maxX >= MI_Volume2.minX); + LOCALASSERT(MI_Volume2.maxY >= MI_Volume2.minY); + LOCALASSERT(MI_Volume2.maxZ >= MI_Volume2.minZ); + LOCALASSERT(MI_Volume3.maxX >= MI_Volume3.minX); + LOCALASSERT(MI_Volume3.maxY >= MI_Volume3.minY); + LOCALASSERT(MI_Volume3.maxZ >= MI_Volume3.minZ); + + /* calculate ep's */ + if( ((MI_Volume1.maxX - MI_Volume1.minX) < (MI_Volume1.maxY - MI_Volume1.minY))&& + ((MI_Volume1.maxX - MI_Volume1.minX) < (MI_Volume1.maxZ - MI_Volume1.minZ))) + { + /* x is smallest */ + int extentCentre; + + if(MI_Volume2.maxY < MI_Volume3.maxY) extentCentre = MI_Volume2.maxY; + else extentCentre = MI_Volume3.maxY; + if(MI_Volume2.minY > MI_Volume3.minY) extentCentre += MI_Volume2.minY; + else extentCentre += MI_Volume3.minY; + extentCentre /= 2; + thisModuleEP.vy = extentCentre; + targetModuleEP.vy = extentCentre; + + if(MI_Volume2.maxZ < MI_Volume3.maxZ) extentCentre = MI_Volume2.maxZ; + else extentCentre = MI_Volume3.maxZ; + if(MI_Volume2.minZ > MI_Volume3.minZ) extentCentre += MI_Volume2.minZ; + else extentCentre += MI_Volume3.minZ; + extentCentre /= 2; + thisModuleEP.vz = extentCentre; + targetModuleEP.vz = extentCentre; + + if(thisModule->m_world.vx > targetModule->m_world.vx) + { + thisModuleEP.vx = MI_Volume2.maxX + EP_POSNDISP; + targetModuleEP.vx = MI_Volume3.minX - EP_POSNDISP; + } + else + { + thisModuleEP.vx = MI_Volume2.minX - EP_POSNDISP; + targetModuleEP.vx = MI_Volume3.maxX + EP_POSNDISP; + } + } + else if((MI_Volume1.maxZ - MI_Volume1.minZ) < (MI_Volume1.maxY - MI_Volume1.minY)) + { + /* z is smallest */ + int extentCentre; + + if(MI_Volume2.maxX < MI_Volume3.maxX) extentCentre = MI_Volume2.maxX; + else extentCentre = MI_Volume3.maxX; + if(MI_Volume2.minX > MI_Volume3.minX) extentCentre += MI_Volume2.minX; + else extentCentre += MI_Volume3.minX; + extentCentre /= 2; + thisModuleEP.vx = extentCentre; + targetModuleEP.vx = extentCentre; + + if(MI_Volume2.maxY < MI_Volume3.maxY) extentCentre = MI_Volume2.maxY; + else extentCentre = MI_Volume3.maxY; + if(MI_Volume2.minY > MI_Volume3.minY) extentCentre += MI_Volume2.minY; + else extentCentre += MI_Volume3.minY; + extentCentre /= 2; + thisModuleEP.vy = extentCentre; + targetModuleEP.vy = extentCentre; + + if(thisModule->m_world.vz > targetModule->m_world.vz) + { + thisModuleEP.vz = MI_Volume2.maxZ + EP_POSNDISP; + targetModuleEP.vz = MI_Volume3.minZ - EP_POSNDISP; + } + else + { + thisModuleEP.vz = MI_Volume2.minZ - EP_POSNDISP; + targetModuleEP.vz = MI_Volume3.maxZ + EP_POSNDISP; + } + } + else + { + /* y is smallest */ + int extentCentre; + + if(MI_Volume2.maxX < MI_Volume3.maxX) extentCentre = MI_Volume2.maxX; + else extentCentre = MI_Volume3.maxX; + if(MI_Volume2.minX > MI_Volume3.minX) extentCentre += MI_Volume2.minX; + else extentCentre += MI_Volume3.minX; + extentCentre /= 2; + thisModuleEP.vx = extentCentre; + targetModuleEP.vx = extentCentre; + + if(MI_Volume2.maxZ < MI_Volume3.maxZ) extentCentre = MI_Volume2.maxZ; + else extentCentre = MI_Volume3.maxZ; + if(MI_Volume2.minZ > MI_Volume3.minZ) extentCentre += MI_Volume2.minZ; + else extentCentre += MI_Volume3.minZ; + extentCentre /= 2; + thisModuleEP.vz = extentCentre; + targetModuleEP.vz = extentCentre; + + if(thisModule->m_world.vy > targetModule->m_world.vy) + { + thisModuleEP.vy = MI_Volume2.maxY + EP_POSNDISP; + targetModuleEP.vy = MI_Volume3.minY - EP_POSNDISP; + } + else + { + thisModuleEP.vy = MI_Volume2.minY - EP_POSNDISP; + targetModuleEP.vy = MI_Volume3.maxY + EP_POSNDISP; + } + } + } + + /* convert back into local space */ + thisModuleEP.vx -= thisModule->m_world.vx; + thisModuleEP.vy -= thisModule->m_world.vy; + thisModuleEP.vz -= thisModule->m_world.vz; + targetModuleEP.vx -= targetModule->m_world.vx; + targetModuleEP.vy -= targetModule->m_world.vy; + targetModuleEP.vz -= targetModule->m_world.vz; + + /* now test to make sure the entry points are inside their respective modules. + (If not, don't add either) */ + { + int inModule; + inModule = PointIsInModule(thisModule, &thisModuleEP); + if(!inModule) + { + #if logFarLocData + fprintf(logfile, "....can't add eps: MODULE %d, EP NOT IN MODULE SPACE \n", thisModule->m_index); + #endif + return; + } + inModule = PointIsInModule(targetModule, &targetModuleEP); + if(!inModule) + { + #if logFarLocData + fprintf(logfile, "....can't add eps: MODULE %d, EP NOT IN MODULE SPACE \n", targetModule->m_index); + #endif + return; + } + } + + /* Finally, set up the entry points for this and target module */ + AddModuleEP(thisModule, targetModule, &thisModuleEP); + AddModuleEP(targetModule, thisModule, &targetModuleEP); + #if logFarLocData + fprintf(logfile, "... entry points added \n"); + #endif + +} +#endif + +/*-----------------------Patrick 28/2/96--------------------------- + This function calculates the bounding box intersection volume + between 2 adjacent modules (in world space coords). + + Returns 1 if the bounding box is valis, 0 if not. + ------------------------------------------------------------------*/ +static int GetModulesIntersection(MODULE *thisModule, MODULE *targetModule) +{ + int thisExtent, targetExtent; + + /* do x extents */ + thisExtent = (thisModule->m_maxx + thisModule->m_world.vx + EPBB_XTRA); + targetExtent = (targetModule->m_maxx + targetModule->m_world.vx + EPBB_XTRA); + if(thisExtent < targetExtent) MI_Volume1.maxX = thisExtent; + else MI_Volume1.maxX = targetExtent; + thisExtent = (thisModule->m_minx + thisModule->m_world.vx - EPBB_XTRA); + targetExtent = (targetModule->m_minx + targetModule->m_world.vx - EPBB_XTRA); + if(thisExtent > targetExtent) MI_Volume1.minX = thisExtent; + else MI_Volume1.minX = targetExtent; + if(!(MI_Volume1.maxX > MI_Volume1.minX)) return 0; + + /* do y extents */ + thisExtent = (thisModule->m_maxy + thisModule->m_world.vy + EPBB_XTRA); + targetExtent = (targetModule->m_maxy + targetModule->m_world.vy + EPBB_XTRA); + if(thisExtent < targetExtent) MI_Volume1.maxY = thisExtent; + else MI_Volume1.maxY = targetExtent; + thisExtent = (thisModule->m_miny + thisModule->m_world.vy - EPBB_XTRA); + targetExtent = (targetModule->m_miny + targetModule->m_world.vy - EPBB_XTRA); + if(thisExtent > targetExtent) MI_Volume1.minY = thisExtent; + else MI_Volume1.minY = targetExtent; + if(!(MI_Volume1.maxY > MI_Volume1.minY)) return 0; + + /* do z extents */ + thisExtent = (thisModule->m_maxz + thisModule->m_world.vz + EPBB_XTRA); + targetExtent = (targetModule->m_maxz+ targetModule->m_world.vz + EPBB_XTRA); + if(thisExtent < targetExtent) MI_Volume1.maxZ = thisExtent; + else MI_Volume1.maxZ = targetExtent; + thisExtent = (thisModule->m_minz + thisModule->m_world.vz - EPBB_XTRA); + targetExtent = (targetModule->m_minz + targetModule->m_world.vz - EPBB_XTRA); + if(thisExtent > targetExtent) MI_Volume1.minZ = thisExtent; + else MI_Volume1.minZ = targetExtent; + if(!(MI_Volume1.maxZ > MI_Volume1.minZ)) return 0; + + return 1; +} + + +/*-----------------------Patrick 28/2/97--------------------------- +Generates a volume defined by the module's points inside the +mutual intersection volume (in world space) +-------------------------------------------------------------------*/ +static int GetModulePointBox(MODULE *thisModule, EPBBEXTENTS *extents) +{ + int numPtsFound = 0; + int pointCounter; + + /* initialise the extents */ + extents->minX = thisModule->m_maxx + thisModule->m_world.vx; + extents->maxX = thisModule->m_minx + thisModule->m_world.vx; + extents->minY = thisModule->m_maxy + thisModule->m_world.vy; + extents->maxY = thisModule->m_miny + thisModule->m_world.vy; + extents->minZ = thisModule->m_maxz + thisModule->m_world.vz; + extents->maxZ = thisModule->m_minz + thisModule->m_world.vz; + + /* go through each point in the shape */ + pointCounter = SetupPointAccessFromShapeIndex(thisModule->m_mapptr->MapShape); + while(pointCounter>0) + { + #if PSX + SVECTOR* thisPt = AccessNextPoint(); + VECTORCH thisWorldPoint; + #else + VECTORCH* thisPt = AccessNextPoint(); + VECTORCH thisWorldPoint; + #endif + + thisWorldPoint.vx = thisPt->vx + thisModule->m_world.vx; + thisWorldPoint.vy = thisPt->vy + thisModule->m_world.vy; + thisWorldPoint.vz = thisPt->vz + thisModule->m_world.vz; + + if( (thisWorldPoint.vx >= MI_Volume1.minX)&& + (thisWorldPoint.vx <= MI_Volume1.maxX)&& + (thisWorldPoint.vy >= MI_Volume1.minY)&& + (thisWorldPoint.vy <= MI_Volume1.maxY)&& + (thisWorldPoint.vz >= MI_Volume1.minZ)&& + (thisWorldPoint.vz <= MI_Volume1.maxZ)) + { + numPtsFound++; + + if(thisWorldPoint.vx > extents->maxX) extents->maxX = thisWorldPoint.vx; + if(thisWorldPoint.vx < extents->minX) extents->minX = thisWorldPoint.vx; + if(thisWorldPoint.vy > extents->maxY) extents->maxY = thisWorldPoint.vy; + if(thisWorldPoint.vy < extents->minY) extents->minY = thisWorldPoint.vy; + if(thisWorldPoint.vz > extents->maxZ) extents->maxZ = thisWorldPoint.vz; + if(thisWorldPoint.vz < extents->minZ) extents->minZ = thisWorldPoint.vz; + } + pointCounter--; + } + return numPtsFound; +} + + + + + + +/*-----------------------Patrick 20/12/96--------------------------- +Adds an entry point to the list for this module, +-------------------------------------------------------------------*/ +static void AddModuleEP(MODULE* thisModule, MODULE*fromModule, VECTORCH *posn) +{ + FARENTRYPOINTSHEADER *epHeader = &FALLP_EntryPoints[thisModule->m_index]; + FARENTRYPOINT *epList = epHeader->entryPointsList; + + if(epHeader->numEntryPoints==(NumAdjacentModules(thisModule))) + { + /* no room for any more eps. This may occur where two modules are not + mutually linked as adjacent... specifically, the target is missing the + link. This shouldn't really happen, and if it does it means there's an + error in the visibility and/or adjacency links which requires attention. + The effective result is that the linked module will get an ep from the + unlinked module, but not the other way round.... + */ + #if logFarLocData + fprintf(logfile, "....CAN'T ADD EP TO MODULE %d : NO EP SLOTS \n", thisModule->m_index); + #endif + return; + } + + LOCALASSERT(epHeader->numEntryPoints<(NumAdjacentModules(thisModule))); + + epList[epHeader->numEntryPoints].position = *posn; + epList[epHeader->numEntryPoints].donorIndex = fromModule->m_index; + + (epHeader->numEntryPoints)++; + +} + + +/*-----------------------Patrick 20/12/96--------------------------- +LOCAL FUNCTIONS FOR AUXILARY MODULE LOCATION SUPPORT +-------------------------------------------------------------------*/ + +/*--------------------- Patrick 26/11/96 -------------------------- + This function attempts to construct a series of valid + auxilary locations inside the module (provided it has entry points) + -----------------------------------------------------------------*/ +static void BuildFM_AuxilaryLocs(MODULE *thisModule) +{ + int gridStartX, gridStartZ, gridExtentX, gridExtentZ, XIndex, ZIndex; + int NumLocsValid = 0; + int NumLocsHeightFailed = 0; + int NumLocsVolFailed = 0; + int ThisModuleIndex; + AIMODULE* aimodule=thisModule->m_aimodule; + + /* get the module index */ + LOCALASSERT(aimodule); + ThisModuleIndex = aimodule->m_index; + LOCALASSERT(ThisModuleIndex >= 0); + LOCALASSERT(ThisModuleIndex < ModuleArraySize); + + gridStartX = thisModule->m_minx + (FAR_BB_WIDTH>>1); + gridStartZ = thisModule->m_minz + (FAR_BB_WIDTH>>1); + gridExtentX = thisModule->m_maxx - thisModule->m_minx - FAR_BB_WIDTH; + gridExtentZ = thisModule->m_maxz - thisModule->m_minz - FAR_BB_WIDTH; + + if(gridExtentX<=0 || gridExtentZ<=0) + { + //module is too narrow for auxilary locations + return; + } + + LOCALASSERT(gridStartX > thisModule->m_minx); + + /* step through each grid (index) location */ + for(XIndex = FAR_GRID_SIZE; XIndex > 0; XIndex--) + { + for(ZIndex = FAR_GRID_SIZE; ZIndex > 0; ZIndex--) + { + int locationsIndex = (XIndex-1)*FAR_GRID_SIZE + (ZIndex-1); + + auxLocsGrid[locationsIndex].position.vx = gridStartX + (gridExtentX*(XIndex-1))/(FAR_GRID_SIZE-1); + auxLocsGrid[locationsIndex].position.vz = gridStartZ + (gridExtentZ*(ZIndex-1))/(FAR_GRID_SIZE-1); + auxLocsGrid[locationsIndex].position.vy = 0; + auxLocsGrid[locationsIndex].valid = 1; /* validated by default */ + + /* get the floor height for this location. + If no valid height is found, the location is set to + minx,minz,miny, ie. outside of the grid, and abandoned */ + + GetFarLocHeight(&auxLocsGrid[locationsIndex], thisModule); + + /* if there's a valid floor height, check the volume around the location + for impinging polygons. If volume is impinged, the location is set to + minx,minz,miny, ie. outside of the grid, and abandoned */ + if(auxLocsGrid[locationsIndex].valid) + { + FarLocVolumeTest(&auxLocsGrid[locationsIndex], thisModule); + if(auxLocsGrid[locationsIndex].valid) + { + + AddVector(&thisModule->m_world,&auxLocsGrid[locationsIndex].position); + SubVector(&aimodule->m_world,&auxLocsGrid[locationsIndex].position); + NumLocsValid++; + } + else NumLocsVolFailed++; + } + else NumLocsHeightFailed++; + } + } + + + #if logFarLocData + fprintf(logfile, "Num valid locs: %d \n", NumLocsValid); + fprintf(logfile, "Num Height failed: %d \n", NumLocsHeightFailed); + fprintf(logfile, "Num Vol failed: %d \n \n", NumLocsVolFailed); + #endif + + /* now have a full list of locations.... + Those that are zero are invalid: hopefully some have survived */ + LOCALASSERT((NumLocsHeightFailed+NumLocsVolFailed+NumLocsValid) == (FAR_GRID_SIZE*FAR_GRID_SIZE)); + + /* If there are any valid locations remaining, store them in the locations list */ + if(NumLocsValid > 0) + { + /* Build a final and definitive list of valid locations for the module: + look at the number of valid locations. If there are more than the maximum + number, take a reasonably distributed sample. Otherwise just put them all in. + + NB this wil be a list of Local Space coordinates. + */ + + if(NumLocsValid > FAR_MAX_LOCS) + { + VECTORCH *destinationPtr; + int locationsIndex = 0; + + int numTaken = 0; + int numFound = 0; + int nextToTake = 0; + + /* fill out the header (space is preallocated) */ + destinationPtr = &FALLP_AuxLocs[ThisModuleIndex].locationsList[FALLP_AuxLocs[ThisModuleIndex].numLocations]; + FALLP_AuxLocs[ThisModuleIndex].numLocations += FAR_MAX_LOCS; + + numTaken=0; + nextToTake = NumLocsValid / FAR_MAX_LOCS; + + while(numTaken 0) + { + fprintf(logfile, "%d %d %d \n", tmpPtr->vx, tmpPtr->vz, tmpPtr->vy); + tmpPtr++; + tmpCounter--; + } + + fprintf(logfile,"\n"); + + } + #endif + } + else + { + /* No valid locations */ + #if logFarLocData + { + /* log an error */ + fprintf(logfile,"All auxilary locations FAILED \n"); + } + #endif + } +} + +/*----------------------Patrick 1/12/96-------------------------- + Given an x/z position for the shape, this function returns a + height value, by examining upwards facing polygons.... + To validate the height, there must also be a downwards facing + polgon above the upwards facing polygon (so that we know that + the location iiiiis inside the shape): if there is no up & + down polygon, the location is invalidated, and an error code + returned (either no up poly, no down poly, no up-or-down poly) + + NB PSX!!!: uses kevin's shape access functions in platsup.c + I have added a new short one for Win95 - PSX needs it's own + version. + ----------------------------------------------------------------*/ +static void GetFarLocHeight(FARVALIDATEDLOCATION *location, MODULE *thisModule) +{ + int polyCounter; + int heightOfUpPoly = thisModule->m_maxy; /* init to lowest module extent */ + int heightOfDownPoly = thisModule->m_miny; /* init to heighest module extent */ + int upPolyFound = 0; + int downPolyFound = 0; + int XZcontainment; + + struct ColPolyTag polygonData; + + polyCounter = SetupPolygonAccessFromShapeIndex(thisModule->m_mapptr->MapShape); + + /* loop through the item list, then ... */ + while(polyCounter>0) + { + AccessNextPolygon(); + GetPolygonVertices(&polygonData); + GetPolygonNormal(&polygonData); + + /* first test if poly is vertical */ + if((polygonData.PolyNormal.vy > FAR_MIN_INCLINE)||(polygonData.PolyNormal.vy < -FAR_MIN_INCLINE)) + { + XZcontainment = IsXZinPoly(&(location->position), &polygonData); + if(XZcontainment) + { + if(polygonData.PolyNormal.vy > 0) /* downwards facing */ + { + downPolyFound++; + { + /* find height of this poly: height of lowest vertex */ + int tmpHeight = polygonData.PolyPoint[0].vy; + + if(polygonData.PolyPoint[1].vy > tmpHeight) tmpHeight = polygonData.PolyPoint[1].vy; + if(polygonData.PolyPoint[2].vy > tmpHeight) tmpHeight = polygonData.PolyPoint[2].vy; + if(polygonData.NumberOfVertices == 4) + { + if(polygonData.PolyPoint[3].vy > tmpHeight) tmpHeight = polygonData.PolyPoint[2].vy; + } + + /* record height of lowest downward facing poly */ + if(tmpHeight > heightOfDownPoly) heightOfDownPoly = tmpHeight; + } + } + else /* upwards facing */ + { + upPolyFound++; + { + /* find height of this poly: height of highest vertex */ + int tmpHeight = polygonData.PolyPoint[0].vy; + + if(polygonData.PolyPoint[1].vy < tmpHeight) tmpHeight = polygonData.PolyPoint[1].vy; + if(polygonData.PolyPoint[2].vy < tmpHeight) tmpHeight = polygonData.PolyPoint[2].vy; + if(polygonData.NumberOfVertices == 4) + { + if(polygonData.PolyPoint[3].vy < tmpHeight) tmpHeight = polygonData.PolyPoint[2].vy; + } + + /* record height of heighest upward facing poly */ + if(tmpHeight < heightOfUpPoly) heightOfUpPoly = tmpHeight; + } + } + } + } + polyCounter--; + } + /* if up & down polys exist check their heights: + if there is not enough clearance bewteen the lowest down poly and the heighest up poly, + invalidate the location.*/ + if((upPolyFound!=0) && (downPolyFound!=0)) + { + int minclearance = FAR_BB_HEIGHT; + if(thisModule->m_flags & MODULEFLAG_AIRDUCT) minclearance>>=1; + if((heightOfUpPoly-heightOfDownPoly)>=minclearance) + { + //position the aux location slightly above the polygon + location->position.vy = heightOfUpPoly-10; + } + else location->valid = 0; + } + else location->valid = 0; + } + + +/*------------------ Patrick 3/12/96 ---------------------- + This function determines whether an x/z position lies + within the x/z projection of a polygon. + + NB is not entirely accurate for concave polygons. + ---------------------------------------------------------*/ +static int IsXZinPoly(VECTORCH* location, struct ColPolyTag *polygonData) +{ + int x = location->vx; + int z = location->vz; + int xa,za,xb,zb; + int intersections = 0; + int intersectMinz, intersectMaxz; + int linesToTest; + int nextLine; + + linesToTest = polygonData->NumberOfVertices; + + if(linesToTest == 3) + { + xa = polygonData->PolyPoint[2].vx; + za = polygonData->PolyPoint[2].vz; + } + else + { + LOCALASSERT(linesToTest == 4); + xa = polygonData->PolyPoint[3].vx; + za = polygonData->PolyPoint[3].vz; + } + + nextLine = 0; + + while(nextLine < linesToTest) + { + /* copy last first point to next last point (?) */ + xb = xa; + zb = za; + + /* get next first point */ + xa = polygonData->PolyPoint[nextLine].vx; + za = polygonData->PolyPoint[nextLine].vz; + + if(((x>=xb) && (x<=xa)) || ((x=xa))) + { + /* intesection ! */ + intersections++; + if(!(intersections<4)) return 0; + + { + int zPosn; + + if(xb==xa) + zPosn = za; + else + zPosn = zb + WideMulNarrowDiv((za-zb),(x-xb),(xa-xb)); + + if(intersections == 1) + intersectMinz = intersectMaxz = zPosn; + else + { + if(zPosn < intersectMinz) intersectMinz = zPosn; + else if(zPosn > intersectMaxz) intersectMaxz = zPosn; + } + } + } + nextLine++; + } + + if(intersections == 0) return 0; + if(intersections == 1) + return (z == intersectMinz); + else + return ((z >= intersectMinz)&&(z <= intersectMaxz)); + +} + + +/*--------------------Patrick 4/12/96-------------------- + This function checks a potential location for impinging + downward or sideways facing polygons (ie ceiling or floor). + This is done using a bounding box containment test. If + the test fails, it invalidates the location. + -------------------------------------------------------*/ + +static int farbbox_maxx; +static int farbbox_minx; +static int farbbox_maxy; +static int farbbox_miny; +static int farbbox_maxz; +static int farbbox_minz; +static struct ColPolyTag farbbox_polygonData; + +static int FarBoxContainsPolygon(); + +static void FarLocVolumeTest(FARVALIDATEDLOCATION *location, MODULE *thisModule) +{ + int polyCounter; + int containmentFailure = 0; + + LOCALASSERT(location->valid); + + /* the location is provided as an x,y,z: + the x and z indicate the centre, and the y indicates the bottom. + translate these into bounding box extents.... */ + + /* 10/7/97: this test has been modified: the bbox is moved up slightly, and any + impinging ploygon invalidates the location */ + + farbbox_maxx = location->position.vx + (FAR_BB_WIDTH>>1); + farbbox_minx = location->position.vx - (FAR_BB_WIDTH>>1); + farbbox_maxz = location->position.vz + (FAR_BB_WIDTH>>1); + farbbox_minz = location->position.vz - (FAR_BB_WIDTH>>1); + farbbox_maxy = location->position.vy - 10; + + /* patrick 4/7/97: a little adittion for airducts: npc should be crouched in them */ + if(thisModule->m_flags & MODULEFLAG_AIRDUCT) + farbbox_miny = location->position.vy - (FAR_BB_HEIGHT>>1) - 10; + else + farbbox_miny = location->position.vy - FAR_BB_HEIGHT - 10; + + /* now just run through the polygons in the shape. If a polygon is + inside (actually, not definitely outside) the bbox, invalidate the location */ + polyCounter = SetupPolygonAccessFromShapeIndex(thisModule->m_mapptr->MapShape); + while((polyCounter>0)&&(!containmentFailure)) + { + AccessNextPolygon(); + GetPolygonVertices(&farbbox_polygonData); + containmentFailure = FarBoxContainsPolygon(); + polyCounter--; + } + /* so, if there has been a containmentFailure, invalidate the location */ + if(containmentFailure) location->valid = 0; +} + +/*--------------------Patrick 5/12/96---------------------------------- + This does a bounding box extent test for a polygon. + NB returns false if the poly definitely isn't in the bbox, and returns + true if the poly is in the bbox, and for unresolved cases. + ----------------------------------------------------------------------*/ +static int FarBoxContainsPolygon() +{ + if(farbbox_polygonData.NumberOfVertices == 3) + { + if( (farbbox_polygonData.PolyPoint[0].vy<=farbbox_miny)&& + (farbbox_polygonData.PolyPoint[1].vy<=farbbox_miny)&& + (farbbox_polygonData.PolyPoint[2].vy<=farbbox_miny)) return 0; + + if( (farbbox_polygonData.PolyPoint[0].vx<=farbbox_minx)&& + (farbbox_polygonData.PolyPoint[1].vx<=farbbox_minx)&& + (farbbox_polygonData.PolyPoint[2].vx<=farbbox_minx)) return 0; + + if( (farbbox_polygonData.PolyPoint[0].vz<=farbbox_minz)&& + (farbbox_polygonData.PolyPoint[1].vz<=farbbox_minz)&& + (farbbox_polygonData.PolyPoint[2].vz<=farbbox_minz)) return 0; + + if( (farbbox_polygonData.PolyPoint[0].vz>=farbbox_maxz)&& + (farbbox_polygonData.PolyPoint[1].vz>=farbbox_maxz)&& + (farbbox_polygonData.PolyPoint[2].vz>=farbbox_maxz)) return 0; + + if( (farbbox_polygonData.PolyPoint[0].vx>=farbbox_maxx)&& + (farbbox_polygonData.PolyPoint[1].vx>=farbbox_maxx)&& + (farbbox_polygonData.PolyPoint[2].vx>=farbbox_maxx)) return 0; + + if( (farbbox_polygonData.PolyPoint[0].vy>=farbbox_maxy)&& + (farbbox_polygonData.PolyPoint[1].vy>=farbbox_maxy)&& + (farbbox_polygonData.PolyPoint[2].vy>=farbbox_maxy)) return 0; + } + else + { + if( (farbbox_polygonData.PolyPoint[0].vy<=farbbox_miny)&& + (farbbox_polygonData.PolyPoint[1].vy<=farbbox_miny)&& + (farbbox_polygonData.PolyPoint[2].vy<=farbbox_miny)&& + (farbbox_polygonData.PolyPoint[3].vy<=farbbox_miny)) return 0; + + if( (farbbox_polygonData.PolyPoint[0].vx<=farbbox_minx)&& + (farbbox_polygonData.PolyPoint[1].vx<=farbbox_minx)&& + (farbbox_polygonData.PolyPoint[2].vx<=farbbox_minx)&& + (farbbox_polygonData.PolyPoint[3].vx<=farbbox_minx)) return 0; + + if( (farbbox_polygonData.PolyPoint[0].vz<=farbbox_minz)&& + (farbbox_polygonData.PolyPoint[1].vz<=farbbox_minz)&& + (farbbox_polygonData.PolyPoint[2].vz<=farbbox_minz)&& + (farbbox_polygonData.PolyPoint[3].vz<=farbbox_minz)) return 0; + + if( (farbbox_polygonData.PolyPoint[0].vz>=farbbox_maxz)&& + (farbbox_polygonData.PolyPoint[1].vz>=farbbox_maxz)&& + (farbbox_polygonData.PolyPoint[2].vz>=farbbox_maxz)&& + (farbbox_polygonData.PolyPoint[3].vz>=farbbox_maxz)) return 0; + + if( (farbbox_polygonData.PolyPoint[0].vx>=farbbox_maxx)&& + (farbbox_polygonData.PolyPoint[1].vx>=farbbox_maxx)&& + (farbbox_polygonData.PolyPoint[2].vx>=farbbox_maxx)&& + (farbbox_polygonData.PolyPoint[3].vx>=farbbox_maxx)) return 0; + + if( (farbbox_polygonData.PolyPoint[0].vy>=farbbox_maxy)&& + (farbbox_polygonData.PolyPoint[1].vy>=farbbox_maxy)&& + (farbbox_polygonData.PolyPoint[2].vy>=farbbox_maxy)&& + (farbbox_polygonData.PolyPoint[3].vy>=farbbox_maxy)) return 0; + } + return 1; +} + diff --git a/3dc/avp/PFARLOCS.H b/3dc/avp/PFARLOCS.H new file mode 100644 index 0000000..277a5a3 --- /dev/null +++ b/3dc/avp/PFARLOCS.H @@ -0,0 +1,97 @@ + +/*------------------------Patrick 13/12/96----------------------------- + Header file for FAR AI alien module locations + --------------------------------------------------------------------*/ + +#ifndef _pfarlocs_h_ + #define _pfarlocs_h_ 1 + + #ifdef __cplusplus + extern "C" { + #endif + + +/* various structure definitions used for module's auxilary location and +entry point data and headers...*/ +typedef struct farlocationsheader +{ + int numLocations; + struct vectorch *locationsList; + +} FARLOCATIONSHEADER; + +typedef struct farvalidatedlocation +{ + int valid; + struct vectorch position; + +} FARVALIDATEDLOCATION; + +typedef struct farentrypoint +{ + struct vectorch position; + int donorIndex; + unsigned int alien_only:1; //this entry point can only be used by aliens + +} FARENTRYPOINT; + +typedef struct farentrypointsheader +{ + int numEntryPoints; + struct farentrypoint *entryPointsList; + +} FARENTRYPOINTSHEADER; + + +/* enum of the different door types, as seen by NPC's */ +typedef enum moduledoortype +{ + MDT_NotADoor, + MDT_ProxDoor, + MDT_LiftDoor, + MDT_SecurityDoor, + +} MODULEDOORTYPE; + + +/* globals */ +extern FARLOCATIONSHEADER *FALLP_AuxLocs; +extern FARENTRYPOINTSHEADER *FALLP_EntryPoints; + +/* defines for auxilary locations */ +#define FAR_BB_HEIGHT 2000 /* should be height of a crouched alien */ +#define FAR_BB_WIDTH 1000 /* should be the 'width' of an alien */ +#define FAR_POS_HEIGHT 680 /* how high of the floor to put the alien (1/2 alien height + a bit) */ +#define FAR_GRID_SIZE 6 +#define FAR_MAX_LOCS 5 +#define FAR_MIN_INCLINE 50 + +/* defines for entry points */ +#define EPBB_XTRA 100 +#define EP_POSNDISP 100 +#define EP_MAXPOINTS 200 +#define EP_MAXEDGES 200 + +/* defines for module door types insofar as they relate to alien behaviour +FADT stands for Far Alien Door Type*/ + + +/* prototypes */ +void BuildFarModuleLocs(void); +void KillFarModuleLocs(void); +MODULEDOORTYPE ModuleIsADoor(MODULE* target); +MODULEDOORTYPE AIModuleIsADoor(AIMODULE* target); +int ModuleIsPhysical(MODULE* target); +int AIModuleIsPhysical(AIMODULE* target); +int ModuleInModule(MODULE* target1, MODULE* target2); +int NumAdjacentModules(AIMODULE* target); +FARENTRYPOINT *GetModuleEP(MODULE* thisModule, MODULE*fromModule); +FARENTRYPOINT *GetAIModuleEP(AIMODULE* thisModule, AIMODULE*fromModule); +int PointIsInModule(MODULE* thisModule, VECTORCH* thisPoint); + + + #ifdef __cplusplus + } + #endif + +#endif \ No newline at end of file diff --git a/3dc/avp/PHEROMON.C b/3dc/avp/PHEROMON.C new file mode 100644 index 0000000..49b8144 --- /dev/null +++ b/3dc/avp/PHEROMON.C @@ -0,0 +1,648 @@ +/*-----------------------Patrick 12/11/96-------------------------- + Source for AVP Pheromone system + -----------------------------------------------------------------*/ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +#include "pheromon.h" +#include "pfarlocs.h" +#include "pvisible.h" +#include "bh_alien.h" +#include "bh_far.h" +#include "bh_gener.h" +#include "showcmds.h" +#include "pldghost.h" + +#if 1 +static unsigned int *Pher_Player1; +static unsigned int *Pher_Player2; +static unsigned char *Pher_Ai1; +#else +#define MaxModules 300 +static unsigned int Pher_Player1[MaxModules]; +static unsigned int Pher_Player2[MaxModules]; +static unsigned char Pher_Ai1[MaxModules]; +#endif + +/* these pointers indicate the current read from and write to +buffers for the player and ai pheromone systems */ +unsigned int *PherPl_ReadBuf; +unsigned int *PherPl_WriteBuf; +unsigned char *PherAi_Buf; + +#if SUPER_PHEROMONE_SYSTEM +static unsigned int *Pher_Aliens1; +static unsigned int *Pher_Aliens2; + +unsigned int *PherAls_ReadBuf; +unsigned int *PherAls_WriteBuf; + +unsigned int AlienPheromoneScale; + +/* Marine pheromones: a pathfinding system only. */ +static unsigned int *Pher_Marines1; +static unsigned int *Pher_Marines2; + +unsigned int *PherMars_ReadBuf; +unsigned int *PherMars_WriteBuf; + +#endif + +/* This global is used to store the current player phermone intensity */ +unsigned int PlayerSmell = 3; +MODULE *playerPherModule = (MODULE *)0; + +/* external globals */ +extern int AIModuleArraySize; + +/* this define enables diagnostic text 'dump' for pheromone system */ +#define logPheromoneDiagnostics 0 + +#if logPheromoneDiagnostics +static void LogPlayerPherValues(void); +static void LogModuleAdjacencies(void); +int printModAdj = 1; +#endif + +/*----------------------Patrick 12/11/96--------------------------- +Initialises pheromone systems +-------------------------------------------------------------------*/ +void InitPheromoneSystem(void) +{ + int i; + + #if 1 + /* allocate the pheromone buffers */ + Pher_Player1 = (unsigned int *)AllocateMem((AIModuleArraySize+1)*sizeof(unsigned int)); + if(!Pher_Player1) + { + memoryInitialisationFailure = 1; + return; + } + Pher_Player2 = (unsigned int *)AllocateMem((AIModuleArraySize+1)*sizeof(unsigned int)); + if(!Pher_Player2) + { + memoryInitialisationFailure = 1; + return; + } + Pher_Ai1 = (unsigned char *)AllocateMem((AIModuleArraySize+1)*sizeof(unsigned char)); + if(!Pher_Ai1) + { + memoryInitialisationFailure = 1; + return; + } + #endif + + #if SUPER_PHEROMONE_SYSTEM + Pher_Aliens1 = (unsigned int *)AllocateMem((AIModuleArraySize+1)*sizeof(unsigned int)); + if(!Pher_Aliens1) + { + memoryInitialisationFailure = 1; + return; + } + + Pher_Aliens2 = (unsigned int *)AllocateMem((AIModuleArraySize+1)*sizeof(unsigned int)); + if(!Pher_Aliens2) + { + memoryInitialisationFailure = 1; + return; + } + + Pher_Marines1 = (unsigned int *)AllocateMem((AIModuleArraySize+1)*sizeof(unsigned int)); + if(!Pher_Marines1) + { + memoryInitialisationFailure = 1; + return; + } + + Pher_Marines2 = (unsigned int *)AllocateMem((AIModuleArraySize+1)*sizeof(unsigned int)); + if(!Pher_Marines2) + { + memoryInitialisationFailure = 1; + return; + } + #endif + + /* init the player phermone system */ + for(i=0;im_module_ptrs); + pdbblk=((PROXDOOR_BEHAV_BLOCK *)renderModule->m_sbptr->SBdataptr); + + if (pdbblk->lockable_door) { + if (pdbblk->door_locked) { + return(0); + } else { + return(1); + } + } else { + if (pdbblk->door_locked) { + return(0); + } else { + return(1); + } + } + } + + case(MDT_LiftDoor): + { + GLOBALASSERT(targetModule->m_module_ptrs); + GLOBALASSERT(*(targetModule->m_module_ptrs)); + if(GetState((*(targetModule->m_module_ptrs))->m_sbptr)) { + /* Open. */ + return (1); + } else { + /* Closed. */ + return (0); + } + break; + } + + case(MDT_SecurityDoor): + { + GLOBALASSERT(targetModule->m_module_ptrs); + GLOBALASSERT(*(targetModule->m_module_ptrs)); + if(GetState((*(targetModule->m_module_ptrs))->m_sbptr)) { + /* Open. */ + return (1); + } else { + /* Closed. */ + return (0); + } + break; + } + + default: + { + LOCALASSERT(doorStatus==MDT_NotADoor); + return(1); + } + + } + +} + +#if SUPER_PHEROMONE_SYSTEM +void AddMarinePheromones(AIMODULE *targetModule) { + + int ThisModuleIndex; + + ThisModuleIndex = targetModule->m_index; + + PherAls_WriteBuf[ThisModuleIndex] += 3; + +} + +void MaintainMarineTargetZone(AIMODULE *targetModule) { + + int ThisModuleIndex; + + ThisModuleIndex = targetModule->m_index; + + PherMars_WriteBuf[ThisModuleIndex] += 3; + +} + +#endif + +/*----------------------Patrick 12/11/96--------------------------- +Updates the player pheromone system: +this is used by the NPC far behaviour for hunting the player. +-------------------------------------------------------------------*/ +void PlayerPheromoneSystem(void) +{ + int moduleCounter; + AIMODULE *ModuleListPointer; + AIMODULE *ThisModulePtr; + int ThisModuleIndex; + AIMODULE **AdjModuleRefPtr; + int AdjModuleIndex; + + + #if logPheromoneDiagnostics + if(printModAdj) + { + printModAdj = 0; + LogModuleAdjacencies(); + } + #endif + + + /* get a pointer to the global array of pointers to the modules + in the environment (interfaces'r'us). + First check if Global_ModulePtr is set. If not we're buggered, + so leave everything as it is and try again next frame*/ + { + extern AIMODULE *AIModuleArray; + + ModuleListPointer = AIModuleArray; + } + + + /* go through each module in the environment */ + for(moduleCounter = 0; moduleCounter < AIModuleArraySize; moduleCounter++) + { + + /* get a pointer to the next current module */ + ThisModulePtr = &(ModuleListPointer[moduleCounter]); + LOCALASSERT(ThisModulePtr); + + /* get it's index */ + ThisModuleIndex = ThisModulePtr->m_index; + + LOCALASSERT(ThisModuleIndex >= 0); + LOCALASSERT(ThisModuleIndex < AIModuleArraySize); + + + /* !!!!!!!!!!!!!!!!!!!!! + check for closed non-traversable door module here if detected, do not update its smell. + + Actually, no: allow smell to pass thro' non-openable doors. Otherwise AIs that can open + doors will choose not to + !!!!!!!!!!!!!!!!!!!!!!!!*/ + + /* CDF 4/12/97: Actually, yes. AIs CAN'T open security doors, fool! */ + + /* check for universal module: don't want to update this! */ + if(AIModuleIsPhysical(ThisModulePtr)) + { + + if (AIModuleAdmitsPheromones(ThisModulePtr)) { + /* get a pointer to the list of physically adjacent modules + and traverse them */ + + AdjModuleRefPtr = ThisModulePtr->m_link_ptrs; + + if(AdjModuleRefPtr) /* check that there is a list of adjacent modules */ + { + while(*AdjModuleRefPtr != 0) + { + /* get the index */ + AdjModuleIndex = (*AdjModuleRefPtr)->m_index; + + /* if adjacent module's previous smell is greater than + the current module's new smell (so far), then update + the current module's newq smell */ + if(PherPl_ReadBuf[AdjModuleIndex] > PherPl_WriteBuf[ThisModuleIndex]) + PherPl_WriteBuf[ThisModuleIndex] = (PherPl_ReadBuf[AdjModuleIndex] - 1); + + #if SUPER_PHEROMONE_SYSTEM + if(PherAls_ReadBuf[AdjModuleIndex] > PherAls_WriteBuf[ThisModuleIndex]) { + PherAls_WriteBuf[ThisModuleIndex] = (PherAls_ReadBuf[AdjModuleIndex] - 1); + } + + if (CheckAdjacencyValidity((*AdjModuleRefPtr),ThisModulePtr,0)) { + if(PherMars_ReadBuf[AdjModuleIndex] > PherMars_WriteBuf[ThisModuleIndex]) { + PherMars_WriteBuf[ThisModuleIndex] = (PherMars_ReadBuf[AdjModuleIndex] - 1); + } + } + #endif + + /* next adjacent module reference pointer */ + AdjModuleRefPtr++; + } + } + } + #if SUPER_PHEROMONE_SYSTEM + /* Decay pheromones. */ + if (PherAls_WriteBuf[ThisModuleIndex]>0) { + PherAls_WriteBuf[ThisModuleIndex]--; + } + + if (PherMars_WriteBuf[ThisModuleIndex]>0) { + PherMars_WriteBuf[ThisModuleIndex]--; + } + #endif + } + } + + /*If in a network game add pheromon's for other players*/ + if(AvP.Network!=I_No_Network && AvP.NetworkAIServer) + { + /* go through the strategy blocks looking for players*/ + int sbIndex; + for(sbIndex=0;sbIndexI_SBtype!=I_BehaviourNetGhost) continue; + ghostData = (NETGHOSTDATABLOCK *)playerSbPtr->SBdataptr; + + if(ghostData->type==I_BehaviourMarinePlayer || + ghostData->type==I_BehaviourPredatorPlayer) + { + /*this is another player*/ + if(playerSbPtr->containingModule) + { + PherPl_WriteBuf[playerSbPtr->containingModule->m_aimodule->m_index] = PlayerSmell; + AddMarinePheromones(playerSbPtr->containingModule->m_aimodule); + } + } + } + } + + /* That completed, find which module the player is in, set it's smell to the + current player smell value, and update the player smell for the next frame */ + { + extern DISPLAYBLOCK* Player; + VECTORCH playerPosition = Player->ObWorld; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + playerPherModule = (ModuleFromPosition(&playerPosition, playerPherModule)); + if(playerPherModule) + { + //the player must be alive to leave pheromones + //(mainly relevant in coop games) + if(playerStatusPtr->IsAlive) + { + PherPl_WriteBuf[playerPherModule->m_aimodule->m_index] = PlayerSmell; + #if SupportWindows95 + if(playerPherModule->name) + { + if (ShowDebuggingText.Module) + { + ReleasePrintDebuggingText("Player Module: %d '%s'\n", playerPherModule->m_index,playerPherModule->name); + ReleasePrintDebuggingText("Player Module Coords: %d %d %d\n",playerPherModule->m_world.vx,playerPherModule->m_world.vy,playerPherModule->m_world.vz); + } + #if SUPER_PHEROMONE_SYSTEM + AlienPheromoneScale+=3; + if (AlienPheromoneScale==0) AlienPheromoneScale=1; + { + unsigned int prop=DIV_FIXED(PherAls_WriteBuf[playerPherModule->m_aimodule->m_index],AlienPheromoneScale); + textprint("Alien readable pheromones in Player Module: %d\n",prop); + } + /* No scale for 'marine' pheromones, the player will never see it. */ + #endif + } + #endif + } + } + } + + PlayerSmell++; + + #if SUPER_PHEROMONE_SYSTEM + /* Note that marines should add pheromones at the AI level... */ + { + unsigned int *tempBufPointer = PherAls_ReadBuf; + PherAls_ReadBuf = PherAls_WriteBuf; + PherAls_WriteBuf= tempBufPointer; + } + /* As should the pathfinding system. */ + { + unsigned int *tempBufPointer = PherMars_ReadBuf; + PherMars_ReadBuf = PherMars_WriteBuf; + PherMars_WriteBuf= tempBufPointer; + } + #endif + + /* swap the read and write buffers: + behaviours access most recent data thro' the read buffer */ + { + unsigned int *tempBufPointer = PherPl_ReadBuf; + PherPl_ReadBuf = PherPl_WriteBuf; + PherPl_WriteBuf = tempBufPointer; + } + + #if logPheromoneDiagnostics + LogPlayerPherValues(); + #endif + + +} + + +/*----------------------Patrick 14/11/96--------------------------- +Ai Pheromone system. + +This system just keeps track of how many aliens are in each module, +and is calculated from scratch at the start of each frame. +Also, the numactivealiens bit of the hive data block is calculated +for this frame. +-------------------------------------------------------------------*/ +void AiPheromoneSystem(void) +{ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + + int sbIndex = 0; + STRATEGYBLOCK *sbPtr; + int i; + + /* first, zero the buffer, and hive counter */ + for(i=0;iI_SBtype == I_BehaviourAlien)||(sbPtr->I_SBtype == I_BehaviourMarine)) + { + if(sbPtr->containingModule) + { + PherAi_Buf[(sbPtr->containingModule->m_aimodule->m_index)]++; + } + } + } +} + + + +#if logPheromoneDiagnostics + + /* write out a list of module ajacencies */ + +static void LogModuleAdjacencies(void) +{ + extern SCENE Global_Scene; + extern SCENEMODULE **Global_ModulePtr; + + GLOBALASSERT(0); + + /* This function does not use AI modules yet! */ + + FILE *logFile; + int i; + SCENEMODULE *ScenePtr; + MODULE **ModuleListPointer; + MODULE *ThisModulePtr; + int ThisModuleIndex; + MREF *AdjModuleRefPtr; + int AdjModuleIndex; + + LOCALASSERT(Global_ModulePtr != 0); + + ScenePtr = Global_ModulePtr[Global_Scene]; + ModuleListPointer = ScenePtr->sm_marray; + + logFile = fopen("D:/PATRICK/MODADJ.TXT","w"); + + if(logFile) + { + + LOCALASSERT(ModuleArraySize); + + for(i = 0; i < ModuleArraySize; i++) + { + ThisModulePtr = ModuleListPointer[i]; + LOCALASSERT(ThisModulePtr); + + /* get it's index */ + ThisModuleIndex = ThisModulePtr->m_index; + + LOCALASSERT(ThisModuleIndex >= 0); + LOCALASSERT(ThisModuleIndex < ModuleArraySize); + + fprintf(logFile, "Module %d Adjoing modules: ", ThisModuleIndex); + + /* get a pointer to the list of physically adjacent modules + and traverse them */ + AdjModuleRefPtr = ThisModulePtr->m_link_ptrs; + if(AdjModuleRefPtr == 0) + { + fprintf(logFile, " None/n"); + } + else + { + while(AdjModuleRefPtr->mref_ptr != 0) + { + /* get the index */ + AdjModuleIndex = (AdjModuleRefPtr->mref_ptr)->m_index; + + fprintf(logFile, " %d,", AdjModuleIndex); + + /* next adjacent module reference pointer */ + AdjModuleRefPtr++; + } + + fprintf(logFile, "\n"); + } + + } + + fclose(logFile); + + + } + + /* also, initialise pheromone value file */ + + logFile = fopen("D:/PATRICK/MODPPHER.TXT","w"); + + if(logFile) + { + fprintf(logFile, "PLAYER PHEROMONE VALUES \n"); + fclose(logFile); + } + + +} + + +/* Log the player pheromone values */ +static void LogPlayerPherValues(void) +{ + FILE *logFile; + int i; + + logFile = fopen("D:/PATRICK/MODPPHER.TXT","a"); + if (!logFile) return; + + fprintf(logFile, "\n ***************************** \n"); + + for(i=0;iObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + /* init a pointer to the weapon's data */ + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + + if (sadarReloadTimer) + { + sadarReloadTimer -= NormalFrameTime; + if (sadarReloadTimer <= 0) + { + sadarReloadTimer = 0; + playerNoise=1; + } + } + + /* Handle weapon reloading */ + #if 0 + if (weaponPtr->CurrentState == WEAPONSTATE_RELOAD_PRIMARY) + { + if (weaponReloading == 0) + { + weaponReloading = 1; + + switch (weaponPtr->WeaponIDNumber) + { + case WEAPON_SADAR: + sadarReloadTimer = ONE_FIXED; + break; + case WEAPON_GRENADELAUNCHER: + Sound_Play(SID_NADELOAD,"h"); + playerNoise=1; + break; + case WEAPON_FLAMETHROWER: + /* Flame thrower reload? */ + break; + case WEAPON_SMARTGUN: + Sound_Play(SID_LONGLOAD,"h"); + playerNoise=1; + break; + case WEAPON_FRISBEE_LAUNCHER: + sadarReloadTimer = ONE_FIXED; + break; + case WEAPON_GRENADELAUNCHER: + Sound_Play(SID_NADELOAD,"h"); + playerNoise=1; + break; + default: + Sound_Play(SID_SHRTLOAD,"h"); + playerNoise=1; + break; + } + } + } + else + { + weaponReloading = 0; + } + #endif + + switch(weaponPtr->WeaponIDNumber) + { + case(WEAPON_PRED_PISTOL): + { + if(weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + if(weaponHandle == SOUND_NOACTIVEINDEX) + { + //Sound_Play(SID_PULSE_START,"hp",-PRED_PISTOL_PITCH_CHANGE); + //Sound_Play(SID_PULSE_LOOP,"elhp",&weaponHandle,-PRED_PISTOL_PITCH_CHANGE); + //weaponPitchTimer=ONE_FIXED>>3; + Sound_Play(SID_PRED_PISTOL,"h"); + playerNoise=1; + } + else + { + //weaponPitchTimer-=NormalFrameTime; + //if (weaponPitchTimer<=0) + //{ + // weaponPitchTimer=ONE_FIXED>>3; + // Sound_ChangePitch(weaponHandle,(FastRandom()&63)-(32+PRED_PISTOL_PITCH_CHANGE)); + //} + } + } + else + { + //if(weaponHandle != SOUND_NOACTIVEINDEX) + //{ + //if (ActiveSounds[weaponHandle].soundIndex == SID_PULSE_LOOP) + //{ + // Sound_Play(SID_PULSE_END,"hp",-PRED_PISTOL_PITCH_CHANGE); + // Sound_Stop(weaponHandle); + //} + //} + } + break; + } + + case(WEAPON_PULSERIFLE): + { + if(weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + if(weaponHandle == SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_PULSE_START,"h"); + Sound_Play(SID_PULSE_LOOP,"elh",&weaponHandle); + playerNoise=1; + weaponPitchTimer=ONE_FIXED>>3; + } + else + { + weaponPitchTimer-=NormalFrameTime; + if (weaponPitchTimer<=0) + { + weaponPitchTimer=ONE_FIXED>>3; + Sound_ChangePitch(weaponHandle,(FastRandom()&63)-32); + playerNoise=1; + } + } + } + else if (weaponPtr->CurrentState == WEAPONSTATE_FIRING_SECONDARY) + { + if (weaponHandle == SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_NADEFIRE,"h"); + playerNoise=1; + } + } + else + { + if(weaponHandle != SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_PULSE_END,"h"); + Sound_Stop(weaponHandle); + } + } + break; + } + + case(WEAPON_FLAMETHROWER): + { + if(weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + if(weaponHandle == SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_INCIN_START,"h"); + Sound_Play(SID_INCIN_LOOP,"elh",&weaponHandle); + playerNoise=1; + } + } + else + { + if(weaponHandle != SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_INCIN_END,"h"); + Sound_Stop(weaponHandle); + } + } + break; + } + + case (WEAPON_MINIGUN): + { + #if 0 + if(weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + if(weaponHandle == SOUND_NOACTIVEINDEX) { + Sound_Play(SID_MINIGUN_LOOP,"elh",&weaponHandle); + playerNoise=1; + } + } + else + { + if(weaponHandle != SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_MINIGUN_END,"h"); + Sound_Stop(weaponHandle); + } + } + #else + if (PlayerStatusPtr->IsAlive==0) { + if(weaponHandle != SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_MINIGUN_END,"h"); + Sound_Stop(weaponHandle); + } + } + #endif + break; + } + + case (WEAPON_AUTOSHOTGUN): + { + if (weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + Sound_Play(SID_SHOTGUN,"h"); + playerNoise=1; + } + break; + } + + case (WEAPON_MARINE_PISTOL): + case (WEAPON_TWO_PISTOLS): + { + if ((weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + ||(weaponPtr->CurrentState == WEAPONSTATE_FIRING_SECONDARY)) + { + Sound_Play(SID_SHOTGUN,"h"); + playerNoise=1; + } + + break; + } + + case (WEAPON_SADAR): + { + if (weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + Sound_Play(SID_SADAR_FIRE,"h"); + playerNoise=1; + } + break; + } + + case (WEAPON_FRISBEE_LAUNCHER): + { + if (weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + playerNoise=1; + if (weaponHandle == SOUND_NOACTIVEINDEX) { + Sound_Play(SID_ED_SKEETERCHARGE,"eh",&weaponHandle); + } + } else { + if (weaponHandle == SOUND_NOACTIVEINDEX) { + playerNoise=0; + } + } + } else { + if (weaponHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(weaponHandle); + } + } + break; + } + + + case(WEAPON_SMARTGUN): + { + if(weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + if(weaponHandle == SOUND_NOACTIVEINDEX) + { + unsigned int rand=FastRandom() % 3; + if (rand == oldRandomValue) rand=(rand + 1) % 3; + oldRandomValue = rand; + playerNoise=1; + switch (rand) + { + case 0: + { + Sound_Play(SID_SMART1,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 1: + { + Sound_Play(SID_SMART2,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 2: + { + Sound_Play(SID_SMART3,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + default: + { + break; + } + } + } + } + break; + } + + case(WEAPON_GRENADELAUNCHER): + { + if(weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + if(playOneShotWS) + { + Sound_Play(SID_ROCKFIRE,"h"); + playerNoise=1; + playOneShotWS = 0; + } + } + else playOneShotWS = 1; + break; + } + + case(WEAPON_PRED_WRISTBLADE): + { + #if 0 + if(weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + if(playOneShotWS) + { + unsigned int rand=FastRandom() % 6; + if (rand == oldRandomValue) rand = (rand + 1) % 6; + oldRandomValue = rand; + switch (rand) + { + case 0: + { + Sound_Play(SID_SWIPE,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 1: + { + Sound_Play(SID_SWIPE2,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 2: + { + Sound_Play(SID_SWIPE3,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 3: + { + Sound_Play(SID_SWIPE4,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 4: + { + Sound_Play(SID_PRED_SLASH,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 5: + { + Sound_Play(SID_RIP,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + default: + { + break; + } + } + playOneShotWS = 0; + } + } + else playOneShotWS = 1; + #endif + break; + } + + case(WEAPON_ALIEN_CLAW): + { + #if 0 + if(weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + if(playOneShotWS) + { + unsigned int rand=FastRandom() & 3; + if (rand == oldRandomValue) rand=(rand + 1) & 3; + + oldRandomValue = rand; + switch (rand) + { + case 0: + { + Sound_Play(SID_SWIPE,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 1: + { + Sound_Play(SID_SWIPE2,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 2: + { + Sound_Play(SID_SWIPE3,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 3: + { + Sound_Play(SID_SWIPE4,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + default: + { + break; + } + } + playOneShotWS = 0; + } + } else { + playOneShotWS = 1; + } + #endif + break; + } + + case(WEAPON_ALIEN_GRAB): + { + #if 0 + if(weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + if(playOneShotWS) + { + unsigned int rand=FastRandom() & 1; + if (rand == oldRandomValue) rand=(rand + 1) & 1; + oldRandomValue = rand; + switch (rand) + { + case 0: + { + Sound_Play(SID_SWISH,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 1: + { + Sound_Play(SID_TAIL,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + + default: + { + break; + } + } + playOneShotWS = 0; + } + } + else playOneShotWS = 1; + #endif + break; + } + + case(WEAPON_PRED_RIFLE): + { + if(weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + if(playOneShotWS) + { + Sound_Play(SID_PRED_LASER,"hp",(FastRandom()&255)-128); + playerNoise=1; + playOneShotWS = 0; + } + } + else playOneShotWS = 1; + break; + } + + case(WEAPON_PRED_SHOULDERCANNON): + { + if(weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + if(playOneShotWS) + { + //Sound_Play(SID_PRED_LAUNCHER,"hp",(FastRandom()&255)-128); + playOneShotWS = 0; + } + } + else playOneShotWS = 1; + break; + } + + case(WEAPON_PRED_DISC): + { + if(weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + if(playOneShotWS) + { + Sound_Play(SID_PRED_FRISBEE,"hp",(FastRandom()&255)-128); + playerNoise=1; + playOneShotWS = 0; + } + } + else playOneShotWS = 1; + break; + } + + case(WEAPON_ALIEN_SPIT): + { + if(weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) + { + if(playOneShotWS) + { + Sound_Play(SID_ACID_SPRAY,"hp",(FastRandom()&255)-128); + playerNoise=1; + playOneShotWS = 0; + } + } + else playOneShotWS = 1; + break; + } + default: + { + break; + } + } +} + +static int SpotEffectWeaponHandle = SOUND_NOACTIVEINDEX; +void PlayWeaponClickingNoise(enum WEAPON_ID weaponIDNumber) +{ + if(SpotEffectWeaponHandle != SOUND_NOACTIVEINDEX) + return; + + switch(weaponIDNumber) + { + // Marine weapons + case WEAPON_PULSERIFLE: + { + Sound_Play(SID_PULSE_RIFLE_FIRING_EMPTY,"eh",&SpotEffectWeaponHandle); + break; + } + case WEAPON_SMARTGUN: + { + Sound_Play(SID_NOAMMO,"eh",&SpotEffectWeaponHandle); + break; + } + case WEAPON_MINIGUN: + { + #if 0 + Sound_Play(SID_MINIGUN_EMPTY,"eh",&SpotEffectWeaponHandle); + #endif + break; + } + // Predator weapons + case WEAPON_PRED_RIFLE: + { + Sound_Play(SID_PREDATOR_SPEARGUN_EMPTY,"eh",&SpotEffectWeaponHandle); + break; + } + + default: + break; + } +} + + +void MakeRicochetSound(VECTORCH *position) +{ + switch(NormalFrameTime&0x3) + { + case(0): + Sound_Play(SID_RICOCH1,"pd",((FastRandom()&255)-128),position); + break; + case(1): + Sound_Play(SID_RICOCH2,"pd",((FastRandom()&255)-128),position); + break; + case(2): + Sound_Play(SID_RICOCH3,"pd",((FastRandom()&255)-128),position); + break; + case(3): + Sound_Play(SID_RICOCH4,"pd",((FastRandom()&255)-128),position); + break; + default: + break; + } +} + + + +void PlayAlienSwipeSound(void) { + + #if 0 + unsigned int rand=FastRandom() & 3; + if (rand == oldRandomValue) rand=(rand + 1) & 3; + + oldRandomValue = rand; + switch (rand) + { + case 0: + { + Sound_Play(SID_SWIPE,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 1: + { + Sound_Play(SID_SWIPE2,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 2: + { + Sound_Play(SID_SWIPE3,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 3: + { + Sound_Play(SID_SWIPE4,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + default: + { + break; + } + } + #else + PlayAlienSound(0,ASC_Swipe,((FastRandom()&255)-128), + &weaponHandle,NULL); + #endif +} + +void PlayAlienTailSound(void) { + + PlayAlienSound(0,ASC_TailSound,((FastRandom()&255)-128), + &weaponHandle,NULL); + +} + +void PlayPredSlashSound(void) { + + #if 0 + unsigned int rand=FastRandom() % 6; + if (rand == oldRandomValue) rand = (rand + 1) % 6; + oldRandomValue = rand; + switch (rand) + { + case 0: + { + Sound_Play(SID_SWIPE,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 1: + { + Sound_Play(SID_SWIPE2,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 2: + { + Sound_Play(SID_SWIPE3,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 3: + { + Sound_Play(SID_SWIPE4,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 4: + { + Sound_Play(SID_SWIPE3,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 5: + { + Sound_Play(SID_SWIPE2,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + default: + { + break; + } + } + #else + PlayPredatorSound(0,PSC_Swipe,((FastRandom()&255)-128), + &weaponHandle,NULL); + #endif +} + +void PlayCudgelSound(void) { + + unsigned int rand=FastRandom() % 4; + if (rand == oldRandomValue) rand = (rand + 1) % 4; + oldRandomValue = rand; + switch (rand) + { + case 0: + { + Sound_Play(SID_PULSE_SWIPE01,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 1: + { + Sound_Play(SID_PULSE_SWIPE02,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 2: + { + Sound_Play(SID_PULSE_SWIPE03,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + case 3: + { + Sound_Play(SID_PULSE_SWIPE04,"ehp",&weaponHandle,(FastRandom()&255)-128); + break; + } + default: + { + break; + } + } + +} + + +char * SecondSoundDir = 0; +static const char * FirstSoundDir = "SOUND\\"; +static char *CommonSoundDirectory = ".\\SOUND\\COMMON\\"; + +int FindAndLoadWavFile(int soundNum,char* wavFileName) +{ + static char sound_name[200]; + sprintf (sound_name, "%s%s", FirstSoundDir,wavFileName); + +#if LOAD_SOUND_FROM_FAST_FILE + //first look in fast file + { + unsigned nLen; + if(ffreadbuf(sound_name,&nLen)) + { + return LoadWavFromFastFile(soundNum,sound_name); + } + } +#endif + +#if !LOAD_SOUND_FROM_FAST_FILE_ONLY + //look for sound locally + { + + { + //check to see if file exists locally first + FILE* wavFile=fopen(sound_name,"rb"); + + if(!wavFile && SecondSoundDir) + { + //look for sound over network + sprintf (sound_name, "%s%s", SecondSoundDir,wavFileName); + + wavFile=fopen(sound_name,"rb"); + if(!wavFile) + { + LOGDXFMT(("Failed to find %s\n",wavFileName)); + return 0; + } + + } + fclose(wavFile); + } + + return LoadWavFile(soundNum,sound_name) ; + } +#else + LOGDXFMT(("Failed to find %s\n",wavFileName)); + return 0; +#endif +} + + + +/* Patrick 5/6/97 ------------------------------------------------------------- + Sound data loaders + ----------------------------------------------------------------------------*/ +#if USE_REBSND_LOADERS +extern unsigned char *ExtractWavFile(int soundIndex, unsigned char *bufferPtr); +void *LoadRebSndFile(char *filename) +{ + void *bufferPtr; + long int save_pos, size_of_file; + FILE *fp; + fp = fopen(filename,"rb"); + + if (!fp) goto error; + + save_pos=ftell(fp); + fseek(fp,0L,SEEK_END); + size_of_file=ftell(fp); + fseek(fp,save_pos,SEEK_SET); + + bufferPtr = AllocateMem(size_of_file); + LOCALASSERT(bufferPtr); + + + if (!fread(bufferPtr, size_of_file,1,fp)) + { + fclose(fp); + DeallocateMem(bufferPtr); + goto error; + } + + fclose(fp); + return bufferPtr; + +error: + { + return 0; + } +} + +void ReleaseRebSndFile(void *bufferPtr) +{ + LOCALASSERT(bufferPtr); + DeallocateMem(bufferPtr); +} + +void LoadSounds(char *soundDirectory) +{ + void *rebSndBuffer; + unsigned char *bufferPtr; + int soundIndex; + int pitch; + + LOCALASSERT(soundDirectory); + + /* first check that sound has initialised and is turned on */ + if(!SoundSys_IsOn()) return; + + /* load RebSnd file into a (big) buffer */ + { + char filename[64]; + #if ALIEN_DEMO + strcpy(filename, ".\\alienfastfile");//CommonSoundDirectory); + #else + strcpy(filename, ".\\fastfile");//CommonSoundDirectory); + #endif +// strcat(filename, soundDirectory); + strcat(filename, "\\"); +// strcat(filename, soundDirectory); +// strcat(filename, ".RebSnd"); + strcat(filename, "common.ffl"); + + rebSndBuffer = LoadRebSndFile(filename); + + if (!rebSndBuffer) + { + LOCALASSERT(0); + return; + } + } + + /* Process the file */ + bufferPtr = (unsigned char*) rebSndBuffer; + soundIndex = (int)(*bufferPtr++); + pitch = (int)((signed char)(*bufferPtr++)); + while((soundIndex!=0xff)||(pitch!=-1)) + { + if((soundIndex<0)||(soundIndex>=SID_MAXIMUM)) + { + /* invalid sound number */ + LOCALASSERT("Invalid Sound Index"==0); + } + if(GameSounds[soundIndex].loaded) + { + /* Duplicate game sound loaded */ + LOCALASSERT("Duplicate game sound loaded"==0); + } + + bufferPtr = ExtractWavFile(soundIndex, bufferPtr); + + GameSounds[soundIndex].loaded = 1; + GameSounds[soundIndex].activeInstances = 0; + GameSounds[soundIndex].volume = VOLUME_DEFAULT; + + /* pitch offset is in semitones: need to convert to 1/128ths */ + GameSounds[soundIndex].pitch = pitch; + + InitialiseBaseFrequency(soundIndex); + soundIndex = (int)(*bufferPtr++); + pitch = (int)((signed char)(*bufferPtr++)); + } + + ReleaseRebSndFile(rebSndBuffer); +} +#else +void LoadSounds(char *soundDirectory) +{ + char soundFileName[48]; + char fileLine[128]; + FILE *myFile; + int soundNum; + int pitchOffset; + int ok; + + LOCALASSERT(soundDirectory); + + /* first check that sound has initialised and is turned on */ + if(!SoundSys_IsOn()) return; + + /* construct the sound list file name, and load it */ + // strcpy((char*)&soundFileName, gameSoundDirectory); + // strcat((char*)&soundFileName, soundDirectory); + // strcat((char*)&soundFileName, "\\"); + strcpy((char*)&soundFileName, CommonSoundDirectory); + strcat((char*)&soundFileName, soundDirectory); + strcat((char*)&soundFileName, ".SL"); + myFile = fopen(soundFileName,"rt"); + LOCALASSERT(myFile!=NULL); + + /* just return if we can't find the file */ + if(!myFile) return; + + /* Process the file */ + while(fgets((char*)fileLine,128,myFile)) + { + char wavFileName[128]; + if(!strncmp((char*)fileLine,"//",2)) continue; /* comment */ + if(strlen((char*)fileLine) < 4) continue; /* blank line, or something */ + + + /* Assume the string is a valid wav file reference */ + soundNum = atoi(strtok(fileLine,", \n")); + strcpy((char*)&wavFileName,"Common\\"); + strcat((char*)&wavFileName,strtok(NULL,", \n")); + + /* pitch offset is in semitones: need to convert to 1/128ths */ + pitchOffset = PITCH_DEFAULTPLAT + (atoi(strtok(NULL,", \n"))*128); + + if((soundNum<0)||(soundNum>=SID_MAXIMUM)) continue; /* invalid sound number */ + if(GameSounds[soundNum].loaded) continue; /* Duplicate game sound loaded */ + ok = FindAndLoadWavFile(soundNum, wavFileName); + + /* Fill in the GameSound: the pointer to the ds buffer is filled in by + the wav file loader, if everthing went ok. If the load failed, do not + fill in the game sound data: it should remain initialised */ + if(ok) + { + GameSounds[soundNum].loaded = 1; + GameSounds[soundNum].activeInstances = 0;; + GameSounds[soundNum].volume = VOLUME_DEFAULT; + GameSounds[soundNum].pitch = pitchOffset; + InitialiseBaseFrequency(soundNum); + } + } + fclose(myFile); + + db_log1("loaded all the sounds."); +} +#endif \ No newline at end of file diff --git a/3dc/avp/PSNDPROJ.H b/3dc/avp/PSNDPROJ.H new file mode 100644 index 0000000..cebc6a5 --- /dev/null +++ b/3dc/avp/PSNDPROJ.H @@ -0,0 +1,426 @@ +/* Patrick 5/6/97 ------------------------------------------------------------- + AvP Project sound header + ----------------------------------------------------------------------------*/ +#ifndef PSNDPROJ_H +#define PSNDPROJ_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Andy 12/6/97 -------------------------------------------------------------- + Some background sound defines +----------------------------------------------------------------------------*/ +#define BACKGROUND_VOLUME 80 +#define BACKGROUND_ATTENUATION 5 +#define ZONE_WIDTH_SHIFT 15 // Size of the sound zones (log 2) + +#define ZONE_WIDTH 1<I_SBtype == I_BehaviourAlien)|| + (sbPtr->I_SBtype == I_BehaviourMarine)|| + (sbPtr->I_SBtype == I_BehaviourInanimateObject)|| + (sbPtr->I_SBtype == I_BehaviourVideoScreen)|| + (sbPtr->I_SBtype == I_BehaviourQueenAlien)|| + (sbPtr->I_SBtype == I_BehaviourFaceHugger)|| + (sbPtr->I_SBtype == I_BehaviourPredator)|| + (sbPtr->I_SBtype == I_BehaviourAutoGun)|| + (sbPtr->I_SBtype == I_BehaviourPlatform)|| + (sbPtr->I_SBtype == I_BehaviourBinarySwitch && sbPtr->DynPtr)||/*Allow for switches with no shape*/ + (sbPtr->I_SBtype == I_BehaviourLinkSwitch && sbPtr->DynPtr)|| + (sbPtr->I_SBtype == I_BehaviourTrackObject)|| + (sbPtr->I_SBtype == I_BehaviourFan)|| + (sbPtr->I_SBtype == I_BehaviourPlacedHierarchy)|| + (sbPtr->I_SBtype == I_BehaviourPlacedLight)|| + (sbPtr->I_SBtype == I_BehaviourXenoborg)|| + (sbPtr->I_SBtype == I_BehaviourSeal)|| + (sbPtr->I_SBtype == I_BehaviourDatabase)|| + (sbPtr->I_SBtype == I_BehaviourDummy)|| + (sbPtr->I_SBtype == I_BehaviourPredatorAlien) + ) + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + sbPtr->containingModule = ModuleFromPosition(&(dynPtr->Position), (MODULE *)0); + + sbPtr->maintainVisibility = 1; + + + } + else + { + /* just in case ... */ + if(sbPtr->I_SBtype != I_BehaviourGenerator && + sbPtr->I_SBtype != I_BehaviourMarinePlayer) + { + sbPtr->containingModule = (MODULE *)0; + } + sbPtr->maintainVisibility = 0; + } + + } + + /* initialise each object's visibility */ + DoObjectVisibilities(); + +} + + +/*----------------------Patrick 13/1/97----------------------------- +This function should be called after the dynamics, and before +rendering (ie via Cris H's module handler call-back function). + +It identifies appropriate strategy blocks in the current block list, +(those which have a non-zero 'containingModule' field), and calls +DoObjectVisibility(). +--------------------------------------------------------------------*/ + +void DoObjectVisibilities(void) +{ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + + int sbIndex = 0; + STRATEGYBLOCK *sbPtr; + + /* loop thro' the strategy block list, looking for objects that need to have + their visibilities managed ... */ + while(sbIndex < NumActiveStBlocks) + { + sbPtr = ActiveStBlockList[sbIndex++]; + if(sbPtr->maintainVisibility) + DoObjectVisibility(sbPtr); + } +} + + +void DoObjectVisibility(STRATEGYBLOCK *sbPtr) +{ + if(!(sbPtr->SBdptr)) + { + /* Note that we don't call modulefromposition() for far objects, as they mostly don't + move, and those that do (eg AIs) move to precalculated positions in modules. Thus + invisible objects are responsible for looking after their own containingModule field. + This should always be ok: we should always have a correct and valid containing + module. However, we will do a paranoia check for a null containingModule... */ + if(!sbPtr->containingModule) + { + textprint("Calling Far EmergencyRelocateObject, On object %x, type %d!\n",(int)sbPtr, sbPtr->I_SBtype); + IdentifyObject(sbPtr); + if(!(EmergencyRelocateObject(sbPtr))) { + textprint("Relocate failed!\n"); + return; + } + } + if (!sbPtr->containingModule) + { + textprint("Relocate failed and reported success\n"); + return; + } + + /* Now do the visibility check: the object has no display block, so check if + it's module is visible. If so, make the object visibile too. */ + + + if ( (sbPtr->I_SBtype == I_BehaviourPlacedLight) + &&ThisObjectIsInAModuleVisibleFromCurrentlyVisibleModules(sbPtr)) + { + MakePlacedLightNear(sbPtr); + return; + } + else if (sbPtr->I_SBtype == I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + if (ghostDataPtr && ghostDataPtr->type == I_BehaviourFlareGrenade) + { + if(ThisObjectIsInAModuleVisibleFromCurrentlyVisibleModules(sbPtr)) + { + MakeGhostNear(sbPtr); + return; + } + } + } + else if (sbPtr->I_SBtype == I_BehaviourPlatform) + { + PLATFORMLIFT_BEHAVIOUR_BLOCK *platformliftdata = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr; + //platform lift needs to be made near if its module near or + //if it is moving + if(ModuleCurrVisArray[(sbPtr->containingModule->m_index)] || + platformliftdata->state==PLBS_GoingUp || + platformliftdata->state==PLBS_GoingDown) + { + MakeObjectNear(sbPtr); + return; + } + } + + if(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]) + { + /* module is visible, so make object visible too */ + switch(sbPtr->I_SBtype) + { + case(I_BehaviourAlien): + { + MakeAlienNear(sbPtr); + break; + } + case(I_BehaviourVideoScreen): + { + MakeObjectNear(sbPtr); + if(sbPtr->SBdptr) AddLightingEffectToObject(sbPtr->SBdptr,LFX_FLARE); + break; + } + case(I_BehaviourRubberDuck): + case(I_BehaviourInanimateObject): + { + MakeObjectNear(sbPtr); + break; + } + case(I_BehaviourAutoGun): + { + MakeSentrygunNear(sbPtr); + break; + } + case(I_BehaviourPlatform): + { + MakeObjectNear(sbPtr); + break; + } + case(I_BehaviourBinarySwitch): + { + MakeObjectNear(sbPtr); + break; + } + case(I_BehaviourDatabase): + { + MakeObjectNear(sbPtr); + break; + } + case(I_BehaviourLinkSwitch): + { + MakeObjectNear(sbPtr); + break; + } + case(I_BehaviourPredator): + { + MakePredatorNear(sbPtr); + break; + } + case(I_BehaviourXenoborg): + { + MakeXenoborgNear(sbPtr); + break; + } + case(I_BehaviourQueenAlien): + { + MakeQueenNear(sbPtr); + break; + } + case(I_BehaviourPredatorAlien): + { + GLOBALASSERT(0); + //MakePAQNear(sbPtr); + break; + } + case(I_BehaviourFaceHugger): + { + MakeFacehuggerNear(sbPtr); + break; + } + case(I_BehaviourMarine): + { + MakeMarineNear(sbPtr); + break; + } + case(I_BehaviourSeal): + { + MakeMarineNear(sbPtr); + break; + } + case(I_BehaviourNetGhost): + { + NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + + /* KJL 16:42:40 23/01/99 - near behaviour is triggered differently for + lightsources such as flares */ + if (ghostDataPtr && ghostDataPtr->type != I_BehaviourFlareGrenade) + { + MakeGhostNear(sbPtr); + } + + break; + } + case(I_BehaviourTrackObject): + { + MakeObjectNear(sbPtr); + break; + } + case(I_BehaviourFan): + { + MakeObjectNear(sbPtr); + break; + } + case(I_BehaviourNetCorpse): + { + MakeCorpseNear(sbPtr); + break; + } + case (I_BehaviourPlacedHierarchy): + { + MakePlacedHierarchyNear(sbPtr); + break; + } + case (I_BehaviourPlacedLight): + { + /* KJL 16:42:40 23/01/99 - do nothing; near behaviour is triggered + differently for lightsources */ + break; + } + case (I_BehaviourDummy): + { + MakeDummyNear(sbPtr); + break; + } + default: + { + /* only the above object types should get here */ + LOCALASSERT(1==0); + } + } + } + } + else + { + /* object is currently visible. + first need to get it's module, as it may have moved under dynamics */ + MODULE* newModule; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + newModule = ModuleFromPosition(&(dynPtr->Position), (sbPtr->containingModule)); + if(!(newModule)) + { + /* attempt to relocate object */ + textprint("Calling Near EmergencyRelocateObject, On object %x, type %d!\n",(int)sbPtr, sbPtr->I_SBtype); + IdentifyObject(sbPtr); + if(!(EmergencyRelocateObject(sbPtr))) { + textprint("Relocate failed!\n"); + return; + } + } + else + /* update object's module field */ + sbPtr->containingModule = newModule; + + /* now check the object's module */ + if (sbPtr->I_SBtype == I_BehaviourPlacedLight) + { + if(!ThisObjectIsInAModuleVisibleFromCurrentlyVisibleModules(sbPtr)) + { + MakeObjectFar(sbPtr); + } + } + else if(ModuleCurrVisArray[(sbPtr->containingModule->m_index)] == 0) + { + /* module is invisible, so make object invisible too */ + switch(sbPtr->I_SBtype) + { + case(I_BehaviourAlien): + { + MakeAlienFar(sbPtr); + break; + } + case(I_BehaviourRubberDuck): + case(I_BehaviourVideoScreen): + case(I_BehaviourInanimateObject): + { + MakeObjectFar(sbPtr); + break; + } + case(I_BehaviourAutoGun): + { + MakeSentrygunFar(sbPtr); + break; + } + case(I_BehaviourPlatform): + { + PLATFORMLIFT_BEHAVIOUR_BLOCK *platformliftdata = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr; + //don't make platform lift far if it is currently moving + //(otherwise the lift won't be able to move) + if(platformliftdata->state!=PLBS_GoingUp && + platformliftdata->state!=PLBS_GoingDown) + { + MakeObjectFar(sbPtr); + } + break; + } + case(I_BehaviourBinarySwitch): + { + MakeObjectFar(sbPtr); + break; + } + case(I_BehaviourDatabase): + { + MakeObjectFar(sbPtr); + break; + } + case(I_BehaviourLinkSwitch): + { + MakeObjectFar(sbPtr); + break; + } + case(I_BehaviourPredator): + { + MakePredatorFar(sbPtr); + break; + } + case(I_BehaviourXenoborg): + { + MakeXenoborgFar(sbPtr); + break; + } + case(I_BehaviourQueenAlien): + { + MakeQueenFar(sbPtr); + break; + } + case(I_BehaviourPredatorAlien): + { + //MakePAQFar(sbPtr); + GLOBALASSERT(0); + /* Should be BehaviourAlien! */ + break; + } + case(I_BehaviourFaceHugger): + { + MakeFacehuggerFar(sbPtr); + break; + } + case(I_BehaviourMarine): + { + MakeMarineFar(sbPtr); + break; + } + case(I_BehaviourSeal): + { + MakeMarineFar(sbPtr); /* not yet supported */ + break; + } + case(I_BehaviourNetGhost): + { + #if PSX + GLOBALASSERT(1==2); + #else + MakeGhostFar(sbPtr); + #endif + break; + } + case(I_BehaviourTrackObject): + { + MakeObjectFar(sbPtr); + break; + } + case(I_BehaviourFan): + { + MakeObjectFar(sbPtr); + break; + } + case(I_BehaviourNetCorpse): + { + MakeCorpseFar(sbPtr); + break; + } + case (I_BehaviourPlacedHierarchy): + { + MakeObjectFar(sbPtr); + break; + } + case (I_BehaviourDummy): + { + MakeDummyFar(sbPtr); + break; + } + default: + { + /* only the above object types should get here */ + LOCALASSERT(1==0); + } + } + + } + + } + +} + +/*-----------------------Patrick 15/1/97--------------------------- +This pair of functions can be used to control the visibility of +most objects in the environment. Object specific stuff can be done +after the approriate call in doObjectVisibility, or a separate +function can be used (as for aliens) +-------------------------------------------------------------------*/ + +HMODELCONTROLLER DropShipHModelController; + +void MakeObjectNear(STRATEGYBLOCK *sbPtr) +{ + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + LOCALASSERT(dynPtr); + LOCALASSERT(sbPtr->SBdptr == NULL); + + VisibilityDefaultObjectMap.MapShape = sbPtr->shapeIndex; + tempModule.m_mapptr = &VisibilityDefaultObjectMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 0; + tempModule.m_lightarray = (struct lightblock *)0; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr = NULL; /* this is important */ + #if SupportWIndows95 + tempModule.name = NULL; /* this is important */ + #endif + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) return; /* cannot create displayblock, so leave object "far" */ + + sbPtr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbPtr; + dPtr->ObMyModule = NULL; + + /* also need to initialise positional information in the new display + block from the existing dynamics block: this necessary because this + function is (usually) called between the dynamics and rendering systems + so it is not initialised by the dynamics system the first time it is + drawn. */ + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + + #if HMODEL_HACK + + if (dPtr->ObShape==GetLoadedShapeMSL("computer")) { + + extern SECTION Chest; + SECTION *Test_Section; + + extern SECTION *GetHierarchyFromLibrary(const char *rif_name); + + Test_Section=GetHierarchyFromLibrary("hnpcalien"); + + //Preprocess_HModel(Test_Section); + Create_HModel(&DropShipHModelController,Test_Section); + InitHModelSequence(&DropShipHModelController,3,3,ONE_FIXED<<1); + dPtr->HModelControlBlock=&DropShipHModelController; + + + //dPtr->HModelControlBlock->Playing=1; + dPtr->HModelControlBlock->Looped=1; + + } + + #endif + + +} + +void MakeObjectFar(STRATEGYBLOCK *sbPtr) +{ + int i; + + #if HMODEL_HACK + + if (sbPtr->SBdptr->ObShape==GetLoadedShapeMSL("chest")) { + Dispel_HModel(&DropShipHModelController); + } + + #endif + + LOCALASSERT(sbPtr->SBdptr != NULL); + + /* get rid of the displayblock */ + i = DestroyActiveObject(sbPtr->SBdptr); + if(i!=0) + { + LOCALASSERT(1==0); + } + sbPtr->SBdptr = NULL; + +} + + +/*----------------------Patrick 15/1/97----------------------------- +This function relocates an object back into the environment: +this may be an npc, inanimate object, etc. +It is called if the visibility system fails to find a +containing module for the object, which may happen for a number +of reasons, eg: an object is blown out of the visible part of the +environment, or an npc falls out... +NB returns 0 if relocation failed. +--------------------------------------------------------------------*/ +static EmergRelocCalls = 0; +static int EmergencyRelocateObject(STRATEGYBLOCK *sbPtr) +{ + + EmergRelocCalls++; + + if(sbPtr->I_SBtype == I_BehaviourNetGhost) return 1; + + /* KJL 14:48:36 09/02/98 - ignore platform lifts */ + if (sbPtr->I_SBtype == I_BehaviourPlatform) return 1; + + /* first, try to reset the object's position: if it has a valid 'containingModule', + this means that it's last position was in that module, so we can use that as a reset + position. + NB this means that NPC's will be unable to 'run away' into an invisible module. + */ + + if(sbPtr->containingModule) + { + + /* Nooo, this doesn't work! CDF 3/12/97 Hack. */ + + if ((sbPtr->I_SBtype!=I_BehaviourAlien) + &&(sbPtr->I_SBtype!=I_BehaviourMarine) + ) { + textprint("Valid containingModule.\n"); + sbPtr->DynPtr->Position = sbPtr->DynPtr->PrevPosition; + return 1; + } + } + + /* so, we don't have a previous module... then search the environment for the + nearest invisible module that has entry point locations, and relocate to one of + these locations. */ + { + extern SCENE Global_Scene; + extern SCENEMODULE **Global_ModulePtr; + + AIMODULE *targetModule = 0; + int targetModuleDistance = 0; + //SCENEMODULE *ScenePtr; + AIMODULE *moduleListPointer; + int moduleCounter; + + LOCALASSERT(ModuleArraySize); + LOCALASSERT(Global_ModulePtr); + LOCALASSERT(FALLP_EntryPoints); /* NB should never get here in a net game, so the codition should be true */ + + //ScenePtr = Global_ModulePtr[Global_Scene]; + //moduleListPointer = ScenePtr->sm_marray; + { + extern AIMODULE *AIModuleArray; + moduleListPointer = AIModuleArray; + } + + for(moduleCounter = 0; moduleCounter < AIModuleArraySize; moduleCounter++) + { + AIMODULE *thisModule = &(moduleListPointer[moduleCounter]); + //MODULE* thisModule = moduleListPointer[moduleCounter]; + + if( (!(ModuleCurrVisArray[thisModule->m_index]))&& + (FALLP_EntryPoints[thisModule->m_index].numEntryPoints != 0) + ) + { + /* a candidate */ + int thisModuleDistance = + VectorDistance(&(thisModule->m_world), &(sbPtr->DynPtr->Position)); + + if((!targetModule) || (thisModuleDistance < targetModuleDistance)) + { + targetModule = thisModule; + targetModuleDistance = thisModuleDistance; + } + } + } + + if(!targetModule) + { + /* this condition shouldn't happen, but since I'm paranoid... */ + //This can happen on the skirmish levels (where the whole level is visible at once) + //Therefore if the object has a previous containing module , use it. + //Otherwise get rid of it. + + //LOCALASSERT(1==0); + if(sbPtr->containingModule) + { + + /* Nooo, this doesn't work! CDF 3/12/97 Hack. */ + + textprint("Valid containingModule.\n"); + sbPtr->DynPtr->Position = sbPtr->DynPtr->PrevPosition; + return 1; + + } + DestroyAnyStrategyBlock(sbPtr); + return 0; + } + + EmergencyPlaceObjectInModule(sbPtr, targetModule); + + #if debug + if (!sbPtr->containingModule) + { + textprint("WARNING!! EmgcyPlcObInMod failed\n"); + } + #endif + + + return sbPtr->containingModule ? 1 : 0; + } +} + +static void EmergencyPlaceObjectInModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule) +{ + int noOfEntryPoints; + FARENTRYPOINT *entryPointsList; + VECTORCH newPosition; + MODULE *renderModule; + + textprint("Calling EmergencyPlaceObjectInModule!\n"); + + /* first off, assert a few pre-conditions */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + GLOBALASSERT(sbPtr->maintainVisibility); + GLOBALASSERT(FALLP_EntryPoints); + + noOfEntryPoints = FALLP_EntryPoints[(targetModule->m_index)].numEntryPoints; + entryPointsList = FALLP_EntryPoints[(targetModule->m_index)].entryPointsList; + + GLOBALASSERT(noOfEntryPoints); + + /* just use the first entry point */ + newPosition = entryPointsList[0].position; + + /* now set the object's new position and current module. + NB this is world position + a little extra in y to make sure */ + { + DYNAMICSBLOCK *dynPtr; + + dynPtr = sbPtr->DynPtr; + dynPtr->Position = newPosition; + + dynPtr->Position.vx += targetModule->m_world.vx; + dynPtr->Position.vy += targetModule->m_world.vy; + dynPtr->Position.vz += targetModule->m_world.vz; + + dynPtr->PrevPosition = dynPtr->Position; + + } + /* finally, update the sb's module */ + renderModule=ModuleFromPosition(&sbPtr->DynPtr->Position,NULL); + + sbPtr->containingModule = renderModule; + +} + + + + +/*------------------------Patrick 14/1/97----------------------------- + This function returns the module in which a given world-space + position is located. A starting point for the search may also be + passed, so that the following search pattern is used: + 1. is the location in the indicated starting module. + 2. is the location in any of the starting module's visible-links. + 3. finally, all modules in the environment are searched until + a containing module is found. + + If no module is found, a null module pointer is returned. + NB only 'physical' modules are returned, ie infinite and + terminator modules are ignored. + + The function is designed to be used for objects which move over small + distances, and for which a recently containing module is known (eg + avp aliens).... so that the first stage of the search will be successful + in the majority of cases, and the third stage rarely used. + Note that the fn returns the first module which contains the given + point, so problems may arise if the point exists in more than one + module. This should be ok for environments like avp, where v-linking + is not used. + --------------------------------------------------------------------*/ + +static int WorldPointIsInModule_WithTolerance(MODULE* thisModule, VECTORCH* thisPoint); +static MODULE* ModuleFromPosition_WithTolerance(VECTORCH *position, MODULE* startingModule); + +MODULE* ModuleFromPosition(VECTORCH *position, MODULE* startingModule) +{ + if((startingModule) && (ModuleIsPhysical(startingModule))) + { + /* first test for the most trivial, and most likely case */ + if(WorldPointIsInModule(startingModule, position)) + return startingModule; + + /* now test visible-linked modules (If there are any) */ + { + VMODULE *vlPtr = startingModule->m_vmptr; + if(vlPtr) + { + while(vlPtr->vmod_type != vmtype_term) + { + MODULE *mPtr = vlPtr->vmod_mref.mref_ptr; + if(mPtr) + { + if(ModuleIsPhysical(mPtr)) + if(WorldPointIsInModule(mPtr, position)) + return mPtr; + } + vlPtr++; + } + } + } + } + + /* either there is no starting module; the starting module is not physical; + we are not in the starting module and it has no visibility-linked modules; + or we haven't found a module yet: so search the entire module list */ + { + extern SCENE Global_Scene; + extern SCENEMODULE **Global_ModulePtr; + extern int ModuleArraySize; + MODULE **moduleListPointer; + int moduleCounter; + + LOCALASSERT(ModuleArraySize); + LOCALASSERT(Global_ModulePtr); + + moduleListPointer = (Global_ModulePtr[Global_Scene])->sm_marray; + moduleCounter = ModuleArraySize; + while(moduleCounter>0) + { + MODULE *thisModule; + + thisModule = *moduleListPointer++; + if(ModuleIsPhysical(thisModule)) + if(WorldPointIsInModule(thisModule, position)) + return (thisModule); + + moduleCounter--; + } + } + + /* couldn't find a module */ + /*Try with slightly larger module bounding boxes*/ + return ModuleFromPosition_WithTolerance(position,startingModule); +} + + +/*-----------------------Patrick 14/1/97--------------------------- +Returns 1 if the given WORLD point is in a given module, +or 0 otherwise. + +NB the bizzare structure of this function produces optimum pentium +instructions... apparently. +-------------------------------------------------------------------*/ +static int WorldPointIsInModule(MODULE* thisModule, VECTORCH* thisPoint) +{ + VECTORCH localpoint = *thisPoint; + localpoint.vx -= thisModule->m_world.vx; + localpoint.vy -= thisModule->m_world.vy; + localpoint.vz -= thisModule->m_world.vz; + + if(localpoint.vx <= thisModule->m_maxx) + if(localpoint.vx >= thisModule->m_minx) + if(localpoint.vy <= thisModule->m_maxy) + if(localpoint.vy >= thisModule->m_miny) + if(localpoint.vz <= thisModule->m_maxz) + if(localpoint.vz >= thisModule->m_minz) + return 1; + return 0; +} + + + + +#define ModuleFromPositionTolerance 50 +static MODULE* ModuleFromPosition_WithTolerance(VECTORCH *position, MODULE* startingModule) +{ + if((startingModule) && (ModuleIsPhysical(startingModule))) + { + /* first test for the most trivial, and most likely case */ + if(WorldPointIsInModule_WithTolerance(startingModule, position)) + return startingModule; + + /* now test visible-linked modules (If there are any) */ + { + VMODULE *vlPtr = startingModule->m_vmptr; + if(vlPtr) + { + while(vlPtr->vmod_type != vmtype_term) + { + MODULE *mPtr = vlPtr->vmod_mref.mref_ptr; + if(mPtr) + { + if(ModuleIsPhysical(mPtr)) + if(WorldPointIsInModule_WithTolerance(mPtr, position)) + return mPtr; + } + vlPtr++; + } + } + } + } + + /* either there is no starting module; the starting module is not physical; + we are not in the starting module and it has no visibility-linked modules; + or we haven't found a module yet: so search the entire module list */ + { + extern SCENE Global_Scene; + extern SCENEMODULE **Global_ModulePtr; + extern int ModuleArraySize; + MODULE **moduleListPointer; + int moduleCounter; + + LOCALASSERT(ModuleArraySize); + LOCALASSERT(Global_ModulePtr); + + moduleListPointer = (Global_ModulePtr[Global_Scene])->sm_marray; + moduleCounter = ModuleArraySize; + while(moduleCounter>0) + { + MODULE *thisModule; + + thisModule = *moduleListPointer++; + if(ModuleIsPhysical(thisModule)) + if(WorldPointIsInModule_WithTolerance(thisModule, position)) + return (thisModule); + + moduleCounter--; + } + } + + /* couldn't find a module */ + return (MODULE *)0; +} + + +static int WorldPointIsInModule_WithTolerance(MODULE* thisModule, VECTORCH* thisPoint) +{ + VECTORCH localpoint = *thisPoint; + localpoint.vx -= thisModule->m_world.vx; + localpoint.vy -= thisModule->m_world.vy; + localpoint.vz -= thisModule->m_world.vz; + + if(localpoint.vx <= thisModule->m_maxx + ModuleFromPositionTolerance) + if(localpoint.vx >= thisModule->m_minx - ModuleFromPositionTolerance) + if(localpoint.vy <= thisModule->m_maxy + ModuleFromPositionTolerance) + if(localpoint.vy >= thisModule->m_miny - ModuleFromPositionTolerance) + if(localpoint.vz <= thisModule->m_maxz + ModuleFromPositionTolerance) + if(localpoint.vz >= thisModule->m_minz - ModuleFromPositionTolerance) + return 1; + return 0; +} + + + +/*---------------------Patrick 14/1/97----------------------------- + + SUPPORT FUNCTIONS FOR INANIMATE OBJECTS + + -----------------------------------------------------------------*/ + + + + + + +/*-----------------------Patrick 16/1/97--------------------------- +Inanimate object initialisation and behaviour and functions. +-------------------------------------------------------------------*/ +void InitInanimateObject(void* bhdata, STRATEGYBLOCK *sbPtr) +{ + TOOLS_DATA_INANIMATEOBJECT *toolsData = (TOOLS_DATA_INANIMATEOBJECT *)bhdata; + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr; + enum DYNAMICS_TEMPLATE_ID inanimateDynamicsInitialiser; + int i; + + LOCALASSERT(sbPtr->I_SBtype == I_BehaviourInanimateObject); + LOCALASSERT(toolsData); + + /* create, initialise and attach a data block */ + objectstatusptr = (void *)AllocateMem(sizeof(INANIMATEOBJECT_STATUSBLOCK)); + if(!objectstatusptr) + { + RemoveBehaviourStrategy(sbPtr); + } + + sbPtr->SBdataptr = objectstatusptr; + objectstatusptr->respawnTimer = 0; + objectstatusptr->lifespanTimer = 0; + objectstatusptr->explosionTimer = 0; + + /* these should be loaded */ + objectstatusptr->typeId = toolsData->typeId; + objectstatusptr->subType = toolsData->subType; + + /* set default indestructibility */ + objectstatusptr->Indestructable = No; + objectstatusptr->ghosted_object=0; + + /* set the default inanimate object dynamics template: Inanimate for single player, + and Static for multiplayer + NB some objects are always static, and initialised using + the static dynamics template directly + NB2 PSX: all objects are static */ + #if SupportWindows95 +// if(AvP.Network==I_No_Network) inanimateDynamicsInitialiser = DYNAMICS_TEMPLATE_INANIMATE; +// else inanimateDynamicsInitialiser = DYNAMICS_TEMPLATE_STATIC; + inanimateDynamicsInitialiser = DYNAMICS_TEMPLATE_INANIMATE; + #else + inanimateDynamicsInitialiser = DYNAMICS_TEMPLATE_STATIC; + #endif + + /* Initialise object's stats */ + { + NPC_DATA *NpcData; + + //#warning Change Me!!! + + NpcData=GetThisNpcData(I_NPC_DefaultInanimate); + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + + sbPtr->SBDamageBlock.Health*=toolsData->integrity; + + if(toolsData->triggering_event) + { + objectstatusptr->event_target=(OBJECT_EVENT_TARGET*)AllocateMem(sizeof(OBJECT_EVENT_TARGET)); + + objectstatusptr->event_target->triggering_event=toolsData->triggering_event; + objectstatusptr->event_target->request=toolsData->event_request; + for(i=0;ievent_target->event_target_ID[i] = toolsData->event_target_ID[i]; + objectstatusptr->event_target->event_target_sbptr=0; + } + else + { + objectstatusptr->event_target=0; + } + + objectstatusptr->explosionType=toolsData->explosionType; + + /* set inanimate-object-type-specific stuff... + 1. dynamics block allocation + 2. integrity */ + switch(objectstatusptr->typeId) + { + case IOT_HitMeAndIllDestroyBase: + case IOT_Static: + { + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + sbPtr->DynPtr->Mass = toolsData->mass; + if (toolsData->integrity > 20) + { + objectstatusptr->Indestructable = Yes; + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + } + else if (toolsData->integrity < 1) + { + sbPtr->integrity = 1; // die immediately + } + else + { + sbPtr->integrity = (DEFAULT_OBJECT_INTEGRITY)*(toolsData->integrity); + } + break; + } + case IOT_Furniture: + { + sbPtr->DynPtr = AllocateDynamicsBlock(inanimateDynamicsInitialiser); + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + sbPtr->DynPtr->Mass = toolsData->mass; + if (toolsData->integrity > 20) + { + objectstatusptr->Indestructable = Yes; + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + } + else if (toolsData->integrity < 1) + { + sbPtr->integrity = 1; // die immediately + } + else + { + sbPtr->integrity = (DEFAULT_OBJECT_INTEGRITY)*(toolsData->integrity); + } + break; + } + case IOT_Weapon: + { + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT); + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + if(objectstatusptr->subType==WEAPON_FLAMETHROWER) + { + //flamethrowers explode using a molotov explosion + objectstatusptr->explosionType=3; + } + break; + } + case IOT_Ammo: + { + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT); + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + + if(objectstatusptr->subType==AMMO_FLAMETHROWER) + { + //flamethrowers explode using a molotov explosion + objectstatusptr->explosionType=3; + } + break; + } + case IOT_Health: + { + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT); + + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + break; + } + case IOT_Armour: + { + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT); + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + break; + } + case IOT_Key: + { + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT); + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + break; + } + case IOT_BoxedSentryGun: + { + sbPtr->DynPtr = AllocateDynamicsBlock(inanimateDynamicsInitialiser); + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + break; + } + case IOT_IRGoggles: + { + sbPtr->DynPtr = AllocateDynamicsBlock(inanimateDynamicsInitialiser); + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + break; + } + case IOT_DataTape: + { + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + break; + } + case IOT_MTrackerUpgrade: + { + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT); + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + break; + } + case IOT_PheromonePod: + { + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT); + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + break; + } + case IOT_SpecialPickupObject: + { + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT); + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + if (toolsData->integrity > 20) + { + objectstatusptr->Indestructable = Yes; + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + } + else if (toolsData->integrity < 1) + { + sbPtr->integrity = 1; // die immediately + } + else + { + sbPtr->integrity = (DEFAULT_OBJECT_INTEGRITY)*(toolsData->integrity); + } + break; + } + case IOT_FieldCharge: + { + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PICKUPOBJECT); + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + /*check to see if object is animated.*/ + { + TXACTRLBLK **pptxactrlblk; + int item_num; + int shape_num = toolsData->shapeIndex; + SHAPEHEADER *shptr = GetShapeData(shape_num); + pptxactrlblk = &objectstatusptr->inan_tac; + for(item_num = 0; item_num < shptr->numitems; item_num ++) + { + POLYHEADER *poly = (POLYHEADER*)(shptr->items[item_num]); + LOCALASSERT(poly); + + SetupPolygonFlagAccessForShape(shptr); + + if((Request_PolyFlags((void *)poly)) & iflag_txanim) + { + TXACTRLBLK *pnew_txactrlblk; + + pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK)); + if(pnew_txactrlblk) + { + pnew_txactrlblk->tac_flags = 0; + pnew_txactrlblk->tac_item = item_num; + pnew_txactrlblk->tac_sequence = 0; + pnew_txactrlblk->tac_node = 0; + pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shape_num, item_num); + pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shape_num); + + *pptxactrlblk = pnew_txactrlblk; + pptxactrlblk = &pnew_txactrlblk->tac_next; + } + else *pptxactrlblk = NULL; + } + } + *pptxactrlblk=0; + + } + + /* Initialise the dynamics block */ + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + GLOBALASSERT(dynPtr); + + dynPtr->PrevPosition = dynPtr->Position = toolsData->position; + dynPtr->OrientEuler = toolsData->orientation; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + } + + /* strategy block initialisation */ + sbPtr->shapeIndex = toolsData->shapeIndex; + for(i=0;iSBname[i] = toolsData->nameID[i]; + + /* these must be initialised for respawning objects in multiplayer game */ + objectstatusptr->startingHealth = sbPtr->SBDamageBlock.Health; + objectstatusptr->startingArmour = sbPtr->SBDamageBlock.Armour; + + if(AvP.Network != I_No_Network) + { + //if in a network game , see if this is an allowable weapon + if(objectstatusptr->typeId==IOT_Weapon) + { + if((!netGameData.allowSmartgun && objectstatusptr->subType==WEAPON_SMARTGUN)|| + (!netGameData.allowFlamer && objectstatusptr->subType==WEAPON_FLAMETHROWER)|| + (!netGameData.allowSadar && objectstatusptr->subType==WEAPON_SADAR)|| + (!netGameData.allowGrenadeLauncher && objectstatusptr->subType==WEAPON_GRENADELAUNCHER)|| + (!netGameData.allowPistols && objectstatusptr->subType==WEAPON_MARINE_PISTOL)|| + (!netGameData.allowSmartDisc && objectstatusptr->subType==WEAPON_FRISBEE_LAUNCHER)|| + (!netGameData.allowMinigun && objectstatusptr->subType==WEAPON_MINIGUN)) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + } + if(objectstatusptr->typeId==IOT_Ammo) + { + if((!netGameData.allowSmartgun && objectstatusptr->subType==AMMO_SMARTGUN)|| + (!netGameData.allowFlamer && objectstatusptr->subType==AMMO_FLAMETHROWER)|| + (!netGameData.allowSadar && objectstatusptr->subType==AMMO_SADAR_TOW)|| + (!netGameData.allowGrenadeLauncher && objectstatusptr->subType==AMMO_GRENADE)|| + (!netGameData.allowPistols && objectstatusptr->subType==AMMO_MARINE_PISTOL_PC)|| + (!netGameData.allowSmartDisc && objectstatusptr->subType==AMMO_FRISBEE)|| + (!netGameData.allowMinigun && objectstatusptr->subType==AMMO_MINIGUN)) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + } + } +} + +void InanimateObjectBehaviour(STRATEGYBLOCK *sbPtr) +{ + /* handle respawn timer here */ + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = sbPtr->SBdataptr; + LOCALASSERT(objectstatusptr); + + LOCALASSERT(!(objectstatusptr->respawnTimer<0)); /* this should never happen */ + + /* Lock disc pickups in place. */ + if ((objectstatusptr->typeId == IOT_Ammo) + &&(objectstatusptr->subType == (int)AMMO_PRED_DISC)) { + + sbPtr->DynPtr->LinVelocity.vx=0; + sbPtr->DynPtr->LinVelocity.vy=0; + sbPtr->DynPtr->LinVelocity.vz=0; + + sbPtr->DynPtr->LinImpulse.vx=0; + sbPtr->DynPtr->LinImpulse.vy=0; + sbPtr->DynPtr->LinImpulse.vz=0; + } + + if(objectstatusptr->inan_tac) + { + DISPLAYBLOCK* dptr = sbPtr->SBdptr; + + /*deal with texture animation*/ + if(dptr) + { + if(!dptr->ObTxAnimCtrlBlks) + { + dptr->ObTxAnimCtrlBlks = objectstatusptr->inan_tac; + } + } + + } + + if(objectstatusptr->explosionTimer) + { + //the object is about to explode + if(objectstatusptr->explosionStartFrame==GlobalFrameCounter) + { + //the explosion was triggered earlier this frame + //therefore don't bother altering the timer until next frame + return; + } + + objectstatusptr->explosionTimer-=NormalFrameTime; + if(objectstatusptr->explosionTimer<=0) + { + objectstatusptr->explosionTimer=-1; + InanimateObjectIsDamaged(sbPtr,0,0); + return; + } + + } + + if(AvP.Network!=I_No_Network) + { + //see if dropped weapons have timed out + if(objectstatusptr->lifespanTimer>0) + { + objectstatusptr->lifespanTimer-=NormalFrameTime; + if(objectstatusptr->lifespanTimer<=0) + { + FragmentInanimateObject(sbPtr); + DestroyAnyStrategyBlock(sbPtr); + } + return; + } + } + + /* do nothing if the timer is zero */ + if(objectstatusptr->respawnTimer==0 || objectstatusptr->respawnTimer==OBJECT_RESPAWN_NO_RESPAWN) return; + + /* textprint("RESPAWN TIMER %d \n", objectstatusptr->respawnTimer); */ + /* If we get here, the object is in a respawn state: + this should only happen in a net-game */ + LOCALASSERT(AvP.Network!=I_No_Network); + LOCALASSERT(!sbPtr->SBdptr); + LOCALASSERT(!sbPtr->maintainVisibility); + + objectstatusptr->respawnTimer -= NormalFrameTime; + if(objectstatusptr->respawnTimer<=0) + { + /* time to respawn, then */ + RespawnInanimateObject(sbPtr); + objectstatusptr->respawnTimer=0; + } +} + +/* this global flag is used to distinguish between messages from the host, +and locally caused damage */ +int InanimateDamageFromNetHost = 0; + + +void InanimateObjectIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple) +{ + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = sbPtr->SBdataptr; + LOCALASSERT(objectstatusptr); + + #if SupportWindows95 + if((AvP.Network==I_Peer)&&(!InanimateDamageFromNetHost)) + { + /* this means that the damage was generated locally in a net-game: + in this case, just send a damage message to the host */ + AddNetMsg_InanimateObjectDamaged(sbPtr,damage,multiple); + return; + } + else if(AvP.Network==I_Host) + { + /* if we're the host, inform everyone that the object is dead */ + if(sbPtr->SBDamageBlock.Health <= 0) AddNetMsg_InanimateObjectDestroyed(sbPtr); + } + #endif + + if(sbPtr->SBflags.please_destroy_me) + { + //object has already been destroyed , so ignore any further damage + return; + } + + //if object has been destroyed , see if it has a target that it needs to notify + if(objectstatusptr->event_target) + { + if(sbPtr->SBDamageBlock.Health <= 0 && !objectstatusptr->Indestructable) + { + if(objectstatusptr->event_target->triggering_event & ObjectEventFlag_Destroyed) + { + RequestState(objectstatusptr->event_target->event_target_sbptr,objectstatusptr->event_target->request,0); + } + } + } + + if (!objectstatusptr->Indestructable && objectstatusptr->explosionType) + { + + + if(InanimateDamageFromNetHost) + { + //do explosion effect , without the damage + switch(objectstatusptr->explosionType) + { + case 1: + { + //small explosion + MakeVolumetricExplosionAt(&(sbPtr->DynPtr->Position),EXPLOSION_SMALL_NOCOLLISIONS); + + Explosion_SoundData.position=sbPtr->DynPtr->Position; + + Sound_Play(SID_NADEEXPLODE,"n",&Explosion_SoundData); + + break; + } + case 2: + { + //big explosion + MakeVolumetricExplosionAt(&(sbPtr->DynPtr->Position),EXPLOSION_HUGE_NOCOLLISIONS); + + Explosion_SoundData.position=sbPtr->DynPtr->Position; + + Sound_Play(SID_NICE_EXPLOSION,"n",&Explosion_SoundData); + + break; + } + case 3: + { + //molotov explosion + MakeVolumetricExplosionAt(&(sbPtr->DynPtr->Position),EXPLOSION_MOLOTOV); + + Explosion_SoundData.position=sbPtr->DynPtr->Position; + + Sound_Play(SID_NADEEXPLODE,"n",&Explosion_SoundData); + + break; + } + } + } + else + { + if(objectstatusptr->explosionTimer==0) + { + if(sbPtr->SBDamageBlock.Health <= 0) + { + //start explosion timer + //this gives a slight time delay for object destruction, to allow for chain reactions + //(rather than all explosive objects going up in one frame) + objectstatusptr->explosionTimer=ONE_FIXED/10; + objectstatusptr->explosionStartFrame=GlobalFrameCounter; + return; + } + } + else if(objectstatusptr->explosionTimer<0) + { + //time for the explosion + objectstatusptr->explosionTimer=0; + switch(objectstatusptr->explosionType) + { + case 1: + { + //small explosion + HandleEffectsOfExplosion + ( + sbPtr, + &(sbPtr->DynPtr->Position), + 5000, + &SmallExplosionDamage, + 0 + ); + Explosion_SoundData.position=sbPtr->DynPtr->Position; + + Sound_Play(SID_NADEEXPLODE,"n",&Explosion_SoundData); + + break; + } + case 2: + { + //big explosion + HandleEffectsOfExplosion + ( + sbPtr, + &(sbPtr->DynPtr->Position), + 10000, + &BigExplosionDamage, + 0 + ); + Explosion_SoundData.position=sbPtr->DynPtr->Position; + + Sound_Play(SID_NICE_EXPLOSION,"n",&Explosion_SoundData); + + break; + } + case 3: + { + //molotov explosion + HandleEffectsOfExplosion + ( + sbPtr, + &(sbPtr->DynPtr->Position), + TemplateAmmo[AMMO_MOLOTOV].MaxRange, + &TemplateAmmo[AMMO_MOLOTOV].MaxDamage[AvP.Difficulty], + TemplateAmmo[AMMO_MOLOTOV].ExplosionIsFlat + ); + Explosion_SoundData.position=sbPtr->DynPtr->Position; + + Sound_Play(SID_NADEEXPLODE,"n",&Explosion_SoundData); + + break; + } + } + + //set health to zero (in case object has recovered in the delay) + sbPtr->SBDamageBlock.Health=0; + } + else + { + //currently in explosion count down , so wait + return; + } + } + } + + + switch(objectstatusptr->typeId) + { + case IOT_Static: + { + if (!objectstatusptr->Indestructable) + { + if(sbPtr->SBDamageBlock.Health <= 0) + { + FragmentInanimateObject(sbPtr); + if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr); + else KillFragmentalObjectForRespawn(sbPtr); + } + } + break; + } + case IOT_Furniture: + { + if (!objectstatusptr->Indestructable) + { + if(sbPtr->SBDamageBlock.Health <= 0) + { + FragmentInanimateObject(sbPtr); + DestroyAnyStrategyBlock(sbPtr); + } + } + break; + } + case IOT_Weapon: + { + if(sbPtr->SBDamageBlock.Health <= 0) + { + FragmentInanimateObject(sbPtr); + if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr); + else KillInanimateObjectForRespawn(sbPtr); + } + break; + } + case IOT_Ammo: + { + if(sbPtr->SBDamageBlock.Health <= 0) + { + FragmentInanimateObject(sbPtr); + if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr); + else KillInanimateObjectForRespawn(sbPtr); + } + break; + } + case IOT_Health: + { + if(sbPtr->SBDamageBlock.Health <= 0) + { + FragmentInanimateObject(sbPtr); + if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr); + else KillInanimateObjectForRespawn(sbPtr); + } + break; + } + case IOT_Armour: + { + if(sbPtr->SBDamageBlock.Health <= 0) + { + FragmentInanimateObject(sbPtr); + if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr); + else KillInanimateObjectForRespawn(sbPtr); + } + break; + } + case IOT_Key: + { + /* do nothing */ + break; + } + case IOT_BoxedSentryGun: + { + if(sbPtr->SBDamageBlock.Health <= 0) + { + ExplodeInanimateObject(sbPtr); + if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr); + else KillInanimateObjectForRespawn(sbPtr); + } + break; + } + case IOT_IRGoggles: + { + if(sbPtr->SBDamageBlock.Health <= 0) + { + ExplodeInanimateObject(sbPtr); + if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr); + else KillInanimateObjectForRespawn(sbPtr); + } + break; + } + case IOT_DataTape: + { + /* do nothing */ + break; + } + case IOT_MTrackerUpgrade: + { + if(sbPtr->SBDamageBlock.Health <= 0) + { + ExplodeInanimateObject(sbPtr); + if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr); + else KillInanimateObjectForRespawn(sbPtr); + } + break; + } + case IOT_PheromonePod: + { + if(sbPtr->SBDamageBlock.Health <= 0) + { + ExplodeInanimateObject(sbPtr); + if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr); + else KillInanimateObjectForRespawn(sbPtr); + } + break; + } + case IOT_SpecialPickupObject: + { + if (!objectstatusptr->Indestructable) + { + if(sbPtr->SBDamageBlock.Health <= 0) + { + FragmentInanimateObject(sbPtr); + if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr); + else KillInanimateObjectForRespawn(sbPtr); + } + } + break; + } + case IOT_HitMeAndIllDestroyBase: + { + if (damage->Penetrative>0) { + /* Destroy base. */ + if (AvP.DestructTimer==-1) { + textprint("Boom! You've blown up the base!\n"); + ActivateSelfDestructSequence(60); + /* Dummy switch hack. */ + { + STRATEGYBLOCK *evil_switch_SBPtr; + char Evil_Switch_SBname[] = {0x46,0xb9,0x01,0xf0,0x63,0xe4,0x56,0x0,}; + + evil_switch_SBPtr=FindSBWithName(Evil_Switch_SBname); + + GLOBALASSERT(evil_switch_SBPtr); + + RequestState(evil_switch_SBPtr,1,Player->ObStrategyBlock); + } + } + } + break; + } + case IOT_FieldCharge: + { + if(sbPtr->SBDamageBlock.Health <= 0) + { + FragmentInanimateObject(sbPtr); + if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr); + else KillInanimateObjectForRespawn(sbPtr); + } + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } +} + +#define ObjectRequest_AdjustIntegrity 0x00000001 +void SendRequestToInanimateObject(STRATEGYBLOCK* sbptr,BOOL state,int extended_data) +{ + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = sbptr->SBdataptr; + GLOBALASSERT(objectstatusptr); + GLOBALASSERT((sbptr->I_SBtype == I_BehaviourInanimateObject)); + + + if(state) + { + if(extended_data & ObjectRequest_AdjustIntegrity) + { + int new_integrity=(extended_data>>7)&0xff; + sbptr->SBDamageBlock.Health=(10<integrity = DEFAULT_OBJECT_INTEGRITY*new_integrity; + + if(new_integrity>20) + objectstatusptr->Indestructable = Yes; + else + objectstatusptr->Indestructable = No; + + if(sbptr->integrity==0) + { + //destroy the object by applying some damage to it + InanimateObjectIsDamaged(sbptr, &certainDeath, ONE_FIXED); + } + } + } + +} + +static void FragmentInanimateObject(STRATEGYBLOCK *sbPtr) +{ + MakeFragments(sbPtr); +} + +static void ExplodeInanimateObject(STRATEGYBLOCK *sbPtr) +{ + Sound_Play(SID_EXPLOSION,"d",&(sbPtr->DynPtr->Position)); +} + +/*-------------------Patrick 30/4/96----------------------- + A couple of functions for supporting respawning objects + in network games... + ---------------------------------------------------------*/ +static void RespawnInanimateObject(STRATEGYBLOCK *sbPtr) +{ + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = sbPtr->SBdataptr; + LOCALASSERT(objectstatusptr); + + sbPtr->maintainVisibility = 1; + MakeObjectNear(sbPtr); + + /* must respawn health too... */ + sbPtr->SBDamageBlock.Health = objectstatusptr->startingHealth; + sbPtr->SBDamageBlock.Armour = objectstatusptr->startingArmour; + +} + +void KillInanimateObjectForRespawn(STRATEGYBLOCK *sbPtr) +{ + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = sbPtr->SBdataptr; + LOCALASSERT(objectstatusptr); + LOCALASSERT(AvP.Network!=I_No_Network); + + /* make the object invisible, and remove it from visibility management */ + if(!objectstatusptr->lifespanTimer) + { + sbPtr->maintainVisibility = 0; + if(sbPtr->SBdptr) MakeObjectFar(sbPtr); + + if(netGameData.timeForRespawn>0) + objectstatusptr->respawnTimer = netGameData.timeForRespawn*ONE_FIXED; + else + objectstatusptr->respawnTimer = OBJECT_RESPAWN_NO_RESPAWN; + } + else + { + //get rid of this object permanently + DestroyAnyStrategyBlock(sbPtr); + + } + +} + +void KillFragmentalObjectForRespawn(STRATEGYBLOCK *sbPtr) +{ + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = sbPtr->SBdataptr; + LOCALASSERT(objectstatusptr); + LOCALASSERT(AvP.Network!=I_No_Network); + + /* make the object invisible, and remove it from visibility management */ + sbPtr->maintainVisibility = 0; + if(sbPtr->SBdptr) MakeObjectFar(sbPtr); + + /* KJL 12:44:23 24/05/98 - + + Set the respawn counter to be the max allowable, so that if all the + respawn counters are set to zero, it forces all the objects that have been + destroyed (eg. glass) to respawn simultaneously. + + Not a perfect solution: the object will respawn in 9.1 hours on its own. */ + + objectstatusptr->respawnTimer = OBJECT_RESPAWN_NO_RESPAWN; + +} + +void RespawnAllObjects(void) +{ + int i; + + LOCALASSERT(AvP.Network!=I_No_Network); + + for (i=0; iI_SBtype == I_BehaviourInanimateObject) + { + INANIMATEOBJECT_STATUSBLOCK* objectStatusPtr = sbPtr->SBdataptr; + LOCALASSERT(objectStatusPtr); + + if(objectStatusPtr->respawnTimer!=0) + { + RespawnInanimateObject(sbPtr); + objectStatusPtr->respawnTimer=0; + } + } + else if(sbPtr->I_SBtype == I_BehaviourPlacedLight) + { + RespawnLight(sbPtr); + } + } +} + +void RespawnAllPickups(void) +{ + int i; + + LOCALASSERT(AvP.Network!=I_No_Network); + + for (i=0; iI_SBtype == I_BehaviourInanimateObject) + { + INANIMATEOBJECT_STATUSBLOCK* objectStatusPtr = sbPtr->SBdataptr; + LOCALASSERT(objectStatusPtr); + + if(objectStatusPtr->typeId==IOT_Weapon || + objectStatusPtr->typeId==IOT_Ammo || + objectStatusPtr->typeId==IOT_Health || + objectStatusPtr->typeId==IOT_Armour || + objectStatusPtr->typeId==IOT_FieldCharge) + { + if(objectStatusPtr->respawnTimer!=0) + { + RespawnInanimateObject(sbPtr); + objectStatusPtr->respawnTimer=0; + } + } + } + } +} + +void IdentifyObject(STRATEGYBLOCK *sbPtr) { + + if (sbPtr==NULL) { + textprint("Object is NULL!\n"); + return; + } + + if (sbPtr->I_SBtype == I_BehaviourInanimateObject) { + INANIMATEOBJECT_STATUSBLOCK* objStatPtr = sbPtr->SBdataptr; + + switch(objStatPtr->typeId) + { + case(IOT_Weapon): + { + switch(objStatPtr->subType) + { + case WEAPON_PULSERIFLE: + { + textprint("Object is a Pulse Rifle.\n"); + return; + } + case WEAPON_AUTOSHOTGUN: + { + textprint("Object is an Autoshotgun.\n"); + return; + } + case WEAPON_SMARTGUN: + { + textprint("Object is a Smartgun.\n"); + return; + } + case WEAPON_FLAMETHROWER: + { + textprint("Object is a Flamethrower.\n"); + return; + } + case WEAPON_PLASMAGUN: + { + textprint("Object is a Plasmagun!\n"); + return; + } + case WEAPON_SADAR: + { + textprint("Object is a Sadar.\n"); + return; + } + case WEAPON_GRENADELAUNCHER: + { + textprint("Object is a Grenade Launcher.\n"); + return; + } + case WEAPON_MINIGUN: + { + textprint("Object is a Minigun.\n"); + return; + } + + default: + textprint("Object is unknown weapon (subtype %d).\n",(int)objStatPtr->subType); + break; + } + break; + } + case(IOT_Ammo): + { + switch(objStatPtr->subType) + { + case AMMO_10MM_CULW: + { + textprint("Object is Pulse Rifle ammo.\n"); + break; + } + case AMMO_SHOTGUN: + { + textprint("Object is Shotgun ammo.\n"); + break; + } + case AMMO_SMARTGUN: + { + textprint("Object is Smartgun ammo.\n"); + break; + } + case AMMO_FLAMETHROWER: + { + textprint("Object is Flamethrower ammo.\n"); + break; + } + case AMMO_PLASMA: + { + textprint("Object is Plasmagun ammo!\n"); + break; + } + case AMMO_SADAR_TOW: + { + textprint("Object is Sadar ammo.\n"); + break; + } + case AMMO_GRENADE: + { + textprint("Object is Grenade Launcher ammo.\n"); + break; + } + case AMMO_MINIGUN: + { + textprint("Object is Minigun ammo.\n"); + break; + } + default: + textprint("Object is unlisted ammo (subtype %d).\n",(int)objStatPtr->subType); + break; + } + + break; + } + case(IOT_Health): + { + textprint("Object is health.\n"); + break; + } + case(IOT_Armour): + { + textprint("Object is armour.\n"); + break; + } + case(IOT_FieldCharge): + { + textprint("Object is field charge powerup.\n"); + break; + } + default: + { + textprint("Object is unlisted subtype (%d).\n",(int)objStatPtr->subType); + break; + } + } + } else { + switch(sbPtr->I_SBtype) { + case I_BehaviourMarine: + { + textprint("Object is a marine.\n"); + textprint("Marine is in %s\n",sbPtr->containingModule->name); + break; + } + case I_BehaviourAlien: + { + textprint("Object is an alien.\n"); + break; + } + case I_BehaviourPredator: + { + textprint("Object is a predator.\n"); + break; + } + default: + { + textprint("Object is not supported - change PVisible.c for expanded diagnostics!\n"); + break; + } + } + } + + if (!sbPtr->DynPtr) { + textprint("Object has no dynamics block!\n"); + } else { + textprint("Object world co-ords: %d %d %d\n",sbPtr->DynPtr->Position.vx,sbPtr->DynPtr->Position.vy,sbPtr->DynPtr->Position.vz); + } + +} + + + +STRATEGYBLOCK* CreateMultiplayerWeaponPickup(VECTORCH* location,int type,char* name) +{ + TOOLS_DATA_INANIMATEOBJECT toolsdata; + STRATEGYBLOCK * sbPtr; + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr; + int trueType; + + if ((type==WEAPON_TWO_PISTOLS)||(type==WEAPON_MARINE_PISTOL)) { + if (!netGameData.allowPistols) { + return(0); + } + } + + if (type==WEAPON_TWO_PISTOLS) { + trueType=WEAPON_MARINE_PISTOL; + } else { + trueType=type; + } + + //fill out a tools template , and use the normal inanimate object creation function + toolsdata.position=*location; + toolsdata.orientation.EulerX=0; + toolsdata.orientation.EulerY=0; + toolsdata.orientation.EulerZ=0; + + toolsdata.typeId=IOT_Weapon; + toolsdata.subType=trueType; + toolsdata.mass=5; + toolsdata.integrity=2; + toolsdata.triggering_event=0; + toolsdata.explosionType=0; + + toolsdata.shapeIndex=-1; + + //find the weapon's shape + switch(trueType) + { + case WEAPON_MARINE_PISTOL: + toolsdata.shapeIndex=GetLoadedShapeMSL("Pistol"); + break; + case WEAPON_PULSERIFLE: + toolsdata.shapeIndex=GetLoadedShapeMSL("pulse"); + break; + case WEAPON_SMARTGUN: + toolsdata.shapeIndex=GetLoadedShapeMSL("smart"); + break; + case WEAPON_FLAMETHROWER: + toolsdata.shapeIndex=GetLoadedShapeMSL("flame"); + break; + case WEAPON_FRISBEE_LAUNCHER: + toolsdata.shapeIndex=GetLoadedShapeMSL("Skeeter"); + toolsdata.orientation.EulerZ=1024; + break; + case WEAPON_SADAR: + toolsdata.shapeIndex=GetLoadedShapeMSL("sadar"); + break; + case WEAPON_GRENADELAUNCHER: + toolsdata.shapeIndex=GetLoadedShapeMSL("grenade"); + break; + case WEAPON_MINIGUN: + toolsdata.shapeIndex=GetLoadedShapeMSL("minigun"); + break; + + } + + if(toolsdata.shapeIndex==-1) + { + //failed to find shape + //forget about it + return 0; + } + //adjust the weapon , so it isn't stuck through the floor + toolsdata.position.vy-=(mainshapelist[toolsdata.shapeIndex]->shapemaxy); + + + + sbPtr = CreateActiveStrategyBlock(); + + InitialiseSBValues(sbPtr); + if(!sbPtr) return 0; + + sbPtr->I_SBtype = I_BehaviourInanimateObject; + sbPtr->shapeIndex=toolsdata.shapeIndex; + + EnableBehaviourType(sbPtr,I_BehaviourInanimateObject, &toolsdata ); + if(!sbPtr->SBdataptr) return 0; + + if(!name) + { + AssignNewSBName(sbPtr); + AddNetMsg_CreateWeapon(&sbPtr->SBname[0],trueType,location); + } + else + { + COPY_NAME(sbPtr->SBname,name); + } + + objectstatusptr=(INANIMATEOBJECT_STATUSBLOCK*)sbPtr->SBdataptr; + + objectstatusptr->lifespanTimer=20*ONE_FIXED; + + //sort out object visibility + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + sbPtr->containingModule = ModuleFromPosition(&(dynPtr->Position), (MODULE *)0); + sbPtr->maintainVisibility = 1; + + + dynPtr->GravityOn = 1; + + } + + return sbPtr; +} + +void MakePlayersWeaponPickupVisible() +{ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + STRATEGYBLOCK* sbPtr; + int i; + /* + Search through the strategy block list for weapons. + Any weapons that have a lifespan timer should be made visible. + There should only be one such object , so we can stop looking once we find it + */ + + for(i=NumActiveStBlocks-1;i>=0;i--) + { + sbPtr=ActiveStBlockList[i]; + if(sbPtr->I_SBtype==I_BehaviourInanimateObject && !sbPtr->maintainVisibility) + { + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr; + objectstatusptr=(INANIMATEOBJECT_STATUSBLOCK*)sbPtr->SBdataptr; + + if(objectstatusptr->typeId==IOT_Weapon) + { + if(objectstatusptr->lifespanTimer>0) + { + //okay we've found the object , so allow it to be visible + sbPtr->maintainVisibility = 1; + return; + } + } + } + } + +} + + +STRATEGYBLOCK* Create_Pred_Disc_Pickup_For_Load() +{ + STRATEGYBLOCK* sbPtr; + TOOLS_DATA_INANIMATEOBJECT toolsData; + int discShapeIndex; + + { + extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); + SECTION* section; + /* + We need to find the shape index of the disc object. To do this , we need to + get the disc head-up-display hierarchy , and search for the disc section + */ + section = GetNamedHierarchyFromLibrary("pred_HUD","disk"); + if(!section) return NULL; + + section = GetThisSection(section,"disk"); + if(!section) return NULL; + + //found the disc section + discShapeIndex = section->ShapeNum; + + } + + //fill in a tools data for the disc + memset(&toolsData,0,sizeof(toolsData)); + toolsData.typeId = IOT_Ammo; + toolsData.subType = (int)AMMO_PRED_DISC; + toolsData.shapeIndex = discShapeIndex; + + + sbPtr = CreateActiveStrategyBlock(); + + if(!sbPtr) + { + return NULL; + } + + InitialiseSBValues(sbPtr); + sbPtr->I_SBtype = I_BehaviourInanimateObject; + sbPtr->shapeIndex = discShapeIndex; + + EnableBehaviourType(sbPtr,I_BehaviourInanimateObject, &toolsData ); + sbPtr->maintainVisibility = 1; + + return sbPtr; + +} + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" +typedef struct inanimate_object_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + INANIMATEOBJECT_TYPE typeId; + int subType; /* weapon id, security level or other relevant enumerated type... */ + + BOOL Indestructable; + int explosionTimer; //slight time delay after destruction for explosion + + //strategyblock stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; + DYNAMICSBLOCK dynamics; +}INANIMATE_OBJECT_SAVE_BLOCK; + + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV objectstatusptr + +void LoadStrategy_InanimateObject(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr; + INANIMATE_OBJECT_SAVE_BLOCK* block = (INANIMATE_OBJECT_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) + { + //Didn't find the object already existing. + //Might be a predator disc pickup however. + if(block->typeId == IOT_Ammo && block->subType == (int)AMMO_PRED_DISC) + { + //okay we need to create a disc then + sbPtr = Create_Pred_Disc_Pickup_For_Load(); + } + if(!sbPtr) return; + + } + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourInanimateObject) return; + + objectstatusptr = (INANIMATEOBJECT_STATUSBLOCK*)sbPtr->SBdataptr; + + //start copying stuff + + COPYELEMENT_LOAD(Indestructable) + COPYELEMENT_LOAD(explosionTimer) + COPYELEMENT_LOAD(typeId) + COPYELEMENT_LOAD(subType) + + + + *sbPtr->DynPtr = block->dynamics; + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + +} + + +void SaveStrategy_InanimateObject(STRATEGYBLOCK* sbPtr) +{ + INANIMATE_OBJECT_SAVE_BLOCK *block; + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr; + + objectstatusptr = (INANIMATEOBJECT_STATUSBLOCK*)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + + COPYELEMENT_SAVE(Indestructable) + COPYELEMENT_SAVE(explosionTimer) + COPYELEMENT_SAVE(typeId) + COPYELEMENT_SAVE(subType) + + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; +} diff --git a/3dc/avp/PVISIBLE.H b/3dc/avp/PVISIBLE.H new file mode 100644 index 0000000..28e457b --- /dev/null +++ b/3dc/avp/PVISIBLE.H @@ -0,0 +1,146 @@ +/*-----------------Patrick 15/1/97--------------------- + This header file supports both the object visibility + management source, and pickup/inanimate objects.... + -----------------------------------------------------*/ + +#ifndef _pvisible_h_ + #define _pvisible_h_ 1 + + #ifdef __cplusplus + extern "C" { + #endif + + /* this enum defines the different inanimate object types ... */ + typedef enum inanimateobject_type + { + IOT_Non=-1, + IOT_Static=0, + IOT_Furniture, + IOT_Weapon, + IOT_Ammo, + IOT_Health, + IOT_Armour, + IOT_Key, + IOT_BoxedSentryGun, + IOT_IRGoggles, + IOT_ReservedForJohn, + IOT_DataTape, + IOT_MTrackerUpgrade, + IOT_PheromonePod, + IOT_SpecialPickupObject, + IOT_HitMeAndIllDestroyBase, + IOT_FieldCharge, + } INANIMATEOBJECT_TYPE; + + + /* this structure defines the datablock for pickup objects: + weapons, armour, etc, and is also used for inanimate objects + such as chairs, which are functionally quite similar + (except that they can't be picked up, obviously) */ + + typedef struct inan_frag + { + int ShapeIndex; + int NumFrags; + } INAN_FRAG; + + #define ObjectEventFlag_Destroyed 0x00000001 + #define ObjectEventFlag_PickedUp 0x00000002 + + typedef struct object_event_target + { + int triggering_event; + int request; + char event_target_ID[SB_NAME_LENGTH]; + STRATEGYBLOCK* event_target_sbptr; + }OBJECT_EVENT_TARGET; + + typedef struct inanimateobjectstatusblock + { + INANIMATEOBJECT_TYPE typeId; + int subType; /* weapon id, security level or other relevant enumerated type... */ + BOOL Indestructable; + int respawnTimer; + int lifespanTimer;//for dropped weapons in multiplayer that time out + int startingHealth; + int startingArmour; + + TXACTRLBLK *inan_tac;//for objects with anims on them + + OBJECT_EVENT_TARGET* event_target;//another strategy can be notified when this object is destroyed or picked up + + int explosionType;//non zero for explosive objects + int explosionTimer; //slight time delay after destruction for explosion + int explosionStartFrame; //frame that explosion started + + #if SupportWindows95 + INAN_FRAG * fragments; + int num_frags; + #endif + unsigned int ghosted_object:1; + + } INANIMATEOBJECT_STATUSBLOCK; + + /* tools interface */ + typedef struct tools_data_inanimateobject + { + struct vectorch position; + struct euler orientation; + INANIMATEOBJECT_TYPE typeId; + int subType; /* weapon id, security level or other relevant enumerated type... */ + int shapeIndex; /* for john */ + char nameID[SB_NAME_LENGTH]; + + int mass; // Kilos?? + int integrity; // 0-20 (>20 = indestructable) + + int triggering_event; + int event_request; + char event_target_ID[SB_NAME_LENGTH]; + + int explosionType; + + #if SupportWindows95 + INAN_FRAG * fragments; + int num_frags; + #endif + + } TOOLS_DATA_INANIMATEOBJECT; + + #define DEFAULT_OBJECT_INTEGRITY (100) + #define NO_OF_FRAGMENTS_FROM_OBJECT (6) + #define OBJECT_RESPAWN_TIME (ONE_FIXED*40) + + #define OBJECT_RESPAWN_NO_RESPAWN 0x7fffffff + + + /*-------------------------------------------- + Prototypes + --------------------------------------------*/ + void InitObjectVisibilities(void); + void DoObjectVisibilities(void); + MODULE* ModuleFromPosition(VECTORCH *position, MODULE* startingModule); + void DoObjectVisibility(STRATEGYBLOCK *sbPtr); + void InitInanimateObject(void* bhdata, STRATEGYBLOCK *sbPtr); + void InanimateObjectBehaviour(STRATEGYBLOCK *sbPtr); + void InanimateObjectIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple); + void KillInanimateObjectForRespawn(STRATEGYBLOCK *sbPtr); + void SendRequestToInanimateObject(STRATEGYBLOCK* sbptr,BOOL state,int extended_data); + + void MakeObjectNear(STRATEGYBLOCK *sbPtr); + void MakeObjectFar(STRATEGYBLOCK *sbPtr); + /* KJL 14:34:25 24/05/98 - does what it says */ + void RespawnAllObjects(void); + + void RespawnAllPickups(void); + /*-------------------------------------------------- + An external global that I need to make gun flashes + --------------------------------------------------*/ + extern MODULEMAPBLOCK VisibilityDefaultObjectMap; + + STRATEGYBLOCK* CreateMultiplayerWeaponPickup(VECTORCH* location,int type,char* name); + void MakePlayersWeaponPickupVisible(); + #ifdef __cplusplus + } + #endif +#endif diff --git a/3dc/avp/Paintball.c b/3dc/avp/Paintball.c new file mode 100644 index 0000000..df2ac75 --- /dev/null +++ b/3dc/avp/Paintball.c @@ -0,0 +1,211 @@ +/* KJL 16:20:30 30/09/98 - Paintball.c */ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "paintball.h" +#include "showcmds.h" +#define DECAL_Z_OFFSET 5 + +PAINTBALLMODE PaintBallMode; + +extern int NormalFrameTime; + +extern void TogglePaintBallMode(void) +{ + PaintBallMode.IsOn = ~PaintBallMode.IsOn; + + if (PaintBallMode.IsOn) + { + extern DECAL_DESC DecalDescription[]; + + PaintBallMode.CurrentDecalID = FIRST_PAINTBALL_DECAL; + PaintBallMode.CurrentDecalSubclass = 0; + PaintBallMode.CurrentDecalSize = DecalDescription[FIRST_PAINTBALL_DECAL].MinSize; + PaintBallMode.CurrentDecalRotation = 0; + PaintBallMode.DecalIsInverted = 0; + } +} + +DECAL CurrentDecal; + +extern void PaintBallMode_DrawCurrentDecalAtTarget(void) +{ + extern DECAL_DESC DecalDescription[]; + DECAL_DESC *decalDescPtr = &DecalDescription[PaintBallMode.CurrentDecalID]; + extern void MakeMatrixFromDirection(VECTORCH *directionPtr, MATRIXCH *matrixPtr); + extern int sine[],cosine[]; + extern MODULE *playerPherModule; + + MATRIXCH orientation; + int sin = MUL_FIXED(PaintBallMode.CurrentDecalSize,GetSin(PaintBallMode.CurrentDecalRotation)); + int cos = MUL_FIXED(PaintBallMode.CurrentDecalSize,GetCos(PaintBallMode.CurrentDecalRotation)); + int z = DECAL_Z_OFFSET; + if (!PaintBallMode.TargetDispPtr) return; + + if (! (PaintBallMode.TargetDispPtr->ObMyModule&&(!PaintBallMode.TargetDispPtr->ObMorphCtrl)) ) + { + return; + } + + CurrentDecal.DecalID = PaintBallMode.CurrentDecalID; + + if(PaintBallMode.DecalIsInverted) + { + PaintBallMode.TargetNormal.vx = -PaintBallMode.TargetNormal.vx; + PaintBallMode.TargetNormal.vy = -PaintBallMode.TargetNormal.vy; + PaintBallMode.TargetNormal.vz = -PaintBallMode.TargetNormal.vz; + z = -z; + } + + MakeMatrixFromDirection(&PaintBallMode.TargetNormal,&orientation); + + CurrentDecal.Vertices[0].vx = (-cos) - (-sin); + CurrentDecal.Vertices[0].vy = (-sin) + (-cos); + CurrentDecal.Vertices[0].vz = z; + RotateVector(&(CurrentDecal.Vertices[0]),&orientation); + CurrentDecal.Vertices[0].vx += PaintBallMode.TargetPosition.vx; + CurrentDecal.Vertices[0].vy += PaintBallMode.TargetPosition.vy; + CurrentDecal.Vertices[0].vz += PaintBallMode.TargetPosition.vz; + + + CurrentDecal.Vertices[1].vx = (cos) - (-sin); + CurrentDecal.Vertices[1].vy = (sin) + (-cos); + CurrentDecal.Vertices[1].vz = z; + RotateVector(&(CurrentDecal.Vertices[1]),&orientation); + CurrentDecal.Vertices[1].vx += PaintBallMode.TargetPosition.vx; + CurrentDecal.Vertices[1].vy += PaintBallMode.TargetPosition.vy; + CurrentDecal.Vertices[1].vz += PaintBallMode.TargetPosition.vz; + + CurrentDecal.Vertices[2].vx = (cos) - (sin); + CurrentDecal.Vertices[2].vy = (sin) + (cos); + CurrentDecal.Vertices[2].vz = z; + RotateVector(&(CurrentDecal.Vertices[2]),&orientation); + CurrentDecal.Vertices[2].vx += PaintBallMode.TargetPosition.vx; + CurrentDecal.Vertices[2].vy += PaintBallMode.TargetPosition.vy; + CurrentDecal.Vertices[2].vz += PaintBallMode.TargetPosition.vz; + + CurrentDecal.Vertices[3].vx = (-cos) - (sin); + CurrentDecal.Vertices[3].vy = (-sin) + (cos); + CurrentDecal.Vertices[3].vz = z; + RotateVector(&(CurrentDecal.Vertices[3]),&orientation); + CurrentDecal.Vertices[3].vx += PaintBallMode.TargetPosition.vx; + CurrentDecal.Vertices[3].vy += PaintBallMode.TargetPosition.vy; + CurrentDecal.Vertices[3].vz += PaintBallMode.TargetPosition.vz; + + CurrentDecal.ModuleIndex = playerPherModule->m_index; + + CurrentDecal.UOffset = PaintBallMode.CurrentDecalSubclass*decalDescPtr->UOffsetForSubclass; + RenderDecal(&CurrentDecal); + + { + PrintDebuggingText("PAINTBALL MODE ACTIVE\n"); + PrintDebuggingText("TOTAL PRE-DECALS: %d OUT OF 1024\n",NumFixedDecals); + } + +} + +extern void PaintBallMode_ChangeSelectedDecalID(int delta) +{ + extern DECAL_DESC DecalDescription[]; + + PaintBallMode.CurrentDecalID += delta; + + if (PaintBallMode.CurrentDecalID>LAST_PAINTBALL_DECAL) + { + PaintBallMode.CurrentDecalID=FIRST_PAINTBALL_DECAL; + } + else if (PaintBallMode.CurrentDecalID0) + { + PaintBallMode.CurrentDecalSize+=NormalFrameTime>>6; + if (PaintBallMode.CurrentDecalSize>decalDescPtr->MaxSize*2) + PaintBallMode.CurrentDecalSize=decalDescPtr->MaxSize*2; + } + else + { + PaintBallMode.CurrentDecalSize-=NormalFrameTime>>6; + if (PaintBallMode.CurrentDecalSizeMinSize) + PaintBallMode.CurrentDecalSize=decalDescPtr->MinSize; + } +} + +extern void PaintBallMode_Rotate(void) +{ + PaintBallMode.CurrentDecalRotation += NormalFrameTime>>5; + PaintBallMode.CurrentDecalRotation &= 4095; +} + +extern void PaintBallMode_ChangeSubclass(int delta) +{ + extern DECAL_DESC DecalDescription[]; + DECAL_DESC *decalDescPtr = &DecalDescription[PaintBallMode.CurrentDecalID]; + + PaintBallMode.CurrentDecalSubclass += delta; + + if (PaintBallMode.CurrentDecalSubclass>decalDescPtr->MaxSubclassNumber) + { + PaintBallMode.CurrentDecalSubclass=0; + } + else if (PaintBallMode.CurrentDecalSubclass<0) + { + PaintBallMode.CurrentDecalSubclass=decalDescPtr->MaxSubclassNumber; + } + +} + + +extern void PaintBallMode_AddDecal(void) +{ + FIXED_DECAL *newDecalPtr = AllocateFixedDecal(); + + if (!newDecalPtr) return; + + newDecalPtr->DecalID = CurrentDecal.DecalID; + newDecalPtr->Vertices[0] = CurrentDecal.Vertices[0]; + newDecalPtr->Vertices[1] = CurrentDecal.Vertices[1]; + newDecalPtr->Vertices[2] = CurrentDecal.Vertices[2]; + newDecalPtr->Vertices[3] = CurrentDecal.Vertices[3]; + newDecalPtr->ModuleIndex = CurrentDecal.ModuleIndex; + newDecalPtr->UOffset = CurrentDecal.UOffset; +} +extern void PaintBallMode_RemoveDecal(void) +{ + RemoveFixedDecal(); +} + +extern void PaintBallMode_Randomise(void) +{ + extern DECAL_DESC DecalDescription[]; + DECAL_DESC *decalDescPtr = &DecalDescription[PaintBallMode.CurrentDecalID]; + + int randomScale = ONE_FIXED+4096 - (FastRandom()&8191); + + PaintBallMode.CurrentDecalSize = MUL_FIXED(PaintBallMode.CurrentDecalSize,randomScale); + + if (PaintBallMode.CurrentDecalSize>decalDescPtr->MaxSize) + { + PaintBallMode.CurrentDecalSize=decalDescPtr->MaxSize; + } + if (PaintBallMode.CurrentDecalSizeMinSize) + { + PaintBallMode.CurrentDecalSize=decalDescPtr->MinSize; + } + + PaintBallMode.CurrentDecalRotation = FastRandom()&4095; + +} \ No newline at end of file diff --git a/3dc/avp/Paintball.h b/3dc/avp/Paintball.h new file mode 100644 index 0000000..47f93ab --- /dev/null +++ b/3dc/avp/Paintball.h @@ -0,0 +1,34 @@ +/* KJL 16:20:56 30/09/98 - Paintball.h */ +#ifndef _included_paintball_h_ /* Is this your first time? */ +#define _included_paintball_h_ 1 + +#include "Decal.h" + +typedef struct +{ + DISPLAYBLOCK *TargetDispPtr; + VECTORCH TargetPosition; + VECTORCH TargetNormal; + + enum DECAL_ID CurrentDecalID; + int CurrentDecalSubclass; + int CurrentDecalSize; + int CurrentDecalRotation; + + unsigned int IsOn :1; + unsigned int DecalIsInverted :1; + +} PAINTBALLMODE; + +extern PAINTBALLMODE PaintBallMode; + +#define FIRST_PAINTBALL_DECAL (DECAL_SCORCHED) +#define LAST_PAINTBALL_DECAL (DECAL_HUMAN_BLOOD) + +extern void TogglePaintBallMode(void); +extern void PaintBallMode_DrawCurrentDecalAtTarget(void); +extern void PaintBallMode_ChangeSelectedDecalID(int delta); +extern void PaintBallMode_ChangeSize(int delta); +extern void PaintBallMode_AddDecal(void); + +#endif \ No newline at end of file diff --git a/3dc/avp/Player.c b/3dc/avp/Player.c new file mode 100644 index 0000000..1d73f10 --- /dev/null +++ b/3dc/avp/Player.c @@ -0,0 +1,2183 @@ +/* KJL 16:23:20 10/25/96 - I'm moved all the weapon stuff to the newly created weapon.c, +so player.c is looking a bit bare at the moment. */ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "inventry.h" +#include "gameplat.h" +#include "dynblock.h" +#include "dynamics.h" +#include "comp_shp.h" +#include "weapons.h" +#include "vision.h" +#include "pheromon.h" +#include "avpview.h" +#include "particle.h" +#include "scream.h" +#include "savegame.h" +#if SupportWindows95 + #include "rebmenus.hpp" +#endif + +#define UseLocalAssert Yes +#include "ourasert.h" + +#include "psnd.h" +#include "psndplat.h" + +/* for win 95 net support */ +#if SupportWindows95 +#include "pldnet.h" +#include "pldghost.h" +#include "dp_func.h" +#endif +#include "ShowCmds.h" +#include "BonusAbilities.h" + +#define PLAYER_HMODEL 0 + +/*KJL**************************************************************************************** +* G L O B A L S * +****************************************************************************************KJL*/ +VECTORCH PlayerStartLocation; +MATRIXCH PlayerStartMat; +extern int NormalFrameTime; +extern ACTIVESOUNDSAMPLE ActiveSounds[]; +extern int PlayerDamagedOverlayIntensity; +extern int playerNoise; +extern int predHUDSoundHandle; +extern int predOVision_SoundHandle; + +extern int AIModuleArraySize; + +int GimmeChargeCalls; +int HtoHStrikes; +int CurrentLightAtPlayer; +int TauntSoundPlayed; + +int TrickleCharge=9000; +int CloakDrain=12000; +int CloakThreshold=(5*ONE_FIXED); +int CloakPowerOnDrain=(2*ONE_FIXED); + +extern DPID myNetworkKillerId; +extern DPID myIgniterId; +extern int MyHitBodyPartId; +extern HMODELCONTROLLER PlayersWeaponHModelController; +extern SECTION_DATA *PWMFSDP; /* PlayersWeaponMuzzleFlashSectionDataPointer */ + +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ +void InitPlayer(STRATEGYBLOCK* sbPtr, int sb_type); +void MaintainPlayer(void); +void PlayerIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiplier,VECTORCH* incoming); +static void PlayerIsDead(DAMAGE_PROFILE *damage,int multiplier,VECTORCH* incoming); + +extern int LightIntensityAtPoint(VECTORCH *pointPtr); +extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); +extern int SlotForThisWeapon(enum WEAPON_ID weaponID); +extern void PointAlert(int level, VECTORCH *point); +extern void RemoveAllThisPlayersDiscs(void); +void ShowAdjacencies(void); + +extern int ShowAdj; + +/*KJL**************************************************************************************** +* F U N C T I O N S * +****************************************************************************************KJL*/ + +PLAYER_STATUS* PlayerStatusPtr = NULL; +static PLAYER_STATUS PlayerStatusBlock; +int ShowPredoStats=0; +int Observer=0; + +/* Patrick 22/8/97------------------------------------------------ +Cloaking stuff +------------------------------------------------------------------*/ +void InitPlayerCloakingSystem(void); +static void DoPlayerCloakingSystem(void); + +void InitPlayer(STRATEGYBLOCK* sbPtr, int sb_type) +{ + /*KJL************************************************************************************** + * InitPlayer() was written by me. It attaches the extra player data to the strategy block * + * and fills in some initial values. * + **************************************************************************************KJL*/ + + SECTION *root_section; + PLAYER_STATUS *psPtr = &PlayerStatusBlock; + GLOBALASSERT(psPtr); + GLOBALASSERT(sbPtr); + + // set up our global + + PlayerStatusPtr = psPtr; + + + sbPtr->I_SBtype = sb_type; + sbPtr->SBdataptr = (void*)psPtr; + + InitialisePlayersInventory(psPtr); + + /* Initialise Player's stats */ + { + NPC_DATA *NpcData; + NPC_TYPES PlayerType; + + switch(AvP.PlayerType) + { + case(I_Marine): + { + switch (AvP.Difficulty) { + case I_Easy: + PlayerType=I_PC_Marine_Easy; + break; + default: + case I_Medium: + PlayerType=I_PC_Marine_Medium; + break; + case I_Hard: + PlayerType=I_PC_Marine_Hard; + break; + case I_Impossible: + PlayerType=I_PC_Marine_Impossible; + break; + } + + #if 0 //this hmodel isn't being set up for the moment - Richard + root_section=GetNamedHierarchyFromLibrary("hnpcmarine","Template"); + if (!root_section) { + GLOBALASSERT(0); + /* Sorry, there's just no bouncing back from this one. Fix it. */ + return; + } + #if PLAYER_HMODEL + Create_HModel(&psPtr->HModelController,root_section); + InitHModelSequence(&psPtr->HModelController,0,0,ONE_FIXED); + #endif + /* Doesn't matter what the sequence is... */ + #endif + break; + } + case(I_Predator): + { + switch (AvP.Difficulty) { + case I_Easy: + PlayerType=I_PC_Predator_Easy; + break; + default: + case I_Medium: + PlayerType=I_PC_Predator_Medium; + break; + case I_Hard: + PlayerType=I_PC_Predator_Hard; + break; + case I_Impossible: + PlayerType=I_PC_Predator_Impossible; + break; + } + + #if 0 //this hmodel isn't being set up for the moment - Richard + root_section=GetNamedHierarchyFromLibrary("hnpcpredator","Template"); + if (!root_section) { + GLOBALASSERT(0); + /* Sorry, there's just no bouncing back from this one. Fix it. */ + return; + } + #if PLAYER_HMODEL + Create_HModel(&psPtr->HModelController,root_section); + InitHModelSequence(&psPtr->HModelController,0,0,ONE_FIXED); + #endif + /* Doesn't matter what the sequence is... */ + #endif + break; + } + case(I_Alien): + { + switch (AvP.Difficulty) { + case I_Easy: + PlayerType=I_PC_Alien_Easy; + break; + default: + case I_Medium: + PlayerType=I_PC_Alien_Medium; + break; + case I_Hard: + PlayerType=I_PC_Alien_Hard; + break; + case I_Impossible: + PlayerType=I_PC_Alien_Impossible; + break; + } + + #if 0 //this hmodel isn't being set up for the moment - Richard + root_section=GetNamedHierarchyFromLibrary("hnpcalien","alien"); + if (!root_section) { + GLOBALASSERT(0); + /* Sorry, there's just no bouncing back from this one. Fix it. */ + return; + } + #if PLAYER_HMODEL + Create_HModel(&psPtr->HModelController,root_section); + InitHModelSequence(&psPtr->HModelController,0,0,ONE_FIXED); + #endif + /* Doesn't matter what the sequence is... */ + #endif + break; + + } + default: + { + LOCALASSERT(1==0); + break; + } + } + + NpcData=GetThisNpcData(PlayerType); + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + sbPtr->SBDamageBlock.IsOnFire=0; + + //{ + // int *nptr,i; + // nptr=(int *)sbPtr->SBname; + // for (i=0; i<(SB_NAME_LENGTH>>2); i++) { + // *nptr=FastRandom(); + // nptr++; + // } + // sbPtr->SBname[SB_NAME_LENGTH-1]=3; /* Just to make sure... */ + //} + AssignNewSBName(sbPtr); + } + + //psPtr->Health=STARTOFGAME_MARINE_HEALTH; + psPtr->Energy=STARTOFGAME_MARINE_ENERGY; + //psPtr->Armour=STARTOFGAME_MARINE_ARMOUR; + + psPtr->Encumberance.MovementMultiple=ONE_FIXED; + psPtr->Encumberance.TurningMultiple=ONE_FIXED; + psPtr->Encumberance.JumpingMultiple=ONE_FIXED; + psPtr->Encumberance.CanCrouch=1; + psPtr->Encumberance.CanRun=1; + + psPtr->incidentFlag=0; + psPtr->incidentTimer=0; + + /* CDF 16/9/97 Now, those health and armour stats are those of the last cycle. */ + + psPtr->Health=sbPtr->SBDamageBlock.Health; + psPtr->Armour=sbPtr->SBDamageBlock.Armour; + + psPtr->IsAlive = 1; + psPtr->IHaveAPlacedAutogun = 0; + psPtr->MyFaceHugger=NULL; + psPtr->MyCorpse=NULL; + psPtr->tauntTimer=0; + TauntSoundPlayed=0; + psPtr->fireTimer=0; + psPtr->invulnerabilityTimer=0; + /* Better safe than sorry. */ + psPtr->soundHandle=SOUND_NOACTIVEINDEX; + psPtr->soundHandle3=SOUND_NOACTIVEINDEX; + psPtr->soundHandle4=SOUND_NOACTIVEINDEX; + psPtr->soundHandle5=SOUND_NOACTIVEINDEX; + psPtr->soundHandleForPredatorCloakDamaged=SOUND_NOACTIVEINDEX; + InitPlayerCloakingSystem();/* Patrick 22/8/97 : Cloaking stuff */ + + /* KJL 12:06:01 11/14/96 - allocate dynamics block & fill from template */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_MARINE_PLAYER); + /* for the time being get world position and orientation from the displayblock */ + { + DISPLAYBLOCK *dPtr = sbPtr->SBdptr; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + GLOBALASSERT(dPtr); + GLOBALASSERT(dynPtr); + + dynPtr->Position = PlayerStartLocation; + dynPtr->OrientMat = PlayerStartMat; + MatrixToEuler(&dynPtr->OrientMat,&dynPtr->OrientEuler); + //dynPtr->OrientEuler = dPtr->ObEuler; + + + dynPtr->PrevPosition = dynPtr->Position; + dynPtr->PrevOrientMat = dynPtr->OrientMat; + dynPtr->PrevOrientEuler = dynPtr->OrientEuler; + + /* let alien walk on walls & ceiling */ + if (AvP.PlayerType == I_Alien) + { + dynPtr->ToppleForce = TOPPLE_FORCE_ALIEN; + } + + /* KJL 10:56:57 11/24/97 - set ObRadius to a sensible value */ + dPtr->ObRadius = 1200; + + /* + if (AvP.PlayerType == I_Alien) sbPtr->I_SBtype = I_BehaviourAlienPlayer; + if (AvP.PlayerType == I_Predator) sbPtr->I_SBtype = I_BehaviourPredatorPlayer;*/ + /* KJL 18:30:09 11/11/98 - datum used for falling damage */ + { + extern int PlayersMaxHeightWhilstNotInContactWithGround; + PlayersMaxHeightWhilstNotInContactWithGround=dynPtr->Position.vy; + } + } + + /* zero inertia values */ + psPtr->ForwardInertia=0; + psPtr->StrafeInertia=0; + psPtr->TurnInertia=0; + psPtr->IsMovingInWater = 0; + PlayerDamagedOverlayIntensity = 0; + + /* a little addition by patrick */ + InitPlayerMovementData(sbPtr); + + /* security clearance */ + psPtr->securityClearances = 0; + + /* thou art mortal */ + psPtr->IsImmortal = 0; + + if (AvP.Network==I_No_Network) + { + SoundSys_FadeIn(); + } + else + { + SoundSys_ResetFadeLevel(); + } + + //restore the number of saves allowed + ResetNumberOfSaves(); + +#if SupportWindows95 + //choosing a start position now occurs later on +// if(AvP.Network!=I_No_Network) TeleportNetPlayerToAStartingPosition(sbPtr, 1); +#endif + +} + +void ChangeToMarine() +{ + if(AvP.Network!=I_No_Network) + { + AvP.PlayerType=I_Marine; + NetPlayerRespawn(Player->ObStrategyBlock); + InitPlayerMovementData(Player->ObStrategyBlock); + Player->ObStrategyBlock->DynPtr->ToppleForce=TOPPLE_FORCE_NONE; + netGameData.myCharacterType=netGameData.myNextCharacterType=NGCT_Marine; + + //reorient the player + { + EULER e; + MatrixToEuler(&Player->ObStrategyBlock->DynPtr->OrientMat,&e); + e.EulerX=0; + e.EulerZ=0; + + CreateEulerMatrix(&e,&Player->ObStrategyBlock->DynPtr->OrientMat); + TransposeMatrixCH(&Player->ObStrategyBlock->DynPtr->OrientMat); + + Player->ObStrategyBlock->DynPtr->UseStandardGravity=1; + } + + /* CDF 15/3/99, delete all discs... */ + RemoveAllThisPlayersDiscs(); + + } +} +void ChangeToAlien() +{ + if(AvP.Network!=I_No_Network) + { + AvP.PlayerType=I_Alien; + NetPlayerRespawn(Player->ObStrategyBlock); + InitPlayerMovementData(Player->ObStrategyBlock); + Player->ObStrategyBlock->DynPtr->ToppleForce=TOPPLE_FORCE_ALIEN; + + netGameData.myCharacterType=netGameData.myNextCharacterType=NGCT_Alien; + + /* CDF 15/3/99, delete all discs... */ + RemoveAllThisPlayersDiscs(); + } +} +void ChangeToPredator() +{ + if(AvP.Network!=I_No_Network) + { + AvP.PlayerType=I_Predator; + NetPlayerRespawn(Player->ObStrategyBlock); + InitPlayerMovementData(Player->ObStrategyBlock); + Player->ObStrategyBlock->DynPtr->ToppleForce=TOPPLE_FORCE_NONE; + netGameData.myCharacterType=netGameData.myNextCharacterType=NGCT_Predator; + + //reorient the player + { + EULER e; + MatrixToEuler(&Player->ObStrategyBlock->DynPtr->OrientMat,&e); + e.EulerX=0; + e.EulerZ=0; + + CreateEulerMatrix(&e,&Player->ObStrategyBlock->DynPtr->OrientMat); + TransposeMatrixCH(&Player->ObStrategyBlock->DynPtr->OrientMat); + + Player->ObStrategyBlock->DynPtr->UseStandardGravity=1; + } + + /* CDF 15/3/99, delete all discs... */ + RemoveAllThisPlayersDiscs(); + } +} + +void MaintainPlayer(void) +{ + int rand = FastRandom(); + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + if (playerStatusPtr->IsAlive) + { + MaintainPlayersInventory(); + } + + if (ShowAdj) { + ShowAdjacencies(); + } + + /* Set here, as first point. */ + playerNoise=0; + + /* Incident handling. */ + playerStatusPtr->incidentFlag=0; + + playerStatusPtr->incidentTimer-=NormalFrameTime; + + if (playerStatusPtr->incidentTimer<0) { + playerStatusPtr->incidentFlag=1; + playerStatusPtr->incidentTimer=32767+(FastRandom()&65535); + } + + /* CDF 9/6/98 - I can't believe this isn't done!!! */ + Player->ObStrategyBlock->containingModule = playerPherModule; + + if (Observer) { + textprint("Observer Mode...\n"); + } + textprint("HtoH Strikes %d\n",HtoHStrikes); + + DoPlayerCloakingSystem();/* Patrick 22/8/97 : Cloaking stuff */ + // HandlePredatorVisionModes(); + + CurrentLightAtPlayer=LightIntensityAtPoint(&Player->ObStrategyBlock->DynPtr->Position); + + #if 1 + textprint("PlayerLight %d\n",CurrentLightAtPlayer); + #endif + + #if SupportWindows95 + #if 0//UseRebMenus + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_PauseGame) + { + REBMENUS_ProcessPauseRequest(); + } + #else + if(AvP.Network==I_No_Network) + { + #if 1 + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_PauseGame) + { + // go to start menu + AvP.MainLoopRunning = 0; + } + #endif + } + else + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_PauseGame) + { + if (AvP.Network == I_Host) + { + TransmitEndOfGameNetMsg(); + netGameData.myGameState = NGS_EndGame; + } + else if (AvP.Network == I_Peer) + { + TransmitPlayerLeavingNetMsg(); + netGameData.myGameState = NGS_Leaving; + } + // go to start menu + AvP.MainLoopRunning = 0; + } + #endif + #endif + //Update the player's invulnerabilty timer + if(playerStatusPtr->invulnerabilityTimer>0) + { + playerStatusPtr->invulnerabilityTimer-=NormalFrameTime; + + if(playerStatusPtr->invulnerabilityTimer<=0) + { + playerStatusPtr->invulnerabilityTimer=0; + } + //lose invulnerability if player is firing + + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FirePrimaryWeapon) + { + PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + if(weaponPtr->WeaponIDNumber!=WEAPON_PRED_MEDICOMP) + { + playerStatusPtr->invulnerabilityTimer=0; + } + } + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FireSecondaryWeapon) + { + //not many weapons have an offensive secondary fire + PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + if(weaponPtr->WeaponIDNumber == WEAPON_PULSERIFLE || + weaponPtr->WeaponIDNumber == WEAPON_CUDGEL || + weaponPtr->WeaponIDNumber == WEAPON_MARINE_PISTOL || + weaponPtr->WeaponIDNumber == WEAPON_TWO_PISTOLS || + weaponPtr->WeaponIDNumber == WEAPON_PRED_WRISTBLADE || + weaponPtr->WeaponIDNumber == WEAPON_ALIEN_CLAW) + { + playerStatusPtr->invulnerabilityTimer=0; + } + } + } + + + if (AvP.DestructTimer>0) { + extern int NormalFrameTime; + + AvP.DestructTimer-=NormalFrameTime; + if (AvP.DestructTimer<0) AvP.DestructTimer=0; + + } else if (AvP.DestructTimer==0) { + // ...Destruct? + CauseDamageToObject(Player->ObStrategyBlock,&TemplateAmmo[AMMO_SADAR_TOW].MaxDamage[AvP.Difficulty], 25*ONE_FIXED,NULL); + // That'll learn 'em. + } + + /* Take speed sample. */ + { + int speed; + + speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity); + CurrentGameStats_SpeedSample(speed,NormalFrameTime); + } + + /* Is the player on fire? */ + if (Player->ObStrategyBlock->SBDamageBlock.IsOnFire) { + + myNetworkKillerId=myIgniterId; + CauseDamageToObject(Player->ObStrategyBlock,&firedamage,NormalFrameTime,NULL); + myNetworkKillerId=AVPDPNetID; + + if (playerStatusPtr->soundHandle3!=SOUND_NOACTIVEINDEX) { + if (ActiveSounds[playerStatusPtr->soundHandle3].soundIndex!=SID_FIRE) { + Sound_Stop(playerStatusPtr->soundHandle3); + Sound_Play(SID_FIRE,"dlev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle3,127); + } else { + Sound_Update3d(playerStatusPtr->soundHandle3,&(Player->ObStrategyBlock->DynPtr->Position)); + } + } else if (playerStatusPtr->IsAlive) { + Sound_Play(SID_FIRE,"dlev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle3,127); + } + + /* Put the fire out... */ + + #if 1 + { + int speed; + /* Go out? */ + speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity); + + if (speed>22000) { + /* Jumping alien. */ + playerStatusPtr->fireTimer-=(NormalFrameTime*6); + } else if (speed>15000) { + /* Running alien. */ + playerStatusPtr->fireTimer-=(NormalFrameTime<<2); + } else { + /* Normal bloke. */ + playerStatusPtr->fireTimer-=NormalFrameTime; + } + + if(playerStatusPtr->invulnerabilityTimer>0) + { + //player is invulnerable, so put him out. + playerStatusPtr->fireTimer=0; + } + + if (playerStatusPtr->fireTimer<=0) { + /* Go out. */ + Player->ObStrategyBlock->SBDamageBlock.IsOnFire=0; + playerStatusPtr->fireTimer=0; + } + } + #else + if (playerStatusPtr->incidentFlag) { + int speed; + /* Go out? */ + speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity); + + if (speed>15000) { + /* Running alien. */ + if ((FastRandom()&65535)<13107) { + Player->ObStrategyBlock->SBDamageBlock.IsOnFire=0; + } + } else { + /* Normal bloke. */ + if ((FastRandom()&65535)<3000) { + Player->ObStrategyBlock->SBDamageBlock.IsOnFire=0; + } + } + } + #endif + } else { + if (playerStatusPtr->soundHandle3!=SOUND_NOACTIVEINDEX) { + Sound_Stop(playerStatusPtr->soundHandle3); + } + } + + if (playerStatusPtr->IsMovingInWater) + { + #if 0 + if (playerStatusPtr->soundHandle4==SOUND_NOACTIVEINDEX) { + switch (rand % 4) { + case 0: + Sound_Play(SID_SPLASH1,"dev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle4,127); + break; + case 1: + Sound_Play(SID_SPLASH2,"dev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle4,127); + break; + case 2: + Sound_Play(SID_SPLASH3,"dev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle4,127); + break; + default: + Sound_Play(SID_SPLASH4,"dev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle4,127); + break; + } + } + #else + /* KJL 19:07:57 25/05/98 - make a noise at most every 1/4 of a sec */ + if (playerStatusPtr->soundHandle4<=0) + { + switch (rand&3) + { + case 0: + Sound_Play(SID_SPLASH1,"d",&(Player->ObStrategyBlock->DynPtr->Position)); + break; + case 1: + Sound_Play(SID_SPLASH2,"d",&(Player->ObStrategyBlock->DynPtr->Position)); + break; + case 2: + Sound_Play(SID_SPLASH3,"d",&(Player->ObStrategyBlock->DynPtr->Position)); + break; + default: + Sound_Play(SID_SPLASH4,"d",&(Player->ObStrategyBlock->DynPtr->Position)); + break; + + } + playerStatusPtr->soundHandle4=16384; + } + else + { + playerStatusPtr->soundHandle4-=NormalFrameTime; + } + #endif + } + + + /* KJL 14:54:48 25/05/98 - reset water flag to zero for next frame */ + playerStatusPtr->IsMovingInWater = 0; + + /* Taunt effects. */ + if (playerStatusPtr->tauntTimer) { + int ex,ey,ez; + + playerNoise=1; + /* An actual noise, too, would probably be good. */ + + if (AvP.PlayerType==I_Alien) { + + //if (playerStatusPtr->tauntTimer>(TAUNT_LENGTH>>1)) { + if (TauntSoundPlayed==0) { + /* That should make sure we don't get more than one. */ + if (playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) { + #if 0 + Sound_Play(SID_ALIEN_SCREAM,"de",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle); + #else + PlayAlienSound(0,ASC_Taunt,0,&playerStatusPtr->soundHandle,&(Player->ObStrategyBlock->DynPtr->Position)); + if(AvP.Network!=I_No_Network) netGameData.myLastScream=ASC_Taunt; + #endif + TauntSoundPlayed=1; + } + } + + /* Wave the head around? */ + ex=0; + ey=0; + ez=0; + + ex=MUL_FIXED(64,GetSin(((playerStatusPtr->tauntTimer>>6)&wrap360))); + ey=MUL_FIXED(128,GetSin(((playerStatusPtr->tauntTimer>>5)&wrap360))); + ez=MUL_FIXED(-64,GetSin(((playerStatusPtr->tauntTimer>>5)&wrap360))); + + ex&=wrap360; + ey&=wrap360; + ez&=wrap360; + + HeadOrientation.EulerX=ex; + HeadOrientation.EulerY=ey; + HeadOrientation.EulerZ=ez; + } else if (AvP.PlayerType==I_Marine) { + if (TauntSoundPlayed==0) { + /* That should make sure we don't get more than one. */ + if (playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) { + PlayMarineScream(0,SC_Taunt,0,&playerStatusPtr->soundHandle,NULL); + if(AvP.Network!=I_No_Network) netGameData.myLastScream=SC_Taunt; + TauntSoundPlayed=1; + } + } + } else if (AvP.PlayerType==I_Predator) { + if (TauntSoundPlayed==0) { + /* That should make sure we don't get more than one. */ + if (playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) { + PlayPredatorSound(0,PSC_Taunt,0,&playerStatusPtr->soundHandle,NULL); + if(AvP.Network!=I_No_Network) netGameData.myLastScream=PSC_Taunt; + TauntSoundPlayed=1; + } + } + } else { + GLOBALASSERT(0); + } + + } + + /* Decay alien superhealth. */ + if (AvP.PlayerType==I_Alien) { + NPC_DATA *NpcData; + + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Alien_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Alien_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Alien_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Alien_Impossible); + break; + } + LOCALASSERT(NpcData); + + if (Player->ObStrategyBlock->SBDamageBlock.Health>(NpcData->StartingStats.Health<ObStrategyBlock->SBDamageBlock.Health-=(NormalFrameTime); + if (Player->ObStrategyBlock->SBDamageBlock.Health<(NpcData->StartingStats.Health<ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<Health=Player->ObStrategyBlock->SBDamageBlock.Health; + } + } +} + +void PlayerIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiplier,VECTORCH* incoming) +{ + int rand = FastRandom(); + int pitch = (rand & 255) - 128; + int deltaHealth; + int deltaArmour; + + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + deltaHealth=playerStatusPtr->Health-sbPtr->SBDamageBlock.Health; + deltaArmour=playerStatusPtr->Armour-sbPtr->SBDamageBlock.Armour; + + CurrentGameStats_DamageTaken(deltaHealth,deltaArmour); + + /* Patrick 4/8/97-------------------------------------------------- + A little hack-et to make the predator tougher in multiplayer games + ------------------------------------------------------------------*/ + //if((AvP.Network!=I_No_Network)&&(AvP.PlayerType==I_Predator)) damage>>=1; + /* ChrisF 16/9/97 No, predators are now... wait for it... tough. */ + + if (playerStatusPtr->IsAlive) + { + #if 0 + damage <<= 16; + if (playerStatusPtr->Armour > 0) + { + if (playerStatusPtr->Armour >= damage/2) + { + playerStatusPtr->Armour -= damage/2; + playerStatusPtr->Health -= damage/4; + } + else + { + damage -= playerStatusPtr->Armour*2; + playerStatusPtr->Health -= playerStatusPtr->Armour/2 + damage; + playerStatusPtr->Armour = 0; + } + } + else + { + playerStatusPtr->Health -= damage; + } + #endif + { + int maxTilt = deltaHealth>>12; + int halfTilt = maxTilt/2; + if (maxTilt) + { + HeadOrientation.EulerX = (FastRandom()%maxTilt)-halfTilt; + HeadOrientation.EulerY = (FastRandom()%maxTilt)-halfTilt; + HeadOrientation.EulerZ = (FastRandom()%maxTilt)-halfTilt; + + if (HeadOrientation.EulerX < 0) HeadOrientation.EulerX += 4096; + if (HeadOrientation.EulerY < 0) HeadOrientation.EulerY += 4096; + if (HeadOrientation.EulerZ < 0) HeadOrientation.EulerZ += 4096; + } + } + + if ((playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX)&&(deltaHealth||deltaArmour)) { + switch (AvP.PlayerType) + { + case I_Alien: + { + if ((damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire>0) + &&(damage->Electrical==0) + &&(damage->Acid==0) + ) { + PlayAlienSound(0,ASC_PC_OnFire,pitch,&playerStatusPtr->soundHandle,NULL); + if(AvP.Network!=I_No_Network) netGameData.myLastScream=ASC_PC_OnFire; + } else { + PlayAlienSound(0,ASC_Scream_Hurt,pitch,&playerStatusPtr->soundHandle,NULL); + if(AvP.Network!=I_No_Network) netGameData.myLastScream=ASC_Scream_Hurt; + } + break; + } + + case I_Marine: + { + if (damage->Id==AMMO_FACEHUGGER) { + PlayMarineScream(0,SC_Facehugged,pitch,&playerStatusPtr->soundHandle,NULL); + } else if (damage->Id==AMMO_FALLING_POSTMAX) { + PlayMarineScream(0,SC_Falling,pitch,&playerStatusPtr->soundHandle,NULL); + } else if ((damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire==0) + &&(damage->Electrical==0) + &&(damage->Acid>0) + ) { + PlayMarineScream(0,SC_Acid,pitch,&playerStatusPtr->soundHandle,NULL); + if(AvP.Network!=I_No_Network) netGameData.myLastScream=SC_Acid; + } else if ((damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire>0) + &&(damage->Electrical==0) + &&(damage->Acid==0) + ) { + PlayMarineScream(0,SC_PC_OnFire,pitch,&playerStatusPtr->soundHandle,NULL); + if(AvP.Network!=I_No_Network) netGameData.myLastScream=SC_PC_OnFire; + } else { + PlayMarineScream(0,SC_Pain,pitch,&playerStatusPtr->soundHandle,NULL); + if(AvP.Network!=I_No_Network) netGameData.myLastScream=SC_Pain; + } + break; + } + + case I_Predator: + { + if (damage->Id==AMMO_FACEHUGGER) { + PlayPredatorSound(0,PSC_Facehugged,pitch,&playerStatusPtr->soundHandle,NULL); + } else if ((damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire==0) + &&(damage->Electrical==0) + &&(damage->Acid>0) + ) { + PlayPredatorSound(0,PSC_Acid,pitch,&playerStatusPtr->soundHandle,NULL); + if(AvP.Network!=I_No_Network) netGameData.myLastScream=PSC_Acid; + } else if ((damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire>0) + &&(damage->Electrical==0) + &&(damage->Acid==0) + ) { + PlayPredatorSound(0,PSC_PC_OnFire,pitch,&playerStatusPtr->soundHandle,NULL); + if(AvP.Network!=I_No_Network) netGameData.myLastScream=PSC_PC_OnFire; + } else { + PlayPredatorSound(0,PSC_Scream_Hurt,pitch,&playerStatusPtr->soundHandle,NULL); + if(AvP.Network!=I_No_Network) netGameData.myLastScream=PSC_Scream_Hurt; + } + break; + } + + default: + { + break; + } + } + playerNoise=1; + /* Alert marines, pretty much whoever you are. */ + if (AvP.PlayerType==I_Marine) { + PointAlert(3, &Player->ObStrategyBlock->DynPtr->Position); + } else { + #if 0 + PointAlert(2, &Player->ObStrategyBlock->DynPtr->Position); + #endif + } + } + + { + NPC_DATA *NpcData; + int scaled_DeltaHealth; + + switch (AvP.PlayerType) + { + case I_Marine: + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Marine_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Marine_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Marine_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Marine_Impossible); + break; + } + break; + case I_Alien: + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Alien_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Alien_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Alien_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Alien_Impossible); + break; + } + break; + case I_Predator: + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Predator_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Predator_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Predator_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Predator_Impossible); + break; + } + break; + default: + LOCALASSERT(0); + break; + } + /* Compute scaled deltaHealth... */ + scaled_DeltaHealth=MUL_FIXED(deltaHealth,100); + scaled_DeltaHealth=DIV_FIXED(scaled_DeltaHealth,NpcData->StartingStats.Health); + + if (scaled_DeltaHealth>PlayerDamagedOverlayIntensity) + { + PlayerDamagedOverlayIntensity=scaled_DeltaHealth; + } + } + + if (deltaHealth>ONE_FIXED) + { + VECTORCH abovePosition = Global_VDB_Ptr->VDB_World; + abovePosition.vy-=1000; + switch (AvP.PlayerType) + { + case I_Alien: + MakeBloodExplosion(&Global_VDB_Ptr->VDB_World, 127, &abovePosition, deltaHealth/ONE_FIXED, PARTICLE_ALIEN_BLOOD); + break; + case I_Marine: + MakeBloodExplosion(&Global_VDB_Ptr->VDB_World, 127, &abovePosition, deltaHealth/ONE_FIXED, PARTICLE_HUMAN_BLOOD); + break; + case I_Predator: + MakeBloodExplosion(&Global_VDB_Ptr->VDB_World, 127, &abovePosition, deltaHealth/ONE_FIXED, PARTICLE_PREDATOR_BLOOD); + break; + } + } + + if (sbPtr->SBDamageBlock.Health <= 0) + { + if (playerStatusPtr->IsImmortal) sbPtr->SBDamageBlock.Health=0; + else + { + PlayerIsDead(damage,multiplier,incoming); + } + } + + playerStatusPtr->Health=sbPtr->SBDamageBlock.Health; + playerStatusPtr->Armour=sbPtr->SBDamageBlock.Armour; + + } +} + +extern EULER deathTargetOrientation; +extern int deathFadeLevel; +extern int weaponHandle; + +static void PlayerIsDead(DAMAGE_PROFILE* damage,int multiplier,VECTORCH* incoming) +{ + STRATEGYBLOCK *sbPtr = Player->ObStrategyBlock; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + /* Stop pred hud sound. */ + if(predHUDSoundHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(predHUDSoundHandle); + } + if(predOVision_SoundHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(predOVision_SoundHandle); + } + if(weaponHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(weaponHandle); + } + + // Do some death sounds + + switch (AvP.PlayerType) + { + case I_Alien: + { + PlayAlienSound(0,ASC_Scream_Dying,0,NULL,NULL); + break; + } + case I_Marine: + { + if (damage->Id==AMMO_FACEHUGGER) { + PlayMarineScream(0,SC_Facehugged,0,NULL,NULL); + } else { + PlayMarineScream(0,SC_Death,0,NULL,NULL); + } + break; + } + case I_Predator: + { + if (damage->Id==AMMO_FACEHUGGER) { + PlayPredatorSound(0,PSC_Facehugged,0,NULL,NULL); + } else { + PlayPredatorSound(0,PSC_Scream_Dying,0,NULL,NULL); + } + + { + VECTORCH abovePosition = Global_VDB_Ptr->VDB_World; + abovePosition.vy-=1000; + MakeBloodExplosion(&Global_VDB_Ptr->VDB_World, 127, &abovePosition, 200, PARTICLE_PREDATOR_BLOOD); + } + break; + } + default: + { + break; + } + } + + /* Well, it was nice knowing you. */ + //playerStatusPtr->Health = 0; + sbPtr->SBDamageBlock.Health=0; + playerStatusPtr->IsAlive = 0; + + /* make player fall to the ground */ +// Player->ObShape=I_ShapeMarinePlayerLieDown; + // MapBlockInit(Player); + + /* give player a little bounce */ + dynPtr->Elasticity = 16384; + /* but a lot of friction */ +// dynPtr->Friction = 1<<20; +// dynPtr->Mass = 1<<20; + + /* cancel any velocity */ + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + + deathTargetOrientation.EulerX = 0;//1024-(FastRandom()&255); + deathFadeLevel=65536; + + /* if in single player, fade out sound... */ + if (AvP.Network==I_No_Network) + { + SoundSys_FadeOut(); + } + + if (AvP.PlayerType == I_Alien) + { + sbPtr->DynPtr->UseStandardGravity=1; + } + + /* network support... */ + #if SupportWindows95 + if(AvP.Network!=I_No_Network) + { + playerStatusPtr->MyCorpse=MakeNewCorpse(); + AddNetMsg_PlayerKilled((*((int *)(&(playerStatusPtr->MyCorpse->SBname[4])))),damage); + + /*---------------------------------------------------------** + ** handle various special body being torn apart cases ** + **---------------------------------------------------------*/ + + /*Note that we need to apply the damage to the corpse before we can determine a + suitable death anim sequence*/ + if(damage) + { + HMODELCONTROLLER* hmodel=playerStatusPtr->MyCorpse->SBdptr->HModelControlBlock; + //was the player killed by a jaw attack? + if(damage->Id==AMMO_ALIEN_BITE_KILLSECTION && AvP.PlayerType!=I_Alien) + { + //knock the head of the corpse + SECTION_DATA *head; + head=GetThisSectionData(playerStatusPtr->MyCorpse->SBdptr->HModelControlBlock->section_data,"head"); + //do lots of damage to it + if(head) + { + CauseDamageToHModel(playerStatusPtr->MyCorpse->SBdptr->HModelControlBlock,playerStatusPtr->MyCorpse, &TemplateAmmo[AMMO_ALIEN_BITE_KILLSECTION].MaxDamage[AvP.Difficulty], + ONE_FIXED,head,NULL,NULL,0); + } + //play the head being bitten off sound + Sound_Play(SID_ALIEN_JAW_ATTACK,"d",&(Player->ObStrategyBlock->DynPtr->Position)); + + } + //chopped by predator disc? + else if(damage->Id==AMMO_PRED_DISC && AvP.PlayerType!=I_Predator) + { + SECTION_DATA *firstSectionPtr; + SECTION_DATA *chest_section=0; + + firstSectionPtr=hmodel->section_data; + LOCALASSERT(firstSectionPtr); + LOCALASSERT(firstSectionPtr->flags§ion_data_initialised); + + /* look for the object's torso in preference */ + chest_section =GetThisSectionData(hmodel->section_data,"chest"); + + if (chest_section) + { + CauseDamageToHModel(hmodel,playerStatusPtr->MyCorpse,damage, ONE_FIXED, chest_section,incoming,&chest_section->World_Offset,0); + } + else + { + CauseDamageToObject(playerStatusPtr->MyCorpse,damage, ONE_FIXED,incoming); + } + } + //blown up by shoulder cannon? + else if(damage->Id==AMMO_PLASMACASTER_PCKILL && AvP.PlayerType!=I_Predator) + { + SECTION_DATA *firstSectionPtr; + SECTION_DATA *chest_section=0; + + firstSectionPtr=hmodel->section_data; + LOCALASSERT(firstSectionPtr); + LOCALASSERT(firstSectionPtr->flags§ion_data_initialised); + + /* look for the object's torso in preference */ + chest_section =GetThisSectionData(hmodel->section_data,"chest"); + + if (chest_section) + { + //spherical blood explosion for aliens + if(AvP.PlayerType==I_Alien) + CauseDamageToHModel(hmodel,playerStatusPtr->MyCorpse,damage, ONE_FIXED, chest_section,NULL,&chest_section->World_Offset,0); + else + CauseDamageToHModel(hmodel,playerStatusPtr->MyCorpse,damage, ONE_FIXED, chest_section,incoming,&chest_section->World_Offset,0); + } + else + { + CauseDamageToObject(playerStatusPtr->MyCorpse,damage, ONE_FIXED,NULL); + } + } + else + { + SECTION_DATA *section_data=0; + if(MyHitBodyPartId!=-1) + { + //we have the id of the section that was hit when we died + //so try to find the section + section_data=GetThisSectionData_FromID(hmodel->section_data,MyHitBodyPartId); + } + //damage the corpse with the fatal blow + if(section_data) + { + DISPLAYBLOCK *fragged_section=0; + fragged_section=CauseDamageToHModel(hmodel,playerStatusPtr->MyCorpse,damage, + multiplier,section_data,incoming,NULL,0); + + if(fragged_section && incoming && damage->Id==AMMO_PRED_RIFLE) + { + //a speargun has fragged off a body part , so we need to create a spear + VECTORCH direction=*incoming; + RotateVector(&direction,&Player->ObMat); + CreateSpearPossiblyWithFragment(fragged_section,&fragged_section->ObWorld,&direction); + + } + } + else + { + CauseDamageToObject(playerStatusPtr->MyCorpse,damage,multiplier,incoming); + } + } + } + /*---------------------------------** + ** Choose death anim sequence ** + **---------------------------------*/ + { + int deathId; + switch(AvP.PlayerType) + { + case I_Marine : + deathId = Deduce_PlayerMarineDeathSequence(playerStatusPtr->MyCorpse,damage,multiplier,incoming); + break; + + case I_Alien : + deathId = Deduce_PlayerAlienDeathSequence(playerStatusPtr->MyCorpse,damage,multiplier,incoming); + break; + + case I_Predator : + deathId = Deduce_PlayerPredatorDeathSequence(playerStatusPtr->MyCorpse,damage,multiplier,incoming); + break; + } + //apply the animation + ApplyCorpseDeathAnim(playerStatusPtr->MyCorpse,deathId); + //tell everyone else about the chosen death + AddNetMsg_PlayerDeathAnim(deathId,*(int*)&playerStatusPtr->MyCorpse->SBname[4]); + + } + +// if(AvP.Network==I_Host) DoNetScoresForHostDeath(); + + //does this death require a change in character type? + if(netGameData.gameType==NGT_LastManStanding) + { + //Am I a marine or predator? + if(AvP.PlayerType!=I_Alien) + { + //was I killed by an alien? + if(myNetworkKillerId && myNetworkKillerId!=AVPDPNetID) + { + int killer_index=PlayerIdInPlayerList(myNetworkKillerId); + GLOBALASSERT(killer_index!=NET_IDNOTINPLAYERLIST); + if(netGameData.playerData[killer_index].characterType==NGCT_Alien) + { + //set the next character to be an alien then + netGameData.myNextCharacterType=NGCT_Alien; + } + + } + else + { + //suicide , so become an alien anyway + netGameData.myNextCharacterType=NGCT_Alien; + } + } + } + else if(netGameData.gameType==NGT_PredatorTag || netGameData.gameType==NGT_AlienTag) + { + //we may need to change character + extern void SpeciesTag_DetermineMyNextCharacterType(); + SpeciesTag_DetermineMyNextCharacterType(); + } + } + #endif + if (playerStatusPtr->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(playerStatusPtr->soundHandle); + } + if (playerStatusPtr->soundHandle3!=SOUND_NOACTIVEINDEX) { + Sound_Stop(playerStatusPtr->soundHandle3); + } + + /* KJL 15:36:41 10/09/98 - don't hang around on my behalf */ + DisengageGrapplingHook(); + +} + +void ActivateSelfDestructSequence (int seconds) +{ + // Currently does nothing, called when sequence is activated + + if (AvP.DestructTimer==-1) { + AvP.DestructTimer=ONE_FIXED*seconds; //2 1/2 mins. + } +} + +void DeInitialisePlayer(void) { + /* I thought it would be logical to put it here... */ + + int slot = MAX_NO_OF_WEAPON_SLOTS; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + do { + TXACTRLBLK *txactrl,*txactrl_next; + PLAYER_WEAPON_DATA *wdPtr = &PlayerStatusBlock.WeaponSlot[--slot]; + + txactrl_next = wdPtr->TxAnimCtrl; + + while(txactrl_next) + { + txactrl = txactrl_next; + txactrl_next = txactrl->tac_next; + DeallocateMem((void*)txactrl); + } + + wdPtr->TxAnimCtrl=NULL; + } while(slot); + + #if 0 //this hmodel isn't being set up for the moment - Richard + Dispel_HModel(&playerStatusPtr->HModelController); + #endif + +} + +static int cloakDebounce = 1; + +void InitPlayerCloakingSystem(void) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + playerStatusPtr->cloakOn = 0; + playerStatusPtr->cloakPositionGivenAway = 0; + playerStatusPtr->CloakingEffectiveness = 0; + + playerStatusPtr->FieldCharge = PLAYERCLOAK_MAXENERGY; + playerStatusPtr->cloakPositionGivenAwayTimer = 0; + playerStatusPtr->PlasmaCasterCharge=0; + + GimmeChargeCalls=0; + HtoHStrikes=0; + CurrentLightAtPlayer=0; +} + +static void DoPlayerCloakingSystem(void) +{ + extern int NormalFrameTime; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + if(AvP.PlayerType!=I_Predator) return; + if(!(playerStatusPtr->IsAlive)) return; + + /* Handle controls. */ + if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_ChangeVision) + { + if (cloakDebounce) + { + cloakDebounce = 0; + if (playerStatusPtr->cloakOn) + { + Sound_Play(SID_PRED_CLOAKOFF,"h"); + playerStatusPtr->cloakOn = 0; + //playerNoise=1; + } else { + /* Check validity. */ + if ((playerStatusPtr->FieldCharge>CloakThreshold) + &&(playerStatusPtr->FieldCharge>CloakPowerOnDrain)) { + + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + if (!(((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)||(weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY)) + &&(twPtr->FireWhenCloaked==0))) + { + playerStatusPtr->FieldCharge-=CloakPowerOnDrain; + CurrentGameStats_ChargeUsed(CloakPowerOnDrain); + playerStatusPtr->cloakOn = 1; + playerStatusPtr->CloakingEffectiveness = 0; + Sound_Play(SID_PRED_CLOAKON,"h"); + //playerNoise=1; + } + } + } + } + } + else + { + cloakDebounce = 1; + + if (playerStatusPtr->cloakOn) + { + int maxPossibleEffectiveness; + VECTORCH velocity; + DYNAMICSBLOCK *dynPtr=Player->ObStrategyBlock->DynPtr; + + velocity.vx = dynPtr->Position.vx - dynPtr->PrevPosition.vx; + velocity.vy = dynPtr->Position.vy - dynPtr->PrevPosition.vy; + velocity.vz = dynPtr->Position.vz - dynPtr->PrevPosition.vz; + + if (playerStatusPtr->IsMovingInWater) + { + maxPossibleEffectiveness = 0; + if(playerStatusPtr->soundHandleForPredatorCloakDamaged==SOUND_NOACTIVEINDEX) + Sound_Play(SID_PREDATOR_CLOAKING_DAMAGED,"el",playerStatusPtr->soundHandleForPredatorCloakDamaged); + } + else + { + if(playerStatusPtr->soundHandleForPredatorCloakDamaged!=SOUND_NOACTIVEINDEX) + Sound_Stop(playerStatusPtr->soundHandleForPredatorCloakDamaged); + + maxPossibleEffectiveness = ONE_FIXED - DIV_FIXED(Magnitude(&velocity)*2,NormalFrameTime); + if (maxPossibleEffectiveness<0) maxPossibleEffectiveness = 0; + } + + playerStatusPtr->CloakingEffectiveness += NormalFrameTime; + if (playerStatusPtr->CloakingEffectiveness>maxPossibleEffectiveness) + { + playerStatusPtr->CloakingEffectiveness = maxPossibleEffectiveness; + } + } + else + { + playerStatusPtr->CloakingEffectiveness -= NormalFrameTime; + if (playerStatusPtr->CloakingEffectiveness<0) + { + playerStatusPtr->CloakingEffectiveness=0; + } + if(playerStatusPtr->soundHandleForPredatorCloakDamaged!=SOUND_NOACTIVEINDEX) + Sound_Stop(playerStatusPtr->soundHandleForPredatorCloakDamaged); + } + + } + #if 1 + + /* position-given-away-timer runs whatever state the cloak is in */ + if(playerStatusPtr->cloakPositionGivenAway) + { + playerStatusPtr->cloakPositionGivenAwayTimer-=NormalFrameTime; + if(playerStatusPtr->cloakPositionGivenAwayTimer<=0) + { + playerStatusPtr->cloakPositionGivenAwayTimer = 0; + playerStatusPtr->cloakPositionGivenAway = 0; + playerStatusPtr->CloakingEffectiveness = 0; + } + } + + /* now sort out energy discharge/recharge */ + if(playerStatusPtr->cloakOn) + { + int chargeUsed; + + chargeUsed=MUL_FIXED(NormalFrameTime,CloakDrain); + + if (playerStatusPtr->IsMovingInWater) { + chargeUsed<<=2; + } + + if (chargeUsed>playerStatusPtr->FieldCharge) { + chargeUsed=playerStatusPtr->FieldCharge; + } + playerStatusPtr->FieldCharge -= chargeUsed; + CurrentGameStats_ChargeUsed(chargeUsed); + if(playerStatusPtr->FieldCharge <= 0) + { + playerStatusPtr->FieldCharge = 0; + playerStatusPtr->cloakOn = 0; + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_ChangeVision = 1; + Sound_Play(SID_PRED_CLOAKOFF,"h"); + //playerNoise=1; + } + + /* TrickleCharge Difficulty Variation! */ + if ((AvP.Difficulty==I_Hard)||(AvP.Difficulty==I_Impossible)) { + playerStatusPtr->FieldCharge += MUL_FIXED(NormalFrameTime,(TrickleCharge>>1)); + } else { + playerStatusPtr->FieldCharge += MUL_FIXED(NormalFrameTime,TrickleCharge); + } + + if(playerStatusPtr->FieldCharge > PLAYERCLOAK_MAXENERGY) { + playerStatusPtr->FieldCharge = PLAYERCLOAK_MAXENERGY; + } + + } + else + { + if(playerStatusPtr->FieldCharge < PLAYERCLOAK_MAXENERGY) + { + + /* TrickleCharge Difficulty Variation! */ + if ((AvP.Difficulty==I_Hard)||(AvP.Difficulty==I_Impossible)) { + playerStatusPtr->FieldCharge += MUL_FIXED(NormalFrameTime,(TrickleCharge>>1)); + } else { + playerStatusPtr->FieldCharge += MUL_FIXED(NormalFrameTime,TrickleCharge); + } + + if(playerStatusPtr->FieldCharge > PLAYERCLOAK_MAXENERGY) { + playerStatusPtr->FieldCharge = PLAYERCLOAK_MAXENERGY; + } + + #if 0 + /* Infinite field charge? */ + playerStatusPtr->FieldCharge = PLAYERCLOAK_MAXENERGY; + #endif + } + } + #endif + + if (ShowPredoStats) { + /* for testing */ + PrintDebuggingText("Cloak on: %d \n",playerStatusPtr->cloakOn); + PrintDebuggingText("Field Charge: %d \n",playerStatusPtr->FieldCharge); + { + int a; + /* Speargun ammo count */ + a=SlotForThisWeapon(WEAPON_PRED_RIFLE); + if (a!=-1) { + PrintDebuggingText("Speargun Rounds: %d Clips: %d\n",(playerStatusPtr->WeaponSlot[a].PrimaryRoundsRemaining>>ONE_FIXED_SHIFT),playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining); + } else { + PrintDebuggingText("Speargun not possessed.\n"); + } + + } + PrintDebuggingText("Cloak given away: %d \n", playerStatusPtr->cloakPositionGivenAway); + PrintDebuggingText("Cloak given away timer: %d \n", playerStatusPtr->cloakPositionGivenAwayTimer); + PrintDebuggingText("Cloaking Effectiveness: %d \n", playerStatusPtr->CloakingEffectiveness); + PrintDebuggingText("Gimme_Charge Calls: %d \n",GimmeChargeCalls); + } + #if 1 + /* now, if we are cloaked, lets see if we have given away our position... + if we have already given away our position, we may do so again */ + if(playerStatusPtr->cloakOn) + { + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + /* weapon fire ?*/ + if(((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_PRIMARY)&&(!twPtr->PrimaryIsMeleeWeapon))|| + ((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_SECONDARY)&&(!twPtr->SecondaryIsMeleeWeapon))) + { + playerStatusPtr->cloakPositionGivenAway = 1; + playerStatusPtr->cloakPositionGivenAwayTimer = PLAYERCLOAK_POSTIONGIVENAWAYTIME; + } + /* collision with npc ?*/ + { + struct collisionreport *nextReport; + LOCALASSERT(Player->ObStrategyBlock->DynPtr); + nextReport = Player->ObStrategyBlock->DynPtr->CollisionReportPtr; + + while(nextReport) + { + if(nextReport->ObstacleSBPtr) + { + if((nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourAlien)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourMarine)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourXenoborg)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourPredatorAlien)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourQueenAlien)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourFaceHugger)|| + (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourSeal)) + { + playerStatusPtr->cloakPositionGivenAway = 1; + playerStatusPtr->cloakPositionGivenAwayTimer = PLAYERCLOAK_POSTIONGIVENAWAYTIME; + break; + } + } + nextReport = nextReport->NextCollisionReportPtr; + } + } + } + #endif + + if (playerStatusPtr->cloakOn) { + CurrentGameStats_CloakOn(); + } +} + +void GimmeCharge(void) { + + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + if(AvP.PlayerType!=I_Predator) return; + + playerStatusPtr->FieldCharge = PLAYERCLOAK_MAXENERGY; + + GimmeChargeCalls++; + +} + +#define AUTOSPOT_RANGE (1000) + +int AlienPCIsCurrentlyVisible(int checktime,STRATEGYBLOCK *sbPtr) { + + PLAYER_WEAPON_DATA *weaponPtr; + int range; + DYNAMICSBLOCK *dynPtr=(Player->ObStrategyBlock->DynPtr); + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + /* sbPtr is the viewer. */ + + if (AvP.PlayerType!=I_Alien) { + /* Just to be sure. */ + return(1); + } + + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + + /* Set a default range? */ + range=-1; + /* Maybe we also need an autospot range. */ + if (sbPtr) { + VECTORCH offset; + + offset.vx=dynPtr->Position.vx-sbPtr->DynPtr->Position.vx; + offset.vy=dynPtr->Position.vy-sbPtr->DynPtr->Position.vy; + offset.vz=dynPtr->Position.vz-sbPtr->DynPtr->Position.vz; + + range=Approximate3dMagnitude(&offset); + + /* In fact, let's turn this around... */ + + if (playerStatusPtr->ShapeState==PMph_Standing) { + if (range>=(CurrentLightAtPlayer)+AUTOSPOT_RANGE) { + return(0); + } + } else { + if (range>=(CurrentLightAtPlayer>>1)+AUTOSPOT_RANGE) { + /* Half that range if crouching? */ + return(0); + } + } + + /* I guess, if we're in _pitch_ darkness... see nothing outside that range? */ + if (CurrentLightAtPlayer<=2560) { + if (playerStatusPtr->ShapeState==PMph_Standing) { + if (range<=(CurrentLightAtPlayer)+AUTOSPOT_RANGE) { + return(1); + } + } else { + if (range<=(CurrentLightAtPlayer>>1)+AUTOSPOT_RANGE) { + /* Half that range if crouching? */ + return(1); + } + } + return(0); + } + + } + + + if (playerStatusPtr->ShapeState==PMph_Standing) { + /* Default to visible, unless stationary and in near darkness. */ + if (weaponPtr->CurrentState!=WEAPONSTATE_IDLE) { + /* Don't even breathe. */ + return(1); + } + if ((dynPtr->Position.vx!=dynPtr->PrevPosition.vx)|| + (dynPtr->Position.vy!=dynPtr->PrevPosition.vy)|| + (dynPtr->Position.vz!=dynPtr->PrevPosition.vz)) { + /* Stand perfectly still. */ + return(1); + } + if (checktime) { + int chance; + /* There is a chance of being seen regardless. */ + chance=32767; /* Lets say. */ + if ((FastRandom()&65535)CurrentState==WEAPONSTATE_FIRING_PRIMARY) { + /* Just don't claw. */ + return(1); + } + + if (CurrentLightAtPlayer>17000) { + /* It's too bright, mere crouching won't save you. */ + return(1); + } + #if 0 + if ((dynPtr->Position.vx!=dynPtr->PrevPosition.vx)|| + (dynPtr->Position.vy!=dynPtr->PrevPosition.vy)|| + (dynPtr->Position.vz!=dynPtr->PrevPosition.vz)) { + /* Stand perfectly still? */ + return(1); + } + #else + speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity); + /* Speed: < 5000 = standing. > 22000 = jumping. + In practice, walk/fall = 18000 ish, jump = 27000 ish. */ + if (speed>22000) { + /* Not getting away with that, mate. */ + return(1); + } + speed-=5000; + if (speed<0) { + speed=0; + } + /* Now should be 0->17000 ish. */ + speed<<=1; + #endif + if (checktime) { + int chance; + /* There is a chance of being seen. */ + chance=CurrentLightAtPlayer-5000; + #if 1 + chance+=speed; + #endif + if ((FastRandom()&65535)m_aimodule->m_module_ptrs))->name); + + thisModule=playerPherModule->m_aimodule; + + AdjModuleRefPtr = thisModule->m_link_ptrs; + + if(AdjModuleRefPtr) /* check that there is a list of adjacent modules */ + { + while(*AdjModuleRefPtr != 0) + { + /* Probably want some validity test for the link. */ + if (AIModuleIsPhysical(*AdjModuleRefPtr)) { + /* Probably a valid link... */ + if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,0)) { + PrintDebuggingText("--AI Module of %s, general.\n",(*((*AdjModuleRefPtr)->m_module_ptrs))->name); + } else if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,1)) { + PrintDebuggingText("--AI Module of %s, alien only.\n",(*((*AdjModuleRefPtr)->m_module_ptrs))->name); + } else { + PrintDebuggingText("--AI Module of %s, fails validity test!\n",(*((*AdjModuleRefPtr)->m_module_ptrs))->name); + } + } + /* next adjacent module reference pointer */ + AdjModuleRefPtr++; + } + } + + PrintDebuggingText("Adjacencies TO Player's Module:\n"); + + { + extern AIMODULE *AIModuleArray; + + ModuleListPointer = AIModuleArray; + } + + /* go through each aimodule in the environment */ + for(moduleCounter = 0; moduleCounter < AIModuleArraySize; moduleCounter++) + { + + /* get a pointer to the next current module */ + thisModule = &(ModuleListPointer[moduleCounter]); + LOCALASSERT(thisModule); + + AdjModuleRefPtr = thisModule->m_link_ptrs; + + if(AdjModuleRefPtr) /* check that there is a list of adjacent modules */ + { + while(*AdjModuleRefPtr != 0) + { + /* Probably want some validity test for the link. */ + if (AIModuleIsPhysical(*AdjModuleRefPtr)) { + /* Is this the target? */ + if ((*AdjModuleRefPtr)==(playerPherModule->m_aimodule)) { + + /* Probably a valid link... */ + if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,0)) { + PrintDebuggingText("--AI Module of %s, general.\n",(*(thisModule->m_module_ptrs))->name); + } else if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,1)) { + PrintDebuggingText("--AI Module of %s, alien only.\n",(*(thisModule->m_module_ptrs))->name); + } else { + PrintDebuggingText("--AI Module of %s, fails validity test!\n",(*(thisModule->m_module_ptrs))->name); + } + + } + } + /* next adjacent module reference pointer */ + AdjModuleRefPtr++; + } + } + + } + +} + + + +/*---------------------------** +** Loading and saving player ** +**---------------------------*/ + + +typedef struct player_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + +//behaviour block things + PLAYER_WEAPON_DATA WeaponSlot[MAX_NO_OF_WEAPON_SLOTS]; + + enum WEAPON_SLOT SelectedWeaponSlot; + enum WEAPON_SLOT SwapToWeaponSlot; + enum WEAPON_SLOT PreviouslySelectedWeaponSlot; + + int Health; /* in 16.16 */ + int Energy; /* in 16.16 */ + int Armour; /* in 16.16 */ + + + enum player_morph_state ShapeState; /* for controlling morphing */ + + signed int ForwardInertia; + signed int StrafeInertia; + signed int TurnInertia; + + int ViewPanX; /* the looking up/down value that used to be in displayblock */ + + unsigned int securityClearances; + + unsigned int IsAlive :1; + unsigned int IsImmortal :1; + unsigned int Mvt_AnalogueTurning :1; + unsigned int Mvt_AnaloguePitching :1; + unsigned int Absolute_Pitching :1; + unsigned int SwappingIsDebounced :1; + unsigned int DemoMode :1; + unsigned int IHaveAPlacedAutogun :1; + unsigned int IsMovingInWater :1; + unsigned int JetpackEnabled :1; + unsigned int GrapplingHookEnabled :1; + + unsigned int MTrackerType; + + unsigned int cloakOn :1; + unsigned int cloakPositionGivenAway :1; + int FieldCharge; + int cloakPositionGivenAwayTimer; + int PlasmaCasterCharge; + + int CloakingEffectiveness; + + ENCUMBERANCE_STATE Encumberance; + int tauntTimer; + + int incidentFlag; + int incidentTimer; + int fireTimer; + +//some stuff for the weapon displayblock + VECTORCH Weapon_World; + EULER Weapon_Euler; + MATRIXCH Weapon_Matrix; + + +//and globals + enum VISION_MODE_ID CurrentVisionMode; + SMARTGUN_MODES SmartgunMode; + GRENADE_LAUNCHER_DATA GrenadeLauncherData; + + +//strategy block stuff + DYNAMICSBLOCK dynamics; + int integrity; + DAMAGEBLOCK SBDamageBlock; + +}PLAYER_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV playerStatusPtr + + +void SaveStrategy_Player(STRATEGYBLOCK* sbPtr) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); + PLAYER_SAVE_BLOCK* block; + int i; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + + COPYELEMENT_SAVE(SelectedWeaponSlot) + COPYELEMENT_SAVE(SwapToWeaponSlot) + COPYELEMENT_SAVE(PreviouslySelectedWeaponSlot) + + COPYELEMENT_SAVE(Health) /* in 16.16 */ + COPYELEMENT_SAVE(Energy) /* in 16.16 */ + COPYELEMENT_SAVE(Armour) /* in 16.16 */ + + + COPYELEMENT_SAVE(ShapeState) /* for controlling morphing */ + + COPYELEMENT_SAVE(ForwardInertia) + COPYELEMENT_SAVE(StrafeInertia) + COPYELEMENT_SAVE(TurnInertia) + + COPYELEMENT_SAVE(ViewPanX) /* the looking up/down value that used to be in displayblock */ + + COPYELEMENT_SAVE(securityClearances) + + COPYELEMENT_SAVE(IsAlive) + COPYELEMENT_SAVE(IsImmortal) + COPYELEMENT_SAVE(Mvt_AnalogueTurning) + COPYELEMENT_SAVE(Mvt_AnaloguePitching) + COPYELEMENT_SAVE(Absolute_Pitching) + COPYELEMENT_SAVE(SwappingIsDebounced) + COPYELEMENT_SAVE(DemoMode) + COPYELEMENT_SAVE(IHaveAPlacedAutogun) + COPYELEMENT_SAVE(IsMovingInWater) + COPYELEMENT_SAVE(JetpackEnabled) + COPYELEMENT_SAVE(GrapplingHookEnabled ) + + COPYELEMENT_SAVE(MTrackerType) + + COPYELEMENT_SAVE(cloakOn) + COPYELEMENT_SAVE(cloakPositionGivenAway) + COPYELEMENT_SAVE(FieldCharge) + COPYELEMENT_SAVE(cloakPositionGivenAwayTimer) + COPYELEMENT_SAVE(PlasmaCasterCharge) + COPYELEMENT_SAVE(CloakingEffectiveness) + COPYELEMENT_SAVE(Encumberance) + COPYELEMENT_SAVE(tauntTimer) + + COPYELEMENT_SAVE(incidentFlag) + COPYELEMENT_SAVE(incidentTimer) + COPYELEMENT_SAVE(fireTimer) + + for(i=0;iWeaponSlot[i].WeaponIDNumber = playerStatusPtr->WeaponSlot[i].WeaponIDNumber; + block->WeaponSlot[i].CurrentState = playerStatusPtr->WeaponSlot[i].CurrentState; + block->WeaponSlot[i].StateTimeOutCounter = playerStatusPtr->WeaponSlot[i].StateTimeOutCounter; + block->WeaponSlot[i].PrimaryRoundsRemaining = playerStatusPtr->WeaponSlot[i].PrimaryRoundsRemaining; + block->WeaponSlot[i].SecondaryRoundsRemaining = playerStatusPtr->WeaponSlot[i].SecondaryRoundsRemaining; + block->WeaponSlot[i].PrimaryMagazinesRemaining = playerStatusPtr->WeaponSlot[i].PrimaryMagazinesRemaining; + block->WeaponSlot[i].SecondaryMagazinesRemaining = playerStatusPtr->WeaponSlot[i].SecondaryMagazinesRemaining; + block->WeaponSlot[i].PositionOffset = playerStatusPtr->WeaponSlot[i].PositionOffset; + block->WeaponSlot[i].DirectionOffset = playerStatusPtr->WeaponSlot[i].DirectionOffset; + block->WeaponSlot[i].Possessed = playerStatusPtr->WeaponSlot[i].Possessed; + } + + //some stuff for the weapon displayblock + block->Weapon_World = PlayersWeapon.ObWorld; + block->Weapon_Euler = PlayersWeapon.ObEuler; + block->Weapon_Matrix = PlayersWeapon.ObMat; + + //global + block->CurrentVisionMode = CurrentVisionMode; + block->SmartgunMode = SmartgunMode; + block->GrenadeLauncherData = GrenadeLauncherData; + + //strategy block stuff + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + //save the weapon hierarchy + SaveHierarchy(&PlayersWeaponHModelController); + + + Save_SoundState(&playerStatusPtr->soundHandle); + Save_SoundState(&playerStatusPtr->soundHandle3); + Save_SoundState(&playerStatusPtr->soundHandle5); + Save_SoundState(&playerStatusPtr->soundHandleForPredatorCloakDamaged); +} + +void LoadStrategy_Player(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + PLAYER_SAVE_BLOCK* block = (PLAYER_SAVE_BLOCK*) header; + STRATEGYBLOCK* sbPtr = Player->ObStrategyBlock; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); + int i; + + if(block->header.size != sizeof(*block)) return; + + COPY_NAME(sbPtr->SBname,header->SBname); + + + + COPYELEMENT_LOAD(SelectedWeaponSlot) + COPYELEMENT_LOAD(SwapToWeaponSlot) + COPYELEMENT_LOAD(PreviouslySelectedWeaponSlot) + + COPYELEMENT_LOAD(Health) /* in 16.16 */ + COPYELEMENT_LOAD(Energy) /* in 16.16 */ + COPYELEMENT_LOAD(Armour) /* in 16.16 */ + + + COPYELEMENT_LOAD(ShapeState) /* for controlling morphing */ + + COPYELEMENT_LOAD(ForwardInertia) + COPYELEMENT_LOAD(StrafeInertia) + COPYELEMENT_LOAD(TurnInertia) + + COPYELEMENT_LOAD(ViewPanX) /* the looking up/down value that used to be in displayblock */ + + COPYELEMENT_LOAD(securityClearances) + + COPYELEMENT_LOAD(IsAlive) + COPYELEMENT_LOAD(IsImmortal) + COPYELEMENT_LOAD(Mvt_AnalogueTurning) + COPYELEMENT_LOAD(Mvt_AnaloguePitching) + COPYELEMENT_LOAD(Absolute_Pitching) + COPYELEMENT_LOAD(SwappingIsDebounced) + COPYELEMENT_LOAD(DemoMode) + COPYELEMENT_LOAD(IHaveAPlacedAutogun) + COPYELEMENT_LOAD(IsMovingInWater) + COPYELEMENT_LOAD(JetpackEnabled) + COPYELEMENT_LOAD(GrapplingHookEnabled ) + + COPYELEMENT_LOAD(MTrackerType) + + COPYELEMENT_LOAD(cloakOn) + COPYELEMENT_LOAD(cloakPositionGivenAway) + COPYELEMENT_LOAD(FieldCharge) + COPYELEMENT_LOAD(cloakPositionGivenAwayTimer) + COPYELEMENT_LOAD(PlasmaCasterCharge) + COPYELEMENT_LOAD(CloakingEffectiveness) + COPYELEMENT_LOAD(Encumberance) + COPYELEMENT_LOAD(tauntTimer) + + COPYELEMENT_LOAD(incidentFlag) + COPYELEMENT_LOAD(incidentTimer) + COPYELEMENT_LOAD(fireTimer) + +// playerStatusPtr->SwapToWeaponSlot = block->SelectedWeaponSlot; + + + + for(i=0;iWeaponSlot[i].WeaponIDNumber = block->WeaponSlot[i].WeaponIDNumber; + playerStatusPtr->WeaponSlot[i].CurrentState = block->WeaponSlot[i].CurrentState; + playerStatusPtr->WeaponSlot[i].StateTimeOutCounter = block->WeaponSlot[i].StateTimeOutCounter; + playerStatusPtr->WeaponSlot[i].PrimaryRoundsRemaining = block->WeaponSlot[i].PrimaryRoundsRemaining; + playerStatusPtr->WeaponSlot[i].SecondaryRoundsRemaining = block->WeaponSlot[i].SecondaryRoundsRemaining; + playerStatusPtr->WeaponSlot[i].PrimaryMagazinesRemaining = block->WeaponSlot[i].PrimaryMagazinesRemaining; + playerStatusPtr->WeaponSlot[i].SecondaryMagazinesRemaining = block->WeaponSlot[i].SecondaryMagazinesRemaining; + playerStatusPtr->WeaponSlot[i].PositionOffset = block->WeaponSlot[i].PositionOffset; + playerStatusPtr->WeaponSlot[i].DirectionOffset = block->WeaponSlot[i].DirectionOffset; + playerStatusPtr->WeaponSlot[i].Possessed = block->WeaponSlot[i].Possessed; + } + + //some stuff for the weapon displayblock + PlayersWeapon.ObWorld = block->Weapon_World; + PlayersWeapon.ObEuler = block->Weapon_Euler; + PlayersWeapon.ObMat = block->Weapon_Matrix; + + //global + CurrentVisionMode = block->CurrentVisionMode; + SmartgunMode = block->SmartgunMode; + GrenadeLauncherData = block->GrenadeLauncherData; + + //strategy block stuff + *sbPtr->DynPtr = block->dynamics; + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + + + + + { + extern VIEWDESCRIPTORBLOCK* Global_VDB_Ptr; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0); + Global_VDB_Ptr->VDB_World = sbPtr->DynPtr->Position; + } + + + //load the weapon hierarchy + { + SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); + if(hier_header) + { + LoadHierarchy(hier_header,&PlayersWeaponHModelController); + } + else + { + Dispel_HModel(&PlayersWeaponHModelController); + } + } + + + PlayersWeapon.HModelControlBlock = &PlayersWeaponHModelController; + + //get the section data pointers + PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"dum flash"); + if (PWMFSDP==NULL) { + PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum flash"); + } + + Load_SoundState(&playerStatusPtr->soundHandle); + Load_SoundState(&playerStatusPtr->soundHandle3); + Load_SoundState(&playerStatusPtr->soundHandle5); + Load_SoundState(&playerStatusPtr->soundHandleForPredatorCloakDamaged); + +} + diff --git a/3dc/avp/Pmove.c b/3dc/avp/Pmove.c new file mode 100644 index 0000000..eefabc3 --- /dev/null +++ b/3dc/avp/Pmove.c @@ -0,0 +1,1718 @@ +/*-------------- Patrick 15/10/96 ------------------ + Source file for Player Movement ... +----------------------------------------------------*/ +#include "3dc.h" +#include "inline.h" +#include "module.h" + +#include "gamedef.h" +#include "stratdef.h" +#include "dynblock.h" +#include "dynamics.h" +#include "gameplat.h" + +#include "bh_types.h" + +#define UseLocalAssert 1 +#include "ourasert.h" +#include "comp_shp.h" + +#include "pmove.h" +#include "usr_io.h" +#include "bh_far.h" +#include "triggers.h" +#include "pvisible.h" +#include "inventry.h" +#include "pfarlocs.h" +#include "weapons.h" +#include "pheromon.h" +#include "bh_pred.h" +#include "psnd.h" +#include "bh_weap.h" +#include "equipmnt.h" +#include "bh_agun.h" +#include "los.h" +#include "krender.h" +#include "pldnet.h" +#include "BonusAbilities.h" +#include "avp_menus.h" +#include "lighting.h" +#include "scream.h" +#include "avp_userprofile.h" + + +#define ALIEN_CONTACT_WEAPON 0 +#if ALIEN_CONTACT_WEAPON +static void AlienContactWeapon(void); +#endif + +#ifdef AVP_DEBUG_VERSION + #define FLY_MODE_CHEAT_ON 1 +#else + #ifdef AVP_DEBUG_FOR_FOX + #define FLY_MODE_CHEAT_ON 1 + #else + #define FLY_MODE_CHEAT_ON 0 + #endif +#endif +//!(PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO||DEATHMATCH_DEMO) +#if FLY_MODE_CHEAT_ON +extern unsigned char KeyboardInput[]; +#endif +extern int DebouncedGotAnyKey; + +/*KJL***************************************************** +* If the define below is set to non-zero then the player * +* movement values will be loaded in from movement.txt * +*****************************************************KJL*/ +#define LOAD_IN_MOVEMENT_VALUES 0 + +#if SupportWindows95 && LOAD_IN_MOVEMENT_VALUES + +static int AlienForwardSpeed; +static int AlienStrafeSpeed; +static int AlienTurnSpeed; +static int AlienJumpSpeed; +static int PredatorForwardSpeed; +static int PredatorStrafeSpeed; +static int PredatorTurnSpeed; +static int PredatorJumpSpeed; +static int MarineForwardSpeed; +static int MarineStrafeSpeed; +static int MarineTurnSpeed; +static int MarineJumpSpeed; + +static void LoadInMovementValues(void); +#endif + +/* Globals */ +int CrouchIsToggleKey; +char CrouchKeyDebounced; +int executeDemo; + +/* Global Externs */ +extern DISPLAYBLOCK* Player; +extern int NormalFrameTime; +extern int cosine[], sine[]; +extern int predHUDSoundHandle; +extern int predOVision_SoundHandle; +extern int TauntSoundPlayed; + +#if SupportWindows95 +extern unsigned char GotAnyKey; +#else +unsigned char GotAnyKey; +#endif + +static char FlyModeOn = 0; +static char FlyModeDebounced = 0; + +static char BonusAbilityDebounced = 0; + +extern int deathFadeLevel; +extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + +// DISPLAYBLOCK *playerdb; + +extern void DeInitialisePlayer(void); + +/* some prototypes for this source file */ +static void MakePlayerCrouch(STRATEGYBLOCK* sbPtr); +static void MakePlayerLieDown(STRATEGYBLOCK* sbPtr); +static void MaintainPlayerShape(STRATEGYBLOCK* sbPtr); +static void NetPlayerDeadProcessing(STRATEGYBLOCK* sbPtr); +static void CorpseMovement(STRATEGYBLOCK *sbPtr); + +extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); +extern void NewOnScreenMessage(unsigned char *messagePtr); +extern void RemoveAllThisPlayersDiscs(void); +void NetPlayerRespawn(STRATEGYBLOCK *sbPtr); + +int timeInContactWithFloor; + +extern int weaponHandle; + +extern int PlayerDamagedOverlayIntensity; + + +#define JETPACK_MAX_SPEED 10000 +#define JETPACK_THRUST 40000 + +/*----------------------------------------------------------- +Initialise player movement data +-------------------------------------------------------------*/ +void InitPlayerMovementData(STRATEGYBLOCK* sbPtr) +{ + InitPlayerGameInput(sbPtr); + + /* set the player's morph control block and state*/ + { + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(sbPtr->SBdataptr); + LOCALASSERT(playerStatusPtr); + + playerStatusPtr->ShapeState = PMph_Standing; + playerStatusPtr->ViewPanX = 0; + + playerStatusPtr->DemoMode = 0; + } + + /* KJL 13:35:13 16/03/98 - make sure fly mode is off */ + FlyModeOn = 0; + + timeInContactWithFloor=(ONE_FIXED/10); + + #if SupportWindows95 && LOAD_IN_MOVEMENT_VALUES + LoadInMovementValues(); + #endif + +} + +void StartPlayerTaunt(void) { + + PLAYER_STATUS *playerStatusPtr; + + /* get the player status block ... */ + playerStatusPtr = (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + if (playerStatusPtr->tauntTimer) { + return; + } + + playerStatusPtr->tauntTimer=-1; /* Cue to start. */ + TauntSoundPlayed=0; +} + +/*-------------- Patrick 15/10/96 ---------------- +--------------------------------------------------*/ +void PlayerBehaviour(STRATEGYBLOCK* sbPtr) +{ + PLAYER_STATUS *playerStatusPtr; + + /* get the player status block ... */ + playerStatusPtr = (PLAYER_STATUS *) (sbPtr->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + /* KJL 18:05:55 03/10/97 - is anybody there? */ + if (playerStatusPtr->IsAlive) + { + if (playerStatusPtr->tauntTimer>0) { + playerStatusPtr->tauntTimer-=NormalFrameTime; + if (playerStatusPtr->tauntTimer<0) { + playerStatusPtr->tauntTimer=0; + } + } else if (AvP.Network==I_No_Network) { + /* *Might* need to monitor this... */ + if (playerStatusPtr->tauntTimer==-1) { + /* Begin taunt. */ + playerStatusPtr->tauntTimer=TAUNT_LENGTH; + } else if (playerStatusPtr->tauntTimer>0) { + playerStatusPtr->tauntTimer-=NormalFrameTime; + if (playerStatusPtr->tauntTimer<0) { + playerStatusPtr->tauntTimer=0; + } + } + } + ExecuteFreeMovement(sbPtr); + } + else CorpseMovement(sbPtr); + + if(playerStatusPtr->IsAlive) + { + if ((sbPtr->containingModule)&&(!Observer)) { + /* Update pheromone system. If there's no containing module, * + * well... I sigh with despair at the system. But I cannot change it. */ + + switch(AvP.PlayerType) + { + case I_Marine: + AddMarinePheromones(sbPtr->containingModule->m_aimodule); + break; + case I_Predator: + /* Ah well, for the moment... */ + AddMarinePheromones(sbPtr->containingModule->m_aimodule); + break; + case I_Alien: + break; + default: + GLOBALASSERT(0); + break; + } + } + } + +} + + + + +/*------------------------Patrick 21/10/96------------------------ + Newer cleaned up version, supporting new input functions + ----------------------------------------------------------------*/ +#define ALIEN_MOVESCALE 18000 +#define PREDATOR_MOVESCALE 16000 +#define MARINE_MOVESCALE 15000 + +#define TURNSCALE 2000 +#define JUMPVELOCITY 9000 + +#define FASTMOVESCALE 12000 +#define SLOWMOVESCALE 8000 +#define FASTTURNSCALE 2000 +#define SLOWTURNSCALE 1000 +#define FASTSTRAFESCALE 10000 +#define SLOWSTRAFESCALE 6000 + +/* KJL 14:39:45 01/14/97 - Camera stuff */ +#define PANRATESHIFT 6 +#define TIMEBEFOREAUTOCENTREVIEW 16384 + +/* patrick 9/7/97: these are for testing AI pre-calculated values... */ +#define PATTEST_EPS 0 +#define PATTEST_AUXLOCS 0 +#if (PATTEST_EPS&&PATTEST_AUXLOCS) + #error Cannot have both +#endif +#if PATTEST_EPS + void EpLocationTest(void); +#endif +#if PATTEST_AUXLOCS + void AuxLocationTest(void); +#endif + +void ExecuteFreeMovement(STRATEGYBLOCK* sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); + + if (dynPtr->IsInContactWithFloor) { + timeInContactWithFloor+=NormalFrameTime; + } else { + timeInContactWithFloor=0; + } + + /*------------------------------------------------------ + GAME INPUTS + Call the (platform dependant) game input reading fn. + ------------------------------------------------------*/ + ReadPlayerGameInput(sbPtr); + + /* KJL 11:07:42 10/09/98 - Bonus Abilities */ + switch (AvP.PlayerType) + { + case I_Alien: + break; + #if 0 + case I_Predator: /* KJL 11:08:19 10/09/98 - Grappling Hook */ + { + if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_BonusAbility) + { + if(BonusAbilityDebounced) + { + ActivateGrapplingHook(); + BonusAbilityDebounced = 0; + } + } + else BonusAbilityDebounced = 1; + + break; + } + #endif + case I_Predator: /* KJL 11:08:19 10/09/98 - Cycle Vision Mode */ + { + if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_CycleVisionMode) + { + ChangePredatorVisionMode(); + } + if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_GrapplingHook && + playerStatusPtr->GrapplingHookEnabled) + { + ActivateGrapplingHook(); + } + + break; + } + case I_Marine: + break; + } + + if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Operate) + OperateObjectInLineOfSight(); + + /* patrick 9/7/97: these are for testing AI pre-calculated values... */ + #if PATTEST_EPS + EpLocationTest(); + #endif + #if PATTEST_AUXLOCS + AuxLocationTest(); + #endif + + + /* Alien damages things by being in contact with them */ + #if ALIEN_CONTACT_WEAPON + if (AvP.PlayerType == I_Alien) AlienContactWeapon(); + #endif + + /*------------------------------------------------------ + MOVEMENT + + NB player must be standing for faster movement + ------------------------------------------------------*/ + + /* KJL 16:59:53 01/07/97 - New 3d strategy code */ + { + int MaxSpeed; + int forwardSpeed; + int strafeSpeed; + int turnSpeed; + int jumpSpeed; + + #if SupportWindows95 && LOAD_IN_MOVEMENT_VALUES + switch (AvP.PlayerType) + { + case I_Alien: + forwardSpeed = AlienForwardSpeed; + strafeSpeed = AlienStrafeSpeed; + turnSpeed = AlienTurnSpeed; + jumpSpeed = AlienJumpSpeed; + break; + + case I_Predator: + forwardSpeed = PredatorForwardSpeed; + strafeSpeed = PredatorStrafeSpeed; + turnSpeed = PredatorTurnSpeed; + jumpSpeed = PredatorJumpSpeed; + break; + + case I_Marine: + forwardSpeed = MarineForwardSpeed; + strafeSpeed = MarineStrafeSpeed; + turnSpeed = MarineTurnSpeed; + jumpSpeed = MarineJumpSpeed; + break; + } + #else + switch (AvP.PlayerType) + { + case I_Alien: + forwardSpeed = ALIEN_MOVESCALE; + strafeSpeed = ALIEN_MOVESCALE; + turnSpeed = TURNSCALE; + jumpSpeed = JUMPVELOCITY; + break; + case I_Predator: + forwardSpeed = PREDATOR_MOVESCALE; + strafeSpeed = PREDATOR_MOVESCALE; + turnSpeed = TURNSCALE; + jumpSpeed = JUMPVELOCITY; + break; + case I_Marine: + forwardSpeed = MARINE_MOVESCALE; + strafeSpeed = MARINE_MOVESCALE; + turnSpeed = TURNSCALE; + jumpSpeed = JUMPVELOCITY; + break; + } + #endif + + MaxSpeed=forwardSpeed; + + if((playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Strafe)&&(playerStatusPtr->Mvt_SideStepIncrement==0)) + { + strafeSpeed = MUL_FIXED(strafeSpeed,playerStatusPtr->Mvt_TurnIncrement); + } + else + { + strafeSpeed = MUL_FIXED(strafeSpeed,playerStatusPtr->Mvt_SideStepIncrement); + } + forwardSpeed = MUL_FIXED(forwardSpeed,playerStatusPtr->Mvt_MotionIncrement); + turnSpeed = MUL_FIXED(turnSpeed,playerStatusPtr->Mvt_TurnIncrement); + + if (MIRROR_CHEATMODE) + { + turnSpeed = -turnSpeed; + strafeSpeed = -strafeSpeed; + } + + { + extern int CameraZoomLevel; + if(CameraZoomLevel) + { + turnSpeed >>= CameraZoomLevel; + playerStatusPtr->Mvt_PitchIncrement >>= CameraZoomLevel; + } + } + + if( ((AvP.PlayerType == I_Alien) || (playerStatusPtr->ShapeState == PMph_Standing)) + && (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Faster) && (playerStatusPtr->Encumberance.CanRun) ) + { + /* Test - half backward speed for predators */ + if (AvP.PlayerType==I_Predator) { + if (playerStatusPtr->Mvt_MotionIncrement<0) { + forwardSpeed = (forwardSpeed)/2; + } + } + } + else + { + /* walk = half speed */ + strafeSpeed = (strafeSpeed)/2; + forwardSpeed = (forwardSpeed)/2; + turnSpeed = (turnSpeed)/2; + } + + /* Marker */ + + strafeSpeed=MUL_FIXED(strafeSpeed,playerStatusPtr->Encumberance.MovementMultiple); + forwardSpeed=MUL_FIXED(forwardSpeed,playerStatusPtr->Encumberance.MovementMultiple); + turnSpeed=MUL_FIXED(turnSpeed,playerStatusPtr->Encumberance.TurningMultiple); + jumpSpeed=MUL_FIXED(jumpSpeed,playerStatusPtr->Encumberance.JumpingMultiple); + + /* KJL 17:45:03 9/9/97 - inertia means it's difficult to stop */ + if (forwardSpeed*playerStatusPtr->ForwardInertia<0) playerStatusPtr->ForwardInertia = 0; + if (strafeSpeed*playerStatusPtr->StrafeInertia<0) playerStatusPtr->StrafeInertia = 0; + + if (!forwardSpeed) + { + int deltaForward = (FASTMOVESCALE*NormalFrameTime)>>14; + if (playerStatusPtr->ForwardInertia>0) + { + forwardSpeed = playerStatusPtr->ForwardInertia - deltaForward; + if (forwardSpeed<0) forwardSpeed=0; + } + else if (playerStatusPtr->ForwardInertia<0) + { + forwardSpeed = playerStatusPtr->ForwardInertia + deltaForward; + if (forwardSpeed>0) forwardSpeed=0; + } + } + else + { + int deltaForward = MUL_FIXED(forwardSpeed*4,NormalFrameTime); + { + int a = playerStatusPtr->ForwardInertia + deltaForward; + if (forwardSpeed>0) + { + if (aforwardSpeed) forwardSpeed = a; + } + } + } + + if (!strafeSpeed) + { + int deltaStrafe = (FASTSTRAFESCALE*NormalFrameTime)>>14; + if (playerStatusPtr->StrafeInertia>0) + { + strafeSpeed = playerStatusPtr->StrafeInertia - deltaStrafe; + if (strafeSpeed<0) strafeSpeed=0; + } + else if (playerStatusPtr->StrafeInertia<0) + { + strafeSpeed = playerStatusPtr->StrafeInertia + deltaStrafe; + if (strafeSpeed>0) strafeSpeed=0; + } + } + else + { + int deltaForward = MUL_FIXED(strafeSpeed*4,NormalFrameTime); + { + int a = playerStatusPtr->StrafeInertia + deltaForward; + if (strafeSpeed>0) + { + if (astrafeSpeed) strafeSpeed = a; + } + } + } + + /* inertia on turning - currently off */ + #if 0 + if(!turnSpeed) + { + int deltaTurn = (FASTTURNSCALE*NormalFrameTime)>>15; + if (playerStatusPtr->TurnInertia>0) + { + turnSpeed = playerStatusPtr->TurnInertia - deltaTurn; + if (turnSpeed<0) turnSpeed=0; + } + else if (playerStatusPtr->TurnInertia<0) + { + turnSpeed = playerStatusPtr->TurnInertia + deltaTurn; + if (turnSpeed>0) turnSpeed=0; + } + } + #endif + + /* Hold it! Correct forwardSpeed vs. strafeSpeed? */ + + #if 0 + { + int mag,angle; + + mag=(forwardSpeed*forwardSpeed)+(strafeSpeed*strafeSpeed); + if (mag>(MaxSpeed*MaxSpeed)) { + + angle=ArcTan(forwardSpeed,strafeSpeed); + + forwardSpeed=MUL_FIXED(GetSin(angle),MaxSpeed); + strafeSpeed=MUL_FIXED(GetCos(angle),MaxSpeed); + + } + } + #endif + + if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Jetpack && + playerStatusPtr->JetpackEnabled) + { + if (dynPtr->LinImpulse.vy>-JETPACK_MAX_SPEED) + { + dynPtr->LinImpulse.vy-=MUL_FIXED(JETPACK_THRUST,NormalFrameTime); + } + AddLightingEffectToObject(Player,LFX_OBJECTONFIRE); + /* Sound handling. */ + if (playerStatusPtr->soundHandle5==SOUND_NOACTIVEINDEX) { + Sound_Play(SID_ED_JETPACK_START,"h"); + Sound_Play(SID_ED_JETPACK_MID,"el",&playerStatusPtr->soundHandle5); + } + + } else { + /* Sound handling. */ + if (playerStatusPtr->soundHandle5!=SOUND_NOACTIVEINDEX) { + Sound_Play(SID_ED_JETPACK_END,"h"); + Sound_Stop(playerStatusPtr->soundHandle5); + } + } + + #if FLY_MODE_CHEAT_ON + dynPtr->GravityOn=1; + if (KeyboardInput[KEY_F6]&&(!(playerStatusPtr->DemoMode))) + { + if(FlyModeDebounced) + { + FlyModeOn = !FlyModeOn; + FlyModeDebounced = 0; + } + } + else FlyModeDebounced = 1; + + if(FlyModeOn) + { + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = forwardSpeed; +// dynPtr->IsNetGhost=1; + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Strafe) + { + dynPtr->LinVelocity.vx = strafeSpeed; + } + else if((playerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepLeft) + || (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepRight)) + { + dynPtr->LinVelocity.vx = strafeSpeed; + } + + /* rotate LinVelocity along camera view */ + { + MATRIXCH mat = Global_VDB_Ptr->VDB_Mat; + TransposeMatrixCH(&mat); + RotateVector(&dynPtr->LinVelocity,&mat); + } + dynPtr->GravityOn=0; + dynPtr->LinImpulse.vx=0; + dynPtr->LinImpulse.vy=0; + dynPtr->LinImpulse.vz=0; + } + else + #endif + /* KJL 12:28:48 14/04/98 - if we're not in contact with the floor, but we've hit + something, set our velocity to zero (otherwise leave it alone) */ + if(!dynPtr->IsInContactWithFloor) + { + if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Jetpack && + playerStatusPtr->JetpackEnabled) + { + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + if (forwardSpeed>0) + { + dynPtr->LinVelocity.vz = forwardSpeed/2; + } + else + { + dynPtr->LinVelocity.vz = forwardSpeed/4; + } + // dynPtr->IsNetGhost=1; + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Strafe) + { + dynPtr->LinVelocity.vx = strafeSpeed/4; + } + else if((playerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepLeft) + || (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepRight)) + { + dynPtr->LinVelocity.vx = strafeSpeed/4; + } + + /* rotate LinVelocity into world space */ + RotateVector(&dynPtr->LinVelocity,&dynPtr->OrientMat); + } + else if (dynPtr->CollisionReportPtr) + { + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = forwardSpeed/8; + /* rotate LinVelocity into world space */ + RotateVector(&dynPtr->LinVelocity,&dynPtr->OrientMat); + + } + } + /* this bit sets the velocity: don't do it in demo mode, though + as we set our own velocity... */ + else if((dynPtr->IsInContactWithFloor)&&(!(playerStatusPtr->DemoMode))) + { + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = forwardSpeed; + + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Strafe) + { + dynPtr->LinVelocity.vx = strafeSpeed; + } + else if((playerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepLeft) + || (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepRight)) + { + dynPtr->LinVelocity.vx = strafeSpeed; + } + + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Jump) + { + COLLISIONREPORT *reportPtr = Player->ObStrategyBlock->DynPtr->CollisionReportPtr; + int notTooSteep = 0; + + while (reportPtr) /* while there is a valid report */ + { + int dot = DotProduct(&(reportPtr->ObstacleNormal),&(dynPtr->GravityDirection)); + + if (dot<-60000) + { + notTooSteep = 1; + break; + } + /* skip to next report */ + reportPtr = reportPtr->NextCollisionReportPtr; + } + + if (notTooSteep) + { + /* alien can jump in the direction it's looking */ + if (AvP.PlayerType == I_Alien) + { + VECTORCH viewDir; + + viewDir.vx = Global_VDB_Ptr->VDB_Mat.mat13; + viewDir.vy = Global_VDB_Ptr->VDB_Mat.mat23; + viewDir.vz = Global_VDB_Ptr->VDB_Mat.mat33; + if ((playerStatusPtr->ShapeState == PMph_Crouching) && (DotProduct(&viewDir,&dynPtr->GravityDirection)<-32768)) + { + dynPtr->LinImpulse.vx += MUL_FIXED(viewDir.vx,jumpSpeed*3); + dynPtr->LinImpulse.vy += MUL_FIXED(viewDir.vy,jumpSpeed*3); + dynPtr->LinImpulse.vz += MUL_FIXED(viewDir.vz,jumpSpeed*3); + } + else + { + dynPtr->LinImpulse.vx -= MUL_FIXED(dynPtr->GravityDirection.vx,jumpSpeed); + dynPtr->LinImpulse.vy -= MUL_FIXED(dynPtr->GravityDirection.vy,jumpSpeed); + dynPtr->LinImpulse.vz -= MUL_FIXED(dynPtr->GravityDirection.vz,jumpSpeed); + dynPtr->LinVelocity.vz += jumpSpeed; + } + dynPtr->TimeNotInContactWithFloor = -1; + } + else + { + dynPtr->LinImpulse.vx -= MUL_FIXED(dynPtr->GravityDirection.vx,jumpSpeed); + dynPtr->LinImpulse.vy -= MUL_FIXED(dynPtr->GravityDirection.vy,jumpSpeed); + dynPtr->LinImpulse.vz -= MUL_FIXED(dynPtr->GravityDirection.vz,jumpSpeed); + dynPtr->TimeNotInContactWithFloor = 0; + } + + switch(AvP.PlayerType) + { + case I_Marine: + { + #if 0 + if (playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) { + int rand=(FastRandom()%4); + + switch (rand) { + case 0: + Sound_Play(SID_MARINE_JUMP_START,"he",&playerStatusPtr->soundHandle); + break; + case 1: + Sound_Play(SID_MARINE_JUMP_START_2,"he",&playerStatusPtr->soundHandle); + break; + case 2: + Sound_Play(SID_MARINE_JUMP_START_3,"he",&playerStatusPtr->soundHandle); + break; + default: + Sound_Play(SID_MARINE_JUMP_START_4,"he",&playerStatusPtr->soundHandle); + break; + } + } + #else + if (playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) { + PlayMarineScream(0,SC_Jump,0,&playerStatusPtr->soundHandle,NULL); + if(AvP.Network!=I_No_Network) netGameData.myLastScream=SC_Jump; + } + #endif + break; + } + case I_Alien: + break; + case I_Predator: + { + #if 0 + if (playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) { + int rand=(FastRandom()%3); + + switch (rand) { + case 0: + Sound_Play(SID_PRED_JUMP_START_1,"he",&playerStatusPtr->soundHandle); + break; + case 1: + Sound_Play(SID_PRED_JUMP_START_2,"he",&playerStatusPtr->soundHandle); + break; + default: + Sound_Play(SID_PRED_JUMP_START_3,"he",&playerStatusPtr->soundHandle); + break; + } + } + #else + if (playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) { + PlayPredatorSound(0,PSC_Jump,0,&playerStatusPtr->soundHandle,NULL); + if(AvP.Network!=I_No_Network) netGameData.myLastScream=PSC_Jump; + } + #endif + break; + } + default: + break; + + } + } + } + /* rotate LinVelocity into world space */ + RotateVector(&dynPtr->LinVelocity,&dynPtr->OrientMat); + } + + /* zero angular velocity */ + dynPtr->AngVelocity.EulerX = 0; + dynPtr->AngVelocity.EulerZ = 0; + + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Strafe) + { + dynPtr->AngVelocity.EulerY = 0; + } + else + { + dynPtr->AngVelocity.EulerY = turnSpeed; + } + + playerStatusPtr->ForwardInertia = forwardSpeed; + playerStatusPtr->StrafeInertia = strafeSpeed; + playerStatusPtr->TurnInertia = turnSpeed; + } + /*KJL**************************************************************************************** + * The player's AngVelocity as set by the above code is only valid in the player's object * + * space, and so has to be rotated into world space. So aliens can walk on the ceiling, etc. * + ****************************************************************************************KJL*/ + if (dynPtr->AngVelocity.EulerY) + { + MATRIXCH mat; + + int angle = MUL_FIXED(NormalFrameTime,dynPtr->AngVelocity.EulerY)&4095; + int cos = GetCos(angle); + int sin = GetSin(angle); + mat.mat11 = cos; + mat.mat12 = 0; + mat.mat13 = -sin; + mat.mat21 = 0; + mat.mat22 = 65536; + mat.mat23 = 0; + mat.mat31 = sin; + mat.mat32 = 0; + mat.mat33 = cos; + + MatrixMultiply(&dynPtr->OrientMat,&mat,&dynPtr->OrientMat); + MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); + + } + /*------------------------------------------------------ + CROUCHING, LYING DOWN, ETC. + ------------------------------------------------------*/ + MaintainPlayerShape(sbPtr); + + /* Alien's wall-crawling abilities */ + if (AvP.PlayerType == I_Alien) + { + /* let alien walk on walls & ceiling */ + if ( (playerStatusPtr->ShapeState == PMph_Crouching) + &&(!dynPtr->RequestsToStandUp) ) + { + dynPtr->UseStandardGravity=0; + } + else + { + dynPtr->UseStandardGravity=1; + } + } + + + + + /*------------------------------------------------------ + WEAPON FIRING + Kevin: The player input functions now interface directly + with the weapons state machine. I hope. + ------------------------------------------------------*/ + + /*------------------------------------------------------ + CAMERA Controls + ------------------------------------------------------*/ + + /* If AbsolutePitch is set, view angle comes direct from Mvt_PitchIncrement, + which takes values -65536 to +65536. */ + + + if (playerStatusPtr->Absolute_Pitching) + { + playerStatusPtr->ViewPanX = MUL_FIXED(playerStatusPtr->Mvt_PitchIncrement,1024-128); + playerStatusPtr->ViewPanX &= wrap360; + } + else + { + static int timeBeenContinuouslyMoving=0; + int AllowedLookDownAngle; + int AllowedLookUpAngle; + + if (AvP.PlayerType==I_Alien) + { + AllowedLookUpAngle = 0; + AllowedLookDownAngle = 2048; + } + else + { + AllowedLookUpAngle = 128; + AllowedLookDownAngle = 2048-128; + } + + #if SupportWindows95 + if (!ControlMethods.AutoCentreOnMovement) + { + timeBeenContinuouslyMoving = 0; + } + #endif + + if (playerStatusPtr->Mvt_MotionIncrement == 0) + { + timeBeenContinuouslyMoving=0; + } + else + { + if (timeBeenContinuouslyMoving>TIMEBEFOREAUTOCENTREVIEW + && !playerStatusPtr->Mvt_InputRequests.Flags.Rqst_LookUp + && !playerStatusPtr->Mvt_InputRequests.Flags.Rqst_LookDown) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_CentreView =1; + } + else + { + timeBeenContinuouslyMoving+=NormalFrameTime; + } + } + + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_LookUp) + { + playerStatusPtr->ViewPanX += 1024; + playerStatusPtr->ViewPanX &= wrap360; + + playerStatusPtr->ViewPanX += MUL_FIXED + ( + playerStatusPtr->Mvt_PitchIncrement, + NormalFrameTime>>PANRATESHIFT + ); + + if (playerStatusPtr->ViewPanX < AllowedLookUpAngle) playerStatusPtr->ViewPanX=AllowedLookUpAngle; + + playerStatusPtr->ViewPanX -= 1024; + playerStatusPtr->ViewPanX &= wrap360; + } + else if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_LookDown) + { + playerStatusPtr->ViewPanX += 1024; + playerStatusPtr->ViewPanX &= wrap360; + + playerStatusPtr->ViewPanX += MUL_FIXED + ( + playerStatusPtr->Mvt_PitchIncrement, + NormalFrameTime>>PANRATESHIFT + ); + + if (playerStatusPtr->ViewPanX > AllowedLookDownAngle) playerStatusPtr->ViewPanX=AllowedLookDownAngle; + + playerStatusPtr->ViewPanX -= 1024; + playerStatusPtr->ViewPanX &= wrap360; + } + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_CentreView) + { + playerStatusPtr->ViewPanX += 1024; + playerStatusPtr->ViewPanX &= wrap360; + + if (playerStatusPtr->ViewPanX > 1024) + { + playerStatusPtr->ViewPanX -= (NormalFrameTime>>PANRATESHIFT)*2; + if (playerStatusPtr->ViewPanX < 1024) playerStatusPtr->ViewPanX=1024; + } + else if (playerStatusPtr->ViewPanX < 1024) + { + playerStatusPtr->ViewPanX += (NormalFrameTime>>PANRATESHIFT)*2; + if (playerStatusPtr->ViewPanX > 1024) playerStatusPtr->ViewPanX=1024; + } + + playerStatusPtr->ViewPanX -= 1024; + playerStatusPtr->ViewPanX &= wrap360; + } + } + + HandleGrapplingHookForces(); +} + + +/*------------------------------------------------------ +Crouch and Lie down support fns. +------------------------------------------------------*/ + +static void MaintainPlayerShape(STRATEGYBLOCK* sbPtr) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); + + /* maintain play morphing state */ + switch (playerStatusPtr->ShapeState) + { + case(PMph_Standing): + { + /* if we're standing, check inputs for a request to + crouch or lie down */ + if (playerStatusPtr->Encumberance.CanCrouch) + { + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Crouch) + { + if (CrouchKeyDebounced) + { + MakePlayerCrouch(sbPtr); + CrouchKeyDebounced = 0; + } + } + else + { + CrouchKeyDebounced = 1; + } + + } + + + sbPtr->DynPtr->RequestsToStandUp=0; + + break; + } + case(PMph_Crouching): + { + /* if we're crouching, then check inputs for crouch request. + if there isn't one, stand up again */ + if(sbPtr->DynPtr->RequestsToStandUp) + { + //currently crouching , but have had a request to stand up. + //cancel request if the crouch key is pressed again + if (playerStatusPtr->Encumberance.CanCrouch) + { + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Crouch) + { + if (CrouchKeyDebounced) + { + sbPtr->DynPtr->RequestsToStandUp = 0; + CrouchKeyDebounced = 0; + } + } + else + { + CrouchKeyDebounced = 1; + } + + } + } + else + { + if (!(playerStatusPtr->Encumberance.CanCrouch)) + { + sbPtr->DynPtr->RequestsToStandUp=1; + } + + if (CrouchIsToggleKey) + { + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Crouch) + { + if (CrouchKeyDebounced) + { + sbPtr->DynPtr->RequestsToStandUp=1; + CrouchKeyDebounced = 0; + } + } + else + { + CrouchKeyDebounced = 1; + } + } + else if(!(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Crouch)) + { + sbPtr->DynPtr->RequestsToStandUp=1; + } + } + break; + } + case(PMph_Lying): + { + /* if we're lying, then check inputs for lie request. + if there isn't one, stand up again */ + break; + } + default: + { + /* should never get here */ + GLOBALASSERT(1==0); + } + + } + +} + +static void MakePlayerCrouch(STRATEGYBLOCK* sbPtr) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); + + /* set player state */ + playerStatusPtr->ShapeState = PMph_Crouching; + + return; +} + +#if 0 +static void MakePlayerLieDown(STRATEGYBLOCK* sbPtr) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); + + + /* set player state */ + playerStatusPtr->ShapeState = PMph_Lying; + + return; +} +#endif + + +int deathFadeLevel; + +static void CorpseMovement(STRATEGYBLOCK *sbPtr) +{ + extern int RealFrameTime; + + /* only fade non-net game */ + if(AvP.Network == I_No_Network) + { + if(deathFadeLevel>0) + { + /* fade screen to black */ + //SetPaletteFadeLevel(deathFadeLevel); + deathFadeLevel-= RealFrameTime/4; + if (deathFadeLevel<0) deathFadeLevel = 0; + + } + else + { + deathFadeLevel = 0; + /* KJL 15:44:10 03/11/97 - game over, quit main loop */ + /* restart level instead -Richard*/ + if (DebouncedGotAnyKey) + { + AvP.RestartLevel = 1; + } + } + } + else + { + if(deathFadeLevel>0) + { + deathFadeLevel-= RealFrameTime/2; + } + else + { + deathFadeLevel = 0; + NetPlayerDeadProcessing(sbPtr); + } + } +} + +/*-------------------Patrick 14/4/97-------------------- + This function does necessary processing for a dead + network player... + ------------------------------------------------------*/ +static void NetPlayerDeadProcessing(STRATEGYBLOCK *sbPtr) +{ + SECTION *root_section; + + #if SupportWindows95 + PLAYER_STATUS *psPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); + + /* call the read input function so that we can still respawn/quit, etc */ + ReadPlayerGameInput(sbPtr); + + /* check for re-spawn */ + if(psPtr->Mvt_InputRequests.Flags.Rqst_Operate) + { + if(AreThereAnyLivesLeft()) + { + //check for change of character + if(netGameData.myCharacterType!=netGameData.myNextCharacterType) + { + switch(netGameData.myNextCharacterType) + { + case (NGCT_Marine) : + ChangeToMarine(); + break; + + case (NGCT_Alien) : + ChangeToAlien(); + break; + + case (NGCT_Predator) : + ChangeToPredator(); + break; + + default : + GLOBALASSERT("dodgy character type"==0); + break; + + } + + netGameData.myCharacterType=netGameData.myNextCharacterType; + } + else + { + /* CDF 15/3/99, delete all discs... */ + RemoveAllThisPlayersDiscs(); + + NetPlayerRespawn(sbPtr); + } + + /* dynamics block stuff... */ + { + EULER zeroEuler = {0,0,0}; + VECTORCH zeroVec = {0,0,0}; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + dynPtr->Position = zeroVec; + dynPtr->OrientEuler = zeroEuler; + dynPtr->LinVelocity = zeroVec; + dynPtr->LinImpulse = zeroVec; + + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + + //Need to get rid of collisions for this frame , so player doesn't pick up + //his dropped weapon when he respawns. + dynPtr->CollisionReportPtr=0; + } + TeleportNetPlayerToAStartingPosition(sbPtr,0); + } + else + { + //no lives left , so have to act as an observer + GetNextMultiplayerObservedPlayer(); + + //The player's dropped weapon (if there was one) can now be drawn + MakePlayersWeaponPickupVisible(); + + } + } + #endif +} + +extern void InitPlayerCloakingSystem(void); +//make the player into new healthy character +void NetPlayerRespawn(STRATEGYBLOCK *sbPtr) +{ + extern int LeanScale; + SECTION *root_section; + + #if SupportWindows95 + PLAYER_STATUS *psPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); + + + /* Turn on corpse. */ + if (psPtr->MyCorpse) { + if (psPtr->MyCorpse->SBdptr) { + psPtr->MyCorpse->SBdptr->ObFlags&=~ObFlag_NotVis; + } + } + psPtr->MyCorpse=NULL; + DeInitialisePlayer(); + /* When you're going to respawn... you might change */ + /* character class, after all. */ + InitialisePlayersInventory(psPtr); + /* psPtr->Health=STARTOFGAME_MARINE_HEALTH; */ + /* psPtr->Armour=STARTOFGAME_MARINE_ARMOUR; */ + psPtr->IsAlive = 1; + psPtr->MyFaceHugger=NULL; + psPtr->Energy=STARTOFGAME_MARINE_ENERGY; + { + NPC_DATA *NpcData; + NPC_TYPES PlayerType; + + switch(AvP.PlayerType) + { + case(I_Marine): + { + switch (AvP.Difficulty) { + case I_Easy: + PlayerType=I_PC_Marine_Easy; + break; + default: + case I_Medium: + PlayerType=I_PC_Marine_Medium; + break; + case I_Hard: + PlayerType=I_PC_Marine_Hard; + break; + case I_Impossible: + PlayerType=I_PC_Marine_Impossible; + break; + } + LeanScale=ONE_FIXED; + + #if 0 //this hmodel isn't being set up for the moment - Richard + root_section=GetNamedHierarchyFromLibrary("hnpcmarine","Template"); + if (!root_section) { + GLOBALASSERT(0); + /* Sorry, there's just no bouncing back from this one. Fix it. */ + return; + } + Create_HModel(&psPtr->HModelController,root_section); + InitHModelSequence(&psPtr->HModelController,0,0,ONE_FIXED); + /* Doesn't matter what the sequence is... */ + #endif + break; + } + case(I_Predator): + { + switch (AvP.Difficulty) { + case I_Easy: + PlayerType=I_PC_Predator_Easy; + break; + default: + case I_Medium: + PlayerType=I_PC_Predator_Medium; + break; + case I_Hard: + PlayerType=I_PC_Predator_Hard; + break; + case I_Impossible: + PlayerType=I_PC_Predator_Impossible; + break; + } + LeanScale=ONE_FIXED; + + #if 0 //this hmodel isn't being set up for the moment - Richard + root_section=GetNamedHierarchyFromLibrary("hnpcpredator","Template"); + if (!root_section) { + GLOBALASSERT(0); + /* Sorry, there's just no bouncing back from this one. Fix it. */ + return; + } + Create_HModel(&psPtr->HModelController,root_section); + InitHModelSequence(&psPtr->HModelController,0,0,ONE_FIXED); + /* Doesn't matter what the sequence is... */ + #endif + break; + } + case(I_Alien): + { + switch (AvP.Difficulty) { + case I_Easy: + PlayerType=I_PC_Alien_Easy; + break; + default: + case I_Medium: + PlayerType=I_PC_Alien_Medium; + break; + case I_Hard: + PlayerType=I_PC_Alien_Hard; + break; + case I_Impossible: + PlayerType=I_PC_Alien_Impossible; + break; + } + LeanScale=ONE_FIXED*3; + + #if 0 //this hmodel isn't being set up for the moment - Richard + root_section=GetNamedHierarchyFromLibrary("hnpcalien","alien"); + if (!root_section) { + GLOBALASSERT(0); + /* Sorry, there's just no bouncing back from this one. Fix it. */ + return; + } + Create_HModel(&psPtr->HModelController,root_section); + InitHModelSequence(&psPtr->HModelController,0,0,ONE_FIXED); + /* Doesn't matter what the sequence is... */ + #endif + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + + NpcData = GetThisNpcData(PlayerType); + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + sbPtr->SBDamageBlock.IsOnFire=0; + } + + psPtr->Encumberance.MovementMultiple=ONE_FIXED; + psPtr->Encumberance.TurningMultiple=ONE_FIXED; + psPtr->Encumberance.JumpingMultiple=ONE_FIXED; + psPtr->Encumberance.CanCrouch=1; + psPtr->Encumberance.CanRun=1; + psPtr->Health=sbPtr->SBDamageBlock.Health; + psPtr->Armour=sbPtr->SBDamageBlock.Armour; + + psPtr->ForwardInertia=0; + psPtr->StrafeInertia=0; + psPtr->TurnInertia=0; + psPtr->IsMovingInWater = 0; + + psPtr->incidentFlag=0; + psPtr->incidentTimer=0; + + if (psPtr->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(psPtr->soundHandle); + } + if (psPtr->soundHandle3!=SOUND_NOACTIVEINDEX) { + Sound_Stop(psPtr->soundHandle3); + } + + if (weaponHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(weaponHandle); + } + + if (predHUDSoundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(predHUDSoundHandle); + } + + if (predOVision_SoundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(predOVision_SoundHandle); + } + + //reset the player's elasticity (which gets altered upon death) + sbPtr->DynPtr->Elasticity = 0; + + + InitPlayerCloakingSystem(); + + SetupVision(); + + PlayerDamagedOverlayIntensity = 0; + + //no longer acting as an observer + TurnOffMultiplayerObserveMode(); + + //The player's dropped weapon (if there was one) can now be drawn + MakePlayersWeaponPickupVisible(); +#endif +} + + +/* Patrick 9/7/97 --------------------------------------------------- +These two functions are used for testing the pre-processed AI +locations... (either entry points or auxilary locs) +They teleport the player to the next location in the sequence, +in response to the player pressing 'unused3' (currently the U key). +--------------------------------------------------------------------*/ +#if PATTEST_EPS +static int pF_ModuleIndex = 0; +static int pF_EpIndex = 0; +static int pF_HaveStarted = 0; +static int pF_CanMove = 0; + +void EpLocationTest(void) +{ + extern SCENE Global_Scene; + extern SCENEMODULE **Global_ModulePtr; + extern int ModuleArraySize; + + SCENEMODULE *ScenePtr; + MODULE **moduleListPointer; + DYNAMICSBLOCK *dynPtr = Player->ObStrategyBlock->DynPtr; + MODULE *thisModulePtr; + + LOCALASSERT(Global_ModulePtr); + ScenePtr = Global_ModulePtr[Global_Scene]; + moduleListPointer = ScenePtr->sm_marray; + + if(PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_Unused3) + { + if(pF_CanMove == 1) + { + /* move to the next one */ + pF_EpIndex++; + if(pF_EpIndex >= FALLP_EntryPoints[pF_ModuleIndex].numEntryPoints) + { + pF_EpIndex=0; + do + { + pF_ModuleIndex++; + if(pF_ModuleIndex>=ModuleArraySize) pF_ModuleIndex = 0; + } + while(FALLP_EntryPoints[pF_ModuleIndex].numEntryPoints==0); + } + + /* now move to the new location */ + thisModulePtr = moduleListPointer[pF_ModuleIndex]; + dynPtr->Position = FALLP_EntryPoints[pF_ModuleIndex].entryPointsList[(pF_EpIndex)].position; + dynPtr->Position.vx += thisModulePtr->m_world.vx; + dynPtr->Position.vy += thisModulePtr->m_world.vy; + dynPtr->Position.vz += thisModulePtr->m_world.vz; + + dynPtr->PrevPosition = dynPtr->Position; + + pF_HaveStarted = 1; + pF_CanMove = 0; + } + } + else pF_CanMove = 1; + + if (pF_HaveStarted) + { + textprint("CURRENT FAR MODULE %d \n", pF_ModuleIndex); + textprint("EP number %d from module %d \n", pF_EpIndex, FALLP_EntryPoints[pF_ModuleIndex].entryPointsList[(pF_EpIndex)].donorIndex); + } +} + +#endif +#if PATTEST_AUXLOCS +static int pF_ModuleIndex = 0; +static int pF_AuxIndex = 0; +static int pF_HaveStarted = 0; +static int pF_CanMove = 0; + +void AuxLocationTest(void) +{ + extern SCENE Global_Scene; + extern SCENEMODULE **Global_ModulePtr; + extern int ModuleArraySize; + + SCENEMODULE *ScenePtr; + MODULE **moduleListPointer; + DYNAMICSBLOCK *dynPtr=Player->ObStrategyBlock->DynPtr; + MODULE *thisModulePtr; + + LOCALASSERT(Global_ModulePtr); + ScenePtr = Global_ModulePtr[Global_Scene]; + moduleListPointer = ScenePtr->sm_marray; + + /* dynPtr->GravityOn = 0; */ + + if(PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_Unused3) + { + if(pF_CanMove == 1) + { + /* move to the next one */ + pF_AuxIndex++; + if(pF_AuxIndex >= FALLP_AuxLocs[pF_ModuleIndex].numLocations) + { + pF_AuxIndex=0; + do + { + pF_ModuleIndex++; + if(pF_ModuleIndex>=ModuleArraySize) pF_ModuleIndex = 0; + } + while(FALLP_AuxLocs[pF_ModuleIndex].numLocations==0); + } + + /* now move to the new location */ + thisModulePtr = moduleListPointer[pF_ModuleIndex]; + dynPtr->Position = FALLP_AuxLocs[pF_ModuleIndex].locationsList[pF_AuxIndex]; + dynPtr->Position.vx += thisModulePtr->m_world.vx; + dynPtr->Position.vy += thisModulePtr->m_world.vy; + dynPtr->Position.vz += thisModulePtr->m_world.vz; + dynPtr->Position.vy -= 1000; + + dynPtr->PrevPosition = dynPtr->Position; + pF_HaveStarted = 1; + pF_CanMove = 0; + } + } + else pF_CanMove = 1; + + if (pF_HaveStarted) + { + textprint("CURRENT FAR MODULE %d \n", pF_ModuleIndex); + textprint("AUX number %d \n", pF_AuxIndex); + } +} + +#endif + + + + + +/* KJL 10:34:54 8/5/97 - The alien can damage things by merely touching them + + This will need work to get the values right - the damage done could be + scaled by the alien's experience points, the relative velocities of the + objects, and so on. +*/ +#define ALIEN_CONTACT_WEAPON_DAMAGE 50 +#define ALIEN_CONTACT_WEAPON_DELAY 65536 + +#if ALIEN_CONTACT_WEAPON +static void AlienContactWeapon(void) +{ + COLLISIONREPORT *reportPtr = Player->ObStrategyBlock->DynPtr->CollisionReportPtr; + static int contactWeaponTimer = 0; + + if (contactWeaponTimer<=0) + { + contactWeaponTimer = ALIEN_CONTACT_WEAPON_DELAY; + + while (reportPtr) /* while there is a valid report */ + { + if (reportPtr->ObstacleSBPtr) + { + switch(reportPtr->ObstacleSBPtr->I_SBtype) + { + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + case I_BehaviourPredator: + case I_BehaviourMarine: + case I_BehaviourSeal: + case I_BehaviourNetGhost: + { + /* make alienesque noise */ + Sound_Play(SID_HIT_FLESH,"h"); + + /* damage unfortunate object */ + CauseDamageToObject(reportPtr->ObstacleSBPtr,ALIEN_CONTACT_WEAPON_DAMAGE,NULL); + break; + } + default: + break; + } + } + /* skip to next report */ + reportPtr = reportPtr->NextCollisionReportPtr; + } + } + else + { + contactWeaponTimer -= NormalFrameTime; + } + +} +#endif + +/* Demo code removed, CDF 28/9/98, by order of Kevin */ + +#if SupportWindows95 && LOAD_IN_MOVEMENT_VALUES +static void LoadInMovementValues(void) +{ + + FILE *fpInput; + + fpInput = fopen("movement.txt","rb"); + + while(fgetc(fpInput) != '#'); + while(fgetc(fpInput) != '#'); + fscanf(fpInput, "%d",&AlienForwardSpeed); + while(fgetc(fpInput) != '#'); + fscanf(fpInput, "%d",&AlienStrafeSpeed); + while(fgetc(fpInput) != '#'); + fscanf(fpInput, "%d",&AlienTurnSpeed); + while(fgetc(fpInput) != '#'); + fscanf(fpInput, "%d",&AlienJumpSpeed); + + while(fgetc(fpInput) != '#'); + fscanf(fpInput, "%d",&PredatorForwardSpeed); + while(fgetc(fpInput) != '#'); + fscanf(fpInput, "%d",&PredatorStrafeSpeed); + while(fgetc(fpInput) != '#'); + fscanf(fpInput, "%d",&PredatorTurnSpeed); + while(fgetc(fpInput) != '#'); + fscanf(fpInput, "%d",&PredatorJumpSpeed); + + while(fgetc(fpInput) != '#'); + fscanf(fpInput, "%d",&MarineForwardSpeed); + while(fgetc(fpInput) != '#'); + fscanf(fpInput, "%d",&MarineStrafeSpeed); + while(fgetc(fpInput) != '#'); + fscanf(fpInput, "%d",&MarineTurnSpeed); + while(fgetc(fpInput) != '#'); + fscanf(fpInput, "%d",&MarineJumpSpeed); + + fclose(fpInput); +} +#endif + + + + + + + + + + + + + + +extern void ThrowAFlare(void) +{ + extern int NumberOfFlaresActive; + + if (NumberOfFlaresActive<4) + { + extern VECTORCH CentreOfMuzzleOffset; + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + MATRIXCH mat = VDBPtr->VDB_Mat; + VECTORCH position = VDBPtr->VDB_World; + + TransposeMatrixCH(&mat); + + CreateGrenadeKernel(I_BehaviourFlareGrenade,&position,&mat,1); + Sound_Play(SID_THROW_FLARE,"h"); + } + +} diff --git a/3dc/avp/Psnd.c b/3dc/avp/Psnd.c new file mode 100644 index 0000000..5ec5550 --- /dev/null +++ b/3dc/avp/Psnd.c @@ -0,0 +1,953 @@ +/* Patrick 5/6/97 ------------------------------------------------------------- + AvP sound management source + ----------------------------------------------------------------------------*/ + +#define DB_LEVEL 1 + +#include "3dc.h" +#include "module.h" +#include "inline.h" +#include "stratdef.h" +#include "gamedef.h" + +#include "psndplat.h" +#define UseLocalAssert Yes +#include "ourasert.h" +#include "db.h" +#include "showcmds.h" +#include "avp_userprofile.h" +/* Patrick 5/6/97 ------------------------------------------------------------- + Internal globals + ----------------------------------------------------------------------------*/ +int SoundSwitchedOn = 0; +static int SoundInitialised = 0; +static int GlobalVolume = VOLUME_DEFAULT; +extern int DebuggingCommandsActive; + + +int EffectsSoundVolume=VOLUME_DEFAULT; + +static int MasterVolumeFadeLevel; +static enum FADE_STATUS_ID {FADE_STATUS_READY, FADE_STATUS_UP, FADE_STATUS_DOWN, FADE_STATUS_DOWN_FAST} MasterVolumeFadeStatus = FADE_STATUS_READY; + + +static unsigned int Sound_MaxActive_HW = 0; + +static void HandleFadingLevel(void); + +/* Patrick 5/6/97 ------------------------------------------------------------- + Internal functions + ----------------------------------------------------------------------------*/ +static int FindFreeActiveSound(unsigned int min, unsigned int max); +static int FindLowerPriorityActiveSound(ACTIVESOUNDPRIORITY testPriority, unsigned int min, unsigned int max); + +/* Patrick 5/6/97 ------------------------------------------------------------- + External refernces + ----------------------------------------------------------------------------*/ +extern int NormalFrameTime; +extern int GlobalFrameCounter; + + +/* Patrick 5/6/97 ------------------------------------------------------------- + Sound system functions + ----------------------------------------------------------------------------*/ +void SoundSys_Start(void) +{ + int i; + + /* if we have already switched on, so do nothing */ + if(SoundSwitchedOn) return; + /* we are not switched on, but we are initialised, so do nothing */ + if(SoundInitialised) return; + + /* initialise game sounds and active instances*/ + for(i=0;i SOUND_MAXACTIVE) + { + Sound_MaxActive_HW = SOUND_MAXACTIVE; + } + SoundSys_SwitchOn(); + + /* cancel any fades */ + + + /* set global volume */ + GlobalVolume = VOLUME_DEFAULT; + PlatChangeGlobalVolume(VOLUME_DEFAULT); + + +} + +void SoundSys_End(void) +{ + /* end only if we are initialised, regardless of whether we are switched on */ + if(!SoundInitialised) return; + + /* stop and remove all sounds */ + SoundSys_RemoveAll(); + + /* switch off, and de-initillise */ + PlatEndSoundSys(); + SoundSys_SwitchOff(); + SoundInitialised = 0; /* forces call to Soundsys_Start to re-start sound system */ +} + +void SoundSys_Management(void) +{ + int i; + int numActive = 0; + int num3dUpdates = 0; + + if(!SoundSwitchedOn) return; + + /* go through all the active sounds */ + for(i=0;i 0) + { + if(ActiveSounds[i].soundIndex != SID_NOSOUND) + { + PrintDebuggingText("%s\n",GameSounds[ActiveSounds[i].soundIndex].wavName); + } + } + + } + + if(WARPSPEED_CHEATMODE || JOHNWOO_CHEATMODE || DebuggingCommandsActive) + UpdateSoundFrequencies(); +} + +extern void SoundSys_ResetFadeLevel(void) +{ + MasterVolumeFadeLevel = ONE_FIXED; + MasterVolumeFadeStatus = FADE_STATUS_READY; +} + +extern void SoundSys_FadeIn(void) +{ + /* always fade in from silence ? */ + MasterVolumeFadeLevel = ONE_FIXED/2; + MasterVolumeFadeStatus = FADE_STATUS_UP; +} +extern void SoundSys_FadeOut(void) +{ + MasterVolumeFadeStatus = FADE_STATUS_DOWN; +} +extern void SoundSys_FadeOutFast(void) +{ + MasterVolumeFadeStatus = FADE_STATUS_DOWN_FAST; +} +static void HandleFadingLevel(void) +{ + switch (MasterVolumeFadeStatus) + { + default: + case FADE_STATUS_READY: + break; + + case FADE_STATUS_UP: + { + MasterVolumeFadeLevel+=NormalFrameTime/2; + if (MasterVolumeFadeLevel>ONE_FIXED) + { + MasterVolumeFadeLevel = ONE_FIXED; + MasterVolumeFadeStatus = FADE_STATUS_READY; + } + break; + } + case FADE_STATUS_DOWN: + { + MasterVolumeFadeLevel-=NormalFrameTime/8; + if (MasterVolumeFadeLevel<0) + { + MasterVolumeFadeLevel = 0; + MasterVolumeFadeStatus = FADE_STATUS_READY; + } + break; + } + case FADE_STATUS_DOWN_FAST: + { + MasterVolumeFadeLevel-=NormalFrameTime; + if (MasterVolumeFadeLevel<0) + { + MasterVolumeFadeLevel = 0; + MasterVolumeFadeStatus = FADE_STATUS_READY; + } + break; + } + } +} +void SoundSys_PauseOn(void) +{ + int i; + + /* if we're not switched on, should be nothing playing */ + if(!SoundSwitchedOn) return; + + for(i=0;iVOLUME_MAX) newVolume = VOLUME_MAX; + if(newVolume=SID_MAXIMUM)) return; + if(!(GameSounds[soundNumber].loaded)) return; + if(!(GameSounds[soundNumber].activeInstancesVOLUME_MAX) volume=VOLUME_MAX; + if(volumePITCH_MAX) pitch=PITCH_MAX; + if(pitch=SOUND_MAXACTIVE) return; + + /* Check there's a sound in this slot */ + if(ActiveSounds[activeSoundNumber].soundIndex == SID_NOSOUND) return; + + /* update game sound instances, and external reference */ + soundNo = ActiveSounds[activeSoundNumber].soundIndex; + GameSounds[soundNo].activeInstances--; + db_assert1((GameSounds[soundNo].activeInstances>=0)&& + (GameSounds[soundNo].activeInstances=SOUND_MAXACTIVE) return; + /* Check there's a sound in this slot */ + if(ActiveSounds[activeSoundNumber].soundIndex == SID_NOSOUND) return; + + /* validate other argument */ + newVolume = volume; + if(newVolume>VOLUME_MAX) newVolume = VOLUME_MAX; + if(newVolume=SOUND_MAXACTIVE) return; + /* Check there's a sound in this slot */ + if(ActiveSounds[activeSoundNumber].soundIndex == SID_NOSOUND) return; + + /* validate other argument */ + newPitch = pitch; + if(newPitch>PITCH_MAX) newPitch = PITCH_MAX; + if(newPitch=SOUND_MAXACTIVE) return; + + /* Check there's a sound in this slot */ + if(ActiveSounds[activeSoundNumber].soundIndex == SID_NOSOUND) return; + + ActiveSounds[activeSoundNumber].threedeedata.position = *posn; +} + +void Sound_UpdateNew3d(int activeSoundNumber, SOUND3DDATA * s3d) +{ + if(!SoundSwitchedOn) return; + + /* validate argument */ + if(activeSoundNumber<0) return; + if(activeSoundNumber>=SOUND_MAXACTIVE) return; + + /* Check there's a sound in this slot */ + if(ActiveSounds[activeSoundNumber].soundIndex == SID_NOSOUND) return; + + ActiveSounds[activeSoundNumber].threedeedata = *s3d; + +} + +unsigned int SoundNumActiveVoices() +{ + int i = Sound_MaxActive_HW; + int num_active = 0; + + while(i-- > 0) + { + if(ActiveSounds[i].soundIndex != SID_NOSOUND) + { + num_active++; + } + } + + return num_active; +} + +/* Patrick 5/6/97 ------------------------------------------------------------- + Internal support functions + ----------------------------------------------------------------------------*/ +static int FindFreeActiveSound(unsigned int min, unsigned int max) +{ + int i; + for(i = min; (i < max); i++) + { + if(ActiveSounds[i].soundIndex == SID_NOSOUND) return i; + } + return SOUND_NOACTIVEINDEX; +} + +static int FindLowerPriorityActiveSound(ACTIVESOUNDPRIORITY testPriority, unsigned int min, unsigned int max) +{ + int i; + for(i = min; (i < max); i++) + { + if((ActiveSounds[i].soundIndex != SID_NOSOUND)&& + (ActiveSounds[i].priority < testPriority)) return i; + } + return SOUND_NOACTIVEINDEX; +} + + + +static SOUNDINDEX GetSoundIndexFromNameAndIndex(const char* name,SOUNDINDEX index); + +#include "savegame.h" + +typedef struct sound_save_block +{ + SAVE_BLOCK_HEADER header; + + int fileNameLength; + + SOUNDINDEX soundIndex; + ACTIVESOUNDPRIORITY priority; + int volume; + int pitch; + unsigned int loop :1; + unsigned int threedee :1; + unsigned int paused :1; + unsigned int marine_ignore :1; + unsigned int reverb_off :1; + unsigned int externalRef :1; + SOUND3DDATA threedeedata; + int position; +}SOUND_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV sound + +void Load_SoundState(int* soundHandle) +{ + SOUND_SAVE_BLOCK* block; + const char* name; + SOUNDINDEX soundIndex; + + if(!soundHandle) return; + block = (SOUND_SAVE_BLOCK*)GetNextBlockIfOfType(SaveBlock_SoundState); + if(!block) return ; + + name = (const char*)(block+1); + //stop the current sound + if(*soundHandle == SOUND_NOACTIVEINDEX) + { + Sound_Stop(*soundHandle); + } + + //check the size + if(block->header.size != sizeof(*block) + block->fileNameLength) return; + + soundIndex = GetSoundIndexFromNameAndIndex(name,block->soundIndex); + if(soundIndex==SID_NOSOUND) return; + + { + char playOptions[20]="evpP"; + + if(block->loop) strcat(playOptions,"l"); + if(block->marine_ignore) strcat(playOptions,"m"); + if(block->reverb_off) strcat(playOptions,"r"); + if(block->priority == ASP_Maximum) strcat(playOptions,"h"); + + if(block->threedee) + { + strcat(playOptions,"n"); + Sound_Play(soundIndex,playOptions,soundHandle,block->volume,block->pitch,block->position,&block->threedeedata); + } + else + { + Sound_Play(soundIndex,playOptions,soundHandle,block->volume,block->pitch,block->position); + } + + } + + +} + + +void Save_SoundState(int* soundHandle) +{ + + if(!soundHandle) return; + + + if(*soundHandle == SOUND_NOACTIVEINDEX) + { + SAVE_BLOCK_HEADER* header; + GET_SAVE_BLOCK_POINTER(header); + + //fill in the header + header->size = sizeof(*header); + header->type = SaveBlock_SoundState; + } + else + { + ACTIVESOUNDSAMPLE* sound = &ActiveSounds[*soundHandle]; + + SOUND_SAVE_BLOCK* block; + const char* name = GameSounds[sound->soundIndex].wavName; + int name_length = strlen(name) + 1; + + block = GetPointerForSaveBlock(sizeof(*block)+name_length); + + //fill in the header + block->header.size = sizeof(*block) + name_length; + block->header.type = SaveBlock_SoundState; + + + + COPYELEMENT_SAVE(soundIndex) + COPYELEMENT_SAVE(priority) + COPYELEMENT_SAVE(volume) + COPYELEMENT_SAVE(pitch) + COPYELEMENT_SAVE(loop) + COPYELEMENT_SAVE(threedee) + COPYELEMENT_SAVE(paused) + COPYELEMENT_SAVE(marine_ignore) + COPYELEMENT_SAVE(reverb_off) + COPYELEMENT_SAVE(threedeedata) + block->externalRef = 1; + + block->position = 0; + block->fileNameLength = name_length; + + //the volume in the active sound list is scaled differently from the volume used + //by Sound_Play + block->volume<<=7; + block->volume/=VOLUME_PLAT2DSCALE; + + if(sound->dsBufferP) + IDirectSoundBuffer_GetCurrentPosition(sound->dsBufferP,(LPDWORD)&block->position,NULL); + else + block->position = 0; + + strcpy((char*)(block+1),name); + + } + +} + +void Load_SoundState_NoRef(SAVE_BLOCK_HEADER* header) +{ + SOUND_SAVE_BLOCK* block = (SOUND_SAVE_BLOCK*) header; + const char* name = (const char*)(block+1); + SOUNDINDEX soundIndex; + + //check the size + if(block->header.size != sizeof(*block) + block->fileNameLength) return; + + //only load if the sound doesn't require an external reference + if(block->externalRef) return; + + + soundIndex = GetSoundIndexFromNameAndIndex(name,block->soundIndex); + if(soundIndex==SID_NOSOUND) return; + + { + char playOptions[20]="vpP"; + + if(block->marine_ignore) strcat(playOptions,"m"); + if(block->reverb_off) strcat(playOptions,"r"); + if(block->priority == ASP_Maximum) strcat(playOptions,"h"); + + if(block->threedee) + { + strcat(playOptions,"n"); + Sound_Play(soundIndex,playOptions,block->volume,block->pitch,block->position,&block->threedeedata); + } + else + { + Sound_Play(soundIndex,playOptions,block->volume,block->pitch,block->position); + } + } +} + +void Save_SoundsWithNoReference() +{ + int i; + + for(i=0;isoundIndex].wavName; + int name_length = strlen(name) + 1; + + block = GetPointerForSaveBlock(sizeof(*block)+name_length); + + //fill in the header + block->header.size = sizeof(*block) + name_length; + block->header.type = SaveBlock_SoundState; + + + COPYELEMENT_SAVE(soundIndex) + COPYELEMENT_SAVE(priority) + COPYELEMENT_SAVE(volume) + COPYELEMENT_SAVE(pitch) + COPYELEMENT_SAVE(loop) + COPYELEMENT_SAVE(threedee) + COPYELEMENT_SAVE(paused) + COPYELEMENT_SAVE(marine_ignore) + COPYELEMENT_SAVE(reverb_off) + COPYELEMENT_SAVE(threedeedata) + block->externalRef = 0; + + block->position = 0; + block->fileNameLength = name_length; + + //the volume in the active sound list is scaled differently from the volume used + //by Sound_Play + block->volume<<=7; + block->volume/=VOLUME_PLAT2DSCALE; + + if(sound->dsBufferP) + IDirectSoundBuffer_GetCurrentPosition(sound->dsBufferP,(LPDWORD)&block->position,NULL); + else + block->position = 0; + + strcpy((char*)(block+1),name); + } + } + } +} + + +static SOUNDINDEX GetSoundIndexFromNameAndIndex(const char* name,SOUNDINDEX index) +{ + int i; + if(index>=0 && indexSBflags.destroyed_but_preserved=0; + #if debug + FreeBlkPtr->SBIsValid = 0; + #endif + FreeBlkPtr++; + } + + /* KJL 17:31:18 11/13/96 - seems like a logical place to initialise dynamics blocks */ + InitialiseDynamicsBlocks(); + + NumActiveStBlocks = 0; + ActiveStBlockListPtr = &ActiveStBlockList[0]; + + IncrementalSBname=0; +} + + +STRATEGYBLOCK* AllocateStrategyBlock(void) +{ + STRATEGYBLOCK *FreeBlkPtr = 0; /* Default to null ptr */ + int *sptr; + int i; + + if(NumFreeStBlocks) + { + FreeBlkPtr = *FreeStBlockListPtr--; + + NumFreeStBlocks--; /* One less free block */ + + /* Clear the block */ + + sptr = (int *)FreeBlkPtr; + for(i = sizeof(STRATEGYBLOCK)/4; i!=0; i--) + { + *sptr++ = 0; + } + } + + return(FreeBlkPtr); +} + + +void DeallocateStrategyBlock(STRATEGYBLOCK *sptr) +{ + int a; + /* Reset name */ + + for(a = 0; a < SB_NAME_LENGTH; a++) { + sptr->SBname[a] = '\0'; + } + + FreeStBlockListPtr++; + + *FreeStBlockListPtr = sptr; + + NumFreeStBlocks++; /* One more free block */ +} + + +STRATEGYBLOCK* CreateActiveStrategyBlock(void) +{ + STRATEGYBLOCK *sb; + sb = AllocateStrategyBlock(); + + if(sb) + { + #if debug + GLOBALASSERT(sb->SBIsValid == 0); + sb->SBIsValid = 1; + #endif + + *ActiveStBlockListPtr++ = sb; + NumActiveStBlocks++; + } + + return sb; +} + + +int DestroyActiveStrategyBlock(STRATEGYBLOCK* sb) +{ + int j = -1; + int i; + + /* If the block ptr is OK, search the Active Blocks List */ + + if(sb) + { + for(i = 0; i < NumActiveStBlocks && j!=0; i++) + { + + if(ActiveStBlockList[i] == sb) + { + ActiveStBlockList[i] = ActiveStBlockList[NumActiveStBlocks-1]; + NumActiveStBlocks--; + ActiveStBlockListPtr--; + + if(!sb->SBflags.preserve_until_end_of_level) + { + DeallocateStrategyBlock(sb); /* Back to Free List */ + } + else + { + sb->SBflags.destroyed_but_preserved=1; + } + + + j = 0; /* Flag OK */ + } + } + } + + return(j); +} + + + +STRATEGYBLOCK * AttachNewStratBlock +( + MODULE* moptr, + MODULEMAPBLOCK* momptr, + DISPLAYBLOCK* dptr +) +{ + /*oh for a constructor*/ + /* fails if any of the above has a + stratgey block attached*/ + + STRATEGYBLOCK* sptr; + int i; + + GLOBALASSERT(momptr || dptr); + + sptr = CreateActiveStrategyBlock(); + if (sptr == 0) return 0; + + InitialiseSBValues(sptr); + + for(i = 0; i < SB_NAME_LENGTH; i++); + { + sptr->SBname[i] = '\0'; + } + + sptr->SBmomptr = momptr; + + if(moptr) + { +/* GLOBALASSERT(!moptr->m_sbptr); HACK*/ + moptr->m_sbptr = sptr; + sptr->SBmoptr = moptr; + } + + if(dptr) + { + GLOBALASSERT(!dptr->ObStrategyBlock); + dptr->ObStrategyBlock = sptr; + sptr->SBdptr = dptr; + } + else + { + sptr->SBflags.no_displayblock = 1; + } + + + + return(sptr); + +} + + +void InitialiseSBValues(STRATEGYBLOCK* sptr) +{ + sptr->I_SBtype = I_BehaviourNull; + sptr->SBdataptr = (void *)0x0; + + sptr->SBDamageBlock.Health=0; + sptr->SBDamageBlock.Armour=0; + sptr->SBDamageBlock.SB_H_flags.AcidResistant=0; + sptr->SBDamageBlock.SB_H_flags.FireResistant=0; + sptr->SBDamageBlock.SB_H_flags.ElectricResistant=0; + sptr->SBDamageBlock.SB_H_flags.PerfectArmour=0; + sptr->SBDamageBlock.SB_H_flags.ElectricSensitive=0; + sptr->SBDamageBlock.SB_H_flags.Indestructable=0; + + sptr->SBflags.please_destroy_me = 0; + sptr->SBflags.no_displayblock = 0; + sptr->SBflags.request_operate = 0; + sptr->SBflags.preserve_until_end_of_level = 0; + sptr->SBflags.destroyed_but_preserved = 0; + sptr->SBflags.not_on_motiontracker = 0; + + sptr->integrity = 0; + + sptr->maintainVisibility = 0; /* patrRWH - function to search thgough the list of active*/ + sptr->containingModule = (MODULE *)0; /* patrstrat blocks and return the pointer*/ + sptr->shapeIndex = 0; /* patr*/ + + sptr->SBmoptr = (MODULE*)0x0; + sptr->SBmomptr = (MODULEMAPBLOCK*)0x0; + sptr->SBmorphctrl = (MORPHCTRL*)0x0; + + sptr->SBdptr=NULL; + + sptr->name=0; + +} + + +/* +RWH - function to search thgough the list of active +strat blocks and return the pointer +*/ + + +STRATEGYBLOCK* FindSBWithName(char* id_name) +{ + int stratblock = NumActiveStBlocks; + int i; + GLOBALASSERT(stratblock); + + if(!id_name) + return NULL; + + //If the name is all 0`s I want to return a null pointer - Richard. + for(i=0;i= 0) + { + STRATEGYBLOCK* sbptr = ActiveStBlockList[stratblock]; + GLOBALASSERT(sbptr); + + if(sbptr->SBname) + { + if(NAME_ISEQUAL(sbptr->SBname, id_name)) + { + return((sbptr)); + } + } + } + // we have to return null for lifts - so that + // we know that the lift is outside the env + return(NULL); +} + + +static STRATEGYBLOCK SB_Preserved[MAX_PRESERVED_SB]; +static int Num_SB_Preserved; + + +void InitPreservedSBs() +{ + Num_SB_Preserved = 0; +} + + +void PreserveStBlocksInModule(MODULE* containing_mod) +{ + // this used within level - find objects in module + // all will have sbs + + int i; + int max_x, min_x, max_y, min_y, max_z, min_z; + + max_x = containing_mod->m_maxx + containing_mod->m_world.vx; + min_x = containing_mod->m_minx + containing_mod->m_world.vx; + max_y = containing_mod->m_maxy + containing_mod->m_world.vy; + min_y = containing_mod->m_miny + containing_mod->m_world.vy; + max_z = containing_mod->m_maxz + containing_mod->m_world.vz; + min_z = containing_mod->m_minz + containing_mod->m_world.vz; + + GLOBALASSERT(Num_SB_Preserved == 0); + + for(i = 0; i < NumActiveStBlocks && Num_SB_Preserved < MAX_PRESERVED_SB; i++) + { + VECTORCH obj_world; + STRATEGYBLOCK *sbptr; + DYNAMICSBLOCK *dynptr; + + sbptr = ActiveStBlockList[i]; + + if(!(dynptr = sbptr->DynPtr)) + continue; + + obj_world = dynptr->Position; + + if(obj_world.vx < max_x) + if(obj_world.vx > min_x) + if(obj_world.vz < max_z) + if(obj_world.vz > min_z) + if(obj_world.vy < max_y) + if(obj_world.vy > min_y) + { + // copy name into somthing + if(sbptr->I_SBtype == I_BehaviourMarinePlayer || + sbptr->I_SBtype == I_BehaviourMarinePlayer || + sbptr->I_SBtype == I_BehaviourMarinePlayer) + { + SB_Preserved[Num_SB_Preserved] = *sbptr; + + Num_SB_Preserved++; + } + } + } +} + + +BOOL SBNeededForNextEnv(STRATEGYBLOCK* sbptr) +{ + int i = 0; + + if(Num_SB_Preserved == 0) + return(0); + + if (sbptr->I_SBtype!=I_BehaviourMarinePlayer) + if (sbptr->I_SBtype!=I_BehaviourAlienPlayer) + if (sbptr->I_SBtype!=I_BehaviourPredatorPlayer) + if (NAME_ISNULL(sbptr->SBname)) + return(0); + + for(i = 0; i < Num_SB_Preserved; i++) + { + STRATEGYBLOCK *pres_sbptr; + + pres_sbptr = &SB_Preserved[i]; + + if(NAME_ISEQUAL(pres_sbptr->SBname, sbptr->SBname)) + return(1); + } + + return(0); +} + + +void AddPreservedSBsToActiveList() +{ + int i; + STRATEGYBLOCK *new_sbptr; + + for(i = 0; i < Num_SB_Preserved; i++) + { + new_sbptr = CreateActiveStrategyBlock(); + + *new_sbptr = SB_Preserved[i]; + + + if(new_sbptr->I_SBtype == I_BehaviourMarinePlayer || + new_sbptr->I_SBtype == I_BehaviourMarinePlayer || + new_sbptr->I_SBtype == I_BehaviourMarinePlayer) + + { + DYNAMICSBLOCK *playerDynPtr; + + Player->ObStrategyBlock = new_sbptr; + + playerDynPtr = Player->ObStrategyBlock->DynPtr; + // Need to copy some of the preserved SB info into the appropriate places + + Player->ObWorld = playerDynPtr->Position; + Player->ObMat = playerDynPtr->OrientMat; + Player->ObEuler = playerDynPtr->OrientEuler; + + playerDynPtr->PrevPosition = playerDynPtr->Position; + playerDynPtr->PrevOrientMat = playerDynPtr->OrientMat; + playerDynPtr->PrevOrientEuler = playerDynPtr->OrientEuler; + + playerDynPtr->LinVelocity.vx = 0; + playerDynPtr->LinVelocity.vy = 0; + playerDynPtr->LinVelocity.vz = 0; + + playerDynPtr->LinImpulse.vx = 0; + playerDynPtr->LinImpulse.vy = 0; + playerDynPtr->LinImpulse.vz = 0; + + playerDynPtr->AngVelocity.EulerX = 0; + playerDynPtr->AngVelocity.EulerY = 0; + playerDynPtr->AngVelocity.EulerZ = 0; + + playerDynPtr->AngImpulse.EulerX = 0; + playerDynPtr->AngImpulse.EulerY = 0; + playerDynPtr->AngImpulse.EulerZ = 0; + + } + + // we will almost certainly need + // some clean up here. esp for the + // LIFT_FLOOR_SWITCHES and for objects + // whose shape reference has changed + } +} + + +void TeleportPreservedSBsToNewEnvModule(MODULE *new_pos, MODULE* old_pos, int orient_change) +{ + int i; + VECTORCH mod_offset; + + mod_offset.vx = new_pos->m_world.vx - old_pos->m_world.vx; + mod_offset.vy = new_pos->m_world.vy - old_pos->m_world.vy; + mod_offset.vz = new_pos->m_world.vz - old_pos->m_world.vz; + + for(i = 0; i < Num_SB_Preserved; i++) + { + VECTORCH obj_world; + VECTORCH pos_rel; + STRATEGYBLOCK *sbptr; + DYNAMICSBLOCK *dynptr; + + sbptr = &SB_Preserved[i]; + + dynptr = sbptr->DynPtr; + GLOBALASSERT(dynptr); + + obj_world = sbptr->DynPtr->Position; + + + { + // okay we need to find our relative position to the moduke + int cos; + int sin; + int angle; + MATRIXCH mat; + + + pos_rel.vx = dynptr->Position.vx - old_pos->m_world.vx; + pos_rel.vy = dynptr->Position.vy - old_pos->m_world.vy; + pos_rel.vz = dynptr->Position.vz - old_pos->m_world.vz; + + if(orient_change == 1 || orient_change == -3) + angle = 1024; + else if(orient_change == 2 || orient_change == -2) + angle = 2048; + else if(orient_change == 3 || orient_change == -1) + angle = 3072; + else + angle = 0; + + cos = GetCos(angle); + sin = GetSin(angle); + + mat.mat11 = cos; + mat.mat12 = 0; + mat.mat13 = -sin; + mat.mat21 = 0; + mat.mat22 = 65536; + mat.mat23 = 0; + mat.mat31 = sin; + mat.mat32 = 0; + mat.mat33 = cos; + + // rotate the relative object about the center of the + // module and rotate the abject about its own y-axis + + RotateVector(&pos_rel, &mat); + MatrixMultiply(&dynptr->OrientMat,&mat,&dynptr->OrientMat); + MatrixToEuler(&dynptr->OrientMat, &dynptr->OrientEuler); + } + +#if 0 + dynptr->Position.vx = mod_offset.vx; + dynptr->Position.vy = mod_offset.vy; + dynptr->Position.vz = mod_offset.vz; + + dynptr->PrevPosition.vx = mod_offset.vx; + dynptr->PrevPosition.vy = mod_offset.vy; + dynptr->PrevPosition.vz = mod_offset.vz; +#endif + + dynptr->Position.vx = pos_rel.vx + new_pos->m_world.vx; + dynptr->Position.vy = pos_rel.vy + new_pos->m_world.vy; + dynptr->Position.vz = pos_rel.vz + new_pos->m_world.vz; + + dynptr->PrevPosition.vx = -pos_rel.vx + old_pos->m_world.vx; + dynptr->PrevPosition.vy = -pos_rel.vy + old_pos->m_world.vy; + dynptr->PrevPosition.vz = -pos_rel.vz + old_pos->m_world.vz; + + } + } + + + + +// RWH 5/6/97 these next two functions were 1, changed and 2, added +// to deal with deallocating stblocks at the end of behaviours +// this stops problems with accessing defunct strategy blocks +// via collision reports + + +void DestroyAnyStrategyBlock(STRATEGYBLOCK *sbptr) +{ + GLOBALASSERT(sbptr); + + sbptr->SBflags.please_destroy_me = 1; +} + + +void RemoveDestroyedStrategyBlocks(void) +{ + /* + Go backwards through the strategy block. + This should prevent any strategy blocks from being skipped when they + get shuffled down from the end of the array. + */ + int i = NumActiveStBlocks; + + while(i) + { + STRATEGYBLOCK* sbptr = ActiveStBlockList[--i]; + + if(sbptr->SBflags.please_destroy_me) + { + RemoveBehaviourStrategy(sbptr); + } else { + + /* Also... gibb aliens? */ + if (sbptr->I_SBtype==I_BehaviourAlien) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + LOCALASSERT(sbptr); + LOCALASSERT(sbptr->DynPtr); + + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbptr->SBdataptr); + + if (alienStatusPointer->GibbFactor>0) { + Extreme_Gibbing(sbptr,alienStatusPointer->HModelController.section_data,alienStatusPointer->GibbFactor); + alienStatusPointer->GibbFactor=0; + } else if (alienStatusPointer->GibbFactor<0) { + KillRandomSections(alienStatusPointer->HModelController.section_data,alienStatusPointer->GibbFactor); + alienStatusPointer->GibbFactor=0; + } + + } else if ( + (sbptr->I_SBtype==I_BehaviourMarine) + || (sbptr->I_SBtype==I_BehaviourSeal) + ) { + + MARINE_STATUS_BLOCK *marineStatusPointer; + LOCALASSERT(sbptr); + LOCALASSERT(sbptr->DynPtr); + + marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbptr->SBdataptr); + + if (marineStatusPointer->GibbFactor>0) { + Extreme_Gibbing(sbptr,marineStatusPointer->HModelController.section_data,marineStatusPointer->GibbFactor); + marineStatusPointer->GibbFactor=0; + } else if (marineStatusPointer->GibbFactor<0) { + KillRandomSections(marineStatusPointer->HModelController.section_data,-(marineStatusPointer->GibbFactor)); + marineStatusPointer->GibbFactor=0; + } + } else if (sbptr->I_SBtype==I_BehaviourPredator) { + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + LOCALASSERT(sbptr); + LOCALASSERT(sbptr->DynPtr); + + predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbptr->SBdataptr); + + if (predatorStatusPointer->GibbFactor>0) { + Extreme_Gibbing(sbptr,predatorStatusPointer->HModelController.section_data,predatorStatusPointer->GibbFactor); + predatorStatusPointer->GibbFactor=0; + } else if (predatorStatusPointer->GibbFactor<0) { + KillRandomSections(predatorStatusPointer->HModelController.section_data,-(predatorStatusPointer->GibbFactor)); + predatorStatusPointer->GibbFactor=0; + } + } else if (sbptr->I_SBtype==I_BehaviourXenoborg) { + XENO_STATUS_BLOCK *xenoStatusPointer; + LOCALASSERT(sbptr); + LOCALASSERT(sbptr->DynPtr); + + xenoStatusPointer=(XENO_STATUS_BLOCK *)(sbptr->SBdataptr); + + if (xenoStatusPointer->GibbFactor>0) { + Extreme_Gibbing(sbptr,xenoStatusPointer->HModelController.section_data,xenoStatusPointer->GibbFactor); + xenoStatusPointer->GibbFactor=0; + } else if (xenoStatusPointer->GibbFactor<0) { + KillRandomSections(xenoStatusPointer->HModelController.section_data,-(xenoStatusPointer->GibbFactor)); + xenoStatusPointer->GibbFactor=0; + } + } else if (sbptr->I_SBtype==I_BehaviourNetCorpse) { + + NETCORPSEDATABLOCK *corpseStatusPointer; + LOCALASSERT(sbptr); + LOCALASSERT(sbptr->DynPtr); + + corpseStatusPointer=(NETCORPSEDATABLOCK *)(sbptr->SBdataptr); + if(corpseStatusPointer->GibbFactor) + { + /*get a seed for the RNG so that we can send gibbing to other + network players*/ + int seed=FastRandom(); + SetSeededFastRandom(seed); + + if(AvP.Network != I_No_Network) + { + AddNetMsg_Gibbing(sbptr,corpseStatusPointer->GibbFactor,seed); + } + + if (corpseStatusPointer->GibbFactor>0) { + Extreme_Gibbing(sbptr,corpseStatusPointer->HModelController.section_data,corpseStatusPointer->GibbFactor); + corpseStatusPointer->GibbFactor=0; + } else if (corpseStatusPointer->GibbFactor<0) { + KillRandomSections(corpseStatusPointer->HModelController.section_data,-(corpseStatusPointer->GibbFactor)); + corpseStatusPointer->GibbFactor=0; + } + } + } else if (sbptr->I_SBtype==I_BehaviourHierarchicalFragment) { + + HDEBRIS_BEHAV_BLOCK *debrisStatusPointer; + LOCALASSERT(sbptr); + LOCALASSERT(sbptr->DynPtr); + + debrisStatusPointer=(HDEBRIS_BEHAV_BLOCK *)(sbptr->SBdataptr); + + if (debrisStatusPointer->GibbFactor>0) { + Extreme_Gibbing(sbptr,debrisStatusPointer->HModelController.section_data,debrisStatusPointer->GibbFactor); + debrisStatusPointer->GibbFactor=0; + } else if (debrisStatusPointer->GibbFactor<0) { + KillRandomSections(debrisStatusPointer->HModelController.section_data,-(debrisStatusPointer->GibbFactor)); + debrisStatusPointer->GibbFactor=0; + } + } + } + } +} + + + +void DestroyAllStrategyBlocks(void) +{ + int i = 0; + int a = NumActiveStBlocks; + + + while(i < a) + { + RemoveBehaviourStrategy(ActiveStBlockList[i++]); + } + + //get rid of all the strategyblocks that have been preserved until the end of the level + + for(i=0;i0xffffff) + { + IncrementalSBname=1; + } + + *((int *)&sbPtr->SBname[4])=IncrementalSBname; + + if(AvP.Network != I_No_Network) + { + //modify name to ensure uniqueness between players + extern DPID AVPDPNetID; + sbPtr->SBname[SB_NAME_LENGTH-1]=+10+PlayerIdInPlayerList(AVPDPNetID); /* Just to make sure... */ + + } + else + { + sbPtr->SBname[SB_NAME_LENGTH-1]=1; /* Just to make sure... */ + } + + +} + +void GivePlayerCloakAway(void) { + + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + playerStatusPtr->cloakPositionGivenAway = 1; + playerStatusPtr->cloakPositionGivenAwayTimer = PLAYERCLOAK_POSTIONGIVENAWAYTIME; +} \ No newline at end of file diff --git a/3dc/avp/STRATDEF.H b/3dc/avp/STRATDEF.H new file mode 100644 index 0000000..f1b54c8 --- /dev/null +++ b/3dc/avp/STRATDEF.H @@ -0,0 +1,299 @@ +#ifndef _stratdef_h_ +#define _stratdef_h_ 1 + +#ifdef __cplusplus + + extern "C" { + +#endif + + + +/* +stratgey block. We gain game control via the strategy blocks +the overall sturcture is basically game independent, though if you +do not use module mapblocks + +The description +of the world is in two structures. These are the Module Map block and the +strategy block. A object does not need to have a strategy block. In this case +in is simply something to be drawn and/or used for standard collsions. Objects +that have an existance beyond simple engine controls has a strategy block. + + + +Control. + +1 creation and destruction of strategy blocks. After Showviews we generate/remove any + displayblocks that we have responsibilty for. Most predictable elements of the + world are handeled by Chris, though we do need to supply him with a function + that attaches SBs to MOdMBs when needed. + +2 Strategies are run. + + Rather than passing the DBs to the stratgey functions we pass the SBs. we + switch on the I_SBtype and use the SBdataptr via a cast to contain and modify the + behaviour in a function specific to that I_SBType. The first element of the SBdata + structure (whatever it is) MUST CONTAIN THE I_SBtype. This is the only check on the + validity of the data as we are passing data via a cast. + + + +changes + + Loading of the SBdataptr is entirley game-tool related and does not concern the + over all design of how strategy blocks work + + TEMPLATES templates no longer exist + + Entities, entitities.c and entity.c We are keeping entities as names for objects + (ModMBs) which have attached strategy blocks + + Relation to ObStrategy. The Obstrategy still can desiginate how something will behave. + If we have a simplistic moving object it can have a OBstratgey. These still can run under + display block control for Bwards stuff. + + + +generation + + strategy blocks. Post loading attaching of stratgey blocks. (useful for testing) + Certain objects may be created at run time eg missiles, dropped guns. We need functions + that can initialise a stratgey block for these objects. Functions can be also wriiten for + attaching testing strategies to objects. + + B Laoding Map + StrategyBlock + StrategyExtensionBLock + + + if you still want ot use templates to fill out strategy blocks you can. + +*/ + +#include "hmodel.h" + +typedef enum bhvr_type +{ + I_BehaviourNull, + + I_BehaviourMarinePlayer, + I_BehaviourPredatorPlayer, + I_BehaviourAlienPlayer, + + I_BehaviourAlien, + I_BehaviourQueenAlien, + I_BehaviourFaceHugger, + I_BehaviourPredator, + I_BehaviourXenoborg, + I_BehaviourMarine, + I_BehaviourSeal, + I_BehaviourPredatorAlien, + + I_BehaviourProximityDoor, + I_BehaviourLiftDoor, + I_BehaviourSwitchDoor, + I_BehaviourSimpleAnimation, + I_BehaviourBinarySwitch, + I_BehaviourLift, + I_BehaviourPlatform, + I_BehaviourAutoGun, + I_BehaviourAutoGunMuzzleFlash, + I_BehaviourGenerator, + I_BehaviourDatabase, + + + I_BehaviourHierarchicalFragment, + + I_BehaviourAlienFragment, + I_BehaviourSmokeGenerator, + + /* KJL 12:51:18 03/20/97 - + this fragment behaviour will be used by all objects */ + I_BehaviourFragment, + + I_BehaviourGrenade, + I_BehaviourFlameProjectile, + I_BehaviourRocket, + I_BehaviourSonicPulse, + I_BehaviourPPPlasmaBolt, + I_BehaviourSpeargunBolt, + + I_BehaviourNPCPredatorDisc, + I_BehaviourPredatorDisc_SeekTrack, + I_BehaviourPredatorEnergyBolt, + I_BehaviourXenoborgEnergyBolt, + + I_BehaviourOneShot, + I_BehaviourOneShotAnim, + I_BehaviourInanimateObject, + + I_BehaviourNetGhost, /* for preliminary network support */ + + I_BehaviourPulseGrenade, + I_BehaviourFlareGrenade, + I_BehaviourFragmentationGrenade, + I_BehaviourProximityGrenade, + I_BehaviourMolotov, + +// added by john for link switches + I_BehaviourLinkSwitch, + + I_BehaviourClusterGrenade, + + I_BehaviourAlienSpit, + + I_BehaviourTest, + + I_BehaviourXenoborgMorphRoom, + + I_BehaviourLightFX, + I_BehaviourPlacedSound, + I_BehaviourMissionComplete, + I_BehaviourTrackObject, + I_BehaviourFan, + I_BehaviourMessage, + I_BehaviourNetCorpse, + + I_BehaviourRubberDuck, + I_BehaviourPlacedHierarchy, + I_BehaviourPlacedLight, + I_BehaviourPowerCable, + I_BehaviourDormantPredator, + I_BehaviourDeathVolume, + I_BehaviourSelfDestruct, + + I_BehaviourGrapplingHook, + I_BehaviourDummy, + I_BehaviourParticleGenerator, + I_BehaviourVideoScreen, + + I_BehaviourFrisbee, + I_BehaviourFrisbeeEnergyBolt, + +}AVP_BEHAVIOUR_TYPE; + + +/* put the tags in here */ + +#define SB_NAME_LENGTH 8 /* DO NOT CHANGE THIS! */ +#define MAX_PRESERVED_SB 20 + +typedef struct +{ + char name [SB_NAME_LENGTH]; +} SBNAMEBLOCK; + + +typedef struct sb_flags_bitfield +{ + unsigned int please_destroy_me :1; + unsigned int no_displayblock :1; + unsigned int request_operate :1; + unsigned int preserve_until_end_of_level:1; /*strategy block targeted by something else , so must stay until end of level*/ + unsigned int destroyed_but_preserved:1; + unsigned int not_on_motiontracker :1; + +}SBFLAGS; + +/* CDF 12/11/97 Damage structures moved to hmodel.h */ + +typedef struct strategyblock +{ + AVP_BEHAVIOUR_TYPE I_SBtype; /* Strategy Extension Type*/ + void * SBdataptr; /* Strategy Extension Data Pointer*/ + struct displayblock* SBdptr; /* pointer to DB if drawn or collided*/ + struct dynamicsblock* DynPtr; /* KJL 17:17:15 11/05/96 - pointer to a DYNAMICSBLOCK */ + /* (If this is NULL the object cannot move AND cannot be collided with.) */ + int integrity; + /* CDF 15/9/97 New Damage System */ + DAMAGEBLOCK SBDamageBlock; + /* CDF 15/9/97 New Damage System */ + + SBFLAGS SBflags; /* flags */ + char SBname[SB_NAME_LENGTH]; + #if SupportModules + struct module *SBmoptr; /* needed if DBdeS are deallocted*/ + struct modulemapblock* SBmomptr; /* module map block ref*/ + #endif + #if SupportMorphing + struct morphctrl *SBmorphctrl; + #endif + + /* patrick 15/1/97 - these fields are for object visibility management system */ + char maintainVisibility; + struct module *containingModule; + int shapeIndex; + #if debug + short SBIsValid; + #endif + char* name; + +} STRATEGYBLOCK; + + + +// interface to Creating StrategyBlocks + + +extern void AssignNewSBName(STRATEGYBLOCK *sbPtr); +extern STRATEGYBLOCK * AttachNewStratBlock(struct module* moptr, + struct modulemapblock* momptr, + struct displayblock* dptr); + +extern void InitialiseSBValues(STRATEGYBLOCK* sbptr); + +extern STRATEGYBLOCK* FindSBWithName(char* id_name); + + +// interface to removing strategy blocks + + +extern void DestroyAnyStrategyBlock(STRATEGYBLOCK* sbptr); +extern void RemoveDestroyedStrategyBlocks(void); +extern void DestroyAllStrategyBlocks(void); + +/* This should be in PLAYER. But Kevin was on holiday with his files checked out. */ +extern void GivePlayerCloakAway(void); + + + + +// for lift and airlock code + +extern void InitPreservedSBs(); +extern void PreserveStBlocksInModule(); +extern BOOL SBNeededForNextEnv(); +extern void AddPreservedSBsToActiveList(); +extern void TeleportPreservedSBsToNewEnvModule(MODULE* old_pos_module, MODULE* new_pos, int orient_diff); + + + +extern int NumActiveStBlocks; +extern STRATEGYBLOCK *ActiveStBlockList[]; + +/****** MACROS FOR NAME COMAPRISONS AND COPYS*******/ + +#define COPY_NAME(name1, name2) \ + { \ + GLOBALASSERT(SB_NAME_LENGTH == 8); \ + *(int*)name1 = *(int*)name2; \ + *((int*)name1 + 1) = *((int*)name2 + 1);\ + } + +#define NAME_ISEQUAL(name1, name2) \ + ((*(int*)name1 == *(int*)name2) && \ + (*(((int*)name1) + 1) == *(((int*)name2) + 1))) + +#define NAME_ISNULL(name1) \ + ((*(int*)name1 == '\0') && \ + (*(((int*)name1) + 1) == '\0')) + + +#ifdef __cplusplus + + }; + +#endif + +#endif \ No newline at end of file diff --git a/3dc/avp/SecStats.c b/3dc/avp/SecStats.c new file mode 100644 index 0000000..9778529 --- /dev/null +++ b/3dc/avp/SecStats.c @@ -0,0 +1,10294 @@ +/***** Secstats.c *****/ +/***** CDF 21/11/97 *****/ + +#include "3dc.h" + +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "comp_shp.h" +#include "dynblock.h" +#include "dynamics.h" +#include "pfarlocs.h" +#include "pheromon.h" +#include "bh_types.h" +#include "pvisible.h" +#include "bh_far.h" +#include "bh_debri.h" +#include "bh_pred.h" +#include "bh_paq.h" +#include "bh_queen.h" +#include "bh_marin.h" +#include "lighting.h" +#include "bh_weap.h" +#include "weapons.h" +#include "psnd.h" +#include "load_shp.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "particle.h" + + +/* Marine With Pulse Rifle Centre Locations */ +HITLOCATIONTABLEENTRY MWPRCL[] = { + /* Centre locs */ + {"pelvis", centre_aspect, ONE_FIXED/28}, + {"Lthigh", centre_aspect, ONE_FIXED/28}, + {"Lshin", centre_aspect, ONE_FIXED/28}, + {"Lfoot", centre_aspect, ONE_FIXED/28}, + {"Lpouch", centre_aspect, ONE_FIXED/28}, + {"Rthigh", centre_aspect, ONE_FIXED/28}, + {"Rshin", centre_aspect, ONE_FIXED/28}, + {"Rfoot", centre_aspect, ONE_FIXED/28}, + {"Rpouch", centre_aspect, ONE_FIXED/28}, + {"chest", centre_aspect, ONE_FIXED/28}, + {"Rbicep", centre_aspect, ONE_FIXED/28}, + {"Rforearm",centre_aspect, ONE_FIXED/28}, + {"Rpalm", centre_aspect, ONE_FIXED/28}, + {"R1fingers",centre_aspect, ONE_FIXED/28}, + {"R2fingers",centre_aspect, ONE_FIXED/28}, + {"R1thumb", centre_aspect, ONE_FIXED/28}, + {"R2thumb", centre_aspect, ONE_FIXED/28}, + {"Rpad", centre_aspect, ONE_FIXED/28}, + {"Lbicep", centre_aspect, ONE_FIXED/28}, + {"Lforearm",centre_aspect, ONE_FIXED/28}, + {"Lpalm", centre_aspect, ONE_FIXED/28}, + {"L1fingers",centre_aspect, ONE_FIXED/28}, + {"L2fingers",centre_aspect, ONE_FIXED/28}, + {"L1thumb", centre_aspect, ONE_FIXED/28}, + {"L2thumb", centre_aspect, ONE_FIXED/28}, + {"Lpad", centre_aspect, ONE_FIXED/28}, + {"neck", centre_aspect, ONE_FIXED/28}, + {"head", centre_aspect, ONE_FIXED/28}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MWPRTL[] = { + /* Top locs */ + {"chest", centre_aspect, ONE_FIXED/11}, + {"Rbicep", centre_aspect, ONE_FIXED/11}, + {"Rforearm",centre_aspect, ONE_FIXED/11}, + {"Rpalm", centre_aspect, ONE_FIXED/11}, + {"Rpad", centre_aspect, ONE_FIXED/11}, + {"Lbicep", centre_aspect, ONE_FIXED/11}, + {"Lforearm",centre_aspect, ONE_FIXED/11}, + {"Lpalm", centre_aspect, ONE_FIXED/11}, + {"Lpad", centre_aspect, ONE_FIXED/11}, + {"neck", centre_aspect, ONE_FIXED/11}, + {"head", centre_aspect, ONE_FIXED/11}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MWPRBL[] = { + /* Base locs */ + {"pelvis", centre_aspect, ONE_FIXED/9}, + {"Lthigh", centre_aspect, ONE_FIXED/9}, + {"Lshin", centre_aspect, ONE_FIXED/9}, + {"Lfoot", centre_aspect, ONE_FIXED/9}, + {"Lpouch", centre_aspect, ONE_FIXED/9}, + {"Rthigh", centre_aspect, ONE_FIXED/9}, + {"Rshin", centre_aspect, ONE_FIXED/9}, + {"Rfoot", centre_aspect, ONE_FIXED/9}, + {"Rpouch", centre_aspect, ONE_FIXED/9}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MWPRLL[] = { + /* Left locs */ + {"pelvis", centre_aspect, ONE_FIXED/16}, + {"Lthigh", centre_aspect, ONE_FIXED/16}, + {"Lshin", centre_aspect, ONE_FIXED/16}, + {"Lfoot", centre_aspect, ONE_FIXED/16}, + {"Lpouch", centre_aspect, ONE_FIXED/16}, + {"chest", centre_aspect, ONE_FIXED/16}, + {"Lbicep", centre_aspect, ONE_FIXED/16}, + {"Lforearm",centre_aspect, ONE_FIXED/16}, + {"Lpalm", centre_aspect, ONE_FIXED/16}, + {"L1fingers",centre_aspect, ONE_FIXED/16}, + {"L2fingers",centre_aspect, ONE_FIXED/16}, + {"L1thumb", centre_aspect, ONE_FIXED/16}, + {"L2thumb", centre_aspect, ONE_FIXED/16}, + {"Lpad", centre_aspect, ONE_FIXED/16}, + {"neck", centre_aspect, ONE_FIXED/16}, + {"head", centre_aspect, ONE_FIXED/16}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MWPRRL[] = { + /* Right locs */ + {"pelvis", centre_aspect, ONE_FIXED/16}, + {"Rthigh", centre_aspect, ONE_FIXED/16}, + {"Rshin", centre_aspect, ONE_FIXED/16}, + {"Rfoot", centre_aspect, ONE_FIXED/16}, + {"Rpouch", centre_aspect, ONE_FIXED/16}, + {"chest", centre_aspect, ONE_FIXED/16}, + {"Rbicep", centre_aspect, ONE_FIXED/16}, + {"Rforearm",centre_aspect, ONE_FIXED/16}, + {"Rpalm", centre_aspect, ONE_FIXED/16}, + {"R1fingers",centre_aspect, ONE_FIXED/16}, + {"R2fingers",centre_aspect, ONE_FIXED/16}, + {"R1thumb", centre_aspect, ONE_FIXED/16}, + {"R2thumb", centre_aspect, ONE_FIXED/16}, + {"Rpad", centre_aspect, ONE_FIXED/16}, + {"neck", centre_aspect, ONE_FIXED/16}, + {"head", centre_aspect, ONE_FIXED/16}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MWPRTLL[] = { + /* TopLeft locs */ + {"chest", centre_aspect, ONE_FIXED/7}, + {"Lbicep", centre_aspect, ONE_FIXED/7}, + {"Lforearm",centre_aspect, ONE_FIXED/7}, + {"Lpalm", centre_aspect, ONE_FIXED/7}, + {"Lpad", centre_aspect, ONE_FIXED/7}, + {"neck", centre_aspect, ONE_FIXED/7}, + {"head", centre_aspect, ONE_FIXED/7}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MWPRTRL[] = { + /* TopRight locs */ + {"chest", centre_aspect, ONE_FIXED/7}, + {"Rbicep", centre_aspect, ONE_FIXED/7}, + {"Rforearm",centre_aspect, ONE_FIXED/7}, + {"Rpalm", centre_aspect, ONE_FIXED/7}, + {"Rpad", centre_aspect, ONE_FIXED/7}, + {"neck", centre_aspect, ONE_FIXED/7}, + {"head", centre_aspect, ONE_FIXED/7}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MWPRBLL[] = { + /* BaseLeft locs */ + {"pelvis", centre_aspect, ONE_FIXED/5}, + {"Lthigh", centre_aspect, ONE_FIXED/5}, + {"Lshin", centre_aspect, ONE_FIXED/5}, + {"Lfoot", centre_aspect, ONE_FIXED/5}, + {"Lpouch", centre_aspect, ONE_FIXED/5}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MWPRBRL[] = { + /* BaseRight locs */ + {"pelvis", centre_aspect, ONE_FIXED/5}, + {"Rthigh", centre_aspect, ONE_FIXED/5}, + {"Rshin", centre_aspect, ONE_FIXED/5}, + {"Rfoot", centre_aspect, ONE_FIXED/5}, + {"Rpouch", centre_aspect, ONE_FIXED/5}, + {NULL, centre_aspect, 0}, +}; + +/* Civvies */ + +HITLOCATIONTABLEENTRY MCCL[] = { + /* Centre locs */ + {"pelvis presley", centre_aspect, ONE_FIXED/23}, + {"male left thigh", centre_aspect, ONE_FIXED/23}, + {"male left shin", centre_aspect, ONE_FIXED/23}, + {"male left foot", centre_aspect, ONE_FIXED/23}, + {"male right thigh", centre_aspect, ONE_FIXED/23}, + {"male right shin", centre_aspect, ONE_FIXED/23}, + {"male right foot", centre_aspect, ONE_FIXED/23}, + {"stomach", centre_aspect, ONE_FIXED/23}, + {"chest", centre_aspect, ONE_FIXED/23}, + {"male right bicep", centre_aspect, ONE_FIXED/23}, + {"male right forearm", centre_aspect, ONE_FIXED/23}, + {"right palm", centre_aspect, ONE_FIXED/23}, + {"right fings top", centre_aspect, ONE_FIXED/23}, + {"right fings end", centre_aspect, ONE_FIXED/23}, + {"male right thumb", centre_aspect, ONE_FIXED/23}, + {"male left bicep", centre_aspect, ONE_FIXED/23}, + {"male left forearm", centre_aspect, ONE_FIXED/23}, + {"left palm", centre_aspect, ONE_FIXED/23}, + {"left fings top", centre_aspect, ONE_FIXED/23}, + {"left fings end", centre_aspect, ONE_FIXED/23}, + {"male left thumb", centre_aspect, ONE_FIXED/23}, + {"neck", centre_aspect, ONE_FIXED/23}, + {"head", centre_aspect, ONE_FIXED/23}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MCTL[] = { + /* Top locs */ + {"chest", centre_aspect, ONE_FIXED/9}, + {"male right bicep", centre_aspect, ONE_FIXED/9}, + {"male right forearm", centre_aspect, ONE_FIXED/9}, + {"right palm", centre_aspect, ONE_FIXED/9}, + {"male left bicep", centre_aspect, ONE_FIXED/9}, + {"male left forearm", centre_aspect, ONE_FIXED/9}, + {"left palm", centre_aspect, ONE_FIXED/9}, + {"neck", centre_aspect, ONE_FIXED/9}, + {"head", centre_aspect, ONE_FIXED/9}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MCBL[] = { + /* Base locs */ + {"pelvis presley", centre_aspect, ONE_FIXED/8}, + {"male left thigh", centre_aspect, ONE_FIXED/8}, + {"male left shin", centre_aspect, ONE_FIXED/8}, + {"male left foot", centre_aspect, ONE_FIXED/8}, + {"male right thigh", centre_aspect, ONE_FIXED/8}, + {"male right shin", centre_aspect, ONE_FIXED/8}, + {"male right foot", centre_aspect, ONE_FIXED/8}, + {"stomach", centre_aspect, ONE_FIXED/8}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MCLL[] = { + /* Left locs */ + {"pelvis presley", centre_aspect, ONE_FIXED/11}, + {"male left thigh", centre_aspect, ONE_FIXED/11}, + {"male left shin", centre_aspect, ONE_FIXED/11}, + {"male left foot", centre_aspect, ONE_FIXED/11}, + {"stomach", centre_aspect, ONE_FIXED/11}, + {"chest", centre_aspect, ONE_FIXED/11}, + {"male left bicep", centre_aspect, ONE_FIXED/11}, + {"male left forearm", centre_aspect, ONE_FIXED/11}, + {"left palm", centre_aspect, ONE_FIXED/11}, + {"neck", centre_aspect, ONE_FIXED/11}, + {"head", centre_aspect, ONE_FIXED/11}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MCRL[] = { + /* Right locs */ + {"pelvis presley", centre_aspect, ONE_FIXED/11}, + {"male right thigh", centre_aspect, ONE_FIXED/11}, + {"male right shin", centre_aspect, ONE_FIXED/11}, + {"male right foot", centre_aspect, ONE_FIXED/11}, + {"stomach", centre_aspect, ONE_FIXED/11}, + {"chest", centre_aspect, ONE_FIXED/11}, + {"male right bicep", centre_aspect, ONE_FIXED/11}, + {"male right forearm", centre_aspect, ONE_FIXED/11}, + {"right palm", centre_aspect, ONE_FIXED/11}, + {"neck", centre_aspect, ONE_FIXED/11}, + {"head", centre_aspect, ONE_FIXED/11}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MCTLL[] = { + /* Top Left locs */ + {"chest", centre_aspect, ONE_FIXED/6}, + {"male left bicep", centre_aspect, ONE_FIXED/6}, + {"male left forearm", centre_aspect, ONE_FIXED/6}, + {"left palm", centre_aspect, ONE_FIXED/6}, + {"neck", centre_aspect, ONE_FIXED/6}, + {"head", centre_aspect, ONE_FIXED/6}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MCTRL[] = { + /* Top Right locs */ + {"chest", centre_aspect, ONE_FIXED/6}, + {"male right bicep", centre_aspect, ONE_FIXED/6}, + {"male right forearm", centre_aspect, ONE_FIXED/6}, + {"right palm", centre_aspect, ONE_FIXED/6}, + {"neck", centre_aspect, ONE_FIXED/6}, + {"head", centre_aspect, ONE_FIXED/6}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MCBLL[] = { + /* Base Left locs */ + {"pelvis presley", centre_aspect, ONE_FIXED/4}, + {"male left thigh", centre_aspect, ONE_FIXED/4}, + {"male left shin", centre_aspect, ONE_FIXED/4}, + {"male left foot", centre_aspect, ONE_FIXED/4}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY MCBRL[] = { + /* Base Right locs */ + {"pelvis presley", centre_aspect, ONE_FIXED/4}, + {"male right thigh", centre_aspect, ONE_FIXED/4}, + {"male right shin", centre_aspect, ONE_FIXED/4}, + {"male right foot", centre_aspect, ONE_FIXED/4}, + {NULL, centre_aspect, 0}, +}; + +/* ALIENS */ + +HITLOCATIONTABLEENTRY AlCL[] = { + /* Centre Locs */ + {"abdom", centre_aspect, ONE_FIXED/21}, + {"left bicep", centre_aspect, ONE_FIXED/21}, + {"left forearm",centre_aspect, ONE_FIXED/21}, + {"left palm", centre_aspect, ONE_FIXED/21}, + {"right bicep", centre_aspect, ONE_FIXED/21}, + {"right forearm",centre_aspect, ONE_FIXED/21}, + {"right palm", centre_aspect, ONE_FIXED/21}, + {"neck", centre_aspect, ONE_FIXED/21}, + {"head", centre_aspect, ONE_FIXED/21}, + {"left thigh", centre_aspect, ONE_FIXED/21}, + {"left shin", centre_aspect, ONE_FIXED/21}, + {"left foot", centre_aspect, ONE_FIXED/21}, + {"right thigh", centre_aspect, ONE_FIXED/21}, + {"right shin", centre_aspect, ONE_FIXED/21}, + {"right foot", centre_aspect, ONE_FIXED/21}, + {"pipe_lt", back_aspect, ONE_FIXED/21}, + {"pipe_lb", back_aspect, ONE_FIXED/21}, + {"pipe_rt", back_aspect, ONE_FIXED/21}, + {"pipe_rb", back_aspect, ONE_FIXED/21}, + {"100 tail", back_aspect, ONE_FIXED/21}, + {"chest", centre_aspect, ONE_FIXED/21}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY AlTL[] = { + /* Top Locs */ + {"left bicep", centre_aspect, ONE_FIXED/7}, + {"right bicep", centre_aspect, ONE_FIXED/7}, + {"neck", centre_aspect, ONE_FIXED/7}, + {"head", centre_aspect, ONE_FIXED/7}, + {"pipe_lt", back_aspect, ONE_FIXED/7}, + {"pipe_rt", back_aspect, ONE_FIXED/7}, + {"chest", centre_aspect, ONE_FIXED/7}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY AlBL[] = { + /* Base Locs */ + {"left thigh", centre_aspect, ONE_FIXED/8}, + {"left shin", centre_aspect, ONE_FIXED/8}, + {"left foot", centre_aspect, ONE_FIXED/8}, + {"right thigh", centre_aspect, ONE_FIXED/8}, + {"right shin", centre_aspect, ONE_FIXED/8}, + {"right foot", centre_aspect, ONE_FIXED/8}, + {"100 tail", back_aspect, ONE_FIXED/8}, + {"abdom", centre_aspect, ONE_FIXED/8}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY AlLL[] = { + /* Left Locs */ + {"abdom", centre_aspect, ONE_FIXED/13}, + {"left bicep", centre_aspect, ONE_FIXED/13}, + {"left forearm",centre_aspect, ONE_FIXED/13}, + {"left palm", centre_aspect, ONE_FIXED/13}, + {"neck", centre_aspect, ONE_FIXED/13}, + {"head", centre_aspect, ONE_FIXED/13}, + {"left thigh", centre_aspect, ONE_FIXED/13}, + {"left shin", centre_aspect, ONE_FIXED/13}, + {"left foot", centre_aspect, ONE_FIXED/13}, + {"pipe_lt", back_aspect, ONE_FIXED/13}, + {"pipe_lb", back_aspect, ONE_FIXED/13}, + {"100 tail", back_aspect, ONE_FIXED/13}, + {"chest", centre_aspect, ONE_FIXED/13}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY AlRL[] = { + /* Right Locs */ + {"abdom", centre_aspect, ONE_FIXED/13}, + {"right bicep", centre_aspect, ONE_FIXED/13}, + {"right forearm",centre_aspect, ONE_FIXED/13}, + {"right palm", centre_aspect, ONE_FIXED/13}, + {"neck", centre_aspect, ONE_FIXED/13}, + {"head", centre_aspect, ONE_FIXED/13}, + {"right thigh", centre_aspect, ONE_FIXED/13}, + {"right shin", centre_aspect, ONE_FIXED/13}, + {"right foot", centre_aspect, ONE_FIXED/13}, + {"pipe_rt", back_aspect, ONE_FIXED/13}, + {"pipe_rb", back_aspect, ONE_FIXED/13}, + {"100 tail", back_aspect, ONE_FIXED/13}, + {"chest", centre_aspect, ONE_FIXED/13}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY AlTRL[] = { + /* Top Right Locs */ + {"right bicep", centre_aspect, ONE_FIXED/5}, + {"neck", centre_aspect, ONE_FIXED/5}, + {"head", centre_aspect, ONE_FIXED/5}, + {"pipe_rt", back_aspect, ONE_FIXED/5}, + {"chest", centre_aspect, ONE_FIXED/5}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY AlTLL[] = { + /* Top Left Locs */ + {"left bicep", centre_aspect, ONE_FIXED/5}, + {"neck", centre_aspect, ONE_FIXED/5}, + {"head", centre_aspect, ONE_FIXED/5}, + {"pipe_lt", back_aspect, ONE_FIXED/5}, + {"chest", centre_aspect, ONE_FIXED/5}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY AlBLL[] = { + /* Base Left Locs */ + {"left thigh", centre_aspect, ONE_FIXED/5}, + {"left shin", centre_aspect, ONE_FIXED/5}, + {"left foot", centre_aspect, ONE_FIXED/5}, + {"100 tail", back_aspect, ONE_FIXED/5}, + {"abdom", centre_aspect, ONE_FIXED/5}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY AlBRL[] = { + /* Base Right Locs */ + {"right thigh", centre_aspect, ONE_FIXED/5}, + {"right shin", centre_aspect, ONE_FIXED/5}, + {"right foot", centre_aspect, ONE_FIXED/5}, + {"100 tail", back_aspect, ONE_FIXED/5}, + {"abdom", centre_aspect, ONE_FIXED/5}, + {NULL, centre_aspect, 0}, +}; + +/* PRED-ALIENS */ + +HITLOCATIONTABLEENTRY PrdAlCL[] = { + /* Centre Locs */ + {"arse", centre_aspect, ONE_FIXED/18}, + {"left bicep", centre_aspect, ONE_FIXED/18}, + {"left forearm",centre_aspect, ONE_FIXED/18}, + {"left hand", centre_aspect, ONE_FIXED/18}, + {"right bicep", centre_aspect, ONE_FIXED/18}, + {"right forearm",centre_aspect, ONE_FIXED/18}, + {"right hand", centre_aspect, ONE_FIXED/18}, + {"neck", centre_aspect, ONE_FIXED/18}, + {"head", centre_aspect, ONE_FIXED/18}, + {"left thigh", centre_aspect, ONE_FIXED/18}, + {"left shin", centre_aspect, ONE_FIXED/18}, + {"left foot", centre_aspect, ONE_FIXED/18}, + {"right thigh", centre_aspect, ONE_FIXED/18}, + {"right shin", centre_aspect, ONE_FIXED/18}, + {"right foot", centre_aspect, ONE_FIXED/18}, + {"tail base", back_aspect, ONE_FIXED/18}, + {"tummy", centre_aspect, ONE_FIXED/18}, + {"chest", centre_aspect, ONE_FIXED/18}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PrdAlTL[] = { + /* Top Locs */ + {"left bicep", centre_aspect, ONE_FIXED/5}, + {"right bicep", centre_aspect, ONE_FIXED/5}, + {"neck", centre_aspect, ONE_FIXED/5}, + {"head", centre_aspect, ONE_FIXED/5}, + {"chest", centre_aspect, ONE_FIXED/5}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PrdAlBL[] = { + /* Base Locs */ + {"left thigh", centre_aspect, ONE_FIXED/8}, + {"left shin", centre_aspect, ONE_FIXED/8}, + {"left foot", centre_aspect, ONE_FIXED/8}, + {"right thigh", centre_aspect, ONE_FIXED/8}, + {"right shin", centre_aspect, ONE_FIXED/8}, + {"right foot", centre_aspect, ONE_FIXED/8}, + {"tail base", back_aspect, ONE_FIXED/8}, + {"arse", centre_aspect, ONE_FIXED/8}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PrdAlLL[] = { + /* Left Locs */ + {"arse", centre_aspect, ONE_FIXED/11}, + {"left bicep", centre_aspect, ONE_FIXED/11}, + {"left forearm",centre_aspect, ONE_FIXED/11}, + {"left hand", centre_aspect, ONE_FIXED/11}, + {"neck", centre_aspect, ONE_FIXED/11}, + {"head", centre_aspect, ONE_FIXED/11}, + {"left thigh", centre_aspect, ONE_FIXED/11}, + {"left shin", centre_aspect, ONE_FIXED/11}, + {"left foot", centre_aspect, ONE_FIXED/11}, + {"tail base", back_aspect, ONE_FIXED/11}, + {"chest", centre_aspect, ONE_FIXED/11}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PrdAlRL[] = { + /* Right Locs */ + {"arse", centre_aspect, ONE_FIXED/11}, + {"right bicep", centre_aspect, ONE_FIXED/11}, + {"right forearm",centre_aspect, ONE_FIXED/11}, + {"right hand", centre_aspect, ONE_FIXED/11}, + {"neck", centre_aspect, ONE_FIXED/11}, + {"head", centre_aspect, ONE_FIXED/11}, + {"right thigh", centre_aspect, ONE_FIXED/11}, + {"right shin", centre_aspect, ONE_FIXED/11}, + {"right foot", centre_aspect, ONE_FIXED/11}, + {"tail base", back_aspect, ONE_FIXED/11}, + {"chest", centre_aspect, ONE_FIXED/11}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PrdAlTRL[] = { + /* Top Right Locs */ + {"right bicep", centre_aspect, ONE_FIXED/4}, + {"neck", centre_aspect, ONE_FIXED/4}, + {"head", centre_aspect, ONE_FIXED/4}, + {"chest", centre_aspect, ONE_FIXED/4}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PrdAlTLL[] = { + /* Top Left Locs */ + {"left bicep", centre_aspect, ONE_FIXED/4}, + {"neck", centre_aspect, ONE_FIXED/4}, + {"head", centre_aspect, ONE_FIXED/4}, + {"chest", centre_aspect, ONE_FIXED/4}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PrdAlBLL[] = { + /* Base Left Locs */ + {"left thigh", centre_aspect, ONE_FIXED/5}, + {"left shin", centre_aspect, ONE_FIXED/5}, + {"left foot", centre_aspect, ONE_FIXED/5}, + {"tail base", back_aspect, ONE_FIXED/5}, + {"arse", centre_aspect, ONE_FIXED/5}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PrdAlBRL[] = { + /* Base Right Locs */ + {"right thigh", centre_aspect, ONE_FIXED/5}, + {"right shin", centre_aspect, ONE_FIXED/5}, + {"right foot", centre_aspect, ONE_FIXED/5}, + {"tail base", back_aspect, ONE_FIXED/5}, + {"arse", centre_aspect, ONE_FIXED/5}, + {NULL, centre_aspect, 0}, +}; + +/* PRAETORIAN GUARD */ + +HITLOCATIONTABLEENTRY PraetCL[] = { + /* Centre Locs */ + {"abdom", centre_aspect, ONE_FIXED/19}, + {"left bicep", centre_aspect, ONE_FIXED/19}, + {"left forearm",centre_aspect, ONE_FIXED/19}, + {"left palm", centre_aspect, ONE_FIXED/19}, + {"right bicep", centre_aspect, ONE_FIXED/19}, + {"right forearm",centre_aspect, ONE_FIXED/19}, + {"right palm", centre_aspect, ONE_FIXED/19}, + {"neck", centre_aspect, ONE_FIXED/19}, + {"head", centre_aspect, ONE_FIXED/19}, + {"left thigh", centre_aspect, ONE_FIXED/19}, + {"left shin", centre_aspect, ONE_FIXED/19}, + {"left ankle", centre_aspect, ONE_FIXED/19}, + {"left foot", centre_aspect, ONE_FIXED/19}, + {"right thigh", centre_aspect, ONE_FIXED/19}, + {"right shin", centre_aspect, ONE_FIXED/19}, + {"right ankle", centre_aspect, ONE_FIXED/19}, + {"right foot", centre_aspect, ONE_FIXED/19}, + {"100 tail", back_aspect, ONE_FIXED/19}, + {"chest", centre_aspect, ONE_FIXED/19}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PraetTL[] = { + /* Top Locs */ + {"left bicep", centre_aspect, ONE_FIXED/5}, + {"right bicep", centre_aspect, ONE_FIXED/5}, + {"neck", centre_aspect, ONE_FIXED/5}, + {"head", centre_aspect, ONE_FIXED/5}, + {"chest", centre_aspect, ONE_FIXED/5}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PraetBL[] = { + /* Base Locs */ + {"left thigh", centre_aspect, ONE_FIXED/10}, + {"left shin", centre_aspect, ONE_FIXED/10}, + {"left ankle", centre_aspect, ONE_FIXED/10}, + {"left foot", centre_aspect, ONE_FIXED/10}, + {"right thigh", centre_aspect, ONE_FIXED/10}, + {"right shin", centre_aspect, ONE_FIXED/10}, + {"right ankle", centre_aspect, ONE_FIXED/10}, + {"right foot", centre_aspect, ONE_FIXED/10}, + {"100 tail", back_aspect, ONE_FIXED/10}, + {"abdom", centre_aspect, ONE_FIXED/10}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PraetLL[] = { + /* Left Locs */ + {"abdom", centre_aspect, ONE_FIXED/12}, + {"left bicep", centre_aspect, ONE_FIXED/12}, + {"left forearm",centre_aspect, ONE_FIXED/12}, + {"left palm", centre_aspect, ONE_FIXED/12}, + {"neck", centre_aspect, ONE_FIXED/12}, + {"head", centre_aspect, ONE_FIXED/12}, + {"left thigh", centre_aspect, ONE_FIXED/12}, + {"left shin", centre_aspect, ONE_FIXED/12}, + {"left ankle", centre_aspect, ONE_FIXED/12}, + {"left foot", centre_aspect, ONE_FIXED/12}, + {"100 tail", back_aspect, ONE_FIXED/12}, + {"chest", centre_aspect, ONE_FIXED/12}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PraetRL[] = { + /* Right Locs */ + {"abdom", centre_aspect, ONE_FIXED/12}, + {"right bicep", centre_aspect, ONE_FIXED/12}, + {"right forearm",centre_aspect, ONE_FIXED/12}, + {"right palm", centre_aspect, ONE_FIXED/12}, + {"neck", centre_aspect, ONE_FIXED/12}, + {"head", centre_aspect, ONE_FIXED/12}, + {"right thigh", centre_aspect, ONE_FIXED/12}, + {"right shin", centre_aspect, ONE_FIXED/12}, + {"right ankle", centre_aspect, ONE_FIXED/12}, + {"right foot", centre_aspect, ONE_FIXED/12}, + {"100 tail", back_aspect, ONE_FIXED/12}, + {"chest", centre_aspect, ONE_FIXED/12}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PraetTRL[] = { + /* Top Right Locs */ + {"right bicep", centre_aspect, ONE_FIXED/4}, + {"neck", centre_aspect, ONE_FIXED/4}, + {"head", centre_aspect, ONE_FIXED/4}, + {"chest", centre_aspect, ONE_FIXED/4}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PraetTLL[] = { + /* Top Left Locs */ + {"left bicep", centre_aspect, ONE_FIXED/4}, + {"neck", centre_aspect, ONE_FIXED/4}, + {"head", centre_aspect, ONE_FIXED/4}, + {"chest", centre_aspect, ONE_FIXED/4}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PraetBLL[] = { + /* Base Left Locs */ + {"left thigh", centre_aspect, ONE_FIXED/6}, + {"left shin", centre_aspect, ONE_FIXED/6}, + {"left ankle", centre_aspect, ONE_FIXED/6}, + {"left foot", centre_aspect, ONE_FIXED/6}, + {"100 tail", back_aspect, ONE_FIXED/6}, + {"abdom", centre_aspect, ONE_FIXED/6}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PraetBRL[] = { + /* Base Right Locs */ + {"right thigh", centre_aspect, ONE_FIXED/6}, + {"right shin", centre_aspect, ONE_FIXED/6}, + {"right ankle", centre_aspect, ONE_FIXED/6}, + {"right foot", centre_aspect, ONE_FIXED/6}, + {"100 tail", back_aspect, ONE_FIXED/6}, + {"abdom", centre_aspect, ONE_FIXED/6}, + {NULL, centre_aspect, 0}, +}; + +/* PREDATORS */ + +/* Predator Centre Locations */ +HITLOCATIONTABLEENTRY PCL[] = { + /* Centre locs */ + {"Pelvis", centre_aspect, ONE_FIXED/20}, + {"L thi", centre_aspect, ONE_FIXED/20}, + {"L shin", centre_aspect, ONE_FIXED/20}, + {"L foot", centre_aspect, ONE_FIXED/20}, + {"R thi", centre_aspect, ONE_FIXED/20}, + {"R shin", centre_aspect, ONE_FIXED/20}, + {"R foot", centre_aspect, ONE_FIXED/20}, + {"chest", centre_aspect, ONE_FIXED/20}, + {"R shoulder", centre_aspect, ONE_FIXED/20}, + {"R bicep", centre_aspect, ONE_FIXED/20}, + {"R elbow", centre_aspect, ONE_FIXED/20}, + {"R forearm", centre_aspect, ONE_FIXED/20}, + {"R hand palm", centre_aspect, ONE_FIXED/20}, + {"L shoulder", centre_aspect, ONE_FIXED/20}, + {"L bicep", centre_aspect, ONE_FIXED/20}, + {"L elbow", centre_aspect, ONE_FIXED/20}, + {"L forearm", centre_aspect, ONE_FIXED/20}, + {"L hand palm", centre_aspect, ONE_FIXED/20}, + {"neck", centre_aspect, ONE_FIXED/20}, + {"head", centre_aspect, ONE_FIXED/20}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PTL[] = { + /* Top locs */ + {"chest", centre_aspect, ONE_FIXED/13}, + {"R shoulder", centre_aspect, ONE_FIXED/13}, + {"R bicep", centre_aspect, ONE_FIXED/13}, + {"R elbow", centre_aspect, ONE_FIXED/13}, + {"R forearm", centre_aspect, ONE_FIXED/13}, + {"R hand palm", centre_aspect, ONE_FIXED/13}, + {"L shoulder", centre_aspect, ONE_FIXED/13}, + {"L bicep", centre_aspect, ONE_FIXED/13}, + {"L elbow", centre_aspect, ONE_FIXED/13}, + {"L forearm", centre_aspect, ONE_FIXED/13}, + {"L hand palm", centre_aspect, ONE_FIXED/13}, + {"neck", centre_aspect, ONE_FIXED/13}, + {"head", centre_aspect, ONE_FIXED/13}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PBL[] = { + /* Base locs */ + {"Pelvis", centre_aspect, ONE_FIXED/7}, + {"L thi", centre_aspect, ONE_FIXED/7}, + {"L shin", centre_aspect, ONE_FIXED/7}, + {"L foot", centre_aspect, ONE_FIXED/7}, + {"R thi", centre_aspect, ONE_FIXED/7}, + {"R shin", centre_aspect, ONE_FIXED/7}, + {"R foot", centre_aspect, ONE_FIXED/7}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PLL[] = { + /* Left locs */ + {"Pelvis", centre_aspect, ONE_FIXED/12}, + {"L thi", centre_aspect, ONE_FIXED/12}, + {"L shin", centre_aspect, ONE_FIXED/12}, + {"L foot", centre_aspect, ONE_FIXED/12}, + {"chest", centre_aspect, ONE_FIXED/12}, + {"L shoulder", centre_aspect, ONE_FIXED/12}, + {"L bicep", centre_aspect, ONE_FIXED/12}, + {"L elbow", centre_aspect, ONE_FIXED/12}, + {"L forearm", centre_aspect, ONE_FIXED/12}, + {"L hand palm", centre_aspect, ONE_FIXED/12}, + {"neck", centre_aspect, ONE_FIXED/12}, + {"head", centre_aspect, ONE_FIXED/12}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PRL[] = { + /* Right locs */ + {"Pelvis", centre_aspect, ONE_FIXED/12}, + {"R thi", centre_aspect, ONE_FIXED/12}, + {"R shin", centre_aspect, ONE_FIXED/12}, + {"R foot", centre_aspect, ONE_FIXED/12}, + {"chest", centre_aspect, ONE_FIXED/12}, + {"R shoulder", centre_aspect, ONE_FIXED/12}, + {"R bicep", centre_aspect, ONE_FIXED/12}, + {"R elbow", centre_aspect, ONE_FIXED/12}, + {"R forearm", centre_aspect, ONE_FIXED/12}, + {"R hand palm", centre_aspect, ONE_FIXED/12}, + {"neck", centre_aspect, ONE_FIXED/12}, + {"head", centre_aspect, ONE_FIXED/12}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PTLL[] = { + /* TopLeft locs */ + {"chest", centre_aspect, ONE_FIXED/8}, + {"L shoulder", centre_aspect, ONE_FIXED/8}, + {"L bicep", centre_aspect, ONE_FIXED/8}, + {"L elbow", centre_aspect, ONE_FIXED/8}, + {"L forearm", centre_aspect, ONE_FIXED/8}, + {"L hand palm", centre_aspect, ONE_FIXED/8}, + {"neck", centre_aspect, ONE_FIXED/8}, + {"head", centre_aspect, ONE_FIXED/8}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PTRL[] = { + /* TopRight locs */ + {"chest", centre_aspect, ONE_FIXED/8}, + {"R shoulder", centre_aspect, ONE_FIXED/8}, + {"R bicep", centre_aspect, ONE_FIXED/8}, + {"R elbow", centre_aspect, ONE_FIXED/8}, + {"R forearm", centre_aspect, ONE_FIXED/8}, + {"R hand palm", centre_aspect, ONE_FIXED/8}, + {"neck", centre_aspect, ONE_FIXED/8}, + {"head", centre_aspect, ONE_FIXED/8}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PBLL[] = { + /* BaseLeft locs */ + {"Pelvis", centre_aspect, ONE_FIXED/4}, + {"L thi", centre_aspect, ONE_FIXED/4}, + {"L shin", centre_aspect, ONE_FIXED/4}, + {"L foot", centre_aspect, ONE_FIXED/4}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY PBRL[] = { + /* BaseRight locs */ + {"Pelvis", centre_aspect, ONE_FIXED/4}, + {"R thi", centre_aspect, ONE_FIXED/4}, + {"R shin", centre_aspect, ONE_FIXED/4}, + {"R foot", centre_aspect, ONE_FIXED/4}, + {NULL, centre_aspect, 0}, +}; + +/* XENOBORGS */ +HITLOCATIONTABLEENTRY XBCL[] = { + /* Centre Locs */ + {"pelvis presley", centre_aspect, ONE_FIXED/26}, + {"left bicep", centre_aspect, ONE_FIXED/26}, + {"left forearm", centre_aspect, ONE_FIXED/26}, + {"left attacher", front_aspect, ONE_FIXED/26}, + {"lazer left", front_aspect, ONE_FIXED/26}, + {"barney", front_aspect, ONE_FIXED/26}, + {"right bicep", centre_aspect, ONE_FIXED/26}, + {"right forearm", centre_aspect, ONE_FIXED/26}, + {"right attacher", front_aspect, ONE_FIXED/26}, + {"pump", front_aspect, ONE_FIXED/26}, + {"ming", front_aspect, ONE_FIXED/26}, + {"neck", centre_aspect, ONE_FIXED/26}, + {"head", centre_aspect, ONE_FIXED/26}, + {"sights", centre_aspect, ONE_FIXED/26}, + {"left thigh", centre_aspect, ONE_FIXED/26}, + {"left shin", centre_aspect, ONE_FIXED/26}, + {"left foot", centre_aspect, ONE_FIXED/26}, + {"right thigh", centre_aspect, ONE_FIXED/26}, + {"right shin", centre_aspect, ONE_FIXED/26}, + {"right foot", centre_aspect, ONE_FIXED/26}, + {"back pac", back_aspect, ONE_FIXED/26}, + {"exhaust", back_aspect, ONE_FIXED/26}, + {"pipe", back_aspect, ONE_FIXED/26}, + {"tail a", back_aspect, ONE_FIXED/26}, + {"tummy", centre_aspect, ONE_FIXED/26}, + {"chest", centre_aspect, ONE_FIXED/26}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY XBTL[] = { + /* Top locs */ + {"left bicep", centre_aspect, ONE_FIXED/16}, + {"left forearm", centre_aspect, ONE_FIXED/16}, + {"left attacher", front_aspect, ONE_FIXED/16}, + {"lazer left", front_aspect, ONE_FIXED/16}, + {"barney", front_aspect, ONE_FIXED/16}, + {"right bicep", centre_aspect, ONE_FIXED/16}, + {"right forearm", centre_aspect, ONE_FIXED/16}, + {"right attacher", front_aspect, ONE_FIXED/16}, + {"pump", front_aspect, ONE_FIXED/16}, + {"ming", front_aspect, ONE_FIXED/16}, + {"neck", centre_aspect, ONE_FIXED/16}, + {"head", centre_aspect, ONE_FIXED/16}, + {"sights", centre_aspect, ONE_FIXED/16}, + {"exhaust", back_aspect, ONE_FIXED/16}, + {"pipe", back_aspect, ONE_FIXED/16}, + {"chest", centre_aspect, ONE_FIXED/16}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY XBBL[] = { + /* Base locs */ + {"pelvis presley", centre_aspect, ONE_FIXED/9}, + {"left thigh", centre_aspect, ONE_FIXED/9}, + {"left shin", centre_aspect, ONE_FIXED/9}, + {"left foot", centre_aspect, ONE_FIXED/9}, + {"right thigh", centre_aspect, ONE_FIXED/9}, + {"right shin", centre_aspect, ONE_FIXED/9}, + {"right foot", centre_aspect, ONE_FIXED/9}, + {"back pac", back_aspect, ONE_FIXED/9}, + {"tail a", back_aspect, ONE_FIXED/9}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY XBLL[] = { + /* Left locs */ + {"pelvis presley", centre_aspect, ONE_FIXED/18}, + {"left bicep", centre_aspect, ONE_FIXED/18}, + {"left forearm", centre_aspect, ONE_FIXED/18}, + {"left attacher", front_aspect, ONE_FIXED/18}, + {"lazer left", front_aspect, ONE_FIXED/18}, + {"barney", front_aspect, ONE_FIXED/18}, + {"neck", centre_aspect, ONE_FIXED/18}, + {"head", centre_aspect, ONE_FIXED/18}, + {"sights", centre_aspect, ONE_FIXED/18}, + {"left thigh", centre_aspect, ONE_FIXED/18}, + {"left shin", centre_aspect, ONE_FIXED/18}, + {"left foot", centre_aspect, ONE_FIXED/18}, + {"back pac", back_aspect, ONE_FIXED/18}, + {"exhaust", back_aspect, ONE_FIXED/18}, + {"pipe", back_aspect, ONE_FIXED/18}, + {"tail a", back_aspect, ONE_FIXED/18}, + {"tummy", centre_aspect, ONE_FIXED/18}, + {"chest", centre_aspect, ONE_FIXED/18}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY XBRL[] = { + /* Right locs */ + {"pelvis presley", centre_aspect, ONE_FIXED/17}, + {"right bicep", centre_aspect, ONE_FIXED/17}, + {"right forearm", centre_aspect, ONE_FIXED/17}, + {"right attacher", front_aspect, ONE_FIXED/17}, + {"pump", front_aspect, ONE_FIXED/17}, + {"ming", front_aspect, ONE_FIXED/17}, + {"neck", centre_aspect, ONE_FIXED/17}, + {"head", centre_aspect, ONE_FIXED/17}, + {"right thigh", centre_aspect, ONE_FIXED/17}, + {"right shin", centre_aspect, ONE_FIXED/17}, + {"right foot", centre_aspect, ONE_FIXED/17}, + {"back pac", back_aspect, ONE_FIXED/17}, + {"exhaust", back_aspect, ONE_FIXED/17}, + {"pipe", back_aspect, ONE_FIXED/17}, + {"tail a", back_aspect, ONE_FIXED/17}, + {"tummy", centre_aspect, ONE_FIXED/17}, + {"chest", centre_aspect, ONE_FIXED/17}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY XBTLL[] = { + /* TopLeft locs */ + {"left bicep", centre_aspect, ONE_FIXED/11}, + {"left forearm", centre_aspect, ONE_FIXED/11}, + {"left attacher", front_aspect, ONE_FIXED/11}, + {"lazer left", front_aspect, ONE_FIXED/11}, + {"barney", front_aspect, ONE_FIXED/11}, + {"neck", centre_aspect, ONE_FIXED/11}, + {"head", centre_aspect, ONE_FIXED/11}, + {"sights", centre_aspect, ONE_FIXED/11}, + {"exhaust", back_aspect, ONE_FIXED/11}, + {"pipe", back_aspect, ONE_FIXED/11}, + {"chest", centre_aspect, ONE_FIXED/11}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY XBTRL[] = { + /* TopRight locs */ + {"right bicep", centre_aspect, ONE_FIXED/10}, + {"right forearm", centre_aspect, ONE_FIXED/10}, + {"right attacher", front_aspect, ONE_FIXED/10}, + {"pump", front_aspect, ONE_FIXED/10}, + {"ming", front_aspect, ONE_FIXED/10}, + {"neck", centre_aspect, ONE_FIXED/10}, + {"head", centre_aspect, ONE_FIXED/10}, + {"exhaust", back_aspect, ONE_FIXED/10}, + {"pipe", back_aspect, ONE_FIXED/10}, + {"chest", centre_aspect, ONE_FIXED/10}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY XBBLL[] = { + /* BaseLeft locs */ + {"pelvis presley", centre_aspect, ONE_FIXED/6}, + {"left thigh", centre_aspect, ONE_FIXED/6}, + {"left shin", centre_aspect, ONE_FIXED/6}, + {"left foot", centre_aspect, ONE_FIXED/6}, + {"back pac", back_aspect, ONE_FIXED/6}, + {"tail a", back_aspect, ONE_FIXED/6}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLEENTRY XBBRL[] = { + /* BaseRight locs */ + {"pelvis presley", centre_aspect, ONE_FIXED/6}, + {"right thigh", centre_aspect, ONE_FIXED/6}, + {"right shin", centre_aspect, ONE_FIXED/6}, + {"right foot", centre_aspect, ONE_FIXED/6}, + {"back pac", back_aspect, ONE_FIXED/6}, + {"tail a", back_aspect, ONE_FIXED/6}, + {NULL, centre_aspect, 0}, +}; + +/* Sentry Guns */ +HITLOCATIONTABLEENTRY SGGL[] = { + /* General locs */ + {"legs", centre_aspect, ONE_FIXED/3}, + {"pivot", centre_aspect, ONE_FIXED/3}, + {"gun", centre_aspect, ONE_FIXED/3}, + {NULL, centre_aspect, 0}, +}; + +HITLOCATIONTABLE Global_Hitlocation_Tables[] = { + { + /* MARINE */ + "marine with pulse rifle", + 0, /*index*/ + &MWPRCL[0], + &MWPRTL[0], + &MWPRBL[0], + &MWPRLL[0], + &MWPRRL[0], + &MWPRTLL[0], + &MWPRTRL[0], + &MWPRBLL[0], + &MWPRBRL[0], + }, + { + /* MARINE */ + "marine with smart gun", + 1, /*index*/ + &MWPRCL[0], + &MWPRTL[0], + &MWPRBL[0], + &MWPRLL[0], + &MWPRRL[0], + &MWPRTLL[0], + &MWPRTRL[0], + &MWPRBLL[0], + &MWPRBRL[0], + }, + { + /* MARINE */ + "marine with flame thrower", + 2, /*index*/ + &MWPRCL[0], + &MWPRTL[0], + &MWPRBL[0], + &MWPRLL[0], + &MWPRRL[0], + &MWPRTLL[0], + &MWPRTRL[0], + &MWPRBLL[0], + &MWPRBRL[0], + }, + { + /* CIVILIAN */ + "male civvie", + 3, /*index*/ + &MCCL[0], + &MCTL[0], + &MCBL[0], + &MCLL[0], + &MCRL[0], + &MCTLL[0], + &MCTRL[0], + &MCBLL[0], + &MCBRL[0], + }, + { + /* ALIEN */ + "alien", + 4, /*index*/ + &AlCL[0], + &AlTL[0], + &AlBL[0], + &AlLL[0], + &AlRL[0], + &AlTLL[0], + &AlTRL[0], + &AlBLL[0], + &AlBRL[0], + }, + { + /* PRED-ALIEN */ + "predalien", + 5, /*index*/ + &PrdAlCL[0], + &PrdAlTL[0], + &PrdAlBL[0], + &PrdAlLL[0], + &PrdAlRL[0], + &PrdAlTLL[0], + &PrdAlTRL[0], + &PrdAlBLL[0], + &PrdAlBRL[0], + }, + { + /* PRAETORIAN */ + "praetorian", + 6, /*index*/ + &PraetCL[0], + &PraetTL[0], + &PraetBL[0], + &PraetLL[0], + &PraetRL[0], + &PraetTLL[0], + &PraetTRL[0], + &PraetBLL[0], + &PraetBRL[0], + }, + { + /* PREDATOR */ + "predator", + 7, /*index*/ + &PCL[0], + &PTL[0], + &PBL[0], + &PLL[0], + &PRL[0], + &PTLL[0], + &PTRL[0], + &PBLL[0], + &PBRL[0], + }, + { + /* XENOBORG */ + "xenoborg", + 8, /*index*/ + &XBCL[0], + &XBTL[0], + &XBBL[0], + &XBLL[0], + &XBRL[0], + &XBTLL[0], + &XBTRL[0], + &XBBLL[0], + &XBBRL[0], + }, + { + /* SENTRY GUN */ + "sentrygun", + 9, /*index*/ + &SGGL[0], + &SGGL[0], + &SGGL[0], + &SGGL[0], + &SGGL[0], + &SGGL[0], + &SGGL[0], + &SGGL[0], + &SGGL[0], + }, + { + /* Terminator */ + NULL, + -1, /*index*/ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + }, +}; + +SECTION_ATTACHMENT Default_Stats = { + NULL, + NULL, + NULL, + { + 10000, /* Health */ + 5000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 1, /* Fire Resistant */ + 1, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_doesnthurtsb|section_flag_passdamagetoparent, +}; + +char *Android_Hierarchy_Names[] = { + "Android shotgun", + "Android Shotgun Special", + "Android Pistol Special", + "Android template", + NULL, +}; + +SECTION_ATTACHMENT Global_Section_Attachments[] = { + /* FACEHUGGERS! */ + { + "hnpchugger", + "body", + NULL, + { + 5, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "right air sack", + NULL, + { + 5, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "left air sack", + NULL, + { + 5, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "l00 tail", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "l01 tail", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "l02 tail", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "l03 tail", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "l04 tail", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "l05 tail", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "l06 tail", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "l07 tail", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "l08 tail", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "l09 tail", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "l10 tail", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "l11 tail", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "left a1 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "left a2 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "left a3 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "left b1 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "left b2 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "left b3 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "left c1 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "left c2 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "left c3 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "left d1 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "left d2 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "left d3 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "right a1 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "right a2 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "right a3 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "right b1 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "right b2 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "right b3 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "right c1 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "right c2 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "right c3 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "right d1 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "right d2 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpchugger", + "right d3 finger", + NULL, + { + 4, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + /* ALIENS */ + { + "HNPCalien", + "head", + NULL, + { + 10, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_head|section_has_sparkoflife|section_sprays_acid, + }, + { + "HNPCalien", + "chest", + NULL, + { + 20, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid|section_flag_gibbwhenfragged, + }, + { + "HNPCalien", + "abdom", + NULL, + { + 20, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "HNPCalien", + "left thigh", + NULL, + { + 20, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_leg, + }, + { + "HNPCalien", + "left shin", + NULL, + { + 15, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_leg, + }, + { + "HNPCalien", + "left foot", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_foot, + }, + { + "HNPCalien", + "right thigh", + NULL, + { + 20, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_leg, + }, + { + "HNPCalien", + "right shin", + NULL, + { + 15, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_leg, + }, + { + "HNPCalien", + "right foot", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_foot, + }, + { + "HNPCalien", + "pipe_rt", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "pipe_rb", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "pipe_lt", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "pipe_lb", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "spike", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "neck", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "HNPCalien", + "bite main", + NULL, + { + 3, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "bite bottom", + NULL, + { + 3, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "bite top", + NULL, + { + 3, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "right bicep", + NULL, + { + 10, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_arm, + }, + { + "HNPCalien", + "right forearm", + NULL, + { + 10, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_arm, + }, + { + "HNPCalien", + "right palm", + NULL, + { + 10, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_hand, + }, + { + "HNPCalien", + "right thumb b", + NULL, + { + 2, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "right thumb a", + NULL, + { + 2, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "right finger b", + NULL, + { + 2, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "right finger a", + NULL, + { + 2, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "left bicep", + NULL, + { + 10, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_arm, + }, + { + "HNPCalien", + "left forearm", + NULL, + { + 10, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_arm, + }, + { + "HNPCalien", + "left palm", + NULL, + { + 10, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_hand, + }, + { + "HNPCalien", + "left thumb b", + NULL, + { + 2, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "left thumb a", + NULL, + { + 2, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "left finger b", + NULL, + { + 2, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "left finger a", + NULL, + { + 2, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "HNPCalien", + "l00 tail", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "HNPCalien", + "l01 tail", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "HNPCalien", + "l02 tail", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "HNPCalien", + "l03 tail", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "HNPCalien", + "l04 tail", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "HNPCalien", + "l05 tail", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "HNPCalien", + "l06 tail", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "HNPCalien", + "l07 tail", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "HNPCalien", + "l08 tail", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "HNPCalien", + "l09 tail", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "HNPCalien", + "l10 tail", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "HNPCalien", + "l11 tail", + NULL, + { + 5, /* Health */ + 5, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + /* PRAETORIAN GUARD */ + { + "hnpcpretorian", + "head", + NULL, + { + 50, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_head|section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpcpretorian", + "chest", + NULL, + { + 100, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid|section_flag_gibbwhenfragged, + }, + { + "hnpcpretorian", + "abdom", + NULL, + { + 100, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpcpretorian", + "left thigh", + NULL, + { + 100, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_leg, + }, + { + "hnpcpretorian", + "left shin", + NULL, + { + 75, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_leg, + }, + { + "hnpcpretorian", + "left ankle", + NULL, + { + 50, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_leg, + }, + { + "hnpcpretorian", + "left foot", + NULL, + { + 25, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_foot, + }, + { + "hnpcpretorian", + "right thigh", + NULL, + { + 100, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_leg, + }, + { + "hnpcpretorian", + "right shin", + NULL, + { + 75, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_leg, + }, + { + "hnpcpretorian", + "right ankle", + NULL, + { + 50, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_leg, + }, + { + "hnpcpretorian", + "right foot", + NULL, + { + 25, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_foot, + }, + { + "hnpcpretorian", + "neck", + NULL, + { + 25, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpcpretorian", + "bite main", + NULL, + { + 15, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "hnpcpretorian", + "bite bottom", + NULL, + { + 15, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "hnpcpretorian", + "bite top", + NULL, + { + 15, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "hnpcpretorian", + "right bicep", + NULL, + { + 50, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_arm, + }, + { + "hnpcpretorian", + "right forearm", + NULL, + { + 50, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_arm, + }, + { + "hnpcpretorian", + "right palm", + NULL, + { + 50, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_hand, + }, + { + "hnpcpretorian", + "right thumb b", + NULL, + { + 10, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "hnpcpretorian", + "right thumb a", + NULL, + { + 10, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "hnpcpretorian", + "right finger b", + NULL, + { + 10, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "hnpcpretorian", + "right finger a", + NULL, + { + 10, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "hnpcpretorian", + "left bicep", + NULL, + { + 50, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_arm, + }, + { + "hnpcpretorian", + "left forearm", + NULL, + { + 50, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_arm, + }, + { + "hnpcpretorian", + "left palm", + NULL, + { + 50, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_hand, + }, + { + "hnpcpretorian", + "left thumb b", + NULL, + { + 10, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "hnpcpretorian", + "left thumb a", + NULL, + { + 10, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "hnpcpretorian", + "left finger b", + NULL, + { + 10, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "hnpcpretorian", + "left finger a", + NULL, + { + 10, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "hnpcpretorian", + "l00 tail", + NULL, + { + 25, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpretorian", + "l01 tail", + NULL, + { + 25, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpretorian", + "l02 tail", + NULL, + { + 25, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpretorian", + "l03 tail", + NULL, + { + 25, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpretorian", + "l04 tail", + NULL, + { + 25, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpretorian", + "l05 tail", + NULL, + { + 25, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpretorian", + "l06 tail", + NULL, + { + 25, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpretorian", + "l07 tail", + NULL, + { + 25, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpretorian", + "l08 tail", + NULL, + { + 25, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpretorian", + "l09 tail", + NULL, + { + 25, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpretorian", + "l10 tail", + NULL, + { + 25, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpretorian", + "l11 tail", + NULL, + { + 25, /* Health */ + 60, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + /* PREDALIENS */ + { + "hnpcpred_alien", + "head", + NULL, + { + 80, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_head|section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpcpred_alien", + "chest", + NULL, + { + 160, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid|section_flag_gibbwhenfragged, + }, + { + "hnpcpred_alien", + "tummy", + NULL, + { + 160, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid|section_flag_gibbwhenfragged, + }, + { + "hnpcpred_alien", + "arse", + NULL, + { + 160, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpcpred_alien", + "left thigh", + NULL, + { + 160, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_leg, + }, + { + "hnpcpred_alien", + "left shin", + NULL, + { + 120, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_leg, + }, + { + "hnpcpred_alien", + "left foot", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_foot, + }, + { + "hnpcpred_alien", + "lx", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_foot, + }, + { + "hnpcpred_alien", + "toe a", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_foot, + }, + { + "hnpcpred_alien", + "toe b", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_foot, + }, + { + "hnpcpred_alien", + "toe c", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_foot, + }, + { + "hnpcpred_alien", + "right thigh", + NULL, + { + 160, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_leg, + }, + { + "hnpcpred_alien", + "right shin", + NULL, + { + 120, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_leg, + }, + { + "hnpcpred_alien", + "right foot", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_foot, + }, + { + "hnpcpred_alien", + "rx", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_foot, + }, + { + "hnpcpred_alien", + "toe d", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_foot, + }, + { + "hnpcpred_alien", + "toe e", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_foot, + }, + { + "hnpcpred_alien", + "toe f", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_foot, + }, + { + "hnpcpred_alien", + "neck", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpcpred_alien", + "right bicep", + NULL, + { + 80, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_arm, + }, + { + "hnpcpred_alien", + "right forearm", + NULL, + { + 80, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_arm, + }, + { + "hnpcpred_alien", + "right hand", + NULL, + { + 80, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_hand, + }, + { + "hnpcpred_alien", + "right thumb", + NULL, + { + 16, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_hand, + }, + { + "hnpcpred_alien", + "right fing a", + NULL, + { + 16, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_hand, + }, + { + "hnpcpred_alien", + "right fing b", + NULL, + { + 16, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_hand, + }, + { + "hnpcpred_alien", + "right fing c", + NULL, + { + 16, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_right_hand, + }, + { + "hnpcpred_alien", + "right arm fin", + NULL, + { + 20, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid + }, + { + "hnpcpred_alien", + "left bicep", + NULL, + { + 80, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_arm, + }, + { + "hnpcpred_alien", + "left forearm", + NULL, + { + 80, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_arm, + }, + { + "hnpcpred_alien", + "left hand", + NULL, + { + 80, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_hand, + }, + { + "hnpcpred_alien", + "left thumb", + NULL, + { + 16, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_hand, + }, + { + "hnpcpred_alien", + "left fing a", + NULL, + { + 16, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_hand, + }, + { + "hnpcpred_alien", + "left fing b", + NULL, + { + 16, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_hand, + }, + { + "hnpcpred_alien", + "left fing c", + NULL, + { + 16, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_left_hand, + }, + { + "hnpcpred_alien", + "left arm fin", + NULL, + { + 20, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid + }, + + + { + "hnpcpred_alien", + "tail base", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + + { + "hnpcpred_alien", + "tail a", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpred_alien", + "tail b", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpred_alien", + "tail c", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpred_alien", + "tail d", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpred_alien", + "tail e", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpred_alien", + "tail f", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpred_alien", + "tail g", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpred_alien", + "tail h", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + { + "hnpcpred_alien", + "tail i", + NULL, + { + 40, /* Health */ + 40, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_nofurthergibbing|section_sprays_acid|section_flag_tail, + }, + /* MARINE */ + { + "hnpcmarine", + "pelvis", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "Lthigh", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_leg|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "Lshin", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_leg|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "Lfoot", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_foot|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "Lpouch", + NULL, + { + 10, /* Health */ + 4, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_doesnthurtsb|section_flag_passdamagetoparent, + }, + { + "hnpcmarine", + "Rthigh", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_leg|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "Rshin", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_leg|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "Rfoot", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_foot|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "Rpouch", + NULL, + { + 10, /* Health */ + 4, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_doesnthurtsb|section_flag_passdamagetoparent, + }, + { + "hnpcmarine", + "chest", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_heatsource|section_flag_fragonlyfordisks, + }, + { + "hnpcmarine", + "Rbicep", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_arm|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "Rforearm", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_arm|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "Rpalm", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "R1fingers", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "R2fingers", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "R1thumb", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "R2thumb", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "Rpad", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_doesnthurtsb|section_flag_passdamagetoparent, + }, + { + "hnpcmarine", + "Lbicep", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_arm|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "Lforearm", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_arm|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "Lpalm", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "L1fingers", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "L2fingers", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "L1thumb", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "L2thumb", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "Lpad", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_doesnthurtsb|section_flag_passdamagetoparent, + }, + { + "hnpcmarine", + "light pack", + NULL, + { + 5, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + //section_sprays_sparks|section_flag_doesnthurtsb, + section_flag_doesnthurtsb|section_flag_passdamagetoparent, + }, + { + "hnpcmarine", + "light ", + NULL, + { + 5, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + //section_sprays_sparks|section_flag_doesnthurtsb, + section_flag_doesnthurtsb|section_flag_passdamagetoparent, + }, + { + "hnpcmarine", + "neck", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_affectedbyheat, + }, + { + "hnpcmarine", + "head", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_head|section_has_sparkoflife|section_sprays_blood|section_flag_heatsource, + }, + { + "hnpcmarine", + "neck guard", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_doesnthurtsb|section_flag_passdamagetoparent, + }, + { + "hnpcmarine", + "helm", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_doesnthurtsb|section_flag_passdamagetoparent, + }, + /* Predator */ + /* CDF 9/3/99 Removed heat source flags from chest and head. */ + #define PRED_SECTION_HEALTH (100) + #define PRED_SECTION_ARMOUR (200) + { + "hnpcpredator", + "Pelvis", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "chest", + NULL, + { + ((PRED_SECTION_HEALTH)<<1), /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood, + }, + { + "hnpcpredator", + "neck", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "head", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_head|section_has_sparkoflife|section_sprays_predoblood, + }, + { + "hnpcpredator", + "L shoulder", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_arm|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L bicep", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_arm|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L elbow", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_arm|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L forearm", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_arm|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L hand palm", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L hand thumb a", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L hand thumb b", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L hand finger 1a", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L hand finger 1b", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L hand finger 2a", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L hand finger 2b", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L hand finger 3a", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L hand finger 3b", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L hand finger 4a", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L hand finger 4b", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R shoulder", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_arm|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R bicep", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_arm|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R elbow", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_arm|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R forearm", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_arm|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R hand palm", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R hand thumb a", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R hand thumb b", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R hand finger 1a", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R hand finger 1b", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R hand finger 2a", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R hand finger 2b", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R hand finger 3a", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R hand finger 3b", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R hand finger 4a", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R hand finger 4b", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R thi", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_leg|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R shin", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_leg|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "R foot", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_right_foot|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L thi", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_leg|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L shin", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_leg|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "L foot", + NULL, + { + PRED_SECTION_HEALTH, /* Health */ + PRED_SECTION_ARMOUR, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_predoblood|section_flag_left_foot|section_flag_affectedbyheat, + }, + { + "hnpcpredator", + "staff center retracted", + NULL, + { + 1000, /* Health */ + 2000, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_doesnthurtsb, + }, + /* CIVILIANS */ + + { + "hnpc_civvie", + "pelvis presley", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_affectedbyheat, + }, + + { + "hnpc_civvie", + "male left thigh", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_leg|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male left shin", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_leg|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male left foot", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_foot|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male right thigh", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_leg|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male right shin", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_leg|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male right foot", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_foot|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "stomach", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_affectedbyheat|section_flag_fragonlyfordisks, + }, + { + "hnpc_civvie", + "chest", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_heatsource|section_flag_fragonlyfordisks, + }, + { + "hnpc_civvie", + "neck", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "head", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_heatsource, + }, + { + "hnpc_civvie", + "male right bicep", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_arm|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male right forearm", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_arm|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "right palm", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "right fings top", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "right fings end", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male right thumb", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male left bicep", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_arm|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male left forearm", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_arm|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "left palm", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "left fings top", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "left fings end", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male left thumb", + NULL, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "hair", + NULL, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_doesnthurtsb|section_flag_passdamagetoparent|section_flag_affectedbyheat, + }, + /* A bit wusser than marines, and no armour! */ + /* Androids! */ + + { + "hnpc_civvie", + "pelvis presley", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_affectedbyheat, + }, + + { + "hnpc_civvie", + "male left thigh", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_leg|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male left shin", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_leg|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male left foot", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_left_foot|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male right thigh", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_leg|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male right shin", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_leg|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male right foot", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_right_foot|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "stomach", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_affectedbyheat|section_flag_fragonlyfordisks, + }, + { + "hnpc_civvie", + "chest", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_fragonlyfordisks, + }, + { + "hnpc_civvie", + "neck", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "head", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_blood, + }, + { + "hnpc_civvie", + "male right bicep", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_right_arm|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male right forearm", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_right_arm|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "right palm", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "right fings top", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "right fings end", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male right thumb", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_right_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male left bicep", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_left_arm|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male left forearm", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_left_arm|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "left palm", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "left fings top", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "left fings end", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "male left thumb", + Android_Hierarchy_Names, + { + 8, /* Health */ + 1, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_blood|section_flag_left_hand|section_flag_affectedbyheat, + }, + { + "hnpc_civvie", + "hair", + Android_Hierarchy_Names, + { + 10, /* Health */ + 8, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_doesnthurtsb|section_flag_passdamagetoparent|section_flag_affectedbyheat, + }, + + /* PREDATOR HUD. */ + { + "pred_hud", + "lbs", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "lba", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_heatsource, + }, + { + "pred_hud", + "lbw", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "lbh", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_heatsource, + }, + { + "pred_hud", + "lbffff", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "lbfff", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "lbff", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "lbf", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "lbt", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rbs", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rba", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_heatsource, + }, + { + "pred_hud", + "rbw", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rbh", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_heatsource, + }, + { + "pred_hud", + "rbffff", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rbfff", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rbff", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rbf", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rbt", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + + { + "pred_hud", + "rps", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rpa", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_heatsource, + }, + { + "pred_hud", + "rpw", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rph", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_heatsource, + }, + { + "pred_hud", + "rpffff", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rpfff", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rpff", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rpf", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rpt", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "lds", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "lda", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_heatsource, + }, + { + "pred_hud", + "ldw", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "ldh", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_heatsource, + }, + { + "pred_hud", + "ldffff", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "ldfff", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "ldff", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "ldf", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "ldt", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rds", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rda", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_heatsource, + }, + { + "pred_hud", + "rdw", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rdh", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_heatsource, + }, + { + "pred_hud", + "rdffff", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rdfff", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rdff", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rdf", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "rdt", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "Staff L palm", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "Staff L little finger", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "Staff L mid finger", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "Staff L ring finger", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "Staff L thumb", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "Staff L index finger", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "staff L forearm", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_heatsource, + }, + { + "pred_hud", + "Staff L bicep", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "Staff R palm", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "Staff R little finger", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "Staff R mid finger", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "Staff R ring finger", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "Staff R thumb", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "Staff R index finger", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + { + "pred_hud", + "staff R forearm", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_heatsource, + }, + { + "pred_hud", + "Staff R bicep", + NULL, + { + 100, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 0, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_affectedbyheat, + }, + /* XENOBORG */ + { + "hnpc_xenoborg", + "pelvis presley", + NULL, + { + 400, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "right thigh", + NULL, + { + 270, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_right_leg|section_has_sparkoflife|section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "right shin", + NULL, + { + 270, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_right_leg|section_has_sparkoflife|section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "right foot", + NULL, + { + 270, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_right_foot|section_has_sparkoflife|section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "left thigh", + NULL, + { + 270, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_left_leg|section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "left shin", + NULL, + { + 270, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_left_leg|section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "left foot", + NULL, + { + 270, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_left_foot|section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "left foot", + NULL, + { + 270, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_left_foot|section_has_sparkoflife|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "tail a", + NULL, + { + 50, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_tail|section_flag_nofurthergibbing|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "tail b", + NULL, + { + 50, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_tail|section_flag_nofurthergibbing|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "tail c", + NULL, + { + 50, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_tail|section_flag_nofurthergibbing|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "tail d", + NULL, + { + 50, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_tail|section_flag_nofurthergibbing|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "tail e", + NULL, + { + 50, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_tail|section_flag_nofurthergibbing|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "tail f", + NULL, + { + 50, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_tail|section_flag_nofurthergibbing|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "tail g", + NULL, + { + 50, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_tail|section_flag_nofurthergibbing|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "tail h", + NULL, + { + 50, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_tail|section_flag_nofurthergibbing|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "tail i", + NULL, + { + 50, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_tail|section_flag_nofurthergibbing|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "tummy", + NULL, + { + 470, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid|section_flag_never_frag, + }, + { + "hnpc_xenoborg", + "chest", + NULL, + { + 500, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid|section_flag_never_frag, + }, + { + "hnpc_xenoborg", + "back pac", + NULL, + { + 400, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "exhaust", + NULL, + { + 80, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "pipe", + NULL, + { + 50, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "shunt a", + NULL, + { + 20, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "piss a", + NULL, + { + 20, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "shunt b", + NULL, + { + 20, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "piss b", + NULL, + { + 20, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "shunt c", + NULL, + { + 20, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "piss c", + NULL, + { + 20, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "shunt d", + NULL, + { + 20, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "piss d", + NULL, + { + 20, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "right bicep", + NULL, + { + 220, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_right_arm|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "right forearm", + NULL, + { + 220, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_right_arm|section_sprays_acid, + }, + { + "hnpc_xenoborg", + "left bicep", + NULL, + { + 220, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_left_arm|section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "left forearm", + NULL, + { + 220, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_left_arm|section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "neck", + NULL, + { + 190, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "head", + NULL, + { + 400, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_flag_head|section_has_sparkoflife, /* No longer sprays acid. */ + }, + { + "hnpc_xenoborg", + "sights", + NULL, + { + 50, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "jaw", + NULL, + { + 50, /* Health */ + 120, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_sparks, + }, + { + "hnpc_xenoborg", + "led", + NULL, + { + 20, /* Health */ + 20, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_sparks, + }, + /* Sentry Gun */ + { + "sentry", + "legs", + NULL, + { + 50, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_sparks, + }, + { + "sentry", + "pivot", + NULL, + { + 50, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_sparks, + }, + { + "sentry", + "gun", + NULL, + { + 50, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_sparks, + }, + /* Queen! */ + { + "queen", + "chest", + NULL, + { + 500*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "pelvis", + NULL, + { + 500*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "l00 tail", + NULL, + { + 20*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "l01 tail", + NULL, + { + 20*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "l02 tail", + NULL, + { + 20*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "l03 tail", + NULL, + { + 20*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "l04 tail", + NULL, + { + 20*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "l05 tail", + NULL, + { + 20*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "l06 tail", + NULL, + { + 20*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "l07 tail", + NULL, + { + 20*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "l08 tail", + NULL, + { + 20*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "l09 tail", + NULL, + { + 20*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "l10 tail", + NULL, + { + 20*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "l11 tail", + NULL, + { + 20*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "tummy", + NULL, + { + 500*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "right bicep", + NULL, + { + 300*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "right fore arm", + NULL, + { + 300*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "right hand", + NULL, + { + 300*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "r fing", + NULL, + { + 20*8, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "rr fing", + NULL, + { + 20*8, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "rrr fing", + NULL, + { + 20*8, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "rrrr fing", + NULL, + { + 20*8, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "rrrrr fing", + NULL, + { + 20*8, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "rrrrrr fing", + NULL, + { + 20*8, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "left bicep", + NULL, + { + 300*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "left fore arm", + NULL, + { + 300*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "left hand", + NULL, + { + 300*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "l fing", + NULL, + { + 20*8, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "ll fing", + NULL, + { + 20*8, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "lll fing", + NULL, + { + 20*8, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "llll fing", + NULL, + { + 20*8, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "lllll fing", + NULL, + { + 20*8, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "llllll fing", + NULL, + { + 20*8, /* Health */ + 100, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + + { + "queen", + "right thigh", + NULL, + { + 400*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "right shin", + NULL, + { + 400*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "right bird", + NULL, + { + 400*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "right foot", + NULL, + { + 400*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "left thigh", + NULL, + { + 400*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "left shin", + NULL, + { + 400*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "left bird", + NULL, + { + 400*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "left foot", + NULL, + { + 400*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "lbx", + NULL, + { + 50*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "lfx", + NULL, + { + 50*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "lhx", + NULL, + { + 50*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "rbx", + NULL, + { + 50*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "rfx", + NULL, + { + 50*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "rhx", + NULL, + { + 50*8, /* Health */ + 500, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "s", + NULL, + { + 10*8, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "ss", + NULL, + { + 10*8, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "sss", + NULL, + { + 10*8, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "ssss", + NULL, + { + 10*8, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "sssss", + NULL, + { + 10*8, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "ssssss", + NULL, + { + 10*8, /* Health */ + 50, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "neck", + NULL, + { + 500*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "pippa", + NULL, + { + 500*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "face", + NULL, + { + 200*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_has_sparkoflife|section_sprays_acid|section_flag_never_frag, + }, + { + "queen", + "jaw", + NULL, + { + 50*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + }, + { + "queen", + "luke", + NULL, + { + 100*8, /* Health */ + 1000, /* Armour */ + 0, /* IsOnFire */ + { + 1, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + section_sprays_acid, + + }, + /* Terminator. */ + { + NULL, + NULL, + NULL, + { + 0, /* Health */ + 0, /* Armour */ + 0, /* IsOnFire */ + { + 0, /* Acid Resistant */ + 0, /* Fire Resistant */ + 0, /* Electric Resistant */ + 1, /* Perfect Armour */ + 0, /* Electric Sensitive */ + 0, /* Combustability */ + 0, /* Indestructable */ + }, + }, + 0, + }, +}; + +SECTION_ATTACHMENT *GetThisSectionAttachment(char *riffname,char *section_name,char *hierarchy_name) { + + int a; + SECTION_ATTACHMENT *result; + + a=0; + result=NULL; + + if (riffname==NULL) return(NULL); + if (section_name==NULL) return(NULL); + + while (Global_Section_Attachments[a].Riffname!=NULL) { + if (strcmp(riffname,Global_Section_Attachments[a].Riffname)==0) { + if (strcmp(section_name,Global_Section_Attachments[a].Section_Name)==0) { + /* If hierarchy_name is provided, it must match. */ + if (hierarchy_name) { + if (Global_Section_Attachments[a].Hierarchy_Name) { + char **this_name; + /* Now, this is an array... */ + this_name=Global_Section_Attachments[a].Hierarchy_Name; + while (*this_name) { + if (strcmp(hierarchy_name,(*this_name))==0) { + result=&Global_Section_Attachments[a]; + break; + } + this_name++; + } + } + } else { + result=&Global_Section_Attachments[a]; + break; + } + } + } + a++; + } + + return(result); + +} + diff --git a/3dc/avp/TRIGGERS.C b/3dc/avp/TRIGGERS.C new file mode 100644 index 0000000..86122a4 --- /dev/null +++ b/3dc/avp/TRIGGERS.C @@ -0,0 +1,192 @@ +/*KJL*********************************************************************** +* I know "triggers.c" is a strange name, but I did write this on a Monday. * +***********************************************************************KJL*/ +#include "3dc.h" +#include "inline.h" +#include "module.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "dynblock.h" +#include "bh_types.h" +#include "huddefs.h" +#include "triggers.h" +#include "pldnet.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +/* in mm */ +#define ACTIVATION_Z_RANGE 3000 +#define ACTIVATION_X_RANGE 1000 +#define ACTIVATION_Y_RANGE 1000 + + +extern int NumOnScreenBlocks; +extern DISPLAYBLOCK *OnScreenBlockList[]; +extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + + +void OperateObjectInLineOfSight(void) +{ + int numberOfObjects = NumOnScreenBlocks; + + DISPLAYBLOCK *nearestObjectPtr=0; + int nearestMagnitude=ACTIVATION_X_RANGE*ACTIVATION_X_RANGE + ACTIVATION_Y_RANGE*ACTIVATION_Y_RANGE; + + while (numberOfObjects) + { + DISPLAYBLOCK* objectPtr = OnScreenBlockList[--numberOfObjects]; + GLOBALASSERT(objectPtr); + + /* does object have a strategy block? */ + if (objectPtr->ObStrategyBlock) + { + AVP_BEHAVIOUR_TYPE behaviour = objectPtr->ObStrategyBlock->I_SBtype; + + /* is it operable? */ + if( (I_BehaviourBinarySwitch == behaviour) + ||(I_BehaviourLinkSwitch == behaviour) + ||(I_BehaviourAutoGun == behaviour) + ||(I_BehaviourDatabase == behaviour) ) + { + /* is it in range? */ + if (objectPtr->ObView.vz > 0 && objectPtr->ObView.vz < ACTIVATION_Z_RANGE) + { + int absX = objectPtr->ObView.vx; + int absY = objectPtr->ObView.vy; + + if (absX<0) absX=-absX; + if (absY<0) absY=-absY; + + if (absX < ACTIVATION_X_RANGE && absY < ACTIVATION_Y_RANGE) + { + int magnitude = (absX*absX + absY*absY); + + if (nearestMagnitude > magnitude) + { + nearestMagnitude = magnitude; + nearestObjectPtr = objectPtr; + } + } + } + } + } + } + + /* if we found a suitable object, operate it */ + if (nearestObjectPtr) + { + //only allow activation if you have a line of sight to the switch + //allow the switch to be activated anyway for the moment + if(IsThisObjectVisibleFromThisPosition_WithIgnore(Player,nearestObjectPtr,&nearestObjectPtr->ObWorld,10000)) + { + switch(nearestObjectPtr->ObStrategyBlock->I_SBtype) + { + case I_BehaviourBinarySwitch: + { + #if SupportWindows95 + if(AvP.Network!=I_No_Network) + { + AddNetMsg_LOSRequestBinarySwitch(nearestObjectPtr->ObStrategyBlock); + } + #endif + RequestState(nearestObjectPtr->ObStrategyBlock,1, 0); + break; + } + case I_BehaviourLinkSwitch: + { + if(AvP.Network!=I_No_Network) + { + AddNetMsg_LOSRequestBinarySwitch(nearestObjectPtr->ObStrategyBlock); + } + RequestState(nearestObjectPtr->ObStrategyBlock,1, 0); + break; + } + case I_BehaviourAutoGun: + { + RequestState(nearestObjectPtr->ObStrategyBlock,1, 0); + break; + } + case I_BehaviourDatabase: + { + #if PC_E3DEMO||PSX_DEMO + /* KJL 10:56:39 05/28/97 - E3DEMO change */ + /* KJL 10:55:44 05/28/97 - display 'Access Denied' message */ + NewOnScreenMessage(GetTextString(TEXTSTRING_DB_ACCESSDENIED)); + #else + AvP.GameMode = I_GM_Menus; + + #if PSX + { + extern int Global_Database_Num; + Global_Database_Num=((DATABASE_BLOCK *)nearestObjectPtr->ObStrategyBlock->SBdataptr)->num; + } + #else + AvP.DatabaseAccessNum=((DATABASE_BLOCK *)nearestObjectPtr->ObStrategyBlock->SBdataptr)->num; + #endif + + + /* KJL 16:43:01 03/19/97 - CHANGE ME! Need to pass database number */ + // RJHG - would be ((*DATABASEBLOCK)nearestObjectPtr->ObStrategyBlock->SBDataPtr)->num + // CDF - I think it would be ((DATABASE_BLOCK *)nearestObjectPtr->ObStrategyBlock->SBdataptr)->num + #endif + + break; + } + default: + break; + } + } + } + + return; +} + + +BOOL AnythingInMyModule(MODULE* my_mod) +{ + + // simple overlap test + + + // this used within level - find objects in module + // all will have sbs + + int i; + int max_x, min_x, max_y, min_y, max_z, min_z; + + max_x = my_mod->m_maxx + my_mod->m_world.vx; + min_x = my_mod->m_minx + my_mod->m_world.vx; + max_y = my_mod->m_maxy + my_mod->m_world.vy; + min_y = my_mod->m_miny + my_mod->m_world.vy; + max_z = my_mod->m_maxz + my_mod->m_world.vz; + min_z = my_mod->m_minz + my_mod->m_world.vz; + + + for(i = 0; i < NumActiveStBlocks; i++) + { + VECTORCH obj_world; + STRATEGYBLOCK *sbptr; + DYNAMICSBLOCK *dynptr; + + sbptr = ActiveStBlockList[i]; + + if(!(dynptr = sbptr->DynPtr)) + continue; + + obj_world = dynptr->Position; + + if(obj_world.vx < max_x) + if(obj_world.vx > min_x) + if(obj_world.vz < max_z) + if(obj_world.vz > min_z) + if(obj_world.vy < max_y) + if(obj_world.vy > min_y) + { + return(1); + } + } + + return(0); +} \ No newline at end of file diff --git a/3dc/avp/TRIGGERS.H b/3dc/avp/TRIGGERS.H new file mode 100644 index 0000000..783191d --- /dev/null +++ b/3dc/avp/TRIGGERS.H @@ -0,0 +1,2 @@ +extern void OperateObjectInLineOfSight(void); +extern BOOL AnythingInMyModule(MODULE* my_mod); \ No newline at end of file diff --git a/3dc/avp/WEAPONS.H b/3dc/avp/WEAPONS.H new file mode 100644 index 0000000..f79f22f --- /dev/null +++ b/3dc/avp/WEAPONS.H @@ -0,0 +1,121 @@ +/*KJL*********************************************************************** +* WEAPONS.H * +* - this file contains prototypes for the functions in weapons.c * +* which can be called externally. * +***********************************************************************KJL*/ +#ifndef _weapons_h_ + #define _weapons_h_ 1 + + + #ifdef __cplusplus + + extern "C" { + + #endif + + +/*KJL**************************************************************************************** +* D E F I N E S * +****************************************************************************************KJL*/ + +typedef enum HitAreaMatrix { + HAM_Centre = 0, + HAM_Front, + HAM_Back, + HAM_Top, + HAM_Base, + HAM_Left, + HAM_Right, + HAM_TopLeft, + HAM_TopRight, + HAM_BaseLeft, + HAM_BaseRight, + HAM_end, +} HITAREAMATRIX; + +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ +extern void UpdateWeaponStateMachine(void); + +extern int AreTwoPistolsInTertiaryFire(void); + +extern void HandleEffectsOfExplosion(STRATEGYBLOCK *objectToIgnorePtr, VECTORCH *centrePtr, int maxRange, DAMAGE_PROFILE *maxDamage, int flat); +/*KJL******************************************************************************* +* centrePtr - is a pointer to the explosion's position vector in world space. * +* * +* maxRange - is the distance away from the explosion's centre an object has to be * +* for no damage to be incurred. * +* * +* maxDamage - is the damage an object would incur if it were zero distance away * +* from the explosion. * +*******************************************************************************KJL*/ + + +extern void FireAutoGun(STRATEGYBLOCK *sbPtr); +/*KJL******** +* bang bang * +********KJL*/ + +extern void MakeMatrixFromDirection(VECTORCH *directionPtr, MATRIXCH *matrixPtr); +/*KJL****************************************************************************** +* directionPtr - is a pointer to a NORMALISED vector in world space (input) * +* matrixPtr - is a pointer to a matrix that will contain the function's output * +* * +* * +* The output matrix is the OrientMat an object would have if it were pointing in * +* in the given direction. * +******************************************************************************KJL*/ + + + +extern void UpdateWeaponShape(void); +/*KJL********************************************** +* Call UpdateWeaponShape on changing environment. * +**********************************************KJL*/ + +extern void GrabWeaponShape(PLAYER_WEAPON_DATA *weaponPtr); +extern void GrabMuzzleFlashShape(TEMPLATE_WEAPON_DATA *twPtr); +extern void FindEndOfShape(VECTORCH* endPositionPtr, int shapeIndex); +extern void InitThisWeapon(PLAYER_WEAPON_DATA *pwPtr); + +extern void CauseDamageToObject(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple,VECTORCH *incoming); +extern DISPLAYBLOCK *CauseDamageToHModel(HMODELCONTROLLER *HMC_Ptr, STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, SECTION_DATA *this_section_data, VECTORCH *incoming, VECTORCH *position, int FromHost); +extern int TotalKineticDamage(DAMAGE_PROFILE *damage); +extern void GetDirectionOfAttack(STRATEGYBLOCK *sbPtr,VECTORCH *WorldVector,VECTORCH *Output); +extern int Staff_Manager(DAMAGE_PROFILE *damage,SECTION_DATA *section1,SECTION_DATA *section2,SECTION_DATA *section3, + STRATEGYBLOCK *wielder); + +/* exported varibles */ +extern DISPLAYBLOCK PlayersWeapon; +extern DISPLAYBLOCK PlayersWeaponMuzzleFlash; +extern void PositionPlayersWeapon(void); +extern void PositionPlayersWeaponMuzzleFlash(void); +extern void AutoSwapToDisc(void); +extern void AutoSwapToDisc_OutOfSequence(void); + + +struct Target +{ + VECTORCH Position; + int Distance; + DISPLAYBLOCK *DispPtr; + SECTION_DATA *HModelSection; +}; + +extern struct Target PlayersTarget; +extern SECTION_DATA *HitLocationRoll(STRATEGYBLOCK *sbPtr, STRATEGYBLOCK *source); + +#define FORCE_MINIGUN_STOP 1 + +#define SPEARS_PER_PICKUP 30 +#define MAX_SPEARS 99 + + #ifdef __cplusplus + + } + + #endif + + +#endif diff --git a/3dc/avp/Weapons.c b/3dc/avp/Weapons.c new file mode 100644 index 0000000..de228e6 --- /dev/null +++ b/3dc/avp/Weapons.c @@ -0,0 +1,12210 @@ +/*KJL****************************************************************** +* weapon.c - this is home to the weapon state machine and related fns * +******************************************************************KJL*/ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "gameplat.h" + +#include "bh_types.h" +#include "inventry.h" +#include "comp_shp.h" +#include "load_shp.h" +#include "huddefs.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +#include "dynblock.h" +#include "dynamics.h" +#include "lighting.h" +#include "pvisible.h" +#include "bh_alien.h" +#include "bh_pred.h" +#include "bh_xeno.h" +#include "bh_paq.h" +#include "bh_queen.h" +#include "bh_fhug.h" +#include "bh_marin.h" +#include "bh_debri.h" +#include "bh_weap.h" +#include "bh_agun.h" +#include "bh_light.h" +#include "bh_corpse.h" +#include "bh_ais.h" +#include "weapons.h" +#include "avpview.h" + +#include "psnd.h" +#include "vision.h" +#include "plat_shp.h" + +#include "particle.h" +#include "psndproj.h" +#include "psndplat.h" +#include "showcmds.h" + +/* for win 95 net support */ +#if SupportWindows95 +#include "pldghost.h" +#include "pldnet.h" +#endif + +#include "los.h" +#include "kshape.h" +#include "targeting.h" +#include "extents.h" +#include "scream.h" +#include "AvP_UserProfile.h" + +#define BITE_HEALTH_RECOVERY (50) +#define BITE_ARMOUR_RECOVERY (30) +#define PULSERIFLE_MINIMUM_BURST (4) +#define SMARTGUN_MINIMUM_BURST (8) + +#define MEDICOMP_USE_THRESHOLD (10*ONE_FIXED) +#define MEDICOMP_DRAIN_BLOCK ((10*ONE_FIXED)-1) +#define EXTINGUISHER_USE_THRESHOLD (3*ONE_FIXED) +#define EXTINGUISHER_DRAIN_BLOCK (3*ONE_FIXED) +#define GREENFLASH_INTENSITY (5*ONE_FIXED) + +#define CASTER_CHARGERATIO (2) +/* Was 3... */ + +#define PRED_PISTOL_SECONDARY_FIRE_CHARGE (ONE_FIXED<<1) + +#define QUIRKAFLEEG 0 +/* That turns on medicomp ammo. Private joke. :-) */ + +/*KJL**************************************************************************************** +* G L O B A L S * +****************************************************************************************KJL*/ + +static char tempstring[256]; + +static int WBStrikeTime=(ONE_FIXED>>1); +static int ACStrikeTime=(ONE_FIXED/6); +int AutoSwap=-1; + +int PredPistol_ShotCost=120000; /* Changed from 60000 (Fox value), 1/3/99 */ +int Caster_Jumpstart=10000; +int Caster_Chargetime=150000; +int Caster_ChargeRatio=400000; +int Caster_TrickleRate=0; +int Caster_TrickleLevel=16384; +int Caster_MinCharge=0; + +int Caster_NPCKill=16384; +int Caster_PCKill=49151; + +static int AC_Speed_Factor=ONE_FIXED; +int Alien_Visible_Weapon; +static int Alien_Tail_Clock; +static int Wristblade_StrikeType; +STRATEGYBLOCK *Alien_Tail_Target; +char Alien_Tail_Target_SBname[SB_NAME_LENGTH]; + +static DAMAGE_PROFILE Player_Weapon_Damage; + +extern SOUND3DDATA Explosion_SoundData; + +extern DISPLAYBLOCK* Player; +extern int NormalFrameTime; +extern unsigned char Null_Name[8]; +extern int ShowPredoStats; +extern int playerNoise; +extern int PlayerDamagedOverlayIntensity; + +extern int NumOnScreenBlocks; +extern int NumActiveBlocks; +extern DISPLAYBLOCK *OnScreenBlockList[]; +extern DISPLAYBLOCK *ActiveBlockList[]; +extern DISPLAYBLOCK *SmartTarget_Object; +extern int HtoHStrikes; +extern int weaponHandle; +extern int predHUDSoundHandle; +extern ACTIVESOUNDSAMPLE ActiveSounds[]; +extern NETGAME_GAMEDATA netGameData; + +int WeaponFidgetPlaying; +int Old_Minigun_SpinSpeed; +int Minigun_SpinSpeed; +int Weapon_ThisBurst; +EULER Minigun_MaxHeadJolt; +EULER Minigun_HeadJolt; +int Flamethrower_Timer; + +SECTION_DATA *PlayerStaff1=NULL; +SECTION_DATA *PlayerStaff2=NULL; +SECTION_DATA *PlayerStaff3=NULL; +int StaffAttack=-1; +STRATEGYBLOCK *Biting; +char Biting_SBname[SB_NAME_LENGTH]; +int Bit=0; + +extern int Validate_Target(STRATEGYBLOCK *target,char *SBname); + +extern MODULEMAPBLOCK * MakeDefaultModuleMapblock(); +extern void InitialiseEnergyBoltBehaviour(DAMAGE_PROFILE *damage,int factor); +extern void PredDisc_GetFirstTarget(PC_PRED_DISC_BEHAV_BLOCK *bptr, DISPLAYBLOCK *target, VECTORCH *position); +extern void InitialiseDiscBehaviour(STRATEGYBLOCK *target,SECTION_DATA *disc_section); +extern int Validate_Target(STRATEGYBLOCK *target,char *SBname); +extern int playerNoise; +extern int SlotForThisWeapon(enum WEAPON_ID weaponID); +extern void MakeBloodExplosion(VECTORCH *originPtr, int creationRadius, VECTORCH *blastPositionPtr, int noOfParticles, enum PARTICLE_ID particleID); +extern HIERARCHY_SHAPE_REPLACEMENT* GetHierarchyAlternateShapeSetFromLibrary(const char* rif_name,const char* shape_set_name); +extern void Crunch_Position_For_Players_Weapon(VECTORCH *position); +extern DISPLAYBLOCK *MakePistolCasing(VECTORCH *position,MATRIXCH *orient); + +int FriendlyFireDamageFilter(DAMAGE_PROFILE *damage); +static void MarineZeroAmmoFunctionality(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr); +static void PredatorZeroAmmoFunctionality(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr); + +/* Line Of Sight information used by FireLineOfSightWeapon() */ +VECTORCH LOS_Point; /* point in world space which player has hit */ +int LOS_Lambda; /* distance in mm to point from player */ +DISPLAYBLOCK* LOS_ObjectHitPtr; /* pointer to object that was hit */ +VECTORCH LOS_ObjectNormal; /* normal of the object's face which was hit */ +SECTION_DATA* LOS_HModel_Section; /* Section of HModel hit */ + + +/* unnormalised vector in the direction which the gun's muzzle is pointing, IN VIEW SPACE */ +/* very useful when considering sprites, which lie in a z-plane in view space */ +VECTORCH GunMuzzleDirectionInVS; + +VECTORCH PlayerGunBarrelOffset; + +/* dir gun is pointing, normalised and in world space */ +VECTORCH GunMuzzleDirectionInWS; + +DISPLAYBLOCK PlayersWeapon; +DISPLAYBLOCK PlayersWeaponMuzzleFlash; +HMODELCONTROLLER PlayersWeaponHModelController; +SECTION_DATA *PWMFSDP; /* PlayersWeaponMuzzleFlashSectionDataPointer */ +VECTORCH PlayersWeaponCameraOffset; + +struct Target PlayersTarget; + +int GrenadeLauncherSelectedAmmo; +int LastHand; // For alien claws and two pistols + +char *GrenadeLauncherBulletNames[6] = { + "bulletF", //05_ + "bulletA", //_ + "bulletB", //01_ + "bulletC", //02_ + "bulletD", //03_ + "bulletE", //04_ +}; + +enum WEAPON_ID MarineWeaponHierarchy[] = { + + WEAPON_PULSERIFLE, + WEAPON_SMARTGUN, + WEAPON_TWO_PISTOLS, + WEAPON_MARINE_PISTOL, + WEAPON_MINIGUN, + WEAPON_FLAMETHROWER, + WEAPON_GRENADELAUNCHER, + WEAPON_SADAR, + WEAPON_FRISBEE_LAUNCHER, + WEAPON_CUDGEL, + NULL_WEAPON + +}; + +enum WEAPON_ID PredatorWeaponHierarchy[] = { + + WEAPON_PRED_RIFLE, + WEAPON_PRED_WRISTBLADE, + NULL_WEAPON + +}; + +extern void CastLOSSpear(STRATEGYBLOCK *sbPtr, VECTORCH *muzzlepos, VECTORCH *in_shotvector, enum AMMO_ID AmmoID, int multiple, int inaccurate); + +VECTORCH SpreadfireSpears[] = { + {0,0, 600,}, + {100,0, 600,}, + {-100,0,600,}, + {50,0, 600,}, + {-50,0, 600,}, + {25,50, 600,}, + {-25,50,600,}, + {75,50, 600,}, + {-75,50,600,}, + {25,-50,600,}, + {-25,-50,600,}, + {75,-50,600,}, + {-75,-50,600,}, + {-1,-1,-1,}, +}; + +SECTION_DATA *GrenadeLauncherSectionPointers[6]; + +/* Used to calculate the damage of one projectile due to FRI + Only used by the flamethrower at the moment */ +int ProjectilesFired; + +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ +extern void DoShapeAnimation (DISPLAYBLOCK * dptr); +void FindHitArea(DISPLAYBLOCK *dptr); +DISPLAYBLOCK *HtoHDamageToHModel(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, STRATEGYBLOCK *source, VECTORCH *attack_dir); +DISPLAYBLOCK *AlienTail_TargetSelect(void); +STRATEGYBLOCK *GetBitingTarget(void); +SECTION_DATA *CheckBiteIntegrity(void); +/* Yes, whatever, but this was LESS TEDIOUS! */ +STRATEGYBLOCK *GetTrophyTarget(SECTION_DATA **head_section_data); + +extern void PlayerIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiplier,VECTORCH* incoming); + +void UpdateWeaponStateMachine(void); +void HandleSpearImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *this_section_data); +static void WeaponStateIdle(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr,TEMPLATE_WEAPON_DATA *twPtr, int justfiredp,int justfireds, int ps); +static int RequestChangeOfWeapon(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr); +void ChangeHUDToAlternateShapeSet(char *riffname,char *setname); + + + +static void StateDependentMovement(PLAYER_STATUS *playerStatusPtr, PLAYER_WEAPON_DATA *weaponPtr); + +int FireAutomaticWeapon(PLAYER_WEAPON_DATA *weaponPtr); +int FireNonAutomaticWeapon(PLAYER_WEAPON_DATA *weaponPtr); +int FireNonAutomaticSecondaryAmmo(PLAYER_WEAPON_DATA *weaponPtr); +int GrenadeLauncherChangeAmmo(PLAYER_WEAPON_DATA *weaponPtr); +int PredDiscChangeMode(PLAYER_WEAPON_DATA *weaponPtr); +int SmartgunSecondaryFire(PLAYER_WEAPON_DATA *weaponPtr); +int DamageObjectInLineOfSight(PLAYER_WEAPON_DATA *weaponPtr); +int MeleeWeapon_180Degree_Front(PLAYER_WEAPON_DATA *weaponPtr); +int MeleeWeapon_90Degree_Front(PLAYER_WEAPON_DATA *weaponPtr); +int FireEmptyMinigun(PLAYER_WEAPON_DATA *weaponPtr); + +int Staff_Manager(DAMAGE_PROFILE *damage,SECTION_DATA *section1,SECTION_DATA *section2,SECTION_DATA *section3, + STRATEGYBLOCK *wielder); + +static void FireLineOfSightAmmo(enum AMMO_ID AmmoID, VECTORCH* sourcePtr, VECTORCH* directionPtr, int multiple); +static void PlayerFireLineOfSightAmmo(enum AMMO_ID AmmoID, int multiple); +extern void FireProjectileAmmo(enum AMMO_ID AmmoID); + +void HandleWeaponImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *section_pointer); + + +void FireAutoGun(STRATEGYBLOCK *sbPtr); +void MakeMatrixFromDirection(VECTORCH *directionPtr, MATRIXCH *matrixPtr); +void FindEndOfShape(VECTORCH* endPositionPtr, int shapeIndex); +static void CalculateTorque(EULER *rotationPtr, VECTORCH *directionPtr, STRATEGYBLOCK *sbPtr); +static void CalculateTorqueAtPoint(EULER *rotationPtr, VECTORCH *pointPtr, STRATEGYBLOCK *sbPtr); + +void PositionPlayersWeaponMuzzleFlash(void); + +void MeleeWeaponNullTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); + +void AlienClawTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +void AlienClawEndTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +void AlienTailTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); + +void PredWristbladeTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +void PredDiscThrowTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); + +void ParticleBeamSwapping(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +void ParticleBeamReadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +void ParticleBeamUnreadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); + +void InitThisWeapon(PLAYER_WEAPON_DATA *pwPtr); + +static int RequestChangeOfWeaponWhilstSwapping(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr); + +static void DamageDamageBlock(DAMAGEBLOCK *DBPtr, DAMAGE_PROFILE *damage, int multiple); +DISPLAYBLOCK *CauseDamageToHModel(HMODELCONTROLLER *HMC_Ptr, STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, SECTION_DATA *this_section_data,VECTORCH *incoming, VECTORCH *position, int FromHost); +#if 0 +void WeaponCreateStartFrame(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr); +#endif +int PC_Alien_Eat_Attack(int hits); +int FirePredatorDisc(PLAYER_WEAPON_DATA *weaponPtr,SECTION_DATA *disc_section); + +void SmartTarget_GetCofM(DISPLAYBLOCK *target,VECTORCH *viewSpaceOutput); + +void BiteAttack_AwardHealth(STRATEGYBLOCK *sbPtr,AVP_BEHAVIOUR_TYPE pre_bite_type); +void LimbRip_AwardHealth(void); +void GrenadeLauncher_EmergencyChangeAmmo(PLAYER_WEAPON_DATA *weaponPtr); +int AccuracyStats_TargetFilter(STRATEGYBLOCK *sbPtr); + +#define Random16BitNumber (FastRandom()&65535) +/*KJL**************************************************************************************** +* F U N C T I O N S * +****************************************************************************************KJL*/ + +int Predator_WantToChangeWeapon(PLAYER_STATUS *playerStatusPtr, PLAYER_WEAPON_DATA *weaponPtr) { + + if (( + (weaponPtr->PrimaryRoundsRemaining==0 && weaponPtr->PrimaryMagazinesRemaining==0) + && (weaponPtr->WeaponIDNumber!=WEAPON_PRED_WRISTBLADE) + && (weaponPtr->WeaponIDNumber!=WEAPON_PRED_STAFF) + && (weaponPtr->WeaponIDNumber!=WEAPON_PRED_MEDICOMP) + )||( + (AvP.PlayerType==I_Predator)&&(weaponPtr->WeaponIDNumber==WEAPON_PRED_SHOULDERCANNON) + &&(playerStatusPtr->PlasmaCasterChargeFieldChargePlasmaCasterCharge),Caster_ChargeRatio)) + )||( + (AvP.PlayerType==I_Predator)&&(weaponPtr->WeaponIDNumber==WEAPON_PRED_PISTOL) + &&(playerStatusPtr->FieldChargeWeaponSlot[slot]); + + switch (this_weaponPtr->WeaponIDNumber) { + default: + { + return(0); + } + break; + case WEAPON_PRED_WRISTBLADE: + case WEAPON_PRED_STAFF: + { + return(1); + } + break; + case WEAPON_PRED_MEDICOMP: + { + if ((playerStatusPtr->FieldChargeFieldChargePrimaryRoundsRemaining==0 && this_weaponPtr->PrimaryMagazinesRemaining==0) { + return(0); + } else { + return(1); + } + } + break; + case WEAPON_PRED_PISTOL: + { + if (playerStatusPtr->FieldChargePlasmaCasterChargeFieldChargePlasmaCasterCharge),Caster_ChargeRatio))) { + return(0); + } else { + return(1); + } + } + break; + } + } + + return(0); +} + +int Marine_WantToChangeWeapon(PLAYER_WEAPON_DATA *weaponPtr) { + + if (((weaponPtr->SecondaryRoundsRemaining==0 && weaponPtr->SecondaryMagazinesRemaining==0) + && (weaponPtr->PrimaryRoundsRemaining==0 && weaponPtr->PrimaryMagazinesRemaining==0)) + || (weaponPtr->WeaponIDNumber==WEAPON_CUDGEL)) { + return(1); + } + return(0); +} + +int WeaponHasAmmo(int slot) { + + if (slot!=-1) { + PLAYER_WEAPON_DATA *this_weaponPtr; + + this_weaponPtr = &(PlayerStatusPtr->WeaponSlot[slot]); + + if ((this_weaponPtr->SecondaryRoundsRemaining!=0 || this_weaponPtr->SecondaryMagazinesRemaining!=0) + || (this_weaponPtr->PrimaryRoundsRemaining!=0 || this_weaponPtr->PrimaryMagazinesRemaining!=0) + || (this_weaponPtr->WeaponIDNumber==WEAPON_CUDGEL) + || ( + (this_weaponPtr->WeaponIDNumber==WEAPON_GRENADELAUNCHER) + && ( + (GrenadeLauncherData.ProximityRoundsRemaining!=0) + ||(GrenadeLauncherData.FragmentationRoundsRemaining!=0) + ||(GrenadeLauncherData.StandardRoundsRemaining!=0) + ||(GrenadeLauncherData.ProximityMagazinesRemaining!=0) + ||(GrenadeLauncherData.FragmentationMagazinesRemaining!=0) + ||(GrenadeLauncherData.StandardMagazinesRemaining!=0) + ) + ) + ) { + return(1); + } + } + return(0); +} + +int SimilarPredWeapons(PLAYER_WEAPON_DATA *nwp,PLAYER_WEAPON_DATA *owp) { + + if ((nwp->WeaponIDNumber==WEAPON_PRED_WRISTBLADE) + ||(nwp->WeaponIDNumber==WEAPON_PRED_SHOULDERCANNON) + ||(nwp->WeaponIDNumber==WEAPON_PRED_MEDICOMP)) { + + if ((owp->WeaponIDNumber==WEAPON_PRED_WRISTBLADE) + ||(owp->WeaponIDNumber==WEAPON_PRED_SHOULDERCANNON) + ||(owp->WeaponIDNumber==WEAPON_PRED_MEDICOMP)) { + + if (nwp->WeaponIDNumber!=owp->WeaponIDNumber) { + return(1); + } + } + } + + return(0); + +} + +enum PARTICLE_ID GetBloodType(STRATEGYBLOCK *sbPtr) { + + enum PARTICLE_ID blood_type=PARTICLE_NULL; + + if (sbPtr==NULL) { + return(PARTICLE_NULL); + } + + switch (sbPtr->I_SBtype) { + default: + blood_type=PARTICLE_NULL; + break; + case I_BehaviourHierarchicalFragment: + { + HDEBRIS_BEHAV_BLOCK *debrisStatusPointer; + + debrisStatusPointer=(HDEBRIS_BEHAV_BLOCK *)(sbPtr->SBdataptr); + GLOBALASSERT(debrisStatusPointer); + + if (debrisStatusPointer->Android) { + blood_type=PARTICLE_ANDROID_BLOOD; + } else { + blood_type=PARTICLE_HUMAN_BLOOD; + } + } + break; + case I_BehaviourSpeargunBolt: + { + SPEAR_BEHAV_BLOCK *debrisStatusPointer; + + debrisStatusPointer=(SPEAR_BEHAV_BLOCK *)(sbPtr->SBdataptr); + GLOBALASSERT(debrisStatusPointer); + + if (debrisStatusPointer->Android) { + blood_type=PARTICLE_ANDROID_BLOOD; + } else { + blood_type=PARTICLE_HUMAN_BLOOD; + } + } + break; + case I_BehaviourMarine: + case I_BehaviourSeal: + { + MARINE_STATUS_BLOCK *marineStatusPointer; + + marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + GLOBALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android) { + blood_type=PARTICLE_ANDROID_BLOOD; + } else { + blood_type=PARTICLE_HUMAN_BLOOD; + } + } + break; + case I_BehaviourAlien: + case I_BehaviourQueenAlien: + blood_type=PARTICLE_ALIEN_BLOOD; + break; + case I_BehaviourPredator: + blood_type=PARTICLE_PREDATOR_BLOOD; + break; + case I_BehaviourXenoborg: + case I_BehaviourAutoGun: + blood_type=PARTICLE_SPARK; + break; + case I_BehaviourNetCorpse: + { + NETCORPSEDATABLOCK *corpseDataPtr; + + corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(corpseDataPtr); + + switch (corpseDataPtr->Type) { + default: + blood_type=PARTICLE_NULL; + break; + case I_BehaviourMarinePlayer : + case I_BehaviourMarine: + case I_BehaviourSeal: + if (corpseDataPtr->Android) { + blood_type=PARTICLE_ANDROID_BLOOD; + } else { + blood_type=PARTICLE_HUMAN_BLOOD; + } + break; + case I_BehaviourAlienPlayer : + case I_BehaviourAlien: + case I_BehaviourQueenAlien: + blood_type=PARTICLE_ALIEN_BLOOD; + break; + case I_BehaviourPredatorPlayer: + case I_BehaviourPredator: + blood_type=PARTICLE_PREDATOR_BLOOD; + break; + case I_BehaviourXenoborg: + case I_BehaviourAutoGun: + blood_type=PARTICLE_SPARK; + break; + } + + } + break; + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *corpseDataPtr; + corpseDataPtr=sbPtr->SBdataptr; + switch (corpseDataPtr->type) { + default: + blood_type=PARTICLE_NULL; + break; + case I_BehaviourMarinePlayer : + case I_BehaviourMarine: + case I_BehaviourSeal: + /* Add an Android test here? */ + blood_type=PARTICLE_HUMAN_BLOOD; + break; + case I_BehaviourAlienPlayer : + case I_BehaviourAlien: + case I_BehaviourQueenAlien: + blood_type=PARTICLE_ALIEN_BLOOD; + break; + case I_BehaviourPredatorPlayer: + case I_BehaviourPredator: + blood_type=PARTICLE_PREDATOR_BLOOD; + break; + case I_BehaviourXenoborg: + case I_BehaviourAutoGun: + blood_type=PARTICLE_SPARK; + break; + case I_BehaviourNetCorpse: + switch (corpseDataPtr->subtype) { + default: + blood_type=PARTICLE_NULL; + break; + case I_BehaviourMarinePlayer : + case I_BehaviourMarine: + case I_BehaviourSeal: + /* Add an Android test here? */ + blood_type=PARTICLE_HUMAN_BLOOD; + break; + case I_BehaviourAlienPlayer : + case I_BehaviourAlien: + case I_BehaviourQueenAlien: + blood_type=PARTICLE_ALIEN_BLOOD; + break; + case I_BehaviourPredatorPlayer: + case I_BehaviourPredator: + blood_type=PARTICLE_PREDATOR_BLOOD; + break; + case I_BehaviourXenoborg: + case I_BehaviourAutoGun: + blood_type=PARTICLE_SPARK; + break; + } + break; + } + } + break; + } + + return(blood_type); +} + +static int FirePrimaryLate,FireSecondaryLate; + +void UpdateWeaponStateMachine(void) +{ + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + int justfiredp,justfireds,ps; + + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + /* player's current weapon */ + GLOBALASSERT(playerStatusPtr->SelectedWeaponSlotMyFaceHugger) { + return; + } + + CurrentGameStats_UsingWeapon(playerStatusPtr->SelectedWeaponSlot); + + /* init a pointer to the weapon's data */ + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + + justfiredp=0; // Has the player just fired... + justfireds=0; // Has the player just fired... + ps=0; // If so, primary or secondary? For rapid fire recoil handling, in WeaponStateIdle. + + FirePrimaryLate=0; + FireSecondaryLate=0; + + /* Hack for autoswap commmands. */ + if (AutoSwap!=-1) { + PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo=(AutoSwap+1); + AutoSwap=-1; + } + + /* Player doesn't have a weapon! This will eventually be changed into an assertion + that the player *does* have a weapon */ + if (weaponPtr->WeaponIDNumber == NULL_WEAPON) + return; + + /* Player is dead. Weapon goes idle */ + if (!playerStatusPtr->IsAlive) + { + #if 0 + WeaponCreateStartFrame((void *)playerStatusPtr, weaponPtr); + #endif + + weaponPtr->CurrentState = WEAPONSTATE_IDLE; + weaponPtr->StateTimeOutCounter=0; + return; + } + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + CalculatePlayersTarget(twPtr,weaponPtr); + + playerStatusPtr->Encumberance=twPtr->Encum_Idle; //Default state + + textprint("Weapon State %d\n",weaponPtr->CurrentState); + textprint("Weapon_ThisBurst %d\n",Weapon_ThisBurst); + textprint("Primary Mags %d\n",weaponPtr->PrimaryMagazinesRemaining); + textprint("Primary Rounds %d\n",weaponPtr->PrimaryRoundsRemaining); + textprint("Players Target Distance %d\n",PlayersTarget.Distance); + #if 0 + textprint("Minigun_HeadJolt %d %d %d\n",Minigun_HeadJolt.EulerX,Minigun_HeadJolt.EulerY,Minigun_HeadJolt.EulerZ); + textprint("HeadOrientation %d %d %d\n",HeadOrientation.EulerX,HeadOrientation.EulerY,HeadOrientation.EulerZ); + textprint("ViewPanX %d\n",playerStatusPtr->ViewPanX); + #endif + + /* if weapon is not idle, evaluate any state changes required */ + if (WEAPONSTATE_IDLE!=weaponPtr->CurrentState) + { + /* Time out current weapon state */ + { + int timeOutRate = twPtr->TimeOutRateForState[weaponPtr->CurrentState]; + + if (WEAPONSTATE_INSTANTTIMEOUT==timeOutRate) + { + weaponPtr->StateTimeOutCounter=0; + } + else + { + weaponPtr->StateTimeOutCounter-=MUL_FIXED(timeOutRate,NormalFrameTime); + } + + } + if(weaponPtr->StateTimeOutCounter<=0) + { + WeaponFidgetPlaying=0; + /* It's the only way to be sure. */ + switch(weaponPtr->CurrentState) + { + case WEAPONSTATE_FIRING_PRIMARY: + { + if (twPtr->PrimaryIsMeleeWeapon) { + /* Melee weapons fire at the end of the 'firing' phase, in * + * addition to other special properties, like infinite ammo. */ + if (twPtr->FirePrimaryFunction!=NULL) { + if ((*twPtr->FirePrimaryFunction)(weaponPtr)) { + /* Er... well done. */ + /* It might be important to put something here, okay? */ + /* Till then, this will be compiled out. */ + } + } + } + + if (twPtr->PrimaryIsRapidFire) + { + /* after shooting weapon goes straight to idle state */ + weaponPtr->CurrentState = WEAPONSTATE_IDLE; + justfiredp=weaponPtr->StateTimeOutCounter+1; + ps=1; + weaponPtr->StateTimeOutCounter=0; + } + else + { + /* there is a 'recovery' time after shooting */ + weaponPtr->CurrentState = WEAPONSTATE_RECOIL_PRIMARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + + playerStatusPtr->Encumberance=twPtr->Encum_FirePrime; + + break; + } + case WEAPONSTATE_FIRING_SECONDARY: + { + + if (twPtr->SecondaryIsMeleeWeapon) { + /* Melee weapons fire at the end of the 'firing' phase, in * + * addition to other special properties, like infinite ammo. */ + if (twPtr->FireSecondaryFunction!=NULL) { + if ((*twPtr->FireSecondaryFunction)(weaponPtr)) { + /* Er... well done. */ + /* It might be important to put something here, okay? */ + /* Till then, this will be compiled out. */ + } + } + } + + if (twPtr->SecondaryIsRapidFire) + { + /* after shooting weapon goes straight to idle state */ + weaponPtr->CurrentState = WEAPONSTATE_IDLE; + justfireds=weaponPtr->StateTimeOutCounter+1; + ps=2; + weaponPtr->StateTimeOutCounter=0; + } + else + { + /* there is a 'recovery' time after shooting */ + weaponPtr->CurrentState = WEAPONSTATE_RECOIL_SECONDARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + + playerStatusPtr->Encumberance=twPtr->Encum_FireSec; + + break; + } + + case WEAPONSTATE_RELOAD_PRIMARY: + { + /* load a new magazine */ + TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->PrimaryAmmoID]; + if (weaponPtr->PrimaryRoundsRemaining==0) { + if (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS) { + /* Two pistols reloads BOTH primary and secondary. */ + if (weaponPtr->PrimaryMagazinesRemaining) { + weaponPtr->PrimaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine; + weaponPtr->PrimaryMagazinesRemaining--; + } + if (weaponPtr->SecondaryMagazinesRemaining) { + weaponPtr->SecondaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine; + weaponPtr->SecondaryMagazinesRemaining--; + } + } else { + /* Grenade launcher has already reloaded at this point. */ + weaponPtr->PrimaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine; + weaponPtr->PrimaryMagazinesRemaining--; + } + } + weaponPtr->CurrentState = WEAPONSTATE_IDLE; + weaponPtr->StateTimeOutCounter=0; + playerStatusPtr->Encumberance=twPtr->Encum_Idle; + + break; + } + case WEAPONSTATE_RELOAD_SECONDARY: + { + /* load a new magazine */ + TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->SecondaryAmmoID]; + weaponPtr->SecondaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine; + weaponPtr->SecondaryMagazinesRemaining--; + weaponPtr->CurrentState = WEAPONSTATE_IDLE; + weaponPtr->StateTimeOutCounter=0; + + playerStatusPtr->Encumberance=twPtr->Encum_Idle; + + break; + } + + case WEAPONSTATE_SWAPPING_IN: + case WEAPONSTATE_SWAPPING_OUT: + { + if (playerStatusPtr->SwapToWeaponSlot!=WEAPON_FINISHED_SWAPPING) + { + PLAYER_WEAPON_DATA *newWeaponPtr; + PLAYER_WEAPON_DATA *nwp,*owp; + + nwp=&(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + owp=&(playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot]); + + playerStatusPtr->PreviouslySelectedWeaponSlot = playerStatusPtr->SelectedWeaponSlot; + playerStatusPtr->SelectedWeaponSlot = playerStatusPtr->SwapToWeaponSlot; + newWeaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot]); + + playerStatusPtr->SwapToWeaponSlot = WEAPON_FINISHED_SWAPPING; + + if (SimilarPredWeapons(nwp,owp) && (weaponPtr->CurrentState==WEAPONSTATE_SWAPPING_IN)) { + + /* Special case. */ + newWeaponPtr->CurrentState = WEAPONSTATE_READYING; + newWeaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + weaponPtr = newWeaponPtr; + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + } else { + + newWeaponPtr->CurrentState = WEAPONSTATE_SWAPPING_IN; + newWeaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + + weaponPtr = newWeaponPtr; + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + GrabWeaponShape(weaponPtr); + + if (!(twPtr->PrimaryIsMeleeWeapon)) { + GrabMuzzleFlashShape(twPtr); + } + PlayersWeapon.ObTxAnimCtrlBlks=weaponPtr->TxAnimCtrl; + if (twPtr->HasShapeAnimation) { + PlayersWeapon.ShapeAnimControlBlock=&weaponPtr->ShpAnimCtrl; + } else { + PlayersWeapon.ShapeAnimControlBlock=NULL; + } + } + } + else + { + weaponPtr->CurrentState = WEAPONSTATE_READYING; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + + playerStatusPtr->Encumberance=twPtr->Encum_Idle; + + break; + } + + case WEAPONSTATE_RECOIL_PRIMARY: + { + if (!twPtr->PrimaryIsAutomatic && playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FirePrimaryWeapon) + { + weaponPtr->CurrentState = WEAPONSTATE_WAITING; + } + else + { + weaponPtr->CurrentState = WEAPONSTATE_IDLE; + weaponPtr->StateTimeOutCounter=0; + } + + playerStatusPtr->Encumberance=twPtr->Encum_FirePrime; + + break; + } + case WEAPONSTATE_RECOIL_SECONDARY: + { + if (!twPtr->SecondaryIsAutomatic && playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FireSecondaryWeapon) + { + weaponPtr->CurrentState = WEAPONSTATE_WAITING; + } + else + { + weaponPtr->CurrentState = WEAPONSTATE_IDLE; + weaponPtr->StateTimeOutCounter=0; + } + playerStatusPtr->Encumberance=twPtr->Encum_FireSec; + break; + } + + + case WEAPONSTATE_WAITING: + { + /* wait for player to take his finger of fire */ + if( (!(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FirePrimaryWeapon + ||playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FireSecondaryWeapon)) + || (/* Alien Claw! */ + (weaponPtr->WeaponIDNumber == WEAPON_ALIEN_CLAW) + &&(twPtr->PrimaryIsAutomatic) + &&(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FirePrimaryWeapon) + ) ) + { + weaponPtr->CurrentState = WEAPONSTATE_IDLE; + weaponPtr->StateTimeOutCounter=0; + } + playerStatusPtr->Encumberance=twPtr->Encum_Idle; + break; + } + + case WEAPONSTATE_UNREADYING: + { + if (SimilarPredWeapons(weaponPtr,&playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot])) { + + PLAYER_WEAPON_DATA *newWeaponPtr; + /* Special case. */ + playerStatusPtr->PreviouslySelectedWeaponSlot = playerStatusPtr->SelectedWeaponSlot; + playerStatusPtr->SelectedWeaponSlot = playerStatusPtr->SwapToWeaponSlot; + newWeaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot]); + playerStatusPtr->SwapToWeaponSlot = WEAPON_FINISHED_SWAPPING; + + newWeaponPtr->CurrentState = WEAPONSTATE_READYING; + newWeaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + + weaponPtr = newWeaponPtr; + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + //GrabWeaponShape(weaponPtr); + + if (!(twPtr->PrimaryIsMeleeWeapon)) GrabMuzzleFlashShape(twPtr); + PlayersWeapon.ObTxAnimCtrlBlks=weaponPtr->TxAnimCtrl; + if (twPtr->HasShapeAnimation) { + PlayersWeapon.ShapeAnimControlBlock=&weaponPtr->ShpAnimCtrl; + } else { + PlayersWeapon.ShapeAnimControlBlock=NULL; + } + + } else { + /* Change Me! */ + weaponPtr->CurrentState = WEAPONSTATE_SWAPPING_OUT; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + playerStatusPtr->Encumberance=twPtr->Encum_Idle; + } + break; + } + case WEAPONSTATE_READYING: + { + //NewOnScreenMessage("WEAPON READY"); + /* That's TEMPORARY! For TESTING! */ + weaponPtr->CurrentState = WEAPONSTATE_IDLE; + weaponPtr->StateTimeOutCounter=0; + playerStatusPtr->Encumberance=twPtr->Encum_Idle; + break; + } + + default: /* applicable to many states, eg. WEAPONSTATE_JAMMED */ + { + /* if timed-out return to idle state */ + weaponPtr->CurrentState = WEAPONSTATE_IDLE; + weaponPtr->StateTimeOutCounter=0; + playerStatusPtr->Encumberance=twPtr->Encum_Idle; + break; + } + } + } + } + else { + int timeOutRate = twPtr->TimeOutRateForState[weaponPtr->CurrentState]; + + /* WEAPONSTATE_IDLE counts UP. */ + + weaponPtr->StateTimeOutCounter+=MUL_FIXED(timeOutRate,NormalFrameTime); + textprint("WeaponstateIdle Time Counter = %d\n",weaponPtr->StateTimeOutCounter); + + //weaponPtr->StateTimeOutCounter=0; + } + + switch(weaponPtr->CurrentState) + { + case WEAPONSTATE_JAMMED: + { + if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FirePrimaryWeapon) + { + // MakeClickingNoise function goes here! + PlayWeaponClickingNoise(weaponPtr->WeaponIDNumber); + } + break; + } + case WEAPONSTATE_IDLE: + { + WeaponStateIdle(playerStatusPtr,weaponPtr,twPtr,justfiredp,justfireds,ps); + break; + } + case WEAPONSTATE_UNREADYING: + { + enum WEAPON_SLOT oldSlot=playerStatusPtr->SwapToWeaponSlot; + if(RequestChangeOfWeaponWhilstSwapping(playerStatusPtr,weaponPtr)) + { + if (playerStatusPtr->SwappingIsDebounced) + { + //if (oldSlot==WEAPON_FINISHED_SWAPPING) + // weaponPtr->StateTimeOutCounter = 65536-weaponPtr->StateTimeOutCounter; + //? + + NewOnScreenMessage + ( + GetTextString + ( + TemplateWeapon[playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot].WeaponIDNumber].Name + ) + ); + playerStatusPtr->SwappingIsDebounced = 0; + } + else + { + playerStatusPtr->SwapToWeaponSlot = oldSlot; + } + } + else playerStatusPtr->SwappingIsDebounced = 1; + break; + } + case WEAPONSTATE_READYING: + case WEAPONSTATE_SWAPPING_IN: + case WEAPONSTATE_SWAPPING_OUT: + { + enum WEAPON_SLOT oldSlot=playerStatusPtr->SwapToWeaponSlot; + + if(RequestChangeOfWeaponWhilstSwapping(playerStatusPtr,weaponPtr)) + { + if (playerStatusPtr->SwappingIsDebounced) + { + + if (weaponPtr->CurrentState==WEAPONSTATE_READYING) { + /* Back outta here? */ + weaponPtr->CurrentState=WEAPONSTATE_UNREADYING; + weaponPtr->StateTimeOutCounter = 65536-weaponPtr->StateTimeOutCounter; + if (twPtr->UseStateMovement==0) { + /* I guess it's hierarchical... */ + PlayersWeaponHModelController.Reversed=1; + } + } else if (SimilarPredWeapons(&playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot],&playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot])) { + + /* Very special case.. */ + + } else if (oldSlot==WEAPON_FINISHED_SWAPPING) { + weaponPtr->StateTimeOutCounter = 65536-weaponPtr->StateTimeOutCounter; + if (twPtr->UseStateMovement==0) { + /* I guess it's hierarchical... */ + PlayersWeaponHModelController.Reversed=1; + } + } + + NewOnScreenMessage + ( + GetTextString + ( + TemplateWeapon[playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot].WeaponIDNumber].Name + ) + ); + playerStatusPtr->SwappingIsDebounced = 0; + } + else + { + playerStatusPtr->SwapToWeaponSlot = oldSlot; + } + } + else playerStatusPtr->SwappingIsDebounced = 1; + + break; + } + default: + { + break; + } + + } + StateDependentMovement(playerStatusPtr,weaponPtr); + PositionPlayersWeapon(); + +} + +static void WeaponStateIdle(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr,TEMPLATE_WEAPON_DATA *twPtr, int justfiredp, int justfireds, int ps) +{ + int CanFirePrimary, CanFireSecondary; + int WishToFirePrimary,PrimaryFired; + + CanFirePrimary=1; + CanFireSecondary=1; + PrimaryFired=0; + + if ( (twPtr->FireInChangeVision==0)&&(IsVisionChanging()) ) { + CanFirePrimary=0; + CanFireSecondary=0; + } + + #if 0 + if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) { + CanFirePrimary=0; + CanFireSecondary=0; + } + #endif + + WishToFirePrimary=playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FirePrimaryWeapon; + + if (weaponPtr->WeaponIDNumber == WEAPON_MINIGUN) { + if ((Weapon_ThisBurst=0) + &&(weaponPtr->PrimaryRoundsRemaining)) { + WishToFirePrimary=1; + /* Retain CanFirePrimary. */ + } + if (Player->ObStrategyBlock->DynPtr->IsInContactWithFloor==0) { + CanFirePrimary=0; + Weapon_ThisBurst = -1; + } + } else if (weaponPtr->WeaponIDNumber == WEAPON_PULSERIFLE) { + if ((Weapon_ThisBurst=0) + &&(weaponPtr->PrimaryRoundsRemaining)) { + WishToFirePrimary=1; + /* Retain CanFirePrimary. */ + } + } else if (weaponPtr->WeaponIDNumber == WEAPON_SMARTGUN) { + if ((Weapon_ThisBurst=0) + &&(weaponPtr->PrimaryRoundsRemaining)) { + WishToFirePrimary=1; + /* Retain CanFirePrimary. */ + } + } + + /* does the player wish to fire primary ammo*/ + if ((WishToFirePrimary)&&(CanFirePrimary)) { + if (twPtr->PrimaryAmmoID != AMMO_NONE) { + if (twPtr->PrimaryIsMeleeWeapon) { + + if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) { + /* Force Decloak. */ + playerStatusPtr->cloakOn=0; + Sound_Play(SID_PRED_CLOAKOFF,"h"); + //playerNoise=1; + } + + weaponPtr->CurrentState = WEAPONSTATE_FIRING_PRIMARY; + if (justfiredp) { + weaponPtr->StateTimeOutCounter = justfiredp-1; + } else { + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + /* KJL 11:46:42 03/04/97 - sound effects? */ + } else if ((weaponPtr->PrimaryRoundsRemaining) + ||( (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS)&&(weaponPtr->SecondaryRoundsRemaining) )) { + + /* consider probability of jamming */ + if (twPtr->ProbabilityOfJamming > Random16BitNumber) { + weaponPtr->CurrentState = WEAPONSTATE_JAMMED; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } else { /* okay, the weapon is able to fire */ + + if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) { + /* Force Decloak. */ + playerStatusPtr->cloakOn=0; + Sound_Play(SID_PRED_CLOAKOFF,"h"); + //playerNoise=1; + } + + if (twPtr->FirePrimaryFunction!=NULL) { + /* FIRE!!! */ + if (twPtr->FirePrimaryLate) { + if (weaponPtr->WeaponIDNumber == WEAPON_PRED_PISTOL) { + /* A little hackette, since I'm tired. */ + if (playerStatusPtr->FieldCharge>0) { + FirePrimaryLate=1; + weaponPtr->CurrentState = WEAPONSTATE_FIRING_PRIMARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + } else { + FirePrimaryLate=1; + weaponPtr->CurrentState = WEAPONSTATE_FIRING_PRIMARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + } else if ((*twPtr->FirePrimaryFunction)(weaponPtr)) { + if (twPtr->PrimaryMuzzleFlash) { + if (twPtr->PrimaryAmmoID==AMMO_PARTICLE_BEAM) { + AddLightingEffectToObject(Player,LFX_PARTICLECANNON); + } else { + AddLightingEffectToObject(Player,LFX_MUZZLEFLASH); + } + } + weaponPtr->CurrentState = WEAPONSTATE_FIRING_PRIMARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + } + PrimaryFired=1; + } + } + else + { + /* KJL 16:07:23 23/11/98 - trying to fire a weapon with no ammo */ + PlayWeaponClickingNoise(weaponPtr->WeaponIDNumber); + if (weaponPtr->WeaponIDNumber == WEAPON_MINIGUN) { + FireEmptyMinigun(weaponPtr); + } + } + } else if (twPtr->FirePrimaryFunction!=NULL) { + + int timeOutRate = twPtr->TimeOutRateForState[WEAPONSTATE_FIRING_PRIMARY]; + + if (timeOutRate!=WEAPONSTATE_INSTANTTIMEOUT) { + if ((*twPtr->FirePrimaryFunction)(weaponPtr)) { + weaponPtr->CurrentState = WEAPONSTATE_FIRING_PRIMARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + } else { + /* Do something special anyway... */ + (*twPtr->FirePrimaryFunction)(weaponPtr); + weaponPtr->CurrentState = WEAPONSTATE_FIRING_PRIMARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + } + } else if((playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FireSecondaryWeapon)&&(CanFireSecondary)) { + /* or the secondary ammo */ + if (twPtr->SecondaryAmmoID != AMMO_NONE) { + if (twPtr->SecondaryIsMeleeWeapon) { + if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) { + /* Force Decloak. */ + playerStatusPtr->cloakOn=0; + Sound_Play(SID_PRED_CLOAKOFF,"h"); + //playerNoise=1; + } + weaponPtr->CurrentState = WEAPONSTATE_FIRING_SECONDARY; + if (justfireds) { + weaponPtr->StateTimeOutCounter = justfireds-1; + } else { + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + /* KJL 11:46:42 03/04/97 - sound effects? */ + } else if ( (weaponPtr->SecondaryRoundsRemaining) + ||( (weaponPtr->WeaponIDNumber==WEAPON_MARINE_PISTOL)&&(weaponPtr->PrimaryRoundsRemaining) ) + ||( (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS)&&(weaponPtr->PrimaryRoundsRemaining) )) { + /* consider probability of jamming */ + if (twPtr->ProbabilityOfJamming > Random16BitNumber) { + weaponPtr->CurrentState = WEAPONSTATE_JAMMED; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } else { + /* okay, the weapon is able to fire */ + if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) { + /* Force Decloak. */ + playerStatusPtr->cloakOn=0; + Sound_Play(SID_PRED_CLOAKOFF,"h"); + //playerNoise=1; + } + if (twPtr->FireSecondaryFunction!=NULL) { + /* FIRE!!! */ + if (twPtr->FireSecondaryLate) { + FireSecondaryLate=1; + weaponPtr->CurrentState = WEAPONSTATE_FIRING_SECONDARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } else if ((*twPtr->FireSecondaryFunction)(weaponPtr)) { + if (twPtr->SecondaryMuzzleFlash) { + AddLightingEffectToObject(Player,LFX_MUZZLEFLASH); + weaponPtr->CurrentState = WEAPONSTATE_FIRING_SECONDARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + } + } + } + } else { + // MakeClickingNoise function goes here! + PlayWeaponClickingNoise(weaponPtr->WeaponIDNumber); + } + } else if (twPtr->FireSecondaryFunction!=NULL) { + + int timeOutRate = twPtr->TimeOutRateForState[WEAPONSTATE_FIRING_SECONDARY]; + + if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) { + /* Force Decloak. */ + playerStatusPtr->cloakOn=0; + Sound_Play(SID_PRED_CLOAKOFF,"h"); + //playerNoise=1; + } + + if (timeOutRate!=WEAPONSTATE_INSTANTTIMEOUT) { + if ((*twPtr->FireSecondaryFunction)(weaponPtr)) { + weaponPtr->CurrentState = WEAPONSTATE_FIRING_SECONDARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + } else { + /* Do something special anyway... */ + (*twPtr->FireSecondaryFunction)(weaponPtr); + weaponPtr->CurrentState = WEAPONSTATE_FIRING_SECONDARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + } + } else if (ps) { + /* Not firing now, for some reason. But you were. * + * Not only that, but your're also rapid fire. * + * For example, Doom Plasma Gun has rapid fire and * + * recoil: also anything that 'charges', like tail.*/ + if (ps==1) { + if (twPtr->TimeOutRateForState[WEAPONSTATE_RECOIL_PRIMARY]!=WEAPONSTATE_INSTANTTIMEOUT) { + /* there is a 'recovery' time after shooting */ + weaponPtr->CurrentState = WEAPONSTATE_RECOIL_PRIMARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + } else { + if (twPtr->TimeOutRateForState[WEAPONSTATE_RECOIL_SECONDARY]!=WEAPONSTATE_INSTANTTIMEOUT) { + /* there is a 'recovery' time after shooting */ + weaponPtr->CurrentState = WEAPONSTATE_RECOIL_SECONDARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + } + } else if ((RequestChangeOfWeapon(playerStatusPtr,weaponPtr)) + ||((playerStatusPtr->SelectedWeaponSlot!=playerStatusPtr->SwapToWeaponSlot)) + &&(playerStatusPtr->SwapToWeaponSlot!=WEAPON_FINISHED_SWAPPING)) { + weaponPtr->CurrentState = WEAPONSTATE_UNREADYING; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + NewOnScreenMessage + ( + GetTextString + ( + TemplateWeapon[playerStatusPtr->WeaponSlot[playerStatusPtr->SwapToWeaponSlot].WeaponIDNumber].Name + ) + ); + } else if (weaponPtr->PrimaryRoundsRemaining==0 && weaponPtr->PrimaryMagazinesRemaining!=0) { + /* if you've ran out of ammo, but you've got some magazines, reload. */ + if (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS) { + /* Two pistols ammo handling! */ + if (weaponPtr->SecondaryRoundsRemaining==0) { + if (weaponPtr->SecondaryMagazinesRemaining!=0) { + weaponPtr->CurrentState = WEAPONSTATE_RELOAD_PRIMARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } else { + /* Change to one pistol if you can! */ + int pistol_slot; + + pistol_slot=SlotForThisWeapon(WEAPON_MARINE_PISTOL); + if (pistol_slot!=-1) { + playerStatusPtr->SwapToWeaponSlot = pistol_slot; + weaponPtr->CurrentState = WEAPONSTATE_UNREADYING; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } else { + /* Utterly fubared. */ + weaponPtr->SecondaryMagazinesRemaining=0; + return; + } + } + } + } else { + weaponPtr->CurrentState = WEAPONSTATE_RELOAD_PRIMARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + #if 0 + } else if ((weaponPtr->PrimaryRoundsRemaining==0 && weaponPtr->PrimaryMagazinesRemaining==0) + && (AvP.PlayerType==I_Marine) + && (weaponPtr->WeaponIDNumber==WEAPON_GRENADELAUNCHER) + && ( + (GrenadeLauncherData.ProximityRoundsRemaining!=0) + ||(GrenadeLauncherData.FragmentationRoundsRemaining!=0) + ||(GrenadeLauncherData.StandardRoundsRemaining!=0) + ||(GrenadeLauncherData.ProximityMagazinesRemaining!=0) + ||(GrenadeLauncherData.FragmentationMagazinesRemaining!=0) + ||(GrenadeLauncherData.StandardMagazinesRemaining!=0) + ) + ) { + /* Deal with Al's 'grenade launcher change ammo' case... */ + GrenadeLauncher_EmergencyChangeAmmo(weaponPtr); + } else if ((weaponPtr->PrimaryRoundsRemaining==0 && weaponPtr->PrimaryMagazinesRemaining==0) + && (AvP.PlayerType==I_Marine) + && ( (weaponPtr->WeaponIDNumber!=WEAPON_GRENADELAUNCHER) + || ( + (GrenadeLauncherData.ProximityRoundsRemaining==0) + &&(GrenadeLauncherData.FragmentationRoundsRemaining==0) + &&(GrenadeLauncherData.StandardRoundsRemaining==0) + &&(GrenadeLauncherData.ProximityMagazinesRemaining==0) + &&(GrenadeLauncherData.FragmentationMagazinesRemaining==0) + &&(GrenadeLauncherData.StandardMagazinesRemaining==0) + )) + && (weaponPtr->WeaponIDNumber!=WEAPON_PULSERIFLE) + && (weaponPtr->WeaponIDNumber!=WEAPON_CUDGEL) + ) { + /* Auto change to pulserifle. */ + int slot; + + /*Don't swap weapons if the marine is a specialist marine*/ + if(AvP.Network == I_No_Network || netGameData.myCharacterSubType==NGSCT_General) + { + slot=SlotForThisWeapon(WEAPON_PULSERIFLE); + if (slot==-1) { + /* Argh! Whadda ya mean, you've got no pulse rifle? */ + } else { + playerStatusPtr->SwapToWeaponSlot = slot; + weaponPtr->CurrentState = WEAPONSTATE_UNREADYING; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + } + } else if ((weaponPtr->PrimaryRoundsRemaining==0 && weaponPtr->PrimaryMagazinesRemaining==0) + && (AvP.PlayerType==I_Marine) + && (weaponPtr->WeaponIDNumber==WEAPON_PULSERIFLE) + && (weaponPtr->SecondaryRoundsRemaining==0 && weaponPtr->SecondaryMagazinesRemaining==0) + ) { + /* If you _are_ the pulserifle, and you have no rounds left, try to get the cudgel. */ + if(AvP.Network == I_No_Network || netGameData.myCharacterSubType==NGSCT_General) + { + int slot; + /* Might want to check for any other weapons with ammo here? */ + slot=SlotForThisWeapon(WEAPON_CUDGEL); + if (slot!=-1) { + playerStatusPtr->SwapToWeaponSlot = slot; + weaponPtr->CurrentState = WEAPONSTATE_UNREADYING; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + } + } else if ((AvP.PlayerType==I_Marine) + && (weaponPtr->WeaponIDNumber==WEAPON_CUDGEL) + ) { + /* If cudgel is selected, and the pulserifle has ammo, change to _it_. */ + int pulserifle_slot; + + pulserifle_slot=SlotForThisWeapon(WEAPON_PULSERIFLE); + if (pulserifle_slot!=-1) { + if (WeaponHasAmmo(pulserifle_slot)) { + playerStatusPtr->SwapToWeaponSlot = pulserifle_slot; + weaponPtr->CurrentState = WEAPONSTATE_UNREADYING; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + } + #else + } else if ((AvP.PlayerType==I_Marine) + &&(Marine_WantToChangeWeapon(weaponPtr))) { + MarineZeroAmmoFunctionality(playerStatusPtr,weaponPtr); + #endif + + #if 0 + } else if (( + (weaponPtr->PrimaryRoundsRemaining==0 && weaponPtr->PrimaryMagazinesRemaining==0) + && (AvP.PlayerType==I_Predator) + #if 0 + /* Why is this line here? */ + && (weaponPtr->WeaponIDNumber!=WEAPON_PRED_RIFLE) + /* I find this VERY scary. The Phantom Code Changer is at work. */ + #endif + && (weaponPtr->WeaponIDNumber!=WEAPON_PRED_WRISTBLADE) + && (weaponPtr->WeaponIDNumber!=WEAPON_PRED_STAFF) + && (weaponPtr->WeaponIDNumber!=WEAPON_PRED_MEDICOMP) + )||( + (AvP.PlayerType==I_Predator)&&(weaponPtr->WeaponIDNumber==WEAPON_PRED_SHOULDERCANNON) + &&(playerStatusPtr->PlasmaCasterChargeFieldChargePlasmaCasterCharge),Caster_ChargeRatio)) + )||( + (AvP.PlayerType==I_Predator)&&(weaponPtr->WeaponIDNumber==WEAPON_PRED_PISTOL) + &&(playerStatusPtr->FieldChargeSwapToWeaponSlot = slot; + weaponPtr->CurrentState = WEAPONSTATE_UNREADYING; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + #else + } else if ((AvP.PlayerType==I_Predator) + && (Predator_WantToChangeWeapon(playerStatusPtr,weaponPtr))) { + PredatorZeroAmmoFunctionality(playerStatusPtr,weaponPtr); + #endif + } else if (twPtr->SecondaryAmmoID != AMMO_NONE) { + /* if you've ran out of ammo, but you've got some magazines, reload. */ + if (weaponPtr->SecondaryRoundsRemaining==0 && weaponPtr->SecondaryMagazinesRemaining!=0) { + if (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS) { + /* Two pistols ammo handling! */ + if (weaponPtr->PrimaryRoundsRemaining==0) { + if (weaponPtr->PrimaryMagazinesRemaining!=0) { + weaponPtr->CurrentState = WEAPONSTATE_RELOAD_PRIMARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } else { + /* Change to one pistol if you can! */ + int pistol_slot; + + pistol_slot=SlotForThisWeapon(WEAPON_MARINE_PISTOL); + if (pistol_slot!=-1) { + playerStatusPtr->SwapToWeaponSlot = pistol_slot; + weaponPtr->CurrentState = WEAPONSTATE_UNREADYING; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } else { + /* Utterly fubared. */ + weaponPtr->PrimaryMagazinesRemaining=0; + return; + } + } + } + } else { + weaponPtr->CurrentState = WEAPONSTATE_RELOAD_SECONDARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + } + } else if ((AvP.PlayerType==I_Predator)&&(weaponPtr->WeaponIDNumber==WEAPON_PRED_DISC)) { + SECTION_DATA *disc_section; + + /* You should have a disc. */ + disc_section=GetThisSectionData(PlayersWeaponHModelController.section_data,"disk"); + GLOBALASSERT(disc_section); + /* Force Appear Disc. */ + disc_section->flags&=~section_data_notreal; + + } else { + /* Wow, genuinely idle! */ + } + + if ((weaponPtr->WeaponIDNumber == WEAPON_PULSERIFLE) + ||(weaponPtr->WeaponIDNumber == WEAPON_SMARTGUN)) { + if (!PrimaryFired) { + /* Maybe Reset? */ + Weapon_ThisBurst=-1; + } + } +} + +static int RequestChangeOfWeapon(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr) +{ + playerStatusPtr->SwappingIsDebounced = 0; + + if (playerStatusPtr->MyFaceHugger) { + return(0); + } + + /* else if you wish to change to the previous weapon */ + if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_PreviousWeapon) + { + enum WEAPON_SLOT newSlot = playerStatusPtr->SelectedWeaponSlot; + int slotValidity; + + slotValidity=0; + + do { + if(newSlot-- == WEAPON_SLOT_1) { + newSlot=MAX_NO_OF_WEAPON_SLOTS-1; + } + + if (playerStatusPtr->WeaponSlot[newSlot].Possessed==1) { + slotValidity=1; + } + /* But not if you're a disk launcher with no disks. */ + if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PRED_DISC) { + if (playerStatusPtr->WeaponSlot[newSlot].PrimaryRoundsRemaining==0 + && playerStatusPtr->WeaponSlot[newSlot].PrimaryMagazinesRemaining==0) { + slotValidity=0; + } + } + /* And not if you're the cudgel. */ + if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_CUDGEL) { + if (playerStatusPtr->SelectedWeaponSlot!=newSlot) { + slotValidity=0; + } + } + /* But, if you are the cudgel, ignore the pulserifle unless it has ammo. */ + if (playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_CUDGEL) { + if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PULSERIFLE) { + if (!WeaponHasAmmo(newSlot)) { + slotValidity=0; + } + } + } else { + /* If you're not the cudgel... if it exists, and the PR has no ammo, select cudgel. */ + int pulserifle_slot; + int cudgel_slot; + + cudgel_slot=SlotForThisWeapon(WEAPON_CUDGEL); + + if (cudgel_slot!=-1) { + if (playerStatusPtr->WeaponSlot[cudgel_slot].Possessed!=1) { + cudgel_slot=-1; + } + } + + if (cudgel_slot!=-1) { + pulserifle_slot=SlotForThisWeapon(WEAPON_PULSERIFLE); + + if (pulserifle_slot!=-1) { + if (!WeaponHasAmmo(pulserifle_slot)) { + newSlot=cudgel_slot; + slotValidity=1; + } + } + } + } + } while(slotValidity==0); + + if(newSlot != playerStatusPtr->SelectedWeaponSlot) + { + playerStatusPtr->SwapToWeaponSlot = newSlot; + return 1; + } + } + /* else if you wish to change to the next weapon */ + else if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_NextWeapon) + { + enum WEAPON_SLOT newSlot = playerStatusPtr->SelectedWeaponSlot; + int slotValidity; + + slotValidity=0; + + do { + if(++newSlot == MAX_NO_OF_WEAPON_SLOTS) { + newSlot=WEAPON_SLOT_1; + } + if (playerStatusPtr->WeaponSlot[newSlot].Possessed==1) { + slotValidity=1; + } + /* But not if you're a disk launcher with no disks. */ + if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PRED_DISC) { + if (playerStatusPtr->WeaponSlot[newSlot].PrimaryRoundsRemaining==0 + && playerStatusPtr->WeaponSlot[newSlot].PrimaryMagazinesRemaining==0) { + slotValidity=0; + } + } + /* And not if you're the cudgel. */ + if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_CUDGEL) { + if (playerStatusPtr->SelectedWeaponSlot!=newSlot) { + slotValidity=0; + } + } + /* But, if you are the cudgel, ignore the pulserifle unless it has ammo. */ + if (playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_CUDGEL) { + if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PULSERIFLE) { + if (!WeaponHasAmmo(newSlot)) { + slotValidity=0; + } + } + } else { + /* If you're not the cudgel... if it exists, and the PR has no ammo, select cudgel. */ + int pulserifle_slot; + int cudgel_slot; + + cudgel_slot=SlotForThisWeapon(WEAPON_CUDGEL); + + if (cudgel_slot!=-1) { + if (playerStatusPtr->WeaponSlot[cudgel_slot].Possessed!=1) { + cudgel_slot=-1; + } + } + + if (cudgel_slot!=-1) { + pulserifle_slot=SlotForThisWeapon(WEAPON_PULSERIFLE); + + if (pulserifle_slot!=-1) { + if (!WeaponHasAmmo(pulserifle_slot)) { + newSlot=cudgel_slot; + slotValidity=1; + } + } + } + } + } while(slotValidity==0); + + if(newSlot != playerStatusPtr->SelectedWeaponSlot) + { + playerStatusPtr->SwapToWeaponSlot = newSlot; + return 1; + } + } + /* else pick a weapon, any weapon */ + else if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo) + { + enum WEAPON_SLOT requestedSlot = (enum WEAPON_SLOT)(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo - 1); + + LOCALASSERT(requestedSlot < MAX_NO_OF_WEAPON_SLOTS); + LOCALASSERT(requestedSlot >= 0); + + if( (requestedSlot != playerStatusPtr->SelectedWeaponSlot) + &&(playerStatusPtr->WeaponSlot[requestedSlot].Possessed == 1) ) + { + if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_PRED_DISC) { + if (playerStatusPtr->WeaponSlot[requestedSlot].PrimaryRoundsRemaining==0 + && playerStatusPtr->WeaponSlot[requestedSlot].PrimaryMagazinesRemaining==0) { + #if 0 + sprintf(tempstring,"NO AMMO FOR %s\n",GetTextString( + TemplateWeapon[playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber].Name) + ); + NewOnScreenMessage(tempstring); + #else + //NewOnScreenMessage(GetTextString(TEXTSTRING_NOAMMOFORWEAPON)); + #endif + return 0; + } + } + /* Look, I said you can't select the cudgel! */ + if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_CUDGEL) { + return 0; + } + /* Of course, if you are the cudgel and the the pulserifle has no ammo... */ + if (playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_CUDGEL) { + if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_PULSERIFLE) { + if (!WeaponHasAmmo(requestedSlot)) { + return(0); + } + } + } else { + if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_PULSERIFLE) { + /* If you're not the cudgel... if it exists, and the PR has no ammo, select cudgel. */ + int pulserifle_slot; + int cudgel_slot; + + cudgel_slot=SlotForThisWeapon(WEAPON_CUDGEL); + if (cudgel_slot!=-1) { + pulserifle_slot=SlotForThisWeapon(WEAPON_PULSERIFLE); + + if (pulserifle_slot!=-1) { + if (!WeaponHasAmmo(pulserifle_slot)) { + requestedSlot=cudgel_slot; + } + } + } + } + } + + playerStatusPtr->SwapToWeaponSlot = requestedSlot; + return 1; + } else if( (requestedSlot != playerStatusPtr->SelectedWeaponSlot) + &&(playerStatusPtr->WeaponSlot[requestedSlot].Possessed == -1) ) + { + #if 0 + sprintf(tempstring,"%s NOT AVAILABLE IN DEMO\n",GetTextString( + TemplateWeapon[playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber].Name) + ); + NewOnScreenMessage(tempstring); + #endif + } + } + + return 0; +} +static int RequestChangeOfWeaponWhilstSwapping(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr) +{ + enum WEAPON_SLOT currentSlot; + + if (playerStatusPtr->MyFaceHugger) { + return(0); + } + + if (playerStatusPtr->SwapToWeaponSlot == WEAPON_FINISHED_SWAPPING) + { + currentSlot = playerStatusPtr->SelectedWeaponSlot; + } + else + { + currentSlot = playerStatusPtr->SwapToWeaponSlot; + } + + + /* else if you wish to change to the previous weapon */ + if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_PreviousWeapon) + { + enum WEAPON_SLOT newSlot = currentSlot; + int slotValidity=0; + + do + { + if(newSlot-- == WEAPON_SLOT_1) { + newSlot=MAX_NO_OF_WEAPON_SLOTS-1; + } + if (playerStatusPtr->WeaponSlot[newSlot].Possessed==1) { + slotValidity=1; + } + /* But not if you're a disk launcher with no disks. */ + if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PRED_DISC) { + if (playerStatusPtr->WeaponSlot[newSlot].PrimaryRoundsRemaining==0 + && playerStatusPtr->WeaponSlot[newSlot].PrimaryMagazinesRemaining==0) { + slotValidity=0; + } + } + /* And not if you're the cudgel. */ + if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_CUDGEL) { + if (playerStatusPtr->SelectedWeaponSlot!=newSlot) { + slotValidity=0; + } + } + /* But, if you are the cudgel, ignore the pulserifle unless it has ammo. */ + if (playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_CUDGEL) { + if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PULSERIFLE) { + if (!WeaponHasAmmo(newSlot)) { + slotValidity=0; + } + } + } else { + /* If you're not the cudgel... if it exists, and the PR has no ammo, select cudgel. */ + int pulserifle_slot; + int cudgel_slot; + + cudgel_slot=SlotForThisWeapon(WEAPON_CUDGEL); + + if (cudgel_slot!=-1) { + if (playerStatusPtr->WeaponSlot[cudgel_slot].Possessed!=1) { + cudgel_slot=-1; + } + } + + if (cudgel_slot!=-1) { + pulserifle_slot=SlotForThisWeapon(WEAPON_PULSERIFLE); + + if (pulserifle_slot!=-1) { + if (!WeaponHasAmmo(pulserifle_slot)) { + newSlot=cudgel_slot; + slotValidity=1; + } + } + } + } + } + while(slotValidity==0); + + playerStatusPtr->SwapToWeaponSlot = newSlot; + return 1; + } + /* else if you wish to change to the next weapon */ + else if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_NextWeapon) + { + enum WEAPON_SLOT newSlot = currentSlot; + int slotValidity=0; + + do + { + if(++newSlot == MAX_NO_OF_WEAPON_SLOTS) { + newSlot=WEAPON_SLOT_1; + } + if (playerStatusPtr->WeaponSlot[newSlot].Possessed==1) { + slotValidity=1; + } + /* But not if you're a disk launcher with no disks. */ + if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PRED_DISC) { + if (playerStatusPtr->WeaponSlot[newSlot].PrimaryRoundsRemaining==0 + && playerStatusPtr->WeaponSlot[newSlot].PrimaryMagazinesRemaining==0) { + slotValidity=0; + } + } + /* And not if you're the cudgel. */ + if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_CUDGEL) { + if (playerStatusPtr->SelectedWeaponSlot!=newSlot) { + slotValidity=0; + } + } + /* But, if you are the cudgel, ignore the pulserifle unless it has ammo. */ + if (playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_CUDGEL) { + if (playerStatusPtr->WeaponSlot[newSlot].WeaponIDNumber==WEAPON_PULSERIFLE) { + if (!WeaponHasAmmo(newSlot)) { + slotValidity=0; + } + } + } else { + /* If you're not the cudgel... if it exists, and the PR has no ammo, select cudgel. */ + int pulserifle_slot; + int cudgel_slot; + + cudgel_slot=SlotForThisWeapon(WEAPON_CUDGEL); + + if (cudgel_slot!=-1) { + if (playerStatusPtr->WeaponSlot[cudgel_slot].Possessed!=1) { + cudgel_slot=-1; + } + } + + if (cudgel_slot!=-1) { + pulserifle_slot=SlotForThisWeapon(WEAPON_PULSERIFLE); + + if (pulserifle_slot!=-1) { + if (!WeaponHasAmmo(pulserifle_slot)) { + newSlot=cudgel_slot; + slotValidity=1; + } + } + } + } + } + while(slotValidity==0); + + playerStatusPtr->SwapToWeaponSlot = newSlot; + return 1; + } + /* else pick a weapon, any weapon */ + else if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo) + { + enum WEAPON_SLOT requestedSlot = (enum WEAPON_SLOT)(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo - 1); + + LOCALASSERT(requestedSlot < MAX_NO_OF_WEAPON_SLOTS); + LOCALASSERT(requestedSlot >= 0); + + if( (requestedSlot != currentSlot) + &&(playerStatusPtr->WeaponSlot[requestedSlot].Possessed == 1) ) + { + if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_PRED_DISC) { + if (playerStatusPtr->WeaponSlot[requestedSlot].PrimaryRoundsRemaining==0 + && playerStatusPtr->WeaponSlot[requestedSlot].PrimaryMagazinesRemaining==0) { + #if 0 + sprintf(tempstring,"NO AMMO FOR %s\n",GetTextString( + TemplateWeapon[playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber].Name) + ); + NewOnScreenMessage(tempstring); + #else + //NewOnScreenMessage(GetTextString(TEXTSTRING_NOAMMOFORWEAPON)); + #endif + return 0; + } + } + /* Look, I said you can't select the cudgel! */ + if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_CUDGEL) { + return 0; + } + /* Of course, if you are the cudgel and the the pulserifle has no ammo... */ + if (playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_CUDGEL) { + if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_PULSERIFLE) { + if (!WeaponHasAmmo(requestedSlot)) { + return(0); + } + } + } else { + if (playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber==WEAPON_PULSERIFLE) { + /* If you're not the cudgel... if it exists, and the PR has no ammo, select cudgel. */ + int pulserifle_slot; + int cudgel_slot; + + cudgel_slot=SlotForThisWeapon(WEAPON_CUDGEL); + if (cudgel_slot!=-1) { + pulserifle_slot=SlotForThisWeapon(WEAPON_PULSERIFLE); + + if (pulserifle_slot!=-1) { + if (!WeaponHasAmmo(pulserifle_slot)) { + requestedSlot=cudgel_slot; + } + } + } + } + } + + playerStatusPtr->SwapToWeaponSlot = requestedSlot; + return 1; + } else if( (requestedSlot != currentSlot) + &&(playerStatusPtr->WeaponSlot[requestedSlot].Possessed == -1) ) + { + #if 0 + sprintf(tempstring,"%s NOT AVAILABLE IN DEMO\n",GetTextString( + TemplateWeapon[playerStatusPtr->WeaponSlot[requestedSlot].WeaponIDNumber].Name) + ); + NewOnScreenMessage(tempstring); + #endif + } + } + + return 0; +} + +/*KJL******************************************************************************************** +* Function to handle weapons whose firing rates are >= the frame rate, and therefore need to be * +* handled in a FRI manner. * +********************************************************************************************KJL*/ +int FireBurstWeapon(PLAYER_WEAPON_DATA *weaponPtr) { + + if (Weapon_ThisBurst==-1) { + Weapon_ThisBurst=0; + } + + Weapon_ThisBurst+=FireAutomaticWeapon(weaponPtr); + + return(1); +} + +int FireAutomaticWeapon(PLAYER_WEAPON_DATA *weaponPtr) +{ + TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber]; + TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->PrimaryAmmoID]; + int oldAmmoCount; + + { + oldAmmoCount=weaponPtr->PrimaryRoundsRemaining>>16; + /* ammo is in 16.16. we want the integer part, rounded up */ + if ( (weaponPtr->PrimaryRoundsRemaining&0xffff)!=0 ) oldAmmoCount+=1; + } + + + { + /* theoretical number of bullets fired each frame, as a 16.16 number */ + int bulletsToFire=MUL_FIXED(twPtr->FiringRate,NormalFrameTime); + + if (bulletsToFirePrimaryRoundsRemaining) + { + weaponPtr->PrimaryRoundsRemaining -= bulletsToFire; + } + else /* end of magazine */ + { + weaponPtr->PrimaryRoundsRemaining=0; + } + } + + { + int bulletsFired; + int newAmmoCount=weaponPtr->PrimaryRoundsRemaining>>16; + /* ammo is in 16.16. we want the integer part, rounded up */ + if ( (weaponPtr->PrimaryRoundsRemaining&0xffff)!=0 ) newAmmoCount+=1; + + bulletsFired = oldAmmoCount-newAmmoCount; + + /* Changed to create projectiles for the flamethrower */ + + if (templateAmmoPtr->CreatesProjectile) + { + if (bulletsFired) + { + ProjectilesFired=bulletsFired; + FireProjectileAmmo(twPtr->PrimaryAmmoID); + } + } + else /* instantaneous line of sight */ + { + if (bulletsFired) + { + PlayerFireLineOfSightAmmo(twPtr->PrimaryAmmoID,bulletsFired); + CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,bulletsFired); + } + } + return(bulletsFired); + } +} + +int FireNonAutomaticWeapon(PLAYER_WEAPON_DATA *weaponPtr) +{ + TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber]; + TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->PrimaryAmmoID]; + weaponPtr->PrimaryRoundsRemaining -= 65536; + + /* does ammo create an actual object? */ + if (templateAmmoPtr->CreatesProjectile) + { + FireProjectileAmmo(twPtr->PrimaryAmmoID); + CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1); + } + else /* instantaneous line of sight */ + { + PlayerFireLineOfSightAmmo(twPtr->PrimaryAmmoID,1); + CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1); + } + return(1); +} + +int FireNonAutomaticSecondaryAmmo(PLAYER_WEAPON_DATA *weaponPtr) +{ + TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber]; + TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->SecondaryAmmoID]; + weaponPtr->SecondaryRoundsRemaining -= 65536; + + /* does ammo create an actual object? */ + if (templateAmmoPtr->CreatesProjectile) + { + FireProjectileAmmo(twPtr->SecondaryAmmoID); + CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1); + } + else /* instantaneous line of sight */ + { + PlayerFireLineOfSightAmmo(twPtr->SecondaryAmmoID,1); + CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1); + } + return(1); +} + + +#define WEAPON_RANGE 1000000 /* link this to weapon/ammo type perhaps */ + +/* instantaneous line of sight firing */ +static void PlayerFireLineOfSightAmmo(enum AMMO_ID AmmoID, int multiple) +{ + + if (PlayersTarget.DispPtr) + { + if (PlayersTarget.HModelSection!=NULL) { + textprint("Hitting a hierarchical section.\n"); + GLOBALASSERT(PlayersTarget.DispPtr->HModelControlBlock==PlayersTarget.HModelSection->my_controller); + } + + HandleWeaponImpact(&(PlayersTarget.Position),PlayersTarget.DispPtr->ObStrategyBlock,AmmoID,&GunMuzzleDirectionInWS, multiple*ONE_FIXED, PlayersTarget.HModelSection); + + /* Put in a target filter here? */ + if (AccuracyStats_TargetFilter(PlayersTarget.DispPtr->ObStrategyBlock)) { + CurrentGameStats_WeaponHit(PlayerStatusPtr->SelectedWeaponSlot,multiple); + } + } + +} + +void HandleWeaponImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *this_section_data) +{ + VECTORCH incoming,*invec; + + /* 'multiple' is now in FIXED POINT! */ + + #if 0 + if ((GRENADE_MODE)&&(positionPtr)) { + switch (AmmoID) { + case AMMO_10MM_CULW: + case AMMO_SMARTGUN: + case AMMO_MINIGUN: + { + HandleEffectsOfExplosion + ( + sbPtr, + positionPtr, + TemplateAmmo[AMMO_PULSE_GRENADE].MaxRange, + &TemplateAmmo[AMMO_PULSE_GRENADE].MaxDamage[AvP.Difficulty], + TemplateAmmo[AMMO_PULSE_GRENADE].ExplosionIsFlat + ); + { + Explosion_SoundData.position=*positionPtr; + Sound_Play(SID_NADEEXPLODE,"n",&Explosion_SoundData); + } + } + break; + default: + break; + } + } + #endif + + if(sbPtr) + { + if (sbPtr->DynPtr) { + MATRIXCH WtoLMat; + /* Consider incoming hit direction. */ + WtoLMat=sbPtr->DynPtr->OrientMat; + TransposeMatrixCH(&WtoLMat); + RotateAndCopyVector(directionPtr,&incoming,&WtoLMat); + invec=&incoming; + } else { + invec=NULL; + } + + if (this_section_data) + { + if (sbPtr->SBdptr) + { + //if (sbPtr->SBdptr->HModelControlBlock && (sbPtr->I_SBtype != I_BehaviourNetGhost)) + if (sbPtr->SBdptr->HModelControlBlock) + { + /* Netghost case now handled properly. */ + AddDecalToHModel(&LOS_ObjectNormal, &LOS_Point,this_section_data); + + GLOBALASSERT(sbPtr->SBdptr->HModelControlBlock==this_section_data->my_controller); + CauseDamageToHModel(sbPtr->SBdptr->HModelControlBlock, sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple, this_section_data,invec,positionPtr,0); + /* No longer return: do knockback. */ + //return; + } + else + { + CauseDamageToObject(sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple,invec); + } + } + else + { + CauseDamageToObject(sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple,invec); + } + } + else + { + CauseDamageToObject(sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple,invec); + } + + if (sbPtr->DynPtr) + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + EULER rotation; + #if 0 + int magnitudeOfForce = (5000*TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty].Impact) / dynPtr->Mass; + #else + int magnitudeOfForce = (5000*TotalKineticDamage(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty])) / dynPtr->Mass; + #endif + /* okay, not too sure yet what this should do */ + dynPtr->LinImpulse.vx += MUL_FIXED(directionPtr->vx,magnitudeOfForce); + dynPtr->LinImpulse.vy += MUL_FIXED(directionPtr->vy,magnitudeOfForce); + dynPtr->LinImpulse.vz += MUL_FIXED(directionPtr->vz,magnitudeOfForce); + + //CalculateTorque(&rotation, directionPtr, sbPtr); + CalculateTorqueAtPoint(&rotation,positionPtr,sbPtr); + /* okay, not too sure yet what this should do */ + // magnitudeOfForce /= 100; + + dynPtr->AngImpulse.EulerX += MUL_FIXED(rotation.EulerX,magnitudeOfForce); + dynPtr->AngImpulse.EulerY += MUL_FIXED(rotation.EulerY,magnitudeOfForce); + dynPtr->AngImpulse.EulerZ += MUL_FIXED(rotation.EulerZ,magnitudeOfForce); + + } + + + } + + /* KJL 10:44:49 02/03/98 - add bullet hole to world */ + if (LOS_ObjectHitPtr) { + /* only add to the landscape, ie. modules */ + if (LOS_ObjectHitPtr->ObMyModule) + { + /* bad idea to put bullethole on a morphing object */ + if(!LOS_ObjectHitPtr->ObMorphCtrl) + { + MakeDecal + ( + DECAL_BULLETHOLE, + &LOS_ObjectNormal, + positionPtr, + LOS_ObjectHitPtr->ObMyModule->m_index + ); + } + /* cause a ricochet 1 in 8 times */ + if (((FastRandom()&65535) < 8192)&&(AmmoID!=AMMO_XENOBORG)) + { + MakeImpactSparks(directionPtr, &LOS_ObjectNormal, positionPtr); + } + } + + /*also do ricochets on the queen*/ + if(sbPtr && sbPtr->I_SBtype==I_BehaviourQueenAlien) + { + /* cause a ricochet 1 in 8 times */ + if (((FastRandom()&65535) < 8192)&&(AmmoID!=AMMO_XENOBORG)) + { + MakeImpactSparks(directionPtr, &LOS_ObjectNormal, positionPtr); + } + } + } + + + + #if 0 + switch (AmmoID) + { + case AMMO_PLASMA: + { + DISPLAYBLOCK *dispPtr = MakeDebris(I_BehaviourPlasmaImpact,positionPtr); + if (dispPtr) + { + #if SupportWindows95 + if(AvP.Network!=I_No_Network) + AddNetMsg_LocalRicochet(I_BehaviourPlasmaImpact,positionPtr,&LOS_ObjectNormal); + #endif + MakeMatrixFromDirection(&LOS_ObjectNormal,&dispPtr->ObMat); + } + break; + } + case AMMO_PARTICLE_BEAM: + { + { + VECTORCH velocity={0,0,0}; + MakeParticle(positionPtr,&(velocity),PARTICLE_BLACKSMOKE); + } + break; + } + default: + { + DISPLAYBLOCK *dispPtr = MakeDebris(I_BehaviourBulletRicochet,positionPtr); + if (dispPtr) + { + #if SupportWindows95 + if(AvP.Network!=I_No_Network) + AddNetMsg_LocalRicochet(I_BehaviourBulletRicochet,positionPtr,&LOS_ObjectNormal); + #endif + MakeMatrixFromDirection(&LOS_ObjectNormal,&dispPtr->ObMat); + } + break; + } + } + #endif + + +} + +int TotalKineticDamage(DAMAGE_PROFILE *damage) { + + int tkd; + + + tkd=(damage->Impact+damage->Penetrative+damage->Cutting); + + + return(tkd); +} + +void GetDirectionOfAttack(STRATEGYBLOCK *sbPtr,VECTORCH *WorldVector,VECTORCH *Output) { + + MATRIXCH WtoLMat; + + GLOBALASSERT(sbPtr); + + if (sbPtr->DynPtr==NULL) { + /* Handle as best we can. */ + Output->vx=0; + Output->vy=0; + Output->vz=0; + return; + } + + /* Consider incoming hit direction. */ + WtoLMat=sbPtr->DynPtr->OrientMat; + TransposeMatrixCH(&WtoLMat); + RotateAndCopyVector(WorldVector,Output,&WtoLMat); + Normalise(Output); + +} + +void CauseDamageToObject(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple,VECTORCH *incoming) +{ + int use_multiple; + + GLOBALASSERT(sbPtr); + GLOBALASSERT(damage); + + use_multiple=multiple; + + if (sbPtr->I_SBtype==I_BehaviourNetGhost) { + DamageNetworkGhost(sbPtr, damage, use_multiple,NULL,incoming); + return; + } + + if (sbPtr->I_SBtype==I_BehaviourDummy) { + /* Dummys are INDESTRUCTIBLE. */ + return; + } + + if (sbPtr->I_SBtype==I_BehaviourPredator) { + if (damage->Id==AMMO_PRED_ENERGY_BOLT) { + /* Make NPC Preds immune to splash damage? */ + return; + } + } + + if (damage->Id==AMMO_NPC_OBSTACLE_CLEAR) { + if (sbPtr->I_SBtype==I_BehaviourInanimateObject) { + INANIMATEOBJECT_STATUSBLOCK* objStatPtr = sbPtr->SBdataptr; + + if (objStatPtr->explosionType!=0) { + /* Try not to blunder through fatal things... */ + return; + } + } + } + + if(sbPtr->I_SBtype==I_BehaviourMarinePlayer || + sbPtr->I_SBtype==I_BehaviourAlienPlayer || + sbPtr->I_SBtype==I_BehaviourPredatorPlayer) + { + //check for player invulnerability + PLAYER_STATUS *psPtr=(PLAYER_STATUS*)sbPtr->SBdataptr; + GLOBALASSERT(psPtr); + if(psPtr->invulnerabilityTimer>0) + { + //player is still invulnerable + return; + } + + #if 0 + /* And check for warpspeed cheatmode. */ + if (WARPSPEED_CHEATMODE) { + use_multiple>>=1; + } + #endif + } + + /* Friendly Fire? */ + if(AvP.Network != I_No_Network) + { + if (netGameData.disableFriendlyFire && (netGameData.gameType==NGT_CoopDeathmatch || netGameData.gameType==NGT_Coop)) { + if (sbPtr->I_SBtype==I_BehaviourMarinePlayer) { + if ((FriendlyFireDamageFilter(damage))==0) { + return; + } + } + } + } + + DamageDamageBlock(&sbPtr->SBDamageBlock,damage,use_multiple); + + /* This bit will still need to exist: but differently. */ + + /* Andy 13/10/97 - + Sound calls now placed in object specific damage functions ...IsDamaged */ + + switch(sbPtr->I_SBtype) + { + case I_BehaviourAlien: + { + /* reduce alien health */ + AlienIsDamaged(sbPtr, damage, use_multiple, 0,NULL,incoming,NULL); + break; + } + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + { + PlayerIsDamaged(sbPtr,damage,use_multiple,incoming); + break; + } + case I_BehaviourInanimateObject: + { + InanimateObjectIsDamaged(sbPtr,damage,use_multiple); + break; + } + case I_BehaviourVideoScreen: + { + VideoScreenIsDamaged(sbPtr,damage,use_multiple); + break; + } + case I_BehaviourPlacedLight: + { + PlacedLightIsDamaged(sbPtr,damage,use_multiple); + break; + } + case I_BehaviourTrackObject: + { + TrackObjectIsDamaged(sbPtr,damage,use_multiple); + break; + } + case I_BehaviourPredator: + { + PredatorIsDamaged(sbPtr,damage,use_multiple,NULL,incoming); + break; + } + case I_BehaviourXenoborg: + { + XenoborgIsDamaged(sbPtr, damage, use_multiple, 0,incoming); + break; + } + case I_BehaviourSeal: + case I_BehaviourMarine: + { + MarineIsDamaged(sbPtr,damage,use_multiple,0,NULL,incoming); + break; + } + case I_BehaviourQueenAlien: + { + QueenIsDamaged(sbPtr,damage,use_multiple,NULL,incoming,NULL); + break; + } + case I_BehaviourPredatorAlien: + { + GLOBALASSERT(0); + //PAQIsDamaged(sbPtr,damage,use_multiple); + break; + } + case I_BehaviourFaceHugger: + { + FacehuggerIsDamaged(sbPtr,damage,use_multiple); + break; + } + case I_BehaviourGrenade: + case I_BehaviourFlareGrenade: + case I_BehaviourFragmentationGrenade: + case I_BehaviourProximityGrenade: + case I_BehaviourRocket: + case I_BehaviourPulseGrenade: + case I_BehaviourPredatorEnergyBolt: + case I_BehaviourXenoborgEnergyBolt: + { + /* make it explode! */ + ((ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = 0; + break; + } + case I_BehaviourFrisbee: + { + /* make it explode! */ + ((FRISBEE_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = 0; + break; + } + case I_BehaviourNetGhost: + { + #if SupportWindows95 + DamageNetworkGhost(sbPtr, damage, use_multiple,NULL,incoming); + #endif + break; + } + case I_BehaviourAutoGun: + { + AGunIsDamaged(sbPtr, damage, use_multiple, 0,incoming); + break; + } + case I_BehaviourNetCorpse: + { + CorpseIsDamaged(sbPtr,damage,use_multiple,0,NULL,incoming); + break; + } + default: + break; + } +} + + +void HandleEffectsOfExplosion(STRATEGYBLOCK *objectToIgnorePtr, VECTORCH *centrePtr, int maxRange, DAMAGE_PROFILE *maxDamage, int flat) +{ + DISPLAYBLOCK *ignoreDispPtr; + int i = NumActiveStBlocks; + + if (objectToIgnorePtr) + { + ignoreDispPtr = objectToIgnorePtr->SBdptr; + } + else + { + ignoreDispPtr = 0; + } + + /* The damage done by an explosions varies linearly with range from the explosion's + centre so that no damage is done to an object which is 'maxRange' away. */ + + while(i) + { + STRATEGYBLOCK *sbPtr = ActiveStBlockList[--i]; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + DISPLAYBLOCK *dispPtr = sbPtr->SBdptr; + + if (sbPtr == objectToIgnorePtr) continue; + + if (dynPtr && dispPtr) + { + int range; + VECTORCH displacement; + + displacement.vx = dynPtr->Position.vx - centrePtr->vx; + displacement.vy = dynPtr->Position.vy - centrePtr->vy; + displacement.vz = dynPtr->Position.vz - centrePtr->vz; + range = Approximate3dMagnitude(&displacement); + + /* find if object is in explosion radius */ + if (range && range < maxRange) + { + /* now check line of sight */ + BOOL visible=IsThisObjectVisibleFromThisPosition_WithIgnore(dispPtr,ignoreDispPtr,centrePtr,maxRange); + if(LOS_Lambda>range) + { + //seen past the object , so it probably is visible , but has a hole in it + visible=TRUE; + } + + if(visible) + { + int mult,damage; + enum PARTICLE_ID blood_type; + + if (flat) mult=ONE_FIXED; + else mult=DIV_FIXED((maxRange-range),maxRange); + + damage=MUL_FIXED(TotalKineticDamage(maxDamage),mult); + + /* Identify blood type now! */ + blood_type=GetBloodType(sbPtr); + { + VECTORCH attack_dir; + GetDirectionOfAttack(sbPtr,&displacement,&attack_dir); + + CauseDamageToObject(sbPtr,maxDamage,mult,&attack_dir); + } + if (NPC_IsDead(sbPtr)) { + /* Blood! */ + VECTORCH position; + + GetTargetingPointOfObject_Far(sbPtr,&position); + + if ((damage)&&(blood_type!=PARTICLE_NULL)) { + /* Let's just use ObMaxX for now... */ + MakeBloodExplosion(&position, dispPtr->ObRadius, centrePtr, damage, blood_type); + } + } + /* effect of explosion on object's dynamics */ + { + VECTORCH directionOfForce; + EULER rotation; + int magnitudeOfForce = 5000*damage/dynPtr->Mass; + + Normalise(&displacement); + + /* okay, not too sure yet what this should do */ + dynPtr->LinImpulse.vx += MUL_FIXED(displacement.vx,magnitudeOfForce); + dynPtr->LinImpulse.vy += MUL_FIXED(displacement.vy,magnitudeOfForce); + dynPtr->LinImpulse.vz += MUL_FIXED(displacement.vz,magnitudeOfForce); + + CalculateTorque(&rotation, &displacement, sbPtr); + + /* okay, not too sure yet what this should do */ + // magnitudeOfForce /= 100; + dynPtr->AngImpulse.EulerX += MUL_FIXED(rotation.EulerX,magnitudeOfForce); + dynPtr->AngImpulse.EulerY += MUL_FIXED(rotation.EulerY,magnitudeOfForce); + dynPtr->AngImpulse.EulerZ += MUL_FIXED(rotation.EulerZ,magnitudeOfForce); + } + } + } + } + } + + switch (maxDamage->ExplosivePower) + { + case 6: + { + + MakeVolumetricExplosionAt(centrePtr,EXPLOSION_SMALL_NOCOLLISIONS); + + if(AvP.Network!=I_No_Network) + { + AddNetMsg_MakeExplosion(centrePtr,EXPLOSION_SMALL_NOCOLLISIONS); + } + break; + } + case 5: + { + MakeVolumetricExplosionAt(centrePtr,EXPLOSION_MOLOTOV); + break; + } + case 4: + { + /* Must be the plasmacaster. SFX? */ + break; + } + case 3: + { + MakeElectricalExplosion(centrePtr); + + if(AvP.Network!=I_No_Network) + { + AddNetMsg_MakeExplosion(centrePtr,EXPLOSION_PREDATORPISTOL); + } + break; + } + case 2: + { + + MakeVolumetricExplosionAt(centrePtr,EXPLOSION_HUGE); + + if(AvP.Network!=I_No_Network) + { + AddNetMsg_MakeExplosion(centrePtr,EXPLOSION_HUGE); + } + break; + } + case 1: + { + + MakeVolumetricExplosionAt(centrePtr,EXPLOSION_PULSEGRENADE); + + if(AvP.Network!=I_No_Network) + { + AddNetMsg_MakeExplosion(centrePtr,EXPLOSION_PULSEGRENADE); + } + break; + } + default: + break; + } + +} + + +void FireAutoGun(STRATEGYBLOCK *sbPtr) +{ + #if 0 + AUTOGUN_BEHAV_BLOCK *ag_bhv; + ag_bhv = (AUTOGUN_BEHAV_BLOCK*)(sbPtr->SBdataptr); + + FireLineOfSightAmmo(AMMO_AUTOGUN, &(ag_bhv->global_muzz_pos), &(ag_bhv->tgt_direction),1); + #endif +} + + +void MakeMatrixFromDirection(VECTORCH *directionPtr, MATRIXCH *matrixPtr) +{ + VECTORCH XVector; + VECTORCH YVector; + + if (directionPtr->vx==0) + { + XVector.vx = 65536; + XVector.vy = 0; + XVector.vz = 0; + } + else if (directionPtr->vy==0) + { + XVector.vx = 0; + XVector.vy = 65536; + XVector.vz = 0; + } + else if (directionPtr->vz==0) + { + XVector.vx = 0; + XVector.vy = 0; + XVector.vz = 65536; + } + else + { + XVector.vx = directionPtr->vz; + XVector.vy = 0; + XVector.vz = -directionPtr->vx; + Normalise(&XVector); + } + + CrossProduct(directionPtr, &XVector, &YVector); + + matrixPtr->mat11 = XVector.vx; + matrixPtr->mat12 = XVector.vy; + matrixPtr->mat13 = XVector.vz; + + matrixPtr->mat21 = YVector.vx; + matrixPtr->mat22 = YVector.vy; + matrixPtr->mat23 = YVector.vz; + + matrixPtr->mat31 = directionPtr->vx; + matrixPtr->mat32 = directionPtr->vy; + matrixPtr->mat33 = directionPtr->vz; +} + + + +/*KJL************* +* 3D Weapon Code * +*************KJL*/ +/* values which are evaluated at runtime */ +VECTORCH CentreOfMuzzleOffset; +int MuzzleFlashLength; + +void PositionPlayersWeapon(void) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + VECTORCH gunDirection; + //VECTORCH gunOffset = twPtr->RestPosition; + VECTORCH gunOffset = PlayersWeaponCameraOffset; + gunOffset.vx += twPtr->RestPosition.vx; + gunOffset.vy += twPtr->RestPosition.vy; + gunOffset.vz += twPtr->RestPosition.vz; + + gunOffset.vx += weaponPtr->PositionOffset.vx; + gunOffset.vy += weaponPtr->PositionOffset.vy; + gunOffset.vz += weaponPtr->PositionOffset.vz; + + if ( (!(twPtr->PrimaryIsMeleeWeapon || (weaponPtr->WeaponIDNumber == WEAPON_PRED_DISC) + ||(weaponPtr->WeaponIDNumber == WEAPON_PRED_SHOULDERCANNON) + ||(weaponPtr->WeaponIDNumber == WEAPON_PRED_MEDICOMP) + )) ) { + { + gunDirection = PlayersTarget.Position; + + { + VECTORCH offset; + offset.vx = gunOffset.vx/4; + offset.vy = gunOffset.vy/4; + offset.vz = gunOffset.vz/4; + + { + MATRIXCH mat = Global_VDB_Ptr->VDB_Mat; + TransposeMatrixCH(&mat); + RotateVector(&offset, &mat); + } + gunDirection.vx -= Global_VDB_Ptr->VDB_World.vx-offset.vx; + gunDirection.vy -= Global_VDB_Ptr->VDB_World.vy-offset.vy; + gunDirection.vz -= Global_VDB_Ptr->VDB_World.vz-offset.vz; + } + Normalise(&gunDirection); + } + { + MATRIXCH mat; + EULER dir = weaponPtr->DirectionOffset; + VECTORCH XVector; + VECTORCH YVector; + VECTORCH ZVector; + + ZVector = gunDirection; + #if 0 + /* KJL 13:13:34 04/05/97 - allow weapon to rotate about z axis */ + XVector.vx = ZVector.vz; + XVector.vy = 0; + XVector.vz = -ZVector.vx; + + Normalise(&XVector); + + CrossProduct(&ZVector,&XVector, &YVector); + #else + /* keep weapon stable about z axis - definitely needed for alien */ + YVector.vx = Global_VDB_Ptr->VDB_Mat.mat12; + YVector.vy = Global_VDB_Ptr->VDB_Mat.mat22; + YVector.vz = Global_VDB_Ptr->VDB_Mat.mat32; + CrossProduct(&YVector,&ZVector, &XVector); + Normalise(&XVector); + #endif + + PlayersWeapon.ObMat.mat11 = XVector.vx; + PlayersWeapon.ObMat.mat12 = XVector.vy; + PlayersWeapon.ObMat.mat13 = XVector.vz; + + PlayersWeapon.ObMat.mat21 = YVector.vx; + PlayersWeapon.ObMat.mat22 = YVector.vy; + PlayersWeapon.ObMat.mat23 = YVector.vz; + + PlayersWeapon.ObMat.mat31 = ZVector.vx; + PlayersWeapon.ObMat.mat32 = ZVector.vy; + PlayersWeapon.ObMat.mat33 = ZVector.vz; + + if (dir.EulerX != 0 || dir.EulerY !=0 || dir.EulerZ != 0) + { + if (dir.EulerX<0) dir.EulerX = 4096 + dir.EulerX; + if (dir.EulerY<0) dir.EulerY = 4096 + dir.EulerY; + if (dir.EulerZ<0) dir.EulerZ = 4096 + dir.EulerZ; + + CreateEulerMatrix(&dir, &mat); + TransposeMatrixCH(&mat); + MatrixMultiply(&PlayersWeapon.ObMat,&mat,&PlayersWeapon.ObMat); + + } + } + } else { + /* Pred Weapons. */ + PlayersWeapon.ObMat=Global_VDB_Ptr->VDB_Mat; + TransposeMatrixCH(&PlayersWeapon.ObMat); + } + + PlayersWeapon.ObView = gunOffset; + + { + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + + VECTORCH offset = PlayersWeapon.ObView; + MATRIXCH matrix = VDBPtr->VDB_Mat; + + TransposeMatrixCH(&matrix); + + RotateVector(&offset, &matrix); + + PlayersWeapon.ObWorld.vx = (VDBPtr->VDB_World.vx + offset.vx); + PlayersWeapon.ObWorld.vy = (VDBPtr->VDB_World.vy + offset.vy); + PlayersWeapon.ObWorld.vz = (VDBPtr->VDB_World.vz + offset.vz); + } + + /* Late firing. Note that this is a horrible hack. */ + if (FirePrimaryLate) { + if ((*twPtr->FirePrimaryFunction)(weaponPtr)) { + if (twPtr->PrimaryMuzzleFlash) { + if (twPtr->PrimaryAmmoID==AMMO_PARTICLE_BEAM) { + AddLightingEffectToObject(Player,LFX_PARTICLECANNON); + } else { + AddLightingEffectToObject(Player,LFX_MUZZLEFLASH); + } + } + } + } else if (FireSecondaryLate) { + if (twPtr->SecondaryMuzzleFlash) { + if ((*twPtr->FireSecondaryFunction)(weaponPtr)) { + AddLightingEffectToObject(Player,LFX_MUZZLEFLASH); + } + } + } + /* It ignores all the things that are pipeline specific, like the return * + * condition of the fire function, and won't work for melee weapons. */ + +} + +void PositionPlayersWeaponMuzzleFlash(void) +{ + int size = 65536*3/4 - (FastRandom()&16383); + int length = size; + + if (PWMFSDP) { +// textprint("Hierarchical Muzzle Flash.\n"); + + PlayersWeaponMuzzleFlash.ObWorld=PWMFSDP->World_Offset; + PlayersWeaponMuzzleFlash.ObMat=PWMFSDP->SecMat; + return; + + } + + { + + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + if (weaponPtr->WeaponIDNumber==WEAPON_SMARTGUN) length*=2; + + } + + { + VECTORCH v = CentreOfMuzzleOffset; + // int disp = MUL_FIXED(MuzzleFlashLength,length); + + RotateVector(&v,&PlayersWeapon.ObMat); + + v.vx+=PlayersWeapon.ObWorld.vx; + v.vy+=PlayersWeapon.ObWorld.vy; + v.vz+=PlayersWeapon.ObWorld.vz; + /* position the muzzle flash in world space */ + PlayersWeaponMuzzleFlash.ObWorld.vx = v.vx+MUL_FIXED(200,PlayersWeapon.ObMat.mat31); + PlayersWeaponMuzzleFlash.ObWorld.vy = v.vy+MUL_FIXED(200,PlayersWeapon.ObMat.mat32); + PlayersWeaponMuzzleFlash.ObWorld.vz = v.vz+MUL_FIXED(200,PlayersWeapon.ObMat.mat33); + // PlayersWeaponMuzzleFlash.ObWorld.vx = v.vx+MUL_FIXED(disp,PlayersWeapon.ObMat.mat31); + // PlayersWeaponMuzzleFlash.ObWorld.vy = v.vy+MUL_FIXED(disp,PlayersWeapon.ObMat.mat32); + // PlayersWeaponMuzzleFlash.ObWorld.vz = v.vz+MUL_FIXED(disp,PlayersWeapon.ObMat.mat33); + } + + /* calculate it's view space position */ + { + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + MATRIXCH matrix = VDBPtr->VDB_Mat; + + PlayersWeaponMuzzleFlash.ObView.vx = PlayersWeaponMuzzleFlash.ObWorld.vx - VDBPtr->VDB_World.vx; + PlayersWeaponMuzzleFlash.ObView.vy = PlayersWeaponMuzzleFlash.ObWorld.vy - VDBPtr->VDB_World.vy; + PlayersWeaponMuzzleFlash.ObView.vz = PlayersWeaponMuzzleFlash.ObWorld.vz - VDBPtr->VDB_World.vz; + RotateVector(&PlayersWeaponMuzzleFlash.ObView, &matrix); + } + + /* align the muzzle flash with the gun */ + PlayersWeaponMuzzleFlash.ObMat.mat11 = MUL_FIXED(size,PlayersWeapon.ObMat.mat11); + PlayersWeaponMuzzleFlash.ObMat.mat12 = MUL_FIXED(size,PlayersWeapon.ObMat.mat12); + PlayersWeaponMuzzleFlash.ObMat.mat13 = MUL_FIXED(size,PlayersWeapon.ObMat.mat13); + + PlayersWeaponMuzzleFlash.ObMat.mat21 = MUL_FIXED(size,PlayersWeapon.ObMat.mat21); + PlayersWeaponMuzzleFlash.ObMat.mat22 = MUL_FIXED(size,PlayersWeapon.ObMat.mat22); + PlayersWeaponMuzzleFlash.ObMat.mat23 = MUL_FIXED(size,PlayersWeapon.ObMat.mat23); + + PlayersWeaponMuzzleFlash.ObMat.mat31 = MUL_FIXED(length,PlayersWeapon.ObMat.mat31); + PlayersWeaponMuzzleFlash.ObMat.mat32 = MUL_FIXED(length,PlayersWeapon.ObMat.mat32); + PlayersWeaponMuzzleFlash.ObMat.mat33 = MUL_FIXED(length,PlayersWeapon.ObMat.mat33); + + /* rotate flash around in random multiples of 60 degrees */ + { + MATRIXCH mat; + extern int cosine[], sine[]; + int angle = (FastRandom()%6)*683; + int cos = GetCos(angle); + int sin = GetSin(angle); + mat.mat11 = cos; + mat.mat12 = sin; + mat.mat13 = 0; + mat.mat21 = -sin; + mat.mat22 = cos; + mat.mat23 = 0; + mat.mat31 = 0; + mat.mat32 = 0; + mat.mat33 = 65536; + MatrixMultiply(&PlayersWeaponMuzzleFlash.ObMat,&mat,&PlayersWeaponMuzzleFlash.ObMat); + } + +} + + + +static void StateDependentMovement(PLAYER_STATUS *playerStatusPtr, PLAYER_WEAPON_DATA *weaponPtr) +{ + TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (twPtr->WeaponStateFunction[weaponPtr->CurrentState]!=NULL) { + (*twPtr->WeaponStateFunction[weaponPtr->CurrentState])((void *)playerStatusPtr,weaponPtr); + } + + if (twPtr->UseStateMovement==0) { + + /* Judder is now in targeting.c! */ + return; + } + + /* Handle on-screen movement of gun */ + switch(weaponPtr->CurrentState) + { + case WEAPONSTATE_SWAPPING_IN: + case WEAPONSTATE_SWAPPING_OUT: + { + //VECTORCH gunOffset = twPtr->RestPosition; + VECTORCH gunOffset = PlayersWeaponCameraOffset; + int offset; + + /* scroll old weapon down screen & new weapon up */ + if (playerStatusPtr->SwapToWeaponSlot != WEAPON_FINISHED_SWAPPING) + { + offset = 65536-weaponPtr->StateTimeOutCounter; + } + else + { + offset = weaponPtr->StateTimeOutCounter; + } + + /* slide a bit to the right when swapping */ + weaponPtr->DirectionOffset.EulerX =(offset>>7); + weaponPtr->PositionOffset.vx = MUL_FIXED(offset,gunOffset.vx); + weaponPtr->PositionOffset.vy = MUL_FIXED(offset,gunOffset.vy); + weaponPtr->PositionOffset.vz = MUL_FIXED(-offset,gunOffset.vz); + + break; + + } + case WEAPONSTATE_FIRING_PRIMARY: + { + if (twPtr->PrimaryIsRapidFire) + { + /* jiggle the weapon around when you shoot */ + weaponPtr->PositionOffset.vz = (FastRandom()&twPtr->RecoilMaxRandomZ) - twPtr->RecoilMaxZ; + weaponPtr->DirectionOffset.EulerX = (FastRandom()&twPtr->RecoilMaxXTilt)-twPtr->RecoilMaxXTilt/2; + weaponPtr->DirectionOffset.EulerY = (FastRandom()&twPtr->RecoilMaxYTilt)-twPtr->RecoilMaxYTilt/2; + + HeadOrientation.EulerX = ((FastRandom()&31)-16)&4095; + } + else + { + HeadOrientation.EulerX = 4095-32; + } + break; + } + case WEAPONSTATE_RECOIL_PRIMARY: + { + int offset = 65536-weaponPtr->StateTimeOutCounter; + + weaponPtr->PositionOffset.vz = -MUL_FIXED(offset,twPtr->RecoilMaxZ); + weaponPtr->DirectionOffset.EulerX =-MUL_FIXED(offset,twPtr->RecoilMaxXTilt); + break; + } + case WEAPONSTATE_RECOIL_SECONDARY: + { + int offset = 65536-weaponPtr->StateTimeOutCounter; + + weaponPtr->PositionOffset.vz = -MUL_FIXED(offset,twPtr->RecoilMaxZ); + weaponPtr->DirectionOffset.EulerX =-MUL_FIXED(offset,twPtr->RecoilMaxXTilt); + break; + } + + + default: + { + /* recentre offsets */ + int linearCenteringSpeed = MUL_FIXED(300,NormalFrameTime); + int rotationalCenteringSpeed = MUL_FIXED(1500,NormalFrameTime); + if (weaponPtr->PositionOffset.vx > 0 ) + { + weaponPtr->PositionOffset.vx -= linearCenteringSpeed; + if (weaponPtr->PositionOffset.vx < 0) weaponPtr->PositionOffset.vx = 0; + } + else if (weaponPtr->PositionOffset.vx < 0 ) + { + weaponPtr->PositionOffset.vx += linearCenteringSpeed; + if (weaponPtr->PositionOffset.vx > 0) weaponPtr->PositionOffset.vx = 0; + } + + if (weaponPtr->PositionOffset.vy > 0 ) + { + weaponPtr->PositionOffset.vy -= linearCenteringSpeed; + if (weaponPtr->PositionOffset.vy < 0) weaponPtr->PositionOffset.vy = 0; + } + else if (weaponPtr->PositionOffset.vy < 0 ) + { + weaponPtr->PositionOffset.vy += linearCenteringSpeed; + if (weaponPtr->PositionOffset.vy > 0) weaponPtr->PositionOffset.vy = 0; + } + + if (weaponPtr->PositionOffset.vz > 0 ) + { + weaponPtr->PositionOffset.vz -= linearCenteringSpeed; + if (weaponPtr->PositionOffset.vz < 0) weaponPtr->PositionOffset.vz = 0; + } + else if (weaponPtr->PositionOffset.vz < 0 ) + { + weaponPtr->PositionOffset.vz += linearCenteringSpeed; + if (weaponPtr->PositionOffset.vz > 0) weaponPtr->PositionOffset.vz = 0; + } + + if (weaponPtr->DirectionOffset.EulerX > 0 ) + { + weaponPtr->DirectionOffset.EulerX -= rotationalCenteringSpeed; + if (weaponPtr->DirectionOffset.EulerX < 0) weaponPtr->DirectionOffset.EulerX = 0; + } + else if (weaponPtr->DirectionOffset.EulerX < 0 ) + { + weaponPtr->DirectionOffset.EulerX += rotationalCenteringSpeed; + if (weaponPtr->DirectionOffset.EulerX > 0) weaponPtr->DirectionOffset.EulerX = 0; + } + + if (weaponPtr->DirectionOffset.EulerY > 0 ) + { + weaponPtr->DirectionOffset.EulerY -= rotationalCenteringSpeed; + if (weaponPtr->DirectionOffset.EulerY < 0) weaponPtr->DirectionOffset.EulerY = 0; + } + else if (weaponPtr->DirectionOffset.EulerY < 0 ) + { + weaponPtr->DirectionOffset.EulerY += rotationalCenteringSpeed; + if (weaponPtr->DirectionOffset.EulerY > 0) weaponPtr->DirectionOffset.EulerY = 0; + } + + if (weaponPtr->DirectionOffset.EulerZ > 0 ) + { + weaponPtr->DirectionOffset.EulerZ -= rotationalCenteringSpeed; + if (weaponPtr->DirectionOffset.EulerZ < 0) weaponPtr->DirectionOffset.EulerZ = 0; + } + else if (weaponPtr->DirectionOffset.EulerZ < 0 ) + { + weaponPtr->DirectionOffset.EulerZ += rotationalCenteringSpeed; + if (weaponPtr->DirectionOffset.EulerZ > 0) weaponPtr->DirectionOffset.EulerZ = 0; + } + + break; + } + + + } + +} + + + +extern void UpdateWeaponShape(void) +{ + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + /* player's current weapon */ + GLOBALASSERT(playerStatusPtr->SelectedWeaponSlotWeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + + /* Player doesn't have a weapon! This will eventually be changed into an assertion + that the player *does* have a weapon */ + if (weaponPtr->WeaponIDNumber == NULL_WEAPON) + return; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + GrabWeaponShape(weaponPtr); + + if (!(twPtr->PrimaryIsMeleeWeapon)) GrabMuzzleFlashShape(twPtr); + + PlayersWeapon.ObTxAnimCtrlBlks=weaponPtr->TxAnimCtrl; + if (twPtr->HasShapeAnimation) { + PlayersWeapon.ShapeAnimControlBlock=&weaponPtr->ShpAnimCtrl; + } else { + PlayersWeapon.ShapeAnimControlBlock=NULL; + } + +} + +void GetHierarchicalWeapon(char *riffname, char *hierarchyname, int sequence_type, int sub_sequence) { + + extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); + SECTION *root_section; + SECTION_DATA *camera_section; + + root_section=GetNamedHierarchyFromLibrary(riffname,hierarchyname); + + GLOBALASSERT(root_section); + + Dispel_HModel(&PlayersWeaponHModelController); + Create_HModel(&PlayersWeaponHModelController,root_section); + InitHModelSequence(&PlayersWeaponHModelController,sequence_type,sub_sequence,ONE_FIXED); // Was >>3 + + /* Causes that 'one frame' flicker? */ + //ProveHModel(&PlayersWeaponHModelController,&PlayersWeapon); + + PlayersWeapon.HModelControlBlock=&PlayersWeaponHModelController; + PlayersWeapon.HModelControlBlock->Playing=1; + PlayersWeapon.HModelControlBlock->Looped=1; + + PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"dum flash"); + if (PWMFSDP==NULL) { + PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum flash"); + /* ?&$(*"*&^ pred pistol!!! */ + if (PWMFSDP==NULL) { + PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum Flash"); + } + } + /* Could be NULL though, I don't care at this stage. */ + + camera_section=GetThisSectionData(PlayersWeaponHModelController.section_data,"Camera Root"); + + if (camera_section) { + //PlayersWeaponCameraOffset=camera_section->sempai->sequence_array->first_frame->Offset; + GetKeyFrameOffset(camera_section->sempai->sequence_array->first_frame,&PlayersWeaponCameraOffset); + PlayersWeaponCameraOffset.vx=-PlayersWeaponCameraOffset.vx; + PlayersWeaponCameraOffset.vy=-PlayersWeaponCameraOffset.vy; + PlayersWeaponCameraOffset.vz=-PlayersWeaponCameraOffset.vz; + } else { + GLOBALASSERT(0); + /* If you really want, you could do something like... * + PlayersWeaponCameraOffset=twPtr->RestPosition; + * But that would cause a compiler error. */ + } + + +} + +void GrabWeaponShape(PLAYER_WEAPON_DATA *weaponPtr) +{ + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + /* if there is no shape name then return */ + if (twPtr->WeaponShapeName == NULL) return; + + PlayersWeapon.ObShape = GetLoadedShapeMSL(twPtr->WeaponShapeName); + LOCALASSERT(PlayersWeapon.ObShape>0); + + PlayersWeapon.ObFlags = ObFlag_VertexHazing|ObFlag_MultLSrc; + PlayersWeapon.ObFlags2 = 0; + PlayersWeapon.ObFlags3 = 0; + + PlayersWeapon.ObLightType = LightType_PerVertex; + + PlayersWeapon.HModelControlBlock=NULL; + + //WeaponSetStartFrame(NULL,NULL); + FindEndOfShape(&CentreOfMuzzleOffset,PlayersWeapon.ObShape); + + if (twPtr->HierarchyName) { + + /* Bit of a cheap test, I know. */ + GetHierarchicalWeapon(twPtr->RiffName,twPtr->HierarchyName,twPtr->InitialSequenceType,twPtr->InitialSubSequence); + + } else { + Dispel_HModel(&PlayersWeaponHModelController); + PWMFSDP=NULL; + PlayersWeaponCameraOffset=twPtr->RestPosition; + } + + if (twPtr->WeaponInitFunction!=NULL) { + (*twPtr->WeaponInitFunction)(weaponPtr); + } + +} + +void GrabMuzzleFlashShape(TEMPLATE_WEAPON_DATA *twPtr) +{ + #if 0 + /* if there is no shape name then return */ + if (twPtr->MuzzleFlashShapeName == NULL) return; + + /* otherwise setup displayblock */ + PlayersWeaponMuzzleFlash.ObShape = GetLoadedShapeMSL(twPtr->MuzzleFlashShapeName); + LOCALASSERT(PlayersWeaponMuzzleFlash.ObShape>0); + + PlayersWeaponMuzzleFlash.ObFlags = ObFlag_NoInfLSrc|ObFlag_MultLSrc; + PlayersWeaponMuzzleFlash.ObFlags2 = 0; + PlayersWeaponMuzzleFlash.ObFlags3 = ObFlag3_NoLightDot; + + PlayersWeaponMuzzleFlash.ObLightType = LightType_PerVertex; + + { + SHAPEHEADER *shapePtr = GetShapeData(PlayersWeaponMuzzleFlash.ObShape); + MuzzleFlashLength = -shapePtr->shapeminz; + } + #endif +} + + +void FindEndOfShape(VECTORCH* endPositionPtr, int shapeIndex) +{ + extern int SetupPolygonAccessFromShapeIndex(int shapeIndex); + int max_z = 0; + int pointsFound = 0; + int numberOfItems; + + { + SHAPEHEADER *shapePtr = GetShapeData(shapeIndex); + LOCALASSERT(shapePtr); + max_z = shapePtr->shapemaxz; + } + endPositionPtr->vx = 0; + endPositionPtr->vy = 0; + endPositionPtr->vz = max_z; + + numberOfItems = SetupPolygonAccessFromShapeIndex(shapeIndex); + + /* go through polys and get the average position of all the + points whose z value is near the max z of the shape */ + while(numberOfItems) + { + AccessNextPolygon(); + { + struct ColPolyTag polyData; + GetPolygonVertices(&polyData); + + { + VECTORCH *vertexPtr = &polyData.PolyPoint[0]; + int noOfVertices = polyData.NumberOfVertices; + do + { + int z = vertexPtr->vz; + + if (z >= max_z-5) + { + endPositionPtr->vx += vertexPtr->vx; + endPositionPtr->vy += vertexPtr->vy; + pointsFound++; + } + + vertexPtr++; + noOfVertices--; + } + while(noOfVertices); + } + } + numberOfItems--; + } + LOCALASSERT(pointsFound!=0); + endPositionPtr->vx /= pointsFound; + endPositionPtr->vy /= pointsFound; + + return; +} + + + +static void FireLineOfSightAmmo(enum AMMO_ID AmmoID, VECTORCH* sourcePtr, VECTORCH* directionPtr, int multiple) +{ + #if 0 + LOS_Lambda = 10000000; + LOS_ObjectHitPtr = 0; + LOS_HModel_Section=NULL; + { + extern int NumActiveBlocks; + extern DISPLAYBLOCK* ActiveBlockList[]; + int numberOfObjects = NumActiveBlocks; + + while (numberOfObjects--) + { + DISPLAYBLOCK* objectPtr = ActiveBlockList[numberOfObjects]; + VECTORCH alpha = *sourcePtr; + VECTORCH beta = *directionPtr; + GLOBALASSERT(objectPtr); + + CheckForVectorIntersectionWith3dObject(objectPtr, &alpha, &beta,1); + } + } + #else + FindPolygonInLineOfSight(directionPtr,sourcePtr,0,NULL); + #endif + + if (LOS_ObjectHitPtr) + { + /* this fn needs updating to take amount of damage into account etc. */ + if (LOS_ObjectHitPtr->ObStrategyBlock) { + if ((LOS_ObjectHitPtr->ObStrategyBlock->SBdptr)&&(LOS_HModel_Section)) { + GLOBALASSERT(LOS_ObjectHitPtr->ObStrategyBlock->SBdptr->HModelControlBlock==LOS_HModel_Section->my_controller); + } + } + + HandleWeaponImpact(&LOS_Point,LOS_ObjectHitPtr->ObStrategyBlock,AmmoID,directionPtr, multiple*ONE_FIXED, LOS_HModel_Section); + } +} + + + +static void CalculateTorque(EULER *rotationPtr, VECTORCH *directionPtr, STRATEGYBLOCK *sbPtr) +{ + VECTORCH point,absPoint; + int intersectionPlane; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + { + MATRIXCH mat=dynPtr->OrientMat; + TransposeMatrixCH(&mat); + + point.vx = directionPtr->vx - dynPtr->Position.vx; + point.vy = directionPtr->vy - dynPtr->Position.vy; + point.vz = directionPtr->vz - dynPtr->Position.vz; + + RotateVector(&point,&mat); + } + + absPoint=point; + if (absPoint.vx<0) absPoint.vx = -absPoint.vx; + if (absPoint.vy<0) absPoint.vy = -absPoint.vy; + if (absPoint.vz<0) absPoint.vz = -absPoint.vz; + + /* KJL 16:59:03 03/06/97 - paranoia check */ + LOCALASSERT(absPoint.vx>=0); + LOCALASSERT(absPoint.vy>=0); + LOCALASSERT(absPoint.vz>=0); + + if (absPoint.vx > absPoint.vz) + { + if (absPoint.vx > absPoint.vy) + { + intersectionPlane = ix; + } + else + { + intersectionPlane = iy; + } + } + else + { + if (absPoint.vz > absPoint.vy) + { + intersectionPlane = iz; + } + else + { + intersectionPlane = iy; + } + } + + switch (intersectionPlane) + { + case ix: + { + + rotationPtr->EulerX = 0; + rotationPtr->EulerY = -DIV_FIXED(point.vz,point.vx); + rotationPtr->EulerZ = DIV_FIXED(point.vy,point.vx); + + break; + } + case iy: + { + rotationPtr->EulerX = DIV_FIXED(point.vz,point.vy); + rotationPtr->EulerY = 0; + rotationPtr->EulerZ = -DIV_FIXED(point.vx,point.vy); + + break; + } + case iz: + { + rotationPtr->EulerX = -DIV_FIXED(point.vy,point.vz); + rotationPtr->EulerY = DIV_FIXED(point.vx,point.vz); + rotationPtr->EulerZ = 0; + + break; + } + default: + break; + } + +} + + +static void CalculateTorqueAtPoint(EULER *rotationPtr, VECTORCH *pointPtr, STRATEGYBLOCK *sbPtr) +{ + #if 0 + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + VECTORCH point; + VECTORCH rotationDirection; + int rotationMagnitude; + + point.vx = pointPtr->vx - dynPtr->Position.vx; + point.vy = pointPtr->vy - dynPtr->Position.vy; + point.vz = pointPtr->vz - dynPtr->Position.vz; + + CrossProduct(pointPtr, directionPtr, &rotationDirection); + + rotationMagnitude = Magnitude(&rotationDirection); + + /* normalise direction */ + rotationDirection.vx = DIV_FIXED(rotationDirection.vx,rotationMagnitude); + rotationDirection.vy = DIV_FIXED(rotationDirection.vy,rotationMagnitude); + rotationDirection.vz = DIV_FIXED(rotationDirection.vz,rotationMagnitude); + + { + // MATRIXCH matrix,mat; + // MakeMatrixFromDirection(directionPtr, &matrix); + + // MatrixMultiply(&mat,&matrix,&mat); + // MatrixToEuler(&mat,rotationPtr); + } + + #else + VECTORCH normal,point; + int intersectionPlane; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + /* if the strategy block doesn't have a dynamics or display block, skip it */ + if (!(dynPtr) || !(sbPtr->SBdptr)) return; + { + MATRIXCH mat=dynPtr->OrientMat; + TransposeMatrixCH(&mat); + + point.vx = pointPtr->vx - dynPtr->Position.vx; + point.vy = pointPtr->vy - dynPtr->Position.vy; + point.vz = pointPtr->vz - dynPtr->Position.vz; + + RotateVector(&point,&mat); + + // normal = *normalPtr; + // RotateVector(&normal,&mat); + normal = point; + } + + { + VECTORCH absNormal = normal; + if (absNormal.vx<0) absNormal.vx=-absNormal.vx; + if (absNormal.vy<0) absNormal.vy=-absNormal.vy; + if (absNormal.vz<0) absNormal.vz=-absNormal.vz; + + if (absNormal.vx > absNormal.vy) + { + if (absNormal.vx > absNormal.vz) + { + intersectionPlane = ix; + } + else + { + intersectionPlane = iz; + } + } + else + { + if (absNormal.vy > absNormal.vz) + { + intersectionPlane = iy; + } + else + { + intersectionPlane = iz; + } + } + } + + + + switch (intersectionPlane) + { + case ix: + { + + rotationPtr->EulerX = 0; + if (point.vx>0) + { + rotationPtr->EulerY = -point.vz; + rotationPtr->EulerZ = point.vy; + } + else + { + rotationPtr->EulerY = point.vz; + rotationPtr->EulerZ = -point.vy; + } + break; + } + case iy: + { + rotationPtr->EulerY = 0; + + if (point.vy>0) + { + rotationPtr->EulerX = point.vz; + rotationPtr->EulerZ = -point.vx; + } + else + { + rotationPtr->EulerX = -point.vz; + rotationPtr->EulerZ = point.vx; + } + break; + } + case iz: + { + rotationPtr->EulerZ = 0; + if (point.vz>0) + { + rotationPtr->EulerX = -point.vy; + rotationPtr->EulerY = point.vx; + } + else + { + rotationPtr->EulerX = point.vy; + rotationPtr->EulerY = -point.vx; + } + break; + } + default: + break; + } + { + SHAPEHEADER *shapePtr = GetShapeData(sbPtr->SBdptr->ObShape); + rotationPtr->EulerX=DIV_FIXED(rotationPtr->EulerX, shapePtr->shaperadius); + rotationPtr->EulerY=DIV_FIXED(rotationPtr->EulerY, shapePtr->shaperadius); + rotationPtr->EulerZ=DIV_FIXED(rotationPtr->EulerZ, shapePtr->shaperadius); + } + #if 0 + { + MATRIXCH mat; + CreateEulerMatrix(rotationPtr, &mat); + TransposeMatrixCH(&mat); + + MatrixMultiply(&mat,&(dynPtr->OrientMat),&mat); + MatrixToEuler(&mat,rotationPtr); + + } + #else + { +// RotateVector((VECTORCH *)(rotationPtr),&(dynPtr->OrientMat)); + } + #endif + #endif +} + + + +void AlienTailTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) +{ +// TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + VECTORCH startDir = {0,-65536,0}; + VECTORCH endDir = {37837,37837,37837}; + VECTORCH direction; + int timeLeft = (weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)? weaponPtr->StateTimeOutCounter:65536-weaponPtr->StateTimeOutCounter; + int timeDone = 65536-timeLeft; + + weaponPtr->PositionOffset.vx = MUL_FIXED(timeDone,300); + weaponPtr->PositionOffset.vy = MUL_FIXED(timeDone,0); + weaponPtr->PositionOffset.vz = MUL_FIXED(timeDone,500); + + direction.vx = WideMul2NarrowDiv(startDir.vx, timeLeft, endDir.vx, timeDone, ONE_FIXED); + direction.vy = WideMul2NarrowDiv(startDir.vy, timeLeft, endDir.vy, timeDone, ONE_FIXED); + direction.vz = WideMul2NarrowDiv(startDir.vz, timeLeft, endDir.vz, timeDone, ONE_FIXED); + Normalise(&direction); + + MakeMatrixFromDirection(&direction,&(PlayersWeapon.ObMat)); + { + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + MATRIXCH matrix = VDBPtr->VDB_Mat; + + TransposeMatrixCH(&matrix); + MatrixMultiply(&matrix,&PlayersWeapon.ObMat,&PlayersWeapon.ObMat); + } +} + +void MeleeWeaponNullTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) +{ + weaponPtr->PositionOffset.vz = -100000; +} + +void AlienClawTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) +{ +// TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + VECTORCH startDir = {-65536,0,0}; + VECTORCH endDir = {-2,0,65535}; + VECTORCH direction; + int timeLeft = weaponPtr->StateTimeOutCounter; + int timeDone = 65536-timeLeft; + + weaponPtr->PositionOffset.vx = MUL_FIXED(timeDone,600); + weaponPtr->PositionOffset.vy = MUL_FIXED(timeDone,-200); + weaponPtr->PositionOffset.vz = MUL_FIXED(timeDone,400); + + direction.vx = WideMul2NarrowDiv(startDir.vx, timeLeft, endDir.vx, timeDone, ONE_FIXED); + direction.vy = WideMul2NarrowDiv(startDir.vy, timeLeft, endDir.vy, timeDone, ONE_FIXED); + direction.vz = WideMul2NarrowDiv(startDir.vz, timeLeft, endDir.vz, timeDone, ONE_FIXED); + Normalise(&direction); +// direction = endDir; + + MakeMatrixFromDirection(&direction,&(PlayersWeapon.ObMat)); + { + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + MATRIXCH matrix = VDBPtr->VDB_Mat; + + TransposeMatrixCH(&matrix); + MatrixMultiply(&matrix,&PlayersWeapon.ObMat,&PlayersWeapon.ObMat); + } + PlayersWeapon.ObMat.mat21 = -PlayersWeapon.ObMat.mat21; + PlayersWeapon.ObMat.mat22 = -PlayersWeapon.ObMat.mat22; + PlayersWeapon.ObMat.mat23 = -PlayersWeapon.ObMat.mat23; + PlayersWeapon.ObMat.mat11 = -PlayersWeapon.ObMat.mat11; + PlayersWeapon.ObMat.mat12 = -PlayersWeapon.ObMat.mat12; + PlayersWeapon.ObMat.mat13 = -PlayersWeapon.ObMat.mat13; +} +void AlienClawEndTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) +{ +// TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + VECTORCH startDir = {-2,0,65535}; + VECTORCH endDir = {-2,0,65535}; + VECTORCH direction; + int timeLeft = weaponPtr->StateTimeOutCounter; + int timeDone = 65536-timeLeft; + + weaponPtr->PositionOffset.vx = 600+MUL_FIXED(timeDone,200); + weaponPtr->PositionOffset.vy = -200+MUL_FIXED(timeDone,300); + weaponPtr->PositionOffset.vz = 400+MUL_FIXED(timeDone,-400); + + direction.vx = WideMul2NarrowDiv(startDir.vx, timeLeft, endDir.vx, timeDone, ONE_FIXED); + direction.vy = WideMul2NarrowDiv(startDir.vy, timeLeft, endDir.vy, timeDone, ONE_FIXED); + direction.vz = WideMul2NarrowDiv(startDir.vz, timeLeft, endDir.vz, timeDone, ONE_FIXED); + Normalise(&direction); + + MakeMatrixFromDirection(&direction,&(PlayersWeapon.ObMat)); + { + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + MATRIXCH matrix = VDBPtr->VDB_Mat; + + TransposeMatrixCH(&matrix); + MatrixMultiply(&matrix,&PlayersWeapon.ObMat,&PlayersWeapon.ObMat); + } + PlayersWeapon.ObMat.mat21 = -PlayersWeapon.ObMat.mat21; + PlayersWeapon.ObMat.mat22 = -PlayersWeapon.ObMat.mat22; + PlayersWeapon.ObMat.mat23 = -PlayersWeapon.ObMat.mat23; + PlayersWeapon.ObMat.mat11 = -PlayersWeapon.ObMat.mat11; + PlayersWeapon.ObMat.mat12 = -PlayersWeapon.ObMat.mat12; + PlayersWeapon.ObMat.mat13 = -PlayersWeapon.ObMat.mat13; +} + +void PredWristbladeTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) +{ +// TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + VECTORCH startDir = {0,0,65536}; + VECTORCH endDir = {-37837,-37837,37837}; + VECTORCH direction; + int timeLeft = ((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)||(weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY))? weaponPtr->StateTimeOutCounter:65536-weaponPtr->StateTimeOutCounter; + int timeDone = 65536-timeLeft; + + weaponPtr->PositionOffset.vx = MUL_FIXED(timeDone,-200); + weaponPtr->PositionOffset.vy = MUL_FIXED(timeDone,-50); + weaponPtr->PositionOffset.vz = MUL_FIXED(timeDone,900); + + direction.vx = WideMul2NarrowDiv(startDir.vx, timeLeft, endDir.vx, timeDone, ONE_FIXED); + direction.vy = WideMul2NarrowDiv(startDir.vy, timeLeft, endDir.vy, timeDone, ONE_FIXED); + direction.vz = WideMul2NarrowDiv(startDir.vz, timeLeft, endDir.vz, timeDone, ONE_FIXED); + Normalise(&direction); + + MakeMatrixFromDirection(&direction,&(PlayersWeapon.ObMat)); + { + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + MATRIXCH matrix = VDBPtr->VDB_Mat; + + TransposeMatrixCH(&matrix); + MatrixMultiply(&matrix,&PlayersWeapon.ObMat,&PlayersWeapon.ObMat); + } +} + + + + + +/* in mm */ +//#define ACTIVATION_Z_RANGE 3000 +//#define ACTIVATION_X_RANGE 500 +//#define ACTIVATION_Y_RANGE 500 + +#define ACTIVATION_Z_RANGE 4000 +#define ACTIVATION_X_RANGE 2000 +#define ACTIVATION_Y_RANGE 2000 + +int DamageObjectInLineOfSight(PLAYER_WEAPON_DATA *weaponPtr) +{ + int numberOfObjects = NumOnScreenBlocks; + enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID; + + while (numberOfObjects) + { + DISPLAYBLOCK* objectPtr = OnScreenBlockList[--numberOfObjects]; + STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock; + GLOBALASSERT(objectPtr); + + /* does object have a strategy block? */ + if (sbPtr) + { + /* is it in range? */ + if (objectPtr->ObView.vz > 0 && objectPtr->ObView.vz < ACTIVATION_Z_RANGE) + { + int screenX = objectPtr->ObView.vx; + int screenY = objectPtr->ObView.vy; + + if (screenX<0) screenX=-screenX; + if (screenY<0) screenY=-screenY; + screenX-=objectPtr->ObMaxX; + screenY-=objectPtr->ObMaxY; + + if (screenX < ACTIVATION_X_RANGE && screenY < ACTIVATION_Y_RANGE) + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + if (dynPtr) + { + int magnitudeOfForce = (5000*TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty].Cutting) / dynPtr->Mass; + dynPtr->LinImpulse.vx += MUL_FIXED(Player->ObMat.mat31,magnitudeOfForce); + dynPtr->LinImpulse.vy += MUL_FIXED(Player->ObMat.mat32,magnitudeOfForce); + dynPtr->LinImpulse.vz += MUL_FIXED(Player->ObMat.mat33,magnitudeOfForce); + CauseDamageToObject(sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + } + } + } + + + return(1); +} + + +void PredDiscThrowTrajectory(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) +{ +// TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + EULER startorient = {0,0,1024}; + EULER endorient = {-1024,0,1024}; + EULER orient; + VECTORCH startpoint= {400,-50,900}; + VECTORCH endpoint= {-800,-50,200}; + int timeLeft = weaponPtr->StateTimeOutCounter; + int timeDone = 65536-timeLeft; + + weaponPtr->PositionOffset.vx = WideMul2NarrowDiv(startpoint.vx, timeLeft, endpoint.vx, timeDone, ONE_FIXED); + weaponPtr->PositionOffset.vy = WideMul2NarrowDiv(startpoint.vy, timeLeft, endpoint.vy, timeDone, ONE_FIXED); + weaponPtr->PositionOffset.vz = WideMul2NarrowDiv(startpoint.vz, timeLeft, endpoint.vz, timeDone, ONE_FIXED); + + orient.EulerX = WideMul2NarrowDiv(startorient.EulerX, timeLeft, endorient.EulerX, timeDone, ONE_FIXED); + orient.EulerY = WideMul2NarrowDiv(startorient.EulerY, timeLeft, endorient.EulerY, timeDone, ONE_FIXED); + orient.EulerZ = WideMul2NarrowDiv(startorient.EulerZ, timeLeft, endorient.EulerZ, timeDone, ONE_FIXED); + + CreateEulerMatrix(&orient,&(PlayersWeapon.ObMat)); + + { + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + MATRIXCH matrix = VDBPtr->VDB_Mat; + + TransposeMatrixCH(&matrix); + MatrixMultiply(&matrix,&PlayersWeapon.ObMat,&PlayersWeapon.ObMat); + } +} + +static void DamageDamageBlock(DAMAGEBLOCK *DBPtr, DAMAGE_PROFILE *damage, int multiple) { + + /* Separate function to ease writing clarity. */ + + int ArmourDamage; + int HealthDamage; + int Fraction; + int Integer; + + Fraction=multiple&(ONE_FIXED-1); + Integer=multiple>>ONE_FIXED_SHIFT; + + /* We must apply damage sequentially. Fraction first, then each 'multiple'. + Otherwise, an armour damaging attack hitting multiple times in one frame + would behave differently depending on the framerate. Sure, that case might + never arise, but that's not the point! + */ + + if (DBPtr->SB_H_flags.Indestructable) { + return; + } + + if (Fraction) { + + ArmourDamage=0; + HealthDamage=0; + + if (damage->Impact) { + int unblocked,tempdamage; + /* Impact damage. */ + tempdamage=damage->Impact*Fraction; + HealthDamage+=tempdamage/10; + + //unblocked=tempdamage-DBPtr->Armour; + unblocked=MUL_FIXED(((damage->Impact*ONE_FIXED)-DBPtr->Armour),Fraction); + if (unblocked>0) { + HealthDamage+=unblocked; + } + tempdamage>>=4; + if (DBPtr->SB_H_flags.PerfectArmour==0) { + ArmourDamage+=tempdamage; + } + } + + if (damage->Cutting) { + int unblocked,tempdamage; + /* Cutting damage. */ + tempdamage=damage->Cutting*Fraction; + HealthDamage+=tempdamage>>2; + + //unblocked=tempdamage-DBPtr->Armour; + unblocked=MUL_FIXED(((damage->Cutting*ONE_FIXED)-DBPtr->Armour),Fraction); + + if (unblocked>0) { + HealthDamage+=unblocked; + } + tempdamage>>=3; + if (DBPtr->SB_H_flags.PerfectArmour==0) { + ArmourDamage+=tempdamage; + } + } + + if (damage->Penetrative) { + int unblocked,tempdamage; + /* Penetrative damage. */ + tempdamage=damage->Penetrative*Fraction; + HealthDamage+=tempdamage/10; + + //unblocked=tempdamage-(DBPtr->Armour>>6); + unblocked=MUL_FIXED(((damage->Penetrative*ONE_FIXED)-(DBPtr->Armour>>6)),Fraction); + + if (unblocked>0) { + HealthDamage+=unblocked; + } + tempdamage>>=4; + if (DBPtr->SB_H_flags.PerfectArmour==0) { + ArmourDamage+=tempdamage; + } + } + + if ((damage->Fire)&&(DBPtr->SB_H_flags.FireResistant==0)) { + int tempdamage; + /* Fire damage. */ + tempdamage=damage->Fire*Fraction; + if (DBPtr->SB_H_flags.Combustability==2) { + tempdamage<<=1; + } else if (DBPtr->SB_H_flags.Combustability==3) { + tempdamage>>=2; + } + HealthDamage+=tempdamage; + if (DBPtr->SB_H_flags.PerfectArmour==0) { + ArmourDamage+=tempdamage>>3; + } + } + + if ((damage->Electrical)&&(DBPtr->SB_H_flags.ElectricResistant==0)) { + int tempdamage; + /* Electrical damage. */ + tempdamage=damage->Electrical*Fraction; + if (DBPtr->SB_H_flags.ElectricSensitive) { + tempdamage<<=2; + } + HealthDamage+=tempdamage; + } + + if ((damage->Acid)&&(DBPtr->SB_H_flags.AcidResistant==0)) { + int unblocked,tempdamage; + /* Acid damage. */ + tempdamage=damage->Acid*Fraction; + unblocked=0; + if (DBPtr->SB_H_flags.PerfectArmour==0) { + if ((AvP.Difficulty==I_Hard)||(AvP.Difficulty==I_Impossible)) { + ArmourDamage+=tempdamage; + if (ArmourDamage>DBPtr->Armour) { + /* Now we're through. */ + unblocked=tempdamage-DBPtr->Armour; + } + } else { + ArmourDamage+=(tempdamage>>1); + if (ArmourDamage>DBPtr->Armour) { + /* Now we're through. */ + unblocked=tempdamage-(DBPtr->Armour<<1); + } + } + } + if (unblocked>0) { + HealthDamage+=unblocked; + } + } + + /* Apply Damage. */ + + if (ArmourDamage>0) { + if (DBPtr->ArmourArmour=0; + else DBPtr->Armour-=ArmourDamage; + } + + if (HealthDamage>0) { + if (DBPtr->HealthHealth=0; + else DBPtr->Health-=HealthDamage; + } + + } + + /* Now, the integer. */ + + while (Integer) { + + ArmourDamage=0; + HealthDamage=0; + + if (damage->Impact) { + int unblocked,tempdamage; + /* Impact damage. */ + tempdamage=damage->Impact*ONE_FIXED; + HealthDamage+=tempdamage/10; + unblocked=tempdamage-DBPtr->Armour; + if (unblocked>0) { + HealthDamage+=unblocked; + } + tempdamage>>=4; + if (DBPtr->SB_H_flags.PerfectArmour==0) { + ArmourDamage+=tempdamage; + } + } + + if (damage->Cutting) { + int unblocked,tempdamage; + /* Cutting damage. */ + tempdamage=damage->Cutting*ONE_FIXED; + HealthDamage+=tempdamage>>2; + unblocked=tempdamage-DBPtr->Armour; + if (unblocked>0) HealthDamage+=unblocked; + tempdamage>>=3; + if (DBPtr->SB_H_flags.PerfectArmour==0) { + ArmourDamage+=tempdamage; + } + } + + if (damage->Penetrative) { + int unblocked,tempdamage; + /* Penetrative damage. */ + tempdamage=damage->Penetrative*ONE_FIXED; + HealthDamage+=tempdamage/10; + unblocked=tempdamage-(DBPtr->Armour>>6); + if (unblocked>0) { + HealthDamage+=unblocked; + } + tempdamage>>=4; + if (DBPtr->SB_H_flags.PerfectArmour==0) { + ArmourDamage+=tempdamage; + } + } + + if ((damage->Fire)&&(DBPtr->SB_H_flags.FireResistant==0)) { + int tempdamage; + /* Fire damage. */ + tempdamage=damage->Fire*ONE_FIXED; + if (DBPtr->SB_H_flags.Combustability==2) { + tempdamage<<=1; + } else if (DBPtr->SB_H_flags.Combustability==3) { + tempdamage>>=2; + } + HealthDamage+=tempdamage; + if (DBPtr->SB_H_flags.PerfectArmour==0) { + ArmourDamage+=tempdamage>>3; + } + } + + if ((damage->Electrical)&&(DBPtr->SB_H_flags.ElectricResistant==0)) { + int tempdamage; + /* Electrical damage. */ + tempdamage=damage->Electrical*ONE_FIXED; + if (DBPtr->SB_H_flags.ElectricSensitive) { + tempdamage<<=2; + } + HealthDamage+=tempdamage; + } + + if ((damage->Acid)&&(DBPtr->SB_H_flags.AcidResistant==0)) { + int unblocked,tempdamage; + /* Acid damage. */ + tempdamage=damage->Acid*ONE_FIXED; + unblocked=0; + if (DBPtr->SB_H_flags.PerfectArmour==0) { + if ((AvP.Difficulty==I_Hard)||(AvP.Difficulty==I_Impossible)) { + ArmourDamage+=tempdamage; + if (ArmourDamage>DBPtr->Armour) { + /* Now we're through. */ + unblocked=tempdamage-DBPtr->Armour; + } + } else { + ArmourDamage+=(tempdamage>>1); + if (ArmourDamage>DBPtr->Armour) { + /* Now we're through. */ + unblocked=tempdamage-(DBPtr->Armour<<1); + } + } + } + if (unblocked>0) { + HealthDamage+=unblocked; + } + } + + /* Apply Damage. */ + + if (ArmourDamage>0) { + if (DBPtr->ArmourArmour=0; + else DBPtr->Armour-=ArmourDamage; + } + + if (HealthDamage>0) { + if (DBPtr->HealthHealth=0; + else DBPtr->Health-=HealthDamage; + } + + Integer--; + + } + +} + +void InitThisWeapon(PLAYER_WEAPON_DATA *pwPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + int shapenum; + SHAPEHEADER *shptr; + + if (pwPtr->WeaponIDNumber==NULL_WEAPON) { + /* D'oh! */ + pwPtr->TxAnimCtrl=NULL; + pwPtr->ShpAnimCtrl.current.seconds_per_frame=0; + pwPtr->ShpAnimCtrl.current.sequence_no=0; + pwPtr->ShpAnimCtrl.current.start_frame=0; + pwPtr->ShpAnimCtrl.current.end_frame=0; + pwPtr->ShpAnimCtrl.current.default_start_and_end_frames=0; + pwPtr->ShpAnimCtrl.current.reversed=0; + pwPtr->ShpAnimCtrl.current.stop_at_end=0; + pwPtr->ShpAnimCtrl.current.empty=0; + pwPtr->ShpAnimCtrl.current.stop_now=0; + pwPtr->ShpAnimCtrl.current.pause_at_end=0; + pwPtr->ShpAnimCtrl.current.done_a_frame=0; + pwPtr->ShpAnimCtrl.current.sequence=NULL; + pwPtr->ShpAnimCtrl.current.current_frame=0; + pwPtr->ShpAnimCtrl.current.time_to_next_frame=0; + + pwPtr->ShpAnimCtrl.next.seconds_per_frame=0; + pwPtr->ShpAnimCtrl.next.sequence_no=0; + pwPtr->ShpAnimCtrl.next.start_frame=0; + pwPtr->ShpAnimCtrl.next.end_frame=0; + pwPtr->ShpAnimCtrl.next.default_start_and_end_frames=0; + pwPtr->ShpAnimCtrl.next.reversed=0; + pwPtr->ShpAnimCtrl.next.stop_at_end=0; + pwPtr->ShpAnimCtrl.next.empty=0; + pwPtr->ShpAnimCtrl.next.stop_now=0; + pwPtr->ShpAnimCtrl.next.pause_at_end=0; + pwPtr->ShpAnimCtrl.next.done_a_frame=0; + pwPtr->ShpAnimCtrl.next.sequence=NULL; + pwPtr->ShpAnimCtrl.next.current_frame=0; + pwPtr->ShpAnimCtrl.next.time_to_next_frame=0; + + pwPtr->ShpAnimCtrl.finished=0; + pwPtr->ShpAnimCtrl.playing=0; + pwPtr->ShpAnimCtrl.anim_header=NULL; + return; + } + + twPtr=&TemplateWeapon[pwPtr->WeaponIDNumber]; + + if (twPtr->WeaponShapeName==NULL) return; + /* Got to allow for GetLoadedShapeMSL not being bomb-proof. */ + + shapenum = GetLoadedShapeMSL(twPtr->WeaponShapeName); + shptr=GetShapeData(shapenum); + + if (twPtr->HasTextureAnimation) { + int item_num; + TXACTRLBLK **pptxactrlblk; + + pptxactrlblk = &pwPtr->TxAnimCtrl; + + SetupPolygonFlagAccessForShape(shptr); + + for(item_num = 0; item_num < shptr->numitems; item_num ++) + { + POLYHEADER *poly = (POLYHEADER*)(shptr->items[item_num]); + LOCALASSERT(poly); + + if((Request_PolyFlags((void *)poly)) & iflag_txanim) + { + TXACTRLBLK *pnew_txactrlblk; + + pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK)); + + if (pnew_txactrlblk) + { + // We have allocated the new tx anim control block so initialise it + + pnew_txactrlblk->tac_flags = 0; + pnew_txactrlblk->tac_item = item_num; + pnew_txactrlblk->tac_sequence = 0; + pnew_txactrlblk->tac_node = 0; + pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shapenum, item_num); + pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shapenum); + + pnew_txactrlblk->tac_txah.txa_currentframe = 0; + pnew_txactrlblk->tac_txah.txa_flags |= txa_flag_play; + + /* change the value held in pptxactrlblk + which point to the previous structures "next" + pointer*/ + + *pptxactrlblk = pnew_txactrlblk; + pptxactrlblk = &pnew_txactrlblk->tac_next; + } + + } + } + *pptxactrlblk=0; + + } else { + pwPtr->TxAnimCtrl=NULL; + } + + /* Now the shape animation... */ + + if (twPtr->HasShapeAnimation) { + InitShapeAnimationController(&pwPtr->ShpAnimCtrl,shptr); + } else { + pwPtr->ShpAnimCtrl.current.seconds_per_frame=0; + pwPtr->ShpAnimCtrl.current.sequence_no=0; + pwPtr->ShpAnimCtrl.current.start_frame=0; + pwPtr->ShpAnimCtrl.current.end_frame=0; + pwPtr->ShpAnimCtrl.current.default_start_and_end_frames=0; + pwPtr->ShpAnimCtrl.current.reversed=0; + pwPtr->ShpAnimCtrl.current.stop_at_end=0; + pwPtr->ShpAnimCtrl.current.empty=0; + pwPtr->ShpAnimCtrl.current.stop_now=0; + pwPtr->ShpAnimCtrl.current.pause_at_end=0; + pwPtr->ShpAnimCtrl.current.done_a_frame=0; + pwPtr->ShpAnimCtrl.current.sequence=NULL; + pwPtr->ShpAnimCtrl.current.current_frame=0; + pwPtr->ShpAnimCtrl.current.time_to_next_frame=0; + + pwPtr->ShpAnimCtrl.next.seconds_per_frame=0; + pwPtr->ShpAnimCtrl.next.sequence_no=0; + pwPtr->ShpAnimCtrl.next.start_frame=0; + pwPtr->ShpAnimCtrl.next.end_frame=0; + pwPtr->ShpAnimCtrl.next.default_start_and_end_frames=0; + pwPtr->ShpAnimCtrl.next.reversed=0; + pwPtr->ShpAnimCtrl.next.stop_at_end=0; + pwPtr->ShpAnimCtrl.next.empty=0; + pwPtr->ShpAnimCtrl.next.stop_now=0; + pwPtr->ShpAnimCtrl.next.pause_at_end=0; + pwPtr->ShpAnimCtrl.next.done_a_frame=0; + pwPtr->ShpAnimCtrl.next.sequence=NULL; + pwPtr->ShpAnimCtrl.next.current_frame=0; + pwPtr->ShpAnimCtrl.next.time_to_next_frame=0; + + pwPtr->ShpAnimCtrl.finished=0; + pwPtr->ShpAnimCtrl.playing=0; + pwPtr->ShpAnimCtrl.anim_header=NULL; + } +} + +void ParticleBeamSwapping(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + /* Setup animation. */ + SHAPEANIMATIONCONTROLDATA sacd; + InitShapeAnimationControlData(&sacd); + sacd.seconds_per_frame = ONE_FIXED/36; + sacd.sequence_no = 0; + sacd.default_start_and_end_frames = 1; + sacd.reversed = 0; + sacd.stop_at_end = 1; + SetShapeAnimationSequence(&PlayersWeapon, &sacd); + } +} + +void ParticleBeamReadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + DoShapeAnimation(&PlayersWeapon); + +} + +void ParticleBeamUnreadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + /* Start animation. */ + SHAPEANIMATIONCONTROLDATA sacd; + InitShapeAnimationControlData(&sacd); + sacd.seconds_per_frame = ONE_FIXED/36; + sacd.sequence_no = 0; + sacd.default_start_and_end_frames = 1; + sacd.reversed = 1; + sacd.stop_at_end = 1; + SetShapeAnimationSequence(&PlayersWeapon, &sacd); + + } else { + DoShapeAnimation(&PlayersWeapon); + } + +} + +void GrenadeLauncher_UpdateBullets(PLAYER_WEAPON_DATA *weaponPtr) { + + int a; + /* Flags the correct number of bullets as visible... */ + + for (a=0; a<6; a++) { + if (a>(weaponPtr->PrimaryRoundsRemaining>>ONE_FIXED_SHIFT)) { + /* Not vis. */ + GrenadeLauncherSectionPointers[a]->flags|=section_data_notreal; + } else { + /* Vis. */ + GrenadeLauncherSectionPointers[a]->flags&=~section_data_notreal; + } + } + + switch (GrenadeLauncherData.SelectedAmmo) { + case AMMO_FLARE_GRENADE: + { + GrenadeLauncherData.FlareRoundsRemaining = weaponPtr->PrimaryRoundsRemaining; + GrenadeLauncherData.FlareMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining; + ChangeHUDToAlternateShapeSet("MarineWeapons","Flare"); + break; + } + case AMMO_FRAGMENTATION_GRENADE: + { + GrenadeLauncherData.FragmentationRoundsRemaining = weaponPtr->PrimaryRoundsRemaining; + GrenadeLauncherData.FragmentationMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining; + ChangeHUDToAlternateShapeSet("MarineWeapons","Frag"); + break; + } + case AMMO_PROXIMITY_GRENADE: + { + GrenadeLauncherData.ProximityRoundsRemaining = weaponPtr->PrimaryRoundsRemaining; + GrenadeLauncherData.ProximityMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining; + ChangeHUDToAlternateShapeSet("MarineWeapons","Proxmine"); + break; + } + case AMMO_GRENADE: + { + GrenadeLauncherData.StandardRoundsRemaining = weaponPtr->PrimaryRoundsRemaining; + GrenadeLauncherData.StandardMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining; + ChangeHUDToAlternateShapeSet("MarineWeapons","Grenade"); + break; + } + default: + { + GLOBALASSERT(0); + break; + } + } + + +} + +int GrenadeLauncherFire(PLAYER_WEAPON_DATA *weaponPtr) { + + int a; + + a=FireNonAutomaticWeapon(weaponPtr); + + //GrenadeLauncher_UpdateBullets(weaponPtr); + + return(a); + +} + +void GrenadeLauncher_EmergencyChangeAmmo(PLAYER_WEAPON_DATA *weaponPtr) { + + enum AMMO_ID change_to_ammo,original_ammo; + + /* CDF 11/3/99: different priorities here. And only three ammo types. */ + + original_ammo=GrenadeLauncherData.SelectedAmmo; + change_to_ammo=AMMO_NONE; + + + switch(original_ammo) { + case AMMO_GRENADE: + { + if ((GrenadeLauncherData.FragmentationRoundsRemaining>0) + ||(GrenadeLauncherData.FragmentationMagazinesRemaining>0)) { + /* Valid. */ + change_to_ammo=AMMO_FRAGMENTATION_GRENADE; + } else if ((GrenadeLauncherData.ProximityRoundsRemaining>0) + ||(GrenadeLauncherData.ProximityMagazinesRemaining>0)) { + /* Valid. */ + change_to_ammo=AMMO_PROXIMITY_GRENADE; + } + break; + } + case AMMO_FLARE_GRENADE: + { + GLOBALASSERT(0); + break; + } + case AMMO_FRAGMENTATION_GRENADE: + { + if ((GrenadeLauncherData.StandardRoundsRemaining>0) + ||(GrenadeLauncherData.StandardMagazinesRemaining>0)) { + /* Valid. */ + change_to_ammo=AMMO_GRENADE; + } else if ((GrenadeLauncherData.ProximityRoundsRemaining>0) + ||(GrenadeLauncherData.ProximityMagazinesRemaining>0)) { + /* Valid. */ + change_to_ammo=AMMO_PROXIMITY_GRENADE; + } + break; + } + case AMMO_PROXIMITY_GRENADE: + { + if ((GrenadeLauncherData.StandardRoundsRemaining>0) + ||(GrenadeLauncherData.StandardMagazinesRemaining>0)) { + /* Valid. */ + change_to_ammo=AMMO_GRENADE; + } else if ((GrenadeLauncherData.FragmentationRoundsRemaining>0) + ||(GrenadeLauncherData.FragmentationMagazinesRemaining>0)) { + /* Valid. */ + change_to_ammo=AMMO_FRAGMENTATION_GRENADE; + } + break; + } + default: + { + GLOBALASSERT(0); + break; + } + } + + + if ((change_to_ammo==original_ammo)||(change_to_ammo==AMMO_NONE)) { + /* No other ammo types! */ + return; + } + + switch (original_ammo) { + case AMMO_FLARE_GRENADE: + { + GrenadeLauncherData.FlareRoundsRemaining = weaponPtr->PrimaryRoundsRemaining; + GrenadeLauncherData.FlareMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining; + break; + } + case AMMO_FRAGMENTATION_GRENADE: + { + GrenadeLauncherData.FragmentationRoundsRemaining = weaponPtr->PrimaryRoundsRemaining; + GrenadeLauncherData.FragmentationMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining; + break; + } + case AMMO_PROXIMITY_GRENADE: + { + GrenadeLauncherData.ProximityRoundsRemaining = weaponPtr->PrimaryRoundsRemaining; + GrenadeLauncherData.ProximityMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining; + break; + } + case AMMO_GRENADE: + { + GrenadeLauncherData.StandardRoundsRemaining = weaponPtr->PrimaryRoundsRemaining; + GrenadeLauncherData.StandardMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining; + break; + } + default: + { + GLOBALASSERT(0); + break; + } + } + + /* KJL 11:31:44 04/09/97 - when you press secondary fire, you change ammo type */ + switch(change_to_ammo) + { + case AMMO_FLARE_GRENADE: + { + GrenadeLauncherData.SelectedAmmo = AMMO_FLARE_GRENADE; + weaponPtr->PrimaryRoundsRemaining = GrenadeLauncherData.FlareRoundsRemaining; + weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.FlareMagazinesRemaining; + NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_FLARE_GRENADE)); + break; + } + case AMMO_FRAGMENTATION_GRENADE: + { + + GrenadeLauncherData.SelectedAmmo = AMMO_FRAGMENTATION_GRENADE; + weaponPtr->PrimaryRoundsRemaining = GrenadeLauncherData.FragmentationRoundsRemaining; + weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.FragmentationMagazinesRemaining; + NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_FRAGMENTATION_GRENADE)); + break; + } + case AMMO_PROXIMITY_GRENADE: + { + GrenadeLauncherData.SelectedAmmo = AMMO_PROXIMITY_GRENADE; + weaponPtr->PrimaryRoundsRemaining = GrenadeLauncherData.ProximityRoundsRemaining; + weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.ProximityMagazinesRemaining; + NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_PROXIMITY_GRENADE)); + break; + } + case AMMO_GRENADE: + { + GrenadeLauncherData.SelectedAmmo = AMMO_GRENADE; + weaponPtr->PrimaryRoundsRemaining = GrenadeLauncherData.StandardRoundsRemaining; + weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.StandardMagazinesRemaining; + NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_GRENADE)); + break; + } + default: + break; + } + + weaponPtr->CurrentState = WEAPONSTATE_RECOIL_SECONDARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + + return; + +} + +int GrenadeLauncherChangeAmmo(PLAYER_WEAPON_DATA *weaponPtr) { + + enum AMMO_ID change_to_ammo,original_ammo,temp_ammo; + + /* CDF 1/5/98: only change to ammo that you have! */ + + original_ammo=GrenadeLauncherData.SelectedAmmo; + change_to_ammo=AMMO_NONE; + temp_ammo=original_ammo; + + while (change_to_ammo==AMMO_NONE) { + switch(temp_ammo) { + case AMMO_GRENADE: + { +// temp_ammo=AMMO_FLARE_GRENADE; + temp_ammo=AMMO_FRAGMENTATION_GRENADE; + if (temp_ammo==original_ammo) { + /* Gone all the way round. Doh! */ + change_to_ammo=temp_ammo; + break; + } + //if ((GrenadeLauncherData.FlareRoundsRemaining>0) + // ||(GrenadeLauncherData.FlareMagazinesRemaining>0)) { + if ((GrenadeLauncherData.FragmentationRoundsRemaining>0) + ||(GrenadeLauncherData.FragmentationMagazinesRemaining>0)) { + /* Valid. */ + change_to_ammo=temp_ammo; + } + break; + } + case AMMO_FLARE_GRENADE: + { + temp_ammo=AMMO_FRAGMENTATION_GRENADE; + if (temp_ammo==original_ammo) { + /* Gone all the way round. Doh! */ + change_to_ammo=temp_ammo; + break; + } + if ((GrenadeLauncherData.FragmentationRoundsRemaining>0) + ||(GrenadeLauncherData.FragmentationMagazinesRemaining>0)) { + /* Valid. */ + change_to_ammo=temp_ammo; + } + break; + } + case AMMO_FRAGMENTATION_GRENADE: + { + temp_ammo=AMMO_PROXIMITY_GRENADE; +// temp_ammo=AMMO_GRENADE; + if (temp_ammo==original_ammo) { + /* Gone all the way round. Doh! */ + change_to_ammo=temp_ammo; + break; + } + if ((GrenadeLauncherData.ProximityRoundsRemaining>0) + ||(GrenadeLauncherData.ProximityMagazinesRemaining>0)) { + //if ((GrenadeLauncherData.StandardRoundsRemaining>0) + // ||(GrenadeLauncherData.StandardMagazinesRemaining>0)) { + /* Valid. */ + change_to_ammo=temp_ammo; + } + break; + } + case AMMO_PROXIMITY_GRENADE: + { + temp_ammo=AMMO_GRENADE; + if (temp_ammo==original_ammo) { + /* Gone all the way round. Doh! */ + change_to_ammo=temp_ammo; + break; + } + if ((GrenadeLauncherData.StandardRoundsRemaining>0) + ||(GrenadeLauncherData.StandardMagazinesRemaining>0)) { + /* Valid. */ + change_to_ammo=temp_ammo; + } + break; + } + default: + { + GLOBALASSERT(0); + break; + } + } + } + + if (change_to_ammo==original_ammo) { + /* No other ammo types! */ + return(0); + } + + switch (original_ammo) { + case AMMO_FLARE_GRENADE: + { + GrenadeLauncherData.FlareRoundsRemaining = weaponPtr->PrimaryRoundsRemaining; + GrenadeLauncherData.FlareMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining; + break; + } + case AMMO_FRAGMENTATION_GRENADE: + { + GrenadeLauncherData.FragmentationRoundsRemaining = weaponPtr->PrimaryRoundsRemaining; + GrenadeLauncherData.FragmentationMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining; + break; + } + case AMMO_PROXIMITY_GRENADE: + { + GrenadeLauncherData.ProximityRoundsRemaining = weaponPtr->PrimaryRoundsRemaining; + GrenadeLauncherData.ProximityMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining; + break; + } + case AMMO_GRENADE: + { + GrenadeLauncherData.StandardRoundsRemaining = weaponPtr->PrimaryRoundsRemaining; + GrenadeLauncherData.StandardMagazinesRemaining = weaponPtr->PrimaryMagazinesRemaining; + break; + } + default: + { + GLOBALASSERT(0); + break; + } + } + + /* KJL 11:31:44 04/09/97 - when you press secondary fire, you change ammo type */ + switch(change_to_ammo) + { + case AMMO_FLARE_GRENADE: + { + GrenadeLauncherData.SelectedAmmo = AMMO_FLARE_GRENADE; + weaponPtr->PrimaryRoundsRemaining = GrenadeLauncherData.FlareRoundsRemaining; + weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.FlareMagazinesRemaining; + NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_FLARE_GRENADE)); + break; + } + case AMMO_FRAGMENTATION_GRENADE: + { + + GrenadeLauncherData.SelectedAmmo = AMMO_FRAGMENTATION_GRENADE; + weaponPtr->PrimaryRoundsRemaining = GrenadeLauncherData.FragmentationRoundsRemaining; + weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.FragmentationMagazinesRemaining; + NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_FRAGMENTATION_GRENADE)); + break; + } + case AMMO_PROXIMITY_GRENADE: + { + GrenadeLauncherData.SelectedAmmo = AMMO_PROXIMITY_GRENADE; + weaponPtr->PrimaryRoundsRemaining = GrenadeLauncherData.ProximityRoundsRemaining; + weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.ProximityMagazinesRemaining; + NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_PROXIMITY_GRENADE)); + break; + } + case AMMO_GRENADE: + { + GrenadeLauncherData.SelectedAmmo = AMMO_GRENADE; + weaponPtr->PrimaryRoundsRemaining = GrenadeLauncherData.StandardRoundsRemaining; + weaponPtr->PrimaryMagazinesRemaining = GrenadeLauncherData.StandardMagazinesRemaining; + NewOnScreenMessage(GetTextString(TEXTSTRING_AMMO_SHORTNAME_GRENADE)); + break; + } + default: + break; + } + + //GrenadeLauncher_UpdateBullets(weaponPtr); + //weaponPtr->CurrentState = WEAPONSTATE_WAITING; + + weaponPtr->CurrentState = WEAPONSTATE_RECOIL_SECONDARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + + return(1); + +} + +int SmartgunSecondaryFire(PLAYER_WEAPON_DATA *weaponPtr) { + + switch (SmartgunMode) { + case I_Track: + /* Language Localise */ + NewOnScreenMessage(GetTextString(TEXTSTRING_INGAME_FREEMODE)); + SmartgunMode=I_Free; + break; + case I_Free: + /* Language Localise */ + NewOnScreenMessage(GetTextString(TEXTSTRING_INGAME_TRACKMODE)); + SmartgunMode=I_Track; + break; + default: + GLOBALASSERT(0); + break; + } + Sound_Play(SID_SMART_MODESWITCH,NULL); + + weaponPtr->CurrentState = WEAPONSTATE_WAITING; + + return(0); + +} + +int PredDiscChangeMode(PLAYER_WEAPON_DATA *weaponPtr) { + + #if 0 + switch (ThisDiscMode) { + case I_Seek_Track: + ThisDiscMode=I_Search_Destroy; + /* Language Localise */ + NewOnScreenMessage("SEARCH AND DESTROY"); + break; + case I_Search_Destroy: + ThisDiscMode=I_Proximity_Mine; + /* Language Localise */ + NewOnScreenMessage("PROXIMITY MINE"); + break; + case I_Proximity_Mine: + ThisDiscMode=I_Seek_Track; + /* Language Localise */ + NewOnScreenMessage("SEEK AND TRACK"); + break; + } + weaponPtr->CurrentState = WEAPONSTATE_WAITING; + #endif + + return(0); +} + + +int MeleeWeapon_180Degree_Front_Core(DAMAGE_PROFILE *damage,int multiple,int range) +{ + int numberOfObjects = NumOnScreenBlocks; + int numhits=0; + STRATEGYBLOCK *objectToHit=0; + + int hurt_people; + + hurt_people=1; + + while (numberOfObjects) + { + VECTORCH targetpos,targetposW; + DISPLAYBLOCK* objectPtr = OnScreenBlockList[--numberOfObjects]; + STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock; + GLOBALASSERT(objectPtr); + + /* does object have a strategy block? */ + if (sbPtr) + { + + GetTargetingPointOfObject(objectPtr,&targetpos); + targetposW=targetpos; + targetpos.vx-=Global_VDB_Ptr->VDB_World.vx; + targetpos.vy-=Global_VDB_Ptr->VDB_World.vy; + targetpos.vz-=Global_VDB_Ptr->VDB_World.vz; + RotateVector(&targetpos,&Global_VDB_Ptr->VDB_Mat); + + /* is it in range? */ + if (targetpos.vz > 0) { + + int dist=Approximate3dMagnitude(&targetpos); + + if (distDynPtr; + if (dynPtr) + { + #if 1 + /* KJL 19:10:49 25/01/99 - I'm going to try changing this to + see if I can have an Alien that doesn't kill multiple things in one frame */ + + /* CDF 30/3/99 - I'm going to change it back with modifications, + since people evidently can't make up their minds. */ + + //if (IsThisObjectVisibleFromThisPosition_WithIgnore(Player,objectPtr,&targetposW,range)) + if (CameraCanSeeThisPosition_WithIgnore(objectPtr,&targetposW)) + { + + int magnitudeOfForce = (5000*damage->Cutting) / dynPtr->Mass; + dynPtr->LinImpulse.vx += MUL_FIXED(Player->ObMat.mat31,magnitudeOfForce); + dynPtr->LinImpulse.vy += MUL_FIXED(Player->ObMat.mat32,magnitudeOfForce); + dynPtr->LinImpulse.vz += MUL_FIXED(Player->ObMat.mat33,magnitudeOfForce); + /* Consider target aspect. */ + { + VECTORCH attack_dir,displacement; + int real_multiple; + int do_attack; + + displacement.vx = dynPtr->Position.vx - Player->ObStrategyBlock->DynPtr->Position.vx; + displacement.vy = dynPtr->Position.vy - Player->ObStrategyBlock->DynPtr->Position.vy; + displacement.vz = dynPtr->Position.vz - Player->ObStrategyBlock->DynPtr->Position.vz; + + GetDirectionOfAttack(sbPtr,&displacement,&attack_dir); + + if (attack_dir.vz>0) { + real_multiple=multiple<<1; + } else { + real_multiple=multiple; + } + + /* Consider player's target. */ + + /* Here's the mod. */ + switch (sbPtr->I_SBtype) { + case I_BehaviourMarine: + case I_BehaviourMarinePlayer: + case I_BehaviourPredator: + case I_BehaviourAutoGun: + case I_BehaviourAlien: + if (hurt_people) { + do_attack=1; + hurt_people=0; + } else { + do_attack=0; + } + break; + default: + do_attack=1; + break; + } + + if (do_attack) { + if (sbPtr->SBdptr->HModelControlBlock) { + DISPLAYBLOCK *frag; + + frag=HtoHDamageToHModel(sbPtr, damage, real_multiple, NULL, &attack_dir); + /* If you're an alien, consider limb rip damage. */ + if (AvP.PlayerType==I_Alien) { + if (sbPtr->I_SBtype==I_BehaviourMarine) { + MARINE_STATUS_BLOCK *marineStatusPointer; + + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android==0) { + if (frag) { + /* Took off a limb! */ + LimbRip_AwardHealth(); + } + } + } else if (sbPtr->I_SBtype==I_BehaviourNetCorpse) { + NETCORPSEDATABLOCK *corpseDataPtr; + + corpseDataPtr = (NETCORPSEDATABLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(corpseDataPtr); + + if (corpseDataPtr->Android==0) { + if (frag) { + /* Took off a limb! */ + LimbRip_AwardHealth(); + } + } + } + } + } else { + CauseDamageToObject(sbPtr, damage, real_multiple,&attack_dir); + } + } + } + numhits++; + } + #else + //if (IsThisObjectVisibleFromThisPosition_WithIgnore(Player,objectPtr,&targetposW,range)) + if (CameraCanSeeThisPosition_WithIgnore(objectPtr,&targetposW)) { + objectToHit = sbPtr; + range = dist; + } + #endif + } + } + } + } + } + + /* Here's a new modification... */ + if (numhits==0) { + /* Let's see if we've missed something obvious. */ + if (PlayersTarget.DispPtr) { + if (PlayersTarget.DistanceObStrategyBlock) { + /* May as well hit this, then. */ + objectToHit=PlayersTarget.DispPtr->ObStrategyBlock; + if (objectToHit->DynPtr) { + DYNAMICSBLOCK *dynPtr = objectToHit->DynPtr; + int magnitudeOfForce = (5000*damage->Cutting) / dynPtr->Mass; + dynPtr->LinImpulse.vx += MUL_FIXED(Player->ObMat.mat31,magnitudeOfForce); + dynPtr->LinImpulse.vy += MUL_FIXED(Player->ObMat.mat32,magnitudeOfForce); + dynPtr->LinImpulse.vz += MUL_FIXED(Player->ObMat.mat33,magnitudeOfForce); + /* Consider target aspect. */ + { + VECTORCH attack_dir,displacement; + int real_multiple; + + displacement.vx = dynPtr->Position.vx - Player->ObStrategyBlock->DynPtr->Position.vx; + displacement.vy = dynPtr->Position.vy - Player->ObStrategyBlock->DynPtr->Position.vy; + displacement.vz = dynPtr->Position.vz - Player->ObStrategyBlock->DynPtr->Position.vz; + + GetDirectionOfAttack(objectToHit,&displacement,&attack_dir); + + if (attack_dir.vz>0) { + real_multiple=multiple<<1; + } else { + real_multiple=multiple; + } + + /* Consider player's target. */ + + if (objectToHit->SBdptr->HModelControlBlock) { + DISPLAYBLOCK *frag; + + frag=HtoHDamageToHModel(objectToHit, damage, real_multiple, NULL, &attack_dir); + /* If you're an alien, consider limb rip damage. */ + if (AvP.PlayerType==I_Alien) { + if (objectToHit->I_SBtype==I_BehaviourMarine) { + MARINE_STATUS_BLOCK *marineStatusPointer; + + marineStatusPointer = (MARINE_STATUS_BLOCK *)(objectToHit->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android==0) { + if (frag) { + /* Took off a limb! */ + LimbRip_AwardHealth(); + } + } + } else if (objectToHit->I_SBtype==I_BehaviourNetCorpse) { + NETCORPSEDATABLOCK *corpseDataPtr; + + corpseDataPtr = (NETCORPSEDATABLOCK *)(objectToHit->SBdataptr); + LOCALASSERT(corpseDataPtr); + + if (corpseDataPtr->Android==0) { + if (frag) { + /* Took off a limb! */ + LimbRip_AwardHealth(); + } + } + } + } + } else { + CauseDamageToObject(objectToHit, damage, real_multiple,&attack_dir); + } + } + numhits++; + } + } + } + } + } + + return(numhits); +} + +int MeleeWeapon_180Degree_Front(PLAYER_WEAPON_DATA *weaponPtr) +{ + enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID; + int hits; + + hits=MeleeWeapon_180Degree_Front_Core(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty],ONE_FIXED,TemplateAmmo[AmmoID].MaxRange); + + return(hits); +} + +int MeleeWeapon_90Degree_Front_Core(DAMAGE_PROFILE *damage,int multiple,int range) +{ + int numberOfObjects = NumOnScreenBlocks; + int numhits=0; + STRATEGYBLOCK *objectToHit=NULL; + + int hurt_people; + + hurt_people=1; + + while (numberOfObjects) + { + STRATEGYBLOCK *sbPtr; + VECTORCH targetpos,targetposW; + DISPLAYBLOCK* objectPtr = OnScreenBlockList[--numberOfObjects]; + + GLOBALASSERT(objectPtr); + sbPtr = objectPtr->ObStrategyBlock; + + /* does object have a strategy block? */ + if (sbPtr) + { + GetTargetingPointOfObject(objectPtr,&targetpos); + targetposW=targetpos; + targetpos.vx-=Global_VDB_Ptr->VDB_World.vx; + targetpos.vy-=Global_VDB_Ptr->VDB_World.vy; + targetpos.vz-=Global_VDB_Ptr->VDB_World.vz; + RotateVector(&targetpos,&Global_VDB_Ptr->VDB_Mat); + + /* is it in the frustrum? */ + if ( (targetpos.vz >0) + && (targetpos.vz > targetpos.vx) + && (targetpos.vz > -targetpos.vx) + && (targetpos.vz > targetpos.vy) + && (targetpos.vz > -targetpos.vy) ) { + + int dist=Approximate3dMagnitude(&targetpos); + + /* HACKAHACKAHACKA */ + + if (objectPtr->HModelControlBlock==NULL) { + if (objectPtr->ObShapeData) { + dist-=(objectPtr->ObShapeData->shaperadius)>>1; + } + } + + if (distDynPtr; + if (dynPtr) + { + + if (IsThisObjectVisibleFromThisPosition_WithIgnore(Player,objectPtr,&targetposW,range)) { + + int magnitudeOfForce = (5000*damage->Cutting) / dynPtr->Mass; + dynPtr->LinImpulse.vx += MUL_FIXED(Player->ObMat.mat31,magnitudeOfForce); + dynPtr->LinImpulse.vy += MUL_FIXED(Player->ObMat.mat32,magnitudeOfForce); + dynPtr->LinImpulse.vz += MUL_FIXED(Player->ObMat.mat33,magnitudeOfForce); + /* Consider player's target. */ + + /* Consider target aspect. */ + { + VECTORCH attack_dir,displacement; + int real_multiple; + int do_attack; + + displacement.vx = dynPtr->Position.vx - Player->ObStrategyBlock->DynPtr->Position.vx; + displacement.vy = dynPtr->Position.vy - Player->ObStrategyBlock->DynPtr->Position.vy; + displacement.vz = dynPtr->Position.vz - Player->ObStrategyBlock->DynPtr->Position.vz; + + GetDirectionOfAttack(sbPtr,&displacement,&attack_dir); + + if (attack_dir.vz>0) { + real_multiple=multiple<<1; + } else { + real_multiple=multiple; + } + + /* Consider player's target. */ + + switch (sbPtr->I_SBtype) { + case I_BehaviourMarine: + case I_BehaviourMarinePlayer: + case I_BehaviourPredator: + case I_BehaviourAutoGun: + case I_BehaviourAlien: + if (hurt_people) { + do_attack=1; + hurt_people=0; + } else { + do_attack=0; + } + break; + default: + do_attack=1; + break; + } + + if (do_attack) { + if (sbPtr->SBdptr->HModelControlBlock) { + if (damage->Special) { + /* Target an alien's chest. */ + if (sbPtr->I_SBtype==I_BehaviourAlien) { + SECTION_DATA *chest; + chest=GetThisSectionData(sbPtr->SBdptr->HModelControlBlock->section_data,"chest"); + GLOBALASSERT(chest); + CauseDamageToHModel(sbPtr->SBdptr->HModelControlBlock,sbPtr,damage,real_multiple,chest,&attack_dir,NULL,0); + } else { + HtoHDamageToHModel(sbPtr, damage, real_multiple, NULL, &attack_dir); + } + } else { + HtoHDamageToHModel(sbPtr, damage, real_multiple, NULL, &attack_dir); + } + } else { + CauseDamageToObject(sbPtr, damage, real_multiple,&attack_dir); + } + } + } + numhits++; + } + } + } + } + } + } + + /* Here's a new modification... */ + if (numhits==0) { + /* Let's see if we've missed something obvious. */ + if (PlayersTarget.DispPtr) { + if (PlayersTarget.DistanceObStrategyBlock) { + /* May as well hit this, then. */ + objectToHit=PlayersTarget.DispPtr->ObStrategyBlock; + if (objectToHit->DynPtr) { + DYNAMICSBLOCK *dynPtr = objectToHit->DynPtr; + int magnitudeOfForce = (5000*damage->Cutting) / dynPtr->Mass; + dynPtr->LinImpulse.vx += MUL_FIXED(Player->ObMat.mat31,magnitudeOfForce); + dynPtr->LinImpulse.vy += MUL_FIXED(Player->ObMat.mat32,magnitudeOfForce); + dynPtr->LinImpulse.vz += MUL_FIXED(Player->ObMat.mat33,magnitudeOfForce); + /* Consider target aspect. */ + { + VECTORCH attack_dir,displacement; + int real_multiple; + + displacement.vx = dynPtr->Position.vx - Player->ObStrategyBlock->DynPtr->Position.vx; + displacement.vy = dynPtr->Position.vy - Player->ObStrategyBlock->DynPtr->Position.vy; + displacement.vz = dynPtr->Position.vz - Player->ObStrategyBlock->DynPtr->Position.vz; + + GetDirectionOfAttack(objectToHit,&displacement,&attack_dir); + + if (attack_dir.vz>0) { + real_multiple=multiple<<1; + } else { + real_multiple=multiple; + } + + /* Consider player's target. */ + + if (objectToHit->SBdptr->HModelControlBlock) { + DISPLAYBLOCK *frag; + + frag=HtoHDamageToHModel(objectToHit, damage, real_multiple, NULL, &attack_dir); + /* If you're an alien, consider limb rip damage. */ + if (AvP.PlayerType==I_Alien) { + if (objectToHit->I_SBtype==I_BehaviourMarine) { + MARINE_STATUS_BLOCK *marineStatusPointer; + + marineStatusPointer = (MARINE_STATUS_BLOCK *)(objectToHit->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->Android==0) { + if (frag) { + /* Took off a limb! */ + LimbRip_AwardHealth(); + } + } + } else if (objectToHit->I_SBtype==I_BehaviourNetCorpse) { + NETCORPSEDATABLOCK *corpseDataPtr; + + corpseDataPtr = (NETCORPSEDATABLOCK *)(objectToHit->SBdataptr); + LOCALASSERT(corpseDataPtr); + + if (corpseDataPtr->Android==0) { + if (frag) { + /* Took off a limb! */ + LimbRip_AwardHealth(); + } + } + } + } + } else { + CauseDamageToObject(objectToHit, damage, real_multiple,&attack_dir); + } + } + numhits++; + } + } + } + } + } + + + return(numhits); +} + +int MeleeWeapon_90Degree_Front(PLAYER_WEAPON_DATA *weaponPtr) +{ + enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID; + int hits; + + hits=MeleeWeapon_90Degree_Front_Core(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty],ONE_FIXED,TemplateAmmo[AmmoID].MaxRange); + + return(hits); +} +#if 0 +void WeaponCreateStartFrame(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + extern void CopyAnimationFrameToShape (SHAPEANIMATIONCONTROLDATA *sacd, DISPLAYBLOCK * dptr); + + /* Setup animation. */ + SHAPEANIMATIONCONTROLDATA sacd; + InitShapeAnimationControlData(&sacd); + sacd.seconds_per_frame = ONE_FIXED/16; + sacd.sequence_no = 0; + sacd.default_start_and_end_frames = 1; + sacd.reversed = 0; + sacd.stop_at_end = 1; + SetShapeAnimationSequence(&PlayersWeapon, &sacd); + sacd.sequence = &(PlayersWeapon.ShapeAnimControlBlock)->anim_header->anim_sequences[sacd.sequence_no]; + sacd.current_frame=0; + CopyAnimationFrameToShape(&sacd, &PlayersWeapon); + WeaponFidgetPlaying=0; + +} +#endif +void WeaponSetStartFrame(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + #if 0 //old shape animation stuff + extern void CopyAnimationFrameToShape (SHAPEANIMATIONCONTROLDATA *sacd, DISPLAYBLOCK * dptr); + + /* Setup animation. */ + SHAPEANIMATIONCONTROLDATA sacd; + InitShapeAnimationControlData(&sacd); + sacd.seconds_per_frame = ONE_FIXED/16; + sacd.sequence_no = 0; + sacd.default_start_and_end_frames = 1; + sacd.reversed = 0; + sacd.stop_at_end = 1; + SetShapeAnimationSequence(&PlayersWeapon, &sacd); + WeaponFidgetPlaying=0; + #endif + +} + +void PulseRifleSwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Come,ONE_FIXED>>3); + PlayersWeaponHModelController.Looped=0; + } + + Weapon_ThisBurst=-1; +} + +void PulseRifleSwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Go,ONE_FIXED>>3); + PlayersWeaponHModelController.Looped=0; + } + +} + +void PulseRifleGrenadeRecoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Secondary_Fire,ONE_FIXED); + PlayersWeaponHModelController.Looped=0; + } + +} + +void PulseRifleReloadClip(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Reload,ONE_FIXED); + PlayersWeaponHModelController.Looped=0; + } + +} + +void MinigunStartSpin(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD); + + Old_Minigun_SpinSpeed=MINIGUN_IDLE_SPEED; + Minigun_SpinSpeed=MINIGUN_IDLE_SPEED; + Weapon_ThisBurst=-1; + Minigun_HeadJolt.EulerX=0; + Minigun_HeadJolt.EulerY=0; + Minigun_HeadJolt.EulerZ=0; + Minigun_MaxHeadJolt.EulerX=0; + Minigun_MaxHeadJolt.EulerY=0; + Minigun_MaxHeadJolt.EulerZ=0; + + if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Standard_Fire) { + #if (MINIGUN_IDLE_SPEED) + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Fire,DIV_FIXED(ONE_FIXED,MINIGUN_IDLE_SPEED)); + PlayersWeaponHModelController.Playing=1; + #else + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Fire,ONE_FIXED); + PlayersWeaponHModelController.Playing=0; + #endif + } + +} + +void MinigunStopSpin(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD); + + /* Spin down first. */ + + Minigun_SpinSpeed-=(NormalFrameTime<<3); + if (Minigun_SpinSpeedStateTimeOutCounter = 0; + Minigun_SpinSpeed=MINIGUN_IDLE_SPEED; + + /* Stop Spin. */ + PlayersWeaponHModelController.Playing=0; + } else { + /* Can't stop yet. */ + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + + } + + if (Minigun_SpinSpeed!=Old_Minigun_SpinSpeed) { + int hmspinrate; + if (Minigun_SpinSpeed) { + hmspinrate=DIV_FIXED(ONE_FIXED,Minigun_SpinSpeed); + HModel_ChangeSpeed(&PlayersWeaponHModelController,hmspinrate); + PlayersWeaponHModelController.Playing=1; + } else { + PlayersWeaponHModelController.Playing=0; + } + } + + Old_Minigun_SpinSpeed=Minigun_SpinSpeed; + + textprint("Minigun Spin Speed = %d\n",Minigun_SpinSpeed); + + /* Think sounds. */ + if (Minigun_SpinSpeed==0) { + /* No sound at all, ideally! */ + if(weaponHandle != SOUND_NOACTIVEINDEX) { + if (ActiveSounds[weaponHandle].soundIndex!=SID_MINIGUN_END) { + /* Allow SID_MINIGUN_END to stop if it's going. */ + Sound_Stop(weaponHandle); + } + } + } else { + /* Winding down - should be playing SID_MINIGUN_END. */ + if(weaponHandle != SOUND_NOACTIVEINDEX) { + if (ActiveSounds[weaponHandle].soundIndex!=SID_MINIGUN_END) { + /* Stop other sounds... */ + Sound_Stop(weaponHandle); + } + } + if(weaponHandle == SOUND_NOACTIVEINDEX) { + Sound_Play(SID_MINIGUN_END,"eh",&weaponHandle); + playerNoise=1; + } + } +} + +#define MINIGUN_MOVING_IMPULSE (-36000) +#define MINIGUN_JOLTTIME_SHIFT (2) + +int FireMinigun(PLAYER_WEAPON_DATA *weaponPtr) { + + #if FORCE_MINIGUN_STOP + if (Player->ObStrategyBlock->DynPtr->IsInContactWithFloor) { + Minigun_SpinSpeed+=(NormalFrameTime<<7); + } + #else + if ((Player->ObStrategyBlock->DynPtr->Position.vx==Player->ObStrategyBlock->DynPtr->PrevPosition.vx) + &&(Player->ObStrategyBlock->DynPtr->Position.vy==Player->ObStrategyBlock->DynPtr->PrevPosition.vy) + &&(Player->ObStrategyBlock->DynPtr->Position.vz==Player->ObStrategyBlock->DynPtr->PrevPosition.vz) + &&(Player->ObStrategyBlock->DynPtr->IsInContactWithFloor) + ){ + + Minigun_SpinSpeed+=(NormalFrameTime<<7); + } else { + Minigun_SpinSpeed-=(NormalFrameTime<<3); + if (Minigun_SpinSpeed=MINIGUN_MAX_SPEED) { + + Minigun_SpinSpeed=MINIGUN_MAX_SPEED; + + Weapon_ThisBurst+=FireAutomaticWeapon(weaponPtr); + + /* Give the player an impulse? */ + if ((Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0) + ||(Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0) + ||(Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0)) + { + int impulse; + + impulse=MUL_FIXED(MINIGUN_MOVING_IMPULSE,NormalFrameTime); + + Player->ObStrategyBlock->DynPtr->LinImpulse.vx+=MUL_FIXED(PlayersWeapon.ObMat.mat31,impulse); + Player->ObStrategyBlock->DynPtr->LinImpulse.vy+=MUL_FIXED(PlayersWeapon.ObMat.mat32,impulse); + Player->ObStrategyBlock->DynPtr->LinImpulse.vz+=MUL_FIXED(PlayersWeapon.ObMat.mat33,impulse); + + Minigun_MaxHeadJolt.EulerX=-(78+(FastRandom()&63)); + Minigun_MaxHeadJolt.EulerY=-(78+(FastRandom()&63)); + Minigun_MaxHeadJolt.EulerZ=300; + + Minigun_HeadJolt.EulerX = Minigun_MaxHeadJolt.EulerX; + Minigun_HeadJolt.EulerY = Minigun_MaxHeadJolt.EulerY; + Minigun_HeadJolt.EulerZ = Minigun_MaxHeadJolt.EulerZ; + + } + + return(1); + } else { + Weapon_ThisBurst=0; + Minigun_HeadJolt.EulerX=0; + Minigun_HeadJolt.EulerY=0; + Minigun_HeadJolt.EulerZ=0; + + Minigun_MaxHeadJolt.EulerX=0; + Minigun_MaxHeadJolt.EulerY=0; + Minigun_MaxHeadJolt.EulerZ=0; + } + + /* Maintain_Minigun called anyway. */ + + return(0); + +} + +int FireEmptyMinigun(PLAYER_WEAPON_DATA *weaponPtr) { + + #if FORCE_MINIGUN_STOP + if (Player->ObStrategyBlock->DynPtr->IsInContactWithFloor) { + Minigun_SpinSpeed+=(NormalFrameTime<<7); + } + #else + if ((Player->ObStrategyBlock->DynPtr->Position.vx==Player->ObStrategyBlock->DynPtr->PrevPosition.vx) + &&(Player->ObStrategyBlock->DynPtr->Position.vy==Player->ObStrategyBlock->DynPtr->PrevPosition.vy) + &&(Player->ObStrategyBlock->DynPtr->Position.vz==Player->ObStrategyBlock->DynPtr->PrevPosition.vz) + &&(Player->ObStrategyBlock->DynPtr->IsInContactWithFloor) + ){ + + Minigun_SpinSpeed+=(NormalFrameTime<<7); + } else { + Minigun_SpinSpeed-=(NormalFrameTime<<3); + if (Minigun_SpinSpeed=MINIGUN_MAX_SPEED) { + + Minigun_SpinSpeed=MINIGUN_MAX_SPEED; + + /* No bullets, no impulse. */ + + return(1); + } else { + Weapon_ThisBurst=0; + Minigun_HeadJolt.EulerX=0; + Minigun_HeadJolt.EulerY=0; + Minigun_HeadJolt.EulerZ=0; + + Minigun_MaxHeadJolt.EulerX=0; + Minigun_MaxHeadJolt.EulerY=0; + Minigun_MaxHeadJolt.EulerZ=0; + } + + /* Maintain_Minigun called anyway. */ + + return(0); + +} + + +void Maintain_Minigun(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->CurrentState!=WEAPONSTATE_FIRING_PRIMARY) { + Minigun_SpinSpeed-=(NormalFrameTime<<3); + if (Minigun_SpinSpeed0) { + if (joltratex>Minigun_HeadJolt.EulerX) { + joltratex=Minigun_HeadJolt.EulerX; + } + Minigun_HeadJolt.EulerX-=joltratex; + if (Minigun_HeadJolt.EulerX<0) { + Minigun_HeadJolt.EulerX=0; + } + } else if (Minigun_HeadJolt.EulerX<0) { + if (joltratex0) { + Minigun_HeadJolt.EulerX=0; + } + } + + ((PLAYER_STATUS *)playerStatus)->ViewPanX += joltratex; + if ((((PLAYER_STATUS *)playerStatus)->ViewPanX>1024) + &&(((PLAYER_STATUS *)playerStatus)->ViewPanX<3200)) { + ((PLAYER_STATUS *)playerStatus)->ViewPanX=3200; + } + /* Okay, that 3200 comes from 3072 + '128'. '128' is hardcoded into pmove.c. */ + ((PLAYER_STATUS *)playerStatus)->ViewPanX &= wrap360; + + if (Minigun_HeadJolt.EulerY>0) { + if (joltratey>Minigun_HeadJolt.EulerY) { + joltratey=Minigun_HeadJolt.EulerY; + } + Minigun_HeadJolt.EulerY-=joltratey; + if (Minigun_HeadJolt.EulerY<0) { + Minigun_HeadJolt.EulerY=0; + } + } else if (Minigun_HeadJolt.EulerY<0) { + if (joltratey0) { + Minigun_HeadJolt.EulerY=0; + } + } + joltratey&=wrap360; + /* Forcibly turn the player! */ + { + MATRIXCH mat; + int cos = GetCos(joltratey); + int sin = GetSin(joltratey); + mat.mat11 = cos; + mat.mat12 = 0; + mat.mat13 = -sin; + mat.mat21 = 0; + mat.mat22 = 65536; + mat.mat23 = 0; + mat.mat31 = sin; + mat.mat32 = 0; + mat.mat33 = cos; + + MatrixMultiply(&Player->ObStrategyBlock->DynPtr->OrientMat,&mat,&Player->ObStrategyBlock->DynPtr->OrientMat); + + MatrixToEuler(&Player->ObStrategyBlock->DynPtr->OrientMat, &Player->ObStrategyBlock->DynPtr->OrientEuler); + } + + if (Minigun_HeadJolt.EulerZ>0) { + if (joltratex>Minigun_HeadJolt.EulerZ) { + joltratex=Minigun_HeadJolt.EulerZ; + } + Minigun_HeadJolt.EulerZ-=joltratez; + if (Minigun_HeadJolt.EulerZ<0) { + Minigun_HeadJolt.EulerZ=0; + } + } else if (Minigun_HeadJolt.EulerZ<0) { + if (joltratex0) { + Minigun_HeadJolt.EulerZ=0; + } + } + HeadOrientation.EulerZ+=joltratez; + + } + + Old_Minigun_SpinSpeed=Minigun_SpinSpeed; + + textprint("Minigun Spin Speed = %d\n",Minigun_SpinSpeed); + +} + +void GrenadeLauncherRecoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Fire,(ONE_FIXED*4)/3); + PlayersWeaponHModelController.Looped=0; + } +} + +void GrenadeLauncherReload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD); + + if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Standard_Reload) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Reload,(ONE_FIXED*4)/3); + PlayersWeaponHModelController.Looped=0; + GrenadeLauncher_UpdateBullets(weaponPtr); + } + + if (PlayersWeaponHModelController.keyframe_flags) { + TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->PrimaryAmmoID]; + + /* Reload grenade launcher ahead of schedule. */ + weaponPtr->PrimaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine; + weaponPtr->PrimaryMagazinesRemaining--; + GrenadeLauncher_UpdateBullets(weaponPtr); + + } +} + +void GrenadeLauncherReload_Change(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD); + + if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Standard_Reload) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Reload,(ONE_FIXED*4)/3); + PlayersWeaponHModelController.Looped=0; + /* No update bullets here. */ + } + + if (PlayersWeaponHModelController.keyframe_flags) { + TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->PrimaryAmmoID]; + + /* Reload grenade launcher if unloaded. */ + if (weaponPtr->PrimaryRoundsRemaining==0) { + weaponPtr->PrimaryRoundsRemaining = templateAmmoPtr->AmmoPerMagazine; + weaponPtr->PrimaryMagazinesRemaining--; + } + GrenadeLauncher_UpdateBullets(weaponPtr); + /* A little cheat... */ + if (weaponPtr->PrimaryRoundsRemainingAmmoPerMagazine) { + GrenadeLauncherSectionPointers[0]->flags|=section_data_notreal; + } + } +} + +void GrenadeLauncherNull(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + /* A bit of a hack - for resetting position. */ + + GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD); + + /* Pop the round in the breach... */ + GrenadeLauncherSectionPointers[0]->flags|=section_data_notreal; + /* It'll be put back at the next update. */ + + if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED); + } +} + +void GrenadeLauncherIdle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD); + +// textprint("GL Rounds = %d\n",(weaponPtr->PrimaryRoundsRemaining>>ONE_FIXED_SHIFT)); + /* Don't update on secondary fire! */ + + GrenadeLauncher_UpdateBullets(weaponPtr); + + if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED); + } + +} + +void GrenadeLauncherFidget(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD); + +// textprint("GL Rounds = %d\n",(weaponPtr->PrimaryRoundsRemaining>>ONE_FIXED_SHIFT)); + GrenadeLauncher_UpdateBullets(weaponPtr); + + if ((PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary)&&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Fidget)) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED); + } + + if (weaponPtr->StateTimeOutCounter > ONE_FIXED) { + + if (WeaponFidgetPlaying) { + if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1); + WeaponFidgetPlaying=0; + } + } else if ((FastRandom()&255)==0) { + /* Start animation. */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Fidget,ONE_FIXED,0); + weaponPtr->StateTimeOutCounter=0; + WeaponFidgetPlaying=1; + } + } + } + +} + +void GrenadeLauncher_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Come,ONE_FIXED/3); + PlayersWeaponHModelController.Looped=0; + } +} + +void GrenadeLauncher_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Go,ONE_FIXED/3); + PlayersWeaponHModelController.Looped=0; + } +} + +void GrenadeLauncherInit(PLAYER_WEAPON_DATA *weaponPtr) { + + int a; + + /* Setup grenades. */ + + for (a=0; a<6; a++) { + GrenadeLauncherSectionPointers[a]=GetThisSectionData( + PlayersWeaponHModelController.section_data,GrenadeLauncherBulletNames[a]); + } + + GrenadeLauncher_UpdateBullets(weaponPtr); + +} + +void PulseRifleFidget(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD); + + if ((PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary)&&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Fidget)) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED); + } + + if (weaponPtr->StateTimeOutCounter > ONE_FIXED) { + + if (WeaponFidgetPlaying) { + if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1); + WeaponFidgetPlaying=0; + } + } else if ((FastRandom()&255)==0) { + /* Start animation. */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Fidget,ONE_FIXED,0); + weaponPtr->StateTimeOutCounter=0; + WeaponFidgetPlaying=1; + } + } + + } + +} + +void WristBlade_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Stand,ONE_FIXED,1); + } + + /* Are we running? */ + + if ( (Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0) + || (Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0) + || (Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0) ) { + + /* Were we running? */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Run)) { + if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Run) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Run,ONE_FIXED,1); + } + } else { + if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),PHSS_Stand,(int)PHSS_Stand,ONE_FIXED,1); + } + } + } else { + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if ((PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1); + } + + if (weaponPtr->StateTimeOutCounter > ONE_FIXED) { + + if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Fidget) { + if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1); + } + } else if ((FastRandom()&255)==0) { + /* Start animation. */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_PredatorHUD,(int)PHSS_Fidget,-1,0); + weaponPtr->StateTimeOutCounter=0; + } + } + } + } + +} + +void TemplateHands_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + SECTION *root_section; + + root_section=GetNamedHierarchyFromLibrary("pred_HUD","Template"); + GLOBALASSERT(root_section); + + PlayersWeaponHModelController.Sequence_Type=(int)HMSQT_PredatorHUD; + PlayersWeaponHModelController.Sub_Sequence=(int)PHSS_Go; + PlayersWeaponHModelController.Seconds_For_Sequence=(ONE_FIXED/3); + /* That to get the new sections right. */ + Transmogrify_HModels(NULL,&PlayersWeaponHModelController,root_section, 0, 1,0); + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Go,(ONE_FIXED/3),0); + + } +} + +void WristBlade_Readying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + SECTION *root_section; + + root_section=GetNamedHierarchyFromLibrary("pred_HUD","wrist blade"); + GLOBALASSERT(root_section); + + PlayersWeaponHModelController.Sequence_Type=(int)HMSQT_PredatorHUD; + PlayersWeaponHModelController.Sub_Sequence=(int)PHSS_Come; + PlayersWeaponHModelController.Seconds_For_Sequence=(ONE_FIXED>>1); + /* That to get the new sections right. */ + Transmogrify_HModels(NULL,&PlayersWeaponHModelController,root_section, 0, 1,0); + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Come,(ONE_FIXED>>1),0); + + } +} + +void WristBlade_Unreadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Go,ONE_FIXED>>1); + PlayersWeaponHModelController.Looped=0; + } +} + +void StrikeTime(int time) { + + char mbuf[128]; + + if (time<1) { + sprintf(mbuf,"STRIKETIME IS %d\n",WBStrikeTime); + NewOnScreenMessage(mbuf); + return; + } + + sprintf(mbuf,"STRIKETIME %d -> %d\n",WBStrikeTime,time); + NewOnScreenMessage(mbuf); + + TemplateWeapon[WEAPON_PRED_WRISTBLADE].TimeOutRateForState[WEAPONSTATE_FIRING_PRIMARY]= + (DIV_FIXED(WEAPONSTATE_INITIALTIMEOUTCOUNT,time)); + WBStrikeTime=time; + +} + +void GoGoGadgetCudgelPrimaryAttackAnimation(void) { + + /* Standard_Fire is the default. */ + + if ((FastRandom()&65535)<21645) { + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Fire)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Standard_Fire,-1,0); + if (PlayerStatusPtr->ShapeState!=PMph_Standing) { + StaffAttack=0; + } else { + StaffAttack=1; + } + return; + } + } + + if ((FastRandom()&65535)<32767) { + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Secondary_Fire)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Secondary_Fire,-1,0); + if (PlayerStatusPtr->ShapeState!=PMph_Standing) { + StaffAttack=2; + } else { + StaffAttack=3; + } + return; + } + } + + /* Still here? Use default. */ + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Standard_Fire,-1,0); + if (PlayerStatusPtr->ShapeState!=PMph_Standing) { + StaffAttack=0; + } else { + StaffAttack=1; + } + +} + +void Cudgel_Strike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + /* Let's cut'n'paster the wristblade code. */ + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + GoGoGadgetCudgelPrimaryAttackAnimation(); + + } else { + if ((PlayersWeaponHModelController.Sub_Sequence!=MHSS_Standard_Fire) + &&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Secondary_Fire)) { + /* Something's changing state without resetting the timer... */ + GoGoGadgetCudgelPrimaryAttackAnimation(); + } + + if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) { + /* End state. */ + weaponPtr->StateTimeOutCounter = 0; + StaffAttack=-1; + } else { + /* Maintain attack. */ + weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1); + + } + + { + /* In the middle. */ + /* Execute attack. */ + int hits; + + hits=0; + + if (PlayersWeaponHModelController.keyframe_flags&1) { + hits++; + } + + if (hits) { + + enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID; + + MeleeWeapon_90Degree_Front_Core(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty],ONE_FIXED,TemplateAmmo[AmmoID].MaxRange); + PlayCudgelSound(); + HtoHStrikes++; + } + } + } + +} + +void GoGoGadgetWristbladePrimaryAttackAnimation(void) { + + /* Attack_Jab is the default. */ + + if ((FastRandom()&65535)<21645) { + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Attack_Primary)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,-1,0); + if (PlayerStatusPtr->ShapeState!=PMph_Standing) { + StaffAttack=6; + } else { + StaffAttack=7; + } + return; + } + } + + if ((FastRandom()&65535)<32767) { + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Attack_Secondary)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Secondary,-1,0); + if (PlayerStatusPtr->ShapeState!=PMph_Standing) { + StaffAttack=8; + } else { + StaffAttack=9; + } + return; + } + } + + /* Still here? Use default. */ + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Jab,-1,0); + if (PlayerStatusPtr->ShapeState!=PMph_Standing) { + StaffAttack=0; + } else { + StaffAttack=1; + } + +} + +void WristBlade_Strike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + #if 0 + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + if ((FastRandom()&65536)<32767) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,WBStrikeTime,0); + } else { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,WBStrikeTime,0); + //InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Secondary,WBStrikeTime,0); + } + } + + { + /* Execute attack. */ + int hits; + + hits=0; + + if (PlayersWeaponHModelController.keyframe_flags&1) { + hits++; + } + + if (hits) { + + enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID; + + MeleeWeapon_90Degree_Front_Core(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty],ONE_FIXED,TemplateAmmo[AmmoID].MaxRange); + PlayPredSlashSound(); + + } + + } + #else + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + GoGoGadgetWristbladePrimaryAttackAnimation(); + + } else { + if ((PlayersWeaponHModelController.Sub_Sequence!=PHSS_Attack_Jab) + &&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Attack_Primary) + &&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Attack_Secondary)) { + /* Something's changing state without resetting the timer... */ + GoGoGadgetWristbladePrimaryAttackAnimation(); + } + + if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) { + /* End state. */ + weaponPtr->StateTimeOutCounter = 0; + StaffAttack=-1; + } else { + /* Maintain attack. */ + weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1); + + } + + { + //enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID; + /* In the middle. */ + /* Execute attack. */ + int hits; + + hits=0; + + if (PlayersWeaponHModelController.keyframe_flags&1) { + hits++; + } + + if (hits) { + + enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID; + + MeleeWeapon_90Degree_Front_Core(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty],ONE_FIXED,TemplateAmmo[AmmoID].MaxRange); + PlayPredSlashSound(); + HtoHStrikes++; + } + } + } + #endif + +} + +void WristBlade_Strike_Secondary(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + if ((FastRandom()&65536)<32767) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,-1,0); + if (PlayerStatusPtr->ShapeState!=PMph_Standing) { + StaffAttack=2; + } else { + StaffAttack=3; + } + } else { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Secondary,-1,0); + if (PlayerStatusPtr->ShapeState!=PMph_Standing) { + StaffAttack=4; + } else { + StaffAttack=5; + } + } + + } else { + if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) { + /* End state. */ + weaponPtr->StateTimeOutCounter = 0; + StaffAttack=-1; + } else { + /* Maintain attack. */ + weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1); + + } + + { + //enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID; + /* In the middle. */ + /* Execute attack. */ + int hits; + + hits=0; + + if (PlayersWeaponHModelController.keyframe_flags&1) { + hits++; + } + + if (hits) { + + enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].SecondaryAmmoID; + + MeleeWeapon_90Degree_Front_Core(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty],ONE_FIXED,TemplateAmmo[AmmoID].MaxRange); + PlayPredSlashSound(); + HtoHStrikes++; + + } + + } + } + +} + +void PredPistol_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Come,-1); + PlayersWeaponHModelController.Looped=0; + + } else if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) { + /* End state. */ + weaponPtr->StateTimeOutCounter = 0; + + } else { + + /* In the middle. */ + weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1); + + } + +} + +void PredPistol_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Go,-1,0); + PlayersWeaponHModelController.Looped=0; + + } else if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) { + /* End state. */ + weaponPtr->StateTimeOutCounter = 0; + + } else { + + /* In the middle. */ + weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1); + + } + +} + +void PredPistol_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Stand,ONE_FIXED,1); + } + + /* Are we running? */ + + #if 1 + if ( (Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0) + || (Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0) + || (Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0) ) { + + /* Were we running? */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Run)) { + if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Run) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Run,ONE_FIXED,1); + } + } else { + if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),PHSS_Stand,(int)PHSS_Stand,ONE_FIXED,1); + } + } + } else { + #else + { + #endif + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if ((PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1); + } + + if (weaponPtr->StateTimeOutCounter > ONE_FIXED) { + + if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Fidget) { + if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1); + } + } else if ((FastRandom()&255)==0) { + /* Start animation. */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_PredatorHUD,(int)PHSS_Fidget,-1,0); + weaponPtr->StateTimeOutCounter=0; + } + } + } + } + + Flamethrower_Timer=0; + +} + +void PredPistol_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,ONE_FIXED,1); + } + +} + +int PlayerFireFlameThrower(PLAYER_WEAPON_DATA *weaponPtr) { + + extern VECTORCH CentreOfMuzzleOffset; + VECTORCH *firingpos; + + TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber]; + int oldAmmoCount; + + ProveHModel(&PlayersWeaponHModelController,&PlayersWeapon); + { + oldAmmoCount=weaponPtr->PrimaryRoundsRemaining>>16; + /* ammo is in 16.16. we want the integer part, rounded up */ + if ( (weaponPtr->PrimaryRoundsRemaining&0xffff)!=0 ) oldAmmoCount+=1; + } + + + { + /* theoretical number of bullets fired each frame, as a 16.16 number */ + int bulletsToFire=MUL_FIXED(twPtr->FiringRate,NormalFrameTime); + + if (bulletsToFirePrimaryRoundsRemaining) + { + weaponPtr->PrimaryRoundsRemaining -= bulletsToFire; + } + else /* end of magazine */ + { + weaponPtr->PrimaryRoundsRemaining=0; + } + } + + { + int bulletsFired; + int newAmmoCount=weaponPtr->PrimaryRoundsRemaining>>16; + /* ammo is in 16.16. we want the integer part, rounded up */ + if ( (weaponPtr->PrimaryRoundsRemaining&0xffff)!=0 ) newAmmoCount+=1; + + bulletsFired = oldAmmoCount-newAmmoCount; + + } + + CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,NormalFrameTime); + + if ((PWMFSDP)&&(PlayersTarget.Distance>2500)) { //Was 1700 + VECTORCH null_vec={0,0,0}; + + textprint("Hierarchical Flamethrower Fire!\n"); + + firingpos=&PWMFSDP->World_Offset; + + FireFlameThrower(firingpos,&null_vec,&PlayersWeapon.ObMat,0, &Flamethrower_Timer); + + } else { + #if 0 + firingpos=&CentreOfMuzzleOffset; + FireFlameThrower(&PlayersWeapon.ObWorld,firingpos,&PlayersWeapon.ObMat,1, &Flamethrower_Timer); + #else + VECTORCH Firing_Position; + VECTORCH null_vec={0,0,0}; + int lerp; + + /* Find a better place to fire from. */ + Firing_Position=PlayersWeapon.ObWorld; + + Firing_Position.vx+=MUL_FIXED(PlayersWeapon.ObMat.mat31,200); //z: 300? + Firing_Position.vy+=MUL_FIXED(PlayersWeapon.ObMat.mat32,200); //z: 300? + Firing_Position.vz+=MUL_FIXED(PlayersWeapon.ObMat.mat33,200); //z: 300? + + Firing_Position.vx+=MUL_FIXED(PlayersWeapon.ObMat.mat21,50); //y: 150? + Firing_Position.vy+=MUL_FIXED(PlayersWeapon.ObMat.mat22,50); //y: 150? + Firing_Position.vz+=MUL_FIXED(PlayersWeapon.ObMat.mat23,50); //y: 150? + + Firing_Position.vx+=MUL_FIXED(PlayersWeapon.ObMat.mat11,200); //x: 250? + Firing_Position.vy+=MUL_FIXED(PlayersWeapon.ObMat.mat12,200); //x: 250? + Firing_Position.vz+=MUL_FIXED(PlayersWeapon.ObMat.mat13,200); //x: 250? + /* Interpolation... */ + if (PWMFSDP) { + lerp=PlayersTarget.Distance-1600; + if (lerp<0) { + lerp=0; + } + lerp=MUL_FIXED(lerp,ONE_FIXED); + lerp=DIV_FIXED(lerp,(2500-1600)); + + textprint("lerp %d\n",lerp); + + Firing_Position.vx=MUL_FIXED((ONE_FIXED-lerp),Firing_Position.vx); + Firing_Position.vy=MUL_FIXED((ONE_FIXED-lerp),Firing_Position.vy); + Firing_Position.vz=MUL_FIXED((ONE_FIXED-lerp),Firing_Position.vz); + + Firing_Position.vx+=MUL_FIXED(lerp,PWMFSDP->World_Offset.vx); + Firing_Position.vy+=MUL_FIXED(lerp,PWMFSDP->World_Offset.vy); + Firing_Position.vz+=MUL_FIXED(lerp,PWMFSDP->World_Offset.vz); + } + + FireFlameThrower(&Firing_Position,&null_vec,&PlayersWeapon.ObMat,0, &Flamethrower_Timer); + #endif + } + + + return(1); + +} + +#define ALWAYS_EXIT_WOUNDS 1 + +DISPLAYBLOCK *CauseDamageToHModel(HMODELCONTROLLER *HMC_Ptr, STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, SECTION_DATA *this_section_data,VECTORCH *incoming, VECTORCH *position, int FromHost) { + + DAMAGEBLOCK tempdamage; + int healthdamage,armourdamage; + int wounds; + DISPLAYBLOCK *frag; + + LOCALASSERT(HMC_Ptr==this_section_data->my_controller); + + frag=NULL; + + if ((FromHost==0)&&(sbPtr->I_SBtype==I_BehaviourNetGhost)) { + DamageNetworkGhost(sbPtr, damage, multiple,this_section_data,incoming); + return(NULL); + } + + if (sbPtr->I_SBtype==I_BehaviourDummy) { + /* Dummys are INDESTRUCTIBLE. */ + return(NULL); + } + + if(sbPtr->I_SBtype==I_BehaviourMarinePlayer || + sbPtr->I_SBtype==I_BehaviourAlienPlayer || + sbPtr->I_SBtype==I_BehaviourPredatorPlayer) + { + //check for player invulnerability + PLAYER_STATUS *psPtr=(PLAYER_STATUS*)sbPtr->SBdataptr; + GLOBALASSERT(psPtr); + if(psPtr->invulnerabilityTimer>0) + { + //player is still invulnerable + return(NULL); + } + } + + wounds=0; + + /* Pass damage up test? */ + if ( (this_section_data->sempai->flags§ion_flag_passdamagetoparent) + &&(this_section_data->My_Parent)) { + /* Try again, a level up. */ + return(CauseDamageToHModel(HMC_Ptr,sbPtr,damage,multiple,this_section_data->My_Parent,incoming,position,FromHost)); + } + + /* The section takes damage... and the SB takes the health and armour damage. */ + tempdamage.Health=this_section_data->current_damage.Health; + tempdamage.Armour=this_section_data->current_damage.Armour; + DamageDamageBlock(&this_section_data->current_damage,damage,multiple); + if (this_section_data->sempai->flags§ion_flag_doesnthurtsb) { + healthdamage=0; + armourdamage=0; + } else { + healthdamage=tempdamage.Health-this_section_data->current_damage.Health; + armourdamage=tempdamage.Armour-this_section_data->current_damage.Armour; + } + + if (armourdamage>0) { + if (sbPtr->SBDamageBlock.ArmourSBDamageBlock.Armour=0; + else sbPtr->SBDamageBlock.Armour-=armourdamage; + } + + if (healthdamage>0) { + if (sbPtr->SBDamageBlock.HealthSBDamageBlock.Health=0; + else sbPtr->SBDamageBlock.Health-=healthdamage; + } + + /* Consider networking. */ + if (AvP.Network != I_No_Network) + { + if (sbPtr->I_SBtype!=I_BehaviourNetGhost) { + AddNetMsg_GhostHierarchyDamaged(sbPtr,damage,multiple,this_section_data->sempai->IDnumber,incoming); + } + } + + #if ALWAYS_EXIT_WOUNDS + /* otherwise, exit wounds! */ + if ((incoming)&&(this_section_data->sempai->flags§ion_sprays_anything) + &&(damage->MakeExitWounds)) { + enum PARTICLE_ID blood_type; + int a; + VECTORCH *startpos; + VECTORCH final_spray_direction; + + if (this_section_data->sempai->flags§ion_sprays_blood) { + blood_type=GetBloodType(sbPtr); + /* Er... default? */ + } else if (this_section_data->sempai->flags§ion_sprays_acid) { + blood_type=PARTICLE_ALIEN_BLOOD; + } else if (this_section_data->sempai->flags§ion_sprays_predoblood) { + blood_type=PARTICLE_PREDATOR_BLOOD; + } else if (this_section_data->sempai->flags§ion_sprays_sparks) { + blood_type=PARTICLE_SPARK; + } else { + blood_type=PARTICLE_FLAME; + /* Distinctive. */ + } + + if (position) { + startpos=position; + } else { + startpos=&this_section_data->World_Offset; + } + /* 'incoming' SHOULD be normalised. */ + for (a=0; a<(multiple>>ONE_FIXED_SHIFT); a++) { + + RotateAndCopyVector(incoming,&final_spray_direction,&sbPtr->DynPtr->OrientMat); + + /* Scale down. */ + + //final_spray_direction.vx>>=1; + //final_spray_direction.vy>>=1; + //final_spray_direction.vz>>=1; + + /* Add random element. */ + + final_spray_direction.vx+=( (FastRandom()&511)-256); + final_spray_direction.vy+=( (FastRandom()&511)-256); + final_spray_direction.vz+=( (FastRandom()&511)-256); + + MakeParticle(startpos, &final_spray_direction, blood_type); + } + } + #endif + + if (this_section_data->current_damage.Health<=0) { + /* Might want to create a frag here? */ + if (damage->BlowUpSections) { + + VECTORCH blastCentre; + /* Deduce blastCentre. */ + blastCentre=this_section_data->World_Offset; + + if (incoming) { + blastCentre.vx+=incoming->vx; + blastCentre.vy+=incoming->vy; + blastCentre.vz+=incoming->vz; + } + + /* For the moment, this ALWAYS has priority. */ + Pop_Section(sbPtr,this_section_data,&blastCentre,&wounds); + + if (wounds§ion_has_sparkoflife) { + /* Kill SB off! */ + sbPtr->SBDamageBlock.Health=0; + /* That's the way... */ + } + + } else if ( ((this_section_data->sempai->flags§ion_is_master_root)==0) + &&((this_section_data->sempai->flags§ion_flag_never_frag)==0) + &&(((this_section_data->sempai->flags§ion_sprays_acid)&&((this_section_data->sempai->flags§ion_flag_fragonlyfordisks)==0)) + ||((this_section_data->sempai->StartingStats.Healthsempai->flags§ion_flag_fragonlyfordisks==0)) + ||((damage->Slicing>2)&&(this_section_data->sempai->flags§ion_flag_fragonlyfordisks)) + ||((damage->Slicing>0)&&((this_section_data->sempai->flags§ion_flag_fragonlyfordisks)==0)) + ) + ){ + + MATRIXCH *orientptr; + { + /* Work out which orientation to use. */ + if (this_section_data->My_Parent==NULL) { + /* The root (Gah!), so use sbPtr. */ + orientptr=&sbPtr->DynPtr->OrientMat; + } else { + /* Use parent. */ + orientptr=&this_section_data->My_Parent->SecMat; + } + } + + /* Never frag off the root, it wouldn't make sense. */ + + frag=MakeHierarchicalDebris(sbPtr,this_section_data, &this_section_data->World_Offset, orientptr,&wounds,3); + + /* Oh Dear! Every section below and including this one becomes... unreal. + And if any of them contain the spark of life, we need to know. */ + + if (wounds§ion_has_sparkoflife) { + /* Kill SB off! */ + sbPtr->SBDamageBlock.Health=0; + /* That's the way... */ + } + } else { + /* Don't frag the master root, and take care with non-aliens. */ + if (this_section_data->sempai->flags§ion_has_sparkoflife) { + /* However, if the master root is destroyed and is a critical section, */ + sbPtr->SBDamageBlock.Health=0; + /* ...still kill them off. */ + } + #if (ALWAYS_EXIT_WOUNDS==0) + /* otherwise, exit wounds! */ + if ((incoming)&&(this_section_data->sempai->flags§ion_sprays_anything) + &&(damage->MakeExitWounds)) { + enum PARTICLE_ID blood_type; + int a; + VECTORCH *startpos; + VECTORCH final_spray_direction; + + if (this_section_data->sempai->flags§ion_sprays_blood) { + blood_type=GetBloodType(sbPtr); + /* Er... default? */ + } else if (this_section_data->sempai->flags§ion_sprays_acid) { + blood_type=PARTICLE_ALIEN_BLOOD; + } else if (this_section_data->sempai->flags§ion_sprays_predoblood) { + blood_type=PARTICLE_PREDATOR_BLOOD; + } else if (this_section_data->sempai->flags§ion_sprays_sparks) { + blood_type=PARTICLE_SPARK; + } else { + blood_type=PARTICLE_FLAME; + /* Distinctive. */ + } + + if (position) { + startpos=position; + } else { + startpos=&this_section_data->World_Offset; + } + /* 'incoming' SHOULD be normalised. */ + for (a=0; a<(multiple>>ONE_FIXED_SHIFT); a++) { + + RotateAndCopyVector(incoming,&final_spray_direction,&sbPtr->DynPtr->OrientMat); + + /* Scale down. */ + + //final_spray_direction.vx>>=1; + //final_spray_direction.vy>>=1; + //final_spray_direction.vz>>=1; + + /* Add random element. */ + + final_spray_direction.vx+=( (FastRandom()&511)-256); + final_spray_direction.vy+=( (FastRandom()&511)-256); + final_spray_direction.vz+=( (FastRandom()&511)-256); + + MakeParticle(startpos, &final_spray_direction, blood_type); + } + } + #endif + } + } + + /* There... */ + + switch(sbPtr->I_SBtype) + { + case I_BehaviourAlien: + { + /* reduce alien health */ + AlienIsDamaged(sbPtr, damage, multiple, wounds,this_section_data,incoming,frag); + break; + } + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + { + PlayerIsDamaged(sbPtr,damage,multiple,incoming); + break; + } + case I_BehaviourInanimateObject: + { + InanimateObjectIsDamaged(sbPtr,damage,multiple); + break; + } + case I_BehaviourPredator: + { + PredatorIsDamaged(sbPtr,damage,multiple,this_section_data,incoming); + break; + } + case I_BehaviourXenoborg: + { + XenoborgIsDamaged(sbPtr, damage, multiple, wounds,incoming); + break; + } + case I_BehaviourSeal: + case I_BehaviourMarine: + { + MarineIsDamaged(sbPtr,damage,multiple,wounds,this_section_data,incoming); + break; + } + case I_BehaviourQueenAlien: + { + QueenIsDamaged(sbPtr,damage,multiple,this_section_data,incoming,position); + break; + } + case I_BehaviourPredatorAlien: + { + GLOBALASSERT(0); + //PAQIsDamaged(sbPtr,damage,multiple); + break; + } + case I_BehaviourFaceHugger: + { + FacehuggerIsDamaged(sbPtr,damage,multiple); + break; + } + #if 0 + /* Whoa, positive feedback! */ + case I_BehaviourNetGhost: + { + #if SupportWindows95 + DamageNetworkGhost(sbPtr, damage, multiple,this_section_data,incoming); + #endif + break; + } + #endif + case I_BehaviourAutoGun: + { + AGunIsDamaged(sbPtr, damage, multiple, wounds,incoming); + break; + } + case I_BehaviourNetCorpse: + { + CorpseIsDamaged(sbPtr,damage,multiple,wounds,this_section_data,incoming); + break; + } + default: + break; + } + + return(frag); +} + +VECTORCH HitAreaArray[HAM_end] = { + {0,0,0}, + {0,0,1000}, + {0,0,-1000}, + {0,-1000,0}, + {0,1000,0}, + {-1000,0,0}, + {1000,0,0}, + {-1000,-1000,0}, + {1000,-1000,0}, + {-1000,1000,0}, + {1000,1000,0}, +}; + +VECTORCH Local_HitAreaArray[HAM_end]; +HITAREAMATRIX HitZone,HitAspect; + +void FindHitArea(DISPLAYBLOCK *dptr) { + + int a; + MATRIXCH LtoV; + int nearest,neardist,dist; + int fbnearest,fbneardist; + + MatrixMultiply(&Global_VDB_Ptr->VDB_Mat,&dptr->ObMat,&LtoV); + + nearest=-1; + fbnearest=-1; + neardist=1000000; + fbneardist=1000000; + + for (a=0; aObView.vx; + Local_HitAreaArray[a].vy+=dptr->ObView.vy; + Local_HitAreaArray[a].vz+=dptr->ObView.vz; + + + dist=Approximate3dMagnitude(&Local_HitAreaArray[a]); + + if ( (a!=HAM_Front) && (a!=HAM_Back) ) { + if (distI_SBtype) { + case I_BehaviourMarine: + case I_BehaviourSeal: + { + /* Get hierarchy name... */ + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + hltable=GetThisHitLocationTable(marineStatusPointer->My_Weapon->HitLocationTableName); + } + break; + case I_BehaviourAlien: + { + ALIEN_STATUS_BLOCK *alienStatusPointer; + + LOCALASSERT(sbPtr); + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + switch (alienStatusPointer->Type) { + case AT_Standard: + default: + hltable=GetThisHitLocationTable("alien"); + break; + case AT_Predalien: + hltable=GetThisHitLocationTable("predalien"); + break; + case AT_Praetorian: + hltable=GetThisHitLocationTable("praetorian"); + break; + } + } + break; + case I_BehaviourPredator: + { + /* Get hierarchy name... */ + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + hltable=GetThisHitLocationTable(predatorStatusPointer->Selected_Weapon->HitLocationTableName); + } + break; + case I_BehaviourXenoborg: + hltable=GetThisHitLocationTable("xenoborg"); + break; + case I_BehaviourAutoGun: + hltable=GetThisHitLocationTable("sentrygun"); + break; + case I_BehaviourNetCorpse: + { + NETCORPSEDATABLOCK *corpseDataPtr; + + LOCALASSERT(sbPtr); + corpseDataPtr = (NETCORPSEDATABLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(corpseDataPtr); + + hltable=corpseDataPtr->hltable; + /* Special corpse case. */ + HitZone=HAM_Centre; + HitAspect=HAM_Centre; + } + break; + case I_BehaviourNetGhost : + { + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + hltable=ghostData->hltable; + + if(ghostData->type==I_BehaviourNetCorpse) + { + //special corpse case here as well , I should imagine + HitZone=HAM_Centre; + HitAspect=HAM_Centre; + } + + } + break; + default: + textprint("No hit table!\n"); + hltable=NULL; + /* See ChrisF */ + break; + } + + if (hltable==NULL) { + /* Hey ho... */ + return(NULL); + } + + /* Now the fun bit. */ + + dice=FastRandom()&65535; + + switch (HitZone) { + case HAM_Centre: + subtable=hltable->CentreLocs; + break; + case HAM_Top: + subtable=hltable->TopLocs; + break; + case HAM_Base: + subtable=hltable->BaseLocs; + break; + case HAM_Left: + subtable=hltable->LeftLocs; + break; + case HAM_Right: + subtable=hltable->RightLocs; + break; + case HAM_TopLeft: + subtable=hltable->TopLeftLocs; + break; + case HAM_TopRight: + subtable=hltable->TopRightLocs; + break; + case HAM_BaseLeft: + subtable=hltable->BaseLeftLocs; + break; + case HAM_BaseRight: + subtable=hltable->BaseRightLocs; + break; + default: + GLOBALASSERT(0); + break; + } + + /* Now, get location. */ + + entry=subtable; + + while (entry->section_name!=NULL) { + if (dicecprob) { + if (!( ( (HitAspect==HAM_Front)&&(entry->aspect&back_aspect) ) + ||( (HitAspect==HAM_Back)&&(entry->aspect&front_aspect) ) )) { + /* Okay! */ + break; + } + } + dice-=entry->cprob; + entry++; + } + + return(entry); +} + +SECTION_DATA *HitLocationRoll(STRATEGYBLOCK *sbPtr, STRATEGYBLOCK *source) { + + HITLOCATIONTABLEENTRY *entry; + + if (sbPtr->SBdptr==NULL) { + /* Far case? Hey ho... */ + return(NULL); + } + + if (sbPtr->SBdptr->HModelControlBlock==NULL) { + /* Not a hierarchy. */ + return(NULL); + } + + if ((source==NULL) || (source==Player->ObStrategyBlock)) { + /* Why not? This shouldn't get called, really... */ + FindHitArea(sbPtr->SBdptr); + } else { + HitZone=HAM_Top; + HitAspect=HAM_Centre; + } + + entry=Get_Sublocation(sbPtr); + + if (entry==NULL) { + /* Failure! */ + return(NULL); + } + + if (entry->section_name) { + /* Valid hit. */ + SECTION_DATA *target; + target=GetThisSectionData(sbPtr->SBdptr->HModelControlBlock->section_data,entry->section_name); + + if (target) { + /* Success! */ + return(target); + } + } + + /* Failure! */ + return(NULL); +} + +DISPLAYBLOCK *HtoHDamageToHModel(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, STRATEGYBLOCK *source, VECTORCH *attack_dir) { + + HITLOCATIONTABLEENTRY *entry; + + if (sbPtr->SBdptr==NULL) { + /* Far case? Hey ho... */ + CauseDamageToObject(sbPtr, damage, multiple,attack_dir); + return(NULL); + } + + LOCALASSERT(sbPtr->SBdptr->HModelControlBlock); + + if ((source==NULL) || (source==Player->ObStrategyBlock)) { + FindHitArea(sbPtr->SBdptr); + } else { + HitZone=HAM_Top; + HitAspect=HAM_Centre; + } + + entry=Get_Sublocation(sbPtr); + + if (entry==NULL) { + /* Failure! */ + CauseDamageToObject(sbPtr, damage, multiple,attack_dir); + return(NULL); + } + + if (entry->section_name) { + /* Valid hit. */ + SECTION_DATA *target; + target=GetThisSectionData(sbPtr->SBdptr->HModelControlBlock->section_data,entry->section_name); + + if (target) { + /* Success! */ + DISPLAYBLOCK *frag; + textprint("Damaged %s!\n",entry->section_name); + frag=CauseDamageToHModel(sbPtr->SBdptr->HModelControlBlock, sbPtr, damage, multiple, target,attack_dir,NULL,0); + return(frag); + } + } + + /* Failure! Never mind. */ + + CauseDamageToObject(sbPtr, damage, multiple,attack_dir); + return(NULL); +} + +void AlienClaw_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_AlienHUD,(int)AHSS_LeftSwipeDown,ONE_FIXED/3); + PlayersWeaponHModelController.Looped=0; + PlayersWeaponHModelController.Playing=0; + } + + LastHand=0; + Alien_Visible_Weapon=0; //Claws +} + +void AlienClaw_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + /* ...Nothing? */ + +} + +void AlienClaw_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + /* ...Nothing? */ + + if ( (Player->ObStrategyBlock->DynPtr->IsInContactWithFloor==0) + && (Player->ObStrategyBlock->DynPtr->TimeNotInContactWithFloor<=0) ) { + /* Jumping or falling... */ + TemplateWeapon[WEAPON_ALIEN_CLAW].PrimaryIsAutomatic=0; + } else { + TemplateWeapon[WEAPON_ALIEN_CLAW].PrimaryIsAutomatic=1; + } + + if (Alien_Visible_Weapon==1) { + /* Correct tail idle position. */ + DELTA_CONTROLLER *XDelta,*YDelta; + + GLOBALASSERT(Alien_Visible_Weapon==1); + + XDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"XDelta"); + YDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"YDelta"); + + XDelta->timer=32767; + YDelta->timer=32767; + } + +} + +void AlienClaw_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + /* Look for surplus claw keyframe flags. */ + { + /* Execute attack. */ + int hits; + + hits=0; + + if (PlayersWeaponHModelController.keyframe_flags&1) { + hits++; + } + + if (PlayersWeaponHModelController.keyframe_flags&2) { + hits++; + } + + if (hits) { + + HtoHStrikes+=hits; + + MeleeWeapon_180Degree_Front_Core(&Player_Weapon_Damage,ONE_FIXED*hits,4000); + PlayAlienSwipeSound(); + + } + } + + if ( (Player->ObStrategyBlock->DynPtr->IsInContactWithFloor==0) + && (Player->ObStrategyBlock->DynPtr->TimeNotInContactWithFloor<=0) ) { + /* Jumping or falling... */ + TemplateWeapon[WEAPON_ALIEN_CLAW].PrimaryIsAutomatic=0; + } else { + TemplateWeapon[WEAPON_ALIEN_CLAW].PrimaryIsAutomatic=1; + } + + if (Alien_Visible_Weapon==1) { + /* Correct tail idle position. */ + DELTA_CONTROLLER *XDelta,*YDelta; + + GLOBALASSERT(Alien_Visible_Weapon==1); + + XDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"XDelta"); + YDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"YDelta"); + + XDelta->timer=32767; + YDelta->timer=32767; + } + +} + +void FixAlienStrikeSpeed(int time) { + + ACStrikeTime=MUL_FIXED(time,AC_Speed_Factor); + + TemplateWeapon[WEAPON_ALIEN_CLAW].TimeOutRateForState[WEAPONSTATE_FIRING_PRIMARY]= + (DIV_FIXED(WEAPONSTATE_INITIALTIMEOUTCOUNT,ACStrikeTime)); + +} + +void AlienStrikeTime(int time) { + + if (time<1) return; + + AC_Speed_Factor=time; + +} + +void WristBlade_WindUp(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD, + (int)PHSS_PullBack,-1,0); + + /* Setup base damage. */ + Player_Weapon_Damage=TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty]; + Player_Weapon_Damage.Special=0; + + Alien_Tail_Clock=0; + Wristblade_StrikeType=0; + + TemplateWeapon[WEAPON_PRED_WRISTBLADE].SecondaryIsAutomatic=1; + + } else if ((PlayersWeaponHModelController.Tweening==Controller_NoTweening) + &&(PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1))) { + + /* Finished poise move. */ + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD, + (int)PHSS_Hold,-1,1); + + Alien_Tail_Clock=-1; + + } else if (Alien_Tail_Clock>=0) { + + int flags,a; + + Alien_Tail_Clock+=NormalFrameTime; + + /* In the move... */ + flags=PlayersWeaponHModelController.keyframe_flags; + + for (a=0; a<6; a++) { + /* Gotta be less than six! */ + if (flags&1) { + Wristblade_StrikeType++; + } + flags>>=1; + } + + } else { + /* Windup finished and holding... timeout? */ + Wristblade_StrikeType=-1; + GLOBALASSERT(Alien_Tail_Clock<0); + Alien_Tail_Clock-=NormalFrameTime; + if (Alien_Tail_Clock<-(ONE_FIXED<<2)) { + /* Time out? */ + if (PlayersWeaponHModelController.Sub_Sequence!=PHSS_PullBack) { + InitHModelTweening_Backwards(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD, + (int)PHSS_PullBack,-1,0); + } else { + /* In the timeout... */ + if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) { + /* End fire, somehow. */ + weaponPtr->CurrentState = WEAPONSTATE_RECOIL_SECONDARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + return; + } + } + } + } + +} + +void ThrowSecondaryStrongStrike(void) { + + int attack=-1; + + if ((FastRandom()&65535)<32767) { + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, + (int)PHSS_Attack_Secondary_Strong_One)) { + attack=0; + } else { + attack=1; + } + } else { + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, + (int)PHSS_Attack_Secondary_Strong_Two)) { + attack=1; + } else { + attack=0; + } + } + + switch (attack) { + default: + case 0: + GLOBALASSERT(HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, + (int)PHSS_Attack_Secondary_Strong_One)); + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD, + (int)PHSS_Attack_Secondary_Strong_One,-1,0); + + if (PlayerStatusPtr->ShapeState!=PMph_Standing) { + StaffAttack=2; + } else { + StaffAttack=3; + } + break; + case 1: + GLOBALASSERT(HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, + (int)PHSS_Attack_Secondary_Strong_Two)); + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD, + (int)PHSS_Attack_Secondary_Strong_Two,-1,0); + + if (PlayerStatusPtr->ShapeState!=PMph_Standing) { + StaffAttack=2; + } else { + StaffAttack=3; + } + break; + } +} + +void ThrowSecondaryWeakStrike(void) { + + int attack=-1; + + if ((FastRandom()&65535)<32767) { + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, + (int)PHSS_Attack_Secondary_Weak_One)) { + attack=0; + } else { + attack=1; + } + } else { + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, + (int)PHSS_Attack_Secondary_Weak_Two)) { + attack=1; + } else { + attack=0; + } + } + + switch (attack) { + default: + case 0: + GLOBALASSERT(HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, + (int)PHSS_Attack_Secondary_Weak_One)); + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD, + (int)PHSS_Attack_Secondary_Weak_One,-1,0); + + if (PlayerStatusPtr->ShapeState!=PMph_Standing) { + StaffAttack=4; + } else { + StaffAttack=5; + } + break; + case 1: + GLOBALASSERT(HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD, + (int)PHSS_Attack_Secondary_Weak_Two)); + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD, + (int)PHSS_Attack_Secondary_Weak_Two,-1,0); + + if (PlayerStatusPtr->ShapeState!=PMph_Standing) { + StaffAttack=4; + } else { + StaffAttack=5; + } + break; + } + +} + +void WristBlade_WindUpStrike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + /* Eek! Well, fire must have been released at this stage. */ + + GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_PredatorHUD); + + if (PlayersWeaponHModelController.Tweening!=Controller_NoTweening) { + /* I don't wanna know right now... */ + GLOBALASSERT(PlayersWeaponHModelController.Playing); + return; + + } + + /* Maintain this state... */ + weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1); + + if (PlayersWeaponHModelController.Sub_Sequence==PHSS_PullBack) { + int flag,multiplyer; + + if (PlayersWeaponHModelController.Reversed) { + /* In the timeout. */ + /* Stop quick refire... */ + TemplateWeapon[WEAPON_PRED_WRISTBLADE].SecondaryIsAutomatic=0; + /* Wait, then end. */ + if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) { + /* End state. */ + weaponPtr->StateTimeOutCounter = 0; + StaffAttack=-1; + } + return; + } + + /* Still in the pull back... wait for the right flag. */ + flag=(1<>1); + ThrowSecondaryWeakStrike(); + Player_Weapon_Damage.Special=0; + break; + } + Player_Weapon_Damage.Impact =MUL_FIXED(TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty].Impact ,multiplyer); + Player_Weapon_Damage.Cutting =MUL_FIXED(TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty].Cutting ,multiplyer); + Player_Weapon_Damage.Penetrative=MUL_FIXED(TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty].Penetrative,multiplyer); + Player_Weapon_Damage.Fire =MUL_FIXED(TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty].Fire ,multiplyer); + Player_Weapon_Damage.Electrical =MUL_FIXED(TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty].Electrical ,multiplyer); + Player_Weapon_Damage.Acid =MUL_FIXED(TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty].Acid ,multiplyer); + + } else if ((PlayersWeaponHModelController.Tweening==Controller_NoTweening) + &&(PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1))) { + /* Hit the end! Whoops. Fire big attack. */ + ThrowSecondaryStrongStrike(); + Player_Weapon_Damage=TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty]; + Player_Weapon_Damage.Special=1; + } + + } else if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Hold) { + /* In 'Held Back' stance: fire the biggest attack. */ + ThrowSecondaryStrongStrike(); + Player_Weapon_Damage=TemplateAmmo[AMMO_HEAVY_PRED_WRISTBLADE].MaxDamage[AvP.Difficulty]; + Player_Weapon_Damage.Special=1; + } else { + /* In the attack. Look for flags and do the damage stuff. */ + if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) { + /* End state. */ + weaponPtr->StateTimeOutCounter = 0; + StaffAttack=-1; + } else { + /* Maintain attack. */ + weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1); + } + + { + /* In the middle. */ + /* Execute attack. */ + int hits; + + hits=0; + + if (PlayersWeaponHModelController.keyframe_flags&1) { + hits++; + } + + if (hits) { + + STRATEGYBLOCK *Trophy; + SECTION_DATA *head_sec; + enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].SecondaryAmmoID; + + + /* Intercept 'trophy' attack. */ + if (Player_Weapon_Damage.Special) { + Trophy=GetTrophyTarget(&head_sec); + } else { + Trophy=NULL; + } + if (Trophy) { + /* Apply damage. */ + CauseDamageToHModel(Trophy->SBdptr->HModelControlBlock, Trophy, &TemplateAmmo[AMMO_PRED_TROPHY_KILLSECTION].MaxDamage[AvP.Difficulty], + ONE_FIXED,head_sec,NULL,NULL,0); + if (PlayerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) { + PlayPredatorSound(0,PSC_Taunt,0,&PlayerStatusPtr->soundHandle,NULL); + playerNoise=1; + } + CurrentGameStats_TrophyCollected(Trophy); + } else { + MeleeWeapon_90Degree_Front_Core(&Player_Weapon_Damage,ONE_FIXED,TemplateAmmo[AmmoID].MaxRange); + } + PlayPredSlashSound(); + HtoHStrikes++; + } + } + + } + +} + +void AlienTail_Poise(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + GLOBALASSERT(TemplateWeapon[WEAPON_ALIEN_CLAW].SecondaryIsAutomatic); + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + DELTA_CONTROLLER *XDelta,*YDelta; + + /* Check we've got the tail. */ + + if (Alien_Visible_Weapon!=1) { + + GetHierarchicalWeapon("alien_HUD","tail",(int)HMSQT_AlienHUD,(int)AHSS_TailCome); + ProveHModel(&PlayersWeaponHModelController,&PlayersWeapon); + + Alien_Visible_Weapon=1; + /* Create delta sequences. */ + XDelta=Add_Delta_Sequence(&PlayersWeaponHModelController, + "XDelta",(int)HMSQT_AlienHUD,(int)AHSS_Hor_Delta,0); + YDelta=Add_Delta_Sequence(&PlayersWeaponHModelController, + "YDelta",(int)HMSQT_AlienHUD,(int)AHSS_Ver_Delta,0); + } else { + + XDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"XDelta"); + YDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"YDelta"); + + } + + XDelta->timer=32767; + YDelta->timer=32767; + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD, + (int)AHSS_TailCome,ONE_FIXED,0); + + /* Setup base damage. */ + Player_Weapon_Damage=TemplateAmmo[AMMO_ALIEN_TAIL].MaxDamage[AvP.Difficulty]; + + Player_Weapon_Damage.Impact=0; + Player_Weapon_Damage.Cutting=0; + Player_Weapon_Damage.Penetrative=30; + Player_Weapon_Damage.Fire=0; + Player_Weapon_Damage.Electrical=0; + Player_Weapon_Damage.Acid=0; + + Player_Weapon_Damage.BlowUpSections=0; + Player_Weapon_Damage.Special=0; + + Alien_Tail_Target=NULL; + COPY_NAME(Alien_Tail_Target_SBname,Null_Name); + + Alien_Tail_Clock=0; + + } else if ((PlayersWeaponHModelController.Tweening==Controller_NoTweening) + &&(PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1))) { + + /* Finished poise move. */ + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD, + (int)AHSS_TailHold,ONE_FIXED,1); + + Alien_Tail_Clock=-1; + + textprint("Tail Max. Pen. Damage = %d\n",Player_Weapon_Damage.Penetrative); + + } else if (Alien_Tail_Clock!=-1) { + + Alien_Tail_Clock+=NormalFrameTime; + + while (Alien_Tail_Clock>=1000) { + Player_Weapon_Damage.Penetrative+=1; + Alien_Tail_Clock-=1000; + } + + textprint("Tail Pen. Damage = %d\n",Player_Weapon_Damage.Penetrative); + + } else { + textprint("Tail Max. Pen. Damage = %d - Poised.\n",Player_Weapon_Damage.Penetrative); + } + +} + +int tail_xcal=120; +int tail_ycal=220; + +void ComputeTailDeltaValues(DELTA_CONTROLLER *XDelta,DELTA_CONTROLLER *YDelta) { + + int temp_timer,screenX,screenY; + VECTORCH target_pos; + + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + + GetTargetingPointOfObject(Alien_Tail_Target->SBdptr,&target_pos); + TranslatePointIntoViewspace(&target_pos); + + screenX = WideMulNarrowDiv + ( + target_pos.vx, + VDBPtr->VDB_ProjX, + target_pos.vz + ); + screenY = WideMulNarrowDiv + ( + target_pos.vy, + VDBPtr->VDB_ProjY, + target_pos.vz + ); + + + if (MIRROR_CHEATMODE) { + screenX=-screenX; + } + + temp_timer=screenX*(-tail_xcal); + temp_timer+=32767; + + if (temp_timer<0) temp_timer=0; + if (temp_timer>65535) temp_timer=65535; + XDelta->timer=temp_timer; + + temp_timer=screenY*(tail_ycal); + temp_timer+=32767; + + if (temp_timer<0) temp_timer=0; + if (temp_timer>65535) temp_timer=65535; + YDelta->timer=temp_timer; + + textprint("Target Screen X,Y %d %d\n",screenX,screenY); + +} + +void AlienTail_Strike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + DELTA_CONTROLLER *XDelta,*YDelta; + + GLOBALASSERT(Alien_Visible_Weapon==1); + + XDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"XDelta"); + YDelta=Get_Delta_Sequence(&PlayersWeaponHModelController,"YDelta"); + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + DISPLAYBLOCK *target; + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD, + (int)AHSS_TailStrike,(ONE_FIXED/6),0); + + /* Find target. */ + target=AlienTail_TargetSelect(); + + if (target) { + Alien_Tail_Target=target->ObStrategyBlock; + COPY_NAME(Alien_Tail_Target_SBname,Alien_Tail_Target->SBname); + /* Set XDelta and YDelta. */ + ComputeTailDeltaValues(XDelta,YDelta); + } else { + XDelta->timer=32767; + YDelta->timer=32767; + } + + /* Don't bother with the next bit. */ + return; + } + + /* Check target validity. */ + + if (Validate_Target(Alien_Tail_Target,Alien_Tail_Target_SBname)==0) { + /* Lost it somehow. */ + Alien_Tail_Target=NULL; + COPY_NAME(Alien_Tail_Target_SBname,Null_Name); + } + + if (Alien_Tail_Target) { + if (Alien_Tail_Target->SBdptr==NULL) { + /* Likewise, moved off screen. */ + Alien_Tail_Target=NULL; + COPY_NAME(Alien_Tail_Target_SBname,Null_Name); + } else { + /* Do we still have a target? Correct for aiming. */ + ComputeTailDeltaValues(XDelta,YDelta); + } + } + + if (PlayersWeaponHModelController.keyframe_flags&1) { + + /* Just for now, do damage anyway... */ + if (Alien_Tail_Target) { + + int multiple; + + multiple=ONE_FIXED; + /* Consider target aspect. */ + { + VECTORCH attack_dir,displacement; + + displacement.vx = Alien_Tail_Target->DynPtr->Position.vx - Player->ObStrategyBlock->DynPtr->Position.vx; + displacement.vy = Alien_Tail_Target->DynPtr->Position.vy - Player->ObStrategyBlock->DynPtr->Position.vy; + displacement.vz = Alien_Tail_Target->DynPtr->Position.vz - Player->ObStrategyBlock->DynPtr->Position.vz; + + GetDirectionOfAttack(Alien_Tail_Target,&displacement,&attack_dir); + + if (attack_dir.vz>0) { + multiple<<=1; + } + + if (Alien_Tail_Target->SBdptr->HModelControlBlock) { + HtoHDamageToHModel(Alien_Tail_Target, &Player_Weapon_Damage,multiple, NULL, &attack_dir); + } else { + CauseDamageToObject(Alien_Tail_Target, &Player_Weapon_Damage,multiple, &attack_dir); + } + } + } + PlayAlienTailSound(); + /* Slower recoil... */ + HModel_ChangeSpeed(&PlayersWeaponHModelController,(ONE_FIXED)); + HtoHStrikes++; + + } + +} + +void AlienClaw_Strike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + int alien_speed; + + /* Consider possibility of bite first... */ + Biting=GetBitingTarget(); + if (Biting) { + /* Fix the name. */ + COPY_NAME(Biting_SBname,Biting->SBname); + /* Fix the speed. */ + FixAlienStrikeSpeed(ONE_FIXED/3); + /* Init attack. */ + Bit=0; + /* Then leave. */ + return; + } + + alien_speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity); + + /* Speed: < 5000 = standing. > 22000 = jumping. + In practice, walk/fall = 18000 ish, jump = 27000 ish. */ + + /* Check we've got the claws. */ + + if (Alien_Visible_Weapon!=0) { + + GetHierarchicalWeapon("alien_HUD","claws",(int)HMSQT_AlienHUD,(int)AHSS_LeftSwipeDown); + ProveHModel(&PlayersWeaponHModelController,&PlayersWeapon); + + Alien_Visible_Weapon=0; + + } + + /* Setup base damage. */ + + Player_Weapon_Damage=TemplateAmmo[AMMO_ALIEN_CLAW].MaxDamage[AvP.Difficulty]; + + /* Choose attack type and speed. */ + + if ((alien_speed<5000)&&(PlayerStatusPtr->ShapeState==PMph_Standing) + &&(Player->ObStrategyBlock->DynPtr->IsInContactWithFloor)) { + /* Standing on solid ground. */ + + TemplateWeapon[WEAPON_ALIEN_CLAW].PrimaryIsAutomatic=1; + + FixAlienStrikeSpeed(ONE_FIXED/3); + + textprint("Standing Claw, Speed %d\n",alien_speed); + + if ((FastRandom()&65536)>32768) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD, + (int)AHSS_Both_In,ACStrikeTime,0); + } else { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD, + (int)AHSS_Both_Down,ACStrikeTime,0); + } + + } else { + + /* Crouching, falling, or running? */ + + if ( (Player->ObStrategyBlock->DynPtr->IsInContactWithFloor==0) + && (Player->ObStrategyBlock->DynPtr->TimeNotInContactWithFloor<=0) ) { + /* Jumping or falling... */ + TemplateWeapon[WEAPON_ALIEN_CLAW].PrimaryIsAutomatic=0; + } else { + TemplateWeapon[WEAPON_ALIEN_CLAW].PrimaryIsAutomatic=1; + } + + if (PlayerStatusPtr->ShapeState!=PMph_Standing) { + /* If crouching, falling or no, slower strike. */ + if ( /* Gravity points vaguely down... */ + (Player->ObStrategyBlock->DynPtr->GravityDirection.vx<46341) + &&(Player->ObStrategyBlock->DynPtr->GravityDirection.vx>-46341) + &&(Player->ObStrategyBlock->DynPtr->GravityDirection.vy>46341) + &&(Player->ObStrategyBlock->DynPtr->GravityDirection.vz<46341) + &&(Player->ObStrategyBlock->DynPtr->GravityDirection.vz>-46341) + ) { + FixAlienStrikeSpeed(ONE_FIXED/4); + } else { + FixAlienStrikeSpeed(ONE_FIXED/3); + } + } else { + FixAlienStrikeSpeed(ONE_FIXED/5); + } + + /* Speed test here, for jumping? */ + + if ( (Player->ObStrategyBlock->DynPtr->IsInContactWithFloor==0) + && (Player->ObStrategyBlock->DynPtr->TimeNotInContactWithFloor<=0) + && (alien_speed>22000) ) { + + /* Must be jumping. */ + FixAlienStrikeSpeed(ONE_FIXED/3); + /* Extra damage for pounce. */ + Player_Weapon_Damage.Impact+=10; + Player_Weapon_Damage.Cutting+=10; + if ((FastRandom()&65536)>32768) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD, + (int)AHSS_PounceIn,ACStrikeTime,0); + } else { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD, + (int)AHSS_PounceDown,ACStrikeTime,0); + } + + } else if (LastHand) { + if ((FastRandom()&65536)>32768) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD, + (int)AHSS_LeftSwipeIn,(ONE_FIXED/6),0); + } else { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD, + (int)AHSS_LeftSwipeDown,(ONE_FIXED/6),0); + } + LastHand=0; + } else { + if ((FastRandom()&65536)>32768) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD, + (int)AHSS_RightSwipeIn,(ONE_FIXED/6),0); + } else { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD, + (int)AHSS_RightSwipeDown,(ONE_FIXED/6),0); + } + LastHand=1; + } + } + + PlayersWeaponHModelController.Playing=1; + } + + /* Now we're in the attack. */ + if (Biting) { + /* Kinda placeholder. */ + if (weaponPtr->StateTimeOutCounter<(WEAPONSTATE_INITIALTIMEOUTCOUNT>>1)) { + if (Bit==0) { + SECTION_DATA *head_sec; + Bit=1; + /* Try the bite. */ + head_sec=CheckBiteIntegrity(); + if (head_sec) + { + AVP_BEHAVIOUR_TYPE pre_bite_type=Biting->I_SBtype; + + CurrentGameStats_HeadBitten(Biting); + + /* Munch! */ + if (SUPERGORE_MODE) { + CauseDamageToHModel(Biting->SBdptr->HModelControlBlock, Biting, &TemplateAmmo[AMMO_ALIEN_BITE_KILLSECTION_SUPER].MaxDamage[AvP.Difficulty], + ONE_FIXED,head_sec,NULL,NULL,0); + } else { + CauseDamageToHModel(Biting->SBdptr->HModelControlBlock, Biting, &TemplateAmmo[AMMO_ALIEN_BITE_KILLSECTION].MaxDamage[AvP.Difficulty], + ONE_FIXED,head_sec,NULL,NULL,0); + } + + /* Side effects, anyone? */ + { + BiteAttack_AwardHealth(Biting,pre_bite_type); + } + /* Play a sound? */ + if (PlayerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) { + Sound_Stop(PlayerStatusPtr->soundHandle); + } + Sound_Play(SID_ALIEN_JAW_ATTACK,"de",&(Player->ObStrategyBlock->DynPtr->Position),&PlayerStatusPtr->soundHandle); + HtoHStrikes++; + + /* KJL 11:55:27 30/07/98 - Cue Special FX! */ + { + extern void AlienBiteAttackHasHappened(void); + AlienBiteAttackHasHappened(); + } + + } + else + { + /* Play a different sound? */ + } + } + } + } else { + /* Execute attack. */ + int hits; + + hits=0; + + if (PlayersWeaponHModelController.keyframe_flags&1) { + hits++; + } + + if (PlayersWeaponHModelController.keyframe_flags&2) { + hits++; + } + + if (hits) { + + HtoHStrikes+=hits; + + MeleeWeapon_180Degree_Front_Core(&Player_Weapon_Damage,ONE_FIXED*hits,4000); + PlayAlienSwipeSound(); + + } + + } + +} + +void AlienGrab_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + /* Same as for claws, ATM */ + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_AlienHUD,(int)AHSS_LeftSwipeDown,ONE_FIXED/3); + PlayersWeaponHModelController.Looped=0; + PlayersWeaponHModelController.Playing=0; + } + + LastHand=0; + Alien_Visible_Weapon=0; //Claws +} + +void AlienGrab_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + /* ...Nothing? */ + +} + +void AlienGrab_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + /* ...Nothing? */ + +} + +void AlienGrab_Strike(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + /* Eating function. */ + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + int alien_speed; + + alien_speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity); + + /* Speed: < 5000 = standing. > 22000 = jumping. + In practice, walk/fall = 18000 ish, jump = 27000 ish. */ + + /* Check we've got the claws. */ + + if (Alien_Visible_Weapon!=2) { + + GetHierarchicalWeapon("alien_HUD","eat",(int)HMSQT_AlienHUD,(int)AHSS_Eat); + + Alien_Visible_Weapon=2; + + } + + /* Setup base damage. */ + + Player_Weapon_Damage=TemplateAmmo[AMMO_ALIEN_CLAW].MaxDamage[AvP.Difficulty]; + + /* Choose attack type and speed. */ + + if ((alien_speed<5000)&&(Player->ObStrategyBlock->DynPtr->IsInContactWithFloor) + &&( /* Gravity check. */ + (Player->ObStrategyBlock->DynPtr->GravityDirection.vx<46341) + &&(Player->ObStrategyBlock->DynPtr->GravityDirection.vx>-46341) + &&(Player->ObStrategyBlock->DynPtr->GravityDirection.vy>46341) + &&(Player->ObStrategyBlock->DynPtr->GravityDirection.vz<46341) + &&(Player->ObStrategyBlock->DynPtr->GravityDirection.vz>-46341) + )) { + /* Standing on solid ground. */ + + TemplateWeapon[WEAPON_ALIEN_GRAB].PrimaryIsAutomatic=1; + + TemplateWeapon[WEAPON_ALIEN_GRAB].TimeOutRateForState[WEAPONSTATE_FIRING_PRIMARY]= + (DIV_FIXED(WEAPONSTATE_INITIALTIMEOUTCOUNT,(ONE_FIXED/3))); + + if ((FastRandom()&65536)>32768) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD, + (int)AHSS_Eat,(ONE_FIXED/3),0); + } else { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_AlienHUD, + (int)AHSS_Eat,(ONE_FIXED/3),0); + } + PlayersWeaponHModelController.Playing=1; + + } else { + + /* No joy. */ + + } + + } + + { + /* Execute attack. */ + int hits; + + hits=0; + + if (PlayersWeaponHModelController.keyframe_flags&1) { + hits++; + } + + if (PlayersWeaponHModelController.keyframe_flags&2) { + hits++; + } + + if (hits) { + + PC_Alien_Eat_Attack(hits); + PlayAlienSwipeSound(); + + } + + } + +} + +int Target_IsEdible(STRATEGYBLOCK *candidate) { + + switch (candidate->I_SBtype) { + case I_BehaviourAlien: + case I_BehaviourQueenAlien: + case I_BehaviourFaceHugger: + case I_BehaviourXenoborg: + case I_BehaviourPredatorAlien: + { + return(0); + break; + } + case I_BehaviourPredator: + case I_BehaviourMarine: + case I_BehaviourSeal: + { + if (NPC_IsDead(candidate)) { + /* Must be dead to be eaten. */ + return(1); + } else { + return(0); + } + break; + } + #if SupportWindows95 + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *dataptr; + dataptr=candidate->SBdataptr; + switch (dataptr->type) { + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + /* Put a test in, once we have dead ghosts. */ + return(0); + break; + default: + return(0); + break; + } + } + break; + #endif + default: + return(0); + break; + } + +} + +void Placeholder_Eating_Effect(STRATEGYBLOCK *sbPtr) { + + VECTORCH final_spray_direction; + enum PARTICLE_ID blood_type; + /* Spray is go! */ + + /* Add random element. */ + + final_spray_direction.vx=( (FastRandom()&2047)-1024); + final_spray_direction.vy=( -(FastRandom()&511)); /* Should be upwards. */ + final_spray_direction.vz=( (FastRandom()&2047)-1024); + + /* Identify spray type. */ + + blood_type=GetBloodType(sbPtr); + + /* Call spray function. */ + + MakeParticle(&sbPtr->DynPtr->Position, &final_spray_direction, blood_type); + +} + +#define EAT_ATTACK_RANGE 1500 + +int PC_Alien_Eat_Attack(int hits) +{ + int numberOfObjects = NumOnScreenBlocks; + int numhits=0; + + while (numberOfObjects) + { + DISPLAYBLOCK* objectPtr = OnScreenBlockList[--numberOfObjects]; + STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock; + GLOBALASSERT(objectPtr); + + /* does object have a strategy block? */ + if (sbPtr) + { + /* is it in the frustrum? */ + if ( (objectPtr->ObView.vz >0) + && (objectPtr->ObView.vz > objectPtr->ObView.vx) + && (objectPtr->ObView.vz > -objectPtr->ObView.vx) + && (objectPtr->ObView.vz > objectPtr->ObView.vy) + && (objectPtr->ObView.vz > -objectPtr->ObView.vy) ) { + + int dist=Approximate3dMagnitude(&objectPtr->ObView); + + if (distDynPtr; + if (dynPtr) + { + + if (Target_IsEdible(sbPtr)) { + /* Go go gadget eat? */ + textprint("Eating! Yum Yum...\n"); + Placeholder_Eating_Effect(sbPtr); + } + + numhits++; + } + } + } + } + } + + return(numhits); +} + +void PlasmaCaster_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + /* Note, not the same as WristConsole_Idle! */ + + /* Do charge, then sequences. */ + + /* Jumpstart plasmacaster. */ + if (playerStatusPtr->PlasmaCasterChargePlasmaCasterCharge; + + if (playerStatusPtr->FieldCharge>=MUL_FIXED(jumpgap,Caster_ChargeRatio)) { + /* We have enough. */ + jumpcharge=jumpgap; + } else { + //jumpcharge=DIV_FIXED(playerStatusPtr->FieldCharge,Caster_ChargeRatio); + /* Don't drain insufficient charge. */ + jumpcharge=0; + } + + playerStatusPtr->PlasmaCasterCharge+=jumpcharge; + playerStatusPtr->FieldCharge-=MUL_FIXED(jumpcharge,Caster_ChargeRatio); + CurrentGameStats_ChargeUsed(MUL_FIXED(jumpcharge,Caster_ChargeRatio)); + LOCALASSERT(playerStatusPtr->FieldCharge>=0); + + } + + if ((playerStatusPtr->PlasmaCasterChargeFieldCharge>0) { + int chargerate; + int optimumchargerate; + + optimumchargerate=MUL_FIXED(Caster_TrickleRate,NormalFrameTime); + /* optimumchargerate is for the CASTER. */ + + if (playerStatusPtr->FieldCharge>=MUL_FIXED(optimumchargerate,Caster_ChargeRatio)) { + chargerate=optimumchargerate; + } else { + GLOBALASSERT(Caster_ChargeRatio); + chargerate=DIV_FIXED(playerStatusPtr->FieldCharge,Caster_ChargeRatio); + } + + if (playerStatusPtr->PlasmaCasterCharge+chargerate>Caster_TrickleLevel) { + chargerate=Caster_TrickleLevel-playerStatusPtr->PlasmaCasterCharge; + } + + playerStatusPtr->FieldCharge-=MUL_FIXED(chargerate,Caster_ChargeRatio); + CurrentGameStats_ChargeUsed(MUL_FIXED(chargerate,Caster_ChargeRatio)); + LOCALASSERT(playerStatusPtr->FieldCharge>=0); + playerStatusPtr->PlasmaCasterCharge+=chargerate; + LOCALASSERT(playerStatusPtr->PlasmaCasterCharge<=Caster_TrickleLevel); + } + } + + if (ShowPredoStats) { + PrintDebuggingText("Plasma Caster Charge = %d\n",playerStatusPtr->PlasmaCasterCharge); + } + + /* Now anim control. */ + + if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Attack_Primary) { + if (PlayersWeaponHModelController.Tweening!=0) { + PlayersWeaponHModelController.Playing=1; + return; + } + GLOBALASSERT(PlayersWeaponHModelController.Looped==0); + if (!(HModelAnimation_IsFinished(&PlayersWeaponHModelController))) { + return; + } + } + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Stand,ONE_FIXED,1); + } + + /* Are we running? */ + + if ( (Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0) + || (Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0) + || (Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0) ) { + + /* Were we running? */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Run)) { + if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Run) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Run,ONE_FIXED,1); + } + } else { + if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),PHSS_Stand,(int)PHSS_Stand,ONE_FIXED,1); + } + } + } else { + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if ((PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1); + } + + if (weaponPtr->StateTimeOutCounter > ONE_FIXED) { + + if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Fidget) { + if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1); + } + } else if ((FastRandom()&255)==0) { + /* Start animation. */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_PredatorHUD,(int)PHSS_Fidget,-1,0); + weaponPtr->StateTimeOutCounter=0; + } + } + } + } + + /* Be very quiet... we're hunting wabbits! */ + if(weaponHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(weaponHandle); + } + +} + +int SecondaryFirePCPlasmaCaster(PLAYER_WEAPON_DATA *weaponPtr) { + + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + if (PlayersWeaponHModelController.Sub_Sequence!=PHSS_Attack_Primary) { + /* Start Animation. */ + GLOBALASSERT(PlayersWeaponHModelController.section_data); + GLOBALASSERT(PlayersWeaponHModelController.Playing==1); + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,-1,0); + } else { + if (PlayersWeaponHModelController.keyframe_flags) { + PlayersWeaponHModelController.Playing=0; + } + } + + /* Handle field charge. */ + if (playerStatusPtr->PlasmaCasterChargeFieldCharge>0) { + int chargerate; + int optimumchargerate; + + //optimumchargerate=NormalFrameTime>>CASTER_CHARGETIME; /* 8 sec recharge? */ + + if (Caster_Chargetime==0) { + optimumchargerate=65536; + } else { + optimumchargerate=DIV_FIXED(NormalFrameTime,Caster_Chargetime); + } + /* optimumchargerate is for the CASTER. */ + + if (playerStatusPtr->FieldCharge>=MUL_FIXED(optimumchargerate,Caster_ChargeRatio)) { + chargerate=optimumchargerate; + } else { + GLOBALASSERT(Caster_ChargeRatio); + chargerate=DIV_FIXED(playerStatusPtr->FieldCharge,Caster_ChargeRatio); + } + + if (playerStatusPtr->PlasmaCasterCharge+chargerate>ONE_FIXED) { + chargerate=ONE_FIXED-playerStatusPtr->PlasmaCasterCharge; + } + + playerStatusPtr->FieldCharge-=MUL_FIXED(chargerate,Caster_ChargeRatio); + CurrentGameStats_ChargeUsed(MUL_FIXED(chargerate,Caster_ChargeRatio)); + LOCALASSERT(playerStatusPtr->FieldCharge>=0); + playerStatusPtr->PlasmaCasterCharge+=chargerate; + LOCALASSERT(playerStatusPtr->PlasmaCasterCharge<=ONE_FIXED); + + if (chargerate) { + /* Play a charging sound! */ + if(weaponHandle != SOUND_NOACTIVEINDEX) { + if (ActiveSounds[weaponHandle].soundIndex!=SID_PREDATOR_PLASMACASTER_CHARGING) { + /* Stop other sounds... */ + Sound_Stop(weaponHandle); + } + } + if(weaponHandle == SOUND_NOACTIVEINDEX) { + Sound_Play(SID_PREDATOR_PLASMACASTER_CHARGING,"ehl",&weaponHandle); + } + } else { + /* Be very quiet... we're hunting wabbits! */ + if(weaponHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(weaponHandle); + } + } + } + } else { + /* Be very quiet... we're hunting wabbits! */ + if(weaponHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(weaponHandle); + } + } + + return(1); +} + +int FirePCPlasmaCaster(PLAYER_WEAPON_DATA *weaponPtr) { + + int jumpcharge; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + if (playerStatusPtr->PlasmaCasterChargePlasmaCasterCharge); + Player_Weapon_Damage.Cutting =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Cutting ,playerStatusPtr->PlasmaCasterCharge); + Player_Weapon_Damage.Penetrative=MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Penetrative,playerStatusPtr->PlasmaCasterCharge); + Player_Weapon_Damage.Fire =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Fire ,playerStatusPtr->PlasmaCasterCharge); + Player_Weapon_Damage.Electrical =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Electrical ,playerStatusPtr->PlasmaCasterCharge); + Player_Weapon_Damage.Acid =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Acid ,playerStatusPtr->PlasmaCasterCharge); + + Player_Weapon_Damage.BlowUpSections=1; + Player_Weapon_Damage.Special=0; + #else + Player_Weapon_Damage=TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty]; + + if (Caster_PCKill>0) { + + /* At least we can theoretically work it. */ + + if ((playerStatusPtr->PlasmaCasterCharge>=Caster_NPCKill) + &&(Caster_PCKill>Caster_NPCKill)) { + /* In the upper graph. */ + int factor; + + factor=playerStatusPtr->PlasmaCasterCharge-Caster_NPCKill; + factor=DIV_FIXED(factor,(Caster_PCKill-Caster_NPCKill)); + + Player_Weapon_Damage.Impact =TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Impact +MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Impact ,factor); + Player_Weapon_Damage.Cutting =TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Cutting +MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Cutting ,factor); + Player_Weapon_Damage.Penetrative=TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Penetrative +MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Penetrative ,factor); + Player_Weapon_Damage.Fire =TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Fire +MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Fire ,factor); + Player_Weapon_Damage.Electrical =TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Electrical +MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Electrical ,factor); + Player_Weapon_Damage.Acid =TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Acid +MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Acid ,factor); + + } else { + /* In the lower graph. */ + int factor; + + factor=playerStatusPtr->PlasmaCasterCharge; + factor=DIV_FIXED(factor,Caster_NPCKill); + + Player_Weapon_Damage.Impact =MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Impact ,factor); + Player_Weapon_Damage.Cutting =MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Cutting ,factor); + Player_Weapon_Damage.Penetrative=MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Penetrative,factor); + Player_Weapon_Damage.Fire =MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Fire ,factor); + Player_Weapon_Damage.Electrical =MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Electrical ,factor); + Player_Weapon_Damage.Acid =MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Acid ,factor); + + } + + } + + Player_Weapon_Damage.BlowUpSections=1; + Player_Weapon_Damage.Special=0; + #endif + + InitialiseEnergyBoltBehaviour(&Player_Weapon_Damage,playerStatusPtr->PlasmaCasterCharge); + + /* Be very quiet... we're hunting wabbits! */ + if(weaponHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(weaponHandle); + } + + /* Jumpstart plasmacaster. */ + + if (playerStatusPtr->FieldCharge>=MUL_FIXED(Caster_Jumpstart,Caster_ChargeRatio)) { + jumpcharge=Caster_Jumpstart; + } else { + //jumpcharge=DIV_FIXED(playerStatusPtr->FieldCharge,Caster_ChargeRatio); + /* Not enough - drain nothing! */ + jumpcharge=0; + } + + playerStatusPtr->PlasmaCasterCharge=jumpcharge; + playerStatusPtr->FieldCharge-=MUL_FIXED(jumpcharge,Caster_ChargeRatio); + CurrentGameStats_ChargeUsed(MUL_FIXED(jumpcharge,Caster_ChargeRatio)); + LOCALASSERT(playerStatusPtr->FieldCharge>=0); + + return(1); +} + +void Secondary_PlasmaCaster_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + /* Restart anim. */ + PlayersWeaponHModelController.Playing=1; + + /* Be very quiet... we're hunting wabbits! */ + if(weaponHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(weaponHandle); + } +} + +void PlasmaCaster_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + int jumpcharge; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + PlayersWeaponHModelController.Playing=1; + + /* Be very quiet... we're hunting wabbits! */ + if(weaponHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(weaponHandle); + } + + #if 0 + if (playerStatusPtr->PlasmaCasterChargeStateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + int multiplyer,a; + + if (playerStatusPtr->PlasmaCasterChargePlasmaCasterCharge; + + /* These values computed by hand! */ + multiplyer=MUL_FIXED(a,a); + multiplyer=MUL_FIXED(multiplyer,26653); + multiplyer+=MUL_FIXED(a,38883); + /* Should fit for JUMPCHARGE == 0.1*max. */ + LOCALASSERT(multiplyer>=0); + + Player_Weapon_Damage=TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty]; + + Player_Weapon_Damage.Impact =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Impact ,multiplyer); + Player_Weapon_Damage.Cutting =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Cutting ,multiplyer); + Player_Weapon_Damage.Penetrative=MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Penetrative,multiplyer); + Player_Weapon_Damage.Fire =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Fire ,multiplyer); + Player_Weapon_Damage.Electrical =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Electrical ,multiplyer); + Player_Weapon_Damage.Acid =MUL_FIXED(TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty].Acid ,multiplyer); + + Player_Weapon_Damage.BlowUpSections=1; + Player_Weapon_Damage.Special=0; + #else + Player_Weapon_Damage=TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty]; + + if (Caster_PCKill>0) { + + /* At least we can theoretically work it. */ + + if ((playerStatusPtr->PlasmaCasterCharge>=Caster_NPCKill) + &&(Caster_PCKill>Caster_NPCKill)) { + /* In the upper graph. */ + int factor; + + factor=playerStatusPtr->PlasmaCasterCharge-Caster_NPCKill; + factor=DIV_FIXED(factor,(Caster_PCKill-Caster_NPCKill)); + + Player_Weapon_Damage.Impact =TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Impact +MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Impact ,factor); + Player_Weapon_Damage.Cutting =TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Cutting +MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Cutting ,factor); + Player_Weapon_Damage.Penetrative=TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Penetrative +MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Penetrative ,factor); + Player_Weapon_Damage.Fire =TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Fire +MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Fire ,factor); + Player_Weapon_Damage.Electrical =TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Electrical +MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Electrical ,factor); + Player_Weapon_Damage.Acid =TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Acid +MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_PCKILL].MaxDamage[AvP.Difficulty].Acid ,factor); + + } else { + /* In the lower graph. */ + int factor; + + factor=playerStatusPtr->PlasmaCasterCharge; + factor=DIV_FIXED(factor,Caster_NPCKill); + + Player_Weapon_Damage.Impact =MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Impact ,factor); + Player_Weapon_Damage.Cutting =MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Cutting ,factor); + Player_Weapon_Damage.Penetrative=MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Penetrative,factor); + Player_Weapon_Damage.Fire =MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Fire ,factor); + Player_Weapon_Damage.Electrical =MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Electrical ,factor); + Player_Weapon_Damage.Acid =MUL_FIXED(TemplateAmmo[AMMO_PLASMACASTER_NPCKILL].MaxDamage[AvP.Difficulty].Acid ,factor); + + } + + } + + Player_Weapon_Damage.BlowUpSections=1; + Player_Weapon_Damage.Special=0; + #endif + + InitialiseEnergyBoltBehaviour(&Player_Weapon_Damage,playerStatusPtr->PlasmaCasterCharge); + + CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1); + + /* Jumpstart plasmacaster. */ + + if (playerStatusPtr->FieldCharge>=MUL_FIXED(Caster_Jumpstart,Caster_ChargeRatio)) { + jumpcharge=Caster_Jumpstart; + } else { + GLOBALASSERT(Caster_ChargeRatio); + jumpcharge=DIV_FIXED(playerStatusPtr->FieldCharge,Caster_ChargeRatio); + } + + playerStatusPtr->PlasmaCasterCharge=jumpcharge; + playerStatusPtr->FieldCharge-=MUL_FIXED(jumpcharge,Caster_ChargeRatio); + CurrentGameStats_ChargeUsed(MUL_FIXED(jumpcharge,Caster_ChargeRatio)); + LOCALASSERT(playerStatusPtr->FieldCharge>=0); + + } +} + +#define FIREPREDPISTOL_FIELDCHARGE (ONE_FIXED>>2) + +int FirePredPistol(PLAYER_WEAPON_DATA *weaponPtr) +{ + TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber]; + + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + if (playerStatusPtr->FieldCharge>=FIREPREDPISTOL_FIELDCHARGE) + { + FireProjectileAmmo(twPtr->PrimaryAmmoID); + playerStatusPtr->FieldCharge-=FIREPREDPISTOL_FIELDCHARGE; + CurrentGameStats_ChargeUsed(FIREPREDPISTOL_FIELDCHARGE); + return(1); + } + else /* instantaneous line of sight */ + { + return(0); + } +} + +#define FIRESPEARGUN_FIELDCHARGE (0) +#define SPEAR_PLAYER_IMPULSE (-8000) + +int FireSpeargun(PLAYER_WEAPON_DATA *weaponPtr) +{ + TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber]; + + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + if (playerStatusPtr->FieldCharge>=FIRESPEARGUN_FIELDCHARGE) + { + /* Ammo check already happened. */ + if (!(PIGSTICKING_MODE)) { + weaponPtr->PrimaryRoundsRemaining -= 65536; + } + + CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1); + + //FireProjectileAmmo(twPtr->PrimaryAmmoID); + if (PlayersTarget.DispPtr) + { + + if (AccuracyStats_TargetFilter(PlayersTarget.DispPtr->ObStrategyBlock)) { + CurrentGameStats_WeaponHit(PlayerStatusPtr->SelectedWeaponSlot,1); + } + + if (PlayersTarget.HModelSection!=NULL) { + textprint("Hitting a hierarchical section.\n"); + GLOBALASSERT(PlayersTarget.DispPtr->HModelControlBlock==PlayersTarget.HModelSection->my_controller); + } + + if (PIGSTICKING_MODE) { + /* Cheat mode goes here! */ + int hitroll=0; + + while (SpreadfireSpears[hitroll].vz>0) { + VECTORCH world_vec; + MATRIXCH transpose; + + transpose=Global_VDB_Ptr->VDB_Mat; + TransposeMatrixCH(&transpose); + RotateAndCopyVector(&SpreadfireSpears[hitroll],&world_vec,&transpose); + CastLOSSpear(Player->ObStrategyBlock,&Global_VDB_Ptr->VDB_World,&world_vec, AMMO_PRED_RIFLE, 1,0); + + hitroll++; + } + } else { + HandleSpearImpact(&(PlayersTarget.Position),PlayersTarget.DispPtr->ObStrategyBlock,twPtr->PrimaryAmmoID,&GunMuzzleDirectionInWS, 1, PlayersTarget.HModelSection); + } + } + + if ((Player->ObStrategyBlock->DynPtr->Position.vx==Player->ObStrategyBlock->DynPtr->PrevPosition.vx) + &&(Player->ObStrategyBlock->DynPtr->Position.vy==Player->ObStrategyBlock->DynPtr->PrevPosition.vy) + &&(Player->ObStrategyBlock->DynPtr->Position.vz==Player->ObStrategyBlock->DynPtr->PrevPosition.vz) + &&(Player->ObStrategyBlock->DynPtr->IsInContactWithFloor) + ){ + /* Behave normally! */ + } else { + /* Kickback! */ + Player->ObStrategyBlock->DynPtr->LinImpulse.vx+=MUL_FIXED(PlayersWeapon.ObMat.mat31,SPEAR_PLAYER_IMPULSE); + Player->ObStrategyBlock->DynPtr->LinImpulse.vy+=MUL_FIXED(PlayersWeapon.ObMat.mat32,SPEAR_PLAYER_IMPULSE); + Player->ObStrategyBlock->DynPtr->LinImpulse.vz+=MUL_FIXED(PlayersWeapon.ObMat.mat33,SPEAR_PLAYER_IMPULSE); + } + + if (!(PIGSTICKING_MODE)) { + playerStatusPtr->FieldCharge-=FIRESPEARGUN_FIELDCHARGE; + CurrentGameStats_ChargeUsed(FIRESPEARGUN_FIELDCHARGE); + } + return(1); + } + else /* instantaneous line of sight */ + { + return(0); + } +} + +int Tail_TargetFilter(STRATEGYBLOCK *candidate) { + + switch (candidate->I_SBtype) { + case I_BehaviourPredator: + case I_BehaviourXenoborg: + case I_BehaviourMarine: + case I_BehaviourSeal: + case I_BehaviourAutoGun: + case I_BehaviourPredatorDisc_SeekTrack: + case I_BehaviourInanimateObject: + case I_BehaviourRubberDuck: + case I_BehaviourPlacedLight: + case I_BehaviourDormantPredator: + case I_BehaviourTrackObject: + return(1); + break; + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *dataptr; + dataptr=candidate->SBdataptr; + switch (dataptr->type) { + case I_BehaviourPredator: + case I_BehaviourXenoborg: + case I_BehaviourMarine: + case I_BehaviourSeal: + case I_BehaviourAutoGun: + case I_BehaviourPredatorDisc_SeekTrack: + case I_BehaviourInanimateObject: + case I_BehaviourRubberDuck: + case I_BehaviourPlacedLight: + case I_BehaviourDormantPredator: + case I_BehaviourMarinePlayer: + case I_BehaviourPredatorPlayer: + return(1); + break; + case I_BehaviourAlienPlayer: + { + switch (netGameData.gameType) { + case NGT_Individual: + return(1); + break; + case NGT_CoopDeathmatch: + return(0); + break; + case NGT_LastManStanding: + return(0); + break; + case NGT_PredatorTag: + return(1); + break; + case NGT_Coop: + return(0); + break; + case NGT_AlienTag: + return(1); //However, there shouldn't be more than one alien in alien tag anyway. + break; + default: + return(0); + break; + } + break; + } + default: + return(0); + break; + } + } + break; + default: + return(0); + break; + } + +} + +#define ALIEN_TAIL_RANGE (4000) + +DISPLAYBLOCK *AlienTail_TargetSelect(void) +{ + int numberOfObjects = NumOnScreenBlocks; + DISPLAYBLOCK *nearest; + STRATEGYBLOCK *sbPtr; + int neardist; + + nearest=NULL; + neardist=100000; + + while (numberOfObjects) + { + DISPLAYBLOCK* objectPtr = OnScreenBlockList[--numberOfObjects]; + sbPtr = objectPtr->ObStrategyBlock; + GLOBALASSERT(objectPtr); + + /* does object have a strategy block? */ + if (sbPtr) + { + if (Tail_TargetFilter(sbPtr)) { + /* is it in the frustrum? */ + if ( (objectPtr->ObView.vz >0) + && (objectPtr->ObView.vz > (objectPtr->ObView.vx>>1)) + && (objectPtr->ObView.vz > -(objectPtr->ObView.vx>>1)) + && (objectPtr->ObView.vz > (objectPtr->ObView.vy>>1)) + && (objectPtr->ObView.vz > -(objectPtr->ObView.vy>>1)) ) { + + int dist=Approximate3dMagnitude(&objectPtr->ObView); + + if (distDynPtr; + if (dynPtr) + { + //if (IsThisObjectVisibleFromThisPosition_WithIgnore(Player,objectPtr,&dynPtr->Position,ALIEN_TAIL_RANGE)) { + if (CameraCanSeeThisPosition_WithIgnore(objectPtr,&dynPtr->Position)) { + /* Consider target validity here? */ + + if (distObStrategyBlock) { + sbPtr=PlayersTarget.DispPtr->ObStrategyBlock; + /* It must be in the frustrum... */ + if (sbPtr) { + if (sbPtr->DynPtr) { + if (Tail_TargetFilter(sbPtr)) { + /* May as well hit this, then. */ + return(PlayersTarget.DispPtr); + } + } + } + } + } + } + + return(NULL); +} + +/* Plasmacaster function set. */ + +void WristConsole_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Stand,ONE_FIXED,1); + } + + /* Are we running? */ + + if ( (Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0) + || (Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0) + || (Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0) ) { + + /* Were we running? */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Run)) { + if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Run) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Run,ONE_FIXED,1); + } + } else { + if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),PHSS_Stand,(int)PHSS_Stand,ONE_FIXED,1); + } + } + } else { + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if ((PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1); + } + + if (weaponPtr->StateTimeOutCounter > ONE_FIXED) { + + if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Fidget) { + if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1); + } + } else if ((FastRandom()&255)==0) { + /* Start animation. */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_PredatorHUD,(int)PHSS_Fidget,-1,0); + weaponPtr->StateTimeOutCounter=0; + } + } + } + } + +} + +void TemplateHands_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + GLOBALASSERT(PlayersWeaponHModelController.section_data); + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Come,ONE_FIXED/3); + PlayersWeaponHModelController.Looped=0; + + /* Stop pred hud sound. */ + if(predHUDSoundHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(predHUDSoundHandle); + } + } + + /* Init damage for plasmacaster. */ + + Player_Weapon_Damage=TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty]; + + Player_Weapon_Damage.Impact=0; + Player_Weapon_Damage.Cutting=0; + Player_Weapon_Damage.Penetrative=0; + Player_Weapon_Damage.Fire=0; + Player_Weapon_Damage.Electrical=0; + Player_Weapon_Damage.Acid=0; + Player_Weapon_Damage.Special=0; + +} + +void WristConsole_Readying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + SECTION *root_section; + + root_section=GetNamedHierarchyFromLibrary("pred_HUD","wrist display"); + GLOBALASSERT(root_section); + + #if 0 + Dispel_HModel(&PlayersWeaponHModelController); + Create_HModel(&PlayersWeaponHModelController,root_section); + GLOBALASSERT(PlayersWeaponHModelController.section_data); + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Come,131625); /* 2.1s */ + PlayersWeaponHModelController.Looped=0; + #else + PlayersWeaponHModelController.Sequence_Type=HMSQT_PredatorHUD; + PlayersWeaponHModelController.Sub_Sequence=PHSS_Come; + Transmogrify_HModels(NULL,&PlayersWeaponHModelController,root_section,0,1,1); + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Come,129434,0); /* 2.1s */ + #endif + + /* Stop pred hud sound. */ + if(predHUDSoundHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(predHUDSoundHandle); + } + + } + +} + +void WristConsole_Unreadying(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + GLOBALASSERT(PlayersWeaponHModelController.section_data); + #if 0 + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Go,104857); /* 1.6s */ + PlayersWeaponHModelController.Looped=0; + #else + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Go,96666,0); /* 1.6s */ + #endif + } +} + +void WristConsole_Use(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + GLOBALASSERT(PlayersWeaponHModelController.section_data); + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,-1,0); + } +} + +void SADAR_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Come,ONE_FIXED); + PlayersWeaponHModelController.Looped=0; + } + +} + +void SADAR_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Go,ONE_FIXED,1); + PlayersWeaponHModelController.Looped=0; + } + +} + +void SADAR_Fidget(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if ((PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary)&&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1); + } + + if (weaponPtr->StateTimeOutCounter > ONE_FIXED) { + + if (WeaponFidgetPlaying) { + if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1); + WeaponFidgetPlaying=0; + } + } else if ((FastRandom()&255)==0) { + /* Start animation. */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Fidget,ONE_FIXED,0); + weaponPtr->StateTimeOutCounter=0; + WeaponFidgetPlaying=1; + } + } + + } + +} + +void SADAR_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1); + } + +} + +void SADAR_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + //InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Standard_Fire,(ONE_FIXED/6)-(ONE_FIXED>>4),0); + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Fire,(ONE_FIXED/6)); + PlayersWeaponHModelController.Looped=0; + } + +} + +void SADAR_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Standard_Reload,((ONE_FIXED*3)/2),0); + } + +} + +void Minigun_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + Weapon_ThisBurst=-1; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + /* Just play the readying sound. */ + Sound_Play(SID_WIL_MINIGUN_READY,"h"); + } + + Flamethrower_Timer=0; +} + +void GenericMarineWeapon_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + Weapon_ThisBurst=-1; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_IN]); + + GLOBALASSERT(time!=0); + + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Come,time); + PlayersWeaponHModelController.Looped=0; + } + + Flamethrower_Timer=0; + StaffAttack=-1; + LastHand=1; +} + +void GenericMarineWeapon_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_OUT]); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Go,time,0); + PlayersWeaponHModelController.Looped=0; + } +} + +void GenericMarineWeapon_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + #if 0 + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)twPtr->InitialSubSequence,ONE_FIXED,1); + } + #endif + + if ((PlayersWeaponHModelController.Sub_Sequence!=(int)twPtr->InitialSubSequence)&&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)twPtr->InitialSubSequence,ONE_FIXED,1); + } + + if (weaponPtr->StateTimeOutCounter > ONE_FIXED) { + + if (WeaponFidgetPlaying) { + if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)twPtr->InitialSubSequence,ONE_FIXED,1); + WeaponFidgetPlaying=0; + } + } else if ((FastRandom()&255)==0) { + /* Start animation. */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Fidget,ONE_FIXED,0); + weaponPtr->StateTimeOutCounter=0; + WeaponFidgetPlaying=1; + } + } + + } + + Flamethrower_Timer=0; + StaffAttack=-1; + +} + +void GenericMarineWeapon_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Standard_Fire,ONE_FIXED,1); + } + +} + +void GenericMarineWeapon_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_RELOAD_PRIMARY]); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Standard_Reload,time,0); + PlayersWeaponHModelController.Looped=0; + } + StaffAttack=-1; +} + +void GenericPredatorWeapon_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_IN]); + + GLOBALASSERT(time!=0); + + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Come,time); + PlayersWeaponHModelController.Looped=0; + } + + Flamethrower_Timer=0; +} + +void GenericPredatorWeapon_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_OUT]); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Go,time,0); + PlayersWeaponHModelController.Looped=0; + } +} + +void GenericPredatorWeapon_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + #if 0 + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)twPtr->InitialSubSequence,ONE_FIXED,1); + } + #endif + + if ((PlayersWeaponHModelController.Sub_Sequence!=(int)twPtr->InitialSubSequence)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget) + &&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Run)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)twPtr->InitialSubSequence,ONE_FIXED,1); + } + + /* Are we running? */ + + if ( (Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0) + || (Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0) + || (Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0) ) { + + /* Were we running? */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Run)) { + if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Run) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Run,ONE_FIXED,1); + } + } else { + if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),PHSS_Stand,(int)PHSS_Stand,ONE_FIXED,1); + } + } + } else { + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if ((PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1); + } + + if (weaponPtr->StateTimeOutCounter > ONE_FIXED) { + + if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Fidget) { + if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1); + } + } else if ((FastRandom()&255)==0) { + /* Start animation. */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_PredatorHUD,(int)PHSS_Fidget,-1,0); + weaponPtr->StateTimeOutCounter=0; + } + } + } + } + +} + +void GenericPredatorWeapon_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_FIRING_PRIMARY]); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,time,1); + } + +} + +void SpearGun_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_RECOIL_PRIMARY]); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,time,0); + } + +} + +void GenericPredatorWeapon_Firing_Secondary(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_FIRING_SECONDARY]); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Attack_Secondary,time,1); + } + +} + +void GenericPredatorWeapon_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + /* Plays 'Program', actually... */ + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_RELOAD_PRIMARY]); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Program,time,0); + PlayersWeaponHModelController.Looped=0; + } +} + +#if 0 +void PredatorDisc_Throwing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_FIRING_PRIMARY]); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,time,0); + } + + if (PlayersWeaponHModelController.keyframe_flags&1) { + SECTION_DATA *disc_section; + disc_section=GetThisSectionData(PlayersWeaponHModelController.section_data,"disk"); + GLOBALASSERT(disc_section); + /* Throw Disc. */ + if (FirePredatorDisc(weaponPtr,disc_section)) { + /* Mask disc. */ + disc_section->flags|=section_data_notreal; + } + } +} +#else +void PredatorDisc_Throwing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_FIRING_PRIMARY]); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,-1,0); + } else if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) { + weaponPtr->StateTimeOutCounter=0; + } else { + weaponPtr->StateTimeOutCounter=(ONE_FIXED>>1); + } + + if (PlayersWeaponHModelController.keyframe_flags&1) { + SECTION_DATA *disc_section; + disc_section=GetThisSectionData(PlayersWeaponHModelController.section_data,"disk"); + GLOBALASSERT(disc_section); + /* Throw Disc. */ + if (FirePredatorDisc(weaponPtr,disc_section)) { + /* Mask disc. */ + disc_section->flags|=section_data_notreal; + } + } +} +#endif + +void PredatorDisc_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + /* A bit like the Alien Claw one. */ + + if ((PlayersWeaponHModelController.Sub_Sequence!=(int)twPtr->InitialSubSequence)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget) + &&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Run)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)twPtr->InitialSubSequence,ONE_FIXED,1); + } + + /* Are we running? */ + + if ( (Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0) + || (Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0) + || (Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0) ) { + + /* Were we running? */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Run)) { + if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Run) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Run,ONE_FIXED,1); + } + } else { + if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),PHSS_Stand,(int)PHSS_Stand,ONE_FIXED,1); + } + } + } else { + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if ((PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand)&&(PlayersWeaponHModelController.Sub_Sequence!=PHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1); + } + + if (weaponPtr->StateTimeOutCounter > ONE_FIXED) { + + if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Fidget) { + if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),twPtr->InitialSequenceType,(int)PHSS_Stand,ONE_FIXED,1); + } + } else if ((FastRandom()&255)==0) { + /* Start animation. */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_PredatorHUD,(int)PHSS_Fidget,-1,0); + weaponPtr->StateTimeOutCounter=0; + } + } + } + } + + if (PlayersWeaponHModelController.keyframe_flags&1) { + SECTION_DATA *disc_section; + disc_section=GetThisSectionData(PlayersWeaponHModelController.section_data,"disk"); + if (disc_section) { + /* Throw Disc. */ + if (FirePredatorDisc(weaponPtr,disc_section)) { + /* Mask disc. */ + disc_section->flags|=section_data_notreal; + } + } + } + +} + +int PredatorDisc_Prefiring(PLAYER_WEAPON_DATA *weaponPtr) { + + /* Hey ho. */ + + return(1); +} + +int FirePredatorDisc(PLAYER_WEAPON_DATA *weaponPtr,SECTION_DATA *disc_section) { + + #if 0 + PC_PRED_DISC_BEHAV_BLOCK bblk; + + PredDisc_GetFirstTarget(&bblk, PlayersTarget.DispPtr, &disc_section->World_Offset); + + if ((bblk.Target==NULL)&&(ThisDiscMode==I_Search_Destroy)) { + NewOnScreenMessage("NO TARGET"); + weaponPtr->CurrentState = WEAPONSTATE_WAITING; + return(0); + } else { + weaponPtr->PrimaryRoundsRemaining -= 65536; + InitialiseDiscBehaviour(bblk.Target,disc_section); + return(1); + } + #else + if (SmartTarget_Object) { + InitialiseDiscBehaviour(SmartTarget_Object->ObStrategyBlock,disc_section); + } else { + InitialiseDiscBehaviour(NULL,disc_section); + } + weaponPtr->PrimaryRoundsRemaining -= 65536; + return(1); + #endif +} + +void PredatorDisc_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + /* Right. Go, recreate disc, then come. */ + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + int time; + + time=DIV_FIXED(ONE_FIXED,(twPtr->TimeOutRateForState[WEAPONSTATE_RELOAD_PRIMARY]<<1)); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Go,time,0); + PlayersWeaponHModelController.Looped=0; + PlayersWeaponHModelController.LoopAfterTweening=0; + } + + if ((PlayersWeaponHModelController.Tweening==Controller_NoTweening) + &&(PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1))) { + + SECTION_DATA *disc_section; + int time; + + if (PlayersWeaponHModelController.Sub_Sequence==PHSS_Come) { + /* If this is the second time, end. */ + weaponPtr->StateTimeOutCounter = 0; + } else { + disc_section=GetThisSectionData(PlayersWeaponHModelController.section_data,"disk"); + GLOBALASSERT(disc_section); + /* Appear Disc. */ + disc_section->flags&=~section_data_notreal; + + time=DIV_FIXED(ONE_FIXED,(twPtr->TimeOutRateForState[WEAPONSTATE_RELOAD_PRIMARY]<<1)); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Come,time,0); + PlayersWeaponHModelController.Looped=0; + PlayersWeaponHModelController.LoopAfterTweening=0; + } + } else { + /* Stay in this state. */ + weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1); + } +} + +void SpikeyThing_Use(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + /* We must be in the animation. */ + + /* Maintain this state... */ + weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1); + GLOBALASSERT(PlayersWeaponHModelController.Sub_Sequence==PHSS_Attack_Secondary); + + /* Force Decloak. */ + if (playerStatusPtr->cloakOn) { + playerStatusPtr->cloakOn=0; + Sound_Play(SID_PRED_CLOAKOFF,"h"); + //playerNoise=1; + } + + /* ...Unless we're at the end. */ + if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) { + /* End state. */ + weaponPtr->StateTimeOutCounter = 0; + } + + if (PlayersWeaponHModelController.keyframe_flags&1) { + if (Player->ObStrategyBlock->SBDamageBlock.IsOnFire) { + Player->ObStrategyBlock->SBDamageBlock.IsOnFire=0; + } + } + + if (PlayersWeaponHModelController.keyframe_flags&2) { + NPC_DATA *NpcData; + + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Predator_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Predator_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Predator_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Predator_Impossible); + break; + } + LOCALASSERT(NpcData); + + /* Ouch. */ + Player->ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<Health=Player->ObStrategyBlock->SBDamageBlock.Health; + + /* Now yell a bit? */ + if (playerStatusPtr->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(playerStatusPtr->soundHandle); + } + Sound_Play(SID_PRED_NEWROAR,"hev",&playerStatusPtr->soundHandle,VOLUME_MAX); + if(AvP.Network!=I_No_Network) netGameData.myLastScream=PSC_Medicomp_Special; + playerNoise=1; + + if (GREENFLASH_INTENSITY>PlayerDamagedOverlayIntensity) + { + PlayerDamagedOverlayIntensity=GREENFLASH_INTENSITY; + } + + { + /* Auto change to wristblade? */ + int slot; + + /* Try flashback weapon... */ + slot=playerStatusPtr->PreviouslySelectedWeaponSlot; + if (slot==-1) { + slot=SlotForThisWeapon(WEAPON_PRED_WRISTBLADE); + } + if (slot==-1) { + /* Argh! Whadda ya mean, you've got no wristblade? */ + GLOBALASSERT(0); + } + + { + playerStatusPtr->SwapToWeaponSlot = slot; + weaponPtr->CurrentState = WEAPONSTATE_UNREADYING; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + } + } +} + +void Extinguisher_Use(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + /* We must be in the animation. */ + + /* Maintain this state... */ + weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1); + GLOBALASSERT(PlayersWeaponHModelController.Sub_Sequence==PHSS_Attack_Primary); + + /* Force Decloak. */ + if (playerStatusPtr->cloakOn) { + playerStatusPtr->cloakOn=0; + Sound_Play(SID_PRED_CLOAKOFF,"h"); + //playerNoise=1; + } + + /* ...Unless we're at the end. */ + if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) { + /* End state. */ + weaponPtr->StateTimeOutCounter = 0; + } + + if (PlayersWeaponHModelController.keyframe_flags&1) { + if (Player->ObStrategyBlock->SBDamageBlock.IsOnFire) { + Player->ObStrategyBlock->SBDamageBlock.IsOnFire=0; + } + } + + /* That's all, folks. */ +} + +int FireSpikeyThing(PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + NPC_DATA *NpcData; + + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Predator_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Predator_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Predator_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Predator_Impossible); + break; + } + LOCALASSERT(NpcData); + LOCALASSERT(playerStatusPtr); + + #if QUIRKAFLEEG + if ((AvP.Difficulty==I_Hard)||(AvP.Difficulty==I_Impossible)) { + if (weaponPtr->PrimaryRoundsRemainingFieldCharge<=MEDICOMP_USE_THRESHOLD) { + return(0); + } + + if ((Player->ObStrategyBlock->SBDamageBlock.Health==NpcData->StartingStats.Health<ObStrategyBlock->SBDamageBlock.IsOnFire==0)) { + return(0); + } + + #if QUIRKAFLEEG + if ((AvP.Difficulty==I_Hard)||(AvP.Difficulty==I_Impossible)) { + if (weaponPtr->PrimaryRoundsRemainingPrimaryRoundsRemaining-=ONE_FIXED; + } + } + #endif + + if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) { + /* Force Decloak. */ + playerStatusPtr->cloakOn=0; + Sound_Play(SID_PRED_CLOAKOFF,"h"); + //playerNoise=1; + } + + GLOBALASSERT(AvP.PlayerType==I_Predator); + + /* No longer will we do that wussey instant healing thing! */ + playerStatusPtr->FieldCharge-=MEDICOMP_DRAIN_BLOCK; + CurrentGameStats_ChargeUsed(MEDICOMP_DRAIN_BLOCK); + /* But we do do the instant charging thing. */ + LOCALASSERT(playerStatusPtr->FieldCharge>=0); + + GLOBALASSERT(PlayersWeaponHModelController.section_data); + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Secondary,-1,0); + + return(1); + +} + +int FireExtinguisher(PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + /* Ha ha ha. I made a funny! */ + + LOCALASSERT(playerStatusPtr); + + if (playerStatusPtr->FieldCharge<=EXTINGUISHER_USE_THRESHOLD) { + return(0); + } + + if (Player->ObStrategyBlock->SBDamageBlock.IsOnFire==0) { + return(0); + } + + + if ( (twPtr->FireWhenCloaked==0)&&(playerStatusPtr->cloakOn) ) { + /* Force Decloak. */ + playerStatusPtr->cloakOn=0; + Sound_Play(SID_PRED_CLOAKOFF,"h"); + //playerNoise=1; + } + + GLOBALASSERT(AvP.PlayerType==I_Predator); + + /* No longer will we do that wussey instant healing thing! */ + playerStatusPtr->FieldCharge-=EXTINGUISHER_DRAIN_BLOCK; + CurrentGameStats_ChargeUsed(EXTINGUISHER_DRAIN_BLOCK); + /* But we do do the instant charging thing. */ + LOCALASSERT(playerStatusPtr->FieldCharge>=0); + + GLOBALASSERT(PlayersWeaponHModelController.section_data); + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,-1,0); + + return(1); + +} + +void Staff_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_IN]); + + GLOBALASSERT(time!=0); + + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Come,time); + PlayersWeaponHModelController.Looped=0; + } + /* Handle staff sections. */ + PlayerStaff1=GetThisSectionData(PlayersWeaponHModelController.section_data,"Staff R blade"); + PlayerStaff2=GetThisSectionData(PlayersWeaponHModelController.section_data,"Staff ROOT"); + PlayerStaff3=GetThisSectionData(PlayersWeaponHModelController.section_data,"Staff L blade"); + StaffAttack=-1; + +} + +void Staff_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_OUT]); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_PredatorHUD,(int)PHSS_Go,time,0); + PlayersWeaponHModelController.Looped=0; + } + /* Handle staff sections. */ + PlayerStaff1=NULL; + PlayerStaff2=NULL; + PlayerStaff3=NULL; + StaffAttack=-1; +} + +void Staff_Idle(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + /* Are we running? */ + + if ( (Player->ObStrategyBlock->DynPtr->LinVelocity.vx!=0) + || (Player->ObStrategyBlock->DynPtr->LinVelocity.vy!=0) + || (Player->ObStrategyBlock->DynPtr->LinVelocity.vz!=0) ) { + + /* Were we running? */ + + if (PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Run) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Run,ONE_FIXED,1); + } + } else { + + if ((PlayersWeaponHModelController.Sub_Sequence!=(int)PHSS_Stand)&&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Stand,ONE_FIXED,1); + } + + if (weaponPtr->StateTimeOutCounter > ONE_FIXED) { + + if (WeaponFidgetPlaying) { + if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Stand,ONE_FIXED,1); + WeaponFidgetPlaying=0; + } + } else if ((FastRandom()&255)==0) { + /* Start animation. */ + #if 1 + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_PredatorHUD,(int)PHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_PredatorHUD,(int)PHSS_Fidget,-1,0); + weaponPtr->StateTimeOutCounter=0; + WeaponFidgetPlaying=1; + } + #endif + } + + } + } +} + +void StaffAttack_Basic(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_PredatorHUD,(int)PHSS_Attack_Primary,-1,0); + if (PlayerStatusPtr->ShapeState!=PMph_Standing) { + StaffAttack=1; + } else { + StaffAttack=0; + } + } else if (HModelAnimation_IsFinished(&PlayersWeaponHModelController)) { + /* End state. */ + weaponPtr->StateTimeOutCounter = 0; + StaffAttack=-1; + } else { + enum AMMO_ID AmmoID=TemplateWeapon[weaponPtr->WeaponIDNumber].PrimaryAmmoID; + /* In the middle. */ + weaponPtr->StateTimeOutCounter = (WEAPONSTATE_INITIALTIMEOUTCOUNT>>1); + + Staff_Manager(&TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty],PlayerStaff1,PlayerStaff2,PlayerStaff3, + Player->ObStrategyBlock); + + } + +} + +int PointIsInPlayer(VECTORCH *point) { + /* Special case. */ + VECTORCH max,min; + + max.vx=Player->ObShapeData->shapemaxx; + min.vx=Player->ObShapeData->shapeminx; + max.vy=Player->ObShapeData->shapemaxy; + min.vy=Player->ObShapeData->shapeminy; + max.vz=Player->ObShapeData->shapemaxz; + min.vz=Player->ObShapeData->shapeminz; + + RotateVector(&max,&Player->ObMat); + RotateVector(&min,&Player->ObMat); + + max.vx+=Player->ObStrategyBlock->DynPtr->Position.vx; + max.vy+=Player->ObStrategyBlock->DynPtr->Position.vy; + max.vz+=Player->ObStrategyBlock->DynPtr->Position.vz; + + min.vx+=Player->ObStrategyBlock->DynPtr->Position.vx; + min.vy+=Player->ObStrategyBlock->DynPtr->Position.vy; + min.vz+=Player->ObStrategyBlock->DynPtr->Position.vz; + /* Now test. */ + if ((point->vx>min.vx)&&(point->vxvy>min.vy)&&(point->vyvz>min.vz)&&(point->vzSBdptr; + + if (dPtr==Player) { + GLOBALASSERT(dPtr); + } + + if (dPtr==NULL) { + *hit_section=NULL; + return(0); + } + if (dPtr->SfxPtr) { + *hit_section=NULL; + return(0); + } + if (dPtr==Player) { + /* Special case for player. */ + if (PointIsInPlayer(point)) { + /* Hit! */ + *hit_section=NULL; + return(1); + } + } else if (dPtr->HModelControlBlock) { + SECTION_DATA *hs; + /* Hierarchy case. */ + hs=PointInHModel(dPtr->HModelControlBlock,point); + if (hs) { + *hit_section=hs; + return(1); + } else { + *hit_section=NULL; + return(0); + } + } else { + VECTORCH offset; + int dist; + /* Use shape data. */ + if (dPtr->ObShapeData==NULL) { + *hit_section=NULL; + return(0); + } + offset.vx=dPtr->ObWorld.vx-point->vx; + offset.vy=dPtr->ObWorld.vy-point->vy; + offset.vz=dPtr->ObWorld.vz-point->vz; + dist=Approximate3dMagnitude(&offset); + if (distObShapeData->shaperadius) { + /* Hit! */ + *hit_section=NULL; + return(1); + } + } + *hit_section=NULL; + return(0); +} + +int Staff_Manager(DAMAGE_PROFILE *damage,SECTION_DATA *section1,SECTION_DATA *section2,SECTION_DATA *section3, + STRATEGYBLOCK *wielder) { + + SECTION_DATA *hit_section; + int numberOfObjects = NumActiveBlocks; + int numhits; + int hitatall=0; + + GLOBALASSERT(wielder->SBdptr); + + while (numberOfObjects) + { + DISPLAYBLOCK* objectPtr = ActiveBlockList[--numberOfObjects]; + STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock; + GLOBALASSERT(objectPtr); + + numhits=0; + + if (objectPtr==Player) { + GLOBALASSERT(objectPtr); + /* So I can breakpoint it. */ + } + + /* does object have a strategy block? */ + if ((sbPtr)&&(sbPtr!=wielder)) + { + + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + if (dynPtr) { + + if (IsThisObjectVisibleFromThisPosition_WithIgnore(objectPtr,wielder->SBdptr,&wielder->DynPtr->Position,10000)) { + + /* Deduce if each section has hit. */ + + if (IsPointInsideObject(§ion1->World_Offset,sbPtr,&hit_section)) { + numhits++; + } else if (IsPointInsideObject(§ion2->World_Offset,sbPtr,&hit_section)) { + numhits++; + } else if (IsPointInsideObject(§ion3->World_Offset,sbPtr,&hit_section)) { + numhits++; + } + + } + } + } + + if (numhits) { + hitatall++; + if (sbPtr->SBdptr->HModelControlBlock) { + #if 0 + if (hit_section==NULL) { + HtoHDamageToHModel(sbPtr, damage, NormalFrameTime, NULL, NULL); + } else { + CauseDamageToHModel(sbPtr->SBdptr->HModelControlBlock, sbPtr, damage, NormalFrameTime, hit_section,NULL,NULL,0); + } + #else + HtoHDamageToHModel(sbPtr, damage, NormalFrameTime, NULL, NULL); + #endif + } else { + CauseDamageToObject(sbPtr, damage, NormalFrameTime,NULL); + } + } + + } + return(hitatall); +} + +/* Cheat mode in here! */ +#define BITE_RANGE ((SNIPERMUNCH_MODE)? 100000:3000) +#define BITE_RADIUS ((SNIPERMUNCH_MODE)? 1500:200) + +#define TROPHY_RANGE (3000) +#define TROPHY_RADIUS (200) + +SECTION_DATA *CheckBiteIntegrity(void) { + + VECTORCH targetpos; + DISPLAYBLOCK *objectPtr; + + if (Biting==NULL) { + return(NULL); + } + if (!(Validate_Strategy(Biting,Biting_SBname))) { + return(NULL); + } + if (!(Biting->SBdptr)) { + /* Gone far? */ + return(NULL); + } + objectPtr=Biting->SBdptr; + + GetTargetingPointOfObject(objectPtr,&targetpos); + targetpos.vx-=Global_VDB_Ptr->VDB_World.vx; + targetpos.vy-=Global_VDB_Ptr->VDB_World.vy; + targetpos.vz-=Global_VDB_Ptr->VDB_World.vz; + RotateVector(&targetpos,&Global_VDB_Ptr->VDB_Mat); + + /* is it in the range band? */ + if ((targetpos.vz >0) + && (targetpos.vz < (BITE_RANGE<<1))) { + + DYNAMICSBLOCK *dynPtr = Biting->DynPtr; + GLOBALASSERT(dynPtr); + + if (IsThisObjectVisibleFromThisPosition_WithIgnore(objectPtr,Player,&Global_VDB_Ptr->VDB_World,(BITE_RANGE<<1))) { + + SECTION_DATA *head; + /* The minute his *head* is in view... */ + head=GetThisSectionData(objectPtr->HModelControlBlock->section_data,"head"); + if (head!=NULL) { + if (head->flags§ion_data_notreal) { + /* Is it still attached? */ + head=NULL; + } + } + /* We'll have the head now if at all. */ + if (head) { + VECTORCH temp_view; + int dist; + /* I assume if we're alive, we have a head. */ + temp_view=head->View_Offset; + temp_view.vz=0; + dist=Approximate3dMagnitude(&temp_view); + /* Scale radius with FOV here? */ + if (dist<(BITE_RADIUS<<1)) { + /* Aw, okay. */ + return(head); + } + } + } + } + /* If you got here, you failed. */ + return(NULL); +} + +int AlienBite_TargetFilter(STRATEGYBLOCK *sbPtr) { + + /* Is it tasty, mm? Is it... crunchable? */ + + if ((sbPtr->I_SBtype==I_BehaviourMarine) + ||(sbPtr->I_SBtype==I_BehaviourSeal)) + { + MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + GLOBALASSERT(marineStatusPointer); + + if (!marineStatusPointer->Android && !NPC_IsDead(sbPtr)) + { + return(1); + } + } + else if (sbPtr->I_SBtype==I_BehaviourNetCorpse) + { + NETCORPSEDATABLOCK *corpseDataPtr; + + corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(corpseDataPtr); + + if (((corpseDataPtr->timer/2)Android) + { + /* Already fading. */ + return(0); + } + else if ((corpseDataPtr->Type==I_BehaviourMarine) + ||(corpseDataPtr->Type==I_BehaviourSeal) + ||(corpseDataPtr->Type==I_BehaviourPredator) + ) + { + /* Of course it's dead! */ + return(1); + } + } else if (sbPtr->I_SBtype==I_BehaviourNetGhost) { + NETGHOSTDATABLOCK* ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + //check for opponent in network game + if(ghostData->type==I_BehaviourNetCorpse) + { + if(ghostData->subtype==I_BehaviourMarinePlayer || + ghostData->subtype==I_BehaviourPredatorPlayer) + { + return 1; + } + } + else if (ghostData->type==I_BehaviourMarinePlayer || + ghostData->type==I_BehaviourPredatorPlayer) + { + // We don't want to allow bite attacks against players + // that have respawn invulnerability + if(!ghostData->invulnerable) + { + return 1; + } + } + } else if (sbPtr->I_SBtype==I_BehaviourPredator) { + + /* There's always got to be a difficult one! */ + SECTION_DATA *head; + + if (!sbPtr->SBdptr) { + return(0); + } + /* The minute his *head* is in view... */ + head=GetThisSectionData(sbPtr->SBdptr->HModelControlBlock->section_data,"head"); + /* Is it still attached? */ + if (head) { + if (head->flags§ion_data_notreal) { + head=NULL; + } + } + /* We'll have the head now if at all. */ + if (head) { + DAMAGEBLOCK temp_damage; + + temp_damage=head->current_damage; + + DamageDamageBlock(&temp_damage,&TemplateAmmo[AMMO_PC_ALIEN_BITE].MaxDamage[AvP.Difficulty],ONE_FIXED); + + if (temp_damage.Health<=0) { + /* Killed the head, that'll do. */ + return(1); + } + /* So the head lived, huh? Let's try the body. */ + temp_damage=sbPtr->SBDamageBlock; + DamageDamageBlock(&temp_damage,&TemplateAmmo[AMMO_PC_ALIEN_BITE].MaxDamage[AvP.Difficulty],ONE_FIXED); + + if (temp_damage.Health<=0) { + /* Killed the body, that'll do too. */ + return(1); + } + + } + return(0); + } + + return(0); + +} + +STRATEGYBLOCK *GetBitingTarget(void) { + + /* Sweep OnScreenBlockList. */ + + int numberOfObjects = NumOnScreenBlocks; + + while (numberOfObjects) + { + STRATEGYBLOCK *sbPtr; + VECTORCH targetpos; + DISPLAYBLOCK* objectPtr = OnScreenBlockList[--numberOfObjects]; + + GLOBALASSERT(objectPtr); + sbPtr = objectPtr->ObStrategyBlock; + + /* does object have a strategy block? */ + if (sbPtr) { + + if (AlienBite_TargetFilter(sbPtr)) { + + GLOBALASSERT(objectPtr->HModelControlBlock); + + GetTargetingPointOfObject(objectPtr,&targetpos); + targetpos.vx-=Global_VDB_Ptr->VDB_World.vx; + targetpos.vy-=Global_VDB_Ptr->VDB_World.vy; + targetpos.vz-=Global_VDB_Ptr->VDB_World.vz; + RotateVector(&targetpos,&Global_VDB_Ptr->VDB_Mat); + + /* is it in the range band? */ + if ((targetpos.vz >0) + && (targetpos.vz < BITE_RANGE)) { + + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + if (dynPtr) { + + if (IsThisObjectVisibleFromThisPosition_WithIgnore(objectPtr,Player,&Global_VDB_Ptr->VDB_World,(BITE_RANGE<<1))) { + + SECTION_DATA *head; + /* The minute his *head* is in view... */ + head=GetThisSectionData(objectPtr->HModelControlBlock->section_data,"head"); + /* Is it still attached? */ + if (head) { + if (head->flags§ion_data_notreal) { + head=NULL; + } + } + /* We'll have the head now if at all. */ + if (head) { + VECTORCH temp_view; + int dist; + /* I assume if we're alive, we have a head. */ + temp_view=head->View_Offset; + temp_view.vz=0; + dist=Approximate3dMagnitude(&temp_view); + if (distI_SBtype==I_BehaviourNetCorpse) + { + NETCORPSEDATABLOCK *corpseDataPtr; + + corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(corpseDataPtr); + + if ((corpseDataPtr->timer/2)Type==I_BehaviourMarine) + ||(corpseDataPtr->Type==I_BehaviourSeal) + ||(corpseDataPtr->Type==I_BehaviourAlien) + ||(corpseDataPtr->Type==I_BehaviourPredator) + ) + { + /* Of course it's dead! */ + return(1); + } + } else if (sbPtr->I_SBtype==I_BehaviourNetGhost) { + NETGHOSTDATABLOCK* ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + //check for opponent in network game + if(ghostData->type==I_BehaviourNetCorpse) + { + if(ghostData->subtype==I_BehaviourMarinePlayer || + ghostData->subtype==I_BehaviourPredatorPlayer || + ghostData->subtype==I_BehaviourAlienPlayer) + { + return 1; + } + } + } else if (sbPtr->I_SBtype==I_BehaviourHierarchicalFragment) { + + DISPLAYBLOCK *objectPtr; + HDEBRIS_BEHAV_BLOCK *debrisDataPtr; + + debrisDataPtr = (HDEBRIS_BEHAV_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(debrisDataPtr); + + /* Check type. */ + + if ((debrisDataPtr->Type==I_BehaviourMarine) + ||(debrisDataPtr->Type==I_BehaviourSeal) + ||(debrisDataPtr->Type==I_BehaviourAlien) + ||(debrisDataPtr->Type==I_BehaviourPredator) + ) { + + objectPtr=sbPtr->SBdptr; + if (objectPtr) { + if (objectPtr->HModelControlBlock) { + SECTION_DATA *head; + /* Test for the head... */ + head=GetThisSectionData(objectPtr->HModelControlBlock->section_data,"head"); + /* Is it still attached? */ + if (head) { + if (head->flags§ion_data_notreal) { + head=NULL; + } + } + if (head) { + if ((HModel_DepthTest(objectPtr->HModelControlBlock,head,1))==0) { + /* Fragment is big enough. */ + return(1); + } + } + } + } + } + } else if (sbPtr->I_SBtype==I_BehaviourSpeargunBolt) { + + DISPLAYBLOCK *objectPtr; + SPEAR_BEHAV_BLOCK *spearDataPtr; + + spearDataPtr = (SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(spearDataPtr); + + /* Check type. */ + + if ((spearDataPtr->Type==I_BehaviourMarine) + ||(spearDataPtr->Type==I_BehaviourSeal) + ||(spearDataPtr->Type==I_BehaviourAlien) + ||(spearDataPtr->Type==I_BehaviourPredator) + ) { + + objectPtr=sbPtr->SBdptr; + if (objectPtr) { + if (objectPtr->HModelControlBlock) { + SECTION_DATA *head; + /* Test for the head... */ + head=GetThisSectionData(objectPtr->HModelControlBlock->section_data,"head"); + /* Is it still attached? */ + if (head) { + if (head->flags§ion_data_notreal) { + head=NULL; + } + } + if (head) { + if ((HModel_DepthTest(objectPtr->HModelControlBlock,head,1))==0) { + /* Fragment is big enough. */ + return(1); + } + } + } + } + } + } + + return(0); + +} + +STRATEGYBLOCK *GetTrophyTarget(SECTION_DATA **head_section_data) { + + /* Sweep OnScreenBlockList. */ + + int numberOfObjects = NumOnScreenBlocks; + + *head_section_data=NULL; + + while (numberOfObjects) + { + STRATEGYBLOCK *sbPtr; + VECTORCH targetpos; + DISPLAYBLOCK* objectPtr = OnScreenBlockList[--numberOfObjects]; + + GLOBALASSERT(objectPtr); + sbPtr = objectPtr->ObStrategyBlock; + + /* does object have a strategy block? */ + if (sbPtr) { + + if (Trophy_TargetFilter(sbPtr)) { + + GLOBALASSERT(objectPtr->HModelControlBlock); + + GetTargetingPointOfObject(objectPtr,&targetpos); + targetpos.vx-=Global_VDB_Ptr->VDB_World.vx; + targetpos.vy-=Global_VDB_Ptr->VDB_World.vy; + targetpos.vz-=Global_VDB_Ptr->VDB_World.vz; + RotateVector(&targetpos,&Global_VDB_Ptr->VDB_Mat); + + /* is it in the range band? */ + if ((targetpos.vz >0) + && (targetpos.vz < TROPHY_RANGE)) { + + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + if (dynPtr) { + + //if (IsThisObjectVisibleFromThisPosition_WithIgnore(objectPtr,Player,&Global_VDB_Ptr->VDB_World,(TROPHY_RANGE<<1))) { + if (CameraCanSeeThisPosition_WithIgnore(objectPtr,&dynPtr->Position)) { + + SECTION_DATA *head; + /* The minute his *head* is in view... */ + head=GetThisSectionData(objectPtr->HModelControlBlock->section_data,"head"); + /* Is it still attached? */ + if (head) { + if (head->flags§ion_data_notreal) { + head=NULL; + } + } + /* We'll have the head now if at all. */ + if (head) { + VECTORCH temp_view; + int dist; + /* I assume if we're alive, we have a head. */ + temp_view=head->View_Offset; + temp_view.vz=0; + dist=Approximate3dMagnitude(&temp_view); + if (distWeaponSlot[PlayerStatusPtr->SelectedWeaponSlot]); + + slot=SlotForThisWeapon(WEAPON_PRED_DISC); + if (slot==-1) { + /* Maybe you're not a predator... */ + return; + #if 0 + } else if (weaponPtr->CurrentState==WEAPONSTATE_IDLE) { + PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo=(slot+1); + #else + } else { + AutoSwap=slot; + #endif + } + +} + +extern void AutoSwapToDisc_OutOfSequence(void) { + + int slot; + PLAYER_WEAPON_DATA *weaponPtr; + + weaponPtr = &(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot]); + + slot=SlotForThisWeapon(WEAPON_PRED_DISC); + + if (slot!=-1) { + AutoSwap=slot; + } + +} + +#define SPEAR_NPC_IMPULSE (20000) + +void CreateSpearPossiblyWithFragment(DISPLAYBLOCK *dispPtr, VECTORCH *spearPositionPtr, VECTORCH *spearDirectionPtr); +void HandleSpearImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *this_section_data) +{ + VECTORCH incoming,*invec; + DISPLAYBLOCK *fragged_section; + + fragged_section=NULL; + + if(sbPtr) + { + if (sbPtr->DynPtr) { + MATRIXCH WtoLMat; + /* Consider incoming hit direction. */ + WtoLMat=sbPtr->DynPtr->OrientMat; + TransposeMatrixCH(&WtoLMat); + RotateAndCopyVector(directionPtr,&incoming,&WtoLMat); + invec=&incoming; + } else { + invec=NULL; + } + + if (this_section_data) + { + if (sbPtr->SBdptr) + { + //if (sbPtr->SBdptr->HModelControlBlock && (sbPtr->I_SBtype != I_BehaviourNetGhost)) + if (sbPtr->SBdptr->HModelControlBlock) + { + /* Netghost case now handled properly. */ + AddDecalToHModel(&LOS_ObjectNormal, &LOS_Point,this_section_data); + + GLOBALASSERT(sbPtr->SBdptr->HModelControlBlock==this_section_data->my_controller); + fragged_section=CauseDamageToHModel(sbPtr->SBdptr->HModelControlBlock, sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple*ONE_FIXED, this_section_data,invec,positionPtr,0); + /* No longer return: do knockback. */ + //return; + } + else + { + CauseDamageToObject(sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple*ONE_FIXED,invec); + } + } + else + { + CauseDamageToObject(sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple*ONE_FIXED,invec); + } + } + else + { + CauseDamageToObject(sbPtr, &TemplateAmmo[AmmoID].MaxDamage[AvP.Difficulty], multiple*ONE_FIXED,invec); + } + + if (sbPtr->DynPtr) + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + /* Forget torque for the moment. */ + + /* + Knock the character back - unless it is the alien queen. + */ + if(sbPtr->I_SBtype!=I_BehaviourQueenAlien) + { + dynPtr->LinImpulse.vx+=MUL_FIXED(directionPtr->vx,(SPEAR_NPC_IMPULSE)); + dynPtr->LinImpulse.vy+=MUL_FIXED(directionPtr->vy,(SPEAR_NPC_IMPULSE)); + dynPtr->LinImpulse.vz+=MUL_FIXED(directionPtr->vz,(SPEAR_NPC_IMPULSE)); + } + + if (fragged_section) { + + fragged_section->ObStrategyBlock->DynPtr->LinImpulse.vx+=MUL_FIXED(directionPtr->vx,SPEAR_NPC_IMPULSE); + fragged_section->ObStrategyBlock->DynPtr->LinImpulse.vy+=MUL_FIXED(directionPtr->vy,SPEAR_NPC_IMPULSE); + fragged_section->ObStrategyBlock->DynPtr->LinImpulse.vz+=MUL_FIXED(directionPtr->vz,SPEAR_NPC_IMPULSE); + } + } + + + } + + + /* check to see if we've shot off a body part, or we're stuck into the environment */ + { + char needToAddSpear = 0; + + if (fragged_section) + { + needToAddSpear = 1; + } + else if (sbPtr) + { + DISPLAYBLOCK *dispPtr = sbPtr->SBdptr; + + if (dispPtr) + if (dispPtr->ObMyModule && (!dispPtr->ObMorphCtrl)) + { + needToAddSpear=1; + } + } + else + { + needToAddSpear = 1; + } + if (needToAddSpear) CreateSpearPossiblyWithFragment(fragged_section,&LOS_Point,directionPtr); + } +} + + +void CreateSpearPossiblyWithFragment(DISPLAYBLOCK *dispPtr, VECTORCH *spearPositionPtr, VECTORCH *spearDirectionPtr) +{ + + if (dispPtr) + { + STRATEGYBLOCK *sbPtr; + DYNAMICSBLOCK *dynPtr; + SPEAR_BEHAV_BLOCK *newBehaviourDataBlock; + int android; + + AVP_BEHAVIOUR_TYPE Type; + int SubType; + + sbPtr = dispPtr->ObStrategyBlock; + LOCALASSERT(sbPtr); + + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + LOCALASSERT(sbPtr->I_SBtype == I_BehaviourHierarchicalFragment); + + newBehaviourDataBlock=(SPEAR_BEHAV_BLOCK*)AllocateMem(sizeof(SPEAR_BEHAV_BLOCK)); + + android=((HDEBRIS_BEHAV_BLOCK *) sbPtr->SBdataptr)->Android; + + Splice_HModels(&(newBehaviourDataBlock->HierarchicalFragment),(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController).section_data); + + Type=((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type; + SubType=((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType; + + /* we don't need the old extra sb data */ + Dispel_HModel(&(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController)); + DeallocateMem(sbPtr->SBdataptr); + + dispPtr->HModelControlBlock = &(newBehaviourDataBlock->HierarchicalFragment); + + sbPtr->SBdataptr =(void*) newBehaviourDataBlock; + + if (!sbPtr->SBdataptr) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(sbPtr); + return; + } + sbPtr->I_SBtype = I_BehaviourSpeargunBolt; + + ((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->counter = 5*ONE_FIXED; + ((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->Stuck = 0; + ((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->SpearThroughFragment = 1; + ((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->Android = android; + ((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->Type = Type; + ((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->SubType = SubType; + + + dynPtr->LinVelocity.vx = spearDirectionPtr->vx/4; + dynPtr->LinVelocity.vy = spearDirectionPtr->vy/4; + dynPtr->LinVelocity.vz = spearDirectionPtr->vz/4; + dynPtr->LinImpulse.vx = 0; + dynPtr->LinImpulse.vy = 0; + dynPtr->LinImpulse.vz = 0; + dynPtr->AngVelocity.EulerX = 0; + dynPtr->AngVelocity.EulerY = 0; + dynPtr->AngVelocity.EulerZ = 0; + dynPtr->GravityOn = 0; + dynPtr->StopOnCollision = 1; + + ((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->Position.vx = spearPositionPtr->vx - dynPtr->Position.vx; + ((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->Position.vy = spearPositionPtr->vy - dynPtr->Position.vy; + ((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->Position.vz = spearPositionPtr->vz - dynPtr->Position.vz; + { + MATRIXCH mat; + MakeMatrixFromDirection(spearDirectionPtr,&mat); + ((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->Orient = mat; + } + + /* Ooooh! Not initialised at all! CDF 23/9/98, hassled about an assert */ + /* KJL 10:37:56 05/10/98 - Just keeping you on your toes :) */ + + InitHModelTweening(&(((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->HierarchicalFragment),(ONE_FIXED<<1),0,1,ONE_FIXED,0); + ProveHModel(dispPtr->HModelControlBlock,dispPtr); + /* And just for now... */ + ((SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr)->HierarchicalFragment.Playing=0; + + /* Baaaad Kevin! And why couldn't you have called the HModelController 'HModelController' like God intended? */ + /* KJL 10:38:17 05/10/98 - Hey, I was trying to be descriptive. */ + + Sound_Play(SID_PLASMABOLT_HIT,"d",&dynPtr->Position); + + } + else /* there is no hierarchical fragment; we've stuck into the environment */ + { + DYNAMICSBLOCK *dynPtr; + + dispPtr = MakeObject(I_BehaviourSpeargunBolt,spearPositionPtr); + if (dispPtr == 0) return; // Failed to allocate display block + + /* KJL 17:53:36 01/08/98 - make the extents teeny-weeny */ + dispPtr->ObMaxX = 10; + dispPtr->ObMaxY = 10; + dispPtr->ObMaxZ = 10; + dispPtr->ObMinX = -10; + dispPtr->ObMinY = -10; + dispPtr->ObMinZ = -10; + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + dynPtr->DynamicsType = DYN_TYPE_NO_COLLISIONS; + + if (!dynPtr) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* give missile a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(SPEAR_BEHAV_BLOCK)); + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + memset(dispPtr->ObStrategyBlock->SBdataptr,0,sizeof(SPEAR_BEHAV_BLOCK)); + + ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 20*ONE_FIXED; + ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->Stuck = 1; + ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->SpearThroughFragment = 0; + ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->Android = 0; + ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->Type = I_BehaviourNull; + ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->SubType = 0; + + dynPtr->Position= *spearPositionPtr; + dynPtr->PrevPosition= *spearPositionPtr; + { + MATRIXCH mat; + MakeMatrixFromDirection(spearDirectionPtr,&mat); + dynPtr->OrientMat = mat; + MatrixToEuler(&mat,&dynPtr->OrientEuler); + } + dynPtr->PrevOrientMat = dynPtr->OrientMat; + { + VECTORCH pos = dynPtr->Position; + pos.vx += spearDirectionPtr->vx; + pos.vy += spearDirectionPtr->vy; + pos.vz += spearDirectionPtr->vz; + MakeFocusedExplosion(&(dynPtr->Position), &pos, 20, PARTICLE_SPARK); + MakeLightElement(&(dynPtr->Position),LIGHTELEMENT_ELECTRICAL_SPARKS); + } + + if(AvP.Network != I_No_Network) + { + //send location here , so as to avoid having to update it every frame + AddNetMsg_LocalObjectState(dispPtr->ObStrategyBlock); + } + + #if 0 // no network yet! + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock); + #endif + #endif + Sound_Play(SID_SPEARGUN_HITTING_WALL,"d",&dynPtr->Position); + return; + } +} + +void LimbRip_AwardHealth(void) { + + NPC_DATA *NpcData; + int health_bonus; + + NpcData=GetThisNpcData(I_PC_Alien_MaxStats); + LOCALASSERT(NpcData); + + switch (AvP.Difficulty) { + case I_Easy: + health_bonus=5; + break; + case I_Medium: + default: + health_bonus=2; + break; + case I_Hard: + health_bonus=1; + break; + case I_Impossible: + health_bonus=0; + break; + } + + /* Now add some health. */ + Player->ObStrategyBlock->SBDamageBlock.Health+=(health_bonus<ObStrategyBlock->SBDamageBlock.Health>(NpcData->StartingStats.Health<ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<Health=Player->ObStrategyBlock->SBDamageBlock.Health; + +} + +void BiteAttack_AwardHealth(STRATEGYBLOCK *sbPtr,AVP_BEHAVIOUR_TYPE pre_bite_type) { + + NPC_DATA *NpcData; + + /* Have all your armour back? */ + NpcData=GetThisNpcData(I_PC_Alien_MaxStats); + LOCALASSERT(NpcData); + + if ((pre_bite_type==I_BehaviourMarine) + ||(pre_bite_type==I_BehaviourSeal) + ||(pre_bite_type==I_BehaviourPredator)) { + + /* Add some armour... */ + Player->ObStrategyBlock->SBDamageBlock.Armour+=(BITE_ARMOUR_RECOVERY<ObStrategyBlock->SBDamageBlock.Armour>(NpcData->StartingStats.Armour<ObStrategyBlock->SBDamageBlock.Armour=NpcData->StartingStats.Armour<Armour=Player->ObStrategyBlock->SBDamageBlock.Armour; + + /* And some health, too. */ + Player->ObStrategyBlock->SBDamageBlock.Health+=(BITE_HEALTH_RECOVERY<ObStrategyBlock->SBDamageBlock.Health>(NpcData->StartingStats.Health<ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<Health=Player->ObStrategyBlock->SBDamageBlock.Health; + + return; + } + + if (pre_bite_type==I_BehaviourNetCorpse) { + /* It probably is still a corpse now... */ + NETCORPSEDATABLOCK *corpseDataPtr; + + corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(corpseDataPtr); + + if ((corpseDataPtr->Type==I_BehaviourMarine) + ||(corpseDataPtr->Type==I_BehaviourSeal) + ||(corpseDataPtr->Type==I_BehaviourPredator) + ) { + /* No armour, just a bit of health. */ + Player->ObStrategyBlock->SBDamageBlock.Health+=(20<ObStrategyBlock->SBDamageBlock.Health>(NpcData->StartingStats.Health<ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<Health=Player->ObStrategyBlock->SBDamageBlock.Health; + } + } + + if(pre_bite_type==I_BehaviourNetGhost) + { + //rather higher health awards for getting network opponents + NETGHOSTDATABLOCK *ghostData; + NPC_DATA* StartingHealth; + + switch (AvP.Difficulty) { + case I_Easy: + StartingHealth=GetThisNpcData(I_PC_Alien_Easy); + break; + default: + case I_Medium: + StartingHealth=GetThisNpcData(I_PC_Alien_Medium); + break; + case I_Hard: + StartingHealth=GetThisNpcData(I_PC_Alien_Hard); + break; + case I_Impossible: + StartingHealth=GetThisNpcData(I_PC_Alien_Impossible); + break; + } + + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + if(ghostData->type==I_BehaviourNetCorpse) + { + if(ghostData->subtype==I_BehaviourMarinePlayer || + ghostData->subtype==I_BehaviourPredatorPlayer) + { + /* Add some armour... */ + Player->ObStrategyBlock->SBDamageBlock.Armour+=(BITE_ARMOUR_RECOVERY<ObStrategyBlock->SBDamageBlock.Armour>(NpcData->StartingStats.Armour<ObStrategyBlock->SBDamageBlock.Armour=NpcData->StartingStats.Armour<Armour=Player->ObStrategyBlock->SBDamageBlock.Armour; + + /* And some health, too. */ + Player->ObStrategyBlock->SBDamageBlock.Health+=(20<ObStrategyBlock->SBDamageBlock.Health>(NpcData->StartingStats.Health<ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<ObStrategyBlock->SBDamageBlock.Health<(StartingHealth->StartingStats.Health<ObStrategyBlock->SBDamageBlock.Health=StartingHealth->StartingStats.Health<Health=Player->ObStrategyBlock->SBDamageBlock.Health; + } + } + else if(ghostData->type==I_BehaviourMarinePlayer || + ghostData->type==I_BehaviourPredatorPlayer) + { + //killed player character with a bite attack + + /* Add some armour... */ + Player->ObStrategyBlock->SBDamageBlock.Armour+=(StartingHealth->StartingStats.Armour<ObStrategyBlock->SBDamageBlock.Armour>(NpcData->StartingStats.Armour<ObStrategyBlock->SBDamageBlock.Armour=NpcData->StartingStats.Armour<Armour=Player->ObStrategyBlock->SBDamageBlock.Armour; + + /* And some health, too. */ + Player->ObStrategyBlock->SBDamageBlock.Health+=(StartingHealth->StartingStats.Health<ObStrategyBlock->SBDamageBlock.Health>(NpcData->StartingStats.Health<ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<Health=Player->ObStrategyBlock->SBDamageBlock.Health; + } + + } + +} + +int PlayerFirePredPistolFlechettes(PLAYER_WEAPON_DATA *weaponPtr) { + + extern VECTORCH CentreOfMuzzleOffset; + VECTORCH *firingpos; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + /* Another cheap copy of the flamethrower function. */ + + ProveHModel(&PlayersWeaponHModelController,&PlayersWeapon); + + if (playerStatusPtr->FieldCharge>0) { + playerStatusPtr->FieldCharge-=(NormalFrameTime); + CurrentGameStats_ChargeUsed(NormalFrameTime); + if (playerStatusPtr->FieldCharge<0) { + playerStatusPtr->FieldCharge=0; + } + } else { + return(0); + } + + if (PWMFSDP) { + VECTORCH null_vec={0,0,0}; + + textprint("Hierarchical Flechettes Fire!\n"); + + firingpos=&PWMFSDP->World_Offset; + + FirePredPistolFlechettes(firingpos,&null_vec,&PlayersWeapon.ObMat,0,&Flamethrower_Timer,TRUE); + + } else { + firingpos=&CentreOfMuzzleOffset; + FirePredPistolFlechettes(&PlayersWeapon.ObWorld,firingpos,&PlayersWeapon.ObMat,1,&Flamethrower_Timer,TRUE); + } + + + return(1); + +} + +int PredPistolSecondaryFire(PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber]; + TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->SecondaryAmmoID]; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + LOCALASSERT(playerStatusPtr); + + if (playerStatusPtr->FieldCharge>=PredPistol_ShotCost) { + + playerStatusPtr->FieldCharge-=PredPistol_ShotCost; + CurrentGameStats_ChargeUsed(PredPistol_ShotCost); + + FireProjectileAmmo(twPtr->PrimaryAmmoID); + CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1); + + return(1); + } + + return(0); +} + +void ChangeHUDToAlternateShapeSet(char *riffname,char *setname) { + + HIERARCHY_SHAPE_REPLACEMENT* replacement_array; + int a; + + replacement_array=GetHierarchyAlternateShapeSetFromLibrary(riffname,setname); + + if (replacement_array==NULL) { + return; + } + + a=0; + + while (replacement_array[a].replaced_section_name!=NULL) { + SECTION_DATA *target_section; + + target_section=GetThisSectionData(PlayersWeaponHModelController.section_data, + replacement_array[a].replaced_section_name); + if (target_section) { + target_section->Shape=replacement_array[a].replacement_shape; + #if 1 + target_section->ShapeNum=replacement_array[a].replacement_shape_index; + #endif + + Setup_Texture_Animation_For_Section(target_section); + } + a++; + } +} + +int AccuracyStats_TargetFilter(STRATEGYBLOCK *sbPtr) { + + if (sbPtr==NULL) { + return(0); + } + + switch (sbPtr->I_SBtype) { + case I_BehaviourPredator: + /* Valid. */ + if (NPC_IsDead(sbPtr)) { + return(1); + } else { + return(1); + } + break; + case I_BehaviourAlien: + case I_BehaviourQueenAlien: + case I_BehaviourFaceHugger: + case I_BehaviourXenoborg: + case I_BehaviourMarine: + case I_BehaviourSeal: + case I_BehaviourPredatorAlien: + /* Valid. */ + if (NPC_IsDead(sbPtr)) { + return(1); + } else { + return(1); + } + break; + case I_BehaviourNetCorpse: + { + NETCORPSEDATABLOCK *corpseDataPtr; + LOCALASSERT(sbPtr); + corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(corpseDataPtr); + + if (corpseDataPtr->validityTimer>0) { + return(1); + } else { + return(0); + } + } + break; + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *dataptr; + dataptr=sbPtr->SBdataptr; + switch (dataptr->type) { + case I_BehaviourPredatorPlayer: + return(1); + break; + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourRocket: + case I_BehaviourGrenade: + case I_BehaviourFlareGrenade: + case I_BehaviourFragmentationGrenade: + case I_BehaviourClusterGrenade: + case I_BehaviourNPCPredatorDisc: + case I_BehaviourPredatorDisc_SeekTrack: + case I_BehaviourAlien: + case I_BehaviourProximityGrenade: + return(1); + break; + default: + return(0); + break; + } + } + break; + default: + return(0); + break; + } + + return(0); + +} + +int FriendlyFireDamageFilter(DAMAGE_PROFILE *damage) { + + BOOL VulnerableToAlienDamage = TRUE; + BOOL VulnerableToMarineDamage = TRUE; + BOOL VulnerableToPredatorDamage = TRUE; + + if(AvP.PlayerType == I_Alien) + { + VulnerableToAlienDamage = FALSE; + } + else if(AvP.PlayerType == I_Marine) + { + VulnerableToMarineDamage = FALSE; + if(netGameData.gameType==NGT_Coop) + { + VulnerableToPredatorDamage = FALSE; + } + } + else if(AvP.PlayerType == I_Predator) + { + VulnerableToPredatorDamage = FALSE; + if(netGameData.gameType==NGT_Coop) + { + VulnerableToMarineDamage = FALSE; + } + } + + /* Does this damage type hurt you? */ + + switch (damage->Id) { + case AMMO_ALIEN_CLAW: + case AMMO_ALIEN_TAIL: + case AMMO_ALIEN_BITE_KILLSECTION: + case AMMO_ALIEN_BITE_KILLSECTION_SUPER: + case AMMO_PC_ALIEN_BITE: + return(VulnerableToAlienDamage); + break; + + case AMMO_10MM_CULW: + case AMMO_SMARTGUN: + case AMMO_FLAMETHROWER: + case AMMO_SADAR_TOW: + case AMMO_GRENADE: + case AMMO_MINIGUN: + case AMMO_PULSE_GRENADE: + case AMMO_FRAGMENTATION_GRENADE: + case AMMO_PROXIMITY_GRENADE: + case AMMO_SADAR_BLAST: + case AMMO_PULSE_GRENADE_STRIKE: + case AMMO_CUDGEL: + case AMMO_FLECHETTE_POSTMAX: + case AMMO_FRISBEE: + case AMMO_FRISBEE_BLAST: + case AMMO_FRISBEE_FIRE: + case AMMO_MARINE_PISTOL_PC: + return(VulnerableToMarineDamage); + break; + + case AMMO_PRED_WRISTBLADE: + case AMMO_PRED_PISTOL: + case AMMO_PRED_RIFLE: + case AMMO_PRED_ENERGY_BOLT: + case AMMO_PRED_DISC: + case AMMO_PRED_STAFF: + case AMMO_HEAVY_PRED_WRISTBLADE: + case AMMO_PREDPISTOL_STRIKE: + case AMMO_PLASMACASTER_NPCKILL: + case AMMO_PLASMACASTER_PCKILL: + case AMMO_PRED_TROPHY_KILLSECTION: + return(VulnerableToPredatorDamage); + break; + } + + return TRUE; +} + + +/*-------------------** +** Load/Save Globals ** +**-------------------*/ +#include "savegame.h" + +typedef struct weapons_c_save_block +{ + SAVE_BLOCK_HEADER header; + + int Alien_Visible_Weapon; + int Alien_Tail_Clock; + int Wristblade_StrikeType; + DAMAGE_PROFILE Player_Weapon_Damage; + int playerNoise; + int PlayerDamagedOverlayIntensity; + int HtoHStrikes; + int WeaponFidgetPlaying; + int Old_Minigun_SpinSpeed; + int Minigun_SpinSpeed; + int Weapon_ThisBurst; + EULER Minigun_MaxHeadJolt; + EULER Minigun_HeadJolt; + int Flamethrower_Timer; + int StaffAttack; + int GrenadeLauncherSelectedAmmo; + int LastHand; // For alien claws + VECTORCH PlayersWeaponCameraOffset; + VECTORCH PlayerGunBarrelOffset; +}WEAPONS_C_SAVE_BLOCK; + +void Load_WeaponsCGlobals(SAVE_BLOCK_HEADER* header) +{ + WEAPONS_C_SAVE_BLOCK* block = (WEAPONS_C_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + Alien_Visible_Weapon = block->Alien_Visible_Weapon; + Alien_Tail_Clock = block->Alien_Tail_Clock; + Wristblade_StrikeType = block->Wristblade_StrikeType; + Player_Weapon_Damage = block->Player_Weapon_Damage; + playerNoise = block->playerNoise; + PlayerDamagedOverlayIntensity = block->PlayerDamagedOverlayIntensity; + HtoHStrikes = block->HtoHStrikes; + WeaponFidgetPlaying = block->WeaponFidgetPlaying; + Old_Minigun_SpinSpeed = block->Old_Minigun_SpinSpeed; + Minigun_SpinSpeed = block->Minigun_SpinSpeed; + Weapon_ThisBurst = block->Weapon_ThisBurst; + Minigun_MaxHeadJolt = block->Minigun_MaxHeadJolt; + Minigun_HeadJolt = block->Minigun_HeadJolt; + Flamethrower_Timer = block->Flamethrower_Timer; + StaffAttack = block->StaffAttack; + GrenadeLauncherSelectedAmmo = block->GrenadeLauncherSelectedAmmo; + LastHand = block->LastHand; // For alien claws + + PlayersWeaponCameraOffset = block->PlayersWeaponCameraOffset; + PlayerGunBarrelOffset = block->PlayerGunBarrelOffset; + + Load_SoundState(&weaponHandle); +} + +void Save_WeaponsCGlobals() +{ + WEAPONS_C_SAVE_BLOCK* block; + + GET_SAVE_BLOCK_POINTER(block); + + //fill in the header + block->header.size = sizeof(*block); + block->header.type = SaveBlock_WeaponsCGlobals; + + block->Alien_Visible_Weapon = Alien_Visible_Weapon; + block->Alien_Tail_Clock = Alien_Tail_Clock; + block->Wristblade_StrikeType = Wristblade_StrikeType; + block->Player_Weapon_Damage = Player_Weapon_Damage; + block->playerNoise = playerNoise; + block->PlayerDamagedOverlayIntensity = PlayerDamagedOverlayIntensity; + block->HtoHStrikes = HtoHStrikes; + block->WeaponFidgetPlaying = WeaponFidgetPlaying; + block->Old_Minigun_SpinSpeed = Old_Minigun_SpinSpeed; + block->Minigun_SpinSpeed = Minigun_SpinSpeed; + block->Weapon_ThisBurst = Weapon_ThisBurst; + block->Minigun_MaxHeadJolt = Minigun_MaxHeadJolt; + block->Minigun_HeadJolt = Minigun_HeadJolt; + block->Flamethrower_Timer = Flamethrower_Timer; + block->StaffAttack = StaffAttack; + block->GrenadeLauncherSelectedAmmo = GrenadeLauncherSelectedAmmo; + block->LastHand = LastHand; // For alien claws + + block->PlayersWeaponCameraOffset = PlayersWeaponCameraOffset; + block->PlayerGunBarrelOffset = PlayerGunBarrelOffset; + + + + Save_SoundState(&weaponHandle); +} + +void MarinePistol_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + DELTA_CONTROLLER *StockBack; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + StockBack=Get_Delta_Sequence(&PlayersWeaponHModelController,"StockBack"); + if (StockBack) { + /* Get rid of it. */ + Remove_Delta_Sequence(&PlayersWeaponHModelController,"StockBack"); + } + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + if (weaponPtr->PrimaryRoundsRemaining>=65536) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>6),HMSQT_MarineHUD,(int)MHSS_Standard_Fire,-1,0); + } else { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>6),HMSQT_MarineHUD,(int)MHSS_Secondary_Fire,-1,0); + } + { + SECTION_DATA *casing; + /* Make a little casing. */ + + casing=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum R Pistol round"); + + if (casing) { + MakePistolCasing(&casing->World_Offset,&casing->SecMat); + } + } + } + +} + +void MarinePistol_Fidget(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + DELTA_CONTROLLER *StockBack; + + GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD); + + StockBack=Get_Delta_Sequence(&PlayersWeaponHModelController,"StockBack"); + if (StockBack) { + /* Get rid of it. */ + Remove_Delta_Sequence(&PlayersWeaponHModelController,"StockBack"); + } + + if ((PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary)&&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Fidget)) { + if (weaponPtr->PrimaryRoundsRemaining) { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED); + } + } + + if (weaponPtr->StateTimeOutCounter > ONE_FIXED) { + + if (WeaponFidgetPlaying) { + if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1); + WeaponFidgetPlaying=0; + } + } else if ((FastRandom()&255)==0) { + /* Start animation. */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Fidget,(ONE_FIXED<<1),0); + weaponPtr->StateTimeOutCounter=0; + WeaponFidgetPlaying=1; + } + } + + } + +} + +void MarinePistol_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + DELTA_CONTROLLER *StockBack; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + StockBack=Get_Delta_Sequence(&PlayersWeaponHModelController,"StockBack"); + if (StockBack) { + /* Get rid of it. */ + Remove_Delta_Sequence(&PlayersWeaponHModelController,"StockBack"); + } + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_RELOAD_PRIMARY]); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Standard_Reload,time,0); + PlayersWeaponHModelController.Looped=0; + + if ((AvP.Network != I_No_Network)&&(PISTOL_INFINITE_AMMO)) { + /* Pistol infinite ammo hack? */ + weaponPtr->PrimaryMagazinesRemaining++; + } + } + StaffAttack=-1; +} + +DISPLAYBLOCK *MakePistolCasing(VECTORCH *position,MATRIXCH *orient) { + + DISPLAYBLOCK *dispPtr; + STRATEGYBLOCK *sbPtr; + MODULEMAPBLOCK *mmbptr; + MODULE m_temp; + + if( (NumActiveBlocks > maxobjects-5) || (NumActiveStBlocks > maxstblocks-5)) return NULL; + + mmbptr = &TempModuleMap; + + CreateShapeInstance(mmbptr,"Pistol case"); + + m_temp.m_numlights = 0; + m_temp.m_lightarray = NULL; + m_temp.m_mapptr = mmbptr; + m_temp.m_sbptr = (STRATEGYBLOCK*)NULL; + m_temp.m_dptr = NULL; + AllocateModuleObject(&m_temp); + dispPtr = m_temp.m_dptr; + if(dispPtr==NULL) return (DISPLAYBLOCK *)0; /* patrick: cannot create displayblock, so just return 0 */ + + dispPtr->ObMyModule = NULL; /* Module that created us */ + dispPtr->ObWorld = *position; + + sbPtr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dispPtr); + + if (sbPtr == 0) return (DISPLAYBLOCK *)0; // Failed to allocate a strategy block + + sbPtr->I_SBtype = I_BehaviourFragment; + + { + DYNAMICSBLOCK *dynPtr; + VECTORCH impulse; + + sbPtr->SBdataptr = (ONE_SHOT_BEHAV_BLOCK *) AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK )); + if (sbPtr->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(sbPtr); + return(DISPLAYBLOCK*)NULL; + } + + + ((ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = ALIEN_DYINGTIME; + + dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEBRIS); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(sbPtr); + return(DISPLAYBLOCK*)NULL; + } + + dynPtr->Position = *position; + dynPtr->OrientMat= *orient; + + dynPtr->AngVelocity.EulerX = 0; + dynPtr->AngVelocity.EulerY = ((FastRandom()&4095)<<2); + dynPtr->AngVelocity.EulerZ = 0; + + impulse.vx=0; + impulse.vy=0; + impulse.vz=6000; + + RotateVector(&impulse,orient); + + dynPtr->LinImpulse = impulse; + + sbPtr->SBflags.not_on_motiontracker=1; + } + + return dispPtr; + +} + +void MarineTwoPistols_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + DELTA_CONTROLLER *FireRight; + DELTA_CONTROLLER *FireLeft; + + FireRight=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireRight"); + if (FireRight==NULL) { + FireRight=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireRight",HMSQT_MarineHUD,MHSS_Standard_Fire,ONE_FIXED); + FireRight->Playing=0; + FireRight->Active=0; + } + + FireLeft=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft"); + if (FireLeft==NULL) { + FireLeft=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft",HMSQT_MarineHUD,MHSS_Secondary_Fire,ONE_FIXED); + FireLeft->Playing=0; + FireLeft->Active=0; + } + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + if (LastHand==0) { + if (weaponPtr->PrimaryRoundsRemaining>=65536) { + Start_Delta_Sequence(FireRight,HMSQT_MarineHUD,MHSS_Standard_Fire,-1); + FireRight->Playing=1; + FireRight->Active=1; + } else { + Start_Delta_Sequence(FireRight,HMSQT_MarineHUD,MHSS_Right_Out,-1); + FireRight->Playing=1; + FireRight->Active=1; + } + { + SECTION_DATA *casing; + /* Make a little casing. */ + + casing=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum R Pistol round"); + + if (casing) { + MakePistolCasing(&casing->World_Offset,&casing->SecMat); + } + } + } else { + if (weaponPtr->SecondaryRoundsRemaining>=65536) { + Start_Delta_Sequence(FireLeft,HMSQT_MarineHUD,MHSS_Secondary_Fire,-1); + FireLeft->Playing=1; + FireLeft->Active=1; + } else { + Start_Delta_Sequence(FireLeft,HMSQT_MarineHUD,MHSS_Left_Out,-1); + FireLeft->Playing=1; + FireLeft->Active=1; + } + { + SECTION_DATA *casing; + /* Make a little casing. */ + + casing=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum L Pistol round"); + + if (casing) { + MakePistolCasing(&casing->World_Offset,&casing->SecMat); + } + } + } + if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>1),HMSQT_MarineHUD,(int)MHSS_Stationary,-1,0); + } + } +} + +void MarineTwoPistols_SecondaryFiring(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + DELTA_CONTROLLER *FireRight; + DELTA_CONTROLLER *FireLeft; + + FireRight=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireRight"); + if (FireRight==NULL) { + FireRight=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireRight",HMSQT_MarineHUD,MHSS_Standard_Fire,ONE_FIXED); + FireRight->Playing=0; + FireRight->Active=0; + } + + FireLeft=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft"); + if (FireLeft==NULL) { + FireLeft=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft",HMSQT_MarineHUD,MHSS_Secondary_Fire,ONE_FIXED); + FireLeft->Playing=0; + FireLeft->Active=0; + } + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + if (LastHand==0) { + if (weaponPtr->PrimaryRoundsRemaining>=65536) { + Start_Delta_Sequence(FireRight,HMSQT_MarineHUD,MHSS_Standard_Fire,-1); + FireRight->Playing=1; + FireRight->Active=1; + } else { + Start_Delta_Sequence(FireRight,HMSQT_MarineHUD,MHSS_Right_Out,-1); + FireRight->Playing=1; + FireRight->Active=1; + } + { + SECTION_DATA *casing; + /* Make a little casing. */ + + casing=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum R Pistol round"); + + if (casing) { + MakePistolCasing(&casing->World_Offset,&casing->SecMat); + } + } + } else { + if (weaponPtr->SecondaryRoundsRemaining>=65536) { + Start_Delta_Sequence(FireLeft,HMSQT_MarineHUD,MHSS_Secondary_Fire,-1); + FireLeft->Playing=1; + FireLeft->Active=1; + } else { + Start_Delta_Sequence(FireLeft,HMSQT_MarineHUD,MHSS_Left_Out,-1); + FireLeft->Playing=1; + FireLeft->Active=1; + } + { + SECTION_DATA *casing; + /* Make a little casing. */ + + casing=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum L Pistol round"); + + if (casing) { + MakePistolCasing(&casing->World_Offset,&casing->SecMat); + } + } + } + + /* Start Crossover sequence too. */ + + if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Tertiary_Fire) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Tertiary_Fire,-1,0); + } + } +} + +int AreTwoPistolsInTertiaryFire(void) { + + PLAYER_WEAPON_DATA *weaponPtr; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + + if (PlayersWeaponHModelController.Sub_Sequence!=MHSS_Tertiary_Fire) { + if ((weaponPtr->WeaponIDNumber==WEAPON_MARINE_PISTOL) + &&((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)||(weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY)) + ) { + /* This to trap single player's reflection. */ + return(1); + } else { + return(0); + } + } else { + return(1); + } + +} + +int FireMarineTwoPistolsPrimary(PLAYER_WEAPON_DATA *weaponPtr) { + + return(FireMarineTwoPistols(weaponPtr,0)); + +} + +int FireMarineTwoPistolsSecondary(PLAYER_WEAPON_DATA *weaponPtr) { + + return(FireMarineTwoPistols(weaponPtr,1)); + +} + +int FireMarineTwoPistols(PLAYER_WEAPON_DATA *weaponPtr, int secondary) +{ + TEMPLATE_WEAPON_DATA *twPtr=&TemplateWeapon[weaponPtr->WeaponIDNumber]; + TEMPLATE_AMMO_DATA *templateAmmoPtr = &TemplateAmmo[twPtr->PrimaryAmmoID]; + + DELTA_CONTROLLER *FireRight; + DELTA_CONTROLLER *FireLeft; + + EULER judder; + MATRIXCH juddermat; + + /* Deduce which pistol can fire, if either? */ + + FireRight=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireRight"); + if (FireRight==NULL) { + FireRight=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireRight",HMSQT_MarineHUD,MHSS_Standard_Fire,ONE_FIXED); + FireRight->Playing=0; + FireRight->Active=0; + } + + FireLeft=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft"); + if (FireLeft==NULL) { + FireLeft=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft",HMSQT_MarineHUD,MHSS_Secondary_Fire,ONE_FIXED); + FireLeft->Playing=0; + FireLeft->Active=0; + } + + if (LastHand==0) { + /* Look to the left. */ + if (!DeltaAnimation_IsFinished(FireLeft)) { + /* Left should not be able to fire. */ + return(0); + } + if (weaponPtr->SecondaryRoundsRemaining) { + /* Fire left. */ + LastHand=1; + PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum Flash L"); + weaponPtr->SecondaryRoundsRemaining -= 65536; + } else { + /* Try the other hand... */ + if (!DeltaAnimation_IsFinished(FireRight)) { + /* Right should not be able to fire. */ + return(0); + } + if (weaponPtr->PrimaryRoundsRemaining) { + /* Fire right. */ + LastHand=0; + PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum Flash"); + weaponPtr->PrimaryRoundsRemaining -= 65536; + } + } + } else { + if (!DeltaAnimation_IsFinished(FireRight)) { + /* Right should not be able to fire. */ + return(0); + } + if (weaponPtr->PrimaryRoundsRemaining) { + /* Fire right. */ + LastHand=0; + PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum Flash"); + weaponPtr->PrimaryRoundsRemaining -= 65536; + } else { + /* Try the other hand... */ + if (!DeltaAnimation_IsFinished(FireLeft)) { + /* Left should not be able to fire. */ + return(0); + } + if (weaponPtr->SecondaryRoundsRemaining) { + /* Fire left. */ + LastHand=1; + PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum Flash L"); + weaponPtr->SecondaryRoundsRemaining -= 65536; + } + } + } + + { + /* Force gun judder */ + if (secondary) { + weaponPtr->CurrentState = WEAPONSTATE_FIRING_SECONDARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } else { + weaponPtr->CurrentState = WEAPONSTATE_FIRING_PRIMARY; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + } + CalculatePlayersTarget(twPtr,weaponPtr); + } + + /* does ammo create an actual object? */ + if (templateAmmoPtr->CreatesProjectile) + { + FireProjectileAmmo(twPtr->PrimaryAmmoID); + CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1); + } + else /* instantaneous line of sight */ + { + PlayerFireLineOfSightAmmo(twPtr->PrimaryAmmoID,1); + CurrentGameStats_WeaponFired(PlayerStatusPtr->SelectedWeaponSlot,1); + } + return(1); +} + +void MarineTwoPistols_Fidget(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + DELTA_CONTROLLER *FireRight; + DELTA_CONTROLLER *FireLeft; + + GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD); + + FireRight=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireRight"); + if (FireRight==NULL) { + FireRight=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireRight",HMSQT_MarineHUD,MHSS_Standard_Fire,ONE_FIXED); + FireRight->Playing=0; + FireRight->Active=0; + } + + FireLeft=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft"); + if (FireLeft==NULL) { + FireLeft=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft",HMSQT_MarineHUD,MHSS_Secondary_Fire,ONE_FIXED); + FireLeft->Playing=0; + FireLeft->Active=0; + } + + if (!DeltaAnimation_IsFinished(FireRight)) { + /* Just leave it alone... */ + return; + } + + /* If we're in Tertiary Fire, leave it alone for a moment. */ + if (PlayersWeaponHModelController.Sub_Sequence==MHSS_Tertiary_Fire) { + if (PlayersWeaponHModelController.Tweening!=Controller_NoTweening) { + return; + } + if (weaponPtr->StateTimeOutCounter < (ONE_FIXED>>2)) { + return; + } + } + + if ((PlayersWeaponHModelController.Sub_Sequence!=MHSS_Stationary)&&(PlayersWeaponHModelController.Sub_Sequence!=MHSS_Fidget)) { + if (PlayersWeaponHModelController.Sub_Sequence==MHSS_Tertiary_Fire) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>1),HMSQT_MarineHUD,(int)MHSS_Stationary,-1,0); + } else { + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED); + } + } + + if (weaponPtr->StateTimeOutCounter > ONE_FIXED) { + + if (WeaponFidgetPlaying) { + if (PlayersWeaponHModelController.sequence_timer==(ONE_FIXED-1)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1); + WeaponFidgetPlaying=0; + } + } else if ((FastRandom()&255)==0) { + /* Start animation. */ + if (HModelSequence_Exists(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Fidget)) { + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>2),HMSQT_MarineHUD,(int)MHSS_Fidget,(ONE_FIXED<<1),0); + weaponPtr->StateTimeOutCounter=0; + WeaponFidgetPlaying=1; + } + } + + } + +} + +void MarineTwoPistols_Reload(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + DELTA_CONTROLLER *FireRight; + DELTA_CONTROLLER *FireLeft; + + GLOBALASSERT(PlayersWeaponHModelController.Sequence_Type==HMSQT_MarineHUD); + + FireRight=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireRight"); + if (FireRight==NULL) { + FireRight=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireRight",HMSQT_MarineHUD,MHSS_Standard_Fire,ONE_FIXED); + FireRight->Playing=0; + FireRight->Active=0; + } + + FireLeft=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft"); + if (FireLeft==NULL) { + FireLeft=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft",HMSQT_MarineHUD,MHSS_Secondary_Fire,ONE_FIXED); + FireLeft->Playing=0; + FireLeft->Active=0; + } + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_RELOAD_PRIMARY]); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Standard_Reload,time,0); + PlayersWeaponHModelController.Looped=0; + FireRight->Active=0; + FireLeft->Active=0; + + + /* Pistol infinite ammo hack? */ + if ((AvP.Network != I_No_Network)&&(PISTOL_INFINITE_AMMO)) { + weaponPtr->PrimaryMagazinesRemaining++; + weaponPtr->SecondaryMagazinesRemaining++; + } + + } + StaffAttack=-1; +} + +static void MarineZeroAmmoFunctionality(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr) { + + int weaponNum; + int slot; + + /* Let's cut this into a function. */ + + if (AvP.PlayerType!=I_Marine) { + /* For now. */ + return; + } + + if ((weaponPtr->WeaponIDNumber==WEAPON_GRENADELAUNCHER) + && ( + (GrenadeLauncherData.ProximityRoundsRemaining!=0) + ||(GrenadeLauncherData.FragmentationRoundsRemaining!=0) + ||(GrenadeLauncherData.StandardRoundsRemaining!=0) + ||(GrenadeLauncherData.ProximityMagazinesRemaining!=0) + ||(GrenadeLauncherData.FragmentationMagazinesRemaining!=0) + ||(GrenadeLauncherData.StandardMagazinesRemaining!=0) + ) + ) { + /* Deal with Al's 'grenade launcher change ammo' case... */ + GrenadeLauncher_EmergencyChangeAmmo(weaponPtr); + return; + } + + /* Now the serious bit. */ + + weaponNum=0; + + /* Now, step up until you get to NULL or find a weapon with ammo. */ + //weaponNum--; + while (MarineWeaponHierarchy[weaponNum]!=NULL_WEAPON) { + + slot=SlotForThisWeapon(MarineWeaponHierarchy[weaponNum]); + if (slot!=-1) { + if (playerStatusPtr->WeaponSlot[slot].Possessed==1) { + if (WeaponHasAmmo(slot)) { + /* Okay! */ + break; + } + } + } + weaponNum++; + } + + if (MarineWeaponHierarchy[weaponNum]==NULL_WEAPON) { + /* No possible action. */ + return; + } + if (MarineWeaponHierarchy[weaponNum]==weaponPtr->WeaponIDNumber) { + /* If you found the current weapon, do nothing. */ + return; + } + + /* So, change to this weapon. */ + playerStatusPtr->SwapToWeaponSlot = slot; + weaponPtr->CurrentState = WEAPONSTATE_UNREADYING; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + +} + +void MarinePistol_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + DELTA_CONTROLLER *StockBack; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_OUT]); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Go,time,0); + PlayersWeaponHModelController.Looped=0; + + if (weaponPtr->PrimaryRoundsRemaining==0) { + StockBack=Get_Delta_Sequence(&PlayersWeaponHModelController,"StockBack"); + if (StockBack==NULL) { + StockBack=Add_Delta_Sequence(&PlayersWeaponHModelController,"StockBack",HMSQT_MarineHUD,MHSS_Right_Out,ONE_FIXED); + } + if (StockBack) { + StockBack->Playing=0; + StockBack->timer=65535; + StockBack->lastframe_timer=65535; + } + } + + /* Alter Two Pistols ammo? */ + { + int slot; + + slot=SlotForThisWeapon(WEAPON_TWO_PISTOLS); + if (slot!=-1) { + ((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryRoundsRemaining=weaponPtr->PrimaryRoundsRemaining; + /* Now split the clips between the pistols? */ + + ((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryMagazinesRemaining=(weaponPtr->PrimaryMagazinesRemaining)>>1; + ((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].SecondaryMagazinesRemaining=(weaponPtr->PrimaryMagazinesRemaining)>>1; + if (weaponPtr->PrimaryMagazinesRemaining&1) { + ((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryMagazinesRemaining++; + } + + } + } + } +} + +void MarineTwoPistols_SwapOut(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_OUT]); + time-=(ONE_FIXED>>4); + + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>4),HMSQT_MarineHUD,(int)MHSS_Go,time,0); + PlayersWeaponHModelController.Looped=0; + /* Alter Pistol ammo? */ + { + int slot; + + slot=SlotForThisWeapon(WEAPON_MARINE_PISTOL); + if (slot!=-1) { + if (weaponPtr->PrimaryRoundsRemaining==0) { + ((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryMagazinesRemaining=weaponPtr->PrimaryMagazinesRemaining+weaponPtr->SecondaryMagazinesRemaining; + if (((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryMagazinesRemaining>99) { + ((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryMagazinesRemaining=99; + }; + ((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryRoundsRemaining=weaponPtr->SecondaryRoundsRemaining; + weaponPtr->SecondaryRoundsRemaining=0; + weaponPtr->PrimaryRoundsRemaining=((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryRoundsRemaining; + } else { + ((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryMagazinesRemaining=weaponPtr->PrimaryMagazinesRemaining+weaponPtr->SecondaryMagazinesRemaining; + ((PLAYER_STATUS *)playerStatus)->WeaponSlot[slot].PrimaryRoundsRemaining=weaponPtr->PrimaryRoundsRemaining; + } + } + } + } +} + +void MarinePistol_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + DELTA_CONTROLLER *StockBack; + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + Weapon_ThisBurst=-1; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_IN]); + + GLOBALASSERT(time!=0); + + if (weaponPtr->PrimaryRoundsRemaining==0) { + StockBack=Get_Delta_Sequence(&PlayersWeaponHModelController,"StockBack"); + if (StockBack==NULL) { + StockBack=Add_Delta_Sequence(&PlayersWeaponHModelController,"StockBack",HMSQT_MarineHUD,MHSS_Right_Out,ONE_FIXED); + } + if (StockBack) { + StockBack->Playing=0; + StockBack->timer=65535; + StockBack->lastframe_timer=65535; + StockBack->Active=1; + } + } + + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Come,time); + PlayersWeaponHModelController.Looped=0; + } + + Flamethrower_Timer=0; + StaffAttack=-1; + LastHand=1; +} + +void MarineTwoPistols_SwapIn(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + TEMPLATE_WEAPON_DATA *twPtr; + DELTA_CONTROLLER *FireRight; + DELTA_CONTROLLER *FireLeft; + + FireRight=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireRight"); + if (FireRight==NULL) { + FireRight=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireRight",HMSQT_MarineHUD,MHSS_Standard_Fire,ONE_FIXED); + FireRight->Playing=0; + FireRight->Active=0; + } + + FireLeft=Get_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft"); + if (FireLeft==NULL) { + FireLeft=Add_Delta_Sequence(&PlayersWeaponHModelController,"FireLeft",HMSQT_MarineHUD,MHSS_Secondary_Fire,ONE_FIXED); + FireLeft->Playing=0; + FireLeft->Active=0; + } + + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + Weapon_ThisBurst=-1; + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + int time; + + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_SWAPPING_IN]); + + GLOBALASSERT(time!=0); + + InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Come,time); + PlayersWeaponHModelController.Looped=0; + + if (weaponPtr->PrimaryRoundsRemaining==0) { + Start_Delta_Sequence(FireRight,HMSQT_MarineHUD,MHSS_Right_Out,-1); + FireRight->Playing=0; + FireRight->timer=65535; + FireRight->lastframe_timer=65535; + FireRight->Active=1; + } + + if (weaponPtr->SecondaryRoundsRemaining==0) { + Start_Delta_Sequence(FireLeft,HMSQT_MarineHUD,MHSS_Left_Out,-1); + FireLeft->Playing=0; + FireLeft->timer=65535; + FireLeft->lastframe_timer=65535; + FireLeft->Active=1; + } + + } + + Flamethrower_Timer=0; + StaffAttack=-1; + LastHand=1; +} + +void Frisbee_Recoil(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + + Sound_Stop(weaponHandle); + Sound_Play(SID_ED_SKEETERLAUNCH,"h"); + + //InitHModelSequence(&PlayersWeaponHModelController,HMSQT_MarineHUD,(int)MHSS_Standard_Fire,(ONE_FIXED/6)); + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>6),HMSQT_MarineHUD,(int)MHSS_Standard_Fire,-1,0); + PlayersWeaponHModelController.Looped=0; + FireNonAutomaticWeapon(weaponPtr); + } + +} + +void Frisbee_Firing(void *playerStatus, PLAYER_WEAPON_DATA *weaponPtr) { + + /* Clumsy, but here we go. */ + + AddLightingEffectToObject(Player,LFX_MUZZLEFLASH); + if (weaponPtr->StateTimeOutCounter == WEAPONSTATE_INITIALTIMEOUTCOUNT) { + //InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Stationary,ONE_FIXED,1); + InitHModelTweening(&PlayersWeaponHModelController,(ONE_FIXED>>3),HMSQT_MarineHUD,(int)MHSS_Secondary_Fire,-1,0); + } + +} + +static void PredatorZeroAmmoFunctionality(PLAYER_STATUS *playerStatusPtr,PLAYER_WEAPON_DATA *weaponPtr) { + + int weaponNum; + int slot; + + /* Let's cut this into a function. */ + + if (AvP.PlayerType!=I_Predator) { + /* For now. */ + return; + } + + /* Now the serious bit. */ + + weaponNum=0; + + /* Now, step up until you get to NULL or find a weapon with ammo. */ + //weaponNum--; + while (PredatorWeaponHierarchy[weaponNum]!=NULL_WEAPON) { + + slot=SlotForThisWeapon(PredatorWeaponHierarchy[weaponNum]); + if (slot!=-1) { + if (playerStatusPtr->WeaponSlot[slot].Possessed==1) { + if (Predator_WeaponHasAmmo(playerStatusPtr,slot)) { + /* Okay! */ + break; + } + } + } + weaponNum++; + } + + if (PredatorWeaponHierarchy[weaponNum]==NULL_WEAPON) { + /* No possible action. */ + return; + } + if (PredatorWeaponHierarchy[weaponNum]==weaponPtr->WeaponIDNumber) { + /* If you found the current weapon, do nothing. */ + return; + } + + /* So, change to this weapon. */ + playerStatusPtr->SwapToWeaponSlot = slot; + weaponPtr->CurrentState = WEAPONSTATE_UNREADYING; + weaponPtr->StateTimeOutCounter = WEAPONSTATE_INITIALTIMEOUTCOUNT; + +} diff --git a/3dc/avp/avpitems.cpp b/3dc/avp/avpitems.cpp new file mode 100644 index 0000000..15ad8d8 --- /dev/null +++ b/3dc/avp/avpitems.cpp @@ -0,0 +1,1512 @@ +/******************************************************************* + * + * DESCRIPTION: avpitems.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 30/3/98: AvP-specific menu items + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" + + #include "avpitems.hpp" + + #if UseRebMenus + #include "indexfnt.hpp" + #include "strtab.hpp" + #include "usr_io.h" + #include "db.h" + + #define UseLocalAssert Yes + #include "ourasert.h" + + #ifdef __WATCOMC__ + #pragma warning 139 5 + #pragma message("Disabled Warning W139") + #endif + #endif + + + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ +#if UseRebMenus +namespace RebMenus +{ + namespace TextLabels + { + class Effects + { + private: + static TextID theID[KEYCONFIG_NUMITEMS]; + + public: + static TextID Get( enum KeyConfigItems in ) + { + GLOBALASSERT( in < KEYCONFIG_NUMITEMS ); + + return theID[in]; + } + }; + + class Methods + { + public: + private: + }; + }; +}; // namespace RebMenus +#endif // UseRebMenus + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ +#if UseRebMenus +// static +TextID +RebMenus :: TextLabels :: Effects :: theID[KEYCONFIG_NUMITEMS] = +{ + TEXTSTRING_PCKEY_FORWARD, // KEYCONFIG_FORWARD, + TEXTSTRING_PCKEY_BACKWARD, // KEYCONFIG_BACKWARD, + TEXTSTRING_PCKEY_LEFT, // KEYCONFIG_TURN_LEFT, + TEXTSTRING_PCKEY_RIGHT, // KEYCONFIG_TURN_RIGHT, + TEXTSTRING_PCKEY_STRAFE, // KEYCONFIG_STRAFE, + TEXTSTRING_PCKEY_STRAFE_LEFT, // KEYCONFIG_STRAFE_LEFT, + TEXTSTRING_PCKEY_STRAFE_RIGHT, // KEYCONFIG_STRAFE_RIGHT, + TEXTSTRING_PCKEY_LOOK_UP, // KEYCONFIG_LOOK_UP, + TEXTSTRING_PCKEY_LOOK_DOWN, // KEYCONFIG_LOOK_DOWN, + TEXTSTRING_PCKEY_CENTRE_VIEW, // KEYCONFIG_CENTRE_VIEW, + TEXTSTRING_PCKEY_WALK, // KEYCONFIG_WALK, + TEXTSTRING_PCKEY_CROUCH, // KEYCONFIG_CROUCH, + TEXTSTRING_PCKEY_JUMP, // KEYCONFIG_JUMP, + TEXTSTRING_PCKEY_OPERATE, // KEYCONFIG_OPERATE, + TEXTSTRING_PCKEY_CHANGE_VISION, // KEYCONFIG_VISION, + TEXTSTRING_PCKEY_NEXT_WEAPON, // KEYCONFIG_NEXT_WEAPON, + TEXTSTRING_PCKEY_PREVIOUS_WEAPON, // KEYCONFIG_PREVIOUS_WEAPON, + TEXTSTRING_PCKEY_FIRE_PRIMARY, // KEYCONFIG_FIRE_PRIMARY, + TEXTSTRING_PCKEY_FIRE_SECONDARY // KEYCONFIG_FIRE_SECONDARY, +}; +#endif + +/* Exported function definitions ***********************************/ +#if UseRebMenus +/////////////////////////////////////////////////////////////////////////////// +// Project-specific item types: /////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +// class Item_NetworkStatus : public Item +// Process various keypresses: +OurBool +RebMenus :: Item_NetworkStatus :: Navigate +( + enum NavigationOp // aNavOp +) +{ + // return = was message processed + + return No; +} + +void +RebMenus :: Item_NetworkStatus :: Diagnostic +( + OurBool // bSelected +) const +{ +} + + +// Methods relating to rendering: +void +RebMenus :: Item_NetworkStatus :: Render +( + const RenderContext& theContext, + OurBool // bSelected +) const +{ + #if 0 + textprintXY + ( + theContext . Pos() . x, + theContext . Pos() . y, + "Item_NetworkStatus" + ); + #endif + + IndexedFont* pFont = IndexedFont :: GetFont + ( + Fonts :: GetIndex + ( + Yes // OurBool bSelected + ) + ); + GLOBALASSERT(pFont); + + r2pos R2Pos_StartOfRow = theContext . Pos(); + + // Title row: + { + // Column title: player name + { + r2pos R2Pos_Where = R2Pos_StartOfRow; + SCString* pSCString_Name = new SCString("NAME"); + + pFont -> RenderString_Clipped + ( + R2Pos_Where, // struct r2pos& R2Pos_Cursor, + theContext . ClipRect(), // const struct r2rect& R2Rect_Clip, + (ONE_FIXED-1), // int FixP_Alpha, + *pSCString_Name // const SCString& SCStr + ); + + pSCString_Name -> R_Release(); + } + + // Column title: player species + { + r2pos R2Pos_Where = theContext . Pos_Column1(); + + SCString* pSCString_Name = new SCString("SPECIES"); + + pFont -> RenderString_Clipped + ( + R2Pos_Where, // struct r2pos& R2Pos_Cursor, + theContext . ClipRect(), // const struct r2rect& R2Rect_Clip, + (ONE_FIXED-1), // int FixP_Alpha, + *pSCString_Name // const SCString& SCStr + ); + + pSCString_Name -> R_Release(); + } + + R2Pos_StartOfRow . y += pFont -> GetHeight(); + } + + for (int i=0;i RenderString_Clipped + ( + R2Pos_Where, // struct r2pos& R2Pos_Cursor, + theContext . ClipRect(), // const struct r2rect& R2Rect_Clip, + (ONE_FIXED-1), // int FixP_Alpha, + *pSCString_Name // const SCString& SCStr + ); + + pSCString_Name -> R_Release(); + } + + // Species: + { + r2pos R2Pos_Where = R2Pos_StartOfRow; + R2Pos_Where . x += theContext . Column0_W(); + + SCString* pSCString_Species = &StringTable :: GetSCString + ( + GetTextIDForCharacterType(slotPlayerData . characterType) + ); + + pFont -> RenderString_Clipped + ( + R2Pos_Where, // struct r2pos& R2Pos_Cursor, + theContext . ClipRect(), // const struct r2rect& R2Rect_Clip, + (ONE_FIXED-1), // int FixP_Alpha, + *pSCString_Species // const SCString& SCStr + ); + + pSCString_Species -> R_Release(); + } + + // Ready to start "Ok" text: + if ( slotPlayerData . startFlag ) + { + r2pos R2Pos_Where = R2Pos_StartOfRow; + R2Pos_Where . x += theContext . Column0_W() + 150; + // hardcoded size + + SCString* pSCString_Ok = &StringTable :: GetSCString + ( + TEXTSTRING_MULTI_OK + ); + + pFont -> RenderString_Clipped + ( + R2Pos_Where, // struct r2pos& R2Pos_Cursor, + theContext . ClipRect(), // const struct r2rect& R2Rect_Clip, + (ONE_FIXED-1), // int FixP_Alpha, + *pSCString_Ok // const SCString& SCStr + ); + } + } + else + { + // Empty slot: + r2pos R2Pos_Where = R2Pos_StartOfRow; + + SCString* pSCString_EmptySlot = new SCString("--------"); + // LOCALISEME() + + pFont -> RenderString_Clipped + ( + R2Pos_Where, // struct r2pos& R2Pos_Cursor, + theContext . ClipRect(), // const struct r2rect& R2Rect_Clip, + (ONE_FIXED-1), // int FixP_Alpha, + *pSCString_EmptySlot // const SCString& SCStr + ); + + pSCString_EmptySlot -> R_Release(); + } + + R2Pos_StartOfRow . y += pFont -> GetHeight(); + } + +} + +RebMenus :: SizeInfo +RebMenus :: Item_NetworkStatus :: GetSizeInfo(void) const +{ + IndexedFont* pFont = IndexedFont :: GetFont + ( + Fonts :: GetIndex + ( + Yes // OurBool bSelected + ) + ); + GLOBALASSERT(pFont); + + int WidthPlayerName = + ( + ( + (NET_PLAYERNAMELENGTH ) + * + ( pFont -> GetMaxWidth() ) + ) + +5 // add a little spacing + ); + + int WidthSpecies = 80; + // for now + + r2size R2Size_PlayerNames + ( + // Width: + (WidthPlayerName + WidthSpecies), + + // Height: + ( + ( NET_MAXPLAYERS + 1 ) + // + 1 to allow for title row + * + ( pFont -> GetHeight() ) + ) + ); + + return SizeInfo + ( + R2Size_PlayerNames, + WidthPlayerName + ); +} + +// static +TextID +RebMenus :: Item_NetworkStatus :: GetTextIDForCharacterType +( + NETGAME_CHARACTERTYPE characterType +) +{ + switch(characterType) + { + default: GLOBALASSERT(0); // then fall through + case(NGCT_Marine): + { + return TEXTSTRING_MULTI_MARINE; + } + case(NGCT_Predator): + { + return TEXTSTRING_MULTI_PREDATOR; + } + case(NGCT_Alien): + { + return TEXTSTRING_MULTI_ALIEN; + } + } +} + + +#if 0 +typedef struct netgame_playerdata +{ + DPID playerId; + char name[NET_PLAYERNAMELENGTH]; + NETGAME_CHARACTERTYPE characterType; + int scores[NET_MAXPLAYERS]; + unsigned char startFlag; +}NETGAME_PLAYERDATA; + +typedef struct netgame_gamedata +{ + NETGAME_STATES myGameState; + NETGAME_CHARACTERTYPE myCharacterType; + unsigned char myStartFlag; + NETGAME_PLAYERDATA playerData[NET_MAXPLAYERS]; + int teamScores[NET_MAXTEAMS]; + NETGAME_TYPE gameType; + unsigned char levelNumber; + unsigned int scoreLimit; + unsigned char timeLimit; + int GameTimeElapsed; +}NETGAME_GAMEDATA; +#endif + + +#if 0 +#endif + +#if 0 + case(MMSelect_Start): + { + netGameData.myStartFlag=1; + if(AvP.Network==I_Host) + { + int myIndex; + myIndex = PlayerIdInPlayerList(AVPDPNetID); + LOCALASSERT(myIndex!=NET_IDNOTINPLAYERLIST); + netGameData.playerData[myIndex].startFlag = 1; + } + break; + } +#endif + + + +// class Item_NetworkErrorView : public Item +RebMenus :: Item_NetworkErrorView :: Item_NetworkErrorView +( +) : Item + ( + OnOffAppearance() + ) +{ +} + +RebMenus :: Item_NetworkErrorView :: ~Item_NetworkErrorView() +{ +} + +// Process various keypresses: +OurBool +RebMenus :: Item_NetworkErrorView :: Navigate +( + enum NavigationOp // aNavOp +) +{ + // return = was message processed + return No; +} + +void +RebMenus :: Item_NetworkErrorView :: Diagnostic +( + OurBool // bSelected +) const +{ + textprint("Item_NetworkErrorView :: Diagnostic()\n"); +} + + +// Methods relating to rendering: +void +RebMenus :: Item_NetworkErrorView :: Render +( + const RenderContext& theContext, + OurBool // bSelected +) const +{ + SCString* pSCString_Error = GetStringForCurrentNetworkError(); + + #if 0 + textprintXY + ( + theContext . Pos() . x, + theContext . Pos() . y, + "Item_NetworkErrorView:%s", + pSCString_Error -> pProjCh() + ); + #endif + + IndexedFont* pFont = IndexedFont :: GetFont + ( + Fonts :: GetIndex + ( + Yes // OurBool bSelected + ) + ); + GLOBALASSERT(pFont); + + r2pos R2Pos_Where = theContext . Pos(); + + pFont -> RenderString_Clipped + ( + R2Pos_Where, // struct r2pos& R2Pos_Cursor, + theContext . ClipRect(), // const struct r2rect& R2Rect_Clip, + (ONE_FIXED-1), // int FixP_Alpha, + *pSCString_Error // const SCString& SCStr + ); + + pSCString_Error -> R_Release(); +} + +RebMenus :: SizeInfo +RebMenus :: Item_NetworkErrorView :: GetSizeInfo(void) const +{ + SCString* pSCString_Error = GetStringForCurrentNetworkError(); + + SizeInfo theSizeInfo + ( + pSCString_Error -> CalcSize + ( + Fonts::GetIndex + ( + Yes // OurBool bSelected + ) + ), + 0 + ); + + pSCString_Error -> R_Release(); + + return theSizeInfo; +} + +// private: +// static +SCString* +RebMenus :: Item_NetworkErrorView :: GetStringForCurrentNetworkError(void) +{ + return &StringTable :: GetSCString + ( + GetTextIDForCurrentNetworkError() + ); +} + +// static +TextID +RebMenus :: Item_NetworkErrorView :: GetTextIDForCurrentNetworkError(void) +{ + switch(netGameData.myGameState) + { + default: LOCALASSERT(1==0); + case(NGS_Error_GameFull): + { + return TEXTSTRING_MULTI_GAMEFULL; + } + case(NGS_Error_GameStarted): + { + return TEXTSTRING_MULTI_ALREADYSTARTED; + } + case(NGS_Error_HostLost): + { + return TEXTSTRING_MULTI_CONNECTIONLOST; + } + } +} + +// class Item_VideoModeSelector : public Item +// public: +RebMenus :: Item_VideoModeSelector :: Item_VideoModeSelector +( + OnOffAppearance theOnOffApp_New +) : Item + ( + theOnOffApp_New + ) +{ +} + +// Process various keypresses: +OurBool +RebMenus :: Item_VideoModeSelector :: Navigate( enum NavigationOp aNavOp ) +{ + // return = was message processed + switch (aNavOp) + { + case NavOp_Left: + Dec(); + return Yes; + + case NavOp_Right: + case NavOp_Trigger: + Inc(); + return Yes; + } + return No; +} + +void +RebMenus :: Item_VideoModeSelector :: Diagnostic(OurBool bSelected) const +{ +} + +void +RebMenus :: Item_VideoModeSelector :: Render +( + const RenderContext& theContext, + OurBool bSelected +) const +{ + RenderAppearance + ( + theContext, + bSelected + ); + + RenderContext valueContext = theContext . NextColumn(); + + IndexedFont* pFont = IndexedFont :: GetFont + ( + Fonts :: GetIndex + ( + bSelected + ) + ); + GLOBALASSERT( pFont ); + + r2pos R2Pos_Cursor = valueContext . Pos(); + + SCString* pSCString_Value = VideoModeSelection :: DescribeCurrentSelection(); + GLOBALASSERT(pSCString_Value); + + pFont -> RenderString_Clipped + ( + R2Pos_Cursor, + valueContext . ClipRect(), + Label_FixP_Alpha, + *pSCString_Value + ); + + pSCString_Value -> R_Release(); + +} + +RebMenus :: SizeInfo +RebMenus :: Item_VideoModeSelector :: GetSizeInfo(void) const +{ + return AppearanceSizeInfo() . AddColumn + ( + SizeInfo + ( + r2size + ( + 150, + 21 + ), + 0 + ) + ); +} + +void +RebMenus :: Item_VideoModeSelector :: Dec(void) +{ + VideoModeSelection :: Dec(); +} + +void +RebMenus :: Item_VideoModeSelector :: Inc(void) +{ + VideoModeSelection :: Inc(); +} + +// class Item_KeyConfig_PageView : public Item +// public: +RebMenus :: Item_KeyConfig_PageView :: Item_KeyConfig_PageView +( + OnOffAppearance theOnOffApp_New, + int NumEffectsPerPage_New +) : Item + ( + theOnOffApp_New + ), + bDebounced(No), + NumEffectsPerPage_Val(NumEffectsPerPage_New), + NumPages_Val + ( + // total num effects divided by num effects per page, + // using an old trick to round up: + (KEYCONFIG_NUMITEMS + (NumEffectsPerPage_New-1))/ NumEffectsPerPage_New + ), + CurrentPage_Val(0) +{ + GLOBALASSERT( pSingleton == NULL ); + pSingleton = this; +} + +RebMenus :: Item_KeyConfig_PageView :: ~Item_KeyConfig_PageView() +{ + if (this == pActive) + { + pActive = NULL; + } + + GLOBALASSERT( pSingleton == this ); + pSingleton = NULL; +} + + +// Process various keypresses: +OurBool +RebMenus :: Item_KeyConfig_PageView :: Navigate( enum NavigationOp aNavOp ) +{ + GLOBALASSERT( NULL == pActive ); + + // return = was message processed + switch (aNavOp) + { + case NavOp_Up: + if (SelectionY>0) + { + SelectionY--; + return Yes; + } + else + { + return No; + } + case NavOp_Down: + if (SelectionY< GetFinalYForPage(CurrentPage_Val)) + { + SelectionY++; + return Yes; + } + else + { + return No; + } + case NavOp_Left: + case NavOp_Right: + SelectionX = 1 - SelectionX; + return Yes; + + case NavOp_Home: + SelectionY = 0; + return Yes; + + case NavOp_End: + SelectionY = GetFinalYForPage(CurrentPage_Val); + return Yes; + + case NavOp_Trigger: + // Expect input: + pActive = this; + return Yes; + + case NavOp_Cancel: + return No; + + default: GLOBALASSERT(0); + } + return No; +} + +void +RebMenus :: Item_KeyConfig_PageView :: Diagnostic(OurBool bSelected) const +{ + textprint("Item_KeyConfig_PageView :: Diagnostic():"); + + DiagnosticAppearance(bSelected); + + for (int i=0;i RenderString_Clipped + ( + R2Pos_Cursor, + theContext . ClipRect(), + Label_FixP_Alpha, + theSCString_EffectLabel + ); + + } + + // Primary method: + if + ( + ! + ( + ExpectingKey() + && + bSelected + && + (SelectionX==0) + && + (SelectionY==viewRow) + ) + + ) + { + SCString* pSCString_Method0 = GetMethodString + ( + pPrimary -> GetMethod(theEffect) + ); + + r2pos R2Pos_Cursor = R2Pos_I; + R2Pos_Cursor .x += theContext . Column0_W(); + + #if 0 + if (bSelected && (SelectionY == viewRow) && (SelectionX==0)) + { + textprintXY + ( + R2Pos_Cursor . x -20, + R2Pos_Cursor . y, + "*" + ); + } + #endif + + ( + bSelectedY && (SelectionX==0) + ? + pFont_Selected + : + pFont_Unselected + ) -> RenderString_Clipped + ( + R2Pos_Cursor, + theContext . ClipRect(), + Label_FixP_Alpha, + *pSCString_Method0 + ); + + pSCString_Method0 -> R_Release(); + } + + // Secondary method: + if + ( + ! + ( + ExpectingKey() + && + bSelected + && + (SelectionX==1) + && + (SelectionY==viewRow) + ) + ) + { + SCString* pSCString_Method1 = GetMethodString + ( + pSecondary -> GetMethod(theEffect) + ); + + r2pos R2Pos_Cursor = R2Pos_I; + R2Pos_Cursor .x += theContext . Column0_W() + 110; + + #if 0 + if (bSelected && (SelectionY == viewRow) && (SelectionX==1)) + { + textprintXY + ( + R2Pos_Cursor . x -20, + R2Pos_Cursor . y, + "*" + ); + } + #endif + + ( + bSelectedY && (SelectionX==1) + ? + pFont_Selected + : + pFont_Unselected + ) -> RenderString_Clipped + ( + R2Pos_Cursor, + theContext . ClipRect(), + Label_FixP_Alpha, + *pSCString_Method1 + ); + + pSCString_Method1 -> R_Release(); + } + + + R2Pos_I . y += theSCString_EffectLabel . CalcSize + ( + Fonts :: GetIndex + ( + bSelected + ) + ) . h; + + theSCString_EffectLabel . R_Release(); + } + } +} + +RebMenus :: SizeInfo +RebMenus :: Item_KeyConfig_PageView :: GetSizeInfo(void) const +{ + SizeInfo thisSizeInfo = AppearanceSizeInfo(); + + // Calc size as if all items were present: + for (int i=0;i=0); + GLOBALASSERT( SelectionY < KEYCONFIG_NUMITEMS ); + + + enum KeyConfigItems theEffect; + OurBool bGotEffect = GetEffectForRowOnPage + ( + SelectionY, + CurrentPage_Val, + theEffect // enum KeyConfigItems& outEffect + ); + + pConfig -> SetMethod + ( + theEffect, + theMethod + ); + + pActive = NULL; + +} + +void +RebMenus :: Item_KeyConfig_PageView :: NxtPage(void) +{ + if (CurrentPage_Val < (NumPages_Val-1)) + { + CurrentPage_Val++; + } + else + { + CurrentPage_Val=0; + } +} +void +RebMenus :: Item_KeyConfig_PageView :: PrvPage(void) +{ + if (CurrentPage_Val > 0) + { + CurrentPage_Val--; + } + else + { + CurrentPage_Val=(NumPages_Val-1); + } +} + +// static +SCString* +RebMenus :: Item_KeyConfig_PageView :: GetMethodString( unsigned char inPhysicalKey ) +{ + TextID theTextID; + + if + ( + RebMenus :: Item_KeyConfig_PageView :: GetKeyLabel + ( + inPhysicalKey, + theTextID // TextID& outTextID + ) + ) + { + return &StringTable :: GetSCString(theTextID); + } + else + { + ProjChar theProjChar[2]; + + if (inPhysicalKey >= KEY_A && inPhysicalKey <= KEY_Z) + { + theProjChar[0] = ProjChar(int(inPhysicalKey) - KEY_A + 'A'); + } + else if (inPhysicalKey >= KEY_0 && inPhysicalKey <= KEY_9) + { + theProjChar[0] = ProjChar(int(inPhysicalKey) - KEY_0 + '0'); + } + else + { + theProjChar[0] = 0; + } + + theProjChar[1] = 0; + + return new SCString(theProjChar); + } +} + +void +RebMenus :: Item_KeyConfig_PageView :: Selected_Hook +( + enum NavigationOp theNavOp +) +{ + switch (theNavOp) + { + default: GLOBALASSERT(0); + case NavOp_Up: + SelectionY = GetFinalYForPage(CurrentPage_Val); + break; + case NavOp_Down: + SelectionY = 0; + break; + case NavOp_Left: + SelectionX = 1; + break; + case NavOp_Right: + SelectionX = 0; + break; + case NavOp_Home: + SelectionY = 0; + break; + case NavOp_End: + SelectionY = GetFinalYForPage(CurrentPage_Val); + break; + case NavOp_Trigger: + break; + case NavOp_Cancel: + break; + } +} + + +// private: +// static +TextID +RebMenus :: Item_KeyConfig_PageView :: GetEffectLabel( enum KeyConfigItems inEffect) +{ + // takes an effect (e.g. jump) and returns + // a text label to use + return TextLabels :: Effects :: Get( inEffect ); +} + + +OurBool +RebMenus :: Item_KeyConfig_PageView :: GetKeyLabel +( + int inPhysicalKey, + TextID& outTextID +) +{ + // takes a physical method key and attempts to find a text + // string to use for it, returning whether it does. + // If it fails, output area is untouched + + switch (inPhysicalKey) + { + case KEY_UP: outTextID = TEXTSTRING_KEYS_UP; return Yes; + case KEY_DOWN: outTextID = TEXTSTRING_KEYS_DOWN; return Yes; + case KEY_LEFT: outTextID = TEXTSTRING_KEYS_LEFT; return Yes; + case KEY_RIGHT: outTextID = TEXTSTRING_KEYS_RIGHT; return Yes; + case KEY_CR: outTextID = TEXTSTRING_KEYS_RETURN; return Yes; + case KEY_TAB: outTextID = TEXTSTRING_KEYS_TAB; return Yes; + case KEY_INS: outTextID = TEXTSTRING_KEYS_INSERT; return Yes; + case KEY_DEL: outTextID = TEXTSTRING_KEYS_DELETE; return Yes; + case KEY_END: outTextID = TEXTSTRING_KEYS_END; return Yes; + case KEY_HOME: outTextID = TEXTSTRING_KEYS_HOME; return Yes; + case KEY_PAGEUP: outTextID = TEXTSTRING_KEYS_PGUP; return Yes; + case KEY_PAGEDOWN: outTextID = TEXTSTRING_KEYS_PGDOWN; return Yes; + case KEY_BACKSPACE: outTextID = TEXTSTRING_KEYS_BACKSP; return Yes; + case KEY_COMMA: outTextID = TEXTSTRING_KEYS_COMMA; return Yes; + case KEY_FSTOP: outTextID = TEXTSTRING_KEYS_PERIOD; return Yes; + case KEY_SPACE: outTextID = TEXTSTRING_KEYS_SPACE; return Yes; + case KEY_LMOUSE: outTextID = TEXTSTRING_KEYS_LMOUSE; return Yes; + case KEY_RMOUSE: outTextID = TEXTSTRING_KEYS_RMOUSE; return Yes; + case KEY_LEFTALT: outTextID = TEXTSTRING_KEYS_LALT; return Yes; + case KEY_RIGHTALT: outTextID = TEXTSTRING_KEYS_RALT; return Yes; + case KEY_LEFTCTRL: outTextID = TEXTSTRING_KEYS_LCTRL; return Yes; + case KEY_RIGHTCTRL: outTextID = TEXTSTRING_KEYS_RCTRL; return Yes; + case KEY_LEFTSHIFT: outTextID = TEXTSTRING_KEYS_LSHIFT; return Yes; + case KEY_RIGHTSHIFT: outTextID = TEXTSTRING_KEYS_RSHIFT; return Yes; + case KEY_CAPS: outTextID = TEXTSTRING_KEYS_CAPS; return Yes; + case KEY_NUMLOCK: outTextID = TEXTSTRING_KEYS_NUMLOCK; return Yes; + case KEY_SCROLLOK: outTextID = TEXTSTRING_KEYS_SCRLOCK; return Yes; + case KEY_NUMPAD0: outTextID = TEXTSTRING_KEYS_PAD0; return Yes; + case KEY_NUMPAD1: outTextID = TEXTSTRING_KEYS_PAD1; return Yes; + case KEY_NUMPAD2: outTextID = TEXTSTRING_KEYS_PAD2; return Yes; + case KEY_NUMPAD3: outTextID = TEXTSTRING_KEYS_PAD3; return Yes; + case KEY_NUMPAD4: outTextID = TEXTSTRING_KEYS_PAD4; return Yes; + case KEY_NUMPAD5: outTextID = TEXTSTRING_KEYS_PAD5; return Yes; + case KEY_NUMPAD6: outTextID = TEXTSTRING_KEYS_PAD6; return Yes; + case KEY_NUMPAD7: outTextID = TEXTSTRING_KEYS_PAD7; return Yes; + case KEY_NUMPAD8: outTextID = TEXTSTRING_KEYS_PAD8; return Yes; + case KEY_NUMPAD9: outTextID = TEXTSTRING_KEYS_PAD9; return Yes; + case KEY_NUMPADSUB: outTextID = TEXTSTRING_KEYS_PADSUB; return Yes; + case KEY_NUMPADADD: outTextID = TEXTSTRING_KEYS_PADADD; return Yes; + case KEY_NUMPADDEL: outTextID = TEXTSTRING_KEYS_PADDEL; return Yes; + default: return No; + } +} + +OurBool +RebMenus :: Item_KeyConfig_PageView :: GetEffectForRowOnPage +( + int inY, + int inPage, + enum KeyConfigItems& outEffect +) const + // returns truth if it can output a valid effect into the specified area +{ + GLOBALASSERT(inY>=0); + GLOBALASSERT(inY=0); + GLOBALASSERT(inPage= 0); + GLOBALASSERT( inPage < NumPages_Val ); + + if (inPage<(NumPages_Val-1)) + { + // If not the final page, it has all the rows: + return (NumEffectsPerPage_Val-1); + } + else + { + // The final page has only got the rows that remain after dealing + // with all the other pages: + int ReturnVal = + ( + (KEYCONFIG_NUMITEMS-1) - (NumEffectsPerPage_Val*inPage) + ); + + GLOBALASSERT( ReturnVal >=0 ); + GLOBALASSERT( ReturnVal < NumEffectsPerPage_Val ); + + return ReturnVal; + } +} + + +// static +RebMenus :: Item_KeyConfig_PageView* +RebMenus :: Item_KeyConfig_PageView :: pActive = NULL; + +// static +RebMenus :: Item_KeyConfig_PageView* +RebMenus :: Item_KeyConfig_PageView :: pSingleton = NULL; + + + + +unsigned char +player_input_configuration :: GetMethod( enum KeyConfigItems theEffect ) const +{ + switch (theEffect) + { + case KEYCONFIG_FORWARD: + return Forward; + case KEYCONFIG_BACKWARD: + return Backward; + case KEYCONFIG_TURN_LEFT: + return Left; + case KEYCONFIG_TURN_RIGHT: + return Right; + case KEYCONFIG_STRAFE: + return Strafe; + case KEYCONFIG_STRAFE_LEFT: + return StrafeLeft; + case KEYCONFIG_STRAFE_RIGHT: + return StrafeRight; + case KEYCONFIG_LOOK_UP: + return LookUp; + case KEYCONFIG_LOOK_DOWN: + return LookDown; + case KEYCONFIG_CENTRE_VIEW: + return CentreView; + case KEYCONFIG_WALK: + return Walk; + case KEYCONFIG_CROUCH: + return Crouch; + case KEYCONFIG_JUMP: + return Jump; + case KEYCONFIG_OPERATE: + return Operate; + case KEYCONFIG_VISION: + return ChangeVision; + case KEYCONFIG_NEXT_WEAPON: + return NextWeapon; + case KEYCONFIG_PREVIOUS_WEAPON: + return PreviousWeapon; + case KEYCONFIG_FIRE_PRIMARY: + return FirePrimaryWeapon; + case KEYCONFIG_FIRE_SECONDARY: + return FireSecondaryWeapon; + default: GLOBALASSERT(0); + return 0; + } +} + +void +player_input_configuration :: SetMethod +( + enum KeyConfigItems theEffect, + unsigned char newMethod +) +{ + switch (theEffect) + { + case KEYCONFIG_FORWARD: + Forward = newMethod; + break; + case KEYCONFIG_BACKWARD: + Backward = newMethod; + break; + case KEYCONFIG_TURN_LEFT: + Left = newMethod; + break; + case KEYCONFIG_TURN_RIGHT: + Right = newMethod; + break; + case KEYCONFIG_STRAFE: + Strafe = newMethod; + break; + case KEYCONFIG_STRAFE_LEFT: + StrafeLeft = newMethod; + break; + case KEYCONFIG_STRAFE_RIGHT: + StrafeRight = newMethod; + break; + case KEYCONFIG_LOOK_UP: + LookUp = newMethod; + break; + case KEYCONFIG_LOOK_DOWN: + LookDown = newMethod; + break; + case KEYCONFIG_CENTRE_VIEW: + CentreView = newMethod; + break; + case KEYCONFIG_WALK: + Walk = newMethod; + break; + case KEYCONFIG_CROUCH: + Crouch = newMethod; + break; + case KEYCONFIG_JUMP: + Jump = newMethod; + break; + case KEYCONFIG_OPERATE: + Operate = newMethod; + break; + case KEYCONFIG_VISION: + ChangeVision = newMethod; + break; + case KEYCONFIG_NEXT_WEAPON: + NextWeapon = newMethod; + break; + case KEYCONFIG_PREVIOUS_WEAPON: + PreviousWeapon = newMethod; + break; + case KEYCONFIG_FIRE_PRIMARY: + FirePrimaryWeapon = newMethod; + break; + case KEYCONFIG_FIRE_SECONDARY: + FireSecondaryWeapon = newMethod; + break; + default: GLOBALASSERT(0); + } +} + +#if 0 +// class Item_KeyConfig_Selector : public CompositeItem +// public: +RebMenus :: Item_KeyConfig_Selector :: Item_KeyConfig_Selector +( + OnOffAppearance theOnOffApp_New +) : CompositeItem + ( + theOnOffApp_New, // OnOffAppearance theOnOffApp_New, + D_Vert, // enum Direction theD, + Align_Centre // enum Alignment theAlignment_New + ) +{ + { + Command* pCommand = new Command_KeyConfig_PrvPage(); + AddNewCommandItem + ( + OnOffAppearance(TEXTSTRING_PSXCOMPUTER_PREVIOUS), + pCommand + ); + pCommand -> R_Release(); + } + { + Command* pCommand = new Command_KeyConfig_NxtPage(); + AddNewCommandItem + ( + OnOffAppearance(TEXTSTRING_PSXCOMPUTER_NEXT), + pCommand + ); + pCommand -> R_Release(); + } + // ...revise these text strings at some point +} +// private: +#endif + + +#endif + // UseRebMenus + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/avpitems.hpp b/3dc/avp/avpitems.hpp new file mode 100644 index 0000000..d5ea4d0 --- /dev/null +++ b/3dc/avp/avpitems.hpp @@ -0,0 +1,297 @@ +/* + + avpitems.hpp + + AvP-specific menu items + +*/ + +#ifndef _avpitems +#define _avpitems 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + + #ifndef _rebmenus_hpp + #include "rebmenus.hpp" + #endif + + #if UseRebMenus + #ifndef _scstring + #include "scstring.hpp" + #endif + + #include "pcmenus.h" + + #ifndef pldnet_h_included + #include "stratdef.h" + #include "equipmnt.h" + // needed to include pldnet.h + + #include "pldnet.h" + #endif + #endif // RebMenus + + +#ifdef __cplusplus +/////////////////////////////////////////////////////////////////////////////// +// Project-specific item types: /////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +// Additions to the RebMenus namespace: AvP specific item types: +namespace RebMenus +{ + class Item_NetworkStatus : public Item + { + public: + Item_NetworkStatus + ( + OnOffAppearance theOnOffApp_New + ) : Item + ( + theOnOffApp_New + ) + { + } + ~Item_NetworkStatus() + { + } + + // Process various keypresses: + OurBool Navigate( enum NavigationOp aNavOp ); + // return = was message processed + + void Diagnostic(OurBool bSelected) const; + + + // Methods relating to rendering: + void Render + ( + const RenderContext& theContext, + OurBool bSelected + ) const; + + SizeInfo GetSizeInfo(void) const; + + static TextID GetTextIDForCharacterType + ( + NETGAME_CHARACTERTYPE characterType + ); + }; + + class Item_NetworkErrorView : public Item + { + public: + Item_NetworkErrorView(); + ~Item_NetworkErrorView(); + + // Process various keypresses: + OurBool Navigate( enum NavigationOp aNavOp ); + // return = was message processed + + void Diagnostic(OurBool bSelected) const; + + + // Methods relating to rendering: + void Render + ( + const RenderContext& theContext, + OurBool bSelected + ) const; + + SizeInfo GetSizeInfo(void) const; + + private: + static SCString* GetStringForCurrentNetworkError(void); + static TextID GetTextIDForCurrentNetworkError(void); + }; + + class Item_VideoModeSelector : public Item + { + public: + Item_VideoModeSelector + ( + OnOffAppearance theOnOffApp_New + ); + + // Process various keypresses: + OurBool Navigate( enum NavigationOp aNavOp ); + // return = was message processed + + void Diagnostic(OurBool bSelected) const; + + void Render + ( + const RenderContext& theContext, + OurBool bSelected + ) const; + + SizeInfo GetSizeInfo(void) const; + + void Dec(void); + void Inc(void); + + }; + + + class Item_KeyConfig_PageView : public Item + { + // DHM 16/3/98: I make a distinction between "methods" and "effects": + // a "method" is something you use to request an "effect" + // For example you might use the "method" of the space key to request + // the effect "jump". + + public: + Item_KeyConfig_PageView + ( + OnOffAppearance theOnOffApp_New, + int NumEffectsPerPage_New + ); + ~Item_KeyConfig_PageView(); + + // Process various keypresses: + OurBool Navigate( enum NavigationOp aNavOp ); + // return = was message processed + + void Diagnostic(OurBool bSelected) const; + + + // Methods relating to rendering: + void Render + ( + const RenderContext& theContext, + OurBool bSelected + ) const; + + SizeInfo GetSizeInfo(void) const; + + void SetMethod(unsigned char theMethod); + + static OurBool ExpectingKey(void) + { + // if this is set, then this class takes over input handling + return (pActive != NULL); + } + + static void Maintain(void); + + int GetPage(void) const + { + return CurrentPage_Val; + } + int GetNumPages(void) const + { + return NumPages_Val; + } + void NxtPage(void); + void PrvPage(void); + + // It's a singleton class: + static Item_KeyConfig_PageView* Get(void) + { + return pSingleton; + } + + static SCString* GetMethodString( unsigned char inPhysicalKey ); + + public: + void Selected_Hook + ( + enum NavigationOp theNavOp + ); + + + private: + static TextID GetEffectLabel( enum KeyConfigItems ); + // takes an effect (e.g. jump) and returns + // a text label to use + + static OurBool GetKeyLabel + ( + int inPhysicalKey, + TextID& outTextID + ); + // takes a physical method key and attempts to find a text + // string to use for it, returning whether it does. + // If it fails, output area is untouched + + OurBool GetEffectForRowOnPage + ( + int inY, + int inPage, + enum KeyConfigItems& outEffect + ) const; + // returns truth if it can output a valid effect into the specified area + + int GetFinalYForPage + ( + int inPage + ) const; + // Y on this page can range from 0 to this inclusive + + private: + // Selection: only meaningful if the item as a whole is selected + int SelectionX; + // range: [0,1] + + int SelectionY; + // range: [0,NumEffectsPerPage_Val) + + static Item_KeyConfig_PageView* pActive; + // iff this is non-NULL, then there's one of these expecting a key + // to change the ketboard setup; change input handling accordingly + + OurBool bDebounced; + + const int NumEffectsPerPage_Val; + const int NumPages_Val; + + int CurrentPage_Val; + // ranges from [0,NumPages_Val) + + static Item_KeyConfig_PageView* pSingleton; + + }; + + class Item_KeyConfig_Selector : public CompositeItem + { + public: + Item_KeyConfig_Selector + ( + OnOffAppearance theOnOffApp_New + ); + private: + + }; + + // Some simple command classes to embed specific function calls into buttons: + class Command_KeyConfig_PrvPage : public Command + { + public: + OurBool Execute(void) + { + Item_KeyConfig_PageView :: Get() -> PrvPage(); + + return Yes; + } + }; + class Command_KeyConfig_NxtPage : public Command + { + public: + OurBool Execute(void) + { + Item_KeyConfig_PageView :: Get() -> NxtPage(); + + return Yes; + } + }; + +}; + + + +/* End of the header ****************************************************/ +#endif // __cplusplus + + +#endif diff --git a/3dc/avp/avppages.cpp b/3dc/avp/avppages.cpp new file mode 100644 index 0000000..dba174d --- /dev/null +++ b/3dc/avp/avppages.cpp @@ -0,0 +1,1820 @@ +/******************************************************************* + * + * DESCRIPTION: avppages.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 27/3/98 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" + + #include "rebmenus.hpp" + + #if UseRebMenus + #include "avppages.hpp" + #include "avpitems.hpp" + + // Network code includes: + #include "dp_func.h" + + #include "stratdef.h" + #include "equipmnt.h" + // needed to include pldnet.h + + #include "pldnet.h" + + // Control config includes: + #include "usr_io.h" + + #endif // UseRebMenus + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + extern int QuickStartMultiplayer; + #if 0 + + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif + + extern enum TexFmt { D3TF_4BIT, D3TF_8BIT, D3TF_16BIT, D3TF_32BIT, D3TF_MAX } d3d_desired_tex_fmt; + +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +#if UseRebMenus +/////////////////////////////////////////////////////////////////////////////// +// Projects-specific commands: access to the "menu loop": ///////////////////// +/////////////////////////////////////////////////////////////////////////////// + +// class Command_QuitProgram : public Command +OurBool Command_QuitProgram :: Execute(void) +{ + #if OverrideOldMenus + RebMenus :: MenuLoop :: QuitProgram(); + #endif + return Yes; +} +// class Command_StartSoloGame : public Command +OurBool Command_StartSoloGame :: Execute(void) +{ + #if OverrideOldMenus + RebMenus :: MenuLoop :: StartSoloGame + ( + thePlayerType, + theStartingEnv + ); + #endif + return Yes; +} +// class Command_Multiplayer : public Command +OurBool Command_Multiplayer :: Execute(void) +{ + #if OverrideOldMenus + // Can only function outside the game: + if ( !RebMenus :: InGame :: Get()) + { + bTriggerMenuDialog = Yes; + return Yes; + } + else + { + // Merely jump to the multiplayer menu without running dialog: + RebMenus :: Page :: SelectPage(PageID_PlaceholderMultiplayer); + return Yes; + } + #else + return Yes; + #endif +} + +// Only takes effect if the flag's been set (and clears the flag) +// Triggers the multiplayer dialog boxes +#if OverrideOldMenus +// static +OurBool +Command_Multiplayer :: bTriggerMenuDialog = No; + +// static +void +Command_Multiplayer :: EndOfMenuLoopProcessing(void) +{ + // Handle post-processing in the multiplayer menu page + if + ( + ( AvP.Network != I_No_Network ) + && + (netGameData.myGameState == NGS_Joining) + ) + { + // Adapted from code in MULTMENU.C; see pp89-91 of DHM's AvP book + // (taken from RunMultiplayerStartUp() ) + + /* we are still in start-up after processing our user inputs */ + /* ... now do some checks */ + if(AvP.Network==I_Peer) + { + if(PlayerIdInPlayerList(AVPDPNetID)==NET_IDNOTINPLAYERLIST) + { + if(EmptySlotInPlayerList() == NET_NOEMPTYSLOTINPLAYERLIST) + { + /* we are not in the list, and there are no free slots: there is no room */ + TransmitPlayerLeavingNetMsg(); + netGameData.myGameState = NGS_Error_GameFull; + } + } + else + { + if(QuickStartMultiplayer || netGameData.playerData[PlayerIdInPlayerList(AVPDPNetID)].startFlag) + { + netGameData.myGameState = NGS_Playing; + } + } + + } + else + { + /* host checks for peer time-out, and game start */ + LOCALASSERT(AvP.Network==I_Host); + LOCALASSERT(PlayerIdInPlayerList(AVPDPNetID)!=NET_IDNOTINPLAYERLIST); + + if(QuickStartMultiplayer + || netGameData.playerData[PlayerIdInPlayerList(AVPDPNetID)].startFlag) + { + TransmitStartGameNetMsg(); + netGameData.myGameState = NGS_Playing; + } + } + } + + // If network game state has been changed, potentially exit the menus: + { + if ( (AvP.Network!=I_No_Network) && (netGameData.myGameState!=NGS_Joining) ) + { + // Copied/adapted from postprocessing in RunMultiplayerStartUp() + // (see p91 of DHM's AvP book#1) + + /* examine our NGS and decide what to do */ + switch(netGameData.myGameState) + { + case(NGS_Playing): + { + /* everything went ok */ + switch(netGameData.myCharacterType) + { + case(NGCT_Marine): + { + RebMenus :: MenuLoop :: StartNetworkGame + ( + I_Marine, + I_Dml1 + ); + break; + } + case(NGCT_Predator): + { + RebMenus :: MenuLoop :: StartNetworkGame + ( + I_Predator, + I_Dml1 + ); + break; + } + case(NGCT_Alien): + { + RebMenus :: MenuLoop :: StartNetworkGame + ( + I_Alien, + I_Dml1 + ); + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + break; + } + case(NGS_Leaving): + case(NGS_EndGame): + { + EndAVPNetGame(); + RebMenus :: Page :: SelectPage( PageID_Initial ); + break; + } + case(NGS_Error_GameFull): + case(NGS_Error_GameStarted): + case(NGS_Error_HostLost): + { + EndAVPNetGame(); + RebMenus :: Page :: SelectPage( PageID_MultiplayerErrorScreen ); + break; + } + default: + { + LOCALASSERT(1==0); + EndAVPNetGame(); + RebMenus :: Page :: SelectPage( PageID_MultiplayerErrorScreen ); + break; + } + } + + } + } + + + // Possible requests to trigger the multiplayer dialog: + if ( bTriggerMenuDialog ) + { + bTriggerMenuDialog = No; + + // Adapted from code in MULTMENU.C; see pp89-91 of DHM's AvP book + AvP.Network=I_No_Network; + EndAVPNetGame(); + + InvokeDirectPlayDialog(); + + if(ProcessDirectPlayDialog()==0) + { + /* didn't connect */ + EndAVPNetGame(); + return; + } + + + /* we have successfully connected to a game...*/ + InitAVPNetGame(); + + // Jump to page: placeholder multiplayer settings + RebMenus :: Page :: SelectPage(PageID_PlaceholderMultiplayer); + } +} +#endif + // OverrideOldMenus + +// class Command_ExitCurrentGame : public Command +OurBool Command_ExitCurrentGame :: Execute(void) +{ + switch (AvP.Network) + { + default: GLOBALASSERT(0); + case I_No_Network: + break; + + case I_Host: + { + TransmitEndOfGameNetMsg(); + netGameData.myGameState = NGS_EndGame; + } + break; + + case I_Peer: + { + TransmitPlayerLeavingNetMsg(); + netGameData.myGameState = NGS_Leaving; + } + break; + } + + // go to start menu + AvP.MainLoopRunning = 0; + + RebMenus :: Page :: SelectPage_ClearingStack(PageID_Initial); + + return Yes; +} + +class Command_KeyConfig_RestoreDefaults : public Command +{ +public: + OurBool Execute(void) + { + PlayerInputPrimaryConfig = DefaultPlayerInputPrimaryConfig; + PlayerInputSecondaryConfig = DefaultPlayerInputSecondaryConfig; + return Yes; + } +}; +class Command_MouseConfig_RestoreDefaults : public Command +{ +public: + OurBool Execute(void) + { + ControlMethods = DefaultControlMethods; + return Yes; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// Export and selection variables for the menu pages: ///////////////////////// +/////////////////////////////////////////////////////////////////////////////// +namespace RebMenus +{ + // Types of export var for setting up selections that can only be changed + // outside the game loop (bounded and unbounded): + template class ExportVariable_NotInGame : public ExportVariable + { + protected: + ExportVariable_NotInGame + ( + ) : ExportVariable + ( + ) + { + } + + private: + // int Get(void) is left pure virtual + + virtual void OutOfGame_Set( T NewVal ) = 0; + + #if OverrideOldMenus + void Set + ( + T newVal + ) + { + if (RebMenus :: InGame :: Get() ) + { + // Silently reject attempts to set these within the game + return; + } + else + { + OutOfGame_Set( newVal ); + } + } + #else + void Set + ( + T // newVal + ) + { + // ignore; these menus are always in-game only + } + #endif + + private: + + }; + template class BoundedExportVariable_NotInGame : public BoundedExportVariable + { + protected: + BoundedExportVariable_NotInGame + ( + T minVal_New, + T maxVal_New + ) : BoundedExportVariable + ( + minVal_New, + maxVal_New + ) + { + } + + private: + // int Get(void) is left pure virtual + + virtual void OutOfGame_Set( T NewVal ) = 0; + + #if OverrideOldMenus + void Implement_Set + ( + T newVal + ) + { + if (RebMenus :: InGame :: Get() ) + { + // Silently reject attempts to set these within the game + return; + } + else + { + OutOfGame_Set( newVal ); + } + } + #else + void Implement_Set + ( + T // newVal + ) + { + // ignore; these menus are always in-game only + } + #endif + private: + + }; + + + /////////////////////////////////////////////////////////////////////////////// + // Export and selection variables for the network game pages: ///////////////// + /////////////////////////////////////////////////////////////////////////////// + + // A class for handling the "start network game" toggle: + class ExportVariable_StartNetworkGame : public ExportVariable + { + public: + ExportVariable_StartNetworkGame + ( + ) : ExportVariable() + { + } + + OurBool Get(void) const + { + // Better than casting? + if ( netGameData.myStartFlag ) + { + return Yes; + } + else + { + return No; + } + } + void Set(OurBool NewVal) + { + // Copied from logic in MULTMENU.C: + netGameData.myStartFlag = NewVal ? 1 : 0; + + if(AvP.Network==I_Host) + { + // Then we can use this to set the start flag in the entry for + // ourselves in the player list + int myIndex; + myIndex = PlayerIdInPlayerList(AVPDPNetID); + LOCALASSERT(myIndex!=NET_IDNOTINPLAYERLIST); + netGameData.playerData[myIndex].startFlag = 1; + } + } + }; + + class BoundedExportVariable_MultiplayerSpecies : public BoundedExportVariable + { + public: + BoundedExportVariable_MultiplayerSpecies + ( + ) : BoundedExportVariable + ( + NGCT_Marine, // T minVal_New, + NGCT_Alien // T maxVal_New + ) + { + } + + private: + int Get(void) const + { + return netGameData.myCharacterType; + } + void Implement_Set(int newVal) + { + netGameData.myCharacterType = netgame_charactertype(newVal); + + if(AvP.Network==I_Host) + { + int myIndex; + myIndex = PlayerIdInPlayerList(AVPDPNetID); + LOCALASSERT(myIndex!=NET_IDNOTINPLAYERLIST); + netGameData.playerData[myIndex].characterType = netGameData.myCharacterType; + } + } + + private: + }; + + class SelectionVariable_MultiplayerSpecies : public SelectionVariable + { + public: + SelectionVariable_MultiplayerSpecies + ( + ) : SelectionVariable + ( + new BoundedExportVariable_MultiplayerSpecies() + ) + { + } + + Appearance GetAppearance + ( + OurBool // bSelected + ) + { + return Appearance + ( + Item_NetworkStatus :: GetTextIDForCharacterType + ( + netGameData.myCharacterType + ) + ); + } + }; + + class BoundedExportVariable_MultiplayerGameMode : public BoundedExportVariable + { + public: + BoundedExportVariable_MultiplayerGameMode + ( + ) : BoundedExportVariable + ( + NGT_Individual, // T minVal_New, + NGT_Coop // T maxVal_New + ) + { + } + + private: + int Get(void) const + { + return netGameData.gameType; + } + void Implement_Set(int newVal) + { + if(AvP.Network==I_Host) + { + netGameData.gameType = netgame_type(newVal); + } + else + { + // ignore the attempt; it's not the host + } + } + private: + }; + + + class SelectionVariable_MultiplayerGameMode : public SelectionVariable + { + public: + SelectionVariable_MultiplayerGameMode + ( + ) : SelectionVariable + ( + new BoundedExportVariable_MultiplayerGameMode() + ) + { + } + + Appearance GetAppearance + ( + OurBool // bSelected + ) + { + return Appearance + ( + netGameData.gameType ? TEXTSTRING_MULTI_INDIVIDUAL : TEXTSTRING_MULTI_COOP + ); + } + }; + + /////////////////////////////////////////////////////////////////////////////// + // Export and selection variables for the video mode pages: /////////////////// + /////////////////////////////////////////////////////////////////////////////// + + // See PCMENUS.CPP + + class BoundedExportVariable_TextureBitDepth : public BoundedExportVariable_NotInGame + { + public: + BoundedExportVariable_TextureBitDepth + ( + ) : BoundedExportVariable_NotInGame + ( + 0, // T minVal_New, + 3 // T maxVal_New + ) + { + } + + private: + int Get(void) const + { + return d3d_desired_tex_fmt; + } + void OutOfGame_Set(int newVal) + { + d3d_desired_tex_fmt = (TexFmt)newVal; + } + private: + + }; + + class SelectionVariable_TextureBitDepth : public SelectionVariable + { + public: + SelectionVariable_TextureBitDepth + ( + ) : SelectionVariable + ( + new BoundedExportVariable_TextureBitDepth() + ) + { + } + + Appearance GetAppearance + ( + OurBool // bSelected + ) + { + return Appearance + ( + GetTextIDForTextureBitDepth() + ); + } + + TextID GetTextIDForTextureBitDepth(void) + { + switch(d3d_desired_tex_fmt) + { + case D3TF_4BIT: + return TEXTSTRING_PC_TEXTURES_4BIT; + break; + case D3TF_8BIT: + return TEXTSTRING_PC_TEXTURES_8BIT; + break; + case D3TF_16BIT: + return TEXTSTRING_PC_TEXTURES_16BIT; + break; + case D3TF_32BIT: + return TEXTSTRING_PC_TEXTURES_32BIT; + break; + default: + return TEXTSTRING_BLANK; + break; + + } + } + + private: + }; + + /////////////////////////////////////////////////////////////////////////////// + // Export and selection variables for the mouse options page: ///////////////// + /////////////////////////////////////////////////////////////////////////////// + class BoundedExportVariable_MouseSensitivity : public BoundedExportVariable + { + public: + BoundedExportVariable_MouseSensitivity + ( + OurBool bXAxis // else it's the y-axis + ) : bXAxis_Val(bXAxis), + BoundedExportVariable + ( + (bXAxis ? (DEFAULT_MOUSEX_SENSITIVITY-20) : (DEFAULT_MOUSEY_SENSITIVITY-40) ), // T minVal_New, + (bXAxis ? (DEFAULT_MOUSEX_SENSITIVITY+20) : (DEFAULT_MOUSEY_SENSITIVITY+40) ) // T maxVal_New + ) + { + } + + int Get(void) const + { + return + ( + (bXAxis_Val) + ? + ControlMethods.MouseXSensitivity + : + ControlMethods.MouseYSensitivity + ); + } + + private: + void Implement_Set(int NewVal) + { + if (bXAxis_Val) + { + ControlMethods.MouseXSensitivity = NewVal; + } + else + { + ControlMethods.MouseYSensitivity = NewVal; + } + } + + private: + const OurBool bXAxis_Val; + }; + + class ExportVariable_MouseAxisEffect_V : public ExportVariable + { + public: + ExportVariable_MouseAxisEffect_V + ( + ) : ExportVariable () + { + } + + OurBool Get(void) const + { + return ControlMethods.VAxisIsMovement; + } + void Set(OurBool NewVal) + { + ControlMethods.VAxisIsMovement = NewVal; + } + }; + class ExportVariable_MouseAxisEffect_H : public ExportVariable + { + public: + ExportVariable_MouseAxisEffect_H + ( + ) : ExportVariable () + { + } + + OurBool Get(void) const + { + return ControlMethods.HAxisIsTurning; + } + void Set(OurBool NewVal) + { + ControlMethods.HAxisIsTurning = NewVal; + } + }; + class ExportVariable_Mouse_FlipVertical : public ExportVariable + { + public: + ExportVariable_Mouse_FlipVertical + ( + ) : ExportVariable () + { + } + + OurBool Get(void) const + { + return ControlMethods.FlipVerticalAxis; + } + void Set(OurBool NewVal) + { + ControlMethods.FlipVerticalAxis = NewVal; + } + }; + class ExportVariable_Mouse_AutoCentre : public ExportVariable + { + public: + ExportVariable_Mouse_AutoCentre + ( + ) : ExportVariable () + { + } + + OurBool Get(void) const + { + return ControlMethods.AutoCentreOnMovement; + } + void Set(OurBool NewVal) + { + ControlMethods.AutoCentreOnMovement = NewVal; + } + }; + + +}; // namespace RebMenus + +/////////////////////////////////////////////////////////////////////////////// +// Additions to the RebMenus namespace: Derived classes for each of the menu pages: +/////////////////////////////////////////////////////////////////////////////// + +namespace RebMenus +{ + // Globals for sliders, toggles, and selections + // Note that all of these are unconnected to game effects; + // if something appears in this list, modifying it in the menus does nothing + OurBool bTest_3dAcceleration; + + int iTest_Brightness; + int iTest_SmokeParticles; + int iTest_BulletHoles; + int iTest_WaterComplexity; + int iTest_BloodParticles; + +// class Page_NoMenu : public Page + Page_NoMenu :: Page_NoMenu + ( + ) : Page + ( + Appearance(), + D_Vert, + Align_Centre, + PageID_NoMenu + ) + { + // empty + AddNewJumpItem + ( + OnOffAppearance(), + PageID_Initial + ); + } + +// class Page_Initial : public Page + Page_Initial :: Page_Initial + ( + ) : Page + ( + Appearance(), + D_Vert, + Align_Centre, + PageID_Initial + ) + { + AddNewJumpItem + ( + OnOffAppearance(TEXTSTRING_MAINMENUS_NEWGAME), + PageID_ChooseCharacter + ); + + AddNewJumpItem + ( + OnOffAppearance(TEXTSTRING_MAINMENUS_LOADGAME), + PageID_LoadGame + ); + + { + Command* pCommand = new Command_Multiplayer(); + + AddNewCommandItem + ( + OnOffAppearance(TEXTSTRING_MAINMENUS_MULTIPLAYER), + pCommand + ); + + pCommand -> R_Release(); + } + + AddNewJumpItem + ( + OnOffAppearance(TEXTSTRING_MAINMENUS_OPTIONS), + PageID_Options + ); + + #if 0 + AddUnimplementedItem + ( + OnOffAppearance(TEXTSTRING_MAINMENUS_DEMO) + ); + #endif + + { + Command* pCommand_Quit = new Command_QuitProgram(); + + AddNewCommandItem + ( + OnOffAppearance(TEXTSTRING_MAINMENUS_EXIT), + pCommand_Quit + ); + + pCommand_Quit -> R_Release(); + } + + #if 0 + // Tests: + AddNewSelectionItem + ( + OnOffAppearance(), + D_Horiz + ); + + AddNewSliderItem + ( + OnOffAppearance(), + D_Horiz + ); + #endif + } + +// class Page_ChooseCharacter : public Page + Page_ChooseCharacter :: Page_ChooseCharacter + ( + ) : Page + ( + Appearance + ( + #if 0 + BitmapName("menugfx\\pg1.pg0") + #endif + ), + D_Vert, + Align_Centre, + PageID_ChooseCharacter + ) + { + #if 1 + AddNewJumpItem + ( + OnOffAppearance + ( + Appearance( BitmapName("Graphics\\NewMenus\\Alien.rim") ), + Appearance( BitmapName("Graphics\\NewMenus\\AlienDark.rim") ) + ), + PageID_AlienBriefing + ); + AddNewJumpItem + ( + OnOffAppearance + ( + Appearance( BitmapName("Graphics\\NewMenus\\Marine.rim") ), + Appearance( BitmapName("Graphics\\NewMenus\\MarineDark.rim") ) + + ), + PageID_MarineBriefing + ); + AddNewJumpItem + ( + OnOffAppearance + ( + Appearance( BitmapName("Graphics\\NewMenus\\Predator.rim") ), + Appearance( BitmapName("Graphics\\NewMenus\\PredatorDark.rim") ) + ), + PageID_PredatorBriefing + ); + #else + CompositeItem* pComposite = AddNewCompositeItem + ( + OnOffAppearance(), + D_Horiz, + Align_Centre + ); + + pComposite -> AddNewJumpItem + ( + OnOffAppearance + ( + Appearance( BitmapName("menugfx\\pg1A.pg0") ), + Appearance() + ), + PageID_AlienBriefing + ); + pComposite -> AddNewJumpItem + ( + OnOffAppearance + ( + Appearance( BitmapName("menugfx\\pg1M.pg0") ), + Appearance() + ), + PageID_MarineBriefing + ); + pComposite -> AddNewJumpItem + ( + OnOffAppearance + ( + Appearance( BitmapName("menugfx\\pg1P.pg0") ), + Appearance() + ), + PageID_PredatorBriefing + ); + #endif + + AddNewCancelItem + ( + OnOffAppearance(TEXTSTRING_RETURNTOLASTMENU) + ); + } + +// class Page_Options : public Page + Page_Options :: Page_Options + ( + ) : Page + ( + Appearance(TEXTSTRING_MAINMENUS_OPTIONS), + D_Vert, + Align_Centre, + PageID_Options + ) + { + AddNewJumpItem + ( + OnOffAppearance(TEXTSTRING_OPTIONSMENU_VIDEO), + PageID_VideoOptions + ); + AddNewJumpItem + ( + OnOffAppearance(TEXTSTRING_OPTIONSMENU_AUDIO), + PageID_AudioOptions + ); + AddNewJumpItem + ( + OnOffAppearance(TEXTSTRING_OPTIONSMENU_INPUT), + PageID_InputOptions + ); + AddNewCancelItem + ( + OnOffAppearance(TEXTSTRING_RETURNTOLASTMENU) + ); + + #if 0 + TEXTSTRING_RETURNTOLASTMENU + "RETURN" + + TEXTSTRING_OPTIONSMENU_VIDEO + "VIDEO" + + TEXTSTRING_OPTIONSMENU_AUDIO + "AUDIO" + + TEXTSTRING_OPTIONSMENU_INPUT + "INPUT" + + #endif + #if 0 + AddNewJumpItem + ( + OnOffAppearance(TEXTSTRING_PC_KEYCONFIG), + PageID_ConfigControls + ); + AddNewJumpItem + ( + OnOffAppearance(TEXTSTRING_RETURNTOMAINMENU), + PageID_Initial + ); + #endif + + #if 0 + TEXTSTRING_PC_3DACCELERATION, + TEXTSTRING_PC_MICROSOFTDIRECT3D, + TEXTSTRING_PC_TEXTURES, + TEXTSTRING_PC_DISPLAY, + TEXTSTRING_PC_ZBUFFERING, + TEXTSTRING_PC_MIPMAPPING, + TEXTSTRING_PC_SHADING, + TEXTSTRING_PC_KEYCONFIG, + TEXTSTRING_PC_FLAT, + TEXTSTRING_PC_GOURAUD, + TEXTSTRING_PC_BILINEARFILTER, + TEXTSTRING_CANCEL, + TEXTSTRING_MORE, + TEXTSTRING_NO, + TEXTSTRING_YES, + TEXTSTRING_NOTAVAILABLE, + TEXTSTRING_RETURNTOMAINMENU, + #endif + + } + +// class Page_VideoOptions : public Page + Page_VideoOptions :: Page_VideoOptions + ( + ) : Page + ( + Appearance(TEXTSTRING_VIDEOOPTIONSMENU_TITLE), + D_Vert, + Align_Min, + PageID_VideoOptions + ) + { + AddNewSliderItem + ( + OnOffAppearance(TEXTSTRING_VIDEOOPTIONSMENU_BRIGHTNESS), + D_Horiz, + new SimpleBoundedExportVariable + ( + iTest_Brightness, + 0, + ONE_FIXED + ) + + ); + AddNewToggleItem + ( + OnOffAppearance(TEXTSTRING_PC_3DACCELERATION), + D_Horiz, + OnOffAppearance + ( + Appearance(TEXTSTRING_YES), + Appearance(TEXTSTRING_NO) + ), + new ExportVariable_3dAcceleration() + ); + AddNewItem_Special + ( + new Item_VideoModeSelector + ( + OnOffAppearance(TEXTSTRING_PC_DISPLAY) + ) + ); + #if 0 + /* + Disabled 1/4/98 by DHM since using it seems to crash + on loading the game with z-buffering off; I don't know if this is a + bug in the way I'm setting things, or it's that Z buffering "off" + is no longer supported somehow + (dies in first call to LoadDDGraphic, loading "blubrmr.pg0" for + marine HUD) + */ + AddNewToggleItem + ( + OnOffAppearance(TEXTSTRING_PC_ZBUFFERING), + D_Horiz, + OnOffAppearance + ( + Appearance(TEXTSTRING_YES), + Appearance(TEXTSTRING_NO) + ), + new ExportVariable_ZBuffering() + ); + #endif + AddNewSelectionItem + ( + OnOffAppearance(TEXTSTRING_PC_TEXTUREBITDEPTH), + D_Horiz, + new SelectionVariable_TextureBitDepth() + ); + + #if 0 + AddNewToggleItem + ( + OnOffAppearance(TEXTSTRING_PC_BILINEARFILTER), + D_Horiz, + OnOffAppearance + ( + Appearance(TEXTSTRING_YES), + Appearance(TEXTSTRING_NO) + ), + new ExportVariable_BilinearFiltering() + ); + AddUnimplementedItem + ( + OnOffAppearance(TEXTSTRING_PC_MIPMAPPING) + ); + AddUnimplementedItem + ( + OnOffAppearance(TEXTSTRING_PC_SHADING) + ); + #endif + AddNewJumpItem + ( + OnOffAppearance(TEXTSTRING_VIDEOOPTIONSMENU_LEVELSOFDETAIL), + PageID_LevelsOfDetail + ); + AddNewCancelItem + ( + OnOffAppearance(TEXTSTRING_RETURNTOLASTMENU) + ); + } + +// class Page_AudioOptions : public Page + Page_AudioOptions :: Page_AudioOptions + ( + ) : Page + ( + Appearance(TEXTSTRING_AUDIOOPTIONSMENU_TITLE), + D_Vert, + Align_Min, + PageID_AudioOptions + ) + { + AddNewCancelItem + ( + OnOffAppearance(TEXTSTRING_RETURNTOLASTMENU) + ); + } + +// class Page_LevelsOfDetail : public Page + Page_LevelsOfDetail :: Page_LevelsOfDetail + ( + ) : Page + ( + Appearance(TEXTSTRING_VIDEOOPTIONSMENU_LEVELSOFDETAIL), + D_Vert, + Align_Min, + PageID_LevelsOfDetail + ) + { + AddNewSliderItem + ( + OnOffAppearance(TEXTSTRING_LEVELSOFDETAIL_SMOKEPARTICLES), + D_Horiz, + new SimpleBoundedExportVariable + ( + iTest_SmokeParticles, + 0, + ONE_FIXED + ) + ); + AddNewSliderItem + ( + OnOffAppearance(TEXTSTRING_LEVELSOFDETAIL_BULLETHOLES), + D_Horiz, + new SimpleBoundedExportVariable + ( + iTest_BulletHoles, + 0, + ONE_FIXED + ) + ); + AddNewSliderItem + ( + OnOffAppearance(TEXTSTRING_LEVELSOFDETAIL_WATERCOMPLEXITY), + D_Horiz, + new SimpleBoundedExportVariable + ( + iTest_WaterComplexity, + 0, + ONE_FIXED + ) + ); + AddNewSliderItem + ( + OnOffAppearance(TEXTSTRING_LEVELSOFDETAIL_BLOODPARTICLES), + D_Horiz, + new SimpleBoundedExportVariable + ( + iTest_BloodParticles, + 0, + ONE_FIXED + ) + ); + + AddNewCancelItem + ( + OnOffAppearance(TEXTSTRING_RETURNTOLASTMENU) + ); + } + +// class Page_MarineBriefing : public Page + Page_MarineBriefing :: Page_MarineBriefing + ( + ) : Page + ( + Appearance(), + D_Vert, + Align_Centre, + PageID_MarineBriefing + ) + { + { + Command* pCommand_StartSoloGame = new Command_StartSoloGame + ( + I_Marine, + I_Entrance + ); + + AddNewCommandItem + ( + OnOffAppearance(TEXTSTRING_MAINMENUS_STARTGAME), + pCommand_StartSoloGame + ); + + pCommand_StartSoloGame -> R_Release(); + } + + AddNewCancelItem + ( + OnOffAppearance(TEXTSTRING_RETURNTOLASTMENU) + ); + } + +// class Page_PredatorBriefing : public Page + Page_PredatorBriefing :: Page_PredatorBriefing + ( + ) : Page + ( + Appearance(), + D_Vert, + Align_Centre, + PageID_PredatorBriefing + ) + { + { + Command* pCommand_StartSoloGame = new Command_StartSoloGame + ( + I_Predator, + I_Cmc4 + ); + + AddNewCommandItem + ( + OnOffAppearance(TEXTSTRING_MAINMENUS_STARTGAME), + pCommand_StartSoloGame + ); + + pCommand_StartSoloGame -> R_Release(); + } + + AddNewCancelItem + ( + OnOffAppearance(TEXTSTRING_RETURNTOLASTMENU) + ); + } + +// class Page_AlienBriefing : public Page + Page_AlienBriefing :: Page_AlienBriefing + ( + ) : Page + ( + Appearance(), + D_Vert, + Align_Centre, + PageID_AlienBriefing + ) + { + { + Command* pCommand_StartSoloGame = new Command_StartSoloGame + ( + I_Alien, + I_Medlab + ); + + AddNewCommandItem + ( + OnOffAppearance(TEXTSTRING_MAINMENUS_STARTGAME), + pCommand_StartSoloGame + ); + + pCommand_StartSoloGame -> R_Release(); + } + + AddNewCancelItem + ( + OnOffAppearance(TEXTSTRING_RETURNTOLASTMENU) + ); + } + +// class Page_LoadGame : public Page + Page_LoadGame :: Page_LoadGame + ( + ) : Page + ( + Appearance(), + D_Vert, + Align_Centre, + PageID_LoadGame + ) + { + AddNewCancelItem + ( + OnOffAppearance(TEXTSTRING_RETURNTOLASTMENU) + ); + } + +// class Page_InputOptions : public Page + Page_InputOptions :: Page_InputOptions + ( + ) : Page + ( + Appearance(TEXTSTRING_PCKEY_TITLE), + D_Vert, + Align_Centre, + PageID_InputOptions + ) + { + #if 0 + AddUnimplementedItem + ( + OnOffAppearance(TEXTSTRING_CONTROLCONFIGURATION_ALIEN) + ); + AddUnimplementedItem + ( + OnOffAppearance(TEXTSTRING_CONTROLCONFIGURATION_MARINE) + ); + AddUnimplementedItem + ( + OnOffAppearance(TEXTSTRING_CONTROLCONFIGURATION_PREDATOR) + ); + AddUnimplementedItem + ( + OnOffAppearance(TEXTSTRING_CONTROLCONFIGURATION_SHARED) + ); + AddUnimplementedItem + ( + OnOffAppearance(TEXTSTRING_SHARECONTROLCONFIGURATION) + ); + #endif + + AddNewItem_Special + ( + new Item_KeyConfig_PageView + ( + OnOffAppearance(), + 7 // int NumEffectsPerPage + ) + ); + + #if 1 + { + Command* pCommand = new Command_KeyConfig_PrvPage(); + AddNewCommandItem + ( + OnOffAppearance(TEXTSTRING_PSXCOMPUTER_PREVIOUS), + pCommand + ); + pCommand -> R_Release(); + } + { + Command* pCommand = new Command_KeyConfig_NxtPage(); + AddNewCommandItem + ( + OnOffAppearance(TEXTSTRING_PSXCOMPUTER_NEXT), + pCommand + ); + pCommand -> R_Release(); + } + #else + AddNewItem_Special + ( + new Item_KeyConfig_Selector + ( + OnOffAppearance() + ) + ); + #endif + + { + Command* pCommand = new Command_KeyConfig_RestoreDefaults(); + AddNewCommandItem + ( + OnOffAppearance(TEXTSTRING_RESTORE_DEFAULTS), + pCommand + ); + pCommand -> R_Release(); + } + + AddNewJumpItem + ( + OnOffAppearance(TEXTSTRING_MOUSE_TITLE), + PageID_MouseConfig + ); + + AddNewCancelItem + ( + OnOffAppearance(TEXTSTRING_RETURNTOLASTMENU) + ); + } + + +// class Page_ConfigMouse : public Page + Page_ConfigMouse :: Page_ConfigMouse + ( + ) : Page + ( + Appearance(TEXTSTRING_MOUSE_TITLE), + D_Vert, + Align_Min, + PageID_MouseConfig + ) + { + AddNewSliderItem + ( + OnOffAppearance(TEXTSTRING_MOUSE_XSENSITIVITY), + D_Horiz, + new BoundedExportVariable_MouseSensitivity + ( + Yes // OurBool bXAxis + ) + ); + AddNewSliderItem + ( + OnOffAppearance(TEXTSTRING_MOUSE_YSENSITIVITY), + D_Horiz, + new BoundedExportVariable_MouseSensitivity + ( + No // OurBool bXAxis + ) + ); + + AddNewToggleItem + ( + OnOffAppearance(TEXTSTRING_MOUSE_VERTICAL_AXIS), + + D_Horiz, + + OnOffAppearance + ( + Appearance(TEXTSTRING_MOUSE_MOVEMENT), + Appearance(TEXTSTRING_MOUSE_LOOKING) + ), + + new ExportVariable_MouseAxisEffect_V() + ); + AddNewToggleItem + ( + OnOffAppearance(TEXTSTRING_MOUSE_HORIZONTAL_AXIS), + + D_Horiz, + + OnOffAppearance + ( + Appearance(TEXTSTRING_MOUSE_TURNING), + Appearance(TEXTSTRING_MOUSE_SIDESTEPPING) + ), + + new ExportVariable_MouseAxisEffect_H() + ); + + AddNewToggleItem + ( + OnOffAppearance(TEXTSTRING_MOUSE_FLIP_VERTICAL), + + D_Horiz, + + OnOffAppearance + ( + Appearance(TEXTSTRING_YES), + Appearance(TEXTSTRING_NO) + ), + + new ExportVariable_Mouse_FlipVertical() + ); + AddNewToggleItem + ( + OnOffAppearance(TEXTSTRING_MOUSE_AUTO_CENTRE), + + D_Horiz, + + OnOffAppearance + ( + Appearance(TEXTSTRING_YES), + Appearance(TEXTSTRING_NO) + ), + + new ExportVariable_Mouse_AutoCentre() + ); + + { + Command* pCommand = new Command_MouseConfig_RestoreDefaults(); + AddNewCommandItem + ( + OnOffAppearance(TEXTSTRING_RESTORE_DEFAULTS), + pCommand + ); + pCommand -> R_Release(); + } + + AddNewCancelItem + ( + OnOffAppearance(TEXTSTRING_RETURNTOLASTMENU) + ); + } + +// class Page_PlaceholderMultiplayer : public Page + Page_PlaceholderMultiplayer :: Page_PlaceholderMultiplayer + ( + ) : Page + ( + Appearance(TEXTSTRING_MAINMENUS_MULTIPLAYER), + D_Vert, + Align_Min, + PageID_PlaceholderMultiplayer + ) + { + AddNewItem_Special + ( + new Item_NetworkStatus + ( + OnOffAppearance(TEXTSTRING_RETURNTOLASTMENU) + // sort this out ! + ) + ); + AddNewSelectionItem + ( + OnOffAppearance(TEXTSTRING_MULTI_CHARACTER), + D_Horiz, + new SelectionVariable_MultiplayerSpecies() + ); + AddNewSelectionItem + ( + OnOffAppearance(TEXTSTRING_MULTI_GAMEMODE), + D_Horiz, + new SelectionVariable_MultiplayerGameMode() + ); + +#if 0 +TEXTSTRING_MULTI_GAMEMODE, +TEXTSTRING_MULTI_INDIVIDUAL, +TEXTSTRING_MULTI_COOP, +#endif + + AddNewToggleItem + ( + OnOffAppearance(TEXTSTRING_MULTI_START), // OnOffAppearance theOnOffApp_Label, + D_Horiz, // enum Direction initDir, + OnOffAppearance + ( + Appearance(TEXTSTRING_MULTI_OK), + Appearance(TEXTSTRING_BLANK) + ), // OnOffAppearance theOnOffApp_Choice, + new ExportVariable_StartNetworkGame() // ExportVariable* pExpVar + ); + AddNewCancelItem + ( + OnOffAppearance(TEXTSTRING_RETURNTOLASTMENU) + ); + } + +// class Page_MultiplayerErrorScreen : public Page + Page_MultiplayerErrorScreen :: Page_MultiplayerErrorScreen + ( + ) : Page + ( + Appearance(TEXTSTRING_MAINMENUS_MULTIPLAYER), + D_Vert, + Align_Centre, + PageID_MultiplayerErrorScreen + ) + { + AddNewItem_Special + ( + new Item_NetworkErrorView() + ); + AddNewJumpItem + ( + OnOffAppearance(TEXTSTRING_MULTI_CANCEL), + PageID_Initial + ); + } + + +}; // end of namespace RebMenus + + +void +RebMenus :: Page_VideoOptions :: Hook_LeavingPage(void) +{ + SaveVideoModeSettings(); + // this function also copies the currently selected mode for the + // currently selected DriverMode into a selected video mode global +} + +void +RebMenus :: Page_InputOptions :: Hook_LeavingPage(void) +{ + SaveKeyConfiguration(); +} + +void +RebMenus :: Page_PlaceholderMultiplayer :: Hook_EnteringPage(void) +{ + // Set START button to a default "off" value: + netGameData.myStartFlag = 0; + + // Leave everything else as it was (e.g. requested species, game mode, etc) +} + +void +RebMenus :: Page_PlaceholderMultiplayer :: Hook_LeavingPage(void) +{ + if (AvP.Network!=I_No_Network) + { + if ( netGameData . myGameState == NGS_Joining ) + { + if(AvP.Network==I_Host) + { + TransmitEndOfGameNetMsg(); + netGameData.myGameState=NGS_EndGame; + } + else + { + TransmitPlayerLeavingNetMsg(); + netGameData.myGameState=NGS_Leaving; + } + } + } +} + +#endif // UseRebMenus + +/* Internal function definitions ***********************************/ +#if 0 +void MouseOptionsMenu(void) +{ + int selection = 0, numSensitivities; + int exit = -1, debounce = 0; + + while (MouseXSensitivities[selection] != -1) + { + if (MouseXSensitivities[selection] == ControlMethods.MouseXSensitivity) mouseXsensitivity = selection; + selection++; + } + + selection = 0; + while (MouseYSensitivities[selection] != -1) + { + if (MouseYSensitivities[selection] == ControlMethods.MouseYSensitivity) mouseYsensitivity = selection; + selection++; + } + numSensitivities = selection; + + selection = 0; + + while (exit == -1) + { + // JCWH 18/02/98: allow ALT+TAB + CheckForWindowsMessages(); + + DrawMouseOptionsScreen(selection); + + /* Deal with moving the selected item */ + ReadUserInput(); + + if (IDemandGoForward() && debounce) + { + debounce = 0; + selection--; + if (selection < 0) selection = MOUSECONFIG_NUMITEMS - 1; + } + else if (IDemandGoBackward() && debounce) + { + debounce = 0; + selection++; + if (selection >= MOUSECONFIG_NUMITEMS) selection = 0; + } + else if (IDemandTurnRight() && debounce) + { + debounce = 0; + /* Execute appropriate action */ + + if (selection == MOUSECONFIG_VAXIS) ControlMethods.VAxisIsMovement = 1 - ControlMethods.VAxisIsMovement; + else if (selection == MOUSECONFIG_HAXIS) ControlMethods.HAxisIsTurning = 1 - ControlMethods.HAxisIsTurning; + else if (selection == MOUSECONFIG_FLIPVERTICAL) ControlMethods.FlipVerticalAxis = 1 - ControlMethods.FlipVerticalAxis; + else if (selection == MOUSECONFIG_AUTOCENTRE) ControlMethods.AutoCentreOnMovement = 1 - ControlMethods.AutoCentreOnMovement; + else if (selection == MOUSECONFIG_XSENSITIVITY) + { + mouseXsensitivity++; + if (mouseXsensitivity >= numSensitivities) mouseXsensitivity = numSensitivities - 1; + } + else if (selection == MOUSECONFIG_YSENSITIVITY) + { + mouseYsensitivity++; + if (mouseYsensitivity >= numSensitivities) mouseYsensitivity = numSensitivities - 1; + } + } + else if (IDemandTurnLeft() && debounce) + { + debounce = 0; + /* ditto */ + + if (selection == MOUSECONFIG_VAXIS) ControlMethods.VAxisIsMovement = 1 - ControlMethods.VAxisIsMovement; + else if (selection == MOUSECONFIG_HAXIS) ControlMethods.HAxisIsTurning = 1 - ControlMethods.HAxisIsTurning; + else if (selection == MOUSECONFIG_FLIPVERTICAL) ControlMethods.FlipVerticalAxis = 1 - ControlMethods.FlipVerticalAxis; + else if (selection == MOUSECONFIG_AUTOCENTRE) ControlMethods.AutoCentreOnMovement = 1 - ControlMethods.AutoCentreOnMovement; + else if (selection == MOUSECONFIG_XSENSITIVITY) + { + mouseXsensitivity--; + if (mouseXsensitivity < 0) mouseXsensitivity = 0; + } + else if (selection == MOUSECONFIG_YSENSITIVITY) + { + mouseYsensitivity--; + if (mouseYsensitivity < 0) mouseYsensitivity = 0; + } + } + else if (IDemandSelect() && debounce) + { + debounce = 0; + + if (selection == MOUSECONFIG_NUMITEMS - 1) + { + /* Exit item */ + exit = 1; + } + } + + if ((!IDemandGoForward()) && (!IDemandGoBackward()) && + (!IDemandTurnLeft()) && (!IDemandTurnRight()) && + (!IDemandSelect()) ) debounce = 1; + } + + ControlMethods.MouseXSensitivity = MouseXSensitivities[mouseXsensitivity]; + ControlMethods.MouseYSensitivity = MouseYSensitivities[mouseYsensitivity]; + +} +#endif \ No newline at end of file diff --git a/3dc/avp/avppages.hpp b/3dc/avp/avppages.hpp new file mode 100644 index 0000000..6a6a76f --- /dev/null +++ b/3dc/avp/avppages.hpp @@ -0,0 +1,164 @@ +/* + + avppages.hpp + +*/ + +#ifndef _avppages +#define _avppages 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + + #ifndef _rebmenus_hpp + #include "rebmenus.hpp" + #endif + +#if UseRebMenus +class Command_QuitProgram : public Command +{ +public: + Command_QuitProgram() : Command() + { + } + OurBool Execute(void); +}; + +class Command_StartSoloGame : public Command +{ +public: + Command_StartSoloGame + ( + I_PLAYER_TYPE inPlayerType, + I_AVP_ENVIRONMENTS inStartingEnv + ) : Command(), + thePlayerType(inPlayerType), + theStartingEnv(inStartingEnv) + { + } + OurBool Execute(void); +private: + const I_PLAYER_TYPE thePlayerType; + const I_AVP_ENVIRONMENTS theStartingEnv; +}; + +class Command_Multiplayer : public Command +{ +public: + Command_Multiplayer() : Command() + { + } + OurBool Execute(void); + + // Only takes effect if the flag's been set (and clears the flag) + // Triggers the multiplayer dialog boxes + static void EndOfMenuLoopProcessing(void); + +private: + static OurBool bTriggerMenuDialog; +}; + +class Command_ExitCurrentGame : public Command +{ +public: + Command_ExitCurrentGame() : Command() + { + } + + OurBool Execute(void); +}; + +namespace RebMenus +{ + class Page_NoMenu : public Page + { + public: + Page_NoMenu(); + }; + class Page_Initial : public Page + { + public: + Page_Initial(); + }; + class Page_ChooseCharacter : public Page + { + public: + Page_ChooseCharacter(); + }; + class Page_Options : public Page + { + public: + Page_Options(); + }; + class Page_VideoOptions : public Page + { + public: + Page_VideoOptions(); + private: + void Hook_LeavingPage(void); + }; + class Page_AudioOptions : public Page + { + public: + Page_AudioOptions(); + }; + class Page_LevelsOfDetail : public Page + { + public: + Page_LevelsOfDetail(); + }; + class Page_MarineBriefing : public Page + { + public: + Page_MarineBriefing(); + }; + class Page_PredatorBriefing : public Page + { + public: + Page_PredatorBriefing(); + }; + class Page_AlienBriefing : public Page + { + public: + Page_AlienBriefing(); + }; + class Page_LoadGame : public Page + { + public: + Page_LoadGame(); + }; + class Page_InputOptions : public Page + { + public: + Page_InputOptions(); + private: + void Hook_LeavingPage(void); + }; + class Page_ConfigMouse : public Page + { + public: + Page_ConfigMouse(); + }; + class Page_PlaceholderMultiplayer : public Page + { + public: + Page_PlaceholderMultiplayer(); + private: + void Hook_EnteringPage(void); + void Hook_LeavingPage(void); + }; + class Page_MultiplayerErrorScreen : public Page + { + public: + Page_MultiplayerErrorScreen(); + }; +}; // namespace RebMenus +#endif // UseRebMenus + + +/* End of the header ****************************************************/ + + + +#endif diff --git a/3dc/avp/bh_RubberDuck.c b/3dc/avp/bh_RubberDuck.c new file mode 100644 index 0000000..3f971f7 --- /dev/null +++ b/3dc/avp/bh_RubberDuck.c @@ -0,0 +1,342 @@ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" + +#include "bh_types.h" +//#include "comp_shp.h" +#include "dynblock.h" +#include "dynamics.h" +//#include "lighting.h" + +#include "pfarlocs.h" + +#include "pvisible.h" +#include "load_shp.h" +#include "particle.h" + +#include "bh_types.h" +#include "bh_RubberDuck.h" +#include "bh_weap.h" +#include "sfx.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; +extern int NormalFrameTime; + +void CreateRubberDuckBot(void) +{ + CreateRubberDuck(&(Global_VDB_Ptr->VDB_World)); +} + + +void CreateRubberDuck(VECTORCH *positionPtr) +{ + STRATEGYBLOCK* sbPtr; + + /* create and initialise a strategy block */ + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) return; /* failure */ + InitialiseSBValues(sbPtr); + + sbPtr->I_SBtype = I_BehaviourRubberDuck; + + AssignNewSBName(sbPtr); + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE); + if(sbPtr->DynPtr) + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + EULER zeroEuler = {0,0,0}; + zeroEuler.EulerY = FastRandom()&4095; + dynPtr->PrevPosition = dynPtr->Position = *positionPtr; + dynPtr->OrientEuler = zeroEuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + dynPtr->LinImpulse.vy = 0; + dynPtr->GravityOn = 0; + dynPtr->Elasticity = 0; + dynPtr->IsFloating = 1; + } + else + { + /* dynamics block allocation failed... */ + RemoveBehaviourStrategy(sbPtr); + return; + } + + sbPtr->shapeIndex = GetLoadedShapeMSL("ciggies");//Duck"); + + sbPtr->maintainVisibility = 1; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), 0); + LOCALASSERT(sbPtr->containingModule); + if(!(sbPtr->containingModule)) + { + /* no containing module can be found... abort*/ + RemoveBehaviourStrategy(sbPtr); + return; + } + +} + +void RubberDuckBehaviour(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + int newLevel; + + if (!sbPtr->SBdptr) return; + #if 1 + newLevel = EffectOfRipples(&(dynPtr->Position)); + { + int minusDeltaX,plusDeltaX,minusDeltaZ,plusDeltaZ; + VECTORCH delta; + delta.vx = dynPtr->Position.vx; + delta.vz = dynPtr->Position.vz; + + + delta.vx -= 50; + minusDeltaX = EffectOfRipples(&(delta))-newLevel; + delta.vx += 100; + plusDeltaX = EffectOfRipples(&(delta))-newLevel; + delta.vx -= 50; + + delta.vz -= 50; + minusDeltaZ = EffectOfRipples(&(delta))-newLevel; + delta.vz += 100; + plusDeltaZ = EffectOfRipples(&(delta))-newLevel; + { + int scale = NormalFrameTime<<1; + if(scale>ONE_FIXED) scale = ONE_FIXED; + scale = ONE_FIXED; + dynPtr->LinImpulse.vx -= MUL_FIXED(scale,dynPtr->LinImpulse.vx); + dynPtr->LinImpulse.vz -= MUL_FIXED(scale,dynPtr->LinImpulse.vz); + } + if (minusDeltaX > plusDeltaX) + { + if (minusDeltaX>0) dynPtr->LinImpulse.vx = -minusDeltaX*256; + } + else + { + if (plusDeltaX>0) dynPtr->LinImpulse.vx = plusDeltaX*256; + } + + if (minusDeltaZ > plusDeltaZ) + { + if (minusDeltaZ>0) dynPtr->LinImpulse.vz = -minusDeltaZ*256; + } + else + { + if (plusDeltaZ>0) dynPtr->LinImpulse.vz = plusDeltaZ*256; + } + + } + dynPtr->LinImpulse.vy = 0; + { + int level = 0; + extern char LevelName[]; + { + if (!strcmp(LevelName,"e3demosp")||!strcmp(LevelName,"e3demo")) + { + level = 3300; + } + else if (!strcmp(LevelName,"invasion_a")) + { + level = -35800; + } + else if (!strcmp(LevelName,"genshd1")) + { + level = 2656; + } + else if (!strcmp(LevelName,"fall")||!strcmp(LevelName,"fall_m")) + { + level = 12925; + } + else if (!strcmp(LevelName,"derelict")) + { + level = 32000; + } + dynPtr->Position.vy = newLevel+level; + } + } + + dynPtr->AngVelocity.EulerY -= MUL_FIXED(dynPtr->AngVelocity.EulerY,NormalFrameTime); + + dynPtr->AngVelocity.EulerY += (dynPtr->LinImpulse.vz + dynPtr->LinImpulse.vx+(FastRandom()&255)-128)/16; + + dynPtr->AngVelocity.EulerZ = (dynPtr->LinImpulse.vz/256); + dynPtr->AngVelocity.EulerX = (dynPtr->LinImpulse.vx/256); + + if (dynPtr->AngVelocity.EulerY > 8192) dynPtr->AngVelocity.EulerY = 8192; + else if (dynPtr->AngVelocity.EulerY < -8192) dynPtr->AngVelocity.EulerY = -8192; + DynamicallyRotateObject(dynPtr); + #else + { + VECTORCH dir; + dynPtr->GravityOn = 1; + dynPtr->IsFloating = 0; + dynPtr->CanClimbStairs = 0; + sbPtr->SBdptr->ObFlags3 |= ObFlag3_DynamicModuleObject; + + if (BestDirectionOfTravel(&(Player->ObStrategyBlock->DynPtr->Position), &(dynPtr->Position), &dir)) + { + dynPtr->LinVelocity.vx = MUL_FIXED(4000,dir.vx); + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = MUL_FIXED(4000,dir.vz); + } + else + { + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + } + } + #endif + +} + +extern void CreateFlamingDebris(VECTORCH *positionPtr, VECTORCH *dirPtr) +{ + STRATEGYBLOCK* sbPtr; + + /* create and initialise a strategy block */ + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) return; /* failure */ + InitialiseSBValues(sbPtr); + + sbPtr->I_SBtype = I_BehaviourFragment; + + AssignNewSBName(sbPtr); + + sbPtr->SBdataptr = (void*)AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK)); + + if (sbPtr->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(sbPtr); + return; + } + ((ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = ((FastRandom()&32768)<<2) + 65535*2; + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ALIEN_DEBRIS); + if(sbPtr->DynPtr) + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + dynPtr->PrevPosition = dynPtr->Position = *positionPtr; + dynPtr->OrientEuler.EulerX = 0; + dynPtr->OrientEuler.EulerY = FastRandom()&4095; + dynPtr->OrientEuler.EulerZ = 0; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + + dynPtr->LinImpulse.vx = dirPtr->vx/4; + dynPtr->LinImpulse.vy = dirPtr->vy/4; + if (dynPtr->LinImpulse.vy>0) dynPtr->LinImpulse.vy=-dynPtr->LinImpulse.vy; + dynPtr->LinImpulse.vy += -4000; + dynPtr->LinImpulse.vz = dirPtr->vz/4; + dynPtr->AngVelocity.EulerX = (((FastRandom()&2047)-1023))<<2; + dynPtr->AngVelocity.EulerY = (((FastRandom()&2047)-1023))<<2; + dynPtr->AngVelocity.EulerZ = (((FastRandom()&2047)-1023))<<2; + + dynPtr->Elasticity = ONE_FIXED/4; + } + else + { + /* dynamics block allocation failed... */ + RemoveBehaviourStrategy(sbPtr); + return; + } + + sbPtr->shapeIndex = GetLoadedShapeMSL("Shell"); + + sbPtr->maintainVisibility = 0; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), 0); + LOCALASSERT(sbPtr->containingModule); + if(!(sbPtr->containingModule)) + { + /* no containing module can be found... abort*/ + RemoveBehaviourStrategy(sbPtr); + return; + } + + { + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + VisibilityDefaultObjectMap.MapShape = sbPtr->shapeIndex; + tempModule.m_mapptr = &VisibilityDefaultObjectMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 0; + tempModule.m_lightarray = (struct lightblock *)0; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr = NULL; /* this is important */ + #if SupportWIndows95 + tempModule.name = NULL; /* this is important */ + #endif + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + sbPtr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbPtr; + dPtr->ObMyModule = NULL; + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + + /* make displayblock a dynamic module object */ + dPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + + sbPtr->SBDamageBlock.IsOnFire=1; + + } +} + +void CreateRubberDucks(void) +{ + extern char LevelName[]; + #if 0 + if ( (!stricmp(LevelName,"e3demo")) || (!stricmp(LevelName,"e3demosp")) ) + { + int i = 6; + + do + { + VECTORCH pos = {1023,3400,27536}; + pos.vx += (FastRandom()&4095)-2048; + pos.vz += (FastRandom()&4095)-2048; + CreateRubberDuck(&pos); + } + while(--i); + } + else + #endif + if ( (!stricmp(LevelName,"invasion_a")) ) + { + int i = 6; + + do + { + VECTORCH pos = {21803,-35491,40607}; + pos.vx += FastRandom()&8191; + pos.vz -= FastRandom()&8191; + CreateRubberDuck(&pos); + } + while(--i); + } +} + diff --git a/3dc/avp/bh_RubberDuck.h b/3dc/avp/bh_RubberDuck.h new file mode 100644 index 0000000..51610e3 --- /dev/null +++ b/3dc/avp/bh_RubberDuck.h @@ -0,0 +1,6 @@ +extern void CreateRubberDuckBot(void); +extern void CreateRubberDuck(VECTORCH *positionPtr); +extern void CreateRubberDucks(void); +extern void RubberDuckBehaviour(STRATEGYBLOCK *sbPtr); + +extern void CreateFlamingDebris(VECTORCH *positionPtr, VECTORCH *dirPtr); diff --git a/3dc/avp/bh_agun.c b/3dc/avp/bh_agun.c new file mode 100644 index 0000000..64179f8 --- /dev/null +++ b/3dc/avp/bh_agun.c @@ -0,0 +1,1720 @@ +// RWH moved out here to provide easier access + +/* CDF 25/7/98 - A completely new file. */ + +#include "3dc.h" +#include "inline.h" +#include "module.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" + +#include "dynblock.h" +#include "dynamics.h" + +#include "weapons.h" +#include "comp_shp.h" +#include "inventry.h" +#include "triggers.h" +#include "mslhand.h" + +#define UseLocalAssert Yes + +#include "ourasert.h" + +#include "pmove.h" +#include "pvisible.h" +#include "bh_swdor.h" +#include "bh_plift.h" +#include "load_shp.h" +#include "bh_weap.h" +#include "bh_debri.h" +#include "lighting.h" +#include "bh_lnksw.h" +#include "bh_binsw.h" +#include "pheromon.h" +#include "bh_pred.h" +#include "bh_agun.h" +#include "plat_shp.h" +#include "psnd.h" +#include "AI_Sight.h" +#include "sequnces.h" +#include "huddefs.h" +#include "ShowCmds.h" +#include "sfx.h" +#include "bh_marin.h" +#include "bh_far.h" +#include "pldghost.h" +#include "pheromon.h" +#include "targeting.h" +#include "dxlog.h" +#include "los.h" +#include "psndplat.h" +#include "bh_dummy.h" +#include "bh_corpse.h" + +#if SupportWindows95 +/* for win95 net game support */ +#include "pldghost.h" +#include "pldnet.h" +#endif + +#define SENTRYGUN_DRAMA 0 + +int SentrygunSpread=5; + +extern int NormalFrameTime; +extern unsigned char Null_Name[8]; +extern ACTIVESOUNDSAMPLE ActiveSounds[]; +extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); +void CreateSentrygun(VECTORCH *Position,int type); + +void AGunMovement_ScanLeftRight(STRATEGYBLOCK *sbPtr,int rate); +void AGunMovement_Centre(STRATEGYBLOCK *sbPtr,int rate); +void Execute_AGun_Target(STRATEGYBLOCK *sbPtr); +void AGun_MaintainGun(STRATEGYBLOCK *sbPtr); +void Execute_AGun_Dying(STRATEGYBLOCK *sbPtr); + +SOUND3DDATA SentryFire_SoundData={ + {0,0,0,}, + {0,0,0,}, + 20000, + 40000, +}; + +SOUND3DDATA SentryWhirr_SoundData={ + {0,0,0,}, + {0,0,0,}, + 0, + 32000, +}; + +/* Begin Code! */ + +void CreatePlayerAutogun(void) { + /* Yow, this actually gets called! */ +} + +void CastSentrygun(void) { + + #define BOTRANGE 2000 + + VECTORCH position; + + if (AvP.Network!=I_No_Network) { + NewOnScreenMessage("NO SENTRYGUNS IN MULTIPLAYER MODE"); + return; + } + + position=Player->ObStrategyBlock->DynPtr->Position; + position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE); + position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE); + position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE); + + CreateSentrygun(&position, 0); + +} + +void CreateSentrygun(VECTORCH *Position,int type) +{ + STRATEGYBLOCK* sbPtr; + int i; + + /* create and initialise a strategy block */ + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) { + NewOnScreenMessage("FAILED TO CREATE BOT: SB CREATION FAILURE"); + return; /* failure */ + } + InitialiseSBValues(sbPtr); + + sbPtr->I_SBtype = I_BehaviourAutoGun; + + AssignNewSBName(sbPtr); + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC); + if(sbPtr->DynPtr) + { + EULER zeroEuler = {0,0,0}; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + GLOBALASSERT(dynPtr); + dynPtr->PrevPosition = dynPtr->Position = *Position; + dynPtr->OrientEuler = zeroEuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + dynPtr->UseDisplacement=0; + + dynPtr->Mass=10000; /* As opposed to 160. */ + } + else + { + /* dynamics block allocation failed... */ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE GUN: DYNBLOCK CREATION FAILURE"); + return; + } + + sbPtr->shapeIndex = 0; + + sbPtr->maintainVisibility = 1; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0); + + /* create, initialise and attach an alien data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(AUTOGUN_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + SECTION *root_section; + AUTOGUN_STATUS_BLOCK *agunStatus = (AUTOGUN_STATUS_BLOCK *)sbPtr->SBdataptr; + + /* Initialise xenoborg's stats */ + { + NPC_DATA *NpcData; + + NpcData=GetThisNpcData(I_NPC_SentryGun); + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + + agunStatus->behaviourState=I_tracking; + agunStatus->Target=NULL; + COPY_NAME(agunStatus->Target_SBname,Null_Name); + agunStatus->targetTrackPos.vx=0; + agunStatus->targetTrackPos.vy=0; + agunStatus->targetTrackPos.vz=0; + + agunStatus->stateTimer=0; + agunStatus->Gun_Pan=0; + agunStatus->Gun_Tilt=0; + + agunStatus->gunpandir=0; + agunStatus->guntiltdir=0; + + agunStatus->IAmFar=1; + agunStatus->Firing=0; + agunStatus->Drama=0; + agunStatus->OnTarget=0; + agunStatus->OnTarget_LastFrame=0; + agunStatus->WhirrSoundOn=0; + agunStatus->GunFlash=NULL; + agunStatus->soundHandle=SOUND_NOACTIVEINDEX; + agunStatus->soundHandle2=SOUND_NOACTIVEINDEX; + + agunStatus->ammo=500; + agunStatus->roundsFired=0; + agunStatus->volleyFired=0; + + agunStatus->incidentFlag=0; + agunStatus->incidentTimer=0; + + agunStatus->HModelController.section_data=NULL; + agunStatus->HModelController.Deltas=NULL; + + for(i=0;ideath_target_ID[i] =0; + agunStatus->death_target_sbptr=0; + agunStatus->death_target_request=0; + + root_section=GetNamedHierarchyFromLibrary("sentry","gun"); + + if (!root_section) { + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE GUN: NO HMODEL"); + return; + } + Create_HModel(&agunStatus->HModelController,root_section); + InitHModelSequence(&agunStatus->HModelController,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED); + + { + DELTA_CONTROLLER *delta; + + delta=Add_Delta_Sequence(&agunStatus->HModelController,"GunTilt",(int)HMSQT_Xenoborg,(int)XBSS_Head_Vertical_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + delta=Add_Delta_Sequence(&agunStatus->HModelController,"GunPan",(int)HMSQT_Xenoborg,(int)XBSS_Head_Horizontal_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + } + + /* Containment test NOW! */ + if(!(sbPtr->containingModule)) + { + /* no containing module can be found... abort*/ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE GUN: MODULE CONTAINMENT FAILURE"); + return; + } + LOCALASSERT(sbPtr->containingModule); + + MakeSentrygunNear(sbPtr); + + NewOnScreenMessage("SENTRYGUN CREATED"); + } + else + { + /* no data block can be allocated */ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE GUN: MALLOC FAILURE"); + return; + } + if(AvP.Network != I_No_Network) + { + AddNetGameObjectID(sbPtr); + } +} + +void MakeSentrygunNear(STRATEGYBLOCK *sbPtr) +{ + extern MODULEMAPBLOCK AlienDefaultMap; + + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr; + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + LOCALASSERT(dynPtr); + LOCALASSERT(sbPtr->SBdptr == NULL); + + AlienDefaultMap.MapShape = sbPtr->shapeIndex; + tempModule.m_mapptr = &AlienDefaultMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 0; + tempModule.m_lightarray = (struct lightblock *)0; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr = NULL; + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) return; /* if cannot create displayblock, leave far */ + + sbPtr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbPtr; + dPtr->ObMyModule = NULL; + + /* need to initialise positional information in the new display block */ + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + /* zero linear velocity in dynamics block */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* state and sequence init */ + dPtr->ShapeAnimControlBlock = NULL; + dPtr->ObTxAnimCtrlBlks = NULL; + + dPtr->HModelControlBlock=&agunStatusPointer->HModelController; + + ProveHModel(dPtr->HModelControlBlock,dPtr); + + agunStatusPointer->IAmFar=0; + +} + +void AutoGunBehaveInit(void *bhdata,STRATEGYBLOCK *sbPtr) { + + AUTOGUN_TOOLS_TEMPLATE *toolsData; + int i; + + LOCALASSERT(bhdata); + toolsData = (AUTOGUN_TOOLS_TEMPLATE *)bhdata; + LOCALASSERT(sbPtr); + + /* check we're not in a net game */ + if(AvP.Network != I_No_Network) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* make the assumption that the loader has initialised the strategy block sensibly... + so just set the shapeIndex from the tools data & copy the name id*/ + sbPtr->shapeIndex = toolsData->shapenum; + for(i=0;iSBname[i] = toolsData->nameID[i]; + + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC); + if(sbPtr->DynPtr) + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + GLOBALASSERT(dynPtr); + dynPtr->PrevPosition = dynPtr->Position = toolsData->position; + dynPtr->OrientEuler = toolsData->orientation; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + + dynPtr->Mass=10000; /* As opposed to 160. */ + } + else + { + /* dynamics block allocation failed... */ + RemoveBehaviourStrategy(sbPtr); + return; + } + + sbPtr->maintainVisibility = 1; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0); + + /* create, initialise and attach an alien data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(AUTOGUN_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + SECTION *root_section; + AUTOGUN_STATUS_BLOCK *agunStatus = (AUTOGUN_STATUS_BLOCK *)sbPtr->SBdataptr; + + /* Initialise xenoborg's stats */ + { + NPC_DATA *NpcData; + + NpcData=GetThisNpcData(I_NPC_SentryGun); + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + if (toolsData->startInactive) { + agunStatus->behaviourState=I_inactive; + } else { + agunStatus->behaviourState=I_tracking; + } + agunStatus->Target=NULL; + COPY_NAME(agunStatus->Target_SBname,Null_Name); + agunStatus->targetTrackPos.vx=0; + agunStatus->targetTrackPos.vy=0; + agunStatus->targetTrackPos.vz=0; + + agunStatus->stateTimer=0; + agunStatus->Gun_Pan=0; + agunStatus->Gun_Tilt=0; + + agunStatus->gunpandir=0; + agunStatus->guntiltdir=0; + + agunStatus->IAmFar=1; + agunStatus->Firing=0; + agunStatus->Drama=0; + agunStatus->OnTarget=0; + agunStatus->OnTarget_LastFrame=0; + agunStatus->WhirrSoundOn=0; + agunStatus->GunFlash=NULL; + agunStatus->soundHandle=SOUND_NOACTIVEINDEX; + agunStatus->soundHandle2=SOUND_NOACTIVEINDEX; + + agunStatus->ammo=toolsData->ammo; + agunStatus->roundsFired=0; + agunStatus->volleyFired=0; + + agunStatus->incidentFlag=0; + agunStatus->incidentTimer=0; + + agunStatus->HModelController.section_data=NULL; + agunStatus->HModelController.Deltas=NULL; + + for(i=0;ideath_target_ID[i] =toolsData->death_target_ID[i]; + agunStatus->death_target_sbptr=0; + agunStatus->death_target_request=toolsData->death_target_request; + + root_section=GetNamedHierarchyFromLibrary("sentry","gun"); + + if (!root_section) { + RemoveBehaviourStrategy(sbPtr); + return; + } + Create_HModel(&agunStatus->HModelController,root_section); + InitHModelSequence(&agunStatus->HModelController,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED); + + { + DELTA_CONTROLLER *delta; + + delta=Add_Delta_Sequence(&agunStatus->HModelController,"GunTilt",(int)HMSQT_Xenoborg,(int)XBSS_Head_Vertical_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + delta=Add_Delta_Sequence(&agunStatus->HModelController,"GunPan",(int)HMSQT_Xenoborg,(int)XBSS_Head_Horizontal_Delta,0); + GLOBALASSERT(delta); + delta->timer=32767; + delta->Active=0; + + } + + /* Containment test NOW! */ + if(!(sbPtr->containingModule)) + { + /* no containing module can be found... abort*/ + RemoveBehaviourStrategy(sbPtr); + return; + } + LOCALASSERT(sbPtr->containingModule); + } + else + { + /* no data block can be allocated */ + RemoveBehaviourStrategy(sbPtr); + return; + } + +} + +void MakeSentrygunFar(STRATEGYBLOCK *sbPtr) +{ + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + int i; + + LOCALASSERT(sbPtr); + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + LOCALASSERT(sbPtr->SBdptr != NULL); + + /* get rid of the displayblock */ + i = DestroyActiveObject(sbPtr->SBdptr); + LOCALASSERT(i==0); + sbPtr->SBdptr = NULL; + + /* if we have any gun flashes, get rid of them */ + if(agunStatusPointer->GunFlash) + { + RemoveNPCGunFlashEffect(agunStatusPointer->GunFlash); + agunStatusPointer->GunFlash = NULL; + } + + /* agun data block init */ + if(agunStatusPointer->behaviourState != I_disabled) { + agunStatusPointer->stateTimer=0; + } + + /* zero linear velocity in dynamics block */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + agunStatusPointer->IAmFar=1; + +} + +static void Autogun_VerifyDeltaControllers(STRATEGYBLOCK *sbPtr) { + + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + + LOCALASSERT(sbPtr); + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + + /* Nothing has deltas like a xenoborg does. */ + /* But sentryguns try their best. */ + + agunStatusPointer->gun_pan=Get_Delta_Sequence(&agunStatusPointer->HModelController,"GunPan"); + GLOBALASSERT(agunStatusPointer->gun_pan); + + agunStatusPointer->gun_tilt=Get_Delta_Sequence(&agunStatusPointer->HModelController,"GunTilt"); + GLOBALASSERT(agunStatusPointer->gun_tilt); + +} + +static void AGun_ComputeDeltaValues(STRATEGYBLOCK *sbPtr) +{ + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + int angle; + + LOCALASSERT(sbPtr); + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + + /* Interpret all status block values, and apply to deltas. */ + /* Gun Pan first. */ + + angle=agunStatusPointer->Gun_Pan>>4; + + if (angle>=3072) angle-=4096; + if (angle>=2048) angle=angle-4096; + + GLOBALASSERT(agunStatusPointer->gun_pan); + + /* Now, we have an angle. */ + + if (angle>SGUN_PAN_GIMBALL) { + angle=SGUN_PAN_GIMBALL; + } else if (angle<-SGUN_PAN_GIMBALL) { + angle=-SGUN_PAN_GIMBALL; + } + + { + int fake_timer; + + if (angle>0) { + + fake_timer=DIV_FIXED(angle,(SGUN_PAN_GIMBALL<<1)); + fake_timer+=32767; + if (fake_timer>=65536) fake_timer=65535; + if (fake_timer<=0) fake_timer=0; + + } else { + + fake_timer=DIV_FIXED(angle,(SGUN_PAN_GIMBALL<<1)); + fake_timer+=32767; + if (fake_timer>=65536) fake_timer=65535; + if (fake_timer<=0) fake_timer=0; + + } + + GLOBALASSERT(fake_timer>=0); + GLOBALASSERT(fake_timer<65536); + + if (agunStatusPointer->gun_pan->timer!=fake_timer) { + agunStatusPointer->WhirrSoundOn=1; + } + agunStatusPointer->gun_pan->timer=fake_timer; + + } + + /* Gun Tilt... */ + + angle=agunStatusPointer->Gun_Tilt>>4; + + if (angle>=3072) angle-=4096; + if (angle>=2048) angle=angle-3072; + if (angle> 1024) angle=2048-angle; + + GLOBALASSERT(agunStatusPointer->gun_tilt); + + /* Now, we have an angle. */ + + if (angle>SGUN_PITCH_GIMBALL) { + angle=SGUN_PITCH_GIMBALL; + } else if (angle<-SGUN_PITCH_GIMBALL) { + angle=-SGUN_PITCH_GIMBALL; + } + + GLOBALASSERT(angle>=-1024); + GLOBALASSERT(angle<=1024); + + { + int fake_timer; + + fake_timer=1024-angle; + fake_timer<<=5; + if (fake_timer==65536) fake_timer=65535; + + fake_timer=65536-fake_timer; + + GLOBALASSERT(fake_timer>=0); + GLOBALASSERT(fake_timer<65536); + + if (agunStatusPointer->gun_tilt->timer!=fake_timer) { + agunStatusPointer->WhirrSoundOn=1; + } + agunStatusPointer->gun_tilt->timer=fake_timer; + + } + +} + +void AGun_UpdateTargetTrackPos(STRATEGYBLOCK *sbPtr) { + + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + + LOCALASSERT(sbPtr); + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + + if (agunStatusPointer->Target==NULL) { + agunStatusPointer->targetTrackPos.vx=0; + agunStatusPointer->targetTrackPos.vy=0; + agunStatusPointer->targetTrackPos.vz=0; + return; + } + + GetTargetingPointOfObject_Far(agunStatusPointer->Target,&agunStatusPointer->targetTrackPos); + +} + +int Autogun_TargetFilter(STRATEGYBLOCK *candidate) { + + /* Reject NULLs and far targets. */ + if (candidate==NULL) { + return(0); + } + + if (candidate->SBdptr==NULL) { + return(0); + } + + /* Shoot pretty much anything. */ + switch (candidate->I_SBtype) { + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + { + if (Observer) { + return(0); + } + + switch(AvP.PlayerType) + { + case I_Alien: + case I_Predator: + return(1); + break; + case I_Marine: + return(0); + break; + default: + GLOBALASSERT(0); + return(0); + break; + } + break; + } + case I_BehaviourDummy: + { + DUMMY_STATUS_BLOCK *dummyStatusPointer; + dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(candidate->SBdataptr); + LOCALASSERT(dummyStatusPointer); + switch (dummyStatusPointer->PlayerType) { + case I_Alien: + case I_Predator: + return(1); + break; + case I_Marine: + return(1); + break; + default: + GLOBALASSERT(0); + return(0); + break; + } + break; + } + case I_BehaviourAlien: + case I_BehaviourQueenAlien: + case I_BehaviourFaceHugger: + case I_BehaviourPredator: + case I_BehaviourPredatorAlien: + { + if (NPC_IsDead(candidate)) { + return(0); + } else { + return(1); + } + break; + } + case I_BehaviourSeal: + case I_BehaviourMarine: + { + if (NPC_IsDead(candidate)) { + return(0); + } else { + return(0); + } + break; + } + case I_BehaviourXenoborg: + return(1); + break; + #if SupportWindows95 + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *dataptr; + dataptr=candidate->SBdataptr; + switch (dataptr->type) { + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + return(1); + break; + default: + return(1); + break; + } + } + break; + #endif + default: + return(0); + break; + } + +} + +STRATEGYBLOCK *Autogun_GetNewTarget(STRATEGYBLOCK *sbPtr) { + + int neardist; + STRATEGYBLOCK *nearest; + int a; + STRATEGYBLOCK *candidate; + MODULE *dmod; + + dmod=ModuleFromPosition((&sbPtr->DynPtr->Position),playerPherModule); + + LOCALASSERT(dmod); + + nearest=NULL; + neardist=ONE_FIXED; + + for (a=0; aDynPtr) { + if (Autogun_TargetFilter(candidate)) { + VECTORCH offset; + int dist; + + offset.vx=(&sbPtr->DynPtr->Position)->vx-candidate->DynPtr->Position.vx; + offset.vy=(&sbPtr->DynPtr->Position)->vy-candidate->DynPtr->Position.vy; + offset.vz=(&sbPtr->DynPtr->Position)->vz-candidate->DynPtr->Position.vz; + + dist=Approximate3dMagnitude(&offset); + + if (distcontainingModule))) { + nearest=candidate; + } + } + } + } + } + } + } + } + + return(nearest); + +} + +int AGunSight_FrustrumReject(VECTORCH *localOffset) { + + VECTORCH fixed_offset; + + #if 0 + PrintDebuggingText("Local Offset: %d %d %d\n",localOffset->vx,localOffset->vy,localOffset->vz); + #endif + + fixed_offset=*localOffset; + fixed_offset.vy-=300; /* ish */ + + if ((fixed_offset.vz <0) && ( + ((fixed_offset.vy) < (-fixed_offset.vz))&&(fixed_offset.vy>=0)) + ||((fixed_offset.vy<0)&&((-fixed_offset.vy) < (-fixed_offset.vz)) + )) { + /* 180 horizontal, 90 vertical. */ + return(1); + } else { + return(0); + } + +} + +void AutoGunBehaveFun(STRATEGYBLOCK* sbPtr) { + + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + int agunIsNear; + + LOCALASSERT(sbPtr); + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + + /* test if we've got a containing module: if we haven't, do nothing. + This is important as the object could have been marked for deletion by the visibility + management system...*/ + if(!sbPtr->containingModule) + { + DestroyAnyStrategyBlock(sbPtr); /* just to make sure */ + return; + } + + if(sbPtr->SBdptr) { + agunIsNear=1; + LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]); + } else { + agunIsNear=0; + } + + Autogun_VerifyDeltaControllers(sbPtr); + + /* zero velocity */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + sbPtr->DynPtr->LinImpulse.vx = 0; + sbPtr->DynPtr->LinImpulse.vy = 0; + sbPtr->DynPtr->LinImpulse.vz = 0; + + /* Target handling. */ + if (Validate_Target(agunStatusPointer->Target,agunStatusPointer->Target_SBname)==0) { + agunStatusPointer->Target=NULL; + } + + if (agunStatusPointer->Target) { + if (!(Autogun_TargetFilter(agunStatusPointer->Target))) { + agunStatusPointer->Target=NULL; + } + } + + if (agunStatusPointer->Firing) { + agunStatusPointer->Firing-=NormalFrameTime; + } + if (agunStatusPointer->Firing<0) { + agunStatusPointer->Firing=0; + } + + if (agunStatusPointer->Target==NULL) { + //if ((agunIsNear)||(agunStatusPointer->incidentFlag)) { + if (agunIsNear) { + /* Get new target. */ + agunStatusPointer->Target=Autogun_GetNewTarget(sbPtr); + if (agunStatusPointer->Target) { + COPY_NAME(agunStatusPointer->Target_SBname,agunStatusPointer->Target->SBname); + } + AGun_UpdateTargetTrackPos(sbPtr); + } + } else if (NPCCanSeeTarget(sbPtr,agunStatusPointer->Target,AGUN_NEAR_VIEW_WIDTH)) { + AGun_UpdateTargetTrackPos(sbPtr); + } else { + /* We have a target that we can't see. */ + agunStatusPointer->Target=NULL; + AGun_UpdateTargetTrackPos(sbPtr); + } + + /* Unset incident flag. */ + agunStatusPointer->incidentFlag=0; + agunStatusPointer->incidentTimer-=NormalFrameTime; + + if (agunStatusPointer->incidentTimer<0) { + agunStatusPointer->incidentFlag=1; + agunStatusPointer->incidentTimer=32767+(FastRandom()&65535); + } + + if (sbPtr->SBDamageBlock.IsOnFire) { + + /* Why not? */ + CauseDamageToObject(sbPtr,&firedamage,NormalFrameTime,NULL); + + if (agunStatusPointer->incidentFlag) { + if ((FastRandom()&65535)<32767) { + sbPtr->SBDamageBlock.IsOnFire=0; + } + } + + } + + /* Now, switch by state. */ + switch (agunStatusPointer->behaviourState) { + case I_inactive: + AGunMovement_Centre(sbPtr,2); + agunStatusPointer->Target=NULL; + break; + case I_tracking: + if (agunStatusPointer->Target==NULL) { + AGunMovement_ScanLeftRight(sbPtr,2); + } else { + Execute_AGun_Target(sbPtr); + } + break; + case I_disabled: + /* Dying function. */ + Execute_AGun_Dying(sbPtr); + break; + default: + /* No action? */ + break; + } + + /* if we have actually died, we need to remove the strategyblock... so + do this here */ + if((agunStatusPointer->behaviourState == I_disabled)&&(agunStatusPointer->stateTimer <= 0)) { + + DestroyAnyStrategyBlock(sbPtr); + } + + agunStatusPointer->WhirrSoundOn=0; + AGun_ComputeDeltaValues(sbPtr); + if ((agunStatusPointer->WhirrSoundOn)&&(agunStatusPointer->behaviourState!=I_disabled)) { + int dist; + + dist=VectorDistance(&Player->ObWorld,&sbPtr->DynPtr->Position); + + if (distsoundHandle2==SOUND_NOACTIVEINDEX) { + SentryWhirr_SoundData.position=sbPtr->DynPtr->Position; + Sound_Play(SID_ED_SENTRYTURN01,"nel",&SentryWhirr_SoundData,&agunStatusPointer->soundHandle2); + } else { + GLOBALASSERT(ActiveSounds[agunStatusPointer->soundHandle2].soundIndex==SID_ED_SENTRYTURN01); + } + } else { + /* Stop whirr sound. */ + if (agunStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) { + Sound_Stop(agunStatusPointer->soundHandle2); + } + } + } else { + /* Stop whirr sound. */ + if (agunStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) { + Sound_Stop(agunStatusPointer->soundHandle2); + } + } + + /* Verify firing. */ + if (agunStatusPointer->behaviourState == I_disabled) { + agunStatusPointer->Firing=0; + } + + ProveHModel_Far(&agunStatusPointer->HModelController,sbPtr); + + /* Now, are we firing? */ + + if (agunStatusPointer->IAmFar) { + /* Just to be sure, for now. */ + agunStatusPointer->Firing=0; + } + AGun_MaintainGun(sbPtr); + + /* Think sounds. */ + if (agunStatusPointer->Firing==0) { + if (agunStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + if (ActiveSounds[agunStatusPointer->soundHandle].soundIndex==SID_SENTRY_GUN) { + Sound_Play(SID_SENTRY_END,"d",&sbPtr->DynPtr->Position); + } + Sound_Stop(agunStatusPointer->soundHandle); + } + /* Sequences! */ + if (agunStatusPointer->HModelController.Sub_Sequence!=XBSS_Powered_Up_Standard) { + InitHModelTweening(&agunStatusPointer->HModelController,(ONE_FIXED>>3),(int)HMSQT_Xenoborg,XBSS_Powered_Up_Standard,(ONE_FIXED),1); + } + } else { + if (agunStatusPointer->HModelController.Sub_Sequence!=XBSS_Fire_Bolter) { + InitHModelTweening(&agunStatusPointer->HModelController,(ONE_FIXED>>3),(int)HMSQT_Xenoborg,XBSS_Fire_Bolter,(ONE_FIXED>>2),1); + } + } + + if (agunStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Update3d(agunStatusPointer->soundHandle,&sbPtr->DynPtr->Position); + } + +} + +void AGunMovement_ScanLeftRight(STRATEGYBLOCK *sbPtr,int rate) +{ + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + + LOCALASSERT(sbPtr); + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + + /* Let's wave the gun around, half full tracking. */ + if (agunStatusPointer->gunpandir) { + agunStatusPointer->Gun_Pan+=(NormalFrameTime>>rate); + if (agunStatusPointer->Gun_Pan>(SGUN_PAN_GIMBALL<<3)) { + agunStatusPointer->Gun_Pan=(SGUN_PAN_GIMBALL<<3); + agunStatusPointer->gunpandir=0; + } + } else { + agunStatusPointer->Gun_Pan-=(NormalFrameTime>>rate); + if (agunStatusPointer->Gun_Pan<-(SGUN_PAN_GIMBALL<<3)) { + agunStatusPointer->Gun_Pan=-(SGUN_PAN_GIMBALL<<3); + agunStatusPointer->gunpandir=1; + } + } + if (agunStatusPointer->gun_pan) { + agunStatusPointer->gun_pan->Active=1; + } + + /* And centre tilt. */ + if (agunStatusPointer->Gun_Tilt<0) { + agunStatusPointer->Gun_Tilt+=(NormalFrameTime>>rate); + if (agunStatusPointer->Gun_Tilt>(SGUN_PAN_GIMBALL<<3)) { + agunStatusPointer->Gun_Tilt=(SGUN_PAN_GIMBALL<<3); + } else if (agunStatusPointer->Gun_Tilt>0) { + agunStatusPointer->Gun_Tilt=0; + } + } else if (agunStatusPointer->Gun_Tilt>0) { + agunStatusPointer->Gun_Tilt-=(NormalFrameTime>>rate); + if (agunStatusPointer->Gun_Tilt<-(SGUN_PAN_GIMBALL<<3)) { + agunStatusPointer->Gun_Tilt=-(SGUN_PAN_GIMBALL<<3); + } else if (agunStatusPointer->Gun_Tilt<0) { + agunStatusPointer->Gun_Tilt=0; + } + } + if (agunStatusPointer->gun_tilt) { + agunStatusPointer->gun_tilt->Active=1; + } +} + +void AGunMovement_Centre(STRATEGYBLOCK *sbPtr,int rate) +{ + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + + LOCALASSERT(sbPtr); + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + + /* Let's centre pan... */ + if (agunStatusPointer->Gun_Pan<0) { + agunStatusPointer->Gun_Pan+=(NormalFrameTime>>rate); + if (agunStatusPointer->Gun_Pan>(SGUN_PAN_GIMBALL<<3)) { + agunStatusPointer->Gun_Pan=(SGUN_PAN_GIMBALL<<3); + } else if (agunStatusPointer->Gun_Pan>0) { + agunStatusPointer->Gun_Pan=0; + } + } else if (agunStatusPointer->Gun_Pan>0) { + agunStatusPointer->Gun_Pan-=(NormalFrameTime>>rate); + if (agunStatusPointer->Gun_Pan<-(SGUN_PAN_GIMBALL<<3)) { + agunStatusPointer->Gun_Pan=-(SGUN_PAN_GIMBALL<<3); + } else if (agunStatusPointer->Gun_Pan<0) { + agunStatusPointer->Gun_Pan=0; + } + } + if (agunStatusPointer->gun_pan) { + agunStatusPointer->gun_pan->Active=1; + } + + /* And centre tilt. */ + if (agunStatusPointer->Gun_Tilt<0) { + agunStatusPointer->Gun_Tilt+=(NormalFrameTime>>rate); + if (agunStatusPointer->Gun_Tilt>(SGUN_PAN_GIMBALL<<3)) { + agunStatusPointer->Gun_Tilt=(SGUN_PAN_GIMBALL<<3); + } else if (agunStatusPointer->Gun_Tilt>0) { + agunStatusPointer->Gun_Tilt=0; + } + } else if (agunStatusPointer->Gun_Tilt>0) { + agunStatusPointer->Gun_Tilt-=(NormalFrameTime>>rate); + if (agunStatusPointer->Gun_Tilt<-(SGUN_PAN_GIMBALL<<3)) { + agunStatusPointer->Gun_Tilt=-(SGUN_PAN_GIMBALL<<3); + } else if (agunStatusPointer->Gun_Tilt<0) { + agunStatusPointer->Gun_Tilt=0; + } + } + if (agunStatusPointer->gun_tilt) { + agunStatusPointer->gun_tilt->Active=1; + } +} + +void AGun_GetRelativeAngles(STRATEGYBLOCK *sbPtr, int *anglex, int *angley, VECTORCH *pivotPoint) { + + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + MATRIXCH WtoL; + VECTORCH targetPos; + + LOCALASSERT(sbPtr); + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + + /* First, extract relative angle. */ + + WtoL=sbPtr->DynPtr->OrientMat; + TransposeMatrixCH(&WtoL); + targetPos=agunStatusPointer->targetTrackPos; + targetPos.vx-=pivotPoint->vx; + targetPos.vy-=pivotPoint->vy; + targetPos.vz-=pivotPoint->vz; + RotateVector(&targetPos,&WtoL); + + /* Now... */ + { + int offsetx,offsety,offsetz,offseta; + + offsetx=(targetPos.vx); + offsety=(targetPos.vz); + offseta=-(targetPos.vy); + + while( (offsetx>(ONE_FIXED>>2)) + ||(offsety>(ONE_FIXED>>2)) + ||(offseta>(ONE_FIXED>>2)) + ||(offsetx<-(ONE_FIXED>>2)) + ||(offsety<-(ONE_FIXED>>2)) + ||(offseta<-(ONE_FIXED>>2))) { + + offsetx>>=1; + offsety>>=1; + offseta>>=1; + + } + + offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety)); + + if (angley) { + (*angley)=ArcTan(offseta,offsetz); + + if ((*angley)>=3072) (*angley)-=4096; + if ((*angley)>=2048) (*angley)=(*angley)-3072; + if ((*angley)> 1024) (*angley)=2048-(*angley); + + } + if (anglex) { + (*anglex)=ArcTan(offsetx,offsety); + + if ((*anglex)>=3072) (*anglex)-=4096; + if ((*anglex)>=2048) (*anglex)=(*anglex)-4096; + + } + } + +} + +int AGunMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley) +{ + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + int real_anglex,angley,online; + + LOCALASSERT(sbPtr); + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + + /* Turn the gun to face a certain way. */ + + real_anglex=in_anglex; + angley=in_angley; + online=0; + + /* Now fix multiples. */ + while ((real_anglex>4095)||(real_anglex<0)) { + if (real_anglex<0) { + real_anglex+=4096; + } else if (real_anglex>4095) { + real_anglex-=4096; + } + } + + if (real_anglex>=3072) real_anglex-=4096; + if (real_anglex>=2048) real_anglex=real_anglex-3072; + if (real_anglex> 1024) real_anglex=2048-real_anglex; + + if (angley>=3072) angley-=4096; + if (angley>=2048) angley=angley-3072; + if (angley> 1024) angley=2048-angley; + + real_anglex<<=4; + angley<<=4; + + if (agunStatusPointer->Gun_PanGun_Pan+=(NormalFrameTime>>rate); + if (agunStatusPointer->Gun_Pan>(SGUN_PAN_GIMBALL<<4)) { + agunStatusPointer->Gun_Pan=(SGUN_PAN_GIMBALL<<4); + } else if (agunStatusPointer->Gun_Pan>real_anglex) { + agunStatusPointer->Gun_Pan=real_anglex; + online++; + } + } else if (agunStatusPointer->Gun_Pan>real_anglex) { + agunStatusPointer->Gun_Pan-=(NormalFrameTime>>rate); + if (agunStatusPointer->Gun_Pan<-(SGUN_PAN_GIMBALL<<4)) { + agunStatusPointer->Gun_Pan=-(SGUN_PAN_GIMBALL<<4); + } else if (agunStatusPointer->Gun_PanGun_Pan=real_anglex; + online++; + } + } else { + online++; + } + + if (agunStatusPointer->gun_pan) { + agunStatusPointer->gun_pan->Active=1; + } + + /* Now y. */ + angley=-angley; + /* Oops. */ + + /* Note that Sentryguns now only track vertically HALF their full traverse. */ + /* Those shifts used to be <<4. */ + + if (agunStatusPointer->Gun_TiltGun_Tilt+=(NormalFrameTime>>rate); + if (agunStatusPointer->Gun_Tilt>(SGUN_PITCH_GIMBALL<<3)) { + agunStatusPointer->Gun_Tilt=(SGUN_PITCH_GIMBALL<<3); + } else if (agunStatusPointer->Gun_Tilt>angley) { + agunStatusPointer->Gun_Tilt=angley; + online++; + } + } else if (agunStatusPointer->Gun_Tilt>angley) { + agunStatusPointer->Gun_Tilt-=(NormalFrameTime>>rate); + if (agunStatusPointer->Gun_Tilt<-(SGUN_PITCH_GIMBALL<<3)) { + agunStatusPointer->Gun_Tilt=-(SGUN_PITCH_GIMBALL<<3); + } else if (agunStatusPointer->Gun_TiltGun_Tilt=angley; + online++; + } + } else { + online++; + } + + if (agunStatusPointer->gun_tilt) { + agunStatusPointer->gun_tilt->Active=1; + } + + if (online>1) { + return(1); + } else { + return(0); + } +} + +void Execute_AGun_Target(STRATEGYBLOCK *sbPtr) { + + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + int anglex,angley; + + LOCALASSERT(sbPtr); + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + + { + SECTION_DATA *gun_section; + + gun_section=GetThisSectionData(agunStatusPointer->HModelController.section_data,"gun"); + GLOBALASSERT(gun_section); + + AGun_GetRelativeAngles(sbPtr,&anglex,&angley,&gun_section->World_Offset); + + } + + agunStatusPointer->OnTarget_LastFrame=agunStatusPointer->OnTarget; + + if (AGunMovement_TrackToAngles(sbPtr,2,anglex,angley)) { + /* Pointing at target! */ + agunStatusPointer->OnTarget=1; + + if (agunStatusPointer->OnTarget_LastFrame==0) { + /* Newly aquired! */ + //Sound_Play(SID_SENTRYGUN_LOCK,"d",&sbPtr->DynPtr->Position); + agunStatusPointer->Drama=SENTRYGUN_DRAMA; + } + + if (agunStatusPointer->Drama<=0) { + if (agunStatusPointer->Firing==0) { + /* Renew firing. */ + agunStatusPointer->Firing=(ONE_FIXED>>1); + } + } else { + agunStatusPointer->Firing=0; + agunStatusPointer->Drama-=NormalFrameTime; + if (agunStatusPointer->Drama<0) { + agunStatusPointer->Drama=0; + } + } + } else { + agunStatusPointer->OnTarget=0; + }; + +} + +void AGun_MaintainGun(STRATEGYBLOCK *sbPtr) +{ + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + SECTION_DATA *dum; + VECTORCH alpha; + VECTORCH beta; + int multiple,volley_section,totalrounds; + + LOCALASSERT(sbPtr); + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + + dum=GetThisSectionData(agunStatusPointer->HModelController.section_data,"flash dummy"); + + if ((agunStatusPointer->Firing==0)||(dum==NULL)||(agunStatusPointer->IAmFar)) { + /* Not firing, go away. */ + if (agunStatusPointer->GunFlash) { + RemoveNPCGunFlashEffect(agunStatusPointer->GunFlash); + agunStatusPointer->GunFlash = NULL; + } + return; + } + + /* Okay, must be firing. Did we get anyone? */ + + volley_section=AGUN_ROF*NormalFrameTime; + + agunStatusPointer->volleyFired+=volley_section; + if (agunStatusPointer->volleyFired>(AGUN_VOLLEYSIZE<volleyFired=(AGUN_VOLLEYSIZE<volleyFired>>ONE_FIXED_SHIFT; + GLOBALASSERT(totalrounds>=agunStatusPointer->roundsFired); + multiple=totalrounds-agunStatusPointer->roundsFired; + + if ((multiple)&&(agunStatusPointer->ammo==0)) { + /* Click ineffectually. */ + if (agunStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + if (ActiveSounds[agunStatusPointer->soundHandle].soundIndex!=SID_NOAMMO) { + Sound_Stop(agunStatusPointer->soundHandle); + } + } + if (agunStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) { + Sound_Play(SID_NOAMMO,"del",&sbPtr->DynPtr->Position,&agunStatusPointer->soundHandle); + } + if(agunStatusPointer->GunFlash) + { + RemoveNPCGunFlashEffect(agunStatusPointer->GunFlash); + agunStatusPointer->GunFlash = NULL; + } + return; + } + + if (multiple>agunStatusPointer->ammo) { + multiple=agunStatusPointer->ammo; + agunStatusPointer->ammo=0; + } else { + agunStatusPointer->ammo-=multiple; + } + agunStatusPointer->roundsFired+=multiple; + + multiple; + + /* End of volley? */ + if (agunStatusPointer->volleyFired==(AGUN_VOLLEYSIZE<volleyFired=0; + agunStatusPointer->roundsFired=0; + agunStatusPointer->Target=NULL; + } + + while (multiple) { + /* Set up LOS. */ + //get a random rotation , for error in firing direction + MATRIXCH rotate; + + multiple--; + + { + EULER e; + //convert angle from degrees to the engine units + int spread=(SentrygunSpread*4096)/360; + e.EulerX=(MUL_FIXED(FastRandom()&0xffff,spread*2)-spread)&wrap360; + e.EulerY=(MUL_FIXED(FastRandom()&0xffff,spread*2)-spread)&wrap360; + e.EulerZ=0; + CreateEulerMatrix(&e,&rotate); + } + alpha = dum->World_Offset; + beta.vx=dum->SecMat.mat31; + beta.vy=dum->SecMat.mat32; + beta.vz=dum->SecMat.mat33; + + RotateVector(&beta,&rotate); + + FindPolygonInLineOfSight(&beta,&alpha,0,sbPtr->SBdptr); + + /* Now deal with LOS_ObjectHitPtr. */ + if (LOS_ObjectHitPtr) { + if (LOS_HModel_Section) { + if (LOS_ObjectHitPtr->ObStrategyBlock) { + if (LOS_ObjectHitPtr->ObStrategyBlock->SBdptr) { + GLOBALASSERT(LOS_ObjectHitPtr->ObStrategyBlock->SBdptr->HModelControlBlock==LOS_HModel_Section->my_controller); + } + } + } + + /*Don't allow the sentrygun to destroy 'special' inanimate objects. + Doing so ruins some puzzles*/ + if(LOS_ObjectHitPtr->ObStrategyBlock) + { + STRATEGYBLOCK* hit_sbptr=LOS_ObjectHitPtr->ObStrategyBlock; + if(hit_sbptr->I_SBtype==I_BehaviourInanimateObject) + { + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr=(INANIMATEOBJECT_STATUSBLOCK*)hit_sbptr->SBdataptr; + if(objectstatusptr->event_target) + { + /*This object has best be left*/ + continue; + } + + } + } + + /* this fn needs updating to take amount of damage into account etc. */ + HandleWeaponImpact(&LOS_Point,LOS_ObjectHitPtr->ObStrategyBlock,AMMO_AUTOGUN,&beta, ONE_FIXED, LOS_HModel_Section); + } + } + + /* Do muzzle flash... */ + if (agunStatusPointer->GunFlash==NULL) { + agunStatusPointer->GunFlash = AddNPCGunFlashEffect( + &dum->World_Offset,&dum->SecMat, + SFX_MUZZLE_FLASH_SMARTGUN); + } else { + MaintainNPCGunFlashEffect(agunStatusPointer->GunFlash,&dum->World_Offset,&dum->SecMat); + } + /* Do the sound. */ + if (agunStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + if (ActiveSounds[agunStatusPointer->soundHandle].soundIndex!=SID_SENTRY_GUN) { + Sound_Stop(agunStatusPointer->soundHandle); + } + } + if (agunStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) { + + SentryFire_SoundData.position=sbPtr->DynPtr->Position; + + Sound_Play(SID_SENTRY_GUN,"nel",&SentryFire_SoundData,&agunStatusPointer->soundHandle); + } + +} + +void Execute_AGun_Dying(STRATEGYBLOCK *sbPtr) +{ + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + + LOCALASSERT(sbPtr); + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + + /* Droop the gun. */ + if (agunStatusPointer->Gun_Tilt<8192) { + agunStatusPointer->Gun_Tilt+=(NormalFrameTime>>3); + if (agunStatusPointer->Gun_Tilt>(SGUN_PITCH_GIMBALL<<3)) { + agunStatusPointer->Gun_Tilt=(SGUN_PITCH_GIMBALL<<3); + } else if (agunStatusPointer->Gun_Tilt>8192) { + agunStatusPointer->Gun_Tilt=8192; + } + } + + { + DISPLAYBLOCK *dispPtr = sbPtr->SBdptr; + /* do we have a displayblock? */ + if (dispPtr) + { + dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND; + dispPtr->ObFlags2 = agunStatusPointer->stateTimer/2; + + if (dispPtr->ObFlags2HModelController.DisableBleeding=1; + } + } + } + agunStatusPointer->stateTimer -= NormalFrameTime; +} + +static void KillAGun(STRATEGYBLOCK *sbPtr,int wounds,DAMAGE_PROFILE *damage, int multiple,VECTORCH *incoming) +{ + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + + LOCALASSERT(sbPtr); + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + + /* make an explosion sound */ + Sound_Play(SID_SENTRYGUNDEST,"d",&sbPtr->DynPtr->Position); + + agunStatusPointer->stateTimer=AGUN_DYINGTIME; + agunStatusPointer->HModelController.Looped=0; + agunStatusPointer->HModelController.LoopAfterTweening=0; + /* switch state */ + agunStatusPointer->behaviourState=I_disabled; + + /* Fiddle with sequences? */ + + /* Ensure sufficient sparking. */ + KillRandomSections(agunStatusPointer->HModelController.section_data,(ONE_FIXED>>1)); + + if(agunStatusPointer->death_target_sbptr) + { + RequestState(agunStatusPointer->death_target_sbptr,agunStatusPointer->death_target_request, 0); + } + + if (agunStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + /* Well, it shouldn't be! */ + Sound_Stop(agunStatusPointer->soundHandle); + } + +} + +void AGunIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,VECTORCH *incoming) +{ + + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + + if (sbPtr->SBDamageBlock.Health <= 0) { + + /* Oh yes, kill them, too. */ + if (agunStatusPointer->behaviourState!=I_disabled) { + KillAGun(sbPtr,wounds,damage,multiple,incoming); + } + } + +} + + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" + +typedef struct agun_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + +//behaviour block stuff + AG_STATE behaviourState; + int stateTimer; + + VECTORCH targetTrackPos; + + int Gun_Pan; + int Gun_Tilt; + + int incidentFlag; + int incidentTimer; + + int ammo; + int roundsFired; + int volleyFired; + + int Firing; + int WhirrSoundOn; + int Drama; + + unsigned int createdByPlayer:1; + unsigned int gunpandir :1; + unsigned int guntiltdir :1; + unsigned int IAmFar :1; + + unsigned int OnTarget :1; + unsigned int OnTarget_LastFrame :1; +//annoying pointer related things + + char Target_SBname[SB_NAME_LENGTH]; + + +//strategy block stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; + DYNAMICSBLOCK dynamics; + +}AGUN_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV agunStatusPointer + +void LoadStrategy_Autogun(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + AUTOGUN_STATUS_BLOCK* agunStatusPointer; + AGUN_SAVE_BLOCK* block = (AGUN_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourAutoGun) return; + + agunStatusPointer =(AUTOGUN_STATUS_BLOCK*) sbPtr->SBdataptr; + + + //start copying stuff + COPYELEMENT_LOAD(behaviourState) + COPYELEMENT_LOAD(stateTimer) + COPYELEMENT_LOAD(targetTrackPos) + COPYELEMENT_LOAD(Gun_Pan) + COPYELEMENT_LOAD(Gun_Tilt) + COPYELEMENT_LOAD(incidentFlag) + COPYELEMENT_LOAD(incidentTimer) + COPYELEMENT_LOAD(ammo) + COPYELEMENT_LOAD(roundsFired) + COPYELEMENT_LOAD(volleyFired) + COPYELEMENT_LOAD(Firing) + COPYELEMENT_LOAD(WhirrSoundOn) + COPYELEMENT_LOAD(Drama) + COPYELEMENT_LOAD(createdByPlayer) + COPYELEMENT_LOAD(gunpandir) + COPYELEMENT_LOAD(guntiltdir) + COPYELEMENT_LOAD(IAmFar) + COPYELEMENT_LOAD(OnTarget) + COPYELEMENT_LOAD(OnTarget_LastFrame) + + //load target + COPY_NAME(agunStatusPointer->Target_SBname,block->Target_SBname); + agunStatusPointer->Target = FindSBWithName(agunStatusPointer->Target_SBname); + + + //copy strategy block stuff + *sbPtr->DynPtr = block->dynamics; + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + + //load hierarchy + { + SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); + if(hier_header) + { + LoadHierarchy(hier_header,&agunStatusPointer->HModelController); + } + } + + //get delta controller pointers + Autogun_VerifyDeltaControllers(sbPtr); + + Load_SoundState(&agunStatusPointer->soundHandle); + Load_SoundState(&agunStatusPointer->soundHandle2); + +} + +void SaveStrategy_Autogun(STRATEGYBLOCK* sbPtr) +{ + AUTOGUN_STATUS_BLOCK* agunStatusPointer; + AGUN_SAVE_BLOCK* block; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + agunStatusPointer =(AUTOGUN_STATUS_BLOCK*) sbPtr->SBdataptr; + + //start copying stuff + COPYELEMENT_SAVE(behaviourState) + COPYELEMENT_SAVE(stateTimer) + COPYELEMENT_SAVE(targetTrackPos) + COPYELEMENT_SAVE(Gun_Pan) + COPYELEMENT_SAVE(Gun_Tilt) + COPYELEMENT_SAVE(incidentFlag) + COPYELEMENT_SAVE(incidentTimer) + COPYELEMENT_SAVE(ammo) + COPYELEMENT_SAVE(roundsFired) + COPYELEMENT_SAVE(volleyFired) + COPYELEMENT_SAVE(Firing) + COPYELEMENT_SAVE(WhirrSoundOn) + COPYELEMENT_SAVE(Drama) + COPYELEMENT_SAVE(createdByPlayer) + COPYELEMENT_SAVE(gunpandir) + COPYELEMENT_SAVE(guntiltdir) + COPYELEMENT_SAVE(IAmFar) + COPYELEMENT_SAVE(OnTarget) + COPYELEMENT_SAVE(OnTarget_LastFrame) + + //save target + COPY_NAME(block->Target_SBname,agunStatusPointer->Target_SBname); + + //save strategy block stuff + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; + + //save the hierarchy + SaveHierarchy(&agunStatusPointer->HModelController); + + Save_SoundState(&agunStatusPointer->soundHandle); + Save_SoundState(&agunStatusPointer->soundHandle2); + +} \ No newline at end of file diff --git a/3dc/avp/bh_agun.h b/3dc/avp/bh_agun.h new file mode 100644 index 0000000..26a355f --- /dev/null +++ b/3dc/avp/bh_agun.h @@ -0,0 +1,87 @@ +// RWH - the autogun code + +/* CDF 25/7/98 - Heaven help us. */ + +extern void AutoGunBehaveFun(STRATEGYBLOCK* ag_sbptr); +extern void AutoGunBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr); +//extern void CreatePlayerAutogun(void); + +void MakeSentrygunNear(STRATEGYBLOCK *sbPtr); +void MakeSentrygunFar(STRATEGYBLOCK *sbPtr); +int AGunSight_FrustrumReject(VECTORCH *localOffset); +void AGunIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,VECTORCH *incoming); + +typedef enum { + I_disabled, + I_tracking, + I_inactive, +}AG_STATE; + +typedef struct autogun_behaviour_block +{ + AG_STATE behaviourState; + int stateTimer; + + HMODELCONTROLLER HModelController; + DELTA_CONTROLLER *gun_pan; + DELTA_CONTROLLER *gun_tilt; + + STRATEGYBLOCK *Target; + char Target_SBname[SB_NAME_LENGTH]; + /* A level of indirection for better control. */ + VECTORCH targetTrackPos; + + int Gun_Pan; + int Gun_Tilt; + DISPLAYBLOCK *GunFlash; + + int incidentFlag; + int incidentTimer; + + int ammo; + int roundsFired; + int volleyFired; + + int soundHandle; + int soundHandle2; + int Firing; + int WhirrSoundOn; + int Drama; + + unsigned int createdByPlayer:1; + unsigned int gunpandir :1; + unsigned int guntiltdir :1; + unsigned int IAmFar :1; + + unsigned int OnTarget :1; + unsigned int OnTarget_LastFrame :1; + + char death_target_ID[SB_NAME_LENGTH]; + STRATEGYBLOCK* death_target_sbptr; + int death_target_request; + +}AUTOGUN_STATUS_BLOCK; + + +typedef struct autogun_tools_template +{ + VECTORCH position; + EULER orientation; + + int ammo; + int shapenum; + int startInactive; + + char nameID[SB_NAME_LENGTH]; + + char death_target_ID[SB_NAME_LENGTH]; + int death_target_request; + +}AUTOGUN_TOOLS_TEMPLATE; + +#define SGUN_PITCH_GIMBALL (1024) +#define SGUN_PAN_GIMBALL (1024) +#define AGUN_NEAR_VIEW_WIDTH 500 /* mm */ + +#define AGUN_ROF (30) +#define AGUN_VOLLEYSIZE (15) diff --git a/3dc/avp/bh_ais.c b/3dc/avp/bh_ais.c new file mode 100644 index 0000000..a27054b --- /dev/null +++ b/3dc/avp/bh_ais.c @@ -0,0 +1,4062 @@ +/* CDF 11/6/98 - AI support functions moved out of bh_pred. */ + +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "comp_shp.h" +#include "dynblock.h" +#include "dynamics.h" +#include "pfarlocs.h" +#include "pheromon.h" +#include "bh_types.h" +#include "pvisible.h" +#include "bh_far.h" +#include "bh_debri.h" +#include "bh_pred.h" +#include "bh_paq.h" +#include "bh_queen.h" +#include "bh_marin.h" +#include "bh_alien.h" +#include "bh_agun.h" +#include "lighting.h" +#include "bh_weap.h" +#include "weapons.h" +#include "psnd.h" +#include "equipmnt.h" +#include "los.h" +#include "AI_Sight.h" +#include "targeting.h" +#include "dxlog.h" +#include "ShowCmds.h" +#include "huddefs.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +/* external global variables used in this file */ +extern int ModuleArraySize; +extern char *ModuleCurrVisArray; +extern int NormalFrameTime; +extern SECTION_DATA* LOS_HModel_Section; /* Section of HModel hit */ +extern void HandleWeaponImpact(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, enum AMMO_ID AmmoID, VECTORCH *directionPtr, int multiple, SECTION_DATA *section_pointer); +extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); +extern int GlobalFrameCounter; +extern int RouteFinder_CallsThisFrame; +extern DEATH_DATA Alien_Deaths[]; +extern DEATH_DATA Marine_Deaths[]; +extern DEATH_DATA Predator_Deaths[]; +extern DEATH_DATA Xenoborg_Deaths[]; +extern ATTACK_DATA Alien_Attacks[]; +extern ATTACK_DATA Wristblade_Attacks[]; +extern ATTACK_DATA PredStaff_Attacks[]; +extern int SBIsEnvironment(STRATEGYBLOCK *sbPtr); + +/* From HModel.c! */ +extern void QNormalise(QUAT *q); +extern int IsAIModuleVisibleFromAIModule(AIMODULE *source,AIMODULE *target); + +int IsMyPolyRidiculous(void); +int New_GetAvoidanceDirection(STRATEGYBLOCK *sbPtr, NPC_AVOIDANCEMANAGER *manager, VECTORCH *aggregateNormal); +int New_GetSecondAvoidanceDirection(STRATEGYBLOCK *sbPtr, NPC_AVOIDANCEMANAGER *manager, VECTORCH *aggregateNormal); +void InitialiseThirdAvoidance(STRATEGYBLOCK *sbPtr,NPC_AVOIDANCEMANAGER *manager); +void ClearThirdAvoidance(STRATEGYBLOCK *sbPtr,NPC_AVOIDANCEMANAGER *manager); +int ExecuteThirdAvoidance(STRATEGYBLOCK *sbPtr,NPC_AVOIDANCEMANAGER *manager); +int SimpleEdgeDetectionTest(STRATEGYBLOCK *sbPtr, COLLISIONREPORT *vcr); + +void AlignVelocityToGravity(STRATEGYBLOCK *sbPtr,VECTORCH *velocity); + +int PathArraySize; +PATHHEADER* PathArray; +/* Patrick 4/7/97 -------------------------------------------------- + + BEHAVIOUR SUPPORT FUNCTIONS THAT MAY BE USED BY ANY NPC + +---------------------------------------------------------------------*/ + +int CheckAdjacencyValidity(AIMODULE *target,AIMODULE *source,int alien) { + + FARENTRYPOINT *thisEp = GetAIModuleEP(target, source); + if(thisEp) { + if ((!alien)&&(thisEp->alien_only)) { + return(0); + } else { + return(1); + } + } + return(0); +} + +/* Patrick------------------------------------------------------------- +For chris, or anyone else who wants it... +-----------------------------------------------------------------------*/ +int NPC_IsDead(STRATEGYBLOCK *sbPtr) +{ + LOCALASSERT(sbPtr); + + if(sbPtr->SBflags.please_destroy_me==1) return 1; + + switch(sbPtr->I_SBtype) + { + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + case I_BehaviourMarinePlayer: + { + /* For now. */ + if (PlayerStatusPtr->IsAlive) { + return(0); + } else { + return(1); + } + break; + } + case(I_BehaviourPredator): + { + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + if(predatorStatusPointer->behaviourState==PBS_Dying) return 1; + break; + } + case(I_BehaviourMarine): + case(I_BehaviourSeal): + { + MARINE_STATUS_BLOCK *marineStatusPointer; + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + if(marineStatusPointer->behaviourState==MBS_Dying) return 1; + break; + } + case(I_BehaviourAlien): + { + ALIEN_STATUS_BLOCK *alienStatusPointer; + alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + if(alienStatusPointer->BehaviourState==ABS_Dying) return 1; + break; + } + case(I_BehaviourPredatorAlien): + case(I_BehaviourQueenAlien): + { + PAQ_STATUS_BLOCK *paqStatusPointer; + paqStatusPointer = (PAQ_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(paqStatusPointer); + if(paqStatusPointer->NearBehaviourState==PAQNS_Dying) return 1; + break; + } + case(I_BehaviourNetCorpse): + /* Corpses are always dead :-) */ + return(1); + break; + case I_BehaviourAutoGun: + { + AUTOGUN_STATUS_BLOCK *agunStatusPointer; + + LOCALASSERT(sbPtr); + agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(agunStatusPointer); + + if (agunStatusPointer->behaviourState==I_disabled) { + return(1); + } else { + return(0); + } + } + break; + default: + { + break; + } + } + + return 0; +} + + +/* Patrick------------------------------------------------------------- +This set of 3 functions is used by all npcs in checking for obstructive +collisions, or targets we cannot reach +-----------------------------------------------------------------------*/ +void NPC_InitMovementData(NPC_MOVEMENTDATA *moveData) +{ + LOCALASSERT(moveData); + + moveData->numObstructiveCollisions = 0; + + moveData->avoidanceDirn.vx = 0; + moveData->avoidanceDirn.vy = 0; + moveData->avoidanceDirn.vz = 0; + + moveData->lastTarget.vx = 0; + moveData->lastTarget.vy = 0; + moveData->lastTarget.vz = 0; + + moveData->lastVelocity.vx = 0; + moveData->lastVelocity.vy = 0; + moveData->lastVelocity.vz = 0; + + moveData->numReverses = 0; + + moveData->lastModule=NULL; +} + +void NPC_IsObstructed(STRATEGYBLOCK *sbPtr, NPC_MOVEMENTDATA *moveData, NPC_OBSTRUCTIONREPORT *details, STRATEGYBLOCK **destructableObject) +{ + DYNAMICSBLOCK *dynPtr; + struct collisionreport *nextReport; + VECTORCH velDirn; + AVP_BEHAVIOUR_TYPE myType; + + LOCALASSERT(destructableObject); + LOCALASSERT(details); + LOCALASSERT(moveData); + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + nextReport = dynPtr->CollisionReportPtr; + + /* init destructable object pointer, etc... */ + *destructableObject = NULL; + details->environment = 0; + details->destructableObject = 0; + details->otherCharacter = 0; + details->anySingleObstruction = 0; + + /* check our velocity: if we haven't got one, we can't be obstructed, so just return */ + if((sbPtr->DynPtr->LinVelocity.vx==0)&&(sbPtr->DynPtr->LinVelocity.vy==0)&&(sbPtr->DynPtr->LinVelocity.vz==0)) + { + moveData->numObstructiveCollisions = 0; + return; + } + + /* get my velocity and behaviour type */ + velDirn = dynPtr->LinVelocity; + Normalise(&velDirn); + myType = sbPtr->I_SBtype; + + /* walk the collision report list, looking for collisions that obstruct our movement... + excluding objects of our own type and the player */ + while(nextReport) + { + int IsCharacterOrPlayer = 0; + /* int dotWithGravity; */ + int normalDotWithVelocity; + + if(nextReport->ObstacleSBPtr) + { + if(nextReport->ObstacleSBPtr==Player->ObStrategyBlock) IsCharacterOrPlayer = 1; + if(nextReport->ObstacleSBPtr->I_SBtype==myType) + { + IsCharacterOrPlayer = 1; + details->otherCharacter = 1; + details->anySingleObstruction = 1; + } + } + + { + VECTORCH normVelocity = sbPtr->DynPtr->LinVelocity; + Normalise(&normVelocity); + normalDotWithVelocity = DotProduct(&(nextReport->ObstacleNormal),&(normVelocity)); + } + +// if((normalDotWithVelocity < -46341)&&(!IsCharacterOrPlayer)) + /* So aliens can break through windows, 19/5/98 CDF */ + if((!IsCharacterOrPlayer)&&((normalDotWithVelocity < -46341)||(nextReport->ObstacleSBPtr))) + { + /* aha... got one....*/ + moveData->numObstructiveCollisions++; + if(moveData->numObstructiveCollisions > NPC_IMPEDING_COL_THRESHOLD) + { + moveData->numObstructiveCollisions = 0; + details->anySingleObstruction = 1; + details->environment = 1; + + if(nextReport->ObstacleSBPtr) + { + if(nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourInanimateObject) + { + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = nextReport->ObstacleSBPtr->SBdataptr; + if((objectstatusptr)&&(objectstatusptr->Indestructable == 0)) + { + /* aha: an object which the npc can destroy... */ + *destructableObject = nextReport->ObstacleSBPtr; + details->destructableObject = 1; + details->environment = 0; + } + } + } + } + /* if we have an obstructive collision, then return at this point + to avoid resetting numObstructiveCollisions. NB we only want to + record one per frame anyway... */ + return; + } + nextReport = nextReport->NextCollisionReportPtr; + } + + /* no obstructions this frame, then ... */ + moveData->numObstructiveCollisions = 0; +} + +#if 0 +int NPCIsExperiencingObstructiveCollision(STRATEGYBLOCK *sbPtr, VECTORCH *velocityDirection) +{ + DYNAMICSBLOCK *dynPtr; + struct collisionreport *nextReport; + + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + nextReport = dynPtr->CollisionReportPtr; + + /* check our velocity: if we haven't got one, we can't be obstructed, so just return */ + if((velocityDirection->vx==0)&&(velocityDirection->vy==0)&&(velocityDirection->vz==0)) return 0; + + /* walk the collision report list, looking for collisions against inanimate objects */ + while(nextReport) + { + if(nextReport->ObstacleNormal.vy > -46341) return 1; + nextReport = nextReport->NextCollisionReportPtr; + } + + /* no collision, then ... */ + return 0; +} +#endif + +int NPC_CannotReachTarget(NPC_MOVEMENTDATA *moveData, VECTORCH* thisTarget, VECTORCH* thisVelocity) +{ + LOCALASSERT(moveData); + LOCALASSERT(thisTarget); + LOCALASSERT(thisVelocity); + + /* if movement data has zero velocity, update and return */ + if((moveData->lastVelocity.vx == 0)&& + (moveData->lastVelocity.vy == 0)&& + (moveData->lastVelocity.vz == 0)) + { + moveData->lastVelocity = *thisVelocity; + moveData->lastTarget = *thisTarget; + moveData->numReverses = 0; + return 0; + } + + /* if new velocity is zero, update and return */ + if((thisVelocity->vx == 0)&& + (thisVelocity->vy == 0)&& + (thisVelocity->vz == 0)) + { + moveData->lastVelocity = *thisVelocity; + moveData->lastTarget = *thisTarget; + moveData->numReverses = 0; + return 0; + } + + /* if move data target and this target are different, update and return*/ + if((thisTarget->vx!=moveData->lastTarget.vx)|| + (thisTarget->vy!=moveData->lastTarget.vy)|| + (thisTarget->vz!=moveData->lastTarget.vz)) + { + moveData->lastVelocity = *thisVelocity; + moveData->lastTarget = *thisTarget; + moveData->numReverses = 0; + return 0; + } + + /* at this point we have a previous velocity, a new velocity, + and the previous target is the same as the current target... + so compare previous and new velocities... */ + if(DotProduct(&(moveData->lastVelocity),thisVelocity)<(-56000)) /* 30 degrees */ + { + moveData->lastVelocity = *thisVelocity; + moveData->lastTarget = *thisTarget; + moveData->numReverses++; + if(moveData->numReverses>1) + { + moveData->numReverses = 0; + #if 1 + return 1; + #else + return 0; + #endif + } + else return 0; + } + + /* just update */ + moveData->lastVelocity = *thisVelocity; + moveData->lastTarget = *thisTarget; + moveData->numReverses = 0; + return 0; +} + +/*------------------------------Patrick 14/2/97----------------------------------- + Returns direction of movement to avoid obstructive collision in current + direction of movement... + -------------------------------------------------------------------------------*/ + +/* in this new version, the direction is taken from the npc's current direction (so +that it will work in 3d, for aliens)... and is returned in velocityDirection */ +void NPCGetAvoidanceDirection(STRATEGYBLOCK *sbPtr, VECTORCH *velocityDirection, NPC_OBSTRUCTIONREPORT *details) +{ + VECTORCH newDirection1; + VECTORCH newDirection2; + int dir1dist = 0; + int dir2dist = 0; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + LOCALASSERT(velocityDirection); + + /* init velcity direction */ + velocityDirection->vx = velocityDirection->vy = velocityDirection->vz = 0; + + /* just in case */ + if(!sbPtr->containingModule) return; + + if((details->environment)||(details->destructableObject)||(details->otherCharacter)||(details->anySingleObstruction)) + { + /* going for a 90 degree turn + back a bit */ + + /* construct the direction(s)... + start with object's local x unit vector (from local coo-ord system in world space) */ + newDirection1.vx = sbPtr->DynPtr->OrientMat.mat11; + newDirection1.vy = sbPtr->DynPtr->OrientMat.mat12; + newDirection1.vz = sbPtr->DynPtr->OrientMat.mat13; + newDirection2.vx = -newDirection1.vx; + newDirection2.vy = -newDirection1.vy; + newDirection2.vz = -newDirection1.vz; + /* ...and add on 1/4 of the -z direction...*/ + newDirection1.vx -= (sbPtr->DynPtr->OrientMat.mat31/4); + newDirection1.vy -= (sbPtr->DynPtr->OrientMat.mat32/4); + newDirection1.vz -= (sbPtr->DynPtr->OrientMat.mat33/4); + newDirection2.vx -= (sbPtr->DynPtr->OrientMat.mat31/4); + newDirection2.vy -= (sbPtr->DynPtr->OrientMat.mat32/4); + newDirection2.vz -= (sbPtr->DynPtr->OrientMat.mat33/4); + Normalise(&newDirection1); + Normalise(&newDirection2); + + /* test how far we could go in each direction... */ + { + VECTORCH startingPosition = sbPtr->DynPtr->Position; + VECTORCH testDirn = newDirection1; + + LOS_ObjectHitPtr = (DISPLAYBLOCK *)0; + LOS_Lambda = NPC_MAX_VIEWRANGE; + CheckForVectorIntersectionWith3dObject(sbPtr->containingModule->m_dptr,&startingPosition,&testDirn,0); + if(!LOS_ObjectHitPtr) dir1dist = NPC_MAX_VIEWRANGE; + else dir1dist = LOS_Lambda; + + startingPosition = sbPtr->DynPtr->Position; + testDirn = newDirection2; + LOS_ObjectHitPtr = (DISPLAYBLOCK *)0; + LOS_Lambda = NPC_MAX_VIEWRANGE; + CheckForVectorIntersectionWith3dObject(sbPtr->containingModule->m_dptr,&startingPosition,&testDirn,0); + if(!LOS_ObjectHitPtr) dir2dist = NPC_MAX_VIEWRANGE; + else dir2dist = LOS_Lambda; + } + + if(dir1dist > dir2dist) *velocityDirection = newDirection1; + else *velocityDirection = newDirection2; + } +} + +/* Project actual shot? */ +void ProjectNPCShot(STRATEGYBLOCK *sbPtr, STRATEGYBLOCK *target, VECTORCH *muzzlepos, MATRIXCH *muzzleorient, enum AMMO_ID AmmoID, int multiple) { + + VECTORCH shotVector; /* direction of view-line */ + VECTORCH targetPos; + int mag; + + GetTargetingPointOfObject_Far(target,&targetPos); + + shotVector.vx = targetPos.vx - muzzlepos->vx; + shotVector.vy = targetPos.vy - muzzlepos->vy; + shotVector.vz = targetPos.vz - muzzlepos->vz; + + mag=Approximate3dMagnitude(&shotVector); + + shotVector.vx = MUL_FIXED(muzzleorient->mat31,mag); + shotVector.vy = MUL_FIXED(muzzleorient->mat32,mag); + shotVector.vz = MUL_FIXED(muzzleorient->mat33,mag); + + + mag>>=2; /* For now. */ + + /* Random tweak. */ + shotVector.vx+=((FastRandom()%mag)-(mag>>1)); + shotVector.vy+=((FastRandom()%mag)-(mag>>1)); + shotVector.vz+=((FastRandom()%mag)-(mag>>1)); + /* Normalise. */ + Normalise(&shotVector); + + #if 0 + LOS_Lambda = NPC_MAX_VIEWRANGE; + LOS_ObjectHitPtr = 0; + LOS_HModel_Section=NULL; + { + extern int NumActiveBlocks; + extern DISPLAYBLOCK* ActiveBlockList[]; + int numberOfObjects = NumActiveBlocks; + + while (numberOfObjects--) + { + DISPLAYBLOCK* objectPtr = ActiveBlockList[numberOfObjects]; + VECTORCH alpha = *muzzlepos; + VECTORCH beta = shotVector; + GLOBALASSERT(objectPtr); + + if ((objectPtr!=sbPtr->SBdptr)&&(objectPtr!=target->SBdptr)) { + /* Can't hit target or self. */ + CheckForVectorIntersectionWith3dObject(objectPtr, &alpha, &beta,1); + } + } + } + #else + FindPolygonInLineOfSight_TwoIgnores(&shotVector,muzzlepos,0,sbPtr->SBdptr,target->SBdptr); + #endif + /* Now deal with LOS_ObjectHitPtr. */ + if (LOS_ObjectHitPtr) { + if (LOS_HModel_Section) { + if (LOS_ObjectHitPtr->ObStrategyBlock) { + if (LOS_ObjectHitPtr->ObStrategyBlock->SBdptr) { + GLOBALASSERT(LOS_ObjectHitPtr->ObStrategyBlock->SBdptr->HModelControlBlock==LOS_HModel_Section->my_controller); + } + } + } + /* this fn needs updating to take amount of damage into account etc. */ + HandleWeaponImpact(&LOS_Point,LOS_ObjectHitPtr->ObStrategyBlock,AmmoID,&shotVector, multiple*ONE_FIXED, LOS_HModel_Section); + } + +} + +void CastLOSProjectile(STRATEGYBLOCK *sbPtr, VECTORCH *muzzlepos, VECTORCH *in_shotvector, enum AMMO_ID AmmoID, int multiple, int inaccurate) { + + VECTORCH shotVector; + DISPLAYBLOCK *self; + + shotVector=*in_shotvector; + + if (sbPtr) { + self=sbPtr->SBdptr; + } else { + self=NULL; + } + + /* Normalise. */ + Normalise(&shotVector); + + if (inaccurate) { + /* Random tweak. */ + shotVector.vx+=((FastRandom()%(ONE_FIXED>>2))-(ONE_FIXED>>3)); + shotVector.vy+=((FastRandom()%(ONE_FIXED>>2))-(ONE_FIXED>>3)); + shotVector.vz+=((FastRandom()%(ONE_FIXED>>2))-(ONE_FIXED>>3)); + /* Normalise. */ + Normalise(&shotVector); + } + + #if 0 + LOS_Lambda = NPC_MAX_VIEWRANGE; + LOS_ObjectHitPtr = 0; + LOS_HModel_Section=NULL; + { + extern int NumActiveBlocks; + extern DISPLAYBLOCK* ActiveBlockList[]; + int numberOfObjects = NumActiveBlocks; + + while (numberOfObjects--) + { + DISPLAYBLOCK* objectPtr = ActiveBlockList[numberOfObjects]; + VECTORCH alpha = *muzzlepos; + VECTORCH beta = shotVector; + GLOBALASSERT(objectPtr); + + if (objectPtr!=self) { + /* Can't hit self. */ + CheckForVectorIntersectionWith3dObject(objectPtr, &alpha, &beta,1); + } + } + } + #else + FindPolygonInLineOfSight(&shotVector,muzzlepos,0,self); + #endif + /* Now deal with LOS_ObjectHitPtr. */ + if (LOS_ObjectHitPtr) { + if (LOS_HModel_Section) { + if (LOS_ObjectHitPtr->ObStrategyBlock) { + if (LOS_ObjectHitPtr->ObStrategyBlock->SBdptr) { + GLOBALASSERT(LOS_ObjectHitPtr->ObStrategyBlock->SBdptr->HModelControlBlock==LOS_HModel_Section->my_controller); + } + } + } + /* this fn needs updating to take amount of damage into account etc. */ + HandleWeaponImpact(&LOS_Point,LOS_ObjectHitPtr->ObStrategyBlock,AmmoID,&shotVector, multiple*ONE_FIXED, LOS_HModel_Section); + } + +} + +int VerifyHitShot(STRATEGYBLOCK *sbPtr, STRATEGYBLOCK *target, VECTORCH *muzzlepos, VECTORCH *in_shotvector, enum AMMO_ID AmmoID, int multiple, int maxrange) { + + VECTORCH shotVector; + DISPLAYBLOCK *self,*target_dptr; + + shotVector=*in_shotvector; + + if (sbPtr) { + self=sbPtr->SBdptr; + } else { + self=NULL; + } + + if (target) { + target_dptr=target->SBdptr; + } else { + target_dptr=NULL; + } + + /* Normalise. */ + Normalise(&shotVector); + + FindPolygonInLineOfSight(&shotVector,muzzlepos,0,self); + + /* Now deal with LOS_ObjectHitPtr. */ + if (LOS_Lambda>maxrange) { + return(1); + } + + if (LOS_ObjectHitPtr) { + if (LOS_HModel_Section) { + if (LOS_ObjectHitPtr->ObStrategyBlock) { + if (LOS_ObjectHitPtr->ObStrategyBlock->SBdptr) { + GLOBALASSERT(LOS_ObjectHitPtr->ObStrategyBlock->SBdptr->HModelControlBlock==LOS_HModel_Section->my_controller); + } + } + } + + if ( ((LOS_ObjectHitPtr==target_dptr)&&(target_dptr!=NULL))||(SBIsEnvironment(LOS_ObjectHitPtr->ObStrategyBlock))) { + return(1); + } else { + HandleWeaponImpact(&LOS_Point,LOS_ObjectHitPtr->ObStrategyBlock,AmmoID,&shotVector, multiple*ONE_FIXED, LOS_HModel_Section); + return(0); + } + } + return(1); +} + +/* this function returns a target point for firing a projectile at the player*/ +void NPCGetTargetPosition(VECTORCH *targetPoint, STRATEGYBLOCK *target) +{ + GLOBALASSERT(target); + GLOBALASSERT(targetPoint); + + if (target->SBdptr) + { + GetTargetingPointOfObject_Far(target, targetPoint); + } + else + { + *targetPoint = target->DynPtr->Position; + } +} + +/*------------------------Patrick 31/1/97----------------------------- + Returns 2d approach velocity and time for given NPC, target, and speed + targetDirn must be a normalised vector direction. + --------------------------------------------------------------------*/ +int NPCSetVelocity(STRATEGYBLOCK *sbPtr, VECTORCH* targetDirn, int in_speed) +{ + int orientated,speed; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + LOCALASSERT(targetDirn); + + /* set targetDirn.vy to 0 just in case: if NPCGetTargetDirn is used get the target + direction, the y component should always be 0, but other target directions may be + passed... */ + /* Okay, that was old. But maybe we need to do that unless UseStandardGravity is unset. */ + + /* Set up speed as local, so we can tamper with it. */ + speed=in_speed; + + if ((sbPtr->I_SBtype!=I_BehaviourMarine)&&(sbPtr->I_SBtype!=I_BehaviourPredator) + &&(sbPtr->I_SBtype!=I_BehaviourXenoborg)) { + + if (sbPtr->DynPtr->UseStandardGravity) { + targetDirn->vy = 0; + + /* first check for zero direction vector */ + if((targetDirn->vx==0)&&(targetDirn->vz==0)) + { + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + return(1); + } + } + + orientated=NPCOrientateToVector(sbPtr, targetDirn,NPC_TURNRATE,NULL); + + { + VECTORCH velocity; + VECTORCH yDirection; + int dotProduct; + + yDirection.vx = sbPtr->DynPtr->OrientMat.mat21; + yDirection.vy = sbPtr->DynPtr->OrientMat.mat22; + yDirection.vz = sbPtr->DynPtr->OrientMat.mat23; + + dotProduct = DotProduct(&yDirection,targetDirn); + + velocity.vx = targetDirn->vx - MUL_FIXED(yDirection.vx,dotProduct); + velocity.vy = targetDirn->vy - MUL_FIXED(yDirection.vy,dotProduct); + velocity.vz = targetDirn->vz - MUL_FIXED(yDirection.vz,dotProduct); + + if ( (velocity.vx==0) && (velocity.vy==0) && (velocity.vz==0) ) { + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + return(orientated); + } + + Normalise(&velocity); + + sbPtr->DynPtr->LinVelocity.vx = MUL_FIXED(velocity.vx,speed); + sbPtr->DynPtr->LinVelocity.vy = MUL_FIXED(velocity.vy,speed); + sbPtr->DynPtr->LinVelocity.vz = MUL_FIXED(velocity.vz,speed); + } + + return(orientated); + } else { + int accelerationThisFrame,deltaVMag,dotProduct; + VECTORCH deltaV,targetV,yDirection,movementOffset; + MOVEMENT_DATA *movementData; + + /* Mode 2, for marines 'n' predators. And xenoborgs. */ + + /* I'll still believe in 'Speed'... but look up acceleration. */ + switch (sbPtr->I_SBtype) { + case I_BehaviourPredator: + /* May need to change this based on state at some point? */ + { + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + LOCALASSERT(sbPtr); + predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(predatorStatusPointer); + + if ((predatorStatusPointer->behaviourState==PBS_Wandering) + ||((predatorStatusPointer->behaviourState==PBS_Avoidance)&&(predatorStatusPointer->lastState==PBS_Wandering))) { + movementData=GetThisMovementData(MDI_Casual_Predator); + /* Fix reduced max speed. */ + speed=movementData->maxSpeed; + } else { + movementData=GetThisMovementData(MDI_Predator); + } + accelerationThisFrame=movementData->acceleration; + } + break; + case I_BehaviourMarine: + { + MARINE_STATUS_BLOCK *marineStatusPointer; + LOCALASSERT(sbPtr); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(marineStatusPointer); + + accelerationThisFrame=marineStatusPointer->acceleration; + } + break; + case I_BehaviourXenoborg: + movementData=GetThisMovementData(MDI_Xenoborg); + accelerationThisFrame=movementData->acceleration; + break; + default: + GLOBALASSERT(0); + break; + } + /* I'll get that from outside in a minute, okay? */ + /* Assume you're ground-based. */ + targetDirn->vy = 0; + + /* first check for zero direction vector */ + if((targetDirn->vx==0)&&(targetDirn->vz==0)) + { + /* For the moment, you can still stop on a dime. */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + return(1); + } + + accelerationThisFrame=MUL_FIXED(accelerationThisFrame,NormalFrameTime); + /* u+at, and all that, wot? */ + + yDirection.vx = sbPtr->DynPtr->OrientMat.mat21; + yDirection.vy = sbPtr->DynPtr->OrientMat.mat22; + yDirection.vz = sbPtr->DynPtr->OrientMat.mat23; + + dotProduct = DotProduct(&yDirection,targetDirn); + + targetV.vx = targetDirn->vx - MUL_FIXED(yDirection.vx,dotProduct); + targetV.vy = targetDirn->vy - MUL_FIXED(yDirection.vy,dotProduct); + targetV.vz = targetDirn->vz - MUL_FIXED(yDirection.vz,dotProduct); + + if ( (targetV.vx==0) && (targetV.vy==0) && (targetV.vz==0) ) { + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + return(1); + } + + Normalise(&targetV); + + targetV.vx=MUL_FIXED(targetV.vx,speed); + targetV.vy=MUL_FIXED(targetV.vy,speed); + targetV.vz=MUL_FIXED(targetV.vz,speed); + + deltaV.vx=targetV.vx-sbPtr->DynPtr->LinVelocity.vx; + deltaV.vy=targetV.vy-sbPtr->DynPtr->LinVelocity.vy; + deltaV.vz=targetV.vz-sbPtr->DynPtr->LinVelocity.vz; + /* Now, deltaV is what we need to match. */ + deltaVMag=Approximate3dMagnitude(&deltaV); + if (deltaVMag<=accelerationThisFrame) { + int dotP,magV; + VECTORCH normVelocity; + + sbPtr->DynPtr->LinVelocity=targetV; + + movementOffset.vx=sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx; + movementOffset.vy=sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy; + movementOffset.vz=sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz; + + normVelocity=sbPtr->DynPtr->LinVelocity; + magV=Approximate3dMagnitude(&sbPtr->DynPtr->LinVelocity); + + Normalise(&movementOffset); + Normalise(&normVelocity); + dotP=DotProduct(&normVelocity,&movementOffset); + + /* To get a reasonable value out... */ + if (magV<(speed>>2)) { + orientated=NPCOrientateToVector(sbPtr, &targetV,NPC_TURNRATE,NULL); + } else if ((dotP>40000)||((movementOffset.vx==0)&&(movementOffset.vy==0)&&(movementOffset.vz==0))) { + orientated=NPCOrientateToVector(sbPtr, &normVelocity,NPC_TURNRATE,NULL); + } else { + orientated=NPCOrientateToVector(sbPtr, &movementOffset,NPC_TURNRATE,NULL); + } + return(orientated); + } + /* If we're here, we can't make the target velocity yet. */ + Normalise(&deltaV); + deltaV.vx=MUL_FIXED(deltaV.vx,accelerationThisFrame); + deltaV.vy=MUL_FIXED(deltaV.vy,accelerationThisFrame); + deltaV.vz=MUL_FIXED(deltaV.vz,accelerationThisFrame); + + sbPtr->DynPtr->LinVelocity.vx+=deltaV.vx; + sbPtr->DynPtr->LinVelocity.vy+=deltaV.vy; + sbPtr->DynPtr->LinVelocity.vz+=deltaV.vz; + + { + int dotP,magV; + VECTORCH normVelocity; + + movementOffset.vx=sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx; + movementOffset.vy=sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy; + movementOffset.vz=sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz; + + normVelocity=sbPtr->DynPtr->LinVelocity; + magV=Approximate3dMagnitude(&sbPtr->DynPtr->LinVelocity); + + Normalise(&movementOffset); + Normalise(&normVelocity); + dotP=DotProduct(&normVelocity,&movementOffset); + + /* To get a reasonable value out... */ + if (magV<(speed>>2)) { + orientated=NPCOrientateToVector(sbPtr, &targetV,NPC_TURNRATE,NULL); + } else if ((dotP>40000)||((movementOffset.vx==0)&&(movementOffset.vy==0)&&(movementOffset.vz==0))) { + orientated=NPCOrientateToVector(sbPtr, &normVelocity,NPC_TURNRATE,NULL); + } else { + orientated=NPCOrientateToVector(sbPtr, &movementOffset,NPC_TURNRATE,NULL); + } + + } + return(orientated); + } +} + +/*------------------------Patrick 3/2/97--------------------------------- + Sets an NPC's orientation so that it's z axis aligns to a given vector + (modified from kevin's alien align to velocity routine) + -----------------------------------------------------------------------*/ +int NPCOrientateToVector(STRATEGYBLOCK *sbPtr, VECTORCH *zAxisVector,int turnspeed, VECTORCH *offset) +{ + extern int cosine[], sine[]; + + int maxTurnThisFrame; + int turnThisFrame; + VECTORCH localZAxisVector; + int localZVecEulerY; + MATRIXCH toLocal; + int orientatedOk = 0; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + LOCALASSERT(zAxisVector); + + localZAxisVector = *zAxisVector; + + /* zero vector: nothing to do */ + if((localZAxisVector.vx==0)&&(localZAxisVector.vy==0)&&(localZAxisVector.vz==0)) return 1; + + /* rotate world zAxisVector into local space */ + toLocal = sbPtr->DynPtr->OrientMat; + + TransposeMatrixCH(&toLocal); + RotateVector(&localZAxisVector, &toLocal); + Normalise(&localZAxisVector); + +// maxTurnThisFrame = WideMulNarrowDiv(NormalFrameTime,4096,NPC_TURNRATE); + maxTurnThisFrame = MUL_FIXED(NormalFrameTime,turnspeed); + localZVecEulerY = ArcTan(localZAxisVector.vx, localZAxisVector.vz); + LOCALASSERT((localZVecEulerY>=0)&&(localZVecEulerY<=4096)); + + if(localZVecEulerY==0||localZVecEulerY==4096) + { + /* if euler-y is 0 we are already aligned: nothing to do */ + return 1; + } + + if(localZVecEulerY>2048) + { + if(localZVecEulerY>(4096-maxTurnThisFrame)) + { + turnThisFrame = localZVecEulerY; + orientatedOk = 1; + } + else + { + turnThisFrame = (4096-maxTurnThisFrame); + orientatedOk = 0; + } + } + else + { + if(localZVecEulerY>maxTurnThisFrame) + { + turnThisFrame = maxTurnThisFrame; + orientatedOk = 0; + } + else + { + turnThisFrame = localZVecEulerY; + orientatedOk = 1; + } + } + + /* now convert into a matrix & multiply existing orientation by it ... */ + { + MATRIXCH mat; + int cos = GetCos(turnThisFrame); + int sin = GetSin(turnThisFrame); + mat.mat11 = cos; + mat.mat12 = 0; + mat.mat13 = -sin; + mat.mat21 = 0; + mat.mat22 = 65536; + mat.mat23 = 0; + mat.mat31 = sin; + mat.mat32 = 0; + mat.mat33 = cos; + + // NOTE : It seems like OrientMat is not being set per frame which + // leads to inaccuracy build-up from the matrix multiplies. When this + // is fixed, the following PSXAccurateMatrixMultiply can be removed + + if (offset) { + VECTORCH new_offset,delta_offset; + //MATRIXCH reverse; + + /* Code to attempt spinning on one foot. */ + + RotateAndCopyVector(offset,&new_offset,&mat); + + //reverse=mat; + //TransposeMatrixCH(&reverse); + // + //RotateAndCopyVector(offset,&new_offset,&reverse); + + delta_offset.vx=(offset->vx-new_offset.vx); + delta_offset.vy=(offset->vy-new_offset.vy); + delta_offset.vz=(offset->vz-new_offset.vz); + /* delta_offset is in local space? */ + + //RotateVector(&delta_offset,&sbPtr->DynPtr->OrientMat); + + /* Now change position. Bear in mind that many calls overwrite this change. */ + + sbPtr->DynPtr->Displacement.vx=delta_offset.vx; + sbPtr->DynPtr->Displacement.vy=delta_offset.vy; + sbPtr->DynPtr->Displacement.vz=delta_offset.vz; + sbPtr->DynPtr->UseDisplacement=1; + + } + + #if PSX + PSXAccurateMatrixMultiply(&sbPtr->DynPtr->OrientMat,&mat,&sbPtr->DynPtr->OrientMat); + #else + MatrixMultiply(&sbPtr->DynPtr->OrientMat,&mat,&sbPtr->DynPtr->OrientMat); + #endif + MatrixToEuler(&sbPtr->DynPtr->OrientMat, &sbPtr->DynPtr->OrientEuler); + } + + return orientatedOk; +} + +/*------------------------Patrick 1/2/97----------------------------- + Tries to find an ep in an adjacent module which can be used as a + movement target for NPC. + --------------------------------------------------------------------*/ +int NPCFindTargetEP(STRATEGYBLOCK *sbPtr, VECTORCH *targetPosn, AIMODULE **targetModule, int alien) +{ + AIMODULE **AdjModuleRefPtr; + FARENTRYPOINT *bestEp; + int bestSmell = 0; + int aTargetExists = 0; + AIMODULE *bestModule = (AIMODULE *)0; + + LOCALASSERT(sbPtr); + LOCALASSERT(targetPosn); + LOCALASSERT(targetModule); + + if(!(sbPtr->containingModule)) return 0; /* just in case */ + AdjModuleRefPtr = sbPtr->containingModule->m_aimodule->m_link_ptrs; + + /* check if there is a module adjacency list */ + if(!AdjModuleRefPtr) return 0; + + /* go through each adjacent module */ + while(*AdjModuleRefPtr != 0) + { + AIMODULE *nextAdjModule = *AdjModuleRefPtr; + if (AIModuleIsVisible(nextAdjModule)) + { + /* it is adjacent & visible ... */ + FARENTRYPOINT *thisEp = GetAIModuleEP(nextAdjModule, sbPtr->containingModule->m_aimodule); + if(thisEp) + { + if (!((!alien)&(thisEp->alien_only))) { + /* ... and has an ep, so test it's pheromone level */ + if(PherPl_ReadBuf[(nextAdjModule->m_index)] > bestSmell) + { + bestSmell = PherPl_ReadBuf[(nextAdjModule->m_index)]; + bestEp = thisEp; + bestModule = nextAdjModule; + aTargetExists = 1; + } + } + } + } + AdjModuleRefPtr++; + } + + /* return the result, if there is one */ + if(aTargetExists) + { + *targetPosn = bestEp->position; + *targetModule = bestModule; + targetPosn->vx += bestModule->m_world.vx; + targetPosn->vy += bestModule->m_world.vy; + targetPosn->vz += bestModule->m_world.vz; + LOCALASSERT(bestEp->donorIndex == sbPtr->containingModule->m_aimodule->m_index); + } + return aTargetExists; +} + + + +/*------------------------Patrick 11/2/97----------------------------- + If we're not in the same module as the player, find an ep for a + suitable target module, and return this. If cannot find an ep, + or if the player is in our module, return the player's position. + --------------------------------------------------------------------*/ +void NPCGetMovementTarget(STRATEGYBLOCK *sbPtr, STRATEGYBLOCK *target, VECTORCH *targetPosition,int *targetIsAirduct,int alien) +{ + LOCALASSERT(sbPtr); + LOCALASSERT(targetPosition); + LOCALASSERT(targetIsAirduct); + LOCALASSERT(target); + GLOBALASSERT(playerPherModule); + + if (target==Player->ObStrategyBlock) { + + if(sbPtr->containingModule->m_aimodule != playerPherModule->m_aimodule) + { + int epFound; + VECTORCH epPosn; + AIMODULE *epModule; + epFound = NPCFindTargetEP(sbPtr, &epPosn, &epModule,alien); + if(epFound) + { + *targetPosition = epPosn; + if((*epModule->m_module_ptrs)->m_flags & MODULEFLAG_AIRDUCT) *targetIsAirduct = 1; + else *targetIsAirduct = 0; + return; + } + } + /* in same module as player, or can't find an entry point */ + //*targetPosition = Player->ObWorld; + GetTargetingPointOfObject(Player, targetPosition); + *targetIsAirduct = 0; + + } else { + + /* Improve this presently */ + //*targetPosition = target->DynPtr->Position; + GetTargetingPointOfObject_Far(target, targetPosition); + *targetIsAirduct = 0; + + } +} + +/*------------------------------Patrick 24/3/97----------------------------------- + Calculates best direction of movement for NPC, from our main target direction: + 1. If on same poly as player, move towards him/her; + 2. Otherwise, find best adjacent floor polygon to move towards our target. + + NB works in 2d... + -------------------------------------------------------------------------------*/ +static int FindMyFloorPoly(VECTORCH* currentPosition, MODULE* currentModule); +static int CheckMyFloorPoly(VECTORCH* currentPosition, MODULE* currentModule); +static int VectorIntersects2dZVector(VECTORCH *vecStart,VECTORCH *vecEnd, int zExtent); +extern int SetupPolygonAccessFromShapeIndex(int shapeIndex); +extern int SetupPointAccessFromShapeIndex(int shapeIndex); + +/* These globals are filled out by FindMyFloorPoly() */ +static VECTORCH GMD_myPolyPoints[4]; +static int GMD_myPolyNumPoints; +/* these Globals are used by NPCGetMovementDirection() */ +VECTORCH myPolyEdgePoints[4]; +VECTORCH myPolyEdgeDirections[4]; +VECTORCH myPolyEdgeNormals[4]; +VECTORCH myPolyMidPoint; +int myPolyEdgeMoveDistances[4]; +extern int ShowNearSquad; +extern int ShowSquadState; +extern int ShowPredoStats; + +/* a quick prototype */ +static void NPCFindCurveToEdgePoint(STRATEGYBLOCK *sbPtr, int index, VECTORCH *velocityDirection); + +void NPCGetMovementDirection(STRATEGYBLOCK *sbPtr, VECTORCH *velocityDirection, VECTORCH *targetPosition, WAYPOINT_MANAGER *waypointManager) +{ + VECTORCH targetDirection; + int i; + int playerPoly = NPC_GMD_NOPOLY; + int ourPolyThisFrame = NPC_GMD_NOPOLY; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + LOCALASSERT(velocityDirection); + LOCALASSERT(targetPosition); + + if (sbPtr->containingModule==NULL) { + /* Oops. */ + targetDirection = *targetPosition; + targetDirection.vx -= sbPtr->DynPtr->Position.vx; + targetDirection.vz -= sbPtr->DynPtr->Position.vz; + targetDirection.vy = 0; + Normalise(&targetDirection); + *velocityDirection = targetDirection; + return; + } else { + if ((sbPtr->containingModule->m_aimodule->m_waypoints!=NULL)&&(waypointManager)) { + if (NPCGetWaypointDirection(sbPtr->containingModule->m_aimodule->m_waypoints,sbPtr,velocityDirection,targetPosition,waypointManager)) { + /* Success! */ + return; + } + } + } + + /* First get the (2d) direction of the main target */ + targetDirection = *targetPosition; + targetDirection.vx -= sbPtr->DynPtr->Position.vx; + targetDirection.vz -= sbPtr->DynPtr->Position.vz; + /* If we got here, we *should* not be a crawling alien... */ + if (AlienIsCrawling(sbPtr)) { + targetDirection.vy -= sbPtr->DynPtr->Position.vy; + } else { + /* Non-planar adjacency warnings? */ + if ((ShowSquadState)||(ShowPredoStats)||(ShowNearSquad)) { + targetDirection.vy -= sbPtr->DynPtr->Position.vy; + Normalise(&targetDirection); + if (targetDirection.vy<-46000) { + PrintDebuggingText("Non-planar adjacency!\n"); + } + } + + targetDirection.vy = 0; + } + #if 1 + Normalise(&targetDirection); + #else + AlignVelocityToGravity(sbPtr,&targetDirection); + #endif + + /* first- a hack to cope with stairs and al those little polygons: + if we're in stairs just return the target direction. This is okay aslong as we don't + have curved stairs*/ + if(sbPtr->containingModule->m_flags&MODULEFLAG_STAIRS) + { + *velocityDirection = targetDirection; + return; + } + + /* get the player's poly index, and ours: + in the unlikely case that the player or npc doesnt have a current containingg module, + just return the target direction */ + if(playerPherModule==NULL) + { + *velocityDirection = targetDirection; + return; + } + playerPoly = FindMyFloorPoly(&(Player->ObWorld), playerPherModule); + ourPolyThisFrame = FindMyFloorPoly(&(sbPtr->DynPtr->Position), sbPtr->containingModule); + + /* Check for not having a current poly: this seems to happen occasionally + around module boundaries- npc just needs a jolt... */ + if(ourPolyThisFrame == NPC_GMD_NOPOLY) + { + *velocityDirection = targetDirection; + return; + } + + /* CDF 9/8/98 So we've got a poly, but is it stupid? */ + if (IsMyPolyRidiculous()) { + *velocityDirection = targetDirection; + return; + } + + /* Now check for player on our poly + NB only do this is we are not the player: as this function is used in player demo */ + + if((sbPtr != Player->ObStrategyBlock)&&(sbPtr->containingModule==playerPherModule)&&(playerPoly != NPC_GMD_NOPOLY)) + { + if(playerPoly == ourPolyThisFrame) + { + /* cripes- we're on the same poly */ + *velocityDirection = targetDirection; + return; + } + } + + /* test */ + if(sbPtr == Player->ObStrategyBlock) + { + textprint("player poly %d \n",ourPolyThisFrame); + } + + /* Now get all the data we need: + 1. World space coords of poly edge mid points + 2. Directions from npc to those points + 3. Midpoint of our polygon. + 3a Some error checking. + 4. Distances we could move from poly midpoint to edge midpoint before hitting something + */ + for(i=0;i= GMD_myPolyNumPoints) point2 = 0; + { + /* find the edge out normal - NB this won't work for clockwise polygons (2d) */ + VECTORCH upNormal = {0,-65536,0}; + VECTORCH edgeVector; + + edgeVector.vx = GMD_myPolyPoints[point2].vx - GMD_myPolyPoints[point1].vx; + edgeVector.vy = 0; + edgeVector.vz = GMD_myPolyPoints[point2].vz - GMD_myPolyPoints[point1].vz; + + CrossProduct(&edgeVector,&upNormal,&myPolyEdgeNormals[i]); + Normalise(&myPolyEdgeNormals[i]); + LOCALASSERT(myPolyEdgeNormals[i].vy == 0); + } + + /* 1 : Calculate edge midpoint (2d) */ + myPolyEdgePoints[i].vx = ((GMD_myPolyPoints[point1].vx + GMD_myPolyPoints[point2].vx)/2)+MUL_FIXED(myPolyEdgeNormals[i].vx,50); + myPolyEdgePoints[i].vy = 0; + myPolyEdgePoints[i].vz = ((GMD_myPolyPoints[point1].vz + GMD_myPolyPoints[point2].vz)/2)+MUL_FIXED(myPolyEdgeNormals[i].vz,50); + /* Into world space*/ + myPolyEdgePoints[i].vx += sbPtr->containingModule->m_world.vx; + myPolyEdgePoints[i].vz += sbPtr->containingModule->m_world.vz; + + /* 2 : Directions to those points */ + myPolyEdgeDirections[i].vx = myPolyEdgePoints[i].vx - sbPtr->DynPtr->Position.vx; + myPolyEdgeDirections[i].vy = 0; + myPolyEdgeDirections[i].vz = myPolyEdgePoints[i].vz - sbPtr->DynPtr->Position.vz; + Normalise(&myPolyEdgeDirections[i]); + } + + /* 3 : Poly midpoint- actually just an approximation, but doesn't matter + as long as its inside the poly (in world space): + NB + Quads are done by finding the midpoint of a diagonal. + Triangles bisect a side then take the midpoint of that and the third point, else + they can end up with a midpoint on one of their sides which buggers things up.*/ + if(GMD_myPolyNumPoints==3) + { + VECTORCH bisect; + bisect.vy = ((GMD_myPolyPoints[1].vy + GMD_myPolyPoints[2].vy)/2); + bisect.vx = ((GMD_myPolyPoints[1].vx + GMD_myPolyPoints[2].vx)/2); + bisect.vz = ((GMD_myPolyPoints[1].vz + GMD_myPolyPoints[2].vz)/2); + myPolyMidPoint.vy = ((GMD_myPolyPoints[0].vy + bisect.vy)/2)+sbPtr->containingModule->m_world.vy; + myPolyMidPoint.vx = ((GMD_myPolyPoints[0].vx + bisect.vx)/2)+sbPtr->containingModule->m_world.vx; + myPolyMidPoint.vz = ((GMD_myPolyPoints[0].vz + bisect.vz)/2)+sbPtr->containingModule->m_world.vz; + } + else + { + myPolyMidPoint.vy = ((GMD_myPolyPoints[0].vy + GMD_myPolyPoints[2].vy)/2)+sbPtr->containingModule->m_world.vy; + myPolyMidPoint.vx = ((GMD_myPolyPoints[0].vx + GMD_myPolyPoints[2].vx)/2)+sbPtr->containingModule->m_world.vx; + myPolyMidPoint.vz = ((GMD_myPolyPoints[0].vz + GMD_myPolyPoints[2].vz)/2)+sbPtr->containingModule->m_world.vz; + } + + /* Error trapping: + 1. if midpoint is not in our polygon, just move to target + 2. If main target is in our poly, just move to target + 3. If any edge points are in our poly, just move to the target also + */ + { + int edgePoint[2]; + int polyPoints[10]; + int j; + + for(j=0;jcontainingModule->m_world.vx; + edgePoint[1] = myPolyEdgePoints[j].vz - sbPtr->containingModule->m_world.vz; + + if(PointInPolygon(&edgePoint[0],&polyPoints[0],GMD_myPolyNumPoints,2)) + { + /* one of the edge points is inside our poly */ + *velocityDirection = targetDirection; + return; + } + } + /* Mid point (in poly local space) */ + edgePoint[0] = myPolyMidPoint.vx - sbPtr->containingModule->m_world.vx; + edgePoint[1] = myPolyMidPoint.vz - sbPtr->containingModule->m_world.vz; + if(!(PointInPolygon(&edgePoint[0],&polyPoints[0],GMD_myPolyNumPoints,2))) + { + /* the midpoint is inside our poly */ + *velocityDirection = targetDirection; + return; + } + + /* Target point (in poly local space)*/ + edgePoint[0] = targetPosition->vx - sbPtr->containingModule->m_world.vx; + edgePoint[1] = targetPosition->vz - sbPtr->containingModule->m_world.vz; + if(PointInPolygon(&edgePoint[0],&polyPoints[0],GMD_myPolyNumPoints,2)) + { + /* the main target point is inside our poly:- this shouldn't happen, + as we have already tested for the player earlier on */ + *velocityDirection = targetDirection; + return; + } + } + + /* 4 : Finally, the distances that we can move from the poly midpoint beyond + each edge midpoint before we hit something... + */ + { + for(i=0;iDynPtr->Position.vy;*/ + /* Normalise the test direction */ + Normalise(&testDirn); + + LOS_ObjectHitPtr = (DISPLAYBLOCK *)0; + LOS_Lambda = NPC_MAX_VIEWRANGE; + CheckForVectorIntersectionWith3dObject(sbPtr->containingModule->m_dptr,&startingPosition,&testDirn,0); + if(!LOS_ObjectHitPtr) myPolyEdgeMoveDistances[i] = NPC_MAX_VIEWRANGE; + else myPolyEdgeMoveDistances[i] = LOS_Lambda; + } + + /* how far we can move beyond the poly edge */ + myPolyEdgeMoveDistances[i] -= centreToEdgeDistance; + + /* quick check to eliminate Saturn type dodgy triangle points: + by setting move distance to zero, we should never select this edge as our + target edge... */ + { + int point1 = i; + int point2 = i+1; + if(point2 >= GMD_myPolyNumPoints) point2 = 0; + if( (GMD_myPolyPoints[point1].vx == GMD_myPolyPoints[point2].vx) && + (GMD_myPolyPoints[point1].vy == GMD_myPolyPoints[point2].vy) && + (GMD_myPolyPoints[point1].vz == GMD_myPolyPoints[point2].vz)) + { + #if (!Saturn) + LOCALASSERT(1==0); + #endif + myPolyEdgeMoveDistances[i] = 0; + } + } + } + } + + /* Now the crucial bit:- try to find an edge in our polygon that we can move towards + and which is intersected by the vector from the mid point to the main target. If + we find one, this is our edge! */ + for(i=0;i NPC_MIN_MOVEFROMPOLYDIST) + { + int vecExtent; + int ePoint1, ePoint2; + VECTORCH endPoint1, endPoint2; + VECTORCH edgeVector; + MATRIXCH edgeMatrix; + + ePoint1 = i; + ePoint2 = i+1; + if(ePoint2>=GMD_myPolyNumPoints) ePoint2 = 0; + edgeVector.vx = GMD_myPolyPoints[ePoint2].vx - GMD_myPolyPoints[ePoint1].vx; + edgeVector.vy = 0; + edgeVector.vz = GMD_myPolyPoints[ePoint2].vz - GMD_myPolyPoints[ePoint1].vz; + + Normalise(&edgeVector); + vecExtent = Magnitude(&edgeVector); + + /* This IS the right way around */ + edgeMatrix.mat11 = myPolyEdgeNormals[i].vx; + edgeMatrix.mat21 = 0; + edgeMatrix.mat31 = myPolyEdgeNormals[i].vz; + edgeMatrix.mat12 = 0; + edgeMatrix.mat22 = 65536; + edgeMatrix.mat32 = 0; + edgeMatrix.mat13 = edgeVector.vx; + edgeMatrix.mat23 = 0; + edgeMatrix.mat33 = edgeVector.vz; + + /* set up the test vector */ + endPoint1 = myPolyMidPoint; + endPoint1.vx = endPoint1.vx - sbPtr->containingModule->m_world.vx - GMD_myPolyPoints[ePoint1].vx; + endPoint1.vy = 0; + endPoint1.vz = endPoint1.vz - sbPtr->containingModule->m_world.vz - GMD_myPolyPoints[ePoint1].vz; + RotateVector(&endPoint1, &edgeMatrix); + + endPoint2 = *targetPosition; + endPoint2.vx = endPoint2.vx - sbPtr->containingModule->m_world.vx - GMD_myPolyPoints[ePoint1].vx; + endPoint2.vy = 0; + endPoint2.vz = endPoint2.vz - sbPtr->containingModule->m_world.vz - GMD_myPolyPoints[ePoint1].vz; + RotateVector(&endPoint2, &edgeMatrix); + + if(VectorIntersects2dZVector(&endPoint1,&endPoint2,vecExtent)) + { + /* that'll do nicely */ + + /* test */ + if(sbPtr == Player->ObStrategyBlock) + { + textprint("intersection test\n"); + } + + #if 0 + *velocityDirection = myPolyEdgeDirections[i]; + #else + NPCFindCurveToEdgePoint(sbPtr,i,velocityDirection); + #endif + return; + } + } + } + + /* test */ + if(sbPtr == Player->ObStrategyBlock) + { + textprint("nearest edge test\n"); + } + + /* Didn't find an intersection edge, so just pick the nearest + edge point that we can traverse */ + { + int directionFound = 0; + VECTORCH bestDirection; + int closestDistance = 1000000; /* something very big */ + + for(i=0;i NPC_MIN_MOVEFROMPOLYDIST) + { + int myDist = (VectorDistance(&myPolyEdgePoints[i],targetPosition)); + if(myDist < closestDistance) + { + bestDirection = myPolyEdgeDirections[i]; + closestDistance = myDist; + directionFound = 1; + } + } + } + /* return best direction, if we have one */ + if(directionFound) + { + LOCALASSERT(bestDirection.vy == 0); + *velocityDirection = bestDirection; + return; + } + } + + /* We have utterly failed to find a suitable direction */ + #if 0 + velocityDirection->vx = velocityDirection->vy = velocityDirection->vz = 0; + #else + *velocityDirection = targetDirection; + #endif +} + +/* Patrick 12/6/97: This function is an auxilary function to NPCGetMovementDirection(), and +adds a curve to the edge point direction, weighted towards the centre of the current poly */ +static void NPCFindCurveToEdgePoint(STRATEGYBLOCK *sbPtr, int edgeIndex, VECTORCH *velocityDirection) +{ + VECTORCH curvedPath; + VECTORCH dirnToCentre; + int weighting; + + LOCALASSERT(sbPtr); + LOCALASSERT(velocityDirection); + + /* default direction- just in case something goes wrong */ + *velocityDirection = myPolyEdgeDirections[edgeIndex]; + + /* find dirn to centre of poly */ + dirnToCentre.vx = myPolyMidPoint.vx - sbPtr->DynPtr->Position.vx; + dirnToCentre.vz = myPolyMidPoint.vz - sbPtr->DynPtr->Position.vz; + dirnToCentre.vy = 0; + if((dirnToCentre.vx==0)&&(dirnToCentre.vz==0)) return; + Normalise(&dirnToCentre); + + /* calculated weighted vector to centre */ + weighting = DotProduct(&myPolyEdgeDirections[edgeIndex],&dirnToCentre); + if(weighting==0) return; + + dirnToCentre.vx = WideMulNarrowDiv(dirnToCentre.vx,weighting,ONE_FIXED); + dirnToCentre.vz = WideMulNarrowDiv(dirnToCentre.vz,weighting,ONE_FIXED); + + /* add them to find curved direction path */ + curvedPath.vx = myPolyEdgeDirections[edgeIndex].vx + dirnToCentre.vx; + curvedPath.vz = myPolyEdgeDirections[edgeIndex].vz + dirnToCentre.vz; + curvedPath.vy = 0; + Normalise(&curvedPath); + *velocityDirection = curvedPath; +} + + +/*------------------------Patrick 24/3/97----------------------------- + This function is used to determine an intersection between 2 line + segments. The passed segment end points have been transformed into + a space where the second segment is aligned to the z axis, and extends + from 0 to the passed extent parameter. This makes the intersection + test easy... + --------------------------------------------------------------------*/ +static int VectorIntersects2dZVector(VECTORCH *vecStart,VECTORCH *vecEnd, int zExtent) +{ + int vecIntercept; + LOCALASSERT(vecStart); + LOCALASSERT(vecEnd); + + if((vecStart->vx < 0)&&(vecEnd->vx < 0)) return 0; + if((vecStart->vx > 0)&&(vecEnd->vx > 0)) return 0; + if((vecStart->vz < 0)&&(vecEnd->vz < 0)) return 0; + if((vecStart->vz > zExtent)&&(vecEnd->vz > zExtent)) return 0; + vecIntercept = vecStart->vz + + WideMulNarrowDiv((vecEnd->vz - vecStart->vz),vecStart->vx,(vecEnd->vx - vecStart->vx)); + if((vecIntercept > 0)&&(vecIntercept < zExtent)) return 1; /* (deliberately ignoring endpoints) */ + return 0; +} + +/*------------------------Patrick 11/2/97----------------------------- + Tries to find a floor polygon for a given world space location in + a given module + --------------------------------------------------------------------*/ +int FindMyFloorPoly(VECTORCH* currentPosition, MODULE* currentModule) +{ + struct ColPolyTag polygonData; + int positionPoints[2]; + VECTORCH localPosition; + int numPolys; + int polyCounter; + int polyFound = 0; + int polyFoundIndex = 0; + + LOCALASSERT(currentPosition); + LOCALASSERT(currentModule); + + /* first, get the local position */ + localPosition.vx = currentPosition->vx - currentModule->m_world.vx; + localPosition.vy = currentPosition->vy - currentModule->m_world.vy; + localPosition.vz = currentPosition->vz - currentModule->m_world.vz; + LOCALASSERT(PointIsInModule(currentModule,&localPosition)); + + /* set up position points for object*/ + positionPoints[0] = localPosition.vx; + positionPoints[1] = localPosition.vz; + + numPolys = SetupPolygonAccessFromShapeIndex(currentModule->m_mapptr->MapShape); + polyCounter = numPolys; + + /* loop through the item list, then ... */ + while((polyCounter > 0) && (!polyFound)) + { + AccessNextPolygon(); + GetPolygonVertices(&polygonData); + GetPolygonNormal(&polygonData); + + /* first of all, reject any that don't have an up normal */ + if(polygonData.PolyNormal.vy < 0) + { + /* set up poly points for containment test */ + int polyPoints[10]; + int numPtsInPoly = polygonData.NumberOfVertices; + int i; + + for(i=0;i= 0); + LOCALASSERT(polyFound < numPolys); + + GMD_myPolyNumPoints = polygonData.NumberOfVertices; + GMD_myPolyPoints[0] = polygonData.PolyPoint[0]; + GMD_myPolyPoints[1] = polygonData.PolyPoint[1]; + GMD_myPolyPoints[2] = polygonData.PolyPoint[2]; + + if(GMD_myPolyNumPoints > 3) + { + GMD_myPolyPoints[3] = polygonData.PolyPoint[3]; + } + + return(polyFoundIndex); +} + + +/*------------------------Patrick 28/1/99----------------------------- + Tries to find a floor polygon for a given world space location in + a given module. Early exit if the location isn't even in the module... + --------------------------------------------------------------------*/ +int CheckMyFloorPoly(VECTORCH* currentPosition, MODULE* currentModule) +{ + struct ColPolyTag polygonData; + int positionPoints[2]; + VECTORCH localPosition; + int numPolys; + int polyCounter; + int polyFound = 0; + int polyFoundIndex = 0; + + LOCALASSERT(currentPosition); + LOCALASSERT(currentModule); + + /* first, get the local position */ + localPosition.vx = currentPosition->vx - currentModule->m_world.vx; + localPosition.vy = currentPosition->vy - currentModule->m_world.vy; + localPosition.vz = currentPosition->vz - currentModule->m_world.vz; + if( !PointIsInModule(currentModule,&localPosition) ) + { + // Whoops ! I'm looking in the wrong module. Better just forget it. + return NPC_GMD_NOPOLY; + } + + /* set up position points for object*/ + positionPoints[0] = localPosition.vx; + positionPoints[1] = localPosition.vz; + + numPolys = SetupPolygonAccessFromShapeIndex(currentModule->m_mapptr->MapShape); + polyCounter = numPolys; + + /* loop through the item list, then ... */ + while((polyCounter > 0) && (!polyFound)) + { + AccessNextPolygon(); + GetPolygonVertices(&polygonData); + GetPolygonNormal(&polygonData); + + /* first of all, reject any that don't have an up normal */ + if(polygonData.PolyNormal.vy < 0) + { + /* set up poly points for containment test */ + int polyPoints[10]; + int numPtsInPoly = polygonData.NumberOfVertices; + int i; + + for(i=0;i= 0); + LOCALASSERT(polyFound < numPolys); + + GMD_myPolyNumPoints = polygonData.NumberOfVertices; + GMD_myPolyPoints[0] = polygonData.PolyPoint[0]; + GMD_myPolyPoints[1] = polygonData.PolyPoint[1]; + GMD_myPolyPoints[2] = polygonData.PolyPoint[2]; + + if(GMD_myPolyNumPoints > 3) + { + GMD_myPolyPoints[3] = polygonData.PolyPoint[3]; + } + + return(polyFoundIndex); +} + + +/* Patrick 23/8/97 ----------------------------------------------------- +A couple of functions for wandering +-----------------------------------------------------------------------*/ +void NPC_InitWanderData(NPC_WANDERDATA *wanderData) +{ + LOCALASSERT(wanderData); + wanderData->currentModule = NPC_NOWANDERMODULE; + wanderData->worldPosition.vx = wanderData->worldPosition.vy = wanderData->worldPosition.vz = 0; +} + + +/* Patrick: 26/8/97 +Finding a suitable target module- look thro' all the visible non-airduct modules +connected to the npc's current module. pick one, and use it's ep as a +target. +We take a random adjacent ep as our target, but reject the most 'backward' one +(compared to our last velocity, as recorded in npc_movedata) as our last choice +*/ + +void NPC_FindAIWanderTarget(STRATEGYBLOCK *sbPtr, NPC_WANDERDATA *wanderData, NPC_MOVEMENTDATA *moveData, int alien) +{ + AIMODULE* chosenModule = NULL; + VECTORCH chosenEpWorld; + int numFound = 0; + + AIMODULE* worstModule = NULL; + VECTORCH worstEpWorld; + int worstEpDot; + + AIMODULE **AdjModuleRefPtr; + VECTORCH lastVelocityDirection; + int gotLastVelocityDirection = 0; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + LOCALASSERT(wanderData); + LOCALASSERT(moveData); + + /* init the wander data block now, and we only have to fill in the correct + values if we get them... */ + NPC_InitWanderData(wanderData); + + /* do we have a current module? */ + if(!(sbPtr->containingModule->m_aimodule)) return; /* no containing module */ + + AdjModuleRefPtr = sbPtr->containingModule->m_aimodule->m_link_ptrs; + /* check if there is a module adjacency list */ + if(!AdjModuleRefPtr) return; + + /* try to get our last velocity direction */ + if((moveData->lastVelocity.vx!=0)||(moveData->lastVelocity.vz!=0)||(moveData->lastVelocity.vy!=0)) + { + lastVelocityDirection = moveData->lastVelocity; + Normalise(&lastVelocityDirection); + gotLastVelocityDirection = 1; + } + else gotLastVelocityDirection = 0; + + /* if we've got a previous velocity, go through each adjacent module, + and try to find the worst one */ + while(*AdjModuleRefPtr != 0) + { + AIMODULE *nextAdjModule = *AdjModuleRefPtr; + if ((AIModuleIsVisible(nextAdjModule))&& + (((*(nextAdjModule->m_module_ptrs))->m_flags&MODULEFLAG_AIRDUCT)==0) + &&(nextAdjModule!=moveData->lastModule)) + { + /* it is adjacent & visible & not an airduct: + try to find the ep position from this module... */ + FARENTRYPOINT *thisEp = GetAIModuleEP(nextAdjModule, sbPtr->containingModule->m_aimodule); + if(thisEp) + { + if (!((!alien)&&(thisEp->alien_only))) { + /* aha. an ep!... */ + VECTORCH thisEpWorld = thisEp->position; + + thisEpWorld.vx += nextAdjModule->m_world.vx; + thisEpWorld.vy += nextAdjModule->m_world.vy; + thisEpWorld.vz += nextAdjModule->m_world.vz; + + if(gotLastVelocityDirection) + { + VECTORCH thisEpDirection; + int thisEpDot; + + thisEpDirection = thisEpWorld; + thisEpDirection.vx -= sbPtr->DynPtr->Position.vx; + thisEpDirection.vy -= sbPtr->DynPtr->Position.vy; + thisEpDirection.vz -= sbPtr->DynPtr->Position.vz; + Normalise(&thisEpDirection); + thisEpDot = DotProduct(&thisEpDirection,&lastVelocityDirection); + + if(!worstModule) + { + worstModule = nextAdjModule; + worstEpWorld = thisEpWorld; + worstEpDot = thisEpDot; + } + else + { + numFound++; + if(thisEpDot=1); + wanderData->currentModule = sbPtr->containingModule->m_aimodule->m_index; + wanderData->worldPosition = chosenEpWorld; + } + else if(worstModule) + { + wanderData->currentModule = sbPtr->containingModule->m_aimodule->m_index; + wanderData->worldPosition = worstEpWorld; + } +} + +#define NEARLINK_QUEUE_LENGTH 100 + +typedef struct nl_route_queue { + int depth; + AIMODULE *aimodule; + AIMODULE *first_step; +} NL_ROUTE_QUEUE; + +NL_ROUTE_QUEUE NearLink_Route_Queue[NEARLINK_QUEUE_LENGTH]; + +int NL_Queue_End,NL_Queue_Exec; + +AIMODULE *GetNextModuleForLink(AIMODULE *source,AIMODULE *target,int max_depth,int alien) { + + return(GetNextModuleForLink_Core(source,target,max_depth,0,alien)); + +} + +AIMODULE *GetNextModuleForLink_Core(AIMODULE *source,AIMODULE *target,int max_depth,int visibility_check,int alien) { + + AIMODULE **AdjModuleRefPtr; + + /* Recursively search AIModule tree, trying to connect source and target. * + * Return NULL on failure. */ + + if (source==target) { + return(source); + } + + /* Clear the start. */ + + NearLink_Route_Queue[0].depth=0; + NearLink_Route_Queue[0].aimodule=source; + NearLink_Route_Queue[0].first_step=NULL; + NearLink_Route_Queue[1].aimodule=NULL; /* To set a standard. */ + + NL_Queue_End=1; + NL_Queue_Exec=0; + + RouteFinder_CallsThisFrame++; + + while (NearLink_Route_Queue[NL_Queue_Exec].aimodule!=NULL) { + + AIMODULE *thisModule; + + thisModule=NearLink_Route_Queue[NL_Queue_Exec].aimodule; + + AdjModuleRefPtr = thisModule->m_link_ptrs; + + if(AdjModuleRefPtr) /* check that there is a list of adjacent modules */ + { + while(*AdjModuleRefPtr != 0) + { + /* Probably want some validity test for the link. */ + if ((AIModuleIsPhysical(*AdjModuleRefPtr)) + &&(AIModuleAdmitsPheromones(*AdjModuleRefPtr)) + &&(CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,alien)) + &&((visibility_check==0)||(IsAIModuleVisibleFromAIModule(source, + (*AdjModuleRefPtr))) + )) { + /* Is this the target? */ + if ( (*AdjModuleRefPtr)==target) { + /* Yes!!! */ + if (NearLink_Route_Queue[NL_Queue_Exec].first_step) { + return(NearLink_Route_Queue[NL_Queue_Exec].first_step); + } else { + /* Must be the next one. */ + return(target); + } + } else if ( + (NearLink_Route_Queue[NL_Queue_Exec].depthRouteFinder_FrameStamp!=GlobalFrameCounter) + ||((*AdjModuleRefPtr)->RouteFinder_IterationNumber!=RouteFinder_CallsThisFrame) + )) { + /* Add to queue. */ + NearLink_Route_Queue[NL_Queue_End].aimodule=(*AdjModuleRefPtr); + NearLink_Route_Queue[NL_Queue_End].depth=NearLink_Route_Queue[NL_Queue_Exec].depth+1; + /* Remember first step. */ + if (NearLink_Route_Queue[NL_Queue_Exec].first_step==NULL) { + NearLink_Route_Queue[NL_Queue_End].first_step=(*AdjModuleRefPtr); + } else { + NearLink_Route_Queue[NL_Queue_End].first_step=NearLink_Route_Queue[NL_Queue_Exec].first_step; + } + /* Stamp as used. */ + (*AdjModuleRefPtr)->RouteFinder_FrameStamp=GlobalFrameCounter; + (*AdjModuleRefPtr)->RouteFinder_IterationNumber=RouteFinder_CallsThisFrame; + NL_Queue_End++; + if (NL_Queue_End>=NEARLINK_QUEUE_LENGTH) { + NL_Queue_End=0; + textprint("Wrapping Nearlink Queue!\n"); + } + NearLink_Route_Queue[NL_Queue_End].aimodule=NULL; + if (NL_Queue_End==NL_Queue_Exec) { + LOGDXFMT(("Oh, no. NearLinkQueue screwed. NL_Queue_End=%d, depth = %d\n",NL_Queue_End,NearLink_Route_Queue[NL_Queue_Exec].depth)); + LOCALASSERT(NL_Queue_End!=NL_Queue_Exec); //if this happens the queue probably needs to be longer + } + } + } + /* next adjacent module reference pointer */ + AdjModuleRefPtr++; + } + } + + /* Done all the links. */ + + NL_Queue_Exec++; + if (NL_Queue_Exec>=NEARLINK_QUEUE_LENGTH) NL_Queue_Exec=0; + + } + + /* Still here? Must have hit the end, then. */ + + return(NULL); +} + + +int GetNextModuleInPath(int current_module, int path) { + + GLOBALASSERT(path>=0 && path=0 && path=0 && pathpath_length); + + //see if enemy is currently in any of the modules in the path + { + AIMODULE* current_aimodule=current_module->m_aimodule; + for(i=0;ipath_length;i++) + { + if(current_aimodule==path_head->modules_in_path[i]) + { + return i; + } + } + } + + //enemy not on path , so try to find the closest module on the path + { + int closest_distance=0x7fffffff; + int closest_point=0; + VECTORCH* current_pos=¤t_module->m_world; + VECTORCH diff; + + for(i=0;ipath_length;i++) + { + int distance; + diff=path_head->modules_in_path[i]->m_world; + SubVector(current_pos,&diff); + distance=Approximate3dMagnitude(&diff); + + if(distanceCrouching==0) { + return(0); + } + } else { + if (ThisDeath->Crouching!=0) { + return(0); + } + } + + /* Burning test. */ + if (burning) { + if (ThisDeath->Burning==0) { + return(0); + } + } else { + if (ThisDeath->Burning!=0) { + return(0); + } + } + + /* Electrical test. */ + if (electrical) { + if (ThisDeath->Electrical==0) { + return(0); + } + } else { + if (ThisDeath->Electrical!=0) { + return(0); + } + } + + /* Hurtiness. */ + switch(hurtiness) { + case 0: + default: + /* Pain case. */ + if (ThisDeath->MinorBoom) { + return(0); + } + if (ThisDeath->MajorBoom) { + return(0); + } + break; + case 1: + /* Minor Boom. */ + if (!ThisDeath->MinorBoom) { + return(0); + } + break; + case 2: + /* Major Boom. */ + if (!ThisDeath->MajorBoom) { + return(0); + } + } + + /* Facing. Complex one... */ + /* Input facing must contain at least all the flags in the death. */ + if (facing) { + if (ThisDeath->Facing.Front) { + if (facing->Front==0) { + return(0); + } + } + if (ThisDeath->Facing.Back) { + if (facing->Back==0) { + return(0); + } + } + if (ThisDeath->Facing.Left) { + if (facing->Left==0) { + return(0); + } + } + if (ThisDeath->Facing.Right) { + if (facing->Right==0) { + return(0); + } + } + } else { + if ( (ThisDeath->Facing.Front)||(ThisDeath->Facing.Back)||(ThisDeath->Facing.Left)||(ThisDeath->Facing.Right) ) { + return(0); + } + } + /* Wound flags. Also quite odd. */ + /* If wound_flags are specified in the death, the input must contain them. */ + if (ThisDeath->wound_flags) { + if ((ThisDeath->wound_flags&wound_flags)!=ThisDeath->wound_flags) { + return(0); + } + } + + /* Priority wound flags. As above, but backwards. */ + /* If the input has priority wounds, the death must contain them. */ + if (priority_wounds) { + if ((ThisDeath->priority_wounds&priority_wounds)!=priority_wounds) { + return(0); + } + } + + /* Finally, sequence validity. */ + if (ThisDeath->Template) { + if (!HModelSequence_Exists_FromRoot(TemplateRoot,ThisDeath->Sequence_Type,ThisDeath->Sub_Sequence)) { + return(0); + } + } else { + if (!HModelSequence_Exists(controller,ThisDeath->Sequence_Type,ThisDeath->Sub_Sequence)) { + return(0); + } + } + + /* It got through! */ + return(1); +} + +int CountValidDeaths(HMODELCONTROLLER *controller,SECTION *TemplateRoot,DEATH_DATA *FirstDeath,int wound_flags,int priority_wounds, + int hurtiness,HIT_FACING *facing,int burning,int crouching, int electrical) { + + DEATH_DATA *this_death; + int number_of_candidates; + + number_of_candidates=0; + this_death=FirstDeath; + + while (this_death->Sequence_Type>=0) { + if (CheckDeathValidity(controller,TemplateRoot,this_death,wound_flags,priority_wounds,hurtiness,facing,burning,crouching,electrical)) { + number_of_candidates++; + } + this_death++; + } + + return(number_of_candidates); +} + +DEATH_DATA *GetThisDeath(HMODELCONTROLLER *controller,SECTION *TemplateRoot,DEATH_DATA *FirstDeath,int wound_flags,int priority_wounds, + int hurtiness,HIT_FACING *facing,int burning,int crouching, int electrical, int index) { + + /* Extract 'index' from the valid deaths. */ + DEATH_DATA *retval; + DEATH_DATA *this_death; + int number; + + retval=NULL; + + number=0; + this_death=FirstDeath; + + while (this_death->Sequence_Type>=0) { + if (CheckDeathValidity(controller,TemplateRoot,this_death,wound_flags,priority_wounds,hurtiness,facing,burning,crouching,electrical)) { + if (number==index) { + retval=this_death; + break; + } else { + number++; + } + } + this_death++; + } + + GLOBALASSERT(retval); + return(retval); +} + +DEATH_DATA *GetThisDeath_FromCode(HMODELCONTROLLER *controller,DEATH_DATA *FirstDeath,int code) { + + /* Extract 'code' from the valid deaths. */ + DEATH_DATA *retval; + DEATH_DATA *this_death; + + retval=NULL; + + this_death=FirstDeath; + + while (this_death->Sequence_Type>=0) { + if (this_death->Multiplayer_Code==code) { + retval=this_death; + break; + } + this_death++; + } + + GLOBALASSERT(retval); + return(retval); +} + +DEATH_DATA *GetThisDeath_FromUniqueCode(int code) { + + extern DEATH_DATA Alien_Deaths[]; + extern DEATH_DATA Marine_Deaths[]; + extern DEATH_DATA Predator_Special_SelfDestruct_Death; + extern DEATH_DATA Predator_Deaths[]; + extern DEATH_DATA Xenoborg_Deaths[]; + + DEATH_DATA* this_death = NULL; + + switch (code>>16) + { + case 0: + this_death = &Alien_Deaths[0]; + break; + case 1: + this_death = &Marine_Deaths[0]; + break; + case 2: + return &Predator_Special_SelfDestruct_Death; + + case 3: + this_death = &Predator_Deaths[0]; + break; + case 4: + this_death = &Xenoborg_Deaths[0]; + break; + default: + return 0; + } + + + while (this_death->Sequence_Type>=0) { + if (this_death->Unique_Code==code) { + return this_death; + } + this_death++; + } + + return 0; +} + + +DEATH_DATA *GetDeathSequence(HMODELCONTROLLER *controller,SECTION *TemplateRoot,DEATH_DATA *FirstDeath,int wound_flags,int priority_wounds, + int hurtiness,HIT_FACING *facing,int burning,int crouching,int electrical) { + + int number_of_candidates; + int index; + + int use_wound_flags; + int use_priority_wounds; + int use_hurtiness; + HIT_FACING *use_facing; + int use_burning; + int use_crouching; + int use_electrical; + + use_priority_wounds=priority_wounds; + use_wound_flags=wound_flags; + use_hurtiness=hurtiness; + use_facing=facing; + use_burning=burning; + use_crouching=crouching; + use_electrical=electrical; + + number_of_candidates=0; + + while (number_of_candidates==0) { + /* Iterate, making simplifications, until there are valid deaths. */ + number_of_candidates=CountValidDeaths(controller,TemplateRoot,FirstDeath,use_wound_flags,use_priority_wounds,use_hurtiness,use_facing,use_burning,use_crouching,use_electrical); + if (number_of_candidates==0) { + /* Right. Make a change. Priority wounds first. */ + if (use_priority_wounds) { + use_priority_wounds=0; + continue; + } + /* Wound flags next. */ + if (use_wound_flags!=0xffffffff) { + use_wound_flags=0xffffffff; + continue; + } + /* Now facing. */ + if (use_facing) { + use_facing=NULL; + continue; + } + /* Now hurtiness. */ + if (use_hurtiness) { + use_hurtiness--; + continue; + } + /* Now electrical. */ + if (use_electrical) { + use_electrical=0; + continue; + } + /* Finally, burning. */ + if (use_burning) { + use_burning=0; + continue; + } + /* Only crouch is left! */ + //NewOnScreenMessage("DEATH SELECTION FAILURE!\n"); + if (use_crouching) { + use_crouching=0; + continue; + } + //NewOnScreenMessage("I REALLY MEAN IT!\n"); + /* Here goes nothing. */ + return(FirstDeath); + } + } + + /* Right, by now we should have a number of candidates. */ + GLOBALASSERT(number_of_candidates); + + index=FastRandom()%number_of_candidates; + + return(GetThisDeath(controller,TemplateRoot,FirstDeath,use_wound_flags,use_priority_wounds, + use_hurtiness,use_facing,use_burning,use_crouching,use_electrical,index)); +} + +DEATH_DATA *GetAlienDeathSequence(HMODELCONTROLLER *controller,SECTION *TemplateRoot,int wound_flags,int priority_wounds, + int hurtiness,HIT_FACING *facing,int burning,int crouching, int electrical) { + + return(GetDeathSequence(controller,TemplateRoot,Alien_Deaths,wound_flags,priority_wounds,hurtiness,facing,burning,crouching,electrical)); + +} + +DEATH_DATA *GetMarineDeathSequence(HMODELCONTROLLER *controller,SECTION *TemplateRoot,int wound_flags,int priority_wounds, + int hurtiness,HIT_FACING *facing,int burning,int crouching, int electrical) { + + return(GetDeathSequence(controller,TemplateRoot,Marine_Deaths,wound_flags,priority_wounds,hurtiness,facing,burning,crouching,electrical)); + +} + +DEATH_DATA *GetPredatorDeathSequence(HMODELCONTROLLER *controller,SECTION *TemplateRoot,int wound_flags,int priority_wounds, + int hurtiness,HIT_FACING *facing,int burning,int crouching,int electrical) { + + return(GetDeathSequence(controller,TemplateRoot,Predator_Deaths,wound_flags,priority_wounds,hurtiness,facing,burning,crouching,electrical)); + +} + +DEATH_DATA *GetXenoborgDeathSequence(HMODELCONTROLLER *controller,SECTION *TemplateRoot,int wound_flags,int priority_wounds, + int hurtiness,HIT_FACING *facing,int burning,int crouching,int electrical) { + + return(GetDeathSequence(controller,TemplateRoot,Xenoborg_Deaths,wound_flags,priority_wounds,hurtiness,facing,burning,crouching,electrical)); + +} + +/* Attack Shell */ + +int CheckAttackValidity(HMODELCONTROLLER *controller,ATTACK_DATA *ThisAttack,int wound_flags, + int crouching,int pouncing) { + + /* Check against many things. Harshly. */ + + /* Crouching test. */ + if (crouching) { + if (ThisAttack->Crouching==0) { + return(0); + } + } else { + if (ThisAttack->Crouching!=0) { + return(0); + } + } + + /* Pouncing test. */ + if (pouncing) { + if (ThisAttack->Pouncing==0) { + return(0); + } + } else { + if (ThisAttack->Pouncing!=0) { + return(0); + } + } + + /* Wound flags. Quite odd, and different to deaths. */ + /* If wound_flags are specified in the death, the input must NOT contain them. */ + if (ThisAttack->wound_flags) { + if (ThisAttack->wound_flags&wound_flags) { + return(0); + } + } + + /* Finally, sequence validity. */ + if (!HModelSequence_Exists(controller,ThisAttack->Sequence_Type,ThisAttack->Sub_Sequence)) { + return(0); + } + + /* It got through! */ + return(1); +} + +int CountValidAttacks(HMODELCONTROLLER *controller,ATTACK_DATA *FirstAttack,int wound_flags, + int crouching, int pouncing) { + + ATTACK_DATA *this_attack; + int number_of_candidates; + + number_of_candidates=0; + this_attack=FirstAttack; + + while (this_attack->Sequence_Type>=0) { + if (CheckAttackValidity(controller,this_attack,wound_flags,crouching,pouncing)) { + number_of_candidates++; + } + this_attack++; + } + + return(number_of_candidates); +} + +ATTACK_DATA *GetThisAttack(HMODELCONTROLLER *controller,ATTACK_DATA *FirstAttack,int wound_flags, + int crouching, int pouncing, int index) { + + /* Extract 'index' from the valid attacks. */ + ATTACK_DATA *retval; + ATTACK_DATA *this_attack; + int number; + + retval=NULL; + + number=0; + this_attack=FirstAttack; + + while (this_attack->Sequence_Type>=0) { + if (CheckAttackValidity(controller,this_attack,wound_flags,crouching,pouncing)) { + if (number==index) { + retval=this_attack; + break; + } else { + number++; + } + } + this_attack++; + } + + GLOBALASSERT(retval); + return(retval); +} + +ATTACK_DATA *GetThisAttack_FromUniqueCode(int code) +{ + extern ATTACK_DATA Alien_Special_Gripping_Attack; + //search for an attack using a code that should be unique across all attacks + //(used for loading) + + ATTACK_DATA *this_attack; + if(code<0) return NULL; + + + ///try the alien attacks + this_attack = &Alien_Attacks[0]; + while (this_attack->Sequence_Type>=0) { + if (this_attack->Unique_Code==code) { + return this_attack; + break; + } + this_attack++; + } + + //try the wristblade attacks + this_attack = &Wristblade_Attacks[0]; + while (this_attack->Sequence_Type>=0) { + if (this_attack->Unique_Code==code) { + return this_attack; + break; + } + this_attack++; + } + + //try the staff attacks + this_attack = &PredStaff_Attacks[0]; + while (this_attack->Sequence_Type>=0) { + if (this_attack->Unique_Code==code) { + return this_attack; + break; + } + this_attack++; + } + + //try gripping attack + if(Alien_Special_Gripping_Attack.Unique_Code==code) + { + return &Alien_Special_Gripping_Attack; + } + + //no such attack + return NULL; +} + + +ATTACK_DATA *GetThisAttack_FromCode(HMODELCONTROLLER *controller,ATTACK_DATA *FirstAttack,int code) { + + /* Extract 'code' from the valid attacks. */ + ATTACK_DATA *retval; + ATTACK_DATA *this_attack; + + retval=NULL; + + this_attack=FirstAttack; + + while (this_attack->Sequence_Type>=0) { + if (this_attack->Multiplayer_Code==code) { + retval=this_attack; + break; + } + this_attack++; + } + + GLOBALASSERT(retval); + return(retval); +} + +ATTACK_DATA *GetAttackSequence(HMODELCONTROLLER *controller,ATTACK_DATA *FirstAttack,int wound_flags,int crouching, int pouncing) { + + int number_of_candidates; + int index; + + int use_wound_flags; + int use_crouching; + + use_wound_flags=wound_flags; + use_crouching=crouching; + + number_of_candidates=0; + + while (number_of_candidates==0) { + /* Iterate, making simplifications, until there are valid deaths. */ + number_of_candidates=CountValidAttacks(controller,FirstAttack,use_wound_flags,use_crouching,pouncing); + if (number_of_candidates==0) { + /* Wound flags first. */ + if (use_wound_flags!=0) { + use_wound_flags=0; + continue; + } + /* Only crouch is left! */ + if (use_crouching) { + use_crouching=0; + continue; + } + /* Now, pounce is absolutely inviolate. */ + if (pouncing) { + /* If we're looking for a pounce, and there is none, return NULL. */ + return(NULL); + } + //NewOnScreenMessage("ATTACK SELECTION FAILURE!\n"); + /* Here goes nothing. */ + return(FirstAttack); + } + } + + /* Right, by now we should have a number of candidates. */ + GLOBALASSERT(number_of_candidates); + + index=FastRandom()%number_of_candidates; + + return(GetThisAttack(controller,FirstAttack,use_wound_flags, + use_crouching,pouncing,index)); +} + +ATTACK_DATA *GetAlienAttackSequence(HMODELCONTROLLER *controller,int wound_flags,int crouching) { + + return(GetAttackSequence(controller,Alien_Attacks,wound_flags,crouching,0)); + +} + +ATTACK_DATA *GetAlienPounceAttack(HMODELCONTROLLER *controller,int wound_flags,int crouching) { + + return(GetAttackSequence(controller,Alien_Attacks,wound_flags,crouching,1)); + +} + +ATTACK_DATA *GetWristbladeAttackSequence(HMODELCONTROLLER *controller,int wound_flags,int crouching) { + + return(GetAttackSequence(controller,Wristblade_Attacks,wound_flags,crouching,0)); + +} + +ATTACK_DATA *GetPredStaffAttackSequence(HMODELCONTROLLER *controller,int wound_flags,int crouching) { + + return(GetAttackSequence(controller,PredStaff_Attacks,wound_flags,crouching,0)); + +} + +AIMODULE *NearNPC_GetTargetAIModuleForRetreat(STRATEGYBLOCK *sbPtr, NPC_MOVEMENTDATA *moveData) +{ + extern unsigned int PlayerSmell; + + AIMODULE **AdjModuleRefPtr; + AIMODULE* targetModule = (AIMODULE *)0; + unsigned int targetSmell = PlayerSmell + 1; /* should be higher than any smell anywhere this frame */ + unsigned int targetNumAdj = 0; + int targetEpDot=-ONE_FIXED; + VECTORCH lastVelocityDirection; + int gotLastVelocityDirection = 0; + + LOCALASSERT(sbPtr); + if(sbPtr->containingModule==NULL) return targetModule; + AdjModuleRefPtr = sbPtr->containingModule->m_aimodule->m_link_ptrs; + + /* try to get our last velocity direction */ + if((moveData->lastVelocity.vx!=0)||(moveData->lastVelocity.vz!=0)||(moveData->lastVelocity.vy!=0)) + { + lastVelocityDirection = moveData->lastVelocity; + Normalise(&lastVelocityDirection); + gotLastVelocityDirection = 1; + } + else gotLastVelocityDirection = 0; + + /* check that there is a list of adjacent modules, and that it is not + empty (ie points to zero) */ + if(AdjModuleRefPtr) + { + while(*AdjModuleRefPtr != 0) + { + + /* get the index */ + int AdjModuleIndex = (*AdjModuleRefPtr)->m_index; + int AdjModuleSmell = PherPl_ReadBuf[AdjModuleIndex]; + FARENTRYPOINT *thisEp = GetAIModuleEP((*AdjModuleRefPtr), sbPtr->containingModule->m_aimodule); + int thisEpDot = -ONE_FIXED; + int chooseThisOne = 0; + + if(thisEp) + { + /* aha. an ep!... */ + VECTORCH thisEpWorld = thisEp->position; + + thisEpWorld.vx += (*AdjModuleRefPtr)->m_world.vx; + thisEpWorld.vy += (*AdjModuleRefPtr)->m_world.vy; + thisEpWorld.vz += (*AdjModuleRefPtr)->m_world.vz; + + if(gotLastVelocityDirection) + { + VECTORCH thisEpDirection; + + thisEpDirection = thisEpWorld; + thisEpDirection.vx -= sbPtr->DynPtr->Position.vx; + thisEpDirection.vy -= sbPtr->DynPtr->Position.vy; + thisEpDirection.vz -= sbPtr->DynPtr->Position.vz; + Normalise(&thisEpDirection); + thisEpDot = DotProduct(&thisEpDirection,&lastVelocityDirection); + } + } + + /* if this adjacent module's smell value is lower than + the current 'highest smell' record the new module as the + target. + Tie break on best direction. */ + + if (!targetModule) { + chooseThisOne=1; + } else { + if (AdjModuleSmell < targetSmell) { + chooseThisOne=1; + } else if (AdjModuleSmell == targetSmell) { + if (thisEpDot>targetEpDot) { + chooseThisOne=1; + } + } + } + + if (chooseThisOne) + { + targetSmell = PherPl_ReadBuf[AdjModuleIndex]; + targetModule = *AdjModuleRefPtr; + targetNumAdj = NumAdjacentModules(*AdjModuleRefPtr); + targetEpDot = thisEpDot; + } + /* next adjacent module reference pointer */ + AdjModuleRefPtr++; + } + } + return targetModule; +} + +AIMODULE *General_GetRetreatModule_Core(STRATEGYBLOCK *sbPtr,AIMODULE *source,int max_depth) { + + AIMODULE **AdjModuleRefPtr; + AIMODULE *deepest_target; + NL_ROUTE_QUEUE deepest_route; + + /* Note this DOES NOT set the CallsThisFrame variable. That MUST be set before the call. */ + + /* Clear the start. */ + + deepest_route.depth=0; + deepest_route.aimodule=NULL; + deepest_route.first_step=NULL; + deepest_target=NULL; + + NearLink_Route_Queue[0].depth=0; + NearLink_Route_Queue[0].aimodule=source; + NearLink_Route_Queue[0].first_step=NULL; + NearLink_Route_Queue[1].aimodule=NULL; /* To set a standard. */ + + NL_Queue_End=1; + NL_Queue_Exec=0; + + while (NearLink_Route_Queue[NL_Queue_Exec].aimodule!=NULL) { + + AIMODULE *thisModule; + + thisModule=NearLink_Route_Queue[NL_Queue_Exec].aimodule; + + AdjModuleRefPtr = thisModule->m_link_ptrs; + + if(AdjModuleRefPtr) /* check that there is a list of adjacent modules */ + { + while(*AdjModuleRefPtr != 0) + { + /* Probably want some validity test for the link. */ + if ((AIModuleIsPhysical(*AdjModuleRefPtr)) + &&(AIModuleAdmitsPheromones(*AdjModuleRefPtr)) + /* No visibility check? */ + ) { + + /* Consider depth? */ + if (NearLink_Route_Queue[NL_Queue_Exec].depthRouteFinder_FrameStamp!=GlobalFrameCounter) + ||((*AdjModuleRefPtr)->RouteFinder_IterationNumber!=RouteFinder_CallsThisFrame) + )) { + /* Add to queue. */ + NearLink_Route_Queue[NL_Queue_End].aimodule=(*AdjModuleRefPtr); + NearLink_Route_Queue[NL_Queue_End].depth=NearLink_Route_Queue[NL_Queue_Exec].depth+1; + /* Remember first step. */ + if (NearLink_Route_Queue[NL_Queue_Exec].first_step==NULL) { + NearLink_Route_Queue[NL_Queue_End].first_step=(*AdjModuleRefPtr); + } else { + NearLink_Route_Queue[NL_Queue_End].first_step=NearLink_Route_Queue[NL_Queue_Exec].first_step; + } + /* Stamp as used. */ + (*AdjModuleRefPtr)->RouteFinder_FrameStamp=GlobalFrameCounter; + (*AdjModuleRefPtr)->RouteFinder_IterationNumber=RouteFinder_CallsThisFrame; + NL_Queue_End++; + if (NL_Queue_End>=NEARLINK_QUEUE_LENGTH) { + NL_Queue_End=0; + textprint("Wrapping Nearlink Queue!\n"); + } + NearLink_Route_Queue[NL_Queue_End].aimodule=NULL; + if (NL_Queue_End==NL_Queue_Exec) { + LOGDXFMT(("Oh, no. NearLinkQueue screwed. NL_Queue_End=%d, depth = %d\n",NL_Queue_End,NearLink_Route_Queue[NL_Queue_Exec].depth)); + LOCALASSERT(NL_Queue_End!=NL_Queue_Exec); //if this happens the queue probably needs to be longer + } + } else if (NearLink_Route_Queue[NL_Queue_Exec].depth>=max_depth) { + /* That's well deep. Let's return. */ + + return(*AdjModuleRefPtr); + + } + } + /* next adjacent module reference pointer */ + AdjModuleRefPtr++; + } + } + + /* Done all the links. */ + NL_Queue_Exec++; + if (NL_Queue_Exec>=NEARLINK_QUEUE_LENGTH) NL_Queue_Exec=0; + + } + + if (deepest_target) { + /* Split up for easier debugging... */ + return(deepest_target); + } else { + /* There's nowhere to retreat to! */ + return(NULL); + } + +} + +AIMODULE *General_GetAIModuleForRetreat(STRATEGYBLOCK *sbPtr,AIMODULE *fearModule,int max_depth) { + + AIMODULE **AdjModuleRefPtr; + AIMODULE *my_module; + int success; + + GLOBALASSERT(sbPtr->containingModule); + my_module=sbPtr->containingModule->m_aimodule; + GLOBALASSERT(my_module); + + if (fearModule==NULL) { + return(NULL); + } + + /* Hmm... maybe we need to consider being in sight at some point. */ + #if 0 + /* Firstly, are we in sight of the fear module? */ + if (IsModuleVisibleFromModule((*fearModule->m_module_ptrs),sbPtr->containingModule)) { + /* Hmm, still in sight. Try to get out of sight. */ + } else { + } + #endif + + /* Step one: search down till we get to my_module, checking off modules. */ + + if (my_module==fearModule) { + /* Cripes! */ + AIMODULE *targetModule; + + RouteFinder_CallsThisFrame++; + targetModule=General_GetRetreatModule_Core(sbPtr,my_module,max_depth); + return(targetModule); + + } + + /* Clear the start. */ + + NearLink_Route_Queue[0].depth=0; + NearLink_Route_Queue[0].aimodule=fearModule; + NearLink_Route_Queue[0].first_step=NULL; + NearLink_Route_Queue[1].aimodule=NULL; /* To set a standard. */ + + NL_Queue_End=1; + NL_Queue_Exec=0; + success=0; + + /* Hijack RouteFinder. */ + RouteFinder_CallsThisFrame++; + + while (NearLink_Route_Queue[NL_Queue_Exec].aimodule!=NULL) { + + AIMODULE *thisModule; + + thisModule=NearLink_Route_Queue[NL_Queue_Exec].aimodule; + + AdjModuleRefPtr = thisModule->m_link_ptrs; + + if(AdjModuleRefPtr) /* check that there is a list of adjacent modules */ + { + while(*AdjModuleRefPtr != 0) + { + /* Probably want some validity test for the link. */ + if ((AIModuleIsPhysical(*AdjModuleRefPtr)) + &&(AIModuleAdmitsPheromones(*AdjModuleRefPtr)) + /* No visibility check. */ + ) { + /* Is this my_module? */ + if ( (*AdjModuleRefPtr)==my_module) { + /* Yes!!! Break out. */ + success=1; + break; + } else if ( + (NearLink_Route_Queue[NL_Queue_Exec].depthRouteFinder_FrameStamp!=GlobalFrameCounter) + ||((*AdjModuleRefPtr)->RouteFinder_IterationNumber!=RouteFinder_CallsThisFrame) + )) { + + success=0; + /* Add to queue. */ + NearLink_Route_Queue[NL_Queue_End].aimodule=(*AdjModuleRefPtr); + NearLink_Route_Queue[NL_Queue_End].depth=NearLink_Route_Queue[NL_Queue_Exec].depth+1; + /* Remember first step. */ + if (NearLink_Route_Queue[NL_Queue_Exec].first_step==NULL) { + NearLink_Route_Queue[NL_Queue_End].first_step=(*AdjModuleRefPtr); + } else { + NearLink_Route_Queue[NL_Queue_End].first_step=NearLink_Route_Queue[NL_Queue_Exec].first_step; + } + /* Stamp as used. */ + (*AdjModuleRefPtr)->RouteFinder_FrameStamp=GlobalFrameCounter; + (*AdjModuleRefPtr)->RouteFinder_IterationNumber=RouteFinder_CallsThisFrame; + NL_Queue_End++; + if (NL_Queue_End>=NEARLINK_QUEUE_LENGTH) { + NL_Queue_End=0; + textprint("Wrapping Nearlink Queue!\n"); + } + NearLink_Route_Queue[NL_Queue_End].aimodule=NULL; + if (NL_Queue_End==NL_Queue_Exec) { + LOGDXFMT(("Oh, no. NearLinkQueue screwed. NL_Queue_End=%d, depth = %d\n",NL_Queue_End,NearLink_Route_Queue[NL_Queue_Exec].depth)); + LOCALASSERT(NL_Queue_End!=NL_Queue_Exec); //if this happens the queue probably needs to be longer + } + } + } + /* next adjacent module reference pointer */ + AdjModuleRefPtr++; + } + } + + /* Done all the links. */ + + if (success) { + /* Continue break out. */ + break; + } + + NL_Queue_Exec++; + if (NL_Queue_Exec>=NEARLINK_QUEUE_LENGTH) NL_Queue_Exec=0; + + } + + /* By now, we should have broken out... or maxed out the range. */ + if (success) { + AIMODULE *targetModule; + targetModule=General_GetRetreatModule_Core(sbPtr,my_module,max_depth); + return(targetModule); + } else { + return(NULL); + } +} + +int AIModuleIsVisible(AIMODULE *aimodule) { + + MODULE **module_list; + /* D'oh! */ + module_list=aimodule->m_module_ptrs; + + while (*module_list) { + if (ModuleCurrVisArray[(*module_list)->m_index]) { + return(1); + } + module_list++; + } + + return(0); +} + +int IsMyPolyRidiculous(void) { + + int a,sideend,distance; + VECTORCH side; + + /* Please make sure the globals are sensible! */ + + a=0; + + for (a=0; a=(GMD_myPolyNumPoints-1)) { + sideend=0; + } else { + sideend=a+1; + } + + side.vx=GMD_myPolyPoints[a].vx-GMD_myPolyPoints[sideend].vx; + side.vy=GMD_myPolyPoints[a].vy-GMD_myPolyPoints[sideend].vy; + side.vz=GMD_myPolyPoints[a].vz-GMD_myPolyPoints[sideend].vz; + + distance=Approximate3dMagnitude(&side); + + if (distance<1000) { + /* Stoopid! */ + return(1); + } + } + + return(0); +} + +void Initialise_AvoidanceManager(STRATEGYBLOCK *sbPtr, NPC_AVOIDANCEMANAGER *manager) { + + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(manager); + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + ClearThirdAvoidance(sbPtr,manager); + + manager->avoidanceDirection.vx=0; + manager->avoidanceDirection.vy=0; + manager->avoidanceDirection.vz=0; + + manager->incidenceDirection.vx=0; + manager->incidenceDirection.vy=0; + manager->incidenceDirection.vz=0; + + manager->incidentPoint.vx=0; + manager->incidentPoint.vy=0; + manager->incidentPoint.vz=0; + + manager->aggregateNormal.vx=0; + manager->aggregateNormal.vy=0; + manager->aggregateNormal.vz=0; + + manager->recommendedDistance=0; + manager->timer=0; + manager->primaryCollision=NULL; + manager->substate=AvSS_FreeMovement; + + if ((sbPtr->I_SBtype==I_BehaviourAlien)||(sbPtr->I_SBtype==I_BehaviourFaceHugger)) { + /* Allows destruction of explosive objects. */ + manager->ClearanceDamage=AMMO_ALIEN_OBSTACLE_CLEAR; + } else { + manager->ClearanceDamage=AMMO_NPC_OBSTACLE_CLEAR; + } +} + +int New_NPC_IsObstructed(STRATEGYBLOCK *sbPtr, NPC_AVOIDANCEMANAGER *manager) +{ + DYNAMICSBLOCK *dynPtr; + struct collisionreport *nextReport; + VECTORCH myVelocityDirection,aggregateNormal; + int numObstructiveCollisions; + STRATEGYBLOCK *highestPriorityCollision; + COLLISIONREPORT vcr; + + LOCALASSERT(manager); + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + nextReport = dynPtr->CollisionReportPtr; + + numObstructiveCollisions=0; + + /* check our velocity: if we haven't got one, we can't be obstructed, so just return */ + if((sbPtr->DynPtr->LinVelocity.vx==0)&&(sbPtr->DynPtr->LinVelocity.vy==0)&&(sbPtr->DynPtr->LinVelocity.vz==0)) + { + return(0); + } + + if (sbPtr->I_SBtype==I_BehaviourMarine) { + if (SimpleEdgeDetectionTest(sbPtr,&vcr)) { + vcr.NextCollisionReportPtr=nextReport; + nextReport=&vcr; + } + } + + if (nextReport==NULL) { + /* Trivial reject to save time. */ + return(0); + } + + /* get my velocity direction, normalised... */ + myVelocityDirection = dynPtr->LinVelocity; + Normalise(&myVelocityDirection); + + highestPriorityCollision=(STRATEGYBLOCK *)-1; + aggregateNormal.vx=0; + aggregateNormal.vy=0; + aggregateNormal.vz=0; + + if (manager->substate==AvSS_FreeMovement) { + Initialise_AvoidanceManager(sbPtr,manager); + } + + /* Walk the collision report list. */ + while(nextReport) + { + int normalDotWithVelocity; + + if(nextReport->ObstacleSBPtr) + { + /* Possible testing for type here. Personally, I don't care, apart from destructibles. */ + } + + normalDotWithVelocity = DotProduct(&(nextReport->ObstacleNormal),&myVelocityDirection); + + #if 0 + if(((normalDotWithVelocity < -46341)|| + ((nextReport->ObstacleSBPtr)&&(!SBIsEnvironment(nextReport->ObstacleSBPtr))&&(normalDotWithVelocity < -32768)))) + /* 45 degs vs environment, 60 degs vs objects. */ + #else + if (normalDotWithVelocity < -32768) + #endif + { + /* If we're in FirstAvoidance already, might want to disregard the same collision again. */ + if (manager->substate==AvSS_FirstAvoidance) { + if (!SBIsEnvironment(manager->primaryCollision)) { + if (manager->primaryCollision==nextReport->ObstacleSBPtr) { + /* Advance and continue. */ + nextReport = nextReport->NextCollisionReportPtr; + continue; + } + } + } + + /* We have detected a collision with a strategy, or an obstructive environment bit. */ + numObstructiveCollisions++; + aggregateNormal.vx+=nextReport->ObstacleNormal.vx; + aggregateNormal.vy+=nextReport->ObstacleNormal.vy; + aggregateNormal.vz+=nextReport->ObstacleNormal.vz; + + /* Sort out highest priority collision. */ + if (highestPriorityCollision==(STRATEGYBLOCK *)-1) { + highestPriorityCollision=nextReport->ObstacleSBPtr; + } else { + /* If this collision is with the environment, and the older one was not, replace it. */ + if (SBIsEnvironment(nextReport->ObstacleSBPtr)&&(!SBIsEnvironment(highestPriorityCollision))) { + highestPriorityCollision=nextReport->ObstacleSBPtr; + } + } + + { + if(nextReport->ObstacleSBPtr) + { + if(nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourInanimateObject) + { + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = nextReport->ObstacleSBPtr->SBdataptr; + if (objectstatusptr) { + if (objectstatusptr->Indestructable == 0) { + /* Consider explosive objects as obstructions to most things. */ + if ((objectstatusptr->explosionType==0)||(manager->ClearanceDamage!=AMMO_NPC_OBSTACLE_CLEAR)) { + /* aha: an object which the npc can destroy... damage it, and return zero. */ + CauseDamageToObject(nextReport->ObstacleSBPtr,&TemplateAmmo[manager->ClearanceDamage].MaxDamage, ONE_FIXED,NULL); + return(0); + /* After a few frames of that, there'll just be real obstructions. */ + } + } + } + } + } + } + } + nextReport = nextReport->NextCollisionReportPtr; + } + + if (numObstructiveCollisions==0) { + /* No collisions! Woohoo! But don't reset the substate... */ + return(0); + } + + switch (manager->substate) { + + case AvSS_FreeMovement: + default: + { + /* Right, we've run into something all right. */ + GLOBALASSERT(highestPriorityCollision!=(STRATEGYBLOCK *)-1); + + manager->primaryCollision=highestPriorityCollision; + manager->incidenceDirection=myVelocityDirection; + manager->incidentPoint=dynPtr->Position; + /* Decide on a distance... */ + + if (SBIsEnvironment(manager->primaryCollision)) { + manager->recommendedDistance=3000; + } else { + manager->recommendedDistance=2000; + } + manager->timer=STANDARD_AVOIDANCE_TIME; + + /* ...and a direction. */ + Normalise(&aggregateNormal); + manager->aggregateNormal=aggregateNormal; + + if (New_GetAvoidanceDirection(sbPtr,manager,&aggregateNormal)==0) { + /* No valid directions in pass 1 - not dealt with yet! */ + GLOBALASSERT(0); + } + + manager->substate=AvSS_FirstAvoidance; + + return(1); + } + break; + case AvSS_FirstAvoidance: + { + /* Right, we've run into something again. */ + + /* Retain point, direction and distance. */ + + /* ...but get a new direction. */ + aggregateNormal.vx+=manager->aggregateNormal.vx; + aggregateNormal.vy+=manager->aggregateNormal.vy; + aggregateNormal.vz+=manager->aggregateNormal.vz; + /* Add the new aggregatenormal to the old one, and normalise... */ + Normalise(&aggregateNormal); + /* Then pass that number into the second direction system. */ + if (New_GetSecondAvoidanceDirection(sbPtr,manager,&aggregateNormal)==0) { + /* No valid directions in pass 2 - not dealt with yet! */ + GLOBALASSERT(0); + } + + manager->substate=AvSS_SecondAvoidance; + manager->timer=STANDARD_AVOIDANCE_TIME; + + return(1); + } + case AvSS_SecondAvoidance: + case AvSS_ThirdAvoidance: + { + /* Right, we've run into something again again. (Again.) */ + + /* Retain point, direction and distance, and go directly to third avoidance. */ + + manager->timer=STANDARD_AVOIDANCE_TIME; + InitialiseThirdAvoidance(sbPtr,manager); + + return(1); + } + break; + } +} + +AVOIDANCE_RETURN_CONDITION AllNewAvoidanceKernel(STRATEGYBLOCK *sbPtr,NPC_AVOIDANCEMANAGER *manager) { + + DYNAMICSBLOCK *dynPtr; + + /* Velocity must be set deliberately... even if it's null. */ + + LOCALASSERT(manager); + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + /* Want to split here based on substate. */ + + switch (manager->substate) { + case AvSS_FreeMovement: + { + /* Really shouldn't be here. Go'way. */ + Initialise_AvoidanceManager(sbPtr,manager); + return(AvRC_Clear); + break; + } + case AvSS_FirstAvoidance: + { + if (New_NPC_IsObstructed(sbPtr,manager)==1) { + /* We're obstructed AGAIN! */ + return(AvRC_Avoidance); + } + + /* Are we far enough away? */ + { + int distance; + VECTORCH offset; + + offset.vx=dynPtr->Position.vx-manager->incidentPoint.vx; + offset.vy=dynPtr->Position.vy-manager->incidentPoint.vy; + offset.vz=dynPtr->Position.vz-manager->incidentPoint.vz; + + distance=Approximate3dMagnitude(&offset); + + if (distance>manager->recommendedDistance) { + /* Exit! */ + Initialise_AvoidanceManager(sbPtr,manager); + return(AvRC_Clear); + } + } + + manager->timer-=NormalFrameTime; + if (manager->timer<=0) { + /* Ooh, we're in a fix here... */ + /* Probably need Avoidance 3 for this. */ + InitialiseThirdAvoidance(sbPtr,manager); + return(AvRC_Avoidance); + } + break; + } + case AvSS_SecondAvoidance: + { + if (New_NPC_IsObstructed(sbPtr,manager)==1) { + /* Should be in Third Avoidance here. */ + return(AvRC_Avoidance); + } + + /* Are we far enough away? */ + { + int distance; + VECTORCH offset; + + offset.vx=dynPtr->Position.vx-manager->incidentPoint.vx; + offset.vy=dynPtr->Position.vy-manager->incidentPoint.vy; + offset.vz=dynPtr->Position.vz-manager->incidentPoint.vz; + + distance=Approximate3dMagnitude(&offset); + + if (distance>manager->recommendedDistance) { + /* Exit! */ + Initialise_AvoidanceManager(sbPtr,manager); + return(AvRC_Clear); + } + } + + manager->timer-=NormalFrameTime; + if (manager->timer<=0) { + /* Ooh, we're in a fix here... */ + /* Probably need Avoidance 3 for this. */ + InitialiseThirdAvoidance(sbPtr,manager); + return(AvRC_Avoidance); + } + break; + } + case AvSS_ThirdAvoidance: + { + int result; + /* Let's have a whole function here! */ + result=ExecuteThirdAvoidance(sbPtr,manager); + if (result==-1) { + /* Totally fubared. Return failure. */ + Initialise_AvoidanceManager(sbPtr,manager); + return(AvRC_Failure); + } else if (result==1) { + /* Success! Return clear. */ + Initialise_AvoidanceManager(sbPtr,manager); + return(AvRC_Clear); + } else { + /* Still going, return avoidance. */ + return(AvRC_Avoidance); + } + break; + } + default: + GLOBALASSERT(0); + break; + } + + return(AvRC_Avoidance); + +} + +int New_GetAvoidanceDirection(STRATEGYBLOCK *sbPtr, NPC_AVOIDANCEMANAGER *manager, VECTORCH *aggregateNormal) { + + DYNAMICSBLOCK *dynPtr; + int dot; + VECTORCH spaceNormal,transverse; + VECTORCH direction[4]; + /* Yeesh. */ + + LOCALASSERT(manager); + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + /* aggregateNormal should be normalised, and should point away from the collisions. */ + /* First dot it with gravity... */ + + if (dynPtr->UseStandardGravity) { + dynPtr->GravityDirection.vx=0; + dynPtr->GravityDirection.vy=65536; + dynPtr->GravityDirection.vz=0; + } + + dot = -(DotProduct(&dynPtr->GravityDirection,aggregateNormal)); + /* Hold that thought. */ + spaceNormal.vx = (aggregateNormal->vx + MUL_FIXED(dot,dynPtr->GravityDirection.vx)); + spaceNormal.vy = (aggregateNormal->vy + MUL_FIXED(dot,dynPtr->GravityDirection.vy)); + spaceNormal.vz = (aggregateNormal->vz + MUL_FIXED(dot,dynPtr->GravityDirection.vz)); + + Normalise(&spaceNormal); + /* Now, spaceNormal should be in the plane we want to consider. */ + CrossProduct(&spaceNormal,&dynPtr->GravityDirection,&transverse); + Normalise(&transverse); + /* ...And 'transverse' should be at 90degs to it. */ + + /* For now, emulate the old avoidance code... */ + + direction[0]=transverse; + direction[1].vx=-transverse.vx; + direction[1].vy=-transverse.vy; + direction[1].vz=-transverse.vz; + + // Added by Alex - see if we can get a better direction this way. + direction[2] = spaceNormal; + direction[3].vx = -direction[2].vx; + direction[3].vy = -direction[2].vy; + direction[3].vz = -direction[2].vz; + + direction[0].vx += (spaceNormal.vx/4); + direction[0].vy += (spaceNormal.vy/4); + direction[0].vz += (spaceNormal.vz/4); + direction[1].vx += (spaceNormal.vx/4); + direction[1].vy += (spaceNormal.vy/4); + direction[1].vz += (spaceNormal.vz/4); + + direction[2].vx -= (transverse.vx/4); + direction[2].vy -= (transverse.vy/4); + direction[2].vz -= (transverse.vz/4); + direction[3].vx -= (transverse.vx/4); + direction[3].vy -= (transverse.vy/4); + direction[3].vz -= (transverse.vz/4); + + Normalise(&direction[0]); + Normalise(&direction[1]); + Normalise(&direction[2]); + Normalise(&direction[3]); + + { + int this_distance, i; + int best_distance_so_far = 0; + int best_direction_so_far = 0; + + /* test how far we could go in each direction... */ + for( i=0; i<4; i++ ) + { + VECTORCH startingPosition = sbPtr->DynPtr->Position; + VECTORCH testDirn = direction[i]; + + LOS_ObjectHitPtr = (DISPLAYBLOCK *)0; + LOS_Lambda = NPC_MAX_VIEWRANGE; + CheckForVectorIntersectionWith3dObject(sbPtr->containingModule->m_dptr,&startingPosition,&testDirn,0); + if(!LOS_ObjectHitPtr) this_distance = NPC_MAX_VIEWRANGE; + else this_distance = LOS_Lambda; + + if( this_distance > best_distance_so_far ) + { + // What follows is an attempt to make sure we don't jump off any cliffs... + VECTORCH test_location; + int test_distance = this_distance / 2; + testDirn.vx *= this_distance; + testDirn.vy *= this_distance; + testDirn.vz *= this_distance; + test_location.vx = startingPosition.vx + testDirn.vx; + test_location.vy = startingPosition.vy + testDirn.vy; + test_location.vz = startingPosition.vz + testDirn.vz; + if( CheckMyFloorPoly(&test_location, sbPtr->containingModule) != NPC_GMD_NOPOLY) + { + best_direction_so_far = i; + best_distance_so_far = this_distance; + } + } + + } + + manager->avoidanceDirection = direction[best_direction_so_far]; + } + + return(1); +} + +int GetAvoidanceDirection(STRATEGYBLOCK *sbPtr, NPC_AVOIDANCEMANAGER *manager) +{ + DYNAMICSBLOCK *dynPtr; + VECTORCH newDirection1, newDirection2; + int dir1dist, dir2dist; + MATRIXCH matrix; + EULER euler; + + LOCALASSERT(manager); + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + /* just in case */ + if(!sbPtr->containingModule) return(0); + + /* going for a 90 degree turn + back a bit */ + newDirection1 = manager->incidenceDirection; + newDirection2 = newDirection1; + euler.EulerX = 0; + euler.EulerY = 1024; + euler.EulerZ = 0; + CreateEulerMatrix( &euler, &matrix ); + RotateVector( &newDirection1, &matrix ); + euler.EulerY = 3072; + CreateEulerMatrix( &euler, &matrix ); + RotateVector( &newDirection2, &matrix ); + +#if 0 + /* construct the direction(s)... + start with object's local x unit vector (from local coo-ord system in world space) */ + newDirection1.vx = sbPtr->DynPtr->OrientMat.mat11; + newDirection1.vy = sbPtr->DynPtr->OrientMat.mat12; + newDirection1.vz = sbPtr->DynPtr->OrientMat.mat13; + newDirection2.vx = -newDirection1.vx; + newDirection2.vy = -newDirection1.vy; + newDirection2.vz = -newDirection1.vz; + /* ...and add on 1/4 of the -z direction...*/ + newDirection1.vx -= (sbPtr->DynPtr->OrientMat.mat31/4); + newDirection1.vy -= (sbPtr->DynPtr->OrientMat.mat32/4); + newDirection1.vz -= (sbPtr->DynPtr->OrientMat.mat33/4); + newDirection2.vx -= (sbPtr->DynPtr->OrientMat.mat31/4); + newDirection2.vy -= (sbPtr->DynPtr->OrientMat.mat32/4); + newDirection2.vz -= (sbPtr->DynPtr->OrientMat.mat33/4); +#endif + + Normalise(&newDirection1); + Normalise(&newDirection2); + + /* test how far we could go in each direction... */ + { + VECTORCH startingPosition = sbPtr->DynPtr->Position; + VECTORCH testDirn = newDirection1; + + LOS_ObjectHitPtr = (DISPLAYBLOCK *)0; + LOS_Lambda = NPC_MAX_VIEWRANGE; + CheckForVectorIntersectionWith3dObject(sbPtr->containingModule->m_dptr,&startingPosition,&testDirn,0); + if(!LOS_ObjectHitPtr) dir1dist = NPC_MAX_VIEWRANGE; + else dir1dist = LOS_Lambda; + + startingPosition = sbPtr->DynPtr->Position; + testDirn = newDirection2; + LOS_ObjectHitPtr = (DISPLAYBLOCK *)0; + LOS_Lambda = NPC_MAX_VIEWRANGE; + CheckForVectorIntersectionWith3dObject(sbPtr->containingModule->m_dptr,&startingPosition,&testDirn,0); + if(!LOS_ObjectHitPtr) dir2dist = NPC_MAX_VIEWRANGE; + else dir2dist = LOS_Lambda; + } + + if(dir1dist > dir2dist) manager->avoidanceDirection = newDirection1; + else manager->avoidanceDirection = newDirection2; + + return(1); +} + +int New_GetSecondAvoidanceDirection(STRATEGYBLOCK *sbPtr, NPC_AVOIDANCEMANAGER *manager, VECTORCH *aggregateNormal) { + + DYNAMICSBLOCK *dynPtr; + int dot; + VECTORCH spaceNormal,transverse; + VECTORCH direction1,direction2; + /* Yeesh. */ + + LOCALASSERT(manager); + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + /* aggregateNormal should be normalised, and should point away from the collisions. */ + /* First dot it with gravity... */ + + dot = -(DotProduct(&dynPtr->GravityDirection,aggregateNormal)); + /* Hold that thought. */ + spaceNormal.vx = (aggregateNormal->vx + MUL_FIXED(dot,dynPtr->GravityDirection.vx)); + spaceNormal.vy = (aggregateNormal->vy + MUL_FIXED(dot,dynPtr->GravityDirection.vy)); + spaceNormal.vz = (aggregateNormal->vz + MUL_FIXED(dot,dynPtr->GravityDirection.vz)); + + Normalise(&spaceNormal); + /* Now, spaceNormal should be in the plane we want to consider. */ + CrossProduct(&spaceNormal,&dynPtr->GravityDirection,&transverse); + Normalise(&transverse); + /* ...And 'transverse' should be at 90degs to it. */ + + /* For now, emulate the old avoidance code... */ + + direction1=transverse; + direction2.vx=-transverse.vx; + direction2.vy=-transverse.vy; + direction2.vz=-transverse.vz; + + if ((FastRandom()&65535)<32767) { + direction1.vx += (spaceNormal.vx/2); + direction1.vy += (spaceNormal.vy/2); + direction1.vz += (spaceNormal.vz/2); + direction2.vx += (spaceNormal.vx/2); + direction2.vy += (spaceNormal.vy/2); + direction2.vz += (spaceNormal.vz/2); + } else { + direction1.vx += (spaceNormal.vx); + direction1.vy += (spaceNormal.vy); + direction1.vz += (spaceNormal.vz); + direction2.vx += (spaceNormal.vx); + direction2.vy += (spaceNormal.vy); + direction2.vz += (spaceNormal.vz); + } + + Normalise(&direction1); + Normalise(&direction2); + + { + int dir1dist,dir2dist; + /* test how far we could go in each direction... */ + { + VECTORCH startingPosition = sbPtr->DynPtr->Position; + VECTORCH testDirn = direction1; + + LOS_ObjectHitPtr = (DISPLAYBLOCK *)0; + LOS_Lambda = NPC_MAX_VIEWRANGE; + CheckForVectorIntersectionWith3dObject(sbPtr->containingModule->m_dptr,&startingPosition,&testDirn,0); + if(!LOS_ObjectHitPtr) dir1dist = NPC_MAX_VIEWRANGE; + else dir1dist = LOS_Lambda; + + startingPosition = sbPtr->DynPtr->Position; + testDirn = direction2; + LOS_ObjectHitPtr = (DISPLAYBLOCK *)0; + LOS_Lambda = NPC_MAX_VIEWRANGE; + CheckForVectorIntersectionWith3dObject(sbPtr->containingModule->m_dptr,&startingPosition,&testDirn,0); + if(!LOS_ObjectHitPtr) dir2dist = NPC_MAX_VIEWRANGE; + else dir2dist = LOS_Lambda; + } + + if(dir1dist > dir2dist) manager->avoidanceDirection = direction1; + else manager->avoidanceDirection = direction2; + } + + return(1); +} + +void AlignVelocityToGravity(STRATEGYBLOCK *sbPtr,VECTORCH *velocity) { + + DYNAMICSBLOCK *dynPtr; + int dot; + + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + if (dynPtr->UseStandardGravity) { + dynPtr->GravityDirection.vx=0; + dynPtr->GravityDirection.vy=65536; + dynPtr->GravityDirection.vz=0; + } + + dot = -(DotProduct(&dynPtr->GravityDirection,velocity)); + /* Hold that thought. */ + velocity->vx = (velocity->vx + MUL_FIXED(dot,dynPtr->GravityDirection.vx)); + velocity->vy = (velocity->vy + MUL_FIXED(dot,dynPtr->GravityDirection.vy)); + velocity->vz = (velocity->vz + MUL_FIXED(dot,dynPtr->GravityDirection.vz)); + + if ((velocity->vx==0)&&(velocity->vy==0)&&(velocity->vz==0)) { + /* That can't be good. Can it? */ + //velocity->vx=ONE_FIXED; + return; + } + + Normalise(velocity); + +} + +void ClearThirdAvoidance(STRATEGYBLOCK *sbPtr,NPC_AVOIDANCEMANAGER *manager) { + + LOCALASSERT(manager); + LOCALASSERT(sbPtr); + + manager->baseVector.vx=0; + manager->baseVector.vy=0; + manager->baseVector.vz=0; + manager->currentVector=manager->baseVector; + manager->avoidanceDirection.vx=0; + manager->avoidanceDirection.vy=0; + manager->avoidanceDirection.vz=0; + manager->bestVector.vx=0; + manager->bestVector.vy=0; + manager->bestVector.vz=0; + manager->basePoint=manager->baseVector; + manager->stage=0; + manager->bestDistance=0; + manager->bestStage=0; + /* Er... ignore the rotmat for now... */ +} + +void InitialiseThirdAvoidance(STRATEGYBLOCK *sbPtr,NPC_AVOIDANCEMANAGER *manager) { + + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(manager); + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + if (dynPtr->UseStandardGravity) { + dynPtr->GravityDirection.vx=0; + dynPtr->GravityDirection.vy=65536; + dynPtr->GravityDirection.vz=0; + } + /* Setup base vector. */ + { + int dot; + /* Try using positive... z. */ + manager->baseVector.vx=sbPtr->DynPtr->OrientMat.mat31; + manager->baseVector.vy=sbPtr->DynPtr->OrientMat.mat32; + manager->baseVector.vz=sbPtr->DynPtr->OrientMat.mat33; + + dot = (DotProduct(&dynPtr->GravityDirection,&manager->baseVector)); + + if (!((dot<65000)&&(dot>-65000))) { + /* Too close. Let's use x. */ + manager->baseVector.vx=sbPtr->DynPtr->OrientMat.mat11; + manager->baseVector.vy=sbPtr->DynPtr->OrientMat.mat12; + manager->baseVector.vz=sbPtr->DynPtr->OrientMat.mat13; + } + AlignVelocityToGravity(sbPtr,&manager->baseVector); + } + manager->currentVector=manager->baseVector; + + /* Keep still! */ + manager->avoidanceDirection.vx=0; + manager->avoidanceDirection.vy=0; + manager->avoidanceDirection.vz=0; + + manager->bestVector.vx=0; + manager->bestVector.vy=0; + manager->bestVector.vz=0; + + manager->basePoint=dynPtr->Position; + + manager->stage=0; + manager->bestDistance=0; + manager->bestStage=0; + + /* Finally, generate a matrix to rotate 22.5degs about GravityDirection. */ + + { + QUAT deltaRotQ; + /* Angle is 256, halfangle is 128. */ + int cosHalfAngle = GetCos(128); + int sinHalfAngle = GetSin(128); + + deltaRotQ.quatw=cosHalfAngle; + deltaRotQ.quatx=MUL_FIXED(sinHalfAngle,dynPtr->GravityDirection.vx); + deltaRotQ.quaty=MUL_FIXED(sinHalfAngle,dynPtr->GravityDirection.vy); + deltaRotQ.quatz=MUL_FIXED(sinHalfAngle,dynPtr->GravityDirection.vz); + + QNormalise(&deltaRotQ); + QuatToMat(&deltaRotQ,&manager->rotationMatrix); + + } + /* Say we're in Third Avoidance. */ + manager->substate=AvSS_ThirdAvoidance; +} + +int ExecuteThirdAvoidance(STRATEGYBLOCK *sbPtr,NPC_AVOIDANCEMANAGER *manager) { + + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(manager); + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + if (manager->stage<9) { + /* Still in the spin. Increment stage NOW! */ + manager->stage++; + /* Now raycast. */ + { + VECTORCH testDirn = manager->currentVector; + + LOS_ObjectHitPtr = (DISPLAYBLOCK *)0; + LOS_Lambda = NPC_MAX_VIEWRANGE; + CheckForVectorIntersectionWith3dObject(sbPtr->containingModule->m_dptr,&manager->basePoint,&testDirn,0); + + #if 0 + MakeParticle(&manager->basePoint,&testDirn,PARTICLE_PREDATOR_BLOOD); + #endif + + if (LOS_ObjectHitPtr) { + /* Hit environment! */ + if (LOS_Lambda>manager->bestDistance) { + /* Register this as best. */ + manager->bestDistance=LOS_Lambda; + manager->bestStage=manager->stage; + manager->bestVector=testDirn; + } + } + + testDirn.vx = -manager->currentVector.vx; + testDirn.vy = -manager->currentVector.vy; + testDirn.vz = -manager->currentVector.vz; + LOS_ObjectHitPtr = (DISPLAYBLOCK *)0; + LOS_Lambda = NPC_MAX_VIEWRANGE; + CheckForVectorIntersectionWith3dObject(sbPtr->containingModule->m_dptr,&manager->basePoint,&testDirn,0); + + #if 0 + MakeParticle(&manager->basePoint,&testDirn,PARTICLE_PREDATOR_BLOOD); + #endif + + if (LOS_ObjectHitPtr) { + /* Hit environment! */ + if (LOS_Lambda>manager->bestDistance) { + /* Register this as best. */ + manager->bestDistance=LOS_Lambda; + manager->bestStage=-manager->stage; + manager->bestVector=testDirn; + } + } + } + /* Now, rotate vector round. */ + RotateVector(&manager->currentVector,&manager->rotationMatrix); + } else if (manager->stage==9) { + /* Now, we must have checked all 16 directions. */ + if (manager->bestStage==0) { + /* That's a bit of a mystery. Return fubared. */ + return(-1); + } + /* Now, my beautiful assistant, open the envelope! */ + if (manager->bestDistanceavoidanceDirection=manager->bestVector; + Normalise(&manager->avoidanceDirection); + manager->stage++; + return(0); + } + } else { + /* In stage 10, we're going that way and trying to escape. */ + if (New_NPC_IsObstructed(sbPtr,manager)==1) { + int distance; + VECTORCH offset; + /* We're obstructed AGAIN! Gordon Bennet... restart? */ + offset.vx=dynPtr->Position.vx-manager->basePoint.vx; + offset.vy=dynPtr->Position.vy-manager->basePoint.vy; + offset.vz=dynPtr->Position.vz-manager->basePoint.vz; + + distance=Approximate3dMagnitude(&offset); + if (distance<300) { + /* I suspect restarting will get us nowhere, * + * something's in the primary path. Fail! */ + return(-1); + } + InitialiseThirdAvoidance(sbPtr,manager); + return(0); + } + + /* Are we far enough away? */ + { + int distance; + VECTORCH offset; + + offset.vx=dynPtr->Position.vx-manager->incidentPoint.vx; + offset.vy=dynPtr->Position.vy-manager->incidentPoint.vy; + offset.vz=dynPtr->Position.vz-manager->incidentPoint.vz; + + distance=Approximate3dMagnitude(&offset); + if (distance>manager->recommendedDistance) { + /* Now let's check against third avoidance. */ + offset.vx=dynPtr->Position.vx-manager->basePoint.vx; + offset.vy=dynPtr->Position.vy-manager->basePoint.vy; + offset.vz=dynPtr->Position.vz-manager->basePoint.vz; + + distance=Approximate3dMagnitude(&offset); + if (distance>(THIRD_AVOIDANCE_MINDIST>>1)) { + /* Exit with success! Glory be! */ + return(1); + } + } else { + /* Still check, to stop repeated third avoidance bouncing. */ + offset.vx=dynPtr->Position.vx-manager->basePoint.vx; + offset.vy=dynPtr->Position.vy-manager->basePoint.vy; + offset.vz=dynPtr->Position.vz-manager->basePoint.vz; + + distance=Approximate3dMagnitude(&offset); + if (distance>((manager->bestDistance)>>1)) { + /* Exit with success, before we look stupid! */ + return(1); + } + } + } + /* Still here, hmm? */ + return(0); + } + + return(0); + +} + +void CastLOSSpear(STRATEGYBLOCK *sbPtr, VECTORCH *muzzlepos, VECTORCH *in_shotvector, enum AMMO_ID AmmoID, int multiple, int inaccurate) { + + VECTORCH shotVector; + DISPLAYBLOCK *self; + + shotVector=*in_shotvector; + + if (sbPtr) { + self=sbPtr->SBdptr; + } else { + self=NULL; + } + + /* Normalise. */ + Normalise(&shotVector); + + if (inaccurate) { + /* Random tweak. */ + shotVector.vx+=((FastRandom()%(ONE_FIXED>>2))-(ONE_FIXED>>3)); + shotVector.vy+=((FastRandom()%(ONE_FIXED>>2))-(ONE_FIXED>>3)); + shotVector.vz+=((FastRandom()%(ONE_FIXED>>2))-(ONE_FIXED>>3)); + /* Normalise. */ + Normalise(&shotVector); + } + + + FindPolygonInLineOfSight(&shotVector,muzzlepos,0,self); + + /* Now deal with LOS_ObjectHitPtr. */ + if (LOS_ObjectHitPtr) { + if (LOS_HModel_Section) { + if (LOS_ObjectHitPtr->ObStrategyBlock) { + if (LOS_ObjectHitPtr->ObStrategyBlock->SBdptr) { + GLOBALASSERT(LOS_ObjectHitPtr->ObStrategyBlock->SBdptr->HModelControlBlock==LOS_HModel_Section->my_controller); + } + } + } + /* this fn needs updating to take amount of damage into account etc. */ + HandleSpearImpact(&LOS_Point,LOS_ObjectHitPtr->ObStrategyBlock,AmmoID,&shotVector, multiple, LOS_HModel_Section); + } + +} + +int SimpleEdgeDetectionTest(STRATEGYBLOCK *sbPtr, COLLISIONREPORT *vcr) { + + VECTORCH alpha,beta,tvec; + + GetTargetingPointOfObject_Far(sbPtr,&alpha); + /* Now add half a metre in positive z. */ + + tvec.vx=sbPtr->DynPtr->OrientMat.mat31; + tvec.vy=sbPtr->DynPtr->OrientMat.mat32; + tvec.vz=sbPtr->DynPtr->OrientMat.mat33; + + tvec.vx=MUL_FIXED(tvec.vx,1000); + tvec.vy=MUL_FIXED(tvec.vy,1000); + tvec.vz=MUL_FIXED(tvec.vz,1000); + + alpha.vx+=tvec.vx; + alpha.vy+=tvec.vy; + alpha.vz+=tvec.vz; + + beta.vx=sbPtr->DynPtr->OrientMat.mat21; + beta.vy=sbPtr->DynPtr->OrientMat.mat22; + beta.vz=sbPtr->DynPtr->OrientMat.mat23; + Normalise(&beta); + + /* Now do an LOS test. */ + FindPolygonInLineOfSight(&beta,&alpha,0,sbPtr->SBdptr); + + /* Pass the test if the test hit something within a metre (y) of dynPtr->Position. */ + + if (LOS_ObjectHitPtr) { + VECTORCH offset; + int dot; + /* Examine LOS_Point. */ + offset.vx=LOS_Point.vx-sbPtr->DynPtr->Position.vx; + offset.vy=LOS_Point.vy-sbPtr->DynPtr->Position.vy; + offset.vz=LOS_Point.vz-sbPtr->DynPtr->Position.vz; + + dot=DotProduct(&offset,&beta); + + //ReleasePrintDebuggingText("Dot %d\n",dot); + + if ((dot>-1000)&&(dot<1000)) { + return(0); + } + } + + /* Must be about to hit a rail or an edge? */ + vcr->ObstacleSBPtr=NULL; + vcr->ObstacleNormal.vx=-sbPtr->DynPtr->OrientMat.mat31; + vcr->ObstacleNormal.vy=-sbPtr->DynPtr->OrientMat.mat32; + vcr->ObstacleNormal.vz=-sbPtr->DynPtr->OrientMat.mat33; + vcr->ObstaclePoint=LOS_Point; + vcr->NextCollisionReportPtr=NULL; + + return(1); + +} diff --git a/3dc/avp/bh_ais.h b/3dc/avp/bh_ais.h new file mode 100644 index 0000000..ae5cd18 --- /dev/null +++ b/3dc/avp/bh_ais.h @@ -0,0 +1,238 @@ +/* CDF 11/6/98 - AI support functions moved out of bh_pred. */ + +#ifndef _bhais_h_ +#define _bhais_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*----------------------------- +General AI Support +-------------------------------*/ +typedef struct npc_obstructionreport +{ + unsigned int environment :1; /* x consecutive obstructive colls against env or indestructible object */ + unsigned int destructableObject :1; /* x consecutive obstructive colls against destructible object */ + unsigned int otherCharacter :1; /* single collison with other npc of same type */ + unsigned int anySingleObstruction :1; /* any single collision of above types */ +}NPC_OBSTRUCTIONREPORT; + +typedef enum avoidance_substate { + AvSS_FreeMovement=0, + AvSS_FirstAvoidance, + AvSS_SecondAvoidance, + AvSS_ThirdAvoidance, +} AVOIDANCE_SUBSTATE; + +typedef enum avoidance_return_condition { + AvRC_Clear=0, + AvRC_Avoidance, + AvRC_Failure, +} AVOIDANCE_RETURN_CONDITION; + +typedef struct npc_avoidancemanager { + /* New structure for super-avoidance system - expand at will! */ + VECTORCH avoidanceDirection; + VECTORCH incidenceDirection; + VECTORCH incidentPoint; + + VECTORCH aggregateNormal; + + int recommendedDistance; + int timer; + STRATEGYBLOCK *primaryCollision; + AVOIDANCE_SUBSTATE substate; + enum AMMO_ID ClearanceDamage; + /* Third avoidance parameters! */ + int stage; + VECTORCH baseVector; + VECTORCH basePoint; + VECTORCH currentVector; + MATRIXCH rotationMatrix; + VECTORCH bestVector; + int bestDistance; + int bestStage; + +} NPC_AVOIDANCEMANAGER; + +#define STANDARD_AVOIDANCE_TIME (ONE_FIXED*5) +#define THIRD_AVOIDANCE_MINDIST (2000) + +typedef struct npc_movementdata +{ + int numObstructiveCollisions; + VECTORCH avoidanceDirn; + VECTORCH lastTarget; + VECTORCH lastVelocity; + int numReverses; + AIMODULE *lastModule; +}NPC_MOVEMENTDATA; + +typedef struct npc_wanderdata +{ + int currentModule; + VECTORCH worldPosition; +}NPC_WANDERDATA; + +#define NPC_AVOIDTIME (ONE_FIXED<<1) +#define NPC_GMD_NOPOLY (-1) +#define NPC_MIN_MOVEFROMPOLYDIST (650) +#define NPC_IMPEDING_COL_THRESHOLD (10) /* Was 10 */ +#define NPC_JUMPSPEED (55) /* mm/s */ +#define NPC_JUMPHEIGHT (1000) +//#define NPC_TURNRATE (ONE_FIXED) /* thro' 360 degrees */ +#define NPC_TURNRATE (4096) +#define NPC_DEATHTIME (ONE_FIXED>>1) +#define NPC_TARGETPOINTELEVATION (-400) +#define NPC_INANIMATEOBJECTDAMAGE (10000) +#define NPC_NOWANDERMODULE (-1) +#define NPC_BIMBLINGINMODULE (-2) + +#define NUM_ATTACKFLAGS (3) + +/* Death Structures */ + +typedef struct hit_facing { + int Front: 1; + int Back: 1; + int Left: 1; + int Right: 1; +} HIT_FACING; + +typedef struct death_data { + int Sequence_Type; + int Sub_Sequence; + int TweeningTime; + int Sequence_Length; + int Multiplayer_Code; + int Unique_Code; //unique across all deaths - for saving + int wound_flags; /* HModel wound flags */ + int priority_wounds; + int Template: 1; + HIT_FACING Facing; + int Burning: 1; + int Electrical: 1; + int Crouching: 1; + int MinorBoom: 1; + int MajorBoom: 1; +} DEATH_DATA; + +typedef struct attack_data { + int Sequence_Type; + int Sub_Sequence; + int TweeningTime; + int Sequence_Length; + int Multiplayer_Code; + int Unique_Code; //unique across all attacks - for saving + int wound_flags; + enum AMMO_ID flag_damage[NUM_ATTACKFLAGS]; + int Crouching: 1; + int Pouncing: 1; +} ATTACK_DATA; + +typedef enum movement_data_index { + MDI_Marine_Mooch_Bored=0, + MDI_Marine_Mooch_Alert, + MDI_Marine_Combat, + MDI_Marine_Sprint, + MDI_Civilian_Mooch_Bored, + MDI_Civilian_Mooch_Alert, + MDI_Civilian_Combat, + MDI_Civilian_Sprint, + MDI_Predator, + MDI_Casual_Predator, + MDI_Xenoborg, + MDI_End, +} MOVEMENT_DATA_INDEX; + +typedef struct movement_data { + MOVEMENT_DATA_INDEX index; + unsigned int maxSpeed; + unsigned int acceleration; +} MOVEMENT_DATA; + +/* Function Declarations */ + +extern int CheckAdjacencyValidity(AIMODULE *target,AIMODULE *source,int alien); +extern int AIModuleIsVisible(AIMODULE *aimodule); + +extern int NPC_IsDead(STRATEGYBLOCK *sbPtr); +extern void NPC_InitMovementData(NPC_MOVEMENTDATA *moveData); +extern void NPC_IsObstructed(STRATEGYBLOCK *sbPtr, NPC_MOVEMENTDATA *moveData, NPC_OBSTRUCTIONREPORT *details, STRATEGYBLOCK **destructableObject); +extern int NPC_CannotReachTarget(NPC_MOVEMENTDATA *moveData, VECTORCH* thisTarget, VECTORCH* thisVelocity); +extern void NPCGetAvoidanceDirection(STRATEGYBLOCK *sbPtr, VECTORCH *velocityDirection, NPC_OBSTRUCTIONREPORT *details); +extern void NPCGetTargetPosition(VECTORCH *targetPoint,STRATEGYBLOCK *target); +extern int NPCSetVelocity(STRATEGYBLOCK *sbPtr, VECTORCH* targetDirn, int in_speed); +extern int NPCOrientateToVector(STRATEGYBLOCK *sbPtr, VECTORCH *zAxisVector, int turnspeed, VECTORCH *offset); +extern void NPCGetMovementTarget(STRATEGYBLOCK *sbPtr, STRATEGYBLOCK *target, VECTORCH *targetPosition, int* targetIsAirduct,int alien); +extern void NPCGetMovementDirection(STRATEGYBLOCK *sbPtr, VECTORCH *velocityDirection, VECTORCH* target, WAYPOINT_MANAGER *waypointManager); +extern int FindMyFloorPoly(VECTORCH* currentPosition, MODULE* currentModule); +extern void NPC_InitWanderData(NPC_WANDERDATA *wanderData); +extern void NPC_FindWanderTarget(STRATEGYBLOCK *sbPtr, NPC_WANDERDATA *wanderData, NPC_MOVEMENTDATA *moveData); +extern void NPC_FindAIWanderTarget(STRATEGYBLOCK *sbPtr, NPC_WANDERDATA *wanderData, NPC_MOVEMENTDATA *moveData, int alien); +extern void ProjectNPCShot(STRATEGYBLOCK *sbPtr, STRATEGYBLOCK *target, VECTORCH *muzzlepos, MATRIXCH *muzzleorient,enum AMMO_ID AmmoID, int multiple); +extern void CastLOSProjectile(STRATEGYBLOCK *sbPtr, VECTORCH *muzzlepos, VECTORCH *in_shotvector, enum AMMO_ID AmmoID, int multiple, int inaccurate); +extern int VerifyHitShot(STRATEGYBLOCK *sbPtr, STRATEGYBLOCK *target, VECTORCH *muzzlepos, VECTORCH *in_shotvector, enum AMMO_ID AmmoID, int multiple, int maxrange); +extern AIMODULE *GetNextModuleForLink(AIMODULE *source,AIMODULE *target,int max_depth,int alien); +extern AIMODULE *GetNextModuleForLink_Core(AIMODULE *source,AIMODULE *target,int max_depth,int visibility_check,int alien); +extern int GetNextModuleInPath(int current_module, int path); +extern AIMODULE *TranslatePathIndex(int current_module, int path); +extern int GetClosestStepInPath(int path,MODULE* current_module); + +extern DEATH_DATA *GetDeathSequence(HMODELCONTROLLER *controller,SECTION *TemplateRoot,DEATH_DATA *FirstDeath,int wound_flags,int priority_wounds, + int hurtiness,HIT_FACING *facing,int burning,int crouching,int electrical); +extern DEATH_DATA *GetAlienDeathSequence(HMODELCONTROLLER *controller,SECTION *TemplateRoot,int wound_flags,int priority_wounds, + int hurtiness,HIT_FACING *facing,int burning,int crouching,int electrical); +extern DEATH_DATA *GetMarineDeathSequence(HMODELCONTROLLER *controller,SECTION *TemplateRoot,int wound_flags,int priority_wounds, + int hurtiness,HIT_FACING *facing,int burning,int crouching,int electrical); +extern DEATH_DATA *GetPredatorDeathSequence(HMODELCONTROLLER *controller,SECTION *TemplateRoot,int wound_flags,int priority_wounds, + int hurtiness,HIT_FACING *facing,int burning,int crouching,int electrical); +extern DEATH_DATA *GetXenoborgDeathSequence(HMODELCONTROLLER *controller,SECTION *TemplateRoot,int wound_flags,int priority_wounds, + int hurtiness,HIT_FACING *facing,int burning,int crouching,int electrical); + +extern DEATH_DATA *GetThisDeath_FromCode(HMODELCONTROLLER *controller,DEATH_DATA *FirstDeath,int code); +extern DEATH_DATA *GetThisDeath_FromUniqueCode(int code); + +extern ATTACK_DATA *GetThisAttack_FromCode(HMODELCONTROLLER *controller,ATTACK_DATA *FirstAttack,int code); +extern ATTACK_DATA *GetAttackSequence(HMODELCONTROLLER *controller,ATTACK_DATA *FirstAttack,int wound_flags,int crouching, int pouncing); +extern ATTACK_DATA *GetAlienAttackSequence(HMODELCONTROLLER *controller,int wound_flags,int crouching); +extern ATTACK_DATA *GetAlienPounceAttack(HMODELCONTROLLER *controller,int wound_flags,int crouching); +extern ATTACK_DATA *GetWristbladeAttackSequence(HMODELCONTROLLER *controller,int wound_flags,int crouching); +extern ATTACK_DATA *GetPredStaffAttackSequence(HMODELCONTROLLER *controller,int wound_flags,int crouching); + +extern ATTACK_DATA *GetThisAttack_FromUniqueCode(int code);//for loading + +extern AIMODULE *NearNPC_GetTargetAIModuleForRetreat(STRATEGYBLOCK *sbPtr, NPC_MOVEMENTDATA *moveData); +extern AIMODULE *General_GetAIModuleForRetreat(STRATEGYBLOCK *sbPtr,AIMODULE *fearModule,int max_depth); +/* All New Avoidance Code! */ +extern int New_NPC_IsObstructed(STRATEGYBLOCK *sbPtr, NPC_AVOIDANCEMANAGER *manager); +extern void Initialise_AvoidanceManager(STRATEGYBLOCK *sbPtr, NPC_AVOIDANCEMANAGER *manager); +extern AVOIDANCE_RETURN_CONDITION AllNewAvoidanceKernel(STRATEGYBLOCK *sbPtr,NPC_AVOIDANCEMANAGER *manager); +/* All New Avoidance Code! */ +extern MOVEMENT_DATA *GetThisMovementData(MOVEMENT_DATA_INDEX index); +extern void AlignVelocityToGravity(STRATEGYBLOCK *sbPtr,VECTORCH *velocity); + +extern int NPC_targetIsPlayer; +extern VECTORCH NPC_movementTarget; +extern int *NPC_myPoly; +extern int *NPC_myLastPoly; +extern int *NPC_lastFrameModule; + +extern int Observer; + +typedef struct pathheader +{ + int path_length; + AIMODULE** modules_in_path; +}PATHHEADER; + +extern int PathArraySize; +extern PATHHEADER* PathArray; + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/3dc/avp/bh_cable.c b/3dc/avp/bh_cable.c new file mode 100644 index 0000000..8c13c84 --- /dev/null +++ b/3dc/avp/bh_cable.c @@ -0,0 +1,128 @@ + +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "dynblock.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "bh_cable.h" +#include "dynamics.h" +#include "pvisible.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "plat_shp.h" + +extern int NormalFrameTime; +extern char *ModuleCurrVisArray; + +void* PowerCableBehaveInit(void* bhdata,STRATEGYBLOCK* sbptr) +{ + POWER_CABLE_BEHAV_BLOCK* pc_bhv; + POWER_CABLE_TOOLS_TEMPLATE* pc_tt; + + GLOBALASSERT(sbptr); + GLOBALASSERT(bhdata); + + pc_bhv=(POWER_CABLE_BEHAV_BLOCK*)AllocateMem(sizeof(POWER_CABLE_BEHAV_BLOCK)); + if(!pc_bhv) + { + memoryInitialisationFailure = 1; + return 0; + } + pc_bhv->bhvr_type=I_BehaviourPowerCable; + + pc_tt=(POWER_CABLE_TOOLS_TEMPLATE*)bhdata; + + //copy stuff from tools template + COPY_NAME(sbptr->SBname, pc_tt->nameID); + pc_bhv->position = pc_tt->position; + pc_bhv->max_charge = pc_tt->max_charge; + pc_bhv->current_charge = pc_tt->current_charge; + pc_bhv->recharge_rate = pc_tt->recharge_rate; + + pc_bhv->position.vy+=10; //temporarily move cable down in case rounding errors have put cable just outside of module + sbptr->containingModule=ModuleFromPosition(&(pc_bhv->position),0); + pc_bhv->position.vy-=10; + + GLOBALASSERT(sbptr->containingModule); + + + return (void*)pc_bhv; +} + +void PowerCableBehaveFun(STRATEGYBLOCK* sbptr) +{ + POWER_CABLE_BEHAV_BLOCK* pc_bhv; + GLOBALASSERT(sbptr); + pc_bhv = (POWER_CABLE_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((pc_bhv->bhvr_type == I_BehaviourPowerCable)); + + //see if player can get health from cable + //player must be an alien + if(AvP.PlayerType==I_Alien) + { + //the cable needs to be in a near module + GLOBALASSERT(sbptr->containingModule); + if(ModuleCurrVisArray[(sbptr->containingModule->m_index)]) + { + //is player close enough + int distance=VectorDistance(&Player->ObWorld,&pc_bhv->position); + if(distanceStartingStats.Health<ObStrategyBlock->SBDamageBlock.Health; + + health_gained=min(pc_bhv->current_charge,max_health-current_health); + + pc_bhv->current_charge-=health_gained; + Player->ObStrategyBlock->SBDamageBlock.Health+=health_gained; + { + /* access the extra data hanging off the strategy block */ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + playerStatusPtr->Health=Player->ObStrategyBlock->SBDamageBlock.Health; + } + } + } + } + + //increase charge if currently below maximum + if(pc_bhv->current_chargemax_charge) + { + if(pc_bhv->recharge_rate) + { + pc_bhv->current_charge+=MUL_FIXED(pc_bhv->recharge_rate,NormalFrameTime); + if(pc_bhv->current_charge>pc_bhv->max_charge) + { + pc_bhv->current_charge=pc_bhv->max_charge; + } + } + } +} + + diff --git a/3dc/avp/bh_cable.h b/3dc/avp/bh_cable.h new file mode 100644 index 0000000..84b10ab --- /dev/null +++ b/3dc/avp/bh_cable.h @@ -0,0 +1,49 @@ +#ifndef _bh_cable_h +#define _bh_cable_h 1 + +#ifdef __cplusplus + + extern "C" { + +#endif + +extern void* PowerCableBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr); +extern void PowerCableBehaveFun(STRATEGYBLOCK* sbptr); + + +#define CABLE_HEALTH_DISTANCE 2000 + +typedef struct power_cable_behav_block +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + + char nameID[SB_NAME_LENGTH]; + + VECTORCH position; + + int max_charge; //health value in fixed point + int current_charge; //ditto + int recharge_rate; //recharge rate per second +}POWER_CABLE_BEHAV_BLOCK; + +typedef struct power_cable_tools_template +{ + char nameID[SB_NAME_LENGTH]; + VECTORCH position; + int max_charge; + int current_charge; + int recharge_rate; +}POWER_CABLE_TOOLS_TEMPLATE; + + + + + +#ifdef __cplusplus + + }; + +#endif + + +#endif diff --git a/3dc/avp/bh_corpse.c b/3dc/avp/bh_corpse.c new file mode 100644 index 0000000..51d19aa --- /dev/null +++ b/3dc/avp/bh_corpse.c @@ -0,0 +1,1077 @@ +/* bh_corpse.c 19/8/98 */ +#include "3dc.h" + +#include "inline.h" +#include "module.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "comp_shp.h" +#include "dynblock.h" +#include "dynamics.h" +#include "lighting.h" + +#include "pfarlocs.h" +#include "pvisible.h" +#include "pheromon.h" +#include "bh_gener.h" +#include "bh_far.h" +#include "bh_pred.h" +#include "bh_marin.h" +#include "bh_weap.h" +#include "bh_debri.h" +#include "bh_alien.h" +#include "bh_xeno.h" +#include "psnd.h" +#include "weapons.h" +#include "load_shp.h" +#include "particle.h" +#include "sfx.h" +#include "huddefs.h" +#include "pldghost.h" +#include "pldnet.h" +#include "psndplat.h" +#include "AI_Sight.h" +#include "los.h" +#include "bh_corpse.h" + +#include "dxlog.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +#include "sequnces.h" +#include "ShowCmds.h" +#include "extents.h" + +extern int NormalFrameTime; +extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); +extern HITLOCATIONTABLE *GetThisHitLocationTable(char *id); +extern MARINE_WEAPON_DATA *GetThisNPCMarineWeapon(MARINE_NPC_WEAPONS this_id); + +void SetCorpseAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime); + +/* these functions are called directly by the visibility management system */ +void MakeCorpseNear(STRATEGYBLOCK *sbPtr) +{ + extern MODULEMAPBLOCK AlienDefaultMap; + NETCORPSEDATABLOCK *corpseData = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + LOCALASSERT(corpseData); + LOCALASSERT(dynPtr); + LOCALASSERT(sbPtr->SBdptr == NULL); + + AlienDefaultMap.MapShape = sbPtr->shapeIndex; + tempModule.m_mapptr = &AlienDefaultMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 0; + tempModule.m_lightarray = (struct lightblock *)0; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr = NULL; /* this is important */ + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) return; /* cannot create displayblock, so leave object "far" */ + + sbPtr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbPtr; + dPtr->ObMyModule = NULL; + dPtr->HModelControlBlock=NULL; + + /* need to initialise positional information in the new display block */ + /*Must be done before ProveHModel*/ + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + + /* set the animation sequence, if we're a player corpse */ + { + /* Okay, no messing, you MUST be a player corpse. */ + dPtr->HModelControlBlock=&corpseData->HModelController; + ProveHModel(dPtr->HModelControlBlock,dPtr); + } + + +} + +void MakeCorpseFar(STRATEGYBLOCK *sbPtr) +{ + int i; + LOCALASSERT(sbPtr->SBdptr != NULL); + + /* get rid of the displayblock */ + i = DestroyActiveObject(sbPtr->SBdptr); + LOCALASSERT(i==0); + sbPtr->SBdptr = NULL; +} + +void Convert_Alien_To_Corpse(STRATEGYBLOCK *sbPtr,DEATH_DATA *this_death,DAMAGE_PROFILE* damage) { + + NETCORPSEDATABLOCK *corpseDataPtr; + ALIEN_STATUS_BLOCK *alienStatusPointer; + + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + /* Convert an alien... to a corpse. */ + + GLOBALASSERT(sbPtr); + GLOBALASSERT(this_death); + GLOBALASSERT(alienStatusPointer); + + /* Inform the network. */ + if (AvP.Network != I_No_Network) + { + AddNetMsg_AlienAIKilled(sbPtr,this_death->Multiplayer_Code,ALIEN_DYINGTIME,alienStatusPointer->GibbFactor,damage); + } + + corpseDataPtr = (void *)AllocateMem(sizeof(NETCORPSEDATABLOCK)); + GLOBALASSERT(corpseDataPtr); + + /* Fill in corpseDataPtr... */ + corpseDataPtr->SoundHandle = SOUND_NOACTIVEINDEX; + corpseDataPtr->SoundHandle2 = SOUND_NOACTIVEINDEX; + corpseDataPtr->SoundHandle3 = SOUND_NOACTIVEINDEX; + corpseDataPtr->SoundHandle4 = SOUND_NOACTIVEINDEX; + + corpseDataPtr->Type=I_BehaviourAlien; + corpseDataPtr->GibbFactor=alienStatusPointer->GibbFactor; + corpseDataPtr->This_Death=this_death; + + corpseDataPtr->CloakStatus = PCLOAK_Off; + corpseDataPtr->CloakTimer = 0; + corpseDataPtr->destructTimer = -1; + corpseDataPtr->WeaponMisfireFunction=NULL; + corpseDataPtr->My_Gunflash_Section=NULL; + corpseDataPtr->My_Weapon=NULL; + corpseDataPtr->weapon_variable=0; + corpseDataPtr->Android=0; + corpseDataPtr->ARealMarine=0; + corpseDataPtr->TemplateRoot=NULL; + corpseDataPtr->DeathFiring=0; + corpseDataPtr->Wounds=0; + + switch (alienStatusPointer->Type) { + case AT_Standard: + default: + corpseDataPtr->subtype = 0; + corpseDataPtr->hltable=GetThisHitLocationTable("alien"); + break; + case AT_Predalien: + corpseDataPtr->subtype = 1; + corpseDataPtr->hltable=GetThisHitLocationTable("predalien"); + break; + case AT_Praetorian: + corpseDataPtr->subtype = 2; + corpseDataPtr->hltable=GetThisHitLocationTable("praetorian"); + break; + } + + /* Remember wounds, or not? */ + Splice_HModels(&corpseDataPtr->HModelController,alienStatusPointer->HModelController.section_data); + + /* Heh... now bin the old data block! */ + if(alienStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(alienStatusPointer->soundHandle); + } + if(alienStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) { + Sound_Stop(alienStatusPointer->soundHandle2); + } + Dispel_HModel(&alienStatusPointer->HModelController); + DeallocateMem(sbPtr->SBdataptr); + /* Turn into the corpse. */ + sbPtr->SBdataptr=corpseDataPtr; + sbPtr->I_SBtype=I_BehaviourNetCorpse; + + SetCorpseAnimSequence_Core(sbPtr,this_death->Sequence_Type,this_death->Sub_Sequence, + this_death->Sequence_Length,this_death->TweeningTime); + + if (sbPtr->SBdptr) { + /* Swap controllers round. */ + sbPtr->SBdptr->HModelControlBlock=&corpseDataPtr->HModelController; + ProveHModel(&corpseDataPtr->HModelController,sbPtr->SBdptr); + } else { + ProveHModel_Far(&corpseDataPtr->HModelController,sbPtr); + } + + corpseDataPtr->timer=ALIEN_DYINGTIME; + corpseDataPtr->validityTimer=CORPSE_VALIDITY_TIME; + corpseDataPtr->HModelController.Looped=0; + corpseDataPtr->HModelController.LoopAfterTweening=0; + + /* stop motion */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->Friction = 400000; + sbPtr->DynPtr->LinImpulse.vx+=sbPtr->DynPtr->LinVelocity.vx; + sbPtr->DynPtr->LinImpulse.vy+=sbPtr->DynPtr->LinVelocity.vy; + sbPtr->DynPtr->LinImpulse.vz+=sbPtr->DynPtr->LinVelocity.vz; + sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; + sbPtr->DynPtr->CanClimbStairs = 0; + /* Experiment... */ + sbPtr->DynPtr->UseStandardGravity=1; + sbPtr->DynPtr->Mass = 160; + /* Okay... */ + + /* KJL 17:19:35 27/08/98 - ignore the player, other body parts, etc */ + sbPtr->DynPtr->OnlyCollideWithEnvironment = 1; + + /* Electric death sound? */ + if (corpseDataPtr->This_Death->Electrical) { + Sound_Play(SID_ED_ELEC_DEATH,"de",&sbPtr->DynPtr->Position,&corpseDataPtr->SoundHandle4); + } +} + +void Convert_Predator_To_Corpse(STRATEGYBLOCK *sbPtr,DEATH_DATA *this_death) { + + NETCORPSEDATABLOCK *corpseDataPtr; + PREDATOR_STATUS_BLOCK *predatorStatusPointer; + + predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr); + /* Convert a predator... to a corpse. */ + + GLOBALASSERT(sbPtr); + GLOBALASSERT(this_death); + GLOBALASSERT(predatorStatusPointer); + + corpseDataPtr = (void *)AllocateMem(sizeof(NETCORPSEDATABLOCK)); + GLOBALASSERT(corpseDataPtr); + + /* Fill in corpseDataPtr... */ + corpseDataPtr->SoundHandle = SOUND_NOACTIVEINDEX; + corpseDataPtr->SoundHandle2 = SOUND_NOACTIVEINDEX; + corpseDataPtr->SoundHandle3 = SOUND_NOACTIVEINDEX; + corpseDataPtr->SoundHandle4 = SOUND_NOACTIVEINDEX; + + corpseDataPtr->Type=I_BehaviourPredator; + corpseDataPtr->GibbFactor=predatorStatusPointer->GibbFactor; + corpseDataPtr->This_Death=this_death; + + corpseDataPtr->CloakStatus = predatorStatusPointer->CloakStatus; + corpseDataPtr->CloakTimer = predatorStatusPointer->CloakTimer; + + if ((predatorStatusPointer->behaviourState==PBS_SelfDestruct) + &&(predatorStatusPointer->internalState==1)) { + corpseDataPtr->destructTimer = predatorStatusPointer->stateTimer; + } else { + corpseDataPtr->destructTimer = -1; + } + + corpseDataPtr->WeaponMisfireFunction=NULL; + corpseDataPtr->My_Gunflash_Section=NULL; + corpseDataPtr->weapon_variable=0; + corpseDataPtr->Android=0; + corpseDataPtr->ARealMarine=0; + corpseDataPtr->TemplateRoot=NULL; + corpseDataPtr->My_Weapon=NULL; + corpseDataPtr->DeathFiring=0; + corpseDataPtr->subtype = 0; + corpseDataPtr->Wounds=0; + + corpseDataPtr->hltable=GetThisHitLocationTable(predatorStatusPointer->Selected_Weapon->HitLocationTableName); + + /* Remember wounds, or not? */ + Splice_HModels(&corpseDataPtr->HModelController,predatorStatusPointer->HModelController.section_data); + + if (this_death->Template) { + SECTION *root; + /* Convert to template. */ + root=GetNamedHierarchyFromLibrary("hnpcpredator","Template"); + Transmogrify_HModels(sbPtr,&corpseDataPtr->HModelController, + root, 1, 0,0); + } + + /* Heh... now bin the old data block! */ + if(predatorStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(predatorStatusPointer->soundHandle); + } + Dispel_HModel(&predatorStatusPointer->HModelController); + DeallocateMem(sbPtr->SBdataptr); + /* Turn into the corpse. */ + sbPtr->SBdataptr=corpseDataPtr; + sbPtr->I_SBtype=I_BehaviourNetCorpse; + + SetCorpseAnimSequence_Core(sbPtr,this_death->Sequence_Type,this_death->Sub_Sequence, + this_death->Sequence_Length,this_death->TweeningTime); + + if (sbPtr->SBdptr) { + /* Swap controllers round. */ + sbPtr->SBdptr->HModelControlBlock=&corpseDataPtr->HModelController; + ProveHModel(&corpseDataPtr->HModelController,sbPtr->SBdptr); + } else { + ProveHModel_Far(&corpseDataPtr->HModelController,sbPtr); + } + + corpseDataPtr->timer=PRED_DIETIME; + corpseDataPtr->validityTimer=CORPSE_VALIDITY_TIME; + corpseDataPtr->HModelController.Looped=0; + corpseDataPtr->HModelController.LoopAfterTweening=0; + + /* stop motion */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->Friction = 400000; + sbPtr->DynPtr->LinImpulse.vx+=sbPtr->DynPtr->LinVelocity.vx; + sbPtr->DynPtr->LinImpulse.vy+=sbPtr->DynPtr->LinVelocity.vy; + sbPtr->DynPtr->LinImpulse.vz+=sbPtr->DynPtr->LinVelocity.vz; + sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; + sbPtr->DynPtr->CanClimbStairs = 0; + + /* KJL 17:19:35 27/08/98 - ignore the player, other body parts, etc */ + sbPtr->DynPtr->OnlyCollideWithEnvironment = 1; + + /* Electric death sound? */ + if (corpseDataPtr->This_Death->Electrical) { + Sound_Play(SID_ED_ELEC_DEATH,"de",&sbPtr->DynPtr->Position,&corpseDataPtr->SoundHandle4); + } + +} + +void Convert_Marine_To_Corpse(STRATEGYBLOCK *sbPtr,DEATH_DATA *this_death) { + + NETCORPSEDATABLOCK *corpseDataPtr; + MARINE_STATUS_BLOCK *marineStatusPointer; + + marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + /* Convert a predator... to a corpse. */ + + GLOBALASSERT(sbPtr); + GLOBALASSERT(this_death); + GLOBALASSERT(marineStatusPointer); + + corpseDataPtr = (void *)AllocateMem(sizeof(NETCORPSEDATABLOCK)); + GLOBALASSERT(corpseDataPtr); + + /* Fill in corpseDataPtr... */ + corpseDataPtr->SoundHandle = SOUND_NOACTIVEINDEX; + corpseDataPtr->SoundHandle2 = SOUND_NOACTIVEINDEX; + corpseDataPtr->SoundHandle3 = SOUND_NOACTIVEINDEX; + corpseDataPtr->SoundHandle4 = SOUND_NOACTIVEINDEX; + + corpseDataPtr->Type=I_BehaviourMarine; + corpseDataPtr->GibbFactor=marineStatusPointer->GibbFactor; + corpseDataPtr->This_Death=this_death; + + corpseDataPtr->CloakStatus = PCLOAK_Off; + corpseDataPtr->CloakTimer = 0; + corpseDataPtr->destructTimer = -1; + + corpseDataPtr->My_Weapon=marineStatusPointer->My_Weapon; + corpseDataPtr->WeaponMisfireFunction=marineStatusPointer->My_Weapon->WeaponMisfireFunction; + corpseDataPtr->My_Gunflash_Section=marineStatusPointer->My_Gunflash_Section; + corpseDataPtr->TemplateRoot=GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,marineStatusPointer->My_Weapon->TemplateName); + corpseDataPtr->Android=marineStatusPointer->Android; + corpseDataPtr->ARealMarine=marineStatusPointer->My_Weapon->ARealMarine; + corpseDataPtr->weapon_variable=0; + corpseDataPtr->Wounds=0; + + corpseDataPtr->subtype = 0; + corpseDataPtr->hltable=GetThisHitLocationTable(marineStatusPointer->My_Weapon->HitLocationTableName); + + if (corpseDataPtr->WeaponMisfireFunction) { + if (marineStatusPointer->behaviourState==MBS_Firing) { + corpseDataPtr->DeathFiring=1; + } else { + corpseDataPtr->DeathFiring=0; + } + } else { + corpseDataPtr->DeathFiring=0; + } + + /* Remember wounds, or not? */ + Splice_HModels(&corpseDataPtr->HModelController,marineStatusPointer->HModelController.section_data); + + if (this_death->Template) { + /* Convert to template. */ + Transmogrify_HModels(sbPtr,&corpseDataPtr->HModelController, + corpseDataPtr->TemplateRoot, 1, 0,0); + } + /* Pass over some sounds? */ + + /* Heh... now bin the old data block! */ + if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(marineStatusPointer->soundHandle); + } + if(marineStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) { + /* soundHandle2 is the voice! */ + corpseDataPtr->SoundHandle2=marineStatusPointer->soundHandle2; + ActiveSounds[marineStatusPointer->soundHandle2].externalRef=&corpseDataPtr->SoundHandle2; + } + Dispel_HModel(&marineStatusPointer->HModelController); + DeallocateMem(sbPtr->SBdataptr); + /* Turn into the corpse. */ + sbPtr->SBdataptr=corpseDataPtr; + sbPtr->I_SBtype=I_BehaviourNetCorpse; + + SetCorpseAnimSequence_Core(sbPtr,this_death->Sequence_Type,this_death->Sub_Sequence, + this_death->Sequence_Length,this_death->TweeningTime); + + if (sbPtr->SBdptr) { + /* Swap controllers round. */ + sbPtr->SBdptr->HModelControlBlock=&corpseDataPtr->HModelController; + ProveHModel(&corpseDataPtr->HModelController,sbPtr->SBdptr); + } else { + ProveHModel_Far(&corpseDataPtr->HModelController,sbPtr); + } + + corpseDataPtr->timer=MARINE_DYINGTIME; + corpseDataPtr->validityTimer=CORPSE_VALIDITY_TIME; + corpseDataPtr->HModelController.Looped=0; + corpseDataPtr->HModelController.LoopAfterTweening=0; + + /* stop motion */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->Friction = 400000; + sbPtr->DynPtr->LinImpulse.vx+=sbPtr->DynPtr->LinVelocity.vx; + sbPtr->DynPtr->LinImpulse.vy+=sbPtr->DynPtr->LinVelocity.vy; + sbPtr->DynPtr->LinImpulse.vz+=sbPtr->DynPtr->LinVelocity.vz; + sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; + sbPtr->DynPtr->CanClimbStairs = 0; + + /* KJL 17:19:35 27/08/98 - ignore the player, other body parts, etc */ + sbPtr->DynPtr->OnlyCollideWithEnvironment = 1; + + /* Electric death sound? */ + if (corpseDataPtr->This_Death->Electrical) { + Sound_Play(SID_ED_ELEC_DEATH,"de",&sbPtr->DynPtr->Position,&corpseDataPtr->SoundHandle4); + } + +} + +void Convert_Xenoborg_To_Corpse(STRATEGYBLOCK *sbPtr,DEATH_DATA *this_death) { + + NETCORPSEDATABLOCK *corpseDataPtr; + XENO_STATUS_BLOCK *xenoStatusPointer; + + xenoStatusPointer=(XENO_STATUS_BLOCK *)(sbPtr->SBdataptr); + /* Convert an xenoborg... to a corpse. */ + + GLOBALASSERT(sbPtr); + GLOBALASSERT(this_death); + GLOBALASSERT(xenoStatusPointer); + + corpseDataPtr = (void *)AllocateMem(sizeof(NETCORPSEDATABLOCK)); + GLOBALASSERT(corpseDataPtr); + + /* Fill in corpseDataPtr... */ + corpseDataPtr->SoundHandle = SOUND_NOACTIVEINDEX; + corpseDataPtr->SoundHandle2 = SOUND_NOACTIVEINDEX; + corpseDataPtr->SoundHandle3 = SOUND_NOACTIVEINDEX; + corpseDataPtr->SoundHandle4 = SOUND_NOACTIVEINDEX; + + corpseDataPtr->Type=I_BehaviourXenoborg; + corpseDataPtr->GibbFactor=xenoStatusPointer->GibbFactor; + corpseDataPtr->This_Death=this_death; + + corpseDataPtr->CloakStatus = PCLOAK_Off; + corpseDataPtr->CloakTimer = 0; + corpseDataPtr->destructTimer = -1; + corpseDataPtr->WeaponMisfireFunction=NULL; + corpseDataPtr->My_Gunflash_Section=NULL; + corpseDataPtr->weapon_variable=0; + corpseDataPtr->Android=0; + corpseDataPtr->ARealMarine=0; + corpseDataPtr->TemplateRoot=NULL; + corpseDataPtr->My_Weapon=NULL; + corpseDataPtr->DeathFiring=0; + corpseDataPtr->subtype = 0; + corpseDataPtr->Wounds=0; + + corpseDataPtr->hltable=GetThisHitLocationTable("xenoborg"); + + /* Remember wounds, or not? */ + Splice_HModels(&corpseDataPtr->HModelController,xenoStatusPointer->HModelController.section_data); + + /* Heh... now bin the old data block! */ + Dispel_HModel(&xenoStatusPointer->HModelController); + DeallocateMem(sbPtr->SBdataptr); + /* Turn into the corpse. */ + sbPtr->SBdataptr=corpseDataPtr; + sbPtr->I_SBtype=I_BehaviourNetCorpse; + + SetCorpseAnimSequence_Core(sbPtr,this_death->Sequence_Type,this_death->Sub_Sequence, + this_death->Sequence_Length,this_death->TweeningTime); + + if (sbPtr->SBdptr) { + /* Swap controllers round. */ + sbPtr->SBdptr->HModelControlBlock=&corpseDataPtr->HModelController; + ProveHModel(&corpseDataPtr->HModelController,sbPtr->SBdptr); + } else { + ProveHModel_Far(&corpseDataPtr->HModelController,sbPtr); + } + + corpseDataPtr->timer=XENO_DYINGTIME; + corpseDataPtr->validityTimer=CORPSE_VALIDITY_TIME; + corpseDataPtr->HModelController.Looped=0; + corpseDataPtr->HModelController.LoopAfterTweening=0; + + /* stop motion */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->Friction = 400000; + sbPtr->DynPtr->LinImpulse.vx+=sbPtr->DynPtr->LinVelocity.vx; + sbPtr->DynPtr->LinImpulse.vy+=sbPtr->DynPtr->LinVelocity.vy; + sbPtr->DynPtr->LinImpulse.vz+=sbPtr->DynPtr->LinVelocity.vz; + sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; + sbPtr->DynPtr->CanClimbStairs = 0; + /* Experiment... */ + sbPtr->DynPtr->UseStandardGravity=1; + sbPtr->DynPtr->Mass = 160; + /* Okay... */ + + /* KJL 17:19:35 27/08/98 - ignore the player, other body parts, etc */ + sbPtr->DynPtr->OnlyCollideWithEnvironment = 1; + + #if 0 + /* Electric death sound? */ + if (corpseDataPtr->This_Death->Electrical) { + Sound_Play(SID_ED_ELEC_DEATH,"de",&sbPtr->DynPtr->Position,&corpseDataPtr->SoundHandle4); + } + #endif + +} + +void CorpseBehaveFun(STRATEGYBLOCK *sbPtr) +{ + + /* Just count down. */ + NETCORPSEDATABLOCK *corpseDataPtr; + + LOCALASSERT(sbPtr); + + corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(corpseDataPtr); + + + if (corpseDataPtr->timer<=0) + { + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr); + + if (playerStatusPtr->MyCorpse==sbPtr) { + /* Set players corpse to null. */ + playerStatusPtr->MyCorpse=NULL; + } + + if(corpseDataPtr->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(corpseDataPtr->SoundHandle); + if(corpseDataPtr->SoundHandle2 != SOUND_NOACTIVEINDEX) Sound_Stop(corpseDataPtr->SoundHandle2); + if(corpseDataPtr->SoundHandle3 != SOUND_NOACTIVEINDEX) Sound_Stop(corpseDataPtr->SoundHandle3); + if(corpseDataPtr->SoundHandle4 != SOUND_NOACTIVEINDEX) Sound_Stop(corpseDataPtr->SoundHandle4); + + /* Remove corpse. */ + DestroyAnyStrategyBlock(sbPtr); + AddNetMsg_LocalObjectDestroyed(sbPtr); + return; + } + else + { + DISPLAYBLOCK *dispPtr = sbPtr->SBdptr; + + /* do we have a displayblock? */ + if (dispPtr) + { + dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND; + dispPtr->ObFlags2 = corpseDataPtr->timer/2; + + if (corpseDataPtr->Type==I_BehaviourXenoborg) { + /* Particularly important for xenoborgs... optional for others? */ + if (dispPtr->ObFlags2HModelController.DisableBleeding=1; + } + } + } + + /* Does the corpse that falls when not visible make no sound? */ + ProveHModel_Far(&corpseDataPtr->HModelController,sbPtr); + } + + corpseDataPtr->timer-=NormalFrameTime; + corpseDataPtr->validityTimer-=NormalFrameTime; + + /* May get decapitated whilst screaming... */ + if ((corpseDataPtr->Type==I_BehaviourMarine) + ||((corpseDataPtr->Type==I_BehaviourMarinePlayer)&&(AvP.PlayerType==I_Marine))) { + + SECTION_DATA *head; + + head=GetThisSectionData(corpseDataPtr->HModelController.section_data,"head"); + + /* Is it still attached? */ + if (head) { + if (head->flags§ion_data_notreal) { + head=NULL; + } + } + + if (head==NULL) { + if(corpseDataPtr->SoundHandle2 != SOUND_NOACTIVEINDEX) { + Sound_Stop(corpseDataPtr->SoundHandle2); + } + } + } + + if ((corpseDataPtr->Type==I_BehaviourPredator)|| + ((corpseDataPtr->Type==I_BehaviourMarinePlayer)&&(AvP.PlayerType==I_Predator))) { + + /* If we're a partially cloaked predator, continue to decloak. */ + if (corpseDataPtr->CloakStatus==PCLOAK_Off) { + /* Do nothing. */ + } else if (corpseDataPtr->CloakStatus==PCLOAK_Activating) { + /* Don't reset timer. */ + corpseDataPtr->CloakStatus = PCLOAK_Deactivating; + } else if (corpseDataPtr->CloakStatus==PCLOAK_Deactivating) { + /* Okay, okay! */ + } else { + /* Cloak must be On. */ + corpseDataPtr->CloakStatus = PCLOAK_Deactivating; + corpseDataPtr->CloakTimer = 0; /* Was predStatus->PredShimmer. */ + } + GLOBALASSERT((corpseDataPtr->CloakStatus==PCLOAK_Deactivating)||(corpseDataPtr->CloakStatus==PCLOAK_Off)); + /* Run the timer. */ + if (corpseDataPtr->CloakStatus==PCLOAK_Deactivating) { + corpseDataPtr->CloakTimer += NormalFrameTime; + if(corpseDataPtr->CloakTimer>=(ONE_FIXED)) + { + corpseDataPtr->CloakTimer=0; + corpseDataPtr->CloakStatus=PCLOAK_Off; + } + } + } else { + GLOBALASSERT(corpseDataPtr->CloakStatus==PCLOAK_Off); + } + + /* Marine specifics. */ + if (corpseDataPtr->Type==I_BehaviourMarine) { + /* Did marine die with the trigger held down? */ + if (corpseDataPtr->DeathFiring) { + /* Is there a gunflash? */ + if(corpseDataPtr->My_Gunflash_Section) { + /* But is it still attached? */ + if (corpseDataPtr->My_Gunflash_Section->my_controller==&(corpseDataPtr->HModelController)) { + /* Keep firing! */ + LOCALASSERT(corpseDataPtr->WeaponMisfireFunction); + /* Shouldn't be doing this without knowing why. */ + (*corpseDataPtr->WeaponMisfireFunction)(corpseDataPtr->My_Gunflash_Section,&corpseDataPtr->weapon_variable); + } + } + } + + /* Do we want to trim off the weapons? */ + + if (corpseDataPtr->HModelController.keyframe_flags) { + + GLOBALASSERT(corpseDataPtr->TemplateRoot); + + TrimToTemplate(sbPtr,&corpseDataPtr->HModelController,corpseDataPtr->TemplateRoot, 1); + } + } + + /* Fire sound code. */ + if(corpseDataPtr->SoundHandle3!=SOUND_NOACTIVEINDEX) Sound_Update3d(corpseDataPtr->SoundHandle3,&(sbPtr->DynPtr->Position)); + if(corpseDataPtr->SoundHandle4!=SOUND_NOACTIVEINDEX) Sound_Update3d(corpseDataPtr->SoundHandle4,&(sbPtr->DynPtr->Position)); + + if (sbPtr->SBDamageBlock.IsOnFire) { + if (corpseDataPtr->SoundHandle3!=SOUND_NOACTIVEINDEX) { + if (ActiveSounds[corpseDataPtr->SoundHandle3].soundIndex!=SID_FIRE) { + Sound_Stop(corpseDataPtr->SoundHandle3); + Sound_Play(SID_FIRE,"dlev",&(sbPtr->DynPtr->Position),&corpseDataPtr->SoundHandle3,127); + } + } else { + Sound_Play(SID_FIRE,"dlev",&(sbPtr->DynPtr->Position),&corpseDataPtr->SoundHandle3,127); + } + } else { + if (corpseDataPtr->SoundHandle3!=SOUND_NOACTIVEINDEX) { + Sound_Stop(corpseDataPtr->SoundHandle3); + } + } + + #if CORPSE_SIGHTINGS + Marine_CorpseSightingTest(sbPtr); + #endif + + /* Finally consider destructing preds. */ + if (corpseDataPtr->destructTimer>=0) { + corpseDataPtr->destructTimer-=NormalFrameTime; + if (corpseDataPtr->destructTimer<=0) { + StartPredatorSelfDestructExplosion(sbPtr); + corpseDataPtr->GibbFactor=ONE_FIXED; + corpseDataPtr->destructTimer=-1; + } + } +} + +void SetCorpseAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime) +{ + + NETCORPSEDATABLOCK *corpseStatus=(NETCORPSEDATABLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(length!=0); + + if (tweeningtime<=0) { + InitHModelSequence(&corpseStatus->HModelController,(int)type,subtype,length); + } else { + InitHModelTweening(&corpseStatus->HModelController, tweeningtime, (int)type,subtype,length,0); + } + + corpseStatus->HModelController.Playing=1; + /* Might be unset... */ +} + +void CorpseIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,SECTION_DATA *Section,VECTORCH *incoming) { + + NETCORPSEDATABLOCK *corpseDataPtr; + int tkd,deathtype; + + LOCALASSERT(sbPtr); + corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(corpseDataPtr); + + /* Set up gibb factor. */ + + tkd=TotalKineticDamage(damage); + deathtype=0; + + corpseDataPtr->Wounds|=wounds; + + switch(corpseDataPtr->Type) { + case I_BehaviourMarinePlayer: + { + if (damage->ExplosivePower==1) { + if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) { + /* Okay, you can gibb now. */ + corpseDataPtr->GibbFactor=ONE_FIXED>>1; + deathtype=2; + } + } else if ((tkd>60)&&((multiple>>16)>1)) { + int newmult; + + newmult=DIV_FIXED(multiple,NormalFrameTime); + if (MUL_FIXED(tkd,newmult)>(500)) { + /* Loadsabullets! */ + corpseDataPtr->GibbFactor=-(ONE_FIXED>>2); + deathtype=2; + } + } + + if ((damage->ExplosivePower==2)||(damage->ExplosivePower==6)) { + /* Basically SADARS only. */ + corpseDataPtr->GibbFactor=ONE_FIXED; + deathtype=3; + } + + if (damage->ForceBoom) { + deathtype+=damage->ForceBoom; + } + } + break; + case I_BehaviourAlien: + case I_BehaviourAlienPlayer: + { + if (damage->ExplosivePower==1) { + /* Explosion case. */ + if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) { + /* Okay, you can gibb now. */ + corpseDataPtr->GibbFactor=ONE_FIXED>>1; + deathtype=2; + } + } else if ((tkd<40)&&((multiple>>16)>1)) { + int newmult; + + newmult=DIV_FIXED(multiple,NormalFrameTime); + if (MUL_FIXED(tkd,newmult)>700) { + /* Excessive bullets case 1. */ + corpseDataPtr->GibbFactor=ONE_FIXED>>2; + deathtype=2; + } else if (MUL_FIXED(tkd,newmult)>250) { + /* Excessive bullets case 2. */ + corpseDataPtr->GibbFactor=ONE_FIXED>>3; + deathtype=1; + } + } + + /* Predaliens and preatorians only gibb for sadars. */ + if (corpseDataPtr->subtype!=0) { + corpseDataPtr->GibbFactor=0; + /* But retain deathtype. */ + } + + if ((damage->ExplosivePower==2)||(damage->ExplosivePower==6)) { + /* Basically SADARS only. */ + if (corpseDataPtr->Type==AT_Standard) { + corpseDataPtr->GibbFactor=ONE_FIXED; + } else { + corpseDataPtr->GibbFactor=ONE_FIXED>>2; + } + deathtype=3; + } + + if (damage->ForceBoom) { + deathtype+=damage->ForceBoom; + } + /* No additional gibbing for flamethrowers. */ + + if (damage->Id==AMMO_PREDPISTOL_STRIKE) { + /* Blow up if hit by the bolt? */ + corpseDataPtr->GibbFactor=ONE_FIXED>>3; + } else if (damage->Id==AMMO_PRED_PISTOL) { + /* Unfortunately, that can't happen. Try this test instead. */ + if (multiple>(43253)) { + /* Must be pretty close. */ + corpseDataPtr->GibbFactor=ONE_FIXED>>3; + } + } else if (damage->Id==AMMO_FLECHETTE_POSTMAX) { + corpseDataPtr->GibbFactor=ONE_FIXED>>2; + } + } + break; + case I_BehaviourPredator: + case I_BehaviourXenoborg: + /* Predator and Xenoborg 'splatting' currently ommitted... */ + break; + default: + break; + } + +} + + + + + + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" +typedef struct corpse_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int timer; + int validityTimer; + + AVP_BEHAVIOUR_TYPE Type; + int hltable_index; + int GibbFactor; + + /* If you're a predator... */ + PRED_CLOAKSTATE CloakStatus; + int CloakTimer; + int destructTimer; + /* If you're a marine... */ + int weapon_id; + int weapon_variable; + int Android; + int ARealMarine; + /* If you're an alien... */ + int subtype; + + int Wounds; + + int DeathFiring :1; + + + int deathCode; + + //strategyblock stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; + DYNAMICSBLOCK dynamics; +}CORPSE_SAVE_BLOCK; + + + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV corpseDataPtr + + +void LoadStrategy_Corpse(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + extern HITLOCATIONTABLE Global_Hitlocation_Tables[]; + + STRATEGYBLOCK* sbPtr; + NETCORPSEDATABLOCK* corpseDataPtr; + CORPSE_SAVE_BLOCK* block = (CORPSE_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //see if there is a living version of this corpse + sbPtr = FindSBWithName(header->SBname); + + if(sbPtr) + { + //make sure the strategy found is some type of creature + if(sbPtr->I_SBtype != I_BehaviourAlien && + sbPtr->I_SBtype != I_BehaviourMarine && + sbPtr->I_SBtype != I_BehaviourPredator && + sbPtr->I_SBtype != I_BehaviourDormantPredator && + sbPtr->I_SBtype != I_BehaviourXenoborg && + sbPtr->I_SBtype != I_BehaviourFaceHugger) + { + return; + } + //get rid of it then + DestroyAnyStrategyBlock(sbPtr); + + sbPtr = NULL; + } + + //now we need to create a corpse from scratch + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) + { + GLOBALASSERT(0=="Run out of strategy blocks"); + return; + } + InitialiseSBValues(sbPtr); + corpseDataPtr = (void *)AllocateMem(sizeof(NETCORPSEDATABLOCK)); + + //fill in some default values + memset(corpseDataPtr,0,sizeof(*corpseDataPtr)); + + corpseDataPtr->SoundHandle = SOUND_NOACTIVEINDEX; + corpseDataPtr->SoundHandle2 = SOUND_NOACTIVEINDEX; + corpseDataPtr->SoundHandle3 = SOUND_NOACTIVEINDEX; + corpseDataPtr->SoundHandle4 = SOUND_NOACTIVEINDEX; + + sbPtr->SBdataptr=corpseDataPtr; + sbPtr->I_SBtype=I_BehaviourNetCorpse; + COPY_NAME(sbPtr->SBname,block->header.SBname); + sbPtr->shapeIndex = 0; + sbPtr->maintainVisibility = 1; + + //get a dynamics block + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC); + + + //start copying stuff + + COPYELEMENT_LOAD(timer) + COPYELEMENT_LOAD(validityTimer) + COPYELEMENT_LOAD(Type) + COPYELEMENT_LOAD(GibbFactor) + COPYELEMENT_LOAD(CloakStatus) + COPYELEMENT_LOAD(CloakTimer) + COPYELEMENT_LOAD(destructTimer) + COPYELEMENT_LOAD(weapon_variable) + COPYELEMENT_LOAD(Android) + COPYELEMENT_LOAD(ARealMarine) + COPYELEMENT_LOAD(subtype) + COPYELEMENT_LOAD(Wounds) + COPYELEMENT_LOAD(DeathFiring) + + + //copy strategy block stuff + *sbPtr->DynPtr = block->dynamics; + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + + //hit location table + if(block->hltable_index>=0) + { + corpseDataPtr->hltable = &Global_Hitlocation_Tables[block->hltable_index]; + } + else + { + corpseDataPtr->hltable = NULL; + } + + // get death_data + corpseDataPtr->This_Death = GetThisDeath_FromUniqueCode(block->deathCode); + + //get marine's weapon (if a marine) + corpseDataPtr->My_Weapon = GetThisNPCMarineWeapon(block->weapon_id); + if(corpseDataPtr->My_Weapon) + { + corpseDataPtr->WeaponMisfireFunction=corpseDataPtr->My_Weapon->WeaponMisfireFunction; + corpseDataPtr->My_Gunflash_Section=corpseDataPtr->My_Gunflash_Section; + corpseDataPtr->TemplateRoot=GetNamedHierarchyFromLibrary(corpseDataPtr->My_Weapon->Riffname,corpseDataPtr->My_Weapon->TemplateName); + } + + + //load the corpse's hierarchy + { + SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); + if(hier_header) + { + LoadHierarchy(hier_header,&corpseDataPtr->HModelController); + } + } + + Load_SoundState(&corpseDataPtr->SoundHandle); + Load_SoundState(&corpseDataPtr->SoundHandle2); + Load_SoundState(&corpseDataPtr->SoundHandle3); + Load_SoundState(&corpseDataPtr->SoundHandle4); + +} + + +void SaveStrategy_Corpse(STRATEGYBLOCK* sbPtr) +{ + CORPSE_SAVE_BLOCK *block; + NETCORPSEDATABLOCK* corpseDataPtr; + + corpseDataPtr = (NETCORPSEDATABLOCK*)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + + COPYELEMENT_SAVE(timer) + COPYELEMENT_SAVE(validityTimer) + COPYELEMENT_SAVE(Type) + COPYELEMENT_SAVE(GibbFactor) + COPYELEMENT_SAVE(CloakStatus) + COPYELEMENT_SAVE(CloakTimer) + COPYELEMENT_SAVE(destructTimer) + COPYELEMENT_SAVE(weapon_variable) + COPYELEMENT_SAVE(Android) + COPYELEMENT_SAVE(ARealMarine) + COPYELEMENT_SAVE(subtype) + COPYELEMENT_SAVE(Wounds) + COPYELEMENT_SAVE(DeathFiring) + + + //hit location table + if(corpseDataPtr->hltable) + { + block->hltable_index = corpseDataPtr->hltable->index; + } + else + { + block->hltable_index = -1; + } + + //save death code + if(corpseDataPtr->This_Death) + { + block->deathCode = corpseDataPtr->This_Death->Unique_Code; + } + else + { + block->deathCode = -1; + } + + //save marine's weapon + if(corpseDataPtr->My_Weapon) + block->weapon_id = corpseDataPtr->My_Weapon->id; + else + block->weapon_id = -1; + + + //save strategy block stuff + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; + + //save the hierarchy + SaveHierarchy(&corpseDataPtr->HModelController); + + Save_SoundState(&corpseDataPtr->SoundHandle); + Save_SoundState(&corpseDataPtr->SoundHandle2); + Save_SoundState(&corpseDataPtr->SoundHandle3); + Save_SoundState(&corpseDataPtr->SoundHandle4); +} diff --git a/3dc/avp/bh_corpse.h b/3dc/avp/bh_corpse.h new file mode 100644 index 0000000..49ac27d --- /dev/null +++ b/3dc/avp/bh_corpse.h @@ -0,0 +1,67 @@ +#ifndef bh_corpse_h_included +#define bh_corpse_h_included +#ifdef __cplusplus +extern "C" { +#endif + +#define CORPSE_SIGHTINGS 1 + +typedef struct netcorpsedatablock { + int timer; + int validityTimer; + int SoundHandle; /* Just in case. */ + int SoundHandle2; + int SoundHandle3; + int SoundHandle4; + HMODELCONTROLLER HModelController; + + AVP_BEHAVIOUR_TYPE Type; + HITLOCATIONTABLE *hltable; + int GibbFactor; + DEATH_DATA *This_Death; + /* If you're a predator... */ + PRED_CLOAKSTATE CloakStatus; + int CloakTimer; + int destructTimer; + /* If you're a marine... */ + void (*WeaponMisfireFunction)(SECTION_DATA *, int *); + SECTION_DATA *My_Gunflash_Section; + SECTION *TemplateRoot; + struct marine_weapon_data *My_Weapon; + int weapon_variable; + int Android; + int ARealMarine; + /* If you're an alien... */ + int subtype; + + int Wounds; + + int DeathFiring :1; + + +}NETCORPSEDATABLOCK; + +extern void Convert_Alien_To_Corpse(STRATEGYBLOCK *sbPtr,DEATH_DATA *this_death,DAMAGE_PROFILE* damage); +extern void Convert_Predator_To_Corpse(STRATEGYBLOCK *sbPtr,DEATH_DATA *this_death); +extern void Convert_Marine_To_Corpse(STRATEGYBLOCK *sbPtr,DEATH_DATA *this_death); +extern void Convert_Xenoborg_To_Corpse(STRATEGYBLOCK *sbPtr,DEATH_DATA *this_death); +extern void CorpseBehaveFun(STRATEGYBLOCK *sbPtr); +extern void MakeCorpseNear(STRATEGYBLOCK *sbPtr); +extern void MakeCorpseFar(STRATEGYBLOCK *sbPtr); +extern void CorpseIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,SECTION_DATA *Section,VECTORCH *incoming); + +#define CORPSE_EXPIRY_TIME (ONE_FIXED*10) +#define CORPSE_VALIDITY_TIME (ONE_FIXED>>2) +#define ALIEN_DYINGTIME (ONE_FIXED*8) +#define PRED_DIETIME (ONE_FIXED*16) +#define MARINE_DYINGTIME (ONE_FIXED*16) +#define XENO_DYINGTIME (ONE_FIXED*8) +#define AGUN_DYINGTIME (ONE_FIXED*8) +#define HDEBRIS_LIFETIME (ONE_FIXED*8) +/* Was (ONE_FIXED*3)... */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/3dc/avp/bh_deathvol.c b/3dc/avp/bh_deathvol.c new file mode 100644 index 0000000..ead05ca --- /dev/null +++ b/3dc/avp/bh_deathvol.c @@ -0,0 +1,206 @@ + +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "dynblock.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "bh_deathvol.h" +#include "dynamics.h" +#include "weapons.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +extern int NumActiveBlocks; +extern DISPLAYBLOCK* ActiveBlockList[]; +extern DAMAGE_PROFILE DeathVolumeDamage; +extern int NormalFrameTime; + +void* DeathVolumeBehaveInit(void* bhdata,STRATEGYBLOCK* sbptr) +{ + DEATH_VOLUME_BEHAV_BLOCK* dv_bhv; + DEATH_VOLUME_TOOLS_TEMPLATE* dv_tt; + + GLOBALASSERT(sbptr); + GLOBALASSERT(bhdata); + + dv_bhv=(DEATH_VOLUME_BEHAV_BLOCK*)AllocateMem(sizeof(DEATH_VOLUME_BEHAV_BLOCK)); + if(!dv_bhv) + { + memoryInitialisationFailure = 1; + return 0; + } + dv_bhv->bhvr_type=I_BehaviourDeathVolume; + + dv_tt=(DEATH_VOLUME_TOOLS_TEMPLATE*)bhdata; + + //copy stuff from tools template + COPY_NAME(sbptr->SBname, dv_tt->nameID); + dv_bhv->volume_min=dv_tt->volume_min; + dv_bhv->volume_max=dv_tt->volume_max; + dv_bhv->damage_per_second=dv_tt->damage_per_second; + dv_bhv->active=dv_tt->active; + dv_bhv->collision_required=dv_tt->collision_required; + + + return (void*)dv_bhv; + +} + + + +void DeathVolumeBehaveFun(STRATEGYBLOCK* vol_sbptr) +{ + DEATH_VOLUME_BEHAV_BLOCK* dv_bhv; + GLOBALASSERT(vol_sbptr); + dv_bhv = (DEATH_VOLUME_BEHAV_BLOCK*)vol_sbptr->SBdataptr; + GLOBALASSERT((dv_bhv->bhvr_type == I_BehaviourDeathVolume)); + + if(dv_bhv->active) + { + int i; + STRATEGYBLOCK* sbPtr; + DYNAMICSBLOCK* dynPtr; + int miny,maxy; + + for(i=0;iObStrategyBlock; + if(!sbPtr) continue; + if(!sbPtr->DynPtr) continue; + dynPtr=sbPtr->DynPtr; + + if(dv_bhv->collision_required) + { + if(!dynPtr->CollisionReportPtr) continue; + } + + //is the object within the death volume? + //check a vertical line against the death volume's bounding box + + //first check the object's centre x and centre z values against the volume + if(dptr->ObWorld.vxvolume_min.vx) continue; + if(dptr->ObWorld.vx>dv_bhv->volume_max.vx) continue; + if(dptr->ObWorld.vzvolume_min.vz) continue; + if(dptr->ObWorld.vz>dv_bhv->volume_max.vz) continue; + + //now check the object's vertical extents for overlap with the death volume bounding box + miny=dptr->ObWorld.vy+dptr->ObMinY; + maxy=dptr->ObWorld.vy+dptr->ObMaxY; + if(max(miny,dv_bhv->volume_min.vy) > min(maxy,dv_bhv->volume_max.vy)) continue; + + /* + if(dynPtr->Position.vx > dv_bhv->volume_min.vx && + dynPtr->Position.vx < dv_bhv->volume_max.vx && + dynPtr->Position.vz > dv_bhv->volume_min.vz && + dynPtr->Position.vz < dv_bhv->volume_max.vz && + dynPtr->Position.vy > dv_bhv->volume_min.vy && + dynPtr->Position.vy < dv_bhv->volume_max.vy) + */ + { + //finally see if the object is one of the types that can be harmed by the death volume + if(sbPtr->I_SBtype==I_BehaviourAlien || + sbPtr->I_SBtype==I_BehaviourQueenAlien || + sbPtr->I_SBtype==I_BehaviourFaceHugger || + sbPtr->I_SBtype==I_BehaviourPredator || + sbPtr->I_SBtype==I_BehaviourXenoborg || + sbPtr->I_SBtype==I_BehaviourMarine || + sbPtr->I_SBtype==I_BehaviourSeal || + sbPtr->I_SBtype==I_BehaviourPredatorAlien || + sbPtr->I_SBtype==I_BehaviourAlien || + sbPtr->I_SBtype==I_BehaviourMarinePlayer || + sbPtr->I_SBtype==I_BehaviourPredatorPlayer || + sbPtr->I_SBtype==I_BehaviourAlienPlayer) + { + extern DPID myNetworkKillerId; + extern DPID AVPDPNetID; + + //this is a neutral source of damage (for cooperative multiplayer games) + myNetworkKillerId = 0; + + if(dv_bhv->damage_per_second) + { + //all new damage volumes. + VECTORCH direction={0,-ONE_FIXED,0}; + DAMAGE_PROFILE damage = DeathVolumeDamage; + damage.Penetrative = dv_bhv->damage_per_second; + CauseDamageToObject(sbPtr,&damage,NormalFrameTime,&direction); + } + else + { + //kill the creature/player + VECTORCH direction={0,-ONE_FIXED,0}; + CauseDamageToObject(sbPtr,&certainDeath,ONE_FIXED,&direction); + } + + //reset network killer id + myNetworkKillerId = AVPDPNetID; + + } + + } + } + + + } + +} + + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" + +typedef struct death_volume_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + BOOL active; + +}DEATH_VOLUME_SAVE_BLOCK; + + +void LoadStrategy_DeathVolume(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + DEATH_VOLUME_BEHAV_BLOCK* dv_bhv; + DEATH_VOLUME_SAVE_BLOCK* block = (DEATH_VOLUME_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourDeathVolume) return; + + dv_bhv = (DEATH_VOLUME_BEHAV_BLOCK*)sbPtr->SBdataptr; + + //start copying stuff + dv_bhv->active = block->active; +} + +void SaveStrategy_DeathVolume(STRATEGYBLOCK* sbPtr) +{ + DEATH_VOLUME_SAVE_BLOCK *block; + DEATH_VOLUME_BEHAV_BLOCK* dv_bhv; + + dv_bhv = (DEATH_VOLUME_BEHAV_BLOCK*)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + block->active = dv_bhv->active; + +} + diff --git a/3dc/avp/bh_deathvol.h b/3dc/avp/bh_deathvol.h new file mode 100644 index 0000000..1226e05 --- /dev/null +++ b/3dc/avp/bh_deathvol.h @@ -0,0 +1,45 @@ +#ifndef _bh_deathvol_h +#define _bh_deathvol_h 1 + +#ifdef __cplusplus + + extern "C" { + +#endif + +extern void* DeathVolumeBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr); +extern void DeathVolumeBehaveFun(STRATEGYBLOCK* sbptr); + + +typedef struct death_volume_behav_block +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + VECTORCH volume_min; + VECTORCH volume_max; + unsigned int damage_per_second; //0 means infinite damage (a proper death volume - bwa ha ha.) + unsigned int active :1; + unsigned int collision_required :1; +}DEATH_VOLUME_BEHAV_BLOCK; + +typedef struct death_volume_tools_template +{ + char nameID[SB_NAME_LENGTH]; + VECTORCH volume_min; + VECTORCH volume_max; + unsigned int damage_per_second; + unsigned int active :1; + unsigned int collision_required :1; +}DEATH_VOLUME_TOOLS_TEMPLATE; + + + + + +#ifdef __cplusplus + + }; + +#endif + + +#endif diff --git a/3dc/avp/bh_debri.h b/3dc/avp/bh_debri.h new file mode 100644 index 0000000..3ea8342 --- /dev/null +++ b/3dc/avp/bh_debri.h @@ -0,0 +1,48 @@ +typedef struct OneShotAnimBehaviourType +{ + int counter; + TXACTRLBLK *tac_os; +} ONESHOT_ANIM_BEHAV_BLOCK; + +typedef struct SmokeGenBehaviourType +{ + int counter; + int smokes; +} SMOKEGEN_BEHAV_BLOCK; + +typedef struct HierarchicalDebrisBehaviourType { + int counter; + int smokes; + int GibbFactor; + int Android; + HMODELCONTROLLER HModelController; + + /* behaviour type of parent object, e.g. I_BehaviourAlien */ + AVP_BEHAVIOUR_TYPE Type; + int SubType; + + /* Silly stuff for bouncing sounds. */ + int bouncelastframe; + enum soundindex Bounce_Sound; + +} HDEBRIS_BEHAV_BLOCK; + +// extern functions + +extern DISPLAYBLOCK *MakeDebris(AVP_BEHAVIOUR_TYPE bhvr, VECTORCH *positionPtr); +extern DISPLAYBLOCK *MakeHierarchicalDebris(STRATEGYBLOCK *parent_sbPtr,SECTION_DATA *root, VECTORCH *positionPtr, MATRIXCH *orientation, int *wounds, int speed); +extern void Pop_Section(STRATEGYBLOCK *sbPtr,SECTION_DATA *section_data, VECTORCH *blastcentre, int *wounds); +extern void CreateShapeInstance(MODULEMAPBLOCK *mmbptr, char *shapeNamePtr); +extern void OneShotBehaveFun(STRATEGYBLOCK* sptr); +extern void OneShot_Anim_BehaveFun(STRATEGYBLOCK* sptr); +extern void MakeFragments (STRATEGYBLOCK *sbptr); + + +#define EXPLOSION_LIFETIME (ONE_FIXED/4) +#define EXPLOSION_ANIM_SPEED (ONE_FIXED*16) +#define EXPLOSION_LIGHTING_SCALE (ONE_FIXED*16/3) +#if PSX || Saturn +#define NO_OF_SPRITES_IN_BIG_EXPLOSION 5 +#else +#define NO_OF_SPRITES_IN_BIG_EXPLOSION 10 +#endif \ No newline at end of file diff --git a/3dc/avp/bh_dummy.c b/3dc/avp/bh_dummy.c new file mode 100644 index 0000000..3ee3c5e --- /dev/null +++ b/3dc/avp/bh_dummy.c @@ -0,0 +1,326 @@ +/* CDF 9/10/98 A bold new initiaitive! */ + +#include "3dc.h" +#include "inline.h" +#include "module.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" + +#include "dynblock.h" +#include "dynamics.h" + +#include "weapons.h" +#include "comp_shp.h" +#include "inventry.h" +#include "triggers.h" +#include "mslhand.h" + +#define UseLocalAssert Yes + +#include "ourasert.h" + +#include "pmove.h" +#include "pvisible.h" +#include "bh_swdor.h" +#include "bh_plift.h" +#include "load_shp.h" +#include "bh_weap.h" +#include "bh_debri.h" +#include "lighting.h" +#include "bh_lnksw.h" +#include "bh_binsw.h" +#include "pheromon.h" +#include "bh_pred.h" +#include "bh_agun.h" +#include "plat_shp.h" +#include "psnd.h" +#include "AI_Sight.h" +#include "sequnces.h" +#include "huddefs.h" +#include "ShowCmds.h" +#include "sfx.h" +#include "bh_marin.h" +#include "bh_dummy.h" +#include "bh_far.h" +#include "pldghost.h" +#include "pheromon.h" +#include "targeting.h" +#include "dxlog.h" +#include "los.h" +#include "psndplat.h" +#include "extents.h" + +#if SupportWindows95 +/* for win95 net game support */ +#include "pldghost.h" +#include "pldnet.h" +#endif + +extern int NormalFrameTime; +extern unsigned char Null_Name[8]; +extern ACTIVESOUNDSAMPLE ActiveSounds[]; +extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); +void CreateDummy(VECTORCH *Position); + +/* Begin code! */ + +void CastDummy(void) { + + #define BOTRANGE 2000 + + VECTORCH position; + + if (AvP.Network!=I_No_Network) { + NewOnScreenMessage("NO DUMMYS IN MULTIPLAYER MODE"); + return; + } + + position=Player->ObStrategyBlock->DynPtr->Position; + position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE); + position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE); + position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE); + + CreateDummy(&position); + +} + +void CreateDummy(VECTORCH *Position) { + + STRATEGYBLOCK* sbPtr; + + /* create and initialise a strategy block */ + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) { + NewOnScreenMessage("FAILED TO CREATE DUMMY: SB CREATION FAILURE"); + return; /* failure */ + } + InitialiseSBValues(sbPtr); + + sbPtr->I_SBtype = I_BehaviourDummy; + + AssignNewSBName(sbPtr); + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_MARINE_PLAYER); + if(sbPtr->DynPtr) + { + EULER zeroEuler = {0,0,0}; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + GLOBALASSERT(dynPtr); + dynPtr->PrevPosition = dynPtr->Position = *Position; + dynPtr->OrientEuler = zeroEuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + } + else + { + /* dynamics block allocation failed... */ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE DUMMY: DYNBLOCK CREATION FAILURE"); + return; + } + + sbPtr->shapeIndex = 0; + + sbPtr->maintainVisibility = 1; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0); + + /* Initialise dummy's stats */ + { + sbPtr->SBDamageBlock.Health=30000<SBDamageBlock.Armour=30000<SBDamageBlock.SB_H_flags.AcidResistant=1; + sbPtr->SBDamageBlock.SB_H_flags.FireResistant=1; + sbPtr->SBDamageBlock.SB_H_flags.ElectricResistant=1; + sbPtr->SBDamageBlock.SB_H_flags.PerfectArmour=1; + sbPtr->SBDamageBlock.SB_H_flags.ElectricSensitive=0; + sbPtr->SBDamageBlock.SB_H_flags.Combustability=0; + sbPtr->SBDamageBlock.SB_H_flags.Indestructable=1; + } + /* create, initialise and attach a dummy data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(DUMMY_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + SECTION *root_section; + DUMMY_STATUS_BLOCK *dummyStatus = (DUMMY_STATUS_BLOCK *)sbPtr->SBdataptr; + GLOBALASSERT(dummyStatus); + + dummyStatus->incidentFlag=0; + dummyStatus->incidentTimer=0; + + dummyStatus->HModelController.section_data=NULL; + dummyStatus->HModelController.Deltas=NULL; + + switch (AvP.PlayerType) { + case I_Marine: + dummyStatus->PlayerType=I_Marine; + root_section=GetNamedHierarchyFromLibrary("hnpcmarine","marine with pulse rifle"); + if (!root_section) { + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE DUMMY: NO HMODEL"); + return; + } + Create_HModel(&dummyStatus->HModelController,root_section); + InitHModelSequence(&dummyStatus->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Fidget_A,-1); + break; + case I_Alien: + dummyStatus->PlayerType=I_Alien; + root_section=GetNamedHierarchyFromLibrary("hnpcalien","alien"); + if (!root_section) { + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE DUMMY: NO HMODEL"); + return; + } + Create_HModel(&dummyStatus->HModelController,root_section); + InitHModelSequence(&dummyStatus->HModelController,(int)HMSQT_AlienStand,(int)ASSS_Standard,-1); + break; + case I_Predator: + dummyStatus->PlayerType=I_Predator; + root_section=GetNamedHierarchyFromLibrary("hnpcpredator","pred with wristblade"); + if (!root_section) { + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE DUMMY: NO HMODEL"); + return; + } + Create_HModel(&dummyStatus->HModelController,root_section); + InitHModelSequence(&dummyStatus->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_Standard,-1); + break; + } + ProveHModel_Far(&dummyStatus->HModelController,sbPtr); + + if(!(sbPtr->containingModule)) + { + /* no containing module can be found... abort*/ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE DUMMY: MODULE CONTAINMENT FAILURE"); + return; + } + LOCALASSERT(sbPtr->containingModule); + + MakeDummyNear(sbPtr); + + NewOnScreenMessage("DUMMY CREATED"); + + } else { + /* no data block can be allocated */ + RemoveBehaviourStrategy(sbPtr); + NewOnScreenMessage("FAILED TO CREATE DUMMY: MALLOC FAILURE"); + return; + } +} + +void MakeDummyNear(STRATEGYBLOCK *sbPtr) +{ + extern MODULEMAPBLOCK AlienDefaultMap; + + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr; + DUMMY_STATUS_BLOCK *dummyStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->SBdptr == NULL); + dynPtr = sbPtr->DynPtr; + dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(dummyStatusPointer); + LOCALASSERT(dynPtr); + + + AlienDefaultMap.MapShape = sbPtr->shapeIndex; + tempModule.m_mapptr = &AlienDefaultMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 0; + tempModule.m_lightarray = (struct lightblock *)0; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr = NULL; + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) return; /* cannot allocate displayblock, so leave far */ + + sbPtr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbPtr; + dPtr->ObMyModule = NULL; + + /* need to initialise positional information in the new display block */ + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + + /* zero linear velocity in dynamics block */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + /* state and sequence initialisation */ + + dPtr->HModelControlBlock=&dummyStatusPointer->HModelController; + + ProveHModel(dPtr->HModelControlBlock,dPtr); + + /*Copy extents from the collision extents in extents.c*/ + dPtr->ObMinX=-CollisionExtents[CE_MARINE].CollisionRadius; + dPtr->ObMaxX=CollisionExtents[CE_MARINE].CollisionRadius; + dPtr->ObMinZ=-CollisionExtents[CE_MARINE].CollisionRadius; + dPtr->ObMaxZ=CollisionExtents[CE_MARINE].CollisionRadius; + dPtr->ObMinY=CollisionExtents[CE_MARINE].CrouchingTop; + dPtr->ObMaxY=CollisionExtents[CE_MARINE].Bottom; + dPtr->ObRadius = 1000; + +} + +void MakeDummyFar(STRATEGYBLOCK *sbPtr) +{ + DUMMY_STATUS_BLOCK *dummyStatusPointer; + int i; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->SBdptr != NULL); + dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(dummyStatusPointer); + + /* get rid of the displayblock */ + i = DestroyActiveObject(sbPtr->SBdptr); + LOCALASSERT(i==0); + sbPtr->SBdptr = NULL; + + /* zero linear velocity in dynamics block */ + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + +} + +void DummyBehaviour(STRATEGYBLOCK *sbPtr) { + + DUMMY_STATUS_BLOCK *dummyStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(dummyStatusPointer); + + /* Should be the same near as far. */ + /* test if we've got a containing module: if we haven't, do nothing. + This is important as the object could have been marked for deletion by the visibility + management system...*/ + if(!sbPtr->containingModule) + { + DestroyAnyStrategyBlock(sbPtr); /* just to make sure */ + return; + } else if (dummyStatusPointer->PlayerType!=I_Alien) { + AddMarinePheromones(sbPtr->containingModule->m_aimodule); + } + + /* Incident handling. */ + dummyStatusPointer->incidentFlag=0; + + dummyStatusPointer->incidentTimer-=NormalFrameTime; + + if (dummyStatusPointer->incidentTimer<0) { + dummyStatusPointer->incidentFlag=1; + dummyStatusPointer->incidentTimer=32767+(FastRandom()&65535); + } + +} diff --git a/3dc/avp/bh_dummy.h b/3dc/avp/bh_dummy.h new file mode 100644 index 0000000..1e1baaa --- /dev/null +++ b/3dc/avp/bh_dummy.h @@ -0,0 +1,34 @@ + +#ifndef _bhdummy_h_ + #define _bhdummy_h_ 1 + + + #ifdef __cplusplus + + extern "C" { + + #endif + + #include "bh_ais.h" + + typedef struct dummyStatusBlock { + I_PLAYER_TYPE PlayerType; + int incidentFlag; + int incidentTimer; + HMODELCONTROLLER HModelController; + } DUMMY_STATUS_BLOCK; + + + extern void MakeDummyNear(STRATEGYBLOCK *sbPtr); + extern void MakeDummyFar(STRATEGYBLOCK *sbPtr); + extern void DummyBehaviour(STRATEGYBLOCK *sbPtr); + + + #ifdef __cplusplus + + } + + #endif + + +#endif diff --git a/3dc/avp/bh_fan.c b/3dc/avp/bh_fan.c new file mode 100644 index 0000000..da098c5 --- /dev/null +++ b/3dc/avp/bh_fan.c @@ -0,0 +1,255 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "dynblock.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "track.h" +#include "bh_fan.h" +#include "dynamics.h" +#include "weapons.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "plat_shp.h" + +extern int NormalFrameTime; +extern DAMAGE_PROFILE fan_damage; + +void* FanBehaveInit(void* bhdata,STRATEGYBLOCK* sbptr) +{ + FAN_BEHAV_BLOCK* f_bhv; + FAN_TOOLS_TEMPLATE* f_tt; + + GLOBALASSERT(sbptr); + GLOBALASSERT(bhdata); + + f_bhv=(FAN_BEHAV_BLOCK*)AllocateMem(sizeof(FAN_BEHAV_BLOCK)); + if(!f_bhv) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + f_bhv->bhvr_type=I_BehaviourFan; + + f_tt=(FAN_TOOLS_TEMPLATE*)bhdata; + + sbptr->shapeIndex = f_tt->shape_num; + COPY_NAME(sbptr->SBname, f_tt->nameID); + + GLOBALASSERT(sbptr->DynPtr); + + sbptr->DynPtr->Position = sbptr->DynPtr->PrevPosition = f_tt->position; + sbptr->DynPtr->OrientEuler = f_tt->orientation; + CreateEulerMatrix(&sbptr->DynPtr->OrientEuler, &sbptr->DynPtr->OrientMat); + TransposeMatrixCH(&sbptr->DynPtr->OrientMat); + + f_bhv->track=f_tt->track; + GLOBALASSERT(f_bhv->track); + f_bhv->track->sbptr=sbptr; + f_bhv->track->use_speed_mult=1; + + f_bhv->speed_up_mult=f_tt->speed_up_mult; + f_bhv->slow_down_mult=f_tt->slow_down_mult; + f_bhv->fan_wind_direction=f_tt->fan_wind_direction; + f_bhv->fan_wind_strength=f_tt->fan_wind_strength; + + if(f_bhv->track->playing) + { + f_bhv->speed_mult=ONE_FIXED; + f_bhv->track->speed_mult=ONE_FIXED; + f_bhv->state=fan_state_go; + } + else + { + f_bhv->speed_mult=0; + f_bhv->state=fan_state_stop; + } + //update wind speed + f_bhv->wind_speed=MUL_FIXED(f_bhv->speed_mult,f_bhv->fan_wind_strength); + + return ((void*)f_bhv); +} + + +void FanBehaveFun(STRATEGYBLOCK* sbptr) +{ + FAN_BEHAV_BLOCK *f_bhv; + + GLOBALASSERT(sbptr); + f_bhv = (FAN_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((f_bhv->bhvr_type == I_BehaviourFan)); + GLOBALASSERT(f_bhv->track); + +// textprint("I am a fan\n"); + if(f_bhv->state==fan_state_go) + { + if(f_bhv->speed_mult==0) + { + //fan just starting + Start_Track_Playing(f_bhv->track); + } + + if(f_bhv->speed_multspeed_mult+=MUL_FIXED(NormalFrameTime,f_bhv->speed_up_mult); + + if(f_bhv->speed_mult>=ONE_FIXED) + { + f_bhv->speed_mult=ONE_FIXED; + } + f_bhv->track->speed_mult=f_bhv->speed_mult; + //update wind speed + f_bhv->wind_speed=MUL_FIXED(f_bhv->speed_mult,f_bhv->fan_wind_strength); + + } + } + else + { + if(f_bhv->speed_mult>0) + { + //fan currently slowing down + f_bhv->speed_mult-=MUL_FIXED(NormalFrameTime,f_bhv->slow_down_mult); + + if(f_bhv->speed_mult<0) + { + //fan has come to a stop + f_bhv->speed_mult=0; + Stop_Track_Playing(f_bhv->track); + } + f_bhv->track->speed_mult=f_bhv->speed_mult; + //update wind speed + f_bhv->wind_speed=MUL_FIXED(f_bhv->speed_mult,f_bhv->fan_wind_strength); + + } + } + + if(f_bhv->speed_mult) + { + Update_Track_Position(f_bhv->track); + } + + //see if fan has hit anything + if(sbptr->DynPtr->CollisionReportPtr) + { + //don't cause damage iunless fan is going reasonably fast + if(f_bhv->speed_mult>ONE_FIXED/4) + { + COLLISIONREPORT* reportptr=sbptr->DynPtr->CollisionReportPtr; + + fan_damage.Cutting=MUL_FIXED(f_bhv->speed_mult,200); + //go through all the collision reports and damage any creatures found + while(reportptr) + { + if(reportptr->ObstacleSBPtr) + { + STRATEGYBLOCK* hit_sbptr=reportptr->ObstacleSBPtr; + if(hit_sbptr->I_SBtype==I_BehaviourAlien || + hit_sbptr->I_SBtype==I_BehaviourQueenAlien || + hit_sbptr->I_SBtype==I_BehaviourFaceHugger || + hit_sbptr->I_SBtype==I_BehaviourPredator || + hit_sbptr->I_SBtype==I_BehaviourXenoborg || + hit_sbptr->I_SBtype==I_BehaviourMarine || + hit_sbptr->I_SBtype==I_BehaviourSeal || + hit_sbptr->I_SBtype==I_BehaviourPredatorAlien || + hit_sbptr->I_SBtype==I_BehaviourAlien || + hit_sbptr->I_SBtype==I_BehaviourMarinePlayer || + hit_sbptr->I_SBtype==I_BehaviourPredatorPlayer || + hit_sbptr->I_SBtype==I_BehaviourAlienPlayer) + { + if(f_bhv->speed_mult==ONE_FIXED) + { + //ensure death if fan is going at full speed + CauseDamageToObject(hit_sbptr,&fan_damage,100*ONE_FIXED,&f_bhv->fan_wind_direction); + } + else + { + CauseDamageToObject(hit_sbptr,&fan_damage,NormalFrameTime,&f_bhv->fan_wind_direction); + } + } + } + reportptr=reportptr->NextCollisionReportPtr; + } + } + } + +} + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" +typedef struct fan_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + FAN_STATE state; + int speed_mult; //0 to one_fixed : current speed relative to full speed + int wind_speed;//fixed point multiplier , taking the fan's current speed into account +}FAN_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV f_bhv + +void LoadStrategy_Fan(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + FAN_BEHAV_BLOCK *f_bhv; + FAN_SAVE_BLOCK* block = (FAN_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourFan) return; + + f_bhv = (FAN_BEHAV_BLOCK*)sbPtr->SBdataptr; + + //start copying stuff + + COPYELEMENT_LOAD(state) + COPYELEMENT_LOAD(speed_mult) + COPYELEMENT_LOAD(wind_speed) + + //load the track position + if(f_bhv->track) + { + SAVE_BLOCK_HEADER* track_header = GetNextBlockIfOfType(SaveBlock_Track); + if(track_header) + { + LoadTrackPosition(track_header,f_bhv->track); + } + } +} + + +void SaveStrategy_Fan(STRATEGYBLOCK* sbPtr) +{ + FAN_SAVE_BLOCK* block; + FAN_BEHAV_BLOCK *f_bhv; + + f_bhv = (FAN_BEHAV_BLOCK*)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + + COPYELEMENT_SAVE(state) + COPYELEMENT_SAVE(speed_mult) + COPYELEMENT_SAVE(wind_speed) + + //save the track position + if(f_bhv->track) + { + SaveTrackPosition(f_bhv->track); + } + +} diff --git a/3dc/avp/bh_fan.h b/3dc/avp/bh_fan.h new file mode 100644 index 0000000..59706a1 --- /dev/null +++ b/3dc/avp/bh_fan.h @@ -0,0 +1,68 @@ +#ifndef _bh_fan_h_ +#define _bh_fan_h_ 1 + + +#ifdef __cplusplus + + extern "C" { + +#endif + +void* FanBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr); +void FanBehaveFun(STRATEGYBLOCK* sbptr); + + + +typedef enum fan_states +{ + fan_state_go, + fan_state_stop, +}FAN_STATE; + + +typedef struct fan_behav_block +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + + FAN_STATE state; + + TRACK_CONTROLLER* track; + + int speed_up_mult; //one over time take to get to full speed + int slow_down_mult; //one over time take to stop + int speed_mult; //0 to one_fixed : current speed relative to full speed + + VECTORCH fan_wind_direction; //normalised vector + int fan_wind_strength; //fixed point multiplier for fan at full speed + + int wind_speed;//fixed point multiplier , taking the fan's current speed into account + +}FAN_BEHAV_BLOCK; + + +typedef struct fan_tools_template +{ + char nameID[SB_NAME_LENGTH]; + int shape_num; + + VECTORCH position; + EULER orientation; + + int speed_up_mult; //one over time take to get to full speed + int slow_down_mult; //one over time take to stop + + TRACK_CONTROLLER* track; + + VECTORCH fan_wind_direction; //normalised vector + int fan_wind_strength; //fixed point multiplier +}FAN_TOOLS_TEMPLATE; + + +#ifdef __cplusplus + + }; + +#endif + + +#endif diff --git a/3dc/avp/bh_far.c b/3dc/avp/bh_far.c new file mode 100644 index 0000000..8f851fa --- /dev/null +++ b/3dc/avp/bh_far.c @@ -0,0 +1,1258 @@ +/*------------------------Patrick 26/11/96----------------------------- + Source file for FAR AI alien behaviour etc.... + NB some of the functions in this file are re-used for other NPC AI. + --------------------------------------------------------------------*/ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "comp_shp.h" + +#include "dynblock.h" +#include "dynamics.h" + +#include "pheromon.h" +#include "bh_pred.h" +#include "bh_alien.h" +#include "bh_far.h" +#include "pfarlocs.h" +#include "bh_gener.h" +#include "pvisible.h" +#include "bh_marin.h" +#include "weapons.h" +#include "ShowCmds.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "dxlog.h" + +/* prototypes for this file */ +static void Execute_AFS_Hunt(STRATEGYBLOCK *sbPtr); +static void Execute_AFS_Wait(STRATEGYBLOCK *sbPtr); +static void Execute_AFS_Retreat(STRATEGYBLOCK *sbPtr); +static void Execute_AFS_Wander(STRATEGYBLOCK *sbPtr); +static void Execute_AFS_Approach(STRATEGYBLOCK *sbPtr); +static void Execute_AFS_Attack(STRATEGYBLOCK *sbPtr); +static void Execute_AFS_Avoidance(STRATEGYBLOCK *sbPtr); +static int ProcessFarAlienTargetModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule); +extern void AlienNearState_Dormant(STRATEGYBLOCK *sbPtr); +extern void AlienNearState_Awakening(STRATEGYBLOCK *sbPtr); +extern void AlienNearState_Taunting(STRATEGYBLOCK *sbPtr); + +/* external global variables used in this file */ +extern int NormalFrameTime; +extern int ModuleArraySize; +extern char *ModuleCurrVisArray; +static int entryPointFailures = 0; +extern int ShowHiveState; + +extern SCENE Global_Scene; +extern SCENEMODULE **Global_ModulePtr; +static MODULE **Global_ModuleArrayPtr; + +extern void Execute_Alien_Dying(STRATEGYBLOCK *sbPtr); + +/*--------------------Patrick 9/12/96----------------------- + Far Alien behaviour execution shell. + Behaviour is defined by a set of states: the AFS_.... + enumeration defined in bh_alien.h. + In addition, the far alien state is defined by a timer: ie + any state may 'timeout', possibly forcing a state change. + ----------------------------------------------------------*/ +void FarAlienBehaviour(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + char *descriptor; + + LOCALASSERT(sbPtr); + /* a precondition: there should be no display block */ + LOCALASSERT(!(sbPtr->SBdptr)); + + /* get the alien's status block */ + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + /* execute far behaviour state... */ + switch(alienStatusPointer->BehaviourState) + { + case(ABS_Wait): + { + Execute_AFS_Wait(sbPtr); + descriptor="Waiting"; + break; + } + case(ABS_Approach): + case(ABS_Jump): + { + Execute_AFS_Approach(sbPtr); + descriptor="Approaching"; + break; + } + case(ABS_Hunt): + { + Execute_AFS_Hunt(sbPtr); + descriptor="Hunting"; + break; + } + case(ABS_Retreat): + { + Execute_AFS_Retreat(sbPtr); + descriptor="Retreating"; + break; + } + case(ABS_Wander): + { + Execute_AFS_Wander(sbPtr); + descriptor="Wandering"; + break; + } + case(ABS_Attack): + case(ABS_Pounce): + { + Execute_AFS_Attack(sbPtr); + descriptor="Attacking"; + break; + } + case(ABS_Avoidance): + { + Execute_AFS_Avoidance(sbPtr); + descriptor="Avoiding"; + break; + } + case(ABS_Dying): + { + descriptor="Dying"; + Execute_Alien_Dying(sbPtr); + break; + } + case ABS_Dormant: + { + AlienNearState_Dormant(sbPtr); + descriptor="Dormant"; + break; + } + case ABS_Awakening: + { + AlienNearState_Awakening(sbPtr); + descriptor="Awakening"; + break; + } + case ABS_Taunting: + { + AlienNearState_Taunting(sbPtr); + descriptor="Taunting"; + break; + } + default: + { + LOCALASSERT(1==0); /* should never get here */ + } + } + + /* check here to see if the alien is in a doorway.... + If so, and it is a proximity door, make sure it is open. */ + { + MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule); + + if(doorType == MDT_ProxDoor) { + ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->alienTrigger = 1; + } + } + + if (ShowHiveState) { + /* Alien position print. */ + + MODULE *thisModule = sbPtr->containingModule; + + LOCALASSERT(thisModule); + + PrintDebuggingText("This FAR %s ALIEN is in module %d, %s\n",descriptor,thisModule->m_index,thisModule->name); + + } + + /* make sure that we are inside a module: + if this fires it means that a far alien is not inside + the module it is supposed to be in */ + #if UseLocalAssert + { + VECTORCH localCoords; + MODULE *thisModule = sbPtr->containingModule; + + LOCALASSERT(thisModule); + + localCoords = sbPtr->DynPtr->Position; + localCoords.vx -= thisModule->m_world.vx; + localCoords.vy -= thisModule->m_world.vy; + localCoords.vz -= thisModule->m_world.vz; + + if(PointIsInModule(thisModule, &localCoords)==0) + { + #if (!PSX) + textprint("FAR ALIEN MODULE CONTAINMENT FAILURE \n"); + + LOGDXFMT(("Alien containment failure: %s alien is in %s, position is %d,%d,%d:\nModule extents are: %d:%d, %d:%d, %d:%d", + descriptor, + thisModule->name,localCoords.vx,localCoords.vy,localCoords.vz, + thisModule->m_maxx,thisModule->m_minx,thisModule->m_maxy,thisModule->m_miny, + thisModule->m_maxz,thisModule->m_minz)); + + LOCALASSERT(1==0); + #endif + } + } + #endif + + /* textprint("NO ENTRY POINT COUNT %d \n", entryPointFailures); */ + + +} + +/*--------------------Patrick 9/12/96----------------------- + Execute far alien hunting behaviour.... + This is basically the default alien behaviour, following + the player's pheromone trail. + + On hunting behaviour, the alien moves between modules + using the pre-computed module locations list. After + being relocated to a new module, the alien waits for 'x' + seconds (having a good sniff around) then decides which + module to move into next. + + NB only passable modules are updated with player smell, + so aliens won't get stuck behind non-automatic doors. + ----------------------------------------------------------*/ +static void Execute_AFS_Hunt(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + AIMODULE *targetModule = 0; + + /* get the alien's status block */ + LOCALASSERT(sbPtr); + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + /* Decrement the Far state timer */ + alienStatusPointer->FarStateTimer -= NormalFrameTime; + + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(alienStatusPointer->FarStateTimer>0) return; + + /* check the alien hive, to see itf we've switched to regroup: + if so, reset the alien far behaviour state to retreat, with the alien far + state timer set to 0, forcing a retreating movement next frame... */ + if(NPCHive.currentState == HS_Regroup) + { + alienStatusPointer->BehaviourState = ABS_Retreat; + alienStatusPointer->FarStateTimer = 0; /* forces execution of new state next frame*/ + return; + } + + /* check to see if the player is invisible, etc... */ +// if ((!AlienIsAwareOfTarget(sbPtr)) +// ||(alienStatusPointer->Target!=Player->ObStrategyBlock)) + if ((!AlienIsAwareOfTarget(sbPtr))&&(alienStatusPointer->Target==Player->ObStrategyBlock) + &&(NPC_IsDead(Player->ObStrategyBlock))) + { + alienStatusPointer->BehaviourState = ABS_Wander; + alienStatusPointer->FarStateTimer = 0; /* forces execution of new state next frame*/ + return; + } + + /* get the target */ + targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr,1); + + /* if there is no target module, it means that the alien is trapped in an + unlinked module. In this case, reset the timer and return. */ + if(!targetModule) + { + alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME; + + #if 0 + /* Better have a handler for this. */ + alienStatusPointer->BehaviourState = ABS_Dormant; + alienStatusPointer->CurveTimeOut = 0; + if (HModelSequence_Exists(&alienStatusPointer->HModelController,HMSQT_AlienStand,ASSS_Dormant)) { + SetAlienShapeAnimSequence_Core(sbPtr,HMSQT_AlienStand,ASSS_Dormant,-1,ONE_FIXED); + } else { + SetAlienShapeAnimSequence_Core(sbPtr,HMSQT_AlienStand,ASSS_Standard,ONE_FIXED,(ONE_FIXED>>2)); + } + #else + alienStatusPointer->BehaviourState = ABS_Wander; + alienStatusPointer->CurveTimeOut = 0; + #endif + return; + } + + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + + #if 0 + ProcessFarAlienTargetModule(sbPtr, targetModule); + /* reset the timer */ + alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME; + #else + alienStatusPointer->FarStateTimer = ProcessFarAlienTargetModule(sbPtr, targetModule); + #endif +} + + +/*-----------------------Patrick 9/12/96-------------------------- + Far alien waiting behaviour functions: + Do nothing: when it becomes visible, it will switch to attack, or + near wait and then wander... + ----------------------------------------------------------------*/ +static void Execute_AFS_Wait(STRATEGYBLOCK *sbPtr) +{ + /* do nothing */ + + //#if ULTRAVIOLENCE + /* Look, now there might be no enemies. */ + #if 0 + /* ...I think not. */ + + ALIEN_STATUS_BLOCK *alienStatusPointer; + + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + alienStatusPointer->BehaviourState = ABS_Hunt; + alienStatusPointer->FarStateTimer = 0; /* forces execution of new state next frame*/ + + #endif +} + +static void Execute_AFS_Approach(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + /* For the moment, switch to attack or to hunt. */ + + if (Validate_Target(alienStatusPointer->Target,alienStatusPointer->Target_SBname)==0) { + /* Whoops, no target. */ + //GLOBALASSERT(0); + /* Go back to hunt. */ + alienStatusPointer->BehaviourState = ABS_Hunt; + alienStatusPointer->FarStateTimer = 0; /* forces execution of new state next frame*/ + return; + /* Should check for this in AlienBehaviour. */ + } + + /* See if we're in the same module. */ + + if (alienStatusPointer->Target->containingModule->m_aimodule!=sbPtr->containingModule->m_aimodule) { + /* Go back to hunt. */ + alienStatusPointer->BehaviourState = ABS_Hunt; + alienStatusPointer->FarStateTimer = 0; /* forces execution of new state next frame*/ + } else { + /* Go to attack. */ + alienStatusPointer->BehaviourState = ABS_Attack; + alienStatusPointer->FarStateTimer = 0; /* forces execution of new state next frame*/ + } + +} + +static void Execute_AFS_Attack(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPointer; + + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + /* For the moment, switch to hunt, or smite the target. */ + + if (Validate_Target(alienStatusPointer->Target,alienStatusPointer->Target_SBname)==0) { + /* Whoops, no target. */ + GLOBALASSERT(0); + /* Should check for this in AlienBehaviour. */ + } + + /* See if we're in the same module. */ + + if (alienStatusPointer->Target->containingModule->m_aimodule!=sbPtr->containingModule->m_aimodule) { + /* Go back to hunt. */ + alienStatusPointer->BehaviourState = ABS_Hunt; + alienStatusPointer->FarStateTimer = 0; /* forces execution of new state next frame*/ + } else { + /* Decrement the Far state timer */ + alienStatusPointer->FarStateTimer -= NormalFrameTime; + + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(alienStatusPointer->FarStateTimer>0) return; + + #if 0 + CauseDamageToObject(alienStatusPointer->Target,&TemplateAmmo[AMMO_NPC_ALIEN_CLAW].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + #endif + /* Kersplat. */ + alienStatusPointer->FarStateTimer=ALIEN_ATTACKTIME; + /* Cunning, eh? */ + + } + +} + +static void Execute_AFS_Avoidance(STRATEGYBLOCK *sbPtr) { + + /* No obstacles in far behaviour. */ + ALIEN_STATUS_BLOCK *alienStatusPointer; + + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + Initialise_AvoidanceManager(sbPtr,&alienStatusPointer->avoidanceManager); + + /* Go directly to hunt. Do not pass GO. */ + alienStatusPointer->BehaviourState = ABS_Hunt; + alienStatusPointer->FarStateTimer = 0; /* forces execution of new state next frame*/ + +} + +static void Execute_AFS_Retreat(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + AIMODULE *targetModule = 0; + + /* get the alien's status block */ + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + /* Decrement the Far state timer */ + alienStatusPointer->FarStateTimer -= NormalFrameTime; + + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(alienStatusPointer->FarStateTimer>0) return; + + /* check the alien hive, to see if we've switched to attack: + if so, reset the alien far behaviour state to attack, with the alien far + state timer set to 0, forcing a movement next frame... + NB if we can't attack the player, hunting function will automatically + switch to wander */ + if(NPCHive.currentState == HS_Attack) + { + alienStatusPointer->BehaviourState = ABS_Hunt; + alienStatusPointer->FarStateTimer = 0; /* forces execution of new state next frame*/ + return; + } + + /* get the target module... */ + targetModule = FarNPC_GetTargetAIModuleForRetreat(sbPtr); + + /* if there is no target module, reset the timer and return. */ + if(!targetModule) + { + alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME; + return; + } + + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + + #if 0 + ProcessFarAlienTargetModule(sbPtr, targetModule); + /* reset the timer */ + alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME; + #else + alienStatusPointer->FarStateTimer = ProcessFarAlienTargetModule(sbPtr, targetModule); + #endif +} + +static void Execute_AFS_Wander(STRATEGYBLOCK *sbPtr) +{ + ALIEN_STATUS_BLOCK *alienStatusPointer; + AIMODULE *targetModule = 0; + + /* get the alien's status block */ + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + /* Decrement the Far state timer */ + alienStatusPointer->FarStateTimer -= NormalFrameTime; + + /* check if far state timer has timed-out. If so, it is time + to do something. Otherwise just return. */ + if(alienStatusPointer->FarStateTimer>0) return; + + /* check for state changes: + if hive says retreat, then retreat, regardless of whether or not we can see the player + otherwise, if we can see the player, go to hunt */ + if(NPCHive.currentState == HS_Regroup) + { + alienStatusPointer->BehaviourState = ABS_Retreat; + alienStatusPointer->FarStateTimer = 0; /* forces execution of new state next frame*/ + return; + } + + /* see if we want to switch to attack */ + if(AlienIsAwareOfTarget(sbPtr)) + { + alienStatusPointer->BehaviourState = ABS_Hunt; + alienStatusPointer->FarStateTimer = 0; /* forces execution of new state next frame*/ + return; + } + /* That used to be 100% for ULTRAVIOLENCE. But, + now, there might concievably be NO targets, -> wander. */ + + /* get the target module... */ + targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr,NULL,1); + + /* if there is no target module, reset the timer and return. */ + if(!targetModule) + { + alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME; + return; + } + + /* Examine target, and decide what to do */ + GLOBALASSERT(AIModuleIsPhysical(targetModule)); + + #if 0 + ProcessFarAlienTargetModule(sbPtr, targetModule); + /* reset the timer */ + alienStatusPointer->FarStateTimer = ALIEN_FAR_MOVE_TIME; + #else + alienStatusPointer->FarStateTimer = ProcessFarAlienTargetModule(sbPtr, targetModule); + #endif +} + + + + +/*--------------------Patrick 27/1/97---------------------- + This function is used by the various far alien behaviour + functions to move an alien NPC: it decides whether and how + to move an alien into a given target. + + 2/7/97 extra bit: + If a location fails, we flip the y-orientation of the npc, + so that wandering behaviour can find a new path; + ----------------------------------------------------------*/ +static int ProcessFarAlienTargetModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule) +{ + NPC_TARGETMODULESTATUS targetStatus; + ALIEN_STATUS_BLOCK *alienStatusPointer; + VECTORCH oldPos; + + LOCALASSERT(sbPtr); + LOCALASSERT(targetModule); + LOCALASSERT(sbPtr->I_SBtype == I_BehaviourAlien); + + /* get the alien's status block */ + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPointer); + + oldPos=sbPtr->DynPtr->Position; + + /* get the target module's status, and decide what to do */ + targetStatus = GetTargetAIModuleStatus(sbPtr, targetModule,1); + switch(targetStatus) + { + case(NPCTM_NoEntryPoint): + { + /* do nothing: can't get in. */ + FarNpc_FlipAround(sbPtr); + entryPointFailures++; + break; + } + case(NPCTM_NormalRoom): + { + /* locate to target */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_AirDuct): + { + /* locate to target */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_LiftTeleport): + { + /* do nothing: aliens can't use lifts */ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_ProxDoorOpen): + { + /* locate to target */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_ProxDoorNotOpen): + { + MODULE *renderModule; + renderModule=*(targetModule->m_module_ptrs); + /* trigger the door, and set timer to quick so we can catch the door when it's open */ + ((PROXDOOR_BEHAV_BLOCK *)renderModule->m_sbptr->SBdataptr)->alienTrigger = 1; + break; + } + case(NPCTM_LiftDoorOpen): + { + #if 0 + /* do nothing: don't really want to go into a lift, or we'll get trapped */ + FarNpc_FlipAround(sbPtr); + #else + /* Another pre-written screw up! */ + LocateFarNPCInAIModule(sbPtr, targetModule); + #endif + break; + } + case(NPCTM_LiftDoorNotOpen): + { + /* do nothing - well, there's nothing we can do, really*/ + FarNpc_FlipAround(sbPtr); + break; + } + case(NPCTM_SecurityDoorOpen): + { + /* locate to target */ + LocateFarNPCInAIModule(sbPtr, targetModule); + break; + } + case(NPCTM_SecurityDoorNotOpen): + { + /* do nothing - well, there's nothing we can do, really*/ + FarNpc_FlipAround(sbPtr); + break; + } + default: + { + LOCALASSERT(1==0); + } + } + /* Now, deduce how far it's moved... */ + oldPos.vx-=sbPtr->DynPtr->Position.vx; + oldPos.vy-=sbPtr->DynPtr->Position.vy; + oldPos.vz-=sbPtr->DynPtr->Position.vz; + { + int distance; + + distance=Approximate3dMagnitude(&oldPos); + + if (distance==0) { + return(ALIEN_FAR_MOVE_TIME); + } else { + /* How long? */ + return(DIV_FIXED(distance,(ALIEN_FORWARDVELOCITY>>1))); + } + } + return(ALIEN_FAR_MOVE_TIME); +} + + +/*----------------------------------------------------------------------- + + FUNCTIONS USED BY ALL NPC FAR BEHAVIOUR FUNCTIONS + +-------------------------------------------------------------------------*/ + + +/*--------------------Patrick 27/1/97---------------------- + This function relocates an NPC into a target module. + If the module is visible it uses the entry point. If not + it uses an auxilary location, or the entry point if there + aren't any. + + 2/7/97: added a bit to update the npc orientation when + moving. This orientation is used for wandering behaviour + ----------------------------------------------------------*/ +void LocateFarNPCInModule(STRATEGYBLOCK *sbPtr, MODULE *targetModule) +{ + int noOfAuxLocs; + VECTORCH *auxLocsList; + int noOfEntryPoints; + FARENTRYPOINT *entryPointsList; + FARENTRYPOINT *targetEntryPoint; + VECTORCH newPosition; + + /* a pre-condition... */ + GLOBALASSERT(ModuleIsPhysical(targetModule)); + + /* now: a few tests for npc's that are generated... (aliens and marines) */ + if((sbPtr->I_SBtype==I_BehaviourAlien)||(sbPtr->I_SBtype==I_BehaviourMarine)) + { + if((PherAi_Buf[(targetModule->m_index)]) >= MAX_GENERATORNPCSPERMODULE) + { + /* do nothing (since there are only a few auxilary locs per module) */ + return; + } + + if(ModuleCurrVisArray[(targetModule->m_index)]) + { + /* the target is visible... */ + if(NumGeneratorNPCsVisible() >= MAX_VISIBLEGENERATORNPCS) + { + /* do nothing: there are already enough visible npcs */ + return; + } + } + } + + /* now move the npc to it's target... */ + noOfAuxLocs = FALLP_AuxLocs[(targetModule->m_index)].numLocations; + auxLocsList = FALLP_AuxLocs[(targetModule->m_index)].locationsList; + noOfEntryPoints = FALLP_EntryPoints[(targetModule->m_index)].numEntryPoints; + entryPointsList = FALLP_EntryPoints[(targetModule->m_index)].entryPointsList; + + /* find the entry point for the target */ + LOCALASSERT(sbPtr->containingModule); + targetEntryPoint = GetModuleEP(targetModule,(sbPtr->containingModule)); + LOCALASSERT(targetEntryPoint); + + /* if it's visible, use the entry point. + if it's not visible, use an auxilary location. If there aren't any auxilary + locations, use the entry point. */ + + if(ModuleCurrVisArray[(targetModule->m_index)]) + { + newPosition = targetEntryPoint->position; + } + else + { + /* pick an auxilary location: if there aren't any, use the entry point */ + if(noOfAuxLocs) + { + int targetLocInx; + int npcHeight; + targetLocInx = FastRandom() % noOfAuxLocs; + newPosition = auxLocsList[targetLocInx]; + /* move up 1/2 npc height, plus a bit more(100). this only applies + to auxilary locations, not eps */ + npcHeight = (mainshapelist[sbPtr->shapeIndex]->shapemaxy + - mainshapelist[sbPtr->shapeIndex]->shapeminy)/2; + if(npcHeight>1000) npcHeight = 1000; + newPosition.vy -=(npcHeight + 100); + } + else newPosition = targetEntryPoint->position; + } + + /* now set the alien's new position and current module. + NB this is world position + alien height in y + a little extra in y to make sure */ + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + dynPtr->Position = newPosition; + dynPtr->Position.vx += targetModule->m_world.vx; + dynPtr->Position.vy += targetModule->m_world.vy; + dynPtr->Position.vz += targetModule->m_world.vz; + dynPtr->PrevPosition = dynPtr->Position; + + dynPtr->OrientEuler.EulerX = 0; + dynPtr->OrientEuler.EulerZ = 0; + { + VECTORCH vec; + vec.vx = targetModule->m_world.vx - sbPtr->containingModule->m_world.vx; + vec.vz = targetModule->m_world.vz - sbPtr->containingModule->m_world.vz; + vec.vy = 0; + Normalise(&vec); + dynPtr->OrientEuler.EulerY = ArcTan(vec.vx, vec.vz); + } + } + /* finally, update the alien's module */ + sbPtr->containingModule = targetModule; +} + +void LocateFarNPCInAIModule(STRATEGYBLOCK *sbPtr, AIMODULE *targetModule) +{ + int noOfAuxLocs; + VECTORCH *auxLocsList; + int noOfEntryPoints; + FARENTRYPOINT *entryPointsList; + FARENTRYPOINT *targetEntryPoint; + VECTORCH newPosition; + MODULE *renderModule; + int targetLocInx; + + SCENEMODULE *smptr; + + smptr = Global_ModulePtr[Global_Scene]; + Global_ModuleArrayPtr = smptr->sm_marray; + + /* now: a few tests for npc's that are generated... (aliens and marines) */ + if((sbPtr->I_SBtype==I_BehaviourAlien)||(sbPtr->I_SBtype==I_BehaviourMarine)) + { + if((PherAi_Buf[(targetModule->m_index)]) >= MAX_GENERATORNPCSPERMODULE) + { + /* do nothing (since there are only a few auxilary locs per module) */ + return; + } + + //if(ModuleCurrVisArray[(*(targetModule->m_module_ptrs))->m_index]) + if (AIModuleIsVisible(targetModule)) + { + /* the target is visible... */ + if(NumGeneratorNPCsVisible() >= MAX_VISIBLEGENERATORNPCS) + { + /* do nothing: there are already enough visible npcs */ + return; + } + } + } + + /* now move the npc to it's target... */ + noOfAuxLocs = FALLP_AuxLocs[(targetModule->m_index)].numLocations; + auxLocsList = FALLP_AuxLocs[(targetModule->m_index)].locationsList; + noOfEntryPoints = FALLP_EntryPoints[(targetModule->m_index)].numEntryPoints; + entryPointsList = FALLP_EntryPoints[(targetModule->m_index)].entryPointsList; + + /* find the entry point for the target */ + LOCALASSERT(sbPtr->containingModule); + targetEntryPoint = GetAIModuleEP(targetModule,(sbPtr->containingModule->m_aimodule)); + LOCALASSERT(targetEntryPoint); + + /* if it's visible, use the entry point. + if it's not visible, use an auxilary location. If there aren't any auxilary + locations, use the entry point. */ + + //if(ModuleCurrVisArray[(*(targetModule->m_module_ptrs))->m_index]) + if (AIModuleIsVisible(targetModule)) + { + newPosition = targetEntryPoint->position; + targetLocInx=-1; + } + else + { + /* pick an auxilary location: if there aren't any, use the entry point */ + if(noOfAuxLocs) + { + #if 0 + int npcHeight; + #endif + targetLocInx = FastRandom() % noOfAuxLocs; + newPosition = auxLocsList[targetLocInx]; + /* move up 1/2 npc height, plus a bit more(100). this only applies + to auxilary locations, not eps */ + #if 0 + npcHeight = (mainshapelist[sbPtr->shapeIndex]->shapemaxy + - mainshapelist[sbPtr->shapeIndex]->shapeminy)/2; + if(npcHeight>1000) npcHeight = 1000; + newPosition.vy -=(npcHeight + 100); + #endif + + if(AvP.Network != I_No_Network) + { + //Multiplayer game + //send this new position to the other players + AddNetMsg_FarAlienPosition(sbPtr,targetModule->m_index,targetLocInx,FALSE); + } + } + else { + newPosition = targetEntryPoint->position; + if(AvP.Network != I_No_Network) + { + //Multiplayer game + //send this new position to the other players + AddNetMsg_FarAlienPosition(sbPtr,targetModule->m_index,sbPtr->containingModule->m_aimodule->m_index,TRUE); + } + } + } + + { + VECTORCH temp_Pos; + + temp_Pos.vx=newPosition.vx+targetModule->m_world.vx; + temp_Pos.vy=newPosition.vy+targetModule->m_world.vy; + temp_Pos.vz=newPosition.vz+targetModule->m_world.vz; + + renderModule=ModuleFromPosition(&temp_Pos,sbPtr->containingModule); + if (renderModule==NULL) { + #if 0 + LOGDXFMT(("Right, here comes the assert.\nNoOfAuxLocs %d.\nTargetLocInx %d\n" + ,noOfAuxLocs,targetLocInx)); + if (*(targetModule->m_module_ptrs)) { + LOGDXFMT(("TargetModule %s.\nContainingModule %s.\n",(*(targetModule->m_module_ptrs))->name,sbPtr->containingModule->name)); + } else { + LOGDXFMT(("TargetModule not found.\nContainingModule %s.\n",sbPtr->containingModule->name)); + } + LOGDXFMT(("I really should crash out here.\n")); + + //GLOBALASSERT(renderModule); + NewOnScreenMessage("DODGED A BULLET.\n"); + #endif + return; + } + } + + /* now set the alien's new position and current module. + NB this is world position + alien height in y + a little extra in y to make sure */ + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + dynPtr->Position = newPosition; + dynPtr->Position.vx += targetModule->m_world.vx; + dynPtr->Position.vy += targetModule->m_world.vy; + dynPtr->Position.vz += targetModule->m_world.vz; + dynPtr->PrevPosition = dynPtr->Position; + + dynPtr->OrientEuler.EulerX = 0; + dynPtr->OrientEuler.EulerZ = 0; + { + VECTORCH vec; + vec.vx = targetModule->m_world.vx - sbPtr->containingModule->m_world.vx; + vec.vz = targetModule->m_world.vz - sbPtr->containingModule->m_world.vz; + vec.vy = 0; + Normalise(&vec); + dynPtr->OrientEuler.EulerY = ArcTan(vec.vx, vec.vz); + } + } + /* finally, update the alien's module */ + sbPtr->containingModule = renderModule; + + #if UseLocalAssert + { + VECTORCH localCoords; + MODULE *thisModule = sbPtr->containingModule; + + LOCALASSERT(thisModule); + + localCoords = sbPtr->DynPtr->Position; + localCoords.vx -= thisModule->m_world.vx; + localCoords.vy -= thisModule->m_world.vy; + localCoords.vz -= thisModule->m_world.vz; + + if(PointIsInModule(thisModule, &localCoords)==0) + { + #if (!PSX) + textprint("FAR ALIEN MODULE CONTAINMENT FAILURE \n"); + + LOGDXFMT(("Alien containment failure: alien is in %s, position is %d,%d,%d:\nModule extents are: %d:%d, %d:%d, %d:%d", + thisModule->name,localCoords.vx,localCoords.vy,localCoords.vz, + thisModule->m_maxx,thisModule->m_minx,thisModule->m_maxy,thisModule->m_miny, + thisModule->m_maxz,thisModule->m_minz)); + + LOCALASSERT(1==0); + #endif + } + } + #endif +} + + +/*--------------------Patrick 10/12/96---------------------- + This function returns the status of a passed target + module that an NPC might want to move to. + ----------------------------------------------------------*/ + +NPC_TARGETMODULESTATUS GetTargetAIModuleStatus(STRATEGYBLOCK *sbPtr, AIMODULE *targetModule, int alien) +{ + MODULEDOORTYPE doorStatus; + MODULE *renderModule; + + /* first check for entry point from current module */ + { + FARENTRYPOINT *targetEntryPoint; + targetEntryPoint = GetAIModuleEP(targetModule,(sbPtr->containingModule->m_aimodule)); + + if(targetEntryPoint == (FARENTRYPOINT *)0) return NPCTM_NoEntryPoint; + + if (!alien) { + if (targetEntryPoint->alien_only) { + return NPCTM_NoEntryPoint; + } + } + } + + renderModule=*(targetModule->m_module_ptrs); + + doorStatus = (ModuleIsADoor(renderModule)); + + switch(doorStatus) + { + case(MDT_ProxDoor): + { + if(GetState(renderModule->m_sbptr)) + return NPCTM_ProxDoorOpen; + else + return NPCTM_ProxDoorNotOpen; + + break; + } + + case(MDT_LiftDoor): + { + if(GetState(renderModule->m_sbptr)) + return NPCTM_LiftDoorOpen; + else + return NPCTM_LiftDoorNotOpen; + + break; + } + + case(MDT_SecurityDoor): + { + if(GetState(renderModule->m_sbptr)) + return NPCTM_SecurityDoorOpen; + else + return NPCTM_SecurityDoorNotOpen; + + break; + } + + default: + { + LOCALASSERT(doorStatus==MDT_NotADoor); + } + + } + + /* now check for lift */ + if(sbPtr->I_SBtype == I_BehaviourLift) return NPCTM_LiftTeleport; + + /* check for air duct */ + if(renderModule->m_flags & MODULEFLAG_AIRDUCT) return NPCTM_AirDuct; + + /* at this point, we know it's a room (or stairs) ... */ + return NPCTM_NormalRoom; +} + +/* Patrick 1/7/97----------------------------------------- + A suit of functions for general far NPC use which return a + target module for hunting, wandering, and retreating + ----------------------------------------------------------*/ + +AIMODULE *FarNPC_GetTargetAIModuleForHunt(STRATEGYBLOCK *sbPtr, int alien) +{ + AIMODULE **AdjModuleRefPtr; + int AdjModuleIndex; + unsigned int highestSmell = 0; + AIMODULE* targetModule = (AIMODULE *)0; + + LOCALASSERT(sbPtr); + if(sbPtr->containingModule==NULL) return targetModule; + AdjModuleRefPtr = sbPtr->containingModule->m_aimodule->m_link_ptrs; + + /* check that there is a list of adjacent modules, and that it is not + empty (ie points to zero) */ + if(AdjModuleRefPtr) + { + while(*AdjModuleRefPtr != 0) + { + /* get the index */ + AdjModuleIndex = (*AdjModuleRefPtr)->m_index; + + if (CheckAdjacencyValidity((*AdjModuleRefPtr), sbPtr->containingModule->m_aimodule,alien)) { + /* if this adjacent module's smell value is higher than + the current 'highest smell' record the new module as the + target. */ + if(PherPl_ReadBuf[AdjModuleIndex] > highestSmell) + { + highestSmell = PherPl_ReadBuf[AdjModuleIndex]; + targetModule = *AdjModuleRefPtr; + } + } + /* next adjacent module reference pointer */ + AdjModuleRefPtr++; + } + } + /* Consider my module being the target. */ + if (PherPl_ReadBuf[sbPtr->containingModule->m_aimodule->m_index] > highestSmell) { + targetModule=sbPtr->containingModule->m_aimodule; + } + + return targetModule; +} + +/* Patrick 2/7/96: this function returns a module for wandering to */ +AIMODULE *FarNPC_GetTargetAIModuleForWander(STRATEGYBLOCK *sbPtr, AIMODULE *exception, int alien) +{ + extern int cosine[], sine[]; + + AIMODULE **AdjModuleRefPtr; + DYNAMICSBLOCK *dynPtr; + AIMODULE* targetModule = (AIMODULE *)0; + int bestDirn = -100000; /* lower than the lowest */ + VECTORCH npcDirn; + + /* some checks */ + if(!sbPtr) return targetModule; + if(!sbPtr) return targetModule; + dynPtr = sbPtr->DynPtr; + if(!dynPtr) return targetModule; + + /* get npc 2d directional vector */ + npcDirn.vx = GetSin(dynPtr->OrientEuler.EulerY); + npcDirn.vz = GetCos(dynPtr->OrientEuler.EulerY); + npcDirn.vy = 0; + Normalise(&npcDirn); + + /* init adjacent module pointer */ + AdjModuleRefPtr = sbPtr->containingModule->m_aimodule->m_link_ptrs; + + /* check that there is a list of adjacent modules, and that it is not + empty (ie points to zero) */ + if(AdjModuleRefPtr) + { + while(*AdjModuleRefPtr != 0) + { + AIMODULE *nextAdjModule = *AdjModuleRefPtr; + VECTORCH moduleDirn; + int thisDirn; + + if (CheckAdjacencyValidity((*AdjModuleRefPtr), sbPtr->containingModule->m_aimodule,alien)) { + moduleDirn.vx = nextAdjModule->m_world.vx - sbPtr->containingModule->m_world.vx; + moduleDirn.vz = nextAdjModule->m_world.vz - sbPtr->containingModule->m_world.vz; + moduleDirn.vy = 0; + Normalise(&moduleDirn); + + thisDirn = DotProduct(&npcDirn,&moduleDirn); + if( (thisDirn>bestDirn) && (exception!=nextAdjModule)) + { + targetModule = nextAdjModule; + bestDirn = thisDirn; + } + } + AdjModuleRefPtr++; + } + } + return targetModule; +} + +AIMODULE *FarNPC_GetTargetAIModuleForRetreat(STRATEGYBLOCK *sbPtr) +{ + extern unsigned int PlayerSmell; + + AIMODULE **AdjModuleRefPtr; + AIMODULE* targetModule = (AIMODULE *)0; + unsigned int targetSmell = PlayerSmell + 1; /* should be higher than any smell anywhere this frame */ + unsigned int targetNumAdj = 0; + + LOCALASSERT(sbPtr); + if(sbPtr->containingModule==NULL) return targetModule; + AdjModuleRefPtr = sbPtr->containingModule->m_aimodule->m_link_ptrs; + + /* check that there is a list of adjacent modules, and that it is not + empty (ie points to zero) */ + if(AdjModuleRefPtr) + { + while(*AdjModuleRefPtr != 0) + { + + /* get the index */ + int AdjModuleIndex = (*AdjModuleRefPtr)->m_index; + int AdjModuleSmell = PherPl_ReadBuf[AdjModuleIndex]; + int AdjModuleNumAdjacencies = NumAdjacentModules((*AdjModuleRefPtr)); + + /* if this adjacent module's smell value is lower than + the current 'highest smell' record the new module as the + target. If they're equal, tie-break on number of adjacencies*/ + if( (!targetModule) || + (AdjModuleSmell < targetSmell)|| + ((AdjModuleSmell == targetSmell) && (AdjModuleNumAdjacencies > targetNumAdj)) + ) + { + targetSmell = PherPl_ReadBuf[AdjModuleIndex]; + targetModule = *AdjModuleRefPtr; + targetNumAdj = NumAdjacentModules((*AdjModuleRefPtr)); + } + /* next adjacent module reference pointer */ + AdjModuleRefPtr++; + } + } + return targetModule; +} + +AIMODULE *FarNPC_GetTargetAIModuleForGlobalHunt(STRATEGYBLOCK *sbPtr) +{ + AIMODULE **AdjModuleRefPtr; + int AdjModuleIndex; + unsigned int highestSmell = 0; + AIMODULE* targetModule = (AIMODULE *)0; + + LOCALASSERT(sbPtr); + if(sbPtr->containingModule==NULL) { + return targetModule; + } + AdjModuleRefPtr = sbPtr->containingModule->m_aimodule->m_link_ptrs; + + /* check that there is a list of adjacent modules, and that it is not + empty (ie points to zero) */ + if(AdjModuleRefPtr) + { + while(*AdjModuleRefPtr != 0) + { + /* get the index */ + AdjModuleIndex = (*AdjModuleRefPtr)->m_index; + + /* if this adjacent module's smell value is higher than + the current 'highest smell' record the new module as the + target. */ + if(PherAls_ReadBuf[AdjModuleIndex] > highestSmell) + { + highestSmell = PherAls_ReadBuf[AdjModuleIndex]; + targetModule = *AdjModuleRefPtr; + } + /* next adjacent module reference pointer */ + AdjModuleRefPtr++; + } + } + + if (highestSmellcontainingModule->m_aimodule->m_index]) { + return (sbPtr->containingModule->m_aimodule); + } else { + return (targetModule); + } +} + +/* CDF 28/5/98 */ +AIMODULE *FarNPC_GetTargetAIModuleForMarineRespond(STRATEGYBLOCK *sbPtr) +{ + AIMODULE **AdjModuleRefPtr; + int AdjModuleIndex; + unsigned int highestSmell = 0; + AIMODULE* targetModule = (AIMODULE *)0; + + LOCALASSERT(sbPtr); + if(sbPtr->containingModule==NULL) return targetModule; + AdjModuleRefPtr = sbPtr->containingModule->m_aimodule->m_link_ptrs; + + /* check that there is a list of adjacent modules, and that it is not + empty (ie points to zero) */ + if(AdjModuleRefPtr) + { + while(*AdjModuleRefPtr != 0) + { + /* get the index */ + AdjModuleIndex = (*AdjModuleRefPtr)->m_index; + + if (CheckAdjacencyValidity((*AdjModuleRefPtr), sbPtr->containingModule->m_aimodule,0)) { + /* if this adjacent module's smell value is higher than + the current 'highest smell' record the new module as the + target. */ + if(PherMars_ReadBuf[AdjModuleIndex] > highestSmell) + { + highestSmell = PherMars_ReadBuf[AdjModuleIndex]; + targetModule = *AdjModuleRefPtr; + } + } + /* next adjacent module reference pointer */ + AdjModuleRefPtr++; + } + } + return targetModule; +} + + +/* Patrick 2/7/97: +This function turns the npc around (in y) a random amount: this is used to +turn the npc around if it reaches an impasse in the environment, and the +orientation is used to select a target module for wandering behaviour */ +void FarNpc_FlipAround(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + /* get the dynamics block */ + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + dynPtr->OrientEuler.EulerY += (1024 + FastRandom()%1024); + dynPtr->OrientEuler.EulerY &= wrap360; +} \ No newline at end of file diff --git a/3dc/avp/bh_ldoor.c b/3dc/avp/bh_ldoor.c new file mode 100644 index 0000000..da1d018 --- /dev/null +++ b/3dc/avp/bh_ldoor.c @@ -0,0 +1,327 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" + +#include "weapons.h" +#include "comp_shp.h" +#include "inventry.h" +#include "triggers.h" +#include "mslhand.h" + +#include "dynblock.h" +#include "dynamics.h" + +#define UseLocalAssert Yes + +#include "ourasert.h" + +#include "pmove.h" +#include "pvisible.h" +#include "bh_pred.h" +#include "bh_swdor.h" +#include "bh_ldoor.h" +#include "bh_plift.h" +#include "load_shp.h" +#include "lighting.h" +#include "bh_lnksw.h" +#include "bh_binsw.h" +#include "bh_lift.h" + +#include "psnd.h" +#include "savegame.h" + +#if SupportWindows95 +/* for win95 net game support */ +#include "pldghost.h" +#endif + + +extern int NormalFrameTime; + + +void* LiftDoorBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr) +{ + LIFT_DOOR_BEHAV_BLOCK *doorbhv; + LIFT_DOOR_TOOLS_TEMPLATE *doortt; + MORPHCTRL* morphctrl; + MORPHHEADER* morphheader; + MORPHFRAME* morphframe; + MODULE * my_mod; + + doorbhv = (LIFT_DOOR_BEHAV_BLOCK*)AllocateMem(sizeof(LIFT_DOOR_BEHAV_BLOCK)); + if (!doorbhv) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + + doorbhv->bhvr_type = I_BehaviourLiftDoor; + + // from loaders + + doortt = (LIFT_DOOR_TOOLS_TEMPLATE*)bhdata; + + // Set up a new Morph Control + morphctrl = (MORPHCTRL*)AllocateMem(sizeof(MORPHCTRL)); + if (!morphctrl) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + morphheader = (MORPHHEADER*)AllocateMem(sizeof(MORPHHEADER)); + if (!morphheader) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + morphframe = (MORPHFRAME*)AllocateMem(sizeof(MORPHFRAME)); + if (!morphframe) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + + morphframe->mf_shape1 = doortt->shape_open; + morphframe->mf_shape2 = doortt->shape_closed; + + morphheader->mph_numframes = 1; + morphheader->mph_maxframes = ONE_FIXED; + morphheader->mph_frames = morphframe; + + morphctrl->ObMorphCurrFrame = 0; + morphctrl->ObMorphFlags = 0; + morphctrl->ObMorphSpeed = 0; + morphctrl->ObMorphHeader = morphheader; + + // Copy the name over + COPY_NAME (sbptr->SBname, doortt->nameID); + + // Setup module ref + { + MREF mref=doortt->my_module; + ConvertModuleNameToPointer (&mref, MainSceneArray[0]->sm_marray); + my_mod = mref.mref_ptr; + } + GLOBALASSERT (my_mod); + + my_mod->m_sbptr = sbptr; + sbptr->SBmoptr = my_mod; + sbptr->SBmomptr = my_mod->m_mapptr; + sbptr->SBflags.no_displayblock = 1; + + doorbhv->door_state = doortt->state; + doorbhv->PDmctrl = morphctrl; + doorbhv->door_closing_speed=doortt->door_closing_speed; + doorbhv->door_opening_speed=doortt->door_opening_speed; + + // all lift doors have a closed starting state except the + // one where the lift is - fill in other data + + sbptr->SBmorphctrl = doorbhv->PDmctrl; + + if(doorbhv->door_state == I_door_open) + { + sbptr->SBmorphctrl->ObMorphCurrFrame = 0; + OpenDoor(sbptr->SBmorphctrl, DOOR_OPENFASTSPEED); + } + else + { + GLOBALASSERT(doorbhv->door_state == I_door_closed); + sbptr->SBmorphctrl->ObMorphCurrFrame = 1; + CloseDoor(sbptr->SBmorphctrl, DOOR_CLOSEFASTSPEED); + } + doorbhv->request_state = doorbhv->door_state; + + // copy data into relevant structures + + sbptr->SBmorphctrl = doorbhv->PDmctrl; + + if(sbptr->SBmoptr) + { + sbptr->SBmoptr->m_flags |= m_flag_open; + } + if(sbptr->SBmomptr) + { + sbptr->SBmomptr->MapMorphHeader = sbptr->SBmorphctrl->ObMorphHeader; + } + + + doorbhv->SoundHandle=SOUND_NOACTIVEINDEX; + + return((void*)doorbhv); +} + + +void LiftDoorBehaveFun(STRATEGYBLOCK* sbptr) +{ + LIFT_DOOR_BEHAV_BLOCK *doorbhv; + MORPHCTRL *mctrl; + DISPLAYBLOCK* dptr; + MODULE *mptr; + + GLOBALASSERT(sbptr); + doorbhv = (LIFT_DOOR_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((doorbhv->bhvr_type == I_BehaviourLiftDoor)); + mctrl = doorbhv->PDmctrl; + GLOBALASSERT(mctrl); + mptr = sbptr->SBmoptr; + GLOBALASSERT(mptr); + dptr = sbptr->SBdptr; + + /* update morphing.... */ + UpdateMorphing(mctrl); + + switch(doorbhv->door_state) + { + case I_door_opening: + { + mptr->m_flags |= m_flag_open; + if(mctrl->ObMorphFlags & mph_flag_finished) + { + if (doorbhv->SoundHandle!=SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_DOOREND,"d",&mptr->m_world); + Sound_Stop(doorbhv->SoundHandle); + } + doorbhv->door_state = I_door_open; + } + break; + } + case I_door_closing: + { + if(mctrl->ObMorphFlags & mph_flag_finished) + { + if (doorbhv->SoundHandle!=SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_DOOREND,"d",&mptr->m_world); + Sound_Stop(doorbhv->SoundHandle); + } + doorbhv->door_state = I_door_closed; + mptr->m_flags &= ~m_flag_open; + } + else if(AnythingInMyModule(sbptr->SBmoptr)) + { + if (doorbhv->SoundHandle==SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_DOORSTART,"d",&mptr->m_world); + Sound_Play(SID_DOORMID,"del",&mptr->m_world,&doorbhv->SoundHandle); + } + OpenDoor(mctrl, doorbhv->door_opening_speed); + doorbhv->door_state = I_door_opening; + mptr->m_flags |= m_flag_open; + } + break; + } + case I_door_open: + { + mptr->m_flags |= m_flag_open; + if(doorbhv->request_state == I_door_closed) + { + + if (doorbhv->SoundHandle==SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_DOORSTART,"d",&mptr->m_world); + Sound_Play(SID_DOORMID,"del",&mptr->m_world,&doorbhv->SoundHandle); + } + + CloseDoor(mctrl, doorbhv->door_closing_speed); + doorbhv->door_state = I_door_closing; + } + break; + } + case I_door_closed: + { + mptr->m_flags &= ~m_flag_open; + if(doorbhv->request_state == I_door_open) + { + + if (doorbhv->SoundHandle==SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_DOORSTART,"d",&mptr->m_world); + Sound_Play(SID_DOORMID,"del",&mptr->m_world,&doorbhv->SoundHandle); + } + + OpenDoor(mctrl, doorbhv->door_opening_speed); + doorbhv->door_state = I_door_opening; + mptr->m_flags |= m_flag_open; + } + break; + } + default: + LOCALASSERT(1==0); + } +} + + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +typedef struct lift_door_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + DOOR_STATES door_state; + DOOR_STATES request_state; + + //from the morph control + int ObMorphCurrFrame; + int ObMorphFlags; + int ObMorphSpeed; + +}LIFT_DOOR_SAVE_BLOCK; + +void LoadStrategy_LiftDoor(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + LIFT_DOOR_BEHAV_BLOCK *doorbhv; + LIFT_DOOR_SAVE_BLOCK* block = (LIFT_DOOR_SAVE_BLOCK*) header; + + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(block->header.SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourLiftDoor) return; + + doorbhv = (LIFT_DOOR_BEHAV_BLOCK*)sbPtr->SBdataptr; + + doorbhv->request_state = block->request_state; + doorbhv->door_state = block->door_state; + + + doorbhv->PDmctrl->ObMorphCurrFrame = block->ObMorphCurrFrame; + doorbhv->PDmctrl->ObMorphFlags = block->ObMorphFlags; + doorbhv->PDmctrl->ObMorphSpeed = block->ObMorphSpeed; + + Load_SoundState(&doorbhv->SoundHandle); + +} + +void SaveStrategy_LiftDoor(STRATEGYBLOCK* sbPtr) +{ + LIFT_DOOR_SAVE_BLOCK *block; + LIFT_DOOR_BEHAV_BLOCK *doorbhv ; + + doorbhv = (LIFT_DOOR_BEHAV_BLOCK*)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + block->request_state = doorbhv->request_state; + block->door_state = doorbhv->door_state; + block->ObMorphCurrFrame = doorbhv->PDmctrl->ObMorphCurrFrame; + block->ObMorphFlags = doorbhv->PDmctrl->ObMorphFlags; + block->ObMorphSpeed = doorbhv->PDmctrl->ObMorphSpeed; + + Save_SoundState(&doorbhv->SoundHandle); +} + +/*---------------------------** +** End of loading and saving ** +**---------------------------*/ diff --git a/3dc/avp/bh_ldoor.h b/3dc/avp/bh_ldoor.h new file mode 100644 index 0000000..5a941f6 --- /dev/null +++ b/3dc/avp/bh_ldoor.h @@ -0,0 +1,46 @@ +/******************** LIFT DOORS ********************/ + +/* + lift doors do not have to look at the environment for + triggers. they wait for the controlling lift block to + say open or closed. EXCEPT when the door is open it + will not close if some other object is in its module +*/ + + +typedef struct lift_door_behaviour_type +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + DOOR_STATES door_state; + MORPHCTRL *PDmctrl; + + DOOR_STATES request_state; + + int SoundHandle; + + /*---- Patrick 1/1/97 ----- + added for far ai stratgies + --------------------------*/ + int door_opening_speed; + int door_closing_speed; +} LIFT_DOOR_BEHAV_BLOCK; + + +typedef struct lift_door_tools_template +{ + BOOL state; + MREF my_module; + int shape_open; + int shape_closed; + char nameID[SB_NAME_LENGTH]; + + int door_opening_speed; + int door_closing_speed; +} LIFT_DOOR_TOOLS_TEMPLATE; + + +extern void* LiftDoorBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr); +extern void LiftDoorBehaveFun(STRATEGYBLOCK* sbptr); + + + diff --git a/3dc/avp/bh_lift.c b/3dc/avp/bh_lift.c new file mode 100644 index 0000000..48b2534 --- /dev/null +++ b/3dc/avp/bh_lift.c @@ -0,0 +1,819 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" + +#include "weapons.h" +#include "comp_shp.h" +#include "inventry.h" +#include "triggers.h" +#include "mslhand.h" +#include "huddefs.h" + +#include "dynblock.h" +#include "dynamics.h" + +#define UseLocalAssert Yes + +#include "ourasert.h" + +#include "pmove.h" +#include "pvisible.h" +#include "bh_swdor.h" +#include "load_shp.h" +#include "lighting.h" +#include "bh_lnksw.h" +#include "bh_binsw.h" +#include "bh_lift.h" + +#include "psnd.h" + + +#if SupportWindows95 +/* for win95 net game support */ +#include "pldghost.h" +#endif + +extern int NormalFrameTime; +// stuff for environment changing + +extern void IntegrateNewEnvironment(); +extern int NumActiveBlocks; + +// Globals we are going to export + +int RequestEnvChangeViaLift = 0; +int RequestEnvChangeViaAirlock = 0; + +LIFT_CONTROL_BLOCK EC_Lift_Ctrl; +MODULE Old_Pos_Module; + + + +static void TeleportFloorSwitches(MODULE* dest, MODULE* src, LIFT_CONTROL_BLOCK* liftCtrl); + + + +/*********************** CLOSED TELEPORT LIFTS INIT ***************/ + +void * LiftBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr) +{ + + LIFT_BEHAV_BLOCK *lift_bhv; + LIFT_STATION* lift_stn; + LIFT_TOOLS_TEMPLATE* lift_tt; + MODULE * my_mod; + + GLOBALASSERT(sbptr); + lift_bhv = (LIFT_BEHAV_BLOCK*)AllocateMem(sizeof(LIFT_BEHAV_BLOCK)); + if(!lift_bhv) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + + lift_bhv->bhvr_type = I_BehaviourLift; + + lift_stn = &lift_bhv->lift_station; + lift_tt = (LIFT_TOOLS_TEMPLATE*)bhdata; + + // Copy the name over + COPY_NAME (sbptr->SBname, lift_tt->nameID); + + + // Setup module ref if not external + if (lift_tt->environment == (int)AvP.CurrentEnv) + { + { + MREF mref=lift_tt->my_module; + ConvertModuleNameToPointer (&mref, MainSceneArray[0]->sm_marray); + + my_mod = mref.mref_ptr; + } + GLOBALASSERT (my_mod); + + my_mod->m_sbptr = sbptr; + sbptr->SBmoptr = my_mod; + sbptr->SBmomptr = my_mod->m_mapptr; + sbptr->SBflags.no_displayblock = 1; + } + + // loaded data - first the station + + COPY_NAME(lift_stn->lift_call_switch_name, lift_tt->call_switch_name); + COPY_NAME(lift_stn->lift_door_name, lift_tt->lift_door_name); + COPY_NAME(lift_stn->lift_floor_switch_name, lift_tt->lift_floor_switch_name); + COPY_NAME(lift_stn->my_sb_name, lift_tt->my_module_name); + + lift_stn->env = lift_tt->environment; + lift_stn->num_floor = lift_tt->num_floor; + lift_stn->orient = lift_tt->orient; + + // fill in the rest of the stn data; + + lift_stn->lift_call_switch = NULL; + lift_stn->lift_door = NULL; + lift_stn->lift_floor_switch = NULL; + lift_stn->lift_module = sbptr->SBmoptr; + if(lift_tt->lift_flags & LiftFlag_Here) + lift_stn->starting_station = 1; + else + lift_stn->starting_station = 0; + + lift_stn->called = 0; + + // fill in the behaviour block + + lift_bhv->control_sb = NULL; + lift_bhv->controller = lift_tt->controller; + COPY_NAME(lift_bhv->control_sb_name, lift_tt->control_sb_name); + + if(lift_bhv->controller) + { + LIFT_CONTROL_BLOCK* lcont = AllocateMem(sizeof(LIFT_CONTROL_BLOCK)); + if(!lcont) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + + lift_bhv->lift_control = lcont; + + // fill in the number of floors + + lcont->num_stations = lift_tt->num_stations; + lcont->lift_stations = (LIFT_STATION**)AllocateMem(sizeof(LIFT_STATION*)*lcont->num_stations); + + if(!lcont->lift_stations) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + + //and init that array + { + int i=0; + while(i < lcont->num_stations) + { + *(lcont->lift_stations + i) = NULL; + i++; + } + } + // fill in the rest of the data + + *(lcont->lift_stations + lift_stn->num_floor) = lift_stn; + lcont->dest_station = -1; + lcont->delay_at_floor = 0; + lcont->delay_between_floors = 0; + lcont->motion = I_going_down; + lcont->state = I_ls_waiting; + lcont->curr_station = -1; + lcont->prev_station = -1; + lcont->SoundHandle = SOUND_NOACTIVEINDEX; + + + if(lift_tt->lift_flags & LiftFlag_NoTel) + lcont->floor_switches_fixed=1; + else + lcont->floor_switches_fixed=0; + + } + + + return((void*)lift_bhv); +} + + +/*************************** LIFT CONTROL *****************************/ + +void LiftBehaveFun(STRATEGYBLOCK* sbptr) +{ + LIFT_BEHAV_BLOCK *lift_bhv; + LIFT_CONTROL_BLOCK *lift_ctrl; + LIFT_STATION *curr_stn; + I_AVP_ENVIRONMENTS dest_env; + + GLOBALASSERT(sbptr); + lift_bhv = (LIFT_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((lift_bhv->bhvr_type == I_BehaviourLift)); + + curr_stn = &lift_bhv->lift_station; + GLOBALASSERT(curr_stn); + + lift_ctrl = lift_bhv->lift_control; + + + /* ALL the lift modules have a Strategy block that contains inforamtion + about that particular location. Only one points to the LIFT CONTROL + BLOCK + */ + + /* the lifts will work between envs as well as on the same env + so the control of the doors in the other envs sin't actually set, + but a record of the postion is maintained + */ + + + + if(lift_bhv->controller) + { + + // HACK - RWH - if this is true the data is broken and this fix won't always work + + if(lift_ctrl->curr_station == -1) + lift_ctrl->curr_station = 0; + + switch(lift_ctrl->state) + { + case I_ls_waiting: + { + /*** find dest and set movement direction this is always the + same even if the lift is on a different floor ***/ + int lower_station = -1; + int upper_station = -1; + int i; + LIFT_STATION *lift_stn; + + /**** find the nearest floors selected ****/ + + // search up and down + for(i = lift_ctrl->curr_station; (i >= 0) && (lower_station == -1); i --) + { + lift_stn = lift_ctrl->lift_stations[i]; + + if(lift_stn->called) + upper_station = i; // higher floors have lower nums + } + for(i = lift_ctrl->curr_station; (i < lift_ctrl->num_stations) && (upper_station == -1); i ++) + { + lift_stn = lift_ctrl->lift_stations[i]; + + if(lift_stn->called) + lower_station = i; // lower floors have higher nums + } + + /****** set the destination and the motion direction ****/ + + if(lift_ctrl->motion == I_going_down)// higher nums + { + if(lower_station != -1) + { + lift_ctrl->dest_station = lower_station; + } + else + { + lift_ctrl->dest_station = upper_station; + lift_ctrl->motion =I_going_up; + } + } + else if(lift_ctrl->motion == I_going_up) // lower nums + { + if(upper_station != -1) + { + lift_ctrl->dest_station = upper_station; + } + else + { + lift_ctrl->dest_station = lower_station; + lift_ctrl->motion =I_going_down; + } + } + + // now we have a station to go to, we start the lift in motion + // unless we have just pressed the current floor switch again + + if(lift_ctrl->dest_station == lift_ctrl->curr_station) + { + // we have just called the lift to the same place + lift_ctrl->dest_station = -1; + lift_stn = lift_ctrl->lift_stations[lift_ctrl->curr_station]; + lift_stn->called = 0; + } + else if(lift_ctrl->dest_station != -1) + { + // if there is a dest, set the lift to go + // close current stations + #if PC_E3DEMO + LIFT_STATION* dest_stn = lift_ctrl->lift_stations[lift_ctrl->dest_station]; + #endif + + lift_stn = lift_ctrl->lift_stations[lift_ctrl->curr_station]; + + #if PC_E3DEMO + if(dest_stn->env != AvP.CurrentEnv) + { + // turn off inter env lifts + NewOnScreenMessage(GetTextString(TEXTSTRING_DB_ACCESSDENIED)); + RequestState(dest_stn->lift_floor_switch, 0, 0); + lift_ctrl->dest_station = -1; + dest_stn->called = 0; + } + else + #endif + { + lift_ctrl->prev_station = lift_ctrl->curr_station; + if(lift_stn->lift_door) + { + // no door - must be on another env + RequestState(lift_stn->lift_door, 0, 0); + } + lift_ctrl->state = I_ls_closing_door; + } + } + + break; + } + case I_ls_closing_door: + { + // lift station for the current lift position has to + // have a closed door + + BOOL door_state; + LIFT_STATION *pos_stn = lift_ctrl->lift_stations[lift_ctrl->curr_station]; + MODULE* mptr; + + mptr = pos_stn->lift_module; + + // deal with the fact that the lift is in a different env + + // same env - normal code + // called from us to another env - normal code + // called from another env to us - jump the close door + + if(pos_stn->env != AvP.CurrentEnv) + { + lift_ctrl->state = I_ls_moving; + lift_ctrl->delay_between_floors = LIFT_MOVE_DELAY; + break; + } + + // otherwise run normal code + // close the door before we change state to moving + + door_state = GetState(pos_stn->lift_door); + + if(!door_state) + { + // turn off the current lift position station call switches + // run only when pos_stn is in our own env POSSIBLE BUG - + // lift wont be called to our floor if there is an Alien in it + + if(BadGuyInModuleOrNoPlayer()) + { + lift_ctrl->state = I_ls_opening_door; + lift_ctrl->dest_station = -1; + lift_ctrl->delay_between_floors = -1; + RequestState(pos_stn->lift_door, 1, 0); + } + else + { + + lift_ctrl->state = I_ls_moving; + lift_ctrl->delay_between_floors = LIFT_MOVE_DELAY; + + RequestState(pos_stn->lift_call_switch, 0, 0); + if(pos_stn->lift_floor_switch) + RequestState(pos_stn->lift_floor_switch, 0, 0); + + //what if there is a bad guy in the lift - if there is open the door + //and reset all the switches and stations + + if (lift_ctrl->SoundHandle==SOUND_NOACTIVEINDEX) + { + GLOBALASSERT(mptr); + Sound_Play(SID_LIFT_START,"dh",&mptr->m_world); + Sound_Play(SID_LIFT_LOOP,"delh",&mptr->m_world, &lift_ctrl->SoundHandle); + } + } + + } + break; + } + + case I_ls_moving: + { + int curr_station_num = lift_ctrl->curr_station; + LIFT_STATION *pos_stn = lift_ctrl->lift_stations[lift_ctrl->curr_station]; + MODULE* mptr; + mptr = pos_stn->lift_module; + + + + dest_env = lift_ctrl->lift_stations[lift_ctrl->dest_station]->env; + + lift_ctrl->delay_between_floors -= NormalFrameTime; + + // TRAP CHANGE OF ENVIRONMENT + // we need to trap it here so we don't have the delay + // between floors. However. The trap should make sure it is the nex array pos + + if(AvP.CurrentEnv != dest_env) + { + // have to load an env - can we do it next - is the + // new env the next floor in the array?? + + if(lift_ctrl->motion == I_going_up) + { + curr_station_num --; + } + else + { + curr_station_num ++; + } + lift_ctrl->curr_station=curr_station_num; + if(curr_station_num == lift_ctrl->dest_station) + { + // OKAY chnage Environment VIA LIFT + // we need a copy of our current module pos + // (for the teleport), a copy of the + // SBs in our module and a copy of the lift + // control block + + LIFT_STATION *lift_stn_old; + EC_Lift_Ctrl = *lift_ctrl; + + lift_stn_old = EC_Lift_Ctrl.lift_stations[EC_Lift_Ctrl.prev_station]; + Old_Pos_Module = *lift_stn_old->lift_module; + + InitPreservedSBs(); + PreserveStBlocksInModule(&Old_Pos_Module); + + EC_Lift_Ctrl.curr_station = curr_station_num; + RequestEnvChangeViaLift = 1; + + // we now do the rest of the SBs. before we + // can chack the env - note that NOTHING can move + // into the lift now. + + } + + } + + // else do normal code + + else if((lift_ctrl->delay_between_floors < 0)) + { + if(lift_ctrl->motion == I_going_up) + { + lift_ctrl->curr_station --; + } + else + { + lift_ctrl->curr_station ++; + } + + + + LOCALASSERT(lift_ctrl->curr_station >= 0); + + + + if(lift_ctrl->curr_station == lift_ctrl->dest_station) + { + // at destination + LIFT_STATION *lift_stn_new = lift_ctrl->lift_stations[lift_ctrl->curr_station]; + LIFT_STATION *lift_stn_old = lift_ctrl->lift_stations[lift_ctrl->prev_station]; + MODULE *new_pos, *old_pos; + + new_pos = lift_stn_new->lift_module; + old_pos = lift_stn_old->lift_module; + + lift_ctrl->dest_station = -1; + lift_ctrl->state = I_ls_opening_door; + + /* roxby: i have taken this out - patrick */ + /* GLOBALASSERT(mptr); */ + Sound_Play(SID_LIFT_END,"h"); + Sound_Stop(lift_ctrl->SoundHandle); + + // door open + + RequestState(lift_stn_new->lift_door, 1, 0); + + lift_stn_new->called = 0; + + if(old_pos) + { + // if we don't have an old pos, we must + // be coming from another env + TeleportContents(new_pos, old_pos,lift_ctrl->floor_switches_fixed); + } + } + + else + { + // interrupt monment to stop at new floor + //this should never happen in a seperate env + LIFT_STATION *lift_stn_new = lift_ctrl->lift_stations[lift_ctrl->curr_station]; + LIFT_STATION *lift_stn_old = lift_ctrl->lift_stations[lift_ctrl->prev_station]; + MODULE* old_pos, *new_pos; + // to trap button presses when moving between floors - + // not really ness and it complecates things + old_pos = lift_stn_old->lift_module; + new_pos = lift_stn_new->lift_module; +#if 0 + + if(lift_stn_new->called) + { + lift_ctrl->state = I_ls_opening_door; + RequestState(lift_stn_new->lift_call_switch, 0, 0); + if(lift_stn_new->lift_floor_switch) + RequestState(lift_stn_new->lift_floor_switch, 0, 0); + RequestState(lift_stn_new->lift_door, 1, 0); + + if(old_pos) + { + // if we don't have an old pos, we must + // be coming from another env + TeleportContents(new_pos, old_pos,lift_ctrl->floor_switches_fixed); + } + + lift_stn_new->called = 0; + + } + else +#endif + { + // futher to go - move along now + lift_ctrl->delay_between_floors += LIFT_MOVE_DELAY; + } + } + } + + break; + } + case I_ls_opening_door: + { + LIFT_STATION *lift_stn_new = lift_ctrl->lift_stations[lift_ctrl->curr_station]; + BOOL door_state = GetState(lift_stn_new->lift_door); + + if(door_state) + { + lift_ctrl->state = I_ls_delay_at_floor; + lift_ctrl->delay_at_floor = LIFT_FLOOR_DELAY; + } + break; + } + case I_ls_delay_at_floor: + { + lift_ctrl->delay_at_floor -= NormalFrameTime; + + if(lift_ctrl->delay_at_floor < 0) + { + LIFT_STATION *lift_stn; + + // turn on the floor lights + lift_stn = lift_ctrl->lift_stations[lift_ctrl->curr_station]; + + RequestState(lift_stn->lift_call_switch, 1, 0); + if(lift_stn->lift_floor_switch_name[0] || lift_stn->lift_floor_switch_name[4]) + RequestState(lift_stn->lift_floor_switch, 1, 0); + + + lift_ctrl->state = I_ls_waiting; + lift_ctrl->dest_station = -1; + + } + break; + } + + default: + + GLOBALASSERT(2<1); + } + } + +} + + +// this function reposts anything that would prevent +// The palyer most be in the module and nothing +// else can be + + +BOOL BadGuyInModuleOrNoPlayer() +{ + return(0); +} + + +void TeleportContents(MODULE* new_pos, MODULE* old_pos,BOOL floor_switches_fixed) +{ + // this used within level - find objects in module + // all will have sbs + + int i; + int max_x, min_x, max_y, min_y, max_z, min_z; + int dest_max_x, dest_min_x, dest_max_y, dest_min_y, dest_max_z, dest_min_z; + VECTORCH mod_offset; + + mod_offset.vx = new_pos->m_world.vx - old_pos->m_world.vx; + mod_offset.vy = new_pos->m_world.vy - old_pos->m_world.vy; + mod_offset.vz = new_pos->m_world.vz - old_pos->m_world.vz; + + max_x = old_pos->m_maxx + old_pos->m_world.vx; + min_x = old_pos->m_minx + old_pos->m_world.vx; + max_y = old_pos->m_maxy + old_pos->m_world.vy; + min_y = old_pos->m_miny + old_pos->m_world.vy; + max_z = old_pos->m_maxz + old_pos->m_world.vz; + min_z = old_pos->m_minz + old_pos->m_world.vz; + + dest_max_x = new_pos->m_maxx + new_pos->m_world.vx -200; + dest_min_x = new_pos->m_minx + new_pos->m_world.vx +200; + dest_max_y = new_pos->m_maxy + new_pos->m_world.vy -200; + dest_min_y = new_pos->m_miny + new_pos->m_world.vy +200; + dest_max_z = new_pos->m_maxz + new_pos->m_world.vz -200; + dest_min_z = new_pos->m_minz + new_pos->m_world.vz +200; + + for(i = 0; i < NumActiveStBlocks; i++) + { + VECTORCH obj_world; + STRATEGYBLOCK *sbptr; + DYNAMICSBLOCK *dynptr; + + sbptr = ActiveStBlockList[i]; + + if(!(dynptr = sbptr->DynPtr)) + continue; + + if(floor_switches_fixed) + { + if(sbptr->I_SBtype==I_BehaviourBinarySwitch || sbptr->I_SBtype==I_BehaviourLinkSwitch) + continue; + else if(sbptr->I_SBtype==I_BehaviourInanimateObject && ((INANIMATEOBJECT_STATUSBLOCK*)sbptr->SBdataptr)->typeId==0) + continue; + } + obj_world = dynptr->Position; + + if(obj_world.vx < max_x) + if(obj_world.vx > min_x) + if(obj_world.vz < max_z) + if(obj_world.vz > min_z) + if(obj_world.vy < max_y) + if(obj_world.vy > min_y) + { + + dynptr->Position.vx += mod_offset.vx; + dynptr->Position.vy += mod_offset.vy; + dynptr->Position.vz += mod_offset.vz; + + dynptr->PrevPosition.vx += mod_offset.vx; + dynptr->PrevPosition.vy += mod_offset.vy; + dynptr->PrevPosition.vz += mod_offset.vz; + + //make sure new location is inside destination module + if(!dynptr->IsStatic) + { + if(dynptr->Position.vxPosition.vx=dest_min_x; + if(dynptr->Position.vyPosition.vy=dest_min_y; + if(dynptr->Position.vzPosition.vz=dest_min_z; + if(dynptr->Position.vx>dest_max_x) dynptr->Position.vx=dest_max_x; + if(dynptr->Position.vy>dest_max_y) dynptr->Position.vy=dest_max_y; + if(dynptr->Position.vz>dest_max_z) dynptr->Position.vz=dest_max_z; + + if(dynptr->PrevPosition.vxPrevPosition.vx=dest_min_x; + if(dynptr->PrevPosition.vyPrevPosition.vy=dest_min_y; + if(dynptr->PrevPosition.vzPrevPosition.vz=dest_min_z; + if(dynptr->PrevPosition.vx>dest_max_x) dynptr->PrevPosition.vx=dest_max_x; + if(dynptr->PrevPosition.vy>dest_max_y) dynptr->PrevPosition.vy=dest_max_y; + if(dynptr->PrevPosition.vz>dest_max_z) dynptr->PrevPosition.vz=dest_max_z; + } + + if(sbptr->maintainVisibility) + { + sbptr->containingModule = new_pos; + } + } + } +} + + +void CleanUpLiftControl() +{ + // okay - we have selected a new env AND it is the + // next env in the list - lets go with the load + // we need a copu list of strat blocks that WE DO NOT + // DEALLOCATE the behaviour / dyn blocks for. We then + // reinitialise AFTER these have been inserted into the + + + // ActiveStBlockList + LIFT_STATION *lift_stn = EC_Lift_Ctrl.lift_stations[EC_Lift_Ctrl.dest_station]; + + char dest_mod_name[8]; + MODULE *new_pos_module; + int orient_diff; + + STRATEGYBLOCK* new_loc_sbptr; + + COPY_NAME(dest_mod_name, lift_stn->my_sb_name); + + orient_diff = EC_Lift_Ctrl.lift_stations[EC_Lift_Ctrl.dest_station]->orient + - EC_Lift_Ctrl.lift_stations[EC_Lift_Ctrl.prev_station]->orient; + + + // DESTROYS ALL OUR OLD DATA - ONLY OUR + // COPIES REMAIN + + ChangeEnvironmentToEnv(lift_stn->env); + + IntegrateNewEnvironment(); + + // find where we have teleported to + + new_loc_sbptr = FindSBWithName(dest_mod_name); + GLOBALASSERT(new_loc_sbptr); + new_pos_module = new_loc_sbptr->SBmoptr; + + // teleport the bastrads + TeleportPreservedSBsToNewEnvModule(new_pos_module, &Old_Pos_Module,orient_diff); + AddPreservedSBsToActiveList(); + + // find the new control block anc copy our preserved one in + // need to recalc lift_station_new + + { + LIFT_BEHAV_BLOCK *lift_bhv; + LIFT_CONTROL_BLOCK *lift_ctrl; + LIFT_STATION *lift_stn_new; + + lift_bhv = (LIFT_BEHAV_BLOCK*)new_loc_sbptr->SBdataptr; + GLOBALASSERT((lift_bhv->bhvr_type == I_BehaviourLift)); + + lift_ctrl = lift_bhv->lift_control; + + GLOBALASSERT(lift_ctrl->num_stations == EC_Lift_Ctrl.num_stations); + + // copy over the vital bits + + lift_ctrl->curr_station = EC_Lift_Ctrl.curr_station; + lift_ctrl->prev_station = EC_Lift_Ctrl.prev_station; + lift_ctrl->motion = EC_Lift_Ctrl.motion; + + // and get into the right state + + lift_ctrl->state = I_ls_opening_door; + lift_ctrl->dest_station = -1; + + // and get the periphs into their right states + // get the new lift station + lift_stn_new = lift_ctrl->lift_stations[lift_ctrl->curr_station]; + + //set all the other station switches to off to overdide + // the starting_station init in AssignAllSBNames + + { + int i; + LIFT_STATION *liftStnPtr; + + for(i=0; i < lift_ctrl->num_stations; i++) + { + liftStnPtr = lift_ctrl->lift_stations[i]; + if(liftStnPtr->env == AvP.CurrentEnv) + { + RequestState(liftStnPtr->lift_call_switch, 0, 0); + RequestState(liftStnPtr->lift_floor_switch, 0, 0); + RequestState(liftStnPtr->lift_door, 0, 0); + } + } + } + + // set our current stations periphs into the correct + // state + + + RequestState(lift_stn_new->lift_call_switch, 1, 0); + RequestState(lift_stn_new->lift_floor_switch, 1, 0); + RequestState(lift_stn_new->lift_door, 1, 0); + + TeleportFloorSwitches + ( + lift_stn_new->lift_module, + lift_stn_new->lift_floor_switch->containingModule, + lift_ctrl + ); + + InitPreservedSBs(); + + UpdateWeaponShape(); // so we get the correct shape in the MSL + } +} + + + + + +static void TeleportFloorSwitches +( + MODULE* dest, + MODULE* src, + LIFT_CONTROL_BLOCK * liftCtrl +) +{ + if(dest != src) + { + TeleportContents(dest, src, 0); + } +} \ No newline at end of file diff --git a/3dc/avp/bh_lift.h b/3dc/avp/bh_lift.h new file mode 100644 index 0000000..7e39974 --- /dev/null +++ b/3dc/avp/bh_lift.h @@ -0,0 +1,116 @@ +extern void LiftBehaveFun(STRATEGYBLOCK* sbptr); +extern void * LiftBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr); +extern void CleanUpLiftControl(); + +extern void TeleportContents(MODULE* new_pos, MODULE* old_pos,BOOL floor_switches_fixed); +extern BOOL BadGuyInModule(); + + + + + +/*********************** Lifts **************************/ + + +typedef struct lift_stations +{ + char lift_call_switch_name[SB_NAME_LENGTH]; + STRATEGYBLOCK* lift_call_switch; + char lift_door_name[SB_NAME_LENGTH]; + STRATEGYBLOCK* lift_door; + char lift_floor_switch_name[SB_NAME_LENGTH]; + STRATEGYBLOCK* lift_floor_switch; // the floor switches teleport + BOOL called; + char my_sb_name[SB_NAME_LENGTH]; // only used when envs change + MODULE* lift_module; + I_AVP_ENVIRONMENTS env; // tells us if we need a cd load + int num_floor; // not the floor num but the poition + // in the array + int orient; //the facing of the lift (from 0 to 3) + BOOL starting_station; + + +}LIFT_STATION; + +typedef enum liftmotion{ + + I_going_up, /*** numbers go down (0 at surface **/ + I_going_down, // numbers go up + +}LIFT_MOTION; + + +typedef enum lift_ctrl_states +{ + I_ls_waiting, + I_ls_closing_door, + I_ls_moving, + I_ls_opening_door, + I_ls_delay_at_floor, + +}LIFT_CTRL_STATES; + +#define LIFT_FLOOR_DELAY ONE_FIXED*2 // two secs +#define LIFT_MOVE_DELAY ONE_FIXED*5 // three secs + + +typedef struct lift_control +{ + int num_stations; // num staions for this lift + LIFT_STATION** lift_stations; // array of lift stations for this lift + int dest_station; // -1 when there is no floor + int curr_station; // tells us the lift pos + int prev_station; // where did we come from + int delay_at_floor; // tells us how long to stay at floor + int delay_between_floors; // tells us how long before teleport + LIFT_MOTION motion; + LIFT_CTRL_STATES state; + BOOL floor_switches_fixed; + int SoundHandle; + +} LIFT_CONTROL_BLOCK; + + +typedef struct lift_behaviour +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + char control_sb_name[SB_NAME_LENGTH]; + STRATEGYBLOCK* control_sb; + LIFT_CONTROL_BLOCK* lift_control; + LIFT_STATION lift_station; + int controller; + +} LIFT_BEHAV_BLOCK; + +#define LiftFlag_Here 0x00000001 +#define LiftFlag_Airlock 0x00000002 +#define LiftFlag_NoTel 0x00000004 /*switches aren't teleported*/ + +typedef struct lift_tools_template +{ + // for behaviour block + char control_sb_name[SB_NAME_LENGTH]; + int controller; + + // for control block + int num_stations; + + // for station block + char call_switch_name[SB_NAME_LENGTH]; + char lift_door_name[SB_NAME_LENGTH]; + char lift_floor_switch_name[SB_NAME_LENGTH]; + char my_module_name[SB_NAME_LENGTH]; + int environment; + int num_floor; + int lift_flags; + int orient; + + // for strategy block + MREF my_module; + char nameID[SB_NAME_LENGTH]; + +} LIFT_TOOLS_TEMPLATE; + + +extern int RequestEnvChangeViaLift; +extern int RequestEnvChangeViaAirlock; diff --git a/3dc/avp/bh_light.c b/3dc/avp/bh_light.c new file mode 100644 index 0000000..c38abb7 --- /dev/null +++ b/3dc/avp/bh_light.c @@ -0,0 +1,1150 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "bh_light.h" +#include "dynblock.h" +#include "dynamics.h" +#include "pldghost.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +#include "pvisible.h" +#include "plat_shp.h" +#include "bh_debri.h" +#include "equipmnt.h" + +extern int NormalFrameTime; +void UpdatePlacedLightState(PLACED_LIGHT_BEHAV_BLOCK* pl_bhv,STRATEGYBLOCK* sbPtr); +void UpdatePlacedLightColour(PLACED_LIGHT_BEHAV_BLOCK* pl_bhv); + +void SetTextureAnimationSequence(int shapeindex,TXACTRLBLK* tac,int sequence) +{ + while(tac) + { + tac->tac_sequence=sequence; + tac->tac_txah_s=GetTxAnimHeaderFromShape(tac, shapeindex); + tac=tac->tac_next; + } +} + + +void* InitPlacedLight(void* bhdata,STRATEGYBLOCK *sbPtr) +{ + TOOLS_DATA_PLACEDLIGHT *toolsData = (TOOLS_DATA_PLACEDLIGHT *)bhdata; + PLACED_LIGHT_BEHAV_BLOCK* pl_bhv; + int i; + + LOCALASSERT(sbPtr->I_SBtype == I_BehaviourPlacedLight); + LOCALASSERT(toolsData); + + /* create, initialise and attach a data block */ + pl_bhv = (void *)AllocateMem(sizeof(PLACED_LIGHT_BEHAV_BLOCK)); + if(!pl_bhv) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + pl_bhv->bhvr_type=I_BehaviourPlacedLight; + + sbPtr->SBdataptr = pl_bhv; + + /* these should be loaded */ + + /* set default indestructibility */ + pl_bhv->Indestructable = No; + + + /* Initialise object's stats */ + { + NPC_DATA *NpcData; + + NpcData=GetThisNpcData(I_NPC_DefaultInanimate); + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + + pl_bhv->destruct_target_request=toolsData->destruct_target_request; + for(i=0;idestruct_target_ID[i]=toolsData->destruct_target_ID[i]; + } + pl_bhv->destruct_target_sbptr=0; + + + + pl_bhv->sequence=toolsData->sequence; + pl_bhv->colour_red=toolsData->colour_red; + pl_bhv->colour_green=toolsData->colour_green; + pl_bhv->colour_blue=toolsData->colour_blue; + pl_bhv->colour_diff_red=toolsData->colour_diff_red; + pl_bhv->colour_diff_green=toolsData->colour_diff_green; + pl_bhv->colour_diff_blue=toolsData->colour_diff_blue; + pl_bhv->fade_up_time=toolsData->fade_up_time; + pl_bhv->fade_down_time=toolsData->fade_down_time; + pl_bhv->up_time=toolsData->up_time; + pl_bhv->down_time=toolsData->down_time; + pl_bhv->timer=toolsData->timer; + pl_bhv->flicker_timer=0; + pl_bhv->type=toolsData->type; + pl_bhv->on_off_type=toolsData->on_off_type; + pl_bhv->state=toolsData->state; + pl_bhv->on_off_state=toolsData->on_off_state; + pl_bhv->swap_colour_and_brightness_alterations=toolsData->swap_colour_and_brightness_alterations; + + pl_bhv->on_off_timer=0; + + + sbPtr->SBDamageBlock.Health*=toolsData->integrity; + + if(toolsData->static_light) + { + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); + } + else + { + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_INANIMATE); + } + + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return 0; + } + + + sbPtr->DynPtr->Mass = toolsData->mass; + if (toolsData->integrity > 20) + { + pl_bhv->Indestructable = Yes; + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + } + else if (toolsData->integrity < 1) + { + sbPtr->integrity = 1; // die immediately + } + else + { + sbPtr->integrity = (DEFAULT_OBJECT_INTEGRITY)*(toolsData->integrity); + } + + pl_bhv->has_broken_sequence=1; + pl_bhv->has_corona=0; + + /*check to see if object is animated.*/ + /*also check for corona flag at the same time*/ + { + TXACTRLBLK **pptxactrlblk; + int item_num; + int shape_num = toolsData->shapeIndex; + SHAPEHEADER *shptr = GetShapeData(shape_num); + pptxactrlblk = &pl_bhv->inan_tac; + for(item_num = 0; item_num < shptr->numitems; item_num ++) + { + POLYHEADER *poly = (POLYHEADER*)(shptr->items[item_num]); + LOCALASSERT(poly); + + SetupPolygonFlagAccessForShape(shptr); + + if((Request_PolyFlags((void *)poly)) & iflag_txanim) + { + TXACTRLBLK *pnew_txactrlblk; + + pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK)); + if(pnew_txactrlblk) + { + + pnew_txactrlblk->tac_flags = 0; + pnew_txactrlblk->tac_item = item_num; + pnew_txactrlblk->tac_sequence = 0; + pnew_txactrlblk->tac_node = 0; + pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shape_num, item_num); + pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shape_num); + + *pptxactrlblk = pnew_txactrlblk; + pptxactrlblk = &pnew_txactrlblk->tac_next; + { + //see how many sequences there are + int num_seq=0; + while(pnew_txactrlblk->tac_txarray[num_seq+1])num_seq++; + if(num_seq<3) pl_bhv->has_broken_sequence=0; + GLOBALASSERT(num_seq>=2); + } + + } + else *pptxactrlblk = NULL; + } + + if((Request_PolyFlags((void *)poly)) & iflag_light_corona) + { + int* vertexptr= &poly->Poly1stPt; + int num_verts=0; + + pl_bhv->has_corona=1; + pl_bhv->corona_location.vx=0; + pl_bhv->corona_location.vy=0; + pl_bhv->corona_location.vz=0; + + //take the average of all the points in the polygon + while(*vertexptr!=-1) + { + num_verts++; + AddVector((VECTORCH*)&shptr->points[0][(*vertexptr)*3],&pl_bhv->corona_location); + vertexptr++; + } + pl_bhv->corona_location.vx/=num_verts; + pl_bhv->corona_location.vy/=num_verts; + pl_bhv->corona_location.vz/=num_verts; + } + } + *pptxactrlblk=0; + + pl_bhv->light=toolsData->light; + GLOBALASSERT(pl_bhv->light); + + pl_bhv->light->RedScale=pl_bhv->colour_red; + pl_bhv->light->GreenScale=pl_bhv->colour_green; + pl_bhv->light->BlueScale=pl_bhv->colour_blue; + } + if(!pl_bhv->inan_tac) + { + pl_bhv->has_broken_sequence=0; + } + + SetTextureAnimationSequence(sbPtr->shapeIndex,pl_bhv->inan_tac,pl_bhv->sequence); + + /* Initialise the dynamics block */ + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + GLOBALASSERT(dynPtr); + + dynPtr->PrevPosition = dynPtr->Position = toolsData->position; + dynPtr->OrientEuler = toolsData->orientation; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + } + + /* strategy block initialisation */ + sbPtr->shapeIndex = toolsData->shapeIndex; + for(i=0;iSBname[i] = toolsData->nameID[i]; + + UpdatePlacedLightState(pl_bhv,sbPtr); + + /* these must be initialised for respawning objects in multiplayer game */ + pl_bhv->startingHealth = sbPtr->SBDamageBlock.Health; + pl_bhv->startingArmour = sbPtr->SBDamageBlock.Armour; + + return((void*)pl_bhv); + +} + + + +void PlacedLightBehaviour(STRATEGYBLOCK *sbPtr) +{ + PLACED_LIGHT_BEHAV_BLOCK* pl_bhv = sbPtr->SBdataptr; + LOCALASSERT(pl_bhv); + + if(AvP.Network!=I_No_Network) + { + //If playing a network game with predestroyed lights , get rid of this light + if(netGameData.preDestroyLights) + { + if(sbPtr->maintainVisibility) + { + if (!pl_bhv->Indestructable) + { + KillLightForRespawn(sbPtr); + } + } + } + } + + + if(pl_bhv->inan_tac) + { + DISPLAYBLOCK* dptr = sbPtr->SBdptr; + + /*deal with texture animation*/ + if(dptr) + { + if(!dptr->ObTxAnimCtrlBlks) + { + dptr->ObTxAnimCtrlBlks = pl_bhv->inan_tac; + } + } + } + //if the light is broken , don't do anything else + if(pl_bhv->state==Light_State_Broken) return; + + //update timer if necessary + if(pl_bhv->on_off_state!=Light_OnOff_Off && pl_bhv->on_off_state!=Light_OnOff_On) + { + pl_bhv->on_off_timer+=NormalFrameTime; + + pl_bhv->flicker_timer%=3500; + + pl_bhv->flicker_timer+=NormalFrameTime; + } + else + { + if(pl_bhv->state==Light_State_StrobeUp || + pl_bhv->state==Light_State_StrobeDown || + pl_bhv->state==Light_State_StrobeUpDelay || + pl_bhv->state==Light_State_StrobeDownDelay) + { + pl_bhv->timer+=NormalFrameTime; + } + else if(pl_bhv->state==Light_State_Flicker) + { + pl_bhv->flicker_timer%=1750; + pl_bhv->flicker_timer+=NormalFrameTime; + } + } + + + UpdatePlacedLightState(pl_bhv,sbPtr); + + //if light is near update the colour + if(sbPtr->SBdptr) + { + UpdatePlacedLightColour(pl_bhv); + } + + +} + +void MakePlacedLightNear(STRATEGYBLOCK *sbPtr) +{ + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + PLACED_LIGHT_BEHAV_BLOCK* pl_bhv=(PLACED_LIGHT_BEHAV_BLOCK*) sbPtr->SBdataptr; + GLOBALASSERT(pl_bhv->bhvr_type==I_BehaviourPlacedLight); + + LOCALASSERT(dynPtr); + LOCALASSERT(sbPtr->SBdptr == NULL); + + VisibilityDefaultObjectMap.MapShape = sbPtr->shapeIndex; + tempModule.m_mapptr = &VisibilityDefaultObjectMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 1; + tempModule.m_lightarray = pl_bhv->light; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr = NULL; /* this is important */ + #if SupportWIndows95 + tempModule.name = NULL; /* this is important */ + #endif + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) return; /* cannot create displayblock, so leave object "far" */ + + sbPtr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbPtr; + dPtr->ObMyModule = NULL; + + /* also need to initialise positional information in the new display + block from the existing dynamics block: this necessary because this + function is (usually) called between the dynamics and rendering systems + so it is not initialised by the dynamics system the first time it is + drawn. */ + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + + dPtr->ObFlags3|=ObFlag3_NoLightDot;//so light will light itself + + //update the colour + UpdatePlacedLightColour(pl_bhv); +} + + +void KillLightForRespawn(STRATEGYBLOCK *sbPtr) +{ + PLACED_LIGHT_BEHAV_BLOCK* pl_bhv = sbPtr->SBdataptr; + LOCALASSERT(pl_bhv); + LOCALASSERT(AvP.Network!=I_No_Network); + + /* make the light invisible, and remove it from visibility management */ + sbPtr->maintainVisibility = 0; + if(sbPtr->SBdptr) MakeObjectFar(sbPtr); +} + +void RespawnLight(STRATEGYBLOCK *sbPtr) +{ + PLACED_LIGHT_BEHAV_BLOCK* pl_bhv = sbPtr->SBdataptr; + LOCALASSERT(pl_bhv); + LOCALASSERT(AvP.Network!=I_No_Network); + + if(netGameData.preDestroyLights) + { + //don't restore lights for this type of net game + return; + } + + + if(pl_bhv->state==Light_State_Broken) + { + + sbPtr->maintainVisibility = 1; + //MakeObjectNear(sbPtr); + + /* must respawn health too... */ + sbPtr->SBDamageBlock.Health = pl_bhv->startingHealth; + sbPtr->SBDamageBlock.Armour = pl_bhv->startingArmour; + + //reactivate the light + pl_bhv->sequence=1; + pl_bhv->light->LightBright=pl_bhv->light->LightBrightStore; + + pl_bhv->on_off_state=Light_OnOff_On; + + switch(pl_bhv->type) + { + case Light_Type_Standard : + pl_bhv->state=Light_State_Standard; + break; + + case Light_Type_Strobe : + pl_bhv->state=Light_State_StrobeUpDelay; + break; + + case Light_Type_Flicker : + pl_bhv->state=Light_State_Flicker; + break; + } + + //need to use the on animation sequence again + SetTextureAnimationSequence(sbPtr->shapeIndex,pl_bhv->inan_tac,pl_bhv->sequence); + + UpdatePlacedLightState(pl_bhv,sbPtr); + } + +} + + +/* this global flag is used to distinguish between messages from the host, +and locally caused damage */ +extern int InanimateDamageFromNetHost; + +void PlacedLightIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple) +{ + PLACED_LIGHT_BEHAV_BLOCK* pl_bhv = sbPtr->SBdataptr; + LOCALASSERT(pl_bhv); + + if(pl_bhv->state==Light_State_Broken) return; + #if 1 + + if((AvP.Network==I_Peer)&&(!InanimateDamageFromNetHost)) + { + //add light damaged net message + AddNetMsg_InanimateObjectDamaged(sbPtr,damage,multiple); + return; + } + else if(AvP.Network==I_Host) + { + //add light damaged net message + if(sbPtr->SBDamageBlock.Health <= 0) AddNetMsg_InanimateObjectDestroyed(sbPtr); + } + #endif + + if (!pl_bhv->Indestructable) + { + + if(sbPtr->SBDamageBlock.Health <= 0) + { + //change to broken sequence if it exists. + //otherwise destroy light + pl_bhv->state=Light_State_Broken; + pl_bhv->on_off_state=Light_OnOff_Off; + pl_bhv->sequence=2; + pl_bhv->light->LightBright=0; + + //notify target of destruction + if(pl_bhv->destruct_target_sbptr) + { + RequestState(pl_bhv->destruct_target_sbptr,pl_bhv->destruct_target_request,0); + } + + /* KJL 17:08:44 10/07/98 - Make some sparks */ + if (sbPtr->SBdptr) + { + MakeSprayOfSparks(&sbPtr->SBdptr->ObMat,&sbPtr->SBdptr->ObWorld); + } + + if(pl_bhv->has_broken_sequence) + { + SetTextureAnimationSequence(sbPtr->shapeIndex,pl_bhv->inan_tac,pl_bhv->sequence); + } + else + { + MakeFragments(sbPtr); + + if(AvP.Network==I_No_Network) DestroyAnyStrategyBlock(sbPtr); + else KillLightForRespawn(sbPtr); + } + + } + } +} + +#define LightRequest_AdjustIntegrity 0x00000001 +#define LightRequest_AdjustType_Standard 0x00000002 +#define LightRequest_AdjustType_Strobe 0x00000004 +#define LightRequest_AdjustType_Flicker 0x00000008 +#define LightRequest_SwapUpAndDown 0x00000010 +void SendRequestToPlacedLight(STRATEGYBLOCK* sbptr,BOOL state,int extended_data) +{ + PLACED_LIGHT_BEHAV_BLOCK* pl_bhv = sbptr->SBdataptr; + LOCALASSERT(pl_bhv); + + if(pl_bhv->state==Light_State_Broken) return; + + if(extended_data) + { + if(extended_data & LightRequest_AdjustIntegrity) + { + if(state) + { + int new_integrity=(extended_data>>7)&0xff; + sbptr->SBDamageBlock.Health=(10<integrity = DEFAULT_OBJECT_INTEGRITY*new_integrity; + + if(new_integrity>20) + pl_bhv->Indestructable = Yes; + else + pl_bhv->Indestructable = No; + + if(sbptr->integrity==0) + { + //destroy the light by applying some damage to it + //DAMAGE_PROFILE certainDeath = {0,0,10000,0,0,0}; + PlacedLightIsDamaged(sbptr, &certainDeath, ONE_FIXED); + } + + } + } + if(state) + { + if(extended_data & (LightRequest_AdjustType_Standard|LightRequest_AdjustType_Flicker)) + { + //changing state , try to preserve strobe timer + switch(pl_bhv->state) + { + //lack of break's intended + case Light_State_StrobeUpDelay: + pl_bhv->timer+=pl_bhv->fade_up_time; + + case Light_State_StrobeUp: + pl_bhv->timer+=pl_bhv->down_time; + + case Light_State_StrobeDownDelay: + pl_bhv->timer+=pl_bhv->fade_down_time; + } + } + + if(extended_data & LightRequest_AdjustType_Standard) + { + pl_bhv->type=Light_Type_Standard; + pl_bhv->state=Light_State_Standard; + + } + if(extended_data & LightRequest_AdjustType_Flicker) + { + pl_bhv->type=Light_Type_Flicker; + pl_bhv->state=Light_State_Flicker; + + } + if(extended_data & LightRequest_AdjustType_Strobe) + { + if(pl_bhv->type!=Light_Type_Strobe) + { + pl_bhv->type=Light_Type_Strobe; + pl_bhv->state=Light_State_StrobeDown; + } + } + if(extended_data & LightRequest_SwapUpAndDown) + { + //swap the up and down colours for the light + int temp_red=pl_bhv->colour_red; + int temp_green=pl_bhv->colour_green; + int temp_blue=pl_bhv->colour_blue; + + pl_bhv->colour_red+=pl_bhv->colour_diff_red; + pl_bhv->colour_green+=pl_bhv->colour_diff_green; + pl_bhv->colour_blue+=pl_bhv->colour_diff_blue; + + pl_bhv->colour_diff_red=temp_red-pl_bhv->colour_red; + pl_bhv->colour_diff_blue=temp_blue-pl_bhv->colour_blue; + pl_bhv->colour_diff_green=temp_green-pl_bhv->colour_green; + + } + + } + } + else + { + if(state) //switch light on + { + if(pl_bhv->on_off_state!=Light_OnOff_On) + { + switch(pl_bhv->on_off_type) + { + case Light_OnOff_Type_Fade : + { + switch(pl_bhv->on_off_state) + { + case Light_OnOff_FadeOn : + break; + + case Light_OnOff_FadeOff : + { + //reverse direction of fade + int mult=ONE_FIXED-DIV_FIXED(pl_bhv->on_off_timer,pl_bhv->fade_down_time); + pl_bhv->on_off_timer=MUL_FIXED(mult,pl_bhv->fade_up_time); + pl_bhv->on_off_state=Light_OnOff_FadeOn; + } + break; + + case Light_OnOff_Off : + { + //start to fade up + pl_bhv->on_off_timer=0; + pl_bhv->on_off_state=Light_OnOff_FadeOn; + + + } + break; + + default : + LOCALASSERT(1==0); + break; + } + } + break; + + case Light_OnOff_Type_Standard : + pl_bhv->on_off_state=Light_OnOff_On; + break; + + + case Light_OnOff_Type_Flicker : + if(pl_bhv->on_off_state!=Light_OnOff_Flicker) + { + pl_bhv->on_off_state=Light_OnOff_Flicker; + pl_bhv->on_off_timer=0; + + //light is flickering on , so play the flickering on sound + Sound_Play(SID_LIGHT_FLICKER_ON,"d",&sbptr->DynPtr->Position); + + } + break; + + default : + LOCALASSERT(1==0); + break; + } + + + } + } + else //switch the light off + { + if(pl_bhv->on_off_state!=Light_OnOff_Off) + { + switch(pl_bhv->on_off_type) + { + case Light_OnOff_Type_Fade : + { + switch(pl_bhv->on_off_state) + { + case Light_OnOff_On : + //start to fade down + pl_bhv->on_off_timer=0; + pl_bhv->on_off_state=Light_OnOff_FadeOff; + break; + + case Light_OnOff_FadeOn : + //reverse direction of fade + { + int mult=ONE_FIXED-DIV_FIXED(pl_bhv->on_off_timer,pl_bhv->fade_up_time); + pl_bhv->on_off_timer=MUL_FIXED(mult,pl_bhv->fade_down_time); + pl_bhv->on_off_state=Light_OnOff_FadeOff; + } + break; + + case Light_OnOff_FadeOff : + break; + + + default : + LOCALASSERT(1==0); + break; + } + } + break; + + case Light_OnOff_Type_Standard : + case Light_OnOff_Type_Flicker : + { + pl_bhv->on_off_state=Light_OnOff_Off; + if(!pl_bhv->swap_colour_and_brightness_alterations) + { + pl_bhv->light->LightBright=0; + } + else + { + pl_bhv->light->RedScale=pl_bhv->colour_red+pl_bhv->colour_diff_red; + pl_bhv->light->GreenScale=pl_bhv->colour_green+pl_bhv->colour_diff_green; + pl_bhv->light->BlueScale=pl_bhv->colour_blue+pl_bhv->colour_diff_blue; + } + } + break; + + default : + LOCALASSERT(1==0); + break; + } + } + } + } + + pl_bhv->sequence=(pl_bhv->on_off_state!=Light_OnOff_Off); + + SetTextureAnimationSequence(sbptr->shapeIndex,pl_bhv->inan_tac,pl_bhv->sequence); + +} + + +void UpdatePlacedLightState(PLACED_LIGHT_BEHAV_BLOCK* pl_bhv,STRATEGYBLOCK* sbPtr) +{ + BOOL done=FALSE; + GLOBALASSERT(pl_bhv); + + while(!done) + { + switch(pl_bhv->state) + { + case Light_State_Standard : + case Light_State_Flicker : + case Light_State_Broken : + done=TRUE; + break; + + + case Light_State_StrobeUp : + if(pl_bhv->timer>=pl_bhv->fade_up_time) + { + pl_bhv->timer-=pl_bhv->fade_up_time; + pl_bhv->state=Light_State_StrobeUpDelay; + } + else + { + done=TRUE; + } + break; + + case Light_State_StrobeUpDelay : + if(pl_bhv->timer>=pl_bhv->up_time) + { + pl_bhv->timer-=pl_bhv->up_time; + pl_bhv->state=Light_State_StrobeDown; + } + else + { + done=TRUE; + } + break; + + case Light_State_StrobeDown : + if(pl_bhv->timer>=pl_bhv->fade_down_time) + { + pl_bhv->timer-=pl_bhv->fade_down_time; + pl_bhv->state=Light_State_StrobeDownDelay; + } + else + { + done=TRUE; + } + break; + + case Light_State_StrobeDownDelay : + if(pl_bhv->timer>=pl_bhv->down_time) + { + pl_bhv->timer-=pl_bhv->down_time; + pl_bhv->state=Light_State_StrobeUp; + } + else + { + done=TRUE; + } + break; + + default : + LOCALASSERT(1==0); + done=TRUE; + } + } + + switch(pl_bhv->on_off_state) + { + case Light_OnOff_On : + case Light_OnOff_Off : + break; + + case Light_OnOff_FadeOn : + if(pl_bhv->on_off_timer>= pl_bhv->fade_up_time) + { + pl_bhv->on_off_timer=0; + if(!pl_bhv->swap_colour_and_brightness_alterations) + { + pl_bhv->light->LightBright=pl_bhv->light->LightBrightStore; + } + else + { + pl_bhv->light->RedScale=pl_bhv->colour_red; + pl_bhv->light->GreenScale=pl_bhv->colour_green; + pl_bhv->light->BlueScale=pl_bhv->colour_blue; + } + pl_bhv->on_off_state=Light_OnOff_On; + } + break; + + case Light_OnOff_FadeOff : + if(pl_bhv->on_off_timer>= pl_bhv->fade_down_time) + { + pl_bhv->on_off_timer=0; + if(!pl_bhv->swap_colour_and_brightness_alterations) + { + pl_bhv->light->LightBright=0; + } + else + { + pl_bhv->light->RedScale=pl_bhv->colour_red+pl_bhv->colour_diff_red; + pl_bhv->light->GreenScale=pl_bhv->colour_green+pl_bhv->colour_diff_green; + pl_bhv->light->BlueScale=pl_bhv->colour_blue+pl_bhv->colour_diff_blue; + } + pl_bhv->on_off_state=Light_OnOff_Off; + } + break; + + case Light_OnOff_Flicker : + if(pl_bhv->on_off_timer>2*ONE_FIXED) + { + pl_bhv->on_off_timer=0; + pl_bhv->on_off_state=Light_OnOff_On; + pl_bhv->light->LightBright=pl_bhv->light->LightBrightStore; + } + break; + default : + LOCALASSERT(1==0); + + } + +} + +void UpdatePlacedLightColour(PLACED_LIGHT_BEHAV_BLOCK* pl_bhv) +{ + int mult; + GLOBALASSERT(pl_bhv); + + //first alter colour for stobing lights + switch(pl_bhv->state) + { + case Light_State_Broken : + break; + case Light_State_Standard : + if(pl_bhv->on_off_state!=Light_OnOff_Off) + { + pl_bhv->light->RedScale=pl_bhv->colour_red; + pl_bhv->light->GreenScale=pl_bhv->colour_green; + pl_bhv->light->BlueScale=pl_bhv->colour_blue; + } + break; + + case Light_State_StrobeUpDelay : + if(!pl_bhv->swap_colour_and_brightness_alterations) + { + pl_bhv->light->RedScale=pl_bhv->colour_red; + pl_bhv->light->GreenScale=pl_bhv->colour_green; + pl_bhv->light->BlueScale=pl_bhv->colour_blue; + } + else + { + pl_bhv->light->LightBright=pl_bhv->light->LightBrightStore; + } + break; + + case Light_State_StrobeDownDelay : + if(!pl_bhv->swap_colour_and_brightness_alterations) + { + pl_bhv->light->RedScale=pl_bhv->colour_red+pl_bhv->colour_diff_red; + pl_bhv->light->GreenScale=pl_bhv->colour_green+pl_bhv->colour_diff_green; + pl_bhv->light->BlueScale=pl_bhv->colour_blue+pl_bhv->colour_diff_blue; + } + else + { + pl_bhv->light->LightBright=0; + } + break; + + case Light_State_StrobeUp : + mult=DIV_FIXED(pl_bhv->fade_up_time-pl_bhv->timer,pl_bhv->fade_up_time); + + if(!pl_bhv->swap_colour_and_brightness_alterations) + { + pl_bhv->light->RedScale=pl_bhv->colour_red+MUL_FIXED(pl_bhv->colour_diff_red,mult); + pl_bhv->light->GreenScale=pl_bhv->colour_green+MUL_FIXED(pl_bhv->colour_diff_green,mult); + pl_bhv->light->BlueScale=pl_bhv->colour_blue+MUL_FIXED(pl_bhv->colour_diff_blue,mult); + } + else + { + mult=ONE_FIXED-mult; + pl_bhv->light->LightBright=MUL_FIXED(pl_bhv->light->LightBrightStore,mult); + } + break; + + case Light_State_StrobeDown : + mult=DIV_FIXED(pl_bhv->timer,pl_bhv->fade_down_time); + if(!pl_bhv->swap_colour_and_brightness_alterations) + { + pl_bhv->light->RedScale=pl_bhv->colour_red+MUL_FIXED(pl_bhv->colour_diff_red,mult); + pl_bhv->light->GreenScale=pl_bhv->colour_green+MUL_FIXED(pl_bhv->colour_diff_green,mult); + pl_bhv->light->BlueScale=pl_bhv->colour_blue+MUL_FIXED(pl_bhv->colour_diff_blue,mult); + } + else + { + mult=ONE_FIXED-mult; + pl_bhv->light->LightBright=MUL_FIXED(pl_bhv->light->LightBrightStore,mult); + } + break; + + case Light_State_Flicker : + if(pl_bhv->on_off_state==Light_OnOff_On) + { + if(pl_bhv->flicker_timer>=1750) + { + mult= FastRandom() & 0xffff; + if (!((mult % 24 )>>3)) + { + mult |= 0xa000; + } + else + { + mult &=~ 0xf000; + } + + pl_bhv->light->LightBright=MUL_FIXED(pl_bhv->light->LightBrightStore,mult); + + + } + } + break; + + default : + LOCALASSERT(1==0); + } + + //now alter brightness for switching on/off + switch(pl_bhv->on_off_state) + { + case Light_OnOff_Off : + if(!pl_bhv->swap_colour_and_brightness_alterations) + { + pl_bhv->light->LightBright=0; + } + else + { + pl_bhv->light->RedScale=pl_bhv->colour_red+pl_bhv->colour_diff_red; + pl_bhv->light->GreenScale=pl_bhv->colour_green+pl_bhv->colour_diff_green; + pl_bhv->light->BlueScale=pl_bhv->colour_blue+pl_bhv->colour_diff_blue; + } + break; + + case Light_OnOff_On : + if(pl_bhv->state!=Light_State_Flicker) + { + if(!pl_bhv->swap_colour_and_brightness_alterations) + { + pl_bhv->light->LightBright=pl_bhv->light->LightBrightStore; + } + else + { + pl_bhv->light->RedScale=pl_bhv->colour_red; + pl_bhv->light->GreenScale=pl_bhv->colour_green; + pl_bhv->light->BlueScale=pl_bhv->colour_blue; + } + } + break; + + case Light_OnOff_FadeOn : + mult=DIV_FIXED(pl_bhv->on_off_timer,pl_bhv->fade_up_time); + if(!pl_bhv->swap_colour_and_brightness_alterations) + { + pl_bhv->light->LightBright=MUL_FIXED(pl_bhv->light->LightBrightStore,mult); + } + else + { + mult=ONE_FIXED-mult; + pl_bhv->light->RedScale=pl_bhv->colour_red+MUL_FIXED(pl_bhv->colour_diff_red,mult); + pl_bhv->light->GreenScale=pl_bhv->colour_green+MUL_FIXED(pl_bhv->colour_diff_green,mult); + pl_bhv->light->BlueScale=pl_bhv->colour_blue+MUL_FIXED(pl_bhv->colour_diff_blue,mult); + } + break; + + case Light_OnOff_FadeOff : + mult=DIV_FIXED(pl_bhv->fade_down_time-pl_bhv->on_off_timer,pl_bhv->fade_down_time); + if(!pl_bhv->swap_colour_and_brightness_alterations) + { + pl_bhv->light->LightBright=MUL_FIXED(pl_bhv->light->LightBrightStore,mult); + } + else + { + mult=ONE_FIXED-mult; + pl_bhv->light->RedScale=pl_bhv->colour_red+MUL_FIXED(pl_bhv->colour_diff_red,mult); + pl_bhv->light->GreenScale=pl_bhv->colour_green+MUL_FIXED(pl_bhv->colour_diff_green,mult); + pl_bhv->light->BlueScale=pl_bhv->colour_blue+MUL_FIXED(pl_bhv->colour_diff_blue,mult); + } + break; + + case Light_OnOff_Flicker : + if(pl_bhv->flicker_timer>=3500) + { + mult= FastRandom() & 0xffff; + if (!((mult % 24 )>>3)) + { + mult |= 0xa000; + } + else + { + mult &=~ 0xf000; + } + pl_bhv->light->LightBright=MUL_FIXED(pl_bhv->light->LightBrightStore,mult); + + } + break; + + default : + LOCALASSERT(1==0); + + } +} + + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" + +typedef struct placed_light_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + BOOL Indestructable; + + LIGHT_TYPE type; + + LIGHT_STATE state; + LIGHT_ON_OFF_STATE on_off_state; + int sequence; //texture animation sequence + + int colour_red; //colour for fade up state + int colour_green; + int colour_blue; + int colour_diff_red; //difference from up colour to down colour + int colour_diff_green; + int colour_diff_blue; + + int timer; + int on_off_timer; + int flicker_timer; + + + //strategyblock stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; +}PLACED_LIGHT_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV pl_bhv + +void LoadStrategy_PlacedLight(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + PLACED_LIGHT_BEHAV_BLOCK* pl_bhv; + PLACED_LIGHT_SAVE_BLOCK* block = (PLACED_LIGHT_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourPlacedLight) return; + + pl_bhv = sbPtr->SBdataptr; + + //start copying stuff + + COPYELEMENT_LOAD(Indestructable); + COPYELEMENT_LOAD(type); + COPYELEMENT_LOAD(state); + COPYELEMENT_LOAD(on_off_state); + COPYELEMENT_LOAD(sequence); //texture animation sequence + COPYELEMENT_LOAD(colour_red); //colour for fade up state + COPYELEMENT_LOAD(colour_green); + COPYELEMENT_LOAD(colour_blue); + COPYELEMENT_LOAD(colour_diff_red); //difference from up colour to down colour + COPYELEMENT_LOAD(colour_diff_green); + COPYELEMENT_LOAD(colour_diff_blue); + COPYELEMENT_LOAD(timer); + COPYELEMENT_LOAD(on_off_timer); + COPYELEMENT_LOAD(flicker_timer); + + + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + + SetTextureAnimationSequence(sbPtr->shapeIndex,pl_bhv->inan_tac,pl_bhv->sequence); + UpdatePlacedLightColour(pl_bhv); + +} + +void SaveStrategy_PlacedLight(STRATEGYBLOCK* sbPtr) +{ + PLACED_LIGHT_SAVE_BLOCK *block; + PLACED_LIGHT_BEHAV_BLOCK* pl_bhv; + + pl_bhv = sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + COPYELEMENT_SAVE(Indestructable); + COPYELEMENT_SAVE(type); + COPYELEMENT_SAVE(state); + COPYELEMENT_SAVE(on_off_state); + COPYELEMENT_SAVE(sequence); //texture animation sequence + COPYELEMENT_SAVE(colour_red); //colour for fade up state + COPYELEMENT_SAVE(colour_green); + COPYELEMENT_SAVE(colour_blue); + COPYELEMENT_SAVE(colour_diff_red); //difference from up colour to down colour + COPYELEMENT_SAVE(colour_diff_green); + COPYELEMENT_SAVE(colour_diff_blue); + COPYELEMENT_SAVE(timer); + COPYELEMENT_SAVE(on_off_timer); + COPYELEMENT_SAVE(flicker_timer); + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; + +} \ No newline at end of file diff --git a/3dc/avp/bh_light.h b/3dc/avp/bh_light.h new file mode 100644 index 0000000..40fef9c --- /dev/null +++ b/3dc/avp/bh_light.h @@ -0,0 +1,141 @@ +typedef enum light_state +{ + Light_State_Standard, + Light_State_Broken, + Light_State_StrobeUp, + Light_State_StrobeDown, + Light_State_StrobeUpDelay, + Light_State_StrobeDownDelay, + Light_State_Flicker, + +}LIGHT_STATE; + +typedef enum light_on_off_state +{ + Light_OnOff_Off, + Light_OnOff_On, + Light_OnOff_FadeOff, + Light_OnOff_FadeOn, + Light_OnOff_Flicker, + +}LIGHT_ON_OFF_STATE; + +typedef enum light_type +{ + Light_Type_Standard, + Light_Type_Strobe, + Light_Type_Flicker, +}LIGHT_TYPE; + +typedef enum light_on_off_type +{ + Light_OnOff_Type_Standard, + Light_OnOff_Type_Fade, + Light_OnOff_Type_Flicker, +}LIGHT_ON_OFF_TYPE; + + +typedef struct placed_light_behav_block +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + BOOL Indestructable; + + TXACTRLBLK *inan_tac;//for lights with anims on them + + LIGHTBLOCK* light; + + LIGHT_STATE state; + LIGHT_ON_OFF_STATE on_off_state; + int sequence; //texture animation sequence + + int colour_red; //colour for fade up state + int colour_green; + int colour_blue; + int colour_diff_red; //difference from up colour to down colour + int colour_diff_green; + int colour_diff_blue; + + int fade_up_time; + int fade_down_time; + int up_time; + int down_time; + + int timer; + int on_off_timer; + int flicker_timer; + + LIGHT_TYPE type; + LIGHT_ON_OFF_TYPE on_off_type; + + int destruct_target_request; + char destruct_target_ID[SB_NAME_LENGTH]; + STRATEGYBLOCK* destruct_target_sbptr; + + VECTORCH corona_location; + + int startingHealth; //for network games + int startingArmour; + + int has_broken_sequence:1; //is there a third texture sequence + int has_corona:1; + int swap_colour_and_brightness_alterations:1; + +}PLACED_LIGHT_BEHAV_BLOCK; + +typedef struct toolsdata_placed_light +{ + struct vectorch position; + struct euler orientation; + int shapeIndex; /* for john */ + char nameID[SB_NAME_LENGTH]; + + int mass; // Kilos?? + int integrity; // 0-20 (>20 = indestructable) + + LIGHTBLOCK* light; + + unsigned int static_light:1; + + int sequence; + + int colour_red; + int colour_green; + int colour_blue; + int colour_diff_red; + int colour_diff_green; + int colour_diff_blue; + + int fade_up_time; + int fade_down_time; + int up_time; + int down_time; + + int timer; + + + LIGHT_STATE state; + LIGHT_ON_OFF_STATE on_off_state; + LIGHT_TYPE type; + LIGHT_ON_OFF_TYPE on_off_type; + + int destruct_target_request; + char destruct_target_ID[SB_NAME_LENGTH]; + int swap_colour_and_brightness_alterations:1; + +}TOOLS_DATA_PLACEDLIGHT; + + + + + +void* InitPlacedLight(void* bhdata,STRATEGYBLOCK *sbPtr); +void PlacedLightBehaviour(STRATEGYBLOCK *sbPtr); + +void MakePlacedLightNear(STRATEGYBLOCK *sbPtr); + +void PlacedLightIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple); + +void SendRequestToPlacedLight(STRATEGYBLOCK* sbptr,BOOL state,int extended_data); + +void RespawnLight(STRATEGYBLOCK *sbPtr); +void KillLightForRespawn(STRATEGYBLOCK *sbPtr); diff --git a/3dc/avp/bh_ltfx.c b/3dc/avp/bh_ltfx.c new file mode 100644 index 0000000..c4af004 --- /dev/null +++ b/3dc/avp/bh_ltfx.c @@ -0,0 +1,643 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" + +#include "dynblock.h" +#include "dynamics.h" + +#define UseLocalAssert Yes + +#include "ourasert.h" + +#include "bh_ltfx.h" + +extern int NormalFrameTime; + + +#if PSX + +void * LightFXBehaveInit (void * bhdata, STRATEGYBLOCK* sbptr) +{ + +} +void LightFXBehaveFun (STRATEGYBLOCK* sbptr) +{ + +} + +#else + +void * LightFXBehaveInit (void * bhdata, STRATEGYBLOCK* sbptr) +{ + LIGHT_FX_BEHAV_BLOCK * lfxbb; + LIGHT_FX_TOOLS_TEMPLATE * lfxtt; + MODULE * my_mod; + + GLOBALASSERT(sbptr); + + lfxbb = (LIGHT_FX_BEHAV_BLOCK *)AllocateMem(sizeof(LIGHT_FX_BEHAV_BLOCK)); + if (!lfxbb) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + + lfxtt = (LIGHT_FX_TOOLS_TEMPLATE *)bhdata; + + COPY_NAME (sbptr->SBname, lfxtt->nameID); + lfxbb->bhvr_type = I_BehaviourLightFX; + + // Setup module ref + { + MREF mref=lfxtt->my_module; + ConvertModuleNameToPointer (&mref, MainSceneArray[0]->sm_marray); + my_mod = mref.mref_ptr; + } + my_mod->m_sbptr = sbptr; + sbptr->SBmoptr = my_mod; + sbptr->SBmomptr = my_mod->m_mapptr; + sbptr->SBflags.no_displayblock = 1; + + GLOBALASSERT (my_mod); + + lfxbb->type = lfxtt->light_data.type; + lfxbb->current_state = lfxtt->light_data.init_state; + + lfxbb->fade_up_speed = lfxtt->light_data.fade_up_speed; + lfxbb->fade_down_speed = lfxtt->light_data.fade_down_speed; + + lfxbb->post_fade_up_delay = lfxtt->light_data.post_fade_up_delay; + lfxbb->post_fade_down_delay = lfxtt->light_data.post_fade_down_delay; + + if (lfxbb->fade_up_speed == 0) + lfxbb->fade_up_speed = 10; + + if (lfxbb->fade_down_speed == 0) + lfxbb->fade_down_speed = 10; + + if (lfxbb->post_fade_up_delay == 0) + lfxbb->post_fade_up_delay = 10; + + if (lfxbb->post_fade_down_delay == 0) + lfxbb->post_fade_down_delay = 10; + + lfxbb->fade_up_speed_multiplier = DIV_FIXED (ONE_FIXED, lfxbb->fade_up_speed); + lfxbb->fade_down_speed_multiplier = DIV_FIXED (ONE_FIXED, lfxbb->fade_down_speed); + + lfxbb->post_fade_up_delay_multiplier = DIV_FIXED (ONE_FIXED, lfxbb->post_fade_up_delay); + lfxbb->post_fade_down_delay_multiplier = DIV_FIXED (ONE_FIXED, lfxbb->post_fade_down_delay); + + switch (lfxbb->type) + { + case LFX_Strobe: + case LFX_Switch: + case LFX_FlickySwitch: + { + switch (lfxbb->current_state) + { + case LFXS_LightOn: + { + lfxbb->multiplier = ONE_FIXED; + lfxbb->timer = 0; + lfxbb->timer2 = 0; + break; + } + + case LFXS_LightOff: + { + lfxbb->multiplier = 0; + lfxbb->timer = 0; + lfxbb->timer2 = 0; + break; + } + + default: + { + lfxbb->multiplier = ONE_FIXED; + lfxbb->timer = 0; + lfxbb->timer2 = 0; + break; + } + } + break; + } + + case LFX_RandomFlicker: + { + lfxbb->current_state = LFXS_Flicking; + lfxbb->multiplier = ONE_FIXED; + lfxbb->timer = 0; + lfxbb->timer2 = 0; + lfxbb->time_to_next_flicker_state = 0; + break; + } + + default: + { + lfxbb->multiplier = ONE_FIXED; + lfxbb->timer = 0; + lfxbb->timer2 = 0; + lfxbb->time_to_next_flicker_state = 0; + break; + } + } + + /* see if this module has a texture animation*/ + { + TXACTRLBLK **pptxactrlblk; + int item_num; + int shape_num=sbptr->shapeIndex; + SHAPEHEADER *shptr = GetShapeData(shape_num); + + pptxactrlblk = &lfxbb->anim_control; + + for(item_num = 0; item_num < shptr->numitems; item_num ++) + { + POLYHEADER *poly = (POLYHEADER*)(shptr->items[item_num]); + LOCALASSERT(poly); + + if((Request_PolyFlags((void *)poly)) & iflag_txanim) + { + TXACTRLBLK *pnew_txactrlblk; + + pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK)); + if (pnew_txactrlblk) + { + pnew_txactrlblk->tac_flags = 0; + pnew_txactrlblk->tac_item = item_num; + pnew_txactrlblk->tac_sequence = 0; + pnew_txactrlblk->tac_node = 0; + pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shape_num, item_num); + pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shape_num); + + + /* change the value held in pptxactrlblk + which point to the previous structures "next" + pointer*/ + + *pptxactrlblk = pnew_txactrlblk; + pptxactrlblk = &pnew_txactrlblk->tac_next; + } + else + { + memoryInitialisationFailure = 1; + } + } + } + *pptxactrlblk=0; + + } + + return((void*)lfxbb); +} + +void LightFXBehaveFun (STRATEGYBLOCK* sbptr) +{ + LIGHT_FX_BEHAV_BLOCK * lfxbb; + DISPLAYBLOCK* dptr; + MODULE *mptr; + + GLOBALASSERT(sbptr); + + mptr = sbptr->SBmoptr; + dptr = sbptr->SBdptr; + + lfxbb = (LIGHT_FX_BEHAV_BLOCK *)sbptr->SBdataptr; + GLOBALASSERT((lfxbb->bhvr_type == I_BehaviourLightFX)); + + /*deal with any texture animation*/ + if(lfxbb->anim_control) + { + if(dptr) + { + if(!dptr->ObTxAnimCtrlBlks) + { + dptr->ObTxAnimCtrlBlks = lfxbb->anim_control; + } + } + } + + /*now update the lighting effects*/ + switch (lfxbb->type) + { + case LFX_RandomFlicker: + { + if (dptr) + { + switch (lfxbb->current_state) + { + case LFXS_Flicking: + { + + lfxbb->time_to_next_flicker_state -= NormalFrameTime; + + if (lfxbb->time_to_next_flicker_state < 0 && 0) + { + int j; + lfxbb->multiplier = FastRandom() & 65535; + + lfxbb->current_state = LFXS_NotFlicking; + + lfxbb->time_to_next_flicker_state = ((FastRandom() & 65535)); + + lfxbb->multiplier &= ~0xf000; + + for (j=0; jObNumLights; j++) + { + LIGHTBLOCK * lp = dptr->ObLights[j]; + if (!(lp->LightFlags & LFlag_PreLitSource)) + { + lp->LightBright = MUL_FIXED (lp->LightBrightStore, lfxbb->multiplier); + } + } + lfxbb->timer = 0; + } + else + { + lfxbb->timer += NormalFrameTime; + if (lfxbb->timer > 1750) + { + int j; + lfxbb->multiplier = FastRandom() & 65535; + if (!((lfxbb->multiplier % 24 )>>3)) + { + lfxbb->multiplier |= 0xa000; + } + else + { + lfxbb->multiplier &= ~0xf000; + } + + for (j=0; jObNumLights; j++) + { + LIGHTBLOCK * lp = dptr->ObLights[j]; + if (!(lp->LightFlags & LFlag_PreLitSource)) + { + lp->LightBright = MUL_FIXED (lp->LightBrightStore, lfxbb->multiplier); + } + } + lfxbb->timer = 0; + } + + } + + break; + } + + case LFXS_NotFlicking: + { + lfxbb->time_to_next_flicker_state -= NormalFrameTime; + if (lfxbb->time_to_next_flicker_state < 0) + { + lfxbb->current_state = LFXS_Flicking; + lfxbb->time_to_next_flicker_state = FastRandom() & 65535; + } + + break; + } + + case LFXS_LightOff : + { + int j; + for (j=0; jObNumLights; j++) + { + LIGHTBLOCK * lp = dptr->ObLights[j]; + if (!(lp->LightFlags & LFlag_PreLitSource)) + { + lp->LightBright = 0; + } + } + break; + } + + default: + { + break; + } + } + + + } + break; + } + + case LFX_Strobe: + { + switch (lfxbb->current_state) + { + case LFXS_LightOn: + { + lfxbb->timer += MUL_FIXED (NormalFrameTime, lfxbb->post_fade_up_delay_multiplier); + if (lfxbb->timer > ONE_FIXED) + { + lfxbb->current_state = LFXS_LightFadingDown; + lfxbb->timer = 0; + } + break; + } + + case LFXS_LightOff: + { + lfxbb->timer += MUL_FIXED (NormalFrameTime, lfxbb->post_fade_down_delay_multiplier); + if (lfxbb->timer > ONE_FIXED) + { + lfxbb->current_state = LFXS_LightFadingUp; + lfxbb->timer = 0; + } + break; + } + + case LFXS_LightFadingUp: + { + int diff = MUL_FIXED (NormalFrameTime, lfxbb->fade_up_speed_multiplier); + lfxbb->timer += diff; + lfxbb->multiplier += diff; + if (lfxbb->timer > ONE_FIXED) + { + lfxbb->current_state = LFXS_LightOn; + lfxbb->timer = 0; + lfxbb->multiplier = 65536; + } + break; + } + + case LFXS_LightFadingDown: + { + int diff = MUL_FIXED (NormalFrameTime, lfxbb->fade_down_speed_multiplier); + lfxbb->timer += diff; + lfxbb->multiplier -= diff; + if (lfxbb->timer > ONE_FIXED) + { + lfxbb->current_state = LFXS_LightOff; + lfxbb->timer = 0; + lfxbb->multiplier = 0; + } + break; + } + + default: + { + GLOBALASSERT (0 == "Light FX state not supported"); + break; + } + } + + if (dptr) + { + int j; + for (j=0; jObNumLights; j++) + { + LIGHTBLOCK * lp = dptr->ObLights[j]; + if (!(lp->LightFlags & LFlag_PreLitSource)) + { + lp->LightBright = MUL_FIXED (lp->LightBrightStore, lfxbb->multiplier); + } + } + + } + + break; + } + + case LFX_Switch: + { + switch (lfxbb->current_state) + { + case LFXS_LightFadingUp: + { + int diff = MUL_FIXED (NormalFrameTime, lfxbb->fade_up_speed_multiplier); + lfxbb->timer += diff; + lfxbb->multiplier += diff; + + if (lfxbb->timer > ONE_FIXED) + { + lfxbb->current_state = LFXS_LightOn; + lfxbb->timer = 0; + lfxbb->multiplier = 65536; + } + break; + } + + case LFXS_LightFadingDown: + { + int diff = MUL_FIXED (NormalFrameTime, lfxbb->fade_down_speed_multiplier); + lfxbb->timer += diff; + lfxbb->multiplier -= diff; + if (lfxbb->timer > ONE_FIXED) + { + lfxbb->current_state = LFXS_LightOff; + lfxbb->timer = 0; + lfxbb->multiplier = 0; + } + break; + } + + case LFXS_LightOn: + case LFXS_LightOff: + { + break; + } + + default: + { + GLOBALASSERT (0 == "Light FX state not supported"); + break; + } + + } + + if (dptr) + { + int j; + for (j=0; jObNumLights; j++) + { + LIGHTBLOCK * lp = dptr->ObLights[j]; + if (!(lp->LightFlags & LFlag_PreLitSource)) + { + lp->LightBright = MUL_FIXED (lp->LightBrightStore, lfxbb->multiplier); + } + } + + } + + break; + } + + case LFX_FlickySwitch: + { + switch (lfxbb->current_state) + { + case LFXS_LightFadingUp: + { + int diff = MUL_FIXED (NormalFrameTime, lfxbb->fade_up_speed_multiplier); + + lfxbb->timer += diff; + + + lfxbb->timer2 += NormalFrameTime; + if (lfxbb->timer2 > 3553) + { + lfxbb->multiplier = FastRandom() & 65535; + if (!((lfxbb->multiplier % 24 )>>3)) + { + lfxbb->multiplier |= 0xa000; + } + else + { + lfxbb->multiplier &= ~0xf000; + } + + lfxbb->timer2 = 0; + } + + if (lfxbb->timer > ONE_FIXED) + { + lfxbb->current_state = LFXS_LightOn; + lfxbb->timer = 0; + lfxbb->multiplier = 65536; + } + break; + } + + case LFXS_LightFadingDown: + { + int diff = MUL_FIXED (NormalFrameTime, lfxbb->fade_down_speed_multiplier); + lfxbb->timer += diff; + lfxbb->multiplier -= diff; + if (lfxbb->timer > ONE_FIXED) + { + lfxbb->current_state = LFXS_LightOff; + lfxbb->timer = 0; + lfxbb->multiplier = 0; + } + break; + } + + case LFXS_LightOn: + case LFXS_LightOff: + { + break; + } + + default: + { + GLOBALASSERT (0 == "Light FX state not supported"); + break; + } + + } + + if (dptr) + { + int j; + for (j=0; jObNumLights; j++) + { + LIGHTBLOCK * lp = dptr->ObLights[j]; + if (!(lp->LightFlags & LFlag_PreLitSource)) + { + lp->LightBright = MUL_FIXED (lp->LightBrightStore, lfxbb->multiplier); + } + } + + } + + break; + } + + default: + { + GLOBALASSERT (0 == "Light FX type not supported"); + break; + } + } +} + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" +typedef struct light_fx_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + LIGHT_FX_STATE current_state; + signed long multiplier; + unsigned long timer; + unsigned long timer2; + signed long time_to_next_flicker_state; + +}LIGHT_FX_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV lfxbb + +void LoadStrategy_LightFx(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + LIGHT_FX_BEHAV_BLOCK * lfxbb; + LIGHT_FX_SAVE_BLOCK* block = (LIGHT_FX_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourLightFX) return; + + lfxbb = (LIGHT_FX_BEHAV_BLOCK *)sbPtr->SBdataptr; + + //start copying stuff + + COPYELEMENT_LOAD(current_state) + COPYELEMENT_LOAD(multiplier) + COPYELEMENT_LOAD(timer) + COPYELEMENT_LOAD(timer2) + COPYELEMENT_LOAD(time_to_next_flicker_state) + + + //update the brightness of the lights + { + DISPLAYBLOCK* dptr = sbPtr->SBdptr;; + if(dptr) + { + //I'm not sure that we will ever have a displayblock at this point, anyway. hmm. + int j; + for (j=0; jObNumLights; j++) + { + LIGHTBLOCK * lp = dptr->ObLights[j]; + if (!(lp->LightFlags & LFlag_PreLitSource)) + { + lp->LightBright = MUL_FIXED (lp->LightBrightStore, lfxbb->multiplier); + } + } + } + } + + +} + +void SaveStrategy_LightFx(STRATEGYBLOCK* sbPtr) +{ + LIGHT_FX_SAVE_BLOCK *block; + LIGHT_FX_BEHAV_BLOCK * lfxbb; + + lfxbb = (LIGHT_FX_BEHAV_BLOCK *)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + + COPYELEMENT_SAVE(current_state) + COPYELEMENT_SAVE(multiplier) + COPYELEMENT_SAVE(timer) + COPYELEMENT_SAVE(timer2) + COPYELEMENT_SAVE(time_to_next_flicker_state) +} +#endif \ No newline at end of file diff --git a/3dc/avp/bh_ltfx.h b/3dc/avp/bh_ltfx.h new file mode 100644 index 0000000..e7f2e6c --- /dev/null +++ b/3dc/avp/bh_ltfx.h @@ -0,0 +1,49 @@ +#ifndef _bh_ltfx_h +#define _bh_ltfx_h 1 + +#include "ltfx_exp.h" + + +typedef struct light_fx_behav_block +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + + LIGHT_FX_TYPE type; + LIGHT_FX_STATE current_state; + + unsigned long fade_up_speed; + unsigned long fade_down_speed; + + unsigned long post_fade_up_delay; + unsigned long post_fade_down_delay; + + unsigned long fade_up_speed_multiplier; + unsigned long fade_down_speed_multiplier; + + unsigned long post_fade_up_delay_multiplier; + unsigned long post_fade_down_delay_multiplier; + + signed long multiplier; + unsigned long timer; + unsigned long timer2; + + signed long time_to_next_flicker_state; + + TXACTRLBLK *anim_control; +} LIGHT_FX_BEHAV_BLOCK; + +typedef struct light_fx_tools_template +{ + + LightFXData light_data; + + char nameID[SB_NAME_LENGTH]; + MREF my_module; + +} LIGHT_FX_TOOLS_TEMPLATE; + +void * LightFXBehaveInit (void * bhdata, STRATEGYBLOCK* sbptr); +void LightFXBehaveFun (STRATEGYBLOCK* sbptr); + + +#endif \ No newline at end of file diff --git a/3dc/avp/bh_mission.c b/3dc/avp/bh_mission.c new file mode 100644 index 0000000..a2c7297 --- /dev/null +++ b/3dc/avp/bh_mission.c @@ -0,0 +1,236 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "bh_types.h" +#include "bh_mission.h" +#include "ourasert.h" + +extern void MissionObjectiveTriggered(void* mission_objective); +extern void MakeMissionVisible(void* mission_objective); +extern void MakeMissionPossible(void* mission_objective); + +void * MissionCompleteBehaveInit(void* bhdata,STRATEGYBLOCK* sbptr) +{ + MISSION_COMPLETE_BEHAV_BLOCK* m_bhv; + MISSION_COMPLETE_TOOLS_TEMPLATE* mc_tt; + + GLOBALASSERT(sbptr); + + m_bhv=(MISSION_COMPLETE_BEHAV_BLOCK*)AllocateMem(sizeof(MISSION_COMPLETE_BEHAV_BLOCK)); + if(!m_bhv) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + mc_tt= (MISSION_COMPLETE_TOOLS_TEMPLATE*) bhdata; + + m_bhv->bhvr_type=I_BehaviourMissionComplete; + sbptr->shapeIndex = 0; + COPY_NAME(sbptr->SBname, mc_tt->nameID); + + + m_bhv->mission_objective_ptr=mc_tt->mission_objective_ptr; + + return((void*)m_bhv); +} + +#define MissionTrigger_MakeVisible 0x00000001 +#define MissionTrigger_MakePossible 0x00000002 +#define MissionTrigger_DontComplete 0x00000004 + +void SendRequestToMissionStrategy(STRATEGYBLOCK* sbptr,BOOL state,int extended_data) +{ + MISSION_COMPLETE_BEHAV_BLOCK *mc_bhv; + GLOBALASSERT(sbptr); + GLOBALASSERT(sbptr->SBdataptr); + mc_bhv = (MISSION_COMPLETE_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((mc_bhv->bhvr_type == I_BehaviourMissionComplete)); + + if(!state) return; + + if(extended_data & MissionTrigger_MakeVisible) + { + MakeMissionVisible(mc_bhv->mission_objective_ptr); + } + if(extended_data & MissionTrigger_MakePossible) + { + MakeMissionPossible(mc_bhv->mission_objective_ptr); + } + if(!(extended_data & MissionTrigger_DontComplete)) + { + MissionObjectiveTriggered(mc_bhv->mission_objective_ptr); + } + +} + + + + +void * MessageBehaveInit(void* bhdata,STRATEGYBLOCK* sbptr) +{ + MESSAGE_BEHAV_BLOCK* m_bhv; + MESSAGE_TOOLS_TEMPLATE* m_tt; + + GLOBALASSERT(sbptr); + + m_bhv=(MESSAGE_BEHAV_BLOCK*)AllocateMem(sizeof(MESSAGE_BEHAV_BLOCK)); + if(!m_bhv) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + m_tt= (MESSAGE_TOOLS_TEMPLATE*) bhdata; + + m_bhv->bhvr_type=I_BehaviourMessage; + sbptr->shapeIndex = 0; + COPY_NAME(sbptr->SBname, m_tt->nameID); + + + m_bhv->string_no=m_tt->string_no; + m_bhv->active=m_tt->active; + + return((void*)m_bhv); +} + +#define TextMessageRequest_Activate 1 +#define TextMessageRequest_ActivateAndDisplay 2 + +void SendRequestToMessageStrategy(STRATEGYBLOCK* sbptr,BOOL state,int extended_data) +{ + MESSAGE_BEHAV_BLOCK *m_bhv; + GLOBALASSERT(sbptr); + GLOBALASSERT(sbptr->SBdataptr); + m_bhv = (MESSAGE_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((m_bhv->bhvr_type == I_BehaviourMessage)); + + + switch(extended_data) + { + case TextMessageRequest_Activate : + m_bhv->active=state; + break; + + case TextMessageRequest_ActivateAndDisplay : + m_bhv->active=state; + + if(m_bhv->active) + { + PrintStringTableEntryInConsole(m_bhv->string_no); + StartTriggerPlotFMV(m_bhv->string_no); + } + break; + + default : + if(m_bhv->active && state) + { + PrintStringTableEntryInConsole(m_bhv->string_no); + StartTriggerPlotFMV(m_bhv->string_no); + } + } +} + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" + +typedef struct message_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + BOOL active; + +}MESSAGE_SAVE_BLOCK; + + +void LoadStrategy_Message(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + MESSAGE_BEHAV_BLOCK* m_bhv; + MESSAGE_SAVE_BLOCK* block = (MESSAGE_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourMessage) return; + + m_bhv = (MESSAGE_BEHAV_BLOCK *)sbPtr->SBdataptr; + + //start copying stuff + + m_bhv->active = block->active; +} + +void SaveStrategy_Message(STRATEGYBLOCK* sbPtr) +{ + MESSAGE_BEHAV_BLOCK* m_bhv; + MESSAGE_SAVE_BLOCK* block; + + m_bhv = (MESSAGE_BEHAV_BLOCK *)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + block->active = m_bhv->active; +} + + + +/*------------------------------** +** Loading/Saving mission state ** +**------------------------------*/ +extern int GetMissionStateForSave(void* mission_objective); +extern void SetMissionStateFromLoad(void* mission_objective,int state); + + +typedef struct mission_complete_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int state; + +}MISSION_COMPLETE_SAVE_BLOCK; + + +void LoadStrategy_MissionComplete(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + MISSION_COMPLETE_BEHAV_BLOCK* m_bhv; + MISSION_COMPLETE_SAVE_BLOCK* block = (MISSION_COMPLETE_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourMissionComplete) return; + + m_bhv = (MISSION_COMPLETE_BEHAV_BLOCK *)sbPtr->SBdataptr; + + //start copying stuff + SetMissionStateFromLoad(m_bhv->mission_objective_ptr , block->state); +} + +void SaveStrategy_MissionComplete(STRATEGYBLOCK* sbPtr) +{ + MISSION_COMPLETE_BEHAV_BLOCK* m_bhv; + MISSION_COMPLETE_SAVE_BLOCK* block; + + m_bhv = (MISSION_COMPLETE_BEHAV_BLOCK *)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + block->state = GetMissionStateForSave(m_bhv->mission_objective_ptr); + +} diff --git a/3dc/avp/bh_mission.h b/3dc/avp/bh_mission.h new file mode 100644 index 0000000..02a854d --- /dev/null +++ b/3dc/avp/bh_mission.h @@ -0,0 +1,50 @@ +#ifndef bh_mission_h_ +#define bh_mission_h 1 + + +void * MissionCompleteBehaveInit(void* bhdata,STRATEGYBLOCK* sbptr); +void * MessageBehaveInit(void* bhdata,STRATEGYBLOCK* sbptr); +extern void ResetMission(void* mission_objective); +extern void PrintStringTableEntryInConsole(enum TEXTSTRING_ID string_id); +extern void SendRequestToMessageStrategy(STRATEGYBLOCK* sbptr,BOOL state,int extended_data); +extern void SendRequestToMissionStrategy(STRATEGYBLOCK* sbptr,BOOL state,int extended_data); + + +//when this strategy receives a request state of 1 it notifies its attached mission that +//it has been achieved + +typedef struct mission_complete_tools_template +{ + void* mission_objective_ptr; + char nameID [SB_NAME_LENGTH]; +}MISSION_COMPLETE_TOOLS_TEMPLATE; + +typedef struct mission_complete_target +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + void* mission_objective_ptr; + +}MISSION_COMPLETE_BEHAV_BLOCK; + + + +//this strategy displays its message upon receiving a request state of 1 + +typedef struct message_tools_template +{ + enum TEXTSTRING_ID string_no; + char nameID [SB_NAME_LENGTH]; + BOOL active; +}MESSAGE_TOOLS_TEMPLATE; + + +typedef struct message_behav_block +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + enum TEXTSTRING_ID string_no; + BOOL active; + +}MESSAGE_BEHAV_BLOCK; + + +#endif \ No newline at end of file diff --git a/3dc/avp/bh_pargen.c b/3dc/avp/bh_pargen.c new file mode 100644 index 0000000..1c2b890 --- /dev/null +++ b/3dc/avp/bh_pargen.c @@ -0,0 +1,369 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "dynblock.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "bh_pargen.h" +#include "dynamics.h" +#include "pvisible.h" +#include "particle.h" +#include "lighting.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +extern char *ModuleCurrVisArray; +extern int NormalFrameTime; + +//particles used by each particle type +static enum PARTICLE_ID ParticleUsed[PARGEN_TYPE_LAST]= +{ + PARTICLE_SPARK, + PARTICLE_STEAM, + PARTICLE_BLACKSMOKE, + PARTICLE_PARGEN_FLAME +}; + +void* ParticleGeneratorBehaveInit(void* bhdata,STRATEGYBLOCK* sbptr) +{ + PARTICLE_GENERATOR_BEHAV_BLOCK* pargen; + PARTICLE_GENERATOR_TOOLS_TEMPLATE* pg_tt; + + GLOBALASSERT(sbptr); + GLOBALASSERT(bhdata); + + pargen=(PARTICLE_GENERATOR_BEHAV_BLOCK*)AllocateMem(sizeof(PARTICLE_GENERATOR_BEHAV_BLOCK)); + if(!pargen) + { + memoryInitialisationFailure = 1; + return 0; + } + pargen->bhvr_type=I_BehaviourParticleGenerator; + + pg_tt=(PARTICLE_GENERATOR_TOOLS_TEMPLATE*)bhdata; + + //copy stuff from tools template + COPY_NAME(sbptr->SBname, pg_tt->nameID); + pargen->position = pg_tt->position; + pargen->orientation = pg_tt->orientation; + pargen->type = pg_tt->type; + pargen->active = pg_tt->active; + pargen->sound = pg_tt->sound; + + //find the generator's module + sbptr->containingModule=ModuleFromPosition(&(pargen->position),0); + + GLOBALASSERT(sbptr->containingModule); + + if(pargen->sound) + { + pargen->sound->playing=pargen->active; + } + + //see if generator has a parent object + pargen->parent_sbptr=FindSBWithName(pg_tt->parentID); + if(pargen->parent_sbptr) + { + if(pargen->parent_sbptr->DynPtr) + { + //work out generator's relative position + MATRIXCH m=pargen->parent_sbptr->DynPtr->OrientMat; + TransposeMatrixCH(&m); + + pargen->relative_position=pargen->position; + pargen->relative_orientation=pargen->orientation; + + SubVector(&pargen->parent_sbptr->DynPtr->Position,&pargen->relative_position); + RotateVector(&pargen->relative_position,&m); + + MatrixMultiply(&pargen->relative_orientation,&m,&pargen->relative_orientation); + } + else + { + //parent object has no dynamics block + //so it can't be used + pargen->parent_sbptr=0; + } + } + + pargen->frequency=pg_tt->frequency; + pargen->timer=pargen->frequency; + + pargen->probability=pg_tt->probability; + pargen->speed=pg_tt->speed; + + return (void*)pargen; +} + +void ParticleGeneratorBehaveFun(STRATEGYBLOCK* sbptr) +{ + BOOL play_sound=FALSE; + PARTICLE_GENERATOR_BEHAV_BLOCK* pargen; + GLOBALASSERT(sbptr); + pargen = (PARTICLE_GENERATOR_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((pargen->bhvr_type == I_BehaviourParticleGenerator)); + + if(pargen->parent_sbptr) + { + //generator has parent object , update position + if(pargen->parent_sbptr->SBflags.destroyed_but_preserved) + { + //parent object destroyed + //switch off generator if active and return + if(pargen->active) + { + pargen->active=0; + if(pargen->sound) + { + //stop sound + Stop_Track_Sound(pargen->sound); + } + } + return; + } + else + { + DYNAMICSBLOCK *dynPtr = pargen->parent_sbptr->DynPtr; + GLOBALASSERT(dynPtr); + + //update orientation + MatrixMultiply(&pargen->relative_orientation,&dynPtr->OrientMat,&pargen->orientation); + + //update position + pargen->position=pargen->relative_position; + RotateVector(&pargen->position,&dynPtr->OrientMat); + AddVector(&dynPtr->Position,&pargen->position); + + //update containing module from parent + sbptr->containingModule=pargen->parent_sbptr->containingModule; + } + } + + + if(pargen->active) + { + //update timer + pargen->timer-=NormalFrameTime; + + if(pargen->sound) + { + //update sound + Update_Track_Sound(pargen->sound,&pargen->position); + } + + if(!sbptr->containingModule) + { + sbptr->containingModule=ModuleFromPosition(&(pargen->position),0); + } + GLOBALASSERT(sbptr->containingModule); + + if(ModuleCurrVisArray[(sbptr->containingModule->m_index)]) + { + //if containing module is near create particles. + + switch(pargen->type) + { + case PARGEN_TYPE_SPARK : + { + if(pargen->timer<0) + { + + if((FastRandom() & 0xffff)<=pargen->probability) + { + //create sparks + //like MakeSprayOfSparks , but in z direction + int noOfSparks = 15; + do + { + + VECTORCH velocity; + velocity.vx = (FastRandom()&2047)-1024; + velocity.vy = (FastRandom()&2047)-1024; + velocity.vz = (FastRandom()&2047); + RotateVector(&velocity,&pargen->orientation); + MakeParticle(&pargen->position,&velocity,ParticleUsed[pargen->type]); + } + while(--noOfSparks); + + MakeLightElement(&pargen->position,LIGHTELEMENT_ELECTRICAL_SPARKS); + play_sound=TRUE; + } + + } + } + break; + + case PARGEN_TYPE_FLAME : + //add light effect + MakeLightElement(&pargen->position,LIGHTELEMENT_PARGEN_FLAME); + //and fall throgh to next section + case PARGEN_TYPE_STEAM : + case PARGEN_TYPE_BLACKSMOKE : + { + while(pargen->timer<0) + { + VECTORCH velocity; + VECTORCH position=pargen->position; + int offset; + + pargen->timer+=pargen->frequency; + + //get a velocity of magnitude in the region of speed + velocity.vx = ((FastRandom()&1023) - 512); + velocity.vy = ((FastRandom()&1023) - 512); + velocity.vz = MUL_FIXED(pargen->speed,(ONE_FIXED+(FastRandom()&0x3fff))); + + RotateVector(&velocity,&pargen->orientation); + + //allow particle to have had part of a frames movement already + offset=FastRandom()%NormalFrameTime; + position.vx+=MUL_FIXED(offset,velocity.vx); + position.vy+=MUL_FIXED(offset,velocity.vy); + position.vz+=MUL_FIXED(offset,velocity.vz); + + MakeParticle(&position,&velocity,ParticleUsed[pargen->type]); + } + } + break; + + } + } + + if(pargen->timer<0) + { + pargen->timer=pargen->frequency+(pargen->timer % pargen->frequency); + } + } + + if(play_sound) + { + //if the generator has a non-looping sound , we should play it now + if(pargen->sound && !pargen->sound->loop) + { + Start_Track_Sound(pargen->sound,&pargen->position); + } + } +} + + +void SendRequestToParticleGenerator(STRATEGYBLOCK* sbptr,BOOL state,int extended_data) +{ + PARTICLE_GENERATOR_BEHAV_BLOCK* pargen = sbptr->SBdataptr; + LOCALASSERT(pargen); + + if(state) + { + //if generator has a parent object that has been destroyed , then it can't be switched on + if(pargen->parent_sbptr && pargen->parent_sbptr->SBflags.destroyed_but_preserved) + { + return; + } + + pargen->active=1; + if(pargen->sound && pargen->sound->loop) + { + //start sound + Start_Track_Sound(pargen->sound,&pargen->position); + } + } + else + { + pargen->active=0; + if(pargen->sound) + { + //stop sound + Stop_Track_Sound(pargen->sound); + } + } + +} + + + + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" + +typedef struct particle_generator_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + + VECTORCH position; + MATRIXCH orientation; + + VECTORCH relative_position; //relative to parent object (if it exists) + MATRIXCH relative_orientation; //relative to parent object (if it exists) + + int timer; //time left to next particle burst + + unsigned int active :1; //is generator currently active + unsigned int sound_playing :1; + +}PARTICLE_GENERATOR_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV pargen + +void LoadStrategy_ParticleGenerator(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + PARTICLE_GENERATOR_BEHAV_BLOCK* pargen; + PARTICLE_GENERATOR_SAVE_BLOCK* block = (PARTICLE_GENERATOR_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourParticleGenerator) return; + + pargen = (PARTICLE_GENERATOR_BEHAV_BLOCK*)sbPtr->SBdataptr; + + //start copying stuff + COPYELEMENT_LOAD(position) + COPYELEMENT_LOAD(orientation) + COPYELEMENT_LOAD(relative_position) + COPYELEMENT_LOAD(relative_orientation) + COPYELEMENT_LOAD(timer) + COPYELEMENT_LOAD(active) + + if(pargen->sound) + { + pargen->sound->playing = block->sound_playing; + Load_SoundState(&pargen->sound->activ_no); + } +} + +void SaveStrategy_ParticleGenerator(STRATEGYBLOCK* sbPtr) +{ + PARTICLE_GENERATOR_SAVE_BLOCK *block; + PARTICLE_GENERATOR_BEHAV_BLOCK* pargen; + + pargen = (PARTICLE_GENERATOR_BEHAV_BLOCK*)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + COPYELEMENT_SAVE(position) + COPYELEMENT_SAVE(orientation) + COPYELEMENT_SAVE(relative_position) + COPYELEMENT_SAVE(relative_orientation) + COPYELEMENT_SAVE(timer) + COPYELEMENT_SAVE(active) + + if(pargen->sound) + { + block->sound_playing = pargen->sound->playing; + Save_SoundState(&pargen->sound->activ_no); + } +} diff --git a/3dc/avp/bh_pargen.h b/3dc/avp/bh_pargen.h new file mode 100644 index 0000000..233d928 --- /dev/null +++ b/3dc/avp/bh_pargen.h @@ -0,0 +1,81 @@ +#ifndef _bh_pargen_h +#define _bh_pargen_h 1 + +#ifdef __cplusplus + + extern "C" { + +#endif +#include "track.h" + +extern void* ParticleGeneratorBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr); +extern void ParticleGeneratorBehaveFun(STRATEGYBLOCK* sbptr); +extern void SendRequestToParticleGenerator(STRATEGYBLOCK* sbptr,BOOL state,int extended_data); + +typedef enum particle_generator_type +{ + PARGEN_TYPE_SPARK, + PARGEN_TYPE_STEAM, + PARGEN_TYPE_BLACKSMOKE, + PARGEN_TYPE_FLAME, + PARGEN_TYPE_LAST + +}PARTICLE_GENERATOR_TYPE; + + +typedef struct particle_generator_behav_block +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + + VECTORCH position; + MATRIXCH orientation; + + VECTORCH relative_position; //relative to parent object (if it exists) + MATRIXCH relative_orientation; //relative to parent object (if it exists) + + PARTICLE_GENERATOR_TYPE type;//particle generator type + + TRACK_SOUND* sound; //not actually a track , but it will do + + STRATEGYBLOCK* parent_sbptr; + + int timer; //time left to next particle burst + + int frequency; //time between bursts + int probability; //probability of particles (0 - 65536) + int speed; //mm/second + + unsigned int active :1; //is generator currently active + +}PARTICLE_GENERATOR_BEHAV_BLOCK; + +typedef struct particle_generator_tools_template +{ + char nameID[SB_NAME_LENGTH]; + char parentID[SB_NAME_LENGTH]; + VECTORCH position; + MATRIXCH orientation; + + PARTICLE_GENERATOR_TYPE type;//particle generator type + + TRACK_SOUND* sound; //not actually a track , but it will do + + int frequency; //time between bursts + int probability; //probability of particles (0 - 65536) + int speed; //mm/second + + unsigned int active :1; +}PARTICLE_GENERATOR_TOOLS_TEMPLATE; + + + + + +#ifdef __cplusplus + + }; + +#endif + + +#endif diff --git a/3dc/avp/bh_plachier.c b/3dc/avp/bh_plachier.c new file mode 100644 index 0000000..e7dd4dc --- /dev/null +++ b/3dc/avp/bh_plachier.c @@ -0,0 +1,456 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "dynblock.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "dynamics.h" +#include "bh_plachier.h" +#include "ourasert.h" +#include "jsndsup.h" +#include "psndplat.h" + +extern MODULEMAPBLOCK VisibilityDefaultObjectMap; + +/* +void PlacedHierarchyRestart(PLACED_HIERARCHY_BEHAV_BLOCK *ph_bhv) +{ +} + +void PlacedHierarchyStop(PLACED_HIERARCHY_BEHAV_BLOCK *ph_bhv) +{ +} +*/ +SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char *); + +void* PlacedHierarchyBehaveInit(void* bhdata,STRATEGYBLOCK* sbptr) +{ + PLACED_HIERARCHY_BEHAV_BLOCK* ph_bhv; + PLACED_HIERARCHY_TOOLS_TEMPLATE* ph_tt; + SECTION *root_section; + SECTION_DATA* sound_section_data; + + GLOBALASSERT(sbptr); + GLOBALASSERT(bhdata); + + ph_bhv=(PLACED_HIERARCHY_BEHAV_BLOCK*)AllocateMem(sizeof(PLACED_HIERARCHY_BEHAV_BLOCK)); + if(!ph_bhv) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + ph_bhv->bhvr_type=I_BehaviourPlacedHierarchy; + + ph_tt=(PLACED_HIERARCHY_TOOLS_TEMPLATE*)bhdata; + + sbptr->shapeIndex=0; + COPY_NAME(sbptr->SBname, ph_tt->nameID); + + sbptr->DynPtr->Position = sbptr->DynPtr->PrevPosition = ph_tt->position; + sbptr->DynPtr->OrientEuler = ph_tt->orientation; + CreateEulerMatrix(&sbptr->DynPtr->OrientEuler, &sbptr->DynPtr->OrientMat); + TransposeMatrixCH(&sbptr->DynPtr->OrientMat); + + ph_bhv->num_sequences=ph_tt->num_sequences; + ph_bhv->sequences=ph_tt->sequences; + ph_bhv->num_sounds=ph_tt->num_sounds; + ph_bhv->sounds=ph_tt->sounds; + + ph_bhv->num_special_track_points=ph_tt->num_special_track_points; + ph_bhv->special_track_points=ph_tt->special_track_points; + + root_section=GetNamedHierarchyFromLibrary(ph_tt->file_name,ph_tt->hier_name); + GLOBALASSERT(root_section); + Create_HModel(&ph_bhv->HModelController,root_section); + + ph_bhv->current_seq=ph_tt->first_sequence; + InitHModelSequence(&ph_bhv->HModelController,ph_bhv->current_seq->sequence_no,ph_bhv->current_seq->sub_sequence_no,ph_bhv->current_seq->time); + ph_bhv->HModelController.Playing=ph_tt->playing; + ph_bhv->HModelController.Looped=ph_bhv->current_seq->loop; + + //find the hierarchy section that sound should be produced from + sound_section_data=GetThisSectionData(ph_bhv->HModelController.section_data,"SoundSource"); + if(!sound_section_data) + { + //if there isn't a SoundSource object , sound can come from the root section + sound_section_data=ph_bhv->HModelController.section_data; + } + ph_bhv->sound_location=&sound_section_data->World_Offset; + + + return ((void*)ph_bhv); +} + + +void MakePlacedHierarchyNear(STRATEGYBLOCK* sbptr) +{ + + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr = sbptr->DynPtr; + PLACED_HIERARCHY_BEHAV_BLOCK *ph_bhv= (PLACED_HIERARCHY_BEHAV_BLOCK*)(sbptr->SBdataptr); + + LOCALASSERT(dynPtr); + LOCALASSERT(sbPtr->SBdptr == NULL); + + VisibilityDefaultObjectMap.MapShape = 0; + tempModule.m_mapptr = &VisibilityDefaultObjectMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 0; + tempModule.m_lightarray = (struct lightblock *)0; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr = NULL; /* this is important */ + #if SupportWIndows95 + tempModule.name = NULL; /* this is important */ + #endif + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) return; /* cannot create displayblock, so leave object "far" */ + + sbptr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbptr; + dPtr->ObMyModule = NULL; + + /* also need to initialise positional information in the new display + block from the existing dynamics block: this necessary because this + function is (usually) called between the dynamics and rendering systems + so it is not initialised by the dynamics system the first time it is + drawn. */ + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + + + + dPtr->HModelControlBlock=&ph_bhv->HModelController; + ProveHModel(dPtr->HModelControlBlock,dPtr); + +} + +void PlacedHierarchyBehaveFun(STRATEGYBLOCK* sbptr) +{ + PLACED_HIERARCHY_BEHAV_BLOCK *ph_bhv; + + GLOBALASSERT(sbptr); + ph_bhv =(PLACED_HIERARCHY_BEHAV_BLOCK*) sbptr->SBdataptr; + GLOBALASSERT((ph_bhv->bhvr_type) == I_BehaviourPlacedHierarchy); + + if(sbptr->SBdptr) + { + ProveHModel(&ph_bhv->HModelController,sbptr->SBdptr); + } + else + { + ProveHModel_Far(&ph_bhv->HModelController,sbptr); + } + + //update sound + if(ph_bhv->HModelController.Playing && ph_bhv->current_seq) + { + int i,j; + int timer=ph_bhv->HModelController.sequence_timer; + int keyframe_flags=ph_bhv->HModelController.keyframe_flags; + + if(keyframe_flags) + { + for(i=0;inum_special_track_points;i++) + { + if(keyframe_flags & ph_bhv->special_track_points[i].track_point_no) + { + SPECIAL_TRACK_POINT* stp=&ph_bhv->special_track_points[i]; + for(j=0;jnum_targets;j++) + { + TRACK_POINT_TARGET* tpt=&stp->targets[j]; + RequestState(tpt->target_sbptr,tpt->request,0); + } + + } + } + + } + + + for(i=0;icurrent_seq->num_sound_times;i++) + { + PLACED_HIERARCHY_SOUND_TIMES* s_time=&ph_bhv->current_seq->sound_times[i]; + if(s_time->sound) + { + PLACED_HIERARCHY_SOUND* sound=s_time->sound; + //not much point in continuing if the sound wasn't loaded anyway + if(sound->sound_loaded) + { + if(timer>=s_time->start_time && timerend_time) + { + //start sound if not already playing + if(!sound->playing) + { + + int dist=VectorDistance(&Player->ObWorld,ph_bhv->sound_location); + if(dist<=sound->outer_range) //make sure sound is in range + { + SOUND3DDATA s3d; + s3d.position = *ph_bhv->sound_location; + s3d.inner_range = sound->inner_range; + s3d.outer_range = sound->outer_range; + s3d.velocity.vx = 0; + s3d.velocity.vy = 0; + s3d.velocity.vz = 0; + + if(s_time->sound->loop) + { + Sound_Play ((SOUNDINDEX)sound->sound_loaded->sound_num, "nvpel", &s3d,sound->max_volume,sound->pitch,&sound->activ_no); + } + else + { + Sound_Play ((SOUNDINDEX)sound->sound_loaded->sound_num, "nvpe", &s3d,sound->max_volume,sound->pitch,&sound->activ_no); + } + } + sound->playing=1; + } + //otherwise update its position + else + { + int dist=VectorDistance(&Player->ObWorld,ph_bhv->sound_location); + if(sound->activ_no!=SOUND_NOACTIVEINDEX) + { + if(dist<=sound->outer_range) + { + SOUND3DDATA s3d; + s3d.position = *ph_bhv->sound_location; + s3d.inner_range = sound->inner_range; + s3d.outer_range = sound->outer_range; + s3d.velocity.vx = 0; + s3d.velocity.vy = 0; + s3d.velocity.vz = 0; + Sound_UpdateNew3d (sound->activ_no, &s3d); + } + else + { + Sound_Stop(sound->activ_no); + } + } + else + { + if(dist<=sound->outer_range && sound->loop) + { + SOUND3DDATA s3d; + s3d.position = *ph_bhv->sound_location; + s3d.inner_range = sound->inner_range; + s3d.outer_range = sound->outer_range; + s3d.velocity.vx = 0; + s3d.velocity.vy = 0; + s3d.velocity.vz = 0; + Sound_Play ((SOUNDINDEX)sound->sound_loaded->sound_num, "nvpel", &s3d,sound->max_volume,sound->pitch,&sound->activ_no); + } + } + } + } + else + { + //stop sound + if(sound->activ_no!=SOUND_NOACTIVEINDEX) + { + Sound_Stop(sound->activ_no); + } + sound->playing=0; + } + } + } + } + + } +} + +void DeletePlacedHierarchy(PLACED_HIERARCHY_BEHAV_BLOCK* ph_bhv) +{ + int i; + if(!ph_bhv) return; + + for(i=0;inum_sounds;i++) + { + if(ph_bhv->sounds[i].activ_no!=SOUND_NOACTIVEINDEX) + { + Sound_Stop(ph_bhv->sounds[i].activ_no); + } + } + + Dispel_HModel(&ph_bhv->HModelController); + +} + +void PlacedHierarchyStopSequence(PLACED_HIERARCHY_BEHAV_BLOCK* ph_bhv) +{ + int i; + //stop hierarchy from playing + ph_bhv->HModelController.Playing=FALSE; + //and stop all the sounds + for(i=0;inum_sounds;i++) + { + if(ph_bhv->sounds[i].activ_no!=SOUND_NOACTIVEINDEX) + { + Sound_Stop(ph_bhv->sounds[i].activ_no); + } + ph_bhv->sounds[i].playing=0; + } +} + + +void SendRequestToPlacedHierarchy(STRATEGYBLOCK* sbptr,BOOL state,int extended_data) +{ + PLACED_HIERARCHY_BEHAV_BLOCK *ph_bhv; + int seq_num; + GLOBALASSERT(sbptr); + GLOBALASSERT(sbptr->SBdataptr); + ph_bhv = (PLACED_HIERARCHY_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((ph_bhv->bhvr_type == I_BehaviourPlacedHierarchy)); + + seq_num=(extended_data>>7)&0xff; + if(state) + { + PLACED_HIERARCHY_SEQUENCE* new_sequence; + GLOBALASSERT(seq_numnum_sequences); + + new_sequence=&ph_bhv->sequences[seq_num]; + GLOBALASSERT(new_sequence->sequence_no!=-1); + + if(new_sequence==ph_bhv->current_seq) + { + //restart the current sequence + ph_bhv->HModelController.Playing=1; + } + else + { + //stop the current sequence + PlacedHierarchyStopSequence(ph_bhv); + //start the new sequence + ph_bhv->current_seq=new_sequence; + InitHModelSequence(&ph_bhv->HModelController,ph_bhv->current_seq->sequence_no,ph_bhv->current_seq->sub_sequence_no,ph_bhv->current_seq->time); + ph_bhv->HModelController.Playing=1; + ph_bhv->HModelController.Looped=ph_bhv->current_seq->loop; + } + + } + else + { + PlacedHierarchyStopSequence(ph_bhv); + } + +} + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" + + +void LoadStrategy_PlacedHierarchy(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + int i; + STRATEGYBLOCK* sbPtr; + PLACED_HIERARCHY_BEHAV_BLOCK *ph_bhv; + char * buffer =(char*) header; + + buffer+=sizeof(*header); + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourPlacedHierarchy) return; + + ph_bhv = (PLACED_HIERARCHY_BEHAV_BLOCK*)sbPtr->SBdataptr; + + { + int sequence_index; + sequence_index = *(int*) buffer; + buffer+=sizeof(int); + if(sequence_index>=0 && sequence_indexnum_sequences) + { + ph_bhv->current_seq = &ph_bhv->sequences[sequence_index]; + } + } + + { + int loaded_num_sounds; + + loaded_num_sounds = *(int*) buffer; + buffer +=sizeof(int); + + for(i=0;inum_sounds;i++) + { + int playing; + playing = *(int*)buffer; + buffer += sizeof(int); + + ph_bhv->sounds[i].playing = playing; + } + + } + + //load the hierarchy + { + SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); + if(hier_header) + { + LoadHierarchy(hier_header,&ph_bhv->HModelController); + } + } + + for(i=0;inum_sounds;i++) + { + Load_SoundState(&ph_bhv->sounds[i].activ_no); + } + +} + +void SaveStrategy_PlacedHierarchy(STRATEGYBLOCK* sbPtr) +{ + PLACED_HIERARCHY_BEHAV_BLOCK *ph_bhv; + SAVE_BLOCK_STRATEGY_HEADER* header; + char* buffer; + unsigned int size; + int i; + + ph_bhv = (PLACED_HIERARCHY_BEHAV_BLOCK*)sbPtr->SBdataptr; + + //determine memeory required + size = sizeof(SAVE_BLOCK_STRATEGY_HEADER)+(2*sizeof(int))+(sizeof(int)*ph_bhv->num_sounds); + + header = (SAVE_BLOCK_STRATEGY_HEADER*) GetPointerForSaveBlock(size); + buffer = (char*) header; + buffer += sizeof(*header); + + //fill in the header + header->type = SaveBlock_Strategy; + header->size = size; + header->bhvr_type = I_BehaviourPlacedHierarchy; + COPY_NAME(header->SBname,sbPtr->SBname); + + { + int sequence_index = ph_bhv->current_seq-ph_bhv->sequences; + *(int*)buffer = sequence_index; + buffer+=sizeof(int); + } + + *(int*)buffer = ph_bhv->num_sounds; + buffer+=sizeof(int); + + for(i=0;inum_sounds;i++) + { + int playing = ph_bhv->sounds[i].playing; + *(int*)buffer = playing; + buffer+=sizeof(int); + } + + //save the hierarchy + SaveHierarchy(&ph_bhv->HModelController); + + for(i=0;inum_sounds;i++) + { + Save_SoundState(&ph_bhv->sounds[i].activ_no); + } + +} \ No newline at end of file diff --git a/3dc/avp/bh_plachier.h b/3dc/avp/bh_plachier.h new file mode 100644 index 0000000..adcd9a8 --- /dev/null +++ b/3dc/avp/bh_plachier.h @@ -0,0 +1,104 @@ +#ifndef _bh_plachier_h_ +#define _bh_plachier_h_ 1 + +#include "bh_track.h" //for the special_track_point structure + +#ifdef __cplusplus + + extern "C" { + +#endif + + +typedef struct placed_hierarchy_sound +{ + unsigned long inner_range; + unsigned long outer_range; + int max_volume; + int pitch; + + struct loaded_sound const * sound_loaded; + int activ_no; + + unsigned int loop:1; + unsigned int playing:1; //sound should be playing (if in range) +}PLACED_HIERARCHY_SOUND; + +typedef struct placed_hierarchy_sound_times +{ + int start_time; + int end_time; + PLACED_HIERARCHY_SOUND* sound; +}PLACED_HIERARCHY_SOUND_TIMES; + +typedef struct placed_hierarchy_sequence +{ + int sequence_no; + int sub_sequence_no; + int time; + unsigned int loop:1; + + int num_sound_times; + PLACED_HIERARCHY_SOUND_TIMES* sound_times; +}PLACED_HIERARCHY_SEQUENCE; + + +typedef struct placed_hierarchy_behav_block +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + + HMODELCONTROLLER HModelController; + + PLACED_HIERARCHY_SEQUENCE* current_seq; + int num_sequences; + PLACED_HIERARCHY_SEQUENCE* sequences; + + VECTORCH* sound_location; + + int num_sounds; + PLACED_HIERARCHY_SOUND* sounds; + + + int num_special_track_points; + SPECIAL_TRACK_POINT* special_track_points; + +}PLACED_HIERARCHY_BEHAV_BLOCK; + + +typedef struct placed_hierarchy_tools_template +{ + char nameID[SB_NAME_LENGTH]; + + VECTORCH position; + EULER orientation; + + int num_sequences; + PLACED_HIERARCHY_SEQUENCE* sequences; + PLACED_HIERARCHY_SEQUENCE* first_sequence; + BOOL playing; + + int num_sounds; + PLACED_HIERARCHY_SOUND* sounds; + + int num_special_track_points; + SPECIAL_TRACK_POINT* special_track_points; + + const char* file_name; + const char* hier_name; +}PLACED_HIERARCHY_TOOLS_TEMPLATE; + +extern void* PlacedHierarchyBehaveInit(void* bhdata,STRATEGYBLOCK* sbptr); +void PlacedHierarchyBehaveFun(STRATEGYBLOCK* sbptr); +void MakePlacedHierarchyNear(STRATEGYBLOCK* sbptr); +void DeletePlacedHierarchy(PLACED_HIERARCHY_BEHAV_BLOCK*); +void SendRequestToPlacedHierarchy(STRATEGYBLOCK* sbptr,BOOL state,int extended_data); + + +#ifdef __cplusplus + + }; + +#endif + + +#endif diff --git a/3dc/avp/bh_plift.c b/3dc/avp/bh_plift.c new file mode 100644 index 0000000..6354f7f --- /dev/null +++ b/3dc/avp/bh_plift.c @@ -0,0 +1,697 @@ +/*------------------------------Patrick 14/3/97----------------------------------- + Source for Platform lift behaviour functions + --------------------------------------------------------------------------------*/ +#include "3dc.h" +#include "module.h" +#include "inline.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "triggers.h" +#include "mslhand.h" +#include "dynblock.h" +#include "dynamics.h" +#include "showcmds.h" + +#define UseLocalAssert Yes + +#include "ourasert.h" +#include "bh_plift.h" + +#if SupportWindows95 +/* for win95 net game support */ +#include "pldnet.h" +#include "pldghost.h" +#endif + +/* prototypes for this file */ +static int SquashingSomething(DYNAMICSBLOCK *dynPtr); +static void PushPassengersUpwards(DYNAMICSBLOCK *dynPtr); +static int ActivatedByPlayer(DYNAMICSBLOCK *dynPtr); +static int PlayerIsNearOtherTerminal(STRATEGYBLOCK *sbPtr); +static int NetPlayerAtOtherTerminal(STRATEGYBLOCK *sbPtr); +static int PLiftIsNearerUpThanDown(STRATEGYBLOCK *sbPtr); + +/* external globals used in this file */ +extern int NormalFrameTime; + +/*------------------------------Patrick 15/3/97----------------------------------- + Behaviour function for platform lift + --------------------------------------------------------------------------------*/ +void PlatformLiftBehaviour(STRATEGYBLOCK *sbPtr) +{ + PLATFORMLIFT_BEHAVIOUR_BLOCK *platformliftdata; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + platformliftdata = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(platformliftdata); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + switch(platformliftdata->state) + { + case(PLBS_AtRest): + { + if(AvP.Network==I_Host) + { + /* multiplayer host */ + if(NetPlayerAtOtherTerminal(sbPtr)) + { + if(platformliftdata->Enabled) ActivatePlatformLift(sbPtr); + } + else if(sbPtr->SBdptr) + { + /* check for activation by this player*/ + if(ActivatedByPlayer(dynPtr)) + { + if (platformliftdata->Enabled) ActivatePlatformLift(sbPtr); + } + } + } + else if(AvP.Network==I_No_Network) + { + /* single player */ + if(sbPtr->SBdptr) + { + /* check for activation */ + if(ActivatedByPlayer(dynPtr) || PlayerIsNearOtherTerminal(sbPtr)) + { + if (platformliftdata->Enabled) ActivatePlatformLift(sbPtr); + } + } + } + else + { + #if SupportWindows95 + LOCALASSERT(AvP.Network==I_Peer); + if(ActivatedByPlayer(dynPtr)) AddNetMsg_RequestPlatformLiftActivate(sbPtr); + #endif + } + //textprint("Platform state: at rest\n"); + break; + } + case(PLBS_Activating): + { + if(AvP.Network!=I_Peer) + { + if(platformliftdata->activationDelayTimer>0) + { + platformliftdata->activationDelayTimer -= NormalFrameTime; + } + + + if(platformliftdata->activationDelayTimer<=0) + { + //play start sound if the lift has any + if(platformliftdata->start_sound) + { + Start_Track_Sound(platformliftdata->start_sound,&sbPtr->DynPtr->Position); + } + + + platformliftdata->activationDelayTimer = 0; + if(dynPtr->Position.vy > ((platformliftdata->upHeight+platformliftdata->downHeight)/2)) + { + SendPlatformLiftUp(sbPtr); + } + else SendPlatformLiftDown(sbPtr); + } + } + //textprint("Platform state: activating\n"); + //textprint("Platform timer: %d\n",platformliftdata->activationDelayTimer); + break; + } + case(PLBS_GoingUp): + { + if(dynPtr->Position.vy <= platformliftdata->upHeight) + { + /* finished */ + StopPlatformLift(sbPtr); + if (platformliftdata->OneUse) + platformliftdata->Enabled = No; + } + else + { + sbPtr->DynPtr->Displacement.vy = -MUL_FIXED(PLATFORMLIFT_SPEED,NormalFrameTime); + { + int d = platformliftdata->upHeight - sbPtr->DynPtr->Position.vy; + + if (d>sbPtr->DynPtr->Displacement.vy) + { + sbPtr->DynPtr->Displacement.vy=d; + } + } + } + + PushPassengersUpwards(dynPtr); + //textprint("Platform state: going up\n"); + break; + } + case(PLBS_GoingDown): + { + if(dynPtr->Position.vy >= platformliftdata->downHeight) + { + /* finished */ + StopPlatformLift(sbPtr); + if (platformliftdata->OneUse) + platformliftdata->Enabled = No; + } + else + { + sbPtr->DynPtr->Displacement.vy = MUL_FIXED(PLATFORMLIFT_SPEED,NormalFrameTime); + { + int d = platformliftdata->downHeight - sbPtr->DynPtr->Position.vy; + + if (dDynPtr->Displacement.vy) + { + sbPtr->DynPtr->Displacement.vy=d; + } + } + + if(AvP.Network!=I_Peer) + { + if(SquashingSomething(dynPtr)) + { +// sbPtr->DynPtr->Displacement.vy = 0; + // SendPlatformLiftUp(sbPtr); + } + } + } + + //textprint("Platform state: going down\n"); + break; + } + default: + { + LOCALASSERT(1==0); + } + } + + //update sound + if(platformliftdata->state==PLBS_GoingUp || platformliftdata->state==PLBS_GoingDown) + { + BOOL mainSoundShouldBePlaying=TRUE; + + //the main sound should be started if there is no start sound , or the start sound has + //almost finished + if(platformliftdata->start_sound && platformliftdata->start_sound->playing) + { + Update_Track_Sound(platformliftdata->start_sound,&dynPtr->Position); + + if(platformliftdata->start_sound->time_left>NormalFrameTime) + { + mainSoundShouldBePlaying=FALSE; + } + + } + + if(platformliftdata->sound) + { + if(platformliftdata->sound->playing) + { + Update_Track_Sound(platformliftdata->sound,&dynPtr->Position); + } + else if(mainSoundShouldBePlaying) + { + Start_Track_Sound(platformliftdata->sound,&sbPtr->DynPtr->Position); + } + } + } + + + //textprint("Platform pos: %d / %d / %d\n",platformliftdata->upHeight,dynPtr->Position.vy,platformliftdata->downHeight); + + /* send state messages in net game */ + #if SupportWindows95 + if(AvP.Network==I_Host) + { + if(platformliftdata->netMsgCount>0) + { + /* don't send at rest messages: peers detect end of movement locally. */ + if(platformliftdata->state!=PLBS_AtRest) + { + AddNetMsg_PlatformLiftState(sbPtr); + } + platformliftdata->netMsgCount--; + } + } + #endif +} + +void InitialisePlatformLift(void* bhdata, STRATEGYBLOCK *sbPtr) +{ + PLATFORMLIFT_TOOLS_TEMPLATE *toolsData = (PLATFORMLIFT_TOOLS_TEMPLATE *)bhdata; + PLATFORMLIFT_BEHAVIOUR_BLOCK* platformliftdata; + int i; + + LOCALASSERT(sbPtr->I_SBtype == I_BehaviourPlatform); + LOCALASSERT(toolsData); + + /* create, initialise and attach a data block */ + platformliftdata = (void *)AllocateMem(sizeof(PLATFORMLIFT_BEHAVIOUR_BLOCK)); + if(!platformliftdata) + { + memoryInitialisationFailure = 1; + return; + } + + sbPtr->SBdataptr = platformliftdata; + platformliftdata->homePosition = toolsData->position; + platformliftdata->activationDelayTimer = 0; + platformliftdata->state = PLBS_AtRest; + platformliftdata->netMsgCount = 0; + + if(toolsData->travel<0) + { + platformliftdata->upHeight = platformliftdata->homePosition.vy + toolsData->travel; + platformliftdata->downHeight = platformliftdata->homePosition.vy; + } + else + { + platformliftdata->upHeight = platformliftdata->homePosition.vy; + platformliftdata->downHeight = platformliftdata->homePosition.vy + toolsData->travel; + } + + LOCALASSERT(platformliftdata->upHeight < platformliftdata->downHeight); + + platformliftdata->sound = toolsData->sound; + platformliftdata->start_sound = toolsData->start_sound; + platformliftdata->end_sound = toolsData->end_sound; + + platformliftdata->Enabled = toolsData->Enabled; + platformliftdata->OneUse = toolsData->OneUse; + + + /* create and initialise the dynamics block */ + { + DYNAMICSBLOCK *dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_PLATFORM_LIFT); + GLOBALASSERT(dynPtr); + + sbPtr->DynPtr = dynPtr; + dynPtr->PrevPosition = dynPtr->Position = toolsData->position; + dynPtr->LinVelocity.vx = dynPtr->LinVelocity.vy = dynPtr->LinVelocity.vz = 0; + dynPtr->OrientEuler = toolsData->orientation; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + } + + /* strategy block initialisation */ + sbPtr->shapeIndex = toolsData->shapeIndex; + for(i=0;iSBname[i] = toolsData->nameID[i]; + sbPtr->integrity = 1; +} + +/*------------------------------Patrick 2/4/97----------------------------------- + State change functions: these are alos used by network message processing fns + --------------------------------------------------------------------------------*/ +void ActivatePlatformLift(STRATEGYBLOCK *sbPtr) +{ + PLATFORMLIFT_BEHAVIOUR_BLOCK *platformliftdata = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(platformliftdata); + + platformliftdata->state = PLBS_Activating; + platformliftdata->activationDelayTimer = PLATFORMLIFT_ACTIVATIONTIME; + platformliftdata->netMsgCount = PLATFORMLIFT_NUMNETMESSAGES; + +} + +void SendPlatformLiftUp(STRATEGYBLOCK *sbPtr) +{ + PLATFORMLIFT_BEHAVIOUR_BLOCK *platformliftdata = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(platformliftdata); + + platformliftdata->state = PLBS_GoingUp; + sbPtr->DynPtr->Displacement.vx = sbPtr->DynPtr->Displacement.vz = 0; + platformliftdata->netMsgCount = PLATFORMLIFT_NUMNETMESSAGES; + + sbPtr->DynPtr->Displacement.vy = -MUL_FIXED(PLATFORMLIFT_SPEED,NormalFrameTime); + { + int d = platformliftdata->upHeight - sbPtr->DynPtr->Position.vy; + + if (d>sbPtr->DynPtr->Displacement.vy) + { + sbPtr->DynPtr->Displacement.vy=d; + } + } +} + +void SendPlatformLiftDown(STRATEGYBLOCK *sbPtr) +{ + PLATFORMLIFT_BEHAVIOUR_BLOCK *platformliftdata = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(platformliftdata); + + platformliftdata->state = PLBS_GoingDown; + sbPtr->DynPtr->Displacement.vx = sbPtr->DynPtr->Displacement.vz = 0; + platformliftdata->netMsgCount = PLATFORMLIFT_NUMNETMESSAGES; + + sbPtr->DynPtr->Displacement.vy = MUL_FIXED(PLATFORMLIFT_SPEED,NormalFrameTime); + { + int d = platformliftdata->downHeight - sbPtr->DynPtr->Position.vy; + + if (dDynPtr->Displacement.vy) + { + sbPtr->DynPtr->Displacement.vy=d; + } + } +} + +void StopPlatformLift(STRATEGYBLOCK *sbPtr) +{ + PLATFORMLIFT_BEHAVIOUR_BLOCK *platformliftdata = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(platformliftdata); + + sbPtr->DynPtr->Displacement.vx = sbPtr->DynPtr->Displacement.vy = sbPtr->DynPtr->Displacement.vz = 0; + platformliftdata->state = PLBS_AtRest; + + /* just to stop drift... */ + /* + if(PLiftIsNearerUpThanDown(sbPtr)) + sbPtr->DynPtr->Position.vy = platformliftdata->upHeight; + else + sbPtr->DynPtr->Position.vy = platformliftdata->downHeight; + */ + platformliftdata->netMsgCount = PLATFORMLIFT_NUMNETMESSAGES; + + //stop sound if the lift has any + if(platformliftdata->sound) + { + Stop_Track_Sound(platformliftdata->sound); + } + //start end sound if lift has any + if(platformliftdata->end_sound) + { + Start_Track_Sound(platformliftdata->end_sound,&sbPtr->DynPtr->Position); + } + +} + + +/*------------------------------Patrick 15/3/97----------------------------------- + Support functions + --------------------------------------------------------------------------------*/ +static int SquashingSomething(DYNAMICSBLOCK *dynPtr) +{ + struct collisionreport *nextReport; + int squashingSomething = 0; + LOCALASSERT(dynPtr); + nextReport = dynPtr->CollisionReportPtr; + + /* walk the collision report list, looking for collisions against objects */ + while(nextReport) + { + STRATEGYBLOCK *sbPtr = nextReport->ObstacleSBPtr; + if(sbPtr) + { + if(nextReport->ObstacleNormal.vy < -46340) + { + extern DAMAGE_PROFILE FallingDamage; + squashingSomething=1; + + /* squish! */ + CauseDamageToObject(sbPtr, &FallingDamage, (100*NormalFrameTime), NULL); + } + else if (nextReport->ObstacleNormal.vy > 46340) + { + DYNAMICSBLOCK *objDynPtr = sbPtr->DynPtr; + if (objDynPtr) + { + if (objDynPtr->LinImpulse.vy < PLATFORMLIFT_SPEED) + { + objDynPtr->LinImpulse.vy = PLATFORMLIFT_SPEED; + } + } + } + } + nextReport = nextReport->NextCollisionReportPtr; + } + return squashingSomething; +} + +static void PushPassengersUpwards(DYNAMICSBLOCK *dynPtr) +{ + #if 0 + struct collisionreport *nextReport; + + LOCALASSERT(dynPtr); + nextReport = dynPtr->CollisionReportPtr; + + /* walk the collision report list, looking for collisions against objects */ + while(nextReport) + { + STRATEGYBLOCK *sbPtr = nextReport->ObstacleSBPtr; + if(sbPtr) + { + DYNAMICSBLOCK *objDynPtr = sbPtr->DynPtr; + if (objDynPtr) + { + int upwardsImpulse = -MUL_FIXED(GRAVITY_STRENGTH,NormalFrameTime) - PLATFORMLIFT_SPEED; + + if (objDynPtr->LinImpulse.vy > upwardsImpulse) + { + objDynPtr->LinImpulse.vy = upwardsImpulse; + objDynPtr->IsInContactWithFloor =1; + PrintDebuggingText("I'M PUSHING UP AN OBJECT!"); + } + } + } + nextReport = nextReport->NextCollisionReportPtr; + } + #endif +} + +static int ActivatedByPlayer(DYNAMICSBLOCK *dynPtr) +{ + struct collisionreport *nextReport; + + LOCALASSERT(dynPtr); + nextReport = dynPtr->CollisionReportPtr; + + /* walk the collision report list, looking for collisions against objects */ + while(nextReport) + { +/// textprint("collision with %p\n",nextReport->ObstacleSBPtr); + if(nextReport->ObstacleSBPtr == Player->ObStrategyBlock) return 1; + + nextReport = nextReport->NextCollisionReportPtr; + } + return 0; +} + +static int PlayerIsNearOtherTerminal(STRATEGYBLOCK *sbPtr) +{ + int averageHeight; + PLATFORMLIFT_BEHAVIOUR_BLOCK *platformliftdata; + DYNAMICSBLOCK *dynPtr; + + LOCALASSERT(sbPtr); + platformliftdata = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(platformliftdata); + LOCALASSERT(platformliftdata->state == PLBS_AtRest); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + averageHeight = (platformliftdata->upHeight+platformliftdata->downHeight)/2; + + if(dynPtr->Position.vy > averageHeight) + { + if (Player->ObStrategyBlock->DynPtr->Position.vy < averageHeight) + return 1; + } + else + { + if (Player->ObStrategyBlock->DynPtr->Position.vy > averageHeight) + return 1; + } + return 0; +} + +/* returns 1 if the player or a remote player is within 5 m of the other end of +the lift track...*/ +static int NetPlayerAtOtherTerminal(STRATEGYBLOCK *sbPtr) +{ +#if SupportWindows95 + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + + int sbIndex = 0; + PLATFORMLIFT_BEHAVIOUR_BLOCK *platformliftdata; + DYNAMICSBLOCK *dynPtr; + VECTORCH otherTerminal; + + LOCALASSERT(sbPtr); + platformliftdata = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(platformliftdata); + LOCALASSERT(platformliftdata->state == PLBS_AtRest); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + + if(PLiftIsNearerUpThanDown(sbPtr)) + { + otherTerminal = dynPtr->Position; + otherTerminal.vy = platformliftdata->downHeight; + } + else + { + otherTerminal = dynPtr->Position; + otherTerminal.vy = platformliftdata->upHeight; + } + + while(sbIndex < NumActiveStBlocks) + { + STRATEGYBLOCK *sbPtr = ActiveStBlockList[sbIndex++]; + + if(sbPtr->I_SBtype==I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData = ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + if((ghostData->type==I_BehaviourMarinePlayer)|| + (ghostData->type==I_BehaviourAlienPlayer)|| + (ghostData->type==I_BehaviourPredatorPlayer)) + { + /* remote player */ + LOCALASSERT(sbPtr->DynPtr); + if(VectorDistance(&(sbPtr->DynPtr->Position),&(otherTerminal))<5000) return 1; + } + } + else if(sbPtr==Player->ObStrategyBlock) + { + /* local player */ + LOCALASSERT(sbPtr->DynPtr); + if(VectorDistance(&(sbPtr->DynPtr->Position),&(otherTerminal))<5000) return 1; + } + } + return 0; +#else + return 0; +#endif +} + + +static int PLiftIsNearerUpThanDown(STRATEGYBLOCK *sbPtr) +{ + PLATFORMLIFT_BEHAVIOUR_BLOCK *platformliftdata; + int upDist, downDist; + + LOCALASSERT(sbPtr); + platformliftdata = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(platformliftdata); + LOCALASSERT(sbPtr->DynPtr); + + upDist = sbPtr->DynPtr->Position.vy - platformliftdata->upHeight; + downDist = platformliftdata->downHeight - sbPtr->DynPtr->Position.vy; + + if(upDistSBdataptr; + LOCALASSERT(platformliftdata); + LOCALASSERT(sbPtr->DynPtr); + + //check to see if this is a new state , and change any sound playing as necessary + + if(new_state==PLBS_Activating) + { + /* + ignore this state change , since only the host does anything while the lift is + activating , and this will prevent the lift from stopping at the ends correctly + */ + return; + + } + + if((new_state==PLBS_GoingUp || new_state==PLBS_GoingUp) && + !(platformliftdata->state==PLBS_GoingUp || platformliftdata->state==PLBS_GoingDown)) + { + //platform lift has started moving + if(platformliftdata->start_sound) + { + Start_Track_Sound(platformliftdata->start_sound,&sbPtr->DynPtr->Position); + } + } + + platformliftdata->state=new_state; + + +} + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" +typedef struct platform_lift_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + DYNAMICSBLOCK dynamics; + + int activationDelayTimer; + PLATFORMLIFT_STATES state; + + BOOL Enabled; + BOOL OneUse; //if set ,lift becomes disabled after changing position once + + +}PLATFORM_LIFT_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV platformliftdata + +void LoadStrategy_PlatformLift(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + PLATFORMLIFT_BEHAVIOUR_BLOCK *platformliftdata; + PLATFORM_LIFT_SAVE_BLOCK* block = (PLATFORM_LIFT_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourPlatform) return; + + platformliftdata = (PLATFORMLIFT_BEHAVIOUR_BLOCK*)sbPtr->SBdataptr; + + //start copying stuff + + COPYELEMENT_LOAD(activationDelayTimer) + COPYELEMENT_LOAD(state) + COPYELEMENT_LOAD(Enabled) + COPYELEMENT_LOAD(OneUse) + + *sbPtr->DynPtr = block->dynamics; + +} + + +void SaveStrategy_PlatformLift(STRATEGYBLOCK* sbPtr) +{ + PLATFORM_LIFT_SAVE_BLOCK *block; + PLATFORMLIFT_BEHAVIOUR_BLOCK *platformliftdata; + + platformliftdata = (PLATFORMLIFT_BEHAVIOUR_BLOCK*)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + + COPYELEMENT_SAVE(activationDelayTimer) + COPYELEMENT_SAVE(state) + COPYELEMENT_SAVE(Enabled) + COPYELEMENT_SAVE(OneUse) + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + +} diff --git a/3dc/avp/bh_plift.h b/3dc/avp/bh_plift.h new file mode 100644 index 0000000..ba98066 --- /dev/null +++ b/3dc/avp/bh_plift.h @@ -0,0 +1,61 @@ +#include "track.h" +/*------------------------------Patrick 14/3/97----------------------------------- + Header for platform lift stuff + --------------------------------------------------------------------------------*/ + +typedef enum platformlift_states +{ + PLBS_AtRest, + PLBS_Activating, + PLBS_GoingUp, + PLBS_GoingDown, +} PLATFORMLIFT_STATES; + +typedef struct platformlift_behaviour_type +{ + VECTORCH homePosition; + int upHeight; + int downHeight; + int activationDelayTimer; + PLATFORMLIFT_STATES state; + + TRACK_SOUND* sound; + TRACK_SOUND* start_sound; + TRACK_SOUND* end_sound; + + // A switch will set these flags on AssignSBNames + + BOOL Enabled; + BOOL OneUse; //if set ,lift becomes disabled after changing position once + + int netMsgCount; + +} PLATFORMLIFT_BEHAVIOUR_BLOCK; + +typedef struct platformlift_tools_template +{ + struct vectorch position; + struct euler orientation; + int shapeIndex; + int travel; /* vertical distance from start position to end position (down = +ve) */ + BOOL Enabled; + BOOL OneUse; + char nameID[SB_NAME_LENGTH]; + + TRACK_SOUND* sound; + TRACK_SOUND* start_sound; + TRACK_SOUND* end_sound; + +} PLATFORMLIFT_TOOLS_TEMPLATE; + +#define PLATFORMLIFT_SPEED 5000 /* mm/s */ +#define PLATFORMLIFT_ACTIVATIONTIME ((ONE_FIXED*3)>>1) /* fixed point seconds */ +#define PLATFORMLIFT_NUMNETMESSAGES 5 + +void InitialisePlatformLift(void* bhdata, STRATEGYBLOCK *sbPtr); +void PlatformLiftBehaviour(STRATEGYBLOCK *sbPtr); + +void ActivatePlatformLift(STRATEGYBLOCK *sbPtr); +void SendPlatformLiftUp(STRATEGYBLOCK *sbPtr); +void SendPlatformLiftDown(STRATEGYBLOCK *sbPtr); +void StopPlatformLift(STRATEGYBLOCK *sbPtr); diff --git a/3dc/avp/bh_queen.c b/3dc/avp/bh_queen.c new file mode 100644 index 0000000..99cccee --- /dev/null +++ b/3dc/avp/bh_queen.c @@ -0,0 +1,5173 @@ +#define DB_LEVEL 2 + +/*------------------------ChrisF 17/3/98------------------------------- + Source file for Queen AI behaviour functions. One year 30 days after bh_paq. + --------------------------------------------------------------------*/ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "comp_shp.h" +#include "dynblock.h" +#include "dynamics.h" +#include "pfarlocs.h" +#include "pvisible.h" +#include "pheromon.h" +#include "bh_far.h" +#include "bh_pred.h" +#include "bh_paq.h" +#include "bh_queen.h" +#include "bh_debri.h" +#define UseLocalAssert Yes +#include "ourasert.h" +#include "psnd.h" +#include "weapons.h" +#include "extents.h" +#include "sequnces.h" +#include "ShowCmds.h" +#include "targeting.h" +#include "dxlog.h" +#include +#include "db.h" + +#include "los.h" +#include "bh_track.h" +#include "scream.h" + +/* external global variables used in this file */ +extern int ModuleArraySize; +extern char *ModuleCurrVisArray; +extern int NormalFrameTime; +extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); +extern char LevelName[]; +extern unsigned char Null_Name[8]; + +#define QueenAttackRange 3500 + +/*minimum time for flamethrower before queen takes notice*/ +#define QueenMinimumFireTime ONE_FIXED/8 + +static BOOL PlayerInTrench=FALSE; +static BOOL PlayerInLocker=FALSE; +static int AirlockTimeOpen=0; + + + +/*special hangar airlock state stuff*/ +static BOOL UpperAirlockDoorOpen=FALSE; +static BOOL LowerAirlockDoorOpen=FALSE; +static STRATEGYBLOCK* UpperAirlockDoorSbptr=0; +static VECTORCH UpperAirlockDoorStart; +static STRATEGYBLOCK* LowerAirlockDoorSbptr=0; +static VECTORCH LowerAirlockDoorStart; +static STRATEGYBLOCK* LockerDoorSbptr=0; + + +#define QUEEN_MAX_OBJECT 10 +int NumQueenObjects; +STRATEGYBLOCK* QueenObjectList[QUEEN_MAX_OBJECT]; + + +void SetQueenShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime); +void QueenMove_Standby(STRATEGYBLOCK *sbPtr); +void QueenMove_StepForward(STRATEGYBLOCK *sbPtr); +void QueenMove_StepBack(STRATEGYBLOCK *sbPtr); +void QueenMove_TurnLeft(STRATEGYBLOCK *sbPtr); +void QueenMove_TurnRight(STRATEGYBLOCK *sbPtr); +void QueenMove_Walk(STRATEGYBLOCK *sbPtr); +void QueenMove_Taunt(STRATEGYBLOCK *sbPtr); +void QueenMove_Hiss(STRATEGYBLOCK *sbPtr); +void QueenMove_LeftSwipe(STRATEGYBLOCK *sbPtr); +void QueenMove_RightSwipe(STRATEGYBLOCK *sbPtr); +void QueenMove_Charge(STRATEGYBLOCK *sbPtr); +void QueenMove_Close(STRATEGYBLOCK *sbPtr); +void Execute_Queen_Dying(STRATEGYBLOCK *sbPtr); +void KillQueen(STRATEGYBLOCK *sbPtr,DAMAGE_PROFILE *damage, int multiple,SECTION_DATA *Section, VECTORCH *incoming); +void QueenForceReconsider(STRATEGYBLOCK *sbPtr); +static BOOL TargetIsFiringFlamethrowerAtQueen(STRATEGYBLOCK *sbPtr); +static void MakeNonFragable(HMODELCONTROLLER *controller); +static void QueenCalculateTargetInfo(STRATEGYBLOCK *sbPtr); +void HandleHangarAirlock(); + +QUEEN_MANOEUVRE Queen_Next_Command; + +int Queen_Next_Waypoint=0; + +int Queen_Walk_Rate=100000; +int Queen_Walk_Step_Speed=ONE_FIXED/4.5; + +int Queen_Charge_Rate=45000; +int Queen_ButtCharge_Rate=30000; +int Queen_Step_Time=50000; +int Queen_Step_Speed=10000; //16000; +int Queen_Charge_Step_Speed=7500; +int Queen_Step_Mode=1; +int Queen_Turn_Rate=(NPC_TURNRATE>>2); + +#define QUEEN_BUTTCHARGE_SPEED 16000 +#define QUEEN_CHARGE_SPEED 12000 + +#define QUEEN_CLOSE_SPEED 3000 + +#define QUEEN_WALK_SPEED 7000 + +#define QUEEN_THROWN_OBJECT_SPEED 60000 + +extern DAMAGE_PROFILE QueenButtDamage; +extern DAMAGE_PROFILE QueenImpactDamage; +extern DAMAGE_PROFILE VacuumDamage; + +VECTORCH Queen_Target_Point={0,0,0}; + +VECTORCH Queen_Waypoints[] = { + {37361,2900,-51942}, + {32937,2900,-19959}, + {62809,2900,-28509}, + {64658,2900,-13328}, + {64658,0,-13328}, + {64991,2900,-50362}, + {32239,2900,-53578}, + {-1,-1,-1} +}; + +void QComm_Stop(void) { + Queen_Next_Command=QM_Standby; + Queen_Next_Waypoint=-1; +} + +void QComm_StepForward(void) { + Queen_Next_Command=QM_StepForward; +} + +void QComm_StepBack(void) { + Queen_Next_Command=QM_StepBack; +} + +void QComm_TurnLeft(void) { + Queen_Next_Command=QM_TurnLeft; +} + +void QComm_TurnRight(void) { + Queen_Next_Command=QM_TurnRight; +} + +void QComm_Heel(void) { + Queen_Next_Command=QM_ComeToPoint; + Queen_Target_Point=Player->ObStrategyBlock->DynPtr->Position; +} + +void QComm_Taunt(void) { + Queen_Next_Command=QM_Taunt; +} + +void QComm_Hiss(void) { + Queen_Next_Command=QM_Hiss; +} + +void QComm_LeftSwipe(void) { + Queen_Next_Command=QM_LeftSwipe; +} + +void QComm_RightSwipe(void) { + Queen_Next_Command=QM_RightSwipe; +} + +void QComm_Route(void) { + Queen_Next_Command=QM_Standby; + Queen_Next_Waypoint=-2; +} + +void QComm_Charge(void) { + Queen_Next_Command=QM_Charge; + Queen_Target_Point=Player->ObStrategyBlock->DynPtr->Position; +} + +static void QueenSoundHiss(STRATEGYBLOCK* sbPtr) +{ + QUEEN_STATUS_BLOCK *queenStatusPointer; + GLOBALASSERT(sbPtr); + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + if(queenStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) + { + PlayQueenSound(0,QSC_Hiss,0,&queenStatusPointer->soundHandle,&sbPtr->DynPtr->Position); + queenStatusPointer->lastSoundCategory=QSC_Hiss; + } +} + +static void QueenSoundHurt(STRATEGYBLOCK* sbPtr) +{ + QUEEN_STATUS_BLOCK *queenStatusPointer; + GLOBALASSERT(sbPtr); + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + /* + If the queen is currently playing a non-hurt sound then cancel it. + */ + if(queenStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) + { + if(queenStatusPointer->lastSoundCategory!=QSC_Scream_Hurt) + { + Sound_Stop(queenStatusPointer->soundHandle); + } + } + + if(queenStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) + { + PlayQueenSound(0,QSC_Scream_Hurt,0,&queenStatusPointer->soundHandle,&sbPtr->DynPtr->Position); + queenStatusPointer->lastSoundCategory=QSC_Scream_Hurt; + } +} + +static void ThrownObjectBounceNoise(int object_index,VECTORCH* location) +{ + static int QueenObjectSoundHandles[QUEEN_MAX_OBJECT]={SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX,SOUND_NOACTIVEINDEX}; + GLOBALASSERT(location); + + PlayQueenSound(0,QSC_Object_Bounce,0,&QueenObjectSoundHandles[object_index],location); +} + +void InitQueenBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr) +{ + TOOLS_DATA_QUEEN *toolsData; + QUEEN_STATUS_BLOCK *queenStatus; + int i; + + LOCALASSERT(sbPtr); + LOCALASSERT(bhdata); + toolsData = (TOOLS_DATA_QUEEN *)bhdata; + + /* Reset command interface. */ + + Queen_Next_Command=QM_Standby; + + /* check we're not in a net game */ + if(AvP.Network != I_No_Network) + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* make the assumption that the loader has initialised the strategy + block sensibly... + so just set the shapeIndex from the tools data & copy the name id*/ + sbPtr->shapeIndex = toolsData->shapeIndex; + for(i=0;iSBname[i] = toolsData->nameID[i]; + + /* create, initialise and attach a dynamics block */ + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC); + if(sbPtr->DynPtr) + { + EULER zeroEuler = {0,0,0}; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + dynPtr->PrevPosition = dynPtr->Position = toolsData->position; + dynPtr->OrientEuler = zeroEuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + /* zero linear velocity in dynamics block */ + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + + dynPtr->UseDisplacement = 1; + + dynPtr->Displacement.vx = 0; + dynPtr->Displacement.vy = 0; + dynPtr->Displacement.vz = 0; + + dynPtr->Mass=60000; /* No knockback, please. */ + } + else + { + RemoveBehaviourStrategy(sbPtr); + return; + } + + /* Initialise alien's stats */ + { + NPC_DATA *NpcData; + + NpcData=GetThisNpcData(I_NPC_AlienQueen); + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + + + } + /* create, initialise and attach a predator-alien/queen data block */ + sbPtr->SBdataptr = (void *)AllocateMem(sizeof(QUEEN_STATUS_BLOCK)); + if(sbPtr->SBdataptr) + { + SECTION *root_section; + + queenStatus = (QUEEN_STATUS_BLOCK *)sbPtr->SBdataptr; + NPC_InitMovementData(&(queenStatus->moveData)); + NPC_InitWanderData(&(queenStatus->wanderData)); + + sbPtr->integrity = QUEEN_STARTING_HEALTH; + + queenStatus->QueenState=QBS_Reconsider; + queenStatus->current_move=QM_Standby; + queenStatus->next_move=QM_Standby; + queenStatus->fixed_foot=RightFoot; + queenStatus->fixed_foot_section=NULL; //Stupid, but I wouldn't want in uninitialised. + queenStatus->fixed_foot_oldpos.vx=0; + queenStatus->fixed_foot_oldpos.vy=0; + queenStatus->fixed_foot_oldpos.vz=0; + + queenStatus->TargetPos.vx=0; + queenStatus->TargetPos.vy=0; + queenStatus->TargetPos.vz=0; + + + queenStatus->moveTimer = 0; + + for(i=0;ideath_target_ID[i] = toolsData->death_target_ID[i]; + queenStatus->death_target_sbptr=0; + queenStatus->death_target_request=toolsData->death_target_request; + + root_section=GetNamedHierarchyFromLibrary("queen","Template"); + GLOBALASSERT(root_section); + Create_HModel(&queenStatus->HModelController,root_section); + InitHModelSequence(&queenStatus->HModelController, + (int)HMSQT_QueenRightStanceTemplate, + (int)QRSTSS_Standard, + ONE_FIXED); + queenStatus->HModelController.Looped=1; + + queenStatus->attack_delta=Add_Delta_Sequence(&queenStatus->HModelController,"attack", + (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_LeftSwipe,Queen_Step_Time); + queenStatus->attack_delta->Playing=0; + + queenStatus->hit_delta=Add_Delta_Sequence(&queenStatus->HModelController,"hit", + (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_LeftHit,Queen_Step_Time); + queenStatus->attack_delta->Playing=0; + + queenStatus->TempTarget=FALSE; + queenStatus->CurrentQueenObject=-1; + queenStatus->QueenObjectBias=1; + if(!stricmp(LevelName,"hangar")) + { + queenStatus->QueenPlayerBias=1; + } + else + { + //int he predator version , make it more likely for the queen to go after the player + queenStatus->QueenPlayerBias=5; + } + queenStatus->QueenTargetSB=Player->ObStrategyBlock; + queenStatus->QueenTauntTimer=0; + queenStatus->QueenFireTimer=0; + + queenStatus->LastVelocity.vx=0; + queenStatus->LastVelocity.vy=0; + queenStatus->LastVelocity.vz=0; + + queenStatus->BeenInAirlock=FALSE; + queenStatus->QueenActivated=FALSE; + + queenStatus->soundHandle=SOUND_NOACTIVEINDEX; + + + NumQueenObjects=-1; + + if(AvP.PlayerType==I_Marine) + { + MakeNonFragable(&queenStatus->HModelController); + } + + queenStatus->AttackDoneItsDamage = FALSE; + + } + else + { + GLOBALASSERT(0); + RemoveBehaviourStrategy(sbPtr); + return; + } + +} + +static BOOL QueenPlayingStunAnimation(HMODELCONTROLLER* HModelController) +{ + GLOBALASSERT(HModelController); + + return(HModelController->Sequence_Type==HMSQT_QueenGeneral && + HModelController->Sub_Sequence==QGSS_Explosion_Stun && + !HModelAnimation_IsFinished(HModelController)); + +} + +void SetQueenFoot(STRATEGYBLOCK *sbPtr, QUEEN_FOOT foot) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + DISPLAYBLOCK *dPtr; + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + dPtr=sbPtr->SBdptr; + GLOBALASSERT(dPtr); + + ProveHModel(dPtr->HModelControlBlock,dPtr); + + switch (foot) { + case (LeftFoot): + queenStatusPointer->fixed_foot=LeftFoot; + queenStatusPointer->fixed_foot_section=GetThisSectionData(queenStatusPointer->HModelController.section_data, + "left foot"); + GLOBALASSERT(queenStatusPointer->fixed_foot_section); + queenStatusPointer->fixed_foot_oldpos=queenStatusPointer->fixed_foot_section->World_Offset; + break; + case (RightFoot): + queenStatusPointer->fixed_foot=RightFoot; + queenStatusPointer->fixed_foot_section=GetThisSectionData(queenStatusPointer->HModelController.section_data, + "right foot"); + GLOBALASSERT(queenStatusPointer->fixed_foot_section); + queenStatusPointer->fixed_foot_oldpos=queenStatusPointer->fixed_foot_section->World_Offset; + break; + default: + GLOBALASSERT(0); + break; + } + +} + + +void MakeQueenNear(STRATEGYBLOCK *sbPtr) +{ + extern MODULEMAPBLOCK AlienDefaultMap; + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + QUEEN_STATUS_BLOCK *queenStatusPointer= (QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + /* This should only be called once! */ + + LOCALASSERT(queenStatusPointer); + LOCALASSERT(dynPtr); + LOCALASSERT(sbPtr->SBdptr == NULL); + + AlienDefaultMap.MapShape = sbPtr->shapeIndex; + tempModule.m_mapptr = &AlienDefaultMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 0; + tempModule.m_lightarray = (struct lightblock *)0; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr=NULL; + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) { + GLOBALASSERT(0); + } + + sbPtr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbPtr; + dPtr->ObMyModule = NULL; + + + /*Copy extents from the collision extents in extents.c*/ + dPtr->ObMinX=-CollisionExtents[CE_QUEEN].CollisionRadius; + dPtr->ObMaxX=CollisionExtents [CE_QUEEN].CollisionRadius; + dPtr->ObMinZ=-CollisionExtents[CE_QUEEN].CollisionRadius; + dPtr->ObMaxZ=CollisionExtents [CE_QUEEN].CollisionRadius; + dPtr->ObMinY=CollisionExtents [CE_QUEEN].CrouchingTop; + dPtr->ObMaxY=CollisionExtents [CE_QUEEN].Bottom; + dPtr->ObRadius = 1000; + /* also need to initialise positional information in the new display block, + from the existing dynamics block. + NB this necessary because this function is (usually) called between the + dynamics and rendering systems so it is not initialised by the dynamics + system the first frame it is drawn. */ + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + + /* init state timers */ + + /* zero linear velocity in dynamics block */ + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + + /* initialise our sequence data */ + dPtr->HModelControlBlock=&queenStatusPointer->HModelController; + + SetQueenFoot(sbPtr,RightFoot); + + /* Calls ProveHModel. */ + +} + +void MakeQueenFar(STRATEGYBLOCK *sbPtr) { + + /* get the queen's status block */ + int i; + QUEEN_STATUS_BLOCK *queenStatusPointer= (QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + LOCALASSERT(sbPtr); + LOCALASSERT(queenStatusPointer); + LOCALASSERT(sbPtr->SBdptr != NULL); + + /* get rid of the displayblock */ + if(sbPtr->SBdptr) + { + i = DestroyActiveObject(sbPtr->SBdptr); + LOCALASSERT(i==0); + sbPtr->SBdptr = NULL; + } + + /* zero linear velocity in dynamics block */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + +} + + +void SetQueenMovement_FromFoot(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + VECTORCH delta_offset,real_pos; + DISPLAYBLOCK *dPtr; + + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + dPtr=sbPtr->SBdptr; + GLOBALASSERT(dPtr); + + real_pos=queenStatusPointer->fixed_foot_section->World_Offset; + + ProveHModel(dPtr->HModelControlBlock,dPtr); + + delta_offset.vx=queenStatusPointer->fixed_foot_oldpos.vx-queenStatusPointer->fixed_foot_section->World_Offset.vx; + delta_offset.vy=0;//queenStatusPointer->fixed_foot_oldpos.vy-queenStatusPointer->fixed_foot_section->World_Offset.vy; + delta_offset.vz=queenStatusPointer->fixed_foot_oldpos.vz-queenStatusPointer->fixed_foot_section->World_Offset.vz; + + #if 1 + delta_offset.vx=DIV_FIXED(delta_offset.vx,NormalFrameTime); + delta_offset.vy=0;//DIV_FIXED(delta_offset.vy,NormalFrameTime); + delta_offset.vz=DIV_FIXED(delta_offset.vz,NormalFrameTime); + + sbPtr->DynPtr->LinVelocity.vx=delta_offset.vx; + sbPtr->DynPtr->LinVelocity.vy=delta_offset.vy; + sbPtr->DynPtr->LinVelocity.vz=delta_offset.vz; + + { + int facex; + int facez; + facex=sbPtr->DynPtr->OrientMat.mat31; + facez=sbPtr->DynPtr->OrientMat.mat33; + + if((MUL_FIXED(facex,sbPtr->DynPtr->LinVelocity.vx)+MUL_FIXED(facez,sbPtr->DynPtr->LinVelocity.vz))<0) + { + //don't want queen to move backwards + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + switch (queenStatusPointer->fixed_foot) + { + case (LeftFoot): + SetQueenFoot(sbPtr,LeftFoot); + break; + case (RightFoot): + SetQueenFoot(sbPtr,RightFoot); + break; + default: + GLOBALASSERT(0); + break; + } + + } + + } + #elif 1 + sbPtr->DynPtr->Displacement.vx = delta_offset.vx; + sbPtr->DynPtr->Displacement.vy = delta_offset.vy; + sbPtr->DynPtr->Displacement.vz = delta_offset.vz; + + //PrintDebuggingText("Displacement = %d %d %d\n",delta_offset.vx,delta_offset.vy,delta_offset.vz); + // + //LOGDXFMT(("New Foot Frame.\nFoot OldPos = %d %d %d.\nFoot NewPos = %d %d %d\nFoot Current Pos = %d %d %d.\nDisplacement = %d %d %d.\n\n", + // queenStatusPointer->fixed_foot_oldpos.vx,queenStatusPointer->fixed_foot_oldpos.vy,queenStatusPointer->fixed_foot_oldpos.vz, + // real_pos.vx,real_pos.vy,real_pos.vz, + // queenStatusPointer->fixed_foot_section->World_Offset.vx,queenStatusPointer->fixed_foot_section->World_Offset.vy, + // queenStatusPointer->fixed_foot_section->World_Offset.vz,delta_offset.vx,delta_offset.vy,delta_offset.vz)); + // + //sbPtr->DynPtr->Displacement.vx = 0; + //sbPtr->DynPtr->Displacement.vy = 0; + //sbPtr->DynPtr->Displacement.vz = 200; + + #else + sbPtr->DynPtr->Position.vx += delta_offset.vx; + sbPtr->DynPtr->Position.vy += delta_offset.vy; + sbPtr->DynPtr->Position.vz += delta_offset.vz; + + #endif +} + +void QueenMove_Standby(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + + /* Verify correct sequence. */ + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + if(queenStatusPointer->PlayingHitDelta) + { + if(QueenPlayingStunAnimation(&queenStatusPointer->HModelController)) + { + //queen is in the process of playing stun animation + return; + } + } + + if(queenStatusPointer->moveTimer==0) + { + //start tweening to standing position + switch(queenStatusPointer->fixed_foot) + { + case (LeftFoot) : + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceTemplate, + (int)QLSTSS_Standard,-1,ONE_FIXED>>2); + break; + case (RightFoot) : + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceTemplate, + (int)QRSTSS_Standard,-1,ONE_FIXED>>2); + break; + default: + GLOBALASSERT(0); + break; + } + queenStatusPointer->moveTimer=1; + } + +} + +void QueenMove_StepForward(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + + /* First movement function. */ + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(queenStatusPointer->current_move==QM_StepForward); + + if (queenStatusPointer->moveTimer==0) { + /* Do setup. */ + int tweeiningtime=(ONE_FIXED>>3); + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,LeftFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceTemplate, + (int)QLSTSS_Forward_L2R,Queen_Step_Time,tweeiningtime); + break; + case (RightFoot): + SetQueenFoot(sbPtr,RightFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceTemplate, + (int)QRSTSS_Forward_R2L,Queen_Step_Time,tweeiningtime); + break; + default: + GLOBALASSERT(0); + break; + } + } + + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) { + GLOBALASSERT(queenStatusPointer->HModelController.Looped==0); + } + + /* Now... move forward? */ + + SetQueenMovement_FromFoot(sbPtr); + + if ((queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(queenStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) { + queenStatusPointer->current_move=QM_Standby; + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,RightFoot); + break; + case (RightFoot): + SetQueenFoot(sbPtr,LeftFoot); + break; + default: + GLOBALASSERT(0); + break; + } + } + + queenStatusPointer->moveTimer+=NormalFrameTime; + +} + +void QueenMove_StepBack(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + + /* First movement function. */ + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(queenStatusPointer->current_move==QM_StepBack); + + if (queenStatusPointer->moveTimer==0) { + /* Do setup. */ + int tweeiningtime=(ONE_FIXED>>3); + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,RightFoot); + /* Wrong Foot w.r.t. Forward. */ + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceFull, + (int)QLSFSS_Backward_L2R,Queen_Step_Time,tweeiningtime); + break; + case (RightFoot): + SetQueenFoot(sbPtr,LeftFoot); + /* Wrong Foot w.r.t. Forward. */ + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceFull, + (int)QRSFSS_Backward_R2L,Queen_Step_Time,tweeiningtime); + break; + default: + GLOBALASSERT(0); + break; + } + } + + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) { + GLOBALASSERT(queenStatusPointer->HModelController.Looped==0); + } + + /* Now... move forward? */ + + SetQueenMovement_FromFoot(sbPtr); + + queenStatusPointer->moveTimer+=NormalFrameTime; + + if ((queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(queenStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) { + queenStatusPointer->current_move=QM_Standby; + /* Already changed foot. */ + } + + +} + +void QueenMove_TurnLeft(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + + /* First movement function. */ + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(queenStatusPointer->current_move==QM_TurnLeft); + + if (queenStatusPointer->moveTimer==0) { + /* Do setup. */ + int tweeiningtime=(ONE_FIXED>>3); + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,LeftFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceFull, + (int)QLSFSS_Forward_L2R,Queen_Step_Time,tweeiningtime); + break; + case (RightFoot): + SetQueenFoot(sbPtr,RightFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceFull, + (int)QRSFSS_Forward_R2L,Queen_Step_Time,tweeiningtime); + break; + default: + GLOBALASSERT(0); + break; + } + } + + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) { + GLOBALASSERT(queenStatusPointer->HModelController.Looped==0); + } + + /* Now... turn left. */ + + { + + VECTORCH left90; + DISPLAYBLOCK *dPtr; + + dPtr=sbPtr->SBdptr; + GLOBALASSERT(dPtr); + + ProveHModel(dPtr->HModelControlBlock,dPtr); + + left90.vx=-sbPtr->DynPtr->OrientMat.mat11; + left90.vy=-sbPtr->DynPtr->OrientMat.mat12; + left90.vz=-sbPtr->DynPtr->OrientMat.mat13; + + #if 1 + NPCOrientateToVector(sbPtr, &left90,Queen_Turn_Rate,NULL); + + SetQueenMovement_FromFoot(sbPtr); + #else + { + VECTORCH localOffset; + VECTORCH version1,version2; + //MATRIXCH WtoL; + + ProveHModel(dPtr->HModelControlBlock,dPtr); + + localOffset.vx=queenStatusPointer->fixed_foot_section->World_Offset.vx-sbPtr->DynPtr->Position.vx; + localOffset.vy=queenStatusPointer->fixed_foot_section->World_Offset.vy-sbPtr->DynPtr->Position.vy; + localOffset.vz=queenStatusPointer->fixed_foot_section->World_Offset.vz-sbPtr->DynPtr->Position.vz; + + //WtoL=sbPtr->DynPtr->OrientMat; + //TransposeMatrixCH(&WtoL); + + //RotateVector(&localOffset,&WtoL); + + PrintDebuggingText("localOffset = %d %d %d\n",localOffset.vx, + localOffset.vy,localOffset.vz); + + NPCOrientateToVector(sbPtr, &left90,Queen_Turn_Rate,&localOffset); + + //version1=sbPtr->DynPtr->Displacement; + //SetQueenMovement_FromFoot(sbPtr); + //version2=sbPtr->DynPtr->Displacement; + // + //LOGDXFMT(("Displacement V1 = %d %d %d\nDisplacement V2 = %d %d %d\n", + // version1.vx,version1.vy,version1.vz, + // version2.vx,version2.vy,version2.vz)); + } + #endif + + } + + if ((queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(queenStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) { + + queenStatusPointer->current_move=QM_Standby; + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,RightFoot); + break; + case (RightFoot): + SetQueenFoot(sbPtr,LeftFoot); + break; + default: + GLOBALASSERT(0); + break; + } + } + + queenStatusPointer->moveTimer+=NormalFrameTime; + +} + +void QueenMove_TurnRight(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + + /* First movement function. */ + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(queenStatusPointer->current_move==QM_TurnRight); + + if (queenStatusPointer->moveTimer==0) { + /* Do setup. */ + int tweeiningtime=(ONE_FIXED>>3); + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,LeftFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceFull, + (int)QLSFSS_Forward_L2R,Queen_Step_Time,tweeiningtime); + break; + case (RightFoot): + SetQueenFoot(sbPtr,RightFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceFull, + (int)QRSFSS_Forward_R2L,Queen_Step_Time,tweeiningtime); + break; + default: + GLOBALASSERT(0); + break; + } + } + + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) { + GLOBALASSERT(queenStatusPointer->HModelController.Looped==0); + } + + /* Now... turn right. */ + + { + + VECTORCH right90; + DISPLAYBLOCK *dPtr; + + dPtr=sbPtr->SBdptr; + GLOBALASSERT(dPtr); + + ProveHModel(dPtr->HModelControlBlock,dPtr); + + right90.vx=sbPtr->DynPtr->OrientMat.mat11; + right90.vy=sbPtr->DynPtr->OrientMat.mat12; + right90.vz=sbPtr->DynPtr->OrientMat.mat13; + + NPCOrientateToVector(sbPtr, &right90,Queen_Turn_Rate,NULL); + + SetQueenMovement_FromFoot(sbPtr); + + } + + if ((queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(queenStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) { + + queenStatusPointer->current_move=QM_Standby; + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,RightFoot); + break; + case (RightFoot): + SetQueenFoot(sbPtr,LeftFoot); + break; + default: + GLOBALASSERT(0); + break; + } + } + + queenStatusPointer->moveTimer+=NormalFrameTime; + +} + +void SetQueenShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime) +{ + + QUEEN_STATUS_BLOCK *queenStatus=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(length!=0); + + if (tweeningtime<=0) { + InitHModelSequence(&queenStatus->HModelController,(int)type,subtype,length); + queenStatus->HModelController.Looped=0; + } else { + InitHModelTweening(&queenStatus->HModelController, tweeningtime, (int)type,subtype,length, 0); + queenStatus->HModelController.Looped=0; + } +} + +void QueenMove_ComeToPoint(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + VECTORCH vectotarget; + + /* Complex movement function. */ + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(queenStatusPointer->current_move==QM_ComeToPoint); + + if (queenStatusPointer->moveTimer==0) { + /* Do setup. */ + int tweeiningtime=0; + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,LeftFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceFull, + (int)QLSFSS_Forward_L2R,Queen_Step_Time,tweeiningtime); + break; + case (RightFoot): + SetQueenFoot(sbPtr,RightFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceFull, + (int)QRSFSS_Forward_R2L,Queen_Step_Time,tweeiningtime); + break; + default: + GLOBALASSERT(0); + break; + } + } + + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) { + GLOBALASSERT(queenStatusPointer->HModelController.Looped==0); + } + + vectotarget.vx=queenStatusPointer->TargetPos.vx-sbPtr->DynPtr->Position.vx; + vectotarget.vy=queenStatusPointer->TargetPos.vy-sbPtr->DynPtr->Position.vy; + vectotarget.vz=queenStatusPointer->TargetPos.vz-sbPtr->DynPtr->Position.vz; + + /* Now... turn to face. */ + + { + + DISPLAYBLOCK *dPtr; + + dPtr=sbPtr->SBdptr; + GLOBALASSERT(dPtr); + + ProveHModel(dPtr->HModelControlBlock,dPtr); + + NPCOrientateToVector(sbPtr, &vectotarget,Queen_Turn_Rate,NULL); + + SetQueenMovement_FromFoot(sbPtr); + + } + + + queenStatusPointer->moveTimer+=NormalFrameTime; + + if ((queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(queenStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) { + + int range; + /* Comsider next step. */ + + range=Approximate3dMagnitude(&vectotarget); + + if (range<5000) { + queenStatusPointer->current_move=QM_Standby; + } else { + queenStatusPointer->moveTimer=0; + } + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,RightFoot); + break; + case (RightFoot): + SetQueenFoot(sbPtr,LeftFoot); + break; + default: + GLOBALASSERT(0); + break; + } + } + +} + +#if 1 +void QueenMove_Walk(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + BOOL ChangingFoot=FALSE; + + /* Very complex movement function... */ + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(queenStatusPointer->current_move==QM_ComeToPoint); + + if (queenStatusPointer->moveTimer==0) { + /* Do setup. */ + int tweeiningtime=(Queen_Step_Time>>2); + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,LeftFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, + (int)QGSS_Walk,-1,tweeiningtime); + queenStatusPointer->HModelController.LoopAfterTweening=1; + queenStatusPointer->moveTimer=1; /* It's something of a state flag here. */ + + break; + case (RightFoot): + /* Argh! Can't start from right foot! */ + queenStatusPointer->current_move=QM_Close; + queenStatusPointer->moveTimer=0; + queenStatusPointer->next_move=QM_ComeToPoint; + return; + break; + default: + GLOBALASSERT(0); + break; + } + } + + + /* Check for change foot? */ + + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) { + if (queenStatusPointer->HModelController.keyframe_flags) + { + if (queenStatusPointer->HModelController.keyframe_flags & 1) + { + SetQueenFoot(sbPtr,LeftFoot); + ChangingFoot=TRUE; + } + if (queenStatusPointer->HModelController.keyframe_flags & 2) + { + SetQueenFoot(sbPtr,RightFoot); + ChangingFoot=TRUE; + } + if(queenStatusPointer->moveTimer==1) queenStatusPointer->moveTimer=3; + } + + HModel_SetToolsRelativeSpeed(&queenStatusPointer->HModelController,(512*ONE_FIXED)/QUEEN_WALK_SPEED); + + } + + /* Now... turn to face. */ + + { + + DISPLAYBLOCK *dPtr; + + dPtr=sbPtr->SBdptr; + GLOBALASSERT(dPtr); + + //ProveHModel(dPtr->HModelControlBlock,dPtr); + + NPCOrientateToVector(sbPtr, &queenStatusPointer->VectToTarget,Queen_Turn_Rate,NULL); + + //SetQueenMovement_FromFoot(sbPtr); + + if (queenStatusPointer->moveTimer!=2) + { + if(queenStatusPointer->moveTimer==1) + { + SetQueenMovement_FromFoot(sbPtr); + } + else + { + VECTORCH velocity; + int walkSpeed; + + velocity.vx=sbPtr->DynPtr->OrientMat.mat31; + velocity.vy=0; + velocity.vz=sbPtr->DynPtr->OrientMat.mat33; + + if ( (velocity.vx==0) && (velocity.vy==0) && (velocity.vz==0) ) { + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + return; + } + + Normalise(&velocity); + + //walkSpeed=DIV_FIXED(Queen_Walk_Step_Speed,Queen_Walk_Rate); + + sbPtr->DynPtr->LinVelocity.vx = MUL_FIXED(velocity.vx,QUEEN_WALK_SPEED); + sbPtr->DynPtr->LinVelocity.vy = MUL_FIXED(velocity.vy,QUEEN_WALK_SPEED); + sbPtr->DynPtr->LinVelocity.vz = MUL_FIXED(velocity.vz,QUEEN_WALK_SPEED); + } + + } + + + } + + /* Consider exit state. */ + + if ((queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(queenStatusPointer->moveTimer==2)) { + + /* Finished coming to a stop. */ + + queenStatusPointer->current_move=QM_Standby; + queenStatusPointer->next_move=QM_Standby; + queenStatusPointer->moveTimer=0; + + switch (queenStatusPointer->fixed_foot) { + case (RightFoot): + SetQueenFoot(sbPtr,RightFoot); + break; + case (LeftFoot): + SetQueenFoot(sbPtr,LeftFoot); + break; + default: + GLOBALASSERT(0); + break; + } + + /* Would you believe the end's in the middle? :-) */ + + } + + + //only check for exiting charge , when changing foot + { + int range; + QueenCalculateTargetInfo(sbPtr); + range=queenStatusPointer->TargetDistance; + + if(range<3000) + { + queenStatusPointer->next_move=QM_Close; + } + if(ChangingFoot) + { + if(queenStatusPointer->PlayingHitDelta) + { + queenStatusPointer->HModelController.Playing=0; + queenStatusPointer->current_move=QM_Standby; + queenStatusPointer->moveTimer=0; + queenStatusPointer->next_move=QM_Standby; + return; + } + + if(queenStatusPointer->moveTimer!=2) + { + + if (queenStatusPointer->next_move!=QM_Standby && queenStatusPointer->next_move!=QM_ComeToPoint) + { + //exit without tweening to stopped position + queenStatusPointer->HModelController.Playing=0; + queenStatusPointer->current_move=queenStatusPointer->next_move; + queenStatusPointer->next_move=QM_Standby; + queenStatusPointer->moveTimer=0; + + } + #if 0 + else if(range<3000) + { + //come to a stop + /* Begin exit. */ + int tweeiningtime=(Queen_Step_Time>>2); + + queenStatusPointer->moveTimer=2; /* It's something of a state flag here. */ + + switch (queenStatusPointer->fixed_foot) { + case (RightFoot): + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceTemplate, + (int)QRSTSS_Standard,(Queen_Step_Time<<1),tweeiningtime); + break; + case (LeftFoot): + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceTemplate, + (int)QLSTSS_Standard,(Queen_Step_Time<<1),tweeiningtime); + break; + default: + GLOBALASSERT(0); + break; + } + + queenStatusPointer->HModelController.LoopAfterTweening=0; + } + #endif + else if(range>10000 && queenStatusPointer->fixed_foot==LeftFoot && !PlayerInTrench) + { + //go into a charge + queenStatusPointer->current_move=QM_Charge; + queenStatusPointer->next_move=QM_Standby; + queenStatusPointer->moveTimer=0; + + } + if(range<5000) + { + /*if the queen is near but facing the wrong way need to go into close mode + (turning circle is too large in walk mode) */ + + + if (queenStatusPointer->TargetDirection.vzTargetDirection.vx || + queenStatusPointer->TargetDirection.vz<-queenStatusPointer->TargetDirection.vx) + { + + //need to switch to close mode + queenStatusPointer->HModelController.Playing=0; + queenStatusPointer->current_move=QM_Close; + queenStatusPointer->moveTimer=0; + queenStatusPointer->next_move=QM_Standby; + return; + } + } + + } + } + } + +} +#else +void QueenMove_Walk(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + VECTORCH vectotarget; + + /* Very complex movement function... */ + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(queenStatusPointer->current_move==QM_ComeToPoint); + + if (queenStatusPointer->moveTimer==0) { + /* Do setup. */ + int tweeiningtime=(Queen_Step_Time>>2); + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,LeftFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, + (int)QGSS_Walk,(Queen_Step_Time<<1),tweeiningtime); + queenStatusPointer->HModelController.LoopAfterTweening=1; + queenStatusPointer->moveTimer=1; /* It's something of a state flag here. */ + break; + case (RightFoot): + /* Argh! Can't start from right foot! */ + queenStatusPointer->current_move=QM_StepForward; + queenStatusPointer->moveTimer=0; + queenStatusPointer->next_move=QM_ComeToPoint; + return; + break; + default: + GLOBALASSERT(0); + break; + } + } + + vectotarget.vx=queenStatusPointer->TargetPos.vx-sbPtr->DynPtr->Position.vx; + vectotarget.vy=queenStatusPointer->TargetPos.vy-sbPtr->DynPtr->Position.vy; + vectotarget.vz=queenStatusPointer->TargetPos.vz-sbPtr->DynPtr->Position.vz; + + /* Check for change foot? */ + + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) { + if (queenStatusPointer->HModelController.keyframe_flags) { + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,RightFoot); + break; + case (RightFoot): + SetQueenFoot(sbPtr,LeftFoot); + break; + default: + GLOBALASSERT(0); + break; + } + } + } + + /* Now... turn to face. */ + + { + + DISPLAYBLOCK *dPtr; + + dPtr=sbPtr->SBdptr; + GLOBALASSERT(dPtr); + + ProveHModel(dPtr->HModelControlBlock,dPtr); + + NPCOrientateToVector(sbPtr, &vectotarget,Queen_Turn_Rate,NULL); + + SetQueenMovement_FromFoot(sbPtr); + + } + + /* Consider exit state. */ + + if ((queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(queenStatusPointer->moveTimer==2)) { + + /* We must have finished. */ + + queenStatusPointer->current_move=QM_Standby; + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,RightFoot); + break; + case (RightFoot): + SetQueenFoot(sbPtr,LeftFoot); + break; + default: + GLOBALASSERT(0); + break; + } + + /* Would you believe the end's in the middle? :-) */ + + } + + + { + int range; + + range=Approximate3dMagnitude(&vectotarget); + + if ((range<5000)&&(queenStatusPointer->moveTimer!=2)) { + /* Begin exit. */ + int tweeiningtime=(Queen_Step_Time>>2); + + queenStatusPointer->moveTimer=2; /* It's something of a state flag here. */ + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceTemplate, + (int)QRSTSS_Standard,(Queen_Step_Time<<1),tweeiningtime); + break; + case (RightFoot): + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceTemplate, + (int)QLSTSS_Standard,(Queen_Step_Time<<1),tweeiningtime); + break; + default: + GLOBALASSERT(0); + break; + } + + queenStatusPointer->HModelController.LoopAfterTweening=0; + } else if (queenStatusPointer->moveTimer!=2) { + queenStatusPointer->moveTimer=1; /* It's something of a state flag here. */ + } + } + + #if 0 + if ((queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(queenStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) { + + int range; + /* Comsider next step. */ + + range=Approximate3dMagnitude(&vectotarget); + + if (range<5000) { + queenStatusPointer->current_move=QM_Standby; + } else { + queenStatusPointer->moveTimer=0; + } + + } + #endif + +} +#endif + +void QueenMove_Taunt(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + + /* First movement function. */ + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(queenStatusPointer->current_move==QM_Taunt); + + if (queenStatusPointer->moveTimer==0) { + /* Do setup. */ + int tweeiningtime=(ONE_FIXED>>3); + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,LeftFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceFull, + (int)QLSFSS_Taunt,-1,tweeiningtime); + break; + case (RightFoot): + SetQueenFoot(sbPtr,RightFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceFull, + (int)QRSFSS_Taunt,-1,tweeiningtime); + break; + default: + GLOBALASSERT(0); + break; + } + + + } + + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) { + GLOBALASSERT(queenStatusPointer->HModelController.Looped==0); + } + + /* Now... move forward? */ + + SetQueenMovement_FromFoot(sbPtr); + + if ((queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(queenStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) { + + queenStatusPointer->current_move=QM_Standby; + + /* Same foot. */ + + } + + queenStatusPointer->moveTimer+=NormalFrameTime; + +} + +void QueenMove_Hiss(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + + /* First movement function. */ + + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(queenStatusPointer->current_move==QM_Hiss); + + if (queenStatusPointer->moveTimer==0) { + /* Do setup. */ + int tweeiningtime=(ONE_FIXED>>3); + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,LeftFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceFull, + (int)QLSFSS_Standard_Hiss,Queen_Step_Time,tweeiningtime); + queenStatusPointer->HModelController.LoopAfterTweening=1; + break; + case (RightFoot): + SetQueenFoot(sbPtr,RightFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceFull, + (int)QRSFSS_Standard_Hiss,Queen_Step_Time,tweeiningtime); + queenStatusPointer->HModelController.LoopAfterTweening=1; + break; + default: + GLOBALASSERT(0); + break; + } + } + + /* + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + { + GLOBALASSERT(queenStatusPointer->HModelController.Looped==0); + } + */ + + + + /* Now... move forward? */ + + SetQueenMovement_FromFoot(sbPtr); + + #if 0 + if ((queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(queenStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) { + + queenStatusPointer->current_move=QM_Hiss; + + /* Same foot. */ + + } + #endif + queenStatusPointer->moveTimer+=NormalFrameTime; + +} + +void QueenMove_LeftSwipe(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + + /* First movement function. */ + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(queenStatusPointer->current_move==QM_LeftSwipe); + + if (queenStatusPointer->moveTimer==0) { + /* Do setup. */ + int tweeiningtime=(ONE_FIXED>>3); + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,LeftFoot); + //SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceTemplate, + // (int)QLSTSS_Forward_L2R,Queen_Step_Time,tweeiningtime); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceFull, + (int)QLSFSS_Standard_Hiss,Queen_Step_Time,tweeiningtime); + + Start_Delta_Sequence(queenStatusPointer->attack_delta, + (int)HMSQT_QueenLeftStanceTemplate,(int)QLSTSS_LeftSwipe,Queen_Step_Time); + queenStatusPointer->attack_delta->Playing=1; + + break; + case (RightFoot): + SetQueenFoot(sbPtr,RightFoot); + //SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceTemplate, + // (int)QRSTSS_Forward_R2L,Queen_Step_Time,tweeiningtime); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceFull, + (int)QRSFSS_Standard_Hiss,Queen_Step_Time,tweeiningtime); + + Start_Delta_Sequence(queenStatusPointer->attack_delta, + (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_LeftSwipe,Queen_Step_Time); + queenStatusPointer->attack_delta->Playing=1; + + break; + default: + GLOBALASSERT(0); + break; + } + } + + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) { + GLOBALASSERT(queenStatusPointer->HModelController.Looped==0); + } + + /* Now... move forward? */ + + SetQueenMovement_FromFoot(sbPtr); + + if ((queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(queenStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) { + + queenStatusPointer->current_move=QM_Standby; + + } + + queenStatusPointer->moveTimer+=NormalFrameTime; + +} + +void QueenMove_RightSwipe(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + + /* First movement function. */ + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(queenStatusPointer->current_move==QM_RightSwipe); + + if (queenStatusPointer->moveTimer==0) { + /* Do setup. */ + int tweeiningtime=(ONE_FIXED>>3); + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,LeftFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceFull, + (int)QLSFSS_Standard_Hiss,Queen_Step_Time,tweeiningtime); + + Start_Delta_Sequence(queenStatusPointer->attack_delta, + (int)HMSQT_QueenLeftStanceTemplate,(int)QLSTSS_RightSwipe,Queen_Step_Time); + queenStatusPointer->attack_delta->Playing=1; + + break; + case (RightFoot): + SetQueenFoot(sbPtr,RightFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceFull, + (int)QRSFSS_Standard_Hiss,Queen_Step_Time,tweeiningtime); + + Start_Delta_Sequence(queenStatusPointer->attack_delta, + (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_RightSwipe,Queen_Step_Time); + queenStatusPointer->attack_delta->Playing=1; + + break; + default: + GLOBALASSERT(0); + break; + } + } + + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) { + GLOBALASSERT(queenStatusPointer->HModelController.Looped==0); + } + + /* Now... move forward? */ + + SetQueenMovement_FromFoot(sbPtr); + + if ((queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(queenStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) { + + queenStatusPointer->current_move=QM_Standby; + + } + + queenStatusPointer->moveTimer+=NormalFrameTime; + +} + +void QueenMove_Charge(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + BOOL ChangingFoot=FALSE; + + /* Very different movement function... */ + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(queenStatusPointer->current_move==QM_Charge); + + /* Charge at the player. */ + if(!queenStatusPointer->TempTarget) + { + // queenStatusPointer->TargetPos=Player->ObStrategyBlock->DynPtr->Position; + queenStatusPointer->TargetPos=queenStatusPointer->QueenTargetSB->DynPtr->Position; + } + + + + if (queenStatusPointer->moveTimer==0) + { + /* Do setup. */ + int tweeiningtime=(Queen_Step_Time>>2); + + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,LeftFoot); + + { + //which version of sprint should we use + if(DeltaAnimation_IsFinished(queenStatusPointer->attack_delta)) + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, + (int)QGSS_Sprint_Full,-1,tweeiningtime); + else + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, + (int)QGSS_Sprint,-1,tweeiningtime); + + queenStatusPointer->HModelController.LoopAfterTweening=1; + queenStatusPointer->moveTimer=1; /* It's something of a state flag here. */ + } + + break; + case (RightFoot): + /* Argh! Can't start from right foot! */ + queenStatusPointer->current_move=QM_Close; + queenStatusPointer->moveTimer=0; + queenStatusPointer->next_move=QM_Charge; + return; + break; + default: + GLOBALASSERT(0); + break; + } + + queenStatusPointer->SwerveTimer=(ONE_FIXED/2)+(FastRandom() & 0xffff)*2; + return; + } + + /* Check for change foot? */ + + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) { + if (queenStatusPointer->HModelController.keyframe_flags) + { + if (queenStatusPointer->HModelController.keyframe_flags & 1) + { + SetQueenFoot(sbPtr,LeftFoot); + ChangingFoot=TRUE; + } + if (queenStatusPointer->HModelController.keyframe_flags & 2) + { + SetQueenFoot(sbPtr,RightFoot); + ChangingFoot=TRUE; + } + + if(queenStatusPointer->moveTimer==1) queenStatusPointer->moveTimer=3; + } + HModel_SetToolsRelativeSpeed(&queenStatusPointer->HModelController,(512*ONE_FIXED)/QUEEN_CHARGE_SPEED); + + } + + /* Now... turn to face. */ + + if (queenStatusPointer->moveTimer!=2) { + + DISPLAYBLOCK *dPtr; + + dPtr=sbPtr->SBdptr; + GLOBALASSERT(dPtr); + + ProveHModel(dPtr->HModelControlBlock,dPtr); + + #if 1 + { + VECTORCH v; + if(queenStatusPointer->QueenTargetSB==Player->ObStrategyBlock && !queenStatusPointer->TempTarget && queenStatusPointer->TargetDistance>5000) + { + //if charging at player don't go in a straight line + #define QUEEN_COS 63302 + #define QUEEN_SIN 16961 + if(queenStatusPointer->SwerveDirection) + { + v.vx=MUL_FIXED(queenStatusPointer->VectToTarget.vx,QUEEN_COS)+MUL_FIXED(queenStatusPointer->VectToTarget.vz,QUEEN_SIN); + v.vy=0; + v.vz=MUL_FIXED(queenStatusPointer->VectToTarget.vz,QUEEN_COS)-MUL_FIXED(queenStatusPointer->VectToTarget.vx,QUEEN_SIN); + } + else + { + v.vx=MUL_FIXED(queenStatusPointer->VectToTarget.vx,QUEEN_COS)-MUL_FIXED(queenStatusPointer->VectToTarget.vz,QUEEN_SIN); + v.vy=0; + v.vz=MUL_FIXED(queenStatusPointer->VectToTarget.vz,QUEEN_COS)+MUL_FIXED(queenStatusPointer->VectToTarget.vx,QUEEN_SIN); + } + + queenStatusPointer->SwerveTimer-=NormalFrameTime; + if(queenStatusPointer->SwerveTimer<=0) + { + //alter swerve direction , and keep it for the next .5 to 2.5 seconds + queenStatusPointer->SwerveTimer=(ONE_FIXED/2)+(FastRandom() & 0xffff)*2; + queenStatusPointer->SwerveDirection=!queenStatusPointer->SwerveDirection; + } + } + else + { + v=queenStatusPointer->VectToTarget; + } + NPCOrientateToVector(sbPtr, &v,Queen_Turn_Rate,NULL); + + //NPCOrientateToVector(sbPtr, &queenStatusPointer->VectToTarget,Queen_Turn_Rate,NULL); + } + /* Now, just a normal lin velocity. */ + { + if(queenStatusPointer->moveTimer==1) + { + SetQueenMovement_FromFoot(sbPtr); + } + else + { + VECTORCH velocity; + + velocity.vx=sbPtr->DynPtr->OrientMat.mat31; + velocity.vy=0; + velocity.vz=sbPtr->DynPtr->OrientMat.mat33; + + if ( (velocity.vx==0) && (velocity.vy==0) && (velocity.vz==0) ) { + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + return; + } + + + Normalise(&velocity); + + + sbPtr->DynPtr->LinVelocity.vx = MUL_FIXED(velocity.vx,QUEEN_CHARGE_SPEED); + sbPtr->DynPtr->LinVelocity.vy = MUL_FIXED(velocity.vy,QUEEN_CHARGE_SPEED); + sbPtr->DynPtr->LinVelocity.vz = MUL_FIXED(velocity.vz,QUEEN_CHARGE_SPEED); + } + } + + #else + NPCOrientateToVector(sbPtr, &vectotarget,Queen_Turn_Rate,NULL); + SetQueenMovement_FromFoot(sbPtr); + #endif + } + + /* Consider exit state. */ + + if ((queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(queenStatusPointer->moveTimer==2)) { + + /* We must have finished. */ + + queenStatusPointer->current_move=QM_Standby; + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,RightFoot); + break; + case (RightFoot): + SetQueenFoot(sbPtr,LeftFoot); + break; + default: + GLOBALASSERT(0); + break; + } + + /* Would you believe the end's in the middle? :-) */ + + } + + + if(ChangingFoot) + { + + QueenCalculateTargetInfo(sbPtr); + + if(queenStatusPointer->PlayingHitDelta) + { + queenStatusPointer->HModelController.Playing=0; + queenStatusPointer->current_move=QM_Standby; + queenStatusPointer->moveTimer=0; + queenStatusPointer->next_move=QM_Standby; + return; + } + //only check for exiting charge , when changing foot + { + /* Only charge if we're facing the right way. */ + + + if (queenStatusPointer->TargetDirection.vzTargetDirection.vx || + queenStatusPointer->TargetDirection.vz<-queenStatusPointer->TargetDirection.vx) + { + /* Spin round a bit more. */ + queenStatusPointer->HModelController.Playing=0; + queenStatusPointer->current_move=QM_Close; + queenStatusPointer->moveTimer=0; + queenStatusPointer->next_move=QM_Charge; + return; + } + } + + if (((queenStatusPointer->TargetDistance<8000 && queenStatusPointer->fixed_foot==LeftFoot && queenStatusPointer->TargetRelSpeednext_move!=QM_Standby)&&(queenStatusPointer->moveTimer!=2)) + { + queenStatusPointer->HModelController.Playing=0; + queenStatusPointer->current_move=queenStatusPointer->next_move; + queenStatusPointer->moveTimer=0; + if(queenStatusPointer->current_move==QM_Standby) + { + if(queenStatusPointer->QueenTargetSB==Player->ObStrategyBlock && !queenStatusPointer->TempTarget) + queenStatusPointer->current_move=QM_Close; + else + queenStatusPointer->current_move=QM_ComeToPoint; + } + queenStatusPointer->next_move=QM_Standby; + return; + #if 0 + /* Begin exit. */ + int tweeiningtime=(Queen_Step_Time>>2); + + queenStatusPointer->moveTimer=2; /* It's something of a state flag here. */ + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, + (int)QGSS_Stop_To_Right,(Queen_Step_Time),tweeiningtime); + break; + case (RightFoot): + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, + (int)QGSS_Stop_To_Left,(Queen_Step_Time),tweeiningtime); + break; + default: + GLOBALASSERT(0); + break; + } + + queenStatusPointer->HModelController.LoopAfterTweening=0; + #endif + } + + //check to see if queen should change between sprints + if(queenStatusPointer->fixed_foot==LeftFoot) + { + if(DeltaAnimation_IsFinished(queenStatusPointer->attack_delta)) + { + //switch to full sprint if not already doing it + if(queenStatusPointer->HModelController.Sub_Sequence!=QGSS_Sprint_Full) + { + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, + (int)QGSS_Sprint_Full,-1,ONE_FIXED>>3); + queenStatusPointer->HModelController.LoopAfterTweening=1; + + } + } + else + { + //switch to template sprint if not already doing it + if(queenStatusPointer->HModelController.Sub_Sequence!=QGSS_Sprint) + { + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, + (int)QGSS_Sprint,-1,ONE_FIXED>>3); + queenStatusPointer->HModelController.LoopAfterTweening=1; + + } + } + } + } + +} + +void QueenMove_ButtAttack(STRATEGYBLOCK* sbPtr) +{ + QUEEN_STATUS_BLOCK *queenStatusPointer; + + /* First movement function. */ + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(queenStatusPointer->current_move==QM_ButtAttack); + + if (queenStatusPointer->moveTimer==0) { + /* Do setup. */ + int tweeiningtime=(ONE_FIXED>>3); + + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, + (int)QGSS_ButtConnect,-1,tweeiningtime); + + } + + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) { + GLOBALASSERT(queenStatusPointer->HModelController.Looped==0); + } + + + if ((queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(queenStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) + { + + queenStatusPointer->current_move=QM_Standby; + //finished attack switch back to reconsider + queenStatusPointer->QueenState=QBS_Reconsider; + + //queen ends this sequence with right foot forward + SetQueenFoot(sbPtr,RightFoot); + + } + + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + + queenStatusPointer->moveTimer+=NormalFrameTime; +} + +void QueenMove_ButtCharge(STRATEGYBLOCK* sbPtr) +{ + + QUEEN_STATUS_BLOCK *queenStatusPointer; + BOOL ChangingFoot=FALSE; + + /* Very different movement function... */ + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(queenStatusPointer->current_move==QM_ButtCharge); + + /* Charge at the player. */ + //queenStatusPointer->TargetPos=queenStatusPointer->QueenTargetSB->DynPtr->Position; + + if (queenStatusPointer->moveTimer==0) + { + /* Do setup. */ + int tweeiningtime=(Queen_Step_Time>>2); + + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,LeftFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, + (int)QGSS_RunButtAttack,-1,tweeiningtime); + queenStatusPointer->HModelController.LoopAfterTweening=1; + queenStatusPointer->moveTimer=1; /* It's something of a state flag here. */ + + break; + case (RightFoot): + /* Argh! Can't start from right foot! */ + queenStatusPointer->current_move=QM_Close; + queenStatusPointer->moveTimer=0; + queenStatusPointer->next_move=QM_Charge; + return; + break; + default: + GLOBALASSERT(0); + break; + } + return; + } + + /* Check for change foot? */ + + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) { + if (queenStatusPointer->HModelController.keyframe_flags) + { + if (queenStatusPointer->HModelController.keyframe_flags & 1) + { + SetQueenFoot(sbPtr,LeftFoot); + ChangingFoot=TRUE; + } + if (queenStatusPointer->HModelController.keyframe_flags & 2) + { + SetQueenFoot(sbPtr,RightFoot); + ChangingFoot=TRUE; + } + if(queenStatusPointer->moveTimer==1) queenStatusPointer->moveTimer=3; + } + HModel_SetToolsRelativeSpeed(&queenStatusPointer->HModelController,(512*ONE_FIXED)/QUEEN_BUTTCHARGE_SPEED); + } + + /* Now... turn to face. */ + + if (queenStatusPointer->moveTimer!=2) { + + DISPLAYBLOCK *dPtr; + + dPtr=sbPtr->SBdptr; + GLOBALASSERT(dPtr); + + ProveHModel(dPtr->HModelControlBlock,dPtr); + + NPCOrientateToVector(sbPtr, &queenStatusPointer->VectToTarget,Queen_Turn_Rate,NULL); + + + /* Now, just a normal lin velocity. */ + if(queenStatusPointer->moveTimer==1) + { + SetQueenMovement_FromFoot(sbPtr); + } + else + { + VECTORCH velocity; + + velocity.vx=sbPtr->DynPtr->OrientMat.mat31; + velocity.vy=0; + velocity.vz=sbPtr->DynPtr->OrientMat.mat33; + + if ( (velocity.vx==0) && (velocity.vy==0) && (velocity.vz==0) ) { + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + return; + } + + + Normalise(&velocity); + + //runSpeed=DIV_FIXED(Queen_Charge_Step_Speed,Queen_ButtCharge_Rate); + + sbPtr->DynPtr->LinVelocity.vx = MUL_FIXED(velocity.vx,QUEEN_BUTTCHARGE_SPEED); + sbPtr->DynPtr->LinVelocity.vy = MUL_FIXED(velocity.vy,QUEEN_BUTTCHARGE_SPEED); + sbPtr->DynPtr->LinVelocity.vz = MUL_FIXED(velocity.vz,QUEEN_BUTTCHARGE_SPEED); + } + + } + + + + if(ChangingFoot) + { + + int range; + QueenCalculateTargetInfo(sbPtr); + range=queenStatusPointer->TargetDistance; + //only check for exiting charge , when changing foot + + if(queenStatusPointer->PlayingHitDelta) + { + queenStatusPointer->HModelController.Playing=0; + queenStatusPointer->current_move=QM_Standby; + queenStatusPointer->moveTimer=0; + queenStatusPointer->next_move=QM_Standby; + return; + } + + if(PlayerInLocker) + { + //stop using butt charge , since the queen can't actually get to the player + queenStatusPointer->moveTimer=0; + queenStatusPointer->current_move=QM_Charge; + queenStatusPointer->next_move=QM_Standby; + return; + + } + + + if (queenStatusPointer->TargetDirection.vzTargetDirection.vx || + queenStatusPointer->TargetDirection.vz<-queenStatusPointer->TargetDirection.vx) + { + /* Spin round a bit more. */ + queenStatusPointer->HModelController.Playing=0; + queenStatusPointer->current_move=QM_Close; + queenStatusPointer->moveTimer=0; + queenStatusPointer->next_move=QM_Standby; + return; + } + + + if (queenStatusPointer->moveTimer!=2 && queenStatusPointer->next_move!=QM_Standby) + { + queenStatusPointer->HModelController.Playing=0; + queenStatusPointer->current_move=queenStatusPointer->next_move; + queenStatusPointer->next_move=QM_Standby; + queenStatusPointer->moveTimer=0; + return; + } + } + + +} + +void QueenMove_Climb(STRATEGYBLOCK* sbPtr) +{ + + QUEEN_STATUS_BLOCK *queenStatusPointer; + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + GLOBALASSERT(queenStatusPointer->current_move==QM_Climbing); + + if (queenStatusPointer->moveTimer==0) + { + //just starting to climb out , so start the animation sequence + int tweeiningtime=(Queen_Step_Time>>2); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral, + (int)QGSS_ClimbOut,-1,tweeiningtime); + + queenStatusPointer->HModelController.Playing=1; + + //set the start position of this maneuver + queenStatusPointer->ClimbStartPosition=sbPtr->DynPtr->Position; + + //while climbing out queen needs to ignore gravity and collisions + sbPtr->DynPtr->GravityOn=0; + sbPtr->DynPtr->OnlyCollideWithObjects=1; + + /*moveTimer is being used as a state flag again*/ + queenStatusPointer->moveTimer=1; + } + + /*Adjust the queen's facing*/ + { + VECTORCH direction={-ONE_FIXED,0,0}; + NPCOrientateToVector(sbPtr, &direction,Queen_Turn_Rate,NULL); + } + + + /*If the queen has stopped tweening , then we need to deal with her movement*/ + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + { + #define QueenClimbTime1 7598 + #define QueenClimbTime2 16146 + #define QueenClimbTime3 42740 + + ProveHModel(sbPtr->SBdptr->HModelControlBlock,sbPtr->SBdptr); + { + VECTORCH StageOneMovement={0,-6771,0}; + VECTORCH StageTwoMovement={-3266,0,-372}; + + //work out where the queen should be + VECTORCH newPosition=queenStatusPointer->ClimbStartPosition; + int timer=queenStatusPointer->HModelController.sequence_timer; + + if(timerDynPtr->Displacement=newPosition; + SubVector(&sbPtr->DynPtr->Position,&sbPtr->DynPtr->Displacement); + } + + if(queenStatusPointer->HModelController.sequence_timer>62000) + { + //the queen has finished getting out + queenStatusPointer->current_move=QM_Standby; + queenStatusPointer->next_move=QM_Standby; + queenStatusPointer->moveTimer=0; + + QueenForceReconsider(sbPtr); + + sbPtr->DynPtr->GravityOn=1; + sbPtr->DynPtr->OnlyCollideWithObjects=0; + + //the queen ends in right stance + queenStatusPointer->fixed_foot=RightFoot; + + } + + } + + +} + + +#define Queen_Swipe_Left 0 +#define Queen_Swipe_Right 1 +#define Queen_Swipe_Left_Low 2 +#define Queen_Swipe_Right_Low 3 + +void Queen_Do_Swipe(STRATEGYBLOCK *sbPtr,int side) +{ + QUEEN_STATUS_BLOCK *queenStatusPointer; + VECTORCH vectohand,targetpos; + int range_to_player; + SECTION_DATA *hand_section; + + + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + /*Is the queen already doing a swipe?*/ + if ((queenStatusPointer->attack_delta->timer==(ONE_FIXED-1)) + ||(queenStatusPointer->attack_delta->timer==0)) + { + /* She isn't , so start it */ + switch (side) + { + case Queen_Swipe_Left : + Start_Delta_Sequence(queenStatusPointer->attack_delta, + (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_LeftSwipe,ONE_FIXED); + break; + + case Queen_Swipe_Right : + Start_Delta_Sequence(queenStatusPointer->attack_delta, + (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_RightSwipe,ONE_FIXED); + break; + + case Queen_Swipe_Left_Low : + Start_Delta_Sequence(queenStatusPointer->attack_delta, + (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_LeftSwipe_Low,ONE_FIXED); + break; + + case Queen_Swipe_Right_Low : + Start_Delta_Sequence(queenStatusPointer->attack_delta, + (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_RightSwipe_Low,ONE_FIXED); + break; + + + default : + LOCALASSERT(1==0); + + } + queenStatusPointer->attack_delta->Playing=1; + queenStatusPointer->attack_delta->Looped=0; + + queenStatusPointer->AttackDoneItsDamage=FALSE; + + } + + if(queenStatusPointer->attack_delta->timer>37000 && !queenStatusPointer->AttackDoneItsDamage) + { + queenStatusPointer->AttackDoneItsDamage=TRUE; + + //get the hand corresponding to the currently playing swipe + switch(queenStatusPointer->attack_delta->sub_sequence) + { + case QRSTSS_RightSwipe: + case QRSTSS_RightSwipe_Low: + hand_section=GetThisSectionData(queenStatusPointer->HModelController.section_data,"right hand"); + break; + + case QRSTSS_LeftSwipe: + case QRSTSS_LeftSwipe_Low: + hand_section=GetThisSectionData(queenStatusPointer->HModelController.section_data,"left hand"); + break; + + default : + LOCALASSERT(1==0); + } + + + GetTargetingPointOfObject(Player,&targetpos); + vectohand.vx=targetpos.vx-hand_section->World_Offset.vx; + vectohand.vy=0;//targetpos.vy-hand_section->World_Offset.vy; + vectohand.vz=targetpos.vz-hand_section->World_Offset.vz; + + range_to_player=Approximate3dMagnitude(&vectohand); + + //see if queen hit an intervening object + { + VECTORCH direction; + + direction.vx=targetpos.vx-hand_section->World_Offset.vx; + direction.vy=targetpos.vy-hand_section->World_Offset.vy; + direction.vz=targetpos.vz-hand_section->World_Offset.vz; + + Normalise(&direction); + + LOS_ObjectHitPtr=0; + FindPolygonInLineOfSight(&direction,&hand_section->World_Offset,1,sbPtr->SBdptr); + + if(LOS_ObjectHitPtr) + { + if(LOS_ObjectHitPtr->ObStrategyBlock) + { + if(LOS_ObjectHitPtr->ObStrategyBlock->I_SBtype==I_BehaviourInanimateObject || + LOS_ObjectHitPtr->ObStrategyBlock->I_SBtype==I_BehaviourTrackObject) + { + //damage the object instead of the player + //if(LOS_LambdaObStrategyBlock,&TemplateAmmo[AMMO_NPC_PAQ_CLAW].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + return; + } + } + } + } + + /* ATM, target is always player. */ + + if (range_to_playerObStrategyBlock,&TemplateAmmo[AMMO_NPC_PAQ_CLAW].MaxDamage[AvP.Difficulty],(ONE_FIXED*.75)+(FastRandom()&0x7fff),NULL); + //set the taunt timer + queenStatusPointer->QueenTauntTimer=ONE_FIXED/2; + } + } + +} + + +void QueenMove_Close(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + + /* First movement function. */ + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(queenStatusPointer->current_move==QM_Close); + + if (queenStatusPointer->moveTimer==0) + { + + /* Do setup. */ + int tweeiningtime=(ONE_FIXED>>3); + + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,LeftFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenLeftStanceTemplate, + (int)QLSTSS_Forward_L2R,-1,tweeiningtime); + queenStatusPointer->HModelController.LoopAfterTweening=0; + + break; + case (RightFoot): + SetQueenFoot(sbPtr,RightFoot); + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenRightStanceTemplate, + (int)QRSTSS_Forward_R2L,-1,tweeiningtime); + queenStatusPointer->HModelController.LoopAfterTweening=0; + + break; + default: + GLOBALASSERT(0); + break; + } + /* Go! */ + queenStatusPointer->moveTimer++; + GLOBALASSERT(queenStatusPointer->HModelController.Looped==0); + return; + } + + if (queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + { + BOOL moveHalfSpeed=FALSE; + if (queenStatusPointer->HModelController.Looped!=0) { + /* Quirkafleeg */ + GLOBALASSERT(queenStatusPointer->HModelController.Looped==0); + } + + QueenCalculateTargetInfo(sbPtr); + //if the queen is close to her target , and the target is not in front of her + //then she needs to slow down to reduce her turning circle + if(queenStatusPointer->TargetDistance<3000) + { + if(queenStatusPointer->TargetDirection.vzTargetDirection.vx || + queenStatusPointer->TargetDirection.vz<-queenStatusPointer->TargetDirection.vx) + { + moveHalfSpeed=TRUE; + } + } + if(moveHalfSpeed) + HModel_SetToolsRelativeSpeed(&queenStatusPointer->HModelController,(512*ONE_FIXED)/(QUEEN_CLOSE_SPEED/2)); + else + HModel_SetToolsRelativeSpeed(&queenStatusPointer->HModelController,(512*ONE_FIXED)/QUEEN_CLOSE_SPEED); + + } + + + /* Now... turn to face. */ + + { + + DISPLAYBLOCK *dPtr; + + dPtr=sbPtr->SBdptr; + GLOBALASSERT(dPtr); + + NPCOrientateToVector(sbPtr,&queenStatusPointer->VectToTarget,Queen_Turn_Rate,NULL); + + #if 1 + SetQueenMovement_FromFoot(sbPtr); + + #else + { + VECTORCH velocity; + int dotProduct; + int runSpeed; + + velocity.vx=sbPtr->DynPtr->OrientMat.mat31; + velocity.vy=0; + velocity.vz=sbPtr->DynPtr->OrientMat.mat33; + + if ( (velocity.vx==0) && (velocity.vy==0) && (velocity.vz==0) ) { + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + return; + } + + + Normalise(&velocity); + + + sbPtr->DynPtr->LinVelocity.vx = MUL_FIXED(velocity.vx,QUEEN_CLOSE_SPEED); + sbPtr->DynPtr->LinVelocity.vy = MUL_FIXED(velocity.vy,QUEEN_CLOSE_SPEED); + sbPtr->DynPtr->LinVelocity.vz = MUL_FIXED(velocity.vz,QUEEN_CLOSE_SPEED); + } + #endif + + } + + queenStatusPointer->moveTimer+=NormalFrameTime; + + if ((queenStatusPointer->HModelController.Tweening==Controller_NoTweening) + &&(queenStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))) { + + queenStatusPointer->current_move=QM_Standby; + + switch (queenStatusPointer->fixed_foot) { + case (LeftFoot): + SetQueenFoot(sbPtr,RightFoot); + break; + case (RightFoot): + SetQueenFoot(sbPtr,LeftFoot); + break; + default: + GLOBALASSERT(0); + break; + } + queenStatusPointer->moveTimer=0; + queenStatusPointer->current_move=queenStatusPointer->next_move; + queenStatusPointer->next_move=QM_Standby; + + } + + +} + +void QueenIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple,SECTION_DATA *Section, VECTORCH *incoming, VECTORCH *point) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + + GLOBALASSERT(sbPtr); + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + GLOBALASSERT(queenStatusPointer); + + /* Ouch. */ + if (sbPtr->SBDamageBlock.Health <= 0) { + if (queenStatusPointer->QueenState!=QBS_Dead) { + KillQueen(sbPtr,damage,multiple,Section,incoming); + } + return; + } + + //scream a bit + QueenSoundHurt(sbPtr); + + GLOBALASSERT(damage); + if(damage->ExplosivePower && incoming) + { + /* + Don't allow the queen to be stunned if she is climbing out of the airlock. + This would screw up the sequence to much. + */ + if(queenStatusPointer->current_move!=QM_Climbing) + { + if(!QueenPlayingStunAnimation(&queenStatusPointer->HModelController)) + { + if((damage->ExplosivePower==2)||(damage->ExplosivePower==6)) + { + //big explosion, play fall over anim + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral,(int)QGSS_Explosion_Stun,-1,ONE_FIXED>>3); + queenStatusPointer->HModelController.LoopAfterTweening=0; + + queenStatusPointer->current_move=QM_Stun; + + queenStatusPointer->PlayingHitDelta=TRUE; + QueenForceReconsider(sbPtr); + + //the queen ends in right stance + queenStatusPointer->fixed_foot=RightFoot; + + } + else + { + //play a hit delta if not already doing so + if ((queenStatusPointer->hit_delta->timer==(ONE_FIXED-1)) + ||(queenStatusPointer->hit_delta->timer==0)) + { + VECTORCH dir=*incoming; + MATRIXCH WtoL=sbPtr->DynPtr->OrientMat; + TransposeMatrixCH(&WtoL); + RotateVector(&dir,&WtoL); + + if(dir.vx>0) + { + Start_Delta_Sequence(queenStatusPointer->hit_delta, + (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_RightHit,-1); + queenStatusPointer->hit_delta->Playing=1; + } + else + { + Start_Delta_Sequence(queenStatusPointer->hit_delta, + (int)HMSQT_QueenRightStanceTemplate,(int)QRSTSS_LeftHit,-1); + queenStatusPointer->hit_delta->Playing=1; + } + + queenStatusPointer->PlayingHitDelta=TRUE; + QueenForceReconsider(sbPtr); + + + } + } + } + } + } + + if(AvP.PlayerType==I_Marine && Section) + { + //don't allow the marine to completely destroy a section + if(Section->current_damage.Health<=0) + { + Section->current_damage.Health=1; + } + } + +} + +void Execute_Queen_Dying(STRATEGYBLOCK *sbPtr) { + + QUEEN_STATUS_BLOCK *queenStatusPointer; + + GLOBALASSERT(sbPtr); + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + GLOBALASSERT(queenStatusPointer); + + /* Here for completeness. Queens never melt away. */ + +} + +void KillQueen(STRATEGYBLOCK *sbPtr,DAMAGE_PROFILE *damage, int multiple,SECTION_DATA *Section, VECTORCH *incoming) +{ + QUEEN_STATUS_BLOCK *queenStatusPointer; + int tkd; + + /* Oh my God! They've killed Queenie! */ + + GLOBALASSERT(sbPtr); + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + GLOBALASSERT(queenStatusPointer); + + /* make a sound. Just this once without a check. */ + Sound_Play(SID_ALIEN_KILL,"d",&sbPtr->DynPtr->Position); + + /*If queen has a death target ,send a request*/ + if(queenStatusPointer->death_target_sbptr) + { + RequestState(queenStatusPointer->death_target_sbptr,queenStatusPointer->death_target_request, 0); + } + /* Queens never gibb, they're that hard. */ + + tkd=TotalKineticDamage(damage); + + /* Deal with sequence. */ + RemoveAllDeltas(&queenStatusPointer->HModelController); + + if (tkd>200) { + //SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral,QGSS_Explode_Death,(ONE_FIXED),(ONE_FIXED>>2)); + /* That death doesn't work. */ + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral,QGSS_FaceDeath,(ONE_FIXED),(ONE_FIXED>>2)); + } else { + SetQueenShapeAnimSequence_Core(sbPtr,HMSQT_QueenGeneral,QGSS_FaceDeath,(ONE_FIXED),(ONE_FIXED>>2)); + } + + //if the queen is carrying an object , release it and reset gravity on it + if(queenStatusPointer->QueenState==QBS_CarryingObject) + { + if(!QueenObjectList[queenStatusPointer->CurrentQueenObject]->SBflags.destroyed_but_preserved) + { + QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->GravityOn=1; + QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->OnlyCollideWithEnvironment=0; + queenStatusPointer->CurrentQueenObject=-1; + } + } + + + /* More restrained death than before... */ + { + + queenStatusPointer->QueenState=QBS_Dead; + + /* stop motion */ + LOCALASSERT(sbPtr->DynPtr); + sbPtr->DynPtr->Friction = 400000; + sbPtr->DynPtr->LinImpulse.vx+=sbPtr->DynPtr->LinVelocity.vx; + sbPtr->DynPtr->LinImpulse.vy+=sbPtr->DynPtr->LinVelocity.vy; + sbPtr->DynPtr->LinImpulse.vz+=sbPtr->DynPtr->LinVelocity.vz; + sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; + sbPtr->DynPtr->IgnoreSameObjectsAsYou = 1; + /* Experiment... */ + sbPtr->DynPtr->UseStandardGravity=1; + + } + + +} + + +void FindQueenObjects() +{ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + int sbIndex = 0; + STRATEGYBLOCK *sbPtr; + + + NumQueenObjects=0; + + //search through all the strategies for the throwable objects + //also look for the special airlock doors + UpperAirlockDoorSbptr=0; + LowerAirlockDoorSbptr=0; + LockerDoorSbptr=0; + UpperAirlockDoorOpen=FALSE; + LowerAirlockDoorOpen=FALSE; + + while(sbIndex < NumActiveStBlocks) + { + sbPtr = ActiveStBlockList[sbIndex++]; + if(sbPtr->name) + { + if(strstr(sbPtr->name,"QueenAmmo")) + { + if(NumQueenObjectsDynPtr); + sbPtr->SBflags.preserve_until_end_of_level=1; + } + } + else if(!strcmp(sbPtr->name,"a1door")) + { + UpperAirlockDoorSbptr=sbPtr; + UpperAirlockDoorStart=sbPtr->DynPtr->Position; + } + else if(!strcmp(sbPtr->name,"a3door")) + { + LowerAirlockDoorSbptr=sbPtr; + LowerAirlockDoorStart=sbPtr->DynPtr->Position; + } + else if(!strcmp(sbPtr->name,"locker door")) + { + LockerDoorSbptr=sbPtr; + sbPtr->SBflags.preserve_until_end_of_level=1; + } + } + } +} + + +BOOL CalculateTrajectory(VECTORCH* start,VECTORCH* dest,VECTORCH* velocity,int obj_speed,VECTORCH* result) +{ + VECTORCH normal; + VECTORCH rotated_vel; + VECTORCH rotated_result; + int closing_speed; + int distance; + int vertical_distance; + int time_to_target; + + //get a normalised vector from start to destination + normal=*dest; + SubVector(start,&normal); + + vertical_distance=normal.vy-1000; + normal.vy=0; + + if(!normal.vx && !normal.vz) + return FALSE; + + distance=Magnitude(&normal); + + Normalise(&normal); + + //apply rotation to velocity that would rotate the normal to (ONE_FIXED,0,0) + rotated_vel.vx=MUL_FIXED(velocity->vx,normal.vx)+MUL_FIXED(velocity->vz,normal.vz); + rotated_vel.vy=0; + rotated_vel.vz=MUL_FIXED(velocity->vx,-normal.vz)+MUL_FIXED(velocity->vz,normal.vx); + + if(rotated_vel.vz>=obj_speed || -rotated_vel.vz>=obj_speed) + { + //no hope of hitting + return FALSE; + } + + rotated_result.vz=rotated_vel.vz; + + //calculate x component using floats + { + float z=(float)rotated_result.vz; + float speed=(float)obj_speed; + + float x=sqrt(speed*speed-z*z); + + rotated_result.vx=x; + } + + closing_speed=rotated_result.vx-rotated_vel.vx; + if(closing_speed<=0) + { + //can't hit + return FALSE; + } + + time_to_target=DIV_FIXED(distance,closing_speed); + + if(time_to_target>(3*ONE_FIXED)) + { + //take to long to hit target + return FALSE; + } + + //rotate result back + result->vx=MUL_FIXED(rotated_result.vx,normal.vx)+MUL_FIXED(rotated_result.vz,-normal.vz); + result->vy=0; + result->vz=MUL_FIXED(rotated_result.vx,normal.vz)+MUL_FIXED(rotated_result.vz,normal.vx); + + //calculate required up component + //u=s/t - a*t/2 + result->vy=DIV_FIXED(vertical_distance,time_to_target)-MUL_FIXED(time_to_target,GRAVITY_STRENGTH/2); + + //we have a targeting solution. + return TRUE; +} + + +//calculate target's relative position +static void QueenCalculateTargetInfo(STRATEGYBLOCK *sbPtr) +{ + QUEEN_STATUS_BLOCK *queenStatusPointer; + GLOBALASSERT(sbPtr); + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + GLOBALASSERT(queenStatusPointer); + + if(queenStatusPointer->TargetInfoValid) return; + + { + MATRIXCH WtoL; + + //get vector from queen to target + queenStatusPointer->VectToTarget=queenStatusPointer->TargetPos; + SubVector(&sbPtr->DynPtr->Position,&queenStatusPointer->VectToTarget); + + queenStatusPointer->VectToTarget.vy=0; + + //get length of vector, and then normalise it + queenStatusPointer->TargetDistance=Approximate3dMagnitude(&queenStatusPointer->VectToTarget); + Normalise(&queenStatusPointer->VectToTarget); + + //rotate vector to queen's local space to get relative direction + queenStatusPointer->TargetDirection=queenStatusPointer->VectToTarget; + WtoL=sbPtr->DynPtr->OrientMat; + TransposeMatrixCH(&WtoL); + RotateVector(&queenStatusPointer->TargetDirection,&WtoL); + + + + queenStatusPointer->TargetRelSpeed=0; + if(!queenStatusPointer->TempTarget && queenStatusPointer->QueenTargetSB) + { + if(queenStatusPointer->QueenTargetSB->DynPtr) + { + VECTORCH facing; + facing.vx=sbPtr->DynPtr->OrientMat.mat31; + facing.vy=sbPtr->DynPtr->OrientMat.mat32; + facing.vz=sbPtr->DynPtr->OrientMat.mat33; + + + queenStatusPointer->TargetRelSpeed=DotProduct(&facing,&queenStatusPointer->QueenTargetSB->DynPtr->LinVelocity); + } + } + } + + queenStatusPointer->TargetInfoValid=TRUE; +} + +void QueenForceReconsider(STRATEGYBLOCK* sbPtr) +{ + QUEEN_STATUS_BLOCK *queenStatusPointer; + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + if(queenStatusPointer->QueenState==QBS_Reconsider) return; + + if(queenStatusPointer->QueenState==QBS_CarryingObject) + { + //need to drop the object + if(queenStatusPointer->CurrentQueenObject!=-1) + { + //if the object has been destroyed anywa, don't need to worry about dropping it + if(!QueenObjectList[queenStatusPointer->CurrentQueenObject]->SBflags.destroyed_but_preserved) + { + //put gravity back on + QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->GravityOn=1; + QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->OnlyCollideWithEnvironment=0; + + { + MATRIXCH id_mat={ONE_FIXED,0,0,0,ONE_FIXED,0,0,0,ONE_FIXED}; + QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->OrientMat=id_mat; + + } + + //give the object a slight impulse away from the queen + QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->LinImpulse.vx+=sbPtr->DynPtr->OrientMat.mat31/10; + QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->LinImpulse.vz+=sbPtr->DynPtr->OrientMat.mat33/10; + } + } + } + + queenStatusPointer->CurrentQueenObject=-1; + queenStatusPointer->QueenState=QBS_Reconsider; + queenStatusPointer->QueenTargetSB=Player->ObStrategyBlock; + queenStatusPointer->TempTarget=FALSE; + queenStatusPointer->TargetInfoValid=FALSE; + queenStatusPointer->TargetPos=queenStatusPointer->QueenTargetSB->DynPtr->Position; + +} + + +#define AirlockMinX 33882 +#define AirlockMaxX 45542 +#define AirlockMinZ -13936 +#define AirlockMaxZ -6266 +#define AirlockCentreX ((AirlockMinX+AirlockMaxX)/2) +#define AirlockCentreZ ((AirlockMinZ+AirlockMaxZ)/2) +#define AirlockY 12000 +#define HangarFloorLevel 3950 + +#define AirlockOpeningDistance 2500 + +#define AirlockOffset 1000 +void QueenCheckForAvoidAirlock(STRATEGYBLOCK *sbPtr) +{ + //only need to look out for the airlock in hangar + if(!stricmp(LevelName,"hangar")) + { + QUEEN_STATUS_BLOCK *queenStatusPointer =(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + VECTORCH* qpos=&sbPtr->DynPtr->Position; + VECTORCH* tpos=&queenStatusPointer->TargetPos; + + if(!UpperAirlockDoorOpen) return; + if(PlayerInTrench) return; + + if(queenStatusPointer->QueenState==QBS_ClimbingOutOfAirlock) + { + //not much point in trying to avoid airlock now! + return; + } + if(!queenStatusPointer->BeenInAirlock) + { + //if the queen hasn't fallen in yet , then she isn't careful while + //charging at the player + if(queenStatusPointer->current_move==QM_ButtCharge) + { + return; + } + } + + if(qpos->vx>AirlockMaxX-1000) + { + if(tpos->vxvx,tpos->vx-qpos->vx); + int zintercept=MUL_FIXED(tpos->vz-qpos->vz,scale)+qpos->vz; + + if(zintercept>=AirlockMinZ && zintercept<=AirlockMaxZ) + { + +// textprint("Airlock Max X\n"); +// return; + //head for the corner that is closest to the current target + queenStatusPointer->TargetPos.vx=AirlockMaxX; + if(abs(AirlockMinZ-tpos->vz)vz)) + { + queenStatusPointer->TargetPos.vz=AirlockMinZ; + } + else + { + queenStatusPointer->TargetPos.vz=AirlockMaxZ; + } + queenStatusPointer->TempTarget=TRUE; + queenStatusPointer->TempTargetTimer=ONE_FIXED; + queenStatusPointer->TargetInfoValid=FALSE; + return; + } + } + } + else if(qpos->vxvx>AirlockMinX+1000) + { + //queen and target are on opposite sides of the min X side + //find out where the queen's path will intersect the side + int scale=DIV_FIXED(AirlockMinX+1000-qpos->vx,tpos->vx-qpos->vx); + int zintercept=MUL_FIXED(tpos->vz-qpos->vz,scale)+qpos->vz; + + if(zintercept>=AirlockMinZ && zintercept<=AirlockMaxZ) + { +// textprint("Airlock Min X\n"); +// return; + //head for the corner that is closest to the current target + queenStatusPointer->TargetPos.vx=AirlockMinX; + if(abs(AirlockMinZ-tpos->vz)vz)) + { + queenStatusPointer->TargetPos.vz=AirlockMinZ; + } + else + { + queenStatusPointer->TargetPos.vz=AirlockMaxZ; + } + queenStatusPointer->TempTarget=TRUE; + queenStatusPointer->TempTargetTimer=ONE_FIXED; + queenStatusPointer->TargetInfoValid=FALSE; + return; + } + } + } + + if(qpos->vz>AirlockMaxZ-1000) + { + if(tpos->vzvz,tpos->vz-qpos->vz); + int xintercept=MUL_FIXED(tpos->vx-qpos->vx,scale)+qpos->vx; + + if(xintercept>=AirlockMinX && xintercept<=AirlockMaxX) + { +// textprint("Airlock Max Z\n"); +// return; + //head for the corner that is closest to the current target + queenStatusPointer->TargetPos.vz=AirlockMaxZ; + if(abs(AirlockMinX-tpos->vx)vx)) + { + queenStatusPointer->TargetPos.vx=AirlockMinX; + } + else + { + queenStatusPointer->TargetPos.vx=AirlockMaxX; + } + queenStatusPointer->TempTarget=TRUE; + queenStatusPointer->TempTargetTimer=ONE_FIXED; + queenStatusPointer->TargetInfoValid=FALSE; + return; + } + } + } + else if(qpos->vzvz>AirlockMinZ+1000) + { + //queen and target are on opposite sides of the min Z side + //find out where the queen's path will intersect the side + int scale=DIV_FIXED(AirlockMinZ+1000-qpos->vz,tpos->vz-qpos->vz); + int xintercept=MUL_FIXED(tpos->vx-qpos->vx,scale)+qpos->vx; + + if(xintercept>=AirlockMinX && xintercept<=AirlockMaxX) + { +// textprint("Airlock Min Z\n"); +// return; + //head for the corner that is closest to the current target + queenStatusPointer->TargetPos.vz=AirlockMinZ; + if(abs(AirlockMinX-tpos->vx)vx)) + { + queenStatusPointer->TargetPos.vx=AirlockMinX; + } + else + { + queenStatusPointer->TargetPos.vx=AirlockMaxX; + } + queenStatusPointer->TempTarget=TRUE; + queenStatusPointer->TempTargetTimer=ONE_FIXED; + queenStatusPointer->TargetInfoValid=FALSE; + return; + } + } + } + textprint("Airlock not in the way\n"); + } +} + +#define HangarLockerMinX 17104 +#define HangarLockerMaxX 19680 +#define HangarLockerMinZ -32700 +#define HangarLockerMaxZ -29661 +#define HangarLockerCentreZ ((HangarLockerMinZ+HangarLockerMaxZ)/2) + + +BOOL ObjectIsInAirlock(STRATEGYBLOCK* sbPtr) +{ + GLOBALASSERT(sbPtr); + GLOBALASSERT(sbPtr->DynPtr); + + if(sbPtr->DynPtr->Position.vx>AirlockMinX && sbPtr->DynPtr->Position.vxDynPtr->Position.vz>AirlockMinZ && sbPtr->DynPtr->Position.vzDynPtr->Position.vy>(HangarFloorLevel+1000)) + { + return TRUE; + } + return FALSE; + +} + +void QueenPickupTargetObject(STRATEGYBLOCK *sbPtr) +{ + QUEEN_STATUS_BLOCK *queenStatusPointer; + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + //queen must be going for an object + if(queenStatusPointer->QueenState!=QBS_GoingForObject) return; + + //disable gravity for object , while it is being carried + queenStatusPointer->QueenTargetSB->DynPtr->GravityOn=0; + //also stop it colliding with the queen + queenStatusPointer->QueenTargetSB->DynPtr->OnlyCollideWithEnvironment=1; + + //change queen's state + queenStatusPointer->QueenState=QBS_CarryingObject; + queenStatusPointer->QueenStateTimer=0; + + //now heading for the player + queenStatusPointer->QueenTargetSB=Player->ObStrategyBlock; + queenStatusPointer->TargetPos=queenStatusPointer->QueenTargetSB->DynPtr->Position; + queenStatusPointer->TargetInfoValid=FALSE; + queenStatusPointer->next_move=QM_Close; + +} + +void QueenBehaviour(STRATEGYBLOCK *sbPtr) +{ + QUEEN_STATUS_BLOCK *queenStatusPointer; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + int DistanceToPlayer; + BOOL JumpDesired=FALSE; + BOOL ConsiderJumping=FALSE; + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + if(NumQueenObjects==-1) + { + //first frame... + //find all objects that the queen can chuck + FindQueenObjects(); + queenStatusPointer->CurrentQueenObject=-1; + //get the queens hand section + queenStatusPointer->QueenRightHand=GetThisSectionData(queenStatusPointer->HModelController.section_data,"rrrr fing"); + GLOBALASSERT(queenStatusPointer->QueenRightHand); + } + + if(!queenStatusPointer->QueenActivated) + { + //is the queen in a visible module? + GLOBALASSERT(sbPtr->containingModule); + if(ModuleCurrVisArray[sbPtr->containingModule->m_index]==2) + { + queenStatusPointer->QueenActivated=TRUE; + } + else + { + return; + } + } + + + HandleHangarAirlock(); + + + if(queenStatusPointer->QueenState==QBS_Dead) + { + //check for victory on marine level. + if(!stricmp(LevelName,"hangar")) + { + //is the player in the locker ('hangar') + if(Player->ObWorld.vx> HangarLockerMinX && Player->ObWorld.vx < HangarLockerMaxX && + Player->ObWorld.vz> HangarLockerMinZ && Player->ObWorld.vz < HangarLockerMaxZ) + PlayerInLocker=TRUE; + else + PlayerInLocker=FALSE; + + //In the marine level the player can only win if he is inside the locker room area ,and + //the locker door is shut + if((PlayerInLocker && LockerDoorIsClosed()) || + !(LowerAirlockDoorOpen && UpperAirlockDoorOpen)) + { + AvP.LevelCompleted=1; + } + } + + + Execute_Queen_Dying(sbPtr); + return; + } + + /*----------------------------------** + ** Check state of delta animations ** + **----------------------------------*/ + if(queenStatusPointer->PlayingHitDelta) + { + //check to see if the queen is still stunned from an explosion + if (!QueenPlayingStunAnimation(&queenStatusPointer->HModelController) && DeltaAnimation_IsFinished(queenStatusPointer->hit_delta)) + { + queenStatusPointer->hit_delta->Playing=0; + queenStatusPointer->hit_delta->timer=0; + + queenStatusPointer->PlayingHitDelta=FALSE; + queenStatusPointer->current_move=QM_Close; + queenStatusPointer->next_move=QM_Standby; + queenStatusPointer->moveTimer=0; + } + } + + if(DeltaAnimation_IsFinished(queenStatusPointer->attack_delta)) + { + queenStatusPointer->attack_delta->Playing=0; + queenStatusPointer->attack_delta->timer=0; + } + + queenStatusPointer->TargetInfoValid=FALSE; + + if(queenStatusPointer->CurrentQueenObject!=-1) + { + if(QueenObjectList[queenStatusPointer->CurrentQueenObject]->SBflags.destroyed_but_preserved) + { + //the object that the queen was going for has been destroyed + queenStatusPointer->CurrentQueenObject=-1; + queenStatusPointer->QueenState=QBS_Reconsider; + } + } + + + if (sbPtr->SBdptr==NULL) { + /* No far behaviour. */ + return; + } + + if(!dynPtr->IsInContactWithFloor && queenStatusPointer->current_move!=QM_Jump && queenStatusPointer->current_move!=QM_Climbing) + { + //if queen is not on the ground , and not currently jumping + //switch to standby + queenStatusPointer->current_move=QM_Standby; + } + + if(dynPtr->IsInContactWithFloor) + { + + if(!stricmp(LevelName,"hangar")) + { + //is the player in the trench + if((dynPtr->Position.vy+1500)ObWorld.vy) + { + PlayerInTrench=TRUE; + if(queenStatusPointer->QueenState!=QBS_Engagement) + { + QueenForceReconsider(sbPtr); + } + } + else + { + PlayerInTrench=FALSE; + } + //is the player in the locker ('hangar') + if(Player->ObWorld.vx> HangarLockerMinX && Player->ObWorld.vx < HangarLockerMaxX && + Player->ObWorld.vz> HangarLockerMinZ && Player->ObWorld.vz < HangarLockerMaxZ) + PlayerInLocker=TRUE; + else + PlayerInLocker=FALSE; + + + //is the queen in the airlock? + if(UpperAirlockDoorOpen && !LowerAirlockDoorOpen) + { + //has the queen fallen into the airlock + if(ObjectIsInAirlock(sbPtr) && !ObjectIsInAirlock(Player->ObStrategyBlock) && queenStatusPointer->QueenState!=QBS_ClimbingOutOfAirlock) + { + QueenForceReconsider(sbPtr); + } + } + + + } + } + + queenStatusPointer->QueenStateTimer+=NormalFrameTime; + + { + VECTORCH pos=Player->ObWorld; + SubVector(&dynPtr->Position,&pos); + DistanceToPlayer=Approximate3dMagnitude(&pos); + } + + /*-------------------------------------------------------** + ** Check collision reports , and check for need to jump ** + **-------------------------------------------------------*/ + JumpDesired=FALSE; + + { + + BOOL ignore_obstacles=FALSE; + if(queenStatusPointer->LastVelocity.vx || queenStatusPointer->LastVelocity.vz || + queenStatusPointer->current_move==QM_Climbing) + { + /* Now, smash stuff. */ + + COLLISIONREPORT *nextReport; + + nextReport = dynPtr->CollisionReportPtr; + + while(nextReport) + { + int normalDotWithVelocity; + BOOL ConsiderJumpingForThisObject=FALSE; + + { + VECTORCH normVelocity = sbPtr->DynPtr->LinVelocity; + normVelocity.vy=0; + Normalise(&normVelocity); + normalDotWithVelocity = DotProduct(&(nextReport->ObstacleNormal),&(normVelocity)); + } + + if(normalDotWithVelocity<-20000)//is the object in the way + { + if(nextReport->ObstacleNormal.vy<20000 && nextReport->ObstacleNormal.vy>-20000) + { + //obstacle is reasonably vertical , may need to jump + ConsiderJumpingForThisObject=TRUE; + } + + if (nextReport->ObstacleSBPtr) + { + + if(nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourInanimateObject) + { + INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = nextReport->ObstacleSBPtr->SBdataptr; + if((objectstatusptr)&&(objectstatusptr->Indestructable == 0)) + { + int i; + BOOL AllowedToDestroy=TRUE; + //is this one of the queen's objects? + for(i=0;iObstacleSBPtr) + { + AllowedToDestroy=FALSE; + } + } + + if(AllowedToDestroy) + { + /* aha: an object which the queen can destroy... */ + CauseDamageToObject(nextReport->ObstacleSBPtr,&TemplateAmmo[AMMO_NPC_PAQ_CLAW].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + //no need to jump over this + ConsiderJumpingForThisObject=FALSE; + } + } + } + else if(nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourTrackObject) + { + /* aha: an object which the queen can destroy... */ + CauseDamageToObject(nextReport->ObstacleSBPtr,&TemplateAmmo[AMMO_NPC_PAQ_CLAW].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + //no need to jump over this + ConsiderJumpingForThisObject=FALSE; + } + else + { + ConsiderJumpingForThisObject=FALSE; + } + + + if(queenStatusPointer->QueenState==QBS_GoingForObject) + { + //is this the object that the queen was heading for? + if(nextReport->ObstacleSBPtr==queenStatusPointer->QueenTargetSB) + { + QueenPickupTargetObject(sbPtr); + + //no need to jump over this + ConsiderJumpingForThisObject=FALSE; + + } + } + else if(queenStatusPointer->QueenState==QBS_CarryingObject) + { + //if the queen is colliding with the object she is carrying , ignore it + if(QueenObjectList[queenStatusPointer->CurrentQueenObject]==nextReport->ObstacleSBPtr) + { + //no need to jump over this + ConsiderJumpingForThisObject=FALSE; + + } + } + + if(nextReport->ObstacleSBPtr==Player->ObStrategyBlock) + { + ConsiderJumpingForThisObject=FALSE; + + //have we connected with a butt attack + if(queenStatusPointer->current_move==QM_ButtCharge) + { + queenStatusPointer->current_move=QM_ButtAttack; + queenStatusPointer->next_move=QM_Standby; + queenStatusPointer->moveTimer=0; + + { + //knock the player back + VECTORCH* player_impulse; + player_impulse=&Player->ObStrategyBlock->DynPtr->LinImpulse; + player_impulse->vx+=dynPtr->OrientMat.mat31/4; + player_impulse->vy-=6000; + player_impulse->vz+=dynPtr->OrientMat.mat33/4; + } + { + //do some damage + CauseDamageToObject(Player->ObStrategyBlock,&QueenButtDamage, ONE_FIXED,NULL); + + } + } + else if(queenStatusPointer->current_move==QM_Climbing) + { + //need to push he player out of the way + Player->ObStrategyBlock->DynPtr->LinImpulse.vx=min(Player->ObStrategyBlock->DynPtr->LinImpulse.vx,-3000); + } + else if(queenStatusPointer->QueenState!=QBS_Engagement && + queenStatusPointer->QueenState!=QBS_CarryingObject) + { + QueenForceReconsider(sbPtr); + } + + } + } + + /*Queen climbing out of the airlock?*/ + if(queenStatusPointer->QueenState==QBS_ClimbingOutOfAirlock && + queenStatusPointer->current_move!=QM_Climbing) + + { + QueenCalculateTargetInfo(sbPtr); + if((dynPtr->Position.vx-AirlockMinX)<2800) + { + //queen has hit the end wall , so start climbing + queenStatusPointer->current_move=QM_Climbing; + queenStatusPointer->moveTimer=0; + } + } + + + } + if(ConsiderJumpingForThisObject) ConsiderJumping=TRUE; + nextReport = nextReport->NextCollisionReportPtr; + } + + } + + //if the queen is approaching the player in the locker + //ignore obstacles to allow the quuen to get to the player + if(PlayerInLocker && !queenStatusPointer->TempTarget && + queenStatusPointer->QueenTargetSB==Player->ObStrategyBlock) + { + QueenCalculateTargetInfo(sbPtr); + if(queenStatusPointer->TargetDistance<12000) + { + ignore_obstacles=TRUE; + } + } + + /*If the queen is trying to get out of the airlock , then we don't want to deviate because + of walls getting in the way*/ + if(queenStatusPointer->QueenState==QBS_ClimbingOutOfAirlock) + { + ignore_obstacles=TRUE; + } + + //check for nearby obstacles , and decide whether to jump. + if(!ignore_obstacles) + { + VECTORCH direction; + VECTORCH position=sbPtr->SBdptr->ObWorld; + + QueenCalculateTargetInfo(sbPtr); + + direction.vx=dynPtr->OrientMat.mat31; + direction.vy=0; + direction.vz=dynPtr->OrientMat.mat33; + Normalise(&direction); + + + //only bother to think of jumping if the queen is facing her target + + if(queenStatusPointer->TargetDirection.vz>(queenStatusPointer->TargetDirection.vx*2) && + queenStatusPointer->TargetDirection.vz>-(queenStatusPointer->TargetDirection.vx*2)) + { + int left_dist,centre_dist,right_dist; + VECTORCH left_point,centre_point,right_point; + int distance; + + //do several line of sight tests one metre above ground , in front of queen. + //if there is nothing near by , then queen should be able to jump over + + position.vy-=1000; + + + LOS_ObjectHitPtr=0; + FindPolygonInLineOfSight(&queenStatusPointer->VectToTarget,&position,1,sbPtr->SBdptr); + centre_dist=LOS_Lambda; + centre_point=LOS_Point; + if(LOS_ObjectHitPtr && LOS_ObjectHitPtr->ObStrategyBlock) + { + if(LOS_ObjectHitPtr->ObStrategyBlock->I_SBtype==I_BehaviourInanimateObject || + LOS_ObjectHitPtr->ObStrategyBlock->I_SBtype==I_BehaviourTrackObject || + LOS_ObjectHitPtr==Player) + { + //not an obstacle + centre_dist=1000000; + } + } + + //check on the right + position.vx+=dynPtr->OrientMat.mat11/32; + position.vy+=dynPtr->OrientMat.mat12/32; + position.vz+=dynPtr->OrientMat.mat13/32; + + LOS_ObjectHitPtr=0; + FindPolygonInLineOfSight(&queenStatusPointer->VectToTarget,&position,1,sbPtr->SBdptr); + right_dist=LOS_Lambda; + right_point=LOS_Point; + if(LOS_ObjectHitPtr && LOS_ObjectHitPtr->ObStrategyBlock) + { + if(LOS_ObjectHitPtr->ObStrategyBlock->I_SBtype==I_BehaviourInanimateObject || + LOS_ObjectHitPtr->ObStrategyBlock->I_SBtype==I_BehaviourTrackObject || + LOS_ObjectHitPtr==Player) + { + //not an obstacle + right_dist=1000000; + } + } + + + //check on the left + position.vx-=dynPtr->OrientMat.mat11/16; + position.vy-=dynPtr->OrientMat.mat12/16; + position.vz-=dynPtr->OrientMat.mat13/16; + + LOS_ObjectHitPtr=0; + FindPolygonInLineOfSight(&queenStatusPointer->VectToTarget,&position,1,sbPtr->SBdptr); + left_dist=LOS_Lambda; + left_point=LOS_Point; + if(LOS_ObjectHitPtr && LOS_ObjectHitPtr->ObStrategyBlock) + { + if(LOS_ObjectHitPtr->ObStrategyBlock->I_SBtype==I_BehaviourInanimateObject || + LOS_ObjectHitPtr->ObStrategyBlock->I_SBtype==I_BehaviourTrackObject || + LOS_ObjectHitPtr==Player) + { + //not an obstacle + left_dist=1000000; + } + } + + distance=queenStatusPointer->TargetDistance; + + if(distance>10000) distance=10000; + + if(right_distTargetPos=centre_point; + } + else if(right_distTargetPos=right_point; + } + else + { + queenStatusPointer->TargetPos=left_point; + } + /* + if(right_distTargetPos.vx-=dynPtr->OrientMat.mat11/8; + queenStatusPointer->TargetPos.vz-=dynPtr->OrientMat.mat13/8; + } + else + { + queenStatusPointer->TargetPos.vx+=dynPtr->OrientMat.mat11/8; + queenStatusPointer->TargetPos.vz+=dynPtr->OrientMat.mat13/8; + } + queenStatusPointer->TempTarget=TRUE; + queenStatusPointer->TempTargetTimer=6*ONE_FIXED; + queenStatusPointer->TargetInfoValid=FALSE; + */ + } + else if(ConsiderJumping) + { + JumpDesired=TRUE; + } + + } + } + + } + + + if(queenStatusPointer->QueenState==QBS_GoingForObject) + { + //if the queen is close enought to the object she is going for + //pick it up even without a collision + QueenCalculateTargetInfo(sbPtr); + + if(queenStatusPointer->TargetDistance<1000) + { + QueenPickupTargetObject(sbPtr); + } + + } + + + /*---------------------------------------------------** + ** consider if queen should change her current plan ** + **---------------------------------------------------*/ + { + + switch(queenStatusPointer->QueenState) + { + case QBS_Reconsider : + { + //find closest object that is on the ground + int closest=-1; + int DistanceToObject=1000000000; + int i; + + textprint("Queen Reconsider\n"); + if(queenStatusPointer->PlayingHitDelta) + { + break; + } + + if(UpperAirlockDoorOpen && !LowerAirlockDoorOpen) + { + + //has the queen fallen into the airlock + if(ObjectIsInAirlock(sbPtr)) + { + //the queen is in the airlock + if(ObjectIsInAirlock(Player->ObStrategyBlock)) + { + //player is in the airlock with the queen + //splat him + queenStatusPointer->QueenState=QBS_Engagement; + queenStatusPointer->QueenTargetSB=Player->ObStrategyBlock; + queenStatusPointer->TargetPos=queenStatusPointer->QueenTargetSB->DynPtr->Position; + } + else + { + //go into get out of airlock mode in that case + queenStatusPointer->QueenState=QBS_ClimbingOutOfAirlock; + queenStatusPointer->TempTarget=TRUE; + queenStatusPointer->TempTargetTimer=50*ONE_FIXED; + + queenStatusPointer->TargetPos.vx=AirlockMinX-6000; + queenStatusPointer->TargetPos.vz=AirlockCentreZ; + + queenStatusPointer->BeenInAirlock=TRUE; + } + queenStatusPointer->QueenStateTimer=0; + queenStatusPointer->TargetInfoValid=FALSE; + break; + } + } + + + for(i=0;iSBflags.destroyed_but_preserved) + { + if(QueenObjectList[i]->DynPtr->IsInContactWithFloor) + { + VECTORCH pos=QueenObjectList[i]->DynPtr->Position; + int dist; + SubVector(&dynPtr->Position,&pos); + + if(!stricmp(LevelName,"battle")) + { + //In battle , the objects near the egg sack are hard for the queen to get to. + //So best ignore them. + if(QueenObjectList[i]->DynPtr->Position.vz>0) continue; + } + + + //if the y distance is more than 1500 , the object is probably inaccesible + if(pos.vy<=1500) + { + dist=Approximate3dMagnitude(&pos); + + if(distQueenPlayerBias); + int object_value=MUL_FIXED(FastRandom()& 0xffff,DistanceToObject/queenStatusPointer->QueenObjectBias); + + if(object_valueQueenState=QBS_GoingForObject; + queenStatusPointer->CurrentQueenObject=closest; + queenStatusPointer->QueenTargetSB=QueenObjectList[queenStatusPointer->CurrentQueenObject]; + + if(!stricmp(LevelName,"hangar")) + { + queenStatusPointer->QueenPlayerBias++; + } + else + { + //int he predator version , make it more likely for the queen to go after the player + queenStatusPointer->QueenPlayerBias+=3; + } + queenStatusPointer->QueenObjectBias--; + if(queenStatusPointer->QueenObjectBias==0) queenStatusPointer->QueenObjectBias=1; + + } + else + { + //go for the player + queenStatusPointer->QueenState=QBS_Engagement; + queenStatusPointer->CurrentQueenObject=-1; + queenStatusPointer->QueenTargetSB=Player->ObStrategyBlock; + queenStatusPointer->QueenObjectBias++; + queenStatusPointer->QueenPlayerBias--; + if(queenStatusPointer->QueenPlayerBias==0)queenStatusPointer->QueenPlayerBias=1; + } + + queenStatusPointer->TargetPos=queenStatusPointer->QueenTargetSB->DynPtr->Position; + queenStatusPointer->QueenStateTimer=0; + queenStatusPointer->TargetInfoValid=FALSE; + + } + + + } + + break; + + case QBS_Engagement : + { + if(queenStatusPointer->QueenStateTimer>10*ONE_FIXED && DistanceToPlayer>4000) + { + queenStatusPointer->QueenState=QBS_Reconsider; + queenStatusPointer->QueenStateTimer=0; + } + } + textprint("Queen Engagement\n"); + break; + + case QBS_GoingForObject : + { + if(queenStatusPointer->QueenStateTimer>15*ONE_FIXED) + { + QueenForceReconsider(sbPtr); + } + } + textprint("Queen Going for object\n"); + break; + + case QBS_CarryingObject : + { + + if(queenStatusPointer->QueenStateTimer>15*ONE_FIXED) + { + QueenForceReconsider(sbPtr); + } + + } + textprint("Queen Carrying object\n"); + break; + + case QBS_ClimbingOutOfAirlock : + textprint("Queen climbing out of airlock\n"); + break; + + + } + } + textprint("Queen Bias - Object %d Player %d\n",queenStatusPointer->QueenObjectBias,queenStatusPointer->QueenPlayerBias); + textprint("Queen Health %d\n",sbPtr->SBDamageBlock.Health>>16); + + /*--------------------** + ** Can queen attack? ** + **--------------------*/ + + //queen must be in engagement mode , and not avoiding stuff + if(!queenStatusPointer->TempTarget && queenStatusPointer->QueenState==QBS_Engagement) + { + //player must be close enough and in front 90 degree arc + QueenCalculateTargetInfo(sbPtr); + if (queenStatusPointer->TargetDistance<4000 || + (queenStatusPointer->TargetDistance<8000 && queenStatusPointer->TargetRelSpeed<1000)) + { + if(queenStatusPointer->current_move==QM_Standby || + queenStatusPointer->current_move==QM_Close || + queenStatusPointer->current_move==QM_Charge) + { + + if(queenStatusPointer->TargetDirection.vz>queenStatusPointer->TargetDirection.vx && + queenStatusPointer->TargetDirection.vz>-queenStatusPointer->TargetDirection.vx) + { + int x=queenStatusPointer->TargetDirection.vx; + x+=(FastRandom() % 80000); + x-=40000; + if (x>0) + { + if(PlayerInTrench) + Queen_Do_Swipe(sbPtr,Queen_Swipe_Right_Low); + else + Queen_Do_Swipe(sbPtr,Queen_Swipe_Right); + + } + else + { + if(PlayerInTrench) + Queen_Do_Swipe(sbPtr,Queen_Swipe_Left_Low); + else + Queen_Do_Swipe(sbPtr,Queen_Swipe_Left); + } + } + } + } + } + + + + /*------------------------------------------** + ** Decide if new movement state is required ** + **------------------------------------------*/ + + + if(queenStatusPointer->QueenState==QBS_CarryingObject) + { + //Queen is lining up to throw object + QueenCalculateTargetInfo(sbPtr); + if(queenStatusPointer->TargetDirection.vz>(queenStatusPointer->TargetDirection.vx*2) && + queenStatusPointer->TargetDirection.vz>-(queenStatusPointer->TargetDirection.vx*2) && !queenStatusPointer->TempTarget) + { + //Time to throw object at player. + VECTORCH impulse; + if(CalculateTrajectory(&QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->Position, + &Player->ObStrategyBlock->DynPtr->Position, + &Player->ObStrategyBlock->DynPtr->LinVelocity, + QUEEN_THROWN_OBJECT_SPEED, + &impulse)) + { + //give the object an impulse ,and reinstate gravity + QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->LinImpulse=impulse; + QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->GravityOn=1; + QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->OnlyCollideWithEnvironment=0; + { + MATRIXCH id_mat={ONE_FIXED,0,0,0,ONE_FIXED,0,0,0,ONE_FIXED}; + QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->OrientMat=id_mat; + + } + //queen will need to choose a new objective + queenStatusPointer->QueenState=QBS_Reconsider; + queenStatusPointer->QueenTargetSB=Player->ObStrategyBlock; + queenStatusPointer->TargetInfoValid=FALSE; + + } + else + { + //continue heading for target + if(queenStatusPointer->current_move==QM_Standby) + { + queenStatusPointer->next_move=QM_Close; + } + } + + + } + else + { + //Queen needs to turn some more + if(queenStatusPointer->current_move==QM_Standby) + { + queenStatusPointer->next_move=QM_Close; + } + } + } + //if in standby , need to choose a move + else if(queenStatusPointer->current_move==QM_Standby && queenStatusPointer->QueenState!=QBS_Reconsider) + { + QueenCalculateTargetInfo(sbPtr); + //queen is heading towards object , or player + if(((queenStatusPointer->TargetDistance>8000)||(queenStatusPointer->TargetDistance>2000 && queenStatusPointer->TargetRelSpeed>QUEEN_CLOSE_SPEED)) && + queenStatusPointer->TargetDirection.vz>queenStatusPointer->TargetDirection.vx && + queenStatusPointer->TargetDirection.vz>-queenStatusPointer->TargetDirection.vx) + { + queenStatusPointer->next_move=QM_Charge; + if(queenStatusPointer->QueenTargetSB==Player->ObStrategyBlock) + { + //going for player. possibility of butting player + //Nb. queen can't actually colide with player , if the player is in the locker area + if((FastRandom()&0xffff)<(ONE_FIXED/2) && !PlayerInLocker) + { + queenStatusPointer->next_move=QM_ButtCharge; + } + } + if(PlayerInTrench) + { + queenStatusPointer->next_move=QM_ComeToPoint; + } + } + else if (queenStatusPointer->TargetDistance>3000 || queenStatusPointer->TargetRelSpeed>0) + { + if(queenStatusPointer->QueenTargetSB==Player->ObStrategyBlock && !queenStatusPointer->TempTarget) + queenStatusPointer->next_move=QM_Close; + else + queenStatusPointer->next_move=QM_ComeToPoint; + } + else + { + if(queenStatusPointer->QueenState!=QBS_ClimbingOutOfAirlock) + { + if(queenStatusPointer->TempTarget) + { + queenStatusPointer->TempTarget=FALSE; + queenStatusPointer->TargetInfoValid=FALSE; + } + } + if(queenStatusPointer->QueenState==QBS_GoingForObject) + { + //have to keep going until queen hits object + queenStatusPointer->next_move=QM_Close; + } + else + { + //queen right next to target now , so wait + queenStatusPointer->next_move=QM_Standby; + //assuming queen is facing her target , that is. + if(queenStatusPointer->TargetDirection.vzTargetDirection.vx*2 || + queenStatusPointer->TargetDirection.vz<-queenStatusPointer->TargetDirection.vx*2) + { + //queen isn't facing target , so she needs to continue closing after all + queenStatusPointer->next_move=QM_Close; + + } + + } + } + + } + textprint("Queen target distance %d\n",queenStatusPointer->TargetDistance); + textprint("Queen target position %d : %d : %d\n",queenStatusPointer->TargetPos.vx,queenStatusPointer->TargetPos.vy,queenStatusPointer->TargetPos.vz); +/////////////////////////////////////////////////////////////////////// + /*--------------------** + ** Airlock avoidance ** + **--------------------*/ + + QueenCheckForAvoidAirlock(sbPtr); + + if(queenStatusPointer->TempTarget) + { + QueenCalculateTargetInfo(sbPtr); + if(queenStatusPointer->TargetDistance<4000) + { + queenStatusPointer->TempTarget=FALSE; + queenStatusPointer->TargetInfoValid=FALSE; + + } + queenStatusPointer->TempTargetTimer-=NormalFrameTime; + if(queenStatusPointer->TempTargetTimer<0) + { + queenStatusPointer->TempTarget=FALSE; + queenStatusPointer->TargetInfoValid=FALSE; + } + } + + + + /*-------------------------------------------------------------------** + ** check for redirecting the queen , if the player is in the locker ** + **-------------------------------------------------------------------*/ + + if(!queenStatusPointer->TempTarget && + queenStatusPointer->QueenTargetSB==Player->ObStrategyBlock && + PlayerInLocker) + { + //is the queen in line with the locker area? + if((dynPtr->Position.vz-HangarLockerMaxZ)*2>dynPtr->Position.vx-HangarLockerMaxX || + (HangarLockerMinZ-dynPtr->Position.vz)*2>dynPtr->Position.vx-HangarLockerMaxX) + { + //nope + queenStatusPointer->TempTarget=TRUE; + queenStatusPointer->TempTargetTimer=2*ONE_FIXED; + queenStatusPointer->TargetInfoValid=FALSE; + + //move the queen so that she is lined up with the locker + queenStatusPointer->TargetPos.vx=dynPtr->Position.vx; + queenStatusPointer->TargetPos.vy=dynPtr->Position.vy; + queenStatusPointer->TargetPos.vz=HangarLockerCentreZ; + } + } + + /*---------------------** + ** check for taunting ** + **---------------------*/ + + if(queenStatusPointer->QueenTauntTimer>0 ) + { + queenStatusPointer->QueenTauntTimer-=NormalFrameTime; + if(queenStatusPointer->QueenTargetSB==Player->ObStrategyBlock && DistanceToPlayer>10000) + { + QueenCalculateTargetInfo(sbPtr); + if(queenStatusPointer->TargetDirection.vz>queenStatusPointer->TargetDirection.vx && + queenStatusPointer->TargetDirection.vz>-queenStatusPointer->TargetDirection.vx) + { + queenStatusPointer->QueenTauntTimer=0; + //Queen has recently hit player , and is facing player + //time to taunt + queenStatusPointer->next_move=QM_Taunt; + } + } + } + + /*-------------------------------** + ** Flamethrower avoidance stuff ** + **-------------------------------*/ + + //only if queen is trying to attack the player in close combat + if(queenStatusPointer->QueenState==QBS_Engagement) + { + + + if(queenStatusPointer->QueenFireTimer>QueenMinimumFireTime) + { + /*stop and hiss for a bit*/ + if(queenStatusPointer->current_move==QM_Standby || + queenStatusPointer->current_move==QM_ComeToPoint || + queenStatusPointer->current_move==QM_ButtCharge || + queenStatusPointer->current_move==QM_Charge || + queenStatusPointer->current_move==QM_Close) + { + queenStatusPointer->current_move=QM_Hiss; + queenStatusPointer->moveTimer=0; + } + + } + else if(queenStatusPointer->QueenFireTimer==0) + { + if(queenStatusPointer->next_move==QM_Hiss) + { + queenStatusPointer->next_move=QM_Standby; + } + + if(queenStatusPointer->current_move==QM_Hiss) + { + queenStatusPointer->moveTimer=0; + queenStatusPointer->current_move=queenStatusPointer->next_move; + queenStatusPointer->next_move=QM_Standby; + + } + + } + //update the timer + if(TargetIsFiringFlamethrowerAtQueen(sbPtr)) + { + queenStatusPointer->QueenFireTimer+=NormalFrameTime; + if(queenStatusPointer->QueenFireTimer>2*ONE_FIXED) + { + queenStatusPointer->QueenFireTimer=2*ONE_FIXED; + } + } + else + { + queenStatusPointer->QueenFireTimer-=NormalFrameTime; + if(queenStatusPointer->QueenFireTimer<0) + { + queenStatusPointer->QueenFireTimer=0; + } + } + } + else + { + //make sure queen isn't hissing + if(queenStatusPointer->next_move==QM_Hiss) + { + queenStatusPointer->next_move=QM_Standby; + } + + if(queenStatusPointer->current_move==QM_Hiss) + { + queenStatusPointer->moveTimer=0; + queenStatusPointer->current_move=queenStatusPointer->next_move; + queenStatusPointer->next_move=QM_Standby; + + } + queenStatusPointer->QueenFireTimer=0; + } + + + + if(!queenStatusPointer->TempTarget) + { + //update target location + queenStatusPointer->TargetPos=queenStatusPointer->QueenTargetSB->DynPtr->Position; + } + + + + /*---------------------------** + ** Handle Queeen's movement ** + **---------------------------*/ + + + dynPtr->Displacement.vx = 0; + dynPtr->Displacement.vy = 0; + dynPtr->Displacement.vz = 0; + + + if (queenStatusPointer->QueenState!=QBS_Dead) + { + switch (queenStatusPointer->current_move) + { + case (QM_Standby): + { + + textprint("Queen State: Standby\n"); + db_log3(("Queen State: Standby\n")); + + if (queenStatusPointer->next_move==QM_Standby || queenStatusPointer->PlayingHitDelta) + { + /* Do not much. */ + QueenMove_Standby(sbPtr); + } + else + { + queenStatusPointer->current_move=queenStatusPointer->next_move; + queenStatusPointer->next_move=QM_Standby; + queenStatusPointer->moveTimer=0; + //queenStatusPointer->TargetPos=Queen_Target_Point; + } + + break; + } + case (QM_Stun) : + { + textprint("Queen State: Stunned\n"); + //don't do anything + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + break; + } + + case (QM_StepForward): + { + textprint("Queen State: Step Forward\n"); + /* Move function. */ + // QueenMove_StepForward(sbPtr); + break; + } + case (QM_StepBack): + { + textprint("Queen State: Step Back\n"); + /* Move function. */ + QueenMove_StepBack(sbPtr); + break; + } + case (QM_TurnLeft): + { + textprint("Queen State: Turn Left\n"); + /* Move function. */ + // QueenMove_TurnLeft(sbPtr); + break; + } + case (QM_TurnRight): + { + textprint("Queen State: Turn Right\n"); + /* Move function. */ + // QueenMove_TurnRight(sbPtr); + break; + } + case (QM_ComeToPoint): + { + textprint("Queen State: Come To Point\n"); + db_log3(("Queen State: Come To Point\n")); + /* Move function. */ + + if(JumpDesired) + { + textprint("Jumping\n"); + sbPtr->DynPtr->LinImpulse.vy-=10000; + queenStatusPointer->next_move=QM_Standby; + queenStatusPointer->current_move=QM_Jump; + } + else + { + QueenMove_Walk(sbPtr); + } + + break; + } + case (QM_Taunt): + { + textprint("Queen State: Taunt\n"); + db_log3(("Queen State: Taunt\n")); + /* Move function. */ + QueenMove_Taunt(sbPtr); + break; + } + case (QM_Hiss): + { + textprint("Queen State: Hiss\n"); + /* Move function. */ + QueenMove_Hiss(sbPtr); + break; + } + case (QM_LeftSwipe): + { + textprint("Queen State: Left Swipe\n"); + // QueenMove_LeftSwipe(sbPtr); + break; + } + case (QM_RightSwipe): + { + textprint("Queen State: Right Swipe\n"); + // QueenMove_RightSwipe(sbPtr); + break; + } + + case (QM_ButtAttack): + { + textprint("Queen State: Butt attack\n"); + db_log3(("Queen State: Butt attack\n")); + QueenMove_ButtAttack(sbPtr); + break; + } + + case (QM_Charge): + { + textprint("Queen State: Charging\n"); + db_log3(("Queen State: Charging\n")); + /* Move function. */ + + if(JumpDesired) + { + textprint("Jumping\n"); + sbPtr->DynPtr->LinImpulse.vy-=10000; + queenStatusPointer->next_move=QM_Standby; + queenStatusPointer->current_move=QM_Jump; + } + else + { + QueenMove_Charge(sbPtr); + } + + break; + } + + case (QM_Close): + { + textprint("Queen State: Closing\n"); + db_log3(("Queen State: Closing\n")); + /* Move function. */ + + + if(JumpDesired) + { + textprint("Jumping\n"); + sbPtr->DynPtr->LinImpulse.vy-=10000; + queenStatusPointer->next_move=QM_Standby; + queenStatusPointer->current_move=QM_Jump; + } + else + { + QueenMove_Close(sbPtr); + } + + break; + } + + case (QM_ButtCharge) : + { + textprint("Queen State: Butt charging\n"); + db_log3(("Queen State: Butt charging\n")); + /* Move function. */ + + + if(JumpDesired) + { + textprint("Jumping\n"); + sbPtr->DynPtr->LinImpulse.vy-=10000; + queenStatusPointer->next_move=QM_Standby; + queenStatusPointer->current_move=QM_Jump; + } + else + { + QueenMove_ButtCharge(sbPtr); + } + + break; + } + + case (QM_Jump): + { + textprint("Queen State: Jumping\n"); + db_log3(("Queen State: Jumping\n")); + //stay in jump mode until queen hits the floor again + if(!dynPtr->IsInContactWithFloor) + { + sbPtr->DynPtr->LinVelocity.vx=sbPtr->DynPtr->OrientMat.mat31/10; + sbPtr->DynPtr->LinVelocity.vy=0; + sbPtr->DynPtr->LinVelocity.vz=sbPtr->DynPtr->OrientMat.mat33/10; + } + else + { + queenStatusPointer->current_move=queenStatusPointer->next_move; + queenStatusPointer->next_move=QM_Standby; + queenStatusPointer->moveTimer=0; + } + + break; + } + + case (QM_Climbing): + { + textprint("Queen State: Climbing\n"); + sbPtr->DynPtr->LinVelocity.vx = 0; + sbPtr->DynPtr->LinVelocity.vy = 0; + sbPtr->DynPtr->LinVelocity.vz = 0; + QueenMove_Climb(sbPtr); + } + break; + + default: + { + GLOBALASSERT(0); + return; + } + } + HModel_Regen(&queenStatusPointer->HModelController,(20*ONE_FIXED)); + + } + + queenStatusPointer->LastVelocity=dynPtr->LinVelocity; + + + /*----------------------------------** + ** Update object queen is carrying ** + **----------------------------------*/ + + if(queenStatusPointer->QueenState==QBS_CarryingObject) + { + ProveHModel(sbPtr->SBdptr->HModelControlBlock,sbPtr->SBdptr); + + QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->Position=queenStatusPointer->QueenRightHand->World_Offset; + QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->PrevPosition=queenStatusPointer->QueenRightHand->World_Offset; + QueenObjectList[queenStatusPointer->CurrentQueenObject]->DynPtr->OrientMat=queenStatusPointer->QueenRightHand->SecMat; + } + + sbPtr->SBDamageBlock.IsOnFire=0; + /* That would be silly. */ + +/*----------------------------------------------------------------------------------------** +** Monitor the queen's objects , and check for any high speed collisions with the player ** +**----------------------------------------------------------------------------------------*/ + { + int i; + for(i=0;iSBflags.destroyed_but_preserved) + { + BOOL doneBounceNoise=FALSE; + COLLISIONREPORT *nextReport; + + nextReport = QueenObjectList[i]->DynPtr->CollisionReportPtr; + + while(nextReport) + { + int impulse=Approximate3dMagnitude(&QueenObjectList[i]->DynPtr->LinImpulse); + if(impulse>10000) + { + //object hit something while moving quickly , so play a bounce sound + if(!doneBounceNoise) + { + ThrownObjectBounceNoise(i,&nextReport->ObstaclePoint); + doneBounceNoise=TRUE; + } + + if(nextReport->ObstacleSBPtr) + { + + if(nextReport->ObstacleSBPtr==Player->ObStrategyBlock || + nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourInanimateObject || + (nextReport->ObstacleSBPtr->name && !strcmp(nextReport->ObstacleSBPtr->name,"locker door"))) + { + + //object has hit the player at speed. + + DAMAGE_PROFILE impact_damage=QueenImpactDamage; + VECTORCH direction; + VECTORCH hit_object_direction; + int dotproduct; + + + //adjust the object's position so it is ear the player + //back in the direction that it came from + direction=QueenObjectList[i]->DynPtr->Position; + SubVector(&QueenObjectList[i]->DynPtr->PrevPosition,&direction); + if(direction.vx || direction.vy || direction.vz) + { + Normalise(&direction); + } + + hit_object_direction=nextReport->ObstacleSBPtr->DynPtr->Position; + SubVector(&nextReport->ObstacleSBPtr->DynPtr->PrevPosition,&hit_object_direction); + if(hit_object_direction.vx || hit_object_direction.vy || hit_object_direction.vz) + { + Normalise(&hit_object_direction); + } + + dotproduct=Dot(&direction,&hit_object_direction); + + //damage the player + impact_damage.Impact=40+MUL_FIXED(15,dotproduct); + CauseDamageToObject(nextReport->ObstacleSBPtr,&impact_damage, ONE_FIXED,NULL); + + //damage the thrown object as well (almost certainly destroying it) + impact_damage.Impact*=10; + CauseDamageToObject(QueenObjectList[i],&impact_damage, ONE_FIXED,NULL); + + + { + //knock the object back + VECTORCH* impulse; + impulse=&nextReport->ObstacleSBPtr->DynPtr->LinImpulse; + impulse->vx+=direction.vx/4; + impulse->vz+=direction.vz/4; + } + + + QueenObjectList[i]->DynPtr->Position.vx=nextReport->ObstacleSBPtr->DynPtr->Position.vx+direction.vx/100; + QueenObjectList[i]->DynPtr->Position.vz=nextReport->ObstacleSBPtr->DynPtr->Position.vz+direction.vz/100; + QueenObjectList[i]->DynPtr->PrevPosition.vx=QueenObjectList[i]->DynPtr->Position.vx; + QueenObjectList[i]->DynPtr->PrevPosition.vz=QueenObjectList[i]->DynPtr->Position.vz; + + //set the taunt timer + queenStatusPointer->QueenTauntTimer=ONE_FIXED/2; + + break; + } + } + } + nextReport = nextReport->NextCollisionReportPtr; + } + + } + } + } + + QueenSoundHiss(sbPtr); + +} + + +BOOL LockerDoorIsClosed() +{ + TRACK_OBJECT_BEHAV_BLOCK* door; + GLOBALASSERT(LockerDoorSbptr); + if(LockerDoorSbptr->SBflags.destroyed_but_preserved) return FALSE; + GLOBALASSERT(LockerDoorSbptr->SBdataptr); + + door=(TRACK_OBJECT_BEHAV_BLOCK*)LockerDoorSbptr->SBdataptr; + + GLOBALASSERT(door->to_track); + + if(door->to_track->reverse && !door->to_track->playing) return TRUE; + + return FALSE; + +} + +void HandleHangarAirlock() +{ + //only need to look out for the airlock in hangar + int wind_multiplier=0; + + if(!stricmp(LevelName,"hangar")) + { + GLOBALASSERT(UpperAirlockDoorSbptr); + GLOBALASSERT(UpperAirlockDoorSbptr->DynPtr); + GLOBALASSERT(LowerAirlockDoorSbptr); + GLOBALASSERT(LowerAirlockDoorSbptr->DynPtr); + + + //check to see which of the airlock doors are open + { + VECTORCH* door_pos=&UpperAirlockDoorSbptr->DynPtr->Position; + int upper_open_amount=0; + int lower_open_amount=0; + + if(door_pos->vz==UpperAirlockDoorStart.vz) + { + UpperAirlockDoorOpen=FALSE; + } + else + { + UpperAirlockDoorOpen=TRUE; + upper_open_amount=DIV_FIXED(door_pos->vz-UpperAirlockDoorStart.vz,AirlockOpeningDistance); + } + + door_pos=&LowerAirlockDoorSbptr->DynPtr->Position; + if(door_pos->vz==LowerAirlockDoorStart.vz) + { + LowerAirlockDoorOpen=FALSE; + } + else + { + LowerAirlockDoorOpen=TRUE; + lower_open_amount=DIV_FIXED(door_pos->vz-LowerAirlockDoorStart.vz,AirlockOpeningDistance); + } + + wind_multiplier=MUL_FIXED(upper_open_amount,lower_open_amount); + + if(wind_multiplier<0) wind_multiplier=-wind_multiplier; + //get a multiplier for the wind strength , based on how far the two pairs of doors are open + if(wind_multiplier>ONE_FIXED) wind_multiplier=ONE_FIXED; + + if(wind_multiplier>=ONE_FIXED) + { + AirlockTimeOpen+=NormalFrameTime; + } + else + { + AirlockTimeOpen=0; + } + + } + + if(LowerAirlockDoorOpen && UpperAirlockDoorOpen) + { + extern int NumActiveBlocks; + + int i = NumActiveBlocks; + extern DISPLAYBLOCK *ActiveBlockList[]; + + textprint("Wind strength %d\n",wind_multiplier); + + + for(i=0;iObStrategyBlock; + if(sbPtr && sbPtr->DynPtr && !sbPtr->DynPtr->IsStatic) + { + VECTORCH* pos=&sbPtr->DynPtr->Position; + VECTORCH* cur_impulse=&sbPtr->DynPtr->LinImpulse; + VECTORCH impulse; + BOOL above_airlock=FALSE; + + if(pos->vx>HangarLockerMinX && pos->vxvz>HangarLockerMinZ && pos->vzvy>20000) + { + //outside , so damage this object + if(sbPtr->I_SBtype==I_BehaviourQueenAlien) + //the queen has loads of health , so need to damage her quicker + CauseDamageToObject(sbPtr,&VacuumDamage,NormalFrameTime*30,NULL); + else + CauseDamageToObject(sbPtr,&VacuumDamage,NormalFrameTime,NULL); + + if(pos->vy>21000) + { + //turn off gravity + sbPtr->DynPtr->GravityOn=0; + } + continue; + } + else if(AirlockTimeOpen> 10*ONE_FIXED) + { + /* + After 10 seconds start doing damage to objects even if they aren't outside yet. + Scale damage so it increases linearly until 30 seconds have passed + */ + + int multiplier; + AirlockTimeOpen=max(AirlockTimeOpen,30*ONE_FIXED); + multiplier=MUL_FIXED(NormalFrameTime,(AirlockTimeOpen-10*ONE_FIXED)/20); + + CauseDamageToObject(sbPtr,&VacuumDamage,multiplier,NULL); + } + + + if(pos->vx>AirlockMinX && pos->vxvz>AirlockMinZ && pos->vzvx; + impulse.vy=0; + impulse.vz=AirlockCentreZ-pos->vz; + + if(!above_airlock && impulse.vx<0) + { + if(impulse.vz*2>impulse.vx && impulse.vz*2<-impulse.vx) + { + if(impulse.vz>0) + { + impulse.vz-=12000; + + } + else + { + impulse.vz+=12000; + } + } + + } + + Normalise(&impulse); + + impulse.vx/=2; + if(above_airlock) + impulse.vy=30000; + else + impulse.vy=0; + impulse.vz/=2; + + if(wind_multiplier0) + { + if(impulse.vx>cur_impulse->vx) + { + cur_impulse->vx+=MUL_FIXED(impulse.vx,NormalFrameTime); + cur_impulse->vx=min(cur_impulse->vx,impulse.vx); + } + } + else + { + if(impulse.vxvx) + { + cur_impulse->vx+=MUL_FIXED(impulse.vx,NormalFrameTime); + cur_impulse->vx=max(cur_impulse->vx,impulse.vx); + } + } + + if(impulse.vy>0) + { + if(impulse.vy>cur_impulse->vy) + { + cur_impulse->vy+=MUL_FIXED(impulse.vy,NormalFrameTime); + cur_impulse->vy=min(cur_impulse->vy,impulse.vy); + } + } + else + { + if(impulse.vyvy) + { + cur_impulse->vy+=MUL_FIXED(impulse.vy,NormalFrameTime); + cur_impulse->vy=max(cur_impulse->vy,impulse.vy); + } + } + + + if(impulse.vz>0) + { + if(impulse.vz>cur_impulse->vz) + { + cur_impulse->vz+=MUL_FIXED(impulse.vz,NormalFrameTime); + cur_impulse->vz=min(cur_impulse->vz,impulse.vz); + } + } + else + { + if(impulse.vzvz) + { + cur_impulse->vz+=MUL_FIXED(impulse.vz,NormalFrameTime); + cur_impulse->vz=max(cur_impulse->vz,impulse.vz); + } + } + + + if((pos->vy+ActiveBlockList[i]->ObMaxY)>3950 && !above_airlock) + { + if(sbPtr->DynPtr->UseStandardGravity) + cur_impulse->vy-=MUL_FIXED(MUL_FIXED(GRAVITY_STRENGTH+5000,NormalFrameTime),wind_multiplier); + else + cur_impulse->vy-=MUL_FIXED(MUL_FIXED(5000,NormalFrameTime),wind_multiplier); + + } + + + } + } + } + } +} + + +static BOOL TargetIsFiringFlamethrowerAtQueen(STRATEGYBLOCK *sbPtr) +{ + QUEEN_STATUS_BLOCK *queenStatusPointer; + GLOBALASSERT(sbPtr); + + queenStatusPointer=(QUEEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + + //only marine has flamethrower + if(AvP.PlayerType!=I_Marine) return FALSE; + + //queen must be heading for the player + if(queenStatusPointer->QueenTargetSB!=Player->ObStrategyBlock) return FALSE; + if(queenStatusPointer->TempTarget) return FALSE; + + QueenCalculateTargetInfo(sbPtr); + + if(queenStatusPointer->TargetDistance>30000) return FALSE; //queen is too far away to be harmed + //if(queenStatusPointer->TargetDistance<3000) return FALSE; //queen close enough to attack , so she may as well go ahead + /* + if (queenStatusPointer->attack_delta->timer!=(ONE_FIXED-1) && + queenStatusPointer->attack_delta->timer!=0) + { + //currently attacking + return FALSE; + } + */ + { + /* Is the player firing a flamethrower? */ + PLAYER_WEAPON_DATA *weaponPtr; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + + if (weaponPtr->WeaponIDNumber != WEAPON_FLAMETHROWER) + { + return(FALSE); + } + if (weaponPtr->CurrentState != WEAPONSTATE_FIRING_PRIMARY) + { + return(FALSE); + } + + } + + //The player is firing the flamethrower. + //are the queen and player facing each other + + { + + VECTORCH offset; + MATRIXCH WtoL; + + WtoL=sbPtr->DynPtr->OrientMat; + + offset=sbPtr->DynPtr->Position; + SubVector(&Player->ObWorld,&offset); + + TransposeMatrixCH(&WtoL); + RotateVector(&offset,&WtoL); + + if ( (offset.vz <0) + && (offset.vz < offset.vx) + && (offset.vz < -offset.vx) + && (offset.vz < offset.vy) + && (offset.vz < -offset.vy) ) { + + /* 90 horizontal, 90 vertical... continue. */ + } else { + return(FALSE); + } + + /* Now test it for the other way round. */ + + WtoL=Player->ObMat; + + offset=Player->ObWorld; + SubVector(&sbPtr->DynPtr->Position,&offset); + + TransposeMatrixCH(&WtoL); + RotateVector(&offset,&WtoL); + + if ( (offset.vz <0) + && (offset.vz < offset.vx) + && (offset.vz < -offset.vx) + && (offset.vz < offset.vy) + && (offset.vz < -offset.vy) ) { + + /* 90 horizontal, 90 vertical... continue. */ + } else { + return(FALSE); + } + + } + + /* If here, then it must be true! */ + return(TRUE); + + + +} + + +static void MakeNonFragable_Recursion(SECTION_DATA *this_section_data) +{ + SECTION_DATA *sdptr; + int health_increment; + + sdptr=NULL; + + /* flag this section. */ + this_section_data->sempai->flags|=section_flag_never_frag; + + /* Now call recursion... */ + + if (this_section_data->First_Child!=NULL) { + + SECTION_DATA *child_list_ptr; + + child_list_ptr=this_section_data->First_Child; + + while (child_list_ptr!=NULL) { + MakeNonFragable_Recursion(child_list_ptr); + child_list_ptr=child_list_ptr->Next_Sibling; + } + } + + return; +} + +static void MakeNonFragable(HMODELCONTROLLER *controller) +{ + MakeNonFragable_Recursion(controller->section_data); +} + + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" + +typedef struct queen_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + +//behaviour block stuff + + QUEEN_BEHAVIOUR_STATE QueenState; + QUEEN_MANOEUVRE current_move; + QUEEN_MANOEUVRE next_move; + + QUEEN_FOOT fixed_foot; + VECTORCH fixed_foot_oldpos; + + VECTORCH TargetPos; + + int moveTimer; + + NPC_WANDERDATA wanderData; + + BOOL TempTarget;//going for an intermediate point + int TempTargetTimer;//time before queen gives up going for intermediate point + + int CurrentQueenObject; + int QueenStateTimer; + int QueenObjectBias; + int QueenPlayerBias; + int QueenTauntTimer; + int QueenFireTimer; + VECTORCH LastVelocity; + + BOOL BeenInAirlock; + BOOL QueenActivated; //queen is inactive until seen + + BOOL TargetInfoValid; //have the next three items been set + int TargetDistance; //distance of current target from queen + int TargetRelSpeed; //targets speed in queen's direction + VECTORCH TargetDirection; //targets direction relative to queen + VECTORCH VectToTarget; + + unsigned int PlayingHitDelta :1; + + int SwerveTimer; + BOOL SwerveDirection; + + QUEEN_SOUND_CATEGORY lastSoundCategory; + + VECTORCH ClimbStartPosition; //used when climing out of the airlock + BOOL AttackDoneItsDamage; + +//and now those evil globals... + BOOL PlayerInTrench; + BOOL PlayerInLocker; + int AirlockTimeOpen; + BOOL UpperAirlockDoorOpen; + BOOL LowerAirlockDoorOpen; + VECTORCH UpperAirlockDoorStart; + VECTORCH LowerAirlockDoorStart; + + +//annoying pointer related things + char Target_SBname[SB_NAME_LENGTH]; + + SECTION_DATA *fixed_foot_section; + SECTION_DATA* QueenRightHand; + +//strategyblock stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; + DYNAMICSBLOCK dynamics; +}QUEEN_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV queenStatusPointer + +void LoadStrategy_Queen(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + QUEEN_STATUS_BLOCK* queenStatusPointer; + QUEEN_SAVE_BLOCK* block = (QUEEN_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourQueenAlien) return; + + queenStatusPointer =(QUEEN_STATUS_BLOCK*) sbPtr->SBdataptr; + + //normally done on first frame , but need to do this here when loading + FindQueenObjects(); + + + //start copying stuff + COPYELEMENT_LOAD(QueenState) + COPYELEMENT_LOAD(current_move) + COPYELEMENT_LOAD(next_move) + + COPYELEMENT_LOAD(fixed_foot) + COPYELEMENT_LOAD(fixed_foot_oldpos) + + COPYELEMENT_LOAD(TargetPos) + + COPYELEMENT_LOAD(moveTimer) + + COPYELEMENT_LOAD(wanderData) + + COPYELEMENT_LOAD(TempTarget)//going for an intermediate point + COPYELEMENT_LOAD(TempTargetTimer)//time before queen gives up going for intermediate point + + COPYELEMENT_LOAD(CurrentQueenObject) + COPYELEMENT_LOAD(QueenStateTimer) + COPYELEMENT_LOAD(QueenObjectBias) + COPYELEMENT_LOAD(QueenPlayerBias) + COPYELEMENT_LOAD(QueenTauntTimer) + COPYELEMENT_LOAD(QueenFireTimer) + COPYELEMENT_LOAD(LastVelocity) + + COPYELEMENT_LOAD(BeenInAirlock) + COPYELEMENT_LOAD(QueenActivated) //queen is inactive until seen + + COPYELEMENT_LOAD(TargetInfoValid) //have the next three items been set + COPYELEMENT_LOAD(TargetDistance) //distance of current target from queen + COPYELEMENT_LOAD(TargetRelSpeed) //targets speed in queen's direction + COPYELEMENT_LOAD(TargetDirection) //targets direction relative to queen + COPYELEMENT_LOAD(VectToTarget) + + COPYELEMENT_LOAD(PlayingHitDelta) + COPYELEMENT_LOAD(SwerveTimer) + COPYELEMENT_LOAD(SwerveDirection) + COPYELEMENT_LOAD(lastSoundCategory) + + COPYELEMENT_LOAD(ClimbStartPosition) //used when climing out of the airlock + COPYELEMENT_LOAD(AttackDoneItsDamage) + + //load globals + PlayerInTrench = block->PlayerInTrench; + PlayerInLocker = block->PlayerInLocker; + AirlockTimeOpen = block->AirlockTimeOpen; + UpperAirlockDoorOpen = block->UpperAirlockDoorOpen; + LowerAirlockDoorOpen = block->LowerAirlockDoorOpen; + UpperAirlockDoorStart = block->UpperAirlockDoorStart; + LowerAirlockDoorStart = block->LowerAirlockDoorStart; + + + //load target + queenStatusPointer->QueenTargetSB = FindSBWithName(block->Target_SBname); + + + //copy strategy block stuff + *sbPtr->DynPtr = block->dynamics; + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + + //load hierarchy + { + SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); + if(hier_header) + { + LoadHierarchy(hier_header,&queenStatusPointer->HModelController); + } + } + + //get delta controller pointers + queenStatusPointer->attack_delta=Get_Delta_Sequence(&queenStatusPointer->HModelController,"attack"); + queenStatusPointer->hit_delta=Get_Delta_Sequence(&queenStatusPointer->HModelController,"hit"); + + + + //get section data pointers + + if(queenStatusPointer->fixed_foot == LeftFoot) + { + queenStatusPointer->fixed_foot_section=GetThisSectionData(queenStatusPointer->HModelController.section_data, + "left foot"); + } + else + { + queenStatusPointer->fixed_foot_section=GetThisSectionData(queenStatusPointer->HModelController.section_data, + "right foot"); + + } + + queenStatusPointer->QueenRightHand=GetThisSectionData(queenStatusPointer->HModelController.section_data,"rrrr fing"); + + Load_SoundState(&queenStatusPointer->soundHandle); + + +} + +void SaveStrategy_Queen(STRATEGYBLOCK* sbPtr) +{ + QUEEN_STATUS_BLOCK* queenStatusPointer; + QUEEN_SAVE_BLOCK* block; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + queenStatusPointer = (QUEEN_STATUS_BLOCK*) sbPtr->SBdataptr; + + //start copying stuff + COPYELEMENT_SAVE(QueenState) + COPYELEMENT_SAVE(current_move) + COPYELEMENT_SAVE(next_move) + + COPYELEMENT_SAVE(fixed_foot) + COPYELEMENT_SAVE(fixed_foot_oldpos) + + COPYELEMENT_SAVE(TargetPos) + + COPYELEMENT_SAVE(moveTimer) + + COPYELEMENT_SAVE(wanderData) + + COPYELEMENT_SAVE(TempTarget)//going for an intermediate point + COPYELEMENT_SAVE(TempTargetTimer)//time before queen gives up going for intermediate point + + COPYELEMENT_SAVE(CurrentQueenObject) + COPYELEMENT_SAVE(QueenStateTimer) + COPYELEMENT_SAVE(QueenObjectBias) + COPYELEMENT_SAVE(QueenPlayerBias) + COPYELEMENT_SAVE(QueenTauntTimer) + COPYELEMENT_SAVE(QueenFireTimer) + COPYELEMENT_SAVE(LastVelocity) + + COPYELEMENT_SAVE(BeenInAirlock) + COPYELEMENT_SAVE(QueenActivated) //queen is inactive until seen + + COPYELEMENT_SAVE(TargetInfoValid) //have the next three items been set + COPYELEMENT_SAVE(TargetDistance) //distance of current target from queen + COPYELEMENT_SAVE(TargetRelSpeed) //targets speed in queen's direction + COPYELEMENT_SAVE(TargetDirection) //targets direction relative to queen + COPYELEMENT_SAVE(VectToTarget) + + COPYELEMENT_SAVE(PlayingHitDelta) + COPYELEMENT_SAVE(SwerveTimer) + COPYELEMENT_SAVE(SwerveDirection) + COPYELEMENT_SAVE(lastSoundCategory) + + COPYELEMENT_SAVE(ClimbStartPosition) //used when climing out of the airlock + COPYELEMENT_SAVE(AttackDoneItsDamage) + + //save globals + block->PlayerInTrench = PlayerInTrench; + block->PlayerInLocker = PlayerInLocker; + block->AirlockTimeOpen = AirlockTimeOpen; + block->UpperAirlockDoorOpen = UpperAirlockDoorOpen; + block->LowerAirlockDoorOpen = LowerAirlockDoorOpen; + block->UpperAirlockDoorStart = UpperAirlockDoorStart; + block->LowerAirlockDoorStart = LowerAirlockDoorStart; + + //save target + if(queenStatusPointer->QueenTargetSB) + { + COPY_NAME(block->Target_SBname,queenStatusPointer->QueenTargetSB->SBname); + } + else + { + COPY_NAME(block->Target_SBname,Null_Name); + } + + //save strategy block stuff + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; + + //save the hierarchy + SaveHierarchy(&queenStatusPointer->HModelController); + + Save_SoundState(&queenStatusPointer->soundHandle); +} \ No newline at end of file diff --git a/3dc/avp/bh_queen.h b/3dc/avp/bh_queen.h new file mode 100644 index 0000000..05e07ba --- /dev/null +++ b/3dc/avp/bh_queen.h @@ -0,0 +1,141 @@ +/* ChrisF 17/3/98 ------------------------------------------------ + Header file for alien queen support functions + -----------------------------------------------------------------*/ + +#ifndef _bhqueen_h_ +#define _bhqueen_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#include "bh_pred.h" +#include "scream.h" + +typedef enum queen_behaviour_state { + + QBS_Command, + QBS_Waypoints, + QBS_Engagement, + QBS_GoingForObject, + QBS_CarryingObject, + QBS_Reconsider, + QBS_ClimbingOutOfAirlock, + QBS_Dead, + +} QUEEN_BEHAVIOUR_STATE; + +typedef enum queen_manoeuvre { + QM_Standby, + QM_StepForward, + QM_StepBack, + QM_TurnLeft, + QM_TurnRight, + QM_ComeToPoint, + QM_Taunt, + QM_Hiss, + QM_LeftSwipe, + QM_RightSwipe, + QM_Charge, + QM_Close, + QM_Jump, + QM_ButtCharge, + QM_ButtAttack, + QM_Stun, + QM_Climbing, + QM_ChangeFacing, + QM_ApproachWall, +} QUEEN_MANOEUVRE; + +typedef enum queen_foot { + LeftFoot, + RightFoot, +} QUEEN_FOOT; + +typedef struct tools_data_queen +{ + struct vectorch position; + int shapeIndex; + char nameID[SB_NAME_LENGTH]; + char death_target_ID[SB_NAME_LENGTH]; + int death_target_request; +}TOOLS_DATA_QUEEN; + +typedef struct queenStatusBlock +{ + QUEEN_BEHAVIOUR_STATE QueenState; + QUEEN_MANOEUVRE current_move; + QUEEN_MANOEUVRE next_move; + + QUEEN_FOOT fixed_foot; + SECTION_DATA *fixed_foot_section; + VECTORCH fixed_foot_oldpos; + + DELTA_CONTROLLER *attack_delta; + DELTA_CONTROLLER *hit_delta; + VECTORCH TargetPos; + + int moveTimer; + + NPC_MOVEMENTDATA moveData; + NPC_WANDERDATA wanderData; + HMODELCONTROLLER HModelController; + + char death_target_ID[SB_NAME_LENGTH]; + STRATEGYBLOCK* death_target_sbptr; + int death_target_request; + + BOOL TempTarget;//going for an intermediate point + int TempTargetTimer;//time before queen gives up going for intermediate point + + int CurrentQueenObject; + int QueenStateTimer; + int QueenObjectBias; + int QueenPlayerBias; + int QueenTauntTimer; + int QueenFireTimer; + VECTORCH LastVelocity; + SECTION_DATA* QueenRightHand; + STRATEGYBLOCK* QueenTargetSB; + + BOOL BeenInAirlock; + BOOL QueenActivated; //queen is inactive until seen + + BOOL TargetInfoValid; //have the next three items been set + int TargetDistance; //distance of current target from queen + int TargetRelSpeed; //targets speed in queen's direction + VECTORCH TargetDirection; //targets direction relative to queen + VECTORCH VectToTarget; + + unsigned int PlayingHitDelta :1; + + int SwerveTimer; + BOOL SwerveDirection; + + VECTORCH ClimbStartPosition; //used when climing out of the airlock + BOOL AttackDoneItsDamage; + + /*special hangar airlock state stuff*/ + STRATEGYBLOCK* upper_airlockdoor_sbptr; + VECTORCH upper_airlockdoor_start; + STRATEGYBLOCK* lower_airlockdoor_sbptr; + VECTORCH lower_airlockdoor_start; + + int soundHandle; + QUEEN_SOUND_CATEGORY lastSoundCategory; + + +} QUEEN_STATUS_BLOCK; + + +void InitQueenBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr); +void QueenBehaviour(STRATEGYBLOCK *sbPtr); +void MakeQueenNear(STRATEGYBLOCK *sbPtr); +void MakeQueenFar(STRATEGYBLOCK *sbPtr); +void QueenIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple,SECTION_DATA *Section, VECTORCH *incoming, VECTORCH *point); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/3dc/avp/bh_selfdest.c b/3dc/avp/bh_selfdest.c new file mode 100644 index 0000000..d693270 --- /dev/null +++ b/3dc/avp/bh_selfdest.c @@ -0,0 +1,151 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "dynblock.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "bh_selfdest.h" +#include "dynamics.h" +#include "weapons.h" +#include "particle.h" +#include "psnd.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + + +extern int NormalFrameTime; + +void* SelfDestructBehaveInit(void* bhdata,STRATEGYBLOCK* sbptr) +{ + SELF_DESTRUCT_BEHAV_BLOCK* sd_bhv; + SELF_DESTRUCT_TOOLS_TEMPLATE* sd_tt; + + GLOBALASSERT(sbptr); + GLOBALASSERT(bhdata); + + sd_bhv=(SELF_DESTRUCT_BEHAV_BLOCK*)AllocateMem(sizeof(SELF_DESTRUCT_BEHAV_BLOCK)); + if(!sd_bhv) + { + memoryInitialisationFailure = 1; + return 0; + } + sd_bhv->bhvr_type=I_BehaviourSelfDestruct; + + sd_tt=(SELF_DESTRUCT_TOOLS_TEMPLATE*)bhdata; + + //copy stuff from tools template + COPY_NAME(sbptr->SBname, sd_tt->nameID); + sd_bhv->timer=sd_tt->timer; + sd_bhv->active=FALSE; + + return (void*)sd_bhv; + +} + + + +void SelfDestructBehaveFun(STRATEGYBLOCK* sbptr) +{ + SELF_DESTRUCT_BEHAV_BLOCK* sd_bhv; + GLOBALASSERT(sbptr); + sd_bhv = (SELF_DESTRUCT_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((sd_bhv->bhvr_type == I_BehaviourSelfDestruct)); + + if(sd_bhv->active) + { + sd_bhv->timer-=NormalFrameTime; + if(sd_bhv->timer<=0) + { + int i; + + /* KJL 16:20:57 27/08/98 - let's do some pyrotechnics */ + Sound_Play(SID_NICE_EXPLOSION,"d",&(Player->ObWorld)); + MakeVolumetricExplosionAt(&Player->ObWorld,EXPLOSION_HUGE); + Player->ObStrategyBlock->SBDamageBlock.IsOnFire=1; + + //blow up everone + for (i=0; iI_SBtype==I_BehaviourAlien || + sbPtr->I_SBtype==I_BehaviourQueenAlien || + sbPtr->I_SBtype==I_BehaviourFaceHugger || + sbPtr->I_SBtype==I_BehaviourPredator || + sbPtr->I_SBtype==I_BehaviourXenoborg || + sbPtr->I_SBtype==I_BehaviourMarine || + sbPtr->I_SBtype==I_BehaviourSeal || + sbPtr->I_SBtype==I_BehaviourPredatorAlien || + sbPtr->I_SBtype==I_BehaviourAlien || + sbPtr->I_SBtype==I_BehaviourMarinePlayer || + sbPtr->I_SBtype==I_BehaviourPredatorPlayer || + sbPtr->I_SBtype==I_BehaviourAlienPlayer) + { + { + //kill the creature/player + VECTORCH direction={0,-ONE_FIXED,0}; + CauseDamageToObject(sbPtr,&certainDeath,ONE_FIXED,&direction); + + } + } + } + sd_bhv->active = FALSE; + } + } +} + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" + +typedef struct self_destruct_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int timer; //in fixed point seconds + BOOL active; +}SELF_DESTRUCT_SAVE_BLOCK; + +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV sd_bhv + +void LoadStrategy_SelfDestruct(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + SELF_DESTRUCT_BEHAV_BLOCK* sd_bhv; + SELF_DESTRUCT_SAVE_BLOCK* block = (SELF_DESTRUCT_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourSelfDestruct) return; + + sd_bhv = (SELF_DESTRUCT_BEHAV_BLOCK*)sbPtr->SBdataptr; + + //start copying stuff + COPYELEMENT_LOAD(timer); + COPYELEMENT_LOAD(active); +} + +void SaveStrategy_SelfDestruct(STRATEGYBLOCK* sbPtr) +{ + SELF_DESTRUCT_SAVE_BLOCK *block; + SELF_DESTRUCT_BEHAV_BLOCK* sd_bhv; + + sd_bhv = (SELF_DESTRUCT_BEHAV_BLOCK*)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + COPYELEMENT_SAVE(timer); + COPYELEMENT_SAVE(active); + +} diff --git a/3dc/avp/bh_selfdest.h b/3dc/avp/bh_selfdest.h new file mode 100644 index 0000000..c0a1348 --- /dev/null +++ b/3dc/avp/bh_selfdest.h @@ -0,0 +1,38 @@ +#ifndef _bh_selfdest_h +#define _bh_selfdest_h 1 + +#ifdef __cplusplus + + extern "C" { + +#endif + +extern void* SelfDestructBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr); +extern void SelfDestructBehaveFun(STRATEGYBLOCK* sbptr); + + +typedef struct self_destruct_behav_block +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + int timer; //in fixed point seconds + BOOL active; +}SELF_DESTRUCT_BEHAV_BLOCK; + +typedef struct self_destruct_tools_template +{ + char nameID[SB_NAME_LENGTH]; + int timer; +}SELF_DESTRUCT_TOOLS_TEMPLATE; + + + + + +#ifdef __cplusplus + + }; + +#endif + + +#endif diff --git a/3dc/avp/bh_snds.c b/3dc/avp/bh_snds.c new file mode 100644 index 0000000..8a6409a --- /dev/null +++ b/3dc/avp/bh_snds.c @@ -0,0 +1,293 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "bh_snds.h" +#include "dynblock.h" +#include "dynamics.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "dxlog.h" + +#include "psndplat.h" +#include "jsndsup.h" + + +void * SoundBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr) +{ + SOUND_BEHAV_BLOCK * sbb = 0; + SOUND_TOOLS_TEMPLATE * stt = (SOUND_TOOLS_TEMPLATE *)bhdata; + + GLOBALASSERT (sbptr && stt); + + sbb = (SOUND_BEHAV_BLOCK *)AllocateMem (sizeof (SOUND_BEHAV_BLOCK)); + + GLOBALASSERT (sbb); + + sbb->sound_loaded = stt->sound_loaded; + + sbb->position = stt->position; + sbb->inner_range = stt->inner_range; + sbb->outer_range = stt->outer_range; + sbb->max_volume = stt->max_volume; + sbb->pitch = stt->pitch; + + sbb->sound_not_started = 1; + + sbb->wav_name = (char *) AllocateMem (strlen (stt->sound_name) + 1); + strcpy (sbb->wav_name, stt->sound_name); + + sbb->playing=stt->playing; + sbb->loop=stt->loop; + + sbb->activ_no = SOUND_NOACTIVEINDEX; + + return((void*)sbb); + +} + +void SoundBehaveDestroy (STRATEGYBLOCK * sbptr) +{ + SOUND_BEHAV_BLOCK * sbb = (SOUND_BEHAV_BLOCK*)sbptr->SBdataptr; + + if (sbb->activ_no != SOUND_NOACTIVEINDEX) + { + Sound_Stop (sbb->activ_no); + } + if (sbb->wav_name) + { + DeallocateMem (sbb->wav_name); + } +} +void SoundBehaveFun (STRATEGYBLOCK * sbptr) +{ + SOUND_BEHAV_BLOCK * sbb = (SOUND_BEHAV_BLOCK*)sbptr->SBdataptr; + + + if(!sbb->sound_loaded) return; + if (sbb->sound_not_started && Player) + { + SOUND3DDATA s3d; + + if(sbb->playing) + { + //start playing the sound , but only if it is close enough + int dist=VectorDistance(&Player->ObWorld,&sbb->position); + if(dist<=sbb->outer_range) + { + + s3d.position = sbb->position; + s3d.inner_range = sbb->inner_range; + s3d.outer_range = sbb->outer_range; + s3d.velocity.vx = 0; + s3d.velocity.vy = 0; + s3d.velocity.vz = 0; + + if(sbb->loop) + Sound_Play ((SOUNDINDEX)sbb->sound_loaded->sound_num, "nelh", &s3d, &sbb->activ_no); + else + Sound_Play ((SOUNDINDEX)sbb->sound_loaded->sound_num, "neh", &s3d, &sbb->activ_no); + + if (sbb->activ_no != SOUND_NOACTIVEINDEX) + { + Sound_ChangeVolume (sbb->activ_no, sbb->max_volume); + Sound_ChangePitch (sbb->activ_no, sbb->pitch); + } + } + } + sbb->sound_not_started = 0; + } + + /* KJL 14:15:39 12/8/97 - kill any objects that are too far away */ + if(sbb->playing) + { + int dist=VectorDistance(&Player->ObWorld,&sbb->position); + if(dist>sbb->outer_range) + { + //stop sound if it is playing + + if (sbb->activ_no != SOUND_NOACTIVEINDEX) + { + Sound_Stop (sbb->activ_no); + } + if(!sbb->loop && sbb->playing) + { + //not much point in restarting a non-looping sound, since it won't restart at the right place + sbb->playing=0; + } + return; + } + } + + if (sbb->activ_no == SOUND_NOACTIVEINDEX && sbb->sound_loaded && sbb->playing) + { + if(sbb->loop) + { + SOUND3DDATA s3d; + + s3d.position = sbb->position; + s3d.inner_range = sbb->inner_range; + s3d.outer_range = sbb->outer_range; + s3d.velocity.vx = 0; + s3d.velocity.vy = 0; + s3d.velocity.vz = 0; + + if(sbb->loop) + Sound_Play ((SOUNDINDEX)sbb->sound_loaded->sound_num, "nelh", &s3d, &sbb->activ_no); + else + Sound_Play ((SOUNDINDEX)sbb->sound_loaded->sound_num, "neh", &s3d, &sbb->activ_no); + + if (sbb->activ_no != SOUND_NOACTIVEINDEX) + { + Sound_ChangeVolume (sbb->activ_no, sbb->max_volume); + Sound_ChangePitch (sbb->activ_no, sbb->pitch); + } + } + else //sound has finished playing + { + sbb->playing=0; + } + } + + // hack hack hack fixme fixme fix me + #pragma message ("Special code to deal with siren.wav!!"); + + if (AvP.DestructTimer != -1) + { + if (sbb->sound_loaded && sbb->activ_no != SOUND_NOACTIVEINDEX) + { + if (!_stricmp(GameSounds[sbb->sound_loaded->sound_num].wavName, "siren.wav")) + { + if (AvP.DestructTimer < ONE_FIXED * 10) + { + sbb->max_volume = 127; + } + else + { + sbb->max_volume = 90; + } + Sound_ChangeVolume (sbb->activ_no, sbb->max_volume); + } + } + } +} + + +void StartPlacedSoundPlaying(STRATEGYBLOCK* sbptr) +{ + SOUND_BEHAV_BLOCK * sbb = 0; + GLOBALASSERT(sbptr); + GLOBALASSERT(sbptr->I_SBtype==I_BehaviourPlacedSound); + sbb = (SOUND_BEHAV_BLOCK*)sbptr->SBdataptr; + + if(!sbb->sound_loaded) return; + + if(!sbb->playing) + { + //if sound is within range start it + int dist=VectorDistance(&Player->ObWorld,&sbb->position); + if(distouter_range) + { + SOUND3DDATA s3d; + + s3d.position = sbb->position; + s3d.inner_range = sbb->inner_range; + s3d.outer_range = sbb->outer_range; + s3d.velocity.vx = 0; + s3d.velocity.vy = 0; + s3d.velocity.vz = 0; + + if(sbb->loop) + Sound_Play ((SOUNDINDEX)sbb->sound_loaded->sound_num, "nelh", &s3d, &sbb->activ_no); + else + Sound_Play ((SOUNDINDEX)sbb->sound_loaded->sound_num, "neh", &s3d, &sbb->activ_no); + + if (sbb->activ_no != SOUND_NOACTIVEINDEX) + { + Sound_ChangeVolume (sbb->activ_no, sbb->max_volume); + Sound_ChangePitch (sbb->activ_no, sbb->pitch); + } + } + sbb->playing=1; + } +} +void StopPlacedSoundPlaying(STRATEGYBLOCK* sbptr) +{ + SOUND_BEHAV_BLOCK * sbb = 0; + GLOBALASSERT(sbptr); + GLOBALASSERT(sbptr->I_SBtype==I_BehaviourPlacedSound); + sbb = (SOUND_BEHAV_BLOCK*)sbptr->SBdataptr; + + if(!sbb->sound_loaded) return; + if(sbb->playing) + { + sbb->playing=0; + if (sbb->activ_no != SOUND_NOACTIVEINDEX) + { + Sound_Stop (sbb->activ_no); + } + } +} + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" +typedef struct placed_sound_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + BOOL playing; + + +}PLACED_SOUND_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV sbb + +void LoadStrategy_PlacedSound(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + SOUND_BEHAV_BLOCK * sbb; + PLACED_SOUND_SAVE_BLOCK* block = (PLACED_SOUND_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourPlacedSound) return; + + sbb = (SOUND_BEHAV_BLOCK *)sbPtr->SBdataptr; + + //start copying stuff + COPYELEMENT_LOAD(playing) + + sbb->sound_not_started = 0; + Load_SoundState(&sbb->activ_no); +} + +void SaveStrategy_PlacedSound(STRATEGYBLOCK* sbPtr) +{ + PLACED_SOUND_SAVE_BLOCK* block; + SOUND_BEHAV_BLOCK * sbb; + + sbb = (SOUND_BEHAV_BLOCK *)sbPtr->SBdataptr; + + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + COPYELEMENT_SAVE(playing) + + Save_SoundState(&sbb->activ_no); + +} \ No newline at end of file diff --git a/3dc/avp/bh_snds.h b/3dc/avp/bh_snds.h new file mode 100644 index 0000000..717c0d3 --- /dev/null +++ b/3dc/avp/bh_snds.h @@ -0,0 +1,73 @@ +#ifndef _bh_snds_h +#define _bh_snds_h + +#include "3dc.h" +#include "inline.h" +#include "module.h" + +#include "jsndsup.h" + +#ifdef __cplusplus + + extern "C" { + +#endif + +typedef struct sound_tools_template +{ + VECTORCH position; + + unsigned long inner_range; + unsigned long outer_range; + + unsigned long max_volume; + unsigned long pitch; + + unsigned int playing :1; + unsigned int loop :1; + + char * sound_name; + LOADED_SOUND const * sound_loaded; + +} SOUND_TOOLS_TEMPLATE; + + +typedef struct sound_behav_block +{ + VECTORCH position; + + unsigned long inner_range; + unsigned long outer_range; + int max_volume; + int pitch; + + int activ_no; + + char * wav_name; + +// sound management stuff + + LOADED_SOUND const * sound_loaded; + + BOOL sound_not_started; + + unsigned int playing :1; + unsigned int loop :1; + +} SOUND_BEHAV_BLOCK; + +void * SoundBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr); +void SoundBehaveFun (STRATEGYBLOCK * ); +void SoundBehaveDestroy (STRATEGYBLOCK * sbptr); + +void StartPlacedSoundPlaying(STRATEGYBLOCK* sbptr); +void StopPlacedSoundPlaying(STRATEGYBLOCK* sbptr); + + +#ifdef __cplusplus + + }; // end of extern "c" + +#endif + +#endif \ No newline at end of file diff --git a/3dc/avp/bh_spcl.c b/3dc/avp/bh_spcl.c new file mode 100644 index 0000000..d365404 --- /dev/null +++ b/3dc/avp/bh_spcl.c @@ -0,0 +1,518 @@ +#include "3dc.h" +#include "bh_spcl.h" +#include "dynblock.h" + +#define UseLocalAssert Yes + +#include "ourasert.h" +#include "vision.h" +#include "plat_shp.h" + +extern int NormalFrameTime; + +signed int RequestFadeToBlackLevel = 0; + +extern DISPLAYBLOCK* Player; + +void * InitXenoMorphRoom (void * bhdata, STRATEGYBLOCK * sbptr) +{ + XENO_MORPH_ROOM_DATA * xmrd; + XENO_MORPH_ROOM_TOOLS_TEMPLATE * xmrtt; + MORPHCTRL* morphctrl; + MORPHHEADER* morphheader; + MORPHFRAME* morphframe; + MODULE * my_mod; + + GLOBALASSERT(sbptr); + + xmrd = (XENO_MORPH_ROOM_DATA *)AllocateMem(sizeof(XENO_MORPH_ROOM_DATA)); + if (!xmrd) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + + xmrd->bhvr_type = I_BehaviourXenoborgMorphRoom; + + xmrtt = (XENO_MORPH_ROOM_TOOLS_TEMPLATE *)bhdata; + + xmrd->MainShape = xmrtt->MainShape; + xmrd->ShutShape = xmrtt->ShutShape; + xmrd->WallsOutShape = xmrtt->WallsOutShape; + xmrd->ProbesInShape = xmrtt->ProbesInShape; + + morphctrl = (MORPHCTRL*)AllocateMem(sizeof(MORPHCTRL)); + if (!morphctrl) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + morphheader = (MORPHHEADER*)AllocateMem(sizeof(MORPHHEADER)); + if (!morphheader) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + morphframe = (MORPHFRAME*)AllocateMem(sizeof(MORPHFRAME)); + if (!morphframe) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + + morphframe->mf_shape1 = xmrd->MainShape; + morphframe->mf_shape2 = xmrd->ShutShape; + + morphheader->mph_numframes = 1; + morphheader->mph_maxframes = ONE_FIXED; + morphheader->mph_frames = morphframe; + + morphctrl->ObMorphCurrFrame = 0; + morphctrl->ObMorphFlags = 0; + morphctrl->ObMorphSpeed = 0; + morphctrl->ObMorphHeader = morphheader; + + // Copy the names over + COPY_NAME (sbptr->SBname, xmrtt->nameID); + COPY_NAME (xmrd->doorID, xmrtt->doorID); + + // Setup module ref + ConvertModuleNameToPointer (&xmrtt->my_module, MainSceneArray[0]->sm_marray); + my_mod = xmrtt->my_module.mref_ptr; + + GLOBALASSERT (my_mod); + + my_mod->m_sbptr = sbptr; + sbptr->SBmoptr = my_mod; + sbptr->SBmomptr = my_mod->m_mapptr; + sbptr->SBflags.no_displayblock = 1; + sbptr->shapeIndex = my_mod->m_mapptr->MapShape; + + + xmrd->XMR_Mctrl = morphctrl; + xmrd->XMR_State = XMRS_Idle; + xmrd->DoorToRoom = 0; + + sbptr->SBmorphctrl = xmrd->XMR_Mctrl; + sbptr->SBmorphctrl->ObMorphCurrFrame = 0; + + if(sbptr->SBmomptr) + { + sbptr->SBmomptr->MapMorphHeader = sbptr->SBmorphctrl->ObMorphHeader; + } + + + // set up the animation control +#if SupportWindows95 + { + int item_num; + TXACTRLBLK **pptxactrlblk; + int shape_num = my_mod->m_mapptr->MapShape; + SHAPEHEADER *shptr = GetShapeData(shape_num); + + SetupPolygonFlagAccessForShape(shptr); + + pptxactrlblk = &xmrd->tacb; + + for(item_num = 0; item_num < shptr->numitems; item_num ++) + { + POLYHEADER *poly = (POLYHEADER*)(shptr->items[item_num]); + LOCALASSERT(poly); + + if((Request_PolyFlags((void *)poly)) & iflag_txanim) + { + TXACTRLBLK *pnew_txactrlblk; + int num_seq = 0; + + pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK)); + if (pnew_txactrlblk) + { + pnew_txactrlblk->tac_flags = 0; + pnew_txactrlblk->tac_item = item_num; + pnew_txactrlblk->tac_sequence = 0; + pnew_txactrlblk->tac_node = 0; + pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shape_num, item_num); + pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shape_num); + + while(pnew_txactrlblk->tac_txarray[num_seq+1])num_seq++; + + /* set the flags in the animation header */ + // we only ever have one frame of animation per sequence - + // nb this can change talk to richard - one sequence with two frames + // or mutliple sequences??? + + // pnew_txactrlblk->tac_txah.txa_flags |= txa_flag_play; + + /* change the value held in pptxactrlblk + which point to the previous structures "next" + pointer*/ + + *pptxactrlblk = pnew_txactrlblk; + pptxactrlblk = &pnew_txactrlblk->tac_next; + } + else + { + memoryInitialisationFailure = 1; + } + } + } + *pptxactrlblk=0; + } +#endif + + RequestFadeToBlackLevel = 0; + + return((void*)xmrd); +} + +extern MODULE * playerPherModule; + +void XenoMorphRoomBehaviour (STRATEGYBLOCK * sbptr) +{ + XENO_MORPH_ROOM_DATA * xmrd = (XENO_MORPH_ROOM_DATA *)sbptr->SBdataptr; + MORPHCTRL * mctrl = xmrd->XMR_Mctrl; + + GLOBALASSERT (mctrl); + GLOBALASSERT (mctrl->ObMorphHeader); + GLOBALASSERT (mctrl->ObMorphHeader->mph_frames); + + + + switch (xmrd->XMR_State) + { + case XMRS_Idle : + { + if (sbptr->SBmoptr->m_dptr) + { + + if (playerPherModule == sbptr->SBmoptr) + { + VECTORCH diff; + diff.vx = Player->ObWorld.vx - sbptr->SBmoptr->m_dptr->ObWorld.vx; + diff.vy = Player->ObWorld.vy - sbptr->SBmoptr->m_dptr->ObWorld.vy; + diff.vz = Player->ObWorld.vz - sbptr->SBmoptr->m_dptr->ObWorld.vz; + + if (diff.vx * diff.vx + diff.vz * diff.vz < 200000) + { + xmrd->XMR_State = XMRS_SafetyChecks; + } + + } + + } + break; + } + + case XMRS_SafetyChecks : + { + BOOL can_continue = 1; + int i; + // waits to make sure everything is OK before it shuts the walls + + if (xmrd->DoorToRoom) + { + PROXDOOR_BEHAV_BLOCK * doorbhv = (PROXDOOR_BEHAV_BLOCK*)xmrd->DoorToRoom->SBdataptr; + + doorbhv->door_locked = 1; + + if (doorbhv->door_state != I_door_closed) + { + can_continue = 0; + } + + } + + for (i=0; iI_SBtype == I_BehaviourMarine || ActiveStBlockList[i]->I_SBtype == I_BehaviourSeal) + { + if (ActiveStBlockList[i]->containingModule == sbptr->SBmoptr) + { + can_continue = 0; + break; + } + } + } + + if (sbptr->SBmoptr->m_dptr) + { + + if (playerPherModule == sbptr->SBmoptr) + { + VECTORCH diff; + diff.vx = Player->ObWorld.vx - sbptr->SBmoptr->m_dptr->ObWorld.vx; + diff.vy = Player->ObWorld.vy - sbptr->SBmoptr->m_dptr->ObWorld.vy; + diff.vz = Player->ObWorld.vz - sbptr->SBmoptr->m_dptr->ObWorld.vz; + + + if (diff.vx * diff.vx + diff.vz * diff.vz > 200000) + { + can_continue = 0; + } + + if (Player->ObStrategyBlock->DynPtr->Position.vx != Player->ObStrategyBlock->DynPtr->PrevPosition.vx) + { + can_continue = 0; + } + if (Player->ObStrategyBlock->DynPtr->Position.vy != Player->ObStrategyBlock->DynPtr->PrevPosition.vy) + { + can_continue = 0; + } + if (Player->ObStrategyBlock->DynPtr->Position.vz != Player->ObStrategyBlock->DynPtr->PrevPosition.vz) + { + can_continue = 0; + } + } + else + { + can_continue = 0; + } + + } + else + { + can_continue = 0; + xmrd->XMR_State = XMRS_Idle; + } + + + if (can_continue) + { + // closes in player + mctrl->ObMorphHeader->mph_frames->mf_shape1 = xmrd->MainShape; + mctrl->ObMorphHeader->mph_frames->mf_shape2 = xmrd->ShutShape; + + mctrl->ObMorphCurrFrame = 0; + mctrl->ObMorphFlags = mph_flag_play; + mctrl->ObMorphFlags |= mph_flag_noloop; + mctrl->ObMorphFlags &= ~mph_flag_reverse; + mctrl->ObMorphFlags &= ~mph_flag_finished; + mctrl->ObMorphSpeed = 1 << 18; + + xmrd->XMR_State = XMRS_EnclosingPlayer; + } + break; + } + + case XMRS_EnclosingPlayer : + { + UpdateMorphing(mctrl); + + if(mctrl->ObMorphFlags & mph_flag_finished) + { + mctrl->ObMorphHeader->mph_frames->mf_shape1 = xmrd->ShutShape; + mctrl->ObMorphHeader->mph_frames->mf_shape2 = xmrd->WallsOutShape; + + mctrl->ObMorphCurrFrame = 0; + + mctrl->ObMorphFlags = mph_flag_play; + mctrl->ObMorphFlags |= mph_flag_noloop; + mctrl->ObMorphFlags &= ~mph_flag_reverse; + mctrl->ObMorphFlags &= ~mph_flag_finished; + mctrl->ObMorphSpeed = 1 << 13; + + xmrd->XMR_State = XMRS_WallsOut; + } + + break; + } + + case XMRS_WallsOut : + { + UpdateMorphing(mctrl); + + if(mctrl->ObMorphFlags & mph_flag_finished) + { + mctrl->ObMorphHeader->mph_frames->mf_shape1 = xmrd->WallsOutShape; + mctrl->ObMorphHeader->mph_frames->mf_shape2 = xmrd->ProbesInShape; + + mctrl->ObMorphCurrFrame = 0; + + mctrl->ObMorphFlags = mph_flag_play; + mctrl->ObMorphFlags |= mph_flag_noloop; + mctrl->ObMorphFlags &= ~mph_flag_reverse; + mctrl->ObMorphFlags &= ~mph_flag_finished; + mctrl->ObMorphSpeed = 1 << 13; + + xmrd->XMR_State = XMRS_ProbesIn; + } + break; + } + + case XMRS_ProbesIn : + { + UpdateMorphing(mctrl); + if(mctrl->ObMorphFlags & mph_flag_finished) + { + #if SupportWindows95 + d3d_light_ctrl.ctrl = LCCM_CONSTCOLOUR; + d3d_light_ctrl.r = ONE_FIXED - RequestFadeToBlackLevel; + d3d_light_ctrl.g = ONE_FIXED - RequestFadeToBlackLevel; + d3d_light_ctrl.b = ONE_FIXED - RequestFadeToBlackLevel; + #endif + + xmrd->XMR_State = XMRS_FadeToBlack; + } + break; + } + + case XMRS_FadeToBlack : + { + RequestFadeToBlackLevel += (NormalFrameTime >> 1); + + + if (RequestFadeToBlackLevel > (ONE_FIXED)) + { + RequestFadeToBlackLevel = ONE_FIXED; + xmrd->timer = 0; + xmrd->XMR_State = XMRS_Process; + } + #if SupportWindows95 + + d3d_light_ctrl.r = ONE_FIXED - RequestFadeToBlackLevel; + d3d_light_ctrl.g = ONE_FIXED - RequestFadeToBlackLevel; + d3d_light_ctrl.b = ONE_FIXED - RequestFadeToBlackLevel; + + #endif + + break; + } + + case XMRS_Process : + { + xmrd->timer += NormalFrameTime; + if (xmrd->timer > (ONE_FIXED << 3)) + { + if(sbptr->SBdptr) + { + SHAPEHEADER * pis = GetShapeData(xmrd->ProbesInShape); + SHAPEHEADER * ms = GetShapeData(xmrd->MainShape); + + sbptr->SBdptr->ObMorphCtrl = 0; + + xmrd->pis_items_str = pis->items; + xmrd->pis_sht_str = pis->sh_textures; + + pis->items = ms->items; + pis->sh_textures = ms->sh_textures; +#if PSX +#else + pis->sh_instruction[4].sh_instr_data = ms->sh_instruction[4].sh_instr_data; +#endif + +#if SupportWindows95 + sbptr->SBdptr->ObTxAnimCtrlBlks = xmrd->tacb; +#endif + + sbptr->SBdptr->ObShape = xmrd->ProbesInShape; + sbptr->SBdptr->ObShapeData = GetShapeData(xmrd->ProbesInShape); + + // This moves the player to the required location + + Player->ObStrategyBlock->DynPtr->Position = sbptr->SBdptr->ObWorld; + + Player->ObStrategyBlock->DynPtr->Position.vy += 1472; + Player->ObStrategyBlock->DynPtr->Position.vx -= 900; + Player->ObStrategyBlock->DynPtr->PrevPosition = Player->ObStrategyBlock->DynPtr->Position; + + Player->ObStrategyBlock->DynPtr->OrientEuler.EulerX = 0; + Player->ObStrategyBlock->DynPtr->OrientEuler.EulerY = 1024; + Player->ObStrategyBlock->DynPtr->OrientEuler.EulerZ = 0; + + Player->ObStrategyBlock->DynPtr->PrevOrientEuler = Player->ObStrategyBlock->DynPtr->OrientEuler; + CreateEulerMatrix (&Player->ObStrategyBlock->DynPtr->OrientEuler, + &Player->ObStrategyBlock->DynPtr->OrientMat); + + TransposeMatrixCH(&Player->ObStrategyBlock->DynPtr->OrientMat); + + Player->ObStrategyBlock->DynPtr->PrevOrientMat = Player->ObStrategyBlock->DynPtr->OrientMat; + + xmrd->XMR_State = XMRS_Return; + } + + } + break; + } + + case XMRS_Return : + { + RequestFadeToBlackLevel -= (NormalFrameTime >> 1); + if (RequestFadeToBlackLevel <= 0) + { + RequestFadeToBlackLevel = 0; + + xmrd->timer = 0; + xmrd->XMR_State = XMRS_ReleasePlayer; + #if SupportWindows95 + d3d_light_ctrl.ctrl = LCCM_NORMAL; + #endif + } + #if SupportWindows95 + + d3d_light_ctrl.r = ONE_FIXED - RequestFadeToBlackLevel; + d3d_light_ctrl.g = ONE_FIXED - RequestFadeToBlackLevel; + d3d_light_ctrl.b = ONE_FIXED - RequestFadeToBlackLevel; + + #endif + break; + } + + case XMRS_ReleasePlayer : + { + xmrd->timer += NormalFrameTime; + + if (xmrd->timer > (ONE_FIXED << 2)) + { + sbptr->SBdptr->ObShape = xmrd->MainShape; + sbptr->SBdptr->ObShapeData = GetShapeData(xmrd->MainShape); + + sbptr->SBdptr->ObMorphCtrl = mctrl; + mctrl->ObMorphHeader->mph_frames->mf_shape1 = xmrd->ProbesInShape; + mctrl->ObMorphHeader->mph_frames->mf_shape2 = xmrd->MainShape; + + mctrl->ObMorphCurrFrame = 0; + + mctrl->ObMorphFlags = mph_flag_play; + mctrl->ObMorphFlags |= mph_flag_noloop; + mctrl->ObMorphFlags &= ~mph_flag_reverse; + mctrl->ObMorphFlags &= ~mph_flag_finished; + mctrl->ObMorphSpeed = 1 << 15; + + xmrd->XMR_State = XMRS_Finished; + } + break; + } + + case XMRS_Finished : + { + if(!(mctrl->ObMorphFlags & mph_flag_finished)) + { + UpdateMorphing(mctrl); + } + else + { + SHAPEHEADER * pis = GetShapeData(xmrd->ProbesInShape); + +#if SupportWindows95 + sbptr->SBdptr->ObTxAnimCtrlBlks = 0; +#endif + pis->items = xmrd->pis_items_str; + pis->sh_textures = xmrd->pis_sht_str; + +#if PSX +#else + pis->sh_instruction[4].sh_instr_data = xmrd->pis_items_str; +#endif + xmrd->XMR_State = XMRS_Idle; + } + break; + } + + default : + GLOBALASSERT (0 == "Shouldn't be here"); + break; + + } + +} + diff --git a/3dc/avp/bh_spcl.h b/3dc/avp/bh_spcl.h new file mode 100644 index 0000000..e57044d --- /dev/null +++ b/3dc/avp/bh_spcl.h @@ -0,0 +1,77 @@ +#ifndef _bh_spcl_h +#define _bh_spcl_h 1 + +#include "3dc.h" +#include "inline.h" +#include "module.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" + + +void * InitXenoMorphRoom (void * bhdata, STRATEGYBLOCK * sbptr); +void XenoMorphRoomBehaviour (STRATEGYBLOCK * sbptr); + + +typedef struct xeno_morph_room_tools_template +{ + int MainShape; + + int ShutShape; + int WallsOutShape; + int ProbesInShape; + + MREF my_module; + char nameID[SB_NAME_LENGTH]; + + char doorID[SB_NAME_LENGTH]; + +} XENO_MORPH_ROOM_TOOLS_TEMPLATE; + +typedef enum xeno_morph_room_state +{ + XMRS_Idle, + XMRS_SafetyChecks, + XMRS_EnclosingPlayer, + XMRS_WallsOut, + XMRS_ProbesIn, + XMRS_FadeToBlack, + XMRS_Process, + XMRS_Return, + XMRS_ReleasePlayer, + XMRS_Finished, + +} XENO_MORPH_ROOM_STATE; + + +typedef struct xeno_morph_room_data +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + TXACTRLBLK *tacb; + + MORPHCTRL *XMR_Mctrl; + + XENO_MORPH_ROOM_STATE XMR_State; + + int MainShape; + int ShutShape; + int WallsOutShape; + int ProbesInShape; + + int timer; + +#if PSX + struct polyheader ** pis_items_str; + struct psx_texture ** pis_sht_str; +#else + int ** pis_items_str; + int ** pis_sht_str; +#endif + + char doorID[SB_NAME_LENGTH]; + STRATEGYBLOCK* DoorToRoom; + +} XENO_MORPH_ROOM_DATA; + +#endif \ No newline at end of file diff --git a/3dc/avp/bh_track.c b/3dc/avp/bh_track.c new file mode 100644 index 0000000..2ba7877 --- /dev/null +++ b/3dc/avp/bh_track.c @@ -0,0 +1,591 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "dynblock.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "bh_track.h" +#include "dynamics.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "plat_shp.h" +#include "pvisible.h" +#include "bh_debri.h" + +extern int RealFrameTime; + +void NotifyTargetsForTrackPoint(TRACK_OBJECT_BEHAV_BLOCK* to_bhv,int point_num,int reversing); + +void* TrackObjectBehaveInit(void* bhdata,STRATEGYBLOCK* sbptr) +{ + TRACK_OBJECT_BEHAV_BLOCK* to_bhv; + TRACK_OBJECT_TOOLS_TEMPLATE* to_tt; + int i; + + GLOBALASSERT(sbptr); + GLOBALASSERT(bhdata); + + to_bhv=(TRACK_OBJECT_BEHAV_BLOCK*)AllocateMem(sizeof(TRACK_OBJECT_BEHAV_BLOCK)); + if(!to_bhv) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + to_bhv->bhvr_type=I_BehaviourTrackObject; + + to_tt=(TRACK_OBJECT_TOOLS_TEMPLATE*)bhdata; + + sbptr->shapeIndex = to_tt->shape_num; + COPY_NAME(sbptr->SBname, to_tt->nameID); + + GLOBALASSERT(to_tt->track); + + to_bhv->to_track=to_tt->track; + to_bhv->to_track->sbptr=sbptr; + + GLOBALASSERT(sbptr->DynPtr); + + sbptr->DynPtr->Position = sbptr->DynPtr->PrevPosition = to_tt->position; + sbptr->DynPtr->OrientEuler = to_tt->orientation; + CreateEulerMatrix(&sbptr->DynPtr->OrientEuler, &sbptr->DynPtr->OrientMat); + TransposeMatrixCH(&sbptr->DynPtr->OrientMat); + + + + + /*check to see if object is animated.*/ + { + TXACTRLBLK **pptxactrlblk; + int item_num; + SHAPEHEADER *shptr = GetShapeData(to_tt->shape_num); + pptxactrlblk = &to_bhv->to_tac; + for(item_num = 0; item_num < shptr->numitems; item_num ++) + { + POLYHEADER *poly = (POLYHEADER*)(shptr->items[item_num]); + LOCALASSERT(poly); + + SetupPolygonFlagAccessForShape(shptr); + + if((Request_PolyFlags((void *)poly)) & iflag_txanim) + { + TXACTRLBLK *pnew_txactrlblk; + + pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK)); + if(pnew_txactrlblk) + { + pnew_txactrlblk->tac_flags = 0; + pnew_txactrlblk->tac_item = item_num; + pnew_txactrlblk->tac_sequence = 0; + pnew_txactrlblk->tac_node = 0; + pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(to_tt->shape_num, item_num); + pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, to_tt->shape_num); + + *pptxactrlblk = pnew_txactrlblk; + pptxactrlblk = &pnew_txactrlblk->tac_next; + } + else *pptxactrlblk = NULL; + } + } + *pptxactrlblk=0; + } + + to_bhv->request=track_no_request; + + + to_bhv->num_special_track_points=to_tt->num_special_track_points; + to_bhv->special_track_points=to_tt->special_track_points; + + to_bhv->destruct_target_request=to_tt->destruct_target_request; + for(i=0;idestruct_target_ID[i]=to_tt->destruct_target_ID[i]; + } + to_bhv->destruct_target_sbptr=0; + + /* Initialise object's stats */ + { + NPC_DATA *NpcData; + + NpcData=GetThisNpcData(I_NPC_DefaultInanimate); + LOCALASSERT(NpcData); + sbptr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + + sbptr->SBDamageBlock.Health*=to_tt->integrity; + + if (to_tt->integrity > 20) + { + to_bhv->Indestructable = Yes; + sbptr->integrity = DEFAULT_OBJECT_INTEGRITY; + } + else if (to_tt->integrity < 1) + { + to_bhv->Indestructable = No; + sbptr->integrity = 1; // die immediately + } + else + { + to_bhv->Indestructable = No; + sbptr->integrity = (DEFAULT_OBJECT_INTEGRITY)*(to_tt->integrity); + } + + + Update_Track_Position_Only(to_bhv->to_track); + + to_bhv->TimeUntilNetSynchAllowed=0; + + return ((void*)to_bhv); +} + +void NotifyTargetsForTrackPoint(TRACK_OBJECT_BEHAV_BLOCK* to_bhv,int point_num,int reversing) +{ + int i; + GLOBALASSERT(to_bhv); + + for(i=0;inum_special_track_points;i++) + { + if(to_bhv->special_track_points[i].track_point_no==point_num) + { + SPECIAL_TRACK_POINT* stp=&to_bhv->special_track_points[i]; + int j; + + for(j=0;jnum_targets;j++) + { + TRACK_POINT_TARGET* tpt=&stp->targets[j]; + if(reversing) + { + if(tpt->flags & TrackRequestFlag_ActiveBackward) + { + if(tpt->flags & TrackRequestFlag_OppositeBackward) + { + RequestState(tpt->target_sbptr,!tpt->request,0); + } + else + { + RequestState(tpt->target_sbptr,tpt->request,0); + } + } + } + else + { + if(tpt->flags & TrackRequestFlag_ActiveForward) + { + RequestState(tpt->target_sbptr,tpt->request,0); + } + } + } + + break; + } + } +} + +void TrackObjectBehaveFun(STRATEGYBLOCK* sbptr) +{ + TRACK_OBJECT_BEHAV_BLOCK *to_bhv; + TRACK_CONTROLLER* track; + int current_section; + int reversing; + GLOBALASSERT(sbptr); + to_bhv = (TRACK_OBJECT_BEHAV_BLOCK*)sbptr->SBdataptr; + GLOBALASSERT((to_bhv->bhvr_type == I_BehaviourTrackObject)); + GLOBALASSERT(to_bhv->to_track); + track=to_bhv->to_track; + + + + //update texture animation if object has one + if(to_bhv->to_tac) + { + DISPLAYBLOCK* dptr = sbptr->SBdptr; + + if(dptr) + { + if(!dptr->ObTxAnimCtrlBlks) + { + dptr->ObTxAnimCtrlBlks = to_bhv->to_tac; + } + } + + } + + //check to see if any request have come through. + + if(AvP.Network != I_No_Network) + { + if(to_bhv->request == track_no_request) + { + to_bhv->TimeUntilNetSynchAllowed-=RealFrameTime; + if(to_bhv->TimeUntilNetSynchAllowed<0) + { + to_bhv->TimeUntilNetSynchAllowed=0; + } + } + else + { + to_bhv->TimeUntilNetSynchAllowed=5*ONE_FIXED; + } + } + + switch(to_bhv->request) + { + case track_request_start : + { + Start_Track_Playing(track); + + to_bhv->request=track_no_request; + } + break; + + case track_request_startforward : + { + track->reverse=0; + Start_Track_Playing(track); + + to_bhv->request=track_no_request; + } + break; + + case track_request_startbackward : + { + track->reverse=1; + Start_Track_Playing(track); + + to_bhv->request=track_no_request; + } + break; + + case track_request_stop : + { + Stop_Track_Playing(track); + + to_bhv->request=track_no_request; + } + break; + } + + if(!track->playing) return; + + current_section=track->current_section; + reversing=track->reverse; + + Update_Track_Position(track); + + if(to_bhv->special_track_points) + { + //see which track points the track has gone through, and notify the + //targets for those points + + /* + if(reversing) + { + while(current_section!=track->current_section) + { + NotifyTargetsForTrackPoint(to_bhv,current_section,1); + current_section--; + if(current_section<0) + { + //looped to end , so passed last point + current_section=track->num_sections-1; + NotifyTargetsForTrackPoint(to_bhv,track->num_sections,1); + } + } + if(current_section==0 && !track->playing) + { + //stopped at start , so passed point 0 + NotifyTargetsForTrackPoint(to_bhv,0,1); + } + } + else + { + while(current_section!=track->current_section) + { + NotifyTargetsForTrackPoint(to_bhv,current_section+1,0); + current_section++; + if(current_section>=track->num_sections) + { + //looped to start , so passed first point + current_section=0; + NotifyTargetsForTrackPoint(to_bhv,0,0); + } + } + if(current_section==(track->num_sections-1) && !track->playing) + { + //stopped at end , so passed last point + NotifyTargetsForTrackPoint(to_bhv,track->num_sections,0); + } + + } + */ + while(reversing!=track->reverse || current_section!=track->current_section) + { + if(reversing) + { + NotifyTargetsForTrackPoint(to_bhv,current_section,1); + current_section--; + if(current_section<0) + { + if(track->loop) + { + //looped to end , so passed last point + current_section=track->num_sections-1; + NotifyTargetsForTrackPoint(to_bhv,track->num_sections,1); + } + else + { + current_section=0; + reversing=0; + } + + + } + + } + else + { + NotifyTargetsForTrackPoint(to_bhv,current_section+1,0); + current_section++; + if(current_section>=track->num_sections) + { + if(track->loop) + { + //looped to start , so passed first point + current_section=0; + NotifyTargetsForTrackPoint(to_bhv,0,0); + } + else + { + current_section=track->num_sections-1; + reversing=1; + } + + + } + } + } + if(!track->playing) + { + if(track->reverse) + { + //stopped at end , so passed last point + NotifyTargetsForTrackPoint(to_bhv,track->num_sections,0); + } + else + { + //stopped at start , so passed point 0 + NotifyTargetsForTrackPoint(to_bhv,0,1); + } + + } + } + + +} + + +void TrackObjectIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple) +{ + TRACK_OBJECT_BEHAV_BLOCK* to_bhv = sbPtr->SBdataptr; + LOCALASSERT(to_bhv); + + #if 0 + + if((AvP.Network==I_Peer)&&(!InanimateDamageFromNetHost)) + { + //add track damaged net message + return; + } + else if(AvP.Network==I_Host) + { + //add track damaged net message + //if(sbPtr->SBDamageBlock.Health <= 0) AddNetMsg_InanimateObjectDestroyed(sbPtr); + } + #endif + + if(AvP.Network != I_No_Network) + { + //I don't want to consider destructable track objects in net games for the moment + //would screw up the strategy synching + return; + } + + if (!to_bhv->Indestructable) + { + + if(sbPtr->SBDamageBlock.Health <= 0) + { + + //notify target of destruction + if(to_bhv->destruct_target_sbptr) + { + RequestState(to_bhv->destruct_target_sbptr,to_bhv->destruct_target_request,0); + } + + MakeFragments(sbPtr); + DestroyAnyStrategyBlock(sbPtr); + } + } +} + +#define TRACKSYNCH_ON_FORWARD 0 +#define TRACKSYNCH_OFF_FORWARD 1 +#define TRACKSYNCH_ON_REVERSE 2 +#define TRACKSYNCH_OFF_REVERSE 3 + +int TrackObjectGetSynchData(STRATEGYBLOCK* sbPtr) +{ + TRACK_OBJECT_BEHAV_BLOCK* to_bhv = sbPtr->SBdataptr; + LOCALASSERT(to_bhv); + + if(to_bhv->to_track->playing) + { + if(to_bhv->to_track->reverse) + return TRACKSYNCH_ON_REVERSE; + else + return TRACKSYNCH_ON_FORWARD; + } + else + { + if(to_bhv->to_track->reverse) + return TRACKSYNCH_OFF_REVERSE; + else + return TRACKSYNCH_OFF_FORWARD; + } +} + + +void TrackObjectSetSynchData(STRATEGYBLOCK* sbPtr,int status) +{ + TRACK_OBJECT_BEHAV_BLOCK* to_bhv = sbPtr->SBdataptr; + LOCALASSERT(to_bhv); + + if(to_bhv->TimeUntilNetSynchAllowed>0) + { + //ignore this attempt to synch the switch + return; + } + + if(to_bhv->to_track->playing) + { + //don't bother stopping moving tracks; + return; + } + + switch(status) + { + case TRACKSYNCH_ON_FORWARD : + to_bhv->request=track_request_startforward; + break; + + case TRACKSYNCH_OFF_FORWARD : + if(to_bhv->to_track->reverse && !to_bhv->to_track->loop) + { + //track is at the end , but should be at the start + to_bhv->request=track_request_startbackward; + } + break; + + case TRACKSYNCH_ON_REVERSE : + to_bhv->request=track_request_startbackward; + break; + + case TRACKSYNCH_OFF_REVERSE : + if(!to_bhv->to_track->reverse && !to_bhv->to_track->loop) + { + //track is at the start , but should be at the end + to_bhv->request=track_request_startforward; + } + break; + + } +} + + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" +typedef struct track_object_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + BOOL Indestructable; + TRACK_OBJECT_REQUEST_STATE request; + + //strategyblock stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; + +}TRACK_OBJECT_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV to_bhv + +void LoadStrategy_TrackObject(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + TRACK_OBJECT_BEHAV_BLOCK *to_bhv; + TRACK_OBJECT_SAVE_BLOCK* block = (TRACK_OBJECT_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourTrackObject) return; + + to_bhv = (TRACK_OBJECT_BEHAV_BLOCK*)sbPtr->SBdataptr; + + //start copying stuff + + COPYELEMENT_LOAD(Indestructable) + COPYELEMENT_LOAD(request) + + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + + //load the track position + if(to_bhv->to_track) + { + SAVE_BLOCK_HEADER* track_header = GetNextBlockIfOfType(SaveBlock_Track); + if(track_header) + { + LoadTrackPosition(track_header,to_bhv->to_track); + } + } + +} + +void SaveStrategy_TrackObject(STRATEGYBLOCK* sbPtr) +{ + TRACK_OBJECT_SAVE_BLOCK* block; + TRACK_OBJECT_BEHAV_BLOCK *to_bhv; + + to_bhv = (TRACK_OBJECT_BEHAV_BLOCK*)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + + COPYELEMENT_SAVE(Indestructable) + COPYELEMENT_SAVE(request) + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; + + //save the track position + if(to_bhv->to_track) + { + SaveTrackPosition(to_bhv->to_track); + } + +} diff --git a/3dc/avp/bh_track.h b/3dc/avp/bh_track.h new file mode 100644 index 0000000..a4798ca --- /dev/null +++ b/3dc/avp/bh_track.h @@ -0,0 +1,104 @@ +#ifndef _bh_track_h_ +#define _bh_track_h_ 1 + +#include "track.h" + +#ifdef __cplusplus + + extern "C" { + +#endif + +extern void* TrackObjectBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr); +extern void TrackObjectBehaveFun(STRATEGYBLOCK* sbptr); +extern void TrackObjectIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple); + +extern int TrackObjectGetSynchData(STRATEGYBLOCK* sbptr); +extern void TrackObjectSetSynchData(STRATEGYBLOCK* sbptr,int status); + +typedef enum track_object_req_states +{ + track_no_request, + track_request_start, + track_request_stop, + track_request_startforward, + track_request_startbackward, +}TRACK_OBJECT_REQUEST_STATE; + + + +#ifndef TrackRequestFlag_ActiveForward + #define TrackRequestFlag_ActiveForward 0x00000001 + #define TrackRequestFlag_ActiveBackward 0x00000002 + #define TrackRequestFlag_OppositeBackward 0x00000004 +#endif +typedef struct track_point_target +{ + + char target_name [SB_NAME_LENGTH]; + STRATEGYBLOCK * target_sbptr; + int request; + int flags; + +}TRACK_POINT_TARGET; + +typedef struct special_track_point +{ + int track_point_no; + int num_targets; + + TRACK_POINT_TARGET* targets; + +}SPECIAL_TRACK_POINT; + +typedef struct track_object_behav_block +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + BOOL Indestructable; + + TRACK_CONTROLLER* to_track; + + TRACK_OBJECT_REQUEST_STATE request; + + TXACTRLBLK *to_tac;//for objects with anims on them + + int num_special_track_points; + SPECIAL_TRACK_POINT* special_track_points; + + int destruct_target_request; + char destruct_target_ID[SB_NAME_LENGTH]; + STRATEGYBLOCK* destruct_target_sbptr; + + int TimeUntilNetSynchAllowed; +}TRACK_OBJECT_BEHAV_BLOCK; + + +typedef struct track_object_tools_template +{ + char nameID[SB_NAME_LENGTH]; + int shape_num; + + TRACK_CONTROLLER* track; + + VECTORCH position; + EULER orientation; + + int num_special_track_points; + SPECIAL_TRACK_POINT* special_track_points; + + + int integrity; // 0-20 (>20 = indestructable) + int destruct_target_request; + char destruct_target_ID[SB_NAME_LENGTH]; + +}TRACK_OBJECT_TOOLS_TEMPLATE; + + +#ifdef __cplusplus + + }; + +#endif + + +#endif diff --git a/3dc/avp/bh_videoscreen.c b/3dc/avp/bh_videoscreen.c new file mode 100644 index 0000000..c2571bd --- /dev/null +++ b/3dc/avp/bh_videoscreen.c @@ -0,0 +1,288 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "bh_videoscreen.h" +#include "dynblock.h" +#include "dynamics.h" +#include "bh_debri.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +#include "pvisible.h" + + + +void* InitVideoScreen(void* bhdata,STRATEGYBLOCK *sbPtr) +{ + TOOLS_DATA_VIDEO_SCREEN *toolsData = (TOOLS_DATA_VIDEO_SCREEN *)bhdata; + VIDEO_SCREEN_BEHAV_BLOCK* videoScreen; + int i; + + LOCALASSERT(sbPtr->I_SBtype == I_BehaviourVideoScreen); + LOCALASSERT(toolsData); + + /* create, initialise and attach a data block */ + videoScreen = (void *)AllocateMem(sizeof(VIDEO_SCREEN_BEHAV_BLOCK)); + if(!videoScreen) + { + memoryInitialisationFailure = 1; + return ((void *)NULL); + } + videoScreen->bhvr_type=I_BehaviourVideoScreen; + + sbPtr->SBdataptr = videoScreen; + + + /* set default indestructibility */ + videoScreen->Indestructable = No; + + + /* Initialise object's stats */ + //set health and armour + { + NPC_DATA *NpcData; + + NpcData=GetThisNpcData(I_NPC_DefaultInanimate); + LOCALASSERT(NpcData); + sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; + } + + sbPtr->SBDamageBlock.Health*=toolsData->integrity; + + //get a dynamics block + sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); + + if(!sbPtr->DynPtr) + { + RemoveBehaviourStrategy(sbPtr); + return 0; + } + + + //is this screen indestructable + if (toolsData->integrity > 20) + { + videoScreen->Indestructable = Yes; + sbPtr->integrity = DEFAULT_OBJECT_INTEGRITY; + } + else if (toolsData->integrity < 1) + { + sbPtr->integrity = 1; // die immediately + } + else + { + sbPtr->integrity = (DEFAULT_OBJECT_INTEGRITY)*(toolsData->integrity); + } + + + /* Initialise the dynamics block */ + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + GLOBALASSERT(dynPtr); + + dynPtr->PrevPosition = dynPtr->Position = toolsData->position; + dynPtr->OrientEuler = toolsData->orientation; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + } + + /* strategy block initialisation */ + sbPtr->shapeIndex = toolsData->shapeIndex; + for(i=0;iSBname[i] = toolsData->nameID[i]; + + + /*check to see if object is animated.*/ + { + TXACTRLBLK **pptxactrlblk; + int item_num; + int shape_num = toolsData->shapeIndex; + SHAPEHEADER *shptr = GetShapeData(shape_num); + pptxactrlblk = &videoScreen->inan_tac; + for(item_num = 0; item_num < shptr->numitems; item_num ++) + { + POLYHEADER *poly = (POLYHEADER*)(shptr->items[item_num]); + LOCALASSERT(poly); + + SetupPolygonFlagAccessForShape(shptr); + + if((Request_PolyFlags((void *)poly)) & iflag_txanim) + { + TXACTRLBLK *pnew_txactrlblk; + + pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK)); + if(pnew_txactrlblk) + { + pnew_txactrlblk->tac_flags = 0; + pnew_txactrlblk->tac_item = item_num; + pnew_txactrlblk->tac_sequence = 0; + pnew_txactrlblk->tac_node = 0; + pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shape_num, item_num); + pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shape_num); + + *pptxactrlblk = pnew_txactrlblk; + pptxactrlblk = &pnew_txactrlblk->tac_next; + } + else *pptxactrlblk = NULL; + } + } + *pptxactrlblk=0; + + } + + //copy destruction target stuff + videoScreen->destruct_target_request=toolsData->destruct_target_request; + for(i=0;idestruct_target_ID[i]=toolsData->destruct_target_ID[i]; + } + videoScreen->destruct_target_sbptr=0; + + return((void*)videoScreen); + +} + + + + +void VideoScreenBehaviour(STRATEGYBLOCK *sbPtr) +{ + DISPLAYBLOCK* dptr; + VIDEO_SCREEN_BEHAV_BLOCK* videoScreen; + GLOBALASSERT(sbPtr); + videoScreen = sbPtr->SBdataptr; + GLOBALASSERT(videoScreen); + + dptr = sbPtr->SBdptr; + if(dptr) + { + LIGHTBLOCK *lightPtr = dptr->ObLights[0]; + //update light if near + if (lightPtr) + { + if(sbPtr->SBdptr->ObNumLights==1) + { + extern int FmvColourRed; + extern int FmvColourGreen; + extern int FmvColourBlue; + + lightPtr->LightBright = ONE_FIXED; + lightPtr->LightFlags = LFlag_Omni; + lightPtr->LightType = LightType_PerVertex; + lightPtr->LightRange = 5000; + + lightPtr->RedScale= FmvColourRed; + lightPtr->GreenScale= FmvColourGreen; + lightPtr->BlueScale= FmvColourBlue; + } + } + + //deal with texture animation if near + if(videoScreen->inan_tac) + { + if(!dptr->ObTxAnimCtrlBlks) + { + dptr->ObTxAnimCtrlBlks = videoScreen->inan_tac; + } + } + } +} + + + + +void VideoScreenIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple) +{ + VIDEO_SCREEN_BEHAV_BLOCK* videoScreen; + GLOBALASSERT(sbPtr); + videoScreen = sbPtr->SBdataptr; + GLOBALASSERT(videoScreen); + + //no netweok code for this yet (if ever) + if (!videoScreen->Indestructable) + { + if(sbPtr->SBDamageBlock.Health <= 0) + { + //notify target of destruction + if(videoScreen->destruct_target_sbptr) + { + RequestState(videoScreen->destruct_target_sbptr,videoScreen->destruct_target_request,0); + } + + + //the object has been destroyed + MakeFragments(sbPtr); + DestroyAnyStrategyBlock(sbPtr); + } + } +} + + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" + +typedef struct video_screen_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + BOOL Indestructable; + + + //strategyblock stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; +}VIDEO_SCREEN_SAVE_BLOCK; + + + +void LoadStrategy_VideoScreen(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + VIDEO_SCREEN_BEHAV_BLOCK* videoScreen; + VIDEO_SCREEN_SAVE_BLOCK* block = (VIDEO_SCREEN_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //find the existing strategy block + sbPtr = FindSBWithName(header->SBname); + if(!sbPtr) return; + + //make sure the strategy found is of the right type + if(sbPtr->I_SBtype != I_BehaviourVideoScreen) return; + + videoScreen = (VIDEO_SCREEN_BEHAV_BLOCK*)sbPtr->SBdataptr; + + //start copying stuff + + videoScreen->Indestructable = block->Indestructable; + + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; +} + + +void SaveStrategy_VideoScreen(STRATEGYBLOCK* sbPtr) +{ + VIDEO_SCREEN_SAVE_BLOCK *block; + VIDEO_SCREEN_BEHAV_BLOCK* videoScreen; + + videoScreen = (VIDEO_SCREEN_BEHAV_BLOCK*)sbPtr->SBdataptr; + + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + //start copying stuff + block->Indestructable = videoScreen->Indestructable; + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; + +} diff --git a/3dc/avp/bh_videoscreen.h b/3dc/avp/bh_videoscreen.h new file mode 100644 index 0000000..06442da --- /dev/null +++ b/3dc/avp/bh_videoscreen.h @@ -0,0 +1,36 @@ +#ifndef _bh_videoscreen_h +#define _bh_videoscreen_h + +typedef struct video_screen_behav_block +{ + AVP_BEHAVIOUR_TYPE bhvr_type; + BOOL Indestructable; + + TXACTRLBLK *inan_tac;//for video screens with anims on them + + int destruct_target_request; + char destruct_target_ID[SB_NAME_LENGTH]; + STRATEGYBLOCK* destruct_target_sbptr; + +}VIDEO_SCREEN_BEHAV_BLOCK; + + +typedef struct toolsdata_video_screen +{ + struct vectorch position; + struct euler orientation; + int shapeIndex; + char nameID[SB_NAME_LENGTH]; + int integrity; // 0-20 (>20 = indestructable) + + int destruct_target_request; + char destruct_target_ID[SB_NAME_LENGTH]; + + +}TOOLS_DATA_VIDEO_SCREEN; + +void* InitVideoScreen(void* bhdata,STRATEGYBLOCK *sbPtr); +void VideoScreenBehaviour(STRATEGYBLOCK *sbPtr); +void VideoScreenIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple); + +#endif \ No newline at end of file diff --git a/3dc/avp/bh_waypt.c b/3dc/avp/bh_waypt.c new file mode 100644 index 0000000..1c6af95 --- /dev/null +++ b/3dc/avp/bh_waypt.c @@ -0,0 +1,998 @@ +/***** bh_waypt.c *****/ + +#include "3dc.h" + +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "comp_shp.h" +#include "dynblock.h" +#include "dynamics.h" +#include "pfarlocs.h" +#include "pheromon.h" +#include "bh_types.h" +#include "pvisible.h" +#include "bh_far.h" +#include "bh_debri.h" +#include "bh_pred.h" +#include "bh_paq.h" +#include "bh_queen.h" +#include "bh_marin.h" +#include "bh_alien.h" +#include "lighting.h" +#include "bh_weap.h" +#include "weapons.h" +#include "psnd.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +/*This allows ai not to go for the shortest all the time*/ +#define ALLOW_USE_OF_LONGER_PATHS Yes + +int NPC_Waypoints; +int Num_Target_Waypoints; +int Global_Num_Waypoints; +int Global_NPC_Type; +WAYPOINT_ROUTE Global_Route; + +static int GlobalLinkShift; //Allows different aliens to take different routes + +WAYPOINT_VOLUME *Global_Target_Waypoint,*Global_NPC_Waypoint; +VECTORCH Global_Module_Offset; + +/* forward declarations for this file */ +int NewFindThisRoute(WAYPOINT_HEADER *waypoints, WAYPOINT_ROUTE *thisroute,WAYPOINT_VOLUME *startwaypoint, WAYPOINT_VOLUME *endwaypoint); +void SweepWaypoints(WAYPOINT_HEADER *waypoints, STRATEGYBLOCK *sbPtr, VECTORCH *targetPosition); +int FindBestRoute(WAYPOINT_ROUTE *bestroute,WAYPOINT_HEADER *waypoints); +int NPCContainsPoint(STRATEGYBLOCK *sbPtr,VECTORCH *point); +void GetTargetPositionInWaypoint(WAYPOINT_VOLUME *waypoint,VECTORCH *output); + + +void InitWaypointSystem(int npctype) { + + Global_Route.num_waypoints=ONE_FIXED; + Global_Route.start=NULL; + Global_Route.second=NULL; + Global_Route.last=NULL; + Global_NPC_Type=npctype; + +} + +void InitWaypointManager(WAYPOINT_MANAGER *manager) { + + manager->current_container=NULL; + manager->current_target=NULL; + manager->current_link=NULL; + + manager->current_target_point.vx=0; + manager->current_target_point.vy=0; + manager->current_target_point.vz=0; + +} + +int NPCGetWaypointDirection(WAYPOINT_HEADER *waypoints, STRATEGYBLOCK *sbPtr, VECTORCH *velocityDirection, VECTORCH *targetPosition,WAYPOINT_MANAGER *manager) { + + /* Revision of NPCGetMovementDirection, to accomodate the waypoint system. */ + + VECTORCH targetDirection; + WAYPOINT_ROUTE current_route; + WAYPOINT_VOLUME *dest_waypoint; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + LOCALASSERT(velocityDirection); + LOCALASSERT(targetPosition); + + /* I don't know if we'll need this... */ + targetDirection = *targetPosition; + targetDirection.vx -= sbPtr->DynPtr->Position.vx; + targetDirection.vz -= sbPtr->DynPtr->Position.vz; + targetDirection.vy = 0; + Normalise(&targetDirection); + + /*in the unlikely case that the player or npc doesnt have a current containingg module, + just return the target direction */ + if((playerPherModule==NULL)||(sbPtr->containingModule==NULL)) + { + *velocityDirection = targetDirection; + textprint("Waypoint dropout: no modules\n"); + InitWaypointManager(manager); + return(0); + } + + Global_Module_Offset=sbPtr->containingModule->m_aimodule->m_world; + + Global_Route.num_waypoints=ONE_FIXED; + Global_Route.start=NULL; + Global_Route.second=NULL; + Global_Route.last=NULL; + Global_Route.first_link=NULL; + + NPC_Waypoints=0; + Num_Target_Waypoints=0; + + /* This will establish the locations of the NPC and the target. */ + SweepWaypoints(waypoints, sbPtr, targetPosition); + + /* Return the target direction if the NPC or the target have no containing waypoint. */ + if ( (NPC_Waypoints==0) || (Num_Target_Waypoints==0) ) { + *velocityDirection = targetDirection; + textprint("Waypoint dropout: no containing waypoints (%d, %d)\n",NPC_Waypoints,Num_Target_Waypoints); + InitWaypointManager(manager); + return(0); + } + + /* Now what? Compute the best route to the target. */ + + textprint("NPC is in %d waypoints.\n",NPC_Waypoints); + + //Base shift value on strategy block so that the aliens don't keep changing their minds + //about which route to take + GlobalLinkShift=(((int)sbPtr)&0xffff)>>4; + if (FindBestRoute(¤t_route,waypoints)==0) { + /* Yuck! */ + textprint("Waypoint dropout: no continuous route!\n"); + InitWaypointManager(manager); + return(0); + } + + /* If the best route has start and end the same, go for it. */ + + Global_Route=current_route; + + if ((Global_Route.start!=Global_Route.second) + &&(Global_Route.second!=Global_Route.last)) { + GLOBALASSERT(Global_Route.first_link); + } + + if (current_route.start==current_route.last) { + textprint("Waypoint dropout Success: start==end\n"); + *velocityDirection = targetDirection; + return(1); + } + + + dest_waypoint=NULL; + + /* If the NPC is entirely inside the first waypoint, then head for the centre of + the second one. Else, head for the centre of the first one. */ + + if (NPC_Waypoints==1) { + /* Global_NPC_Waypoint must be correct. */ + if (Global_NPC_Waypoint==current_route.start) { + dest_waypoint=current_route.second; + } else { + /* wtf? */ + } + } else { + if (NPCContainsPoint(sbPtr,&manager->current_target_point)) { + /* Must have reached the 'centre'. */ + if (Global_NPC_Waypoint==current_route.start) { + dest_waypoint=current_route.second; + } else { + /* wtf? */ + } + } + } + + if (dest_waypoint==NULL) { + dest_waypoint=current_route.start; + } + + LOCALASSERT(dest_waypoint); + + /* Right, at this point we have a route, a containing waypoint, a destination, etc. */ + if (manager->current_target==dest_waypoint) { + /* Continue to head for the old target position, if it's valid. */ + if (!WaypointContainsPoint(manager->current_target,&manager->current_target_point)) { + manager->current_target_point=dest_waypoint->centre; + } + } else { + /* Set destination... */ + manager->current_target=dest_waypoint; + manager->current_link=Global_Route.first_link; + /* Get a new target position, based on the link we're now using. */ + if (manager->current_link==NULL) { + manager->current_target_point=dest_waypoint->centre; + } else if (manager->current_link->link_flags&linkflag_largetarget) { + GetTargetPositionInWaypoint(dest_waypoint,&manager->current_target_point); + } else { + manager->current_target_point=dest_waypoint->centre; + } + } + + if (manager->current_container!=Global_Route.start) { + manager->current_container=Global_Route.start; + manager->current_link=Global_Route.first_link; + /* Actually, no need to change the target... is there? */ + #if ALLOW_USE_OF_LONGER_PATHS + //make it cost to enter this waypoint volume + //(encouraging ai to use other routes) + Global_Route.start->weighting++; + //if the weighting for a volume has got too high , reduce the weighting for all volumes + if(Global_Route.start->weighting>25) + { + int i; + for(i=0;inum_waypoints;i++) + { + //don't want to reduce weighting below the original weighting + if(waypoints->first_waypoint[i].weighting>5) + { + waypoints->first_waypoint[i].weighting--; + } + } + } + #endif + } else { + /* Er, well done. */ + } + + //targetDirection=dest_waypoint->centre; + targetDirection=manager->current_target_point; + + targetDirection.vx+=Global_Module_Offset.vx; + targetDirection.vy+=Global_Module_Offset.vy; + targetDirection.vz+=Global_Module_Offset.vz; + + targetDirection.vx -= sbPtr->DynPtr->Position.vx; + targetDirection.vz -= sbPtr->DynPtr->Position.vz; + targetDirection.vy -= sbPtr->DynPtr->Position.vy; + Normalise(&targetDirection); + + { + int a,b; + + b=-1; + + for (a=0; anum_waypoints; a++) { + + WAYPOINT_VOLUME *this_waypoint; + + this_waypoint=waypoints->first_waypoint; + this_waypoint+=a; + + if (this_waypoint==dest_waypoint) { + b=a; + } + } + + textprint("Destination waypoint: %d\n",b); + } + textprint("Waypoint Generated Velocity = %d %d %d\n",targetDirection.vx,targetDirection.vy,targetDirection.vz); + + *velocityDirection = targetDirection; + + /* That's all folks. */ + + return(1); + +} + +int WaypointContainsPoint(WAYPOINT_VOLUME *waypoint, VECTORCH *point) { + + /* 'point' should be in module space. */ + + int minx,maxx,miny,maxy,minz,maxz; + + minx=waypoint->centre.vx+waypoint->min_extents.vx; + miny=waypoint->centre.vy+waypoint->min_extents.vy; + minz=waypoint->centre.vz+waypoint->min_extents.vz; + + maxx=waypoint->centre.vx+waypoint->max_extents.vx; + maxy=waypoint->centre.vy+waypoint->max_extents.vy; + maxz=waypoint->centre.vz+waypoint->max_extents.vz; + + if (point->vx>=minx) { + if (point->vx<=maxx) { + if (point->vy>=miny) { + if (point->vy<=maxy) { + if (point->vz>=minz) { + if (point->vz<=maxz) { + return(1); + } + } + } + } + } + } + + return(0); + +} + +int WaypointContainsPoint_2d(WAYPOINT_VOLUME *waypoint, VECTORCH *point) { + + /* 'point' should be in module space. */ + + int minx,maxx,minz,maxz; + + minx=waypoint->centre.vx+waypoint->min_extents.vx; + minz=waypoint->centre.vz+waypoint->min_extents.vz; + + maxx=waypoint->centre.vx+waypoint->max_extents.vx; + maxz=waypoint->centre.vz+waypoint->max_extents.vz; + + if (point->vx>=minx) { + if (point->vx<=maxx) { + if (point->vz>=minz) { + if (point->vz<=maxz) { + return(1); + } + } + } + } + + return(0); + +} + +int WaypointContainsNPC(WAYPOINT_VOLUME *volume,STRATEGYBLOCK *sbPtr) { + + VECTORCH testpoint; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + LOCALASSERT(sbPtr->SBdptr); + + testpoint.vx=sbPtr->DynPtr->Position.vx+sbPtr->SBdptr->ObMaxX-Global_Module_Offset.vx; + testpoint.vy=sbPtr->DynPtr->Position.vy+sbPtr->SBdptr->ObMaxY-Global_Module_Offset.vy; + testpoint.vz=sbPtr->DynPtr->Position.vz+sbPtr->SBdptr->ObMaxZ-Global_Module_Offset.vz; + if (WaypointContainsPoint(volume,&testpoint)) return(1); + + testpoint.vx=sbPtr->DynPtr->Position.vx+sbPtr->SBdptr->ObMinX-Global_Module_Offset.vx; + testpoint.vy=sbPtr->DynPtr->Position.vy+sbPtr->SBdptr->ObMaxY-Global_Module_Offset.vy; + testpoint.vz=sbPtr->DynPtr->Position.vz+sbPtr->SBdptr->ObMaxZ-Global_Module_Offset.vz; + if (WaypointContainsPoint(volume,&testpoint)) return(1); + + testpoint.vx=sbPtr->DynPtr->Position.vx+sbPtr->SBdptr->ObMaxX-Global_Module_Offset.vx; + testpoint.vy=sbPtr->DynPtr->Position.vy+sbPtr->SBdptr->ObMinY-Global_Module_Offset.vy; + testpoint.vz=sbPtr->DynPtr->Position.vz+sbPtr->SBdptr->ObMaxZ-Global_Module_Offset.vz; + if (WaypointContainsPoint(volume,&testpoint)) return(1); + + testpoint.vx=sbPtr->DynPtr->Position.vx+sbPtr->SBdptr->ObMinX-Global_Module_Offset.vx; + testpoint.vy=sbPtr->DynPtr->Position.vy+sbPtr->SBdptr->ObMinY-Global_Module_Offset.vy; + testpoint.vz=sbPtr->DynPtr->Position.vz+sbPtr->SBdptr->ObMaxZ-Global_Module_Offset.vz; + if (WaypointContainsPoint(volume,&testpoint)) return(1); + + testpoint.vx=sbPtr->DynPtr->Position.vx+sbPtr->SBdptr->ObMaxX-Global_Module_Offset.vx; + testpoint.vy=sbPtr->DynPtr->Position.vy+sbPtr->SBdptr->ObMaxY-Global_Module_Offset.vy; + testpoint.vz=sbPtr->DynPtr->Position.vz+sbPtr->SBdptr->ObMinZ-Global_Module_Offset.vz; + if (WaypointContainsPoint(volume,&testpoint)) return(1); + + testpoint.vx=sbPtr->DynPtr->Position.vx+sbPtr->SBdptr->ObMinX-Global_Module_Offset.vx; + testpoint.vy=sbPtr->DynPtr->Position.vy+sbPtr->SBdptr->ObMaxY-Global_Module_Offset.vy; + testpoint.vz=sbPtr->DynPtr->Position.vz+sbPtr->SBdptr->ObMinZ-Global_Module_Offset.vz; + if (WaypointContainsPoint(volume,&testpoint)) return(1); + + testpoint.vx=sbPtr->DynPtr->Position.vx+sbPtr->SBdptr->ObMaxX-Global_Module_Offset.vx; + testpoint.vy=sbPtr->DynPtr->Position.vy+sbPtr->SBdptr->ObMinY-Global_Module_Offset.vy; + testpoint.vz=sbPtr->DynPtr->Position.vz+sbPtr->SBdptr->ObMinZ-Global_Module_Offset.vz; + if (WaypointContainsPoint(volume,&testpoint)) return(1); + + testpoint.vx=sbPtr->DynPtr->Position.vx+sbPtr->SBdptr->ObMinX-Global_Module_Offset.vx; + testpoint.vy=sbPtr->DynPtr->Position.vy+sbPtr->SBdptr->ObMinY-Global_Module_Offset.vy; + testpoint.vz=sbPtr->DynPtr->Position.vz+sbPtr->SBdptr->ObMinZ-Global_Module_Offset.vz; + if (WaypointContainsPoint(volume,&testpoint)) return(1); + + /* Failed! */ + + return(0); + +} + +int NPCContainsPoint(STRATEGYBLOCK *sbPtr,VECTORCH *point) { + + /* Point is in MODULESPACE! */ + LOCALASSERT(point); + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + LOCALASSERT(sbPtr->SBdptr); + + if (point->vx<(sbPtr->DynPtr->Position.vx+sbPtr->SBdptr->ObMaxX-Global_Module_Offset.vx)) { + if (point->vx>(sbPtr->DynPtr->Position.vx+sbPtr->SBdptr->ObMinX-Global_Module_Offset.vx)) { + if (point->vy<(sbPtr->DynPtr->Position.vy+sbPtr->SBdptr->ObMaxY-Global_Module_Offset.vy)) { + if (point->vy>(sbPtr->DynPtr->Position.vy+sbPtr->SBdptr->ObMinY-Global_Module_Offset.vy)) { + if (point->vz<(sbPtr->DynPtr->Position.vz+sbPtr->SBdptr->ObMaxZ-Global_Module_Offset.vz)) { + if (point->vz>(sbPtr->DynPtr->Position.vz+sbPtr->SBdptr->ObMinZ-Global_Module_Offset.vz)) { + return(1); + } + } + } + } + } + } + + return(0); + +} + +void SweepWaypoints(WAYPOINT_HEADER *waypoints, STRATEGYBLOCK *sbPtr, VECTORCH *targetPosition) { + + WAYPOINT_VOLUME *this_waypoint; + int a; + + Global_Num_Waypoints=waypoints->num_waypoints; + + for (a=0; anum_waypoints; a++) { + + VECTORCH modtargetpos; + + this_waypoint=waypoints->first_waypoint; + this_waypoint+=a; + + this_waypoint->contains_npc=0; + this_waypoint->contains_target=0; + + modtargetpos.vx=targetPosition->vx-Global_Module_Offset.vx; + modtargetpos.vy=targetPosition->vy-Global_Module_Offset.vy; + modtargetpos.vz=targetPosition->vz-Global_Module_Offset.vz; + + if (WaypointContainsPoint(this_waypoint,&modtargetpos)) { + Num_Target_Waypoints++; + Global_Target_Waypoint=this_waypoint; + this_waypoint->contains_target=1; + } + if (WaypointContainsNPC(this_waypoint,sbPtr)) { + NPC_Waypoints++; + Global_NPC_Waypoint=this_waypoint; + this_waypoint->contains_npc=1; + } + } + +} + +void Trickle_Down(WAYPOINT_HEADER *waypoints, WAYPOINT_VOLUME *this_waypoint, int trickle_value) { + + int a; + + LOCALASSERT(this_waypoint->workspace<=trickle_value); + + this_waypoint->workspace=trickle_value; + + for (a=0; anum_links; a++) { + + WAYPOINT_LINK *link_to_next; + WAYPOINT_VOLUME *next_waypoint; + + link_to_next=this_waypoint->first_link; + link_to_next+=a; + + if ((link_to_next->link_flags&linkflag_oneway)==0) { + + next_waypoint=waypoints->first_waypoint; + next_waypoint+=link_to_next->link_target_index; + + if (next_waypoint->workspace0); + + Trickle_Down(waypoints,next_waypoint,trickle_value-1); + + } + + } + + } + +} + +void FindThisRoute(WAYPOINT_HEADER *waypoints, WAYPOINT_ROUTE *thisroute,WAYPOINT_VOLUME *startwaypoint, WAYPOINT_VOLUME *endwaypoint) { + + int a,b; + int current_trickle_value; + WAYPOINT_VOLUME *thiswaypoint; + + /* Trivial case... */ + if ( (startwaypoint->contains_npc) && (startwaypoint->contains_target) ) { + thisroute->num_waypoints=0; + thisroute->start=startwaypoint; + thisroute->second=startwaypoint; + thisroute->last=startwaypoint; + return; + } + + /* Setup... */ + + thisroute->num_waypoints=0; + thisroute->start=startwaypoint; + thisroute->second=NULL; + thisroute->last=endwaypoint; + + for (a=0; anum_waypoints; a++) { + /* Preparation... */ + WAYPOINT_VOLUME *temp_waypoint; + + temp_waypoint=waypoints->first_waypoint; + temp_waypoint+=a; + temp_waypoint->workspace=0; + } + + current_trickle_value=waypoints->num_waypoints; + + /* Not so trivial cases: cheap 'pheromone' system. */ + + Trickle_Down(waypoints, endwaypoint, current_trickle_value); + + /* Now extract best route. */ + + b=0; /* Number of waypoints stepped. */ + thiswaypoint=startwaypoint; + + while (thiswaypoint!=endwaypoint) { + + /* Look through links for highest increment. */ + + int nextstep=0; + WAYPOINT_VOLUME *bestnextwaypoint=NULL; + + for (a=0; anum_links; a++) { + + WAYPOINT_LINK *link_to_next; + WAYPOINT_VOLUME *next_waypoint; + + link_to_next=thiswaypoint->first_link; + link_to_next+=a; + + if ((link_to_next->link_flags&linkflag_reversed_oneway)==0) { + + next_waypoint=waypoints->first_waypoint; + next_waypoint+=link_to_next->link_target_index; + + if (next_waypoint->workspace>thiswaypoint->workspace) { + if (next_waypoint->workspace>nextstep) { + + /* Found a better step. */ + + + nextstep=next_waypoint->workspace; + bestnextwaypoint=next_waypoint; + + } + } + } + + } + + LOCALASSERT(nextstep); + LOCALASSERT(bestnextwaypoint); + + if (b==0) { + thisroute->second=bestnextwaypoint; + } + + b++; + + thiswaypoint=bestnextwaypoint; + + /* Go round again... */ + + } + + thisroute->num_waypoints=b; + + /* That may be it... */ + +} + +int FindBestRoute(WAYPOINT_ROUTE *bestroute,WAYPOINT_HEADER *waypoints) { + + int a; + WAYPOINT_ROUTE thisroute; + + /* Wipe the best route... */ + bestroute->num_waypoints=ONE_FIXED; + bestroute->start=NULL; + bestroute->second=NULL; + bestroute->last=NULL; + bestroute->first_link=NULL; + + for (a=0; anum_waypoints; a++) { + + WAYPOINT_VOLUME *start; + + start=waypoints->first_waypoint; + start+=a; + + if (start->contains_npc) { + if (NewFindThisRoute(waypoints,&thisroute,start,Global_Target_Waypoint)==0) { + /* Yuck. */ + return(0); + } + + /* We now have a route from this waypoint to the target. */ + + if (thisroute.num_waypointsnum_waypoints) { + /* New best route. */ + bestroute->num_waypoints=thisroute.num_waypoints; + bestroute->start=thisroute.start; + bestroute->second=thisroute.second; + bestroute->last=thisroute.last; + bestroute->first_link=thisroute.first_link; + } + + } + + } + + /* We now have a best route. */ + { + int start, second, last; + + for (a=0; anum_waypoints; a++) { + + WAYPOINT_VOLUME *this_waypoint; + + this_waypoint=waypoints->first_waypoint; + this_waypoint+=a; + + if (this_waypoint==bestroute->start) { + start=a; + } + if (this_waypoint==bestroute->second) { + second=a; + } + if (this_waypoint==bestroute->last) { + last=a; + } + + } + + textprint("Waypoint route: %d %d %d\n",start,second,last); + + } + return(1); +} + +int AlienIsAllowedToAttack(STRATEGYBLOCK *sbPtr) { + + ALIEN_STATUS_BLOCK *alienStatusPtr; + + /* Define rules: alien may not attack if the containing module has + waypoints, AND the target is more than one waypoint away. + Note that the waypoint system MUST have been called just a bit earlier... */ + + LOCALASSERT(sbPtr); + alienStatusPtr=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(alienStatusPtr); + + if (alienStatusPtr->EnableWaypoints==0) { + /* I see no waypoints. */ + return(1); + } + + if (sbPtr->containingModule->m_aimodule->m_waypoints!=NULL) { + + if ((Global_Route.num_waypoints<2) + ||(Global_Route.num_waypoints==ONE_FIXED)) { + /* ONE_FIXED = no containing waypoints dropout. */ + return(1); + } else { + return(0); + } + + } else { + return(1); + } +} + +#define WAYVOLUME_QUEUE_LENGTH 100 + +typedef struct route_queue { + int depth; + WAYPOINT_VOLUME *wayvolume; +} ROUTE_QUEUE; + +ROUTE_QUEUE Waypoint_Route_Queue[WAYVOLUME_QUEUE_LENGTH]; + +int Queue_End,Queue_Exec; + +int NewFindThisRoute(WAYPOINT_HEADER *waypoints, WAYPOINT_ROUTE *thisroute,WAYPOINT_VOLUME *startwaypoint, WAYPOINT_VOLUME *endwaypoint) { + + int a; + int terminate; + + /* Trivial case... */ + if ( (startwaypoint->contains_npc) && (startwaypoint->contains_target) ) { + thisroute->num_waypoints=0; + thisroute->start=startwaypoint; + thisroute->second=startwaypoint; + thisroute->last=startwaypoint; + thisroute->first_link=NULL; + return(1); + } + + /* Setup... */ + + thisroute->num_waypoints=0; + thisroute->start=startwaypoint; + thisroute->second=NULL; + thisroute->last=endwaypoint; + thisroute->first_link=NULL; + + for (a=0; anum_waypoints; a++) { + /* Preparation... */ + WAYPOINT_VOLUME *temp_waypoint; + + temp_waypoint=waypoints->first_waypoint; + temp_waypoint+=a; + temp_waypoint->workspace=0; + } + + /* Start with the end point. Look down all the links, + add all the waypoints there to the queue. */ + #if ALLOW_USE_OF_LONGER_PATHS + #define STARTING_DEPTH 5000 + #else + #define STARTING_DEPTH waypoints->num_waypoints + #endif + + Waypoint_Route_Queue[0].depth=STARTING_DEPTH; + Waypoint_Route_Queue[0].wayvolume=endwaypoint; + endwaypoint->workspace=Waypoint_Route_Queue[0].depth; + Waypoint_Route_Queue[1].wayvolume=NULL; /* To set a standard. */ + + Queue_End=1; + Queue_Exec=0; + terminate=0; + + while ( (Waypoint_Route_Queue[Queue_Exec].wayvolume!=NULL)&&(terminate==0) ) { + + WAYPOINT_VOLUME *this_waypoint; + int current_link=0; + + this_waypoint=Waypoint_Route_Queue[Queue_Exec].wayvolume; + + //don't always start with the first link so that the ai can arbitrarily + //choose between routes of equal length + if(this_waypoint->num_links) + { + current_link=GlobalLinkShift % this_waypoint->num_links; + } + for (a=0; anum_links; a++) { + + WAYPOINT_LINK *link_to_next; + WAYPOINT_VOLUME *next_waypoint; + int exec_this_link; + + link_to_next=this_waypoint->first_link; + link_to_next+=current_link; + + current_link++; + if(current_link==this_waypoint->num_links)current_link=0; + + if ( (Global_NPC_Type!=1) && (link_to_next->link_flags&linkflag_alienonly) ) { + exec_this_link=0; + } else { + exec_this_link=1; + } + + if ( ((link_to_next->link_flags&linkflag_oneway)==0)&&(exec_this_link) ) { + + next_waypoint=waypoints->first_waypoint; + next_waypoint+=link_to_next->link_target_index; + + /* Got the next waypoint. */ + + if (next_waypoint==startwaypoint) { + /* Found the route. */ + thisroute->start=next_waypoint; + thisroute->second=this_waypoint; + thisroute->last=endwaypoint; + thisroute->num_waypoints=1+STARTING_DEPTH-this_waypoint->workspace; + thisroute->first_link=link_to_next; + terminate=1; + textprint("Got a route.\n"); + #if ALLOW_USE_OF_LONGER_PATHS + }else if (next_waypoint->workspace+next_waypoint->weightingworkspace) { + /* Add to queue. */ + Waypoint_Route_Queue[Queue_End].wayvolume=next_waypoint; + Waypoint_Route_Queue[Queue_End].depth=Waypoint_Route_Queue[Queue_Exec].depth-next_waypoint->weighting; + next_waypoint->workspace=Waypoint_Route_Queue[Queue_End].depth; + { + /*Need to move this new entry down the queue until the entries are sorted + by depth*/ + int this_index=Queue_End; + int prev_index; + while(1) + { + prev_index=this_index-1; + if(prev_index==-1)prev_index=WAYVOLUME_QUEUE_LENGTH-1; + + if(Waypoint_Route_Queue[this_index].depth>Waypoint_Route_Queue[prev_index].depth) + { + /*Swap two entries in the queue*/ + int temp_depth=Waypoint_Route_Queue[this_index].depth; + WAYPOINT_VOLUME * temp_wayvolume=Waypoint_Route_Queue[this_index].wayvolume; + Waypoint_Route_Queue[this_index].depth=Waypoint_Route_Queue[prev_index].depth; + Waypoint_Route_Queue[this_index].wayvolume=Waypoint_Route_Queue[prev_index].wayvolume; + Waypoint_Route_Queue[prev_index].depth=temp_depth; + Waypoint_Route_Queue[prev_index].wayvolume=temp_wayvolume; + } + else + { + break; + } + + this_index=prev_index; + + } + } + Queue_End++; + if (Queue_End>=WAYVOLUME_QUEUE_LENGTH) { + Queue_End=0; + textprint("Wrapping Waypoint Queue!\n"); + } + Waypoint_Route_Queue[Queue_End].wayvolume=NULL; + LOCALASSERT(Queue_End!=Queue_Exec); //if this happens the queue probably needs to be longer + + } + #else + }else if (next_waypoint->workspaceworkspace) { + /* Add to queue. */ + Waypoint_Route_Queue[Queue_End].wayvolume=next_waypoint; + Waypoint_Route_Queue[Queue_End].depth=Waypoint_Route_Queue[Queue_Exec].depth-1; + next_waypoint->workspace=Waypoint_Route_Queue[Queue_End].depth; + + Queue_End++; + if (Queue_End>=WAYVOLUME_QUEUE_LENGTH) { + Queue_End=0; + textprint("Wrapping Waypoint Queue!\n"); + } + Waypoint_Route_Queue[Queue_End].wayvolume=NULL; + LOCALASSERT(Queue_End!=Queue_Exec); //if this happens the queue probably needs to be longer + + } + #endif + + } + + } + + /* Done all the links. */ + + Queue_Exec++; + if (Queue_Exec>=WAYVOLUME_QUEUE_LENGTH) Queue_Exec=0; + + } + + /* Still here? */ + + if (terminate) { + /* We found a route! */ + return(1); + } else { + /* We didn't find a route... oh dear. */ + thisroute->start=startwaypoint; + thisroute->second=endwaypoint; + thisroute->last=endwaypoint; + thisroute->first_link=NULL; + /* |(&(*$*&"^)(*!*&%&%!!!!! */ + return(0); + } + +} + + +extern int AlienIsEncouragedToCrawl(void) { + + if (Global_Route.first_link==NULL) { + #if 0 + if (Global_Route.start!=NULL) { + if (Global_Route.second!=NULL) { + if (Global_Route.start->flags&wayflag_cancrawl) { + if (Global_Route.second->flags&wayflag_cancrawl) { + return(1); + } + } + } + } + #endif + return(0); + } else { + /* Look at this link. */ + if (Global_Route.first_link->link_flags&linkflag_alienonly) { + return(1); + } else { + return(0); + } + } +} + +WAYPOINT_VOLUME *GetPositionValidity(MODULE *conmod, VECTORCH *position, VECTORCH *suggestion) { + + WAYPOINT_HEADER *waypoints; + WAYPOINT_VOLUME *this_waypoint,*retval; + int a; + + /* Added for near bimble state. */ + + waypoints=conmod->m_waypoints; + retval=NULL; + + if (waypoints==NULL) { + return(NULL); + } + + suggestion->vx=position->vx; + suggestion->vy=position->vy; + suggestion->vz=position->vz; + + for (a=0; anum_waypoints; a++) { + + VECTORCH modtargetpos; + + this_waypoint=waypoints->first_waypoint; + this_waypoint+=a; + + this_waypoint->contains_npc=0; + this_waypoint->contains_target=0; + + modtargetpos.vx=position->vx-conmod->m_world.vx; + modtargetpos.vy=position->vy-conmod->m_world.vy; + modtargetpos.vz=position->vz-conmod->m_world.vz; + + if (WaypointContainsPoint(this_waypoint,&modtargetpos)) { + retval=this_waypoint; + } + } + + if (retval) { + return(retval); + } + + /* Try again, sneakily. */ + + for (a=0; anum_waypoints; a++) { + + VECTORCH modtargetpos; + + this_waypoint=waypoints->first_waypoint; + this_waypoint+=a; + + this_waypoint->contains_npc=0; + this_waypoint->contains_target=0; + + modtargetpos.vx=position->vx-conmod->m_world.vx; + modtargetpos.vy=position->vy-conmod->m_world.vy; + modtargetpos.vz=position->vz-conmod->m_world.vz; + + if (WaypointContainsPoint_2d(this_waypoint,&modtargetpos)) { + retval=this_waypoint; + } + } + + if (retval) { + suggestion->vy=(retval->max_extents.vy+retval->min_extents.vy)>>1; + suggestion->vy+=conmod->m_world.vy; + return(retval); + } + + return(NULL); +} + +void GetTargetPositionInWaypoint(WAYPOINT_VOLUME *waypoint,VECTORCH *output) { + + int minx,maxx,miny,maxy,minz,maxz; + int rangex,rangey,rangez; + + minx=waypoint->centre.vx+((waypoint->min_extents.vx*3)>>2); + miny=waypoint->centre.vy+((waypoint->min_extents.vy*3)>>2); + minz=waypoint->centre.vz+((waypoint->min_extents.vz*3)>>2); + + maxx=waypoint->centre.vx+((waypoint->max_extents.vx*3)>>2); + maxy=waypoint->centre.vy+((waypoint->max_extents.vy*3)>>2); + maxz=waypoint->centre.vz+((waypoint->max_extents.vz*3)>>2); + + rangex=maxx-minx; + rangey=maxy-miny; + rangez=maxz-minz; + + output->vx=minx+(FastRandom()%rangex); + output->vy=miny+(FastRandom()%rangey); + output->vz=minz+(FastRandom()%rangez); + + GLOBALASSERT(WaypointContainsPoint(waypoint,output)); + +} \ No newline at end of file diff --git a/3dc/avp/bh_waypt.h b/3dc/avp/bh_waypt.h new file mode 100644 index 0000000..39fbd31 --- /dev/null +++ b/3dc/avp/bh_waypt.h @@ -0,0 +1,69 @@ +/***** bh_waypt.h *****/ + +/***** Waypoint system code... *****/ + +/***** CDF 27/10/97 *****/ + +struct strategyblock; + +typedef struct waypoint_link { + + int link_target_index; + int link_flags; + +} WAYPOINT_LINK; + +#define linkflag_oneway 0x00000001 /* link is... get this... one way! */ +#define linkflag_reversed_oneway 0x00000002 /* link is one way, only NOT this way. */ +#define linkflag_alienonly 0x00000004 +#define linkflag_largetarget 0x00000008 + +typedef struct waypoint_volume { + + VECTORCH centre; /* in MODULE space! */ + VECTORCH max_extents; + VECTORCH min_extents; + int flags; + int workspace:14; + unsigned int contains_npc:1; + unsigned int contains_target:1; + int num_links; + WAYPOINT_LINK *first_link; + unsigned char weighting; + +} WAYPOINT_VOLUME; + +#define wayflag_cancrawl 0x00000001 + +typedef struct waypoint_header { + + int num_waypoints; + WAYPOINT_VOLUME *first_waypoint; + +} WAYPOINT_HEADER; + +typedef struct waypoint_route { + + int num_waypoints; + WAYPOINT_VOLUME *start; + WAYPOINT_VOLUME *second; + WAYPOINT_VOLUME *last; + WAYPOINT_LINK *first_link; + +} WAYPOINT_ROUTE; + +typedef struct waypoint_manager { + + WAYPOINT_VOLUME *current_container; + WAYPOINT_VOLUME *current_target; + WAYPOINT_LINK *current_link; + VECTORCH current_target_point; + +} WAYPOINT_MANAGER; + +extern void InitWaypointSystem(int npctype); +extern int NPCGetWaypointDirection(WAYPOINT_HEADER *waypoints, struct strategyblock *sbPtr, VECTORCH *velocityDirection, VECTORCH *targetPosition, WAYPOINT_MANAGER *manager); +extern int AlienIsAllowedToAttack(struct strategyblock *sbPtr); +extern int AlienIsEncouragedToCrawl(void); +extern WAYPOINT_VOLUME *GetPositionValidity(struct module *conmod, VECTORCH *position, VECTORCH *suggestion); +extern void InitWaypointManager(WAYPOINT_MANAGER *manager); diff --git a/3dc/avp/bh_weap.c b/3dc/avp/bh_weap.c new file mode 100644 index 0000000..039c5fe --- /dev/null +++ b/3dc/avp/bh_weap.c @@ -0,0 +1,5530 @@ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" + +#include "bh_types.h" +#include "comp_shp.h" +#include "inventry.h" + +#define UseLocalAssert Yes + +#include "ourasert.h" + +#include "bh_weap.h" +#include "bh_debri.h" +#include "weapons.h" +#include "dynblock.h" +#include "dynamics.h" +#include "lighting.h" +#include "bh_pred.h" +#include "bh_alien.h" +#include "bh_marin.h" +#include "bh_dummy.h" +#include "pvisible.h" +#include "pheromon.h" +#include "psnd.h" +#include "psndplat.h" +#include "huddefs.h" + +#include "particle.h" +#include "sfx.h" +#include "ShowCmds.h" +#include "savegame.h" +#include "los.h" +#include "DetailLevels.h" + +#if SupportWindows95 +/* for win95 net game support */ +#include "pldghost.h" +#include "pldnet.h" +#endif + +#define FLAMETHROWER_PARTICLES_PER_FRAME (MUL_FIXED(120,NormalFrameTime)) +#define PREDPISTOLFLECHETTES_PARTICLES_PER_FRAME (MUL_FIXED(50,NormalFrameTime)) +#define TIME_FOR_PREDPISTOLFLECHETTE (ONE_FIXED/50) +#define TIME_FOR_FLAMETHROWER_PARTICLE (ONE_FIXED/120) +#define NEAR_WEAPON_FUDGE 1 +#define PREDPISTOL_SPREAD (4) + +#define NEW_PREDPISTOL_BOLT 1 +#define FRISBEE_SPEED 20000 +/* Was 10000. */ +#define ENERGY_BOLT_SPEED 65536 + +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ +static void InitialiseRocketBehaviour(void); +static void InitialiseGrenadeBehaviour(AVP_BEHAVIOUR_TYPE behaviourID); +static STRATEGYBLOCK* InitialisePulseGrenadeBehaviour(void); +static void InitialisePPPlasmaBoltBehaviour(void); +static void InitialiseSpeargunBoltBehaviour(void); +void InitialiseEnergyBoltBehaviour(DAMAGE_PROFILE *damage, int factor); +static void InitialiseFlameThrowerBehaviour(void); +void InitialiseDiscBehaviour(STRATEGYBLOCK *target,SECTION_DATA *disc_section); +static void InitialiseAlienSpitBehaviour(void); +static void InitialiseFragmentationGrenade(VECTORCH *originPtr); +STRATEGYBLOCK* InitialiseEnergyBoltBehaviourKernel(VECTORCH *position,MATRIXCH *orient, int player, DAMAGE_PROFILE *damage, int factor); +static void InitialiseFrisbeeBehaviour(void); +STRATEGYBLOCK* InitialiseFrisbeeBoltBehaviourKernel(VECTORCH *position,MATRIXCH *orient, int player, DAMAGE_PROFILE *damage, int factor); + +static void GetGunDirection(VECTORCH *gunDirectionPtr, VECTORCH *positionPtr); +void PredDisc_GetFirstTarget(PC_PRED_DISC_BEHAV_BLOCK *bptr, DISPLAYBLOCK *target, VECTORCH *position); +int PredDisc_TargetFilter(STRATEGYBLOCK *candidate); +void EulerAnglesHoming(VECTORCH *source, VECTORCH *Target, EULER *eulr, int rate); +void SetEulerAngles(VECTORCH *source, VECTORCH *Target, EULER *eulr); +STRATEGYBLOCK *PredDisc_GetNewTarget(PC_PRED_DISC_BEHAV_BLOCK *bptr,VECTORCH *discpos, STRATEGYBLOCK *prevtarg, int mine); +int ObjectIsOnScreen(DISPLAYBLOCK *object); +void Frisbee_Hit_Environment(STRATEGYBLOCK *sbPtr,COLLISIONREPORT *reportPtr); +void Crunch_Position_For_Players_Weapon(VECTORCH *position); + +/*KJL**************************************************************************************** +* G L O B A L S * +****************************************************************************************KJL*/ +extern int NormalFrameTime; +extern int ProjectilesFired; +extern SECTION_DATA *PWMFSDP; +extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); +extern ACTIVESOUNDSAMPLE ActiveSounds[]; +extern int AccuracyStats_TargetFilter(STRATEGYBLOCK *sbPtr); +extern BOOL CalculateFiringSolution(VECTORCH* firing_pos,VECTORCH* target_pos,VECTORCH* target_vel,int projectile_speed,VECTORCH* solution); + +int mx=0; +int my=-2000; +int mz=12000; + +extern int NumberOfFlaresActive; +int PredPistolBoltSpeed=32767; +int PredPistolBoltGravity=80000; + +int Caster_BlastRadius=5000; + +SOUND3DDATA Explosion_SoundData={ + {0,0,0,}, + {0,0,0,}, + 15000, + 150000, +}; + +SOUND3DDATA PredPistolExplosion_SoundData={ + {0,0,0,}, + {0,0,0,}, + 15000, + 100000, +}; + +/*KJL**************************************************************************************** +* F U N C T I O N S * +****************************************************************************************KJL*/ + +void FireProjectileAmmo(enum AMMO_ID AmmoID) +{ + switch (AmmoID) + { + case AMMO_GRENADE: + { + switch(GrenadeLauncherData.SelectedAmmo) + { + case AMMO_GRENADE: + { + InitialiseGrenadeBehaviour(I_BehaviourGrenade); + break; + } + case AMMO_FLARE_GRENADE: + { + InitialiseGrenadeBehaviour(I_BehaviourFlareGrenade); + break; + } + case AMMO_FRAGMENTATION_GRENADE: + { + InitialiseGrenadeBehaviour(I_BehaviourClusterGrenade); + break; + } + case AMMO_PROXIMITY_GRENADE: + { + InitialiseGrenadeBehaviour(I_BehaviourProximityGrenade); + break; + } + default: + { + /* KJL 10:36:25 04/21/97 - data error if you got here */ + LOCALASSERT(0); + break; + } + } + break; + } + case AMMO_PULSE_GRENADE: + { + InitialisePulseGrenadeBehaviour(); + break; + } + case AMMO_SADAR_TOW: + { + InitialiseRocketBehaviour(); + break; + } + case AMMO_FRISBEE: + { + InitialiseFrisbeeBehaviour(); + break; + } + + case AMMO_PRED_RIFLE: + { + InitialiseSpeargunBoltBehaviour(); + break; + } + + case AMMO_PRED_PISTOL: + { + InitialisePPPlasmaBoltBehaviour(); + break; + } + + case AMMO_PRED_ENERGY_BOLT: + { + InitialiseEnergyBoltBehaviour(&TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty],65536); + break; + } + + case AMMO_PRED_DISC: + { + break; + } + + case AMMO_FLAMETHROWER: + { + InitialiseFlameThrowerBehaviour(); + break; + } + + case AMMO_ALIEN_SPIT: + { + InitialiseAlienSpitBehaviour(); + break; + } + default: + break; + } +} + +/* CDF 12/7/99 Smart Frisbee for expansion pack? */ + +int FrisbeeSight_FrustrumReject(STRATEGYBLOCK *sbPtr,VECTORCH *localOffset,STRATEGYBLOCK *target) { + + FRISBEE_BEHAV_BLOCK *frisbeeStatusPointer; + VECTORCH fixed_offset; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + frisbeeStatusPointer = (FRISBEE_BEHAV_BLOCK *)(sbPtr->SBdataptr); + LOCALASSERT(frisbeeStatusPointer); + + #if 0 + PrintDebuggingText("Local Offset: %d %d %d\n",localOffset->vx,localOffset->vy,localOffset->vz); + #endif + + fixed_offset=*localOffset; + + #if 0 + if ((fixed_offset.vx <0) && ( + ((fixed_offset.vy) < (-fixed_offset.vx))&&(fixed_offset.vy>=0)) + ||((fixed_offset.vy<0)&&((-fixed_offset.vy) < (-fixed_offset.vx)) + )&&( + ((fixed_offset.vz) < (-fixed_offset.vx))&&(fixed_offset.vz>=0)) + ||((fixed_offset.vz<0)&&((-fixed_offset.vz) < (-fixed_offset.vx)) + )) { + /* 90 horizontal, 90 vertical? */ + #else + if ((fixed_offset.vx <0) && ( + ((fixed_offset.vy) < (-fixed_offset.vx))&&(fixed_offset.vy>=0)) + ||((fixed_offset.vy<0)&&((-fixed_offset.vy) < (-fixed_offset.vx)) + )&&( + (fixed_offset.vz>0) + )) { + /* 90 horizontal, 90 vertical? */ + #endif + return(1); + } else { + return(0); + } +} + +int Frisbee_TargetFilter(STRATEGYBLOCK *candidate) { + + switch (candidate->I_SBtype) { + case I_BehaviourMarinePlayer: + case I_BehaviourDummy: + { + switch (AvP.PlayerType) { + default: + case I_Marine: + return(0); + break; + case I_Predator: + case I_Alien: + return(1); + break; + } + return(0); + } + break; + case I_BehaviourAlien: + { + ALIEN_STATUS_BLOCK *alienStatusPointer; + LOCALASSERT(candidate); + LOCALASSERT(candidate->DynPtr); + + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(candidate->SBdataptr); + + if (NPC_IsDead(candidate)) { + return(0); + } else { + if ((alienStatusPointer->BehaviourState==ABS_Dormant)|| + (alienStatusPointer->BehaviourState==ABS_Awakening)) { + return(0); + } else { + return(1); + } + } + break; + } + case I_BehaviourQueenAlien: + case I_BehaviourFaceHugger: + case I_BehaviourPredator: + case I_BehaviourXenoborg: + case I_BehaviourSeal: + case I_BehaviourPredatorAlien: + /* Valid. */ + return(1); + break; + case I_BehaviourMarine: + return(0); + break; + #if SupportWindows95 + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *dataptr; + dataptr=candidate->SBdataptr; + switch (dataptr->type) { + case I_BehaviourMarinePlayer: + switch (netGameData.gameType) { + case NGT_Individual: + return(1); + break; + case NGT_CoopDeathmatch: + return(0); + break; + case NGT_LastManStanding: + return(0); + break; + case NGT_PredatorTag: + return(1); + break; + case NGT_Coop: + return(0); + break; + case NGT_AlienTag: + return(1); //However, there shouldn't be more than one alien in alien tag anyway. + break; + default: + return(0); + break; + } + break; + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + case I_BehaviourAlien: + return(1); + break; + default: + return(0); + break; + } + } + break; + #endif + default: + return(0); + break; + } + +} + +/* +Function only does minimal frisbee setup , the rest will be done by the load function +*/ +static STRATEGYBLOCK* InitialiseFrisbeeBehaviour_ForLoad() { + VECTORCH zeroVect = {0,0,0}; + + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + FRISBEE_BEHAV_BLOCK *bblk; + int a; + + + /* make displayblock with correct shape, etc */ + dispPtr = MakeObject(I_BehaviourFrisbee,&zeroVect); + + if (dispPtr == 0) return NULL; // Failed to allocate display block + + /* make displayblock a dynamic module object */ + dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + + /* give missile a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr = AllocateMem(sizeof(FRISBEE_BEHAV_BLOCK)); + bblk = dispPtr->ObStrategyBlock->SBdataptr; + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + memset(dispPtr->ObStrategyBlock->SBdataptr,0,sizeof(FRISBEE_BEHAV_BLOCK)); + + bblk->soundHandle = SOUND_NOACTIVEINDEX; + + bblk->Laser.SourcePosition=zeroVect; + bblk->Laser.SourcePosition=zeroVect; + bblk->Laser.BeamHasHitPlayer=0; + bblk->Laser.BeamIsOn=0; + + dispPtr->HModelControlBlock=&bblk->HModelController; + + + return dispPtr->ObStrategyBlock; +} + +STRATEGYBLOCK* CreateFrisbeeKernel(VECTORCH *position, MATRIXCH *orient, int fromplayer) { + + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + FRISBEE_BEHAV_BLOCK *fblk; + + /* make displayblock with correct shape, etc */ + dispPtr = MakeObject(I_BehaviourFrisbee,position); + if (dispPtr == 0) return NULL; // Failed to allocate display block + + /* make displayblock a dynamic module object */ + dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + + /* add lighting effect */ + AddLightingEffectToObject(dispPtr,LFX_ROCKETJET); + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + + if (fromplayer==0) { + dynPtr->IgnoreThePlayer=0; + } + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* give missile a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(FRISBEE_BEHAV_BLOCK)); + + fblk=((FRISBEE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr); + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + fblk->counter = (5*ONE_FIXED); + fblk->soundHandle = SOUND_NOACTIVEINDEX; + fblk->Bounced = 0; + fblk->bounces = 0; + + fblk->Laser.SourcePosition=*position; + fblk->Laser.SourcePosition=*position; + fblk->Laser.BeamHasHitPlayer=0; + fblk->Laser.BeamIsOn=0; + + /* Create HModel. */ + { + SECTION *root_section; + SECTION_DATA *local_disc; + + root_section=GetNamedHierarchyFromLibrary("mdisk","Mdisk"); + + GLOBALASSERT(root_section); + + Create_HModel(&fblk->HModelController,root_section); + InitHModelSequence(&fblk->HModelController,HMSQT_MarineStand,MSSS_Minigun_Delta,(ONE_FIXED>>1)); + + ProveHModel(&fblk->HModelController,dispPtr); + fblk->HModelController.Looped=1; + + dispPtr->HModelControlBlock=&fblk->HModelController; + + #if 0 + /* Match disks. */ + local_disc=GetThisSectionData(bblk->HModelController.section_data,"disk"); + local_disc->World_Offset=disc_section->World_Offset; + local_disc->SecMat=disc_section->SecMat; + InitHModelTweening(&bblk->HModelController,(ONE_FIXED>>2),HMSQT_MarineStand,MSSS_Minigun_Delta,ONE_FIXED,1); + #endif + } + + /* align rocket to launcher */ + dynPtr->Position=*position; + dynPtr->PrevPosition=*position; + + dynPtr->OrientMat = *orient; + dynPtr->PrevOrientMat = dynPtr->OrientMat; + + dynPtr->IgnoreThePlayer=1; + + /* I added this next line for networking: Patrick */ + MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); + + /* align velocity too */ + dynPtr->LinVelocity.vx = dynPtr->OrientMat.mat31; + dynPtr->LinVelocity.vy = dynPtr->OrientMat.mat32; + dynPtr->LinVelocity.vz = dynPtr->OrientMat.mat33; + + dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx, FRISBEE_SPEED); + dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy, FRISBEE_SPEED); + dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz, FRISBEE_SPEED); + + #if 0 + if (fromplayer==1) { + /* Add player velocity? */ + dynPtr->LinVelocity.vx+=Player->ObStrategyBlock->DynPtr->LinVelocity.vx; + dynPtr->LinVelocity.vy+=Player->ObStrategyBlock->DynPtr->LinVelocity.vy; + dynPtr->LinVelocity.vz+=Player->ObStrategyBlock->DynPtr->LinVelocity.vz; + } + #endif + + /* for net game support */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock); + #endif + + return dispPtr->ObStrategyBlock; + +} + +extern void FrisbeeBehaviour(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + FRISBEE_BEHAV_BLOCK *fbPtr = (FRISBEE_BEHAV_BLOCK * ) sbPtr->SBdataptr; + int explodeNow; + + MODULE *dmod; + + dmod=ModuleFromPosition(&sbPtr->DynPtr->Position,playerPherModule); + + //MakeRocketTrailParticles(&(dynPtr->PrevPosition), &(dynPtr->Position)); + explodeNow=0; + + if (fbPtr->counter<=0) + { + explodeNow=1; + } + else + { + if (reportPtr) + { + + /* Cut from disc code. Don't care about whether it was the player... */ + { + + /* Hit a random strategyblock - what is it? */ + if (SBForcesBounce(reportPtr->ObstacleSBPtr)) { + + MATRIXCH mat; + /* Bounce. */ + Reflect(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal, &dynPtr->OrientEuler); + dynPtr->OrientEuler.EulerZ=0; + dynPtr->IgnoreThePlayer=0; + MakeImpactSparks(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal,&dynPtr->Position); + Sound_Play(SID_ED_SKEETERDISC_HITWALL,"dp",&(dynPtr->Position),((FastRandom()&511)-255)); + fbPtr->bounces++; + /* + Record that the disc has bounced - for use in network game + */ + fbPtr->Bounced=1; + + CreateEulerMatrix(&dynPtr->OrientEuler, &mat); + TransposeMatrixCH(&mat); + + dynPtr->OrientMat=mat; + + dynPtr->LinVelocity.vx = MUL_FIXED(mat.mat31,FRISBEE_SPEED); + dynPtr->LinVelocity.vy = MUL_FIXED(mat.mat32,FRISBEE_SPEED); + dynPtr->LinVelocity.vz = MUL_FIXED(mat.mat33,FRISBEE_SPEED); + + dynPtr->LinImpulse.vx=0; + dynPtr->LinImpulse.vy=0; + dynPtr->LinImpulse.vz=0; + + + } else if (SBIsEnvironment(reportPtr->ObstacleSBPtr)) { + Frisbee_Hit_Environment(sbPtr,reportPtr); + } else { + /* Hit a creature? */ + VECTORCH attack_dir; + + /* Accuracy snipped. */ + GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir); + CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_FRISBEE].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir); + explodeNow=1; + } + } + } + } + + if (explodeNow) { + //NewOnScreenMessage("Frisbee Exploded."); + + /* KJL 17:51:56 12/17/96 - make explosion damage other objects */ + HandleEffectsOfExplosion + ( + sbPtr, + &(dynPtr->Position), + TemplateAmmo[AMMO_FRISBEE_BLAST].MaxRange, + &TemplateAmmo[AMMO_FRISBEE_BLAST].MaxDamage[AvP.Difficulty], + TemplateAmmo[AMMO_FRISBEE_BLAST].ExplosionIsFlat + ); + + if (sbPtr->containingModule) { + Explosion_SoundData.position=dynPtr->Position; + Sound_Play(SID_NICE_EXPLOSION,"n",&Explosion_SoundData); + } + + /* for net game support: send a message saying we've blown up... */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) { + AddNetMsg_LocalObjectDestroyed(sbPtr); + AddNetMsg_SpotOtherSound(SID_NICE_EXPLOSION,&dynPtr->Position,1); + } + #endif + + /* destroy rocket */ + DestroyAnyStrategyBlock(sbPtr); + + } + else + { + VECTORCH line; + SECTION_DATA *disc_section; + + /* We must be flying. Maintain sound. */ + if(fbPtr->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Update3d(fbPtr->soundHandle,&(sbPtr->DynPtr->Position)); + if (ActiveSounds[fbPtr->soundHandle].soundIndex!=SID_PREDATOR_DISK_FLYING) { + Sound_Stop(fbPtr->soundHandle); + Sound_Play(SID_ED_SKEETERDISC_SPIN,"del",&(sbPtr->DynPtr->Position),&fbPtr->soundHandle); + } + } else { + Sound_Play(SID_ED_SKEETERDISC_SPIN,"del",&(sbPtr->DynPtr->Position),&fbPtr->soundHandle); + } + + disc_section=GetThisSectionData(fbPtr->HModelController.section_data,"Mdisk"); + + if (disc_section) { + //ReleasePrintDebuggingText("Disc section found!\n"); + line.vx=disc_section->SecMat.mat11; + line.vy=disc_section->SecMat.mat12; + line.vz=disc_section->SecMat.mat13; + + //MakeParticle(&dynPtr->Position,&line,PARTICLE_PREDATOR_BLOOD); + /* Make a laser? */ + // KJL 12:32:40 08/02/00 - Fox want the laser beam removed + fbPtr->Laser.BeamIsOn=0; + { + int l; + for (l=0;l<4;l++) + MakeFlareParticle(dynPtr); + } + /* Now do the target sweep. */ + if (fbPtr->counter<(4*(ONE_FIXED))) + { + int a; + STRATEGYBLOCK *candidate,*nearest; + VECTORCH offset; + /* + MODULE *dmod; + dmod=ModuleFromPosition(&sbPtr->DynPtr->Position,playerPherModule); + LOCALASSERT(dmod); + */ + nearest=NULL; + + for (a=0; aDynPtr) + { + if (Frisbee_TargetFilter(candidate)) + { + /* Check visibility? */ + if ((candidate->SBdptr)&&(sbPtr->SBdptr)) + { + /* Near case. */ + if ((!NPC_IsDead(candidate)) + ||(candidate->I_SBtype==I_BehaviourMarinePlayer) + ||(candidate->I_SBtype==I_BehaviourDummy)) + { + if (NPCCanSeeTarget(sbPtr, candidate, ONE_FIXED)) + { + VECTORCH targetPos; + nearest=candidate; + + /* Shoot it, */ + GetTargetingPointOfObject_Far(nearest,&targetPos); + + if (CalculateFiringSolution(&sbPtr->DynPtr->Position,&nearest->DynPtr->Position, + &nearest->DynPtr->LinVelocity,ENERGY_BOLT_SPEED,&offset)) { + /* Use this. */ + } else { + offset.vx=targetPos.vx-sbPtr->DynPtr->Position.vx; + offset.vy=targetPos.vy-sbPtr->DynPtr->Position.vy; + offset.vz=targetPos.vz-sbPtr->DynPtr->Position.vz; + Normalise(&offset); + } + + { + MATRIXCH mat; + MatrixFromZVector(&offset,&mat); + InitialiseFrisbeeBoltBehaviourKernel(&sbPtr->DynPtr->Position,&mat, 0, + &TemplateAmmo[AMMO_FRISBEE].MaxDamage[AvP.Difficulty], 65536); + + } + } + } + } + else + { + if ((!NPC_IsDead(candidate)) + ||(candidate->I_SBtype==I_BehaviourMarinePlayer) + ||(candidate->I_SBtype==I_BehaviourDummy)) + { + + if (dmod) + { + if ((IsModuleVisibleFromModule(dmod,candidate->containingModule))) + { + VECTORCH targetPos; + nearest=candidate; + + /* Shoot it, */ + GetTargetingPointOfObject_Far(nearest,&targetPos); + + if (CalculateFiringSolution(&sbPtr->DynPtr->Position,&nearest->DynPtr->Position, + &nearest->DynPtr->LinVelocity,ENERGY_BOLT_SPEED,&offset)) { + /* Use this. */ + } else { + offset.vx=targetPos.vx-sbPtr->DynPtr->Position.vx; + offset.vy=targetPos.vy-sbPtr->DynPtr->Position.vy; + offset.vz=targetPos.vz-sbPtr->DynPtr->Position.vz; + Normalise(&offset); + } + + { + MATRIXCH mat; + MatrixFromZVector(&offset,&mat); + InitialiseFrisbeeBoltBehaviourKernel(&sbPtr->DynPtr->Position,&mat, 0, + &TemplateAmmo[AMMO_FRISBEE].MaxDamage[AvP.Difficulty], 65536); + } + } + } + } + } + } + } + } + } + if (nearest) + { + /* And explode. */ + + HandleEffectsOfExplosion + ( + sbPtr, + &(dynPtr->Position), + TemplateAmmo[AMMO_FRISBEE_FIRE].MaxRange, + &TemplateAmmo[AMMO_FRISBEE_FIRE].MaxDamage[AvP.Difficulty], + TemplateAmmo[AMMO_FRISBEE_FIRE].ExplosionIsFlat + ); + + if (sbPtr->containingModule) { + Explosion_SoundData.position=dynPtr->Position; + Sound_Play(SID_ED_SKEETERPLASMAFIRE,"n",&Explosion_SoundData); + } + + /* for net game support: send a message saying we've blown up... */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) { + AddNetMsg_LocalObjectDestroyed(sbPtr); + AddNetMsg_SpotOtherSound(SID_ED_SKEETERPLASMAFIRE,&dynPtr->Position,1); + } + #endif + + /* destroy rocket */ + DestroyAnyStrategyBlock(sbPtr); + } + } + } else { + //ReleasePrintDebuggingText("No disc section found!\n"); + } + fbPtr->counter-=NormalFrameTime; + } +} + + +/* KJL 14:08:18 02/21/97 - New rocket & grenade functions */ + +STRATEGYBLOCK* CreateRocketKernel(VECTORCH *position, MATRIXCH *orient, int fromplayer) { + + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + + /* make displayblock with correct shape, etc */ + dispPtr = MakeObject(I_BehaviourRocket,position); + if (dispPtr == 0) return NULL; // Failed to allocate display block + + /* make displayblock a dynamic module object */ + dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + + /* add lighting effect */ + AddLightingEffectToObject(dispPtr,LFX_ROCKETJET); + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + + if (fromplayer==0) { + dynPtr->IgnoreThePlayer=0; + } + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* give missile a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(PREDPISTOL_BEHAV_BLOCK)); + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED; + ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->player = fromplayer; + + /* align rocket to launcher */ + dynPtr->Position=*position; + dynPtr->PrevPosition=*position; + + dynPtr->OrientMat = *orient; + dynPtr->PrevOrientMat = dynPtr->OrientMat; + /* I added this next line for networking: Patrick */ + MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); + + /* align velocity too */ + #define MISSILE_SPEED 80000 + dynPtr->LinVelocity.vx = dynPtr->OrientMat.mat31; + dynPtr->LinVelocity.vy = dynPtr->OrientMat.mat32; + dynPtr->LinVelocity.vz = dynPtr->OrientMat.mat33; + + dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx, MISSILE_SPEED); + dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy, MISSILE_SPEED); + dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz, MISSILE_SPEED); + + /* for net game support */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock); + #endif + + return dispPtr->ObStrategyBlock; + +} + +static void InitialiseFrisbeeBehaviour(void) +{ + VECTORCH position; + + /* calculate the position */ + { + extern VECTORCH CentreOfMuzzleOffset; + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + position = CentreOfMuzzleOffset; + + RotateVector(&position,&PlayersWeapon.ObMat); + + position.vx+=PlayersWeapon.ObWorld.vx - VDBPtr->VDB_World.vx; + position.vx = position.vx/4 + VDBPtr->VDB_World.vx; + + position.vy+=PlayersWeapon.ObWorld.vy - VDBPtr->VDB_World.vy; + position.vy = position.vy/4 + VDBPtr->VDB_World.vy; + + position.vz+=PlayersWeapon.ObWorld.vz - VDBPtr->VDB_World.vz; + position.vz = position.vz/4 + VDBPtr->VDB_World.vz; + } + + CreateFrisbeeKernel(&position,&PlayersWeapon.ObMat,1); +} + +static void InitialiseRocketBehaviour(void) +{ + VECTORCH position; + + /* calculate the position */ + { + extern VECTORCH CentreOfMuzzleOffset; + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + position = CentreOfMuzzleOffset; + + RotateVector(&position,&PlayersWeapon.ObMat); + + position.vx+=PlayersWeapon.ObWorld.vx - VDBPtr->VDB_World.vx; + position.vx = position.vx/4 + VDBPtr->VDB_World.vx; + + position.vy+=PlayersWeapon.ObWorld.vy - VDBPtr->VDB_World.vy; + position.vy = position.vy/4 + VDBPtr->VDB_World.vy; + + position.vz+=PlayersWeapon.ObWorld.vz - VDBPtr->VDB_World.vz; + position.vz = position.vz/4 + VDBPtr->VDB_World.vz; + } + + CreateRocketKernel(&position,&PlayersWeapon.ObMat,1); +} + +extern void RocketBehaviour(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + PREDPISTOL_BEHAV_BLOCK *bbPtr = (PREDPISTOL_BEHAV_BLOCK * ) sbPtr->SBdataptr; + + MakeRocketTrailParticles(&(dynPtr->PrevPosition), &(dynPtr->Position)); + + if (reportPtr || (bbPtr->counter<=0) ) + { + + if (reportPtr) { + if (reportPtr->ObstacleSBPtr) { + VECTORCH attack_dir; + + if (AccuracyStats_TargetFilter(reportPtr->ObstacleSBPtr)) { + if (bbPtr->player) { + int slot; + /* Log accuracy! */ + slot=SlotForThisWeapon(WEAPON_SADAR); + if (slot!=-1) { + CurrentGameStats_WeaponHit(slot,1); + } + } + } + + GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir); + CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_SADAR_TOW].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir); + } + } + + /* KJL 17:51:56 12/17/96 - make explosion damage other objects */ + HandleEffectsOfExplosion + ( + sbPtr, + &(dynPtr->Position), + TemplateAmmo[AMMO_SADAR_BLAST].MaxRange, + &TemplateAmmo[AMMO_SADAR_BLAST].MaxDamage[AvP.Difficulty], + TemplateAmmo[AMMO_SADAR_BLAST].ExplosionIsFlat + ); + + if (sbPtr->containingModule) { + Explosion_SoundData.position=dynPtr->Position; + Sound_Play(SID_NICE_EXPLOSION,"n",&Explosion_SoundData); + } + + /* for net game support: send a message saying we've blown up... */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + + /* destroy rocket */ + DestroyAnyStrategyBlock(sbPtr); + + } + else + { + bbPtr->counter-=NormalFrameTime; + //dynPtr->IgnoreThePlayer=0; + } +} + +STRATEGYBLOCK* CreateGrenadeKernel(AVP_BEHAVIOUR_TYPE behaviourID, VECTORCH *position, MATRIXCH *orient,int fromplayer) { + + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + + /* make displayblock with correct shape, etc */ + dispPtr = MakeObject(behaviourID,position); + if (dispPtr == 0) return NULL; // Failed to allocate display block + + /* make displayblock a dynamic module object */ + dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + + switch(behaviourID) + { + case I_BehaviourFlareGrenade: + { + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(FLARE_BEHAV_BLOCK)); + break; + } + case I_BehaviourProximityGrenade: + { + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(PROX_GRENADE_BEHAV_BLOCK)); + break; + } + default: + { + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(GRENADE_BEHAV_BLOCK)); + break; + } + } + + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE); + + if (fromplayer==0) { + dynPtr->IgnoreThePlayer=0; + } + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + /* setup dynamics block */ + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* align grenade to launcher */ + dynPtr->Position=*position; + dynPtr->PrevPosition=*position; + dynPtr->OrientMat = *orient; + dynPtr->PrevOrientMat = dynPtr->OrientMat; + /* and convert to an euler */ + MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); + + /* align velocity too */ + #define GRENADE_SPEED 70000 + dynPtr->LinImpulse.vx = MUL_FIXED(dynPtr->OrientMat.mat31,GRENADE_SPEED); + dynPtr->LinImpulse.vy = MUL_FIXED(dynPtr->OrientMat.mat32,GRENADE_SPEED); + dynPtr->LinImpulse.vz = MUL_FIXED(dynPtr->OrientMat.mat33,GRENADE_SPEED); + dynPtr->AngImpulse.EulerX = ((FastRandom()&2047)-1024)*4; + dynPtr->AngImpulse.EulerY = ((FastRandom()&2047)-1024)*4; + dynPtr->AngImpulse.EulerZ = ((FastRandom()&2047)-1024)*8; + + dynPtr->IgnoresNotVisPolys = 1; + + switch(behaviourID) + { + case I_BehaviourFlareGrenade: + { + dynPtr->StopOnCollision = 1; + ((FLARE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->LifeTimeRemaining = FLARE_LIFETIME*ONE_FIXED; + ((FLARE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->ParticleGenerationTimer = 0; + AddLightingEffectToObject(dispPtr,LFX_FLARE); + ((FLARE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->SoundHandle = SOUND_NOACTIVEINDEX; + + ((FLARE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->becomeStuck = 0; + + NumberOfFlaresActive++; + + break; + } + case I_BehaviourProximityGrenade: + { + dynPtr->StopOnCollision = 1; + ((PROX_GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->LifeTimeRemaining = 2*ONE_FIXED; + ((PROX_GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->SoundHandle = SOUND_NOACTIVEINDEX; + ((PROX_GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->SoundGenerationTimer = 0; + break; + } + default: + { + ((GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 2*ONE_FIXED; + ((GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->bouncelastframe = 0; + break; + } + } + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock); + #endif + + return dispPtr->ObStrategyBlock; +} + +static void InitialiseGrenadeBehaviour(AVP_BEHAVIOUR_TYPE behaviourID) +{ + VECTORCH position; + + /* calculate the position */ + { + extern VECTORCH CentreOfMuzzleOffset; + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + position = CentreOfMuzzleOffset; + + RotateVector(&position,&PlayersWeapon.ObMat); + + position.vx+=PlayersWeapon.ObWorld.vx - VDBPtr->VDB_World.vx; + position.vx = position.vx/4 + VDBPtr->VDB_World.vx; + + position.vy+=PlayersWeapon.ObWorld.vy - VDBPtr->VDB_World.vy; + position.vy = position.vy/4 + VDBPtr->VDB_World.vy; + + position.vz+=PlayersWeapon.ObWorld.vz - VDBPtr->VDB_World.vz; + position.vz = position.vz/4 + VDBPtr->VDB_World.vz; + } + + CreateGrenadeKernel(behaviourID,&position,&PlayersWeapon.ObMat,1); + +} + + +extern void GrenadeBehaviour(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + GRENADE_BEHAV_BLOCK *bbPtr = (GRENADE_BEHAV_BLOCK * ) sbPtr->SBdataptr; + int explodeNow = 0; + int bounce=0; + + /* some sort of trail would look good */ + /* but calling this takes bloody ages */ + MakeGrenadeTrailParticles(&dynPtr->PrevPosition,&dynPtr->Position); + #if 0 + { + VECTORCH velocity; + velocity.vx = (FastRandom()&255) - 128; + velocity.vy = -1000-(FastRandom()&255); + velocity.vz = (FastRandom()&255) - 128; + MakeParticle(&(dynPtr->Position),&(velocity),PARTICLE_BLACKSMOKE); + } + #endif + + //if (reportPtr==NULL) { + // dynPtr->IgnoreThePlayer=0; + //} + /* explode if the grenade touches an alien */ + if (reportPtr==NULL) { + bbPtr->bouncelastframe=0; + } + + while (reportPtr) + { + STRATEGYBLOCK *sbPtr = reportPtr->ObstacleSBPtr; + + bounce=1; + + if(sbPtr) + { + if((sbPtr->I_SBtype == I_BehaviourAlien) + ||(sbPtr->I_SBtype == I_BehaviourMarinePlayer) + ||(sbPtr->I_SBtype == I_BehaviourAlienPlayer) + ||(sbPtr->I_SBtype == I_BehaviourPredatorPlayer) + ||(sbPtr->I_SBtype == I_BehaviourPredator) + ||(sbPtr->I_SBtype == I_BehaviourXenoborg) + ||(sbPtr->I_SBtype == I_BehaviourMarine) + ||(sbPtr->I_SBtype == I_BehaviourQueenAlien) + ||(sbPtr->I_SBtype == I_BehaviourPredatorAlien) + ||(sbPtr->I_SBtype == I_BehaviourFaceHugger)) + { + explodeNow = 1; /* kaboom */ + } + + #if SupportWindows95 + if(sbPtr->I_SBtype == I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData = sbPtr->SBdataptr; + LOCALASSERT(ghostData); + LOCALASSERT(AvP.Network!=I_No_Network); + + if((ghostData->type == I_BehaviourMarinePlayer)|| + (ghostData->type == I_BehaviourPredatorPlayer)|| + (ghostData->type == I_BehaviourAlienPlayer)|| + (ghostData->type == I_BehaviourAlien)) + { + explodeNow = 1; + } + } + #endif + } else { + dynPtr->IgnoreThePlayer=0; + } + + /* skip to next report */ + reportPtr = reportPtr->NextCollisionReportPtr; + } + + if (bounce&&(explodeNow==0)&&(bbPtr->bouncelastframe==0)) { + Sound_Play(SID_GRENADE_BOUNCE,"dp",&(dynPtr->Position),((FastRandom()&511)-255)); + bbPtr->bouncelastframe=1; + } + + if ((bbPtr->counter<=0) || explodeNow) + { + /* KJL 17:51:56 12/17/96 - make explosion damage other objects */ + HandleEffectsOfExplosion + ( + sbPtr, + &(dynPtr->Position), + TemplateAmmo[AMMO_GRENADE].MaxRange, + &TemplateAmmo[AMMO_GRENADE].MaxDamage[AvP.Difficulty], + TemplateAmmo[AMMO_GRENADE].ExplosionIsFlat + ); + + if (sbPtr->containingModule) { + Explosion_SoundData.position=dynPtr->Position; + Sound_Play(SID_ED_GRENADE_EXPLOSION,"n",&Explosion_SoundData); + } + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + /* destroy rocket */ + DestroyAnyStrategyBlock(sbPtr); + } + else + { + bbPtr->counter-=NormalFrameTime; + DynamicallyRotateObject(dynPtr); + } +} +extern void ClusterGrenadeBehaviour(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + GRENADE_BEHAV_BLOCK *bbPtr = (GRENADE_BEHAV_BLOCK * ) sbPtr->SBdataptr; + int explodeNow = 0; + int bounce=0; + + { + VECTORCH velocity; + velocity.vx = (FastRandom()&255) - 128; + velocity.vy = -1000-(FastRandom()&255); + velocity.vz = (FastRandom()&255) - 128; + MakeParticle(&(dynPtr->Position),&(velocity),PARTICLE_BLACKSMOKE); + } + + //if (reportPtr==NULL) { + // dynPtr->IgnoreThePlayer=0; + //} + /* explode if the grenade touches an alien */ + if (reportPtr==NULL) { + bbPtr->bouncelastframe=0; + } + + while (reportPtr) + { + STRATEGYBLOCK *sbPtr = reportPtr->ObstacleSBPtr; + + bounce=1; + + if (sbPtr) + { + if((sbPtr->I_SBtype == I_BehaviourAlien) + ||(sbPtr->I_SBtype == I_BehaviourMarinePlayer) + ||(sbPtr->I_SBtype == I_BehaviourAlienPlayer) + ||(sbPtr->I_SBtype == I_BehaviourPredatorPlayer) + ||(sbPtr->I_SBtype == I_BehaviourPredator) + ||(sbPtr->I_SBtype == I_BehaviourXenoborg) + ||(sbPtr->I_SBtype == I_BehaviourMarine) + ||(sbPtr->I_SBtype == I_BehaviourQueenAlien) + ||(sbPtr->I_SBtype == I_BehaviourPredatorAlien) + ||(sbPtr->I_SBtype == I_BehaviourFaceHugger)) + { + explodeNow = 1; /* kaboom */ + } + #if SupportWindows95 + if(sbPtr->I_SBtype == I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData = sbPtr->SBdataptr; + LOCALASSERT(ghostData); + LOCALASSERT(AvP.Network!=I_No_Network); + + if((ghostData->type == I_BehaviourMarinePlayer)|| + (ghostData->type == I_BehaviourPredatorPlayer)|| + (ghostData->type == I_BehaviourAlienPlayer)|| + (ghostData->type == I_BehaviourAlien)) + { + explodeNow = 1; + } + } + #endif + } else { + dynPtr->IgnoreThePlayer=0; + } + + /* skip to next report */ + reportPtr = reportPtr->NextCollisionReportPtr; + } + + if (bounce&&(explodeNow==0)&&(bbPtr->bouncelastframe==0)) { + Sound_Play(SID_GRENADE_BOUNCE,"dp",&(dynPtr->Position),((FastRandom()&511)-255)); + bbPtr->bouncelastframe=1; + } + + if ((bbPtr->counter<=0) || explodeNow) + { + extern void MakeFlechetteExplosionAt(VECTORCH *positionPtr,int seed); + MakeFlechetteExplosionAt(&dynPtr->Position,0); + #if 0 + /* make explosion sprite & frag grenades */ + { + int num; + for(num=0;numPosition)); + } + } + #endif + if (sbPtr->containingModule) { + Explosion_SoundData.position=dynPtr->Position; + Sound_Play(SID_NADEEXPLODE,"n",&Explosion_SoundData); + } + /* for net game support: send a message saying we've blown up... */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + /* destroy rocket */ + DestroyAnyStrategyBlock(sbPtr); + } + else + { + bbPtr->counter-=NormalFrameTime; + DynamicallyRotateObject(dynPtr); + } +} + +static void InitialiseFragmentationGrenade(VECTORCH *originPtr) +{ + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + VECTORCH position; + + /* calculate the position */ + position = *originPtr; + + /* make displayblock with correct shape, etc */ + dispPtr = MakeObject(I_BehaviourFragmentationGrenade,&position); + if (dispPtr == 0) return; // Failed to allocate display block + + /* make displayblock a dynamic module object */ + dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + + /* give grenade a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(GRENADE_BEHAV_BLOCK)); + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + + ((GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = FRAG_LIFETIME; + ((GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->bouncelastframe = 0; + + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + + /* setup dynamics block */ + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* align grenade to launcher */ + dynPtr->Position=position; + dynPtr->OrientMat = PlayersWeapon.ObMat; + dynPtr->PrevOrientMat = dynPtr->OrientMat; + /* and convert to an euler */ + MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); + + /* align velocity too */ + dynPtr->LinImpulse.vx = ((FastRandom()&16383)-8192); + dynPtr->LinImpulse.vy = -(FastRandom()&16383)-8192; + dynPtr->LinImpulse.vz = ((FastRandom()&16383)-8192); + dynPtr->AngImpulse.EulerX = ((FastRandom()&2047)-1024)*4; + dynPtr->AngImpulse.EulerY = ((FastRandom()&2047)-1024)*4; + dynPtr->AngImpulse.EulerZ = ((FastRandom()&2047)-1024)*8; + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock); + #endif +} +extern void ProximityGrenadeBehaviour(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + PROX_GRENADE_BEHAV_BLOCK *bbPtr = (PROX_GRENADE_BEHAV_BLOCK * ) sbPtr->SBdataptr; + + MakeGrenadeTrailParticles(&dynPtr->PrevPosition,&dynPtr->Position); + + if (bbPtr->LifeTimeRemaining<=0) + { + /* KJL 17:51:56 12/17/96 - make explosion damage other objects */ + HandleEffectsOfExplosion + ( + sbPtr, + &(dynPtr->Position), + TemplateAmmo[AMMO_GRENADE].MaxRange, + &TemplateAmmo[AMMO_GRENADE].MaxDamage[AvP.Difficulty], + TemplateAmmo[AMMO_GRENADE].ExplosionIsFlat + ); + + if (bbPtr->SoundHandle!=SOUND_NOACTIVEINDEX) + { + Sound_Stop(bbPtr->SoundHandle); + bbPtr->SoundHandle = SOUND_NOACTIVEINDEX; + + } + + if (sbPtr->containingModule) { + Explosion_SoundData.position=dynPtr->Position; + Sound_Play(SID_ED_GRENADE_PROXEXPLOSION,"n",&Explosion_SoundData); + } + + /* for net game support: send a message saying we've blown up... */ + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + + /* destroy! */ + DestroyAnyStrategyBlock(sbPtr); + return; + } + else if (dynPtr->IsStatic && bbPtr->LifeTimeRemaining>PROX_GRENADE_TRIGGER_TIME) + { + // scan for objects in proximity + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + int i = NumActiveStBlocks; + + { + int scale = ONE_FIXED-bbPtr->LifeTimeRemaining/PROX_GRENADE_LIFETIME; + scale = MUL_FIXED(scale,scale); + scale = MUL_FIXED(scale,scale)*8; + bbPtr->SoundGenerationTimer += NormalFrameTime + MUL_FIXED(NormalFrameTime,scale); + } + while (bbPtr->SoundGenerationTimer >= PROX_GRENADE_SOUND_GENERATION_TIME) + { + bbPtr->SoundGenerationTimer -= PROX_GRENADE_SOUND_GENERATION_TIME; + Sound_Play(SID_PROX_GRENADE_ACTIVE,"d",&(dynPtr->Position)); + } + + + while (i--) + { + STRATEGYBLOCK *obstaclePtr = ActiveStBlockList[i]; + DYNAMICSBLOCK *obstacleDynPtr = obstaclePtr->DynPtr; + + if (obstacleDynPtr) + { + if(ValidTargetForProxMine(obstaclePtr)) + { + VECTORCH disp = obstacleDynPtr->Position; + disp.vx -= dynPtr->Position.vx; + disp.vy -= dynPtr->Position.vy; + disp.vz -= dynPtr->Position.vz; + + if (Approximate3dMagnitude(&disp)<=PROX_GRENADE_RANGE) + { + bbPtr->LifeTimeRemaining = PROX_GRENADE_TRIGGER_TIME; + } + } + } + } + } + else + { + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + + if (reportPtr) + { + char stickWhereYouAre = 0; + + STRATEGYBLOCK *obstaclePtr = reportPtr->ObstacleSBPtr; + + if (obstaclePtr) + { + DISPLAYBLOCK *dispPtr = obstaclePtr->SBdptr; + + if(ValidTargetForProxMine(obstaclePtr)) + { + /* best blow up then */ + bbPtr->LifeTimeRemaining=0; + return; + } + else if (dispPtr) + { + if (dispPtr->ObMyModule && (!dispPtr->ObMorphCtrl)) + { + stickWhereYouAre=1; + } + } + } + else + { + stickWhereYouAre = 1; + } + + + if(stickWhereYouAre) + { + dynPtr->IsStatic=1; + dynPtr->PrevPosition=dynPtr->Position; + MakeMatrixFromDirection(&(reportPtr->ObstacleNormal),&(dynPtr->OrientMat)); + /* KJL 15:27:42 23/01/99 - Euler has to be filled out for network play! */ + MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); + bbPtr->LifeTimeRemaining = PROX_GRENADE_LIFETIME*ONE_FIXED; + } + } + } + + if (bbPtr->LifeTimeRemaining<=PROX_GRENADE_TRIGGER_TIME && bbPtr->SoundHandle==SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_PROX_GRENADE_READYTOBLOW,"de",&(dynPtr->Position),&bbPtr->SoundHandle); + } + bbPtr->LifeTimeRemaining-=NormalFrameTime; + + +} + +int ValidTargetForProxMine(STRATEGYBLOCK *obstaclePtr) +{ + if((obstaclePtr->I_SBtype == I_BehaviourAlien) + ||(obstaclePtr->I_SBtype == I_BehaviourMarinePlayer) + ||(obstaclePtr->I_SBtype == I_BehaviourAlienPlayer) + ||(obstaclePtr->I_SBtype == I_BehaviourPredatorPlayer) + ||(obstaclePtr->I_SBtype == I_BehaviourPredator) + ||(obstaclePtr->I_SBtype == I_BehaviourXenoborg) + ||(obstaclePtr->I_SBtype == I_BehaviourMarine) + ||(obstaclePtr->I_SBtype == I_BehaviourQueenAlien) + ||(obstaclePtr->I_SBtype == I_BehaviourFaceHugger)) + { + return 1; + } + + if(obstaclePtr->I_SBtype == I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)obstaclePtr->SBdataptr; + + if (ghostDataPtr->type==I_BehaviourAlienPlayer + ||ghostDataPtr->type==I_BehaviourMarinePlayer + ||ghostDataPtr->type==I_BehaviourPredatorPlayer + ||ghostDataPtr->type==I_BehaviourAlien) + { + return 1; + } + } + return 0; +} + + +extern void FlareGrenadeBehaviour(STRATEGYBLOCK *sbPtr) +{ + FLARE_BEHAV_BLOCK *bbPtr = (FLARE_BEHAV_BLOCK * ) sbPtr->SBdataptr; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + + if ((bbPtr->LifeTimeRemaining<=0)) + { + if (bbPtr->SoundHandle!=SOUND_NOACTIVEINDEX) + { + Sound_Stop(bbPtr->SoundHandle); + bbPtr->SoundHandle = SOUND_NOACTIVEINDEX; + + } + + /* for net game support: send a message saying we've blown up... */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + /* destroy rocket */ + DestroyAnyStrategyBlock(sbPtr); + + + NumberOfFlaresActive--; + return; + } + + { + if (bbPtr->LifeTimeRemaining>ONE_FIXED*4) + { + bbPtr->ParticleGenerationTimer += NormalFrameTime; + } + else + { + bbPtr->ParticleGenerationTimer += MUL_FIXED(NormalFrameTime,bbPtr->LifeTimeRemaining)/4; + } + + while (bbPtr->ParticleGenerationTimer >= FLARE_PARTICLE_GENERATION_TIME) + { + bbPtr->ParticleGenerationTimer -= FLARE_PARTICLE_GENERATION_TIME; + MakeFlareParticle(dynPtr); + } + + /* add lighting effect */ + { + LIGHTBLOCK *lightPtr = sbPtr->SBdptr->ObLights[0]; + LOCALASSERT(sbPtr->SBdptr->ObNumLights==1); + lightPtr->LightBright = 1+MUL_FIXED + ( + (ONE_FIXED*4-(FastRandom()&32767)), + bbPtr->LifeTimeRemaining/FLARE_LIFETIME + ); + } + + bbPtr->LifeTimeRemaining-=NormalFrameTime; + } + + if (dynPtr->IsFloating) + { + RubberDuckBehaviour(sbPtr); + } + else if (!dynPtr->IsStatic) + { + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + + //if (reportPtr==NULL) { + // dynPtr->IgnoreThePlayer=0; + //} + if (reportPtr) + { + char stickWhereYouAre = 0; + + if (reportPtr->ObstacleSBPtr) + { + DISPLAYBLOCK *dispPtr = reportPtr->ObstacleSBPtr->SBdptr; + if (dispPtr) + if (dispPtr->ObMyModule && (!dispPtr->ObMorphCtrl)) + { + stickWhereYouAre=1; + } + } + else + { + stickWhereYouAre = 1; + } + + + if(stickWhereYouAre) + { + dynPtr->IsStatic=1; + dynPtr->OnlyCollideWithEnvironment = 1; + dynPtr->PrevPosition=dynPtr->Position; + MakeMatrixFromDirection(&(reportPtr->ObstacleNormal),&(dynPtr->OrientMat)); + /* KJL 15:27:42 23/01/99 - Euler has to be filled out for network play! */ + MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); + Sound_Play(SID_BURNING_FLARE,"dle",&(dynPtr->Position),&bbPtr->SoundHandle); + + //set flag ,so appropriate net message gets sent + bbPtr->becomeStuck=1; + + } + } +// DynamicallyRotateObject(dynPtr); + } +} + +static STRATEGYBLOCK* InitialisePulseGrenadeBehaviour(void) +{ + /* more of a rocket than a grenade... */ + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + VECTORCH position; + + /* calculate the position */ + { + extern VECTORCH CentreOfMuzzleOffset; + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + position = CentreOfMuzzleOffset; + + RotateVector(&position,&PlayersWeapon.ObMat); + + position.vx+=PlayersWeapon.ObWorld.vx - VDBPtr->VDB_World.vx; + position.vx = position.vx/4 + VDBPtr->VDB_World.vx; + + position.vy+=PlayersWeapon.ObWorld.vy - VDBPtr->VDB_World.vy; + position.vy = position.vy/4 + VDBPtr->VDB_World.vy; + + position.vz+=PlayersWeapon.ObWorld.vz - VDBPtr->VDB_World.vz; + position.vz = position.vz/4 + VDBPtr->VDB_World.vz; + } + + /* make displayblock with correct shape, etc */ + dispPtr = MakeObject(I_BehaviourPulseGrenade,&position); + if (dispPtr == 0) return NULL; // Failed to allocate display block + + /* add lighting effect */ + AddLightingEffectToObject(dispPtr,LFX_ROCKETJET); + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* give missile a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(PREDPISTOL_BEHAV_BLOCK)); + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED; + ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->player = 1; + + /* align rocket to launcher */ + dynPtr->Position=position; + dynPtr->PrevPosition=position; + dynPtr->OrientMat = PlayersWeapon.ObMat; + dynPtr->PrevOrientMat = dynPtr->OrientMat; + + /* align velocity too */ + #define PULSEGRENADE_SPEED 100000 // Was 30000 + GetGunDirection(&(dynPtr->LinVelocity),&position); + dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx, PULSEGRENADE_SPEED); + dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy, PULSEGRENADE_SPEED); + dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz, PULSEGRENADE_SPEED); + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock); + #endif + + return dispPtr->ObStrategyBlock; +} + + +extern void PulseGrenadeBehaviour(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + PREDPISTOL_BEHAV_BLOCK *bbPtr = (PREDPISTOL_BEHAV_BLOCK * ) sbPtr->SBdataptr; + + MakeRocketTrailParticles(&(dynPtr->PrevPosition), &(dynPtr->Position)); + + //Work out the containing module now , since it doesn't seem to get done anywhere else + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), sbPtr->containingModule); + + + //if (reportPtr==NULL) { + // dynPtr->IgnoreThePlayer=0; + //} + if (reportPtr || (bbPtr->counter<=0) ) + { + + if (reportPtr) { + if (reportPtr->ObstacleSBPtr) { + VECTORCH attack_dir; + + if (AccuracyStats_TargetFilter(reportPtr->ObstacleSBPtr)) { + if (bbPtr->player) { + int slot; + /* Log accuracy! */ + slot=SlotForThisWeapon(WEAPON_PULSERIFLE); + if (slot!=-1) { + CurrentGameStats_WeaponHit(slot,1); + } + } + } + + GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir); + CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PULSE_GRENADE_STRIKE].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir); + } + } + + /* KJL 17:51:56 12/17/96 - make explosion damage other objects */ + HandleEffectsOfExplosion + ( + sbPtr, + &(dynPtr->Position), + TemplateAmmo[AMMO_PULSE_GRENADE].MaxRange, + &TemplateAmmo[AMMO_PULSE_GRENADE].MaxDamage[AvP.Difficulty], + TemplateAmmo[AMMO_PULSE_GRENADE].ExplosionIsFlat + ); + + if (sbPtr->containingModule) { + Explosion_SoundData.position=dynPtr->Position; + Sound_Play(SID_NADEEXPLODE,"n",&Explosion_SoundData); + } + + /* for net game support: send a message saying we've blown up... */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + /* destroy rocket */ + DestroyAnyStrategyBlock(sbPtr); + } + else + { + bbPtr->counter-=NormalFrameTime; + } +} + +STRATEGYBLOCK* InitialiseEnergyBoltBehaviourKernel(VECTORCH *position,MATRIXCH *orient, int player, DAMAGE_PROFILE *damage, int factor) { + + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + + /* make displayblock with correct shape, etc */ + dispPtr = MakeObject(I_BehaviourPredatorEnergyBolt,position); + if (dispPtr == 0) return NULL; // Failed to allocate display block + + dispPtr->SfxPtr = AllocateSfxBlock(); + + if (!dispPtr->SfxPtr) + { + // Failed to allocate a special fx block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + dispPtr->SfxPtr->SfxID = SFX_PREDATOR_PLASMA_BOLT; + /* make displayblock a dynamic module object */ + dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + dispPtr->ObShape = 0; + dispPtr->ObStrategyBlock->shapeIndex = 0; + dispPtr->ObMinX = -50; + dispPtr->ObMinY = -50; + dispPtr->ObMinZ = -50; + dispPtr->ObMaxX = 50; + dispPtr->ObMaxY = 50; + dispPtr->ObMaxZ = 50; + /* add lighting effect */ + AddLightingEffectToObject(dispPtr,LFX_PLASMA_BOLT); + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* give missile a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(CASTER_BOLT_BEHAV_BLOCK)); + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED; + ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->damage = *damage; + ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->blast_radius = MUL_FIXED(factor,Caster_BlastRadius); + ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->player = player; + ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->soundHandle = SOUND_NOACTIVEINDEX; + + /* align rocket to launcher */ + dynPtr->Position=*position; + dynPtr->PrevPosition=*position; + + //GetGunDirection(&(dynPtr->LinVelocity),&position); + //MakeMatrixFromDirection(&(dynPtr->LinVelocity),&(dynPtr->OrientMat)); + //MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); + //dynPtr->PrevOrientMat = dynPtr->OrientMat; + + /* align velocity too */ + dynPtr->OrientMat = *orient; + dynPtr->PrevOrientMat = dynPtr->OrientMat; + /* I added this next line for networking: Patrick */ + MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); + + /* align velocity too */ + dynPtr->LinVelocity.vx = dynPtr->OrientMat.mat31; + dynPtr->LinVelocity.vy = dynPtr->OrientMat.mat32; + dynPtr->LinVelocity.vz = dynPtr->OrientMat.mat33; + + dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx, ENERGY_BOLT_SPEED); + dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy, ENERGY_BOLT_SPEED); + dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz, ENERGY_BOLT_SPEED); + + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock); + #endif + + /* Extra cunning! */ + Sound_Play(SID_PRED_LAUNCHER,"hpd",(FastRandom()&255)-128,&dynPtr->Position); + + if (player==0) { + dynPtr->IgnoreThePlayer=0; + } + + return dispPtr->ObStrategyBlock; +} + +void InitialiseEnergyBoltBehaviour(DAMAGE_PROFILE *damage, int factor) +{ + VECTORCH position={-300,0,0}; + + /* calculate the position */ + { + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + + MATRIXCH matrix = VDBPtr->VDB_Mat; + TransposeMatrixCH(&matrix); + + RotateVector(&position,&matrix); + + position.vx += VDBPtr->VDB_World.vx; + position.vy += VDBPtr->VDB_World.vy; + position.vz += VDBPtr->VDB_World.vz; + } + + #if 1 + { + VECTORCH targetDirection; + MATRIXCH orient; + + GetGunDirection(&targetDirection,&position); + MakeMatrixFromDirection(&targetDirection,&orient); + + InitialiseEnergyBoltBehaviourKernel(&position,&orient,1,damage,factor); + } + #else + /* make displayblock with correct shape, etc */ + dispPtr = MakeObject(I_BehaviourPredatorEnergyBolt,&position); + if (dispPtr == 0) return; // Failed to allocate display block + + dispPtr->SfxPtr = AllocateSfxBlock(); + + if (!dispPtr->SfxPtr) + { + // Failed to allocate a special fx block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + + dispPtr->SfxPtr->SfxID = SFX_PREDATOR_PLASMA_BOLT; + /* make displayblock a dynamic module object */ + dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + dispPtr->ObShape = 0; + dispPtr->ObStrategyBlock->shapeIndex = 0; + /* add lighting effect */ + AddLightingEffectToObject(dispPtr,LFX_PLASMA_BOLT); + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* give missile a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(CASTER_BOLT_BEHAV_BLOCK)); + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + + ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED; + ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->damage = *damage; + + /* align rocket to launcher */ + dynPtr->Position=position; + dynPtr->PrevPosition=position; + + /* align velocity too */ + #define ENERGY_BOLT_SPEED 3000 + GetGunDirection(&(dynPtr->LinVelocity),&position); + MakeMatrixFromDirection(&(dynPtr->LinVelocity),&(dynPtr->OrientMat)); + MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); + dynPtr->PrevOrientMat = dynPtr->OrientMat; + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock); + #endif + + /* Extra cunning! */ + Sound_Play(SID_PRED_LAUNCHER,"hpd",(FastRandom()&255)-128,&dynPtr->Position); + #endif +} + +/****/ + +#if NEW_PREDPISTOL_BOLT +STRATEGYBLOCK* CreatePPPlasmaBoltKernel(VECTORCH *position,MATRIXCH *orient, int player) +{ + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + + /* make displayblock with correct shape, etc */ + dispPtr = MakeObject(I_BehaviourPPPlasmaBolt,position); + if (dispPtr == 0) return NULL; // Failed to allocate display block + + dispPtr->SfxPtr = AllocateSfxBlock(); + + if (!dispPtr->SfxPtr) + { + // Failed to allocate a special fx block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + dispPtr->SfxPtr->SfxID = SFX_SMALL_PREDATOR_PLASMA_BOLT; + /* make displayblock a dynamic module object */ + dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + dispPtr->ObShape = 0; + dispPtr->ObStrategyBlock->shapeIndex = 0; + + /* add lighting effect */ + AddLightingEffectToObject(dispPtr,LFX_PLASMA_BOLT); + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* give missile a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(PREDPISTOL_BEHAV_BLOCK)); + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED; + ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->player = player; + + /* align rocket to launcher */ + dynPtr->Position=*position; + dynPtr->PrevPosition=*position; + + /* align velocity too */ + dynPtr->OrientMat = *orient; + dynPtr->PrevOrientMat = dynPtr->OrientMat; + /* I added this next line for networking: Patrick */ + MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); + + /* align velocity too */ + + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + + dynPtr->LinImpulse.vx = dynPtr->OrientMat.mat31; + dynPtr->LinImpulse.vy = dynPtr->OrientMat.mat32; + dynPtr->LinImpulse.vz = dynPtr->OrientMat.mat33; + + dynPtr->LinImpulse.vx = MUL_FIXED(dynPtr->LinImpulse.vx, PredPistolBoltSpeed); + dynPtr->LinImpulse.vy = MUL_FIXED(dynPtr->LinImpulse.vy, PredPistolBoltSpeed); + dynPtr->LinImpulse.vz = MUL_FIXED(dynPtr->LinImpulse.vz, PredPistolBoltSpeed); + + dynPtr->UseStandardGravity=0; + dynPtr->GravityDirection.vx=0; + dynPtr->GravityDirection.vy=PredPistolBoltGravity; /* Half gravity! */ + dynPtr->GravityDirection.vz=0; + + dynPtr->StopOnCollision=1; + + if (player==0) { + dynPtr->IgnoreThePlayer=0; + } + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock); + #endif + return dispPtr->ObStrategyBlock; +} +#else +void CreatePPPlasmaBoltKernel(VECTORCH *position,MATRIXCH *orient, int player) +{ + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + + /* make displayblock with correct shape, etc */ + dispPtr = MakeObject(I_BehaviourPPPlasmaBolt,position); + if (dispPtr == 0) return; // Failed to allocate display block + + dispPtr->SfxPtr = AllocateSfxBlock(); + + if (!dispPtr->SfxPtr) + { + // Failed to allocate a special fx block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + + dispPtr->SfxPtr->SfxID = SFX_SMALL_PREDATOR_PLASMA_BOLT; + /* make displayblock a dynamic module object */ + dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + dispPtr->ObShape = 0; + dispPtr->ObStrategyBlock->shapeIndex = 0; + + /* add lighting effect */ + AddLightingEffectToObject(dispPtr,LFX_PLASMA_BOLT); + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* give missile a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK)); + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + + ((ONE_SHOT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED; + + /* align rocket to launcher */ + dynPtr->Position=*position; + dynPtr->PrevPosition=*position; + + /* align velocity too */ + dynPtr->OrientMat = *orient; + dynPtr->PrevOrientMat = dynPtr->OrientMat; + /* I added this next line for networking: Patrick */ + MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); + + /* align velocity too */ + #define PPBOLT_SPEED 32767 + dynPtr->LinVelocity.vx = dynPtr->OrientMat.mat31; + dynPtr->LinVelocity.vy = dynPtr->OrientMat.mat32; + dynPtr->LinVelocity.vz = dynPtr->OrientMat.mat33; + + dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx, PPBOLT_SPEED); + dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy, PPBOLT_SPEED); + dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz, PPBOLT_SPEED); + + if (player==0) { + dynPtr->IgnoreThePlayer=0; + } + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock); + #endif +} +#endif + +static void InitialisePPPlasmaBoltBehaviour(void) +{ + VECTORCH position; + + GLOBALASSERT(PWMFSDP); + + /* calculate the position */ + + position=PWMFSDP->World_Offset; + + #if NEAR_WEAPON_FUDGE + { + VECTORCH fudgeFactor; + extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + + fudgeFactor.vx=position.vx-Global_VDB_Ptr->VDB_World.vx; + fudgeFactor.vy=position.vy-Global_VDB_Ptr->VDB_World.vy; + fudgeFactor.vz=position.vz-Global_VDB_Ptr->VDB_World.vz; + + Crunch_Position_For_Players_Weapon(&fudgeFactor); + + position=fudgeFactor; + } + #endif + + CreatePPPlasmaBoltKernel(&position,&PlayersWeapon.ObMat,1); + +} + +#if NEW_PREDPISTOL_BOLT +extern void PPPlasmaBoltBehaviour(STRATEGYBLOCK *sbPtr) +{ + /* Now, kinda explosive. */ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + PREDPISTOL_BEHAV_BLOCK *bbPtr = (PREDPISTOL_BEHAV_BLOCK * ) sbPtr->SBdataptr; + int explodeNow=0; + + /* check for a collision with something */ + if (bbPtr->counter <= 0) + { + /* for net game support: send a message saying we've blown up... */ + explodeNow=1; + } + else if (reportPtr) + { + #if 1 + if(reportPtr->ObstacleSBPtr) { + VECTORCH attack_dir; + /* A bit more damage if it hits you? */ + + if (AccuracyStats_TargetFilter(reportPtr->ObstacleSBPtr)) { + if (bbPtr->player) { + int slot; + /* Log accuracy! */ + slot=SlotForThisWeapon(WEAPON_PRED_PISTOL); + if (slot!=-1) { + CurrentGameStats_WeaponHit(slot,1); + } + } + } + + GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir); + CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PREDPISTOL_STRIKE].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + #endif + explodeNow=1; + + } else { + bbPtr->counter -= NormalFrameTime; + } + + if (explodeNow) { + + HandleEffectsOfExplosion + ( + sbPtr, + &(dynPtr->Position), + TemplateAmmo[AMMO_PRED_PISTOL].MaxRange, + &TemplateAmmo[AMMO_PRED_PISTOL].MaxDamage[AvP.Difficulty], + TemplateAmmo[AMMO_PRED_PISTOL].ExplosionIsFlat + ); + + + #if 0 + MakeBloodExplosion(&dynPtr->Position,50,&dynPtr->Position,100,PARTICLE_PREDPISTOL_FLECHETTE); + #endif + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + DestroyAnyStrategyBlock(sbPtr); + } +} +#else +extern void PPPlasmaBoltBehaviour(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + ONE_SHOT_BEHAV_BLOCK *bbPtr = (ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr; + + /* check for a collision with something */ + if (bbPtr->counter <= 0) + { + /* for net game support: send a message saying we've blown up... */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + DestroyAnyStrategyBlock(sbPtr); /* timed-out */ + } + else if (reportPtr) + { + if(reportPtr->ObstacleSBPtr) { + VECTORCH attack_dir; + GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir); + CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_PISTOL].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + DestroyAnyStrategyBlock(sbPtr); + + } else { + bbPtr->counter -= NormalFrameTime; + } +} +#endif + +/****/ + +#define SPEAR_BOLT_SPEED (200000) +#define SPEAR_PLAYER_IMPULSE (-8000) +#define SPEAR_FUDGE_FACTOR (500) +/* Was 50000. */ + +static void InitialiseSpeargunBoltBehaviour(void) +{ + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + VECTORCH position; + + LOCALASSERT(0); // this routine should not be called + + GLOBALASSERT(PWMFSDP); + + position=PWMFSDP->World_Offset; + + /* make displayblock with correct shape, etc */ + dispPtr = MakeObject(I_BehaviourSpeargunBolt,&position); + if (dispPtr == 0) return; // Failed to allocate display block + + /* KJL 17:53:36 01/08/98 - make the extents teeny-weeny */ + dispPtr->ObMaxX = 10; + dispPtr->ObMaxY = 10; + dispPtr->ObMaxZ = 10; + dispPtr->ObMinX = -10; + dispPtr->ObMinY = -10; + dispPtr->ObMinZ = -10; + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* give missile a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(SPEAR_BEHAV_BLOCK)); + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + memset(dispPtr->ObStrategyBlock->SBdataptr,0,sizeof(SPEAR_BEHAV_BLOCK)); + + ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED; + ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->Stuck = 0; + /* Is this function still used? */ + ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->Android = 0; + + /* align rocket to launcher */ + dynPtr->Position=position; + #if NEAR_WEAPON_FUDGE + { + VECTORCH fudgeFactor; + extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + + fudgeFactor.vx=dynPtr->Position.vx-Global_VDB_Ptr->VDB_World.vx; + fudgeFactor.vy=dynPtr->Position.vy-Global_VDB_Ptr->VDB_World.vy; + fudgeFactor.vz=dynPtr->Position.vz-Global_VDB_Ptr->VDB_World.vz; + + Crunch_Position_For_Players_Weapon(&fudgeFactor); + + dynPtr->Position=fudgeFactor; + } + #endif + dynPtr->PrevPosition=position; + dynPtr->OrientMat = PlayersWeapon.ObMat; + dynPtr->PrevOrientMat = dynPtr->OrientMat; + /* align velocity too */ + + GetGunDirection(&(dynPtr->LinVelocity),&dynPtr->Position); + dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx,SPEAR_BOLT_SPEED); + dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy,SPEAR_BOLT_SPEED); + dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz,SPEAR_BOLT_SPEED); + + Player->ObStrategyBlock->DynPtr->LinImpulse.vx+=MUL_FIXED(PlayersWeapon.ObMat.mat31,SPEAR_PLAYER_IMPULSE); + Player->ObStrategyBlock->DynPtr->LinImpulse.vy+=MUL_FIXED(PlayersWeapon.ObMat.mat32,SPEAR_PLAYER_IMPULSE); + Player->ObStrategyBlock->DynPtr->LinImpulse.vz+=MUL_FIXED(PlayersWeapon.ObMat.mat33,SPEAR_PLAYER_IMPULSE); + + dynPtr->Mass=1000; + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock); + #endif +} + +static DISPLAYBLOCK* InitialiseSpeargunBoltBehaviour_ForLoad(void) +{ + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + VECTORCH position = {0,0,0}; + + + /* make displayblock with correct shape, etc */ + dispPtr = MakeObject(I_BehaviourSpeargunBolt,&position); + if (dispPtr == 0) return NULL; // Failed to allocate display block + + /* KJL 17:53:36 01/08/98 - make the extents teeny-weeny */ + dispPtr->ObMaxX = 10; + dispPtr->ObMaxY = 10; + dispPtr->ObMaxZ = 10; + dispPtr->ObMinX = -10; + dispPtr->ObMinY = -10; + dispPtr->ObMinZ = -10; + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* give missile a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(SPEAR_BEHAV_BLOCK)); + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + memset(dispPtr->ObStrategyBlock->SBdataptr,0,sizeof(SPEAR_BEHAV_BLOCK)); + return dispPtr; +} + + +extern void SpeargunBoltBehaviour(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + SPEAR_BEHAV_BLOCK *bbPtr = (SPEAR_BEHAV_BLOCK * ) sbPtr->SBdataptr; + + if (!bbPtr->Stuck) { + // MakeRocketTrailParticles(&(dynPtr->PrevPosition), &(dynPtr->Position)); + } else { + /* Stuck behaviour. */ + + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + + dynPtr->LinImpulse.vx = 0; + dynPtr->LinImpulse.vy = 0; + dynPtr->LinImpulse.vz = 0; + + bbPtr->counter -= NormalFrameTime; + if (bbPtr->counter <= 0) + { + /* for net game support: send a message saying we've blown up... */ + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + DestroyAnyStrategyBlock(sbPtr); /* timed-out */ + } + return; + } + + /* check for a collision with something */ + if (bbPtr->counter <= 0) + { + /* for net game support: send a message saying we've blown up... */ + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + DestroyAnyStrategyBlock(sbPtr); /* timed-out */ + } + else if (reportPtr) + { + int normDotBeta = DotProduct(&(dynPtr->LinVelocity),&(reportPtr->ObstacleNormal)); + char stickWhereYouAre = 0; + + if (reportPtr->ObstacleSBPtr) + { + DISPLAYBLOCK *dispPtr = reportPtr->ObstacleSBPtr->SBdptr; + if (dispPtr) + if (dispPtr->ObMyModule && (!dispPtr->ObMorphCtrl)) + { + stickWhereYouAre=1; + } + } + else + { + stickWhereYouAre = 1; + } + + if(stickWhereYouAre && normDotBeta!=0) + { + /* Sink in... */ + Sound_Play(SID_SPEARGUN_HITTING_WALL,"d",&dynPtr->Position); + // MakeImpactSparks(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal,&dynPtr->Position); + bbPtr->Stuck=1; + /* Counter at 20s. */ + bbPtr->counter=(20*ONE_FIXED); + dynPtr->GravityOn=0; + dynPtr->DynamicsType = DYN_TYPE_NO_COLLISIONS; + + { + int d; + { + /* get a pt in the poly */ + VECTORCH pop = reportPtr->ObstaclePoint; + pop.vx -= dynPtr->Position.vx; + pop.vy -= dynPtr->Position.vy; + pop.vz -= dynPtr->Position.vz; + + /* hmm, what about double sided polys? */ + d = DotProduct(&(reportPtr->ObstacleNormal),&pop); + } + + { + int lambda = DIV_FIXED(d,normDotBeta); + + dynPtr->Position.vx += MUL_FIXED(lambda,dynPtr->LinVelocity.vx); + dynPtr->Position.vy += MUL_FIXED(lambda,dynPtr->LinVelocity.vy); + dynPtr->Position.vz += MUL_FIXED(lambda,dynPtr->LinVelocity.vz); + } + + } + dynPtr->LinVelocity.vx=0; + dynPtr->LinVelocity.vy=0; + dynPtr->LinVelocity.vz=0; + dynPtr->LinImpulse.vx=0; + dynPtr->LinImpulse.vy=0; + dynPtr->LinImpulse.vz=0; + + MakeFocusedExplosion(&(dynPtr->PrevPosition), &(dynPtr->Position), 20, PARTICLE_SPARK); + + } + else + { + if(reportPtr->ObstacleSBPtr) + { + VECTORCH attack_dir; + GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir); + CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_RIFLE].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + DestroyAnyStrategyBlock(sbPtr); + } + } else { + /* No collisions. */ + //dynPtr->IgnoreThePlayer=0; + + bbPtr->counter -= NormalFrameTime; + } +} + +/****/ + +void Crunch_Position_For_Players_Weapon(VECTORCH *position) { + + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + + position->vx+=PlayersWeapon.ObWorld.vx - VDBPtr->VDB_World.vx; + position->vx = position->vx/4 + VDBPtr->VDB_World.vx; + + position->vy+=PlayersWeapon.ObWorld.vy - VDBPtr->VDB_World.vy; + position->vy = position->vy/4 + VDBPtr->VDB_World.vy; + + position->vz+=PlayersWeapon.ObWorld.vz - VDBPtr->VDB_World.vz; + position->vz = position->vz/4 + VDBPtr->VDB_World.vz; + +} + +void FireFlameThrower(VECTORCH *base_position,VECTORCH *base_offset,MATRIXCH *orientmat,int player, int *timer) { + + /* Simple function containing flamethrower function. */ + + VECTORCH position; + + (*timer)+=NormalFrameTime; + + while ((*timer)>=TIME_FOR_FLAMETHROWER_PARTICLE) + { + VECTORCH velocity; + + (*timer)-=TIME_FOR_FLAMETHROWER_PARTICLE; + + /* calculate the position */ + + { + int offset = MUL_FIXED(FastRandom()&16383,NormalFrameTime); + + position=*base_offset; + + position.vz += offset; + position.vy += (FastRandom()%(offset/8+1)) - offset/16; + position.vx += (FastRandom()%(offset/8+1)) - offset/16; + } + + RotateVector(&position,orientmat); + + if (player) { + Crunch_Position_For_Players_Weapon(&position); + } else { + position.vx+=base_position->vx; + position.vy+=base_position->vy; + position.vz+=base_position->vz; + } + + velocity.vx = ((FastRandom()&1023) - 512);//*2; + velocity.vy = ((FastRandom()&1023) - 512);//*2; + velocity.vz = ((FastRandom()&511) + 200+512)*16; + RotateVector(&velocity,orientmat); + MakeParticle(&position,&(velocity),PARTICLE_FLAME); + } + +} + +void FireNetGhostFlameThrower(VECTORCH *positionPtr, MATRIXCH *orientMatPtr) +{ + /* KJL 16:31:42 27/01/98 - these particles aren't colliding, so I'll + see what happens if I use more... */ + int i = FLAMETHROWER_PARTICLES_PER_FRAME*2; + + VECTORCH position; + + while(i--) + /* calculate the position */ + { + VECTORCH velocity; + + { + int offset = MUL_FIXED(FastRandom()&16383,NormalFrameTime); + + position.vz = offset; + position.vy = (FastRandom()%(offset/8+1)) - offset/16; + position.vx = (FastRandom()%(offset/8+1)) - offset/16; + } + + velocity.vx = ((FastRandom()&1023) - 512);//*2; + velocity.vy = ((FastRandom()&1023) - 512);//*2; + velocity.vz = ((FastRandom()&511) + 200+512)*16; + + RotateVector(&position,orientMatPtr); + RotateVector(&velocity,orientMatPtr); + + position.vx+=positionPtr->vx; + position.vy+=positionPtr->vy; + position.vz+=positionPtr->vz; + + if (LocalDetailLevels.GhostFlameThrowerCollisions==0) { + MakeParticle(&position,&(velocity),PARTICLE_NONCOLLIDINGFLAME); + } else { + MakeParticle(&position,&(velocity),PARTICLE_NONDAMAGINGFLAME); + } + } + +} + + +static void InitialiseFlameThrowerBehaviour(void) +{ + VECTORCH position; + +#if 1 + { + int i = FLAMETHROWER_PARTICLES_PER_FRAME; + while(i--) + /* calculate the position */ + { + extern VECTORCH CentreOfMuzzleOffset; + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + VECTORCH velocity; + + position = CentreOfMuzzleOffset; + + #if 1 + { + int offset = MUL_FIXED(FastRandom()&16383,NormalFrameTime); + position.vz += offset; + position.vy += (FastRandom()%(offset/8+1)) - offset/16; + position.vx += (FastRandom()%(offset/8+1)) - offset/16; + } + #endif + RotateVector(&position,&PlayersWeapon.ObMat); + + position.vx+=PlayersWeapon.ObWorld.vx - VDBPtr->VDB_World.vx; + position.vx = position.vx/4 + VDBPtr->VDB_World.vx; + + position.vy+=PlayersWeapon.ObWorld.vy - VDBPtr->VDB_World.vy; + position.vy = position.vy/4 + VDBPtr->VDB_World.vy; + + position.vz+=PlayersWeapon.ObWorld.vz - VDBPtr->VDB_World.vz; + position.vz = position.vz/4 + VDBPtr->VDB_World.vz; + + + + velocity.vx = ((FastRandom()&1023) - 512);//*2; + velocity.vy = ((FastRandom()&1023) - 512);//*2; + velocity.vz = ((FastRandom()&1023) + 200)*16; + RotateVector(&velocity,&(PlayersWeapon.ObMat)); + MakeParticle(&position,&(velocity),PARTICLE_FLAME); + } + } + #endif +} + +/*----------------------Patrick 4/3/97-------------------------- + Stuff for predator (and xenoborg) projectiles... + NB will need a creation function for player (AIs have their own) + --------------------------------------------------------------*/ +extern void PredatorEnergyBoltBehaviour(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + CASTER_BOLT_BEHAV_BLOCK *bbPtr = (CASTER_BOLT_BEHAV_BLOCK * ) sbPtr->SBdataptr; + STRATEGYBLOCK *victim; + + victim=NULL; + + if (bbPtr->damage.Impact) { + MakePlasmaTrailParticles(dynPtr,bbPtr->damage.Impact); + } else if(bbPtr->damage.Id==AMMO_SADAR_TOW) { + MakePlasmaTrailParticles(dynPtr,100); + } + + /* check for a collision with something */ + if (bbPtr->counter <= 0) + { + /* for net game support: send a message saying we've blown up... */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + DestroyAnyStrategyBlock(sbPtr); /* timed-out */ + } + else if (reportPtr) + { + if(reportPtr->ObstacleSBPtr) + { + VECTORCH attack_dir; + + if (AccuracyStats_TargetFilter(reportPtr->ObstacleSBPtr)) { + if (bbPtr->player) { + int slot; + /* Log accuracy! */ + slot=SlotForThisWeapon(WEAPON_PRED_SHOULDERCANNON); + if (slot!=-1) { + CurrentGameStats_WeaponHit(slot,1); + } + } + } + + GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir); + + switch (reportPtr->ObstacleSBPtr->I_SBtype) + { + case I_BehaviourMarine: + case I_BehaviourAlien: + { + SECTION_DATA *chest_section=0; + DISPLAYBLOCK *objectPtr = reportPtr->ObstacleSBPtr->SBdptr; + + if(objectPtr) + { + SECTION_DATA *firstSectionPtr; + + firstSectionPtr=objectPtr->HModelControlBlock->section_data; + LOCALASSERT(firstSectionPtr); + LOCALASSERT(firstSectionPtr->flags§ion_data_initialised); + + /* look for the object's torso in preference */ + chest_section =GetThisSectionData(objectPtr->HModelControlBlock->section_data,"chest"); + + if (chest_section) + { + VECTORCH rel_pos; + + rel_pos=dynPtr->Position; + + rel_pos.vx-=chest_section->World_Offset.vx; + rel_pos.vy-=chest_section->World_Offset.vy; + rel_pos.vz-=chest_section->World_Offset.vz; + + Normalise(&rel_pos); + + if (reportPtr->ObstacleSBPtr->I_SBtype==I_BehaviourAlien) { + /* Spherical BloodExplosion for aliens. Under protest. Bleagh. */ + CauseDamageToHModel(objectPtr->HModelControlBlock,reportPtr->ObstacleSBPtr,&bbPtr->damage, ONE_FIXED, chest_section,NULL,&chest_section->World_Offset,0); + } else { + CauseDamageToHModel(objectPtr->HModelControlBlock,reportPtr->ObstacleSBPtr,&bbPtr->damage, ONE_FIXED, chest_section,&rel_pos,&chest_section->World_Offset,0); + } + } + else + { + CauseDamageToObject(reportPtr->ObstacleSBPtr,&bbPtr->damage, ONE_FIXED,NULL); + } + victim=reportPtr->ObstacleSBPtr; + } + + break; + } + default: + { + CauseDamageToObject(reportPtr->ObstacleSBPtr,&bbPtr->damage, ONE_FIXED,NULL); + victim=reportPtr->ObstacleSBPtr; + break; + } + } + } + + { + char hitEnvironment = 0; + + if (reportPtr->ObstacleSBPtr) + { + DISPLAYBLOCK *dispPtr = reportPtr->ObstacleSBPtr->SBdptr; + if (dispPtr) + if (dispPtr->ObMyModule) + { + hitEnvironment=1; + } + } + else + { + hitEnvironment = 1; + } + + #if 0 + MakeParticle(&(dynPtr->Position),&(dynPtr->Position),PARTICLE_BLUEPLASMASPHERE); + MakeLightElement(&dynPtr->Position,LIGHTELEMENT_PLASMACASTERHIT); + if(hitEnvironment) + { + MakeBloodExplosion(&(dynPtr->PrevPosition), 127, &(dynPtr->Position), 200, PARTICLE_ORANGE_SPARK); + Sound_Play(SID_PLASMABOLT_DISSIPATE,"d",&(dynPtr->Position)); + } + else + { + MakeFocusedExplosion(&(dynPtr->PrevPosition), &(dynPtr->Position), 100, PARTICLE_ORANGE_PLASMA); + Sound_Play(SID_PLASMABOLT_HIT,"d",&(dynPtr->Position)); +// Sound_Play(SID_BLOOD_SPLASH,"d",&(dynPtr->Position)); + } + #endif + if (hitEnvironment) + { + MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_DISSIPATINGPLASMA); + if (AvP.Network != I_No_Network) AddNetMsg_MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_DISSIPATINGPLASMA); + } + else + { + MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_FOCUSEDPLASMA); + if (AvP.Network != I_No_Network) AddNetMsg_MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_FOCUSEDPLASMA); + } + } + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + /* Splash damage? */ + HandleEffectsOfExplosion + ( + victim, + &(dynPtr->Position), + bbPtr->blast_radius, + &bbPtr->damage, + 0 + ); + DestroyAnyStrategyBlock(sbPtr); + } else { + { + VECTORCH direction; + direction.vx = dynPtr->LinVelocity.vx + dynPtr->LinImpulse.vx; + direction.vy = dynPtr->LinVelocity.vy + dynPtr->LinImpulse.vy; + direction.vz = dynPtr->LinVelocity.vz + dynPtr->LinImpulse.vz; + Normalise(&direction); + MakeMatrixFromDirection(&direction,&dynPtr->OrientMat); + } + bbPtr->counter -= NormalFrameTime; + } + + + +} + +extern void XenoborgEnergyBoltBehaviour(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + ONE_SHOT_BEHAV_BLOCK *bbPtr = (ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr; + + /* check for a collision with something */ + if (bbPtr->counter <= 0) + { + /* for net game support: send a message saying we've blown up... */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + DestroyAnyStrategyBlock(sbPtr); /* timed-out */ + } + else if (reportPtr) + { + if(reportPtr->ObstacleSBPtr) + CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_XENOBORG].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + DestroyAnyStrategyBlock(sbPtr); + } + else bbPtr->counter -= NormalFrameTime; +} + +#define DISC_SPEED 30000 //5000 +#define DISC_LIFETIME (10*ONE_FIXED) +#define DISC_FREETIME (1*ONE_FIXED) +#define DISC_MAX_BOUNCES (10) + +void InitialiseDiscBehaviour(STRATEGYBLOCK *target,SECTION_DATA *disc_section) { + + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + PC_PRED_DISC_BEHAV_BLOCK *bblk; + int a; + + GLOBALASSERT(disc_section); + + /* make displayblock with correct shape, etc */ + dispPtr = MakeObject(I_BehaviourPredatorDisc_SeekTrack,&disc_section->World_Offset); + + if (dispPtr == 0) return; // Failed to allocate display block + + /* make displayblock a dynamic module object */ + dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* Stats! */ + dispPtr->ObStrategyBlock->SBDamageBlock.Health=100<ObStrategyBlock->SBDamageBlock.Armour=100<ObStrategyBlock->SBDamageBlock.SB_H_flags.AcidResistant=0; + dispPtr->ObStrategyBlock->SBDamageBlock.SB_H_flags.FireResistant=0; + dispPtr->ObStrategyBlock->SBDamageBlock.SB_H_flags.ElectricResistant=0; + dispPtr->ObStrategyBlock->SBDamageBlock.SB_H_flags.PerfectArmour=0; + dispPtr->ObStrategyBlock->SBDamageBlock.SB_H_flags.ElectricSensitive=0; + dispPtr->ObStrategyBlock->SBDamageBlock.SB_H_flags.Indestructable=1; + + { + /* align rocket to launcher */ + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + MATRIXCH matrix = VDBPtr->VDB_Mat; + + if (PlayersTarget.Distance<1400) { + /* Yuck! */ + dynPtr->Position=Global_VDB_Ptr->VDB_World; + /* Nudge down a wee tad bit. */ + dynPtr->Position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat21,200); + dynPtr->Position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat22,200); + dynPtr->Position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat23,200); + + dynPtr->Position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat11,200); + dynPtr->Position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat12,200); + dynPtr->Position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat13,200); + + } else { + dynPtr->Position=disc_section->World_Offset; + } + + + dynPtr->PrevPosition = dynPtr->Position; + TransposeMatrixCH(&matrix); + /* dynPtr->OrientMat = Player->ObMat; */ + dynPtr->OrientMat = matrix; + dynPtr->PrevOrientMat = dynPtr->OrientMat; + /* I added this next line for networking: Patrick */ + MatrixToEuler(&matrix, &PlayersWeapon.ObEuler); + + dynPtr->OrientEuler.EulerX=PlayersWeapon.ObEuler.EulerX; + dynPtr->OrientEuler.EulerY=PlayersWeapon.ObEuler.EulerY; + dynPtr->OrientEuler.EulerZ=PlayersWeapon.ObEuler.EulerZ; + + /* align velocity too */ + dynPtr->LinVelocity.vx = MUL_FIXED(matrix.mat31,DISC_SPEED); + dynPtr->LinVelocity.vy = MUL_FIXED(matrix.mat32,DISC_SPEED); + dynPtr->LinVelocity.vz = MUL_FIXED(matrix.mat33,DISC_SPEED); + + } + + /* give missile a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(PC_PRED_DISC_BEHAV_BLOCK)); + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + + bblk=(PC_PRED_DISC_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr; + if (target) { + bblk->counter = DISC_LIFETIME; + } else { + bblk->counter = DISC_FREETIME; + } + bblk->bounces=0; + bblk->Destruct=0; + bblk->Stuck=0; + bblk->Bounced=0; + bblk->soundHandle = SOUND_NOACTIVEINDEX; + for (a=0; aPrev_Target_SBname[a]='\0'; + bblk->Prev_Damaged_SBname[a]='\0'; + } + bblk->Target=target; + + if (bblk->Target) { + COPY_NAME(bblk->Prev_Target_SBname,bblk->Target_SBname); + COPY_NAME(bblk->Target_SBname,bblk->Target->SBname); + } else { + for (a=0; aTarget_SBname[a]='\0'; + } + } + + /* Create HModel. */ + { + SECTION *root_section; + SECTION_DATA *local_disc; + + root_section=GetNamedHierarchyFromLibrary("disk","Disk"); + + GLOBALASSERT(root_section); + + Create_HModel(&bblk->HModelController,root_section); + InitHModelSequence(&bblk->HModelController,HMSQT_MarineStand,MSSS_Minigun_Delta,ONE_FIXED); + + ProveHModel(&bblk->HModelController,dispPtr); + + dispPtr->HModelControlBlock=&bblk->HModelController; + + /* Match disks. */ + local_disc=GetThisSectionData(bblk->HModelController.section_data,"disk"); + local_disc->World_Offset=disc_section->World_Offset; + local_disc->SecMat=disc_section->SecMat; + InitHModelTweening(&bblk->HModelController,(ONE_FIXED>>2),HMSQT_MarineStand,MSSS_Minigun_Delta,ONE_FIXED,1); + } + + /* for net game support */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) { + AddNetGameObjectID(dispPtr->ObStrategyBlock); + } + #endif +} + +/* +Function only does minimal disc setup , the rest will be done by the load function +*/ +static STRATEGYBLOCK* InitialiseDiscBehaviour_ForLoad() { + VECTORCH zeroVect = {0,0,0}; + + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + PC_PRED_DISC_BEHAV_BLOCK *bblk; + int a; + + + /* make displayblock with correct shape, etc */ + dispPtr = MakeObject(I_BehaviourPredatorDisc_SeekTrack,&zeroVect); + + if (dispPtr == 0) return NULL; // Failed to allocate display block + + /* make displayblock a dynamic module object */ + dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + + /* give missile a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr = AllocateMem(sizeof(PC_PRED_DISC_BEHAV_BLOCK)); + bblk = dispPtr->ObStrategyBlock->SBdataptr; + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + memset(dispPtr->ObStrategyBlock->SBdataptr,0,sizeof(PC_PRED_DISC_BEHAV_BLOCK)); + + bblk->soundHandle = SOUND_NOACTIVEINDEX; + + dispPtr->HModelControlBlock=&bblk->HModelController; + + + return dispPtr->ObStrategyBlock; +} + +extern void NPCDiscBehaviour(STRATEGYBLOCK *sbPtr) +{ + /* I have change this: mainly because npc preds fire them too... patrick */ + #if 0 + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + ONE_SHOT_BEHAV_BLOCK *bbPtr = (ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr; + int destruct; + + destruct=0; + + while (reportPtr) { + + if (reportPtr->ObstacleSBPtr!=Player->ObStrategyBlock) { + + if (reportPtr->ObstacleSBPtr==NULL) + { + destruct=1; + } + else + { + CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + + } + reportPtr=reportPtr->NextCollisionReportPtr; + } + + if (destruct || (bbPtr->counter<=0) ) + { + /* KJL 17:51:56 12/17/96 - make explosion damage other objects */ + HandleEffectsOfExplosion + ( + sbPtr, + &(dynPtr->Position), + TemplateAmmo[AMMO_PRED_DISC].MaxRange, + &TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], + TemplateAmmo[AMMO_PRED_DISC].ExplosionIsFlat + ); + + Sound_Play(SID_EXPLOSION,"d",&(dynPtr->Position)); + + + /* for net game support: send a message saying we've blown up... */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + + /* destroy rocket */ + DestroyAnyStrategyBlock(sbPtr); + + } + else + { + bbPtr->counter-=NormalFrameTime; + } + #endif + + + + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + ONE_SHOT_BEHAV_BLOCK *bbPtr = (ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr; + + /* check for a collision with something */ + if(bbPtr->counter <= 0) + { + /* for net game support: send a message saying we've blown up... */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + DestroyAnyStrategyBlock(sbPtr); /* timed-out */ + } + else if(reportPtr) + { + if(reportPtr->ObstacleSBPtr) + { + if(!((reportPtr->ObstacleSBPtr==Player->ObStrategyBlock)&&(AvP.PlayerType==I_Predator))) { + CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + DestroyAnyStrategyBlock(sbPtr); + } else { + bbPtr->counter -= NormalFrameTime; + } +} + + +static void InitialiseAlienSpitBehaviour(void) +{ + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + VECTORCH position; + int numGlobules; + + /* calculate the position */ + { +// position=PlayersWeapon.ObWorld; + /* KJL 12:31:39 8/11/97 - the spit was being created to far in front + of the player */ + position=Player->ObWorld; + } + + #define NUM_ALIENSPITGLOBULES 7 + for(numGlobules=0;numGlobulesObFlags3 |= ObFlag3_DynamicModuleObject; + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* spit does not collide with other spit */ + dynPtr->IgnoreSameObjectsAsYou = 1; + + /* give missile a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK)); + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return; + } + + ((ONE_SHOT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED; + + /* align rocket to launcher */ + dynPtr->Position=position; + /* align rocket to launcher */ + { + #define SPIT_SPEED 10000 + #define SPIT_SPREAD 340 + + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + MATRIXCH spitDirn; + EULER spitOffset; + + dynPtr->OrientMat = VDBPtr->VDB_Mat; + TransposeMatrixCH(&dynPtr->OrientMat); + + spitOffset.EulerX = (FastRandom()%(SPIT_SPREAD<<1))-SPIT_SPREAD; + if(spitOffset.EulerX<0) spitOffset.EulerX += 4096; + spitOffset.EulerY = (FastRandom()%(SPIT_SPREAD<<1))-SPIT_SPREAD; + if(spitOffset.EulerY<0) spitOffset.EulerY += 4096; + spitOffset.EulerZ = 0; + + CreateEulerMatrix(&spitOffset, &spitDirn); + TransposeMatrixCH(&spitDirn); + MatrixMultiply(&dynPtr->OrientMat,&spitDirn,&dynPtr->OrientMat); + + /* align velocity to z axis */ + dynPtr->PrevOrientMat = dynPtr->OrientMat; + dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->OrientMat.mat31,SPIT_SPEED)+ + Player->ObStrategyBlock->DynPtr->LinVelocity.vx+ + Player->ObStrategyBlock->DynPtr->LinImpulse.vx; + dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->OrientMat.mat32,SPIT_SPEED)+ + Player->ObStrategyBlock->DynPtr->LinVelocity.vy+ + Player->ObStrategyBlock->DynPtr->LinImpulse.vy; + dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->OrientMat.mat33,SPIT_SPEED)+ + Player->ObStrategyBlock->DynPtr->LinVelocity.vz+ + Player->ObStrategyBlock->DynPtr->LinImpulse.vz; + + /* dynamics blocks flags */ + dynPtr->GravityOn = 1; + + } + /* I added this next line for networking: Patrick */ + MatrixToEuler(&PlayersWeapon.ObMat, &PlayersWeapon.ObEuler); + + /* for net game support */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock); + #endif + } +} + +extern void AlienSpitBehaviour(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + ONE_SHOT_BEHAV_BLOCK *bbPtr = (ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr; + + if (bbPtr->counter<=0) + { + /* for net game support: send a message saying we've blown up... */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + + /* destroy rocket */ + DestroyAnyStrategyBlock(sbPtr); + } + else if (reportPtr) + { + STRATEGYBLOCK *hitSBPtr = reportPtr->ObstacleSBPtr; + + /* ignore hitting another spit or aliens */ + if(hitSBPtr) + { + if(!((hitSBPtr->I_SBtype==I_BehaviourAlienSpit) + ||(hitSBPtr->I_SBtype==I_BehaviourAlien) + ||(hitSBPtr==Player->ObStrategyBlock) ) ) + CauseDamageToObject(hitSBPtr,&TemplateAmmo[AMMO_ALIEN_SPIT].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + + Sound_Play(SID_PRED_NEWROAR,"d",&(dynPtr->Position)); + + /* for net game support: send a message saying we've blown up... */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + /* destroy rocket */ + DestroyAnyStrategyBlock(sbPtr); + } + else + { + bbPtr->counter-=NormalFrameTime; + } +} + + +static void GetGunDirection(VECTORCH *gunDirectionPtr, VECTORCH *positionPtr) +{ + gunDirectionPtr->vx = PlayersTarget.Position.vx - positionPtr->vx; + gunDirectionPtr->vy = PlayersTarget.Position.vy - positionPtr->vy; + gunDirectionPtr->vz = PlayersTarget.Position.vz - positionPtr->vz; + Normalise(gunDirectionPtr); +} + +int Reflect(VECTORCH *Incident, VECTORCH *Normal, EULER *Output) { + + int dot,retval; + VECTORCH outVec,normInc; + MATRIXCH tempMat; + /* Ah, the wonders of better math support. */ + + GLOBALASSERT(Incident); + GLOBALASSERT(Normal); + GLOBALASSERT(Output); + + normInc=*Incident; + Normalise(&normInc); + retval = DotProduct(&normInc,Normal); + /* Hold that thought. */ + dot = retval*(-2); + /* Yeah, okay, and a better algorithm. */ + outVec.vx = (normInc.vx + MUL_FIXED(dot,Normal->vx)); + outVec.vy = (normInc.vy + MUL_FIXED(dot,Normal->vy)); + outVec.vz = (normInc.vz + MUL_FIXED(dot,Normal->vz)); + + MakeMatrixFromDirection(&outVec,&tempMat); + MatrixToEuler(&tempMat,Output); + /* But bear in mind, most of the early one was coping with * + * bad functions and junk inputs... that's my excuse. */ + + return(retval); +} + +int SBForcesBounce(STRATEGYBLOCK *sbPtr) { + + if (sbPtr==NULL) { + return(0); + } + + /* Now switch by type. */ + switch (sbPtr->I_SBtype) { + case I_BehaviourInanimateObject: + { + INANIMATEOBJECT_STATUSBLOCK* objectStatusPtr; + objectStatusPtr=(INANIMATEOBJECT_STATUSBLOCK *)sbPtr->SBdataptr; + GLOBALASSERT(objectStatusPtr); + if (objectStatusPtr->Indestructable) { + return(1); + } else { + return(0); + } + } + break; + case I_BehaviourProximityDoor: + case I_BehaviourTrackObject: + case I_BehaviourLiftDoor: + case I_BehaviourSwitchDoor: + case I_BehaviourLinkSwitch: + case I_BehaviourBinarySwitch: + case I_BehaviourLift: + case I_BehaviourPlatform: + case I_BehaviourPredatorDisc_SeekTrack: + return(1); + break; + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *dataptr; + dataptr=sbPtr->SBdataptr; + switch (dataptr->type) { + case I_BehaviourPredatorDisc_SeekTrack: + return(1); + break; + default: + return(0); + break; + } + } + break; + default: + return(0); + break; + } + + return(0); +} + +int SBIsEnvironment(STRATEGYBLOCK *sbPtr) { + + if (sbPtr==NULL) { + return(1); + } + + if (sbPtr->SBdptr) { + if (sbPtr->SBdptr->ObMyModule) { + return(1); + } + } + + return(0); +} + +void Frisbee_Hit_Environment(STRATEGYBLOCK *sbPtr,COLLISIONREPORT *reportPtr) { + + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + FRISBEE_BEHAV_BLOCK *fbPtr = (FRISBEE_BEHAV_BLOCK * ) sbPtr->SBdataptr; + MATRIXCH mat; + + /* Hit the environment. Bounce? */ + int dp; + + dp=Reflect(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal, &dynPtr->OrientEuler); + dynPtr->OrientEuler.EulerZ=0; + dynPtr->IgnoreThePlayer=0; + + /* Always bounce. Reference Disc_Hit_Environment for sticking conditions. */ + MakeImpactSparks(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal,&dynPtr->Position); + Sound_Play(SID_ED_SKEETERDISC_HITWALL,"dp",&(dynPtr->Position),((FastRandom()&511)-255)); + + CreateEulerMatrix(&dynPtr->OrientEuler, &mat); + TransposeMatrixCH(&mat); + + dynPtr->OrientMat=mat; + + dynPtr->LinVelocity.vx = MUL_FIXED(mat.mat31,FRISBEE_SPEED); + dynPtr->LinVelocity.vy = MUL_FIXED(mat.mat32,FRISBEE_SPEED); + dynPtr->LinVelocity.vz = MUL_FIXED(mat.mat33,FRISBEE_SPEED); + + dynPtr->LinImpulse.vx=0; + dynPtr->LinImpulse.vy=0; + dynPtr->LinImpulse.vz=0; + + /* + Record that the disc has bounced - for use in network game + */ + fbPtr->Bounced=1; + fbPtr->bounces++; + +} + +void Disc_Hit_Environment(STRATEGYBLOCK *sbPtr,COLLISIONREPORT *reportPtr) { + + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + PC_PRED_DISC_BEHAV_BLOCK *bbPtr = (PC_PRED_DISC_BEHAV_BLOCK * ) sbPtr->SBdataptr; + MATRIXCH mat; + + /* Hit the environment. Bounce? */ + int dp; + + dp=Reflect(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal, &dynPtr->OrientEuler); + dynPtr->OrientEuler.EulerZ=0; + dynPtr->IgnoreThePlayer=0; + + if ((dp>-46341)&&(bbPtr->counter>0)&&(bbPtr->bounces<=DISC_MAX_BOUNCES)) { /* 65536/Rt2 */ + /* Bounce. */ + MakeImpactSparks(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal,&dynPtr->Position); + Sound_Play(SID_PREDATOR_DISK_HITTING_WALL,"dp",&(dynPtr->Position),((FastRandom()&511)-255)); + /* + Record that the disc has bounced - for use in network game + */ + bbPtr->Bounced=1; + bbPtr->bounces++; + } else { + CreateEulerMatrix(&dynPtr->OrientEuler, &mat); + TransposeMatrixCH(&mat); + /* very steep angle (or very long flight!) - stick. */ + bbPtr->Stuck=1; + bbPtr->HModelController.Playing=0; + MakeSprayOfSparks(&mat,&dynPtr->Position); + Sound_Stop(bbPtr->soundHandle); + Sound_Play(SID_DISC_STICKSINWALL,"dp",&(dynPtr->Position),((FastRandom()&511)-255)); + } + + if (bbPtr->Target==NULL) { + /* No target, so come home. */ + bbPtr->Target=Player->ObStrategyBlock; + COPY_NAME(bbPtr->Target_SBname,bbPtr->Target->SBname); + } + +} + +extern void DiscBehaviour_SeekTrack(STRATEGYBLOCK *sbPtr) +{ + + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + PC_PRED_DISC_BEHAV_BLOCK *bbPtr = (PC_PRED_DISC_BEHAV_BLOCK * ) sbPtr->SBdataptr; + MATRIXCH mat; + int getadisc; + + textprint("Disc active!\n"); + + ProveHModel_Far(&bbPtr->HModelController,sbPtr); + + if (sbPtr->SBDamageBlock.IsOnFire) { + sbPtr->SBDamageBlock.IsOnFire=0; + } + + /* Update target */ + if (bbPtr->Stuck) { + /* No business doing anything. */ + #if 0 + bbPtr->HModelController.Playing=0; + if (sbPtr->SBdptr) { + sbPtr->SBdptr->ObFlags3 &= ~ObFlag3_DynamicModuleObject; + } + #else + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + + dynPtr->LinImpulse.vx = 0; + dynPtr->LinImpulse.vy = 0; + dynPtr->LinImpulse.vz = 0; + + Sound_Stop(bbPtr->soundHandle); + /* Are we inside the player? */ + { + extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + VECTORCH offset; + int dist; + + offset=Global_VDB_Ptr->VDB_World; + offset.vx-=dynPtr->Position.vx; + offset.vy-=dynPtr->Position.vy; + offset.vz-=dynPtr->Position.vz; + + dist=Approximate3dMagnitude(&offset); + + if (dist<600) { + /* My, that's close. */ + PLAYER_STATUS *psptr; + int a; + psptr=(PLAYER_STATUS *)Player->ObStrategyBlock->SBdataptr; + for (a=0; aWeaponSlot[a].WeaponIDNumber==WEAPON_PRED_DISC) { + break; + } + } + if (a!=MAX_NO_OF_WEAPON_SLOTS) { + + if ((psptr->WeaponSlot[a].PrimaryMagazinesRemaining==0) + && (psptr->WeaponSlot[a].PrimaryRoundsRemaining==0)) { + //psptr->WeaponSlot[a].PrimaryRoundsRemaining+=ONE_FIXED; + psptr->WeaponSlot[a].PrimaryMagazinesRemaining+=1; + /* Autoswap to disc here? */ + AutoSwapToDisc(); + } else { + psptr->WeaponSlot[a].PrimaryMagazinesRemaining+=1; + } + + #if 0 + NewOnScreenMessage("CAUGHT DISC"); + #endif + + Sound_Stop(bbPtr->soundHandle); + Sound_Play(SID_PREDATOR_DISK_BEING_CAUGHT,"h"); + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + DestroyAnyStrategyBlock(sbPtr); + + return; + } + } + } + /* Just to make sure... */ + Convert_Disc_To_Pickup(sbPtr); + return; + #endif + } else if (bbPtr->Target==Player->ObStrategyBlock) { + VECTORCH targetPos; + /* Home on the player. */ + textprint("Disc homing on player.\n"); + GetTargetingPointOfObject_Far(bbPtr->Target,&targetPos); + if (bbPtr->counter>0) { + EulerAnglesHoming(&dynPtr->Position,&targetPos,&dynPtr->OrientEuler,4); + } else { + textprint("Disc super homing!\n"); + EulerAnglesHoming(&dynPtr->Position,&targetPos,&dynPtr->OrientEuler,2); + } + } else if (bbPtr->Target) { + /* We have a target. */ + textprint("Disc homing on target.\n"); + if (NAME_ISEQUAL(bbPtr->Target_SBname,bbPtr->Target->SBname)) { + if (!NPC_IsDead(bbPtr->Target)) { + /* Our target lives! */ + VECTORCH targetPos; + GLOBALASSERT(bbPtr->Target->DynPtr); + GetTargetingPointOfObject_Far(bbPtr->Target,&targetPos); + EulerAnglesHoming(&dynPtr->Position,&targetPos,&dynPtr->OrientEuler,4); + } else { + /* Target dying - unset. */ + bbPtr->Target=NULL; + } + } else { + /* Target no longer valid - unset. */ + bbPtr->Target=NULL; + } + } else { + /* No target. Oh well... */ + textprint("Disc in free flight.\n"); + } + + if (bbPtr->Stuck==0) { + /* We must be flying. Maintain sound. */ + if(bbPtr->soundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Update3d(bbPtr->soundHandle,&(sbPtr->DynPtr->Position)); + if (ActiveSounds[bbPtr->soundHandle].soundIndex!=SID_PREDATOR_DISK_FLYING) { + Sound_Stop(bbPtr->soundHandle); + Sound_Play(SID_PREDATOR_DISK_FLYING,"del",&(sbPtr->DynPtr->Position),&bbPtr->soundHandle); + } + } else { + Sound_Play(SID_PREDATOR_DISK_FLYING,"del",&(sbPtr->DynPtr->Position),&bbPtr->soundHandle); + } + } + + /* check for a collision with something */ + if(bbPtr->counter <= 0) + { + #if 0 + /* for net game support: send a message saying we've blown up... */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + DestroyAnyStrategyBlock(sbPtr); /* timed-out */ + return; + #else + /* For now, do nothing... */ + if (bbPtr->counter<-DISC_LIFETIME) { + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + DestroyAnyStrategyBlock(sbPtr); /* timed-out */ + return; + } + #endif + } + + getadisc=0; + /* To make sure you can't get multiple discs back! */ + + while (reportPtr) { + /* Should be while? */ + if(reportPtr->ObstacleSBPtr) + { + /* Hit a strategyblock. */ + + if (bbPtr->Stuck) { + /* Don't hurt anyone. */ + if ((reportPtr->ObstacleSBPtr==Player->ObStrategyBlock)&&(AvP.PlayerType==I_Predator)) { + /* Hit the owner. Recover it! */ + PLAYER_STATUS *psptr; + int a; + psptr=(PLAYER_STATUS *)Player->ObStrategyBlock->SBdataptr; + for (a=0; aWeaponSlot[a].WeaponIDNumber==WEAPON_PRED_DISC) { + break; + } + } + if (a!=MAX_NO_OF_WEAPON_SLOTS) { + + getadisc=1; + + #if 0 + NewOnScreenMessage("RECOVERED DISC"); + #endif + + Sound_Stop(bbPtr->soundHandle); + Sound_Play(SID_PREDATOR_DISK_RECOVERED,"h"); + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + DestroyAnyStrategyBlock(sbPtr); + + } + } + } else if(!((reportPtr->ObstacleSBPtr==Player->ObStrategyBlock)&&(AvP.PlayerType==I_Predator))) { + + /* Hit a random strategyblock - what is it? */ + if (SBForcesBounce(reportPtr->ObstacleSBPtr)) { + + /* Bounce. */ + Reflect(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal, &dynPtr->OrientEuler); + dynPtr->OrientEuler.EulerZ=0; + dynPtr->IgnoreThePlayer=0; + MakeImpactSparks(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal,&dynPtr->Position); + Sound_Play(SID_PREDATOR_DISK_HITTING_WALL,"dp",&(dynPtr->Position),((FastRandom()&511)-255)); + bbPtr->bounces++; + + /* + Record that the disc has bounced - for use in network game + */ + bbPtr->Bounced=1; + + } else if (SBIsEnvironment(reportPtr->ObstacleSBPtr)) { + Disc_Hit_Environment(sbPtr,reportPtr); + } else { + /* Hit a creature? */ + SECTION_DATA *hit_section; + VECTORCH attack_dir; + + dynPtr->IgnoreThePlayer=0; + /* To make sure. */ + + hit_section=NULL; + + GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir); + + switch (reportPtr->ObstacleSBPtr->I_SBtype) + { + case I_BehaviourMarine: + case I_BehaviourAlien: + { + SECTION_DATA *chest_section=0; + DISPLAYBLOCK *objectPtr = reportPtr->ObstacleSBPtr->SBdptr; + + if(objectPtr) + { + SECTION_DATA *firstSectionPtr; + + firstSectionPtr=objectPtr->HModelControlBlock->section_data; + LOCALASSERT(firstSectionPtr); + LOCALASSERT(firstSectionPtr->flags§ion_data_initialised); + + /* look for the object's torso in preference */ + chest_section =GetThisSectionData(objectPtr->HModelControlBlock->section_data,"chest"); + + if (chest_section) + { + VECTORCH rel_pos; + + rel_pos=dynPtr->Position; + + rel_pos.vx-=chest_section->World_Offset.vx; + rel_pos.vy-=chest_section->World_Offset.vy; + rel_pos.vz-=chest_section->World_Offset.vz; + + Normalise(&rel_pos); + + CauseDamageToHModel(objectPtr->HModelControlBlock,reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED, chest_section,&rel_pos,&chest_section->World_Offset,0); + } + else + { + CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + } + } + break; + } + case I_BehaviourAutoGun: + case I_BehaviourXenoborg: + { + /* Spark a bit? */ + CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + break; + } + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *dataptr; + dataptr=reportPtr->ObstacleSBPtr->SBdataptr; + switch (dataptr->type) { + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + /* Maybe a different damage here? */ + CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + break; + default: + CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + break; + } + } + break; + default: + { + CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL); + break; + } + } + + Sound_Play(SID_PREDATOR_DISK_HITTING_TARGET,"dp",&(dynPtr->Position),((FastRandom()&511)-255)); + + if (NAME_ISEQUAL(reportPtr->ObstacleSBPtr->SBname,bbPtr->Target_SBname)) { + /* Got him! Seek the player. */ + bbPtr->Target=Player->ObStrategyBlock; + bbPtr->counter = DISC_LIFETIME; + COPY_NAME(bbPtr->Target_SBname,bbPtr->Target->SBname); + } + } + } else { + /* Hit the owner. Catch it! */ + PLAYER_STATUS *psptr; + int a; + psptr=(PLAYER_STATUS *)Player->ObStrategyBlock->SBdataptr; + for (a=0; aWeaponSlot[a].WeaponIDNumber==WEAPON_PRED_DISC) { + break; + } + } + if (a!=MAX_NO_OF_WEAPON_SLOTS) { + + getadisc=1; + + #if 0 + NewOnScreenMessage("CAUGHT DISC"); + #endif + + Sound_Stop(bbPtr->soundHandle); + Sound_Play(SID_PREDATOR_DISK_BEING_CAUGHT,"h"); + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + DestroyAnyStrategyBlock(sbPtr); + + } + } + } else { + Disc_Hit_Environment(sbPtr,reportPtr); + } + + /* skip to next report */ + reportPtr = reportPtr->NextCollisionReportPtr; + + } + + if (getadisc) { + PLAYER_STATUS *psptr; + int a; + psptr=(PLAYER_STATUS *)Player->ObStrategyBlock->SBdataptr; + for (a=0; aWeaponSlot[a].WeaponIDNumber==WEAPON_PRED_DISC) { + break; + } + } + if (a!=MAX_NO_OF_WEAPON_SLOTS) { + + if ((psptr->WeaponSlot[a].PrimaryMagazinesRemaining==0) + && (psptr->WeaponSlot[a].PrimaryRoundsRemaining==0)) { + psptr->WeaponSlot[a].PrimaryRoundsRemaining+=ONE_FIXED; + /* Autoswap to disc here? */ + AutoSwapToDisc(); + } else { + psptr->WeaponSlot[a].PrimaryMagazinesRemaining+=1; + } + } + } + + #if 0 + else { + /* We must be in the clear! */ + #if 0 + dynPtr->IgnoreThePlayer=0; + #endif + } + #endif + + if (bbPtr->Stuck) { + dynPtr->LinVelocity.vx = 0; + dynPtr->LinVelocity.vy = 0; + dynPtr->LinVelocity.vz = 0; + + dynPtr->LinImpulse.vx = 0; + dynPtr->LinImpulse.vy = 0; + dynPtr->LinImpulse.vz = 0; + + } else { + /* Decrement Timer.. */ + + bbPtr->counter -= NormalFrameTime; + + if (bbPtr->Target==NULL) { + if (bbPtr->counter<=0) { + /* Turn around! */ + bbPtr->Target=Player->ObStrategyBlock; + bbPtr->counter = DISC_LIFETIME; + COPY_NAME(bbPtr->Target_SBname,bbPtr->Target->SBname); + dynPtr->IgnoreThePlayer=0; + } + } + + /* Move Disc */ + + CreateEulerMatrix(&dynPtr->OrientEuler, &mat); + + TransposeMatrixCH(&mat); + + dynPtr->OrientMat=mat; + + dynPtr->LinVelocity.vx = MUL_FIXED(mat.mat31,DISC_SPEED); + dynPtr->LinVelocity.vy = MUL_FIXED(mat.mat32,DISC_SPEED); + dynPtr->LinVelocity.vz = MUL_FIXED(mat.mat33,DISC_SPEED); + + dynPtr->LinImpulse.vx=0; + dynPtr->LinImpulse.vy=0; + dynPtr->LinImpulse.vz=0; + NewTrailPoint(sbPtr->DynPtr); + } +} + +void SetEulerAngles(VECTORCH *source, VECTORCH *Target, EULER *eulr) { + + int offsetx,offsety,offsetz; + + offsetx=(Target->vx)-(source->vx); + offsety=(Target->vz)-(source->vz); + + eulr->EulerY=ArcTan(offsetx,offsety); + eulr->EulerY&=wrap360; + + /* That was for the first plane. Now the second. */ + + offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety)); + offsety=-((Target->vy)-(source->vy)); + + eulr->EulerX=ArcTan(offsety,offsetz); + eulr->EulerX&=wrap360; + + eulr->EulerZ=0; + +} + +void EulerAnglesHoming(VECTORCH *source, VECTORCH *Target, EULER *eulr, int rate) { + + int offsetx,offsety,offsetz,angle1,angle2,testangle; + + offsetx=(Target->vx)-(source->vx); + offsety=(Target->vz)-(source->vz); + + angle1=ArcTan(offsetx,offsety); + + angle2=eulr->EulerY; + + if (angle1!=angle2) { + + testangle=angle2-angle1; + if (abs(testangle)<(NormalFrameTime>>rate)) { + eulr->EulerY=angle1; + eulr->EulerY&=wrap360; + } else if ( ((testangle>0) && (testangleEulerY-=(NormalFrameTime>>rate); + eulr->EulerY&=wrap360; + } else { + eulr->EulerY+=(NormalFrameTime>>rate); + eulr->EulerY&=wrap360; + } + + } + + /* That was for the first plane. Now the second. */ + + offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety)); + offsety=-((Target->vy)-(source->vy)); + + angle1=ArcTan(offsety,offsetz); + angle2=eulr->EulerX; + + if (angle1!=angle2) { + testangle=angle2-angle1; + if (abs(testangle)<(NormalFrameTime>>rate)) { + eulr->EulerX=angle1; + eulr->EulerX&=wrap360; + } else if ( ((testangle>0) && (testangleEulerX-=(NormalFrameTime>>rate); + eulr->EulerX&=wrap360; + } else { + eulr->EulerX+=(NormalFrameTime>>rate); + eulr->EulerX&=wrap360; + } + } + +} + +int PredDisc_TargetFilter(STRATEGYBLOCK *candidate) { + + switch (candidate->I_SBtype) { + case I_BehaviourAlien: + { + ALIEN_STATUS_BLOCK *alienStatusPointer; + LOCALASSERT(candidate); + LOCALASSERT(candidate->DynPtr); + + alienStatusPointer=(ALIEN_STATUS_BLOCK *)(candidate->SBdataptr); + + if (alienStatusPointer->BehaviourState==ABS_Dying) { + return(0); + } else { + return(1); + } + break; + } + case I_BehaviourQueenAlien: + case I_BehaviourFaceHugger: + case I_BehaviourPredator: + case I_BehaviourXenoborg: + case I_BehaviourMarine: + case I_BehaviourSeal: + case I_BehaviourPredatorAlien: + /* Valid. */ + return(1); + break; + #if SupportWindows95 + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *dataptr; + dataptr=candidate->SBdataptr; + switch (dataptr->type) { + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourPredatorPlayer: + return(1); + break; + default: + return(0); + break; + } + } + break; + #endif + default: + return(0); + break; + } + +} + +void PredDisc_GetFirstTarget(PC_PRED_DISC_BEHAV_BLOCK *bptr, DISPLAYBLOCK *target, VECTORCH *position) { + + int a; + + if (target!=NULL) { + if (target->ObStrategyBlock!=NULL) { + if (PredDisc_TargetFilter(target->ObStrategyBlock)) { + /* Valid. */ + bptr->Target=target->ObStrategyBlock; + COPY_NAME(bptr->Target_SBname,target->ObStrategyBlock->SBname); + return; + } + } + } + + /* Second try. */ + + bptr->Target=PredDisc_GetNewTarget(bptr,position,NULL,2); + if (bptr->Target!=NULL) { + COPY_NAME(bptr->Target_SBname,bptr->Target->SBname); + return; + } + + /* Failed! */ + + bptr->Target=NULL; + { + for (a=0; aTarget_SBname[a]='\0'; + } + } + +} + +int ObjectIsOnScreen(DISPLAYBLOCK *object) { + + int a; + extern DISPLAYBLOCK *OnScreenBlockList[]; + extern int NumOnScreenBlocks; + + for (a=0; aObStrategyBlock)) { + if (candidate->DynPtr) { + if (PredDisc_TargetFilter(candidate)) { + VECTORCH offset; + int dist; + + offset.vx=discpos->vx-candidate->DynPtr->Position.vx; + offset.vy=discpos->vy-candidate->DynPtr->Position.vy; + offset.vz=discpos->vz-candidate->DynPtr->Position.vz; + + dist=Approximate3dMagnitude(&offset); + + if (! ((mine==1)&&dist>DISC_PROX_RANGE)) { + if (distSBdptr) { + if (!NPC_IsDead(candidate)) { + /* Not the last one again! */ + if (!NAME_ISEQUAL(bptr->Prev_Target_SBname,candidate->SBname)) { + if (mine==1) { + if (IsThisObjectVisibleFromThisPosition(candidate->SBdptr,discpos,DISC_PROX_RANGE) ) { + nearest=candidate; + } + } else if (mine==2) { + if (ObjectIsOnScreen(candidate->SBdptr)) { + nearest=candidate; + } + } else if (candidate->containingModule) { + if ((IsModuleVisibleFromModule(dmod,candidate->containingModule))) { + nearest=candidate; + } + } + } + } + } + } + } + } + } + } + } + + return(nearest); + +} + + + +void NukeObject(STRATEGYBLOCK *sbPtr) +{ + CauseDamageToObject(sbPtr, &certainDeath, ONE_FIXED,NULL); +} + + + +DISPLAYBLOCK *SpawnMolotovCocktail(SECTION_DATA *root, MATRIXCH *master_orient) +{ + + DISPLAYBLOCK *dispPtr; + STRATEGYBLOCK *sbPtr; + MODULEMAPBLOCK *mmbptr; + MODULE m_temp; + AVP_BEHAVIOUR_TYPE bhvr; + int woundflags; + + //if( (NumActiveBlocks > maxobjects-5) || (NumActiveStBlocks > maxstblocks-5)) return NULL; + + // 1. Set up shape data BEFORE making the displayblock, + // since "AllocateModuleObject()" will fill in shapeheader + // information and extent data + + mmbptr = &TempModuleMap; + + /* Doesn't really matter what shape gets generated... */ + //CreateShapeInstance(mmbptr,root->sempai->ShapeName); + CreateShapeInstance(mmbptr,"Shell"); + + bhvr = I_BehaviourMolotov; + + // And allocate the modulemapblock object + + m_temp.m_numlights = 0; + m_temp.m_lightarray = NULL; + m_temp.m_mapptr = mmbptr; + m_temp.m_sbptr = (STRATEGYBLOCK*)NULL; + m_temp.m_dptr = NULL; + AllocateModuleObject(&m_temp); + dispPtr = m_temp.m_dptr; + if(dispPtr==NULL) return (DISPLAYBLOCK *)0; /* patrick: cannot create displayblock, so just return 0 */ + + dispPtr->ObMyModule = NULL; /* Module that created us */ + + if(root) //allow case root==NULL for loading + { + dispPtr->ObWorld = root->World_Offset; + } + + sbPtr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dispPtr); + + if (sbPtr == 0) return (DISPLAYBLOCK *)0; // Failed to allocate a strategy block + + // 2. NOW set up the strategyblock-specific fields for + // the new displayblock. We won't go through the "AttachNew + // StrategyBlock" and "AssignRunTimeBehaviours" pair, since + // the first switches on ObShape and the second on bhvr; + // but, in this case, there isn't a particular connection + // between them. + + sbPtr->I_SBtype = bhvr; + + { + DYNAMICSBLOCK *dynPtr; + + sbPtr->SBdataptr = (MOLOTOV_BEHAV_BLOCK *) AllocateMem(sizeof(MOLOTOV_BEHAV_BLOCK)); + if (sbPtr->SBdataptr == 0) { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(sbPtr); + return (DISPLAYBLOCK*)NULL; + } + + ((MOLOTOV_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = 65536;//32767;//FastRandom()&32767; + + if(root) //allow case root==NULL for loading + { + woundflags=Splice_HModels(&(((MOLOTOV_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),root); + InitHModelSequence( &(((MOLOTOV_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),0,1,ONE_FIXED); + } + + dispPtr->HModelControlBlock=&(((MOLOTOV_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController); + + if(root) //allow case root==NULL for loading + { + dispPtr->ObWorld=root->World_Offset; + dispPtr->ObMat=root->SecMat; + } + + LOCALASSERT(dispPtr->ObWorld.vx<1000000 && dispPtr->ObWorld.vx>-1000000); + LOCALASSERT(dispPtr->ObWorld.vy<1000000 && dispPtr->ObWorld.vy>-1000000); + LOCALASSERT(dispPtr->ObWorld.vz<1000000 && dispPtr->ObWorld.vz>-1000000); + + ProveHModel(dispPtr->HModelControlBlock,dispPtr); + + dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE); + + if (dynPtr == 0) { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(sbPtr); + return (DISPLAYBLOCK*)NULL; + } + + if(root) //allow case root==NULL for loading + { + dynPtr->Position = root->World_Offset; + + dynPtr->OrientMat=root->SecMat; + } + + // Give explosion fragments an angular velocity + dynPtr->AngVelocity.EulerX = (FastRandom()&2047)-1024; + dynPtr->AngVelocity.EulerY = (FastRandom()&2047)-1024; + dynPtr->AngVelocity.EulerZ = (FastRandom()&2047)-1024; + + dynPtr->LinVelocity.vx=0; + dynPtr->LinVelocity.vy=0; + dynPtr->LinVelocity.vz=0; + + dynPtr->IgnoreThePlayer=0; + + { + /* Handle velocity... */ + //VECTORCH start={0,2000,12000}; + MATRIXCH tm=*master_orient; + VECTORCH start; + + start.vx=mx; + start.vy=my; + start.vz=mz; + + RotateAndCopyVector(&start,&dynPtr->LinImpulse,&tm); + + } + + } + + + return dispPtr; + +} +extern void MolotovBehaviour(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + MOLOTOV_BEHAV_BLOCK *bbPtr = (MOLOTOV_BEHAV_BLOCK * ) sbPtr->SBdataptr; + int explodeNow = 0; + + //Work out the containing module now , since it doesn't seem to get done anywhere else + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), sbPtr->containingModule); + + /* explode if the grenade touches an alien */ + while (reportPtr) + { + STRATEGYBLOCK *sbPtr = reportPtr->ObstacleSBPtr; + + if(sbPtr) + { + if((sbPtr->I_SBtype == I_BehaviourAlien) + ||(sbPtr->I_SBtype == I_BehaviourMarinePlayer) + ||(sbPtr->I_SBtype == I_BehaviourAlienPlayer) + ||(sbPtr->I_SBtype == I_BehaviourPredatorPlayer) + ||(sbPtr->I_SBtype == I_BehaviourPredator) + ||(sbPtr->I_SBtype == I_BehaviourXenoborg) + ||(sbPtr->I_SBtype == I_BehaviourMarine) + ||(sbPtr->I_SBtype == I_BehaviourQueenAlien) + ||(sbPtr->I_SBtype == I_BehaviourPredatorAlien) + ||(sbPtr->I_SBtype == I_BehaviourFaceHugger)) + { + explodeNow = 1; /* kaboom */ + //explodeNow = 0; /* kaboom */ + } + + #if SupportWindows95 + if(sbPtr->I_SBtype == I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData = sbPtr->SBdataptr; + LOCALASSERT(ghostData); + LOCALASSERT(AvP.Network!=I_No_Network); + + if((ghostData->type == I_BehaviourMarinePlayer)|| + (ghostData->type == I_BehaviourPredatorPlayer)|| + (ghostData->type == I_BehaviourAlienPlayer)) + { + explodeNow = 1; + } + } + #endif + } else { + /* What the hell! */ + explodeNow=1; + } + + /* skip to next report */ + reportPtr = reportPtr->NextCollisionReportPtr; + } + + if ((bbPtr->counter<=0) || explodeNow) + { + /* KJL 17:51:56 12/17/96 - make explosion damage other objects */ + HandleEffectsOfExplosion + ( + sbPtr, + &(dynPtr->Position), + TemplateAmmo[AMMO_MOLOTOV].MaxRange, + &TemplateAmmo[AMMO_MOLOTOV].MaxDamage[AvP.Difficulty], + TemplateAmmo[AMMO_MOLOTOV].ExplosionIsFlat + ); + + if (sbPtr->containingModule) { + Explosion_SoundData.position=dynPtr->Position; + Sound_Play(SID_ED_MOLOTOV_EXPLOSION,"n",&Explosion_SoundData); + } + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + /* destroy rocket */ + DestroyAnyStrategyBlock(sbPtr); + } + else + { + bbPtr->counter-=NormalFrameTime; + DynamicallyRotateObject(dynPtr); + } +} + +void FirePredPistolFlechettes(VECTORCH *base_position,VECTORCH *base_offset,MATRIXCH *orientmat,int player, int *timer,BOOL damaging) { + + /* A cheap knock off of the flamethrower function, so as not to rock the boat. */ + + VECTORCH position; + + (*timer)+=NormalFrameTime; + + while ((*timer)>=TIME_FOR_PREDPISTOLFLECHETTE) + { + VECTORCH velocity, ratio; + + (*timer)-=TIME_FOR_PREDPISTOLFLECHETTE; + + /* Calculate velocity... */ + velocity.vx = ((FastRandom()&1023) - 512)*PREDPISTOL_SPREAD;//*2; + velocity.vy = ((FastRandom()&1023) - 512)*PREDPISTOL_SPREAD;//*2; + velocity.vz = ((FastRandom()&1023) + 200+1024)*16; // Was 511, 512. + + /* calculate the position */ + + { + int offset = MUL_FIXED(FastRandom()&32767,NormalFrameTime); // Was 16383 + + position=*base_offset; + + /* Make sure position corresponds to velocity direction... */ + ratio=velocity; + Normalise(&ratio); + position.vx += MUL_FIXED(offset,ratio.vx); + position.vy += MUL_FIXED(offset,ratio.vy); + position.vz += MUL_FIXED(offset,ratio.vz); + + } + + RotateVector(&position,orientmat); + + if (player) { + Crunch_Position_For_Players_Weapon(&position); + } else { + position.vx+=base_position->vx; + position.vy+=base_position->vy; + position.vz+=base_position->vz; + } + + RotateVector(&velocity,orientmat); + MakeParticle(&position,&(velocity),damaging ? PARTICLE_PREDPISTOL_FLECHETTE : PARTICLE_PREDPISTOL_FLECHETTE_NONDAMAGING); + } + +} + + +/*-------------------** +** Load/Save Grenade ** +**-------------------*/ +typedef struct grenade_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int counter; + int bouncelastframe; + + DYNAMICSBLOCK dynamics; +}GRENADE_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV behav + +void LoadStrategy_Grenade(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + GRENADE_BEHAV_BLOCK* behav; + GRENADE_SAVE_BLOCK* block = (GRENADE_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //create default grende + sbPtr = CreateGrenadeKernel(I_BehaviourGrenade,&block->dynamics.Position,&block->dynamics.OrientMat,0); + if(!sbPtr) return; + + behav = (GRENADE_BEHAV_BLOCK*) sbPtr->SBdataptr; + + //copy stuff over + COPYELEMENT_LOAD(counter); + COPYELEMENT_LOAD(bouncelastframe); + + *sbPtr->DynPtr = block->dynamics; +} + +void SaveStrategy_Grenade(STRATEGYBLOCK* sbPtr) +{ + GRENADE_BEHAV_BLOCK* behav; + GRENADE_SAVE_BLOCK* block; + + behav = (GRENADE_BEHAV_BLOCK*) sbPtr->SBdataptr; + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + COPYELEMENT_SAVE(counter); + COPYELEMENT_SAVE(bouncelastframe); + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + +} + + +/*-------------------** +** Load/Save Cluster Grenade ** +**-------------------*/ +typedef struct cluster_grenade_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int counter; + int bouncelastframe; + + DYNAMICSBLOCK dynamics; +}CLUSTER_GRENADE_SAVE_BLOCK; + + +void LoadStrategy_ClusterGrenade(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + GRENADE_BEHAV_BLOCK* behav; + CLUSTER_GRENADE_SAVE_BLOCK* block = (CLUSTER_GRENADE_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //create default grenade + sbPtr = CreateGrenadeKernel(I_BehaviourClusterGrenade,&block->dynamics.Position,&block->dynamics.OrientMat,0); + if(!sbPtr) return; + + behav = (GRENADE_BEHAV_BLOCK*) sbPtr->SBdataptr; + + //copy stuff over + COPYELEMENT_LOAD(counter); + COPYELEMENT_LOAD(bouncelastframe); + + *sbPtr->DynPtr = block->dynamics; +} + +void SaveStrategy_ClusterGrenade(STRATEGYBLOCK* sbPtr) +{ + GRENADE_BEHAV_BLOCK* behav; + CLUSTER_GRENADE_SAVE_BLOCK* block; + + behav = (GRENADE_BEHAV_BLOCK*) sbPtr->SBdataptr; + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + COPYELEMENT_SAVE(counter); + COPYELEMENT_SAVE(bouncelastframe); + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + +} + + +/*-------------------** +** Load/Save Flare Grenade ** +**-------------------*/ +typedef struct flare_grenade_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int LifeTimeRemaining; + int ParticleGenerationTimer; + + DYNAMICSBLOCK dynamics; +}FLARE_GRENADE_SAVE_BLOCK; + +void LoadStrategy_FlareGrenade(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + FLARE_BEHAV_BLOCK* behav; + FLARE_GRENADE_SAVE_BLOCK* block = (FLARE_GRENADE_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //create default grende + sbPtr = CreateGrenadeKernel(I_BehaviourFlareGrenade,&block->dynamics.Position,&block->dynamics.OrientMat,0); + if(!sbPtr) return; + + behav = (FLARE_BEHAV_BLOCK*) sbPtr->SBdataptr; + + //copy stuff over + COPYELEMENT_LOAD(LifeTimeRemaining) + COPYELEMENT_LOAD(ParticleGenerationTimer) + + *sbPtr->DynPtr = block->dynamics; + + Load_SoundState(&behav->SoundHandle); +} + +void SaveStrategy_FlareGrenade(STRATEGYBLOCK* sbPtr) +{ + FLARE_BEHAV_BLOCK* behav; + FLARE_GRENADE_SAVE_BLOCK* block; + + behav = (FLARE_BEHAV_BLOCK*) sbPtr->SBdataptr; + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + COPYELEMENT_SAVE(LifeTimeRemaining) + COPYELEMENT_SAVE(ParticleGenerationTimer) + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + Save_SoundState(&behav->SoundHandle); + +} + +/*-------------------** +** Load/Save Prox Grenade ** +**-------------------*/ +typedef struct prox_grenade_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int LifeTimeRemaining; + int SoundGenerationTimer; + + DYNAMICSBLOCK dynamics; +}PROX_GRENADE_SAVE_BLOCK; + +void LoadStrategy_ProxGrenade(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + PROX_GRENADE_BEHAV_BLOCK* behav; + PROX_GRENADE_SAVE_BLOCK* block = (PROX_GRENADE_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //create default grende + sbPtr = CreateGrenadeKernel(I_BehaviourProximityGrenade,&block->dynamics.Position,&block->dynamics.OrientMat,0); + if(!sbPtr) return; + + behav = (PROX_GRENADE_BEHAV_BLOCK*) sbPtr->SBdataptr; + + //copy stuff over + COPYELEMENT_LOAD(LifeTimeRemaining) + COPYELEMENT_LOAD(SoundGenerationTimer) + + *sbPtr->DynPtr = block->dynamics; + + Load_SoundState(&behav->SoundHandle); +} + +void SaveStrategy_ProxGrenade(STRATEGYBLOCK* sbPtr) +{ + PROX_GRENADE_BEHAV_BLOCK* behav; + PROX_GRENADE_SAVE_BLOCK* block; + + behav = (PROX_GRENADE_BEHAV_BLOCK*) sbPtr->SBdataptr; + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + COPYELEMENT_SAVE(LifeTimeRemaining) + COPYELEMENT_SAVE(SoundGenerationTimer) + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + Save_SoundState(&behav->SoundHandle); + +} + +/*-------------------** +** Load/Save rocket ** +**-------------------*/ +typedef struct rocket_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int counter; + int player; + + DYNAMICSBLOCK dynamics; +}ROCKET_SAVE_BLOCK; + +void LoadStrategy_Rocket(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + PREDPISTOL_BEHAV_BLOCK* behav; + ROCKET_SAVE_BLOCK* block = (ROCKET_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //create default grende + sbPtr = CreateRocketKernel(&block->dynamics.Position,&block->dynamics.OrientMat,0); + if(!sbPtr) return; + + behav = (PREDPISTOL_BEHAV_BLOCK*) sbPtr->SBdataptr; + + //copy stuff over + COPYELEMENT_LOAD(counter) + COPYELEMENT_LOAD(player) + + *sbPtr->DynPtr = block->dynamics; +} + +void SaveStrategy_Rocket(STRATEGYBLOCK* sbPtr) +{ + PREDPISTOL_BEHAV_BLOCK* behav; + ROCKET_SAVE_BLOCK* block; + + behav = (PREDPISTOL_BEHAV_BLOCK*) sbPtr->SBdataptr; + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + COPYELEMENT_SAVE(counter) + COPYELEMENT_SAVE(player) + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + +} + + +/*-------------------** +** Load/Save PP plasma bolt ** +**-------------------*/ +typedef struct ppplasma_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int counter; + int player; + + DYNAMICSBLOCK dynamics; +}PPPLASMA_SAVE_BLOCK; + +void LoadStrategy_PPPlasmaBolt(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + PREDPISTOL_BEHAV_BLOCK* behav; + PPPLASMA_SAVE_BLOCK* block = (PPPLASMA_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //create default bolt + sbPtr = CreatePPPlasmaBoltKernel(&block->dynamics.Position,&block->dynamics.OrientMat,0); + if(!sbPtr) return; + + behav = (PREDPISTOL_BEHAV_BLOCK*) sbPtr->SBdataptr; + + //copy stuff over + COPYELEMENT_LOAD(counter) + COPYELEMENT_LOAD(player) + + *sbPtr->DynPtr = block->dynamics; +} + +void SaveStrategy_PPPlasmaBolt(STRATEGYBLOCK* sbPtr) +{ + PREDPISTOL_BEHAV_BLOCK* behav; + PPPLASMA_SAVE_BLOCK* block; + + behav = (PREDPISTOL_BEHAV_BLOCK*) sbPtr->SBdataptr; + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + COPYELEMENT_SAVE(counter) + COPYELEMENT_SAVE(player) + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + +} + + + + +/*-------------------** +** Load/Save energy bolt ** +**-------------------*/ +typedef struct pred_energy_bolt_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int counter; + int player; + DAMAGE_PROFILE damage; + int blast_radius; + + DYNAMICSBLOCK dynamics; +}PREDATOR_ENERGY_BOLT_SAVE_BLOCK; + +void LoadStrategy_PredatorEnergyBolt(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + CASTER_BOLT_BEHAV_BLOCK* behav; + PREDATOR_ENERGY_BOLT_SAVE_BLOCK* block = (PREDATOR_ENERGY_BOLT_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //create default bolt + sbPtr = InitialiseEnergyBoltBehaviourKernel(&block->dynamics.Position,&block->dynamics.OrientMat,0,&block->damage,ONE_FIXED); + if(!sbPtr) return; + + behav = (CASTER_BOLT_BEHAV_BLOCK*) sbPtr->SBdataptr; + + //copy stuff over + COPYELEMENT_LOAD(counter) + COPYELEMENT_LOAD(player) + COPYELEMENT_LOAD(damage) + COPYELEMENT_LOAD(blast_radius) + + *sbPtr->DynPtr = block->dynamics; +} + +void SaveStrategy_PredatorEnergyBolt(STRATEGYBLOCK* sbPtr) +{ + CASTER_BOLT_BEHAV_BLOCK* behav; + PREDATOR_ENERGY_BOLT_SAVE_BLOCK* block; + + behav = (CASTER_BOLT_BEHAV_BLOCK*) sbPtr->SBdataptr; + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + COPYELEMENT_SAVE(counter) + COPYELEMENT_SAVE(player) + COPYELEMENT_SAVE(damage) + COPYELEMENT_SAVE(blast_radius) + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + +} + + + + +/*-------------------** +** Load/Save pulse grenade ** +**-------------------*/ +typedef struct pulse_grenade_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int counter; + int player; + + DYNAMICSBLOCK dynamics; +}PULSE_GRENADE_SAVE_BLOCK; + +void LoadStrategy_PulseGrenade(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + PREDPISTOL_BEHAV_BLOCK* behav; + PULSE_GRENADE_SAVE_BLOCK* block = (PULSE_GRENADE_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //create default grenade + sbPtr = InitialisePulseGrenadeBehaviour(); + if(!sbPtr) return; + + behav = (PREDPISTOL_BEHAV_BLOCK*) sbPtr->SBdataptr; + + //copy stuff over + COPYELEMENT_LOAD(counter) + COPYELEMENT_LOAD(player) + + *sbPtr->DynPtr = block->dynamics; +} + +void SaveStrategy_PulseGrenade(STRATEGYBLOCK* sbPtr) +{ + PREDPISTOL_BEHAV_BLOCK* behav; + PULSE_GRENADE_SAVE_BLOCK* block; + + behav = (PREDPISTOL_BEHAV_BLOCK*) sbPtr->SBdataptr; + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + COPYELEMENT_SAVE(counter) + COPYELEMENT_SAVE(player) + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + +} + +/*-------------------** +** Load/Save molotov ** +**-------------------*/ +typedef struct molotov_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + + int counter; + + DYNAMICSBLOCK dynamics; +}MOLOTOV_SAVE_BLOCK; + +void LoadStrategy_Molotov(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + DISPLAYBLOCK* dPtr; + MOLOTOV_BEHAV_BLOCK* behav; + PULSE_GRENADE_SAVE_BLOCK* block = (PULSE_GRENADE_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //create default molotov + dPtr = SpawnMolotovCocktail(0,&block->dynamics.OrientMat); + if(!dPtr) return; + + sbPtr = dPtr->ObStrategyBlock; + + behav = (MOLOTOV_BEHAV_BLOCK*) sbPtr->SBdataptr; + + //copy stuff over + COPYELEMENT_LOAD(counter) + + *sbPtr->DynPtr = block->dynamics; + + + //load the molotov hierarchy + { + SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); + if(hier_header) + { + LoadHierarchy(hier_header,&behav->HModelController); + } + } + +} + +void SaveStrategy_Molotov(STRATEGYBLOCK* sbPtr) +{ + MOLOTOV_BEHAV_BLOCK* behav; + PULSE_GRENADE_SAVE_BLOCK* block; + + behav = (MOLOTOV_BEHAV_BLOCK*) sbPtr->SBdataptr; + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + COPYELEMENT_SAVE(counter) + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + //save the molotov hierarchy + SaveHierarchy(&behav->HModelController); +} + + + +/*-------------------------** +** Load/Save Predator Disc ** +**-------------------------*/ + + +typedef struct predator_disc_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + +//behaviour block stuff + int counter; + int Destruct:1; + int Stuck :1; + int Bounced :1; + int bounces; + + char Prev_Target_SBname[SB_NAME_LENGTH]; + char Prev_Damaged_SBname[SB_NAME_LENGTH]; +//pointer things + char Target_SBname[SB_NAME_LENGTH]; + +//strategy block stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; + DYNAMICSBLOCK dynamics; +}PREDATOR_DISC_SAVE_BLOCK; + +void LoadStrategy_PredatorDisc(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + PC_PRED_DISC_BEHAV_BLOCK* behav; + PREDATOR_DISC_SAVE_BLOCK* block = (PREDATOR_DISC_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //create default disc + sbPtr = InitialiseDiscBehaviour_ForLoad(); + if(!sbPtr) return; + + behav = (PC_PRED_DISC_BEHAV_BLOCK*) sbPtr->SBdataptr; + + COPYELEMENT_LOAD(counter) + COPYELEMENT_LOAD(Destruct) + COPYELEMENT_LOAD(Stuck) + COPYELEMENT_LOAD(Bounced) + COPYELEMENT_LOAD(bounces) + + COPY_NAME(behav->Target_SBname,block->Target_SBname); + COPY_NAME(behav->Prev_Target_SBname,block->Prev_Target_SBname); + COPY_NAME(behav->Prev_Damaged_SBname,block->Prev_Damaged_SBname); + behav->Target = FindSBWithName(behav->Target_SBname); + +//strategy block stuff + *sbPtr->DynPtr = block->dynamics; + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + + //load the hierarchy + { + SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); + if(hier_header) + { + LoadHierarchy(hier_header,&behav->HModelController); + } + } + Load_SoundState(&behav->soundHandle); +} + +void SaveStrategy_PredatorDisc(STRATEGYBLOCK* sbPtr) +{ + PREDATOR_DISC_SAVE_BLOCK *block; + PC_PRED_DISC_BEHAV_BLOCK *behav; + + + behav = (PC_PRED_DISC_BEHAV_BLOCK*)sbPtr->SBdataptr; + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + +//start copying stuff + COPYELEMENT_SAVE(counter) + COPYELEMENT_SAVE(Destruct) + COPYELEMENT_SAVE(Stuck) + COPYELEMENT_SAVE(Bounced) + COPYELEMENT_SAVE(bounces) + + COPY_NAME(block->Target_SBname,behav->Target_SBname); + COPY_NAME(block->Prev_Target_SBname,behav->Prev_Target_SBname); + COPY_NAME(block->Prev_Damaged_SBname,behav->Prev_Damaged_SBname); + +//strategy block stuff + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; +//save hierarchy + SaveHierarchy(&behav->HModelController); + + Save_SoundState(&behav->soundHandle); +} + + + +/*-------------------------** +** Load/Save speargun bolt ** +**-------------------------*/ + +typedef struct spear_bolt_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + +//behaviour block stuff + int counter; + MATRIXCH Orient; + VECTORCH Position; +// HMODELCONTROLLER HierarchicalFragment; + int Android; + AVP_BEHAVIOUR_TYPE Type; + int SubType; + unsigned int SpearThroughFragment; + unsigned int Stuck :1; + +//strategy block stuff + DYNAMICSBLOCK dynamics; +}SPEAR_BOLT_SAVE_BLOCK; + + +void LoadStrategy_SpearBolt(SAVE_BLOCK_HEADER* header) +{ + DISPLAYBLOCK* dPtr; + STRATEGYBLOCK* sbPtr; + SPEAR_BEHAV_BLOCK* behav; + SPEAR_BOLT_SAVE_BLOCK* block = (SPEAR_BOLT_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //create default spear bolt + dPtr = InitialiseSpeargunBoltBehaviour_ForLoad(); + if(!dPtr) return; + + sbPtr = dPtr->ObStrategyBlock; + if(!sbPtr) return; + + behav = (SPEAR_BEHAV_BLOCK*)sbPtr->SBdataptr; + + COPYELEMENT_LOAD(counter) + COPYELEMENT_LOAD(Orient) + COPYELEMENT_LOAD(Position) + COPYELEMENT_LOAD(Android) + COPYELEMENT_LOAD(Type) + COPYELEMENT_LOAD(SubType) + COPYELEMENT_LOAD(SpearThroughFragment) + COPYELEMENT_LOAD(Stuck) + + *sbPtr->DynPtr = block->dynamics; + + { + SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); + if(hier_header) + { + LoadHierarchy(hier_header,&behav->HierarchicalFragment); + } + } + //if there is a hierarchy fill it in the displayblock + if(behav->HierarchicalFragment.Root_Section) + { + dPtr->HModelControlBlock = &behav->HierarchicalFragment; + } +} + +void SaveStrategy_SpearBolt(STRATEGYBLOCK* sbPtr) +{ + SPEAR_BOLT_SAVE_BLOCK *block; + SPEAR_BEHAV_BLOCK *behav; + + behav = (SPEAR_BEHAV_BLOCK*)sbPtr->SBdataptr; + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + + + COPYELEMENT_SAVE(counter) + COPYELEMENT_SAVE(Orient) + COPYELEMENT_SAVE(Position) + COPYELEMENT_SAVE(Android) + COPYELEMENT_SAVE(Type) + COPYELEMENT_SAVE(SubType) + COPYELEMENT_SAVE(SpearThroughFragment) + COPYELEMENT_SAVE(Stuck) + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + //save the hierarchy + SaveHierarchy(&behav->HierarchicalFragment); +} + +typedef struct frisbee_save_block +{ + SAVE_BLOCK_STRATEGY_HEADER header; + +//behaviour block stuff + int counter; + int Bounced :1; + int bounces; + +//strategy block stuff + int integrity; + DAMAGEBLOCK SBDamageBlock; + DYNAMICSBLOCK dynamics; +} FRISBEE_SAVE_BLOCK; + +void LoadStrategy_Frisbee(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + FRISBEE_BEHAV_BLOCK* behav; + FRISBEE_SAVE_BLOCK* block = (FRISBEE_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //create default disc + sbPtr = InitialiseFrisbeeBehaviour_ForLoad(); + if(!sbPtr) return; + + behav = (FRISBEE_BEHAV_BLOCK*) sbPtr->SBdataptr; + + COPYELEMENT_LOAD(counter) + COPYELEMENT_LOAD(Bounced) + COPYELEMENT_LOAD(bounces) + +//strategy block stuff + *sbPtr->DynPtr = block->dynamics; + sbPtr->integrity = block->integrity; + sbPtr->SBDamageBlock = block->SBDamageBlock; + + //load the hierarchy + { + SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); + if(hier_header) + { + LoadHierarchy(hier_header,&behav->HModelController); + } + } + Load_SoundState(&behav->soundHandle); +} + +void SaveStrategy_Frisbee(STRATEGYBLOCK* sbPtr) +{ + FRISBEE_SAVE_BLOCK *block; + FRISBEE_BEHAV_BLOCK *behav; + + + behav = (FRISBEE_BEHAV_BLOCK*)sbPtr->SBdataptr; + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + +//start copying stuff + COPYELEMENT_SAVE(counter) + COPYELEMENT_SAVE(Bounced) + COPYELEMENT_SAVE(bounces) + +//strategy block stuff + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + + block->integrity = sbPtr->integrity; + block->SBDamageBlock = sbPtr->SBDamageBlock; +//save hierarchy + SaveHierarchy(&behav->HModelController); + + Save_SoundState(&behav->soundHandle); +} + +STRATEGYBLOCK* InitialiseFrisbeeBoltBehaviourKernel(VECTORCH *position,MATRIXCH *orient, int player, DAMAGE_PROFILE *damage, int factor) { + + DISPLAYBLOCK *dispPtr; + DYNAMICSBLOCK *dynPtr; + + /* make displayblock with correct shape, etc */ + dispPtr = MakeObject(I_BehaviourFrisbeeEnergyBolt,position); + if (dispPtr == 0) return NULL; // Failed to allocate display block + + dispPtr->SfxPtr = AllocateSfxBlock(); + + if (!dispPtr->SfxPtr) + { + // Failed to allocate a special fx block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + dispPtr->SfxPtr->SfxID = SFX_FRISBEE_PLASMA_BOLT; + /* make displayblock a dynamic module object */ + dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; + dispPtr->ObShape = 0; + dispPtr->ObStrategyBlock->shapeIndex = 0; + dispPtr->ObMinX = -50; + dispPtr->ObMinY = -50; + dispPtr->ObMinZ = -50; + dispPtr->ObMaxX = 50; + dispPtr->ObMaxY = 50; + dispPtr->ObMaxZ = 50; + /* add lighting effect */ + AddLightingEffectToObject(dispPtr,LFX_PLASMA_BOLT); + + /* setup dynamics block */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); + + if (dynPtr == 0) + { + // Failed to allocate a dynamics block + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + dispPtr->ObStrategyBlock->DynPtr = dynPtr; + + /* give missile a maximum lifetime */ + dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(CASTER_BOLT_BEHAV_BLOCK)); + + if (dispPtr->ObStrategyBlock->SBdataptr == 0) + { + // Failed to allocate a strategy block data pointer + RemoveBehaviourStrategy(dispPtr->ObStrategyBlock); + return NULL; + } + + ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED; + ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->damage = *damage; + ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->blast_radius = MUL_FIXED(factor,Caster_BlastRadius); + ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->player = player; + ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->soundHandle = SOUND_NOACTIVEINDEX; + + /* align rocket to launcher */ + dynPtr->Position=*position; + dynPtr->PrevPosition=*position; + + dynPtr->IgnoreSameObjectsAsYou = 1; + + //GetGunDirection(&(dynPtr->LinVelocity),&position); + //MakeMatrixFromDirection(&(dynPtr->LinVelocity),&(dynPtr->OrientMat)); + //MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); + //dynPtr->PrevOrientMat = dynPtr->OrientMat; + + /* align velocity too */ + dynPtr->OrientMat = *orient; + dynPtr->PrevOrientMat = dynPtr->OrientMat; + /* I added this next line for networking: Patrick */ + MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); + + /* align velocity too */ + dynPtr->LinVelocity.vx = dynPtr->OrientMat.mat31; + dynPtr->LinVelocity.vy = dynPtr->OrientMat.mat32; + dynPtr->LinVelocity.vz = dynPtr->OrientMat.mat33; + + dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx, ENERGY_BOLT_SPEED); + dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy, ENERGY_BOLT_SPEED); + dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz, ENERGY_BOLT_SPEED); + + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock); + #endif + + /* Extra cunning! */ + Sound_Play(SID_PRED_LAUNCHER,"hpd",(FastRandom()&255)-128,&dynPtr->Position); + + if (player==0) { + dynPtr->IgnoreThePlayer=0; + } + + return dispPtr->ObStrategyBlock; +} + +extern void FrisbeeEnergyBoltBehaviour(STRATEGYBLOCK *sbPtr) +{ + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; + CASTER_BOLT_BEHAV_BLOCK *bbPtr = (CASTER_BOLT_BEHAV_BLOCK * ) sbPtr->SBdataptr; + STRATEGYBLOCK *victim; + + victim=NULL; + + MakeDewlineTrailParticles(dynPtr,32); + + /* check for a collision with something */ + if (bbPtr->counter <= 0) + { + /* for net game support: send a message saying we've blown up... */ + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + DestroyAnyStrategyBlock(sbPtr); /* timed-out */ + } + else if (reportPtr) + { + if(reportPtr->ObstacleSBPtr) + { + VECTORCH attack_dir; + + /* Accuracy snipped again! */ + + GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir); + + switch (reportPtr->ObstacleSBPtr->I_SBtype) + { + /* No specific location damage. */ + default: + { + CauseDamageToObject(reportPtr->ObstacleSBPtr,&bbPtr->damage, ONE_FIXED,NULL); + victim=reportPtr->ObstacleSBPtr; + break; + } + } + } + + #if 0 + { + char hitEnvironment = 0; + + if (reportPtr->ObstacleSBPtr) + { + DISPLAYBLOCK *dispPtr = reportPtr->ObstacleSBPtr->SBdptr; + if (dispPtr) + if (dispPtr->ObMyModule) + { + hitEnvironment=1; + } + } + else + { + hitEnvironment = 1; + } + + if (hitEnvironment) + { + MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_DISSIPATINGPLASMA); + if (AvP.Network != I_No_Network) AddNetMsg_MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_DISSIPATINGPLASMA); + } + else + { + MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_FOCUSEDPLASMA); + if (AvP.Network != I_No_Network) AddNetMsg_MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_FOCUSEDPLASMA); + } + } + #endif + + #if SupportWindows95 + if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr); + #endif + /* Splash damage? */ + HandleEffectsOfExplosion + ( + victim, + &(dynPtr->Position), + bbPtr->blast_radius, + &bbPtr->damage, + 0 + ); + DestroyAnyStrategyBlock(sbPtr); + } else { + + { + VECTORCH direction; + direction.vx = dynPtr->LinVelocity.vx + dynPtr->LinImpulse.vx; + direction.vy = dynPtr->LinVelocity.vy + dynPtr->LinImpulse.vy; + direction.vz = dynPtr->LinVelocity.vz + dynPtr->LinImpulse.vz; + Normalise(&direction); + MakeMatrixFromDirection(&direction,&dynPtr->OrientMat); + } + bbPtr->counter -= NormalFrameTime; + } + +} + +void LoadStrategy_FrisbeeEnergyBolt(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + STRATEGYBLOCK* sbPtr; + CASTER_BOLT_BEHAV_BLOCK* behav; + PREDATOR_ENERGY_BOLT_SAVE_BLOCK* block = (PREDATOR_ENERGY_BOLT_SAVE_BLOCK*) header; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //create default bolt + sbPtr = InitialiseFrisbeeBoltBehaviourKernel(&block->dynamics.Position,&block->dynamics.OrientMat,0,&block->damage,ONE_FIXED); + if(!sbPtr) return; + + behav = (CASTER_BOLT_BEHAV_BLOCK*) sbPtr->SBdataptr; + + //copy stuff over + COPYELEMENT_LOAD(counter) + COPYELEMENT_LOAD(player) + COPYELEMENT_LOAD(damage) + COPYELEMENT_LOAD(blast_radius) + + *sbPtr->DynPtr = block->dynamics; +} + +void SaveStrategy_FrisbeeEnergyBolt(STRATEGYBLOCK* sbPtr) +{ + CASTER_BOLT_BEHAV_BLOCK* behav; + PREDATOR_ENERGY_BOLT_SAVE_BLOCK* block; + + behav = (CASTER_BOLT_BEHAV_BLOCK*) sbPtr->SBdataptr; + GET_STRATEGY_SAVE_BLOCK(block,sbPtr); + + COPYELEMENT_SAVE(counter) + COPYELEMENT_SAVE(player) + COPYELEMENT_SAVE(damage) + COPYELEMENT_SAVE(blast_radius) + + block->dynamics = *sbPtr->DynPtr; + block->dynamics.CollisionReportPtr=0; + +} diff --git a/3dc/avp/bh_weap.h b/3dc/avp/bh_weap.h new file mode 100644 index 0000000..3cf575e --- /dev/null +++ b/3dc/avp/bh_weap.h @@ -0,0 +1,196 @@ + +/***** bh_weap.h *****/ + +#include "particle.h" + +extern void FireProjectileAmmo(enum AMMO_ID AmmoID); +extern void FrisbeeBehaviour(STRATEGYBLOCK *sbPtr); +extern void RocketBehaviour(STRATEGYBLOCK *sbPtr); +extern void GrenadeBehaviour(STRATEGYBLOCK *sbPtr); +extern void MolotovBehaviour(STRATEGYBLOCK *sbPtr); +extern void PulseGrenadeBehaviour(STRATEGYBLOCK *sbPtr); +extern void ProximityGrenadeBehaviour(STRATEGYBLOCK *sbPtr); +extern void FlareGrenadeBehaviour(STRATEGYBLOCK *sbPtr); +extern void ClusterGrenadeBehaviour(STRATEGYBLOCK *sbPtr); +extern void XenoborgEnergyBoltBehaviour(STRATEGYBLOCK *sbPtr); +extern void PredatorEnergyBoltBehaviour(STRATEGYBLOCK *sbPtr); +extern void AlienSpitBehaviour(STRATEGYBLOCK *sbPtr); +extern void NPCDiscBehaviour(STRATEGYBLOCK *sbPtr); +extern void DiscBehaviour_SeekTrack(STRATEGYBLOCK *sbPtr); +extern void PPPlasmaBoltBehaviour(STRATEGYBLOCK *sbPtr); +extern void SpeargunBoltBehaviour(STRATEGYBLOCK *sbPtr); +extern void FireFlameThrower(VECTORCH *position,VECTORCH *base_offset,MATRIXCH *orientmat, int player, int *timer); +extern void FireNetGhostFlameThrower(VECTORCH *positionPtr, MATRIXCH *orientMatPtr); +extern DISPLAYBLOCK *SpawnMolotovCocktail(SECTION_DATA *root, MATRIXCH *master_orient); +void Convert_Disc_To_Pickup(STRATEGYBLOCK *sbPtr); +void FirePredPistolFlechettes(VECTORCH *base_position,VECTORCH *base_offset,MATRIXCH *orientmat,int player,int *timer,BOOL damaging); +extern void FrisbeeEnergyBoltBehaviour(STRATEGYBLOCK *sbPtr); + +extern int SBIsEnvironment(STRATEGYBLOCK *sbPtr); + +typedef struct OneShotBehaviourType +{ + int counter; +} ONE_SHOT_BEHAV_BLOCK; + +typedef struct PredPistolBehaviourType +{ + int counter; + int player; +} PREDPISTOL_BEHAV_BLOCK; + +typedef struct GrenadeBehaviourType +{ + int counter; + int bouncelastframe; +} GRENADE_BEHAV_BLOCK; + +typedef struct +{ + int LifeTimeRemaining; + int ParticleGenerationTimer; + int SoundHandle; + + /* + becomeStuck set when flare hits wall. + gets reset once a network message about it has been sent + */ + unsigned int becomeStuck:1; + +} FLARE_BEHAV_BLOCK; + +typedef struct +{ + int LifeTimeRemaining; + int SoundGenerationTimer; + int SoundHandle; + +} PROX_GRENADE_BEHAV_BLOCK; + +typedef struct CasterBoltBehaviourType +{ + int counter; + DAMAGE_PROFILE damage; + int blast_radius; + int player; + int soundHandle; +} CASTER_BOLT_BEHAV_BLOCK; + +typedef struct MolotovBehaviourType { + int counter; + HMODELCONTROLLER HModelController; +} MOLOTOV_BEHAV_BLOCK; + +typedef struct FrisbeeBehaviourType +{ + int counter; + HMODELCONTROLLER HModelController; + int soundHandle; + int Bounced :1; + int bounces; + + LASER_BEAM_DESC Laser; + +} FRISBEE_BEHAV_BLOCK; + +typedef struct PCPredDiscBehaviourType +{ + int counter; + STRATEGYBLOCK *Target; + char Target_SBname[SB_NAME_LENGTH]; + char Prev_Target_SBname[SB_NAME_LENGTH]; + char Prev_Damaged_SBname[SB_NAME_LENGTH]; + HMODELCONTROLLER HModelController; + int soundHandle; + int Destruct:1; + int Stuck :1; + int Bounced :1; + int bounces; + + +} PC_PRED_DISC_BEHAV_BLOCK; + +typedef struct SpearBehaviourType +{ + int counter; + MATRIXCH Orient; + VECTORCH Position; + HMODELCONTROLLER HierarchicalFragment; + int Android; + + /* behaviour type of parent object, e.g. I_BehaviourAlien */ + AVP_BEHAVIOUR_TYPE Type; + int SubType; + + unsigned int SpearThroughFragment; + unsigned int Stuck :1; + +} SPEAR_BEHAV_BLOCK; + +#define FLARE_LIFETIME 16 +#define FLARE_PARTICLE_GENERATION_TIME (ONE_FIXED/120) + +#define FRAG_LIFETIME 65536 + +#if SupportWindows95 + #define NO_OF_FRAGS_IN_CLUSTER_BOMB 6 +#else + #define NO_OF_FRAGS_IN_CLUSTER_BOMB 4 +#endif + + +#define PROX_GRENADE_TRIGGER_TIME (ONE_FIXED/4) +#define PROX_GRENADE_RANGE (4000) +#define PROX_GRENADE_SOUND_GENERATION_TIME 65536 +#define PROX_GRENADE_LIFETIME (20) + + + +/* KJL 17:46:30 02/24/97 - below is some old stuff I'll leave for reference */ +#if 0 +extern void FlameProjectileFunction(STRATEGYBLOCK *sptr); +extern void GrenadeBehaviour(STRATEGYBLOCK *sptr); +extern void TOWMissileBehaviour(STRATEGYBLOCK *sptr); +extern void PredatorDiscBehaviour(STRATEGYBLOCK *sptr); + +typedef struct OneShotBehaviourType { + + AVP_BEHAVIOUR_TYPE bhvr_type; + VECTORCH ObWorld; + int counter; + + } ONE_SHOT_BEHAV_BLOCK; + +typedef struct FlameProjectileBehaviourType { + + AVP_BEHAVIOUR_TYPE bhvr_type; + VECTORCH ObWorld; + int counter; +#if SupportMorphing + MORPHCTRL *FPmctrl; +#endif + +} FLAME_PROJ_BEHAV_BLOCK; + +typedef struct TowMissileBehaviourType { + + AVP_BEHAVIOUR_TYPE bhvr_type; + VECTORCH ObWorld; + VECTORCH Target; + int counter; + +} TOW_MISSILE_BEHAV_BLOCK; + +typedef struct PredatorDiscBehaviourType { + + AVP_BEHAVIOUR_TYPE bhvr_type; + VECTORCH ObWorld; + VECTORCH Target; + STRATEGYBLOCK *MovingTarget; + int counter; + int retargetcounter; + int phase; + +} PRED_DISC_BEHAV_BLOCK; + +#endif \ No newline at end of file diff --git a/3dc/avp/cconvars.cpp b/3dc/avp/cconvars.cpp new file mode 100644 index 0000000..867ccec --- /dev/null +++ b/3dc/avp/cconvars.cpp @@ -0,0 +1,1292 @@ +/* KJL 11:10:15 28/01/98 - + + This file contains game-specific console variables + + */ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "davehook.h" +#include "r2base.h" +#include "gadget.h" +#include "daemon.h" +#include "rentrntq.h" + +#include "bh_types.h" +#include "consvar.hpp" +#include "conscmnd.hpp" +#include "equipmnt.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "weapons.h" +#include "bh_queen.h" +#include "bh_gener.h" +#include "dxlog.h" +#include "avp_menus.h" +#include "pheromon.h" +#include "ShowCmds.h" +#include "pfarlocs.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +#include "game_statistics.h" +#include "AvP_EnvInfo.h" +#include "AvP_UserProfile.h" + +extern "C" +{ + +extern int Simplify_HModel_Rendering; + +extern int TrickleCharge; +extern int CloakDrain; +extern int CloakThreshold; +extern int CloakPowerOnDrain; +extern int GlobalGoreRate; +extern int PredPistol_ShotCost; +extern int PredPistolBoltSpeed; +extern int PredPistolBoltGravity; +extern int Caster_Jumpstart; +extern int Caster_Chargetime; +extern int Caster_TrickleRate; +extern int Caster_TrickleLevel; +extern int Caster_ChargeRatio; +extern int Caster_NPCKill; +extern int Caster_PCKill; +extern int Caster_BlastRadius; +extern int Caster_MinCharge; +extern int RecallDisc_Charge; +extern void Recall_Disc(void); + +extern int Marine_Skill; +extern int Marine_Terminal_Velocity; + +extern int ShowPredoStats; +extern int ShowSquadState; +extern int ShowNearSquad; +extern int ShowHiveState; +extern int ShowXenoStats; +extern int ShowSlack; +extern void ActivateHive(void); +extern void DeActivateHive(void); +extern void ForceAGenerator_Shell(void); +extern void StrikeTime(int time); +extern void AlienStrikeTime(int time); +extern void CastSentrygun(void); +extern void CastDummy(void); +extern void StartPlayerTaunt(void); +extern void Console_ZoneAlert(int input); +extern void ZapSlack(void); +/* Queen commands */ +extern int Queen_Charge_Rate; +extern int Queen_Step_Time; +extern int Queen_Step_Speed; +extern int Queen_Step_Mode; +extern int Queen_Turn_Rate; +extern void QComm_Stop(void); +extern void QComm_StepForward(void); +extern void QComm_StepBack(void); +extern void QComm_TurnLeft(void); +extern void QComm_TurnRight(void); +extern void QComm_Heel(void); +extern void QComm_Taunt(void); +extern void QComm_Hiss(void); +extern void QComm_LeftSwipe(void); +extern void QComm_RightSwipe(void); +extern void QComm_Route(void); +extern void QComm_Charge(void); +/* Tail calibration */ +extern int tail_xcal; +extern int tail_ycal; +/* Molotov Callibration! */ +extern int mx,my,mz; + +extern int RATweak; + +extern TEMPLATE_WEAPON_DATA TemplateWeapon[MAX_NO_OF_WEAPON_TEMPLATES]; +extern void NewOnScreenMessage(unsigned char *messagePtr); + +extern int GlobalAmbience; +int Old_GlobalAmbience=ONE_FIXED; + +int ShowAdj=0; + +char ccv_tempstring[128]; + +void Toggle_Ambience(void) { + + int buffer; + + buffer=GlobalAmbience; + GlobalAmbience=Old_GlobalAmbience; + Old_GlobalAmbience=buffer; + +} + +void ActivateAllGenerators(void) { + int a; + STRATEGYBLOCK *candidate; + + for (a=0; aI_SBtype==I_BehaviourGenerator) { + GENERATOR_BLOCK *genBlock; + + genBlock=(GENERATOR_BLOCK *)candidate->SBdataptr; + genBlock->Active=1; + } + } +} + +void KillAllInanimates(void) { + int a; + STRATEGYBLOCK *candidate; + + for (a=0; aI_SBtype==I_BehaviourInanimateObject) { + candidate->SBflags.please_destroy_me=1; + } + } +} + +void KillAllMarines(void) { + int a; + STRATEGYBLOCK *candidate; + + for (a=0; aI_SBtype==I_BehaviourMarine) + ||(candidate->I_SBtype==I_BehaviourSeal)) { + CauseDamageToObject(candidate,&console_nuke,ONE_FIXED,NULL); + } + } +} + +void KillAllAliens(void) { + int a; + STRATEGYBLOCK *candidate; + + for (a=0; aI_SBtype==I_BehaviourAlien) { + CauseDamageToObject(candidate,&console_nuke,ONE_FIXED,NULL); + } + } +} + +void KillAllPreds(void) { + int a; + STRATEGYBLOCK *candidate; + + for (a=0; aI_SBtype==I_BehaviourPredator) { + CauseDamageToObject(candidate,&console_nuke,ONE_FIXED,NULL); + } + } +} + +void KillAllDummies(void) { + int a; + STRATEGYBLOCK *candidate; + + for (a=0; aI_SBtype==I_BehaviourDummy) { + DestroyAnyStrategyBlock(candidate); + } + } +} + +void ToggleShapeRender(void) { + Simplify_HModel_Rendering=(~Simplify_HModel_Rendering); +} + +void Show_PredOStats(void) { + ShowPredoStats=(~ShowPredoStats); +} + +void Show_XenoStats(void) { + ShowXenoStats=(~ShowXenoStats); +} + +void Show_SquadState(void) { + ShowSquadState=(~ShowSquadState); +} + +void Show_NearSquad(void) { + ShowNearSquad=(~ShowNearSquad); +} + +void Show_HiveState(void) { + ShowHiveState=(~ShowHiveState); +} + +void Show_Slack(void) { + ShowSlack=(~ShowSlack); +} + +void Show_Adj(void) { + ShowAdj=(~ShowAdj); +} + +void Toggle_Observer(void) { + Observer=(~Observer); +} + +void ShowRecoilMaxXTilt(void) { + + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + sprintf(ccv_tempstring,"RECOILMAXXTILT = %d\n",twPtr->RecoilMaxXTilt); + + NewOnScreenMessage((unsigned char *)&ccv_tempstring[0]); +} + +void ShowRecoilMaxYTilt(void) { + + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + sprintf(ccv_tempstring,"RECOILMAXYTILT = %d\n",twPtr->RecoilMaxYTilt); + + NewOnScreenMessage((unsigned char *)&ccv_tempstring[0]); +} + +void ShowRecoilMaxZ(void) { + + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + sprintf(ccv_tempstring,"RECOILMAXZ = %d\n",twPtr->RecoilMaxZ); + + NewOnScreenMessage((unsigned char *)&ccv_tempstring[0]); +} + +void ShowRecoilMaxRandomZ(void) { + + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + sprintf(ccv_tempstring,"RECOILMAXRANDOMZ = %d\n",twPtr->RecoilMaxRandomZ); + + NewOnScreenMessage((unsigned char *)&ccv_tempstring[0]); +} + +void SetRecoilMaxXTilt(int value) { + + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + twPtr->RecoilMaxXTilt=value; + + sprintf(ccv_tempstring,"RECOILMAXXTILT = %d\n",twPtr->RecoilMaxXTilt); + + NewOnScreenMessage((unsigned char *)&ccv_tempstring[0]); +} + +void SetRecoilMaxYTilt(int value) { + + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + twPtr->RecoilMaxYTilt=value; + + sprintf(ccv_tempstring,"RECOILMAXYTILT = %d\n",twPtr->RecoilMaxYTilt); + + NewOnScreenMessage((unsigned char *)&ccv_tempstring[0]); +} + +void SetRecoilMaxZ(int value) { + + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + twPtr->RecoilMaxZ=value; + + sprintf(ccv_tempstring,"RECOILMAXZ = %d\n",twPtr->RecoilMaxZ); + + NewOnScreenMessage((unsigned char *)&ccv_tempstring[0]); +} + +void SetRecoilMaxRandomZ(int value) { + + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + GLOBALASSERT(playerStatusPtr); + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + twPtr->RecoilMaxRandomZ=value; + + sprintf(ccv_tempstring,"RECOILMAXRANDOMZ = %d\n",twPtr->RecoilMaxRandomZ); + + NewOnScreenMessage((unsigned char *)&ccv_tempstring[0]); +} + +void SetPredPistolRecoilTime(int value) { + + TEMPLATE_WEAPON_DATA *twPtr; + int timeOutRate; + + twPtr = &TemplateWeapon[WEAPON_PRED_PISTOL]; + + if (value==0) { + int time; + + GLOBALASSERT(twPtr->TimeOutRateForState[WEAPONSTATE_RECOIL_PRIMARY]); + time=DIV_FIXED(ONE_FIXED,twPtr->TimeOutRateForState[WEAPONSTATE_RECOIL_PRIMARY]); + sprintf(ccv_tempstring,"PREDPISTOL_RECOILTIME = %d\n",time); + + NewOnScreenMessage((unsigned char *)&ccv_tempstring[0]); + return; + } + + timeOutRate=DIV_FIXED(ONE_FIXED,value); + + twPtr->TimeOutRateForState[WEAPONSTATE_RECOIL_PRIMARY]=timeOutRate; + +} + +void SetPredPistolMaxDamage(int value) { + + if (value<0) { + sprintf(ccv_tempstring,"PREDPISTOL_BLASTDAMAGE = %d\n",TemplateAmmo[AMMO_PRED_PISTOL].MaxDamage[AvP.Difficulty].Electrical); + + NewOnScreenMessage((unsigned char *)&ccv_tempstring[0]); + return; + } + + if (value>1000) return; + + TemplateAmmo[AMMO_PRED_PISTOL].MaxDamage[AvP.Difficulty].Electrical=value; + +} + +void SetPredPistolBlastRange(int value) { + + if (value<0) { + sprintf(ccv_tempstring,"PREDPISTOL_BLASTRANGE = %d\n",TemplateAmmo[AMMO_PRED_PISTOL].MaxRange); + + NewOnScreenMessage((unsigned char *)&ccv_tempstring[0]); + return; + } + + if (value>65536) return; + + TemplateAmmo[AMMO_PRED_PISTOL].MaxRange=value; + +} + +void SetPredPistolStrikeDamage(int value) { + + if (value<0) { + sprintf(ccv_tempstring,"PREDPISTOL_STRIKEDAMAGE = %d\n",TemplateAmmo[AMMO_PREDPISTOL_STRIKE].MaxDamage[AvP.Difficulty].Electrical); + + NewOnScreenMessage((unsigned char *)&ccv_tempstring[0]); + return; + } + + if (value>1000) return; + + TemplateAmmo[AMMO_PREDPISTOL_STRIKE].MaxDamage[AvP.Difficulty].Electrical=value; + +} + +void PredPistol_FullAuto(void) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[WEAPON_PRED_PISTOL]; + + twPtr->PrimaryIsAutomatic=1; + +} + +void PredPistol_SemiAuto(void) { + + TEMPLATE_WEAPON_DATA *twPtr; + + twPtr = &TemplateWeapon[WEAPON_PRED_PISTOL]; + + twPtr->PrimaryIsAutomatic=0; + +} + +void SetPlayerStartingHealth(int value) { + + NPC_DATA *NpcData; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + switch (AvP.PlayerType) + { + case I_Marine: + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Marine_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Marine_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Marine_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Marine_Impossible); + break; + } + break; + case I_Alien: + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Alien_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Alien_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Alien_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Alien_Impossible); + break; + } + break; + default: + LOCALASSERT(0); + } + GLOBALASSERT(NpcData); + + if (value<=0) { + sprintf(ccv_tempstring,"PLAYER STARTING HEALTH = %d\n",NpcData->StartingStats.Health); + + NewOnScreenMessage((unsigned char *)&ccv_tempstring[0]); + return; + } + + if (value>1000) return; + + NpcData->StartingStats.Health=value; + + Player->ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<Health=Player->ObStrategyBlock->SBDamageBlock.Health; + +} + +void SetPlayerStartingArmour(int value) { + + NPC_DATA *NpcData; + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + switch (AvP.PlayerType) + { + case I_Marine: + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Marine_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Marine_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Marine_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Marine_Impossible); + break; + } + break; + case I_Alien: + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Alien_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Alien_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Alien_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Alien_Impossible); + break; + } + break; + default: + LOCALASSERT(0); + } + GLOBALASSERT(NpcData); + + if (value<=0) { + sprintf(ccv_tempstring,"PLAYER STARTING ARMOUR = %d\n",NpcData->StartingStats.Armour); + + NewOnScreenMessage((unsigned char *)&ccv_tempstring[0]); + return; + } + + if (value>1000) return; + + NpcData->StartingStats.Armour=value; + + Player->ObStrategyBlock->SBDamageBlock.Armour=NpcData->StartingStats.Armour<Armour=Player->ObStrategyBlock->SBDamageBlock.Armour; + +} + +void ResetPersonalBests(void) { + + { + int a,b; + + for (a=0; aPersonalBests[a][b]=DefaultLevelGameStats; + } + } + } + +} + +void CreateMoreGameSpecificConsoleVariables(void) +{ + #if CONSOLE_DEBUGGING_COMMANDS_ACTIVATED + /* Calibrate Tail Hack */ + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + tail_xcal, // int& Value_ToUse, + "TAIL-XCAL", // ProjChar* pProjCh_ToUse, + "CLASSIFIED", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1000 // int MaxVal_New + ); + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + tail_ycal, // int& Value_ToUse, + "TAIL-YCAL", // ProjChar* pProjCh_ToUse, + "CLASSIFIED", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1000 // int MaxVal_New + ); + + #if 0 + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + RATweak, // int& Value_ToUse, + "RATWEAK", // ProjChar* pProjCh_ToUse, + "CLASSIFIED", // ProjChar* pProjCh_Description_ToUse + -512, // int MinVal_New, + 512 // int MaxVal_New + ); + #endif + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + GlobalGoreRate, // int& Value_ToUse, + "GLOBALGORERATE", // ProjChar* pProjCh_ToUse, + "(TAKES VALUES 0 -> 65536, LESS IS MORE: 0 = DISABLED)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 65536 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Marine_Skill, // int& Value_ToUse, + "MARINE-SKILL", // ProjChar* pProjCh_ToUse, + "(NPC SKILL, 65536 WILL RARELY MISS)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 131072 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Marine_Terminal_Velocity, // int& Value_ToUse, + "MARINE-TERMINAL-VELOCITY", // ProjChar* pProjCh_ToUse, + "(SPEED WHICH KILLS A FALLING MARINE)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 131072 // int MaxVal_New + ); + + /* Cloaking */ + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + TrickleCharge, // int& Value_ToUse, + "TRICKLECHARGE", // ProjChar* pProjCh_ToUse, + "(PRED TRICKLE CHARGE RATE)", // ProjChar* pProjCh_Description_ToUse + -131072, // int MinVal_New, + 131072 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + CloakDrain, // int& Value_ToUse, + "CLOAKDRAIN", // ProjChar* pProjCh_ToUse, + "(PRED CLOAK DRAIN RATE)", // ProjChar* pProjCh_Description_ToUse + -131072, // int MinVal_New, + 131072 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + CloakThreshold, // int& Value_ToUse, + "CLOAKTHRESHOLD", // ProjChar* pProjCh_ToUse, + "(CANNOT CLOAK WITHOUT THIS MUCH ENERGY)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + PLAYERCLOAK_MAXENERGY // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + CloakPowerOnDrain, // int& Value_ToUse, + "CLOAKPOWERONDRAIN", // ProjChar* pProjCh_ToUse, + "(CLOAKING USES THIS MUCH POWER)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + PLAYERCLOAK_MAXENERGY // int MaxVal_New + ); + + /* Pred Pistol */ + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + PredPistol_ShotCost, // int& Value_ToUse, + "PREDPISTOL_SHOTCOST", // ProjChar* pProjCh_ToUse, + "(ONE SHOT USES THIS MUCH POWER)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + PLAYERCLOAK_MAXENERGY // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + PredPistolBoltSpeed, // int& Value_ToUse, + "PREDPISTOL_BOLTSPEED", // ProjChar* pProjCh_ToUse, + "(SPEED OF BOLT)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 262144 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + PredPistolBoltGravity, // int& Value_ToUse, + "PREDPISTOL_BOLTGRAVITY", // ProjChar* pProjCh_ToUse, + "(GGRAVITY APPLIED TO BOLT)", // ProjChar* pProjCh_Description_ToUse + -131072, // int MinVal_New, + 131072 // int MaxVal_New + ); + + ConsoleCommand :: Make + ( + "RESET_PERSONAL_BESTS", + "RESETS PERSONAL BESTS STRUCTURES", + ResetPersonalBests + ); + + ConsoleCommand :: Make + ( + "PREDPISTOL_BLASTRANGE", + "ALTERS PRED PISTOL EXPLOSIVE RANGE", + SetPredPistolBlastRange + ); + + ConsoleCommand :: Make + ( + "PREDPISTOL_BLASTDAMAGE", + "ALTERS PRED PISTOL EXPLOSIVE DAMAGE", + SetPredPistolMaxDamage + ); + + ConsoleCommand :: Make + ( + "PREDPISTOL_STRIKEDAMAGE", + "ALTERS PRED PISTOL DIRECT DAMAGE", + SetPredPistolStrikeDamage + ); + + ConsoleCommand :: Make + ( + "PREDPISTOL_RECOILTIME", + "ALTERS PRED PISTOL RECOIL TIME", + SetPredPistolRecoilTime + ); + + ConsoleCommand :: Make + ( + "PREDPISTOL_FULLAUTO", + "MAKES PRED PISTOL FULLY AUTOMATIC", + PredPistol_FullAuto + ); + + ConsoleCommand :: Make + ( + "PREDPISTOL_SEMIAUTO", + "MAKES PRED PISTOL SEMI AUTOMATIC", + PredPistol_SemiAuto + ); + + /* Plasmacaster */ + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Caster_Jumpstart, // int& Value_ToUse, + "CASTER_JUMPSTART", // ProjChar* pProjCh_ToUse, + "(INSTANT CHARGE WHEN FIRED)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 65536 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Caster_Chargetime, // int& Value_ToUse, + "CASTER_CHARGETIME", // ProjChar* pProjCh_ToUse, + "(TIME TO CHARGE UP WITH FIRE)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + (65536*60) // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Caster_TrickleRate, // int& Value_ToUse, + "CASTER_TRICKLERATE", // ProjChar* pProjCh_ToUse, + "(ONE FIXED PER SECOND)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 65536 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Caster_TrickleLevel, // int& Value_ToUse, + "CASTER_TRICKLELEVEL", // ProjChar* pProjCh_ToUse, + "(TRICKLES TO THIS LEVEL)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 65536 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Caster_ChargeRatio, // int& Value_ToUse, + "CASTER_CHARGERATIO", // ProjChar* pProjCh_ToUse, + "(FIELD CHARGE FOR A FULL SHOT)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + (65536*30) // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Caster_NPCKill, // int& Value_ToUse, + "CASTER_NPCKILL", // ProjChar* pProjCh_ToUse, + "(CASTER CHARGE TO KILL AN NPC)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 65536 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Caster_PCKill, // int& Value_ToUse, + "CASTER_PCKILL", // ProjChar* pProjCh_ToUse, + "(CASTER CHARGE TO KILL A PC)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 65536 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Caster_BlastRadius, // int& Value_ToUse, + "CASTER_BLASTRADIUS", // ProjChar* pProjCh_ToUse, + "(BLAST RADIUS OF A FULL BOLT)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 65536 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Caster_MinCharge, // int& Value_ToUse, + "CASTER_MINCHARGE", // ProjChar* pProjCh_ToUse, + "(MINIMUM CASTER CHARGE TO FIRE)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 65536 // int MaxVal_New + ); + + /* Disc */ + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + RecallDisc_Charge, // int& Value_ToUse, + "RECALL_DISC_CHARGE", // ProjChar* pProjCh_ToUse, + "(COST TO RECALL A DISC)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + PLAYERCLOAK_MAXENERGY // int MaxVal_New + ); + + ConsoleCommand :: Make + ( + "RECALL_DISC", + "RECALLS A STUCK DISC", + Recall_Disc + ); + + /* Player Stats */ + + ConsoleCommand :: Make + ( + "PLAYER_STARTING_HEALTH", + "CHANGES CURRENT PLAYER STARTING HEALTH", + SetPlayerStartingHealth + ); + + ConsoleCommand :: Make + ( + "PLAYER_STARTING_ARMOUR", + "CHANGES CURRENT PLAYER STARTING ARMOUR", + SetPlayerStartingArmour + ); + + /* Debugging */ + #if 1 + ConsoleCommand :: Make + ( + "TOGGLE_SHAPERENDER", + "SWITCHES ALL HIERARCHY SECTIONS FOR SHELLS", + ToggleShapeRender + ); + #endif + /* TEMPORARY */ + ConsoleCommand :: Make + ( + "STRIKETIME", + "ALTERS WRISTBLADE STRIKE TIME", + StrikeTime + ); + + ConsoleCommand :: Make + ( + "ALIEN-STRIKETIME", + "ALTERS ALIEN CLAW STRIKE TIME", + AlienStrikeTime + ); + + ConsoleCommand :: Make + ( + "SHOWPREDOSTATS", + "TOGGLES PREDATOR ENERGY PRINT", + Show_PredOStats + ); + + ConsoleCommand :: Make + ( + "SHOWXENOSTATS", + "TOGGLES XENOBORG BEHAVIOUR PRINT", + Show_XenoStats + ); + + + ConsoleCommand :: Make + ( + "SHOWSQUADSTATE", + "TOGGLES MARINE SQUAD STATUS PRINT", + Show_SquadState + ); + + ConsoleCommand :: Make + ( + "SHOWNEARSQUAD", + "TOGGLES NEAR MARINE STATUS PRINT", + Show_NearSquad + ); + + ConsoleCommand :: Make + ( + "SHOWHIVESTATE", + "TOGGLES HIVE STATUS PRINT", + Show_HiveState + ); + #if 0 + ConsoleCommand :: Make + ( + "TOGGLEAMBIENCE", + "TOGGLES THE AMBIENT LIGHT", + Toggle_Ambience + ); + #endif + ConsoleCommand :: Make + ( + "SHOWSLACK", + "TOGGLES SLACK STATUS PRINT", + Show_Slack + ); + + ConsoleCommand :: Make + ( + "SHOWADJACENCIES", + "TOGGLES ADJACENCY STATUS PRINT", + Show_Adj + ); + + ConsoleCommand :: Make + ( + "ZAPSLACK", + "ZEROES SLACK COUNTERS", + ZapSlack + ); + + ConsoleCommand :: Make + ( + "ZONEALERT", + "TRIGGERS A MARINE ALERT", + Console_ZoneAlert + ); + /* TEMPORARY */ + + ConsoleCommand :: Make + ( + "TAUNT", + "STARTS TAUNT SEQUENCE", + StartPlayerTaunt + ); + + ConsoleCommand :: Make + ( + "ACTIVATE-HIVE", + "ACTIVATES ALIEN/NPC HIVE", + ActivateHive + ); + + ConsoleCommand :: Make + ( + "DEACTIVATE-HIVE", + "DEACTIVATES ALIEN/NPC HIVE", + DeActivateHive + ); + + ConsoleCommand :: Make + ( + "FORCEGEN", + "FORCES GENERATION OF AN NPC - SOMEWHERE", + ForceAGenerator_Shell + ); + + ConsoleCommand :: Make + ( + "DUMMY", + "CREATES PLAYER DUMMY.", + CastDummy + ); + + #if 0 + ConsoleCommand :: Make + ( + "SENTRYGUN", + "DROPS A SENTRY GUN", + CastSentrygun + ); + #endif + ConsoleCommand :: Make + ( + "ACTIVATE_GENERATORS", + "ACTIVATES ALL GENERATORS.", + ActivateAllGenerators + ); + + ConsoleCommand :: Make + ( + "NUKEINANIMATES", + "DESTROYS ALL INANIMATE OBJECTS.", + KillAllInanimates + ); + + ConsoleCommand :: Make + ( + "NUKEMARINES", + "KILLS ALL MARINES.", + KillAllMarines + ); + + ConsoleCommand :: Make + ( + "NUKEALIENS", + "KILLS ALL ALIENS.", + KillAllAliens + ); + + ConsoleCommand :: Make + ( + "NUKEPREDS", + "KILLS ALL PREDATORS.", + KillAllPreds + ); + + ConsoleCommand :: Make + ( + "NUKEDUMMIES", + "KILLS ALL PLAYER DUMMIES.", + KillAllDummies + ); + + ConsoleCommand :: Make + ( + "OBSERVER", + "TOGGLES OBSERVER MODE.", + Toggle_Observer + ); + + ConsoleCommand :: Make + ( + "SHOWRECOILMAXXTILT", + "SHOWS THAT VALUE.", + ShowRecoilMaxXTilt + ); + + ConsoleCommand :: Make + ( + "SHOWRECOILMAXYTILT", + "SHOWS THAT VALUE.", + ShowRecoilMaxYTilt + ); + + ConsoleCommand :: Make + ( + "SHOWRECOILMAXZ", + "SHOWS THAT VALUE.", + ShowRecoilMaxZ + ); + + ConsoleCommand :: Make + ( + "SHOWRECOILMAXRANDOMZ", + "SHOWS THAT VALUE.", + ShowRecoilMaxRandomZ + ); + + ConsoleCommand :: Make + ( + "SETRECOILMAXXTILT", + "SETS THAT VALUE.", + SetRecoilMaxXTilt + ); + + ConsoleCommand :: Make + ( + "SETRECOILMAXYTILT", + "SETS THAT VALUE.", + SetRecoilMaxYTilt + ); + + ConsoleCommand :: Make + ( + "SETRECOILMAXZ", + "SETS THAT VALUE.", + SetRecoilMaxZ + ); + + ConsoleCommand :: Make + ( + "SETRECOILMAXRANDOMZ", + "SETS THAT VALUE.", + SetRecoilMaxRandomZ + ); + + #if 0 + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + mx, + "MX", + "MOLOTOV X IMPULSE", + -ONE_FIXED, + ONE_FIXED + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + my, + "MY", + "MOLOTOV Y IMPULSE", + -ONE_FIXED, + ONE_FIXED + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + mz, + "MZ", + "MOLOTOV Z IMPULSE", + -ONE_FIXED, + ONE_FIXED + ); + #endif + + #if 0 + /* Queen commands */ + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Queen_Step_Time, + "QSTEP-TIME", + "QUEEN STEP FORWARD TIME", + 0, + (ONE_FIXED<<8) + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Queen_Charge_Rate, + "QCHARGE_RATE", + "QUEEN CHARGE PACE", + 0, + (ONE_FIXED<<8) + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Queen_Step_Speed, + "QSTEP-SPEED", + "QUEEN STEP FORWARD SPEED", + 0, + (ONE_FIXED) + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Queen_Step_Mode, + "QSTEP-MODE", + "QUEEN STEP FORWARD MODE", + 0, + 1 + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + Queen_Turn_Rate, + "QTURN-RATE", + "QUEEN TURN RATE", + 0, + 65536 + ); + + ConsoleCommand :: Make + ( + "QCOMM-STOP", + "STOPS SLAVE QUEEN.", + QComm_Stop + ); + + ConsoleCommand :: Make + ( + "QCOMM-SF", + "ORDERS SLAVE QUEEN ONE STEP FORWARD.", + QComm_StepForward + ); + + ConsoleCommand :: Make + ( + "QCOMM-SB", + "ORDERS SLAVE QUEEN ONE STEP Back.", + QComm_StepBack + ); + + ConsoleCommand :: Make + ( + "QCOMM-TL", + "ORDERS SLAVE QUEEN TO TURN LEFT.", + QComm_TurnLeft + ); + + ConsoleCommand :: Make + ( + "QCOMM-TR", + "ORDERS SLAVE QUEEN TO TURN RIGHT.", + QComm_TurnRight + ); + + ConsoleCommand :: Make + ( + "QCOMM-HEEL", + "ORDERS SLAVE QUEEN TO COME TO PLAYER.", + QComm_Heel + ); + + ConsoleCommand :: Make + ( + "QCOMM-TAUNT", + "ORDERS SLAVE QUEEN TO TAUNT.", + QComm_Taunt + ); + + ConsoleCommand :: Make + ( + "QCOMM-HISS", + "ORDERS SLAVE QUEEN TO HISS.", + QComm_Hiss + ); + + ConsoleCommand :: Make + ( + "QCOMM-LS", + "ORDERS SLAVE QUEEN TO SWIPE (LEFT).", + QComm_LeftSwipe + ); + + ConsoleCommand :: Make + ( + "QCOMM-RS", + "ORDERS SLAVE QUEEN TO SWIPE (Right).", + QComm_RightSwipe + ); + + ConsoleCommand :: Make + ( + "QCOMM-ROUTE", + "ORDERS SLAVE QUEEN TO FOLLOW THE PROGRAMMED ROUTE.", + QComm_Route + ); + + ConsoleCommand :: Make + ( + "QCOMM-CHARGE", + "ORDERS SLAVE QUEEN TO CHARGE.", + QComm_Charge + ); + #endif + + #endif +} + +}; // extern "C" + diff --git a/3dc/avp/comp_map.c b/3dc/avp/comp_map.c new file mode 100644 index 0000000..ec68781 --- /dev/null +++ b/3dc/avp/comp_map.c @@ -0,0 +1,521 @@ +#include "3dc.h" +#include "module.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "comp_shp.h" + +#define UseLocalAssert Yes + +#include "ourasert.h" + +extern SHAPEHEADER ** mainshapelist; + +extern MAPBLOCK8 Player_and_Camera_Type8[]; +extern MAPBLOCK6 Empty_Object_Type6; +extern MAPBLOCK6 Term_Type6; + +extern MODULEMAPBLOCK AvpCompiledMaps[]; + +MAPHEADER Map[]={ + + 0, + 0, + 0, + 0, + 0, + 0, + 0, + &Player_and_Camera_Type8[0], +}; + + +MAPSETVDB chnk_playcam_vdb = { + + ViewDB_Flag_AdjustScale +// | ViewDB_Flag_Hazing + | ViewDB_Flag_AddSubject + | ViewDB_Flag_ImageBackdrop + | ViewDB_Flag_FullSize, + + 0, + 0, + + 0, + 0, + + 0, + 0, + 0, + + 0, + 0, + 0, + 0, + + 5000, /* Hazing in */ + 30000, /*+ (ONE_FIXED << 0), hazing end */ + 0, + + /*col24(200,200,200),*/ /* Background Colour */ + /*col24(32,128,255),*/ /* Background Colour */ + 0, /* Background Colour */ + /*col24(0,0,0),*/ /* Background Colour */ + /*col24(255,0,0),*/ /* Background Colour */ + + 65536 >> 2 , /* Ambience */ + + #if 0 + VState_RelativeYRemote, /* View State */ + 2/*-1*/, /* View Distance */ + 0,0, /* Pan X,Y */ + #endif + +#if 1 + VState_Inside, /* View State */ + 1, /* View Distance */ + 0,0, /* Pan X,Y */ +#endif + +}; + + + + +/****************************************************************************/ + +MAPBLOCK6 Empty_Landscape_Type6 = { + + + MapType_Default, + + -1, /* No shape */ + + 0,0,0, /* Loc */ + 0,0,0, /* Orient */ + + ObFlag_MultLSrc + /*| ObFlag_BFCRO*/ + | ObFlag_VertexHazing + /* Hack CONSTANTINE */ + /* | ObFlag_SortFarZ */ + /*| ObFlag_RSP*/ + /*| ObFlag_NotVis*/ + /*| ObFlag_NoColls*/, /* Flags */ + + #if StandardStrategyAndCollisions + StrategyI_Null, /* Strategy */ + CollType_Landscape,/* e.g. Shape or Landscape */ + GameCollStrat_Default, /* Game Collision Strategy */ + 0, /* Shape Collision Strategy */ + 0, /* Landscape Collision Strategy */ + #endif + + 0, /* VDB Definition */ + 0 /* Interior Type */ + +}; + + + +MAPBLOCK6 Empty_Object_Type6 = { + + + MapType_Default, + + -1, /* No shape */ + + 0,0,0, /* Loc */ + 0,0,0, /* Orient */ + + ObFlag_MultLSrc | + /*| ObFlag_BFCRO*/ + ObFlag_VertexHazing | + /* hack CONSTANTINE */ + /* ObFlag_SortFarZ | */ + /*| ObFlag_RSP*/ + /*| ObFlag_NotVis*/ + /*| ObFlag_NoColls*/ + 0, /* Flags1 (no others in this map type)*/ + + #if StandardStrategyAndCollisions + StrategyI_Null, /* Strategy */ + 0,/* e.g. Shape or Landscape */ + GameCollStrat_Default, /* Game Collision Strategy */ + 0, /* Shape Collision Strategy */ + 0, /* Landscape Collision Strategy */ + #endif + 0, /* VDB Definition */ + 0 /* Interior Type */ + +}; + + +MAPBLOCK6 Term_Type6 = { + +/* map end */ + + MapType_Term, + 0, + 0,0,0, + 0,0,0, + 0, /* Flags */ + + #if StandardStrategyAndCollisions + 0, /* Strategy */ + 0, /* e.g. Shape or Landscape */ + 0, /* Game Collision Strategy */ + 0, /* Shape Collision Strategy */ + 0, /* Landscape Collision Strategy */ + #endif + 0, /* VDB Definition */ + 0, /* Interior Type */ + +}; + +/****************************************************************************/ + + +MAPBLOCK8 Player_and_Camera_Type8[] = { +#if SupportModules + /* Ship */ + + MapType_Player, + + I_ShapeMarinePlayer, /*mainshapelist position 0*/ + + + /* MapType_Camera, */ + + 0, 0, 0, /* Loc */ + 0, 3062, 0, /* Orient */ + + ObFlag_MultLSrc + |0 + |0, + /* Flags 2 */ + 0 + /* | ObFlag2_DirectedMerge */ + /* | ObFlag2_SurfaceAlign*/ + /* | ObFlag2_Augmented_LFR*/ + /* | ObFlag2_LFR_GuessReloc*/ + /* | ObFlag2_LFR_UseFRM*/ + /* | ObFlag2_FRM_VariableR */ + /* | ObFlag2_NoMotionLerp*/ + /*| ObFlag2_NoMerge*/ + /*| ObFlag2_NoMergeDIfNear*/ + /*| ObFlag2_NoMergeD*/ + |0, + + 0 + | 0, /* Flags 3 */ + + #if StandardStrategyAndCollisions + StrategyI_Player, /* Strategy */ + 0, /* e.g. Shape or Landscape */ + GameCollStrat_Default, /* Game Collision Strategy */ + ShapeCStrat_DoubleExtentEllipsoid, /* Shape Collision Strategy */ + 0, /* Landscape Collision Strategy */ + #endif + + &chnk_playcam_vdb, /* VDB Definition */ + IType_Body, /* Interior Type */ + + 0, /* MapLightType */ + #if StandardStrategyAndCollisions + 0, /* MapMass */ + 0,0,0, /* MapNewtonV */ + #endif + 0,0,0, /* MapOrigin */ + + 0, /* MapSimShapes */ + 0, /* MapViewType */ + + 0, /* MapMPtr */ + + 0, /* MapDPtr */ + 0,0,0, /* MapMOffset */ + + +/****************************************************************************/ + + #if 0 + /* Player Ship Camera - MUST be next map object */ + + MapType_PlayerShipCamera, + + I_ShapeCube, /* mainshapelist position 1 */ + + 0,0,0, /* Loc */ + 0,0,0, /* Orient */ + 0 + |0 /* Flags 1 */ + | 0, + + 0, /* Flags 2 */ + 0, /* Flags 3 */ + + #if StandardStrategyAndCollisions + StrategyI_Camera, /* Strategy */ + 0, /* e.g. Shape or Landscape */ + GameCollStrat_Default, /* Game Collision Strategy */ + 0, /* Shape Collision Strategy */ + 0, /* Landscape Collision Strategy */ + #endif + + &chnk_playcam_vdb, /* VDB Definition */ + + #if 0 + + IType_Default, /* Interior Type */ + + #else + + IType_Body, /* Interior Type */ + + #endif + + 0, /* MapLightType */ + + #if StandardStrategyAndCollisions + 0, /* MapMass */ + 0,0,0, /* MapNewtonV */ + #endif + 0,0,0, /* MapOrigin */ + 0, /* MapSimShapes */ + 0, /* MapViewType */ + + 0, /* MapMPtr */ + 0, /* MapDPtr */ + 0,0,0, /* MapMOffset */ + #endif + +/****************************************************************************/ +/****************************************************************************/ + /* Map End */ +#endif /*SupportModules*/ + MapType_Term, /* Map Type Function */ + 0, /* Shape */ + 0,0,0, /* Loc */ + 0,0,0, /* Orient */ + 0, /* Flags 1 */ + 0, /* Flags 2 */ + 0, /* Flags 3 */ + #if StandardStrategyAndCollisions + 0, /* Strategy */ + 0, /* e.g. Shape or Landscape */ + 0, /* Game Collision Strategy */ + 0, /* Shape Collision Strategy */ + 0, /* Landscape Collision Strategy */ + #endif + 0, /* VDB Definition */ + 0, /* Interior Type */ + 0, /* MapLightType */ + #if StandardStrategyAndCollisions + 0, /* MapMass */ + 0,0,0, /* MapNewtonV */ + #endif + 0,0,0, /* MapOrigin */ + 0, /* MapSimShapes */ + 0, /* MapViewType */ + 0, /* MapMPtr */ + 0, /* MapDPtr */ + 0,0,0, /* MapMOffset */ + +}; + + + +/* ******************************************************************************** */ + + +/*--------------** +** Module stuff ** +**--------------*/ + +SCENEMODULE MainScene; + +SCENEMODULE * MainSceneArray[] = +{ + &MainScene, + 0 +}; + +/* these are effectively mapblock8*/ + +extern MODULEMAPBLOCK AvpCompiledMaps[]; + +MODULEMAPBLOCK AvpCompiledMaps[] = { +/****************************************************************************/ +/****************************************************************************/ + /* Map End */ + { + MapType_Term, /* Map Type Function */ + 0, /* Shape */ + 0,0,0, /* Loc */ + 0,0,0, /* Orient */ + 0, /* Flags 1 */ + 0, /* Flags 2 */ + 0, /* Flags 3 */ + #if StandardStrategyAndCollisions + 0, /* Strategy */ + 0, /* e.g. Shape or Landscape */ + 0, /* Game Collision Strategy */ + 0, /* Shape Collision Strategy */ + 0, /* Landscape Collision Strategy */ + #endif + 0, /* VDB Definition */ + 0, /* Interior Type */ + 0, /* MapLightType */ + #if StandardStrategyAndCollisions + 0, /* MapMass */ + 0,0,0, /* MapNewtonV */ + #endif + 0,0,0, /* MapOrigin */ + 0, /* MapSimShapes */ + 0, /* MapViewType */ + 0, /* MapMPtr */ + 0, /* MapDPtr */ + 0,0,0, /* MapMOffset */ + } +}; + + + +MODULE Empty_Module = { + + mtype_module, /* MODULETYPE m_type */ + "null", /* char m_name[] */ + 0, /* int m_index */ + 0, /* int m_flags */ + 0,0,0, /* VECTOR m_world */ + "null", /* MREF m_ext */ + 0, /* int m_ext_scale */ + 0, /* int m_maxx */ + 0, /* int m_minx */ + 0, /* int m_maxy */ + 0, /* int m_miny */ + 0, /* int m_maxz */ + 0, /* int m_minz */ + 0, /* MODULEMAPBLOCK *m_mapptr */ + 0, /* struct displayblock *m_dptr */ + "null", /* MREF m_vptr */ + 0, /* VMODULE *m_v_ptrs */ + 0, /* struct module **m_link_ptrs */ +// 0, /* VIEWPORT *m_viewports */ + 0, /* MODULETABLEHEADER *m_table */ + mfun_null, /* MFUNCTION m_ifvisible */ + mfun_null, /* MFUNCTION m_ifvinside */ + "null", /* MREF m_funref */ + 0, /* Strategy block * */ + 0, /* num lights*/ + NULL, /* pointer to light blocks*/ + NULL, /* pointer to extraitemdata */ + + 0,0,0, + 0,0,0, + 0,0,0, + + #if SupportWindows95 + 0, + #endif + +}; + + +MODULE Term_Module = { + + mtype_term /* MODULETYPE m_type */ + +}; + + +// this is the one used for the loaded modules + +MODULEMAPBLOCK Empty_Module_Map = +{ + + MapType_Default, /* MapType */ + -1, /* MapShape */ + 0, 0, 0, /* MapWorld */ + 0, 0, 0, /* MapEuler */ /* Orient */ + + 0 + | ObFlag_MultLSrc /* MapFlags */ + | ObFlag_NoInfLSrc + //| ObFlag_BFCRO + //| ObFlag_VertexHazing + | 0, + + 0 + //| ObFlag2_SortD + | 0, /* Flags 2 */ + + 0 + | ObFlag3_ObjectSortedItems + | ObFlag3_NoLightDot + | ObFlag3_PreLit + | 0, /* Flags 3 */ + + 0, /* VDB Definition */ + 0, /* Interior Type */ + + LightType_PerVertex, /* MapLightType */ + 0,0,0, /* MapOrigin */ + 0, /* MapSimShapes */ + 0, /* MapViewType */ + + 0, /* MapMPtr */ + 0, /* MapDPtr */ + 0,0,0, /* MapMOffset */ + +}; + +// !!!!!!!!!!!! + +// Default ModuleMapBlock defined below; this will be used for +// run-time creation of both temporary, local, and global objects; +// for the most part, these objects will have no collisions, comprising +// sprite-based explosions, vertex-based explosion fragments, missiles, +// grenades, etc. They might also include "placeable" objects, like +// deposited inventory items, ammo, medpacks, etc. + +// !!!!!!!!!!!! + +MODULEMAPBLOCK TempModuleMap = \ +{ + + MapType_Default, /* MapType */ + -1, /* MapShape */ + + 0, 0, 0, /* MapWorld */ + 0, 0, 0, /* MapEuler */ /* Orient */ + + 0 /* flags 1*/ + | ObFlag_NoInfLSrc + | ObFlag_MultLSrc + |0, + /* Flags 2 */ + 0, + + 0 +// | ObFlag3_NoLightDot + | 0, /* Flags 3 */ + + 0, /* VDB Definition */ + 0, /* Interior Type */ + +#if Saturn + LightType_PerObject, /* MapLightType */ +#else + LightType_PerVertex, /* MapLightType */ +#endif + 0,0,0, /* MapOrigin */ + 0, /* MapSimShapes */ + 0, /* MapViewType */ + 0, /* MapMPtr */ + 0, /* MapDPtr */ + 0,0,0 /* MapMOffset */ + +}; + diff --git a/3dc/avp/davehook.cpp b/3dc/avp/davehook.cpp new file mode 100644 index 0000000..ccd7c9c --- /dev/null +++ b/3dc/avp/davehook.cpp @@ -0,0 +1,596 @@ +/******************************************************************* + * + * DESCRIPTION: davehook.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 18/11/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "davehook.h" + + +#include "r2base.h" + // hooks to R2 code + +#include "gadget.h" + // hooks to gadgets code + +#include "daemon.h" + // hooks to daemon code + +#include "rentrntq.h" + +//#include "ammo666.hpp" + +#include "iofocus.h" + +//#include "statpane.h" + +#include "font.h" + +#include "hudgadg.hpp" + +#include "consvar.hpp" +#include "conscmnd.hpp" + +#include "missions.hpp" + +#include "rebmenus.hpp" +#include "indexfnt.hpp" + // Includes for console variables: + #include "textexp.hpp" + + // Includes for console commands: + #include "consvar.hpp" + #include "modcmds.hpp" + #include "trepgadg.hpp" + + #include "consbind.hpp" + + #include "consbtch.hpp" + + + #define UseLocalAssert Yes + #include "ourasert.h" + +#include "frontend/avp_menus.h" +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + #define DEFAULT_KEY_STATUS_PANEL_WEAPONS ( KEY_TAB ) + #define DEFAULT_KEY_STATUS_PANEL_INVENTORY ( KEY_V ) + #define DEFAULT_KEY_STATUS_PANEL_OBJECTIVES ( KEY_O ) + #define DEFAULT_KEY_STATUS_PANEL_GAMESTATS ( KEY_G ) + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + + extern unsigned char KeyboardInput[]; + + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + extern int VideoModeColourDepth; + + extern int bEnableTextprint; + extern int bEnableTextprintXY; + extern signed int HUDTranslucencyLevel; + + + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + #if 0 + int FixP_Test = (ONE_FIXED/2); + #endif + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + namespace Testing + { + void VVTest(void); + void VITest(int); + int IVTest(void); + int IITest(int); + + void DumpRefCounts(void); + void DumpVideoMode(void); + }; + + static void davehook_HandleStatusPanelControls(void); + + static int bFirstFrame = No; + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +/*static*/ void ConsoleVariable :: CreateAll(void) +{ + // hook to create all the console variables + // (to make it easy to add new ones) + + + MakeSimpleConsoleVariable_Int + ( + TextExpansion :: bVerbose, // int& Value_ToUse, + "EXPV", // ProjChar* pProjCh_ToUse, + "(VERBOSE REPORTS OF TEXT EXPANSIONS)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1 // int MaxVal_New + ); + + #if 0 + MakeSimpleConsoleVariable_Int + ( + bEnableTextprint, // int& Value_ToUse, + "TEXT", // ProjChar* pProjCh_ToUse, + "(ENABLE/DISABLE DIAGNOSTIC TEXT)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1 // int MaxVal_New + ); + + MakeSimpleConsoleVariable_Int + ( + bEnableTextprintXY, // int& Value_ToUse, + "TEXTXY", // ProjChar* pProjCh_ToUse, + "(ENABLE/DISABLE POSITIONED TEXT)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1 // int MaxVal_New + ); + MakeSimpleConsoleVariable_Int + ( + HUDTranslucencyLevel, // int& Value_ToUse, + "HUDALPHA", // ProjChar* pProjCh_ToUse, + "(OPACITY OF HEAD-UP-DISPLAY)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 255 // int MaxVal_New + ); + + MakeSimpleConsoleVariable_FixP + ( + FixP_Test, // int& Value_ToUse, + "FIXPTEST", // ProjChar* pProjCh_ToUse, + "(A TEST)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 65536 // int MaxVal_New + ); + + MakeSimpleConsoleVariable_FixP + ( + Daemon :: DaemonTimeScale, // int& Value_ToUse, + "IO-TIME", // ProjChar* pProjCh_ToUse, + "TIMESCALE FOR USER INTERFACE", // ProjChar* pProjCh_Description_ToUse + 655, // int MinVal_New, + 65536 // int MaxVal_New + ); + + MakeSimpleConsoleVariable_Int + ( + KeyBinding :: bEcho, + "ECHO-BIND", + "(ENABLES ECHOING OF STRINGS BOUND TO KEYS)", + 0, + 1 + ); + + MakeSimpleConsoleVariable_Int + ( + BatchFileProcessing :: bEcho, + "ECHO-BATCH", + "(ENABLES ECHOING OF BATCH FILES)", + 0, + 1 + ); + #endif + + +} + +/*static*/ void ConsoleCommand :: CreateAll(void) +{ + Make + ( + "LISTCMD", + "LIST ALL CONSOLE COMMANDS", + ListAll + ); + + Make + ( + "LISTEXP", + "LIST ALL TEXT EXPANSIONS", + TextExpansion :: ListAll + ); + + Make + ( + "LISTVAR", + "LIST ALL CONSOLE VARIABLES", + ConsoleVariable :: ListAllVariables + ); + + + + // Need to add + #if 0 + static void AttemptToBind + ( + SCString* pSCString_Key, // description of key + SCString* pSCString_ToBind // string to be bound + ); + static void AttemptToUnbind + ( + SCString* pSCString_Key // description of key + ); + #endif + + + Make + ( + "LISTBIND", + "LIST ALL KEY BINDINGS", + KeyBinding::ListAllBindings + ); + Make + ( + "UNBIND-ALL", + "GET RID OF ALL KEY BINDINGS", + KeyBinding::UnbindAll + ); + #if 0 + Make + ( + "LISTMOD", + "LIST ALL MODULES", + ModuleCommands :: ListModules + ); + Make + ( + "C-KILL", + "CLEAR TEXT REPORT QUEUE", + TextReportGadget :: ClearTheQueue + ); + + Make + ( + "D-REFDUMP", + "DIAGNOSTICS ON REFERENCE COUNTS", + Testing :: DumpRefCounts + ); + + Make + ( + "VIDMODE", + "DUMP INFO ON VIDEO MODE", + Testing :: DumpVideoMode + ); + #endif + #if 0 + Make + ( + "VVTEST", + "TEST COMMAND", + Testing :: VVTest + ); + Make + ( + "VITEST", + "TEST COMMAND", + Testing :: VITest + ); + Make + ( + "IVTEST", + "TEST COMMAND", + Testing :: IVTest + ); + Make + ( + "IITEST", + "TEST COMMAND", + Testing :: IITest + ); + #endif + + +} + +void DAVEHOOK_Init(void) +{ + SCString* pSCString_TestLeak = new SCString("this is a test memory leak"); + + MissionHacks :: TestInit(); + + { + DAEMON_Init(); + +// AmmoDaemon :: Init(); + } + + new IndexedFont_HUD(DATABASE_MESSAGE_FONT); + + GADGET_Init(); + + #if UseGadgets + ConsoleVariable :: CreateAll(); + ConsoleCommand :: CreateAll(); + #endif + + #if 0//UseRebMenus + { + RebMenus :: Init(); + } + #endif + +} + +void DAVEHOOK_UnInit(void) +{ + #if 0//UseRebMenus + { + RebMenus :: UnInit(); + } + #endif + IndexedFont :: UnloadFont(DATABASE_MESSAGE_FONT); + + GADGET_UnInit(); +} + +void DAVEHOOK_Maintain(void) +{ + { +// AmmoDaemon :: Maintain(); + + DAEMON_Maintain(); + } + + #if KeyBindingUses_KEY_ID + { + KeyBinding :: Maintain(); + } + #endif + + // Hacked in input support: + #if SupportWindows95 + { + #if EnableStatusPanels + davehook_HandleStatusPanelControls(); + #endif + + #if 0 + if ( KeyboardInput[ KEY_J ] ) + { + // Test jitter hack + HUDGadget* pHUD = HUDGadget :: GetHUD(); + + if ( pHUD ) + { + pHUD -> Jitter(ONE_FIXED); + } + + } + #endif + + #if 0 + if ( KeyboardInput[ KEY_CR ] ) + { + IOFOCUS_Toggle(); + + #if 0 + // toggle typing/control mode + textprint("\n\n\n\nTOGGLE TYPING MODE\n"); + #endif + } + #endif + } + #endif // SupportWindows95 + + #if SupportWindows95 + if ( bFirstFrame ) + { + RE_ENTRANT_QUEUE_WinMain_FlushMessagesWithoutProcessing(); + // this is a hack to ensure that none of the keypresses used + // in the menu get through to the first frame of the game and + // for example, switch to typing mode (for CR presses) + + bFirstFrame = No; + } + else + { + // Flush the WinProc messages: + RE_ENTRANT_QUEUE_WinMain_FlushMessages(); + } + #endif // SupportWindows95 + + /* KJL 20:14:23 28/03/98 - for now I've disabled the calls to the menus while in-game */ + #if 0//UseRebMenus + { + RebMenus :: Maintain(); + RebMenus :: Render(); + } + #endif +} + +void DAVEHOOK_ScreenModeChange_Setup(void) +{ +} + +void DAVEHOOK_ScreenModeChange_Cleanup(void) +{ + R2BASE_ScreenModeChange_Cleanup(); + GADGET_ScreenModeChange_Cleanup(); + + #if 0 + LoadPFFont(MENU_FONT_1); + #endif + + bFirstFrame = Yes; + // to ensure a flush without processing of messages in first frame, so as to + // avoid carriage returns/enter from menu selections triggering typing mode + + // Run program-generated batch file: + #if !(PREDATOR_DEMO|MARINE_DEMO||ALIEN_DEMO||DEATHMATCH_DEMO) + BatchFileProcessing :: Run("CONFIG.CFG"); + + // Run user-generated batch file: + BatchFileProcessing :: Run("STARTUP.CFG"); + #endif +} + + +/* Internal function definitions ***********************************/ +void Testing :: VVTest(void) +{ + textprint("Testing :: VVTest()\n"); +} +void Testing :: VITest(int i) +{ + textprint("Testing :: VITest(%i)\n",i); +} +int Testing :: IVTest(void) +{ + textprint("Testing :: IVTest()\n"); + + return 180; +} +int Testing :: IITest(int i) +{ + textprint("Testing :: IITest(%i)\n",i); + + return (i*2); +} + + +// Diagnostic hook for reference counting system: +void Testing :: DumpRefCounts(void) +{ + #if TrackReferenceCounted + { + SCString* pSCString_Feedback = new SCString("DUMPING REFCOUNT INFO"); + pSCString_Feedback -> SendToScreen(); + pSCString_Feedback -> R_Release(); + + LogFile tempLog("REFDUMP.TXT"); + RefCountObject :: DumpAll(tempLog); + } + #else + { + SCString* pSCString_Feedback = new SCString("REFCOUNT INFO DISABLED AT COMPILE-TIME"); + pSCString_Feedback -> SendToScreen(); + pSCString_Feedback -> R_Release(); + } + #endif +} + +void Testing :: DumpVideoMode(void) +{ + char msg[256]; + sprintf + ( + msg, + "VIDEO MODE:%iX%iX%i", + ScreenDescriptorBlock . SDB_Width, + ScreenDescriptorBlock . SDB_Height, + VideoModeColourDepth + ); + + SCString* pSCString_Feedback = new SCString(msg); + pSCString_Feedback -> SendToScreen(); + pSCString_Feedback -> R_Release(); +} + +#if EnableStatusPanels +static void davehook_HandleStatusPanelControls(void) +{ + /* + DHM 27/1/98: + ------------ + This code ought to be rewritten in terms of the PLAYER_INPUT_CONFIGURATION + code in USR_IO.C + + I've done it as a bit of a hack here to avoid messing up people's saved + control config files, and because there's no more room on the control config + screen for redefining these keys. + + It will depend on whether the status panels stay in the final version. + */ + if ( IOFOCUS_AcceptControls()) + { + if + ( + KeyboardInput[ DEFAULT_KEY_STATUS_PANEL_WEAPONS ] + ) + { + STATPANE_RequestStatusPanel + ( + I_StatusPanel_Weapons + ); + return; + } + + if + ( + KeyboardInput[ DEFAULT_KEY_STATUS_PANEL_INVENTORY ] + ) + { + STATPANE_RequestStatusPanel + ( + I_StatusPanel_Inventory + ); + return; + } + + if + ( + KeyboardInput[ DEFAULT_KEY_STATUS_PANEL_OBJECTIVES ] + ) + { + STATPANE_RequestStatusPanel + ( + I_StatusPanel_Objectives + ); + return; + } + + if + ( + KeyboardInput[ DEFAULT_KEY_STATUS_PANEL_GAMESTATS ] + ) + { + STATPANE_RequestStatusPanel + ( + I_StatusPanel_GameStats + ); + return; + } + } + + STATPANE_NoRequestedPanel(); +} +#endif // EnableStatusPanels \ No newline at end of file diff --git a/3dc/avp/davehook.h b/3dc/avp/davehook.h new file mode 100644 index 0000000..9955f21 --- /dev/null +++ b/3dc/avp/davehook.h @@ -0,0 +1,45 @@ +/* + + davehook.h + + + Created 18/11/97 by DHM: + Contains all the hooks for my code +*/ + +#ifndef _davehook +#define _davehook 1 + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + extern void DAVEHOOK_Init(void); + extern void DAVEHOOK_UnInit(void); + extern void DAVEHOOK_Maintain(void); + + extern void DAVEHOOK_ScreenModeChange_Setup(void); + extern void DAVEHOOK_ScreenModeChange_Cleanup(void); + + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/deaths.c b/3dc/avp/deaths.c new file mode 100644 index 0000000..489eb50 --- /dev/null +++ b/3dc/avp/deaths.c @@ -0,0 +1,1912 @@ +/* CDF 22/6/98 - Single file for the death lists. */ + +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "comp_shp.h" +#include "dynblock.h" +#include "dynamics.h" +#include "pfarlocs.h" +#include "pheromon.h" +#include "bh_types.h" +#include "pvisible.h" +#include "bh_far.h" +#include "bh_debri.h" +#include "bh_pred.h" +#include "bh_paq.h" +#include "bh_queen.h" +#include "bh_marin.h" +#include "bh_alien.h" +#include "lighting.h" +#include "bh_weap.h" +#include "weapons.h" +#include "psnd.h" +#include "equipmnt.h" +#include "los.h" +#include "AI_Sight.h" +#include "targeting.h" +#include "dxlog.h" +#include "ShowCmds.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +/* General Death Structures! */ +DEATH_DATA Alien_Deaths[] = { + { + HMSQT_AlienCrouch, /* Sequence_Type */ + ACrSS_Dies, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 0, /* Multiplayer_Code */ + (0<<16)|0, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 1, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_AlienCrawl, /* Sequence_Type */ + ACSS_Pain_Fall_Right, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 1, /* Multiplayer_Code */ + (0<<16)|1, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 1, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_AlienCrawl, /* Sequence_Type */ + ACSS_Boom_Fall_Back, /* Sub_Sequence */ + (ONE_FIXED>>4), /* TweeningTime */ + -1, /* Sequence_Length */ + 2, /* Multiplayer_Code */ + (0<<16)|2, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 1, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 1, /* Crouching */ + 1, /* Minor Boom */ + 1, /* Major Boom */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Pain_Fall_Back, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 3, /* Multiplayer_Code */ + (0<<16)|3, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Dies, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 4, /* Multiplayer_Code */ + (0<<16)|4, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Pain_Fall_Fwd, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 5, /* Multiplayer_Code */ + (0<<16)|5, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Boom_Fall_Fwd, /* Sub_Sequence */ + (ONE_FIXED>>4), /* TweeningTime */ + -1, /* Sequence_Length */ + 6, /* Multiplayer_Code */ + (0<<16)|6, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 1, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 1, /* Minor Boom */ + 1, /* Major Boom */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Boom_Fall_Back, /* Sub_Sequence */ + (ONE_FIXED>>5), /* TweeningTime */ + -1, /* Sequence_Length */ + 7, /* Multiplayer_Code */ + (0<<16)|7, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 1, /* Minor Boom */ + 1, /* Major Boom */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Spin_Clockwise, /* Sub_Sequence */ + (ONE_FIXED>>5), /* TweeningTime */ + -1, /* Sequence_Length */ + 8, /* Multiplayer_Code */ + (0<<16)|8, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 1, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_AlienCrouch, /* Sequence_Type */ + ACrSS_Dies_Thrash, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 9, /* Multiplayer_Code */ + (0<<16)|9, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 1, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + /* Electric deaths! */ + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Boom_Fall_Back, /* Sub_Sequence */ + (ONE_FIXED>>5), /* TweeningTime */ + -1, /* Sequence_Length */ + 10, /* Multiplayer_Code */ + (0<<16)|10, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 1, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Pain_Fall_Back, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 11, /* Multiplayer_Code */ + (0<<16)|11, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 1, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Pain_Fall_Fwd, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 12, /* Multiplayer_Code */ + (0<<16)|12, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Spin_Clockwise, /* Sub_Sequence */ + (ONE_FIXED>>5), /* TweeningTime */ + -1, /* Sequence_Length */ + 13, /* Multiplayer_Code */ + (0<<16)|13, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 1, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_AlienCrawl, /* Sequence_Type */ + ACSS_Pain_Fall_Right, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 14, /* Multiplayer_Code */ + (0<<16)|14, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 1, /* Electrical */ + 1, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_AlienCrawl, /* Sequence_Type */ + ACSS_Boom_Fall_Back, /* Sub_Sequence */ + (ONE_FIXED>>4), /* TweeningTime */ + -1, /* Sequence_Length */ + 15, /* Multiplayer_Code */ + (0<<16)|15, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 1, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 1, /* Electrical */ + 1, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + /* Terminator */ + { + -1, /* Sequence_Type */ + -1, /* Sub_Sequence */ + 0, /* TweeningTime */ + 0, /* Sequence_Length */ + 0, /* Multiplayer_Code */ + (0<<16)|0, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, +}; + +DEATH_DATA Marine_Deaths[] = { + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Dies_Standard, /* Sub_Sequence */ + (ONE_FIXED>>3), /* TweeningTime */ + -1, /* Sequence_Length */ + 0, /* Multiplayer_Code */ + (1<<16)|0, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_MarineCrouch, /* Sequence_Type */ + MCrSS_Dies_Standard, /* Sub_Sequence */ + (ONE_FIXED>>3), /* TweeningTime */ + -1, /* Sequence_Length */ + 1, /* Multiplayer_Code */ + (1<<16)|1, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 1, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_Back_Death, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 2, /* Multiplayer_Code */ + (1<<16)|2, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 1, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_Front_Death, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 3, /* Multiplayer_Code */ + (1<<16)|3, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 1, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_Sum_Death, /* Sub_Sequence */ + (ONE_FIXED>>5), /* TweeningTime */ + -1, /* Sequence_Length */ + 4, /* Multiplayer_Code */ + (1<<16)|4, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 1, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 1, /* Minor Boom */ + 1, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_Burning, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 5, /* Multiplayer_Code */ + (1<<16)|5, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 1, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_LeftSholdr, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 6, /* Multiplayer_Code */ + (1<<16)|6, /* Unique Code */ + section_flag_left_arm, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_RightSholdr, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 7, /* Multiplayer_Code */ + (1<<16)|7, /* Unique Code */ + section_flag_right_arm, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_LeftForarm, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 8, /* Multiplayer_Code */ + (1<<16)|8, /* Unique Code */ + section_flag_left_hand, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_RightForarm, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 9, /* Multiplayer_Code */ + (1<<16)|9, /* Unique Code */ + section_flag_right_hand,/* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_LeftThigh, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 10, /* Multiplayer_Code */ + (1<<16)|10, /* Unique Code */ + section_flag_left_leg, /* wound_flags */ + section_flag_left_leg|section_flag_left_foot,/* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_RightThigh, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 11, /* Multiplayer_Code */ + (1<<16)|11, /* Unique Code */ + section_flag_right_leg, /* wound_flags */ + section_flag_right_leg|section_flag_right_foot,/* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_LeftShin, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 12, /* Multiplayer_Code */ + (1<<16)|12, /* Unique Code */ + section_flag_left_foot, /* wound_flags */ + section_flag_left_foot, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_RightShin, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 13, /* Multiplayer_Code */ + (1<<16)|13, /* Unique Code */ + section_flag_right_foot,/* wound_flags */ + section_flag_right_foot,/* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + /* Listed twice for pain and boom. */ + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_LeftThigh, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 10, /* Multiplayer_Code */ + (1<<16)|14, /* Unique Code */ + section_flag_left_leg, /* wound_flags */ + section_flag_left_leg|section_flag_left_foot,/* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 1, /* Minor Boom */ + 1, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_RightThigh, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 11, /* Multiplayer_Code */ + (1<<16)|15, /* Unique Code */ + section_flag_right_leg, /* wound_flags */ + section_flag_right_leg|section_flag_right_foot,/* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 1, /* Minor Boom */ + 1, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_LeftShin, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 12, /* Multiplayer_Code */ + (1<<16)|16, /* Unique Code */ + section_flag_left_foot, /* wound_flags */ + section_flag_left_foot, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 1, /* Minor Boom */ + 1, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_RightShin, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 13, /* Multiplayer_Code */ + (1<<16)|17, /* Unique Code */ + section_flag_right_foot,/* wound_flags */ + section_flag_right_foot,/* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 1, /* Minor Boom */ + 1, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_Back_Death, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 14, /* Multiplayer_Code */ + (1<<16)|18, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 1, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + /* And now the crouch template. */ + { + HMSQT_MarineCrouch, /* Sequence_Type */ + MCrSS_Dies_Standard, /* Sub_Sequence */ + (ONE_FIXED>>3), /* TweeningTime */ + -1, /* Sequence_Length */ + 1, /* Multiplayer_Code */ + 15, /* wound_flags */ + (1<<16)|19, /* Unique Code */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 1, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + /* And now this one, for directionlessness. */ + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_Back_Death, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 16, /* Multiplayer_Code */ + (1<<16)|20, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_Electric_Death_One, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 17, /* Multiplayer_Code */ + (1<<16)|21, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 1, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_MarineStand, /* Sequence_Type */ + MSSS_Tem_Electric_Death_Two, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 18, /* Multiplayer_Code */ + (1<<16)|22, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 1, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_MarineCrouch, /* Sequence_Type */ + MCrSS_Tem_Electric_Death_One, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 19, /* Multiplayer_Code */ + (1<<16)|23, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 1, /* Electrical */ + 1, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + -1, /* Sequence_Type */ + -1, /* Sub_Sequence */ + 0, /* TweeningTime */ + 0, /* Sequence_Length */ + 0, /* Multiplayer_Code */ + (1<<16)|0, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, +}; + +DEATH_DATA Predator_Special_SelfDestruct_Death = { + + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_Dies_Standard, /* Sub_Sequence */ + (ONE_FIXED>>3), /* TweeningTime */ + -1, /* Sequence_Length */ + 10, /* Multiplayer_Code */ + (2<<16)|0, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ +}; + +DEATH_DATA Predator_Deaths[] = { + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_Dies_Standard, /* Sub_Sequence */ + (ONE_FIXED>>3), /* TweeningTime */ + -1, /* Sequence_Length */ + 0, /* Multiplayer_Code */ + (2<<16)|0, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_PredatorCrouch, /* Sequence_Type */ + PCrSS_Dies_Standard, /* Sub_Sequence */ + (ONE_FIXED>>3), /* TweeningTime */ + -1, /* Sequence_Length */ + 1, /* Multiplayer_Code */ + (2<<16)|1, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 1, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_TemDeath_Fwrd, /* Sub_Sequence */ + (ONE_FIXED>>3), /* TweeningTime */ + -1, /* Sequence_Length */ + 2, /* Multiplayer_Code */ + (2<<16)|2, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 1, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_TemDeath_Bwrd, /* Sub_Sequence */ + (ONE_FIXED>>3), /* TweeningTime */ + -1, /* Sequence_Length */ + 3, /* Multiplayer_Code */ + (2<<16)|3, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 1, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_Tem_LeftArm, /* Sub_Sequence */ + (ONE_FIXED>>3), /* TweeningTime */ + -1, /* Sequence_Length */ + 4, /* Multiplayer_Code */ + (2<<16)|4, /* Unique Code */ + section_flag_left_arm, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_Tem_LeftLeg, /* Sub_Sequence */ + (ONE_FIXED>>3), /* TweeningTime */ + -1, /* Sequence_Length */ + 5, /* Multiplayer_Code */ + (2<<16)|5, /* Unique Code */ + section_flag_left_leg, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_Tem_RightArm, /* Sub_Sequence */ + (ONE_FIXED>>3), /* TweeningTime */ + -1, /* Sequence_Length */ + 6, /* Multiplayer_Code */ + (2<<16)|6, /* Unique Code */ + section_flag_right_arm, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_Tem_RightLeg, /* Sub_Sequence */ + (ONE_FIXED>>3), /* TweeningTime */ + -1, /* Sequence_Length */ + 7, /* Multiplayer_Code */ + (2<<16)|7, /* Unique Code */ + section_flag_right_leg, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_Tem_Riddled, /* Sub_Sequence */ + (ONE_FIXED>>3), /* TweeningTime */ + -1, /* Sequence_Length */ + 8, /* Multiplayer_Code */ + (2<<16)|8, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 1, /* Minor Boom */ + 1, /* Major Boom */ + }, + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_Tem_Burning, /* Sub_Sequence */ + (ONE_FIXED>>3), /* TweeningTime */ + -1, /* Sequence_Length */ + 9, /* Multiplayer_Code */ + (2<<16)|9, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 1, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_PredatorCrouch, /* Sequence_Type */ + PCrSS_Dies_Standard, /* Sub_Sequence */ + (ONE_FIXED>>3), /* TweeningTime */ + -1, /* Sequence_Length */ + 10, /* Multiplayer_Code */ + (2<<16)|10, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 1, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 1, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + -1, /* Sequence_Type */ + -1, /* Sub_Sequence */ + 0, /* TweeningTime */ + 0, /* Sequence_Length */ + 0, /* Multiplayer_Code */ + (2<<16)|0, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, +}; + +DEATH_DATA Xenoborg_Deaths[] = { + { + HMSQT_Xenoborg, /* Sequence_Type */ + XBSS_Die_Backwards, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 0, /* Multiplayer_Code */ + (3<<16)|0, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 1, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_Xenoborg, /* Sequence_Type */ + XBSS_Die_Forwards, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 1, /* Multiplayer_Code */ + (3<<16)|1, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 1, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_Xenoborg, /* Sequence_Type */ + XBSS_Die_Backwards, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 2, /* Multiplayer_Code */ + (3<<16)|2, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 1, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 1, /* Minor Boom */ + 1, /* Major Boom */ + }, + { + HMSQT_Xenoborg, /* Sequence_Type */ + XBSS_Die_Forwards, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 3, /* Multiplayer_Code */ + (3<<16)|3, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 1, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 1, /* Minor Boom */ + 1, /* Major Boom */ + }, + { + HMSQT_Xenoborg, /* Sequence_Type */ + XBSS_Standing_Death, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 4, /* Multiplayer_Code */ + (3<<16)|4, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_Xenoborg, /* Sequence_Type */ + XBSS_Standing_Death, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 5, /* Multiplayer_Code */ + (3<<16)|5, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 1, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_Xenoborg, /* Sequence_Type */ + XBSS_LeftLegMissingDeath, /* Sub_Sequence */ + (ONE_FIXED>>4), /* TweeningTime */ + -1, /* Sequence_Length */ + 6, /* Multiplayer_Code */ + (3<<16)|6, /* Unique Code */ + section_flag_left_leg, /* wound_flags */ + section_flag_left_leg|section_flag_left_foot, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_Xenoborg, /* Sequence_Type */ + XBSS_RightLegMissingDeath, /* Sub_Sequence */ + (ONE_FIXED>>4), /* TweeningTime */ + -1, /* Sequence_Length */ + 7, /* Multiplayer_Code */ + (3<<16)|7, /* Unique Code */ + section_flag_right_leg, /* wound_flags */ + section_flag_right_leg|section_flag_right_foot, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, + { + HMSQT_Xenoborg, /* Sequence_Type */ + XBSS_LeftLegMissingDeath, /* Sub_Sequence */ + (ONE_FIXED>>4), /* TweeningTime */ + -1, /* Sequence_Length */ + 8, /* Multiplayer_Code */ + (3<<16)|8, /* Unique Code */ + section_flag_left_leg, /* wound_flags */ + section_flag_left_leg|section_flag_left_foot, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 1, /* Minor Boom */ + 1, /* Major Boom */ + }, + { + HMSQT_Xenoborg, /* Sequence_Type */ + XBSS_RightLegMissingDeath, /* Sub_Sequence */ + (ONE_FIXED>>4), /* TweeningTime */ + -1, /* Sequence_Length */ + 9, /* Multiplayer_Code */ + (3<<16)|9, /* Unique Code */ + section_flag_right_leg, /* wound_flags */ + section_flag_right_leg|section_flag_right_foot, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 1, /* Minor Boom */ + 1, /* Major Boom */ + }, + { + -1, /* Sequence_Type */ + -1, /* Sub_Sequence */ + 0, /* TweeningTime */ + 0, /* Sequence_Length */ + 0, /* Multiplayer_Code */ + (3<<16)|0, /* Unique Code */ + 0, /* wound_flags */ + 0, /* priority_wounds */ + 0, /* Template */ + { + 0, /* Front */ + 0, /* Back */ + 0, /* Left */ + 0, /* Right */ + }, + 0, /* Burning */ + 0, /* Electrical */ + 0, /* Crouching */ + 0, /* Minor Boom */ + 0, /* Major Boom */ + }, +}; + +/* And now, in a change from our advertised programme, Alien Attacks. */ + +ATTACK_DATA Alien_Special_Gripping_Attack = { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Feed, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 0, /* Multiplayer_Code */ + (0<<16)|0, /* Unique_Code */ + 0, /* wound_flags */ + { /* flag_damage */ + AMMO_NPC_ALIEN_BITE, + AMMO_NPC_ALIEN_BITE, + AMMO_NPC_ALIEN_BITE, + }, + 1, /* Crouching */ + 0, /* Pouncing */ +}; + +ATTACK_DATA Alien_Attacks[] = { + + { + HMSQT_AlienCrouch, /* Sequence_Type */ + ACrSS_Attack_Bite, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 0, /* Multiplayer_Code */ + (1<<16)|0, /* Unique_Code */ + 0, /* wound_flags */ + { /* flag_damage */ + AMMO_NPC_ALIEN_BITE, + AMMO_NPC_ALIEN_BITE, + AMMO_NPC_ALIEN_BITE, + }, + 1, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_AlienCrouch, /* Sequence_Type */ + ACrSS_Attack_Tail, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 1, /* Multiplayer_Code */ + (1<<16)|1, /* Unique_Code */ + section_flag_tail, /* wound_flags */ + { /* flag_damage */ + AMMO_NPC_ALIEN_TAIL, + AMMO_NPC_ALIEN_TAIL, + AMMO_NPC_ALIEN_TAIL, + }, + 1, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_AlienCrouch, /* Sequence_Type */ + ACrSS_Attack_Swipe, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 2, /* Multiplayer_Code */ + (1<<16)|2, /* Unique_Code */ + section_flag_left_hand, /* wound_flags */ + { /* flag_damage */ + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_ALIEN_CLAW, + }, + 1, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Attack_Bite, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 3, /* Multiplayer_Code */ + (1<<16)|3, /* Unique_Code */ + 0, /* wound_flags */ + { /* flag_damage */ + AMMO_NPC_ALIEN_BITE, + AMMO_NPC_ALIEN_BITE, + AMMO_NPC_ALIEN_BITE, + }, + 0, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Attack_Left_Swipe_In,/* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 4, /* Multiplayer_Code */ + (1<<16)|4, /* Unique_Code */ + section_flag_left_hand, /* wound_flags */ + { /* flag_damage */ + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_ALIEN_CLAW, + }, + 0, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Attack_Right_Swipe_In, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 5, /* Multiplayer_Code */ + (1<<16)|5, /* Unique_Code */ + section_flag_right_hand,/* wound_flags */ + { /* flag_damage */ + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_ALIEN_CLAW, + }, + 0, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Attack_Tail, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 5, /* Multiplayer_Code */ + (1<<16)|6, /* Unique_Code */ + section_flag_tail, /* wound_flags */ + { /* flag_damage */ + AMMO_NPC_ALIEN_TAIL, + AMMO_NPC_ALIEN_TAIL, + AMMO_NPC_ALIEN_TAIL, + }, + 0, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_AlienCrouch, /* Sequence_Type */ + ACrSS_Pounce, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + ALIEN_ATTACKTIME, /* Sequence_Length */ + 6, /* Multiplayer_Code */ + (1<<16)|7, /* Unique_Code */ + section_flag_tail, /* wound_flags */ + { /* flag_damage */ + AMMO_NPC_ALIEN_TAIL, + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_ALIEN_CLAW, + }, + 1, /* Crouching */ + 1, /* Pouncing */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Attack_Both_In, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 7, /* Multiplayer_Code */ + (1<<16)|8, /* Unique_Code */ + section_flag_right_hand|section_flag_left_hand,/* wound_flags */ + { /* flag_damage */ + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_ALIEN_CLAW, + }, + 0, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Attack_Both_Down, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 8, /* Multiplayer_Code */ + (1<<16)|9, /* Unique_Code */ + section_flag_right_hand|section_flag_left_hand,/* wound_flags */ + { /* flag_damage */ + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_ALIEN_CLAW, + }, + 0, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Attack_Low_Left_Swipe,/* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 9, /* Multiplayer_Code */ + (1<<16)|10, /* Unique_Code */ + section_flag_left_hand, /* wound_flags */ + { /* flag_damage */ + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_ALIEN_CLAW, + }, + 0, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_AlienStand, /* Sequence_Type */ + ASSS_Attack_Low_Right_Swipe, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 10, /* Multiplayer_Code */ + (1<<16)|11, /* Unique_Code */ + section_flag_right_hand,/* wound_flags */ + { /* flag_damage */ + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_ALIEN_CLAW, + AMMO_NPC_ALIEN_CLAW, + }, + 0, /* Crouching */ + 0, /* Pouncing */ + }, + { + -1, /* Sequence_Type */ + -1, /* Sub_Sequence */ + 0, /* TweeningTime */ + 0, /* Sequence_Length */ + 0, /* Multiplayer_Code */ + 0, /* Unique_Code */ + 0, /* wound_flags */ + AMMO_NONE, /* damage_type */ + 0, /* Crouching */ + 0, /* Pouncing */ + }, + +}; + +ATTACK_DATA Wristblade_Attacks[] = { + + { + HMSQT_PredatorCrouch, /* Sequence_Type */ + PCrSS_Attack_Primary, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 0, /* Multiplayer_Code */ + (2<<16)|0, /* Unique_Code */ + 0, /* wound_flags */ + { /* flag_damage */ + AMMO_PRED_WRISTBLADE, + AMMO_PRED_WRISTBLADE, + AMMO_PRED_WRISTBLADE, + }, + 1, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_Attack_Primary, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 1, /* Multiplayer_Code */ + (2<<16)|1, /* Unique_Code */ + 0, /* wound_flags */ + { /* flag_damage */ + AMMO_HEAVY_PRED_WRISTBLADE, + AMMO_HEAVY_PRED_WRISTBLADE, + AMMO_HEAVY_PRED_WRISTBLADE, + }, + 0, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_Attack_Quick_Jab, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 2, /* Multiplayer_Code */ + (2<<16)|2, /* Unique_Code */ + 0, /* wound_flags */ + { /* flag_damage */ + AMMO_PRED_WRISTBLADE, + AMMO_PRED_WRISTBLADE, + AMMO_PRED_WRISTBLADE, + }, + 0, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_Attack_Uppercut, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 3, /* Multiplayer_Code */ + (2<<16)|3, /* Unique_Code */ + 0, /* wound_flags */ + { /* flag_damage */ + AMMO_HEAVY_PRED_WRISTBLADE, + AMMO_HEAVY_PRED_WRISTBLADE, + AMMO_HEAVY_PRED_WRISTBLADE, + }, + 0, /* Crouching */ + 0, /* Pouncing */ + }, + { + -1, /* Sequence_Type */ + -1, /* Sub_Sequence */ + 0, /* TweeningTime */ + 0, /* Sequence_Length */ + 0, /* Multiplayer_Code */ + 0, /* Unique_Code */ + 0, /* wound_flags */ + AMMO_NONE, /* damage_type */ + 0, /* Crouching */ + 0, /* Pouncing */ + }, + +}; + +ATTACK_DATA PredStaff_Attacks[] = { + + { + HMSQT_PredatorCrouch, /* Sequence_Type */ + PCrSS_Attack_Primary, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 0, /* Multiplayer_Code */ + (3<<16)|0, /* Unique_Code */ + 0, /* wound_flags */ + { /* flag_damage */ + AMMO_NPC_PRED_STAFF, + AMMO_NPC_PRED_STAFF, + AMMO_NPC_PRED_STAFF, + }, + 1, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_Attack_Primary, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 1, /* Multiplayer_Code */ + (3<<16)|1, /* Unique_Code */ + 0, /* wound_flags */ + { /* flag_damage */ + AMMO_NPC_PRED_STAFF, + AMMO_NPC_PRED_STAFF, + AMMO_NPC_PRED_STAFF, + }, + 0, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_Attack_Offense_Sweep, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 2, /* Multiplayer_Code */ + (3<<16)|2, /* Unique_Code */ + 0, /* wound_flags */ + { /* flag_damage */ + AMMO_NPC_PRED_STAFF, + AMMO_NPC_PRED_STAFF, + AMMO_NPC_PRED_STAFF, + }, + 0, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_Attack_Defence_Stab, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 3, /* Multiplayer_Code */ + (3<<16)|3, /* Unique_Code */ + 0, /* wound_flags */ + { /* flag_damage */ + AMMO_NPC_PRED_STAFF, + AMMO_NPC_PRED_STAFF, + AMMO_NPC_PRED_STAFF, + }, + 0, /* Crouching */ + 0, /* Pouncing */ + }, + { + HMSQT_PredatorStand, /* Sequence_Type */ + PSSS_Attack_Defence_Sweep, /* Sub_Sequence */ + (ONE_FIXED>>2), /* TweeningTime */ + -1, /* Sequence_Length */ + 4, /* Multiplayer_Code */ + (3<<16)|4, /* Unique_Code */ + 0, /* wound_flags */ + { /* flag_damage */ + AMMO_NPC_PRED_STAFF, + AMMO_NPC_PRED_STAFF, + AMMO_NPC_PRED_STAFF, + }, + 0, /* Crouching */ + 0, /* Pouncing */ + }, + { + -1, /* Sequence_Type */ + -1, /* Sub_Sequence */ + 0, /* TweeningTime */ + 0, /* Sequence_Length */ + 0, /* Multiplayer_Code */ + 0, /* Unique_Code */ + 0, /* wound_flags */ + AMMO_NONE, /* damage_type */ + 0, /* Crouching */ + 0, /* Pouncing */ + }, + +}; diff --git a/3dc/avp/decal.c b/3dc/avp/decal.c new file mode 100644 index 0000000..95078ad --- /dev/null +++ b/3dc/avp/decal.c @@ -0,0 +1,1176 @@ +/** KJL 16:44:26 11/17/97 *** +* * +* D E C A L S Y S T E M * +* * +************************KJL*/ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "gameplat.h" +#include "bh_types.h" +#include "bh_pred.h" +#include "weapons.h" + +#include "particle.h" +#include "pldnet.h" +#include "pldghost.h" +#include "kshape.h" +#include "d3d_render.h" +#include "hmodel.h" +#include "paintball.h" +#include "detaillevels.h" +#include "savegame.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +#define MAX_NO_OF_DECALS 1024 +#define MAX_NO_OF_FIXED_DECALS 1024 +#define DECAL_Z_OFFSET 0 + +THREE_LASER_DOT_DESC PredatorLaserTarget; +/* KJL 11:49:51 20/05/98 - probably not the neatest way of doing it, but +this array stores the information required to render the predator players' +laser sights. */ +THREE_LASER_DOT_DESC PredatorLaserSights[NET_MAXPLAYERS]; + + +static DECAL DecalStorage[MAX_NO_OF_DECALS]; +static int NumActiveDecals; +static int CurrentDecalIndex; + +FIXED_DECAL FixedDecalStorage[MAX_NO_OF_FIXED_DECALS]; +int NumFixedDecals; +int CurrentFixedDecalIndex; + +DECAL_DESC DecalDescription[MAX_NO_OF_DECAL_IDS] = +{ + /* DECAL_FMV */ + { + //int StartU; + 0<<16, + //int StartV; + 0<<16, + //int EndU; + (127)<<16, + //int EndV; + (95)<<16, + + //int MinSize; + 3000, + //int MaxSize; + 3000, + //int GrowthRate; + 0, + + //int MaxSubclassNumber; + 0, + //int UOffsetForSubclass; + 0, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_NORMAL, + + //unsigned char Alpha; + 96, + //unsigned char RedScale; + {255, 255, 0, 255, 255}, + //unsigned char GreenScale; + {255, 255, 255, 0, 0}, + //unsigned char BlueScale; + {255, 255, 0, 255, 0}, + + //unsigned char IsLit:1; + 0, + //unsigned char CanCombine:1; + 0, + }, + /* DECAL_SCORCHED */ + { + //int StartU; + 0<<16, + //int StartV; + 64<<16, + //int EndU; + 63<<16, + //int EndV; + 127<<16, + + //int MinSize; + 20, + //int MaxSize; + 200, + //int GrowthRate; + 200, + + //int MaxSubclassNumber; + 0, + //int UOffsetForSubclass; + 0, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_INVCOLOUR, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {128,128,128,128,128}, + //unsigned char GreenScale; + {128,128,128,128,128}, + //unsigned char BlueScale; + {128,128,128,128,128}, + + //unsigned char IsLit:1; + 0, + //unsigned char CanCombine:1; + 0, + + }, + /* DECAL_BULLETHOLE */ + { + //int StartU; + 224<<16, + //int StartV; + 224<<16, + //int EndU; + 255<<16, + //int EndV; + 255<<16, + + //int MinSize; + 32, + //int MaxSize; + 32, + //int GrowthRate; + 0, + + //int MaxSubclassNumber; + 0, + //int UOffsetForSubclass; + 0, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_INVCOLOUR, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255,255,255,255,255}, + //unsigned char GreenScale; + {255,255,255,255,255}, + //unsigned char BlueScale; + {255,255,255,255,255}, + + //unsigned char IsLit:1; + 0, + //unsigned char CanCombine:1; + 0, + }, + /* DECAL_PREDATOR_BLOOD */ + { + //int StartU; + (0)<<16, + //int StartV; + 224<<16, + //int EndU; + (31)<<16, + //int EndV; + 255<<16, + + //int MinSize; + 20, + //int MaxSize; + 400, + //int GrowthRate; + 100, + + //int MaxSubclassNumber; + 3, + //int UOffsetForSubclass; + 32<<16, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 128, + //unsigned char RedScale; + {0, 0, 192, 0, 255}, + //unsigned char GreenScale; + {255, 255, 255, 255, 0}, + //unsigned char BlueScale; + {0, 0, 192, 255, 0}, + + //unsigned char IsLit:1; + 0, + //unsigned char CanCombine:1; + 1, + }, + /* DECAL_ALIEN_BLOOD */ + { + //int StartU; + 0<<16, + //int StartV; + 64<<16, + //int EndU; + 63<<16, + //int EndV; + 127<<16, + + //int MinSize; + 20, + //int MaxSize; + 400, + //int GrowthRate; + 100, + + //int MaxSubclassNumber; + 0, + //int UOffsetForSubclass; + 0, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 128, + //unsigned char RedScale; + {255, 255, 0, 128, 128}, + //unsigned char GreenScale; + {255, 255, 255, 128, 128}, + //unsigned char BlueScale; + {0, 0, 0, 128, 128}, + + //unsigned char IsLit:1; + 1, + //unsigned char CanCombine:1; + 1, + + }, + /* DECAL_HUMAN_BLOOD */ + { + //int StartU; + (0)<<16, + //int StartV; + 224<<16, + //int EndU; + (31)<<16, + //int EndV; + 255<<16, + + //int MinSize; + 20, + //int MaxSize; + 400, + //int GrowthRate; + 100, + + //int MaxSubclassNumber; + 4, + //int UOffsetForSubclass; + 32<<16, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_INVCOLOUR,//GLOWING, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {64, 64, 255, 0, 0}, + //unsigned char GreenScale; + {192, 192, 192, 112, 112}, + //unsigned char BlueScale; + {192, 192, 255, 112, 112}, + + //unsigned char IsLit:1; + 0, + //unsigned char CanCombine:1; + 1, + + }, + /* DECAL_ANDROID_BLOOD */ + { + //int StartU; + (0)<<16, + //int StartV; + 224<<16, + //int EndU; + (31)<<16, + //int EndV; + 255<<16, + + //int MinSize; + 20, + //int MaxSize; + 400, + //int GrowthRate; + 100, + + //int MaxSubclassNumber; + 3, + //int UOffsetForSubclass; + 32<<16, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 128, + //unsigned char RedScale; + {255, 255, 255, 255, 255}, + //unsigned char GreenScale; + {255, 255, 255, 255, 255}, + //unsigned char BlueScale; + {255, 255, 255, 255, 255}, + + //unsigned char IsLit:1; + 1, + //unsigned char CanCombine:1; + 1, + }, + + /* DECAL_LASERTARGET */ + { + //int StartU; + 0<<16, + //int StartV; + 0<<16, + //int EndU; + 63<<16, + //int EndV; + 63<<16, + + //int MinSize; + 20, + //int MaxSize; + 20, + //int GrowthRate; + 0, + + //int MaxSubclassNumber; + 0, + //int UOffsetForSubclass; + 0, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255, 255, 255, 255, 255}, + //unsigned char GreenScale; + {0, 0, 255, 255, 255}, + //unsigned char BlueScale; + {0, 0, 255, 255, 255}, + + //unsigned char IsLit:1; + 0, + //unsigned char CanCombine:1; + 0, + + }, + /* DECAL_SHAFTOFLIGHT */ + { + //int StartU; + 0, + //int StartV; + 0, + //int EndU; + 0, + //int EndV; + 0, + + //int MinSize; + 0, + //int MaxSize; + 0, + //int GrowthRate; + 0, + + //int MaxSubclassNumber; + 0, + //int UOffsetForSubclass; + 0, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255,255,255,255}, + //unsigned char GreenScale; + {255,255,255,255}, + //unsigned char BlueScale; + {192,192,192,192}, + + //unsigned char IsLit:1; + 0, + //unsigned char CanCombine:1; + 0, + + }, + /* DECAL_SHAFTOFLIGHT_OUTER */ + { + //int StartU; + 0, + //int StartV; + 0, + //int EndU; + 0, + //int EndV; + 0, + + //int MinSize; + 0, + //int MaxSize; + 0, + //int GrowthRate; + 0, + + //int MaxSubclassNumber; + 0, + //int UOffsetForSubclass; + 0, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 32, + //unsigned char RedScale; + {255,255,255,255}, + //unsigned char GreenScale; + {255,255,255,255}, + //unsigned char BlueScale; + {192,192,192,192}, + + //unsigned char IsLit:1; + 0, + //unsigned char CanCombine:1; + 0, + + }, + +}; + + + +static DECAL* AllocateDecal(void); +static int TooManyDecalsOfThisType(enum DECAL_ID decalID, VECTORCH *positionPtr); + +void InitialiseDecalSystem(void) +{ +// VECTORCH normal = {0,0,65536}; +// VECTORCH position = {-1603,2675,8000}; + NumActiveDecals=0; + CurrentDecalIndex=0; + + // MakeDecal(DECAL_FMV, &normal,&position,1); +} + +static DECAL* AllocateDecal(void) +{ + DECAL *decalPtr; + + decalPtr = &DecalStorage[CurrentDecalIndex]; + + CurrentDecalIndex++; + if (CurrentDecalIndex>=LocalDetailLevels.MaximumAllowedNumberOfDecals) + { + CurrentDecalIndex=0; + } + + if (NumActiveDecals < LocalDetailLevels.MaximumAllowedNumberOfDecals) + { + NumActiveDecals++; + } + + LOCALASSERT(decalPtr); + return decalPtr; +} + +extern FIXED_DECAL* AllocateFixedDecal(void) +{ + FIXED_DECAL *decalPtr; + + + if (CurrentFixedDecalIndex>=MAX_NO_OF_FIXED_DECALS) + { + return 0; + } + + decalPtr = &FixedDecalStorage[CurrentFixedDecalIndex]; + CurrentFixedDecalIndex++; + NumFixedDecals++; + + LOCALASSERT(decalPtr); + return decalPtr; +} +extern void RemoveFixedDecal(void) +{ + if (CurrentFixedDecalIndex) + { + CurrentFixedDecalIndex--; + NumFixedDecals--; + } +} + +extern void RemoveAllFixedDecals(void) +{ + if (PaintBallMode.IsOn) + { + /* pretty drastic */ + CurrentFixedDecalIndex = 0; + NumFixedDecals = 0; + } +} +void MakeDecal(enum DECAL_ID decalID, VECTORCH *normalPtr, VECTORCH *positionPtr, int moduleIndex) +{ + if (TooManyDecalsOfThisType(decalID,positionPtr)) return; + AddDecal(decalID,normalPtr,positionPtr,moduleIndex); + + /* no blood across network? */ + if(AvP.Network!=I_No_Network) + { + if(netGameData.sendDecals) + { + switch (decalID) + { + case DECAL_BULLETHOLE: + case DECAL_SCORCHED: + { + AddNetMsg_MakeDecal(decalID,normalPtr,positionPtr,moduleIndex); + break; + } + default: + break; + } + } + } +} + +#define MAX_NO_OF_SIMILAR_DECALS_IN_ONE_PLACE 4 +#define INCREMENT_IN_DECAL_SIZE (25*4) +static int TooManyDecalsOfThisType(enum DECAL_ID decalID, VECTORCH *positionPtr) +{ + int i = NumActiveDecals; + DECAL *decalPtr = DecalStorage; + DECAL *similarDecalsPtr[MAX_NO_OF_SIMILAR_DECALS_IN_ONE_PLACE]; + + int minX,maxX, minY,maxY, minZ,maxZ; + int decalsOfThisType = 0; + { + int decalSize = DecalDescription[decalID].MaxSize; + minX = positionPtr->vx - decalSize; + maxX = positionPtr->vx + decalSize; + minY = positionPtr->vy - decalSize; + maxY = positionPtr->vy + decalSize; + minZ = positionPtr->vz - decalSize; + maxZ = positionPtr->vz + decalSize; + } + + while(i--) + { + if (decalPtr->DecalID == decalID) + { + if (decalPtr->Centre.vx > minX && decalPtr->Centre.vx < maxX) + if (decalPtr->Centre.vy > minY && decalPtr->Centre.vy < maxY) + if (decalPtr->Centre.vz > minZ && decalPtr->Centre.vz < maxZ) + { + similarDecalsPtr[decalsOfThisType] = decalPtr; + decalsOfThisType++; + } + + } + if (decalsOfThisType>=MAX_NO_OF_SIMILAR_DECALS_IN_ONE_PLACE) + { + if (DecalDescription[decalID].CanCombine) + { + int j;//= FastRandom()%MAX_NO_OF_SIMILAR_DECALS_IN_ONE_PLACE; + for (j=0; jTargetSize += INCREMENT_IN_DECAL_SIZE; + if (similarDecalsPtr[j]->TargetSize > DecalDescription[decalID].MaxSize) + { + similarDecalsPtr[j]->TargetSize = DecalDescription[decalID].MaxSize; + } + else + { + break; + } + } + } + return 1; + } + decalPtr++; + } + + return 0; +} + +void AddDecal(enum DECAL_ID decalID, VECTORCH *normalPtr, VECTORCH *positionPtr, int moduleIndex) +{ + DECAL *decalPtr; + MATRIXCH orientation; + int decalSize; + extern int sine[],cosine[]; + int theta = FastRandom()&4095; + int sin = GetSin(theta); + int cos = GetCos(theta); + + + MakeMatrixFromDirection(normalPtr,&orientation); + + if (decalID == DECAL_BULLETHOLE) + { + MakeImpactSmoke(&orientation,positionPtr); + } + + decalPtr = AllocateDecal(); + + decalPtr->DecalID = decalID; + + decalPtr->Centre = *positionPtr; + + if(DecalDescription[decalID].GrowthRate) + { + decalSize = ONE_FIXED; + decalPtr->Direction[0].vx = MUL_FIXED(-decalSize,cos) - MUL_FIXED(-decalSize,sin); + decalPtr->Direction[0].vy = MUL_FIXED(-decalSize,sin) + MUL_FIXED(-decalSize,cos); + decalPtr->Direction[0].vz = DECAL_Z_OFFSET; + RotateVector(&(decalPtr->Direction[0]),&orientation); + Normalise(&(decalPtr->Direction[0])); + + decalPtr->Direction[1].vx = MUL_FIXED(decalSize,cos) - MUL_FIXED(-decalSize,sin); + decalPtr->Direction[1].vy = MUL_FIXED(decalSize,sin) + MUL_FIXED(-decalSize,cos); + decalPtr->Direction[1].vz = DECAL_Z_OFFSET; + RotateVector(&(decalPtr->Direction[1]),&orientation); + Normalise(&(decalPtr->Direction[1])); + + decalPtr->Direction[2].vx = MUL_FIXED(decalSize,cos) - MUL_FIXED(decalSize,sin); + decalPtr->Direction[2].vy = MUL_FIXED(decalSize,sin) + MUL_FIXED(decalSize,cos); + decalPtr->Direction[2].vz = DECAL_Z_OFFSET; + RotateVector(&(decalPtr->Direction[2]),&orientation); + Normalise(&(decalPtr->Direction[2])); + + decalPtr->Direction[3].vx = MUL_FIXED(-decalSize,cos) - MUL_FIXED(decalSize,sin); + decalPtr->Direction[3].vy = MUL_FIXED(-decalSize,sin) + MUL_FIXED(decalSize,cos); + decalPtr->Direction[3].vz = DECAL_Z_OFFSET; + RotateVector(&(decalPtr->Direction[3]),&orientation); + Normalise(&(decalPtr->Direction[3])); + decalPtr->CurrentSize = DecalDescription[decalID].MinSize; + decalPtr->TargetSize = DecalDescription[decalID].MaxSize; + if (DecalDescription[decalID].CanCombine) decalPtr->TargetSize/=4; + } + else + { + decalSize = DecalDescription[decalID].MinSize; + decalPtr->Vertices[0].vx = MUL_FIXED(-decalSize,cos) - MUL_FIXED(-decalSize,sin); + decalPtr->Vertices[0].vy = MUL_FIXED(-decalSize,sin) + MUL_FIXED(-decalSize,cos); + decalPtr->Vertices[0].vz = DECAL_Z_OFFSET; + RotateVector(&(decalPtr->Vertices[0]),&orientation); + decalPtr->Vertices[0].vx += positionPtr->vx; + decalPtr->Vertices[0].vy += positionPtr->vy; + decalPtr->Vertices[0].vz += positionPtr->vz; + + + decalPtr->Vertices[1].vx = MUL_FIXED(decalSize,cos) - MUL_FIXED(-decalSize,sin); + decalPtr->Vertices[1].vy = MUL_FIXED(decalSize,sin) + MUL_FIXED(-decalSize,cos); + decalPtr->Vertices[1].vz = DECAL_Z_OFFSET; + RotateVector(&(decalPtr->Vertices[1]),&orientation); + decalPtr->Vertices[1].vx += positionPtr->vx; + decalPtr->Vertices[1].vy += positionPtr->vy; + decalPtr->Vertices[1].vz += positionPtr->vz; + + decalPtr->Vertices[2].vx = MUL_FIXED(decalSize,cos) - MUL_FIXED(decalSize,sin); + decalPtr->Vertices[2].vy = MUL_FIXED(decalSize,sin) + MUL_FIXED(decalSize,cos); + decalPtr->Vertices[2].vz = DECAL_Z_OFFSET; + RotateVector(&(decalPtr->Vertices[2]),&orientation); + decalPtr->Vertices[2].vx += positionPtr->vx; + decalPtr->Vertices[2].vy += positionPtr->vy; + decalPtr->Vertices[2].vz += positionPtr->vz; + + decalPtr->Vertices[3].vx = MUL_FIXED(-decalSize,cos) - MUL_FIXED(decalSize,sin); + decalPtr->Vertices[3].vy = MUL_FIXED(-decalSize,sin) + MUL_FIXED(decalSize,cos); + decalPtr->Vertices[3].vz = DECAL_Z_OFFSET; + RotateVector(&(decalPtr->Vertices[3]),&orientation); + decalPtr->Vertices[3].vx += positionPtr->vx; + decalPtr->Vertices[3].vy += positionPtr->vy; + decalPtr->Vertices[3].vz += positionPtr->vz; + + } + + decalPtr->ModuleIndex = moduleIndex; + + switch (decalID) + { + case DECAL_HUMAN_BLOOD: + case DECAL_PREDATOR_BLOOD: + case DECAL_ANDROID_BLOOD: + { + decalPtr->UOffset = (FastRandom()&1)*(32<<16); + if (normalPtr->vy<-32768) + { + decalPtr->UOffset+=64<<16; + } + else + { + decalPtr->TargetSize = DecalDescription[decalID].MaxSize; + decalPtr->CurrentSize = decalPtr->TargetSize-1; + } + break; + } + default: + { + decalPtr->UOffset = 0; + break; + } + + } + +} + +void RenderLaserTarget(THREE_LASER_DOT_DESC *laserTargetPtr) +{ + extern MODULE * playerPherModule; + int i; + + if(!playerPherModule) return; + + i=2; + do + { + DECAL decal; + MATRIXCH orientation; + int decalSize; + VECTORCH *positionPtr = &(laserTargetPtr->Position[i]); + + MakeMatrixFromDirection(&(laserTargetPtr->Normal[i]),&orientation); + + decal.DecalID = DECAL_LASERTARGET; + decalSize = DecalDescription[DECAL_LASERTARGET].MaxSize; + + decal.Vertices[0].vx = -decalSize; + decal.Vertices[0].vy = -decalSize; + decal.Vertices[0].vz = DECAL_Z_OFFSET; + RotateVector(&(decal.Vertices[0]),&orientation); + decal.Vertices[0].vx += positionPtr->vx; + decal.Vertices[0].vy += positionPtr->vy; + decal.Vertices[0].vz += positionPtr->vz; + + decal.Vertices[1].vx = decalSize; + decal.Vertices[1].vy = -decalSize; + decal.Vertices[1].vz = DECAL_Z_OFFSET; + RotateVector(&(decal.Vertices[1]),&orientation); + decal.Vertices[1].vx += positionPtr->vx; + decal.Vertices[1].vy += positionPtr->vy; + decal.Vertices[1].vz += positionPtr->vz; + + decal.Vertices[2].vx = decalSize; + decal.Vertices[2].vy = decalSize; + decal.Vertices[2].vz = DECAL_Z_OFFSET; + RotateVector(&(decal.Vertices[2]),&orientation); + decal.Vertices[2].vx += positionPtr->vx; + decal.Vertices[2].vy += positionPtr->vy; + decal.Vertices[2].vz += positionPtr->vz; + + decal.Vertices[3].vx = -decalSize; + decal.Vertices[3].vy = decalSize; + decal.Vertices[3].vz = DECAL_Z_OFFSET; + RotateVector(&(decal.Vertices[3]),&orientation); + decal.Vertices[3].vx += positionPtr->vx; + decal.Vertices[3].vy += positionPtr->vy; + decal.Vertices[3].vz += positionPtr->vz; + + decal.ModuleIndex = playerPherModule->m_index; + decal.UOffset = 0; + RenderDecal(&decal); + } + while(i--); +} + +void HandleDecalSystem(void) +{ + D3D_DecalSystem_Setup(); + + if (NumActiveDecals > LocalDetailLevels.MaximumAllowedNumberOfDecals) + { + NumActiveDecals = LocalDetailLevels.MaximumAllowedNumberOfDecals; + } + + { + int i = NumActiveDecals; + DECAL *decalPtr = DecalStorage; + // textprint("Decals Active: %d\n",i); + while(i--) + { + DECAL_DESC *decalDescPtr = &DecalDescription[decalPtr->DecalID]; + + if (decalDescPtr->GrowthRate && decalPtr->CurrentSize < decalPtr->TargetSize) + { + int i; + extern int NormalFrameTime; + decalPtr->CurrentSize += MUL_FIXED(decalDescPtr->GrowthRate,NormalFrameTime); + if (decalPtr->CurrentSize > decalPtr->TargetSize) + { + decalPtr->CurrentSize = decalPtr->TargetSize; + } + for (i=0; i<4; i++) + { + decalPtr->Vertices[i].vx = MUL_FIXED(decalPtr->Direction[i].vx,decalPtr->CurrentSize); + decalPtr->Vertices[i].vy = MUL_FIXED(decalPtr->Direction[i].vy,decalPtr->CurrentSize); + decalPtr->Vertices[i].vz = MUL_FIXED(decalPtr->Direction[i].vz,decalPtr->CurrentSize); + decalPtr->Vertices[i].vx += decalPtr->Centre.vx; + decalPtr->Vertices[i].vy += decalPtr->Centre.vy; + decalPtr->Vertices[i].vz += decalPtr->Centre.vz; + } + + } + RenderDecal(decalPtr); + decalPtr++; + } + } + { + int i = NumFixedDecals; + DECAL dummyDecal; + FIXED_DECAL *decalPtr = FixedDecalStorage; + // textprint("Decals Active: %d\n",i); + while(i--) + { + dummyDecal.DecalID = decalPtr->DecalID; + dummyDecal.Vertices[0] = decalPtr->Vertices[0]; + dummyDecal.Vertices[1] = decalPtr->Vertices[1]; + dummyDecal.Vertices[2] = decalPtr->Vertices[2]; + dummyDecal.Vertices[3] = decalPtr->Vertices[3]; + dummyDecal.ModuleIndex = decalPtr->ModuleIndex; + dummyDecal.UOffset = decalPtr->UOffset; + + RenderDecal(&dummyDecal); + decalPtr++;; + } + } +// CubeOMatic(); + if (AvP.PlayerType == I_Predator && PredatorLaserTarget.ShouldBeDrawn) + { + RenderLaserTarget(&PredatorLaserTarget); + } + + + { + extern int NumActiveBlocks; + extern DISPLAYBLOCK *ActiveBlockList[]; + int numOfObjects = NumActiveBlocks; + while(numOfObjects) + { + DISPLAYBLOCK *objectPtr = ActiveBlockList[--numOfObjects]; + STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock; + + if (sbPtr) + { + switch(sbPtr->I_SBtype) + { + case (I_BehaviourNetGhost): + { + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + GLOBALASSERT(AvP.Network!=I_No_Network); + if (ghostData->type == I_BehaviourPredatorPlayer) + { + extern DPID AVPDPNetID; + int playerIndex = PlayerIdInPlayerList(ghostData->playerId); + if(playerIndex==NET_IDNOTINPLAYERLIST) + { + continue; + } + if ((ghostData->CurrentWeapon != WEAPON_PRED_RIFLE) + &&(ghostData->CurrentWeapon != WEAPON_PRED_SHOULDERCANNON)) + { + continue; + } + + if (AVPDPNetID==PredatorLaserSights[playerIndex].TargetID) + { + SECTION_DATA *plasma_muzzle; + plasma_muzzle=GetThisSectionData(ghostData->HModelController.section_data,"dum flash"); + if (plasma_muzzle!=NULL) + { + extern void RenderLightFlare(VECTORCH *positionPtr, unsigned int colour); + RenderLightFlare(&plasma_muzzle->World_Offset,0xffff0000); + } + } + else + { + RenderLaserTarget(&PredatorLaserSights[playerIndex]); + } + } + break; + } + case (I_BehaviourPredator): + { + extern void RenderLightFlare(VECTORCH *positionPtr, unsigned int colour); + PREDATOR_STATUS_BLOCK *statusPtr = (PREDATOR_STATUS_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(statusPtr); +// RenderLightFlare(&(sbPtr->DynPtr->Position),0x7fffffff); +// textprint("predator?\n"); + if(statusPtr->Pred_Laser_On) + { + if (statusPtr->Pred_Laser_Sight.DotIsOnPlayer) + { +// textprint("Render flare\n"); + RenderLightFlare(&(statusPtr->Pred_Laser_Sight.LightSource),0xffff0000); + } + else + { +// textprint("Render dots\n"); + RenderLaserTarget(&(statusPtr->Pred_Laser_Sight)); + } + } + break; + + } + default: + break; + } + + } + } + } + + /* KJL 11:03:53 01/10/98 - check for paintball mode */ + { + if (PaintBallMode.IsOn) + { + PaintBallMode_DrawCurrentDecalAtTarget(); + } + } +} + +void AddDecalToHModel(VECTORCH *normalPtr, VECTORCH *positionPtr, SECTION_DATA *sectionDataPtr) +{ + enum DECAL_ID decalID; + OBJECT_DECAL *decalPtr; + MATRIXCH orientation; + VECTORCH v; + + int decalSize; + extern int sine[],cosine[]; + int theta,sin,cos; + + if (!LocalDetailLevels.DrawHierarchicalDecals) return; + + theta = FastRandom()&4095; + sin = GetSin(theta); + cos = GetCos(theta); + + + LOCALASSERT(sectionDataPtr->NumberOfDecals <= MAX_NO_OF_DECALS_PER_HIERARCHICAL_SECTION); + { + MATRIXCH mat = sectionDataPtr->SecMat; + VECTORCH n = *normalPtr; + + TransposeMatrixCH(&mat); + + RotateVector(&n,&mat); + MakeMatrixFromDirection(&n,&orientation); + + v = *positionPtr; + v.vx -= sectionDataPtr->World_Offset.vx; + v.vy -= sectionDataPtr->World_Offset.vy; + v.vz -= sectionDataPtr->World_Offset.vz; + RotateVector(&v,&mat); + } + + + { + SECTION *sectionPtr = sectionDataPtr->sempai; + + if(sectionPtr->flags§ion_sprays_blood) + { + decalID = DECAL_HUMAN_BLOOD; + } + else if(sectionPtr->flags§ion_sprays_predoblood) + { + decalID = DECAL_PREDATOR_BLOOD; + } + else if(sectionPtr->flags§ion_sprays_acid) + { + decalID = DECAL_ALIEN_BLOOD; + } + else + { + decalID = DECAL_BULLETHOLE; + } + + } + + decalPtr = §ionDataPtr->Decals[sectionDataPtr->NextDecalToUse]; + + if (sectionDataPtr->NextDecalToUse >= MAX_NO_OF_DECALS_PER_HIERARCHICAL_SECTION-1) + { + sectionDataPtr->NextDecalToUse = 0; + } + else + { + sectionDataPtr->NextDecalToUse++; + } + + if (sectionDataPtr->NumberOfDecals < MAX_NO_OF_DECALS_PER_HIERARCHICAL_SECTION) + { + sectionDataPtr->NumberOfDecals++; + } + + + decalPtr->DecalID = decalID; + decalSize = 40;//DecalDescription[decalID].MaxSize; + + decalPtr->Centre = v; + + decalPtr->Vertices[0].vx = MUL_FIXED(-decalSize,cos) - MUL_FIXED(-decalSize,sin); + decalPtr->Vertices[0].vy = MUL_FIXED(-decalSize,sin) + MUL_FIXED(-decalSize,cos); + decalPtr->Vertices[0].vz = DECAL_Z_OFFSET; + RotateVector(&(decalPtr->Vertices[0]),&orientation); + decalPtr->Vertices[0].vx += v.vx; + decalPtr->Vertices[0].vy += v.vy; + decalPtr->Vertices[0].vz += v.vz; + + decalPtr->Vertices[1].vx = MUL_FIXED(decalSize,cos) - MUL_FIXED(-decalSize,sin); + decalPtr->Vertices[1].vy = MUL_FIXED(decalSize,sin) + MUL_FIXED(-decalSize,cos); + decalPtr->Vertices[1].vz = DECAL_Z_OFFSET; + RotateVector(&(decalPtr->Vertices[1]),&orientation); + decalPtr->Vertices[1].vx += v.vx; + decalPtr->Vertices[1].vy += v.vy; + decalPtr->Vertices[1].vz += v.vz; + + decalPtr->Vertices[2].vx = MUL_FIXED(decalSize,cos) - MUL_FIXED(decalSize,sin); + decalPtr->Vertices[2].vy = MUL_FIXED(decalSize,sin) + MUL_FIXED(decalSize,cos); + decalPtr->Vertices[2].vz = DECAL_Z_OFFSET; + RotateVector(&(decalPtr->Vertices[2]),&orientation); + decalPtr->Vertices[2].vx += v.vx; + decalPtr->Vertices[2].vy += v.vy; + decalPtr->Vertices[2].vz += v.vz; + + decalPtr->Vertices[3].vx = MUL_FIXED(-decalSize,cos) - MUL_FIXED(decalSize,sin); + decalPtr->Vertices[3].vy = MUL_FIXED(-decalSize,sin) + MUL_FIXED(decalSize,cos); + decalPtr->Vertices[3].vz = DECAL_Z_OFFSET; + RotateVector(&(decalPtr->Vertices[3]),&orientation); + decalPtr->Vertices[3].vx += v.vx; + decalPtr->Vertices[3].vy += v.vy; + decalPtr->Vertices[3].vz += v.vz; +} + + +void ScanHModelForDecals(DISPLAYBLOCK *objectPtr, SECTION_DATA *sectionDataPtr) +{ + SECTION *sectionPtr = sectionDataPtr->sempai; + + /* Unreal things aren't drawn... */ + if (!(sectionDataPtr->flags§ion_data_notreal) && (sectionPtr->Shape!=NULL)) + { + /* does the object have decals? */ + extern MODULE *playerPherModule; + if(sectionDataPtr->NumberOfDecals && playerPherModule) + { + int d; + for(d=0; dNumberOfDecals; d++) + { + int i; + DECAL decal; + decal.DecalID = sectionDataPtr->Decals[d].DecalID; + decal.ModuleIndex = playerPherModule->m_index; + decal.UOffset = 0; + + for(i=0; i<5; i++) + { + decal.Vertices[i] = sectionDataPtr->Decals[d].Vertices[i]; + RotateVector(&(decal.Vertices[i]),&(sectionDataPtr->SecMat)); + decal.Vertices[i].vx += sectionDataPtr->World_Offset.vx; + decal.Vertices[i].vy += sectionDataPtr->World_Offset.vy; + decal.Vertices[i].vz += sectionDataPtr->World_Offset.vz; + } + RenderDecal(&decal); + } + } + } + + /* Now call recursion... */ + if (sectionDataPtr->First_Child!=NULL) + { + SECTION_DATA *childrenListPtr = sectionDataPtr->First_Child; + + while (childrenListPtr!=NULL) + { + ScanHModelForDecals(objectPtr,childrenListPtr); + childrenListPtr=childrenListPtr->Next_Sibling; + } + } + +} + + + +/*------------------** +** Load/Save Decals ** +**------------------*/ + +typedef struct decal_save_block_header +{ + SAVE_BLOCK_HEADER header; + + int NumActiveDecals; + + //followed by array of decals +}DECAL_SAVE_BLOCK_HEADER; + +void Load_Decals(SAVE_BLOCK_HEADER* header) +{ + int i; + DECAL_SAVE_BLOCK_HEADER* block = (DECAL_SAVE_BLOCK_HEADER*) header; + DECAL* saved_decal = (DECAL*) (block+1); + int expected_size; + + //make sure the block is the correct size + expected_size = sizeof(*block); + expected_size += sizeof(DECAL) * block->NumActiveDecals; + if(header->size != expected_size) return; + + + for(i=0;iNumActiveDecals;i++) + { + DECAL* decal = AllocateDecal(); + if(decal) + { + *decal = *saved_decal++; + } + } + +} + +void Save_Decals() +{ + DECAL_SAVE_BLOCK_HEADER* block; + int i; + + if(!NumActiveDecals) return; + + //get memory for header + GET_SAVE_BLOCK_POINTER(block); + + //fill in header + block->header.type = SaveBlock_Decals; + block->header.size = sizeof(*block) + NumActiveDecals * sizeof(DECAL); + + block->NumActiveDecals = NumActiveDecals; + + + //now save the decals + for(i=0;iIsAlive==0) { + return; + } + + CurrentGameStatistics.IntegralSpeed+=(MUL_FIXED(speed,time)); + +} + +extern void CurrentGameStats_DamageTaken(unsigned int health,unsigned int armour) { + + if (PlayerStatusPtr->IsAlive==0) { + return; + } + + CurrentGameStatistics.HealthDamage+=health; + CurrentGameStatistics.ArmourDamage+=armour; + +} + +extern void CurrentGameStats_ChargeUsed(unsigned int charge) { + + if (PlayerStatusPtr->IsAlive==0) { + return; + } + + CurrentGameStatistics.FieldChargeUsed+=charge; + +} + +extern void CurrentGameStats_VisionMode(enum VISION_MODE_ID mode) { + + if (PlayerStatusPtr->IsAlive==0) { + return; + } + + CurrentGameStatistics.VisionModeTimes[mode]+=NormalFrameTime; + +} + +extern void CurrentGameStats_CloakOn(void) { + + if (PlayerStatusPtr->IsAlive==0) { + return; + } + + CurrentGameStatistics.Cloak_ElapsedSeconds += NormalFrameTime; + + if(CurrentGameStatistics.Cloak_ElapsedSeconds >= FIXED_MINUTE) + { + CurrentGameStatistics.Cloak_ElapsedSeconds -= FIXED_MINUTE; + CurrentGameStatistics.Cloak_ElapsedMinutes ++; + } + + if(CurrentGameStatistics.Cloak_ElapsedMinutes >= 60) + { + CurrentGameStatistics.Cloak_ElapsedMinutes -= 60; + CurrentGameStatistics.Cloak_ElapsedHours ++; + } + +} + +extern void CurrentGameStats_WeaponFired(enum WEAPON_SLOT slot,unsigned int rounds) { + + if (PlayerStatusPtr->IsAlive==0) { + return; + } + + if ((slot>=0)&&(slot<=MAX_NO_OF_WEAPON_SLOTS)) { + CurrentGameStatistics.ShotsFired[slot]+=rounds; + } + +} + +extern void CurrentGameStats_WeaponHit(enum WEAPON_SLOT slot,unsigned int rounds) { + + if (PlayerStatusPtr->IsAlive==0) { + return; + } + + if ((slot>=0)&&(slot<=MAX_NO_OF_WEAPON_SLOTS)) { + CurrentGameStatistics.ShotsHit[slot]+=rounds; + } + +} + +extern void CurrentGameStats_UsingWeapon(enum WEAPON_SLOT slot) { + + if (PlayerStatusPtr->IsAlive==0) { + return; + } + + if ((slot>=0)&&(slot<=MAX_NO_OF_WEAPON_SLOTS)) { + CurrentGameStatistics.WeaponTimes[slot]+=NormalFrameTime; + } + +} + +extern void CurrentGameStats_Spotted(void) { + + if (PlayerStatusPtr->IsAlive==0) { + return; + } + + CurrentGameStatistics.Spotted++; + +} + +extern void PrintSpottedNumber(void) { + + /* It must be in this file... */ + + textprint("Spotted: %d\n",CurrentGameStatistics.Spotted); + textprint("Size %d\n",sizeof(AvP_GameStats_Stored)); + +} + +extern void CurrentGameStats_HeadBitten(STRATEGYBLOCK *sbPtr) { + + if (PlayerStatusPtr->IsAlive==0) { + return; + } + + switch (sbPtr->I_SBtype) { + case I_BehaviourAlien: + { + ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr; + + switch (alienStatus->Type) + { + case 0: + default: + CurrentGameStatistics.LiveHeadBites[STATS_VICTIM_XENOMORPH]++; + break; + case 1: + CurrentGameStatistics.LiveHeadBites[STATS_VICTIM_PREDALIEN]++; + break; + case 2: + CurrentGameStatistics.LiveHeadBites[STATS_VICTIM_PRAETORIAN]++; + break; + } + + break; + } + case I_BehaviourMarine: + { + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + + if (marineStatusPointer->My_Weapon->Android) + { + CurrentGameStatistics.LiveHeadBites[STATS_VICTIM_ANDROID]++; + } + else if (marineStatusPointer->My_Weapon->ARealMarine) + { + CurrentGameStatistics.LiveHeadBites[STATS_VICTIM_MARINE]++; + } + else + { + CurrentGameStatistics.LiveHeadBites[STATS_VICTIM_CIVILIAN]++; + } + break; + } + case I_BehaviourQueenAlien: + { + CurrentGameStatistics.LiveHeadBites[STATS_VICTIM_QUEEN]++; + break; + } + case I_BehaviourFaceHugger: + { + CurrentGameStatistics.LiveHeadBites[STATS_VICTIM_FACEHUGGER]++; + break; + } + case I_BehaviourXenoborg: + { + CurrentGameStatistics.LiveHeadBites[STATS_VICTIM_XENOBORG]++; + break; + } + case I_BehaviourPredator: + { + CurrentGameStatistics.LiveHeadBites[STATS_VICTIM_PREDATOR]++; + break; + } + case I_BehaviourNetCorpse: + { + NETCORPSEDATABLOCK *corpseDataPtr; + + LOCALASSERT(sbPtr); + corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(corpseDataPtr); + + switch (corpseDataPtr->Type) + { + case I_BehaviourAlien: + { + switch (corpseDataPtr->subtype) + { + case 0: + default: + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_XENOMORPH]++; + break; + case 1: + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_PREDALIEN]++; + break; + case 2: + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_PRAETORIAN]++; + break; + } + break; + } + case I_BehaviourMarine: + { + + if (corpseDataPtr->Android) + { + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_ANDROID]++; + } + else if (corpseDataPtr->ARealMarine) + { + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_MARINE]++; + } + else + { + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_CIVILIAN]++; + } + break; + } + case I_BehaviourQueenAlien: + { + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_QUEEN]++; + break; + } + case I_BehaviourFaceHugger: + { + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_FACEHUGGER]++; + break; + } + case I_BehaviourXenoborg: + { + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_XENOBORG]++; + break; + } + + + case I_BehaviourPredator: + { + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_PREDATOR]++; + break; + } + default: + { + break; + } + } + break; + } + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *ghostData; + + LOCALASSERT(sbPtr); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + switch (ghostData->type) { + case I_BehaviourMarinePlayer: + CurrentGameStatistics.LiveHeadBites[STATS_VICTIM_MARINE]++; + break; + case I_BehaviourAlienPlayer: + CurrentGameStatistics.LiveHeadBites[STATS_VICTIM_XENOMORPH]++; + break; + case I_BehaviourPredatorPlayer: + CurrentGameStatistics.LiveHeadBites[STATS_VICTIM_PREDATOR]++; + break; + case I_BehaviourNetCorpse: + { + switch (ghostData->subtype) { + case I_BehaviourAlien: + { + switch (ghostData->IOType) { + /* Hey ho, it was free... */ + case 0: + default: + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_XENOMORPH]++; + break; + case 1: + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_PREDALIEN]++; + break; + case 2: + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_PRAETORIAN]++; + break; + } + break; + } + case I_BehaviourMarinePlayer: + { + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_MARINE]++; + break; + } + case I_BehaviourAlienPlayer: + { + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_XENOMORPH]++; + break; + } + case I_BehaviourPredatorPlayer: + { + CurrentGameStatistics.DeadHeadBites[STATS_VICTIM_PREDATOR]++; + break; + } + default: + { + break; + } + } + break; + } + default: + { + break; + } + } + break; + } + default: + { + break; + } + } + +} + +extern void CurrentGameStats_TrophyCollected(STRATEGYBLOCK *sbPtr) { + + if (PlayerStatusPtr->IsAlive==0) { + return; + } + + /* It's always going to be a corpse or a ghost, isn't it? */ + + switch (sbPtr->I_SBtype) { + case I_BehaviourNetCorpse: + { + NETCORPSEDATABLOCK *corpseDataPtr; + + LOCALASSERT(sbPtr); + corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(corpseDataPtr); + + switch (corpseDataPtr->Type) + { + case I_BehaviourAlien: + { + switch (corpseDataPtr->subtype) + { + case 0: + default: + CurrentGameStatistics.Trophies[STATS_VICTIM_XENOMORPH]++; + break; + case 1: + CurrentGameStatistics.Trophies[STATS_VICTIM_PREDALIEN]++; + break; + case 2: + CurrentGameStatistics.Trophies[STATS_VICTIM_PRAETORIAN]++; + break; + } + break; + } + case I_BehaviourMarine: + { + + if (corpseDataPtr->Android) + { + CurrentGameStatistics.Trophies[STATS_VICTIM_ANDROID]++; + } + else if (corpseDataPtr->ARealMarine) + { + CurrentGameStatistics.Trophies[STATS_VICTIM_MARINE]++; + } + else + { + CurrentGameStatistics.Trophies[STATS_VICTIM_CIVILIAN]++; + } + break; + } + case I_BehaviourQueenAlien: + { + CurrentGameStatistics.Trophies[STATS_VICTIM_QUEEN]++; + break; + } + case I_BehaviourFaceHugger: + { + CurrentGameStatistics.Trophies[STATS_VICTIM_FACEHUGGER]++; + break; + } + case I_BehaviourXenoborg: + { + CurrentGameStatistics.Trophies[STATS_VICTIM_XENOBORG]++; + break; + } + + + case I_BehaviourPredator: + { + CurrentGameStatistics.Trophies[STATS_VICTIM_PREDATOR]++; + break; + } + default: + { + break; + } + } + break; + } + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *ghostData; + + LOCALASSERT(sbPtr); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + switch (ghostData->type) { + case I_BehaviourNetCorpse: + { + switch (ghostData->subtype) { + case I_BehaviourAlien: + { + switch (ghostData->IOType) { + /* Hey ho, it was free... */ + case 0: + default: + CurrentGameStatistics.Trophies[STATS_VICTIM_XENOMORPH]++; + break; + case 1: + CurrentGameStatistics.Trophies[STATS_VICTIM_PREDALIEN]++; + break; + case 2: + CurrentGameStatistics.Trophies[STATS_VICTIM_PRAETORIAN]++; + break; + } + break; + } + case I_BehaviourMarinePlayer: + { + CurrentGameStatistics.Trophies[STATS_VICTIM_MARINE]++; + break; + } + case I_BehaviourAlienPlayer: + { + CurrentGameStatistics.Trophies[STATS_VICTIM_XENOMORPH]++; + break; + } + case I_BehaviourPredatorPlayer: + { + CurrentGameStatistics.Trophies[STATS_VICTIM_PREDATOR]++; + break; + } + default: + { + break; + } + } + break; + } + default: + { + break; + } + } + break; + } + case I_BehaviourHierarchicalFragment: + { + HDEBRIS_BEHAV_BLOCK *debrisDataPtr; + + LOCALASSERT(sbPtr); + debrisDataPtr = (HDEBRIS_BEHAV_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(debrisDataPtr); + + switch (debrisDataPtr->Type) { + case I_BehaviourAlien: + { + switch (debrisDataPtr->SubType) + { + case 0: + default: + CurrentGameStatistics.Trophies[STATS_VICTIM_XENOMORPH]++; + break; + case 1: + CurrentGameStatistics.Trophies[STATS_VICTIM_PREDALIEN]++; + break; + case 2: + CurrentGameStatistics.Trophies[STATS_VICTIM_PRAETORIAN]++; + break; + } + break; + } + case I_BehaviourMarine: + { + + if (debrisDataPtr->Android) + { + CurrentGameStatistics.Trophies[STATS_VICTIM_ANDROID]++; + } + else if (debrisDataPtr->SubType) /* Means ARealMarine for fragments of marines */ + { + CurrentGameStatistics.Trophies[STATS_VICTIM_MARINE]++; + } + else + { + CurrentGameStatistics.Trophies[STATS_VICTIM_CIVILIAN]++; + } + break; + } + case I_BehaviourQueenAlien: + { + CurrentGameStatistics.Trophies[STATS_VICTIM_QUEEN]++; + break; + } + case I_BehaviourFaceHugger: + { + CurrentGameStatistics.Trophies[STATS_VICTIM_FACEHUGGER]++; + break; + } + case I_BehaviourXenoborg: + { + CurrentGameStatistics.Trophies[STATS_VICTIM_XENOBORG]++; + break; + } + + + case I_BehaviourPredator: + { + CurrentGameStatistics.Trophies[STATS_VICTIM_PREDATOR]++; + break; + } + default: + { + break; + } + } + break; + } + case I_BehaviourSpeargunBolt: + { + SPEAR_BEHAV_BLOCK *spearDataPtr; + + LOCALASSERT(sbPtr); + spearDataPtr = (SPEAR_BEHAV_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(spearDataPtr); + + switch (spearDataPtr->Type) { + case I_BehaviourAlien: + { + switch (spearDataPtr->SubType) + { + case 0: + default: + CurrentGameStatistics.Trophies[STATS_VICTIM_XENOMORPH]++; + break; + case 1: + CurrentGameStatistics.Trophies[STATS_VICTIM_PREDALIEN]++; + break; + case 2: + CurrentGameStatistics.Trophies[STATS_VICTIM_PRAETORIAN]++; + break; + } + break; + } + case I_BehaviourMarine: + { + + if (spearDataPtr->Android) + { + CurrentGameStatistics.Trophies[STATS_VICTIM_ANDROID]++; + } + else if (spearDataPtr->SubType) /* Means ARealMarine for fragments of marines */ + { + CurrentGameStatistics.Trophies[STATS_VICTIM_MARINE]++; + } + else + { + CurrentGameStatistics.Trophies[STATS_VICTIM_CIVILIAN]++; + } + break; + } + case I_BehaviourQueenAlien: + { + CurrentGameStatistics.Trophies[STATS_VICTIM_QUEEN]++; + break; + } + case I_BehaviourFaceHugger: + { + CurrentGameStatistics.Trophies[STATS_VICTIM_FACEHUGGER]++; + break; + } + case I_BehaviourXenoborg: + { + CurrentGameStatistics.Trophies[STATS_VICTIM_XENOBORG]++; + break; + } + + + case I_BehaviourPredator: + { + CurrentGameStatistics.Trophies[STATS_VICTIM_PREDATOR]++; + break; + } + default: + { + break; + } + } + break; + } + default: + { + break; + } + } +} + +extern void CurrentGameStats_CreatureKilled(STRATEGYBLOCK *sbPtr,SECTION_DATA *sectionDataPtr) +{ + + if (PlayerStatusPtr->IsAlive==0) { + return; + } + + switch (sbPtr->I_SBtype) + { + case I_BehaviourAlien: + { + ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr; + + switch (alienStatus->Type) + { + case 0: + default: + CurrentGameStatistics.Killed[STATS_VICTIM_XENOMORPH]++; + break; + case 1: + CurrentGameStatistics.Killed[STATS_VICTIM_PREDALIEN]++; + break; + case 2: + CurrentGameStatistics.Killed[STATS_VICTIM_PRAETORIAN]++; + break; + } + + if (sectionDataPtr) + { + if (sectionDataPtr->sempai) + { + if (sectionDataPtr->sempai->Section_Name) + { + if (!_stricmp(sectionDataPtr->sempai->Section_Name,"head")) + { + CurrentGameStatistics.Decapitated[STATS_VICTIM_XENOMORPH]++; + } + } + } + } + + break; + } + case I_BehaviourMarine: + { + MARINE_STATUS_BLOCK *marineStatusPointer; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->containingModule); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr); + + if (marineStatusPointer->My_Weapon->Android) + { + CurrentGameStatistics.Killed[STATS_VICTIM_ANDROID]++; + } + else if (marineStatusPointer->My_Weapon->ARealMarine) + { + CurrentGameStatistics.Killed[STATS_VICTIM_MARINE]++; + } + else + { + CurrentGameStatistics.Killed[STATS_VICTIM_CIVILIAN]++; + } + break; + } + case I_BehaviourQueenAlien: + { + CurrentGameStatistics.Killed[STATS_VICTIM_QUEEN]++; + break; + } + case I_BehaviourFaceHugger: + { + CurrentGameStatistics.Killed[STATS_VICTIM_FACEHUGGER]++; + break; + } + case I_BehaviourXenoborg: + { + CurrentGameStatistics.Killed[STATS_VICTIM_XENOBORG]++; + break; + } + + + case I_BehaviourPredator: + { + CurrentGameStatistics.Killed[STATS_VICTIM_PREDATOR]++; + break; + } + + } +} + + +extern void DoFailedLevelStatisticsScreen(void) +{ + extern int deathFadeLevel; + D3D_FadeDownScreen(deathFadeLevel,0); + DoStatisticsScreen(0); + + if (!deathFadeLevel) + { + RenderStringCentred(GetTextString(TEXTSTRING_MULTIPLAYER_PRESSKEYTORESTARTGAME),ScreenDescriptorBlock.SDB_Width/2,ScreenDescriptorBlock.SDB_Height-20,0xffffffff); + } + +} + +enum TEXTSTRING_ID TemporaryNameStore[] = +{ + TEXTSTRING_GAMESTATS_FACEHUGGER_PL, + TEXTSTRING_GAMESTATS_XENOMORPH_PL, + TEXTSTRING_GAMESTATS_PRAETORIAN_PL, + TEXTSTRING_GAMESTATS_QUEEN_PL, + TEXTSTRING_GAMESTATS_XENOBORG_PL, + TEXTSTRING_GAMESTATS_PREDALIEN_PL, + TEXTSTRING_GAMESTATS_PREDATOR_PL, + TEXTSTRING_GAMESTATS_MARINE_PL, + TEXTSTRING_GAMESTATS_CIVILIAN_PL, + TEXTSTRING_GAMESTATS_ANDROID_PL, +}; + +enum TEXTSTRING_ID TemporaryNameStore2[] = +{ + TEXTSTRING_GAMESTATS_FACEHUGGER, + TEXTSTRING_GAMESTATS_XENOMORPH, + TEXTSTRING_GAMESTATS_PRAETORIAN, + TEXTSTRING_GAMESTATS_QUEEN, + TEXTSTRING_GAMESTATS_XENOBORG, + TEXTSTRING_GAMESTATS_PREDALIEN, + TEXTSTRING_GAMESTATS_PREDATOR, + TEXTSTRING_GAMESTATS_MARINE, + TEXTSTRING_GAMESTATS_CIVILIAN, + TEXTSTRING_GAMESTATS_ANDROID, +}; + +enum TEXTSTRING_ID VisionModeNames[] = +{ + TEXTSTRING_GAMESTATS_VM_NORMAL, + TEXTSTRING_GAMESTATS_VM_NAVSENSE, + TEXTSTRING_GAMESTATS_VM_INTENSIFIER, + TEXTSTRING_GAMESTATS_VM_THERMAL, + TEXTSTRING_GAMESTATS_VM_ELECTRICAL, + TEXTSTRING_GAMESTATS_VM_PREDTECH, +}; + + +extern void DoStatisticsScreen(int completed_level) +{ + // content to be finalised. Language localisation issues: time formats etc. + int y; + char buffer[100]; + int level_num; + int colour_to_draw,best; + + int targets,targetspassed; + + NPC_DATA *NpcData; + + switch (AvP.PlayerType) + { + case I_Marine: + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Marine_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Marine_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Marine_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Marine_Impossible); + break; + } + break; + case I_Alien: + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Alien_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Alien_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Alien_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Alien_Impossible); + break; + } + break; + case I_Predator: + switch (AvP.Difficulty) { + case I_Easy: + NpcData=GetThisNpcData(I_PC_Predator_Easy); + break; + default: + case I_Medium: + NpcData=GetThisNpcData(I_PC_Predator_Medium); + break; + case I_Hard: + NpcData=GetThisNpcData(I_PC_Predator_Hard); + break; + case I_Impossible: + NpcData=GetThisNpcData(I_PC_Predator_Impossible); + break; + } + break; + default: + LOCALASSERT(0); + } + + if (PlayerStatusPtr->soundHandle5!=SOUND_NOACTIVEINDEX) { + Sound_Stop(PlayerStatusPtr->soundHandle5); + } + + level_num=NumberForCurrentLevel(); + targets=0; + targetspassed=0; + + /* Print their name. */ + sprintf(buffer,"%s",UserProfilePtr->Name); + RenderString(buffer,TABPOINT1,20,COLOUR_WHITE); + + if (completed_level) { + RenderStringCentred(GetTextString(TEXTSTRING_GAMESTATS_LEVELCOMPLETED), + ScreenDescriptorBlock.SDB_Width/2,20,COLOUR_GREEN); + } else { + RenderStringCentred(GetTextString(TEXTSTRING_GAMESTATS_LEVELNOTCOMPLETED), + ScreenDescriptorBlock.SDB_Width/2,20,COLOUR_RED); + } + + #if 0 + RenderStringCentred(GetTextString(TEXTSTRING_GAMESTATS_NAME),TABPOINT1A,40,COLOUR_WHITE); + #endif + RenderStringCentred(GetTextString(TEXTSTRING_GAMESTATS_YOUR),TABPOINT2,40,COLOUR_WHITE); + RenderStringCentred(GetTextString(TEXTSTRING_GAMESTATS_BEST),TABPOINT3,40,COLOUR_WHITE); + RenderStringCentred(GetTextString(TEXTSTRING_GAMESTATS_TARGET),TABPOINT4,40,COLOUR_WHITE); + + y = 55; + + colour_to_draw=COLOUR_WHITE; + + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].Total_ElapsedHours>AvP.ElapsedHours) { + best=1; + } else if (UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Total_ElapsedHours==AvP.ElapsedHours) { + if (UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Total_ElapsedMinutes>AvP.ElapsedMinutes) { + best=1; + } else if (UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Total_ElapsedMinutes==AvP.ElapsedMinutes) { + if (UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Total_ElapsedSeconds>AvP.ElapsedSeconds) { + best=1; + } else if (UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Total_ElapsedSeconds==AvP.ElapsedSeconds) { + best=1; + } + } + } + if (best) { + colour_to_draw=COLOUR_GREEN; + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Total_ElapsedHours=AvP.ElapsedHours; + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Total_ElapsedMinutes=AvP.ElapsedMinutes; + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Total_ElapsedSeconds=AvP.ElapsedSeconds; + } + } + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_TIMEELAPSED),TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%dh %02dm %02ds",AvP.ElapsedHours,AvP.ElapsedMinutes,AvP.ElapsedSeconds/65536); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); //y was 50! + + if ((level_numPersonalBests[AvP.Difficulty][level_num].Total_ElapsedHours, + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Total_ElapsedMinutes, + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Total_ElapsedSeconds/65536); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); //y was 50! + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Total_ElapsedHours>AvP.ElapsedHours) { + best=1; + } else if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Total_ElapsedHours==AvP.ElapsedHours) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Total_ElapsedMinutes>AvP.ElapsedMinutes) { + best=1; + } else if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Total_ElapsedMinutes==AvP.ElapsedMinutes) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Total_ElapsedSeconds>AvP.ElapsedSeconds) { + best=1; + } else if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Total_ElapsedSeconds==AvP.ElapsedSeconds) { + best=1; + } + } + } + if (best) { + targetspassed++; + colour_to_draw=COLOUR_RED; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Total_ElapsedHours>-1) { + sprintf(buffer,"%dh %02dm %02ds", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Total_ElapsedHours, + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Total_ElapsedMinutes, + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Total_ElapsedSeconds/65536 + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + + if (AvP.PlayerType==I_Predator) { + + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].Cloak_ElapsedHours>CurrentGameStatistics.Cloak_ElapsedHours) { + best=1; + } else if (UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Cloak_ElapsedHours==CurrentGameStatistics.Cloak_ElapsedHours) { + if (UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Cloak_ElapsedMinutes>CurrentGameStatistics.Cloak_ElapsedMinutes) { + best=1; + } else if (UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Cloak_ElapsedMinutes==CurrentGameStatistics.Cloak_ElapsedMinutes) { + if (UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Cloak_ElapsedSeconds>CurrentGameStatistics.Cloak_ElapsedSeconds) { + best=1; + } else if (UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Cloak_ElapsedSeconds==CurrentGameStatistics.Cloak_ElapsedSeconds) { + best=1; + } + } + } + if (best) { + colour_to_draw=COLOUR_GREEN; + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Cloak_ElapsedHours=CurrentGameStatistics.Cloak_ElapsedHours; + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Cloak_ElapsedMinutes=CurrentGameStatistics.Cloak_ElapsedMinutes; + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Cloak_ElapsedSeconds=CurrentGameStatistics.Cloak_ElapsedSeconds; + } + } + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_TIMECLOAKED),TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%dh %02dm %02ds",CurrentGameStatistics.Cloak_ElapsedHours,CurrentGameStatistics.Cloak_ElapsedMinutes,CurrentGameStatistics.Cloak_ElapsedSeconds/65536); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].Cloak_ElapsedHours, + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Cloak_ElapsedMinutes, + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Cloak_ElapsedSeconds/65536); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); //y was 50! + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Cloak_ElapsedHours>AvP.ElapsedHours) { + best=1; + } else if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Cloak_ElapsedHours==AvP.ElapsedHours) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Cloak_ElapsedMinutes>AvP.ElapsedMinutes) { + best=1; + } else if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Cloak_ElapsedMinutes==AvP.ElapsedMinutes) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Cloak_ElapsedSeconds>AvP.ElapsedSeconds) { + best=1; + } else if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Cloak_ElapsedSeconds==AvP.ElapsedSeconds) { + best=1; + } + } + } + if (best) { + targetspassed++; + colour_to_draw=COLOUR_RED; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Cloak_ElapsedHours>-1) { + sprintf(buffer,"%dh %02dm %02ds", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Cloak_ElapsedHours, + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Cloak_ElapsedMinutes, + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Cloak_ElapsedSeconds/65536 + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + } + + { + int i; + for (i=0; i-1) + ||((AvP.PlayerType==I_Predator)&&(LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Trophies[i]>-1)) + ||((AvP.PlayerType==I_Alien)&&(LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.LiveHeadBites[i]>-1)) + ||((AvP.PlayerType==I_Alien)&&(LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.DeadHeadBites[i]>-1)) + ) { + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].Killed[i]<=CurrentGameStatistics.Killed[i]) { + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Killed[i]=CurrentGameStatistics.Killed[i]; + colour_to_draw=COLOUR_GREEN; + } + } + + sprintf(buffer,"%s %s",GetTextString(TemporaryNameStore[i]),GetTextString(TEXTSTRING_GAMESTATS_KILLED)); + RenderString(buffer,TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%d",CurrentGameStatistics.Killed[i]); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].Killed[i] + ); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Killed[i]<=CurrentGameStatistics.Killed[i]) { + colour_to_draw=COLOUR_RED; + targetspassed++; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Killed[i]>-1) { + sprintf(buffer,"%d", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Killed[i] + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + if (AvP.PlayerType==I_Predator) { + if ((i!=STATS_VICTIM_XENOBORG) + &&(i!=STATS_VICTIM_QUEEN) + &&(i!=STATS_VICTIM_FACEHUGGER) + &&(i!=STATS_VICTIM_PREDATOR) + ){ + + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].Trophies[i]<=CurrentGameStatistics.Trophies[i]) { + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Trophies[i]=CurrentGameStatistics.Trophies[i]; + colour_to_draw=COLOUR_GREEN; + } + } + + sprintf(buffer,"%s %s",GetTextString(TemporaryNameStore2[i]),GetTextString(TEXTSTRING_GAMESTATS_TROPHIESCOLLECTED)); + RenderString(buffer,TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%d",CurrentGameStatistics.Trophies[i]); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].Trophies[i] + ); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Trophies[i]<=CurrentGameStatistics.Trophies[i]) { + colour_to_draw=COLOUR_RED; + targetspassed++; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Trophies[i]>-1) { + sprintf(buffer,"%d", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Trophies[i] + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + } + } else if (AvP.PlayerType==I_Alien) { + if ((i!=STATS_VICTIM_ANDROID) + &&(i!=STATS_VICTIM_XENOMORPH) + &&(i!=STATS_VICTIM_PREDALIEN) + &&(i!=STATS_VICTIM_PRAETORIAN) + &&(i!=STATS_VICTIM_QUEEN) + &&(i!=STATS_VICTIM_XENOBORG) + &&(i!=STATS_VICTIM_FACEHUGGER) + ){ + + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].LiveHeadBites[i]<=CurrentGameStatistics.LiveHeadBites[i]) { + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].LiveHeadBites[i]=CurrentGameStatistics.LiveHeadBites[i]; + colour_to_draw=COLOUR_GREEN; + } + } + + sprintf(buffer,"%s %s",GetTextString(TemporaryNameStore2[i]),GetTextString(TEXTSTRING_GAMESTATS_LIVEHEADBITES)); + RenderString(buffer,TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%d",CurrentGameStatistics.LiveHeadBites[i]); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].LiveHeadBites[i] + ); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.LiveHeadBites[i]<=CurrentGameStatistics.LiveHeadBites[i]) { + colour_to_draw=COLOUR_RED; + targetspassed++; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.LiveHeadBites[i]>-1) { + sprintf(buffer,"%d", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.LiveHeadBites[i] + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].DeadHeadBites[i]<=CurrentGameStatistics.DeadHeadBites[i]) { + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].DeadHeadBites[i]=CurrentGameStatistics.DeadHeadBites[i]; + colour_to_draw=COLOUR_GREEN; + } + } + + sprintf(buffer,"%s %s",GetTextString(TemporaryNameStore2[i]),GetTextString(TEXTSTRING_GAMESTATS_DEADHEADBITES)); + RenderString(buffer,TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%d",CurrentGameStatistics.DeadHeadBites[i]); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].DeadHeadBites[i] + ); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.DeadHeadBites[i]<=CurrentGameStatistics.DeadHeadBites[i]) { + colour_to_draw=COLOUR_RED; + targetspassed++; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.DeadHeadBites[i]>-1) { + sprintf(buffer,"%d", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.DeadHeadBites[i] + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + } + } + } + } + } + + /* Speed? */ + { + unsigned int total_time; + unsigned int average_speed; + + float float_speed; + + total_time=(AvP.ElapsedSeconds>>ONE_FIXED_SHIFT); + total_time+=(AvP.ElapsedMinutes*60); + total_time+=((AvP.ElapsedHours*60)*60); + + if (total_time) { + average_speed=(CurrentGameStatistics.IntegralSpeed/total_time); + + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].Speed<=average_speed) { + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Speed=average_speed; + colour_to_draw=COLOUR_GREEN; + } + } + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_AVERAGESPEED),TABPOINT1,y,colour_to_draw); + + float_speed=(float)average_speed; + float_speed/=1000; + + sprintf(buffer,"%.1f m/s",float_speed); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].Speed; + float_speed/=1000; + + sprintf(buffer,"%.1f m/s",float_speed); + + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Speed<=average_speed) { + colour_to_draw=COLOUR_RED; + targetspassed++; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Speed>-1) { + float_speed=(float)LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Speed; + float_speed/=1000; + sprintf(buffer,"%.1f m/s",float_speed); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } + } + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + { + unsigned int percentage; + /* Health and armour. */ + if (NpcData->StartingStats.Health) { + percentage=((CurrentGameStatistics.HealthDamage>>ONE_FIXED_SHIFT)*100)/(NpcData->StartingStats.Health); + + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].HealthDamage>=percentage) { + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].HealthDamage=percentage; + colour_to_draw=COLOUR_GREEN; + } + } + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_HEALTHDAMAGETAKEN),TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%03d%%",percentage); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].HealthDamage + ); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.HealthDamage>=percentage) { + colour_to_draw=COLOUR_RED; + targetspassed++; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.HealthDamage>-1) { + sprintf(buffer,"%03d%%", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.HealthDamage + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + } + if ((NpcData->StartingStats.Armour)&&(AvP.PlayerType==I_Marine)) { + percentage=((CurrentGameStatistics.ArmourDamage>>ONE_FIXED_SHIFT)*100)/(NpcData->StartingStats.Armour); + + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].ArmourDamage>=percentage) { + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].ArmourDamage=percentage; + colour_to_draw=COLOUR_GREEN; + } + } + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_ARMOURDAMAGETAKEN),TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%03d%%",percentage); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].ArmourDamage + ); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.ArmourDamage>=percentage) { + colour_to_draw=COLOUR_RED; + targetspassed++; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.ArmourDamage>-1) { + sprintf(buffer,"%03d%%", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.ArmourDamage + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + } + + } + /* Creature specific stats... */ + if (AvP.PlayerType==I_Marine) { + int headshots=0,kills=0,i; + + for (i=0; iPersonalBests[AvP.Difficulty][level_num].HeadShotPercentage<=headshots) { + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].HeadShotPercentage=headshots; + colour_to_draw=COLOUR_GREEN; + } + } + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_HEADSHOTS),TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%03d%%",headshots); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].HeadShotPercentage + ); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.HeadShotPercentage<=headshots) { + colour_to_draw=COLOUR_RED; + targetspassed++; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.HeadShotPercentage>-1) { + sprintf(buffer,"%03d%%", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.HeadShotPercentage + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + /* Shots fired... */ + { + unsigned int total_shots; + + total_shots=0; + + for (i=0; iWeaponSlot[i]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (twPtr->LogShots) { + total_shots+=CurrentGameStatistics.ShotsFired[i]; + } + } + + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].ShotsFired>=total_shots) { + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].ShotsFired=total_shots; + colour_to_draw=COLOUR_GREEN; + } + } + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_TOTALSHOTSFIRED),TABPOINT1,y,colour_to_draw); + sprintf(buffer,"%d\n",(total_shots)); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].ShotsFired + ); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.ShotsFired>=total_shots) { + colour_to_draw=COLOUR_RED; + targetspassed++; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.ShotsFired>-1) { + sprintf(buffer,"%d", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.ShotsFired + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + } + /* Accuracy... */ + { + unsigned int total_shots,total_hits,percentage; + + total_shots=0; + total_hits=0; + + for (i=0; iWeaponSlot[i]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (twPtr->LogAccuracy) { + total_shots+=CurrentGameStatistics.ShotsFired[i]; + total_hits+=CurrentGameStatistics.ShotsHit[i]; + } + } + if (total_shots) { + percentage=(100*total_hits)/total_shots; + } else { + percentage=0; + } + + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].Accuracy<=percentage) { + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Accuracy=percentage; + colour_to_draw=COLOUR_GREEN; + } + } + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_ACCURACY),TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%03d%%",percentage); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].Accuracy + ); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Accuracy<=percentage) { + colour_to_draw=COLOUR_RED; + targetspassed++; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Accuracy>-1) { + sprintf(buffer,"%03d%%", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Accuracy + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + } + /* Preferred weapon... */ + { + unsigned int maxtime=0; + int preferred_slot=-1; + PLAYER_WEAPON_DATA *weaponPtr; + + for (i=0; i=maxtime) { + maxtime=CurrentGameStatistics.WeaponTimes[i]; + preferred_slot=i; + } + } + GLOBALASSERT(preferred_slot!=-1); + + weaponPtr = &(PlayerStatusPtr->WeaponSlot[preferred_slot]); + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_PREFERREDWEAPON),TABPOINT1,y,colour_to_draw); + sprintf(buffer,"%s\n",GetTextString(TemplateWeapon[weaponPtr->WeaponIDNumber].Name)); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + RenderStringCentred("---",TABPOINT3,y,colour_to_draw); + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + } + } else if (AvP.PlayerType==I_Alien) { + + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].Spotted>=CurrentGameStatistics.Spotted) { + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Spotted=CurrentGameStatistics.Spotted; + colour_to_draw=COLOUR_GREEN; + } + } + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_SPOTTED),TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%d",CurrentGameStatistics.Spotted); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].Spotted + ); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Spotted>=CurrentGameStatistics.Spotted) { + colour_to_draw=COLOUR_RED; + targetspassed++; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Spotted>-1) { + sprintf(buffer,"%d", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Spotted + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + + } else if (AvP.PlayerType==I_Predator) { + + int i; + + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].Spotted>=CurrentGameStatistics.Spotted) { + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Spotted=CurrentGameStatistics.Spotted; + colour_to_draw=COLOUR_GREEN; + } + } + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_SPOTTED),TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%d",CurrentGameStatistics.Spotted); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].Spotted + ); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Spotted>=CurrentGameStatistics.Spotted) { + colour_to_draw=COLOUR_RED; + targetspassed++; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Spotted>-1) { + sprintf(buffer,"%d", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Spotted + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + + /* FieldCharge... */ + { + unsigned int percentage; + + percentage=CurrentGameStatistics.FieldChargeUsed/(PLAYERCLOAK_MAXENERGY/100); + + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].FieldChargeUsed>=percentage) { + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].FieldChargeUsed=percentage; + colour_to_draw=COLOUR_GREEN; + } + } + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_FIELDCHARGEUSED),TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%03d%%",percentage); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].FieldChargeUsed + ); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.FieldChargeUsed>=percentage) { + colour_to_draw=COLOUR_RED; + targetspassed++; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.FieldChargeUsed>-1) { + sprintf(buffer,"%03d%%", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.FieldChargeUsed + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + + } + /* Shots fired... */ + { + unsigned int total_shots; + + total_shots=0; + + for (i=0; iWeaponSlot[i]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (twPtr->LogShots) { + total_shots+=CurrentGameStatistics.ShotsFired[i]; + } + } + + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].ShotsFired>=total_shots) { + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].ShotsFired=total_shots; + colour_to_draw=COLOUR_GREEN; + } + } + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_TOTALSHOTSFIRED),TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%d",(total_shots)); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].ShotsFired + ); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.ShotsFired>=total_shots) { + colour_to_draw=COLOUR_RED; + targetspassed++; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.ShotsFired>-1) { + sprintf(buffer,"%d", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.ShotsFired + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + } + /* Accuracy... */ + { + unsigned int total_shots,total_hits,percentage; + + total_shots=0; + total_hits=0; + + for (i=0; iWeaponSlot[i]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + if (twPtr->LogAccuracy) { + total_shots+=CurrentGameStatistics.ShotsFired[i]; + total_hits+=CurrentGameStatistics.ShotsHit[i]; + } + } + if (total_shots) { + percentage=(100*total_hits)/total_shots; + } else { + percentage=0; + } + + if ((completed_level)&&(level_numPersonalBests[AvP.Difficulty][level_num].Accuracy<=percentage) { + UserProfilePtr->PersonalBests[AvP.Difficulty][level_num].Accuracy=percentage; + colour_to_draw=COLOUR_GREEN; + } + } + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_ACCURACY),TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%03d%%",percentage); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + if ((level_numPersonalBests[AvP.Difficulty][level_num].Accuracy + ); + RenderStringCentred(buffer,TABPOINT3,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT3,y,COLOUR_WHITE); + } + + colour_to_draw=COLOUR_WHITE; + if ((completed_level)&&(level_num-1) { + targets++; + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Accuracy<=percentage) { + colour_to_draw=COLOUR_RED; + targetspassed++; + } + } + } + if ((level_numCheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + if (LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Accuracy>-1) { + sprintf(buffer,"%03d%%", + LevelStatsTargets[AvP.Difficulty][level_num].StatTargets.Accuracy + ); + RenderStringCentred(buffer,TABPOINT4,y,colour_to_draw); + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + } else { + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + } + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + } + /* Preferred weapon... */ + { + unsigned int maxtime=0; + int preferred_slot=-1; + PLAYER_WEAPON_DATA *weaponPtr; + + for (i=0; i=maxtime) { + maxtime=CurrentGameStatistics.WeaponTimes[i]; + preferred_slot=i; + } + } + GLOBALASSERT(preferred_slot!=-1); + + weaponPtr = &(PlayerStatusPtr->WeaponSlot[preferred_slot]); + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_PREFERREDWEAPON),TABPOINT1,y,colour_to_draw); + + sprintf(buffer,"%s",GetTextString(TemplateWeapon[weaponPtr->WeaponIDNumber].Name)); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + RenderStringCentred("---",TABPOINT3,y,colour_to_draw); + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + } + } + + /* Vision Mode... */ + { + int i; + unsigned int maxtime=0; + int preferred_slot=-1; + + for (i=0; i=maxtime) { + maxtime=CurrentGameStatistics.VisionModeTimes[i]; + preferred_slot=i; + } + } + GLOBALASSERT(preferred_slot!=-1); + + RenderString(GetTextString(TEXTSTRING_GAMESTATS_PREFERREDVISIONMODE),TABPOINT1,y,colour_to_draw); + sprintf(buffer,"%s\n",GetTextString(VisionModeNames[preferred_slot])); + RenderStringCentred(buffer,TABPOINT2,y,colour_to_draw); + + RenderStringCentred("---",TABPOINT3,y,colour_to_draw); + RenderStringCentred("---",TABPOINT4,y,COLOUR_WHITE); + + } + y+=NEWLINE_SPACING; + colour_to_draw=COLOUR_WHITE; + + /* Unlock a cheat mode? */ + + if (NotCheating) { + if (targets) { + if (targets==targetspassed) { + if (LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate!=CHEATMODE_NONACTIVE) { + if (UserProfilePtr->CheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]!=1) { + UserProfilePtr->CheatMode[LevelStatsTargets[AvP.Difficulty][level_num].CheatModeToActivate]=2; + RenderStringCentred(GetTextString(TEXTSTRING_GAMESTATS_CHEATMODEENABLED),ScreenDescriptorBlock.SDB_Width/2,y,COLOUR_GREEN); + } + } + } + } + } +} diff --git a/3dc/avp/game_statistics.h b/3dc/avp/game_statistics.h new file mode 100644 index 0000000..79a827c --- /dev/null +++ b/3dc/avp/game_statistics.h @@ -0,0 +1,107 @@ +#ifndef _game_stats_h_ +#define _game_stats_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* KJL 99/2/12 - Statistics of current game */ +#include "equipmnt.h" + +enum STATS_VICTIM_ID +{ + STATS_VICTIM_FACEHUGGER, + STATS_VICTIM_XENOMORPH, + STATS_VICTIM_PRAETORIAN, + STATS_VICTIM_QUEEN, + STATS_VICTIM_XENOBORG, + STATS_VICTIM_PREDALIEN, + STATS_VICTIM_PREDATOR, + STATS_VICTIM_MARINE, + STATS_VICTIM_CIVILIAN, + STATS_VICTIM_ANDROID, + STATS_VICTIM_MAXIMUM +}; + +typedef struct +{ + int Killed[STATS_VICTIM_MAXIMUM]; + int Decapitated[STATS_VICTIM_MAXIMUM]; + int Trophies[STATS_VICTIM_MAXIMUM]; + int LiveHeadBites[STATS_VICTIM_MAXIMUM]; + int DeadHeadBites[STATS_VICTIM_MAXIMUM]; + unsigned int WeaponTimes[MAX_NO_OF_WEAPON_SLOTS]; + unsigned int ShotsFired[MAX_NO_OF_WEAPON_SLOTS]; + unsigned int ShotsHit[MAX_NO_OF_WEAPON_SLOTS]; + unsigned int VisionModeTimes[NUMBER_OF_VISION_MODES]; + int Spotted; + /* Cloak time... */ + unsigned int Cloak_ElapsedSeconds; + unsigned int Cloak_ElapsedMinutes; + unsigned int Cloak_ElapsedHours; + unsigned int FieldChargeUsed; + /* Damage... */ + unsigned int HealthDamage; + unsigned int ArmourDamage; + /* Speed? */ + unsigned int IntegralSpeed; +} AvP_GameStats; + +typedef struct +{ + int Killed[STATS_VICTIM_MAXIMUM]; + int Decapitated[STATS_VICTIM_MAXIMUM]; + + union { + int Trophies[STATS_VICTIM_MAXIMUM]; + int LiveHeadBites[STATS_VICTIM_MAXIMUM]; + }; + + int DeadHeadBites[STATS_VICTIM_MAXIMUM]; + int ShotsFired; + int Accuracy; + int Spotted; + /* Total time... */ + unsigned int Total_ElapsedSeconds; + unsigned int Total_ElapsedMinutes; + int Total_ElapsedHours; + /* Cloak time... */ + unsigned int Cloak_ElapsedSeconds; + unsigned int Cloak_ElapsedMinutes; + int Cloak_ElapsedHours; + /* Damage... */ + int HealthDamage; + int ArmourDamage; + /* Some day the predator might have armour. */ + + /* Speed in mm/s */ + int Speed; + /* For a predator. */ + int FieldChargeUsed; + + int HeadShotPercentage; + + unsigned char Padding[40]; +} AvP_GameStats_Stored; + +extern AvP_GameStats_Stored DefaultLevelGameStats; +extern AvP_GameStats CurrentGameStatistics; +extern void CurrentGameStats_SpeedSample(unsigned int speed,unsigned int time); +extern void CurrentGameStats_DamageTaken(unsigned int health,unsigned int armour); +extern void CurrentGameStats_ChargeUsed(unsigned int charge); +extern void CurrentGameStats_VisionMode(enum VISION_MODE_ID mode); +extern void CurrentGameStats_CloakOn(void); +extern void CurrentGameStats_WeaponFired(enum WEAPON_SLOT slot,unsigned int rounds); +extern void CurrentGameStats_WeaponHit(enum WEAPON_SLOT slot,unsigned int rounds); +extern void CurrentGameStats_UsingWeapon(enum WEAPON_SLOT slot); +extern void CurrentGameStats_Spotted(void); +extern void CurrentGameStats_CreatureKilled(STRATEGYBLOCK *sbPtr,SECTION_DATA *sectionDataPtr); +extern void CurrentGameStats_TrophyCollected(STRATEGYBLOCK *sbPtr); +extern void CurrentGameStats_HeadBitten(STRATEGYBLOCK *sbPtr); +extern void InitialiseCurrentGameStatistics(void); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/3dc/avp/gamecmds.cpp b/3dc/avp/gamecmds.cpp new file mode 100644 index 0000000..21f0b96 --- /dev/null +++ b/3dc/avp/gamecmds.cpp @@ -0,0 +1,818 @@ +#include "3dc.h" +#include "conscmnd.hpp" +#include "strutil.h" + +// Includes for the actual commands: +//#include "consvar.hpp" +//#include "modcmds.hpp" +//#include "textexp.hpp" +//#include "trepgadg.hpp" + +#define UseLocalAssert Yes +#include "ourasert.h" + +extern "C" +{ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "gameplat.h" + +#include "bh_types.h" + +#include "showcmds.h" +#include "version.h" +#include "equipmnt.h" +#include "cheat.h" +#include "cd_player.h" +#include "dynblock.h" +#include "bh_RubberDuck.h" +#include "pvisible.h" +#include "pldnet.h" + +#include "lighting.h" +#include "paintball.h" +#include "decal.h" +#include "ConsoleLog.hpp" +#include "psndplat.h" +#include "avp_menus.h" +#include "smacker.h" +#include "detaillevels.h" +#include "savegame.h" + + +int DebuggingCommandsActive=0; +extern void GimmeCharge(void); + +// just change these to prototypes etc. +extern void QuickLoad() +{ + //set the load request + LoadGameRequest = 0; //(that's slot 0 - not false) +} +extern void QuickSave() +{ + //set the save request + SaveGameRequest = 0; //(that's slot 0 - not false) +} + +void ConsoleCommandLoad(int slot) +{ + if(slot>=1 && slot<=NUMBER_OF_SAVE_SLOTS) + { + LoadGameRequest = slot-1; + } +} + +void ConsoleCommandSave(int slot) +{ + if(slot>=1 && slot<=NUMBER_OF_SAVE_SLOTS) + { + SaveGameRequest = slot-1; + } +} +extern void DisplaySavesLeft(); + + + +struct DEBUGGINGTEXTOPTIONS ShowDebuggingText; + +extern void ChangeNetGameType_Individual(); +extern void ChangeNetGameType_Coop(); +extern void ChangeNetGameType_LastManStanding(); +extern void ChangeNetGameType_PredatorTag(); +extern void ShowNearestPlayersName(); +extern void ScreenShot(void); +extern void CastAlienBot(void); +extern void CastMarineBot(int weapon); +extern void CastPredoBot(int weapon); +extern void CastPredAlienBot(void); +extern void CastPraetorianBot(void); +extern void CastXenoborg(void); + +extern int ShowMultiplayerScoreTimer; + +static void ShowFPS(void) +{ + ShowDebuggingText.FPS = ~ShowDebuggingText.FPS; +} +static void ShowEnvironment(void) +{ + ShowDebuggingText.Environment = ~ShowDebuggingText.Environment; +} +static void ShowCoords(void) +{ + ShowDebuggingText.Coords = ~ShowDebuggingText.Coords; +} +static void ShowModule(void) +{ + ShowDebuggingText.Module = ~ShowDebuggingText.Module; +} +static void ShowTarget(void) +{ + ShowDebuggingText.Target = ~ShowDebuggingText.Target; +} +static void ShowNetworking(void) +{ + ShowDebuggingText.Networking = ~ShowDebuggingText.Networking; +} +static void ShowDynamics(void) +{ + ShowDebuggingText.Dynamics = ~ShowDebuggingText.Dynamics; +} +static void ShowGunPos(void) +{ + ShowDebuggingText.GunPos = ~ShowDebuggingText.GunPos; +} +static void ShowTears(void) +{ + ShowDebuggingText.Tears = ~ShowDebuggingText.Tears; +} +static void ShowPolyCount(void) +{ + ShowDebuggingText.PolyCount = ~ShowDebuggingText.PolyCount; +} +static void ShowSounds(void) +{ + ShowDebuggingText.Sounds = ~ShowDebuggingText.Sounds; +} + + +extern void ChangeToMarine(); +static void ChangeToSpecialist_General() +{ + netGameData.myCharacterSubType=NGSCT_General; + ChangeToMarine(); +} +static void ChangeToSpecialist_PulseRifle() +{ + netGameData.myCharacterSubType=NGSCT_PulseRifle; + ChangeToMarine(); +} +static void ChangeToSpecialist_Smartgun() +{ + if(netGameData.allowSmartgun) + { + netGameData.myCharacterSubType=NGSCT_Smartgun; + } + ChangeToMarine(); +} +static void ChangeToSpecialist_Flamer() +{ + if(netGameData.allowFlamer) + { + netGameData.myCharacterSubType=NGSCT_Flamer; + } + ChangeToMarine(); +} +static void ChangeToSpecialist_Sadar() +{ + if(netGameData.allowSadar) + { + netGameData.myCharacterSubType=NGSCT_Sadar; + } + ChangeToMarine(); +} +static void ChangeToSpecialist_GrenadeLauncher() +{ + if(netGameData.allowGrenadeLauncher) + { + netGameData.myCharacterSubType=NGSCT_GrenadeLauncher; + } + ChangeToMarine(); +} +static void ChangeToSpecialist_Minigun() +{ + if(netGameData.allowMinigun) + { + netGameData.myCharacterSubType=NGSCT_Minigun; + } + ChangeToMarine(); +} +static void ChangeToSpecialist_Frisbee() +{ + if(netGameData.allowSmartDisc) + { + netGameData.myCharacterSubType=NGSCT_Frisbee; + } + ChangeToMarine(); +} + +static void ChangeToSpecialist_Pistols() +{ + if(netGameData.allowPistols) + { + netGameData.myCharacterSubType=NGSCT_Pistols; + } + ChangeToMarine(); +} + +extern void ShowMultiplayerScores() +{ + ShowMultiplayerScoreTimer=5*ONE_FIXED; +} + +extern void AddNetMsg_ChatBroadcast(char *string,BOOL same_species_only); + +static void DoMultiplayerSay(char* string) +{ + AddNetMsg_ChatBroadcast(string,FALSE); +} + +static void DoMultiplayerSaySpecies(char* string) +{ + AddNetMsg_ChatBroadcast(string,TRUE); +} + +static void ForceAssertionFailure(void) +{ + LOCALASSERT("This assertion has been forced to stop the game"==0); +} + + + +static void CDCommand_Play(int track) +{ + if(!CDDA_IsOn()) CDDA_SwitchOn(); + + CDDA_Stop(); + CDDA_Play(track); +} +void CDCommand_PlayLoop(int track) +{ + if(!CDDA_IsOn()) CDDA_SwitchOn(); + + CDDA_Stop(); + CDDA_PlayLoop(track); +} + +static void CDCommand_Stop(void) +{ + CDDA_Stop(); +} + +static void CDCommand_Volume(int volume) +{ + if (volume>=0 && volume<=127) + { + CDDA_ChangeVolume(volume); + } + else + { + // say the volume setting is incorrect + } +} + + +static void GunX(int x) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + twPtr->RestPosition.vx = x; +} +static void GunY(int y) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + twPtr->RestPosition.vy = y; +} +static void GunZ(int z) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + twPtr->RestPosition.vz = z; +} + +static void MakeRotatingLight(void) +{ + MakeLightElement(&Player->ObWorld,LIGHTELEMENT_ROTATING); +} +VECTORCH boing = {12345,12345,12345}; +VECTORCH boing2 = {23451,34512,45123}; + +static void Trash_Frame_Rate(void) +{ + int i=0; + + for (i=0; i<10000000; i++) + { + // Normalise(&boing); + boing.vx += boing2.vx+FastRandom(); + boing.vy += boing2.vy; + boing.vz += boing2.vz; + } +} + + +static void RestartMultiplayer(void) +{ + /* obviously have to be in a network game... */ + if (AvP.Network==I_No_Network) return; + + int seed=FastRandom(); + AddNetMsg_RestartNetworkGame(seed); + RestartNetworkGame(seed); +} + +static void CompleteLevel(void) +{ + AvP.LevelCompleted = 1; +} + + +void CreateGameSpecificConsoleCommands(void) +{ + ShowDebuggingText.FPS = 0; + ShowDebuggingText.Environment = 0; + ShowDebuggingText.Coords = 0; + ShowDebuggingText.Module = 0; + ShowDebuggingText.Target = 0; + ShowDebuggingText.Networking = 0; + ShowDebuggingText.Dynamics = 0; + ShowDebuggingText.GunPos = 0; + ShowDebuggingText.Tears = 0; + ShowDebuggingText.PolyCount = 0; + + #ifndef AVP_DEBUG_VERSION + BOOL IsACheat = TRUE; + #else + BOOL IsACheat = FALSE; + #endif + + #ifndef AVP_DEBUG_VERSION // allow debug commands without -debug + #ifndef AVP_DEBUG_FOR_FOX // allow debug commands without -debug + if (DebuggingCommandsActive) + #endif + #endif + { + ConsoleCommand::Make + ( + "GIVEALLWEAPONS", + "BE CAREFUL WHAT YOU WISH FOR", + GiveAllWeaponsCheat, + IsACheat + ); + + + /* KJL 14:51:09 29/03/98 - show commands */ + ConsoleCommand::Make + ( + "SHOWFPS", + "DISPLAY THE FRAMERATE", + ShowFPS, + IsACheat + ); + + ConsoleCommand::Make + ( + "SHOWPOLYCOUNT", + "DISPLAY NUMBER OF LANDSCAPE POLYS, AND NUMBER OF POLYS ACTUALLY RENDERED", + ShowPolyCount, + IsACheat + ); + ConsoleCommand::Make + ( + "LIGHT", + "CREATE A LIGHT", + MakeRotatingLight, + IsACheat + ); + ConsoleCommand :: Make + ( + "GIMME_CHARGE", + "GRANTS FULL FIELD CHARGE", + GimmeCharge, + IsACheat + ); + ConsoleCommand :: Make + ( + "ALIENBOT", + "CREATES ALIEN BOT. SAME AS ANY OTHER ALIEN.", + CastAlienBot, + IsACheat + ); + + ConsoleCommand :: Make + ( + "MARINEBOT", + "CREATES MARINE BOT. SAME AS A GENERATED MARINE.", + CastMarineBot, + IsACheat + ); + + ConsoleCommand :: Make + ( + "PREDOBOT", + "CREATES PREDATOR BOT.", + CastPredoBot, + IsACheat + ); + + ConsoleCommand :: Make + ( + "PREDALIENBOT", + "CREATES PREDATOR ALIEN BOT.", + CastPredAlienBot, + IsACheat + ); + + ConsoleCommand :: Make + ( + "PRAETORIANBOT", + "CREATES PRAETORIAN GUARD BOT.", + CastPraetorianBot, + IsACheat + ); + + ConsoleCommand :: Make + ( + "XENOBORG", + "THEY'RE ALL BOTS ANYWAY...", + CastXenoborg, + IsACheat + ); + + + } + + #if CONSOLE_DEBUGGING_COMMANDS_ACTIVATED + ConsoleCommand::Make + ( + "SHOWENV", + "DISPLAY THE ENVIRONMENT NAME", + ShowEnvironment + ); + + ConsoleCommand::Make + ( + "SHOWCOORDS", + "DISPLAY THE PLAYERS CURRENT POSITION", + ShowCoords + ); + + ConsoleCommand::Make + ( + "SHOWMODULE", + "DISPLAY THE PLAYERS CURRENT MODULE", + ShowModule + ); + + ConsoleCommand::Make + ( + "SHOWTARGET", + "DISPLAY THE CURRENT TARGET POSITION", + ShowTarget + ); + + ConsoleCommand::Make + ( + "SHOWNETWORKING", + "DISPLAY NETWORKING DEBUG TEXT", + ShowNetworking + ); + + ConsoleCommand::Make + ( + "SHOWDYNAMICS", + "DISPLAY DYNAMICS DEBUG TEXT", + ShowDynamics + ); + + ConsoleCommand::Make + ( + "SHOWGUNPOS", + "DISPLAY GUN OFFSET COORDS", + ShowGunPos + ); + + ConsoleCommand::Make + ( + "SHOWTEARS", + "MAKE TEARS AND LINKING ERRORS APPEAR BRIGHT GREEN", + ShowTears + ); + + ConsoleCommand::Make + ( + "SHOWSOUNDS", + "DISPLAY NUMBER OF ACTIVE SOUNDS", + ShowSounds + ); + + + #if 1 + ConsoleCommand::Make + ( + "GUNX", + "CHANGE POSITION", + GunX + ); + ConsoleCommand::Make + ( + "GUNY", + "CHANGE POSITION", + GunY + ); + ConsoleCommand::Make + ( + "GUNZ", + "CHANGE POSITION", + GunZ + ); + ConsoleCommand::Make + ( + "DUCKBOT", + "MAKE A RUBBER DUCK", + CreateRubberDuckBot + ); + + ConsoleCommand::Make + ( + "FORCEASSERTIONFAILURE", + "MAKE AN ASSERTION FIRE, EXITING THE GAME", + ForceAssertionFailure + ); + #endif + + ConsoleCommand::Make + ( + "RESTARTMULTIPLAYER", + "RESTARTS A NETWORK GAME FROM SCRATCH", + RestartMultiplayer + ); + #if 0 + ConsoleCommand::Make + ( + "NEWPLANET", + "", + NewPlanet + ); + #endif + ConsoleCommand::Make + ( + "PAINTBALL", + "TOGGLES PAINTBALLMODE ON/OFF", + TogglePaintBallMode + ); + + ConsoleCommand::Make + ( + "BUG", + "ADD A BUG REPORT TO CONSOLELOG.TXT", + OutputBugReportToConsoleLogfile + ); + ConsoleCommand::Make + ( + "REMOVEDECALS", + "DELETES ALL PRE-DECALS", + RemoveAllFixedDecals + ); + + ConsoleCommand::Make + ( + "TURN3DSOUNDHARDWAREOFF", + "DEACTIVATES 3D SOUND IN HARDWARE", + PlatDontUse3DSoundHW + ); + ConsoleCommand::Make + ( + "TURN3DSOUNDHARDWAREON", + "ACTIVATES 3D SOUND IN HARDWARE", + PlatUse3DSoundHW + ); + + ConsoleCommand::Make + ( + "NETGAME_INDIVIDUAL", + "CHANGE NETWORK GAME TYPE", + ChangeNetGameType_Individual + ); + ConsoleCommand::Make + ( + "NETGAME_COOP", + "CHANGE NETWORK GAME TYPE", + ChangeNetGameType_Coop + ); + ConsoleCommand::Make + ( + "NETGAME_LASTMANSTANDING", + "CHANGE NETWORK GAME TYPE", + ChangeNetGameType_LastManStanding + ); + ConsoleCommand::Make + ( + "NETGAME_PREDATORTAG", + "CHANGE NETWORK GAME TYPE", + ChangeNetGameType_PredatorTag + ); + + + ConsoleCommand::Make + ( + "TRIGGER_PLOT_FMV", + "", + StartTriggerPlotFMV + ); + + + ConsoleCommand::Make + ( + "SPECIALISTMARINE_GENERAL", + "Become a general marine (can use all weapons)", + ChangeToSpecialist_General + ); + ConsoleCommand::Make + ( + "SPECIALISTMARINE_PULSERIFLE", + "Become a pulserifle marine", + ChangeToSpecialist_PulseRifle + ); + ConsoleCommand::Make + ( + "SPECIALISTMARINE_SMARTGUN", + "Become a smartgun marine", + ChangeToSpecialist_Smartgun + ); + ConsoleCommand::Make + ( + "SPECIALISTMARINE_FLAMER", + "Become a flamethrower marine", + ChangeToSpecialist_Flamer + ); + ConsoleCommand::Make + ( + "SPECIALISTMARINE_SADAR", + "Become a sadar marine", + ChangeToSpecialist_Sadar + ); + ConsoleCommand::Make + ( + "SPECIALISTMARINE_GRENADELAUNCHER", + "Become a grenade launcher marine", + ChangeToSpecialist_GrenadeLauncher + ); + ConsoleCommand::Make + ( + "SPECIALISTMARINE_MINIGUN", + "Become a minigun marine", + ChangeToSpecialist_Minigun + ); + ConsoleCommand::Make + ( + "SPECIALISTMARINE_SD", + "Become an SD marine", + ChangeToSpecialist_Frisbee + ); + ConsoleCommand::Make + ( + "SPECIALISTMARINE_PISTOLS", + "Become a pistol marine", + ChangeToSpecialist_Pistols + ); + + + #if 1 + ConsoleCommand::Make + ( + "TRASH_FRAME_RATE", + "", + Trash_Frame_Rate + ); + + ConsoleCommand::Make + ( + "COMPLETE_LEVEL", + "", + CompleteLevel + ); + #endif + #endif + /* KJL 15:52:41 29/03/98 - version info */ + ConsoleCommand::Make + ( + "VERSION", + "", + GiveVersionDetails + ); + + ConsoleCommand::Make + ( + "SAY", + "BROADCAST MESSAGE", + DoMultiplayerSay + ); + + ConsoleCommand::Make + ( + "SAY_SPECIES", + "BROADCAST MESSAGE", + DoMultiplayerSaySpecies + ); + + ConsoleCommand::Make + ( + "CDSTOP", + "STOP THE CD PLAYING", + CDCommand_Stop + ); + + ConsoleCommand::Make + ( + "CDPLAY", + "SELECT A TRACK TO PLAY", + CDCommand_Play + ); + ConsoleCommand::Make + ( + "CDPLAYLOOP", + "SELECT A TRACK TO PLAY LOOPED", + CDCommand_PlayLoop + ); + + ConsoleCommand::Make + ( + "CDVOLUME", + "SELECT SOUND LEVEL 0 TO 127", + CDCommand_Volume + ); + ConsoleCommand::Make + ( + "ID_PLAYER", + "Get name of player nearest centre of screen", + ShowNearestPlayersName + ); + ConsoleCommand::Make + ( + "SHOW_SCORE", + "Show frag table", + ShowMultiplayerScores + ); + + ConsoleCommand::Make + ( + "DETAIL_LEVEL_MAX", + "", + SetToDefaultDetailLevels + ); + + ConsoleCommand::Make + ( + "DETAIL_LEVEL_MIN", + "", + SetToMinimalDetailLevels + ); + + ConsoleCommand::Make + ( + "SCREENSHOT", + "", + ScreenShot + ); + + ConsoleCommand::Make + ( + "QUICKSAVE", + "", + QuickSave + ); + ConsoleCommand::Make + ( + "QUICKLOAD", + "", + QuickLoad + ); + ConsoleCommand::Make + ( + "SAVE", + "Save game to slot 1-8", + ConsoleCommandSave + ); + ConsoleCommand::Make + ( + "LOAD", + "Load game from slot 1-8", + ConsoleCommandLoad + ); + ConsoleCommand::Make + ( + "SAVESLEFT", + "", + DisplaySavesLeft + ); + +} + + + + + +} // extern "C" \ No newline at end of file diff --git a/3dc/avp/gameflow.c b/3dc/avp/gameflow.c new file mode 100644 index 0000000..842fb11 --- /dev/null +++ b/3dc/avp/gameflow.c @@ -0,0 +1,641 @@ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "inventry.h" +#include "gameplat.h" + +#include "gameflow.h" + +#include "bh_types.h" +#include "bh_gener.h" + +#define UseLocalAssert Yes + +#include "ourasert.h" + +extern void ActivateSelfDestructSequence(int seconds); + +GAMEOBJECT GameObjects[] = +{ + GOT_LIFTOVERRIDE1, + //0x4b630a49,0xe6d1ca, + 0,0, + + GOT_LIFTOVERRIDE2, + //0xa90f8f50,0x252139, + 0,0, + + GOT_LIFTOVERRIDE3, + //0x32d82514,0x286a42, + 0,0, + + GOT_LIFTOVERRIDE4, + //0xa2befeb4,0xe2e009, + 0,0, + + GOT_SELFDESTRUCT, + //0xf2d0d89c,0x923401, + 0,0, + + GOT_PREDSHIP1, + //0x385fb8b9,0x7e14ad, + 0,0, + + GOT_PREDSHIP2, + 0,0, + + /* New stuff for Jules's level: 1/12/97 CDF */ + + GOT_FAKESWITCH_IN_GENERATOR, + 0x5caeb020,0x88620, + + GOT_DATALOG_1, + 0xbbfbd11a,0x1d34bf, + + GOT_DATALOG_2, + 0x68045d04,0x69092e, + + GOT_DATALOG_3, + 0x3d784e97,0x31a9c5, + + GOT_ENDLEVEL_EVENT, + 0x5655280,0xb5aef1, + + // This has to be last in the list + GOT_LASTGAMEOBJECT, + 0,0 + +}; + +GAME_STRATBLOCK_LIST_ENTRY GameStratblockList[] = { + + GT_YARD_DOOR_1, + {0xd9,0x15,0xd7,0xcc,0xa7,0xf4,0xb6,0x00,}, + GT_YARD_DOOR_2, + {0x01,0x0a,0x0f,0xf5,0x76,0x0b,0x5a,0x00,}, + GT_YARD_DOOR_3, + {0x7b,0x18,0x0f,0xa7,0x14,0xae,0x67,0x00,}, + GT_YARD_DOOR_4, + {0xd7,0x52,0x95,0x48,0xcc,0xf2,0x14,0x00,}, + + GT_LAST_TARGET_OBJECT, + {0,0,0,0,0,0,0,0,}, + +}; + +BOOL GameFlowOn = 1; + +static unsigned long MakeFlag (unsigned long num) +{ + return(1<CurrentMission) + { + case MarineMission_NoneAsYet: + { + GLOBALASSERT (current == I_Entrance && next == I_Gen1); + + DoStartMissionSequence (MarineMission_DisableLifts); + retval = 1; + PlayerStatusPtr->CurrentMission = MarineMission_DisableLifts; + PlayerStatusPtr->securityClearances = MakeFlag (LS_Gen1_Gen2) + + MakeFlag (LS_Gen3Internal) + + MakeFlag (LS_Gen2_Gen3); + + break; + } + + case MarineMission_DisableLifts: + { + GLOBALASSERT ((current == I_Gen1 || + current == I_Gen2 || + current == I_Gen3) + && + (next == I_Gen1 || + next == I_Gen2 || + next == I_Gen3) + ); + + if (next == I_Gen2) + { + PlayerStatusPtr->securityClearances &= ~MakeFlag (LS_Gen1_Gen2); + } + + if (current == I_Gen3 && next == I_Gen1) + { + DoStartMissionSequence (MarineMission_GoToSP2); + retval = 1; + PlayerStatusPtr->CurrentMission = MarineMission_GoToSP2; + PlayerStatusPtr->securityClearances = MakeFlag (LS_Gen1_SP2); + } + + break; + } + + case MarineMission_GoToSP2: + { + GLOBALASSERT (current == I_Gen1 && next == I_Sp2); + + DoStartMissionSequence (MarineMission_LeaveRnDs); + retval = 1; + PlayerStatusPtr->CurrentMission = MarineMission_LeaveRnDs; + PlayerStatusPtr->securityClearances = MakeFlag (LS_SP2_RnD2) + + MakeFlag (LS_RnD2_RnD3) + + MakeFlag (LS_Gen1_RnD4) + + MakeFlag (LS_RnD3_RnD4); + + break; + } + + case MarineMission_LeaveRnDs: + { + GLOBALASSERT ((current == I_Rnd4 || + current == I_Rnd2 || + current == I_Gen1 || + current == I_Sp2 || + current == I_Rnd3) + && + (next == I_Rnd4 || + next == I_Rnd2 || + next == I_Gen1 || + next == I_Sp2 || + next == I_Rnd3) + ); + + if (current == I_Rnd4 && next == I_Gen1) + { + DoStartMissionSequence (MarineMission_GoToCMC6); + retval = 1; + PlayerStatusPtr->CurrentMission = MarineMission_GoToCMC6; + PlayerStatusPtr->securityClearances = MakeFlag (LS_Gen1_CMC6); + } + + break; + } + + case MarineMission_GoToCMC6: + { + GLOBALASSERT (current == I_Gen1 && next == I_Cmc6); + + DoStartMissionSequence (MarineMission_GoToCMC2); + retval = 1; + PlayerStatusPtr->CurrentMission = MarineMission_GoToCMC2; + PlayerStatusPtr->securityClearances = MakeFlag (LS_CMC2_CMC4) + + MakeFlag (LS_CMC4_CMC6); + + break; + } + + case MarineMission_GoToCMC2: + { + GLOBALASSERT ((current == I_Cmc4 || + current == I_Cmc2 || + current == I_Cmc6) + && + (next == I_Cmc4 || + next == I_Cmc2 || + next == I_Cmc6) + ); + + if (current == I_Cmc4 && next == I_Cmc2) + { + DoStartMissionSequence (MarineMission_DestructBase); + retval = 1; + PlayerStatusPtr->CurrentMission = MarineMission_DestructBase; + PlayerStatusPtr->securityClearances = MakeFlag (LS_MPS2_MPS4) + + MakeFlag (LS_SP3_MPS2) + + MakeFlag (LS_Gen1_Medlab) + + MakeFlag (LS_Gen1_CMC2) + + MakeFlag (LS_Gen1_SP3); + } + + break; + } + + case MarineMission_DestructBase: + { + if (current == I_Mps4 && next == I_Surface) + { + DoStartMissionSequence (MarineMission_Won); + } + + break; + } + + case MarineMission_Won: + { + break; + } + + + default: + { + GLOBALASSERT (0 == "Mission not in marine list"); + break; + } + } + break; + } + + case I_Predator: + { + switch (PlayerStatusPtr->CurrentMission) + { + case PredMission_DestroyComputers: + { + if (current == I_Cmc4 && next == I_Cmc6) + { + PlayerStatusPtr->securityClearances = + MakeFlag (LS_Gen1_Entrance)+ + MakeFlag (LS_Gen1_Medlab)+ + MakeFlag (LS_Gen1_Gen2)+ + MakeFlag (LS_Gen1_Gen3)+ + MakeFlag (LS_Gen1_SP3)+ + MakeFlag (LS_Gen1_CMC6)+ + MakeFlag (LS_Gen1_CMC2)+ + MakeFlag (LS_Gen1_RnD4)+ + MakeFlag (LS_Gen1_SP2)+ + MakeFlag (LS_Gen2_Gen3)+ + MakeFlag (LS_CMC2_CMC4)+ + MakeFlag (LS_CMC4_CMC6)+ + MakeFlag (LS_SP3_MPS2)+ + MakeFlag (LS_MPS2_MPS4)+ + MakeFlag (LS_MPS4_SURFACE)+ + MakeFlag (LS_SP2_RnD2)+ + MakeFlag (LS_RnD2_RnD3)+ + MakeFlag (LS_RnD3_RnD4)+ + MakeFlag (LS_Gen3Internal)+ + MakeFlag (LS_MaxLifts); + + } + else if (current == I_Cmc6) + { + DoStartMissionSequence (PredMission_GetShipGen3); + PlayerStatusPtr->CurrentMission = PredMission_GetShipGen3; + retval = 1; + } + + break; + } + + case PredMission_GetShipGen3: + { + if (PlayerStatusPtr->StateChangeObjectFlags & MakeFlag (GOT_PREDSHIP1)) + { + if (PlayerStatusPtr->StateChangeObjectFlags & MakeFlag (GOT_PREDSHIP2)) + { + DoStartMissionSequence (PredMission_KillPredAlien); + PlayerStatusPtr->CurrentMission = PredMission_KillPredAlien; + retval = 1; + } + else + { + DoStartMissionSequence (PredMission_GetShipCMC2); + PlayerStatusPtr->CurrentMission = PredMission_GetShipCMC2; + retval = 1; + } + } + break; + } + + case PredMission_GetShipCMC2: + { + if (PlayerStatusPtr->StateChangeObjectFlags & MakeFlag (GOT_PREDSHIP2)) + { + DoStartMissionSequence (PredMission_KillPredAlien); + PlayerStatusPtr->CurrentMission = PredMission_KillPredAlien; + retval = 1; + } + break; + } + + case PredMission_KillPredAlien: + { + break; + } + + case PredMission_KillQueen: + { + break; + } + + case PredMission_ReturnToShip: + { + break; + } + + default: + { + GLOBALASSERT (0 == "Mission not in Predator list"); + break; + } + } + break; + } + + case I_Alien: + { + break; + } + + default: + { + GLOBALASSERT (0 == "Player type is wrong"); + break; + } + } + return(retval); + +} + +void InitGameFlowSystem (struct player_status * ps, INITGAMEFLOWTYPE igft) +{ + if (!GameFlowOn) + { + ps->securityClearances = 0xfffffff; + return; + } + if (igft == IGFT_NewGame) + { + switch (AvP.PlayerType) + { + case I_Marine: + { + ps->CurrentMission = MarineMission_NoneAsYet; + ps->StateChangeObjectFlags = 0; + //ps->securityClearances = MakeFlag (LS_Gen1_Entrance); + ps->securityClearances = 0; + + break; + } + + case I_Predator: + { + ps->CurrentMission = PredMission_DestroyComputers; + ps->StateChangeObjectFlags = 0; + ps->securityClearances = MakeFlag (LS_CMC4_CMC6); + break; + } + + case I_Alien: + { + ps->CurrentMission = AlienMission_DestroyMarines; + ps->StateChangeObjectFlags = 0; + + break; + } + + + default: + { + break; + } + } + } +} + +static GAMEOBJECT * GetGameObject (const char * id) +{ + GAMEOBJECT * goptr = &GameObjects[0]; + + while (goptr->StateChangeObjectNum != GOT_LASTGAMEOBJECT) + { + int id1, id2; + + id1 = *(int*)id; + id2 = *(((int*)id) + 1); + + if ((id1 == goptr->id1) && (id2 == goptr->id2)) + { + return(goptr); + } + + goptr++; + + } + return(0); +} + +STRATEGYBLOCK *GetMeThisStrategyBlock(GAMETARGETOBJECTS This_One) { + + int a,num; + + a=0; + num=-1; + + while (GameStratblockList[a].TargetObjectNum!=GT_LAST_TARGET_OBJECT) { + if (GameStratblockList[a].TargetObjectNum==This_One) { + num=a; + break; + } + a++; + } + + if (num==-1) { + return(NULL); + } + + return(FindSBWithName(GameStratblockList[num].SBname)); + +} + +BOOL GameFlowStateChangeObjectEncountered (STRATEGYBLOCK * sbPtr) +{ + //I don't hink any of these are necessary any more - Richard. + #if 0 + char * id = sbPtr->SBname; + + if (!(AvP.Network == I_No_Network) || !GameFlowOn) + { + return (0); + } + + switch (AvP.PlayerType) + { + case I_Marine: + { + switch (PlayerStatusPtr->CurrentMission) + { + case MarineMission_DisableLifts: + { + GAMEOBJECT * goptr = GetGameObject (id); + + GLOBALASSERT(0); + /* How could that happen??? */ + + if (goptr) + { + if (goptr->StateChangeObjectNum >= GOT_LIFTOVERRIDE1 && + goptr->StateChangeObjectNum <= GOT_LIFTOVERRIDE4) + { + PlayerStatusPtr->StateChangeObjectFlags |= MakeFlag (goptr->StateChangeObjectNum); + } + if (goptr->StateChangeObjectNum == GOT_LIFTOVERRIDE3) + { + PlayerStatusPtr->securityClearances &= ~MakeFlag (LS_Gen3Internal); + } + } + + if ( + (PlayerStatusPtr->StateChangeObjectFlags & MakeFlag (GOT_LIFTOVERRIDE1)) && + (PlayerStatusPtr->StateChangeObjectFlags & MakeFlag (GOT_LIFTOVERRIDE2)) && + (PlayerStatusPtr->StateChangeObjectFlags & MakeFlag (GOT_LIFTOVERRIDE3)) && + (PlayerStatusPtr->StateChangeObjectFlags & MakeFlag (GOT_LIFTOVERRIDE4)) + ) + { + PlayerStatusPtr->securityClearances |= MakeFlag (LS_Gen1_Gen3); + } + + break; + } + + case MarineMission_DestructBase: + { + GAMEOBJECT * goptr = GetGameObject (id); + + GLOBALASSERT(0); + /* How could that happen??? */ + + if (goptr) if (goptr->StateChangeObjectNum == GOT_SELFDESTRUCT) + { + ActivateSelfDestructSequence(150); + PlayerStatusPtr->securityClearances |= MakeFlag (LS_MPS4_SURFACE); + } + + break; + } + + case MarineMission_NoneAsYet: + { + /* This is Jules's level. CDF 1/12/97 */ + GAMEOBJECT * goptr = GetGameObject (id); + + if (goptr) { + switch (goptr->StateChangeObjectNum) { + case GOT_FAKESWITCH_IN_GENERATOR: + { + STRATEGYBLOCK *target; + + target=NULL; + target=GetMeThisStrategyBlock(GT_YARD_DOOR_1); + if (target) { + UnlockThisProxdoor(target); + } + target=NULL; + target=GetMeThisStrategyBlock(GT_YARD_DOOR_2); + if (target) { + UnlockThisProxdoor(target); + } + target=NULL; + target=GetMeThisStrategyBlock(GT_YARD_DOOR_3); + if (target) { + UnlockThisProxdoor(target); + } + target=NULL; + target=GetMeThisStrategyBlock(GT_YARD_DOOR_4); + if (target) { + UnlockThisProxdoor(target); + } + ActivateHive(); + + break; + } + case GOT_DATALOG_1: + case GOT_DATALOG_2: + case GOT_DATALOG_3: + PlayerStatusPtr->StateChangeObjectFlags |= MakeFlag (goptr->StateChangeObjectNum); + return(1); + break; + case GOT_ENDLEVEL_EVENT: + if ( + (PlayerStatusPtr->StateChangeObjectFlags & MakeFlag (GOT_DATALOG_1)) && + (PlayerStatusPtr->StateChangeObjectFlags & MakeFlag (GOT_DATALOG_2)) && + (PlayerStatusPtr->StateChangeObjectFlags & MakeFlag (GOT_DATALOG_3)) + ) { + /* I guess we'd better end the level, then. */ + textprint("\n\n\nEND OF LEVEL!\n\n\n"); + AvP.MainLoopRunning = 0; + } + break; + default: + textprint("Unknown gameflow object %d! I'm well confused!\n",goptr->StateChangeObjectNum); + GLOBALASSERT(0); + break; + } + } + + break; + } + + default: + { + break; + } + } + + break; + } + + case I_Predator: + { + #if 1 + return(1); + #else + switch (PlayerStatusPtr->CurrentMission) + { + case PredMission_GetShipGen3: + case PredMission_GetShipCMC2: + { + GAMEOBJECT * goptr = GetGameObject (id); + if (goptr) + if (goptr->StateChangeObjectNum == GOT_PREDSHIP1 || + goptr->StateChangeObjectNum == GOT_PREDSHIP2) + { + PlayerStatusPtr->StateChangeObjectFlags |= MakeFlag (goptr->StateChangeObjectNum); + return(1); + } + + break; + } + + default: + { + break; + } + } + #endif + break; + } + + default: + { + break; + } + } + #endif + return(0); +} + + + diff --git a/3dc/avp/gameflow.h b/3dc/avp/gameflow.h new file mode 100644 index 0000000..48ae21e --- /dev/null +++ b/3dc/avp/gameflow.h @@ -0,0 +1,126 @@ +#ifndef _gameflow_h +#define _gameflow_h 1 + +// allow a compile flag to switch system on and off +// otherwise assert frenzy may ensue +#include "gamedef.h" +#include "system.h" + +extern BOOL GameFlowOn; + +typedef enum +{ + IGFT_NewGame, + IGFT_ResumeGame, +}INITGAMEFLOWTYPE; + +typedef enum +{ + MarineMission_NoneAsYet, + MarineMission_DisableLifts, + MarineMission_GoToSP2, + MarineMission_LeaveRnDs, + MarineMission_GoToCMC6, + MarineMission_GoToCMC2, + MarineMission_DestructBase, + MarineMission_Won, + + PredMission_DestroyComputers, + PredMission_GetShipGen3, + PredMission_GetShipCMC2, + PredMission_KillPredAlien, + PredMission_KillQueen, + PredMission_ReturnToShip, + + AlienMission_DestroyMarines, + AlienMission_DestroyMarinesWithSpit, + AlienMission_DestoryOtherBaddies, + AlienMission_DestroyQueen, + + PlayerMissions_Last, + +} PLAYERMISSION; + +typedef enum +{ + LS_Gen1_Entrance = 1, + LS_Gen1_Medlab, + LS_Gen1_Gen2, + LS_Gen1_Gen3, + LS_Gen1_SP3, + LS_Gen1_CMC6, + LS_Gen1_CMC2, + LS_Gen1_RnD4, + LS_Gen1_SP2, + LS_Gen2_Gen3, + LS_CMC2_CMC4, + LS_CMC4_CMC6, + LS_SP3_MPS2, + LS_MPS2_MPS4, + LS_MPS4_SURFACE, + LS_SP2_RnD2, + LS_RnD2_RnD3, + LS_RnD3_RnD4, + LS_Gen3Internal, + LS_MaxLifts, + +} LIFTSECURITYNUMBERS; + +typedef enum +{ + GOT_LIFTOVERRIDE1, + GOT_LIFTOVERRIDE2, + GOT_LIFTOVERRIDE3, + GOT_LIFTOVERRIDE4, + GOT_SELFDESTRUCT, + GOT_COMPUTERSYSTEM, + GOT_PREDSHIP1, + GOT_PREDSHIP2, + /* New stuff for Jules's level: 1/12/97 CDF */ + GOT_FAKESWITCH_IN_GENERATOR, + GOT_DATALOG_1, + GOT_DATALOG_2, + GOT_DATALOG_3, + GOT_ENDLEVEL_EVENT, + + GOT_LASTGAMEOBJECT, +} GAMESTATECHANGEOBJECTS; + +typedef struct +{ + GAMESTATECHANGEOBJECTS StateChangeObjectNum; + int id1; + int id2; +} GAMEOBJECT; + +typedef enum { + GT_YARD_DOOR_1, + GT_YARD_DOOR_2, + GT_YARD_DOOR_3, + GT_YARD_DOOR_4, + + GT_LAST_TARGET_OBJECT, +} GAMETARGETOBJECTS; + +typedef struct { + GAMETARGETOBJECTS TargetObjectNum; + char SBname[SB_NAME_LENGTH]; +} GAME_STRATBLOCK_LIST_ENTRY; + +struct player_status; + +// Internal Platform independent fns. +extern int ChangingLevelGameFlowUpdate (I_AVP_ENVIRONMENTS current, I_AVP_ENVIRONMENTS next); +// returns 1 if it is playing an FMV, or 0 otherwise + +extern void InitGameFlowSystem (struct player_status * ps, INITGAMEFLOWTYPE igft); + +// returns 1 if the Object should be picked up, 0 otherwise +extern BOOL GameFlowStateChangeObjectEncountered (STRATEGYBLOCK * sbPtr); + +// Internal Platform dependent fns. +// see glfwplat.c +extern void DoStartMissionSequence (PLAYERMISSION mission); + + +#endif \ No newline at end of file diff --git a/3dc/avp/gamevars.cpp b/3dc/avp/gamevars.cpp new file mode 100644 index 0000000..8fcb03a --- /dev/null +++ b/3dc/avp/gamevars.cpp @@ -0,0 +1,470 @@ +/* KJL 11:10:15 28/01/98 - + + This file contains game-specific console variables + + */ +//#include "rentrntq.h" +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" + +#include "davehook.h" + + +#include "r2base.h" + // hooks to R2 code + +#include "gadget.h" + // hooks to gadgets code + +#include "daemon.h" + // hooks to daemon code + +#include "rentrntq.h" + +//#include "ammo666.hpp" + +//#include "iofocus.h" + +//#include "statpane.h" + +//#include "font.h" + +//#include "hudgadg.hpp" + +#include "consvar.hpp" +#include "conscmnd.hpp" + +#include "equipmnt.h" +#include "pldnet.h" +#include "avp_menus.h" + +extern "C" +{ + +/* KJL 11:48:45 28/01/98 - used to scale NormalFrameTime, so the game can be slowed down */ +extern int TimeScale; +extern int MotionTrackerScale; +extern int LeanScale; + +extern int CrouchIsToggleKey; +extern int CloakingMode; +extern int LogConsoleTextToFile; + +extern int PlanarGravity; + + +extern int GlobalLevelOfDetail_Hierarchical; +extern int JoystickEnabled; + +extern int SkyColour_R; +extern int SkyColour_G; +extern int SkyColour_B; + +extern int DrawCompanyLogos; + +extern int QuantumObjectDieRollOveride; + +extern int WireFrameMode; +extern int LightScale; + +extern int MotionTrackerSpeed; +extern int MotionTrackerVolume; + +extern int DrawFullBright; + +extern void ChangeToMarine(); +extern void ChangeToAlien(); +extern void ChangeToPredator(); + +extern int SentrygunSpread; +int PlaySounds; +int DopplerShiftIsOn; + +extern int UseExtrapolation; + +extern int DebuggingCommandsActive; + +extern int AutoWeaponChangeOn; + +void CreateGameSpecificConsoleVariables(void) +{ + TimeScale = 65536; + if (AvP.PlayerType==I_Alien) + { + LeanScale=ONE_FIXED*3; + } + else + { + LeanScale=ONE_FIXED; + } + CrouchIsToggleKey = 0; + CloakingMode=0; + LogConsoleTextToFile=0; + JoystickEnabled=0; + GlobalLevelOfDetail_Hierarchical = ONE_FIXED; + DrawCompanyLogos=0; + LightScale = ONE_FIXED; + DopplerShiftIsOn=1; + PlaySounds=1; + DrawFullBright=0; + + #ifndef AVP_DEBUG_VERSION // allow debug commands without -debug + BOOL IsACheat = TRUE; + #else + BOOL IsACheat = FALSE; + #endif + + #ifndef AVP_DEBUG_VERSION // allow debug commands without -debug + #ifndef AVP_DEBUG_FOR_FOX // allow debug commands without -debug + if (DebuggingCommandsActive) + #endif + #endif + { + ConsoleVariable :: MakeSimpleConsoleVariable_FixP + ( + TimeScale, // int& Value_ToUse, + "TIMESCALE", // ProjChar* pProjCh_ToUse, + "1.0 IS NORMAL", // ProjChar* pProjCh_Description_ToUse + 655, // int MinVal_New, + 65536*4, // int MaxVal_New + IsACheat + ); + ConsoleVariable :: MakeSimpleConsoleVariable_FixP + ( + LeanScale, // int& Value_ToUse, + "LEANSCALE", // ProjChar* pProjCh_ToUse, + "1.0 IS DEFAULT, HIGHER MEANS MORE TILT", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 65536*10, // int MaxVal_New + IsACheat + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + WireFrameMode, // int& Value_ToUse, + "WIREFRAMEMODE", // ProjChar* pProjCh_ToUse, + "0 = OFF, 1 = ENVIRONMENT, 2 = OBJECTS, 3 = EVERYTHING", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 3, // int MaxVal_New + IsACheat + ); + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + (int&)DopplerShiftIsOn, // int& Value_ToUse, + "DOPPLERSHIFT", // ProjChar* pProjCh_ToUse, + "", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1, // int MaxVal_New + IsACheat + ); + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + SkyColour_R, // int& Value_ToUse, + "SKY_RED", // ProjChar* pProjCh_ToUse, + "SET RED COMPONENT OF SKY COLOUR", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 255, // int MaxVal_New + IsACheat + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + SkyColour_G, // int& Value_ToUse, + "SKY_GREEN", // ProjChar* pProjCh_ToUse, + "SET GREEN COMPONENT OF SKY COLOUR", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 255, // int MaxVal_New + IsACheat + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + SkyColour_B, // int& Value_ToUse, + "SKY_BLUE", // ProjChar* pProjCh_ToUse, + "SET BLUE COMPONENT OF SKY COLOUR", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 255, // int MaxVal_New + IsACheat + ); + ConsoleVariable :: MakeSimpleConsoleVariable_FixP + ( + MotionTrackerSpeed, // int& Value_ToUse, + "MOTIONTRACKERSPEED", // ProjChar* pProjCh_ToUse, + "1.0 IS NORMAL", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 65536*16, // int MaxVal_New + IsACheat + ); + } + + #if CONSOLE_DEBUGGING_COMMANDS_ACTIVATED + ConsoleVariable :: MakeSimpleConsoleVariable_FixP + ( + MotionTrackerScale, // int& Value_ToUse, + "MOTIONTRACKERSCALE", // ProjChar* pProjCh_ToUse, + "1.0 IS FULL SIZE", // ProjChar* pProjCh_Description_ToUse + 26214, // int MinVal_New, + 655360 // int MaxVal_New + ); + + + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + CloakingMode, // int& Value_ToUse, + "CLOAKINGMODE", // ProjChar* pProjCh_ToUse, + "0 MEANS TRANSLUCENCY WAVES, 1 MEANS SPECKLED", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + LogConsoleTextToFile, // int& Value_ToUse, + "LOGCONSOLE", // ProjChar* pProjCh_ToUse, + "ENABLE/DISABLE LOGGING CONSOLE TEXT TO FILE", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + JoystickEnabled, // int& Value_ToUse, + "JOYSTICKENABLED", // ProjChar* pProjCh_ToUse, + "ENABLE/DISABLE JOYSTICK", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + PlanarGravity, + "PLANARGRAVITY", + "", + 0, + 1 + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + DrawCompanyLogos, + "DRAW_LOGOS", + "", + 0, + 1 + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_FixP + ( + GlobalLevelOfDetail_Hierarchical, // int& Value_ToUse, + "LOD_HIERARCHICAL", // ProjChar* pProjCh_ToUse, + "1.0 IS NORMAL, 0 MEANS ALWAYS USE MOST DETAILED LEVEL, HIGHER NUMBERS MEAN LOWER DETAIL MODELS ARE USED AT CLOSER DISTANCES", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 65536*100 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_FixP + ( + LightScale, // int& Value_ToUse, + "LIGHTSCALE", // ProjChar* pProjCh_ToUse, + "1.0 IS NORMAL", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 65536*100 // int MaxVal_New + ); + + + + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + QuantumObjectDieRollOveride, // int& Value_ToUse, + "QUANTUM_ROLL", // ProjChar* pProjCh_ToUse, + "FORCE QUANTUM OBJECT DIE ROLL (-1 MEANS DON'T FORCE ROLL)", // ProjChar* pProjCh_Description_ToUse + -1, // int MinVal_New, + 65535 // int MaxVal_New + ); + + ConsoleCommand :: Make + ( + "MORPH_ALIEN", + "BECOME AN ALIEN", + ChangeToAlien + ); + ConsoleCommand :: Make + ( + "MORPH_MARINE", + "BECOME A MARINE", + ChangeToMarine + ); + ConsoleCommand :: Make + ( + "MORPH_PREDATOR", + "BECOME A PREDATOR", + ChangeToPredator + ); + + //various network scoring options + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + netGameData.baseKillValue, // int& Value_ToUse, + "NETSCORE_BASEKILLVALUE", // ProjChar* pProjCh_ToUse, + "SET BASE VALUE FOR KILL/SUICIDE", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 255 // int MaxVal_New + ); + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + netGameData.characterKillValues[NGCT_Marine], // int& Value_ToUse, + "NETSCORE_MARINEVALUE", // ProjChar* pProjCh_ToUse, + "SET RELATIVE VALUE OF MARINE", // ProjChar* pProjCh_Description_ToUse + 1, // int MinVal_New, + 255 // int MaxVal_New + ); + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + netGameData.characterKillValues[NGCT_Predator], // int& Value_ToUse, + "NETSCORE_PREDATORVALUE", // ProjChar* pProjCh_ToUse, + "SET RELATIVE VALUE OF PREDATOR", // ProjChar* pProjCh_Description_ToUse + 1, // int MinVal_New, + 255 // int MaxVal_New + ); + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + netGameData.characterKillValues[NGCT_Alien], // int& Value_ToUse, + "NETSCORE_ALIENVALUE", // ProjChar* pProjCh_ToUse, + "SET RELATIVE VALUE OF ALIEN", // ProjChar* pProjCh_Description_ToUse + 1, // int MinVal_New, + 255 // int MaxVal_New + ); + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + netGameData.useDynamicScoring, // int& Value_ToUse, + "NETSCORE_USEDYNAMICSCORING", // ProjChar* pProjCh_ToUse, + "TURN DYNAMIC SCORING ON AND OFF", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1 // int MaxVal_New + ); + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + netGameData.useCharacterKillValues, // int& Value_ToUse, + "NETSCORE_USECHARVALUES", // ProjChar* pProjCh_ToUse, + "TURN RELATIVE SCORES FOR CHARACTER TYPES ON AND OFF", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1 // int MaxVal_New + ); + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + netGameData.invulnerableTime, // int& Value_ToUse, + "NETSTAT_INVULNERABLETIME", // ProjChar* pProjCh_ToUse, + "SET INVULNERABILITY TIME AFTER RESPAWN (IN SECONDS)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 255 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + (int&)AvP.Difficulty, // int& Value_ToUse, + "DIFFICULTY", // ProjChar* pProjCh_ToUse, + "SET DIFFICULTY LEVEL (WILL REQUIRE LEVEL RESTART)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 2 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + (int&)netGameData.sendDecals, // int& Value_ToUse, + "NETOPTION_SENDDECALS", // ProjChar* pProjCh_ToUse, + "SHOULD DECALS BE SENT ACROSS THE NETWORK?", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + (int&)SentrygunSpread, // int& Value_ToUse, + "SENTRYGUN_SPREAD", // ProjChar* pProjCh_ToUse, + "Angle in degrees for random deviation in direction", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 360 // int MaxVal_New + ); + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + (int&)PlaySounds, // int& Value_ToUse, + "PLAYSOUNDS", // ProjChar* pProjCh_ToUse, + "", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + (int&)DrawFullBright, // int& Value_ToUse, + "DRAWFULLBRIGHT", // ProjChar* pProjCh_ToUse, + "", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_FixP + ( + netGameData.sendFrequency, // int& Value_ToUse, + "NETSENDFREQUENCY", // ProjChar* pProjCh_ToUse, + "0 MEANS SEND EVERY FRAME", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 65536 // int MaxVal_New + ); + #endif +/* + MakeSimpleConsoleVariable_Int + ( + bEnableTextprint, // int& Value_ToUse, + "TEXT", // ProjChar* pProjCh_ToUse, + "(ENABLE/DISABLE DIAGNOSTIC TEXT)", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1 // int MaxVal_New + ); +*/ + + ConsoleVariable :: MakeSimpleConsoleVariable_FixP + ( + MotionTrackerVolume, // int& Value_ToUse, + "MOTIONTRACKERVOLUME", // ProjChar* pProjCh_ToUse, + "1.0 IS NORMAL", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 65536 // int MaxVal_New + ); + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + (int&)UseExtrapolation, // int& Value_ToUse, + "EXTRAPOLATE_MOVEMENT", // ProjChar* pProjCh_ToUse, + "TURN EXTRAPOLATION FOR MOVEMENT OF NETWORK OPPONENTS ON AND OFF", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1 // int MaxVal_New + ); + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + CrouchIsToggleKey, // int& Value_ToUse, + "CROUCHMODE", // ProjChar* pProjCh_ToUse, + "0 MEANS HOLD DOWN MODE, 1 MEANS TOGGLE MODE", // ProjChar* pProjCh_Description_ToUse + 0, // int MinVal_New, + 1 // int MaxVal_New + ); + + ConsoleVariable :: MakeSimpleConsoleVariable_Int + ( + AutoWeaponChangeOn, + "AUTOWEAPONCHANGE", + "SET TO 0 IF YOU DON'T WANT TO CHANGE TO NEWLY GAINED WEAPONS AUTOMATICALLY. OTHERWISE SET TO 1.", + 0, + 1 + ); + + +} + +}; // extern "C" \ No newline at end of file diff --git a/3dc/avp/hmodel.h b/3dc/avp/hmodel.h new file mode 100644 index 0000000..e5c03f2 --- /dev/null +++ b/3dc/avp/hmodel.h @@ -0,0 +1,401 @@ +/***** HModel.h *****/ + +#ifndef _hmodel_h +#define _hmodel_h 1 + +#ifdef __cplusplus +extern "C" { +#endif +#include "decal.h" +#include "psnd.h" + +/* CDF 15/9/97 New Damage System */ +typedef struct sb_health_bitfield +{ + unsigned int AcidResistant:1; + unsigned int FireResistant:1; + unsigned int ElectricResistant:1; + unsigned int PerfectArmour:1; /* For true aliens! */ + unsigned int ElectricSensitive:1; /* For Xenoborgs */ + unsigned int Combustability:2; + unsigned int Indestructable:1; +}SBHEALTHFLAGS; +/* +Combustability: +0=Non: Will not burn. +1=Combustable: Normal rules. +2=Sensitive: Normal rules?, + double damage. +3=Flammable: Always ignites + double damage. +*/ + +typedef struct damageblock { + /* CDF 15/9/97 New Damage System */ + int Health; + int Armour; + unsigned int IsOnFire:1; + + SBHEALTHFLAGS SB_H_flags; + /* CDF 15/9/97 New Damage System */ +} DAMAGEBLOCK; + +/* CDF 15/9/97 New Damage System */ +/* Moved to this file 12/11/97 */ + +typedef struct Hierarchy_Sound +{ + SOUND3DDATA s3d; + struct loaded_sound const * sound_loaded; + SOUNDINDEX sound_index; + int pitch; + int volume; +}HIERARCHY_SOUND; + + +/* +I'm going to try storing the quaternions as shorts within the keyframes , +because there are loads of them. +-Richard. +*/ +typedef struct quat_short +{ + short quatx; + short quaty; + short quatz; + short quatw; +}QUAT_SHORT; +/*A couple of conversion functions */ +extern void CopyShortQuatToInt(QUAT_SHORT* qs_from,QUAT* q_to); +extern void CopyIntQuatToShort(QUAT* q_from,QUAT_SHORT* qs_to); + + +#define KEYFRAME_VECTOR_SHIFT 4 + +//make sure the keyframe structure packs as much as possible +#pragma pack(push,1) +typedef struct keyframe_data { + short Offset_x; /*Offset values may need to be scaled*/ + short Offset_y; /*In practice scaling should only be needed for 'placed' hierarchies*/ + short Offset_z; + + /* Quats */ + QUAT_SHORT QOrient; + /* + int oneoversinomega; + Removed oneoversinomega , since I can save a far amount of memory by doing so , + and the value is just calculated using a lookup table anyway. -Richard + */ + int oneoversequencelength; + unsigned short omega:12; + /* Quats */ + unsigned short slerp_to_negative_quat:1; /*Should the slerping use the negative version of the next quaternion*/ + unsigned short frame_has_extended_data:1; /*frame can be cast to a KEYFRAME_DATA_EXTENDED in order to access flag and sound info*/ + unsigned short shift_offset:1; /*does offset need to be scaled*/ + + unsigned short last_frame:1; /*Is this the last frame?*/ + + unsigned short Sequence_Length; /* Time between these values and the next ones. */ + struct keyframe_data *Next_Frame; /*This is no longer Null for the last frame - look at the last_frame setting instead*/ +} KEYFRAME_DATA; +#pragma pack(pop) + + + +/*Two functions for extracting and setting the key frame offset */ +extern void GetKeyFrameOffset(KEYFRAME_DATA* frame,VECTORCH* output_vector); +extern void SetKeyFrameOffset(KEYFRAME_DATA* frame,VECTORCH* input_vector); + +/* +If a keyframe has frame_has_extended_data set , then it can be cast to a +KEYFRAME_DATA_EXTENDED in order to access the flags and sound. +*/ +typedef struct keyframe_data_extended { + KEYFRAME_DATA frame_data; + /* Keyframe flagging! */ + int flags; + /*sound to be played this frame*/ + HIERARCHY_SOUND* sound; +} KEYFRAME_DATA_EXTENDED; + +typedef struct sequence { + int sequence_id; + KEYFRAME_DATA *first_frame; + KEYFRAME_DATA *last_frame; + int Time; +} SEQUENCE; + +typedef struct Hierarchy_Shape_Replacement +{ + char* replaced_section_name; + int replacement_shape_index; + SHAPEHEADER* replacement_shape; + int replacement_id; +}HIERARCHY_SHAPE_REPLACEMENT; + +typedef struct section { + int ShapeNum; /* Just in case */ + SHAPEHEADER *Shape; + char *ShapeName; + char *Section_Name; + char *Hierarchy_Name; + char *Rif_Name; + struct section **Children; + int num_sequences; + SEQUENCE *sequence_array; + struct damageblock StartingStats; + VECTORCH gore_spray_direction; + int flags; + int IDnumber; +} SECTION; + +typedef struct section_attachment { + char *Riffname; + char *Section_Name; + char **Hierarchy_Name; + struct damageblock StartingStats; + int flags; +} SECTION_ATTACHMENT; + +/* Nature flags */ +#define section_has_shape_animation 0x00000001 +#define section_has_sparkoflife 0x00000002 +#define section_is_master_root 0x00000004 + +/* Section behaviour flags */ +#define section_sprays_blood 0x00000008 +#define section_sprays_acid 0x00000010 +#define section_sprays_predoblood 0x00000020 +#define section_sprays_sparks 0x00000040 +#define section_flag_nofurthergibbing 0x00000080 +#define section_flag_doesnthurtsb 0x00000100 +#define section_flag_heatsource 0x00000200 +#define section_flag_affectedbyheat 0x00000400 +#define section_flag_never_frag 0x00000800 +#define section_flag_fragonlyfordisks 0x00001000 +#define section_flag_gibbwhenfragged 0x00002000 +#define section_flag_passdamagetoparent 0x00004000 + +#define NORMAL_GORE_RATE 10000 + +/* Wounding flags */ +#define section_flag_left_arm 0x00010000 +#define section_flag_right_arm 0x00020000 +#define section_flag_left_leg 0x00040000 +#define section_flag_right_leg 0x00080000 +#define section_flag_left_foot 0x00100000 +#define section_flag_right_foot 0x00200000 +#define section_flag_left_hand 0x00400000 +#define section_flag_right_hand 0x00800000 +#define section_flag_head 0x01000000 +#define section_flag_tail 0x02000000 + +/* Multipart flags */ +#define section_flags_wounding (section_flag_left_arm|section_flag_right_arm|section_flag_left_leg|section_flag_right_leg\ + |section_flag_left_foot|section_flag_right_foot|section_flag_left_hand|section_flag_right_hand|section_flag_head\ + |section_flag_tail|section_has_sparkoflife) +#define section_sprays_anything (section_sprays_blood|section_sprays_acid|section_sprays_predoblood|section_sprays_sparks) + +typedef struct section_data { + int ShapeNum; /* Just in case */ + SHAPEHEADER *Shape; + + VECTORCH Offset; + VECTORCH World_Offset; + VECTORCH Last_World_Offset; + VECTORCH View_Offset; + MATRIXCH RelSecMat; + MATRIXCH SecMat; + + struct damageblock current_damage; + struct hmodelcontroller *my_controller; + SHAPEANIMATIONCONTROLLER *sac_ptr; + TXACTRLBLK *tac_ptr; + SECTION *sempai; + + SEQUENCE *current_sequence; + KEYFRAME_DATA *current_keyframe; + int accumulated_timer; + int freezeframe_timer; + int lastframe_timer; + int gore_timer; + + int flags; + + struct section_data *First_Child; + struct section_data *Prev_Sibling; + struct section_data *My_Parent; + struct section_data *Next_Sibling; + + /* KJL 16:56:51 31/07/98 - decal support */ + OBJECT_DECAL Decals[MAX_NO_OF_DECALS_PER_HIERARCHICAL_SECTION]; + int NumberOfDecals; + int NextDecalToUse; + + /*For remembering the alternate shape sets*/ + int replacement_id; + + /* Tweening */ + VECTORCH stored_offset; + VECTORCH target_offset; + VECTORCH delta_offset; + QUAT stored_quat; + QUAT target_quat; + int omega; + int oneoversinomega; + int oneovertweeninglength; + unsigned int Tweening:1; + +} SECTION_DATA; + + +#define section_data_master_root 0x00000001 +#define section_data_false_root 0x00000002 +#define section_data_notreal 0x00000004 +#define section_data_terminate_here 0x00000008 +#define section_data_view_init 0x40000000 +#define section_data_initialised 0x80000000 + +typedef struct delta_controller { + char *id; + int timer; + int lastframe_timer; + int sequence_type; + int sub_sequence; + int seconds_for_sequence; + int timer_increment; + int Looped:1; + int Playing:1; + int Active:1; + struct delta_controller *next_controller; + struct hmodelcontroller *my_hmodel_controller; +} DELTA_CONTROLLER; + +typedef struct hmodelcontroller { + + int Seconds_For_Sequence; + int timer_increment; + int Sequence_Type; + int Sub_Sequence; + int sequence_timer; + int FrameStamp; + int View_FrameStamp; + VECTORCH Computed_Position; + /* For keeping track of the state of the viewspace coords. */ + int keyframe_flags; + + DELTA_CONTROLLER *Deltas; + + SECTION *Root_Section; + SECTION_DATA *section_data; + + int After_Tweening_Sequence_Type; + int After_Tweening_Sub_Sequence; + int AT_seconds_for_sequence; + int AT_sequence_timer; + + unsigned int Playing:1; + unsigned int Reversed:1; + unsigned int Looped:1; + unsigned int Tweening:2; + unsigned int LoopAfterTweening:1; + unsigned int StopAfterTweening:1; + unsigned int ElevationTweening:1; + unsigned int DisableBleeding:1; + unsigned int LockTopSection:1; + unsigned int ZeroRootDisplacement:1; + unsigned int ZeroRootRotation:1; + unsigned int DisableSounds:1; + /* Bear in mind that 'Reversed' carries A LOT + of overhead. In fact, it does it the old way, + looking down the entire frame list each frame. */ + +} HMODELCONTROLLER; + +#define Controller_NoTweening 0 +#define Controller_Tweening 1 +#define Controller_EndTweening 2 + +typedef struct hitlocationtableentry { + char *section_name; + int aspect; + int cprob; +} HITLOCATIONTABLEENTRY; + +#define centre_aspect 0 +#define front_aspect 1 +#define back_aspect 2 + +typedef struct hitlocationtable { + + char *id; + int index; //for loading and saving + HITLOCATIONTABLEENTRY *CentreLocs; + HITLOCATIONTABLEENTRY *TopLocs; + HITLOCATIONTABLEENTRY *BaseLocs; + HITLOCATIONTABLEENTRY *LeftLocs; + HITLOCATIONTABLEENTRY *RightLocs; + HITLOCATIONTABLEENTRY *TopLeftLocs; + HITLOCATIONTABLEENTRY *TopRightLocs; + HITLOCATIONTABLEENTRY *BaseLeftLocs; + HITLOCATIONTABLEENTRY *BaseRightLocs; + +} HITLOCATIONTABLE; + +extern SECTION_ATTACHMENT Global_Section_Attachments[]; +extern SECTION_ATTACHMENT Default_Stats; + +struct strategyblock; + +extern void Preprocess_HModel(SECTION *root,char *riffname); +extern void Create_HModel(HMODELCONTROLLER *controller,SECTION *root); +extern void InitHModelSequence(HMODELCONTROLLER *controller, int sequence_type, int subsequence, int seconds_for_sequence); +extern void DoHModel(HMODELCONTROLLER *controller, struct displayblock *dptr); +extern void DoHModelTimer(HMODELCONTROLLER *controller); +extern void ProveHModel(HMODELCONTROLLER *controller, struct displayblock *dptr); +extern void ProveHModel_Far(HMODELCONTROLLER *controller, struct strategyblock *sbPtr); +extern void Dispel_HModel(HMODELCONTROLLER *controller); +extern int Prune_HModel_Virtual(SECTION_DATA *top_section); +extern void Correlate_HModel_Instances(SECTION_DATA *victim,SECTION_DATA *templat); +extern int GetSequenceID(int sequence_type,int sub_sequence); +extern SEQUENCE *GetSequencePointer(int sequence_type,int sub_sequence,SECTION *this_section); +extern SECTION_ATTACHMENT *GetThisSectionAttachment(char *riffname,char *section_name,char *hierarchy_name); +extern void Extreme_Gibbing(struct strategyblock *sbPtr,SECTION_DATA *this_section_data, int probability); +extern int Splice_HModels(HMODELCONTROLLER *new_controller,SECTION_DATA *top_section_data); +extern void HModel_ChangeSpeed(HMODELCONTROLLER *controller, int seconds_for_sequence); +extern SECTION_DATA *GetThisSectionData(SECTION_DATA *root,char *name); +extern SECTION *GetThisSection(SECTION *root,char *name); +extern void InitHModelTweening(HMODELCONTROLLER *controller, int seconds_for_tweening, int target_sequence_type, int target_subsequence, int target_seconds_for_sequence, int loop); +extern void InitHModelTweening_Backwards(HMODELCONTROLLER *controller, int seconds_for_tweening, int target_sequence_type, int target_subsequence, int target_seconds_for_sequence, int loop); +extern void InitHModelTweening_ToTheMiddle(HMODELCONTROLLER *controller, int seconds_for_tweening,int target_sequence_type, int target_subsequence, int target_seconds_for_sequence, int target_sequence_timer, int loop); +extern DELTA_CONTROLLER *Add_Delta_Sequence(HMODELCONTROLLER *controller,char *id,int sequence_type,int sub_sequence, int seconds_for_sequence); +extern DELTA_CONTROLLER *Get_Delta_Sequence(HMODELCONTROLLER *controller,char *id); +extern void Remove_Delta_Sequence(HMODELCONTROLLER *controller,char *id); +extern void Transmogrify_HModels(struct strategyblock *sbPtr,HMODELCONTROLLER *controller,SECTION *new_template, int frag, int newsections, int regrowsections); +extern void TrimToTemplate(struct strategyblock *sbPtr,HMODELCONTROLLER *controller,SECTION *new_template, int frag); +extern void Start_Delta_Sequence(DELTA_CONTROLLER *delta_controller,int sequence_type,int sub_sequence,int seconds_for_sequence); +extern void Delta_Sequence_ChangeSpeed(DELTA_CONTROLLER *delta_controller,int seconds_for_sequence); +extern int HModelSequence_Exists(HMODELCONTROLLER *controller,int sequence_type,int sub_sequence); +extern int HModelSequence_Exists_FromRoot(SECTION *root,int sequence_type,int sub_sequence); +extern void RemoveAllDeltas(HMODELCONTROLLER *controller); +extern void KillRandomSections(SECTION_DATA *this_section_data, int probability); +extern void HModel_Regen(HMODELCONTROLLER *controller,int time); +extern int HModelAnimation_IsFinished(HMODELCONTROLLER *controller); +extern int DeltaAnimation_IsFinished(DELTA_CONTROLLER *controller); +extern SECTION_DATA *PointInHModel(HMODELCONTROLLER *controller,VECTORCH *point); +extern SECTION *Get_Corresponding_Section_Recursive(SECTION *this_section,char *Name); +extern SECTION_DATA *GetThisSectionData_FromID(SECTION_DATA *root,int IDnumber); +extern void PlayHierarchySound(HIERARCHY_SOUND* sound,VECTORCH* location); +extern void HModel_SetToolsRelativeSpeed(HMODELCONTROLLER *controller, int factor); +extern void Setup_Texture_Animation_For_Section(SECTION_DATA *this_section_data); +extern void Verify_Positions_In_HModel(struct strategyblock *sbPtr,HMODELCONTROLLER *controller,char *callCode); +extern int HModel_DepthTest(HMODELCONTROLLER *controller,SECTION_DATA *test_section_data,int depth); +extern void DeInitialise_HModel(HMODELCONTROLLER *controller); + + +extern void LoadHierarchy(struct save_block_header* header,HMODELCONTROLLER* controller); +extern void SaveHierarchy(HMODELCONTROLLER* controller); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/3dc/avp/langenum.h b/3dc/avp/langenum.h new file mode 100644 index 0000000..28832ae --- /dev/null +++ b/3dc/avp/langenum.h @@ -0,0 +1,1368 @@ +#ifndef _langenum_h_ +#define _langenum_h_ 1 +/* KJL 17:05:36 05/01/97 + * + * Enum for text output. Warning: any changes to this file may be lost as + * the enums are updated by a utility which rewrites the entire file. + */ + +enum TEXTSTRING_ID +{ + TEXTSTRING_BLANK=0, + TEXTSTRING_LEVELMSG_001, + TEXTSTRING_LEVELMSG_002, + TEXTSTRING_LEVELMSG_003, + TEXTSTRING_LEVELMSG_004, + TEXTSTRING_LEVELMSG_005, + TEXTSTRING_LEVELMSG_006, + TEXTSTRING_LEVELMSG_007, + TEXTSTRING_LEVELMSG_008, + TEXTSTRING_LEVELMSG_009, + TEXTSTRING_LEVELMSG_010, + TEXTSTRING_LEVELMSG_011, + TEXTSTRING_LEVELMSG_012, + TEXTSTRING_LEVELMSG_013, + TEXTSTRING_LEVELMSG_014, + TEXTSTRING_LEVELMSG_015, + TEXTSTRING_LEVELMSG_016, + TEXTSTRING_LEVELMSG_017, + TEXTSTRING_LEVELMSG_018, + TEXTSTRING_LEVELMSG_019, + TEXTSTRING_LEVELMSG_020, + TEXTSTRING_LEVELMSG_021, + TEXTSTRING_LEVELMSG_022, + TEXTSTRING_LEVELMSG_023, + TEXTSTRING_LEVELMSG_024, + TEXTSTRING_LEVELMSG_025, + TEXTSTRING_LEVELMSG_026, + TEXTSTRING_LEVELMSG_027, + TEXTSTRING_LEVELMSG_028, + TEXTSTRING_LEVELMSG_029, + TEXTSTRING_LEVELMSG_030, + TEXTSTRING_LEVELMSG_031, + TEXTSTRING_LEVELMSG_032, + TEXTSTRING_LEVELMSG_033, + TEXTSTRING_LEVELMSG_034, + TEXTSTRING_LEVELMSG_035, + TEXTSTRING_LEVELMSG_036, + TEXTSTRING_LEVELMSG_037, + TEXTSTRING_LEVELMSG_038, + TEXTSTRING_LEVELMSG_039, + TEXTSTRING_LEVELMSG_040, + TEXTSTRING_LEVELMSG_041, + TEXTSTRING_LEVELMSG_042, + TEXTSTRING_LEVELMSG_043, + TEXTSTRING_LEVELMSG_044, + TEXTSTRING_LEVELMSG_045, + TEXTSTRING_LEVELMSG_046, + TEXTSTRING_LEVELMSG_047, + TEXTSTRING_LEVELMSG_048, + TEXTSTRING_LEVELMSG_049, + TEXTSTRING_LEVELMSG_050, + TEXTSTRING_LEVELMSG_051, + TEXTSTRING_LEVELMSG_052, + TEXTSTRING_LEVELMSG_053, + TEXTSTRING_LEVELMSG_054, + TEXTSTRING_LEVELMSG_055, + TEXTSTRING_LEVELMSG_056, + TEXTSTRING_LEVELMSG_057, + TEXTSTRING_LEVELMSG_058, + TEXTSTRING_LEVELMSG_059, + TEXTSTRING_LEVELMSG_060, + TEXTSTRING_LEVELMSG_061, + TEXTSTRING_LEVELMSG_062, + TEXTSTRING_LEVELMSG_063, + TEXTSTRING_LEVELMSG_064, + TEXTSTRING_LEVELMSG_065, + TEXTSTRING_LEVELMSG_066, + TEXTSTRING_LEVELMSG_067, + TEXTSTRING_LEVELMSG_068, + TEXTSTRING_LEVELMSG_069, + TEXTSTRING_LEVELMSG_070, + TEXTSTRING_LEVELMSG_071, + TEXTSTRING_LEVELMSG_072, + TEXTSTRING_LEVELMSG_073, + TEXTSTRING_LEVELMSG_074, + TEXTSTRING_LEVELMSG_075, + TEXTSTRING_LEVELMSG_076, + TEXTSTRING_LEVELMSG_077, + TEXTSTRING_LEVELMSG_078, + TEXTSTRING_LEVELMSG_079, + TEXTSTRING_LEVELMSG_080, + TEXTSTRING_LEVELMSG_081, + TEXTSTRING_LEVELMSG_082, + TEXTSTRING_LEVELMSG_083, + TEXTSTRING_LEVELMSG_084, + TEXTSTRING_LEVELMSG_085, + TEXTSTRING_LEVELMSG_086, + TEXTSTRING_LEVELMSG_087, + TEXTSTRING_LEVELMSG_088, + TEXTSTRING_LEVELMSG_089, + TEXTSTRING_LEVELMSG_090, + TEXTSTRING_LEVELMSG_091, + TEXTSTRING_LEVELMSG_092, + TEXTSTRING_LEVELMSG_093, + TEXTSTRING_LEVELMSG_094, + TEXTSTRING_LEVELMSG_095, + TEXTSTRING_LEVELMSG_096, + TEXTSTRING_LEVELMSG_097, + TEXTSTRING_LEVELMSG_098, + TEXTSTRING_LEVELMSG_099, + TEXTSTRING_LEVELMSG_100, + TEXTSTRING_LEVELMSG_101, + TEXTSTRING_LEVELMSG_102, + TEXTSTRING_LEVELMSG_103, + TEXTSTRING_LEVELMSG_104, + TEXTSTRING_LEVELMSG_105, + TEXTSTRING_LEVELMSG_106, + TEXTSTRING_LEVELMSG_107, + TEXTSTRING_LEVELMSG_108, + TEXTSTRING_LEVELMSG_109, + TEXTSTRING_LEVELMSG_110, + TEXTSTRING_LEVELMSG_111, + TEXTSTRING_LEVELMSG_112, + TEXTSTRING_LEVELMSG_113, + TEXTSTRING_LEVELMSG_114, + TEXTSTRING_LEVELMSG_115, + TEXTSTRING_LEVELMSG_116, + TEXTSTRING_LEVELMSG_117, + TEXTSTRING_LEVELMSG_118, + TEXTSTRING_LEVELMSG_119, + TEXTSTRING_LEVELMSG_120, + TEXTSTRING_LEVELMSG_121, + TEXTSTRING_LEVELMSG_122, + TEXTSTRING_LEVELMSG_123, + TEXTSTRING_LEVELMSG_124, + TEXTSTRING_LEVELMSG_125, + TEXTSTRING_LEVELMSG_126, + TEXTSTRING_LEVELMSG_127, + TEXTSTRING_LEVELMSG_128, + TEXTSTRING_LEVELMSG_129, + TEXTSTRING_LEVELMSG_130, + TEXTSTRING_LEVELMSG_131, + TEXTSTRING_LEVELMSG_132, + TEXTSTRING_LEVELMSG_133, + TEXTSTRING_LEVELMSG_134, + TEXTSTRING_LEVELMSG_135, + TEXTSTRING_LEVELMSG_136, + TEXTSTRING_LEVELMSG_137, + TEXTSTRING_LEVELMSG_138, + TEXTSTRING_LEVELMSG_139, + TEXTSTRING_LEVELMSG_140, + TEXTSTRING_LEVELMSG_141, + TEXTSTRING_LEVELMSG_142, + TEXTSTRING_LEVELMSG_143, + TEXTSTRING_LEVELMSG_144, + TEXTSTRING_LEVELMSG_145, + TEXTSTRING_LEVELMSG_146, + TEXTSTRING_LEVELMSG_147, + TEXTSTRING_LEVELMSG_148, + TEXTSTRING_LEVELMSG_149, + TEXTSTRING_LEVELMSG_150, + TEXTSTRING_LEVELMSG_151, + TEXTSTRING_LEVELMSG_152, + TEXTSTRING_LEVELMSG_153, + TEXTSTRING_LEVELMSG_154, + TEXTSTRING_LEVELMSG_155, + TEXTSTRING_LEVELMSG_156, + TEXTSTRING_LEVELMSG_157, + TEXTSTRING_LEVELMSG_158, + TEXTSTRING_LEVELMSG_159, + TEXTSTRING_LEVELMSG_160, + TEXTSTRING_LEVELMSG_161, + TEXTSTRING_LEVELMSG_162, + TEXTSTRING_LEVELMSG_163, + TEXTSTRING_LEVELMSG_164, + TEXTSTRING_LEVELMSG_165, + TEXTSTRING_LEVELMSG_166, + TEXTSTRING_LEVELMSG_167, + TEXTSTRING_LEVELMSG_168, + TEXTSTRING_LEVELMSG_169, + TEXTSTRING_LEVELMSG_170, + TEXTSTRING_LEVELMSG_171, + TEXTSTRING_LEVELMSG_172, + TEXTSTRING_LEVELMSG_173, + TEXTSTRING_LEVELMSG_174, + TEXTSTRING_LEVELMSG_175, + TEXTSTRING_LEVELMSG_176, + TEXTSTRING_LEVELMSG_177, + TEXTSTRING_LEVELMSG_178, + TEXTSTRING_LEVELMSG_179, + TEXTSTRING_LEVELMSG_180, + TEXTSTRING_LEVELMSG_181, + TEXTSTRING_LEVELMSG_182, + TEXTSTRING_LEVELMSG_183, + TEXTSTRING_LEVELMSG_184, + TEXTSTRING_LEVELMSG_185, + TEXTSTRING_LEVELMSG_186, + TEXTSTRING_LEVELMSG_187, + TEXTSTRING_LEVELMSG_188, + TEXTSTRING_LEVELMSG_189, + TEXTSTRING_LEVELMSG_190, + TEXTSTRING_LEVELMSG_191, + TEXTSTRING_LEVELMSG_192, + TEXTSTRING_LEVELMSG_193, + TEXTSTRING_LEVELMSG_194, + TEXTSTRING_LEVELMSG_195, + TEXTSTRING_LEVELMSG_196, + TEXTSTRING_LEVELMSG_197, + TEXTSTRING_LEVELMSG_198, + TEXTSTRING_LEVELMSG_199, + TEXTSTRING_LEVELMSG_200, + TEXTSTRING_LEVELMSG_201, + TEXTSTRING_LEVELMSG_202, + TEXTSTRING_LEVELMSG_203, + TEXTSTRING_LEVELMSG_204, + TEXTSTRING_LEVELMSG_205, + TEXTSTRING_LEVELMSG_206, + TEXTSTRING_LEVELMSG_207, + TEXTSTRING_LEVELMSG_208, + TEXTSTRING_LEVELMSG_209, + TEXTSTRING_LEVELMSG_210, + TEXTSTRING_LEVELMSG_211, + TEXTSTRING_LEVELMSG_212, + TEXTSTRING_LEVELMSG_213, + TEXTSTRING_LEVELMSG_214, + TEXTSTRING_LEVELMSG_215, + TEXTSTRING_LEVELMSG_216, + TEXTSTRING_LEVELMSG_217, + TEXTSTRING_LEVELMSG_218, + TEXTSTRING_LEVELMSG_219, + TEXTSTRING_LEVELMSG_220, + TEXTSTRING_LEVELMSG_221, + TEXTSTRING_LEVELMSG_222, + TEXTSTRING_LEVELMSG_223, + TEXTSTRING_LEVELMSG_224, + TEXTSTRING_LEVELMSG_225, + TEXTSTRING_LEVELMSG_226, + TEXTSTRING_LEVELMSG_227, + TEXTSTRING_LEVELMSG_228, + TEXTSTRING_LEVELMSG_229, + TEXTSTRING_LEVELMSG_230, + TEXTSTRING_LEVELMSG_231, + TEXTSTRING_LEVELMSG_232, + TEXTSTRING_LEVELMSG_233, + TEXTSTRING_LEVELMSG_234, + TEXTSTRING_LEVELMSG_235, + TEXTSTRING_LEVELMSG_236, + TEXTSTRING_LEVELMSG_237, + TEXTSTRING_LEVELMSG_238, + TEXTSTRING_LEVELMSG_239, + TEXTSTRING_LEVELMSG_240, + TEXTSTRING_LEVELMSG_241, + TEXTSTRING_LEVELMSG_242, + TEXTSTRING_LEVELMSG_243, + TEXTSTRING_LEVELMSG_244, + TEXTSTRING_LEVELMSG_245, + TEXTSTRING_LEVELMSG_246, + TEXTSTRING_LEVELMSG_247, + TEXTSTRING_LEVELMSG_248, + TEXTSTRING_LEVELMSG_249, + TEXTSTRING_LEVELMSG_250, + TEXTSTRING_LEVELMSG_251, + TEXTSTRING_LEVELMSG_252, + TEXTSTRING_LEVELMSG_253, + TEXTSTRING_LEVELMSG_254, + TEXTSTRING_LEVELMSG_255, + TEXTSTRING_LEVELMSG_256, + TEXTSTRING_LEVELMSG_257, + TEXTSTRING_LEVELMSG_258, + TEXTSTRING_LEVELMSG_259, + TEXTSTRING_LEVELMSG_260, + TEXTSTRING_LEVELMSG_261, + TEXTSTRING_LEVELMSG_262, + TEXTSTRING_LEVELMSG_263, + TEXTSTRING_LEVELMSG_264, + TEXTSTRING_LEVELMSG_265, + TEXTSTRING_LEVELMSG_266, + TEXTSTRING_LEVELMSG_267, + TEXTSTRING_LEVELMSG_268, + TEXTSTRING_LEVELMSG_269, + TEXTSTRING_LEVELMSG_270, + TEXTSTRING_LEVELMSG_271, + TEXTSTRING_LEVELMSG_272, + TEXTSTRING_LEVELMSG_273, + TEXTSTRING_LEVELMSG_274, + TEXTSTRING_LEVELMSG_275, + TEXTSTRING_LEVELMSG_276, + TEXTSTRING_LEVELMSG_277, + TEXTSTRING_LEVELMSG_278, + TEXTSTRING_LEVELMSG_279, + TEXTSTRING_LEVELMSG_280, + TEXTSTRING_LEVELMSG_281, + TEXTSTRING_LEVELMSG_282, + TEXTSTRING_LEVELMSG_283, + TEXTSTRING_LEVELMSG_284, + TEXTSTRING_LEVELMSG_285, + TEXTSTRING_LEVELMSG_286, + TEXTSTRING_LEVELMSG_287, + TEXTSTRING_LEVELMSG_288, + TEXTSTRING_LEVELMSG_289, + TEXTSTRING_LEVELMSG_290, + TEXTSTRING_LEVELMSG_291, + TEXTSTRING_LEVELMSG_292, + TEXTSTRING_LEVELMSG_293, + TEXTSTRING_LEVELMSG_294, + TEXTSTRING_LEVELMSG_295, + TEXTSTRING_LEVELMSG_296, + TEXTSTRING_LEVELMSG_297, + TEXTSTRING_LEVELMSG_298, + TEXTSTRING_LEVELMSG_299, + TEXTSTRING_LEVELMSG_300, + TEXTSTRING_LEVELMSG_301, + TEXTSTRING_LEVELMSG_302, + TEXTSTRING_LEVELMSG_303, + TEXTSTRING_LEVELMSG_304, + TEXTSTRING_LEVELMSG_305, + TEXTSTRING_LEVELMSG_306, + TEXTSTRING_LEVELMSG_307, + TEXTSTRING_LEVELMSG_308, + TEXTSTRING_LEVELMSG_309, + TEXTSTRING_LEVELMSG_310, + TEXTSTRING_LEVELMSG_311, + TEXTSTRING_LEVELMSG_312, + TEXTSTRING_LEVELMSG_313, + TEXTSTRING_LEVELMSG_314, + TEXTSTRING_LEVELMSG_315, + TEXTSTRING_LEVELMSG_316, + TEXTSTRING_LEVELMSG_317, + TEXTSTRING_LEVELMSG_318, + TEXTSTRING_LEVELMSG_319, + TEXTSTRING_LEVELMSG_320, + TEXTSTRING_LEVELMSG_321, + TEXTSTRING_LEVELMSG_322, + TEXTSTRING_LEVELMSG_323, + TEXTSTRING_LEVELMSG_324, + TEXTSTRING_LEVELMSG_325, + TEXTSTRING_LEVELMSG_326, + TEXTSTRING_LEVELMSG_327, + TEXTSTRING_LEVELMSG_328, + TEXTSTRING_LEVELMSG_329, + TEXTSTRING_LEVELMSG_330, + TEXTSTRING_LEVELMSG_331, + TEXTSTRING_LEVELMSG_332, + TEXTSTRING_LEVELMSG_333, + TEXTSTRING_LEVELMSG_334, + TEXTSTRING_LEVELMSG_335, + TEXTSTRING_LEVELMSG_336, + TEXTSTRING_LEVELMSG_337, + TEXTSTRING_LEVELMSG_338, + TEXTSTRING_LEVELMSG_339, + TEXTSTRING_LEVELMSG_340, + TEXTSTRING_LEVELMSG_341, + TEXTSTRING_LEVELMSG_342, + TEXTSTRING_LEVELMSG_343, + TEXTSTRING_LEVELMSG_344, + TEXTSTRING_LEVELMSG_345, + TEXTSTRING_LEVELMSG_346, + TEXTSTRING_LEVELMSG_347, + TEXTSTRING_LEVELMSG_348, + TEXTSTRING_LEVELMSG_349, + TEXTSTRING_LEVELMSG_350, + TEXTSTRING_LEVELMSG_351, + TEXTSTRING_LEVELMSG_352, + TEXTSTRING_LEVELMSG_353, + TEXTSTRING_LEVELMSG_354, + TEXTSTRING_LEVELMSG_355, + TEXTSTRING_LEVELMSG_356, + TEXTSTRING_LEVELMSG_357, + TEXTSTRING_LEVELMSG_358, + TEXTSTRING_LEVELMSG_359, + TEXTSTRING_LEVELMSG_360, + TEXTSTRING_LEVELMSG_361, + TEXTSTRING_LEVELMSG_362, + TEXTSTRING_LEVELMSG_363, + TEXTSTRING_LEVELMSG_364, + TEXTSTRING_LEVELMSG_365, + TEXTSTRING_LEVELMSG_366, + TEXTSTRING_LEVELMSG_367, + TEXTSTRING_LEVELMSG_368, + TEXTSTRING_LEVELMSG_369, + TEXTSTRING_LEVELMSG_370, + TEXTSTRING_LEVELMSG_371, + TEXTSTRING_LEVELMSG_372, + TEXTSTRING_LEVELMSG_373, + TEXTSTRING_LEVELMSG_374, + TEXTSTRING_LEVELMSG_375, + TEXTSTRING_LEVELMSG_376, + TEXTSTRING_LEVELMSG_377, + TEXTSTRING_LEVELMSG_378, + TEXTSTRING_LEVELMSG_379, + TEXTSTRING_LEVELMSG_380, + TEXTSTRING_LEVELMSG_381, + TEXTSTRING_LEVELMSG_382, + TEXTSTRING_LEVELMSG_383, + TEXTSTRING_LEVELMSG_384, + TEXTSTRING_LEVELMSG_385, + TEXTSTRING_LEVELMSG_386, + TEXTSTRING_LEVELMSG_387, + TEXTSTRING_LEVELMSG_388, + TEXTSTRING_LEVELMSG_389, + TEXTSTRING_LEVELMSG_390, + TEXTSTRING_LEVELMSG_391, + TEXTSTRING_LEVELMSG_392, + TEXTSTRING_LEVELMSG_393, + TEXTSTRING_LEVELMSG_394, + TEXTSTRING_LEVELMSG_395, + TEXTSTRING_LEVELMSG_396, + TEXTSTRING_LEVELMSG_397, + TEXTSTRING_LEVELMSG_398, + TEXTSTRING_LEVELMSG_399, + TEXTSTRING_LEVELMSG_400, + TEXTSTRING_LEVELMSG_401, + TEXTSTRING_LEVELMSG_402, + TEXTSTRING_LEVELMSG_403, + TEXTSTRING_LEVELMSG_404, + TEXTSTRING_LEVELMSG_405, + TEXTSTRING_LEVELMSG_406, + TEXTSTRING_LEVELMSG_407, + TEXTSTRING_LEVELMSG_408, + TEXTSTRING_LEVELMSG_409, + TEXTSTRING_LEVELMSG_410, + TEXTSTRING_LEVELMSG_411, + TEXTSTRING_LEVELMSG_412, + TEXTSTRING_LEVELMSG_413, + TEXTSTRING_LEVELMSG_414, + TEXTSTRING_LEVELMSG_415, + TEXTSTRING_LEVELMSG_416, + TEXTSTRING_LEVELMSG_417, + TEXTSTRING_LEVELMSG_418, + TEXTSTRING_LEVELMSG_419, + TEXTSTRING_LEVELMSG_420, + TEXTSTRING_LEVELMSG_421, + TEXTSTRING_LEVELMSG_422, + TEXTSTRING_LEVELMSG_423, + TEXTSTRING_LEVELMSG_424, + TEXTSTRING_LEVELMSG_425, + TEXTSTRING_LEVELMSG_426, + TEXTSTRING_LEVELMSG_427, + TEXTSTRING_LEVELMSG_428, + TEXTSTRING_LEVELMSG_429, + TEXTSTRING_LEVELMSG_430, + TEXTSTRING_LEVELMSG_431, + TEXTSTRING_LEVELMSG_432, + TEXTSTRING_LEVELMSG_433, + TEXTSTRING_LEVELMSG_434, + TEXTSTRING_LEVELMSG_435, + TEXTSTRING_LEVELMSG_436, + TEXTSTRING_LEVELMSG_437, + TEXTSTRING_LEVELMSG_438, + TEXTSTRING_LEVELMSG_439, + TEXTSTRING_LEVELMSG_440, + TEXTSTRING_LEVELMSG_441, + TEXTSTRING_LEVELMSG_442, + TEXTSTRING_LEVELMSG_443, + TEXTSTRING_LEVELMSG_444, + TEXTSTRING_LEVELMSG_445, + TEXTSTRING_LEVELMSG_446, + TEXTSTRING_LEVELMSG_447, + TEXTSTRING_LEVELMSG_448, + TEXTSTRING_LEVELMSG_449, + TEXTSTRING_LEVELMSG_450, + TEXTSTRING_MAINMENU_TITLE, + TEXTSTRING_MAINMENU_STARTSINGLEPLAYER, + TEXTSTRING_MAINMENU_STARTSINGLEPLAYER_HELP, + TEXTSTRING_MAINMENU_SINGLEPLAYER_ALIEN, + TEXTSTRING_MAINMENU_SINGLEPLAYER_MARINE, + TEXTSTRING_MAINMENU_SINGLEPLAYER_PREDATOR, + TEXTSTRING_MAINMENU_MULTIPLAYER, + TEXTSTRING_MAINMENU_MULTIPLAYER_HELP, + TEXTSTRING_MAINMENU_SKIRMISH, + TEXTSTRING_MAINMENU_SKIRMISH_HELP, + TEXTSTRING_MAINMENU_GAMEPLAYOPTIONS, + TEXTSTRING_MAINMENU_GAMEPLAYOPTIONS_HELP, + TEXTSTRING_MAINMENU_CHANGEUSERPROFILE, + TEXTSTRING_MAINMENU_CHANGEUSERPROFILE_HELP, + TEXTSTRING_MAINMENU_CHEATOPTIONS, + TEXTSTRING_MAINMENU_CHEATOPTIONS_HELP, + TEXTSTRING_MAINMENU_CHEATMODE, + TEXTSTRING_CHEATOPTIONS_1, + TEXTSTRING_CHEATOPTIONS_2, + TEXTSTRING_CHEATOPTIONS_3, + TEXTSTRING_CHEATOPTIONS_4, + TEXTSTRING_CHEATOPTIONS_5, + TEXTSTRING_CHEATOPTIONS_6, + TEXTSTRING_CHEATOPTIONS_7, + TEXTSTRING_CHEATOPTIONS_8, + TEXTSTRING_CHEATOPTIONS_9, + TEXTSTRING_CHEATOPTIONS_10, + TEXTSTRING_CHEATOPTIONS_11, + TEXTSTRING_CHEATOPTIONS_12, + TEXTSTRING_CHEATOPTIONS_13, + TEXTSTRING_CHEATOPTIONS_14, + TEXTSTRING_CHEATOPTIONS_15, + TEXTSTRING_CHEATOPTIONS_16, + TEXTSTRING_CHEATOPTIONS_17, + TEXTSTRING_CHEATOPTIONS_18, + TEXTSTRING_CHEATOPTIONS_19, + TEXTSTRING_CHEATOPTIONS_20, + TEXTSTRING_CHEATOPTIONS_21, + TEXTSTRING_CHEATOPTIONS_CHEATMODE_HELP, + TEXTSTRING_CHEATOPTIONS_SPECIES_HELP, + TEXTSTRING_CHEATOPTIONS_ENVIRONMENT_HELP, + TEXTSTRING_VIDEOOPTIONS_TITLE, + TEXTSTRING_VIDEOOPTIONS_TITLE_HELP, + TEXTSTRING_AVOPTIONS_TITLE, + TEXTSTRING_AVOPTIONS_TITLE_HELP, + TEXTSTRING_AVOPTIONS_MUSICVOLUME, + TEXTSTRING_AVOPTIONS_MUSICVOLUME_HELP, + TEXTSTRING_AVOPTIONS_EFFECTSVOLUME, + TEXTSTRING_AVOPTIONS_EFFECTSVOLUME_HELP, + TEXTSTRING_AVOPTIONS_INGAMEMOVIES, + TEXTSTRING_AVOPTIONS_INGAMEMOVIES_HELP, + TEXTSTRING_AVOPTIONS_INTROOUTROMOVIES, + TEXTSTRING_AVOPTIONS_INTROOUTROMOVIES_HELP, + TEXTSTRING_AVOPTIONS_USETHESESETTINGS, + TEXTSTRING_AVOPTIONS_USETHESESETTINGS_HELP, + TEXTSTRING_AVOPTIONS_GAMMASETTING, + TEXTSTRING_AVOPTIONS_GAMMASETTING_HELP, + TEXTSTRING_MAINMENU_EXITGAME, + TEXTSTRING_MAINMENU_EXITGAME_HELP, + TEXTSTRING_USERPROFILE_SELECT, + TEXTSTRING_USERPROFILE_NEW, + TEXTSTRING_USERPROFILE_ENTERNAME, + TEXTSTRING_USERPROFILE_HELP, + TEXTSTRING_USERPROFILE_DELETE, + TEXTSTRING_USERPROFILE_DELETE_HELP, + TEXTSTRING_USERPROFILE_ENTERINGNAME_HELP, + TEXTSTRING_USERPROFILE_USETHISNAME_HELP, + TEXTSTRING_EXITGAME_TITLE, + TEXTSTRING_LEVELSELECT_TITLE, + TEXTSTRING_LEVELSELECT_START, + TEXTSTRING_LEVELSELECT_START_HELP, + TEXTSTRING_MULTIPLAYER_START2_HELP, + TEXTSTRING_MULTIPLAYER_STARTGAME, + TEXTSTRING_MULTIPLAYER_STARTGAME_HELP, + TEXTSTRING_MULTIPLAYER_JOINGAME, + TEXTSTRING_MULTIPLAYER_JOINGAME_HELP, + TEXTSTRING_MULTIPLAYER_CONTINUE, + TEXTSTRING_MULTIPLAYER_CONTINUETOCONFIG_HELP, + TEXTSTRING_MULTIPLAYER_SPECIES, + TEXTSTRING_MULTIPLAYER_SPECIES_HELP, + TEXTSTRING_MULTIPLAYER_MARINE, + TEXTSTRING_MULTIPLAYER_PREDATOR, + TEXTSTRING_MULTIPLAYER_ALIEN, + TEXTSTRING_MULTIPLAYER_MARINE_PULSERIFLE, + TEXTSTRING_MULTIPLAYER_MARINE_SMARTGUN, + TEXTSTRING_MULTIPLAYER_MARINE_FLAMER, + TEXTSTRING_MULTIPLAYER_MARINE_SADAR, + TEXTSTRING_MULTIPLAYER_MARINE_GRENADELAUNCHER, + TEXTSTRING_MULTIPLAYER_MARINE_MINIGUN, + TEXTSTRING_MULTIPLAYER_MARINE_SKEETER, + TEXTSTRING_MULTIPLAYER_MARINE_PISTOLS, + TEXTSTRING_MULTIPLAYER_PLAYERNAME, + TEXTSTRING_MULTIPLAYER_PLAYERNAME_HELP, + TEXTSTRING_MULTIPLAYER_SESSIONNAME, + TEXTSTRING_MULTIPLAYER_FINDLOCAL, + TEXTSTRING_MULTIPLAYER_FINDLOCAL_HELP, + TEXTSTRING_MULTIPLAYER_OPENADDRESS, + TEXTSTRING_MULTIPLAYER_OPENADDRESS_HELP, + TEXTSTRING_MULTIPLAYER_ADDRESS, + TEXTSTRING_MULTIPLAYER_LOADADDRESS, + TEXTSTRING_MULTIPLAYER_LOADADDRESS_HELP, + TEXTSTRING_MULTIPLAYER_TCPIP, + TEXTSTRING_MULTIPLAYER_IPX, + TEXTSTRING_MULTIPLAYER_SERIAL, + TEXTSTRING_MULTIPLAYER_MODEM, + TEXTSTRING_MULTIPLAYER_PROTOCOL_HELP, + TEXTSTRING_MULTIPLAYER_NOCONNECTIONS, + TEXTSTRING_MULTIPLAYER_NOCONNECTIONS_HELP, + TEXTSTRING_MULTIPLAYER_OKTOCONNECT, + TEXTSTRING_MULTIPLAYER_OKTOCONNECT_HELP, + TEXTSTRING_MULTIPLAYER_SELECTSESSION, + TEXTSTRING_MULTIPLAYER_SELECTSESSION_HELP, + TEXTSTRING_MULTIPLAYER_NOSESSIONSFOUND, + TEXTSTRING_MULTIPLAYER_NOSESSIONSFOUND_HELP, + TEXTSTRING_MULTIPLAYER_ENVIRONMENT, + TEXTSTRING_MULTIPLAYER_GAMESTYLE, + TEXTSTRING_MULTIPLAYER_DEATHMATCH, + TEXTSTRING_MULTIPLAYER_DEATHMATCHTEAM, + TEXTSTRING_MULTIPLAYER_LASTMANSTANDING, + TEXTSTRING_MULTIPLAYER_PREDATORTAG, + TEXTSTRING_MULTIPLAYER_COOPERATIVE, + TEXTSTRING_MULTIPLAYER_ALIENTAG, + TEXTSTRING_MULTIPLAYER_MAXALIEN, + TEXTSTRING_MULTIPLAYER_MAXPREDATOR, + TEXTSTRING_MULTIPLAYER_MAXMARINE, + TEXTSTRING_MULTIPLAYER_MAXMARINE_GENERAL, + TEXTSTRING_MULTIPLAYER_MAXMARINE_PULSERIFLE, + TEXTSTRING_MULTIPLAYER_MAXMARINE_SMARTGUN, + TEXTSTRING_MULTIPLAYER_MAXMARINE_FLAMER, + TEXTSTRING_MULTIPLAYER_MAXMARINE_SADAR, + TEXTSTRING_MULTIPLAYER_MAXMARINE_GRENADE, + TEXTSTRING_MULTIPLAYER_MAXMARINE_MINIGUN, + TEXTSTRING_MULTIPLAYER_MAXMARINE_SKEETER, + TEXTSTRING_MULTIPLAYER_MAXMARINE_PISTOLS, + TEXTSTRING_MULTIPLAYER_ALLOW_SMARTGUN, + TEXTSTRING_MULTIPLAYER_ALLOW_FLAMER, + TEXTSTRING_MULTIPLAYER_ALLOW_SADAR, + TEXTSTRING_MULTIPLAYER_ALLOW_GRENADELAUNCHER, + TEXTSTRING_MULTIPLAYER_ALLOW_MINIGUN, + TEXTSTRING_MULTIPLAYER_ALLOW_SKEETER, + TEXTSTRING_MULTIPLAYER_ALLOW_MARINE_PISTOLS, + TEXTSTRING_MULTIPLAYER_ALLOW_DISC, + TEXTSTRING_MULTIPLAYER_ALLOW_PISTOL, + TEXTSTRING_MULTIPLAYER_ALLOW_PLASMACASTER, + TEXTSTRING_MULTIPLAYER_ALLOW_SPEARGUN, + TEXTSTRING_MULTIPLAYER_ALLOW_MEDICOMP, + TEXTSTRING_MULTIPLAYER_DYNAMICSCORING, + TEXTSTRING_MULTIPLAYER_CHARACTERSCORING, + TEXTSTRING_MULTIPLAYER_BASEKILLVALUE, + TEXTSTRING_MULTIPLAYER_ALIENVALUE, + TEXTSTRING_MULTIPLAYER_MARINEVALUE, + TEXTSTRING_MULTIPLAYER_PREDATORVALUE, + TEXTSTRING_MULTIPLAYER_SENDDECALS, + TEXTSTRING_MULTIPLAYER_SCORELIMIT, + TEXTSTRING_MULTIPLAYER_NOSCORELIMIT, + TEXTSTRING_MULTIPLAYER_TIMELIMIT, + TEXTSTRING_MULTIPLAYER_NOTIMELIMIT, + TEXTSTRING_MULTIPLAYER_INVULNTIME, + TEXTSTRING_MULTIPLAYER_LIVES, + TEXTSTRING_MULTIPLAYER_INFINITE, + TEXTSTRING_MULTIPLAYER_SHAREDLIVES, + TEXTSTRING_MULTIPLAYER_RESPAWN_POINTS, + TEXTSTRING_MULTIPLAYER_RESPAWN_POINTS_NO, + TEXTSTRING_MULTIPLAYER_RESPAWN_TIME, + TEXTSTRING_MULTIPLAYER_RESPAWN_TIME_NO, + TEXTSTRING_MULTIPLAYER_GAMESPEED, + TEXTSTRING_MULTIPLAYER_70PERCENT, + TEXTSTRING_MULTIPLAYER_80PERCENT, + TEXTSTRING_MULTIPLAYER_90PERCENT, + TEXTSTRING_MULTIPLAYER_100PERCENT, + TEXTSTRING_MULTIPLAYER_PREDESTROYLIGHTS, + TEXTSTRING_MULTIPLAYER_NOFRIENDLYFIRE, + TEXTSTRING_MULTIPLAYER_FALLINGDAMAGE, + TEXTSTRING_MULTIPLAYER_PISTOLINFINITEAMMO, + TEXTSTRING_MULTIPLAYER_SPECIALISTPISTOLS, + TEXTSTRING_MULTIPLAYER_POINTS, + TEXTSTRING_MULTIPLAYER_SECONDS, + TEXTSTRING_MULTIPLAYER_MINUTES, + TEXTSTRING_MULTIPLAYER_CONFIG, + TEXTSTRING_MULTIPLAYER_SAVECONFIG, + TEXTSTRING_MULTIPLAYER_SAVECONFIG_HELP, + TEXTSTRING_MULTIPLAYER_LOADCONFIG, + TEXTSTRING_MULTIPLAYER_LOADCONFIG_HELP, + TEXTSTRING_MULTIPLAYER_AI_ALIENVALUE, + TEXTSTRING_MULTIPLAYER_AI_PREDALIENVALUE, + TEXTSTRING_MULTIPLAYER_AI_PRAETORIANVALUE, + TEXTSTRING_MULTIPLAYER_SCORE, + TEXTSTRING_MULTIPLAYER_SCOREFOR, + TEXTSTRING_MULTIPLAYER_SCOREAGAINST, + TEXTSTRING_MULTIPLAYER_TIME, + TEXTSTRING_MULTIPLAYER_LIVES_LEFT, + TEXTSTRING_MULTIPLAYER_SPECIESSCORE, + TEXTSTRING_MULTIPLAYER_ALIENS, + TEXTSTRING_MULTIPLAYER_PREDALIENS, + TEXTSTRING_MULTIPLAYER_PRAETORIANS, + TEXTSTRING_MULTIPLAYER_WEAPON_RESPAWN, + TEXTSTRING_MPHELP_SESSIONNAME, + TEXTSTRING_MPHELP_GAMESTYLE_DEATHMATCH, + TEXTSTRING_MPHELP_GAMESTYLE_DEATHMATCHTEAM, + TEXTSTRING_MPHELP_GAMESTYLE_LASTMANSTANDING, + TEXTSTRING_MPHELP_GAMESTYLE_PREDATORTAG, + TEXTSTRING_MPHELP_GAMESTYLE_COOPERATIVE, + TEXTSTRING_MPHELP_GAMESTYLE_ALIENTAG, + TEXTSTRING_MPHELP_ENVIRONMENT, + TEXTSTRING_MPHELP_GAMESPEED, + TEXTSTRING_MPHELP_SCORELIMIT, + TEXTSTRING_MPHELP_TIMELIMIT, + TEXTSTRING_MPHELP_INVULNTIME, + TEXTSTRING_MPHELP_MAXCHARACTER, + TEXTSTRING_MPHELP_MAXSPECIALIST, + TEXTSTRING_MPHELP_ALLOWEAPON, + TEXTSTRING_MPHELP_ALLOWEAPON_PRED, + TEXTSTRING_MPHELP_DYNAMICSCORING, + TEXTSTRING_MPHELP_CHARACTERSCORING, + TEXTSTRING_MPHELP_BASEKILLVALUE, + TEXTSTRING_MPHELP_ALIENVALUE, + TEXTSTRING_MPHELP_MARINEVALUE, + TEXTSTRING_MPHELP_PREDATORVALUE, + TEXTSTRING_MPHELP_AIVALUE, + TEXTSTRING_MPHELP_LIVES, + TEXTSTRING_MPHELP_SHAREDLIVES, + TEXTSTRING_MPHELP_RESPAWN_POINTS, + TEXTSTRING_MPHELP_RESPAWN_TIME, + TEXTSTRING_MPHELP_PREDESTROYLIGHTS, + TEXTSTRING_MPHELP_NOFRIENDLYFIRE, + TEXTSTRING_MPHELP_FALLINGDAMAGE, + TEXTSTRING_MPHELP_PISTOLINFINITEAMMO, + TEXTSTRING_MPHELP_SPECIALISTPISTOLS, + TEXTSTRING_MPHELP_IPADDRESS, + TEXTSTRING_MPHELP_LOADADDRESS, + TEXTSTRING_MPHELP_ADDRESSDESCRIPTION, + TEXTSTRING_MULTIPLAYERCONSOLE_KILLEDBY, + TEXTSTRING_MULTIPLAYERCONSOLE_SUICIDE, + TEXTSTRING_MULTIPLAYERCONSOLE_LEAVEGAME, + TEXTSTRING_MULTIPLAYERCONSOLE_JOINGAME, + TEXTSTRING_MULTIPLAYERCONSOLE_CONNECTGAME, + TEXTSTRING_MULTIPLAYERCONSOLE_NEWHOST, + TEXTSTRING_MULTIPLAYER_PRESSKEYTORESTARTGAME, + TEXTSTRING_MULTIPLAYER_WAITFORRESTARTGAME, + TEXTSTRING_MULTIPLAYERCONSOLE_ALIEN_KILLED, + TEXTSTRING_MULTIPLAYERCONSOLE_PREDALIEN_KILLED, + TEXTSTRING_MULTIPLAYERCONSOLE_PRAETORIAN_KILLED, + TEXTSTRING_MULTIPLAYERCONSOLE_KILLEDBY_ALIEN, + TEXTSTRING_MULTIPLAYERCONSOLE_KILLEDBY_PREDALIEN, + TEXTSTRING_MULTIPLAYERCONSOLE_KILLEDBY_PRAETORIAN, + TEXTSTRING_MULTIPLAYERCONSOLE_PLAYERSEEN, + TEXTSTRING_MULTIPLAYER_LMS_ALLMARINESDEAD, + TEXTSTRING_MULTIPLAYER_LMS_WAITFORHOST, + TEXTSTRING_MULTIPLAYER_LMS_HOSTPRESSOPERATE, + TEXTSTRING_MULTIPLAYER_LMS_GO, + TEXTSTRING_MULTIPLAYER_LMS_LASTMANSTANDING, + TEXTSTRING_MULTIPLAYER_LMS_WILLBEALIEN, + TEXTSTRING_MULTIPLAYERLEVELS_1, + TEXTSTRING_MULTIPLAYERLEVELS_2, + TEXTSTRING_MULTIPLAYERLEVELS_3, + TEXTSTRING_MULTIPLAYERLEVELS_4, + TEXTSTRING_MULTIPLAYERLEVELS_5, + TEXTSTRING_MULTIPLAYERLEVELS_6, + TEXTSTRING_MULTIPLAYERLEVELS_7, + TEXTSTRING_MULTIPLAYERLEVELS_8, + TEXTSTRING_MULTIPLAYERLEVELS_9, + TEXTSTRING_MULTIPLAYERLEVELS_10, + TEXTSTRING_MULTIPLAYERLEVELS_11, + TEXTSTRING_MULTIPLAYERLEVELS_12, + TEXTSTRING_MULTIPLAYERLEVELS_13, + TEXTSTRING_MULTIPLAYERLEVELS_14, + TEXTSTRING_COOPLEVEL_1, + TEXTSTRING_COOPLEVEL_2, + TEXTSTRING_COOPLEVEL_3, + TEXTSTRING_COOPLEVEL_4, + TEXTSTRING_COOPLEVEL_5, + TEXTSTRING_COOPLEVEL_6, + TEXTSTRING_COOPLEVEL_7, + TEXTSTRING_COOPLEVEL_8, + TEXTSTRING_COOPLEVEL_9, + TEXTSTRING_COOPLEVEL_10, + TEXTSTRING_COOPLEVEL_11, + TEXTSTRING_COOPLEVEL_12, + TEXTSTRING_COOPLEVEL_13, + TEXTSTRING_START_MARINE_DEMO, + TEXTSTRING_START_PREDATOR_DEMO, + TEXTSTRING_START_ALIEN_DEMO, + TEXTSTRING_START_DEATHMATCH_DEMO, + TEXTSTRING_MOUSECONTROLS_TITLE, + TEXTSTRING_MOUSECONTROLS_TITLE_HELP, + TEXTSTRING_MOUSECONTROLS_XSENSITIVITY, + TEXTSTRING_MOUSECONTROLS_XSENSITIVITY_HELP, + TEXTSTRING_MOUSECONTROLS_YSENSITIVITY, + TEXTSTRING_MOUSECONTROLS_YSENSITIVITY_HELP, + TEXTSTRING_MOUSECONTROLS_VERTICAL_AXIS, + TEXTSTRING_MOUSECONTROLS_VERTICAL_AXIS_HELP, + TEXTSTRING_MOUSECONTROLS_HORIZONTAL_AXIS, + TEXTSTRING_MOUSECONTROLS_HORIZONTAL_AXIS_HELP, + TEXTSTRING_MOUSECONTROLS_LOOKING, + TEXTSTRING_MOUSECONTROLS_MOVEMENT, + TEXTSTRING_MOUSECONTROLS_SIDESTEPPING, + TEXTSTRING_MOUSECONTROLS_TURNING, + TEXTSTRING_MOUSECONTROLS_INVERTVERTICAL, + TEXTSTRING_MOUSECONTROLS_INVERTVERTICAL_HELP, + TEXTSTRING_JOYSTICKCONTROLS_INVERTVERTICAL_HELP, + TEXTSTRING_MOUSECONTROLS_AUTOCENTRE, + TEXTSTRING_MOUSECONTROLS_AUTOCENTRE_HELP, + TEXTSTRING_MOUSECONTROLS_SAVETHESESETTINGS, + TEXTSTRING_MOUSECONTROLS_SAVETHESESETTINGS_HELP, + TEXTSTRING_CONTROLS_RESETTODEFAULT, + TEXTSTRING_CONTROLS_RESETTODEFAULT_HELP, + TEXTSTRING_JOYSTICKCONTROLS_TITLE, + TEXTSTRING_JOYSTICKCONTROLS_TITLE_HELP, + TEXTSTRING_JOYSTICKCONTROLS_ENABLED, + TEXTSTRING_JOYSTICKCONTROLS_ENABLED_HELP, + TEXTSTRING_JOYSTICKCONTROLS_IGNORED, + TEXTSTRING_JOYSTICKCONTROLS_MOVEMENT, + TEXTSTRING_JOYSTICKCONTROLS_POVHATREVERSED, + TEXTSTRING_JOYSTICKCONTROLS_POVHATREVERSED_HELP, + TEXTSTRING_JOYSTICKCONTROLS_POVHATVERTICAL, + TEXTSTRING_JOYSTICKCONTROLS_POVHATVERTICAL_HELP, + TEXTSTRING_JOYSTICKCONTROLS_POVHATHORIZONTAL, + TEXTSTRING_JOYSTICKCONTROLS_POVHATHORIZONTAL_HELP, + TEXTSTRING_JOYSTICKCONTROLS_RUDDERENABLED, + TEXTSTRING_JOYSTICKCONTROLS_RUDDERENABLED_HELP, + TEXTSTRING_JOYSTICKCONTROLS_RUDDERAXIS, + TEXTSTRING_JOYSTICKCONTROLS_RUDDERAXIS_HELP, + TEXTSTRING_PREDATORKEYCONTROLS_TITLE, + TEXTSTRING_PREDATORKEYCONTROLS_TITLE_HELP, + TEXTSTRING_ALIENKEYCONTROLS_TITLE, + TEXTSTRING_ALIENKEYCONTROLS_TITLE_HELP, + TEXTSTRING_MARINEKEYCONTROLS_TITLE, + TEXTSTRING_MARINEKEYCONTROLS_TITLE_HELP, + TEXTSTRING_KEYCONTROLS_HELP, + TEXTSTRING_MARINELEVELS_1, + TEXTSTRING_MARINELEVELS_2, + TEXTSTRING_MARINELEVELS_3, + TEXTSTRING_MARINELEVELS_4, + TEXTSTRING_MARINELEVELS_5, + TEXTSTRING_MARINELEVELS_6, + TEXTSTRING_MARINELEVELS_7, + TEXTSTRING_MARINELEVELS_8, + TEXTSTRING_MARINELEVELS_9, + TEXTSTRING_MARINELEVELS_10, + TEXTSTRING_MARINELEVELS_11, + TEXTSTRING_PREDATORLEVELS_1, + TEXTSTRING_PREDATORLEVELS_2, + TEXTSTRING_PREDATORLEVELS_3, + TEXTSTRING_PREDATORLEVELS_4, + TEXTSTRING_PREDATORLEVELS_5, + TEXTSTRING_PREDATORLEVELS_6, + TEXTSTRING_PREDATORLEVELS_7, + TEXTSTRING_PREDATORLEVELS_8, + TEXTSTRING_PREDATORLEVELS_9, + TEXTSTRING_PREDATORLEVELS_10, + TEXTSTRING_PREDATORLEVELS_11, + TEXTSTRING_ALIENLEVELS_1, + TEXTSTRING_ALIENLEVELS_2, + TEXTSTRING_ALIENLEVELS_3, + TEXTSTRING_ALIENLEVELS_4, + TEXTSTRING_ALIENLEVELS_5, + TEXTSTRING_ALIENLEVELS_6, + TEXTSTRING_ALIENLEVELS_7, + TEXTSTRING_ALIENLEVELS_8, + TEXTSTRING_ALIENLEVELS_9, + TEXTSTRING_ALIENLEVELS_10, + TEXTSTRING_MARINELEVELSBRIEFING_1, + TEXTSTRING_MARINELEVELSBRIEFING_1B, + TEXTSTRING_MARINELEVELSBRIEFING_1C, + TEXTSTRING_MARINELEVELSBRIEFING_1D, + TEXTSTRING_MARINELEVELSBRIEFING_1E, + TEXTSTRING_MARINELEVELSBRIEFING_2, + TEXTSTRING_MARINELEVELSBRIEFING_2B, + TEXTSTRING_MARINELEVELSBRIEFING_2C, + TEXTSTRING_MARINELEVELSBRIEFING_2D, + TEXTSTRING_MARINELEVELSBRIEFING_2E, + TEXTSTRING_MARINELEVELSBRIEFING_3, + TEXTSTRING_MARINELEVELSBRIEFING_3B, + TEXTSTRING_MARINELEVELSBRIEFING_3C, + TEXTSTRING_MARINELEVELSBRIEFING_3D, + TEXTSTRING_MARINELEVELSBRIEFING_3E, + TEXTSTRING_MARINELEVELSBRIEFING_4, + TEXTSTRING_MARINELEVELSBRIEFING_4B, + TEXTSTRING_MARINELEVELSBRIEFING_4C, + TEXTSTRING_MARINELEVELSBRIEFING_4D, + TEXTSTRING_MARINELEVELSBRIEFING_4E, + TEXTSTRING_MARINELEVELSBRIEFING_5, + TEXTSTRING_MARINELEVELSBRIEFING_5B, + TEXTSTRING_MARINELEVELSBRIEFING_5C, + TEXTSTRING_MARINELEVELSBRIEFING_5D, + TEXTSTRING_MARINELEVELSBRIEFING_5E, + TEXTSTRING_MARINELEVELSBRIEFING_6, + TEXTSTRING_MARINELEVELSBRIEFING_6B, + TEXTSTRING_MARINELEVELSBRIEFING_6C, + TEXTSTRING_MARINELEVELSBRIEFING_6D, + TEXTSTRING_MARINELEVELSBRIEFING_6E, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_1, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_1B, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_1C, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_1D, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_1E, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_2, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_2B, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_2C, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_2D, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_2E, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_3, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_3B, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_3C, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_3D, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_3E, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_4, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_4B, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_4C, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_4D, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_4E, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_5, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_5B, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_5C, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_5D, + TEXTSTRING_MARINEBONUSLEVELBRIEFING_5E, + TEXTSTRING_PREDATORLEVELSBRIEFING_1, + TEXTSTRING_PREDATORLEVELSBRIEFING_1B, + TEXTSTRING_PREDATORLEVELSBRIEFING_1C, + TEXTSTRING_PREDATORLEVELSBRIEFING_1D, + TEXTSTRING_PREDATORLEVELSBRIEFING_1E, + TEXTSTRING_PREDATORLEVELSBRIEFING_2, + TEXTSTRING_PREDATORLEVELSBRIEFING_2B, + TEXTSTRING_PREDATORLEVELSBRIEFING_2C, + TEXTSTRING_PREDATORLEVELSBRIEFING_2D, + TEXTSTRING_PREDATORLEVELSBRIEFING_2E, + TEXTSTRING_PREDATORLEVELSBRIEFING_3, + TEXTSTRING_PREDATORLEVELSBRIEFING_3B, + TEXTSTRING_PREDATORLEVELSBRIEFING_3C, + TEXTSTRING_PREDATORLEVELSBRIEFING_3D, + TEXTSTRING_PREDATORLEVELSBRIEFING_3E, + TEXTSTRING_PREDATORLEVELSBRIEFING_4, + TEXTSTRING_PREDATORLEVELSBRIEFING_4B, + TEXTSTRING_PREDATORLEVELSBRIEFING_4C, + TEXTSTRING_PREDATORLEVELSBRIEFING_4D, + TEXTSTRING_PREDATORLEVELSBRIEFING_4E, + TEXTSTRING_PREDATORLEVELSBRIEFING_5, + TEXTSTRING_PREDATORLEVELSBRIEFING_5B, + TEXTSTRING_PREDATORLEVELSBRIEFING_5C, + TEXTSTRING_PREDATORLEVELSBRIEFING_5D, + TEXTSTRING_PREDATORLEVELSBRIEFING_5E, + TEXTSTRING_PREDATORLEVELSBRIEFING_6, + TEXTSTRING_PREDATORLEVELSBRIEFING_6B, + TEXTSTRING_PREDATORLEVELSBRIEFING_6C, + TEXTSTRING_PREDATORLEVELSBRIEFING_6D, + TEXTSTRING_PREDATORLEVELSBRIEFING_6E, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_1, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_1B, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_1C, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_1D, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_1E, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_2, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_2B, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_2C, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_2D, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_2E, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_3, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_3B, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_3C, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_3D, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_3E, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_4, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_4B, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_4C, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_4D, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_4E, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_5, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_5B, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_5C, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_5D, + TEXTSTRING_PREDATORBONUSLEVELBRIEFING_5E, + TEXTSTRING_ALIENLEVELSBRIEFING_1, + TEXTSTRING_ALIENLEVELSBRIEFING_1B, + TEXTSTRING_ALIENLEVELSBRIEFING_1C, + TEXTSTRING_ALIENLEVELSBRIEFING_1D, + TEXTSTRING_ALIENLEVELSBRIEFING_1E, + TEXTSTRING_ALIENLEVELSBRIEFING_2, + TEXTSTRING_ALIENLEVELSBRIEFING_2B, + TEXTSTRING_ALIENLEVELSBRIEFING_2C, + TEXTSTRING_ALIENLEVELSBRIEFING_2D, + TEXTSTRING_ALIENLEVELSBRIEFING_2E, + TEXTSTRING_ALIENLEVELSBRIEFING_3, + TEXTSTRING_ALIENLEVELSBRIEFING_3B, + TEXTSTRING_ALIENLEVELSBRIEFING_3C, + TEXTSTRING_ALIENLEVELSBRIEFING_3D, + TEXTSTRING_ALIENLEVELSBRIEFING_3E, + TEXTSTRING_ALIENLEVELSBRIEFING_4, + TEXTSTRING_ALIENLEVELSBRIEFING_4B, + TEXTSTRING_ALIENLEVELSBRIEFING_4C, + TEXTSTRING_ALIENLEVELSBRIEFING_4D, + TEXTSTRING_ALIENLEVELSBRIEFING_4E, + TEXTSTRING_ALIENLEVELSBRIEFING_5, + TEXTSTRING_ALIENLEVELSBRIEFING_5B, + TEXTSTRING_ALIENLEVELSBRIEFING_5C, + TEXTSTRING_ALIENLEVELSBRIEFING_5D, + TEXTSTRING_ALIENLEVELSBRIEFING_5E, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_1, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_1B, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_1C, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_1D, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_1E, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_2, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_2B, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_2C, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_2D, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_2E, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_3, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_3B, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_3C, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_3D, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_3E, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_4, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_4B, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_4C, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_4D, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_4E, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_5, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_5B, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_5C, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_5D, + TEXTSTRING_ALIENBONUSLEVELBRIEFING_5E, + TEXTSTRING_INGAMEMENU_RESUMEGAME, + TEXTSTRING_INGAMEMENU_RESTARTMISSION, + TEXTSTRING_INGAMEMENU_QUITTOMAINMENU, + TEXTSTRING_DIFFICULTY_LEVEL, + TEXTSTRING_DIFFICULTY_EASY, + TEXTSTRING_DIFFICULTY_MEDIUM, + TEXTSTRING_DIFFICULTY_HARD, + TEXTSTRING_DIFFICULTY_EASY_HELP, + TEXTSTRING_DIFFICULTY_MEDIUM_HELP, + TEXTSTRING_DIFFICULTY_HARD_HELP, + TEXTSTRING_NOTYETCOMPLETED, + TEXTSTRING_COMPLETED_ON_EASY, + TEXTSTRING_COMPLETED_ON_MEDIUM, + TEXTSTRING_COMPLETED_ON_HARD, + TEXTSTRING_COMPLETED, + TEXTSTRING_NOTYETAVAILABLE_1, + TEXTSTRING_NOTYETAVAILABLE_2, + TEXTSTRING_DETAILLEVELS_TITLE, + TEXTSTRING_DETAILLEVELS_TITLE_HELP, + TEXTSTRING_DETAILLEVELS_DECALNUMBER, + TEXTSTRING_DETAILLEVELS_DECALNUMBER_HELP, + TEXTSTRING_DETAILLEVELS_LIGHTCORONAS, + TEXTSTRING_DETAILLEVELS_LIGHTCORONAS_HELP, + TEXTSTRING_DETAILLEVELS_DECALSONCHARACTERS, + TEXTSTRING_DETAILLEVELS_DECALSONCHARACTERS_HELP, + TEXTSTRING_DETAILLEVELS_DEFORMABLEEXPLOSIONS, + TEXTSTRING_DETAILLEVELS_DEFORMABLEEXPLOSIONS_HELP, + TEXTSTRING_DETAILLEVELS_CHARACTERCOMPLEXITY, + TEXTSTRING_DETAILLEVELS_CHARACTERCOMPLEXITY_HELP, + TEXTSTRING_DETAILLEVELS_PARTICLECOMPLEXITY, + TEXTSTRING_DETAILLEVELS_PARTICLECOMPLEXITY_HELP, + TEXTSTRING_DETAILLEVELS_VERYLOW, + TEXTSTRING_DETAILLEVELS_LOW, + TEXTSTRING_DETAILLEVELS_MEDIUM, + TEXTSTRING_DETAILLEVELS_HIGH, + TEXTSTRING_DETAILLEVELS_OFF, + TEXTSTRING_DETAILLEVELS_ON, + TEXTSTRING_LEVELBRIEFING_TITLE, + TEXTSTRING_CONTINUE, + TEXTSTRING_NO, + TEXTSTRING_YES, + TEXTSTRING_MISSION_ACCOMPLISHED, + TEXTSTRING_INGAME_PRESSANYKEYTOCONTINUE, + TEXTSTRING_INGAME_MESSAGENUMBER, + TEXTSTRING_INGAME_CHEATACTIVATED, + TEXTSTRING_INGAME_MEDIKIT, + TEXTSTRING_INGAME_AMMO, + TEXTSTRING_INGAME_PULSERIFLE, + TEXTSTRING_INGAME_SMARTGUN, + TEXTSTRING_INGAME_FLAMETHROWER, + TEXTSTRING_INGAME_SADAR, + TEXTSTRING_INGAME_GRENADELAUNCHER, + TEXTSTRING_INGAME_MINIGUN, + TEXTSTRING_INGAME_MARINE_PISTOL, + TEXTSTRING_INGAME_SKEETER, + TEXTSTRING_INGAME_TWOPISTOLS, + TEXTSTRING_INGAME_CLAW, + TEXTSTRING_INGAME_TAIL, + TEXTSTRING_INGAME_WRISTBLADE, + TEXTSTRING_INGAME_PISTOL, + TEXTSTRING_INGAME_RIFLE, + TEXTSTRING_INGAME_SHOULDERCANNON, + TEXTSTRING_INGAME_DISC, + TEXTSTRING_INGAME_MEDICOMP, + TEXTSTRING_INGAME_INTENSIFIERON, + TEXTSTRING_INGAME_INTENSIFIEROFF, + TEXTSTRING_INGAME_HEALTH, + TEXTSTRING_INGAME_ARMOUR, + TEXTSTRING_INGAME_FREEMODE, + TEXTSTRING_INGAME_TRACKMODE, + TEXTSTRING_PREDATOR_KEY_FORWARD, + TEXTSTRING_PREDATOR_KEY_BACKWARD, + TEXTSTRING_PREDATOR_KEY_LEFT, + TEXTSTRING_PREDATOR_KEY_RIGHT, + TEXTSTRING_PREDATOR_KEY_STRAFE, + TEXTSTRING_PREDATOR_KEY_STRAFE_LEFT, + TEXTSTRING_PREDATOR_KEY_STRAFE_RIGHT, + TEXTSTRING_PREDATOR_KEY_LOOK_UP, + TEXTSTRING_PREDATOR_KEY_LOOK_DOWN, + TEXTSTRING_PREDATOR_KEY_CENTRE_VIEW, + TEXTSTRING_PREDATOR_KEY_WALK, + TEXTSTRING_PREDATOR_KEY_CROUCH, + TEXTSTRING_PREDATOR_KEY_JUMP, + TEXTSTRING_PREDATOR_KEY_OPERATE, + TEXTSTRING_PREDATOR_KEY_FIRE_PRIMARY, + TEXTSTRING_PREDATOR_KEY_FIRE_SECONDARY, + TEXTSTRING_PREDATOR_KEY_NEXT_WEAPON, + TEXTSTRING_PREDATOR_KEY_PREVIOUS_WEAPON, + TEXTSTRING_PREDATOR_KEY_FLASHBACK_WEAPON, + TEXTSTRING_PREDATOR_KEY_CLOAK, + TEXTSTRING_PREDATOR_KEY_CYCLE_VISION, + TEXTSTRING_PREDATOR_KEY_ZOOM_IN, + TEXTSTRING_PREDATOR_KEY_ZOOM_OUT, + TEXTSTRING_PREDATOR_KEY_GRAPPLING_HOOK, + TEXTSTRING_PREDATOR_KEY_RECALLDISC, + TEXTSTRING_PREDATOR_KEY_TAUNT, + ADDITIONAL_TEXTSTRING_PREDATOR_KEY_MESSAGEHISTORY, + ADDITIONAL_TEXTSTRING_PREDATOR_KEY_SAY, + ADDITIONAL_TEXTSTRING_PREDATOR_KEY_SPECIESSAY, + ADDITIONAL_TEXTSTRING_PREDATOR_KEY_SHOWSCORES, + TEXTSTRING_MARINE_KEY_FORWARD, + TEXTSTRING_MARINE_KEY_BACKWARD, + TEXTSTRING_MARINE_KEY_LEFT, + TEXTSTRING_MARINE_KEY_RIGHT, + TEXTSTRING_MARINE_KEY_STRAFE, + TEXTSTRING_MARINE_KEY_STRAFE_LEFT, + TEXTSTRING_MARINE_KEY_STRAFE_RIGHT, + TEXTSTRING_MARINE_KEY_LOOK_UP, + TEXTSTRING_MARINE_KEY_LOOK_DOWN, + TEXTSTRING_MARINE_KEY_CENTRE_VIEW, + TEXTSTRING_MARINE_KEY_WALK, + TEXTSTRING_MARINE_KEY_CROUCH, + TEXTSTRING_MARINE_KEY_JUMP, + TEXTSTRING_MARINE_KEY_OPERATE, + TEXTSTRING_MARINE_KEY_FIRE_PRIMARY, + TEXTSTRING_MARINE_KEY_FIRE_SECONDARY, + TEXTSTRING_MARINE_KEY_NEXT_WEAPON, + TEXTSTRING_MARINE_KEY_PREVIOUS_WEAPON, + TEXTSTRING_MARINE_KEY_FLASHBACK_WEAPON, + TEXTSTRING_MARINE_KEY_IMAGE_INTENSIFIER, + TEXTSTRING_MARINE_KEY_THROW_FLARE, + TEXTSTRING_MARINE_KEY_JETPACK, + TEXTSTRING_MARINE_KEY_TAUNT, + ADDITIONAL_TEXTSTRING_MARINE_KEY_MESSAGEHISTORY, + ADDITIONAL_TEXTSTRING_MARINE_KEY_SAY, + ADDITIONAL_TEXTSTRING_MARINE_KEY_SPECIESSAY, + ADDITIONAL_TEXTSTRING_MARINE_KEY_SHOWSCORES, + TEXTSTRING_ALIEN_KEY_FORWARD, + TEXTSTRING_ALIEN_KEY_BACKWARD, + TEXTSTRING_ALIEN_KEY_LEFT, + TEXTSTRING_ALIEN_KEY_RIGHT, + TEXTSTRING_ALIEN_KEY_STRAFE, + TEXTSTRING_ALIEN_KEY_STRAFE_LEFT, + TEXTSTRING_ALIEN_KEY_STRAFE_RIGHT, + TEXTSTRING_ALIEN_KEY_LOOK_UP, + TEXTSTRING_ALIEN_KEY_LOOK_DOWN, + TEXTSTRING_ALIEN_KEY_CENTRE_VIEW, + TEXTSTRING_ALIEN_KEY_WALK, + TEXTSTRING_ALIEN_KEY_CROUCH, + TEXTSTRING_ALIEN_KEY_JUMP, + TEXTSTRING_ALIEN_KEY_OPERATE, + TEXTSTRING_ALIEN_KEY_FIRE_PRIMARY, + TEXTSTRING_ALIEN_KEY_FIRE_SECONDARY, + TEXTSTRING_ALIEN_KEY_ALTERNATE_VISION, + TEXTSTRING_ALIEN_KEY_TAUNT, + ADDITIONAL_TEXTSTRING_ALIEN_KEY_MESSAGEHISTORY, + ADDITIONAL_TEXTSTRING_ALIEN_KEY_SAY, + ADDITIONAL_TEXTSTRING_ALIEN_KEY_SPECIESSAY, + ADDITIONAL_TEXTSTRING_ALIEN_KEY_SHOWSCORES, + TEXTSTRING_KEYS_LEFT, + TEXTSTRING_KEYS_RIGHT, + TEXTSTRING_KEYS_UP, + TEXTSTRING_KEYS_DOWN, + TEXTSTRING_KEYS_RETURN, + TEXTSTRING_KEYS_TAB, + TEXTSTRING_KEYS_INSERT, + TEXTSTRING_KEYS_DELETE, + TEXTSTRING_KEYS_END, + TEXTSTRING_KEYS_HOME, + TEXTSTRING_KEYS_PGUP, + TEXTSTRING_KEYS_PGDOWN, + TEXTSTRING_KEYS_BACKSP, + TEXTSTRING_KEYS_COMMA, + TEXTSTRING_KEYS_PERIOD, + TEXTSTRING_KEYS_SPACE, + TEXTSTRING_KEYS_LSHIFT, + TEXTSTRING_KEYS_RSHIFT, + TEXTSTRING_KEYS_LALT, + TEXTSTRING_KEYS_RALT, + TEXTSTRING_KEYS_LCTRL, + TEXTSTRING_KEYS_RCTRL, + TEXTSTRING_KEYS_CAPS, + TEXTSTRING_KEYS_NUMLOCK, + TEXTSTRING_KEYS_SCRLOCK, + TEXTSTRING_KEYS_PAD0, + TEXTSTRING_KEYS_PAD1, + TEXTSTRING_KEYS_PAD2, + TEXTSTRING_KEYS_PAD3, + TEXTSTRING_KEYS_PAD4, + TEXTSTRING_KEYS_PAD5, + TEXTSTRING_KEYS_PAD6, + TEXTSTRING_KEYS_PAD7, + TEXTSTRING_KEYS_PAD8, + TEXTSTRING_KEYS_PAD9, + TEXTSTRING_KEYS_PADSUB, + TEXTSTRING_KEYS_PADADD, + TEXTSTRING_KEYS_PADDEL, + TEXTSTRING_KEYS_NUMPADENTER, + TEXTSTRING_KEYS_NUMPADDIVIDE, + TEXTSTRING_KEYS_NUMPADMULTIPLY, + TEXTSTRING_KEYS_LBRACKET, + TEXTSTRING_KEYS_RBRACKET, + TEXTSTRING_KEYS_SEMICOLON, + TEXTSTRING_KEYS_APOSTROPHE, + TEXTSTRING_KEYS_GRAVE, + TEXTSTRING_KEYS_BACKSLASH, + TEXTSTRING_KEYS_SLASH, + TEXTSTRING_KEYS_CAPITAL, + TEXTSTRING_KEYS_MINUS, + TEXTSTRING_KEYS_EQUALS, + TEXTSTRING_KEYS_LWIN, + TEXTSTRING_KEYS_RWIN, + TEXTSTRING_KEYS_APPS, + TEXTSTRING_KEYS_F1, + TEXTSTRING_KEYS_F2, + TEXTSTRING_KEYS_F3, + TEXTSTRING_KEYS_F4, + TEXTSTRING_KEYS_F5, + TEXTSTRING_KEYS_F6, + TEXTSTRING_KEYS_F7, + TEXTSTRING_KEYS_F8, + TEXTSTRING_KEYS_F9, + TEXTSTRING_KEYS_F10, + TEXTSTRING_KEYS_F11, + TEXTSTRING_KEYS_F12, + TEXTSTRING_KEYS_JOYSTICKBUTTON_1, + TEXTSTRING_KEYS_JOYSTICKBUTTON_2, + TEXTSTRING_KEYS_JOYSTICKBUTTON_3, + TEXTSTRING_KEYS_JOYSTICKBUTTON_4, + TEXTSTRING_KEYS_JOYSTICKBUTTON_5, + TEXTSTRING_KEYS_JOYSTICKBUTTON_6, + TEXTSTRING_KEYS_JOYSTICKBUTTON_7, + TEXTSTRING_KEYS_JOYSTICKBUTTON_8, + TEXTSTRING_KEYS_JOYSTICKBUTTON_9, + TEXTSTRING_KEYS_JOYSTICKBUTTON_10, + TEXTSTRING_KEYS_LMOUSE, + TEXTSTRING_KEYS_RMOUSE, + TEXTSTRING_KEYS_MMOUSE, + TEXTSTRING_KEYS_MOUSEBUTTON4, + TEXTSTRING_KEYS_MOUSEWHEELUP, + TEXTSTRING_KEYS_MOUSEWHEELDOWN, + TEXTSTRING_AMMO_SHORTNAME_UNKNOWN, + TEXTSTRING_AMMO_SHORTNAME_10MM_CULW, + TEXTSTRING_AMMO_SHORTNAME_SHOTGUN, + TEXTSTRING_AMMO_SHORTNAME_SMARTGUN, + TEXTSTRING_AMMO_SHORTNAME_FLAMETHROWER, + TEXTSTRING_AMMO_SHORTNAME_SADAR_TOW, + TEXTSTRING_AMMO_SHORTNAME_GRENADE, + TEXTSTRING_AMMO_SHORTNAME_MINIGUN, + TEXTSTRING_AMMO_SHORTNAME_PULSE_GRENADE, + TEXTSTRING_AMMO_SHORTNAME_MARINE_PISTOL, + TEXTSTRING_AMMO_SHORTNAME_SKEETER, + TEXTSTRING_AMMO_SHORTNAME_FLARE_GRENADE, + TEXTSTRING_AMMO_SHORTNAME_FRAGMENTATION_GRENADE, + TEXTSTRING_AMMO_SHORTNAME_PROXIMITY_GRENADE, + TEXTSTRING_SELECTEDGRENADE_STANDARD, + TEXTSTRING_SELECTEDGRENADE_FLARE, + TEXTSTRING_SELECTEDGRENADE_PROXIMITY, + TEXTSTRING_SELECTEDGRENADE_FRAGMENTATION, + TEXTSTRING_ROUNDS, + TEXTSTRING_MAGAZINES, + TEXTSTRING_MAGAZINES_FLAMETHROWER, + TEXTSTRING_FILENAME, + TEXTSTRING_CONFIGFILENAME_HELP, + TEXTSTRING_DESCRIPTION, + TEXTSTRING_CONFIGDESCRIPTION_HELP, + TEXTSTRING_SAVEFILE, + TEXTSTRING_CONFIGSAVEFILE_HELP, + TEXTSTRING_GAMESTATS_LEVELCOMPLETED, + TEXTSTRING_GAMESTATS_LEVELNOTCOMPLETED, + TEXTSTRING_GAMESTATS_YOUR, + TEXTSTRING_GAMESTATS_BEST, + TEXTSTRING_GAMESTATS_TARGET, + TEXTSTRING_GAMESTATS_TIMEELAPSED, + TEXTSTRING_GAMESTATS_TIMECLOAKED, + TEXTSTRING_GAMESTATS_KILLED, + TEXTSTRING_GAMESTATS_TROPHIESCOLLECTED, + TEXTSTRING_GAMESTATS_LIVEHEADBITES, + TEXTSTRING_GAMESTATS_DEADHEADBITES, + TEXTSTRING_GAMESTATS_AVERAGESPEED, + TEXTSTRING_GAMESTATS_PREFERREDVISIONMODE, + TEXTSTRING_GAMESTATS_HEALTHDAMAGETAKEN, + TEXTSTRING_GAMESTATS_ARMOURDAMAGETAKEN, + TEXTSTRING_GAMESTATS_HEADSHOTS, + TEXTSTRING_GAMESTATS_PREFERREDWEAPON, + TEXTSTRING_GAMESTATS_TOTALSHOTSFIRED, + TEXTSTRING_GAMESTATS_ACCURACY, + TEXTSTRING_GAMESTATS_SPOTTED, + TEXTSTRING_GAMESTATS_FIELDCHARGEUSED, + TEXTSTRING_GAMESTATS_CHEATMODEENABLED, + TEXTSTRING_GAMESTATS_FACEHUGGER, + TEXTSTRING_GAMESTATS_XENOMORPH, + TEXTSTRING_GAMESTATS_PRAETORIAN, + TEXTSTRING_GAMESTATS_QUEEN, + TEXTSTRING_GAMESTATS_XENOBORG, + TEXTSTRING_GAMESTATS_PREDALIEN, + TEXTSTRING_GAMESTATS_PREDATOR, + TEXTSTRING_GAMESTATS_MARINE, + TEXTSTRING_GAMESTATS_CIVILIAN, + TEXTSTRING_GAMESTATS_ANDROID, + TEXTSTRING_GAMESTATS_FACEHUGGER_PL, + TEXTSTRING_GAMESTATS_XENOMORPH_PL, + TEXTSTRING_GAMESTATS_PRAETORIAN_PL, + TEXTSTRING_GAMESTATS_QUEEN_PL, + TEXTSTRING_GAMESTATS_XENOBORG_PL, + TEXTSTRING_GAMESTATS_PREDALIEN_PL, + TEXTSTRING_GAMESTATS_PREDATOR_PL, + TEXTSTRING_GAMESTATS_MARINE_PL, + TEXTSTRING_GAMESTATS_CIVILIAN_PL, + TEXTSTRING_GAMESTATS_ANDROID_PL, + TEXTSTRING_GAMESTATS_VM_NORMAL, + TEXTSTRING_GAMESTATS_VM_NAVSENSE, + TEXTSTRING_GAMESTATS_VM_INTENSIFIER, + TEXTSTRING_GAMESTATS_VM_THERMAL, + TEXTSTRING_GAMESTATS_VM_ELECTRICAL, + TEXTSTRING_GAMESTATS_VM_PREDTECH, + TEXTSTRING_MPLAYER_TEXT_1, + TEXTSTRING_MPLAYER_TEXT_2, + TEXTSTRING_MPLAYER_TEXT_3, + TEXTSTRING_MPLAYER_TEXT_4, + TEXTSTRING_MPLAYER_TEXT_5, + TEXTSTRING_NOAMMOFORWEAPON, + TEXTSTRING_PREVIOUSGAME_FILENAME, + TEXTSTRING_NOTENOUGHMEMORY, + TEXTSTRING_MPCONFIG1_FILENAME, + TEXTSTRING_MPCONFIG2_FILENAME, + TEXTSTRING_MPCONFIG3_FILENAME, + TEXTSTRING_MPCONFIG4_FILENAME, + TEXTSTRING_MPCONFIG5_FILENAME, + TEXTSTRING_MPCONFIG6_FILENAME, + TEXTSTRING_MPCONFIG7_FILENAME, + TEXTSTRING_MPCONFIG1_DESCRIPTION, + TEXTSTRING_MPCONFIG2_DESCRIPTION, + TEXTSTRING_MPCONFIG3_DESCRIPTION, + TEXTSTRING_MPCONFIG4_DESCRIPTION, + TEXTSTRING_MPCONFIG5_DESCRIPTION, + TEXTSTRING_MPCONFIG6_DESCRIPTION, + TEXTSTRING_MPCONFIG7_DESCRIPTION, + TEXTSTRING_MULTIPLAYER_JOININGGAME, + TEXTSTRING_MULTIPLAYER_WAITSTART, + TEXTSTRING_MULTIPLAYER_WAITDESC, + TEXTSTRING_MULTIPLAYER_WAITINCOMPATABLE, + TEXTSTRING_MULTIPLAYER_WAITNOLEVEL, + TEXTSTRING_MULTIPLAYER_WAIT_HELP, + TEXTSTRING_MULTIPLAYER_ERROR, + TEXTSTRING_MULTIPLAYER_ERROR_HELP, + TEXTSTRING_MULTIPLAYER_SEARCHINGFORSESSIONS, + TEXTSTRING_TRACKERBALL_ENABLED, + TEXTSTRING_TRACKERBALL_ENABLED_HELP, + TEXTSTRING_TRACKERBALL_FLIPVERTICALAXIS, + TEXTSTRING_TRACKERBALL_FLIPVERTICALAXIS_HELP, + TEXTSTRING_TRACKERBALL_HORIZONTAL_SENSITIVITY, + TEXTSTRING_TRACKERBALL_VERTICAL_SENSITIVITY, + TEXTSTRING_KEYS_JOYSTICKBUTTON_11, + TEXTSTRING_KEYS_JOYSTICKBUTTON_12, + TEXTSTRING_KEYS_JOYSTICKBUTTON_13, + TEXTSTRING_KEYS_JOYSTICKBUTTON_14, + TEXTSTRING_KEYS_JOYSTICKBUTTON_15, + TEXTSTRING_KEYS_JOYSTICKBUTTON_16, + TEXTSTRING_COMPLETEDLEVEL_PRESSAKEY, + TEXTSTRING_AVOPTIONS_CDVOLUME, + TEXTSTRING_AVOPTIONS_CDVOLUME_HELP, + TEXTSTRING_EXTRAPOLATEMOVEMENT, + TEXTSTRING_EXTRAPOLATEMOVEMENT_HELP, + TEXTSTRING_SESSIONFULL, + TEXTSTRING_FOXINTERACTIVE, + TEXTSTRING_PRESENTS, + TEXTSTRING_DELETECONFIGURATION, + TEXTSTRING_DELETECONFIGURATION_HELP, + TEXTSTRING_LOADMULTIPLAYERCONFIG_HELP, + TEXTSTRING_LOADGAME, + TEXTSTRING_LOADGAME_HELP, + TEXTSTRING_SAVEGAME, + TEXTSTRING_LOADGAME_INSTRUCTIONS, + TEXTSTRING_SAVEGAME_INSTRUCTIONS, + TEXTSTRING_SAVEGAME_EMPTYSLOT, + TEXTSTRING_SAVEGAME_ERRORSAVING, + TEXTSTRING_SAVEGAME_ERRORLOADING, + TEXTSTRING_SAVEGAME_NOSAVESLEFT, + TEXTSTRING_SAVEGAME_GAMESAVED, + TEXTSTRING_SAVEGAME_GAMELOADED, + TEXTSTRING_SAVEGAME_NOTALLOWED, + TEXTSTRING_SAVEGAME_SAVESLEFT, + TEXTSTRING_AUTOWEAPONCHANGE, + TEXTSTRING_AUTOWEAPONCHANGE_HELP, + TEXTSTRING_MAINMENU_SUBTITLE, + TEXTSTRING_BRIEFING_PREDATOR_PISTOL, + TEXTSTRING_BRIEFING_UNAVAILABLE_WEAPONS, + TEXTSTRING_NEW_LEVEL, + TEXTSTRING_CUSTOM_LEVEL, + TEXTSTRING_MULTIPLAYER_OPERATETORESPAWN, + TEXTSTRING_MULTIPLAYER_OPERATETOOBSERVE, + MAX_NO_OF_TEXTSTRINGS +}; + +#endif diff --git a/3dc/avp/load_shp.c b/3dc/avp/load_shp.c new file mode 100644 index 0000000..fa2c7c3 --- /dev/null +++ b/3dc/avp/load_shp.c @@ -0,0 +1,140 @@ + +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" + +#include "load_shp.h" + +#define UseLocalAssert No + +#include "ourasert.h" + +char *Marine_Loaded_Shape_Names[I_Num_Character_Shapes] = +{ + "ALIEN_STANDING", + "ALIEN_CROUCHING", + "XENOBORG", + "PREDATOR", + "PREDATOR_ALIEN", + "FACE_HUGGER", + "QUEEN", + + "GRENADE", + "MISSILE", + "DISC", + "PRED_PALSMA", + "AUTOGUN", + + "EXPLOSION", + "EXPLOSION", + "PLASMA_EXP", + "RICOCHET", + + "ALIEN_BLOOD_SPLASH", + "ALIEN_BLOOD_SPLASH", + "PREDATOR_BLOOD_SPLASH", + "ALIEN_BLOOD_SPLASH", + "FACEHUGGER_BLOOD_SPLASH", +}; + + +char *Alien_Loaded_Shape_Names[I_Num_Character_Shapes] = +{ + "MARINE", + "NONE", + "XENOBORG", + "PREDATOR", + "PREDATOR_ALIEN", + "NONE", + "QUEEN", + + "GRENADE", + "MISSILE", + "DISC", + "PRED_PALSMA", + "NONE", + + "EXPLOSION", + "EXPLOSION", + "PLASMA_EXP", + "RICOCHET", + + "MARINE_BLOOD_SPLASH", + "NONE", + "PREDATOR_BLOOD_SPLASH", + "NONE", + "NONE", +}; + + +char *Predator_Loaded_Shape_Names[I_Num_Character_Shapes] = +{ + "MARINE", + "NONE", + "XENOBORG", + "SPECIAL_MARINE", + "PREDATOR_ALIEN", + "FACE_HUGGER", + "QUEEN", + + "GRENADE", + "MISSILE", + "DISC", + "PRED_PALSMA", + "NONE", + + "EXPLOSION", + "EXPLOSION", + "PLASMA_EXP", + "RICOCHET", + + "ALIEN_BLOOD_SPLASH", + "ALIEN_BLOOD_SPLASH", + "MARINE_BLOOD_SPLASH", + "ALIEN_BLOOD_SPLASH", + "FACEHUGGER_BLOOD_SPLASH", +}; + +static int LoadedShapesInMSL[I_Num_Character_Shapes]; + +void InitCharacterMSLReferences() +{ + int shape_num = I_Num_Character_Shapes; + + while(--shape_num >= 0) + { + switch(AvP.PlayerType) + { + case I_Marine: + { +// LoadedShapesInMSL[shape_num] = +// GetLoadedShapeMSL(Marine_Loaded_Shape_Names[shape_num]); + break; + } + case I_Predator: + { +// LoadedShapesInMSL[shape_num] = +// GetLoadedShapeMSL(Predator_Loaded_Shape_Names[shape_num]); + break; + } + case I_Alien: + { +// LoadedShapesInMSL[shape_num] = +// GetLoadedShapeMSL(Alien_Loaded_Shape_Names[shape_num]); + break; + } + + default: + GLOBALASSERT(2<1); + } + } +} + + + +int GetMSLPosFromEnum(CHARACTER_SHAPES shape_enum) +{ + return(LoadedShapesInMSL[shape_enum]); +} \ No newline at end of file diff --git a/3dc/avp/load_shp.h b/3dc/avp/load_shp.h new file mode 100644 index 0000000..9f3c9e3 --- /dev/null +++ b/3dc/avp/load_shp.h @@ -0,0 +1,36 @@ + +typedef enum +{ + I_Shape_BadGuy1 = 0, + I_Shape_BadGuy2, + I_Shape_BadGuy3, + I_Shape_BadGuy4, + I_Shape_BadGuy5, + I_Shape_BadGuy6, + I_Shape_BadGuy7, + + I_Shape_Grenade, + I_Shape_Missile, + I_Shape_Disc, + I_Shape_Plasma, + I_Shape_AutoGun, + + I_Shape_Explosion1, + I_Shape_Explosion2, + I_Shape_PlasmaGunExp, + I_Shape_Ricochet, + + I_Shape_BloodSplash1, + I_Shape_BloodSplash2, + I_Shape_BloodSplash3, + I_Shape_BloodSplash4, + I_Shape_BloodSplash5, + + I_Num_Character_Shapes, + +}CHARACTER_SHAPES; + + +extern void InitCharacterMSLReferences(); +extern int GetMSLPosFromEnum(CHARACTER_SHAPES shape_enum); +extern int GetLoadedShapeMSL(const char *); diff --git a/3dc/avp/los.c b/3dc/avp/los.c new file mode 100644 index 0000000..bc929c7 --- /dev/null +++ b/3dc/avp/los.c @@ -0,0 +1,702 @@ +/*KJL************************* +* los.c - Line of sight code * +*************************KJL*/ +#include "3dc.h" +#include "module.h" +#include "inline.h" +#include "stratdef.h" +#include "gamedef.h" +#include "dynblock.h" +#include "dynamics.h" + +#include "bh_types.h" +#include "comp_shp.h" +#include "avpview.h" +#define UseLocalAssert Yes +#include "ourasert.h" +#include "dxlog.h" +#include "showcmds.h" +#include "targeting.h" +#include "los.h" + +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ +int IsThisObjectVisibleFromThisPosition(DISPLAYBLOCK *dPtr,VECTORCH *positionPtr,int maxRange); +void CheckForVectorIntersectionWithHierarchicalObject(DISPLAYBLOCK *dPtr, VECTORCH *viewVectorAlphaPtr, VECTORCH *viewVectorBetaPtr); +void CheckForRayIntersectionWithHierarchy(DISPLAYBLOCK *objectPtr, SECTION_DATA *sectionDataPtr); +void CheckForRayIntersectionWithObject(DISPLAYBLOCK *dPtr); +/*KJL**************************************************************************************** +* D E F I N E S * +****************************************************************************************KJL*/ +#define POLY_REJECT_RANGE 500 + +extern MORPHDISPLAY MorphDisplay; +extern VECTORCH MorphedPts[]; +extern VECTORCH *ShapePointsPtr; +extern int *ShapeNormalsPtr; +extern int *Shape2NormalsPtr; +extern char ShapeIsMorphed; +extern int **ItemArrayPtr; +extern POLYHEADER *PolyheaderPtr; + +#define AccessNextPolygon()\ +{\ + int *itemPtr = *(ItemArrayPtr++);\ + PolyheaderPtr = (POLYHEADER *) itemPtr;\ +} + +#define GetPolygonVertices(polyPtr)\ +{\ + int *vertexNumberPtr = &PolyheaderPtr->Poly1stPt;\ +\ + (polyPtr)->PolyPoint[0] = *(ShapePointsPtr + *vertexNumberPtr++);\ + (polyPtr)->PolyPoint[1] = *(ShapePointsPtr + *vertexNumberPtr++);\ + (polyPtr)->PolyPoint[2] = *(ShapePointsPtr + *vertexNumberPtr++);\ + \ + if (*vertexNumberPtr != Term)\ + {\ + (polyPtr)->PolyPoint[3] = *(ShapePointsPtr + *vertexNumberPtr);\ + (polyPtr)->NumberOfVertices=4; \ + }\ + else\ + {\ + (polyPtr)->NumberOfVertices=3; \ + }\ +} +#define GetPolygonNormal(polyPtr)\ +{ \ + if (ShapeIsMorphed)\ + {\ + VECTORCH n1Ptr = *(VECTORCH*)(ShapeNormalsPtr + PolyheaderPtr->PolyNormalIndex);\ + VECTORCH n2Ptr = *(VECTORCH*)(Shape2NormalsPtr + PolyheaderPtr->PolyNormalIndex);\ + \ + if( ((n1Ptr.vx == n2Ptr.vx)\ + && (n1Ptr.vy == n2Ptr.vy)\ + && (n1Ptr.vz == n2Ptr.vz))\ + || (MorphDisplay.md_lerp == 0) )\ + {\ + (polyPtr)->PolyNormal = n1Ptr;\ + }\ + else if(MorphDisplay.md_lerp == 0xffff)\ + {\ + (polyPtr)->PolyNormal = n2Ptr;\ + }\ + else\ + {\ + VECTORCH *pointPtr[3];\ + int *vertexNumPtr = &PolyheaderPtr->Poly1stPt;\ +\ + pointPtr[0] = (ShapePointsPtr + *vertexNumPtr++);\ + pointPtr[1] = (ShapePointsPtr + *vertexNumPtr++);\ + pointPtr[2] = (ShapePointsPtr + *vertexNumPtr);\ +\ + MakeNormal\ + (\ + pointPtr[0],\ + pointPtr[1],\ + pointPtr[2],\ + &(polyPtr)->PolyNormal\ + );\ + }\ + }\ + else /* not morphed */\ + {\ + (polyPtr)->PolyNormal = *(VECTORCH*)(ShapeNormalsPtr + PolyheaderPtr->PolyNormalIndex);\ + }\ +} + +/*KJL**************************************************************************************** +* G L O B A L S * +****************************************************************************************KJL*/ +extern DISPLAYBLOCK *Player; + +/* unnormalised vector in the direction which the gun's muzzle is pointing, IN VIEW SPACE */ +/* very useful when considering sprites, which lie in a Z-plane in view space */ +extern VECTORCH GunMuzzleDirectionInVS; +/* dir gun is pointing, normalised and IN WORLD SPACE */ +extern VECTORCH GunMuzzleDirectionInWS; + +extern DISPLAYBLOCK PlayersWeapon; + + +extern int NumOnScreenBlocks; +extern DISPLAYBLOCK *OnScreenBlockList[]; +extern int NumActiveBlocks; +extern DISPLAYBLOCK *ActiveBlockList[]; + + +static VECTORCH *ViewpointDirectionPtr; +static VECTORCH *ViewpointPositionPtr; + +static int ObjectVisiblityTest(DISPLAYBLOCK *objectPtr,VECTORCH *positionPtr,int maxRange); + + +/*KJL**************************************************************************************** +* CODE STARTS HERE! * +****************************************************************************************KJL*/ +int CameraCanSeeThisPosition_WithIgnore(DISPLAYBLOCK *ignoredObjectPtr,VECTORCH *positionPtr) +{ + VECTORCH viewVector; /* direction of view-line */ + + GLOBALASSERT(ignoredObjectPtr); + + /* try to look at the centre of the camera */ + viewVector = Global_VDB_Ptr->VDB_World; + + viewVector.vx -= positionPtr->vx; + viewVector.vy -= positionPtr->vy; + viewVector.vz -= positionPtr->vz; + Normalise(&viewVector); + + FindPolygonInLineOfSight(&viewVector, positionPtr, 0,ignoredObjectPtr); + + + if (LOS_ObjectHitPtr == Player) return 1; + else return 0; +} + +int IsThisObjectVisibleFromThisPosition_WithIgnore(DISPLAYBLOCK *objectPtr,DISPLAYBLOCK *ignoredObjectPtr,VECTORCH *positionPtr,int maxRange) +{ + VECTORCH viewVector; /* direction of view-line */ + + GLOBALASSERT(objectPtr); + + /* try to look at the centre of the object */ + GetTargetingPointOfObject(objectPtr, &viewVector); + + viewVector.vx -= positionPtr->vx; + viewVector.vy -= positionPtr->vy; + viewVector.vz -= positionPtr->vz; + Normalise(&viewVector); + + FindPolygonInLineOfSight(&viewVector, positionPtr, 0,ignoredObjectPtr); + + + if (LOS_ObjectHitPtr == objectPtr) return 1; + else return 0; +} + +int IsThisObjectVisibleFromThisPosition(DISPLAYBLOCK *objectPtr,VECTORCH *positionPtr,int maxRange) +{ + VECTORCH viewVector; /* direction of view-line */ + + GLOBALASSERT(objectPtr); + + /* try to look at the centre of the object */ + GetTargetingPointOfObject(objectPtr, &viewVector); + + viewVector.vx -= positionPtr->vx; + viewVector.vy -= positionPtr->vy; + viewVector.vz -= positionPtr->vz; + Normalise(&viewVector); + + FindPolygonInLineOfSight(&viewVector, positionPtr, 0,0); + + + if (LOS_ObjectHitPtr == objectPtr) return 1; + else return 0; +} + + +void CheckForVectorIntersectionWith3dObject(DISPLAYBLOCK *objectPtr, VECTORCH *viewVectorAlphaPtr, VECTORCH *viewVectorBetaPtr, int rigorous) +{ + ViewpointPositionPtr = viewVectorAlphaPtr; + ViewpointDirectionPtr = viewVectorBetaPtr; + + if (objectPtr->HModelControlBlock) + { + SECTION_DATA *firstSectionPtr; + firstSectionPtr=objectPtr->HModelControlBlock->section_data; + LOCALASSERT(firstSectionPtr); + if ( !( + (objectPtr->ObWorld.vx<1000000 && objectPtr->ObWorld.vx>-1000000) + && (objectPtr->ObWorld.vy<1000000 && objectPtr->ObWorld.vy>-1000000) + && (objectPtr->ObWorld.vz<1000000 && objectPtr->ObWorld.vz>-1000000) + ) ) + { + return; + } + LOCALASSERT(objectPtr->ObWorld.vx<1000000 && objectPtr->ObWorld.vx>-1000000); + LOCALASSERT(objectPtr->ObWorld.vy<1000000 && objectPtr->ObWorld.vy>-1000000); + LOCALASSERT(objectPtr->ObWorld.vz<1000000 && objectPtr->ObWorld.vz>-1000000); + CheckForRayIntersectionWithHierarchy(objectPtr,firstSectionPtr); + } + else + { + CheckForRayIntersectionWithObject(objectPtr); + } +} + + + + + + + + + +/* KJL 15:26:08 14/05/98 - FindPolygonInLineOfSight + + Using either the Active or OnScreen Block list, find which polygon you would hit first + if a ray of light was cast out from a given point in world space (viewpointPositionPtr) + in a given direction (viewpointDirectionPtr). + + The following are set: + + LOS_ObjectHitPtr - dispPtr of hit object (NULL if none found) + + LOS_Lambda - distance to hit polygon (or max if no hit) + LOS_Point - world space coords of intersection of ray & hit poly + LOS_ObjectNormal - normal of the hit polygon + LOS_HModel_Section - hierarchical section that was hit (or NULL if not hmodel) + +*/ +void FindPolygonInLineOfSight(VECTORCH *viewpointDirectionPtr, VECTORCH *viewpointPositionPtr, int useOnScreenBlockList, DISPLAYBLOCK *objectToIgnorePtr) { + + /* Shell function. */ + FindPolygonInLineOfSight_TwoIgnores(viewpointDirectionPtr,viewpointPositionPtr,useOnScreenBlockList,objectToIgnorePtr,NULL); + /* No, it's not recursive! */ +} + + +void FindPolygonInLineOfSight_TwoIgnores(VECTORCH *viewpointDirectionPtr, VECTORCH *viewpointPositionPtr, int useOnScreenBlockList, DISPLAYBLOCK *objectToIgnorePtr,DISPLAYBLOCK *next_objectToIgnorePtr) +{ + DISPLAYBLOCK **displayBlockList; + int numberOfObjects; + + if (useOnScreenBlockList) + { + numberOfObjects = NumOnScreenBlocks; + displayBlockList = OnScreenBlockList; + } + else + { + numberOfObjects = NumActiveBlocks; + displayBlockList = ActiveBlockList; + } + + /* initialise the LoS data */ + + LOS_Lambda=10000000; + LOS_ObjectHitPtr = 0; + LOS_HModel_Section= 0; + ViewpointPositionPtr = viewpointPositionPtr; + ViewpointDirectionPtr = viewpointDirectionPtr; + + + /* scan throught each object */ + while (numberOfObjects--) + { + DISPLAYBLOCK* objectPtr = displayBlockList[numberOfObjects]; + + if ((objectPtr == objectToIgnorePtr)||(objectPtr == next_objectToIgnorePtr)) continue; + + /* if hierarchical model, consider each object in the model separately */ + if (objectPtr->HModelControlBlock) + { + SECTION_DATA *firstSectionPtr; + firstSectionPtr=objectPtr->HModelControlBlock->section_data; + + LOCALASSERT(firstSectionPtr); + if ( !( + (objectPtr->ObWorld.vx<1000000 && objectPtr->ObWorld.vx>-1000000) + && (objectPtr->ObWorld.vy<1000000 && objectPtr->ObWorld.vy>-1000000) + && (objectPtr->ObWorld.vz<1000000 && objectPtr->ObWorld.vz>-1000000) + ) ) + { + continue; + + LOGDXFMT(("Pre assertions check for having processed the section...\n")); + LOGDXFMT(("State of initialised flag: %d\n",(firstSectionPtr->flags§ion_data_initialised))); + LOGDXFMT(("Name of section: %s\n",firstSectionPtr->sempai->Section_Name)); + LOGDXFMT(("It was playing sequence: %d,%d\n",firstSectionPtr->my_controller->Sequence_Type, + firstSectionPtr->my_controller->Sub_Sequence)); + LOGDXFMT(("ObWorld %d,%d,%d\n",objectPtr->ObWorld.vx,objectPtr->ObWorld.vy,objectPtr->ObWorld.vz)); + + { + DYNAMICSBLOCK *dynPtr=objectPtr->ObStrategyBlock->DynPtr; + LOCALASSERT(dynPtr); + LOGDXFMT(("DynPtr->Position %d,%d,%d\n",dynPtr->Position.vx,dynPtr->Position.vy,dynPtr->Position.vz)); + } + + LOCALASSERT(firstSectionPtr->flags§ion_data_initialised); + LOCALASSERT(objectPtr->ObWorld.vx<1000000 && objectPtr->ObWorld.vx>-1000000); + LOCALASSERT(objectPtr->ObWorld.vy<1000000 && objectPtr->ObWorld.vy>-1000000); + LOCALASSERT(objectPtr->ObWorld.vz<1000000 && objectPtr->ObWorld.vz>-1000000); + + } + CheckForRayIntersectionWithHierarchy(objectPtr,firstSectionPtr); + } + else + { + CheckForRayIntersectionWithObject(objectPtr); + } + } +} + +void CheckForRayIntersectionWithHierarchy(DISPLAYBLOCK *objectPtr, SECTION_DATA *sectionDataPtr) +{ + SECTION *sectionPtr; + + /* LOS check. */ + + sectionPtr=sectionDataPtr->sempai; + + /* Unreal things can't be hit... */ + + if (!(sectionDataPtr->flags§ion_data_notreal) && (sectionPtr->Shape!=NULL)) + { + DISPLAYBLOCK dummy_displayblock; + + dummy_displayblock.ObShape=sectionPtr->ShapeNum; + dummy_displayblock.ObShapeData=sectionPtr->Shape; + dummy_displayblock.ObWorld=sectionDataPtr->World_Offset; + dummy_displayblock.ObMat=sectionDataPtr->SecMat; + + dummy_displayblock.ObRadius=0; + dummy_displayblock.ObMaxX=0; + dummy_displayblock.ObMinX=0; + dummy_displayblock.ObMaxY=0; + dummy_displayblock.ObMinY=0; + dummy_displayblock.ObMaxZ=0; + dummy_displayblock.ObMinZ=0; + + dummy_displayblock.ObTxAnimCtrlBlks=NULL; + dummy_displayblock.ObEIDPtr=NULL; + dummy_displayblock.ObMorphCtrl=NULL; + dummy_displayblock.ObStrategyBlock=objectPtr->ObStrategyBlock; + dummy_displayblock.ShapeAnimControlBlock=sectionDataPtr->sac_ptr; + dummy_displayblock.HModelControlBlock=NULL; /* Don't even want to think about that. */ + dummy_displayblock.ObMyModule=NULL; + + /* KJL 21:12:11 12/11/98 - arg! ObFlags wasn't set */ + dummy_displayblock.ObFlags = 0; + + if ( !( + (dummy_displayblock.ObWorld.vx<1000000 && dummy_displayblock.ObWorld.vx>-1000000) + && (dummy_displayblock.ObWorld.vy<1000000 && dummy_displayblock.ObWorld.vy>-1000000) + && (dummy_displayblock.ObWorld.vz<1000000 && dummy_displayblock.ObWorld.vz>-1000000) + ) ) { + + LOGDXFMT(("Pre assertions check for having processed the section...\n")); + LOGDXFMT(("State of initialised flag: %x\n",(sectionDataPtr->flags§ion_data_initialised))); + LOGDXFMT(("Name of section: %s\n",sectionDataPtr->sempai->Section_Name)); + LOGDXFMT(("It was playing sequence: %d,%d\n",sectionDataPtr->my_controller->Sequence_Type, + sectionDataPtr->my_controller->Sub_Sequence)); + LOGDXFMT(("ObWorld %d,%d,%d\n",dummy_displayblock.ObWorld.vx,dummy_displayblock.ObWorld.vy,dummy_displayblock.ObWorld.vz)); + + { + DYNAMICSBLOCK *dynPtr=objectPtr->ObStrategyBlock->DynPtr; + LOCALASSERT(dynPtr); + LOGDXFMT(("DynPtr->Position %d,%d,%d\n",dynPtr->Position.vx,dynPtr->Position.vy,dynPtr->Position.vz)); + } + + LOCALASSERT(sectionDataPtr->flags§ion_data_initialised); + LOCALASSERT(dummy_displayblock.ObWorld.vx<1000000 && dummy_displayblock.ObWorld.vx>-1000000); + LOCALASSERT(dummy_displayblock.ObWorld.vy<1000000 && dummy_displayblock.ObWorld.vy>-1000000); + LOCALASSERT(dummy_displayblock.ObWorld.vz<1000000 && dummy_displayblock.ObWorld.vz>-1000000); + + } + + CheckForRayIntersectionWithObject(&dummy_displayblock); + + if (LOS_ObjectHitPtr == &dummy_displayblock) + { + /* ah, we've hit this object */ + LOS_ObjectHitPtr = objectPtr; + LOS_HModel_Section = sectionDataPtr; + } + } + + /* Now call recursion... */ + if (sectionDataPtr->First_Child!=NULL) + { + SECTION_DATA *childrenListPtr = sectionDataPtr->First_Child; + + while (childrenListPtr!=NULL) + { + CheckForRayIntersectionWithHierarchy(objectPtr,childrenListPtr); + childrenListPtr=childrenListPtr->Next_Sibling; + } + } + +} + + + + +void CheckForRayIntersectionWithObject(DISPLAYBLOCK *dPtr) +{ + int numberOfItems; + VECTORCH viewVectorAlpha = *ViewpointPositionPtr; + VECTORCH viewVectorBeta = *ViewpointDirectionPtr; + VECTORCH position; + int needToRotate; + + /* check for a valid object */ + { + STRATEGYBLOCK* sbPtr; + GLOBALASSERT(dPtr); + + /* can it be seen? */ + if((dPtr->ObFlags&ObFlag_NotVis)&&(dPtr!=Player)) return; + /* KJL 21:18:44 23/05/98 - ugh. Currently the player's bounding box is notvis; I need a rethink */ + + /* any hierarchical models should have been split up by now */ + LOCALASSERT(dPtr->HModelControlBlock==NULL); + + /* no shape? */ + if (!dPtr->ObShape && dPtr->SfxPtr) return; + + sbPtr = dPtr->ObStrategyBlock; + + /* test for objects we're not interested in */ + if (sbPtr) + { + if (sbPtr->DynPtr) + { + /* ignore it if it's a non-collideable object, eg. debris */ + if(sbPtr->DynPtr->DynamicsType == DYN_TYPE_NO_COLLISIONS) + return; + } + } + } + + /* check objects position is sensible */ + #if 0 + LOCALASSERT(dPtr->ObWorld.vx<1000000 && dPtr->ObWorld.vx>-1000000); + LOCALASSERT(dPtr->ObWorld.vy<1000000 && dPtr->ObWorld.vy>-1000000); + LOCALASSERT(dPtr->ObWorld.vz<1000000 && dPtr->ObWorld.vz>-1000000); + #else + if(dPtr->ObWorld.vx>1000000 || dPtr->ObWorld.vx<-1000000) return; + if(dPtr->ObWorld.vy>1000000 || dPtr->ObWorld.vy<-1000000) return; + if(dPtr->ObWorld.vz>1000000 || dPtr->ObWorld.vz<-1000000) return; + #endif + if (dPtr==Player) + { + position = dPtr->ObStrategyBlock->DynPtr->Position; + } + else + { + position = dPtr->ObWorld; + } + /* transform view line into shape space */ + viewVectorAlpha.vx -= position.vx; + viewVectorAlpha.vy -= position.vy; + viewVectorAlpha.vz -= position.vz; + + #if 1 + if (dPtr!=Player) + { + if (MagnitudeOfCrossProduct(&viewVectorAlpha,&viewVectorBeta)>dPtr->ObShapeData->shaperadius) + return; + } + #endif + + /* if we're not dealing with a module, it's probably rotated */ + if(!dPtr->ObMyModule&&dPtr!=Player) + { + needToRotate = 1; + } + else + { + needToRotate = 0; + } + + if (needToRotate) + { + MATRIXCH matrix = dPtr->ObMat; + TransposeMatrixCH(&matrix); + RotateVector(&viewVectorBeta,&matrix); + RotateVector(&viewVectorAlpha,&matrix); + } + + numberOfItems = SetupPolygonAccess(dPtr); + if (!dPtr->ObShape) + { +// PrintDebuggingText("polys %d\n",numberOfItems); + } + + while(numberOfItems--) + { + extern POLYHEADER *PolyheaderPtr; + VECTORCH polyNormal; + struct ColPolyTag polyData; + VECTORCH pointOnPlane; + int lambda; + int axis1; + int axis2; + + /* scanning through polys */ + AccessNextPolygon(); + + if( (PolyheaderPtr->PolyFlags & iflag_notvis) && !(PolyheaderPtr->PolyFlags & iflag_mirror)) continue; + + + { + int normDotBeta; + + GetPolygonNormal(&polyData); + polyNormal = polyData.PolyNormal; + + normDotBeta = DotProduct(&(polyNormal),&viewVectorBeta); + { + /* if the polygon is flagged as double-sided, and it's pointing + the wrong way, consider it to be flipped round */ + //if((PolyheaderPtr->PolyFlags) & iflag_no_bfc) + /* KJL 16:06:11 10/07/98 - treat all polys as no bfc */ + { + if (normDotBeta>0) + { + normDotBeta=-normDotBeta; + polyNormal.vx = -polyNormal.vx; + polyNormal.vy = -polyNormal.vy; + polyNormal.vz = -polyNormal.vz; + } + } + } + + /* trivial rejection of poly if it is not facing LOS */ + if (normDotBeta>-POLY_REJECT_RANGE) + { + continue; + } + + GetPolygonVertices(&polyData); + /* calculate coords of plane-line intersection */ + { + int d; + { + /* get a pt in the poly */ + VECTORCH pop=polyData.PolyPoint[0]; + pop.vx -= viewVectorAlpha.vx; + pop.vy -= viewVectorAlpha.vy; + pop.vz -= viewVectorAlpha.vz; + + d = DotProduct(&(polyNormal),&pop); + } + + if (d>0) continue; + + lambda = DIV_FIXED(d,normDotBeta); + + if (lambda>=LOS_Lambda) + { + continue; + } + pointOnPlane.vx = viewVectorAlpha.vx + MUL_FIXED(lambda,viewVectorBeta.vx); + pointOnPlane.vy = viewVectorAlpha.vy + MUL_FIXED(lambda,viewVectorBeta.vy); + pointOnPlane.vz = viewVectorAlpha.vz + MUL_FIXED(lambda,viewVectorBeta.vz); + + } + + /* decide which 2d plane to project onto */ + + { + VECTORCH absNormal = (polyNormal); + if (absNormal.vx<0) absNormal.vx=-absNormal.vx; + if (absNormal.vy<0) absNormal.vy=-absNormal.vy; + if (absNormal.vz<0) absNormal.vz=-absNormal.vz; + + if (absNormal.vx > absNormal.vy) + { + if (absNormal.vx > absNormal.vz) + { + axis1=iy; + axis2=iz; + } + else + { + axis1=ix; + axis2=iy; + } + } + else + { + if (absNormal.vy > absNormal.vz) + { + axis1=ix; + axis2=iz; + } + else + { + axis1=ix; + axis2=iy; + } + } + } + + } + + { + int projectedPolyVertex[20]; + int projectedPointOnPlane[2]; + int *popPtr = &pointOnPlane.vx; + + projectedPointOnPlane[0]=*(popPtr+axis1); + projectedPointOnPlane[1]=*(popPtr+axis2); + + { + VECTORCH *vertexPtr = &polyData.PolyPoint[0]; + int *projectedVertexPtr= &projectedPolyVertex[0]; + int noOfVertices = polyData.NumberOfVertices; + + do + { + *projectedVertexPtr++ = *((int*)vertexPtr + axis1); + *projectedVertexPtr++ = *((int*)vertexPtr + axis2); + + vertexPtr++; + noOfVertices--; + } + while(noOfVertices); + + } + + + if (PointInPolygon(&projectedPointOnPlane[0],&projectedPolyVertex[0],polyData.NumberOfVertices,2)) + { + /* rotate vector back into World Space if it's not a module */ + LOS_ObjectNormal = polyNormal; + if (needToRotate) + { + MATRIXCH matrix = dPtr->ObMat; + RotateVector(&pointOnPlane,&matrix); + + RotateVector(&LOS_ObjectNormal,&matrix); + } + + /* and translate origin */ + pointOnPlane.vx += position.vx; + pointOnPlane.vy += position.vy; + pointOnPlane.vz += position.vz; + + LOS_Point=pointOnPlane; + LOS_ObjectHitPtr = dPtr; + LOS_Lambda=lambda; + LOS_HModel_Section = 0; + } + } + } + return; +} + +/* KJL 15:35:58 14/05/98 - IsObjectVisibleFromThisPoint + + Returns a non-zero value if an object can be seen from a given point in world space + (viewpointPositionPtr), with a given field of view (fieldOfView) about a given + direction (viewpointDirectionPtr). +*/ +int IsObjectVisibleFromThisPoint(DISPLAYBLOCK *dispPtr, VECTORCH *viewpointDirectionPtr, VECTORCH *viewpointPositionPtr, int fieldOfView) +{ + + return 0; +} + + + + + + + diff --git a/3dc/avp/los.h b/3dc/avp/los.h new file mode 100644 index 0000000..9e060e7 --- /dev/null +++ b/3dc/avp/los.h @@ -0,0 +1,50 @@ +/* routines which check an object to see if it is in the player's line of sight */ +extern int CameraCanSeeThisPosition_WithIgnore(DISPLAYBLOCK *ignoredObjectPtr,VECTORCH *positionPtr); + +extern void CheckForViewVectorIntersectionWith3dObject(DISPLAYBLOCK *dPtr); + +extern void CheckForVectorIntersectionWith3dObject(DISPLAYBLOCK *objectPtr, VECTORCH *viewVectorAlphaPtr, VECTORCH *viewVectorBetaPtr, int rigorous); + +/* General line of sight routine: (written for Roxby!) */ +extern int IsThisObjectVisibleFromThisPosition(DISPLAYBLOCK *objectPtr,VECTORCH *positionPtr,int maxRange); +/*KJL**************************************************** +* dPtr - DISPLAYBLOCK* target * +* positionPtr - VECTORCH* co-ord from which to look * +* maxRange - int maximum range in metres to look * +****************************************************KJL*/ + +/* KJL 18:17:46 16/05/98 - check for an object's visibility, but ignore an object - e.g. ignore the character which is looking */ +extern int IsThisObjectVisibleFromThisPosition_WithIgnore(DISPLAYBLOCK *objectPtr,DISPLAYBLOCK *ignoredObjectPtr,VECTORCH *positionPtr,int maxRange); + +void FindPolygonInLineOfSight(VECTORCH *viewpointDirectionPtr, VECTORCH *viewpointPositionPtr, int useOnScreenBlockList, DISPLAYBLOCK *objectToIgnorePtr); +void FindPolygonInLineOfSight_TwoIgnores(VECTORCH *viewpointDirectionPtr, VECTORCH *viewpointPositionPtr, int useOnScreenBlockList, DISPLAYBLOCK *objectToIgnorePtr,DISPLAYBLOCK *next_objectToIgnorePtr); + +/* Line Of Sight data */ +extern VECTORCH LOS_Point; /* point in world space which player has hit */ +extern int LOS_Lambda; /* distance in mm to point from player */ +extern DISPLAYBLOCK* LOS_ObjectHitPtr; /* pointer to object that was hit */ +extern VECTORCH LOS_ObjectNormal; /* normal of the object's face which was hit */ +extern SECTION_DATA* LOS_HModel_Section; /* Section of HModel hit */ + +/*KJL********************************************************************************** +* The interface for this function is a bit muddle since it was originally a static fn * +* used by the dynamics system. * +* * +* Input: (in world space) * +* dPtr - target object (in world space) * +* viewVectorAlphaPtr - starting point of view-line * +* viewVectorBetaPtr - direction of view-line (NORMALISED) * +* * +* WARNING! the contents of the above vectors will be changed! * +* * +* also set * +* * +* LOS_ObjectHitPtr - to zero (GLOBAL VARIABLE) * +* LOS_Lambda - to max range in mm (GLOBAL VARIABLE) * +* * +* Output: * +* LOS_ObjectHitPtr - dPtr of hit object * +* LOS_Lambda - distance to hit polygon (or max if no hit) * +* LOS_Point - world space coords of intersection of line & hit poly * +* LOS_ObjectNormal - normal of the hit polygon * +**********************************************************************************KJL*/ diff --git a/3dc/avp/ltfx_exp.h b/3dc/avp/ltfx_exp.h new file mode 100644 index 0000000..acf91f4 --- /dev/null +++ b/3dc/avp/ltfx_exp.h @@ -0,0 +1,53 @@ +#ifndef _ltfx_exp_h +#define _ltfx_exp_h 1 + +#ifdef __cplusplus + +extern "C" +{ + +#endif + +typedef enum +{ + + LFX_RandomFlicker, + LFX_Strobe, + LFX_Switch, + LFX_FlickySwitch, + +} LIGHT_FX_TYPE; + +typedef enum +{ + + LFXS_LightOn, + LFXS_LightOff, + LFXS_LightFadingUp, + LFXS_LightFadingDown, + LFXS_Flicking, + LFXS_NotFlicking, + +} LIGHT_FX_STATE; + +typedef struct +{ + + unsigned long type; + unsigned long init_state; + + unsigned long fade_up_speed; + unsigned long fade_down_speed; + + unsigned long post_fade_up_delay; + unsigned long post_fade_down_delay; + +} LightFXData; + +#ifdef __cplusplus + +}; + +#endif + +#endif \ No newline at end of file diff --git a/3dc/avp/mempool.c b/3dc/avp/mempool.c new file mode 100644 index 0000000..46de25d --- /dev/null +++ b/3dc/avp/mempool.c @@ -0,0 +1,60 @@ +#include "ourasert.h" +#include "mem3dc.h" +#include "mempool.h" + + +#if USE_LEVEL_MEMORY_POOL + +#define MAX_NUM_MEMORY_BLOCK 40 +#define MEMORY_BLOCK_SIZE (1024*1024) + +static char* MemoryBlocks[MAX_NUM_MEMORY_BLOCK]; +static int CurrentMemoryBlock =-1; + +static char* MemoryPoolPtr=0; +static unsigned int MemoryLeft=0; + + +void* PoolAllocateMem(unsigned int amount) +{ + char* retval; + + GLOBALASSERT(amount<=MEMORY_BLOCK_SIZE) + + if(amount>MemoryLeft) + { + CurrentMemoryBlock++; + GLOBALASSERT(CurrentMemoryBlock ONE_FIXED * 30) + { + selection = DEMO_ITEM; + } + #endif + + #endif + + } + + UnLoadMenuGraphics(CHOOSE_GAMESTART); + return(selection); +} + + +int ChooseCharacterMenu(void) +{ + int a,current_item = MARINE_ITEM; + int selection = -1, debounce = 0; + + // initialise + for (a=0; a= MAX_CHARACTER_MENU_ITEMS) + { + current_item = ALIEN_ITEM; + } + + #if PSX_DEMO + if (current_item==ALIEN_ITEM) current_item++; + #endif + CurrentMenuStatus[current_item]=1; + + MenuChangeSound(); + } + else if (IDemandTurnLeft() && debounce) + { + debounce=0; + CurrentMenuStatus[current_item]=0; + current_item--; + #if PSX_DEMO + if (current_item==PREDATOR_ITEM) current_item--; + if (current_item==ALIEN_ITEM) current_item--; + #endif + if (current_item < 0) + { + current_item = MAX_CHARACTER_MENU_ITEMS - 1; + } + CurrentMenuStatus[current_item]=1; + + MenuChangeSound(); + } + else if (IDemandSelect() && debounce) + { + debounce=0; + selection=current_item; + + MenuSelectSound(); + } + else if ((IDemandTurnLeft()==0) && (IDemandTurnRight()==0) && (IDemandSelect()==0)) + { + debounce=1; + } + DrawEntireMenuScreen(); + SoundSys_Management(); + + } + + UnLoadMenuGraphics(CHOOSE_CHARACTER); + return(selection); +} + + +int AlienBriefingMenu(void) +{ + int a,current_item,selection,debounce; + + LoadMenuGraphics(ALIEN_BRIEFING); + + for (a=0; a MissionHint :: List_pMissionHint; + /*static*/ List MissionObjective :: List_pMissionObjective; + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ + +// class MissionHint +// Friends +// Public methods: +MissionHint :: MissionHint +( + enum TEXTSTRING_ID I_TextString_Description, + OurBool bVisible_New +) : I_TextString_Description_Val + ( + I_TextString_Description + ), + bVisible_Val( bVisible_New ) +{ + List_pMissionHint . add_entry(this); +} + +MissionHint :: ~MissionHint() +{ + List_pMissionHint . delete_entry(this); +} + + +// Protected methods: + +// Private methods: + +#if 0 +// class MissionEvent +// public: +// protected: +MissionEvent :: MissionEvent +( + enum TEXTSTRING_ID I_TextString_TriggeringFeedback, + enum MissionEffects MissionFX +) : I_TextString_TriggeringFeedback_Val + ( + I_TextString_TriggeringFeedback + ), + MissionFX_Val( MissionFX ) +{ + List_pMissionEvent . add_entry(this); +} + +MissionEvent :: ~MissionEvent() +{ + List_pMissionEvent . delete_entry(this); +} + +// private: +#endif + + +// class MissionObjective +// public: +extern "C" +{ +//function for triggering mission objective that can be called from a c file +void MissionObjectiveTriggered(void* mission_objective) +{ + GLOBALASSERT(mission_objective); + ((MissionObjective*)mission_objective)->OnTriggering(); +} +void MakeMissionPossible(void* mission_objective) +{ + GLOBALASSERT(mission_objective); + ((MissionObjective*)mission_objective)->MakePossible(); +} +void MakeMissionVisible(void* mission_objective) +{ + GLOBALASSERT(mission_objective); + ((MissionObjective*)mission_objective)->MakeVisible(); +} + +void ResetMission(void* mission_objective) +{ + GLOBALASSERT(mission_objective); + ((MissionObjective*)mission_objective)->ResetMission(); +} + +int GetMissionStateForSave(void* mission_objective) +{ + GLOBALASSERT(mission_objective); + + return (int) ((MissionObjective*)mission_objective)->GetMOS(); +} + +void SetMissionStateFromLoad(void* mission_objective,int state) +{ + GLOBALASSERT(mission_objective); + ((MissionObjective*)mission_objective)->SetMOS_Public((MissionObjectiveState)state); +} + +void PrintStringTableEntryInConsole(enum TEXTSTRING_ID string_id) +{ + #if UseGadgets + SCString* pSCString = &StringTable :: GetSCString + ( + string_id + ); + pSCString -> SendToScreen(); + pSCString -> R_Release(); + #endif // UseGadgets + /* KJL 99/2/5 - play 'incoming message' sound */ + switch(AvP.PlayerType) + { + case I_Marine: + { + Sound_Play(SID_CONSOLE_MARINEMESSAGE,NULL); + break; + } + case I_Predator: + { + Sound_Play(SID_CONSOLE_PREDATORMESSAGE,NULL); + break; + } + case I_Alien: + { + Sound_Play(SID_CONSOLE_ALIENMESSAGE,NULL); + break; + } + default: + break; + } + // add to message history + MessageHistory_Add(string_id); +} +}; + +void MissionObjective :: OnTriggering(void) +{ + textprint + ( + "MissionObjective :: OnTriggering() called\n" + ); + + if(!bAchievable()) return; + + if ( !bAchieved() ) + { + // Update hint visibilities: + { + SetMOS( MOS_VisibleAndAchieved ); + } + + // Send triggering message to the screen: + if (I_TextString_TriggeringFeedback_Val) + { + #if UseGadgets + SCString* pSCString_Feedback = &StringTable :: GetSCString + ( + I_TextString_TriggeringFeedback_Val + ); + pSCString_Feedback -> SendToScreen(); + pSCString_Feedback -> R_Release(); + #endif // UseGadgets + } + + // Any further effects? e.g. next objective appears? + { + switch ( MissionFX_Val ) + { + case MissionFX_None: + // Do nothing + break; + + case MissionFX_UncoversNext: + // Reveal next objective in list... + { + MissionObjective* pNext = + ( + List_pMissionObjective . next_entry(this) + ); + + if ( pNext ) + { + pNext->MakeVisible(); + } + + } + break; + + case MissionFX_CompletesLevel: + { + //complete level unless we are in paintball mode + if(!PaintBallMode.IsOn) + { + AvP.LevelCompleted = 1; + // AvP.MainLoopRunning = 0; + } + break; + } + case MissionFX_FailsLevel: + { + // unwritten + } + break; + + default: + GLOBALASSERT(0); + break; + } + } + //go through the list of mission alterations + for(LIF ma_lif(&List_pMissionAlteration);!ma_lif.done();ma_lif.next()) + { + if(ma_lif()->alteration_to_mission & MissionAlteration_MakeVisible) + { + ma_lif()->mission_objective->MakeVisible(); + + } + if(ma_lif()->alteration_to_mission & MissionAlteration_MakePossible) + { + ma_lif()->mission_objective->MakePossible(); + } + } + + } + // otherwise already achieved; ignore +} + +void MissionObjective :: MakeVisible() +{ + BOOL has_become_visible=FALSE; + switch(MOS_Val) + { + default: + GLOBALASSERT(0); + break; + case MOS_JustAHint: + break; + case MOS_HiddenUnachieved: + SetMOS( MOS_VisibleUnachieved ); + has_become_visible=TRUE; + break; + case MOS_HiddenUnachievedNotPossible: + SetMOS( MOS_VisibleUnachievedNotPossible ); + has_become_visible=TRUE; + break; + case MOS_VisibleUnachieved: + break; + case MOS_VisibleUnachievedNotPossible: + break; + case MOS_VisibleAndAchieved: + break; + + } + + if(has_become_visible)//send objective text to console + { + { + #if UseGadgets + SCString* pSCString_Description = &StringTable :: GetSCString + ( + I_TextString_Description_Val + ); + + pSCString_Description -> SendToScreen(); + + pSCString_Description -> R_Release(); + #endif // UseGadgets + } + } +} + +void MissionObjective :: MakePossible() +{ + switch(MOS_Val) + { + default: + GLOBALASSERT(0); + break; + case MOS_JustAHint: + break; + case MOS_HiddenUnachieved: + break; + case MOS_HiddenUnachievedNotPossible: + SetMOS( MOS_HiddenUnachieved); + break; + case MOS_VisibleUnachieved: + break; + case MOS_VisibleUnachievedNotPossible: + SetMOS( MOS_VisibleUnachieved); + break; + case MOS_VisibleAndAchieved: + break; + + } +} + +MissionObjective :: MissionObjective +( + enum TEXTSTRING_ID I_TextString_Description, + enum MissionObjectiveState MOS_New, + + enum TEXTSTRING_ID I_TextString_TriggeringFeedback, + enum MissionEffects MissionFX + +) : aMissionHint_Incomplete + ( + I_TextString_Description, // enum TEXTSTRING_ID I_TextString_Description, + ( + bVisible( MOS_New ) + && + !bComplete( MOS_New ) + ) // OurBool bVisible_New + ), + aMissionHint_Complete + ( + I_TextString_TriggeringFeedback, // enum TEXTSTRING_ID I_TextString_Description, + ( + bVisible( MOS_New ) + && + bComplete( MOS_New ) + ) // OurBool bVisible_New + ), + I_TextString_Description_Val( I_TextString_Description ), + I_TextString_TriggeringFeedback_Val( I_TextString_TriggeringFeedback ), + MissionFX_Val( MissionFX ), + MOS_Val( MOS_New ), + initial_MOS_Val( MOS_New ) +{ + List_pMissionObjective . add_entry(this); +} + +MissionObjective :: ~MissionObjective() +{ + List_pMissionObjective . delete_entry(this); + + while(List_pMissionAlteration.size()) + { + delete List_pMissionAlteration.first_entry(); + List_pMissionAlteration.delete_first_entry(); + } +} + +// private: +void MissionObjective :: SetMOS( MissionObjectiveState MOS_New ) +{ + if ( MOS_Val != MOS_New ) + { + MOS_Val = MOS_New; + + aMissionHint_Incomplete . SetVisibility + ( + bVisible( MOS_New ) + && + !bComplete( MOS_New ) + ); + + aMissionHint_Complete . SetVisibility + ( + bVisible( MOS_New ) + && + bComplete( MOS_New ) + ); + } +} + +void MissionObjective::AddMissionAlteration(MissionObjective* mission_objective,int alteration_to_mission) +{ + GLOBALASSERT(mission_objective); + MissionAlteration* ma=new MissionAlteration; + ma->mission_objective=mission_objective; + ma->alteration_to_mission=alteration_to_mission; + List_pMissionAlteration.add_entry(ma); +} + +void MissionObjective::ResetMission() +{ + MOS_Val=initial_MOS_Val; +} + +// Suggested mission objectives for GENSHD1: +void MissionHacks :: TestInit(void) +{ + #if 0 + #if 1 + new MissionHint + ( + TEXTSTRING_LEVELMSG_001, // ProjChar* pProjCh_Description, + Yes // OurBool bVisible + ); + #endif + + new MissionObjective + ( + TEXTSTRING_LEVELMSG_002, // ProjChar* pProjCh_Description, + MOS_VisibleUnachieved, // enum MissionObjectiveState MOS_New, + + TEXTSTRING_LEVELMSG_003, // ProjChar* pProjCh_TriggeringFeedback, + MissionFX_UncoversNext // enum MissionEffects MissionFX, + ); + + new MissionObjective + ( + TEXTSTRING_LEVELMSG_004, // ProjChar* pProjCh_Description, + MOS_HiddenUnachieved, // enum MissionObjectiveState MOS_New, + + TEXTSTRING_LEVELMSG_005, // ProjChar* pProjCh_TriggeringFeedback, + MissionFX_UncoversNext // enum MissionEffects MissionFX, + ); + + new MissionObjective + ( + TEXTSTRING_LEVELMSG_006, // ProjChar* pProjCh_Description, + MOS_HiddenUnachieved, // enum MissionObjectiveState MOS_New, + + TEXTSTRING_LEVELMSG_007, // ProjChar* pProjCh_TriggeringFeedback, + MissionFX_UncoversNext // enum MissionEffects MissionFX, + ); + + new MissionObjective + ( + TEXTSTRING_LEVELMSG_008, // ProjChar* pProjCh_Description, + MOS_HiddenUnachieved, // enum MissionObjectiveState MOS_New, + + TEXTSTRING_LEVELMSG_009, // ProjChar* pProjCh_TriggeringFeedback, + MissionFX_UncoversNext // enum MissionEffects MissionFX, + ); + + new MissionObjective + ( + TEXTSTRING_LEVELMSG_010, // ProjChar* pProjCh_Description, + MOS_HiddenUnachieved, // enum MissionObjectiveState MOS_New, + + TEXTSTRING_LEVELMSG_011, // ProjChar* pProjCh_TriggeringFeedback, + MissionFX_CompletesLevel // enum MissionEffects MissionFX, + ); + #endif +} + +void MissionObjective :: TestCompleteNext(void) +{ + // Do it: + { + MissionObjective* pMissionObjective = NULL; + + for + ( + LIF oi(&List_pMissionObjective); + !oi.done(); + oi.next() + ) + { + if + ( + !oi() -> bAchieved() + ) + { + pMissionObjective = oi(); + break; + } + } + + if ( pMissionObjective ) + { + GLOBALASSERT( pMissionObjective ); + + // Feedback: + { + #if UseGadgets + + SCString* pSCString_Temp = new SCString("TESTING MISSION COMPLETION HOOK:"); + + pSCString_Temp -> SendToScreen(); + + pSCString_Temp -> R_Release(); + #endif // UseGadgets + + } + + pMissionObjective -> OnTriggering(); + } + else + { + // Feedback: + { + #if UseGadgets + + SCString* pSCString_Temp = new SCString("NO INCOMPLETE OBJECTIVES"); + + pSCString_Temp -> SendToScreen(); + + pSCString_Temp -> R_Release(); + #endif // UseGadgets + } + } + } + +} + + + +/* Internal function definitions ***********************************/ + + + + + + + +#if 0 + "BACKUP POWER SYSTEM ACTIVATED", // ProjChar* pProjCh_TriggeringFeedback, + MissionFX_None // enum MissionEffects MissionFX, + ); + + new MissionObjective + ( + "SECURITY DOORS RESTRICT ACCESS WITHIN THE COLONY. FIND THE OPERATIONS ROOM IN THE MAIN BUILDING. " + "INSIDE ARE FIVE SWITCHES. TRIGGER ALL OF THEM TO OPEN THE SECURITY DOORS REMOTELY. " + , // ProjChar* pProjCh_Description, + Yes, // OurBool bHidden + + "SECURITY DOOR EMERGENCY OVERRIDE TRIGGERED: DOORS HAVE BEEN OPENED. ", // ProjChar* pProjCh_TriggeringFeedback, + MissionFX_None // enum MissionEffects MissionFX, + ); + + new MissionObjective + ( + "MAKE YOUR WAY TO MEDLAB. COLLECT COMPUTER ARCHIVES " + "DOCUMENTING THE COLONISTS WORK ON THE FACEHUGGERS. " + , // ProjChar* pProjCh_Description, + Yes, // OurBool bHidden + + "PARTIAL MEDLAB ARCHIVE COLLECTED", // ProjChar* pProjCh_TriggeringFeedback, + MissionFX_None // enum MissionEffects MissionFX, + ); + + new MissionObjective + ( + "THE MEDLAB ARCHIVE YOU HAVE COLLECTED IS ONLY ONE OF THREE FILES. " + "WE'VE GOT A PDT READING ON THE MEDLAB OFFICER WHO WAS RESEARCHING THE FACEHUGGERS. " + "IT'S COMING FROM THE BASEMENT OF THE PROCESSOR PLANT. " + "SHE MIGHT BE ALIVE, BUT IT'S PROBABLY JUST HER REMAINS. " + "MAKE YOUR WAY THERE AND TRY TO FIND MORE ARCHIVES. " + , // ProjChar* pProjCh_Description, + Yes, // OurBool bHidden + + "MEDLAB ARCHIVE COLLECTED", // ProjChar* pProjCh_TriggeringFeedback, + MissionFX_None // enum MissionEffects MissionFX, + ); + + new MissionObjective + ( + "THAT LOOKS LIKE ALL THE FILES. " + "GET BACK TO THE YARD. THE LANDING BEACON CONTROLS ARE IN A RECESS TO THE LEFT OF THE " + "ATMOSPHERE PROCESSOR. ACTIVATE THE BEACON AND PREPARE FOR EVAC." + , // ProjChar* pProjCh_Description, + Yes, // OurBool bHidden + + "LANDING BEACON ACTIVATED. STAND CLEAR AND PREPARE FOR EVAC. ", // ProjChar* pProjCh_TriggeringFeedback, +#endif \ No newline at end of file diff --git a/3dc/avp/missions.hpp b/3dc/avp/missions.hpp new file mode 100644 index 0000000..807b883 --- /dev/null +++ b/3dc/avp/missions.hpp @@ -0,0 +1,272 @@ +/* + + missions.hpp + +*/ + +#ifndef _missions +#define _missions 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + + #ifndef _scstring + #include "scstring.hpp" + #endif + + #ifndef _langenum_h_ + #include "langenum.h" + #endif + + #ifndef _strtab + #include "strtab.hpp" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + #define WithinTheGame Yes + // as opposed to within the editor + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + // Enum for what can happen when a mission event is triggered; these + // effects are "meta-events" e.g. the levels is completed. These are + // post-processing after the rest of the mission event processing occurs. + enum MissionEffects + { + MissionFX_None = 0, + + MissionFX_UncoversNext, + + MissionFX_CompletesLevel, + + // Possibility of: + // MissionFX_CompletesLevelSpecial + // which takes you to a hidden level for power-ups? + + MissionFX_FailsLevel, + + NUM_MISSION_EFFECTS + }; // suggested naming: MissionFX + + enum MissionObjectiveState + { + MOS_JustAHint = 0, + MOS_HiddenUnachieved, + MOS_HiddenUnachievedNotPossible, + MOS_VisibleUnachieved, + MOS_VisibleUnachievedNotPossible, + MOS_VisibleAndAchieved, + + NUM_MOS + }; + + class MissionHint + { + // Friends + + // Public methods: + public: + MissionHint + ( + enum TEXTSTRING_ID I_TextString_Description, + OurBool bVisible_New + ); + virtual ~MissionHint(); + + SCString* GetDesc(void) const; + + OurBool bVisible(void) const; + + void SetVisibility + ( + OurBool bVisible_New + ); + + static const List& GetAll(void); + + // Protected methods: + protected: + + // Private methods: + private: + + // Private data: + private: + enum TEXTSTRING_ID I_TextString_Description_Val; + OurBool bVisible_Val; + + static List List_pMissionHint; + + }; + // Inline methods: + inline SCString* MissionHint::GetDesc(void) const + { + return &StringTable :: GetSCString + ( + I_TextString_Description_Val + ); + } + inline OurBool MissionHint::bVisible(void) const + { + return bVisible_Val; + } + inline void MissionHint::SetVisibility + ( + OurBool bVisible_New + ) + { + bVisible_Val = bVisible_New; + } + inline /*static*/ const List& MissionHint::GetAll(void) + { + return List_pMissionHint; + } + + + #if 0 + class MissionEvent + { + public: + virtual void OnTriggering(void) = 0; + + virtual ~MissionEvent(); + + protected: + MissionEvent + ( + enum TEXTSTRING_ID I_TextString_TriggeringFeedback, + enum MissionEffects MissionFX + ); + + protected: + enum MissionEffects MissionFX_Val; + + private: + enum TEXTSTRING_ID I_TextString_TriggeringFeedback_Val; + + static List List_pMissionEvent; + }; + #endif + + class MissionObjective; + #define MissionAlteration_MakeVisible 0x00000001 + #define MissionAlteration_MakePossible 0x00000002 + //when a mission is achieved it can alter the visibility and doability of other mission objectives + struct MissionAlteration + { + MissionObjective* mission_objective; + int alteration_to_mission; + }; + + class MissionObjective + { + public: + void OnTriggering(void); + + MissionObjective + ( + enum TEXTSTRING_ID I_TextString_Description, + enum MissionObjectiveState MOS, + + enum TEXTSTRING_ID I_TextString_TriggeringFeedback, + enum MissionEffects MissionFX + ); + + ~MissionObjective(); + + static void TestCompleteNext(void); + + int bAchieved(void) const; + + void AddMissionAlteration(MissionObjective* mission_objective,int alteration_to_mission); + + void MakeVisible(); + void MakePossible(); + void ResetMission(); //restores objective to start of level state + + MissionObjectiveState GetMOS() {return MOS_Val;}; + void SetMOS_Public(MissionObjectiveState MOS_New) {SetMOS(MOS_New);} ; + + private: + void SetMOS( MissionObjectiveState MOS_New ); + + private: + #if WithinTheGame + MissionHint aMissionHint_Incomplete; + MissionHint aMissionHint_Complete; + #endif + + enum TEXTSTRING_ID I_TextString_Description_Val; + + enum TEXTSTRING_ID I_TextString_TriggeringFeedback_Val; + enum MissionEffects MissionFX_Val; + + enum MissionObjectiveState MOS_Val; + enum MissionObjectiveState initial_MOS_Val; + + + static List List_pMissionObjective; + + List List_pMissionAlteration; + + public: + int bAchievable(void) const + { + return ( MOS_Val != MOS_HiddenUnachievedNotPossible && + MOS_Val != MOS_VisibleUnachievedNotPossible); + } + + private: + static int bVisible + ( + enum MissionObjectiveState MOS_In + ) + { + return ( MOS_In != MOS_HiddenUnachieved && + MOS_In != MOS_HiddenUnachievedNotPossible); + } + + static int bComplete + ( + enum MissionObjectiveState MOS_In + ) + { + return ( MOS_In == MOS_VisibleAndAchieved ); + } + + }; + + inline int MissionObjective::bAchieved(void) const + { + return bComplete( MOS_Val ); + } + + + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + namespace MissionHacks + { + void TestInit(void); + }; + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif + diff --git a/3dc/avp/movement.c b/3dc/avp/movement.c new file mode 100644 index 0000000..ff43511 --- /dev/null +++ b/3dc/avp/movement.c @@ -0,0 +1,121 @@ +/* CDF 20/10/98 - Single file for the movement stat lists. */ + +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "comp_shp.h" +#include "dynblock.h" +#include "dynamics.h" +#include "pfarlocs.h" +#include "pheromon.h" +#include "bh_types.h" +#include "pvisible.h" +#include "bh_far.h" +#include "bh_debri.h" +#include "bh_pred.h" +#include "bh_paq.h" +#include "bh_queen.h" +#include "bh_marin.h" +#include "bh_alien.h" +#include "lighting.h" +#include "bh_weap.h" +#include "weapons.h" +#include "psnd.h" +#include "equipmnt.h" +#include "los.h" +#include "AI_Sight.h" +#include "targeting.h" +#include "dxlog.h" +#include "ShowCmds.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +/* First number is max speed, in mm/s. */ +/* Second number is acceleration, in mm/s^2. */ +/* Individual marines vary this by +/- 12.5%. */ +/* Predators and xenoborgs don't at the moment. */ + +static MOVEMENT_DATA Movement_Stats[] = { + { + MDI_Marine_Mooch_Bored, + 1500, + 1500, + }, + { + MDI_Marine_Mooch_Alert, + 1500, + 1500, + }, + { + MDI_Marine_Combat, + 4000, + 4000, + }, + { + MDI_Marine_Sprint, + 10000, + 10000, + }, + { + MDI_Civilian_Mooch_Bored, + 1500, + 1500, + }, + { + MDI_Civilian_Mooch_Alert, + 1500, + 1500, + }, + { + MDI_Civilian_Combat, + 4000, + 4000, + }, + { + MDI_Civilian_Sprint, + 10000, + 10000, + }, + { + MDI_Predator, + 8000, + 10000, + }, + { + MDI_Casual_Predator, + 3000, + 3000, + }, + { + MDI_Xenoborg, + 1000, + 1000, + }, + { + MDI_End, + 0, + 0, + }, +}; + +MOVEMENT_DATA *GetThisMovementData(MOVEMENT_DATA_INDEX index) { + + int a; + + if (index<0) { + return(NULL); + } + + a=0; + while (Movement_Stats[a].index!=MDI_End) { + if (Movement_Stats[a].index==index) { + return(&Movement_Stats[a]); + } + a++; + GLOBALASSERT(a<1000); + } + return(NULL); +} diff --git a/3dc/avp/mp_launch.c b/3dc/avp/mp_launch.c new file mode 100644 index 0000000..4ac44a5 --- /dev/null +++ b/3dc/avp/mp_launch.c @@ -0,0 +1,115 @@ +// Launches mplayer.com into a specific URL with LaunchMplayer() +// By Rich Rice --rich@mpath.com +// Modified by Edmond Meinfelder (edmond@mpath.com) for use with AvP + +#include +#include +#include + +#ifdef _MSC_VER + #define stat _stat +#endif + +// Execute executes whatever the text in cmdline is. +// If an executable is successfully launched as a +// result, TRUE is returned. False is returned if +// nothing happens. + +static int +Execute(char *cmdline) +{ + STARTUPINFO StartupInfo; + PROCESS_INFORMATION ProcessInfo; + + memset (&StartupInfo, 0, sizeof StartupInfo); + StartupInfo.cb = sizeof (StartupInfo); + StartupInfo.dwFlags = STARTF_USESHOWWINDOW; + StartupInfo.wShowWindow = SW_SHOWNORMAL; + + if (CreateProcess(NULL, cmdline, NULL, NULL, FALSE, + CREATE_DEFAULT_ERROR_MODE, NULL, NULL, + &StartupInfo, &ProcessInfo) == 0) + return FALSE; + + return TRUE; +} + +// Mplayer stores it installed location in the Windows Registry +// under HKEY_LOCAL_MACHINE\Software\Mplayer\Main\Root Directory +// This function returns the location stored in that string value. +// Upon failure, FALSE is returned and, upon success, TRUE is +// returned. +// The location of the Mplayer's install path is returned in +// the parameter mplayer_directory. + +static int +GetMplayerDirectory(char *mplayer_directory) +{ + HKEY hkey; + HKEY key = HKEY_LOCAL_MACHINE; + char subkey[]="software\\mpath\\mplayer\\main"; + char valuename[]="root directory"; + char buffer[MAX_PATH]; + DWORD dwType, dwSize; + + + if (RegOpenKeyEx(key, subkey, 0, KEY_READ, &hkey) == ERROR_SUCCESS) + { + dwSize = MAX_PATH; + if (RegQueryValueEx(hkey, valuename, 0, &dwType, (LPBYTE) buffer, + &dwSize) == ERROR_SUCCESS) + { + sprintf(mplayer_directory, "%s", buffer); + return TRUE; + } + RegCloseKey(hkey); + } + + return FALSE; +} + +// If the named file exists, this function +// returns TRUE, otherwise FALSE is returned. + +static int +FileExists(char *file) +{ + struct stat buf; + int result; + + // Get data associated with 'file' + result = stat( file, &buf ); + + // Check if we have a file + if( result == 0 ) + { + return TRUE; + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +// This is the only public function, it launches Mplayer's user interface. +// This function returns FALSE upon failure and TRUE on success. + +int +LaunchMplayer() +{ + char mplayer_url[]="http://www.mplayer.com/mic/avp.html"; + char cmdline[MAX_PATH], mplaunch_exe[MAX_PATH], mplayer_directory[MAX_PATH]; + + if (GetMplayerDirectory(mplayer_directory)) + { + sprintf(mplaunch_exe, "%s\\programs\\mplaunch.exe", mplayer_directory); + if (FileExists(mplaunch_exe)) + { + sprintf(cmdline, "%s AvP.mpi", mplaunch_exe); + return Execute(cmdline); + } + } + + sprintf(cmdline, "rundll32.exe url.dll,FileProtocolHandler %s", mplayer_url); + return Execute(cmdline); +} diff --git a/3dc/avp/particle.c b/3dc/avp/particle.c new file mode 100644 index 0000000..c57c59b --- /dev/null +++ b/3dc/avp/particle.c @@ -0,0 +1,5671 @@ +/* KJL 14:50:53 10/13/97 - + * + * Experimental particle system + * + */ + +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "dynblock.h" +#include "dynamics.h" +#include "particle.h" +#include "kshape.h" +#include "sfx.h" +#include "d3d_render.h" +#include "psndproj.h" +#include "lighting.h" +#include "bh_light.h" +#include "bh_xeno.h" +#include "pvisible.h" +#include "sphere.h" +#include "bh_rubberduck.h" +#include "bh_weap.h" +#include "avpview.h" +#include "pldghost.h" +#include "detaillevels.h" +#include "psnd.h" +#include "avp_userprofile.h" +#define UseLocalAssert Yes +#include "ourasert.h" +#include "savegame.h" +#include "los.h" + +#include + +#define RGBALIGHT_MAKE(r,g,b,a) RGBA_MAKE(r,g,b,a) + +#define MAX_NO_OF_PHEROMONE_TRAILS 500 +#define MAX_NO_OF_PARTICLES 5000 +#define MAX_NO_OF_EXPLOSIONS 10 + +#define TRAIL_DECAY_SPEED (51*65536*5) + +static PHEROMONE_TRAIL TrailStorage[MAX_NO_OF_PHEROMONE_TRAILS]; +static PARTICLE ParticleStorage[MAX_NO_OF_PARTICLES]; +static VOLUMETRIC_EXPLOSION ExplosionStorage[MAX_NO_OF_EXPLOSIONS]; + +static int NumActiveTrails; +static int NumActiveParticles; +static int CurrentExplosionIndex; + +extern int NormalFrameTime; +extern int PrevNormalFrameTime; +extern int CloakingPhase; + +int NumberOfBloodParticles; +int NumberOfFlaresActive; + +extern SOUND3DDATA PredPistolExplosion_SoundData; +extern MODULE *playerPherModule; + +static void InitialiseVolumetricExplosions(void); +void DoFlareCorona(DISPLAYBLOCK *objectPtr); +void InitialiseRainDrops(void); +void HandleRipples(void); +void AddRipple(int x,int z,int amplitude); +void MakeMolotovExplosionAt(VECTORCH *positionPtr,int seed); +static void HandleVolumetricExplosion(VOLUMETRIC_EXPLOSION *expPtr); +void DrawXenoborgMainLaserbeam(LASER_BEAM_DESC *laserPtr); +void HandlePheromoneTrails(void); +void RenderTrailSegment(PHEROMONE_TRAIL *trailPtr); + +PARTICLE_DESC ParticleDescription[MAX_NO_OF_PARTICLE_IDS] = +{ + /* PARTICLE_PREDATOR_BLOOD */ + { + //int StartU; + 0<<16, + //int StartV; + 64<<16, + //int EndU; + 63<<16, + //int EndV; + 127<<16, + //unsigned int Size; + 200, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 128, + //unsigned char RedScale; + {0, 0, 255, 255, 255}, + //unsigned char GreenScale; + {255, 255, 255, 255, 0}, + //unsigned char BlueScale; + {0, 0, 255, 255, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + + }, + /* PARTICLE_ALIEN_BLOOD */ + { +#if 0 + //int StartU; + 1<<16, + //int StartV; + 248<<16, + //int EndU; + 8<<16, + //int EndV; + 256<<16, +#else + //int StartU; + 0<<16, + //int StartV; + 64<<16, + //int EndU; + 63<<16, + //int EndV; + 127<<16, +#endif + //unsigned int Size; + 50, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 128, + //unsigned char RedScale; + {255, 255, 0, 16, 255}, + //unsigned char GreenScale; + {255, 255, 255, 0, 255}, + //unsigned char BlueScale; + {0, 0, 0, 255, 255}, + + //unsigned char IsLit:1; + 1, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + + }, + /* PARTICLE_HUMAN_BLOOD */ + { + //int StartU; + 0<<16, + //int StartV; + 63<<16, + //int EndU; + 63<<16, + //int EndV; + 127<<16, + //unsigned int Size; + 50, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_INVCOLOUR, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {0, 0, 0, 0 , 0}, + //unsigned char GreenScale; + {255, 255, 64, 64, 255}, + //unsigned char BlueScale; + {255, 255, 0, 64, 255}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_ANDROID_BLOOD */ + { + //int StartU; + 0<<16, + //int StartV; + 63<<16, + //int EndU; + 63<<16, + //int EndV; + 127<<16, + //unsigned int Size; + 50, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255, 255, 255, 255, 255}, + //unsigned char GreenScale; + {255, 255, 255, 255, 255}, + //unsigned char BlueScale; + {255, 255, 255, 255, 255}, + + //unsigned char IsLit:1; + 1, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_MUZZLEFLASH */ + { + //int StartU; + 64<<16, + //int StartV; + 64<<16, + //int EndU; + 127<<16, + //int EndV; + 127<<16, + //unsigned int Size; + 200, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255, 255, 255, 255, 255}, + //unsigned char GreenScale; + {192, 255, 255, 0 , 255}, + //unsigned char BlueScale; + {128, 255, 255, 0 , 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_SMARTGUNMUZZLEFLASH */ + { + //int StartU; + 64<<16, + //int StartV; + 0<<16, + //int EndU; + 127<<16, + //int EndV; + 63<<16, + //unsigned int Size; + 800, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255, 255, 255, 255, 255}, + //unsigned char GreenScale; + {255, 255, 255, 0, 255}, + //unsigned char BlueScale; + {255, 255, 255, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_WATERSPRAY */ + { + //int StartU; + 0<<16, + //int StartV; + 64<<16, + //int EndU; + 63<<16, + //int EndV; + 127<<16, + //unsigned int Size; + 80, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {200, 200, 0, 0}, + //unsigned char GreenScale; + {230, 230, 240, 0}, + //unsigned char BlueScale; + {255, 255, 0, 120}, + + //unsigned char IsLit:1; + 1, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_WATERFALLSPRAY */ + { + //int StartU; + 0<<16, + //int StartV; + 64<<16, + //int EndU; + 63<<16, + //int EndV; + 127<<16, + //unsigned int Size; + 1600,//200, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 32, + //unsigned char RedScale; + {100, 200, 240, 120, 120, 120}, + //unsigned char GreenScale; + {130, 230, 240, 120, 120, 120}, + //unsigned char BlueScale; + {255, 255, 240, 120, 120, 120}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_BLACKSMOKE */ + { + //int StartU; + 0<<16, + //int StartV; + 130<<16, + //int EndU; + 28<<16, + //int EndV; + 157<<16, + //unsigned int Size; + 200, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_INVCOLOUR, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {64, 64, 64, 64, 64}, + //unsigned char GreenScale; + {64, 64, 64, 64, 64}, + //unsigned char BlueScale; + {64, 64, 64, 64, 64}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_FLARESMOKE */ + { + #if 0 + //int StartU; + 0<<16, + //int StartV; + 130<<16, + //int EndU; + 28<<16, + //int EndV; + 157<<16, + #else + //int StartU; + 128<<16, + //int StartV; + 0<<16, + //int EndU; + 195<<16, + //int EndV; + 63<<16, + #endif + //unsigned int Size; + 200, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 255, 64}, + //unsigned char GreenScale; + {255, 255, 255, 0, 64}, + //unsigned char BlueScale; + {255, 255, 255, 64, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_STEAM */ + { + //int StartU; + 0<<16, + //int StartV; + 130<<16, + //int EndU; + 28<<16, + //int EndV; + 157<<16, + //unsigned int Size; + 100, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {128, 128, 128, 128, 64}, + //unsigned char GreenScale; + {128, 128, 128, 128, 64}, + //unsigned char BlueScale; + {128, 128, 128, 128, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_IMPACTSMOKE */ + { + //int StartU; + 0<<16, + //int StartV; + 130<<16, + //int EndU; + 28<<16, + //int EndV; + 157<<16, + //unsigned int Size; + 100, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_INVCOLOUR, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {64, 64, 64, 64, 64}, + //unsigned char GreenScale; + {64, 64, 64, 64, 64}, + //unsigned char BlueScale; + {64, 64, 64, 64, 64}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_GUNMUZZLE_SMOKE */ + { + //int StartU; + 128<<16, + //int StartV; + 0<<16, + //int EndU; + 195<<16, + //int EndV; + 63<<16, + //unsigned int Size; + 32, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 255, 64}, + //unsigned char GreenScale; + {255, 255, 255, 0, 64}, + //unsigned char BlueScale; + {255, 255, 255, 64, 0}, + + //unsigned char IsLit:1; + 1, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_FLAME */ + { + #if 0 + //int StartU; + 0<<16, + //int StartV; + 0<<16, + //int EndU; + 63<<16, + //int EndV; + 63<<16, + #else + //int StartU; + 64<<16, + //int StartV; + 0<<16, + //int EndU; + (64+127)<<16, + //int EndV; + 63<<16, + #endif + //unsigned int Size; + 0, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 128, 128, 0}, + //unsigned char GreenScale; + {128, 128, 255, 64, 64, 128}, + //unsigned char BlueScale; + {64, 64, 255, 255, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_NONCOLLIDINGFLAME */ + { + #if 0 + //int StartU; + 0<<16, + //int StartV; + 0<<16, + //int EndU; + 63<<16, + //int EndV; + 63<<16, + #else + //int StartU; + 64<<16, + //int StartV; + 0<<16, + //int EndU; + (64+127)<<16, + //int EndV; + 63<<16, + #endif + //unsigned int Size; + 0, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 128, 128, 0}, + //unsigned char GreenScale; + {128, 128, 255, 64, 64, 128}, + //unsigned char BlueScale; + {64, 64, 255, 255, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_NONDAMAGINGFLAME */ + { + #if 0 + //int StartU; + 0<<16, + //int StartV; + 0<<16, + //int EndU; + 63<<16, + //int EndV; + 63<<16, + #else + //int StartU; + 64<<16, + //int StartV; + 0<<16, + //int EndU; + (64+127)<<16, + //int EndV; + 63<<16, + #endif + //unsigned int Size; + 0, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 128, 128, 0}, + //unsigned char GreenScale; + {128, 128, 255, 64, 64, 128}, + //unsigned char BlueScale; + {64, 64, 255, 255, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_FIRE */ + { + #if 1 + //int StartU; + 0<<16, + //int StartV; + 0<<16, + //int EndU; + 63<<16, + //int EndV; + 63<<16, + #else + //int StartU; + 64<<16, + //int StartV; + 0<<16, + //int EndU; + (64+127)<<16, + //int EndV; + 63<<16, + #endif + + //unsigned int Size; + 0, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 128, 128, 0}, + //unsigned char GreenScale; + {128, 128, 255, 64, 64, 128}, + //unsigned char BlueScale; + {64, 64, 255, 255, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_EXPLOSIONFIRE */ + { + #if 0 + //int StartU; + 128<<16, + //int StartV; + 0<<16, + //int EndU; + 192<<16, + //int EndV; + 63<<16, + #else + //int StartU; + 0<<16, + //int StartV; + 0<<16, + //int EndU; + 48<<16, + //int EndV; + 63<<16, + #endif + //unsigned int Size; + 800, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255, 255, 255, 128, 128, 0}, + //unsigned char GreenScale; + {128, 128, 255, 64, 64, 128}, + //unsigned char BlueScale; + {64, 64, 255, 255, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_MOLOTOVFLAME */ + { + //int StartU; + 64<<16, + //int StartV; + 0<<16, + //int EndU; + (64+127)<<16, + //int EndV; + 63<<16, + //unsigned int Size; + 800, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255, 255, 255, 128, 128, 0}, + //unsigned char GreenScale; + {128, 128, 255, 64, 64, 128}, + //unsigned char BlueScale; + {64, 64, 255, 255, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_MOLOTOVFLAME_NONDAMAGING */ + { + //int StartU; + 64<<16, + //int StartV; + 0<<16, + //int EndU; + (64+127)<<16, + //int EndV; + 63<<16, + //unsigned int Size; + 800, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255, 255, 255, 128, 128, 0}, + //unsigned char GreenScale; + {128, 128, 255, 64, 64, 128}, + //unsigned char BlueScale; + {64, 64, 255, 255, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_SPARK */ + { + //int StartU; + 1<<16, + //int StartV; + 1<<16, + //int EndU; + 64<<16, + //int EndV; + 64<<16, + //unsigned int Size; + 200/8, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 255, 255}, + //unsigned char GreenScale; + {128, 128, 255, 0, 255}, + //unsigned char BlueScale; + {64, 64, 255, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_RICOCHET_SPARK */ + { + //int StartU; + 1<<16, + //int StartV; + 1<<16, + //int EndU; + 64<<16, + //int EndV; + 64<<16, + //unsigned int Size; + 200/8, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 255, 255}, + //unsigned char GreenScale; + {128, 128, 255, 0, 255}, + //unsigned char BlueScale; + {64, 64, 255, 0, 255}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_ORANGE_SPARK */ + { + //int StartU; + 224<<16, + //int StartV; + 192<<16, + //int EndU; + 255<<16, + //int EndV; + 223<<16, + //unsigned int Size; + 50, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255, 64, 64, 64, 64}, + //unsigned char GreenScale; + {255, 64, 64, 64, 64}, + //unsigned char BlueScale; + {255, 64, 64, 64, 64}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_ORANGE_PLASMA */ + { + //int StartU; + 224<<16, + //int StartV; + 192<<16, + //int EndU; + 255<<16, + //int EndV; + 223<<16, + //unsigned int Size; + 50, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255, 64, 64, 64, 64, 0}, + //unsigned char GreenScale; + {255, 64, 64, 64, 64, 64}, + //unsigned char BlueScale; + {255, 64, 64, 64, 64, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + + /* PARTICLE_PLASMATRAIL */ + { + //int StartU; + 64<<16, + //int StartV; + 64<<16, + //int EndU; + 127<<16, + //int EndV; + 127<<16, + //unsigned int Size; + 200/4, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 255, 255, 0}, + //unsigned char GreenScale; + {128, 128, 255, 0, 255, 255}, + //unsigned char BlueScale; + {64, 64, 255, 0, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_LASERBEAM */ + { + //int StartU; + 32<<16, + //int StartV; + 0<<16, + //int EndU; + 32<<16, + //int EndV; + 63<<16, + //unsigned int Size; + 50, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 255, 255, 0}, + //unsigned char GreenScale; + {128, 128, 255, 0, 255, 255}, + //unsigned char BlueScale; + {64, 64, 255, 0, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_PLASMABEAM */ + { + //int StartU; + 192<<16, + //int StartV; + 224<<16, + //int EndU; + 223<<16, + //int EndV; + 255<<16, + //unsigned int Size; + 50, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 255, 255, 0}, + //unsigned char GreenScale; + {128, 128, 255, 0, 255, 255}, + //unsigned char BlueScale; + {64, 64, 255, 0, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_TRACER */ + { + //int StartU; + 32<<16, + //int StartV; + 0<<16, + //int EndU; + 32<<16, + //int EndV; + 63<<16, + //unsigned int Size; + 16, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 255, 255}, + //unsigned char GreenScale; + {255, 128, 255, 0, 255}, + //unsigned char BlueScale; + {64, 64, 255, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + + + + /* PARTICLE_LIGHTFLARE */ + { + //int StartU; + 64<<16, + //int StartV; + 64<<16, + //int EndU; + 127<<16, + //int EndV; + 127<<16, + //unsigned int Size; + 200, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255, 255, 255, 255, 255, 0}, + //unsigned char GreenScale; + {255, 255, 255, 0, 255, 255}, + //unsigned char BlueScale; + {255, 255, 255, 0, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 1, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_STAR */ + { + //int StartU; + 64<<16, + //int StartV; + 64<<16, + //int EndU; + 127<<16, + //int EndV; + 127<<16, + //unsigned int Size; + 200, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255, 255, 255, 255, 255, 0}, + //unsigned char GreenScale; + {255, 255, 255, 0, 255, 255}, + //unsigned char BlueScale; + {255, 255, 255, 0, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 1, + }, + /* PARTICLE_FLECHETTE */ + { + //int StartU; + 64<<16, + //int StartV; + 64<<16, + //int EndU; + 127<<16, + //int EndV; + 127<<16, + //unsigned int Size; + 100, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_NORMAL, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255, 255, 255, 255, 255, 0}, + //unsigned char GreenScale; + {255, 255, 255, 0, 255, 255}, + //unsigned char BlueScale; + {255, 255, 255, 0, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_SMOKECLOUD */ + { + //int StartU; + 128<<16, + //int StartV; + 64<<16, + //int EndU; + 191<<16, + //int EndV; + 127<<16, + //unsigned int Size; + 1000, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {128, 64, 64, 64, 0}, + //unsigned char GreenScale; + {128, 64, 64, 64, 64}, + //unsigned char BlueScale; + {128, 64, 64, 64, 0}, + + //unsigned char IsLit:1; + 1, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_BLUEPLASMASPHERE */ + { + //int StartU; + 224<<16, + //int StartV; + 160<<16, + //int EndU; + 255<<16, + //int EndV; + 191<<16, + //unsigned int Size; + 500, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255, 64, 64, 64, 64, 0}, + //unsigned char GreenScale; + {255, 64, 64, 64, 64, 255}, + //unsigned char BlueScale; + {255, 64, 64, 64, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_ELECTRICALPLASMASPHERE */ + { + //int StartU; + 64<<16, + //int StartV; + 128<<16, + //int EndU; + 127<<16, + //int EndV; + 191<<16, + //unsigned int Size; + 2000, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255, 64, 64, 64, 64, 0}, + //unsigned char GreenScale; + {255, 64, 64, 64, 64, 255}, + //unsigned char BlueScale; + {255, 64, 64, 64, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_PREDPISTOL_FLECHETTE */ + { + //int StartU; + 1<<16, + //int StartV; + 1<<16, + //int EndU; + 64<<16, + //int EndV; + 64<<16, + //unsigned int Size; + 200/8, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 255, 255, 0}, + //unsigned char GreenScale; + {128, 128, 255, 0, 255, 255}, + //unsigned char BlueScale; + {64, 64, 255, 0, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_PREDPISTOL_FLECHETTE_NONDAMAGING */ + { + //int StartU; + 1<<16, + //int StartV; + 1<<16, + //int EndU; + 64<<16, + //int EndV; + 64<<16, + //unsigned int Size; + 200/8, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 255, 255, 0}, + //unsigned char GreenScale; + {128, 128, 255, 0, 255, 255}, + //unsigned char BlueScale; + {64, 64, 255, 0, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_FLECHETTE_NONDAMAGING */ + { + //int StartU; + 64<<16, + //int StartV; + 64<<16, + //int EndU; + 127<<16, + //int EndV; + 127<<16, + //unsigned int Size; + 100, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_NORMAL, + + //unsigned char Alpha; + 255, + //unsigned char RedScale; + {255, 255, 255, 255, 255, 0}, + //unsigned char GreenScale; + {255, 255, 255, 0, 255, 255}, + //unsigned char BlueScale; + {255, 255, 255, 0, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_DEWLINE */ + { + //int StartU; + 64<<16, + //int StartV; + 64<<16, + //int EndU; + 127<<16, + //int EndV; + 127<<16, + //unsigned int Size; + 200/4, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 255, 255, 0}, + //unsigned char GreenScale; + {128, 128, 255, 0, 255, 255}, + //unsigned char BlueScale; + {64, 64, 255, 0, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + /* PARTICLE_PARGEN_FLAME */ + { + //int StartU; + 64<<16, + //int StartV; + 0<<16, + //int EndU; + (64+127)<<16, + //int EndV; + 63<<16, + //unsigned int Size; + 0, + + //enum TRANSLUCENCY_TYPE TranslucencyType; + TRANSLUCENCY_GLOWING, + + //unsigned char Alpha; + 64, + //unsigned char RedScale; + {255, 255, 255, 128, 128, 0}, + //unsigned char GreenScale; + {128, 128, 255, 64, 64, 128}, + //unsigned char BlueScale; + {64, 64, 255, 255, 0, 0}, + + //unsigned char IsLit:1; + 0, + //IsDrawnInFront:1; + 0, + //IsDrawnAtBack:1; + 0, + }, + +}; + + +static PARTICLE* AllocateParticle(void); +static void DeallocateParticle(PARTICLE *particlePtr); +static PHEROMONE_TRAIL* AllocatePheromoneTrail(void); +static void DeallocatePheromoneTrail(PHEROMONE_TRAIL *trailPtr); + + + + +void InitialiseParticleSystem(void) +{ + NumActiveParticles = 0; + NumberOfBloodParticles = 0; + + NumActiveTrails = 0; + + InitialiseVolumetricExplosions(); + InitialiseRainDrops(); + InitialiseDecalSystem(); + InitForceField(); + Generate_Sphere(); + + { + NumberOfFlaresActive=0; + } +} + +static PARTICLE* AllocateParticle(void) +{ + PARTICLE *particlePtr = 0; /* Default to null ptr */ + + if (NumActiveParticles != MAX_NO_OF_PARTICLES) + { + particlePtr = &ParticleStorage[NumActiveParticles]; + NumActiveParticles++; + } + else + { + /* unable to allocate a particle */ + } + + return particlePtr; +} +static void DeallocateParticle(PARTICLE *particlePtr) +{ + /* is pointer within array? */ + LOCALASSERT(particlePtr>=ParticleStorage); + LOCALASSERT(particlePtr<=&ParticleStorage[MAX_NO_OF_PARTICLES-1]); + + NumActiveParticles--; + *particlePtr = ParticleStorage[NumActiveParticles]; +} + +static PHEROMONE_TRAIL* AllocatePheromoneTrail(void) +{ + PHEROMONE_TRAIL *trailPtr = 0; /* Default to null ptr */ + + if (NumActiveTrails != MAX_NO_OF_PHEROMONE_TRAILS) + { + trailPtr = &TrailStorage[NumActiveTrails]; + NumActiveTrails++; + } + else + { + /* unable to allocate a trail */ + } + + return trailPtr; +} +static void DeallocatePheromoneTrail(PHEROMONE_TRAIL *trailPtr) +{ + /* is pointer within array? */ + LOCALASSERT(trailPtr>=TrailStorage); + LOCALASSERT(trailPtr<=&TrailStorage[MAX_NO_OF_PHEROMONE_TRAILS-1]); + + NumActiveTrails--; + *trailPtr = TrailStorage[NumActiveTrails]; +} + +static void InitialiseVolumetricExplosions(void) +{ + int i; + for(i=0; i=MAX_NO_OF_EXPLOSIONS) + { + CurrentExplosionIndex=0; + } + + LOCALASSERT(explosionPtr); + return explosionPtr; +} + + +void MakeParticle(VECTORCH *positionPtr, VECTORCH *velocityPtr, enum PARTICLE_ID particleID) +{ + PARTICLE *particlePtr; + + if( (particleID == PARTICLE_ALIEN_BLOOD) || (particleID == PARTICLE_PREDATOR_BLOOD) || (particleID == PARTICLE_HUMAN_BLOOD)|| (particleID == PARTICLE_ANDROID_BLOOD)) + if (NumberOfBloodParticles>MAX_NO_OF_BLOOD_PARTICLES) + return; + + particlePtr = AllocateParticle(); + /* were we able to allocate a particle? */ + if (particlePtr) + { + PARTICLE_DESC *particleDescPtr = &ParticleDescription[particleID]; + particlePtr->Position = *positionPtr; + particlePtr->Velocity = *velocityPtr; + + particlePtr->ParticleID = particleID; + + particlePtr->Colour = RGBALIGHT_MAKE + ( + particleDescPtr->RedScale[CurrentVisionMode], + particleDescPtr->GreenScale[CurrentVisionMode], + particleDescPtr->BlueScale[CurrentVisionMode], + particleDescPtr->Alpha + ); + particlePtr->Size = particleDescPtr->Size; + + switch(particlePtr->ParticleID) + { + case PARTICLE_PREDATOR_BLOOD: + case PARTICLE_ALIEN_BLOOD: + case PARTICLE_HUMAN_BLOOD: + case PARTICLE_ANDROID_BLOOD: + { + particlePtr->Offset = particlePtr->Position; + particlePtr->LifeTime = ONE_FIXED; + NumberOfBloodParticles++; + break; + } + case PARTICLE_BLACKSMOKE: + { + particlePtr->LifeTime = ONE_FIXED+(FastRandom()&32767); + particlePtr->Offset.vx = ((FastRandom()&1023) - 512)*2; + particlePtr->Offset.vz = ((FastRandom()&1023) - 512)*2; + break; + } + case PARTICLE_WATERSPRAY: + { + particlePtr->LifeTime = ONE_FIXED/2; + break; + } + case PARTICLE_WATERFALLSPRAY: + { + particlePtr->LifeTime = ONE_FIXED*10; + break; + } + + case PARTICLE_FLARESMOKE: + case PARTICLE_STEAM: + { + particlePtr->LifeTime = (ONE_FIXED*1)/2+(FastRandom()&32767); + particlePtr->Offset.vx = ((FastRandom()&8191) - 4096); + particlePtr->Offset.vz = ((FastRandom()&8191) - 4096); + break; + } + case PARTICLE_IMPACTSMOKE: + { + particlePtr->LifeTime = ONE_FIXED+(FastRandom()&32767); + particlePtr->Offset.vx = ((FastRandom()&1023) - 512)*2; + particlePtr->Offset.vz = ((FastRandom()&1023) - 512)*2; + break; + } + case PARTICLE_GUNMUZZLE_SMOKE: + { + particlePtr->LifeTime = ONE_FIXED/2+(FastRandom()&32767); + particlePtr->Offset.vx = ((FastRandom()&1023) - 512); + particlePtr->Offset.vz = ((FastRandom()&1023) - 512); + break; + } + + case PARTICLE_SPARK: + { + particlePtr->LifeTime = ONE_FIXED; + break; + } + case PARTICLE_RICOCHET_SPARK: + case PARTICLE_ORANGE_SPARK: + { + particlePtr->LifeTime = ONE_FIXED/4; + break; + } + + case PARTICLE_ORANGE_PLASMA: + { + particlePtr->LifeTime = ONE_FIXED/8; + break; + } + + case PARTICLE_PLASMATRAIL: + { + particlePtr->LifeTime = ONE_FIXED/2; + particlePtr->Offset=particlePtr->Position; + break; + } + case PARTICLE_DEWLINE: + { + particlePtr->LifeTime = ONE_FIXED; // /2 + particlePtr->Offset=particlePtr->Position; + break; + } + + case PARTICLE_FLAME: + case PARTICLE_NONCOLLIDINGFLAME: + case PARTICLE_NONDAMAGINGFLAME: + case PARTICLE_PARGEN_FLAME: + { + particlePtr->Offset.vx = (FastRandom()&4095); + particlePtr->Offset.vy = ((FastRandom()&32767) - 16384); + + particlePtr->LifeTime = ONE_FIXED/2; + break; + } + case PARTICLE_FIRE: + { + particlePtr->LifeTime = ONE_FIXED/2+(FastRandom()&16383); + break; + } + case PARTICLE_EXPLOSIONFIRE: + { + particlePtr->LifeTime = ONE_FIXED/4; + particlePtr->Offset = particlePtr->Position; +// particlePtr->Position.vx += particlePtr->Velocity.vx; +// particlePtr->Position.vy += particlePtr->Velocity.vy; +// particlePtr->Position.vz += particlePtr->Velocity.vz; + break; + } + case PARTICLE_MOLOTOVFLAME: + { + particlePtr->LifeTime = ONE_FIXED*2-(FastRandom()&32767); + break; + } + + case PARTICLE_FLECHETTE: + case PARTICLE_FLECHETTE_NONDAMAGING: + { + particlePtr->LifeTime = ONE_FIXED*8; + { + particlePtr->Offset.vy = 1; + } + break; + } + + case PARTICLE_SMOKECLOUD: + { + particlePtr->LifeTime = ONE_FIXED*16-1; + particlePtr->Offset.vx = (FastRandom()&4095); + particlePtr->Offset.vy = ((FastRandom()&16383) - 8192); + break; + } + case PARTICLE_BLUEPLASMASPHERE: + { + particlePtr->LifeTime = 0; + break; + } + case PARTICLE_ELECTRICALPLASMASPHERE: + { + particlePtr->LifeTime = 32767; + break; + } + case PARTICLE_PREDPISTOL_FLECHETTE: + case PARTICLE_PREDPISTOL_FLECHETTE_NONDAMAGING: + { + particlePtr->LifeTime = ONE_FIXED; + break; + } + case PARTICLE_TRACER: + { + particlePtr->Position = *positionPtr; + particlePtr->Offset = *velocityPtr; + particlePtr->LifeTime = 0; + break; + } + + default: + { + /* particle initialised wrongly */ + DeallocateParticle(particlePtr); + LOCALASSERT(0); + break; + } + } + + } +} + +void HandleParticleSystem(void) +{ + int i; + PARTICLE *particlePtr; + HandleRipples(); +// D3D_DrawWaterTest(); + + HandleDecalSystem(); + D3D_DecalSystem_End(); + + + +// textprint("Particles Active: %d\n",i); +// D3D_DecalSystem_Setup(); + i = NumActiveParticles; + particlePtr = ParticleStorage; + + while(i--) + { + PARTICLE_DESC *particleDescPtr = &ParticleDescription[particlePtr->ParticleID]; + + particlePtr->NotYetRendered = 1; + switch(particlePtr->ParticleID) + { + case PARTICLE_ALIEN_BLOOD: + case PARTICLE_PREDATOR_BLOOD: + case PARTICLE_HUMAN_BLOOD: + case PARTICLE_ANDROID_BLOOD: + { + particlePtr->Size = 64-(FastRandom()&31); + particlePtr->Offset = particlePtr->Position; + particlePtr->Offset.vx += particlePtr->Velocity.vx>>4; + particlePtr->Offset.vy += particlePtr->Velocity.vy>>4; + particlePtr->Offset.vz += particlePtr->Velocity.vz>>4; + break; + } + case PARTICLE_FLARESMOKE: + { + extern sine[],cosine[]; + +// particlePtr->Position.vy -= MUL_FIXED(1000+(FastRandom()&511),NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + + if (particlePtr->Velocity.vy > -1300) + particlePtr->Velocity.vy -= MUL_FIXED(4000,NormalFrameTime); + + if (particlePtr->Velocity.vx > 0) + { + particlePtr->Velocity.vx -= MUL_FIXED(2000,NormalFrameTime); + if (particlePtr->Velocity.vx < 0) particlePtr->Velocity.vx = 0; + } + else if (particlePtr->Velocity.vx < 0) + { + particlePtr->Velocity.vx += MUL_FIXED(2000,NormalFrameTime); + if (particlePtr->Velocity.vx > 0) particlePtr->Velocity.vx = 0; + } + + if (particlePtr->Velocity.vz > 0) + { + particlePtr->Velocity.vz -= MUL_FIXED(2000,NormalFrameTime); + if (particlePtr->Velocity.vz < 0) particlePtr->Velocity.vz = 0; + } + else if (particlePtr->Velocity.vz < 0) + { + particlePtr->Velocity.vz += MUL_FIXED(2000,NormalFrameTime); + if (particlePtr->Velocity.vz > 0) particlePtr->Velocity.vz = 0; + } + + + particlePtr->Position.vx += MUL_FIXED + ( + particlePtr->Velocity.vx+ + MUL_FIXED + ( + -GetSin((particlePtr->Position.vz+particlePtr->Position.vy)&4095)/4, + particlePtr->Offset.vx + ), + NormalFrameTime + + ); + + particlePtr->Position.vz += MUL_FIXED + ( + particlePtr->Velocity.vz+ + MUL_FIXED + ( + GetCos((particlePtr->Position.vx+particlePtr->Position.vy)&4095)/4, + particlePtr->Offset.vz + ), + NormalFrameTime + + ); + + particlePtr->Colour = RGBALIGHT_MAKE + ( + particleDescPtr->RedScale[CurrentVisionMode], + particleDescPtr->GreenScale[CurrentVisionMode], + particleDescPtr->BlueScale[CurrentVisionMode], + (particlePtr->LifeTime>>10) + ); + particlePtr->Size = MUL_FIXED(ONE_FIXED-particlePtr->LifeTime,200)+50; + + break; + } + case PARTICLE_STEAM: + { + extern sine[],cosine[]; + +// particlePtr->Position.vy -= MUL_FIXED(1000+(FastRandom()&511),NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + + if (particlePtr->Velocity.vy > -1300) + particlePtr->Velocity.vy -= MUL_FIXED(4000,NormalFrameTime); + + if (particlePtr->Velocity.vx > 0) + { + particlePtr->Velocity.vx -= MUL_FIXED(2000,NormalFrameTime); + if (particlePtr->Velocity.vx < 0) particlePtr->Velocity.vx = 0; + } + else if (particlePtr->Velocity.vx < 0) + { + particlePtr->Velocity.vx += MUL_FIXED(2000,NormalFrameTime); + if (particlePtr->Velocity.vx > 0) particlePtr->Velocity.vx = 0; + } + + if (particlePtr->Velocity.vz > 0) + { + particlePtr->Velocity.vz -= MUL_FIXED(2000,NormalFrameTime); + if (particlePtr->Velocity.vz < 0) particlePtr->Velocity.vz = 0; + } + else if (particlePtr->Velocity.vz < 0) + { + particlePtr->Velocity.vz += MUL_FIXED(2000,NormalFrameTime); + if (particlePtr->Velocity.vz > 0) particlePtr->Velocity.vz = 0; + } + + + particlePtr->Position.vx += MUL_FIXED + ( + particlePtr->Velocity.vx+ + MUL_FIXED + ( + -GetSin((particlePtr->Position.vz+particlePtr->Position.vy)&4095)/4, + particlePtr->Offset.vx + ), + NormalFrameTime + + ); + + particlePtr->Position.vz += MUL_FIXED + ( + particlePtr->Velocity.vz+ + MUL_FIXED + ( + GetCos((particlePtr->Position.vx+particlePtr->Position.vy)&4095)/4, + particlePtr->Offset.vz + ), + NormalFrameTime + + ); + particlePtr->Colour = RGBALIGHT_MAKE + ( + particleDescPtr->RedScale[CurrentVisionMode], + particleDescPtr->GreenScale[CurrentVisionMode], + particleDescPtr->BlueScale[CurrentVisionMode], + (particlePtr->LifeTime>>14)+17 + ); + break; + } + + case PARTICLE_BLACKSMOKE: + case PARTICLE_IMPACTSMOKE: + { + extern sine[],cosine[]; + +// particlePtr->Position.vy -= MUL_FIXED(1000+(FastRandom()&511),NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + + if (particlePtr->Velocity.vy > -1300) + particlePtr->Velocity.vy -= MUL_FIXED(3000,NormalFrameTime); + + if (particlePtr->Velocity.vx > 0) + { + particlePtr->Velocity.vx -= MUL_FIXED(2000,NormalFrameTime); + if (particlePtr->Velocity.vx < 0) particlePtr->Velocity.vx = 0; + } + else if (particlePtr->Velocity.vx < 0) + { + particlePtr->Velocity.vx += MUL_FIXED(2000,NormalFrameTime); + if (particlePtr->Velocity.vx > 0) particlePtr->Velocity.vx = 0; + } + + if (particlePtr->Velocity.vz > 0) + { + particlePtr->Velocity.vz -= MUL_FIXED(2000,NormalFrameTime); + if (particlePtr->Velocity.vz < 0) particlePtr->Velocity.vz = 0; + } + else if (particlePtr->Velocity.vz < 0) + { + particlePtr->Velocity.vz += MUL_FIXED(2000,NormalFrameTime); + if (particlePtr->Velocity.vz > 0) particlePtr->Velocity.vz = 0; + } + + + particlePtr->Position.vx += MUL_FIXED + ( + particlePtr->Velocity.vx+ + MUL_FIXED + ( + -GetSin((particlePtr->Position.vz+particlePtr->Position.vy)&4095)/4, + particlePtr->Offset.vx + ), + NormalFrameTime + + ); + + particlePtr->Position.vz += MUL_FIXED + ( + particlePtr->Velocity.vz+ + MUL_FIXED + ( + GetCos((particlePtr->Position.vx+particlePtr->Position.vy)&4095)/4, + particlePtr->Offset.vz + ), + NormalFrameTime + + ); + + { + int colour = particlePtr->LifeTime>>11; + particlePtr->Colour = RGBALIGHT_MAKE(colour,colour,colour,255); + } + + break; + } + case PARTICLE_GUNMUZZLE_SMOKE: + { + extern sine[],cosine[]; + +// particlePtr->Position.vy -= MUL_FIXED(1000+(FastRandom()&511),NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + #if 1 + if (particlePtr->Velocity.vy > -1300) + particlePtr->Velocity.vy -= MUL_FIXED(1024,NormalFrameTime); + + if (particlePtr->Velocity.vx > 0) + { + particlePtr->Velocity.vx -= MUL_FIXED(1024,NormalFrameTime); + if (particlePtr->Velocity.vx < 0) particlePtr->Velocity.vx = 0; + } + else if (particlePtr->Velocity.vx < 0) + { + particlePtr->Velocity.vx += MUL_FIXED(1024,NormalFrameTime); + if (particlePtr->Velocity.vx > 0) particlePtr->Velocity.vx = 0; + } + + if (particlePtr->Velocity.vz > 0) + { + particlePtr->Velocity.vz -= MUL_FIXED(1024,NormalFrameTime); + if (particlePtr->Velocity.vz < 0) particlePtr->Velocity.vz = 0; + } + else if (particlePtr->Velocity.vz < 0) + { + particlePtr->Velocity.vz += MUL_FIXED(1024,NormalFrameTime); + if (particlePtr->Velocity.vz > 0) particlePtr->Velocity.vz = 0; + } + #endif + + particlePtr->Position.vx += MUL_FIXED + ( + particlePtr->Velocity.vx+ + MUL_FIXED + ( + -GetSin(((particlePtr->Position.vz+particlePtr->Position.vy)*16)&4095)/4, + particlePtr->Offset.vx + ), + NormalFrameTime + + ); + + particlePtr->Position.vz += MUL_FIXED + ( + particlePtr->Velocity.vz+ + MUL_FIXED + ( + GetCos(((particlePtr->Position.vx+particlePtr->Position.vy)*16)&4095)/4, + particlePtr->Offset.vz + ), + NormalFrameTime + + ); + + particlePtr->Size = MUL_FIXED(ONE_FIXED-particlePtr->LifeTime,48); + { + int colour = particlePtr->LifeTime>>11; + particlePtr->Colour = RGBALIGHT_MAKE(32,32,32,colour); + } + + break; + } + case PARTICLE_FLAME: + case PARTICLE_NONDAMAGINGFLAME: + case PARTICLE_PARGEN_FLAME: + { + particlePtr->Size = 20+(ONE_FIXED/2-particlePtr->LifeTime)/64; + if (particlePtr->LifeTime==ONE_FIXED/2) + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(16,16,128,(particlePtr->LifeTime>>8)|9); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(0,32,0,(particlePtr->LifeTime>>8)|9); + break; + } + case VISION_MODE_PRED_THERMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(0,0,128,(particlePtr->LifeTime>>8)|9); + break; + } + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(192,128,32,(particlePtr->LifeTime>>8)|9); + break; + } + } + } + else + { + particlePtr->Colour = RGBALIGHT_MAKE + ( + particleDescPtr->RedScale[CurrentVisionMode], + particleDescPtr->GreenScale[CurrentVisionMode], + particleDescPtr->BlueScale[CurrentVisionMode], + (particlePtr->LifeTime>>8)|9 + ); + } + + + break; + } + case PARTICLE_FIRE: + { + particlePtr->Size = 300-(FastRandom()&127); + break; + } + case PARTICLE_EXPLOSIONFIRE: + { + VECTORCH obstacleNormal; + int moduleIndex; + + if(ParticleDynamics(particlePtr,&obstacleNormal,&moduleIndex) && !(FastRandom()&15)) + { + MakeDecal(DECAL_SCORCHED,&obstacleNormal,&(particlePtr->Position),moduleIndex); + particlePtr->LifeTime=0; + } + break; + } + case PARTICLE_MOLOTOVFLAME: + { + VECTORCH obstacleNormal; + int moduleIndex; + + particlePtr->Colour = RGBALIGHT_MAKE + ( + particleDescPtr->RedScale[CurrentVisionMode], + particleDescPtr->GreenScale[CurrentVisionMode], + particleDescPtr->BlueScale[CurrentVisionMode], + (particlePtr->LifeTime>>10)|9 + ); + + particlePtr->Velocity.vy += MUL_FIXED(8000,NormalFrameTime); + if(ParticleDynamics(particlePtr,&obstacleNormal,&moduleIndex)) + { + #if 0 + int magOfPerpImp = DotProduct(&obstacleNormal,&(particlePtr->Velocity)); + particlePtr->Velocity.vx -= MUL_FIXED(obstacleNormal.vx, magOfPerpImp); + particlePtr->Velocity.vy -= MUL_FIXED(obstacleNormal.vy, magOfPerpImp); + particlePtr->Velocity.vz -= MUL_FIXED(obstacleNormal.vz, magOfPerpImp); + #endif + } + particlePtr->Size = 800-(FastRandom()&255); + break; + } + + + case PARTICLE_NONCOLLIDINGFLAME: + { + particlePtr->Size = 20+(ONE_FIXED/2-particlePtr->LifeTime)/64; + break; + } + case PARTICLE_ORANGE_SPARK: + { + particlePtr->Offset = particlePtr->Position; + + particlePtr->Position.vx += MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Velocity.vx -= MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Velocity.vy -= MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Position.vz += MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + particlePtr->Velocity.vz -= MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + + { + int l = particlePtr->LifeTime*8; + l = MUL_FIXED(255,l); + + if (l>255) + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,255,l-255,255); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,l/2,255); + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(l-255,255,255,255); + break; + } + } + } + else + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,l,0,l); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,128,l); + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(0,l,l,l); + break; + } + } + } + } + + break; + } + case PARTICLE_ORANGE_PLASMA: + { + particlePtr->Offset = particlePtr->Position; + + particlePtr->Position.vx += MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Velocity.vx -= MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Velocity.vy -= MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Position.vz += MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + particlePtr->Velocity.vz -= MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + + { + int l = particlePtr->LifeTime*16; + l = MUL_FIXED(255,l); + + if (l>255) + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,255,l-255,255); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,l/2,255); + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(l-255,255,255,255); + break; + } + } + } + else + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,l,0,l); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,128,l); + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(0,l,l,l); + break; + } + } + } + } + + break; + } + case PARTICLE_RICOCHET_SPARK: + { + particlePtr->Offset = particlePtr->Position; + + particlePtr->Position.vx += MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Velocity.vx -= MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Velocity.vy -= MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Position.vz += MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + particlePtr->Velocity.vz -= MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + + { + int l = particlePtr->LifeTime*8; + l = MUL_FIXED(255,l); + + if (l>255) + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,255,l-255,255); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,l/2,255); + break; + } + case VISION_MODE_PRED_THERMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(l-255,255,255,255); + break; + } + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,255,l-255,255); + break; + } + } + } + else + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,l,0,l); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,128,l); + break; + } + case VISION_MODE_PRED_THERMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(0,l,l,l); + break; + } + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(l,l,0,l); + break; + } + + } + } + } + + break; + } + + case PARTICLE_SPARK: + { + particlePtr->Offset = particlePtr->Position; + + particlePtr->Position.vx += MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Velocity.vx -= MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Velocity.vy += MUL_FIXED(5000,NormalFrameTime); + particlePtr->Position.vz += MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + particlePtr->Velocity.vz -= MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + + { + int l = particlePtr->LifeTime*2; + l = MUL_FIXED(255,l); + + if (l>255) + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,255,255); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,l/2,255); + break; + } + case VISION_MODE_PRED_THERMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(l-255,255,255,255); + break; + } + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,255,l-255,255); + break; + } + } + } + else + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,l,l); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,128,l); + break; + } + case VISION_MODE_PRED_THERMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(0,l,l,l); + break; + } + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(l,l,0,l); + break; + } + } + } + } + break; + } + + case PARTICLE_DEWLINE: + { + int l = (particlePtr->LifeTime)/64/4; + if (l>255) + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,255,255,255); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(0,255,0,255); + break; + } + case VISION_MODE_PRED_THERMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,0,0,255); + break; + } + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,128,64,255); + break; + } + } + } + else + { + particlePtr->Position.vx += MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Position.vz += MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,128+(l/2),64+((3*l)/4),l); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,l/2,l); + break; + } + case VISION_MODE_PRED_THERMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,l/2,l/2,l); + break; + } + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,l/2,l/4,l); + break; + } + } + particlePtr->Size = 32+(FastRandom()&31); + } + + break; + } + case PARTICLE_PLASMATRAIL: + { + int l = (particlePtr->LifeTime)/64/4; + if (l>255) + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(0,0,255,255); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(0,255,0,255); + break; + } + case VISION_MODE_PRED_THERMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(0,0,255,255); + break; + } + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,128,64,255); + break; + } + } + } + else + { + particlePtr->Position.vx += MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Position.vz += MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/4,l/2,255,l); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,l/2,l); + break; + } + case VISION_MODE_PRED_THERMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/4,l/2,255,l); + break; + } + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,l/2,l/4,l); + break; + } + } + particlePtr->Size = 32+(FastRandom()&31); + } + + break; + } + + case PARTICLE_WATERSPRAY: + { + particlePtr->Colour = RGBALIGHT_MAKE + ( + particleDescPtr->RedScale[CurrentVisionMode], + particleDescPtr->GreenScale[CurrentVisionMode], + particleDescPtr->BlueScale[CurrentVisionMode], + particleDescPtr->Alpha + ); + particlePtr->Position.vx += MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Position.vz += MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + particlePtr->Velocity.vy += MUL_FIXED(10000,NormalFrameTime); + + break; + } + case PARTICLE_WATERFALLSPRAY: + { + extern int WaterFallBase; + int y = particlePtr->Position.vy; + particlePtr->Colour = RGBALIGHT_MAKE + ( + particleDescPtr->RedScale[CurrentVisionMode], + particleDescPtr->GreenScale[CurrentVisionMode], + particleDescPtr->BlueScale[CurrentVisionMode], + particleDescPtr->Alpha + ); + + particlePtr->Position.vx += MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Position.vz += MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + + particlePtr->Velocity.vy += MUL_FIXED(10000+(FastRandom()&511),NormalFrameTime); + + if(particlePtr->Position.vz < 54885 && particlePtr->Position.vx < 179427) + { + if (y<4742 && particlePtr->Position.vy>4742) + { + particlePtr->Position.vy=4742; + particlePtr->Velocity.vy=-MUL_FIXED(particlePtr->Velocity.vy,ONE_FIXED/2-(FastRandom()&16384)); + } + } + else if (particlePtr->Position.vz < 58600) + { + int l = DIV_FIXED(particlePtr->Position.vz - 54885,58600-54885); + + if (particlePtr->Position.vx < 179427 - MUL_FIXED(l,179427-175545)) + { + int yThreshold = 4742 + MUL_FIXED(l,8635-4742); + if (yPosition.vy>yThreshold) + { + particlePtr->Position.vy=yThreshold; + particlePtr->Velocity.vy=-MUL_FIXED(particlePtr->Velocity.vy,ONE_FIXED/2-(FastRandom()&16384)); + } + } + } + + particlePtr->Offset.vx = particlePtr->Position.vx - particlePtr->Velocity.vx/4; + particlePtr->Offset.vy = particlePtr->Position.vy - particlePtr->Velocity.vy/4; + particlePtr->Offset.vz = particlePtr->Position.vz - particlePtr->Velocity.vz/4; + + if (particlePtr->Position.vy>WaterFallBase) + { + particlePtr->LifeTime = 0; + } + + break; + } + case PARTICLE_FLECHETTE: + case PARTICLE_FLECHETTE_NONDAMAGING: + { + { + int l = particlePtr->LifeTime/4; + l = MUL_FIXED(255,l); + + if (l>255) + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE((l-255)/2+32,0,0,255); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,l/2,255); + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(l-255,255,255,255); + break; + } + } + } + else + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(32,0,0,l); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,l/2,l); + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(0,l,l,l); + break; + } + } + } + } + + if (particlePtr->Offset.vy)//particlePtr->Velocity.vx || particlePtr->Velocity.vy || particlePtr->Velocity.vz) + { + VECTORCH obstacleNormal; + int moduleIndex; + VECTORCH velocityBackup = particlePtr->Velocity; + + if(ParticleDynamics(particlePtr,&obstacleNormal,&moduleIndex)) + { + if(moduleIndex==-1) + { + particlePtr->LifeTime=0; + } + else + { + particlePtr->Offset.vy = 0; + particlePtr->Velocity = velocityBackup; + particlePtr->Position.vx += particlePtr->Velocity.vx>>10; + particlePtr->Position.vy += particlePtr->Velocity.vy>>10; + particlePtr->Position.vz += particlePtr->Velocity.vz>>10; + } + } + } + + break; + } + case PARTICLE_SMOKECLOUD: + { + if (particlePtr->LifeTimeLifeTime/(8*256*4)); + particlePtr->Colour = RGBALIGHT_MAKE(255,255,255,colour); + } + else + { + particlePtr->Colour = RGBALIGHT_MAKE(255,255,255,64); + } + particlePtr->Size = 1000+500-(particlePtr->LifeTime>>10); + + AddEffectsOfForceGenerators(&particlePtr->Position,&particlePtr->Velocity,32*64); + + break; + } + case PARTICLE_BLUEPLASMASPHERE: + { + break; + } + case PARTICLE_ELECTRICALPLASMASPHERE: + { + { + int colour = (particlePtr->LifeTime/128); + particlePtr->Size = 200+(ONE_FIXED-particlePtr->LifeTime)/16; + particlePtr->Colour = RGBALIGHT_MAKE(255,255,255,colour); + } + break; + } + case PARTICLE_PREDPISTOL_FLECHETTE: + case PARTICLE_PREDPISTOL_FLECHETTE_NONDAMAGING: + { + /* CDF 7/12/98 Placeholder till Kevin gets better. */ + + /* Based on PARTICLE_SPARK for vision... */ + particlePtr->Offset = particlePtr->Position; + + { + int l = particlePtr->LifeTime*2; + l = MUL_FIXED(255,l); + + if (l>255) + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,255,255); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,l/2,255); + break; + } + case VISION_MODE_PRED_THERMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(l-255,255,255,255); + break; + } + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(255,255,l-255,255); + break; + } + } + } + else + { + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,l,l); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particlePtr->Colour = RGBALIGHT_MAKE(l/2,l/2,128,l); + break; + } + case VISION_MODE_PRED_THERMAL: + { + particlePtr->Colour = RGBALIGHT_MAKE(0,l,l,l); + break; + } + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particlePtr->Colour = RGBALIGHT_MAKE(l,l,0,l); + break; + } + } + } + } + + { + VECTORCH obstacleNormal; + int moduleIndex; + + if(ParticleDynamics(particlePtr,&obstacleNormal,&moduleIndex)) + { + if (moduleIndex!=-1) + { + MakeDecal(DECAL_SCORCHED,&obstacleNormal,&(particlePtr->Position),moduleIndex); + } + particlePtr->LifeTime=0; + } + } + break; + } + case PARTICLE_TRACER: + { + break; + } + default: + { + /* particle initialised wrongly */ + LOCALASSERT(0); + break; + } + } + particlePtr++; + } + + // + PostLandscapeRendering(); + D3D_DecalSystem_Setup(); + OutputTranslucentPolyList(); + + i = NumActiveParticles; + particlePtr = ParticleStorage; + while(i--) + { + particlePtr->LifeTime -= NormalFrameTime; + + if (particlePtr->LifeTime<=0) + { + enum PARTICLE_ID particleID = particlePtr->ParticleID; + if( (particleID == PARTICLE_ALIEN_BLOOD) || (particleID == PARTICLE_PREDATOR_BLOOD) || (particleID==PARTICLE_HUMAN_BLOOD) || (particleID == PARTICLE_ANDROID_BLOOD)) + { + NumberOfBloodParticles--; + LOCALASSERT(NumberOfBloodParticles>=0); + } + + if ((particleID == PARTICLE_NONCOLLIDINGFLAME) && (FastRandom()&65535)<4096) + { + VECTORCH zero = {0,0,0}; + MakeParticle(&(particlePtr->Position),&zero,PARTICLE_IMPACTSMOKE); + } + else if ((particleID == PARTICLE_MOLOTOVFLAME) && (FastRandom()&65535)<4096) + { + VECTORCH zero = {0,0,0}; + MakeParticle(&(particlePtr->Position),&zero,PARTICLE_IMPACTSMOKE); + } + + + DeallocateParticle(particlePtr); + } + else + { + particlePtr++; + } + } + + { + extern int NumOnScreenBlocks; + extern DISPLAYBLOCK *OnScreenBlockList[]; + int numOfObjects = NumOnScreenBlocks; + while(numOfObjects) + { + DISPLAYBLOCK *objectPtr = OnScreenBlockList[--numOfObjects]; + STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock; + + if (!objectPtr->ObShape && objectPtr->SfxPtr) + { + DrawSfxObject(objectPtr); + } + if (objectPtr->HModelControlBlock) + { + SECTION_DATA *firstSectionPtr=objectPtr->HModelControlBlock->section_data; + ScanHModelForDecals(objectPtr,firstSectionPtr); + } + if (sbPtr) + { + switch(sbPtr->I_SBtype) + { + case I_BehaviourPlacedLight: + { + PLACED_LIGHT_BEHAV_BLOCK* pl_bhv = sbPtr->SBdataptr; + GLOBALASSERT(pl_bhv); + GLOBALASSERT(sbPtr->containingModule); + + if (LocalDetailLevels.DrawLightCoronas + && pl_bhv->has_corona + && pl_bhv->light->LightBright + && (ModuleCurrVisArray[sbPtr->containingModule->m_index]==2) + && (pl_bhv->light->RedScale + || pl_bhv->light->GreenScale + || pl_bhv->light->BlueScale) + ) + { + VECTORCH position=pl_bhv->corona_location; + RotateVector(&position,&objectPtr->ObMat); + position.vx += objectPtr->ObWorld.vx; + position.vy += objectPtr->ObWorld.vy; + position.vz += objectPtr->ObWorld.vz; + + if (CameraCanSeeThisPosition_WithIgnore(objectPtr,&position)) + { + LIGHTBLOCK *lPtr = pl_bhv->light; + int colour; + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + int r = MUL_FIXED(lPtr->RedScale,lPtr->LightBright)>>8; + int g = MUL_FIXED(lPtr->GreenScale,lPtr->LightBright)>>8; + int b = MUL_FIXED(lPtr->BlueScale,lPtr->LightBright)>>8; + if (r>255) r=255; + if (g>255) g=255; + if (b>255) b=255; + colour = 0xff000000+(r<<16)+(g<<8)+(b); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + colour = 0xffffffff; + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + int b = MUL_FIXED + ( + lPtr->RedScale+lPtr->GreenScale+lPtr->BlueScale, + lPtr->LightBright + )>>10; + if (b>255) b=255; + + colour = 0xff000000+(b<<16)+((b>>1)<<8); + break; + } + } + RenderLightFlare(&position,colour); + } + } + + break; + } + case I_BehaviourFlareGrenade: + { + if (LocalDetailLevels.DrawLightCoronas) + { + DoFlareCorona(objectPtr); + } + break; + } + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + + if (ghostDataPtr->type==I_BehaviourFlareGrenade && LocalDetailLevels.DrawLightCoronas) + { + DoFlareCorona(objectPtr); + } + else if (ghostDataPtr->type==I_BehaviourFrisbee) + { + if (sbPtr->DynPtr) + { + if (CameraCanSeeThisPosition_WithIgnore(objectPtr,&(sbPtr->DynPtr->Position))) + { + int colour; + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + colour = 0x40ffffff; + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + colour = 0x40ffffff; + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + colour = 0x40ff8000; + break; + } + } + RenderLightFlare(&(sbPtr->DynPtr->Position),colour); + } + } + } + break; + } + /* CDF 21/7/99 Frisbee Laser? */ + case I_BehaviourFrisbee: + { + if (sbPtr->DynPtr) + { + if (CameraCanSeeThisPosition_WithIgnore(objectPtr,&(sbPtr->DynPtr->Position))) + { + int colour; + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + colour = 0x40ffffff; + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + colour = 0x40ffffff; + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + colour = 0x40ff8000; + break; + } + } + RenderLightFlare(&(sbPtr->DynPtr->Position),colour); + } + } + break; + } + /* CDF 21/7/99 Frisbee Laser? */ + case I_BehaviourXenoborg: + { + XENO_STATUS_BLOCK *statusPtr = (XENO_STATUS_BLOCK *)sbPtr->SBdataptr; + LASER_BEAM_DESC *laserPtr = statusPtr->TargetingLaser; + int i = 2; + do + { + if (laserPtr->BeamIsOn) + { + if (laserPtr->BeamHasHitPlayer) + { + int colour; + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + colour = 0xffff0000; + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + colour = 0xffffffff; + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + colour = 0xffff8000; + break; + } + } + RenderLightFlare(&(laserPtr->SourcePosition),colour); + } + else + { + PARTICLE particle; + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particle.Colour = RGBALIGHT_MAKE(255,0,0,255); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particle.Colour = RGBALIGHT_MAKE(255,255,255,255); + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particle.Colour = RGBALIGHT_MAKE(255,128,0,255); + break; + } + } + particle.ParticleID = PARTICLE_LASERBEAM; + particle.Position = laserPtr->SourcePosition; + particle.Offset = laserPtr->TargetPosition; + particle.Size = 20; + RenderParticle(&particle); + } + } + laserPtr++; + } + while(i--); + + if (statusPtr->LeftMainBeam.BeamIsOn) + { + DrawXenoborgMainLaserbeam(&statusPtr->LeftMainBeam); + } + if (statusPtr->RightMainBeam.BeamIsOn) + { + DrawXenoborgMainLaserbeam(&statusPtr->RightMainBeam); + } + break; + } + case I_BehaviourSpeargunBolt: + { + SPEAR_BEHAV_BLOCK *bbPtr = (SPEAR_BEHAV_BLOCK * ) sbPtr->SBdataptr; + + if (bbPtr->SpearThroughFragment) + { + DISPLAYBLOCK displayblock; + displayblock.ObWorld.vx=bbPtr->Position.vx+sbPtr->DynPtr->Position.vx; + displayblock.ObWorld.vy=bbPtr->Position.vy+sbPtr->DynPtr->Position.vy; + displayblock.ObWorld.vz=bbPtr->Position.vz+sbPtr->DynPtr->Position.vz; + displayblock.ObMat=bbPtr->Orient; + displayblock.ObShape=GetLoadedShapeMSL("spear"); + displayblock.ObShapeData=GetShapeData(displayblock.ObShape); + + displayblock.name=NULL; + displayblock.ObEuler.EulerX=0; + displayblock.ObEuler.EulerY=0; + displayblock.ObEuler.EulerZ=0; + displayblock.ObFlags=0; + displayblock.ObFlags2=0; + displayblock.ObFlags3=0; + displayblock.ObNumLights=0; + displayblock.ObRadius=0; + displayblock.ObMaxX=0; + displayblock.ObMinX=0; + displayblock.ObMaxY=0; + displayblock.ObMinY=0; + displayblock.ObMaxZ=0; + displayblock.ObMinZ=0; + displayblock.ObTxAnimCtrlBlks=NULL; + displayblock.ObEIDPtr=NULL; + displayblock.ObMorphCtrl=NULL; + displayblock.ObStrategyBlock=NULL; + displayblock.ShapeAnimControlBlock=NULL; + displayblock.HModelControlBlock=NULL; + displayblock.ObMyModule=NULL; + displayblock.SpecialFXFlags = 0; + displayblock.SfxPtr=0; + + MakeVector(&displayblock.ObWorld, &Global_VDB_Ptr->VDB_World, &displayblock.ObView); + RotateVector(&displayblock.ObView, &Global_VDB_Ptr->VDB_Mat); + RenderThisDisplayblock(&displayblock); + + } + break; + } + default: + { + /* KJL 19:17:48 31/07/98 - check for hmodels */ + break; + } + } + } + } + } + HandlePheromoneTrails(); + { + int i; + for(i=0; iNotYetRendered) + { + VECTORCH position = particlePtr->Position; + TranslatePointIntoViewspace(&position); + + if (position.vz>zThreshold) + { + particlePtr->NotYetRendered = 0; + switch(particlePtr->ParticleID) + { + case PARTICLE_ALIEN_BLOOD: + { + RenderParticle(particlePtr); + { + VECTORCH obstacleNormal; + int moduleIndex; + #if 1 + if(ParticleDynamics(particlePtr,&obstacleNormal,&moduleIndex)) + { + if(moduleIndex!=-1) + { + #if 1 + int i = 1; + MATRIXCH orientation; + MakeMatrixFromDirection(&obstacleNormal,&orientation); + while(i--) + { + VECTORCH velocity; + velocity.vx = ((FastRandom()&1023) - 512); + velocity.vy = ((FastRandom()&1023) - 512); + velocity.vz = (255+(FastRandom()&255)); + RotateVector(&velocity,&orientation); + MakeParticle(&(particlePtr->Position),&(velocity),PARTICLE_IMPACTSMOKE); + } + #endif + MakeDecal(DECAL_SCORCHED,&obstacleNormal,&(particlePtr->Position),moduleIndex); + } + particlePtr->LifeTime = 0; + } + #endif + } + + particlePtr->Velocity.vy += MUL_FIXED(10000,NormalFrameTime); + AddEffectsOfForceGenerators(&particlePtr->Position,&particlePtr->Velocity,32*16); + + break; + } + case PARTICLE_PREDATOR_BLOOD: + { + RenderParticle(particlePtr); + { + VECTORCH obstacleNormal; + int moduleIndex; + + if(ParticleDynamics(particlePtr,&obstacleNormal,&moduleIndex))//&& !(FastRandom()&15)) + { + if(moduleIndex!=-1) + { + MakeDecal(DECAL_PREDATOR_BLOOD,&obstacleNormal,&(particlePtr->Position),moduleIndex); + } + particlePtr->LifeTime = 0; + } + } + + particlePtr->Velocity.vy += MUL_FIXED(10000,NormalFrameTime); + AddEffectsOfForceGenerators(&particlePtr->Position,&particlePtr->Velocity,32*16); + break; + + } + case PARTICLE_HUMAN_BLOOD: + { + RenderParticle(particlePtr); + { + VECTORCH obstacleNormal; + int moduleIndex; + + if(ParticleDynamics(particlePtr,&obstacleNormal,&moduleIndex))//&& !(FastRandom()&15)) + { + if(moduleIndex!=-1) + { + MakeDecal(DECAL_HUMAN_BLOOD,&obstacleNormal,&(particlePtr->Position),moduleIndex); + } + particlePtr->LifeTime = 0; + } + } + + particlePtr->Velocity.vy += MUL_FIXED(10000,NormalFrameTime); + AddEffectsOfForceGenerators(&particlePtr->Position,&particlePtr->Velocity,32*16); + break; + } + case PARTICLE_ANDROID_BLOOD: + { + RenderParticle(particlePtr); + { + VECTORCH obstacleNormal; + int moduleIndex; + + if(ParticleDynamics(particlePtr,&obstacleNormal,&moduleIndex))//&& !(FastRandom()&15)) + { + if(moduleIndex!=-1) + { + MakeDecal(DECAL_ANDROID_BLOOD,&obstacleNormal,&(particlePtr->Position),moduleIndex); + } + particlePtr->LifeTime = 0; + } + } + + particlePtr->Velocity.vy += MUL_FIXED(10000,NormalFrameTime); + AddEffectsOfForceGenerators(&particlePtr->Position,&particlePtr->Velocity,32*16); + break; + } + case PARTICLE_FLARESMOKE: + { + RenderParticle(particlePtr); + { + VECTORCH impulse={0,0,0}; + int t = MUL_FIXED(NormalFrameTime,NormalFrameTime*4); + AddEffectsOfForceGenerators(&particlePtr->Position,&impulse,8); + particlePtr->Position.vx += MUL_FIXED(impulse.vx,t); + particlePtr->Position.vy += MUL_FIXED(impulse.vy,t); + particlePtr->Position.vz += MUL_FIXED(impulse.vz,t); + + } + break; + } + case PARTICLE_FLAME: + case PARTICLE_NONDAMAGINGFLAME: + case PARTICLE_PARGEN_FLAME: + { + RenderParticle(particlePtr); + { + VECTORCH obstacleNormal; + int moduleIndex; + + if(ParticleDynamics(particlePtr,&obstacleNormal,&moduleIndex) && !(FastRandom()&15)) + { + if (particlePtr->ParticleID!=PARTICLE_NONDAMAGINGFLAME) { + if(moduleIndex!=-1) + { + MakeDecal(DECAL_SCORCHED,&obstacleNormal,&(particlePtr->Position),moduleIndex); + } + } + } + } + particlePtr->Velocity.vy -= MUL_FIXED(8000,NormalFrameTime); + break; + } + case PARTICLE_FIRE: + { + RenderParticle(particlePtr); + + particlePtr->Position.vx += MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Position.vz += MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + particlePtr->Velocity.vy -= MUL_FIXED(4000,NormalFrameTime); + + break; + } + case PARTICLE_NONCOLLIDINGFLAME: + { + RenderParticle(particlePtr); + + particlePtr->Position.vx += MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Position.vz += MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + particlePtr->Velocity.vy -= MUL_FIXED(8000,NormalFrameTime); + break; + } + case PARTICLE_FLECHETTE: + case PARTICLE_FLECHETTE_NONDAMAGING: + { + RenderFlechetteParticle(particlePtr); + break; + } + case PARTICLE_STEAM: + case PARTICLE_BLACKSMOKE: + case PARTICLE_IMPACTSMOKE: + case PARTICLE_GUNMUZZLE_SMOKE: + case PARTICLE_EXPLOSIONFIRE: + case PARTICLE_MOLOTOVFLAME: + case PARTICLE_ORANGE_SPARK: + case PARTICLE_ORANGE_PLASMA: + case PARTICLE_RICOCHET_SPARK: + case PARTICLE_SPARK: + case PARTICLE_PLASMATRAIL: + case PARTICLE_DEWLINE: + case PARTICLE_WATERSPRAY: + case PARTICLE_WATERFALLSPRAY: + case PARTICLE_SMOKECLOUD: + case PARTICLE_BLUEPLASMASPHERE: + case PARTICLE_ELECTRICALPLASMASPHERE: + case PARTICLE_PREDPISTOL_FLECHETTE: + case PARTICLE_PREDPISTOL_FLECHETTE_NONDAMAGING: + case PARTICLE_TRACER: + { + RenderParticle(particlePtr); + break; + } + default: + { + /* particle initialised wrongly */ + LOCALASSERT(0); + break; + } + } + } + } + particlePtr++; + } +} +void DoFlareCorona(DISPLAYBLOCK *objectPtr) +{ + VECTORCH position=objectPtr->ObWorld; + + if (CameraCanSeeThisPosition_WithIgnore(objectPtr,&position)) + { + LIGHTBLOCK *lPtr = objectPtr->ObLights[0]; + int a = lPtr->LightBright>>8; + int colour; + + if (a>255) a=255; + + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + colour = 0xffc8ff + (a<<24); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + colour = 0xffffffff; + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + int b = MUL_FIXED + ( + lPtr->RedScale+lPtr->GreenScale+lPtr->BlueScale, + lPtr->LightBright + )>>10; + if (b>255) b=255; + + colour = 0xff000000+(b<<16)+((b>>1)<<8); + break; + } + } + RenderLightFlare(&position,colour); + } +} +#define MAX_RAINDROPS 1000 +static PARTICLE RainDropStorage[MAX_RAINDROPS]; +#define MAX_NO_OF_RIPPLES 100 +RIPPLE RippleStorage[MAX_NO_OF_RIPPLES]; +int ActiveRippleNumber; +void InitialiseRainDrops(void) +{ + { + int i = MAX_RAINDROPS; + PARTICLE *particlePtr = RainDropStorage; + do + { + particlePtr->Position.vy = 0x7fffffff; + particlePtr->LifeTime = 0; + particlePtr++; + } + while(--i); + } + { + int i = MAX_NO_OF_RIPPLES; + RIPPLE *ripplePtr = RippleStorage; + do + { + ripplePtr->Active = 0; + ripplePtr++; + } + while(--i); + ActiveRippleNumber=0; + } +} + +void HandleRainDrops(MODULE *modulePtr,int numberOfRaindrops) +{ + int i = numberOfRaindrops; + + PARTICLE *particlePtr = RainDropStorage; + LOCALASSERT(iPosition.vy > modulePtr->m_world.vy+modulePtr->m_maxy-500) + ||(particlePtr->Position.vx < modulePtr->m_world.vx+modulePtr->m_minx) + ||(particlePtr->Position.vx > modulePtr->m_world.vx+modulePtr->m_maxx) + ||(particlePtr->Position.vz < modulePtr->m_world.vz+modulePtr->m_minz) + ||(particlePtr->Position.vz > modulePtr->m_world.vz+modulePtr->m_maxz)) + { + AddRipple(particlePtr->Position.vx,particlePtr->Position.vz,400); + particlePtr->Position.vy = modulePtr->m_world.vy+modulePtr->m_miny; + particlePtr->Position.vx = modulePtr->m_world.vx+modulePtr->m_minx+(FastRandom()%(modulePtr->m_maxz-modulePtr->m_minx)); + particlePtr->Position.vz = modulePtr->m_world.vz+modulePtr->m_minz+(FastRandom()%(modulePtr->m_maxz-modulePtr->m_minz)); + // particlePtr->Velocity.vy = (FastRandom()&8191)+15000; + // particlePtr->Velocity.vx = (FastRandom()&255)+5000; + // particlePtr->Velocity.vz = (FastRandom()&255)-128; + particlePtr->Velocity.vy = (FastRandom()&8191)+15000; + particlePtr->Velocity.vx = (FastRandom()&255)-128; + particlePtr->Velocity.vz = (FastRandom()&255)-128; + { + particlePtr->Offset.vx = -particlePtr->Velocity.vz; + particlePtr->Offset.vy = 0; + particlePtr->Offset.vz = particlePtr->Velocity.vx; + Normalise(&(particlePtr->Offset)); +// particlePtr->Offset.vx = MUL_FIXED(particlePtr->Offset.vx,20); +// particlePtr->Offset.vz = MUL_FIXED(particlePtr->Offset.vz,20); + particlePtr->Offset.vx = MUL_FIXED(particlePtr->Offset.vx,50); + particlePtr->Offset.vz = MUL_FIXED(particlePtr->Offset.vz,50); + } + } + { + VECTORCH prevPosition = particlePtr->Position; + + #if 0 + ParticleDynamics(particlePtr); + #else + particlePtr->Position.vx += MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Position.vz += MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + #endif + if (particlePtr->Position.vy>modulePtr->m_world.vy+modulePtr->m_maxy-500) + particlePtr->Position.vy=modulePtr->m_world.vy+modulePtr->m_maxy-495; + D3D_DrawParticle_Rain(particlePtr,&prevPosition); + } + particlePtr++; + } + while(--i); + +} +#if 0 +void HandleRain(MODULE *modulePtr,int numberOfRaindrops) +{ + int i = numberOfRaindrops; + /* KJL 15:23:37 12/8/97 - this is written to work with the yard in genshd1 */ + + PARTICLE *particlePtr = RainDropStorage; + LOCALASSERT(iPosition.vx > -10418) + &&(particlePtr->Position.vy > -4030) + &&(particlePtr->Position.vz < 35070) + &&(particlePtr->Position.vz > -11600)) + { + killDrop=1; + } + + if((particlePtr->Position.vy > 3000) + ||(particlePtr->Position.vx < modulePtr->m_world.vx+modulePtr->m_minx) + ||(particlePtr->Position.vx > modulePtr->m_world.vx+modulePtr->m_maxx) + ||(particlePtr->Position.vz < -50655)//modulePtr->m_world.vz+modulePtr->m_minz) + ||(particlePtr->Position.vz > modulePtr->m_world.vz+modulePtr->m_maxz)) + { + killDrop=1; + } + + if (killDrop) + { + particlePtr->Position.vy = modulePtr->m_world.vy+modulePtr->m_miny; + particlePtr->Position.vx = modulePtr->m_world.vx+modulePtr->m_minx+(FastRandom()%(modulePtr->m_maxz-modulePtr->m_minx)); + particlePtr->Position.vz = -50655/*+modulePtr->m_minz*/+(FastRandom()%(modulePtr->m_maxz+50655));//-modulePtr->m_minz)); + particlePtr->Velocity.vy = (FastRandom()&8191)+15000; + particlePtr->Velocity.vx = (FastRandom()&255)+5000; + particlePtr->Velocity.vz = (FastRandom()&255)-128; + { + particlePtr->Offset.vx = -particlePtr->Velocity.vz; + particlePtr->Offset.vy = 0; + particlePtr->Offset.vz = particlePtr->Velocity.vx; + Normalise(&(particlePtr->Offset)); + particlePtr->Offset.vx = MUL_FIXED(particlePtr->Offset.vx,20); + particlePtr->Offset.vz = MUL_FIXED(particlePtr->Offset.vz,20); + } + } + { + VECTORCH prevPosition = particlePtr->Position; + + #if 0 + ParticleDynamics(particlePtr); + #else + particlePtr->Position.vx += MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Position.vz += MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + #endif + D3D_DrawParticle_Rain(particlePtr,&prevPosition); + } + particlePtr++; + } + while(--i); + +} +#endif +void HandleRain(int numberOfRaindrops) +{ + int i = numberOfRaindrops; + /* KJL 15:23:37 12/8/97 - this is written to work with the yard in genshd1 */ + + PARTICLE *particlePtr = RainDropStorage; + LOCALASSERT(iPosition.vx > -10418) + &&(particlePtr->Position.vy > -4030) + &&(particlePtr->Position.vz < 35070) + &&(particlePtr->Position.vz > -11600)) + { + killDrop=1; + } + if((particlePtr->Position.vx > -45486) + &&(particlePtr->Position.vx < -29901) + &&(particlePtr->Position.vy > -6000) + &&(particlePtr->Position.vz < -50656) + &&(particlePtr->Position.vz > -70130)) + { + killDrop=1; + } + + if((particlePtr->Position.vy > 3000) + ||(particlePtr->Position.vx < -77000) + ||(particlePtr->Position.vx > 134000) + ||(particlePtr->Position.vz < -145000)//modulePtr->m_world.vz+modulePtr->m_minz) + ||(particlePtr->Position.vz > 48706)) + { + killDrop=1; + } + + if (killDrop) + { + particlePtr->Position.vy = -10000; + particlePtr->Position.vx = -77000+(FastRandom()%(211000)); + particlePtr->Position.vz = -145000+(FastRandom()%(145000+49000)); + particlePtr->Velocity.vy = (FastRandom()&8191)+15000; + particlePtr->Velocity.vx = (FastRandom()&255)+5000; + particlePtr->Velocity.vz = (FastRandom()&255)-128; + { + particlePtr->Offset.vx = -particlePtr->Velocity.vz; + particlePtr->Offset.vy = 0; + particlePtr->Offset.vz = particlePtr->Velocity.vx; + Normalise(&(particlePtr->Offset)); + particlePtr->Offset.vx = MUL_FIXED(particlePtr->Offset.vx,20); + particlePtr->Offset.vz = MUL_FIXED(particlePtr->Offset.vz,20); + } + } + { + VECTORCH prevPosition = particlePtr->Position; + + #if 0 + ParticleDynamics(particlePtr); + #else + particlePtr->Position.vx += MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Position.vz += MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + #endif + D3D_DrawParticle_Rain(particlePtr,&prevPosition); + } + particlePtr++; + } + while(--i); + +} +void HandleRainInTrench(int numberOfRaindrops) +{ + int i = numberOfRaindrops; + /* KJL 15:23:37 12/8/97 - this is written to work with the yard in genshd1 */ + + PARTICLE *particlePtr = RainDropStorage; + LOCALASSERT(iPosition.vx > -10418) + &&(particlePtr->Position.vy > -4030) + &&(particlePtr->Position.vz < 35070) + &&(particlePtr->Position.vz > -11600)) + { + killDrop=1; + } + */ + if((particlePtr->Position.vy > 3000) + ||(particlePtr->Position.vx < 13500) + ||(particlePtr->Position.vx > -50000) + ||(particlePtr->Position.vz < -150655) + ||(particlePtr->Position.vz > -50655)) + { + killDrop=1; + } + + if (killDrop) + { + particlePtr->Position.vy = -16000; + particlePtr->Position.vx = -50000+(FastRandom()%(63500)); + particlePtr->Position.vz = -150655+(FastRandom()%(100000)); + particlePtr->Velocity.vy = (FastRandom()&8191)+15000; + particlePtr->Velocity.vx = (FastRandom()&255)+5000; + particlePtr->Velocity.vz = (FastRandom()&255)-128; + { + particlePtr->Offset.vx = -particlePtr->Velocity.vz; + particlePtr->Offset.vy = 0; + particlePtr->Offset.vz = particlePtr->Velocity.vx; + Normalise(&(particlePtr->Offset)); + particlePtr->Offset.vx = MUL_FIXED(particlePtr->Offset.vx,20); + particlePtr->Offset.vz = MUL_FIXED(particlePtr->Offset.vz,20); + } + } + { + VECTORCH prevPosition = particlePtr->Position; + + #if 0 + ParticleDynamics(particlePtr); + #else + particlePtr->Position.vx += MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Position.vz += MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); + #endif + D3D_DrawParticle_Rain(particlePtr,&prevPosition); + } + particlePtr++; + } + while(--i); + +} + +void HandleRainShaft(MODULE *modulePtr, int bottomY, int topY, int numberOfRaindrops) +{ + int i = numberOfRaindrops; + PARTICLE_DESC *particleDescPtr = &ParticleDescription[PARTICLE_WATERFALLSPRAY]; + + PARTICLE *particlePtr = RainDropStorage; + LOCALASSERT(iPosition.vx < modulePtr->m_world.vx+modulePtr->m_minx) + ||(particlePtr->Position.vx > modulePtr->m_world.vx+modulePtr->m_maxx) + ||(particlePtr->Position.vz < modulePtr->m_world.vz+modulePtr->m_minz) + ||(particlePtr->Position.vz > modulePtr->m_world.vz+modulePtr->m_maxz)) + { + particlePtr->LifeTime=0; + } + else if(particlePtr->Position.vy > bottomY) + { + particlePtr->Position.vy = bottomY; + particlePtr->Velocity.vy = -particlePtr->Velocity.vy; + particlePtr->Velocity.vx = particlePtr->Velocity.vx; + particlePtr->Velocity.vz = particlePtr->Velocity.vz; + particlePtr->LifeTime = 1; + particlePtr->Size = 100; + AddRipple(particlePtr->Position.vx,particlePtr->Position.vz,100); + } + + if (particlePtr->LifeTime<=0) + { + particlePtr->Position.vy = topY; + particlePtr->Position.vx = modulePtr->m_world.vx+modulePtr->m_minx+(FastRandom()%(modulePtr->m_maxz-modulePtr->m_minx)); + particlePtr->Position.vz = modulePtr->m_world.vz+modulePtr->m_minz+(FastRandom()%(modulePtr->m_maxz-modulePtr->m_minz)); + particlePtr->Velocity.vy = (FastRandom()&8191)+15000; + particlePtr->Velocity.vx = (FastRandom()&1023)-512; + particlePtr->Velocity.vz = (FastRandom()&1023)-512; + particlePtr->LifeTime = 100*ONE_FIXED; + particlePtr->ParticleID = PARTICLE_WATERFALLSPRAY; + particlePtr->Colour = RGBALIGHT_MAKE + ( + particleDescPtr->RedScale[CurrentVisionMode], + particleDescPtr->GreenScale[CurrentVisionMode], + particleDescPtr->BlueScale[CurrentVisionMode], + particleDescPtr->Alpha + ); + particlePtr->Size = 20; + } + else + { + particlePtr->LifeTime -= NormalFrameTime; + } + + { + particlePtr->Position.vx += MUL_FIXED(particlePtr->Velocity.vx,NormalFrameTime); + particlePtr->Position.vy += MUL_FIXED(particlePtr->Velocity.vy,NormalFrameTime); + particlePtr->Position.vz += MUL_FIXED(particlePtr->Velocity.vz,NormalFrameTime); +#if 0 + D3D_DrawParticle_Rain(particlePtr,&prevPosition); +#else + particlePtr->Offset.vx = particlePtr->Position.vx - particlePtr->Velocity.vx/16; + particlePtr->Offset.vy = particlePtr->Position.vy - particlePtr->Velocity.vy/16; + particlePtr->Offset.vz = particlePtr->Position.vz - particlePtr->Velocity.vz/16; + + RenderParticle(particlePtr); +#endif + } + particlePtr++; + } + while(--i); + +} + +#include +void HandleRipples(void) +{ + extern int sine[]; + int i; + + for(i=0; ivx+point->vz+CloakingPhase)&4095)>>11; + offset += GetSin((point->vx-point->vz*2+CloakingPhase/2)&4095)>>12; + + for(i=0; ivx-RippleStorage[i].X; + int dz=point->vz-RippleStorage[i].Z; + + if (dx<0) dx = -dx; + if (dz<0) dz = -dz; + { + int a; + + if (dx>dz) + { + a = dx+(dz>>1); + } + else + { + a = dz+(dx>>1); + } + + if (a256) offset = 256; + else if (offset<-256) offset = -256; + return offset; +} + + +void AddRipple(int x,int z,int amplitude) +{ + RippleStorage[ActiveRippleNumber].Active=1; + RippleStorage[ActiveRippleNumber].X = x; + RippleStorage[ActiveRippleNumber].Z = z; + RippleStorage[ActiveRippleNumber].Radius = 200; + RippleStorage[ActiveRippleNumber].Amplitude = amplitude; + + ActiveRippleNumber++; + if (ActiveRippleNumber == MAX_NO_OF_RIPPLES) ActiveRippleNumber=0; + +} + + +void CheckForObjectsInWater(int minX, int maxX, int minZ, int maxZ, int averageY) +{ + extern int NumActiveBlocks; + extern DISPLAYBLOCK* ActiveBlockList[]; + int numberOfObjects = NumActiveBlocks; + + while (numberOfObjects--) + { + DISPLAYBLOCK* objectPtr = ActiveBlockList[numberOfObjects]; + + if(objectPtr->ObStrategyBlock) + { + DYNAMICSBLOCK *dynPtr = objectPtr->ObStrategyBlock->DynPtr; + + + if (dynPtr) + { + int overlapInY=0; + int overlapInX=0; + int overlapInZ=0; + + /* floating objects are ignored to avoid positive feedback */ + if(dynPtr->IsFloating) continue; + #if 1 + if ( (dynPtr->Position.vx==dynPtr->PrevPosition.vx) + &&(dynPtr->Position.vy==dynPtr->PrevPosition.vy) + &&(dynPtr->Position.vz==dynPtr->PrevPosition.vz) ) + continue; + #endif + + if (dynPtr->Position.vy>dynPtr->PrevPosition.vy) + { + if ((dynPtr->Position.vy+objectPtr->ObRadius > averageY) + &&(dynPtr->PrevPosition.vy-objectPtr->ObRadius < averageY)) + { + overlapInY=1; + } + } + else + { + if ((dynPtr->PrevPosition.vy+objectPtr->ObRadius > averageY) + &&(dynPtr->Position.vy-objectPtr->ObRadius < averageY)) + { + overlapInY=1; + } + } + + if (!overlapInY) continue; + + if (dynPtr->Position.vx>dynPtr->PrevPosition.vx) + { + if ((dynPtr->Position.vx+objectPtr->ObRadius > minX) + &&(dynPtr->PrevPosition.vx-objectPtr->ObRadius < maxX)) + { + overlapInX=1; + } + } + else + { + if ((dynPtr->PrevPosition.vx+objectPtr->ObRadius > minX) + &&(dynPtr->Position.vx-objectPtr->ObRadius < maxX)) + { + overlapInX=1; + } + } + + if (!overlapInX) continue; + + if (dynPtr->Position.vz>dynPtr->PrevPosition.vz) + { + if ((dynPtr->Position.vz+objectPtr->ObRadius > minZ) + &&(dynPtr->PrevPosition.vz-objectPtr->ObRadius < maxZ)) + { + overlapInZ=1; + } + } + else + { + if ((dynPtr->PrevPosition.vz+objectPtr->ObRadius > minZ) + &&(dynPtr->Position.vz-objectPtr->ObRadius < maxZ)) + { + overlapInZ=1; + } + } + + if (!overlapInZ) continue; + + /* we have an overlap */ + + /* KJL 16:37:29 27/08/98 - if object is on fire its now put out */ + objectPtr->ObStrategyBlock->SBDamageBlock.IsOnFire=0; + + if (objectPtr->ObStrategyBlock->I_SBtype == I_BehaviourFlareGrenade) + { + VECTORCH upwards = {0,-65536,0}; + dynPtr->IsFloating = 1; + dynPtr->GravityOn = 0; + dynPtr->Elasticity = 0; + MakeMatrixFromDirection(&upwards,&(dynPtr->OrientMat)); + } + else if (objectPtr == Player) + { + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(objectPtr->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + playerStatusPtr->IsMovingInWater = 1; + } + { + + AddRipple(dynPtr->Position.vx,dynPtr->Position.vz,100); + #if 0 + { + int i; + for (i=0; i<10; i++) + { + VECTORCH velocity; + velocity.vy = (-(FastRandom()%(magnitude)))*8; + velocity.vx = ((FastRandom()&1023)-512)*8; + velocity.vz = ((FastRandom()&1023)-512)*8; + MakeParticle(&(dynPtr->Position), &velocity, PARTICLE_WATERSPRAY); + } + } + #endif + } + } + } + } +} + +void DrawMuzzleFlash(VECTORCH *positionPtr,VECTORCH *directionPtr, enum MUZZLE_FLASH_ID muzzleFlashID) +{ + PARTICLE particle; + particle.Position = *positionPtr; + + D3D_DecalSystem_Setup(); + + switch (muzzleFlashID) + { + case MUZZLE_FLASH_SMARTGUN: + { + #if 0 + PARTICLE_DESC *particleDescPtr; + particle.ParticleID=PARTICLE_SMARTGUNMUZZLEFLASH; + particleDescPtr = &ParticleDescription[particle.ParticleID]; + + particle.Colour = RGBALIGHT_MAKE(particleDescPtr->RedScale[CurrentVisionMode],particleDescPtr->GreenScale[CurrentVisionMode],particleDescPtr->BlueScale[CurrentVisionMode],particleDescPtr->Alpha); + particle.Size = particleDescPtr->Size; + + particle.Position.vx += MUL_FIXED(100,directionPtr->vx); + particle.Position.vy += MUL_FIXED(100,directionPtr->vy); + particle.Position.vz += MUL_FIXED(100,directionPtr->vz); + RenderParticle(&particle); + #else + PARTICLE_DESC *particleDescPtr=&ParticleDescription[PARTICLE_MUZZLEFLASH]; + MATRIXCH muzzleMatrix; + MATRIXCH rotmat; + MakeMatrixFromDirection(directionPtr,&muzzleMatrix); + { + extern int cosine[], sine[]; + int angle = 4096/12; + int cos = GetCos(angle); + int sin = GetSin(angle); + rotmat.mat11 = cos; + rotmat.mat12 = sin; + rotmat.mat13 = 0; + rotmat.mat21 = -sin; + rotmat.mat22 = cos; + rotmat.mat23 = 0; + rotmat.mat31 = 0; + rotmat.mat32 = 0; + rotmat.mat33 = 65536; + } + #if 1 + { + int i = 16; + PARTICLE particle; + + particle.Position = *positionPtr; + particle.Position.vx += MUL_FIXED(100 - (FastRandom()&15),directionPtr->vx); + particle.Position.vy += MUL_FIXED(100 - (FastRandom()&15),directionPtr->vy); + particle.Position.vz += MUL_FIXED(100 - (FastRandom()&15),directionPtr->vz); + + particle.ParticleID=PARTICLE_MUZZLEFLASH; + + particle.Colour = RGBALIGHT_MAKE(particleDescPtr->RedScale[CurrentVisionMode],particleDescPtr->GreenScale[CurrentVisionMode],particleDescPtr->BlueScale[CurrentVisionMode],particleDescPtr->Alpha); + particle.Size = 200; + + while(i--) + { + RenderParticle(&particle); + particle.Position.vx += MUL_FIXED(50 - (FastRandom()&15),directionPtr->vx); + particle.Position.vy += MUL_FIXED(50 - (FastRandom()&15),directionPtr->vy); + particle.Position.vz += MUL_FIXED(50 - (FastRandom()&15),directionPtr->vz); + particle.Size -= (FastRandom()&3)+3; + } + + } + #endif + { + int a; + for (a=0; a<12;a++) + { + int i=8; + PARTICLE particle; + + particle.Position = *positionPtr; + particle.Position.vx += -MUL_FIXED(200,directionPtr->vx) + MUL_FIXED(50,muzzleMatrix.mat21); + particle.Position.vy += -MUL_FIXED(200,directionPtr->vy) + MUL_FIXED(50,muzzleMatrix.mat22); + particle.Position.vz += -MUL_FIXED(200,directionPtr->vz) + MUL_FIXED(50,muzzleMatrix.mat23); + + particle.ParticleID=PARTICLE_MUZZLEFLASH; + + particle.Colour = RGBALIGHT_MAKE(particleDescPtr->RedScale[CurrentVisionMode],particleDescPtr->GreenScale[CurrentVisionMode],particleDescPtr->BlueScale[CurrentVisionMode],particleDescPtr->Alpha); + particle.Size = 50; + + if (!(a&1)) i+=8; + + while(i--) + { + RenderParticle(&particle); + particle.Position.vx += MUL_FIXED((FastRandom()&31)+16,muzzleMatrix.mat21); + particle.Position.vy += MUL_FIXED((FastRandom()&31)+16,muzzleMatrix.mat22); + particle.Position.vz += MUL_FIXED((FastRandom()&31)+16,muzzleMatrix.mat23); + particle.Size += (FastRandom()&15); + } + + MatrixMultiply(&muzzleMatrix,&rotmat,&muzzleMatrix); + } + + } + #endif + break; + } + case MUZZLE_FLASH_AMORPHOUS: + { + PARTICLE_DESC *particleDescPtr; + particle.ParticleID=PARTICLE_MUZZLEFLASH; + particleDescPtr = &ParticleDescription[particle.ParticleID]; + + particle.Colour = RGBALIGHT_MAKE(particleDescPtr->RedScale[CurrentVisionMode],particleDescPtr->GreenScale[CurrentVisionMode],particleDescPtr->BlueScale[CurrentVisionMode],particleDescPtr->Alpha); + particle.Size = particleDescPtr->Size; + + RenderParticle(&particle); + particle.Position.vx += MUL_FIXED(100,directionPtr->vx); + particle.Position.vy += MUL_FIXED(100,directionPtr->vy); + particle.Position.vz += MUL_FIXED(100,directionPtr->vz); + RenderParticle(&particle); + particle.Position.vx += MUL_FIXED(100,directionPtr->vx); + particle.Position.vy += MUL_FIXED(100,directionPtr->vy); + particle.Position.vz += MUL_FIXED(100,directionPtr->vz); + RenderParticle(&particle); + { + int i = 16; + particle.Size = 20; + + while(i--) + { + RenderParticle(&particle); + particle.Position.vx = positionPtr->vx + MUL_FIXED(100,directionPtr->vx) + (FastRandom()&127)-64; + particle.Position.vy = positionPtr->vy + MUL_FIXED(100,directionPtr->vy) + (FastRandom()&127)-64; + particle.Position.vz = positionPtr->vz + MUL_FIXED(100,directionPtr->vz) + (FastRandom()&127)-64; + } + + } + break; + } + case MUZZLE_FLASH_SKEETER: + { + PARTICLE_DESC *particleDescPtr; + particle.ParticleID=PARTICLE_MUZZLEFLASH; + particleDescPtr = &ParticleDescription[particle.ParticleID]; + + particle.Colour = RGBALIGHT_MAKE(particleDescPtr->RedScale[CurrentVisionMode],particleDescPtr->GreenScale[CurrentVisionMode],particleDescPtr->BlueScale[CurrentVisionMode],particleDescPtr->Alpha); + particle.Size = particleDescPtr->Size; + + RenderParticle(&particle); + particle.Position.vx += MUL_FIXED(20,directionPtr->vx); + particle.Position.vy += MUL_FIXED(20,directionPtr->vy); + particle.Position.vz += MUL_FIXED(20,directionPtr->vz); + RenderParticle(&particle); + particle.Position.vx += MUL_FIXED(20,directionPtr->vx); + particle.Position.vy += MUL_FIXED(20,directionPtr->vy); + particle.Position.vz += MUL_FIXED(20,directionPtr->vz); + RenderParticle(&particle); + { + int i = 16; + particle.Size = 20; + + while(i--) + { + RenderParticle(&particle); + particle.Position.vx = positionPtr->vx + MUL_FIXED(100,directionPtr->vx) + (FastRandom()&127)-64; + particle.Position.vy = positionPtr->vy + MUL_FIXED(100,directionPtr->vy) + (FastRandom()&127)-64; + particle.Position.vz = positionPtr->vz + MUL_FIXED(100,directionPtr->vz) + (FastRandom()&127)-64; + } + + } + break; + } + default: + { + LOCALASSERT(0); + return; + } + } + D3D_DecalSystem_End(); + +} + +void DrawFrisbeePlasmaBolt(VECTORCH *positionPtr,VECTORCH *directionPtr) +{ + int i = 16; + PARTICLE particle; + + particle.Position = *positionPtr; + + particle.ParticleID=PARTICLE_MUZZLEFLASH; + + particle.Colour = RGBALIGHT_MAKE(255,255,255,255); + particle.Size = 200; + + while(i--) + { + RenderParticle(&particle); + particle.Position.vx -= MUL_FIXED(50,directionPtr->vx); + particle.Position.vy -= MUL_FIXED(50,directionPtr->vy); + particle.Position.vz -= MUL_FIXED(50,directionPtr->vz); + particle.Size -= 10; + } + +} + +void DrawPredatorPlasmaBolt(VECTORCH *positionPtr,VECTORCH *directionPtr) +{ + int i = 16; + PARTICLE particle; + + particle.Position = *positionPtr; + + particle.ParticleID=PARTICLE_MUZZLEFLASH; + + particle.Colour = RGBALIGHT_MAKE(50,255,255,255); + particle.Size = 200; + + while(i--) + { + RenderParticle(&particle); + particle.Position.vx -= MUL_FIXED(50,directionPtr->vx); + particle.Position.vy -= MUL_FIXED(50,directionPtr->vy); + particle.Position.vz -= MUL_FIXED(50,directionPtr->vz); + particle.Size -= 10; + } + +} + +void DrawSmallPredatorPlasmaBolt(VECTORCH *positionPtr,VECTORCH *directionPtr) +{ + #if 0 + int i = 16; + PARTICLE particle; + + particle.Position = *positionPtr; + + particle.ParticleID=PARTICLE_MUZZLEFLASH; + + particle.Colour = RGBALIGHT_MAKE(50,255,255,255); + particle.Size = 100; + + while(i--) + { + RenderParticle(&particle); + particle.Position.vx -= MUL_FIXED(25,directionPtr->vx); + particle.Position.vy -= MUL_FIXED(25,directionPtr->vy); + particle.Position.vz -= MUL_FIXED(25,directionPtr->vz); + particle.Size -= 5; + } + #else + PARTICLE particle; + + particle.Position = *positionPtr; + + particle.ParticleID=PARTICLE_ELECTRICALPLASMASPHERE; + + particle.Colour = RGBALIGHT_MAKE(255,255,255,128); + particle.Size = 200; + + RenderParticle(&particle); + particle.ParticleID=PARTICLE_MUZZLEFLASH; + particle.Colour = RGBALIGHT_MAKE(255,255,255,64); + particle.Size = 1000; + RenderParticle(&particle); + RenderParticle(&particle); + + #endif + +} + + + +void MakeFlareParticle(DYNAMICSBLOCK *dynPtr) +{ +// int i = MUL_FIXED(4,density); +// while(i--) + { + VECTORCH velocity; + velocity.vx = ((FastRandom()&2047) - 1024); + velocity.vy = ((FastRandom()&2047) - 1024); + velocity.vz = (1000+(FastRandom()&255))*2; + RotateVector(&velocity,&(dynPtr->OrientMat)); + MakeParticle(&(dynPtr->Position),&(velocity),PARTICLE_FLARESMOKE); + } +} +void MakeRocketTrailParticles(VECTORCH *prevPositionPtr, VECTORCH *positionPtr) +{ + VECTORCH disp; + + disp.vx = positionPtr->vx - prevPositionPtr->vx; + disp.vy = positionPtr->vy - prevPositionPtr->vy; + disp.vz = positionPtr->vz - prevPositionPtr->vz; + + if (disp.vx!=0 || disp.vy!=0 || disp.vz!=0) + { + int i=16; + do + { + { + VECTORCH position; + VECTORCH velocity; + velocity.vx = (FastRandom()&1023) - 512; + velocity.vy = (FastRandom()&1023) - 512; + velocity.vz = (FastRandom()&1023) - 512; + + position.vx = prevPositionPtr->vx + (disp.vx*i)/16; + position.vy = prevPositionPtr->vy + (disp.vy*i)/16; + position.vz = prevPositionPtr->vz + (disp.vz*i)/16; + + MakeParticle(&position,&(velocity),PARTICLE_BLACKSMOKE); + } + } + while(i--); + } +} +void MakeGrenadeTrailParticles(VECTORCH *prevPositionPtr, VECTORCH *positionPtr) +{ + VECTORCH disp; + + disp.vx = positionPtr->vx - prevPositionPtr->vx; + disp.vy = positionPtr->vy - prevPositionPtr->vy; + disp.vz = positionPtr->vz - prevPositionPtr->vz; + + if (!(disp.vx==0 && disp.vy==0 && disp.vz==0)) + { + int i=8; + do + { + { + VECTORCH position; + VECTORCH velocity; + velocity.vx = (FastRandom()&1023) - 512; + velocity.vy = (FastRandom()&1023) - 512; + velocity.vz = (FastRandom()&1023) - 512; + + position.vx = prevPositionPtr->vx + (disp.vx*i)/16; + position.vy = prevPositionPtr->vy + (disp.vy*i)/16; + position.vz = prevPositionPtr->vz + (disp.vz*i)/16; + + MakeParticle(&position,&(velocity),PARTICLE_FLARESMOKE); + } + } + while(i--); + } +} + +void MakeImpactSmoke(MATRIXCH *orientationPtr, VECTORCH *positionPtr) +{ + int i = 5; + while(i--) + { + VECTORCH velocity; + velocity.vx = ((FastRandom()&1023) - 512); + velocity.vy = ((FastRandom()&1023) - 512); + velocity.vz = (255+(FastRandom()&255)); + RotateVector(&velocity,orientationPtr); + MakeParticle(positionPtr,&(velocity),PARTICLE_IMPACTSMOKE); + } +} + +void MakeImpactSparks(VECTORCH *incidentPtr, VECTORCH *normalPtr, VECTORCH *positionPtr) +{ + int noOfSparks = 5; + VECTORCH velocity; + int d = -2*DotProduct(incidentPtr,normalPtr); + velocity.vx = (incidentPtr->vx + MUL_FIXED(d,normalPtr->vx))>>3; + velocity.vy = (incidentPtr->vy + MUL_FIXED(d,normalPtr->vy))>>3; + velocity.vz = (incidentPtr->vz + MUL_FIXED(d,normalPtr->vz))>>3; + + do + { + +// VECTORCH velocity; + velocity.vx = velocity.vx + (FastRandom()&2047)-1024; + velocity.vy = velocity.vy + (FastRandom()&2047)-1024; + velocity.vz = velocity.vz + (FastRandom()&2047)-1024; + MakeParticle(positionPtr,&velocity,PARTICLE_RICOCHET_SPARK); + } + while(--noOfSparks); + MakeRicochetSound(positionPtr); +} + +void MakeSprayOfSparks(MATRIXCH *orientationPtr, VECTORCH *positionPtr) +{ + int noOfSparks = 15; + do + { + + VECTORCH velocity; + velocity.vx = (FastRandom()&2047)-1024; + velocity.vy = (FastRandom()&2047); + velocity.vz = -(FastRandom()&2047)-1024; + RotateVector(&velocity,orientationPtr); + MakeParticle(positionPtr,&velocity,PARTICLE_SPARK); + } + while(--noOfSparks); + + MakeLightElement(positionPtr,LIGHTELEMENT_ELECTRICAL_SPARKS); +} + +void MakeVolumetricExplosionAt(VECTORCH *positionPtr, enum EXPLOSION_ID explosionID) +{ + switch (explosionID) + { + case EXPLOSION_HUGE: + case EXPLOSION_HUGE_NOCOLLISIONS: + { + VOLUMETRIC_EXPLOSION *expPtr; + int i; + int r; + + /* KJL 11:49:25 19/08/98 - check to see if explosion is inside environment */ + { + MODULE *module = ModuleFromPosition(positionPtr, (MODULE*)NULL); + if (!module) return; + } + + expPtr = AllocateVolumetricExplosion(); + r = (FastRandom()&7)+1; + + if (explosionID == EXPLOSION_HUGE_NOCOLLISIONS) + { + expPtr->UseCollisions = 0; + } + else + { + expPtr->UseCollisions = 1; + } + + for(i=0; iPosition[i] = *positionPtr; + expPtr->Velocity[i].vx = SphereVertex[i].vx; + expPtr->Velocity[i].vy = SphereVertex[i].vy; + expPtr->Velocity[i].vz = SphereVertex[i].vz; + expPtr->BeenStopped[i] = 0; + expPtr->RipplePhase[i] = FastRandom()&4095; + expPtr->NumberVerticesMoving=SPHERE_VERTICES; + } + expPtr->LifeTime = ONE_FIXED-1; + expPtr->ExplosionPhase = 1; + + for(i=0; ivx!=Player->ObWorld.vx) + ||(positionPtr->vy!=Player->ObWorld.vy) + ||(positionPtr->vz!=Player->ObWorld.vz)) + { + MakeLightElement(positionPtr, LIGHTELEMENT_EXPLOSION); + } + + #if 1 + for (i=0; iUseCollisions = 0; + } + else + { + expPtr->UseCollisions = 1; + } + r = (FastRandom()&7)+1; + + for(i=0; iPosition[i] = *positionPtr; + expPtr->Velocity[i].vx = SphereVertex[i].vx; + expPtr->Velocity[i].vy = SphereVertex[i].vy; + expPtr->Velocity[i].vz = SphereVertex[i].vz; + expPtr->BeenStopped[i] = 0; + expPtr->RipplePhase[i] = FastRandom()&4095; + expPtr->NumberVerticesMoving=SPHERE_VERTICES; + } + expPtr->LifeTime = ONE_FIXED/2; + expPtr->ExplosionPhase = 1; + #endif + #if 0 + for(i=0; ivx!=Player->ObWorld.vx) + ||(positionPtr->vy!=Player->ObWorld.vy) + ||(positionPtr->vz!=Player->ObWorld.vz)) + { + MakeLightElement(positionPtr, LIGHTELEMENT_EXPLOSION); +// MakeLightElement(positionPtr, LIGHTELEMENT_ELECTRICAL_EXPLOSION); + } + + #if 1 + for (i=0; iLifeTime) return; + RenderExplosionSurface(expPtr); + + if (expPtr->ExplosionPhase) + { + { + int v = (DIV_FIXED(SPHERE_VERTICES,expPtr->NumberVerticesMoving+1)+ONE_FIXED); + velocityModifier = MUL_FIXED(GetSin(expPtr->LifeTime/64)/16,v); + } + + for(i=0; iVelocity[i].vx==0) + &&(expPtr->Velocity[i].vy==0) + &&(expPtr->Velocity[i].vz==0)) + continue; + particle.Velocity = expPtr->Velocity[i]; + #if 1 + { + v = GetSin((CloakingPhase*4+expPtr->RipplePhase[i])&4095)/4; + v = velocityModifier+MUL_FIXED(v,velocityModifier); + } + #endif + particle.Velocity.vx = MUL_FIXED(particle.Velocity.vx,v); + particle.Velocity.vy = MUL_FIXED(particle.Velocity.vy,v); + particle.Velocity.vz = MUL_FIXED(particle.Velocity.vz,v); + + + particle.Position = expPtr->Position[i]; + + if(LocalDetailLevels.ExplosionsDeformToEnvironment && expPtr->UseCollisions) + { + if(ParticleDynamics(&particle,&obstacleNormal,&moduleIndex)) + { + int magOfPerpImp = DotProduct(&obstacleNormal,&(expPtr->Velocity[i])); + expPtr->Velocity[i].vx -= MUL_FIXED(obstacleNormal.vx, magOfPerpImp); + expPtr->Velocity[i].vy -= MUL_FIXED(obstacleNormal.vy, magOfPerpImp); + expPtr->Velocity[i].vz -= MUL_FIXED(obstacleNormal.vz, magOfPerpImp); + + if(!expPtr->BeenStopped[i]) + { + expPtr->BeenStopped[i] = 1; + expPtr->NumberVerticesMoving--; + } + } + } + else + { + particle.Position.vx += MUL_FIXED(particle.Velocity.vx,NormalFrameTime); + particle.Position.vy += MUL_FIXED(particle.Velocity.vy,NormalFrameTime); + particle.Position.vz += MUL_FIXED(particle.Velocity.vz,NormalFrameTime); + } + expPtr->Position[i] = particle.Position; + } + + + expPtr->LifeTime -= NormalFrameTime; + + if (expPtr->LifeTime<=0) + { + expPtr->LifeTime=0; + } + } +} + +void MakeOldVolumetricExplosionAt(VECTORCH *positionPtr) +{ + int noRequired = 32;//MUL_FIXED(2500,NormalFrameTime); + int i; +// VECTORCH zero={0,0,0}; + for (i=0; ivx - blastPositionPtr->vx; + blastDir.vy = originPtr->vy - blastPositionPtr->vy; + blastDir.vz = originPtr->vz - blastPositionPtr->vz; + + for (i=0; ivx + MUL_FIXED(velocity.vx,r); + position.vy = originPtr->vy + MUL_FIXED(velocity.vy,r); + position.vz = originPtr->vz + MUL_FIXED(velocity.vz,r); + + velocity.vx = MUL_FIXED(velocity.vx,speed); + velocity.vy = MUL_FIXED(velocity.vy,speed); + velocity.vz = MUL_FIXED(velocity.vz,speed); + + + MakeParticle(&position, &velocity, particleID); + } +} + + +void MakeFocusedExplosion(VECTORCH *originPtr, VECTORCH *blastPositionPtr, int noOfParticles, enum PARTICLE_ID particleID) +{ + VECTORCH blastDir; + int i; + + blastDir.vx = originPtr->vx - blastPositionPtr->vx; + blastDir.vy = originPtr->vy - blastPositionPtr->vy; + blastDir.vz = originPtr->vz - blastPositionPtr->vz; + + for (i=0; ivx + MUL_FIXED(velocity.vx,r); + position.vy = originPtr->vy + MUL_FIXED(velocity.vy,r); + position.vz = originPtr->vz + MUL_FIXED(velocity.vz,r); + + velocity.vx = MUL_FIXED(velocity.vx,speed); + velocity.vy = MUL_FIXED(velocity.vy,speed); + velocity.vz = MUL_FIXED(velocity.vz,speed); + + + MakeParticle(&position, &velocity, particleID); + } +} + + + + +void MakePlasmaTrailParticles(DYNAMICSBLOCK *dynPtr, int number) +{ + + VECTORCH disp; + + disp.vx = dynPtr->Position.vx - dynPtr->PrevPosition.vx; + disp.vy = dynPtr->Position.vy - dynPtr->PrevPosition.vy; + disp.vz = dynPtr->Position.vz - dynPtr->PrevPosition.vz; + + // if (disp.vx!=0 || disp.vy!=0 || disp.vz!=0) + { + int i=number; + do + { + VECTORCH velocity; + VECTORCH position; + #if 1 + + int phi = FastRandom()&4095; + int speed = 512; + + velocity.vz = (FastRandom()&131071) - ONE_FIXED; + { + float z = ((float)velocity.vz)/65536.0; + z = sqrt(1-z*z); + + f2i(velocity.vx,(float)GetCos(phi)*z); + f2i(velocity.vy,(float)GetSin(phi)*z); + } + + velocity.vx = MUL_FIXED(velocity.vx,speed);//+dynPtr->LinVelocity.vx/32; + velocity.vy = MUL_FIXED(velocity.vy,speed);//+dynPtr->LinVelocity.vy/32; + velocity.vz = MUL_FIXED(velocity.vz,speed);//+dynPtr->LinVelocity.vz/32; + #else + velocity.vx = dynPtr->LinVelocity.vx; + velocity.vy = dynPtr->LinVelocity.vy; + velocity.vz = dynPtr->LinVelocity.vz; + #endif + position.vx = dynPtr->PrevPosition.vx + (disp.vx*i)/number; + position.vy = dynPtr->PrevPosition.vy + (disp.vy*i)/number; + position.vz = dynPtr->PrevPosition.vz + (disp.vz*i)/number; + + MakeParticle(&position, &velocity, PARTICLE_PLASMATRAIL); + } + while(i--); + } +} + +void MakeDewlineTrailParticles(DYNAMICSBLOCK *dynPtr, int number) +{ + + VECTORCH disp; + + disp.vx = dynPtr->Position.vx - dynPtr->PrevPosition.vx; + disp.vy = dynPtr->Position.vy - dynPtr->PrevPosition.vy; + disp.vz = dynPtr->Position.vz - dynPtr->PrevPosition.vz; + + // if (disp.vx!=0 || disp.vy!=0 || disp.vz!=0) + { + int i=number; + do + { + VECTORCH velocity; + VECTORCH position; + #if 1 + + int phi = FastRandom()&4095; + int speed = 256; //512 + + velocity.vz = (FastRandom()&131071) - ONE_FIXED; + { + float z = ((float)velocity.vz)/65536.0; + z = sqrt(1-z*z); + + f2i(velocity.vx,(float)GetCos(phi)*z); + f2i(velocity.vy,(float)GetSin(phi)*z); + } + + velocity.vx = MUL_FIXED(velocity.vx,speed);//+dynPtr->LinVelocity.vx/32; + velocity.vy = MUL_FIXED(velocity.vy,speed);//+dynPtr->LinVelocity.vy/32; + velocity.vz = MUL_FIXED(velocity.vz,speed);//+dynPtr->LinVelocity.vz/32; + #else + velocity.vx = dynPtr->LinVelocity.vx; + velocity.vy = dynPtr->LinVelocity.vy; + velocity.vz = dynPtr->LinVelocity.vz; + #endif + position.vx = dynPtr->PrevPosition.vx + (disp.vx*i)/number; + position.vy = dynPtr->PrevPosition.vy + (disp.vy*i)/number; + position.vz = dynPtr->PrevPosition.vz + (disp.vz*i)/number; + + MakeParticle(&position, &velocity, PARTICLE_DEWLINE); + } + while(i--); + } +} + +void DrawXenoborgMainLaserbeam(LASER_BEAM_DESC *laserPtr) +{ + if (laserPtr->BeamHasHitPlayer) + { + int colour; + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + colour = 0xff0000ff; + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + colour = 0xffffffff; + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + colour = 0xffff8000; + break; + } + } + RenderLightFlare(&(laserPtr->SourcePosition),colour); + RenderLightFlare(&(laserPtr->SourcePosition),0xffffffff); + } + else + { + PARTICLE particle; + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + particle.Colour = RGBALIGHT_MAKE(0,0,255,255); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + particle.Colour = RGBALIGHT_MAKE(255,255,255,255); + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + particle.Colour = RGBALIGHT_MAKE(255,128,0,255); + break; + } + } + particle.Colour = RGBALIGHT_MAKE(255,255,255,255); + particle.ParticleID = PARTICLE_PLASMABEAM; + particle.Position = laserPtr->SourcePosition; + particle.Offset = laserPtr->TargetPosition; + particle.Size = 32; + RenderParticle(&particle); + // particle.Colour = RGBALIGHT_MAKE(255,255,255,255); + // particle.Size = 20; + // RenderParticle(&particle); + + } +} +/* KJL 16:37:03 20/06/98 - stupid but quick implementation */ +#define NO_OF_VERTICES_IN_TRAIL 300 +PHEROMONE_TRAIL Trail[NO_OF_VERTICES_IN_TRAIL]; + +void NewTrailPoint(DYNAMICSBLOCK *dynPtr) +{ + PHEROMONE_TRAIL *trailPtr = AllocatePheromoneTrail(); + if (!trailPtr) return; + + GLOBALASSERT(dynPtr); + trailPtr->Vertex[0] = dynPtr->Position; + // trailPtr->Vertex[0].vy -=1000; + + trailPtr->Perp[0] = *((VECTORCH*)&(dynPtr->OrientMat.mat11)); + trailPtr->Size[0] = 127*65536; + + trailPtr->Vertex[1] = dynPtr->PrevPosition; + // trailPtr->Vertex[1].vy -=1000; + trailPtr->Perp[1] = *((VECTORCH*)&(dynPtr->PrevOrientMat.mat11)); + trailPtr->Size[1] = 127*65536-MUL_FIXED(TRAIL_DECAY_SPEED,PrevNormalFrameTime); +} + +VECTORCH PlayerPheromoneTrailPerp = {0,0,0}; +void PlayerPheromoneTrail(DYNAMICSBLOCK *dynPtr) +{ + PHEROMONE_TRAIL *trailPtr = AllocatePheromoneTrail(); + VECTORCH disp; + if (!trailPtr) return; + + disp.vx = dynPtr->Position.vx-dynPtr->PrevPosition.vx; + disp.vy = dynPtr->Position.vy-dynPtr->PrevPosition.vy; + disp.vz = dynPtr->Position.vz-dynPtr->PrevPosition.vz; + + trailPtr->Vertex[0] = dynPtr->Position; + #if 1 + trailPtr->Vertex[0].vx -= dynPtr->OrientMat.mat21>>6; + trailPtr->Vertex[0].vy -= dynPtr->OrientMat.mat22>>6; + trailPtr->Vertex[0].vz -= dynPtr->OrientMat.mat23>>6; + #endif + // trailPtr->Vertex[0].vy -= 500; + + trailPtr->Perp[0] = *((VECTORCH*)&(dynPtr->OrientMat.mat11)); +#if 0 + trailPtr->Perp[0].vx = disp.vz - disp.vy; + trailPtr->Perp[0].vy = disp.vx - disp.vz; + trailPtr->Perp[0].vz = disp.vy - disp.vx; + if (trailPtr->Perp[0].vx!=0 || trailPtr->Perp[0].vy !=0 || trailPtr->Perp[0].vz!=0) + { + Normalise(&trailPtr->Perp[0]); + } + else + { + trailPtr->Perp[0] = PlayerPheromoneTrailPerp; + } +#endif + trailPtr->Size[0] = 127*65536*4; + + trailPtr->Vertex[1] = dynPtr->PrevPosition; + #if 1 + trailPtr->Vertex[1].vx -= dynPtr->PrevOrientMat.mat21>>6; + trailPtr->Vertex[1].vy -= dynPtr->PrevOrientMat.mat22>>6; + trailPtr->Vertex[1].vz -= dynPtr->PrevOrientMat.mat23>>6; + #endif + // trailPtr->Vertex[1].vy -= 500; + + + trailPtr->Perp[1] = *((VECTORCH*)&(dynPtr->PrevOrientMat.mat11)); +// trailPtr->Perp[1] = PlayerPheromoneTrailPerp; +// PlayerPheromoneTrailPerp = trailPtr->Perp[0]; + + trailPtr->Size[1] = 127*65536*4-MUL_FIXED(TRAIL_DECAY_SPEED,PrevNormalFrameTime); +} + +void HandlePheromoneTrails(void) +{ + int i; + PHEROMONE_TRAIL *trailPtr; + int decayDelta; + + i = NumActiveTrails; + trailPtr = TrailStorage; + //textprint("Pheromone Segments active:%d\n",NumActiveTrails); + + decayDelta = MUL_FIXED(TRAIL_DECAY_SPEED,NormalFrameTime); + +#if 0 + if (TICKERTAPE_CHEATMODE) + { + decayDelta/=4; + } +#endif + while(i--) + { + + trailPtr->Size[0] -= decayDelta; + trailPtr->Size[1] -= decayDelta; + if (trailPtr->Size[1]<0) trailPtr->Size[1]=0; + if (trailPtr->Size[0]<0) + { + DeallocatePheromoneTrail(trailPtr); + } + else + { + RenderTrailSegment(trailPtr); + trailPtr++; + } + + } +} +#include "frustrum.h" +void RenderTrailSegment(PHEROMONE_TRAIL *trailPtr) +{ + POLYHEADER fakeHeader; + VECTORCH temp; + int Uoffset = GetCos(CloakingPhase&4095)*128; + int Voffset = GetSin(CloakingPhase&4095)*128; + + temp.vx = trailPtr->Vertex[0].vx - MUL_FIXED(trailPtr->Perp[0].vx,trailPtr->Size[0]/65536); + temp.vy = trailPtr->Vertex[0].vy - MUL_FIXED(trailPtr->Perp[0].vy,trailPtr->Size[0]/65536); + temp.vz = trailPtr->Vertex[0].vz - MUL_FIXED(trailPtr->Perp[0].vz,trailPtr->Size[0]/65536); + VerticesBuffer[0].U = (temp.vx+temp.vz)*8192+Uoffset; + VerticesBuffer[0].V = (temp.vy+temp.vz)*8192+Voffset; + TranslatePointIntoViewspace(&temp); + VerticesBuffer[0].X = temp.vx; + VerticesBuffer[0].Y = temp.vy; + VerticesBuffer[0].Z = temp.vz; +// VerticesBuffer[0].U = ParticleDescription[PARTICLE_PLASMABEAM].StartU/2; +// VerticesBuffer[0].V = ParticleDescription[PARTICLE_PLASMABEAM].StartV/2; + + temp.vx = trailPtr->Vertex[0].vx + MUL_FIXED(trailPtr->Perp[0].vx,trailPtr->Size[0]/65536); + temp.vy = trailPtr->Vertex[0].vy + MUL_FIXED(trailPtr->Perp[0].vy,trailPtr->Size[0]/65536); + temp.vz = trailPtr->Vertex[0].vz + MUL_FIXED(trailPtr->Perp[0].vz,trailPtr->Size[0]/65536); + VerticesBuffer[1].U = (temp.vx+temp.vz)*8192+Uoffset; + VerticesBuffer[1].V = (temp.vy+temp.vz)*8192+Voffset; + TranslatePointIntoViewspace(&temp); + VerticesBuffer[1].X = temp.vx; + VerticesBuffer[1].Y = temp.vy; + VerticesBuffer[1].Z = temp.vz; +// VerticesBuffer[1].U = ParticleDescription[PARTICLE_PLASMABEAM].StartU/2; +// VerticesBuffer[1].V = ParticleDescription[PARTICLE_PLASMABEAM].EndV/2; + + + temp.vx = trailPtr->Vertex[1].vx + MUL_FIXED(trailPtr->Perp[1].vx,trailPtr->Size[1]/65536); + temp.vy = trailPtr->Vertex[1].vy + MUL_FIXED(trailPtr->Perp[1].vy,trailPtr->Size[1]/65536); + temp.vz = trailPtr->Vertex[1].vz + MUL_FIXED(trailPtr->Perp[1].vz,trailPtr->Size[1]/65536); + VerticesBuffer[2].U = (temp.vx+temp.vz)*8192+Uoffset; + VerticesBuffer[2].V = (temp.vy+temp.vz)*8192+Voffset; + TranslatePointIntoViewspace(&temp); + VerticesBuffer[2].X = temp.vx; + VerticesBuffer[2].Y = temp.vy; + VerticesBuffer[2].Z = temp.vz; +// VerticesBuffer[2].U = ParticleDescription[PARTICLE_PLASMABEAM].EndU/2; +// VerticesBuffer[2].V = ParticleDescription[PARTICLE_PLASMABEAM].EndV/2; + + temp.vx = trailPtr->Vertex[1].vx - MUL_FIXED(trailPtr->Perp[1].vx,trailPtr->Size[1]/65536); + temp.vy = trailPtr->Vertex[1].vy - MUL_FIXED(trailPtr->Perp[1].vy,trailPtr->Size[1]/65536); + temp.vz = trailPtr->Vertex[1].vz - MUL_FIXED(trailPtr->Perp[1].vz,trailPtr->Size[1]/65536); + VerticesBuffer[3].U = (temp.vx+temp.vz)*8192+Uoffset; + VerticesBuffer[3].V = (temp.vy+temp.vz)*8192+Voffset; + TranslatePointIntoViewspace(&temp); + VerticesBuffer[3].X = temp.vx; + VerticesBuffer[3].Y = temp.vy; + VerticesBuffer[3].Z = temp.vz; +// VerticesBuffer[3].U = ParticleDescription[PARTICLE_PLASMABEAM].EndU/2; +// VerticesBuffer[3].V = ParticleDescription[PARTICLE_PLASMABEAM].StartV/2; + + { + extern int SpecialFXImageNumber; + extern int CloudyImageNumber; + fakeHeader.PolyFlags = iflag_transparent; + fakeHeader.PolyColour = SpecialFXImageNumber; + fakeHeader.PolyColour = CloudyImageNumber; + } + RenderPolygon.TranslucencyMode = TRANSLUCENCY_GLOWING; + + + { + int i; + for (i=0; i<4; i++) + { + VerticesBuffer[i].A = trailPtr->Size[i/2]/65536; + + + VerticesBuffer[i].R = 255; + VerticesBuffer[i].G = 255; + VerticesBuffer[i].B = 255; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + + } + RenderPolygon.NumberOfVertices=4; + } + + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); +} + +extern void RenderParticlesInMirror(void) +{ + /* now render particles */ + int i = NumActiveParticles; + PARTICLE *particlePtr = ParticleStorage; + +// RenderPlayersImageInMirror(); + + D3D_DecalSystem_Setup(); + while(i--) + { + switch(particlePtr->ParticleID) + { + case PARTICLE_FLARESMOKE: + case PARTICLE_STEAM: + case PARTICLE_BLACKSMOKE: + case PARTICLE_IMPACTSMOKE: + case PARTICLE_SMOKECLOUD: + { + particlePtr->Position.vx = MirroringAxis - particlePtr->Position.vx; + RenderParticle(particlePtr); + particlePtr->Position.vx = MirroringAxis - particlePtr->Position.vx; + break; + } + default: + break; + } + particlePtr++; + } +// DrawingAReflection=1; +// DrawingAReflection=0; + + { + extern int NumOnScreenBlocks; + extern DISPLAYBLOCK *OnScreenBlockList[]; + int numOfObjects = NumOnScreenBlocks; + while(numOfObjects) + { + DISPLAYBLOCK *objectPtr = OnScreenBlockList[--numOfObjects]; + STRATEGYBLOCK *sbPtr = objectPtr->ObStrategyBlock; + + if (!objectPtr->ObShape && objectPtr->SfxPtr) + { + DrawSfxObject(objectPtr); + } + } + } + D3D_DecalSystem_End(); + +} + + + +#if 0 + +int FogNotSetupYet=1; +int Fog_Phi[256]; +int Fog_Theta[256]; +int Fog_Radius[256]; +int Fog_PhiDelta[256]; +int Fog_ThetaDelta[256]; +int Fog_RadiusDelta[256]; + +void RenderFog(void) +{ + int i; + if (FogNotSetupYet) + { + FogNotSetupYet=0; + for (i=0; i<256; i++) + { + Fog_Phi[i] = FastRandom()&2047; + Fog_Theta[i] = FastRandom()&4095; + Fog_Radius[i] = (FastRandom()&8191)-4096; + Fog_PhiDelta[i] = (FastRandom()&1023)-512; + Fog_ThetaDelta[i] = (FastRandom()&1023)-512; + Fog_RadiusDelta[i] = (FastRandom()&255)+255; + } + + } + for (i=0; i<255; i++) + { + int phi = Fog_Phi[i]; + int theta = Fog_Theta[i]; + int radius = Fog_Radius[i]; + + { + PARTICLE particle; + particle.ParticleID = PARTICLE_NONCOLLIDINGFLAME; + particle.Position.vx = MUL_FIXED(MUL_FIXED(GetCos(phi),GetSin(theta)),radius); + particle.Position.vy = MUL_FIXED(MUL_FIXED(GetSin(phi),GetSin(theta)),radius); + if (particle.Position.vy<0)particle.Position.vy=-particle.Position.vy; + particle.Position.vz = MUL_FIXED(GetCos(theta),radius); + particle.Colour = RGBA_MAKE(255,255,255,255); + particle.Size = 100; + RenderParticle(&particle); + } + Fog_Phi[i]+= MUL_FIXED(Fog_PhiDelta[i],NormalFrameTime); + Fog_Theta[i]+= MUL_FIXED(Fog_ThetaDelta[i],NormalFrameTime); + Fog_Phi[i]&=2047; + Fog_Theta[i]&=4095; + if (Fog_Radius[i]>4096) + { + Fog_Radius[i]-= MUL_FIXED(Fog_RadiusDelta[i],NormalFrameTime); + } + else + { + Fog_Radius[i]+= MUL_FIXED(Fog_RadiusDelta[i],NormalFrameTime); + } + + } + +} +#endif + + + + + + + + +#if 1 +void TimeScaleThingy() +{ + extern int NumActiveBlocks; + extern DISPLAYBLOCK *ActiveBlockList[]; + extern int TimeScale; + int DesiredTimeScale=ONE_FIXED; + extern int RealFrameTime; + + int i; + + for(i=0;iObStrategyBlock; + if(sbPtr) + { + switch(sbPtr->I_SBtype) + { + case I_BehaviourAlien: + case I_BehaviourQueenAlien : + case I_BehaviourFaceHugger : + case I_BehaviourPredator : + case I_BehaviourXenoborg : + case I_BehaviourMarine : + case I_BehaviourSeal : + case I_BehaviourPredatorAlien : + case I_BehaviourAutoGun : + DesiredTimeScale=MUL_FIXED(DesiredTimeScale,ONE_FIXED*.8); + break; + + case I_BehaviourGrenade : + case I_BehaviourRocket : + case I_BehaviourFrisbee: + case I_BehaviourPulseGrenade : + case I_BehaviourMolotov : + DesiredTimeScale=MUL_FIXED(DesiredTimeScale,ONE_FIXED*.7); + break; + } + } + } + + for(i=0; iDesiredTimeScale) TimeScale=DesiredTimeScale; + } + else if (TimeScale>DesiredTimeScale) + { + TimeScale-=RealFrameTime; + if(TimeScaleNumActiveParticles; + if(header->size != expected_size) return; + + //right copy the stuff then + NumActiveParticles = block->NumActiveParticles; + NumberOfBloodParticles = block->NumberOfBloodParticles; + + for(i=0;iheader.type = SaveBlock_Particles; + block->header.size = sizeof(*block) + NumActiveParticles * sizeof(PARTICLE); + + block->NumActiveParticles = NumActiveParticles; + block->NumberOfBloodParticles = NumberOfBloodParticles; + + + //now save the particles + for(i=0;iNumActiveExplosions; + if(header->size != expected_size) return; + + for(i=0;iNumActiveExplosions;i++) + { + VOLUMETRIC_EXPLOSION* explosion = AllocateVolumetricExplosion(); + if(explosion) + { + *explosion = *saved_explosion++; + } + } + +} + +void Save_VolumetricExplosions() +{ + int i; + EXPLOSION_SAVE_BLOCK_HEADER* block; + int NumActiveExplosions = 0; + + //first find the number of explosions currently active + for(i=0;iheader.type = SaveBlock_VolumetricExplosions; + block->header.size = sizeof(*block) + NumActiveExplosions * sizeof(VOLUMETRIC_EXPLOSION); + + block->NumActiveExplosions = NumActiveExplosions; + + //now save the explosions + for(i=0;iNumActiveTrails; + if(header->size != expected_size) return; + + for(i=0;iNumActiveTrails;i++) + { + PHEROMONE_TRAIL* trail = AllocatePheromoneTrail(); + if(trail) + { + *trail = *saved_trail++; + } + } + +} + +void Save_PheromoneTrails() +{ + PHEROMONE_SAVE_BLOCK_HEADER* block; + int i; + + if(!NumActiveTrails) return; + + //get memory for header + GET_SAVE_BLOCK_POINTER(block); + + //fill in header + block->header.type = SaveBlock_PheromoneTrail; + block->header.size = sizeof(*block) + NumActiveTrails * sizeof(PHEROMONE_TRAIL); + + block->NumActiveTrails = NumActiveTrails; + + + //now save the trails + for(i=0;i(i); + + OurBool bThisFrame = KeyboardInput + [ + KeyForNavOp[theNavOp] + ]; + + if (bThisFrame) + { + textprint("undebounced NavOp:%i\n",theNavOp); + } + + // Call the key-handlers for "key down" transitions: + if + ( + bThisFrame + && + ( !bLastFrame[ theNavOp ] ) + ) + { + // Recompute here (in case page changes mid-computation) + Page* pPage = Page :: GetSelected(); + GLOBALASSERT( pPage ); + + pPage -> Navigate( theNavOp ); + } + + bLastFrame[ theNavOp ] = bThisFrame; + } + } + } +} + +// static +void +RebMenus :: Item_KeyConfig_PageView :: Maintain(void) +{ + GLOBALASSERT( pActive ); + unsigned char theKey; + + if ( InputHandler :: bPressedKey( theKey ) ) + { + if (pActive -> bDebounced ) + { + pActive -> bDebounced = No; + pActive -> SetMethod(theKey); + } + } + else + { + pActive -> bDebounced = Yes; + } +} + + +// static +OurBool +RebMenus :: InputHandler :: bPressedKey +( + unsigned char& outKey +) +{ + // return val= was a key pressed; if so, output area is written to + + #if ( MAX_NUMBER_OF_INPUT_KEYS >= 255 ) + #error Range problem in this routine; it will need rewriting + #endif + + for (unsigned char key = 0 ; key <= MAX_NUMBER_OF_INPUT_KEYS ; key++) + { + if (!(key == KEY_ESCAPE) && + !(key >= KEY_F1 && key <= KEY_F12) && + !(key >= KEY_0 && key <= KEY_9) ) + { + if ( KeyboardInput[key] ) + { + outKey = key; + return Yes; + } + } + } + + return No; +} + + + + +// private: +// static +OurBool +RebMenus :: InputHandler :: bLastFrame[NUM_NAVIGATION_OPS]; + +// static +int +RebMenus :: InputHandler :: KeyForNavOp[NUM_NAVIGATION_OPS] = +{ + KEY_UP, + KEY_DOWN, + KEY_LEFT, + KEY_RIGHT, + KEY_HOME, + KEY_END, + KEY_CR, + // NavOp_Trigger + + #if 1 + KEY_ESCAPE + #else + KEY_R + #endif + // NavOp_Cancel + // for the moment + +}; + +// end of namespace RebMenus + +void +RebMenus :: PrecacheGraphics(void) +{ + #if OverrideOldMenus + // Grab all the bitmaps we'll ever need now, before the music starts + // so as to avoid sound glitches: + + // Graphics used by menus in general: + { + // Sliders: + { + Bitmap :: Precache("Graphics\\NewMenus\\SliderBar.rim"); + Bitmap :: Precache("Graphics\\NewMenus\\SliderBarDark.rim"); + Bitmap :: Precache("Graphics\\NewMenus\\Slider.rim"); + Bitmap :: Precache("Graphics\\NewMenus\\SliderDark.rim"); + } + } + + // Graphics used by specific menu pages: + { + // Start solo game: + { + Bitmap :: Precache("Graphics\\NewMenus\\Alien.rim"); + Bitmap :: Precache("Graphics\\NewMenus\\AlienDark.rim"); + Bitmap :: Precache("Graphics\\NewMenus\\MarineDark.rim"); + Bitmap :: Precache("Graphics\\NewMenus\\Predator.rim"); + Bitmap :: Precache("Graphics\\NewMenus\\PredatorDark.rim"); + } + } + #endif +} + +#if OverrideOldMenus +int REBMENUS_DoTheMenus(void) +{ + // This code created from the routines in PCMENUS.CPP: + RebMenus :: InGame :: Set_OutsideTheGame(); + + ResetFrameCounter(); + + PlatformSpecificEnteringMenus(); + + // Ensure r2rect for screen size is properly setup: + { + R2BASE_ScreenModeChange_Cleanup(); + } + + // Experiment to get WAV file play working: + { + #if 0 + BOOL bSuccess = PlaySound + ( + "NewMenus\\Intro.wav", // LPCSTR pszSound, + NULL, // HMODULE hmod, + ( + SND_ASYNC + | SND_FILENAME + ) // DWORD fdwSound + ); + + db_logf1(("PlaySound() returned %i",bSuccess)); + #endif + } + + #if SupportTextprintBeforeGame + // Load debugging font: + { + #if 0 + InitialiseImageHeaders(); + // some kind of init needed ??? + #else + InitialiseTextures(); + #endif + } + #endif + + // Load the starfield backdrop graphic + // Ultimately will want to replace with e.g. an FMV sequence init call + { + LoadMenuGraphic(&Starfield_Backdrop); + } + + // Load the fonts: + { + #if 1 + IndexedFont_Kerned_Column :: Create + ( + IntroFont_Light, // FontIndex I_Font_New, + "Graphics\\NewMenus\\IntroFont.rim", + 21, // int HeightPerChar_New, + 5, // int SpaceWidth_New, + 32 // ASCIICodeForInitialCharacter + ); + + IndexedFont_Kerned_Column :: Create + ( + IntroFont_Dark, // FontIndex I_Font_New, + "Graphics\\NewMenus\\IntroFontDark.rim", + 21, // int HeightPerChar_New, + 5, // int SpaceWidth_New, + 32 // ASCIICodeForInitialCharacter + ); + #else + IndexedFont_Proportional_Column :: Create + ( + IntroFont_Light, // FontIndex I_Font_New, + "Graphics\\NewMenus\\IntroFont.rim", + 21, // int HeightPerChar_New, + 5, // int SpaceWidth_New, + 32 // ASCIICodeForInitialCharacter + ); + + IndexedFont_Proportional_Column :: Create + ( + IntroFont_Dark, // FontIndex I_Font_New, + "Graphics\\NewMenus\\IntroFontDark.rim", + 21, // int HeightPerChar_New, + 5, // int SpaceWidth_New, + 32 // ASCIICodeForInitialCharacter + ); + #endif + } + + // 30/3/98 DHM: Avoid menu sound glitches by doing all the loading now: + { + RebMenus :: PrecacheGraphics(); + } + + + /* KJL 15:00:30 28/03/98 - hook to play the intro sequence + + This call checks to see if this is the first time into the + menus, and plays the intro accordingly + + */ + PlayIntroSequence(); + + + RebMenus :: MenuLoop :: Start(); + + while ( RebMenus :: MenuLoop :: bStillGoing() ) + { + #if 0 + // Allow ALT+TAB + { + CheckForWindowsMessages(); + } + #endif + + // Network messaging; replaces code from RunMultiPlayerStartUp() + // see pp89-91 of DHMS's AvP book + { + if + ( + ( AvP.Network != I_No_Network ) + && + ( netGameData . myGameState == NGS_Joining ) + ) + { + NetCollectMessages(); + } + + if + ( + ( AvP.Network != I_No_Network ) + && + ( netGameData . myGameState == NGS_Joining ) + ) + { + /* we are still in start-up after collecting our messages */ + if(AvP.Network==I_Host) + { + AddNetMsg_GameDescription(); + } + else + { + AddNetMsg_PlayerDescription(); + } + + NetSendMessages(); + } + + } + + + // Do stuff to replace DrawEntireMenuScreen() + { + // DrawMenuBackdrop(); ultimately called BLTMenuToScreen() + // Could replace with a call to render a new flat backdrop + // eg Al's pretty starfield. + // Ultimately might play an FMV sequence + { + // For now: + { + BLTMenuToScreen + ( + &Starfield_Backdrop + ); + } + } + + /* play music */ + PlayMenuMusic(); + + // Add stuff relating to current menu state: + { + RebMenus :: Render(); + } + + // For now, manually flush textprint buffer: + { + #if SupportTextprintBeforeGame + FlushTextprintBuffer(); + #endif + } + + // Flip buffers etc: + { + FlipBuffers(); + } + } + + + // Keep input handling code up-to-date: + { + ReadUserInput(); + } + + // Process user input and update bExit accordingly + { + RebMenus :: Maintain(); + } + + // Update sound system: + { + SoundSys_Management(); + } + + // Handle timing: + { + FrameCounterHandler(); + } + + // Handle possible requests to run the multiplayer dialog + { + Command_Multiplayer :: EndOfMenuLoopProcessing(); + } + + } // end of while loop + + + // Set some globals: + { + #if 0 + AvP . PlayerType = I_Marine; + AvP . CurrentEnv = AvP.StartingEnv; + AvP . Network = I_No_Network; + #endif + // the above are now set in the MenuLoop::StartGame() method + + } + + IndexedFont :: UnloadFont( IntroFont_Dark ); + IndexedFont :: UnloadFont( IntroFont_Light ); + + // Unload any graphics loaded for menu items: + { + RebMenus :: Bitmap :: EmptyCache(); + } + + // Unload the starfeild backdrop; replace with FMV unloading calls + { + ReleaseMenuGraphic + ( + &Starfield_Backdrop + ); + } + + /* play music */ + EndMenuMusic(); + + PlatformSpecificExitingMenus(); + + RebMenus :: InGame :: Set_InTheGame(); + + return RebMenus :: MenuLoop :: MenuRoutineReturnVal(); + +} +#endif + // OverrideOldMenus + +// Pause hook, used by PLAYER.C: +void REBMENUS_ProcessPauseRequest(void) +{ + textprint("REBMENUS_ProcessPauseRequest()\n"); + + Command* pCommand = new Command_ExitCurrentGame(); + pCommand -> Execute(); + + pCommand -> R_Release(); +} +#endif + // UseRebMenus + +void REBMENUS_ProjectSpecific_EndOfMainLoopHook(void) +{ + #if UseRebMenus + RebMenus :: Bitmap :: EmptyCache(); + #endif + + // Set menu page to initial one; ultimately might want to set + // a briefing screen for next level at this point etc. + #if UseRebMenus + RebMenus :: Page :: SelectPage_ClearingStack( PageID_Initial ); + #endif +} + diff --git a/3dc/avp/projmenu.hpp b/3dc/avp/projmenu.hpp new file mode 100644 index 0000000..6ddae44 --- /dev/null +++ b/3dc/avp/projmenu.hpp @@ -0,0 +1,273 @@ +/* + + projmenu.hpp + + New menu system for AvP. + + This file created 23/3/98 by DHM, by extracting project specific bits + out of other headers. + + I've attempted to impose a split between project-specific and project-independent + portions of the code. This is perhaps a little academic given that the code is (so + far) just used by AvP. Still, Devil's Own have requested I try to lock off the + project-specific bits. I hope I've done a good job. + + Some of the content of this file is required by REBMENUS.HPP; see comment + at the top of that header file. Other content is specific to getting the + code to work both in the game and outside, given that the code has to work + ASAP within an extensive framework of existing code. + +*/ + +#ifndef _projmenu_hpp +#define _projmenu_hpp 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + + #if UseRebMenus + + #ifndef _projfont + #include "projfont.h" + #endif + + #ifndef GAMEDEF_INCLUDED + #ifndef MODULE_INCLUDED + #include "module.h" + // needed to include gamedef.h + #endif + + #include "gamedef.h" + #endif + + #endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ +#if UseRebMenus + enum PageID + { + PageID_NoMenu, + + PageID_Initial, + + + PageID_ChooseCharacter, + PageID_MarineBriefing, + PageID_PredatorBriefing, + PageID_AlienBriefing, + + PageID_LoadGame, + + PageID_Options, + PageID_VideoOptions, + PageID_AudioOptions, + PageID_InputOptions, + + PageID_LevelsOfDetail, + + PageID_MouseConfig, + + PageID_PlaceholderMultiplayer, + PageID_MultiplayerErrorScreen, + + NUM_PAGE_IDS + }; + + // Grab Avp's string table enum, and typedef "TextID" to it: + #ifndef _langenum_h_ + #include "langenum.h" + #endif + + typedef enum TEXTSTRING_ID TextID; + + #ifdef __cplusplus + // Extend the RebMenus namespace with stuff to handle an out-of-the-game + // menu loop for AvP, plus some project-supplied hooks needed for the menu code + namespace RebMenus + { + namespace ProjectSpecific + { + void Init(void); + void UnInit(void); + void Maintain(void); + }; + + #if OverrideOldMenus + // Additions to the RebMenus namespace: handling a loop outside the main game + class MenuLoop + { + // This class handles the exit condition from the out-of-game menu loop + // Functions are provided to request exit next time round the loop, giving + // a reason why the loop is to terminate + public: + + enum ExitReason + { + ExitReason_None, + ExitReason_QuitProgram, + ExitReason_StartGame + }; + + static void Start(void) + { + theExitReason_Val = ExitReason_None; + } + + static OurBool bStillGoing(void) + { + return ( ExitReason_None == theExitReason_Val ); + } + + static int MenuRoutineReturnVal(void) + { + // value to be returned by the dedicated menu loop to WinMain() + if ( theExitReason_Val == ExitReason_QuitProgram ) + { + // Then the while( themenus ) loop should receive a false value + // which will kill the main loop + return No; + } + else + { + // Then the while( themenus ) loop should receive a true value + // which will pass control into the innards of the main loop + return Yes; + } + } + + static void QuitProgram(void) + { + SetExit + ( + ExitReason_QuitProgram + ); + } + + static void StartSoloGame + ( + I_PLAYER_TYPE inPlayerType, + I_AVP_ENVIRONMENTS inStartingEnv + ); + + static void StartNetworkGame + ( + I_PLAYER_TYPE inPlayerType, + I_AVP_ENVIRONMENTS inStartingEnv + ); + + + private: + static void SetExit + ( + enum ExitReason theExitReason_New + ) + { + theExitReason_Val = theExitReason_New; + } + + private: + static enum ExitReason theExitReason_Val; + }; + + // A class to handle knowledge for the menus of whether + // they are being run outisde the game in their own loop, + // or within the main game loop: + class InGame + { + public: + static void Set_InTheGame(void) + { + bInTheGame_Val = Yes; + } + static void Set_OutsideTheGame(void) + { + bInTheGame_Val = No; + } + + static OurBool Get(void) + { + return bInTheGame_Val; + } + + private: + static OurBool bInTheGame_Val; + }; + #endif + // OverrideOldMenus + + // A class required by the project-independent menu code + // to tell label rendering which fonts to use, and when: + class Fonts + { + private: + static const FontIndex LabelFont_InGame; + static const FontIndex LabelFont_OutOfGame_Selected; + static const FontIndex LabelFont_OutOfGame_Unselected; + + public: + static FontIndex GetIndex + ( + #if OverrideOldMenus + OurBool bSelected + #else + OurBool + #endif + ) + { + #if OverrideOldMenus + if (InGame::Get()) + { + return LabelFont_InGame; + } + else + { + if (bSelected) + { + return LabelFont_OutOfGame_Selected; + } + else + { + return LabelFont_OutOfGame_Unselected; + } + } + #else + return LabelFont_InGame; + #endif + } + }; + + const int Label_FixP_Alpha = ONE_FIXED; + const int ColumnSpacing = 15; + + void PrecacheGraphics(void); + + }; + #endif +#endif // UseRebMenus +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ +#ifdef __cplusplus + extern "C" { +#endif + // Function call hook for AvP: + extern int REBMENUS_DoTheMenus(void); + + // Pause hook, used by PLAYER.C: + extern void REBMENUS_ProcessPauseRequest(void); +#ifdef __cplusplus + }; +#endif + + + +/* End of the header ****************************************************/ + +#endif diff --git a/3dc/avp/projtext.h b/3dc/avp/projtext.h new file mode 100644 index 0000000..898b5df --- /dev/null +++ b/3dc/avp/projtext.h @@ -0,0 +1,39 @@ +/* + + projtext.h + + Created 12 Nov 97 by DHM: Project specific text type + +*/ + +#ifndef _projtext +#define _projtext 1 + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + + typedef char ProjChar; + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/savegame.c b/3dc/avp/savegame.c new file mode 100644 index 0000000..a400ced --- /dev/null +++ b/3dc/avp/savegame.c @@ -0,0 +1,1374 @@ +#include "3dc.h" + +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "comp_shp.h" +#include "dynblock.h" + +#include "bh_alien.h" +#include "pvisible.h" +#include "bh_pred.h" +#include "bh_xeno.h" +#include "bh_paq.h" +#include "bh_queen.h" +#include "bh_marin.h" +#include "bh_fhug.h" +#include "bh_debri.h" +#include "bh_plachier.h" +#include "plat_shp.h" +#include "psnd.h" +#include "lighting.h" +#include "pldnet.h" +#include "bh_dummy.h" +#include "bh_videoscreen.h" +#include "bh_plift.h" +#include "bh_ldoor.h" +#include "AvP_Menus.h" +#include "game_statistics.h" +#include "AvP_UserProfile.h" + +#include "savegame.h" +#include "huffman.hpp" +#include "smacker.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +static struct +{ + char* BufferStart; + char* BufferPos; + int BufferSize; + int BufferSpaceLeft; + int BufferSpaceUsed; + +} SaveInfo = {0,0,0,0,0}; + +static struct +{ + char* BufferStart; + char* BufferPos; + int BufferSize; + int BufferSpaceLeft; + +} LoadInfo = {0,0,0,0}; + + +int LoadGameRequest = SAVELOAD_REQUEST_NONE; //slot number of game to be loaded +int SaveGameRequest = SAVELOAD_REQUEST_NONE; //slot number of game to be saved + + +#define NUM_SAVES_FOR_EASY_MODE 8 +#define NUM_SAVES_FOR_MEDIUM_MODE 4 +#define NUM_SAVES_FOR_HARD_MODE 2 + +int NumberOfSavesLeft; + + + +static void SaveStrategies(); +static void LoadStrategy(SAVE_BLOCK_STRATEGY_HEADER* header); + +static void SaveDeadStrategies(); +static void LoadDeadStrategy(SAVE_BLOCK_HEADER* block); + + +static void LoadMiscGlobalStuff(SAVE_BLOCK_HEADER* header); +static void SaveMiscGlobalStuff(); + +/*---------------------------------------------** +** externs for all the load and save functions ** +**---------------------------------------------*/ +extern void LoadStrategy_LiftDoor(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_LiftDoor(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_ProxDoor(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_ProxDoor(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_SwitchDoor(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_SwitchDoor(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_PlatformLift(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_PlatformLift(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_BinarySwitch(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_BinarySwitch(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_LinkSwitch(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_LinkSwitch(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_Generator(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Generator(STRATEGYBLOCK* sbPtr); + +extern void LoadHiveSettings(SAVE_BLOCK_HEADER* header); +extern void SaveHiveSettings(); + +extern void LoadStrategy_InanimateObject(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_InanimateObject(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_LightFx(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_LightFx(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_PlacedSound(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_PlacedSound(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_Message(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Message(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_MissionComplete(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_MissionComplete(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_TrackObject(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_TrackObject(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_Fan(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Fan(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_PlacedLight(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_PlacedLight(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_VideoScreen(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_VideoScreen(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_DeathVolume(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_DeathVolume(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_ParticleGenerator(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_ParticleGenerator(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_SelfDestruct(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_SelfDestruct(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_Alien(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Alien(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_Corpse(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Corpse(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_FaceHugger(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_FaceHugger(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_Marine(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Marine(STRATEGYBLOCK* sbPtr); + +extern void LoadMarineSquadState(SAVE_BLOCK_HEADER* header); +extern void SaveMarineSquadState(); + +extern void LoadStrategy_PlacedHierarchy(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_PlacedHierarchy(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_Predator(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Predator(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_Xenoborg(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Xenoborg(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_Queen(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Queen(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_Player(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Player(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_Autogun(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Autogun(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_HierarchicalDebris(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_HierarchicalDebris(STRATEGYBLOCK* sbPtr); + +extern void Load_Decals(SAVE_BLOCK_HEADER* header); +extern void Save_Decals(); + +extern void Load_Particles(SAVE_BLOCK_HEADER* header); +extern void Save_Particles(); + +extern void Load_VolumetricExplosions(SAVE_BLOCK_HEADER* header); +extern void Save_VolumetricExplosions(); + +extern void Load_PheromoneTrails(SAVE_BLOCK_HEADER* header); +extern void Save_PheromoneTrails(); + +extern void Load_LightElements(SAVE_BLOCK_HEADER* header); +extern void Save_LightElements(); + +extern void Load_MessageHistory(SAVE_BLOCK_HEADER* header); +extern void Save_MessageHistory(); + +extern void LoadStrategy_Grenade(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Grenade(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_FlareGrenade(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_FlareGrenade(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_ProxGrenade(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_ProxGrenade(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_Rocket(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Rocket(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_PPPlasmaBolt(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_PPPlasmaBolt(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_PredatorEnergyBolt(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_PredatorEnergyBolt(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_PulseGrenade(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_PulseGrenade(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_ClusterGrenade(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_ClusterGrenade(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_Molotov(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Molotov(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_PredatorDisc(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_PredatorDisc(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_SpearBolt(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_SpearBolt(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_Grapple(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Grapple(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_Debris(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Debris(STRATEGYBLOCK* sbPtr); + +extern void LoadLevelHeader(SAVE_BLOCK_HEADER* header); +extern void SaveLevelHeader(); + +extern void Load_WeaponsCGlobals(SAVE_BLOCK_HEADER* header); +extern void Save_WeaponsCGlobals(); + +extern void Load_SoundState_NoRef(SAVE_BLOCK_HEADER* header); +extern void Save_SoundsWithNoReference(); + +extern void LoadStrategy_Frisbee(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_Frisbee(STRATEGYBLOCK* sbPtr); + +extern void LoadStrategy_FrisbeeEnergyBolt(SAVE_BLOCK_STRATEGY_HEADER* header); +extern void SaveStrategy_FrisbeeEnergyBolt(STRATEGYBLOCK* sbPtr); + +extern int DebuggingCommandsActive; + +/*-----------------------------------------------------** +** end of externs for all the load and save functions ** +**-----------------------------------------------------*/ + +extern void DisplaySavesLeft(); + +/* +Functions for converting between ai modules and their indeces. +They don't really belong here , but they are only used by loading/saving at +the moment. +*/ + +struct aimodule * GetPointerFromAIModuleIndex(int index) +{ + + if(index>=0 && indexm_index; + else + return -1; +} + + + + + +void* GetPointerForSaveBlock(unsigned int size) +{ + void* retPointer; + + //see if we need to enlarge the buffer to allow for this block + if(size > SaveInfo.BufferSpaceLeft) + { + //need more space + int spaceNeeded = SaveInfo.BufferSpaceUsed + size; + //buffer incremented in lots of 100000 bytes (more or less) + int newBufferSize = ((spaceNeeded /100000)+1)*100000; + + //allocate the memory + SaveInfo.BufferStart = (char*) realloc(SaveInfo.BufferStart,newBufferSize); + + //correct the position etc. + SaveInfo.BufferPos = SaveInfo.BufferStart + SaveInfo.BufferSpaceUsed; + SaveInfo.BufferSpaceLeft += (newBufferSize - SaveInfo.BufferSize); + SaveInfo.BufferSize = newBufferSize; + + } + + //get the pointer to the next part of the save buffer + retPointer = (void*)SaveInfo.BufferPos; + + SaveInfo.BufferSpaceUsed += size; + SaveInfo.BufferSpaceLeft -= size; + SaveInfo.BufferPos += size; + + return retPointer; +} + + + +static void InitSaveGame() +{ + SaveInfo.BufferPos = SaveInfo.BufferStart; + SaveInfo.BufferSpaceLeft = SaveInfo.BufferSize; + SaveInfo.BufferSpaceUsed = 0; + +} + + +static BOOL SaveGameAllowed() +{ + PLAYER_STATUS *playerStatusPtr; + + //can't save in multiplayer (or skirmish) + if(AvP.Network != I_No_Network) return FALSE; + + //check player's state + if(!Player) return FALSE; + if(!Player->ObStrategyBlock) return FALSE; + if(!Player->ObStrategyBlock->SBdataptr) return FALSE; + + playerStatusPtr = (PLAYER_STATUS*)Player->ObStrategyBlock->SBdataptr; + + //player must be alive , and not face hugged + if(!playerStatusPtr->IsAlive) return FALSE; + if(playerStatusPtr->MyFaceHugger) return FALSE; + + //cheating? + if(DebuggingCommandsActive || CheatMode_Active!=CHEATMODE_NONACTIVE) + { + NewOnScreenMessage(GetTextString(TEXTSTRING_SAVEGAME_NOTALLOWED)); + return FALSE; + } + + //now check the number of saves left + //first some validation + + if(NumberOfSavesLeft<0) NumberOfSavesLeft =0; + switch(AvP.Difficulty) + { + case I_Easy : + if(NumberOfSavesLeft > NUM_SAVES_FOR_EASY_MODE) + NumberOfSavesLeft = NUM_SAVES_FOR_EASY_MODE; + break; + case I_Medium : + if(NumberOfSavesLeft > NUM_SAVES_FOR_MEDIUM_MODE) + NumberOfSavesLeft = NUM_SAVES_FOR_MEDIUM_MODE; + break; + case I_Hard : + case I_Impossible : + if(NumberOfSavesLeft > NUM_SAVES_FOR_HARD_MODE) + NumberOfSavesLeft = NUM_SAVES_FOR_HARD_MODE; + break; + + } + + + if(!NumberOfSavesLeft) + { + NewOnScreenMessage(GetTextString(TEXTSTRING_SAVEGAME_NOSAVESLEFT)); + return FALSE; + } + + NumberOfSavesLeft--; + + + //saving is allowed then + return TRUE; + + +} + +void SaveGame() +{ + char filename[100]; + HANDLE file; + DWORD bytes_written; + int headerLength; + HuffmanPackage *packagePtr; + + //make sure there is a save request + if(SaveGameRequest == SAVELOAD_REQUEST_NONE) return; + + if(SaveGameRequest<0 || SaveGameRequest>=NUMBER_OF_SAVE_SLOTS) + { + SaveGameRequest = SAVELOAD_REQUEST_NONE; + return; + } + + //check that we are allowed to save at this point + if(!SaveGameAllowed()) + { + //cancel request + SaveGameRequest = SAVELOAD_REQUEST_NONE; + return; + } + + InitSaveGame(); + + SaveLevelHeader(); + + headerLength = SaveInfo.BufferSpaceUsed; + + SaveDeadStrategies(); + + SaveStrategies(); + + SaveHiveSettings(); + + SaveMarineSquadState(); + + SaveMiscGlobalStuff(); + + Save_SoundsWithNoReference(); + + //save particles etc. + Save_Decals(); + Save_Particles(); + Save_VolumetricExplosions(); + Save_PheromoneTrails(); + Save_LightElements(); + + Save_MessageHistory(); + + Save_WeaponsCGlobals(); + + + //get the filename + GetFilenameForSaveSlot(SaveGameRequest,filename); + + //clear the save request + SaveGameRequest = SAVELOAD_REQUEST_NONE; + + //write the file + file = CreateFile(filename,GENERIC_WRITE, 0, 0, CREATE_ALWAYS,FILE_FLAG_RANDOM_ACCESS, 0); + + if (file == INVALID_HANDLE_VALUE) + { + GLOBALASSERT("Error saving file"==0); + return; + } + + WriteFile(file,SaveInfo.BufferStart,headerLength,&bytes_written,0); + + packagePtr = HuffmanCompression(SaveInfo.BufferStart+headerLength,SaveInfo.BufferSpaceUsed-headerLength); + + WriteFile(file,packagePtr,packagePtr->CompressedDataSize+sizeof(HuffmanPackage),&bytes_written,0); + + CloseHandle(file); + + + NewOnScreenMessage(GetTextString(TEXTSTRING_SAVEGAME_GAMESAVED)); + DisplaySavesLeft(); + +} + + + + + + + + +static void EndLoadGame() +{ + if(LoadInfo.BufferStart) + { + DeallocateMem(LoadInfo.BufferStart); + } + LoadInfo.BufferStart = NULL; + LoadInfo.BufferPos = NULL; + LoadInfo.BufferSize = 0; + LoadInfo.BufferSpaceLeft = 0; + +} + +extern SAVE_SLOT_HEADER SaveGameSlot[]; + +extern int AlienEpisodeToPlay; +extern int MarineEpisodeToPlay; +extern int PredatorEpisodeToPlay; +BOOL ValidateLevelForLoadGameRequest(SAVE_SLOT_HEADER* save_slot) +{ + //see if we will need to change level + if(save_slot->Species != AvP.PlayerType) return FALSE; + + //probably need to reload if in cheat mode + if(CheatMode_Active!=CHEATMODE_NONACTIVE) return FALSE; + + switch(save_slot->Species) + { + case I_Marine : + if(save_slot->Episode != MarineEpisodeToPlay) return FALSE;; + break; + + case I_Alien : + if(save_slot->Episode != AlienEpisodeToPlay) return FALSE; + break; + + case I_Predator : + if(save_slot->Episode != PredatorEpisodeToPlay) return FALSE; + break; + } + //certainly need to change level if in multiplayer (or skirmish) + if(AvP.Network != I_No_Network) return FALSE; + + return TRUE; +} + +void LoadSavedGame() +{ + SAVE_SLOT_HEADER* save_slot; + char filename[100]; + HANDLE file; + BOOL terminal_error = FALSE; + unsigned int bytes_read; + + if(LoadGameRequest == SAVELOAD_REQUEST_NONE) return; + + if(LoadGameRequest<0 || LoadGameRequest>=NUMBER_OF_SAVE_SLOTS) + { + LoadGameRequest = SAVELOAD_REQUEST_NONE; + return; + } + + + //get the save_slot + save_slot = &SaveGameSlot[LoadGameRequest]; + + //make sure the slot is being used + ScanSaveSlots(); + if(!save_slot->SlotUsed) return; + + ///make sure we're on the right level etc. + if(!ValidateLevelForLoadGameRequest(save_slot)) + { + AvP.MainLoopRunning = FALSE; + return; + } + { + extern int GlobalFrameCounter; + if(!GlobalFrameCounter) return; + } + //set the difficulty level and restart the level + AvP.Difficulty = save_slot->Difficulty; + RestartLevel(); + + //get the filename for the save slot + GetFilenameForSaveSlot(LoadGameRequest,filename); + + //we can now clear the load request + LoadGameRequest = SAVELOAD_REQUEST_NONE; + + //load the file + file = CreateFile(filename,GENERIC_READ, 0, 0, OPEN_EXISTING,FILE_FLAG_RANDOM_ACCESS, 0); + + + if(file==INVALID_HANDLE_VALUE) + { + //failed to load + EndLoadGame(); + return; + } + + LoadInfo.BufferSize = GetFileSize(file,0); + if(!LoadInfo.BufferSize) + { + CloseHandle(file); + EndLoadGame(); + return; + } + + //allocate buffer , and read file into memory + LoadInfo.BufferStart = (char*) AllocateMem(LoadInfo.BufferSize); + ReadFile(file,LoadInfo.BufferStart,LoadInfo.BufferSize,(LPDWORD)&bytes_read,0); + CloseHandle(file); + + + + LoadInfo.BufferPos = LoadInfo.BufferStart; + LoadInfo.BufferSpaceLeft = LoadInfo.BufferSize; + + // attempt to access level header + { + //read the next header + SAVE_BLOCK_HEADER* header = (SAVE_BLOCK_HEADER*) LoadInfo.BufferPos; + + if(header->size>LoadInfo.BufferSpaceLeft) + { + //oh dear, dodgy file + GLOBALASSERT("Invalid save game header size"==0); + terminal_error = TRUE; + } + else + { + //go to the next header + LoadInfo.BufferPos += header->size; + LoadInfo.BufferSpaceLeft -= header->size; + + switch(header->type) + { + case SaveBlock_MainHeader : + LoadLevelHeader(header); + break; + default: + GLOBALASSERT("Unrecognized save block type"==0); + terminal_error = TRUE; + break; + } + } + } + + if (!terminal_error) + { + if (!strncmp (LoadInfo.BufferPos, "REBCRIF1", 8)) + { + char *uncompressedBufferPtr = (char*)HuffmanDecompress((HuffmanPackage*)(LoadInfo.BufferPos)); + LoadInfo.BufferSpaceLeft = ((HuffmanPackage*)LoadInfo.BufferPos)->UncompressedDataSize; + DeallocateMem(LoadInfo.BufferStart); + LoadInfo.BufferStart=uncompressedBufferPtr; + LoadInfo.BufferPos = LoadInfo.BufferStart; + } + else + { + terminal_error = TRUE; + } + + } + + //go through loading things + while(LoadInfo.BufferSpaceLeft && !terminal_error) + { + //read the next header + SAVE_BLOCK_HEADER* header = (SAVE_BLOCK_HEADER*) LoadInfo.BufferPos; + + if(header->size>LoadInfo.BufferSpaceLeft) + { + //oh dear, dodgy file + GLOBALASSERT("Invalid save game header size"==0); + terminal_error = TRUE; + break; + } + + //go to the next header + LoadInfo.BufferPos += header->size; + LoadInfo.BufferSpaceLeft -= header->size; + + + switch(header->type) + { + case SaveBlock_MainHeader : + LoadLevelHeader(header); + break; + + case SaveBlock_DeadStrategy : + LoadDeadStrategy(header); + break; + + case SaveBlock_Strategy : + LoadStrategy((SAVE_BLOCK_STRATEGY_HEADER*) header); + break; + + case SaveBlock_Track : + //all these should be used up by the various strategy loaders + GLOBALASSERT("Unexpected track save block"==0); + break; + + case SaveBlock_Hierarchy : + //all these should be used up by the various strategy loaders + GLOBALASSERT("Unexpected hierarchy save block"==0); + break; + + case SaveBlock_HierarchySection : + //all these should be used up by the various strategy loaders + GLOBALASSERT("Unexpected hierarchy section save block"==0); + break; + + case SaveBlock_HierarchyTween : + //all these should be used up by the various strategy loaders + GLOBALASSERT("Unexpected hierarchy tween save block"==0); + break; + + case SaveBlock_HierarchyDecals : + //all these should be used up by the various strategy loaders + GLOBALASSERT("Unexpected hierarchy decal save block"==0); + break; + + case SaveBlock_HierarchyDelta : + //all these should be used up by the various strategy loaders + GLOBALASSERT("Unexpected hierarchy delta save block"==0); + break; + + case SaveBlock_GlobalHive : + LoadHiveSettings(header); + break; + + case SaveBlock_MiscGlobal : + LoadMiscGlobalStuff(header); + break; + + case SaveBlock_MarineSquad : + LoadMarineSquadState(header); + break; + + case SaveBlock_Particles : + Load_Particles(header); + break; + + case SaveBlock_Decals : + Load_Decals(header); + break; + + case SaveBlock_PheromoneTrail : + Load_PheromoneTrails(header); + break; + + case SaveBlock_VolumetricExplosions : + Load_VolumetricExplosions(header); + break; + + case SaveBlock_LightElements : + Load_LightElements(header); + break; + + case SaveBlock_MessageHistory : + Load_MessageHistory(header); + break; + + case SaveBlock_WeaponsCGlobals : + Load_WeaponsCGlobals(header); + break; + + case SaveBlock_SoundState : + Load_SoundState_NoRef(header); + break; + + + default : + GLOBALASSERT("Unrecognized save block type"==0); + terminal_error = TRUE; + break; + } + + + } + + if(terminal_error) + { + //the save file was screwed , restart the level to be on the safe side + RestartLevel(); + NewOnScreenMessage(GetTextString(TEXTSTRING_SAVEGAME_ERRORLOADING)); + } + + EndLoadGame(); + + RemoveDestroyedStrategyBlocks(); + + //make sure all the containing modules are set properly + { + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + + int sbIndex = 0; + STRATEGYBLOCK *sbPtr; + + /* loop thro' the strategy block list, looking for objects that need to have + their visibilities managed ... */ + while(sbIndex < NumActiveStBlocks) + { + sbPtr = ActiveStBlockList[sbIndex++]; + if(sbPtr->maintainVisibility && sbPtr->DynPtr) + { + MODULE* newModule; + newModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (sbPtr->containingModule)); + + if(newModule) sbPtr->containingModule = newModule; + } + } + } + + AllNewModuleHandler(); + + DoObjectVisibilities(); + + ResetFrameCounter(); + + if(!terminal_error) + { + NewOnScreenMessage(GetTextString(TEXTSTRING_SAVEGAME_GAMELOADED)); + DisplaySavesLeft(); + } + +} + +SAVE_BLOCK_HEADER* GetNextBlockIfOfType(SAVE_BLOCK_TYPE type) +{ + SAVE_BLOCK_HEADER* header; + + GLOBALASSERT(LoadInfo.BufferPos); + + if(LoadInfo.BufferSpaceLeft==0) + { + //no more blocks left + return 0; + } + + //look at the next header in the buffer + header = (SAVE_BLOCK_HEADER*) LoadInfo.BufferPos; + if(header->size>LoadInfo.BufferSpaceLeft) + { + //oh dear, dodgy file + GLOBALASSERT("Invalid save game header size"==0); + return 0; + } + + //see if the header is of the type that we are after + if(header->type == type) + { + //okay , advance the buffer position , and return this header + LoadInfo.BufferPos += header->size; + LoadInfo.BufferSpaceLeft -= header->size; + + return header; + } + else + { + //out of luck + return 0; + } + +} + +static void SaveStrategies() +{ + int i; + + for(i=0;iI_SBtype) + { + case I_BehaviourMarinePlayer : + SaveStrategy_Player(sbPtr); + break; + + case I_BehaviourLiftDoor : + SaveStrategy_LiftDoor(sbPtr); + break; + + case I_BehaviourProximityDoor : + SaveStrategy_ProxDoor(sbPtr); + break; + + case I_BehaviourSwitchDoor : + SaveStrategy_SwitchDoor(sbPtr); + break; + + case I_BehaviourPlatform : + SaveStrategy_PlatformLift(sbPtr); + break; + + case I_BehaviourBinarySwitch : + SaveStrategy_BinarySwitch(sbPtr); + break; + + case I_BehaviourLinkSwitch : + SaveStrategy_LinkSwitch(sbPtr); + break; + + case I_BehaviourGenerator : + SaveStrategy_Generator(sbPtr); + break; + + case I_BehaviourInanimateObject : + SaveStrategy_InanimateObject(sbPtr); + break; + + case I_BehaviourLightFX : + SaveStrategy_LightFx(sbPtr); + break; + + case I_BehaviourPlacedSound : + SaveStrategy_PlacedSound(sbPtr); + break; + + case I_BehaviourMessage : + SaveStrategy_Message(sbPtr); + break; + + case I_BehaviourMissionComplete : + SaveStrategy_MissionComplete(sbPtr); + break; + + case I_BehaviourTrackObject : + SaveStrategy_TrackObject(sbPtr); + break; + + case I_BehaviourFan : + SaveStrategy_Fan(sbPtr); + break; + + case I_BehaviourPlacedLight : + SaveStrategy_PlacedLight(sbPtr); + break; + + case I_BehaviourVideoScreen : + SaveStrategy_VideoScreen(sbPtr); + break; + + case I_BehaviourSelfDestruct : + SaveStrategy_SelfDestruct(sbPtr); + break; + + case I_BehaviourParticleGenerator : + SaveStrategy_ParticleGenerator(sbPtr); + break; + + case I_BehaviourDeathVolume : + SaveStrategy_DeathVolume(sbPtr); + break; + + case I_BehaviourAlien : + SaveStrategy_Alien(sbPtr); + break; + + case I_BehaviourNetCorpse : + SaveStrategy_Corpse(sbPtr); + break; + + case I_BehaviourFaceHugger : + SaveStrategy_FaceHugger(sbPtr); + break; + + case I_BehaviourMarine : + SaveStrategy_Marine(sbPtr); + break; + + case I_BehaviourPlacedHierarchy : + SaveStrategy_PlacedHierarchy(sbPtr); + break; + + case I_BehaviourPredator : + SaveStrategy_Predator(sbPtr); + break; + + case I_BehaviourXenoborg : + SaveStrategy_Xenoborg(sbPtr); + break; + + case I_BehaviourQueenAlien : + SaveStrategy_Queen(sbPtr); + break; + + case I_BehaviourAutoGun : + SaveStrategy_Autogun(sbPtr); + break; + + case I_BehaviourHierarchicalFragment : + SaveStrategy_HierarchicalDebris(sbPtr); + break; + + case I_BehaviourGrenade : + SaveStrategy_Grenade(sbPtr); + break; + + case I_BehaviourFlareGrenade : + SaveStrategy_FlareGrenade(sbPtr); + break; + + case I_BehaviourProximityGrenade : + SaveStrategy_ProxGrenade(sbPtr); + break; + + case I_BehaviourRocket : + SaveStrategy_Rocket(sbPtr); + break; + + case I_BehaviourPPPlasmaBolt : + SaveStrategy_PPPlasmaBolt(sbPtr); + break; + + case I_BehaviourPredatorEnergyBolt : + SaveStrategy_PredatorEnergyBolt(sbPtr); + break; + + case I_BehaviourFrisbeeEnergyBolt : + SaveStrategy_FrisbeeEnergyBolt(sbPtr); + break; + + case I_BehaviourPulseGrenade : + SaveStrategy_PulseGrenade(sbPtr); + break; + + case I_BehaviourClusterGrenade : + SaveStrategy_ClusterGrenade(sbPtr); + break; + + case I_BehaviourMolotov : + SaveStrategy_Molotov(sbPtr); + break; + + case I_BehaviourPredatorDisc_SeekTrack : + SaveStrategy_PredatorDisc(sbPtr); + break; + + case I_BehaviourSpeargunBolt : + SaveStrategy_SpearBolt(sbPtr); + break; + + case I_BehaviourGrapplingHook : + SaveStrategy_Grapple(sbPtr); + break; + + case I_BehaviourFragment : + SaveStrategy_Debris(sbPtr); + break; + + case I_BehaviourFrisbee : + SaveStrategy_Frisbee(sbPtr); + break; + + } + } + +} + +static void LoadStrategy(SAVE_BLOCK_STRATEGY_HEADER* header) +{ + switch(header->bhvr_type) + { + case I_BehaviourMarinePlayer : + LoadStrategy_Player(header); + break; + + case I_BehaviourLiftDoor : + LoadStrategy_LiftDoor(header); + break; + + case I_BehaviourProximityDoor : + LoadStrategy_ProxDoor(header); + break; + + case I_BehaviourSwitchDoor : + LoadStrategy_SwitchDoor(header); + break; + + case I_BehaviourPlatform : + LoadStrategy_PlatformLift(header); + break; + + case I_BehaviourBinarySwitch : + LoadStrategy_BinarySwitch(header); + break; + + case I_BehaviourLinkSwitch : + LoadStrategy_LinkSwitch(header); + break; + + case I_BehaviourGenerator : + LoadStrategy_Generator(header); + break; + + case I_BehaviourInanimateObject : + LoadStrategy_InanimateObject(header); + break; + + case I_BehaviourLightFX : + LoadStrategy_LightFx(header); + break; + + case I_BehaviourPlacedSound : + LoadStrategy_PlacedSound(header); + break; + + case I_BehaviourMessage : + LoadStrategy_Message(header); + break; + + case I_BehaviourMissionComplete : + LoadStrategy_MissionComplete(header); + break; + + case I_BehaviourTrackObject : + LoadStrategy_TrackObject(header); + break; + + case I_BehaviourFan : + LoadStrategy_Fan(header); + break; + + case I_BehaviourPlacedLight : + LoadStrategy_PlacedLight(header); + break; + + case I_BehaviourVideoScreen : + LoadStrategy_VideoScreen(header); + break; + + case I_BehaviourSelfDestruct : + LoadStrategy_SelfDestruct(header); + break; + + case I_BehaviourParticleGenerator : + LoadStrategy_ParticleGenerator(header); + break; + + case I_BehaviourDeathVolume : + LoadStrategy_DeathVolume(header); + break; + + case I_BehaviourAlien : + LoadStrategy_Alien(header); + break; + + case I_BehaviourNetCorpse : + LoadStrategy_Corpse(header); + break; + + case I_BehaviourFaceHugger : + LoadStrategy_FaceHugger(header); + break; + + case I_BehaviourMarine : + LoadStrategy_Marine(header); + break; + + case I_BehaviourPlacedHierarchy : + LoadStrategy_PlacedHierarchy(header); + break; + + case I_BehaviourPredator : + LoadStrategy_Predator(header); + break; + + case I_BehaviourXenoborg : + LoadStrategy_Xenoborg(header); + break; + + case I_BehaviourQueenAlien : + LoadStrategy_Queen(header); + break; + + case I_BehaviourAutoGun : + LoadStrategy_Autogun(header); + break; + + case I_BehaviourHierarchicalFragment : + LoadStrategy_HierarchicalDebris(header); + break; + + case I_BehaviourGrenade : + LoadStrategy_Grenade(header); + break; + + case I_BehaviourFlareGrenade : + LoadStrategy_FlareGrenade(header); + break; + + case I_BehaviourProximityGrenade : + LoadStrategy_ProxGrenade(header); + break; + + case I_BehaviourRocket : + LoadStrategy_Rocket(header); + break; + + case I_BehaviourPPPlasmaBolt : + LoadStrategy_PPPlasmaBolt(header); + break; + + case I_BehaviourPredatorEnergyBolt : + LoadStrategy_PredatorEnergyBolt(header); + break; + + case I_BehaviourFrisbeeEnergyBolt : + LoadStrategy_FrisbeeEnergyBolt(header); + break; + + case I_BehaviourPulseGrenade : + LoadStrategy_PulseGrenade(header); + break; + + case I_BehaviourClusterGrenade : + LoadStrategy_ClusterGrenade(header); + break; + + case I_BehaviourMolotov : + LoadStrategy_Molotov(header); + break; + + case I_BehaviourPredatorDisc_SeekTrack : + LoadStrategy_PredatorDisc(header); + break; + + case I_BehaviourSpeargunBolt : + LoadStrategy_SpearBolt(header); + break; + + case I_BehaviourGrapplingHook : + LoadStrategy_Grapple(header); + break; + + case I_BehaviourFragment : + LoadStrategy_Debris(header); + break; + + case I_BehaviourFrisbee : + LoadStrategy_Frisbee(header); + break; + + } +} + + +/*------------------------------------** +** Loading and saving dead strategies ** +**------------------------------------*/ + +typedef struct dead_strategy_save_block +{ + SAVE_BLOCK_HEADER header; + char SBname[SB_NAME_LENGTH]; + +}DEAD_STRATEGY_SAVE_BLOCK; + +static void SaveDeadStrategies() +{ + extern STRATEGYBLOCK FreeStBlockData[]; + int i; + STRATEGYBLOCK* sbPtr = &FreeStBlockData[0]; + + //search for all the strategies that existed at the start , and have been destroyed + for(i=0;iSBflags.destroyed_but_preserved) + { + DEAD_STRATEGY_SAVE_BLOCK* block; + GET_SAVE_BLOCK_POINTER(block); + + block->header.type = SaveBlock_DeadStrategy; + block->header.size = sizeof(*block); + + COPY_NAME(block->SBname,sbPtr->SBname); + + } + } +} + +static void LoadDeadStrategy(SAVE_BLOCK_HEADER* header) +{ + DEAD_STRATEGY_SAVE_BLOCK* block = (DEAD_STRATEGY_SAVE_BLOCK*) header; + + STRATEGYBLOCK* sbPtr = FindSBWithName(block->SBname); + if(sbPtr) + { + DestroyAnyStrategyBlock(sbPtr); + } +} + + + +/*--------------------------------------------------------------------------------** +** Loading and saving miscellaneos global rubbish that has nowhere else to live ** +**--------------------------------------------------------------------------------*/ + +extern unsigned int IncrementalSBname; +extern int PlayersMaxHeightWhilstNotInContactWithGround; + + +typedef struct misc_global_save_block +{ + SAVE_BLOCK_HEADER header; + + unsigned int IncrementalSBname; + AvP_GameStats CurrentGameStatistics; + int PlayersMaxHeightWhilstNotInContactWithGround; + int NumberOfSavesLeft; + + int FMV_MessageNumber; + int FMV_FrameNumber; + +}MISC_GLOBAL_SAVE_BLOCK; + +static void LoadMiscGlobalStuff(SAVE_BLOCK_HEADER* header) +{ + MISC_GLOBAL_SAVE_BLOCK* block; + block = (MISC_GLOBAL_SAVE_BLOCK*) header; + + if(block->header.size != sizeof(*block)) return; + + IncrementalSBname = block->IncrementalSBname; + CurrentGameStatistics = block->CurrentGameStatistics; + PlayersMaxHeightWhilstNotInContactWithGround = block->PlayersMaxHeightWhilstNotInContactWithGround; + NumberOfSavesLeft = block-> NumberOfSavesLeft; + + StartFMVAtFrame(block->FMV_MessageNumber,block->FMV_FrameNumber); +} + +static void SaveMiscGlobalStuff() +{ + MISC_GLOBAL_SAVE_BLOCK* block; + block = GetPointerForSaveBlock(sizeof(*block)); + + //fill in the header + block->header.type = SaveBlock_MiscGlobal; + block->header.size = sizeof(*block); + + block->IncrementalSBname = IncrementalSBname; + block->CurrentGameStatistics = CurrentGameStatistics; + block->PlayersMaxHeightWhilstNotInContactWithGround = PlayersMaxHeightWhilstNotInContactWithGround; + block->NumberOfSavesLeft = NumberOfSavesLeft; + + GetFMVInformation(&block->FMV_MessageNumber,&block->FMV_FrameNumber); +} + + + + + +extern void DisplaySavesLeft() +{ + char text [100]; + + sprintf(text, "%s: %d",GetTextString(TEXTSTRING_SAVEGAME_SAVESLEFT),NumberOfSavesLeft); + + NewOnScreenMessage(text); +} + + + + +extern void ResetNumberOfSaves() +{ + switch(AvP.Difficulty) + { + case I_Easy : + NumberOfSavesLeft = NUM_SAVES_FOR_EASY_MODE; + break; + case I_Medium : + NumberOfSavesLeft = NUM_SAVES_FOR_MEDIUM_MODE; + break; + case I_Hard : + case I_Impossible : + NumberOfSavesLeft = NUM_SAVES_FOR_HARD_MODE; + break; + + } +} \ No newline at end of file diff --git a/3dc/avp/savegame.h b/3dc/avp/savegame.h new file mode 100644 index 0000000..4a7da5b --- /dev/null +++ b/3dc/avp/savegame.h @@ -0,0 +1,99 @@ +#ifndef savegame_h_ +#define savegame_h_ 1 + +#define SAVELOAD_REQUEST_NONE -1 +extern int LoadGameRequest; //slot number of game to be loaded +extern int SaveGameRequest; //slot number of game to be saved + +extern int NumberOfSavesLeft; + +typedef enum save_block_type +{ + SaveBlock_MainHeader, + SaveBlock_DeadStrategy, + SaveBlock_Strategy, + SaveBlock_Track, + SaveBlock_GlobalHive, + SaveBlock_Hierarchy, + SaveBlock_HierarchySection, + SaveBlock_HierarchyDecals, + SaveBlock_HierarchyTween, + SaveBlock_HierarchyDelta, + SaveBlock_MiscGlobal, + SaveBlock_MarineSquad, + SaveBlock_Particles, + SaveBlock_Decals, + SaveBlock_PheromoneTrail, + SaveBlock_VolumetricExplosions, + SaveBlock_LightElements, + SaveBlock_MessageHistory, + SaveBlock_WeaponsCGlobals, + SaveBlock_SoundState, +}SAVE_BLOCK_TYPE; + + +//structure needs to be at the start of each block +typedef struct save_block_header +{ + SAVE_BLOCK_TYPE type; + int size; +}SAVE_BLOCK_HEADER; + + +//structure to go at the start of stategy save blocks +typedef struct save_block_strategy_header +{ + SAVE_BLOCK_TYPE type; + int size; + + AVP_BEHAVIOUR_TYPE bhvr_type; + char SBname[SB_NAME_LENGTH]; + +}SAVE_BLOCK_STRATEGY_HEADER; + +typedef struct level_save_block +{ + SAVE_BLOCK_HEADER header; + + char AvP_Save_String[8]; + + unsigned char Species; + unsigned char Episode; + unsigned char ElapsedTime_Hours; + unsigned char ElapsedTime_Minutes; + unsigned int ElapsedTime_Seconds; + unsigned char Difficulty; + unsigned char NumberOfSavesLeft;//For Load/Save menu only (if it gets used) + +}LEVEL_SAVE_BLOCK; + + +#define COPYELEMENT_LOAD(element) SAVELOAD_BEHAV->element = SAVELOAD_BLOCK->element; +#define COPYELEMENT_SAVE(element) SAVELOAD_BLOCK->element = SAVELOAD_BEHAV->element; + +#define COPYELEMENT_LOAD_EXT(block,behav) behav=block; +#define COPYELEMENT_SAVE_EXT(block,behav) block=behav; + + + +extern void* GetPointerForSaveBlock(unsigned int size); +extern struct aimodule * GetPointerFromAIModuleIndex(int index); +extern int GetIndexFromAIModulePointer(struct aimodule* module); + +extern SAVE_BLOCK_HEADER* GetNextBlockIfOfType(SAVE_BLOCK_TYPE type); + +#define GET_SAVE_BLOCK_POINTER(block) block = GetPointerForSaveBlock(sizeof(*block)) + +#define GET_STRATEGY_SAVE_BLOCK(block,sbPtr)\ + block = GetPointerForSaveBlock(sizeof(*block));\ + block->header.type = SaveBlock_Strategy;\ + block->header.size = sizeof(*block);\ + block->header.bhvr_type = sbPtr->I_SBtype;\ + COPY_NAME(block->header.SBname,sbPtr->SBname); + + +extern void SaveGame(); +extern void LoadSavedGame(); +extern void ResetNumberOfSaves(); + +#endif \ No newline at end of file diff --git a/3dc/avp/scream.cpp b/3dc/avp/scream.cpp new file mode 100644 index 0000000..a43ab8a --- /dev/null +++ b/3dc/avp/scream.cpp @@ -0,0 +1,387 @@ +#include "3dc.h" +#include "ourasert.h" +#include "psndplat.h" +#include "jsndsup.h" +#include "mempool.h" +#include "scream.h" +#include "dxlog.h" +#include "avp_menus.h" + +extern "C" +{ +extern DISPLAYBLOCK* Player; + + +struct ScreamSound +{ + struct loaded_sound const * sound_loaded; + int pitch; + int volume; +}; + +struct ScreamSoundCategory +{ + int num_sounds; + ScreamSound* sounds; + + SOUNDINDEX last_sound; +}; + +struct ScreamVoiceType +{ + ScreamSoundCategory* category; +}; + +struct CharacterSoundEffects +{ + int num_voice_types; + int num_voice_cats; + ScreamVoiceType* voice_types; + SOUNDINDEX global_last_sound; + + void PlaySound(int VoiceType,int SoundCategory,int PitchShift,int* ExternalRef,VECTORCH* Location); + void UnloadSounds(); + void LoadSounds(const char* filename,const char* directory); +}; + +static CharacterSoundEffects MarineSounds={0,0,0,SID_NOSOUND}; +static CharacterSoundEffects AlienSounds={0,0,0,SID_NOSOUND}; +static CharacterSoundEffects PredatorSounds={0,0,0,SID_NOSOUND}; +static CharacterSoundEffects QueenSounds={0,0,0,SID_NOSOUND}; + + +//static int num_voice_types=0; +//static int num_voice_cats=0; +//static ScreamVoiceType* voice_types=0; +//static SOUNDINDEX global_last_sound; + + +#if ALIEN_DEMO +#define ScreamFilePath "alienfastfile\\" +#elif LOAD_SCREAMS_FROM_FASTFILES +#define ScreamFilePath "fastfile\\" +#else +#define ScreamFilePath "sound\\" +#endif + +#if 0 +void LoadScreamSounds() +{ + if(voice_types) return; + + HANDLE file=CreateFile(ScreamFileName,GENERIC_READ, 0, 0, OPEN_EXISTING,FILE_FLAG_RANDOM_ACCESS, 0); + if(file==INVALID_HANDLE_VALUE) + { + LOGDXFMT(("Failed to open %s",ScreamFileName)); + return; + } + + char* buffer; + int file_size; + unsigned long bytes_read; + + file_size= GetFileSize(file,0); + buffer=new char[file_size+1]; + ReadFile(file,buffer,file_size,&bytes_read,0); + CloseHandle(file); + + if(strncmp("MARSOUND",buffer,8)) + { + return; + } + + char* bufpos=buffer+8; + + num_voice_types=*(int*)bufpos; + bufpos+=4; + num_voice_cats=*(int*)bufpos; + bufpos+=4; + + voice_types=(ScreamVoiceType*) PoolAllocateMem(num_voice_types * sizeof(ScreamVoiceType)); + + char wavpath[200]="npc\\marinevoice\\"; + char* wavname=&wavpath[strlen(wavpath)]; + for(int i=0;ilast_sound=SID_NOSOUND; + cat->num_sounds=*(int*)bufpos; + bufpos+=4; + + if(cat->num_sounds) + { + cat->sounds=(ScreamSound*) PoolAllocateMem(cat->num_sounds * sizeof(ScreamSound)); + } + else + { + cat->sounds=0; + } + + for(int k=0;knum_sounds;) + { + ScreamSound * sound=&cat->sounds[k]; + + strcpy(wavname,bufpos); + bufpos+=strlen(bufpos)+1; + + sound->pitch=*(int*)bufpos; + bufpos+=4; + sound->volume=*(int*)bufpos; + bufpos+=4; + + sound->sound_loaded=GetSound(wavpath); + if(sound->sound_loaded) + { + k++; + } + else + { + cat->num_sounds--; + } + + } + + } + } + + delete [] buffer; + +} +#endif + + +void CharacterSoundEffects::LoadSounds(const char* filename,const char* directory) +{ + if(voice_types) return; + + char path[100]=ScreamFilePath; + strcat(path,filename); + + HANDLE file=CreateFile(path,GENERIC_READ, 0, 0, OPEN_EXISTING,FILE_FLAG_RANDOM_ACCESS, 0); + if(file==INVALID_HANDLE_VALUE) + { + LOGDXFMT(("Failed to open %s",path)); + return; + } + + char* buffer; + int file_size; + unsigned long bytes_read; + + file_size= GetFileSize(file,0); + buffer=new char[file_size+1]; + ReadFile(file,buffer,file_size,&bytes_read,0); + CloseHandle(file); + + if(strncmp("MARSOUND",buffer,8)) + { + return; + } + + char* bufpos=buffer+8; + + num_voice_types=*(int*)bufpos; + bufpos+=4; + num_voice_cats=*(int*)bufpos; + bufpos+=4; + + voice_types=(ScreamVoiceType*) PoolAllocateMem(num_voice_types * sizeof(ScreamVoiceType)); + + char wavpath[200]; + strcpy(wavpath,directory); + char* wavname=&wavpath[strlen(wavpath)]; + + for(int i=0;ilast_sound=SID_NOSOUND; + cat->num_sounds=*(int*)bufpos; + bufpos+=4; + + if(cat->num_sounds) + { + cat->sounds=(ScreamSound*) PoolAllocateMem(cat->num_sounds * sizeof(ScreamSound)); + } + else + { + cat->sounds=0; + } + + for(int k=0;knum_sounds;) + { + ScreamSound * sound=&cat->sounds[k]; + + strcpy(wavname,bufpos); + bufpos+=strlen(bufpos)+1; + + sound->pitch=*(int*)bufpos; + bufpos+=4; + sound->volume=*(int*)bufpos; + bufpos+=4; + + sound->sound_loaded=GetSound(wavpath); + if(sound->sound_loaded) + { + k++; + } + else + { + cat->num_sounds--; + } + + } + + } + } + + delete [] buffer; + +} + +void CharacterSoundEffects::UnloadSounds() +{ + if(!voice_types) return; + #if !NEW_DEALLOCATION_ORDER + for(int i=0;inum_sounds;k++) + { + LoseSound(cat->sounds[k].sound_loaded); + } + } + } + #endif + voice_types=0; + num_voice_types=0; + num_voice_cats=0; +} + + + +void CharacterSoundEffects::PlaySound(int VoiceType,int SoundCategory,int PitchShift,int* ExternalRef,VECTORCH* Location) +{ +// GLOBALASSERT(Location); + + if(!voice_types) return; + //make sure the values are within bounds + if(VoiceType<0 || VoiceType>=num_voice_types) return; + if(SoundCategory<0 || SoundCategory>=num_voice_cats) return; + if(ExternalRef) + { + if(*ExternalRef!=SOUND_NOACTIVEINDEX) + { + //already playing a sound + return; + } + } + + #if 0 + if(Location) + { + //need to make sure this sound is close enough to be heard + VECTORCH seperation=Player->ObWorld; + SubVector(Location,&seperation); + + //(default sound range is 32 metres) + if(Approximate3dMagnitude(&seperation)>32000) + { + //too far away . don't bother playing a sound. + return; + } + } + #endif + + ScreamSoundCategory* cat=&voice_types[VoiceType].category[SoundCategory]; + //make sure there are some sound for this category + if(!cat->num_sounds) return; + + int index=FastRandom()% cat->num_sounds; + int num_checked=0; + + //pick a sound , trying to avoid the last one picked + if(cat->num_sounds>2) + { + while(num_checkednum_sounds) + { + SOUNDINDEX sound_ind=(SOUNDINDEX)cat->sounds[index].sound_loaded->sound_num; + if(sound_ind!=cat->last_sound && sound_ind!=global_last_sound) break; + + index++; + num_checked++; + if(index==cat->num_sounds) index=0; + } + } + + ScreamSound* sound=&cat->sounds[index]; + + int pitch=sound->pitch+PitchShift; + + if(Location) + Sound_Play((SOUNDINDEX)sound->sound_loaded->sound_num,"dvpe",Location,sound->volume,pitch,ExternalRef); + else + Sound_Play((SOUNDINDEX)sound->sound_loaded->sound_num,"vpe",sound->volume,pitch,ExternalRef); + + //take note of the last sound played + global_last_sound=cat->last_sound=(SOUNDINDEX)sound->sound_loaded->sound_num; +} + + + +void UnloadScreamSounds() +{ + MarineSounds.UnloadSounds(); + AlienSounds.UnloadSounds(); + PredatorSounds.UnloadSounds(); + QueenSounds.UnloadSounds(); +} + + +void LoadMarineScreamSounds() +{ + MarineSounds.LoadSounds("marsound.dat","npc\\marinevoice\\"); +} +void LoadAlienScreamSounds() +{ + AlienSounds.LoadSounds("aliensound.dat","npc\\alienvoice\\"); +} +void LoadPredatorScreamSounds() +{ + PredatorSounds.LoadSounds("predsound.dat","npc\\predatorvoice\\"); +} + +void LoadQueenScreamSounds() +{ + QueenSounds.LoadSounds("queensound.dat","npc\\queenvoice\\"); +} + + +void PlayMarineScream(int VoiceType,int SoundCategory,int PitchShift,int* ExternalRef,VECTORCH* Location) +{ + MarineSounds.PlaySound(VoiceType,SoundCategory,PitchShift,ExternalRef,Location); +} +void PlayAlienSound(int VoiceType,int SoundCategory,int PitchShift,int* ExternalRef,VECTORCH* Location) +{ + AlienSounds.PlaySound(VoiceType,SoundCategory,PitchShift,ExternalRef,Location); +} +void PlayPredatorSound(int VoiceType,int SoundCategory,int PitchShift,int* ExternalRef,VECTORCH* Location) +{ + PredatorSounds.PlaySound(VoiceType,SoundCategory,PitchShift,ExternalRef,Location); +} + +void PlayQueenSound(int VoiceType,int SoundCategory,int PitchShift,int* ExternalRef,VECTORCH* Location) +{ + QueenSounds.PlaySound(VoiceType,SoundCategory,PitchShift,ExternalRef,Location); +} + + + +}; \ No newline at end of file diff --git a/3dc/avp/scream.h b/3dc/avp/scream.h new file mode 100644 index 0000000..b6032a8 --- /dev/null +++ b/3dc/avp/scream.h @@ -0,0 +1,77 @@ +#ifndef scream_h +#define scream_h 1 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum sound_category { + SC_Angry=0, + SC_Panic, + SC_Pain, + SC_Death, + SC_Surprise, + SC_Oooph, + SC_OnFire, + SC_Electrocution, + SC_Sobbing, + SC_Acid, + SC_Facehugged, + SC_PC_OnFire, + SC_Taunt, + SC_Falling, + SC_Jump, +} SOUND_CATERGORY; + +typedef enum alien_sound_category +{ + ASC_TailSound, + ASC_Swipe, + ASC_Scream_Hurt, + ASC_Scream_Dying, + ASC_Scream_General, + ASC_Taunt, + ASC_LimbLoss, + ASC_Death, + ASC_PC_OnFire, +}ALIEN_SOUND_CATEGORY; + +typedef enum predator_sound_category +{ + PSC_Swipe, + PSC_Scream_Hurt, + PSC_Scream_Dying, + PSC_Scream_General, + PSC_Taunt, + PSC_Acid, + PSC_Facehugged, + PSC_PC_OnFire, + PSC_Jump, + PSC_Medicomp_Special, +}PREDATOR_SOUND_CATEGORY; + +typedef enum queen_sound_category +{ + QSC_Hiss, + QSC_Scream_Hurt, + + QSC_Object_Bounce, //not actually used by the queen , but only occurs in queen's level +}QUEEN_SOUND_CATEGORY; + +void UnloadScreamSounds(); + +void LoadMarineScreamSounds(); +void LoadAlienScreamSounds(); +void LoadPredatorScreamSounds(); +void LoadQueenScreamSounds(); + +void PlayMarineScream(int VoiceType,int SoundCategory,int PitchShift,int* ExternalRef,VECTORCH* Location); +void PlayAlienSound(int VoiceType,int SoundCategory,int PitchShift,int* ExternalRef,VECTORCH* Location); +void PlayPredatorSound(int VoiceType,int SoundCategory,int PitchShift,int* ExternalRef,VECTORCH* Location); +void PlayQueenSound(int VoiceType,int SoundCategory,int PitchShift,int* ExternalRef,VECTORCH* Location); + +#ifdef __cplusplus +}; +#endif + +#endif \ No newline at end of file diff --git a/3dc/avp/sequnces.h b/3dc/avp/sequnces.h new file mode 100644 index 0000000..4ee07a4 --- /dev/null +++ b/3dc/avp/sequnces.h @@ -0,0 +1,484 @@ +/* Sequnces.h CDF 8/12/97 */ + +#ifndef _sequnces_h_ + + #define _sequnces_h_ 1 + + #ifdef __cplusplus + + extern "C" { + + #endif + + /* Sequences enums. */ + + typedef enum HModelSequenceTypes { + HMSQT_AlienRun=0, + HMSQT_AlienCrawl, + HMSQT_AlienStand, + HMSQT_AlienCrouch, + HMSQT_Hugger, + HMSQT_MarineRun, + HMSQT_MarineCrawl, + HMSQT_MarineStand, + HMSQT_MarineCrouch, + HMSQT_PredatorHUD, + HMSQT_MarineHUD, + HMSQT_PredatorRun, + HMSQT_PredatorCrawl, + HMSQT_PredatorStand, + HMSQT_PredatorCrouch, + HMSQT_QueenLeftStanceTemplate, + HMSQT_QueenLeftStanceFull, + HMSQT_QueenRightStanceTemplate, + HMSQT_QueenRightStanceFull, + HMSQT_QueenGeneral, + HMSQT_AlienHUD, + HMSQT_Xenoborg, + } HMODEL_SEQUENCE_TYPES; + + typedef enum AlienRunSubSequences { + ARSS_Standard=0, + ARSS_Dies, + ARSS_Attack_Swipe, + ARSS_Jump, + ARSS_Standard_II, + ARSS_Left_Hobble, + ARSS_Right_Hobble, + ARSS_end, + } ALIENRUN_SUBSEQUENCES; + + typedef enum AlienCrawlSubSequences { + ACSS_Standard=0, + ACSS_Dies, + ACSS_Attack_Bite, + ACSS_Attack_Tail, + ACSS_Pain_Fall_Fwd, + ACSS_Pain_Fall_Back, + ACSS_Pain_Fall_Left, + ACSS_Pain_Fall_Right, + ACSS_Boom_Fall_Fwd, + ACSS_Boom_Fall_Back, + ACSS_Boom_Fall_Left, + ACSS_Boom_Fall_Right, + ACSS_Attack_Swipe, + ACSS_Crawl_Hurt, + ACSS_Scamper, + ACSS_end, + } ALIENCRAWL_SUBSEQUENCES; + + typedef enum AlienStandSubSequences { + ASSS_Standard=0, + ASSS_Dies, + ASSS_Attack_Right_Swipe_In, + ASSS_Attack_Bite, + ASSS_Pain_Fall_Fwd, + ASSS_Pain_Fall_Back, + ASSS_Pain_Fall_Left, + ASSS_Pain_Fall_Right, + ASSS_Boom_Fall_Fwd, + ASSS_Boom_Fall_Back, + ASSS_Boom_Fall_Left, + ASSS_Boom_Fall_Right, + ASSS_Spin_Clockwise, + ASSS_Spin_Anticlockwise, + ASSS_Feed, + ASSS_Taunt, + ASSS_BurningDeath, + ASSS_Standard_Elevation, + ASSS_FidgetA, + ASSS_FidgetB, + ASSS_Attack_Left_Swipe_In, + ASSS_Attack_Tail, + ASSS_Dormant, + ASSS_Unfurl, + ASSS_Attack_Both_In, + ASSS_Attack_Both_Down, + ASSS_Spasm, + ASSS_SpearFlyFwrd, + ASSS_SpearFlyBack, + ASSS_SpearHitBck, + ASSS_SpearHitFrnt, + ASSS_Attack_Low_Left_Swipe, + ASSS_Attack_Low_Right_Swipe, + ASSS_Taunt2, + ASSS_Taunt3, + ASSS_Fear, + ASSS_Hit_Left, + ASSS_Hit_Right, + ASSS_end, + } ALIENSTAND_SUBSEQUENCES; + + typedef enum AlienCrouchSubSequences { + ACrSS_Standard=0, + ACrSS_Dies, + ACrSS_Attack_Bite, + ACrSS_Attack_Tail, + ACrSS_Attack_Swipe, + ACrSS_Dies_Thrash, + ACrSS_Standard_Elevation, + ACrSS_Pounce, + ACrSS_Hit_Left, + ACrSS_Hit_Right, + ACrSS_Taunt, + ACrSS_end, + } ALIENCROUCH_SUBSEQUENCES; + + typedef enum HuggerSubSequences { + HSS_Stand=0, + HSS_Run, + HSS_Dies, + HSS_Jump, + HSS_Attack, + HSS_DieOnFire, + HSS_Floats, + HSS_end, + } HUGGER_SUBSEQUENCES; + + typedef enum MarineRunSubSequences { + MRSS_Standard=0, + MRSS_Dies_Standard, + MRSS_Jump, + MRSS_Attack_Primary, + MRSS_Elevation, + MRSS_Walk, + MRSS_Tem_Run_On_Fire, + MRSS_Tem_Run_On_FireB, + MRSS_Tem_Run_On_FireC, + MRSS_Mooch_Bored, + MRSS_Mooch_Alert, + MRSS_Sprint, + MRSS_SprintHeadDelta, + MRSS_Fire_From_Hips, + MRSS_end, + } MARINERUN_SUBSEQUENCES; + + typedef enum MarineCrawlSubSequences { + MCSS_Standard=0, + MCSS_Dies_Standard, + MCSS_Jump, + MCSS_Attack_Primary, + MCSS_Elevation, + MCSS_FireFromHips, + MCSS_end, + } MARINECRAWL_SUBSEQUENCES; + + typedef enum MarineStandSubSequences { + MSSS_Standard=0, + MSSS_Dies_Standard, + MSSS_Jump, + MSSS_Attack_Primary, + MSSS_Elevation, + MSSS_DieSecondary, + MSSS_Fidget_A, + MSSS_Fidget_B, + MSSS_Fidget_C, + MSSS_Tem_Back_Death, + MSSS_Tem_Front_Death, + MSSS_Tem_Sum_Death, + MSSS_HitLeftLeg, + MSSS_HitRightLeg, + MSSS_HitLeftArm, + MSSS_HitRightArm, + MSSS_HitChestFront, + MSSS_HitChestBack, + MSSS_HitHeadFront, + MSSS_HitHeadBack, + MSSS_Attack_Secondary, + MSSS_Stand_To_Fidget, + MSSS_Tem_LeftSholdr, + MSSS_Tem_RightSholdr, + MSSS_Tem_LeftThigh, + MSSS_Tem_RightThigh, + MSSS_Tem_LeftForarm, + MSSS_Tem_RightForarm, + MSSS_Tem_LeftShin, + MSSS_Tem_RightShin, + MSSS_Tem_Burning, + MSSS_Taunt_One, + MSSS_Wait_Alert, + MSSS_Minigun_Delta, + MSSS_WildFire_0, + MSSS_SpearFlyFwrd, + MSSS_SpearFlyBack, + MSSS_SpearHitWallB, + MSSS_SpearHitWallF, + MSSS_Spasm, + MSSS_FireFromHips, + MSSS_Hip_Fire_Elevation, + MSSS_WildFire_45, + MSSS_WildFire_67, + MSSS_WildFire_90, + MSSS_Reload, + MSSS_PumpAction, + MSSS_Get_Weapon, + MSSS_Panic_One, + MSSS_Panic_Two, + MSSS_Tem_Electric_Death_One, + MSSS_Tem_Electric_Death_Two, + MSSS_WildFire_22, + MSSS_Panic_Reload, + MSSS_end, + } MARINESTAND_SUBSEQUENCES; + + typedef enum MarineCrouchSubSequences { + MCrSS_Standard=0, + MCrSS_Dies_Standard, + MCrSS_Jump, + MCrSS_Attack_Primary, + MCrSS_Elevation, + MCrSS_HitLeftLeg, + MCrSS_HitRightLeg, + MCrSS_HitLeftArm, + MCrSS_HitRightArm, + MCrSS_HitChestFront, + MCrSS_HitChestBack, + MCrSS_HitHeadFront, + MCrSS_HitHeadBack, + MCrSS_Attack_Secondary, + MCrSS_PumpAction, + MCrSS_Tem_Electric_Death_One, + MCrSS_FireFromHips, + MCrSS_Hip_Fire_Elevation, + MCrSS_end, + }MARINECROUCH_SUBSEQUENCES; + + typedef enum PredatorHUDSubSequences { + PHSS_Stand=0, + PHSS_Run, + PHSS_Come, + PHSS_Go, + PHSS_Attack_Primary, + PHSS_Attack_Secondary, + PHSS_Program, + PHSS_Attack_Jab, + PHSS_Fidget, + PHSS_Attack_Primary_Two, + PHSS_PullBack, + PHSS_Hold, + PHSS_Attack_Secondary_Weak_One, + PHSS_Attack_Secondary_Weak_Two, + PHSS_Attack_Secondary_Strong_One, + PHSS_Attack_Secondary_Strong_Two, + PHSS_end, + } PREDATORHUD_SUBSEQUENCES; + + typedef enum MarineHUDSubSequences { + MHSS_Stationary=0, + MHSS_Standard_Reload, + MHSS_Standard_Fire, + MHSS_Come, + MHSS_Go, + MHSS_Fidget, + MHSS_Secondary_Fire, + MHSS_Tertiary_Fire, + MHSS_Right_Out, + MHSS_Left_Out, + MHSS_end, + } MARINEHUD_SUBSEQUENCES; + + typedef enum PredatorRunSubSequences { + PRSS_Standard=0, + PRSS_Dies_Standard, + PRSS_Jump, + PRSS_Attack_Primary, + PRSS_Elevation, + PRSS_Attack_Offence_Sweep, + PRSS_Attack_Defence_Stab, + PRSS_Attack_Defence_Sweep, + PRSS_Walk, + PRSS_end, + } PREDATORRUN_SUBSEQUENCES; + + typedef enum PredatorCrawlSubSequences { + PCSS_Standard=0, + PCSS_Dies_Standard, + PCSS_Jump, + PCSS_Attack_Primary, + PCSS_Elevation, + PCSS_Attack_Offence_Sweep, + PCSS_Attack_Defence_Stab, + PCSS_Attack_Defence_Sweep, + PCSS_end, + } PREDATORCRAWL_SUBSEQUENCES; + + typedef enum PredatorStandSubSequences { + PSSS_Standard=0, + PSSS_Dies_Standard, + PSSS_Jump, + PSSS_Attack_Primary, + PSSS_Elevation, + PSSS_Get_Weapon, + PSSS_HitLeftLeg, + PSSS_HitRightLeg, + PSSS_HitLeftArm, + PSSS_HitRightArm, + PSSS_HitChestFront, + PSSS_HitChestBack, + PSSS_HitHeadFront, + PSSS_HitHeadBack, + PSSS_TemDeath_Fwrd, + PSSS_TemDeath_Bwrd, + PSSS_Tem_LeftArm, + PSSS_Tem_LeftLeg, + PSSS_Tem_RightArm, + PSSS_Tem_RightLeg, + PSSS_Tem_Riddled, + PSSS_Tem_Burning, + PSSS_Taunt_One, + PSSS_Attack_Offense_Sweep, + PSSS_Attack_Defence_Stab, + PSSS_Attack_Defence_Sweep, + PSSS_Attack_Quick_Jab, + PSSS_Attack_Uppercut, + PSSS_Jump_Up, + PSSS_Spasm, + PSSS_end, + } PREDATORSTAND_SUBSEQUENCES; + + typedef enum PredatorCrouchSubSequences { + PCrSS_Standard=0, + PCrSS_Dies_Standard, + PCrSS_Jump, + PCrSS_Attack_Primary, + PCrSS_Elevation, + PCrSS_Get_Weapon, + PCrSS_HitLeftLeg, + PCrSS_HitRightLeg, + PCrSS_HitLeftArm, + PCrSS_HitRightArm, + PCrSS_HitChestFront, + PCrSS_HitChestBack, + PCrSS_HitHeadFront, + PCrSS_HitHeadBack, + PCrSS_Attack_Offence_Sweep, + PCrSS_Attack_Defence_Stab, + PCrSS_Attack_Defence_Sweep, + PCrSS_Det_Prog, + PCrSS_Det_Laugh, + PCrSS_Det_Die1, + PCrSS_end, + } PREDATORCROUCH_SUBSEQUENCES; + + typedef enum QueenLeftStanceTemplateSubSequences { + QLSTSS_Standard, + QLSTSS_Forward_L2R, + QLSTSS_Backward_L2R, + QLSTSS_Right_L2L, + QLSTSS_Left_L2L, + QLSTSS_LeftSwipe, + QLSTSS_RightSwipe, + QLSTSS_RightHit, + QLSTSS_LeftHit, + QLSTSS_end, + } QLST_SUBSEQUENCES; + + typedef enum QueenLeftStanceFull_SubSequences { + QLSFSS_Standard_Hiss, + QLSFSS_Taunt, + QLSFSS_Forward_L2R, + QLSFSS_Backward_L2R, + QLSFSS_Right_L2L, + QLSFSS_Left_L2L, + QLSFSS_end, + } QLSF_SUBSEQUENCES; + + typedef enum QueenRightStanceTemplateSubSequences { + QRSTSS_Standard, + QRSTSS_Forward_R2L, + QRSTSS_Backward_R2L, + QRSTSS_Right_R2R, + QRSTSS_Left_R2R, + QRSTSS_LeftSwipe, + QRSTSS_RightSwipe, + QRSTSS_RightHit, + QRSTSS_LeftHit, + QRSTSS_LeftSwipe_Low, + QRSTSS_RightSwipe_Low, + QRSTSS_end, + } QRST_SUBSEQUENCES; + + typedef enum QueenRightStanceFull_SubSequences { + QRSFSS_Standard_Hiss, + QRSFSS_Taunt, + QRSFSS_Forward_R2L, + QRSFSS_Backward_R2L, + QRSFSS_Right_R2R, + QRSFSS_Left_R2R, + QRSFSS_end, + } QRSF_SUBSEQUENCES; + + typedef enum QueenGeneral_SubSequences { + QGSS_SquashDeath, + QGSS_FaceDeath, + QGSS_FallDeath, + QGSS_ButtConnect, + QGSS_RunButtAttack, + QGSS_Walk, + QGSS_Explode_Death, + QGSS_Sprint, + QGSS_Stop_To_Left, + QGSS_Stop_To_Right, + QGSS_Walk_II, + QGSS_Sprint_II, + QGSS_Spine_Elevation, + QGSS_Search_Floor, + QGSS_Fire_Flinch, + QGSS_Fire_Steps, + QGSS_Sprint_Full, + QGSS_Explosion_Stun, + QGSS_ClimbOut, + QGSS_end, + } QG_SUBSEQUENCES; + + typedef enum AlienHUDSubSequences { + AHSS_LeftSwipeDown=0, + AHSS_RightSwipeDown, + AHSS_LeftSwipeIn, + AHSS_RightSwipeIn, + AHSS_Both_In, + AHSS_Both_Down, + AHSS_TailCome, + AHSS_TailHold, + AHSS_TailStrike, + AHSS_PounceIn, + AHSS_PounceDown, + AHSS_Hor_Delta, + AHSS_Ver_Delta, + AHSS_Eat, + AHSS_end, + } ALIENHUD_SUBSEQUENCES; + + typedef enum XenoborgSubSequences { + XBSS_Die_Backwards=0, + XBSS_Die_Forwards, + XBSS_Fire_Bolter, + XBSS_Head_Horizontal_Delta, + XBSS_Head_Vertical_Delta, + XBSS_LeftArm_Horizontal_Delta, + XBSS_LeftArm_Vertical_Delta, + XBSS_Fire_Plasma, + XBSS_Power_Up, + XBSS_Power_Down, + XBSS_RightArm_Horizontal_Delta, + XBSS_RightArm_Vertical_Delta, + XBSS_Powered_Down_Standard, + XBSS_Powered_Up_Standard, + XBSS_Standing_Death, + XBSS_Torso_Delta, + XBSS_Turn_Left, + XBSS_Turn_Right, + XBSS_Walking, + XBSS_LeftLegMissingDeath, + XBSS_RightLegMissingDeath, + XBSS_end, + } XENOBORG_SUBSEQUENCES; + + #ifdef __cplusplus + + } + + #endif + + +#endif diff --git a/3dc/avp/sfx.c b/3dc/avp/sfx.c new file mode 100644 index 0000000..fdead67 --- /dev/null +++ b/3dc/avp/sfx.c @@ -0,0 +1,296 @@ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "dynblock.h" + +#include "particle.h" +#include "sfx.h" +#include "detaillevels.h" +#include "bh_types.h" +#include "bh_ais.h" +#include "bh_pred.h" +#include "bh_corpse.h" +#include "lighting.h" +#define UseLocalAssert Yes +#include "ourasert.h" + +static SFXBLOCK SfxBlockStorage[MAX_NO_OF_SFX_BLOCKS]; +static int NumFreeSfxBlocks; +static SFXBLOCK *FreeSfxBlockList[MAX_NO_OF_SFX_BLOCKS]; +static SFXBLOCK **FreeSfxBlockListPtr; + + +void HandleObjectOnFire(DISPLAYBLOCK *dispPtr); + + +/*KJL*************************************************************************** +* FUNCTIONS TO ALLOCATE AND DEALLOCATE SFX BLOCKS - KJL 12:02:14 11/13/96 * +***************************************************************************KJL*/ +void InitialiseSfxBlocks(void) +{ + SFXBLOCK *freeBlockPtr = SfxBlockStorage; + int blk; + + for(blk=0; blk < MAX_NO_OF_SFX_BLOCKS; blk++) + { + FreeSfxBlockList[blk] = freeBlockPtr++; + } + + FreeSfxBlockListPtr = &FreeSfxBlockList[MAX_NO_OF_SFX_BLOCKS-1]; + NumFreeSfxBlocks = MAX_NO_OF_SFX_BLOCKS; +} + + +SFXBLOCK* AllocateSfxBlock(void) +{ + SFXBLOCK *sfxPtr = 0; /* Default to null ptr */ + + if (NumFreeSfxBlocks) + { + sfxPtr = *FreeSfxBlockListPtr--; + NumFreeSfxBlocks--; + } + else + { + /* unable to allocate a sfxamics block I'm afraid; + MAX_NO_OF_SFX_BLOCKS is too low */ + //LOCALASSERT(NumFreeSfxBlocks); + textprint("No Free SFX blocks!\n"); + } + + return sfxPtr; +} + + +void DeallocateSfxBlock(SFXBLOCK *sfxPtr) +{ + GLOBALASSERT(sfxPtr); + *(++FreeSfxBlockListPtr) = sfxPtr; + NumFreeSfxBlocks++; +} + + + +DISPLAYBLOCK *CreateSFXObject(enum SFX_ID sfxID) +{ + DISPLAYBLOCK *dispPtr = CreateActiveObject(); + + if (dispPtr) + { + SFXBLOCK *sfxPtr = AllocateSfxBlock(); + + if (sfxPtr) + { + dispPtr->SfxPtr = sfxPtr; + sfxPtr->SfxID = sfxID; + } + else + { + /* damn, we've got a DISPLAYBLOCK, but were unable to get a SFXBLOCK; + this means we must dealloc the DISPLAYBLOCK and return NULL to indicate + failure. + */ + DestroyActiveObject(dispPtr); + dispPtr = 0; + } + } + + return dispPtr; +} + + +void DrawSfxObject(DISPLAYBLOCK *dispPtr) +{ + SFXBLOCK *sfxPtr; + + GLOBALASSERT(dispPtr); + + sfxPtr = dispPtr->SfxPtr; + GLOBALASSERT(sfxPtr); + + + switch(sfxPtr->SfxID) + { + case SFX_MUZZLE_FLASH_AMORPHOUS: + { + if (!sfxPtr->EffectDrawnLastFrame) + { + VECTORCH direction; + + direction.vx = dispPtr->ObMat.mat31; + direction.vy = dispPtr->ObMat.mat32; + direction.vz = dispPtr->ObMat.mat33; + DrawMuzzleFlash(&dispPtr->ObWorld,&direction,MUZZLE_FLASH_AMORPHOUS); + } + sfxPtr->EffectDrawnLastFrame=!sfxPtr->EffectDrawnLastFrame; + + break; + } + case SFX_MUZZLE_FLASH_SMARTGUN: + { + VECTORCH direction; + + direction.vx = dispPtr->ObMat.mat31; + direction.vy = dispPtr->ObMat.mat32; + direction.vz = dispPtr->ObMat.mat33; + DrawMuzzleFlash(&dispPtr->ObWorld,&direction,MUZZLE_FLASH_SMARTGUN); + break; + } + case SFX_MUZZLE_FLASH_SKEETER: + { + if (!sfxPtr->EffectDrawnLastFrame) + { + VECTORCH direction; + + direction.vx = dispPtr->ObMat.mat31; + direction.vy = dispPtr->ObMat.mat32; + direction.vz = dispPtr->ObMat.mat33; + DrawMuzzleFlash(&dispPtr->ObWorld,&direction,MUZZLE_FLASH_SKEETER); + } + sfxPtr->EffectDrawnLastFrame=!sfxPtr->EffectDrawnLastFrame; + + break; + } + case SFX_FRISBEE_PLASMA_BOLT: + { + VECTORCH direction; + direction.vx = dispPtr->ObMat.mat31; + direction.vy = dispPtr->ObMat.mat32; + direction.vz = dispPtr->ObMat.mat33; + DrawFrisbeePlasmaBolt(&dispPtr->ObWorld,&direction); + + break; + } + case SFX_PREDATOR_PLASMA_BOLT: + { + VECTORCH direction; + direction.vx = dispPtr->ObMat.mat31; + direction.vy = dispPtr->ObMat.mat32; + direction.vz = dispPtr->ObMat.mat33; + DrawPredatorPlasmaBolt(&dispPtr->ObWorld,&direction); + + break; + } + case SFX_SMALL_PREDATOR_PLASMA_BOLT: + { + VECTORCH direction; + direction.vx = dispPtr->ObMat.mat31; + direction.vy = dispPtr->ObMat.mat32; + direction.vz = dispPtr->ObMat.mat33; + DrawSmallPredatorPlasmaBolt(&dispPtr->ObWorld,&direction); + + break; + } + + default: + { + GLOBALASSERT(0); + break; + } + } +} + +void HandleSfxForObject(DISPLAYBLOCK *dispPtr) +{ + STRATEGYBLOCK *sbPtr = dispPtr->ObStrategyBlock; + + if (dispPtr->SpecialFXFlags & SFXFLAG_ONFIRE) + { + HandleObjectOnFire(dispPtr); + } + + if (sbPtr) + { + if(sbPtr->I_SBtype == I_BehaviourNetCorpse) + { + NETCORPSEDATABLOCK *corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + + if(!( (dispPtr->SpecialFXFlags & SFXFLAG_MELTINGINTOGROUND)&&(dispPtr->ObFlags2 < ONE_FIXED) ) + && corpseDataPtr->This_Death->Electrical && ((FastRandom()&255)==0)) + { + VECTORCH velocity; + velocity.vx = (FastRandom()&2047)-1024; + velocity.vy = (FastRandom()&2047)-1024; + velocity.vz = (FastRandom()&2047)-1024; + MakeParticle(&dispPtr->ObWorld,&velocity,PARTICLE_SPARK); + velocity.vx = (FastRandom()&2047)-1024; + velocity.vy = (FastRandom()&2047)-1024; + velocity.vz = (FastRandom()&2047)-1024; + MakeParticle(&dispPtr->ObWorld,&velocity,PARTICLE_SPARK); + MakeLightElement(&dispPtr->ObWorld,LIGHTELEMENT_ELECTRICAL_SPARKS); + + } + } + + } +} + + +void HandleObjectOnFire(DISPLAYBLOCK *dispPtr) +{ + int objectIsDisappearing; + extern int NormalFrameTime; + int noRequired = 1; + int i; + VECTORCH velocity; + + if (!dispPtr->ObShape) return; + + if (dispPtr->ObShapeData->shaperadius<=LocalDetailLevels.AlienEnergyViewThreshold) return; + + #if 1 + { + DYNAMICSBLOCK *dynPtr; + STRATEGYBLOCK *sbPtr; + + sbPtr = dispPtr->ObStrategyBlock; + LOCALASSERT(sbPtr); + dynPtr = sbPtr->DynPtr; + LOCALASSERT(sbPtr); + + + velocity.vx = DIV_FIXED((dynPtr->Position.vx-dynPtr->PrevPosition.vx)*3,NormalFrameTime*4); + velocity.vy = DIV_FIXED((dynPtr->Position.vy-dynPtr->PrevPosition.vy)*3,NormalFrameTime*4); + velocity.vz = DIV_FIXED((dynPtr->Position.vz-dynPtr->PrevPosition.vz)*3,NormalFrameTime*4); + + if (dispPtr==sbPtr->SBdptr) noRequired = 5; + + } + #else + velocity.vx = 0; + velocity.vy = 0; + velocity.vz = 0; + #endif + + objectIsDisappearing = ( (dispPtr->SpecialFXFlags & SFXFLAG_MELTINGINTOGROUND) &&(dispPtr->ObFlags2 <= ONE_FIXED) ) ; + + for (i=0; iObWorld.vx+(FastRandom()&255)-128; + position.vy = dispPtr->ObWorld.vy+(FastRandom()&255)-128; + position.vz = dispPtr->ObWorld.vz+(FastRandom()&255)-128; + #if 0 + MakeParticle(&(position), &velocity, PARTICLE_NONCOLLIDINGFLAME); + #else + if (objectIsDisappearing) + { + if ((FastRandom()&65535) < dispPtr->ObFlags2) + MakeParticle(&(position), &velocity, PARTICLE_FIRE); + } + else + { + MakeParticle(&(position), &velocity, PARTICLE_FIRE); + } + + if (FastRandom()&65535 > 32768) + { + MakeParticle(&(position), &velocity, PARTICLE_IMPACTSMOKE); + } + #endif + } + +} \ No newline at end of file diff --git a/3dc/avp/sfx.h b/3dc/avp/sfx.h new file mode 100644 index 0000000..2762901 --- /dev/null +++ b/3dc/avp/sfx.h @@ -0,0 +1,51 @@ +#ifndef _included_sfx_h_ /* Is this your first time? */ +#define _included_sfx_h_ 1 + +#define MAX_NO_OF_SFX_BLOCKS 10 +enum SFX_ID +{ + SFX_NONE, + SFX_MUZZLE_FLASH_SMARTGUN, + SFX_MUZZLE_FLASH_AMORPHOUS, + SFX_PREDATOR_PLASMA_BOLT, + SFX_SMALL_PREDATOR_PLASMA_BOLT, + SFX_FRISBEE_PLASMA_BOLT, + SFX_MUZZLE_FLASH_SKEETER, + MAX_NO_OF_SFXS, +}; + +typedef struct sfxblock +{ + enum SFX_ID SfxID; + + unsigned int EffectDrawnLastFrame:1; // useful for strobing effects + + +} SFXBLOCK; + +#define SFXFLAG_ISAFFECTEDBYHEAT 0x1 +#define SFXFLAG_MELTINGINTOGROUND 0x2 +#define SFXFLAG_ONFIRE 0x4 +#define SFXFLAG_SPARKING 0x8 + +typedef struct forcefield +{ + VECTORCH Corner; + VECTORCH Scale; + int ModuleIndex; + +} FORCEFIELD; + + + +extern void InitialiseSfxBlocks(void); +extern SFXBLOCK* AllocateSfxBlock(void); +extern void DeallocateSfxBlock(SFXBLOCK *sfxPtr); + + +extern struct displayblock *CreateSFXObject(enum SFX_ID sfxID); +extern void DrawSfxObject(struct displayblock *dispPtr); + +extern void HandleSfxForObject(DISPLAYBLOCK *dispPtr); + +#endif \ No newline at end of file diff --git a/3dc/avp/shapes/CUBE.C b/3dc/avp/shapes/CUBE.C new file mode 100644 index 0000000..ff5eb34 --- /dev/null +++ b/3dc/avp/shapes/CUBE.C @@ -0,0 +1,168 @@ +#include + +#include "system.h" + +#if PSX +#else //PSX + +#include "shape.h" +/* + +CUBE_ + +*/ + +/* + +Prototype CUBE Data + +*/ + +#define PLAYER_RADIUS 300 +#define cube_scale 1/40 + +#define CUBE_PolyType I_Polygon + +#define CUBE_colour1 col24(255,16,16) + +int *CUBE_points[]; +int *CUBE_normals[]; +int *CUBE_vnormals[]; +int *CUBE_items[]; + +SHAPEINSTR CUBE_instructions[]; + +int CUBE_points0[]; + +int CUBE_normals0[]; + +int CUBE_vnormals0[]; + +/* Items Data */ +int CUBE_item0[]; +int CUBE_item1[]; +int CUBE_item2[]; +int CUBE_item3[]; +int CUBE_item4[]; +int CUBE_item5[]; + + +SHAPEHEADER CUBE_header={ + 8, + 6, + 0, + &CUBE_points[0], + &CUBE_items[0], + &CUBE_normals[0], + &CUBE_vnormals[0], + 0, + 0, + 0, 0, 0, + + + 2000, + PLAYER_RADIUS, + -PLAYER_RADIUS, + 0, + -2000, + PLAYER_RADIUS, + -PLAYER_RADIUS, + &CUBE_instructions[0], + 0 +}; + +SHAPEINSTR CUBE_instructions[]={ + I_ShapePoints,8,&CUBE_points[0], + I_ShapeNormals,6,&CUBE_normals[0], + I_ShapeProject,8,&CUBE_points[0], + I_ShapeVNormals,8,&CUBE_vnormals[0], + I_ShapeItems,6,&CUBE_items[0], + I_ShapeEnd,0,0 +}; + +int *CUBE_points[]={ + &CUBE_points0[0] +}; + +int CUBE_points0[]={ + PLAYER_RADIUS, -2000, -PLAYER_RADIUS, + PLAYER_RADIUS, 0, -PLAYER_RADIUS, + -PLAYER_RADIUS, 0, -PLAYER_RADIUS, + -PLAYER_RADIUS, -2000, -PLAYER_RADIUS, + PLAYER_RADIUS, -2000, PLAYER_RADIUS, + PLAYER_RADIUS, 0, PLAYER_RADIUS, + -PLAYER_RADIUS, 0, PLAYER_RADIUS, + -PLAYER_RADIUS, -2000, PLAYER_RADIUS +}; + +int *CUBE_normals[]={ + &CUBE_normals0[0] +}; + +int CUBE_normals0[]={ + 65536,0,0, + 0,65535,0, + -65535,0,0, + 0,-65535,0, + 0,0,65535, + 0,0,-65535 +}; + +int *CUBE_vnormals[]={ + &CUBE_vnormals0[0] +}; + +int CUBE_vnormals0[]={ + 37837,-37837,-37837, + 37837,37837,-37837, + -37837,37837,-37837, + -37837,-37837,-37837, + 37837,-37837,37837, + 37837,37837,37837, + -37837,37837,37837, + -37837,-37837,37837 +}; + + +int *CUBE_items[]={ + &CUBE_item0[0], + &CUBE_item1[0], + &CUBE_item2[0], + &CUBE_item3[0], + &CUBE_item4[0], + &CUBE_item5[0] +}; + + + int CUBE_item0[]={ + CUBE_PolyType,0*3,0,CUBE_colour1, + 0*1,1*1,5*1,4*1, + Term +}; + int CUBE_item1[]={ + CUBE_PolyType,1*3,0,CUBE_colour1, + 1*1,2*1,6*1,5*1, + Term +}; + int CUBE_item2[]={ + CUBE_PolyType,2*3,0,CUBE_colour1, + 2*1,3*1,7*1,6*1, + Term +}; + int CUBE_item3[]={ + CUBE_PolyType,3*3,0,CUBE_colour1, + 3*1,0*1,4*1,7*1, + Term +}; + int CUBE_item4[]={ + CUBE_PolyType,4*3,0,CUBE_colour1, + 6*1,7*1,4*1,5*1, + Term +}; + int CUBE_item5[]={ + CUBE_PolyType,5*3,0,CUBE_colour1, + 2*1,1*1,0*1,3*1, + Term +}; + +#endif //PSX \ No newline at end of file diff --git a/3dc/avp/shapes/vssver.scc b/3dc/avp/shapes/vssver.scc new file mode 100644 index 0000000..9fc571b Binary files /dev/null and b/3dc/avp/shapes/vssver.scc differ diff --git a/3dc/avp/statpane.h b/3dc/avp/statpane.h new file mode 100644 index 0000000..359ac61 --- /dev/null +++ b/3dc/avp/statpane.h @@ -0,0 +1,63 @@ +/* + + statpane.h + + Created 18/11/97 by DHM: status panels for Marine HUD +*/ + +#ifndef _statpane_h +#define _statpane_h 1 + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + enum StatusPanelIndex + { + I_StatusPanel_Weapons, + // assumed to be the first + + I_StatusPanel_Inventory, + I_StatusPanel_Objectives, + I_StatusPanel_GameStats, + + NUM_STATUS_PANELS + }; /* suggested naming: "I_StatusPanel" */ + + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + void STATPANE_RequestStatusPanel + ( + enum StatusPanelIndex I_StatusPanel + ); + /* this should be called once per frame, or else call STATPANE_NoRequestedIndex() + Call it if the button for a panel is in a "down" state. + Currently the system has an internal order of precedence using the + enum StatusPanelIndex; the earlier entries have greater priority. + */ + + void STATPANE_NoRequestedPanel(void); + /* + Makes the status panel retreats off the screen; call if none of the buttons + for selecting status panels are depressed + */ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/support/COORDSTR.CPP b/3dc/avp/support/COORDSTR.CPP new file mode 100644 index 0000000..92d983f --- /dev/null +++ b/3dc/avp/support/COORDSTR.CPP @@ -0,0 +1,730 @@ +/* + + COORDSTR.CPP + + Coordinates with strategies + +*/ + #include "3dc.h" + #include "inline.h" + + #include "coordstr.hpp" + +#if 0 + #include "davemcro.h" + #include "scrobj.hpp" +#endif + + + #define UseLocalAssert Yes + #include "ourasert.h" + +#if 0 + static CoordinateWithStrategy* CoordinateWithStrategy::pCWS_FirstActive = NULL; +#endif + + #define INT_SECONDS_FOR_STANDARD_HOMING (0.25) + #define FIXP_SECONDS_FOR_STANDARD_HOMING (ONE_FIXED * INT_SECONDS_FOR_STANDARD_HOMING) + + #define DAVEMCRO_NONZERO_AND_OPPOSITESIGN(Int1, Int2) \ + ( \ + ( \ + ((Int1) > 0) \ + && \ + ((Int2) < 0) \ + ) \ + || \ + ( \ + ((Int1) < 0) \ + && \ + ((Int2) > 0) \ + ) \ + ) + + + +CoordinateWithStrategy::CoordinateWithStrategy +( + int Int_InitialCoord, + OurBool fActive +) : Daemon + ( + fActive + ) +{ + Int_CurrentCoord_Val = Int_InitialCoord; +} + + +CoordinateWithStrategy::~CoordinateWithStrategy +( +) +{ +} + + +int CoordinateWithStrategy::GetCoord_Int(void) +{ + return(Int_CurrentCoord_Val); +} + +void CoordinateWithStrategy::SetCoord_Int(int Int_NewCoord) +{ + Int_CurrentCoord_Val = Int_NewCoord; +} + + +// Coordinates with velocity /////////////////////////////////////////////// +CoordinateWithVelocity :: CoordinateWithVelocity +( + int Int_InitialCoord, + int FixP_Velocity, + OurBool fActive +) : CoordinateWithStrategy + ( + Int_InitialCoord, + fActive + ) +{ + FixP_Velocity_Val = FixP_Velocity; + FixP_Position_Val = OUR_INT_TO_FIXED( Int_CurrentCoord_Val ); +} + +CoordinateWithVelocity :: ~CoordinateWithVelocity() +{ + // empty +} + +void CoordinateWithVelocity :: SetCoord_Int +( + int Int_NewCoord +) +{ + Int_CurrentCoord_Val = Int_NewCoord; + FixP_Position_Val = OUR_INT_TO_FIXED( Int_CurrentCoord_Val ); +} + +void CoordinateWithVelocity :: SetCoord_FixP +( + int FixP_NewCoord +) +{ + Int_CurrentCoord_Val = OUR_FIXED_TO_INT( FixP_NewCoord ); + FixP_Position_Val = FixP_NewCoord; +} + +void CoordinateWithVelocity :: SetVelocity_FixP(int FixP_NewVelocity) +{ + FixP_Velocity_Val = FixP_NewVelocity; +} + + +void CoordinateWithVelocity :: ApplyVelocity +( + int FixP_Time +) +{ + FixP_Position_Val += MUL_FIXED(FixP_Time, FixP_Velocity_Val); + + Int_CurrentCoord_Val = OUR_FIXED_TO_INT( FixP_Position_Val ); +} + +int CoordinateWithVelocity :: GetCoord_Int_RoundedUp(void) +{ + + int ReturnVal = (FixP_Position_Val >> 16); + + if ( (FixP_Position_Val&0xffff) ) + { + ReturnVal++; + } + + #if 0 + textprint + ( + "CoordinateWithVelocity :: GetCoord_Int_RoundedUp()\n" + "FixP_Position_Val = %i\n" + "ReturnVal = %i\n", + FixP_Position_Val, + ReturnVal + ); + #endif + + return ReturnVal; +} + +// Coordinates with velocity: pulsing ///////////////////////////////////////////// +PulsingCoordinate :: PulsingCoordinate +( + int Int_InitialCoord, + int Int_SecondCoord, + int FixP_Velocity, + OurBool fActive +) : CoordinateWithVelocity + ( + Int_InitialCoord, + FixP_Velocity, + fActive + ) +{ + Int_Target0_Val = Int_InitialCoord; + FixP_Target0_Val = OUR_INT_TO_FIXED( Int_Target0_Val ); + + Int_Target1_Val = Int_SecondCoord; + FixP_Target1_Val = OUR_INT_TO_FIXED( Int_Target1_Val ); + +} + +PulsingCoordinate :: ~PulsingCoordinate() +{ + // empty +} + +// Pulsing coordinates: acyclic /////////////////////////////////////////////////// +AcyclicPulsingCoordinate :: AcyclicPulsingCoordinate +( + int Int_InitialCoord, + int Int_SecondCoord, + int FixP_Velocity, + OurBool fActive +) : PulsingCoordinate + ( + Int_InitialCoord, + Int_SecondCoord, + FixP_Velocity, + fActive + ) +{ + // empty +} + +AcyclicPulsingCoordinate :: ~AcyclicPulsingCoordinate() +{ + // empty +} + + +ACTIVITY_RETURN_TYPE AcyclicPulsingCoordinate :: Activity(ACTIVITY_INPUT) +{ + #if 0 + textprint("AcyclicPulsingCoordinate :: Activity(%i)\n", FixP_Time); + #endif + + int Int_CurrentCoord_Old = Int_CurrentCoord_Val; + + ApplyVelocity( FixP_Time ); + + int FixP_Displacement = (FixP_Target1_Val - FixP_Position_Val); + + #if 0 + textprint + ( + "FixP_Velocity_Val = %i FixP_Displacement = %i\n", + FixP_Velocity_Val, + FixP_Displacement + ); + #endif + + if + ( + DAVEMCRO_NONZERO_AND_OPPOSITESIGN + ( + FixP_Velocity_Val, + FixP_Displacement + ) + ) + { + { + SetCoord_FixP + ( + FixP_Target0_Val + + + FixP_Displacement + ); + } + } + + ACTIVITY_RVAL_BOOL(Int_CurrentCoord_Old != Int_CurrentCoord_Val) +} + +// Pulsing coordinates: acyclic /////////////////////////////////////////////////// +CyclicPulsingCoordinate :: CyclicPulsingCoordinate +( + int Int_InitialCoord, + int Int_SecondCoord, + int FixP_Velocity, + OurBool fActive +) : PulsingCoordinate + ( + Int_InitialCoord, + Int_SecondCoord, + FixP_Velocity, + fActive + ) +{ + fGoingForSecondCoord = Yes; +} + +CyclicPulsingCoordinate :: ~CyclicPulsingCoordinate() +{ + // empty +} + +ACTIVITY_RETURN_TYPE CyclicPulsingCoordinate :: Activity(ACTIVITY_INPUT) +{ + #if 0 + textprint("CyclicPulsingCoordinate :: Activity(%i)\n", FixP_Time); + #endif + + int Int_CurrentCoord_Old = Int_CurrentCoord_Val; + + ApplyVelocity( FixP_Time ); + + int FixP_Displacement = + ( + ( fGoingForSecondCoord ? FixP_Target1_Val : FixP_Target0_Val ) - FixP_Position_Val + ); + + #if 0 + textprint + ( + "FixP_Velocity_Val = %i FixP_Displacement = %i\n", + FixP_Velocity_Val, + FixP_Displacement + ); + #endif + + if + ( + DAVEMCRO_NONZERO_AND_OPPOSITESIGN + ( + FixP_Velocity_Val, + FixP_Displacement + ) + ) + { + { + SetCoord_FixP + ( + ( fGoingForSecondCoord ? FixP_Target1_Val : FixP_Target0_Val ) + + + FixP_Displacement + ); + + fGoingForSecondCoord = !fGoingForSecondCoord; + + SetVelocity_FixP + ( + -FixP_Velocity_Val + ); + } + } + + ACTIVITY_RVAL_BOOL(Int_CurrentCoord_Old != Int_CurrentCoord_Val) +} + + + + + + + + + + + + + + + +#if 1 +HomingCoordinate::HomingCoordinate +( + int Int_InitialCoord, + int Int_TargetCoord +) : CoordinateWithVelocity + ( + Int_InitialCoord, + 0, //FixP_Velocity, + (Int_InitialCoord != Int_TargetCoord) + ) +{ + Int_TargetCoord_Val = Int_TargetCoord; + FixP_TargetCoord_Val = OUR_INT_TO_FIXED( Int_TargetCoord ); + + FixP_IdealVelocity_Val = DIV_FIXED + ( + (FixP_TargetCoord_Val - FixP_Position_Val), + FIXP_SECONDS_FOR_STANDARD_HOMING + ); +} + +void HomingCoordinate :: SetCoord_Int(int Int_NewCoord) +{ + CoordinateWithVelocity :: SetCoord_Int + ( + Int_NewCoord + ); + + SetActive( Int_TargetCoord_Val != GetCoord_Int() ); +} + +void HomingCoordinate :: SetCoord_FixP(int FixP_NewCoord) +{ + CoordinateWithVelocity :: SetCoord_FixP + ( + FixP_NewCoord + ); + + SetActive( Int_TargetCoord_Val != GetCoord_Int() ); +} + + +AcyclicHomingCoordinate :: AcyclicHomingCoordinate +( + int Int_InitialCoord, + int Int_TargetCoord +) : HomingCoordinate + ( + Int_InitialCoord, + Int_TargetCoord + ) +{ + // empty +} + +ACTIVITY_RETURN_TYPE AcyclicHomingCoordinate :: Activity(ACTIVITY_INPUT) +{ + int Int_CurrentCoord_Old = Int_CurrentCoord_Val; + + #if 0 + textprint("acyclic homing coord for time %i\n",FixP_Time); + #endif + + int FixP_Delta_Homing = (FixP_TargetCoord_Val - FixP_Position_Val); + + #if 0 + textprint + ( + "current = %6i fixp = %6i\n", + (int)Int_CurrentCoord_Val, + (int)FixP_Position_Val + ); + + textprint + ( + "target = %6i fixp = %6i\n", + (int)Int_TargetCoord_Val, + (int)FixP_TargetCoord_Val + ); + #endif + + SetVelocity_FixP( FixP_IdealVelocity_Val ); + int FixP_Delta_Position = MUL_FIXED(FixP_Time, FixP_Velocity_Val); + + #if 0 + textprint + ( + "FixP delta Homing= %6i PosN=%6i\n", + (int)FixP_Delta_Homing, + (int)FixP_Delta_Position + ); + #endif + + + //if target is within this frame's velocity... + if + ( + abs(FixP_Delta_Homing) + <= + abs(FixP_Delta_Position) + ) + { + #if 0 + textprint("within range\n"); + #endif + +#if 1 + SetCoord_Int + ( + Int_TargetCoord_Val + ); + SetVelocity_FixP( 0 ); + Stop(); +#else + ApplyVelocity(FixP_Time); +#endif + } + else + { + #if 0 + textprint("not within range\n"); + #endif + + ApplyVelocity(FixP_Time); + + + } + + ACTIVITY_RVAL_BOOL(Int_CurrentCoord_Old != Int_CurrentCoord_Val) + +} + + + + +#if 0 +OurBool AcyclicHomingCoordinate::Activity(int FixP_Time) +{ + #if 1 + textprint("acyclic homing coord for time %i\n",FixP_Time); + #endif +} +#endif + + +void AcyclicHomingCoordinate :: SetTarget_Int +( + int Int_TargetCoord +) +{ + #if 0 + { + char temp[100]; + sprintf + ( + temp, + "SetTarget(Int_=%i)", + Int_TargetCoord + ); + DAVELOG(temp); + } + #endif + #if 0 + { + textprint + ( + "SetTarget(Int_=%i)\n", + Int_TargetCoord + ); + } + #endif + + Int_TargetCoord_Val = Int_TargetCoord; + FixP_TargetCoord_Val = OUR_INT_TO_FIXED( Int_TargetCoord ); + + FixP_IdealVelocity_Val = DIV_FIXED( + (FixP_TargetCoord_Val - FixP_Position_Val), + FIXP_SECONDS_FOR_STANDARD_HOMING + ); + + + SetActive( Int_TargetCoord != GetCoord_Int() ); +} + +#if 0 +OurBool AcyclicHomingCoordinate :: fTargetWithinThisFramesRange(void) +{ + +} + +void AcyclicHomingCoordinate :: ChangeVelocityBasedOnHoming(int FixP_Time) +{ +} +#endif + +// class AcyclicFixedSpeedHoming : public CoordinateWithVelocity +// public: +AcyclicFixedSpeedHoming :: AcyclicFixedSpeedHoming +( + int Int_InitialCoord, + int Int_TargetCoord, + int FixP_Speed_New + // must be >= zero +) : CoordinateWithVelocity + ( + Int_InitialCoord, // int Int_InitialCoord, + ( + (Int_TargetCoord > Int_InitialCoord ) + ? + ( FixP_Speed_New ) + : + ( -FixP_Speed_New ) + ), // int FixP_Velocity, + ( Int_InitialCoord != Int_TargetCoord ) // OurBool fActive + ) +{ + GLOBALASSERT( FixP_Speed_New >= 0); + + FixP_Speed_Val = FixP_Speed_New; +} + +AcyclicFixedSpeedHoming :: ~AcyclicFixedSpeedHoming() +{ +} + +ACTIVITY_RETURN_TYPE AcyclicFixedSpeedHoming :: Activity(ACTIVITY_INPUT) +{ + int Int_CurrentCoord_Old = Int_CurrentCoord_Val; + + #if 0 + textprint("acyclic homing coord for time %i\n",FixP_Time); + #endif + + int FixP_Delta_Homing = (FixP_TargetCoord_Val - FixP_Position_Val); + + #if 0 + textprint + ( + "current = %6i fixp = %6i\n", + (int)Int_CurrentCoord_Val, + (int)FixP_Position_Val + ); + + textprint + ( + "target = %6i fixp = %6i\n", + (int)Int_TargetCoord_Val, + (int)FixP_TargetCoord_Val + ); + #endif + + #if 0 + SetVelocity_FixP( FixP_IdealVelocity_Val ); + #endif + + int FixP_Delta_Position = MUL_FIXED(FixP_Time, FixP_Velocity_Val); + + #if 0 + textprint + ( + "FixP delta Homing= %6i PosN=%6i\n", + (int)FixP_Delta_Homing, + (int)FixP_Delta_Position + ); + #endif + + + //if target is within this frame's velocity... + if + ( + abs(FixP_Delta_Homing) + <= + abs(FixP_Delta_Position) + ) + { + #if 0 + textprint("within range\n"); + #endif + + SetCoord_FixP + ( + FixP_TargetCoord_Val + ); + SetVelocity_FixP( 0 ); + Stop(); + } + else + { + #if 0 + textprint("not within range\n"); + #endif + + ApplyVelocity(FixP_Time); + + + } + + ACTIVITY_RVAL_BOOL(Int_CurrentCoord_Old != Int_CurrentCoord_Val) +} + +void AcyclicFixedSpeedHoming :: SetTarget_Int +( + int Int_TargetCoord +) +{ + Int_TargetCoord_Val = Int_TargetCoord; + FixP_TargetCoord_Val = OUR_INT_TO_FIXED( Int_TargetCoord ); + + #if 1 + SetVelocity_FixP + ( + (Int_TargetCoord_Val > GetCoord_Int() ) + ? + ( FixP_Speed_Val ) + : + ( -FixP_Speed_Val ) + ); + #else + if (FixP_TargetCoord_Val > FixP_Position_Val) + { + FixP_IdealVelocity_Val = FixP_IdealSpeed; + } + else + { + FixP_IdealVelocity_Val = -FixP_IdealSpeed; + } + #endif + + SetActive( Int_TargetCoord != GetCoord_Int() ); +} + +void AcyclicFixedSpeedHoming :: SetTarget_FixP +( + int FixP_TargetCoord +) +{ + Int_TargetCoord_Val = OUR_FIXED_TO_INT( FixP_TargetCoord ); + FixP_TargetCoord_Val = FixP_TargetCoord; + + #if 1 + SetVelocity_FixP + ( + ( FixP_TargetCoord_Val > FixP_Position_Val ) + ? + ( FixP_Speed_Val ) + : + ( -FixP_Speed_Val ) + ); + #else + if (FixP_TargetCoord_Val > FixP_Position_Val) + { + FixP_IdealVelocity_Val = FixP_IdealSpeed; + } + else + { + FixP_IdealVelocity_Val = -FixP_IdealSpeed; + } + #endif + + SetActive( FixP_TargetCoord != GetCoord_FixP() ); +} + + +void AcyclicFixedSpeedHoming :: SetSpeed_FixP +( + int FixP_Speed_New + // must be >= zero +) +{ + GLOBALASSERT( FixP_Speed_New >= 0); + + FixP_Speed_Val = FixP_Speed_New; + + SetVelocity_FixP + ( + ( FixP_TargetCoord_Val > FixP_Position_Val ) + ? + ( FixP_Speed_Val ) + : + ( -FixP_Speed_Val ) + ); + +} + +#endif + + + + + diff --git a/3dc/avp/support/COORDSTR.HPP b/3dc/avp/support/COORDSTR.HPP new file mode 100644 index 0000000..2fe8b96 --- /dev/null +++ b/3dc/avp/support/COORDSTR.HPP @@ -0,0 +1,264 @@ +/* + + coordstr.hpp + +*/ + +#ifndef coordstr +#define coordstr 1 + + #ifndef _daemon + #include "daemon.h" + #endif + +/* Type definitions *****************************************************/ + + class CoordinateWithStrategy : public Daemon + { + public: + CoordinateWithStrategy + ( + int Int_InitialCoord, + OurBool fActive + ); + + virtual ~CoordinateWithStrategy(); + + int GetCoord_Int(void); + virtual void SetCoord_Int(int Int_NewCoord); + + virtual ACTIVITY_RETURN_TYPE Activity(ACTIVITY_INPUT) = 0; + // the strategy to run when active... + + #if 0 + virtual void UpdateScreenObject + ( + ScreenObject* pScrObj + ) = 0; + #endif + + protected: + int Int_CurrentCoord_Val; + }; + +#if 0 + class CoordinateWith2DStrategy : public Daemon + { + public + CoordinateWith2DStrategy + }; +#endif + + class CoordinateWithVelocity : public CoordinateWithStrategy + { + protected: + void ApplyVelocity(int FixP_Time); + int FixP_Velocity_Val; + int FixP_Position_Val; + + public: + CoordinateWithVelocity + ( + int Int_InitialCoord, + int FixP_Velocity, + OurBool fActive + ); + + virtual ~CoordinateWithVelocity(); + + virtual void SetCoord_Int(int Int_NewCoord); + virtual void SetCoord_FixP(int FixP_NewCoord); + + void SetVelocity_FixP(int FixP_NewVelocity); + + virtual ACTIVITY_RETURN_TYPE Activity(ACTIVITY_INPUT) = 0; + + int GetCoord_FixP(void) {return FixP_Position_Val;} + int GetCoord_Int_RoundedUp(void); + + }; + + class PulsingCoordinate : public CoordinateWithVelocity + { + public: + PulsingCoordinate + ( + int Int_InitialCoord, + int Int_SecondCoord, + int FixP_Velocity, + OurBool fActive + ); + + virtual ~PulsingCoordinate(); + + virtual ACTIVITY_RETURN_TYPE Activity(ACTIVITY_INPUT) = 0; + + protected: + int Int_Target0_Val; + int FixP_Target0_Val; + + int Int_Target1_Val; + int FixP_Target1_Val; + }; + + class AcyclicPulsingCoordinate : public PulsingCoordinate + { + public: + AcyclicPulsingCoordinate + ( + int Int_InitialCoord, + int Int_SecondCoord, + int FixP_Velocity, + OurBool fActive + ); + + virtual ~AcyclicPulsingCoordinate(); + + virtual ACTIVITY_RETURN_TYPE Activity(ACTIVITY_INPUT); + // base class activity; derived classes should call this + }; + + class CyclicPulsingCoordinate : public PulsingCoordinate + { + public: + CyclicPulsingCoordinate + ( + int Int_InitialCoord, + int Int_SecondCoord, + int FixP_Velocity, + OurBool fActive + ); + + virtual ~CyclicPulsingCoordinate(); + + ACTIVITY_RETURN_TYPE Activity(ACTIVITY_INPUT); + private: + OurBool fGoingForSecondCoord; + + }; + +#if 1 + class HomingCoordinate : public CoordinateWithVelocity + { + protected: + int Int_TargetCoord_Val; + int FixP_TargetCoord_Val; + + int FixP_IdealVelocity_Val; + + public: + HomingCoordinate + ( + int Int_InitialCoord, + int Int_TargetCoord + ); + + int GetTarget_Int(void) const; + + void SetCoord_Int(int Int_NewCoord); + void SetCoord_FixP(int FixP_NewCoord); + + #if 0 + virtual OurBool fTargetWithinThisFramesRange(void) = 0; + virtual void ChangeVelocityBasedOnHoming(int FixP_Time) = 0; + #endif + }; + + // Inline fns: + inline int HomingCoordinate::GetTarget_Int(void) const {return Int_TargetCoord_Val;} + + + + class AcyclicHomingCoordinate : public HomingCoordinate + { + public: + AcyclicHomingCoordinate + ( + int Int_InitialCoord, + int Int_TargetCoord + ); + + virtual ACTIVITY_RETURN_TYPE Activity(ACTIVITY_INPUT); + + void SetTarget_Int + ( + int Int_TargetCoord + ); + + #if 0 + OurBool fTargetWithinThisFramesRange(void); + void ChangeVelocityBasedOnHoming(int FixP_Time); + #endif + + }; + + class CyclicHomingCoordinate : public CoordinateWithStrategy + { + public: + CyclicHomingCoordinate + ( + int Int_InitialCoord, + int Int_TargetCoord, + int Int_MinVal, + int Int_MaxVal + ); + + void SetTarget_Int + ( + int Int_TargetCoord + ); + + private: + int Int_TargetCoord_Val; + }; + + class AcyclicFixedSpeedHoming : public CoordinateWithVelocity + { + public: + AcyclicFixedSpeedHoming + ( + int Int_InitialCoord, + int Int_TargetCoord, + int FixP_Speed + // must be >= zero + ); + ~AcyclicFixedSpeedHoming(); + + virtual ACTIVITY_RETURN_TYPE Activity(ACTIVITY_INPUT); + + int GetTarget_Int(void) const; + + void SetTarget_Int + ( + int Int_TargetCoord + ); + void SetTarget_FixP + ( + int FixP_TargetCoord + ); + + void SetSpeed_FixP + ( + int FixP_Speed + // must be >= zero + ); + + protected: + int Int_TargetCoord_Val; + int FixP_TargetCoord_Val; + + int FixP_Speed_Val; + + }; + inline int AcyclicFixedSpeedHoming::GetTarget_Int(void) const {return Int_TargetCoord_Val;} + +#endif + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + +/* End of the header ****************************************************/ + +#endif diff --git a/3dc/avp/support/DAEMON.CPP b/3dc/avp/support/DAEMON.CPP new file mode 100644 index 0000000..3cf38ec --- /dev/null +++ b/3dc/avp/support/DAEMON.CPP @@ -0,0 +1,418 @@ +/******************************************************************* + * + * DESCRIPTION: Daemon code - things that need to be updated on a + * per-frame basis provided they are "active" + * AUTHOR: David Malcolm + * + * HISTORY: + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "daemon.h" + +#include "inline.h" + +#if SupportCallbackHooks +#include "scrobj.hpp" +#endif + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Constants *******************************************************/ + #define UseRealFrameTime Yes + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + #endif +#ifdef __cplusplus + }; +#endif + + +/* Internal function prototypes ************************************/ + +/* Exported globals ************************************************/ + /*static*/ int Daemon :: DaemonTimeScale = ONE_FIXED; + + #if !IndividualTiming + /*static*/ int Daemon :: FixP_Time = 0; + #endif + +/* Internal globals ************************************************/ +// static +Daemon* Daemon :: p666_FirstActive = NULL; +// static +Daemon* Daemon :: p666_Iteration_Current = NULL; +// static +Daemon* Daemon :: p666_Iteration_Next = NULL; + +/* Exported function definitions ***********************************/ +#if SupportCallbackHooks +// class CallbackHook +CallbackHook :: CallbackHook +( + Daemon* p666_New, + void* pUser_New +) +{ + if ( p666_New -> pFirstHook ) + { + GLOBALASSERT( p666_New -> pFirstHook -> pPrvHook == NULL); + p666_New -> pFirstHook -> pPrvHook = this; + } + + pNxtHook = p666_New -> pFirstHook; + + p666_New -> pFirstHook = this; + + pPrvHook = NULL; + + p666_Val = p666_New; + pUser_Val = pUser_New; +} + +CallbackHook :: ~CallbackHook() +{ + // Remove from list: + if ( pPrvHook ) + { + #if debug + if ( p666_Val ) + { + GLOBALASSERT( this != p666_Val -> pFirstHook ); + } + #endif + pPrvHook -> pNxtHook = pNxtHook; + } + else + { + if ( p666_Val ) + { + // this was it's daemon's first callback: + GLOBALASSERT( this == p666_Val -> pFirstHook ); + p666_Val -> pFirstHook = pNxtHook; + } + } + + if ( pNxtHook ) + { + pNxtHook -> pPrvHook = pPrvHook; + } + +} +#endif // SupportCallbackHooks + +// class Daemon +Daemon :: Daemon +( + OurBool fActive +) +{ + #if SupportCallbackHooks + pFirstHook= NULL; + #endif + + fIsActive_Val = No; + + if (fActive) + { + Start(); + } + else + { + p666_NextActive = NULL; + p666_PrevActive = NULL; + } +} + +Daemon :: ~Daemon() +{ + if (fIsActive_Val) + { + Stop(); + } + + if ( p666_Iteration_Current == this ) + { + // Then this daemon is being processed for Activity(); + // Set the static iteration ptr to NULL to signify it has been deleted + // so that callback hooks don't get called + p666_Iteration_Current = NULL; + } + + #if SupportCallbackHooks + // remove from screen objects lists of attached daemons + while ( pFirstHook ) + { + pFirstHook -> p666_Val = NULL; + + pFirstHook = pFirstHook -> pNxtHook; + } + #endif +} + + +void Daemon :: Start(void) +{ + if (!fIsActive_Val) + { + // Insert at front of active 666 list + p666_PrevActive = NULL; + p666_NextActive = p666_FirstActive; + + if (p666_FirstActive) + { + p666_FirstActive -> p666_PrevActive = this; + } + + p666_FirstActive = this; + + fIsActive_Val = Yes; + } +} + +void Daemon :: Stop(void) +{ + if (fIsActive_Val) + { + // Remove from active 666 list + { + // Check against the iteration in the Maintain() static function: + { + if ( p666_Iteration_Next == this ) + { + // then this is due the next daemon to have its Activity() called; + // advance the static iteration ptr to this daemon's next + p666_Iteration_Next = p666_NextActive; + } + } + + if ( p666_PrevActive ) + { + GLOBALASSERT( p666_PrevActive -> fIsActive_Val ); + + p666_PrevActive -> p666_NextActive = p666_NextActive; + } + + if ( p666_NextActive ) + { + GLOBALASSERT( p666_NextActive -> fIsActive_Val ); + + p666_NextActive -> p666_PrevActive = p666_PrevActive; + } + + if (p666_FirstActive == this) + { + p666_FirstActive = p666_NextActive; + } + } + + fIsActive_Val = No; + } +} + +void Daemon :: SetActive(OurBool fActive) +{ + if (fActive) + { + Start(); + } + else + { + Stop(); + } +} + +OurBool Daemon :: bActive(void) const +{ + return fIsActive_Val; +} + +#if SupportCallbackHooks +void Daemon :: ForceHookActivity(void) +{ + // a way to call the OnActivity() method for all attached hooks + + CallbackHook* pCallbackHook = pFirstHook; + while ( pCallbackHook ) + { + CallbackHook* pCallbackHook_Nxt = pCallbackHook -> pNxtHook; + + pCallbackHook -> OnActivity(); + + pCallbackHook = pCallbackHook_Nxt; + } + +} +#endif // SupportCallbackHooks + +#if 0 +void Daemon :: LinkScreenObject +( + ScreenObject& ScrObj +) +{ + UNWRITTEN(); +} + +void Daemon :: UnlinkScreenObject +( + ScreenObject& ScrObj +) +{ + UNWRITTEN(); +} +#endif + +// static +void Daemon :: Maintain(int FixP_Time_ToUse) +{ + GLOBALASSERT( NULL == p666_Iteration_Current ); + GLOBALASSERT( NULL == p666_Iteration_Next ); + + #if DaemonDiagnostics + ProfileStart(); + #endif + + p666_Iteration_Current = p666_FirstActive; + + FixP_Time = FixP_Time_ToUse; + + while ( p666_Iteration_Current ) + { + p666_Iteration_Next = p666_Iteration_Current -> p666_NextActive; + + { + #if DaemonNaming && DaemonDiagnostics + char* tempDebugName = p666_Iteration_Current -> GetDebugName(); + // in case it gets deleted during the loop + + ProfileStart(); + #endif + + #if SupportCallbackHooks + if + ( + p666_Iteration_Current -> Activity(FixP_Time) + ) + { + if ( p666_Iteration_Current ) + { + // run the OnActivity() method for all the callback hooks attached to this daemon + CallbackHook* pCallbackHook = p666_Iteration_Current -> pFirstHook; + while ( pCallbackHook ) + { + CallbackHook* pCallbackHook_Nxt = pCallbackHook -> pNxtHook; + + pCallbackHook -> OnActivity(); + + pCallbackHook = pCallbackHook_Nxt; + } + } + // else the iterating daemon got deleted during the call to Activity() + } + #else + { + #if IndividualTiming + { + p666_Iteration_Current -> Activity(FixP_Time); + } + #else + { + p666_Iteration_Current -> Activity(); + } + #endif + } + #endif + + #if DaemonNaming && DaemonDiagnostics + ProfileStop + ( + tempDebugName + ); + #endif + + } + /* + Advance to the next in the iteration. + This will be either the next ptr of the current as stored above, + or one further along the list (since the pNext one itself might + have got deleted during the call to Activity) + */ + p666_Iteration_Current = p666_Iteration_Next; + } + + #if DaemonDiagnostics + + ProfileStop("Daemon :: Maintain()"); + + #if CountActiveDaemons + textprint("Num active daemons:%i\n",GetNumActive()); + #endif + + #endif // #if DaemonDiagnostics + +} + +void DAEMON_Init(void) +{ +} + +#if UseRealFrameTime +extern "C" extern int RealFrameTime; +#else +extern "C" extern int NormalFrameTime; +#endif + +void DAEMON_Maintain(void) +{ + #if 0 + textprint("DAEMON_Maintain() called\n"); + #endif + + #if 0 + textprint("RealFrameTime=%i\n",RealFrameTime); + #endif + + int DaemonFrameTime = + ( + #if UseRealFrameTime + RealFrameTime + #else + NormalFrameTime + #endif + ); + + { + if (Daemon :: DaemonTimeScale!=ONE_FIXED) + { + DaemonFrameTime = MUL_FIXED(DaemonFrameTime,Daemon :: DaemonTimeScale); + } + + } + + /* cap DaemonFrameTime if frame rate is really low */ + if (DaemonFrameTime>32768) DaemonFrameTime=32768; + + Daemon :: Maintain + ( + DaemonFrameTime + ); +} + + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/support/command.hpp b/3dc/avp/support/command.hpp new file mode 100644 index 0000000..72b932a --- /dev/null +++ b/3dc/avp/support/command.hpp @@ -0,0 +1,60 @@ +/* + + command.hpp + + An object for encapsulating requests; see pp233-242 of + "Design Patterns" + +*/ + +#ifndef _command +#define _command 1 + + #ifndef _refobj + #include "refobj.hpp" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + class Command : public RefCountObject + { + public: + virtual OurBool Execute(void) = 0; + // return value is "was command completed successfully?" + + protected: + // Empty constructor: + Command() : RefCountObject() {} + + protected: + // Protected destructor; Release() is the only method allowed to + // delete it... + virtual ~Command() + { + // empty + } + }; + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/support/consbind.cpp b/3dc/avp/support/consbind.cpp new file mode 100644 index 0000000..b621bac --- /dev/null +++ b/3dc/avp/support/consbind.cpp @@ -0,0 +1,946 @@ +/******************************************************************* + * + * DESCRIPTION: consbind.cpp + * + * Ability to kind keystrokes to strings so they appear in the + * console when you hit the key. Initial implementation went through + * the WM_KEYDOWN hook so that we get debouncing and typematic action + * for free; subsequently added an implementation based on the KeyboadInput[] + * array. + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 6/4/98 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "consbind.hpp" + + #if KeyBindingUses_KEY_ID + #include "avpitems.hpp" + #include "iofocus.h" + #include "scstring.hpp" + #include "strtab.hpp" + #endif + + + #define UseLocalAssert Yes + #include "ourasert.h" +#include "frontend/avp_menus.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + #if KeyBindingUses_WM_KEYDOWN + #define MAX_VALUE_BINDABLE_KEY (VK_DIVIDE) + #endif + + #if KeyBindingUses_KEY_ID + #define MAX_VALUE_BINDABLE_KEY (MAX_NUMBER_OF_INPUT_KEYS) + #endif +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + extern unsigned char KeyboardInput[]; + extern unsigned char DebouncedKeyboardInput[]; + + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +// class KeyBinding +// public: + +// static +void +KeyBinding :: ParseBindCommand +( + ProjChar* pProjCh_ToParse +) +{ + GLOBALASSERT(pProjCh_ToParse); + + BindableKey theKey; + ProjChar* pProjCh_FollowingTheKey; + + if + ( + KeyBinding :: ParseBindCommand + ( + theKey, // BindableKey& theKey_Out, + &pProjCh_FollowingTheKey, // ProjChar** ppProjCh_Out, + // returns where in the input string to continue processing + + pProjCh_ToParse // ProjChar* pProjCh_In + ) + ) + { + SCString* pSCString_ToBind = new SCString(pProjCh_FollowingTheKey); + + // Create the KeyBinding object: + KeyBinding* pNewBinding = new KeyBinding + ( + theKey, + pSCString_ToBind + ); + + // Feedback: + { + SCString* pSCString_1 = new SCString("BOUND \""); + // LOCALISEME + + SCString* pSCString_2 = new SCString("\" TO "); + + SCString* pSCString_3 = MakeStringForKey + ( + theKey + ); + + SCString* pSCString_Feedback = new SCString + ( + pSCString_1, + pSCString_ToBind, + pSCString_2, + pSCString_3 + ); + + pSCString_Feedback -> SendToScreen(); + + pSCString_Feedback -> R_Release(); + pSCString_3 -> R_Release(); + pSCString_2 -> R_Release(); + pSCString_1 -> R_Release(); + } + + pSCString_ToBind -> R_Release(); + } + else + { + // Can't recognise which key is to be bound to; + // provide an error message + // UNWRITTEN + } +} + +// static +void +KeyBinding :: ParseUnbindCommand +( + ProjChar* pProjCh_ToParse +) +{ + GLOBALASSERT(pProjCh_ToParse); + + // Iterate through leading whitespace: + { + while + ( + *pProjCh_ToParse + ) + { + // LOCALISEME: + if (!isspace(*pProjCh_ToParse)) + { + break; + } + pProjCh_ToParse++; + } + } + + // Scan through the string, trying to find matches against strings for keys + // We will use the longest match: + { + OurBool bGotMatch = No; + unsigned int LongestMatch = 0; + BindableKey theKey_ToUnbind; + + for (int i=0;i GetNumChars(); + + if (LengthOfTestString > 0) + { + if + ( + 0 == _strnicmp + ( + pSCString_TestKey -> pProjCh(), + pProjCh_ToParse, + LengthOfTestString + ) + // LOCALISEME + ) + { + // Then we have a match; see if it's longer than + // what's come before... + if (LengthOfTestString>LongestMatch) + { + LongestMatch = LengthOfTestString; + + theKey_ToUnbind = theKey; + bGotMatch = Yes; + + } + } + } + + pSCString_TestKey -> R_Release(); + } + + if (bGotMatch) + { + // Then we must get rid of all bindings with this as their key: + for + ( + LIF oi(&List_pKeyBindings); + !oi . done(); + ) + { + GLOBALASSERT(oi()); + if ( oi() -> theKey == theKey_ToUnbind ) + { + oi . delete_current(); + } + else + { + oi . next(); + } + } + } + } +} + +#if 0 +// static +void +KeyBinding :: AttemptToBind +( + SCString* pSCString_Key, // description of key + SCString* pSCString_ToBind // string to be bound +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pSCString_Key ); + GLOBALASSERT( pSCString_ToBind ); + } + + /* CODE */ + { + BindableKey theBindableKey_ToUse; + + if + ( + !bGetKeyForString + ( + theBindableKey_ToUse, // BindableKey& theKey_Out, + pSCString_Key -> pProjCh() + ) + ) + { + // Can't recognise which key is to be bound to; + // provide an error message + ErrorDontRecogniseKey(pSCString_Key); + + return; + } + + // Create the KeyBinding object: + new KeyBinding + ( + theBindableKey_ToUse, + pSCString_ToBind + ); + } +} + +// static +void +KeyBinding :: AttemptToUnbind +( + SCString* pSCString_Key // description of key +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pSCString_Key ); + } + + /* CODE */ + { + BindableKey theBindableKey_ToUse; + + if + ( + !bGetKeyForString + ( + theBindableKey_ToUse, // BindableKey& theKey_Out, + pSCString_Key -> pProjCh() + ) + ) + { + // Can't recognise which key is to be bound to; + // provide an error message + ErrorDontRecogniseKey(pSCString_Key); + + return; + } + + // Find and remove any bindings to that key; note the number: + + // Provide feedback: + } +} +#endif + + +// static +void +KeyBinding :: UnbindAll(void) +{ + SCString* pSCString_Feedback = new SCString("DESTROYING ALL KEY BINDINGS"); + // LOCALISEME + + pSCString_Feedback -> SendToScreen(); + + pSCString_Feedback -> R_Release(); + + while + ( + List_pKeyBindings . size() > 0 + ) + { + delete List_pKeyBindings . first_entry(); + // The destructor for the KeyBinding will remove + // it from the list and hence the list will shrink. + } +} + +// static +void +KeyBinding :: ListAllBindings(void) +{ + SCString* pSCString_Feedback = new SCString("LIST OF ALL KEY BINDINGS:"); + // LOCALISEME + + pSCString_Feedback -> SendToScreen(); + + pSCString_Feedback -> R_Release(); + + for + ( + CLIF oi(&List_pKeyBindings); + !oi . done(); + oi . next() + ) + { + GLOBALASSERT(oi()); + oi() -> ListThis(); + } +} + +// static +void KeyBinding :: WriteToConfigFile(char* Filename) +{ + // overwrites the file with a batch file that'll + // restore current bindings + + GLOBALASSERT(Filename); + + FILE* pFile = fopen(Filename,"w"); + + if (!pFile) + { + return; + // and don't destroy the bindings, since we won't + // restore them next time into game + } + + fprintf(pFile,"#This file generated by AVP\n"); + // LOCALISEME + + for + ( + LIF oi(&List_pKeyBindings); + !oi.done(); + oi.next() + ) + { + SCString* pSCString_Key = MakeStringForKey + ( + oi() -> theKey + ); + + fprintf + ( + pFile, + "BIND %s %s\n", + pSCString_Key -> pProjCh(), + oi() -> pSCString_ToOutput -> pProjCh() + ); + + pSCString_Key->R_Release(); + } + + fclose(pFile); + + // Destroy all the current bindings so we don't get a duplicate + // set next time the batch file fires: + { + while + ( + List_pKeyBindings . size() > 0 + ) + { + delete List_pKeyBindings . first_entry(); + // The destructor for the KeyBinding will remove + // it from the list and hence the list will shrink. + } + } +} + + +#if KeyBindingUses_WM_KEYDOWN +// static +void +KeyBinding :: Process_WM_KEYDOWN +( + WPARAM wParam +) +{ + + // Iterate through the list, finding matches. + // We must process the matching objects later, in case they are bound to things + // which modify the list. So we built a list of pending SCString*'s. + // (so BIND X UNBIND X won't kill the program. I hope) + + // The list of pending SCStrings has been made static to the class in an attempt to + // optimise this function + + // Ensure it starts off empty (which it would if it was a local): + GLOBALASSERT( 0 == PendingList . NumEntries() ); + + for + ( + LIFoi(&List_pKeyBindings); + !oi.done(); + oi.next() + ) + { + // Note that the BindableKey type is type-equal to WPARAM if this function + // exists: + if + ( + oi() -> theKey == wParam + ) + { + // Add _the_string_ to the pending list (with a reference) + // The reference is added by the RefList template, and this ensures + // the string stays alive whatever that pesky user does: + GLOBALASSERT( oi() -> pSCString_ToOutput ); + PendingList . AddToEnd + ( + *( oi() -> pSCString_ToOutput ) + ); + + if (bEcho) + { + oi() -> pSCString_ToOutput -> SendToScreen(); + } + } + } + + // Iterate through the pending list, destructively reading the + // "references" from the front: + { + SCString* pSCString; + + // The assignment in this boolean expression is deliberate: + while + ( + NULL != (pSCString = PendingList . GetYourFirst()) + ) + { + pSCString -> ProcessAnyCheatCodes(); + pSCString -> R_Release(); + } + } + + // Ensure the pending list finishes off empty + // (since we're pretending it's a local variable): + GLOBALASSERT( 0 == PendingList . NumEntries() ); + +} +#endif + +#if KeyBindingUses_KEY_ID +// static +void +KeyBinding :: Maintain(void) +{ + // Only process if we're in a running-around type of mode + // rather than typing at the console: + if + ( + IOFOCUS_AcceptControls() + ) + { + // Iterate through the list, finding matches. + // We must process the matching objects later, in case they are bound to things + // which modify the list. So we built a list of pending SCString*'s. + // (so BIND X UNBIND X won't kill the program. I hope) + + // The list of pending SCStrings has been made static to the class in an attempt to + // optimise this function + + // Ensure it starts off empty (which it would if it was a local): + GLOBALASSERT( 0 == PendingList . NumEntries() ); + + for + ( + LIFoi(&List_pKeyBindings); + !oi.done(); + oi.next() + ) + { + // Note that the BindableKey type is type-equal to enum KEY_ID if this function + // exists: + if + ( + DebouncedKeyboardInput[ oi() -> theKey ] + ) + { + // Add _the_string_ to the pending list (with a reference) + // The reference is added by the RefList template, and this ensures + // the string stays alive whatever that pesky user does: + GLOBALASSERT( oi() -> pSCString_ToOutput ); + PendingList . AddToEnd + ( + *( oi() -> pSCString_ToOutput ) + ); + + if (bEcho) + { + oi() -> pSCString_ToOutput -> SendToScreen(); + } + } + } + + // Iterate through the pending list, destructively reading the + // "references" from the front: + { + SCString* pSCString; + + // The assignment in this boolean expression is deliberate: + while + ( + NULL != (pSCString = PendingList . GetYourFirst()) + ) + { + pSCString -> ProcessAnyCheatCodes(); + pSCString -> R_Release(); + } + } + + // Ensure the pending list finishes off empty + // (since we're pretending it's a local variable): + GLOBALASSERT( 0 == PendingList . NumEntries() ); + } +} +#endif + + +// private: +// Private ctor/dtor; to be called only by static fns of the class: +KeyBinding :: KeyBinding +( + BindableKey theKey_ToUse, + SCString* pSCString_ToBind +) : theKey(theKey_ToUse), + pSCString_ToOutput(pSCString_ToBind) +{ + GLOBALASSERT(pSCString_ToOutput); + + pSCString_ToOutput -> R_AddRef(); + + List_pKeyBindings . add_entry(this); +} + +KeyBinding :: ~KeyBinding() +{ + List_pKeyBindings . delete_entry(this); + + pSCString_ToOutput -> R_Release(); +} + +#if 0 +// static +OurBool +KeyBinding :: bGetKeyForString +( + BindableKey& theKey_Out, + const ProjChar* const pProjCh_In +) +{ + #if KeyBindingUses_WM_KEYDOWN + { + // takes an input string and tries to figure out + // what the corresponding WPARAM would be... + // Returns truth if it manages to get a sensible value + // into the output area. + + GLOBALASSERT( pProjCh_In ); + + #if 1 + theKey_Out = pProjCh_In[0]; + return Yes; + // LOCALISEME + #else + + return No; + // for now + #endif + } + #endif + + #if KeyBindingUses_KEY_ID + { + theKey_Out = KEY_NUMPADDEL; + return Yes; + // for now + } + #endif +} +#endif + +// static +void +KeyBinding :: ErrorDontRecogniseKey( SCString* pSCString_Key ) +{ + GLOBALASSERT( pSCString_Key ); + + SCString* pSCString_1 = new SCString("UNRECOGNISED KEY: \""); + SCString* pSCString_2 = new SCString("\""); + // LOCALISEME + + SCString* pSCString_Feedback = new SCString + ( + pSCString_1, + pSCString_Key, + pSCString_2 + ); + + pSCString_Feedback -> SendToScreen(); + + pSCString_Feedback -> R_Release(); + pSCString_2 -> R_Release(); + pSCString_1 -> R_Release(); +} + +void +KeyBinding :: ListThis(void) const +{ + // used by ListAllBindings() + SCString* pSCString_1 = MakeStringForKey(theKey); + SCString* pSCString_2 = new SCString(" -> \""); + // LOCALISEME + SCString* pSCString_3 = new SCString("\""); + + SCString* pSCString_Feedback = new SCString + ( + pSCString_1, + pSCString_2, + pSCString_ToOutput, + pSCString_3 + ); + + pSCString_Feedback -> SendToScreen(); + + pSCString_Feedback -> R_Release(); + pSCString_3 -> R_Release(); + pSCString_2 -> R_Release(); + pSCString_1 -> R_Release(); + +} + + +static int GetKeyLabel(int inPhysicalKey, TextID& outTextID) +{ + // takes a physical method key and attempts to find a text + // string to use for it, returning whether it does. + // If it fails, output area is untouched + if (inPhysicalKey>=KEY_LEFT && inPhysicalKey<=KEY_MOUSEWHEELDOWN) + { + outTextID = (enum TEXTSTRING_ID) (TEXTSTRING_KEYS_LEFT + (inPhysicalKey-KEY_LEFT)); + return Yes; + } + else return No; + + #if 0 + switch (inPhysicalKey) + { + case KEY_UP: outTextID = TEXTSTRING_KEYS_UP; return Yes; + case KEY_DOWN: outTextID = TEXTSTRING_KEYS_DOWN; return Yes; + case KEY_LEFT: outTextID = TEXTSTRING_KEYS_LEFT; return Yes; + case KEY_RIGHT: outTextID = TEXTSTRING_KEYS_RIGHT; return Yes; + case KEY_CR: outTextID = TEXTSTRING_KEYS_RETURN; return Yes; + case KEY_TAB: outTextID = TEXTSTRING_KEYS_TAB; return Yes; + case KEY_INS: outTextID = TEXTSTRING_KEYS_INSERT; return Yes; + case KEY_DEL: outTextID = TEXTSTRING_KEYS_DELETE; return Yes; + case KEY_END: outTextID = TEXTSTRING_KEYS_END; return Yes; + case KEY_HOME: outTextID = TEXTSTRING_KEYS_HOME; return Yes; + case KEY_PAGEUP: outTextID = TEXTSTRING_KEYS_PGUP; return Yes; + case KEY_PAGEDOWN: outTextID = TEXTSTRING_KEYS_PGDOWN; return Yes; + case KEY_BACKSPACE: outTextID = TEXTSTRING_KEYS_BACKSP; return Yes; + case KEY_COMMA: outTextID = TEXTSTRING_KEYS_COMMA; return Yes; + case KEY_FSTOP: outTextID = TEXTSTRING_KEYS_PERIOD; return Yes; + case KEY_SPACE: outTextID = TEXTSTRING_KEYS_SPACE; return Yes; + case KEY_LMOUSE: outTextID = TEXTSTRING_KEYS_LMOUSE; return Yes; + case KEY_RMOUSE: outTextID = TEXTSTRING_KEYS_RMOUSE; return Yes; + case KEY_LEFTALT: outTextID = TEXTSTRING_KEYS_LALT; return Yes; + case KEY_RIGHTALT: outTextID = TEXTSTRING_KEYS_RALT; return Yes; + case KEY_LEFTCTRL: outTextID = TEXTSTRING_KEYS_LCTRL; return Yes; + case KEY_RIGHTCTRL: outTextID = TEXTSTRING_KEYS_RCTRL; return Yes; + case KEY_LEFTSHIFT: outTextID = TEXTSTRING_KEYS_LSHIFT; return Yes; + case KEY_RIGHTSHIFT: outTextID = TEXTSTRING_KEYS_RSHIFT; return Yes; + case KEY_CAPS: outTextID = TEXTSTRING_KEYS_CAPS; return Yes; + case KEY_NUMLOCK: outTextID = TEXTSTRING_KEYS_NUMLOCK; return Yes; + case KEY_SCROLLOK: outTextID = TEXTSTRING_KEYS_SCRLOCK; return Yes; + case KEY_NUMPAD0: outTextID = TEXTSTRING_KEYS_PAD0; return Yes; + case KEY_NUMPAD1: outTextID = TEXTSTRING_KEYS_PAD1; return Yes; + case KEY_NUMPAD2: outTextID = TEXTSTRING_KEYS_PAD2; return Yes; + case KEY_NUMPAD3: outTextID = TEXTSTRING_KEYS_PAD3; return Yes; + case KEY_NUMPAD4: outTextID = TEXTSTRING_KEYS_PAD4; return Yes; + case KEY_NUMPAD5: outTextID = TEXTSTRING_KEYS_PAD5; return Yes; + case KEY_NUMPAD6: outTextID = TEXTSTRING_KEYS_PAD6; return Yes; + case KEY_NUMPAD7: outTextID = TEXTSTRING_KEYS_PAD7; return Yes; + case KEY_NUMPAD8: outTextID = TEXTSTRING_KEYS_PAD8; return Yes; + case KEY_NUMPAD9: outTextID = TEXTSTRING_KEYS_PAD9; return Yes; + case KEY_NUMPADSUB: outTextID = TEXTSTRING_KEYS_PADSUB; return Yes; + case KEY_NUMPADADD: outTextID = TEXTSTRING_KEYS_PADADD; return Yes; + case KEY_NUMPADDEL: outTextID = TEXTSTRING_KEYS_PADDEL; return Yes; + default: return No; + } + #endif +} + +static SCString* GetMethodString(BindableKey inPhysicalKey) +{ + TextID theTextID; + + if + ( + GetKeyLabel + ( + inPhysicalKey, + theTextID // TextID& outTextID + ) + ) + { + return &StringTable :: GetSCString(theTextID); + } + else + { + ProjChar theProjChar[2]; + + if (inPhysicalKey >= KEY_A && inPhysicalKey <= KEY_Z) + { + theProjChar[0] = ProjChar(int(inPhysicalKey) - KEY_A + 'A'); + } + else if (inPhysicalKey >= KEY_0 && inPhysicalKey <= KEY_9) + { + theProjChar[0] = ProjChar(int(inPhysicalKey) - KEY_0 + '0'); + } + else + { + theProjChar[0] = 0; + } + + theProjChar[1] = 0; + + return new SCString(theProjChar); + } +} + +// static +SCString* +KeyBinding :: MakeStringForKey +( + BindableKey theKey +) +{ + #if KeyBindingUses_WM_KEYDOWN + { + ProjChar tempProjCh[2]; + + tempProjCh[0] = (ProjChar)theKey; + tempProjCh[1] = 0; + // LOCALISEME + + + return new SCString(&tempProjCh[0]); + } + #endif + + #if KeyBindingUses_KEY_ID + { + return GetMethodString(theKey); + } + #endif +} + +// static +OurBool KeyBinding :: ParseBindCommand +( + BindableKey& theKey_Out, + ProjChar** ppProjCh_Out, + // returns where in the input string to continue processing + + ProjChar* pProjCh_In +) +{ + // returns Yes if it understands the binding and fills out the output + + GLOBALASSERT( ppProjCh_Out ); + GLOBALASSERT( pProjCh_In ); + + // Iterate through leading whitespace: + { + while + ( + *pProjCh_In + ) + { + // LOCALISEME: + if (!isspace(*pProjCh_In)) + { + break; + } + pProjCh_In++; + } + } + + // Scan through the string, trying to find matches against strings for keys + // We will use the longest match: + { + OurBool bGotMatch = No; + unsigned int LongestMatch = 0; + + for (int i=0;i GetNumChars(); + + if (LengthOfTestString > 0) + { + if + ( + 0 == _strnicmp + ( + pSCString_TestKey -> pProjCh(), + pProjCh_In, + LengthOfTestString + ) + // LOCALISEME + ) + { + // Then we have a match; see if it's longer than + // what's come before... + if (LengthOfTestString>LongestMatch) + { + LongestMatch = LengthOfTestString; + + theKey_Out = theKey; + *ppProjCh_Out = pProjCh_In + LengthOfTestString; + // Continue processing after the string + bGotMatch = Yes; + + } + } + } + + pSCString_TestKey -> R_Release(); + } + + if (bGotMatch) + { + // Strip away whitespace following the key string: + { + while (**ppProjCh_Out) + { + // LOCALISEME: + if (!isspace(**ppProjCh_Out)) + { + break; + } + (*ppProjCh_Out)++; + } + } + } + + return bGotMatch; + } + +} + + + +// private: +// Maintain a static list of all of objects of the class: +// static +List KeyBinding :: List_pKeyBindings; + +// static +RefList KeyBinding :: PendingList; + +// public: +// static +int KeyBinding :: bEcho = No; + +void CONSBIND_WriteKeyBindingsToConfigFile(void) +{ + #if !(PREDATOR_DEMO|MARINE_DEMO||ALIEN_DEMO||DEATHMATCH_DEMO) + KeyBinding :: WriteToConfigFile("CONFIG.CFG"); + #endif +} + + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/support/consbind.hpp b/3dc/avp/support/consbind.hpp new file mode 100644 index 0000000..5df00be --- /dev/null +++ b/3dc/avp/support/consbind.hpp @@ -0,0 +1,201 @@ +/* + + consbind.hpp + + Created 6/4/98 by DHM: + + Ability to bind strings to a key. When the key is pressed, the string + is passed to the console as if it had been typed. +*/ + +#ifndef _consbind_hpp +#define _consbind_hpp 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + + #ifdef __cplusplus + #ifndef _scstring + #include "scstring.hpp" + #endif + + #ifndef _reflist_hpp + #include "reflist.hpp" + #endif + #endif /* __cplusplus */ + +/* Version settings *****************************************************/ +#ifdef __cplusplus + #define KeyBindingUses_WM_KEYDOWN No + // if this is set to yes, the system works off the WM_KEYDOWN + // messages, which provide a system for getting at the keyboard + // which is guaranteed to work for the codes in pp247-9 of + // Petzold 4th Edition, across all locales. + // It also: + // - debounces for free, then gives a typematic action + // - won't lose keystrokes, even at low framerates + // - provides ordering between all the keystrokes + + #define KeyBindingUses_KEY_ID Yes + // if this is set, the system accesses the KeyboardInput[] array + // in IO.C Currently (7/4/98) this comes from DirectInput, via + // DI_FUNC.CPP + // I have been told that this has the advantage of allowing us to treat + // mouse/joystick buttons in an analagous way. However it has + // the following disadvantages: + // - it will lose keystrokes at low framerates (below 60Hz at the + // rate I type) + // - it loses the ordering of keystrokes that come in the same frame + // - I believe it is locale-dependent; I believe there's no guarantee + // it will remap according to settings in the Control Panel. + // + // There's no debouncing at present. +#endif /* __cplusplus */ + + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ +#ifdef __cplusplus + #if KeyBindingUses_KEY_ID + typedef enum KEY_ID BindableKey; + #endif + + #if KeyBindingUses_WM_KEYDOWN + typedef WPARAM BindableKey; + #endif + + class KeyBinding + { + public: + static void ParseBindCommand + ( + ProjChar* pProjCh_ToParse + ); + static void ParseUnbindCommand + ( + ProjChar* pProjCh_ToParse + ); + + #if 0 + static void AttemptToBind + ( + SCString* pSCString_Key, // description of key + SCString* pSCString_ToBind // string to be bound + ); + static void AttemptToUnbind + ( + SCString* pSCString_Key // description of key + ); + #endif + static void UnbindAll(void); + + static void ListAllBindings(void); + + static void WriteToConfigFile(char* Filename); + // overwrites the file with a batch file that'll + // restore current bindings + // Also destroys all current bindings, so that + // next time into the game you don't get a second + // lot when the config file is processed + + #if KeyBindingUses_WM_KEYDOWN + static void Process_WM_KEYDOWN + ( + WPARAM wParam + ); + #endif + + #if KeyBindingUses_KEY_ID + static void Maintain(void); + #endif + + public: + static int bEcho; + + private: + // Private ctor/dtor; to be called only by static fns of the class: + KeyBinding + ( + BindableKey theKey_ToUse, + SCString* pSCString_ToBind + ); + ~KeyBinding(); + + #if 0 + static OurBool bGetKeyForString + ( + BindableKey& theKey_Out, + const ProjChar* const pProjCh_In + ); + // takes an input string and tries to figure out + // what the corresponding WPARAM would be... + // Returns truth if it manages to get a sensible value + // into the output area. + #endif + + + static void ErrorDontRecogniseKey( SCString* pSCString_Key ); + + void ListThis(void) const; + // used by ListAllBindings() + + static SCString* MakeStringForKey + ( + BindableKey theKey + ); + + static OurBool ParseBindCommand + ( + BindableKey& theKey_Out, + ProjChar** ppProjCh_Out, + // returns where in the input string to continue processing + + ProjChar* pProjCh_In + ); // returns Yes if it understands the binding and fills out the output + + + private: + BindableKey theKey; + SCString* pSCString_ToOutput; + + // Maintain a static list of all of objects of the class: + static List List_pKeyBindings; + + // A list that ought to be local to Process_WM_KEYDOWN() + // and the Maintain() functions + // but has been made static to the class as an optimisation: + static RefList PendingList; + + + }; + // Should the binding be debounced/undebounced? + // Should the string appear to be typed? + + // Algorithm for processing? + + // Perhaps should just look at Windows messages for key down, + // like we should have been doing all along... +#endif /* __cplusplus */ + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + +#ifdef __cplusplus + extern "C" { +#endif + void CONSBIND_WriteKeyBindingsToConfigFile(void); +#ifdef __cplusplus + }; +#endif + + +/* End of the header ****************************************************/ + + + +#endif diff --git a/3dc/avp/support/consbtch.cpp b/3dc/avp/support/consbtch.cpp new file mode 100644 index 0000000..0f137de --- /dev/null +++ b/3dc/avp/support/consbtch.cpp @@ -0,0 +1,217 @@ +/******************************************************************* + * + * DESCRIPTION: consbtch.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 8/4/98 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" + + #include "consbtch.hpp" + #include "reflist.hpp" + + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + + enum + { + MaxBatchFileLineLength=300, + MaxBatchFileLineSize=(MaxBatchFileLineLength+1) + }; + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +// class BatchFileProcessing +// public: +// static +OurBool +BatchFileProcessing :: Run(char* Filename) +{ + // Tries to find the file, if it finds it it reads it, + // adds the non-comment lines to the pending list, and returns Yes + // If it can't find the file, it returns No + + // LOCALISEME + // This code makes several uses of the assumption that char is type-equal + // to ProjChar + + RefList PendingList; + + { + FILE* pFile = fopen(Filename,"r"); + + if (NULL==pFile) + { + return No; + } + + + + // Read the file, line by line. + { + // We impose a maximum length on lines that will be valid: + char LineBuffer[MaxBatchFileLineSize]; + + int CharsReadInLine = 0; + + while (1) + { + int Char = fgetc(pFile); + + if (Char==EOF) + { + break; + } + else + { + if + ( + Char=='\n' + ) + { + // Flush the buffer into the pending queue: + GLOBALASSERT(CharsReadInLine<=MaxBatchFileLineLength); + LineBuffer[CharsReadInLine] = '\0'; + + SCString* pSCString_Line = new SCString(&LineBuffer[0]); + + PendingList . AddToEnd + ( + *pSCString_Line + ); + + pSCString_Line -> R_Release(); + + CharsReadInLine = 0; + } + else + { + // Add to buffer; silently reject characters beyond the length limit + if ( CharsReadInLine < MaxBatchFileLineLength ) + { + LineBuffer[CharsReadInLine++]=toupper((char)Char); + } + } + } + } + + // Flush anything still in the buffer into the pending queue: + { + GLOBALASSERT(CharsReadInLine<=MaxBatchFileLineLength); + LineBuffer[CharsReadInLine] = '\0'; + + SCString* pSCString_Line = new SCString(&LineBuffer[0]); + + PendingList . AddToEnd + ( + *pSCString_Line + ); + + pSCString_Line -> R_Release(); + } + } + + fclose(pFile); + } + + // Feedback: + { + SCString* pSCString_1 = new SCString("EXECUTING BATCH FILE "); + // LOCALISEME + SCString* pSCString_2 = new SCString(Filename); + SCString* pSCString_Feedback = new SCString + ( + pSCString_1, + pSCString_2 + ); + + pSCString_Feedback -> SendToScreen(); + + pSCString_Feedback -> R_Release(); + pSCString_2 -> R_Release(); + pSCString_1 -> R_Release(); + + } + + // Now process the pending queue: + { + // Iterate through the pending list, destructively reading the + // "references" from the front: + { + SCString* pSCString; + + // The assignment in this boolean expression is deliberate: + while + ( + NULL != (pSCString = PendingList . GetYourFirst()) + ) + { + if (pSCString->pProjCh()[0] != '#') + { + // lines beginning with hash are comments + if (bEcho) + { + pSCString -> SendToScreen(); + } + + pSCString -> ProcessAnyCheatCodes(); + } + pSCString -> R_Release(); + } + } + + } + + return Yes; + +} + +// public: +// static +int BatchFileProcessing :: bEcho = No; + + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/support/consbtch.hpp b/3dc/avp/support/consbtch.hpp new file mode 100644 index 0000000..107597d --- /dev/null +++ b/3dc/avp/support/consbtch.hpp @@ -0,0 +1,56 @@ +/* + + consbtch.hpp + + Console batch file support + +*/ + +#ifndef _consbtch +#define _consbtch 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + + #ifndef _scstring + #include "scstring.hpp" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + class BatchFileProcessing + { + public: + static OurBool Run(char* Filename); + // Tries to find the file, if it finds it it reads it, + // adds the non-comment lines to the pending list, and returns Yes + // If it can't find the file, it returns No + + public: + static int bEcho; + }; + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/support/daemon.h b/3dc/avp/support/daemon.h new file mode 100644 index 0000000..7079bbf --- /dev/null +++ b/3dc/avp/support/daemon.h @@ -0,0 +1,152 @@ +/* + + daemon.h + +*/ + +#ifndef _daemon +#define _daemon 1 + +#ifdef __cplusplus + + #ifndef _ourbool + #include "ourbool.h" + #endif + + extern "C" { +#endif + +/* Version settings *****************************************************/ + #define SupportCallbackHooks No + + #define IndividualTiming No + /* + Should daemons get individually passed a time to run for, + or do they all share the same timing information? + */ +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + #if SupportCallbackHooks + #define ACTIVITY_RETURN_TYPE OurBool + + #define ACTIVITY_RVAL_CHANGE {return Yes;} + #define ACTIVITY_RVAL_NOCHANGE {return No;} + #define ACTIVITY_RVAL_BOOL(b) {return b;} + #else + #define ACTIVITY_RETURN_TYPE void + + #define ACTIVITY_RVAL_CHANGE {return;} + #define ACTIVITY_RVAL_NOCHANGE {return;} + #define ACTIVITY_RVAL_BOOL(ignore) {return;} + #endif + + #if IndividualTiming + #define ACTIVITY_INPUT int FixP_Time + #else + #define ACTIVITY_INPUT void + /* note that int FixP_Time is still available to the activity + functions, but in the form of a protected member rather than + an actual parameter + */ + #endif + +/* Type definitions *****************************************************/ + #ifdef __cplusplus + class Daemon; + + #if SupportCallbackHooks + class CallbackHook + { + public: + virtual void OnActivity(void) = 0; + + CallbackHook + ( + Daemon* p666_New, + void* pUser_New + ); + virtual ~CallbackHook(); + + // ought to be private: + CallbackHook* pNxtHook; + CallbackHook* pPrvHook; + Daemon* p666_Val; + void* pUser_Val; + + + }; + #endif // SupportCallbackHooks + + class Daemon + { + // Constructors etc: + public: + Daemon + ( + OurBool fActive + ); + + virtual ~Daemon(); + + // Per object stuff: + public: + void Start(void); + void Stop(void); + void SetActive(OurBool fActive); + OurBool bActive(void) const; + + virtual ACTIVITY_RETURN_TYPE Activity(ACTIVITY_INPUT) = 0; + // the strategy to run when active; returns Yes if linked screen objects/gadgets will + // need updating + + #if SupportCallbackHooks + void ForceHookActivity(void); + // a way to call the OnActivity() method for all attached hooks + #endif + + // Static stuff: + public: + static Daemon* p666_FirstActive; + static Daemon* p666_Iteration_Current; + static Daemon* p666_Iteration_Next; + + static void Maintain(int FixP_Time); + + static int DaemonTimeScale; + + // Private stuff: + private: + OurBool fIsActive_Val; + Daemon* p666_NextActive; // only valid if fIsActive + Daemon* p666_PrevActive; // only valid if fIsActive + + + #if !IndividualTiming + protected: + // if all Daemon activity calls share one timing; this is it: + static int FixP_Time; + #endif + + #if SupportCallbackHooks + public: // but probably ought to be private: + CallbackHook* pFirstHook; + #endif + }; + #endif // ifdef __cplusplus + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + extern void DAEMON_Init(void); + extern void DAEMON_Maintain(void); + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/support/dcontext.hpp b/3dc/avp/support/dcontext.hpp new file mode 100644 index 0000000..9ef1897 --- /dev/null +++ b/3dc/avp/support/dcontext.hpp @@ -0,0 +1,60 @@ +/* + + DCONTEXT.HPP + + Created 14/1/98 by DHM: + + Dump-contexts for use by debugging routines. + + The idea is that debug-dump routines take a reference + to one of these, signifying how they should output; + these are in separate headers to avoid dependencies. + + There are derived classes for the screen and for log files. + + Analagous to the class CDumpContext in Microsoft's MFC. + +*/ + +#ifndef _dcontext +#define _dcontext 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + class R_DumpContext + { + public: + virtual int dputs(char const * const buf) = 0; + virtual int dprintf(char const * format, ... ) = 0; + virtual int vdprintf(char const * format, va_list ap ) = 0; + }; + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif + + diff --git a/3dc/avp/support/expvar.hpp b/3dc/avp/support/expvar.hpp new file mode 100644 index 0000000..a440c8d --- /dev/null +++ b/3dc/avp/support/expvar.hpp @@ -0,0 +1,147 @@ +/* + + expvar.hpp + + Template for variable with pure virtual get/set methods + (I believe Borland's Delphi calls them "properties") + + Handy for setting up e.g. selection items in the menu system + + I've called them ExportVariables + +*/ + +#ifndef _expvar_hpp +#define _expvar_hpp 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + +#ifdef __cplusplus +#endif // __cplusplus + +/* Type definitions *****************************************************/ +template class ExportVariable +{ +protected: + ExportVariable() + { + } + +public: + virtual T Get(void) const = 0; + virtual void Set(T NewVal) = 0; + +}; + +// Similar to an ExportVariable, but has boundary values defined. +// Can only be instantiated for types with ordering +template class BoundedExportVariable +{ +protected: + BoundedExportVariable + ( + T minVal_New, + T maxVal_New + ) : minVal(minVal_New), + maxVal(maxVal_New) + { + } + +private: + // This virtual function is private; it's only accessible within this class + // although it must be overridden by derived classes + virtual void Implement_Set(T NewVal) = 0; + +public: + virtual T Get(void) const = 0; + + T GetMin(void) const + { + return minVal; + } + T GetMax(void) const + { + return maxVal; + } + void Set(T NewVal) + { + // Check bounds, reject if outside. Otherwise call pure virtual fn + // (which doesn't need to bother checking) + if (NewValmaxVal) return; + Implement_Set(NewVal); + } + + +private: + const T minVal; + const T maxVal; +}; + +// An export var with empty "get/""set" hooks: +template class SimpleExportVariable : public ExportVariable +{ +public: + SimpleExportVariable + ( + T& aT + ) : theT(aT), + ExportVariable() + { + } + + T Get(void) const + { + return theT; + } + void Set(T NewVal) + { + theT = NewVal; + } + +protected: + T& theT; + +}; + +// A bounded export var with empty "get/""set" hooks: +template class SimpleBoundedExportVariable : public BoundedExportVariable +{ +public: + SimpleBoundedExportVariable + ( + T& aT, + T minVal_New, + T maxVal_New + ) : theT(aT), + BoundedExportVariable + ( + minVal_New, + maxVal_New + ) + { + } + + T Get(void) const + { + return theT; + } + + void Implement_Set(T NewVal) + { + theT = NewVal; + } + +private: + T& theT; + + +}; + +/* End of the header ****************************************************/ + + + +#endif diff --git a/3dc/avp/support/indexfnt.cpp b/3dc/avp/support/indexfnt.cpp new file mode 100644 index 0000000..5d686e6 --- /dev/null +++ b/3dc/avp/support/indexfnt.cpp @@ -0,0 +1,1336 @@ +/******************************************************************* + * + * DESCRIPTION: indexfnt.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 18/11/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "inline.h" +#include "indexfnt.hpp" +#include "tallfont.hpp" + +extern "C" +{ + #include "d3d_hud.h" +}; + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + #define Use_BLT No + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ +extern void D3D_RenderHUDString(char *stringPtr,int x,int y,int colour); +extern void D3D_RenderHUDString_Clipped(char *stringPtr,int x,int y,int colour); + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + extern unsigned char *ScreenBuffer; + extern long BackBufferPitch; + extern LPDIRECTDRAWSURFACE lpDDSBack; + extern DDPIXELFORMAT DisplayPixelFormat; + extern int CloudTable[128][128]; + extern int CloakingPhase; + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + /*static*/ IndexedFont* IndexedFont :: pIndexedFont[ IndexedFonts_MAX_NUMBER_OF_FONTS ]; + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +// class IndexedFont +// public: +/*static*/ void IndexedFont :: UnloadFont( FontIndex I_Font_ToGet ) +{ + + // there must be a font loaded in that slot + + /* PRECONDITION */ + { + GLOBALASSERT( pIndexedFont[I_Font_ToGet ] ); + } + + /* CODE */ + { + IndexedFont* pDelete = pIndexedFont[I_Font_ToGet ]; + + pIndexedFont[ I_Font_ToGet ] = NULL; + + delete pDelete; + } +} + +/*virtual*/ IndexedFont :: ~IndexedFont() +{ + // Inform the SCString code there's been a change... + SCString :: UpdateAfterFontChange( I_Font_Val ); + + pIndexedFont[ I_Font_Val ] = NULL; +} + + +OurBool IndexedFont :: bCanRenderFully( ProjChar* pProjCh ) +{ + // returns true iff all characters in the string are renderable by the font + + // Assumes one byte-per-character: + while ( *pProjCh ) + { + if + ( + !bCanRender( *pProjCh ) + ) + { + return No; + } + + pProjCh++; + } + + return Yes; +} + +#if debug +void IndexedFont :: Render_Clipped_Report +( + const struct r2pos& R2Pos_Cursor, + const struct r2rect& R2Rect_Clip, + int,// FixP_Alpha, + const SCString& SCStr +) const +{ + textprint + ( + "IndexedFont(%i)::RenderString_Clipped() at(%i,%i) clip(%i,%i,%i,%i) \"%s\"\n", + I_Font_Val, + R2Pos_Cursor . x, + R2Pos_Cursor . y, + R2Rect_Clip . x0, + R2Rect_Clip . y0, + R2Rect_Clip . x1, + R2Rect_Clip . y1, + SCStr . pProjCh() + ); +} +#endif + + +// protected: +// Protected constructor since abstract class +IndexedFont :: IndexedFont +( + FontIndex I_Font_New +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( I_Font_New < IndexedFonts_MAX_NUMBER_OF_FONTS ); + } + + /* CODE */ + { + I_Font_Val = I_Font_New; + + pIndexedFont[ I_Font_New ] = this; + } +} + + +// private: + +#if 1 +// class IndexedFont_Proportional : public IndexedFont +// public: +void IndexedFont_Proportional :: RenderString_Clipped +( + struct r2pos& R2Pos_Cursor, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha,// FixP_Alpha, + const SCString& SCStr +) const +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + #if 0 + Render_Clipped_Report + ( + R2Pos_Cursor, + R2Rect_Clip, + FixP_Alpha, + SCStr + ); + #endif + + ProjChar* pProjChar_I = SCStr . pProjCh(); + + while ( *pProjChar_I ) + { + const ProjChar ProjCh = *pProjChar_I; + + if + ( + bCanRender( ProjCh ) + ) + { + #if 0 + textprint("printable \'%c\'\n",ProjCh); + #endif + + #if 1 + // Rewritten by DHM 18/3/98 to use the single character renderer: + RenderChar_Clipped + ( + R2Pos_Cursor, + R2Rect_Clip, + FixP_Alpha, + ProjCh + ); + #else + // For the moment, only render characters that are fully on-screen: + if + ( + r2rect + ( + R2Pos_Cursor, + GetWidth(ProjCh), + GetHeight() + ) . bFitsIn( R2Rect_Clip ) + ) + { + #if Use_BLT + R2Pos_Cursor . x += 1+BLTFontOffsetToHUD + ( + pffont_Val, // PFFONT* font, + R2Pos_Cursor . x, // int xdest, + R2Pos_Cursor . y, // int ydest, + pffont_Val -> ProjCharToOffset( ProjCh ) // int offset + ); + #else + textprintXY + ( + R2Pos_Cursor . x, + R2Pos_Cursor . y, + "%c", ProjCh + ); + R2Pos_Cursor . x += 1+GetWidth(ProjCh); + #endif + // appears to return the width of the character... + } + else + { + R2Pos_Cursor . x += GetWidth( ProjCh ); + } + #endif + } + else + { + #if 0 + textprint("unprintable \'%c\'\n",ProjCh); + #endif + } + + pProjChar_I++; + } + } +} + +void IndexedFont_Proportional :: RenderString_Unclipped +( + struct r2pos& R2Pos_Cursor, + int FixP_Alpha, // FixP_Alpha, + const SCString& SCStr +) const +{ + { + ProjChar* pProjChar_I = SCStr . pProjCh(); + + while ( *pProjChar_I ) + { + const ProjChar ProjCh = *pProjChar_I; + + if + ( + bCanRender( ProjCh ) + ) + { + #if 0 + textprint("printable \'%c\'\n",ProjCh); + #endif + + #if 1 + // Rewritten by DHM 18/3/98 to use the single character renderer: + RenderChar_Unclipped + ( + R2Pos_Cursor, + FixP_Alpha, + ProjCh + ); + #else + #if Use_BLT + R2Pos_Cursor . x += 1+BLTFontOffsetToHUD + ( + pffont_Val, // PFFONT* font, + R2Pos_Cursor . x, // int xdest, + R2Pos_Cursor . y, // int ydest, + pffont_Val -> ProjCharToOffset( ProjCh ) // int offset + ); + // appears to return the width of the character... + #else + textprintXY + ( + R2Pos_Cursor . x, + R2Pos_Cursor . y, + "%c", ProjCh + ); + R2Pos_Cursor . x += 1+GetWidth(ProjCh); + #endif + #endif + + } + else + { + #if 0 + textprint("unprintable \'%c\'\n",ProjCh); + #endif + } + + pProjChar_I++; + } + } +} + + +r2size IndexedFont_Proportional :: CalcSize +( + ProjChar* pProjCh +) const +{ + GLOBALASSERT( pProjCh ); + + r2size R2Size_Return + ( + 0, + GetHeight() + ); + + if (*pProjCh) + { + // non-empty strings have one pixel space between characters; the if/do/while + // construction is to take one off the final result for a non-empty string + do + { + R2Size_Return . w += GetWidth( *pProjCh ) + 1; + + pProjCh++; + } while (*pProjCh); + + R2Size_Return . w --; + } + + return R2Size_Return; +} + +r2size IndexedFont_Proportional :: CalcSize +( + ProjChar* pProjCh, + int MaxChars +) const +{ + GLOBALASSERT( pProjCh ); + GLOBALASSERT( MaxChars >= 0 ); + + r2size R2Size_Return + ( + 0, + GetHeight() + ); + + if + ( + (*pProjCh) + && + (MaxChars>0) + ) + { + // non-empty strings have one pixel space between characters; the if/do/while + // construction is to take one off the final result for a non-empty string + do + { + R2Size_Return . w += GetWidth( *pProjCh ) + 1; + + pProjCh++; + } while + ( + (*pProjCh) + && + (--MaxChars>0) + ); + + R2Size_Return . w --; + } + + return R2Size_Return; +} + +#endif + +// class IndexedFont_Kerned : public IndexedFont +// public: +void +IndexedFont_Kerned :: RenderString_Clipped +( + struct r2pos& R2Pos_Cursor, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha, + const SCString& SCStr +) const +{ + ProjChar* pProjChar_I = SCStr . pProjCh(); + + const LPDIRECTDRAWSURFACE image_ptr = GetImagePtr(); + + DDSURFACEDESC ddsdimage; + + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdimage.dwSize = sizeof(ddsdimage); + + /* lock the image */ + while (image_ptr->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + while ( *pProjChar_I ) + { + const ProjChar ProjCh = *pProjChar_I; + + if + ( + bCanRender( ProjCh ) + ) + { + #if 0 + textprint("printable \'%c\'\n",ProjCh); + #endif + + #if 0 + RenderChar_Clipped + ( + R2Pos_Cursor, + R2Rect_Clip, + FixP_Alpha, + ProjCh + ); + #else + if (ProjCh != ' ') + { + unsigned int theOffset=ProjCh - 32; + int width = GetWidth(ProjCh); + + /* + if + ( + GetOffset + ( + theOffset, + ProjCh + ) + ) + */ + { + if + ( + width>0 + ) + { + { + // This code adapted from DrawGraphicWithAlphaChannel(); + // it assumes you're in a 16-bit mode... + + // okay, now we have the surfaces, we can copy from one to the other, + // darkening pixels as we go + { + long fontimagePitchInShorts = (ddsdimage.lPitch/2); + long backbufferPitchInShorts = (BackBufferPitch/2); + + unsigned short* fontimageRowStartPtr = + ( + ((unsigned short *)ddsdimage.lpSurface) + + + (GetHeight()*theOffset*fontimagePitchInShorts) + ); + + unsigned short* backbufferRowStartPtr = + ( + ((unsigned short *)ScreenBuffer) + + + (R2Pos_Cursor.y*backbufferPitchInShorts) + + + (R2Pos_Cursor.x) + ); + int screenY = R2Pos_Cursor.y; + + for (int yCount=GetHeight(); yCount>0; yCount--) + { + unsigned short* fontimagePtr = fontimageRowStartPtr; + unsigned short* backbufferPtr = backbufferRowStartPtr; + + if (screenY >= R2Rect_Clip.y0 && screenY <= R2Rect_Clip.y1) + for (int xCount=width; xCount>0;xCount--) + { + int r = CloudTable[(xCount+R2Pos_Cursor.x+CloakingPhase/64)&127][(screenY+CloakingPhase/128)&127]; + // b += CloudTable[((xCount+R2Pos_Cursor.x)/2-CloakingPhase/96)&127][((yCount+R2Pos_Cursor.y)/4+CloakingPhase/64)&127]/4; + // b += CloudTable[((xCount+R2Pos_Cursor.x+10)/4-CloakingPhase/64)&127][((yCount+R2Pos_Cursor.y-50)/8+CloakingPhase/32)&127]/8; + // if (b>ONE_FIXED) b = ONE_FIXED; + r = MUL_FIXED(FixP_Alpha,r); + if (*fontimagePtr) + { + unsigned int backR = (int)(*backbufferPtr) & DisplayPixelFormat.dwRBitMask; + unsigned int backG = (int)(*backbufferPtr) & DisplayPixelFormat.dwGBitMask; + unsigned int backB = (int)(*backbufferPtr) & DisplayPixelFormat.dwBBitMask; + + unsigned int fontR = (int)(*fontimagePtr) & DisplayPixelFormat.dwRBitMask; + unsigned int fontG = (int)(*fontimagePtr) & DisplayPixelFormat.dwGBitMask; + unsigned int fontB = (int)(*fontimagePtr) & DisplayPixelFormat.dwBBitMask; + + backR += MUL_FIXED(r,fontR); + if (backR>DisplayPixelFormat.dwRBitMask) backR = DisplayPixelFormat.dwRBitMask; + else backR &= DisplayPixelFormat.dwRBitMask; + + backG += MUL_FIXED(r,fontG); + if (backG>DisplayPixelFormat.dwGBitMask) backG = DisplayPixelFormat.dwGBitMask; + else backG &= DisplayPixelFormat.dwGBitMask; + + backB += MUL_FIXED(r,fontB); + if (backB>DisplayPixelFormat.dwBBitMask) backB = DisplayPixelFormat.dwBBitMask; + else backB &= DisplayPixelFormat.dwBBitMask; + + *backbufferPtr = (short)(backR|backG|backB); + } + fontimagePtr++; + backbufferPtr++; + } + screenY++; + fontimageRowStartPtr += fontimagePitchInShorts; + backbufferRowStartPtr += backbufferPitchInShorts; + } + } + + } + } + } + } + + #endif + } + else + { + #if 0 + textprint("unprintable \'%c\'\n",ProjCh); + #endif + } + + R2Pos_Cursor . x += 1+GetXInc + ( + ProjCh, + *(pProjChar_I+1) + ); + // this takes responsibility for updating cursor pos, + // rather than the RenderChar function + + pProjChar_I++; + } + image_ptr->Unlock((LPVOID)ddsdimage.lpSurface); +} + +void +IndexedFont_Kerned :: RenderString_Unclipped +( + struct r2pos& R2Pos_Cursor, + int FixP_Alpha, + const SCString& SCStr +) const +#if 1 +{ + ProjChar* pProjChar_I = SCStr . pProjCh(); + + const LPDIRECTDRAWSURFACE image_ptr = GetImagePtr(); + + DDSURFACEDESC ddsdimage; + + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdimage.dwSize = sizeof(ddsdimage); + + /* lock the image */ + while (image_ptr->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + while ( *pProjChar_I ) + { + const ProjChar ProjCh = *pProjChar_I; + + if + ( + bCanRender( ProjCh ) + ) + { + #if 0 + textprint("printable \'%c\'\n",ProjCh); + #endif + + #if 0 + RenderChar_Clipped + ( + R2Pos_Cursor, + R2Rect_Clip, + FixP_Alpha, + ProjCh + ); + #else + if (ProjCh != ' ') + { + unsigned int theOffset=ProjCh - 32; + int width = GetWidth(ProjCh); + + /* + if + ( + GetOffset + ( + theOffset, + ProjCh + ) + ) + */ + { + if + ( + width>0 + ) + { + { + // This code adapted from DrawGraphicWithAlphaChannel(); + // it assumes you're in a 16-bit mode... + + // okay, now we have the surfaces, we can copy from one to the other, + // darkening pixels as we go + { + long fontimagePitchInShorts = (ddsdimage.lPitch/2); + long backbufferPitchInShorts = (BackBufferPitch/2); + + unsigned short* fontimageRowStartPtr = + ( + ((unsigned short *)ddsdimage.lpSurface) + + + (GetHeight()*theOffset*fontimagePitchInShorts) + ); + + unsigned short* backbufferRowStartPtr = + ( + ((unsigned short *)ScreenBuffer) + + + (R2Pos_Cursor.y*backbufferPitchInShorts) + + + (R2Pos_Cursor.x) + ); + int screenY = R2Pos_Cursor.y; + + for (int yCount=GetHeight(); yCount>0; yCount--) + { + unsigned short* fontimagePtr = fontimageRowStartPtr; + unsigned short* backbufferPtr = backbufferRowStartPtr; + + int xIndex = R2Pos_Cursor.x+CloakingPhase/64; + int yIndex = (screenY+CloakingPhase/128)&127; + +// if (screenY >= R2Rect_Clip.y0 && screenY <= R2Rect_Clip.y1) + for (int xCount=width; xCount>0;xCount--) + { + int r = CloudTable[(xCount+xIndex)&127][yIndex]; + // b += CloudTable[((xCount+R2Pos_Cursor.x)/2-CloakingPhase/96)&127][((yCount+R2Pos_Cursor.y)/4+CloakingPhase/64)&127]/4; + // b += CloudTable[((xCount+R2Pos_Cursor.x+10)/4-CloakingPhase/64)&127][((yCount+R2Pos_Cursor.y-50)/8+CloakingPhase/32)&127]/8; + // if (b>ONE_FIXED) b = ONE_FIXED; + r = MUL_FIXED(FixP_Alpha,r); + //int r = FixP_Alpha; + if (*fontimagePtr) + { + unsigned int backR = (int)(*backbufferPtr) & DisplayPixelFormat.dwRBitMask; + unsigned int backG = (int)(*backbufferPtr) & DisplayPixelFormat.dwGBitMask; + unsigned int backB = (int)(*backbufferPtr) & DisplayPixelFormat.dwBBitMask; + + unsigned int fontR = (int)(*fontimagePtr) & DisplayPixelFormat.dwRBitMask; + unsigned int fontG = (int)(*fontimagePtr) & DisplayPixelFormat.dwGBitMask; + unsigned int fontB = (int)(*fontimagePtr) & DisplayPixelFormat.dwBBitMask; + + backR += MUL_FIXED(r,fontR); + if (backR>DisplayPixelFormat.dwRBitMask) backR = DisplayPixelFormat.dwRBitMask; + else backR &= DisplayPixelFormat.dwRBitMask; + + backG += MUL_FIXED(r,fontG); + if (backG>DisplayPixelFormat.dwGBitMask) backG = DisplayPixelFormat.dwGBitMask; + else backG &= DisplayPixelFormat.dwGBitMask; + + backB += MUL_FIXED(r,fontB); + if (backB>DisplayPixelFormat.dwBBitMask) backB = DisplayPixelFormat.dwBBitMask; + else backB &= DisplayPixelFormat.dwBBitMask; + + *backbufferPtr = (short)(backR|backG|backB); + } + fontimagePtr++; + backbufferPtr++; + } + screenY++; + fontimageRowStartPtr += fontimagePitchInShorts; + backbufferRowStartPtr += backbufferPitchInShorts; + } + } + + } + } + } + } + + #endif + } + else + { + #if 0 + textprint("unprintable \'%c\'\n",ProjCh); + #endif + } + + R2Pos_Cursor . x += 1+GetXInc + ( + ProjCh, + *(pProjChar_I+1) + ); + // this takes responsibility for updating cursor pos, + // rather than the RenderChar function + + pProjChar_I++; + } + image_ptr->Unlock((LPVOID)ddsdimage.lpSurface); +} +#else +{ + /* PRECONDITION */ + #if 0 + { + // Check it's already been properly clipped: + // (using direct calculation of string sizes) + GLOBALASSERT + ( + r2rect + ( + R2Pos_Cursor, + CalcSize( SCStr . pProjCh() ) + ) . bValidPhys() + ); + } + #endif + /* CODE */ + { + ProjChar* pProjChar_I = SCStr . pProjCh(); + + while ( *pProjChar_I ) + { + const ProjChar ProjCh = *pProjChar_I; + + if + ( + bCanRender( ProjCh ) + ) + { + #if 0 + textprint("printable \'%c\'\n",ProjCh); + #endif +#if 1 + RenderChar_Unclipped + ( + R2Pos_Cursor, + FixP_Alpha, + ProjCh + ); +#endif + } + else + { + #if 0 + textprint("unprintable \'%c\'\n",ProjCh); + #endif + } + + R2Pos_Cursor . x += 1+GetXInc + ( + ProjCh, + *(pProjChar_I+1) + ); + // this takes responsibility for updating cursor pos, + // rather than the RenderChar function + + pProjChar_I++; + } + } +} +#endif + +// The string CalcSize() functions are implemented at this level +// For this class, it's not just done by adding together the sizes for +// the characters: +r2size +IndexedFont_Kerned :: CalcSize +( + ProjChar* pProjCh +) const +{ + GLOBALASSERT(pProjCh); + + r2size R2Size_Return + ( + 0, + GetHeight() + ); + + while (*pProjCh) + { + R2Size_Return . w += 1+GetXInc + ( + *(pProjCh), + *(pProjCh+1) + ); + // note how the final non-null character has a call to GetXInc + // with the null character as its successor + + pProjCh++; + } + + return R2Size_Return; +} + +r2size +IndexedFont_Kerned :: CalcSize +( + ProjChar* pProjCh, + int MaxChars +) const +{ + GLOBALASSERT(pProjCh); + GLOBALASSERT( MaxChars >=0 ); + + r2size R2Size_Return + ( + 0, + GetHeight() + ); + + while + ( + (*pProjCh) + && + ((MaxChars--)>0) + ) + { + R2Size_Return . w += 1+GetXInc + ( + *(pProjCh), + *(pProjCh+1) + ); + // note how the final non-null character has a call to GetXInc + // with the null character as its successor + + pProjCh++; + } + + return R2Size_Return; +} + + +void IndexedFont_Proportional_PF :: RenderChar_Clipped +( + struct r2pos& R2Pos_Cursor, + const struct r2rect& R2Rect_Clip, + int, // FixP_Alpha, + ProjChar ProjCh +) const +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + if + ( + bCanRender( ProjCh ) + ) + { + #if 0 + textprint("printable \'%c\'\n",ProjCh); + #endif + // For the moment, only render characters that are fully on-screen: + if + ( + r2rect + ( + R2Pos_Cursor, + GetWidth(ProjCh), + GetHeight() + ) . bFitsIn( R2Rect_Clip ) + ) + { + #if Use_BLT + R2Pos_Cursor . x += 1+BLTFontOffsetToHUD + ( + pffont_Val, // PFFONT* font, + R2Pos_Cursor . x, // int xdest, + R2Pos_Cursor . y, // int ydest, + pffont_Val -> ProjCharToOffset( ProjCh ) // int offset + ); + // appears to return the width of the character... + #else + textprintXY + ( + R2Pos_Cursor . x, + R2Pos_Cursor . y, + "%c", ProjCh + ); + R2Pos_Cursor . x += 1+GetWidth(ProjCh); + #endif + } + else + { + R2Pos_Cursor . x += GetWidth( ProjCh ); + } + } + else + { + #if 0 + textprint("unprintable \'%c\'\n",ProjCh); + #endif + } + } +} + +void IndexedFont_Proportional_PF :: RenderChar_Unclipped +( + struct r2pos& R2Pos_Cursor, + int, // FixP_Alpha, + ProjChar ProjCh +) const +{ + /* PRECONDITION */ + #if 1 + { + // Check it's already been properly clipped: + // (using direct calculation of char size) + GLOBALASSERT + ( + r2rect + ( + R2Pos_Cursor, + CalcSize( ProjCh ) + ) . bValidPhys() + ); + } + #endif + /* CODE */ + { + if + ( + bCanRender( ProjCh ) + ) + { + #if 0 + textprint("printable \'%c\'\n",ProjCh); + #endif + + #if Use_BLT + R2Pos_Cursor . x += 1+BLTFontOffsetToHUD + ( + pffont_Val, // PFFONT* font, + R2Pos_Cursor . x, // int xdest, + R2Pos_Cursor . y, // int ydest, + pffont_Val -> ProjCharToOffset( ProjCh ) // int offset + ); + // appears to return the width of the character... + #else + textprintXY + ( + R2Pos_Cursor . x, + R2Pos_Cursor . y, + "%c", ProjCh + ); + R2Pos_Cursor . x += 1+GetWidth(ProjCh); + #endif + } + else + { + #if 0 + textprint("unprintable \'%c\'\n",ProjCh); + #endif + } + } +} + + +/*static*/ void IndexedFont_Proportional_PF :: PFLoadHook +( + FontIndex I_Font_New, + PFFONT *pffont_New +) +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + new IndexedFont_Proportional_PF + ( + I_Font_New, + pffont_New + ); + + SCString :: UpdateAfterFontChange( I_Font_New ); + } +} + +/*static*/ void IndexedFont_Proportional_PF :: PFUnLoadHook +( + FontIndex // I_Font_Old +) +{ + #if 0 + delete + SCString :: UpdateAfterFontChange( I_Font_Old ); + #endif +} + +// private: +IndexedFont_Proportional_PF :: IndexedFont_Proportional_PF +( + FontIndex I_Font_New, + PFFONT *pffont_New +) : IndexedFont_Proportional + ( + I_Font_New + ), + MaxWidth_Val(0) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pffont_New ); + } + + /* CODE */ + { + pffont_Val = pffont_New; + + // Calculate MaxWidth_Val: + int i=(pffont_New -> num_chars_in_font); + int Offset = pffont_New -> GetOffset(); + + while (i>0) + { + i--; + + int ThisWidth = pffont_Val -> GetWidth + ( + (ProjChar) (i + Offset ) + ); + if ( MaxWidth_Val < ThisWidth) + { + MaxWidth_Val = ThisWidth; + } + } + + } +} + + + + +void INDEXFNT_PFLoadHook +( + FontIndex I_Font_New, + PFFONT *pffont_New +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( I_Font_New < IndexedFonts_MAX_NUMBER_OF_FONTS ); + GLOBALASSERT( pffont_New ); + } + + /* CODE */ + { + IndexedFont_Proportional_PF :: PFLoadHook + ( + I_Font_New, + pffont_New // PFFONT *pffont_New + ); + + } +} + + +void IndexedFont_HUD :: RenderString_Clipped +( + struct r2pos& R2Pos_Cursor, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha,// FixP_Alpha, + const SCString& SCStr +) const +{ + /* KJL 16:16:26 16/04/98 - if you're completely off-screen, go away */ + if (R2Pos_Cursor . y<=-HUD_FONT_HEIGHT) return; + + { + ProjChar* pProjChar_I = SCStr . pProjCh(); + + if (R2Pos_Cursor . y<=0) + { + D3D_RenderHUDString_Clipped(pProjChar_I,R2Pos_Cursor.x,R2Pos_Cursor.y,(255<<24)+(192<<16)+(192<<8)+(192)); + } + else + #if 0 + { + HUDCharDesc charDesc; + charDesc.Y = R2Pos_Cursor . y; + + charDesc.Red = 192; + charDesc.Green = 192; + charDesc.Blue = 192; + charDesc.Alpha= 255; + + while ( *pProjChar_I ) + { + const ProjChar ProjCh = *pProjChar_I; + + charDesc.Character=ProjCh; + charDesc.X = R2Pos_Cursor . x; + D3D_DrawHUDFontCharacter(&charDesc); + + R2Pos_Cursor . x += 1+GetWidth(ProjCh); + pProjChar_I++; + } + } + #else + D3D_RenderHUDString(pProjChar_I,R2Pos_Cursor.x,R2Pos_Cursor.y,(255<<24)+(192<<16)+(192<<8)+(192)); + #endif + } +} + +void IndexedFont_HUD :: RenderString_Unclipped +( + struct r2pos& R2Pos_Cursor, + int FixP_Alpha, // FixP_Alpha, + const SCString& SCStr +) const +{ + LOCALASSERT(0); +} + + +r2size IndexedFont_HUD :: CalcSize +( + ProjChar* pProjCh +) const +{ + GLOBALASSERT( pProjCh ); + + r2size R2Size_Return + ( + 0, + GetHeight() + ); + + if (*pProjCh) + { + // non-empty strings have one pixel space between characters; the if/do/while + // construction is to take one off the final result for a non-empty string + do + { + R2Size_Return . w += GetWidth( *pProjCh ) + 1; + + pProjCh++; + } while (*pProjCh); + + R2Size_Return . w --; + } + + return R2Size_Return; +} +#if 0 +r2size IndexedFont_HUD :: CalcSize +( + ProjChar* pProjCh, + int MaxChars +) const +{ + GLOBALASSERT( pProjCh ); + GLOBALASSERT( MaxChars >= 0 ); + + r2size R2Size_Return + ( + 0, + GetHeight() + ); + + if + ( + (*pProjCh) + && + (MaxChars>0) + ) + { + // non-empty strings have one pixel space between characters; the if/do/while + // construction is to take one off the final result for a non-empty string + do + { + R2Size_Return . w += GetWidth( *pProjCh ) + 1; + + pProjCh++; + } while + ( + (*pProjCh) + && + (--MaxChars>0) + ); + + R2Size_Return . w --; + } + + return R2Size_Return; +} +#endif +void IndexedFont_HUD :: RenderChar_Clipped +( + struct r2pos& R2Pos_Cursor, + const struct r2rect& R2Rect_Clip, + int, // FixP_Alpha, + ProjChar ProjCh +) const +{ + HUDCharDesc charDesc; + charDesc.Y = R2Pos_Cursor . y; + + charDesc.Red = 255; + charDesc.Green = 255; + charDesc.Blue = 255; + charDesc.Alpha= 255; + + charDesc.Character=ProjCh; + charDesc.X = R2Pos_Cursor . x; + D3D_DrawHUDFontCharacter(&charDesc); + R2Pos_Cursor . x += GetWidth(ProjCh); +} + +void IndexedFont_HUD :: RenderChar_Unclipped +( + struct r2pos& R2Pos_Cursor, + int, // FixP_Alpha, + ProjChar ProjCh +) const +{ + /* PRECONDITION */ + { + // Check it's already been properly clipped: + // (using direct calculation of char size) + GLOBALASSERT + ( + r2rect + ( + R2Pos_Cursor, + CalcSize( ProjCh ) + ) . bValidPhys() + ); + } + + /* CODE */ + { + { + + HUDCharDesc charDesc; + charDesc.Character=ProjCh; + charDesc.X = R2Pos_Cursor . x; + charDesc.Y = R2Pos_Cursor . y; + + charDesc.Red = FastRandom()&255; + charDesc.Green = FastRandom()&255; + charDesc.Blue = FastRandom()&255; + charDesc.Alpha=255; + + D3D_DrawHUDFontCharacter(&charDesc); + + R2Pos_Cursor . x += 1+GetWidth(ProjCh); + } + #if 0 + else + { + R2Pos_Cursor . x += GetWidth( ProjCh ); + } + #endif + } +} + +/* Internal function definitions ***********************************/ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/3dc/avp/support/indexfnt.hpp b/3dc/avp/support/indexfnt.hpp new file mode 100644 index 0000000..5afa66a --- /dev/null +++ b/3dc/avp/support/indexfnt.hpp @@ -0,0 +1,540 @@ +/* + + indexfnt.hpp + + Created 19/11/97 by DHM : An "indexed font" type; it is assumed that + there is a maximum number of possible fonts that the program can have + installed, with an enum for accessing the different fonts (as opposed + to a system allowing arbitrary numbers of fonts to be loaded at run-time). + + Expects an enum "FontIndex" for the font to be defined in PROJFONT.H + + + (haven't worked out what happens for colour information/selection) +*/ + +#ifndef _indexfnt +#define _indexfnt 1 + + #ifndef _projfont + #include "projfont.h" + #endif + + #ifndef _r2base + #include "r2base.h" + #endif + +#ifdef __cplusplus + + #ifndef _scstring + #include "scstring.hpp" + #endif + +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ +#include "HUD_layout.h" +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + #ifdef __cplusplus + class IndexedFont + { + public: + static IndexedFont* GetFont( FontIndex I_Font_ToGet ); + // can return NULL if no font loaded in that slot + + static void UnloadFont( FontIndex I_Font_ToGet ); + // there must be a font loaded in that slot + + virtual ~IndexedFont(); + + virtual void RenderString_Clipped + ( + struct r2pos& R2Pos_Cursor, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha, + const SCString& SCStr + ) const = 0; + // unsupported characters come out invisible, they may or may not affect + // the spacing/size depending on implementation + // the cursor pos is used for both input and output; the function returns + // the next position after the string for rendering further text + + virtual void RenderString_Unclipped + ( + struct r2pos& R2Pos_Cursor, + int FixP_Alpha, + const SCString& SCStr + ) const = 0; + // unsupported characters come out invisible, they may or may not affect + // the spacing/size depending on implementation + // the cursor pos is used for both input and output; the function returns + // the next position after the string for rendering further text + + // These functions are as above but for single characters: + virtual void RenderChar_Clipped + ( + struct r2pos& R2Pos_Cursor, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha, + ProjChar ProjCh + ) const = 0; + + virtual void RenderChar_Unclipped + ( + struct r2pos& R2Pos_Cursor, + int FixP_Alpha, + ProjChar ProjCh + ) const = 0; + + virtual r2size CalcSize + ( + ProjChar* pProjCh + ) const = 0; + // calculates how big the string would occupy as a single line + // without carriage returns etc + // unsupported characters come out invisible, they may or may not affect + // the spacing/size depending on implementation + // The SCString code assumes that for any strings pCh1, pCh2: + // + // height(pCh1) == height (pCh2) == height (pCh1+pCh2) + // width(pCh1 + pCh2) = width(pCh1) + width(pCh2) + // + // where "+" on strings used to mean concatenation + + virtual r2size CalcSize + ( + ProjChar* pProjCh, + int MaxChars + ) const = 0; + // as above, but will only use at most MaxChars characters, ignoring + // any that follow (used by the word wrap code) + + virtual r2size CalcSize + ( + ProjChar ProjCh + ) const = 0; + // calc size of individual character + // however size of (Ch0+Ch1+...ChN) doesn't need to equal + // size(Ch0) + size(Ch1) + ... size(ChN) because the string + // sizing/display fns are allowed to add spacing pixels + // in their own ways + + virtual OurBool bCanRender( ProjChar ProjCh_In ) const = 0; + // many fonts don't support all the characters within the ProjChar + // character set; you can check with this + + virtual int GetMaxWidth(void) const = 0; + virtual int GetWidth + ( + ProjChar ProjCh + ) const = 0; + virtual int GetHeight(void) const = 0; + + OurBool bCanRenderFully( ProjChar* pProjCh ); + // returns true iff all characters in the string are renderable by the font + + #if debug + void Render_Clipped_Report + ( + const struct r2pos& R2Pos_Cursor, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha, + const SCString& SCStr + ) const; + #endif + + protected: + // Protected constructor since abstract class + IndexedFont + ( + FontIndex I_Font_New + ); + + private: + FontIndex I_Font_Val; + + static IndexedFont* pIndexedFont[ IndexedFonts_MAX_NUMBER_OF_FONTS ]; + + }; + // Inline methods: + inline/*static*/ IndexedFont* IndexedFont::GetFont( FontIndex I_Font_ToGet ) + { + return pIndexedFont[ I_Font_ToGet ]; + } + + #if 0 + class IndexedFont_FixedSpace : public IndexedFont + { + public: + private: + }; + #endif + /* + KJL 17:20:10 15/04/98 - May God have mercy on my soul + fixed space HUD font + */ + class IndexedFont_HUD : public IndexedFont + { + public: + void RenderString_Clipped + ( + struct r2pos& R2Pos_Cursor, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha, + const SCString& SCStr + ) const; + + void RenderString_Unclipped + ( + struct r2pos& R2Pos_Cursor, + int FixP_Alpha, + const SCString& SCStr + ) const; + + void RenderChar_Clipped + ( + struct r2pos& R2Pos_Cursor, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha, + ProjChar ProjCh + ) const; + + void RenderChar_Unclipped + ( + struct r2pos& R2Pos_Cursor, + int FixP_Alpha, + ProjChar ProjCh + ) const; + + OurBool bCanRender( ProjChar ProjCh_In ) const + { + return Yes; + } + + inline int GetMaxWidth(void) const + { + return HUD_FONT_WIDTH; + } + + inline int GetWidth + ( + ProjChar ProjCh + ) const + { + return AAFontWidths[ProjCh]; + } + + inline int GetHeight(void) const + { + // +2 for line spacing + return HUD_FONT_HEIGHT+2; + } + + r2size CalcSize + ( + ProjChar* pProjCh + ) const; + r2size CalcSize + ( + ProjChar* pProjCh, + int MaxChars + ) const; + + r2size CalcSize + ( + ProjChar ProjCh + ) const; + +// protected: + IndexedFont_HUD + ( + FontIndex I_Font_New + ) : IndexedFont + ( + I_Font_New + ) + { + } + }; + inline r2size IndexedFont_HUD::CalcSize + ( + ProjChar ProjCh + ) const + { + return r2size + ( + GetWidth( ProjCh ), + GetHeight() + ); + } + #if 1 + inline r2size IndexedFont_HUD::CalcSize + ( + ProjChar* pProjCh, + int MaxChars + ) const + { + int width=0; + for (int i=0; i bPrintable(ProjCh_In); + } + + inline int IndexedFont_Proportional_PF::GetWidth + ( + ProjChar ProjCh + ) const + { + return pffont_Val -> GetWidth( ProjCh ); + } + inline int IndexedFont_Proportional_PF::GetHeight(void) const { return pffont_Val -> GetHeight(); } + + inline int IndexedFont_Proportional_PF::GetMaxWidth(void) const + { + return MaxWidth_Val; + } + + + + #endif // __cplusplus +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ +#ifdef __cplusplus + extern "C" { +#endif + extern void INDEXFNT_PFLoadHook + ( + FontIndex I_Font_New, + PFFONT *pffont_New + ); +#ifdef __cplusplus + }; +#endif + +/* End of the header ****************************************************/ + + + +#endif diff --git a/3dc/avp/support/ourbool.h b/3dc/avp/support/ourbool.h new file mode 100644 index 0000000..a61c20d --- /dev/null +++ b/3dc/avp/support/ourbool.h @@ -0,0 +1,38 @@ +/* + + ourbool.h + + Exists in order to define the type OurBool; +*/ + +#ifndef _ourbool +#define _ourbool 1 + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + typedef char OurBool; + // marker for an explicitly boolean type (e.g. for a return value) + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/support/r2base.cpp b/3dc/avp/support/r2base.cpp new file mode 100644 index 0000000..23da40c --- /dev/null +++ b/3dc/avp/support/r2base.cpp @@ -0,0 +1,269 @@ +/******************************************************************* + * + * DESCRIPTION: r2base.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 14/11/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "r2base.h" +#include "inline.h" + + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + + extern int D3DDriverMode; + + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + /*static*/ const r2pos r2pos :: Origin = r2pos(0,0); + /*static*/ r2rect r2rect :: R2Rect_PhysicalScreen = r2rect(0,0,640,480); + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +r2pos r2pos :: FixP_Scale +( + int FixP_ScaleFactor +) const +{ + // assumes the position to be in 16:16 fixed point, + // returns the position scaled by the fixed pt factor + + return r2pos + ( + MUL_FIXED(x, FixP_ScaleFactor), + MUL_FIXED(y, FixP_ScaleFactor) + ); +} + + +// Repository for code that ought to be in D3_FUNC.CPP +#if 0 +void r2rect :: AlphaFill +( + unsigned char R, + unsigned char G, + unsigned char B, + unsigned char translucency +) const +{ + GLOBALASSERT + ( + bValidPhys() + ); + + #if 0 + float RecipW, RecipH; + + // Check for textures that have not loaded properly + LOCALASSERT(TextureHandle != (D3DTEXTUREHANDLE) 0); + + if(ImageHeaderArray[imageNumber].ImageWidth==128) + { + RecipW = 1.0 /128.0; + } + else + { + float width = (float) ImageHeaderArray[imageNumber].ImageWidth; + RecipW = (1.0 / width); + } + if(ImageHeaderArray[imageNumber].ImageHeight==128) + { + RecipH = 1.0 / 128.0; + } + else + { + float height = (float) ImageHeaderArray[imageNumber].ImageHeight; + RecipH = (1.0 / height); + } + #endif + + + /* OUTPUT quadVerticesPtr TO EXECUTE BUFFER */ + { + D3DCOLOR Colour; + + switch (D3DDriverMode) + { + case D3DSoftwareRGBDriver: + { + Colour = RGBLIGHT_MAKE(R,G,B); + break; + } + + case D3DSoftwareRampDriver: + { + Colour = RGB_MAKE(0,0,B); + break; + } + + default: + case D3DHardwareRGBDriver: + { + Colour = RGBALIGHT_MAKE(R,G,B,translucency); + break; + } + } + + #if 1 + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + + /* Vertex 0 = Top left */ + vertexPtr->sx= x0; + vertexPtr->sy= y0; + vertexPtr->color = Colour; + + NumVertices++; + vertexPtr++; + + /* Vertex 1 = Top right */ + vertexPtr->sx=( x1 - 1); + vertexPtr->sy=( y0 ); + vertexPtr->color = Colour; + + NumVertices++; + vertexPtr++; + + /* Vertex 2 = Bottom right */ + vertexPtr->sx=( x1 - 1); + vertexPtr->sy=( y1 - 1); + vertexPtr->color = Colour; + + NumVertices++; + vertexPtr++; + + /* Vertex 3 = Bottom left */ + vertexPtr->sx=x0; + vertexPtr->sy=( y1 - 1); + vertexPtr->color = Colour; + + NumVertices++; + } + #else + int i = 4; + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + +// textprint("x %d, y %d, u %d, v %d\n",quadVerticesPtr->X,quadVerticesPtr->Y,quadVerticesPtr->U,quadVerticesPtr->V); + vertexPtr->sx=quadVerticesPtr->X; + vertexPtr->sy=quadVerticesPtr->Y; + #if 0 + vertexPtr->tu = ((float)(quadVerticesPtr->U)) * RecipW; + vertexPtr->tv = ((float)(quadVerticesPtr->V)) * RecipH; + #endif + + vertexPtr->color = Colour; + } + quadVerticesPtr++; + NumVertices++; + } + while(--i); + #endif + } + + // set correct texture handle + if (0 != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, 0, ExecBufInstPtr); + CurrTextureHandle = 0; + } + + /* output triangles to execute buffer */ + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + + /* check to see if buffer is getting full */ + if (NumVertices > (MaxD3DVertices-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } +} +#endif + +r2pos operator+ ( const r2pos& R2Pos_1, const r2pos& R2Pos_2 ) +{ + return r2pos + ( + R2Pos_1 . x + R2Pos_2 . x, + R2Pos_1 . y + R2Pos_2 . y + ); +} + + +extern void R2BASE_ScreenModeChange_Setup(void) +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + } +} + +extern "C" extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + +extern void R2BASE_ScreenModeChange_Cleanup(void) +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + + r2rect :: R2Rect_PhysicalScreen .x1 = ScreenDescriptorBlock.SDB_Width; + r2rect :: R2Rect_PhysicalScreen .y1 = ScreenDescriptorBlock.SDB_Height; + } +} + + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/support/r2base.h b/3dc/avp/support/r2base.h new file mode 100644 index 0000000..64daed9 --- /dev/null +++ b/3dc/avp/support/r2base.h @@ -0,0 +1,638 @@ +/* + + r2base.h + + Created 13/11/97 by David Malcolm + + "R2" is a proposed 2d-rendering interface; this + is the base header for it + +*/ + +#ifndef _r2base +#define _r2base 1 + +//#ifdef __cplusplus + //extern "C" { +//#endif + +/* Version settings *****************************************************/ + #define UseTemplates No + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + struct r2pos + { + int x; + int y; + + #ifdef __cplusplus + static const r2pos Origin; + // always (0,0) + + // Construction + r2pos() : x(0), y(0) + { + // empty + } + r2pos(int x_new,int y_new) : x(x_new), y(y_new) + { + // empty + } + + #if 0 + friend bool operator==(const r2pos& R2Pos_1, const r2pos& R2Pos_2); + #endif + + int bIsOrigin(void) const; + + friend r2pos operator+ ( const r2pos& R2Pos_1, const r2pos& R2Pos_2 ); + void operator+= ( const r2pos& R2Pos ); + // standard vector arithmetic + + r2pos FixP_Scale + ( + int FixP_ScaleFactor + ) const; + // assumes the position to be in 16:16 fixed point, + // returns the position scaled by the fixed pt factor + + int ApproxMagnitude(void) const; + // assumes the position to be in 16:16 fixed point + + #endif // __cplusplus + }; // suggested naming convention: "R2Pos" + + #ifdef __cplusplus + // Inline methods: + inline int r2pos::bIsOrigin(void) const + { + if (x==0) + { + if (y==0) + { + return Yes; + } + } + return No; + } + + inline void r2pos::operator+= + ( + const r2pos& R2Pos + ) + { + x += R2Pos . x; + y += R2Pos . y; + } + + inline int r2pos::ApproxMagnitude(void) const + { + // assumes the position to be in 16:16 fixed point + // based around the Foley+vanDam 2d distance function + int xAbs = (x>0) ? x : -x; + int yAbs = (y>0) ? y : -y; + + int xyMax = (xAbs > yAbs) ? xAbs : yAbs; + + return (xAbs + yAbs + (xyMax * 2)); + } + #endif /* __cplusplus */ + + + #if UseTemplates + #ifdef __cplusplus + // C++ implementation: + // r2size defined from a template + template struct size2d + { + ValType w; + ValType h; + + // Construction: + size2d() : w(0), h(0) + { + // empty + } + + size2d(ValType w_new,ValType h_new) : w(w_new), h(h_new) + { + // empty + } + + // Method declarations: + int bHasArea(void); + // Does this size have non-zero area?: + + void VCompose(const size2d& Size2D_Other ); + void HCompose(const size2d& Size2D_Other ); + // update size to the size necessary for composing + // this and another size either vertically or horizontally + + + // Inline methods: + int bHasArea(void) + { + // Does this size have non-zero area?: + if (w<=0) + { + return No; + } + if (h<=0) + { + return No; + } + return Yes; + } + void VCompose(const size2d& Size2D_Other ) + { + // sum of heights; greater of widths + + h += Size2D_Other . h; + + if (w < Size2D_Other . w) + { + w = Size2D_Other . w; + } + } + void HCompose(const size2d& Size2D_Other ) + { + // sum of widths; greater of heights + w += Size2D_Other . w; + + if (h < Size2D_Other . h) + { + h = Size2D_Other . h; + } + } + + }; // Suggested naming convention: "Size2D" + + typedef size2d r2size; // suggested naming convention: "R2Size" + #else + /* C implementation: r2size defined as a simple struct: */ + + struct r2size + { + int w; + int h; + }; /* suggested naming convention: "R2Size" */ + + #endif // __cplusplus + #else // UseTemplates + struct r2size + { + int w; + int h; + + #ifdef __cplusplus + // Construction: + r2size() : w(0), h(0) + { + // empty + } + + r2size(int w_new,int h_new) : w(w_new), h(h_new) + { + // empty + } + + // Method declarations: + int bHasArea(void); + // Does this size have non-zero area?: + + void VCompose(const r2size& R2Size_Other ); + void HCompose(const r2size& R2Size_Other ); + // update size to the size necessary for composing + // this and another size either vertically or horizontally + + #endif // __cplusplus + + }; // Suggested naming convention: "Size2D" + + #ifdef __cplusplus + // Inline methods: + inline int r2size::bHasArea(void) + { + // Does this size have non-zero area?: + if (w<=0) + { + return No; + } + if (h<=0) + { + return No; + } + return Yes; + } + inline void r2size::VCompose(const r2size& R2Size_Other ) + { + // sum of heights; greater of widths + + h += R2Size_Other . h; + + if (w < R2Size_Other . w) + { + w = R2Size_Other . w; + } + } + inline void r2size::HCompose(const r2size& R2Size_Other ) + { + // sum of widths; greater of heights + w += R2Size_Other . w; + + if (h < R2Size_Other . h) + { + h = R2Size_Other . h; + } + } + #endif /* __cplusplus */ + + #endif // UseTemplates + + struct r2rect + { + int x0; + int y0; + int x1; + int y1; + + // Rectangle defined in the "Windows" fashion + // i.e. first coord is top-left of rectangle and inside it + // second coord is bottom-right of rectange and immediately + // outside it. If the second coord is co-incident with the first + // or to the left or above, then the rectangle has zero area; no + // points are within it + + #ifdef __cplusplus + // Friends: + friend void R2BASE_ScreenModeChange_Cleanup(void); + // allowed to update the internal record of the dimensions of the physical screen + + // Construction: + r2rect(int x0_new,int y0_new,int x1_new,int y1_new) : + x0(x0_new), + y0(y0_new), + x1(x1_new), + y1(y1_new) + { + // empty + } + + r2rect(int x0_new,int y0_new, r2size R2Size) : + x0(x0_new), + y0(y0_new), + x1(x0_new + R2Size . w), + y1(y0_new + R2Size . h) + { + // empty + } + + r2rect(struct r2pos R2Pos, r2size R2Size) : + x0(R2Pos . x), + y0(R2Pos . y), + x1(R2Pos . x + R2Size . w), + y1(R2Pos . y + R2Size . h) + { + // empty + } + + r2rect(struct r2pos R2Pos, int W,int H) : + x0(R2Pos . x), + y0(R2Pos . y), + x1(R2Pos . x + W), + y1(R2Pos . y + H) + { + // empty + } + + // Method declarations: + int bHasArea(void) const; + struct r2pos GetPos(void) const; + r2size GetSize(void) const; + int Width(void) const; + int Height(void) const; + void SetWidth(int w_New); + void SetHeight(int h_New); + int bWithin( const struct r2pos& R2Pos ) const; + // is point inside this rect + + int bFitsIn( const struct r2rect& R2Rect ) const; + // is this rect fully inside ? + + int bOverlap( const struct r2rect& R2Rect_ToTest ) const; + void Clip( struct r2rect& R2Rect_ToClip ) const; + void Clip(const struct r2rect& R2Rect_In, struct r2rect& R2Rect_Out ) const; + static const r2rect& PhysicalScreen(void); + // for read-only access to the dimensions of the physical screen + + int bValidPhys(void) const; + // is this a valid rect within the physical screen? + // useful for asserting in a rendering routine + + // Access to 9 "interesting" positions in the rectangle: + // top-left, top-middle, etc... + r2pos Hotspot_TL(void) const; + r2pos Hotspot_TM(void) const; + r2pos Hotspot_TR(void) const; + r2pos Hotspot_ML(void) const; + r2pos Hotspot_MM(void) const; + r2pos Hotspot_MR(void) const; + r2pos Hotspot_BL(void) const; + r2pos Hotspot_BM(void) const; + r2pos Hotspot_BR(void) const; + + r2pos Centre(void) const { return Hotspot_MM(); } + + r2pos CentredWithSize_TL( r2size R2Size_In ) const; + // finds location for top left of a rect with the given size so that + // it gets centred on this rect + + // Rendering: + void AlphaFill + ( + unsigned char R, + unsigned char G, + unsigned char B, + unsigned char translucency + ) const; + + + private: + static r2rect R2Rect_PhysicalScreen; + + #endif // __cplusplus + }; // suggested naming convention: "R2Rect" + + #ifdef __cplusplus + // Inline methods: + inline int r2rect::bHasArea(void) const + { + if (x1<=x0) + { + return No; + } + if (y1<=y0) + { + return No; + } + return Yes; + } + inline struct r2pos r2rect::GetPos(void) const + { + return r2pos(x0,y0); + } + inline r2size r2rect::GetSize(void) const + { + return r2size(x1-x0,y1-y0); + } + inline int r2rect::Width(void) const + { + return x1-x0; + } + inline int r2rect::Height(void) const + { + return y1-y0; + } + inline void r2rect::SetWidth(int w_New) + { + x1 = x0 + w_New; + } + inline void r2rect::SetHeight(int h_New) + { + y1 = y0 + h_New; + } + inline int r2rect::bWithin( const struct r2pos& R2Pos ) const + { + if + ( + R2Pos . x < x0 + ) + { + return No; + } + if + ( + R2Pos . y < y0 + ) + { + return No; + } + if + ( + R2Pos . x >= x1 + ) + { + return No; + } + if + ( + R2Pos . y >= y1 + ) + { + return No; + } + return Yes; + } + inline int r2rect::bFitsIn( const struct r2rect& R2Rect ) const + { + if ( x0 < R2Rect . x0) + { + return No; + } + if ( y0 < R2Rect . y0) + { + return No; + } + if ( x1 > R2Rect . x1) + { + return No; + } + if ( y1 > R2Rect . y1) + { + return No; + } + return Yes; + } + inline int r2rect::bOverlap( const struct r2rect& R2Rect_ToTest ) const + { + if ( x0 >= R2Rect_ToTest . x1 ) + { + return No; + } + if ( y0 >= R2Rect_ToTest . y1 ) + { + return No; + } + if ( x1 <= R2Rect_ToTest . x0 ) + { + return No; + } + if ( y1 <= R2Rect_ToTest . y0 ) + { + return No; + } + return Yes; + } + inline void r2rect::Clip( struct r2rect& R2Rect_ToClip ) const + { + if ( R2Rect_ToClip . x0 < x0) + { + R2Rect_ToClip . x0 = x0; + } + if ( R2Rect_ToClip . y0 < y0) + { + R2Rect_ToClip . y0 = y0; + } + if ( R2Rect_ToClip . x1 >= x1) + { + R2Rect_ToClip . x1 = x1; + } + if ( R2Rect_ToClip . y1 >= y1) + { + R2Rect_ToClip . y1 = y1; + } + } + #if 0 + inline void r2rect::Clip(const struct r2rect& R2Rect_In, struct r2rect& R2Rect_Out ) + { + R2Rect_Out . x0 = + } + #endif + inline /*static*/ const r2rect& r2rect::PhysicalScreen(void) + { + return R2Rect_PhysicalScreen; + } + inline int r2rect::bValidPhys(void) const + { + // is this a valid rect within the physical screen? + // useful for asserting in a rendering routine + if ( x0 < 0 ) + { + return No; + } + if ( y0 < 0 ) + { + return No; + } + if ( x1 > R2Rect_PhysicalScreen . x1 ) + { + return No; + } + if ( y1 > R2Rect_PhysicalScreen . y1 ) + { + return No; + } + // Check for well-formedness: + if ( x0 > x1 ) + { + return No; + } + if ( y0 > y1 ) + { + return No; + } + + return Yes; + } + inline r2pos r2rect::Hotspot_TL(void) const + { + return r2pos + ( + x0, + y0 + ); + } + inline r2pos r2rect::Hotspot_TM(void) const + { + return r2pos + ( + (x0+x1)/2, + y0 + ); + } + inline r2pos r2rect::Hotspot_TR(void) const + { + return r2pos + ( + (x1-1), + y0 + ); + } + inline r2pos r2rect::Hotspot_ML(void) const + { + return r2pos + ( + x0, + (y0+y1)/2 + ); + } + inline r2pos r2rect::Hotspot_MM(void) const + { + return r2pos + ( + (x0+x1)/2, + (y0+y1)/2 + ); + } + inline r2pos r2rect::Hotspot_MR(void) const + { + return r2pos + ( + (x1-1), + (y0+y1)/2 + ); + } + inline r2pos r2rect::Hotspot_BL(void) const + { + return r2pos + ( + x0, + (y1-1) + ); + } + inline r2pos r2rect::Hotspot_BM(void) const + { + return r2pos + ( + (x0+x1)/2, + (y1-1) + ); + } + inline r2pos r2rect::Hotspot_BR(void) const + { + return r2pos + ( + (x1-1), + (y1-1) + ); + } + + inline r2pos r2rect::CentredWithSize_TL( r2size R2Size_In ) const + { + return r2pos + ( + x0+((Width() - R2Size_In . w)/2), + y0+((Height() - R2Size_In . h)/2) + ); + } + #endif /* __cplusplus */ + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + extern void R2BASE_ScreenModeChange_Setup(void); + extern void R2BASE_ScreenModeChange_Cleanup(void); + + +/* End of the header ****************************************************/ + + +//#ifdef __cplusplus +// }; +//#endif + +#endif diff --git a/3dc/avp/support/r2pos666.cpp b/3dc/avp/support/r2pos666.cpp new file mode 100644 index 0000000..3135a8f --- /dev/null +++ b/3dc/avp/support/r2pos666.cpp @@ -0,0 +1,106 @@ +/******************************************************************* + * + * DESCRIPTION: r2pos666.cpp - Daemonic r2 positions + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 1/12/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "r2pos666.hpp" +#include "inline.h" + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +// class R2PosDaemon : public Daemon +// public: +R2PosDaemon :: R2PosDaemon +( + r2pos R2Pos_Int_Initial, + OurBool bActive +) : Daemon( bActive ), + R2Pos_Int_Current( R2Pos_Int_Initial ), + R2Pos_FixP_Current + ( + OUR_INT_TO_FIXED( R2Pos_Int_Initial . x ), + OUR_INT_TO_FIXED( R2Pos_Int_Initial . y ) + ) +{ + +} + +void R2PosDaemon :: SetPos_Int(const r2pos R2Pos_Int_New ) +{ + R2Pos_Int_Current = R2Pos_Int_New; + R2Pos_FixP_Current = r2pos + ( + OUR_INT_TO_FIXED( R2Pos_Int_Current . x ), + OUR_INT_TO_FIXED( R2Pos_Int_Current . y ) + ); +} + +void R2PosDaemon :: SetPos_FixP(const r2pos R2Pos_FixP_New ) +{ + R2Pos_FixP_Current = R2Pos_FixP_New; + R2Pos_Int_Current = r2pos + ( + OUR_FIXED_TO_INT( R2Pos_FixP_Current . x ), + OUR_FIXED_TO_INT( R2Pos_FixP_Current . y ) + ); +} + +// Activity remains pure virtual... + + +// private: +#if 0 +r2pos R2Pos_Int_Current; +r2pos R2Pos_FixP_Current; +#endif + + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/support/r2pos666.hpp b/3dc/avp/support/r2pos666.hpp new file mode 100644 index 0000000..a9adcdd --- /dev/null +++ b/3dc/avp/support/r2pos666.hpp @@ -0,0 +1,79 @@ +/* + + r2pos666.hpp + +*/ + +#ifndef _r2pos666 +#define _r2pos666 1 + + #ifndef _r2base + #include "r2base.h" + #endif + + #ifndef _daemon + #include "daemon.h" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + class R2PosDaemon : public Daemon + { + public: + R2PosDaemon + ( + r2pos R2Pos_Int_Initial, + OurBool bActive + ); + + ~R2PosDaemon() + { + // empty + } + + r2pos GetPos_Int(void) const; + r2pos GetPos_FixP(void) const; + + void SetPos_Int(const r2pos R2Pos_Int_New ); + void SetPos_FixP(const r2pos R2Pos_FixP_New ); + + // Activity remains pure virtual... + + private: + r2pos R2Pos_Int_Current; + r2pos R2Pos_FixP_Current; + + }; + // Inline methods: + inline r2pos R2PosDaemon::GetPos_Int(void) const + { + return R2Pos_Int_Current; + } + inline r2pos R2PosDaemon::GetPos_FixP(void) const + { + return R2Pos_FixP_Current; + } + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/support/rebitems.cpp b/3dc/avp/support/rebitems.cpp new file mode 100644 index 0000000..0027a9a --- /dev/null +++ b/3dc/avp/support/rebitems.cpp @@ -0,0 +1,870 @@ +/******************************************************************* + * + * DESCRIPTION: rebitems.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 9/3/98 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" + + #include "rebitems.hpp" + + #if UseRebMenus + #include "strtab.hpp" + #include "indexfnt.hpp" + + #include "module.h" + // to include stratdef.h + + #include "stratdef.h" + // to include usr_io.h + + #include "usr_io.h" + + #include "db.h" + + #define UseLocalAssert Yes + #include "ourasert.h" + + #endif + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ +#if UseRebMenus +// static +const FontIndex RebMenus :: Fonts :: LabelFont_InGame = DATABASE_MESSAGE_FONT; +// static +const FontIndex RebMenus :: Fonts :: LabelFont_OutOfGame_Selected = IntroFont_Light; +const FontIndex RebMenus :: Fonts :: LabelFont_OutOfGame_Unselected = IntroFont_Dark; +#endif + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +#if UseRebMenus +// Derived classes for the item types: +//class Item_Unimplemented : public Item +// public: +// Process various keypresses: +OurBool +RebMenus :: Item_Unimplemented :: Navigate( enum NavigationOp aNavOp ) +{ + // return = was message processed + switch ( aNavOp ) + { + case NavOp_Trigger: + textprint("this is an unimplemented item\n"); + return Yes; + + case NavOp_Up: + case NavOp_Down: + case NavOp_Left: + case NavOp_Right: + case NavOp_Home: + case NavOp_End: + case NavOp_Cancel: + // No way of processing + return No; + + default: + GLOBALASSERT(0); + } + return No; +} + +void +RebMenus :: Item_Unimplemented :: Diagnostic(OurBool bSelected) const +{ + textprint("Unimplemented:"); + + DiagnosticAppearance(bSelected); +} + +// Methods relating to rendering: +void +RebMenus :: Item_Unimplemented :: Render +( + const RenderContext& theContext, + OurBool bSelected +) const +{ + RenderAppearance + ( + theContext, + bSelected + ); +} + +RebMenus :: SizeInfo +RebMenus :: Item_Unimplemented :: GetSizeInfo(void) const +{ + return AppearanceSizeInfo(); +} +// public: +// Process various keypresses: +OurBool +RebMenus :: Item_Command :: Navigate( enum NavigationOp aNavOp ) +{ + // return = was message processed + switch ( aNavOp ) + { + case NavOp_Trigger: + return pCommand_Val -> Execute(); + + case NavOp_Up: + case NavOp_Down: + case NavOp_Left: + case NavOp_Right: + case NavOp_Home: + case NavOp_End: + case NavOp_Cancel: + // No way of processing + return No; + + default: + GLOBALASSERT(0); + } + return No; +} + +void +RebMenus :: Item_Command :: Diagnostic(OurBool bSelected) const +{ + textprint("Item_Command:"); + + DiagnosticAppearance(bSelected); +} +// contains a command; can contain a "goto menu page" command + +// Methods relating to rendering: +void +RebMenus :: Item_Command :: Render +( + const RenderContext& theContext, + OurBool bSelected +) const +{ + RenderAppearance + ( + theContext, + bSelected + ); +} + +RebMenus :: SizeInfo +RebMenus :: Item_Command :: GetSizeInfo(void) const +{ + return AppearanceSizeInfo(); +} + + +// class Item_Selection : public Item +// public: +#if 1 +// Process various keypresses: +OurBool +RebMenus :: Item_Selection :: Navigate( enum NavigationOp aNavOp ) +{ + // return = was message processed + switch ( aNavOp ) + { + case NavOp_Up: + if ( theDir == D_Vert ) + { + Dec(); + return Yes; + } + else + { + return No; + } + + case NavOp_Down: + if ( theDir == D_Vert ) + { + Inc(); + return Yes; + } + else + { + return No; + } + + case NavOp_Left: + if ( theDir == D_Horiz ) + { + Dec(); + return Yes; + } + else + { + return No; + } + + case NavOp_Right: + if ( theDir == D_Horiz ) + { + Inc(); + return Yes; + } + else + { + return No; + } + case NavOp_Home: + Min(); + return Yes; + + case NavOp_End: + Max(); + return Yes; + + case NavOp_Trigger: + Inc(); + return Yes; + + case NavOp_Cancel: + // No way of processing + return No; + + default: + GLOBALASSERT(0); + } + return No; +} +#endif + +void +RebMenus :: Item_Selection :: Diagnostic(OurBool bSelected) const +{ + textprint("Item_Selection: "); + + #if 1 + DiagnosticAppearance(bSelected); + #endif + +} + +void +RebMenus :: Item_Selection :: Min(void) +{ + textprint("Min\n"); + + pSelectionVar_Val -> Set + ( + pSelectionVar_Val -> GetMin() + ); +} + +void +RebMenus :: Item_Selection :: Max(void) +{ + textprint("Max\n"); + + pSelectionVar_Val -> Set + ( + pSelectionVar_Val -> GetMax() + ); +} + +void +RebMenus :: Item_Selection :: Inc(void) +{ + textprint("Inc\n"); + + pSelectionVar_Val -> Set + ( + pSelectionVar_Val -> GetNxt() + ); + +} + +void +RebMenus :: Item_Selection :: Dec(void) +{ + textprint("Dec\n"); + + pSelectionVar_Val -> Set + ( + pSelectionVar_Val -> GetPrv() + ); +} + +// Methods relating to rendering: +void +RebMenus :: Item_Selection :: Render +( + const RenderContext& theContext, + OurBool bSelected +) const +{ + RenderAppearance + ( + theContext, + bSelected + ); + + RenderContext valueContext = theContext . NextColumn(); + + pSelectionVar_Val -> GetAppearance( bSelected ) . Render + ( + valueContext, + bSelected + ); +} + +RebMenus :: SizeInfo +RebMenus :: Item_Selection :: GetSizeInfo(void) const +{ + return AppearanceSizeInfo(); +} + + +// class Item_Slider : public Item +// public: +// Process various keypresses: +OurBool +RebMenus :: Item_Slider :: Navigate( enum NavigationOp aNavOp ) +{ + // return = was message processed + switch ( aNavOp ) + { + case NavOp_Up: + if ( theDir == D_Vert ) + { + Inc(); + return Yes; + } + else + { + return No; + } + + case NavOp_Down: + if ( theDir == D_Vert ) + { + Dec(); + return Yes; + } + else + { + return No; + } + + case NavOp_Left: + if ( theDir == D_Horiz ) + { + Dec(); + return Yes; + } + else + { + return No; + } + + case NavOp_Right: + if ( theDir == D_Horiz ) + { + Inc(); + return Yes; + } + else + { + return No; + } + case NavOp_Home: + SetToMax(); + return Yes; + + case NavOp_End: + SetToMin(); + return Yes; + + case NavOp_Trigger: + Inc(); + return Yes; + + case NavOp_Cancel: + // No way of processing + return No; + + default: + GLOBALASSERT(0); + } + return No; +} + +void +RebMenus :: Item_Slider :: Diagnostic(OurBool bSelected) const +{ + textprint("Item_Slider:"); + + #if 1 + DiagnosticAppearance(bSelected); + #endif +} + +// Handy ways to process discrete movements of the slider +void +RebMenus :: Item_Slider :: SetToMin(void) +{ + textprint("SetToMin\n"); + + pBoundedExpVar_Val -> Set + ( + pBoundedExpVar_Val -> GetMin() + ); +} + +void +RebMenus :: Item_Slider :: SetToMax(void) +{ + textprint("SetToMax\n"); + + pBoundedExpVar_Val -> Set + ( + pBoundedExpVar_Val -> GetMax() + ); +} + +void +RebMenus :: Item_Slider :: Inc(void) +{ + textprint("Inc\n"); + + // The Set() method silently rejects attempt to set outside range + // For this reason, if close to the bounding value, + // set direct to bounding value + + int NewVal = pBoundedExpVar_Val -> Get() + GetFraction(); + + int Bound = pBoundedExpVar_Val -> GetMax(); + + pBoundedExpVar_Val -> Set + ( + (NewVal < Bound) ? NewVal : Bound + ); +} + +void +RebMenus :: Item_Slider :: Dec(void) +{ + textprint("Dec\n"); + + // Analogous to the Inc() method above + + int NewVal = pBoundedExpVar_Val -> Get() - GetFraction(); + + int Bound = pBoundedExpVar_Val -> GetMin(); + + pBoundedExpVar_Val -> Set + ( + (NewVal > Bound) ? NewVal : Bound + ); +} + +// Methods relating to rendering: +void +RebMenus :: Item_Slider :: Render +( + const RenderContext& theContext, + OurBool bSelected +) const +{ + RenderAppearance + ( + theContext, + bSelected + ); + + RenderContext sliderContext = theContext . NextColumn(); + + float floatPos = + ( + float( GetVal() - GetMin() ) + / + float( GetRange() ) + ); + + RenderSlider + ( + sliderContext, + bSelected, + floatPos + ); + + #if 0 + textprintXY + ( + sliderContext . Pos() . x, + sliderContext . Pos() . y, + " [%i,%i] range(%i) val(%i)", + GetMin(), + GetMax(), + GetRange(), + GetVal() + + ); + #endif +} + +RebMenus :: SizeInfo +RebMenus :: Item_Slider :: GetSizeInfo(void) const +{ + return AppearanceSizeInfo() . AddColumn + ( + SizeInfo + ( + Bitmap :: GetSize("Graphics\\NewMenus\\SliderBar.rim"), + 0 + ) + ); +} + +// private: +// static +void +RebMenus :: Item_Slider :: RenderSlider +( + const RenderContext& theContext, + OurBool bSelected, + float floatAmount +) +{ + #if 1 + Bitmap :: Blit_Transparent + ( + ( + bSelected + ? + "Graphics\\NewMenus\\SliderBar.rim" // const char* const pCh_Name, + : + "Graphics\\NewMenus\\SliderBarDark.rim" // const char* const pCh_Name, + ), + theContext . ClipRect(), + theContext . Pos() + ); + Bitmap :: Blit_Transparent + ( + ( + bSelected + ? + "Graphics\\NewMenus\\Slider.rim" // const char* const pCh_Name, + : + "Graphics\\NewMenus\\SliderDark.rim" // const char* const pCh_Name, + ), + theContext . ClipRect(), + r2pos + ( + ( + theContext . Pos() . x + 3 + + ( + int(200.0f * floatAmount) + ) + ), + ( + theContext . Pos() . y + 4 + ) + ) + ); + #else + textprintXY + ( + theContext . Pos() . x, + theContext . Pos() . y, + "[---------------]" + ); + + const int TotalWidth = (16*CharWidth); + int Offset = + ( + int(float(TotalWidth) * floatAmount) + ); + + textprintXY + ( + theContext . Pos() . x + Offset, + theContext . Pos() . y, + "|" + ); + #endif +} + + +// class Item_Toggle : public Item +// public: +// Process various keypresses: +OurBool +RebMenus :: Item_Toggle :: Navigate( enum NavigationOp aNavOp ) +{ + // return = was message processed + switch ( aNavOp ) + { + case NavOp_Up: + case NavOp_Down: + if ( theDir == D_Vert ) + { + Toggle(); + return Yes; + } + else + { + return No; + } + case NavOp_Left: + case NavOp_Right: + if ( theDir == D_Horiz ) + { + Toggle(); + return Yes; + } + else + { + return No; + } + case NavOp_Trigger: + Toggle(); + return Yes; + + case NavOp_Home: + TurnOn(); + return Yes; + + case NavOp_End: + TurnOff(); + return Yes; + + case NavOp_Cancel: + // No way of processing + return No; + + default: + GLOBALASSERT(0); + } + return No; +} + +void +RebMenus :: Item_Toggle :: Diagnostic(OurBool bSelected) const +{ + textprint("Item_Toggle:"); + + DiagnosticAppearance(bSelected); + + theOnOffApp_Val . GetAppearance + ( + pExpVar_Val -> Get() + ) . Diagnostic(); +} + +void +RebMenus :: Item_Toggle :: Toggle(void) +{ + OurBool bCurrent = pExpVar_Val -> Get(); + pExpVar_Val -> Set + ( + !bCurrent + ); +} + +void +RebMenus :: Item_Toggle :: TurnOn(void) +{ + pExpVar_Val -> Set(Yes); +} + +void +RebMenus :: Item_Toggle :: TurnOff(void) +{ + pExpVar_Val -> Set(No); +} + +// Methods relating to rendering: +void +RebMenus :: Item_Toggle :: Render +( + const RenderContext& theContext, + OurBool bSelected +) const +{ + RenderAppearance + ( + theContext, + bSelected + ); + + + RenderContext valueContext = theContext . NextColumn(); + + theOnOffApp_Val .GetAppearance + ( + pExpVar_Val -> Get() + ) . Render + ( + valueContext, + bSelected + ); +} + +RebMenus :: SizeInfo +RebMenus :: Item_Toggle :: GetSizeInfo(void) const +{ + return AppearanceSizeInfo() . AddColumn + ( + theOnOffApp_Val . GetSizeInfo() + ); +} + +#if 0 +// class Item_Table : public Item +// public: +RebMenus :: Item_Table :: Item_Table +( + OnOffAppearance theOnOffApp_New +) : Item(theOnOffApp_New), + NumX(0), + NumY(0), + SelectedX(0), + SelectedY(0) +{ +} + +// Process various keypresses: +OurBool +RebMenus :: Item_Table :: Navigate( enum NavigationOp aNavOp ) +{ + // return = was message processed + return No; +} + +void +RebMenus :: Item_Table :: Diagnostic(OurBool bSelected) const +{ +} + +Item* +RebMenus :: Item_Table :: GetSelected(void) const +{ + // will return NULL iff there are no items in the composition + if (NumX == 0) + { + GLOBALASSERT(NumY==0); + return NULL; + } + + GLOBALASSERT( NumY > 0 ); + + GLOBALASSERT( NumX < MAX_X ); + GLOBALASSERT( NumY < MAX_Y ); + + GLOBALASSERT( SelectedX >= 0 ); + GLOBALASSERT( SelectedY >= 0 ); + + GLOBALASSERT( SelectedX < NumX ); + GLOBALASSERT( SelectedY < NumY ); + + Item* pItem = pItem_A[SelectedX][SelectedY]; + + GLOBALASSERT( pItem ); + + return pItem; +} + +// private: +void +RebMenus :: Item_Table :: AddRow +( + Item** ppItem_ToAdd +) +{ + // takes a NULL-terminated list of Item*s + + GLOBALASSERT(NumY < (MAX_Y-1) ); + // can't get any bigger + + int Pos_I = 0; + + while ( *ppItem_ToAdd ) + { + GLOBALASSERT( Pos_I < MAX_X ); + + pItem_A + [ + Pos_I++ + ] + [ + NumY + ] + = + ( + *(ppItem_ToAdd++) + ); + } + + if (NumX < Pos_I) + { + } + + NumY++; + +} + +void +RebMenus :: Item_Table :: AddColumn +( + Item** ppItem_ToAdd +) +{ + // takes a NULL-terminated list of Item*s +} + +#if 0 +// List of selectables: +enum {MAX_X = 10}; +enum {MAX_Y = 20}; +#endif + +#endif + +#endif + // UseRebMenus + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/support/rebitems.hpp b/3dc/avp/support/rebitems.hpp new file mode 100644 index 0000000..37ec9b2 --- /dev/null +++ b/3dc/avp/support/rebitems.hpp @@ -0,0 +1,358 @@ +/* + + rebitems.hpp + + Derived classes for the item types; all except CompositeItem go in this + file. +*/ + +#ifndef _rebitems_hpp +#define _rebitems_hpp 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + + #ifndef _rebmenus_hpp + #include "rebmenus.hpp" + #endif + + #if UseRebMenus + #ifndef _included_pcmenus_h_ + #include "pcmenus.h" + // for enum KeyConfigItems + #endif + + #ifndef _scstring + #include "scstring.hpp" + #endif + #endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ +#if UseRebMenus +// Derived classes for the item types: +namespace RebMenus +{ + class Item_Unimplemented : public Item + { + public: + Item_Unimplemented + ( + OnOffAppearance theOnOffApp + ) : Item + ( + theOnOffApp + ) + { + } + + // Process various keypresses: + OurBool Navigate( enum NavigationOp aNavOp ); + // return = was message processed + + void Diagnostic(OurBool bSelected) const; + + // Methods relating to rendering: + void Render + ( + const RenderContext& theContext, + OurBool bSelected + ) const; + + SizeInfo GetSizeInfo(void) const; + + }; + + class Item_Command : public Item + { + public: + Item_Command + ( + OnOffAppearance theOnOffApp, + Command* pCommand + ) : Item + ( + theOnOffApp + ), + pCommand_Val(pCommand) + { + pCommand_Val -> R_AddRef(); + } + + ~Item_Command() + { + pCommand_Val -> R_Release(); + } + + // Process various keypresses: + OurBool Navigate( enum NavigationOp aNavOp ); + // return = was message processed + + void Diagnostic(OurBool bSelected) const; + + // Methods relating to rendering: + void Render + ( + const RenderContext& theContext, + OurBool bSelected + ) const; + + SizeInfo GetSizeInfo(void) const; + + private: + Command *const pCommand_Val; + }; + // contains a command; can contain a "goto menu page" command + + class Item_Selection : public Item + { + public: + Item_Selection + ( + OnOffAppearance theOnOffApp, + enum Direction initDir, + SelectionVariable* pSelectionVar + ) : Item + ( + theOnOffApp + ), + theDir(initDir), + pSelectionVar_Val(pSelectionVar) + { + } + + // Process various keypresses: + OurBool Navigate( enum NavigationOp aNavOp ); + // return = was message processed + + void Diagnostic(OurBool bSelected) const; + + void Min(void); + void Max(void); + void Inc(void); + void Dec(void); + + // Methods relating to rendering: + void Render + ( + const RenderContext& theContext, + OurBool bSelected + ) const; + + SizeInfo GetSizeInfo(void) const; + + private: + // Direction: + const enum Direction theDir; + SelectionVariable* const pSelectionVar_Val; + + }; + + class Item_Slider : public Item + { + public: + Item_Slider + ( + OnOffAppearance theOnOffApp, + enum Direction initDir, + BoundedExportVariable* pBoundedExpVar + // takes responsibility for deallocating this + ) : Item + ( + theOnOffApp + ), + theDir(initDir), + pBoundedExpVar_Val(pBoundedExpVar) + { + } + + // Process various keypresses: + OurBool Navigate( enum NavigationOp aNavOp ); + // return = was message processed + + void Diagnostic(OurBool bSelected) const; + + // Handy ways to process discrete movements of the slider + void SetToMin(void); + void SetToMax(void); + void Inc(void); + void Dec(void); + + // Handy ways to values of the slider: + int GetMin(void) const + { + return pBoundedExpVar_Val -> GetMin(); + } + int GetMax(void) const + { + return pBoundedExpVar_Val -> GetMax(); + } + int GetRange(void) const + { + return ( GetMax() - GetMin() ); + } + int GetVal(void) const + { + return pBoundedExpVar_Val -> Get(); + } + + // Methods relating to rendering: + void Render + ( + const RenderContext& theContext, + OurBool bSelected + ) const; + + SizeInfo GetSizeInfo(void) const; + + private: + static void RenderSlider + ( + const RenderContext& theContext, + OurBool bSelected, + float floatPos + ); + + int GetFraction(void) const + { + // returns a fractional amout good for a small increment/decrement + + int Amt = (GetRange() / 32); + + return ( (Amt>1) ? Amt : 1); + // ensure amount is at least 1 + } + + private: + // Direction: + const enum Direction theDir; + BoundedExportVariable* const pBoundedExpVar_Val; + + }; + + class Item_Toggle : public Item + { + public: + Item_Toggle + ( + OnOffAppearance theOnOffApp_Label, + + enum Direction initDir, + OnOffAppearance theOnOffApp_Choice, + ExportVariable* pExpVar + // takes responsibility for deallocating this + ) : Item + ( + theOnOffApp_Label + ), + theDir(initDir), + theOnOffApp_Val(theOnOffApp_Choice), + pExpVar_Val(pExpVar) + { + } + + // Process various keypresses: + OurBool Navigate( enum NavigationOp aNavOp ); + // return = was message processed + + void Diagnostic(OurBool bSelected) const; + + void Toggle(void); + void TurnOn(void); + void TurnOff(void); + + // Methods relating to rendering: + void Render + ( + const RenderContext& theContext, + OurBool bSelected + ) const; + + SizeInfo GetSizeInfo(void) const; + + private: + // Direction: + const enum Direction theDir; + + OnOffAppearance theOnOffApp_Val; + + ExportVariable* pExpVar_Val; + }; + + #if 0 + // A 2d analogue of the composite item: + class Item_Table : public Item + { + public: + Item_Table + ( + OnOffAppearance theOnOffApp_New + ); + + // Process various keypresses: + OurBool Navigate( enum NavigationOp aNavOp ); + // return = was message processed + + void Diagnostic(OurBool bSelected) const; + + Item* GetSelected(void) const; + // will return NULL iff there are no items in the composition + + private: + #if 1 + void AddControlConfigRow(); + #else + void AddRow + ( + Item** ppItem_ToAdd + ); + // takes a NULL-terminated list of Item*s + + void AddColumn + ( + Item** ppItem_ToAdd + ); + // takes a NULL-terminated list of Item*s + #endif + + // List of selectables: + enum {MAX_X = 10}; + enum {MAX_Y = 20}; + + int NumX; + int NumY; + Item* pItem_A[ MAX_X ][ MAX_Y ]; + + int SelectedX; + int SelectedY; + + }; + #endif + + + #if 0 + // Decorator contains another item, and passes on calls to it ?? + class Item_Decorator_VScroll : public Item + { + public: + private: + }; + #endif + +}; +#endif // UseRebMenus + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ +#endif diff --git a/3dc/avp/support/rebmenus.cpp b/3dc/avp/support/rebmenus.cpp new file mode 100644 index 0000000..4581a82 --- /dev/null +++ b/3dc/avp/support/rebmenus.cpp @@ -0,0 +1,1722 @@ +/******************************************************************* + * + * DESCRIPTION: rebmenus.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 9/3/98 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" + + #include "rebmenus.hpp" + + #if UseRebMenus + #include "rebitems.hpp" + #include "strtab.hpp" + #include "indexfnt.hpp" + + #include "awTexLd.h" + #include "alt_tab.h" + + #define UseLocalAssert Yes + #include "ourasert.h" + #endif // UseRebMenus + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#if UseRebMenus + #ifdef __cplusplus + extern "C" + { + #endif + + extern LPDIRECTDRAWSURFACE lpDDSBack; + + #ifdef __cplusplus + }; + #endif +#endif // UseRebMenus + + +/* Exported globals ************************************************/ +#if UseRebMenus +#if OverrideOldMenus +// private: +// static +OurBool RebMenus :: InGame :: bInTheGame_Val = No; + +// static + +// enum RebMenus :: MenuLoop :: ExitReason +// enum ExitReason +RebMenus :: MenuLoop :: ExitReason +RebMenus :: MenuLoop :: theExitReason_Val = ExitReason_None; +#endif + // OverrideOldMenus +#endif + // UseRebMenus + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +#if UseRebMenus +// namespace RebMenus +// class Command_JumpToPage : public Command +// public: +OurBool +RebMenus :: Command_JumpToPage :: Execute(void) +{ + Page :: SelectPage(thePage_Val); + + return Yes; +} + + +// class Command_ReturnFromPage : public Command +// public: +OurBool +RebMenus :: Command_ReturnFromPage :: Execute(void) +{ + Page :: TryToReturn(); + + return Yes; +} + +RebMenus :: SizeInfo +RebMenus :: SizeInfo :: Overlay +( + SizeInfo other +) +{ + int minW_Max = + ( + (minR2Size_Val . w > other . minR2Size_Val . w) + ? + minR2Size_Val . w + : + other . minR2Size_Val . w + ); + int minH_Max = + ( + (minR2Size_Val . h > other . minR2Size_Val . h) + ? + minR2Size_Val . h + : + other . minR2Size_Val . h + ); + int maxColumn_minW = + ( + (Column0_minW_Val > other . Column0_minW_Val) + ? + Column0_minW_Val + : + other . Column0_minW_Val + ); + return SizeInfo + ( + r2size + ( + minW_Max, + minH_Max + ), + maxColumn_minW + ); +} + +RebMenus :: SizeInfo +RebMenus :: SizeInfo :: AddColumn +( + SizeInfo nextColumn +) +{ + r2size R2Size_New = minR2Size_Val; + r2size R2Size_NextColumn = nextColumn . minR2Size_Val; + + R2Size_New . HCompose + ( + R2Size_NextColumn + ); + + return SizeInfo + ( + R2Size_New, + minR2Size_Val . w + ); +} + +RebMenus :: SizeInfo +RebMenus :: SizeInfo :: AddRow +( + SizeInfo nextRow +) +{ + r2size R2Size_New = minR2Size_Val; + + int maxColumn_minW = + ( + (Column0_minW_Val > nextRow . Column0_minW_Val) + ? + Column0_minW_Val + : + nextRow . Column0_minW_Val + ); + + R2Size_New . VCompose(nextRow . minR2Size_Val); + + return SizeInfo + ( + R2Size_New, + maxColumn_minW + ); +} + +#if 1 +void +RebMenus :: SizeInfo :: Compose +( + const SizeInfo& other, + enum Direction theD, + enum Alignment // theAl +) +{ + if ( theD == D_Vert ) + { + minR2Size_Val . VCompose + ( + other . minR2Size_Val + ); + } + else + { + minR2Size_Val . HCompose + ( + other . minR2Size_Val + ); + } + + Column0_minW_Val = + ( + (Column0_minW_Val > other . Column0_minW_Val) + ? + Column0_minW_Val + : + other . Column0_minW_Val + ); +} + + +#endif + + + +// class Appearance +// public: +void +RebMenus :: Appearance :: Diagnostic(void) const +{ + if ( bHasBitmap ) + { + textprint("bitmap:\"%s\"; ",BMapN_Val . Get()); + } + else + { + textprint("plain; "); + } + + if ( bHasTextLabel ) + { + SCString& theLabel = StringTable :: GetSCString + ( + ID_Label_Val + ); + + textprint + ( + "label=\"%s\"\n", + theLabel . pProjCh() + ); + + theLabel . R_Release(); + } + else + { + textprint("unlabelled\n"); + } +} + +// Methods relating to rendering: +void +RebMenus :: Appearance :: Render +( + const RenderContext& theContext, + OurBool bSelected +) const +{ + if + ( + bSelected + ) + { + textprintXY + ( + theContext . Pos() . x-20, + theContext . Pos() . y, + "*" + ); + } + + if ( bHasTextLabel ) + { + SCString& theLabel = StringTable :: GetSCString + ( + ID_Label_Val + ); + + #if 1 + IndexedFont* pFont = IndexedFont :: GetFont + ( + Fonts :: GetIndex + ( + bSelected + ) + ); + // can return NULL if no font loaded in that slot + GLOBALASSERT( pFont ); + + r2pos R2Pos_Cursor = theContext . Pos(); + + pFont -> RenderString_Clipped + ( + R2Pos_Cursor, + theContext . ClipRect(), + Label_FixP_Alpha, + theLabel + ); + #else + textprintXY + ( + theContext . Pos() . x, + theContext . Pos() . y, + theLabel . pProjCh() + ); + #endif + + theLabel . R_Release(); + + } + + if ( bHasBitmap ) + { + #if 1 + textprintXY + ( + theContext . Pos() . x, + theContext . Pos() . y, + "bitmap:\"%s\"; ", + BMapN_Val . Get() + ); + #endif + + Bitmap :: Blit_Transparent + ( + BMapN_Val . Get(), // const char* const pCh_Name, + theContext . ClipRect(), // r2rect R2Rect_Clip, + theContext . Pos() // r2pos dstR2Pos + ); + } +} + +RebMenus :: SizeInfo +RebMenus :: Appearance :: GetSizeInfo(void) const +{ + r2size runningR2Size; + int runningColumn0; + + if ( bHasTextLabel ) + { + SCString& theLabel = StringTable :: GetSCString + ( + ID_Label_Val + ); + + r2size R2Size_Label = theLabel . CalcSize + ( + Fonts :: GetIndex + ( + Yes + // for the moment + ) + ); + + theLabel . R_Release(); + + runningR2Size = R2Size_Label; + runningColumn0 = R2Size_Label . w + ColumnSpacing; + } + else + { + runningR2Size = r2size(0,0); + runningColumn0 = 0; + } + + SizeInfo theSizeInfo + ( + runningR2Size, + runningColumn0 + ); + + if ( bHasBitmap ) + { + theSizeInfo = theSizeInfo . Overlay + ( + SizeInfo + ( + Bitmap :: GetSize + ( + BMapN_Val . Get() + ), + 0 + ) + ); + } + + return theSizeInfo; +} + +RebMenus :: SizeInfo +RebMenus :: OnOffAppearance :: GetSizeInfo(void) const +{ + SizeInfo SizeInfo_On = App_On_Val . GetSizeInfo(); + SizeInfo SizeInfo_Off = App_Off_Val . GetSizeInfo(); + + return SizeInfo_On . Overlay(SizeInfo_Off); +} + + +void +RebMenus :: Item :: DiagnosticAppearance(OurBool bSelected) const +{ + theOnOffApp_Val . GetAppearance(bSelected) . Diagnostic(); +} + + + +// Combined factory/"add to list" methods: +RebMenus :: Item_Unimplemented* +RebMenus :: CompositeItem :: AddUnimplementedItem +( + OnOffAppearance theOnOffApp +) +{ + Item_Unimplemented* pItem = new Item_Unimplemented + ( + theOnOffApp + ); + + AddToList + ( + pItem + ); + + return pItem; +} + +RebMenus :: Item_Command* +RebMenus :: CompositeItem :: AddNewCommandItem +( + OnOffAppearance theOnOffApp, + Command* pCommand +) +{ + GLOBALASSERT( pCommand ); + + Item_Command* pItem = new Item_Command + ( + theOnOffApp, + pCommand + ); + + AddToList + ( + pItem + ); + + return pItem; +} + +RebMenus :: Item_Command* +RebMenus :: CompositeItem :: AddNewJumpItem +( + OnOffAppearance theOnOffApp, + enum PageID theDst +) +{ + Command_JumpToPage* pCommand = new Command_JumpToPage + ( + theDst + ); + + Item_Command* pItem = new Item_Command + ( + theOnOffApp, + pCommand + ); + + pCommand -> R_Release(); + + AddToList + ( + pItem + ); + + return pItem; +} + +RebMenus :: Item_Selection* +RebMenus :: CompositeItem :: AddNewSelectionItem +( + OnOffAppearance theOnOffApp, + enum Direction initDir, + SelectionVariable* pSelectionVar +) +{ + Item_Selection* pItem = new Item_Selection + ( + theOnOffApp, + initDir, + pSelectionVar + ); + + AddToList + ( + pItem + ); + + return pItem; +} + +RebMenus :: Item_Slider* +RebMenus :: CompositeItem :: AddNewSliderItem +( + OnOffAppearance theOnOffApp, + enum Direction initDir, + BoundedExportVariable* pBoundedExpVar +) +{ + Item_Slider* pItem = new Item_Slider + ( + theOnOffApp, + initDir, + pBoundedExpVar + ); + + AddToList + ( + pItem + ); + + return pItem; +} + +RebMenus :: Item_Toggle* +RebMenus :: CompositeItem :: AddNewToggleItem +( + OnOffAppearance theOnOffApp_Label, + enum Direction initDir, + OnOffAppearance theOnOffApp_Choice, + ExportVariable* pExpVar +) +{ + Item_Toggle* pItem = new Item_Toggle + ( + theOnOffApp_Label, + initDir, + theOnOffApp_Choice, + pExpVar + ); + + AddToList + ( + pItem + ); + + return pItem; +} + +RebMenus :: CompositeItem* +RebMenus :: CompositeItem :: AddNewCompositeItem +( + OnOffAppearance theOnOffApp, + enum Direction theD, + enum Alignment theAlignment_New +) +{ + CompositeItem* pItem = new CompositeItem + ( + theOnOffApp, + theD, + theAlignment_New + ); + + AddToList + ( + pItem + ); + + return pItem; +} + +RebMenus :: Item* +RebMenus :: CompositeItem :: AddNewCancelItem +( + OnOffAppearance theOnOffApp +) +{ + Command_ReturnFromPage* pCommand = new Command_ReturnFromPage(); + + Item* pItem = new Item_Command + ( + theOnOffApp, + pCommand + ); + + pCommand -> R_Release(); + + AddToList + ( + pItem + ); + + return pItem; +} + +void +RebMenus :: CompositeItem :: AddNewItem_Special(Item* pItem) +{ + GLOBALASSERT(pItem); + + AddToList(pItem); +} + + +// Process various keypresses: +OurBool +RebMenus :: CompositeItem :: Navigate( enum NavigationOp aNavOp ) +{ + // return = was message processed + + if ( NumItems >0 ) + { + // Pass to selected child for processing: + if + ( + !( GetSelected() -> Navigate( aNavOp ) ) + ) + { + // then selected child couldn't process it, this composite should have a go: + switch ( aNavOp ) + { + case NavOp_Up: + { + if ( theDir == D_Vert ) + { + if ( SelectedItem > 0) + { + SelectedItem--; + GetSelected() -> Selected_Hook + ( + aNavOp + ); + return Yes; + } + else + { + if ( Wraparound :: bEnabled() ) + { + SelectedItem = NumItems-1; + GetSelected() -> Selected_Hook + ( + aNavOp + ); + return Yes; + } + else + { + return No; + } + } + } + else + { + return No; + } + } + case NavOp_Down: + { + if ( theDir == D_Vert ) + { + if ( SelectedItem < (NumItems-1)) + { + SelectedItem++; + GetSelected() -> Selected_Hook + ( + aNavOp + ); + return Yes; + } + else + { + if ( Wraparound :: bEnabled() ) + { + SelectedItem = 0; + GetSelected() -> Selected_Hook + ( + aNavOp + ); + return Yes; + } + else + { + return No; + } + } + } + else + { + return No; + } + } + + case NavOp_Left: + { + if ( theDir == D_Horiz ) + { + if ( SelectedItem > 0) + { + SelectedItem--; + GetSelected() -> Selected_Hook + ( + aNavOp + ); + return Yes; + } + else + { + if ( Wraparound :: bEnabled() ) + { + SelectedItem = NumItems-1; + GetSelected() -> Selected_Hook + ( + aNavOp + ); + return Yes; + } + else + { + return No; + } + } + } + else + { + return No; + } + } + case NavOp_Right: + { + if ( theDir == D_Horiz ) + { + if ( SelectedItem < (NumItems-1)) + { + SelectedItem++; + GetSelected() -> Selected_Hook + ( + aNavOp + ); + return Yes; + } + else + { + if ( Wraparound :: bEnabled() ) + { + SelectedItem = 0; + GetSelected() -> Selected_Hook + ( + aNavOp + ); + return Yes; + } + else + { + return No; + } + } + } + else + { + return No; + } + } + + case NavOp_Home: + { + SelectedItem=0; + GetSelected() -> Selected_Hook + ( + aNavOp + ); + return Yes; + } + + case NavOp_End: + { + SelectedItem=(NumItems-1); + GetSelected() -> Selected_Hook + ( + aNavOp + ); + return Yes; + } + + case NavOp_Trigger: + { + return No; + } + + case NavOp_Cancel: + { + Page :: TryToReturn(); + return Yes; + } + + default: + GLOBALASSERT(0); + } + } + } + // else: no items to navigate + + if ( aNavOp == NavOp_Cancel ) + { + // don't need any items for this to work + Page :: TryToReturn(); + return Yes; + } + + + return No; + +} + +void +RebMenus :: CompositeItem :: Diagnostic(OurBool bSelected) const +{ + { + textprint("CompositeItem ::Diagnostic()... "); + + DiagnosticAppearance(bSelected); + } + + textprint("NumItems=%i\n",NumItems); + + for (int i=0;i" + : + " " + ); + + pItem_A[i]->Diagnostic(i==SelectedItem); + // or should the "selected" nature also depend on whether the + // parent is selected? + } +} + +RebMenus :: Item* +RebMenus :: CompositeItem :: GetSelected(void) const +{ + // will return NULL iff there are no items in the composition + if (NumItems>0) + { + return pItem_A[SelectedItem]; + } + else + { + return NULL; + } +} + +// Methods relating to rendering: +void +RebMenus :: CompositeItem :: Render +( + const RenderContext& theContext, + OurBool bSelected +) const +{ + r2size R2Size_Composite = GetSizeInfo() . GetMin(); + int nonIterationAxisSize_Composite = + ( + theDir == D_Vert + ? + R2Size_Composite . w + : + R2Size_Composite . h + ); + + // Always render appearance (the title) centred + { + SizeInfo titleSizeInfo = AppearanceSizeInfo(); + + r2pos titlePos = theContext . Pos(); + + if ( theDir == D_Vert ) + { + titlePos . x += ( R2Size_Composite . w - titleSizeInfo . GetMin() . w)/2; + } + else + { + titlePos . y += ( R2Size_Composite . h - titleSizeInfo . GetMin() . h)/2; + } + + RenderContext titleContext = RenderContext + ( + theContext . ClipRect(), // r2rect R2Rect_Clip_New, + titlePos, // r2pos R2Pos_At_New, + // top-left hotspot + 0 // int Column0_W_New + // width of 1st column + ); + + RenderAppearance + ( + titleContext, + bSelected + ); + } + + + // Iterate through items, calling Render(): + r2pos R2Pos_I + ( + theContext . Pos() + ); + + // Adjust position for any title: + { + SizeInfo titleSizeInfo = AppearanceSizeInfo(); + + if ( theDir == D_Horiz ) + { + R2Pos_I . x += titleSizeInfo . GetMin() . w + ItemSpacing(); + } + else + { + R2Pos_I . y += titleSizeInfo . GetMin() . h + ItemSpacing(); + } + } + + #if 0 + SizeInfo thisSizeInfo = GetSizeInfo(); + + R2Pos_I . x -= (thisSizeInfo . GetMin() . w/2); + R2Pos_I . y -= (thisSizeInfo . GetMin() . h/2); + #endif + + for (int i=0;i GetSizeInfo() . GetMin(); + + int nonIterationAxisSize_I = + ( + theDir == D_Vert + ? + R2Size_I . w + : + R2Size_I . h + ); + + switch ( theAlignment_Val ) + { + case Align_Min: + { + // means "left-aligned" for V-composition, "top-aligned" for H-Composition + // so leave untouched + } + break; + + case Align_Centre: + { + // means "centred about X" for V-composition, "centred about Y" for H-Composition + // so centre the nonIterationAxis + nonIterationAxisPos_I += ( nonIterationAxisSize_Composite - nonIterationAxisSize_I)/2; + // could be negative; this equation ought to still be valid + } + break; + + case Align_Max: + { + // increase the nonIterationAxis to maximal value that will fit + nonIterationAxisPos_I += ( nonIterationAxisSize_Composite - nonIterationAxisSize_I); + // could be negative; this equation ought to still be valid + } + break; + + default: + GLOBALASSERT(0); + break; + } + + r2pos R2Pos_ToUse = + ( + theDir == D_Vert + ? + r2pos( nonIterationAxisPos_I, theIterationAxisPos_I ) + : + r2pos( theIterationAxisPos_I, nonIterationAxisPos_I ) + ); + + RenderContext yourContext + ( + theContext.ClipRect(), // r2rect R2Rect_Clip_New, + R2Pos_ToUse, // r2pos R2Pos_At_New + theContext.Column0_W() + ); + + pItem_A[i] -> Render + ( + yourContext, + ( + bSelected && (SelectedItem == i) + ) + ); + + if ( theDir == D_Horiz ) + { + R2Pos_I . x += R2Size_I . w + ItemSpacing(); + } + else + { + R2Pos_I . y += R2Size_I . h + ItemSpacing(); + } + } +} + +RebMenus :: SizeInfo +RebMenus :: CompositeItem :: GetSizeInfo(void) const +{ + SizeInfo SizeInfo_ToReturn + ( + #if 1 + r2size(0,0), + 0 + #else + AppearanceSizeInfo() . GetMin(), + AppearanceSizeInfo() . GetColumn0_minW() + #endif + ); + + for (int i=0;i GetSizeInfo(); + + #if 1 + SizeInfo_ToReturn . Compose + ( + itemSizeInfo, + theDir, + theAlignment_Val + ); + + #else + + r2size ItemSize_Min = itemSizeInfo . GetMin(); + + if ( theDir == D_Horiz ) + { + AppSize_Min . HCompose + ( + ItemSize_Min + ); + + if (i!=0) + { + AppSize_Min . w += ItemSpacing(); + } + } + else + { + AppSize_Min . VCompose + ( + ItemSize_Min + ); + + if ( max_Column0_minW < itemSizeInfo . GetColumn0_minW() ) + { + max_Column0_minW = itemSizeInfo . GetColumn0_minW(); + } + + if (i!=0) + { + AppSize_Min . h += ItemSpacing(); + } + } + #endif + } + + #if 1 + return SizeInfo_ToReturn; + #else + return SizeInfo + ( + AppSize_Min, + max_Column0_minW + ); + #endif +} + + +// private: +void +RebMenus :: CompositeItem :: AddToList +( + Item* pItem_ToAdd +) +{ + GLOBALASSERT(NumItems < MAX_ITEMS_PER_LIST ); + + pItem_A[ NumItems++ ] = pItem_ToAdd; + + + if (NumItems == 1) + { + // then this was the first item added: + SelectedItem = 0; + } +} + +// static +int RebMenus :: CompositeItem :: ItemSpacing(void) +{ + return 2; +} + + +void +RebMenus :: Page :: MiniStack :: Push(enum PageID in) +{ + if (NumItems < NUM_PAGES_MEMORY) + { + theA[ NumItems++ ] = in; + } + else + { + // one falls off the bottom; shuffle everything up + GLOBALASSERT( NumItems == NUM_PAGES_MEMORY ); + + for (int i=0;i<(NUM_PAGES_MEMORY-1);i++) + { + theA[i] = theA[i+1]; + } + + // ...and set the end element: + theA[NUM_PAGES_MEMORY-1] = in; + } +} + +OurBool +RebMenus :: Page :: MiniStack :: Pop(enum PageID& out) +{ + // return value: was there anything? + if ( NumItems > 0) + { + out = theA[--NumItems]; + return Yes; + } + else + { + return No; + } +} + +void +RebMenus :: Page :: MiniStack :: Diagnostic(void) +{ + textprint("page stack: num pages = %i\n",NumItems); + + for (int i=0;i=0); + GLOBALASSERT(inID=0); + GLOBALASSERT(inID Hook_LeavingPage(); + + // Set the all-important variable: + SelectedPageID = inID; + + // Call hook for entering the new page: + GetSelected() -> Hook_EnteringPage(); +} + + +// private: +// static +RebMenus :: Page* RebMenus :: Page :: pPage[ NUM_PAGE_IDS ]; +// static +enum PageID RebMenus :: Page :: SelectedPageID = PageID_Initial; +// static +RebMenus :: Page :: MiniStack +RebMenus :: Page :: thePageStack; + + +// class Wraparound +// static +const OurBool RebMenus :: Wraparound :: bEnabled_Val = Yes; + +// Globals within RebMenus: +void RebMenus :: Init(void) +{ + ProjectSpecific :: Init(); +} + +void RebMenus :: UnInit(void) +{ + ProjectSpecific :: UnInit(); + + // Destroy all menu pages: + { + + } +} + +void RebMenus :: Maintain(void) +{ + textprint("RebMenus::Maintain()\n"); + + ProjectSpecific :: Maintain(); + + #if 1 + { + Page* pPage = Page :: GetSelected(); + GLOBALASSERT( pPage ); + + pPage -> Diagnostic(Yes); + } + #endif +} + +// static +void +RebMenus :: Render(void) +{ + textprint("RebMenus :: Render()\n"); + + Page* pPage = Page :: GetSelected(); + GLOBALASSERT( pPage ); + + SizeInfo theSizeInfo = pPage -> GetSizeInfo(); + + pPage -> Render + ( + RenderContext + ( + r2rect::PhysicalScreen(), // r2rect R2Rect_Clip_New, + + r2rect::PhysicalScreen() . CentredWithSize_TL + ( + theSizeInfo . GetMin() + ), // r2pos R2Pos_At_New + + theSizeInfo . GetColumn0_minW() // int Column0_W_New + ), + Yes //OurBool bSelected + ); +} + + +// namespace Bitmap +namespace RebMenus +{ + namespace Bitmap + { + class Implementation + { + private: + class CacheEntry + { + public: + CacheEntry + ( + const char* const pCh_Name_New + ); + ~CacheEntry(); + + static void Empty(void) + { + while (List_pCacheEntry . size() > 0) + { + delete List_pCacheEntry . first_entry(); + } + } + + void Blit_Transparent + ( + r2rect R2Rect_Clip, + r2pos dstR2Pos + ); + + r2size GetSize(void) const + { + return R2Size; + } + + static CacheEntry* Get(const char* const pCh_Name); + + private: + const char* const pCh_Name_Val; + LPDIRECTDRAWSURFACE pSurface; + AW_BACKUPTEXTUREHANDLE hBackup; + r2size R2Size; + + static List List_pCacheEntry; + // maintains a set of all of these + // really ought to do this as a hash table (potentially using Jake's + // template), but no need for the moment + }; + private: + + + + public: + static void Precache(const char* const pCh_Name) + { + new CacheEntry(pCh_Name); + } + + static void UnCache(const char* const pCh_Name) + { + CacheEntry* pEntry = CacheEntry :: Get(pCh_Name); + + if (!pEntry) { return; } + + delete pEntry; + } + + static void EmptyCache(void) + { + CacheEntry :: Empty(); + } + + static void Blit_Transparent + ( + const char* const pCh_Name, + r2rect R2Rect_Clip, + r2pos dstR2Pos + ) + { + CacheEntry* pEntry = CacheEntry :: Get(pCh_Name); + + if (!pEntry) + { + pEntry = new CacheEntry(pCh_Name); + } + + GLOBALASSERT( pEntry ); + + pEntry -> Blit_Transparent + ( + R2Rect_Clip, + dstR2Pos + ); + } + static r2size GetSize(const char* const pCh_Name) + { + CacheEntry* pEntry = CacheEntry :: Get(pCh_Name); + + if (!pEntry) + { + pEntry = new CacheEntry(pCh_Name); + } + + GLOBALASSERT( pEntry ); + + return pEntry -> GetSize(); + } + + }; + }; +}; + +RebMenus :: Bitmap :: Implementation :: CacheEntry :: CacheEntry +( + const char* const pCh_Name_New +) : pCh_Name_Val(pCh_Name_New) +{ + unsigned nWidth,nHeight; + + pSurface = AwCreateSurface + ( + "sfXYB", + pCh_Name_Val, + ( + 0 + ), // flags + &nWidth, + &nHeight, + &hBackup + ); + ATIncludeSurface(pSurface,hBackup); + + + R2Size . w = nWidth; + R2Size . h = nHeight; + + List_pCacheEntry . add_entry(this); +} + +RebMenus :: Bitmap :: Implementation :: CacheEntry :: ~CacheEntry() +{ + List_pCacheEntry . delete_entry(this); + + GLOBALASSERT(pSurface); + ATRemoveSurface(pSurface); + ReleaseDDSurface(pSurface); + pSurface = NULL; + + if (hBackup) + { + AwDestroyBackupTexture(hBackup); + } + + hBackup = NULL; + +} + +void +RebMenus :: Bitmap :: Implementation :: CacheEntry :: Blit_Transparent +( + r2rect R2Rect_Clip, + r2pos dstR2Pos +) +{ + if + ( + r2rect + ( + dstR2Pos, + GetSize() + ) . bFitsIn( R2Rect_Clip ) + ) + { + RECT destRect; + + destRect.left = dstR2Pos . x; + destRect.top = dstR2Pos . y; + + destRect.right = dstR2Pos . x + R2Size . w; + destRect.bottom = dstR2Pos . y + R2Size . h; + + + RECT srcRect; + + srcRect.left =0; + srcRect.top =0; + srcRect.right = R2Size . w; + srcRect.bottom = R2Size . h; + + #if 1 + DDBLTFX tempDDBltFx; + + memset(&tempDDBltFx,0,sizeof(DDBLTFX)); + + tempDDBltFx . dwSize = sizeof(DDBLTFX); + tempDDBltFx . ddckSrcColorkey . dwColorSpaceLowValue = 0; + tempDDBltFx . ddckSrcColorkey . dwColorSpaceHighValue = 0; + #endif + + HRESULT ddrval = lpDDSBack->Blt + ( + &destRect, + pSurface, + #if 1 + NULL, + #else + &srcRect, + #endif + ( + DDBLT_WAIT + #if 0 + | DDBLT_KEYSRC + #else + | DDBLT_KEYSRCOVERRIDE + #endif + ), + &tempDDBltFx // LPDDBLTFX lpDDBltFx + ); + + #if 0 + if(ddrval != DD_OK) + { + ReleaseDirect3D(); + exit(0x666009); + } + #endif + } + // else reject as I can't be bothered to write clipping code +} + +// static +RebMenus :: Bitmap :: Implementation :: CacheEntry* +RebMenus :: Bitmap :: Implementation :: CacheEntry :: Get(const char* const pCh_Name) +{ + GLOBALASSERT( pCh_Name ); + + // A simple linear search for now: + for + ( + LIFoi(&List_pCacheEntry); + !oi . done(); + oi . next() + ) + { + if + ( + strcmp + ( + pCh_Name, + oi() -> pCh_Name_Val + ) == 0 + ) + { + return oi(); + } + } + return NULL; +} + +// static +List +RebMenus :: Bitmap :: Implementation :: CacheEntry :: List_pCacheEntry; + + +void +RebMenus :: Bitmap :: Precache(const char* const pCh_Name) +{ + GLOBALASSERT( pCh_Name ); + + Implementation :: Precache(pCh_Name); +} + +void +RebMenus :: Bitmap :: UnCache(const char* const pCh_Name) +{ + GLOBALASSERT( pCh_Name ); + Implementation :: UnCache(pCh_Name); +} + +void +RebMenus :: Bitmap :: EmptyCache(void) +{ + Implementation :: EmptyCache(); +} +void +RebMenus :: Bitmap :: Blit_Transparent +( + const char* const pCh_Name, + r2rect R2Rect_Clip, + r2pos dstR2Pos +) +{ + GLOBALASSERT( pCh_Name ); + Implementation :: Blit_Transparent + ( + pCh_Name, + R2Rect_Clip, + dstR2Pos + ); +} + +r2size +RebMenus :: Bitmap :: GetSize(const char* const pCh_Name) +{ + GLOBALASSERT( pCh_Name ); + + return Implementation :: GetSize(pCh_Name); +} + +#endif + // UseRebMenus + + + + + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/support/rebmenus.hpp b/3dc/avp/support/rebmenus.hpp new file mode 100644 index 0000000..3b18509 --- /dev/null +++ b/3dc/avp/support/rebmenus.hpp @@ -0,0 +1,981 @@ +/* + + rebmenus.hpp + +*/ + +#ifndef _rebmenus_hpp +#define _rebmenus_hpp 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + +/* Version settings *****************************************************/ + #define UseRebMenus Yes + // If this is set, then the new menus are compiled in, and take + // effect in-game + // If this is set to no, then the new menus don't compile in + + #define OverrideOldMenus Yes + // If this is set, then the new menus also override the out-of-game + // menus. Don't set this without setting UseRebMenus + + #define SupportTextprintBeforeGame No + // however, this causes a problem in the second call + // to InitialiseTextures(), but only outside the debugger, + // so it's a real pain to debug + +/* Includes *************************************************************/ +#if UseRebMenus + #ifdef __cplusplus + #ifndef _ourbool + #include "ourbool.h" + #endif + + #if 0 + #ifndef _scstring + #include "scstring.hpp" + #endif + #endif + + #ifndef _command + #include "command.hpp" + #endif + + #ifndef _r2base + #include "r2base.h" + #endif + + #if 0 + // Expects an enum "FontIndex" for the font to be defined in PROJFONT.H + #ifndef _projfont + #include "projfont.h" + #endif + #endif + + #ifndef _expvar_hpp + #include "expvar.hpp" + #endif + + #ifndef _projmenu_hpp + #include "projmenu.hpp" + // Include project specific header. + /* + It is assumed that this project specific header will define + the following: + + - an "enum PageID" enumeration of the various pages in the menus; + they must range in value from 0 inclusive to NUM_PAGE_IDS exclusive + (currently gaps are allowed in the range, but an array of pointers + gets defined so don't be excessive) + + - a TextID typedef giving an enumeration of text string IDs from + the language localisation table + + - functions: + void Init(void) + void UnInit(void) + void Maintain(void) + within scope ProjectSpecific (either namespace or public static in a class) + inside namespace RebMenus. They can be empty, but typically + you should construct your menu pages within them. + + - a scope (class or namespace) Fonts containing + ( static ) + FontIndex RebMenus :: Fonts :: GetIndex(OurBool bSelected) + to tell the text code which font to use for labels + */ + + #endif + #endif + /* __cplusplus */ +#endif + // UseRebMenus + + + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ +#if UseRebMenus +#ifdef __cplusplus + #define DUMMY_TEXTID ((TextID)0) + +namespace RebMenus +{ + #if 0 + // perhaps has some kind of message passing hook: + class Message + { + }; + // derived classes for keydown messages, mouse messages, etc + // But how is it interrogated? + // (you have two class hierarchies, with a single process fn) + // + // What class have I forgotten? + + // need a class with somd kind of hook for either processing + // a messages, or passing it down the chain of responsibility + // (a boolean return type to say whether it's been processed?) + + class MessageProcessor + { + + }; + + class Selectable : MessageProcessor //????? + { + }; + #endif + enum Direction + { + D_Horiz, + D_Vert + }; + + enum Alignment + { + Align_Min, + // means "left-aligned" for V-composition, "top-aligned" for H-Composition + + Align_Centre, + // means "centred about X" for V-composition, "centred about Y" for H-Composition + + Align_Max + // means "right-aligned" for V-composition, "bottom-aligned" for H-Composition + + }; + + enum NavigationOp + { + NavOp_Up = 0, + NavOp_Down, + NavOp_Left, + NavOp_Right, + NavOp_Home, + NavOp_End, + NavOp_Trigger, + NavOp_Cancel, + + NUM_NAVIGATION_OPS + }; + + // Name of a bitmap, for referring to bitmaps in an appearance: + class BitmapName + { + public: + BitmapName + ( + char* pCh_New + ) : pCh_Val(pCh_New) + { + } + BitmapName() : pCh_Val(NULL) + { + } + const char* const Get(void) const + { + return pCh_Val; + } + + private: + const char* const pCh_Val; + }; + + // Name of an FMV sequence, for referring to FMV sequences in an appearance: + class FMVName + { + public: + FMVName + ( + char* pCh_New + ) : pCh_Val(pCh_New) + { + } + FMVName() : pCh_Val(NULL) + { + } + const char* const Get(void) const + { + return pCh_Val; + } + + private: + const char* const pCh_Val; + }; + + namespace Bitmap + { + void Precache(const char* const pCh_Name); + void UnCache(const char* const pCh_Name); + void EmptyCache(void); + + void Blit_Transparent + ( + const char* const pCh_Name, + r2rect R2Rect_Clip, + r2pos dstR2Pos + ); + + r2size GetSize(const char* const pCh_Name); + }; + + // Menu-specific commands: + class Command_JumpToPage : public Command + { + public: + Command_JumpToPage + ( + enum PageID thePage + ) : Command(), + thePage_Val(thePage) + { + } + OurBool Execute(void); + + private: + const enum PageID thePage_Val; + }; + + class Command_ReturnFromPage : public Command + { + public: + OurBool Execute(void); + }; + + // Class for describing size requirements of things in the menus + // Currently only support a "minimum size" idea + class SizeInfo + { + public: + SizeInfo + ( + r2size minR2Size, + int Column0_minW + ) : minR2Size_Val(minR2Size), + Column0_minW_Val(Column0_minW) + { + } + r2size GetMin(void) const + { + return minR2Size_Val; + } + int GetColumn0_minW(void) const + { + return Column0_minW_Val; + } + + SizeInfo Overlay + ( + SizeInfo other + ); + + SizeInfo AddColumn + ( + SizeInfo nextColumn + ); + + SizeInfo AddRow + ( + SizeInfo nextRow + ); + + void Compose + ( + const SizeInfo& other, + enum Direction theD, + enum Alignment theAl + ); + private: + r2size minR2Size_Val; + int Column0_minW_Val; + + }; + + + class RenderContext + { + public: + RenderContext + ( + r2rect R2Rect_Clip_New, + r2pos R2Pos_At_New, + // top-left hotspot + int Column0_W_New + // width of 1st column + ) : R2Rect_Clip_Val(R2Rect_Clip_New), + R2Pos_At_Val(R2Pos_At_New), + Column0_W_Val(Column0_W_New) + { + } + r2rect ClipRect(void) const {return R2Rect_Clip_Val;} + r2pos Pos(void) const {return R2Pos_At_Val;} + int Column0_W(void) const {return Column0_W_Val;} + r2pos Pos_Column1(void) const + { + return r2pos + ( + R2Pos_At_Val . x + Column0_W_Val, + R2Pos_At_Val . y + ); + } + + RenderContext NextColumn(void) const + { + return RenderContext + ( + R2Rect_Clip_Val, + Pos_Column1(), + 0 + ); + } + + private: + r2rect R2Rect_Clip_Val; + r2pos R2Pos_At_Val; + int Column0_W_Val; + }; + + // 9/3/98 DHM: A "policy" pattern for what an item sould look like: + // ("Design Patterns" would call it a "strategy", but since that word + // is already overused in 3DC et al I prefer the alternate name "policy") + class Appearance + { + public: + // Use just a text label: + Appearance + ( + TextID ID_Label + ) : bHasTextLabel(Yes), + ID_Label_Val(ID_Label), + bHasBitmap(No), + bHasFMV(No) + { + } + + // Use just a bitmap: + Appearance + ( + BitmapName inBMapName + ) : bHasTextLabel(No), + ID_Label_Val(DUMMY_TEXTID), + bHasBitmap(Yes), + BMapN_Val(inBMapName), + bHasFMV(No) + { + } + + // Don't have any appearance at all = invisible + Appearance + ( + ) : bHasTextLabel(No), + ID_Label_Val(DUMMY_TEXTID), + bHasBitmap(No), + bHasFMV(No) + { + } + + // Other possible appearances might be: + // - bitmaps, + // - fmv sequences, + // - combos of the above + // etc + + void Diagnostic(void) const; + + // Methods relating to rendering: + void Render + ( + const RenderContext& theContext, + OurBool bSelected + ) const; + + SizeInfo GetSizeInfo(void) const; + + private: + const OurBool bHasTextLabel; + const TextID ID_Label_Val; + + const OurBool bHasBitmap; + const BitmapName BMapN_Val; + + const OurBool bHasFMV; + const FMVName FMVN_Val; + }; + + // An appearance with two states: + class OnOffAppearance + { + public: + // Constructors + OnOffAppearance + ( + Appearance App_On, + Appearance App_Off + ) : App_On_Val(App_On), + App_Off_Val(App_Off) + { + // most general constructor: independent appearances, one for + // "on", the other for "off" + } + + OnOffAppearance + ( + Appearance App_Shared + ) : App_On_Val(App_Shared), + App_Off_Val(App_Shared) + { + // easy way to give something the same appearance both on and off + } + + OnOffAppearance + ( + TextID ID_Label + ) : App_On_Val(Appearance(ID_Label)), + App_Off_Val(Appearance(ID_Label)) + { + // easy way of setting up a text label + } + + OnOffAppearance + ( + ) : App_On_Val(Appearance()), + App_Off_Val(Appearance()) + { + // easy way to set up something as invisible both on and off + } + + + Appearance GetAppearance(OurBool bOn) const + { + return + ( + bOn + ? + App_On_Val + : + App_Off_Val + ); + } + + SizeInfo GetSizeInfo(void) const; + + private: + Appearance App_On_Val; + Appearance App_Off_Val; + }; + + class SelectionVariable + { + protected: + SelectionVariable + ( + BoundedExportVariable* pBoundedExpVar + // takes responsibility for deleting this + ) : pBoundedExpVar_Val(pBoundedExpVar) + { + } + + public: + virtual ~SelectionVariable() + { + delete pBoundedExpVar_Val; + } + + virtual Appearance GetAppearance(OurBool bSelected) = 0; + + // Chain-of-responsibility onto the bounded export var: + int Get(void) const + { + return pBoundedExpVar_Val -> Get(); + } + + int GetMin(void) const + { + return pBoundedExpVar_Val -> GetMin(); + } + int GetMax(void) const + { + return pBoundedExpVar_Val -> GetMax(); + } + int GetNxt(void) const + { + int CurrentVal = pBoundedExpVar_Val -> Get(); + if ( CurrentVal < pBoundedExpVar_Val -> GetMax() ) + { + return ++CurrentVal; + } + else + { + return pBoundedExpVar_Val -> GetMin(); + } + } + int GetPrv(void) const + { + int CurrentVal = pBoundedExpVar_Val -> Get(); + if ( CurrentVal > pBoundedExpVar_Val -> GetMin() ) + { + return --CurrentVal; + } + else + { + return pBoundedExpVar_Val -> GetMax(); + } + } + void Set(int NewVal) + { + pBoundedExpVar_Val -> Set(NewVal); + } + + private: + BoundedExportVariable* pBoundedExpVar_Val; + }; + + + + // Class for a list of discrete selections with appearances and values: + template class Selection + { + class Selectable + { + public: + Selectable + ( + Appearance theApp, + T theValue + ) : App_Val(theApp), + T_Val(theValue) + { + } + Appearance GetAppearance(void) const + { + return App_Val; + } + T GetValue(void) const + { + return T_Val; + } + private: + const Appearance App_Val; + const T T_Val; + }; + + class SelectionList + { + public: + SelectionList + ( + ) : NumInList(0) + { + } + + ~SelectionList(); + + AddSelection + ( + Selectable Sel_ToAdd + ) + { + if ( NumInList < MAX_IN_LIST ) + { + theSel_A[NumInList++] = Sel_ToAdd; + } + } + private: + int NumInList; + Selectable theSel_A[MAX_IN_LIST]; + }; + }; + + + class Item + { + public: + OurBool bSelectable(void); + // items can be temporarily or permanently unselectable + // e.g. "greyed out" + + /////////////// PURE VIRTUAL FUNCTIONS /////////////////////////////// + public: + // Process various keypresses: + virtual OurBool Navigate( enum NavigationOp aNavOp ) = 0; + // return = was message processed + + virtual void Diagnostic(OurBool bSelected) const = 0; + + virtual void Render + ( + const RenderContext& theContext, + OurBool bSelected + ) const = 0; + + virtual SizeInfo GetSizeInfo(void) const = 0; + + + public: + void DiagnosticAppearance(OurBool bSelected) const; + + // Methods relating to rendering: + void RenderAppearance + ( + const RenderContext& theContext, + OurBool bSelected + ) const + { + theOnOffApp_Val . GetAppearance + ( + bSelected + ) . Render + ( + theContext, + bSelected + ); + } + SizeInfo AppearanceSizeInfo(void) const + { + return theOnOffApp_Val . GetSizeInfo(); + } + + + public: + virtual void Selected_Hook + ( + enum NavigationOp // theNavOp + ) + { + // empty default implementation + } + + protected: + Item + ( + OnOffAppearance theOnOffApp_New + ) : theOnOffApp_Val(theOnOffApp_New) + { + // empty inline constructor; but protected so must use + // a derived class. + } + + virtual ~Item() + { + } + + private: + OnOffAppearance theOnOffApp_Val; + }; + + // Proposed derived classes of Item: + class Item_Unimplemented; + + class Item_Command; + // contains a command; can contain a "goto menu page" command + + class Item_Selection; + + class Item_Slider; + + class Item_Toggle; + + class Item_KeyConfig_PageView; + + // A composition of items. + // There will exist a selected item iff there are any items contained + // in this composition + class CompositeItem : public Item + { + public: + CompositeItem + ( + OnOffAppearance theOnOffApp_New, + enum Direction theD, + enum Alignment theAlignment_New + ) : Item(theOnOffApp_New), + theDir(theD), + theAlignment_Val(theAlignment_New), + NumItems(0) + { + // what value should SelectedItem have when there aren't any items? + } + + // Combined factory/"add to list" methods: + Item_Unimplemented* AddUnimplementedItem + ( + OnOffAppearance theOnOffApp + ); + + Item_Command* AddNewCommandItem + ( + OnOffAppearance theOnOffApp, + Command* pCommand + ); + + Item_Command* AddNewJumpItem + ( + OnOffAppearance theOnOffApp, + enum PageID theDst + ); + + Item_Selection* AddNewSelectionItem + ( + OnOffAppearance theOnOffApp, + enum Direction initDir, + SelectionVariable* pSelectionVar + ); + + Item_Slider* AddNewSliderItem + ( + OnOffAppearance theOnOffApp, + enum Direction initDir, + BoundedExportVariable* pBoundedExpVar + ); + + Item_Toggle* AddNewToggleItem + ( + OnOffAppearance theOnOffApp_Label, + enum Direction initDir, + OnOffAppearance theOnOffApp_Choice, + ExportVariable* pExpVar + ); + + CompositeItem* AddNewCompositeItem + ( + OnOffAppearance theOnOffApp, + enum Direction theD, + enum Alignment theAlignment_New + ); + + Item* AddNewCancelItem + ( + OnOffAppearance theOnOffApp + ); + + void AddNewItem_Special(Item* pItem); + + // Process various keypresses: + OurBool Navigate( enum NavigationOp aNavOp ); + // return = was message processed + + virtual void Diagnostic(OurBool bSelected) const; + + Item* GetSelected(void) const; + // will return NULL iff there are no items in the composition + + // Get index of next selectable + #if 0 + // what if all disabled? + + // what if wraparound turned off? + + ItemIndex NxtSelectable(void) const; + ItemIndex PrvSelectable(void) const; + #endif + + // Methods relating to rendering: + virtual void Render + ( + const RenderContext& theContext, + OurBool bSelected + ) const; + + virtual SizeInfo GetSizeInfo(void) const; + + + private: + void AddToList + ( + Item* pItem_ToAdd + ); + static int ItemSpacing(void); + + // List of selectables: + enum {MAX_ITEMS_PER_LIST = 20}; + + int NumItems; + Item* pItem_A[ MAX_ITEMS_PER_LIST ]; + + #if 1 + int SelectedItem; + #else + // Selected item: + IndexInRange theIIR; + #endif + + // Direction: + const enum Direction theDir; + + // Alignment: + const enum Alignment theAlignment_Val; + + // selection list contains a list of selectables; + // has a selected child. + + // Has an "enum direction": + // if D_Horiz, interprets left/right as moving the selection + // if D_Vert, interprets up/down as moving the selection + + // Considered doing it with two separate classes, but makes it nasty + // to derive stuff off them + + }; + + + class Page : public CompositeItem + { + // This class maintains a static array + // mapping of PageIDs to Page*s + // There can be at most one Page of each ID; the class implements + // a kind of array of singletons + // (See "Design Patterns" Addison-Wesley 1994) + + // The precise classes derived from Page are project-specific. A project might + // choose to derive a new class used by all of its pages, or have + // a separate class for each page, or any combination in between. + + // An internal class for storing a history of menu pages visited: + class MiniStack + { + // A small stack; when it gets full, the items + // at the bottom are lost + // Originally done as a template, but Jonathon told be to stop being too + // clever for my own good... + + public: + enum { NUM_PAGES_MEMORY = 16 }; + + public: + MiniStack() : NumItems(0) + { + } + + void Push(enum PageID in); + + OurBool Pop(enum PageID& out); + // return value: was there anything? + + void Diagnostic(void); + + void Clear(void); + + private: + int NumItems; + enum PageID theA[ NUM_PAGES_MEMORY ]; + }; + + protected: + Page + ( + Appearance theApp_New, + enum Direction theD, + enum Alignment theAlignment_New, + PageID theID + ); + + ~Page(); + + public: + void Diagnostic(OurBool bSelected) const; + + static void SelectPage(enum PageID inID); + static void SelectPage_ClearingStack(enum PageID inID); + static void TryToReturn(void); + + static Page* Get(enum PageID inID); + static Page* GetSelected(void); + + private: + // Every page can have hook functions for entering/leaving the page + // These are private since they're only to be called by the page selection + // function + // Default implementation is empty; specific pages can override this. + virtual void Hook_EnteringPage(void) + { + } + virtual void Hook_LeavingPage(void) + { + } + + private: + static void Internal_SelectPage_NoPush( enum PageID inID ); + // Worker function to call hooks and actually change the page + // Used by SelectPage() and TryToReturn() + // Doesn't push current page onto page stack + + + private: + + const PageID theID_Val; + static Page* pPage[ NUM_PAGE_IDS ]; + + static enum PageID SelectedPageID; + + static MiniStack thePageStack; + }; + + + // What happens if you compose various levels of selection list? + // + + // Is a menu page a type of selection list; if so, how does it respond + // to cursor keys? + + // + + // now + + class Wraparound + { + public: + static OurBool bEnabled(void) + { + return bEnabled_Val; + } + + private: + const static OurBool bEnabled_Val; + }; + + // Globals within RebMenus: + void Init(void); + void UnInit(void); + void Maintain(void); + void Render(void); + + +}; // end of namespace RebMenus +#endif // __cplusplus +#endif // UseRebMenus +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + + extern void REBMENUS_ProjectSpecific_EndOfMainLoopHook(void); + +#ifdef __cplusplus + }; +#endif + +/* End of the header ****************************************************/ + + +#endif + + + + + + + + + + + + + + diff --git a/3dc/avp/support/reflist.cpp b/3dc/avp/support/reflist.cpp new file mode 100644 index 0000000..1757022 --- /dev/null +++ b/3dc/avp/support/reflist.cpp @@ -0,0 +1,17 @@ +/******************************************************************* + * + * DESCRIPTION: reflist.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 28/1/98 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "reflist.hpp" + +/* Exported globals ************************************************/ + + char const* reflist_fail_destructor = "Failure in RefList destructor\n"; diff --git a/3dc/avp/support/reflist.hpp b/3dc/avp/support/reflist.hpp new file mode 100644 index 0000000..cf91549 --- /dev/null +++ b/3dc/avp/support/reflist.hpp @@ -0,0 +1,174 @@ +/* + + REFLIST.HPP + + Created 27/1/98 by DHM: + ----------------------- + + Template for managing lists of pointers to reference-counted objects. + + The functions R_AddRef() and R_Release() must be defined for the type parameter. + + Uses the list template LIST_TEM.HPP + + The access functions return pointers to objects, or NULL for failure. The rule + is that: + + Read() + ------ + just returns a pointer; the caller should R_AddRef() only if they want to store the pointer + somewhere (like the COM out-parameter rule; see p81 of "Inside COM") + + GetYour() + --------- + destructively reads the pointer from the list; ownership of the reference is transferred + to the caller who _must_ call R_Release() at some subsequent point. + +*/ + +#ifndef _reflist_hpp +#define _reflist_hpp 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + + #ifndef list_template_hpp + #include "list_tem.hpp" + #endif + + #ifndef _refobj + #include "refobj.hpp" + #endif + +extern char const* reflist_fail_destructor; + + +/* Type definitions *****************************************************/ + +// nb templates cannot have C linkage +template class RefList +{ +private: + List List_pRC; + +public: + // {{{ Constructors: + RefList() : List_pRC() + { + } + // }}} + + // {{{ Destructor + ~RefList() + { + EmptyYourself(); + } + // }}} + + // {{{ + int NumEntries(void) const + { + return List_pRC . size(); + } + // }}} + + // {{{ Inserting new members + void AddToFront(RC& theRC) + { + theRC . R_AddRef(); + + List_pRC . add_entry_start( &theRC ); + } + void AddToEnd(RC& theRC) + { + theRC . R_AddRef(); + + List_pRC . add_entry_end( &theRC ); + } + // }}} + + // {{{ Accessing & removing existing members; see notes at top of header + RC* ReadFirst(void) const + { + if (List_pRC . size() >0 ) + { + return List_pRC . first_entry(); + } + else + { + return NULL; + } + } + RC* ReadFinal(void) const + { + if (List_pRC . size() >0 ) + { + return List_pRC . last_entry(); + } + else + { + return NULL; + } + } + RC* GetYourFirst(void) + { + if (List_pRC . size() >0 ) + { + RC* pReturn = List_pRC . first_entry(); + + List_pRC . delete_first_entry(); + // note that a reference is still owned; ownership is transferred to the caller + + return pReturn; + } + else + { + return NULL; + } + } + RC* GetYourFinal(void) + { + if (List_pRC . size() >0 ) + { + RC* pReturn = List_pRC . last_entry(); + + List_pRC . delete_last_entry(); + // note that a reference is still owned; ownership is transferred to the caller + + return pReturn; + } + else + { + return NULL; + } + } + void EmptyYourself(void) + { + // Destroys the list, releasing all refs + while ( List_pRC . size() > 0 ) + { + RC* pRC = List_pRC . first_entry(); + + List_pRC . delete_first_entry(); + + #ifndef NDEBUG + if ( !pRC ) + { + fail( reflist_fail_destructor ); + } + #endif + + pRC -> R_Release(); + } + } + // }}} + + +}; // end of template class RefList + + +/* End of the header ****************************************************/ + + +#endif diff --git a/3dc/avp/support/refobj.cpp b/3dc/avp/support/refobj.cpp new file mode 100644 index 0000000..e1c4181 --- /dev/null +++ b/3dc/avp/support/refobj.cpp @@ -0,0 +1,339 @@ +/******************************************************************* + * + * DESCRIPTION: refobj.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 15/9/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "refobj.hpp" + + #if TrackReferenceCounted + #include "dcontext.hpp" + + #ifndef list_template_hpp + #include "list_tem.hpp" + #endif + #endif + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + #if TrackReferenceCounted + #define OutputRefCountLogOnExit Yes + + + #if OutputRefCountLogOnExit + #include "debuglog.hpp" + #endif + + + #endif + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + char const* refobj_fail_addref = "Failure in R_AddRef()\n"; + char const* refobj_fail_release = "Failure in R_Release()\n"; + char const* refobj_fail_destructor = "Failure in Destructor()\n"; + +/* Internal type definitions ***************************************/ +#if TrackReferenceCounted +class RefCountObject_TrackData +{ +public: + enum transtype + { + tt_addref, + tt_release + }; + +private: + class ReferenceTransaction + { + public: + void Dump( R_DumpContext& theContext ) const; + + private: + char* Filename; + int LineNum; + enum transtype Type; + + protected: + ReferenceTransaction(char* theFilename, int theLineNum, enum transtype theType) : + Filename(theFilename), + LineNum(theLineNum), + Type(theType) + {} + }; + + class Transaction_R_AddRef : public ReferenceTransaction + { + public: + Transaction_R_AddRef(char* theFilename, int theLineNum) : + ReferenceTransaction(theFilename, theLineNum, tt_addref) + {} + }; + + class Transaction_R_Release : public ReferenceTransaction + { + public: + Transaction_R_Release(char* theFilename, int theLineNum) : + ReferenceTransaction(theFilename, theLineNum, tt_release) + {} + }; + +public: + static void DumpAll(R_DumpContext& theContext); + + RefCountObject_TrackData(RefCountObject *const pRCObj, char* theFilename, int theLineNum); + ~RefCountObject_TrackData(); + + void Track_R_AddRef(char* theFilename, int theLineNum); + void Track_R_Release(char* theFilename, int theLineNum); + + void DumpTransactions( R_DumpContext& theContext ) const; + +private: + RefCountObject *const pRCObj_Val; + char* constructionFilename; + int constructionLineNum; + List List_pTransaction; + +private: + /* + Maintain various global stuff. + This is all held together as a BSS object so that we can be sure that we call + the log-on-exit in the destructor before destroying the records of what hasn't + been fully released. + + We maintain a list of all reference counted objects, which the class RefCountObject + has indirect access to. + + */ + class Globals + { + friend class RefCountObject_TrackData; + + private: + List List_pRCObj; + #if OutputRefCountLogOnExit + char* filename; + #endif + public: + #if OutputRefCountLogOnExit + Globals(char* theFilename) : + filename(theFilename), + #else + Globals() : + #endif + List_pRCObj() + { + } + ~Globals(); + + }; + + static Globals theGlobals; +}; + + + static RefCountObject_TrackData :: Globals RefCountObject_TrackData :: theGlobals + ( + #if OutputRefCountLogOnExit + "REFDUMP.TXT" + #endif + ); + + #if 0 + static List RefCountObject_TrackData :: TheList :: List_pRCObj; + #endif + + + +#endif +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ + +// class RefCountObject +#if TrackReferenceCounted +void RefCountObject :: Track_Construct(void) +{ + GLOBALASSERT( pTrackData == NULL ); + + pTrackData = new RefCountObject_TrackData(this,"unknown file",666); +} + +void RefCountObject :: Track_R_AddRef(char* theFilename, int theLineNum) +{ + GLOBALASSERT( pTrackData ); + + pTrackData -> Track_R_AddRef(theFilename,theLineNum); +} + +void RefCountObject :: Track_R_Release(char* theFilename, int theLineNum) +{ + GLOBALASSERT( pTrackData ); + + pTrackData -> Track_R_Release(theFilename,theLineNum); +} + +void RefCountObject :: Track_Destroy(void) +{ + GLOBALASSERT( pTrackData ); + + delete pTrackData; +} + +void RefCountObject :: ReferenceDump(R_DumpContext& theContext) const +{ + GLOBALASSERT( pTrackData ); + + DumpIDForReferenceDump(theContext); + + pTrackData -> DumpTransactions(theContext); +} + +static void RefCountObject :: DumpAll(R_DumpContext& theContext) +{ + RefCountObject_TrackData :: DumpAll(theContext); +} +#endif // TrackReferenceCounted +/* Internal function definitions ***********************************/ +#if TrackReferenceCounted +// class RefCountObject_TrackData +// class RefCountObject_TrackData :: ReferenceTransaction +// public: +void RefCountObject_TrackData :: ReferenceTransaction :: Dump( R_DumpContext& theContext ) const +{ + char* Action = + ( + ( Type == tt_addref) + ? + "R_AddRef()" + : + "R_Release()" + ); + + theContext.dprintf("-- %s in file \"%s\" at line %i\n",Action,Filename,LineNum); +} + +// public: +static void RefCountObject_TrackData :: DumpAll(R_DumpContext& theContext) +{ + theContext . dprintf + ( + "RefCountObject::DumpAll(); num objects=%i\n", + theGlobals . List_pRCObj . size() + ); + + for + ( + CLIF oi(&theGlobals . List_pRCObj); + !oi . done(); + oi . next() + ) + { + GLOBALASSERT(oi()); + oi() -> ReferenceDump(theContext); + } +} +RefCountObject_TrackData :: RefCountObject_TrackData(RefCountObject *const pRCObj,char* theFilename, int theLineNum) : + pRCObj_Val(pRCObj), + List_pTransaction(), + constructionFilename(theFilename), + constructionLineNum(theLineNum) +{ + theGlobals . List_pRCObj . add_entry(pRCObj_Val); +} + +RefCountObject_TrackData :: ~RefCountObject_TrackData() +{ + while ( List_pTransaction . size() > 0) + { + List_pTransaction . delete_first_entry(); + } + + theGlobals . List_pRCObj . delete_entry(pRCObj_Val); + +} + +void RefCountObject_TrackData :: Track_R_AddRef(char* theFilename, int theLineNum) +{ + List_pTransaction . add_entry_end + ( + new Transaction_R_AddRef(theFilename,theLineNum) + ); +} + +void RefCountObject_TrackData :: Track_R_Release(char* theFilename, int theLineNum) +{ + List_pTransaction . add_entry_end + ( + new Transaction_R_Release(theFilename,theLineNum) + ); +} + +void RefCountObject_TrackData :: DumpTransactions( R_DumpContext& theContext) const +{ + theContext . dprintf("-- Constructed in \"%s\" at line %i\n",constructionFilename,constructionLineNum); + for + ( + CLIF oi(&List_pTransaction); + !oi . done(); + oi . next() + ) + { + oi() -> Dump(theContext); + } +} + +// private: + +#if OutputRefCountLogOnExit +// We put one of these in the BSS segment so that its destructor +// gets called at exit. The destructor writes all the info +// to a log file +// class Globals +RefCountObject_TrackData :: Globals :: ~Globals() +{ + LogFile theLogFile(filename); + RefCountObject :: DumpAll(theLogFile); +} +#endif + +#endif // TrackReferenceCounted \ No newline at end of file diff --git a/3dc/avp/support/refobj.hpp b/3dc/avp/support/refobj.hpp new file mode 100644 index 0000000..9fad9b2 --- /dev/null +++ b/3dc/avp/support/refobj.hpp @@ -0,0 +1,201 @@ +/* + + refobj.hpp + + Created by DHM for Headhunter; copied into AVP + + Reference-counted base class to be used by e.g. strings + +*/ + +#ifndef _refobj +#define _refobj 1 + + + #ifndef __fail_h + #include "fail.h" + #endif + + + +#ifdef __cplusplus + extern "C" { +#endif + + +/* Version settings *****************************************************/ + #define TrackReferenceCounted No + /* + This is a debug option that has a fair amount of run-time + cost. + + It maintains a list of all reference-counted objects, and + data on when references were added or released. + + Data on a particular object can be sent to a log file; + there is a function to do this for all that exist. + */ + +/* Macros ***************************************************************/ + +#if TrackReferenceCounted + #define R_AddRef() imp_R_AddRef(__FILE__,__LINE__) + #define R_Release() imp_R_Release(__FILE__,__LINE__) +#endif + +/* Imported globals *****************************************************/ + + extern char const* refobj_fail_addref; + extern char const* refobj_fail_release; + extern char const* refobj_fail_destructor; + + +/* Type definitions *****************************************************/ + class R_DumpContext; // fully declared in DCONTEXT.HPP + + class RefCountObject_TrackData; // fully declared within REFOBJ.CPP + + class RefCountObject + { + // {{{ Private data + private: + int RefCount; + + #if TrackReferenceCounted + RefCountObject_TrackData* pTrackData; + // done as a non-NULL pointer rather than a ref so as to hide + // definition (avoiding compiler dependency) + #endif + + // }}} + + + // {{{ Private functions + private: + // Private fns for the tracking system are complex and defined in REFOBJ.CPP + #if TrackReferenceCounted + void Track_Construct(void); + void Track_R_AddRef(char* theFilename, int theLineNum); + void Track_R_Release(char* theFilename, int theLineNum); + void Track_Destroy(void); + #endif + // }}} + + public: + RefCountObject() : + #if TrackReferenceCounted + pTrackData(NULL), + #endif + RefCount(1) + { + #if TrackReferenceCounted + Track_Construct(); + #endif + } + + #if TrackReferenceCounted + void imp_R_AddRef(char* theFilename, int theLineNum) + { + #ifndef NDEBUG + if ( RefCount <= 0) + { + fail(refobj_fail_addref); + } + #endif + RefCount++; + + Track_R_AddRef(theFilename,theLineNum); + } + + void imp_R_Release(char* theFilename, int theLineNum) + { + #ifndef NDEBUG + if ( RefCount <= 0) + { + fail(refobj_fail_release); + } + #endif + + Track_R_Release(theFilename,theLineNum); + + if ( (--RefCount) == 0 ) + { + delete this; + } + } + #else + void R_AddRef(void) + { + #ifndef NDEBUG + if ( RefCount <= 0) + { + fail(refobj_fail_addref); + } + #endif + RefCount++; + } + + void R_Release(void) + { + #ifndef NDEBUG + if ( RefCount <= 0) + { + fail(refobj_fail_release); + } + #endif + + if ( (--RefCount) == 0 ) + { + delete this; + } + } + #endif + + #if debug + int CheckRef() const + { + return RefCount; + } + // Handy way to examine reference count for debugging only + #endif + + #if TrackReferenceCounted + virtual void DumpIDForReferenceDump(R_DumpContext& theContext) const = 0; + void ReferenceDump(R_DumpContext& theContext) const; + static void DumpAll(R_DumpContext& theContext); + #endif + + protected: + // Destructors must be protected; only derived classes may use the + // destructor and (we hope) only in the R_Release() method: + virtual ~RefCountObject() + { + #ifndef NDEBUG + if ( RefCount != 0 ) + { + fail(refobj_fail_destructor); + } + #endif + + #if TrackReferenceCounted + Track_Destroy(); + #endif + } + }; + + + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/support/rentrntq.cpp b/3dc/avp/support/rentrntq.cpp new file mode 100644 index 0000000..b00464e --- /dev/null +++ b/3dc/avp/support/rentrntq.cpp @@ -0,0 +1,294 @@ +/******************************************************************* + * + * DESCRIPTION: rentrntq.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 21/11/97 + * (refer to comment in RENTRTQ.H from a description of what + * this is for) + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "gadget.h" + +#if SupportWindows95 + +#include "rentrntq.h" + + #if UseGadgets + #include "iofocus.h" + #include "hudgadg.hpp" + #include "textin.hpp" + #include "consbind.hpp" + #endif + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + #define MAX_Q_MESSAGES (256) + +#if 0 + #if 1 + #define METACHAR_CHANGEFOCUS '~' + #else + #define METACHAR_CHANGEFOCUS '\r' + #endif + + #define METAKEY_CHANGEFOCUS_VK (0xdf) + /* + DHM 14/1/98: + ------------ + + I have been asked to make this key the + + "you know, the tilde key, the one in the top left of everyone's + keyboards, like Quake does" + + However, I have yet to find a keyboard for which the tilde key is in the + top left. + + I obtained the value (0xdf) by experiment on my keyboard. According to + the Petzold book: + + "Although all keys cause keystroke messages, the table does not + include any symbol keys (such as the key with the / and ? symbols). + These keys have virtual key codes of 128 and above, and they are often + defined differently for international keyboards. You can determine the + values of these virtual key codes using the KEYLOOK program that is shown + later in this chapter, but normally you should not process keystroke + messages for these keys." + + What about DirectInput? + + */ +#endif + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ + enum QEntryCategory + { + QEntryCat_WM_CHAR, + QEntryCat_WM_KEYDOWN, + + NUM_Q_ENTRY_CATS + }; + + struct Q_Entry + { + enum QEntryCategory QEntryCat; + + union + { + char Ch; + // Valid for: QEntryCat_WM_CHAR + + WPARAM wParam; + // Valid for: QEntryCat_WM_KEYDOWN + } CatData; + }; + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + static struct Q_Entry OurQ[MAX_Q_MESSAGES]; + static unsigned int NumQMessages = 0; + +/* Exported function definitions ***********************************/ +/* Functions callable within the Windows procedure */ +void RE_ENTRANT_QUEUE_WinProc_AddMessage_WM_CHAR +( + char Ch +) +{ + if ( NumQMessages < MAX_Q_MESSAGES ) + { + OurQ[ NumQMessages ] . QEntryCat = QEntryCat_WM_CHAR; + OurQ[ NumQMessages ] . CatData . Ch = Ch; + NumQMessages++; + } + // otherwise ignore the message + // since no decent error handling facilties/memory allocators + // can safely be called at this stage +} + +void RE_ENTRANT_QUEUE_WinProc_AddMessage_WM_KEYDOWN +( + WPARAM wParam +) +{ + if ( NumQMessages < MAX_Q_MESSAGES ) + { + OurQ[ NumQMessages ] . QEntryCat = QEntryCat_WM_KEYDOWN; + OurQ[ NumQMessages ] . CatData . wParam = wParam; + NumQMessages++; + } + // otherwise ignore the message + // since no decent error handling facilties/memory allocators + // can safely be called at this stage +} + + +/* Functions callable from the WinMain() body of code */ +void RE_ENTRANT_QUEUE_WinMain_FlushMessages(void) +{ + // Process the messages: + { + #if UseGadgets + // AVP/Win95-specific code + if ( HUDGadget :: GetHUD() ) + { + int i; + + for (i=0;i CharTyped + ( + Ch + ); + } + } + #if 0 + textprint + ( + "\n\n\nWM_CHAR message flushed; code=0x%x\n\n\n", + Ch + ); + #endif + } + break; + + case QEntryCat_WM_KEYDOWN: + { + if ( IOFOCUS_AcceptTyping() ) + { + switch ( OurQ[i] . CatData . wParam ) + { + default: + // ignore most keys; + break; + + case VK_BACK: + HUDGadget :: GetHUD() -> Key_Backspace(); + break; + case VK_END: + HUDGadget :: GetHUD() -> Key_End(); + break; + case VK_HOME: + HUDGadget :: GetHUD() -> Key_Home(); + break; + case VK_LEFT: + HUDGadget :: GetHUD() -> Key_Left(); + break; + case VK_UP: + HUDGadget :: GetHUD() -> Key_Up(); + break; + case VK_RIGHT: + HUDGadget :: GetHUD() -> Key_Right(); + break; + case VK_DOWN: + HUDGadget :: GetHUD() -> Key_Down(); + break; + case VK_INSERT: + TextInputState :: ToggleTypingMode(); + break; + case VK_DELETE: + HUDGadget :: GetHUD() -> Key_Delete(); + break; + case VK_TAB: + HUDGadget :: GetHUD() -> Key_Tab(); + break; + } + + } + else + { + #if KeyBindingUses_WM_KEYDOWN + // 6/4/98: + // Pass the key to the console-binding code: + KeyBinding::Process_WM_KEYDOWN + ( + OurQ[i] . CatData . wParam + ); + #endif + } + #if 0 + textprint + ( + "\n\n\nWM_KEYDOWN message flushed; code=0x%x\n\n\n", + OurQ[i] . CatData . wParam + ); + #endif + + } + break; + + } + } + } + #endif + } + + // Clear the messages (only place where a semaphore might be needed): + NumQMessages = 0; +} + +void RE_ENTRANT_QUEUE_WinMain_FlushMessagesWithoutProcessing(void) +{ + NumQMessages = 0; +} + +/* Internal function definitions ***********************************/ + + + + + +#endif // SupportWindows95 diff --git a/3dc/avp/support/rentrntq.h b/3dc/avp/support/rentrntq.h new file mode 100644 index 0000000..763cafb --- /dev/null +++ b/3dc/avp/support/rentrntq.h @@ -0,0 +1,71 @@ +/* + + rentrntq.h + + Created 21/11/97 by DHM: + + "Support for a queue of messages (generated by/analagous to Windows messages) + to avoid problems with re-entrancy". + + The problem being solved is that (in theory at least) the application's + WinProc() procedure can be called at any point within any function in the Win32 API. + + This means that any code that the application's WinProc procedure + calls (both directly or indirectly) must, in general, be re-entrant + + For example, textprint(), the memory allocators, etc. can't be guaranteed to work if + called from WinProc() or something called by it. This is a mahor restriction on what + you can call from WinProc. + + The idea of this code is to isolate the re-entrancy by buffering the + messages, which can then be flushed somewhere "safe" within the main loop + that doesn't need to be re-entrant. + + Functions within this header are labelled with either (i)"WinProc" or (ii)"WinMain" + in their names to indicate whether (i)they should be called from the windows procedure + or (ii) from within the WinMain function (or anything it calls i.e. the entire program + and main loop _except_ for the windows procedure) +*/ + +#ifndef _rentrntq +#define _rentrntq 1 + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + /* Functions callable within the Windows procedure */ + extern void RE_ENTRANT_QUEUE_WinProc_AddMessage_WM_CHAR + ( + char Ch + ); + + extern void RE_ENTRANT_QUEUE_WinProc_AddMessage_WM_KEYDOWN + ( + WPARAM wParam + ); + + /* Functions callable from the WinMain() body of code */ + extern void RE_ENTRANT_QUEUE_WinMain_FlushMessages(void); + extern void RE_ENTRANT_QUEUE_WinMain_FlushMessagesWithoutProcessing(void); + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/support/scstring.cpp b/3dc/avp/support/scstring.cpp new file mode 100644 index 0000000..94f3b19 --- /dev/null +++ b/3dc/avp/support/scstring.cpp @@ -0,0 +1,1973 @@ +/******************************************************************* + * + * DESCRIPTION: string.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created ages ago + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "scstring.hpp" + +#if SupportHHStuff + #include "hhfonts.h" + #include "hhfile.h" + #include "ifmisc.h" + #include "holder.hpp" + #include "mcstring.hpp" +#else + #include "strutil.h" + #include "indexfnt.hpp" +#endif + + #if TrackReferenceCounted + #include "dcontext.hpp" + #endif + + #define UseLocalAssert Yes + #include "ourasert.h" + +#ifdef __WATCOMC__ +#pragma warning 139 5 +#pragma message("Disabled Warning W139") +#endif + + +/* Version settings ************************************************/ + #define LogStringTables No + +/* Constants *******************************************************/ + #define MAX_BYTES_IN_NUMERIC_STRING (100) + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + extern DISPLAYBLOCK *Player; + + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + /*static*/ SCString* SCString :: pFirst = NULL; + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + #if SupportHHStuff + static void strutil_Failure(Failure_Behaviour FailBehav); + #endif + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +// class SCString +// public: +#if TrackReferenceCounted +void SCString :: DumpIDForReferenceDump(R_DumpContext& theContext) const +{ + theContext . dprintf("SCString \"%s\" refs remainining=%i\n",pProjCh_Val,CheckRef()); +} +#endif + +ProjChar* SCString :: pProjCh(void) const +{ + /* PRECONDITION */ + { + GLOBALASSERT( pProjCh_Val ); + } + + /* CODE */ + { + return pProjCh_Val; + } +} + + +SCString :: SCString +( + const ProjChar* pProjCh_Init +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pProjCh_Init ); + } + + /* CODE */ + { + AllocatedSize = (size_t) STRUTIL_SC_NumBytes + ( + pProjCh_Init + ); + + pProjCh_Val = new ProjChar[ AllocatedSize ]; + GLOBALASSERT( pProjCh_Val ); + + STRUTIL_SC_StrCpy + ( + pProjCh_Val, + pProjCh_Init + ); + + NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1; + // doesn't include NULL terminator + + #if SupportHHStuff + { + FDIBMAP FDIBMap_Temp; + + HHFONTS_GetSizeOfSingleLine + ( + &FDIBMap_Temp, + + pProjCh_Val, + pStandardFont + ); + + WidthGivenStandardFont = FDIBMap_Temp . Width; + // width in pixels, to save constant recalc + } + #else + { + FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS; + + while ( i>0 ) + { + i = (FontIndex)(i-1); + + IndexedFont* pFont = IndexedFont :: GetFont( i ); + + if ( pFont ) + { + #if EnableSizeData + R2Size[ i ] = pFont -> CalcSize + ( + pProjCh_Val + ); + #endif + bCanRender[ i ] = pFont -> bCanRenderFully + ( + pProjCh_Val + ); + } + else + { + #if EnableSizeData + R2Size[ i ] = r2size(0,0); + #endif + bCanRender[ i ] = No; + } + } + } + #endif + + // Insert at head of list: + { + if ( pFirst ) + { + pFirst -> pPrv = this; + } + + pNxt = pFirst; + pPrv = NULL; + + pFirst = this; + } + } +} + +SCString :: SCString +( + signed int Number +) +{ + // forms a new string object that describes the number passed + // standard decimal representation + + /* PRECONDITION */ + { + } + + /* CODE */ + { + ProjChar pProjCh_Init[ MAX_BYTES_IN_NUMERIC_STRING ]; + + sprintf + ( + pProjCh_Init, + "%i", + (int)Number + ); + + #if 0 + LOCALISEME(); + #endif + + AllocatedSize = (size_t) STRUTIL_SC_NumBytes + ( + pProjCh_Init + ); + + pProjCh_Val = new ProjChar[ AllocatedSize ]; + GLOBALASSERT( pProjCh_Val ); + // this is always "owned" by the String + + STRUTIL_SC_StrCpy + ( + pProjCh_Val, + pProjCh_Init + ); + + NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1; + // doesn't include NULL terminator + + #if SupportHHStuff + { + FDIBMAP FDIBMap_Temp; + + HHFONTS_GetSizeOfSingleLine + ( + &FDIBMap_Temp, + + pProjCh_Val, + pStandardFont + ); + + WidthGivenStandardFont = FDIBMap_Temp . Width; + // width in pixels, to save constant recalc + } + #else + { + FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS; + + while ( i>0 ) + { + i = (FontIndex)(i-1); + + IndexedFont* pFont = IndexedFont :: GetFont( i ); + + if ( pFont ) + { + #if EnableSizeData + R2Size[ i ] = pFont -> CalcSize + ( + pProjCh_Val + ); + #endif + + bCanRender[ i ] = pFont -> bCanRenderFully + ( + pProjCh_Val + ); + } + else + { + #if EnableSizeData + R2Size[ i ] = r2size(0,0); + #endif + bCanRender[ i ] = No; + } + } + } + #endif + + // Insert at head of list: + { + if ( pFirst ) + { + pFirst -> pPrv = this; + } + + pNxt = pFirst; + pPrv = NULL; + + pFirst = this; + } + + } +} + +SCString :: SCString +( + unsigned int Number +) +{ + // forms a new string object that describes the number passed + // standard decimal representation + + /* PRECONDITION */ + { + } + + /* CODE */ + { + ProjChar pProjCh_Init[ MAX_BYTES_IN_NUMERIC_STRING ]; + + sprintf + ( + pProjCh_Init, + "%u", + Number + ); + + #if 0 + LOCALISEME(); + #endif + + AllocatedSize = (size_t) STRUTIL_SC_NumBytes + ( + pProjCh_Init + ); + + pProjCh_Val = new ProjChar[ AllocatedSize ]; + GLOBALASSERT( pProjCh_Val ); + // this is always "owned" by the String + + STRUTIL_SC_StrCpy + ( + pProjCh_Val, + pProjCh_Init + ); + + NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1; + // doesn't include NULL terminator + + #if SupportHHStuff + { + FDIBMAP FDIBMap_Temp; + + HHFONTS_GetSizeOfSingleLine + ( + &FDIBMap_Temp, + + pProjCh_Val, + pStandardFont + ); + + WidthGivenStandardFont = FDIBMap_Temp . Width; + // width in pixels, to save constant recalc + } + #else + { + FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS; + + while ( i>0 ) + { + i = (FontIndex)(i-1); + + IndexedFont* pFont = IndexedFont :: GetFont( i ); + + if ( pFont ) + { + #if EnableSizeData + R2Size[ i ] = pFont -> CalcSize + ( + pProjCh_Val + ); + #endif + + bCanRender[ i ] = pFont -> bCanRenderFully + ( + pProjCh_Val + ); + } + else + { + #if EnableSizeData + R2Size[ i ] = r2size(0,0); + #endif + bCanRender[ i ] = No; + } + } + } + #endif + + // Insert at head of list: + { + if ( pFirst ) + { + pFirst -> pPrv = this; + } + + pNxt = pFirst; + pPrv = NULL; + + pFirst = this; + } + + } +} + +SCString :: SCString +( + float Number +) +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + ProjChar pProjCh_Init[ MAX_BYTES_IN_NUMERIC_STRING ]; + + sprintf + ( + pProjCh_Init, + "%6f", + Number + ); + + #if 0 + LOCALISEME(); + #endif + + AllocatedSize = (size_t) STRUTIL_SC_NumBytes + ( + pProjCh_Init + ); + + pProjCh_Val = new ProjChar[ AllocatedSize ]; + GLOBALASSERT( pProjCh_Val ); + // this is always "owned" by the String + + STRUTIL_SC_StrCpy + ( + pProjCh_Val, + pProjCh_Init + ); + + NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1; + // doesn't include NULL terminator + + #if SupportHHStuff + { + FDIBMAP FDIBMap_Temp; + + HHFONTS_GetSizeOfSingleLine + ( + &FDIBMap_Temp, + + pProjCh_Val, + pStandardFont + ); + + WidthGivenStandardFont = FDIBMap_Temp . Width; + // width in pixels, to save constant recalc + } + #else + { + FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS; + + while ( i>0 ) + { + i = (FontIndex)(i-1); + + IndexedFont* pFont = IndexedFont :: GetFont( i ); + + if ( pFont ) + { + #if EnableSizeData + R2Size[ i ] = pFont -> CalcSize + ( + pProjCh_Val + ); + #endif + + bCanRender[ i ] = pFont -> bCanRenderFully + ( + pProjCh_Val + ); + } + else + { + #if EnableSizeData + R2Size[ i ] = r2size(0,0); + #endif + bCanRender[ i ] = No; + } + } + } + #endif + + // Insert at head of list: + { + if ( pFirst ) + { + pFirst -> pPrv = this; + } + + pNxt = pFirst; + pPrv = NULL; + + pFirst = this; + } + + } +} + + + +SCString :: SCString +( + ProjChar* pProjCh_Init, + unsigned int Length +) +{ + // Forms a string of length at most Length (with 1 extra for NULL-terminator) + + /* PRECONDITION */ + { + GLOBALASSERT( pProjCh_Init ); + } + + /* CODE */ + { + NumberOfCharacters = STRUTIL_SC_Strlen( pProjCh_Init ); + // doesn't include NULL terminator + + if ( NumberOfCharacters > Length ) + { + NumberOfCharacters = Length; + } + + AllocatedSize = (size_t) STRUTIL_SC_NumBytes + ( + pProjCh_Init + ); + + { + size_t TruncSize = sizeof(ProjChar) * (Length + 1); + + if (AllocatedSize > TruncSize ) + { + AllocatedSize = TruncSize; + } + } + + pProjCh_Val = new ProjChar[ AllocatedSize ]; + GLOBALASSERT( pProjCh_Val ); + // this is always "owned" by the String + + STRUTIL_SC_SafeCopy + ( + pProjCh_Val, + (NumberOfCharacters+1), + + pProjCh_Init + ); + + #if SupportHHStuff + { + FDIBMAP FDIBMap_Temp; + + HHFONTS_GetSizeOfSingleLine + ( + &FDIBMap_Temp, + + pProjCh_Val, + pStandardFont + ); + + WidthGivenStandardFont = FDIBMap_Temp . Width; + // width in pixels, to save constant recalc + } + #else + { + FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS; + + while ( i>0 ) + { + i = (FontIndex)(i-1); + + IndexedFont* pFont = IndexedFont :: GetFont( i ); + + if ( pFont ) + { + #if EnableSizeData + R2Size[ i ] = pFont -> CalcSize + ( + pProjCh_Val + ); + #endif + + bCanRender[ i ] = pFont -> bCanRenderFully + ( + pProjCh_Val + ); + } + else + { + #if EnableSizeData + R2Size[ i ] = r2size(0,0); + #endif + + bCanRender[ i ] = No; + } + } + } + #endif + + // Insert at head of list: + { + if ( pFirst ) + { + pFirst -> pPrv = this; + } + + pNxt = pFirst; + pPrv = NULL; + + pFirst = this; + } + + } +} + + +SCString :: SCString +( + SCString* pStringObj_0, + SCString* pStringObj_1 +) +{ + // forms a new string object by concatenating the strings in 0 + // and 1 + + /* PRECONDITION */ + { + GLOBALASSERT( pStringObj_0 ); + GLOBALASSERT( pStringObj_1 ); + } + + /* CODE */ + { + ProjChar* pProjCh_Init_0 = pStringObj_0 -> pProjCh(); + GLOBALASSERT( pProjCh_Init_0 ); + + ProjChar* pProjCh_Init_1 = pStringObj_1 -> pProjCh(); + GLOBALASSERT( pProjCh_Init_1 ); + + AllocatedSize = (size_t) + ( + STRUTIL_SC_NumBytes + ( + pProjCh_Init_0 + ) + + + STRUTIL_SC_NumBytes + ( + pProjCh_Init_1 + ) + - sizeof(ProjChar) // only one null terminator needed + ); + + pProjCh_Val = new ProjChar[ AllocatedSize ]; + GLOBALASSERT( pProjCh_Val ); + + // this is always "owned" by the String + STRUTIL_SC_FastCat + ( + pProjCh_Val, + pProjCh_Init_0, + pProjCh_Init_1 + ); + + NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1; + // doesn't include NULL terminator + + #if SupportHHStuff + { + FDIBMAP FDIBMap_Temp; + + HHFONTS_GetSizeOfSingleLine + ( + &FDIBMap_Temp, + + pProjCh_Val, + pStandardFont + ); + + WidthGivenStandardFont = FDIBMap_Temp . Width; + // width in pixels, to save constant recalc + } + #else + { + FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS; + + while ( i>0 ) + { + i = (FontIndex)(i-1); + + #if EnableSizeData + R2Size[ i ] = pStringObj_0 -> CalcSize( i ); + R2Size[ i ] . w += pStringObj_1 -> CalcSize( i ) . w; + #endif + + bCanRender[ i ] = + ( + pStringObj_0 -> bCanRenderFully( i ) + && + pStringObj_1 -> bCanRenderFully( i ) + ); + } + } + #endif + + // Insert at head of list: + { + if ( pFirst ) + { + pFirst -> pPrv = this; + } + + pNxt = pFirst; + pPrv = NULL; + + pFirst = this; + } + + } +} + + +SCString :: SCString +( + SCString* pStringObj_0, + SCString* pStringObj_1, + SCString* pStringObj_2 +) +{ + // forms a new string object by concatenating the strings in 0, 1 and 2 + + /* PRECONDITION */ + { + GLOBALASSERT( pStringObj_0 ); + GLOBALASSERT( pStringObj_1 ); + GLOBALASSERT( pStringObj_2 ); + } + + /* CODE */ + { + // Insert at head of list: + { + if ( pFirst ) + { + pFirst -> pPrv = this; + } + + pNxt = pFirst; + pPrv = NULL; + + pFirst = this; + } + + SCString* pStringObj_Intermediate = new SCString + ( + pStringObj_1, + pStringObj_2 + ); + + { + + ProjChar* pProjCh_Init_0 = pStringObj_0 -> pProjCh(); + GLOBALASSERT( pProjCh_Init_0 ); + + ProjChar* pProjCh_Intermediate = pStringObj_Intermediate -> pProjCh(); + GLOBALASSERT( pProjCh_Intermediate ); + + AllocatedSize = (size_t) + ( + STRUTIL_SC_NumBytes + ( + pProjCh_Init_0 + ) + + + STRUTIL_SC_NumBytes + ( + pProjCh_Intermediate + ) + - sizeof(ProjChar) // only one null terminator needed + ); + + pProjCh_Val = new ProjChar[ AllocatedSize ]; + GLOBALASSERT( pProjCh_Val ); + // this is always "owned" by the String + STRUTIL_SC_FastCat + ( + pProjCh_Val, + pProjCh_Init_0, + pProjCh_Intermediate + ); + + NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1; + // doesn't include NULL terminator + + #if SupportHHStuff + { + FDIBMAP FDIBMap_Temp; + + HHFONTS_GetSizeOfSingleLine + ( + &FDIBMap_Temp, + + pProjCh_Val, + pStandardFont + ); + + WidthGivenStandardFont = FDIBMap_Temp . Width; + // width in pixels, to save constant recalc + } + #else + { + FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS; + + while ( i>0 ) + { + i = (FontIndex)(i-1); + + #if EnableSizeData + R2Size[ i ] = pStringObj_0 -> CalcSize( i ); + R2Size[ i ] . w += + ( + pStringObj_1 -> CalcSize( i ) . w + + + pStringObj_2 -> CalcSize( i ) . w + ); + #endif + + bCanRender[ i ] = + ( + pStringObj_0 -> bCanRenderFully( i ) + && + pStringObj_1 -> bCanRenderFully( i ) + && + pStringObj_2 -> bCanRenderFully( i ) + ); + } + } + #endif + } + + + pStringObj_Intermediate -> R_Release(); + + } +} + +SCString :: SCString +( + SCString* pStringObj_0, + SCString* pStringObj_1, + SCString* pStringObj_2, + SCString* pStringObj_3 +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pStringObj_0 ); + GLOBALASSERT( pStringObj_1 ); + GLOBALASSERT( pStringObj_2 ); + GLOBALASSERT( pStringObj_3 ); + } + + /* CODE */ + { + // Insert at head of list: + { + if ( pFirst ) + { + pFirst -> pPrv = this; + } + + pNxt = pFirst; + pPrv = NULL; + + pFirst = this; + } + + SCString* pStringObj_Intermediate = new SCString + ( + pStringObj_1, + pStringObj_2, + pStringObj_3 + ); + + { + + ProjChar* pProjCh_Init_0 = pStringObj_0 -> pProjCh(); + GLOBALASSERT( pProjCh_Init_0 ); + + ProjChar* pProjCh_Intermediate = pStringObj_Intermediate -> pProjCh(); + GLOBALASSERT( pProjCh_Intermediate ); + + AllocatedSize = (size_t) + ( + STRUTIL_SC_NumBytes + ( + pProjCh_Init_0 + ) + + + STRUTIL_SC_NumBytes + ( + pProjCh_Intermediate + ) + - sizeof(ProjChar) // only one null terminator needed + ); + + pProjCh_Val = new ProjChar[ AllocatedSize ]; + GLOBALASSERT( pProjCh_Val ); + // this is always "owned" by the String + STRUTIL_SC_FastCat + ( + pProjCh_Val, + pProjCh_Init_0, + pProjCh_Intermediate + ); + + NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1; + // doesn't include NULL terminator + + #if SupportHHStuff + { + FDIBMAP FDIBMap_Temp; + + HHFONTS_GetSizeOfSingleLine + ( + &FDIBMap_Temp, + + pProjCh_Val, + pStandardFont + ); + + WidthGivenStandardFont = FDIBMap_Temp . Width; + // width in pixels, to save constant recalc + } + #else + { + FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS; + + while ( i>0 ) + { + i = (FontIndex)(i-1); + + #if EnableSizeData + R2Size[ i ] = pStringObj_0 -> CalcSize( i ); + R2Size[ i ] . w += + ( + pStringObj_1 -> CalcSize( i ) . w + + + pStringObj_2 -> CalcSize( i ) . w + + + pStringObj_3 -> CalcSize( i ) . w + ); + #endif + + bCanRender[ i ] = + ( + pStringObj_0 -> bCanRenderFully( i ) + && + pStringObj_1 -> bCanRenderFully( i ) + && + pStringObj_2 -> bCanRenderFully( i ) + && + pStringObj_3 -> bCanRenderFully( i ) + ); + } + } + #endif + } + + + pStringObj_Intermediate -> R_Release(); + + } +} + + +SCString :: SCString +( + SCString* pStringObj_0, + SCString* pStringObj_1, + SCString* pStringObj_2, + SCString* pStringObj_3, + SCString* pStringObj_4 +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pStringObj_0 ); + GLOBALASSERT( pStringObj_1 ); + GLOBALASSERT( pStringObj_2 ); + GLOBALASSERT( pStringObj_3 ); + GLOBALASSERT( pStringObj_4 ); + } + + /* CODE */ + { + // Insert at head of list: + { + if ( pFirst ) + { + pFirst -> pPrv = this; + } + + pNxt = pFirst; + pPrv = NULL; + + pFirst = this; + } + + SCString* pStringObj_Intermediate = new SCString + ( + pStringObj_1, + pStringObj_2, + pStringObj_3, + pStringObj_4 + ); + + { + + ProjChar* pProjCh_Init_0 = pStringObj_0 -> pProjCh(); + GLOBALASSERT( pProjCh_Init_0 ); + + ProjChar* pProjCh_Intermediate = pStringObj_Intermediate -> pProjCh(); + GLOBALASSERT( pProjCh_Intermediate ); + + AllocatedSize = (size_t) + ( + STRUTIL_SC_NumBytes + ( + pProjCh_Init_0 + ) + + + STRUTIL_SC_NumBytes + ( + pProjCh_Intermediate + ) + - sizeof(ProjChar) // only one null terminator needed + ); + + pProjCh_Val = new ProjChar[ AllocatedSize ]; + GLOBALASSERT( pProjCh_Val ); + // this is always "owned" by the String + STRUTIL_SC_FastCat + ( + pProjCh_Val, + pProjCh_Init_0, + pProjCh_Intermediate + ); + + NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1; + // doesn't include NULL terminator + + #if SupportHHStuff + { + FDIBMAP FDIBMap_Temp; + + HHFONTS_GetSizeOfSingleLine + ( + &FDIBMap_Temp, + + pProjCh_Val, + pStandardFont + ); + + WidthGivenStandardFont = FDIBMap_Temp . Width; + // width in pixels, to save constant recalc + } + #else + { + FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS; + + while ( i>0 ) + { + i = (FontIndex)(i-1); + + #if EnableSizeData + R2Size[ i ] = pStringObj_0 -> CalcSize( i ); + R2Size[ i ] . w += + ( + pStringObj_1 -> CalcSize( i ) . w + + + pStringObj_2 -> CalcSize( i ) . w + + + pStringObj_3 -> CalcSize( i ) . w + + + pStringObj_4 -> CalcSize( i ) . w + ); + #endif + + bCanRender[ i ] = + ( + pStringObj_0 -> bCanRenderFully( i ) + && + pStringObj_1 -> bCanRenderFully( i ) + && + pStringObj_2 -> bCanRenderFully( i ) + && + pStringObj_3 -> bCanRenderFully( i ) + && + pStringObj_4 -> bCanRenderFully( i ) + ); + } + } + #endif + } + + + pStringObj_Intermediate -> R_Release(); + + } +} + + +SCString :: SCString +( + List List_ProjChar +) +{ + { + AllocatedSize = (size_t) (List_ProjChar . size() + 1) * sizeof(ProjChar); + + pProjCh_Val = new ProjChar[ AllocatedSize ]; + GLOBALASSERT( pProjCh_Val ); + + #if 1 + { + ProjChar* pDst = pProjCh_Val; + + for + ( + LIF oi(&(List_ProjChar)); + !oi.done(); + oi.next() + ) + { + *(pDst++) = oi(); + } + + // Write terminator: + *pDst = 0; + } + #else + STRUTIL_SC_StrCpy + ( + pProjCh_Val, + pProjCh_Init + ); + #endif + + NumberOfCharacters = ( AllocatedSize / sizeof(ProjChar ) ) - 1; + // doesn't include NULL terminator + + #if SupportHHStuff + { + FDIBMAP FDIBMap_Temp; + + HHFONTS_GetSizeOfSingleLine + ( + &FDIBMap_Temp, + + pProjCh_Val, + pStandardFont + ); + + WidthGivenStandardFont = FDIBMap_Temp . Width; + // width in pixels, to save constant recalc + } + #else + { + FontIndex i = IndexedFonts_MAX_NUMBER_OF_FONTS; + + while ( i>0 ) + { + i = (FontIndex)(i-1); + + IndexedFont* pFont = IndexedFont :: GetFont( i ); + + if ( pFont ) + { + #if EnableSizeData + R2Size[ i ] = pFont -> CalcSize + ( + pProjCh_Val + ); + #endif + bCanRender[ i ] = pFont -> bCanRenderFully + ( + pProjCh_Val + ); + } + else + { + #if EnableSizeData + R2Size[ i ] = r2size(0,0); + #endif + bCanRender[ i ] = No; + } + } + } + #endif + + // Insert at head of list: + { + if ( pFirst ) + { + pFirst -> pPrv = this; + } + + pNxt = pFirst; + pPrv = NULL; + + pFirst = this; + } + } + +} + + +#if SupportHHStuff +void SCString :: GetSizeOfSingleLineGivenStandardFont +( + FDIBMAP* pFDIBMap_Out +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pFDIBMap_Out ); + } + + /* CODE */ + { + pFDIBMap_Out -> Width = WidthGivenStandardFont; + + pFDIBMap_Out -> Height = HHFONTS_GetMaxHeight + ( + pStandardFont + ); + } +} + +FDIBMAP SCString :: GetSizeOfSingleLineGivenStandardFont(void) +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + FDIBMAP FDIBMap_Temp; + + FDIBMap_Temp . Width = WidthGivenStandardFont; + + FDIBMap_Temp . Height = HHFONTS_GetMaxHeight + ( + pStandardFont + ); + + return FDIBMap_Temp; + } +} + +int SCString :: GetWidthOfSingleLineGivenStandardFont(void) +{ + return WidthGivenStandardFont; +} + +FDIQUAD SCString :: MinFDIQuadForSCStringAtPos +( + FDIPOS FDIPos +) +{ + FDIQUAD FDIQuad_Temp = FDIQuad + ( + FDIPos . LeftX, + FDIPos . TopY, + WidthGivenStandardFont, + HHFONTS_GetMaxHeight + ( + pStandardFont + ) + ); + + return FDIQuad_Temp; +} +#endif + +/*static*/ void SCString :: UpdateAfterFontChange( FontIndex I_Font_Changed ) +{ + // called by the font code whenever fonts are loaded/unloaded + + /* PRECONDITION */ + { + GLOBALASSERT( I_Font_Changed < IndexedFonts_MAX_NUMBER_OF_FONTS ); + } + + /* CODE */ + { + IndexedFont* pFont = IndexedFont :: GetFont( I_Font_Changed ); + + SCString* pSCString = pFirst; + + while ( pSCString ) + { + if ( pFont ) + { + #if EnableSizeData + pSCString -> R2Size[ I_Font_Changed ] = pFont -> CalcSize + ( + pSCString -> pProjCh_Val + ); + #endif + + pSCString -> bCanRender[ I_Font_Changed ] = pFont -> bCanRenderFully + ( + pSCString -> pProjCh_Val + ); + } + else + { + #if EnableSizeData + pSCString -> R2Size[ I_Font_Changed ] = r2size(0,0); + #endif + + pSCString -> bCanRender[ I_Font_Changed ] = No; + } + + pSCString = pSCString -> pNxt; + } + } +} + +/*static*/ List SCString :: Parse +( + ProjChar* pProjChar_Start +) +{ + // takes a string and builds a list of new SCStrings, in which + // each string in the list consists of non-whitespace characters from + // the input, and the whitespace is used to separate individual + // strings + + // I call the strings "words" + + /* PRECONDITION */ + { + GLOBALASSERT( pProjChar_Start ); + } + + /* CODE */ + { + List List_Return; + + ProjChar* pProjChar_Iterate = pProjChar_Start; + int NumCharsNonWhitespace = 0; + + while + ( + *pProjChar_Iterate + ) + { + if + ( + *pProjChar_Iterate == ' ' + ) + { + // Whitespace: + if ( NumCharsNonWhitespace > 0 ) + { + // End of a word; add the string to the list: + List_Return . add_entry + ( + new SCString + ( + pProjChar_Start, + NumCharsNonWhitespace + ) + ); + NumCharsNonWhitespace = 0; + } + else + { + // Already processing a block of whitespace; do nothing + } + } + else + { + // Non-whitespace: + if ( NumCharsNonWhitespace > 0 ) + { + // In the middle of a word: + } + else + { + // Start of a word: + pProjChar_Start = pProjChar_Iterate; + } + + NumCharsNonWhitespace++; + + } + + pProjChar_Iterate++; + } + + // End of the string; flush any remaining whitespace: + if ( NumCharsNonWhitespace > 0 ) + { + List_Return . add_entry + ( + new SCString + ( + pProjChar_Start, + NumCharsNonWhitespace + ) + ); + } + + return List_Return; + } +} + + +//private: +SCString :: ~SCString() +{ + /* PRECONDITION */ + { + GLOBALASSERT( pProjCh_Val ); + } + + /* CODE */ + { + delete[] pProjCh_Val; + + // Remove from list: + { + if ( pFirst == this ) + { + pFirst = pNxt; + } + else + { + pPrv -> pNxt = pNxt; + } + + if (pNxt) + { + pNxt -> pPrv = pPrv; + } + } + + } +} + +#if SupportHHStuff +HHStringTable* STRUTIL_LoadStringTable(char* Filename,Failure_Behaviour FailBehav) +{ + /* PRECONDITION */ + { + GLOBALASSERT(Filename); + } + /* CODE */ + { + /* Allocate memory for a table of pointers to strings in memory */ + HHStringTable* pHHST= (HHStringTable*)AllocateMem + ( + sizeof(HHStringTable) + ); + + if (!pHHST) + { + /* Out of memory */ + + return 0; + } + else + { + + /* Load the file into a buffer in memory */ + OurByteBuffer ByteBuf; + OurByte* pTextBuffer; + + { + /* clear the pointers in the new string table */ + int i = MAX_ENTRIES_PER_STRING_TABLE; + while (i>0) + { + i--; + + pHHST -> pStringObj[i] = NULL; + } + + } + + HHFILE_LoadLogicalFile + ( + Filename, + FailBehav, + &ByteBuf + ); + + pTextBuffer=ByteBuf.pbData; + + if (!pTextBuffer) + { + /* Error loading file */ + return 0; + } + else + { + /* Build table of string pointers in the buffer */ + + #define START_OF_COMMENT_TC ('#') + #define END_OF_COMMENT_TC (0x0D) + #define SKIP_TC (0x0A) + + /* + Scan through loaded buffer, finding strings, making copies with NULL termination, + until you reach the end (can be signified by EOF or by two successive # characters + without intermediate end-of-comment chars) + + When done, free up loaded buffer. + */ + + OurByte* pbExtract=pTextBuffer; + unsigned int CountChars=0; + OurBool StillGoing=Yes; + + OurBool FoundStartChar=No; + OurBool FoundEndChar=No; + ProjChar* pChStart=NULL; + unsigned int CountSinceEndChar=0; + unsigned int SkipChars=0; + + pHHST->NumEntries_Val=0; + + while + ( + (CountChars<(ByteBuf.NumBytes)) + && + (StillGoing) + ) + { + ProjChar TChar=(ProjChar)*pbExtract; + + switch (TChar) + { + case SKIP_TC: + /* Skip this char */ + { + SkipChars++; + } + break; + + case START_OF_COMMENT_TC: + if (FoundStartChar) + { + /* Two successive StartOf.. TChars without a EndOf... are a termination sequence */ + StillGoing=No; + } + else + { + /* It is the start of a comment */ + FoundStartChar=Yes; + } + break; + case END_OF_COMMENT_TC: + if (FoundEndChar) + { + /* This is the terminating character of a string; copy it up */ + LOCALASSERT(pChStart); + + /* copy it up here...*/ + #if LimitedStringLengths + LOCALASSERT(CountSinceEndCharNumEntries() < MAX_ENTRIES_PER_STRING_TABLE); + + #if 1 + pHHST->pStringObj[ (pHHST->NumEntries_Val++) ] = new SCString + ( + NewString + ); // you get an automatic reference when you construct it. + + DeallocateMem( NewString ); + + #else + pHHST->pEntry[(pHHST->NumEntries_Val++)]=NewString; + #endif + + + } + } + + FoundEndChar=No; + FoundStartChar=No; + CountSinceEndChar=0; + SkipChars=0; + pChStart=NULL; + } + else + { + if (FoundStartChar) + { + /* Then this signifies the end of a comment and the start of the string */ + FoundEndChar=Yes; + CountSinceEndChar=0; + SkipChars=0; + + /* Start extracting string from next character onwards...*/ + pChStart=(pbExtract+1); + } + /* else it is padding; ignore */ + + } + + break; + default: + /* It is a normal character...*/ + if (FoundEndChar) + { + CountSinceEndChar++; + } + + break; + } + + /* On to next character */ + pbExtract++; + CountChars++; + } + + + DeallocateMem(pTextBuffer); + + #if (debug && LogStringTables ) + { + int i; + char Temp[200]; + + sprintf(Temp,"Loaded string table:\"%s\"",Filename); + DAVELOG(Temp); + + sprintf(Temp,"Number of strings=%i",pHHST->NumEntries); + DAVELOG(Temp); + + for (i=0;iNumEntries();i++) + { + GLOBALASSERT(pHHST->pStringObj[i]); + + if + ( + STRUTIL_SC_Strlen + ( + pHHST -> pStringObj[i] -> pProjCh() + ) < 100 + ) + { + sprintf + ( + Temp, + "Entry %3i=\"%s\"", + i, + pHHST -> pStringObj[i] -> pProjCh() + ); + DAVELOG(Temp); + } + else + { + DAVELOG("String too long to log"); + } + } + sprintf(Temp,"End of string table:\"%s\"",Filename); + DAVELOG(Temp); + } + #endif + + // Clear the lazy evaluation table: + { + MCSCString** ppMCStringObj_Clear = &(pHHST -> pMCStringObj[ 0 ][ 0 ]); + + for ( int i=pHHST->NumEntries(); i>0; i--) + { + for ( int j = NUM_BASE_COLOURS; j > 0; j-- ) + { + *(ppMCStringObj_Clear++) = NULL; + } + } + } + + /* Return a pointer to this table */ + return pHHST; + } + } + } +} + +void STRUTIL_UnloadStringTable(HHStringTable* pHHST) +/* This function DOES deallocate the passed structure */ +{ + /* PRECONDITION */ + { + GLOBALASSERT(pHHST); + } + /* CODE */ + { + /* Kill off strings in table */ + int i; + + for (i=0;iNumEntries();i++) + { + #if 1 + LOCALASSERT( pHHST->pStringObj[i] ); + pHHST -> pStringObj[i] -> R_Release(); + #else + LOCALASSERT(pHHST->pEntry[i]); + DeallocateMem(pHHST->pEntry[i]); + #endif + } + + // R_Release any refs in the lazy evaluation table: + { + for (i=0;iNumEntries();i++) + { + for ( int j=0; j< NUM_BASE_COLOURS; j++ ) + { + if ( pHHST -> pMCStringObj[i][j] ) + { + pHHST -> pMCStringObj[ i ][ j ] -> R_Release(); + } + } + } + } + + /* Kill off table of pointers */ + DeallocateMem(pHHST); + } +} + +ProjChar* STRUTIL_SC_GetString(HHStringTable* pHHST,unsigned int StrNum) +{ + /* PRECONDITION */ + { + GLOBALASSERT(pHHST); + GLOBALASSERT(StrNumNumEntries()); + GLOBALASSERT(StrNum< MAX_ENTRIES_PER_STRING_TABLE); + } + /* CODE */ + { + GLOBALASSERT( pHHST -> pStringObj[StrNum] ); + GLOBALASSERT( pHHST -> pStringObj[StrNum] -> pProjCh() ); + + return pHHST -> pStringObj[StrNum] -> pProjCh(); + } +} + +unsigned int STRUTIL_GetNumEntries +( + HHStringTable* pHHST +) +{ + /* PRECONDITION */ + { + GLOBALASSERT(pHHST); + } + /* CODE */ + { + unsigned int ReturnVal = pHHST -> NumEntries(); + GLOBALASSERT( ReturnVal <= MAX_ENTRIES_PER_STRING_TABLE); + + return ReturnVal; + } +} + +SCString* STRUTIL_GetSCString +( + HHStringTable* pHHST, + unsigned int StrNum +) +{ + /* PRECONDITION */ + { + GLOBALASSERT(pHHST); + GLOBALASSERT(StrNumNumEntries()); + GLOBALASSERT(StrNum< MAX_ENTRIES_PER_STRING_TABLE); + } + /* CODE */ + { + GLOBALASSERT( pHHST -> pStringObj[StrNum] ); + GLOBALASSERT + ( + pHHST -> pStringObj[StrNum] -> CheckRef() + > + 0 + ); + // check that the reference count is above zero + // otherwise some code has messed up the reference + // count and the string will have been deallocated... + + pHHST -> pStringObj[StrNum] -> R_AddRef(); + + return pHHST -> pStringObj[StrNum]; + } +} + +SCString* hhstringtablestruct :: GetSCString +( + unsigned int StrNum +) +{ + /* PRECONDITION */ + { + GLOBALASSERT(StrNum< NumEntries() ); + GLOBALASSERT(StrNum< MAX_ENTRIES_PER_STRING_TABLE); + } + + /* CODE */ + { + GLOBALASSERT( pStringObj[StrNum] ); + GLOBALASSERT + ( + pStringObj[StrNum] -> CheckRef() + > + 0 + ); + // check that the reference count is above zero + // otherwise some code has messed up the reference + // count and the string will have been deallocated... + + pStringObj[StrNum] -> R_AddRef(); + + return pStringObj[StrNum]; + } +} + +MCSCString* hhstringtablestruct :: GetMCSCString +( + unsigned int StrNum, + LogicalColour LogCol +) +{ + /* PRECONDITION */ + { + GLOBALASSERT(StrNum< NumEntries() ); + GLOBALASSERT(StrNum< MAX_ENTRIES_PER_STRING_TABLE); + } + + /* CODE */ + { + // Lazily evaluate: + if + ( + NULL == pMCStringObj[ StrNum ][ LogCol ] + ) + { + // no updating of reference count of SCString + // due to direct access to the array + pMCStringObj[ StrNum ][ LogCol ] = new MCSCString + ( + pStringObj[StrNum], + LogCol + ); + } + + GLOBALASSERT( pMCStringObj[ StrNum ][ LogCol ] ); + + pMCStringObj[ StrNum ][ LogCol ] -> R_AddRef(); + + return pMCStringObj[ StrNum ][ LogCol ]; + } +} + + + + + +#if debug +void STRUTIL_Diagnostics(void) +{ + /* CODE */ + { + #if 0 + int i; + + for (i=0;iNumEntries;i++) + { + GLOBALASSERT(strlen(pHHST_UserInterface->pEntry[0])<90); + textprint("String %i = \"%s\"\n",i,pHHST_UserInterface->pEntry[i]); + } + #endif + } + + #if 0 + { + int i; + + for + textprint("%50s",pHHST_UserInterface->pEntry[0]); + } + #endif +} +#endif + +/* Internal function definitions ***********************************/ +static void strutil_Failure(Failure_Behaviour FailBehav) +{ + /* unwritten */ + + return; +} +#endif // SupportHHStuff + diff --git a/3dc/avp/support/scstring.hpp b/3dc/avp/support/scstring.hpp new file mode 100644 index 0000000..257cfdc --- /dev/null +++ b/3dc/avp/support/scstring.hpp @@ -0,0 +1,271 @@ +/* + + scstring.hpp + +*/ + +#ifndef _scstring +#define _scstring 1 + + #define SupportHHStuff No + + #ifndef _refobj + #include "refobj.hpp" + #endif + + #ifndef _ourbool + #include "ourbool.h" + #endif + + #if SupportHHStuff + #ifndef HHSTRING + #include "hhstring.h" + #endif + + #ifndef FDIPUB_INCLUDED + #include "fdipub.h" + #endif + #else + #ifndef _projtext + #include "projtext.h" + #endif + + #ifndef _projfont + #include "projfont.h" + #endif + + #ifndef _r2base + #include "r2base.h" + #endif + + #endif + + #ifndef list_template_hpp + #include "list_tem.hpp" + #endif + + #define EnableSizeData Yes + + class SCString : public RefCountObject + { + public: + ProjChar* pProjCh(void) const; + + SCString + ( + const ProjChar* pProjCh_Init + ); // you get an automatic reference when you construct it. + + SCString + ( + signed int Number + ); + + SCString + ( + unsigned int Number + ); + // forms a new string object that describes the number passed + // standard decimal representation + + SCString + ( + float Number + ); + // the string is to a standard number of decimal places + + + SCString + ( + ProjChar* pProjCh_Init, + unsigned int Length + ); + // Forms a string of length at most Length (with 1 extra for NULL-terminator) + + SCString + ( + SCString* pStringObj_0, + SCString* pStringObj_1 + ); + // forms a new string object by concatenating the strings in 0 + // and 1 + + SCString + ( + SCString* pStringObj_0, + SCString* pStringObj_1, + SCString* pStringObj_2 + ); + // forms a new string object by concatenating the strings in 0, 1 and 2 + + SCString + ( + SCString* pStringObj_0, + SCString* pStringObj_1, + SCString* pStringObj_2, + SCString* pStringObj_3 + ); + // forms a new string object by concatenating the strings; + // implementation is _slow_ + + SCString + ( + SCString* pStringObj_0, + SCString* pStringObj_1, + SCString* pStringObj_2, + SCString* pStringObj_3, + SCString* pStringObj_4 + ); + // forms a new string object by concatenating the strings; + // implementation is _slow_ + + SCString + ( + List List_ProjChar + ); + + #if SupportHHStuff + void GetSizeOfSingleLineGivenStandardFont + ( + FDIBMAP* pFDIBMap_Out + ); + FDIBMAP GetSizeOfSingleLineGivenStandardFont(void); + int GetWidthOfSingleLineGivenStandardFont(void); + + FDIQUAD MinFDIQuadForSCStringAtPos + ( + FDIPOS FDIPos + ); + #else + r2size CalcSize + ( + FontIndex I_Font + ); + // Size for this string drawn on a single line in the specified font + // Behaviour is not fully defined when unprintable characters occur in the string + + OurBool bCanRenderFully( FontIndex I_Font ); + // can this string be fully rendered by the font (not all fonts support + // all characters) ? + + static void UpdateAfterFontChange( FontIndex I_Font_Changed ); + // called by the font code whenever fonts are loaded/unloaded + #endif + + unsigned int GetNumChars(void); + + void ProcessAnyCheatCodes(void); + + void SendToScreen(void); + // adds this as a new on-screen message + + static List Parse + ( + ProjChar* pProjChar_In + ); + // takes a string and builds a list of new SCStrings, in which + // each string in the list consists of non-whitespace characters from + // the input, and the whitespace is used to separate individual + // strings + + #if TrackReferenceCounted + void DumpIDForReferenceDump(R_DumpContext& theContext) const; + #endif + + private: + ~SCString(); + // private destructor; only called when reference count hits zero + + ProjChar* pProjCh_Val; + // this is always "owned" by the String execpt when + // fAllocFailure is set + + int NumberOfCharacters; + // doesn't include NULL terminator + + #if SupportHHStuff + int WidthGivenStandardFont; + // width in pixels, to save constant recalc + #else + #if EnableSizeData + r2size R2Size[ IndexedFonts_MAX_NUMBER_OF_FONTS ]; + #endif + + OurBool bCanRender[ IndexedFonts_MAX_NUMBER_OF_FONTS ]; + #endif + + size_t AllocatedSize; + // this includes the NULL terminator + + // Maintain an intrusive doubly-linked list + // so that you can find all the strings when a font is loaded/unloaded + // and hence update their data + // Strings are added to the front of the list upon construction + SCString* pNxt; + SCString* pPrv; + static SCString* pFirst; + }; // Naming: "StringObj" + + // Inline methods: + #if !SupportHHStuff + #if EnableSizeData + inline r2size SCString::CalcSize + ( + FontIndex I_Font + ) + { + return R2Size[ I_Font ]; + } + #endif + + inline OurBool SCString::bCanRenderFully( FontIndex I_Font ) + { + return bCanRender[ I_Font ]; + } + #endif // !SupportHHStuff + + inline unsigned int SCString::GetNumChars(void) + { + return NumberOfCharacters; + } + + #if SupportHHStuff + extern SCString* HHSTRING_GetSCString + ( + HHStringTable* pHHST, + unsigned int StrNum + ); + // The result is guaranteed to be non-NULL if you pick a valid + // StrNum. + + // Remember to call R_AddRef() if you use the result + // NO LONGER THE CASE!!!! + #endif + + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif + + diff --git a/3dc/avp/support/strtab.cpp b/3dc/avp/support/strtab.cpp new file mode 100644 index 0000000..74a367d --- /dev/null +++ b/3dc/avp/support/strtab.cpp @@ -0,0 +1,160 @@ +/******************************************************************* + * + * DESCRIPTION: strtab.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 12 Nov 97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "strtab.hpp" + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ +#if OnlyOneStringTable + /*static*/ SCString* StringTable :: pSCString[ MAX_NO_OF_TEXTSTRINGS ]; + /*static*/ unsigned int StringTable :: NumStrings = 0; +#endif + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +// class StringTable +// public: +/*STRINGTABLE_DECL_SPECIFIER*/ SCString& StringTable :: GetSCString +( + enum TEXTSTRING_ID stringID +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( stringID < MAX_NO_OF_TEXTSTRINGS ); + GLOBALASSERT( pSCString[ stringID ] ); + } + + /* CODE */ + { + pSCString[ stringID ] -> R_AddRef(); + return *( pSCString[ stringID ] ); + } +} + + +/*STRINGTABLE_DECL_SPECIFIER*/ void StringTable :: Add( ProjChar* pProjChar ) +{ + /* PRECONDITION */ + { + GLOBALASSERT( NumStrings < MAX_NO_OF_TEXTSTRINGS ); + GLOBALASSERT( pSCString[ NumStrings ] == 0 ); + } + + /* CODE */ + { + pSCString[ NumStrings++ ] = new SCString( pProjChar ); + } +} + +#if OnlyOneStringTable +/*static*/ void StringTable :: Unload(void) +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + while ( NumStrings ) + { + pSCString[ --NumStrings ] -> R_Release(); + } + } +} +#else +StringTable :: StringTable() +{ + NumStrings = 0; +} + +StringTable :: ~StringTable() +{ + while ( NumStrings ) + { + pSCString[ --NumStrings ] -> R_Release(); + } +} +#endif + + +// private: + +// C-callable functions: +#if OnlyOneStringTable +extern void AddToTable( ProjChar* pProjChar ) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pProjChar ); + } + + /* CODE */ + { + StringTable :: Add( pProjChar ); + } +} + +extern void UnloadTable(void) +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + StringTable :: Unload(); + } +} +#endif + + + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/support/strtab.hpp b/3dc/avp/support/strtab.hpp new file mode 100644 index 0000000..da4bd6d --- /dev/null +++ b/3dc/avp/support/strtab.hpp @@ -0,0 +1,81 @@ +/* + + strtab.hpp + +*/ + +#ifndef _strtab +#define _strtab 1 + + #ifndef _projtext + #include "projtext.h" + #endif + + #ifndef _langenum_h_ + #include "langenum.h" + #endif + + #ifdef __cplusplus + #ifndef _scstring + #include "scstring.hpp" + #endif + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + #define OnlyOneStringTable Yes + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + #if OnlyOneStringTable + #define STRINGTABLE_DECL_SPECIFIER static + #else + #define STRINGTABLE_DECL_SPECIFIER + #endif + +/* Type definitions *****************************************************/ + #ifdef __cplusplus + class StringTable + { + public: + STRINGTABLE_DECL_SPECIFIER SCString& GetSCString + ( + enum TEXTSTRING_ID stringID + ); + + STRINGTABLE_DECL_SPECIFIER void Add( ProjChar* pProjChar ); + + #if OnlyOneStringTable + static void Unload(void); + #else + StringTable(); + ~StringTable(); + #endif + + private: + STRINGTABLE_DECL_SPECIFIER unsigned int NumStrings; + STRINGTABLE_DECL_SPECIFIER SCString* pSCString[ MAX_NO_OF_TEXTSTRINGS ]; + }; + #endif // __cplusplus + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + #if OnlyOneStringTable + extern void AddToTable( ProjChar* pProjChar ); + extern void UnloadTable(void); + #endif + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/support/strutil.c b/3dc/avp/support/strutil.c new file mode 100644 index 0000000..8175a2e --- /dev/null +++ b/3dc/avp/support/strutil.c @@ -0,0 +1,834 @@ +/* + + STRUTIL.C + + Created 13/11/97 by David Malcolm from Headhunter code: more carefully specified + versions of the C string library functions, to act on ProjChars + rather than chars + +*/ + +#include "3dc.h" + +#include "strutil.h" + +#if 0 +#include "hhfile.h" + +#include "hhcolour.h" + +#include "daveserr.h" + +#include "inouttxt.h" +#include "menutxt.h" + +#include "davelog.h" +#endif + +#define UseLocalAssert Yes +#include "ourasert.h" + + + +/* VERSION DEFINES */ +#define LogStringTables No + +#define MAX_ENTRIES_PER_STRING_TABLE (200) +#define LimitedStringLengths Yes +#if LimitedStringLengths +#define MAX_STRING_LENGTH (30000) +#endif + +/* TYPE DEFINITIONS */ +#if 0 +static HHMCTC HHMCTS_Terminator={'\0',LogCol_OpaqueBlack}; +#endif + +/* EXPORTED GLOBALS */ + +#if 0 +HHStringTable* pHHST_UserInterface = NULL; +HHStringTable* pHHST_MenuText = NULL; + +HHMCTC* HHMCTS_Blank=&HHMCTS_Terminator; +#endif + +/* EXPORTED FUNCTION PROTOTYPES */ +#if 0 +void STRUTIL_Init(void) +{ + pHHST_UserInterface=STRUTIL_LoadStringTable("hh/testdata/inout.txt",OnFailure_ExitSystem); + + LOCALASSERT(pHHST_UserInterface); + /* + If error loading text file containing the error message text strings, + there is no real way to generate an error message... + */ + LOCALASSERT + ( + STRUTIL_GetNumEntries + ( + pHHST_UserInterface + ) + == + NUM_IN_OUT_TXT_MESSAGES + ); + + /* If we reach here, user interface messages have been loaded Ok... */ + + + pHHST_MenuText = STRUTIL_LoadStringTable + ( + "hh/testdata/menu.txt", + OnFailure_ExitSystem + ); + LOCALASSERT( pHHST_MenuText ); + LOCALASSERT + ( + STRUTIL_GetNumEntries + ( + pHHST_MenuText + ) + == + NUM_MENU_TXT_MESSAGES + ); + +} + +void STRUTIL_Destroy(void) +{ + LOCALASSERT(pHHST_UserInterface); + + STRUTIL_UnloadStringTable(pHHST_UserInterface); + + LOCALASSERT(pHHST_MenuText); + + STRUTIL_UnloadStringTable(pHHST_MenuText); + +} +#endif + +void STRUTIL_SC_WriteTerminator(ProjChar* pProjCh) +{ + /* Supplied as a function in case we switch to double-byte character sets */ + + *pProjCh='\0'; + +} + +#if 0 +void STRUTIL_MC_WriteTerminator +( + HHMCTC* pHHMCTC +) +{ + GLOBALASSERT(pHHMCTC); + /* Supplied as a function in case we switch to double-byte character sets */ + + pHHMCTC->Char='\0'; +} +#endif + + +/* Ansi to HHTS conversion ********************************************/ +OurBool STRUTIL_ANSI_To_ProjChar +( + ProjChar* pProjCh_Out, + unsigned int MaxSize, /* includes NULL-terminator; truncates after this */ + + LPTSTR lptszANSI_In +) +{ + /* PRECONDITION */ + { + GLOBALASSERT(pProjCh_Out); + GLOBALASSERT(lptszANSI_In); + } + + /* CODE */ + { + /* For the moment: */ + return STRUTIL_SC_SafeCopy + ( + pProjCh_Out, + MaxSize, + + lptszANSI_In + ); + } +} + +OurBool STRUTIL_ProjChar_To_ANSI +( + LPTSTR lptszANSI_Out, + unsigned int MaxSize, /* includes NULL-terminator; truncates after this */ + +ProjChar* pProjCh_In +) +{ + /* PRECONDITION */ + { + GLOBALASSERT(lptszANSI_Out); + GLOBALASSERT(pProjCh_In); + } + + /* CODE */ + { + /* For the moment: */ + return STRUTIL_SC_SafeCopy + ( + lptszANSI_Out, + MaxSize, + + pProjCh_In + ); + } +} + +unsigned int STRUTIL_SC_Strlen +( + const ProjChar* String +) +{ + GLOBALASSERT(String); + + return strlen(String); +} + +#if 0 +unsigned int STRUTIL_MC_Strlen +( + HHMCTC* MCString +) +{ + unsigned int Count=0; + + while (MCString->Char!='\0') + { + MCString++; + Count++; + } + return Count; +} +#endif + + +ProjChar* STRUTIL_SC_StrCpy +( + ProjChar* pProjCh_Dst, + const ProjChar* pProjCh_Src +) +{ + GLOBALASSERT(pProjCh_Dst); + GLOBALASSERT(pProjCh_Src); + + return (strcpy(pProjCh_Dst,pProjCh_Src)); +} + +void STRUTIL_SC_FastCat +( + ProjChar* pProjCh_Dst, + const ProjChar* pProjCh_Src_0, + const ProjChar* pProjCh_Src_1 +) +{ + /* This function assumes the destination area is large enough; + it copies Src0 followed by Src1 to the dest area. + */ + + /* PRECONDITION */ + { + GLOBALASSERT( pProjCh_Dst ); + GLOBALASSERT( pProjCh_Src_0 ); + GLOBALASSERT( pProjCh_Src_1 ); + } + + /* CODE */ + { + while ( *pProjCh_Src_0 ) + { + *( pProjCh_Dst++ ) = *( pProjCh_Src_0++ ); + } + while ( *pProjCh_Src_1 ) + { + *( pProjCh_Dst++ ) = *( pProjCh_Src_1++ ); + } + + /* Write terminator */ + *pProjCh_Dst = 0; + } +} + + +OurBool STRUTIL_SC_Strequal +( + const ProjChar* String1, + const ProjChar* String2 +) +{ +#if 0 + DAVELOG("Comparing strings"); + DAVELOG(String1); + DAVELOG(String2); +#endif + + while + ( + (*String1!='\0') + && + (*String2!='\0') + ) + { + if + ( + (*String1) + != + (*String2) + ) + { + return No; + } + String1++; + String2++; + } + + return + ( + (*String1) + == + (*String2) + ); +} + +OurBool STRUTIL_SC_Strequal_Insensitive +( + const ProjChar* String1, + const ProjChar* String2 +) +{ + + while + ( + (*String1!='\0') + && + (*String2!='\0') + ) + { + if + ( + (tolower(*String1)) + != + (tolower(*String2)) + ) + { + return No; + } + String1++; + String2++; + } + + return + ( + (tolower(*String1)) + == + (tolower(*String2)) + ); +} + + +#if 0 +void STRUTIL_MC_MakeMCTS +( + HHMCTC* DestString, + ProjChar* InputString, + LogicalColour LogCol +) +{ + /* PRECONDITION */ + { + GLOBALASSERT(DestString); + GLOBALASSERT(InputString); + GLOBALASSERT(LogColChar=*InputString; + DestString->LogCol=LogCol; + + InputString++; + DestString++; + } + + STRUTIL_MC_WriteTerminator(DestString); + } +} +#endif + +void STRUTIL_SC_SafeCat +( + ProjChar* pProjCh_Dst, + unsigned int MaxSize, + + const ProjChar* pProjCh_Add +) +{ + /* PRECONDITION */ + { + GLOBALASSERT(pProjCh_Dst); + GLOBALASSERT(pProjCh_Add); + GLOBALASSERT(MaxSize>0); + } + + /* CODE */ + { + unsigned int MaxNonTerminatingCharsToUse = (MaxSize - 1); + + while + ( + (*pProjCh_Dst) + && + (MaxNonTerminatingCharsToUse>0) + ) + { + pProjCh_Dst++; + MaxNonTerminatingCharsToUse--; + } + + while + ( + (*pProjCh_Add) + && + (MaxNonTerminatingCharsToUse>0) + ) + { + *pProjCh_Dst = *pProjCh_Add; + + pProjCh_Add++; + pProjCh_Dst++; + + MaxNonTerminatingCharsToUse--; + + STRUTIL_SC_WriteTerminator(pProjCh_Dst); + } + } +} + +size_t STRUTIL_SC_NumBytes +( + const ProjChar* String +) +{ + return + ( + sizeof(ProjChar) + * + (STRUTIL_SC_Strlen(String)+1) + ); +} + +#if 0 +size_t STRUTIL_MC_NumBytes(HHMCTC* MCString) +{ + return STRUTIL_MC_LengthToNumBytes + ( + STRUTIL_MC_Strlen(MCString) + ); +} + +size_t STRUTIL_MC_NumBytesFromSC +( + ProjChar* pProjCh +) +{ + return STRUTIL_MC_LengthToNumBytes + ( + STRUTIL_SC_Strlen(pProjCh) + ); +} + +size_t STRUTIL_MC_LengthToNumBytes(unsigned int Length) +{ + return + ( + sizeof(HHMCTC) + * + (Length+1) + ); +} + + +void STRUTIL_MC_CatHHTSOntoMCTS +( + HHMCTC* DestString, + ProjChar* InputString, + LogicalColour LogCol +) +{ + /* PRECONDITION */ + { + GLOBALASSERT(DestString); + GLOBALASSERT(InputString); + GLOBALASSERT(LogColChar) + { + DestString++; + } + + while (*InputString) + { + DestString->Char=*InputString; + DestString->LogCol=LogCol; + + InputString++; + DestString++; + + STRUTIL_MC_WriteTerminator(DestString); + } + } +} + +void STRUTIL_MC_SafeMakeMCTS +( + HHMCTC* DestString, + unsigned int MaxSize, + + ProjChar* InputString, + LogicalColour LogCol +) +{ + /* PRECONDITION */ + { + GLOBALASSERT(DestString); + GLOBALASSERT(InputString); + GLOBALASSERT(LogCol0); + } + + /* CODE */ + { + unsigned int MaxNonTerminatingCharsToUse = (MaxSize - 1); + + while + ( + (*InputString) + && + (MaxNonTerminatingCharsToUse > 0) + ) + { + DestString->Char=*InputString; + DestString->LogCol=LogCol; + + InputString++; + DestString++; + MaxNonTerminatingCharsToUse--; + } + + STRUTIL_MC_WriteTerminator(DestString); + } +} + +void STRUTIL_MC_SafeCatHHTSOntoMCTS +( + HHMCTC* DestString, + unsigned int MaxSize, + + ProjChar* AddString, + LogicalColour LogCol +) +{ + /* PRECONDITION */ + { + GLOBALASSERT(DestString); + GLOBALASSERT(AddString); + GLOBALASSERT(LogCol0); + } + + /* CODE */ + { + unsigned int MaxNonTerminatingCharsToUse = (MaxSize - 1); + + while + ( + (DestString->Char) + && + (MaxNonTerminatingCharsToUse>0) + ) + { + DestString++; + MaxNonTerminatingCharsToUse--; + } + + while + ( + (*AddString) + && + (MaxNonTerminatingCharsToUse>0) + ) + { + DestString->Char=*AddString; + DestString->LogCol=LogCol; + + AddString++; + DestString++; + + MaxNonTerminatingCharsToUse--; + + STRUTIL_MC_WriteTerminator(DestString); + } + } +} + + +OurBool fValidHHMCTS(HHMCTC* MCString) +{ + GLOBALASSERT(MCString); + + { + unsigned int CharCount=0; + + while + ( + (MCString->Char!='\0') +#if LimitedStringLengths + && + (CharCountLogCol>=NUM_BASE_COLOURS) + { + DAVELOG("Invalid colour in MC String"); + return No; + } + MCString++; + } + + #if LimitedStringLengths + { + if (CharCount>=MAX_STRING_LENGTH) + { + DAVELOG("MC String too long..."); + return No; + } + else + { + return Yes; + } + } + #else + { + return Yes; + } + #endif + + } +} + +HHMCTC STRUTIL_SC_To_MC +( + ProjChar Char, + LogicalColour LogCol +) +{ + HHMCTC ReturnVal; + + ReturnVal. Char = Char; + ReturnVal. LogCol = LogCol; + + return ReturnVal; +} +#endif + +OurBool STRUTIL_SC_SafeCopy +( + ProjChar* pProjCh_Dst, + unsigned int MaxSize, + + const ProjChar* pProjCh_Src +) +{ + GLOBALASSERT(pProjCh_Dst); + GLOBALASSERT(MaxSize > 0); + GLOBALASSERT(pProjCh_Src); + + { + unsigned int MaxNonTerminatingCharsToCopy = (MaxSize - 1); + + while + ( + (MaxNonTerminatingCharsToCopy > 0 ) + && + (*pProjCh_Src != 0) + ) + { + MaxNonTerminatingCharsToCopy--; + *(pProjCh_Dst++) = *(pProjCh_Src++); + } + + STRUTIL_SC_WriteTerminator(pProjCh_Dst); + + return ( STRUTIL_SC_fIsTerminator(pProjCh_Src) ); + } + +} + +#if 0 +OurBool STRUTIL_MC_SafeCopy +( + HHMCTC* pHHMCTC_Dst, + unsigned int MaxSize, + + HHMCTC* pHHMCTC_Src + +) +{ + /* PRECONDITION */ + { + GLOBALASSERT(pHHMCTC_Dst); + GLOBALASSERT(MaxSize > 0); + GLOBALASSERT(pHHMCTC_Src); + } + + /* CODE */ + { + #if 1 + HHMCTC* pHHMCTC_StoredDst = pHHMCTC_Dst; + #endif + + { + unsigned int MaxNonTerminatingCharsToCopy = (MaxSize - 1); + + while + ( + (MaxNonTerminatingCharsToCopy > 0 ) + && + (!STRUTIL_MC_fIsTerminator(pHHMCTC_Src)) + ) + { + MaxNonTerminatingCharsToCopy--; + *(pHHMCTC_Dst++) = *(pHHMCTC_Src++); + } + + STRUTIL_MC_WriteTerminator(pHHMCTC_Dst); + + #if 0 + { + char temp[256]; + sprintf + ( + temp, + "STRUTIL_MC_SafeCopy maxsize %i", + MaxSize + ); + DAVELOG(temp); + + { + HHMCTC* pHHMCTC = pHHMCTC_StoredDst; + char* pCh_Out = &temp[0]; + while ( pHHMCTC -> Char != '\0' ) + { + *(pCh_Out++) = ( *(pHHMCTC++) ).Char; + } + *pCh_Out = '\0'; + } + DAVELOG(temp); + } + #endif + + return ( STRUTIL_MC_fIsTerminator(pHHMCTC_Src) ); + + } + } + +} +#endif + +OurBool STRUTIL_SC_fIsTerminator +( + const ProjChar* pProjCh +) +{ + GLOBALASSERT(pProjCh); + return (*pProjCh == '\0'); +} + +#if 0 +OurBool STRUTIL_MC_fIsTerminator(HHMCTC* pHHMCTC) +{ + GLOBALASSERT(pHHMCTC); + return ((pHHMCTC->Char) == '\0'); +} + + +HHMCTC* STRUTIL_MC_StrCpy +( + HHMCTC* pHHMCTC_Dst, + HHMCTC* pHHMCTC_Src +) +{ + GLOBALASSERT(pHHMCTC_Dst); + GLOBALASSERT(pHHMCTC_Src); + + while + ( + pHHMCTC_Src->Char != '\0' + ) + { + *(pHHMCTC_Dst++) = *(pHHMCTC_Src++); + } + pHHMCTC_Dst->Char = '\0'; +} + +HHMCTC* STRUTIL_MC_FastCat +( + HHMCTC* pHHMCTC_Dst, + HHMCTC* pHHMCTC_Src_0, + HHMCTC* pHHMCTC_Src_1 +) +{ + /* This function assumes the destination area is large enough; + it copies Src0 followed by Src1 to the dest area. + */ + + /* PRECONDITION */ + { + GLOBALASSERT( pHHMCTC_Dst ); + GLOBALASSERT( pHHMCTC_Src_0 ); + GLOBALASSERT( pHHMCTC_Src_1 ); + } + + /* CODE */ + { + while + ( + (!STRUTIL_MC_fIsTerminator(pHHMCTC_Src_0)) + ) + { + *(pHHMCTC_Dst++) = *(pHHMCTC_Src_0++); + } + + while + ( + (!STRUTIL_MC_fIsTerminator(pHHMCTC_Src_1)) + ) + { + *(pHHMCTC_Dst++) = *(pHHMCTC_Src_1++); + } + + STRUTIL_MC_WriteTerminator(pHHMCTC_Dst); + + return pHHMCTC_Dst; + } +} + + +#endif diff --git a/3dc/avp/support/strutil.h b/3dc/avp/support/strutil.h new file mode 100644 index 0000000..0659dca --- /dev/null +++ b/3dc/avp/support/strutil.h @@ -0,0 +1,138 @@ +/* + + strutil.h + + Created 13/11/97 by David Malcolm: more carefully specified + versions of the C string library functions, to act on ProjChars + rather than chars + +*/ + +#ifndef _strutil +#define _strutil 1 + + #ifndef _projtext + #include "projtext.h" + #endif + + #ifndef _ourbool + #include "ourbool.h" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + /* String manipulation **********************************************/ + extern void STRUTIL_SC_WriteTerminator + ( + ProjChar* pProjCh + ); + + extern OurBool STRUTIL_SC_fIsTerminator + ( + const ProjChar* pProjCh + ); + + /* Ansi to HHTS conversion ********************************************/ + /* Return value = Yes iff no truncation occurred i.e. the whole string was copied */ + + #if 0 + extern OurBool STRUTIL_ProjChar_To_ANSI + ( + LPTSTR lptszANSI_Out, + unsigned int MaxSize, /* includes NULL-terminator; truncates after this */ + + ProjChar* pProjCh_In + ); + + extern OurBool STRUTIL_ANSI_To_ProjChar + ( + ProjChar* pProjCh_Out, + unsigned int MaxSize, /* includes NULL-terminator; truncates after this */ + + LPTSTR lptszANSI_In + ); + #endif + + /* Emulation of *******************************************/ + extern unsigned int STRUTIL_SC_Strlen + ( + const ProjChar* pProjCh_In + ); + + extern ProjChar* STRUTIL_SC_StrCpy + ( + ProjChar* pProjCh_Dst, + const ProjChar* pProjCh_Src + ); + + extern void STRUTIL_SC_FastCat + ( + ProjChar* pProjCh_Dst, + const ProjChar* pProjCh_Src_0, + const ProjChar* pProjCh_Src_1 + ); + /* This function assumes the destination area is large enough; + it copies Src0 followed by Src1 to the dest area. + */ + + extern OurBool STRUTIL_SC_Strequal + ( + const ProjChar* pProjCh_1, + const ProjChar* pProjCh_2 + ); + + extern OurBool STRUTIL_SC_Strequal_Insensitive + ( + const ProjChar* pProjCh_1, + const ProjChar* pProjCh_2 + ); + /* + these functions copy at most MaxSize chars from Src to Dst; this INCLUDES + space used by a NULL terminator (so that you can pass it an array + for the destination together with its size. The return value is + whether the entire string was copied. + */ + extern OurBool STRUTIL_SC_SafeCopy + ( + ProjChar* pProjCh_Dst, + unsigned int MaxSize, + + const ProjChar* pProjCh_Src + ); + + extern void STRUTIL_SC_SafeCat + ( + ProjChar* pProjCh_Dst, + unsigned int MaxSize, + + const ProjChar* pProjCh_Add + ); + + extern size_t STRUTIL_SC_NumBytes + ( + const ProjChar* pProjCh + ); + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/support/tallfont.cpp b/3dc/avp/support/tallfont.cpp new file mode 100644 index 0000000..11f6982 --- /dev/null +++ b/3dc/avp/support/tallfont.cpp @@ -0,0 +1,1709 @@ +/******************************************************************* + * + * DESCRIPTION: tallfont.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 18/3/98 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" + + #include "db.h" + #include "dxlog.h" + + #include "tallfont.hpp" + + #include "awTexLd.h" + #include "alt_tab.h" + + #include "ffstdio.h" + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + #define UseSoftwareAlphaRendering Yes + // an option which assumes you're in a 16-bit graphic mode... + + #if UseSoftwareAlphaRendering + #include "inline.h" + #endif + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + + extern unsigned char *ScreenBuffer; + extern long BackBufferPitch; + extern LPDIRECTDRAWSURFACE lpDDSBack; + extern DDPIXELFORMAT DisplayPixelFormat; + extern int CloudTable[128][128]; + extern int CloakingPhase; + + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +// class IndexedFont_Proportional_Column : public IndexedFont_Proportional +// public: +void +IndexedFont_Proportional_Column :: RenderChar_Clipped +( + struct r2pos& R2Pos_Cursor, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha, + ProjChar ProjCh +) const +{ + // Easy first attempt: pass on to unclipped routine, but only if no clipping + // required. Otherwise ignore... + if + ( + r2rect + ( + R2Pos_Cursor, + GetWidth(ProjCh), + GetHeight() + ) . bFitsIn( R2Rect_Clip ) + ) + { + RenderChar_Unclipped + ( + R2Pos_Cursor, + FixP_Alpha, + ProjCh + ); + } + else + { + R2Pos_Cursor . x += GetWidth(ProjCh); + } +} + +void +IndexedFont_Proportional_Column :: RenderChar_Unclipped +( + struct r2pos& R2Pos_Cursor, + int FixP_Alpha, + ProjChar ProjCh +) const +{ + #if 1 + unsigned int theOffset; + + if (ProjCh == ' ') + { + // Space is a special case: + R2Pos_Cursor . x += SpaceWidth(); + return; + } + + if + ( + GetOffset + ( + theOffset, + ProjCh + ) + ) + { + if + ( + GetWidth(ProjCh)>0 + ) + { + RECT destRect; + + destRect.left = R2Pos_Cursor . x; + destRect.top = R2Pos_Cursor . y; + + R2Pos_Cursor . x += GetWidth(ProjCh); + + destRect.right = R2Pos_Cursor . x++; + destRect.bottom = R2Pos_Cursor . y + GetHeight(); + + RECT tempnonConstRECTSoThatItCanWorkWithMicrosoft = WindowsRectForOffset[ theOffset ]; + + #if 0 + DDBLTFX tempDDBltFx; + + memset(&tempDDBltFx,0,sizeof(DDBLTFX)); + tempDDBltFx . dwSize = sizeof(DDBLTFX); + + tempDDBltFx . ddckSrcColorkey . dwColorSpaceLowValue = 0; + tempDDBltFx . ddckSrcColorkey . dwColorSpaceHighValue = 0; + #endif + + HRESULT ddrval = lpDDSBack->Blt + ( + &destRect, + image_ptr, + &tempnonConstRECTSoThatItCanWorkWithMicrosoft, + ( + DDBLT_WAIT + #if 1 + | DDBLT_KEYSRC + #else + | DDBLT_KEYSRCOVERRIDE + #endif + + #if 0 + | DDBLT_ALPHADEST + #endif + ), + NULL + // &tempDDBltFx // LPDDBLTFX lpDDBltFx + ); + + + #if 0 + // or even: + ddrval = lpDDSBack->BltFast(x, y, + lpDDDbgFont, &source, + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); + #endif + + #if 0 + if(ddrval != DD_OK) + { + ReleaseDirect3D(); + exit(0x666009); + } + #endif + } + } + #else + textprintXY + ( + R2Pos_Cursor . x, + R2Pos_Cursor . y, + "%c", + ProjCh + ); + #endif +} + +int +IndexedFont_Proportional_Column :: GetMaxWidth(void) const +{ + return R2Size_OverallImage . w; +} + +int +IndexedFont_Proportional_Column :: GetWidth +( + ProjChar ProjCh_In +) const +{ + unsigned int offsetTemp; + + if (ProjCh_In == ' ') + { + return SpaceWidth(); + } + + if + ( + GetOffset + ( + offsetTemp, + ProjCh_In + ) + ) + { + return WidthForOffset[ offsetTemp ]; + } + else + { + return 0; + } +} + +// static +IndexedFont_Proportional_Column* IndexedFont_Proportional_Column :: Create +( + FontIndex I_Font_New, + char* Filename, + int HeightPerChar_New, + int SpaceWidth_New, + int ASCIICodeForInitialCharacter +) +{ + IndexedFont_Proportional_Column* pFont = new IndexedFont_Proportional_Column + ( + I_Font_New, + Filename, + HeightPerChar_New, + SpaceWidth_New, + ASCIICodeForInitialCharacter + ); + + SCString :: UpdateAfterFontChange( I_Font_New ); + + return pFont; +} + + +IndexedFont_Proportional_Column :: ~IndexedFont_Proportional_Column() +{ + GLOBALASSERT(image_ptr); + ATRemoveSurface(image_ptr); + ReleaseDDSurface(image_ptr); + image_ptr = NULL; + + if (hBackup) + { + AwDestroyBackupTexture(hBackup); + } + + hBackup = NULL; +} + +IndexedFont_Proportional_Column :: IndexedFont_Proportional_Column +( + FontIndex I_Font_New, + char* Filename, + int HeightPerChar_New, + int SpaceWidth_New, + int ASCIICodeForInitialCharacter +) : IndexedFont_Proportional + ( + I_Font_New + ), + ASCIICodeForOffset0 + ( + ASCIICodeForInitialCharacter + ), + HeightPerChar_Val(HeightPerChar_New), + SpaceWidth_Val(SpaceWidth_New), + NumChars(0) +{ + { + unsigned nWidth,nHeight; + + //see if graphic can be found in fast file + unsigned int fastFileLength; + void const * pFastFileData = ffreadbuf(Filename,&fastFileLength); + + if(pFastFileData) + { + //load from fast file + image_ptr = AwCreateSurface + ( + "pxfXYB", + pFastFileData, + fastFileLength, + ( + #if 1 + 0 + #else + AW_TLF_TRANSP + #endif + #if 0 + | AW_TLF_CHROMAKEY + #endif + ), + &nWidth, + &nHeight, + &hBackup + ); + } + else + { + //load graphic from rim file + image_ptr = AwCreateSurface + ( + "sfXYB", + Filename, + ( + #if 1 + 0 + #else + AW_TLF_TRANSP + #endif + #if 0 + | AW_TLF_CHROMAKEY + #endif + ), + &nWidth, + &nHeight, + &hBackup + ); + } + R2Size_OverallImage . w = nWidth; + R2Size_OverallImage . h = nHeight; + } + + GLOBALASSERT(image_ptr); + GLOBALASSERT(hBackup); + + GLOBALASSERT(R2Size_OverallImage . w>0); + GLOBALASSERT(R2Size_OverallImage . h>0); + ATIncludeSurface(image_ptr,hBackup); + + DDCOLORKEY tempDDColorKey; + + tempDDColorKey . dwColorSpaceLowValue = 0; + tempDDColorKey . dwColorSpaceHighValue = 0; + + + HRESULT hrSetColorKey = image_ptr -> SetColorKey + ( + ( + DDCKEY_SRCBLT + ), // DWORD dwFlags, + &tempDDColorKey // LPDDCOLORKEY lpDDColorKey + ); + + if ( hrSetColorKey != DD_OK ) + { + LOGDXERR(hrSetColorKey); + } + +#if 0 + +typedef struct _DDCOLORKEY{ + DWORD dwColorSpaceLowValue; + DWORD dwColorSpaceHighValue; +} DDCOLORKEY,FAR* LPDDCOLORKEY; + + Parameters + + dwFlags + + Determines which color key is requested. + + DDCKEY_COLORSPACE + Set if the structure contains a color space. Not set if the structure contains a single color key. + DDCKEY_DESTBLT + Set if the structure specifies a color key or color space to be used as a destination color key for blit operations. + DDCKEY_DESTOVERLAY + Set if the structure specifies a color key or color space to be used as a destination color key for overlay operations. + DDCKEY_SRCBLT + Set if the structure specifies a color key or color space to be used as a source color key for blit operations. + DDCKEY_SRCOVERLAY + Set if the structure specifies a color key or color space to be used as a source color key for overlay operations. + lpDDColorKey + + Address of the DDCOLORKEY structure that contains the new color key values for the DirectDrawSurface object. +#endif + + + + + NumChars = (R2Size_OverallImage . h)/HeightPerChar_Val; + + GLOBALASSERT( NumChars < MAX_CHARS_IN_TALLFONT ); + + for (int i=0;i Lock + ( + NULL, // LPRECT lpDestRect, + &tempDDSurfaceDesc, // LPDDSURFACEDESC lpDDSurfaceDesc, + ( + DDLOCK_READONLY + | DDLOCK_SURFACEMEMORYPTR + #if 0 + | DDLOCK_WAIT + | DDLOCK_NOSYSLOCK + #endif + ), // DWORD dwFlags, + NULL // HANDLE hEvent + ); + + if ( hrLock != DD_OK ) + { + // ought really to throw an exception + + LOGDXERR(hrLock); + return; + } + + // Read the data... + { + for (int iOffset=0;iOffset0) + { + if + ( + bAnyNonTransparentPixelsInColumn + ( + r2pos(x,y), // r2pos R2Pos_TopOfColumn, + HeightPerChar_Val, // int HeightOfColumn + &tempDDSurfaceDesc // LPDDSURFACEDESC lpDDSurfaceDesc + ) + ) + { + break; + // and the current value of (x+1) is the width to use + } + + x--; + } + + SetWidth(iOffset,x+1); + } + } + + + HRESULT hrUnlock = image_ptr -> Unlock + ( + NULL // LPVOID lpSurfaceData + ); + + + if ( hrUnlock != DD_OK ) + { + // ought really to throw an exception + + LOGDXERR(hrUnlock); + return; + } + } +} + +// static +OurBool +IndexedFont_Proportional_Column :: bAnyNonTransparentPixelsInColumn +( + r2pos R2Pos_TopOfColumn, + int HeightOfColumn, + LPDDSURFACEDESC lpDDSurfaceDesc + // assumes you have a read lock +) +{ + GLOBALASSERT( lpDDSurfaceDesc ); + + void* pSurface = lpDDSurfaceDesc -> lpSurface; + + int BytesPerPixel = lpDDSurfaceDesc -> ddpfPixelFormat . dwRGBBitCount /8; + + int BytesPerRow = + ( + #if 0 + (BytesPerPixel * lpDDSurfaceDesc -> dwWidth) + + + #endif + lpDDSurfaceDesc -> lPitch + ); + + int y = R2Pos_TopOfColumn . y; + + #if 0 + db_logf1(("x=%i",R2Pos_TopOfColumn . x)); + #endif + + while ( y < R2Pos_TopOfColumn . y + HeightOfColumn ) + { + int Pixel = + ( + *(int*) + ( + ((char*)pSurface) + + + ( y * BytesPerRow ) + + + (R2Pos_TopOfColumn . x * BytesPerPixel) + ) + ); + + int R = Pixel & lpDDSurfaceDesc -> ddpfPixelFormat . dwRBitMask; + int G = Pixel & lpDDSurfaceDesc -> ddpfPixelFormat . dwGBitMask; + int B = Pixel & lpDDSurfaceDesc -> ddpfPixelFormat . dwBBitMask; + + #if 0 + db_logf1(("y=%i",y)); + db_logf1(("Pixel=0x%x",Pixel)); + db_logf1(("R=0x%x",R)); + db_logf1(("G=0x%x",G)); + db_logf1(("B=0x%x",B)); + #endif + + #if 1 + if (Pixel > 0 ) + { + return Yes; + } + #else + if + ( + (R > 32) + || + (G > 32) + || + (B > 32) + ) + { + // nasty hack to get it working... + return Yes; + } + #endif + + y++; + } + + return No; +} + + + + + + +///////////////////////////////////////////////////////////////// +// 3/4/98 DHM: A new implementation, supporting character kerning +///////////////////////////////////////////////////////////////// + +// class IndexedFont_Kerned_Column : public IndexedFont_Kerned +// public: +void +IndexedFont_Kerned_Column :: RenderChar_Clipped +( + struct r2pos& R2Pos_Cursor, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha, + ProjChar ProjCh +) const +{ + unsigned int theOffset; + + if (ProjCh == ' ') + { + // Space is a special case: + return; + } + + if + ( + GetOffset + ( + theOffset, + ProjCh + ) + ) + { + if + ( + GetWidth(ProjCh)>0 + ) + { + { + // This code adapted from DrawGraphicWithAlphaChannel(); + // it assumes you're in a 16-bit mode... + DDSURFACEDESC ddsdimage; + + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdimage.dwSize = sizeof(ddsdimage); + + /* lock the image */ + while (image_ptr->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + // okay, now we have the surfaces, we can copy from one to the other, + // darkening pixels as we go + { + long fontimagePitchInShorts = (ddsdimage.lPitch/2); + long backbufferPitchInShorts = (BackBufferPitch/2); + + unsigned short* fontimageRowStartPtr = + ( + ((unsigned short *)ddsdimage.lpSurface) + + + (GetHeight()*theOffset*fontimagePitchInShorts) + ); + + unsigned short* backbufferRowStartPtr = + ( + ((unsigned short *)ScreenBuffer) + + + (R2Pos_Cursor.y*backbufferPitchInShorts) + + + (R2Pos_Cursor.x) + ); + int screenY = R2Pos_Cursor.y; + + for (int yCount=GetHeight(); yCount>0; yCount--) + { + unsigned short* fontimagePtr = fontimageRowStartPtr; + unsigned short* backbufferPtr = backbufferRowStartPtr; + + if (screenY >= R2Rect_Clip.y0 && screenY <= R2Rect_Clip.y1) + for (int xCount=FullWidthForOffset[theOffset]; xCount>0;xCount--) + { + int r = CloudTable[(xCount+R2Pos_Cursor.x+CloakingPhase/64)&127][(screenY+CloakingPhase/128)&127]; +// b += CloudTable[((xCount+R2Pos_Cursor.x)/2-CloakingPhase/96)&127][((yCount+R2Pos_Cursor.y)/4+CloakingPhase/64)&127]/4; +// b += CloudTable[((xCount+R2Pos_Cursor.x+10)/4-CloakingPhase/64)&127][((yCount+R2Pos_Cursor.y-50)/8+CloakingPhase/32)&127]/8; +// if (b>ONE_FIXED) b = ONE_FIXED; + r = MUL_FIXED(FixP_Alpha,r); + if (*fontimagePtr) + { + unsigned int backR = (int)(*backbufferPtr) & DisplayPixelFormat.dwRBitMask; + unsigned int backG = (int)(*backbufferPtr) & DisplayPixelFormat.dwGBitMask; + unsigned int backB = (int)(*backbufferPtr) & DisplayPixelFormat.dwBBitMask; + + unsigned int fontR = (int)(*fontimagePtr) & DisplayPixelFormat.dwRBitMask; + unsigned int fontG = (int)(*fontimagePtr) & DisplayPixelFormat.dwGBitMask; + unsigned int fontB = (int)(*fontimagePtr) & DisplayPixelFormat.dwBBitMask; + + backR += MUL_FIXED(r,fontR); + if (backR>DisplayPixelFormat.dwRBitMask) backR = DisplayPixelFormat.dwRBitMask; + else backR &= DisplayPixelFormat.dwRBitMask; + + backG += MUL_FIXED(r,fontG); + if (backG>DisplayPixelFormat.dwGBitMask) backG = DisplayPixelFormat.dwGBitMask; + else backG &= DisplayPixelFormat.dwGBitMask; + + backB += MUL_FIXED(r,fontB); + if (backB>DisplayPixelFormat.dwBBitMask) backB = DisplayPixelFormat.dwBBitMask; + else backB &= DisplayPixelFormat.dwBBitMask; + + *backbufferPtr = (short)(backR|backG|backB); + } + fontimagePtr++; + backbufferPtr++; + } + screenY++; + fontimageRowStartPtr += fontimagePitchInShorts; + backbufferRowStartPtr += backbufferPitchInShorts; + } + } + + image_ptr->Unlock((LPVOID)ddsdimage.lpSurface); + } + } + } +} + +void +IndexedFont_Kerned_Column :: RenderChar_Unclipped +( + struct r2pos& R2Pos_Cursor, + int FixP_Alpha, + ProjChar ProjCh +) const +{ + unsigned int theOffset; + + if (ProjCh == ' ') + { + // Space is a special case: + return; + } + + if + ( + GetOffset + ( + theOffset, + ProjCh + ) + ) + { + if + ( + GetWidth(ProjCh)>0 + ) + { + { + // This code adapted from DrawGraphicWithAlphaChannel(); + // it assumes you're in a 16-bit mode... + DDSURFACEDESC ddsdback, ddsdimage; + + memset(&ddsdback, 0, sizeof(ddsdback)); + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdback.dwSize = sizeof(ddsdback); + ddsdimage.dwSize = sizeof(ddsdimage); + + /* lock the image */ + while (image_ptr->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + /* lock the backbuffer */ + while (lpDDSBack->Lock(NULL, &ddsdback, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + // okay, now we have the surfaces, we can copy from one to the other, + // darkening pixels as we go + { + long fontimagePitchInShorts = (ddsdimage.lPitch/2); + long backbufferPitchInShorts = (ddsdback.lPitch/2); + + unsigned short* fontimageRowStartPtr = + ( + ((unsigned short *)ddsdimage.lpSurface) + + + (GetHeight()*theOffset*fontimagePitchInShorts) + ); + + unsigned short* backbufferRowStartPtr = + ( + ((unsigned short *)ddsdback.lpSurface) + + + (R2Pos_Cursor.y*backbufferPitchInShorts) + + + (R2Pos_Cursor.x) + ); + + for (int yCount=GetHeight(); yCount>0; yCount--) + { + unsigned short* fontimagePtr = fontimageRowStartPtr; + unsigned short* backbufferPtr = backbufferRowStartPtr; + int yIndex = (yCount+R2Pos_Cursor.y+CloakingPhase/128)&127; + int xIndex = R2Pos_Cursor.x+CloakingPhase/64; + + for (int xCount=FullWidthForOffset[theOffset]; xCount>0;xCount--) + { + int r = CloudTable[(xCount+xIndex)&127][yIndex]; +// b += CloudTable[((xCount+R2Pos_Cursor.x)/2-CloakingPhase/96)&127][((yCount+R2Pos_Cursor.y)/4+CloakingPhase/64)&127]/4; +// b += CloudTable[((xCount+R2Pos_Cursor.x+10)/4-CloakingPhase/64)&127][((yCount+R2Pos_Cursor.y-50)/8+CloakingPhase/32)&127]/8; +// if (b>ONE_FIXED) b = ONE_FIXED; + r = MUL_FIXED(FixP_Alpha,r); + if (*fontimagePtr) + { + unsigned int backR = (int)(*backbufferPtr) & DisplayPixelFormat.dwRBitMask; + unsigned int backG = (int)(*backbufferPtr) & DisplayPixelFormat.dwGBitMask; + unsigned int backB = (int)(*backbufferPtr) & DisplayPixelFormat.dwBBitMask; + + unsigned int fontR = (int)(*fontimagePtr) & DisplayPixelFormat.dwRBitMask; + unsigned int fontG = (int)(*fontimagePtr) & DisplayPixelFormat.dwGBitMask; + unsigned int fontB = (int)(*fontimagePtr) & DisplayPixelFormat.dwBBitMask; + + backR += MUL_FIXED(r,fontR); + if (backR>DisplayPixelFormat.dwRBitMask) backR = DisplayPixelFormat.dwRBitMask; + else backR &= DisplayPixelFormat.dwRBitMask; + + backG += MUL_FIXED(r,fontG); + if (backG>DisplayPixelFormat.dwGBitMask) backG = DisplayPixelFormat.dwGBitMask; + else backG &= DisplayPixelFormat.dwGBitMask; + + backB += MUL_FIXED(r,fontB); + if (backB>DisplayPixelFormat.dwBBitMask) backB = DisplayPixelFormat.dwBBitMask; + else backB &= DisplayPixelFormat.dwBBitMask; + + *backbufferPtr = (short)(backR|backG|backB); + } + fontimagePtr++; + backbufferPtr++; + } + + fontimageRowStartPtr += fontimagePitchInShorts; + backbufferRowStartPtr += backbufferPitchInShorts; + } + } + + lpDDSBack->Unlock((LPVOID)ddsdback.lpSurface); + image_ptr->Unlock((LPVOID)ddsdimage.lpSurface); + } + } + } +} + +int +IndexedFont_Kerned_Column :: GetMaxWidth(void) const +{ + return R2Size_OverallImage . w; +} + +int +IndexedFont_Kerned_Column :: GetWidth +( + ProjChar ProjCh_In +) const +{ + unsigned int offsetTemp; + + if (ProjCh_In == ' ') + { + return SpaceWidth(); + } + + if + ( + GetOffset + ( + offsetTemp, + ProjCh_In + ) + ) + { + return FullWidthForOffset[ offsetTemp ]; + } + else + { + return 0; + } +} + +int +IndexedFont_Kerned_Column :: GetXInc +( + ProjChar currentProjCh, + ProjChar nextProjCh +) const +{ + GLOBALASSERT(currentProjCh!='\0'); + // LOCALISEME + + if (currentProjCh == ' ') + { + return SpaceWidth(); + } + + if (!((nextProjCh>='0' && nextProjCh<=']') || (nextProjCh>='a' && nextProjCh<='}'))) + { + return GetWidth(currentProjCh); + } + + unsigned int currentOffset; + + if + ( + GetOffset + ( + currentOffset, + currentProjCh + ) + ) + { + unsigned int nextOffset; + + if + ( + GetOffset + ( + nextOffset, + nextProjCh + ) + ) + { + return XIncForOffset[currentOffset][nextOffset]; + } + else + { + return FullWidthForOffset[currentOffset]; + } + } + else + { + return 0; + } + +} + + +// static +IndexedFont_Kerned_Column* IndexedFont_Kerned_Column :: Create +( + FontIndex I_Font_New, + char* Filename, + int HeightPerChar_New, + int SpaceWidth_New, + int ASCIICodeForInitialCharacter +) +{ + IndexedFont_Kerned_Column* pFont = new IndexedFont_Kerned_Column + ( + I_Font_New, + Filename, + HeightPerChar_New, + SpaceWidth_New, + ASCIICodeForInitialCharacter + ); + + SCString :: UpdateAfterFontChange( I_Font_New ); + + return pFont; +} + + +IndexedFont_Kerned_Column :: ~IndexedFont_Kerned_Column() +{ + GLOBALASSERT(image_ptr); + ATRemoveSurface(image_ptr); + ReleaseDDSurface(image_ptr); + image_ptr = NULL; + + if (hBackup) + { + AwDestroyBackupTexture(hBackup); + } + + hBackup = NULL; +} + +IndexedFont_Kerned_Column :: IndexedFont_Kerned_Column +( + FontIndex I_Font_New, + char* Filename, + int HeightPerChar_New, + int SpaceWidth_New, + int ASCIICodeForInitialCharacter +) : IndexedFont_Kerned + ( + I_Font_New + ), + ASCIICodeForOffset0 + ( + ASCIICodeForInitialCharacter + ), + HeightPerChar_Val(HeightPerChar_New), + SpaceWidth_Val(SpaceWidth_New), + NumChars(0) +{ + { + unsigned nWidth,nHeight; + + //see if graphic can be found in fast file + unsigned int fastFileLength; + void const * pFastFileData = ffreadbuf(Filename,&fastFileLength); + + if(pFastFileData) + { + //load from fast file + image_ptr = AwCreateSurface + ( + "pxfXYB", + pFastFileData, + fastFileLength, + ( + #if 1 + 0 + #else + AW_TLF_TRANSP + #endif + #if 0 + | AW_TLF_CHROMAKEY + #endif + ), + &nWidth, + &nHeight, + &hBackup + ); + } + else + { + //load graphic from rim file + image_ptr = AwCreateSurface + ( + "sfXYB", + Filename, + ( + #if 1 + 0 + #else + AW_TLF_TRANSP + #endif + #if 0 + | AW_TLF_CHROMAKEY + #endif + ), + &nWidth, + &nHeight, + &hBackup + ); + } + + R2Size_OverallImage . w = nWidth; + R2Size_OverallImage . h = nHeight; + } + + GLOBALASSERT(image_ptr); + GLOBALASSERT(hBackup); + + GLOBALASSERT(R2Size_OverallImage . w>0); + GLOBALASSERT(R2Size_OverallImage . h>0); + ATIncludeSurface(image_ptr,hBackup); + + DDCOLORKEY tempDDColorKey; + + tempDDColorKey . dwColorSpaceLowValue = 0; + tempDDColorKey . dwColorSpaceHighValue = 0; + + + HRESULT hrSetColorKey = image_ptr -> SetColorKey + ( + ( + DDCKEY_SRCBLT + ), // DWORD dwFlags, + &tempDDColorKey // LPDDCOLORKEY lpDDColorKey + ); + + if ( hrSetColorKey != DD_OK ) + { + LOGDXERR(hrSetColorKey); + } + +#if 0 + +typedef struct _DDCOLORKEY{ + DWORD dwColorSpaceLowValue; + DWORD dwColorSpaceHighValue; +} DDCOLORKEY,FAR* LPDDCOLORKEY; + + Parameters + + dwFlags + + Determines which color key is requested. + + DDCKEY_COLORSPACE + Set if the structure contains a color space. Not set if the structure contains a single color key. + DDCKEY_DESTBLT + Set if the structure specifies a color key or color space to be used as a destination color key for blit operations. + DDCKEY_DESTOVERLAY + Set if the structure specifies a color key or color space to be used as a destination color key for overlay operations. + DDCKEY_SRCBLT + Set if the structure specifies a color key or color space to be used as a source color key for blit operations. + DDCKEY_SRCOVERLAY + Set if the structure specifies a color key or color space to be used as a source color key for overlay operations. + lpDDColorKey + + Address of the DDCOLORKEY structure that contains the new color key values for the DirectDrawSurface object. +#endif + + + + + NumChars = (R2Size_OverallImage . h)/HeightPerChar_Val; + + GLOBALASSERT( NumChars < MAX_CHARS_IN_TALLFONT ); + + for (int i=0;i Lock + ( + NULL, // LPRECT lpDestRect, + &tempDDSurfaceDesc, // LPDDSURFACEDESC lpDDSurfaceDesc, + ( + DDLOCK_READONLY + | DDLOCK_SURFACEMEMORYPTR + #if 0 + | DDLOCK_WAIT + | DDLOCK_NOSYSLOCK + #endif + ), // DWORD dwFlags, + NULL // HANDLE hEvent + ); + + if ( hrLock != DD_OK ) + { + // ought really to throw an exception + + LOGDXERR(hrLock); + return; + } + + // Read the data... + { + for (int iOffset=0;iOffset0) + { + if + ( + bAnyNonTransparentPixelsInColumn + ( + r2pos(x,y), // r2pos R2Pos_TopOfColumn, + HeightPerChar_Val, // int HeightOfColumn + &tempDDSurfaceDesc // LPDDSURFACEDESC lpDDSurfaceDesc + ) + ) + { + break; + // and the current value of (x+1) is the width to use + } + + x--; + } + + SetWidth(iOffset,x+1); + } + } + + + HRESULT hrUnlock = image_ptr -> Unlock + ( + NULL // LPVOID lpSurfaceData + ); + + + if ( hrUnlock != DD_OK ) + { + // ought really to throw an exception + + LOGDXERR(hrUnlock); + return; + } + } +} + +void +IndexedFont_Kerned_Column :: UpdateXIncs(void) +{ + DDSURFACEDESC tempDDSurfaceDesc; + + tempDDSurfaceDesc . dwSize = sizeof(DDSURFACEDESC); + + HRESULT hrLock = image_ptr -> Lock + ( + NULL, // LPRECT lpDestRect, + &tempDDSurfaceDesc, // LPDDSURFACEDESC lpDDSurfaceDesc, + ( + DDLOCK_READONLY + | DDLOCK_SURFACEMEMORYPTR + #if 0 + | DDLOCK_WAIT + | DDLOCK_NOSYSLOCK + #endif + ), // DWORD dwFlags, + NULL // HANDLE hEvent + ); + + if ( hrLock != DD_OK ) + { + // ought really to throw an exception + LOGDXERR(hrLock); + + // fill table up with sensible values: + for (int i=0;i0) + { + if + ( + bOpaque + ( + &tempDDSurfaceDesc, + rightmostX, // int x, + Row + ) + ) + { + break; + } + else + { + rightmostX--; + } + } + + maxOpaqueX[Row]=rightmostX; + } + + // Find left-most pixel in row of second character + { + int leftmostX=0; + while(leftmostX Unlock + ( + NULL // LPVOID lpSurfaceData + ); + + + if ( hrUnlock != DD_OK ) + { + // ought really to throw an exception + LOGDXERR(hrUnlock); + + // fill table up with sensible values: + for (int i=0;i=0); + #if 0 + GLOBALASSERT(XInc<=GetMaxWidth()); + #endif + + XIncForOffset[i][j] =XInc; + } + } + } + + // Destroy the table of opaque extents: + { + delete[] maxOpaqueX; + delete[] minOpaqueX; + } + +} + + +// static +OurBool +IndexedFont_Kerned_Column :: bAnyNonTransparentPixelsInColumn +( + r2pos R2Pos_TopOfColumn, + int HeightOfColumn, + LPDDSURFACEDESC lpDDSurfaceDesc + // assumes you have a read lock +) +{ + GLOBALASSERT( lpDDSurfaceDesc ); + + void* pSurface = lpDDSurfaceDesc -> lpSurface; + + int BytesPerPixel = lpDDSurfaceDesc -> ddpfPixelFormat . dwRGBBitCount /8; + + int BytesPerRow = + ( + lpDDSurfaceDesc -> lPitch + ); + + int y = R2Pos_TopOfColumn . y; + + #if 0 + db_logf1(("x=%i",R2Pos_TopOfColumn . x)); + #endif + + while ( y < R2Pos_TopOfColumn . y + HeightOfColumn ) + { + int Pixel = + ( + *(int*) + ( + ((char*)pSurface) + + + ( y * BytesPerRow ) + + + (R2Pos_TopOfColumn . x * BytesPerPixel) + ) + ); + + int R = Pixel & lpDDSurfaceDesc -> ddpfPixelFormat . dwRBitMask; + int G = Pixel & lpDDSurfaceDesc -> ddpfPixelFormat . dwGBitMask; + int B = Pixel & lpDDSurfaceDesc -> ddpfPixelFormat . dwBBitMask; + + #if 0 + db_logf1(("y=%i",y)); + db_logf1(("Pixel=0x%x",Pixel)); + db_logf1(("R=0x%x",R)); + db_logf1(("G=0x%x",G)); + db_logf1(("B=0x%x",B)); + #endif + + #if 1 + if (Pixel > 0 ) + { + return Yes; + } + #else + if + ( + (R > 32) + || + (G > 32) + || + (B > 32) + ) + { + // nasty hack to get it working... + return Yes; + } + #endif + + y++; + } + + return No; +} + +int +IndexedFont_Kerned_Column :: CalcXInc +( + unsigned int currentOffset, + unsigned int nextOffset, + int* minOpaqueX, + int* maxOpaqueX +) +{ + GLOBALASSERT(currentOffset Biggest_MinXInc) + { + Biggest_MinXInc = MinXIncForRow; + } + } + + return Biggest_MinXInc; + } + #else + return FullWidthForOffset[currentOffset]; + #endif +} + +OurBool +IndexedFont_Kerned_Column :: OverlapOnRow +( + unsigned int currentOffset, + unsigned int nextOffset, + int Row, + int ProposedXInc +) +{ + GLOBALASSERT(currentOffset Lock + ( + NULL, // LPRECT lpDestRect, + &tempDDSurfaceDesc, // LPDDSURFACEDESC lpDDSurfaceDesc, + ( + DDLOCK_READONLY + | DDLOCK_SURFACEMEMORYPTR + #if 0 + | DDLOCK_WAIT + | DDLOCK_NOSYSLOCK + #endif + ), // DWORD dwFlags, + NULL // HANDLE hEvent + ); + + if ( hrLock != DD_OK ) + { + // ought really to throw an exception + + LOGDXERR(hrLock); + return Yes; + } + + // Find right-most pixel in row of first character + int rightmostX; + int firstoffsetY = Row+(currentOffset*GetHeight()); + for (rightmostX=GetMaxWidth()-1;rightmostX>0;rightmostX--) + { + if + ( + bOpaque + ( + &tempDDSurfaceDesc, // LPDDSURFACEDESC lpDDSurfaceDesc + rightmostX, // int x, + firstoffsetY // int y + ) + ) + { + break; + } + } + + // Find left-most pixel in row of second character + int leftmostX; + int nextoffsetY = Row+(nextOffset*GetHeight()); + for (leftmostX=0;leftmostX= + (leftmostX+ProposedXInc) + ); + } + } + #else + return Yes; + // for now + #endif +} + +int +IndexedFont_Kerned_Column :: GetSmallestXIncForRow +( + unsigned int currentOffset, + unsigned int nextOffset, + int* minOpaqueX, + int* maxOpaqueX, + unsigned int Row +) +{ + GLOBALASSERT( currentOffset < NumChars ); + GLOBALASSERT( nextOffset < NumChars ); + GLOBALASSERT( minOpaqueX ); + GLOBALASSERT( maxOpaqueX ); + GLOBALASSERT( Row < GetHeight() ); + + { + int Difference = + ( + maxOpaqueX[Row+(currentOffset*GetHeight())] - minOpaqueX[Row+(nextOffset*GetHeight())] + +1 + ); + + if (Difference>0) + { + return Difference; + } + else + { + return 0; + } + } +} + + +OurBool +IndexedFont_Kerned_Column :: bOpaque +( + LPDDSURFACEDESC lpDDSurfaceDesc, + // assumes you have a read lock + int x, + int y + // must be in range +) +{ + GLOBALASSERT(lpDDSurfaceDesc); + + void* pSurface = lpDDSurfaceDesc -> lpSurface; + + GLOBALASSERT(pSurface); + + int BytesPerPixel = lpDDSurfaceDesc -> ddpfPixelFormat . dwRGBBitCount /8; + + int BytesPerRow = + ( + lpDDSurfaceDesc -> lPitch + ); + + int Pixel = + ( + *(int*) + ( + ((char*)pSurface) + + + ( y * BytesPerRow ) + + + ( x * BytesPerPixel) + ) + ); + + return (Pixel != 0 ); +} + + + + + + + + + + + + + + + + + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/support/tallfont.hpp b/3dc/avp/support/tallfont.hpp new file mode 100644 index 0000000..d8008a8 --- /dev/null +++ b/3dc/avp/support/tallfont.hpp @@ -0,0 +1,344 @@ +/* + + tallfont.hpp + +*/ + +#ifndef _tallfont +#define _tallfont 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + + + #ifdef __cplusplus + #ifndef _indexfnt + #include "indexfnt.hpp" + #endif + #endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ +#ifdef __cplusplus + // A new way of handling proportionally-spaced fonts: artists prepare + // a tall thin bitmap containing all the characters, with a constant + // height. Loader needs to know this height, and extracts character + // widths using transparency information. + class IndexedFont_Proportional_Column : public IndexedFont_Proportional + { + enum { MAX_CHARS_IN_TALLFONT = 100 }; + + public: + void RenderChar_Clipped + ( + struct r2pos& R2Pos_Cursor, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha, + ProjChar ProjCh + ) const; + + void RenderChar_Unclipped + ( + struct r2pos& R2Pos_Cursor, + int FixP_Alpha, + ProjChar ProjCh + ) const; + + OurBool bCanRender( ProjChar ProjCh_In ) const + { + unsigned int offsetTemp; + return GetOffset + ( + offsetTemp, + ProjCh_In + ); + } + + int GetMaxWidth(void) const; + int GetWidth + ( + ProjChar ProjCh + ) const; + int GetHeight(void) const + { + return HeightPerChar_Val; + } + + static IndexedFont_Proportional_Column* Create + ( + FontIndex I_Font_New, + char* Filename, + int HeightPerChar_New, + int SpaceWidth_New, + int ASCIICodeForInitialCharacter + ); + + ~IndexedFont_Proportional_Column(); + + private: + IndexedFont_Proportional_Column + ( + FontIndex I_Font_New, + char* Filename, + int HeightPerChar_New, + int SpaceWidth_New, + int ASCIICodeForInitialCharacter + ); + + int HeightPerChar_Val; + int SpaceWidth_Val; + + LPDIRECTDRAWSURFACE image_ptr; + AW_BACKUPTEXTUREHANDLE hBackup; + + r2size R2Size_OverallImage; + + int ASCIICodeForOffset0; + int NumChars; + RECT WindowsRectForOffset[ MAX_CHARS_IN_TALLFONT ]; + // coordinates of characters in the image + int WidthForOffset[ MAX_CHARS_IN_TALLFONT ]; + + private: + int SpaceWidth(void) const + { + return SpaceWidth_Val; + } + + void UpdateWidths(void); + // called by constructor + void SetWidth(unsigned int Offset, int newWidth) + { + WindowsRectForOffset[ Offset ] . right = newWidth; + WidthForOffset[ Offset ] = newWidth; + } + + static OurBool bAnyNonTransparentPixelsInColumn + ( + r2pos R2Pos_TopOfColumn, + int HeightOfColumn, + LPDDSURFACEDESC lpDDSurfaceDesc + // assumes you have a read lock + ); + + OurBool GetOffset + ( + unsigned int& outputOffset, + ProjChar inProjCh + ) const + { + if (inProjCh < ASCIICodeForOffset0 ) + { + return No; + } + + outputOffset = (inProjCh - ASCIICodeForOffset0); + + if (outputOffset >= NumChars) + { + return No; + } + + return Yes; + + } + }; + + // 3/4/98 DHM: A new implementation, supporting character kerning + class IndexedFont_Kerned_Column : public IndexedFont_Kerned + { + enum { MAX_CHARS_IN_TALLFONT = 255 }; + // note that we define an array of ints sized this squared + // so for 100, this works out as 100*100*4bytes + // which is 40,000 bytes, or about 39k + + public: + void RenderChar_Clipped + ( + struct r2pos& R2Pos_Cursor, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha, + ProjChar ProjCh + ) const; + + void RenderChar_Unclipped + ( + struct r2pos& R2Pos_Cursor, + int FixP_Alpha, + ProjChar ProjCh + ) const; + + OurBool bCanRender( ProjChar ProjCh_In ) const + { + unsigned int offsetTemp; + return GetOffset + ( + offsetTemp, + ProjCh_In + ); + } + + int GetMaxWidth(void) const; + int GetWidth + ( + ProjChar ProjCh + ) const; + int GetHeight(void) const + { + return HeightPerChar_Val; + } + + int GetXInc + ( + ProjChar currentProjCh, + ProjChar nextProjCh + ) const; + + static IndexedFont_Kerned_Column* Create + ( + FontIndex I_Font_New, + char* Filename, + int HeightPerChar_New, + int SpaceWidth_New, + int ASCIICodeForInitialCharacter + ); + + ~IndexedFont_Kerned_Column(); + + int FullWidthForOffset[ MAX_CHARS_IN_TALLFONT ]; + + LPDIRECTDRAWSURFACE GetImagePtr(void) const + { + return (LPDIRECTDRAWSURFACE) image_ptr; + } + LPDIRECTDRAWSURFACE image_ptr; + private: + IndexedFont_Kerned_Column + ( + FontIndex I_Font_New, + char* Filename, + int HeightPerChar_New, + int SpaceWidth_New, + int ASCIICodeForInitialCharacter + ); + + int HeightPerChar_Val; + int SpaceWidth_Val; + + AW_BACKUPTEXTUREHANDLE hBackup; + + r2size R2Size_OverallImage; + + int ASCIICodeForOffset0; + int NumChars; + RECT WindowsRectForOffset[ MAX_CHARS_IN_TALLFONT ]; + // coordinates of characters in the image + int XIncForOffset[ MAX_CHARS_IN_TALLFONT ][ MAX_CHARS_IN_TALLFONT ]; + + private: + int SpaceWidth(void) const + { + return SpaceWidth_Val; + } + + void UpdateWidths(void); + void UpdateXIncs(void); + // called by constructor + + void SetWidth(unsigned int Offset, int newWidth) + { + WindowsRectForOffset[ Offset ] . right = newWidth; + FullWidthForOffset[ Offset ] = newWidth; + } + + static OurBool bAnyNonTransparentPixelsInColumn + ( + r2pos R2Pos_TopOfColumn, + int HeightOfColumn, + LPDDSURFACEDESC lpDDSurfaceDesc + // assumes you have a read lock + ); + + OurBool GetOffset + ( + unsigned int& outputOffset, + ProjChar inProjCh + ) const + { + if (inProjCh < ASCIICodeForOffset0 ) + { + return No; + } + + outputOffset = (inProjCh - ASCIICodeForOffset0); + + if (outputOffset >= NumChars) + { + return No; + } + + return Yes; + + } + + int CalcXInc + ( + unsigned int currentOffset, + unsigned int nextOffset, + int* minOpaqueX, + int* maxOpaqueX + ); + + OurBool OverlapOnRow + ( + unsigned int currentOffset, + unsigned int nextOffset, + int Row, + int ProposedXInc + ); + + int GetSmallestXIncForRow + ( + unsigned int currentOffset, + unsigned int nextOffset, + int* minOpaqueX, + int* maxOpaqueX, + unsigned int Row + ); + + OurBool bOpaque + ( + LPDDSURFACEDESC lpDDSurfaceDesc, + // assumes you have a read lock + int x, + int y + // must be in range + ); + + }; + +#endif + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/support/trig666.cpp b/3dc/avp/support/trig666.cpp new file mode 100644 index 0000000..30d0372 --- /dev/null +++ b/3dc/avp/support/trig666.cpp @@ -0,0 +1,182 @@ +/******************************************************************* + * + * DESCRIPTION: trig666.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 18/11/97 from Headhunter's TRIGGERS.CPP; had to + * rename to avoid conflict with AVP file TRIGGERS.H + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "trig666.hpp" + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +// class TriggerDaemon : public Daemon +TriggerDaemon :: TriggerDaemon +( + OurBool fActive +) : Daemon + ( + fActive + ) +{ +} + +TriggerDaemon :: ~TriggerDaemon() +{ +} + +// A daemon which fires at regular intervals (potentially more than once per frame) +// class PulsingTriggerDaemon : public TriggerDaemon +PulsingTriggerDaemon :: PulsingTriggerDaemon +( + OurBool fActive, + int FixP_Period // interval between triggers in seconds +) : TriggerDaemon + ( + fActive + ) +{ + GLOBALASSERT( FixP_Period > 0); + + FixP_Period_Val = FixP_Period; + FixP_TimeToNextPulse = FixP_Period; +} + +PulsingTriggerDaemon :: ~PulsingTriggerDaemon() +{ +} + +ACTIVITY_RETURN_TYPE PulsingTriggerDaemon :: Activity(ACTIVITY_INPUT) +{ + while ( FixP_Time > 0 ) + { + if ( FixP_Time >= FixP_TimeToNextPulse ) + { + // then elapse some of the available time to take you to the pulse + FixP_Time -= FixP_TimeToNextPulse; + FixP_TimeToNextPulse = FixP_Period_Val; + + // and trigger: + Triggered(); + } + else + { + // Not enough time to warrant triggering; reduce time + // to next pulse and stop. + FixP_TimeToNextPulse -= FixP_Time; + ACTIVITY_RVAL_NOCHANGE + } + } + + ACTIVITY_RVAL_NOCHANGE +} + +void PulsingTriggerDaemon :: SetFuse_FixP +( + int FixP_Fuse // time until it next triggers; doesn't change the period +) +{ + GLOBALASSERT( FixP_Fuse > 0 ); + FixP_TimeToNextPulse = FixP_Fuse; +} + +// A countdown daemon which DESTROYS ITSELF after it triggers +// class CountdownDaemon : public TriggerDaemon +CountdownDaemon :: CountdownDaemon +( + OurBool fActive, + int FixP_Fuse // time until it triggers +) : TriggerDaemon + ( + fActive + ) +{ + GLOBALASSERT( FixP_Fuse > 0 ); + + FixP_TimeRemaining = FixP_Fuse; +} + +CountdownDaemon :: ~CountdownDaemon() +{ +} + +ACTIVITY_RETURN_TYPE CountdownDaemon :: Activity(ACTIVITY_INPUT) +{ + #if 0 + textprint + ( + "CountdownDaemon :: Activity(%i) with fuse %i\n", + FixP_Time, + FixP_TimeRemaining + ); + #endif + + if ( FixP_TimeRemaining > FixP_Time ) + { + // Keep counting down: + FixP_TimeRemaining -= FixP_Time; + } + else + { + // Countdown has elapsed: + Triggered(); + delete this; + } + + ACTIVITY_RVAL_NOCHANGE +} + +void CountdownDaemon :: SetFuse_FixP +( + int FixP_Fuse // time until it triggers +) +{ + FixP_TimeRemaining = FixP_Fuse; +} + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/support/trig666.hpp b/3dc/avp/support/trig666.hpp new file mode 100644 index 0000000..f965943 --- /dev/null +++ b/3dc/avp/support/trig666.hpp @@ -0,0 +1,103 @@ +/* + + trig666.hpp + +*/ + +#ifndef _trig666 +#define _trig666 1 + + #ifndef _daemon + #include "daemon.h" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + class TriggerDaemon : public Daemon + { + public: + TriggerDaemon + ( + OurBool fActive + ); + ~TriggerDaemon(); + virtual void Triggered(void) = 0; + // called by the daemon's activity whenever the daemon decides to + // trigger it. + private: + + }; + + // A daemon which fires at regular intervals (potentially more than once per frame) + class PulsingTriggerDaemon : public TriggerDaemon + { + public: + PulsingTriggerDaemon + ( + OurBool fActive, + int FixP_Period // interval between triggers in seconds + ); + + ~PulsingTriggerDaemon(); + + ACTIVITY_RETURN_TYPE Activity(ACTIVITY_INPUT); + // never causes callback hooks to fire + + void SetFuse_FixP + ( + int FixP_Fuse // time until it next triggers; doesn't change the period + ); + + // void Triggered(void) remains pure virtual + private: + int FixP_Period_Val; + int FixP_TimeToNextPulse; + }; + + // A countdown daemon which DESTROYS ITSELF after it triggers + class CountdownDaemon : public TriggerDaemon + { + public: + CountdownDaemon + ( + OurBool fActive, + int FixP_Fuse // time until it triggers + ); + + ~CountdownDaemon(); + + ACTIVITY_RETURN_TYPE Activity(ACTIVITY_INPUT); + // never causes callback hooks to fire + + void SetFuse_FixP + ( + int FixP_Fuse // time until it triggers + ); + + // void Triggered(void) remains pure virtual + private: + int FixP_TimeRemaining; + }; + + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/support/vssver.scc b/3dc/avp/support/vssver.scc new file mode 100644 index 0000000..56e2581 Binary files /dev/null and b/3dc/avp/support/vssver.scc differ diff --git a/3dc/avp/support/wrapstr.cpp b/3dc/avp/support/wrapstr.cpp new file mode 100644 index 0000000..2676c90 --- /dev/null +++ b/3dc/avp/support/wrapstr.cpp @@ -0,0 +1,372 @@ +/******************************************************************* + * + * DESCRIPTION: wrapstr.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 6/8/98 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "wrapstr.hpp" +#include "strutil.h" + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +// namespace WordWrap +List* WordWrap :: DeprecatedMake +( + const SCString& SCString_In, + + const IndexedFont& IndexedFnt_In, + + int W_FirstLine_In, + int W_Subsequently_In + // widths to wrap with. + // They are different in order to support paragraph starts of various kinds + // e.g. bulleting +) +{ + GLOBALASSERT( W_FirstLine_In >= 0 ); + GLOBALASSERT( W_Subsequently_In >= 0 ); + + // The list to return is initially empty: + List* pList_pSCString_Return = new List; + + #if 1 + { + // Iterate through the string: + ProjChar* pProjCh_I = SCString_In . pProjCh(); + + ProjChar* pProjCh_StartOfLine = pProjCh_I; + int CharsInLine = 0; + + ProjChar* pProjCh_StartOfNextLine = 0; + int CharsInLine_Good = 0; + // update this whenever you have a "good" wrap position i.e. + // one where there's whitespace + + int W_Available = W_FirstLine_In; + + while + ( + !STRUTIL_SC_fIsTerminator + ( + pProjCh_I + ) + ) + { + // Determine if adding this character to the line being + // formed will make the line too long to fit: + if + ( + IndexedFnt_In . CalcSize + ( + pProjCh_StartOfLine, + ( CharsInLine + 1 ) + ) . w + > + W_Available + ) + { + // It won't fit: + if ( CharsInLine_Good > 0 ) + { + GLOBALASSERT( pProjCh_StartOfNextLine ); + + // If so, flush the current line by creating a new SCString + // for it and start a new line with this as the first character + pList_pSCString_Return -> add_entry_end + ( + new SCString + ( + pProjCh_StartOfLine, + CharsInLine_Good + ) + ); + + pProjCh_StartOfLine = pProjCh_StartOfNextLine; + CharsInLine = (CharsInLine - CharsInLine_Good ); + CharsInLine_Good = 0; + // Note that we don't advance pProjCh_I, but the variant does + // decrease since pProjCh_StartOfLine will advance, reducing the number + // of characters left to add. + + W_Available = W_Subsequently_In; + + continue; + } + else + { + // Emergency: what we have won't fit even by itself in the given + // width. Continue processing until you reach a "good" breaking point: + } + } + + // Otherwise, add this character to the line being formed: + { + if + ( + bWhitespace( *pProjCh_I ) + ) + { + // Whitespace character: + if + ( + (CharsInLine == 0) + ) + { + // Ignore leading whitespace in a line: + pProjCh_StartOfLine++; + pProjCh_I++; + } + else + { + // Add this character to the line being generated; it is an acceptable + // breaking point: + pProjCh_I++; + CharsInLine++; + + CharsInLine_Good = CharsInLine; + pProjCh_StartOfNextLine = pProjCh_I; + } + } + else if (*pProjCh_I=='\n') + { + pProjCh_I++; + CharsInLine++; + + CharsInLine_Good = CharsInLine; + pProjCh_StartOfNextLine = pProjCh_I; + + pList_pSCString_Return -> add_entry_end + ( + new SCString + ( + pProjCh_StartOfLine, + CharsInLine_Good + ) + ); + + pProjCh_StartOfLine = pProjCh_StartOfNextLine; + CharsInLine = (CharsInLine - CharsInLine_Good ); + CharsInLine_Good = 0; + W_Available = W_Subsequently_In; + + + } + else + { + // Non-whitespace character: + + // Add this character to the line being generated; it is not an acceptable + // breaking point: + CharsInLine++; + pProjCh_I++; + } + } + } + + // Flush the final line that was formed: + pList_pSCString_Return -> add_entry_end + ( + new SCString + ( + pProjCh_StartOfLine, + CharsInLine + ) + ); + + + } + #else + { + // Iterate through the string: + ProjChar* pProjCh_I = SCString_In . pProjCh(); + ProjChar* pProjCh_StartOfLine = pProjCh_I; + + int CharsInLine = 0; + + int W_Available = W_FirstLine_In; + + while + ( + !STRUTIL_SC_fIsTerminator + ( + pProjCh_I + ) + ) + { + // Determine if adding this character to the line being + // formed will make the line too long to fit: + if + ( + IndexedFnt_In . CalcSize + ( + pProjCh_StartOfLine, + ( CharsInLine + 1 ) + ) . w + > + W_Available + ) + { + // It won't fit: + if ( CharsInLine > 0 ) + { + // If so, flush the current line by creating a new SCString + // for it and start a new line with this as the first character + pList_pSCString_Return -> add_entry_end + ( + new SCString + ( + pProjCh_StartOfLine, + CharsInLine + ) + ); + + pProjCh_StartOfLine = pProjCh_I; + CharsInLine = 0; + // Note that we don't advance pProjCh_I, but the variant does + // decrease since pProjCh_StartOfLine will advance, reducing the number + // of characters left to add. + + W_Available = W_Subsequently_In; + } + else + { + // Emergency: the character we have won't fit even by itself in the given + // width. Make a line containing just this character (to avoid infinite loops): + pList_pSCString_Return -> add_entry_end + ( + new SCString + ( + pProjCh_StartOfLine, + 1 + ) + ); + + pProjCh_I++; + + pProjCh_StartOfLine = pProjCh_I; + CharsInLine = 0; + + W_Available = W_Subsequently_In; + } + } + else + { + // Otherwise, add this character to the line being formed: + if + ( + (CharsInLine == 0) + && + bWhitespace( *pProjCh_I ) + ) + { + // Ignore leading whitespace in a line: + pProjCh_StartOfLine++; + } + else + { + // Add this character to the line being generated: + CharsInLine ++; + } + + pProjCh_I++; + + } + } + + // Flush the final line that was formed: + pList_pSCString_Return -> add_entry_end + ( + new SCString + ( + pProjCh_StartOfLine, + CharsInLine + ) + ); + + + } + #endif + + return pList_pSCString_Return; +} + +int WordWrap :: bWhitespace( ProjChar ProjCh ) +{ + // LOCALISEME(); + return ( ProjCh == ' '); +} + +int WordWrap :: bWithinWord( ProjChar* pProjCh_Test ) +{ + GLOBALASSERT( pProjCh_Test ); + + if ( bWhitespace(*pProjCh_Test) ) + { + return No; + } + + GLOBALASSERT + ( + !STRUTIL_SC_fIsTerminator + ( + pProjCh_Test + ) + ); + + return + ( + !bWhitespace( *(pProjCh_Test++) ) + ); + // i.e you're within a word iff + // neither you nor the next char are whitespace +} + + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/support/wrapstr.hpp b/3dc/avp/support/wrapstr.hpp new file mode 100644 index 0000000..4070149 --- /dev/null +++ b/3dc/avp/support/wrapstr.hpp @@ -0,0 +1,99 @@ +/* + + wrapstr.hpp + + Support for word-wrapping strings: the heart of it takes a string, + a font, and a width, and creates a list of strings objects guaranteed + to have width less than or equal to the specified width when displayed with + the specified font. + + This guarantee is not absolute; it can fail to be upheld if there's a word + in the string that's wider than the width you give it (and thus can't fit + without being broken) + + There is no support for mixing fonts. + + There is no support for carriage returns, tabs, etc. + +*/ + +#ifndef _wrapstr_hpp +#define _wrapstr_hpp 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + + #ifndef _scstring + #include "scstring.hpp" + #endif + + #ifndef _indexfnt + #include "indexfnt.hpp" + #endif + + #ifndef _reflist_hpp + #include "reflist.hpp" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + namespace WordWrap + { + /* Deprecated version; to be phased out once we have interators for RefLists + since you have to manually release references as you destroy all/parts of the list + */ + extern List* DeprecatedMake + ( + const SCString& SCString_In, + + const IndexedFont& IndexedFnt_In, + + int W_FirstLine_In, + int W_Subsequently_In + // widths to wrap with. + // They are different in order to support paragraph starts of various kinds + // e.g. bulleting + ); + + extern RefList* Make + ( + const SCString& SCString_In, + + const IndexedFont& IndexedFnt_In, + + int W_FirstLine_In, + int W_Subsequently_In + // widths to wrap with. + // They are different in order to support paragraph starts of various kinds + // e.g. bulleting + ); + + int bWhitespace( ProjChar ProjCh ); + + int bWithinWord( ProjChar* pProjCh_Test ); + + }; + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/targeting.c b/3dc/avp/targeting.c new file mode 100644 index 0000000..b01098c --- /dev/null +++ b/3dc/avp/targeting.c @@ -0,0 +1,1097 @@ +/* KJL 14:30:27 06/05/98 - weapon targeting code */ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "gameplat.h" + +#include "bh_types.h" +#include "inventry.h" +#include "comp_shp.h" +#include "load_shp.h" +#include "huddefs.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +#include "dynblock.h" +#include "dynamics.h" +#include "lighting.h" +#include "pvisible.h" +#include "bh_alien.h" +#include "bh_pred.h" +#include "bh_xeno.h" +#include "bh_paq.h" +#include "bh_queen.h" +#include "bh_fhug.h" +#include "bh_marin.h" +#include "bh_debri.h" +#include "bh_weap.h" +#include "bh_agun.h" +#include "weapons.h" +#include "avpview.h" + +#include "psnd.h" +#include "vision.h" +#include "plat_shp.h" + +#include "particle.h" +#include "psndproj.h" +#include "showcmds.h" +#include "los.h" +#include + + +#include "paintball.h" +/* for win 95 net support */ +#if SupportWindows95 +#include "pldghost.h" +#include "pldnet.h" +#endif + +/*KJL**************************************************************************************** +* G L O B A L S * +****************************************************************************************KJL*/ + +void SmartTarget_GetCofM(DISPLAYBLOCK *target,VECTORCH *viewSpaceOutput); +void GetTargetingPointOfObject(DISPLAYBLOCK *objectPtr, VECTORCH *targetPtr); + +extern int NumOnScreenBlocks; +extern DISPLAYBLOCK *OnScreenBlockList[]; +extern struct Target PlayersTarget; +extern VECTORCH GunMuzzleDirectionInVS; +extern VECTORCH GunMuzzleDirectionInWS; +extern int NormalFrameTime; +extern int Weapon_ThisBurst; + +/* stuff to do with where a gun is pointing */ +extern int GunMuzzleSightX, GunMuzzleSightY; +/* In 16.16 for smoothness. On-screen coords indicating to where the gun's muzzle is pointing */ + +int SmartTargetSightX, SmartTargetSightY; +char CurrentlySmartTargetingObject; +DISPLAYBLOCK *SmartTarget_Object; +DISPLAYBLOCK *Old_SmartTarget_Object; + +void CalculateWhereGunIsPointing(TEMPLATE_WEAPON_DATA *twPtr, PLAYER_WEAPON_DATA *weaponPtr); +void CalculatePlayersTarget(TEMPLATE_WEAPON_DATA *twPtr, PLAYER_WEAPON_DATA *weaponPtr); +DISPLAYBLOCK *SmartTarget_GetNewTarget(void); +int SmartTarget_TargetFilter(STRATEGYBLOCK *candidate); + +void CalculateWhereGunIsPointing(TEMPLATE_WEAPON_DATA *twPtr, PLAYER_WEAPON_DATA *weaponPtr) +{ + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + MATRIXCH matrix = VDBPtr->VDB_Mat; + + TransposeMatrixCH(&matrix); + +// textprint("Calculating where gun is pointing...\n"); + + /* unnormalised vector in the direction which the gun's muzzle is pointing, IN VIEW SPACE */ + /* very useful when considering sprites, which lie in a Z-plane in view space */ + GunMuzzleDirectionInVS.vz = 65536; + GunMuzzleDirectionInVS.vx = + (GunMuzzleSightX-(ScreenDescriptorBlock.SDB_Width<<15))/(VDBPtr->VDB_ProjX); + GunMuzzleDirectionInVS.vy = + (((GunMuzzleSightY-(ScreenDescriptorBlock.SDB_Height<<15))/(VDBPtr->VDB_ProjY))*3)/4; + + /* Now fudge for gun judder! */ + if ((twPtr->UseStateMovement==0)||(weaponPtr->WeaponIDNumber == WEAPON_MINIGUN)) { + if ((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY) + ||( (weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY)&&(weaponPtr->WeaponIDNumber == WEAPON_TWO_PISTOLS) )){ + if ((twPtr->PrimaryIsRapidFire)||(weaponPtr->WeaponIDNumber == WEAPON_TWO_PISTOLS)) { + + EULER judder; + MATRIXCH juddermat; + + if (twPtr->RecoilMaxRandomZ>0) { + weaponPtr->PositionOffset.vz = (FastRandom()%twPtr->RecoilMaxRandomZ) - twPtr->RecoilMaxZ; + } + + if ((Weapon_ThisBurst>0)||(weaponPtr->WeaponIDNumber == WEAPON_TWO_PISTOLS)) { + + /* jiggle the weapon around when you shoot */ + int speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity); + /* speed should be between ~0 and ~27000 (jumping alien). ~15000 is a moving marine. */ + + if (twPtr->RecoilMaxXTilt>0) { + judder.EulerX=(FastRandom()%twPtr->RecoilMaxXTilt)-twPtr->RecoilMaxXTilt/2; + } else { + judder.EulerX=0; + } + if (twPtr->RecoilMaxYTilt>0) { + judder.EulerY=(FastRandom()%twPtr->RecoilMaxYTilt)-twPtr->RecoilMaxYTilt/2; + } else { + judder.EulerY=0; + } + judder.EulerZ=0; + + judder.EulerX=MUL_FIXED(judder.EulerX,(ONE_FIXED+(speed<<2))); + judder.EulerY=MUL_FIXED(judder.EulerY,(ONE_FIXED+(speed<<2))); + + judder.EulerX&=wrap360; + judder.EulerY&=wrap360; + + CreateEulerMatrix(&judder,&juddermat); + RotateVector(&GunMuzzleDirectionInVS,&juddermat); + } + } + } else { + /* Recentre Z offset. */ + int linearCenteringSpeed = MUL_FIXED(300,NormalFrameTime); + + if (weaponPtr->PositionOffset.vz > 0 ) + { + weaponPtr->PositionOffset.vz -= linearCenteringSpeed; + if (weaponPtr->PositionOffset.vz < 0) weaponPtr->PositionOffset.vz = 0; + } + else if (weaponPtr->PositionOffset.vz < 0 ) + { + weaponPtr->PositionOffset.vz += linearCenteringSpeed; + if (weaponPtr->PositionOffset.vz > 0) weaponPtr->PositionOffset.vz = 0; + } + + } + } + + GunMuzzleDirectionInWS = GunMuzzleDirectionInVS; + /* rotate vector into world space and then normalise */ + RotateVector(&GunMuzzleDirectionInWS,&matrix); + Normalise(&GunMuzzleDirectionInWS); + +} + +void CalculatePlayersTarget(TEMPLATE_WEAPON_DATA *twPtr, PLAYER_WEAPON_DATA *weaponPtr) +{ + + CalculateWhereGunIsPointing(twPtr,weaponPtr); + + FindPolygonInLineOfSight(&GunMuzzleDirectionInWS, &Global_VDB_Ptr->VDB_World, 1,Player); + + PlayersTarget.DispPtr = LOS_ObjectHitPtr; + PlayersTarget.Distance = LOS_Lambda; + PlayersTarget.HModelSection = LOS_HModel_Section; + + if (PaintBallMode.IsOn) + { + PaintBallMode.TargetDispPtr = LOS_ObjectHitPtr; + PaintBallMode.TargetPosition = LOS_Point; + PaintBallMode.TargetNormal = LOS_ObjectNormal; + } + + //textprint("Exiting CPT - PT.DP is %x, PT.HMS is %x\n",PlayersTarget.DispPtr,PlayersTarget.HModelSection); + + if (PlayersTarget.DispPtr) { + if (PlayersTarget.HModelSection) { + if (PlayersTarget.HModelSection->my_controller!=PlayersTarget.DispPtr->HModelControlBlock) { + PlayersTarget.HModelSection=NULL; + } + } + } + + /* did we hit anything? */ + if (PlayersTarget.DispPtr) + { + PlayersTarget.Position = LOS_Point; + } + else + { + /* pretend the target is right in front of the player, but a very long way off */ + PlayersTarget.Position.vx = Global_VDB_Ptr->VDB_World.vx + (Global_VDB_Ptr->VDB_Mat.mat13<<7); + PlayersTarget.Position.vy = Global_VDB_Ptr->VDB_World.vy + (Global_VDB_Ptr->VDB_Mat.mat23<<7); + PlayersTarget.Position.vz = Global_VDB_Ptr->VDB_World.vz + (Global_VDB_Ptr->VDB_Mat.mat33<<7); + PlayersTarget.HModelSection = NULL; + } + if (ShowDebuggingText.Target) + { + PrintDebuggingText("Target Position: %d %d %d\n",PlayersTarget.Position.vx,PlayersTarget.Position.vy,PlayersTarget.Position.vz); + } + + if (PlayersTarget.HModelSection) { + GLOBALASSERT(PlayersTarget.DispPtr->HModelControlBlock==PlayersTarget.HModelSection->my_controller); + } + + if(AvP.Network!=I_No_Network) + { + AddNetMsg_PredatorLaserSights(&PlayersTarget.Position,&LOS_ObjectNormal,PlayersTarget.DispPtr); + } + + + /* find position/orientation of predator's targeting sights */ + if ( (AvP.PlayerType == I_Predator) + &&((weaponPtr->WeaponIDNumber == WEAPON_PRED_RIFLE) + ||(weaponPtr->WeaponIDNumber == WEAPON_PRED_SHOULDERCANNON)) ) + { + int i=2; + + VECTORCH offset[3] = + { + {0,-50,0}, + {43,25,0}, + {-43,25,0}, + }; + + MATRIXCH matrix = Global_VDB_Ptr->VDB_Mat; + TransposeMatrixCH(&matrix); + + do + { + VECTORCH position = offset[i]; + + RotateVector(&position,&matrix); + position.vx += Global_VDB_Ptr->VDB_World.vx; + position.vy += Global_VDB_Ptr->VDB_World.vy; + position.vz += Global_VDB_Ptr->VDB_World.vz; + FindPolygonInLineOfSight(&GunMuzzleDirectionInWS, &position, 1,Player); + PredatorLaserTarget.Normal[i] = LOS_ObjectNormal; + + if (PlayersTarget.DispPtr) + { + PredatorLaserTarget.Position[i] = LOS_Point; + } + else + { + /* pretend the target is right in front of the player, but a very long way off */ + PredatorLaserTarget.Position[i].vx = Global_VDB_Ptr->VDB_World.vx + (Global_VDB_Ptr->VDB_Mat.mat13<<7); + PredatorLaserTarget.Position[i].vy = Global_VDB_Ptr->VDB_World.vy + (Global_VDB_Ptr->VDB_Mat.mat23<<7); + PredatorLaserTarget.Position[i].vz = Global_VDB_Ptr->VDB_World.vz + (Global_VDB_Ptr->VDB_Mat.mat33<<7); + } + + } + while(i--); + PredatorLaserTarget.ShouldBeDrawn=1; + } + else + { + PredatorLaserTarget.ShouldBeDrawn=0; + } + + +} + +BOOL CalculateFiringSolution(VECTORCH* firing_pos,VECTORCH* target_pos,VECTORCH* target_vel,int projectile_speed,VECTORCH* solution) +{ + VECTORCH normal; //normal from firer to target + VECTORCH rotated_vel; + VECTORCH rotated_solution; + MATRIXCH mat; + + int distance_to_target; + + GLOBALASSERT(firing_pos); + GLOBALASSERT(target_pos); + GLOBALASSERT(target_vel); + GLOBALASSERT(projectile_speed); + GLOBALASSERT(solution); + + //get a normalised vector from start to destination + normal=*target_pos; + SubVector(firing_pos,&normal); + + if(!normal.vx && !normal.vy && !normal.vz) + return FALSE; + + distance_to_target=Approximate3dMagnitude(&normal); + Normalise(&normal); + + //calculate a matrix that will rotate the normal to the zaxis + { + //normal will be the third row + VECTORCH row1,row2; + + + if(normal.vx>30000 || normal.vx<-30000 || normal.vy>30000 || normal.vy<-30000) + { + row1.vx=-normal.vy; + row1.vy=normal.vx; + row1.vz=0; + } + else + { + row1.vx=-normal.vz; + row1.vy=0; + row1.vz=normal.vx; + } + Normalise(&row1); + + CrossProduct(&normal,&row1,&row2); + + mat.mat11=row1.vx; + mat.mat21=row1.vy; + mat.mat31=row1.vz; + + mat.mat12=row2.vx; + mat.mat22=row2.vy; + mat.mat32=row2.vz; + + mat.mat13=normal.vx; + mat.mat23=normal.vy; + mat.mat33=normal.vz; + + } + + + //apply the rotation to the velocity + rotated_vel=*target_vel; + RotateVector(&rotated_vel,&mat); + + //is the target moving too fast? + if(rotated_vel.vz>=projectile_speed || -rotated_vel.vz>=projectile_speed) + { + return FALSE; + } + + //the x and y components of the rotated solution should match the rotated velocity + //(scale down by projectile speed , because we want a normalised direction) + + rotated_solution.vx=DIV_FIXED(rotated_vel.vx,projectile_speed); + rotated_solution.vy=DIV_FIXED(rotated_vel.vy,projectile_speed); + + //z=1-(x*x+y*y) + { + //not sure we have a fixed point square root + float x=(float)rotated_solution.vx; + float y=(float)rotated_solution.vy; + float z_squared=65536.0*65536.0-(x*x+y*y); + if(z_squared<0) + { + //target moving too fast to hit + return FALSE; + } + rotated_solution.vz=(int)sqrt(z_squared); + } + + //finally need to rotated solution back + *solution=rotated_solution; + TransposeMatrixCH(&mat); + RotateVector(solution,&mat); + + //normalise solution to be on the safe side + Normalise(solution); + + return TRUE; + +} + +void SmartTarget(int speed,int projectile_speed) +{ + DISPLAYBLOCK *trackedObject; + + if (SmartgunMode==I_Track) { + trackedObject=SmartTarget_GetNewTarget(); + } else { + trackedObject=NULL; + } + +// textprint("Tracking object %x ",trackedObject); + { + int screenX; + int screenY; + CurrentlySmartTargetingObject=0; + + /* If there is a valid near object which isn't so close as to cause a division by zero */ + if (trackedObject && (trackedObject->ObView.vz!=0)) + { + VECTORCH targetView; + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + #if 0 + STRATEGYBLOCK *sbPtr = trackedObject->ObStrategyBlock; + int offsetX,offsetY; + + { + /* calculate offset required to aim at the middle torso rather + than the sprite's bollocks */ + MATRIXCH mat; + int offsetMag; + { + SHAPEHEADER *shapePtr = GetShapeData(sbPtr->SBdptr->ObShape); + offsetMag = shapePtr->shapeminy/2; + } + + offsetX = MUL_FIXED(trackedObject->ObMat.mat21,offsetMag); + offsetY = MUL_FIXED(trackedObject->ObMat.mat22,offsetMag); + } + #endif + /* Set targetView. */ + SmartTarget_GetCofM(trackedObject,&targetView); + + if(projectile_speed) + { + //get a firing solution so that projectile should hit if target maintains curremt velocity + if(trackedObject->ObStrategyBlock) + { + if(trackedObject->ObStrategyBlock->DynPtr) + { + DYNAMICSBLOCK *dynPtr = trackedObject->ObStrategyBlock->DynPtr; + if(dynPtr->LinVelocity.vx || dynPtr->LinVelocity.vy || dynPtr->LinVelocity.vz) + { + + VECTORCH velocity=dynPtr->LinVelocity; + VECTORCH zero={0,0,0}; + VECTORCH solution; + //rotate velocity into view space + RotateVector(&velocity,&Global_VDB_Ptr->VDB_Mat); + + if(CalculateFiringSolution(&zero,&targetView,&velocity,projectile_speed,&solution)) + { + targetView=solution; + } + + + } + } + } + } + + if (targetView.vz>0) + { + screenX = WideMulNarrowDiv + ( + //trackedObject->ObView.vx,//+offsetX, + targetView.vx, + VDBPtr->VDB_ProjX, + //trackedObject->ObView.vz + targetView.vz + ); + screenY = WideMulNarrowDiv + ( + //trackedObject->ObView.vy,//+offsetY, + targetView.vy*4, + VDBPtr->VDB_ProjY, + //trackedObject->ObView.vz + (targetView.vz*3) + ); + CurrentlySmartTargetingObject=1; + } + else + { + screenX=0; + screenY=0; + } + } + else + { + screenX=0; + screenY=0; + } + + + { + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + int targetX,targetY,dx,dy; + int targetingSpeed = NormalFrameTime*speed; + + /* KJL 14:08:50 09/20/96 - the targeting is FRI, but care has to be taken + at very low frame rates to ensure that the sight doesn't jump about + all over the place. */ + if (targetingSpeed > 65536) targetingSpeed=65536; + + targetX = (ScreenDescriptorBlock.SDB_Width>>1); + targetY = (ScreenDescriptorBlock.SDB_Height>>1); + + { + int maxRangeX = (ScreenDescriptorBlock.SDB_Width*14)/32; /* gives nearly 90% of screen */ + + if ((screenX>-maxRangeX) && (screenX-maxRangeY) && (screenY16384 || dx<-16384) SmartTargetSightX += dx; + else SmartTargetSightX = targetX<<16; + + /* Similarly for the y-coord */ + if (dy>16384 || dy<-16384) SmartTargetSightY += dy; + else SmartTargetSightY = targetY<<16; + } + } + + } + + Old_SmartTarget_Object=SmartTarget_Object; + + if (CurrentlySmartTargetingObject) { + SmartTarget_Object=trackedObject; + } else { + SmartTarget_Object=NULL; + } + + return; +} + +#define SMART_TRACKABLE_TARGETS 100 + +DISPLAYBLOCK *SmartTarget_GetNewTarget(void) { + + int a,b,c; + int numberOfObjects = NumOnScreenBlocks; + DISPLAYBLOCK *nearestObjectPtr, *target; + int nearestObjectDist; + + DISPLAYBLOCK *track_array[SMART_TRACKABLE_TARGETS]; + + target=NULL; + + nearestObjectPtr=NULL; + + for (a=0; aObStrategyBlock; + + if (sbPtr && sbPtr->DynPtr) + { + VECTORCH viewPos; + /* Arc reject. */ + SmartTarget_GetCofM(objectPtr,&viewPos); + if (viewPos.vz>0) { + if (SmartTarget_TargetFilter(sbPtr)) { + if (aObWorld,&Player->ObWorld); + + sbPtr = objectPtr->ObStrategyBlock; + + if (distVDB_World),nearestObjectDist) ) { + /* Valid. */ + target=track_array[notFar]; + break; // Exit loop + } else { + /* Remove from list. */ + track_array[notFar]=NULL; + } + } + } + + return(target); + +} + +void SmartTarget_GetCofM(DISPLAYBLOCK *target,VECTORCH *viewSpaceOutput) { + + AVP_BEHAVIOUR_TYPE targetType; + + /* Get smartgun aiming point. */ + + if (target->HModelControlBlock==NULL) { + *viewSpaceOutput=target->ObView; + return; + } else if (target->HModelControlBlock->section_data==NULL) { + /* Always consider extreme possibilities. */ + *viewSpaceOutput=target->ObView; + return; + } + + /* Must be a hierarchy. */ + + if (target->ObStrategyBlock->I_SBtype==I_BehaviourNetGhost) { + + NETGHOSTDATABLOCK *dataptr; + + dataptr=target->ObStrategyBlock->SBdataptr; + + targetType=dataptr->type; + + } else if ( + (target->ObStrategyBlock->I_SBtype==I_BehaviourMarinePlayer)|| + (target->ObStrategyBlock->I_SBtype==I_BehaviourAlienPlayer)|| + (target->ObStrategyBlock->I_SBtype==I_BehaviourPredatorPlayer)) { + + switch(AvP.PlayerType) + { + case I_Alien: + targetType=I_BehaviourAlienPlayer; + break; + case I_Predator: + targetType=I_BehaviourPredatorPlayer; + break; + case I_Marine: + targetType=I_BehaviourMarinePlayer; + break; + default: + GLOBALASSERT(0); + return; + break; + } + + } else { + targetType=target->ObStrategyBlock->I_SBtype; + } + + /* Now, switch case on targetType. */ + + switch (targetType) { + case I_BehaviourMarine: + case I_BehaviourMarinePlayer: + { + SECTION_DATA *targetsection; + + targetsection=GetThisSectionData(target->HModelControlBlock->section_data, + "chest"); + + if (targetsection==NULL) { + targetsection=target->HModelControlBlock->section_data; + } + + if (targetsection->flags§ion_data_view_init) { + *viewSpaceOutput=targetsection->View_Offset; + return; + } else { + /* Whoops. */ + *viewSpaceOutput=target->ObView; + return; + } + } + break; + case I_BehaviourPredator: + case I_BehaviourPredatorPlayer: + { + SECTION_DATA *targetsection; + + targetsection=GetThisSectionData(target->HModelControlBlock->section_data, + "chest"); + + if (targetsection==NULL) { + targetsection=target->HModelControlBlock->section_data; + } + + if (targetsection->flags§ion_data_view_init) { + *viewSpaceOutput=targetsection->View_Offset; + return; + } else { + /* Whoops. */ + *viewSpaceOutput=target->ObView; + return; + } + } + break; + case I_BehaviourAlien: + case I_BehaviourAlienPlayer: + { + SECTION_DATA *targetsection; + + targetsection=GetThisSectionData(target->HModelControlBlock->section_data, + "chest"); + + if (targetsection==NULL) { + targetsection=target->HModelControlBlock->section_data; + } + + if (targetsection->flags§ion_data_view_init) { + *viewSpaceOutput=targetsection->View_Offset; + return; + } else { + /* Whoops. */ + *viewSpaceOutput=target->ObView; + return; + } + } + break; + default: + { + /* General case. */ + if (target->HModelControlBlock->section_data->flags§ion_data_view_init) { + *viewSpaceOutput=target->HModelControlBlock->section_data->View_Offset; + return; + } else { + /* Whoops. */ + *viewSpaceOutput=target->ObView; + return; + } + } + break; + } + +} + + + +int SmartTarget_TargetFilter(STRATEGYBLOCK *candidate) +{ + PLAYER_WEAPON_DATA *weaponPtr = &(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot]); + + /* KJL 11:56:33 14/10/98 - the Predator's Shoulder cannon can only track objects when used in the correct + vision mode, e.g. you can only target marines when in infrared mode */ + if ((weaponPtr->WeaponIDNumber == WEAPON_PRED_SHOULDERCANNON) + ||(weaponPtr->WeaponIDNumber == WEAPON_PRED_DISC)) + { + switch (CurrentVisionMode) + { + case VISION_MODE_PRED_SEEALIENS: + { + if (candidate->I_SBtype==I_BehaviourAlien && !NPC_IsDead(candidate)) + { + return 1; + } + if (candidate->I_SBtype==I_BehaviourXenoborg && !NPC_IsDead(candidate)) + { + return 1; + } + if (candidate->I_SBtype==I_BehaviourMarine && !NPC_IsDead(candidate)) + { + MARINE_STATUS_BLOCK *marineStatusPointer; + LOCALASSERT(candidate); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(candidate->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->My_Weapon->Android) { + return(1); + } else { + return(0); + } + } + if (candidate->I_SBtype==I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)candidate->SBdataptr; + + if (ghostDataPtr->type==I_BehaviourAlienPlayer || ghostDataPtr->type==I_BehaviourAlien) + { + return 1; + } + } + break; + } + case VISION_MODE_PRED_THERMAL: + { + if (candidate->I_SBtype==I_BehaviourMarine && !NPC_IsDead(candidate)) + { + MARINE_STATUS_BLOCK *marineStatusPointer; + LOCALASSERT(candidate); + marineStatusPointer = (MARINE_STATUS_BLOCK *)(candidate->SBdataptr); + LOCALASSERT(marineStatusPointer); + + if (marineStatusPointer->My_Weapon->Android) { + return(0); + } else { + return(1); + } + } + if (candidate->I_SBtype==I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)candidate->SBdataptr; + + if (ghostDataPtr->type==I_BehaviourMarinePlayer || ghostDataPtr->type==I_BehaviourMarine) + { + return 1; + } + } + break; + + } + case VISION_MODE_PRED_SEEPREDTECH: + { + if (candidate->I_SBtype==I_BehaviourPredator && !NPC_IsDead(candidate)) + { + return 1; + } + if (candidate->I_SBtype==I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)candidate->SBdataptr; + + if (ghostDataPtr->type==I_BehaviourPredatorPlayer || ghostDataPtr->type==I_BehaviourPredator) + { + /* Check for game type? */ + switch (netGameData.gameType) { + case NGT_Individual: + return(1); + break; + case NGT_CoopDeathmatch: + return(0); + break; + case NGT_LastManStanding: + return(0); + break; + case NGT_PredatorTag: + return(1); + break; + case NGT_Coop: + return(0); + break; + default: + return(1); + break; + } + return (1); + } + } + break; + } + default: + break; + } + return 0; + } else if (weaponPtr->WeaponIDNumber == WEAPON_SMARTGUN) { + /* Don't target marines if Friendly Fire is disabled. */ + if (netGameData.disableFriendlyFire && (netGameData.gameType==NGT_CoopDeathmatch || netGameData.gameType==NGT_Coop)) { + NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)candidate->SBdataptr; + if (ghostDataPtr->type==I_BehaviourMarinePlayer || ghostDataPtr->type==I_BehaviourMarine) { + return(0); + } + } + } + + switch (candidate->I_SBtype) { + case I_BehaviourPredator: + /* Valid. */ + if (NPC_IsDead(candidate)) { + return(0); + } else { + #if 0 + if (NPCPredatorIsCloaked(candidate)) { + return(0); + } else { + return(1); + } + #else + return(1); + #endif + } + break; + case I_BehaviourAlien: + case I_BehaviourQueenAlien: + case I_BehaviourFaceHugger: + case I_BehaviourXenoborg: + case I_BehaviourMarine: + case I_BehaviourSeal: + case I_BehaviourPredatorAlien: + /* Valid. */ + if (NPC_IsDead(candidate)) { + return(0); + } else { + return(1); + } + break; + #if SupportWindows95 + case I_BehaviourNetGhost: + { + NETGHOSTDATABLOCK *dataptr; + dataptr=candidate->SBdataptr; + switch (dataptr->type) { + case I_BehaviourPredatorPlayer: + #if 0 + if (dataptr->CloakingEffectiveness) { + return(0); + } else { + return(1); + } + #else + return(1); + #endif + break; + case I_BehaviourMarinePlayer: + case I_BehaviourAlienPlayer: + case I_BehaviourRocket: + case I_BehaviourFrisbee: + case I_BehaviourGrenade: + case I_BehaviourFlareGrenade: + case I_BehaviourFragmentationGrenade: + case I_BehaviourClusterGrenade: + case I_BehaviourNPCPredatorDisc: + case I_BehaviourPredatorDisc_SeekTrack: + case I_BehaviourAlien: + return(1); + break; + case I_BehaviourProximityGrenade: + { + DYNAMICSBLOCK *dynPtr=candidate->DynPtr; + + /* Only visible when moving. */ + + if (!((dynPtr->Position.vx==dynPtr->PrevPosition.vx) + &&(dynPtr->Position.vy==dynPtr->PrevPosition.vy) + &&(dynPtr->Position.vz==dynPtr->PrevPosition.vz) )) { + + return(1); + + } else { + return(0); + } + + } + break; + default: + return(0); + break; + } + } + break; + #endif + default: + return(0); + break; + } + +} + +void GetTargetingPointOfObject_Far(STRATEGYBLOCK *sbPtr, VECTORCH *targetPtr) +{ + /* Can we use the near one? This is a more general shell. */ + if (sbPtr->SBdptr) { + GetTargetingPointOfObject(sbPtr->SBdptr,targetPtr); + return; + } else { + if (sbPtr->DynPtr) { + *targetPtr=sbPtr->DynPtr->Position; + targetPtr->vy-=500; /* Just to be on the safe side. */ + return; + } else { + /* Aw, gawd! I don't know! There's NO position for this! */ + GLOBALASSERT(0); + } + } + +} + +void GetTargetingPointOfObject(DISPLAYBLOCK *objectPtr, VECTORCH *targetPtr) +{ + /* try to look at the centre of the object */ + if (objectPtr->HModelControlBlock) + { + SECTION_DATA *targetSectionPtr; + SECTION_DATA *firstSectionPtr; + + ProveHModel(objectPtr->HModelControlBlock,objectPtr); + + firstSectionPtr=objectPtr->HModelControlBlock->section_data; + LOCALASSERT(firstSectionPtr); + LOCALASSERT(firstSectionPtr->flags§ion_data_initialised); + + /* look for the object's torso in preference */ + targetSectionPtr =GetThisSectionData(objectPtr->HModelControlBlock->section_data,"chest"); + + if (targetSectionPtr) + { + LOCALASSERT(targetSectionPtr->flags§ion_data_initialised); + *targetPtr = targetSectionPtr->World_Offset; + } + else /* just use the top of the hierarchy then */ + { + *targetPtr = firstSectionPtr->World_Offset; + } + } + else + { + /* KJL 12:23:26 15/05/98 - need to consider the player differently */ + if (objectPtr == Player) + { + #if 0 + *targetPtr = Global_VDB_Ptr->VDB_World; + #else + int height; + + /* Let's try a little experiment. */ + if (PlayerStatusPtr->IsAlive==0) { + *targetPtr = Global_VDB_Ptr->VDB_World; + return; + } + + if (PlayerStatusPtr->ShapeState!=PMph_Standing) { + height=-800; + } else { + height=-1500; + } + + targetPtr->vx=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat21,height); + targetPtr->vy=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat22,height); + targetPtr->vz=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat23,height); + #if 0 + targetPtr->vx+=Player->ObStrategyBlock->DynPtr->Position.vx; + targetPtr->vy+=Player->ObStrategyBlock->DynPtr->Position.vy; + targetPtr->vz+=Player->ObStrategyBlock->DynPtr->Position.vz; + #else + targetPtr->vx+=Player->ObWorld.vx; + targetPtr->vy+=Player->ObWorld.vy; + targetPtr->vz+=Player->ObWorld.vz; + #endif + #endif + } + else + { + *targetPtr = objectPtr->ObWorld; + } + + } +} \ No newline at end of file diff --git a/3dc/avp/targeting.h b/3dc/avp/targeting.h new file mode 100644 index 0000000..34ce929 --- /dev/null +++ b/3dc/avp/targeting.h @@ -0,0 +1,5 @@ +/* KJL 16:20:20 19/05/98 - targeting externs */ + +extern void GetTargetingPointOfObject(DISPLAYBLOCK *objectPtr, VECTORCH *targetPtr); +extern void GetTargetingPointOfObject_Far(STRATEGYBLOCK *sbPtr, VECTORCH *targetPtr); +extern void CalculatePlayersTarget(TEMPLATE_WEAPON_DATA *twPtr, PLAYER_WEAPON_DATA *weaponPtr); diff --git a/3dc/avp/track.c b/3dc/avp/track.c new file mode 100644 index 0000000..5b1e0b3 --- /dev/null +++ b/3dc/avp/track.c @@ -0,0 +1,1020 @@ +#define DB_LEVEL 1 +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "dynblock.h" +#include "stratdef.h" +#include "gamedef.h" +#include "track.h" +#include "jsndsup.h" +#include "psndplat.h" +#include "ourasert.h" +#include "mempool.h" + +#include "db.h" + +static void Preprocess_Smooth_Track_Controller(TRACK_CONTROLLER* tc); +static void SmoothTrackPosition(TRACK_SECTION_DATA* trackPtr, int u, VECTORCH *outputPositionPtr); +static void SmoothTrackOrientation(TRACK_SECTION_DATA* trackPtr, int lerp, MATRIXCH* outputMatrixPtr); +static void BasicSlerp(QUAT *input1,QUAT *input2,QUAT *output,int lerp); +static void MakeControlQuat(QUAT *control, QUAT *q0, QUAT *q1, QUAT *q2); +static void LnQuat(QUAT *q); +static void ExpPurelyImaginaryQuat(QUAT *q); +extern void MulQuat(QUAT *q1, QUAT *q2, QUAT *output); + + + +extern int NormalFrameTime; +extern void QNormalise(QUAT*); +extern int QDot(QUAT *, QUAT *); +extern int sine[]; +extern int cosine[]; + +static void TrackSlerp(TRACK_SECTION_DATA* tsd,int lerp,MATRIXCH* output_mat) +{ + int sclp,sclq; + + QUAT* input1=&tsd->quat_start; + QUAT* input2=&tsd->quat_end; + QUAT output; + + if(lerp<0) lerp=0; + if(lerp>65536)lerp=65536; + + /* First check for special case. */ + + if (tsd->omega==2048) { + int t1,t2; + + output.quatx=-input1->quaty; + output.quaty=input1->quatx; + output.quatz=-input1->quatw; + output.quatw=input1->quatz; + + t1=MUL_FIXED((ONE_FIXED-lerp),1024); + sclp=GetSin(t1); + + t2=MUL_FIXED(lerp,1024); + sclq=GetSin(t2); + + output.quatx=(MUL_FIXED(input1->quatx,sclp))+(MUL_FIXED(output.quatx,sclq)); + output.quaty=(MUL_FIXED(input1->quaty,sclp))+(MUL_FIXED(output.quaty,sclq)); + output.quatz=(MUL_FIXED(input1->quatz,sclp))+(MUL_FIXED(output.quatz,sclq)); + output.quatw=(MUL_FIXED(input1->quatw,sclp))+(MUL_FIXED(output.quatw,sclq)); + + } else { + if ( (tsd->omega==0) && (tsd->oneoversinomega==0) ) { + sclp=ONE_FIXED-lerp; + sclq=lerp; + } else { + int t1,t2; + + t1=MUL_FIXED((ONE_FIXED-lerp),tsd->omega); + t2=GetSin(t1); + sclp=MUL_FIXED(t2,tsd->oneoversinomega); + + t1=MUL_FIXED(lerp,tsd->omega); + t2=GetSin(t1); + sclq=MUL_FIXED(t2,tsd->oneoversinomega); + + } + + output.quatx=(MUL_FIXED(input1->quatx,sclp))+(MUL_FIXED(input2->quatx,sclq)); + output.quaty=(MUL_FIXED(input1->quaty,sclp))+(MUL_FIXED(input2->quaty,sclq)); + output.quatz=(MUL_FIXED(input1->quatz,sclp))+(MUL_FIXED(input2->quatz,sclq)); + output.quatw=(MUL_FIXED(input1->quatw,sclp))+(MUL_FIXED(input2->quatw,sclq)); + } + + QNormalise(&output); + QuatToMat(&output,output_mat); +} + + +void Start_Track_Sound(TRACK_SOUND* ts,VECTORCH * location) +{ + SOUND3DDATA s3d; + + GLOBALASSERT(ts); + + ts->playing=1; + if(ts->activ_no!=SOUND_NOACTIVEINDEX) return; + if(!ts->sound_loaded) return; + + if(ts->loop) + { + //make sure track is close enough to be heard + int dist=VectorDistance(&Player->ObWorld,location); + if(dist>ts->outer_range) + { + return; + } + } + + s3d.position = *location; + s3d.inner_range = ts->inner_range; + s3d.outer_range = ts->outer_range; + s3d.velocity.vx = 0; + s3d.velocity.vy = 0; + s3d.velocity.vz = 0; + + if(ts->loop) + { + Sound_Play ((SOUNDINDEX)ts->sound_loaded->sound_num, "nvpel", &s3d,ts->max_volume,ts->pitch,&ts->activ_no); + } + else + { + Sound_Play ((SOUNDINDEX)ts->sound_loaded->sound_num, "nvpe", &s3d,ts->max_volume,ts->pitch,&ts->activ_no); + } + ts->time_left=GameSounds[ts->sound_loaded->sound_num].length; + + db_logf3(("Playing sound %d\t%s",ts->sound_loaded->sound_num,GameSounds[ts->sound_loaded->sound_num].wavName)); + +} +void Stop_Track_Sound(TRACK_SOUND* ts) +{ + GLOBALASSERT(ts); + + ts->playing=0; + if(ts->activ_no!=SOUND_NOACTIVEINDEX) + { + Sound_Stop(ts->activ_no); + ts->time_left=0; + } +} +void Update_Track_Sound(TRACK_SOUND* ts,VECTORCH * location) +{ + GLOBALASSERT(ts); + + if(ts->playing) + { + ts->time_left-=NormalFrameTime; + if(ts->loop) + { + //check to see if sound is close enough to player + int dist=VectorDistance(&Player->ObWorld,location); + if(dist>ts->outer_range) + { + //stop playing the sound for the moment + if(ts->activ_no != SOUND_NOACTIVEINDEX) + { + Sound_Stop(ts->activ_no); + } + } + else + { + if(ts->activ_no == SOUND_NOACTIVEINDEX) + { + //restart the sound + Start_Track_Sound(ts,location); + return; + } + + if (ts->activ_no != SOUND_NOACTIVEINDEX) + { + //update the sound's location + SOUND3DDATA s3d; + s3d.position = *location; + s3d.inner_range = ts->inner_range; + s3d.outer_range = ts->outer_range; + s3d.velocity.vx = 0; + s3d.velocity.vy = 0; + s3d.velocity.vz = 0; + + Sound_UpdateNew3d (ts->activ_no, &s3d); + } + } + } + else + { + if(ts->activ_no == SOUND_NOACTIVEINDEX) + { + //sound has stopped playing. + ts->playing=0; + } + } + } +} + +void Deallocate_Track_Sound(TRACK_SOUND* ts) +{ + GLOBALASSERT(ts); + + Stop_Track_Sound(ts); + + if(ts->sound_loaded) + { + LoseSound(ts->sound_loaded); + } + + #if !USE_LEVEL_MEMORY_POOL + DeallocateMem (ts); + #endif +} + +void Update_Track_Position_Only(TRACK_CONTROLLER* tc) +{ + TRACK_SECTION_DATA* cur_tsd; + DYNAMICSBLOCK* dynptr; + + GLOBALASSERT(tc); + + GLOBALASSERT(tc->sbptr); + GLOBALASSERT(tc->sections); + + dynptr=tc->sbptr->DynPtr; + GLOBALASSERT(dynptr); + + cur_tsd=&tc->sections[tc->current_section]; + + + //adjust timer until time lies within a section + while(tc->timer>cur_tsd->time_for_section || tc->timer<0) + { + if(tc->timer>cur_tsd->time_for_section) + { + tc->timer-=cur_tsd->time_for_section; + + if(tc->current_section==(tc->num_sections-1) && !tc->loop) + { + if(tc->loop_backandforth) + { + //turn around + tc->reverse=1; + tc->timer=cur_tsd->time_for_section-tc->timer; + } + else + { + //reached end of track + tc->timer=cur_tsd->time_for_section; + tc->playing=0; + tc->reverse=1; + } + } + else + { + tc->current_section++; + + if(tc->current_section==tc->num_sections) tc->current_section=0; + + cur_tsd=&tc->sections[tc->current_section]; + } + + } + else + { + if(tc->current_section==0 && !tc->loop) + { + if(tc->loop_backandforth) + { + //turn around + tc->reverse=0; + tc->timer=-tc->timer; + } + else + { + //reached end of track + tc->timer=0; + tc->playing=0; + tc->reverse=0; + } + + } + else + { + tc->current_section--; + + if(tc->current_section<0) tc->current_section=tc->num_sections-1; + + cur_tsd=&tc->sections[tc->current_section]; + tc->timer+=cur_tsd->time_for_section; + } + + } + + } + + // now work out the object position at this time + + /* KJL 14:47:44 24/03/98 - check for smoothing; if you've + less than 3 points then smoothing is a bit pointless */ + if (tc->use_smoothing && tc->num_sections>=3) + { + int lerp=MUL_FIXED(tc->timer,cur_tsd->oneovertime); + SmoothTrackOrientation(cur_tsd,lerp,&(dynptr->OrientMat)); + SmoothTrackPosition(cur_tsd,lerp,&(dynptr->Position)); + + } + else + { + if(tc->no_rotation) + { + int lerp=MUL_FIXED(tc->timer,cur_tsd->oneovertime); + VECTORCH pivot_pos=cur_tsd->pivot_start; + + pivot_pos.vx+=MUL_FIXED(cur_tsd->pivot_travel.vx,lerp); + pivot_pos.vy+=MUL_FIXED(cur_tsd->pivot_travel.vy,lerp); + pivot_pos.vz+=MUL_FIXED(cur_tsd->pivot_travel.vz,lerp); + + + + dynptr->Position=pivot_pos; + } + else + { + int lerp=MUL_FIXED(tc->timer,cur_tsd->oneovertime); + MATRIXCH orient; + VECTORCH pivot_pos=cur_tsd->pivot_start; + VECTORCH object_pos=cur_tsd->object_offset; + + TrackSlerp(cur_tsd,lerp,&orient); + + pivot_pos.vx+=MUL_FIXED(cur_tsd->pivot_travel.vx,lerp); + pivot_pos.vy+=MUL_FIXED(cur_tsd->pivot_travel.vy,lerp); + pivot_pos.vz+=MUL_FIXED(cur_tsd->pivot_travel.vz,lerp); + + RotateVector(&object_pos,&orient); + + AddVector(&pivot_pos,&object_pos); + + + dynptr->OrientMat=orient; + dynptr->Position=object_pos; + } + } +} + +void Update_Track_Position(TRACK_CONTROLLER* tc) +{ + DYNAMICSBLOCK* dynptr; + + GLOBALASSERT(tc); + + if(!tc->playing) return; + + GLOBALASSERT(tc->sbptr); + GLOBALASSERT(tc->sections); + + dynptr=tc->sbptr->DynPtr; + GLOBALASSERT(dynptr); + + if(tc->playing_start_sound) + { + Update_Track_Sound(tc->start_sound,&dynptr->Position); + if(tc->start_sound->playing) + { + return; + } + tc->playing_start_sound=FALSE; + if(tc->sound) + { + Start_Track_Sound(tc->sound,&tc->sbptr->DynPtr->Position); + } + } + + //update timer and current section number + if(tc->reverse) + { + if(tc->use_speed_mult) + tc->timer-=MUL_FIXED(NormalFrameTime,tc->speed_mult); + else + tc->timer-=NormalFrameTime; + } + else + { + if(tc->use_speed_mult) + tc->timer+=MUL_FIXED(NormalFrameTime,tc->speed_mult); + else + tc->timer+=NormalFrameTime; + } + + Update_Track_Position_Only(tc); + + if(tc->sound) + { + if(tc->playing) + { + Update_Track_Sound(tc->sound,&dynptr->Position); + } + else + { + Stop_Track_Sound(tc->sound); + if(tc->end_sound) + { + Start_Track_Sound(tc->end_sound,&tc->sbptr->DynPtr->Position); + } + } + } +} + +void Preprocess_Track_Controller(TRACK_CONTROLLER* tc) +{ + int i; + GLOBALASSERT(tc->sections); + + /* KJL 14:47:44 24/03/98 - check for smoothing; if you've + less than 3 points then smoothing is a bit pointless */ + if (tc->use_smoothing && tc->num_sections>=3) + { + Preprocess_Smooth_Track_Controller(tc); + return; + } + + for(i=0;inum_sections;i++) + { + + TRACK_SECTION_DATA* tsd=&tc->sections[i]; + + tsd->oneovertime=DIV_FIXED(ONE_FIXED,tsd->time_for_section); + + if(!tc->no_rotation) + { + int cosom,sinom; + cosom=QDot(&tsd->quat_start,&tsd->quat_end); + + if (cosom<0) { + tsd->quat_end.quatx=-tsd->quat_end.quatx; + tsd->quat_end.quaty=-tsd->quat_end.quaty; + tsd->quat_end.quatz=-tsd->quat_end.quatz; + tsd->quat_end.quatw=-tsd->quat_end.quatw; + cosom=-cosom; + } + + + tsd->omega=ArcCos(cosom); + sinom=GetSin(tsd->omega); + if (sinom) { + tsd->oneoversinomega=DIV_FIXED(ONE_FIXED,sinom); + } else { + tsd->omega=0; + tsd->oneoversinomega=0; + } + } + } + +} + + + +void Start_Track_Playing(TRACK_CONTROLLER* tc) +{ + GLOBALASSERT(tc); + GLOBALASSERT(tc->sbptr); + GLOBALASSERT(tc->sbptr->DynPtr); + + if(tc->playing) return; + + tc->playing=1; + if(tc->start_sound) + { + tc->playing_start_sound=1; + Start_Track_Sound(tc->start_sound,&tc->sbptr->DynPtr->Position); + } + else if(tc->sound) + { + Start_Track_Sound(tc->sound,&tc->sbptr->DynPtr->Position); + } + +} + +void Stop_Track_Playing(TRACK_CONTROLLER* tc) +{ + GLOBALASSERT(tc); + GLOBALASSERT(tc->sbptr); + GLOBALASSERT(tc->sbptr->DynPtr); + + if(!tc->playing) return; + + tc->playing=0; + tc->playing_start_sound=0; + + if(tc->sound) + { + Stop_Track_Sound(tc->sound); + } + if(tc->start_sound) + { + Stop_Track_Sound(tc->sound); + } + if(tc->end_sound) + { + Start_Track_Sound(tc->end_sound,&tc->sbptr->DynPtr->Position); + } +} + + +void Reset_Track(TRACK_CONTROLLER* tc) +{ + GLOBALASSERT(tc); + + if(tc->sound) + { + Stop_Track_Sound(tc->sound); + } + if(tc->start_sound) + { + Stop_Track_Sound(tc->start_sound); + } + if(tc->end_sound) + { + Stop_Track_Sound(tc->end_sound); + } + tc->timer=tc->initial_state_timer; + tc->playing=tc->initial_state_playing; + tc->reverse=tc->initial_state_reverse; + tc->current_section=0; + + if(tc->playing && tc->sound) + { + tc->sound->playing=1; + } + +} + +void Deallocate_Track(TRACK_CONTROLLER* tc) +{ + GLOBALASSERT(tc); + + + if(tc->sound) + { + Deallocate_Track_Sound(tc->sound); + } + if(tc->start_sound) + { + Deallocate_Track_Sound(tc->start_sound); + } + if(tc->end_sound) + { + Deallocate_Track_Sound(tc->end_sound); + } + + #if !USE_LEVEL_MEMORY_POOL + if(tc->sections) DeallocateMem(tc->sections); + DeallocateMem(tc); + #endif + +} + + +/*KJL******************************************************************* +* * +* Smooth track system - this code overlays cubic splines over the lerp * +* and slerp code used by the original track system * +* * +*******************************************************************KJL*/ +static void Preprocess_Smooth_Track_Controller(TRACK_CONTROLLER* tc) +{ + int i; + GLOBALASSERT(tc->sections); + + for(i=0;inum_sections;i++) + { + TRACK_SECTION_DATA* tsd=&tc->sections[i]; + tsd->oneovertime=DIV_FIXED(ONE_FIXED,tsd->time_for_section); + + if (i==0) + { + tsd->quat_prev = tsd->quat_start; + tsd->pivot_0 = tsd->pivot_start; + tsd->pivot_1 = tsd->pivot_start; + tsd->pivot_2 = tc->sections[1].pivot_start; + tsd->pivot_3 = tc->sections[2].pivot_start; + } + else if (i==tc->num_sections-1) + { + tsd->quat_prev = tc->sections[i-1].quat_start; + tsd->pivot_0 = tc->sections[i-1].pivot_1; + tsd->pivot_1 = tsd->pivot_start; + + tsd->pivot_2 = tsd->pivot_1; + tsd->pivot_2.vx += tsd->pivot_travel.vx; + tsd->pivot_2.vy += tsd->pivot_travel.vy; + tsd->pivot_2.vz += tsd->pivot_travel.vz; + + tsd->pivot_3 = tsd->pivot_2; + } + else if (i==tc->num_sections-2) + { + tsd->quat_prev = tc->sections[i-1].quat_start; + tsd->pivot_0 = tc->sections[i-1].pivot_1; + tsd->pivot_1 = tsd->pivot_start; + tsd->pivot_2 = tc->sections[i+1].pivot_start; + + tsd->pivot_3 = tsd->pivot_2; + tsd->pivot_3.vx += tc->sections[i+1].pivot_travel.vx; + tsd->pivot_3.vy += tc->sections[i+1].pivot_travel.vy; + tsd->pivot_3.vz += tc->sections[i+1].pivot_travel.vz; + } + else + { + tsd->quat_prev = tc->sections[i-1].quat_start; + tsd->pivot_0 = tc->sections[i-1].pivot_start; + tsd->pivot_1 = tsd->pivot_start; + tsd->pivot_2 = tc->sections[i+1].pivot_start; + tsd->pivot_3 = tc->sections[i+2].pivot_start; + } + } + + for(i=0;inum_sections;i++) + { + TRACK_SECTION_DATA* tsd=&tc->sections[i]; + if (QDot(&tsd->quat_prev,&tsd->quat_start)<0) + { + tsd->quat_start.quatx=-tsd->quat_start.quatx; + tsd->quat_start.quaty=-tsd->quat_start.quaty; + tsd->quat_start.quatz=-tsd->quat_start.quatz; + tsd->quat_start.quatw=-tsd->quat_start.quatw; + } + if (QDot(&tsd->quat_start,&tsd->quat_end)<0) + { + tsd->quat_end.quatx=-tsd->quat_end.quatx; + tsd->quat_end.quaty=-tsd->quat_end.quaty; + tsd->quat_end.quatz=-tsd->quat_end.quatz; + tsd->quat_end.quatw=-tsd->quat_end.quatw; + } + MakeControlQuat + ( + &(tsd->quat_start_control), + &(tsd->quat_prev), + &(tsd->quat_start), + &(tsd->quat_end) + ); + } + for(i=0;inum_sections-1;i++) + { + tc->sections[i].quat_end_control = tc->sections[i+1].quat_start_control; + } + tc->sections[tc->num_sections-1].quat_end_control = tc->sections[tc->num_sections-1].quat_end; +} + +static void SmoothTrackPosition(TRACK_SECTION_DATA* trackPtr, int u, VECTORCH *outputPositionPtr) +{ + int u2 = MUL_FIXED(u,u); + int u3 = MUL_FIXED(u2,u); + + { + int a = (-trackPtr->pivot_0.vx+3*trackPtr->pivot_1.vx-3*trackPtr->pivot_2.vx+trackPtr->pivot_3.vx); + int b = (2*trackPtr->pivot_0.vx-5*trackPtr->pivot_1.vx+4*trackPtr->pivot_2.vx-trackPtr->pivot_3.vx); + int c = (-1*trackPtr->pivot_0.vx+trackPtr->pivot_2.vx); + outputPositionPtr->vx = (MUL_FIXED(a,u3)+MUL_FIXED(b,u2)+MUL_FIXED(c,u))/2+trackPtr->pivot_1.vx; + } + { + int a = (-trackPtr->pivot_0.vy+3*trackPtr->pivot_1.vy-3*trackPtr->pivot_2.vy+trackPtr->pivot_3.vy); + int b = (2*trackPtr->pivot_0.vy-5*trackPtr->pivot_1.vy+4*trackPtr->pivot_2.vy-trackPtr->pivot_3.vy); + int c = (-1*trackPtr->pivot_0.vy+trackPtr->pivot_2.vy); + outputPositionPtr->vy = (MUL_FIXED(a,u3)+MUL_FIXED(b,u2)+MUL_FIXED(c,u))/2+trackPtr->pivot_1.vy; + } + { + int a = (-trackPtr->pivot_0.vz+3*trackPtr->pivot_1.vz-3*trackPtr->pivot_2.vz+trackPtr->pivot_3.vz); + int b = (2*trackPtr->pivot_0.vz-5*trackPtr->pivot_1.vz+4*trackPtr->pivot_2.vz-trackPtr->pivot_3.vz); + int c = (-1*trackPtr->pivot_0.vz+trackPtr->pivot_2.vz); + outputPositionPtr->vz = (MUL_FIXED(a,u3)+MUL_FIXED(b,u2)+MUL_FIXED(c,u))/2+trackPtr->pivot_1.vz; + } +} +#if 0 + +static void SmoothTrackPositionBSpline(TRACK_SECTION_DATA* trackPtr, int u, VECTORCH *outputPositionPtr) +{ + int u2 = MUL_FIXED(u,u); + int u3 = MUL_FIXED(u2,u); + + { + int a = (-trackPtr->pivot_0.vx +3*trackPtr->pivot_1.vx -3*trackPtr->pivot_2.vx +1*trackPtr->pivot_3.vx); + int b = (3*trackPtr->pivot_0.vx -6*trackPtr->pivot_1.vx +3*trackPtr->pivot_2.vx +0*trackPtr->pivot_3.vx); + int c = (-3*trackPtr->pivot_0.vx +0*trackPtr->pivot_1.vx +3*trackPtr->pivot_2.vx +0*trackPtr->pivot_3.vx); + int d = (trackPtr->pivot_0.vx +4*trackPtr->pivot_1.vx +1*trackPtr->pivot_2.vx +0*trackPtr->pivot_3.vx); + + outputPositionPtr->vx = (MUL_FIXED(a,u3)+MUL_FIXED(b,u2)+MUL_FIXED(c,u)+d)/6; + } + { + int a = (-trackPtr->pivot_0.vy +3*trackPtr->pivot_1.vy -3*trackPtr->pivot_2.vy +1*trackPtr->pivot_3.vy); + int b = (3*trackPtr->pivot_0.vy -6*trackPtr->pivot_1.vy +3*trackPtr->pivot_2.vy +0*trackPtr->pivot_3.vy); + int c = (-3*trackPtr->pivot_0.vy +0*trackPtr->pivot_1.vy +3*trackPtr->pivot_2.vy +0*trackPtr->pivot_3.vy); + int d = (trackPtr->pivot_0.vy +4*trackPtr->pivot_1.vy +1*trackPtr->pivot_2.vy +0*trackPtr->pivot_3.vy); + + outputPositionPtr->vy = (MUL_FIXED(a,u3)+MUL_FIXED(b,u2)+MUL_FIXED(c,u)+d)/6; + } + { + int a = (-trackPtr->pivot_0.vz +3*trackPtr->pivot_1.vz -3*trackPtr->pivot_2.vz +1*trackPtr->pivot_3.vz); + int b = (3*trackPtr->pivot_0.vz -6*trackPtr->pivot_1.vz +3*trackPtr->pivot_2.vz +0*trackPtr->pivot_3.vz); + int c = (-3*trackPtr->pivot_0.vz +0*trackPtr->pivot_1.vz +3*trackPtr->pivot_2.vz +0*trackPtr->pivot_3.vz); + int d = (trackPtr->pivot_0.vz +4*trackPtr->pivot_1.vz +1*trackPtr->pivot_2.vz +0*trackPtr->pivot_3.vz); + + outputPositionPtr->vz = (MUL_FIXED(a,u3)+MUL_FIXED(b,u2)+MUL_FIXED(c,u)+d)/6; + } +} + +#endif + +static void SmoothTrackOrientation(TRACK_SECTION_DATA* trackPtr, int lerp, MATRIXCH* outputMatrixPtr) +{ + QUAT q1,q2,q3; + + if(lerp<0) lerp=0; + if(lerp>65536)lerp=65536; + + BasicSlerp(&trackPtr->quat_start,&trackPtr->quat_end, &q1, lerp); + BasicSlerp(&trackPtr->quat_start_control,&trackPtr->quat_end_control, &q2, lerp); + + lerp = MUL_FIXED(ONE_FIXED-lerp,2*lerp); + if(lerp<0) lerp=0; + if(lerp>65536)lerp=65536; + + BasicSlerp(&q1, &q2, &q3, lerp); + + QuatToMat(&q3,outputMatrixPtr); +} + +static void BasicSlerp(QUAT *input1,QUAT *input2,QUAT *output,int lerp) +{ + int sclp,sclq; + + int cosom; + int omega, sinom; + + cosom=QDot(input1,input2); + if (cosom>0) + { + *output=*input2; + } + else + { + output->quatx=-input2->quatx; + output->quaty=-input2->quaty; + output->quatz=-input2->quatz; + output->quatw=-input2->quatw; + cosom =-cosom; + } + + if(cosom<65500) + { + omega=ArcCos(cosom); + sinom=GetSin(omega); + + /* healthy paranoia */ + LOCALASSERT(sinom!=0); + + sclp=DIV_FIXED + ( + GetSin + ( + MUL_FIXED((ONE_FIXED-lerp),omega) + ), + sinom + ); + sclq=DIV_FIXED + ( + GetSin + ( + MUL_FIXED(lerp,omega) + ), + sinom + ); + } + else + { + sclp=ONE_FIXED-lerp; + sclq=lerp; + } + + + output->quatx=(MUL_FIXED(input1->quatx,sclp))+(MUL_FIXED(output->quatx,sclq)); + output->quaty=(MUL_FIXED(input1->quaty,sclp))+(MUL_FIXED(output->quaty,sclq)); + output->quatz=(MUL_FIXED(input1->quatz,sclp))+(MUL_FIXED(output->quatz,sclq)); + output->quatw=(MUL_FIXED(input1->quatw,sclp))+(MUL_FIXED(output->quatw,sclq)); + QNormalise(output); +} + +static void MakeControlQuat(QUAT *control, QUAT *q0, QUAT *q1, QUAT *q2) +{ + QUAT a; + QUAT b,c; + + a.quatx=-q1->quatx; + a.quaty=-q1->quaty; + a.quatz=-q1->quatz; + a.quatw=q1->quatw; + + MulQuat(&a,q2, &b); + MulQuat(&a,q0, &c); + + LnQuat(&b); + LnQuat(&c); + + a.quatx = -(b.quatx+c.quatx)/4; + a.quaty = -(b.quaty+c.quaty)/4; + a.quatz = -(b.quatz+c.quatz)/4; + + ExpPurelyImaginaryQuat(&a); + MulQuat(q1,&a, control); +} + + +#include +static void LnQuat(QUAT *q) +{ + float theta; + float m,x,y,z; + + x = q->quatx; + y = q->quaty; + z = q->quatz; + + if (x==0 && y==0 && z==0) + { + q->quatw = 0; + q->quatx = 0; + q->quaty = 0; + q->quatz = 0; + return; + + } + { + double cosine = (q->quatw/65536.0); + + if (cosine > 1.0) cosine = 1.0; + else if (cosine < -1.0) cosine = -1.0; + + + theta = (float)acos(cosine); + } + + m = (65536.0/sqrt((x*x) + (y*y) + (z*z)) ); + + x *= m; + y *= m; + z *= m; + + q->quatw = 0; + q->quatx = (int)(x*theta); + q->quaty = (int)(y*theta); + q->quatz = (int)(z*theta); +} +static void ExpPurelyImaginaryQuat(QUAT *q) +{ + float x,y,z; + int theta; + + x = q->quatx; + y = q->quaty; + z = q->quatz; + + if (x!=0||y!=0||z!=0) + { + float m = sqrt((x*x) + (y*y) + (z*z)); + x /= m; + y /= m; + z /= m; + + theta = (int)((m / 16.0) / 6.28318530718); + + q->quatx = (int)(x*(float)GetSin(theta)); + q->quaty = (int)(y*(float)GetSin(theta)); + q->quatz = (int)(z*(float)GetSin(theta)); + q->quatw = GetCos(theta); + } + else + { + q->quatx = 0; + q->quaty = 0; + q->quatz = 0; + q->quatw = ONE_FIXED; + } + QNormalise(q); +} + + +/*--------------------** +** Loading and Saving ** +**--------------------*/ +#include "savegame.h" +typedef struct track_save_block +{ + SAVE_BLOCK_HEADER header; + + int timer; + int speed_mult; + int current_section; + + unsigned int playing:1; + unsigned int reverse:1; + unsigned int no_rotation:1; + unsigned int use_speed_mult:1; + + unsigned int start_sound_playing:1; + unsigned int mid_sound_playing:1; + unsigned int end_sound_playing:1; + + int start_sound_time_left; + int mid_sound_time_left; + int end_sound_time_left; + +}TRACK_SAVE_BLOCK; + +//defines for load/save macros +#define SAVELOAD_BLOCK block +#define SAVELOAD_BEHAV tc + +void LoadTrackPosition(SAVE_BLOCK_HEADER* header,TRACK_CONTROLLER* tc) +{ + TRACK_SAVE_BLOCK* block = (TRACK_SAVE_BLOCK*)header; + if(!header || !tc) return; + + //check the size of the save block + if(header->size!=sizeof(*block)) return; + + //start copying stuff + + COPYELEMENT_LOAD(timer) + COPYELEMENT_LOAD(speed_mult) + COPYELEMENT_LOAD(current_section) + + COPYELEMENT_LOAD(playing) + COPYELEMENT_LOAD(reverse) + COPYELEMENT_LOAD(no_rotation) + COPYELEMENT_LOAD(use_speed_mult) + + Update_Track_Position_Only(tc); + + if(tc->start_sound) + { + tc->start_sound->playing = block->start_sound_playing; + tc->start_sound->time_left = block->start_sound_time_left; + } + if(tc->sound) + { + tc->sound->playing = block->mid_sound_playing; + tc->sound->time_left = block->mid_sound_time_left; + } + if(tc->end_sound) + { + tc->end_sound->playing = block->end_sound_playing; + tc->end_sound->time_left = block->end_sound_time_left; + } + + if(tc->start_sound) Load_SoundState(&tc->start_sound->activ_no); + if(tc->sound) Load_SoundState(&tc->sound->activ_no); + if(tc->end_sound) Load_SoundState(&tc->end_sound->activ_no); + + +} +void SaveTrackPosition(TRACK_CONTROLLER* tc) +{ + TRACK_SAVE_BLOCK* block; + if(!tc) return; + + GET_SAVE_BLOCK_POINTER(block); + + //fill in header + block->header.type = SaveBlock_Track; + block->header.size = sizeof(*block); + + //start copying stuff + + COPYELEMENT_SAVE(timer) + COPYELEMENT_SAVE(speed_mult) + COPYELEMENT_SAVE(current_section) + + COPYELEMENT_SAVE(playing) + COPYELEMENT_SAVE(reverse) + COPYELEMENT_SAVE(no_rotation) + COPYELEMENT_SAVE(use_speed_mult) + + if(tc->start_sound) + { + block->start_sound_playing = tc->start_sound->playing; + block->start_sound_time_left = tc->start_sound->time_left; + } + else + { + block->start_sound_playing = 0; + block->start_sound_time_left = 0; + } + + if(tc->sound) + { + block->mid_sound_playing = tc->sound->playing; + block->mid_sound_time_left = tc->sound->time_left; + } + else + { + block->mid_sound_playing = 0; + block->mid_sound_time_left = 0; + } + + if(tc->end_sound) + { + block->end_sound_playing = tc->end_sound->playing; + block->end_sound_time_left = tc->end_sound->time_left; + } + else + { + block->end_sound_playing = 0; + block->end_sound_time_left = 0; + } + + if(tc->start_sound) Save_SoundState(&tc->start_sound->activ_no); + if(tc->sound) Save_SoundState(&tc->sound->activ_no); + if(tc->end_sound) Save_SoundState(&tc->end_sound->activ_no); + +} \ No newline at end of file diff --git a/3dc/avp/track.h b/3dc/avp/track.h new file mode 100644 index 0000000..25b43b4 --- /dev/null +++ b/3dc/avp/track.h @@ -0,0 +1,117 @@ +#ifndef track_h +#define track_h 1 + +#ifdef __cplusplus +extern "C" { +#endif + +struct loaded_sound; + +typedef struct track_sound +{ + unsigned long inner_range; + unsigned long outer_range; + int max_volume; + int pitch; + + struct loaded_sound const * sound_loaded; + int activ_no; + int time_left; + + unsigned int loop:1; + unsigned int playing:1; //sound should be playing (if in range) + +} TRACK_SOUND; + +typedef struct track_section_data +{ + QUAT quat_start; //orientations of object relative to pivot + QUAT quat_end; + + VECTORCH pivot_start; //pivot start pos in world space + VECTORCH pivot_travel; + + VECTORCH object_offset; //from pivot + + int time_for_section; //time take for this section in fixed point seconds + + //preprocessed stuff + int omega; + int oneoversinomega; + int oneovertime; + + + + /* KJL 12:25:51 24/03/98 - quaternions added to handle spining of quaternions over track */ + QUAT quat_prev; + QUAT quat_start_control; + QUAT quat_end_control; + + /* KJL 12:25:37 24/03/98 - data points used to create a smooth curve from the 3d keyframes */ + VECTORCH pivot_0; + VECTORCH pivot_1; + VECTORCH pivot_2; + VECTORCH pivot_3; + +} TRACK_SECTION_DATA; + +typedef struct track_controller +{ + STRATEGYBLOCK* sbptr; + + int num_sections; + TRACK_SECTION_DATA* sections; + + int timer; + int speed_mult; + int current_section; + + TRACK_SOUND* sound; + TRACK_SOUND* start_sound; + TRACK_SOUND* end_sound; + + int initial_state_timer; //used by Reset_Track() + + unsigned int playing:1; + unsigned int reverse:1; + unsigned int no_rotation:1; + unsigned int loop:1; + unsigned int loop_backandforth:1; + unsigned int use_speed_mult:1; + unsigned int use_smoothing:1; + unsigned int playing_start_sound:1; + unsigned int initial_state_playing:1; //used by Reset_Track() + unsigned int initial_state_reverse:1; //used by Reset_Track() + + + +}TRACK_CONTROLLER; + +void Update_Track_Position_Only(TRACK_CONTROLLER* tc); //just moves track to correspond with current timer setting +void Update_Track_Position(TRACK_CONTROLLER* tc); +void Preprocess_Track_Controller(TRACK_CONTROLLER* tc); + +void Start_Track_Playing(TRACK_CONTROLLER* tc); +void Stop_Track_Playing(TRACK_CONTROLLER* tc); + +void Reset_Track(TRACK_CONTROLLER* tc); //called when restarting a level + +void Deallocate_Track(TRACK_CONTROLLER* tc); + +/*the track_sound stuff doesn't actually refer to the track directly , so +it can be used by other things*/ +void Start_Track_Sound(TRACK_SOUND* ts,VECTORCH * location); +void Stop_Track_Sound(TRACK_SOUND* ts); +void Update_Track_Sound(TRACK_SOUND* ts,VECTORCH * location); +void Deallocate_Track_Sound(TRACK_SOUND* ts); + +struct save_block_header; + +void LoadTrackPosition(struct save_block_header*,TRACK_CONTROLLER*); +void SaveTrackPosition(TRACK_CONTROLLER*); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/3dc/avp/vssver.scc b/3dc/avp/vssver.scc new file mode 100644 index 0000000..660b649 Binary files /dev/null and b/3dc/avp/vssver.scc differ diff --git a/3dc/avp/win95/AVPCHUNK.CPP b/3dc/avp/win95/AVPCHUNK.CPP new file mode 100644 index 0000000..fa43ac9 --- /dev/null +++ b/3dc/avp/win95/AVPCHUNK.CPP @@ -0,0 +1,951 @@ +#include "avpchunk.hpp" +#include "md5.h" +//#include "strachnk.hpp" +//#include "obchunk.hpp" + +#ifdef cencon +#define new my_new +#endif + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(avpchunk) + +RIF_IMPLEMENT_DYNCREATE("AVPGENER",AVP_Generator_Chunk) + +void AVP_Generator_Chunk::fill_data_block (char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((ChunkVectorInt *) data_start) = location; + data_start += sizeof(ChunkVectorInt); + + + *((int *) data_start) = orientation; + data_start += 4; + + *((int *) data_start) = type; + data_start += 4; + + *((int *) data_start) = flags; + data_start += 4; + + *(data_start) = textureID; + data_start ++; + + *(data_start) = sub_type; + data_start ++; + + *(data_start) = extra1; + data_start ++; + + *(data_start) = extra2; + data_start ++; + + strcpy (data_start, name); + +} + +size_t AVP_Generator_Chunk::size_chunk () +{ + chunk_size = 12 + 3 * 4 + 4 * 4 + strlen(name) + 4 - strlen(name)%4; + + return(chunk_size); + +} +#if UseOldChunkLoader +AVP_Generator_Chunk::AVP_Generator_Chunk (Chunk_With_Children * parent, const char * data, size_t /*size*/) +: Chunk (parent, "AVPGENER") +{ + location = *((ChunkVector *) data); + data += sizeof(ChunkVector); + + orientation = *((int *) data); + data += 4; + + type = *((int *) data); + data += 4; + + flags = *((int *) data); + data += 4; + + textureID = *(data); + data ++; + + sub_type = *(data); + data ++; + + extra1 = *(unsigned char*)(data); + data ++; + + extra2 = *(unsigned char*)(data); + data ++; + + name = new char [strlen(data) + 1]; + strcpy (name, data); +} +#else +AVP_Generator_Chunk::AVP_Generator_Chunk (Chunk_With_Children * parent, const char * data, size_t /*size*/) +: Chunk (parent, "AVPGENER") +{ + location = *((ChunkVectorInt*) data); + data += sizeof(ChunkVectorInt); + + orientation = *((int *) data); + data += 4; + + type = *((int *) data); + data += 4; + + flags = *((int *) data); + data += 4; + + textureID = *(data); + data ++; + + sub_type = *(data); + data ++; + + extra1 = *(unsigned char*)(data); + data ++; + + extra2 = *(unsigned char*)(data); + data ++; + + name = new char [strlen(data) + 1]; + strcpy (name, data); +} +#endif + + + +AVP_Generator_Chunk::~AVP_Generator_Chunk () +{ + if (name) + delete [] name; +} + + +ObjectID AVP_Generator_Chunk::CalculateID() +{ + ObjectID retval={0,0}; + + //get the environment_data_chunk + Chunk_With_Children* cwc=((Special_Objects_Chunk *)parent)->parent; + + List chlist; + cwc->lookup_child("RIFFNAME",chlist); + if(!chlist.size()) return retval; + char Name[100]; + + #if InterfaceEngine||cencon + //need to check for console specific rif files,and skip the 'sat' or 'psx' + //so that they get the same ids as the pc + const char* r_name=((RIF_Name_Chunk*)chlist.first_entry())->rif_name; + if(tolower(r_name[0])=='p' && tolower(r_name[1])=='s' && tolower(r_name[2])=='x' ) + strcpy(Name,&r_name[3]); + else if (tolower(r_name[0])=='s' && tolower(r_name[1])=='a' && tolower(r_name[2])=='t' ) + strcpy(Name,&r_name[3]); + else + strcpy(Name,r_name); + #else + strcpy(Name,((RIF_Name_Chunk*)chlist.first_entry())->rif_name); + #endif + + strcat(Name,name); + char buffer[16]; + md5_buffer(Name,strlen(Name),&buffer[0]); + buffer[7]=0; + retval = *(ObjectID*)&buffer[0]; + return retval; + +} + +AVP_Generator_Extra_Data_Chunk* AVP_Generator_Chunk::get_extra_data_chunk() +{ + List chlist; + parent->lookup_child("AVPGENEX",chlist); + if(!chlist.size())return 0; + + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + AVP_Generator_Extra_Data_Chunk* agedc=(AVP_Generator_Extra_Data_Chunk*)chlif(); + List chlist2; + agedc->lookup_child("AVPGENNM",chlist2); + if(chlist2.size()) + { + const char* ename=((AVP_Generator_Extra_Name_Chunk*)chlist2.first_entry())->name; + if(!strcmp(name,ename)) + { + return agedc; + } + } + } + //no extra data chunk found + return 0; + +} +AVP_Generator_Extra_Data_Chunk* AVP_Generator_Chunk::create_extra_data_chunk() +{ + AVP_Generator_Extra_Data_Chunk* agedc=get_extra_data_chunk(); + if(agedc)return agedc; + + return new AVP_Generator_Extra_Data_Chunk(parent,this); +} + +AVP_Generator_Extended_Settings_Chunk* AVP_Generator_Chunk::get_extended_settings() +{ + if(flags & AVPGENFLAG_ADVANCEDGENERATOR) + { + AVP_Generator_Extra_Data_Chunk* agedc=get_extra_data_chunk(); + if(!agedc) return 0; + return (AVP_Generator_Extended_Settings_Chunk*)agedc->lookup_single_child("GENEXSET"); + } + return 0; +} + +AVP_Generator_Extended_Settings_Chunk* AVP_Generator_Chunk::create_extended_settings() +{ + flags|=AVPGENFLAG_ADVANCEDGENERATOR; + AVP_Generator_Extra_Data_Chunk* agedc=create_extra_data_chunk(); + + AVP_Generator_Extended_Settings_Chunk* setting=(AVP_Generator_Extended_Settings_Chunk*)agedc->lookup_single_child("GENEXSET"); + if(setting) return setting; + + return new AVP_Generator_Extended_Settings_Chunk(agedc); +} + +Object_Alternate_Locations_Chunk* AVP_Generator_Chunk::get_alternate_locations_chunk() +{ + AVP_Generator_Extra_Data_Chunk* agedc=get_extra_data_chunk(); + if(!agedc) return 0; + return (Object_Alternate_Locations_Chunk*)agedc->lookup_single_child("ALTLOCAT"); +} + + +////////////////////////////////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("AVPGENEX",AVP_Generator_Extra_Data_Chunk) + +//loader for AVP_Generator_Extra_Data_Chunk +CHUNK_WITH_CHILDREN_LOADER("AVPGENEX",AVP_Generator_Extra_Data_Chunk) + +/* +children for AVP_Generator_Extra_Data_Chunk : + +"AVPSTRAT" AVP_Strategy_Chunk) +"AVPGENNM" AVP_Generator_Extra_Name_Chunk) +"R6GENDAT" Rainbow6_Generator_Extra_Data_Chunk) +"GENEXSET" AVP_Generator_Extended_Settings_Chunk) +"ALTLOCAT" Object_Alternate_Locations_Chunk) +*/ + + +AVP_Generator_Extra_Data_Chunk::AVP_Generator_Extra_Data_Chunk(Chunk_With_Children* parent,AVP_Generator_Chunk* agc) +:Chunk_With_Children(parent,"AVPGENEX") +{ + new AVP_Generator_Extra_Name_Chunk(this,agc->name); +} + +AVP_Generator_Chunk* AVP_Generator_Extra_Data_Chunk::get_generator_chunk() +{ + List chlist; + lookup_child("AVPGENNM",chlist); + if(!chlist.size()) return 0; + const char* name=((AVP_Generator_Extra_Name_Chunk*)chlist.first_entry())->name; + + parent->lookup_child("AVPGENER",chlist); + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + AVP_Generator_Chunk* agc=(AVP_Generator_Chunk*)chlif(); + if(!strcmp(agc->name,name)) + { + return agc; + } + } + //no generator chunk found + return 0; +} +////////////////////////////////////////////////////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("AVPGENNM",AVP_Generator_Extra_Name_Chunk) + +AVP_Generator_Extra_Name_Chunk::AVP_Generator_Extra_Name_Chunk(Chunk_With_Children * parent, const char * data, size_t /*size*/) +:Chunk(parent,"AVPGENNM") +{ + int length=strlen(data); + name=new char[length+1]; + strcpy(name,data); +} + +AVP_Generator_Extra_Name_Chunk::AVP_Generator_Extra_Name_Chunk(Chunk_With_Children * parent, const char * _name) +:Chunk(parent,"AVPGENNM") +{ + name=new char[strlen(_name)+1]; + strcpy(name,_name); +} + +AVP_Generator_Extra_Name_Chunk::~AVP_Generator_Extra_Name_Chunk() +{ + delete name; +} + +void AVP_Generator_Extra_Name_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + strcpy(data_start,name); +} + + +size_t AVP_Generator_Extra_Name_Chunk::size_chunk() +{ + chunk_size=12; + chunk_size+=(strlen(name)+4)&~3; + return chunk_size; +} + +////////////////////////////////////////////////////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("GENEXSET",AVP_Generator_Extended_Settings_Chunk) + +AVP_Generator_Extended_Settings_Chunk::AVP_Generator_Extended_Settings_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk(parent,"GENEXSET") +{ + CHUNK_EXTRACT(GenerationRate,int) + CHUNK_EXTRACT(GenRateIncrease,int) + CHUNK_EXTRACT(GenLimit,unsigned char) + CHUNK_EXTRACT(pad1,unsigned char) + CHUNK_EXTRACT(pad2,unsigned char) + CHUNK_EXTRACT(pad3,unsigned char) + CHUNK_EXTRACT(spare1,int) + CHUNK_EXTRACT(spare2,int) + + + size_t size=max(*(int*) data,sizeof(AVP_Generator_Weighting)); + + weights=(AVP_Generator_Weighting*)new unsigned char[size]; + memset(weights,0,sizeof(AVP_Generator_Weighting)); + memcpy(weights,data,*(int*) data); + + weights->data_size=size; +} + +AVP_Generator_Extended_Settings_Chunk::AVP_Generator_Extended_Settings_Chunk(Chunk_With_Children* parent) +:Chunk(parent,"GENEXSET") +{ + weights=new AVP_Generator_Weighting; + memset(weights,0,sizeof(AVP_Generator_Weighting)); + weights->data_size=sizeof(AVP_Generator_Weighting); + GenLimit=pad1=pad2=pad3=0; + spare1=spare2=0; + +} + + +AVP_Generator_Extended_Settings_Chunk::~AVP_Generator_Extended_Settings_Chunk() +{ + delete weights; +} + +void AVP_Generator_Extended_Settings_Chunk::fill_data_block (char * data) +{ + CHUNK_FILL_START + + CHUNK_FILL(GenerationRate,int) + CHUNK_FILL(GenRateIncrease,int) + CHUNK_FILL(GenLimit,unsigned char) + CHUNK_FILL(pad1,unsigned char) + CHUNK_FILL(pad2,unsigned char) + CHUNK_FILL(pad3,unsigned char) + CHUNK_FILL(spare1,int) + CHUNK_FILL(spare2,int) + + + memcpy(data,weights,weights->data_size); +} + +size_t AVP_Generator_Extended_Settings_Chunk::size_chunk () +{ + chunk_size = 12+20+weights->data_size; + return(chunk_size); + +} + + +////////////////////////////////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("GLOGENDC",Global_Generator_Data_Chunk) + +Global_Generator_Data_Chunk::Global_Generator_Data_Chunk(Chunk_With_Children* parent) +:Chunk(parent,"GLOGENDC") +{ + EnemyGenerated=Generate_Aliens; + MaxNPCSOnLevel=25; + NPCSPerMinute=4; + NPCAcceleration=2; + HiveStateChangeTime=60; + spare1=spare2=0; + +} +Global_Generator_Data_Chunk::Global_Generator_Data_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk(parent,"GLOGENDC") +{ + EnemyGenerated=*(int*)data; + data+=sizeof(int); + MaxNPCSOnLevel=*(int*)data; + data+=sizeof(int); + NPCSPerMinute=*(int*)data; + data+=sizeof(int); + NPCAcceleration=*(int*)data; + data+=sizeof(int); + HiveStateChangeTime=*(int*)data; + data+=sizeof(int); + + spare1=*(int*)data; + data+=sizeof(int); + spare2=*(int*)data; + data+=sizeof(int); + +} + +void Global_Generator_Data_Chunk::fill_data_block (char * data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + + *(int*)data_start=EnemyGenerated; + data_start+=4; + *(int*)data_start=MaxNPCSOnLevel; + data_start+=4; + *(int*)data_start=NPCSPerMinute; + data_start+=4; + *(int*)data_start=NPCAcceleration; + data_start+=4; + *(int*)data_start=HiveStateChangeTime; + data_start+=4; + + *(int*)data_start=spare1; + data_start+=4; + *(int*)data_start=spare2; + data_start+=4; +} + +size_t Global_Generator_Data_Chunk::size_chunk () +{ + chunk_size = 12+28; + + return(chunk_size); + +} +////////////////////////////////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("AVPSTART",AVP_Player_Start_Chunk) + +AVP_Player_Start_Chunk::AVP_Player_Start_Chunk(Chunk_With_Children* parent) +:Chunk(parent,"AVPSTART") +{ + location.x=location.y=location.z=0; + orientation.mat11=orientation.mat22=orientation.mat33=65536; + orientation.mat12=orientation.mat23=orientation.mat31=0; + orientation.mat21=orientation.mat32=orientation.mat13=0; + moduleID.id1=0; + moduleID.id2=0; + +} +#if UseOldChunkLoader +AVP_Player_Start_Chunk::AVP_Player_Start_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk(parent,"AVPSTART") +{ + location=*(ChunkVector*)data; + data+=sizeof(ChunkVector); + orientation=*(ChunkMatrix*)data; + data+=sizeof(ChunkMatrix); + spare1=*(int*)data; + data+=4; + spare2=*(int*)data; +} +#else +AVP_Player_Start_Chunk::AVP_Player_Start_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk(parent,"AVPSTART") +{ + CHUNK_EXTRACT(location,ChunkVectorInt) + CHUNK_EXTRACT(orientation,ChunkMatrix) + CHUNK_EXTRACT(moduleID,ObjectID) +} +#endif + +void AVP_Player_Start_Chunk::fill_data_block (char * data) +{ + CHUNK_FILL_START + + CHUNK_FILL(location,ChunkVectorInt) + CHUNK_FILL(orientation,ChunkMatrix) + CHUNK_FILL(moduleID,ObjectID) + +} + +size_t AVP_Player_Start_Chunk::size_chunk () +{ + chunk_size = 12+sizeof(ChunkVectorInt)+sizeof(ChunkMatrix)+sizeof(ObjectID); + + return(chunk_size); + +} +////////////////////////////////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("AVPCABLE",AVP_Power_Cable_Chunk) + +AVP_Power_Cable_Chunk::AVP_Power_Cable_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk (parent,"AVPCABLE") +{ + location=*(ChunkVectorInt*)data; + data+=sizeof(ChunkVectorInt); + + id=*(ObjectID*)data; + data+=sizeof(ObjectID); + + max_charge=*(int*)data; + data+=4; + + initial_charge=*(int*)data; + data+=4; + + recharge_rate=*(int*)data; + data+=4; + + flags=*(int*)data; + data+=4; + + for(int i=0;i<3;i++) + { + spare[i]=*(int*)data; + data+=4; + } + + int length=strlen(data); + if(length) + { + name=new char[length+1]; + strcpy(name,data); + } + else + { + name=0; + } +} + +AVP_Power_Cable_Chunk::AVP_Power_Cable_Chunk(Chunk_With_Children* parent,const char* _name,ObjectID _id) +:Chunk (parent,"AVPCABLE") +{ + location.x=location.y=location.z=0; + name=new char[strlen(_name)+1]; + strcpy(name,_name); + id=_id; + for(int i=0;i<3;i++) spare[i]=0; +} + +AVP_Power_Cable_Chunk::~AVP_Power_Cable_Chunk() +{ + if(name) delete name; +} + +void AVP_Power_Cable_Chunk::fill_data_block(char* data) +{ + strncpy (data, identifier, 8); + data += 8; + *((int *) data) = chunk_size; + data += 4; + + *(ChunkVectorInt*)data=location; + data+=sizeof(ChunkVectorInt); + + *(ObjectID*)data=id; + data+=sizeof(ObjectID); + + *(int*)data=max_charge; + data+=4; + + *(int*)data=initial_charge; + data+=4; + + *(int*)data=recharge_rate; + data+=4; + + *(int*)data=flags; + data+=4; + + + for(int i=0;i<3;i++) + { + *(int*)data=spare[i]; + data+=4; + } + + if(name) + { + strcpy(data,name); + } + else + { + *data=0; + } + +} +size_t AVP_Power_Cable_Chunk::size_chunk() +{ + chunk_size=(strlen(name)+4)&~3; + chunk_size+=12+sizeof(ChunkVectorInt)+sizeof(ObjectID)+28; + return chunk_size; +} + +////////////////////////////////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("AVPENVIR",AVP_Environment_Settings_Chunk) + + +AVP_Environment_Settings_Chunk::AVP_Environment_Settings_Chunk(Chunk_With_Children* parent,const char* data,size_t data_size) +:Chunk(parent,"AVPENVIR") +{ + size_t size=max(data_size,sizeof(AVP_Environment_Settings)); + + settings=(AVP_Environment_Settings*)new unsigned char[size]; + memcpy(settings,data,data_size); + + if(settings->data_size<16) + { + settings->sky_colour_red=200; + settings->sky_colour_green=200; + settings->sky_colour_blue=200; + } + if(settings->data_size<24) + { + settings->predator_pistol=1; + settings->predator_plasmacaster=1; + settings->predator_disc=1; + settings->predator_medicomp=1; + settings->predator_grappling_hook=0; + settings->predator_num_spears=30; + settings->marine_jetpack=0; + settings->stars_in_sky=0; + settings->spare_bits=0; + } + + settings->data_size=size; +} +AVP_Environment_Settings_Chunk::AVP_Environment_Settings_Chunk(Chunk_With_Children* parent) +:Chunk(parent,"AVPENVIR") +{ + settings=new AVP_Environment_Settings; + settings->data_size=sizeof(AVP_Environment_Settings); + settings->sky_colour_red=200; + settings->sky_colour_green=200; + settings->sky_colour_blue=200; + + settings->predator_pistol=1; + settings->predator_plasmacaster=1; + settings->predator_disc=1; + settings->predator_medicomp=1; + settings->predator_grappling_hook=0; + settings->predator_num_spears=30; + settings->marine_jetpack=0; + settings->stars_in_sky=0; + settings->spare_bits=0; + +} + + +AVP_Environment_Settings_Chunk::~AVP_Environment_Settings_Chunk() +{ + delete settings; +} + +void AVP_Environment_Settings_Chunk::fill_data_block (char * data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + memcpy(data_start,settings,settings->data_size); +} + +size_t AVP_Environment_Settings_Chunk::size_chunk () +{ + chunk_size = 12+settings->data_size; + return(chunk_size); + +} + +AVP_Environment_Settings_Chunk* GetAVPEnvironmentSettings(Environment_Data_Chunk* env_chunk) +{ + assert(env_chunk); + + AVP_Environment_Settings_Chunk* env_set=(AVP_Environment_Settings_Chunk*)env_chunk->lookup_single_child("AVPENVIR"); + if(!env_set) env_set=new AVP_Environment_Settings_Chunk(env_chunk); + + return env_set; +} +////////////////////////////////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("AVPDECAL",AVP_Decal_Chunk) + +AVP_Decal_Chunk::AVP_Decal_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk(parent,"AVPDECAL") +{ + num_decals=*(int*)data; + data+=4; + + int loaded_decal_size=*(int*)data; + data+=4; + + decal_size=max(loaded_decal_size,sizeof(AVP_Decal)); + + //allocate buffer for decals , and initialise to zero + decal_buffer=new char[num_decals*decal_size]; + memset(decal_buffer,0,num_decals*decal_size); + + char* buffer_ptr=decal_buffer; + for(int i=0;i>R6GENFLAG_BADDY_INDEX_SHIFT;} + void Set_Baddy_Index(int index) { flags&=~R6GENFLAG_BADDY_INDEX_MASK; flags |=(index< +#include +#include "avpreg.hpp" + +extern "C" +{ +char* AvpCDPath=0; +extern char const * SecondTex_Directory; +extern char * SecondSoundDir; + +void GetPathFromRegistry() +{ + HKEY hKey; + + if(AvpCDPath) + { + delete AvpCDPath; + AvpCDPath=0; + } + + if + ( + ERROR_SUCCESS == RegOpenKeyEx + ( + HKEY_LOCAL_MACHINE, + "Software\\Fox Interactive\\Aliens vs Predator\\1.00", + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, + &hKey + ) + ) + { + char szBuf[MAX_PATH+1]; + DWORD dwType = REG_NONE; + DWORD dwSize = sizeof szBuf; + + if + ( + ERROR_SUCCESS == RegQueryValueEx + ( + hKey, + const_cast("Source Path"), + 0, + &dwType, + reinterpret_cast(szBuf), + &dwSize + ) + && REG_SZ == dwType + ) + { + int length=strlen(szBuf); + if(length) + { + AvpCDPath=new char[length+1]; + strcpy(AvpCDPath,szBuf); + } + + } + + RegCloseKey(hKey); + } + + //now set second texture directory + if(!SecondTex_Directory) + { + char* directory; + if(AvpCDPath) + { + directory=new char[strlen(AvpCDPath)+10]; + sprintf(directory,"%sGraphics",AvpCDPath); + } + else + { + directory=new char[40]; + strcpy(directory,"\\\\bob\\textures\\avp_graphics"); + } + *(char**)&SecondTex_Directory=directory; + } + + //and the second sound directory + if(!SecondSoundDir) + { + char* directory; + if(AvpCDPath) + { + directory=new char[strlen(AvpCDPath)+20]; + sprintf(directory,"%ssound\\",AvpCDPath); + } + else + { + directory=new char[40]; + strcpy(directory,"\\\\bob\\vss\\avp\\sound\\"); + } + SecondSoundDir=directory; + } + + +} + +}; \ No newline at end of file diff --git a/3dc/avp/win95/AvpReg.hpp b/3dc/avp/win95/AvpReg.hpp new file mode 100644 index 0000000..d7f6762 --- /dev/null +++ b/3dc/avp/win95/AvpReg.hpp @@ -0,0 +1,17 @@ +#ifndef _avpreg_h +#define _avpreg_h 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + + +extern char* AvpCDPath; +void GetPathFromRegistry(); + + +#ifdef __cplusplus +}; +#endif +#endif \ No newline at end of file diff --git a/3dc/avp/win95/BMP2.H b/3dc/avp/win95/BMP2.H new file mode 100644 index 0000000..d5d60dc --- /dev/null +++ b/3dc/avp/win95/BMP2.H @@ -0,0 +1,164 @@ +/****************************************************************************\ +** Title: BMP.H ** +** Purpose: BMP Header file ** +** Version: 1.0 ** +** Date: October 1991 ** +** Author: James D. Murray, Anaheim, CA, USA ** +** ** +** This header file contains the structures for the three flavors of the ** +** BMP image file format (OS/2 1.x, WIndows 3.0, and OS/2 2.0). Each BMP ** +** file will contain a BMPINFO header followed by either a PMINFPHEAD, ** +** WININFOHEAD, or PM2INFOHEAD header. To simplify reading and writing ** +** BMP files the BMP file format structure defined in BMP.H contains ** +** structures for all three flavors of the BMP image file format. ** +** ** +** Copyright (C) 1991 Graphics Software Labs. All rights reserved. ** +\****************************************************************************/ +#ifndef BMP2_H +#define BMP2_H 1 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "datatype.h" /* Include the data type definitions */ + +#define COMPRESS_RGB 0L /* No compression */ +#define COMPRESS_RLE8 1L /* 8 bits per pixel compression */ +#define COMPRESS_RLE4 2L /* 4 bits per pixel compression */ +#define BMP_ID 0x4d42 /* BMP "magic" number */ + +#define LSN(value) ((value) & 0x0f) /* Least-significant nibble */ +#define MSN(value) (((value) & 0xf0) >> 4) /* Most-significant nibble */ + +/* +** BMP File Format Bitmap Header. +*/ +typedef struct _BmpInfo /* Offset Description */ +{ + WORD Type; /* 00h File Type Identifier */ + DWORD FileSize; /* 02h Size of File */ + WORD Reserved1; /* 06h Reserved (should be 0) */ + WORD Reserved2; /* 08h Reserved (should be 0) */ + DWORD Offset; /* 0Ah Offset to bitmap data */ +} BMPINFO; + +/* +** Presentation Manager (OS/2 1.x) Information Header Format. +*/ +typedef struct _PmInfoHeader /* Offset Description */ +{ + DWORD Size; /* 0Eh Size of Remianing Header */ + WORD Width; /* 12h Width of Bitmap in Pixels */ + WORD Height; /* 14h Height of Bitmap in Pixels */ + WORD Planes; /* 16h Number of Planes */ + WORD BitCount; /* 18h Color Bits Per Pixel */ +} PMINFOHEAD; + +/* +** Windows 3.x Information Header Format. +*/ +typedef struct _WinInfoHeader /* Offset Description */ +{ + DWORD Size; /* 0Eh Size of Remianing Header */ + DWORD Width; /* 12h Width of Bitmap in Pixels */ + DWORD Height; /* 16h Height of Bitmap in Pixels */ + WORD Planes; /* 1Ah Number of Planes */ + WORD BitCount; /* 1Ch Bits Per Pixel */ + DWORD Compression; /* 1Eh Compression Scheme (0=none) */ + DWORD SizeImage; /* 22h Size of bitmap in bytes */ + DWORD XPelsPerMeter; /* 26h Horz. Resolution in Pixels/Meter */ + DWORD YPelsPerMeter; /* 2Ah Vert. Resolution in Pixels/Meter */ + DWORD ClrUsed; /* 2Eh Number of Colors in Color Table */ + DWORD ClrImportant; /* 32h Number of Important Colors */ +} WININFOHEAD; + +/* +** Presentation Manager (OS/2 2.0) Information Header Format. +*/ +typedef struct _Pm2InfoHeader /* Offset Description */ +{ + DWORD Size; /* 0Eh Size of Info Header (always 64) */ + WORD Width; /* 12h Width of Bitmap in Pixels */ + WORD Height; /* 14h Height of Bitmap in Pixels */ + WORD Planes; /* 16h Number of Planes */ + WORD BitCount; /* 18h Color Bits Per Pixel */ + DWORD Compression; /* 1Ah Compression Scheme (0=none) */ + DWORD SizeImage; /* 1Eh Size of bitmap in bytes */ + DWORD XPelsPerMeter; /* 22h Horz. Resolution in Pixels/Meter */ + DWORD YPelsPerMeter; /* 26h Vert. Resolution in Pixels/Meter */ + DWORD ClrUsed; /* 2Ah Number of Colors in Color Table */ + DWORD ClrImportant; /* 2Eh Number of Important Colors */ + WORD Units; /* 32h Resolution Mesaurement Used */ + WORD Reserved; /* 34h Reserved FIelds (always 0) */ + WORD Recording; /* 36h Orientation of Bitmap */ + WORD Rendering; /* 38h Halftone Algorithm Used on Image */ + DWORD Size1; /* 3Ah Halftone Algorithm Data */ + DWORD Size2; /* 3Eh Halftone Algorithm Data */ + DWORD ColorEncoding; /* 42h Color Table Format (always 0) */ + DWORD Identifier; /* 46h Misc. Field for Application Use */ +} PM2INFOHEAD; + +/* +** Presentation Manager (OS/2) RGB Color Triple. +*/ +typedef struct _PmRgbTriple +{ + BYTE rgbBlue; /* Blue Intensity Value */ + BYTE rgbGreen; /* Green Intensity Value */ + BYTE rgbRed; /* Red Intensity Value */ +} PMRGBTRIPLE; + +/* +** Windows 3.x RGB Color Quadruple. +*/ +typedef struct _WinRgbQuad +{ + BYTE rgbBlue; /* Blue Intensity Value */ + BYTE rgbGreen; /* Green Intensity Value */ + BYTE rgbRed; /* Red Intensity Value */ + BYTE rgbReserved; /* Reserved (should be 0) */ +} WINRGBQUAD; + +/* +** OS/2 2.0 RGB Color Quadruple. +*/ +typedef struct _Pm2RgbQuad +{ + BYTE rgbBlue; /* Blue Intensity Value */ + BYTE rgbGreen; /* Green Intensity Value */ + BYTE rgbRed; /* Red Intensity Value */ + BYTE rgbReserved; /* Reserved (should be 0) */ +} PM2RGBQUAD; + + +/* +** Composite structure of the BMP image file format. +** +** This structure holds information for all three flavors of the BMP format. +*/ +typedef struct _BmpHeader +{ + BMPINFO Header; /* Bitmap Header */ + PMINFOHEAD PmInfo; /* OS/2 1.x Information Header */ + PMRGBTRIPLE *PmColorTable; /* OS/2 1.x Color Table */ + WININFOHEAD WinInfo; /* Windows 3 Information Header */ + WINRGBQUAD *WinColorTable; /* Windows 3 Color Table */ + PM2INFOHEAD Pm2Info; /* OS/2 2.0 Information Header */ + PM2RGBQUAD *Pm2ColorTable; /* OS/2 2.0 Color Table */ +} BMPHEADER2; + +/* +** Function prototypes +*/ +//SHORT ReadBmpHeader(BMPHEADER *, FILE *); +//VOID WriteBmpHeader(BMPHEADER *, FILE *); +//SHORT BmpEncodeScanLine(BYTE *, WORD, WORD, DWORD, FILE *); +//SHORT BmpDecodeScanLine(BYTE *, WORD, WORD, DWORD, FILE *); + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ + +#endif /* BMP2_H */ + diff --git a/3dc/avp/win95/CHEAT.C b/3dc/avp/win95/CHEAT.C new file mode 100644 index 0000000..5754594 --- /dev/null +++ b/3dc/avp/win95/CHEAT.C @@ -0,0 +1,176 @@ +/* KJL 11:24:31 03/21/97 - quick cheat mode stuff */ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "gameplat.h" + +#include "bh_types.h" +#include "krender.h" +#include "huddefs.h" +#include "language.h" +#include "cheat.h" +#include "weapons.h" +#include "gameflow.h" +#include "equipmnt.h" + +/* Extern for global keyboard buffer */ +extern unsigned char KeyboardInput[]; +extern void LoadAllWeapons(PLAYER_STATUS *playerStatusPtr); + + +void HandleCheatModes(void) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + #if 1 + playerStatusPtr->securityClearances = 0; + #else + /* KJL 16:28:54 05/11/97 - reveal map */ + if (KeyboardInput[KEY_F9]) + { + extern SCENE Global_Scene; + extern int ModuleArraySize; + MODULE **moduleList; + int i; + + moduleList = MainSceneArray[Global_Scene]->sm_marray; + + for(i = 0; i < ModuleArraySize; i++) + { + MODULE *modulePtr = moduleList[i]; + + if (modulePtr && modulePtr->m_mapptr) + { + modulePtr->m_flags |= m_flag_visible_on_map; + } + } + NewOnScreenMessage(GetTextString(TEXTSTRING_INGAME_CHEATACTIVATED)); + } + + +//#if !GAMEFLOW_ON +#if 0 + + /* give all security levels */ + if (KeyboardInput[KEY_F10]) + { + playerStatusPtr->securityClearances = 0xffffffff; + NewOnScreenMessage(GetTextString(TEXTSTRING_INGAME_CHEATACTIVATED)); + } + if (KeyboardInput[KEY_F5]) + { + playerStatusPtr->securityClearances = 0x3f; + NewOnScreenMessage(GetTextString(TEXTSTRING_INGAME_CHEATACTIVATED)); + } +#endif + + #if 1 + /* give all weapons & ammo */ + if((KeyboardInput[KEY_F11])) + { + } + #endif + /* give immortality */ + if (KeyboardInput[KEY_F12]) + { + if(AvP.Network==I_No_Network) + { + NewOnScreenMessage(GetTextString(TEXTSTRING_INGAME_CHEATACTIVATED)); + playerStatusPtr->IsImmortal = 1; + } + else + { + /* commit suicide */ + CauseDamageToObject(Player->ObStrategyBlock, &certainDeath, ONE_FIXED,NULL); + } + } + #endif +} + +void GiveAllWeaponsCheat(void) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + if(AvP.PlayerType == I_Marine) + { + int slot = MAX_NO_OF_WEAPON_SLOTS; + while(slot--) + { + PLAYER_WEAPON_DATA *wdPtr = &playerStatusPtr->WeaponSlot[slot]; + + //if (slot == WEAPON_PLASMAGUN || slot == WEAPON_SONICCANNON) continue; + + if (wdPtr->WeaponIDNumber==NULL_WEAPON) continue; + + if (wdPtr->Possessed==-1) continue; /* This weapon not allowed! */ + + wdPtr->Possessed=1; + + /* KJL 21:49:47 05/15/97 - give ammo for weapons, apart from + experimental weapons */ + if (slot<=WEAPON_SLOT_10) { + if (wdPtr->WeaponIDNumber==WEAPON_CUDGEL) { + wdPtr->PrimaryMagazinesRemaining=0; + } else { + wdPtr->PrimaryMagazinesRemaining=50; + } + } else wdPtr->PrimaryMagazinesRemaining=0; + + if (wdPtr->WeaponIDNumber==WEAPON_PULSERIFLE) { + wdPtr->SecondaryRoundsRemaining=(ONE_FIXED*99); + } + if (wdPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS) { + wdPtr->SecondaryMagazinesRemaining=50; + } + + + } + GrenadeLauncherData.StandardMagazinesRemaining=50; + GrenadeLauncherData.FlareMagazinesRemaining=50; + GrenadeLauncherData.ProximityMagazinesRemaining=50; + GrenadeLauncherData.FragmentationMagazinesRemaining=50; + + } else if (AvP.PlayerType==I_Predator) { + + int slot = MAX_NO_OF_WEAPON_SLOTS; + while(slot--) + { + PLAYER_WEAPON_DATA *wdPtr = &playerStatusPtr->WeaponSlot[slot]; + + //if (slot == WEAPON_PLASMAGUN || slot == WEAPON_SONICCANNON) continue; + + if (wdPtr->WeaponIDNumber==NULL_WEAPON) continue; + + if (wdPtr->Possessed==-1) continue; /* This weapon not allowed! */ + + if (wdPtr->WeaponIDNumber==WEAPON_PRED_RIFLE) { + wdPtr->PrimaryRoundsRemaining+=(ONE_FIXED*SPEARS_PER_PICKUP); + if (wdPtr->PrimaryRoundsRemaining>(ONE_FIXED*MAX_SPEARS)) { + wdPtr->PrimaryRoundsRemaining=(ONE_FIXED*MAX_SPEARS); + } + wdPtr->Possessed=1; + continue; + } + + if (wdPtr->WeaponIDNumber==WEAPON_PRED_DISC) { + wdPtr->PrimaryRoundsRemaining+=(ONE_FIXED); + if (wdPtr->PrimaryRoundsRemaining>(ONE_FIXED*99)) { + wdPtr->PrimaryRoundsRemaining=(ONE_FIXED*99); + } + wdPtr->Possessed=1; + continue; + } + + if (wdPtr->WeaponIDNumber==WEAPON_PRED_STAFF) { + continue; + } + + wdPtr->Possessed=1; + + } + } + LoadAllWeapons(playerStatusPtr); +} \ No newline at end of file diff --git a/3dc/avp/win95/CHEAT.H b/3dc/avp/win95/CHEAT.H new file mode 100644 index 0000000..842b904 --- /dev/null +++ b/3dc/avp/win95/CHEAT.H @@ -0,0 +1,2 @@ +extern void HandleCheatModes(void); +extern void GiveAllWeaponsCheat(void); diff --git a/3dc/avp/win95/Ddplat.cpp b/3dc/avp/win95/Ddplat.cpp new file mode 100644 index 0000000..d797eda --- /dev/null +++ b/3dc/avp/win95/Ddplat.cpp @@ -0,0 +1,1659 @@ +/*KJL************************************************************************************** +* ddplat.cpp - this contains all the display code for the HUD, menu screens and so forth. * +* * +**************************************************************************************KJL*/ +extern "C" { + +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "dxlog.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "gameplat.h" + +#include "equipmnt.h" + +#include "huddefs.h" +#include "hudgfx.h" + +#include "font.h" + +#include "kshape.h" +#include "krender.h" +#include "chnktexi.h" +#include "awTexLd.h" +#include "ffstdio.h" + + + +#include "d3d_hud.h" + +extern "C++" +{ +#include "r2base.h" +#include "indexfnt.hpp" + +#include "projload.hpp" // c++ header which ignores class definitions/member functions if __cplusplus is not defined ? +#include "chnkload.hpp" // c++ header which ignores class definitions/member functions if __cplusplus is not defined ? +#include "pcmenus.h" +}; + +#include "alt_tab.h" + +extern int ScanDrawMode; +extern int ZBufferMode; +extern int sine[],cosine[]; +extern IMAGEHEADER ImageHeaderArray[]; +int BackdropImage; +//#define UseLocalAssert Yes +//#include "ourasert.h" + + +int UsingDataBase = 0; + + + +/* HUD globals */ +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; +static int TrackerPolyBuffer[25]; +static int ScanlinePolyBuffer[25]; +static int MotionTrackerWidth; +static int MotionTrackerTextureSize; +static int MotionTrackerCentreY; +static int MotionTrackerCentreX; +static RECT MT_BarDestRect; +static int MT_BlipHeight; +static int MT_BlipWidth; +struct LittleMDescTag *MTLittleMPtr; +enum HUD_RES_ID HUDResolution; + +/* display co-ords, etc. */ +#include "hud_data.h" + + + +static struct DDGraphicTag PauseDDInfo; +static struct DDGraphicTag E3FontDDInfo; + + +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ +void PlatformSpecificInitMarineHUD(void); +void PlatformSpecificInitPredatorHUD(void); + +void PlatformSpecificExitingHUD(void); +void PlatformSpecificEnteringHUD(void); + +void BLTMotionTrackerToHUD(int scanLineSize); +void BLTMotionTrackerBlipToHUD(int x, int y, int brightness); + +static void BLTDigitToHUD(char digit, int x, int y, int font); + +void BLTGunSightToScreen(int screenX, int screenY, enum GUNSIGHT_SHAPE gunsightShape); +void BLTWeaponToHUD(PLAYER_WEAPON_DATA* weaponPtr); +int CueWeaponFrameFromSequence(struct WeaponFrameTag *weaponFramePtr, int timeOutCounter, int weaponIDNumber); + + + +void BLTPredatorOverlayToHUD(void); +void BLTPredatorNumericsToHUD(void); +static void BLTPredatorDigitToHUD(char digit, int x, int y, int font); + +void LoadDDGraphic(struct DDGraphicTag *DDGfxPtr, char *Filename); + + +static void DrawMotionTrackerPoly(void); +static void SetupScanlinePoly(char const *filenamePtr, int width); + + +extern void D3D_InitialiseMarineHUD(void); +extern void D3D_BLTMotionTrackerToHUD(int scanLineSize); +extern void D3D_BLTMotionTrackerBlipToHUD(int x, int y, int brightness); +extern void D3D_BLTDigitToHUD(char digit, int x, int y, int font); +extern void D3D_BLTGunSightToHUD(int screenX, int screenY, enum GUNSIGHT_SHAPE gunsightShape); + +extern void LoadCommonTextures(void); +/*KJL**************************************************************************************** +* F U N C T I O N S * +****************************************************************************************KJL*/ + + +/**************************************** +* SETTING UP THE HUD * +****************************************/ +void PlatformSpecificInitMarineHUD(void) +{ + if ((ScanDrawMode != ScanDrawDirectDraw) && (ZBufferOn==ZBufferMode)) + { + D3D_InitialiseMarineHUD(); + LoadCommonTextures(); +// ChromeImageNumber = CL_LoadImageOnce("Common\\chromelike.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE); + return; + } + + //SelectGenTexDirectory(ITI_TEXTURE); + + extern unsigned char *ScreenBuffer; + + /* set game mode: different, though for multiplayer game */ + if(AvP.Network==I_No_Network) + cl_pszGameMode = "marine"; + else + cl_pszGameMode = "multip"; + + // SetCurrentImageGroup(0); + + // load_rif("avp_huds\\marine.rif"); + + // copy_chunks_from_environment(0); + + /* load HUD gfx */ + int gfxID = NO_OF_MARINE_HUD_GFX; + if (ScreenDescriptorBlock.SDB_Width>=800) + { + HUDResolution = HUD_RES_HI; + /* load Medres gfx */ + while(gfxID--) + { + HUDDDInfo[gfxID].LPDDS = 0; // ensure 0 just in case one doesn't load and we try to delete it + LoadDDGraphic + ( + &HUDDDInfo[gfxID], + HiresMarineHUDGfxFilenamePtr[gfxID] + ); + } + + TrackerPolyBuffer[3] = CL_LoadImageOnce("trakHiRz",(ScanDrawDirectDraw == ScanDrawMode ? LIO_CHIMAGE : LIO_D3DTEXTURE)|LIO_TRANSPARENT|LIO_RIFFPATH|LIO_RESTORABLE); + MotionTrackerWidth = 244; + MotionTrackerTextureSize = 243<<16; + MTLittleMPtr = &HiresHUDLittleM; + + SetupScanlinePoly("scanhirz",MotionTrackerTextureSize); + + LoadDDGraphic(&E3FontDDInfo,"e3fontMR"); + } + else if (ScreenDescriptorBlock.SDB_Width>=640) + { + HUDResolution = HUD_RES_MED; + /* load Medres gfx */ + while(gfxID--) + { + HUDDDInfo[gfxID].LPDDS = 0; // ensure 0 just in case one doesn't load and we try to delete it + LoadDDGraphic + ( + &HUDDDInfo[gfxID], + MedresMarineHUDGfxFilenamePtr[gfxID] + ); + } + + TrackerPolyBuffer[3] = CL_LoadImageOnce("trakMdRz",(ScanDrawDirectDraw == ScanDrawMode ? LIO_CHIMAGE : LIO_D3DTEXTURE)|LIO_TRANSPARENT|LIO_RIFFPATH|LIO_RESTORABLE); + MotionTrackerWidth = 195; + MotionTrackerTextureSize = 194<<16; + MTLittleMPtr = &MedresHUDLittleM; + + SetupScanlinePoly("scanmdrz",MotionTrackerTextureSize); + + LoadDDGraphic(&E3FontDDInfo,"e3fontMR"); + } + else + { + HUDResolution = HUD_RES_LO; + + /* load lores gfx */ + while(gfxID--) + { + HUDDDInfo[gfxID].LPDDS = 0; // ensure 0 just in case one doesn't load and we try to delete it + LoadDDGraphic + ( + &HUDDDInfo[gfxID], + LoresMarineHUDGfxFilenamePtr[gfxID] + ); + } + TrackerPolyBuffer[3] = CL_LoadImageOnce("tracker",(ScanDrawDirectDraw == ScanDrawMode ? LIO_CHIMAGE : LIO_D3DTEXTURE)|LIO_TRANSPARENT|LIO_RIFFPATH|LIO_RESTORABLE); + MotionTrackerWidth = 97; + MotionTrackerTextureSize = 96<<16; + MTLittleMPtr = &LoresHUDLittleM; + + /* lores scanline slightly smaller than tracker... */ + SetupScanlinePoly("scan",MotionTrackerTextureSize-65536); + + LoadDDGraphic(&E3FontDDInfo,"e3font"); + } + + TrackerPolyBuffer[0] = I_2dTexturedPolygon; + TrackerPolyBuffer[2] = iflag_nolight|iflag_ignore0; + + ScanlinePolyBuffer[0] = I_2dTexturedPolygon; + ScanlinePolyBuffer[2] = iflag_nolight|iflag_ignore0; + + /* screen dest of blue bar under motion tracker */ + MT_BarDestRect.bottom = ScreenDescriptorBlock.SDB_Height-1; + MT_BarDestRect.top = MT_BarDestRect.bottom - HUDDDInfo[MARINE_HUD_GFX_BLUEBAR].SrcRect.bottom; + MT_BarDestRect.left = 0;//MotionTrackerWidth/4; + MT_BarDestRect.right = MT_BarDestRect.left + HUDDDInfo[MARINE_HUD_GFX_BLUEBAR].SrcRect.right; + + /* centre of motion tracker */ + MotionTrackerCentreY = MT_BarDestRect.top+1; + MotionTrackerCentreX = (MT_BarDestRect.left+MT_BarDestRect.right)/2; + + /* motion tracker blips */ + MT_BlipHeight = HUDDDInfo[MARINE_HUD_GFX_MOTIONTRACKERBLIP].SrcRect.bottom/5; + MT_BlipWidth = HUDDDInfo[MARINE_HUD_GFX_MOTIONTRACKERBLIP].SrcRect.right; + + + LoadDDGraphic(&PauseDDInfo,"paused"); +} + +void PlatformSpecificInitPredatorHUD(void) +{ + //SelectGenTexDirectory(ITI_TEXTURE); + /* set game mode: different, though for multiplayer game */ + if(AvP.Network==I_No_Network) + { + cl_pszGameMode = "predator"; + /* load in sfx */ + LoadCommonTextures(); + } + else + { + cl_pszGameMode = "multip"; + /* load in sfx */ + LoadCommonTextures(); + //load marine stuff as well + D3D_InitialiseMarineHUD(); + } + return; + + int gfxID = NO_OF_PREDATOR_HUD_GFX; + + if (ScreenDescriptorBlock.SDB_Width>=640) + { + HUDResolution = HUD_RES_MED; + /* load Medres gfx */ + while(gfxID--) + { + HUDDDInfo[gfxID].LPDDS = 0; // ensure 0 just in case one doesn't load and we try to delete it + LoadDDGraphic + ( + &HUDDDInfo[gfxID], + MedresPredatorHUDGfxFilenamePtr[gfxID] + ); + } + LoadDDGraphic(&E3FontDDInfo,"e3fontmr"); + } + else + { + /* load Lores gfx */ + int gfxID = NO_OF_PREDATOR_HUD_GFX; + while(gfxID--) + { + HUDDDInfo[gfxID].LPDDS = 0; // ensure 0 just in case one doesn't load and we try to delete it + LoadDDGraphic + ( + &HUDDDInfo[gfxID], + LoresPredatorHUDGfxFilenamePtr[gfxID] + ); + } + LoadDDGraphic(&E3FontDDInfo,"e3font"); + } + LoadDDGraphic(&PauseDDInfo,"paused"); +} + + +void PlatformSpecificInitAlienHUD(void) +{ + //SelectGenTexDirectory(ITI_TEXTURE); + /* set game mode: different, though for multiplayer game */ + if(AvP.Network==I_No_Network) + { + cl_pszGameMode = "alien"; + LoadCommonTextures(); + } + else + { + cl_pszGameMode = "multip"; + /* load in sfx */ + LoadCommonTextures(); + //load marine stuff as well + D3D_InitialiseMarineHUD(); + } + + return; + + int gfxID = NO_OF_ALIEN_HUD_GFX; + + if (ScreenDescriptorBlock.SDB_Width==640) + { + HUDResolution = HUD_RES_MED; + /* load Medres gfx */ + while(gfxID--) + { + HUDDDInfo[gfxID].LPDDS = 0; // ensure 0 just in case one doesn't load and we try to delete it + LoadDDGraphic + ( + &HUDDDInfo[gfxID], + MedresAlienHUDGfxFilenamePtr[gfxID] + ); + } + LoadDDGraphic(&E3FontDDInfo,"e3fontmr"); + } + else + { + HUDResolution = HUD_RES_LO; + + /* load lores gfx */ + while(gfxID--) + { + HUDDDInfo[gfxID].LPDDS = 0; // ensure 0 just in case one doesn't load and we try to delete it + LoadDDGraphic + ( + &HUDDDInfo[gfxID], + LoresAlienHUDGfxFilenamePtr[gfxID] + ); + } + LoadDDGraphic(&E3FontDDInfo,"e3font"); + } + LoadDDGraphic(&PauseDDInfo,"paused"); +} + + +/*JH 14/5/97***************************** +* KILLING THE HUD * +************************************JH**/ + + +void PlatformSpecificKillMarineHUD(void) +{ + int gfxID = NO_OF_MARINE_HUD_GFX; + + while(gfxID--) + { + if (HUDDDInfo[gfxID].hBackup) + { + ATRemoveSurface(HUDDDInfo[gfxID].LPDDS); + AwDestroyBackupTexture( HUDDDInfo[gfxID].hBackup ); + } + if (HUDDDInfo[gfxID].LPDDS) + HUDDDInfo[gfxID].LPDDS->Release(); + HUDDDInfo[gfxID].LPDDS = 0; + HUDDDInfo[gfxID].hBackup = 0; + } + + if (PauseDDInfo.hBackup) + { + ATRemoveSurface(PauseDDInfo.LPDDS); + AwDestroyBackupTexture( PauseDDInfo.hBackup ); + } + if (PauseDDInfo.LPDDS) + PauseDDInfo.LPDDS->Release(); + PauseDDInfo.LPDDS = 0; + PauseDDInfo.hBackup = 0; + + if (E3FontDDInfo.hBackup) + { + ATRemoveSurface(E3FontDDInfo.LPDDS); + AwDestroyBackupTexture( E3FontDDInfo.hBackup ); + } + if (E3FontDDInfo.LPDDS) + E3FontDDInfo.LPDDS->Release(); + E3FontDDInfo.LPDDS = 0; + E3FontDDInfo.hBackup = 0; +} + +void PlatformSpecificKillPredatorHUD(void) +{ + /* load HUD gfx */ + int gfxID = NO_OF_PREDATOR_HUD_GFX; + + while(gfxID--) + { + if (HUDDDInfo[gfxID].hBackup) + { + ATRemoveSurface(HUDDDInfo[gfxID].LPDDS); + AwDestroyBackupTexture( HUDDDInfo[gfxID].hBackup ); + } + if (HUDDDInfo[gfxID].LPDDS) + HUDDDInfo[gfxID].LPDDS->Release(); + HUDDDInfo[gfxID].LPDDS = 0; + HUDDDInfo[gfxID].hBackup = 0; + } + + if (PauseDDInfo.hBackup) + { + ATRemoveSurface(PauseDDInfo.LPDDS); + AwDestroyBackupTexture( PauseDDInfo.hBackup ); + } + if (PauseDDInfo.LPDDS) + PauseDDInfo.LPDDS->Release(); + PauseDDInfo.LPDDS = 0; + PauseDDInfo.hBackup = 0; + + if (E3FontDDInfo.hBackup) + { + ATRemoveSurface(E3FontDDInfo.LPDDS); + AwDestroyBackupTexture( E3FontDDInfo.hBackup ); + } + if (E3FontDDInfo.LPDDS) + E3FontDDInfo.LPDDS->Release(); + E3FontDDInfo.LPDDS = 0; + E3FontDDInfo.hBackup = 0; +} + + +void PlatformSpecificKillAlienHUD(void) +{ + int gfxID = NO_OF_ALIEN_HUD_GFX; + while(gfxID--) + { + if (HUDDDInfo[gfxID].hBackup) + { + ATRemoveSurface(HUDDDInfo[gfxID].LPDDS); + AwDestroyBackupTexture( HUDDDInfo[gfxID].hBackup ); + } + if (HUDDDInfo[gfxID].LPDDS) + HUDDDInfo[gfxID].LPDDS->Release(); + HUDDDInfo[gfxID].LPDDS = 0; + HUDDDInfo[gfxID].hBackup = 0; + } + + if (PauseDDInfo.hBackup) + { + ATRemoveSurface(PauseDDInfo.LPDDS); + AwDestroyBackupTexture( PauseDDInfo.hBackup ); + } + if (PauseDDInfo.LPDDS) + PauseDDInfo.LPDDS->Release(); + PauseDDInfo.LPDDS = 0; + PauseDDInfo.hBackup = 0; + + if (E3FontDDInfo.hBackup) + { + ATRemoveSurface(E3FontDDInfo.LPDDS); + AwDestroyBackupTexture( E3FontDDInfo.hBackup ); + } + if (E3FontDDInfo.LPDDS) + E3FontDDInfo.LPDDS->Release(); + E3FontDDInfo.LPDDS = 0; + E3FontDDInfo.hBackup = 0; +} + + +/*********************/ +/* RUNTIME HUD STUFF */ +/*********************/ + +void PlatformSpecificExitingHUD(void) +{ +#if 0 + /* KJL 11:37:19 06/14/97 - draw whatever is in the execute buffer */ + if (ScanDrawMode != ScanDrawDirectDraw) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + EndD3DScene(); + } +#endif +} + +void PlatformSpecificEnteringHUD(void) +{ + /* JH 13/5/97 */ + /* Flush the ZBuffer so the weapons don't sink into the wall! */ + #if SupportZBuffering + if ((ScanDrawMode != ScanDrawDirectDraw) && (ZBufferMode != ZBufferOff)) + { + // FlushD3DZBuffer(); + } + #endif + +#if 0 + /* KJL 11:37:49 06/14/97 - reinit execute buffer */ + if (ScanDrawMode != ScanDrawDirectDraw) + { + BeginD3DScene(); + LockExecuteBuffer(); + } +#endif +} + +/*KJL********************** +* MARINE DRAWING ROUTINES * +**********************KJL*/ +void BLTMotionTrackerToHUD(int scanLineSize) +{ + // if (VideoModeType_8 != VideoModeTypeScreen) return; + if ((ScanDrawMode != ScanDrawDirectDraw) && (ZBufferOn==ZBufferMode)) + { + D3D_BLTMotionTrackerToHUD(scanLineSize); + } + return; + +} + +void BLTMotionTrackerBlipToHUD(int x, int y, int brightness) +{ + if ((ScanDrawMode != ScanDrawDirectDraw) && (ZBufferOn==ZBufferMode)) + { + D3D_BLTMotionTrackerBlipToHUD(x,y,brightness); + } + return; + +} + + +/*KJL******************* +* Draw numerics to HUD * +*******************KJL*/ +extern void BLTMarineNumericsToHUD(enum MARINE_HUD_DIGIT digitsToDraw) +{ + int digit = digitsToDraw; + struct DigitPropertiesTag *propertiesPtr; + + + if (HUDResolution == HUD_RES_LO) + { + propertiesPtr = &LoresMarineHUDDigitProperties[digit]; + } + else if (HUDResolution == HUD_RES_MED) + { + propertiesPtr = &MedresMarineHUDDigitProperties[digit]; + } + else + { + propertiesPtr = &HiresMarineHUDDigitProperties[digit]; + } + + do + { + /* paranoia check */ + LOCALASSERT(ValueOfHUDDigit[digit]>=0 && ValueOfHUDDigit[digit]<=9); + + if ((ScanDrawMode != ScanDrawDirectDraw) && (ZBufferOn==ZBufferMode)) + { + D3D_BLTDigitToHUD + ( + ValueOfHUDDigit[digit], + propertiesPtr->X, + propertiesPtr->Y, + propertiesPtr->Font + ); + } + propertiesPtr--; + } + while(digit--); +} +static void BLTDigitToHUD(char digit, int x, int y, int font) +{ + HRESULT ddrval; + struct HUDFontDescTag *FontDescPtr; + RECT srcRect; + int gfxID; + + switch (font) + { + case MARINE_HUD_FONT_MT_SMALL: + case MARINE_HUD_FONT_MT_BIG: + { + gfxID = MARINE_HUD_GFX_TRACKERFONT; + y+=MotionTrackerCentreY; + x+=MotionTrackerCentreX; + break; + } + case MARINE_HUD_FONT_RED: + case MARINE_HUD_FONT_BLUE: + { + if (x<0) x+=ScreenDescriptorBlock.SDB_Width; + gfxID = MARINE_HUD_GFX_NUMERALS; + break; + } + case ALIEN_HUD_FONT: + { + gfxID = ALIEN_HUD_GFX_NUMBERS; + break; + } + default: + LOCALASSERT(0); + break; + } + + + if (HUDResolution == HUD_RES_LO) + { + FontDescPtr = &LoresHUDFontDesc[font]; + } + else if (HUDResolution == HUD_RES_MED) + { + FontDescPtr = &MedresHUDFontDesc[font]; + } + else + { + FontDescPtr = &HiresHUDFontDesc[font]; + } + + srcRect.top = digit*FontDescPtr->Height; + srcRect.bottom =srcRect.top + FontDescPtr->Height; + srcRect.left = FontDescPtr->XOffset; + srcRect.right = srcRect.left + FontDescPtr->Width; + + ddrval = lpDDSBack->BltFast + ( + x,y, + HUDDDInfo[gfxID].LPDDS, + &srcRect, + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + + if(ddrval != DD_OK) + { + ReleaseDirect3D(); + exit(0x666004); + } +} + + + +void BLTGunSightToScreen(int screenX, int screenY, enum GUNSIGHT_SHAPE gunsightShape) +{ + if ((ScanDrawMode != ScanDrawDirectDraw) && (ZBufferOn==ZBufferMode)) + { + D3D_BLTGunSightToHUD(screenX,screenY,gunsightShape); + return; + } +} + +/*KJL************************ +* PREDATOR DRAWING ROUTINES * +************************KJL*/ +void BLTPredatorOverlayToHUD(void) +{ + /* KJL 11:37:19 06/14/97 - draw whatever is in the execute buffer */ + if (ScanDrawMode != ScanDrawDirectDraw) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + EndD3DScene(); + } + + HRESULT ddrval; + if ((ScreenDescriptorBlock.SDB_Height ==200) ||(ScreenDescriptorBlock.SDB_Width ==320) ) + { + ddrval = lpDDSBack->BltFast + ( + 0, + 13, + HUDDDInfo[PREDATOR_HUD_GFX_TOP].LPDDS, + &(HUDDDInfo[PREDATOR_HUD_GFX_TOP].SrcRect), + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + ddrval = lpDDSBack->BltFast + ( + 0, + 136, + HUDDDInfo[PREDATOR_HUD_GFX_BOTTOM].LPDDS, + &(HUDDDInfo[PREDATOR_HUD_GFX_BOTTOM].SrcRect), + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + } + else if ((ScreenDescriptorBlock.SDB_Height ==480) ||(ScreenDescriptorBlock.SDB_Width ==640) ) + { + ddrval = lpDDSBack->BltFast + ( + 1, + 13*2, + HUDDDInfo[PREDATOR_HUD_GFX_TOP].LPDDS, + &(HUDDDInfo[PREDATOR_HUD_GFX_TOP].SrcRect), + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + ddrval = lpDDSBack->BltFast + ( + 1, + 136*2+80, + HUDDDInfo[PREDATOR_HUD_GFX_BOTTOM].LPDDS, + &(HUDDDInfo[PREDATOR_HUD_GFX_BOTTOM].SrcRect), + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + } +} +void BLTPredatorNumericsToHUD(void) +{ + int digit = MAX_NO_OF_PREDATOR_HUD_DIGITS; + + struct DigitPropertiesTag *propertiesPtr; + + if (HUDResolution == HUD_RES_LO) + { + propertiesPtr = &LoresPredatorHUDDigitProperties[digit]; + } + else + { + propertiesPtr = &MedresPredatorHUDDigitProperties[digit]; + } + + while(digit) + { + digit--; + propertiesPtr--; + /* paranoia check */ + LOCALASSERT(ValueOfHUDDigit[digit]>=0 && ValueOfHUDDigit[digit]<=9); + + BLTPredatorDigitToHUD + ( + ValueOfHUDDigit[digit], + propertiesPtr->X, + propertiesPtr->Y, + propertiesPtr->Font + ); + } +} +static void BLTPredatorDigitToHUD(char digit, int x, int y, int font) +{ + HRESULT ddrval; + RECT srcRect; + + srcRect.top = digit*12; + srcRect.bottom = digit*12+12; + + srcRect.left = 0; + srcRect.right = HUDDDInfo[font].SrcRect.right; + + ddrval = lpDDSBack->BltFast + ( + x, + y, + HUDDDInfo[font].LPDDS, + &srcRect, + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + + if(ddrval != DD_OK) + { + ReleaseDirect3D(); + exit(0x666004); + } + +} + +/*KJL********************* +* ALIEN DRAWING ROUTINES * +*********************KJL*/ +extern void BLTAlienOverlayToHUD(void) +{ + /* KJL 11:37:19 06/14/97 - draw whatever is in the execute buffer */ + if (ScanDrawMode != ScanDrawDirectDraw) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + EndD3DScene(); + } + + /* KJL 10:24:49 7/17/97 - no overlay, please */ + return; + + HRESULT ddrval; + if ((ScreenDescriptorBlock.SDB_Height ==200)&&(ScreenDescriptorBlock.SDB_Width ==320)) + { + ddrval = lpDDSBack->BltFast + ( + 0, + 0, + HUDDDInfo[ALIEN_HUD_GFX_TOP].LPDDS, + &(HUDDDInfo[ALIEN_HUD_GFX_TOP].SrcRect), + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + ddrval = lpDDSBack->BltFast + ( + 0, + 25, + HUDDDInfo[ALIEN_HUD_GFX_LEFT].LPDDS, + &(HUDDDInfo[ALIEN_HUD_GFX_LEFT].SrcRect), + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + ddrval = lpDDSBack->BltFast + ( + 320-48, + 25, + HUDDDInfo[ALIEN_HUD_GFX_RIGHT].LPDDS, + &(HUDDDInfo[ALIEN_HUD_GFX_RIGHT].SrcRect), + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + ddrval = lpDDSBack->BltFast + ( + 0, + 160, + HUDDDInfo[ALIEN_HUD_GFX_BOTTOM].LPDDS, + &(HUDDDInfo[ALIEN_HUD_GFX_BOTTOM].SrcRect), + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + } + else if ((ScreenDescriptorBlock.SDB_Height ==480)&&(ScreenDescriptorBlock.SDB_Width ==640)) + { + ddrval = lpDDSBack->BltFast + ( + 0, + 0, + HUDDDInfo[ALIEN_HUD_GFX_TOP].LPDDS, + &(HUDDDInfo[ALIEN_HUD_GFX_TOP].SrcRect), + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + ddrval = lpDDSBack->BltFast + ( + 0, + 52, + HUDDDInfo[ALIEN_HUD_GFX_LEFT].LPDDS, + &(HUDDDInfo[ALIEN_HUD_GFX_LEFT].SrcRect), + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + ddrval = lpDDSBack->BltFast + ( + 640-97, + 52, + HUDDDInfo[ALIEN_HUD_GFX_RIGHT].LPDDS, + &(HUDDDInfo[ALIEN_HUD_GFX_RIGHT].SrcRect), + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + ddrval = lpDDSBack->BltFast + ( + 0, + 480-97, + HUDDDInfo[ALIEN_HUD_GFX_BOTTOM].LPDDS, + &(HUDDDInfo[ALIEN_HUD_GFX_BOTTOM].SrcRect), + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + } + +} +void BLTAlienNumericsToHUD(void) +{ + + if ((ScreenDescriptorBlock.SDB_Height ==200)&&(ScreenDescriptorBlock.SDB_Width ==320)) + { + int digit = MAX_NO_OF_ALIEN_HUD_DIGITS; + + while(digit) + { + digit--; + /* paranoia check */ + LOCALASSERT(ValueOfHUDDigit[digit]>=0 && ValueOfHUDDigit[digit]<=9); + + BLTDigitToHUD + ( + ValueOfHUDDigit[digit], + LoresAlienHUDDigitProperties[digit].X, + LoresAlienHUDDigitProperties[digit].Y, + LoresAlienHUDDigitProperties[digit].Font + ); + } + } + else if ((ScreenDescriptorBlock.SDB_Height ==480)&&(ScreenDescriptorBlock.SDB_Width ==640)) + { + int digit = MAX_NO_OF_ALIEN_HUD_DIGITS; + + while(digit) + { + digit--; + /* paranoia check */ + LOCALASSERT(ValueOfHUDDigit[digit]>=0 && ValueOfHUDDigit[digit]<=9); + + BLTDigitToHUD + ( + ValueOfHUDDigit[digit], + MedresAlienHUDDigitProperties[digit].X, + MedresAlienHUDDigitProperties[digit].Y, + MedresAlienHUDDigitProperties[digit].Font + ); + } + } +} + + + + +void BLTPausedToScreen(void) +{ + lpDDSBack->BltFast + ( + (ScreenDescriptorBlock.SDB_Width-PauseDDInfo.SrcRect.right)/2, + (ScreenDescriptorBlock.SDB_Height-PauseDDInfo.SrcRect.bottom)/2, + PauseDDInfo.LPDDS, + &(PauseDDInfo.SrcRect), + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + +} + + + +void LoadDDGraphic(struct DDGraphicTag *DDGfxPtr, char *Filename) +{ + /* + set up the direct draw surface. we can take the width and height + from the imageheader image + */ + + GLOBALASSERT(DDGfxPtr); + GLOBALASSERT(Filename); + + // get the filename that we need + char szAbsFileName[MAX_PATH]; + char * pszRet = CL_GetImageFileName(szAbsFileName,sizeof szAbsFileName / sizeof szAbsFileName[0], Filename, LIO_DDSURFACE|LIO_SYSMEM|LIO_TRANSPARENT|LIO_CHROMAKEY|LIO_RIFFPATH|LIO_RESTORABLE); + GLOBALASSERT(pszRet); + + // we'll put the width and height in here + unsigned nWidth, nHeight; + + // is it in a fast file? + unsigned nFastFileLen; + void const * pFastFileData = ffreadbuf(szAbsFileName,&nFastFileLen); + + if (pFastFileData) + { + DDGfxPtr->LPDDS = + AwCreateSurface + ( + "pxfXYB", + pFastFileData, + nFastFileLen, + AW_TLF_TRANSP|AW_TLF_CHROMAKEY, + &nWidth, + &nHeight, + &DDGfxPtr->hBackup + ); + } + else + { + DDGfxPtr->LPDDS = + AwCreateSurface + ( + "sfXYB", + &szAbsFileName[0], + AW_TLF_TRANSP|AW_TLF_CHROMAKEY, + &nWidth, + &nHeight, + &DDGfxPtr->hBackup + ); + } + + GLOBALASSERT(DDGfxPtr->LPDDS); + GLOBALASSERT(DDGfxPtr->hBackup); + ATIncludeSurface(DDGfxPtr->LPDDS,DDGfxPtr->hBackup); + + // set the rectangle size for blitting before padding to 4x4 has been done + DDGfxPtr->SrcRect.left = 0; + DDGfxPtr->SrcRect.right = nWidth; + DDGfxPtr->SrcRect.top = 0; + DDGfxPtr->SrcRect.bottom = nHeight; + + /*move the width and height to four byte bounadries*/ + + GLOBALASSERT((DDGfxPtr->SrcRect.right > 0)); + GLOBALASSERT((DDGfxPtr->SrcRect.bottom > 0)); +} + + +/* JH 3/6/97 functions to remove dd surfaces from hud graphics + so that the video mode can be completely changed, + but then everything can still be restored */ +/* perhaps not a final solution since it will be occupying memory */ + +void MinimizeAllDDGraphics(void) +{ + /* do all in array - don't care how many actually are used + because the array is static (hence initially filled with zeros) + The release functions should replace with NULL a pointer + that is no longer valid */ + + int gfxID = sizeof HUDDDInfo / sizeof (DDGraphicTag); // number of DDGraphicTags in array + + while(gfxID--) + { + if (HUDDDInfo[gfxID].LPDDS) + { + ATRemoveSurface(HUDDDInfo[gfxID].LPDDS); + HUDDDInfo[gfxID].LPDDS->Release(); + HUDDDInfo[gfxID].LPDDS = 0; + } + } + + if (PauseDDInfo.LPDDS) + { + ATRemoveSurface(PauseDDInfo.LPDDS); + PauseDDInfo.LPDDS->Release(); + PauseDDInfo.LPDDS = 0; + } + + if (E3FontDDInfo.LPDDS) + { + ATRemoveSurface(E3FontDDInfo.LPDDS); + E3FontDDInfo.LPDDS->Release(); + E3FontDDInfo.LPDDS = 0; + } +} + +void RestoreAllDDGraphics(void) +{ + /* do all in array - don't care how many actually are used + because the array is static (hence initially filled with zeros) + The release functions should replace with NULL a pointer + that is no longer valid */ + + int gfxID = sizeof HUDDDInfo / sizeof (DDGraphicTag); // number of DDGraphicTags in array + + while(gfxID--) + { + if (HUDDDInfo[gfxID].hBackup) + { + HUDDDInfo[gfxID].LPDDS = AwCreateSurface("rf",HUDDDInfo[gfxID].hBackup,AW_TLF_PREVSRC|AW_TLF_CHROMAKEY); + GLOBALASSERT(HUDDDInfo[gfxID].LPDDS); + ATIncludeSurface(HUDDDInfo[gfxID].LPDDS,HUDDDInfo[gfxID].hBackup); + } + } + + if (PauseDDInfo.hBackup) + { + PauseDDInfo.LPDDS = AwCreateSurface("rf",PauseDDInfo.hBackup,AW_TLF_PREVSRC|AW_TLF_CHROMAKEY); + GLOBALASSERT(PauseDDInfo.LPDDS); + ATIncludeSurface(PauseDDInfo.LPDDS,PauseDDInfo.hBackup); + } + + if (E3FontDDInfo.hBackup) + { + E3FontDDInfo.LPDDS = AwCreateSurface("rf",E3FontDDInfo.hBackup,AW_TLF_PREVSRC|AW_TLF_CHROMAKEY); + GLOBALASSERT(E3FontDDInfo.LPDDS); + ATIncludeSurface(E3FontDDInfo.LPDDS,E3FontDDInfo.hBackup); + } +} + + +void ReleaseHUDGraphic(HUDGRAPHIC* hgptr) +{ + GLOBALASSERT(hgptr); + GLOBALASSERT(hgptr->data); + ReleaseDDSurface((void*)(*(int*)hgptr->data)); +} + + + +/* + Windows externs. See win_func +*/ + + +void BLTGraphicToScreen(HUDGRAPHIC* hgptr) +{ + /* + sets up the drawing of general hud graphics. Bltted + to full screen if there is no width and heiht information in + the DD HUDGRAPHIC + */ + + RECT destRect; + + GLOBALASSERT(hgptr != NULL); + + GLOBALASSERT(1 > 0); + + HRESULT ddrval; + + LPDIRECTDRAWSURFACE wdds = *((LPDIRECTDRAWSURFACE*)hgptr->data); + + GLOBALASSERT(hgptr->srcRect->top < hgptr->srcRect->bottom); + GLOBALASSERT(hgptr->srcRect->left < hgptr->srcRect->right); + +#if 0 + textprint("%d TOP %d BOTTOM\n", hgptr->srcRect->top , hgptr->srcRect->bottom); + textprint("%d LEFT %d RIGHT\n", hgptr->srcRect->left , hgptr->srcRect->right); + + textprint("/n%d TOP %d BOTTOM\n", screenRect.top , screenRect.bottom); + textprint("%d LEFT %d RIGHT\n", screenRect.left , screenRect.right); + + WaitForReturn(); +#endif + + + if((hgptr->width == 0) || (hgptr->height == 0)) + { + ddrval = lpDDSBack->Blt(NULL, wdds, hgptr->srcRect, DDBLT_WAIT, NULL); + } + else + { + /* fill in the structure for the dest rect*/ + + destRect.top = hgptr->ydest; + destRect.bottom = hgptr->ydest + hgptr->height; + + destRect.left = hgptr->xdest; + destRect.right = hgptr->xdest + hgptr->width; + + ddrval = lpDDSBack->Blt(&destRect, wdds, hgptr->srcRect, DDBLT_WAIT, NULL); + + } + + if(ddrval != DD_OK) + { + ReleaseDirect3D(); + exit(0x666009); + } + +} + + + + + +/************************** FONTS *************************/ +/**********************************************************/ +/**********************************************************/ + +//static int BLTFontCharToHUD(PFFONT* font , int xdest, int ydest, char todraw); + +LPDIRECTDRAWSURFACE FontLPDDS[NUM_FONTS]; + +PFFONT AvpFonts[] = +{ + { + FontLPDDS[0], + "menufont.bmp", + 18, // font height + 118, // num chars + I_FONT_UCLC_NUMERIC, + {0} //flags + + }, + { + FontLPDDS[1], + "Common\\fontdark.RIM", + 14, // font height + 59, // num chars + I_FONT_UC_NUMERIC + }, + { + FontLPDDS[2], + "Common\\fontlite.RIM", + 14, // font height + 59, // num chars + I_FONT_UC_NUMERIC + }, + { + FontLPDDS[3], + "Common\\dbfont.RIM", + 11, // font height + 59, // num chars + I_FONT_UC_NUMERIC + }, + +}; + +extern int VideoModeColourDepth; + +void LoadFont(PFFONT *pffont) +{ + GLOBALASSERT(pffont); + GLOBALASSERT(pffont->filename); + + // get the filename that we need + char szAbsFileName[MAX_PATH]; + char * pszRet = CL_GetImageFileName(szAbsFileName,sizeof szAbsFileName / sizeof szAbsFileName[0], pffont->filename, LIO_DDSURFACE|LIO_SYSMEM|LIO_CHROMAKEY|LIO_TRANSPARENT + // hack for the moment so that the menu font is correctly loaded into an 8-bit vid mode + |(strchr(pffont->filename,'\\') ? LIO_RELATIVEPATH : LIO_RIFFPATH)); + GLOBALASSERT(pszRet); + + + // we'll put the width and height in here + unsigned nWidth, nHeight; + + // is it in a fast file? + unsigned nFastFileLen; + void const * pFastFileData = ffreadbuf(szAbsFileName,&nFastFileLen); + + if (pFastFileData) + { + pffont->data = + AwCreateSurface + ( + "pxfXYB", + pFastFileData, + nFastFileLen, + AW_TLF_TRANSP|AW_TLF_CHROMAKEY, + &nWidth, + &nHeight, + &pffont->hBackup + ); + } + else + { + pffont->data = + AwCreateSurface + ( + "sfXYB", + &szAbsFileName[0], + AW_TLF_TRANSP|AW_TLF_CHROMAKEY, + &nWidth, + &nHeight, + &pffont->hBackup + ); + } + + GLOBALASSERT(pffont->data); + GLOBALASSERT(pffont->hBackup); + + ATIncludeSurface(pffont->data,pffont->hBackup); + + pffont->fttexBitDepth = VideoModeColourDepth; + + pffont->fttexWidth = nWidth; + pffont->fttexHeight = nHeight; + + GLOBALASSERT((nHeight > 0)); + GLOBALASSERT((nWidth > 0)); + + pffont->flags.loaded = 1; +} + + +void * FontLock(PFFONT const * pFont, unsigned * pPitch) +{ + GLOBALASSERT(pFont); + GLOBALASSERT(pFont->data); + + DDSURFACEDESC ddsd; + memset(&ddsd,0,sizeof ddsd); + ddsd.dwSize = sizeof ddsd; + HRESULT hResult = pFont->data->Lock(NULL,&ddsd,DDLOCK_NOSYSLOCK,NULL); + GLOBALASSERT(DD_OK == hResult); + + *pPitch = ddsd.lPitch; + return ddsd.lpSurface; +} + +void FontUnlock(PFFONT const * pFont) +{ + GLOBALASSERT(pFont); + GLOBALASSERT(pFont->data); + + HRESULT hResult = pFont->data->Unlock(NULL); + GLOBALASSERT(DD_OK == hResult); +} + + +void UnloadFont(PFFONT *pffont) +{ + GLOBALASSERT(pffont); + + if (pffont->hBackup) + { + ATRemoveSurface(pffont->data); + AwDestroyBackupTexture(pffont->hBackup); + pffont->hBackup = NULL; + } + + if(pffont->data) + { + ReleaseDDSurface(pffont->data); + pffont->data = NULL; + } + + IndexedFont_Proportional_PF :: PFUnLoadHook + ( + (FontIndex) + ( + (pffont - &AvpFonts[0]) / sizeof(PFFONT) + ) + // FontIndex I_Font_Old, + // very ugly way to get at the index + ); +} + + +void FillCharacterSlot(int u, int v, + int width, int height, + int charnum, PFFONT* font) + +{ + + /* + simply set the srcRect.top to null in order to tell the drawing easily that + this char dosn't exist + */ + + GLOBALASSERT(width > -1); + GLOBALASSERT(height > -1); + GLOBALASSERT(u > -1); + GLOBALASSERT(v > -1); + + GLOBALASSERT(font); + GLOBALASSERT(charnum < font->num_chars_in_font); + font->srcRect[charnum].left = u; + font->srcRect[charnum].right = u + width; + font->srcRect[charnum].top = v; + font->srcRect[charnum].bottom = v + height; +} + + + +int BLTFontOffsetToHUD(PFFONT* font , int xdest, int ydest, int offset) +{ + HRESULT ddrval; + + RECT *rect = &(font->srcRect[offset]); + + if(rect->right - rect->left <= 0) + return 0; + + if(rect->bottom - rect->top <= 0) + return(rect->right - rect->left + 1); + + + ddrval = lpDDSBack->BltFast(xdest, ydest, font->data, rect, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); + + LOGDXERR(ddrval); + + if(ddrval != DD_OK) + { + LOGDXERR(ddrval); + GLOBALASSERT(0); + finiObjects(); + exit(ddrval); + } + + return(font->srcRect[offset].right - font->srcRect[offset].left); +} + + + + + + + + + +#if 1 +void YClipMotionTrackerVertices(struct VertexTag *v1, struct VertexTag *v2); +void XClipMotionTrackerVertices(struct VertexTag *v1, struct VertexTag *v2); + +static void DrawMotionTrackerPoly(void) +{ + struct VertexTag vertex[4]; + int widthCos,widthSin; + + { + int angle = 4095 - Player->ObEuler.EulerY; + + widthCos = MUL_FIXED + ( + MotionTrackerWidth, + GetCos(angle) + ); + widthSin = MUL_FIXED + ( + MotionTrackerWidth, + GetSin(angle) + ); + } + + /* I've put these -1s in here to help clipping 45 degree cases, + where two vertices can end up around the clipping line of Y=0 */ + vertex[0].X = (-widthCos - (-widthSin))/2; + vertex[0].Y = (-widthSin + (-widthCos))/2 -1; + vertex[0].U = 0; + vertex[0].V = 0; + vertex[1].X = (widthCos - (-widthSin))/2; + vertex[1].Y = (widthSin + (-widthCos))/2 -1; + vertex[1].U = MotionTrackerTextureSize; + vertex[1].V = 0; + vertex[2].X = (widthCos - widthSin)/2; + vertex[2].Y = (widthSin + widthCos)/2 -1; + vertex[2].U = MotionTrackerTextureSize; + vertex[2].V = MotionTrackerTextureSize; + vertex[3].X = ((-widthCos) - widthSin)/2; + vertex[3].Y = ((-widthSin) + widthCos)/2 -1; + vertex[3].U = 0; + vertex[3].V = MotionTrackerTextureSize; + + /* clip to Y<=0 */ + YClipMotionTrackerVertices(&vertex[0],&vertex[1]); + YClipMotionTrackerVertices(&vertex[1],&vertex[2]); + YClipMotionTrackerVertices(&vertex[2],&vertex[3]); + YClipMotionTrackerVertices(&vertex[3],&vertex[0]); + + /* translate into screen coords */ + vertex[0].X += MotionTrackerCentreX; + vertex[1].X += MotionTrackerCentreX; + vertex[2].X += MotionTrackerCentreX; + vertex[3].X += MotionTrackerCentreX; + vertex[0].Y += MotionTrackerCentreY; + vertex[1].Y += MotionTrackerCentreY; + vertex[2].Y += MotionTrackerCentreY; + vertex[3].Y += MotionTrackerCentreY; + #if 0 + textprint("%d %d %d %d\n%d %d %d %d\n%d %d %d %d\n%d %d %d %d\n", + vertex[0].X,vertex[0].Y,vertex[0].U,vertex[0].V, + vertex[1].X,vertex[1].Y,vertex[1].U,vertex[1].V, + vertex[2].X,vertex[2].Y,vertex[2].U,vertex[2].V, + vertex[3].X,vertex[3].Y,vertex[3].U,vertex[3].V); + #endif + + /* dodgy offset 'cos I'm not x clipping */ + if (vertex[0].X==-1) vertex[0].X = 0; + if (vertex[1].X==-1) vertex[1].X = 0; + if (vertex[2].X==-1) vertex[2].X = 0; + if (vertex[3].X==-1) vertex[3].X = 0; + + /* setup polygon in item format */ + { + int *itemDataPtr = TrackerPolyBuffer+4; + *itemDataPtr++ = vertex[3].X; + *itemDataPtr++ = vertex[3].Y; + *itemDataPtr++ = vertex[3].U; + *itemDataPtr++ = vertex[3].V; + + *itemDataPtr++ = vertex[2].X; + *itemDataPtr++ = vertex[2].Y; + *itemDataPtr++ = vertex[2].U; + *itemDataPtr++ = vertex[2].V; + + *itemDataPtr++ = vertex[1].X; + *itemDataPtr++ = vertex[1].Y; + *itemDataPtr++ = vertex[1].U; + *itemDataPtr++ = vertex[1].V; + + *itemDataPtr++ = vertex[0].X; + *itemDataPtr++ = vertex[0].Y; + *itemDataPtr++ = vertex[0].U; + *itemDataPtr++ = vertex[0].V; + + *itemDataPtr = Term; + + + /* draw polygon */ + Draw_Item_2dTexturePolygon(TrackerPolyBuffer); + } +} + +void YClipMotionTrackerVertices(struct VertexTag *v1, struct VertexTag *v2) +{ + char vertex1Inside=0,vertex2Inside=0; + + if (v1->Y<0) vertex1Inside = 1; + if (v2->Y<0) vertex2Inside = 1; + + /* if both vertices inside clip region no clipping required */ + if (vertex1Inside && vertex2Inside) return; + + /* if both vertices outside clip region no action required + (the other lines will be clipped) */ + if (!vertex1Inside && !vertex2Inside) return; + + /* okay, let's clip */ + if (vertex1Inside) + { + int lambda = DIV_FIXED(v1->Y,v2->Y - v1->Y); + + v2->X = v1->X - MUL_FIXED(v2->X - v1->X,lambda); + v2->Y=0; + + v2->U = v1->U - MUL_FIXED(v2->U - v1->U,lambda); + v2->V = v1->V - MUL_FIXED(v2->V - v1->V,lambda); + } + else + { + int lambda = DIV_FIXED(v2->Y,v1->Y - v2->Y); + + v1->X = v2->X - MUL_FIXED(v1->X - v2->X,lambda); + v1->Y=0; + + v1->U = v2->U - MUL_FIXED(v1->U - v2->U,lambda); + v1->V = v2->V - MUL_FIXED(v1->V - v2->V,lambda); + } +} +void XClipMotionTrackerVertices(struct VertexTag *v1, struct VertexTag *v2) +{ + char vertex1Inside=0,vertex2Inside=0; + + if (v1->X>0) vertex1Inside = 1; + if (v1->X>0) vertex1Inside = 1; + + /* if both vertices inside clip region no clipping required */ + if (vertex1Inside && vertex2Inside) return; + + /* if both vertices outside clip region no action required + (the other lines will be clipped) */ + if (!vertex1Inside && !vertex2Inside) return; + + /* okay, let's clip */ + if (vertex1Inside) + { + int lambda = DIV_FIXED(v1->X,v2->X - v1->X); + + v2->Y = v1->Y - MUL_FIXED(v2->Y - v1->Y,lambda); + v2->X=0; + + v2->U = v1->U - MUL_FIXED(v2->U - v1->U,lambda); + v2->V = v1->V - MUL_FIXED(v2->V - v1->V,lambda); + } + else + { + int lambda = DIV_FIXED(v2->X,v1->X - v2->X); + + v1->Y = v2->Y - MUL_FIXED(v1->Y - v2->Y,lambda); + v1->X=0; + + v1->U = v2->U - MUL_FIXED(v1->U - v2->U,lambda); + v1->V = v2->V - MUL_FIXED(v1->V - v2->V,lambda); + } +} + +static void SetupScanlinePoly(char const *filenamePtr, int width) +{ + int imageNumber; + int height; + + imageNumber = CL_LoadImageOnce(filenamePtr, (ScanDrawDirectDraw == ScanDrawMode ? LIO_CHIMAGE : LIO_D3DTEXTURE)|LIO_TRANSPARENT|LIO_RIFFPATH|LIO_RESTORABLE); + height = width/2; + + ScanlinePolyBuffer[3] = imageNumber; + + ScanlinePolyBuffer[6] = 0; + ScanlinePolyBuffer[7] = height; + + ScanlinePolyBuffer[10] = width; + ScanlinePolyBuffer[11] = height; + + ScanlinePolyBuffer[14] = width; + ScanlinePolyBuffer[15] = 0; + + ScanlinePolyBuffer[18] = 0; + ScanlinePolyBuffer[19] = 0; + + ScanlinePolyBuffer[20] = Term; +} + + + +#endif + +#define MAX_MESSAGE_LENGTH 50 +#define MESSAGE_FONT_WIDTH 5 +#define MESSAGE_FONT_HEIGHT 8 +extern void DrawOnScreenMessage(unsigned char *messagePtr) +{ + RECT srcRect; + int destX,destY; + int lengthOfMessage=0; + int messageFontHeight,messageFontWidth; + + { + unsigned char *textPtr = messagePtr; + + while(*textPtr++) + { + lengthOfMessage++; + if(lengthOfMessage>MAX_MESSAGE_LENGTH) + { + /* message is too long; this could indicate a corrupt ptr */ + LOCALASSERT(0); + return; + } + } + } + if (HUDResolution == HUD_RES_LO) + { + messageFontWidth = MESSAGE_FONT_WIDTH; + messageFontHeight = MESSAGE_FONT_HEIGHT; + srcRect.top = 0; + srcRect.bottom = messageFontHeight; + } + else + { + messageFontWidth = MESSAGE_FONT_WIDTH*2; + messageFontHeight = MESSAGE_FONT_HEIGHT*2; + srcRect.left = 0; + srcRect.right = messageFontWidth; + } + + destX = (ScreenDescriptorBlock.SDB_Width - (messageFontWidth+1)*lengthOfMessage)/2; + destX &= 0xfffffffe; + destY = ScreenDescriptorBlock.SDB_Height/2 - messageFontHeight*3; + + + while(*messagePtr) + { + signed int letter; + + letter = *messagePtr++; + letter -= 'A'; + + /* needs changing for other languages! */ + if (letter>=0 && letter<=26) + { + if (HUDResolution == HUD_RES_LO) + { + srcRect.left = letter*messageFontWidth; + srcRect.right = srcRect.left+messageFontWidth; + } + else + { + srcRect.top = letter*messageFontHeight; + srcRect.bottom = srcRect.top+messageFontHeight; + } + + lpDDSBack->BltFast + ( + destX,destY, + E3FontDDInfo.LPDDS, + &srcRect, + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY + ); + } + destX += messageFontWidth+2; + } +} + + +}; // extern diff --git a/3dc/avp/win95/DirectPlay.c b/3dc/avp/win95/DirectPlay.c new file mode 100644 index 0000000..d0e0a65 --- /dev/null +++ b/3dc/avp/win95/DirectPlay.c @@ -0,0 +1,893 @@ +/* KJL 15:54:57 03/07/98 - DirectPlay.c */ +#include "3dc.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "system.h" +#include "equates.h" +#include "platform.h" +#include "shape.h" +#include "prototyp.h" +#include "inline.h" +#include "dp_sprh.h" +#include "dplayext.h" +#include "equipmnt.h" +#include "pldnet.h" +#include "dp_func.h" +#include "dxlog.h" + +#include "AvP_Menus.h" +#include "AvP_MP_Config.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +GUID SPGuid; +LPGUID lpSPGuid = (LPGUID) &SPGuid; +BOOL GotTCPIP; + +/* +Version 0 - Original multiplayer + save patch +Version 100 - Added pistol,skeeter (and new levels) +*/ +#define AVP_MULTIPLAYER_VERSION 100 + +extern void MinimalNetCollectMessages(void); +extern void InitAVPNetGameForHost(int species, int gamestyle, int level); +extern void InitAVPNetGameForJoin(void); +extern int DetermineAvailableCharacterTypes(BOOL ConsiderUsedCharacters); + +extern BOOL GetGDISurface(); +extern BOOL LeaveGDISurface(); +void FindAvPSessions(void); + +LPDIRECTPLAYLOBBY3 lpDPlayLobby; + +BOOL DirectPlay_GetSessionDesc(LPDPSESSIONDESC2 lpSessionDesc) +{ + HRESULT hr; + DWORD dwSize=0; + LPDPSESSIONDESC2 sessionDescBuffer; + + if(!glpDP || !lpSessionDesc) return 0; + + //get size of session desc + IDirectPlayX_GetSessionDesc(glpDP,NULL,&dwSize); + sessionDescBuffer =(LPDPSESSIONDESC2) AllocateMem(dwSize); + + //now get the session description + hr=IDirectPlayX_GetSessionDesc(glpDP,sessionDescBuffer,&dwSize); + if(hr==DP_OK) + { + //copy the contents of the description + memcpy(lpSessionDesc,sessionDescBuffer,sizeof(DPSESSIONDESC2)); + DeallocateMem(sessionDescBuffer); + return TRUE; + } + + DeallocateMem(sessionDescBuffer); + return 0; +} + +BOOL DirectPlay_UpdateSessionDescForLobbiedGame(int gamestyle,int level) +{ + DPSESSIONDESC2 sessionDesc; + HRESULT hr; + if(!DirectPlay_GetSessionDesc(&sessionDesc)) return 0; + + { + char* customLevelName = GetCustomMultiplayerLevelName(level,gamestyle); + if(customLevelName[0]) + { + //store the gamestyle and a too big level number in dwUser2 + sessionDesc.dwUser2 = (gamestyle<<8)|100; + } + else + { + //store the gamestyle and level number in dwUser2 + sessionDesc.dwUser2 = (gamestyle<<8)|level; + } + + //store the custom level name in the session name as is. + //since we never see the session name for lobbied games anyway + sessionDesc.lpszSessionNameA = customLevelName; + + //make sure that dwUser2 is nonzero , so that it can be checked for by the + //clients + sessionDesc.dwUser2|=0x80000000; + + sessionDesc.dwUser1 = AVP_MULTIPLAYER_VERSION; + + hr = IDirectPlayX_SetSessionDesc(glpDP,&sessionDesc,0); + if(hr!=DP_OK) + { + return FALSE; + } + + } + + + return TRUE; +} + +int DirectPlay_HostGame(char *playerName, char *sessionName,int species,int gamestyle,int level) +{ + int maxPlayers=DetermineAvailableCharacterTypes(FALSE); + if(maxPlayers<1) maxPlayers=1; + if(maxPlayers>8) maxPlayers=8; + + if(!netGameData.skirmishMode) + { + //for lobbied games most of the directplay setup is done when AvP is first started + if(!LobbiedGame) + { + /* This function is intended to handle everything that is required to start a new multiplayer game. */ + CoInitialize(NULL); + + /* Init DP object */ + DPlayCreate(NULL); + + CoCreateInstance(&CLSID_DirectPlayLobby, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectPlayLobby3, (LPVOID*)&lpDPlayLobby); + + + /* Get TCPIP connection */ + //if (!GetTCPIPConnection()) return 0; + if (!InitialiseConnection()) return 0; + + /* create session */ + { + char* customLevelName = GetCustomMultiplayerLevelName(level,gamestyle); + if(customLevelName[0]) + { + //add the level name to the beginning of the session name + char name_buffer[100]; + sprintf(name_buffer,"%s:%s",customLevelName,sessionName); + if ((DPlayCreateSession(name_buffer,maxPlayers,AVP_MULTIPLAYER_VERSION,(gamestyle<<8)|100)) != DP_OK) return 0; + } + else + { + // static TCHAR sessionName[] = "AvP test session"; + if ((DPlayCreateSession(sessionName,maxPlayers,AVP_MULTIPLAYER_VERSION,(gamestyle<<8)|level)) != DP_OK) return 0; + } + } + + /* Try to create a DP player */ + } + else + { + //for lobbied games we need to fill in the level number into the existing session description + if(!DirectPlay_UpdateSessionDescForLobbiedGame(gamestyle,level)) return 0; + } + + if(!DirectPlay_CreatePlayer(playerName,playerName)) return 0; + + } + else + { + //fake multiplayer + //need to set the id to an non zero value + AVPDPNetID=100; + + ZeroMemory(&AVPDPplayerName,sizeof(DPNAME)); + AVPDPplayerName.dwSize = sizeof(DPNAME); + AVPDPplayerName.lpszShortNameA = playerName; + AVPDPplayerName.lpszLongNameA = playerName; + + } + InitAVPNetGameForHost(species,gamestyle,level); + return 1; +} + +int DirectPlay_JoinGame(void) +{ + /* This function is intended to handle everything that is required to start a new multiplayer game. */ + CoInitialize(NULL); + + /* Init DP object */ + DPlayCreate(NULL); + + CoCreateInstance(&CLSID_DirectPlayLobby, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectPlayLobby3, (LPVOID*)&lpDPlayLobby); + + /* Get TCPIP connection */ +// if (!GetTCPIPConnection()) return 0; + if (!InitialiseConnection()) return 0; + + + /* enum sessions */ + FindAvPSessions(); + return NumberOfSessionsFound; +} + +int DirectPlay_ConnectToSession(int sessionNumber, char *playerName) +{ + extern unsigned char DebouncedKeyboardInput[]; + + if (FAILED(DPlayOpenSession((LPGUID)&SessionData[sessionNumber].Guid))) return 0; + + if(!DirectPlay_CreatePlayer(playerName,playerName)) return 0; + + InitAVPNetGameForJoin(); + + netGameData.levelNumber = SessionData[sessionNumber].levelIndex; + + netGameData.joiningGameStatus = JOINNETGAME_WAITFORDESC; + + return 1; +} + + +int DirectPlay_ConnectingToSession() +{ + extern unsigned char DebouncedKeyboardInput[]; + //see if the player has got bored of waiting + if(DebouncedKeyboardInput[KEY_ESCAPE]) + { + //abort attempt to join game + if(AVPDPNetID) + { + IDirectPlayX_DestroyPlayer(glpDP, AVPDPNetID); + AVPDPNetID = NULL; + } + DPlayClose(); + AvP.Network = I_No_Network; + return 0; + } + + MinimalNetCollectMessages(); + if(!netGameData.needGameDescription) + { + //we now have the game description , so we can go to the configuration menu + return AVPMENU_MULTIPLAYER_CONFIG_JOIN; + } + return 1; +} + +int DirectPlay_InitLobbiedGame() +{ + HRESULT hr; + DWORD dwSize; + LPDPLCONNECTION lpConnectionSettings; + extern char MP_PlayerName[]; + + + /* This function is intended to handle everything that is required to start a new multiplayer game. */ + CoInitialize(NULL); + + /* Init DP object */ + DPlayCreate(NULL); + + CoCreateInstance(&CLSID_DirectPlayLobby, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectPlayLobby3A, (LPVOID*)&lpDPlayLobby); + + //get the size of the connection settings + hr = IDirectPlayLobby_GetConnectionSettings(lpDPlayLobby,0, NULL, &dwSize); + + //get the connection settings + lpConnectionSettings = (LPDPLCONNECTION) AllocateMem(dwSize); + + hr= IDirectPlayLobby_GetConnectionSettings(lpDPlayLobby,0,lpConnectionSettings, &dwSize); + + if(hr!=DP_OK) return 0; + + + //Make sure the host migrration , and keep alive flags are set for this session + if(LobbiedGame==LobbiedGame_Server) + { + lpConnectionSettings->lpSessionDesc->dwFlags|=(DPSESSION_KEEPALIVE|DPSESSION_MIGRATEHOST); + lpConnectionSettings->lpSessionDesc->dwUser1 = AVP_MULTIPLAYER_VERSION; + hr=IDirectPlayLobby_SetConnectionSettings(lpDPlayLobby,0,0,lpConnectionSettings); + if(hr!=DP_OK) + { + LOGDXFMT(("Set connection settings : %x",hr)); + } + } + + //copy the player's name from the connection settings + strncpy(MP_PlayerName,lpConnectionSettings->lpPlayerName->lpszShortNameA,NET_PLAYERNAMELENGTH-1); + MP_PlayerName[NET_PLAYERNAMELENGTH-1]='\0'; + + + //connect to the lobbied game + hr = IDirectPlayLobby_ConnectEx(lpDPlayLobby,0,&IID_IDirectPlay4A, &glpDP, NULL); + + if(hr!=DP_OK) + { + LOGDXFMT(("Connect Ex %x\n",hr)); + return 0; + } + + DeallocateMem(lpConnectionSettings); + return 1; +} + + +#if 0 +int DirectPlay_ConnectToLobbiedGame(char *playerName) +{ + extern unsigned char DebouncedKeyboardInput[]; + + InitAVPNetGameForJoin(); + + /* + Wait until there is at least one player in the game (this will be the host). + This way we can avoid joining until the host is ready + */ + while(!DirectPlay_CountPlayersInCurrentSession()) + { + //see if the player has got bored of waiting + CheckForWindowsMessages(); + ReadUserInput(); + if(DebouncedKeyboardInput[KEY_ESCAPE]) + { + //abort attempt to join game + AvP.Network = I_No_Network; + return 0; + } + } + + + //create our player + if(!DirectPlay_CreatePlayer(playerName,playerName)) + { + LOGDXFMT(("Failed to create player")); + + return 0; + } + + //wait for the game description from the host + while(netGameData.needGameDescription) + { + MinimalNetCollectMessages(); + + //see if the player has got bored of waiting + CheckForWindowsMessages(); + ReadUserInput(); + if(DebouncedKeyboardInput[KEY_ESCAPE]) + { + //abort attempt to join game + IDirectPlayX_DestroyPlayer(glpDP, AVPDPNetID); + AVPDPNetID = NULL; + AvP.Network = I_No_Network; + return 0; + } + } + return 1; +} +#else +int DirectPlay_ConnectingToLobbiedGame(char* playerName) +{ + extern unsigned char DebouncedKeyboardInput[]; + DPSESSIONDESC2 sessionDesc; + + //see if the player has got bored of waiting + if(DebouncedKeyboardInput[KEY_ESCAPE]) + { + //abort attempt to join game + if(AVPDPNetID) + { + IDirectPlayX_DestroyPlayer(glpDP, AVPDPNetID); + AVPDPNetID = NULL; + } + AvP.Network = I_No_Network; + return 0; + } + + //get the session description + if(!DirectPlay_GetSessionDesc(&sessionDesc)) + { + return 1; + } + + if(netGameData.joiningGameStatus == JOINNETGAME_WAITFORSTART) + { + /* + Wait until there is at least one player in the game (this will be the host). + This way we can avoid joining until the host is ready + */ + + if(sessionDesc.dwCurrentPlayers) + { + int gamestyle; + int level; + int local_level_index; + + //make sure the version number is correct + if(sessionDesc.dwUser1 != AVP_MULTIPLAYER_VERSION) + { + //argh + netGameData.joiningGameStatus = JOINNETGAME_WRONGAVPVERSION; + return 1; + } + + //need to wait until the level number has been filled into dwUser2 + if(!sessionDesc.dwUser2) return 1; + + gamestyle = (sessionDesc.dwUser2 >> 8) & 0xff; + level = sessionDesc.dwUser2 & 0xff; + + //see if we have the level that the host has chosen + //(note that the level name is stored in session name for custom levels) + local_level_index = GetLocalMultiplayerLevelIndex(level,sessionDesc.lpszSessionNameA,gamestyle); + if(local_level_index<0) + { + ///no good + netGameData.joiningGameStatus = JOINNETGAME_DONTHAVELEVEL; + return 1; + } + netGameData.levelNumber = local_level_index; + + + netGameData.joiningGameStatus = JOINNETGAME_WAITFORDESC; + + //we can now create our player + if(!DirectPlay_CreatePlayer(playerName,playerName)) + { + LOGDXFMT(("Failed to create player")); + return 0; + } + } + + } + if(netGameData.joiningGameStatus == JOINNETGAME_WAITFORDESC) + { + MinimalNetCollectMessages(); + if(!netGameData.needGameDescription) + { + //we now have the game description , so we can go to the configuration menu + return AVPMENU_MULTIPLAYER_CONFIG_JOIN; + + } + } + return 1; +} + +#endif + +int DirectPlay_Disconnect(void) +{ + DPlayClose(); + if (glpDP) IDirectPlayX_Release(glpDP); + glpDP=NULL; + AvP.Network = I_No_Network; + return 1; +} + + + +BOOL FAR PASCAL EnumSessionsCallback( + LPCDPSESSIONDESC2 lpSessionDesc, + LPDWORD lpdwTimeOut, + DWORD dwFlags, + LPVOID lpContext) +{ + char sessionName[100]=""; + char levelName[100]=""; + int gamestyle; + int level; + + + // see if last session has been enumerated + if (dwFlags & DPESC_TIMEDOUT || NumberOfSessionsFound>=MAX_NO_OF_SESSIONS) + return (FALSE); + + gamestyle = (lpSessionDesc->dwUser2 >> 8) & 0xff; + level = lpSessionDesc->dwUser2 & 0xff; + + + //split the session name up into its parts + if(level>=100) + { + char* colon_pos; + //custom level name may be at the start + strcpy(levelName,lpSessionDesc->lpszSessionNameA); + + colon_pos = strchr(levelName,':'); + if(colon_pos) + { + *colon_pos = 0; + strcpy(sessionName,colon_pos+1); + } + else + { + strcpy(sessionName,lpSessionDesc->lpszSessionNameA); + levelName[0] = 0; + + } + + + } + else + { + strcpy(sessionName,lpSessionDesc->lpszSessionNameA); + } + + sprintf(SessionData[NumberOfSessionsFound].Name,"%s (%d/%d)",sessionName,lpSessionDesc->dwCurrentPlayers,lpSessionDesc->dwMaxPlayers); + + SessionData[NumberOfSessionsFound].Guid = lpSessionDesc->guidInstance; + + if(lpSessionDesc->dwCurrentPlayers < lpSessionDesc->dwMaxPlayers) + SessionData[NumberOfSessionsFound].AllowedToJoin =TRUE; + else + SessionData[NumberOfSessionsFound].AllowedToJoin =FALSE; + + //multiplayer version number (possibly) + if(lpSessionDesc->dwUser1 != AVP_MULTIPLAYER_VERSION) + { + float version = 1.0 + lpSessionDesc->dwUser1/100.0; + SessionData[NumberOfSessionsFound].AllowedToJoin =FALSE; + sprintf(SessionData[NumberOfSessionsFound].Name,"%s (V %.2f)",sessionName,version); + + } + else + { + //get the level number in our list of levels (assuming we have the level) + int local_index = GetLocalMultiplayerLevelIndex(level,levelName,gamestyle); + + if(local_index<0) + { + //we don't have the level , so ignore this session + return TRUE; + } + + SessionData[NumberOfSessionsFound].levelIndex = local_index; + + + } + + NumberOfSessionsFound++; + + return (TRUE); +} + +void FindAvPSessions(void) +{ + DPSESSIONDESC2 sessionDesc; + + ZeroMemory(&sessionDesc, sizeof(DPSESSIONDESC2)); + sessionDesc.dwSize = sizeof(DPSESSIONDESC2); + sessionDesc.guidApplication = *glpGuid; + + + NumberOfSessionsFound=0; + + IDirectPlayX_EnumSessions(glpDP, &sessionDesc, 0, + EnumSessionsCallback, 0, +// DPENUMSESSIONS_AVAILABLE| + DPENUMSESSIONS_ALL| + DPENUMSESSIONS_ASYNC); +// DPENUMSESSIONS_RETURNSTATUS); +} + + + + +// --------------------------------------------------------------------------- +BOOL FAR PASCAL EnumSPCallback( + LPCGUID lpguidSP, + LPVOID lpConnection, + DWORD dwSize, + LPCDPNAME lpName, + DWORD dwFlags, + LPVOID lpContext) +{ + HRESULT hr = DPlayCreate(lpConnection); + //make sure we can actually use this service provider + if(hr==DP_OK) + { + if (IsEqualGUID(lpguidSP, &DPSPGUID_TCPIP)) + { + netGameData.tcpip_available=1; + } + else if(IsEqualGUID(lpguidSP, &DPSPGUID_IPX)) + { + netGameData.ipx_available=1; + } + else if(IsEqualGUID(lpguidSP, &DPSPGUID_SERIAL)) + { + netGameData.serial_available=1; + } + + else if(IsEqualGUID(lpguidSP, &DPSPGUID_MODEM)) + { + netGameData.modem_available=1; + } + } + return(TRUE); +} + + +static BOOL ConnectionOk; + +BOOL FAR PASCAL EnumSPAndConnectCallback( + LPCGUID lpguidSP, + LPVOID lpConnection, + DWORD dwSize, + LPCDPNAME lpName, + DWORD dwFlags, + LPVOID lpContext) +{ + if (IsEqualGUID(lpguidSP, lpContext)) + { + HRESULT hr; + //check for windows messages in order to clear any key presses from the windows messages. + CheckForWindowsMessages(); + //switch to gdi surface in case any dialog boxes are brought up + GetGDISurface(); + hr=DPlayCreate(lpConnection); + if(hr==DP_OK) + { + ConnectionOk=TRUE; + } + LeaveGDISurface(); + return FALSE; + } + return(TRUE); +} + +void DirectPlay_EnumConnections() +{ + netGameData.tcpip_available=0; + netGameData.ipx_available=0; + netGameData.modem_available=0; + netGameData.serial_available=0; + + /* This function is intended to handle everything that is required to start a new multiplayer game. */ + CoInitialize(NULL); + + /* Init DP object */ + DPlayCreate(NULL); + + IDirectPlayX_EnumConnections( glpDP, glpGuid, EnumSPCallback, 0, 0); +} + + + +BOOL GetTCPIPConnection(void) +{ + extern char IPAddressString[]; + HRESULT hr; + DPCOMPOUNDADDRESSELEMENT addressElements[3]; + LPVOID lpAddress=NULL; + DWORD dwElementCount; + DWORD dwAddressSize; + + GotTCPIP = FALSE; + /* Enumerate Service Providers */ + IDirectPlayX_EnumConnections( glpDP, glpGuid, EnumSPCallback, 0, 0); + + if (!GotTCPIP) return FALSE; + + DPlayRelease(); + + addressElements[0].guidDataType = DPAID_ServiceProvider; + addressElements[0].dwDataSize = sizeof(GUID); + addressElements[0].lpData = (LPVOID) &DPSPGUID_TCPIP; + + // IP address string + addressElements[1].guidDataType = DPAID_INet; + addressElements[1].dwDataSize = lstrlen(IPAddressString) + 1; + addressElements[1].lpData = IPAddressString; + dwElementCount = 2; + + // see how much room is needed to store this address + hr = lpDPlayLobby->lpVtbl->CreateCompoundAddress(lpDPlayLobby,addressElements, dwElementCount, NULL, &dwAddressSize); + + if (hr != DPERR_BUFFERTOOSMALL) goto FAILURE; + + // allocate space + lpAddress = AllocMem(dwAddressSize); + if (lpAddress == NULL) + { + hr = DPERR_NOMEMORY; + goto FAILURE; + } + + // create the address + hr = lpDPlayLobby->lpVtbl->CreateCompoundAddress(lpDPlayLobby,addressElements, dwElementCount, lpAddress, &dwAddressSize); + if FAILED(hr) goto FAILURE; + + DPlayCreate(lpAddress); + return TRUE; + + FAILURE: + + if (lpAddress) DeallocateMem(lpAddress); + return FALSE; +} + +BOOL InitialiseConnection() +{ + HRESULT hr; + ConnectionOk=FALSE; + + switch(netGameData.connectionType) + { + case CONN_TCPIP : + { + extern char IPAddressString[]; + DPCOMPOUNDADDRESSELEMENT addressElements[3]; + LPVOID lpAddress=NULL; + DWORD dwElementCount; + DWORD dwAddressSize; + + DPlayRelease(); + + addressElements[0].guidDataType = DPAID_ServiceProvider; + addressElements[0].dwDataSize = sizeof(GUID); + addressElements[0].lpData = (LPVOID) &DPSPGUID_TCPIP; + + // IP address string + addressElements[1].guidDataType = DPAID_INet; + addressElements[1].dwDataSize = lstrlen(IPAddressString) + 1; + addressElements[1].lpData = IPAddressString; + dwElementCount = 2; + + // see how much room is needed to store this address + hr = lpDPlayLobby->lpVtbl->CreateCompoundAddress(lpDPlayLobby,addressElements, dwElementCount, NULL, &dwAddressSize); + + if (hr != DPERR_BUFFERTOOSMALL) goto FAILURE; + + // allocate space + lpAddress = AllocMem(dwAddressSize); + if (lpAddress == NULL) + { + hr = DPERR_NOMEMORY; + goto FAILURE; + } + + // create the address + hr = lpDPlayLobby->lpVtbl->CreateCompoundAddress(lpDPlayLobby,addressElements, dwElementCount, lpAddress, &dwAddressSize); + if FAILED(hr) goto FAILURE; + + hr=DPlayCreate(lpAddress); + + if (lpAddress) DeallocateMem(lpAddress); + + return hr==DP_OK; + + FAILURE: + + if (lpAddress) DeallocateMem(lpAddress); + return FALSE; + break; + } + case CONN_IPX : + IDirectPlayX_EnumConnections( glpDP, glpGuid, EnumSPAndConnectCallback,(void*)&DPSPGUID_IPX,0); + break; + + case CONN_Modem : + IDirectPlayX_EnumConnections( glpDP, glpGuid, EnumSPAndConnectCallback,(void*)&DPSPGUID_MODEM,0); + break; + + case CONN_Serial : + IDirectPlayX_EnumConnections( glpDP, glpGuid, EnumSPAndConnectCallback, (void*)&DPSPGUID_SERIAL,0); + break; + } + + return ConnectionOk; +} + +static BOOL DirectPlay_CreatePlayer(char* FormalName,char* FriendlyName) +{ + HRESULT hr; + + // Initialise static DP name structure to refer to the names: + ZeroMemory(&AVPDPplayerName,sizeof(DPNAME)); + AVPDPplayerName.dwSize = sizeof(DPNAME); + AVPDPplayerName.lpszShortNameA = FriendlyName; + AVPDPplayerName.lpszLongNameA = FormalName; + + hr = IDirectPlayX_CreatePlayer + ( + glpDP, /* our dp object*/ + &AVPDPNetID, /* our ID */ + &AVPDPplayerName, /* our name */ + NULL, /* event */ + NULL, /* player data */ + 0, /* size of player data */ + 0 /* flags */ + ); + + if (hr == DP_OK) return 1; + else return 0; +} + + + + +#if 0 +void DirectPlay_ExitLobbiedGame() +{ + HRESULT hres = IDirectPlayX_DestroyPlayer(glpDP, AVPDPNetID); + + if(AvP.Network == I_Host) + { + int i; + int numPlayersLeft=0; + for(i=0;i0) + { + //See if our previously selected session is in the new session list + int OldSelection = *SelectedItem; + *SelectedItem=0; + + for(i=0;i +#include +#include +#include + +#include "ffread.hpp" + +/******************/ +/* ERROR HANDLING */ +/******************/ + +#include "fail.h" +void ReportError(char const * mesg1, char const * mesg2) +{ + char * mesg; + DWORD err = 0; + + if (!mesg1) mesg1=""; + + if (mesg2) + { + mesg = new char [strlen(mesg1)+strlen(mesg2)+3]; + + strcpy(mesg,mesg1); + strcat(mesg,"\n\n"); + strcat(mesg,mesg2); + } + else + { + char * lpMsgBuf; + + err = GetLastError(); + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL + ); + + mesg = new char [strlen(mesg1)+strlen(lpMsgBuf)+3]; + + strcpy(mesg,mesg1); + strcat(mesg,"\n\n"); + strcat(mesg,lpMsgBuf); + + // Free the buffer. + LocalFree( lpMsgBuf ); + } + + // Display the string. + fail("----------ERROR:%08x-----------\n\n%s\n\n",err,mesg); + + // Free the buffer. + delete[] mesg; +} + +/***************/ +/* HANDY MACRO */ +/***************/ + +#define READ_FILE(fname,post_proc,on_return,h,data,n_bytes,n_bytes_read,p5) \ + if (!ReadFile(h,data,n_bytes,&n_bytes_read,p5)) \ + { \ + ReportError(fname); \ + post_proc; \ + on_return; \ + return FF_COULDNOTWRITEFILE; \ + } \ + else if (n_bytes_read != n_bytes) \ + { \ + ReportError(fname,"Could not write the correct number of bytes"); \ + post_proc; \ + on_return; \ + return FF_COULDNOTWRITEFILE; \ + } \ + else post_proc; + + +/*****************/ +/* class FFDataI */ +/*****************/ + +FFDataI::FFDataI(char const *_filename, void *_data, size_t _length) +: filename(0) +, data(_data) +, length(_length) +{ + if (_filename) + { + filename = new char [strlen(_filename)+1]; + strcpy(filename,_filename); + } +} + +FFDataI::FFDataI(FFDataI const & ffd, ptrdiff_t offset) +: filename(0) +, data((void *)((size_t)ffd.data + offset)) +, length(ffd.length) +{ + if (ffd.filename) + { + filename = new char [1+strlen(ffd.filename)]; + strcpy(filename,ffd.filename); + } +} + +FFDataI & FFDataI::operator = (FFDataI const & ffd) +{ + if (&ffd != this) + { + if (filename) delete[] filename; + + filename = 0; + data = ffd.data; + length = ffd.length; + + if (ffd.filename) + { + filename = new char [1+strlen(ffd.filename)]; + strcpy(filename,ffd.filename); + } + } + return *this; +} + +FFDataI::~FFDataI() +{ + if (filename) delete[] filename; +} + +int FFDataI::operator == (FFDataI const & ffd) const +{ + return ! _stricmp(filename ? filename : "", ffd.filename ? ffd.filename : ""); +} + +int FFDataI::operator < (FFDataI const & ffd) const +{ + return _stricmp(filename ? filename : "", ffd.filename ? ffd.filename : "") < 0; +} + +int FFDataI::operator == (char const * name) const +{ + return ! _stricmp(filename ? filename : "", name ? name : ""); +} + +int FFDataI::operator < (char const * name) const +{ + return _stricmp(filename ? filename : "", name ? name : "") < 0; +} + +/*******************/ +/* class FFHeaderI */ +/*******************/ + +int FFHeaderI::HashFunction(char const * nam) +{ + int v = 0; + + while (*nam) v += toupper(*nam++); + + return v & (FFHI_HASHTABLESIZE-1); +} + +FFHeaderI::FFHeaderI(char const *_filename,BOOL _should_be_kept) +: filename(0) +, data(0) +, length(0) +,should_be_kept(_should_be_kept) +{ + if (_filename) + { + filename = new char [strlen(_filename)+1]; + strcpy(filename,_filename); + + Read(); + } +} + +FFHeaderI::FFHeaderI(FFHeaderI const & ffh) +: filename(0) +, data(0) +, length(ffh.length) +,should_be_kept(ffh.should_be_kept) +{ + if (ffh.filename) + { + filename = new char [1+strlen(ffh.filename)]; + strcpy(filename,ffh.filename); + } + if (ffh.data) + { + data = malloc(length); + memcpy(data,ffh.data,length); + } + ptrdiff_t offset = (size_t)data - (size_t)ffh.data; + for (int i=0; i i_file(&ffh.files[i]); !i_file.done(); i_file.next()) + { + files[i].add_entry(FFDataI(i_file(),offset)); + } + } +} + +FFHeaderI & FFHeaderI::operator = (FFHeaderI const & ffh) +{ + if (&ffh != this) + { + if (data) free(data); + if (filename) delete[] filename; + + filename = 0; + data = 0; + length = ffh.length; + + if (ffh.filename) + { + filename = new char [1+strlen(ffh.filename)]; + strcpy(filename,ffh.filename); + } + if (ffh.data) + { + data = malloc(length); + memcpy(data,ffh.data,length); + } + ptrdiff_t offset = (size_t)data - (size_t)ffh.data; + for (int i=0; i i_file(&ffh.files[i]); !i_file.done(); i_file.next()) + { + files[i].add_entry(FFDataI(i_file(),offset)); + } + } + } + return *this; +} + +FFHeaderI::~FFHeaderI() +{ + if (filename) delete[] filename; + if (data) free(data); +} + +int FFHeaderI::operator == (FFHeaderI const & ffh) const +{ + return ! _stricmp(filename ? filename : "", ffh.filename ? ffh.filename : ""); +} + +void FFHeaderI::Clear() +{ + if (data) free(data); + data = 0; + length = 0; + + for (int i=0; i0) + { + ReportError(filename,"Version not supported"); + CloseHandle(h); + return FF_COULDNOTREADFILE; + } + + void * header = malloc(total_headsize); + + READ_FILE(filename,(void)0,CloseHandle(h),h,header,total_headsize,bytes_read,0) + + data = malloc(length); + + READ_FILE(filename,(void)0,CloseHandle(h),h,data,length,bytes_read,0) + + CloseHandle(h); + + // now parse the header + + void * headerP = header; + + for (int i=0; i i_file(&files[HashFunction(name)]); !i_file.done(); i_file.next()) + { + if (i_file()==name) + { + if (lengthP) *lengthP = i_file().GetLength(); + return i_file().GetDataPointer(); + } + } + return 0; +} + diff --git a/3dc/avp/win95/FFREAD.HPP b/3dc/avp/win95/FFREAD.HPP new file mode 100644 index 0000000..76668f5 --- /dev/null +++ b/3dc/avp/win95/FFREAD.HPP @@ -0,0 +1,110 @@ +#ifndef _included_ffread_hpp_ +#define _included_ffread_hpp_ + +#ifndef __cplusplus +#error "ffread.hpp requires C++ compilation" +#endif + +/* + +Fastfile format: + +1. Identifier, num_files +2. Header - contains information about files and offsets +3. Data - concatenated files + +1.1 DWORD: RFFL - identifier +1.2 DWORD: version 0 +1.3 DWORD: num_files +1.4 DWORD: num bytes of header +1.5 DWORD: num bytes of data + +2.1 DWORD: Offset +2.2 DWORD: Length +2.3 STRING: Filename - null term then to 4 bytes + +3.1 DATA: padded to 4 bytes per file + +*/ + +#include +#include +#include "list_tem.hpp" + +enum FFError +{ + FF_OK, + FF_COULDNOTOPENFILE, + FF_COULDNOTREADFILE, + FF_COULDNOTWRITEFILE, + FF_INVALIDPARMS +}; + +void ReportError(char const * mesg1, char const * mesg2 = 0); + +class FFDataI +{ +private: + char * filename; + void * data; + size_t length; + +public: + FFDataI(char const *_filename = 0, void *_data = 0, size_t _length = 0); + FFDataI(FFDataI const &, ptrdiff_t offset = 0); + FFDataI & operator = (FFDataI const &); + ~FFDataI(); + + int operator == (FFDataI const &) const; + int operator != (FFDataI const & ffd) const + { return ! operator == (ffd); } + + int operator == (char const * name) const; + int operator != (char const * name) const + { return ! operator == (name); } + + int operator < (FFDataI const &) const; + int operator < (char const * name) const; + + inline void * GetDataPointer() const + { return data; } + inline size_t GetLength() const + { return length; } +}; + +#define FFHI_HASHTABLESIZE 256 + +class FFHeaderI +{ +private: + char * filename; + void * data; + size_t length; + List files [FFHI_HASHTABLESIZE]; // hash table + + static int HashFunction(char const * nam); + + BOOL should_be_kept; + +public: + FFHeaderI(char const *_filename = 0,BOOL _should_be_kept=FALSE); + FFHeaderI(FFHeaderI const &); + FFHeaderI & operator = (FFHeaderI const &); + ~FFHeaderI(); + + int operator == (FFHeaderI const &) const; + int operator != (FFHeaderI const & ffh) const + { return ! operator == (ffh); } + + FFError Read(char const *_filename = 0); + + void const * FindFile(char const * name, size_t * lengthP) const; + //mark files that should kept when using ffclose_almost_all with a capital letter + //should probably be done with an extra entry in the info text file, but I want to mantain + //compatibility with the predator demo + BOOL ShouldBeKept(){return should_be_kept;} + + void Clear(); +}; + +#endif // ! _included_ffread_hpp_ diff --git a/3dc/avp/win95/FFSTDIO.CPP b/3dc/avp/win95/FFSTDIO.CPP new file mode 100644 index 0000000..ffda27e --- /dev/null +++ b/3dc/avp/win95/FFSTDIO.CPP @@ -0,0 +1,496 @@ +#include +#include +#include "ffstdio.h" +#include "ffread.hpp" +#include "list_tem.hpp" +#include "dxlog.h" +#include "system.h" + +class FFileDesc +{ +private: + size_t dname_len; + char * dir_name; + char * file_name; +public: + FFileDesc(char const * infoline = 0, char const * path = 0); + FFileDesc(FFileDesc const &); + FFileDesc & operator = (FFileDesc const &); + ~FFileDesc(); + + int CouldInclude(char const * fname) const; + FFHeaderI * Load() const; + + //mark files that should kept when using ffclose_almost_all with a capital letter + //should probably be done with an extra entry in the info text file, but I want to mantain + //compatibility with the predator demo + BOOL ShouldBeKept() const {return *dir_name>='A' && *dir_name<='Z';} + + int operator == (FFileDesc const &) const; + int operator != (FFileDesc const & ffd) const + { return ! operator == (ffd); } +}; + +FFileDesc::FFileDesc(char const * infoline, char const * path) +: dir_name(0) +, file_name(0) +{ + if (infoline) + { + char dbuf[256]; + char fbuf[256]; + + char * dbufP = dbuf; + char * fbufP = fbuf; + if (path) + { + strcpy(fbuf,path); + fbufP += strlen(path); + } + + int c1; + int c2; + + do + { + c2 = c1 = *infoline++; + if (';'==c1||'\n'==c1) + c1 = 0; + *dbufP++ = (char)c1; + } + while (c1); + + if (c2) + { + do + { + c1 = *infoline++; + if ('\n'==c1) + c1 = 0; + *fbufP++ = (char)c1; + } + while (c1); + + dname_len = strlen(dbuf); + dir_name = new char[1+dname_len]; + strcpy(dir_name,dbuf); + file_name = new char[1+strlen(fbuf)]; + strcpy(file_name,fbuf); + } + } +} + +FFileDesc::FFileDesc(FFileDesc const & ffd) +: dir_name(0) +, file_name(0) +, dname_len(ffd.dname_len) +{ + if (ffd.dir_name) + { + dir_name = new char [1+dname_len]; + strcpy(dir_name,ffd.dir_name); + } + if (ffd.file_name) + { + file_name = new char [1+strlen(ffd.file_name)]; + strcpy(file_name,ffd.file_name); + } +} + +FFileDesc & FFileDesc::operator = (FFileDesc const & ffd) +{ + if (&ffd != this) + { + if (dir_name) delete[] dir_name; + if (file_name) delete[] file_name; + dir_name = 0; + file_name = 0; + dname_len = ffd.dname_len; + if (ffd.dir_name) + { + dir_name = new char [1+dname_len]; + strcpy(dir_name,ffd.dir_name); + } + if (ffd.file_name) + { + file_name = new char [1+strlen(ffd.file_name)]; + strcpy(file_name,ffd.file_name); + } + } + return *this; +} + +FFileDesc::~FFileDesc() +{ + if (dir_name) delete[] dir_name; + if (file_name) delete[] file_name; +} + +int FFileDesc::CouldInclude(char const * fname) const +{ + if (dir_name) + { + return ! _strnicmp(dir_name,fname,dname_len); + } + return 0; +} + +FFHeaderI * FFileDesc::Load() const +{ + LOGDXFMT(("Loaded FastFile: %s\n(for directory: %s)\n",file_name,dir_name)); + return new FFHeaderI(file_name,ShouldBeKept()); +} + +int FFileDesc::operator == (FFileDesc const & ffd) const +{ + return ! _stricmp(file_name ? file_name : "", ffd.file_name ? ffd.file_name : ""); +} + + +static List fdesclist; + +static List floadeddesclist; + +static List fflist; + +static List openlist; + + +int ffInit(char const * infofilename, char const * ffpath) +{ + FILE * fp = fopen(infofilename,"r"); + if (!fp) return 0; + + while (fdesclist.size()) + fdesclist.delete_first_entry(); + + // read data + char buf[512]; + buf[0]=0; + + fgets(buf,sizeof buf,fp); + do + { + //Only look at lines that start with a letter + //mainly so as to avoid using blank lines + + if((buf[0]>='a' && buf[0]<='z') || + (buf[0]>='A' && buf[0]<='Z')) + { + fdesclist.add_entry(FFileDesc(buf,ffpath)); + } + } + while (fgets(buf,sizeof buf,fp)); + + fclose(fp); + + return 1; +} + +void ffKill(void) +{ + #define EMPTY_LIST(list) while ((list).size()) (list).delete_first_entry(); + #define EMPTY_POINTER_LIST(list) while ((list).size()) {delete (list).first_entry();(list).delete_first_entry();} + + EMPTY_LIST(fdesclist) + EMPTY_LIST(floadeddesclist) + EMPTY_POINTER_LIST(fflist) + EMPTY_POINTER_LIST(openlist) +} + +int ffcloseall(void) +{ + int cnt = openlist.size(); + LOGDXFMT(("Unloading all fastfiles: %d subfile(s) still open",cnt)); + for (LIF i_open(&openlist); !i_open.done();) + { + FFILE * fp = i_open(); + if (fp->flag & FFF_ALOC) free((void *)fp->data_start); + fp->data_start = 0; + fp->data_ptr = 0; + delete fp; + i_open.delete_current(); + } + while (fflist.size()) + { + delete fflist.first_entry(); + fflist.delete_first_entry(); + } + while (floadeddesclist.size()) + { + floadeddesclist.delete_first_entry(); + } + return cnt; +} + +int ffclose_almost_all(void) +{ + //unload all fastfiles except for the common ones + int cnt = openlist.size(); + LOGDXFMT(("Unloading almost all fastfiles: %d subfile(s) still open",cnt)); + for (LIF i_open(&openlist); !i_open.done();) + { + FFILE * fp = i_open(); + if (fp->flag & FFF_ALOC) free((void *)fp->data_start); + fp->data_start = 0; + fp->data_ptr = 0; + delete fp; + i_open.delete_current(); + } + + for(LIF fflif(&fflist);!fflif.done();) + { + if(fflif()->ShouldBeKept()) + { + fflif.next(); + } + else + { + delete fflif(); + fflif.delete_current(); + } + } + + for(LIF desc_lif(&floadeddesclist);!desc_lif.done();) + { + if(desc_lif().ShouldBeKept()) + { + desc_lif.next(); + } + else + { + desc_lif.delete_current(); + } + } + + LOGDXFMT(("Keeping %d fastfile(s)",fflist.size())); + return cnt; +} + + +int ffclose(FFILE * fp) +{ + if (fp->flag & FFF_ALOC) free((void *)fp->data_start); + fp->data_start = 0; + fp->data_ptr = 0; + openlist.delete_entry(fp); + delete fp; + return 0; +} + +int ffgetc(FFILE * fp) +{ + if (fp->remaining) + { + -- fp->remaining; + ++ fp->pos; + return *(signed char const *)fp->data_ptr++; + } + else + { + fp->flag |= FFF_EOF; + return EOF; + } +} + +char * ffgets(char * s, int n, FFILE * fp) +{ + char * sP = s; + + for (int n_read = 0; n_readremaining) + { + fp->flag |= FFF_EOF; + return 0; + } + int ch = *(char const *)fp->data_ptr++; + -- fp->remaining; + ++ fp->pos; + *sP++ = (char)ch; + if ('\n'==ch) break; + } + *sP=0; + return s; +} + +void const * ffreadbuf(char const * filename, size_t * p_len) +{ + void const * data; + + for (LIF i_ff(&fflist); !i_ff.done(); i_ff.next()) + { + data = i_ff()->FindFile(filename,p_len); + if (data) return data; + } + + // try loading another big catfile + + for (LIF i_fdesc(&fdesclist); !i_fdesc.done(); i_fdesc.next()) + { + if (i_fdesc().CouldInclude(filename) && !floadeddesclist.contains(i_fdesc())) + { + floadeddesclist.add_entry(i_fdesc()); + FFHeaderI * newffh = i_fdesc().Load(); + fflist.add_entry(newffh); + + data = newffh->FindFile(filename,p_len); + if (data) + { + return data; + } + } + } + + return NULL; +} + +FFILE * ffopen(char const * filename, char const * mode) +{ + if (mode[0]!='r' || mode[1]!='b') return 0; + + size_t length; + void const * data = ffreadbuf(filename,&length); + + if (data) + { + FFILE * fp = new FFILE; + fp->data_start = data; + fp->data_ptr = (unsigned char const *)data; + fp->length = length; + fp->pos = 0; + fp->remaining = length; + fp->flag = 0; + openlist.add_entry(fp); + return fp; + } + + errno = ENOENT; + // ok, just use fopen (if debug) + #if debug && 0 // dont do this, caller should handle this situation + LOGDXFMT(("%s not in any fastfile",filename)); + + FILE * sfp = fopen(filename,mode); + if (!sfp) return 0; + + fseek(sfp,0,SEEK_END); + length = ftell(sfp); + fseek(sfp,0,SEEK_SET); + data = malloc(length); + if (!data) + { + fclose(sfp); + return 0; + } + length = fread((void *)data,1,length,sfp); + + FFILE * fp = new FFILE; + fp->data_start = data; + fp->data_ptr = (unsigned char const *)data; + fp->length = length; + fp->pos = 0; + fp->remaining = length; + fp->flag = FFF_ALOC; + if (ferror(sfp)) + { + fp->flag |= FFF_ERR; + } + fclose(sfp); + openlist.add_entry(fp); + return fp; + #else + return 0; + #endif +} + +size_t ffreadb(void * ptr, size_t n, FFILE * fp) +{ + if (fp->remaining < n) + { + n = fp->remaining; + fp->flag |= FFF_EOF; + } + + memcpy(ptr,fp->data_ptr,n); + + fp->data_ptr += n; + fp->pos += n; + fp->remaining -= n; + + return n; +} + +size_t fflookb(void const * * ptr, size_t n, FFILE * fp) +{ + if (fp->remaining < n) + { + n = fp->remaining; + fp->flag |= FFF_EOF; + } + + *ptr = fp->data_ptr; + + fp->data_ptr += n; + fp->pos += n; + fp->remaining -= n; + + return n; +} + +int ffseek(FFILE * fp, long offset, int whence) +{ + switch (whence) + { + case SEEK_SET: + if (offset > fp->length || offset < 0) + { + fp->flag |= FFF_ERR; + errno = EDOM; + return 1; + } + fp->pos = offset; + break; + case SEEK_CUR: + if (offset+fp->pos > fp->length || offset+(long)fp->pos < 0) + { + fp->flag |= FFF_ERR; + errno = EDOM; + return 1; + } + fp->pos += offset; + break; + case SEEK_END: + if (offset < -(signed int)fp->length || offset>0) + { + fp->flag |= FFF_ERR; + errno = EDOM; + return 1; + } + fp->pos = fp->length + offset; + break; + default: + errno = EINVAL; + fp->flag |= FFF_ERR; + return 1; + } + fp->flag &= ~FFF_EOF; + fp->remaining = fp->length - fp->pos; + fp->data_ptr = (unsigned char const *)fp->data_start + fp->pos; + return 0; +} + +int ffsetpos(FFILE * fp, ffpos_t const * pos) +{ + if (*pos > fp->length || *pos < 0) + { + fp->flag |= FFF_ERR; + errno = EDOM; + return 1; + } + + fp->pos = *pos; + fp->remaining = fp->length - *pos; + fp->data_ptr = (unsigned char const *)fp->data_start + *pos; + + return 0; +} diff --git a/3dc/avp/win95/FFSTDIO.H b/3dc/avp/win95/FFSTDIO.H new file mode 100644 index 0000000..3e8015d --- /dev/null +++ b/3dc/avp/win95/FFSTDIO.H @@ -0,0 +1,66 @@ +#ifndef _included_ffstdio_h_ +#define _included_ffstdio_h_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define FFF_EOF 0x0001 +#define FFF_ERR 0x0002 +#define FFF_ALOC 0x0004 + +struct _FFile +{ + void const * data_start; + unsigned char const * data_ptr; + size_t length; + size_t pos; + size_t remaining; + int flag; +}; +typedef struct _FFile FFILE; +typedef size_t ffpos_t; + +extern int ffInit(char const * infofilename, char const * ffpath); +extern void ffKill(void); /* only need to call this to prevent misreported memory leaks */ + +/* only mode supported is "rb" */ +extern int ffclearerr(FFILE * fp); +extern int ffclose(FFILE * fp); +extern int ffcloseall(void); +extern int ffclose_almost_all(void); +extern int ffeof(FFILE * fp); +extern int fferror(FFILE * fp); +extern int ffgetc(FFILE * fp); +extern int ffgetpos(FFILE * fp, ffpos_t * pos); +extern char * ffgets(char * s, int n, FFILE * fp); +extern size_t fflook(void const * * ptr, size_t size, size_t n, FFILE * fp); +extern size_t fflookb(void const * * ptr, size_t n, FFILE * fp); +extern FFILE * ffopen(char const * filename, char const * mode); +extern size_t ffread(void * ptr, size_t size, size_t n, FFILE * fp); +extern size_t ffreadb(void * ptr, size_t n, FFILE * fp); +extern int ffseek(FFILE * fp, long offset, int whence); +extern int ffsetpos(FFILE * fp, ffpos_t const * pos); +extern long fftell(FFILE * fp); + +/* this function is called by ffopen, but you can call it direct + to get a pointer to memory where the contents of a file exist */ +/* nb. the buffer remains valid until a call to ffcloseall */ +extern void const * ffreadbuf(char const * filename, size_t * len); + +/* speedy macros */ +#define ffclearerr(fp) ((fp)->flag &= ~(FFF_ERR|FFF_EOF)) +#define ffeof(fp) ((fp)->flag & FFF_EOF) +#define fferror(fp) ((fp)->flag & FFF_ERR) +#define ffgetpos(fp,pos) (*(pos) = (fp)->pos,0) +#define fftell(fp) ((fp)->pos) +#define ffread(ptr,size,n,fp) ffreadb(ptr,(size)*(n),fp) +#define fflook(ptr,size,n,fp) fflookb(ptr,(size)*(n),fp) + +#ifdef __cplusplus +} +#endif + +#endif /* ! _included_ffstdio_h_ */ diff --git a/3dc/avp/win95/Frontend/AvP_EnvInfo.c b/3dc/avp/win95/Frontend/AvP_EnvInfo.c new file mode 100644 index 0000000..8285b31 --- /dev/null +++ b/3dc/avp/win95/Frontend/AvP_EnvInfo.c @@ -0,0 +1,5234 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "AvP_EnvInfo.h" +#include "AvP_UserProfile.h" +#include "AvP_MP_Config.h" +#include "pldnet.h" + +static enum AVP_ENVIRONMENT_ID MarineEpisodes[] = +{ + // main single player game + AVP_ENVIRONMENT_DERELICT, + AVP_ENVIRONMENT_COLONY, + AVP_ENVIRONMENT_INVASION, + AVP_ENVIRONMENT_ORBITAL, + AVP_ENVIRONMENT_TYRARGO, + AVP_ENVIRONMENT_TYRARGOHANGAR, + + AVP_ENVIRONMENT_TEMPLE_M, + AVP_ENVIRONMENT_VAULTS_M, + AVP_ENVIRONMENT_FERARCO_M, + AVP_ENVIRONMENT_GATEWAY_M, + AVP_ENVIRONMENT_WATERFALL_M, + // that's all folks + AVP_ENVIRONMENT_END_OF_LIST +}; + +static enum AVP_ENVIRONMENT_ID PredatorEpisodes[] = +{ + // main single player game + AVP_ENVIRONMENT_WATERFALL, + AVP_ENVIRONMENT_AREA52, + AVP_ENVIRONMENT_VAULTS, + AVP_ENVIRONMENT_FURY161, + AVP_ENVIRONMENT_CAVERNS, + AVP_ENVIRONMENT_CAVERNSEND, + + AVP_ENVIRONMENT_INVASION_P, + AVP_ENVIRONMENT_ESCAPE_P, + AVP_ENVIRONMENT_TEMPLE_P, + AVP_ENVIRONMENT_EARTHBOUND_P, + AVP_ENVIRONMENT_TYRARGO_P, + + // that's all folks + AVP_ENVIRONMENT_END_OF_LIST +}; + +static enum AVP_ENVIRONMENT_ID AlienEpisodes[] = +{ + // main single player game + AVP_ENVIRONMENT_TEMPLE, + AVP_ENVIRONMENT_ESCAPE, + AVP_ENVIRONMENT_FERARCO, + AVP_ENVIRONMENT_GATEWAY, + AVP_ENVIRONMENT_EARTHBOUND, + + AVP_ENVIRONMENT_INVASION_A, + AVP_ENVIRONMENT_DERELICT_A, + AVP_ENVIRONMENT_TYRARGO_A, + AVP_ENVIRONMENT_CAVERNS_A, + AVP_ENVIRONMENT_FURY161_A, + // that's all folks + AVP_ENVIRONMENT_END_OF_LIST +}; + +static enum AVP_ENVIRONMENT_ID MultiplayerEpisodes[] = +{ + #ifndef MPLAYER_DEMO + AVP_ENVIRONMENT_SEWER, +// AVP_ENVIRONMENT_SCREAM, + AVP_ENVIRONMENT_MASSACRE, +// AVP_ENVIRONMENT_STATION, +// AVP_ENVIRONMENT_DESTRUCTION, + AVP_ENVIRONMENT_STATUE, + AVP_ENVIRONMENT_JOCKEY, + #endif + + AVP_ENVIRONMENT_HIVE, + +//and now the multipack levels + AVP_ENVIRONMENT_LEADWORKS_MP, + AVP_ENVIRONMENT_HADLEYSHOPE_MP, + AVP_ENVIRONMENT_MEATFACTORY_MP, + AVP_ENVIRONMENT_NOSTROMO_MP, + AVP_ENVIRONMENT_SUBWAY_MP, + AVP_ENVIRONMENT_ELEVATOR_MP, + AVP_ENVIRONMENT_LAB14_MP, + AVP_ENVIRONMENT_COMPOUND_MP, + AVP_ENVIRONMENT_OFFICE_MP, + + // that's all folks + AVP_ENVIRONMENT_END_OF_LIST +}; + +static enum AVP_ENVIRONMENT_ID CooperativeEpisodes[] = +{ + AVP_ENVIRONMENT_KENS_COOP, + AVP_ENVIRONMENT_HIVE_COOP, + AVP_ENVIRONMENT_TRAPPED_COOP, + AVP_ENVIRONMENT_ALS_DM_COOP, + AVP_ENVIRONMENT_JOCKEY_COOP, + +//and now the multipack levels + AVP_ENVIRONMENT_LEADWORKS_COOP, + AVP_ENVIRONMENT_HADLEYSHOPE_COOP, + AVP_ENVIRONMENT_MEATFACTORY_COOP, + AVP_ENVIRONMENT_NOSTROMO_COOP, + AVP_ENVIRONMENT_SUBWAY_COOP, + AVP_ENVIRONMENT_ELEVATOR_COOP, + AVP_ENVIRONMENT_LAB14_COOP, + AVP_ENVIRONMENT_COMPOUND_COOP, + + AVP_ENVIRONMENT_END_OF_LIST +}; + +static char *RifNamesForEnvironments[] = +{ + // primarily Marine + "derelict",//AVP_ENVIRONMENT_DERELICT, + "genshd1",//AVP_ENVIRONMENT_COLONY, + "invasion",//AVP_ENVIRONMENT_INVASION, + "odobenus",//AVP_ENVIRONMENT_ORBITAL, + "sulaco",//AVP_ENVIRONMENT_TYRARGO, + "hangar",//AVP_ENVIRONMENT_TYRARGOHANGAR, + + // primarily Predator + "fall",//AVP_ENVIRONMENT_WATERFALL, + "area52",//AVP_ENVIRONMENT_AREA52, + "vaults",//AVP_ENVIRONMENT_VAULTS, + "furyall",//AVP_ENVIRONMENT_FURY161, + "caverns",//AVP_ENVIRONMENT_CAVERNS, + "battle",//AVP_ENVIRONMENT_CAVERNSEND, + + // primarily Alien + "nost03",//AVP_ENVIRONMENT_FERARCO, + "temple",//AVP_ENVIRONMENT_TEMPLE, + "stat101",//AVP_ENVIRONMENT_GATEWAY, + "escape",//AVP_ENVIRONMENT_ESCAPE, + "breakout",//AVP_ENVIRONMENT_EARTHBOUND, + + // primarily multiplayer + "als-dm",//AVP_ENVIRONMENT_SEWER, + "e3demo",//AVP_ENVIRONMENT_MASSACRE, + "statue",//AVP_ENVIRONMENT_STATUE, + "jockey",//AVP_ENVIRONMENT_JOCKEY + "hive",//AVP_ENVIRONEMENT_HIVE + + // Alien bonus levels + "invasion_a",//AVP_ENVIRONMENT_INVASION_A, + "derelict_a",//AVP_ENVIRONMENT_DERELICT_A, + "sulaco_a",//AVP_ENVIRONMENT_TYRARGO_A, + "furyall_a",//AVP_ENVIRONMENT_FURY161_A, + "caverns_a",//AVP_ENVIRONMENT_CAVERNS_A, + + // Predator bonus levels + "invasion_p",//AVP_ENVIRONMENT_INVASION_P, + "sulaco_p",//AVP_ENVIRONMENT_TYRARGO_P, + "temple_p",//AVP_ENVIRONMENT_TEMPLE_P, + "escape_p",//AVP_ENVIRONMENT_ESCAPE_P, + "breakout_p",//AVP_ENVIRONMENT_EARTHBOUND_P, + + // Marine bonus levels + "fall_m",//AVP_ENVIRONMENT_WATERFALL_M, + "vaults_m",//AVP_ENVIRONMENT_VAULTS_M, + "nost03_m",//AVP_ENVIRONMENT_FERARCO_M, + "temple_m",//AVP_ENVIRONMENT_TEMPLE_M, + "stat101_m",//AVP_ENVIRONMENT_GATEWAY_M, + + + //cooperative levels + "kens-co-op",//AVP_ENVIRONMENT_KENS_COOP, + "hive_c",//AVP_ENVIRONMENT_HIVE_COOP, + "trapped",//AVP_ENVIRONMENT_TRAPPED_COOP, + "als-dm-coop",//AVP_ENVIRONMENT_ALS_DM_COOP, + "jockeycoop",//AVP_ENVIRONMENT_JOCKEY_COOP, + + // demo levels + "e3demosp",//AVP_ENVIRONMENT_E3DEMOSP, + + "Not a Level",//AVP_ENVIRONMENT_END_OF_LIST + + //multipack multiplayer levels + "Leadworks",//AVP_ENVIRONMENT_LEADWORKS_MP, + "HadleysHope",//AVP_ENVIRONMENT_HADLEYSHOPE_MP, + "Meat_Factory",//AVP_ENVIRONMENT_MEATFACTORY_MP, + "Nostromo",//AVP_ENVIRONMENT_NOSTROMO_MP, + "Subway",//AVP_ENVIRONMENT_SUBWAY_MP, + "Elevator",//AVP_ENVIRONMENT_ELEVATOR_MP, + "Lab14",//AVP_ENVIRONMENT_LAB14_MP, + "Compound",//AVP_ENVIRONMENT_COMPOUND_MP, + "Office",//AVP_ENVIRONMENT_OFFICE_MP, + + //multipack multiplayer cooperative levels + "Leadworks_coop",//AVP_ENVIRONMENT_LEADWORKS_COOP, + "hadleyshope_coop",//AVP_ENVIRONMENT_HADLEYSHOPE_COOP, + "Co-op_Meat_Factory",//AVP_ENVIRONMENT_MEATFACTORY_COOP, + "Nostromo_Coop",//AVP_ENVIRONMENT_NOSTROMO_COOP, + "SubwayCoop",//AVP_ENVIRONMENT_SUBWAY_COOP, + "Elevator_co-op",//AVP_ENVIRONMENT_ELEVATOR_COOP, + "Lab14coop",//AVP_ENVIRONMENT_LAB14_COOP, + "CompoundCoop",//AVP_ENVIRONMENT_COMPOUND_COOP, + +}; + +extern char LevelName[]; + +AvP_Level_Target_Desc LevelStatsTargets[I_MaxDifficulties][AVP_ENVIRONMENT_END_OF_LIST] = { +{ + { + { /* Derelict / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Colony / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Invasion / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Orbital / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Tyrago / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Hangar / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Waterfall / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Area52 / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Vaults / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Fury161 / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Caverns / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Battle / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Feraco / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Temple / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Gateway / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Escape / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Earthbound / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Sewer / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Massacre / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Statue / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Jockey / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Hive / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Invasion_A / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Derelict_A / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Tyrago_A / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Fury161_A / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Caverns_A / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Invasion_P / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Tyrago_P / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Temple_P / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Escape_P / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Earthbound_P / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Waterfall_M / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Vaults_M / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Feraco_M / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Temple_M / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Gateway_M / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Kens_Coop / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Hive_Coop / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Trapped_Coop / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Als_DM_Coop / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* E3DemoSP / Easy */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, +}, + +{ + { + { /* Derelict / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + 80, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_JOHNWOO, /* Cheat to activate */ + }, + { + { /* Colony / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + 40, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_GRENADE, /* Cheat to activate */ + }, + { + { /* Invasion / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 4, /* Total Minutes (unsigned!) */ + 0, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_WARPSPEED, /* Cheat to activate */ + }, + { + { /* Orbital / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + 20, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_LANDOFTHEGIANTS, /* Cheat to activate */ + }, + { + { /* Tyrago / Medium */ + {-1,32,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_SLUGTRAIL, /* Cheat to activate */ + }, + { + { /* Hangar / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Waterfall / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + 80, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_PIGSTICKING, /* Cheat to activate */ + }, + { + { /* Area52 / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,25,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_SUPERGORE, /* Cheat to activate */ + }, + { + { /* Vaults / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + 100, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_DISCOINFERNO, /* Cheat to activate */ + }, + { + { /* Fury161 / Medium */ + {-1,40,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_BALLSOFFIRE, /* Cheat to activate */ + }, + { + { /* Caverns / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + 15, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_RAINBOWBLOOD, /* Cheat to activate */ + }, + { + { /* Battle / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Feraco / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,15,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_PIPECLEANER, /* Cheat to activate */ + }, + { + { /* Temple / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,10,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_SNIPERMUNCH, /* Cheat to activate */ + }, + { + { /* Gateway / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + (30*ONE_FIXED), /* Total Seconds (unsigned!) */ + 4, /* Total Minutes (unsigned!) */ + 0, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + 9000, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_MOTIONBLUR, /* Cheat to activate */ + }, + { + { /* Escape / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 2, /* Total Minutes (unsigned!) */ + 0, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NAUSEA, /* Cheat to activate */ + }, + { + { /* Earthbound / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_MIRROR, /* Cheat to activate */ + }, + { + { /* Sewer / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Massacre / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Statue / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Jockey / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Hive / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Invasion_A / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Derelict_A / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,20,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_IMPOSSIBLEMISSION, /* Cheat to activate */ + }, + { + { /* Tyrago_A / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Fury161_A / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Caverns_A / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Invasion_P / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,15,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_TICKERTAPE, /* Cheat to activate */ + }, + { + { /* Tyrago_P / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Temple_P / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Escape_P / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,10,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_TRIPTASTIC, /* Cheat to activate */ + }, + { + { /* Earthbound_P / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Waterfall_M / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Vaults_M / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + 60, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_UNDERWATER, /* Cheat to activate */ + }, + { + { /* Feraco_M / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Temple_M / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + 100, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_FREEFALL, /* Cheat to activate */ + }, + { + { /* Gateway_M / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Kens_Coop / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Hive_Coop / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Trapped_Coop / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Als_DM_Coop / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* E3DemoSP / Medium */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, +}, + +{ + { + { /* Derelict / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + 80, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_JOHNWOO, /* Cheat to activate */ + }, + { + { /* Colony / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + 40, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_GRENADE, /* Cheat to activate */ + }, + { + { /* Invasion / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 4, /* Total Minutes (unsigned!) */ + 0, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_WARPSPEED, /* Cheat to activate */ + }, + { + { /* Orbital / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + 20, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_LANDOFTHEGIANTS, /* Cheat to activate */ + }, + { + { /* Tyrago / Hard */ + {-1,32,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_SLUGTRAIL, /* Cheat to activate */ + }, + { + { /* Hangar / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Waterfall / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + 80, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_PIGSTICKING, /* Cheat to activate */ + }, + { + { /* Area52 / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,25,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_SUPERGORE, /* Cheat to activate */ + }, + { + { /* Vaults / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + 100, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_DISCOINFERNO, /* Cheat to activate */ + }, + { + { /* Fury161 / Hard */ + {-1,40,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_BALLSOFFIRE, /* Cheat to activate */ + }, + { + { /* Caverns / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + 15, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_RAINBOWBLOOD, /* Cheat to activate */ + }, + { + { /* Battle / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Feraco / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,15,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_PIPECLEANER, /* Cheat to activate */ + }, + { + { /* Temple / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,10,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_SNIPERMUNCH, /* Cheat to activate */ + }, + { + { /* Gateway / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + (30*ONE_FIXED), /* Total Seconds (unsigned!) */ + 4, /* Total Minutes (unsigned!) */ + 0, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + 9000, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_MOTIONBLUR, /* Cheat to activate */ + }, + { + { /* Escape / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 2, /* Total Minutes (unsigned!) */ + 0, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NAUSEA, /* Cheat to activate */ + }, + { + { /* Earthbound / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1, 1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_MIRROR, /* Cheat to activate */ + }, + { + { /* Sewer / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Massacre / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Statue / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Jockey / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Hive / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Invasion_A / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Derelict_A / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,20,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_IMPOSSIBLEMISSION, /* Cheat to activate */ + }, + { + { /* Tyrago_A / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Fury161_A / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Caverns_A / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Invasion_P / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,15,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_TICKERTAPE, /* Cheat to activate */ + }, + { + { /* Tyrago_P / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Temple_P / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Escape_P / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,10,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_TRIPTASTIC, /* Cheat to activate */ + }, + { + { /* Earthbound_P / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Waterfall_M / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Vaults_M / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + 60, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_UNDERWATER, /* Cheat to activate */ + }, + { + { /* Feraco_M / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Temple_M / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + 100, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_FREEFALL, /* Cheat to activate */ + }, + { + { /* Gateway_M / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Kens_Coop / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Hive_Coop / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Trapped_Coop / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Als_DM_Coop / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* E3DemoSP / Hard */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, +}, + +{ + { + { /* Derelict / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Colony / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Invasion / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Orbital / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Tyrago / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Hangar / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Waterfall / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Area52 / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Vaults / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Fury161 / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Caverns / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Battle / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Feraco / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Temple / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Gateway / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Escape / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Earthbound / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Sewer / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Massacre / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Statue / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Jockey / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Hive / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Invasion_A / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Derelict_A / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Tyrago_A / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Fury161_A / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Caverns_A / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Invasion_P / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Tyrago_P / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Temple_P / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Escape_P / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Earthbound_P / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Waterfall_M / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Vaults_M / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Feraco_M / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Temple_M / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Gateway_M / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Kens_Coop / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Hive_Coop / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Trapped_Coop / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Als_DM_Coop / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* Jockey_Coop / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, + { + { /* E3DemoSP / Impossible */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures Killed */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Creatures decapitated*/ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Trophies / Live Head Bites */ + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,}, /* Dead Head Bites */ + -1, /* Shots Fired */ + -1, /* Accuracy */ + -1, /* Spotted */ + 0, /* Total Seconds (unsigned!) */ + 0, /* Total Minutes (unsigned!) */ + -1, /* Total Hours */ + 0, /* Cloaked Seconds */ + 0, /* Cloaked Minutes */ + -1, /* Cloaked Hours */ + -1, /* Health Damage */ + -1, /* Armour Damage */ + -1, /* Average Speed */ + -1, /* Field Charge Used */ + -1, /* Head Shot Percentage */ + { /* Padding */ + 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,0,0,0,0,0,0,0,0, + }, + }, + CHEATMODE_NONACTIVE, /* Cheat to activate */ + }, +}, + +}; + +void SetLevelToLoadForAlien(int episode) +{ + strcpy(LevelName,RifNamesForEnvironments[AlienEpisodes[episode]]); +} +void SetLevelToLoadForPredator(int episode) +{ + strcpy(LevelName,RifNamesForEnvironments[PredatorEpisodes[episode]]); +} +void SetLevelToLoadForMarine(int episode) +{ + strcpy(LevelName,RifNamesForEnvironments[MarineEpisodes[episode]]); +} + +void SetLevelToLoadForMultiplayer(int episode) +{ + //is this a custom level? + if(episode>=MAX_NO_OF_MULTIPLAYER_EPISODES) + { + //it certainly is + //(the game type sent passed to the function doesn't really matter , as long as it isn't NGT_COOP) + sprintf(LevelName,"Custom\\%s",GetCustomMultiplayerLevelName(episode,NGT_Individual)); + } + else + { + strcpy(LevelName,RifNamesForEnvironments[MultiplayerEpisodes[episode]]); + } +} +void SetLevelToLoadForCooperative(int episode) +{ + //is this a custom level? + if(episode>=MAX_NO_OF_COOPERATIVE_EPISODES) + { + //it certainly is + sprintf(LevelName,"Custom\\%s",GetCustomMultiplayerLevelName(episode,NGT_Coop)); + } + else + { + strcpy(LevelName,RifNamesForEnvironments[CooperativeEpisodes[episode]]); + } +} + +void SetLevelToLoad(enum AVP_ENVIRONMENT_ID env) +{ + strcpy(LevelName,RifNamesForEnvironments[env]); +} +void SetLevelToLoadForCheatMode(int environment) +{ + if (environment<=10) + { + SetLevelToLoadForMarine(environment); + } + else if (environment>=22) + { + SetLevelToLoadForAlien(environment-22); + } + else + { + SetLevelToLoadForPredator(environment-11); + } +} + +int NumberForCurrentLevel(void) { + + int a; + + for (a=0; a=MAX_NO_OF_MULTIPLAYER_EPISODES) return FALSE; + return DoesNamedLevelExist(RifNamesForEnvironments[MultiplayerEpisodes[level]]); + +} + +BOOL DoesCooperativeLevelExist(int level) +{ + /* + Check that the level number is valid , and the level actually exists on + the players hard drive. + */ + if(level<0 || level>=MAX_NO_OF_COOPERATIVE_EPISODES) return FALSE; + return DoesNamedLevelExist(RifNamesForEnvironments[CooperativeEpisodes[level]]); +} \ No newline at end of file diff --git a/3dc/avp/win95/Frontend/AvP_EnvInfo.h b/3dc/avp/win95/Frontend/AvP_EnvInfo.h new file mode 100644 index 0000000..ff42a70 --- /dev/null +++ b/3dc/avp/win95/Frontend/AvP_EnvInfo.h @@ -0,0 +1,125 @@ +#ifndef _avp_env_info_h_ +#define _avp_env_info_h_ 1 + +#define MAX_NO_OF_BASIC_ALIEN_EPISODES 5 +#define MAX_NO_OF_BASIC_MARINE_EPISODES 6 +#define MAX_NO_OF_BASIC_PREDATOR_EPISODES 6 + +#define MAX_NO_OF_ALIEN_EPISODES 10 +#define MAX_NO_OF_MARINE_EPISODES 11 +#define MAX_NO_OF_PREDATOR_EPISODES 11 + +// Edmond for Mplayer demo +#ifdef MPLAYER_DEMO +#define MAX_NO_OF_MULTIPLAYER_EPISODES 1 +#else +#define MAX_NO_OF_MULTIPLAYER_EPISODES 14 +#endif + +#define MAX_NO_OF_COOPERATIVE_EPISODES 13 + +enum AVP_ENVIRONMENT_ID +{ + // primarily Marine + AVP_ENVIRONMENT_DERELICT, + AVP_ENVIRONMENT_COLONY, + AVP_ENVIRONMENT_INVASION, + AVP_ENVIRONMENT_ORBITAL, + AVP_ENVIRONMENT_TYRARGO, + AVP_ENVIRONMENT_TYRARGOHANGAR, + + // primarily Predator + AVP_ENVIRONMENT_WATERFALL, + AVP_ENVIRONMENT_AREA52, + AVP_ENVIRONMENT_VAULTS, + AVP_ENVIRONMENT_FURY161, + AVP_ENVIRONMENT_CAVERNS, + AVP_ENVIRONMENT_CAVERNSEND, + + // primarily Alien + AVP_ENVIRONMENT_FERARCO, + AVP_ENVIRONMENT_TEMPLE, + AVP_ENVIRONMENT_GATEWAY, + AVP_ENVIRONMENT_ESCAPE, + AVP_ENVIRONMENT_EARTHBOUND, + + // primarily Multiplayer + AVP_ENVIRONMENT_SEWER, + AVP_ENVIRONMENT_MASSACRE, + AVP_ENVIRONMENT_STATUE, + AVP_ENVIRONMENT_JOCKEY, + AVP_ENVIRONMENT_HIVE, + + // Alien bonus levels + AVP_ENVIRONMENT_INVASION_A, + AVP_ENVIRONMENT_DERELICT_A, + AVP_ENVIRONMENT_TYRARGO_A, + AVP_ENVIRONMENT_FURY161_A, + AVP_ENVIRONMENT_CAVERNS_A, + + // Predator bonus levels + AVP_ENVIRONMENT_INVASION_P, + AVP_ENVIRONMENT_TYRARGO_P, + AVP_ENVIRONMENT_TEMPLE_P, + AVP_ENVIRONMENT_ESCAPE_P, + AVP_ENVIRONMENT_EARTHBOUND_P, + + // Marine bonus levels + AVP_ENVIRONMENT_WATERFALL_M, + AVP_ENVIRONMENT_VAULTS_M, + AVP_ENVIRONMENT_FERARCO_M, + AVP_ENVIRONMENT_TEMPLE_M, + AVP_ENVIRONMENT_GATEWAY_M, + + // primarily Multiplayer cooperative + AVP_ENVIRONMENT_KENS_COOP, + AVP_ENVIRONMENT_HIVE_COOP, + AVP_ENVIRONMENT_TRAPPED_COOP, + AVP_ENVIRONMENT_ALS_DM_COOP, + AVP_ENVIRONMENT_JOCKEY_COOP, + + // demo levels + AVP_ENVIRONMENT_E3DEMOSP, + + AVP_ENVIRONMENT_END_OF_LIST, + + /* + I'll put the multipack levels after the 'AVP_ENVIRONMENT_END_OF_LIST' + so as to avoid having to add game statistic entries for the levels. + */ + + //multipack multiplayer levels + AVP_ENVIRONMENT_LEADWORKS_MP, + AVP_ENVIRONMENT_HADLEYSHOPE_MP, + AVP_ENVIRONMENT_MEATFACTORY_MP, + AVP_ENVIRONMENT_NOSTROMO_MP, + AVP_ENVIRONMENT_SUBWAY_MP, + AVP_ENVIRONMENT_ELEVATOR_MP, + AVP_ENVIRONMENT_LAB14_MP, + AVP_ENVIRONMENT_COMPOUND_MP, + AVP_ENVIRONMENT_OFFICE_MP, + + //multipack multiplayer cooperative levels + AVP_ENVIRONMENT_LEADWORKS_COOP, + AVP_ENVIRONMENT_HADLEYSHOPE_COOP, + AVP_ENVIRONMENT_MEATFACTORY_COOP, + AVP_ENVIRONMENT_NOSTROMO_COOP, + AVP_ENVIRONMENT_SUBWAY_COOP, + AVP_ENVIRONMENT_ELEVATOR_COOP, + AVP_ENVIRONMENT_LAB14_COOP, + AVP_ENVIRONMENT_COMPOUND_COOP, + + AVP_ENVIRONMENT_END_OF_MULTIPACK_LIST + +}; + +extern void SetLevelToLoadForAlien(int episode); +extern void SetLevelToLoadForPredator(int episode); +extern void SetLevelToLoadForMarine(int episode); +extern void SetLevelToLoadForMultiplayer(int episode); +extern void SetLevelToLoadForCooperative(int episode); +extern void SetLevelToLoad(enum AVP_ENVIRONMENT_ID env); +extern void SetLevelToLoadForCheatMode(int environment); +extern int NumberForCurrentLevel(void); + +#endif diff --git a/3dc/avp/win95/Frontend/AvP_Intro.cpp b/3dc/avp/win95/Frontend/AvP_Intro.cpp new file mode 100644 index 0000000..168bfff --- /dev/null +++ b/3dc/avp/win95/Frontend/AvP_Intro.cpp @@ -0,0 +1,324 @@ + +extern "C" +{ + #include "3dc.h" + //#include "intro.hpp" + #include "inline.h" + #include "smacker.h" + #include "AvP_Menus.h" + extern int NormalFrameTime; + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + extern DDPIXELFORMAT DisplayPixelFormat; + extern LPDIRECTDRAWSURFACE lpDDSBack; + extern int GotAnyKey; + extern int DebouncedGotAnyKey; + + extern AVPMENUGFX AvPMenuGfxStorage[]; +extern void DirectReadKeyboard(void); + + +static IntroHasAlreadyBeenPlayed = 1; + + +void Show_CopyrightInfo(void); +void Show_Presents(void); +void Show_ARebellionGame(void); +void Show_AvPLogo(void); +extern void ShowSplashScreens(void); +extern void Show_WinnerScreen(void); +extern void PlayBinkedFMV(char *filenamePtr); +extern void DrawMainMenusBackdrop(void); +extern void FadedScreen(int alpha); + +void WeWantAnIntro(void) +{ + IntroHasAlreadyBeenPlayed = 0; +} + + +extern void PlayIntroSequence(void) +{ + if (IntroHasAlreadyBeenPlayed) + { + StartMenuMusic(); + return; + } + IntroHasAlreadyBeenPlayed=1; + + ResetFrameCounter(); + Show_CopyrightInfo(); + + /* play the Fox Interactive FMV */ + ClearScreenToBlack(); + FlipBuffers(); + ClearScreenToBlack(); + + PlayBinkedFMV("FMVs/logos.bik"); + //PlayFMV("FMVs/rebellion.smk"); + + StartMenuMusic(); + ResetFrameCounter(); + + Show_Presents(); + #if ALLOW_SKIP_INTRO + if (!GotAnyKey) Show_ARebellionGame(); + if (!GotAnyKey) Show_AvPLogo(); + #else + Show_ARebellionGame(); + Show_AvPLogo(); + #endif + +} +extern void ShowSplashScreens(void) +{ + LoadAllSplashScreenGfx(); + int i; + enum AVPMENUGFX_ID graphic[] = + { + AVPMENUGFX_SPLASH_SCREEN1,AVPMENUGFX_SPLASH_SCREEN2,AVPMENUGFX_SPLASH_SCREEN3, + AVPMENUGFX_SPLASH_SCREEN4,AVPMENUGFX_SPLASH_SCREEN5, + }; + for (i=0; i<5; i++) + { + int timeRemaining = 5*ONE_FIXED; + do + { + int a = timeRemaining*2; + if (a>ONE_FIXED) a=ONE_FIXED; + + if (i!=4) + { + DrawAvPMenuGfx_CrossFade(graphic[i],graphic[i+1], a); + timeRemaining-=NormalFrameTime; + } + else + { + if (a==ONE_FIXED) + { + DrawAvPMenuGfx(graphic[i], 0, 0, ONE_FIXED+1,AVPMENUFORMAT_LEFTJUSTIFIED); + } + else + { + DrawAvPMenuGfx_Faded(graphic[i], 0, 0, a,AVPMENUFORMAT_LEFTJUSTIFIED); + } + timeRemaining-=NormalFrameTime/2; + } + CheckForWindowsMessages(); + FlipBuffers(); + + DirectReadKeyboard(); + FrameCounterHandler(); + } + while(timeRemaining>=0 && !DebouncedGotAnyKey); + } + ClearScreenToBlack(); + FlipBuffers(); + ClearScreenToBlack(); + FlipBuffers(); + +} +extern void Show_WinnerScreen(void) +{ + LoadAvPMenuGfx(AVPMENUGFX_WINNER_SCREEN); + + int timeRemaining = 10*ONE_FIXED; + do + { + int a = timeRemaining*2; + if (a>ONE_FIXED) + { + DrawAvPMenuGfx(AVPMENUGFX_WINNER_SCREEN, 0, 0, ONE_FIXED+1,AVPMENUFORMAT_LEFTJUSTIFIED); + } + else + { + DrawAvPMenuGfx_Faded(AVPMENUGFX_WINNER_SCREEN, 0, 0, a,AVPMENUFORMAT_LEFTJUSTIFIED); + } + + CheckForWindowsMessages(); + FlipBuffers(); + + DirectReadKeyboard(); + FrameCounterHandler(); + timeRemaining-=NormalFrameTime; + } + while(timeRemaining>=0 && !DebouncedGotAnyKey); + ClearScreenToBlack(); + FlipBuffers(); + ClearScreenToBlack(); + FlipBuffers(); + +} + +void Show_CopyrightInfo(void) +{ + int timeRemaining = ONE_FIXED/2; + do + { + CheckForWindowsMessages(); + { + DrawAvPMenuGfx_Faded(AVPMENUGFX_COPYRIGHT_SCREEN, 0, 0, ONE_FIXED-timeRemaining*2,AVPMENUFORMAT_LEFTJUSTIFIED); + FlipBuffers(); + } + FrameCounterHandler(); + timeRemaining-=NormalFrameTime; + } + while(timeRemaining>0); + + timeRemaining = ONE_FIXED*2; + do + { + CheckForWindowsMessages(); + { + DrawAvPMenuGfx_Faded(AVPMENUGFX_COPYRIGHT_SCREEN, 0, 0, ONE_FIXED,AVPMENUFORMAT_LEFTJUSTIFIED); + FlipBuffers(); + } + FrameCounterHandler(); + timeRemaining-=NormalFrameTime; + } + while(timeRemaining>0); + + timeRemaining = ONE_FIXED/2; + do + { + CheckForWindowsMessages(); + { + DrawAvPMenuGfx_Faded(AVPMENUGFX_COPYRIGHT_SCREEN, 0, 0, timeRemaining*2,AVPMENUFORMAT_LEFTJUSTIFIED); + FlipBuffers(); + } + FrameCounterHandler(); + timeRemaining-=NormalFrameTime; + } + while(timeRemaining>0); +} + +void Show_Presents(void) +{ + int timeRemaining = 8*ONE_FIXED-ONE_FIXED/2; + do + { + CheckForWindowsMessages(); + { + char *textPtr = GetTextString(TEXTSTRING_FOXINTERACTIVE); + int y = (480-AvPMenuGfxStorage[AVPMENUGFX_PRESENTS].Height)/2; + PlayMenuMusic(); + DrawMainMenusBackdrop(); + + if (timeRemaining > 6*ONE_FIXED) + { + // DrawGraphicWithFadingLevel(&Starfield_Backdrop,timeRemaining-7*ONE_FIXED); +// DrawAvPMenuGfx_Faded(AVPMENUGFX_BACKDROP, 0, 0, 15*ONE_FIXED-timeRemaining*2,AVPMENUFORMAT_LEFTJUSTIFIED); + FadedScreen((15*ONE_FIXED-timeRemaining*2)/3); + } + else if (timeRemaining > 5*ONE_FIXED) + { + RenderMenuText(textPtr,MENU_CENTREX,y,6*ONE_FIXED-timeRemaining,AVPMENUFORMAT_CENTREJUSTIFIED); + } + else if (timeRemaining > 4*ONE_FIXED) + { + RenderMenuText(textPtr,MENU_CENTREX,y,ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + } + else if (timeRemaining > 3*ONE_FIXED) + { + RenderMenuText(textPtr,MENU_CENTREX,y,timeRemaining-3*ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + } + + FlipBuffers(); + } + #if ALLOW_SKIP_INTRO + DirectReadKeyboard(); + #endif + FrameCounterHandler(); + timeRemaining-=NormalFrameTime; + } + #if ALLOW_SKIP_INTRO + while((timeRemaining>0) && !GotAnyKey); + #else + while(timeRemaining>0);// && !GotAnyKey); + #endif +} + +void Show_ARebellionGame(void) +{ + int timeRemaining = 7*ONE_FIXED; + do + { + CheckForWindowsMessages(); + { + char *textPtr = GetTextString(TEXTSTRING_PRESENTS); + int y = (480-AvPMenuGfxStorage[AVPMENUGFX_AREBELLIONGAME].Height)/2; + DrawMainMenusBackdrop(); +// DrawAvPMenuGfx(AVPMENUGFX_BACKDROP, 0, 0, ONE_FIXED+1,AVPMENUFORMAT_LEFTJUSTIFIED); + PlayMenuMusic(); + + if (timeRemaining > 13*ONE_FIXED/2) + { +// DrawAvPMenuGfx(AVPMENUGFX_AREBELLIONGAME, MENU_CENTREX, y, 14*ONE_FIXED-timeRemaining*2,AVPMENUFORMAT_CENTREJUSTIFIED); + RenderMenuText(textPtr,MENU_CENTREX,y,14*ONE_FIXED-timeRemaining*2,AVPMENUFORMAT_CENTREJUSTIFIED); +// DrawGraphicWithAlphaChannel(&RebellionLogo,timeRemaining*2-13*ONE_FIXED); + } + else if (timeRemaining > 5*ONE_FIXED) + { +// DrawAvPMenuGfx(AVPMENUGFX_AREBELLIONGAME, MENU_CENTREX, y, ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + RenderMenuText(textPtr,MENU_CENTREX,y,ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); +// DrawGraphicWithAlphaChannel(&RebellionLogo,0); + } + else if (timeRemaining > 3*ONE_FIXED) + { +// DrawAvPMenuGfx(AVPMENUGFX_AREBELLIONGAME, MENU_CENTREX, y, (timeRemaining-3*ONE_FIXED)/2,AVPMENUFORMAT_CENTREJUSTIFIED); + RenderMenuText(textPtr,MENU_CENTREX,y,(timeRemaining-3*ONE_FIXED)/2,AVPMENUFORMAT_CENTREJUSTIFIED); +// DrawGraphicWithAlphaChannel(&RebellionLogo, ONE_FIXED - (timeRemaining-3*ONE_FIXED)/2); + } + + FlipBuffers(); + } + DirectReadKeyboard(); + FrameCounterHandler(); + timeRemaining-=NormalFrameTime; + } + #if ALLOW_SKIP_INTRO + while((timeRemaining>0) && !GotAnyKey); + #else + while(timeRemaining>0);// && !GotAnyKey); + #endif +} +void Show_AvPLogo(void) +{ + int timeRemaining = 5*ONE_FIXED; + do + { + CheckForWindowsMessages(); + { + int y = (480-AvPMenuGfxStorage[AVPMENUGFX_ALIENSVPREDATOR].Height)/2; + DrawMainMenusBackdrop(); +// DrawAvPMenuGfx(AVPMENUGFX_BACKDROP, 0, 0, ONE_FIXED+1,AVPMENUFORMAT_LEFTJUSTIFIED); + PlayMenuMusic(); + + if (timeRemaining > 9*ONE_FIXED/2) + { + DrawAvPMenuGfx(AVPMENUGFX_ALIENSVPREDATOR, MENU_CENTREX, y, -timeRemaining*2+10*ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + } + else if (timeRemaining > 4*ONE_FIXED) + { + DrawAvPMenuGfx(AVPMENUGFX_ALIENSVPREDATOR, MENU_CENTREX, y, ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + } + else + { + DrawAvPMenuGfx(AVPMENUGFX_ALIENSVPREDATOR, MENU_CENTREX, y, timeRemaining/4,AVPMENUFORMAT_CENTREJUSTIFIED); + timeRemaining-=NormalFrameTime/4; + } + + FlipBuffers(); + } + DirectReadKeyboard(); + FrameCounterHandler(); + timeRemaining-=NormalFrameTime; + } + #if ALLOW_SKIP_INTRO + while((timeRemaining>0) && !GotAnyKey); + #else + while(timeRemaining>0);// && !GotAnyKey); + #endif +} + +}; + diff --git a/3dc/avp/win95/Frontend/AvP_MP_Config.cpp b/3dc/avp/win95/Frontend/AvP_MP_Config.cpp new file mode 100644 index 0000000..bf3e5a0 --- /dev/null +++ b/3dc/avp/win95/Frontend/AvP_MP_Config.cpp @@ -0,0 +1,853 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "pldnet.h" + +#include "AvP_MP_Config.h" +#include "AvP_Envinfo.h" + +#include "AvP_Menus.h" +#include "list_tem.hpp" + +#define UseLocalAssert Yes +#include "ourasert.h" + +extern "C" +{ +extern void SetDefaultMultiplayerConfig(); +extern char MP_SessionName[]; +extern char MP_Config_Description[]; + +#define MP_CONFIG_DIR "MPConfig" +#define MP_CONFIG_WILDCARD "MPConfig\\*.cfg" + +#define SKIRMISH_CONFIG_WILDCARD "MPConfig\\*.skirmish_cfg" + +static List ConfigurationFilenameList; +static List ConfigurationLocalisedFilenameList; +char* LastDescriptionFile=0; +char* LastDescriptionText=0; + + +AVPMENU_ELEMENT* AvPMenu_Multiplayer_LoadConfig=0; + +BOOL BuildLoadMPConfigMenu() +{ + //delete the old list of filenames + while(ConfigurationFilenameList.size()) + { + delete [] ConfigurationFilenameList.first_entry(); + ConfigurationFilenameList.delete_first_entry(); + } + while(ConfigurationLocalisedFilenameList.size()) + { + ConfigurationLocalisedFilenameList.delete_first_entry(); + } + + //do a search for all the configuration in the configuration directory + + const char* load_name=MP_CONFIG_WILDCARD; + if(netGameData.skirmishMode) + { + load_name=SKIRMISH_CONFIG_WILDCARD; + } + // allow a wildcard search + WIN32_FIND_DATA wfd; + + HANDLE hFindFile = ::FindFirstFile(load_name,&wfd); + + if (INVALID_HANDLE_VALUE == hFindFile) + { + return FALSE; + } + + // get any path in the load_name + int nPathLen = 0; + char * pColon = strrchr(load_name,':'); + if (pColon) nPathLen = pColon - load_name + 1; + char * pBackSlash = strrchr(load_name,'\\'); + if (pBackSlash) + { + int nLen = pBackSlash - load_name + 1; + if (nLen > nPathLen) nPathLen = nLen; + } + char * pSlash = strrchr(load_name,'/'); + if (pSlash) + { + int nLen = pSlash - load_name + 1; + if (nLen > nPathLen) nPathLen = nLen; + } + + do + { + if + ( + !(wfd.dwFileAttributes & + (FILE_ATTRIBUTE_DIRECTORY + |FILE_ATTRIBUTE_SYSTEM + |FILE_ATTRIBUTE_HIDDEN)) + // not a directory, hidden or system file + ) + { + char* name=new char[strlen(wfd.cFileName)+1]; + strcpy(name,wfd.cFileName); + char* dotpos=strchr(name,'.'); + if(dotpos) *dotpos=0; + ConfigurationFilenameList.add_entry(name); + + BOOL localisedFilename=FALSE; + + //seeif this is one of the default language localised configurations + if(!strncmp(name,"Config",6)) + { + if(name[6]>='1' && name[6]<='7' && name[7]=='\0') + { + TEXTSTRING_ID string_index=(TEXTSTRING_ID)(TEXTSTRING_MPCONFIG1_FILENAME+(name[6]-'1')); + ConfigurationLocalisedFilenameList.add_entry(GetTextString(string_index)); + localisedFilename=TRUE; + } + } + if(!localisedFilename) + { + ConfigurationLocalisedFilenameList.add_entry(name); + } + + } + + }while (::FindNextFile(hFindFile,&wfd)); + + + if (ERROR_NO_MORE_FILES != GetLastError()) + { + printf("Error finding next file\n"); + } + + ::FindClose(hFindFile); + + + //delete the old menu + if(AvPMenu_Multiplayer_LoadConfig) delete AvPMenu_Multiplayer_LoadConfig; + + AvPMenu_Multiplayer_LoadConfig=0; + + if(!ConfigurationFilenameList.size()) return FALSE; + + //create a new menu from the list of filenames + AvPMenu_Multiplayer_LoadConfig=new AVPMENU_ELEMENT[ConfigurationFilenameList.size()+1]; + + for(int i=0;i= ConfigurationFilenameList.size()) return 0; + const char* name = ConfigurationFilenameList[index]; + //see if we have already got the description for this file + if(LastDescriptionFile) + { + if(!strcmp(LastDescriptionFile,name)) + { + return LastDescriptionText; + } + else + { + delete [] LastDescriptionFile; + delete [] LastDescriptionText; + LastDescriptionFile=0; + LastDescriptionText=0; + } + } + + LastDescriptionFile=new char[strlen(name)+1]; + strcpy(LastDescriptionFile,name); + + //seeif this is one of the default language localised configurations + if(!strncmp(name,"Config",6)) + { + if(name[6]>='1' && name[6]<='7' && name[7]=='\0') + { + TEXTSTRING_ID string_index=(TEXTSTRING_ID)(TEXTSTRING_MPCONFIG1_DESCRIPTION+(name[6]-'1')); + LastDescriptionText=new char[strlen(GetTextString(string_index))+1]; + strcpy(LastDescriptionText,GetTextString(string_index)); + + return LastDescriptionText; + } + } + + + FILE* file; + char filename[200]; + if(netGameData.skirmishMode) + sprintf(filename,"%s\\%s.skirmish_cfg",MP_CONFIG_DIR,name); + else + sprintf(filename,"%s\\%s.cfg",MP_CONFIG_DIR,name); + + file=fopen(filename,"rb"); + if(!file) + { + return 0; + } + + //skip to the part of the file containing the description + fseek(file,169,SEEK_SET); + + int description_length=0; + fread(&description_length,sizeof(int),1,file); + + if(description_length) + { + LastDescriptionText=new char[description_length]; + fread(LastDescriptionText,1,description_length,file); + } + fclose(file); + + return LastDescriptionText; +} + +void LoadMultiplayerConfigurationByIndex(int index) +{ + if(index<0 || index>= ConfigurationFilenameList.size()) return; + + LoadMultiplayerConfiguration(ConfigurationFilenameList[index]); +} + +void LoadMultiplayerConfiguration(const char* name) +{ + + + FILE* file; + char filename[200]; + if(netGameData.skirmishMode) + sprintf(filename,"%s\\%s.skirmish_cfg",MP_CONFIG_DIR,name); + else + sprintf(filename,"%s\\%s.cfg",MP_CONFIG_DIR,name); + + file=fopen(filename,"rb"); + if(!file) return; + + + + + //set defaults first , in case there are entries not set by this file + SetDefaultMultiplayerConfig(); + + fread(&netGameData.gameType,sizeof(int),1,file); + fread(&netGameData.levelNumber,sizeof(int),1,file); + fread(&netGameData.scoreLimit,sizeof(int),1,file); + fread(&netGameData.timeLimit,sizeof(int),1,file); + fread(&netGameData.invulnerableTime,sizeof(int),1,file); + fread(&netGameData.characterKillValues[0],sizeof(int),1,file); + fread(&netGameData.characterKillValues[1],sizeof(int),1,file); + fread(&netGameData.characterKillValues[2],sizeof(int),1,file); + fread(&netGameData.baseKillValue,sizeof(int),1,file); + fread(&netGameData.useDynamicScoring,sizeof(BOOL),1,file); + fread(&netGameData.useCharacterKillValues,sizeof(BOOL),1,file); + + fread(&netGameData.maxMarine,sizeof(int),1,file); + fread(&netGameData.maxAlien,sizeof(int),1,file); + fread(&netGameData.maxPredator,sizeof(int),1,file); + fread(&netGameData.maxMarineGeneral,sizeof(int),1,file); + fread(&netGameData.maxMarinePulseRifle,sizeof(int),1,file); + fread(&netGameData.maxMarineSmartgun,sizeof(int),1,file); + fread(&netGameData.maxMarineFlamer,sizeof(int),1,file); + fread(&netGameData.maxMarineSadar,sizeof(int),1,file); + fread(&netGameData.maxMarineGrenade,sizeof(int),1,file); + fread(&netGameData.maxMarineMinigun,sizeof(int),1,file); + + fread(&netGameData.allowSmartgun,sizeof(BOOL),1,file); + fread(&netGameData.allowFlamer,sizeof(BOOL),1,file); + fread(&netGameData.allowSadar,sizeof(BOOL),1,file); + fread(&netGameData.allowGrenadeLauncher,sizeof(BOOL),1,file); + fread(&netGameData.allowMinigun,sizeof(BOOL),1,file); + fread(&netGameData.allowDisc,sizeof(BOOL),1,file); + fread(&netGameData.allowPistol,sizeof(BOOL),1,file); + fread(&netGameData.allowPlasmaCaster,sizeof(BOOL),1,file); + fread(&netGameData.allowSpeargun,sizeof(BOOL),1,file); + fread(&netGameData.allowMedicomp,sizeof(BOOL),1,file); + fread(&MP_SessionName[0],sizeof(char),13,file); + + + fread(&netGameData.maxLives,sizeof(int),1,file); + fread(&netGameData.useSharedLives,sizeof(BOOL),1,file); + + fread(&netGameData.pointsForRespawn,sizeof(int),1,file); + fread(&netGameData.timeForRespawn,sizeof(int),1,file); + + fread(&netGameData.aiKillValues[0],sizeof(int),1,file); + fread(&netGameData.aiKillValues[1],sizeof(int),1,file); + fread(&netGameData.aiKillValues[2],sizeof(int),1,file); + + fread(&netGameData.gameSpeed,sizeof(int),1,file); + + int description_length=0; + fread(&description_length,sizeof(int),1,file); + fread(MP_Config_Description,1,description_length,file); + + fread(&netGameData.preDestroyLights,sizeof(BOOL),1,file); + fread(&netGameData.disableFriendlyFire,sizeof(BOOL),1,file); + fread(&netGameData.fallingDamage,sizeof(BOOL),1,file); + #if LOAD_NEW_MPCONFIG_ENTRIES + fread(&netGameData.maxMarineSmartDisc,sizeof(int),1,file); + fread(&netGameData.maxMarinePistols,sizeof(int),1,file); + fread(&netGameData.allowSmartDisc,sizeof(BOOL),1,file); + fread(&netGameData.allowPistols,sizeof(BOOL),1,file); + fread(&netGameData.pistolInfiniteAmmo,sizeof(BOOL),1,file); + fread(&netGameData.specialistPistols,sizeof(BOOL),1,file); + #endif + + //read the custom level name + int length=0; + fread(&length,sizeof(int),1,file); + if(length) + { + fread(netGameData.customLevelName,1,length,file); + } + else + { + netGameData.customLevelName[0] = 0; + } + + fclose(file); + + //if the custom level name has been set , we need to find the index + if(netGameData.customLevelName[0]) + { + netGameData.levelNumber = GetCustomMultiplayerLevelIndex(netGameData.customLevelName,netGameData.gameType); + + if(netGameData.levelNumber <0) + { + //we don't have the level + netGameData.levelNumber = 0; + netGameData.customLevelName[0] = 0; + } + } + +} + +void SaveMultiplayerConfiguration(const char* name) +{ + FILE* file; + char filename[200]; + if(netGameData.skirmishMode) + sprintf(filename,"%s\\%s.skirmish_cfg",MP_CONFIG_DIR,name); + else + sprintf(filename,"%s\\%s.cfg",MP_CONFIG_DIR,name); + + CreateDirectory(MP_CONFIG_DIR,0); + file=fopen(filename,"wb"); + if(!file) return; + + fwrite(&netGameData.gameType,sizeof(int),1,file); + fwrite(&netGameData.levelNumber,sizeof(int),1,file); + fwrite(&netGameData.scoreLimit,sizeof(int),1,file); + fwrite(&netGameData.timeLimit,sizeof(int),1,file); + fwrite(&netGameData.invulnerableTime,sizeof(int),1,file); + fwrite(&netGameData.characterKillValues[0],sizeof(int),1,file); + fwrite(&netGameData.characterKillValues[1],sizeof(int),1,file); + fwrite(&netGameData.characterKillValues[2],sizeof(int),1,file); + fwrite(&netGameData.baseKillValue,sizeof(int),1,file); + fwrite(&netGameData.useDynamicScoring,sizeof(BOOL),1,file); + fwrite(&netGameData.useCharacterKillValues,sizeof(BOOL),1,file); + + fwrite(&netGameData.maxMarine,sizeof(int),1,file); + fwrite(&netGameData.maxAlien,sizeof(int),1,file); + fwrite(&netGameData.maxPredator,sizeof(int),1,file); + fwrite(&netGameData.maxMarineGeneral,sizeof(int),1,file); + fwrite(&netGameData.maxMarinePulseRifle,sizeof(int),1,file); + fwrite(&netGameData.maxMarineSmartgun,sizeof(int),1,file); + fwrite(&netGameData.maxMarineFlamer,sizeof(int),1,file); + fwrite(&netGameData.maxMarineSadar,sizeof(int),1,file); + fwrite(&netGameData.maxMarineGrenade,sizeof(int),1,file); + fwrite(&netGameData.maxMarineMinigun,sizeof(int),1,file); + + fwrite(&netGameData.allowSmartgun,sizeof(BOOL),1,file); + fwrite(&netGameData.allowFlamer,sizeof(BOOL),1,file); + fwrite(&netGameData.allowSadar,sizeof(BOOL),1,file); + fwrite(&netGameData.allowGrenadeLauncher,sizeof(BOOL),1,file); + fwrite(&netGameData.allowMinigun,sizeof(BOOL),1,file); + fwrite(&netGameData.allowDisc,sizeof(BOOL),1,file); + fwrite(&netGameData.allowPistol,sizeof(BOOL),1,file); + fwrite(&netGameData.allowPlasmaCaster,sizeof(BOOL),1,file); + fwrite(&netGameData.allowSpeargun,sizeof(BOOL),1,file); + fwrite(&netGameData.allowMedicomp,sizeof(BOOL),1,file); + fwrite(&MP_SessionName[0],sizeof(char),13,file); + + fwrite(&netGameData.maxLives,sizeof(int),1,file); + fwrite(&netGameData.useSharedLives,sizeof(BOOL),1,file); + + fwrite(&netGameData.pointsForRespawn,sizeof(int),1,file); + fwrite(&netGameData.timeForRespawn,sizeof(int),1,file); + + fwrite(&netGameData.aiKillValues[0],sizeof(int),1,file); + fwrite(&netGameData.aiKillValues[1],sizeof(int),1,file); + fwrite(&netGameData.aiKillValues[2],sizeof(int),1,file); + + fwrite(&netGameData.gameSpeed,sizeof(int),1,file); + + //write the description of the config + //first the length + int length=strlen(MP_Config_Description)+1; + fwrite(&length,sizeof(int),1,file); + //and now the string + fwrite(MP_Config_Description,1,length,file); + + fwrite(&netGameData.preDestroyLights,sizeof(BOOL),1,file); + fwrite(&netGameData.disableFriendlyFire,sizeof(BOOL),1,file); + fwrite(&netGameData.fallingDamage,sizeof(BOOL),1,file); + #if SAVE_NEW_MPCONFIG_ENTRIES + fwrite(&netGameData.maxMarineSmartDisc,sizeof(int),1,file); + fwrite(&netGameData.maxMarinePistols,sizeof(int),1,file); + fwrite(&netGameData.allowSmartDisc,sizeof(BOOL),1,file); + fwrite(&netGameData.allowPistols,sizeof(BOOL),1,file); + fwrite(&netGameData.pistolInfiniteAmmo,sizeof(BOOL),1,file); + fwrite(&netGameData.specialistPistols,sizeof(BOOL),1,file); + #endif + + //write the custom level name (if relevant) + //first the length + length=strlen(netGameData.customLevelName)+1; + fwrite(&length,sizeof(int),1,file); + //and now the string + fwrite(netGameData.customLevelName,1,length,file); + + + fclose(file); + + //clear the last description stuff + delete [] LastDescriptionFile; + delete [] LastDescriptionText; + LastDescriptionFile=0; + LastDescriptionText=0; + +} + + +void DeleteMultiplayerConfigurationByIndex(int index) +{ + if(index<0 || index>= ConfigurationFilenameList.size()) return; + + char filename[200]; + if(netGameData.skirmishMode) + sprintf(filename,"%s\\%s.skirmish_cfg",MP_CONFIG_DIR,ConfigurationFilenameList[index]); + else + sprintf(filename,"%s\\%s.cfg",MP_CONFIG_DIR,ConfigurationFilenameList[index]); + + DeleteFile(filename); +} + + +#define IP_ADDRESS_DIR "IP_Address" +#define IP_ADDRESS_WILDCARD "IP_Address\\*.IP Address" + +static List IPAddFilenameList; + +AVPMENU_ELEMENT* AvPMenu_Multiplayer_LoadIPAddress=0; + +BOOL BuildLoadIPAddressMenu() +{ + //delete the old list of filenames + while(IPAddFilenameList.size()) + { + delete [] IPAddFilenameList.first_entry(); + IPAddFilenameList.delete_first_entry(); + } + + //do a search for all the addresses in the address directory + + const char* load_name=IP_ADDRESS_WILDCARD; + // allow a wildcard search + WIN32_FIND_DATA wfd; + + HANDLE hFindFile = ::FindFirstFile(load_name,&wfd); + + if (INVALID_HANDLE_VALUE == hFindFile) + { + return FALSE; + } + + // get any path in the load_name + int nPathLen = 0; + char * pColon = strrchr(load_name,':'); + if (pColon) nPathLen = pColon - load_name + 1; + char * pBackSlash = strrchr(load_name,'\\'); + if (pBackSlash) + { + int nLen = pBackSlash - load_name + 1; + if (nLen > nPathLen) nPathLen = nLen; + } + char * pSlash = strrchr(load_name,'/'); + if (pSlash) + { + int nLen = pSlash - load_name + 1; + if (nLen > nPathLen) nPathLen = nLen; + } + + do + { + if + ( + !(wfd.dwFileAttributes & + (FILE_ATTRIBUTE_DIRECTORY + |FILE_ATTRIBUTE_SYSTEM + |FILE_ATTRIBUTE_HIDDEN)) + // not a directory, hidden or system file + ) + { + char* name=new char[strlen(wfd.cFileName)+1]; + strcpy(name,wfd.cFileName); + char* dotpos=strchr(name,'.'); + if(dotpos) *dotpos=0; + IPAddFilenameList.add_entry(name); + + } + + }while (::FindNextFile(hFindFile,&wfd)); + + + ::FindClose(hFindFile); + + + //delete the old menu + if(AvPMenu_Multiplayer_LoadIPAddress) delete [] AvPMenu_Multiplayer_LoadIPAddress; + + + //create a new menu from the list of filenames + AvPMenu_Multiplayer_LoadIPAddress=new AVPMENU_ELEMENT[IPAddFilenameList.size()+1]; + + for(int i=0;i0); +} + + +void SaveIPAddress(const char* name,const char* address) +{ + if(!name) return; + if(!address) return; + if(!strlen(name)) return; + if(!strlen(address)) return; + + FILE* file; + char filename[200]; + sprintf(filename,"%s\\%s.IP Address",IP_ADDRESS_DIR,name); + + CreateDirectory(IP_ADDRESS_DIR,0); + file=fopen(filename,"wb"); + if(!file) return; + + fwrite(address,1,strlen(address)+1,file); + + fclose(file); + +} + +void LoadIPAddress(const char* name) +{ + extern char IPAddressString[]; + + + if(!name) return; + + FILE* file; + char filename[200]; + sprintf(filename,"%s\\%s.IP Address",IP_ADDRESS_DIR,name); + + file=fopen(filename,"rb"); + if(!file) return; + + fread(IPAddressString,1,16,file); + IPAddressString[15]=0; + + fclose(file); +} + + + +extern AVPMENU_ELEMENT AvPMenu_Multiplayer_Config[]; +extern AVPMENU_ELEMENT AvPMenu_Skirmish_Config[]; +extern AVPMENU_ELEMENT AvPMenu_Multiplayer_Config_Join[]; + + +int NumCustomLevels = 0; +int NumMultiplayerLevels = 0; +int NumCoopLevels = 0; + +char** MultiplayerLevelNames = 0; +char** CoopLevelNames = 0; + +List CustomLevelNameList; + +void BuildMultiplayerLevelNameArray() +{ + char buffer[256]; + //only want to do this once + if(MultiplayerLevelNames) return; + + //first do a search for custom level rifs + // allow a wildcard search + WIN32_FIND_DATA wfd; + const char* load_name="avp_rifs\\custom\\*.rif"; + + HANDLE hFindFile = ::FindFirstFile(load_name,&wfd); + + if (INVALID_HANDLE_VALUE != hFindFile) + { + char* custom_string = GetTextString(TEXTSTRING_CUSTOM_LEVEL); + do + { + if + ( + !(wfd.dwFileAttributes & + (FILE_ATTRIBUTE_DIRECTORY + |FILE_ATTRIBUTE_SYSTEM + |FILE_ATTRIBUTE_HIDDEN)) + // not a directory, hidden or system file + ) + { + strcpy(buffer,wfd.cFileName); + char* dotpos=strchr(buffer,'.'); + if(dotpos) *dotpos=0; + strcat(buffer," ("); + strcat(buffer,custom_string); + strcat(buffer,")"); + + char* name=new char[strlen(buffer)+1]; + strcpy(name,buffer); + + CustomLevelNameList.add_entry(name); + + } + + }while (::FindNextFile(hFindFile,&wfd)); + + + ::FindClose(hFindFile); + } + + NumCustomLevels = CustomLevelNameList.size(); + + + NumMultiplayerLevels = MAX_NO_OF_MULTIPLAYER_EPISODES + NumCustomLevels; + NumCoopLevels = MAX_NO_OF_COOPERATIVE_EPISODES + NumCustomLevels; + + MultiplayerLevelNames = (char**) AllocateMem(sizeof(char*)* NumMultiplayerLevels); + + int i; + //first the standard multiplayer levels + for(i=0;i=5) + { + //a new level + char* new_string = GetTextString(TEXTSTRING_NEW_LEVEL); + sprintf(buffer,"%s (%s)",level_name,new_string); + + //allocate memory and copy the string. + MultiplayerLevelNames[i] = (char*) AllocateMem(strlen(buffer)+1); + strcpy(MultiplayerLevelNames[i],buffer); + + } + else + { + MultiplayerLevelNames[i] = level_name; + } + } + + + CoopLevelNames = (char**) AllocateMem(sizeof(char*)* NumCoopLevels); + + //and the standard coop levels + for(i=0;i=5) + { + //a new level + char* new_string = GetTextString(TEXTSTRING_NEW_LEVEL); + sprintf(buffer,"%s (%s)",level_name,new_string); + + //allocate memory and copy the string. + CoopLevelNames[i] =(char*) AllocateMem(strlen(buffer)+1); + strcpy(CoopLevelNames[i],buffer); + + } + else + { + CoopLevelNames[i] = level_name; + } + } + + //now add the custom level names + for(i=0;iTextDescription!=TEXTSTRING_MULTIPLAYER_ENVIRONMENT) + { + GLOBALASSERT(elementPtr->ElementID!=AVPMENU_ELEMENT_ENDOFMENU); + elementPtr++; + + } + elementPtr->MaxSliderValue = NumMultiplayerLevels-1; + elementPtr->TextSliderStringPointer = MultiplayerLevelNames; + + elementPtr = AvPMenu_Multiplayer_Config_Join; + //search for the level name element + while(elementPtr->TextDescription!=TEXTSTRING_MULTIPLAYER_ENVIRONMENT) + { + GLOBALASSERT(elementPtr->ElementID!=AVPMENU_ELEMENT_ENDOFMENU); + elementPtr++; + + } + elementPtr->MaxSliderValue = NumMultiplayerLevels-1; + elementPtr->TextSliderStringPointer = MultiplayerLevelNames; + + elementPtr = AvPMenu_Skirmish_Config; + //search for the level name element + while(elementPtr->TextDescription!=TEXTSTRING_MULTIPLAYER_ENVIRONMENT) + { + GLOBALASSERT(elementPtr->ElementID!=AVPMENU_ELEMENT_ENDOFMENU); + elementPtr++; + + } + elementPtr->MaxSliderValue = NumMultiplayerLevels-1; + elementPtr->TextSliderStringPointer = MultiplayerLevelNames; + +} + + +//returns local index of a custom level (if it is a custom level) +int GetCustomMultiplayerLevelIndex(char* name,int gameType) +{ + char buffer[256]; + //tack ( custom) onto the end of the name , before doing the string compare + char* custom_string = GetTextString(TEXTSTRING_CUSTOM_LEVEL); + sprintf(buffer,"%s (%s)",name,custom_string); + + //find the index of a custom level from its name + if(gameType==NGT_Coop) + { + for(int i=MAX_NO_OF_COOPERATIVE_EPISODES;i=MAX_NO_OF_COOPERATIVE_EPISODES) + { + strcpy(return_string,CoopLevelNames[index]); + } + } + else + { + if(index>=MAX_NO_OF_MULTIPLAYER_EPISODES) + { + strcpy(return_string,MultiplayerLevelNames[index]); + } + } + + //need to remove ' (custom)' from the end of the level name + char* bracket_pos = strrchr(return_string,'('); + if(bracket_pos) + { + bracket_pos --; //to get back to the space + *bracket_pos = 0; + + } + + + return return_string; +} + + +int GetLocalMultiplayerLevelIndex(int index,char* customLevelName,int gameType) +{ + if(customLevelName[0] == 0) + { + //not a custom level , just need to check to see if the level index is in range + if(gameType==NGT_Coop) + { + if(index0) UserProfileNumber=1; + else UserProfileNumber=0; +} + +extern void MakeConnectionSelectMenu() +{ + int pos=0; + + if(netGameData.tcpip_available) + { + AvPMenu_MultiplayerConnection[pos].ElementID = AVPMENU_ELEMENT_CONNECTIONCHOICE; + AvPMenu_MultiplayerConnection[pos].TextDescription = TEXTSTRING_MULTIPLAYER_TCPIP; + AvPMenu_MultiplayerConnection[pos].MenuToGoTo = AVPMENU_MULTIPLAYER; + AvPMenu_MultiplayerConnection[pos].Value = CONN_TCPIP; + AvPMenu_MultiplayerConnection[pos].HelpString = TEXTSTRING_MULTIPLAYER_PROTOCOL_HELP; + pos++; + } + if(netGameData.ipx_available) + { + AvPMenu_MultiplayerConnection[pos].ElementID = AVPMENU_ELEMENT_CONNECTIONCHOICE; + AvPMenu_MultiplayerConnection[pos].TextDescription = TEXTSTRING_MULTIPLAYER_IPX; + AvPMenu_MultiplayerConnection[pos].MenuToGoTo = AVPMENU_MULTIPLAYER; + AvPMenu_MultiplayerConnection[pos].Value = CONN_IPX; + AvPMenu_MultiplayerConnection[pos].HelpString = TEXTSTRING_MULTIPLAYER_PROTOCOL_HELP; + pos++; + } + if(netGameData.modem_available) + { + AvPMenu_MultiplayerConnection[pos].ElementID = AVPMENU_ELEMENT_CONNECTIONCHOICE; + AvPMenu_MultiplayerConnection[pos].TextDescription = TEXTSTRING_MULTIPLAYER_MODEM; + AvPMenu_MultiplayerConnection[pos].MenuToGoTo = AVPMENU_MULTIPLAYER; + AvPMenu_MultiplayerConnection[pos].Value = CONN_Modem; + AvPMenu_MultiplayerConnection[pos].HelpString = TEXTSTRING_MULTIPLAYER_PROTOCOL_HELP; + pos++; + } + if(netGameData.serial_available) + { + AvPMenu_MultiplayerConnection[pos].ElementID = AVPMENU_ELEMENT_CONNECTIONCHOICE; + AvPMenu_MultiplayerConnection[pos].TextDescription = TEXTSTRING_MULTIPLAYER_SERIAL; + AvPMenu_MultiplayerConnection[pos].MenuToGoTo = AVPMENU_MULTIPLAYER; + AvPMenu_MultiplayerConnection[pos].Value = CONN_Serial; + AvPMenu_MultiplayerConnection[pos].HelpString = TEXTSTRING_MULTIPLAYER_PROTOCOL_HELP; + pos++; + } + #if MPLAYER_SUPPORT + //if(!LobbiedGame) + //Add an option for launching a game using mplayer + { + AvPMenu_MultiplayerConnection[pos].ElementID = AVPMENU_ELEMENT_CONNECTIONCHOICE; + AvPMenu_MultiplayerConnection[pos].TextDescription = TEXTSTRING_MPLAYER_TEXT_1; + AvPMenu_MultiplayerConnection[pos].MenuToGoTo = AVPMENU_MULTIPLAYER; + AvPMenu_MultiplayerConnection[pos].Value = CONN_Mplayer; + pos++; + } + #endif + + + + if(pos==0) + { + //no available connections + AvPMenu_MultiplayerConnection[0].ElementID = AVPMENU_ELEMENT_GOTOMENU; + AvPMenu_MultiplayerConnection[0].TextDescription = TEXTSTRING_MULTIPLAYER_NOCONNECTIONS; + AvPMenu_MultiplayerConnection[0].MenuToGoTo = AVPMENU_MAIN; + AvPMenu_MultiplayerConnection[pos].HelpString = TEXTSTRING_MULTIPLAYER_NOCONNECTIONS_HELP; + + pos=1; + } + AvPMenu_MultiplayerConnection[pos].ElementID = AVPMENU_ELEMENT_ENDOFMENU; +} + +extern void MakeOpenIPAddressMenu() +{ + IP_Address_Name[0]=0; + //determine whether the load ip address option should be available + if(BuildLoadIPAddressMenu()) + { + AvPMenu_MultiplayerOpenAddress[3].ElementID=AVPMENU_ELEMENT_GOTOMENU; + } + else + { + AvPMenu_MultiplayerOpenAddress[3].ElementID=AVPMENU_ELEMENT_ENDOFMENU; + } + +} + + + diff --git a/3dc/avp/win95/Frontend/AvP_MenuGfx.cpp b/3dc/avp/win95/Frontend/AvP_MenuGfx.cpp new file mode 100644 index 0000000..3d16379 --- /dev/null +++ b/3dc/avp/win95/Frontend/AvP_MenuGfx.cpp @@ -0,0 +1,1852 @@ +#include "3dc.h" +#include "inline.h" + +#include "tallfont.hpp" +#include "strtab.hpp" + +#include "awTexLd.h" +#include "alt_tab.h" + +#include "chnktexi.h" +#include "hud_layout.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "ffstdio.h" + + +extern void D3D_RenderHUDString(char *stringPtr,int x,int y,int colour); + +extern "C" +{ +#include "AvP_Menus.h" +extern unsigned char *ScreenBuffer; +extern long BackBufferPitch; +extern DDPIXELFORMAT DisplayPixelFormat; +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + +char AAFontWidths[256]; + +AVPMENUGFX AvPMenuGfxStorage[MAX_NO_OF_AVPMENUGFXS] = +{ + {"Menus\\fractal.rim"}, + {"Common\\aa_font.rim"},// Warning! Texture from common used + + {"Menus\\copyright.rim"}, + + {"Menus\\FIandRD.rim"}, + {"Menus\\presents.rim"}, + {"Menus\\AliensVPredator.rim"}, + + {"Menus\\sliderbar.rim"},//AVPMENUGFX_SLIDERBAR, + {"Menus\\slider.rim"},//AVPMENUGFX_SLIDER, + + {"Menus\\starfield.rim"}, + {"Menus\\aliens.rim"}, + {"Menus\\Alien.rim"}, + {"Menus\\Marine.rim"}, + {"Menus\\Predator.rim"}, + + {"Menus\\glowy_left.rim"}, + {"Menus\\glowy_middle.rim"}, + {"Menus\\glowy_right.rim"}, + + // Marine level + {"Menus\\MarineEpisode1.rim"}, + {"Menus\\MarineEpisode2.rim"}, + {"Menus\\MarineEpisode3.rim"}, + {"Menus\\MarineEpisode4.rim"}, + {"Menus\\MarineEpisode5.rim"}, + {"Menus\\MarineEpisode6.rim"}, + {"Menus\\bonus.rim"}, + {"Menus\\bonus.rim"}, + {"Menus\\bonus.rim"}, + {"Menus\\bonus.rim"}, + {"Menus\\bonus.rim"}, + + // Predator level + {"Menus\\PredatorEpisode1.rim"}, + {"Menus\\PredatorEpisode2.rim"}, + {"Menus\\PredatorEpisode3.rim"}, + {"Menus\\PredatorEpisode4.rim"}, + {"Menus\\PredatorEpisode5.rim"}, + {"Menus\\PredatorEpisode5.rim"}, + {"Menus\\bonus.rim"}, + {"Menus\\bonus.rim"}, + {"Menus\\bonus.rim"}, + {"Menus\\bonus.rim"}, + {"Menus\\bonus.rim"}, + + // Alien level + {"Menus\\AlienEpisode2.rim"}, + {"Menus\\AlienEpisode4.rim"}, + {"Menus\\AlienEpisode1.rim"}, + {"Menus\\AlienEpisode3.rim"}, + {"Menus\\AlienEpisode5.rim"}, + {"Menus\\bonus.rim"}, + {"Menus\\bonus.rim"}, + {"Menus\\bonus.rim"}, + {"Menus\\bonus.rim"}, + {"Menus\\bonus.rim"}, + + // Splash screens + #if MARINE_DEMO + {"MarineSplash\\splash00.rim"}, + {"MarineSplash\\splash01.rim"}, + {"MarineSplash\\splash02.rim"}, + {"MarineSplash\\splash03.rim"}, + {"MarineSplash\\splash04.rim"}, + {"MarineSplash\\splash05.rim"}, + #elif ALIEN_DEMO + {"AlienSplash\\splash00.rim"}, + {"AlienSplash\\splash01.rim"}, + {"AlienSplash\\splash02.rim"}, + {"AlienSplash\\splash03.rim"}, + {"AlienSplash\\splash04.rim"}, + {"AlienSplash\\splash05.rim"}, + #else + {"PredatorSplash\\splash00.rim"}, + {"PredatorSplash\\splash01.rim"}, + {"PredatorSplash\\splash02.rim"}, + {"PredatorSplash\\splash03.rim"}, + {"PredatorSplash\\splash04.rim"}, + {"PredatorSplash\\splash05.rim"}, + #endif +}; + +static void LoadMenuFont(void); +static void UnloadMenuFont(void); +static int RenderSmallFontString(char *textPtr,int sx,int sy,int alpha, int red, int green, int blue); +static void CalculateWidthsOfAAFont(void); +extern void DrawAvPMenuGlowyBar(int topleftX, int topleftY, int alpha, int length); +extern void DrawAvPMenuGlowyBar_Clipped(int topleftX, int topleftY, int alpha, int length, int topY, int bottomY); +static void LoadMenuFont(void) +{ + char buffer[100]; + IndexedFont_Kerned_Column :: Create + ( + IntroFont_Light, // FontIndex I_Font_New, + CL_GetImageFileName(buffer, 100, "Menus\\IntroFont.rim", LIO_RELATIVEPATH), + 33,//21, // int HeightPerChar_New, + 5, // int SpaceWidth_New, + 32 // ASCIICodeForInitialCharacter + ); +} + +static void UnloadMenuFont(void) +{ + IndexedFont :: UnloadFont( IntroFont_Light ); +} +extern int LengthOfMenuText(char *textPtr) +{ + IndexedFont* pFont = IndexedFont :: GetFont(IntroFont_Light); + + return (pFont->CalcSize(textPtr).w); +} + +extern int RenderMenuText(char *textPtr, int x, int y, int alpha, enum AVPMENUFORMAT_ID format) +{ + IndexedFont* pFont = IndexedFont :: GetFont(IntroFont_Light); + r2pos R2Pos_StartOfRow; + switch(format) + { + default: + GLOBALASSERT("UNKNOWN TEXT FORMAT"==0); + case AVPMENUFORMAT_LEFTJUSTIFIED: + { + // supplied x is correct + break; + } + case AVPMENUFORMAT_RIGHTJUSTIFIED: + { + x -= (pFont->CalcSize(textPtr).w); + break; + } + case AVPMENUFORMAT_CENTREJUSTIFIED: + { + x -= (pFont->CalcSize(textPtr).w)/2; + break; + } + } + + LOCALASSERT(x>0); + + if (alpha >BRIGHTNESS_OF_DARKENED_ELEMENT) + { + int size = pFont->CalcSize(textPtr).w - 18; + if (size<18) size = 18; + DrawAvPMenuGfx(AVPMENUGFX_GLOWY_LEFT,x+18,y-8,alpha,AVPMENUFORMAT_RIGHTJUSTIFIED); + DrawAvPMenuGlowyBar(x+18,y-8,alpha,size-18); +// for (int i=18; i RenderString_Unclipped + ( + R2Pos_StartOfRow, // struct r2pos& R2Pos_Cursor, + alpha, // int FixP_Alpha, + *pSCString_Name // const SCString& SCStr + ); + + pSCString_Name -> R_Release(); + } + + } + return R2Pos_StartOfRow.x; +} +extern int RenderMenuText_Clipped(char *textPtr, int x, int y, int alpha, enum AVPMENUFORMAT_ID format, int topY, int bottomY) +{ + IndexedFont* pFont = IndexedFont :: GetFont(IntroFont_Light); + r2pos R2Pos_StartOfRow; + switch(format) + { + default: + GLOBALASSERT("UNKNOWN TEXT FORMAT"==0); + case AVPMENUFORMAT_LEFTJUSTIFIED: + { + // supplied x is correct + break; + } + case AVPMENUFORMAT_RIGHTJUSTIFIED: + { + x -= (pFont->CalcSize(textPtr).w); + break; + } + case AVPMENUFORMAT_CENTREJUSTIFIED: + { + x -= (pFont->CalcSize(textPtr).w)/2; + break; + } + } + + LOCALASSERT(x>0); + + if (alpha > BRIGHTNESS_OF_DARKENED_ELEMENT) + { + int size = pFont->CalcSize(textPtr).w - 18; + if (size<18) size = 18; + DrawAvPMenuGfx_Clipped(AVPMENUGFX_GLOWY_LEFT,x+18,y-8,alpha,AVPMENUFORMAT_RIGHTJUSTIFIED,topY,bottomY); + DrawAvPMenuGlowyBar_Clipped(x+18,y-8,alpha,size-18,topY,bottomY); + DrawAvPMenuGfx_Clipped(AVPMENUGFX_GLOWY_RIGHT,x+size,y-8,alpha,AVPMENUFORMAT_LEFTJUSTIFIED,topY,bottomY); + } + + R2Pos_StartOfRow = r2pos(x,y); + const struct r2rect R2Rect_Clip = r2rect(0,topY,0,bottomY); + { + { + SCString* pSCString_Name = new SCString(textPtr); + + pFont -> RenderString_Clipped + ( + R2Pos_StartOfRow, // struct r2pos& R2Pos_Cursor, + R2Rect_Clip, //const struct r2rect& R2Rect_Clip + alpha, // int FixP_Alpha, + *pSCString_Name // const SCString& SCStr + ); + + pSCString_Name -> R_Release(); + } + + } + return R2Pos_StartOfRow.x; +} + + +extern int RenderSmallMenuText(char *textPtr, int x, int y, int alpha, enum AVPMENUFORMAT_ID format) +{ + switch(format) + { + default: + GLOBALASSERT("UNKNOWN TEXT FORMAT"==0); + case AVPMENUFORMAT_LEFTJUSTIFIED: + { + // supplied x is correct + break; + } + case AVPMENUFORMAT_RIGHTJUSTIFIED: + { + int length = 0; + char *ptr = textPtr; + + while(*ptr) + { + length+=AAFontWidths[*ptr++]; + } + + x -= length; + break; + } + case AVPMENUFORMAT_CENTREJUSTIFIED: + { + int length = 0; + char *ptr = textPtr; + + while(*ptr) + { + length+=AAFontWidths[*ptr++]; + } + + x -= length/2; + break; + } + } + + LOCALASSERT(x>0); + + x = RenderSmallFontString(textPtr,x,y,alpha,ONE_FIXED,ONE_FIXED,ONE_FIXED); + return x; +} +extern int RenderSmallMenuText_Coloured(char *textPtr, int x, int y, int alpha, enum AVPMENUFORMAT_ID format, int red, int green, int blue) +{ + switch(format) + { + default: + GLOBALASSERT("UNKNOWN TEXT FORMAT"==0); + case AVPMENUFORMAT_LEFTJUSTIFIED: + { + // supplied x is correct + break; + } + case AVPMENUFORMAT_RIGHTJUSTIFIED: + { + int length = 0; + char *ptr = textPtr; + + while(*ptr) + { + length+=AAFontWidths[*ptr++]; + } + + x -= length; + break; + } + case AVPMENUFORMAT_CENTREJUSTIFIED: + { + int length = 0; + char *ptr = textPtr; + + while(*ptr) + { + length+=AAFontWidths[*ptr++]; + } + + x -= length/2; + break; + } + } + + LOCALASSERT(x>0); + + x = RenderSmallFontString(textPtr,x,y,alpha,red,green,blue); + return x; +} + +extern int Hardware_RenderSmallMenuText(char *textPtr, int x, int y, int alpha, enum AVPMENUFORMAT_ID format) +{ + switch(format) + { + default: + GLOBALASSERT("UNKNOWN TEXT FORMAT"==0); + case AVPMENUFORMAT_LEFTJUSTIFIED: + { + // supplied x is correct + break; + } + case AVPMENUFORMAT_RIGHTJUSTIFIED: + { + int length = 0; + char *ptr = textPtr; + + while(*ptr) + { + length+=AAFontWidths[*ptr++]; + } + + x -= length; + break; + } + case AVPMENUFORMAT_CENTREJUSTIFIED: + { + int length = 0; + char *ptr = textPtr; + + while(*ptr) + { + length+=AAFontWidths[*ptr++]; + } + + x -= length/2; + break; + } + } + + LOCALASSERT(x>0); + + { + unsigned int colour = alpha>>8; + if (colour>255) colour = 255; + colour = (colour<<24)+0xffffff; + D3D_RenderHUDString(textPtr,x,y,colour); + } + return x; +} + +extern int Hardware_RenderSmallMenuText_Coloured(char *textPtr, int x, int y, int alpha, enum AVPMENUFORMAT_ID format, int red, int green, int blue) +{ + switch(format) + { + default: + GLOBALASSERT("UNKNOWN TEXT FORMAT"==0); + case AVPMENUFORMAT_LEFTJUSTIFIED: + { + // supplied x is correct + break; + } + case AVPMENUFORMAT_RIGHTJUSTIFIED: + { + int length = 0; + char *ptr = textPtr; + + while(*ptr) + { + length+=AAFontWidths[*ptr++]; + } + + x -= length; + break; + } + case AVPMENUFORMAT_CENTREJUSTIFIED: + { + int length = 0; + char *ptr = textPtr; + + while(*ptr) + { + length+=AAFontWidths[*ptr++]; + } + + x -= length/2; + break; + } + } + + LOCALASSERT(x>0); + + { + unsigned int colour = alpha>>8; + if (colour>255) colour = 255; + colour = (colour<<24); + colour += MUL_FIXED(red,255)<<16; + colour += MUL_FIXED(green,255)<<8; + colour += MUL_FIXED(blue,255); + D3D_RenderHUDString(textPtr,x,y,colour); + } + return x; +} + +extern void Hardware_RenderKeyConfigRectangle(int alpha) +{ + extern void D3D_DrawRectangle(int x, int y, int w, int h, int alpha); + D3D_DrawRectangle(10,ScreenDescriptorBlock.SDB_Height/2+25-115,ScreenDescriptorBlock.SDB_Width-20,250,alpha); +} +extern void RenderKeyConfigRectangle(int alpha) +{ + int x1 = 10; + int x2 = ScreenDescriptorBlock.SDB_Width-10; + int y1 = ScreenDescriptorBlock.SDB_Height/2+25-115; + int y2 = ScreenDescriptorBlock.SDB_Height/2+25-115+250; + int x,y; + int c; + + c = MUL_FIXED(DisplayPixelFormat.dwRBitMask,alpha) & DisplayPixelFormat.dwRBitMask; + c |= MUL_FIXED(DisplayPixelFormat.dwGBitMask,alpha) & DisplayPixelFormat.dwGBitMask; + c |= MUL_FIXED(DisplayPixelFormat.dwBBitMask,alpha) & DisplayPixelFormat.dwBBitMask; + + y=y1; + { + unsigned short *destPtr = (unsigned short *)(ScreenBuffer + x1*2 + y*BackBufferPitch); + + for (x=x1; x<=x2; x++) + { + *destPtr |= c; + destPtr++; + } + } + y=y2; + { + unsigned short *destPtr = (unsigned short *)(ScreenBuffer + x1*2 + y*BackBufferPitch); + + for (x=x1; x<=x2; x++) + { + *destPtr |= c; + destPtr++; + } + } + { + + for (y=y1+1; yImagePtr; + + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdimage.dwSize = sizeof(ddsdimage); + + /* lock the image */ + while (surface->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + + while( *textPtr ) + { + char c = *textPtr++; + + if (c>=' ') + { + int topLeftU = 1+((c-32)&15)*16; + int topLeftV = 1+((c-32)>>4)*16; + + srcPtr = (unsigned short *)(ddsdimage.lpSurface) + (topLeftU)+(topLeftV*ddsdimage.lPitch/2); + + int x,y; + + for (y=sy; yDisplayPixelFormat.dwRBitMask) destR = DisplayPixelFormat.dwRBitMask; + else destR &= DisplayPixelFormat.dwRBitMask; + + destG += MUL_FIXED(alphaG,srcG); + if (destG>DisplayPixelFormat.dwGBitMask) destG = DisplayPixelFormat.dwGBitMask; + else destG &= DisplayPixelFormat.dwGBitMask; + + destB += MUL_FIXED(alphaB,srcB); + if (destB>DisplayPixelFormat.dwBBitMask) destB = DisplayPixelFormat.dwBBitMask; + else destB &= DisplayPixelFormat.dwBBitMask; + + *destPtr = (short)(destR|destG|destB); + } + destPtr++; + srcPtr++; + } + srcPtr += (ddsdimage.lPitch/2) - HUD_FONT_WIDTH; + } + sx += AAFontWidths[c]; + #if 0 + if(c!=32) + { + extra += 8-AAFontWidths[c]; + } + else + { + sx+=extra+8-AAFontWidths[c]; + extra=0; + } + #endif + } + } + + surface->Unlock((LPVOID)ddsdimage.lpSurface); + return sx; +} + + +extern void RenderSmallFontString_Wrapped(char *textPtr,RECT* area,int alpha,int* output_x,int* output_y) +{ + DDSURFACEDESC ddsdimage; + unsigned short *destPtr; + unsigned short *srcPtr; + int extra = 0; + AVPMENUGFX *gfxPtr; + LPDIRECTDRAWSURFACE surface; + int wordWidth; + + + int sx=area->left; + int sy=area->top; + + gfxPtr = &AvPMenuGfxStorage[AVPMENUGFX_SMALL_FONT]; + surface = gfxPtr->ImagePtr; + + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdimage.dwSize = sizeof(ddsdimage); + + /* lock the image */ + while (surface->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + + /* + Determine area used by text , so we can draw it centrally + */ + { + char* textPtr2=textPtr; + while( *textPtr2) + { + //find the width of the next word + int widthFromSpaces=0; + int widthFromChars=0; + + // get width used by spaces before this word + while(*textPtr2 && *textPtr2==' ') + { + widthFromSpaces+=AAFontWidths[*textPtr2++]; + } + + //get width used by word + while(*textPtr2 && *textPtr2!=' ') + { + widthFromChars+=AAFontWidths[*textPtr2++]; + } + wordWidth=widthFromSpaces+widthFromChars; + + if(wordWidth> area->right-sx) + { + if(wordWidth >area->right-area->left) + { + int extraLinesNeeded=0; + //word is too long too fit on one line , so it will have to be split + wordWidth-=(area->right-sx); + + //advance to the beginning of the next line + sy+=HUD_FONT_HEIGHT; + sx=area->left; + + //see how many extra whole lines are equired + extraLinesNeeded=wordWidth/(area->right-area->left); + + sy+=HUD_FONT_HEIGHT*extraLinesNeeded; + wordWidth %= (area->right-area->left); + + //make sure we haven't gone off the bottom + if(sy+HUD_FONT_HEIGHT> area->bottom) break; + + + } + else + { + //word to long to fit on this line , so go to next line + sy+=HUD_FONT_HEIGHT; + sx=area->left; + + //make sure we haven't gone off the bottom + if(sy+HUD_FONT_HEIGHT> area->bottom) break; + + //make sure the word will fit on a line anyway + if(wordWidth> area->right-sx) break; + + //don't bother drawing spaces at the start of the new line + wordWidth-=widthFromSpaces; + } + + } + sx+=wordWidth; + } + + //if the string fits on one line , centre it horizontally + if(sy==area->top) + { + sx=area->left+ (area->right-sx)/2; + } + else + { + sx=area->left; + } + + //centre string vertically + sy+=HUD_FONT_HEIGHT; + if(sybottom) + { + sy=area->top + (area->bottom-sy)/2; + } + else + { + sy=area->top; + } + + } + + + + while( *textPtr ) + { + //find the width of the next word + char* textPtr2=textPtr; + wordWidth=0; + + // get width used by spaces before this word + while(*textPtr2 && *textPtr2==' ') + { + wordWidth+=AAFontWidths[*textPtr2++]; + } + + //get width used by word + while(*textPtr2 && *textPtr2!=' ') + { + wordWidth+=AAFontWidths[*textPtr2++]; + } + + if(wordWidth> area->right-sx) + { + if(wordWidth>area->right - area->left) + { + //word is too long too fit on one line , so we'll just have to allow it to be split + } + else + { + //word to long to fit on this line , so go to next line + sy+=HUD_FONT_HEIGHT; + sx=area->left; + + //make sure we haven't gone off the bottom + if(sy+HUD_FONT_HEIGHT> area->bottom) break; + + //make sure the word will fit on a line anyway + if(wordWidth> area->right-sx) break; + + //don't bother drawing spaces at the start of the new line + while(*textPtr && *textPtr==' ') + { + *textPtr++; + } + } + + } + + //'render' the spaces + while(*textPtr && *textPtr==' ') + { + sx+=AAFontWidths[*textPtr++]; + } + + if(sx>area->right) + { + //gone of the end of the line doing spaces + while(sx>area->right) + { + sx-=(area->right-area->left); + sy+=HUD_FONT_HEIGHT; + } + //make sure we haven't gone off the bottom + if(sy+HUD_FONT_HEIGHT> area->bottom) break; + + } + + //render this word + while(*textPtr && *textPtr!=' ') + { + char c = *textPtr++; + int letterWidth = AAFontWidths[c]; + + if(sx+letterWidth>area->right) + { + //need to go on to the next line + sx=area->left; + sy+=HUD_FONT_HEIGHT; + + //make sure we haven't gone off the bottom + if(sy+HUD_FONT_HEIGHT> area->bottom) break; + + } + + if (c>=' ' || c<='z') + { + int topLeftU = 1+((c-32)&15)*16; + int topLeftV = 1+((c-32)>>4)*16; + + srcPtr = (unsigned short *)(ddsdimage.lpSurface) + (topLeftU)+(topLeftV*ddsdimage.lPitch/2); + + int x,y; + + for (y=sy; yDisplayPixelFormat.dwRBitMask) destR = DisplayPixelFormat.dwRBitMask; + else destR &= DisplayPixelFormat.dwRBitMask; + + destG += MUL_FIXED(alpha,srcG); + if (destG>DisplayPixelFormat.dwGBitMask) destG = DisplayPixelFormat.dwGBitMask; + else destG &= DisplayPixelFormat.dwGBitMask; + + destB += MUL_FIXED(alpha,srcB); + if (destB>DisplayPixelFormat.dwBBitMask) destB = DisplayPixelFormat.dwBBitMask; + else destB &= DisplayPixelFormat.dwBBitMask; + + *destPtr = (short)(destR|destG|destB); + } + destPtr++; + srcPtr++; + } + srcPtr += (ddsdimage.lPitch/2) - HUD_FONT_WIDTH; + } + sx += AAFontWidths[c]; + #if 0 + if(c!=32) + { + extra += 8-AAFontWidths[c]; + } + else + { + sx+=extra+8-AAFontWidths[c]; + extra=0; + } + #endif + } + } + } + + surface->Unlock((LPVOID)ddsdimage.lpSurface); + + if(output_x) *output_x=sx; + if(output_y) *output_y=sy; +} + + + +extern void LoadAvPMenuGfx(enum AVPMENUGFX_ID menuGfxID) +{ + AVPMENUGFX *gfxPtr; + char buffer[100]; + + GLOBALASSERT(menuGfxID < MAX_NO_OF_AVPMENUGFXS); + + gfxPtr = &AvPMenuGfxStorage[menuGfxID]; + + CL_GetImageFileName(buffer, 100, gfxPtr->FilenamePtr, LIO_RELATIVEPATH); + + //see if graphic can be found in fast file + unsigned int fastFileLength; + void const * pFastFileData = ffreadbuf(buffer,&fastFileLength); + + if(pFastFileData) + { + //load from fast file + #if 0 + gfxPtr->ImagePtr = AwCreateSurface + ( + "pxfXYB", + pFastFileData, + fastFileLength, + AW_TLF_TRANSP|AW_TLF_CHROMAKEY, + &(gfxPtr->Width), + &(gfxPtr->Height), + &(gfxPtr->hBackup) + ); + #else + gfxPtr->ImagePtr = AwCreateSurface + ( + "pxfXY", + pFastFileData, + fastFileLength, + AW_TLF_TRANSP|AW_TLF_CHROMAKEY, + &(gfxPtr->Width), + &(gfxPtr->Height) + ); + #endif + } + else + { + //load graphic from rim file + gfxPtr->ImagePtr = AwCreateSurface + ( + "sfXYB", + buffer, + AW_TLF_TRANSP|AW_TLF_CHROMAKEY, + &(gfxPtr->Width), + &(gfxPtr->Height), + &(gfxPtr->hBackup) + ); + } + GLOBALASSERT(gfxPtr->ImagePtr); +// GLOBALASSERT(gfxPtr->hBackup); + GLOBALASSERT(gfxPtr->Width>0); + GLOBALASSERT(gfxPtr->Height>0); + gfxPtr->hBackup=0; +// ATIncludeSurface(gfxPtr->ImagePtr,gfxPtr->hBackup); +} + +static void ReleaseAvPMenuGfx(enum AVPMENUGFX_ID menuGfxID) +{ + AVPMENUGFX *gfxPtr; + + GLOBALASSERT(menuGfxID < MAX_NO_OF_AVPMENUGFXS); + + gfxPtr = &AvPMenuGfxStorage[menuGfxID]; + + GLOBALASSERT(gfxPtr); + GLOBALASSERT(gfxPtr->ImagePtr); + + // ATRemoveSurface(gfxPtr->ImagePtr); + ReleaseDDSurface(gfxPtr->ImagePtr); + + gfxPtr->ImagePtr = NULL; + #if 0 + if (gfxPtr->hBackup) + { + AwDestroyBackupTexture(gfxPtr->hBackup); + gfxPtr->hBackup = NULL; + } + #endif +} + +extern void LoadAllAvPMenuGfx(void) +{ + int i = 0; + while(iImagePtr; + + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdimage.dwSize = sizeof(ddsdimage); + + /* lock the image */ + while (surface->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + srcPtr = (unsigned short *)ddsdimage.lpSurface; + + { + int x,y; + + for (y=0; yHeight; y++) + { + for (x=0; xWidth; x++) + { + extern int CloudTable[128][128]; + int r = (int)(*srcPtr) & DisplayPixelFormat.dwRBitMask; +// int g = (int)(*srcPtr) & DisplayPixelFormat.dwGBitMask; +// int b = (int)(*srcPtr) & DisplayPixelFormat.dwBBitMask; + r = DIV_FIXED(r,DisplayPixelFormat.dwRBitMask); +// g = DIV_FIXED(g,DisplayPixelFormat.dwGBitMask); +// b = DIV_FIXED(b,DisplayPixelFormat.dwBBitMask); + CloudTable[x][y]=r; +// CloudTable[x][y]=g; +// CloudTable[x][y]=b; + srcPtr++; + } + srcPtr += (ddsdimage.lPitch/2) - gfxPtr->Width; + } + } + + surface->Unlock((LPVOID)ddsdimage.lpSurface); + } + CalculateWidthsOfAAFont(); +} +extern void LoadAllSplashScreenGfx(void) +{ + int i = AVPMENUGFX_SPLASH_SCREEN1; + while(iImagePtr; + + switch(format) + { + default: + GLOBALASSERT("UNKNOWN TEXT FORMAT"==0); + case AVPMENUFORMAT_LEFTJUSTIFIED: + { + // supplied x is correct + break; + } + case AVPMENUFORMAT_RIGHTJUSTIFIED: + { + topleftX -= gfxPtr->Width; + break; + } + case AVPMENUFORMAT_CENTREJUSTIFIED: + { + topleftX -= gfxPtr->Width/2; + break; + } + } + + + + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdimage.dwSize = sizeof(ddsdimage); + + /* lock the image */ + while (surface->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + srcPtr = (unsigned short *)ddsdimage.lpSurface; + int length = gfxPtr->Width; + + if (ScreenDescriptorBlock.SDB_Width - topleftX < length) + { + length = ScreenDescriptorBlock.SDB_Width - topleftX; + } + if (length<=0) return; + + if (alpha>ONE_FIXED) + { + int x,y; + + for (y=topleftY; yHeight+topleftY; y++) + { + destPtr = (unsigned short *)(ScreenBuffer + topleftX*2 + y*BackBufferPitch); + + for (x=0; xHeight+topleftY; y++) + { + destPtr = (unsigned short *)(ScreenBuffer + topleftX*2 + y*BackBufferPitch); + + for (x=0; xDisplayPixelFormat.dwRBitMask) destR = DisplayPixelFormat.dwRBitMask; + else destR &= DisplayPixelFormat.dwRBitMask; + + destG += MUL_FIXED(alpha,srcG); + if (destG>DisplayPixelFormat.dwGBitMask) destG = DisplayPixelFormat.dwGBitMask; + else destG &= DisplayPixelFormat.dwGBitMask; + + destB += MUL_FIXED(alpha,srcB); + if (destB>DisplayPixelFormat.dwBBitMask) destB = DisplayPixelFormat.dwBBitMask; + else destB &= DisplayPixelFormat.dwBBitMask; + + *destPtr = (short)(destR|destG|destB); + } + destPtr++; + srcPtr++; + } + srcPtr += (ddsdimage.lPitch/2) - length; + } + } + + surface->Unlock((LPVOID)ddsdimage.lpSurface); + + UnlockSurface(); +} +extern void DrawAvPMenuGlowyBar(int topleftX, int topleftY, int alpha, int length) +{ + enum AVPMENUGFX_ID menuGfxID = AVPMENUGFX_GLOWY_MIDDLE; + LockSurfaceAndGetBufferPointer(); + + DDSURFACEDESC ddsdimage; + unsigned short *destPtr; + unsigned short *srcPtr; + AVPMENUGFX *gfxPtr; + LPDIRECTDRAWSURFACE surface; + + GLOBALASSERT(menuGfxID < MAX_NO_OF_AVPMENUGFXS); + gfxPtr = &AvPMenuGfxStorage[menuGfxID]; + surface = gfxPtr->ImagePtr; + + + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdimage.dwSize = sizeof(ddsdimage); + + /* lock the image */ + while (surface->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + srcPtr = (unsigned short *)ddsdimage.lpSurface; + + if (ScreenDescriptorBlock.SDB_Width - topleftX < length) + { + length = ScreenDescriptorBlock.SDB_Width - topleftX; + } + + if (length<0) length = 0; + + if (alpha>ONE_FIXED) + { + int x,y; + + for (y=topleftY; yHeight+topleftY; y++) + { + destPtr = (unsigned short *)(ScreenBuffer + topleftX*2 + y*BackBufferPitch); + + for (x=0; xHeight+topleftY; y++) + { + destPtr = (unsigned short *)(ScreenBuffer + topleftX*2 + y*BackBufferPitch); + + for (x=0; xDisplayPixelFormat.dwRBitMask) destR = DisplayPixelFormat.dwRBitMask; + else destR &= DisplayPixelFormat.dwRBitMask; + + destG += MUL_FIXED(alpha,srcG); + if (destG>DisplayPixelFormat.dwGBitMask) destG = DisplayPixelFormat.dwGBitMask; + else destG &= DisplayPixelFormat.dwGBitMask; + + destB += MUL_FIXED(alpha,srcB); + if (destB>DisplayPixelFormat.dwBBitMask) destB = DisplayPixelFormat.dwBBitMask; + else destB &= DisplayPixelFormat.dwBBitMask; + + *destPtr = (short)(destR|destG|destB); + } + destPtr++; + } + srcPtr += (ddsdimage.lPitch/2); + } + } + + surface->Unlock((LPVOID)ddsdimage.lpSurface); + + UnlockSurface(); +} +extern void DrawAvPMenuGlowyBar_Clipped(int topleftX, int topleftY, int alpha, int length, int topY, int bottomY) +{ + enum AVPMENUGFX_ID menuGfxID = AVPMENUGFX_GLOWY_MIDDLE; + LockSurfaceAndGetBufferPointer(); + + DDSURFACEDESC ddsdimage; + unsigned short *destPtr; + unsigned short *srcPtr; + AVPMENUGFX *gfxPtr; + LPDIRECTDRAWSURFACE surface; + + GLOBALASSERT(menuGfxID < MAX_NO_OF_AVPMENUGFXS); + gfxPtr = &AvPMenuGfxStorage[menuGfxID]; + surface = gfxPtr->ImagePtr; + + + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdimage.dwSize = sizeof(ddsdimage); + + /* lock the image */ + while (surface->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + srcPtr = (unsigned short *)ddsdimage.lpSurface; + + if (length<0) length = 0; + + if (alpha>ONE_FIXED) + { + int x,y; + + for (y=topleftY; yHeight+topleftY; y++) + { + if(y>=topY && y<=bottomY) + { + destPtr = (unsigned short *)(ScreenBuffer + topleftX*2 + y*BackBufferPitch); + for (x=0; xHeight+topleftY; y++) + { + if(y>=topY && y<=bottomY) + { + destPtr = (unsigned short *)(ScreenBuffer + topleftX*2 + y*BackBufferPitch); + + for (x=0; xDisplayPixelFormat.dwRBitMask) destR = DisplayPixelFormat.dwRBitMask; + else destR &= DisplayPixelFormat.dwRBitMask; + + destG += MUL_FIXED(alpha,srcG); + if (destG>DisplayPixelFormat.dwGBitMask) destG = DisplayPixelFormat.dwGBitMask; + else destG &= DisplayPixelFormat.dwGBitMask; + + destB += MUL_FIXED(alpha,srcB); + if (destB>DisplayPixelFormat.dwBBitMask) destB = DisplayPixelFormat.dwBBitMask; + else destB &= DisplayPixelFormat.dwBBitMask; + + *destPtr = (short)(destR|destG|destB); + } + destPtr++; + } + } + srcPtr += (ddsdimage.lPitch/2); + } + } + + surface->Unlock((LPVOID)ddsdimage.lpSurface); + + UnlockSurface(); +} +extern void DrawAvPMenuGfx_CrossFade(enum AVPMENUGFX_ID menuGfxID,enum AVPMENUGFX_ID menuGfxID2,int alpha) +{ + LockSurfaceAndGetBufferPointer(); + + DDSURFACEDESC ddsdimage,ddsdimage2; + unsigned int *destPtr; + unsigned int *srcPtr; + unsigned int *srcPtr2; + AVPMENUGFX *gfxPtr; + AVPMENUGFX *gfxPtr2; + LPDIRECTDRAWSURFACE surface; + LPDIRECTDRAWSURFACE surface2; + + GLOBALASSERT(menuGfxID < MAX_NO_OF_AVPMENUGFXS); + gfxPtr = &AvPMenuGfxStorage[menuGfxID]; + surface = gfxPtr->ImagePtr; + GLOBALASSERT(menuGfxID2 < MAX_NO_OF_AVPMENUGFXS); + gfxPtr2 = &AvPMenuGfxStorage[menuGfxID2]; + surface2 = gfxPtr2->ImagePtr; + + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdimage.dwSize = sizeof(ddsdimage); + + /* lock the image */ + while (surface->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + srcPtr = (unsigned int *)ddsdimage.lpSurface; + + memset(&ddsdimage2, 0, sizeof(ddsdimage2)); + ddsdimage2.dwSize = sizeof(ddsdimage2); + + /* lock the image */ + while (surface2->Lock(NULL, &ddsdimage2, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + srcPtr2 = (unsigned int *)ddsdimage2.lpSurface; + + if (alpha==ONE_FIXED) + { + int x,y; + + for (y=0; y<480; y++) + { + destPtr = (unsigned int *)(ScreenBuffer + y*BackBufferPitch); + + for (x=0; x<320; x++) + { + *destPtr = *srcPtr; + destPtr++; + srcPtr++; + } + srcPtr += (ddsdimage.lPitch/4) - 320; + } + } + else + { + int x,y; + + for (y=0; y<480; y++) + { + destPtr = (unsigned int *)(ScreenBuffer + y*BackBufferPitch); + + for (x=0; x<320; x++) + { + int destination; + int src1=*srcPtr,src2=*srcPtr2; + + { + unsigned int srcR,srcG,srcB; + unsigned int srcR2,srcG2,srcB2; + + srcR2 = (src2) & DisplayPixelFormat.dwRBitMask; + srcG2 = (src2) & DisplayPixelFormat.dwGBitMask; + srcB2 = (src2) & DisplayPixelFormat.dwBBitMask; + + srcR = (src1) & DisplayPixelFormat.dwRBitMask; + srcG = (src1) & DisplayPixelFormat.dwGBitMask; + srcB = (src1) & DisplayPixelFormat.dwBBitMask; + + srcR2 = MUL_FIXED(ONE_FIXED-alpha,srcR2)+MUL_FIXED(alpha,srcR); + if (srcR2>DisplayPixelFormat.dwRBitMask) srcR2 = DisplayPixelFormat.dwRBitMask; + else srcR2 &= DisplayPixelFormat.dwRBitMask; + + srcG2 = MUL_FIXED(ONE_FIXED-alpha,srcG2)+MUL_FIXED(alpha,srcG); + if (srcG2>DisplayPixelFormat.dwGBitMask) srcG2 = DisplayPixelFormat.dwGBitMask; + else srcG2 &= DisplayPixelFormat.dwGBitMask; + + srcB2 = MUL_FIXED(ONE_FIXED-alpha,srcB2)+MUL_FIXED(alpha,srcB); + if (srcB2>DisplayPixelFormat.dwBBitMask) srcB2 = DisplayPixelFormat.dwBBitMask; + else srcB2 &= DisplayPixelFormat.dwBBitMask; + + destination = (srcR2|srcG2|srcB2); + } + src1>>=16; + src2>>=16; + { + unsigned int srcR,srcG,srcB; + unsigned int srcR2,srcG2,srcB2; + + srcR2 = (src2) & DisplayPixelFormat.dwRBitMask; + srcG2 = (src2) & DisplayPixelFormat.dwGBitMask; + srcB2 = (src2) & DisplayPixelFormat.dwBBitMask; + + srcR = (src1) & DisplayPixelFormat.dwRBitMask; + srcG = (src1) & DisplayPixelFormat.dwGBitMask; + srcB = (src1) & DisplayPixelFormat.dwBBitMask; + + srcR2 = MUL_FIXED(ONE_FIXED-alpha,srcR2)+MUL_FIXED(alpha,srcR); + if (srcR2>DisplayPixelFormat.dwRBitMask) srcR2 = DisplayPixelFormat.dwRBitMask; + else srcR2 &= DisplayPixelFormat.dwRBitMask; + + srcG2 = MUL_FIXED(ONE_FIXED-alpha,srcG2)+MUL_FIXED(alpha,srcG); + if (srcG2>DisplayPixelFormat.dwGBitMask) srcG2 = DisplayPixelFormat.dwGBitMask; + else srcG2 &= DisplayPixelFormat.dwGBitMask; + + srcB2 = MUL_FIXED(ONE_FIXED-alpha,srcB2)+MUL_FIXED(alpha,srcB); + if (srcB2>DisplayPixelFormat.dwBBitMask) srcB2 = DisplayPixelFormat.dwBBitMask; + else srcB2 &= DisplayPixelFormat.dwBBitMask; + + destination |= (srcR2|srcG2|srcB2)<<16; + + } + *destPtr++=destination; + srcPtr++; + srcPtr2++; + } + srcPtr += (ddsdimage.lPitch/4) - 320; + srcPtr2 += (ddsdimage2.lPitch/4) - 320; + } + } + surface2->Unlock((LPVOID)ddsdimage2.lpSurface); + surface->Unlock((LPVOID)ddsdimage.lpSurface); + + UnlockSurface(); +} + +extern void DrawAvPMenuGfx_Faded(enum AVPMENUGFX_ID menuGfxID, int topleftX, int topleftY, int alpha,enum AVPMENUFORMAT_ID format) +{ + LockSurfaceAndGetBufferPointer(); + + DDSURFACEDESC ddsdimage; + unsigned short *destPtr; + unsigned short *srcPtr; + AVPMENUGFX *gfxPtr; + LPDIRECTDRAWSURFACE surface; + + GLOBALASSERT(menuGfxID < MAX_NO_OF_AVPMENUGFXS); + gfxPtr = &AvPMenuGfxStorage[menuGfxID]; + surface = gfxPtr->ImagePtr; + + switch(format) + { + default: + GLOBALASSERT("UNKNOWN TEXT FORMAT"==0); + case AVPMENUFORMAT_LEFTJUSTIFIED: + { + // supplied x is correct + break; + } + case AVPMENUFORMAT_RIGHTJUSTIFIED: + { + topleftX -= gfxPtr->Width; + break; + } + case AVPMENUFORMAT_CENTREJUSTIFIED: + { + topleftX -= gfxPtr->Width/2; + break; + } + } + + + + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdimage.dwSize = sizeof(ddsdimage); + + /* lock the image */ + while (surface->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + srcPtr = (unsigned short *)ddsdimage.lpSurface; + + { + int x,y; + + for (y=topleftY; yHeight+topleftY; y++) + { + destPtr = (unsigned short *)(ScreenBuffer + topleftX*2 + y*BackBufferPitch); + + for (x=0; xWidth; x++) + { + if (*srcPtr) + { + unsigned int srcR,srcG,srcB; + + srcR = (int)(*srcPtr) & DisplayPixelFormat.dwRBitMask; + srcG = (int)(*srcPtr) & DisplayPixelFormat.dwGBitMask; + srcB = (int)(*srcPtr) & DisplayPixelFormat.dwBBitMask; + srcR = MUL_FIXED(alpha,srcR); + srcR &= DisplayPixelFormat.dwRBitMask; + + srcG = MUL_FIXED(alpha,srcG); + srcG &= DisplayPixelFormat.dwGBitMask; + + srcB = MUL_FIXED(alpha,srcB); + srcB &= DisplayPixelFormat.dwBBitMask; + + *destPtr = (short)(srcR|srcG|srcB); + } + else + { + *destPtr = 0; + } + + destPtr++; + srcPtr++; + } + srcPtr += (ddsdimage.lPitch/2) - gfxPtr->Width; + } + } + + surface->Unlock((LPVOID)ddsdimage.lpSurface); + + UnlockSurface(); +} +extern void DrawAvPMenuGfx_Clipped(enum AVPMENUGFX_ID menuGfxID, int topleftX, int topleftY, int alpha,enum AVPMENUFORMAT_ID format, int topY, int bottomY) +{ + LockSurfaceAndGetBufferPointer(); + + DDSURFACEDESC ddsdimage; + unsigned short *destPtr; + unsigned short *srcPtr; + AVPMENUGFX *gfxPtr; + LPDIRECTDRAWSURFACE surface; + + GLOBALASSERT(menuGfxID < MAX_NO_OF_AVPMENUGFXS); + gfxPtr = &AvPMenuGfxStorage[menuGfxID]; + surface = gfxPtr->ImagePtr; + + switch(format) + { + default: + GLOBALASSERT("UNKNOWN TEXT FORMAT"==0); + case AVPMENUFORMAT_LEFTJUSTIFIED: + { + // supplied x is correct + break; + } + case AVPMENUFORMAT_RIGHTJUSTIFIED: + { + topleftX -= gfxPtr->Width; + break; + } + case AVPMENUFORMAT_CENTREJUSTIFIED: + { + topleftX -= gfxPtr->Width/2; + break; + } + } + + + + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdimage.dwSize = sizeof(ddsdimage); + + /* lock the image */ + while (surface->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + srcPtr = (unsigned short *)ddsdimage.lpSurface; + + if (alpha>ONE_FIXED) + { + int x,y; + + for (y=topleftY; yHeight+topleftY; y++) + { + destPtr = (unsigned short *)(ScreenBuffer + topleftX*2 + y*BackBufferPitch); + if(y>=topY && y<=bottomY) + { + for (x=0; xWidth; x++) + { + *destPtr = *srcPtr; + destPtr++; + srcPtr++; + } + srcPtr += (ddsdimage.lPitch/2) - gfxPtr->Width; + } + else + { + srcPtr+=(ddsdimage.lPitch/2); + } + } + } + else + { + int x,y; + + for (y=topleftY; yHeight+topleftY; y++) + { + destPtr = (unsigned short *)(ScreenBuffer + topleftX*2 + y*BackBufferPitch); + + if(y>=topY && y<=bottomY) + { + for (x=0; xWidth; x++) + { + if (*srcPtr) + { + unsigned int srcR,srcG,srcB; + unsigned int destR,destG,destB; + + destR = (int)(*destPtr) & DisplayPixelFormat.dwRBitMask; + destG = (int)(*destPtr) & DisplayPixelFormat.dwGBitMask; + destB = (int)(*destPtr) & DisplayPixelFormat.dwBBitMask; + + srcR = (int)(*srcPtr) & DisplayPixelFormat.dwRBitMask; + srcG = (int)(*srcPtr) & DisplayPixelFormat.dwGBitMask; + srcB = (int)(*srcPtr) & DisplayPixelFormat.dwBBitMask; + + destR += MUL_FIXED(alpha,srcR); + if (destR>DisplayPixelFormat.dwRBitMask) destR = DisplayPixelFormat.dwRBitMask; + else destR &= DisplayPixelFormat.dwRBitMask; + + destG += MUL_FIXED(alpha,srcG); + if (destG>DisplayPixelFormat.dwGBitMask) destG = DisplayPixelFormat.dwGBitMask; + else destG &= DisplayPixelFormat.dwGBitMask; + + destB += MUL_FIXED(alpha,srcB); + if (destB>DisplayPixelFormat.dwBBitMask) destB = DisplayPixelFormat.dwBBitMask; + else destB &= DisplayPixelFormat.dwBBitMask; + + *destPtr = (short)(destR|destG|destB); + } + destPtr++; + srcPtr++; + } + srcPtr += (ddsdimage.lPitch/2) - gfxPtr->Width; + } + else + { + srcPtr += (ddsdimage.lPitch/2); + } + } + } + + surface->Unlock((LPVOID)ddsdimage.lpSurface); + + UnlockSurface(); +} + +extern int HeightOfMenuGfx(enum AVPMENUGFX_ID menuGfxID) +{ + return AvPMenuGfxStorage[menuGfxID].Height; +} + +extern void ClearScreenToBlack(void) +{ + LockSurfaceAndGetBufferPointer(); + { + int x,y; + + for (y=0; y<480; y++) + { + unsigned int *destPtr = (unsigned int *)(ScreenBuffer + y*BackBufferPitch); + + for (x=0; x<320; x++) + { + *destPtr++=0; + } + } + } + UnlockSurface(); +} + +extern void FadedScreen(int alpha) +{ + LockSurfaceAndGetBufferPointer(); + + { + int x,y; + + for (y=60; yImagePtr; + + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdimage.dwSize = sizeof(ddsdimage); + + /* lock the image */ + while (surface->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + srcPtr = (unsigned char *)ddsdimage.lpSurface; + + // special case for space + AAFontWidths[32]=3; + + for (c=33; c<255; c++) + { + int x,y; + int x1 = 1+((c-32)&15)*16; + int y1 = 1+((c-32)>>4)*16; + AAFontWidths[c]=17; + + for (x=x1+HUD_FONT_WIDTH; x>x1; x--) + { + int blank = 1; + for (y=y1; yUnlock((LPVOID)ddsdimage.lpSurface); + +} + +}; \ No newline at end of file diff --git a/3dc/avp/win95/Frontend/AvP_MenuGfx.hpp b/3dc/avp/win95/Frontend/AvP_MenuGfx.hpp new file mode 100644 index 0000000..2502f59 --- /dev/null +++ b/3dc/avp/win95/Frontend/AvP_MenuGfx.hpp @@ -0,0 +1,115 @@ +/* KJL 12:27:18 26/06/98 - AvP_MenuGfx.hpp */ + +enum AVPMENUGFX_ID +{ + AVPMENUGFX_CLOUDY, + AVPMENUGFX_SMALL_FONT, + AVPMENUGFX_COPYRIGHT_SCREEN, + + AVPMENUGFX_PRESENTS, + AVPMENUGFX_AREBELLIONGAME, + AVPMENUGFX_ALIENSVPREDATOR, + + AVPMENUGFX_SLIDERBAR, + AVPMENUGFX_SLIDER, + + AVPMENUGFX_BACKDROP, + AVPMENUGFX_ALIENS_LOGO, + AVPMENUGFX_ALIEN_LOGO, + AVPMENUGFX_MARINE_LOGO, + AVPMENUGFX_PREDATOR_LOGO, + + AVPMENUGFX_GLOWY_LEFT, + AVPMENUGFX_GLOWY_MIDDLE, + AVPMENUGFX_GLOWY_RIGHT, + + AVPMENUGFX_MARINE_EPISODE1, + AVPMENUGFX_MARINE_EPISODE2, + AVPMENUGFX_MARINE_EPISODE3, + AVPMENUGFX_MARINE_EPISODE4, + AVPMENUGFX_MARINE_EPISODE5, + AVPMENUGFX_MARINE_EPISODE6, + + AVPMENUGFX_MARINE_EPISODE7, + AVPMENUGFX_MARINE_EPISODE8, + AVPMENUGFX_MARINE_EPISODE9, + AVPMENUGFX_MARINE_EPISODE10, + AVPMENUGFX_MARINE_EPISODE11, + + AVPMENUGFX_PREDATOR_EPISODE1, + AVPMENUGFX_PREDATOR_EPISODE2, + AVPMENUGFX_PREDATOR_EPISODE3, + AVPMENUGFX_PREDATOR_EPISODE4, + AVPMENUGFX_PREDATOR_EPISODE5, + AVPMENUGFX_PREDATOR_EPISODE6, + + AVPMENUGFX_PREDATOR_EPISODE7, + AVPMENUGFX_PREDATOR_EPISODE8, + AVPMENUGFX_PREDATOR_EPISODE9, + AVPMENUGFX_PREDATOR_EPISODE10, + AVPMENUGFX_PREDATOR_EPISODE11, + + AVPMENUGFX_ALIEN_EPISODE1, + AVPMENUGFX_ALIEN_EPISODE2, + AVPMENUGFX_ALIEN_EPISODE3, + AVPMENUGFX_ALIEN_EPISODE4, + AVPMENUGFX_ALIEN_EPISODE5, + AVPMENUGFX_ALIEN_EPISODE6, + AVPMENUGFX_ALIEN_EPISODE7, + AVPMENUGFX_ALIEN_EPISODE8, + AVPMENUGFX_ALIEN_EPISODE9, + AVPMENUGFX_ALIEN_EPISODE10, + + AVPMENUGFX_WINNER_SCREEN, + + AVPMENUGFX_SPLASH_SCREEN1, + AVPMENUGFX_SPLASH_SCREEN2, + AVPMENUGFX_SPLASH_SCREEN3, + AVPMENUGFX_SPLASH_SCREEN4, + AVPMENUGFX_SPLASH_SCREEN5, + + MAX_NO_OF_AVPMENUGFXS, +}; + +typedef struct +{ + char *FilenamePtr; + LPDIRECTDRAWSURFACE ImagePtr; + AW_BACKUPTEXTUREHANDLE hBackup; + int Width; + int Height; + +} AVPMENUGFX; + +enum AVPMENUFORMAT_ID +{ + AVPMENUFORMAT_LEFTJUSTIFIED, + AVPMENUFORMAT_RIGHTJUSTIFIED, + AVPMENUFORMAT_CENTREJUSTIFIED, +}; + +extern void LoadAvPMenuGfx(enum AVPMENUGFX_ID menuGfxID); +extern void LoadAllAvPMenuGfx(void); +extern void LoadAllSplashScreenGfx(void); +extern void ReleaseAllAvPMenuGfx(void); + +extern int RenderMenuText(char *textPtr, int x, int y, int alpha, enum AVPMENUFORMAT_ID format); + +extern int RenderSmallMenuText(char *textPtr, int x, int y, int alpha, enum AVPMENUFORMAT_ID format); +extern int RenderSmallMenuText_Coloured(char *textPtr, int x, int y, int alpha, enum AVPMENUFORMAT_ID format, int red, int green, int blue); + +extern int Hardware_RenderSmallMenuText(char *textPtr, int x, int y, int alpha, enum AVPMENUFORMAT_ID format); +extern int Hardware_RenderSmallMenuText_Coloured(char *textPtr, int x, int y, int alpha, enum AVPMENUFORMAT_ID format, int red, int green, int blue); + +extern int RenderMenuText_Clipped(char *textPtr, int x, int y, int alpha, enum AVPMENUFORMAT_ID format, int topY, int bottomY); +extern void RenderSmallFontString_Wrapped(char *textPtr,RECT* area,int alpha,int* output_x,int* output_y); + + +extern void DrawAvPMenuGfx(enum AVPMENUGFX_ID menuGfxID, int topleftX, int topleftY, int alpha,enum AVPMENUFORMAT_ID format); +extern void DrawAvPMenuGfx_Clipped(enum AVPMENUGFX_ID menuGfxID, int topleftX, int topleftY, int alpha,enum AVPMENUFORMAT_ID format, int topY, int bottomY); +extern void DrawAvPMenuGfx_CrossFade(enum AVPMENUGFX_ID menuGfxID,enum AVPMENUGFX_ID menuGfxID2,int alpha); +extern void DrawAvPMenuGfx_Faded(enum AVPMENUGFX_ID menuGfxID, int topleftX, int topleftY, int alpha,enum AVPMENUFORMAT_ID format); +extern int HeightOfMenuGfx(enum AVPMENUGFX_ID menuGfxID); + + +extern void ClearScreenToBlack(void); diff --git a/3dc/avp/win95/Frontend/AvP_Menus.c b/3dc/avp/win95/Frontend/AvP_Menus.c new file mode 100644 index 0000000..50e9754 --- /dev/null +++ b/3dc/avp/win95/Frontend/AvP_Menus.c @@ -0,0 +1,5711 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "pldnet.h" + +#include "AvP_Menus.h" +#include "AvP_EnvInfo.h" + +#include "hud_Layout.h" +#include "AvP_UserProfile.h" +#include "huffman.hpp" + +#include "hudgfx.h" +#include "usr_io.h" +#define UseLocalAssert Yes +#include "ourasert.h" +#include "iofocus.h" +#include +#include "winnls.h" +#include "GammaControl.h" +#include "AvP_MP_Config.h" +#include "psnd.h" +#include "savegame.h" + +#if 0 +#undef BRIGHTNESS_CHANGE_SPEED +#define BRIGHTNESS_CHANGE_SPEED (RealFrameTime/4) +#endif + + +extern void StartMenuBackgroundBink(void); +extern int PlayMenuBackgroundBink(void); +extern void EndMenuBackgroundBink(void); + + +/* KJL 11:22:37 23/06/98 - Hopefully these will be the final menus! */ + +extern int IDemandSelect(void); + +extern char *GetVideoModeDescription(void); +extern void PreviousVideoMode(void); +extern void NextVideoMode(void); +extern void SaveVideoModeSettings(void); + + +extern void MakeSelectSessionMenu(void); + +extern void MakeInGameMenu(void); +extern void MakeMarineKeyConfigMenu(void); +extern void MakePredatorKeyConfigMenu(void); +extern void MakeAlienKeyConfigMenu(void); +extern void MakeUserProfileSelectMenu(void); + +extern void SaveKeyConfiguration(void); + + +extern void D3D_DrawSliderBar(int x, int y, int alpha); +extern void D3D_DrawSlider(int x, int y, int alpha); +extern void D3D_FadeDownScreen(int brightness, int colour); +extern void PlayIntroSequence(void); + +extern void MinimalNetCollectMessages(void); + +extern int DirectPlay_HostGame(char *playerName, char *sessionName,int species,int gamestyle,int level); +extern int DirectPlay_JoinGame(void); +extern int DirectPlay_ConnectToSession(int sessionNumber, char *playerName); +extern int DirectPlay_Disconnect(void); + +extern void ShowSplashScreens(void); +extern void Show_WinnerScreen(void); + +extern void GetNextAllowedSpecies(int* species,BOOL search_forwards); +static void SetBriefingTextForMultiplayer(); + +int CloudTable[128][128]; + +extern char MP_Config_Name[]; + +void HandlePostGameFMVs(void); +void HandlePreGameFMVs(void); +extern void AvP_UpdateMenus(void); +static void SetupNewMenu(enum AVPMENU_ID menuID); +static void RenderMenu(void); +static void RenderBriefingScreenInfo(void); +static void RenderEpisodeSelectMenu(void); +static void RenderKeyConfigurationMenu(void); +static void RenderUserProfileSelectMenu(void); +static void RenderLoadGameMenu(void); +static void RenderConfigurationDescriptionString(); +static void ActUponUsersInput(void); +static void InteractWithMenuElement(enum AVPMENU_ELEMENT_INTERACTION_ID interactionID); +static void RenderMenuElement(AVPMENU_ELEMENT *elementPtr, int e, int y); +void DisplayVideoModeUnavailableScreen(void); +void CheckForCredits(void); +void DoCredits(void); +BOOL RollCreditsText(int position, unsigned char *textPtr); +extern void SelectMenuDisplayMode(void); +static void InitMainMenusBackdrop(void); +extern void DrawMainMenusBackdrop(void); +static void TestValidityOfCheatMenu(void); +void SetBriefingTextForEpisode(int episode, I_PLAYER_TYPE playerID); +void SetBriefingTextToBlank(void); +void RenderBriefingText(int centreY, int brightness); +void CheckForKeysWithMultipleAssignments(void); +void HandleCheatModeFeatures(void); +void ShowMenuFrameRate(void); +static void KeyboardEntryQueue_Clear(void); +static void KeyboardEntryQueue_StartProcessing(void); +void ScanSaveSlots(void); +extern void GetFilenameForSaveSlot(int i, unsigned char *filenamePtr); +static void GetHeaderInfoForSaveSlot(SAVE_SLOT_HEADER* save_slot,const char* filename); + +static void PasteFromClipboard(char* Text,int MaxTextLength); +/* KJL 11:23:03 23/06/98 - Requirements + + 1. 'Floating' over backdrop, possibly using translucency effects + 2. Quick to write! + 3. Quick to change + 4. Certain menus need to be used in-game - e.g. key configuration +*/ + +/* KJL 11:27:18 23/06/98 - Available menus + + 1. Main Menu + + Start Singleplayer + Start Multiplayer + Gameplay Options + Audio/Visual Options + Exit + + 2. Singleplayer + + Alien + Marine + Predator + Exit + + 3. Multiplayer + + -> Complex + + 4. Gameplay Options + + 5. Audio/Visual Options + + */ + + +/* KJL 11:57:21 23/06/98 - + + + Need mouse position code (?) etc. In-game menus using mouse? Ugh. + No mouse then. + +*/ +SAVE_SLOT_HEADER SaveGameSlot[NUMBER_OF_SAVE_SLOTS]; + + +extern int VideoModeNotAvailable; + +extern int RealFrameTime; +extern unsigned char KeyboardInput[]; +extern unsigned char DebouncedKeyboardInput[]; +extern int DebouncedGotAnyKey; +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; +extern int TimeScale; + +static AVP_MENUS AvPMenus; +extern AVPMENU AvPMenusData[]; + +extern int AlienEpisodeToPlay; +extern int MarineEpisodeToPlay; +extern int PredatorEpisodeToPlay; +extern int UserProfileNumber; +AVP_USER_PROFILE *UserProfilePtr; + +SESSION_DESC SessionData[MAX_NO_OF_SESSIONS]; +int NumberOfSessionsFound; +extern NETGAME_GAMEDATA netGameData; + +static int InputIsDebounced = 0; +static int KeyDepressedCounter = 0; +extern int CloakingPhase; +static int EpisodeSelectScrollOffset; +static int MaximumSelectableLevel; +static int KeyConfigSelectionColumn; + +static int Brightness[16]; + +static unsigned char MultipleAssignments[2][32]; + +static char *GetDescriptionOfKey(unsigned char key); +static int OkayToPlayNextEpisode(void); +static PLAYER_INPUT_CONFIGURATION PlayerInputPrimaryConfig; +static PLAYER_INPUT_CONFIGURATION PlayerInputSecondaryConfig; +CONTROL_METHODS PlayerControlMethods; +JOYSTICK_CONTROL_METHODS PlayerJoystickControlMethods; + +static void RenderScrollyMenu(); +static void RenderHelpString(); +static void CheckForLoadGame(); + +static void UpdateMultiplayerConfigurationMenu(); + +static char KeyboardEntryQueue_ProcessCharacter(void); + +static BOOL LaunchingMplayer=FALSE; + +static int MultiplayerConfigurationIndex; //just used for the configuration deletion stuff +static const char* MultiplayerConfigurationName=0; //ditto + +extern int DebuggingCommandsActive; + +extern int AvP_MainMenus(void) +{ + #if 0 + SaveDefaultPrimaryConfigs(); + #else + LoadDefaultPrimaryConfigs(); + #endif + + SoundSys_ResetFadeLevel(); + SoundSys_Management(); + + TimeScale = ONE_FIXED; + + + + if (!LobbiedGame) // Edmond + CheckForCredits(); + + TimeStampedMessage("start of menus"); + // open a 640x480x16 screen + SelectMenuDisplayMode(); + TimeStampedMessage("after SelectMenuDisplayMode"); + + + + + + InitialiseMenuGfx(); + TimeStampedMessage("after InitialiseMenuGfx"); + + // inform backdrop code + InitMainMenusBackdrop(); + TimeStampedMessage("after InitMainMenusBackdrop"); + + + #if PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO + if (AvP.LevelCompleted) + { + Show_WinnerScreen(); + } + #endif + + LoadAllAvPMenuGfx(); + TimeStampedMessage("after LoadAllAvPMenuGfx"); + + + + ResetFrameCounter(); + + if (!LobbiedGame) // Edmond + PlayIntroSequence(); + + if (VideoModeNotAvailable) + { + LoadGameRequest = SAVELOAD_REQUEST_NONE; + DisplayVideoModeUnavailableScreen(); + } + VideoModeNotAvailable = 0; + + if(AvP.LevelCompleted && CheatMode_Active == CHEATMODE_NONACTIVE && !DebuggingCommandsActive) + { + HandlePostGameFMVs(); + OkayToPlayNextEpisode(); + AvP.LevelCompleted = 0; + AvPMenus.MenusState = MENUSSTATE_MAINMENUS; + } + else if(!LobbiedGame) + { + if (UserProfileNumber==-1) + { + SetupNewMenu(AVPMENU_USERPROFILESELECT); + } + else + { + SetupNewMenu(AVPMENU_MAIN); + } + AvPMenus.MenusState = MENUSSTATE_MAINMENUS; + } + else + { + SetupNewMenu(AVPMENU_USERPROFILESELECT); + //AvPMenus.MenusState = MENUSSTATE_STARTGAME; + + } + + CheatMode_Active = CHEATMODE_NONACTIVE; + + + TimeStampedMessage("starting general menus"); + + while(AvPMenus.MenusState == MENUSSTATE_MAINMENUS) + { + CheckForWindowsMessages(); + DrawMainMenusBackdrop(); + ReadUserInput(); + AvP_UpdateMenus(); + // BezierCurve(); + + ShowMenuFrameRate(); + + FlipBuffers(); + FrameCounterHandler(); + PlayMenuMusic(); + #if 0 + { + extern int EffectsSoundVolume; + SoundSys_ChangeVolume(EffectsSoundVolume); + } + #endif + SoundSys_Management(); + UpdateGammaSettings(); + + CheckForLoadGame(); + } + + if (AvPMenus.MenusState==MENUSSTATE_OUTSIDEMENUS) + { + //Don't bother showing credits if we are just exiting in order to start a game + //using mplayer. The credits will get shown later after the player has actually + //played the game + if(!LaunchingMplayer) + { + if (!LobbiedGame) // Edmond + DoCredits(); + } + } + TimeStampedMessage("ready to exit menus"); + + EndMenuMusic(); + EndMenuBackgroundBink(); + TimeStampedMessage("after EndMenuMusic"); + + #if 0 + #if PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO + if (/*!AvP.LevelCompleted &&*/ (AvPMenus.MenusState != MENUSSTATE_STARTGAME)) ShowSplashScreens(); + TimeStampedMessage("after ShowSplashScreens"); + #endif + #endif + ReleaseAllAvPMenuGfx(); + + TimeStampedMessage("after ReleaseAllAvPMenuGfx"); + + SoundSys_StopAll(); + SoundSys_Management(); + + if (CheatMode_Active == CHEATMODE_NONACTIVE) HandlePreGameFMVs(); + + HandleCheatModeFeatures(); + AvP.LevelCompleted = 0; + + return (AvPMenus.MenusState == MENUSSTATE_STARTGAME); +} +void HandlePostGameFMVs(void) +{ + switch(AvP.PlayerType) + { + case I_Marine: + { + if (MarineEpisodeToPlay==MAX_NO_OF_BASIC_MARINE_EPISODES-1) + { + ClearScreenToBlack(); + FlipBuffers(); + ClearScreenToBlack(); + PlayBinkedFMV("FMVs/marineoutro.bik"); + } + break; + } + case I_Alien: + { + if (AlienEpisodeToPlay==MAX_NO_OF_BASIC_ALIEN_EPISODES-1) + { + ClearScreenToBlack(); + FlipBuffers(); + ClearScreenToBlack(); + PlayBinkedFMV("FMVs/alienoutro.bik"); + } + break; + } + case I_Predator: + { + if (PredatorEpisodeToPlay==MAX_NO_OF_BASIC_PREDATOR_EPISODES-1) + { + ClearScreenToBlack(); + FlipBuffers(); + ClearScreenToBlack(); + PlayBinkedFMV("FMVs/predatoroutro.bik"); + } + break; + } + } +} +void HandlePreGameFMVs(void) +{ + if (AvPMenus.MenusState == MENUSSTATE_STARTGAME && LoadGameRequest == SAVELOAD_REQUEST_NONE) + { + extern char LevelName[]; + if (!stricmp("derelict",&LevelName)) + { + ClearScreenToBlack(); + FlipBuffers(); + ClearScreenToBlack(); + PlayBinkedFMV("FMVs/marineintro.bik"); + } + else if (!stricmp("temple",&LevelName)) + { + ClearScreenToBlack(); + FlipBuffers(); + ClearScreenToBlack(); + PlayBinkedFMV("FMVs/alienintro.bik"); + } + else if (!stricmp("fall",&LevelName)) + { + ClearScreenToBlack(); + FlipBuffers(); + ClearScreenToBlack(); + PlayBinkedFMV("FMVs/predatorintro.bik"); + } + } +} + +extern void QuickSplashScreens(void) +{ + SelectMenuDisplayMode(); + if (AvP.LevelCompleted) + { + Show_WinnerScreen(); + } + ShowSplashScreens(); +} + +extern void AvP_TriggerInGameMenus(void) +{ + AvPMenus.MenusState = MENUSSTATE_INGAMEMENUS; + SetupNewMenu(AVPMENU_INGAME); + + /* KJL 16:32:55 21/07/98 - tell the console to go away */ + if (IOFOCUS_AcceptTyping()) IOFOCUS_Toggle(); +// SoundSys_PauseOn(); +} +extern int AvP_InGameMenus(void) +{ + if(AvPMenus.MenusState == MENUSSTATE_INGAMEMENUS) + { + D3D_FadeDownScreen(ONE_FIXED/8,0); + AvP_UpdateMenus(); + UpdateGammaSettings(); + + return 1; + } + else return 0; +} + +extern int InGameMenusAreRunning(void) +{ + return (AvPMenus.MenusState == MENUSSTATE_INGAMEMENUS); +} +extern void AvP_UpdateMenus(void) +{ +// DrawAvPMenuGfx(AVPMENUGFX_BIG_AVP_LOGO,50,50,16384); +// DrawAvPMenuGfx(AVPMENUGFX_ALIENS_LOGO,10,75,16384,AVPMENUFORMAT_LEFTJUSTIFIED); +// DrawAvPMenuGfx(AVPMENUGFX_PREDATOR_LOGO,380,77,16384,AVPMENUFORMAT_LEFTJUSTIFIED); +// RenderMenuText("VS",330,95,16384,AVPMENUFORMAT_CENTREJUSTIFIED); + + #if 0 + if (AvPMenus.CurrentMenu == AVPMENU_MULTIPLAYERJOINGAME2) + { + MinimalNetCollectMessages(); + /* KJL 19:49:04 05/07/98 - ugh, there goes the interface */ + { + extern int MP_GameStyle; + extern int MP_LevelNumber; + extern int MP_Species; + MP_GameStyle = netGameData.gameType; + MP_LevelNumber = netGameData.levelNumber; + switch (MP_Species) + { + default: + case 0: + netGameData.myCharacterType = NGCT_Marine; + netGameData.myNextCharacterType = NGCT_Marine; + AvP.PlayerType = I_Marine; + break; + case 1: + netGameData.myCharacterType = NGCT_Predator; + netGameData.myNextCharacterType = NGCT_Predator; + AvP.PlayerType = I_Predator; + break; + case 2: + netGameData.myCharacterType = NGCT_Alien; + netGameData.myNextCharacterType = NGCT_Alien; + AvP.PlayerType = I_Alien; + break; + } + } + AddNetMsg_PlayerDescription(); + + NetSendMessages(); + } + #endif + + if (AvPMenus.CurrentMenu == AVPMENU_MULTIPLAYER_SPECIES_JOIN || + AvPMenus.CurrentMenu == AVPMENU_MULTIPLAYER_CONFIG_JOIN) + { + MinimalNetCollectMessages(); + if(AvP.Network==I_Host) + { /* + We have become host while in the process of joining. + This is bad. + Best leave the game and return to the main menus. + */ + DirectPlay_Disconnect(); + SetupNewMenu(AVPMENU_MAIN); + return; + } + + if (AvPMenus.CurrentMenu == AVPMENU_MULTIPLAYER_SPECIES_JOIN) + { + /* KJL 19:49:04 05/07/98 - ugh, there goes the interface */ + { +// extern int MP_GameStyle; +// extern int MP_LevelNumber; + extern int MP_Species; +// MP_GameStyle = netGameData.gameType; +// MP_LevelNumber = netGameData.levelNumber; + + GetNextAllowedSpecies(&MP_Species,TRUE); + netGameData.myCharacterSubType=NGSCT_General; + switch (MP_Species) + { + default: + case 0: + netGameData.myCharacterType = NGCT_Marine; + netGameData.myNextCharacterType = NGCT_Marine; + AvP.PlayerType = I_Marine; + break; + case 1: + netGameData.myCharacterType = NGCT_Predator; + netGameData.myNextCharacterType = NGCT_Predator; + AvP.PlayerType = I_Predator; + break; + case 2: + netGameData.myCharacterType = NGCT_Alien; + netGameData.myNextCharacterType = NGCT_Alien; + AvP.PlayerType = I_Alien; + break; + + case 3: //various marine subtypes + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + netGameData.myCharacterType = NGCT_Marine; + netGameData.myNextCharacterType = NGCT_Marine; + AvP.PlayerType = I_Marine; + netGameData.myCharacterSubType =(NETGAME_SPECIALISTCHARACTERTYPE) (MP_Species-2); + break; + } + } + AddNetMsg_PlayerDescription(); + + NetSendMessages(); + } + } + else if (AvPMenus.CurrentMenu == AVPMENU_MULTIPLAYER_SPECIES_HOST) + { + extern int MP_Species; + GetNextAllowedSpecies(&MP_Species,TRUE); + } + else if (AvPMenus.CurrentMenu == AVPMENU_MULTIPLAYER_JOINING) + { + //check status of joining game + int retval=0; + if(LobbiedGame) + { + extern char MP_PlayerName[]; + retval=DirectPlay_ConnectingToLobbiedGame(MP_PlayerName); + if(!retval) + { + //player has aborted , go back a menu + SetupNewMenu(AVPMENU_MULTIPLAYER_LOBBIEDCLIENT); + return ; + } + } + else + { + retval=DirectPlay_ConnectingToSession(); + if(!retval) + { + //player has aborted , go back a menu + SetupNewMenu(AVPMENU_MULTIPLAYER); + return ; + } + } + + if(retval==AVPMENU_MULTIPLAYER_CONFIG_JOIN) + { + //successfully joined + SetupNewMenu(AVPMENU_MULTIPLAYER_CONFIG_JOIN); + } + } + else if (AvPMenus.CurrentMenu == AVPMENU_MULTIPLAYERSELECTSESSION) + { + extern BOOL DirectPlay_UpdateSessionList(int * SelectedItem); + int selection=AvPMenus.CurrentlySelectedElement; + + if(DirectPlay_UpdateSessionList(&selection)) + { + //session list has changed , so we need to set the menu again + SetupNewMenu(AVPMENU_MULTIPLAYERSELECTSESSION); + //adjust the selected menu item + AvPMenus.CurrentlySelectedElement=selection; + } + } + + + + /* render menu; episode select goes through a separate system */ + switch (AvPMenus.CurrentMenu) + { + case AVPMENU_LOADGAME: + case AVPMENU_SAVEGAME: + { + RenderLoadGameMenu(); + RenderHelpString(); + break; + } + + case AVPMENU_MARINELEVELS: + case AVPMENU_PREDATORLEVELS: + case AVPMENU_ALIENLEVELS: + { + RenderEpisodeSelectMenu(); + break; + } + case AVPMENU_USERPROFILESELECT: + { + RenderUserProfileSelectMenu(); + RenderHelpString(); + break; + } + case AVPMENU_USERPROFILEDELETE: + { + int i; + AVP_USER_PROFILE *profilePtr = GetFirstUserProfile(); + for (i=0; iName,MENU_CENTREX,MENU_CENTREY-100,ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + { + char buffer[100]; + char buffer2[100]; + int nLen = 80; + + time_t time_of_day; + + time_of_day = time( NULL ); + + nLen = GetDateFormat(GetThreadLocale(), DATE_LONGDATE, &profilePtr->TimeLastUpdated,NULL,buffer,nLen); + nLen = GetTimeFormat(GetThreadLocale(), 0, &profilePtr->TimeLastUpdated,NULL,buffer2,100); + + strcat(buffer2," "); + strcat(buffer2,buffer); + RenderSmallMenuText(buffer2,MENU_CENTREX,MENU_CENTREY-70,ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + } + + RenderMenu(); + RenderHelpString(); + break; + + } + case AVPMENU_MULTIPLAYER_DELETECONFIG : + { + //show the name of the configuration we're trying to delete + RenderMenuText(MultiplayerConfigurationName,MENU_CENTREX,MENU_CENTREY-100,ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + + RenderMenu(); + RenderHelpString(); + break; + } + + case AVPMENU_ALIENKEYCONFIG: + case AVPMENU_MARINEKEYCONFIG: + case AVPMENU_PREDATORKEYCONFIG: + { + CheckForKeysWithMultipleAssignments(); + RenderKeyConfigurationMenu(); + + if (AvPMenus.MenusState == MENUSSTATE_MAINMENUS) + { + RenderHelpString(); + } + + break; + } + case AVPMENU_SKIRMISH_CONFIG : + case AVPMENU_MULTIPLAYER_CONFIG : + case AVPMENU_MULTIPLAYER_CONFIG_JOIN : + { + UpdateMultiplayerConfigurationMenu(); + RenderScrollyMenu(); + RenderHelpString(); + break; + } + case AVPMENU_MULTIPLAYEROPENADDRESS : + { + RenderMenu(); + RenderHelpString(); + break; + } + + case AVPMENU_MULTIPLAYER_LOADIPADDRESS : + { + RenderScrollyMenu(); + break; + } + + case AVPMENU_MULTIPLAYER_LOADCONFIG : + { + RenderScrollyMenu(); + RenderConfigurationDescriptionString(); + RenderHelpString(); + break; + } + case AVPMENU_INGAMEAVOPTIONS: + { + int scale = DIV_FIXED(ScreenDescriptorBlock.SDB_Height,480); + int h = scale/2048; + int offset = scale/4096; + D3D_DrawColourBar(offset, offset+h, ONE_FIXED, 0, 0); + D3D_DrawColourBar(offset*2+h, offset*2+h*2, 0, ONE_FIXED, 0); + D3D_DrawColourBar(ScreenDescriptorBlock.SDB_Height-offset*2-h*2, ScreenDescriptorBlock.SDB_Height-offset*2-h, 0, 0, ONE_FIXED); + D3D_DrawColourBar(ScreenDescriptorBlock.SDB_Height-offset-h, ScreenDescriptorBlock.SDB_Height-offset, ONE_FIXED, ONE_FIXED, ONE_FIXED); + RenderMenu(); + break; + } + + case AVPMENU_CHEATOPTIONS: + { + TestValidityOfCheatMenu(); + RenderMenu(); + RenderHelpString(); + break; + } + default: + { + RenderMenu(); + RenderHelpString(); + break; + } + } + ActUponUsersInput(); + +} + +static void SetupNewMenu(enum AVPMENU_ID menuID) +{ + enum AVPMENU_ID previousMenuID = AvPMenus.CurrentMenu; + AvPMenus.CurrentMenu = menuID; + + /* set pointer to the start of the menu's element data */ + AvPMenus.MenuElements = AvPMenusData[menuID].MenuElements; // could use default + + AvPMenus.FontToUse = AvPMenusData[menuID].FontToUse; + AvPMenus.CurrentlySelectedElement = 0; + AvPMenus.UserEnteringText = 0; + AvPMenus.UserEnteringNumber = 0; + AvPMenus.UserChangingKeyConfig = 0; + AvPMenus.PositionInTextField = 0; + AvPMenus.WidthLeftForText = 0; + + + /* menu specific stuff */ + switch (menuID) + { + case AVPMENU_MAIN: + { + GetSettingsFromUserProfile(); + SaveUserProfile(UserProfilePtr); + + if (DebuggingCommandsActive) + { + if (AnyCheatModesAllowed()) + { + // turn on cheats + SetupNewMenu(AVPMENU_DEBUG_MAIN_WITHCHEATS); + } + else + { + SetupNewMenu(AVPMENU_DEBUG_MAIN); + } + } + else + { + if (AnyCheatModesAllowed()) + { + // turn on cheats + SetupNewMenu(AVPMENU_MAIN_WITHCHEATS); + } + } + break; + } + + case AVPMENU_VIDEOMODE: + { + LoadDeviceAndVideoModePreferences(); + break; + } + + case AVPMENU_USERPROFILESELECT: + { + InitialiseGammaSettings(128); + EpisodeSelectScrollOffset=0; + ExamineSavedUserProfiles(); + MakeUserProfileSelectMenu(); + break; + } + case AVPMENU_USERPROFILEENTERNAME: + { + AvPMenus.UserEnteringText = 1; + KeyboardEntryQueue_Clear(); + AvPMenus.MenuElements->TextPtr = UserProfilePtr->Name; + UserProfilePtr->Name[0] = 0; + AvPMenus.WidthLeftForText = 0; //will be calculated properly when menus are drawn + break; + } + case AVPMENU_MULTIPLAYER_SAVECONFIG: + { + AvPMenus.UserEnteringText = 1; + KeyboardEntryQueue_Clear(); + AvPMenus.WidthLeftForText = 0; //will be calculated properly when menus are drawn + break; + } + + case AVPMENU_SINGLEPLAYER: + { + break; + } + + case AVPMENU_MARINELEVELS: + { + MarineEpisodeToPlay=0; + EpisodeSelectScrollOffset=0; + AvPMenus.MenuElements->MaxSliderValue = NumberOfAvailableLevels(I_Marine); + *AvPMenus.MenuElements->SliderValuePtr = LevelMostLikelyToPlay(I_Marine); + break; + } + case AVPMENU_PREDATORLEVELS: + { + PredatorEpisodeToPlay=0; + EpisodeSelectScrollOffset=0; + AvPMenus.MenuElements->MaxSliderValue = NumberOfAvailableLevels(I_Predator); + *AvPMenus.MenuElements->SliderValuePtr = LevelMostLikelyToPlay(I_Predator); + break; + } + case AVPMENU_ALIENLEVELS: + { + AlienEpisodeToPlay=0; + EpisodeSelectScrollOffset=0; + AvPMenus.MenuElements->MaxSliderValue = NumberOfAvailableLevels(I_Alien); + *AvPMenus.MenuElements->SliderValuePtr = LevelMostLikelyToPlay(I_Alien); + break; + } + case AVPMENU_MULTIPLAYERSELECTSESSION: + { + if(previousMenuID!=AVPMENU_MULTIPLAYERSELECTSESSION) + { + //save ip address (if it has been set) + extern char IPAddressString[]; + SaveIPAddress(IP_Address_Name,IPAddressString); + DirectPlay_JoinGame(); + } + MakeSelectSessionMenu(); + break; + } + + case AVPMENU_MULTIPLAYER_SKIRMISH : + { + extern char MP_Config_Description[]; + netGameData.skirmishMode=TRUE; + LoadMultiplayerConfiguration(GetTextString(TEXTSTRING_PREVIOUSGAME_FILENAME)); + MP_Config_Description[0]=0; + break; + } + + case AVPMENU_MULTIPLAYER_CONNECTION: + { + extern char MP_Config_Description[]; + //skirmishMode must be false + netGameData.skirmishMode=FALSE; + + LoadMultiplayerConfiguration(GetTextString(TEXTSTRING_PREVIOUSGAME_FILENAME)); + MP_Config_Description[0]=0; + + + if(LobbiedGame) + { + //use alternative multiplayer menus for lobbied games + if(LobbiedGame==LobbiedGame_Server) + { + SetupNewMenu(AVPMENU_MULTIPLAYER_LOBBIEDSERVER); + } + else + { + SetupNewMenu(AVPMENU_MULTIPLAYER_LOBBIEDCLIENT); + } + return; + } + + DirectPlay_EnumConnections(); + MakeConnectionSelectMenu(); + break; + } + + case AVPMENU_INGAME: + case AVPMENU_INNETGAME: + { + if(AvP.Network != I_No_Network) + { + //in a multiplayer game set up a menu without the restart mission option + menuID=AVPMENU_INNETGAME; + AvPMenus.CurrentMenu = menuID; + AvPMenus.MenuElements = AvPMenusData[menuID].MenuElements; // could use default + AvPMenus.FontToUse = AvPMenusData[menuID].FontToUse; + } + MakeInGameMenu(); + break; + } + case AVPMENU_MARINEKEYCONFIG: + { + MakeMarineKeyConfigMenu(); + PlayerInputPrimaryConfig = MarineInputPrimaryConfig; + PlayerInputSecondaryConfig = MarineInputSecondaryConfig; + EpisodeSelectScrollOffset=0; + KeyConfigSelectionColumn = 0; + break; + } + case AVPMENU_PREDATORKEYCONFIG: + { + MakePredatorKeyConfigMenu(); + PlayerInputPrimaryConfig = PredatorInputPrimaryConfig; + PlayerInputSecondaryConfig = PredatorInputSecondaryConfig; + EpisodeSelectScrollOffset=0; + KeyConfigSelectionColumn = 0; + break; + } + case AVPMENU_ALIENKEYCONFIG: + { + MakeAlienKeyConfigMenu(); + PlayerInputPrimaryConfig = AlienInputPrimaryConfig; + PlayerInputSecondaryConfig = AlienInputSecondaryConfig; + EpisodeSelectScrollOffset=0; + KeyConfigSelectionColumn = 0; + break; + } + case AVPMENU_CONTROLS: + { + PlayerControlMethods = ControlMethods; + break; + } + case AVPMENU_JOYSTICKCONTROLS: + { + PlayerJoystickControlMethods = JoystickControlMethods; + break; + } + + case AVPMENU_MULTIPLAYERJOINGAME: + { + extern char IPAddressString[]; + extern char CommandLineIPAddressString[]; + strcpy(IPAddressString,CommandLineIPAddressString); + IP_Address_Name[0] = 0; + + if(netGameData.connectionType!=CONN_TCPIP) + { + ////for non tcpip games skip to the select session menu + SetupNewMenu(AVPMENU_MULTIPLAYERSELECTSESSION); + return; + + } + + + break; + } + + case AVPMENU_MULTIPLAYER : + { + break; + } + + + case AVPMENU_MULTIPLAYER_LOADCONFIG : + { + extern AVPMENU_ELEMENT* AvPMenu_Multiplayer_LoadConfig; + if(!BuildLoadMPConfigMenu()) + { + SetupNewMenu(AVPMENU_MULTIPLAYER_CONFIG); + return; + } + AvPMenus.MenuElements=AvPMenu_Multiplayer_LoadConfig; + break; + } + + case AVPMENU_MULTIPLAYER_CONFIG : + { + //need to set the menu we return to , according to whether this is + //a lobbied game or not. + if(LobbiedGame) + { + AvPMenusData[AvPMenus.CurrentMenu].ParentMenu=AVPMENU_MULTIPLAYER_LOBBIEDSERVER; + } + else if(netGameData.skirmishMode) + { + //for skirmish games , use skirmish config menu instead + SetupNewMenu(AVPMENU_SKIRMISH_CONFIG); + return; + } + else + { + AvPMenusData[AvPMenus.CurrentMenu].ParentMenu=AVPMENU_MULTIPLAYER; + } + break; + } + + case AVPMENU_MULTIPLAYER_CONFIG_JOIN : + { + //need to set the menu we return to , according to whether this is + //a lobbied game or not. + if(LobbiedGame) + { + AvPMenusData[AvPMenus.CurrentMenu].ParentMenu=AVPMENU_MULTIPLAYER_LOBBIEDCLIENT; + } + else + { + AvPMenusData[AvPMenus.CurrentMenu].ParentMenu=AVPMENU_MULTIPLAYER; + } + break; + } + + case AVPMENU_MULTIPLAYER_LOADIPADDRESS : + { + extern AVPMENU_ELEMENT* AvPMenu_Multiplayer_LoadIPAddress; + AvPMenus.MenuElements=AvPMenu_Multiplayer_LoadIPAddress; + break; + } + + case AVPMENU_MULTIPLAYEROPENADDRESS : + { + extern void MakeOpenIPAddressMenu(); + MakeOpenIPAddressMenu(); + break; + } + + case AVPMENU_SAVEGAME: + case AVPMENU_LOADGAME: + { + ScanSaveSlots(); + break; + } + + default: + break; + } + + /* count the number of elements in the menu */ + { + AVPMENU_ELEMENT *elementPtr = AvPMenus.MenuElements; + AvPMenus.NumberOfElementsInMenu=0; + AvPMenus.MenuHeight=0; + do + { + elementPtr->Brightness = BRIGHTNESS_OF_DARKENED_ELEMENT; + + AvPMenus.MenuHeight += HeightOfMenuElement(elementPtr); + + AvPMenus.NumberOfElementsInMenu++; + elementPtr++; + } + while(elementPtr->ElementID != AVPMENU_ELEMENT_ENDOFMENU); + } + + switch(menuID) + { + case AVPMENU_CHEATOPTIONS: + { + CheatMode_Active = 0; + break; + } + + case AVPMENU_MARINEKEYCONFIG: + case AVPMENU_ALIENKEYCONFIG: + case AVPMENU_PREDATORKEYCONFIG: + AvPMenus.MenuHeight += 50; + break; + case AVPMENU_LEVELBRIEFING_BASIC: + { + int episodeToPlay; + switch (AvP.PlayerType) + { + case I_Marine: + { + episodeToPlay = MarineEpisodeToPlay; + break; + } + case I_Predator: + { + episodeToPlay = PredatorEpisodeToPlay; + break; + } + case I_Alien: + { + episodeToPlay = AlienEpisodeToPlay; + break; + } + } + + /* find available difficulty levels */ + AvPMenus.NumberOfElementsInMenu=MaxDifficultyLevelAllowed(AvP.PlayerType, episodeToPlay); + /* highlight a suitable level of difficulty */ + if (episodeToPlay) + { + AvPMenus.CurrentlySelectedElement = AvPMenus.NumberOfElementsInMenu-1; + } + else // default to medium difficulty for first level + { + AvPMenus.CurrentlySelectedElement = 1; + } + + SetBriefingTextForEpisode(episodeToPlay, AvP.PlayerType); + + break; + } + case AVPMENU_LEVELBRIEFING_BONUS: + { + int episodeToPlay; + switch (AvP.PlayerType) + { + case I_Marine: + { + episodeToPlay = MarineEpisodeToPlay; + break; + } + case I_Predator: + { + episodeToPlay = PredatorEpisodeToPlay; + break; + } + case I_Alien: + { + episodeToPlay = AlienEpisodeToPlay; + break; + } + } + + SetBriefingTextForEpisode(episodeToPlay, AvP.PlayerType); + break; + } + default: + SetBriefingTextToBlank(); + break; + } +} + + +static void RenderMenu(void) +{ + AVPMENU_ELEMENT *elementPtr = AvPMenus.MenuElements; + int e; + int y; + + + if (AvPMenus.MenusState == MENUSSTATE_MAINMENUS) + { + if ((AvPMenus.CurrentMenu == AVPMENU_LEVELBRIEFING_BASIC) + ||(AvPMenus.CurrentMenu == AVPMENU_LEVELBRIEFING_BONUS)) + { + y = MENU_BOTTOMYEDGE - AvPMenus.MenuHeight; + RenderBriefingScreenInfo(); + } + else + { + y = MENU_CENTREY - (AvPMenus.MenuHeight)/2; + } + } + else // in game menus + { + y = (ScreenDescriptorBlock.SDB_Height - AvPMenus.MenuHeight)/2; + } + + for (e = 0; e elementPtr->Brightness) + { + elementPtr->Brightness+=BRIGHTNESS_CHANGE_SPEED; + if(elementPtr->Brightness>targetBrightness) + { + elementPtr->Brightness = targetBrightness; + } + } + else + { + elementPtr->Brightness-=BRIGHTNESS_CHANGE_SPEED; + if(elementPtr->BrightnessBrightness = targetBrightness; + } + + } + + RenderMenuElement(elementPtr,e,y); + y += HeightOfMenuElement(elementPtr); + } + + /* Render Menu Title */ + if (AvPMenus.MenusState == MENUSSTATE_MAINMENUS) + { + char *textPtr = GetTextString(AvPMenusData[AvPMenus.CurrentMenu].MenuTitle); + RenderMenuText(textPtr,MENU_CENTREX,70,ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + +#if 1 // and now we've been told to remove the "Gamers Edition" etc. :) + // main menu subtitle e.g. "Gamers Edition" etc. + if (AvPMenusData[AvPMenus.CurrentMenu].MenuTitle==TEXTSTRING_MAINMENU_TITLE) + RenderMenuText(GetTextString(TEXTSTRING_MAINMENU_SUBTITLE),MENU_CENTREX,100,ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); +#endif + } + + #if 0 + else + { + char *textPtr = GetTextString(AvPMenusData[AvPMenus.CurrentMenu].MenuTitle); + Hardware_RenderSmallMenuText(textPtr,MENU_CENTREX,70,ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + } + #endif + +} +static void RenderBriefingScreenInfo(void) +{ + enum TEXTSTRING_ID textID; + switch (AvP.PlayerType) + { + case I_Marine: + { + textID = MarineEpisodeToPlay+TEXTSTRING_MARINELEVELS_1; + break; + } + case I_Predator: + { + textID = PredatorEpisodeToPlay+TEXTSTRING_PREDATORLEVELS_1; + break; + } + case I_Alien: + { + textID = AlienEpisodeToPlay+TEXTSTRING_ALIENLEVELS_1; + break; + } + } + RenderMenuText(GetTextString(textID),MENU_LEFTXEDGE,120,ONE_FIXED,AVPMENUFORMAT_LEFTJUSTIFIED); +#if 0 + switch (AvP.PlayerType) + { + case I_Marine: + { + textID = MarineEpisodeToPlay+TEXTSTRING_LEVELBRIEFING_MARINELEVELS_1; + break; + } + case I_Predator: + { + textID = PredatorEpisodeToPlay+TEXTSTRING_LEVELBRIEFING_PREDATORLEVELS_1; + break; + } + case I_Alien: + { + textID = AlienEpisodeToPlay+TEXTSTRING_LEVELBRIEFING_ALIENLEVELS_1; + break; + } + } + RenderMenuText(GetTextString(textID),MENU_LEFTXEDGE,180,ONE_FIXED/2,AVPMENUFORMAT_LEFTJUSTIFIED); +#endif + RenderBriefingText(ScreenDescriptorBlock.SDB_Height/2,ONE_FIXED); +} +/* KJL 12:11:18 24/09/98 - specialised code to handle episode selection screen, which +has features which make it too awkward to add to the general system */ +static void RenderEpisodeSelectMenu(void) +{ + AVPMENU_ELEMENT *elementPtr = &AvPMenus.MenuElements[AvPMenus.CurrentlySelectedElement]; + int currentEpisode = *(elementPtr->SliderValuePtr); + int centrePosition = (currentEpisode)*65536+EpisodeSelectScrollOffset; + enum AVPMENUGFX_ID graphicID; + I_PLAYER_TYPE playerID; + int i; + int numberOfBasicLevels; + + switch (AvPMenus.CurrentMenu) + { + default: + { + LOCALASSERT(0);/* Panic */ + } + case AVPMENU_MARINELEVELS: + { + graphicID = AVPMENUGFX_MARINE_EPISODE1; + numberOfBasicLevels = MAX_NO_OF_BASIC_MARINE_EPISODES; + playerID = I_Marine; + break; + } + case AVPMENU_PREDATORLEVELS: + { + graphicID = AVPMENUGFX_PREDATOR_EPISODE1; + numberOfBasicLevels = MAX_NO_OF_BASIC_PREDATOR_EPISODES; + playerID = I_Predator; + break; + } + case AVPMENU_ALIENLEVELS: + { + graphicID = AVPMENUGFX_ALIEN_EPISODE1; + numberOfBasicLevels = MAX_NO_OF_BASIC_ALIEN_EPISODES; + playerID = I_Alien; + break; + } + } + { + char *textPtr = GetTextString(AvPMenusData[AvPMenus.CurrentMenu].MenuTitle); + RenderMenuText(textPtr,MENU_CENTREX,70,ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + } + for (i=0; i<=elementPtr->MaxSliderValue; i++) + { + int y; + + y = MUL_FIXED(i*65536-centrePosition,100); + + if (y>=-150 && y<=150) + { + char *textPtr = GetTextString(elementPtr->TextDescription+i); + int b; + int targetBrightness; + + if (i==currentEpisode) + { + targetBrightness = BRIGHTNESS_OF_HIGHLIGHTED_ELEMENT; + } + else + { + targetBrightness = BRIGHTNESS_OF_DARKENED_ELEMENT; + } + + if (targetBrightness > Brightness[i]) + { + Brightness[i]+=BRIGHTNESS_CHANGE_SPEED; + if(Brightness[i]>targetBrightness) + { + Brightness[i] = targetBrightness; + } + } + else + { + Brightness[i]-=BRIGHTNESS_CHANGE_SPEED; + if(Brightness[i]=i) + { + char *completedTextPtr; + + if (iLevelCompleted[playerID][i]); + } + else + { + if (UserProfilePtr->LevelCompleted[playerID][i]) + { + completedTextPtr = GetTextString(TEXTSTRING_COMPLETED); + } + else + { + completedTextPtr = GetTextString(TEXTSTRING_NOTYETCOMPLETED); + } + } + + RenderSmallMenuText + ( + completedTextPtr, + MENU_LEFTXEDGE+150, + yCoord+30, + b, + AVPMENUFORMAT_LEFTJUSTIFIED + ); + } + else + { + if (i == elementPtr->MaxSliderValue) + { + RenderSmallMenuText + ( + GetTextString(TEXTSTRING_NOTYETAVAILABLE_2), + MENU_LEFTXEDGE+150, + yCoord+30, + b, + AVPMENUFORMAT_LEFTJUSTIFIED + ); + } + else + { + RenderSmallMenuText + ( + GetTextString(TEXTSTRING_NOTYETAVAILABLE_1), + MENU_LEFTXEDGE+150, + yCoord+30, + b, + AVPMENUFORMAT_LEFTJUSTIFIED + ); + } + } + /* + ,MENU_CENTREY-60-100, + MENU_CENTREY-60+180 + );*/ + } + } + } + + if (EpisodeSelectScrollOffset>0) + { + EpisodeSelectScrollOffset -= MUL_FIXED(EpisodeSelectScrollOffset*2+8192,RealFrameTime<<1); + if (EpisodeSelectScrollOffset<0) + { + EpisodeSelectScrollOffset=0; + } + } + else if (EpisodeSelectScrollOffset<0) + { + EpisodeSelectScrollOffset += MUL_FIXED(-EpisodeSelectScrollOffset*2+8192,RealFrameTime<<1); + if (EpisodeSelectScrollOffset>0) + { + EpisodeSelectScrollOffset=0; + } + } + + +} +static void RenderKeyConfigurationMenu(void) +{ + AVPMENU_ELEMENT *elementPtr = AvPMenus.MenuElements;//AvPMenus.CurrentlySelectedElement]; + int centrePosition; + int i; + int centreY = ScreenDescriptorBlock.SDB_Height/2+25; + int y; + + if (AvPMenus.MenusState == MENUSSTATE_MAINMENUS) + { + char *textPtr = GetTextString(AvPMenusData[AvPMenus.CurrentMenu].MenuTitle); + int b; + if (AvPMenus.CurrentlySelectedElement>=2) + { + b = ONE_FIXED; + } + else + { + b = ONE_FIXED/4; + } + + RenderKeyConfigRectangle(b); + RenderMenuText(textPtr,MENU_CENTREX,70,ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + } + else + { + int b; + if (AvPMenus.CurrentlySelectedElement>=2) + { + b = ONE_FIXED; + } + else + { + b = ONE_FIXED/4; + } + + Hardware_RenderKeyConfigRectangle(b); + } + y = centreY-160; + for (i = 0; i<2; i++, elementPtr++) + { + int targetBrightness; + + if (i==AvPMenus.CurrentlySelectedElement) + { + targetBrightness = BRIGHTNESS_OF_HIGHLIGHTED_ELEMENT; + } + else + { + targetBrightness = BRIGHTNESS_OF_DARKENED_ELEMENT; + } + + if (targetBrightness > elementPtr->Brightness) + { + elementPtr->Brightness+=BRIGHTNESS_CHANGE_SPEED; + if(elementPtr->Brightness>targetBrightness) + { + elementPtr->Brightness = targetBrightness; + } + } + else + { + elementPtr->Brightness-=BRIGHTNESS_CHANGE_SPEED; + if(elementPtr->BrightnessBrightness = targetBrightness; + } + + } + + RenderMenuElement(elementPtr,i,y); + y += HeightOfMenuElement(elementPtr); + } + centrePosition = (AvPMenus.CurrentlySelectedElement)*ONE_FIXED; + if (centrePosition<2*ONE_FIXED) centrePosition = 2*ONE_FIXED; + for (i=2; i=-100 && y<=100) + { +// char *textPtr = GetTextString(elementPtr->TextDescription); + int targetBrightness; + + if (i==AvPMenus.CurrentlySelectedElement) + { + targetBrightness = BRIGHTNESS_OF_HIGHLIGHTED_ELEMENT; + } + else + { + targetBrightness = BRIGHTNESS_OF_DARKENED_ELEMENT; + } + + #if 0 + if (targetBrightness > elementPtr->Brightness) + { + elementPtr->Brightness+=BRIGHTNESS_CHANGE_SPEED; + if(elementPtr->Brightness>targetBrightness) + { + elementPtr->Brightness = targetBrightness; + } + } + else + { + elementPtr->Brightness-=BRIGHTNESS_CHANGE_SPEED; + if(elementPtr->BrightnessBrightness = targetBrightness; + } + + } + #else + elementPtr->Brightness = targetBrightness; + #endif + RenderMenuElement(elementPtr, i, centreY+y); + #if 0 + if (AvPMenus.MenusState == MENUSSTATE_INGAMEMENUS) + { + Hardware_RenderSmallMenuText(textPtr,MENU_LEFTXEDGE+150,centreY+y,b,AVPMENUFORMAT_LEFTJUSTIFIED/*,MENU_CENTREY-60-100,MENU_CENTREY-60+180*/); + } + else + { + RenderSmallMenuText(textPtr,MENU_LEFTXEDGE+150,centreY+y,b,AVPMENUFORMAT_LEFTJUSTIFIED/*,MENU_CENTREY-60-100,MENU_CENTREY-60+180*/); + } + #endif + + } + } + + if (EpisodeSelectScrollOffset>0) + { + EpisodeSelectScrollOffset -= MUL_FIXED(EpisodeSelectScrollOffset*2+8192,RealFrameTime<<1); + if (EpisodeSelectScrollOffset<0) + { + EpisodeSelectScrollOffset=0; + } + } + else if (EpisodeSelectScrollOffset<0) + { + EpisodeSelectScrollOffset += MUL_FIXED(-EpisodeSelectScrollOffset*2+8192,RealFrameTime<<1); + if (EpisodeSelectScrollOffset>0) + { + EpisodeSelectScrollOffset=0; + } + } +} + +static void RenderScrollyMenu() +{ + AVPMENU_ELEMENT *elementPtr = AvPMenus.MenuElements; + { + //draw the title + char *textPtr = GetTextString(AvPMenusData[AvPMenus.CurrentMenu].MenuTitle); + RenderMenuText(textPtr,MENU_CENTREX,70,ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + } + + { + int first=AvPMenus.CurrentlySelectedElement; + int last=AvPMenus.CurrentlySelectedElement; + int i; + int y; + BOOL done=FALSE; + + int available_above=(MENU_HEIGHT-HeightOfMenuElement(&elementPtr[AvPMenus.CurrentlySelectedElement]))/2; + int available_below=available_above; + + //work out the first and last element to be drawn + do + { + done=TRUE; + if(first-1>=0) + { + int h=HeightOfMenuElement(&elementPtr[first-1]); + if(h<=available_above) + { + available_above-=h; + first--; + done=FALSE; + } + else + { + available_below+=available_above; + available_above=0; + } + } + if(first==0) + { + //no more elements above selected element + available_below+=available_above; + available_above=0; + } + + if(last+1TextDescription); + int targetBrightness; + + if (i==AvPMenus.CurrentlySelectedElement) + { + targetBrightness = BRIGHTNESS_OF_HIGHLIGHTED_ELEMENT; + } + else + { + targetBrightness = BRIGHTNESS_OF_DARKENED_ELEMENT; + } + + elementPtr->Brightness = targetBrightness; + + RenderMenuElement(elementPtr, i, y); + y+=HeightOfMenuElement(elementPtr); + } + + } + +} + + +static void RenderUserProfileSelectMenu(void) +{ + AVPMENU_ELEMENT *elementPtr = &AvPMenus.MenuElements[AvPMenus.CurrentlySelectedElement]; + int currentEpisode = *(elementPtr->SliderValuePtr); + int centrePosition = (currentEpisode)*65536+EpisodeSelectScrollOffset; + int i; + AVP_USER_PROFILE *profilePtr = GetFirstUserProfile(); + { + char *textPtr = GetTextString(AvPMenusData[AvPMenus.CurrentMenu].MenuTitle); + RenderMenuText(textPtr,MENU_CENTREX,70,ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + } + GetLocalTime(&profilePtr->TimeLastUpdated); + for (i=0; i<=elementPtr->MaxSliderValue; i++, profilePtr = GetNextUserProfile()) + { + int y; + + y = MUL_FIXED(i*65536-centrePosition,80); + + if (y>=-150 && y<=150) + { + char *textPtr = profilePtr->Name; + int b; + int targetBrightness; + + if (i==currentEpisode) + { + targetBrightness = BRIGHTNESS_OF_HIGHLIGHTED_ELEMENT; + } + else + { + targetBrightness = BRIGHTNESS_OF_DARKENED_ELEMENT; + } + + if (targetBrightness > Brightness[i]) + { + Brightness[i]+=BRIGHTNESS_CHANGE_SPEED; + if(Brightness[i]>targetBrightness) + { + Brightness[i] = targetBrightness; + } + } + else + { + Brightness[i]-=BRIGHTNESS_CHANGE_SPEED; + if(Brightness[i]TimeLastUpdated.wHour, + profilePtr->TimeLastUpdated.wMinute, + profilePtr->TimeLastUpdated.wSecond, + profilePtr->TimeLastUpdated.wYear, + profilePtr->TimeLastUpdated.wMonth, + profilePtr->TimeLastUpdated.wDay); + */ + time_t time_of_day; + + time_of_day = time( NULL ); +// strftime( buffer, 80, "%c", +// localtime( &time_of_day ) ); + + nLen = GetDateFormat(GetThreadLocale(), DATE_LONGDATE, &profilePtr->TimeLastUpdated, + NULL,buffer, + nLen); + nLen = GetTimeFormat(GetThreadLocale(), 0, &profilePtr->TimeLastUpdated, + NULL,buffer2, + 100); + strcat(buffer2," "); + strcat(buffer2,buffer); + RenderSmallMenuText(buffer2,MENU_CENTREX,MENU_CENTREY+y-30,b,AVPMENUFORMAT_CENTREJUSTIFIED); + } + } + } + + if (EpisodeSelectScrollOffset>0) + { + EpisodeSelectScrollOffset -= MUL_FIXED(EpisodeSelectScrollOffset*2+8192,RealFrameTime<<1); + if (EpisodeSelectScrollOffset<0) + { + EpisodeSelectScrollOffset=0; + } + } + else if (EpisodeSelectScrollOffset<0) + { + EpisodeSelectScrollOffset += MUL_FIXED(-EpisodeSelectScrollOffset*2+8192,RealFrameTime<<1); + if (EpisodeSelectScrollOffset>0) + { + EpisodeSelectScrollOffset=0; + } + } + + +} + +static void RenderLoadGameMenu(void) +{ + AVPMENU_ELEMENT *elementPtr = AvPMenus.MenuElements; + int e; + int y; + int (*RenderText)(char *textPtr, int x, int y, int alpha, enum AVPMENUFORMAT_ID format); + + if (AvPMenus.MenusState == MENUSSTATE_MAINMENUS) + { + y = MENU_CENTREY - (AvPMenus.MenuHeight)/2; + RenderText = RenderSmallMenuText; + } + else // in game menus + { + y = (ScreenDescriptorBlock.SDB_Height - AvPMenus.MenuHeight)/2; + RenderText = Hardware_RenderSmallMenuText; + } + + for (e = 0; e elementPtr->Brightness) + { + elementPtr->Brightness+=BRIGHTNESS_CHANGE_SPEED; + if(elementPtr->Brightness>targetBrightness) + { + elementPtr->Brightness = targetBrightness; + } + } + else + { + elementPtr->Brightness-=BRIGHTNESS_CHANGE_SPEED; + if(elementPtr->BrightnessBrightness = targetBrightness; + } + + } + + sprintf(buffer,"%d.",e+1); + RenderText(buffer,MENU_LEFTXEDGE+20,y,elementPtr->Brightness,AVPMENUFORMAT_RIGHTJUSTIFIED); + + if (slotPtr->SlotUsed) + { + int textID; + int numberOfBasicEpisodes; + switch(slotPtr->Species) + { + case I_Marine: + { + textID = TEXTSTRING_MARINELEVELS_1; + numberOfBasicEpisodes = MAX_NO_OF_BASIC_MARINE_EPISODES; + break; + } + case I_Alien: + { + textID = TEXTSTRING_ALIENLEVELS_1; + numberOfBasicEpisodes = MAX_NO_OF_BASIC_ALIEN_EPISODES; + break; + } + case I_Predator: + { + textID = TEXTSTRING_PREDATORLEVELS_1; + numberOfBasicEpisodes = MAX_NO_OF_BASIC_PREDATOR_EPISODES; + break; + } + } + + + sprintf(buffer,"%s",GetTextString(TEXTSTRING_MULTIPLAYER_MARINE+slotPtr->Species)); + RenderText(buffer,MENU_LEFTXEDGE+30,y,elementPtr->Brightness,AVPMENUFORMAT_LEFTJUSTIFIED); + + sprintf(buffer,"%s",GetTextString(textID+slotPtr->Episode)); + RenderText(buffer,MENU_CENTREX,y,elementPtr->Brightness,AVPMENUFORMAT_CENTREJUSTIFIED); + + if (numberOfBasicEpisodes>slotPtr->Episode) + { + sprintf(buffer,"%s",GetTextString(TEXTSTRING_DIFFICULTY_EASY+slotPtr->Difficulty)); + RenderText(buffer,MENU_RIGHTXEDGE-30,y,elementPtr->Brightness,AVPMENUFORMAT_RIGHTJUSTIFIED); + } + + sprintf(buffer, "%s %02d:%02d:%02d",GetTextString(TEXTSTRING_GAMESTATS_TIMEELAPSED),slotPtr->ElapsedTime_Hours,slotPtr->ElapsedTime_Minutes,slotPtr->ElapsedTime_Seconds); + RenderText(buffer,MENU_LEFTXEDGE+30,y+HUD_FONT_HEIGHT+1,elementPtr->Brightness,AVPMENUFORMAT_LEFTJUSTIFIED); + + sprintf(buffer, "%s: %d",GetTextString(TEXTSTRING_SAVEGAME_SAVESLEFT),slotPtr->SavesLeft); + RenderText(buffer,MENU_CENTREX,y+HUD_FONT_HEIGHT+1,elementPtr->Brightness,AVPMENUFORMAT_CENTREJUSTIFIED); + + { + char buffer2[100]; + int nLen = 80; + + //GetLocalTime(&slotPtr->TimeStamp); + + nLen = GetDateFormat(GetThreadLocale(), DATE_SHORTDATE, &slotPtr->TimeStamp,NULL,buffer,nLen); + nLen = GetTimeFormat(GetThreadLocale(), 0, &slotPtr->TimeStamp,NULL,buffer2,100); + + strcat(buffer2," "); + strcat(buffer2,buffer); + RenderText(buffer2,MENU_RIGHTXEDGE-30,y+HUD_FONT_HEIGHT+1,elementPtr->Brightness,AVPMENUFORMAT_RIGHTJUSTIFIED); + } + } + else + { + RenderText(GetTextString(TEXTSTRING_SAVEGAME_EMPTYSLOT),MENU_CENTREX,y,elementPtr->Brightness,AVPMENUFORMAT_CENTREJUSTIFIED); + } + + y += HeightOfMenuElement(elementPtr); + } + + + /* Render Menu Title */ + if (AvPMenus.MenusState == MENUSSTATE_MAINMENUS) + { + char *textPtr = GetTextString(AvPMenusData[AvPMenus.CurrentMenu].MenuTitle); + RenderMenuText(textPtr,MENU_CENTREX,70,ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + } + else + { + char *textPtr = GetTextString(AvPMenusData[AvPMenus.CurrentMenu].MenuTitle); + AVPMENU_ELEMENT *elementPtr = &AvPMenus.MenuElements[AvPMenus.CurrentlySelectedElement]; + y = (ScreenDescriptorBlock.SDB_Height - AvPMenus.MenuHeight)/2 - 30; + RenderText(textPtr,MENU_CENTREX,y,ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + y = (ScreenDescriptorBlock.SDB_Height + AvPMenus.MenuHeight)/2 + 20; + RenderText(GetTextString(elementPtr->HelpString),MENU_CENTREX,y,ONE_FIXED,AVPMENUFORMAT_CENTREJUSTIFIED); + } +} + +static void RenderHelpString() +{ + AVPMENU_ELEMENT *elementPtr = &AvPMenus.MenuElements[AvPMenus.CurrentlySelectedElement]; + + if(elementPtr->HelpString!=TEXTSTRING_BLANK && AvPMenus.MenusState != MENUSSTATE_INGAMEMENUS) + { + RECT area; + //draw the attached string at the bottom of the screen + + area.left=MENU_LEFTXEDGE; + area.right=MENU_RIGHTXEDGE; + area.top=420; + area.bottom=ScreenDescriptorBlock.SDB_Height; + + RenderSmallFontString_Wrapped(GetTextString(elementPtr->HelpString),&area,BRIGHTNESS_OF_HIGHLIGHTED_ELEMENT,0,0); + + } +} + +static void RenderConfigurationDescriptionString() +{ + const char* text=GetMultiplayerConfigDescription(AvPMenus.CurrentlySelectedElement); + if(text) + { + RECT area; + //draw the text at the bottom of the screen + //now at the top. + + area.left=MENU_LEFTXEDGE; + area.right=MENU_RIGHTXEDGE; + area.top=0; + area.bottom=60; + + RenderSmallFontString_Wrapped(text,&area,BRIGHTNESS_OF_HIGHLIGHTED_ELEMENT,0,0); + } +} + + +static void ActUponUsersInput(void) +{ + static int BackspaceTimer=0; + //Set up a keyboard repeat rate thingy for deleting long strings + if(KeyboardInput[KEY_BACKSPACE]) + { + BackspaceTimer+=RealFrameTime; + } + else + { + BackspaceTimer=0; + } + + if (AvPMenus.UserEnteringText) + { + AVPMENU_ELEMENT *elementPtr = &AvPMenus.MenuElements[AvPMenus.CurrentlySelectedElement]; + + if (DebouncedKeyboardInput[KEY_ESCAPE] || DebouncedKeyboardInput[KEY_CR]) + { + elementPtr->TextPtr[AvPMenus.PositionInTextField] = 0; + AvPMenus.UserEnteringText = 0; + + // KJL 10:09:35 09/02/00 - when the user has entered their name, + // move down to the next option. If the user enters a null + // string, replace it with a placeholder name + if((AvPMenus.CurrentMenu == AVPMENU_USERPROFILEENTERNAME) + ||(AvPMenus.CurrentMenu == AVPMENU_MULTIPLAYER_SKIRMISH) + ||(AvPMenus.CurrentMenu == AVPMENU_MULTIPLAYER)) + { + if(AvPMenus.PositionInTextField==0) + { + strcpy(elementPtr->TextPtr,"DeadMeat"); + } + AvPMenus.CurrentlySelectedElement++; + } + } + else if (DebouncedKeyboardInput[KEY_BACKSPACE] || DebouncedKeyboardInput[KEY_LEFT]) + { + if (AvPMenus.PositionInTextField>0) + { + elementPtr->TextPtr[--AvPMenus.PositionInTextField] = 0; + } + } + else if(BackspaceTimer>ONE_FIXED/2) + { + //check for backspace being held down for a long time + while(BackspaceTimer>ONE_FIXED/2) + { + BackspaceTimer-=ONE_FIXED/20; + if (AvPMenus.PositionInTextField>0) + { + elementPtr->TextPtr[--AvPMenus.PositionInTextField] = 0; + } + } + } + else + { + //allow Ctrl+V to paste from the clipboard (really just for pasting in ip addresses) + if((KeyboardInput[KEY_LEFTCTRL] || KeyboardInput[KEY_RIGHTCTRL]) && KeyboardInput[KEY_V]) + { + PasteFromClipboard(elementPtr->TextPtr,elementPtr->MaxTextLength); + AvPMenus.PositionInTextField = strlen(elementPtr->TextPtr); + } + else if (AvPMenus.PositionInTextFieldMaxTextLength) + { + char c=0; + KeyboardEntryQueue_StartProcessing(); + + while(c=KeyboardEntryQueue_ProcessCharacter()) + { + if (AvPMenus.PositionInTextFieldMaxTextLength) + { + //see if there is room for this character + if(AvPMenus.FontToUse==AVPMENU_FONT_BIG && elementPtr->ElementID !=AVPMENU_ELEMENT_TEXTFIELD_SMALLWRAPPED) + { + //using large font + //allocate 32 pixels for each new character for the moment + //the true amount used will be worked out when the font is drawn + //Might cause a slight glitch for fast typists , but I forgot about + //the damned kerned fonts until after I'd written most of this + if(AvPMenus.WidthLeftForText<32) break; + AvPMenus.WidthLeftForText-=32; + + } + else + { + extern char AAFontWidths[256]; + //using small font + if(AvPMenus.WidthLeftForTextTextPtr[AvPMenus.PositionInTextField++] = c; + elementPtr->TextPtr[AvPMenus.PositionInTextField] = 0; + } + } + + } + + KeyboardEntryQueue_Clear(); + + } + } + else if (AvPMenus.UserEnteringNumber) + { + AVPMENU_ELEMENT *elementPtr = &AvPMenus.MenuElements[AvPMenus.CurrentlySelectedElement]; + + if (DebouncedKeyboardInput[KEY_ESCAPE] || DebouncedKeyboardInput[KEY_CR]) + { + AvPMenus.UserEnteringNumber = 0; + } + else if (DebouncedKeyboardInput[KEY_BACKSPACE] || DebouncedKeyboardInput[KEY_LEFT]) + { + (*elementPtr->NumberPtr)/=10; + } + else + { + char c=0; + + KeyboardEntryQueue_StartProcessing(); + while(c=KeyboardEntryQueue_ProcessCharacter()) + { + if (AvPMenus.PositionInTextFieldMaxTextLength) + { + if(c>='0' && c<='9') + { + (*elementPtr->NumberPtr)*=10; + (*elementPtr->NumberPtr)+=c-'0'; + + if((*elementPtr->NumberPtr)>elementPtr->MaxValue) + { + (*elementPtr->NumberPtr)=elementPtr->MaxValue; + } + } + } + } + } + KeyboardEntryQueue_Clear(); + } + else if (AvPMenus.UserChangingKeyConfig) + { + if (DebouncedKeyboardInput[KEY_ESCAPE]) + { + AvPMenus.UserChangingKeyConfig = 0; + } + else + { + signed int key,selectedKey=-1; + + // see if a valid key has been pressed + for (key = 0 ; key <= MAX_NUMBER_OF_INPUT_KEYS ; key++) + { + if (!(key == KEY_ESCAPE) && +// !(key >= KEY_F1 && key <= KEY_F12) && + !(key >= KEY_0 && key <= KEY_9) ) + { + if (DebouncedKeyboardInput[key]) + { + selectedKey = key; + break; + } + } + } + + if (AvPMenus.ChangingPrimaryConfig) + { + if (selectedKey!=-1) + { + *(((unsigned char*)&PlayerInputPrimaryConfig)+AvPMenus.CurrentlySelectedElement-2) = selectedKey; + AvPMenus.UserChangingKeyConfig=0; + } + } + else // changing Secondary + { + if (selectedKey!=-1) + { + *(((unsigned char*)&PlayerInputSecondaryConfig)+AvPMenus.CurrentlySelectedElement-2) = selectedKey; + AvPMenus.UserChangingKeyConfig=0; + } + } + } + } + else + { + if (DebouncedKeyboardInput[KEY_ESCAPE] && (AvPMenus.CurrentMenu != AVPMENU_MAIN && AvPMenus.CurrentMenu != AVPMENU_INGAME)) + { + //if (AvPMenus.CurrentMenu == AVPMENU_MULTIPLAYERJOINGAME2) + switch(AvPMenus.CurrentMenu) + { + case AVPMENU_MULTIPLAYER_CONFIG_JOIN: + { + AddNetMsg_PlayerLeaving(); + NetSendMessages(); + if(!LobbiedGame) + { + DirectPlay_Disconnect(); + } + break; + } + case AVPMENU_DETAILLEVELS: + { + SetDetailLevelsFromMenu(); + SaveUserProfile(UserProfilePtr); + if(AvPMenus.MenusState == MENUSSTATE_INGAMEMENUS) + { + SetupNewMenu(AVPMENU_INGAMEAVOPTIONS); + } + break; + } + case AVPMENU_INGAMEAVOPTIONS: + case AVPMENU_MAINMENUAVOPTIONS: + { + SaveUserProfile(UserProfilePtr); + break; + } + case AVPMENU_CHEATOPTIONS: + { + CheatMode_Active = CHEATMODE_NONACTIVE; + break; + } + + case AVPMENU_MULTIPLAYER_CONFIG : + case AVPMENU_SKIRMISH_CONFIG : + { + //reload the previous multiplayer configuration + extern char MP_Config_Description[]; + LoadMultiplayerConfiguration(GetTextString(TEXTSTRING_PREVIOUSGAME_FILENAME)); + MP_Config_Description[0]=0; + break; + } + + } + + + if(AvPMenus.MenusState == MENUSSTATE_INGAMEMENUS) + { + SetupNewMenu(AVPMENU_INGAME); + } + else + { + SetupNewMenu(AvPMenusData[AvPMenus.CurrentMenu].ParentMenu); + } + } + else if (IDemandSelect()) // select element + { + if (InputIsDebounced) + { + InteractWithMenuElement(AVPMENU_ELEMENT_INTERACTION_SELECT); + InputIsDebounced = 0; + } + } + else if (IDemandGoForward()) // previous element + { + if (InputIsDebounced) + { + switch (AvPMenus.CurrentMenu) + { + case AVPMENU_USERPROFILESELECT: + case AVPMENU_MARINELEVELS: + case AVPMENU_PREDATORLEVELS: + case AVPMENU_ALIENLEVELS: + { + InteractWithMenuElement(AVPMENU_ELEMENT_INTERACTION_DECREASE); + break; + } + case AVPMENU_MARINEKEYCONFIG: + case AVPMENU_PREDATORKEYCONFIG: + case AVPMENU_ALIENKEYCONFIG: + { + if (AvPMenus.CurrentlySelectedElement>0) + { + AvPMenus.CurrentlySelectedElement--; + Sound_Play(SID_MENUS_CHANGE_ITEM,"r"); + } + break; + } + default: + { + AvPMenus.CurrentlySelectedElement--; + if (AvPMenus.CurrentlySelectedElement<0) + { + AvPMenus.CurrentlySelectedElement= AvPMenus.NumberOfElementsInMenu-1; + } + Sound_Play(SID_MENUS_CHANGE_ITEM,"r"); + break; + } + } + InputIsDebounced = 0; + } + else + { + KeyDepressedCounter += RealFrameTime; + } + + } + else if (IDemandGoBackward()) // next element + { + if (InputIsDebounced) + { + switch (AvPMenus.CurrentMenu) + { + case AVPMENU_USERPROFILESELECT: + case AVPMENU_MARINELEVELS: + case AVPMENU_PREDATORLEVELS: + case AVPMENU_ALIENLEVELS: + { + InteractWithMenuElement(AVPMENU_ELEMENT_INTERACTION_INCREASE); + break; + } + case AVPMENU_MARINEKEYCONFIG: + case AVPMENU_PREDATORKEYCONFIG: + case AVPMENU_ALIENKEYCONFIG: + { + if (AvPMenus.CurrentlySelectedElement=AvPMenus.NumberOfElementsInMenu) + { + AvPMenus.CurrentlySelectedElement= 0; + } + Sound_Play(SID_MENUS_CHANGE_ITEM,"r"); + break; + } + } + + InputIsDebounced = 0; + } + else + { + KeyDepressedCounter += RealFrameTime; + } + } + else if (IDemandTurnLeft()) + { + if (InputIsDebounced) + { + InteractWithMenuElement(AVPMENU_ELEMENT_INTERACTION_DECREASE); + InputIsDebounced = 0; + } + else + { + KeyDepressedCounter += RealFrameTime; + } + } + else if (IDemandTurnRight()) + { + if (InputIsDebounced) + { + InteractWithMenuElement(AVPMENU_ELEMENT_INTERACTION_INCREASE); + InputIsDebounced = 0; + } + else + { + KeyDepressedCounter += RealFrameTime; + } + } + else if (DebouncedKeyboardInput[KEY_BACKSPACE]) + { + switch (AvPMenus.MenuElements[AvPMenus.CurrentlySelectedElement].ElementID) + { + case AVPMENU_ELEMENT_KEYCONFIG: + { + if (!KeyConfigSelectionColumn) + { + *(((unsigned char*)&PlayerInputPrimaryConfig)+AvPMenus.CurrentlySelectedElement-2) = KEY_VOID; + } + else // changing Secondary + { + *(((unsigned char*)&PlayerInputSecondaryConfig)+AvPMenus.CurrentlySelectedElement-2) = KEY_VOID; + } + break; + } + case AVPMENU_ELEMENT_USERPROFILE: + { + if (UserProfileNumber) + { + SetupNewMenu(AVPMENU_USERPROFILEDELETE); + } + break; + } + case AVPMENU_ELEMENT_LOADMPCONFIG : + { + //take note of the current configuration + MultiplayerConfigurationIndex=AvPMenus.CurrentlySelectedElement; + MultiplayerConfigurationName=AvPMenus.MenuElements[AvPMenus.CurrentlySelectedElement].TextPtr; + //setup the delete configuration menu + SetupNewMenu(AVPMENU_MULTIPLAYER_DELETECONFIG); + break; + } + default: + break; + } + } + else + { + InputIsDebounced=1; + KeyDepressedCounter = 0; + } + + if (KeyDepressedCounter>ONE_FIXED) + InputIsDebounced = 1; + } + +} +static void InteractWithMenuElement(enum AVPMENU_ELEMENT_INTERACTION_ID interactionID) +{ + AVPMENU_ELEMENT *elementPtr = &AvPMenus.MenuElements[AvPMenus.CurrentlySelectedElement]; + + if (interactionID==AVPMENU_ELEMENT_INTERACTION_SELECT) + { + Sound_Play(SID_MENUS_SELECT_ITEM,"r"); + } + else + { + Sound_Play(SID_MENUS_CHANGE_ITEM,"r"); + } + switch(elementPtr->ElementID) + { + default: + GLOBALASSERT("UNKNOWN MENU ELEMENT"==0); + case AVPMENU_ELEMENT_GOTOMENU: + case AVPMENU_ELEMENT_GOTOMENU_GFX: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + //Check to see if we are on one of the menus for entering multiplayer name + if(AvPMenus.CurrentMenu==AVPMENU_MULTIPLAYER || + AvPMenus.CurrentMenu==AVPMENU_MULTIPLAYER_LOBBIEDSERVER) + { + //save profile , so that multiplayer name is remembered + SaveUserProfile(UserProfilePtr); + } + + SetupNewMenu(elementPtr->MenuToGoTo); + } + break; + } + case AVPMENU_ELEMENT_SAVEMPCONFIG : + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + if(MP_Config_Name[0]) + { + SaveMultiplayerConfiguration(MP_Config_Name); + } + SetupNewMenu(elementPtr->MenuToGoTo); + } + break; + } + case AVPMENU_ELEMENT_TEXTFIELD: + { + AvPMenus.UserEnteringText = 1; + KeyboardEntryQueue_Clear(); + AvPMenus.PositionInTextField = strlen(elementPtr->TextPtr); + elementPtr->TextPtr[AvPMenus.PositionInTextField] = 0; + AvPMenus.WidthLeftForText = 0; //will be calculated properly when menus are drawn + break; + } + case AVPMENU_ELEMENT_TEXTFIELD_SMALLWRAPPED: + { + AvPMenus.UserEnteringText = 1; + KeyboardEntryQueue_Clear(); + AvPMenus.PositionInTextField = strlen(elementPtr->TextPtr); + AvPMenus.WidthLeftForText = 0; //will be calculated properly when menus are drawn + break; + } + + case AVPMENU_ELEMENT_NUMBERFIELD: + { + if(interactionID == AVPMENU_ELEMENT_INTERACTION_DECREASE) + { + (*elementPtr->NumberPtr)--; + if(*elementPtr->NumberPtr<0) + { + *elementPtr->NumberPtr=0; + } + } + else if(interactionID == AVPMENU_ELEMENT_INTERACTION_INCREASE) + { + (*elementPtr->NumberPtr)++; + if(*elementPtr->NumberPtr>elementPtr->MaxValue) + { + *elementPtr->NumberPtr=elementPtr->MaxValue; + } + + } + else + { + *elementPtr->NumberPtr=0; + AvPMenus.UserEnteringNumber = 1; + KeyboardEntryQueue_Clear(); + } + break; + } + case AVPMENU_ELEMENT_DUMMYTEXTFIELD: + case AVPMENU_ELEMENT_DUMMYTEXTSLIDER: + case AVPMENU_ELEMENT_DUMMYTEXTSLIDER_POINTER: + case AVPMENU_ELEMENT_DUMMYNUMBERFIELD: + case AVPMENU_ELEMENT_TOGGLE: + { + break; + } + case AVPMENU_ELEMENT_SLIDER: + { + if ((interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + ||(interactionID == AVPMENU_ELEMENT_INTERACTION_INCREASE)) + { + if (*elementPtr->SliderValuePtrMaxSliderValue) + { + *elementPtr->SliderValuePtr+=1; + } + } + else + { + if (*elementPtr->SliderValuePtr>0) + { + *elementPtr->SliderValuePtr-=1; + } + } + break; + } + case AVPMENU_ELEMENT_TEXTSLIDER: + case AVPMENU_ELEMENT_TEXTSLIDER_POINTER: + { + if ((interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + ||(interactionID == AVPMENU_ELEMENT_INTERACTION_INCREASE)) + { + *elementPtr->SliderValuePtr+=1; + if (*elementPtr->SliderValuePtr>elementPtr->MaxSliderValue) + { + *elementPtr->SliderValuePtr=0; + } + } + else + { + *elementPtr->SliderValuePtr-=1; + if (*elementPtr->SliderValuePtr<0) + { + *elementPtr->SliderValuePtr=elementPtr->MaxSliderValue; + } + } + break; + } + case AVPMENU_ELEMENT_SPECIES_TEXTSLIDER: + { + if ((interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + ||(interactionID == AVPMENU_ELEMENT_INTERACTION_INCREASE)) + { + *elementPtr->SliderValuePtr+=1; + if (*elementPtr->SliderValuePtr>elementPtr->MaxSliderValue) + { + *elementPtr->SliderValuePtr=0; + } + GetNextAllowedSpecies(elementPtr->SliderValuePtr,TRUE); + } + else + { + *elementPtr->SliderValuePtr-=1; + if (*elementPtr->SliderValuePtr<0) + { + *elementPtr->SliderValuePtr=elementPtr->MaxSliderValue; + } + GetNextAllowedSpecies(elementPtr->SliderValuePtr,FALSE); + } + break; + } + case AVPMENU_ELEMENT_CHEATMODE_SPECIES_TEXTSLIDER: + { + if ((interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + ||(interactionID == AVPMENU_ELEMENT_INTERACTION_INCREASE)) + { + *elementPtr->SliderValuePtr+=1; + if (*elementPtr->SliderValuePtr>elementPtr->MaxSliderValue) + { + *elementPtr->SliderValuePtr=0; + } + CheatMode_GetNextAllowedSpecies(elementPtr->SliderValuePtr,TRUE); + } + else + { + *elementPtr->SliderValuePtr-=1; + if (*elementPtr->SliderValuePtr<0) + { + *elementPtr->SliderValuePtr=elementPtr->MaxSliderValue; + } + CheatMode_GetNextAllowedSpecies(elementPtr->SliderValuePtr,FALSE); + } + break; + } + case AVPMENU_ELEMENT_CHEATMODE_TEXTSLIDER: + { + if ((interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + ||(interactionID == AVPMENU_ELEMENT_INTERACTION_INCREASE)) + { + *elementPtr->SliderValuePtr+=1; + if (*elementPtr->SliderValuePtr>elementPtr->MaxSliderValue) + { + *elementPtr->SliderValuePtr=0; + } + CheatMode_GetNextAllowedMode(elementPtr->SliderValuePtr,TRUE); + } + else + { + *elementPtr->SliderValuePtr-=1; + if (*elementPtr->SliderValuePtr<0) + { + *elementPtr->SliderValuePtr=elementPtr->MaxSliderValue; + } + CheatMode_GetNextAllowedMode(elementPtr->SliderValuePtr,FALSE); + } + break; + } + case AVPMENU_ELEMENT_CHEATMODE_ENVIRONMENT_TEXTSLIDER: + { + if ((interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + ||(interactionID == AVPMENU_ELEMENT_INTERACTION_INCREASE)) + { + *elementPtr->SliderValuePtr+=1; + if (*elementPtr->SliderValuePtr>elementPtr->MaxSliderValue) + { + *elementPtr->SliderValuePtr=0; + } + CheatMode_GetNextAllowedEnvironment(elementPtr->SliderValuePtr,TRUE); + } + else + { + *elementPtr->SliderValuePtr-=1; + if (*elementPtr->SliderValuePtr<0) + { + *elementPtr->SliderValuePtr=elementPtr->MaxSliderValue; + } + CheatMode_GetNextAllowedEnvironment(elementPtr->SliderValuePtr,FALSE); + } + break; + } + + case AVPMENU_ELEMENT_QUITGAME: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + if(AvPMenus.MenusState == MENUSSTATE_INGAMEMENUS) + { + AvP.MainLoopRunning = 0; + } + AvPMenus.MenusState = MENUSSTATE_OUTSIDEMENUS; + } + break; + } + + case AVPMENU_ELEMENT_USERPROFILE: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + /* a profile has been selected */ + int i; + UserProfilePtr = GetFirstUserProfile(); + for (i=0; iSliderValuePtrMaxSliderValue) + { + *elementPtr->SliderValuePtr+=1; + EpisodeSelectScrollOffset-=ONE_FIXED; + } + } + else + { + if (*elementPtr->SliderValuePtr>0) + { + *elementPtr->SliderValuePtr-=1; + EpisodeSelectScrollOffset+=ONE_FIXED; + } + } + break; + } + case AVPMENU_ELEMENT_USERPROFILE_DELETE: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + DeleteUserProfile(UserProfileNumber); + SetupNewMenu(AVPMENU_USERPROFILESELECT); + } + break; + } + case AVPMENU_ELEMENT_DELETEMPCONFIG: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + DeleteMultiplayerConfigurationByIndex(MultiplayerConfigurationIndex); + //go back to the load config menu + SetupNewMenu(AVPMENU_MULTIPLAYER_LOADCONFIG); + + } + break; + } + case AVPMENU_ELEMENT_DIFFICULTYLEVEL: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + if (AvPMenus.CurrentMenu == AVPMENU_LEVELBRIEFING_BASIC) + { + AvP.Difficulty = AvPMenus.CurrentlySelectedElement; + } + else + { + AvP.Difficulty = 1; + } + AvPMenus.MenusState = MENUSSTATE_STARTGAME; + } + break; + } + + case AVPMENU_ELEMENT_ALIENEPISODE: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT + &&MaximumSelectableLevel>=*elementPtr->SliderValuePtr) + { + AvP.PlayerType = I_Alien; + SetLevelToLoadForAlien(AlienEpisodeToPlay); + + if (AlienEpisodeToPlay=*elementPtr->SliderValuePtr) + { + AvP.PlayerType = I_Marine; + SetLevelToLoadForMarine(MarineEpisodeToPlay); + + if (MarineEpisodeToPlay=*elementPtr->SliderValuePtr) + { + AvP.PlayerType = I_Predator; + SetLevelToLoadForPredator(PredatorEpisodeToPlay); + + if (PredatorEpisodeToPlaySliderValuePtrMaxSliderValue) + { + *elementPtr->SliderValuePtr+=1; + EpisodeSelectScrollOffset-=ONE_FIXED; + } + } + else + { + if (*elementPtr->SliderValuePtr>0) + { + *elementPtr->SliderValuePtr-=1; + EpisodeSelectScrollOffset+=ONE_FIXED; + } + } + break; + } + case AVPMENU_ELEMENT_BUTTONSETTING: + { + + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + break; + } + /* else let it fall through */ + + if (interactionID == AVPMENU_ELEMENT_INTERACTION_INCREASE) + { + if (*elementPtr->SliderValuePtrMaxSliderValue) + { + *elementPtr->SliderValuePtr+=1; + EpisodeSelectScrollOffset-=ONE_FIXED; + } + } + else + { + if (*elementPtr->SliderValuePtr>0) + { + *elementPtr->SliderValuePtr-=1; + EpisodeSelectScrollOffset+=ONE_FIXED; + } + } + break; + } + + case AVPMENU_ELEMENT_STARTMARINEDEMO: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + AvPMenus.MenusState = MENUSSTATE_STARTGAME; + AvP.PlayerType = I_Marine; + AvP.Difficulty = 1; + SetLevelToLoad(AVP_ENVIRONMENT_INVASION); + } + break; + } + case AVPMENU_ELEMENT_STARTPREDATORDEMO: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + AvPMenus.MenusState = MENUSSTATE_STARTGAME; + AvP.PlayerType = I_Predator; + AvP.Difficulty = 1; + SetLevelToLoad(AVP_ENVIRONMENT_INVASION_P); + } + break; + } + case AVPMENU_ELEMENT_STARTALIENDEMO: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + AvPMenus.MenusState = MENUSSTATE_STARTGAME; + AvP.PlayerType = I_Alien; + AvP.Difficulty = 1; + SetLevelToLoad(AVP_ENVIRONMENT_INVASION_A); + } + break; + } + case AVPMENU_ELEMENT_STARTLEVELWITHCHEAT: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + AvPMenus.MenusState = MENUSSTATE_STARTGAME; + AvP.PlayerType = CheatMode_Species; + AvP.Difficulty = 1; + SetLevelToLoadForCheatMode(CheatMode_Environment); + } + break; + } + case AVPMENU_ELEMENT_STARTMPGAME: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + extern int DirectPlay_HostGame(char *playerName, char *sessionName,int species,int gamestyle,int level); + extern char MP_PlayerName[]; + extern char MP_SessionName[]; + extern int MP_Species; + extern char MP_Config_Description[]; +// extern int MP_GameStyle; +// extern int MP_LevelNumber; + + //save the 'Previous Game' multiplayer configuration + strcpy(MP_Config_Description,GetTextString(TEXTSTRING_PREVIOUSGAME_FILENAME)); + SaveMultiplayerConfiguration(GetTextString(TEXTSTRING_PREVIOUSGAME_FILENAME)); + + + AvP.Difficulty = 1; + + if (DirectPlay_HostGame(MP_PlayerName,MP_SessionName,MP_Species,netGameData.gameType,netGameData.levelNumber)) + { + AvPMenus.MenusState = MENUSSTATE_STARTGAME; + if(netGameData.gameType==NGT_Coop) + SetLevelToLoadForCooperative(netGameData.levelNumber); + else + SetLevelToLoadForMultiplayer(netGameData.levelNumber); + + + SetBriefingTextForMultiplayer(); + + } + } + break; + } + case AVPMENU_ELEMENT_JOINMPGAME: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + extern int MP_LevelNumber; + AvPMenus.MenusState = MENUSSTATE_STARTGAME; + netGameData.myStartFlag = 1; +// netGameData.myGameState = NGS_Playing; + if(netGameData.gameType==NGT_Coop) + SetLevelToLoadForCooperative(netGameData.levelNumber); + else + SetLevelToLoadForMultiplayer(netGameData.levelNumber); + SetBriefingTextForMultiplayer(); + } + break; + } + case AVPMENU_ELEMENT_LISTCHOICE: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + extern char MP_PlayerName[]; + extern char MP_SessionName[]; + int s = AvPMenus.CurrentlySelectedElement; + + if(SessionData[s].AllowedToJoin) + { + //copy the session name , leaving of the player count information + char * braket_pos; + strcpy(MP_SessionName,SessionData[s].Name); + + braket_pos=strrchr(MP_SessionName,'('); + if(braket_pos) *braket_pos=0; + + if(DirectPlay_ConnectToSession(s,MP_PlayerName)) + SetupNewMenu(elementPtr->MenuToGoTo); + } + } + break; + } + case AVPMENU_ELEMENT_JOINLOBBIED : + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + //save profile , so that multiplayer name is remembered + SaveUserProfile(UserProfilePtr); + + InitAVPNetGameForJoin(); + SetupNewMenu(elementPtr->MenuToGoTo); + } + break; + } + + case AVPMENU_ELEMENT_LOADMPCONFIG: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + LoadMultiplayerConfigurationByIndex(AvPMenus.CurrentlySelectedElement); + SetupNewMenu(elementPtr->MenuToGoTo); + } + break; + } + + case AVPMENU_ELEMENT_LOADIPADDRESS: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + LoadIPAddress(elementPtr->TextPtr); + SetupNewMenu(elementPtr->MenuToGoTo); + } + break; + } + + case AVPMENU_ELEMENT_CONNECTIONCHOICE : + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + netGameData.connectionType=elementPtr->Value; + if(netGameData.connectionType == CONN_Mplayer) + { + //exit the game and launch the mplayer stuff + LaunchingMplayer=TRUE; + LaunchMplayer(); + AvP.MainLoopRunning = 0; + AvPMenus.MenusState = MENUSSTATE_OUTSIDEMENUS; + break; + } + else + { + SetupNewMenu(elementPtr->MenuToGoTo); + } + + } + break; + } + + case AVPMENU_ELEMENT_VIDEOMODE: + { + if ((interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + ||(interactionID == AVPMENU_ELEMENT_INTERACTION_INCREASE)) + { + NextVideoMode2(); + } + else + { + PreviousVideoMode2(); + } + break; + } + case AVPMENU_ELEMENT_VIDEOMODEOK: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + SaveDeviceAndVideoModePreferences(); + SetupNewMenu(elementPtr->MenuToGoTo); + } + break; + } + case AVPMENU_ELEMENT_RESUMEGAME: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + AvPMenus.MenusState = MENUSSTATE_STARTGAME; + } + break; + } + case AVPMENU_ELEMENT_RESTARTGAME: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + AvP.RestartLevel=1; + AvPMenus.MenusState = MENUSSTATE_STARTGAME; + } + break; + } + + case AVPMENU_ELEMENT_KEYCONFIG: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + AvPMenus.UserChangingKeyConfig = 1; + if (KeyConfigSelectionColumn) + { + AvPMenus.ChangingPrimaryConfig = 0; + } + else + { + AvPMenus.ChangingPrimaryConfig = 1; + } + } + else + { + KeyConfigSelectionColumn=!KeyConfigSelectionColumn; + } + break; + } + case AVPMENU_ELEMENT_KEYCONFIGOK: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + switch (AvPMenus.CurrentMenu) + { + case AVPMENU_MARINEKEYCONFIG: + { + MarineInputPrimaryConfig = PlayerInputPrimaryConfig; + MarineInputSecondaryConfig = PlayerInputSecondaryConfig; + { + extern int AutoWeaponChangeOn_Temp; + extern int AutoWeaponChangeOn; + AutoWeaponChangeOn = AutoWeaponChangeOn_Temp; + } + break; + } + case AVPMENU_PREDATORKEYCONFIG: + { + PredatorInputPrimaryConfig = PlayerInputPrimaryConfig; + PredatorInputSecondaryConfig = PlayerInputSecondaryConfig; + break; + } + case AVPMENU_ALIENKEYCONFIG: + { + AlienInputPrimaryConfig = PlayerInputPrimaryConfig; + AlienInputSecondaryConfig = PlayerInputSecondaryConfig; + break; + } + case AVPMENU_CONTROLS: + { + ControlMethods = PlayerControlMethods; + break; + } + case AVPMENU_JOYSTICKCONTROLS: + { + JoystickControlMethods = PlayerJoystickControlMethods; + break; + } + } + + + SaveUserProfile(UserProfilePtr); + + if(AvPMenus.MenusState == MENUSSTATE_INGAMEMENUS) + { + SetupNewMenu(AVPMENU_INGAME); + } + else + { + SetupNewMenu(AVPMENU_OPTIONS); + } + } + break; + } + case AVPMENU_ELEMENT_RESETKEYCONFIG: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + switch (AvPMenus.CurrentMenu) + { + case AVPMENU_MARINEKEYCONFIG: + { + PlayerInputPrimaryConfig = DefaultMarineInputPrimaryConfig; + PlayerInputSecondaryConfig = DefaultMarineInputSecondaryConfig; + break; + } + case AVPMENU_PREDATORKEYCONFIG: + { + PlayerInputPrimaryConfig = DefaultPredatorInputPrimaryConfig; + PlayerInputSecondaryConfig = DefaultPredatorInputSecondaryConfig; + break; + } + case AVPMENU_ALIENKEYCONFIG: + { + PlayerInputPrimaryConfig = DefaultAlienInputPrimaryConfig; + PlayerInputSecondaryConfig = DefaultAlienInputSecondaryConfig; + break; + } + case AVPMENU_CONTROLS: + { + PlayerControlMethods = DefaultControlMethods; + break; + } + case AVPMENU_JOYSTICKCONTROLS: + { + PlayerJoystickControlMethods = DefaultJoystickControlMethods; + break; + } + + } + } + break; + } + + case AVPMENU_ELEMENT_RESETMPCONFIG : + { + //reset the multiplayer configuration + extern void SetDefaultMultiplayerConfig(); + SetDefaultMultiplayerConfig(); + break; + } + + case AVPMENU_ELEMENT_SAVESETTINGS: + { + if (interactionID == AVPMENU_ELEMENT_INTERACTION_SELECT) + { + SetDetailLevelsFromMenu(); + SaveUserProfile(UserProfilePtr); + + if(AvPMenus.MenusState == MENUSSTATE_INGAMEMENUS) + { + if(AvPMenus.CurrentMenu == AVPMENU_DETAILLEVELS) + { + SetupNewMenu(AVPMENU_INGAMEAVOPTIONS); + } + else + { + SetupNewMenu(AVPMENU_INGAME); + } + } + else + { + SetupNewMenu(AvPMenusData[AvPMenus.CurrentMenu].ParentMenu); + } + } + break; + } + + case AVPMENU_ELEMENT_LOADGAME: + { + int slot = AvPMenus.CurrentlySelectedElement; + if(slot>=0 && slot=0 && slotElementID) + { + default: + GLOBALASSERT("UNKNOWN MENU ELEMENT"==0); + case AVPMENU_ELEMENT_GOTOMENU: + case AVPMENU_ELEMENT_QUITGAME: + case AVPMENU_ELEMENT_STARTMPGAME: + case AVPMENU_ELEMENT_JOINMPGAME: + case AVPMENU_ELEMENT_VIDEOMODEOK: + case AVPMENU_ELEMENT_RESUMEGAME: + case AVPMENU_ELEMENT_RESTARTGAME: + case AVPMENU_ELEMENT_KEYCONFIGOK: + case AVPMENU_ELEMENT_RESETKEYCONFIG: + case AVPMENU_ELEMENT_STARTMARINEDEMO: + case AVPMENU_ELEMENT_STARTPREDATORDEMO: + case AVPMENU_ELEMENT_STARTALIENDEMO: + case AVPMENU_ELEMENT_STARTLEVELWITHCHEAT: + case AVPMENU_ELEMENT_SAVEMPCONFIG: + case AVPMENU_ELEMENT_DIFFICULTYLEVEL: + case AVPMENU_ELEMENT_JOINLOBBIED: + case AVPMENU_ELEMENT_CONNECTIONCHOICE : + case AVPMENU_ELEMENT_USERPROFILE_DELETE: + case AVPMENU_ELEMENT_RESETMPCONFIG: + case AVPMENU_ELEMENT_DELETEMPCONFIG: + case AVPMENU_ELEMENT_SAVESETTINGS: + { + char *textPtr = GetTextString(elementPtr->TextDescription); + RenderText(textPtr,MENU_CENTREX,y,elementPtr->Brightness,AVPMENUFORMAT_CENTREJUSTIFIED); + break; + } + #if 0 + case AVPMENU_ELEMENT_STARTALIENGAME: + case AVPMENU_ELEMENT_STARTMARINEGAME: + case AVPMENU_ELEMENT_STARTPREDATORGAME: + { + char *textPtr = GetTextString(elementPtr->TextDescription); + RenderText(textPtr,MENU_LEFTXEDGE,MENU_BOTTOMYEDGE,elementPtr->Brightness,AVPMENUFORMAT_LEFTJUSTIFIED); + break; + } + + case AVPMENU_ELEMENT_MARINEEPISODE: + case AVPMENU_ELEMENT_ALIENEPISODE: + case AVPMENU_ELEMENT_PREDATOREPISODE: + { + char *textPtr = GetTextString(elementPtr->TextDescription+*(elementPtr->SliderValuePtr)); + RenderText(textPtr,MENU_LEFTXEDGE,MENU_TOPYEDGE,elementPtr->Brightness,AVPMENUFORMAT_LEFTJUSTIFIED); + break; + } + #endif + + case AVPMENU_ELEMENT_DUMMYTEXTSLIDER: + case AVPMENU_ELEMENT_DUMMYTEXTSLIDER_POINTER: + case AVPMENU_ELEMENT_TEXTSLIDER: + case AVPMENU_ELEMENT_TEXTSLIDER_POINTER: + case AVPMENU_ELEMENT_SPECIES_TEXTSLIDER: + case AVPMENU_ELEMENT_CHEATMODE_TEXTSLIDER: + case AVPMENU_ELEMENT_CHEATMODE_SPECIES_TEXTSLIDER: + case AVPMENU_ELEMENT_CHEATMODE_ENVIRONMENT_TEXTSLIDER: + { + char *textPtr = ""; + if(elementPtr->ElementID == AVPMENU_ELEMENT_TEXTSLIDER_POINTER || + elementPtr->ElementID == AVPMENU_ELEMENT_DUMMYTEXTSLIDER_POINTER) + { + //we have a pointer to the strings rather than the first string index + if(elementPtr->TextSliderStringPointer) + { + textPtr = elementPtr->TextSliderStringPointer[*(elementPtr->SliderValuePtr)]; + } + } + else + { + //we have the index of the first string + textPtr = GetTextString(elementPtr->FirstTextSliderString+*(elementPtr->SliderValuePtr)); + } + + if(elementPtr->TextDescription!=TEXTSTRING_BLANK) + { + + if(AvPMenus.MenusState == MENUSSTATE_INGAMEMENUS) + { + RenderText + ( + GetTextString(elementPtr->TextDescription), + MENU_CENTREX-MENU_ELEMENT_SPACING, + y, + elementPtr->Brightness, + AVPMENUFORMAT_RIGHTJUSTIFIED + ); + RenderText + ( + textPtr, + MENU_CENTREX+MENU_ELEMENT_SPACING, + y, + elementPtr->Brightness, + AVPMENUFORMAT_LEFTJUSTIFIED + ); + + } + else + { + int length = LengthOfMenuText(textPtr); + + if (length>ScreenDescriptorBlock.SDB_Width-MENU_CENTREX-MENU_ELEMENT_SPACING*2) + { + RenderText + ( + GetTextString(elementPtr->TextDescription), + ScreenDescriptorBlock.SDB_Width-MENU_ELEMENT_SPACING*2-length, + y, + elementPtr->Brightness, + AVPMENUFORMAT_RIGHTJUSTIFIED + ); + RenderText + ( + textPtr, + ScreenDescriptorBlock.SDB_Width-MENU_ELEMENT_SPACING, + y, + elementPtr->Brightness, + AVPMENUFORMAT_RIGHTJUSTIFIED + ); + } + else + { + + RenderText + ( + GetTextString(elementPtr->TextDescription), + MENU_CENTREX-MENU_ELEMENT_SPACING, + y, + elementPtr->Brightness, + AVPMENUFORMAT_RIGHTJUSTIFIED + ); + RenderText + ( + textPtr, + MENU_CENTREX+MENU_ELEMENT_SPACING, + y, + elementPtr->Brightness, + AVPMENUFORMAT_LEFTJUSTIFIED + ); + } + } + } + else + { + RenderText + ( + textPtr, + MENU_CENTREX, + y, + elementPtr->Brightness, + AVPMENUFORMAT_CENTREJUSTIFIED + ); + } + break; + } + case AVPMENU_ELEMENT_DUMMYTEXTFIELD: + case AVPMENU_ELEMENT_TEXTFIELD: + { + if (elementPtr->TextDescription==TEXTSTRING_BLANK) + { + if (AvPMenus.UserEnteringText && e==AvPMenus.CurrentlySelectedElement) + { + int b = GetSin(CloakingPhase&4095); + int x = RenderText(elementPtr->TextPtr,MENU_CENTREX,y,elementPtr->Brightness/2,AVPMENUFORMAT_CENTREJUSTIFIED); + x = RenderText("I",x,y,MUL_FIXED(b,b),AVPMENUFORMAT_CENTREJUSTIFIED); + + //work out how much space was left over + if(AvPMenus.PositionInTextField) + AvPMenus.WidthLeftForText = MENU_RIGHTXEDGE -x; + else + AvPMenus.WidthLeftForText = MENU_RIGHTXEDGE -MENU_CENTREX; + } + else + { + RenderText(elementPtr->TextPtr,MENU_CENTREX,y,elementPtr->Brightness,AVPMENUFORMAT_CENTREJUSTIFIED); + } + } + else + { + RenderText(GetTextString(elementPtr->TextDescription),MENU_CENTREX-MENU_ELEMENT_SPACING,y,elementPtr->Brightness,AVPMENUFORMAT_RIGHTJUSTIFIED); + + if (AvPMenus.UserEnteringText && e==AvPMenus.CurrentlySelectedElement) + { + int b = GetSin(CloakingPhase&4095); + int x = RenderText(elementPtr->TextPtr,MENU_CENTREX+MENU_ELEMENT_SPACING,y,elementPtr->Brightness/2,AVPMENUFORMAT_LEFTJUSTIFIED); + x = RenderText("I",x,y,MUL_FIXED(b,b),AVPMENUFORMAT_LEFTJUSTIFIED); + + //work out how much space was left over + if(AvPMenus.PositionInTextField) + AvPMenus.WidthLeftForText = MENU_RIGHTXEDGE -x; + else + AvPMenus.WidthLeftForText = MENU_RIGHTXEDGE -(MENU_CENTREX+MENU_ELEMENT_SPACING); + } + else + { + RenderText(elementPtr->TextPtr,MENU_CENTREX+MENU_ELEMENT_SPACING,y,elementPtr->Brightness,AVPMENUFORMAT_LEFTJUSTIFIED); + } + } + break; + } + + case AVPMENU_ELEMENT_TEXTFIELD_SMALLWRAPPED: + { + if (elementPtr->TextDescription==TEXTSTRING_BLANK) + { + RECT area; + area.left=MENU_LEFTXEDGE; + area.right=MENU_RIGHTXEDGE; + area.top=y; + area.bottom=y+4*HUD_FONT_HEIGHT; + + if (AvPMenus.UserEnteringText && e==AvPMenus.CurrentlySelectedElement) + { + int output_x,output_y; + int b = GetSin(CloakingPhase&4095); + RenderSmallFontString_Wrapped(elementPtr->TextPtr,&area,elementPtr->Brightness/2,&output_x,&output_y); + output_x = RenderSmallMenuText("I",output_x,output_y,MUL_FIXED(b,b),AVPMENUFORMAT_LEFTJUSTIFIED); + + //work out how much space was left over + if(area.bottom - output_y < HUD_FONT_HEIGHT) + { + //no space left + AvPMenus.WidthLeftForText= 0; + } + else if(area.bottom - output_y >= 2*HUD_FONT_HEIGHT) + { + //at least a whole line left + AvPMenus.WidthLeftForText= area.right-area.left; + } + else + { + //on the last line + AvPMenus.WidthLeftForText= area.right-output_x; + } + } + else + { + RenderSmallFontString_Wrapped(elementPtr->TextPtr,&area,elementPtr->Brightness,0,0); + } + } + else + { + RECT area; + area.left=MENU_CENTREX+MENU_ELEMENT_SPACING; + area.right=MENU_RIGHTXEDGE; + area.top=y; + area.bottom=y+4*HUD_FONT_HEIGHT; + + RenderText(GetTextString(elementPtr->TextDescription),MENU_CENTREX-MENU_ELEMENT_SPACING,y+HUD_FONT_HEIGHT,elementPtr->Brightness,AVPMENUFORMAT_RIGHTJUSTIFIED); + + if (AvPMenus.UserEnteringText && e==AvPMenus.CurrentlySelectedElement) + { + int output_x,output_y; + int b = GetSin(CloakingPhase&4095); + RenderSmallFontString_Wrapped(elementPtr->TextPtr,&area,elementPtr->Brightness/2,&output_x,&output_y); + output_x = RenderSmallMenuText("I",output_x,output_y,MUL_FIXED(b,b),AVPMENUFORMAT_LEFTJUSTIFIED); + + //work out how much space was left over + if(area.bottom - output_y < HUD_FONT_HEIGHT) + { + //no space left + AvPMenus.WidthLeftForText= 0; + } + else if(area.bottom - output_y >= 2*HUD_FONT_HEIGHT) + { + //at least a whole line left + AvPMenus.WidthLeftForText= area.right-area.left; + } + else + { + //on the last line + AvPMenus.WidthLeftForText= area.right-output_x; + } + } + else + { + RenderSmallFontString_Wrapped(elementPtr->TextPtr,&area,elementPtr->Brightness,0,0); + } + } + break; + } + + case AVPMENU_ELEMENT_DUMMYNUMBERFIELD: + case AVPMENU_ELEMENT_NUMBERFIELD: + { + { + static char NumberString[50]; + if(*elementPtr->NumberPtr!=0 || elementPtr->NumberFieldZeroString==TEXTSTRING_BLANK) + { + sprintf(NumberString,"%d",*elementPtr->NumberPtr); + if(elementPtr->NumberFieldUnitsString!=TEXTSTRING_BLANK) + { + //add the text for the unit type + strcat(NumberString," "); + strcat(NumberString,GetTextString(elementPtr->NumberFieldUnitsString)); + } + } + else + { + //use the special string to represent 0 + sprintf(NumberString,"%s",GetTextString(elementPtr->NumberFieldZeroString)); + } + + if (elementPtr->TextDescription==TEXTSTRING_BLANK) + { + if (AvPMenus.UserEnteringNumber && e==AvPMenus.CurrentlySelectedElement) + { + int b = GetSin(CloakingPhase&4095); + int x = RenderText(NumberString,MENU_CENTREX,y,elementPtr->Brightness/2,AVPMENUFORMAT_CENTREJUSTIFIED); + RenderText("I",x,y,MUL_FIXED(b,b),AVPMENUFORMAT_CENTREJUSTIFIED); + } + else + { + RenderText(NumberString,MENU_CENTREX,y,elementPtr->Brightness,AVPMENUFORMAT_CENTREJUSTIFIED); + } + } + else + { + RenderText(GetTextString(elementPtr->TextDescription),MENU_CENTREX-MENU_ELEMENT_SPACING,y,elementPtr->Brightness,AVPMENUFORMAT_RIGHTJUSTIFIED); + + if (AvPMenus.UserEnteringNumber && e==AvPMenus.CurrentlySelectedElement) + { + int b = GetSin(CloakingPhase&4095); + int x = RenderText(NumberString,MENU_CENTREX+MENU_ELEMENT_SPACING,y,elementPtr->Brightness/2,AVPMENUFORMAT_LEFTJUSTIFIED); + RenderText("I",x,y,MUL_FIXED(b,b),AVPMENUFORMAT_LEFTJUSTIFIED); + } + else + { + RenderText(NumberString,MENU_CENTREX+MENU_ELEMENT_SPACING,y,elementPtr->Brightness,AVPMENUFORMAT_LEFTJUSTIFIED); + } + } + } + break; + } + + case AVPMENU_ELEMENT_GOTOMENU_GFX: + { + DrawAvPMenuGfx(elementPtr->GfxID,MENU_CENTREX,y,elementPtr->Brightness,AVPMENUFORMAT_CENTREJUSTIFIED); + break; + } + case AVPMENU_ELEMENT_LISTCHOICE: + { + RenderText(elementPtr->TextPtr,MENU_CENTREX,y,elementPtr->Brightness,AVPMENUFORMAT_CENTREJUSTIFIED); + break; + } + case AVPMENU_ELEMENT_LOADMPCONFIG: + { + RenderText(elementPtr->TextPtr,MENU_CENTREX,y,elementPtr->Brightness,AVPMENUFORMAT_CENTREJUSTIFIED); + break; + } + case AVPMENU_ELEMENT_LOADIPADDRESS: + { + RenderText(elementPtr->TextPtr,MENU_CENTREX,y,elementPtr->Brightness,AVPMENUFORMAT_CENTREJUSTIFIED); + break; + } + + case AVPMENU_ELEMENT_TOGGLE: + { + break; + } + case AVPMENU_ELEMENT_SLIDER: + { + int x = MENU_CENTREX+MENU_ELEMENT_SPACING+3; + x+=(201*(*elementPtr->SliderValuePtr))/elementPtr->MaxSliderValue; + RenderText(GetTextString(elementPtr->TextDescription),MENU_CENTREX-MENU_ELEMENT_SPACING,y,elementPtr->Brightness,AVPMENUFORMAT_RIGHTJUSTIFIED); + if(AvPMenus.MenusState == MENUSSTATE_INGAMEMENUS) + { + D3D_DrawSliderBar(MENU_CENTREX+MENU_ELEMENT_SPACING,y+1,elementPtr->Brightness); + D3D_DrawSlider(x,y+4,elementPtr->Brightness); + } + else + { + DrawAvPMenuGfx(AVPMENUGFX_SLIDERBAR,MENU_CENTREX+MENU_ELEMENT_SPACING,y+1,elementPtr->Brightness,AVPMENUFORMAT_LEFTJUSTIFIED); + DrawAvPMenuGfx(AVPMENUGFX_SLIDER,x,y+4,elementPtr->Brightness,AVPMENUFORMAT_LEFTJUSTIFIED); + } + + + break; + } + case AVPMENU_ELEMENT_VIDEOMODE: + { +/* RenderText + ( + GetTextString(elementPtr->TextDescription), + MENU_CENTREX-MENU_ELEMENT_SPACING, + y, + elementPtr->Brightness, + AVPMENUFORMAT_RIGHTJUSTIFIED + ); */ + RenderText + ( + GetVideoModeDescription2(), + MENU_CENTREX, + y, + elementPtr->Brightness, + AVPMENUFORMAT_CENTREJUSTIFIED + ); + RenderText + ( + GetVideoModeDescription3(), + MENU_CENTREX, + y+MENU_FONT_HEIGHT+MENU_ELEMENT_SPACING, + elementPtr->Brightness, + AVPMENUFORMAT_CENTREJUSTIFIED + ); + break; + } + case AVPMENU_ELEMENT_KEYCONFIG: + { + unsigned char *primaryKey = ((unsigned char*)&PlayerInputPrimaryConfig)+e-2; + unsigned char *secondaryKey = ((unsigned char*)&PlayerInputSecondaryConfig)+e-2; + if (e==AvPMenus.CurrentlySelectedElement) + { + int x,g; + if (KeyConfigSelectionColumn) + { + x = MENU_RIGHTXEDGE; + } + else + { + x = MENU_CENTREX; + } + if (AvPMenus.UserChangingKeyConfig) + { + g = 255; + } + else + { + g = 128; + } + + if(AvPMenus.MenusState == MENUSSTATE_INGAMEMENUS) + { + Hardware_RenderHighlightRectangle(x-100,y-4,x+4,y+19,0,g,0); + } + else + { + RenderHighlightRectangle(x-100,y-4,x+4,y+19,0,g,0); + } + } + if (AvPMenus.UserChangingKeyConfig && e==AvPMenus.CurrentlySelectedElement) + { + int b = GetSin(CloakingPhase&4095); + if (AvPMenus.ChangingPrimaryConfig) + { + RenderText("_",MENU_CENTREX,y,MUL_FIXED(b,b),AVPMENUFORMAT_RIGHTJUSTIFIED); + RenderText + ( + GetDescriptionOfKey(*secondaryKey), + MENU_RIGHTXEDGE, + y, + elementPtr->Brightness, + AVPMENUFORMAT_RIGHTJUSTIFIED + ); + + } + else + { + RenderText + ( + GetDescriptionOfKey(*primaryKey), + MENU_CENTREX, + y, + elementPtr->Brightness, + AVPMENUFORMAT_RIGHTJUSTIFIED + ); + RenderText("_",MENU_RIGHTXEDGE,y,MUL_FIXED(b,b),AVPMENUFORMAT_RIGHTJUSTIFIED); + + } + + } + else + { + if (MultipleAssignments[0][e-2]) + { + RenderText_Coloured + ( + GetDescriptionOfKey(*primaryKey), + MENU_CENTREX, + y, + ONE_FIXED, + AVPMENUFORMAT_RIGHTJUSTIFIED, + ONE_FIXED, + ONE_FIXED, + 0 + ); + } + else + { + RenderText + ( + GetDescriptionOfKey(*primaryKey), + MENU_CENTREX, + y, + elementPtr->Brightness, + AVPMENUFORMAT_RIGHTJUSTIFIED + ); + } + if (MultipleAssignments[1][e-2]) + { + RenderText_Coloured + ( + GetDescriptionOfKey(*secondaryKey), + MENU_RIGHTXEDGE, + y, + ONE_FIXED, + AVPMENUFORMAT_RIGHTJUSTIFIED, + ONE_FIXED, + ONE_FIXED, + 0 + ); + } + else + { + RenderText + ( + GetDescriptionOfKey(*secondaryKey), + MENU_RIGHTXEDGE, + y, + elementPtr->Brightness, + AVPMENUFORMAT_RIGHTJUSTIFIED + ); + } + } + + RenderText + ( + GetTextString(elementPtr->TextDescription), + MENU_LEFTXEDGE, + y, + elementPtr->Brightness, + AVPMENUFORMAT_LEFTJUSTIFIED + ); + + + } + } +} + +static int HeightOfMenuElement(AVPMENU_ELEMENT *elementPtr) +{ + int h = MENU_ELEMENT_SPACING; + + switch(elementPtr->ElementID) + { + default: + { + if (AvPMenus.FontToUse==AVPMENU_FONT_BIG) + { + h += MENU_FONT_HEIGHT; + } + else + { + h = HUD_FONT_HEIGHT+4; + } + break; + } + case AVPMENU_ELEMENT_LOADGAME: + case AVPMENU_ELEMENT_SAVEGAME: + { + h= HUD_FONT_HEIGHT*2+4; + break; + } + case AVPMENU_ELEMENT_VIDEOMODE: + { + h += MENU_FONT_HEIGHT; + h *=2; + break; + } + + case AVPMENU_ELEMENT_TEXTFIELD_SMALLWRAPPED : + { + h+=HUD_FONT_HEIGHT*4; + break; + } + + #if 0 + case AVPMENU_ELEMENT_STARTALIENGAME: + case AVPMENU_ELEMENT_STARTMARINEGAME: + case AVPMENU_ELEMENT_STARTPREDATORGAME: + #endif + /* + case AVPMENU_ELEMENT_DUMMYTEXTFIELD: + case AVPMENU_ELEMENT_TEXTFIELD: + { + h += MENU_FONT_HEIGHT*2; + break; + } + */ + + case AVPMENU_ELEMENT_GOTOMENU_GFX: + { + h += HeightOfMenuGfx(elementPtr->GfxID); + break; + } +#if 0 + case AVPMENU_ELEMENT_SLIDER: + { + h += HeightOfMenuGfx(AVPMENUGFX_SLIDER); + break; + } +#endif + } + return h; +} + +static char *GetDescriptionOfKey(unsigned char key) +{ + static char KeyDescBuffer[2]="\0\0"; + char *textPtr; + + switch (key) + { + case KEY_UP: + textPtr = GetTextString(TEXTSTRING_KEYS_UP); + break; + case KEY_DOWN: + textPtr = GetTextString(TEXTSTRING_KEYS_DOWN); + break; + case KEY_LEFT: + textPtr = GetTextString(TEXTSTRING_KEYS_LEFT); + break; + case KEY_RIGHT: + textPtr = GetTextString(TEXTSTRING_KEYS_RIGHT); + break; + case KEY_CR: + textPtr = GetTextString(TEXTSTRING_KEYS_RETURN); + break; + case KEY_TAB: + textPtr = GetTextString(TEXTSTRING_KEYS_TAB); + break; + case KEY_INS: + textPtr = GetTextString(TEXTSTRING_KEYS_INSERT); + break; + case KEY_DEL: + textPtr = GetTextString(TEXTSTRING_KEYS_DELETE); + break; + case KEY_END: + textPtr = GetTextString(TEXTSTRING_KEYS_END); + break; + case KEY_HOME: + textPtr = GetTextString(TEXTSTRING_KEYS_HOME); + break; + case KEY_PAGEUP: + textPtr = GetTextString(TEXTSTRING_KEYS_PGUP); + break; + case KEY_PAGEDOWN: + textPtr = GetTextString(TEXTSTRING_KEYS_PGDOWN); + break; + case KEY_BACKSPACE: + textPtr = GetTextString(TEXTSTRING_KEYS_BACKSP); + break; + case KEY_COMMA: + textPtr = GetTextString(TEXTSTRING_KEYS_COMMA); + break; + case KEY_FSTOP: + textPtr = GetTextString(TEXTSTRING_KEYS_PERIOD); + break; + case KEY_SPACE: + textPtr = GetTextString(TEXTSTRING_KEYS_SPACE); + break; + case KEY_LMOUSE: + textPtr = GetTextString(TEXTSTRING_KEYS_LMOUSE); + break; + case KEY_RMOUSE: + textPtr = GetTextString(TEXTSTRING_KEYS_RMOUSE); + break; + case KEY_MMOUSE: + textPtr = GetTextString(TEXTSTRING_KEYS_MMOUSE); + break; + case KEY_MOUSEBUTTON4: + textPtr = GetTextString(TEXTSTRING_KEYS_MOUSEBUTTON4); + break; + case KEY_MOUSEWHEELUP: + textPtr = GetTextString(TEXTSTRING_KEYS_MOUSEWHEELUP); + break; + case KEY_MOUSEWHEELDOWN: + textPtr = GetTextString(TEXTSTRING_KEYS_MOUSEWHEELDOWN); + break; + case KEY_LEFTALT: + textPtr = GetTextString(TEXTSTRING_KEYS_LALT); + break; + case KEY_RIGHTALT: + textPtr = GetTextString(TEXTSTRING_KEYS_RALT); + break; + case KEY_LEFTCTRL: + textPtr = GetTextString(TEXTSTRING_KEYS_LCTRL); + break; + case KEY_RIGHTCTRL: + textPtr = GetTextString(TEXTSTRING_KEYS_RCTRL); + break; + case KEY_LEFTSHIFT: + textPtr = GetTextString(TEXTSTRING_KEYS_LSHIFT); + break; + case KEY_RIGHTSHIFT: + textPtr = GetTextString(TEXTSTRING_KEYS_RSHIFT); + break; + case KEY_CAPS: + textPtr = GetTextString(TEXTSTRING_KEYS_CAPS); + break; + case KEY_NUMLOCK: + textPtr = GetTextString(TEXTSTRING_KEYS_NUMLOCK); + break; + case KEY_SCROLLOK: + textPtr = GetTextString(TEXTSTRING_KEYS_SCRLOCK); + break; + case KEY_NUMPAD0: + textPtr = GetTextString(TEXTSTRING_KEYS_PAD0); + break; + case KEY_NUMPAD1: + textPtr = GetTextString(TEXTSTRING_KEYS_PAD1); + break; + case KEY_NUMPAD2: + textPtr = GetTextString(TEXTSTRING_KEYS_PAD2); + break; + case KEY_NUMPAD3: + textPtr = GetTextString(TEXTSTRING_KEYS_PAD3); + break; + case KEY_NUMPAD4: + textPtr = GetTextString(TEXTSTRING_KEYS_PAD4); + break; + case KEY_NUMPAD5: + textPtr = GetTextString(TEXTSTRING_KEYS_PAD5); + break; + case KEY_NUMPAD6: + textPtr = GetTextString(TEXTSTRING_KEYS_PAD6); + break; + case KEY_NUMPAD7: + textPtr = GetTextString(TEXTSTRING_KEYS_PAD7); + break; + case KEY_NUMPAD8: + textPtr = GetTextString(TEXTSTRING_KEYS_PAD8); + break; + case KEY_NUMPAD9: + textPtr = GetTextString(TEXTSTRING_KEYS_PAD9); + break; + case KEY_NUMPADSUB: + textPtr = GetTextString(TEXTSTRING_KEYS_PADSUB); + break; + case KEY_NUMPADADD: + textPtr = GetTextString(TEXTSTRING_KEYS_PADADD); + break; + case KEY_NUMPADDEL: + textPtr = GetTextString(TEXTSTRING_KEYS_PADDEL); + break; + case KEY_JOYSTICK_BUTTON_1: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_1); + break; + case KEY_JOYSTICK_BUTTON_2: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_2); + break; + case KEY_JOYSTICK_BUTTON_3: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_3); + break; + case KEY_JOYSTICK_BUTTON_4: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_4); + break; + case KEY_JOYSTICK_BUTTON_5: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_5); + break; + case KEY_JOYSTICK_BUTTON_6: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_6); + break; + case KEY_JOYSTICK_BUTTON_7: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_7); + break; + case KEY_JOYSTICK_BUTTON_8: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_8); + break; + case KEY_JOYSTICK_BUTTON_9: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_9); + break; + case KEY_JOYSTICK_BUTTON_10: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_10); + break; + case KEY_JOYSTICK_BUTTON_11: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_11); + break; + case KEY_JOYSTICK_BUTTON_12: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_12); + break; + case KEY_JOYSTICK_BUTTON_13: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_13); + break; + case KEY_JOYSTICK_BUTTON_14: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_14); + break; + case KEY_JOYSTICK_BUTTON_15: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_15); + break; + case KEY_JOYSTICK_BUTTON_16: + textPtr = GetTextString(TEXTSTRING_KEYS_JOYSTICKBUTTON_16); + break; + case KEY_LBRACKET: + textPtr = GetTextString(TEXTSTRING_KEYS_LBRACKET); + break; + case KEY_RBRACKET: + textPtr = GetTextString(TEXTSTRING_KEYS_RBRACKET); + break; + case KEY_SEMICOLON: + textPtr = GetTextString(TEXTSTRING_KEYS_SEMICOLON); + break; + case KEY_APOSTROPHE: + textPtr = GetTextString(TEXTSTRING_KEYS_APOSTROPHE); + break; + case KEY_GRAVE: + textPtr = GetTextString(TEXTSTRING_KEYS_GRAVE); + break; + case KEY_BACKSLASH: + textPtr = GetTextString(TEXTSTRING_KEYS_BACKSLASH); + break; + case KEY_SLASH: + textPtr = GetTextString(TEXTSTRING_KEYS_SLASH); + break; + case KEY_NUMPADENTER: + textPtr = GetTextString(TEXTSTRING_KEYS_NUMPADENTER); + break; + case KEY_NUMPADDIVIDE: + textPtr = GetTextString(TEXTSTRING_KEYS_NUMPADDIVIDE); + break; + case KEY_NUMPADMULTIPLY: + textPtr = GetTextString(TEXTSTRING_KEYS_NUMPADMULTIPLY); + break; + case KEY_CAPITAL: + textPtr = GetTextString(TEXTSTRING_KEYS_CAPITAL); + break; + case KEY_MINUS: + textPtr = GetTextString(TEXTSTRING_KEYS_MINUS); + break; + case KEY_EQUALS: + textPtr = GetTextString(TEXTSTRING_KEYS_EQUALS); + break; + case KEY_LWIN: + textPtr = GetTextString(TEXTSTRING_KEYS_LWIN); + break; + case KEY_RWIN: + textPtr = GetTextString(TEXTSTRING_KEYS_RWIN); + break; + case KEY_APPS: + textPtr = GetTextString(TEXTSTRING_KEYS_APPS); + break; + case KEY_F1: + textPtr = GetTextString(TEXTSTRING_KEYS_F1); + break; + case KEY_F2: + textPtr = GetTextString(TEXTSTRING_KEYS_F2); + break; + case KEY_F3: + textPtr = GetTextString(TEXTSTRING_KEYS_F3); + break; + case KEY_F4: + textPtr = GetTextString(TEXTSTRING_KEYS_F4); + break; + case KEY_F5: + textPtr = GetTextString(TEXTSTRING_KEYS_F5); + break; + case KEY_F6: + textPtr = GetTextString(TEXTSTRING_KEYS_F6); + break; + case KEY_F7: + textPtr = GetTextString(TEXTSTRING_KEYS_F7); + break; + case KEY_F8: + textPtr = GetTextString(TEXTSTRING_KEYS_F8); + break; + case KEY_F9: + textPtr = GetTextString(TEXTSTRING_KEYS_F9); + break; + case KEY_F10: + textPtr = GetTextString(TEXTSTRING_KEYS_F10); + break; + case KEY_F11: + textPtr = GetTextString(TEXTSTRING_KEYS_F11); + break; + case KEY_F12: + textPtr = GetTextString(TEXTSTRING_KEYS_F12); + break; + + case KEY_A_UMLAUT: + KeyDescBuffer[0] = 196; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_O_UMLAUT: + KeyDescBuffer[0] = 214; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_U_UMLAUT: + KeyDescBuffer[0] = 220; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_BETA: + KeyDescBuffer[0] = 223; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_PLUS: + KeyDescBuffer[0] = '+'; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_HASH: + KeyDescBuffer[0] = '#'; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_UPSIDEDOWNEXCLAMATION: + KeyDescBuffer[0] = 161; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_C_CEDILLA: + KeyDescBuffer[0] = 199; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_N_TILDE: + KeyDescBuffer[0] = 209; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_RIGHTBRACKET: + KeyDescBuffer[0] = ')'; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_ASTERISK: + KeyDescBuffer[0] = '*'; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_DOLLAR: + KeyDescBuffer[0] = '$'; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_U_GRAVE: + KeyDescBuffer[0] = 217; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_EXCLAMATION: + KeyDescBuffer[0] = '!'; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_COLON: + KeyDescBuffer[0] = ':'; + textPtr = KeyDescBuffer; + break; + case KEY_DIACRITIC_GRAVE: + KeyDescBuffer[0] = 96; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_DIACRITIC_ACUTE: + KeyDescBuffer[0] = 180; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_DIACRITIC_CARET: + KeyDescBuffer[0] = '^'; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_DIACRITIC_UMLAUT: + KeyDescBuffer[0] = 168; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_ORDINAL: + KeyDescBuffer[0] = 186; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + case KEY_LESSTHAN: + KeyDescBuffer[0] = '<'; // Windows Latin 1 (ANSI) + textPtr = KeyDescBuffer; + break; + + case KEY_VOID: + KeyDescBuffer[0] = 0; + textPtr = KeyDescBuffer; + break; + + + default: // alpha-numeric case + { + if (key >= KEY_A && key <= KEY_Z) + { + KeyDescBuffer[0] = key - KEY_A + 'A'; + } + else if (key >= KEY_0 && key <= KEY_9) + { + KeyDescBuffer[0] = key - KEY_0 + '0'; + } + else // um, no idea - send blank + { + KeyDescBuffer[0] = 0; + } + textPtr = KeyDescBuffer; + break; + } + + } + return textPtr; +} + +static int OkayToPlayNextEpisode(void) +{ + switch(AvP.PlayerType) + { + default: + GLOBALASSERT(0); + case I_Marine: + { + if (UserProfilePtr->LevelCompleted[AvP.PlayerType][MarineEpisodeToPlay] < AvP.Difficulty+1) + { + UserProfilePtr->LevelCompleted[AvP.PlayerType][MarineEpisodeToPlay]=AvP.Difficulty+1; + } + SaveUserProfile(UserProfilePtr); + SetupNewMenu(AVPMENU_MARINELEVELS); + return 1; + #if 0 + if (MarineEpisodeToPlayLevelCompleted[AvP.PlayerType][PredatorEpisodeToPlay] < AvP.Difficulty+1) + { + UserProfilePtr->LevelCompleted[AvP.PlayerType][PredatorEpisodeToPlay]=AvP.Difficulty+1; + } + SaveUserProfile(UserProfilePtr); + SetupNewMenu(AVPMENU_PREDATORLEVELS); + return 1; + #if 0 + if (PredatorEpisodeToPlayLevelCompleted[AvP.PlayerType][AlienEpisodeToPlay] < AvP.Difficulty+1) + { + UserProfilePtr->LevelCompleted[AvP.PlayerType][AlienEpisodeToPlay]=AvP.Difficulty+1; + } + SaveUserProfile(UserProfilePtr); + SetupNewMenu(AVPMENU_ALIENLEVELS); + return 1; + #if 0 + if (AlienEpisodeToPlayLevelCompleted[playerID][i]=3)) + i++; + UserProfilePtr->LevelCompleted[playerID][i]=3; + #else + + while (iLevelCompleted[playerID][i]) + i++; + + MaximumSelectableLevel = i; + { + int l; + for (l=0; l<=numberOfBasicLevels; l++) + { + if (UserProfilePtr->LevelCompleted[playerID][l]LevelCompleted[playerID][l]; + } + } + switch(maxDifficulty) + { + case AVP_DIFFICULTY_LEVEL_EASY: + { + MaximumSelectableLevel = maximumLevel-3; + i = maximumLevel; + break; + } + case AVP_DIFFICULTY_LEVEL_MEDIUM: + { + MaximumSelectableLevel = maximumLevel-1; + i = maximumLevel; + break; + } + case AVP_DIFFICULTY_LEVEL_HARD: + { + MaximumSelectableLevel = maximumLevel; + i = maximumLevel; + break; + } + default: + break; + } + } + //while (iLevelCompleted[playerID][i]!=0)) + // i++; + #endif + + return i; +} +int LevelMostLikelyToPlay(I_PLAYER_TYPE playerID) +{ + int i=0; + int maximumLevel; + + switch(playerID) + { + case I_Marine: + { + maximumLevel = MAX_NO_OF_MARINE_EPISODES-1; + break; + } + case I_Predator: + { + maximumLevel = MAX_NO_OF_PREDATOR_EPISODES-1; + break; + } + case I_Alien: + { + maximumLevel = MAX_NO_OF_ALIEN_EPISODES-1; + break; + } + } + + while (iLevelCompleted[playerID][i]!=0)) + i++; + + return i; +} + +int MaxDifficultyLevelAllowed(I_PLAYER_TYPE playerID, int level) +{ + if (level == 0) return 3; + else return UserProfilePtr->LevelCompleted[playerID][level-1]; +} +void DisplayVideoModeUnavailableScreen(void) +{ + do + { + CheckForWindowsMessages(); + DrawMainMenusBackdrop(); + ReadUserInput(); + { + RECT area; + //draw the attached string at the bottom of the screen + + area.left=MENU_LEFTXEDGE; + area.right=MENU_RIGHTXEDGE; + area.top=0; + area.bottom=ScreenDescriptorBlock.SDB_Height; + + RenderSmallFontString_Wrapped(GetTextString(TEXTSTRING_NOTENOUGHMEMORY),&area,BRIGHTNESS_OF_HIGHLIGHTED_ELEMENT,0,0); + + } + + ShowMenuFrameRate(); + + FlipBuffers(); + FrameCounterHandler(); + PlayMenuMusic(); + } + while(!DebouncedGotAnyKey); +} + + +void CheckForCredits(void) +{ + FILE *fp = fopen("credits.txt","rb"); + + if (!fp) + { + char message[100]; + sprintf(message,"Unable to access credits.txt\n"); + MessageBox(NULL,message,"AvP Error",MB_OK+MB_SYSTEMMODAL); + exit(0x111); + return; + } + else + { + fclose(fp); + } +} +void DoCredits(void) +{ + int position = 300*2048; + BOOL FinishedCredits = FALSE; + + char *creditsBufferPtr = LoadTextFile("credits.txt"); + char *creditsPtr; + + if (!creditsBufferPtr) return; + + if (!strncmp (creditsBufferPtr, "REBCRIF1", 8)) + { + creditsPtr = (char*)HuffmanDecompress((HuffmanPackage*)(creditsBufferPtr)); + DeallocateMem(creditsBufferPtr); + creditsBufferPtr=creditsPtr; + } + else + { + creditsPtr = creditsBufferPtr; + } + + + do + { + CheckForWindowsMessages(); + DrawMainMenusBackdrop(); + ReadUserInput(); + + FinishedCredits = !RollCreditsText(position,creditsPtr+4); + ShowMenuFrameRate(); + + FlipBuffers(); + FrameCounterHandler(); + PlayMenuMusic(); + position -= RealFrameTime; + } + while(!DebouncedGotAnyKey && !FinishedCredits); + + UnloadTextFile("credits.txt",creditsPtr); +} + +BOOL RollCreditsText(int position, unsigned char *textPtr) +{ + int y=0; + + while(*textPtr!='#') + { + char buffer1[96]; + char buffer2[96]; + int i; + int centredText,splitText; + + + { + int yy = 60+y+position/2048; + + if (yy >= 60 && yy <= 400) + { + int b; + { + if (*textPtr=='}') + { + textPtr++; + centredText = 1; + } + else + { + centredText = 0; + } + + for (i=0; i<80 && (*textPtr!='\r')&&(*textPtr!='\n')&&(*textPtr!='\0')&&(*textPtr!='|'); i++) + { + buffer1[i] = *textPtr++; + // if (buffer1[i]>='a' && buffer1[i]<='z') buffer1[i] += 'A' - 'a'; + } + buffer1[i]=0; + + if (*textPtr=='|') + { + textPtr++; + for (i=0; i<80 && (*textPtr!='\r')&&(*textPtr!='\n')&&(*textPtr!='\0'); i++) + { + buffer2[i] = *textPtr++; + } + buffer2[i]=0; + splitText = 1; + } + else + { + splitText = 0; + } + + textPtr++; + while(*textPtr=='\n') textPtr++; + + } + + if (yy<92) + { + b = (yy-60)*2048; + } + else if (yy>400-32) + { + b = (400-yy)*2048; + } + else + { + b = ONE_FIXED; + } + + if (splitText) + { + RenderSmallMenuText(buffer1,MENU_CENTREX-MENU_ELEMENT_SPACING,yy,b,AVPMENUFORMAT_RIGHTJUSTIFIED); + RenderSmallMenuText(buffer2,MENU_CENTREX+MENU_ELEMENT_SPACING,yy,b,AVPMENUFORMAT_LEFTJUSTIFIED); + } + else + { + if (centredText) + { + RenderSmallMenuText(buffer1,MENU_CENTREX,yy,b,AVPMENUFORMAT_CENTREJUSTIFIED); + } + else + { + RenderSmallMenuText(buffer1,MENU_LEFTXEDGE,yy,b,AVPMENUFORMAT_LEFTJUSTIFIED); + } + } + + } + else + { + while(*textPtr++!='\n'); + } + } + y+=15; + } + + if(y+(position/2048)<0) + { + //finished + return FALSE; + } + return TRUE; +} +/* KJL 17:50:06 24/06/98 - setup video mode for Menus */ + +extern int VideoModeTypeScreen; +extern int RasterisationRequestMode; +extern int VideoMode; +extern int WindowMode; +extern int WindowRequestMode; + +extern int DXMemoryMode; +extern int DXMemoryRequestMode; + +extern void SelectMenuDisplayMode(void) +{ + MinimizeAllImages(); + TimeStampedMessage("after MinimizeAllImages"); + MinimizeAllDDGraphics(); + TimeStampedMessage("after MinimizeAllDDGraphics"); + + ReleaseDirect3DNotDDOrImages(); + TimeStampedMessage("after ReleaseDirect3DNotDDOrImages"); + + finiObjectsExceptDD(); + TimeStampedMessage("after finiObjectsExceptDD"); + + finiObjects(); + SelectDirectDrawObject(NULL); + + DXMemoryRequestMode = RequestSystemMemoryAlways; + DXMemoryMode = SystemMemoryPreferred; + + RasterisationRequestMode = RequestSoftwareRasterisation; + VideoMode = VideoMode_DX_640x480x15; + VideoModeTypeScreen = VideoModeType_15; + WindowMode = WindowRequestMode; + ScreenDescriptorBlock.SDB_Width = 640; + ScreenDescriptorBlock.SDB_Height = 480; + ScreenDescriptorBlock.SDB_ScreenDepth = VideoModeType_15; + + #if !(PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO) + ChangeDirectDrawObject(); + #endif + TimeStampedMessage("after ChangeDirectDrawObject"); + + GenerateDirectDrawSurface(); + TimeStampedMessage("after GenerateDirectDrawSurface"); + + { + extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + Global_VDB_Ptr = 0; + } +} + + + + + + + + + + + + + + + + + + + + + + +#if 0 + + + +struct STARDESC +{ + int X; + int Y; + int Chasing; + int Fleeing; +}; +#define NUMBER_OF_STARS 128 + +struct STARDESC Star[NUMBER_OF_STARS]; + +static void DrawStar(int x, int y) +{ + extern unsigned char *ScreenBuffer; + extern long BackBufferPitch; + + int xi,xf,xfm,yi,yf,yfm; + + xi=x/65536; + yi=y/65536; + xf = x - xi*65536; + yf = y - yi*65536; + xfm = ONE_FIXED - xf; + yfm = ONE_FIXED - yf; + + *(unsigned short*)(ScreenBuffer + ((xi+0)*2 + (yi+0)*BackBufferPitch)) = (unsigned short)WhiteOfBrightness(MUL_FIXED(xfm,yfm)); + *(unsigned short*)(ScreenBuffer + ((xi+0)*2 + (yi+1)*BackBufferPitch)) = (unsigned short)WhiteOfBrightness(MUL_FIXED(xfm,yf)); + *(unsigned short*)(ScreenBuffer + ((xi+1)*2 + (yi+0)*BackBufferPitch)) = (unsigned short)WhiteOfBrightness(MUL_FIXED(xf,yfm)); + *(unsigned short*)(ScreenBuffer + ((xi+1)*2 + (yi+1)*BackBufferPitch)) = (unsigned short)WhiteOfBrightness(MUL_FIXED(xf,yf)); + +} +#endif + +static void InitMainMenusBackdrop(void) +{ + #if 0 + int i; + for(i=0; i638*ONE_FIXED) + ||(y<61*ONE_FIXED || y>418*ONE_FIXED)) + { + Star[i].X = (FastRandom()&65535)*640; + Star[i].Y = ((FastRandom()&65535)*360)+60; + Star[i].Chasing = (FastRandom()&127); + Star[i].Fleeing = (FastRandom()&127); + } + else + { + int s = Star[i].Chasing; + int f = Star[i].Fleeing; + DrawStar(x,y); +// Star[i].X -= MUL_FIXED(Star[i].X - 320*ONE_FIXED,RealFrameTime*4); + // Star[i].Y -= MUL_FIXED(Star[i].Y - 240*ONE_FIXED,RealFrameTime*4); + + if ((Star[i].X/131072 == Star[f].X/131072) + &&(Star[i].Y/131072 == Star[f].Y/131072)) + { + Star[i].X = (FastRandom()&65535)*640; + Star[i].Y = ((FastRandom()&65535)*360)+60; + } + else + { + Star[i].X -= MUL_FIXED(Star[i].X - Star[s].X,RealFrameTime*4); + Star[i].Y -= MUL_FIXED(Star[i].Y - Star[s].Y,RealFrameTime*4); + Star[i].X += MUL_FIXED(Star[i].X - Star[f].X,RealFrameTime); + Star[i].Y += MUL_FIXED(Star[i].Y - Star[f].Y,RealFrameTime); + } + + + } + } + + } + #endif + //UnlockSurface(); + #endif +} + +int WhiteOfBrightness(int brightness) +{ + extern DDPIXELFORMAT DisplayPixelFormat; + int a; + + a = MUL_FIXED(DisplayPixelFormat.dwRBitMask,brightness) & DisplayPixelFormat.dwRBitMask; + a |= MUL_FIXED(DisplayPixelFormat.dwGBitMask,brightness) & DisplayPixelFormat.dwGBitMask; + a |= MUL_FIXED(DisplayPixelFormat.dwBBitMask,brightness) & DisplayPixelFormat.dwBBitMask; + + return a; +} + +void RenderPixel(int x,int y,int r,int g,int b) +{ + extern DDPIXELFORMAT DisplayPixelFormat; + extern unsigned char *ScreenBuffer; + extern long BackBufferPitch; + + unsigned short colour; + + colour = MUL_FIXED(DisplayPixelFormat.dwRBitMask,r<<8) & DisplayPixelFormat.dwRBitMask; + colour |= MUL_FIXED(DisplayPixelFormat.dwGBitMask,g<<8) & DisplayPixelFormat.dwGBitMask; + colour |= MUL_FIXED(DisplayPixelFormat.dwBBitMask,b<<8) & DisplayPixelFormat.dwBBitMask; + + + *(unsigned short*) (ScreenBuffer + (x)*2 + (y)*BackBufferPitch) = colour; + +} +#if 0 +void BezierCurve(void) +{ + int i; + extern unsigned char *ScreenBuffer; + extern long BackBufferPitch; + static b=0; + for (i=0; i<=255; i++) + { + int u = ((i*65536)/255); + int m = MUL_FIXED(u,u); + int l = MUL_FIXED(2*u,ONE_FIXED-u); + + int a; + + a = MUL_FIXED(255,m)+MUL_FIXED(b,l); + if (a<0) a=0; + if (a>255) a=255; + + m = MUL_FIXED(a*256,a*256); + l = MUL_FIXED(2*a*256,ONE_FIXED-a*256); + + a; + + a = MUL_FIXED(255,m)+MUL_FIXED(b,l); + if (a<0) a=0; + if (a>255) a=255; + + *(unsigned short*)(ScreenBuffer + ((i+0)*2 + (400-a)*BackBufferPitch)) = 0xffff; + //*(unsigned short*)(ScreenBuffer + ((i+0)*2 + (400-i)*BackBufferPitch)) = 0xff; + + *(unsigned short*)(ScreenBuffer + ((i+0)*2 + (400-i)*BackBufferPitch)) = 0xffff; + *(unsigned short*)(ScreenBuffer + ((i+50)*2 + (400-i)*BackBufferPitch)) = 0xffff; + *(unsigned short*)(ScreenBuffer + ((i+100)*2 + (400-i)*BackBufferPitch)) = 0xffff; + + + } +// PlayWithGammaSettings(b); + b++; + if (b>=255) b=0; +} +#endif + + + +static void UpdateMultiplayerConfigurationMenu() +{ + /*update the displayed levels according to the cuurent game type*/ + + AVPMENU_ELEMENT *elementPtr = AvPMenus.MenuElements; + + //search for the level name element + do + { + GLOBALASSERT(elementPtr->ElementID!=AVPMENU_ELEMENT_ENDOFMENU); + elementPtr++; + + }while(elementPtr->TextDescription!=TEXTSTRING_MULTIPLAYER_ENVIRONMENT); + + + if(netGameData.skirmishMode) + { + //force 'cooperative' game if using skirmish mode + netGameData.gameType=NGT_Coop; + } + + if(netGameData.gameType!=NGT_Coop) + { + elementPtr->MaxSliderValue = NumMultiplayerLevels-1; + elementPtr->TextSliderStringPointer = MultiplayerLevelNames; + + //make sure the level number is within bounds + netGameData.levelNumber%=NumMultiplayerLevels; + } + else + { + elementPtr->MaxSliderValue = NumCoopLevels-1; + elementPtr->TextSliderStringPointer = CoopLevelNames; + + //make sure the level number is within bounds + netGameData.levelNumber%=NumCoopLevels; + } + + + //see if selected element is the gamestyle element + elementPtr = &AvPMenus.MenuElements[AvPMenus.CurrentlySelectedElement]; + + if(elementPtr->TextDescription==TEXTSTRING_MULTIPLAYER_GAMESTYLE) + { + //change the helpstring according to the game style + switch(netGameData.gameType) + { + case NGT_Individual : + elementPtr->HelpString=TEXTSTRING_MPHELP_GAMESTYLE_DEATHMATCH; + break; + + case NGT_CoopDeathmatch : + elementPtr->HelpString=TEXTSTRING_MPHELP_GAMESTYLE_DEATHMATCHTEAM; + break; + + case NGT_LastManStanding : + elementPtr->HelpString=TEXTSTRING_MPHELP_GAMESTYLE_LASTMANSTANDING; + break; + + case NGT_PredatorTag : + elementPtr->HelpString=TEXTSTRING_MPHELP_GAMESTYLE_PREDATORTAG; + break; + + case NGT_Coop : + elementPtr->HelpString=TEXTSTRING_MPHELP_GAMESTYLE_COOPERATIVE; + break; + + case NGT_AlienTag : + elementPtr->HelpString=TEXTSTRING_MPHELP_GAMESTYLE_ALIENTAG; + break; + } + } + + //also need to fill in customLevelName + strcpy(netGameData.customLevelName,GetCustomMultiplayerLevelName(netGameData.levelNumber,netGameData.gameType)); + +} + +static void TestValidityOfCheatMenu(void) +{ + CheatMode_GetNextAllowedMode(AvPMenus.MenuElements[0].SliderValuePtr,TRUE); + CheatMode_GetNextAllowedSpecies(AvPMenus.MenuElements[1].SliderValuePtr,TRUE); + CheatMode_GetNextAllowedEnvironment(AvPMenus.MenuElements[2].SliderValuePtr,TRUE); +} + +static unsigned char *BriefingTextString[5]; +static unsigned char BlankLine[]=""; + +void SetBriefingTextForEpisode(int episode, I_PLAYER_TYPE playerID) +{ + int i,s; + + switch(playerID) + { + default: + case I_Marine: + { + s = TEXTSTRING_MARINELEVELSBRIEFING_1; + break; + } + case I_Predator: + { + s = TEXTSTRING_PREDATORLEVELSBRIEFING_1; + break; + } + case I_Alien: + { + s = TEXTSTRING_ALIENLEVELSBRIEFING_1; + break; + } + } + + for(i=0; i<5; i++) + { + BriefingTextString[i] = GetTextString(s+i+ episode*5); + } +} + +static char MultiplayerBriefing[3][100]; + +static void AddMultiplayerBriefingString(const char* text) +{ + int shortest = 0; + int shortest_length =1000; + int i; + + for(i=0;i<3;i++) + { + int length = strlen(MultiplayerBriefing[i]); + if(length=100) return; + + if(shortest_length>0) + { + strcat(MultiplayerBriefing[shortest]," , "); + } + strcat(MultiplayerBriefing[shortest],text); +} + +static BOOL IsFlamerInLevel(int level) +{ + if(level == AVP_ENVIRONMENT_SUBWAY_MP || + level == AVP_ENVIRONMENT_SUBWAY_COOP) + { + return FALSE; + } + return TRUE; +} + +static BOOL IsMinigunInLevel(int level) +{ + if(level == AVP_ENVIRONMENT_SEWER) + { + return FALSE; + } + return TRUE; +} + +static BOOL IsSadarInLevel(int level) +{ + if(level == AVP_ENVIRONMENT_MASSACRE || + level == AVP_ENVIRONMENT_MEATFACTORY_MP || + level == AVP_ENVIRONMENT_MEATFACTORY_COOP || + level == AVP_ENVIRONMENT_HADLEYSHOPE_MP || + level == AVP_ENVIRONMENT_HADLEYSHOPE_COOP || + level == AVP_ENVIRONMENT_HIVE || + level == AVP_ENVIRONMENT_HIVE_COOP || + level == AVP_ENVIRONMENT_KENS_COOP || + level == AVP_ENVIRONMENT_LEADWORKS_MP || + level == AVP_ENVIRONMENT_LEADWORKS_COOP) + { + return FALSE; + } + return TRUE; +} + +static BOOL IsSkeeterInLevel(int level) +{ + if(level == AVP_ENVIRONMENT_LEADWORKS_MP || + level == AVP_ENVIRONMENT_LEADWORKS_COOP) + { + return FALSE; + } + return TRUE; +} + +static BOOL IsSmartgunInLevel(int level) +{ + if(level == AVP_ENVIRONMENT_NOSTROMO_MP) return FALSE; + return TRUE; +} + + +static void SetBriefingTextForMultiplayer() +{ + int level = NumberForCurrentLevel(); + + int num_not_available = 0; + + if(netGameData.customLevelName[0] != 0) + { + //custom level + BriefingTextString[0] = netGameData.customLevelName; + return; + } + + MultiplayerBriefing[0][0] = 0; + MultiplayerBriefing[1][0] = 0; + MultiplayerBriefing[2][0] = 0; + + if(!netGameData.allowSmartgun || !IsSmartgunInLevel(level)) + { + AddMultiplayerBriefingString(GetTextString(TEXTSTRING_INGAME_SMARTGUN)); + num_not_available++; + } + if(!netGameData.allowFlamer || !IsFlamerInLevel(level)) + { + AddMultiplayerBriefingString(GetTextString(TEXTSTRING_INGAME_FLAMETHROWER)); + num_not_available++; + } + if(!netGameData.allowSadar || !IsSadarInLevel(level)) + { + AddMultiplayerBriefingString(GetTextString(TEXTSTRING_INGAME_SADAR)); + num_not_available++; + } + if(!netGameData.allowGrenadeLauncher) + { + AddMultiplayerBriefingString(GetTextString(TEXTSTRING_INGAME_GRENADELAUNCHER)); + num_not_available++; + } + if(!netGameData.allowMinigun || !IsMinigunInLevel(level)) + { + AddMultiplayerBriefingString(GetTextString(TEXTSTRING_INGAME_MINIGUN)); + num_not_available++; + } + if(!netGameData.allowSmartDisc || !IsSkeeterInLevel(level)) + { + AddMultiplayerBriefingString(GetTextString(TEXTSTRING_INGAME_SKEETER)); + num_not_available++; + } + if(!netGameData.allowPistols) + { + AddMultiplayerBriefingString(GetTextString(TEXTSTRING_INGAME_MARINE_PISTOL)); + num_not_available++; + } + if(!netGameData.allowDisc) + { + AddMultiplayerBriefingString(GetTextString(TEXTSTRING_INGAME_DISC)); + num_not_available++; + } + if(!netGameData.allowPistol) + { + AddMultiplayerBriefingString(GetTextString(TEXTSTRING_BRIEFING_PREDATOR_PISTOL)); + num_not_available++; + } + if(!netGameData.allowPlasmaCaster) + { + AddMultiplayerBriefingString(GetTextString(TEXTSTRING_INGAME_SHOULDERCANNON)); + num_not_available++; + } + if(!netGameData.allowSpeargun) + { + AddMultiplayerBriefingString(GetTextString(TEXTSTRING_INGAME_RIFLE)); + num_not_available++; + } + if(!netGameData.allowMedicomp) + { + AddMultiplayerBriefingString(GetTextString(TEXTSTRING_INGAME_MEDICOMP)); + num_not_available++; + } + + if(netGameData.gameType!=NGT_Coop) + { + BriefingTextString[0] = GetTextString(netGameData.levelNumber + TEXTSTRING_MULTIPLAYERLEVELS_1); + + } + else + { + BriefingTextString[0] = GetTextString(netGameData.levelNumber + TEXTSTRING_COOPLEVEL_1); + } + + if(num_not_available) + { + BriefingTextString[1] = GetTextString(TEXTSTRING_BRIEFING_UNAVAILABLE_WEAPONS); + BriefingTextString[2] = MultiplayerBriefing[0]; + BriefingTextString[3] = MultiplayerBriefing[1]; + BriefingTextString[4] = MultiplayerBriefing[2]; + } +} + +void SetBriefingTextToBlank(void) +{ + int i; + + for(i=0; i<5; i++) + { + BriefingTextString[i] = BlankLine; + } +} + +void RenderBriefingText(int centreY, int brightness) +{ + int lengthOfLongestLine=-1; + int x,y,i; + + for(i=0; i<5; i++) + { + int length = 0; + { + char *ptr = BriefingTextString[i]; + + while(*ptr) + { + length+=AAFontWidths[*ptr++]; + } + } + + if (lengthOfLongestLine < length) + { + lengthOfLongestLine = length; + } + } + + x = (ScreenDescriptorBlock.SDB_Width-lengthOfLongestLine)/2; + y = centreY - 3*HUD_FONT_HEIGHT; + for(i=0; i<5; i++) + { + if (AvPMenus.MenusState != MENUSSTATE_MAINMENUS) + { + Hardware_RenderSmallMenuText(BriefingTextString[i], x, y, brightness, AVPMENUFORMAT_LEFTJUSTIFIED/*,MENU_CENTREY-60-100,MENU_CENTREY-60+180*/); + } + else + { + RenderSmallMenuText(BriefingTextString[i], x, y, brightness, AVPMENUFORMAT_LEFTJUSTIFIED); + } + if (i) y+=HUD_FONT_HEIGHT; + else y+=HUD_FONT_HEIGHT*2; + } +} + + +void CheckForKeysWithMultipleAssignments(void) +{ + unsigned char *configPtr[2]; + int column,row; + + configPtr[0] = (unsigned char*)&PlayerInputPrimaryConfig; + configPtr[1] = (unsigned char*)&PlayerInputSecondaryConfig; + + for (column=0; column<=1; column++) + { + for (row=0; row<32; row++) + { + int innerColumn,innerRow; + + MultipleAssignments[column][row] = 0; + + for (innerColumn=0; innerColumn<=1; innerColumn++) + for (innerRow=0; innerRow<32; innerRow++) + { + if (innerRow==row) continue; + // && innerColumn==column) continue; + if ( (configPtr[column])[row]==(configPtr[innerColumn])[innerRow] ) + { + MultipleAssignments[column][row] = 1; + } + } + } + } +} + +void HandleCheatModeFeatures(void) +{ + switch(CheatMode_Active) + { + case CHEATMODE_WARPSPEED: + { + TimeScale = 2*ONE_FIXED; + AvP.Difficulty = 0; + break; + } + case CHEATMODE_LANDOFTHEGIANTS: + { + TimeScale =ONE_FIXED/2; + break; + } + case CHEATMODE_IMPOSSIBLEMISSION: + { + AvP.Difficulty = 3; + break; + } + case CHEATMODE_UNDERWATER: + { + TimeScale = (ONE_FIXED*7)/10; + break; + } + default: + break; + } +} + +void ShowMenuFrameRate(void) +{ +#if 0 + extern NormalFrameTime; + char buffer[8]; + + sprintf(buffer,"%d fps",65536/NormalFrameTime); + RenderSmallMenuText(buffer,20,20,ONE_FIXED, AVPMENUFORMAT_LEFTJUSTIFIED); +#endif +} + +#define MAX_ITEMS_IN_KEYBOARDENTRYQUEUE 8 +static char KeyboardEntryQueue[MAX_ITEMS_IN_KEYBOARDENTRYQUEUE]; +static int NumberOfItemsInKeyboardEntryQueue; +static int KeyboardEntryQueue_ProcessingIndex; + +extern void KeyboardEntryQueue_Add(char c) +{ + if (c<32) return; + + if (NumberOfItemsInKeyboardEntryQueueName,i+1); +} + + + +/*------------------------------------** +** Loading and saving main level info ** +**------------------------------------*/ + + +extern int AlienEpisodeToPlay; +extern int MarineEpisodeToPlay; +extern int PredatorEpisodeToPlay; + +void SaveLevelHeader() +{ + LEVEL_SAVE_BLOCK* block = (LEVEL_SAVE_BLOCK*) GetPointerForSaveBlock(sizeof(LEVEL_SAVE_BLOCK)); + + //fill in the header + block->header.type = SaveBlock_MainHeader; + block->header.size = sizeof(*block); + + //fill in the main block + strncpy(block->AvP_Save_String,"AVPSAVE0",8); + + block->Species = AvP.PlayerType; + + switch(block->Species) + { + case I_Marine : + block->Episode = MarineEpisodeToPlay; + break; + + case I_Alien : + block->Episode = AlienEpisodeToPlay; + break; + + case I_Predator : + block->Episode = PredatorEpisodeToPlay; + break; + } + + block->ElapsedTime_Hours =(unsigned char) AvP.ElapsedHours; + block->ElapsedTime_Minutes =(unsigned char) AvP.ElapsedMinutes; + block->ElapsedTime_Seconds = AvP.ElapsedSeconds; + + block->Difficulty = AvP.Difficulty; + block->NumberOfSavesLeft = (unsigned char) NumberOfSavesLeft; + +} + +void LoadLevelHeader(SAVE_BLOCK_HEADER* header) +{ + LEVEL_SAVE_BLOCK* block =(LEVEL_SAVE_BLOCK*) header; + + if(block->header.size!=sizeof(*block)) return; + + AvP.ElapsedHours = block->ElapsedTime_Hours; + AvP.ElapsedMinutes = block->ElapsedTime_Minutes; + AvP.ElapsedSeconds = block->ElapsedTime_Seconds; + +} + + +static void GetHeaderInfoForSaveSlot(SAVE_SLOT_HEADER* save_slot,const char* filename) +{ + LEVEL_SAVE_BLOCK block; + unsigned int file_size; + unsigned int bytes_read; + HANDLE file; + + save_slot->SlotUsed = 0; + + file = CreateFile(filename,GENERIC_READ, 0, 0, OPEN_EXISTING,FILE_FLAG_RANDOM_ACCESS, 0); + + if(file==INVALID_HANDLE_VALUE) + { + //failed to load (probably doesn't exist) + return; + } + + + file_size = GetFileSize(file,0); + + if(file_size < sizeof(LEVEL_SAVE_BLOCK)) + { + //obviously not much of a save file then... + CloseHandle(file); + return; + + } + + //get the time stamp for the file + { + FILETIME time,localTime; + GetFileTime(file,0,0,&time); + FileTimeToLocalFileTime(&time,&localTime); + FileTimeToSystemTime(&localTime,&save_slot->TimeStamp); + + } + + + //load the level header + ReadFile(file,&block,sizeof(block),(LPDWORD)&bytes_read,0); + CloseHandle(file); + + //a few checks + if(block.header.type != SaveBlock_MainHeader || + block.header.size != sizeof(block) || + strncmp(block.AvP_Save_String,"AVPSAVE0",8)) + { + //no good. + return; + } + + //appears to be a reasonable file + save_slot->SlotUsed = TRUE; + + //copy stuff from the block + + save_slot->Species = block.Species; + save_slot->Episode = block.Episode; + save_slot->ElapsedTime_Hours = block.ElapsedTime_Hours; + save_slot->ElapsedTime_Minutes = block.ElapsedTime_Minutes; + save_slot->ElapsedTime_Seconds = (block.ElapsedTime_Seconds >> 16); + save_slot->Difficulty = block.Difficulty; + save_slot->SavesLeft = block.NumberOfSavesLeft; +} + + +static void CheckForLoadGame() +{ + if(LoadGameRequest >=0 && LoadGameRequestSlotUsed) + { + AvP.PlayerType = save_slot->Species; + AvP.Difficulty = save_slot->Difficulty; + + switch(AvP.PlayerType) + { + case I_Marine : + MarineEpisodeToPlay = save_slot->Episode; + SetLevelToLoadForMarine(MarineEpisodeToPlay); + break; + + case I_Alien : + AlienEpisodeToPlay = save_slot->Episode; + SetLevelToLoadForAlien(AlienEpisodeToPlay); + + break; + + case I_Predator : + PredatorEpisodeToPlay = save_slot->Episode; + SetLevelToLoadForPredator(PredatorEpisodeToPlay); + break; + + } + SetBriefingTextForEpisode(save_slot->Episode, AvP.PlayerType); + AvPMenus.MenusState = MENUSSTATE_STARTGAME; + } + else + { + //cancel request + LoadGameRequest = SAVELOAD_REQUEST_NONE; + } + } +} + + +static void PasteFromClipboard(char* Text,int MaxTextLength) +{ + HANDLE hGlobal; + if(!Text) + { + return; + } + + if(IsClipboardFormatAvailable(CF_TEXT)) + { + OpenClipboard(0); + hGlobal = GetClipboardData(CF_TEXT); + if(hGlobal) + { + char* pGlobal = GlobalLock(hGlobal); + if(pGlobal) + { + strncpy(Text,pGlobal,MaxTextLength-1); + Text[MaxTextLength-1] = 0; + GlobalUnlock(hGlobal); + } + } + CloseClipboard(); + } +} + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/3dc/avp/win95/Frontend/AvP_Menus.h b/3dc/avp/win95/Frontend/AvP_Menus.h new file mode 100644 index 0000000..2b5ae4d --- /dev/null +++ b/3dc/avp/win95/Frontend/AvP_Menus.h @@ -0,0 +1,345 @@ +#ifndef _included_AvP_Menus_h_ +#define _included_AvP_Menus_h_ + +#define MARINE_DEMO 0 +#define PREDATOR_DEMO 0 +#define ALIEN_DEMO 0 + // Edmond modified for Mplayer Demo + #ifdef MPLAYER_DEMO + #define DEATHMATCH_DEMO 1 + #else + #define DEATHMATCH_DEMO 0 // more multiplayer-only demo really + #endif + +#ifdef AVP_DEBUG_VERSION + #define CONSOLE_DEBUGGING_COMMANDS_ACTIVATED 1 + + #define LOAD_SCREAMS_FROM_FASTFILES 0 + #define LOAD_USING_FASTFILES 0 + +#else //AVP_DEBUG_VERSION + + #ifdef AVP_DEBUG_FOR_FOX + #define CONSOLE_DEBUGGING_COMMANDS_ACTIVATED 1 + #else + #define CONSOLE_DEBUGGING_COMMANDS_ACTIVATED 0 + #endif + + #define LOAD_SCREAMS_FROM_FASTFILES 1 + #define LOAD_USING_FASTFILES 1 +#endif //AVP_DEBUG_VERSION + +#define PLAY_INTRO 1 +#define ALLOW_SKIP_INTRO 1 + +#define SAVE_GAME_ON 1 + +#include "AvP_MenuGfx.hpp" +#include "language.h" + +enum MENUSSTATE_ID +{ + MENUSSTATE_MAINMENUS, + MENUSSTATE_INGAMEMENUS, + MENUSSTATE_OUTSIDEMENUS, + MENUSSTATE_STARTGAME, +}; + +enum AVPMENU_ID +{ + AVPMENU_MAIN, + AVPMENU_MAIN_WITHCHEATS, + AVPMENU_DEBUG_MAIN, + AVPMENU_DEBUG_MAIN_WITHCHEATS, + + AVPMENU_EXITGAME, + + AVPMENU_USERPROFILESELECT, + AVPMENU_USERPROFILEENTERNAME, + AVPMENU_USERPROFILEDELETE, + + AVPMENU_SINGLEPLAYER, + AVPMENU_MARINELEVELS, + AVPMENU_ALIENLEVELS, + AVPMENU_PREDATORLEVELS, + + AVPMENU_MULTIPLAYER, + AVPMENU_MULTIPLAYER_LOBBIEDSERVER, + AVPMENU_MULTIPLAYER_LOBBIEDCLIENT, + AVPMENU_MULTIPLAYER_SKIRMISH, + AVPMENU_MULTIPLAYERSTARTGAME, + AVPMENU_MULTIPLAYERJOINGAME, + AVPMENU_MULTIPLAYERSELECTSESSION, + AVPMENU_MULTIPLAYERJOINGAME2, + AVPMENU_MULTIPLAYEROPENADDRESS, + AVPMENU_MULTIPLAYER_LOADIPADDRESS, + AVPMENU_MULTIPLAYER_CONNECTION, + AVPMENU_MULTIPLAYER_CONFIG, + AVPMENU_MULTIPLAYER_CONFIG_JOIN, + AVPMENU_SKIRMISH_CONFIG, + AVPMENU_MULTIPLAYER_SPECIES_HOST, + AVPMENU_MULTIPLAYER_SPECIES_JOIN, + + AVPMENU_MULTIPLAYER_SAVECONFIG, + AVPMENU_MULTIPLAYER_LOADCONFIG, + AVPMENU_MULTIPLAYER_DELETECONFIG, + + AVPMENU_MULTIPLAYER_JOINING, + + AVPMENU_CONTROLS, + AVPMENU_JOYSTICKCONTROLS, + + AVPMENU_INGAMEAVOPTIONS, + AVPMENU_MAINMENUAVOPTIONS, + AVPMENU_VIDEOMODE, + + + AVPMENU_INGAME, + AVPMENU_INNETGAME, + + AVPMENU_MARINEKEYCONFIG, + AVPMENU_PREDATORKEYCONFIG, + AVPMENU_ALIENKEYCONFIG, + AVPMENU_OPTIONS, + + AVPMENU_LEVELBRIEFING_BASIC, + AVPMENU_LEVELBRIEFING_BONUS, + + AVPMENU_CHEATOPTIONS, + AVPMENU_DETAILLEVELS, + + AVPMENU_LOADGAME, + AVPMENU_SAVEGAME, + +}; + +enum AVPMENU_FONT_ID +{ + AVPMENU_FONT_SMALL, + AVPMENU_FONT_BIG, +}; +/* menu elements */ +enum AVPMENU_ELEMENT_ID +{ + AVPMENU_ELEMENT_GOTOMENU, + AVPMENU_ELEMENT_GOTOMENU_GFX, + + AVPMENU_ELEMENT_TOGGLE, + AVPMENU_ELEMENT_SLIDER, + + AVPMENU_ELEMENT_USERPROFILE, + AVPMENU_ELEMENT_ALIENEPISODE, + AVPMENU_ELEMENT_MARINEEPISODE, + AVPMENU_ELEMENT_PREDATOREPISODE, + AVPMENU_ELEMENT_STARTMPGAME, + AVPMENU_ELEMENT_JOINMPGAME, + AVPMENU_ELEMENT_JOINLOBBIED, + + AVPMENU_ELEMENT_QUITGAME, + + AVPMENU_ELEMENT_TEXTFIELD, + AVPMENU_ELEMENT_DUMMYTEXTFIELD, + AVPMENU_ELEMENT_TEXTFIELD_SMALLWRAPPED, + AVPMENU_ELEMENT_TEXTSLIDER, + AVPMENU_ELEMENT_DUMMYTEXTSLIDER, + AVPMENU_ELEMENT_SPECIES_TEXTSLIDER, + + AVPMENU_ELEMENT_TEXTSLIDER_POINTER, // text slider with a char** rather than a string index + AVPMENU_ELEMENT_DUMMYTEXTSLIDER_POINTER, // text slider with a char** rather than a string index + + AVPMENU_ELEMENT_CHEATMODE_TEXTSLIDER, + AVPMENU_ELEMENT_CHEATMODE_SPECIES_TEXTSLIDER, + AVPMENU_ELEMENT_CHEATMODE_ENVIRONMENT_TEXTSLIDER, + + AVPMENU_ELEMENT_NUMBERFIELD, + AVPMENU_ELEMENT_DUMMYNUMBERFIELD, + + AVPMENU_ELEMENT_LISTCHOICE, + + AVPMENU_ELEMENT_CONNECTIONCHOICE, + + AVPMENU_ELEMENT_VIDEOMODE, + AVPMENU_ELEMENT_VIDEOMODEOK, + + AVPMENU_ELEMENT_KEYCONFIG, + AVPMENU_ELEMENT_KEYCONFIGOK, + AVPMENU_ELEMENT_RESETKEYCONFIG, + + AVPMENU_ELEMENT_ENDOFMENU, + + AVPMENU_ELEMENT_RESUMEGAME, + AVPMENU_ELEMENT_RESTARTGAME, + + AVPMENU_ELEMENT_STARTMARINEDEMO, + AVPMENU_ELEMENT_STARTPREDATORDEMO, + AVPMENU_ELEMENT_STARTALIENDEMO, + AVPMENU_ELEMENT_STARTLEVELWITHCHEAT, + + AVPMENU_ELEMENT_BUTTONSETTING, + AVPMENU_ELEMENT_LOADMPCONFIG, + AVPMENU_ELEMENT_SAVEMPCONFIG, + AVPMENU_ELEMENT_DELETEMPCONFIG, + AVPMENU_ELEMENT_RESETMPCONFIG, + + AVPMENU_ELEMENT_DIFFICULTYLEVEL, + + AVPMENU_ELEMENT_LOADIPADDRESS, + + AVPMENU_ELEMENT_USERPROFILE_DELETE, + + + AVPMENU_ELEMENT_SAVESETTINGS, + + AVPMENU_ELEMENT_SAVEGAME, + AVPMENU_ELEMENT_LOADGAME, +}; + + +enum AVPMENU_ELEMENT_INTERACTION_ID +{ + AVPMENU_ELEMENT_INTERACTION_SELECT, + AVPMENU_ELEMENT_INTERACTION_DECREASE, + AVPMENU_ELEMENT_INTERACTION_INCREASE, +}; + +typedef struct +{ + enum AVPMENU_ELEMENT_ID ElementID; + + union + { + enum TEXTSTRING_ID TextDescription; + enum AVPMENUGFX_ID GfxID; + }; + + union + { + enum AVPMENU_ID MenuToGoTo; + int MaxSliderValue; + int MaxTextLength; + int MaxValue; //for number fields + }; + + union + { + int *ToggleValuePtr; + int *SliderValuePtr; + char *TextPtr; + int *NumberPtr; + int Value; + }; + + union + { + enum TEXTSTRING_ID FirstTextSliderString; + enum TEXTSTRING_ID NumberFieldUnitsString; + char** TextSliderStringPointer; + }; + + enum TEXTSTRING_ID HelpString; + + union + { + enum TEXTSTRING_ID NumberFieldZeroString; //special string for 0 + }; + int Brightness; + +} AVPMENU_ELEMENT; + +typedef struct +{ + enum AVPMENU_FONT_ID FontToUse; + enum TEXTSTRING_ID MenuTitle; + + AVPMENU_ELEMENT *MenuElements; + enum AVPMENU_ID ParentMenu; + int DefaultElement; + + +} AVPMENU; + + +typedef struct +{ + enum MENUSSTATE_ID MenusState; + + + enum AVPMENU_ID CurrentMenu; + AVPMENU_ELEMENT *MenuElements; + int NumberOfElementsInMenu; + int CurrentlySelectedElement; + int MenuHeight; + + enum AVPMENU_FONT_ID FontToUse; + + int PositionInTextField; + + int WidthLeftForText; //thing for checking whether user input will fit on screen + + unsigned int UserEnteringText :1; + unsigned int UserEnteringNumber :1; + unsigned int UserChangingKeyConfig :1; + unsigned int ChangingPrimaryConfig :1; + +} AVP_MENUS; + + +#define BRIGHTNESS_OF_HIGHLIGHTED_ELEMENT (ONE_FIXED) +#define BRIGHTNESS_OF_DARKENED_ELEMENT (ONE_FIXED/4) +#define BRIGHTNESS_CHANGE_SPEED (RealFrameTime*2) + +#define MENU_TOPY (150) +#define MENU_CENTREY (280) +#define MENU_HEIGHT (255) +#define MENU_CENTREX (ScreenDescriptorBlock.SDB_Width/2) + +#define MENU_ELEMENT_SPACING (9) +#define MENU_FONT_HEIGHT (21) +#define MENU_LEFTXEDGE (30) +#define MENU_RIGHTXEDGE (ScreenDescriptorBlock.SDB_Width-30) +#define MENU_BOTTOMYEDGE (390) +#define MENU_TOPYEDGE (130) +#define MENU_WIDTH (MENU_RIGHTXEDGE-MENU_LEFTXEDGE) + + +/* +Defines for numbers of levels transferred to AvP_EnvInfo.h +-Richard. +*/ + + + +/* KJL 18:05:51 05/07/98 - multiplayer stuff */ +typedef struct +{ + char Name[40]; + char levelIndex;//local level index + GUID Guid; + BOOL AllowedToJoin; +} SESSION_DESC; +#define MAX_NO_OF_SESSIONS 10 +extern SESSION_DESC SessionData[]; +extern int NumberOfSessionsFound; + +extern char IP_Address_Name[]; + + + +typedef struct +{ + unsigned char SlotUsed; + unsigned char SavesLeft; + unsigned char Species; + unsigned char Episode; + unsigned char ElapsedTime_Hours; + unsigned char ElapsedTime_Minutes; + unsigned char ElapsedTime_Seconds; + unsigned char Difficulty; + + SYSTEMTIME TimeStamp; + +} SAVE_SLOT_HEADER; + +#define NUMBER_OF_SAVE_SLOTS 8 + +#endif \ No newline at end of file diff --git a/3dc/avp/win95/Frontend/AvP_UserProfile.cpp b/3dc/avp/win95/Frontend/AvP_UserProfile.cpp new file mode 100644 index 0000000..3ff88fb --- /dev/null +++ b/3dc/avp/win95/Frontend/AvP_UserProfile.cpp @@ -0,0 +1,429 @@ +/* KJL 15:17:31 10/12/98 - user profile stuff */ +#include "list_tem.hpp" +extern "C" +{ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" + +#include "AvP_UserProfile.h" +#include "language.h" +#include "GammaControl.h" +#include "psnd.h" +#include "cd_player.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + + // Edmond + #include "pldnet.h" + #include "dp_func.h" + #include + +static int LoadUserProfiles(void); + +static void EmptyUserProfilesList(void); +static int MakeNewUserProfile(void); +static void InsertProfileIntoList(AVP_USER_PROFILE *profilePtr); +static int ProfileIsMoreRecent(AVP_USER_PROFILE *profilePtr, AVP_USER_PROFILE *profileToTestAgainstPtr); +static void SetDefaultProfileOptions(AVP_USER_PROFILE *profilePtr); + +extern int SmackerSoundVolume; +extern int EffectsSoundVolume; +extern int MoviesAreActive; +extern int IntroOutroMoviesAreActive; +extern char MP_PlayerName[]; +extern int AutoWeaponChangeOn; + + +List UserProfilesList; +static AVP_USER_PROFILE DefaultUserProfile = +{ + "", +}; +static AVP_USER_PROFILE *CurrentUserProfilePtr; + +extern void ExamineSavedUserProfiles(void) +{ + // delete any existing profiles + EmptyUserProfilesList(); + +// UserProfilesList.add_entry(profilePtr); +// SaveUserProfile(profilePtr); + if (LoadUserProfiles()) + { + + } + else /* No user profile found. We'll have to make one */ + { + // MakeNewUserProfile(); + } + + AVP_USER_PROFILE *profilePtr = new AVP_USER_PROFILE; + *profilePtr = DefaultUserProfile; + + GetLocalTime(&profilePtr->TimeLastUpdated); + SystemTimeToFileTime(&profilePtr->TimeLastUpdated,&profilePtr->FileTime); + + strncpy(profilePtr->Name,GetTextString(TEXTSTRING_USERPROFILE_NEW),MAX_SIZE_OF_USERS_NAME); + profilePtr->Name[MAX_SIZE_OF_USERS_NAME]=0; + SetDefaultProfileOptions(profilePtr); + + InsertProfileIntoList(profilePtr); + +} + +extern int NumberOfUserProfiles(void) +{ + int n = UserProfilesList.size(); + + LOCALASSERT(n>0); + + return n-1; +} + +extern AVP_USER_PROFILE *GetFirstUserProfile(void) +{ + CurrentUserProfilePtr=UserProfilesList.first_entry(); + return CurrentUserProfilePtr; +} + +extern AVP_USER_PROFILE *GetNextUserProfile(void) +{ + if (CurrentUserProfilePtr == UserProfilesList.last_entry()) + { + CurrentUserProfilePtr = UserProfilesList.first_entry(); + } + else + { + CurrentUserProfilePtr = UserProfilesList.next_entry(CurrentUserProfilePtr); + } + return CurrentUserProfilePtr; +} + +static void EmptyUserProfilesList(void) +{ + while (UserProfilesList.size()) + { + delete UserProfilesList.first_entry(); + UserProfilesList.delete_first_entry(); + } +} + +extern int SaveUserProfile(AVP_USER_PROFILE *profilePtr) +{ + char *filename = new char [strlen(USER_PROFILES_PATH)+strlen(profilePtr->Name)+strlen(USER_PROFILES_SUFFIX)+1]; + strcpy(filename,USER_PROFILES_PATH); + strcat(filename,profilePtr->Name); + strcat(filename,USER_PROFILES_SUFFIX); + + FILE* file=fopen(filename,"wb"); + delete [] filename; + if(!file) return 0; + + SaveSettingsToUserProfile(profilePtr); + + fwrite(profilePtr,sizeof(AVP_USER_PROFILE),1,file); + fclose(file); + + return 1; + +} + +extern void DeleteUserProfile(int number) +{ + AVP_USER_PROFILE *profilePtr = GetFirstUserProfile(); + + for (int i=0; iName)+strlen(USER_PROFILES_SUFFIX)+1]; + strcpy(filename,USER_PROFILES_PATH); + strcat(filename,profilePtr->Name); + strcat(filename,USER_PROFILES_SUFFIX); + + DeleteFile(filename); + + delete [] filename; + { + int i; + filename = new char [100]; + + for (i=0; iName,i+1); + DeleteFile(filename); + } + delete [] filename; + } + +} + + + +static void InsertProfileIntoList(AVP_USER_PROFILE *profilePtr) +{ + if (UserProfilesList.size()) + { + AVP_USER_PROFILE *profileInListPtr = GetFirstUserProfile(); + + for (int i=0; iFileTime,&profileToTestAgainstPtr->FileTime)==1) + { + return 1; + } + else + { + return 0; + } +} +static int LoadUserProfiles(void) +{ + + const char* load_name=USER_PROFILES_WILDCARD_NAME; + // allow a wildcard search + WIN32_FIND_DATA wfd; + + HANDLE hFindFile = ::FindFirstFile(load_name,&wfd); + + if (INVALID_HANDLE_VALUE == hFindFile) + { +// printf("File Not Found: <%s>\n",load_name); + return 0; + } + + // get any path in the load_name + int nPathLen = 0; + char * pColon = strrchr(load_name,':'); + if (pColon) nPathLen = pColon - load_name + 1; + char * pBackSlash = strrchr(load_name,'\\'); + if (pBackSlash) + { + int nLen = pBackSlash - load_name + 1; + if (nLen > nPathLen) nPathLen = nLen; + } + char * pSlash = strrchr(load_name,'/'); + if (pSlash) + { + int nLen = pSlash - load_name + 1; + if (nLen > nPathLen) nPathLen = nLen; + } + + do + { + if + ( + !(wfd.dwFileAttributes & + (FILE_ATTRIBUTE_DIRECTORY + |FILE_ATTRIBUTE_SYSTEM + |FILE_ATTRIBUTE_HIDDEN + |FILE_ATTRIBUTE_READONLY)) + // not a directory, hidden or system file + ) + { + char * pszFullPath = new char [nPathLen+strlen(wfd.cFileName)+1]; + strncpy(pszFullPath,load_name,nPathLen); + strcpy(pszFullPath+nPathLen,wfd.cFileName); + + + //make sure the file is a rif file + HANDLE rif_file; + rif_file = CreateFile (pszFullPath, GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, 0); + if(rif_file==INVALID_HANDLE_VALUE) + { +// printf("couldn't open %s\n",pszFullPath); + delete[] pszFullPath; + continue; + } + + AVP_USER_PROFILE *profilePtr = new AVP_USER_PROFILE; + unsigned long bytes_read; + + if (!ReadFile(rif_file, profilePtr, sizeof(AVP_USER_PROFILE), &bytes_read, 0)) + { + CloseHandle (rif_file); + delete[] pszFullPath; + delete profilePtr; + continue; + } + FILETIME ftLocal; + FileTimeToLocalFileTime(&wfd.ftLastWriteTime,&ftLocal); + FileTimeToSystemTime(&ftLocal,&profilePtr->TimeLastUpdated); + profilePtr->FileTime = ftLocal; + InsertProfileIntoList(profilePtr); + CloseHandle (rif_file); + delete[] pszFullPath; + + } + + } + while (::FindNextFile(hFindFile,&wfd)); + + + if (ERROR_NO_MORE_FILES != GetLastError()) + { + // printf("Error finding next file\n"); + } + + ::FindClose(hFindFile); + + return 1; +} + + + +static void SetDefaultProfileOptions(AVP_USER_PROFILE *profilePtr) +{ + // set Gamma + RequestedGammaSetting = 128; + + // controls + MarineInputPrimaryConfig = DefaultMarineInputPrimaryConfig; + MarineInputSecondaryConfig = DefaultMarineInputSecondaryConfig; + PredatorInputPrimaryConfig = DefaultPredatorInputPrimaryConfig; + PredatorInputSecondaryConfig = DefaultPredatorInputSecondaryConfig; + AlienInputPrimaryConfig = DefaultAlienInputPrimaryConfig; + AlienInputSecondaryConfig = DefaultAlienInputSecondaryConfig; + ControlMethods = DefaultControlMethods; + JoystickControlMethods = DefaultJoystickControlMethods; + + SmackerSoundVolume = ONE_FIXED/512; + EffectsSoundVolume = VOLUME_DEFAULT; + CDPlayerVolume = CDDA_VOLUME_DEFAULT; + MoviesAreActive = 1; + IntroOutroMoviesAreActive = 1; + AutoWeaponChangeOn = TRUE; + + + // Edmond to add in network name + srand(time(NULL)); + switch(rand()%11) + { + case 0: + strcpy(MP_PlayerName, "DogMeat"); + break; + case 1: + strcpy(MP_PlayerName, "FreshMeat"); + break; + case 2: + strcpy(MP_PlayerName, "RancidMeat"); + break; + case 3: + strcpy(MP_PlayerName, "HorseMeat"); + break; + case 4: + strcpy(MP_PlayerName, "RawMeat"); + break; + case 5: + strcpy(MP_PlayerName, "LiveMeat"); + break; + case 6: + strcpy(MP_PlayerName, "M-m-m-meat"); + break; + case 7: + strcpy(MP_PlayerName, "LlamaMeat"); + break; + case 8: + strcpy(MP_PlayerName, "JustMeat"); + break; + case 9: + strcpy(MP_PlayerName, "TastyMeat"); + break; + case 10: + strcpy(MP_PlayerName, "MonkeyMeat"); + break; + } + strcpy(MP_PlayerName,"DeadMeat"); + + SetToDefaultDetailLevels(); + + { + int a,b; + + for (a=0; aPersonalBests[a][b]=DefaultLevelGameStats; + } + } + } + + SaveSettingsToUserProfile(profilePtr); +} + + + + + +extern void GetSettingsFromUserProfile(void) +{ + RequestedGammaSetting = UserProfilePtr->GammaSetting; + + MarineInputPrimaryConfig = UserProfilePtr->MarineInputPrimaryConfig; + MarineInputSecondaryConfig = UserProfilePtr->MarineInputSecondaryConfig; + PredatorInputPrimaryConfig = UserProfilePtr->PredatorInputPrimaryConfig; + PredatorInputSecondaryConfig = UserProfilePtr->PredatorInputSecondaryConfig; + AlienInputPrimaryConfig = UserProfilePtr->AlienInputPrimaryConfig; + AlienInputSecondaryConfig = UserProfilePtr->AlienInputSecondaryConfig; + ControlMethods = UserProfilePtr->ControlMethods; + JoystickControlMethods = UserProfilePtr->JoystickControlMethods; + MenuDetailLevelOptions = UserProfilePtr->DetailLevelSettings; + SmackerSoundVolume = UserProfilePtr->SmackerSoundVolume; + EffectsSoundVolume = UserProfilePtr->EffectsSoundVolume; + CDPlayerVolume = UserProfilePtr->CDPlayerVolume; + MoviesAreActive = UserProfilePtr->MoviesAreActive; + IntroOutroMoviesAreActive = UserProfilePtr->IntroOutroMoviesAreActive; + AutoWeaponChangeOn = !UserProfilePtr->AutoWeaponChangeDisabled; + strncpy(MP_PlayerName,UserProfilePtr->MultiplayerCallsign,15); + + SetDetailLevelsFromMenu(); +} + + +extern void SaveSettingsToUserProfile(AVP_USER_PROFILE *profilePtr) +{ + profilePtr->GammaSetting = RequestedGammaSetting; + + profilePtr->MarineInputPrimaryConfig = MarineInputPrimaryConfig; + profilePtr->MarineInputSecondaryConfig = MarineInputSecondaryConfig; + profilePtr->PredatorInputPrimaryConfig = PredatorInputPrimaryConfig; + profilePtr->PredatorInputSecondaryConfig = PredatorInputSecondaryConfig; + profilePtr->AlienInputPrimaryConfig = AlienInputPrimaryConfig; + profilePtr->AlienInputSecondaryConfig = AlienInputSecondaryConfig; + profilePtr->ControlMethods = ControlMethods; + profilePtr->JoystickControlMethods = JoystickControlMethods; + profilePtr->DetailLevelSettings = MenuDetailLevelOptions; + profilePtr->SmackerSoundVolume = SmackerSoundVolume; + profilePtr->EffectsSoundVolume = EffectsSoundVolume; + profilePtr->CDPlayerVolume = CDPlayerVolume; + profilePtr->MoviesAreActive = MoviesAreActive; + profilePtr->IntroOutroMoviesAreActive = IntroOutroMoviesAreActive; + profilePtr->AutoWeaponChangeDisabled= !AutoWeaponChangeOn; + strncpy(profilePtr->MultiplayerCallsign,MP_PlayerName,15); +} + +extern void FixCheatModesInUserProfile(AVP_USER_PROFILE *profilePtr) +{ + int a; + + for (a=0; aCheatMode[a]==2) { + profilePtr->CheatMode[a]=1; + } + } + +} + +}; // extern "C" \ No newline at end of file diff --git a/3dc/avp/win95/Frontend/AvP_UserProfile.h b/3dc/avp/win95/Frontend/AvP_UserProfile.h new file mode 100644 index 0000000..381c075 --- /dev/null +++ b/3dc/avp/win95/Frontend/AvP_UserProfile.h @@ -0,0 +1,183 @@ +#ifndef _avp_user_profile_h_ +#define _avp_user_profile_h_ 1 + +#include "usr_io.h" +#include "AvP_EnvInfo.h" +#include "game_statistics.h" +#include "detaillevels.h" +/* KJL 14:17:41 10/12/98 - User profile + + Structures that contains the information required by the single player game + + e.g. which levels have been played, which difficulty levels etc. + + */ +#define MAX_NO_OF_USERS 4 + +#define MAX_SIZE_OF_USERS_NAME 15 + +enum AVP_DIFFICULTY_LEVEL_ID +{ + AVP_DIFFICULTY_LEVEL_NONE, + /* the 'none' difficulty level setting can be used to indicate that + a level has never been completed */ + + AVP_DIFFICULTY_LEVEL_EASY, + AVP_DIFFICULTY_LEVEL_MEDIUM, + AVP_DIFFICULTY_LEVEL_HARD, +}; + +enum CHEATMODE_ID +{ + CHEATMODE_PIGSTICKING, + CHEATMODE_SLUGTRAIL, + CHEATMODE_SNIPERMUNCH, + CHEATMODE_TERROR, + CHEATMODE_SUPERGORE, + CHEATMODE_GRENADE, + CHEATMODE_MIRROR, + CHEATMODE_PIPECLEANER, + CHEATMODE_DISCOINFERNO, + CHEATMODE_TRIPTASTIC, + CHEATMODE_MOTIONBLUR, + CHEATMODE_UNDERWATER, + CHEATMODE_JOHNWOO, + CHEATMODE_WARPSPEED, + CHEATMODE_LANDOFTHEGIANTS, + CHEATMODE_IMPOSSIBLEMISSION, + CHEATMODE_RAINBOWBLOOD, + CHEATMODE_TICKERTAPE, + CHEATMODE_NAUSEA, + CHEATMODE_FREEFALL, + CHEATMODE_BALLSOFFIRE, + + MAX_NUMBER_OF_CHEATMODES, + + + CHEATMODE_NONACTIVE// leave me at the end! + + +}; + +/* Putting this here to get the definition of the cheat enum. */ +typedef struct { + AvP_GameStats_Stored StatTargets; + enum CHEATMODE_ID CheatModeToActivate; +} AvP_Level_Target_Desc; + +typedef struct +{ + char Name[MAX_SIZE_OF_USERS_NAME+1]; + + SYSTEMTIME TimeLastUpdated; + FILETIME FileTime; + + /* KJL 15:14:12 10/12/98 - array to hold level completion data + 3 species, pad out to 16 levels each */ + char LevelCompleted[3][16]; + + unsigned char CheatMode[32]; + unsigned char GammaSetting; + unsigned char AutoWeaponChangeDisabled : 1; + unsigned char SpareBits : 7; //not used + char Padding[74]; + + int CDPlayerVolume; + + char MultiplayerCallsign[16]; + + int SmackerSoundVolume; + int EffectsSoundVolume; + int MoviesAreActive; + int IntroOutroMoviesAreActive; + + MENU_DETAIL_LEVEL_OPTIONS DetailLevelSettings; + + PLAYER_INPUT_CONFIGURATION MarineInputPrimaryConfig; + PLAYER_INPUT_CONFIGURATION MarineInputSecondaryConfig; + PLAYER_INPUT_CONFIGURATION AlienInputPrimaryConfig; + PLAYER_INPUT_CONFIGURATION AlienInputSecondaryConfig; + PLAYER_INPUT_CONFIGURATION PredatorInputPrimaryConfig; + PLAYER_INPUT_CONFIGURATION PredatorInputSecondaryConfig; + CONTROL_METHODS ControlMethods; + JOYSTICK_CONTROL_METHODS JoystickControlMethods; + + /* This feels a bit bloaty. */ + AvP_GameStats_Stored PersonalBests[I_MaxDifficulties][AVP_ENVIRONMENT_END_OF_LIST]; + /* Yes, it contains impossible! So sue me! */ + +} AVP_USER_PROFILE; + + + +#define SUPERGORE_MODE (CheatMode_Active == CHEATMODE_SUPERGORE) +#define SLUGTRAIL_MODE (CheatMode_Active == CHEATMODE_SLUGTRAIL) +#define TERROR_MODE (CheatMode_Active == CHEATMODE_TERROR) +#define GRENADE_MODE (CheatMode_Active == CHEATMODE_GRENADE) +#define PIGSTICKING_MODE (CheatMode_Active == CHEATMODE_PIGSTICKING) +#define SNIPERMUNCH_MODE (CheatMode_Active == CHEATMODE_SNIPERMUNCH) +#define MIRROR_CHEATMODE (CheatMode_Active == CHEATMODE_MIRROR) +#define PIPECLEANER_CHEATMODE (CheatMode_Active == CHEATMODE_PIPECLEANER) +#define DISCOINFERNO_CHEATMODE (CheatMode_Active == CHEATMODE_DISCOINFERNO) +#define TRIPTASTIC_CHEATMODE (CheatMode_Active == CHEATMODE_TRIPTASTIC) +#define MOTIONBLUR_CHEATMODE (CheatMode_Active == CHEATMODE_MOTIONBLUR) +#define UNDERWATER_CHEATMODE (CheatMode_Active == CHEATMODE_UNDERWATER) +#define JOHNWOO_CHEATMODE (CheatMode_Active == CHEATMODE_JOHNWOO) +#define WARPSPEED_CHEATMODE (CheatMode_Active == CHEATMODE_WARPSPEED) +#define LANDOFTHEGIANTS_CHEATMODE (CheatMode_Active == CHEATMODE_LANDOFTHEGIANTS) +#define IMPOSSIBLEMISSION_CHEATMODE (CheatMode_Active == CHEATMODE_IMPOSSIBLEMISSION) +#define RAINBOWBLOOD_CHEATMODE (CheatMode_Active == CHEATMODE_RAINBOWBLOOD) +#define TICKERTAPE_CHEATMODE (CheatMode_Active == CHEATMODE_TICKERTAPE) +#define NAUSEA_CHEATMODE (CheatMode_Active == CHEATMODE_NAUSEA) +#define FREEFALL_CHEATMODE (CheatMode_Active == CHEATMODE_FREEFALL) +#define BALLSOFFIRE_CHEATMODE (CheatMode_Active == CHEATMODE_BALLSOFFIRE) + + +/* e.g. to access a cheat mode + + if (UserProfilePtr->CheatMode[CHEATMODE_PIGSTICKING]&CHEATMODE_IS_ACTIVE) + { + ... + } +*/ + + + + + + +#define USER_PROFILES_PATH "User_Profiles\\" +#define USER_PROFILES_WILDCARD_NAME "User_Profiles\\*.prf" +#define USER_PROFILES_SUFFIX ".prf" + + +#ifdef __cplusplus +extern "C" +{ +#endif + +extern void ExamineSavedUserProfiles(void); +extern int NumberOfUserProfiles(void); +extern AVP_USER_PROFILE *GetFirstUserProfile(void); +extern AVP_USER_PROFILE *GetNextUserProfile(void); +extern int SaveUserProfile(AVP_USER_PROFILE *profilePtr); +extern void DeleteUserProfile(int number); + + +extern void GetSettingsFromUserProfile(void); +extern void SaveSettingsToUserProfile(AVP_USER_PROFILE *profilePtr); + +extern AVP_USER_PROFILE *UserProfilePtr; + +extern int CheatMode_Active; +extern int CheatMode_Species; +extern int CheatMode_Environment; + + +extern int EdmondsTest(); + +#ifdef __cplusplus +}; // extern "C" +#endif + +#endif \ No newline at end of file diff --git a/3dc/avp/win95/Frontend/vssver.scc b/3dc/avp/win95/Frontend/vssver.scc new file mode 100644 index 0000000..632f148 Binary files /dev/null and b/3dc/avp/win95/Frontend/vssver.scc differ diff --git a/3dc/avp/win95/GAMEPLAT.H b/3dc/avp/win95/GAMEPLAT.H new file mode 100644 index 0000000..eade914 --- /dev/null +++ b/3dc/avp/win95/GAMEPLAT.H @@ -0,0 +1,39 @@ +/* + This contains project platfrom specifc externs + and prototypes. Only valid when we are calling one + p\p function from another. +*/ + + + +extern void LoadRifFile(); + + + +/* record of the histance passed to winmain */ + + +extern HINSTANCE AVP_HInstance; +extern int AVP_NCmd; + +extern int AVP_ChangeDisplayMode + ( + HINSTANCE hInst, + int nCmd, + int NewVideoMode, + int NewWindowMode, + int NewZBufferMode, + int NewRasterisationMode, + int NewSoftwareScanDrawMode, + int NewDXMemoryMode + ); + + + +extern int WindowMode; +extern int WindowRequestMode; +extern int VideoRequestMode; +extern int ZBufferRequestMode; +extern int RasterisationRequestMode; +extern int SoftwareScanDrawRequestMode; +extern int DXMemoryRequestMode; diff --git a/3dc/avp/win95/GammaControl.cpp b/3dc/avp/win95/GammaControl.cpp new file mode 100644 index 0000000..dad5a99 --- /dev/null +++ b/3dc/avp/win95/GammaControl.cpp @@ -0,0 +1,96 @@ +extern "C" +{ + +#include "3dc.h" +#include "module.h" +#include "inline.h" +#include "d3dmacs.h" +#include "GammaControl.h" + +extern LPDIRECTDRAWSURFACE lpDDSPrimary; +static int ActualGammaSetting; +int RequestedGammaSetting; + +unsigned char GammaValues[256]; + +void InitialiseGammaSettings(int gamma) +{ + ActualGammaSetting = gamma+1; + RequestedGammaSetting = gamma; + UpdateGammaSettings(); +} +#if 0 +void UpdateGammaSettings(void) +{ + LPDIRECTDRAWGAMMACONTROL handle=NULL; + DDGAMMARAMP gammaValues; + + if (RequestedGammaSetting==ActualGammaSetting) return; + + lpDDSPrimary->QueryInterface(IID_IDirectDrawGammaControl,(LPVOID*)&handle); + if(!handle) + { + return; + } +// handle->GetGammaRamp(0,&gammaValues); + for (int i=0; i<=255; i++) + { + int u = ((i*65536)/255); + int m = MUL_FIXED(u,u); + int l = MUL_FIXED(2*u,ONE_FIXED-u); + + int a; + + a = m/256+MUL_FIXED(RequestedGammaSetting,l); + if (a<0) a=0; + if (a>255) a=255; + + gammaValues.red[i]=a*256; + gammaValues.green[i]=a*256; + gammaValues.blue[i]=a*256; + } + + HRESULT result = handle->SetGammaRamp(0,&gammaValues); + + RELEASE(handle); + + ActualGammaSetting=RequestedGammaSetting; + +} +#else +void UpdateGammaSettings(void) +{ + LPDIRECTDRAWGAMMACONTROL handle=NULL; + DDGAMMARAMP gammaValues; + + if (RequestedGammaSetting==ActualGammaSetting) return; + + for (int i=0; i<=255; i++) + { + int u = ((i*65536)/255); + int m = MUL_FIXED(u,u); + int l = MUL_FIXED(2*u,ONE_FIXED-u); + + int a; + + a = m+MUL_FIXED(RequestedGammaSetting*256,l); + + + + m = MUL_FIXED(a,a); + l = MUL_FIXED(2*a,ONE_FIXED-a); + + a = m/256+MUL_FIXED(RequestedGammaSetting,l); + + if (a<0) a=0; + if (a>255) a=255; + + GammaValues[i]=a; + } + + ActualGammaSetting=RequestedGammaSetting; + +} +#endif + +}; \ No newline at end of file diff --git a/3dc/avp/win95/GammaControl.h b/3dc/avp/win95/GammaControl.h new file mode 100644 index 0000000..e722b72 --- /dev/null +++ b/3dc/avp/win95/GammaControl.h @@ -0,0 +1,9 @@ +#ifndef _included_GammaControl_h_ +#define _included_GammaControl_h_ 1 + +extern void InitialiseGammaSettings(int gamma); +extern void UpdateGammaSettings(void); +extern int RequestedGammaSetting; + + +#endif \ No newline at end of file diff --git a/3dc/avp/win95/HEAP_TEM.HPP b/3dc/avp/win95/HEAP_TEM.HPP new file mode 100644 index 0000000..7bc6701 --- /dev/null +++ b/3dc/avp/win95/HEAP_TEM.HPP @@ -0,0 +1,555 @@ +#ifndef _included_heap_tem_hpp_ +#define _included_heap_tem_hpp_ + +// Author: Jake Hotson, Rebellion Developments Ltd. + +// Previously, the first declaration of these class templates was as friends +// of Ordered_Heap_Member. But Visual C++ 5 will not parse the friend +// declarations unless we give a forward declaration first. I think this is +// a compiler bug - Garry. +template +class Ordered_Heap; +template +class Ordered_Heap_Iterator_Forward; +template +class Ordered_Heap_Iterator_Backward; + +template +class Ordered_Heap_Member +{ +private: + T data; + Ordered_Heap_Member * lower, * higher, * parent; + int num_lower, num_higher; + + // Ordered_Heap_Member() : lower(0), higher(0), parent(0), num_lower(0), num_higher(0) {} + Ordered_Heap_Member(const T & d) : lower(0), higher(0), parent(0), num_lower(0), num_higher(0), data(d) {} + + void delete_tree() + { + if (lower) + { + lower->delete_tree(); + delete lower; + } + if (higher) + { + higher->delete_tree(); + delete higher; + } + } + + #if 0 + operator T const & () const { return data; } + operator T & () { return data; } + #endif + + friend class Ordered_Heap; + friend class Ordered_Heap_Iterator_Forward; + friend class Ordered_Heap_Iterator_Backward; +}; + +// I haven't implemented balancing of the heap on addition or deletion of entries +// so if you build the heap by adding the elements in order, it will be lopsided and inefficient +// if anyone wants to suggest a good way of keeping the heap balanced, please do... + +// the operator < must be defined (and should be transitive). +// equivalent elements (!(a +class Ordered_Heap +{ +private: + Ordered_Heap_Member * lowest, * highest, * root; + int n_entries; + +public: + // empty heap + Ordered_Heap() : lowest(0), highest(0), root(0), n_entries(0) {} + + // heap with one element + Ordered_Heap(T const & d) + { + lowest = highest = root = new Ordered_Heap_Member(d); + n_entries = 1; + } + + // heap with all the elents of another heap + Ordered_Heap(const Ordered_Heap & h) : lowest(0), highest(0), root(0), n_entries(0) { add_heap(h); } + + // assignment from another heap + Ordered_Heap & operator = (const Ordered_Heap & h) + { + if (&h != this) + { + if (root) + { + root->delete_tree(); + delete root; + } + n_entries = 0; + root = highest = lowest = 0; + add_heap(h); + } + return *this; + } + + // deconstructor + ~Ordered_Heap() + { + if (root) + { + root->delete_tree(); + delete root; + } + } + + // add all elements of another heap (merge) + void add_heap(const Ordered_Heap & h) + { + if (h.root) add_heap(*h.root); + } + +private: + void add_heap(const Ordered_Heap_Member & m) + { + add_entry(m.data); + if (m.lower) add_heap(*m.lower); + if (m.higher) add_heap(*m.higher); + } + +public: + // inclued a new element + void add_entry(const T & d) + { + if (n_entries) + { + Ordered_Heap_Member * new_member = new Ordered_Heap_Member(d); + Ordered_Heap_Member * new_lowest = new_member; + Ordered_Heap_Member * new_highest = new_member; + for (Ordered_Heap_Member * m = root;1;) + { + if (d < m->data) + { + ++ m->num_lower; + if (m->lower) + { + m = m->lower; + new_highest = highest; + } + else + { + m->lower = new_member; + new_member->parent = m; + lowest = new_lowest; + break; + } + } + else + { + ++ m->num_higher; + if (m->higher) + { + m = m->higher; + new_lowest = lowest; + } + else + { + m->higher = new_member; + new_member->parent = m; + highest = new_highest; + break; + } + } + } + } + else + { + lowest = highest = root = new Ordered_Heap_Member(d); + } + ++ n_entries; + } + + // delete the element a in heap h such that for all b in h : !(b < a) + void delete_lowest() + { + if (1==n_entries) + { + delete root; + n_entries = 0; + root = lowest = highest = 0; + } + else if (n_entries) + { + Ordered_Heap_Member * new_lowest; + if (lowest->parent) + { + for (Ordered_Heap_Member * m = lowest; m->parent; m = m->parent) + { + -- m->parent->num_lower; + } + if (lowest->higher) + { + new_lowest = lowest->higher; + lowest->parent->lower = new_lowest; + new_lowest->parent = lowest->parent; + delete lowest; + while (new_lowest->lower) new_lowest = new_lowest->lower; + } + else + { + new_lowest = lowest->parent; + new_lowest->lower = 0; + delete lowest; + } + } + else // lowest is root + { + new_lowest = lowest->higher; + new_lowest->parent = 0; + delete lowest; + root = new_lowest; + while (new_lowest->lower) new_lowest = new_lowest->lower; + } + lowest = new_lowest; + -- n_entries; + } + } + + // delete the element a in heap h such that for all b in h : !(a < b) + void delete_highest() + { + if (1==n_entries) + { + delete root; + n_entries = 0; + root = lowest = highest = 0; + } + else if (n_entries) + { + Ordered_Heap_Member * new_highest; + if (highest->parent) + { + for (Ordered_Heap_Member * m = highest; m->parent; m = m->parent) + { + -- m->parent->num_higher; + } + if (highest->lower) + { + new_highest = highest->lower; + highest->parent->higher = new_highest; + new_highest->parent = highest->parent; + delete highest; + while (new_highest->higher) new_highest = new_highest->higher; + } + else + { + new_highest = highest->parent; + new_highest->higher = 0; + delete highest; + } + } + else // highest is root + { + new_highest = highest->lower; + new_highest->parent = 0; + delete highest; + root = new_highest; + while (new_highest->higher) new_highest = new_highest->higher; + } + highest = new_highest; + -- n_entries; + } + } + + Ordered_Heap_Member * equivalent_entry(T const & d) + { + Ordered_Heap_Member * m = root; + + while (m && (m->datadata)) + m = ddata ? m->lower : m->higher; + + return m; + } + + void delete_entry_by_pointer(Ordered_Heap_Member * m) + { + if (m == lowest) delete_lowest(); + else if (m == highest) delete_highest(); + else if (m->lower) + { + Ordered_Heap_Member * new_node = m->lower; + while (new_node->higher) + { + -- new_node->num_higher; + new_node = new_node->higher; + } + if (new_node != m->lower) + { + new_node->parent->higher = new_node->lower; + if (new_node->lower) new_node->lower->parent = new_node->parent; + } + else + { + m->lower = new_node->lower; + } + if (m->parent) + { + if (m->parent->higher == m) + { + m->parent->higher = new_node; + -- m->parent->num_higher; + } + else + { + m->parent->lower = new_node; + -- m->parent->num_lower; + } + } + else root = new_node; + if (m->lower) m->lower->parent = new_node; + if (m->higher) m->higher->parent = new_node; + new_node->parent = m->parent; + new_node->lower = m->lower; + new_node->higher = m->higher; + new_node->num_lower = m->num_lower-1; + new_node->num_higher = m->num_higher; + delete m; + -- n_entries; + } + else + { + if (m->parent) + { + if (m->parent->higher == m) + { + m->parent->higher = m->higher; + -- m->parent->num_higher; + } + else + { + m->parent->lower = m->higher; + -- m->parent->num_lower; + } + } + else root = m->higher; + if (m->higher) m->higher->parent = m->parent; + delete m; + -- n_entries; + } + } + + // return the ith element, when i=0 returns the lowest + T const & operator [](int i) const + { + Ordered_Heap_Member * m = root; + while (m->num_lower != i) + { + if (m->num_lower > i) m = m->lower; + else + { + i -= m->num_lower; + m = m->higher; + -- i; + } + } + return m->data; + } + + // return the element a in heap h such that for all b in h : !(b < a) + T const & lowest_entry() const { return lowest->data; } + // return the element a in heap h such that for all b in h : !(a < b) + T const & highest_entry() const { return highest->data; } + + // return the number of elements + int size() const { return n_entries; } + + friend class Ordered_Heap_Iterator_Forward; + friend class Ordered_Heap_Iterator_Backward; +}; + + +template +class Ordered_Heap_Iterator_Forward +{ +private: + Ordered_Heap_Member * m; + Ordered_Heap const * h; + Ordered_Heap * hnc; + +public: + // construct with pointer to heap, start at lowest + Ordered_Heap_Iterator_Forward() {} + Ordered_Heap_Iterator_Forward(Ordered_Heap const * const h) : h(h), hnc(0), m(h->lowest) {} + Ordered_Heap_Iterator_Forward(Ordered_Heap * const h) : h(h), hnc(h), m(h->lowest) {} + + int operator == (Ordered_Heap_Iterator_Forward const & i2) const { return m==i2.m; } + int operator != (Ordered_Heap_Iterator_Forward const & i2) const { return m!=i2.m; } + + // move to next highest, sequentially + void next() + { + if (m->higher) + { + m = m->higher; + while (m->lower) m = m->lower; + } + else + { + while (m->parent) + { + if (m->parent->lower == m) break; + m = m->parent; + } + if (m->parent) m = m->parent; + else m = 0; + } + } + + // undo a next operation + void un_next() + { + if (m->lower) + { + m = m->lower; + while (m->higher) m = m->higher; + } + else + { + while (m->parent) + { + if (m->parent->higher == m) break; + m = m->parent; + } + if (m->parent) m = m->parent; + else m = 0; + } + } + + // return the current element + T const & operator() () const { return m->data; } + operator T const & () const { return m->data; } + + // delete the current element + // unpredictable if iterator constructed from a constant heap + void delete_current() + { + Ordered_Heap_Member * old_m = m; + next(); + hnc->delete_entry_by_pointer(old_m); + } + + // change the current element, checking that the ordering is preserved + int change_current(T const & new_val) // be very careful with this -- check the return value which is non-zero on success + { + Ordered_Heap_Member * old_m = m; + next(); + Ordered_Heap_Member * higher_m = m; + m = old_m; + un_next(); + Ordered_Heap_Member * lower_m = m; + m = old_m; + + if (lower_m) if (new_val < lower_m->data) { return 0; } + if (higher_m) if (higher_m->data < new_val) { return 0; } + m->data = new_val; + return 1; + } + + // have we gone past the highest? + int done() const { return m ? 0 : 1; } + + // start again at lowest + void restart() { m = h->lowest; } +}; + +#define OHIF Ordered_Heap_Iterator_Forward + + +template +class Ordered_Heap_Iterator_Backward +{ +private: + Ordered_Heap_Member * m; + Ordered_Heap const * h; + Ordered_Heap * hnc; + +public: + Ordered_Heap_Iterator_Backward() {} + Ordered_Heap_Iterator_Backward(Ordered_Heap const * const h) : h(h), hnc(0), m(h->highest) {} + Ordered_Heap_Iterator_Backward(Ordered_Heap * const h) : h(h), hnc(h), m(h->highest) {} + + int operator == (Ordered_Heap_Iterator_Backward const & i2) const { return m==i2.m; } + int operator != (Ordered_Heap_Iterator_Backward const & i2) const { return m!=i2.m; } + + void next() + { + if (m->lower) + { + m = m->lower; + while (m->higher) m = m->higher; + } + else + { + while (m->parent) + { + if (m->parent->higher == m) break; + m = m->parent; + } + if (m->parent) m = m->parent; + else m = 0; + } + } + + void un_next() + { + if (m->higher) + { + m = m->higher; + while (m->lower) m = m->lower; + } + else + { + while (m->parent) + { + if (m->parent->lower == m) break; + m = m->parent; + } + if (m->parent) m = m->parent; + else m = 0; + } + } + + T const & operator() () const { return m->data; } + operator T const & () const { return m->data; } + + void delete_current() + { + Ordered_Heap_Member * old_m = m; + next(); + hnc->delete_entry_by_pointer(old_m); + } + + int change_current(T const & new_val) // be very careful with this -- check the return value which is non-zero on success + { + Ordered_Heap_Member * old_m = m; + next(); + Ordered_Heap_Member * lower_m = m; + m = old_m; + un_next(); + Ordered_Heap_Member * higher_m = m; + m = old_m; + + if (lower_m) if (new_val < lower_m->data) { return 0; } + if (higher_m) if (higher_m->data < new_val) { return 0; } + m->data = new_val; + return 1; + } + + int done() const { return m ? 0 : 1; } + void restart() { m = h->highest; } +}; + +#define OHIB Ordered_Heap_Iterator_Backward + +#endif // !_included_heap_tem_hpp_ \ No newline at end of file diff --git a/3dc/avp/win95/HUDGFX.H b/3dc/avp/win95/HUDGFX.H new file mode 100644 index 0000000..e0f3882 --- /dev/null +++ b/3dc/avp/win95/HUDGFX.H @@ -0,0 +1,123 @@ +#ifndef _hudgfx_h +#define _hudgfx_h +/*KJL********************************************************************************************* +* HUDGFX.H * +* * +* Contains the enumerations and structures that are used in DDPLAT.CPP to draw the HUD graphics. * +*********************************************************************************************KJL*/ + + +/*KJL**************************************************************************************** +* D E F I N E S * +****************************************************************************************KJL*/ + +/* fonts used in HUD */ +enum HUD_FONT +{ + MARINE_HUD_FONT_BLUE, + MARINE_HUD_FONT_RED, + MARINE_HUD_FONT_MT_SMALL, + MARINE_HUD_FONT_MT_BIG, + + ALIEN_HUD_FONT, + + NUM_HUD_FONTS +}; +/* DD Surfaces */ +enum MARINE_HUD_GFX +{ + MARINE_HUD_GFX_MOTIONTRACKERBLIP, + MARINE_HUD_GFX_NUMERALS, + MARINE_HUD_GFX_GUNSIGHTS, + MARINE_HUD_GFX_TRACKERFONT, + MARINE_HUD_GFX_BLUEBAR, + NO_OF_MARINE_HUD_GFX +}; + +enum PREDATOR_HUD_GFX +{ + PREDATOR_HUD_GFX_TOP, + PREDATOR_HUD_GFX_BOTTOM, + PREDATOR_HUD_GFX_NUMBERS, + PREDATOR_HUD_GFX_SYMBOLS, + NO_OF_PREDATOR_HUD_GFX +}; + +enum ALIEN_HUD_GFX +{ + ALIEN_HUD_GFX_BOTTOM, + ALIEN_HUD_GFX_LEFT, + ALIEN_HUD_GFX_RIGHT, + ALIEN_HUD_GFX_TOP, + ALIEN_HUD_GFX_NUMBERS, + NO_OF_ALIEN_HUD_GFX +}; + +enum HUD_RES_ID +{ + HUD_RES_LO, + HUD_RES_MED, + HUD_RES_HI, +}; +/*KJL**************************************************************************************** +* S T R U C T U R E S * +****************************************************************************************KJL*/ + +/* description of a single DD surface used for HUD gfx */ +struct DDGraphicTag +{ + LPDIRECTDRAWSURFACE LPDDS; + AW_BACKUPTEXTUREHANDLE hBackup; // JH 12/2/98 changed for new gfx loading system + RECT SrcRect; +}; + +/* description of a digit appearing on the HUD */ +struct DigitPropertiesTag +{ + int X; + int Y; + int Font; +}; + +/* info about a particular frame */ +struct FrameInfoTag +{ + int X; /* centre X coord of frame */ + int Y; /* bottom Y of frame */ + char *FilenamePtr; /* filename of graphic */ +}; + +struct HUDFontDescTag +{ + int XOffset; + int Height; + int Width; +}; + +struct LittleMDescTag +{ + int SourceTop; + int SourceLeft; + int Width; + int Height; + int X; + int Y; +}; + +/*JH***************************************************************************************** +* P R O T O T Y P E S * +*****************************************************************************************JH*/ + +/* JH 3/6/97 - these functions are to + release hud graphics with any links to direct draw + but still keep them in memory, so they can be restored */ +extern void MinimizeAllDDGraphics(void); +extern void RestoreAllDDGraphics(void); + +/*KJL**************************************************************************************** +* E X T E R N S * +****************************************************************************************KJL*/ +extern LPDIRECTDRAW lpDD; +extern LPDIRECTDRAWSURFACE lpDDSBack; + +#endif \ No newline at end of file diff --git a/3dc/avp/win95/HUD_DATA.H b/3dc/avp/win95/HUD_DATA.H new file mode 100644 index 0000000..3892065 --- /dev/null +++ b/3dc/avp/win95/HUD_DATA.H @@ -0,0 +1,417 @@ +/*KJL**************************************************************************************** +* D I S P L A Y D A T A * +****************************************************************************************KJL*/ + +/* KJL 16:58:11 05/08/97 - the display data was getting quite long, so I moved it to +a header file to make things clearer. */ +static struct DDGraphicTag HUDDDInfo[NO_OF_MARINE_HUD_GFX]; + +/* MARINE LO RES (width = 320) */ +static struct DigitPropertiesTag LoresMarineHUDDigitProperties[] = +{ + /* motion tracker digits, units first, thousands last */ + /* these are relative to motion tracker centre! */ + {9, -2, MARINE_HUD_FONT_MT_SMALL}, + {3, -2, MARINE_HUD_FONT_MT_SMALL}, + {-8, -2, MARINE_HUD_FONT_MT_BIG}, + {-17, -2,MARINE_HUD_FONT_MT_BIG}, + + /* -ve values are relative to right side of the screen */ + /* marine health, units first */ + {28,10, MARINE_HUD_FONT_BLUE}, + {19,10, MARINE_HUD_FONT_BLUE}, + {10,10, MARINE_HUD_FONT_BLUE}, + + /* marine energy, units first */ + {28,25, MARINE_HUD_FONT_BLUE}, + {19,25, MARINE_HUD_FONT_BLUE}, + {10,25, MARINE_HUD_FONT_BLUE}, + + /* marine armour, units first */ + {28,40, MARINE_HUD_FONT_BLUE}, + {19,40, MARINE_HUD_FONT_BLUE}, + {10,40, MARINE_HUD_FONT_BLUE}, + + /* marine ammo/rounds, units first */ + {-22,10, MARINE_HUD_FONT_RED}, + {-31,10, MARINE_HUD_FONT_RED}, + {-40,10, MARINE_HUD_FONT_RED}, + + /* marine ammo/magazines, units first */ + {-61,10, MARINE_HUD_FONT_RED}, + {-70,10, MARINE_HUD_FONT_RED}, + + /* marine secondary ammo/rounds, units first */ + {-22,25, MARINE_HUD_FONT_RED}, + {-31,25, MARINE_HUD_FONT_RED}, + {-40,25, MARINE_HUD_FONT_RED}, + + /* marine secondary ammo/magazines, units first */ + {-61,25, MARINE_HUD_FONT_RED}, + {-70,25, MARINE_HUD_FONT_RED}, +}; +static char *LoresMarineHUDGfxFilenamePtr[]= +{ + {"blips.pg0"}, //MARINE_HUD_GFX_MOTIONTRACKERBLIP, + {"num.pg0"}, //MARINE_HUD_GFX_NUMERALS, + {"gunsight.pg0"}, //MARINE_HUD_GFX_GUNSIGHTS, + {"trakfont.pg0"}, + {"bluebar.pg0"}, +}; +static struct HUDFontDescTag LoresHUDFontDesc[] = +{ + //MARINE_HUD_FONT_BLUE, + { + 0,//XOffset + 12,//Height + 8,//Width + }, + //MARINE_HUD_FONT_RED, + { + 8,//XOffset + 12,//Height + 8,//Width + }, + //MARINE_HUD_FONT_MT_SMALL, + { + 8,//XOffset + 8,//Height + 5,//Width + }, + //MARINE_HUD_FONT_MT_BIG, + { + 0,//XOffset + 12,//Height + 8,//Width + }, + //ALIEN_HUD_FONT, + { + 0, + 8, + 6, + }, + +}; +static struct LittleMDescTag LoresHUDLittleM = +{ + 80,8, // source top,left + + 5,5, // width, height + + 7,7, // screen x,y +}; + + +/* MARINE MED RES (width = 640) */ +static struct DigitPropertiesTag MedresMarineHUDDigitProperties[] = +{ + /* motion tracker digits, units first, thousands last */ + /* these are relative to motion tracker centre! */ + {17, -4, MARINE_HUD_FONT_MT_SMALL}, + {9, -4, MARINE_HUD_FONT_MT_SMALL}, + {-9, -4, MARINE_HUD_FONT_MT_BIG}, + {-25, -4,MARINE_HUD_FONT_MT_BIG}, + + /* -ve values are relative to right side of the screen */ + /* marine health, units first */ + {56,20, MARINE_HUD_FONT_BLUE}, + {38,20, MARINE_HUD_FONT_BLUE}, + {20,20, MARINE_HUD_FONT_BLUE}, + + /* marine energy, units first */ + {56,50, MARINE_HUD_FONT_BLUE}, + {38,50, MARINE_HUD_FONT_BLUE}, + {20,50, MARINE_HUD_FONT_BLUE}, + + /* marine armour, units first */ + {56,80, MARINE_HUD_FONT_BLUE}, + {38,80, MARINE_HUD_FONT_BLUE}, + {20,80, MARINE_HUD_FONT_BLUE}, + + /* marine ammo/rounds, units first */ + {-44,20, MARINE_HUD_FONT_RED}, + {-62,20, MARINE_HUD_FONT_RED}, + {-80,20, MARINE_HUD_FONT_RED}, + + /* marine ammo/magazines, units first */ + {-122,20, MARINE_HUD_FONT_RED}, + {-140,20, MARINE_HUD_FONT_RED}, + + /* marine secondary ammo/rounds, units first */ + {-44,50, MARINE_HUD_FONT_RED}, + {-62,50, MARINE_HUD_FONT_RED}, + {-80,50, MARINE_HUD_FONT_RED}, + + /* marine secondary ammo/magazines, units first */ + {-122,50, MARINE_HUD_FONT_RED}, + {-140,50, MARINE_HUD_FONT_RED}, +}; +static char *MedresMarineHUDGfxFilenamePtr[]= +{ + {"blipsHRz.pg0"}, //MARINE_HUD_GFX_MOTIONTRACKERBLIP, + {"numMR.pg0"}, //MARINE_HUD_GFX_NUMERALS, + {"sightsmr.pg0"}, //MARINE_HUD_GFX_GUNSIGHTS, + {"trkfntmr.pg0"}, + {"blubarmr.pg0"}, +}; +static struct HUDFontDescTag MedresHUDFontDesc[] = +{ + //MARINE_HUD_FONT_BLUE, + { + 0,//XOffset + 24,//Height + 16,//Width + }, + //MARINE_HUD_FONT_RED, + { + 16,//XOffset + 24,//Height + 16,//Width + }, + //MARINE_HUD_FONT_MT_SMALL, + { + 14,//XOffset + 12,//Height + 8,//Width + }, + //MARINE_HUD_FONT_MT_BIG, + { + 0,//XOffset + 24,//Height + 14,//Width + }, + //ALIEN_HUD_FONT, + { + 0, + 16, + 12, + }, + +}; +static struct LittleMDescTag MedresHUDLittleM = +{ + 120,14, // source top,left + + 8,11, // width, height + + 10,10, // screen x,y +}; + + + + + + +/* MARINE HI RES (width = 800) */ +static struct DigitPropertiesTag HiresMarineHUDDigitProperties[] = +{ + /* motion tracker digits, units first, thousands last */ + /* these are relative to motion tracker centre! */ + {17, -4, MARINE_HUD_FONT_MT_SMALL}, + {5, -4, MARINE_HUD_FONT_MT_SMALL}, + {-16, -4, MARINE_HUD_FONT_MT_BIG}, + {-32, -4,MARINE_HUD_FONT_MT_BIG}, + + /* -ve values are relative to right side of the screen */ + /* marine health, units first */ + {60,20, MARINE_HUD_FONT_BLUE}, + {40,20, MARINE_HUD_FONT_BLUE}, + {20,20, MARINE_HUD_FONT_BLUE}, + + /* marine energy, units first */ + {60,55, MARINE_HUD_FONT_BLUE}, + {40,55, MARINE_HUD_FONT_BLUE}, + {20,55, MARINE_HUD_FONT_BLUE}, + + /* marine armour, units first */ + {60,90, MARINE_HUD_FONT_BLUE}, + {40,90, MARINE_HUD_FONT_BLUE}, + {20,90, MARINE_HUD_FONT_BLUE}, + + /* marine ammo/rounds, units first */ + {-44,20, MARINE_HUD_FONT_RED}, + {-64,20, MARINE_HUD_FONT_RED}, + {-84,20, MARINE_HUD_FONT_RED}, + + /* marine ammo/magazines, units first */ + {-122,20, MARINE_HUD_FONT_RED}, + {-142,20, MARINE_HUD_FONT_RED}, + + /* marine secondary ammo/rounds, units first */ + {-44,55, MARINE_HUD_FONT_RED}, + {-64,55, MARINE_HUD_FONT_RED}, + {-84,55, MARINE_HUD_FONT_RED}, + + /* marine secondary ammo/magazines, units first */ + {-122,55, MARINE_HUD_FONT_RED}, + {-142,55, MARINE_HUD_FONT_RED}, +}; +static char *HiresMarineHUDGfxFilenamePtr[]= +{ + {"blipsHRz.pg0"}, //MARINE_HUD_GFX_MOTIONTRACKERBLIP, + {"numhR.pg0"}, //MARINE_HUD_GFX_NUMERALS, + {"sightsmr.pg0"}, //MARINE_HUD_GFX_GUNSIGHTS, + {"trkfnthr.pg0"}, + {"blubarhr.pg0"}, +}; +static struct HUDFontDescTag HiresHUDFontDesc[] = +{ + //MARINE_HUD_FONT_BLUE, + { + 0,//XOffset + 27,//Height + 19,//Width + }, + //MARINE_HUD_FONT_RED, + { + 20,//XOffset + 27,//Height + 19,//Width + }, + //MARINE_HUD_FONT_MT_SMALL, + { + 18,//XOffset + 15,//Height + 8,//Width + }, + //MARINE_HUD_FONT_MT_BIG, + { + 0,//XOffset + 29,//Height + 17,//Width + }, +}; +static struct LittleMDescTag HiresHUDLittleM = +{ + 150,17, // source top,left + + 9,13, // width, height + + 14,14, // screen x,y +}; + + + + + + + + + + + + + + + + + + + + + +/* PREDATOR */ + + +static char *LoresPredatorHUDGfxFilenamePtr[]= +{ + {"topmask.pg0"}, //PREDATOR_HUD_GFX_TOP, + {"botmmask.pg0"}, //PREDATOR_HUD_GFX_BOTTOM, + {"prednum.pg0"}, //PREDATOR_HUD_GFX_NUMBERS, + {"predsymb.pg0"}, //PREDATOR_HUD_GFX_SYMBOLS, +}; +static char *MedresPredatorHUDGfxFilenamePtr[]= +{ + {"prhdtpMR.pg0"}, //PREDATOR_HUD_GFX_TOP, + {"prhdbmMR.pg0"}, //PREDATOR_HUD_GFX_BOTTOM, + {"prednum.pg0"}, //PREDATOR_HUD_GFX_NUMBERS, + {"predsymb.pg0"}, //PREDATOR_HUD_GFX_SYMBOLS, +}; +static struct DigitPropertiesTag LoresPredatorHUDDigitProperties[] = +{ + /* armour, units first */ + {63, 158, PREDATOR_HUD_GFX_NUMBERS}, + {72, 153, PREDATOR_HUD_GFX_NUMBERS}, + {81, 149, PREDATOR_HUD_GFX_NUMBERS}, + {90, 146, PREDATOR_HUD_GFX_NUMBERS}, + {99, 144, PREDATOR_HUD_GFX_NUMBERS}, + + /* health, units first */ + {249, 158, PREDATOR_HUD_GFX_NUMBERS}, + {240, 153, PREDATOR_HUD_GFX_NUMBERS}, + {231, 149, PREDATOR_HUD_GFX_NUMBERS}, + {222, 146, PREDATOR_HUD_GFX_NUMBERS}, + {213, 144, PREDATOR_HUD_GFX_NUMBERS}, + + /* threat display, units first */ + {90-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + {110-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + {130-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + {150-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + {170-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + {190-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + {210-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + {230-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + +}; +static struct DigitPropertiesTag MedresPredatorHUDDigitProperties[] = +{ + /* armour, units first */ + {63*2+8, 158*2+80, PREDATOR_HUD_GFX_NUMBERS}, + {72*2+8, 153*2+80, PREDATOR_HUD_GFX_NUMBERS}, + {81*2+8, 149*2+80, PREDATOR_HUD_GFX_NUMBERS}, + {90*2+8, 146*2+80, PREDATOR_HUD_GFX_NUMBERS}, + {99*2+8, 144*2+80, PREDATOR_HUD_GFX_NUMBERS}, + + /* health, units first */ + {249*2, 158*2+80, PREDATOR_HUD_GFX_NUMBERS}, + {240*2, 153*2+80, PREDATOR_HUD_GFX_NUMBERS}, + {231*2, 149*2+80, PREDATOR_HUD_GFX_NUMBERS}, + {222*2, 146*2+80, PREDATOR_HUD_GFX_NUMBERS}, + {213*2, 144*2+80, PREDATOR_HUD_GFX_NUMBERS}, + + /* threat display, units first */ + {90-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + {110-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + {130-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + {150-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + {170-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + {190-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + {210-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + {230-6, 180, PREDATOR_HUD_GFX_NUMBERS}, + +}; + + +/* ALIEN */ +static char *LoresAlienHUDGfxFilenamePtr[]= +{ + {"AlHudBot.pg0"}, // ALIEN_HUD_GFX_BOTTOM + {"AlHudLft.pg0"}, // ALIEN_HUD_GFX_LEFT + {"AlHudRgt.pg0"}, // ALIEN_HUD_GFX_RIGHT + {"AlHudTop.pg0"}, // ALIEN_HUD_GFX_TOP + {"AlienNum.pg0"}, // ALIEN_HUD_GFX_NUMBERS +}; +static char *MedresAlienHUDGfxFilenamePtr[]= +{ + {"ahMRBtm.pg0"}, // ALIEN_HUD_GFX_BOTTOM + {"ahMRLft.pg0"}, // ALIEN_HUD_GFX_LEFT + {"ahMRRgt.pg0"}, // ALIEN_HUD_GFX_RIGHT + {"ahMRTop.pg0"}, // ALIEN_HUD_GFX_TOP + {"ahMRNum.pg0"}, // ALIEN_HUD_GFX_NUMBERS +}; +static struct DigitPropertiesTag LoresAlienHUDDigitProperties[] = +{ + /* health, units first */ + {288, 157, ALIEN_HUD_GFX_NUMBERS}, + {281, 157, ALIEN_HUD_GFX_NUMBERS}, + {274, 157, ALIEN_HUD_GFX_NUMBERS}, +}; + +static struct DigitPropertiesTag MedresAlienHUDDigitProperties[] = +{ + /* health, units first */ + {288*2, 157*2+80, ALIEN_HUD_GFX_NUMBERS}, + {281*2, 157*2+80, ALIEN_HUD_GFX_NUMBERS}, + {274*2, 157*2+80, ALIEN_HUD_GFX_NUMBERS}, +}; diff --git a/3dc/avp/win95/HUD_layout.h b/3dc/avp/win95/HUD_layout.h new file mode 100644 index 0000000..0e645b8 --- /dev/null +++ b/3dc/avp/win95/HUD_layout.h @@ -0,0 +1,33 @@ +/* KJL 17:58:47 18/04/98 - layout defines */ + +#define HUD_FONT_WIDTH 15 +//5 +#define HUD_FONT_HEIGHT 15 +//8 +#define HUD_DIGITAL_NUMBERS_WIDTH 14 +#define HUD_DIGITAL_NUMBERS_HEIGHT 22 + +#define HUDLayout_RightmostTextCentre -40 + +#define HUDLayout_Health_TopY 10 +#define HUDLayout_Armour_TopY 60 + +/* KJL 15:28:12 09/06/98 - the following are pixels from the bottom of the screen */ +#define HUDLayout_Rounds_TopY 40 +#define HUDLayout_Magazines_TopY 90 +#define HUDLayout_AmmoDesc_TopY 115 + + +#define HUDLayout_Colour_BrightWhite 0xffffffff +#define HUDLayout_Colour_MarineGreen ((255<<24)+(95<<16)+(179<<8)+(39)) +#define HUDLayout_Colour_MarineRed ((255<<24)+(255<<16)) +#define HUDLayout_Linespacing 16 + +#ifdef __cplusplus +extern "C" +{ +#endif +extern char AAFontWidths[]; +#ifdef __cplusplus +}; +#endif diff --git a/3dc/avp/win95/Ia3d.h b/3dc/avp/win95/Ia3d.h new file mode 100644 index 0000000..15d8be3 --- /dev/null +++ b/3dc/avp/win95/Ia3d.h @@ -0,0 +1,249 @@ +/*--------------------------------------------------------------------- + * + * ia3d.h + * + *--------------------------------------------------------------------- + * + * $Id: ia3d.h%v 1.1 1996/09/02 10:50:35 mike Exp mike $ + * + *--------------------------------------------------------------------- + * + * ia3d header file. It's the part the outside world needs to see. + * + *--------------------------------------------------------------------- + * + * AUREAL SEMICONDUCTOR, INC. PROPRIETARY AND CONFIDENTIAL + * Copyright (c) 1996 Aureal Semiconductor, Inc. - All rights + * reserved. + * + *--------------------------------------------------------------------- + */ + + +#ifndef _IA3D_H_ +#define _IA3D_H_ + +#ifdef __cplusplus +extern "C" { +#endif + + +// A3d Class ID! {D8F1EEE0-F634-11cf-8700-00A0245D918B} +DEFINE_GUID(CLSID_A3d, +0xd8f1eee0, 0xf634, 0x11cf, 0x87, 0x0, 0x0, 0xa0, 0x24, 0x5d, 0x91, 0x8b); + +// A3d Interface ID! {D8F1EEE1-F634-11cf-8700-00A0245D918B} +DEFINE_GUID(IID_IA3d, +0xd8f1eee1, 0xf634, 0x11cf, 0x87, 0x0, 0x0, 0xa0, 0x24, 0x5d, 0x91, 0x8b); + +// GUID generated from UUGENID.EXE, Good until the year 3400 AD +// A3d Interface ID! {fb80d1e0-98d3-11d1-90fb-006008a1f441} +DEFINE_GUID(IID_IA3d2, +0xfb80d1e0, 0x98d3, 0x11d1, 0x90, 0xfb, 0x00, 0x60, 0x08, 0xa1, 0xf4, 0x41); + +// Bits for manipulating output modes + +// Values for bOutputMode +#define OUTPUT_MODE_STEREO 0x00000001 +#define OUTPUT_MODE_QUAD 0x00000002 + +// Values for FrontXtalkMode and bRearXtalkMode +#define OUTPUT_HEADPHONES 0x00000001 // headphones +#define OUTPUT_SPEAKERS_WIDE 0x00000002 +#define OUTPUT_SPEAKERS_NARROW 0x00000003 + +// Values for Resource Management Mode +#define A3D_RESOURCE_MODE_OFF 0x00000000 +#define A3D_RESOURCE_MODE_NOTIFY 0x00000001 +#define A3D_RESOURCE_MODE_DYNAMIC 0x00000002 +#define A3D_RESOURCE_MODE_DYNAMIC_LOOPERS 0x00000003 +#define A3D_RESOURCE_MODE_LAST 0x00000003 + + +// Version Definitions for A3DCAPS + +#define A3D_CURRENT_VERSION IA3DVERSION_RELEASE12 + +#define IA3DVERSION_RELEASE10 10 +#define IA3DVERSION_RELEASE12 12 + +// A3d Caps structure for A3d2 interface +// If Fail to get IA3d2 interface, version of DLL is IA3DVERSION_PRE12 + +typedef struct __A3DCAPS_SOFTWARE +{ + DWORD dwSize; // Use for internal version control + DWORD dwVersion; // For Backwards capablities purposes + DWORD dwFlags; + DWORD dwReserved; + DWORD dwReserved2; +} A3DCAPS_SOFTWARE, *LPA3DCAPS_SOFTWARE; + +typedef struct __A3DCAPS_HARDWARE +{ + DWORD dwSize; // Use for internal version control + DWORD dwFlags; + DWORD dwReserved; + DWORD dwReserved2; +} A3DCAPS_HARDWARE, *LPA3DCAPS_HARDWARE; + + +// Declare the IA3d Interface. It's not very complex at all. + +#undef INTERFACE +#define INTERFACE IA3d + +typedef struct IA3d *LPIA3D; + +DECLARE_INTERFACE_(IA3d, IUnknown) +{ + // IUnknown + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IA3d + STDMETHOD(SetOutputMode)(THIS_ DWORD dwFrontXtalkMode, DWORD dwBackXtalkMode, DWORD dwQuadMode) PURE; + STDMETHOD(GetOutputMode)(THIS_ DWORD *lpdwFrontXtalkMode, DWORD *lpdwBackXtalkMode, DWORD *lpdwQuadMode) PURE; + + STDMETHOD(SetResourceManagerMode) (THIS_ DWORD ) PURE; + STDMETHOD(GetResourceManagerMode) (THIS_ DWORD *) PURE; + + STDMETHOD(SetHFAbsorbFactor)(THIS_ FLOAT ) PURE; + STDMETHOD(GetHFAbsorbFactor)(THIS_ FLOAT *) PURE; + +}; + + +// IA3d2 interface derived from IA3d + +#undef INTERFACE +#define INTERFACE IA3d2 + +typedef struct IA3d2 *LPIA3D2; + +DECLARE_INTERFACE_(IA3d2, IUnknown) +{ + // IUnknown + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IA3d + STDMETHOD(SetOutputMode)(THIS_ DWORD dwFrontXtalkMode, DWORD dwBackXtalkMode, DWORD dwQuadMode) PURE; + STDMETHOD(GetOutputMode)(THIS_ DWORD *lpdwFrontXtalkMode, DWORD *lpdwBackXtalkMode, DWORD *lpdwQuadMode) PURE; + + STDMETHOD(SetResourceManagerMode) (THIS_ DWORD ) PURE; + STDMETHOD(GetResourceManagerMode) (THIS_ DWORD *) PURE; + + STDMETHOD(SetHFAbsorbFactor)(THIS_ FLOAT ) PURE; + STDMETHOD(GetHFAbsorbFactor)(THIS_ FLOAT *) PURE; + + // New Methods inaddition to old ones + STDMETHOD(RegisterVersion) (THIS_ DWORD dwVersionNr) PURE; + STDMETHOD(GetSoftwareCaps) (THIS_ LPA3DCAPS_SOFTWARE lpCaps) PURE; + STDMETHOD(GetHardwareCaps) (THIS_ LPA3DCAPS_HARDWARE lpCaps) PURE; +}; + + +// The library function that gets things going. It returns an interface +// pointer to DirectSound. + +#define A3D_OK 1 // A3dCreate returns this upon detection of A3D Dll. +#define A3D_OK_OLD_DLL 2 // A3dCreate returns this upon detection of A3D Dll but user's version is older than expected. + +// Usefull Macros for C folks. + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IA3d_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IA3d_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IA3d_Release(p) (p)->lpVtbl->Release(p) +#define IA3d_SetOutputMode(p,a,b,c) (p)->lpVtbl->SetOutputMode(p,a,b,c) +#define IA3d_GetOutputMode(p,a,b,c) (p)->lpVtbl->GetOutputMode(p,a,b,c) +#define IA3d_SetResourceManagerMode(p,a) (p)->lpVtbl->SetResourceManagerMode(p,a) +#define IA3d_GetResourceManagerMode(p,a) (p)->lpVtbl->GetResourceManagerMode(p,a) +#define IA3d_SetHFAbsorbFactor(p,a) (p)->lpVtbl->SetHFAbsorbFactor(p,a) +#define IA3d_GetHFAbsorbFactor(p,a) (p)->lpVtbl->GetHFAbsorbFactor(p,a) + +// C function def +#define IA3d2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IA3d2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IA3d2_Release(p) (p)->lpVtbl->Release(p) +#define IA3d2_SetOutputMode(p,a,b,c) (p)->lpVtbl->SetOutputMode(p,a,b,c) +#define IA3d2_GetOutputMode(p,a,b,c) (p)->lpVtbl->GetOutputMode(p,a,b,c) +#define IA3d2_SetResourceManagerMode(p,a) (p)->lpVtbl->SetResourceManagerMode(p,a) +#define IA3d2_GetResourceManagerMode(p,a) (p)->lpVtbl->GetResourceManagerMode(p,a) +#define IA3d2_SetHFAbsorbFactor(p,a) (p)->lpVtbl->SetHFAbsorbFactor(p,a) +#define IA3d2_GetHFAbsorbFactor(p,a) (p)->lpVtbl->GetHFAbsorbFactor(p,a) +#define IA3d2_RegisterVersion(p,a) (p)->lpVtbl->RegisterVersion(p,a) +#define IA3d2_GetSoftwareCaps(p,a) (p)->lpVtbl->GetSoftwareCaps(p,a) +#define IA3d2_GetHardwareCaps(p,a) (p)->lpVtbl->GetHardwareCaps(p,a) + +#else +#define IA3d_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IA3d_AddRef(p) (p)->AddRef() +#define IA3d_Release(p) (p)->Release() +#define IA3d_SetOutputMode(p,a,b,c) (p)->SetOutputMode(a,b,c) +#define IA3d_GetOutputMode(p,a,b,c) (p)->GetOutputMode(a,b,c) +#define IA3d_SetResourceManagerMode(p,a) (p)->SetResourceManagerMode(a) +#define IA3d_GetResourceManagerMode(p,a) (p)->GetResourceManagerMode(a) +#define IA3d_SetHFAbsorbFactor(p,a) (p)->SetHFAbsorbFactor(a) +#define IA3d_GetHFAbsorbFactor(p,a) (p)->GetHFAbsorbFactor(a) + +// C++ function def +#define IA3d2_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IA3d2_AddRef(p) (p)->AddRef() +#define IA3d2_Release(p) (p)->Release() +#define IA3d2_SetOutputMode(p,a,b,c) (p)->SetOutputMode(a,b,c) +#define IA3d2_GetOutputMode(p,a,b,c) (p)->GetOutputMode(a,b,c) +#define IA3d2_SetResourceManagerMode(p,a) (p)->SetResourceManagerMode(a) +#define IA3d2_GetResourceManagerMode(p,a) (p)->GetResourceManagerMode(a) +#define IA3d2_SetHFAbsorbFactor(p,a) (p)->SetHFAbsorbFactor(a) +#define IA3d2_GetHFAbsorbFactor(p,a) (p)->GetHFAbsorbFactor(a) +#define IA3d2_RegisterVersion(p,a) (p)->RegisterVersion(a) +#define IA3d2_GetSoftwareCaps(p,a) (p)->GetSoftwareCaps(a) +#define IA3d2_GetHardwareCaps(p,a) (p)->GetHardwareCaps(a) + +#endif + +// Convenience Macro A3D_REGISTER_VERSION() +// Register version for backwards compatibility +// Pass in any COM object from CLSID_A3d + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define A3D_UNKNOWN_QI(pU,I,ppI) (SUCCEEDED((pU)->lpVtbl->QueryInterface(pU,&I,ppI))) +#else +#define A3D_UNKNOWN_QI(pU,I,ppI) (SUCCEEDED((pU)->QueryInterface(I,ppI))) +#endif + +#define A3D_REGISTER_VERSION(p) \ +{ \ + LPIA3D2 __pIA3d2__=NULL; \ + IUnknown *__pU__ = (IUnknown *)p; \ + \ + if (p) \ + { \ + if (A3D_UNKNOWN_QI(__pU__,IID_IA3d2,(void **)&__pIA3d2__))\ + { \ + IA3d2_RegisterVersion(__pIA3d2__,A3D_CURRENT_VERSION); \ + IA3d2_Release(__pIA3d2__); \ + } \ + } \ + \ +} + +// Helper functions in ia3d.lib + +extern HRESULT WINAPI A3dInitialize(void); + +extern void WINAPI A3dUninitialize(void); + +extern HRESULT WINAPI A3dCreate(GUID * lpGUID, /* in, Prefered Driver Guid, NULL ok */ + void **ppDS, /* out, Direct Sound pointer */ + IUnknown FAR *pUnkOuter); /* in, Outer COM object, for Aggregate only NULL oK */ + +#ifdef __cplusplus +}; +#endif + +#endif // _IA3D_H_ diff --git a/3dc/avp/win95/KZSORT.C b/3dc/avp/win95/KZSORT.C new file mode 100644 index 0000000..5005c60 --- /dev/null +++ b/3dc/avp/win95/KZSORT.C @@ -0,0 +1,1188 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" + +#include "stratdef.h" +#include "gamedef.h" + +#include "kzsort.h" +#include "kshape.h" + +#include "d3d_render.h" +#define UseLocalAssert Yes +#include "ourasert.h" +#include "avp_userprofile.h" + +#define PENTIUM_PROFILING_ON 0 +#if PENTIUM_PROFILING_ON +#include "pentime.h" +#else +#define ProfileStart(); +#define ProfileStop(x); +#endif +#define MultipleExecuteBuffers Yes + +extern int *ItemPointers[maxpolyptrs]; +extern int ItemCount; + +extern int ScanDrawMode; +extern int ZBufferMode; +extern int NumVertices; +extern int WireFrameMode; +extern int DrawingAReflection; + +struct KItem KItemList[maxpolyptrs]={0,}; +static struct KItem KItemList2[maxpolyptrs]={0,}; + +static struct KObject VisibleModules[MAX_NUMBER_OF_VISIBLE_MODULES]={0,}; +static struct KObject VisibleModules2[MAX_NUMBER_OF_VISIBLE_MODULES]={0,}; +static struct KObject *SortedModules; +static struct KObject VisibleObjects[maxobjects]={0,}; + + +/*KJL***************************** +* externs for new shape function * +*****************************KJL*/ +int *MorphedObjectPointsPtr=0; + +static void MergeItems(struct KItem *src1, int n1, struct KItem *src2, int n2, struct KItem *dest) +{ + /* merge the 2 sorted lists: at src1, length n1, and at src2, length n2, into dest */ + + while (n1>0 && n2>0) /* until one list is exhausted */ + { + if (src1->SortKey < src2->SortKey) + { + /* src1 is nearer */ + *dest++ = *src1++; + n1--; + } + else + { + /* src2 is nearer */ + *dest++ = *src2++; + n2--; + } + } + + if (n1==0) + { + /* remainder in srce2 goes into dest */ + while (n2>0) + { + *dest++ = *src2++; + n2--; + } + } + else + { + /* remainder in srce1 goes into dest */ + while (n1>0) + { + *dest++ = *src1++; + n1--; + } + } +} + +static void MergeObjects(struct KObject *src1, int n1, struct KObject *src2, int n2, struct KObject *dest) +{ + /* merge the 2 sorted lists: at src1, length n1, and at src2, length n2, into dest */ + + while (n1>0 && n2>0) /* until one list is exhausted */ + { + if (src1->SortKey < src2->SortKey) + { + /* src1 is nearer */ + *dest++ = *src1++; + n1--; + } + else + { + /* src2 is nearer */ + *dest++ = *src2++; + n2--; + } + } + + if (n1==0) + { + /* remainder in srce2 goes into dest */ + while (n2>0) + { + *dest++ = *src2++; + n2--; + } + } + else + { + /* remainder in srce1 goes into dest */ + while (n1>0) + { + *dest++ = *src1++; + n1--; + } + } +} +#if 0 +static void ZSortItems(void) +{ + unsigned int partitionSize; + unsigned int noOfPasses = 0; + unsigned int noOfItems = ItemCount; + struct KItem *mergeFrom = &KItemList[0]; + struct KItem *mergeTo = &KItemList2[0]; + struct KItem *mergeTemp; + unsigned int offSet; + + for (partitionSize=1;partitionSizeObMyModule; + + /* if it's a module, which isn't inside another module */ + if (modulePtr && !(modulePtr->m_flags & m_flag_slipped_inside)) + { + #if 1 + if(PointIsInModule(&(VDBPtr->VDB_World),modulePtr)) + { + VisibleModules[numVisMods].DispPtr = objectPtr; + VisibleModules[numVisMods].SortKey = smallint; +// textprint("fog is %d in player's module\n",modulePtr->m_flags & MODULEFLAG_FOG); + } + #else + // these tests should really be done using the camera (VDB) position + extern MODULE *playerPherModule; + if (playerPherModule == modulePtr) + { + VisibleModules[numVisMods].DispPtr = objectPtr; + VisibleModules[numVisMods].SortKey = smallint; + } + #endif + else + { + VECTORCH position; + VECTORCH dist; + + position.vx = modulePtr->m_world.vx - Player->ObWorld.vx; + position.vy = modulePtr->m_world.vy - Player->ObWorld.vy; + position.vz = modulePtr->m_world.vz - Player->ObWorld.vz; + + { + int minX = modulePtr->m_minx + position.vx; + int maxX = modulePtr->m_maxx + position.vx; + + if (maxX<0) /* outside maxX side */ + { + dist.vx = maxX; + } + else if (minX>0) /* outside minX faces */ + { + dist.vx = minX; + } + else /* between faces */ + { + dist.vx = 0; + } + } + { + int minY = modulePtr->m_miny + position.vy; + int maxY = modulePtr->m_maxy + position.vy; + + if (maxY<0) /* outside maxY side */ + { + dist.vy = maxY; + } + else if (minY>0) /* outside minY faces */ + { + dist.vy = minY; + } + else /* between faces */ + { + dist.vy = 0; + } + } + { + int minZ = modulePtr->m_minz + position.vz; + int maxZ = modulePtr->m_maxz + position.vz; + + if (maxZ<0) /* outside maxZ side */ + { + dist.vz = maxZ; + } + else if (minZ>0) /* outside minZ faces */ + { + dist.vz = minZ; + } + else /* between faces */ + { + dist.vz = 0; + } + } + + VisibleModules[numVisMods].DispPtr = objectPtr; + #if 1 + VisibleModules[numVisMods].SortKey = Magnitude(&dist); + #else + VisibleModules[numVisMods].SortKey = MUL_FIXED(dist.vx,dist.vx) + + MUL_FIXED(dist.vy,dist.vy) + + MUL_FIXED(dist.vz,dist.vz); + #endif + } + + if(numVisMods>MAX_NUMBER_OF_VISIBLE_MODULES) + { + /* outside the environment! */ + textprint("MAX_NUMBER_OF_VISIBLE_MODULES (%d) exceeded!\n",MAX_NUMBER_OF_VISIBLE_MODULES); + textprint("Possibly outside the environment!\n"); +// LOCALASSERT(0); + return; + } + + numVisMods++; + } + else /* it's just an object */ + { + VisibleObjects[numVisObjs].DispPtr = objectPtr; + /* this sort key defaults to the object not being drawn, ie. a grenade + behind a closed door (so there is no module behind door) would still be + in the OnScreenBlockList but need not be drawn. */ + VisibleObjects[numVisObjs].SortKey = 0X7FFFFFFF; + numVisObjs++; + } + } + ProfileStop("SORTSETUP"); + textprint("numvismods %d\n",numVisMods); + textprint("numvisobjs %d\n",numVisObjs); + + ProfileStart(); + #if 1 + { + int numMods = numVisMods; + + while(numMods) + { + int n = numMods; + + int furthestModule=0; + int furthestDistance=0; + + while(n) + { + n--; + if (furthestDistance < VisibleModules[n].SortKey) + { + furthestDistance = VisibleModules[n].SortKey; + furthestModule = n; + } + } + + numMods--; + + VisibleModules2[numMods] = VisibleModules[furthestModule]; + VisibleModules[furthestModule] = VisibleModules[numMods]; + SortedModules = VisibleModules2; + } + } + #else + SortModules(numVisMods); + #endif + ProfileStop("MODULESORT"); + + ProfileStart(); + { + int fogDistance = 0x7f000000; + + int o = numVisObjs; + while(o--) + { + DISPLAYBLOCK *objectPtr = VisibleObjects[o].DispPtr; + int maxX = objectPtr->ObWorld.vx + objectPtr->ObRadius; + int minX = objectPtr->ObWorld.vx - objectPtr->ObRadius; + int maxZ = objectPtr->ObWorld.vz + objectPtr->ObRadius; + int minZ = objectPtr->ObWorld.vz - objectPtr->ObRadius; + int maxY = objectPtr->ObWorld.vy + objectPtr->ObRadius; + int minY = objectPtr->ObWorld.vy - objectPtr->ObRadius; + + int numMods = 0; + while(numModsObMyModule; + + if (maxX >= modulePtr->m_minx+modulePtr->m_world.vx) + if (minX <= modulePtr->m_maxx+modulePtr->m_world.vx) + if (maxZ >= modulePtr->m_minz+modulePtr->m_world.vz) + if (minZ <= modulePtr->m_maxz+modulePtr->m_world.vz) + if (maxY >= modulePtr->m_miny+modulePtr->m_world.vy) + if (minY <= modulePtr->m_maxy+modulePtr->m_world.vy) + { + VisibleObjects[o].SortKey=numMods; + break; + } + numMods++; + } + #if 0 + /* find nearest module which is fogged */ + if(modulePtr->m_flags & MODULEFLAG_FOG) + { + if (fogDistance>SortedModules[numMods].SortKey) + fogDistance = SortedModules[numMods].SortKey; + } + #endif + if (CurrentVisionMode == VISION_MODE_PRED_SEEALIENS && objectPtr->ObStrategyBlock) + { + if (objectPtr->ObStrategyBlock->I_SBtype == I_BehaviourAlien) + VisibleObjects[o].DrawBeforeEnvironment = 0;//1; + } + else + { + VisibleObjects[o].DrawBeforeEnvironment = 0; + } + } + + if (fogDistance<0) fogDistance=0; + SetFogDistance(fogDistance); + } + ProfileStop("OBJS IN MOD TESTS"); + DrawingAReflection=0; + { + int numMods = numVisMods; + #if 1 + { + int o = numVisObjs; + CheckWireFrameMode(WireFrameMode&2); + while(o) + { + o--; + + if(VisibleObjects[o].DrawBeforeEnvironment) + { + DISPLAYBLOCK *dptr = VisibleObjects[o].DispPtr; + AddShape(VisibleObjects[o].DispPtr,VDBPtr); + #if MIRRORING_ON + if (MirroringActive && !dptr->HModelControlBlock) + { + ReflectObject(dptr); + + MakeVector(&dptr->ObWorld, &VDBPtr->VDB_World, &dptr->ObView); + RotateVector(&dptr->ObView, &VDBPtr->VDB_Mat); + + DrawingAReflection=1; + AddShape(dptr,VDBPtr); + DrawingAReflection=0; + ReflectObject(dptr); + } + #endif + } + } + } + + ClearTranslucentPolyList(); + + if (MOTIONBLUR_CHEATMODE) + { + for (numMods=0; numModsObMyModule; + + CheckWireFrameMode(WireFrameMode&1); + AddShape(SortedModules[numMods].DispPtr,VDBPtr); + #if MIRRORING_ON + if (MirroringActive) + { + DISPLAYBLOCK *dptr = SortedModules[numMods].DispPtr; + { + ReflectObject(dptr); + + MakeVector(&dptr->ObWorld, &VDBPtr->VDB_World, &dptr->ObView); + RotateVector(&dptr->ObView, &VDBPtr->VDB_Mat); + + DrawingAReflection=1; + AddShape(dptr,VDBPtr); + DrawingAReflection=0; + ReflectObject(dptr); + } + } + #endif + CheckWireFrameMode(WireFrameMode&2); + { + int o = numVisObjs; + while(o) + { + o--; + + if(VisibleObjects[o].SortKey == numMods && !VisibleObjects[o].DrawBeforeEnvironment) + { + DISPLAYBLOCK *dptr = VisibleObjects[o].DispPtr; + AddShape(VisibleObjects[o].DispPtr,VDBPtr); + #if MIRRORING_ON + if (MirroringActive && !dptr->HModelControlBlock) + { + ReflectObject(dptr); + + MakeVector(&dptr->ObWorld, &VDBPtr->VDB_World, &dptr->ObView); + RotateVector(&dptr->ObView, &VDBPtr->VDB_Mat); + + DrawingAReflection=1; + AddShape(dptr,VDBPtr); + DrawingAReflection=0; + ReflectObject(dptr); + } + #endif + } + } + } + + + { + D3D_DrawWaterTest(modulePtr); + } + } + } + else + { + while(numMods--) + { + MODULE *modulePtr = SortedModules[numMods].DispPtr->ObMyModule; + + CheckWireFrameMode(WireFrameMode&1); + AddShape(SortedModules[numMods].DispPtr,VDBPtr); + #if MIRRORING_ON + if (MirroringActive) + { + DISPLAYBLOCK *dptr = SortedModules[numMods].DispPtr; + { + ReflectObject(dptr); + + MakeVector(&dptr->ObWorld, &VDBPtr->VDB_World, &dptr->ObView); + RotateVector(&dptr->ObView, &VDBPtr->VDB_Mat); + + DrawingAReflection=1; + AddShape(dptr,VDBPtr); + DrawingAReflection=0; + ReflectObject(dptr); + } + } + #endif + CheckWireFrameMode(WireFrameMode&2); + { + int o = numVisObjs; + while(o) + { + o--; + + if(VisibleObjects[o].SortKey == numMods && !VisibleObjects[o].DrawBeforeEnvironment) + { + DISPLAYBLOCK *dptr = VisibleObjects[o].DispPtr; + AddShape(VisibleObjects[o].DispPtr,VDBPtr); + #if MIRRORING_ON + if (MirroringActive && !dptr->HModelControlBlock) + { + ReflectObject(dptr); + + MakeVector(&dptr->ObWorld, &VDBPtr->VDB_World, &dptr->ObView); + RotateVector(&dptr->ObView, &VDBPtr->VDB_Mat); + + DrawingAReflection=1; + AddShape(dptr,VDBPtr); + DrawingAReflection=0; + ReflectObject(dptr); + } + #endif + } + } + } + + + { + D3D_DrawWaterTest(modulePtr); + } + } + } +// OutputTranslucentPolyList(); + #endif + #if 0 + { + int numMods = numVisMods; + while(numMods--) + AddShape(SortedModules[numMods].DispPtr,VDBPtr); + } + #endif + /* KJL 12:51:00 13/08/98 - scan for hierarchical objects which aren't going to be drawn, + and update their timers */ + { + int o = numVisObjs; + while(o) + { + o--; + + if(VisibleObjects[o].SortKey == 0x7fffffff) + { + if(VisibleObjects[o].DispPtr->HModelControlBlock) + { + DoHModelTimer(VisibleObjects[o].DispPtr->HModelControlBlock); + } + } + } + } + + #if MIRRORING_ON + if (MirroringActive) + { + DrawingAReflection=1; + RenderPlayersImageInMirror(); + DrawingAReflection=0; + } + + #endif + + #if 0//SupportWindows95 + if (ScanDrawMode != ScanDrawDirectDraw) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + EndD3DScene(); + } + #endif + + if (ScanDrawMode == ScanDrawDirectDraw) + { + UnlockSurface(); + } + + } +} + +static int ObjectIsInModule(DISPLAYBLOCK *objectPtr,MODULE *modulePtr) +{ + int objectSize = objectPtr->ObRadius; + VECTORCH position = objectPtr->ObWorld; + + position.vx -= modulePtr->m_world.vx; + position.vy -= modulePtr->m_world.vy; + position.vz -= modulePtr->m_world.vz; + + if (position.vx + objectSize >= modulePtr->m_minx) + if (position.vx - objectSize <= modulePtr->m_maxx) + if (position.vz + objectSize >= modulePtr->m_minz) + if (position.vz - objectSize <= modulePtr->m_maxz) + if (position.vy + objectSize >= modulePtr->m_miny) + if (position.vy - objectSize <= modulePtr->m_maxy) + return 1; + + return 0; + +} +static int PointIsInModule(VECTORCH *pointPtr,MODULE *modulePtr) +{ + VECTORCH position = *pointPtr; + position.vx -= modulePtr->m_world.vx; + position.vy -= modulePtr->m_world.vy; + position.vz -= modulePtr->m_world.vz; + + if (position.vx >= modulePtr->m_minx) + if (position.vx <= modulePtr->m_maxx) + if (position.vz >= modulePtr->m_minz) + if (position.vz <= modulePtr->m_maxz) + if (position.vy >= modulePtr->m_miny) + if (position.vy <= modulePtr->m_maxy) + return 1; + return 0; + +} + + + +void RenderThisDisplayblock(DISPLAYBLOCK *dbPtr) +{ + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + + AddShape(dbPtr,VDBPtr); +} + +void RenderThisHierarchicalDisplayblock(DISPLAYBLOCK *dbPtr) +{ + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + + AddHierarchicalShape(dbPtr,VDBPtr); + #if MIRRORING_ON + if (MirroringActive && dbPtr->ObStrategyBlock) + { + ReflectObject(dbPtr); + + MakeVector(&dbPtr->ObWorld, &VDBPtr->VDB_World, &dbPtr->ObView); + RotateVector(&dbPtr->ObView, &VDBPtr->VDB_Mat); + + AddHierarchicalShape(dbPtr,VDBPtr); + ReflectObject(dbPtr); + } + #endif +} + + + + + +/* KJL 10:33:03 7/9/97 - this code no longer used */ + +#if 0 +void OutputKItem(int *shapeitemptr) +{ + /* Allocate space in the Item Data array */ + if (IPtsArrSize) + { + int *itemDataPtr = AllocateItemData(IHdrSize + IPtsArrSize + ITrmSize); + + if(itemDataPtr) + { + POLYHEADER *mypolyheader = (POLYHEADER*) itemDataPtr; + struct KItem * const currentItemPtr = &KItemList[ItemCount]; + + currentItemPtr->PolyPtr = mypolyheader; + + { + POLYHEADER* polyheader = (POLYHEADER *)shapeitemptr; + int *offsetPtr = (int*) &polyheader->Poly1stPt; + + int maxZ = smallint; + int minZ = bigint; + + if (MorphedObjectPointsPtr) + { + while(*offsetPtr != Term) + { + VECTORCH v = *(VECTORCH*)((int *)MorphedObjectPointsPtr + *offsetPtr); + int z; + + z = MUL_FIXED(LToVMat.mat13, v.vx); + z += MUL_FIXED(LToVMat.mat23, v.vy); + z += MUL_FIXED(LToVMat.mat33, v.vz); + z += Global_ODB_Ptr->ObView.vz; + + if(z > maxZ) maxZ = z; + else if(z < minZ) minZ = z; + + offsetPtr++; + } + } + else + { + while(*offsetPtr != Term) + { + int z = *((int *)RotatedPts + *offsetPtr + iz); + + if(z > maxZ) maxZ = z; + else if(z < minZ) minZ = z; + + offsetPtr++; + } + } + + if (polyheader->PolyFlags & iflag_sortnearz) currentItemPtr->SortKey = minZ; + else if (polyheader->PolyFlags & iflag_sortfarz) currentItemPtr->SortKey = maxZ +10; + else currentItemPtr->SortKey = maxZ; + } + + ItemCount++; + + /* Write out the Item Header */ + + mypolyheader->PolyItemType = *shapeitemptr++; + mypolyheader->PolyNormalIndex = *shapeitemptr++; + mypolyheader->PolyFlags = *shapeitemptr++; + mypolyheader->PolyColour = ItemColour; + + /* Write out the Item Points Array */ + { + int *ptsArrayPtr = &PointsArray[0]; + int i = IPtsArrSize; + + itemDataPtr = &mypolyheader->Poly1stPt; + + do + { + *itemDataPtr++ = *ptsArrayPtr++; + } + while(--i); + } + + /* Write out the Item Terminator */ + *itemDataPtr = Term; + } + } +} + +void KShapeItemsInstr(SHAPEINSTR *shapeinstrptr) +{ + int numitems= shapeinstrptr->sh_numitems; + int **shapeitemarrayptr = shapeinstrptr->sh_instr_data; + + while(numitems) + { + int clip_output; + int *shapeitemptr = *shapeitemarrayptr; + POLYHEADER *pheaderPtr = (POLYHEADER*) shapeitemptr; + + GLOBALASSERT(*shapeitemptr < I_Last); + + + if((Global_ODB_Ptr->ObFlags & ObFlag_BFCRO) + ||(Global_ODB_Ptr->ObFlags & ObFlag_ParrallelBFC)) + { + if((pheaderPtr->PolyFlags & iflag_viewdotpos) == 0) + { + ItemOCSBlock.ocs_flags |= ocs_flag_outcoded; + } + else + { + ItemOCSBlock.ocs_flags = ocs_flag_nobfc; + OutcodeItem[*shapeitemptr](shapeitemptr, &ItemOCSBlock); + } + } + else + { + ItemOCSBlock.ocs_flags = 0; + OutcodeItem[*shapeitemptr](shapeitemptr, &ItemOCSBlock); + } + + + if((ItemOCSBlock.ocs_flags & ocs_flag_outcoded) == 0) + { + #if support3dtextures + if((pheaderPtr->PolyFlags & iflag_tx2dor3d) + && pheaderPtr->PolyItemType == I_2dTexturedPolygon) + pheaderPtr->PolyItemType = I_3dTexturedPolygon; + #if SupportZBuffering + if((pheaderPtr->PolyFlags & iflag_tx2dor3d) + && pheaderPtr->PolyItemType == I_ZB_2dTexturedPolygon) + pheaderPtr->PolyItemType = I_ZB_3dTexturedPolygon; + #endif + #endif + + #if SupportGouraud3dTextures + if((pheaderPtr->PolyFlags & iflag_tx2dor3d) + && pheaderPtr->PolyItemType == I_Gouraud2dTexturedPolygon) + pheaderPtr->PolyItemType = I_Gouraud3dTexturedPolygon; + #if SupportZBuffering + if((pheaderPtr->PolyFlags & iflag_tx2dor3d) + && pheaderPtr->PolyItemType == I_ZB_Gouraud2dTexturedPolygon) + pheaderPtr->PolyItemType = I_ZB_Gouraud3dTexturedPolygon; + #endif + #endif + + /* KJL 14:08:52 04/26/97 - hack to draw everything as a certain poly type */ + #if 0 + pheaderPtr->PolyItemType = I_2dTexturedPolygon; + #endif + + /* KJL 17:15:46 06/07/97 - I'm not sure that we need 3dTexturedPolys */ + if(pheaderPtr->PolyItemType == I_3dTexturedPolygon) + pheaderPtr->PolyItemType = I_2dTexturedPolygon; + + /* KJL 12:57:43 05/29/97 - E3DEMO hack to draw everything in 3d */ + #if PC_E3DEMO + pheaderPtr->PolyFlags &= ~iflag_tx2dor3d; + if(pheaderPtr->PolyItemType == I_Gouraud2dTexturedPolygon) + pheaderPtr->PolyItemType = I_Gouraud3dTexturedPolygon; + #endif + + + if(ItemOCSBlock.ocs_clipstate == ocs_cs_totally_on) + { + CreateItemPtsArray[*shapeitemptr](shapeitemptr, &PointsArray[0]); + + if(Global_ShapeNormals) + ItemColour = ItemLightingModel[*shapeitemptr](shapeitemptr); + else + ItemColour = pheaderPtr->PolyColour; + + OutputKItem(shapeitemptr); + } + else + { + #if 0 + /* Because in d3d polygons are rendered as triangles + the splits made to turn n-gons into triangles must + be invariant with the clipping performed on the poly, + otherwise artefacts will occur as polygons are clipped + to fit into screen space, such as the apparent intensity + changing on a clipper-created vertex. + This is difficult to achieve; the best way, which seems + to work well is to split the quads into triangles before + clipping - splitting them across the same diagonal as the + renderer does. */ + int num_verts = 0; + if (ScanDrawDirectDraw != ScanDrawMode) + { + /* count the number of verts - see if its a quad */ + int * ptsptr = &((POLYHEADER *)shapeitemptr)->Poly1stPt; + while (Term != *ptsptr++) + ++num_verts; + /* shouldn't have pentagons etc. at this stage */ + GLOBALASSERT(num_verts<=4); + } + /* FIXME: + I am not doing this quad splitting on textures with iflag_txanim set + This is rather more complicated than I care to imagine - the uv + co-ords which also need splitting are generated in a function + called CreateTxAnimUVArray which also seems to do a lot more than + just that. Bloody Chris Humphries. + Anyway, I think the lighting artefact will be less noticeable if the texture is animating */ + if (4==num_verts && !(((POLYHEADER *)shapeitemptr)->PolyFlags & iflag_txanim)) + /* need to split quads in d3d mode - + note that num_verts will be 0 in scandraw mode + so this condition will always be false */ + { + /* get pointers to the output items - we may need to adjust the sort key */ + struct KItem * triangle1 = 0; + struct KItem * triangle2 = 0; + /* For a quad we create the triangles (0,1,3) and (1,2,3) */ + /* (see item.c - PrepareTriangleArray_4 functions) */ + /* copy the header data for the quad into this buffer */ + int item_array_buf[sizeof(POLYHEADER)+sizeof(int)*4]; /* 4 verts + polyheader & term */ + /* save the previous uv data in this buffer and modify the actual uv data */ + int uv_array_store[8]; /* 4 verts, U and V foreach vert */ + /* this points to the uv data we are going to save and modify */ + int * uv_array_ptr = NULL; /* will set this non-null if we have a textured item type */ + if ( + I_2dTexturedPolygon == *shapeitemptr || + I_Gouraud2dTexturedPolygon == *shapeitemptr || + I_3dTexturedPolygon == *shapeitemptr || + I_UnscaledSprite == *shapeitemptr || + I_ScaledSprite == *shapeitemptr || + I_ZB_2dTexturedPolygon == *shapeitemptr || + I_ZB_Gouraud2dTexturedPolygon == *shapeitemptr || + I_ZB_3dTexturedPolygon == *shapeitemptr || + I_Gouraud3dTexturedPolygon == *shapeitemptr || + I_ZB_Gouraud3dTexturedPolygon == *shapeitemptr + ) /* textured item type - has uv coords */ + uv_array_ptr = Global_ShapeTextures[((POLYHEADER *)shapeitemptr)->PolyColour >> TxDefn]; + /* copy the header data for the quad into the buffer */ + /* ...and the first two verts since these are the same for the first triangle as for the quad */ + memcpy(item_array_buf,shapeitemptr,sizeof(POLYHEADER)-sizeof(int)+2*sizeof(int)); + /* save the uv data */ + if (uv_array_ptr) memcpy(uv_array_store,uv_array_ptr,sizeof uv_array_store); + /* select vertices for the first triangle */ + #define PFP_OFFSET (sizeof(POLYHEADER)/sizeof(int)-1) /* normally 4 but what if polyheader changes */ + LOCALASSERT(item_array_buf[PFP_OFFSET+0] == shapeitemptr[PFP_OFFSET+0]); + LOCALASSERT(item_array_buf[PFP_OFFSET+1] == shapeitemptr[PFP_OFFSET+1]); + item_array_buf[PFP_OFFSET+2] = shapeitemptr[PFP_OFFSET+3]; + item_array_buf[PFP_OFFSET+3] = Term; + if (uv_array_ptr) + { + /* select the uv coords for the first triangle */ + LOCALASSERT(uv_array_ptr[0] == uv_array_store[0]); /* U */ + LOCALASSERT(uv_array_ptr[1] == uv_array_store[1]); /* V */ + LOCALASSERT(uv_array_ptr[2] == uv_array_store[2]); /* U */ + LOCALASSERT(uv_array_ptr[3] == uv_array_store[3]); /* V */ + uv_array_ptr[4] = uv_array_store[6]; /* U */ + uv_array_ptr[5] = uv_array_store[7]; /* V */ + } + /* output it in the usual way */ + if(ItemOCSBlock.ocs_ptsoutstate == ocs_pout_2d) + { + CreateItemPtsArray[*item_array_buf](item_array_buf, &ClipPointsArray0[0]); + clip_output = Clip2d[*item_array_buf](item_array_buf); + } + else + { + /* also ensure both polygons are rendered in 3d */ + ((POLYHEADER *)item_array_buf)->PolyFlags &= ~iflag_tx2dor3d; + CreateItemPtsArray_Clip3d[*item_array_buf](item_array_buf, &ClipPointsArray0[0]); + clip_output = Clip3d[*item_array_buf](item_array_buf); + } + if(clip_output) + { + + if(Global_ShapeNormals) + ItemColour = ItemLightingModel[*item_array_buf](item_array_buf); + else + ItemColour = pheaderPtr->PolyColour; + + triangle1 = OutputKItem(item_array_buf); + } + /* copy the header data for the quad into the buffer again + because the outcode function fuck around with it,,, */ + memcpy(item_array_buf,shapeitemptr,sizeof(POLYHEADER)-sizeof(int)); + /* select vertices for the second triangle */ + item_array_buf[PFP_OFFSET+0] = shapeitemptr[PFP_OFFSET+1]; + item_array_buf[PFP_OFFSET+1] = shapeitemptr[PFP_OFFSET+2]; + LOCALASSERT(item_array_buf[PFP_OFFSET+2] == shapeitemptr[PFP_OFFSET+3]); + LOCALASSERT(item_array_buf[PFP_OFFSET+3] == Term); + if (uv_array_ptr) + { + /* select the uv coords for the first triangle */ + uv_array_ptr[0] = uv_array_store[2]; /* U */ + uv_array_ptr[1] = uv_array_store[3]; /* V */ + uv_array_ptr[2] = uv_array_store[4]; /* U */ + uv_array_ptr[3] = uv_array_store[5]; /* V */ + LOCALASSERT(uv_array_ptr[4] == uv_array_store[6]); /* U */ + LOCALASSERT(uv_array_ptr[5] == uv_array_store[7]); /* V */ + } + /* output it in the usual way */ + if(ItemOCSBlock.ocs_ptsoutstate == ocs_pout_2d) + { + CreateItemPtsArray[*item_array_buf](item_array_buf, &ClipPointsArray0[0]); + clip_output = Clip2d[*item_array_buf](item_array_buf); + } + else + { + /* also ensure both polygons are rendered in 3d */ + ((POLYHEADER *)item_array_buf)->PolyFlags &= ~iflag_tx2dor3d; + CreateItemPtsArray_Clip3d[*item_array_buf](item_array_buf, &ClipPointsArray0[0]); + clip_output = Clip3d[*item_array_buf](item_array_buf); + } + if(clip_output) + { + + if(Global_ShapeNormals) + ItemColour = ItemLightingModel[*item_array_buf](item_array_buf); + else + ItemColour = pheaderPtr->PolyColour; + + triangle2 = OutputKItem(item_array_buf); + } + /* restore the uv data */ + if (uv_array_ptr) memcpy(uv_array_ptr,uv_array_store,sizeof uv_array_store); + /* if both triangles have been output, + we may need to change the sort keys on one or both, + so that far z and near z values will hopefully be + the same as if it was output as a quad */ + if (triangle1 && triangle2) + { + if (((POLYHEADER *)shapeitemptr)->PolyFlags & iflag_sortnearz) + { + /* take minimum sort keys */ + if (triangle1->SortKey < triangle2->SortKey) + triangle2->SortKey = triangle1->SortKey; + else + triangle1->SortKey = triangle2->SortKey; + } + else + { + /* since sortfarz and no sort flag both take the largest z value + take maximum sort keys */ + if (triangle1->SortKey > triangle2->SortKey) + triangle2->SortKey = triangle1->SortKey; + else + triangle1->SortKey = triangle2->SortKey; + } + } + } + else + #endif + { + if(ItemOCSBlock.ocs_ptsoutstate == ocs_pout_2d) + { + CreateItemPtsArray[*shapeitemptr](shapeitemptr, &ClipPointsArray0[0]); + clip_output = Clip2d[*shapeitemptr](shapeitemptr); + } + else + { + CreateItemPtsArray_Clip3d[*shapeitemptr](shapeitemptr, &ClipPointsArray0[0]); + clip_output = Clip3d[*shapeitemptr](shapeitemptr); + } + if(clip_output) + { + + if(Global_ShapeNormals) + ItemColour = ItemLightingModel[*shapeitemptr](shapeitemptr); + else + ItemColour = pheaderPtr->PolyColour; + + OutputKItem(shapeitemptr); + } + } + } + } + + shapeitemarrayptr++; /* next polygon etc. */ + numitems--; + } +} +#endif + + diff --git a/3dc/avp/win95/KZSORT.H b/3dc/avp/win95/KZSORT.H new file mode 100644 index 0000000..02c512a --- /dev/null +++ b/3dc/avp/win95/KZSORT.H @@ -0,0 +1,30 @@ +/* If this is set to a non-zero value then kzsort.c hijacks the pipeline */ +#define KZSORT_ON 1 + +/* maximum number of modules likely to appear on-screen */ +#define MAX_NUMBER_OF_VISIBLE_MODULES 400 + +struct KItem +{ + POLYHEADER *PolyPtr; + + int SortKey; +}; + +struct KObject +{ + DISPLAYBLOCK *DispPtr; + + int SortKey; + + int DrawBeforeEnvironment; +}; + +/* render with new z-sort */ +extern void KRenderItems(VIEWDESCRIPTORBLOCK *VDBPtr); + +/* generic item shape function */ +extern void KShapeItemsInstr(SHAPEINSTR *shapeinstrptr); +extern void OutputKItem(int *shapeitemptr); + +extern void RenderThisDisplayblock(DISPLAYBLOCK *dbPtr); diff --git a/3dc/avp/win95/LANGPLAT.C b/3dc/avp/win95/LANGPLAT.C new file mode 100644 index 0000000..ac564f7 --- /dev/null +++ b/3dc/avp/win95/LANGPLAT.C @@ -0,0 +1,14 @@ +#include "3dc.h" +#include "inline.h" +#include "language.h" +/* KJL 12:07:26 05/02/97 - this will be buggered +up if the enum in gamedef.h changes */ +unsigned char *LanguageFilename[] = +{ + ENGLISH_TEXT_FILENAME, /* I_English */ + ENGLISH_TEXT_FILENAME, /* I_French */ + ENGLISH_TEXT_FILENAME, /* I_Spanish */ + ENGLISH_TEXT_FILENAME, /* I_German */ + ENGLISH_TEXT_FILENAME, /* I_Italian */ + ENGLISH_TEXT_FILENAME, /* I_Swedish */ +}; diff --git a/3dc/avp/win95/MENUPLAT.CPP b/3dc/avp/win95/MENUPLAT.CPP new file mode 100644 index 0000000..72f740e --- /dev/null +++ b/3dc/avp/win95/MENUPLAT.CPP @@ -0,0 +1,1228 @@ +/*KJL*************************** +* Platform specific menu stuff * +* Transplanted from ddplat.cpp * +***************************KJL*/ + +/* KJL 14:41:13 04/28/97 - I hate this code so much, I put it +in a separate file so that I could keep an eye on it. */ +extern "C" { + +#include "3dc.h" +#include "module.h" +#include "inline.h" +#include "dxlog.h" + +#include + +#include "stratdef.h" +#include "gamedef.h" +#include "gameplat.h" +#include "bh_types.h" + +#include "equipmnt.h" + +#include "huddefs.h" +#include "hudgfx.h" + +#include "font.h" + +#include "menudefs.h" +#include "menugfx.h" +#include "pcmenus.h" + +#include "krender.h" +#include "chnktexi.h" +#include "language.h" + +#include "awTexLd.h" +#include "alt_tab.h" + +extern "C++" +{ +#include "projload.hpp" // c++ header which ignores class definitions/member functions if __cplusplus is not defined ? +#include "chnkload.hpp" // c++ header which ignores class definitions/member functions if __cplusplus is not defined ? +}; +extern void SelectMenuDisplayMode(void); + + +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + +extern DDPIXELFORMAT DisplayPixelFormat; + +extern RIFFHANDLE player_rif; + +/***************** Functions ******************/ +// RWH - unashamably stolen from the PSX +/****************** GAMESTART *****************/ +// THESE ARE THE GRAPHICS WE NEED +MENU_GRAPHIC_ITEM Gamestart_MenuItems[] = +{ + { + -1, + } +}; + +MENUGRAPHIC Gamestart_Backdrop = +{ + "menugfx\\pg0.pg0", -1, NULL, NULL, 0, 0, 640, 480, +}; + + +/* Hardcoded text centring since FJ_CENTRED doesn't work in BLTstring + (some highlighted characters have different widths from their non-highlighted versions?!) +*/ +MENU_TEXT_ITEM Gamestart_MenuFItems[] = +{ + { NEW_GAME_ITEM,TEXTSTRING_MAINMENUS_NEWGAME, NULL, 271, 160 }, + { LOAD_GAME_ITEM, TEXTSTRING_MAINMENUS_LOADGAME, NULL, 268, 180 }, + { OPTIONS_ITEM, TEXTSTRING_MAINMENUS_OPTIONS, NULL, 282, 200 }, + { DEMO_ITEM, TEXTSTRING_MAINMENUS_DEMO, NULL, 293, 220 }, + { MULTIPLAYER_ITEM, TEXTSTRING_MAINMENUS_MULTIPLAYER, NULL, 232, 240 }, + { QUIT_ITEM, TEXTSTRING_MAINMENUS_EXIT, NULL, 297, 270 }, + { -1, } +}; + + +AVP_MENU GameStartMenu = +{ + &Gamestart_Backdrop, + &Gamestart_MenuItems[0], + &Gamestart_MenuFItems[0], + -1, + 0, +}; + + +/**************** CHOOSE CHAR ****************/ + +MENU_GRAPHIC_ITEM ChooseCharacter_MenuGItems[] = +{ + { + ALIEN_ITEM, + {"menugfx\\pg1A.pg0",-1,NULL, NULL, 0, 0, 0, 0,}, + {"NONE", -1, NULL,NULL,}, + }, + { + MARINE_ITEM, + {"menugfx\\pg1M.pg0",-1,NULL, NULL, 208, 0, 0, 0,}, + {"NONE",-1, NULL,NULL,}, + }, + { + PREDATOR_ITEM, + {"menugfx\\pg1P.pg0",-1,NULL, NULL, 420, 0, 0, 0,}, + {"NONE",-1, NULL,NULL,}, + }, + { + -1, + } + +}; + + +MENU_TEXT_ITEM ChooseCharacter_MenuFItems[] = +{ + { EXIT_ITEM, TEXTSTRING_MAINMENUS_EXIT, NULL, 300, 440 }, + { -1, } +}; + + +MENUGRAPHIC ChooseCharacter_Backdrop = +{ + "menugfx\\pg1.pg0", -1, NULL, NULL, 0, 0, 640, 480, +}; + + +AVP_MENU CharacterMenu = +{ + &ChooseCharacter_Backdrop, + &ChooseCharacter_MenuGItems[0], + &ChooseCharacter_MenuFItems[0], + -1, + 0, +}; + + + +/**************** ALIEN BRIEFING ****************/ + +MENU_GRAPHIC_ITEM AlienBriefing_MenuGItems[] = +{ + { -1, } +}; + + +MENU_TEXT_ITEM AlienBriefing_MenuFItems[] = +{ + { ENTER_GAME_ALIEN, TEXTSTRING_MAINMENUS_STARTGAME, NULL, 200, 440 }, + { EXIT_ITEM_ALIEN, TEXTSTRING_MAINMENUS_EXIT, NULL, 400, 440 }, + { -1, } +}; + +MENUGRAPHIC AlienBriefing_Backdrop = +{"menugfx\\pg2a.pg0",-1, NULL, NULL, 0,0,0,0,}; + +AVP_MENU AlienBriefing = +{ + &AlienBriefing_Backdrop, + AlienBriefing_MenuGItems, + AlienBriefing_MenuFItems, + -1, + 0, +}; + + +/******************* PREDATOR BRIEFING ***************/ + +MENU_GRAPHIC_ITEM PredatorBriefing_MenuGItems[] = +{ + { -1, } +}; + +MENU_TEXT_ITEM PredatorBriefing_MenuFItems[] = +{ + { ENTER_GAME_PREDATOR, TEXTSTRING_MAINMENUS_STARTGAME, NULL, 200, 440 }, + { EXIT_ITEM_PREDATOR, TEXTSTRING_MAINMENUS_EXIT, NULL, 400, 440 }, + { -1, } +}; + +MENUGRAPHIC PredatorBriefing_Backdrop = +{"menugfx\\pg2b.pg0", -1, NULL, NULL, 0,0,0,0}; + +AVP_MENU PredatorBriefing = +{ + &PredatorBriefing_Backdrop, + &PredatorBriefing_MenuGItems[0], + &PredatorBriefing_MenuFItems[0], + -1, + 0, +}; + + +/********************** MARINE BRIEFING **************/ + + +MENU_TEXT_ITEM MarineBriefing_MenuFItems[] = +{ + { ENTER_GAME_MARINE, TEXTSTRING_MAINMENUS_STARTGAME, NULL, 200, 440 }, + { EXIT_ITEM_MARINE, TEXTSTRING_MAINMENUS_EXIT, NULL, 400, 440 }, + { -1, } +}; + +MENU_GRAPHIC_ITEM MarineBriefing_MenuGItems[] = +{ + +#if 0 + { + MALE_MARINE_FACE, + {MARPROF2,-1,NULL,NULL, 189, 42, 52,52,}, + {MARPROF2,-1,NULL,NULL, 189, 42, 52,52,}, + }, + { + FEMALE_MARINE_FACE, + {MARPROF2,-1,NULL,NULL, 249, 42, 52,52,}, + {MARPROF2,-1,NULL,NULL, 249, 42, 52,52,}, + }, +#endif + { + -1, + } +}; + +MENUGRAPHIC MarineBriefing_Backdrop = {"menugfx\\pg2c.pg0", -1, NULL, NULL, 0,0,0,0}; + +AVP_MENU MarineBriefing = +{ + &MarineBriefing_Backdrop, + &MarineBriefing_MenuGItems[0], + &MarineBriefing_MenuFItems[0], + -1, + 0, +}; + + +#if 0 +/********************** LOAD MENU **************/ + +MENU_TEXT_ITEM LoadGame_MenuFItems[] = +{ + { ENTER_GAME_MARINE, TEXTSTRING_MAINMENUS_STARTGAME, NULL, 200, 440 }, + { EXIT_ITEM_MARINE, TEXTSTRING_MAINMENUS_EXIT, NULL, 400, 440 }, + { -1, } +}; + +MENU_GRAPHIC_ITEMLoadGame_MenuItems[] = +{ + { -1, } +}; + + +MENUGRAPHIC Load_Backdrop = {"menugfx\\pg2c.pg0", -1, NULL, NULL, 0,0,0,0}; + +AVP_MENU LoadGame = +{ + &LoadGame_Backdrop, + &LoadGame_MenuGItems[0], + &LoadGame_MenuFItems[0], + -1, + 0, +}; + +#endif + + +AVP_MENU *Current_Menu; + +extern void DrawInternationalizedString(MENU_TEXT_ITEM *itemPtr, int highlighted); +extern void DrawMenuBackdrop(void); + +void LoadMenuGraphics(int menu_id) +{ + // this loads up the correct menu items - effectively + // it is a draw menu items function + + switch (menu_id) + { + case CHOOSE_GAMESTART: + Current_Menu=&GameStartMenu; + break; + case CHOOSE_CHARACTER: + Current_Menu=&CharacterMenu; + break; + case CHOOSE_OPTIONS: + Current_Menu=&OptionsMenuData; + break; + case MARINE_BRIEFING: + Current_Menu=&MarineBriefing; + break; + case PREDATOR_BRIEFING: + Current_Menu=&PredatorBriefing; + break; + case ALIEN_BRIEFING: + Current_Menu=&AlienBriefing; + break; + default: + break; + } + ProcessGraphicForLoading(Current_Menu); +} + +// okay lets load the menu graphics + +void ProcessGraphicForLoading(AVP_MENU *menu_to_load) +{ + MENU_GRAPHIC_ITEM *menuitemptr; + menuitemptr = menu_to_load->menugitems; + + LoadMenuGraphic(menu_to_load->backdrop); + + while (menuitemptr->id != -1) + { + if(strcmp(menuitemptr->On.filename, "NONE")) + LoadMenuGraphic(&menuitemptr->On); + if(strcmp(menuitemptr->Off.filename, "NONE")) + LoadMenuGraphic(&menuitemptr->Off); + menuitemptr++; + } +} + + +void UnLoadMenuGraphics(int menu_id) +{ + // this loads up the correct menu items - effectively + // it is a draw menu items function + +// int a; + + switch (menu_id) + { + case CHOOSE_GAMESTART: + Current_Menu=&GameStartMenu; + break; + case CHOOSE_CHARACTER: + Current_Menu=&CharacterMenu; + break; + case CHOOSE_OPTIONS: + Current_Menu=&OptionsMenuData; + break; + case MARINE_BRIEFING: + Current_Menu=&MarineBriefing; + break; + case PREDATOR_BRIEFING: + Current_Menu=&PredatorBriefing; + break; + case ALIEN_BRIEFING: + Current_Menu=&AlienBriefing; + GLOBALASSERT(menu_id==ALIEN_BRIEFING); + break; + default: + break; + } + ProcessGraphicForUnloading(Current_Menu); +} + +void ProcessGraphicForUnloading(AVP_MENU *menu_to_unload) +{ + MENU_GRAPHIC_ITEM *menuitemptr; + // okay lets Unload the menu graphics + ReleaseMenuGraphic(menu_to_unload->backdrop); + menuitemptr=menu_to_unload->menugitems; + + while (menuitemptr->id != -1) + { + if(strcmp(menuitemptr->On.filename, "NONE")) + ReleaseMenuGraphic(&menuitemptr->On); + if(strcmp(menuitemptr->Off.filename, "NONE")) + ReleaseMenuGraphic(&menuitemptr->Off); + menuitemptr++; + } +} + + +/* JH 12/5/97 - no longer static function */ +void LoadMenuGraphic(MENUGRAPHIC* menugraphptr) +{ + /* + Weapons + + The hud direct draw surfaces are stored in + system memory. It is only the current weapon that is + cashed into video memory + + First we attach the weapons direct draw surface to the + Direct Draw lpDD. We then lock the newly created surface and draw the + weapon image into it. FIle in the rest of the HUD graphic and then + exit + */ + + /* + set up the direct draw surface. we can take the width and height + from the imageheader image + */ + // JH 17/2/98 - just a bit of a wrapper to AwCreateSurface now... + + unsigned nWidth,nHeight; + + GLOBALASSERT(menugraphptr); + menugraphptr->image_ptr = AwCreateSurface("sfXYB",menugraphptr->filename,AW_TLF_TRANSP|AW_TLF_CHROMAKEY,&nWidth,&nHeight,&menugraphptr->hBackup); + menugraphptr->width = nWidth; + menugraphptr->height = nHeight; + GLOBALASSERT(menugraphptr->image_ptr); + GLOBALASSERT(menugraphptr->hBackup); + GLOBALASSERT(menugraphptr->width>0); + GLOBALASSERT(menugraphptr->height>0); + ATIncludeSurface(menugraphptr->image_ptr,menugraphptr->hBackup); +} + + + +void DeIlluminate(int menuitem) +{ + + /***** Menuitem comes from the enum. Match it to id. *****/ + + int num_menu_item = 0; + + MENU_GRAPHIC_ITEM *ThisMenuGItem = NULL; + MENU_TEXT_ITEM *ThisMenuFItem = NULL; + + + // lok throught the array of graphic oitems and font + // items, and draw the menu item we have been passed + + while (Current_Menu->menugitems[num_menu_item].id!=-1) + { + + if(Current_Menu->menugitems[num_menu_item].id==menuitem) + { + ThisMenuGItem=&Current_Menu->menugitems[num_menu_item]; + } + num_menu_item++; + } + + num_menu_item = 0; + while (Current_Menu->menufitems[num_menu_item].id!=-1) + { + if(Current_Menu->menufitems[num_menu_item].id==menuitem) + { + ThisMenuFItem=&Current_Menu->menufitems[num_menu_item]; + } + num_menu_item++; + } + + + if(ThisMenuGItem != NULL) + { + if(strcmp(ThisMenuGItem->Off.filename, "NONE")) + BLTMenuToScreen(&ThisMenuGItem->Off); + } + + if(ThisMenuFItem != NULL) + { + DrawInternationalizedString(ThisMenuFItem,0); + } + +} + + + +void Illuminate(int menuitem) +{ + + /***** Menuitem comes from the enum. Match it to id. *****/ + + int num_menu_item = 0; + + MENU_GRAPHIC_ITEM *ThisMenuGItem = NULL; + MENU_TEXT_ITEM *ThisMenuFItem = NULL; + + + // lok throught the array of graphic oitems and font + // items, and draw the menu item we have been passed + + while (Current_Menu->menugitems[num_menu_item].id!=-1) + { + + if(Current_Menu->menugitems[num_menu_item].id==menuitem) + { + ThisMenuGItem=&Current_Menu->menugitems[num_menu_item]; + } + num_menu_item++; + } + + + num_menu_item = 0; + while (Current_Menu->menufitems[num_menu_item].id!=-1) + { + if(Current_Menu->menufitems[num_menu_item].id==menuitem) + { + ThisMenuFItem=&Current_Menu->menufitems[num_menu_item]; + } + num_menu_item++; + } + + + if(ThisMenuGItem != NULL) + { + if(strcmp(ThisMenuGItem->On.filename, "NONE")) + BLTMenuToScreen(&ThisMenuGItem->On); + } + + if(ThisMenuFItem != NULL) + { + DrawInternationalizedString(ThisMenuFItem,1); + } + + // okay, now we draw a +} + +extern HINSTANCE AVP_HInstance, hInst; +extern int AVP_NCmd; + + +static RIFFHANDLE menu_rif = INVALID_RIFFHANDLE; + +void PlatformSpecificEnteringMenus(void) +{ + // Load and process the font + SelectMenuDisplayMode(); + + SetCursor(NULL); + + + + cl_pszGameMode = "menus"; + + if(menu_rif == INVALID_RIFFHANDLE) + { + menu_rif = load_rif("menugfx\\menugfx.rif"); + LoadPFFont(MENU_FONT_1); + } + + if(menu_rif == INVALID_RIFFHANDLE) + { + GLOBALASSERT(0); + } + +} + +void PlatformSpecificExitingMenus(void) +{ + // just need to release the DD surface + // lets leave the rects as valid, so we can + // do lazy eval of the font char rects if we want + int fadeLevel=65536; + while(fadeLevel>=0) + { + /* fade screen to black */ + SetPaletteFadeLevel(fadeLevel); + fadeLevel-= 2048; + } + + UnloadFont(&AvpFonts[MENU_FONT_1]); + unload_rif(menu_rif);//get rid of File_Chunk + menu_rif = INVALID_RIFFHANDLE; + BlankScreen(); +} + + +void DrawMenuBackdrop(void) +{ + BLTMenuToScreen(Current_Menu->backdrop); +} + +/* KJL 15:54:28 03/20/97 - intro hack variable */ +int WhiteOutLevel; +extern int NormalFrameTime; + +extern int VideoMode; +extern void (*UpdateScreen[]) (void); + +void DrawEntireMenuScreen(void) +{ + /***** Frankly, I don't care which menu. *****/ + + int a; + + DrawMenuBackdrop(); + + a=0; + + while (CurrentMenuStatus[a]!=-1) + { + + if (CurrentMenuStatus[a]!=0) + { + Illuminate(a); + } + else + { + DeIlluminate(a); + } + + a++; + } + + UpdateScreen[VideoMode](); + + /* KJL 15:52:41 03/20/97 - hack from intro that's ended up here */ + { + // fade in + if (WhiteOutLevel==0) + { + int fadeLevel = 0; + do + { + ResetFrameCounter(); + FadePaletteToWhite(TestPalette,fadeLevel); + fadeLevel+=NormalFrameTime*4; + FrameCounterHandler(); + } + while(fadeLevel<65536); + + ChangePalette(TestPalette); + WhiteOutLevel=65536; + } + } + +} + + + +/* JH 12/5/97 - no longer static functions */ + +void ReleaseMenuGraphic(MENUGRAPHIC* mptr) +{ + GLOBALASSERT(mptr); + GLOBALASSERT(mptr->image_ptr); + ATRemoveSurface(mptr->image_ptr); + ReleaseDDSurface(mptr->image_ptr); + mptr->image_ptr = NULL; + if (mptr->hBackup) + AwDestroyBackupTexture(mptr->hBackup); + mptr->hBackup = NULL; +} + + + +/* + Windows externs. See win_func +*/ + + + +void BLTMenuToScreen(MENUGRAPHIC* menuptr) +{ + /* + sets up the drawing of general hud graphics. Bltted + to full screen if there is no width and heiht information in + the DD HUDGRAPHIC + */ + + RECT destRect; + RECT scrRect; + HRESULT ddrval; + + GLOBALASSERT(menuptr != NULL); + + scrRect.top = 0; + scrRect.bottom = menuptr->height; + scrRect.left = 0; + scrRect.right = menuptr->width; + + + destRect.top = menuptr->desty; + destRect.bottom = menuptr->desty + menuptr->height; + destRect.left = menuptr->destx; + destRect.right = menuptr->destx + menuptr->width; + + ddrval = lpDDSBack->Blt(&destRect, menuptr->image_ptr, &scrRect, DDBLT_WAIT, NULL); + + if(ddrval != DD_OK) + { + ReleaseDirect3D(); + exit(0x666009); + } +} + + +void DrawInternationalizedString(MENU_TEXT_ITEM *itemPtr, int highlighted) +{ + char textBuffer[100]; + char *destPtr = textBuffer; + char offset; + + /* KJL 17:39:03 05/03/97 - I hate Roxby. Due to the way he's set up the menu font + I have to add 27+'a'-'A' (!) to each letter if I want it *not* to be highlighted. */ + if (!highlighted) + { + offset = 27+'a'-'A'; + } + else + { + offset = 0; + } + + if (itemPtr->StringID != TEXTSTRING_BLANK) + { + /* copy the string into the buffer */ + char *sourcePtr = GetTextString(itemPtr->StringID); + + while(*sourcePtr) + { + /* Roxby has a lot to answer for... */ + *destPtr++ = offset + (*sourcePtr++); + } + + /* if another string follows this string, add a space */ + if (itemPtr->SecondStringPtr) + { + *destPtr++=' '; + } + } + + /* add second string, if it exists */ + if (itemPtr->SecondStringPtr) + { + char *sourcePtr = itemPtr->SecondStringPtr; + + while(*sourcePtr) + { + /* Roxby has a lot to answer for... */ + *destPtr++ = offset + (*sourcePtr++); + } + } + + /* add null terminator to end of string */ + *destPtr = 0; + + { + FONT_DESC packet; + packet.fontnum = MENU_FONT_1; + packet.string = textBuffer; + packet.destx = itemPtr->X; + packet.desty = itemPtr->Y; + packet.just = FJ_LEFT_JUST; + packet.width = 320; + + BLTString(packet); + } +} + + + + +/*KJL******* +* DATABASE * +*******KJL*/ +#include "database.h" +void LoadDDGraphic2(struct DDGraphicTag *DDGfxPtr, char *Filename); +static void GetMessageName(char* messagename); + +static RIFFHANDLE dbgfx_rif = INVALID_RIFFHANDLE; + + + +struct DDGraphicTag DatabaseBackground; +struct DatabaseGraphicsDataTag +{ + char *Filename; + int X; /* top-left coords */ + int Y; +}; + + + +LPDIRECTDRAWSURFACE lpDDSInGameMenuBackdrop; +extern LPDIRECTDRAWSURFACE lpDDSPrimary; // DirectDraw primary surface + + +static int DatabaseInitialised = 1; + +void InitialiseDatabaseGraphics() +{ + // load up the fonts + + LoadPFFont(DATABASE_FONT_DARK); + LoadPFFont(DATABASE_FONT_LITE); + LoadPFFont(DATABASE_MESSAGE_FONT); + + + { + DDSURFACEDESC ddsd; + HRESULT ddrval; + + // attach a system memory back buffer so we can record + // what is on the screen before we enter the menus + + // Create back buffer + memset(&ddsd,0,sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.dwHeight = ScreenDescriptorBlock.SDB_Height; + ddsd.dwWidth = ScreenDescriptorBlock.SDB_Width; + + // Request a 3D capable device so that + // Direct3D accesses will work + ddsd.ddsCaps.dwCaps = + ( + DDSCAPS_OFFSCREENPLAIN | + DDSCAPS_SYSTEMMEMORY | + DDSCAPS_3DDEVICE + ); + + ddrval = lpDD->CreateSurface(&ddsd, &lpDDSInGameMenuBackdrop, NULL); + LOGDXERR(ddrval); + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(0x1055); + } + #else + return; + #endif + } +} + + + + + + +void PlatformSpecificEnteringDatabase(void) +{ + + + // lets make a copy of the back buffer, and in the process darken the + // colours by half + + // first, take a lock for both surfaces + + + DDSURFACEDESC ddsdback; + DDSURFACEDESC ddsdmenu; + unsigned char *src, *dest, *srcStart, *destStart; + long srcPitch, destPitch; + HRESULT ddrval; + + + memset(&ddsdback, 0, sizeof(ddsdback)); + ddsdback.dwSize = sizeof(ddsdback); + + memset(&ddsdmenu, 0, sizeof(ddsdmenu)); + ddsdmenu.dwSize = sizeof(ddsdmenu); + + + // take a lock of the back buffer + + while ((ddrval = lpDDSBack->Lock(NULL, &ddsdback, DDLOCK_WAIT, NULL)) == DDERR_WASSTILLDRAWING) + { + LOGDXERR(ddrval); + ReleaseDirect3D(); + exit(0x2021); + } + + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + return; + #endif + } + + /* ddsdback now contains my lpSurface)*/ + + src = srcStart = (unsigned char *)ddsdback.lpSurface; + srcPitch = ddsdback.lPitch - ddsdback.dwWidth; + + + // take a lock of the menubackdrop buffer + + + while ((ddrval = lpDDSInGameMenuBackdrop->Lock(NULL, &ddsdmenu, DDLOCK_WAIT, NULL)) == DDERR_WASSTILLDRAWING) + { + LOGDXERR(ddrval); + ReleaseDirect3D(); + exit(0x2022); + } + + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + return; + #endif + } + + destStart = (unsigned char *)ddsdmenu.lpSurface; + destPitch = ddsdmenu.lPitch - ddsdmenu.dwWidth; + + + + // okay, now we have the surfaces, we can copy from one to the other, + // darkening pixels as we go + + + { + int i = 0, j = 0; + extern int VideoModeColourDepth; + + + switch(VideoModeColourDepth) + { + case 8: + { + unsigned char* dest = (unsigned char *)ddsdmenu.lpSurface; + unsigned char* src = (unsigned char *)ddsdback.lpSurface; + + for(j=0; j < ScreenDescriptorBlock.SDB_Height; j++) + { + for(i=0;i < ScreenDescriptorBlock.SDB_Width; i++) + { + extern unsigned char* TextureLightingTable; + + *dest++ = *(TextureLightingTable + (32 * 256) + *src++); + } + + dest += destPitch; + src += srcPitch; + } + break; + } +#if 1 + case 16: + { + short r,g,b; + short *destShort = (short*)ddsdmenu.lpSurface; + short *srcShort = (short*)ddsdback.lpSurface; + + for(j=0; j < ScreenDescriptorBlock.SDB_Height; j++) + { + destShort = (short*)(((char*)ddsdmenu.lpSurface) + + ddsdmenu.lPitch * j); + srcShort = (short*)(((char*)ddsdback.lpSurface) + + ddsdback.lPitch * j); + + + for(i=0;i < ScreenDescriptorBlock.SDB_Width; i++) + { + r = (*srcShort & DisplayPixelFormat.dwRBitMask)>>1; + g = (*srcShort & DisplayPixelFormat.dwGBitMask)>>1; + b = (*srcShort & DisplayPixelFormat.dwBBitMask)>>1; + srcShort++; + + r &= DisplayPixelFormat.dwRBitMask; + g &= DisplayPixelFormat.dwGBitMask; + b &= DisplayPixelFormat.dwBBitMask; + + *destShort++ = r|g|b; + } + } + break; + } + case 32: + { + int *destInt = (int*)ddsdmenu.lpSurface; + int *srcInt = (int*)ddsdback.lpSurface; + int r,g,b; + + for(j=0; j < ScreenDescriptorBlock.SDB_Height; j++) + { + for(i=0;i < ScreenDescriptorBlock.SDB_Width; i++) + { + r = (*srcInt & DisplayPixelFormat.dwRBitMask)>>1; + g = (*srcInt & DisplayPixelFormat.dwGBitMask)>>1; + b = (*srcInt++ & DisplayPixelFormat.dwBBitMask)>>1; + + r &= DisplayPixelFormat.dwRBitMask; + g &= DisplayPixelFormat.dwGBitMask; + b &= DisplayPixelFormat.dwBBitMask; + + *destInt++ = r|g|b; + + + } + + destInt += (destPitch >> 2); + srcInt += (srcPitch >> 2); + } + break; + + } +#endif + default: + break; + } + } + + + // unlock the two surfaces + + ddrval = lpDDSInGameMenuBackdrop->Unlock((LPVOID)destStart); + LOGDXERR(ddrval); + #if debug + if (ddrval != DD_OK) + { + ReleaseDirect3D(); + exit(ddrval); + } + #endif + ddrval = lpDDSBack->Unlock((LPVOID)srcStart); + LOGDXERR(ddrval); + + #if debug + if (ddrval != DD_OK) + { + ReleaseDirect3D(); + exit(ddrval); + } + #endif +} + + + + + +void DrawDatabaseBackground(void) +{ + HRESULT ddrval; + RECT screen_coords; + + screen_coords.left = 0; + screen_coords.top =0; + screen_coords.right = ScreenDescriptorBlock.SDB_Width; + screen_coords.bottom = ScreenDescriptorBlock.SDB_Height; + + + ddrval = lpDDSBack->BltFast + ( + 0, + 0, + lpDDSInGameMenuBackdrop, + &screen_coords, + DDBLTFAST_WAIT + ); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(0x2055); + } + #else + return; + #endif + + + + return; + + /* draw to top-left corner of the screen, opaque */ + ddrval = lpDDSBack->BltFast + ( + 0, + 0, + DatabaseBackground.LPDDS, + &(DatabaseBackground.SrcRect), + DDBLTFAST_WAIT + ); + if(ddrval != DD_OK) + { + ReleaseDirect3D(); + exit(0); + } + return; +} + + +extern int IDemandGoForward(); +extern int IDemandGoBackward(); +extern int IDemandTurnRight(); +extern int IDemandTurnLeft(); +extern int IDemandSelect(); +#define MAPSCREENWIDTH 251 +#define MAPSCREENHEIGHT 137 + +int MapXOffset = (640-MAPSCREENWIDTH)/2; +int MapYOffset = (480-MAPSCREENHEIGHT)/2; + + + +void PlatformSpecificExitingDatabase(void) +{ +// extern void SetVisionPalette(void); + +// unload_rif(dbgfx_rif);//get rid of File_Chunk + +// UnloadFont(&AvpFonts[DATABASE_FONT_LITE]); +// UnloadFont(&AvpFonts[DATABASE_FONT_DARK]); + +// ReleaseDDSurface(DatabaseBackground.LPDDS); + + /* blank screen before changing palette to avoid screen glitches */ +// BlankScreen(); + /* KJL 12:35:21 03/12/97 - get correct palette */ +// SetVisionPalette(); +} + + +void LoadDDGraphic2(struct DDGraphicTag *DDGfxPtr, char *Filename) +{ + /* + set up the direct draw surface. we can take the width and height + from the imageheader image + */ + + GLOBALASSERT(DDGfxPtr); + GLOBALASSERT(Filename); + + unsigned nWidth,nHeight; + DDGfxPtr->LPDDS = AwCreateSurface("sfXYB",Filename,AW_TLF_TRANSP|AW_TLF_CHROMAKEY,&nWidth,&nHeight,&DDGfxPtr->hBackup); + GLOBALASSERT(DDGfxPtr->LPDDS); + + ATIncludeSurface(DDGfxPtr->LPDDS,DDGfxPtr->hBackup); + + DDGfxPtr->SrcRect.left = 0; + DDGfxPtr->SrcRect.right = nWidth; + DDGfxPtr->SrcRect.top = 0; + DDGfxPtr->SrcRect.bottom = nHeight; +} + + +static void* MessageString; + +#define DATABASE_MESSAGE_NAME_LENGTH 50 + +#if 1 +void LoadDatabaseMessage() +{ + char filename[DATABASE_MESSAGE_NAME_LENGTH] = {"\000"}; + FILE* message_fp; + struct _stat filestatus; + int filesize; + + GetMessageName(filename); + + message_fp = fopen(filename, "rb"); + + GLOBALASSERT(message_fp); + + _stat(filename, &filestatus); + + filesize = filestatus.st_size;//filestatus.off_t; + + MessageString = AllocateMem(filesize + 1); + + if (!MessageString) + { + memoryInitialisationFailure = 1; + return; + } + + fread(MessageString, 1, filesize, message_fp); + + // add the terminator + + *((char*)MessageString + filesize) = 0; +} + + +static void GetMessageName(char* messagename) +{ + char messagenum[5]; + + sprintf(messagenum,"%d", (int)PlayerStatusPtr->CurrentMission); + + strcat(messagename, "DBMESS\\"); + strcat(messagename, LanguageDirNames[AvP.Language]); + strcat(messagename, "\\MSG"); + strcat(messagename, messagenum); + strcat(messagename, ".TXT"); + +} + + +#define MESSAGE_TOP_MARGIN 25 +#define MESSAGE_SIDE_MARGIN 35 + +void WriteDatabaseMessage() +{ + + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + + FONT_DESC db_message; + + db_message.fontnum = DATABASE_MESSAGE_FONT; + db_message.string = (char*)MessageString; + db_message.destx = MESSAGE_SIDE_MARGIN; + db_message.desty = MESSAGE_TOP_MARGIN; + db_message.width = ScreenDescriptorBlock.SDB_Width - (MESSAGE_SIDE_MARGIN*2); + db_message.just = FJ_LEFT_JUST; + + + BLTString(db_message); +} + + +void UnloadDatabaseMessage() +{ + if (MessageString) DeallocateMem(MessageString); +} +#endif + +void UpdateDatabaseScreen(void) +{ + FlipBuffers(); +} + + + + + +}; // extern "C" \ No newline at end of file diff --git a/3dc/avp/win95/MULTMENU.C b/3dc/avp/win95/MULTMENU.C new file mode 100644 index 0000000..a9c1e2d --- /dev/null +++ b/3dc/avp/win95/MULTMENU.C @@ -0,0 +1,844 @@ +/*-------------------------Patrick 7/5/97----------------------------- + Source for the multiplayer menus: I have have heavily modified this + ---------------------------------------------------------------------*/ + +#include "3dc.h" +#include "module.h" +#include "inline.h" +#include "stratdef.h" +#include "gamedef.h" +#include "font.h" +#include "menudefs.h" +#include "menugfx.h" +#include "dp_func.h" +#include "multmenu.h" +#include "equipmnt.h" +#include "pldnet.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +static char mPLevelNameString[] = "KIPPER"; +static char mPScoreLimitString[] = "PAT"; +static char mPTimeLimitString[] = "PAT"; +static char mPBlankString[] = "\0"; + +/* Setup stuff for the Multiplayer Menus graphics and options */ +static MENU_GRAPHIC_ITEM MPGameSelect_MenuItems[] = {{-1,}}; + +static MENUGRAPHIC MPGameSelect_Backdrop = {"menugfx\\pg0.pg0",-1,NULL,NULL,0,0,640,480,}; + +static MENU_TEXT_ITEM MPGameSelect_MenuFItems[] = +{ + {MMSelect_Title, TEXTSTRING_MULTI_TITLE, NULL, 80, 40}, + {MMSelect_P1Name, TEXTSTRING_BLANK, mPBlankString, 80, 80}, + {MMSelect_P2Name, TEXTSTRING_BLANK, mPBlankString, 80, 100}, + {MMSelect_P3Name, TEXTSTRING_BLANK, mPBlankString, 80, 120}, + {MMSelect_P4Name, TEXTSTRING_BLANK, mPBlankString, 80, 140}, + {MMSelect_P5Name, TEXTSTRING_BLANK, mPBlankString, 80, 160}, + {MMSelect_P6Name, TEXTSTRING_BLANK, mPBlankString, 80, 180}, + {MMSelect_P7Name, TEXTSTRING_BLANK, mPBlankString, 80, 200}, + {MMSelect_P8Name, TEXTSTRING_BLANK, mPBlankString, 80, 220}, + {MMSelect_P1Type, TEXTSTRING_BLANK, mPBlankString, 240, 80}, + {MMSelect_P2Type, TEXTSTRING_BLANK, mPBlankString, 240, 100}, + {MMSelect_P3Type, TEXTSTRING_BLANK, mPBlankString, 240, 120}, + {MMSelect_P4Type, TEXTSTRING_BLANK, mPBlankString, 240, 140}, + {MMSelect_P5Type, TEXTSTRING_BLANK, mPBlankString, 240, 160}, + {MMSelect_P6Type, TEXTSTRING_BLANK, mPBlankString, 240, 180}, + {MMSelect_P7Type, TEXTSTRING_BLANK, mPBlankString, 240, 200}, + {MMSelect_P8Type, TEXTSTRING_BLANK, mPBlankString, 240, 220}, + {MMSelect_P1Ok, TEXTSTRING_BLANK, mPBlankString, 400, 80}, + {MMSelect_P2Ok, TEXTSTRING_BLANK, mPBlankString, 400, 100}, + {MMSelect_P3Ok, TEXTSTRING_BLANK, mPBlankString, 400, 120}, + {MMSelect_P4Ok, TEXTSTRING_BLANK, mPBlankString, 400, 140}, + {MMSelect_P5Ok, TEXTSTRING_BLANK, mPBlankString, 400, 160}, + {MMSelect_P6Ok, TEXTSTRING_BLANK, mPBlankString, 400, 180}, + {MMSelect_P7Ok, TEXTSTRING_BLANK, mPBlankString, 400, 200}, + {MMSelect_P8Ok, TEXTSTRING_BLANK, mPBlankString, 400, 220}, + {MMSelect_Character, TEXTSTRING_MULTI_CHARACTER, NULL, 80, 260}, + {MMSelect_Level, TEXTSTRING_MULTI_LEVEL, NULL, 80, 280}, + {MMSelect_Mode, TEXTSTRING_MULTI_GAMEMODE, NULL, 80, 300}, + {MMSelect_ScoreLimit, TEXTSTRING_MULTI_SCORELIMIT, NULL, 80, 320}, + {MMSelect_TimeLimit, TEXTSTRING_MULTI_TIMELIMIT, NULL, 80, 340}, + {MMSelect_Start, TEXTSTRING_MULTI_START, NULL, 80, 380}, + {MMSelect_Cancel, TEXTSTRING_MULTI_CANCEL, NULL, 240, 380}, + {MMSelect_CharacterSelection, TEXTSTRING_MULTI_MARINE, NULL, 240, 260}, + {MMSelect_LevelSelection, TEXTSTRING_BLANK, mPLevelNameString, 240, 280}, + {MMSelect_ModeSelection, TEXTSTRING_MULTI_INDIVIDUAL, NULL, 240, 300}, + {MMSelect_ScoreLimitSelection, TEXTSTRING_NO, NULL, 240, 320}, + {MMSelect_TimeLimitSelection, TEXTSTRING_NO, NULL, 240, 340}, + {-1,} +}; + +static AVP_MENU MPGameSelectMenu = +{ + &MPGameSelect_Backdrop, + &MPGameSelect_MenuItems[0], + &MPGameSelect_MenuFItems[0], + -1, + 0, +}; + + +/* Local function prototypes */ +static MULTIPLAYER_SELECT_OPTIONS DoSelectionState(void); +static void DrawMultiStartUpScreen(void); +static void DoMultiStartUpSelection(void); +static void DisplayMultiStartUpErrorMessage(void); + +/* Externally defined functions and variables used in this file */ +extern int IDemandGoBackward(); +extern int IDemandGoForward(); +extern int IDemandSelect(); +extern int menustate; +extern int NormalFrameTime; + +/* globals used in this file */ +static int debounce = 0; +static MULTIPLAYER_SELECT_OPTIONS thisSelection = MMSelect_Max; +static int currentItem = MMSelect_Start; + +/* The main multiplayer menu state loop function */ +int RunMultiplayerStartUp(int lobbied) +{ + /* first, run the connection dialog */ + if(!lobbied) + { + AvP.Network=I_No_Network; + InvokeDirectPlayDialog(); + + if(ProcessDirectPlayDialog()==0) + { + /* didn't connect */ + EndAVPNetGame(); + return 0; + } + } + + /* we have successfully connected to a game...*/ + InitAVPNetGame(); + + /* init the menu items and strings */ + { + int i; + + /* players names, types, and ok flags */ + for(i=0;i=NET_MAXPLAYERSCORE) netGameData.scoreLimit=0; + else netGameData.scoreLimit+=5; + break; + } + case(MMSelect_TimeLimitSelection): + { + LOCALASSERT(AvP.Network==I_Host); + if(netGameData.timeLimit>=NET_MAXGAMETIME) netGameData.timeLimit=0; + else netGameData.timeLimit+=5; + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + } + else if((IDemandGoForward()==0)&&(IDemandGoBackward()==0)&&(IDemandSelect()==0)) + debounce =1; +} + +/* Patrick 19/7/97--------------------------------------------------- +function for displaying multiplayer startup error messages : +adjusts existing menu... +---------------------------------------------------------------------*/ +static MENU_TEXT_ITEM MPStartUpError_MenuFItems[] = +{ + {MMSelect_Title, TEXTSTRING_MULTI_TITLE, NULL, 80, 40}, + {MMSelect_Start, TEXTSTRING_BLANK, NULL, 80, 80}, + {MMSelect_Cancel, TEXTSTRING_MULTI_OK, NULL, 80, 120}, + {-1,} +}; +static AVP_MENU MPStartUpErrorMenu = +{ + &MPGameSelect_Backdrop, + &MPGameSelect_MenuItems[0], + &MPStartUpError_MenuFItems[0], + -1, + 0, +}; + + +static void DisplayMultiStartUpErrorMessage(void) +{ + /* examine our NGS and decide what message to display */ + switch(netGameData.myGameState) + { + case(NGS_Error_GameFull): + { + MPStartUpError_MenuFItems[1].StringID = TEXTSTRING_MULTI_GAMEFULL; + break; + } + case(NGS_Error_GameStarted): + { + MPStartUpError_MenuFItems[1].StringID = TEXTSTRING_MULTI_ALREADYSTARTED; + break; + } + case(NGS_Error_HostLost): + { + MPStartUpError_MenuFItems[1].StringID = TEXTSTRING_MULTI_CONNECTIONLOST; + break; + } + default: + { + LOCALASSERT(1==0); + return; + break; + } + } + + thisSelection = MMSelect_Max; + currentItem = MMSelect_Cancel; + Current_Menu = &MPStartUpErrorMenu; + { + int index; + for (index=0; index=0) sprintf(scoreStringsTotal[i],"%.3d",totalScore); + else if(totalScore>=(-99)) sprintf(scoreStringsTotal[i],"%.2d",totalScore); + else sprintf(scoreStringsTotal[i],"%.2d",(-99)); + } + EndNetGame_MenuFItems[(i+(NET_MAXPLAYERS*2))].SecondStringPtr = scoreStringsTotal[i]; + + /* initials for score table ... */ + initialString[i][0] = netGameData.playerData[i].name[0]; + initialString[i][1] = '\0'; + EndNetGame_MenuFItems[(i+(NET_MAXPLAYERS*3))].SecondStringPtr = initialString[i]; + EndNetGame_MenuFItems[(i+(NET_MAXPLAYERS*4))].SecondStringPtr = initialString[i]; + + /* score: player by player... */ + { + int j; + for(j=0;j=0) sprintf(scoreStrings[i][j],"%.3d",thisScore); + else if(thisScore>=(-99)) sprintf(scoreStrings[i][j],"%.2d",thisScore); + else sprintf(scoreStrings[i][j],"%.2d",thisScore); + EndNetGame_MenuFItems[(j+(NET_MAXPLAYERS*(5+i)))].SecondStringPtr = scoreStrings[i][j]; + } + else + { + EndNetGame_MenuFItems[(j+(NET_MAXPLAYERS*(5+i)))].SecondStringPtr = mPBlankString; + } + } + } + } + else + { + /* make sure it's blank... incase this screen has been displayed previously */ + EndNetGame_MenuFItems[i].SecondStringPtr = mPBlankString; + EndNetGame_MenuFItems[(i+NET_MAXPLAYERS)].StringID = TEXTSTRING_BLANK; + EndNetGame_MenuFItems[(i+(NET_MAXPLAYERS*2))].SecondStringPtr = mPBlankString; + EndNetGame_MenuFItems[(i+(NET_MAXPLAYERS*3))].SecondStringPtr = mPBlankString; + EndNetGame_MenuFItems[(i+(NET_MAXPLAYERS*4))].SecondStringPtr = mPBlankString; + { + int j; + for(j=0;j +#include + +#include + + +extern "C" +{ + extern BOOL bActive; + extern int WinLeftX, WinRightX, WinTopY, WinBotY; + +} + +static volatile int EndMouseThread=0; + + + + +//thread continually moves the mouse cursor to the centre of the window +//so you don't accidently click outside it. +void MouseThread(void* ) +{ + while(!EndMouseThread) + { + Sleep(10); + + if(!bActive) continue; + + SetCursorPos((WinLeftX+WinRightX)>>1,(WinTopY+WinBotY)>>1); + + + } + EndMouseThread=0; +} + + + +extern "C" +{ + + +void InitCentreMouseThread() +{ + _beginthread(MouseThread,10000,0); +} + + +void FinishCentreMouseThread() +{ + EndMouseThread=1; +} + + + +}; + + diff --git a/3dc/avp/win95/NPCSETUP.CPP b/3dc/avp/win95/NPCSETUP.CPP new file mode 100644 index 0000000..958769b --- /dev/null +++ b/3dc/avp/win95/NPCSETUP.CPP @@ -0,0 +1,656 @@ +#include "npcsetup.h" +#include "ourasert.h" +#include "list_tem.hpp" +#include "chunkpal.hpp" +#include "chnkload.hpp" +#include "projload.hpp" +#include "envchunk.hpp" +#include "avpchunk.hpp" +#include "strachnk.hpp" +#include "gamedef.h" +#include "progress_bar.h" +#include "scream.h" +#include "avp_menus.h" + + +#if ALIEN_DEMO +#define DIRECTORY_FOR_RIFS "alienavp_huds\\" +#else +#define DIRECTORY_FOR_RIFS "avp_huds\\" +#endif +#define FIRST_FREE_IMAGE_GROUP 3 // 0 for char,1 for weapon rif ,2 for env + +#if debug +extern "C" +{ + BOOL ForceLoad_Alien=FALSE; + BOOL ForceLoad_Marine=FALSE; + BOOL ForceLoad_Predator=FALSE; + BOOL ForceLoad_Hugger=FALSE; + BOOL ForceLoad_Queen=FALSE; + BOOL ForceLoad_Civvie=FALSE; + BOOL ForceLoad_PredAlien=FALSE; + BOOL ForceLoad_Xenoborg=FALSE; + BOOL ForceLoad_Pretorian=FALSE; + BOOL ForceLoad_SentryGun=FALSE; + + extern BOOL KeepMainRifFile; + +}; +#endif + +static char Marine_File[]= "hnpcmarine.rif"; +static char Alien_File[]= "hnpcalien.rif"; +static char Predator_File[]= "hnpcpredator.rif"; +static char Hugger_File[]= "hnpchugger.rif"; +static char AlienQueen_File[]= "queen.rif"; +static char Civilian_File[]= "hnpc_civvie.rif"; +static char PredAlien_File[]= "hnpcpred_alien.rif"; +static char Xenoborg_File[]= "hnpc_xenoborg.rif"; +static char Pretorian_File[]= "hnpcpretorian.rif"; +static char SentryGun_File[]= "sentry.rif"; + +static char* HNPC_FileNames[]= +{ + &Marine_File[0], + &Alien_File[0], + &Predator_File[0], + &Hugger_File[0], + &AlienQueen_File[0], + &Civilian_File[0], + &PredAlien_File[0], + &Xenoborg_File[0], + &Pretorian_File[0], + &SentryGun_File[0], +}; + +typedef enum +{ + HNPC_Marine, + HNPC_Alien, + HNPC_Predator, + HNPC_Hugger, + HNPC_AlienQueen, + HNPC_Civilian, + HNPC_PredAlien, + HNPC_Xenoborg, + HNPC_Pretorian, + HNPC_SentryGun, + HNPC_Last, +}HNPC_Files; + +static BOOL Load_HNPC[HNPC_Last]; + + +class LoadedNPC +{ +public: + LoadedNPC(RIF_Child_Chunk const *); + LoadedNPC(char const *); + LoadedNPC(); + LoadedNPC(LoadedNPC const &); + ~LoadedNPC(); + LoadedNPC & operator = (LoadedNPC const &); + + void Load(int progress_start,int progress_interval); + void Unload(); // not called automatically + inline int IsValid() + { return filename ? 1 : 0; } + + int operator == (LoadedNPC const &) const; + inline int operator != (LoadedNPC const & npc2) const + { return ! operator == (npc2); } + +private: + char * rifname; + char * filename; + int img_group; + + RIFFHANDLE npc_rif; + static List image_groups; +}; + +List loaded_npcs; + +LoadedNPC::LoadedNPC(RIF_Child_Chunk const * rcc) +: rifname(0) +, filename(0) +, npc_rif(INVALID_RIFFHANDLE) +, img_group(-1) +{ + if (rcc->filename && *rcc->filename) + { + char const * fnptr = rcc->filename; + if (strchr(fnptr,'\\')) fnptr = strrchr(fnptr,'\\')+1; + if (strchr(fnptr,'/')) fnptr = strrchr(fnptr,'/')+1; + if (strchr(fnptr,':')) fnptr = strrchr(fnptr,':')+1; + + if (!_strnicmp(fnptr,"npc",3) || + !_strnicmp (fnptr, "hnpc", 4) || + !_strnicmp (fnptr, "loof", 4) || + !_strnicmp (fnptr, "marwep", 6) || + !_strnicmp (fnptr, "pred_hud", 8) || + !_strnicmp (fnptr, "bmantest", 8) + ) // all thes files names start with 'npc' + { + filename = new char[strlen(DIRECTORY_FOR_RIFS)+strlen(fnptr)+1]; + strcpy(filename,DIRECTORY_FOR_RIFS); + strcat(filename,fnptr); + + rifname = new char[strlen(rcc->rifname)+1]; + strcpy(rifname,rcc->rifname); + } + } +} +LoadedNPC::LoadedNPC(char const * name) +: rifname(0) +, filename(0) +, npc_rif(INVALID_RIFFHANDLE) +, img_group(-1) +{ + if (name && *name) + { + char const * fnptr = name; + if (strchr(fnptr,'\\')) fnptr = strrchr(fnptr,'\\')+1; + if (strchr(fnptr,'/')) fnptr = strrchr(fnptr,'/')+1; + if (strchr(fnptr,':')) fnptr = strrchr(fnptr,':')+1; + + filename = new char[strlen(DIRECTORY_FOR_RIFS)+strlen(fnptr)+1]; + strcpy(filename,DIRECTORY_FOR_RIFS); + strcat(filename,fnptr); + + rifname = new char[strlen(name)+1]; + strcpy(rifname,name); + + } +} + +LoadedNPC::LoadedNPC() +: rifname(0) +, filename(0) +, npc_rif(INVALID_RIFFHANDLE) +, img_group(-1) +{ +} + +LoadedNPC::LoadedNPC(LoadedNPC const & npc2) +: rifname(npc2.rifname ? new char[strlen(npc2.rifname)+1] : 0) +, filename(npc2.filename ? new char[strlen(npc2.filename)+1] : 0) +, npc_rif(npc2.npc_rif) +, img_group(npc2.img_group) +{ + if (rifname) strcpy(rifname,npc2.rifname); + if (filename) strcpy(filename,npc2.filename); +} + +LoadedNPC::~LoadedNPC() +{ + if (rifname) delete[] rifname; + if (filename) delete[] filename; +} + +LoadedNPC & LoadedNPC::operator = (LoadedNPC const & npc2) +{ + if (&npc2 != this) + { + if (rifname) delete[] rifname; + if (filename) delete[] filename; + + rifname = npc2.rifname ? new char[strlen(npc2.rifname)+1] : 0; + filename = npc2.filename ? new char[strlen(npc2.filename)+1] : 0; + img_group = npc2.img_group; + npc_rif = npc2.npc_rif; + + if (rifname) strcpy(rifname,npc2.rifname); + if (filename) strcpy(filename,npc2.filename); + } + return *this; +} + +int LoadedNPC::operator == (LoadedNPC const & npc2) const +{ + return !_stricmp(rifname ? rifname : "",npc2.rifname ? npc2.rifname : ""); +} + +void LoadedNPC::Load(int progress_start,int progress_interval) +{ + Set_Progress_Bar_Position(progress_start); + if (filename) + { + npc_rif = avp_load_rif_non_env(filename); + if (INVALID_RIFFHANDLE != npc_rif) + { + #if MaxImageGroups>1 + for (img_group=FIRST_FREE_IMAGE_GROUP; image_groups.contains(img_group); ++img_group) + ; + GLOBALASSERT(img_group1 + image_groups.delete_entry(img_group); + SetCurrentImageGroup(img_group); + DeallocateCurrentImages(); + #endif + avp_undo_rif_load(npc_rif); // destroys copied shapes + } + npc_rif = INVALID_RIFFHANDLE; +} + + +static BOOL MarineIsNomcombatant(AVP_Generator_Chunk* agc) +{ + AVP_Generator_Extra_Data_Chunk* agedc=agc->get_extra_data_chunk(); + if(agedc) + { + AVP_Strategy_Chunk* asc =(AVP_Strategy_Chunk*) agedc->lookup_single_child("AVPSTRAT"); + if(asc) + { + if(asc->Strategy && asc->Strategy->StrategyType==StratEnemy) + { + EnemyStrategy* es=(EnemyStrategy*)asc->Strategy; + if(es->MissionType==3) + { + return TRUE; + } + + } + } + } + return FALSE; +} + + +List LoadedNPC::image_groups; + +extern "C" +{ + extern BOOL Current_Level_Requires_Mirror_Image(); +}; +void InitNPCs(RIFFHANDLE h) +{ + + File_Chunk * old_env_chunk = Env_Chunk; // push Env_Chunk + + + // build list of objects for the npcs in this level + + for(int i=0;ienvd)->lookup_single_child("GLOGENDC"); + if(pChunk) + { + Global_Generator_Data_Chunk* ggdc=(Global_Generator_Data_Chunk*)pChunk; + switch(ggdc->EnemyGenerated) + { + case Generate_Aliens : + DefaultGeneratorEnemy=HNPC_Alien; + break; + case Generate_Marines : + DefaultGeneratorEnemy=HNPC_Marine; + break; + default : + GLOBALASSERT("Invalid enemy type"==0); + + } + + } + else + { + DefaultGeneratorEnemy=HNPC_Alien; + } + + if(Current_Level_Requires_Mirror_Image()) + { + //need to load model for player's character , for mirror + switch(AvP.PlayerType) + { + case I_Marine : + Load_HNPC[HNPC_Marine]=TRUE; + break; + + case I_Alien : + Load_HNPC[HNPC_Alien]=TRUE; + break; + + case I_Predator : + Load_HNPC[HNPC_Predator]=TRUE; + break; + } + } + + + + if(AvP.Network != I_No_Network) + { + /* KJL 19:35:46 01/07/98 - multiplayer only needs the 3 main characters */ + Load_HNPC[HNPC_Alien]=TRUE; + Load_HNPC[HNPC_Predator]=TRUE; + Load_HNPC[HNPC_Marine]=TRUE; + } + + + /* KJL 16:31:03 06/05/98 - Force all characters to be loaded + for testing of 'bots etc. */ + + #if 0 //characters can now be loaded with command line options + Load_HNPC[HNPC_Alien]=TRUE; + Load_HNPC[HNPC_Predator]=TRUE; + Load_HNPC[HNPC_Marine]=TRUE; + Load_HNPC[HNPC_PredAlien] =TRUE; + #endif + + Special_Objects_Chunk * soc = 0; + soc = (Special_Objects_Chunk *)((Chunk_With_Children*)h->envd)->lookup_single_child ("SPECLOBJ"); + + if (soc) + { + List cl; + soc->lookup_child("AVPGENER",cl); + for (LIF cli(&cl); !cli.done(); cli.next()) + { + AVP_Generator_Chunk * agc = (AVP_Generator_Chunk *)cli(); + + if (agc->type) + { + #if 0 //forget about game mode settings for generators / badguys + if(AvP.PlayerType==I_Alien && (agc->flags & AVPGENFLAG_AVPGAMEMODEALIEN)|| + AvP.PlayerType==I_Marine && (agc->flags & AVPGENFLAG_AVPGAMEMODEMARINE)|| + AvP.PlayerType==I_Predator && (agc->flags & AVPGENFLAG_AVPGAMEMODEPREDATOR)) + #endif + { + switch (agc->type) + { + case 1: + Load_HNPC[HNPC_Alien]=TRUE; + break; + case 2: + if(AvP.Network == I_No_Network) + Load_HNPC[HNPC_Predator]=TRUE; + break; + + case 3: + if(AvP.Network == I_No_Network) + Load_HNPC[HNPC_Hugger]=TRUE; + break; + case 4: + if(AvP.Network == I_No_Network) + Load_HNPC[HNPC_Xenoborg]=TRUE; + break; + case 5: + Load_HNPC[HNPC_PredAlien] =TRUE; + break; + case 6: + if(AvP.Network == I_No_Network) + Load_HNPC[HNPC_AlienQueen]=TRUE; + break; + case 7: //marine or variant of marine + if(AvP.Network == I_No_Network) + { + switch (agc->sub_type) + { + case 0: //pulse rifle + case 5: //pistol marine + case 10: //smartgun + case 20://grenade launcher + case 50://flamethrower + case 60://sadar + case 70://Minigun + Load_HNPC[HNPC_Marine]=TRUE; + if(!Load_HNPC[HNPC_Civilian]) + { + //noncombatant marines become civilians + if(MarineIsNomcombatant(agc)) + { + Load_HNPC[HNPC_Civilian]=TRUE; + + } + } + break; + + + case 30://shotgun 1 + case 31://shotgun 2 + case 32://shotgun 3 + case 40://pistol 1 + case 41://pistol 2 + case 80://Molotov + case 90://Scientist1 + case 91://Scientist2 + case 100://civilian flamer + case 110://civilian unarmed + case 120://android + Load_HNPC[HNPC_Civilian] =TRUE; + break; + + + default: + Load_HNPC[HNPC_Marine]=TRUE; + break; + } + } + break; + case 8: + Load_HNPC[HNPC_Pretorian]=TRUE; + break; + case 9: + if(AvP.Network == I_No_Network) + Load_HNPC[HNPC_SentryGun]=TRUE; + break; + default: + break; + } + + + } + } + else + { + //see if generator is a multiplayer start position + if(agc->flags & AVPGENFLAG_MULTIPLAYERSTART) + { + continue; + } + + //this is a generator , look to see what it generates + AVP_Generator_Extended_Settings_Chunk* setting=agc->get_extended_settings(); + if(setting) + { + BOOL all_zero=TRUE; + if(AvP.Network == I_No_Network) + { + if(setting->weights->PulseMarine_Wt || + setting->weights->PistolMarine_Wt || + setting->weights->FlameMarine_Wt || + setting->weights->SmartMarine_Wt || + setting->weights->SadarMarine_Wt || + setting->weights->GrenadeMarine_Wt || + setting->weights->MinigunMarine_Wt) + { + Load_HNPC[HNPC_Marine]=TRUE; + all_zero=FALSE; + } + if(setting->weights->ShotgunCiv_Wt || + setting->weights->PistolCiv_Wt || + setting->weights->FlameCiv_Wt || + setting->weights->UnarmedCiv_Wt || + setting->weights->MolotovCiv_Wt) + { + Load_HNPC[HNPC_Civilian]=TRUE; + all_zero=FALSE; + } + } + + if(setting->weights->Alien_Wt) + { + Load_HNPC[HNPC_Alien]=TRUE; + all_zero=FALSE; + } + if(setting->weights->PredAlien_Wt) + { + Load_HNPC[HNPC_PredAlien]=TRUE; + all_zero=FALSE; + } + if(setting->weights->Praetorian_Wt) + { + Load_HNPC[HNPC_Pretorian]=TRUE; + all_zero=FALSE; + } + + if(all_zero) + { + //all the weightings are zero , use the default badguy + Load_HNPC[DefaultGeneratorEnemy]=TRUE; + } + + + } + else + { + //no extended generator data , use the default badguy + Load_HNPC[DefaultGeneratorEnemy]=TRUE; + } + } + } + } + + List newnpcs; + + for(i=0;i i_loaded_npc(&loaded_npcs); !i_loaded_npc.done(); ) + { + if (newnpcs.contains(i_loaded_npc())) + { + newnpcs.delete_entry(i_loaded_npc()); + i_loaded_npc.next(); + } + else + { + LoadedNPC tounload(i_loaded_npc()); + tounload.Unload(); + i_loaded_npc.delete_current(); + } + } + + if(!KeepMainRifFile) + { + //at this point we no longer need the main level rif file + unload_rif(h); + } + + // load the new ones, adding them to the main list + int NumToLoad=newnpcs.size(); + int NumLoaded=0; + + if(Load_HNPC[HNPC_Marine] || Load_HNPC[HNPC_Civilian] || AvP.PlayerType==I_Marine) + { + LoadMarineScreamSounds(); + } + if(Load_HNPC[HNPC_Predator] ||AvP.PlayerType==I_Predator) + { + LoadPredatorScreamSounds(); + } + if(Load_HNPC[HNPC_Alien] || Load_HNPC[HNPC_PredAlien]|| Load_HNPC[HNPC_Pretorian] || AvP.PlayerType==I_Alien) + { + LoadAlienScreamSounds(); + } + if(Load_HNPC[HNPC_AlienQueen]) + { + LoadQueenScreamSounds(); + } + + for (LIF i_newnpc(&newnpcs); !i_newnpc.done(); i_newnpc.next()) + { + LoadedNPC toload(i_newnpc()); + toload.Load(PBAR_NPC_START+(PBAR_NPC_INTERVAL*NumLoaded)/NumToLoad,PBAR_NPC_INTERVAL/NumToLoad); + loaded_npcs.add_entry(toload); + NumLoaded++; + } + Set_Progress_Bar_Position(PBAR_NPC_START+PBAR_NPC_INTERVAL); + + if(KeepMainRifFile) + { + Env_Chunk = old_env_chunk; // pop Env_Chunk + } + else + { + Env_Chunk=0; + } +} + +void EndNPCs() +{ + while (loaded_npcs.size()) + { + LoadedNPC tounload(loaded_npcs.first_entry()); + tounload.Unload(); + loaded_npcs.delete_first_entry(); + } + EmptyHierarchyLibrary(); + UnloadScreamSounds(); +} diff --git a/3dc/avp/win95/NPCSETUP.H b/3dc/avp/win95/NPCSETUP.H new file mode 100644 index 0000000..773541a --- /dev/null +++ b/3dc/avp/win95/NPCSETUP.H @@ -0,0 +1,20 @@ +#ifndef _included_npcsetup_h_ +#define _included_npcsetup_h_ + +#include "chnkload.h" /* for RIFFHANDLE type */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* pass handle to environment rif */ +void InitNPCs(RIFFHANDLE); + +/* unload them all after intance of game */ +void EndNPCs(); + +#ifdef __cplusplus +} +#endif + +#endif /* ! _included_npcsetup_h_ */ diff --git a/3dc/avp/win95/OBJSETUP.HPP b/3dc/avp/win95/OBJSETUP.HPP new file mode 100644 index 0000000..3b1e019 --- /dev/null +++ b/3dc/avp/win95/OBJSETUP.HPP @@ -0,0 +1,22 @@ +#ifndef _objsetup_hpp_ +#define _objsetup_hpp_ + +#include "envchunk.hpp" +#include "obchunk.hpp" + +extern "C" { +#include "3dc.h" +void SetUpRunTimeLights (); +void create_strategies_from_list(); +void deallocate_behaviour_list(); +}; + +void deal_with_module_object(Object_Chunk * ob, int shape1, int AnimationShape, int shape2, MODULE * mod); +void deal_with_placed_object(Object_Chunk * ob, int shape1, int AnimationShape); +void setup_generators (Environment_Data_Chunk * envd); +void setup_particle_generators (Environment_Data_Chunk * envd); +void setup_cables (Environment_Data_Chunk * envd); +void DealWithExternalObjectStategies (Environment_Data_Chunk * envd); +void Create_Xenoborg_Morph_Jobby(Object_Chunk * ob, int AnimationShape, MODULE * mod, MORPHCTRL * mc); +void setup_sounds (Environment_Data_Chunk * envd); +#endif \ No newline at end of file diff --git a/3dc/avp/win95/Objsetup.cpp b/3dc/avp/win95/Objsetup.cpp new file mode 100644 index 0000000..10c47bb --- /dev/null +++ b/3dc/avp/win95/Objsetup.cpp @@ -0,0 +1,3837 @@ +#ifdef DAVEW + #define DB_LEVEL 1 +#else + #define DB_LEVEL 1 +#endif + +#include +#include + +#include "list_tem.hpp" +#include "chnkload.hpp" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "envchunk.hpp" +#include "obchunk.hpp" +#include "ltchunk.hpp" +#include "avpchunk.hpp" +#include "strachnk.hpp" +#include "sndchunk.hpp" +#include "pvisible.h" +#include "objsetup.hpp" +#include "hierplace.hpp" + +#include "bh_gener.h" +#include "bh_swdor.h" +#include "bh_ldoor.h" +#include "bh_plift.h" +#include "bh_pred.h" +#include "bh_fhug.h" +#include "bh_marin.h" +#include "bh_paq.h" +#include "bh_queen.h" +#include "bh_alien.h" +#include "bh_xeno.h" +#include "bh_binsw.h" +#include "bh_lnksw.h" +#include "bh_spcl.h" +#include "bh_agun.h" +#include "bh_lift.h" +#include "bh_ltfx.h" +#include "bh_snds.h" +#include "bh_mission.h" +#include "bh_track.h" +#include "bh_fan.h" +#include "bh_light.h" +#include "bh_plachier.h" +#include "bh_cable.h" +#include "bh_deathvol.h" +#include "bh_selfdest.h" +#include "bh_pargen.h" +#include "bh_videoscreen.h" +#include "missions.hpp" +#include "track.h" +#include "psndplat.h" + +#include "dxlog.h" +#include "mempool.h" +#include "db.h" + +#include "pldnet.h" + +extern "C" { +#include "3dc.h" +extern int cosine[]; +extern MAPSETVDB chnk_playcam_vdb; +extern int GlobalAmbience; +extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; +extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; +}; + +static void get_marine_facing_point(VECTORCH& pos,EULER& euler,VECTORCH& facing_point); + +//if this number is non-negative , use this value for all random location dierolls +extern "C" +{ +int QuantumObjectDieRollOveride=-1; +}; + +struct BehaviourBlockData +{ + AVP_BEHAVIOUR_TYPE sb_type; + ObjectID id; + int shapeindex; + void *bhdata; + char* name; + + unsigned int diff_easy :1; + unsigned int diff_medium :1; + unsigned int diff_hard :1; + + //alternative locations for 'quantum objects' + int num_locations; + int location_group; + VECTORCH* alt_vector; + EULER* alt_euler; +}; + +struct LocationGroupDieRoll +{ + int group; + int roll; +}; + +static List Behav_List; +static List DieRoll_List; + +const char * light_set_name = "NORMALLT"; + +BOOL Xenoborg_Morph_Thingy = 0; +XENO_MORPH_ROOM_TOOLS_TEMPLATE xmrtt; + + +extern char* Rif_Sound_Directory; + +LOADED_SOUND const * GetSoundForMainRif(const char* wav_name) +{ + static char filename[200]; + if(Rif_Sound_Directory) + { + sprintf(filename,"%s\\%s",Rif_Sound_Directory,wav_name); + return GetSound(filename); + } + else + { + return GetSound(wav_name); + } + +} + +void setup_track_sound(Indexed_Sound_Chunk* s_chunk,TRACK_SOUND** ts) +{ + *ts=0; + if(!s_chunk) return; + + + LOADED_SOUND const * ls=GetSoundForMainRif(s_chunk->wav_name); + if(ls) + { + TRACK_SOUND* sound=(TRACK_SOUND*)PoolAllocateMem(sizeof(TRACK_SOUND)); + + sound->sound_loaded=ls; + sound->inner_range=s_chunk->inner_range*local_scale; + sound->outer_range=s_chunk->outer_range*local_scale; + sound->pitch=s_chunk->pitch; + sound->max_volume=s_chunk->max_volume; + sound->activ_no=SOUND_NOACTIVEINDEX; + sound->playing=0; + + if(s_chunk->flags & IndexedSoundFlag_Loop) + sound->loop=1; + else + sound->loop=0; + + *ts=sound; + } +} + +void setup_track_sound(Object_Chunk* oc,TRACK_SOUND** start_sound,TRACK_SOUND** mid_sound,TRACK_SOUND** end_sound) +{ + if(start_sound)*start_sound=0; + if(mid_sound)*mid_sound=0; + if(end_sound)*end_sound=0; + + db_logf3(("Setting up track sound")); + + List chlist; + oc->lookup_child("TRAKSOUN",chlist); + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + Object_Track_Sound_Chunk* otsc=(Object_Track_Sound_Chunk*)chlif(); + TRACK_SOUND** sound_ptr; + + switch(otsc->index) + { + case 0: + sound_ptr=mid_sound; + break; + case 1: + sound_ptr=start_sound; + break; + case 2: + sound_ptr=end_sound; + break; + } + if(!sound_ptr) continue; + if(*sound_ptr) continue; + + + db_logf3(("Getting %s",otsc->wav_name)); + LOADED_SOUND const * ls=GetSoundForMainRif(otsc->wav_name); + db_logf3(("Finished getting %s",otsc->wav_name)); + if(ls) + { + + TRACK_SOUND* sound=(TRACK_SOUND*)PoolAllocateMem(sizeof(TRACK_SOUND)); + + sound->sound_loaded=ls; + sound->inner_range=otsc->inner_range*local_scale; + sound->outer_range=otsc->outer_range*local_scale; + sound->pitch=otsc->pitch; + sound->max_volume=otsc->max_volume; + sound->activ_no=SOUND_NOACTIVEINDEX; + sound->playing=0; + + if(otsc->flags & TrackSoundFlag_Loop) + sound->loop=1; + else + sound->loop=0; + + *sound_ptr=sound; + } + + } +} + +TRACK_CONTROLLER* setup_track_controller(Object_Chunk* oc) +{ + Object_Track_Chunk2* otc=(Object_Track_Chunk2*)oc->lookup_single_child("OBJTRAK2"); + if(!otc) return 0; + + + + TRACK_CONTROLLER* tc=(TRACK_CONTROLLER*)PoolAllocateMem(sizeof(TRACK_CONTROLLER)); + + tc->sbptr=0; + tc->playing=0; + tc->playing_start_sound=0; + tc->reverse=0; + tc->loop=0; + tc->loop_backandforth=0; + tc->no_rotation=1; + tc->timer=otc->timer_start; + tc->current_section=0; + tc->use_speed_mult=0; + tc->speed_mult=0; + + GLOBALASSERT(otc->num_sections); + + tc->num_sections=otc->num_sections; + + tc->sections=(TRACK_SECTION_DATA*)PoolAllocateMem(sizeof(TRACK_SECTION_DATA)*otc->num_sections); + + QUAT quat_start; + quat_start.quatx=(int)-(otc->sections[0].quat_start.x*ONE_FIXED); + quat_start.quaty=(int)-(otc->sections[0].quat_start.x*ONE_FIXED); + quat_start.quatz=(int)-(otc->sections[0].quat_start.x*ONE_FIXED); + quat_start.quatw=(int)(otc->sections[0].quat_start.x*ONE_FIXED); + + for(int i=0;inum_sections;i++) + { + TRACK_SECTION_DATA* tsd=&tc->sections[i]; + ChunkTrackSection* cts=&otc->sections[i]; + + tsd->quat_start.quatx=(int)-(cts->quat_start.x*ONE_FIXED); + tsd->quat_start.quaty=(int)-(cts->quat_start.y*ONE_FIXED); + tsd->quat_start.quatz=(int)-(cts->quat_start.z*ONE_FIXED); + tsd->quat_start.quatw=(int)(cts->quat_start.w*ONE_FIXED); + + tsd->quat_end.quatx=(int)-(cts->quat_end.x*ONE_FIXED); + tsd->quat_end.quaty=(int)-(cts->quat_end.y*ONE_FIXED); + tsd->quat_end.quatz=(int)-(cts->quat_end.z*ONE_FIXED); + tsd->quat_end.quatw=(int)(cts->quat_end.w*ONE_FIXED); + + if(tsd->quat_start.quatx!=quat_start.quatx|| + tsd->quat_start.quaty!=quat_start.quaty|| + tsd->quat_start.quatz!=quat_start.quatz|| + tsd->quat_start.quatw!=quat_start.quatw) + { + tc->no_rotation=0; + } + if(tsd->quat_end.quatx!=quat_start.quatx|| + tsd->quat_end.quaty!=quat_start.quaty|| + tsd->quat_end.quatz!=quat_start.quatz|| + tsd->quat_end.quatw!=quat_start.quatw) + { + tc->no_rotation=0; + } + + + + tsd->pivot_start=cts->pivot_start*local_scale; + tsd->pivot_travel=(cts->pivot_end-cts->pivot_start)*local_scale; + tsd->object_offset=cts->object_offset*local_scale; + + tsd->time_for_section=cts->time_for_section; + } + + if(otc->flags & TrackFlag_Loop) + tc->loop=1; + else if(otc->flags & TrackFlag_LoopBackAndForth) + tc->loop_backandforth=1; + + + if(otc->flags & TrackFlag_PlayingAtStart) + tc->playing=1; + + + setup_track_sound(oc,&tc->start_sound,&tc->sound,&tc->end_sound); + + if(tc->sound) + { + tc->sound->playing=tc->playing; + } + + /* KJL 14:29:09 24/03/98 - addition for smooth tracks */ + if(otc->flags & TrackFlag_UseTrackSmoothing && tc->num_sections>=3) + tc->use_smoothing = 1; + else + tc->use_smoothing = 0; + + Preprocess_Track_Controller(tc); + + //set the initial state entries + tc->initial_state_timer=tc->timer; + tc->initial_state_playing=tc->playing; + tc->initial_state_reverse=tc->reverse; + + + return tc; + +} + +static int get_location_group_die_roll(int group) +{ + //see if a vaule has already been rolled for this group + for(LIF dlif(&DieRoll_List);!dlif.done();dlif.next()) + { + if(dlif()->group==group) + { + //found the group , so return its roll + return dlif()->roll; + } + } + //need to roll a new value for this group + LocationGroupDieRoll* loc_group=new LocationGroupDieRoll; + loc_group->group=group; + loc_group->roll=FastRandom() & 0xffff; + DieRoll_List.add_entry(loc_group); + + return loc_group->roll; +} + +static void clear_location_group_die_roll_list() +{ + while(DieRoll_List.size()) + { + delete DieRoll_List.first_entry(); + DieRoll_List.delete_first_entry(); + } +} + + + +static void select_alternate_location(BehaviourBlockData* bbd) +{ + GLOBALASSERT (bbd); + if(bbd->num_locations<2) return; + + int dieroll=0; + if(QuantumObjectDieRollOveride>=0) + { + dieroll=QuantumObjectDieRollOveride; + } + else + { + if(bbd->location_group) + { + dieroll=get_location_group_die_roll(bbd->location_group); + } + else + { + dieroll=FastRandom() & 0xffff; + } + } + + dieroll=dieroll%bbd->num_locations; + + VECTORCH* chosen_pos=&bbd->alt_vector[dieroll]; + EULER* chosen_euler=&bbd->alt_euler[dieroll]; + + switch(bbd->sb_type) + { + case I_BehaviourInanimateObject : + { + TOOLS_DATA_INANIMATEOBJECT* tdio=(TOOLS_DATA_INANIMATEOBJECT*) bbd->bhdata; + tdio->position=*chosen_pos; + tdio->orientation=*chosen_euler; + break; + } + + case I_BehaviourVideoScreen : + { + TOOLS_DATA_VIDEO_SCREEN* tdvs=(TOOLS_DATA_VIDEO_SCREEN*) bbd->bhdata; + tdvs->position=*chosen_pos; + tdvs->orientation=*chosen_euler; + break; + } + + + case I_BehaviourPlacedSound : + { + SOUND_TOOLS_TEMPLATE* stt=(SOUND_TOOLS_TEMPLATE*) bbd->bhdata; + stt->position = *chosen_pos; + break; + } + + case I_BehaviourGenerator : + { + GENERATOR_BLOCK* tdg =(GENERATOR_BLOCK*) bbd->bhdata; + tdg->Position=*chosen_pos; + break; + } + + case I_BehaviourAlien : + { + TOOLS_DATA_ALIEN* tda=(TOOLS_DATA_ALIEN*) bbd->bhdata; + tda->position=*chosen_pos; + tda->starteuler=*chosen_euler; + break; + } + + case I_BehaviourMarine : + { + TOOLS_DATA_MARINE* tdm=(TOOLS_DATA_MARINE*) bbd->bhdata; + tdm->position=*chosen_pos; + get_marine_facing_point(*chosen_pos,*chosen_euler,tdm->facing_point); + break; + } + + case I_BehaviourDormantPredator : + case I_BehaviourPredator : + { + TOOLS_DATA_PREDATOR* tdp=(TOOLS_DATA_PREDATOR*) bbd->bhdata; + tdp->position=*chosen_pos; + break; + } + + case I_BehaviourQueenAlien : + { + TOOLS_DATA_QUEEN* tdq=(TOOLS_DATA_QUEEN*) bbd->bhdata; + tdq->position=*chosen_pos; + break; + } + + case I_BehaviourFaceHugger : + { + TOOLS_DATA_FACEHUGGER* tdf=(TOOLS_DATA_FACEHUGGER*) bbd->bhdata; + tdf->position=*chosen_pos; + break; + } + + case I_BehaviourAutoGun : + { + AUTOGUN_TOOLS_TEMPLATE* tda=(AUTOGUN_TOOLS_TEMPLATE*) bbd->bhdata; + tda->position=*chosen_pos; + tda->orientation=*chosen_euler; + break; + } + + case I_BehaviourXenoborg : + { + TOOLS_DATA_XENO* tdx=(TOOLS_DATA_XENO*) bbd->bhdata; + tdx->position=*chosen_pos; + tdx->starteuler=*chosen_euler; + break; + } + + case I_BehaviourParticleGenerator : + { + PARTICLE_GENERATOR_TOOLS_TEMPLATE* part_temp=(PARTICLE_GENERATOR_TOOLS_TEMPLATE*) bbd->bhdata; + part_temp->position=*chosen_pos; + MATRIXCH m; + CreateEulerMatrix(chosen_euler,&m); + TransposeMatrixCH(&m); + + part_temp->orientation=m; + break; + } + } +} + +void create_strategies_from_list () +{ + for(LIF blif(&Behav_List);!blif.done();blif.next()) + { + BehaviourBlockData* bbd=blif(); + + //is the strategy required by the current difficulty level? + switch(AvP.Difficulty) + { + case I_Easy : + if(!bbd->diff_easy) continue; + break; + case I_Medium : + if(!bbd->diff_medium) continue; + break; + case I_Hard : + case I_Impossible : + if(!bbd->diff_hard) continue; + break; + } + + if(AvP.Network != I_No_Network && !AvP.NetworkAIServer) + { + //if this is a network game , and we aren't the ai host , then we shouldn't set up + //any aliens + if(bbd->sb_type==I_BehaviourAlien) continue; + } + + //if this is a quantum object , need to select location + select_alternate_location(bbd); + + STRATEGYBLOCK * sbPtr; + sbPtr = CreateActiveStrategyBlock(); + + if(!sbPtr) + { + GLOBALASSERT(0=="Run out of strategy blocks"); + } + + InitialiseSBValues(sbPtr); + sbPtr->I_SBtype = bbd->sb_type; + sbPtr->shapeIndex=bbd->shapeindex; + sbPtr->SBflags.preserve_until_end_of_level=1; + if(bbd->name) + { + sbPtr->name=bbd->name; + } + *(ObjectID*)&sbPtr->SBname[0]=bbd->id; + + EnableBehaviourType(sbPtr, bbd->sb_type, bbd->bhdata ); + + } + //get rid of stored list of rolls for quantum object groups + clear_location_group_die_roll_list(); +} + +void AddToBehaviourList(const char* name,const ObjectID &ID,AVP_BEHAVIOUR_TYPE sb_type,void* bhdata,int shapeindex=-1,Object_Alternate_Locations_Chunk* loc_chunk=0,int flags=0) +{ + BehaviourBlockData* bbd=(BehaviourBlockData*) PoolAllocateMem(sizeof(BehaviourBlockData)); + bbd->sb_type=sb_type; + bbd->bhdata=bhdata; + bbd->id=ID; + bbd->shapeindex=shapeindex; + + bbd->diff_easy=1; + bbd->diff_medium=1; + bbd->diff_hard=1; + + if(name) + { + bbd->name=(char*) PoolAllocateMem(strlen(name)+1); + strcpy(bbd->name,name); + } + else + { + bbd->name=0; + } + + if(loc_chunk && loc_chunk->num_locations>=2) + { + bbd->num_locations=loc_chunk->num_locations; + bbd->location_group=loc_chunk->group; + bbd->alt_vector=(VECTORCH*) PoolAllocateMem(bbd->num_locations*sizeof(VECTORCH)); + bbd->alt_euler=(EULER*) PoolAllocateMem(bbd->num_locations*sizeof(EULER)); + for(int i=0;inum_locations;i++) + { + bbd->alt_vector[i]=loc_chunk->locations[i].position*local_scale; + + QUAT q; + + q.quatx = (int) -(loc_chunk->locations[i].orientation.x*ONE_FIXED); + q.quaty = (int) -(loc_chunk->locations[i].orientation.y*ONE_FIXED); + q.quatz = (int) -(loc_chunk->locations[i].orientation.z*ONE_FIXED); + q.quatw = (int) (loc_chunk->locations[i].orientation.w*ONE_FIXED); + + + MATRIXCH m; + + QuatToMat (&q, &m); + + MatrixToEuler(&m, &bbd->alt_euler[i]); + } + } + else + { + bbd->num_locations=0; + bbd->location_group=0; + bbd->alt_vector=0; + bbd->alt_euler=0; + } + + if(flags) + { + //see which difficulty levels this object is used for + bbd->diff_easy=(flags & OBJECT_FLAG_NOTDIFFICULTY1)==0; + bbd->diff_medium=(flags & OBJECT_FLAG_NOTDIFFICULTY2)==0; + bbd->diff_hard=(flags & OBJECT_FLAG_NOTDIFFICULTY3)==0; + } + + Behav_List.add_entry(bbd); +} + +void deallocate_behaviour_list() +{ + while(Behav_List.size()) + { + BehaviourBlockData* bbd=Behav_List.first_entry(); + + switch(bbd->sb_type) + { + case I_BehaviourMissionComplete : + { + MISSION_COMPLETE_TOOLS_TEMPLATE* mctt=(MISSION_COMPLETE_TOOLS_TEMPLATE*)bbd->bhdata; + if(mctt->mission_objective_ptr) + { + delete mctt->mission_objective_ptr; + } + + } + break; + #if !NEW_DEALLOCATION_ORDER + case I_BehaviourLinkSwitch: + { + LINK_SWITCH_TOOLS_TEMPLATE* lstt=(LINK_SWITCH_TOOLS_TEMPLATE*)bbd->bhdata; + if(lstt->track) + { + Deallocate_Track(lstt->track); + } + #if !USE_LEVEL_MEMORY_POOL + DeallocateMem (lstt->targets); + if(lstt->switchIDs) + { + DeallocateMem (lstt->switchIDs); + } + #endif + } + break; + + case I_BehaviourBinarySwitch : + { + BIN_SWITCH_TOOLS_TEMPLATE* bstt=(BIN_SWITCH_TOOLS_TEMPLATE*)bbd->bhdata; + #if !USE_LEVEL_MEMORY_POOL + DeallocateMem(bstt->target_names); + DeallocateMem(bstt->request_messages); + #endif + + if(bstt->track) + { + Deallocate_Track(bstt->track); + } + } + break; + + case I_BehaviourPlacedSound : + { + SOUND_TOOLS_TEMPLATE* stt=(SOUND_TOOLS_TEMPLATE*)bbd->bhdata; + #if !USE_LEVEL_MEMORY_POOL + DeallocateMem(stt->sound_name); + #endif + if(stt->sound_loaded) + { + LoseSound(stt->sound_loaded); + } + } + break; + + case I_BehaviourTrackObject : + { + TRACK_OBJECT_TOOLS_TEMPLATE* tott=(TRACK_OBJECT_TOOLS_TEMPLATE*)bbd->bhdata; + if(tott->track) + { + Deallocate_Track(tott->track); + } + #if !USE_LEVEL_MEMORY_POOL + if(tott->special_track_points) + { + int i; + for(i=0;inum_special_track_points;i++) + { + if(tott->special_track_points[i].targets) + DeallocateMem(tott->special_track_points[i].targets); + } + DeallocateMem(tott->special_track_points); + } + #endif + } + break; + + case I_BehaviourFan : + { + FAN_TOOLS_TEMPLATE* ftt=(FAN_TOOLS_TEMPLATE*)bbd->bhdata; + if(ftt->track) + { + Deallocate_Track(ftt->track); + } + } + break; + + + case I_BehaviourPlatform : + { + PLATFORMLIFT_TOOLS_TEMPLATE* pltt=(PLATFORMLIFT_TOOLS_TEMPLATE*)bbd->bhdata; + if(pltt->start_sound) + { + Deallocate_Track_Sound(pltt->start_sound); + } + if(pltt->sound) + { + Deallocate_Track_Sound(pltt->sound); + } + if(pltt->end_sound) + { + Deallocate_Track_Sound(pltt->end_sound); + } + } + break; + + case I_BehaviourParticleGenerator : + { + PARTICLE_GENERATOR_TOOLS_TEMPLATE* pgtt=(PARTICLE_GENERATOR_TOOLS_TEMPLATE*)bbd->bhdata; + if(pgtt->sound) + { + Deallocate_Track_Sound(pgtt->sound); + } + } + break; + + + #if !USE_LEVEL_MEMORY_POOL + case I_BehaviourPlacedLight : + { + TOOLS_DATA_PLACEDLIGHT * pltt=(TOOLS_DATA_PLACEDLIGHT*)bbd->bhdata; + if(pltt->light) + { + DeallocateMem(pltt->light); + } + } + break; + #endif + + case I_BehaviourPlacedHierarchy : + { + PLACED_HIERARCHY_TOOLS_TEMPLATE* phtt=(PLACED_HIERARCHY_TOOLS_TEMPLATE*)bbd->bhdata; + int i; + #if !USE_LEVEL_MEMORY_POOL + if(phtt->num_sequences) + { + for(i=0;inum_sequences;i++) + { + if(phtt->sequences[i].sound_times) + { + DeallocateMem(phtt->sequences[i].sound_times); + } + } + DeallocateMem(phtt->sequences); + } + #endif + for(i=0;inum_sounds;i++) + { + if(phtt->sounds[i].sound_loaded) + { + LoseSound(phtt->sounds[i].sound_loaded); + } + } + #if !USE_LEVEL_MEMORY_POOL + if(phtt->sounds) + { + DeallocateMem(phtt->sounds); + } + + if(phtt->special_track_points) + { + int i; + for(i=0;inum_special_track_points;i++) + { + if(phtt->special_track_points[i].targets) + DeallocateMem(phtt->special_track_points[i].targets); + } + DeallocateMem(phtt->special_track_points); + } + #endif + + } + #endif //!NEW_DEALLOCATION_ORDER + } + + #if !USE_LEVEL_MEMORY_POOL + if(bbd->alt_vector) DeallocateMem(bbd->alt_vector); + if(bbd->alt_euler) DeallocateMem(bbd->alt_euler); + if(bbd->name) DeallocateMem(bbd->name); + DeallocateMem(bbd->bhdata); + DeallocateMem(bbd); + #endif + Behav_List.delete_first_entry(); + } +} + +static void add_simple_animation (Object_Chunk * ob, int list_pos, MODULE * mod) +{ + SIMPLE_ANIM_TOOLS_TEMPLATE * satt =(SIMPLE_ANIM_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(SIMPLE_ANIM_TOOLS_TEMPLATE)); + + satt->shape_num = list_pos; + if (mod) + { + *((int *)satt->my_module.mref_name) = *((int *)mod->m_name); + } + else + { + *((int *)satt->my_module.mref_name) = 0; + } + *((ObjectID *)satt->nameID) = ob->object_data.ID; + + AddToBehaviourList(ob->object_data.o_name,ob->object_data.ID, I_BehaviourSimpleAnimation, (void*)satt,list_pos); +} + + +static void add_default_object(Object_Chunk * ob, int list_pos) +{ + + TOOLS_DATA_INANIMATEOBJECT* tdio =(TOOLS_DATA_INANIMATEOBJECT*) PoolAllocateMem(sizeof(TOOLS_DATA_INANIMATEOBJECT)); + + tdio->position.vx = ob->object_data.location.x * local_scale; + tdio->position.vy = ob->object_data.location.y * local_scale; + tdio->position.vz = ob->object_data.location.z * local_scale; + + QUAT q; + + q.quatx = (int) -(ob->object_data.orientation.x*ONE_FIXED); + q.quaty = (int) -(ob->object_data.orientation.y*ONE_FIXED); + q.quatz = (int) -(ob->object_data.orientation.z*ONE_FIXED); + q.quatw = (int) (ob->object_data.orientation.w*ONE_FIXED); + + + MATRIXCH m; + + QuatToMat (&q, &m); + + MatrixToEuler(&m, &tdio->orientation); + + tdio->triggering_event=0; + tdio->typeId = IOT_Furniture; + tdio->subType = 0; + tdio->shapeIndex = list_pos; + tdio->mass=5; + tdio->integrity=2; + tdio->explosionType=0; + + AddToBehaviourList(ob->object_data.o_name,ob->object_data.ID, I_BehaviourInanimateObject, (void*)tdio,list_pos,0,ob->get_header()->flags); +} + +static void add_trackobject(Object_Chunk* ob, int list_pos,AVP_Strategy_Chunk* asc) +{ + + TRACK_CONTROLLER* track=setup_track_controller(ob); + if(!track) + { + LOGDXFMT(("%s has no track\n",ob->object_data.o_name)); + GLOBALASSERT(track); + } + + TrackStrategy* ts=(TrackStrategy*) asc->Strategy; + + TRACK_OBJECT_TOOLS_TEMPLATE* tott=(TRACK_OBJECT_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(TRACK_OBJECT_TOOLS_TEMPLATE)); + + *(ObjectID*)&tott->nameID[0]=ob->object_data.ID; + + tott->position.vx = ob->object_data.location.x * local_scale; + tott->position.vy = ob->object_data.location.y * local_scale; + tott->position.vz = ob->object_data.location.z * local_scale; + + QUAT q; + + q.quatx = (int) -(ob->object_data.orientation.x*ONE_FIXED); + q.quaty = (int) -(ob->object_data.orientation.y*ONE_FIXED); + q.quatz = (int) -(ob->object_data.orientation.z*ONE_FIXED); + q.quatw = (int) (ob->object_data.orientation.w*ONE_FIXED); + + + MATRIXCH m; + + QuatToMat (&q, &m); + + MatrixToEuler(&m, &tott->orientation); + + tott->shape_num = list_pos; + + tott->track=track; + + tott->num_special_track_points=ts->num_point_effects; + if(ts->num_point_effects) + { + tott->special_track_points=(SPECIAL_TRACK_POINT*)PoolAllocateMem(sizeof(SPECIAL_TRACK_POINT)*ts->num_point_effects); + for(int i=0;inum_point_effects;i++) + { + SPECIAL_TRACK_POINT* stp=&tott->special_track_points[i]; + TrackPointEffect* tpe=ts->point_effects[i]; + + stp->track_point_no=tpe->point_no; + stp->num_targets=tpe->num_targets; + + if(stp->num_targets) + { + stp->targets=(TRACK_POINT_TARGET*)PoolAllocateMem(sizeof(TRACK_POINT_TARGET)*stp->num_targets); + for(int j=0;jnum_targets;j++) + { + stp->targets[j].request=tpe->targets[j].request; + stp->targets[j].flags=tpe->targets[j].flags; + *(ObjectID*)&stp->targets[j].target_name[0]=tpe->targets[j].targetID; + } + + } + else + stp->targets=0; + } + } + else + tott->special_track_points=0; + + if(ts->StrategyType==StratTrackDestruct) + { + TrackDestructStrategy* tds=(TrackDestructStrategy*)ts; + tott->integrity=tds->integrity; + tott->destruct_target_request=tds->target_request; + *(ObjectID*)tott->destruct_target_ID=tds->targetID; + } + else + { + tott->integrity=21; + tott->destruct_target_request=0; + ObjectID ID0={0,0}; + *(ObjectID*)tott->destruct_target_ID=ID0; + } + + AddToBehaviourList(ob->object_data.o_name,ob->object_data.ID, I_BehaviourTrackObject, (void*)tott,list_pos); + +} + +void add_placed_hierarchy(Placed_Hierarchy_Chunk* phc,const char* fname,const char* hname) +{ + int i; + PLACED_HIERARCHY_TOOLS_TEMPLATE* phtt=(PLACED_HIERARCHY_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(PLACED_HIERARCHY_TOOLS_TEMPLATE)); + + //first setup the sounds + phtt->sounds=0; + + List chlist; + phc->lookup_child("INDSOUND",chlist); + phtt->num_sounds=0; + //find the highest index + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + Indexed_Sound_Chunk* isc=(Indexed_Sound_Chunk*)chlif(); + phtt->num_sounds=max(phtt->num_sounds,isc->index+1); + } + + if(phtt->num_sounds) + { + phtt->sounds=(PLACED_HIERARCHY_SOUND*)PoolAllocateMem(sizeof(PLACED_HIERARCHY_SOUND)*phtt->num_sounds); + for(i=0;inum_sounds;i++) + { + phtt->sounds[i].sound_loaded=0; + phtt->sounds[i].activ_no=SOUND_NOACTIVEINDEX; + } + + for(chlif.restart();!chlif.done();chlif.next()) + { + Indexed_Sound_Chunk* isc=(Indexed_Sound_Chunk*)chlif(); + PLACED_HIERARCHY_SOUND* phs=&phtt->sounds[isc->index]; + + phs->inner_range=isc->inner_range*local_scale; + phs->outer_range=isc->outer_range*local_scale; + phs->pitch=isc->pitch; + phs->max_volume=isc->max_volume; + phs->playing=0; + phs->loop=((isc->flags & IndexedSoundFlag_Loop)!=0); + phs->sound_loaded=GetSoundForMainRif(isc->wav_name); + } + } + + //now setup the sequences + phc->lookup_child("PLHISEQU",chlist); + phtt->num_sequences=0; + //find the highest sequence index + for(chlif.restart();!chlif.done();chlif.next()) + { + Placed_Hierarchy_Sequence_Chunk* phsc=(Placed_Hierarchy_Sequence_Chunk*)chlif(); + phtt->num_sequences=max(phtt->num_sequences,phsc->index+1); + } + + GLOBALASSERT(phtt->num_sequences); + + phtt->sequences=(PLACED_HIERARCHY_SEQUENCE*)PoolAllocateMem(sizeof(PLACED_HIERARCHY_SEQUENCE)*phtt->num_sequences); + for(i=0;inum_sequences;i++) + { + phtt->sequences[i].sequence_no=-1; + } + phtt->first_sequence=&phtt->sequences[0]; + phtt->playing=0; + + for(chlif.restart();!chlif.done();chlif.next()) + { + Placed_Hierarchy_Sequence_Chunk* phsc=(Placed_Hierarchy_Sequence_Chunk*)chlif(); + PLACED_HIERARCHY_SEQUENCE* ph_seq=&phtt->sequences[phsc->index]; + + ph_seq->sequence_no=phsc->sequence; + ph_seq->sub_sequence_no=phsc->sub_sequence; + ph_seq->time=((float)phsc->time*(float)ONE_FIXED)/1000.0; + ph_seq->loop=((phsc->flags & HierarchySequenceFlag_Loop)!=0); + + if(phsc->flags & HierarchySequenceFlag_InitialSequence) + { + phtt->first_sequence=ph_seq; + if(phsc->flags & HierarchySequenceFlag_Playing) + { + phtt->playing=0; + } + } + + ph_seq->num_sound_times=phsc->sound_list_size; + if(ph_seq->num_sound_times) + { + ph_seq->sound_times=(PLACED_HIERARCHY_SOUND_TIMES*)PoolAllocateMem(sizeof(PLACED_HIERARCHY_SOUND_TIMES)*ph_seq->num_sound_times); + for(i=0;inum_sound_times;i++) + { + ph_seq->sound_times[i].start_time=phsc->sound_list[i].start_time; + ph_seq->sound_times[i].end_time=phsc->sound_list[i].end_time; + + int sound_index=phsc->sound_list[i].sound_index; + if(sound_index>=0 && sound_indexnum_sounds) + { + ph_seq->sound_times[i].sound=&phtt->sounds[sound_index]; + } + else + { + ph_seq->sound_times[i].sound=0; + } + + } + } + else + { + ph_seq->sound_times=0; + } + + } + + phtt->num_special_track_points=0; + phtt->special_track_points=0; + AVP_Strategy_Chunk* asc=(AVP_Strategy_Chunk*) phc->lookup_single_child("AVPSTRAT"); + if(asc && asc->Strategy) + { + GLOBALASSERT(asc->Strategy->StrategyType==StratHierarchy); + HierarchyStrategy* hs=(HierarchyStrategy*) asc->Strategy; + + phtt->num_special_track_points=hs->num_point_effects; + if(hs->num_point_effects) + { + phtt->special_track_points=(SPECIAL_TRACK_POINT*)PoolAllocateMem(sizeof(SPECIAL_TRACK_POINT)*hs->num_point_effects); + for(int i=0;inum_point_effects;i++) + { + SPECIAL_TRACK_POINT* stp=&phtt->special_track_points[i]; + TrackPointEffect* tpe=hs->point_effects[i]; + + stp->track_point_no=1<point_no; + stp->num_targets=tpe->num_targets; + + if(stp->num_targets) + { + stp->targets=(TRACK_POINT_TARGET*)PoolAllocateMem(sizeof(TRACK_POINT_TARGET)*stp->num_targets); + for(int j=0;jnum_targets;j++) + { + stp->targets[j].request=tpe->targets[j].request; + stp->targets[j].flags=tpe->targets[j].flags; + *(ObjectID*)&stp->targets[j].target_name[0]=tpe->targets[j].targetID; + } + + } + else + stp->targets=0; + } + } + else + phtt->special_track_points=0; + + } + + Placed_Hierarchy_Data_Chunk* data=phc->get_data_chunk(); + + + *(ObjectID*) &phtt->nameID[0]=data->id; + + phtt->position.vx = data->location.x * local_scale; + phtt->position.vy = data->location.y * local_scale; + phtt->position.vz = data->location.z * local_scale; + + QUAT q; + + q.quatx = (int) -(data->orientation.x*ONE_FIXED); + q.quaty = (int) -(data->orientation.y*ONE_FIXED); + q.quatz = (int) -(data->orientation.z*ONE_FIXED); + q.quatw = (int) (data->orientation.w*ONE_FIXED); + + + MATRIXCH m; + + QuatToMat (&q, &m); + + MatrixToEuler(&m, &phtt->orientation); + + phtt->hier_name=hname; + phtt->file_name=fname; + + AddToBehaviourList(0,data->id, I_BehaviourPlacedHierarchy, (void *) phtt,0); +} + + +static void GetFanWindDirection(QUAT *q1, QUAT *q2, VECTORCH* dir) + +{ + + //calulate q1 inverse * q2 , and then take axis of rotation + int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8; + int S, T; + + temp1 = MUL_FIXED((q1->quatz - q1->quaty), (q2->quaty - q2->quatz)); + temp2 = MUL_FIXED((-q1->quatw + q1->quatx), (q2->quatw + q2->quatx)); + temp3 = MUL_FIXED((-q1->quatw - q1->quatx), (q2->quaty + q2->quatz)); + temp4 = MUL_FIXED((q1->quatz + q1->quaty), (q2->quatw - q2->quatx)); + temp5 = MUL_FIXED((q1->quatz - q1->quatx), (q2->quatx - q2->quaty)); + temp6 = MUL_FIXED((q1->quatz + q1->quatx), (q2->quatx + q2->quaty)); + temp7 = MUL_FIXED((-q1->quatw + q1->quaty), (q2->quatw - q2->quatz)); + temp8 = MUL_FIXED((-q1->quatw - q1->quaty), (q2->quatw + q2->quatz)); + + S = temp6 + temp7 + temp8; + + T = (temp5 + S) / 2; + + dir->vx = temp2 + T - S; + dir->vy = temp3 + T - temp8; + dir->vz = temp4 + T - temp7; + + if(temp1 + T - temp6 > 0) + { + dir->vx=-dir->vx; + dir->vy=-dir->vy; + dir->vz=-dir->vz; + } + + Normalise(dir); + +} + +static void add_fan(Object_Chunk* ob, int list_pos,AVP_Strategy_Chunk* asc) +{ + + TRACK_CONTROLLER* track=setup_track_controller(ob); + GLOBALASSERT(track); + + FanStrategy* fs=(FanStrategy*) asc->Strategy; + + FAN_TOOLS_TEMPLATE* ftt=(FAN_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(FAN_TOOLS_TEMPLATE)); + + *(ObjectID*)&ftt->nameID[0]=ob->object_data.ID; + + ftt->position.vx = ob->object_data.location.x * local_scale; + ftt->position.vy = ob->object_data.location.y * local_scale; + ftt->position.vz = ob->object_data.location.z * local_scale; + + QUAT q; + + q.quatx = (int) -(ob->object_data.orientation.x*ONE_FIXED); + q.quaty = (int) -(ob->object_data.orientation.y*ONE_FIXED); + q.quatz = (int) -(ob->object_data.orientation.z*ONE_FIXED); + q.quatw = (int) (ob->object_data.orientation.w*ONE_FIXED); + + + MATRIXCH m; + + QuatToMat (&q, &m); + + MatrixToEuler(&m, &ftt->orientation); + + ftt->shape_num = list_pos; + ftt->track=track; + ftt->speed_up_mult=DIV_FIXED(ONE_FIXED,fs->speed_up_time); + ftt->slow_down_mult=DIV_FIXED(ONE_FIXED,fs->slow_down_time); + + GetFanWindDirection(&track->sections[0].quat_start,&track->sections[0].quat_end,&ftt->fan_wind_direction); + + if(fs->fan_wind_strength>=-1000 && fs->fan_wind_strength<=1000) + ftt->fan_wind_strength=(fs->fan_wind_strength*ONE_FIXED)/100; + else + ftt->fan_wind_strength=ONE_FIXED; + //if the wind strength is negative , then the wind goes in the opposite direction + if(ftt->fan_wind_strength<0) + { + ftt->fan_wind_strength=-ftt->fan_wind_strength; + ftt->fan_wind_direction.vx=-ftt->fan_wind_direction.vx; + ftt->fan_wind_direction.vy=-ftt->fan_wind_direction.vy; + ftt->fan_wind_direction.vz=-ftt->fan_wind_direction.vz; + } + + AddToBehaviourList(ob->object_data.o_name,ob->object_data.ID, I_BehaviourFan, (void*)ftt,list_pos,0,ob->get_header()->flags); +} + + +static void add_linkswitch(const char* name,AVP_Strategy_Chunk* asc,const ObjectID& ID,Object_Chunk* oc=0,int list_pos=-1) +{ + + LinkSwitchStrategy * lss = (LinkSwitchStrategy *)asc->Strategy; + + LINK_SWITCH_TOOLS_TEMPLATE* lstt=(LINK_SWITCH_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(LINK_SWITCH_TOOLS_TEMPLATE)); + + lstt->trigger_volume_min.vx=lstt->trigger_volume_max.vx=0; + lstt->trigger_volume_min.vy=lstt->trigger_volume_max.vy=0; + lstt->trigger_volume_min.vz=lstt->trigger_volume_max.vz=0; + lstt->switch_flags=0; + + if(oc) //switch has a shape + { + lstt->position.vx = oc->object_data.location.x * local_scale; + lstt->position.vy = oc->object_data.location.y * local_scale; + lstt->position.vz = oc->object_data.location.z * local_scale; + + + QUAT q; + + q.quatx = (int) -(oc->object_data.orientation.x*ONE_FIXED); + q.quaty = (int) -(oc->object_data.orientation.y*ONE_FIXED); + q.quatz = (int) -(oc->object_data.orientation.z*ONE_FIXED); + q.quatw = (int) (oc->object_data.orientation.w*ONE_FIXED); + + + MATRIXCH m; + + QuatToMat (&q, &m); + + MatrixToEuler(&m, &lstt->orientation); + + lstt->track=setup_track_controller(oc); + if(lstt->track) + { + lstt->track->loop=FALSE; + lstt->track->loop_backandforth=FALSE; + lstt->track->playing=FALSE; + lstt->track->initial_state_playing=FALSE; + lstt->track->timer=0; + lstt->track->initial_state_timer=0; + } + lstt->switch_always_on=0; + } + else //switch has no shape + { + lstt->position.vx = 0; + lstt->position.vy = 0; + lstt->position.vz = 0; + + lstt->track=0; + + lstt->orientation.EulerX=lstt->orientation.EulerY=lstt->orientation.EulerZ=0; + lstt->switch_always_on=1; + } + + + lstt->rest_state = ((lss->flags & BinSwitchFlag_StartsOn)!=0); + lstt->mode = lss->Mode; + lstt->time_for_reset = lss->Time; + lstt->security_clearance = lss->Security; + lstt->shape_num = list_pos; + *((ObjectID *)lstt->nameID) =ID; + + + lstt->switch_off_message_same = ((lss->flags & BinSwitchFlag_OffMessageSame)!=0); + lstt->switch_off_message_none = ((lss->flags & BinSwitchFlag_OffMessageNone)!=0); + + LINK_SWITCH_TARGET* ls_target=(LINK_SWITCH_TARGET*) PoolAllocateMem (sizeof(LINK_SWITCH_TARGET)); + + *(ObjectID*)ls_target->name=lss->Target.ID; + ls_target->request_message=1|lss->Target.request; + ls_target->sbptr=0; + + lstt->num_targets=1; + lstt->targets=ls_target; + + if(lss->NumLinks) + lstt->switchIDs=(SBNAMEBLOCK*) PoolAllocateMem(lss->NumLinks*sizeof(SBNAMEBLOCK)); + else + lstt->switchIDs=0; + + lstt->num_linked_switches=lss->NumLinks; + for (int i=0; iNumLinks; i++) + { + *((ObjectID *)lstt->switchIDs[i].name) = lss->LinkedSwitches[i]; + } + + AddToBehaviourList(name,ID, I_BehaviourLinkSwitch, (void*)lstt,list_pos); + +} +static void add_multitarget_linkswitch(const char* name,AVP_Strategy_Chunk* asc,const ObjectID& ID,Object_Chunk* oc=0,int list_pos=-1) +{ + MultiSwitchStrategy * mss = (MultiSwitchStrategy *)asc->Strategy; + + LINK_SWITCH_TOOLS_TEMPLATE* lstt=(LINK_SWITCH_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(LINK_SWITCH_TOOLS_TEMPLATE)); + + if(oc) //switch has a shape + { + lstt->position.vx = oc->object_data.location.x * local_scale; + lstt->position.vy = oc->object_data.location.y * local_scale; + lstt->position.vz = oc->object_data.location.z * local_scale; + + + QUAT q; + + q.quatx = (int) -(oc->object_data.orientation.x*ONE_FIXED); + q.quaty = (int) -(oc->object_data.orientation.y*ONE_FIXED); + q.quatz = (int) -(oc->object_data.orientation.z*ONE_FIXED); + q.quatw = (int) (oc->object_data.orientation.w*ONE_FIXED); + + + MATRIXCH m; + + QuatToMat (&q, &m); + + MatrixToEuler(&m, &lstt->orientation); + + lstt->track=setup_track_controller(oc); + if(lstt->track) + { + lstt->track->loop=FALSE; + lstt->track->loop_backandforth=FALSE; + lstt->track->playing=FALSE; + lstt->track->initial_state_playing=FALSE; + lstt->track->timer=0; + lstt->track->initial_state_timer=0; + } + } + else //switch has no shape + { + lstt->position.vx = 0; + lstt->position.vy = 0; + lstt->position.vz = 0; + + lstt->track=0; + + lstt->orientation.EulerX=lstt->orientation.EulerY=lstt->orientation.EulerZ=0; + } + + if(mss->StrategyType==StratAreaSwitch) + { + //switch can be triggered by walking into a ceartain area + AreaSwitchStrategy* ass=(AreaSwitchStrategy*)mss; + lstt->trigger_volume_min=ass->trigger_min*local_scale; + lstt->trigger_volume_max=ass->trigger_max*local_scale; + lstt->switch_flags=SwitchFlag_UseTriggerVolume; + } + else + { + lstt->trigger_volume_min.vx=lstt->trigger_volume_max.vx=0; + lstt->trigger_volume_min.vy=lstt->trigger_volume_max.vy=0; + lstt->trigger_volume_min.vz=lstt->trigger_volume_max.vz=0; + lstt->switch_flags=0; + } + + lstt->switch_off_message_same = ((mss->flags & BinSwitchFlag_OffMessageSame)!=0); + lstt->switch_off_message_none = ((mss->flags & BinSwitchFlag_OffMessageNone)!=0); + lstt->rest_state = mss->RestState; + + lstt->mode = mss->Mode; + if(lstt->mode>I_lswitch_toggle) + { + lstt->mode=I_lswitch_timer; + } + lstt->time_for_reset = mss->Time; + lstt->security_clearance = mss->Security; + lstt->shape_num = list_pos; + *((ObjectID *)lstt->nameID) =ID; + + int i; + + lstt->num_targets=mss->NumTargets; + if(mss->NumTargets) + { + lstt->targets=(LINK_SWITCH_TARGET*) PoolAllocateMem(mss->NumTargets * sizeof(LINK_SWITCH_TARGET)); + for(i=0;iNumTargets;i++) + { + *(ObjectID*)lstt->targets[i].name=mss->Targets[i].ID; + lstt->targets[i].request_message=mss->Targets[i].request; + lstt->targets[i].sbptr=0; + } + } + else + { + lstt->targets=0; + } + + + + if(mss->NumLinks) + lstt->switchIDs=(SBNAMEBLOCK*) PoolAllocateMem(mss->NumLinks * sizeof(SBNAMEBLOCK)); + else + lstt->switchIDs=0; + + lstt->num_linked_switches=mss->NumLinks; + for (i=0; iNumLinks; i++) + { + *((ObjectID *)lstt->switchIDs[i].name) = mss->LinkedSwitches[i]; + } + lstt->switch_always_on=0; + + + AddToBehaviourList(name,ID, I_BehaviourLinkSwitch, (void*)lstt,list_pos); + +} + +static void add_binswitch (const char* name,AVP_Strategy_Chunk* asc,const ObjectID& ID,Object_Chunk* oc=0,int list_pos=-1) +{ + BinSwitchStrategy * bss = (BinSwitchStrategy *)asc->Strategy; + + BIN_SWITCH_TOOLS_TEMPLATE* bstt=(BIN_SWITCH_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(BIN_SWITCH_TOOLS_TEMPLATE)); + + if(oc)//switch has a shape + { + bstt->position.vx = oc->object_data.location.x * local_scale; + bstt->position.vy = oc->object_data.location.y * local_scale; + bstt->position.vz = oc->object_data.location.z * local_scale; + + + bstt->trigger_volume_min.vx=bstt->trigger_volume_max.vx=0; + bstt->trigger_volume_min.vy=bstt->trigger_volume_max.vy=0; + bstt->trigger_volume_min.vz=bstt->trigger_volume_max.vz=0; + bstt->switch_flags=0; + + + QUAT q; + + q.quatx = (int) -(oc->object_data.orientation.x*ONE_FIXED); + q.quaty = (int) -(oc->object_data.orientation.y*ONE_FIXED); + q.quatz = (int) -(oc->object_data.orientation.z*ONE_FIXED); + q.quatw = (int) (oc->object_data.orientation.w*ONE_FIXED); + + + MATRIXCH m; + + QuatToMat (&q, &m); + + MatrixToEuler(&m, &bstt->orientation); + + bstt->track=setup_track_controller(oc); + if(bstt->track) + { + bstt->track->loop=FALSE; + bstt->track->loop_backandforth=FALSE; + bstt->track->playing=FALSE; + bstt->track->initial_state_playing=FALSE; + bstt->track->timer=0; + bstt->track->initial_state_timer=0; + } + } + else //switch has no shape + { + bstt->position.vx = 0; + bstt->position.vy = 0; + bstt->position.vz = 0; + + bstt->track=0; + + bstt->trigger_volume_min.vx=bstt->trigger_volume_max.vx=0; + bstt->trigger_volume_min.vy=bstt->trigger_volume_max.vy=0; + bstt->trigger_volume_min.vz=bstt->trigger_volume_max.vz=0; + bstt->switch_flags=0; + + bstt->orientation.EulerX=bstt->orientation.EulerY=bstt->orientation.EulerZ=0; + + } + + bstt->starts_on = ((bss->flags & BinSwitchFlag_StartsOn)!=0); + bstt->switch_off_message_same = ((bss->flags & BinSwitchFlag_OffMessageSame)!=0); + bstt->switch_off_message_none = ((bss->flags & BinSwitchFlag_OffMessageNone)!=0); + + bstt->mode = bss->Mode; + bstt->time_for_reset = bss->Time; + bstt->security_clearance = bss->Security; + + bstt->num_targets = 1; + + int* request_message=(int*) PoolAllocateMem(sizeof(int)); + request_message[0]=1|bss->Target.request; + bstt->request_messages=request_message; + + SBNAMEBLOCK* snb =(SBNAMEBLOCK*) PoolAllocateMem(sizeof(SBNAMEBLOCK)); + *((ObjectID *)snb->name) = bss->Target.ID; + bstt->target_names = snb; + + bstt->shape_num = list_pos; + *((ObjectID *)bstt->nameID) = ID; + + AddToBehaviourList(name,ID, I_BehaviourBinarySwitch, (void*)bstt,list_pos); + +} + +static void add_multiswitch (const char* name,AVP_Strategy_Chunk* asc,const ObjectID& ID,Object_Chunk* oc=0,int list_pos=-1) +{ + MultiSwitchStrategy * mss = (MultiSwitchStrategy *)asc->Strategy; + if(mss->NumLinks) + { + add_multitarget_linkswitch(name,asc,ID,oc,list_pos); + return; + } + + BIN_SWITCH_TOOLS_TEMPLATE* bstt=(BIN_SWITCH_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(BIN_SWITCH_TOOLS_TEMPLATE)); + + if(oc) //switch has a shape + { + bstt->position.vx = oc->object_data.location.x * local_scale; + bstt->position.vy = oc->object_data.location.y * local_scale; + bstt->position.vz = oc->object_data.location.z * local_scale; + + + QUAT q; + + q.quatx = (int) -(oc->object_data.orientation.x*ONE_FIXED); + q.quaty = (int) -(oc->object_data.orientation.y*ONE_FIXED); + q.quatz = (int) -(oc->object_data.orientation.z*ONE_FIXED); + q.quatw = (int) (oc->object_data.orientation.w*ONE_FIXED); + + + MATRIXCH m; + + QuatToMat (&q, &m); + + MatrixToEuler(&m, &bstt->orientation); + + bstt->track=setup_track_controller(oc); + if(bstt->track) + { + bstt->track->loop=FALSE; + bstt->track->loop_backandforth=FALSE; + bstt->track->playing=FALSE; + bstt->track->initial_state_playing=FALSE; + bstt->track->timer=0; + bstt->track->initial_state_timer=0; + } + } + else //switch has no shapes + { + bstt->position.vx = 0; + bstt->position.vy = 0; + bstt->position.vz = 0; + + bstt->track=0; + bstt->orientation.EulerX=bstt->orientation.EulerY=bstt->orientation.EulerZ=0; + } + + if(mss->StrategyType==StratAreaSwitch) + { + //switch can be triggered by walking into a ceartain area + AreaSwitchStrategy* ass=(AreaSwitchStrategy*)mss; + bstt->trigger_volume_min=ass->trigger_min*local_scale; + bstt->trigger_volume_max=ass->trigger_max*local_scale; + bstt->switch_flags=SwitchFlag_UseTriggerVolume; + } + else + { + bstt->trigger_volume_min.vx=bstt->trigger_volume_max.vx=0; + bstt->trigger_volume_min.vy=bstt->trigger_volume_max.vy=0; + bstt->trigger_volume_min.vz=bstt->trigger_volume_max.vz=0; + bstt->switch_flags=0; + } + + + bstt->starts_on = mss->RestState; + bstt->switch_off_message_same = ((mss->flags & MultiSwitchFlag_OffMessageSame)!=0); + bstt->switch_off_message_none = ((mss->flags & MultiSwitchFlag_OffMessageNone)!=0); + + bstt->mode = mss->Mode; + bstt->time_for_reset = mss->Time; + bstt->security_clearance = mss->Security; + + bstt->num_targets = mss->NumTargets; + + + SBNAMEBLOCK * snb = (SBNAMEBLOCK*) PoolAllocateMem(sizeof(SBNAMEBLOCK)*mss->NumTargets); + + int* request_messages=(int*) PoolAllocateMem(sizeof(int) * mss->NumTargets); + for (int i=0; iNumTargets; i++) + { + *((ObjectID *)snb[i].name) = mss->Targets[i].ID; + request_messages[i]=mss->Targets[i].request; + } + + bstt->request_messages=request_messages; + + bstt->target_names = snb; + + bstt->shape_num = list_pos; + *((ObjectID *)bstt->nameID) = ID; + + + AddToBehaviourList(name,ID, I_BehaviourBinarySwitch, (void*)bstt,list_pos); + +} + + +static void add_platlift (Object_Chunk * ob, int list_pos, AVP_Strategy_Chunk * asc) +{ + PlatLiftStrategy* pls=(PlatLiftStrategy*)asc->Strategy; + + PLATFORMLIFT_TOOLS_TEMPLATE* ptt=(PLATFORMLIFT_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(PLATFORMLIFT_TOOLS_TEMPLATE)); + + ptt->position.vx = ob->object_data.location.x * local_scale; + ptt->position.vy = ob->object_data.location.y * local_scale; + ptt->position.vz = ob->object_data.location.z * local_scale; + + QUAT q; + + q.quatx = (int) -(ob->object_data.orientation.x*ONE_FIXED); + q.quaty = (int) -(ob->object_data.orientation.y*ONE_FIXED); + q.quatz = (int) -(ob->object_data.orientation.z*ONE_FIXED); + q.quatw = (int) (ob->object_data.orientation.w*ONE_FIXED); + + + MATRIXCH m; + + QuatToMat (&q, &m); + + MatrixToEuler(&m, &ptt->orientation); + + ptt->shapeIndex = list_pos; + *((ObjectID *)ptt->nameID) = ob->object_data.ID; + ptt->travel=0; + + Object_Track_Chunk2* otc=(Object_Track_Chunk2*)ob->lookup_single_child("OBJTRAK2"); + if(otc) + { + if(otc->num_sections==1) + { + ptt->travel=(otc->sections[0].pivot_end.y-otc->sections[0].pivot_start.y)*local_scale; + } + } + else + { + GLOBALASSERT(0=="Platform lift must have a track"); + } + + setup_track_sound(ob,&ptt->start_sound,&ptt->sound,&ptt->end_sound); + + if(pls->flags & PlatformLiftFlags_Disabled) + ptt->Enabled=FALSE; + else + ptt->Enabled=TRUE; + + if(pls->flags & PlatformLiftFlags_OneUse) + ptt->OneUse=TRUE; + else + ptt->OneUse=FALSE; + + AddToBehaviourList(ob->object_data.o_name,ob->object_data.ID, I_BehaviourPlatform, (void*)ptt,list_pos,0,ob->get_header()->flags); + +} + +static void add_deathvolume(const char* name,AVP_Strategy_Chunk* asc,ObjectID ID) +{ + DeathVolumeStrategy* dvs=(DeathVolumeStrategy*)asc->Strategy; + + DEATH_VOLUME_TOOLS_TEMPLATE* dvtt=(DEATH_VOLUME_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(DEATH_VOLUME_TOOLS_TEMPLATE)); + + dvtt->volume_min=dvs->volume_min*local_scale; + dvtt->volume_max=dvs->volume_max*local_scale; + if(dvs->flags & DeathVolumeFlag_StartsOn) + dvtt->active=1; + else + dvtt->active=0; + + if(dvs->flags & DeathVolumeFlag_CollisionNotRequired) + dvtt->collision_required=0; + else + dvtt->collision_required=1; + + dvtt->damage_per_second = dvs->damage; + + *(ObjectID*)&dvtt->nameID[0]=ID; + + + AddToBehaviourList(name,ID, I_BehaviourDeathVolume, (void*)dvtt); +} + +static void add_selfdestruct(const char* name,AVP_Strategy_Chunk* asc,ObjectID ID) +{ + SelfDestructStrategy* sds=(SelfDestructStrategy*)asc->Strategy; + + SELF_DESTRUCT_TOOLS_TEMPLATE* sdtt=(SELF_DESTRUCT_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(SELF_DESTRUCT_TOOLS_TEMPLATE)); + + sdtt->timer=sds->timer<<16; + + *(ObjectID*)&sdtt->nameID[0]=ID; + + + AddToBehaviourList(name,ID, I_BehaviourSelfDestruct, (void*)sdtt); +} + +static void add_message_strategy(const char* name,AVP_Strategy_Chunk* asc,ObjectID ID) +{ + TextMessageStrategy* tms=(TextMessageStrategy*)asc->Strategy; + assert (tms->message_string>0 && tms->message_string<450); + + MESSAGE_TOOLS_TEMPLATE* mtt=(MESSAGE_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(MESSAGE_TOOLS_TEMPLATE)); + + mtt->string_no=(TEXTSTRING_ID)((tms->message_string-1)+TEXTSTRING_LEVELMSG_001); + *(ObjectID*)&mtt->nameID[0]=ID; + + if(tms->flags & TextMessageFlag_NotActiveAtStart) + mtt->active=FALSE; + else + mtt->active=TRUE; + + + + AddToBehaviourList(name,ID, I_BehaviourMessage, (void*)mtt); + +} + +void setup_placed_light_data (LIGHTBLOCK * lPtr, Placed_Object_Light_Chunk * lc); + +static void add_placed_light(Object_Chunk* ob,int list_pos,AVP_Strategy_Chunk* asc) +{ + SimpleStrategy * ss = (SimpleStrategy *)asc->Strategy; + + + + TOOLS_DATA_PLACEDLIGHT* pltd=(TOOLS_DATA_PLACEDLIGHT*) PoolAllocateMem(sizeof(TOOLS_DATA_PLACEDLIGHT)); + + pltd->position.vx = ob->object_data.location.x * local_scale; + pltd->position.vy = ob->object_data.location.y * local_scale; + pltd->position.vz = ob->object_data.location.z * local_scale; + + QUAT q; + + q.quatx = (int) -(ob->object_data.orientation.x*ONE_FIXED); + q.quaty = (int) -(ob->object_data.orientation.y*ONE_FIXED); + q.quatz = (int) -(ob->object_data.orientation.z*ONE_FIXED); + q.quatw = (int) (ob->object_data.orientation.w*ONE_FIXED); + + + MATRIXCH m; + + QuatToMat (&q, &m); + + MatrixToEuler(&m, &pltd->orientation); + + pltd->shapeIndex = list_pos; + pltd->mass = ss->mass/10; + if (!pltd->mass) pltd->mass = 1; + pltd->integrity = ss->integrity & 0xff; + *((ObjectID *)pltd->nameID) = ob->object_data.ID; + + Placed_Object_Light_Chunk* lchunk=(Placed_Object_Light_Chunk*)ob->lookup_single_child("PLOBJLIT"); + GLOBALASSERT(lchunk); + + pltd->light=(LIGHTBLOCK*) PoolAllocateMem(sizeof(LIGHTBLOCK)); + + setup_placed_light_data(pltd->light,lchunk); + + pltd->colour_red=((lchunk->light.up_colour>>16)&0xff)*257; + pltd->colour_green=((lchunk->light.up_colour>>8)&0xff)*257; + pltd->colour_blue=((lchunk->light.up_colour)&0xff)*257; + pltd->colour_diff_red=((lchunk->light.down_colour>>16)&0xff)*257; + pltd->colour_diff_green=((lchunk->light.down_colour>>8)&0xff)*257; + pltd->colour_diff_blue=((lchunk->light.down_colour)&0xff)*257; + + pltd->colour_diff_red-=pltd->colour_red; + pltd->colour_diff_green-=pltd->colour_green; + pltd->colour_diff_blue-=pltd->colour_blue; + + pltd->fade_up_time=(max(lchunk->light.fade_up_time,1)*ONE_FIXED)/1000; + pltd->fade_down_time=(max(lchunk->light.fade_down_time,1)*ONE_FIXED)/1000; + pltd->up_time=(max(lchunk->light.up_time,1)*ONE_FIXED)/1000; + pltd->down_time=(max(lchunk->light.down_time,1)*ONE_FIXED)/1000; + pltd->timer=(max(lchunk->light.start_time,1)*ONE_FIXED)/1000; + + pltd->type=(LIGHT_TYPE)lchunk->light.light_type; + pltd->on_off_type=(LIGHT_ON_OFF_TYPE)lchunk->light.on_off_type; + + if(lchunk->light.flags & PlacedLightFlag_On) + { + pltd->sequence=1; + pltd->on_off_state=Light_OnOff_On; + + } + else + { + pltd->sequence=0; + pltd->on_off_state=Light_OnOff_Off; + //pltd->light->LightBright=0; + } + + if(lchunk->light.flags & PlacedLightFlag_SwapColourBright) + pltd->swap_colour_and_brightness_alterations=1; + else + pltd->swap_colour_and_brightness_alterations=0; + + + if(pltd->type==Light_Type_Strobe) + pltd->state=Light_State_StrobeUp; + else if(pltd->type==Light_Type_Flicker) + pltd->state=Light_State_Flicker; + else + pltd->state=Light_State_Standard; + + pltd->destruct_target_request=ss->target_request; + *(ObjectID*)pltd->destruct_target_ID=ss->targetID; + + pltd->static_light=1; + + + AddToBehaviourList(ob->object_data.o_name,ob->object_data.ID, I_BehaviourPlacedLight, (void *) pltd,list_pos,0,ob->get_header()->flags); +} + +static void add_prox_door (Object_Chunk * ob, int shp1, int shp2, MODULE * mod,AVP_Strategy_Chunk* asc) +{ + + PROX_DOOR_TOOLS_TEMPLATE * pdtt =(PROX_DOOR_TOOLS_TEMPLATE *) PoolAllocateMem(sizeof(PROX_DOOR_TOOLS_TEMPLATE)); + + pdtt->has_lock_target = No; + pdtt->door_opening_speed=1<<16; + pdtt->door_closing_speed=1<<17; + if(asc) + { + DoorStrategy * ds = (DoorStrategy *)asc->Strategy; + if(ds->DoorFlags & DoorFlag_Locked) + pdtt->door_is_locked=Yes; + else + pdtt->door_is_locked=No; + + if(ds->DoorFlags & DoorFlag_Horizontal) + { + mod->m_flags|=MODULEFLAG_HORIZONTALDOOR; + } + if(ds->TimeToOpen) + { + pdtt->door_opening_speed=655360/ds->TimeToOpen; + } + if(ds->TimeToClose) + { + pdtt->door_closing_speed=655360/ds->TimeToClose; + } + + } + else pdtt->door_is_locked=No; + pdtt->shape_open = shp1; + pdtt->shape_closed = shp2; + *((int *)pdtt->my_module.mref_name) = *((int *) mod->m_name); + *((ObjectID *)pdtt->nameID) = ob->object_data.ID; + + AddToBehaviourList(ob->object_data.o_name,ob->object_data.ID, I_BehaviourProximityDoor, (void*)pdtt,shp1); + + + +} + + +static void add_lift_door (Object_Chunk * ob, int shape1, int shape2, MODULE * mod, AVP_Strategy_Chunk * asc) +{ + + DoorStrategy * ds = (DoorStrategy *)asc->Strategy; + + LIFT_DOOR_TOOLS_TEMPLATE * ldtt =(LIFT_DOOR_TOOLS_TEMPLATE *) PoolAllocateMem(sizeof( LIFT_DOOR_TOOLS_TEMPLATE)); + + ldtt->state = (ds->DoorFlags & DoorFlag_Open) ? I_door_open : I_door_closed; + *((int *)ldtt->my_module.mref_name) = *((int *)mod->m_name); + *((ObjectID *)ldtt->nameID) = ob->object_data.ID; + ldtt->shape_open = shape1; + ldtt->shape_closed = shape2; + + if(ds->TimeToOpen) + ldtt->door_opening_speed=655360/ds->TimeToOpen; + else + ldtt->door_opening_speed=1<<16; + + if(ds->TimeToClose) + ldtt->door_closing_speed=655360/ds->TimeToClose; + else + ldtt->door_closing_speed=1<<17; + + AddToBehaviourList(ob->object_data.o_name,ob->object_data.ID, I_BehaviourLiftDoor, (void*)ldtt,shape1); + +} + + + +static void add_switch_door (Object_Chunk * ob, int shape1, int shape2, MODULE * mod, AVP_Strategy_Chunk * asc) +{ + + SwitchDoorStrategy * sds = (SwitchDoorStrategy*)asc->Strategy; + + SWITCH_DOOR_TOOLS_TEMPLATE * sdtt =(SWITCH_DOOR_TOOLS_TEMPLATE *) PoolAllocateMem(sizeof(SWITCH_DOOR_TOOLS_TEMPLATE)); + + sdtt->state =I_door_closed; + *((int *)sdtt->myModule.mref_name) = *((int *)mod->m_name); + *((ObjectID *)sdtt->nameID) = ob->object_data.ID; + sdtt->shapeOpen = shape1; + sdtt->shapeClosed = shape2; + *(ObjectID*)sdtt->linkedDoorName=sds->AssocDoor; + + AddToBehaviourList(ob->object_data.o_name,ob->object_data.ID, I_BehaviourSwitchDoor, (void*)sdtt,shape1); + +} + +static void add_door (Object_Chunk * ob, int shape1, int shape2, MODULE * mod, AVP_Strategy_Chunk * asc) +{ + + DoorStrategy * ds = (DoorStrategy *)asc->Strategy; + + if (ds->DoorFlags & DoorFlag_Lift) + { + add_lift_door (ob, shape1, shape2, mod, asc); + } + else if (ds->DoorFlags & DoorFlag_Proximity) + { + add_prox_door (ob, shape1, shape2, mod, asc); + } +} + +static void add_lift_object (Object_Chunk * ob, int list_pos, MODULE * mod, AVP_Strategy_Chunk * asc) +{ + LiftStrategy * ls = (LiftStrategy *)asc->Strategy; + + ObjectID ControlID=ob->object_data.ID; + for(int i=0;iNumAssocLifts;i++) + { + ControlID=Minimum(ControlID,ls->AssocLifts[i]); + } + LIFT_TOOLS_TEMPLATE * ltt =(LIFT_TOOLS_TEMPLATE *) PoolAllocateMem(sizeof(LIFT_TOOLS_TEMPLATE)); + + *((ObjectID *)ltt->my_module_name) = ob->object_data.ID; + *((ObjectID *)ltt->call_switch_name) = ls->AssocCallSwitch; + *((ObjectID *)ltt->lift_door_name) = ls->AssocDoor; + *((ObjectID *)ltt->lift_floor_switch_name) = ls->AssocFloorSwitch; + + ltt->environment = AvP.CurrentEnv; + + ltt->num_floor = ls->Floor; + + *((ObjectID *)ltt->control_sb_name)=ControlID; + + ltt->controller = (ControlID==ob->object_data.ID); + + ltt->num_stations = ls->NumAssocLifts +ls->NumExternalLifts +1; + + ltt->lift_flags=ls->LiftFlags; + + *((int *)ltt->my_module.mref_name) = *((int *)mod->m_name); + *((ObjectID *)ltt->nameID) = ob->object_data.ID; + + ltt->orient=ls->Facing; + + AddToBehaviourList(ob->object_data.o_name,ob->object_data.ID, I_BehaviourLift, (void*)ltt,list_pos); + +} + + +static void add_light_fx (Object_Chunk * ob,int list_pos, MODULE * mod, AVP_Strategy_Chunk * asc) +{ + LightingStrategy * ls = (LightingStrategy *)asc->Strategy; + + LIGHT_FX_TOOLS_TEMPLATE * lfxtt =(LIGHT_FX_TOOLS_TEMPLATE *) PoolAllocateMem(sizeof(LIGHT_FX_TOOLS_TEMPLATE)); + + lfxtt->light_data = ls->LightData; + + *((ObjectID *)lfxtt->nameID) = ob->object_data.ID; + *((int *)lfxtt->my_module.mref_name) = *((int *)mod->m_name); + + AddToBehaviourList(ob->object_data.o_name,ob->object_data.ID, I_BehaviourLightFX, (void*)lfxtt,list_pos); + +} + +void deal_with_module_object(Object_Chunk * ob, int shape1, int AnimationShape, int shape2, MODULE * mod) +{ + Chunk * pChunk = ob->lookup_single_child("OBJPRJDT"); + + AVP_Strategy_Chunk * asc = 0; + + Object_Project_Data_Chunk * opdc = 0; + + if (pChunk) + { + opdc = (Object_Project_Data_Chunk *)pChunk; + + pChunk = opdc->lookup_single_child("AVPSTRAT"); + + if (pChunk) + { + asc = (AVP_Strategy_Chunk *)pChunk; + } + } + + if (asc) + { + assert (asc->Strategy != 0); + + switch (asc->Strategy->StrategyType) + { + case StratLift: + add_lift_object(ob, shape1, mod, asc); + break; + + case StratDoor: + if (shape2 != -1) + { + add_door (ob, shape1, shape2, mod, asc); + } + break; + case StratSwitchDoor: + if (shape2 != -1) + { + add_switch_door (ob, shape1, shape2, mod, asc); + } + break; + + case StratLighting: + { + add_light_fx (ob,shape1, mod, asc); + break; + } + + default: + assert (0); // Strategy not recognised + break; + } + } + else + { + + if (shape2 != -1) + { + add_prox_door (ob, shape1, shape2, mod,0); + } + else if(AnimationShape!=-1) + { + add_simple_animation (ob, AnimationShape, mod); + } + + } +} + + +static void add_videoscreen(Object_Chunk * ob, int list_pos, AVP_Strategy_Chunk * asc) +{ + SimpleStrategy * ss = (SimpleStrategy *)asc->Strategy; + + TOOLS_DATA_VIDEO_SCREEN* tdvs=(TOOLS_DATA_VIDEO_SCREEN*) PoolAllocateMem(sizeof(TOOLS_DATA_VIDEO_SCREEN)); + + tdvs->position.vx = ob->object_data.location.x * local_scale; + tdvs->position.vy = ob->object_data.location.y * local_scale; + tdvs->position.vz = ob->object_data.location.z * local_scale; + + QUAT q; + + q.quatx = (int) -(ob->object_data.orientation.x*ONE_FIXED); + q.quaty = (int) -(ob->object_data.orientation.y*ONE_FIXED); + q.quatz = (int) -(ob->object_data.orientation.z*ONE_FIXED); + q.quatw = (int) (ob->object_data.orientation.w*ONE_FIXED); + + + MATRIXCH m; + + QuatToMat (&q, &m); + + MatrixToEuler(&m, &tdvs->orientation); + + tdvs->shapeIndex = list_pos; + tdvs->integrity = ss->integrity & 0xff; + *((ObjectID *)tdvs->nameID) = ob->object_data.ID; + + //copy destruction target info + tdvs->destruct_target_request=ss->target_request; + *(ObjectID*)tdvs->destruct_target_ID=ss->targetID; + + + Object_Alternate_Locations_Chunk* loc_chunk = (Object_Alternate_Locations_Chunk*) ob->lookup_single_child("ALTLOCAT"); + + AddToBehaviourList(ob->object_data.o_name,ob->object_data.ID, I_BehaviourVideoScreen, (void *) tdvs,list_pos,loc_chunk,ob->get_header()->flags); +} + +static void add_newsimpleobject(Object_Chunk * ob, int list_pos, AVP_Strategy_Chunk * asc) +{ +// test for video screen which is type ReservedForJohn + + SimpleStrategy * ss = (SimpleStrategy *)asc->Strategy; + + if (ss->Type == IOT_ReservedForJohn) + { + add_videoscreen (ob, list_pos, asc); + return; + } + + if(ob->lookup_single_child("PLOBJLIT")) + { + add_placed_light(ob,list_pos,asc); + return; + } + + + TOOLS_DATA_INANIMATEOBJECT* tdio=(TOOLS_DATA_INANIMATEOBJECT*) PoolAllocateMem(sizeof(TOOLS_DATA_INANIMATEOBJECT)); + + tdio->position.vx = ob->object_data.location.x * local_scale; + tdio->position.vy = ob->object_data.location.y * local_scale; + tdio->position.vz = ob->object_data.location.z * local_scale; + + QUAT q; + + q.quatx = (int) -(ob->object_data.orientation.x*ONE_FIXED); + q.quaty = (int) -(ob->object_data.orientation.y*ONE_FIXED); + q.quatz = (int) -(ob->object_data.orientation.z*ONE_FIXED); + q.quatw = (int) (ob->object_data.orientation.w*ONE_FIXED); + + + MATRIXCH m; + + QuatToMat (&q, &m); + + MatrixToEuler(&m, &tdio->orientation); + + tdio->typeId = (INANIMATEOBJECT_TYPE)ss->Type; + tdio->subType = ss->ExtraData; + tdio->shapeIndex = list_pos; + tdio->mass = ss->mass/10; + if (!tdio->mass) tdio->mass = 1; + tdio->integrity = ss->integrity & 0xff; + *((ObjectID *)tdio->nameID) = ob->object_data.ID; + + + + tdio->explosionType=(ss->flags & SimStratFlag_ExplosionMask)>>SimStratFlag_ExplosionShift; + + + if(ss->targetID.id1 || ss->targetID.id2) + { + tdio->triggering_event=ss->flags; + tdio->event_request=ss->target_request; + *(ObjectID*)tdio->event_target_ID=ss->targetID; + } + else + { + tdio->triggering_event=0; + } + + if(tdio->typeId==IOT_Ammo) + { + //need to convert the subtype number + switch(tdio->subType) + { + case 0: + tdio->subType=AMMO_10MM_CULW; + break; + case 2: + tdio->subType=AMMO_SMARTGUN; + break; + case 3: + tdio->subType=AMMO_FLAMETHROWER; + break; + case 5: + tdio->subType=AMMO_SADAR_TOW; + break; + case 6: + tdio->subType=AMMO_GRENADE; + break; + case 7: + tdio->subType=AMMO_MINIGUN; + break; + case 8: + tdio->subType=AMMO_PULSE_GRENADE; + break; + case 9: + tdio->subType=AMMO_PRED_RIFLE; + break; + } + } + + Object_Alternate_Locations_Chunk* loc_chunk = (Object_Alternate_Locations_Chunk*) ob->lookup_single_child("ALTLOCAT"); + + AddToBehaviourList(ob->object_data.o_name,ob->object_data.ID, I_BehaviourInanimateObject, (void *) tdio,list_pos,loc_chunk,ob->get_header()->flags); + +} + +static void add_simpleobject(Object_Chunk * ob, int list_pos, AVP_Strategy_Chunk * asc) +{ +// test for sentry gun which is type ReservedForJohn + + if (asc->Strategy->Type == IOT_ReservedForJohn) + { + //add_autogun (ob, list_pos, asc->Strategy->ExtraData); + return; + } + + + TOOLS_DATA_INANIMATEOBJECT* tdio=(TOOLS_DATA_INANIMATEOBJECT*) PoolAllocateMem(sizeof(TOOLS_DATA_INANIMATEOBJECT)); + + tdio->position.vx = ob->object_data.location.x * local_scale; + tdio->position.vy = ob->object_data.location.y * local_scale; + tdio->position.vz = ob->object_data.location.z * local_scale; + + QUAT q; + + q.quatx = (int) -(ob->object_data.orientation.x*ONE_FIXED); + q.quaty = (int) -(ob->object_data.orientation.y*ONE_FIXED); + q.quatz = (int) -(ob->object_data.orientation.z*ONE_FIXED); + q.quatw = (int) (ob->object_data.orientation.w*ONE_FIXED); + + + MATRIXCH m; + + QuatToMat (&q, &m); + + MatrixToEuler(&m, &tdio->orientation); + + tdio->typeId = (INANIMATEOBJECT_TYPE)asc->Strategy->Type; + tdio->subType = asc->Strategy->ExtraData; + tdio->shapeIndex = list_pos; + tdio->mass = 5; + tdio->integrity = DEFAULT_OBJECT_INTEGRITY; + tdio->explosionType=0; + *((ObjectID *)tdio->nameID) = ob->object_data.ID; + + Object_Alternate_Locations_Chunk* loc_chunk = (Object_Alternate_Locations_Chunk*) ob->lookup_single_child("ALTLOCAT"); + + AddToBehaviourList(ob->object_data.o_name,ob->object_data.ID, I_BehaviourInanimateObject, (void *) tdio,list_pos,loc_chunk,ob->get_header()->flags); + +} + +void deal_with_placed_object(Object_Chunk * ob, int shape1, int /*AnimationShape*/) +{ + db_logf3(("Dealing with object %s , shape %d",ob->object_data.o_name,shape1)); + Chunk * pChunk = ob->lookup_single_child("OBJPRJDT"); + + AVP_Strategy_Chunk * asc = 0; + + Object_Project_Data_Chunk * opdc = 0; + + if (pChunk) + { + opdc = (Object_Project_Data_Chunk *)pChunk; + + pChunk = opdc->lookup_single_child("AVPSTRAT"); + + if (pChunk) + { + asc = (AVP_Strategy_Chunk *)pChunk; + } + } + + int obflags=ob->get_header()->flags; + if (asc) + { + assert (asc->Strategy != 0); + + switch (asc->Strategy->StrategyType) + { + case StratBinSwitch: + add_binswitch (ob->object_data.o_name,asc,ob->object_data.ID,ob,shape1); + break; + + case StratAreaSwitch: //(Area Switch derived from Multi Switch) + case StratMultiSwitch: + add_multiswitch (ob->object_data.o_name,asc,ob->object_data.ID,ob,shape1); + break; + + case StratLinkSwitch: + add_linkswitch (ob->object_data.o_name,asc,ob->object_data.ID,ob,shape1); + break; + + case StratPlatLift : + add_platlift(ob,shape1,asc); + break; + + case StratSimpleObject: + if(obflags & OBJECT_FLAG_PCLOAD) + { + if((AvP.PlayerType==I_Marine && (obflags & OBJECT_FLAG_AVPGAMEMODEMARINE))|| + (AvP.PlayerType==I_Predator && (obflags & OBJECT_FLAG_AVPGAMEMODEPREDATOR))|| + (AvP.PlayerType==I_Alien && (obflags & OBJECT_FLAG_AVPGAMEMODEALIEN))) + { + add_simpleobject (ob, shape1,asc); + } + } + break; + + case StratNewSimpleObject: + if(obflags & OBJECT_FLAG_PCLOAD) + { + if((AvP.PlayerType==I_Marine && (obflags & OBJECT_FLAG_AVPGAMEMODEMARINE))|| + (AvP.PlayerType==I_Predator && (obflags & OBJECT_FLAG_AVPGAMEMODEPREDATOR))|| + (AvP.PlayerType==I_Alien && (obflags & OBJECT_FLAG_AVPGAMEMODEALIEN))) + { + add_newsimpleobject (ob, shape1,asc); + } + } + break; + + + case StratTrack : + case StratTrackDestruct : + add_trackobject(ob,shape1,asc); + break; + + case StratFan : + add_fan(ob,shape1,asc); + break; + + default: + assert (0); // Strategy not recognised + break; + } + } + else + { +#if 0 + if(AnimationShape!=-1) + { + add_simple_animation (ob, AnimationShape, 0); + } + else +#endif + { + if(obflags & OBJECT_FLAG_PCLOAD) + { + if((AvP.PlayerType==I_Marine && (obflags & OBJECT_FLAG_AVPGAMEMODEMARINE))|| + (AvP.PlayerType==I_Predator && (obflags & OBJECT_FLAG_AVPGAMEMODEPREDATOR))|| + (AvP.PlayerType==I_Alien && (obflags & OBJECT_FLAG_AVPGAMEMODEALIEN))) + { + add_default_object(ob,shape1); + } + } + } + } + db_logf3(("Finished with object %s , shape %d",ob->object_data.o_name,shape1)); +} + +static void add_alien(AVP_Generator_Chunk * agc) +{ + + TOOLS_DATA_ALIEN* tda=(TOOLS_DATA_ALIEN*) PoolAllocateMem(sizeof(TOOLS_DATA_ALIEN)); + tda->position.vx = agc->location.x * local_scale; + tda->position.vy = agc->location.y * local_scale; + tda->position.vz = agc->location.z * local_scale; + + //tda->shapeIndex = GetLoadedShapeMSL("Alien"); + tda->shapeIndex = 0; + + tda->start_inactive=(agc->flags & AVPGENFLAG_GENERATORINACTIVE)!=0; + + tda->starteuler.EulerX=0; + tda->starteuler.EulerY=agc->orientation & 4095; + tda->starteuler.EulerZ=0; + + + switch (agc->type) + { + case 1: + tda->type=AT_Standard; + break; + + case 5: + tda->type=AT_Predalien; + break; + + case 8: + tda->type=AT_Praetorian; + break; + + default : + tda->type=AT_Standard; + } + + //look for extra strategy stuff + for(int i=0;ideath_target_ID[i]=0; + AVP_Generator_Extra_Data_Chunk* agedc=agc->get_extra_data_chunk(); + AVP_Strategy_Chunk* asc=0; + if(agedc) + { + Chunk * pChunk = agedc->lookup_single_child("AVPSTRAT"); + if(pChunk) + { + asc=(AVP_Strategy_Chunk*) pChunk; + + if(asc->Strategy) + { + switch(asc->Strategy->StrategyType) + { + case StratEnemy : + { + EnemyStrategy* es=(EnemyStrategy*)asc->Strategy; + + *(ObjectID*)&tda->death_target_ID[0]=es->DeathTarget; + } + break; + + } + } + } + } + + + ObjectID ID=agc->CalculateID(); + *(ObjectID*)&tda->nameID[0]=ID; + + AddToBehaviourList(agc->name,ID, I_BehaviourAlien, (void *) tda,0,agc->get_alternate_locations_chunk(),agc->flags); +} + +extern int ConvertObjectIndexToPathIndex(int path_index,int object_index); + + +static void add_marine(AVP_Generator_Chunk * agc) +{ + TOOLS_DATA_MARINE* tdm=(TOOLS_DATA_MARINE*) PoolAllocateMem(sizeof(TOOLS_DATA_MARINE)); + + tdm->position.vx = agc->location.x * local_scale; + tdm->position.vy = agc->location.y * local_scale; + tdm->position.vz = agc->location.z * local_scale; + + EULER euler; + euler.EulerX=0; + euler.EulerY=agc->orientation & 4095; + euler.EulerZ=0; + + get_marine_facing_point(tdm->position,euler,tdm->facing_point); + + + tdm->shapeIndex = 0; + + tdm->textureID=agc->textureID; + + + ObjectID ID=agc->CalculateID(); + *(ObjectID*)&tdm->nameID[0]=ID; + + tdm->Mission=MM_Wait_Then_Wander; + tdm->path=-1; + tdm->stepnumber=-1; + + //look for extra strategy stuff + for(int i=0;ideath_target_ID[i]=0; + AVP_Generator_Extra_Data_Chunk* agedc=agc->get_extra_data_chunk(); + AVP_Strategy_Chunk* asc=0; + + if(agedc) + { + Chunk * pChunk = agedc->lookup_single_child("AVPSTRAT"); + if(pChunk) + { + asc=(AVP_Strategy_Chunk*) pChunk; + + if(asc->Strategy) + { + switch(asc->Strategy->StrategyType) + { + case StratEnemy : + { + EnemyStrategy* es=(EnemyStrategy*)asc->Strategy; + + switch (es->MissionType) + { + case 1: + tdm->Mission=MM_Wander; + break; + case 2: + tdm->Mission=MM_Guard; + break; + case 3: + tdm->Mission=MM_NonCom; + break; + case 4: + tdm->Mission=MM_LocalGuard; + break; + case 5: + tdm->Mission=MM_Pathfinder; + tdm->path=es->ExtraMissionData &0xffff; + tdm->stepnumber=ConvertObjectIndexToPathIndex(tdm->path,es->ExtraMissionData>>16); + if(tdm->stepnumber==-1) + { + LOGDXFMT(("Error setting up path for marine %s\n",agc->name)); + GLOBALASSERT(0); + } + break; + } + + *(ObjectID*)&tdm->death_target_ID[0]=es->DeathTarget; + + tdm->death_target_request=es->target_request; + + } + break; + } + } + } + } + + switch (agc->sub_type) + { + case 0: //pulse rifle + tdm->marine_type=MNPCW_PulseRifle; + break; + + case 5: //pistol marine + tdm->marine_type=MNPCW_PistolMarine; + break; + + case 10: //smartgun + tdm->marine_type=MNPCW_Smartgun; + break; + + case 20://grenade launcher + tdm->marine_type=MNPCW_GrenadeLauncher; + break; + + case 30://shotgun 1 + case 31://shotgun 2 + case 32://shotgun 3 + tdm->marine_type=MNPCW_MShotgun; + break; + + case 80://Molotov + tdm->marine_type=MNPCW_MMolotov; + break; + + case 40://pistol 1 + case 41://pistol 2 + case 90://Scientist1 + case 91://Scientist2 + tdm->marine_type=MNPCW_MPistol; + break; + + case 50://flamethrower + tdm->marine_type=MNPCW_Flamethrower; + break; + + case 60://sadar + tdm->marine_type=MNPCW_SADAR; + break; + + case 70://Minigun + tdm->marine_type=MNPCW_Minigun; + break; + + case 100://Civilian flamer + tdm->marine_type=MNPCW_MFlamer; + break; + + case 110://Civilian unarmed + tdm->marine_type=MNPCW_MUnarmed; + break; + + case 120://android + tdm->marine_type=MNPCW_Android; + break; + + default: + tdm->marine_type=MNPCW_PulseRifle; + break; + } + + + AddToBehaviourList(agc->name,ID, I_BehaviourMarine, (void *) tdm,0,agc->get_alternate_locations_chunk(),agc->flags); +} + + +static void add_predator(AVP_Generator_Chunk * agc) +{ + + TOOLS_DATA_PREDATOR* tdp=(TOOLS_DATA_PREDATOR*) PoolAllocateMem(sizeof(TOOLS_DATA_PREDATOR)); + tdp->position.vx = agc->location.x * local_scale; + tdp->position.vy = agc->location.y * local_scale; + tdp->position.vz = agc->location.z * local_scale; + + #if 0 + switch (agc->textureID) + { + case 1: + tdp->shapeIndex = GetLoadedShapeMSL("PHead1"); + break; + case 2: + tdp->shapeIndex = GetLoadedShapeMSL("PHead2"); + break; + case 3: + tdp->shapeIndex = GetLoadedShapeMSL("PHead3"); + break; + case 4: + tdp->shapeIndex = GetLoadedShapeMSL("PHead4"); + break; + default : + tdp->shapeIndex = GetLoadedShapeMSL("fred"); /* patrick 8/7/96 */ + break; + } + #endif + tdp->predator_number=agc->textureID; + tdp->shapeIndex = 0; + + switch((agc->sub_type)&7) + { + case 0: + tdp->primary=PNPCW_Pistol; + break; + case 1: + tdp->primary=PNPCW_Wristblade; + break; + case 2: + tdp->primary=PNPCW_PlasmaCaster; + break; + case 3: + tdp->primary=PNPCW_Staff; + break; + default : + tdp->primary=PNPCW_Pistol; + break; + + } + switch((agc->sub_type>>3)&7) + { + case 0: + tdp->secondary=PNPCW_Pistol; + break; + case 1: + tdp->secondary=PNPCW_Wristblade; + break; + case 2: + tdp->secondary=PNPCW_PlasmaCaster; + break; + case 3: + tdp->secondary=PNPCW_Staff; + break; + default : + tdp->secondary=PNPCW_Pistol; + break; + + } + //make sure primary and secondary weapons are different + if(tdp->primary==tdp->secondary) + { + if(tdp->primary==PNPCW_Wristblade) + tdp->secondary=PNPCW_Pistol; + else + tdp->secondary=PNPCW_Wristblade; + } + + tdp->path=-1; + tdp->stepnumber=-1; + + for(int i=0;ideath_target_ID[i]=0; + //look for extra strategy stuff + AVP_Generator_Extra_Data_Chunk* agedc=agc->get_extra_data_chunk(); + AVP_Strategy_Chunk* asc=0; + + if(agedc) + { + Chunk * pChunk = agedc->lookup_single_child("AVPSTRAT"); + if(pChunk) + { + asc=(AVP_Strategy_Chunk*) pChunk; + + if(asc->Strategy) + { + switch(asc->Strategy->StrategyType) + { + case StratEnemy : + { + EnemyStrategy* es=(EnemyStrategy*)asc->Strategy; + + *(ObjectID*)&tdp->death_target_ID[0]=es->DeathTarget; + tdp->death_target_request=es->target_request; + switch (es->MissionType) + { + case 1: + tdp->path=es->ExtraMissionData &0xffff; + tdp->stepnumber=ConvertObjectIndexToPathIndex(tdp->path,es->ExtraMissionData>>16); + if(tdp->stepnumber==-1) + { + LOGDXFMT(("Error setting up path for predator %s\n",agc->name)); + GLOBALASSERT(0); + } + + break; + } + + + } + break; + } + } + } + } + + + + + ObjectID ID=agc->CalculateID(); + *(ObjectID*)&tdp->nameID[0] = ID; + + if(agc->flags & AVPGENFLAG_GENERATORINACTIVE) + AddToBehaviourList(agc->name,ID, I_BehaviourDormantPredator, (void *) tdp,0,agc->get_alternate_locations_chunk(),agc->flags); + else + AddToBehaviourList(agc->name,ID, I_BehaviourPredator, (void *) tdp,0,agc->get_alternate_locations_chunk(),agc->flags); +} + +static void add_queen(AVP_Generator_Chunk * agc) +{ + + TOOLS_DATA_QUEEN* tdq=(TOOLS_DATA_QUEEN*) PoolAllocateMem(sizeof(TOOLS_DATA_QUEEN)); + tdq->position.vx = agc->location.x * local_scale; + tdq->position.vy = agc->location.y * local_scale; + tdq->position.vz = agc->location.z * local_scale; + + tdq->shapeIndex = 0; + + ObjectID ID=agc->CalculateID(); + *(ObjectID*)&tdq->nameID[0]=ID; + + + //look for extra strategy stuff + for(int i=0;ideath_target_ID[i]=0; + tdq->death_target_request=0; + + AVP_Generator_Extra_Data_Chunk* agedc=agc->get_extra_data_chunk(); + AVP_Strategy_Chunk* asc=0; + if(agedc) + { + Chunk * pChunk = agedc->lookup_single_child("AVPSTRAT"); + if(pChunk) + { + asc=(AVP_Strategy_Chunk*) pChunk; + + if(asc->Strategy) + { + switch(asc->Strategy->StrategyType) + { + case StratEnemy : + { + EnemyStrategy* es=(EnemyStrategy*)asc->Strategy; + + *(ObjectID*)&tdq->death_target_ID[0]=es->DeathTarget; + tdq->death_target_request=es->target_request; + } + break; + + } + } + } + } + + + AddToBehaviourList(agc->name,ID, I_BehaviourQueenAlien, (void *) tdq,0,agc->get_alternate_locations_chunk(),agc->flags); + +} + +static void add_hugger(AVP_Generator_Chunk * agc) +{ + + TOOLS_DATA_FACEHUGGER* tdfh =(TOOLS_DATA_FACEHUGGER*) PoolAllocateMem(sizeof(TOOLS_DATA_FACEHUGGER)); + + tdfh->position.vx = agc->location.x * local_scale; + tdfh->position.vy = agc->location.y * local_scale; + tdfh->position.vz = agc->location.z * local_scale; + + //tdfh->shapeIndex = GetLoadedShapeMSL("Facehug"); + tdfh->shapeIndex = 0; + + tdfh->startInactive=(agc->flags & AVPGENFLAG_GENERATORINACTIVE)!=0; + + ObjectID ID=agc->CalculateID(); + *(ObjectID*)&tdfh->nameID[0]=ID; + + + for(int i=0;ideath_target_ID[i]=0; + + //look for extra strategy stuff + AVP_Generator_Extra_Data_Chunk* agedc=agc->get_extra_data_chunk(); + AVP_Strategy_Chunk* asc=0; + + if(agedc) + { + Chunk * pChunk = agedc->lookup_single_child("AVPSTRAT"); + if(pChunk) + { + asc=(AVP_Strategy_Chunk*) pChunk; + + if(asc->Strategy) + { + switch(asc->Strategy->StrategyType) + { + case StratEnemy : + { + EnemyStrategy* es=(EnemyStrategy*)asc->Strategy; + + *(ObjectID*)&tdfh->death_target_ID[0]=es->DeathTarget; + tdfh->death_target_request=es->target_request; + + } + break; + } + } + } + } + + + AddToBehaviourList(agc->name,ID, I_BehaviourFaceHugger, (void *) tdfh,0,agc->get_alternate_locations_chunk(),agc->flags); +} + +static void add_autogun(AVP_Generator_Chunk * agc) +{ + AUTOGUN_TOOLS_TEMPLATE* att=(AUTOGUN_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(AUTOGUN_TOOLS_TEMPLATE)); + att->position.vx = agc->location.x * local_scale; + att->position.vy = agc->location.y * local_scale; + att->position.vz = agc->location.z * local_scale; + + att->shapenum = 0; + + att->startInactive=(agc->flags & AVPGENFLAG_GENERATORINACTIVE)!=0; + + att->orientation.EulerX=0; + att->orientation.EulerY=agc->orientation & 4095; + att->orientation.EulerZ=0; + + att->ammo=(agc->extra1<<8)+agc->extra2; + if(att->ammo>=30000) att->ammo=0x7fffffff; + + //look for extra strategy stuff + for(int i=0;ideath_target_ID[i]=0; + att->death_target_request=0; + + AVP_Generator_Extra_Data_Chunk* agedc=agc->get_extra_data_chunk(); + AVP_Strategy_Chunk* asc=0; + if(agedc) + { + Chunk * pChunk = agedc->lookup_single_child("AVPSTRAT"); + if(pChunk) + { + asc=(AVP_Strategy_Chunk*) pChunk; + + if(asc->Strategy) + { + switch(asc->Strategy->StrategyType) + { + case StratEnemy : + { + EnemyStrategy* es=(EnemyStrategy*)asc->Strategy; + + *(ObjectID*)&att->death_target_ID[0]=es->DeathTarget; + att->death_target_request=es->target_request; + } + break; + + } + } + } + } + + + ObjectID ID=agc->CalculateID(); + *(ObjectID*)&att->nameID[0]=ID; + + AddToBehaviourList(agc->name,ID,I_BehaviourAutoGun, (void *) att,0,agc->get_alternate_locations_chunk(),agc->flags); +} + + +static void add_xenoborg(AVP_Generator_Chunk * agc) +{ + + TOOLS_DATA_XENO* tdx=(TOOLS_DATA_XENO*) PoolAllocateMem(sizeof(TOOLS_DATA_XENO)); + + tdx->position.vx = agc->location.x * local_scale; + tdx->position.vy = agc->location.y * local_scale; + tdx->position.vz = agc->location.z * local_scale; + + tdx->shapeIndex = 0; + + tdx->starteuler.EulerX=0; + tdx->starteuler.EulerY=agc->orientation & 4095; + tdx->starteuler.EulerZ=0; + + if(agc->extra1) + tdx->UpTime=(int)agc->extra1*5; + else + tdx->UpTime=20;//default value + if(agc->extra2) + tdx->ModuleRange=agc->extra2; + else + tdx->ModuleRange=7;//default value + + //look for extra strategy stuff + for(int i=0;ideath_target_ID[i]=0; + tdx->death_target_request=0; + AVP_Generator_Extra_Data_Chunk* agedc=agc->get_extra_data_chunk(); + AVP_Strategy_Chunk* asc=0; + if(agedc) + { + Chunk * pChunk = agedc->lookup_single_child("AVPSTRAT"); + if(pChunk) + { + asc=(AVP_Strategy_Chunk*) pChunk; + + if(asc->Strategy) + { + switch(asc->Strategy->StrategyType) + { + case StratEnemy : + { + EnemyStrategy* es=(EnemyStrategy*)asc->Strategy; + + *(ObjectID*)&tdx->death_target_ID[0]=es->DeathTarget; + tdx->death_target_request=es->target_request; + } + break; + + } + } + } + } + + + ObjectID ID=agc->CalculateID(); + *(ObjectID*)&tdx->nameID[0]=ID; + + + AddToBehaviourList(agc->name,ID, I_BehaviourXenoborg, (void *) tdx,0,agc->get_alternate_locations_chunk(),agc->flags); + +} + +extern "C"{ +extern void SetHiveParamaters(int enemytype,int max,int genpermin,int deltagenpermin,int time); +}; + +void setup_generators (Environment_Data_Chunk * envd) +{ + //first setup the global generator paramaters + Chunk * pChunk = envd->lookup_single_child("GLOGENDC"); + + int generator_enemy; + + if(pChunk) + { + Global_Generator_Data_Chunk* ggdc=(Global_Generator_Data_Chunk*)pChunk; + switch(ggdc->EnemyGenerated) + { + case Generate_Aliens : + generator_enemy=I_BehaviourAlien; + break; + case Generate_Marines : + generator_enemy=I_BehaviourMarine; + break; + default : + GLOBALASSERT("Invalid enemy type"==0); + + } + SetHiveParamaters(generator_enemy,ggdc->MaxNPCSOnLevel,ggdc->NPCSPerMinute,ggdc->NPCAcceleration,ggdc->HiveStateChangeTime*ONE_FIXED); + + } + else + { + generator_enemy=I_BehaviourAlien; + SetHiveParamaters(generator_enemy,25,4,2,60*ONE_FIXED); + } + + + + Special_Objects_Chunk * soc = 0; + + pChunk = envd->lookup_single_child ("SPECLOBJ"); + if (pChunk) + { + soc = (Special_Objects_Chunk *)pChunk; + } + // and alien generator objects + + if (soc) + { + { + List cl; + soc->lookup_child("AVPGENER",cl); + for (LIF cli(&cl); !cli.done(); cli.next()) + { + AVP_Generator_Chunk * agc = (AVP_Generator_Chunk *)cli(); + + if (agc->type) + { + + #if 0 + if(AvP.PlayerType==I_Alien && (agc->flags & AVPGENFLAG_AVPGAMEMODEALIEN)|| + AvP.PlayerType==I_Marine && (agc->flags & AVPGENFLAG_AVPGAMEMODEMARINE)|| + AvP.PlayerType==I_Predator && (agc->flags & AVPGENFLAG_AVPGAMEMODEPREDATOR)) + #endif + { + //note : only aliens can appear in a network game + switch (agc->type) + { + case 1: + add_alien(agc); + break; + case 2: + if(AvP.Network == I_No_Network) + add_predator(agc); + break; + + case 3: + if(AvP.Network == I_No_Network) + add_hugger(agc); + break; + case 4: + if(AvP.Network == I_No_Network) + add_xenoborg(agc); + break; + case 5: + add_alien(agc);//add_alien also does predaliens + break; + case 6: + if(AvP.Network == I_No_Network) + add_queen(agc); + break; + case 7: + if(AvP.Network == I_No_Network) + add_marine(agc); + break; + case 8: + add_alien(agc); //add_alien will also do pretorian guards + break; + + case 9: + if(AvP.Network == I_No_Network) + add_autogun(agc); + break; + + default: + + break; + } + + + } + } + else + { + #if 0 + //check to see if generator is flagged for this game mode + + if(AvP.PlayerType==I_Alien && (agc->flags & AVPGENFLAG_AVPGAMEMODEALIEN)|| + AvP.PlayerType==I_Marine && (agc->flags & AVPGENFLAG_AVPGAMEMODEMARINE)|| + AvP.PlayerType==I_Predator && (agc->flags & AVPGENFLAG_AVPGAMEMODEPREDATOR)) + #endif + //see if generator is a multiplayer start position + if(agc->flags & AVPGENFLAG_MULTIPLAYERSTART) + { + continue; + } + + + { + ObjectID ID=agc->CalculateID(); + + + GENERATOR_BLOCK* tdg = (GENERATOR_BLOCK*) PoolAllocateMem(sizeof(GENERATOR_BLOCK)); + memset(tdg,0,sizeof(GENERATOR_BLOCK)); + + tdg->Position.vx = agc->location.x * local_scale; + tdg->Position.vy = agc->location.y * local_scale; + tdg->Position.vz = agc->location.z * local_scale; + tdg->Active=!(agc->flags & AVPGENFLAG_GENERATORINACTIVE); + + tdg->GenerationRate=1; + tdg->GenerationRateIncrease=0; + tdg->use_own_rate_values=0; + + tdg->MaxGenNPCs=0; + tdg->use_own_max_npc=0; + + tdg->path=-1; + tdg->stepnumber=-1; + + AVP_Generator_Extended_Settings_Chunk* setting=agc->get_extended_settings(); + if(setting) + { + /*The weightings are in the same order in generator_block and avp_generator_weighting, + and I can't be bothered to copy them individually*/ + int* copyfrom = (int*) &setting->weights->PulseMarine_Wt; + int* copyto = (int*) &tdg->PulseMarine_Wt; + + for(int i=0;i<15;i++) + { + copyto[i]=copyfrom[i]; + tdg->WeightingTotal+=copyto[i]; + } + + if(agc->flags & AVPGENFLAG_USEOWNRATE) + { + tdg->GenerationRate=setting->GenerationRate; + tdg->GenerationRateIncrease=setting->GenRateIncrease; + tdg->use_own_rate_values=1; + } + if(agc->flags & AVPGENFLAG_USEOWNLIMIT) + { + tdg->MaxGenNPCs=setting->GenLimit; + tdg->use_own_max_npc=1; + } + + } + + if(tdg->WeightingTotal==0) + { + //set genrator to generate level's default creature + if(generator_enemy==I_BehaviourAlien) + { + tdg->Alien_Wt=1; + tdg->WeightingTotal=1; + } + else + { + tdg->PulseMarine_Wt=1; + tdg->WeightingTotal=1; + } + + } + + + /*See if generator has extra strategy data, currently just used for producing path following creatures*/ + + AVP_Generator_Extra_Data_Chunk* agedc=agc->get_extra_data_chunk(); + + if(agedc) + { + AVP_Strategy_Chunk* asc = (AVP_Strategy_Chunk*) agedc->lookup_single_child("AVPSTRAT"); + if(asc) + { + + if(asc->Strategy) + { + switch(asc->Strategy->StrategyType) + { + case StratGenerator : + { + GeneratorStrategy* gs=(GeneratorStrategy*)asc->Strategy; + + if(gs->MissionType==1) + { + tdg->path=gs->ExtraMissionData &0xffff; + tdg->stepnumber=ConvertObjectIndexToPathIndex(tdg->path,gs->ExtraMissionData>>16); + if(tdg->stepnumber==-1) + { + LOGDXFMT(("Error setting up path for generator %s\n",agc->name)); + GLOBALASSERT(0); + } + } + + + } + break; + } + } + } + } + + + AddToBehaviourList(agc->name,ID, I_BehaviourGenerator, (void *) tdg,0,agc->get_alternate_locations_chunk(),agc->flags); + } + } + + } + } + + if(AvP.Network != I_No_Network) + { + //setup multiplayer start positions + numMarineStartPos=0; + numAlienStartPos=0; + numPredatorStartPos=0; + + marineStartPositions=0; + alienStartPositions=0; + predatorStartPositions=0; + + //go through the list to find the number of each type of start location + List cl; + soc->lookup_child("AVPGENER",cl); + for (LIF cli(&cl); !cli.done(); cli.next()) + { + AVP_Generator_Chunk * agc = (AVP_Generator_Chunk *)cli(); + if(agc->type) continue; + if(!(agc->flags & AVPGENFLAG_MULTIPLAYERSTART)) + { + continue; + } + + + if(agc->flags & AVPGENFLAG_AVPGAMEMODEALIEN) numAlienStartPos++; + if(agc->flags & AVPGENFLAG_AVPGAMEMODEMARINE) numMarineStartPos++; + if(agc->flags & AVPGENFLAG_AVPGAMEMODEPREDATOR) numPredatorStartPos++; + } + + if(numMarineStartPos) + { + marineStartPositions=(MULTIPLAYER_START*) PoolAllocateMem(sizeof(MULTIPLAYER_START)*numMarineStartPos); + } + if(numPredatorStartPos) + { + predatorStartPositions=(MULTIPLAYER_START*) PoolAllocateMem(sizeof(MULTIPLAYER_START)*numPredatorStartPos); + } + if(numAlienStartPos) + { + alienStartPositions=(MULTIPLAYER_START*) PoolAllocateMem(sizeof(MULTIPLAYER_START)*numAlienStartPos); + } + + int mpos=0; + int apos=0; + int ppos=0; + + //go through the list a second time setting up the positions + for(cli.restart();!cli.done();cli.next()) + { + AVP_Generator_Chunk * agc = (AVP_Generator_Chunk *)cli(); + if(agc->type) continue; + if(!(agc->flags & AVPGENFLAG_MULTIPLAYERSTART)) + { + continue; + } + + MULTIPLAYER_START start_pos; + start_pos.location.vx = agc->location.x * local_scale; + start_pos.location.vy = agc->location.y * local_scale; + start_pos.location.vz = agc->location.z * local_scale; + + start_pos.orientation.EulerX=0; + start_pos.orientation.EulerY=agc->orientation & 4095; + start_pos.orientation.EulerZ=0; + + if(agc->flags & AVPGENFLAG_AVPGAMEMODEALIEN) alienStartPositions[apos++]=start_pos; + if(agc->flags & AVPGENFLAG_AVPGAMEMODEMARINE) marineStartPositions[mpos++]=start_pos; + if(agc->flags & AVPGENFLAG_AVPGAMEMODEPREDATOR) predatorStartPositions[ppos++]=start_pos; + } + } + } + +} + +typedef struct mission_setup +{ + AVP_Strategy_Chunk* asc; + int order_number; + ObjectID ID; + MissionObjective* mission; +}MISSION_SETUP; + +static List mos_list; + +static void add_mission_to_list(AVP_Strategy_Chunk * asc,ObjectID id) +{ + MISSION_SETUP* ms=new MISSION_SETUP; + + ms->asc=asc; + ms->ID=id; + ms->mission=0; + + MissionObjectiveStrategy * mos = (MissionObjectiveStrategy *)asc->Strategy; + ms->order_number=mos->mission_number; + + for(LIF mlif(&mos_list);!mlif.done();mlif.next()) + { + if(mlif()->order_number>ms->order_number) + { + mos_list.add_entry_before(ms,mlif()); + return; + } + } + mos_list.add_entry(ms); +} + +void SetupMissionObjectives() +{ + for(LIF mlif(&mos_list);!mlif.done();mlif.next()) + { + MissionObjectiveStrategy * mos=(MissionObjectiveStrategy*) mlif()->asc->Strategy; + assert (mos->mission_description_string>=0 && mos->mission_description_string<450); + assert (mos->mission_complete_string>=0 && mos->mission_complete_string<450); + + TEXTSTRING_ID desc_string; + if(mos->mission_description_string==0) + desc_string=TEXTSTRING_BLANK; + else + desc_string=(TEXTSTRING_ID)((mos->mission_description_string-1)+TEXTSTRING_LEVELMSG_001); + + TEXTSTRING_ID complete_string; + if(mos->mission_complete_string==0) + complete_string=TEXTSTRING_BLANK; + else + complete_string=(TEXTSTRING_ID)((mos->mission_complete_string-1)+TEXTSTRING_LEVELMSG_001); + + MissionObjectiveState m_state; + + if(mos->flags & MissionFlag_Visible) + { + if (mos->flags & MissionFlag_CurrentlyPossible) + m_state=MOS_VisibleUnachieved; + else + m_state=MOS_VisibleUnachievedNotPossible; + } + else if (mos->flags & MissionFlag_CurrentlyPossible) + { + m_state=MOS_HiddenUnachieved; + } + else + m_state=MOS_HiddenUnachievedNotPossible; + + MissionObjective* mission; + + /* KJL 22:50:21 02/08/98 - set any additional effect of completing the mission */ + switch(mos->mission_completion_effect) + { + default: // fall through to 'no effect' if effect not yet catered for + case MCE_None: + mission = new MissionObjective(desc_string,m_state,complete_string,MissionFX_None); + break; + case MCE_CompleteLevel: + mission = new MissionObjective(desc_string,m_state,complete_string,MissionFX_CompletesLevel); + break; + } + + mlif()->mission=mission; + + MISSION_COMPLETE_TOOLS_TEMPLATE* mctt=(MISSION_COMPLETE_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(MISSION_COMPLETE_TOOLS_TEMPLATE)); + mctt->mission_objective_ptr=mission; + *(ObjectID*)&mctt->nameID[0]=mlif()->ID; + + AddToBehaviourList(0,mlif()->ID, I_BehaviourMissionComplete, (void*)mctt,-1); + } + + //now set up the mission alterations + for(mlif.restart();!mlif.done();mlif.next()) + { + MissionObjectiveStrategy * mos=(MissionObjectiveStrategy*) mlif()->asc->Strategy; + + for(int i=0;inum_mission_targets;i++) + { + //find the mission referred to + for(LIF mlif2(&mos_list);!mlif2.done();mlif2.next()) + { + if(mlif2()->ID==mos->mission_targets->target_mission) + { + mlif()->mission->AddMissionAlteration(mlif2()->mission,mos->mission_targets->effect_on_target); + break; + } + } + + } + + } + + while(mos_list.size()) + { + delete mos_list.first_entry(); + mos_list.delete_first_entry(); + } +} + + + +void setup_light_data (LIGHTBLOCK * lPtr, Light_Chunk * lc) +{ + /* KJL 14:42:42 20/02/98 - this function has been updated; + many things have been removed from the lightblock structure */ + + lPtr->LightFlags = lc->light.engine_light_flags | LFlag_PreLitSource + | LFlag_AbsPos | LFlag_WasNotAllocated + | LFlag_AbsLightDir | LFlag_CosAtten; // Forcing attenuation + + lPtr->LightType = LightType_PerVertex; + + lPtr->LightWorld.vx = lc->light.location.x * local_scale; + lPtr->LightWorld.vy = lc->light.location.y * local_scale; + lPtr->LightWorld.vz = lc->light.location.z * local_scale; + + lPtr->LightBright = lc->light.brightness * 1.0; + lPtr->LightBrightStore = lc->light.brightness * 1.0; + + /* KJL 10:57:57 9/24/97 - colour scales - these take the values 0 to 65536 */ + lPtr->RedScale = ((lc->light.colour>>16)&255)*257; + lPtr->GreenScale = ((lc->light.colour>>8)&255)*257; + lPtr->BlueScale = ((lc->light.colour)&255)*257; + + lPtr->LightRange = (lc->light.range * 1.0) * local_scale; + + if (lc->light.local_light_flags & LOFlag_NoPreLight) + { + lPtr->LightFlags &= ~LFlag_PreLitSource; + } + +} + +void setup_placed_light_data (LIGHTBLOCK * lPtr, Placed_Object_Light_Chunk * lc) +{ + /* KJL 14:42:42 20/02/98 - this function has been updated; + many things have been removed from the lightblock structure */ + + lPtr->LightFlags = lc->light.engine_light_flags | LFlag_WasNotAllocated + | LFlag_AbsLightDir | LFlag_CosAtten; // Forcing attenuation + + if(lc->light.flags & PlacedLightFlag_NoSpecular) + { + lPtr->LightFlags|=LFlag_NoSpecular; + } + + lPtr->LightType = LightType_PerVertex; + + lPtr->LightWorld.vx = 0; + lPtr->LightWorld.vy = 0; + lPtr->LightWorld.vz = 0; + + lPtr->LightBright = lc->light.brightness * 1.0; + lPtr->LightBrightStore = lc->light.brightness * 1.0; + + /* KJL 10:57:57 9/24/97 - colour scales - these take the values 0 to 65536 */ + lPtr->RedScale = ((lc->light.up_colour>>16)&255)*257; + lPtr->GreenScale = ((lc->light.up_colour>>8)&255)*257; + lPtr->BlueScale = ((lc->light.up_colour)&255)*257; + + lPtr->LightRange = (lc->light.range * 1.0) * local_scale; + +} + +void SetUpRunTimeLights () +{ + // go through the list of modules adding lights + + Environment_Data_Chunk * edc = 0; + Light_Set_Chunk * lsc = 0; + + Chunk * pChunk = Env_Chunk->lookup_single_child("REBENVDT"); + + if (pChunk) + { + edc = (Environment_Data_Chunk *)pChunk; + + List cl; + edc->lookup_child("LIGHTSET",cl); + + while (cl.size()) + { + Light_Set_Chunk * ls = (Light_Set_Chunk *)cl.first_entry(); + + Chunk * pChunk2 = ls->lookup_single_child("LTSETHDR"); + if (pChunk2) + { + if (!strncmp(light_set_name, ((Light_Set_Header_Chunk *)pChunk2)->light_set_name, 8)) + { + lsc = ls; + break; + } + } + + cl.delete_first_entry(); + } + + } + + if (!lsc) + { + return; + } + + pChunk = lsc->lookup_single_child("AMBIENCE"); + + if (pChunk) + { + GlobalAmbience = (chnk_playcam_vdb.SVDB_Ambience = ((Lighting_Ambience_Chunk *)pChunk)->ambience); + + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + + if (VDBPtr) + { + VDBPtr->VDB_Ambience = GlobalAmbience; + } + } + + List cl; + lsc->lookup_child ("STDLIGHT",cl); + LIF cli(&cl); + + + MODULE ** m_arrayPtr = MainScene.sm_marray; + + while (*m_arrayPtr) + { + List lights_for_this_module; + + MODULE * this_mod = *m_arrayPtr++; + + if (this_mod->m_flags & m_flag_infinite) + { + continue; + } + + for (cli.restart(); !cli.done(); cli.next()) + { + Light_Chunk * lc = (Light_Chunk *)cli(); + + // try to throw away light + if (!(lc->light.local_light_flags & LOFlag_Runtime)) + { + continue; + } + + if (lc->light_added_to_module) + { + continue; + } + + if ((lc->light.location.x * local_scale) > (this_mod->m_world.vx + this_mod->m_maxx)) + continue; + + if ((lc->light.location.x * local_scale) < (this_mod->m_world.vx + this_mod->m_minx)) + continue; + + if ((lc->light.location.y * local_scale) > (this_mod->m_world.vy + this_mod->m_maxy)) + continue; + + if ((lc->light.location.y * local_scale) < (this_mod->m_world.vy + this_mod->m_miny)) + continue; + + if ((lc->light.location.z * local_scale) > (this_mod->m_world.vz + this_mod->m_maxz)) + continue; + + if ((lc->light.location.z * local_scale) < (this_mod->m_world.vz + this_mod->m_minz)) + continue; + + // light in module + + lc->light_added_to_module = TRUE; + + lights_for_this_module.add_entry(lc); + + } + + this_mod->m_numlights = lights_for_this_module.size(); + + assert (lights_for_this_module.size() <= MaxObjectLights); + + if (lights_for_this_module.size()) + { + this_mod->m_lightarray = (LIGHTBLOCK *) PoolAllocateMem (sizeof(LIGHTBLOCK)*(lights_for_this_module.size())); + if (!this_mod->m_lightarray) + { + memoryInitialisationFailure = 1; + return; + } + + LIGHTBLOCK * lPtr = this_mod->m_lightarray; + + for (LIF lci(&lights_for_this_module); !lci.done(); lci.next(), lPtr++) + { + setup_light_data (lPtr, lci()); + } + } + else + { + this_mod->m_lightarray = 0; + } + } +} +#if 0 +void SetupExternalLift(AVP_External_Strategy_Chunk* aesc) +{ + LiftStrategy* ls=(LiftStrategy*)aesc->Strategy; + + ObjectID ControlID={0x7fffffff,0x7fffffff}; + for(int i=0;iNumExternalLifts;i++) + { + if(ls->ExternalLifts[i].EnvNum==aesc->ThisEnvNum) + { + ControlID=Minimum(ControlID,ls->ExternalLifts[i].LiftID); + } + } + + + LIFT_TOOLS_TEMPLATE * ltt = new LIFT_TOOLS_TEMPLATE; + + *((ObjectID *)ltt->my_module_name) = aesc->ObjID; + *((ObjectID *)ltt->call_switch_name) = ls->AssocCallSwitch; + *((ObjectID *)ltt->lift_door_name) = ls->AssocDoor; + *((ObjectID *)ltt->lift_floor_switch_name) = ls->AssocFloorSwitch; + + ltt->environment = aesc->ExtEnvNum-1; + + ltt->num_floor = ls->Floor; + + *((ObjectID *)ltt->control_sb_name)=ControlID; + + ltt->controller = 0; + + ltt->num_stations = ls->NumAssocLifts + ls->NumExternalLifts+1; + + ltt->lift_flags=ls->LiftFlags; + + *((ObjectID *)ltt->nameID) = aesc->ObjID; + + ltt->orient=ls->Facing; + if((ls->LiftFlags & LiftFlag_Airlock) || (ls->LiftFlags & LiftFlag_ExitOtherSide)) + ltt->orient=(ltt->orient+2) % 4; + + ltt_list.add_entry(ltt); +} +#endif + +void DealWithExternalObjectStategies (Environment_Data_Chunk * envd) +{ + List chlist; + #if 0 + envd->lookup_child("AVPEXSTR",chlist); + for(LIF slif(&chlist);!slif.done();slif.next()) + { + AVP_External_Strategy_Chunk* aesc=(AVP_External_Strategy_Chunk*) slif(); + if(aesc->Strategy) + { + switch(aesc->Strategy->StrategyType) + { + case StratLift : + SetupExternalLift(aesc); + break; + } + } + } + #endif + + Chunk * pChunk = envd->lookup_single_child("SPECLOBJ"); + if(pChunk) + { + List chlist; + ((Chunk_With_Children*)pChunk)->lookup_child("VIOBJECT",chlist); + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + Virtual_Object_Chunk* voc=(Virtual_Object_Chunk*)chlif(); + Chunk * pChunk2=voc->lookup_single_child("AVPSTRAT"); + if(!pChunk2)continue; + AVP_Strategy_Chunk* asc=(AVP_Strategy_Chunk*)pChunk2; + + pChunk2=voc->lookup_single_child("VOBJPROP"); + if(!pChunk2)continue; + Virtual_Object_Properties_Chunk* vopc=(Virtual_Object_Properties_Chunk*)pChunk2; + + if(asc->Strategy) + { + switch(asc->Strategy->StrategyType) + { + case StratAreaSwitch: //(Area Switch derived from Multi Switch) + case StratMultiSwitch: + add_multiswitch (vopc->name,asc,vopc->ID); + break; + case StratBinSwitch: + add_binswitch (vopc->name,asc,vopc->ID); + break; + case StratLinkSwitch: + add_linkswitch (vopc->name,asc,vopc->ID); + break; + + case StratMessage: + add_message_strategy (vopc->name,asc,vopc->ID); + break; + + case StratMissionObjective : + add_mission_to_list(asc,vopc->ID); + break; + + case StratDeathVolume : + add_deathvolume(vopc->name,asc,vopc->ID); + break; + + case StratSelfDestruct : + add_selfdestruct(vopc->name,asc,vopc->ID); + break; + } + } + } + } + SetupMissionObjectives(); +} + + +void setup_sounds (Environment_Data_Chunk * envd) +{ + Special_Objects_Chunk * soc = 0; + + Chunk * pChunk = envd->lookup_single_child ("SPECLOBJ"); + if (pChunk) + { + soc = (Special_Objects_Chunk *)pChunk; + } + + if (soc) + { + List cl; + soc->lookup_child("SOUNDOB2",cl); + for (LIF cli(&cl); !cli.done(); cli.next()) + { + Sound_Object_Chunk * snd = (Sound_Object_Chunk *) cli(); + SOUND_TOOLS_TEMPLATE* stt =(SOUND_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(SOUND_TOOLS_TEMPLATE)); + + stt->position.vx = snd->position.x * local_scale; + stt->position.vy = snd->position.y * local_scale; + stt->position.vz = snd->position.z * local_scale; + + stt->inner_range = snd->inner_range * local_scale; + stt->outer_range = snd->outer_range * local_scale; + stt->max_volume = snd->max_volume; + stt->pitch = snd->pitch; + + if(snd->flags & SoundObjectFlag_NotPlayingAtStart) + stt->playing=0; + else + stt->playing=1; + + if(snd->flags & SoundObjectFlag_NoLoop) + stt->loop=0; + else + stt->loop=1; + + + stt->sound_name =(char*) PoolAllocateMem(strlen (snd->wav_name) + 1); + strcpy(stt->sound_name,snd->wav_name); + stt->sound_loaded=GetSoundForMainRif(snd->wav_name); + + + AddToBehaviourList(snd->snd_name,snd->CalculateID(), I_BehaviourPlacedSound, (void *) stt); + } + } +} + + +void setup_cables(Environment_Data_Chunk * envd) +{ + if(!envd) return; + Special_Objects_Chunk* soc = (Special_Objects_Chunk*) envd->lookup_single_child("SPECLOBJ"); + if(!soc) return; + List chlist; + soc->lookup_child("AVPCABLE",chlist); + + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + AVP_Power_Cable_Chunk* appc=(AVP_Power_Cable_Chunk*)chlif(); + + POWER_CABLE_TOOLS_TEMPLATE* tdpc=(POWER_CABLE_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(POWER_CABLE_TOOLS_TEMPLATE)); + + tdpc->position.vx = appc->location.x * local_scale; + tdpc->position.vy = appc->location.y * local_scale; + tdpc->position.vz = appc->location.z * local_scale; + + if(appc->flags & PowerCableFlag_UseDefaultSettings) + { + tdpc->max_charge=90*ONE_FIXED; + tdpc->current_charge=90*ONE_FIXED; + tdpc->recharge_rate=ONE_FIXED; + } + else + { + tdpc->max_charge=appc->max_charge; + tdpc->current_charge=appc->initial_charge; + tdpc->recharge_rate=appc->recharge_rate; + } + *(ObjectID*)&tdpc->nameID[0]=appc->id; + + AddToBehaviourList(0,appc->id, I_BehaviourPowerCable, (void *) tdpc,0); + + } +} + +void setup_particle_generators(Environment_Data_Chunk * envd) +{ + if(!envd) return; + Special_Objects_Chunk* soc = (Special_Objects_Chunk*) envd->lookup_single_child("SPECLOBJ"); + if(!soc) return; + + List chlist; + soc->lookup_child("PARGENER",chlist); + + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + + AVP_Particle_Generator_Chunk* part_chunk=(AVP_Particle_Generator_Chunk*)chlif(); + AVP_Particle_Generator_Data_Chunk* data_chunk=(AVP_Particle_Generator_Data_Chunk*)part_chunk->get_data_chunk(); + GLOBALASSERT(data_chunk); + + PARTICLE_GENERATOR_TOOLS_TEMPLATE* part_temp=(PARTICLE_GENERATOR_TOOLS_TEMPLATE*) PoolAllocateMem(sizeof(PARTICLE_GENERATOR_TOOLS_TEMPLATE)); + + part_temp->position.vx = data_chunk->location.x * local_scale; + part_temp->position.vy = data_chunk->location.y * local_scale; + part_temp->position.vz = data_chunk->location.z * local_scale; + + *(ObjectID*)&part_temp->nameID[0]=data_chunk->id; + *(ObjectID*)&part_temp->parentID[0]=data_chunk->parent_id; + + part_temp->type=(enum particle_generator_type)data_chunk->type; + + part_temp->probability=(data_chunk->probability*ONE_FIXED)/100; + part_temp->speed=data_chunk->speed*10; + + if(data_chunk->type==PARGEN_TYPE_SPARK) + part_temp->frequency=(data_chunk->time*ONE_FIXED)/10; + else + part_temp->frequency=ONE_FIXED/max(data_chunk->quantity,1); + + part_temp->active=!(data_chunk->flags & ParticleGeneratorFlag_Inactive); + + { + //get direction vector from orientation + QUAT q; + q.quatx = (int) -(data_chunk->orientation.x*ONE_FIXED); + q.quaty = (int) -(data_chunk->orientation.y*ONE_FIXED); + q.quatz = (int) -(data_chunk->orientation.z*ONE_FIXED); + q.quatw = (int) (data_chunk->orientation.w*ONE_FIXED); + + MATRIXCH m; + QuatToMat (&q, &m); + + part_temp->orientation=m; + + } + + setup_track_sound(part_chunk->get_sound_chunk(),&part_temp->sound); + + AddToBehaviourList(data_chunk->name,data_chunk->id, I_BehaviourParticleGenerator, (void *) part_temp,0,part_chunk->get_alternate_locations_chunk()); + + } +} + +static void get_marine_facing_point(VECTORCH& pos,EULER& euler,VECTORCH& facing_point) +{ + //select point 2 metres(ish) in front of marine + MATRIXCH mat; + CreateEulerMatrix(&euler,&mat); + facing_point=pos; + facing_point.vx+=mat.mat13/30; + facing_point.vy+=mat.mat23/30; + facing_point.vz+=mat.mat33/30; +} diff --git a/3dc/avp/win95/PCMENUS.CPP b/3dc/avp/win95/PCMENUS.CPP new file mode 100644 index 0000000..357a6d8 --- /dev/null +++ b/3dc/avp/win95/PCMENUS.CPP @@ -0,0 +1,1214 @@ +// PCMENUS - pc specific menus for avp - eg options, video mode, etc +// also contains functions for setting video mode, etc. in conjunction +// with these menus + +/*****************/ +/* INCLUDE FILES */ +/*****************/ + +#include // for sqrt +#include // for SetCursor +#include // strcat, strcpy, etc + +#include "3dc.h" // for directdraw stuff +#include "chnktexi.h" // for requesting textures on powers of two +#include "d3_func.h" + +//#include "menudefs.h" // general menu stuff +//#include "menugfx.h" // menu graphics stuff +#include "module.h" // required by gamedef +#include "gamedef.h" // for IDemand... +#include "pcmenus.h" // enums and functions for these menus +#include "ourasert.h" +#include "heap_tem.hpp" // so I can have sorted lists of video modes +#include "list_tem.hpp" // for linked lists as and when required + +#include "dxlog.h" + +#include "scstring.hpp" + + +extern "C" +{ + #include "font.h" // for the font stuff + #include "language.h" /* KJL 14:43:53 05/04/97 - language internationalization code */ + #include "gameplat.h" // for AVP_ChangeDisplayMode + #include "hudgfx.h" // for minimizing/restoring hud gfx + #include "frustrum.h" + + #include "stratdef.h" // needed for usr_io.h + #include "usr_io.h" // for the PlayerInputConfig's + #include "videomodes.h" + +/**********************/ +/* EXTERNAL FUNCTIONS */ +/**********************/ + + extern void DrawInternationalizedString(MENU_TEXT_ITEM *itemPtr, int highlighted); + extern void DrawMenuBackdrop(void); + extern void (*UpdateScreen[]) (void); + extern int IDemandSelect(void); // not in any header file!!! + +/**********************/ +/* EXTERNAL C GLOBALS */ +/**********************/ + + extern int NumAvailableVideoModes; // ditto!!! + extern VIDEOMODEINFO AvailableVideoModes[]; // ditto - sort you globals out Chris&Neal!!! + extern LPDIRECTDRAWSURFACE lpDDSBack; // DirectDraw back surface + extern unsigned char KeyboardInput[]; + extern CONTROL_METHODS ControlMethods; + extern D3DINFO d3d; + extern BOOL D3DHardwareAvailable; + extern int TotalVideoMemory; + extern int DXMemoryMode; + extern BOOL BilinearTextureFilter; + extern BOOL really_32_bit; + extern SHAPEHEADER **mainshapelist; + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + extern int VideoMode; + extern int VideoModeType; + extern int VideoModeTypeScreen; + extern int ScanDrawMode; + extern unsigned char AttemptVideoModeRestart; + extern unsigned char TestPalette[]; + extern unsigned char LPTestPalette[]; /* to cast to lp*/ + extern int **ShadingTableArray; + extern unsigned char **PaletteShadingTableArray; + + + extern void SaveKeyConfiguration(); + + extern BOOL g_bMustRedrawScreen; + + #define D3TF_FIRST D3TF_4BIT + #define D3TF_DEFAULT D3TF_4BIT + enum TexFmt { D3TF_4BIT, D3TF_8BIT, D3TF_16BIT, D3TF_32BIT, D3TF_MAX } d3d_desired_tex_fmt = D3TF_DEFAULT; +} + +/***************************/ +/* PRIVATE MACRO-CONSTANTS */ +/***************************/ + +#define DISABLE_VIDEOCARD_ANALYSIS 0 // presently still unstable +#define FORCE_TEXDIMS_POWER_OF_TWO 1 // full support for determining if this is necessary not yet implemented + +// some random random seeds so that we always create the same random texture +#define RND_SEED1 4479 +#define RND_SEED2 22408 +#define RND_SEED3 14 +#define RND_SEED4 5610 + +/***************************/ +/* PRIVATE MACRO-FUNCTIONS */ +/***************************/ + +/*****************/ +/* PRIVATE ENUMS */ +/*****************/ + +enum ImageSizeIdx +{ + ISI_100PC = 0, + ISI_75PC, + ISI_50PC, + ISI_MAX +}; + +enum ImageSizeRestrictionIdx +{ + ISRI_UNIT4 = 0, + ISRI_POWER2, + ISRI_SQUARE, + ISRI_SQUAREANDPOWER2, + ISRI_MAX +}; + +enum D3DOption +{ + VM3_SCANDRAW = 0, + VM3_D3D = 1, + + VM3_MAX = 2 +}; + + +/**********************/ +/* PRIVATE STRUCTURES */ +/**********************/ + +class VidModeInfo : public VIDEOMODEINFO +{ + // 2/4/98 DHM: Added a lazily-constructed description string, which you + // can get references to. + +public: + VidModeInfo(VIDEOMODEINFO const & vmi) + : VIDEOMODEINFO(vmi),pSCString_Description(NULL) {} + VidModeInfo() + { Width=0; Height=0; ColourDepth=0; pSCString_Description= NULL;} + VidModeInfo(int w,int h,int d) + { Width=w; Height=h; ColourDepth=d; pSCString_Description= NULL;} + ~VidModeInfo() + { + if (pSCString_Description) + { + pSCString_Description -> R_Release(); + } + } + // Copy constructor potentially needs to add a reference: + VidModeInfo(const VidModeInfo& vmi) + { + Width=vmi.Width; Height=vmi.Height; ColourDepth=vmi.ColourDepth; + pSCString_Description = vmi.pSCString_Description; + if (pSCString_Description) + { + pSCString_Description -> R_AddRef(); + } + } + + // Assignment operator potentially needs to deal with references: + VidModeInfo& operator=(const VidModeInfo& vmi) + { + Width=vmi.Width; Height=vmi.Height; ColourDepth=vmi.ColourDepth; + SCString* pSCString_Description_Old = pSCString_Description; + + pSCString_Description = vmi.pSCString_Description; + if (pSCString_Description) + { + pSCString_Description -> R_AddRef(); + } + if (pSCString_Description_Old) + { + pSCString_Description_Old -> R_Release(); + } + return *this; + } + + // to sort the modes for nice display + int operator < (VidModeInfo const & vmi2) const + { + return ColourDepth==vmi2.ColourDepth + ? Width==vmi2.Width + ? HeightMaxScreenWidth) // no 8-bit support - it looks crap in 3-3-2!! & look at MaxScreenWidth + return 0; + else + if (ColourDepth<=16) + if (d3d.ThisDriver.dwDeviceRenderBitDepth & DDBD_16) + return 1; + else + return 0; + else + if (ColourDepth<=24) + if (d3d.ThisDriver.dwDeviceRenderBitDepth & DDBD_24) + return 1; + else + return 0; + else + if (ColourDepth<=32) + if (d3d.ThisDriver.dwDeviceRenderBitDepth & DDBD_32) + return 1; + else + return 0; + else + // ColourDepth>32 + return 0; + + } + // filter for scan draw video modes + int IsForScanDraw() const + { return ColourDepth<=8 && Width<=MaxScreenWidth; } + + // Lazily-constructed descriptive string: + SCString* GetDescription(void) + { + if (!pSCString_Description) + { + MakeDescription(); + } + GLOBALASSERT(pSCString_Description); + + pSCString_Description -> R_AddRef(); + + return pSCString_Description; + } +private: + SCString* pSCString_Description; + void MakeDescription(void) + { + GLOBALASSERT(NULL==pSCString_Description); + + SCString* pSCString_W = new SCString(Width); + SCString* pSCString_H = new SCString(Height); + SCString* pSCString_CD = new SCString(ColourDepth); + SCString* pSCString_X = new SCString("X"); + // LOCALISEME + + // Construct string of the form "XX" with a possible + // trailing " ?" for more dubious modes: + SCString* pSCString_Temp = new SCString + ( + pSCString_W, + pSCString_X, + pSCString_H, + pSCString_X, + pSCString_CD + ); + + #if 1 + pSCString_Description = pSCString_Temp; + #else + if (notreporting_vga && *vmi==vga_mode) + { + SCString* pSCString_Questionable = new SCString + ( + " ?" + ); // LOCALISEME + + pSCString_Description = new SCString + ( + pSCString_Temp, + pSCString_Questionable + ); + + pSCString_Questionable -> R_Release(); + pSCString_Temp -> R_Release(); + } + else + { + pSCString_Description = pSCString_Temp; + } + #endif + + + pSCString_X -> R_Release(); + pSCString_CD -> R_Release(); + pSCString_H -> R_Release(); + pSCString_W -> R_Release(); + } +}; + +/*************************/ +/* PRIVATE CONSTANT DATA */ +/*************************/ + + +static int const hw_max_num_texels [ISRI_MAX] [ITI_MAX] [ISI_MAX] = +{ + // fullsize 3/4 size 1/2 size + + // ISRI_UNIT4 + { + { 0, 0, 0 }, // hud + { 327680, 184320, 81920 }, // texture + { 900000, 506250, 225000 } // sprites + }, + // ISRI_POWER2, + { + { 0, 0, 0 }, + { 327680, 327680, 81920 }, + { 1350000, 675000, 337500 } + }, + // ISRI_SQUARE, + { + { 0, 0, 0 }, + { 327680, 184320, 81920 }, + { 1350000, 759375, 337500 } + }, + // ISRI_SQUAREANDPOWER2, + { + { 0, 0, 0 }, + { 327680, 327680, 81920 }, + { 1350000, 1350000, 337500 } + } +}; + +static ImageSizeIdx const hw_try_desc_1 [] = { ISI_100PC, ISI_100PC, ISI_100PC }; +static ImageSizeIdx const hw_try_desc_2 [] = { ISI_100PC, ISI_100PC, ISI_75PC }; +static ImageSizeIdx const hw_try_desc_2a[] = { ISI_100PC, ISI_75PC, ISI_100PC }; +static ImageSizeIdx const hw_try_desc_3 [] = { ISI_100PC, ISI_75PC, ISI_75PC }; +static ImageSizeIdx const hw_try_desc_4 [] = { ISI_100PC, ISI_75PC, ISI_50PC }; +static ImageSizeIdx const hw_try_desc_4a[] = { ISI_100PC, ISI_50PC, ISI_75PC }; +static ImageSizeIdx const hw_try_desc_5 [] = { ISI_100PC, ISI_50PC, ISI_50PC }; + +static ImageSizeIdx const * hw_try_desc [] = +{ + hw_try_desc_1, + hw_try_desc_2, + hw_try_desc_2a, + hw_try_desc_3, + hw_try_desc_4, + hw_try_desc_4a, + hw_try_desc_5, + 0 +}; + + +/*******************/ +/* PRIVATE GLOBALS */ +/*******************/ + +static ImageSizeIdx const * desc_textures_to_load; // points to an array of size ITI_MAX + +// HARDWARE +static int hw_avail; +static D3DOption d3d_opt; + +// VIDEOMODES +static VidModeInfo vidmode[VM3_MAX]; +static unsigned int sel_vidmode_index[VM3_MAX]; // a call to intialize this value will be introduced later + // the last video mode should be saved in a file + // and if it is still available, reselected on re-running app +static Ordered_Heap avail_vidmodes[VM3_MAX]; // two lists, zero for not d3d, one for d3d + +static int notreporting_vga = 0; +static VidModeInfo vga_mode(320,200,8); + +// SHADING +static SHADING sel_shading[VM3_MAX]; + +// ZBUFFER +static ZBUFFERREQUESTMODES zbufopt[VM3_MAX]; +static BOOL zbuf_avail[VM3_MAX]; + +// MIPMAP +static BOOL mipmap_opt[VM3_MAX]; +static BOOL mipmap_avail[VM3_MAX]; + +// BILINEAR FILTER? +static BOOL bilin_filter_avail; + +/* KJL 15:57:04 05/04/97 - I've added these strings here for simplicity's sake. +The memory could be allocated/deallocated during run-time to save some space, +but it's only a few bytes. They have to be long to contain any required message. */ +static char DisplayModeString[16]; +static char TextureDepthString[16]; + +/******************/ +/* PUBLIC GLOBALS */ +/******************/ + +SHADING desired_shading = SHADE_GOURAUD; + +/*********************/ +/* PRIVATE FUNCTIONS */ +/*********************/ + +static inline int BitsPerPixel(D3DTEXTUREFORMAT const * texfmt) +{ + return texfmt->Palette ? texfmt->IndexBPP : texfmt->RedBPP + texfmt->BlueBPP + texfmt->GreenBPP; +} + +static inline int BitsPerPixel(TexFmt f) +{ + switch (f) + { + case D3TF_4BIT: + return 4; + case D3TF_8BIT: + return 8; + case D3TF_16BIT: + return 16; + case D3TF_32BIT: + return 32; + default: + return 0; + } +} + +static void LoadVideoModeSettings(void) +{ + FILE * fp = fopen("AVPVMOPT.BIN","rb"); + if (!fp) return; + + + unsigned long magic; + fread(&magic,4,1,fp); + if (magic == *(unsigned long *)"VMOP") + { + fread(&vidmode[VM3_SCANDRAW].Width,4,1,fp); + fread(&vidmode[VM3_SCANDRAW].Height,4,1,fp); + fread(&vidmode[VM3_SCANDRAW].ColourDepth,4,1,fp); + fread(&vidmode[VM3_D3D].Width,4,1,fp); + fread(&vidmode[VM3_D3D].Height,4,1,fp); + fread(&vidmode[VM3_D3D].ColourDepth,4,1,fp); + fread(&d3d_opt,4,1,fp); + fread(&hw_avail,4,1,fp); + fread(&zbufopt[VM3_SCANDRAW],4,1,fp); + fread(&zbufopt[VM3_D3D],4,1,fp); + fread(&d3d_desired_tex_fmt,4,1,fp); + fread(&sel_shading[VM3_SCANDRAW],4,1,fp); + fread(&sel_shading[VM3_D3D],4,1,fp); + fread(&BilinearTextureFilter,4,1,fp); + fread(&mipmap_opt[VM3_SCANDRAW],4,1,fp); + fread(&mipmap_opt[VM3_D3D],4,1,fp); + if (zbufopt[VM3_D3D] != RequestZBufferNever) zbufopt[VM3_D3D]=RequestZBufferAlways; + if (zbufopt[VM3_SCANDRAW] != RequestZBufferNever) zbufopt[VM3_SCANDRAW]=RequestZBufferAlways; + if (VM3_SCANDRAW!=d3d_opt) d3d_opt=VM3_D3D; // ensure 0 or 1 + if (d3d_desired_tex_fmt >= D3TF_MAX) d3d_desired_tex_fmt = D3TF_DEFAULT; + + d3d_desired_tex_fmt=D3TF_8BIT; + if (sel_shading[VM3_D3D] != SHADE_FLAT) sel_shading[VM3_D3D] = SHADE_GOURAUD; + if (sel_shading[VM3_SCANDRAW] != SHADE_FLAT) sel_shading[VM3_SCANDRAW] = SHADE_GOURAUD; + if (BilinearTextureFilter != FALSE) BilinearTextureFilter = TRUE; + if (mipmap_opt[VM3_D3D] != FALSE) mipmap_opt[VM3_D3D]=TRUE; + if (mipmap_opt[VM3_SCANDRAW] != FALSE) mipmap_opt[VM3_SCANDRAW]=TRUE; + } + fclose(fp); + return; +} + + +static size_t IsNotEnoughVidMemForBytes(size_t required) +{ + return 0; + + // Won't be using this. I don't think + #if 0 + + char buff[128]; + sprintf(buff,"Want: %d Have: %d",(int)required,GetAvailableVideoMemory()); + LOGDXSTR(buff); + + if (required > GetAvailableVideoMemory()) return GetAvailableVideoMemory(); + + LOGDXSTR("Maybe enough"); + + #if DISABLE_VIDEOCARD_ANALYSIS + return 0; + #endif + + static size_t what_we_know_we_can_have = 0; + + if (required <= what_we_know_we_can_have) return 0; + + // deal with cards whose video memory is fragmented + // such that textures may not be able to use all the + // available video memory + + // we don't know we can use all the available video memory + // for textures - so try and find out what we can use + // with the current options - and in future, as long as + // available video memory exceeds this amount, we'll know + // at least a minimum amount that we can have without having + // to run this test again + + List imgs; + size_t vidmem_before = GetAvailableVideoMemory(); + CL_Image random_tx; + + CL_Select_Mode(CLL_D3DTEXTURE); + random_tx.MakeRandom(512,512,RND_SEED1); + + // throw d3d textures at the system until we can no more + do + { + CL_Error copyerr; + do + { + IMAGEHEADER * new_ih = new IMAGEHEADER; + memset(new_ih,0,sizeof(IMAGEHEADER)); + size_t vidmem_before_create = GetAvailableVideoMemory(); + copyerr = random_tx.CopyToD3DTexture((LPDIRECTDRAWSURFACE *)&new_ih->DDPtr,(LPVOID *)&new_ih->DDSurface,DDSCAPS_SYSTEMMEMORY); + if (CLE_OK == copyerr) + { + copyerr = CLE_DXERROR; + if (CopyD3DTexture(new_ih)) + { + if (LoadD3DTextureIntoD3DMaterial(new_ih)) + copyerr = CLE_OK; + } + } + size_t vidmem_after_create = GetAvailableVideoMemory(); + imgs.add_entry(new_ih); + if (vidmem_after_create >= vidmem_before_create) copyerr = CLE_DXERROR; + LOGDXFMT(("VidMem: %d",vidmem_after_create)); + } + while (CLE_OK==copyerr); + random_tx.MakeRandom(random_tx.width>>1,random_tx.height>>1); + } + while (random_tx.width>=32 && random_tx.height>=32); + + size_t vidmem_after = GetAvailableVideoMemory(); + + what_we_know_we_can_have = vidmem_before - vidmem_after; + + char buf[128]; + sprintf(buf,"Can have %d\n",what_we_know_we_can_have); + LOGDXSTR(buf); + + // release all dummy textures we threw at the system + while (imgs.size()) + { + if (imgs.first_entry()->DDSurface) + ReleaseDDSurface(imgs.first_entry()->DDSurface); + if (imgs.first_entry()->D3DTexture) + ReleaseD3DTexture(imgs.first_entry()->D3DTexture); + delete imgs.first_entry(); + imgs.delete_first_entry(); + } + + + if (required <= what_we_know_we_can_have) + return 0; + else + return what_we_know_we_can_have; + #endif +} + +static BOOL IsNotEnoughVidMemForScreenDepth(int s_depth) +{ + // bollocks - this is all obsolete - FIXME + return FALSE; + + #if 0 + + LOGDXSTR("Testing Vid Mem"); + + CL_Init_All(); - not required any more + + // determine if d3d textures need to be a power of two in width and height + // try 48x48 + IMAGEHEADER tmp_iheader; + memset(&tmp_iheader,0,sizeof(IMAGEHEADER)); + CL_Image random_tx; + CL_Error copyerr; + + // do we need texture powers of two or square + need_textures_powers_of_two = d3d.ThisDriver.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2 ? 1 : 0; + need_textures_square = d3d.ThisDriver.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY ? 1 : 0; + + LOGDXFMT(("Need POW_2 : %d",need_textures_powers_of_two)); + LOGDXFMT(("Need SQUARE : %d",need_textures_square)); + + // determine how much texture memory is used by a typical 64x64 hud graphic + + #if DISABLE_VIDEOCARD_ANALYSIS + size_t vidmem_before, vidmem_after; + copyerr = CLE_DXERROR; + #else + + CL_Select_Mode(CLL_DDSURFACE); + random_tx.MakeRandom(64,64,RND_SEED4); + size_t vidmem_before = GetAvailableVideoMemory(); + copyerr = random_tx.CopyToDirectDrawSurface((LPDIRECTDRAWSURFACE *)&tmp_iheader.DDSurface,(LPVOID *)&tmp_iheader.DDPtr,DDSCAPS_SYSTEMMEMORY); + size_t vidmem_after = GetAvailableVideoMemory(); + if (tmp_iheader.DDSurface) + { + ReleaseDDSurface(tmp_iheader.DDSurface); + tmp_iheader.DDSurface = (void*) 0; + tmp_iheader.DDPtr = (void*) 0; + } + if (tmp_iheader.D3DTexture) + { + ReleaseD3DTexture(tmp_iheader.D3DTexture); + tmp_iheader.D3DTexture = (void*) 0; + tmp_iheader.D3DMaterial = (void*) 0; + tmp_iheader.D3DHandle = (void*) 0; + } + + #endif + + float hud_bytespertexel = + CLE_OK == copyerr + ? (float)(vidmem_before-vidmem_after)/(random_tx.width*random_tx.height) + : (float)s_depth/8 + ; + + char buf[128]; + sprintf(buf,"HUD BPP: %f",hud_bytespertexel); + LOGDXSTR(buf); + + // determine how much texture memory is used by a typical 128x128 texture + + #if DISABLE_VIDEOCARD_ANALYSIS + #else + + CL_Select_Mode(CLL_D3DTEXTURE); + random_tx.MakeRandom(128,128,RND_SEED2); + LOGDXSTR("Trying D3D"); + + //size_t + vidmem_before = GetAvailableVideoMemory(); + copyerr = random_tx.CopyToD3DTexture((LPDIRECTDRAWSURFACE *)&tmp_iheader.DDPtr,(LPVOID *)&tmp_iheader.DDSurface,DDSCAPS_SYSTEMMEMORY); + if (CLE_OK == copyerr) + { + copyerr = CLE_DXERROR; + if (CopyD3DTexture(&tmp_iheader)) + if (LoadD3DTextureIntoD3DMaterial(&tmp_iheader)) + copyerr = CLE_OK; + } + //size_t + vidmem_after = GetAvailableVideoMemory(); + if (tmp_iheader.DDSurface) + { + ReleaseDDSurface(tmp_iheader.DDSurface); + tmp_iheader.DDSurface = (void*) 0; + tmp_iheader.DDPtr = (void*) 0; + } + if (tmp_iheader.D3DTexture) + { + ReleaseD3DTexture(tmp_iheader.D3DTexture); + tmp_iheader.D3DTexture = (void*) 0; + tmp_iheader.D3DMaterial = (void*) 0; + tmp_iheader.D3DHandle = (void*) 0; + } + #endif + + float textures_bytespertexel = + CLE_OK == copyerr + ? (float)(vidmem_before-vidmem_after)/(random_tx.width*random_tx.height) + : (float)BitsPerPixel(&d3d.TextureFormat[d3d.CurrentTextureFormat])/8 + ; + + //char buf[128]; + sprintf(buf,"Textures BPP: %f",textures_bytespertexel); + LOGDXSTR(buf); + + ImageSizeRestrictionIdx isri = need_textures_square ? need_textures_powers_of_two ? ISRI_SQUAREANDPOWER2 : ISRI_SQUARE : need_textures_powers_of_two ? ISRI_POWER2 : ISRI_UNIT4; + + size_t vram_rq; + size_t vram_avail; + for (int i=0; hw_try_desc[i]; ++i) + { + desc_textures_to_load = hw_try_desc[i]; + vram_rq = (size_t)( + hw_max_num_texels[isri][ITI_HUD][desc_textures_to_load[ITI_HUD]] * hud_bytespertexel + + hw_max_num_texels[isri][ITI_TEXTURE][desc_textures_to_load[ITI_TEXTURE]] * textures_bytespertexel + + hw_max_num_texels[isri][ITI_SPRITE][desc_textures_to_load[ITI_SPRITE]] * textures_bytespertexel + ); + vram_avail = IsNotEnoughVidMemForBytes(vram_rq); + if (!vram_avail) return FALSE; + } + // bollocks - return FALSE anayway, since the following doesn't actually work anymore anyway + return FALSE; + + char errstring[512]; + sprintf(errstring,"THIS SET OF OPTIONS REQUIRES AT LEAST %d BYTES OF VIDEO MEMORY FREE. THERE ARE ONLY %d BYTES FREE. THE TEXTURE FORMAT WAS %d-BIT",(int)vram_rq,(int)vram_avail,BitsPerPixel(&d3d.TextureFormat[d3d.CurrentTextureFormat])); + EmergencyPcOptionsMenu(errstring); + return TRUE; + #endif +} + + +/********************/ +/* PUBLIC FUNCTIONS */ +/********************/ + +BOOL PreferTextureFormat(D3DTEXTUREFORMAT const * oldfmt,D3DTEXTUREFORMAT const * newfmt) +{ + int old_bpp = BitsPerPixel(oldfmt); + int new_bpp = BitsPerPixel(newfmt); + int cur_bpp = BitsPerPixel(d3d_desired_tex_fmt); + + int old_bpp_dif = abs(old_bpp-cur_bpp); + int new_bpp_dif = abs(new_bpp-cur_bpp); + if (new_bpp==8 && !newfmt->Palette) return FALSE; + + if (new_bpp_dif < old_bpp_dif) return TRUE; + if (new_bpp_dif > old_bpp_dif) return FALSE; + + if (new_bpp < old_bpp) return TRUE; + if (new_bpp > old_bpp) return FALSE; + + if (newfmt->Palette) return TRUE; + else return FALSE; +} +#if 1 +void InitOptionsMenu(void) +{ + #if debug // Check that this function is only called once + static int already_called = 0; + GLOBALASSERT(!already_called); + already_called=1; + #endif + + // hardware and direct 3d, zbuffering? + int hw_now_avail = D3DHardwareAvailable ? 1 : 0; // 4Mb cards only? + + // find the direct 3d driver we'll be using + d3d.CurrentDriver = 0; + for (int i = 0; i < d3d.NumDrivers; ++i) + { + if (d3d.Driver[i].Hardware && hw_now_avail) + { + d3d.CurrentDriver = i; + break; + } + if (D3DCOLOR_RGB == d3d.Driver[i].Desc.dcmColorModel) + d3d.CurrentDriver = i; + } + + d3d.ThisDriver = d3d.Driver[d3d.CurrentDriver].Desc; + + zbuf_avail[VM3_D3D] = d3d.Driver[d3d.CurrentDriver].ZBuffer ? TRUE : FALSE; + zbuf_avail[VM3_SCANDRAW] = TRUE; + + // not yet implemented properly and never been tested + mipmap_avail[VM3_D3D] = d3d.ThisDriver.dpcTriCaps.dwTextureFilterCaps & (D3DPTFILTERCAPS_MIPLINEAR|D3DPTFILTERCAPS_MIPNEAREST) ? TRUE : FALSE; + mipmap_avail[VM3_SCANDRAW] = TRUE; + + bilin_filter_avail = d3d.ThisDriver.dpcTriCaps.dwTextureFilterCaps & D3DPTFILTERCAPS_LINEAR ? TRUE : FALSE; + + hw_avail = hw_now_avail; + d3d_opt = hw_avail ? VM3_D3D : VM3_SCANDRAW; + + sel_vidmode_index[VM3_SCANDRAW]=0; // lowest res + sel_vidmode_index[VM3_D3D]=0; + + zbufopt[VM3_SCANDRAW]=RequestZBufferNever; + zbufopt[VM3_D3D]=hw_avail ? RequestZBufferAlways : RequestZBufferNever; + + mipmap_opt[VM3_SCANDRAW] = mipmap_avail[VM3_SCANDRAW]; + mipmap_opt[VM3_D3D] = mipmap_avail[VM3_D3D]; + + sel_shading[VM3_SCANDRAW]=SHADE_GOURAUD; + sel_shading[VM3_D3D]=SHADE_GOURAUD; + + BilinearTextureFilter = hw_avail && bilin_filter_avail ? TRUE : FALSE; + + LoadVideoModeSettings(); + + #if !ENABLE_MIPMAP_OPTION + mipmap_opt[VM3_SCANDRAW] = mipmap_avail[VM3_SCANDRAW]; + mipmap_opt[VM3_D3D] = FALSE; + #endif + + if (hw_now_avail != hw_avail) // card removed/added so set default + { + hw_avail = hw_now_avail; + d3d_opt = hw_avail ? VM3_D3D : VM3_SCANDRAW; + zbufopt[VM3_D3D]=hw_avail ? RequestZBufferAlways : RequestZBufferNever; + BilinearTextureFilter = hw_avail && bilin_filter_avail ? TRUE : FALSE; + mipmap_opt[VM3_D3D] = mipmap_avail[VM3_D3D]; + } + + // possible hardware video modes + for (i=0; i=384 && vmi.Width>=512) + avail_vidmodes[VM3_D3D].add_entry(vmi); + } + + // get the indexes of the video modes + int idx = 0; + for (OHIF i_vidmode_d3d(&avail_vidmodes[VM3_D3D]); !i_vidmode_d3d.done(); i_vidmode_d3d.next(), ++idx) + { + if (i_vidmode_d3d()==vidmode[VM3_D3D]) + { + sel_vidmode_index[VM3_D3D] = idx; + break; + } + } + + RasterisationRequestMode = RequestSoftwareRasterisation; +#if 0 + ChangeDirectDrawObject(); + + notreporting_vga = 1; + // possible software video modes + for (i=0; i i_vidmode_sd(&avail_vidmodes[VM3_SCANDRAW]); !i_vidmode_sd.done(); i_vidmode_sd.next(), ++idx) + { + if (i_vidmode_sd()==vidmode[VM3_SCANDRAW]) + { + sel_vidmode_index[VM3_SCANDRAW] = idx; + break; + } + } + + vidmode[VM3_SCANDRAW] = avail_vidmodes[VM3_SCANDRAW][sel_vidmode_index[VM3_SCANDRAW]]; + vidmode[VM3_D3D] = avail_vidmodes[VM3_D3D][sel_vidmode_index[VM3_D3D]]; + #if ENABLE_SHADING_OPTION + desired_shading = sel_shading[d3d_opt]; + #endif +#endif +} +#endif + +extern int SetGameVideoMode(void) +{ + desc_textures_to_load = hw_try_desc[0]; + + LOGDXSTR("SetGameVideoMode"); + unsigned int s_width; + unsigned int s_height; + unsigned int s_depth; +// do + { + finiObjectsExceptDD(); + WindowMode = WindowRequestMode; + + ScreenDescriptorBlock.SDB_Flags &= ~SDB_Flag_MIP; // mip mapping in d3d cannot be tested since no known drivers support it! + if (VM3_SCANDRAW==d3d_opt) // don't use d3d + { + RasterisationRequestMode = RequestSoftwareRasterisation; + SoftwareScanDrawRequestMode = RequestScanDrawDirectDraw; + DXMemoryRequestMode = RequestSystemMemoryAlways; + DXMemoryMode = SystemMemoryPreferred; + } + else + { + if (hw_avail) // use hw accel + { + RasterisationRequestMode = RequestDefaultRasterisation; + SoftwareScanDrawRequestMode = RequestScanDrawDefault; + DXMemoryRequestMode = RequestDefaultMemoryAllocation; + DXMemoryMode = VideoMemoryPreferred; + } + else // use microsofts software drivers!!! + { + RasterisationRequestMode = RequestDefaultRasterisation; + SoftwareScanDrawRequestMode = RequestScanDrawSoftwareRGB; // FIXME:ramp driver appears broken??? + DXMemoryRequestMode = RequestSystemMemoryAlways; + DXMemoryMode = SystemMemoryPreferred; + } + } + if (mipmap_opt[d3d_opt] && mipmap_avail[d3d_opt]) + ScreenDescriptorBlock.SDB_Flags |= SDB_Flag_MIP; // mip mapping in d3d cannot be tested since no known drivers support it! + + // deal with hw dd objects required? + ChangeDirectDrawObject(); + + #if SupportZBuffering + if (zbuf_avail[d3d_opt]) + ZBufferRequestMode = zbufopt[d3d_opt]; + else + ZBufferRequestMode = RequestZBufferNever; + #else + ZBufferRequestMode = RequestZBufferNever; + #endif + + #if 0 + s_width = vidmode[d3d_opt].Width; + s_height = vidmode[d3d_opt].Height; + s_depth = vidmode[d3d_opt].ColourDepth; + #else + { + DEVICEANDVIDEOMODESDESC *dPtr = &DeviceDescriptions[CurrentlySelectedDevice]; + VIDEOMODEDESC *vmPtr = &(dPtr->VideoModes[CurrentlySelectedVideoMode]); + s_width = vmPtr->Width; + s_height = vmPtr->Height; + s_depth = vmPtr->ColourDepth; + } + #endif + if (s_depth<=8) + { + /* temp hack to test super TLTs */ + ScreenDescriptorBlock.SDB_Flags &= ~SDB_Flag_TLTPalette; + #if 0 && SupportZBuffering + if (RequestZBufferAlways==ZBufferRequestMode) + ScreenDescriptorBlock.SDB_Flags |= SDB_Flag_TLTPalette; + #endif + + GLOBALASSERT(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_Raw256); + ConvertToDDPalette(TestPalette, LPTestPalette, 256, 0); + + ScreenDescriptorBlock.SDB_ScreenDepth = VideoModeType_8; + VideoModeTypeScreen = VideoModeType_8; + } + else if (s_depth<=16) + { + ScreenDescriptorBlock.SDB_ScreenDepth = VideoModeType_15; + VideoModeTypeScreen = VideoModeType_15; + } + else + { + ScreenDescriptorBlock.SDB_ScreenDepth = VideoModeType_24; + VideoModeTypeScreen = VideoModeType_24; + really_32_bit = s_depth > 24 ? TRUE : FALSE; + } + + /* Set up the Screen Descriptor Block */ + + ScreenDescriptorBlock.SDB_Width = s_width; + ScreenDescriptorBlock.SDB_Height = s_height; + ScreenDescriptorBlock.SDB_Size = s_width*s_height; + + ScreenDescriptorBlock.SDB_DiagonalWidth = sqrt((float)s_width*s_width+s_height*s_height)+0.5; + + ScreenDescriptorBlock.SDB_CentreX = s_width/2; + ScreenDescriptorBlock.SDB_CentreY = s_height/2; + + /* KJL 12:00:54 07/04/97 - new projection angles */ + #if USE_FOV_53 + ScreenDescriptorBlock.SDB_ProjX = s_width; + ScreenDescriptorBlock.SDB_ProjY = s_height*4/3; + #else + ScreenDescriptorBlock.SDB_ProjX = s_width/2; + ScreenDescriptorBlock.SDB_ProjY = s_height/2; + #endif + + ScreenDescriptorBlock.SDB_ClipLeft = 0; + ScreenDescriptorBlock.SDB_ClipRight = s_width; + ScreenDescriptorBlock.SDB_ClipUp = 0; + ScreenDescriptorBlock.SDB_ClipDown = s_height; + + GenerateDirectDrawSurface(); + SetCursor(NULL); + + /* For dubious DirectX failures */ + if (AttemptVideoModeRestart) + return 0; + LOGDXSTR("Testing"); + + } + #if 0 + while + ( + InitialiseDirect3DImmediateMode() || VM3_SCANDRAW==d3d_opt + ? VideoMemoryPreferred == DXMemoryMode + ? IsNotEnoughVidMemForScreenDepth(s_depth) + : 0 + : (GLOBALASSERT(0=="CANNOT INITIALIZE DIRECT 3D FOR THIS VIDEO MODE"),1)//(EmergencyPcOptionsMenu("CANNOT INITIALIZE DIRECT 3D FOR THIS VIDEO MODE"), 1) + ); + #endif + if (IsNotEnoughVidMemForScreenDepth(s_depth)) + { + // erm, something + return 0; + } + + if (!InitialiseDirect3DImmediateMode()) + { + return 0; + } + + // CL_Init_All(); // set up shifts for display pixel format - not required + + if (ScanDrawMode == ScanDrawDirectDraw) + { + ScreenDescriptorBlock.SDB_Depth = ScreenDescriptorBlock.SDB_ScreenDepth; + VideoModeType = VideoModeTypeScreen; + + } + else + { + ScreenDescriptorBlock.SDB_Depth = VideoModeType_24; + VideoModeType = VideoModeType_24; + } + + + #define VideoMode_Any 0x0fffffff + VideoMode = VideoMode_Any; // to trip up any functions using this variable + + // but if it matches a predifined constant, set it so - may be required ?????? + switch (s_width) + { + case 320: + switch (s_height) + { + case 200: + switch (VideoModeTypeScreen) + { + case VideoModeType_8: + VideoMode = VideoMode_DX_320x200x8; + break; + case VideoModeType_8T: + VideoMode = VideoMode_DX_320x200x8T; + break; + case VideoModeType_15: + VideoMode = VideoMode_DX_320x200x15; + break; + } + break; + case 240: + if (VideoModeType_8==VideoModeTypeScreen) + VideoMode = VideoMode_DX_320x240x8; + break; + } + break; + case 640: + if (480==s_height) switch (VideoModeTypeScreen) + { + case VideoModeType_8: + VideoMode = VideoMode_DX_640x480x8; + break; + case VideoModeType_8T: + VideoMode = VideoMode_DX_640x480x8T; + break; + case VideoModeType_15: + VideoMode = VideoMode_DX_640x480x15; + break; + case VideoModeType_24: + VideoMode = VideoMode_DX_640x480x24; + break; + } + break; + case 800: + if (600==s_height) switch (VideoModeTypeScreen) + { + case VideoModeType_8: + VideoMode = VideoMode_DX_800x600x8; + break; + case VideoModeType_8T: + VideoMode = VideoMode_DX_800x600x8T; + break; + case VideoModeType_15: + VideoMode = VideoMode_DX_800x600x15; + break; + case VideoModeType_24: + VideoMode = VideoMode_DX_800x600x24; + break; + } + break; + case 1024: + if (768==s_height) switch (VideoModeTypeScreen) + { + case VideoModeType_8: + VideoMode = VideoMode_DX_1024x768x8; + break; + case VideoModeType_8T: + VideoMode = VideoMode_DX_1024x768x8T; + break; + case VideoModeType_15: + VideoMode = VideoMode_DX_1024x768x15; + break; + case VideoModeType_24: + VideoMode = VideoMode_DX_1024x768x24; + break; + } + break; + case 1280: + if (1024==s_height) switch (VideoModeTypeScreen) + { + case VideoModeType_8: + VideoMode = VideoMode_DX_1280x1024x8; + break; + case VideoModeType_8T: + VideoMode = VideoMode_DX_1280x1024x8T; + break; + case VideoModeType_15: + VideoMode = VideoMode_DX_1280x1024x15; + break; + case VideoModeType_24: + VideoMode = VideoMode_DX_1280x1024x24; + break; + } + break; + case 1600: + if (1200==s_height) switch (VideoModeTypeScreen) + { + case VideoModeType_8: + VideoMode = VideoMode_DX_1600x1200x8; + break; + case VideoModeType_8T: + VideoMode = VideoMode_DX_1600x1200x8T; + break; + case VideoModeType_15: + VideoMode = VideoMode_DX_1600x1200x15; + break; + case VideoModeType_24: + VideoMode = VideoMode_DX_1600x1200x24; + break; + } + break; + } + + LOGDXSTR("leaving SetGameVideoMode"); + return 1; +} + +extern "C" +{ +/* KJL 17:11:26 19/07/98 - The 3 fns below are the interface between the +video mode selection and the frontend menus. */ + +extern char *GetVideoModeDescription(void) +{ + const VidModeInfo* pVidModeInfo = &avail_vidmodes[d3d_opt][sel_vidmode_index[d3d_opt]]; + + // Unfortunately, the heap template [] operator gives us a const reference; + // we must cast away the constness: + + return ((VidModeInfo*)pVidModeInfo) -> GetDescription()->pProjCh(); +} + +extern void PreviousVideoMode(void) +{ + if(sel_vidmode_index[d3d_opt] > 0) + { + sel_vidmode_index[d3d_opt]--; + } + else + { + sel_vidmode_index[d3d_opt] = avail_vidmodes[d3d_opt].size() -1; + } +} + +extern void NextVideoMode(void) +{ + if(sel_vidmode_index[d3d_opt] < (avail_vidmodes[d3d_opt].size()-1)) + { + sel_vidmode_index[d3d_opt]++; + } + else + { + sel_vidmode_index[d3d_opt] = 0; + } +} +extern void SaveVideoModeSettings(void) +{ + vidmode[VM3_SCANDRAW] = avail_vidmodes[VM3_SCANDRAW][sel_vidmode_index[VM3_SCANDRAW]]; + vidmode[VM3_D3D] = avail_vidmodes[VM3_D3D][sel_vidmode_index[VM3_D3D]]; + + FILE * fp = fopen("AVPVMOPT.BIN","wb"); + if (!fp) return; + fwrite("VMOP",4,1,fp); + fwrite(&vidmode[VM3_SCANDRAW].Width,4,1,fp); + fwrite(&vidmode[VM3_SCANDRAW].Height,4,1,fp); + fwrite(&vidmode[VM3_SCANDRAW].ColourDepth,4,1,fp); + fwrite(&vidmode[VM3_D3D].Width,4,1,fp); + fwrite(&vidmode[VM3_D3D].Height,4,1,fp); + fwrite(&vidmode[VM3_D3D].ColourDepth,4,1,fp); + fwrite(&d3d_opt,4,1,fp); + fwrite(&hw_avail,4,1,fp); + fwrite(&zbufopt[VM3_SCANDRAW],4,1,fp); + fwrite(&zbufopt[VM3_D3D],4,1,fp); + fwrite(&d3d_desired_tex_fmt,4,1,fp); + fwrite(&sel_shading[VM3_SCANDRAW],4,1,fp); + fwrite(&sel_shading[VM3_D3D],4,1,fp); + fwrite(&BilinearTextureFilter,4,1,fp); + fwrite(&mipmap_opt[VM3_SCANDRAW],4,1,fp); + fwrite(&mipmap_opt[VM3_D3D],4,1,fp); + fclose(fp); + return; +} +} \ No newline at end of file diff --git a/3dc/avp/win95/PCMENUS.H b/3dc/avp/win95/PCMENUS.H new file mode 100644 index 0000000..36db6e2 --- /dev/null +++ b/3dc/avp/win95/PCMENUS.H @@ -0,0 +1,184 @@ +#ifndef _included_pcmenus_h_ +#define _included_pcmenus_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "menugfx.h" + +#define ENABLE_SHADING_OPTION 0 +#define ENABLE_MIPMAP_OPTION 0 + +typedef enum OptionsMenuItem +{ + OMI_DIRECT3D, + OMI_DISPLAY, + OMI_ZBUFFER, + #if ENABLE_MIPMAP_OPTION + OMI_MIPMAP, + #endif + #if ENABLE_SHADING_OPTION + OMI_SHADING, + #endif + OMI_TEXTUREFORMAT, + OMI_BILINFILTER, + OMI_KEYCONFIG, + OMI_RETURN, + + OMI_NUMMENUITEMS + +} OPTIONSMENUITEM; + +typedef enum KeyConfigItems +{ + KEYCONFIG_FORWARD, + KEYCONFIG_BACKWARD, + KEYCONFIG_TURN_LEFT, + KEYCONFIG_TURN_RIGHT, + KEYCONFIG_STRAFE, + KEYCONFIG_STRAFE_LEFT, + KEYCONFIG_STRAFE_RIGHT, + KEYCONFIG_LOOK_UP, + KEYCONFIG_LOOK_DOWN, + KEYCONFIG_CENTRE_VIEW, + KEYCONFIG_WALK, + KEYCONFIG_CROUCH, + KEYCONFIG_JUMP, + KEYCONFIG_OPERATE, + KEYCONFIG_VISION, + KEYCONFIG_NEXT_WEAPON, + KEYCONFIG_PREVIOUS_WEAPON, + KEYCONFIG_FIRE_PRIMARY, + KEYCONFIG_FIRE_SECONDARY, + + KEYCONFIG_NUMITEMS + +} KEYCONFIGITEMS; + +typedef enum MouseConfigItems +{ + MOUSECONFIG_XSENSITIVITY, + MOUSECONFIG_YSENSITIVITY, + MOUSECONFIG_VAXIS, + MOUSECONFIG_HAXIS, + MOUSECONFIG_FLIPVERTICAL, + MOUSECONFIG_AUTOCENTRE, + MOUSECONFIG_EXIT, + + MOUSECONFIG_NUMITEMS + +} MOUSECONFIGITEMS; + + +typedef enum Shading { + + SHADE_FLAT, + SHADE_GOURAUD + +} SHADING; + +typedef enum ImageTypeIdx +{ + ITI_HUD = 0, + ITI_TEXTURE, + ITI_SPRITE, + ITI_MAX + +} IMAGETYPEIDX; + +extern SHADING desired_shading; + +int PcOptionsMenu(void); +void MouseOptionsMenu(void); +void DrawMouseOptionsScreen(int selection); +void PCKeyConfigMenu(void); +void DrawKeyConfigScreen(int currentRow,int currentColumn); +void RedefineKey(int currentRow,int currentColumn); + +extern int SetGameVideoMode(void); +void RestoreGameVideoMode(void); +void InitOptionsMenu(void); + +extern void SaveVideoModeSettings(void); + +BOOL PreferTextureFormat(struct D3DTextureFormat const * oldfmt,struct D3DTextureFormat const * newfmt); + +extern const char * GenTex4bit_Directory; +extern const char * GenTex8bit_Directory; +extern const char * GenTex75pc_Directory; +extern const char * GenTex50pc_Directory; + +void SelectGenTexDirectory(IMAGETYPEIDX); +float GetUVScale(IMAGETYPEIDX); + +/* This will change the video mode to 640x480x8 (or rather, the menu video mode) if it is not already in that mode */ +#define AMB_MODELESS 0x00000001 /* do not wait for select or blank screen */ +void AvpMessageBox(char const * text, char const * title, int flags); + +extern AVP_MENU OptionsMenuData; +extern AVP_MENU VideoModeOptionsMenu; + +#ifdef __cplusplus +} +#endif + + + + +/* + NEW CONTENT 1/4/98 by DHM: + -------------------------- + + Building the video options page for the new menu system, I need + access to various variables declared as static within PCMENUS.CPP + + I've decided to access them through an export variable interface, + hoping this will make the code cleaner. +*/ +#ifdef __cplusplus +# ifndef _expvar_hpp +# include "expvar.hpp" +# endif +# ifndef _scstring +# include "scstring.hpp" +# endif + + namespace RebMenus + { + class ExportVariable_3dAcceleration : public ExportVariable + { + public: + OurBool Get(void) const; + void Set(OurBool NewVal); + }; + + class ExportVariable_ZBuffering : public ExportVariable + { + public: + OurBool Get(void) const; + void Set(OurBool NewVal); + }; + + class ExportVariable_BilinearFiltering : public ExportVariable + { + public: + OurBool Get(void) const; + void Set(OurBool NewVal); + }; + + class VideoModeSelection + { + public: + static SCString* DescribeCurrentSelection(void); + static void Dec(void); + static void Inc(void); + }; + }; + +#endif /* __cplusplus */ + + + + +#endif /* ! _included_pcmenus_h_ */ diff --git a/3dc/avp/win95/PCPAUSE.C b/3dc/avp/win95/PCPAUSE.C new file mode 100644 index 0000000..7753ba0 --- /dev/null +++ b/3dc/avp/win95/PCPAUSE.C @@ -0,0 +1,83 @@ +/*-----------------------------Patrick 14/5/97------------------------------ + Source for PC game pause stuff + --------------------------------------------------------------------------*/ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "gameplat.h" +#include "bh_types.h" +#include "menudefs.h" +#include "menugfx.h" +#include "pcmenus.h" +#include "usr_io.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +extern void CheckForGamePause(void); +extern void SaveGameToFile(void); +extern void AccessDatabase(void); +extern int ScanDrawMode; + + +void DoPcPause(void) +{ + ReadUserInput(); + ReadPlayerGameInput(Player->ObStrategyBlock); + + if(AvP.Network!=I_No_Network) + { + // escape ends game for network play + AvP.MainLoopRunning = 0; + AvP.GameMode = I_GM_Playing; + return; + } + + + CheckForGamePause(); + + #if 0 + FlushTextprintBuffer(); + AvpShowViews(); + + /* KJL 11:25:33 7/29/97 - this needs to be changed if + the HUD goes all 3D accelerator drawn */ + if (ScanDrawMode != ScanDrawDirectDraw) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + EndD3DScene(); + } + + BLTPausedToScreen(); + + + FlipBuffers(); + #endif + + AccessDatabase(); + + ResetFrameCounter(); + + AvP.GameMode = I_GM_Playing; +} + +static int pauseOk = 1; +void CheckForGamePause(void) +{ + /* check for pause key */ + if(PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_PauseGame) + { + if(pauseOk) + { + /* switch state */ + if(AvP.GameMode == I_GM_Playing) AvP.GameMode = I_GM_Paused; + else if(AvP.GameMode == I_GM_Paused) AvP.GameMode = I_GM_Playing; + pauseOk = 0; + } + } + else pauseOk = 1; +} \ No newline at end of file diff --git a/3dc/avp/win95/PLATSUP.C b/3dc/avp/win95/PLATSUP.C new file mode 100644 index 0000000..b6dfa77 --- /dev/null +++ b/3dc/avp/win95/PLATSUP.C @@ -0,0 +1,411 @@ +/* + + Platform specific project specific C functions + +*/ + +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "gameplat.h" +#include "gamedef.h" + +#include "dynblock.h" +#include "dynamics.h" +#define UseLocalAssert No +#include "ourasert.h" + +/* + Externs from pc\io.c +*/ + +extern int InputMode; +extern unsigned char KeyboardInput[]; + +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; +extern void (*SetVideoMode[]) (void); +extern unsigned char *ScreenBuffer; + +extern unsigned char KeyASCII; + + +/* External functions */ + +extern void D3D_Line(VECTOR2D* LineStart, VECTOR2D* LineEnd, int LineColour); +extern void Draw_Line_VMType_8(VECTOR2D* LineStart, VECTOR2D* LineEnd, int LineColour); + +// Prototypes + +int IDemandFireWeapon(void); + +int IDemandNextWeapon(void); +int IDemandPreviousWeapon(void); + + +// Functions + + + +void catpathandextension(char* dst, char* src) +{ + int len = lstrlen(dst); + + if ((len > 0 && (dst[len-1] != '\\' && dst[len-1] != '/')) && *src != '.') + { + lstrcat(dst,"\\"); + } + + lstrcat(dst,src); + +/* + The second null here is to support the use + of SHFileOperation, which is a Windows 95 + addition that is uncompilable under Watcom + with ver 10.5, but will hopefully become + available later... +*/ + len = lstrlen(dst); + dst[len+1] = 0; + +} + + +/* game platform definition of the Mouse Mode*/ + +int MouseMode = MouseVelocityMode; + +/* + + Real PC control functions + +*/ +#if 1 +int IDemandLookUp(void) +{ + return No; +} + + +int IDemandLookDown(void) +{ + return No; +} + + +int IDemandTurnLeft(void) +{ + InputMode = Digital; + if(KeyboardInput[KEY_LEFT]) + return Yes; + return No; +} + + +int IDemandTurnRight(void) +{ + InputMode = Digital; + if(KeyboardInput[KEY_RIGHT]) + return Yes; + return No; +} + + +int IDemandGoForward(void) +{ + InputMode = Digital; + if(KeyboardInput[KEY_UP]) + return Yes; + return No; +} + + +int IDemandGoBackward(void) +{ + InputMode = Digital; + if(KeyboardInput[KEY_DOWN]) + return Yes; + return No; +} + + +int IDemandJump(void) +{ + InputMode = Digital; + if(KeyboardInput[KEY_CAPS]) + return Yes; + return No; +} + + + +int IDemandCrouch(void) +{ + InputMode = Digital; + if(KeyboardInput[KEY_Z]) + return Yes; + return No; +} + +int IDemandSelect(void) +{ + InputMode = Digital; + + if(KeyboardInput[KEY_CR]) return Yes; + if(KeyboardInput[KEY_SPACE]) return Yes; + else return No; +} + +int IDemandStop(void) +{ + return No; +} + + +int IDemandFaster(void) +{ + InputMode = Digital; + if(KeyboardInput[KEY_LEFTSHIFT]) + return Yes; + return No; +} + + +int IDemandSideStep(void) +{ + InputMode = Digital; + if(KeyboardInput[KEY_LEFTALT]) + return Yes; + return No; +} + +int IDemandPickupItem(void) +{ + InputMode = Digital; + if(KeyboardInput[KEY_P]) + return Yes; + return No; +} + +int IDemandDropItem(void) +{ + InputMode = Digital; + if(KeyboardInput[KEY_D]) + return Yes; + return No; +} + +int IDemandMenu(void) +{ + InputMode = Digital; + if(KeyboardInput[KEY_M]) + return Yes; + return No; +} + +int IDemandOperate(void) +{ + InputMode = Digital; + if(KeyboardInput[KEY_SPACE]) + return Yes; + return No; +} + + + +int IDemandFireWeapon(void) +{ + InputMode = Digital; + if(KeyboardInput[KEY_CR]) + return Yes; + return No; +} + +/* KJL 11:29:12 10/07/96 - added by me */ +int IDemandPreviousWeapon(void) +{ + InputMode = Digital; + if(KeyboardInput[KEY_1]) return Yes; + else return No; +} +int IDemandNextWeapon(void) +{ + InputMode = Digital; + if(KeyboardInput[KEY_2]) return Yes; + else return No; +} +#endif + + +int IDemandChangeEnvironment() +{ + InputMode = Digital; + + if(KeyboardInput[KEY_F1]) + return 0; + else if(KeyboardInput[KEY_F2]) + return 1; + else if(KeyboardInput[KEY_F3]) + return 2; + else if(KeyboardInput[KEY_F4]) + return 3; + else if(KeyboardInput[KEY_F5]) + return 4; + else + return(-1); +} + + + + + + +#if 0 +/*KJL*************************************** +* HUD MAP DISPLAY CODE * +***************************************KJL*/ +#include "hud_map.h" +static unsigned int GreyColour; +static unsigned int WhiteColour; +static unsigned int RedColour; +extern int ScanDrawMode; +extern int NumVertices; +extern int ZBufferMode; + +void PlatformSpecificInitHUDMap(void) +{ + if (ScanDrawMode != ScanDrawDirectDraw) + { + GreyColour = /*GetSingleColourForPrimary(*/0x007f7f7f/*)*/; + WhiteColour = /*GetSingleColourForPrimary(*/0x00ffffff/*)*/; + RedColour = /*GetSingleColourForPrimary(*/0x007f0000/*)*/; + } + else + { + extern unsigned char TestPalette[]; + GreyColour = NearestColour(31,31,31, TestPalette); + WhiteColour = NearestColour(63,63,63, TestPalette); + RedColour = NearestColour(63,0,0, TestPalette); + } +} +void DrawHUDMapLine(VECTOR2D *vertex1, VECTOR2D *vertex2, enum MAP_COLOUR_ID colourID) +{ + unsigned int colourIndex; + switch(colourID) + { + default: + case MAP_COLOUR_WHITE: + { + colourIndex = WhiteColour; + break; + } + + case MAP_COLOUR_GREY: + { + colourIndex = GreyColour; + break; + } + + case MAP_COLOUR_RED: + { + colourIndex = RedColour; + break; + } + + } + + if (ScanDrawMode != ScanDrawDirectDraw) + { + if (ZBufferOn!=ZBufferMode) + { + DirectWriteD3DLine(vertex1,vertex2,colourIndex); + /* + The offset by 24 is a bodge until Microsoft work out + what the fuck's going on... + */ /* Neal's comment, not mine... :) KJL */ + if ((ScanDrawMode != ScanDrawDirectDraw) && (NumVertices > (MaxD3DVertices-24))) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + } + else D3D_Line(vertex1,vertex2,colourIndex); + + } + else + { + Draw_Line_VMType_8(vertex1,vertex2,colourIndex); + } +} + + +void PlatformSpecificEnteringHUDMap(void) +{ + /* this is here to make sure that the right colours + are chosen from the palette */ + PlatformSpecificInitHUDMap(); +} + +void PlatformSpecificExitingHUDMap(void) +{ +} + +/*KJL*************************************** +* HUD MAP DISPLAY CODE * +***************************************KJL*/ +#endif + + + + +/* KJL 15:53:52 05/04/97 - +Loaders/Unloaders for language internationalization code in language.c */ + +char *LoadTextFile(char *filename) +{ + char *bufferPtr; + long int save_pos, size_of_file; + FILE *fp; + fp = fopen(filename,"rb"); + + if (!fp) goto error; + + save_pos=ftell(fp); + fseek(fp,0L,SEEK_END); + size_of_file=ftell(fp); + + bufferPtr = AllocateMem(size_of_file); + if (!bufferPtr) + { + memoryInitialisationFailure = 1; + goto error; + } + + fseek(fp,save_pos,SEEK_SET); + + + if (!fread(bufferPtr, size_of_file,1,fp)) + { + fclose(fp); + goto error; + } + + fclose(fp); + return bufferPtr; + +error: + { + /* error whilst trying to load file */ + textprint("Error! Can not load file %s.\n",filename); + LOCALASSERT(0); + return 0; + } +} + + +void UnloadTextFile(char *filename, char *bufferPtr) +{ + if (bufferPtr) DeallocateMem(bufferPtr); +} diff --git a/3dc/avp/win95/PLDGHOST.H b/3dc/avp/win95/PLDGHOST.H new file mode 100644 index 0000000..c866873 --- /dev/null +++ b/3dc/avp/win95/PLDGHOST.H @@ -0,0 +1,141 @@ +/*---------------------------Patrick 28/3/97---------------------------- + Header for Multi-Player ghost object support header + ----------------------------------------------------------------------*/ +#ifndef pldghost_h_included +#define pldghost_h_included +#ifdef __cplusplus +extern "C" { +#endif + +#include "pvisible.h" +#include "pldnet.h" + +/*---------------------------Patrick 28/3/97---------------------------- + Structures for ghosts and ghost data blocks + ----------------------------------------------------------------------*/ + +typedef struct netghostdatablock +{ + DPID playerId; + signed int playerObjectId; /* -1 == player, all other numbers used for objects */ + AVP_BEHAVIOUR_TYPE type; + INANIMATEOBJECT_TYPE IOType; + int subtype; + SHAPEANIMATIONCONTROLLER ShpAnimCtrl; + + /* KJL 17:33:41 22/01/99 - I've made this a union because I needed a storage space, + and the currentAnimSequence is only used by specific objects */ + union + { + int currentAnimSequence; + int EventCounter; // used by grenades + }; + + DISPLAYBLOCK *myGunFlash; + SECTION_DATA *GunflashSectionPtr; + int GunFlashFrameStamp; + int CurrentWeapon; + + int SoundHandle; + int SoundHandle2; + int SoundHandle3; + int SoundHandle4; + int integrity; + int timer; + + int FlameHitCount;//number of fire particles that have hit since last frame + int FlechetteHitCount;//number of flechette particles that have hit since last frame + + HMODELCONTROLLER HModelController; + HITLOCATIONTABLE *hltable; + + int CloakingEffectiveness; + + unsigned int IgnitionHandshaking :1; + + unsigned int invulnerable :1; //for netghost's of players + unsigned int onlyValidFar:1; //set for alien ai that are far from everyone + unsigned int soundStartFlag:1; + + #if EXTRAPOLATION_TEST + VECTORCH velocity; + int extrapTimerLast; + int extrapTimer; + unsigned int lastTimeRead; + #endif +}NETGHOSTDATABLOCK; + +/*---------------------------Patrick 28/3/97---------------------------- + Protoypes + ----------------------------------------------------------------------*/ +extern void UpdateGhost(STRATEGYBLOCK *sbPtr,VECTORCH *position,EULER *orientation,int sequence, int special); +extern void RemoveGhost(STRATEGYBLOCK *sbPtr); +extern void RemovePlayersGhosts(DPID id); +extern void RemovePlayerGhost(DPID id); +extern STRATEGYBLOCK *FindGhost(DPID Id, int obId); +extern STRATEGYBLOCK *CreateNetGhost(DPID playerId, int objectId, VECTORCH *position, EULER* orientation, AVP_BEHAVIOUR_TYPE type, unsigned char IOType, unsigned char subtype); +extern void MakeGhostNear(STRATEGYBLOCK *sbPtr); +extern void MakeGhostFar(STRATEGYBLOCK *sbPtr); +extern void DamageNetworkGhost(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, SECTION_DATA *section,VECTORCH* incoming); +extern void HandleGhostGunFlashEffect(STRATEGYBLOCK *sbPtr, int gunFlashOn); +extern void HandlePlayerGhostWeaponSound(STRATEGYBLOCK *sbPtr, int weapon, int firingPrimary, int firingSecondary); +extern void HandleWeaponElevation(STRATEGYBLOCK *sbPtr, int elevation, int weapon); +extern void MaintainGhosts(void); +extern void HandleGhostAutoGunMuzzleFlash(STRATEGYBLOCK *sbPtr, int firing); +extern void HandleGhostAutoGunSound(STRATEGYBLOCK *sbPtr, int firing); +extern void MaintainGhostCloakingStatus(STRATEGYBLOCK *sbPtr, int IsCloaked); +extern void MaintainGhostFireStatus(STRATEGYBLOCK *sbPtr, int IsOnFire); + +extern void NetGhostBehaviour(STRATEGYBLOCK *sbPtr); +extern void KillGhost(STRATEGYBLOCK *sbPtr, int objectId); +extern int Deduce_PlayerDeathSequence(void); +extern STRATEGYBLOCK *MakeNewCorpse(); +extern void ApplyGhostCorpseDeathAnim(STRATEGYBLOCK *sbPtr,int deathId); +extern void ApplyCorpseDeathAnim(STRATEGYBLOCK *sbPtr,int deathId); + +extern int Deduce_PlayerMarineDeathSequence(STRATEGYBLOCK* sbPtr,DAMAGE_PROFILE* damage,int multiple,VECTORCH* incoming); +extern int Deduce_PlayerAlienDeathSequence(STRATEGYBLOCK* sbPtr,DAMAGE_PROFILE* damage,int multiple,VECTORCH* incoming); +extern int Deduce_PlayerPredatorDeathSequence(STRATEGYBLOCK* sbPtr,DAMAGE_PROFILE* damage,int multiple,VECTORCH* incoming); + +extern void UpdateAlienAIGhost(STRATEGYBLOCK *sbPtr,VECTORCH *position,EULER *orientation,int sequence_type,int sub_sequence, int sequence_length); +extern void KillAlienAIGhost(STRATEGYBLOCK *sbPtr,int death_code,int death_time,int GibbFactor); + +extern void Convert_DiscGhost_To_PickupGhost(STRATEGYBLOCK *sbPtr); +extern void PlayHitDeltaOnGhost(STRATEGYBLOCK *sbPtr,char delta_seq,char delta_sub_seq); +extern void PlayOtherSound(enum soundindex SoundIndex, VECTORCH *position, int explosion); + +/*---------------------------Patrick 29/3/97---------------------------- + Defines + ----------------------------------------------------------------------*/ +#define GHOST_PLAYEROBJECTID -1 +#define PLAYERGHOST_NUMBEROFFRAGMENTS 10 +#define GHOST_INTEGRITY (ONE_FIXED*8) + +#define MPPRED_MUZZLEFLASHOFFSET_INFRONT 800 +#define MPPRED_MUZZLEFLASHOFFSET_ACROSS 200 +#define MPPRED_MUZZLEFLASHOFFSET_UP 100 +#define MPPRED_MUZZLEFLASHOFFSET_INFRONT_CROUCH 1000 +#define MPPRED_MUZZLEFLASHOFFSET_ACROSS_CROUCH 200 +#define MPPRED_MUZZLEFLASHOFFSET_UP_CROUCH 0 + +#define MPMARINE_MUZZLEFLASHOFFSET_INFRONT 1100 +#define MPMARINE_MUZZLEFLASHOFFSET_ACROSS 200 +#define MPMARINE_MUZZLEFLASHOFFSET_UP 0 +#define MPMARINE_MUZZLEFLASHOFFSET_INFRONT_CROUCHED 400 +#define MPMARINE_MUZZLEFLASHOFFSET_ACROSS_CROUCHED 300 +#define MPMARINE_MUZZLEFLASHOFFSET_UP_CROUCHED (-400) +#define MPMARINE_MUZZLEFLASHOFFSET_INFRONT_RUNNING 1100 +#define MPMARINE_MUZZLEFLASHOFFSET_ACROSS_RUNNING 50 +#define MPMARINE_MUZZLEFLASHOFFSET_UP_RUNNING 400 + + +/*---------------------------Patrick 28/3/97---------------------------- + Globals + ----------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/3dc/avp/win95/PROJLOAD.HPP b/3dc/avp/win95/PROJLOAD.HPP new file mode 100644 index 0000000..9ea2e3e --- /dev/null +++ b/3dc/avp/win95/PROJLOAD.HPP @@ -0,0 +1,161 @@ +#ifndef _projload_hpp +#define _projload_hpp 1 + +#include "chnkload.h" +#include "hmodel.h" + + + +#ifdef __cplusplus + +#include "hierchnk.hpp" + +// project specifc structure contained in rif handle +struct Project_RifHandle {}; + +struct Object_ShapeNum_Pair +{ + int sh_num; + Object_Chunk * ob; +}; + +struct Hierarchy_ID_Time_Pair +{ + int id; + int time; +}; + + +struct Hierarchy_Alternate_Shape_Set +{ + char* shape_set_name; + int index; + int num_replaced_shapes; + int flags; + //terminator has 0 for name and replacement_shape + HIERARCHY_SHAPE_REPLACEMENT* replaced_shapes; +}; + +struct Hierarchy_Descriptor +{ + // this is null if the sequence is a template + // or contains the name of the SECTION that it + // attachs to + + SECTION * hierarchy_root; + + char * hierarchy_name; + + +}; + +extern "C" +{ +struct hierarchy_variant_data; +}; + +class Global_Hierarchy_Store +{ + +public: + + // in a vain hope + Global_Hierarchy_Store (RIFFHANDLE h); + + ~Global_Hierarchy_Store(); + + void add_hierarchy (List & osnp_lst, Object_Hierarchy_Chunk * ohc); + void setup_alternate_shape_sets (List & osnp_lst, File_Chunk * fc); + + List hierarchy_list; + + List alternate_shape_set_list; + + int num_shape_collections; + struct hierarchy_variant_data* shape_collections; + List random_shape_colls; + + + RIFFHANDLE rif_hand; + + char * riffname; + + private: + + int num_sounds; + HIERARCHY_SOUND* sound_array; + + static List time_list; + + int get_time_from_sequence_id(int id); + void build_time_list(Object_Hierarchy_Chunk* ohc); + + SECTION * build_hierarchy (Object_Hierarchy_Chunk * ohc,char* hierarchy_name); + + void delete_section(SECTION *); + + +}; + +extern "C" { + +#endif + +#define LOAD_MORPH_SHAPES 1 // you can compile out the code that copies morph data + +#define CL_SUPPORT_ALTTAB 1 // textures and surfaces loaded with CL_LoadImageOnce with LIO_RESTORABLE set will be added to ALT+TAB lists +#define CL_SUPPORT_FASTFILE 1 // AvP uses fastfiles (but if the gfx aren't in them, it'll try the actual files +#ifdef AVP_DEBUG_VERSION +#define CL_SUPPORTONLY_FASTFILE 0 // for release, milestones, CDs, demos, may want this to be non-zero +#else +//allow loading from outside of fastfiles to help with custom levels +#define CL_SUPPORTONLY_FASTFILE 0 // for release, milestones, CDs, demos, may want this to be non-zero +#endif +// project specific copy chunks flags +#define CCF_ENVIRONMENT 0x00000001 +#define CCF_IMAGEGROUPSET 0x00000002 +#define CCF_LOAD_AS_HIERARCHY_IF_EXISTS 0x00000004 +#define CCF_DONT_INITIALISE_TEXTURES 0x00000008 + +extern void setup_shading_tables(void); +extern void SetUpRunTimeLights (); + +// copies all shapes and objects etc +extern BOOL copy_chunks_from_environment(int flags); + +// set the local_scale +extern void set_local_scale(RIFFHANDLE, int flags); +#define SetLocalScale(h,f) set_local_scale(h,f) + +// copies all shapes and objects etc +extern BOOL copy_rif_data (RIFFHANDLE, int flags,int progress_start,int progress_interval); +#define CopyRIFData(h,f) copy_rif_data(h,f) + +// this should return the next free main shape list position for loaded shapes; it may be called more than once +extern int load_precompiled_shapes(); +#define LoadPrecompiledShapes() load_precompiled_shapes() + +void avp_undo_rif_load(RIFFHANDLE h); +RIFFHANDLE avp_load_rif (const char * fname); +RIFFHANDLE avp_load_rif_non_env (const char * fname); + +void DeallocateModules(); + +void EmptyHierarchyLibrary (); + +void DeleteHierarchyLibraryEntry(RIFFHANDLE); + +SECTION * GetHierarchyFromLibrary(const char * rif_name); +SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char *); +HIERARCHY_SHAPE_REPLACEMENT* GetHierarchyAlternateShapeSetFromLibrary(const char* rif_name,const char* shape_set_name); + + +extern void save_preplaced_decals(); + +#ifdef __cplusplus + +}; +#endif + + +#endif \ No newline at end of file diff --git a/3dc/avp/win95/PSNDPLAT.H b/3dc/avp/win95/PSNDPLAT.H new file mode 100644 index 0000000..7d8f1de --- /dev/null +++ b/3dc/avp/win95/PSNDPLAT.H @@ -0,0 +1,207 @@ +/* Patrick 5/6/97 ------------------------------------------------------------- + AvP platform specific sound management header: + Support for sample and CDDA sounds. + ----------------------------------------------------------------------------*/ +#ifndef PSNDPLAT_H +#define PSNDPLAT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "psndproj.h" +#include "psnd.h" + +/* Patrick 10/6/97 ------------------------------------------------------------- + SAMPLE SUPPORT + ----------------------------------------------------------------------------*/ + +/* Patrick 5/6/97 ------------------------------------------------------------- + Data structure for a loaded sound. The first four fields must be included + for all platforms. + ----------------------------------------------------------------------------*/ +typedef struct soundsampledata +{ + int loaded; + int activeInstances; + int volume; + int pitch; + LPDIRECTSOUNDBUFFER dsBufferP; + unsigned int flags; + int dsFrequency; + char * wavName; + int length; //time in fixed point seconds + +}SOUNDSAMPLEDATA; + +/* Defines for the flags. */ +#define SAMPLE_IN_HW 0x00000001 +#define SAMPLE_IN_SW 0x00000002 +#define SAMPLE_IN_3D 0x00000004 + +/* Patrick 5/6/97 ------------------------------------------------------------- + Data structure for a playing (active) sound. The first eight fields must be + included for all platforms. + ----------------------------------------------------------------------------*/ +typedef struct activesoundsample +{ + SOUNDINDEX soundIndex; + ACTIVESOUNDPRIORITY priority; + int volume; + int pitch; + int *externalRef; + unsigned int loop :1; + unsigned int threedee :1; + unsigned int paused :1; + unsigned int marine_ignore :1; + unsigned int reverb_off :1; + SOUND3DDATA threedeedata; + + LPDIRECTSOUNDBUFFER dsBufferP; + LPDIRECTSOUND3DBUFFER ds3DBufferP; + LPKSPROPERTYSET PropSetP; + +}ACTIVESOUNDSAMPLE; + +/* Patrick 5/6/97 ------------------------------------------------------------- + Data structures for WAV headers and chuncks + ----------------------------------------------------------------------------*/ +typedef struct pwavchunkheader +{ + char chunkName[4]; + int chunkLength; +} PWAVCHUNKHEADER; + +typedef struct pwavriffheader +{ + char type[4]; +} PWAVRIFFHEADER; + +void InitialiseBaseFrequency(SOUNDINDEX soundNum); +int LoadWavFile(int soundNum, char *); +int LoadWavFromFastFile(int soundNum, char *); + +/* Patrick 5/6/97 ------------------------------------------------------------- + Start and EndSoundSys: does any platform operations required to initialise + and exit the sound system + ----------------------------------------------------------------------------*/ +extern int PlatStartSoundSys(void); +extern void PlatEndSoundSys(void); +/* Patrick 5/6/97 ------------------------------------------------------------- + Sets the global volume, and returns true (1) if successful, or false (0) + otherwise. + ----------------------------------------------------------------------------*/ +extern int PlatChangeGlobalVolume(int volume); +/* Patrick 5/6/97 ------------------------------------------------------------- + Play a sound: does platform operations required to create and play a new + sound from the active sound data for the given sound. This function must + also perform any neccessary operations that may be required to initilaise + a sounds volume, pitch, or 3d attributes. + PlatStartSoundSys returns true (1) if successful, or false (0) otherwise. + ----------------------------------------------------------------------------*/ +extern int PlatPlaySound(int activeIndex); +/* Patrick 5/6/97 ------------------------------------------------------------- + Stop a sound: Any platform operations required for stopping a sound. returns + true (1) if successful, or SOUND_PLATFORMERROR (-1) otherwise. + ----------------------------------------------------------------------------*/ +extern void PlatStopSound(int activeIndex); +/* Patrick 5/6/97 ------------------------------------------------------------- + The following perform the required platform operations for changing volume, + and pitch for a playing sound. All return true (1) if successful, or + SOUND_PLATFORMERROR (-1) otherwise. + ----------------------------------------------------------------------------*/ +extern int PlatChangeSoundVolume(int activeIndex, int volume); +extern int PlatChangeSoundPitch(int activeIndex, int pitch); +/* Patrick 5/6/97 ------------------------------------------------------------- + The following function performs the neccessary operations required for a 3d + sound (eg volume, pan). Return true (1) if successful, or SOUND_PLATFORMERROR + (-1) otherwise. + ----------------------------------------------------------------------------*/ +extern int PlatDo3dSound(int activeIndex); +/* Patrick 5/6/97 ------------------------------------------------------------- + Return true (1) if the sound has stopped, false (0) if it is still playing + or SOUND_PLATFORMERROR (-1) otherwise. + ----------------------------------------------------------------------------*/ +extern int PlatSoundHasStopped(int activeIndex); +/* Patrick 5/6/97 ------------------------------------------------------------- + Performs any platform specific operations required to unload a game sound, + wile the sound system is exiting + ----------------------------------------------------------------------------*/ +extern void PlatEndGameSound(SOUNDINDEX index); + +/* Davew 23/7/98 -------------------------------------------------------------- + Update the player in the 3D sound system. + ----------------------------------------------------------------------------*/ +extern void PlatUpdatePlayer(); + +/* Davew 27/7/98 --------------------------------------------------------------- + This sets the enviroment for the Listener. The first parameter is the index + of the enviroment, the second is the reverb ratio to apply to sound (0 - 1) + float. Negative means let the card deal with reverb. + ---------------------------------------------------------------------------*/ +extern void PlatSetEnviroment(unsigned int env_index, float reverb_mix); +extern unsigned int PlatMaxHWSounds(); + +/* Davew 11/11/98 -------------------------------------------------------------- + Controls the use of 3DHW, by default it is used if present. Return codes + 2 means it was already in that state, 1 means to changed state sucessfully + -1 means it failed to change state. Note these functions may well be slow. + ---------------------------------------------------------------------------*/ +extern int PlatUse3DSoundHW(); +extern int PlatDontUse3DSoundHW(); + +/* Patrick 5/6/97 ------------------------------------------------------------- + Defines for max number of sounds, and instances of sounds, allowed; + also maximum and minimum volume, pitch, and pan values for platform. + ----------------------------------------------------------------------------*/ +#define SOUND_MAXACTIVE (120) +#define SOUND_MAXACTIVE_SW (20) +#define SOUND_MAXINSTANCES (20) +#define SOUND_MAXSIZE (250000) /* biggest sample we will allow to be loaded */ + +#define SOUND_DEACTIVATERANGE (10000 * GlobalScale) + +#define VOLUME_MAXPLAT (0) /* attenuation values, in db's */ +#define VOLUME_MINPLAT (-10000) +#define VOLUME_PLAT2DSCALE (96) /* in 128ths of the original volume */ + +/* frequency values are those accepted by ds. Pitch is measured in semi-tones, +and is applied relative to the loaded frequency of the sound */ +#define FREQUENCY_MAXPLAT (100000) +#define FREQUENCY_MINPLAT (100) +#define PITCH_MAXPLAT (6144) +#define PITCH_MINPLAT (-6144) +#define PITCH_DEFAULTPLAT (0) + +#define PAN_MAXPLAT (1200) +#define PAN_MINPLAT (-1200) +#define PAN_3DDAMPDISTANCE (1000) + +/* NB ds supports pan +- 10000: */ + +/* Patrick 5/6/97 ------------------------------------------------------------- + Defines for 3D attenuation: + Volume attenuation is per metre, in global volume units, as defined by + VOLUME_MAX and VOLUME_MIN in psnd.h + Pan attenuation is per 180/2048 degrees, in platform units as defined above + by PAN_MAXPLAT and PAN_MINPLAT (ie panattenuation*(1024)<=PAN_MAXPLAT), + assuming symetrical range. + ----------------------------------------------------------------------------*/ +#define VOLUME_3DATTENUATION (4) + +/* Patrick 5/6/97 ------------------------------------------------------------- + Global references to sound management data areas, and blank instances of data + structures storted in those areas + ----------------------------------------------------------------------------*/ +extern SOUNDSAMPLEDATA GameSounds[]; +extern ACTIVESOUNDSAMPLE ActiveSounds[]; +extern SOUNDSAMPLEDATA BlankGameSound; +extern ACTIVESOUNDSAMPLE BlankActiveSound; + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/3dc/avp/win95/PathChnk.cpp b/3dc/avp/win95/PathChnk.cpp new file mode 100644 index 0000000..205a3b1 --- /dev/null +++ b/3dc/avp/win95/PathChnk.cpp @@ -0,0 +1,83 @@ +#include "PathChnk.hpp" +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(pathchnk) + +RIF_IMPLEMENT_DYNCREATE("AVPPATH2",AVP_Path_Chunk) + +AVP_Path_Chunk::AVP_Path_Chunk(Chunk_With_Children* parent) +:Chunk(parent,"AVPPATH2") +{ + PathLength=0; + Path=0; + PathID=0; + PathName=0; + flags=spare2=0; +} + +AVP_Path_Chunk::AVP_Path_Chunk(Chunk_With_Children* parent,const char* data,size_t datasize) +:Chunk(parent,"AVPPATH2") +{ + int name_length=strlen(data); + PathName=new char[name_length+1]; + strcpy(PathName,data); + data+=(name_length+4)&~3; + + PathID=*(int*)data; + data+=4; + flags=*(int*)data; + data+=4; + spare2=*(int*)data; + data+=4; + PathLength=*(int*)data; + data+=4; + + if(PathLength) Path=new ChunkPathPoint[PathLength]; + else Path=0; + + for(int i=0;iSBdataptr; + + /* for visibility support: as ghosts can be moved when invisible, we need to work out + which module they're in whenever we update them. We must be carefull, however, not + to set the containingModule to NULL if the object has moved outside the env, as + the visibility system expects that we at least know what module any object WAS in, + even if we do not now... thus, if we cannot find a containing module, we abort the update */ + + /* KJL 21:01:09 23/05/98 - I've put this test here because the player's image in a mirror goes + throught this code, and it's obviously going to be outside the environment */ + if (sbPtr->I_SBtype==I_BehaviourNetGhost) + { + MODULE *myContainingModule = ModuleFromPosition(position, (sbPtr->containingModule)); + if(myContainingModule==NULL) + { + //Not in any module , so don't try updating ghost, + //except for various projectiles which can be shot + //out of the environment semi-legitamately + if(ghostData->type!=I_BehaviourGrenade && + ghostData->type!=I_BehaviourRocket && + ghostData->type!=I_BehaviourPPPlasmaBolt && + ghostData->type!=I_BehaviourSpeargunBolt && + ghostData->type!=I_BehaviourPredatorDisc_SeekTrack && + ghostData->type!=I_BehaviourPredatorEnergyBolt && + ghostData->type!=I_BehaviourPulseGrenade && + ghostData->type!=I_BehaviourFlareGrenade && + ghostData->type!=I_BehaviourFragmentationGrenade && + ghostData->type!=I_BehaviourClusterGrenade && + ghostData->type!=I_BehaviourFrisbeeEnergyBolt && + ghostData->type!=I_BehaviourProximityGrenade) + return; + } + else + { + sbPtr->containingModule = myContainingModule; + } + } + + /* CDF 29/7/98 I'll assume that stationary discs are stuck. */ + if (ghostData->type==I_BehaviourPredatorDisc_SeekTrack) { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + if ((dynPtr->Position.vx==dynPtr->PrevPosition.vx)&& + (dynPtr->Position.vy==dynPtr->PrevPosition.vy)&& + (dynPtr->Position.vz==dynPtr->PrevPosition.vz)) { + ghostData->HModelController.Playing=0; + + + } else { + extern void NewTrailPoint(DYNAMICSBLOCK *dynPtr); + ghostData->HModelController.Playing=1; + //draw the disc's trail + NewTrailPoint(dynPtr); + + //update sound for disc + if(ghostData->SoundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Update3d(ghostData->SoundHandle,&(sbPtr->DynPtr->Position)); + } else { + Sound_Play(SID_PREDATOR_DISK_FLYING,"del",&(sbPtr->DynPtr->Position),&ghostData->SoundHandle); + + } + } + } + + if (ghostData->type==I_BehaviourFrisbee) { + //update sound for disc + if(ghostData->SoundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Update3d(ghostData->SoundHandle,&(sbPtr->DynPtr->Position)); + } else { + Sound_Play(SID_ED_SKEETERDISC_SPIN,"del",&(sbPtr->DynPtr->Position),&ghostData->SoundHandle); + } + } + + /* update the dynamics block */ + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; +// dynPtr->Position = dynPtr->PrevPosition = *position; + dynPtr->PrevPosition = dynPtr->Position; + dynPtr->PrevOrientMat = dynPtr->OrientMat; + dynPtr->Position = *position; + dynPtr->OrientEuler = *orientation; + CreateEulerMatrix(&dynPtr->OrientEuler,&dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + } + UpdateObjectTrails(sbPtr); + #if 0 + if (ghostData->type == I_BehaviourPredatorEnergyBolt) + { + MakePlasmaTrailParticles(sbPtr->DynPtr,32); + } + #endif + + + /* if we're a player type, update the animation sequence */ + if((ghostData->type==I_BehaviourMarinePlayer)|| + (ghostData->type==I_BehaviourAlienPlayer)|| + (ghostData->type==I_BehaviourPredatorPlayer)) + { + if(sequence!=-1) + { + UpdatePlayerGhostAnimSequence(sbPtr,sequence, special); + } + } + + /* KJL 15:59:59 26/11/98 - no pheromone trails */ + #if 0 + if (AvP.PlayerType == I_Alien) + { + if ((ghostData->type==I_BehaviourMarinePlayer) + ||(ghostData->type==I_BehaviourPredatorPlayer)) + NewTrailPoint(sbPtr->DynPtr); + } + #endif + + /* KJL 16:58:04 17/06/98 - we want to update anims differently for NPCS */ + if((ghostData->type==I_BehaviourMarine)|| + (ghostData->type==I_BehaviourAlien)|| + (ghostData->type==I_BehaviourPredator)) + { + UpdatePlayerGhostAnimSequence(sbPtr,sequence, special); + } + + /* refresh integrity */ + ghostData->integrity = GHOST_INTEGRITY; + +} +void UpdateObjectTrails(STRATEGYBLOCK *sbPtr) +{ + NETGHOSTDATABLOCK *ghostDataPtr; + + LOCALASSERT(sbPtr); + + ghostDataPtr = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostDataPtr); + + LOCALASSERT(sbPtr->DynPtr); + + switch(ghostDataPtr->type) + { + case I_BehaviourPulseGrenade: + { + MakeRocketTrailParticles(&(sbPtr->DynPtr->PrevPosition), &(sbPtr->DynPtr->Position)); + break; + } + case I_BehaviourRocket: + { + MakeRocketTrailParticles(&(sbPtr->DynPtr->PrevPosition), &(sbPtr->DynPtr->Position)); + break; + } + case I_BehaviourPredatorEnergyBolt: + { + MakePlasmaTrailParticles(sbPtr->DynPtr,32); + break; + } + case I_BehaviourFrisbeeEnergyBolt: + { + MakeDewlineTrailParticles(sbPtr->DynPtr,32); + break; + } + case I_BehaviourFrisbee: + { + { + int l; + for (l=0;l<4;l++) + MakeFlareParticle(sbPtr->DynPtr); + } + break; + } + case I_BehaviourGrenade: + case I_BehaviourProximityGrenade: + { + MakeGrenadeTrailParticles(&(sbPtr->DynPtr->PrevPosition), &(sbPtr->DynPtr->Position)); + break; + } + default: + break; + } +} + + +/* removes a ghost */ +void RemoveGhost(STRATEGYBLOCK *sbPtr) +{ + NETGHOSTDATABLOCK *ghostData; + + LOCALASSERT(sbPtr); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + /* this is where we add fragmentation and explosion effects to destroyed ghosts */ + switch(ghostData->type) + { + case(I_BehaviourAlienPlayer): + case(I_BehaviourMarinePlayer): + case(I_BehaviourPredatorPlayer): + { + Extreme_Gibbing(sbPtr,ghostData->HModelController.section_data,ONE_FIXED); + break; + } + case(I_BehaviourGrenade): + { + if (sbPtr->containingModule) { + Ghost_Explosion_SoundData.position=sbPtr->DynPtr->Position; + Sound_Play(SID_ED_GRENADE_EXPLOSION,"n",&Ghost_Explosion_SoundData); + } + break; + } + case(I_BehaviourRocket): + { + if (sbPtr->containingModule) { + Ghost_Explosion_SoundData.position=sbPtr->DynPtr->Position; + Sound_Play(SID_NICE_EXPLOSION,"n",&Ghost_Explosion_SoundData); + } + break; + } + case(I_BehaviourProximityGrenade): + { + if (sbPtr->containingModule) { + Ghost_Explosion_SoundData.position=sbPtr->DynPtr->Position; + Sound_Play(SID_ED_GRENADE_PROXEXPLOSION,"n",&Ghost_Explosion_SoundData); + } + break; + } + case(I_BehaviourFragmentationGrenade): + case(I_BehaviourClusterGrenade): + { + if (sbPtr->containingModule) { + Ghost_Explosion_SoundData.position=sbPtr->DynPtr->Position; + Sound_Play(SID_NADEEXPLODE,"n",&Ghost_Explosion_SoundData); + } + break; + } + case(I_BehaviourPulseGrenade): + { + if (sbPtr->containingModule) { + Ghost_Explosion_SoundData.position=sbPtr->DynPtr->Position; + Sound_Play(SID_NADEEXPLODE,"n",&Ghost_Explosion_SoundData); + } + break; + } + case(I_BehaviourNPCPredatorDisc): + case(I_BehaviourPredatorDisc_SeekTrack): + { + /* MakeAnExplosion... ? */ + Sound_Play(SID_NADEEXPLODE,"d",&(sbPtr->DynPtr->Position)); + break; + } + case(I_BehaviourFrisbee): + { + //Ghost_Explosion_SoundData.position=sbPtr->DynPtr->Position; + //Sound_Play(SID_NICE_EXPLOSION,"n",&Ghost_Explosion_SoundData); + break; + } + case (I_BehaviourPPPlasmaBolt) : + { + break; + } + + + case(I_BehaviourAlienSpit): + { + break; + } + case(I_BehaviourNetCorpse): + { + break; + } + default: + { + /* do absolutely bugger all, probably: + remaining cases are: predator energy bolt;flame;predator disc;flare; + and AUTOGUN */ + break; + } + } + + /* see if we've got a sound... */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + if(ghostData->SoundHandle2 != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle2); + if(ghostData->SoundHandle3 != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle3); + if(ghostData->SoundHandle4 != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle4); + + /* see if we've got a muzzle flash... */ + if(ghostData->myGunFlash) + { + RemoveNPCGunFlashEffect(ghostData->myGunFlash); + ghostData->myGunFlash = NULL; + } + + DestroyAnyStrategyBlock(sbPtr); +} + +/* removes a given player's ghost, and all associated ghosts, eg when a player +leaves the game... */ +void RemovePlayersGhosts(DPID id) +{ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + + int sbIndex = 0; + STRATEGYBLOCK *sbPtr; + + while(sbIndex < NumActiveStBlocks) + { + sbPtr = ActiveStBlockList[sbIndex++]; + if(sbPtr->I_SBtype==I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + if(ghostData->playerId==id) { + RemoveGhost(sbPtr); + } + } + } +} + + +/* locates a ghost from Id and ObId */ +STRATEGYBLOCK *FindGhost(DPID Id, int obId) +{ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + + int sbIndex = 0; + STRATEGYBLOCK *sbPtr; + + while(sbIndex < NumActiveStBlocks) + { + sbPtr = ActiveStBlockList[sbIndex++]; + if(sbPtr->I_SBtype==I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + if((ghostData->playerId==Id)&&(ghostData->playerObjectId==obId)) return sbPtr; + } + } + return NULL; +} + +/* create a new ghost: doesn't do shape animation stuff: this is performed using a +seperate set of functions */ +STRATEGYBLOCK *CreateNetGhost(DPID playerId, int objectId, VECTORCH *position, EULER* orientation, AVP_BEHAVIOUR_TYPE type, unsigned char IOType, unsigned char subtype) +{ + int i; + STRATEGYBLOCK *sbPtr; + MODULE *myContainingModule; + + /* first check that the position we've been passed is in a module */ + myContainingModule = ModuleFromPosition(position, (MODULE *)0); + if(myContainingModule==NULL) return NULL; + + /* create a strategy block */ + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) + { + /* allocation failed */ + return NULL; + } + InitialiseSBValues(sbPtr); + sbPtr->I_SBtype = I_BehaviourNetGhost; + + for(i = 0; i < SB_NAME_LENGTH; i++) sbPtr->SBname[i] = '\0'; + AssignNewSBName(sbPtr); + + /* dynamics block */ + { + DYNAMICSBLOCK *dynPtr; + + /* need different templates for objects and sprites */ + #if EXTRAPOLATION_TEST + if(type==I_BehaviourMarinePlayer||type==I_BehaviourAlienPlayer||type==I_BehaviourPredatorPlayer || type==I_BehaviourAlien) + { + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_MARINE_PLAYER); + if(type==I_BehaviourAlienPlayer || type==I_BehaviourAlien) + { + dynPtr->ToppleForce=TOPPLE_FORCE_ALIEN; + } + } + else + #endif + { + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_NET_GHOST); + } + if(!dynPtr) + { + /* allocation failed */ + RemoveBehaviourStrategy(sbPtr); + return NULL; + } + + sbPtr->DynPtr = dynPtr; + /* zero linear velocity in dynamics block */ + dynPtr->LinVelocity.vx = dynPtr->LinVelocity.vy = dynPtr->LinVelocity.vz = 0; + dynPtr->LinImpulse.vx = dynPtr->LinImpulse.vy = dynPtr->LinImpulse.vz = 0; + dynPtr->GravityOn = 0; + + dynPtr->Position = dynPtr->PrevPosition = *position; + dynPtr->OrientEuler = *orientation; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + + } + + /* data block */ + { + NETGHOSTDATABLOCK *ghostData = AllocateMem(sizeof(NETGHOSTDATABLOCK)); + if(!ghostData) + { + /* allocation failed */ + RemoveBehaviourStrategy(sbPtr); + return NULL; + } + sbPtr->SBdataptr = (void *)ghostData; + ghostData->playerId = playerId; + ghostData->playerObjectId = objectId; + ghostData->type = type; + ghostData->IOType=(INANIMATEOBJECT_TYPE)IOType; + ghostData->subtype=(int)subtype; + ghostData->myGunFlash = NULL; + ghostData->GunFlashFrameStamp=GlobalFrameCounter; + ghostData->SoundHandle = SOUND_NOACTIVEINDEX; + ghostData->SoundHandle2 = SOUND_NOACTIVEINDEX; + ghostData->SoundHandle3 = SOUND_NOACTIVEINDEX; + ghostData->SoundHandle4 = SOUND_NOACTIVEINDEX; + ghostData->currentAnimSequence = 0; + ghostData->timer = 0; + ghostData->CloakingEffectiveness = 0; + ghostData->IgnitionHandshaking = 0; + ghostData->soundStartFlag = 0; + ghostData->FlameHitCount = 0; + ghostData->FlechetteHitCount = 0; + ghostData->invulnerable=0; + ghostData->onlyValidFar=0; + + #if EXTRAPOLATION_TEST + ghostData->velocity.vx=0; + ghostData->velocity.vy=0; + ghostData->velocity.vz=0; + ghostData->extrapTimerLast=0; + ghostData->extrapTimer=0; + #endif + + /* Clear HModelController. */ + ghostData->HModelController.Seconds_For_Sequence=0; + ghostData->HModelController.timer_increment=0; + ghostData->HModelController.Sequence_Type=0; + ghostData->HModelController.Sub_Sequence=0; + ghostData->HModelController.sequence_timer=0; + ghostData->HModelController.FrameStamp=0; + ghostData->HModelController.keyframe_flags=0; + ghostData->HModelController.Deltas=NULL; + ghostData->HModelController.Root_Section=NULL; + ghostData->HModelController.section_data=NULL; + ghostData->HModelController.After_Tweening_Sequence_Type=0; + ghostData->HModelController.After_Tweening_Sub_Sequence=0; + ghostData->HModelController.AT_seconds_for_sequence=0; + ghostData->HModelController.Playing=0; + ghostData->HModelController.Reversed=0; + ghostData->HModelController.Looped=0; + ghostData->HModelController.Tweening=0; + ghostData->HModelController.LoopAfterTweening=0; + ghostData->HModelController.ElevationTweening=0; + /* Whew. */ + ghostData->hltable=0; + /* init the integrity */ + ghostData->integrity = GHOST_INTEGRITY; + + /* set the shape */ + switch(type) + { + case(I_BehaviourMarinePlayer): + { + CreateMarineHModel(ghostData,WEAPON_PULSERIFLE); + ProveHModel_Far(&ghostData->HModelController,sbPtr); + break; + } + case(I_BehaviourAlienPlayer): + { + CreateAlienHModel(ghostData,0); + ProveHModel_Far(&ghostData->HModelController,sbPtr); + break; + } + case(I_BehaviourPredatorPlayer): + { + CreatePredatorHModel(ghostData,WEAPON_PRED_WRISTBLADE); + ProveHModel_Far(&ghostData->HModelController,sbPtr); + break; + } + + /* KJL 16:57:14 17/06/98 - NPC characters */ + case(I_BehaviourAlien): + { + CreateAlienHModel(ghostData,subtype); + + ProveHModel_Far(&ghostData->HModelController,sbPtr); + break; + } + + + case(I_BehaviourGrenade): + case(I_BehaviourPulseGrenade): + sbPtr->shapeIndex = GetLoadedShapeMSL("Shell"); + break; + case(I_BehaviourFragmentationGrenade): + sbPtr->shapeIndex = GetLoadedShapeMSL("Frag"); + break; + case(I_BehaviourClusterGrenade): + sbPtr->shapeIndex = GetLoadedShapeMSL("Cluster"); + break; + case(I_BehaviourRocket): + sbPtr->shapeIndex = GetLoadedShapeMSL("missile"); + break; + case(I_BehaviourPredatorEnergyBolt): + sbPtr->shapeIndex = 0; // uses a special effect + //need to play the energy bolt being fired sound + Sound_Play(SID_PRED_LAUNCHER,"hpd",(FastRandom()&255)-128,&sbPtr->DynPtr->Position); + break; + case(I_BehaviourFrisbeeEnergyBolt): + sbPtr->shapeIndex = 0; // uses a special effect + //need to play the energy bolt being fired sound + Sound_Play(SID_PRED_LAUNCHER,"hpd",(FastRandom()&255)-128,&sbPtr->DynPtr->Position); + break; + case(I_BehaviourPPPlasmaBolt): + sbPtr->shapeIndex = 0; // uses a special effect + break; + case(I_BehaviourNPCPredatorDisc): + case(I_BehaviourPredatorDisc_SeekTrack): + { + + SECTION *root_section = GetNamedHierarchyFromLibrary("disk","Disk"); + + GLOBALASSERT(root_section); + + Create_HModel(&ghostData->HModelController,root_section); + InitHModelSequence(&ghostData->HModelController,HMSQT_MarineStand,MSSS_Minigun_Delta,ONE_FIXED); + ProveHModel_Far(&ghostData->HModelController,sbPtr); + + /* Just to make sure. */ + sbPtr->shapeIndex = GetLoadedShapeMSL("Shell"); + break; + } + case(I_BehaviourFrisbee): + { + + SECTION *root_section = GetNamedHierarchyFromLibrary("mdisk","Mdisk"); + + GLOBALASSERT(root_section); + + Create_HModel(&ghostData->HModelController,root_section); + InitHModelSequence(&ghostData->HModelController,HMSQT_MarineStand,MSSS_Minigun_Delta,(ONE_FIXED>>1)); + ProveHModel_Far(&ghostData->HModelController,sbPtr); + + /* Just to make sure. */ + sbPtr->shapeIndex = GetLoadedShapeMSL("Shell"); + + Sound_Play(SID_ED_SKEETERLAUNCH,"hd",&(sbPtr->DynPtr->Position)); + + break; + } + case(I_BehaviourInanimateObject): + /* That *should* only happen for pred discs at this stage */ + //Now there are also weapons that appear when players die + if(IOType==IOT_Weapon) + { + switch(subtype) + { + case WEAPON_MARINE_PISTOL: + case WEAPON_PULSERIFLE: + sbPtr->shapeIndex=GetLoadedShapeMSL("pulse"); + break; + case WEAPON_SMARTGUN: + sbPtr->shapeIndex=GetLoadedShapeMSL("smart"); + break; + case WEAPON_FLAMETHROWER: + sbPtr->shapeIndex=GetLoadedShapeMSL("flame"); + break; + case WEAPON_SADAR: + sbPtr->shapeIndex=GetLoadedShapeMSL("sadar"); + break; + case WEAPON_GRENADELAUNCHER: + sbPtr->shapeIndex=GetLoadedShapeMSL("grenade"); + break; + case WEAPON_MINIGUN: + sbPtr->shapeIndex=GetLoadedShapeMSL("minigun"); + break; + case WEAPON_FRISBEE_LAUNCHER: + sbPtr->shapeIndex=GetLoadedShapeMSL("sadar"); + break; + default : + GLOBALASSERT(0=="Unexpected weapon type"); + + + } + sbPtr->DynPtr->IsPickupObject=1; + GLOBALASSERT(sbPtr->shapeIndex!=-1); + + } + else + { + SECTION *disc_section; + SECTION *root_section = GetNamedHierarchyFromLibrary("disk","Disk"); + + GLOBALASSERT(IOType==IOT_Ammo); + GLOBALASSERT(subtype==AMMO_PRED_DISC); + GLOBALASSERT(root_section); + + #if 0 + Create_HModel(&ghostData->HModelController,root_section); + InitHModelSequence(&ghostData->HModelController,HMSQT_MarineStand,MSSS_Minigun_Delta,ONE_FIXED); + ProveHModel_Far(&ghostData->HModelController,sbPtr); + + /* Just to make sure. */ + sbPtr->shapeIndex = GetLoadedShapeMSL("Shell"); + #else + /* Now it's not hierarchical! */ + disc_section=GetThisSection(root_section,"disk"); + GLOBALASSERT(disc_section); + + sbPtr->shapeIndex = disc_section->ShapeNum; + #endif + } + break; + + case(I_BehaviourFlareGrenade): + sbPtr->shapeIndex = GetLoadedShapeMSL("Flare"); + ghostData->timer = FLARE_LIFETIME*ONE_FIXED; + break; + case(I_BehaviourProximityGrenade): + sbPtr->shapeIndex = GetLoadedShapeMSL("Proxmine"); + ghostData->timer = PROX_GRENADE_LIFETIME*ONE_FIXED*2; + break; + case(I_BehaviourAlienSpit): + sbPtr->shapeIndex = GetLoadedShapeMSL("Spit"); + break; + case(I_BehaviourAutoGun): + sbPtr->shapeIndex = GetLoadedShapeMSL("Sentry01"); + break; + case(I_BehaviourSpeargunBolt): + sbPtr->shapeIndex = GetLoadedShapeMSL("spear"); + //speargun bolt won't get any location updates , so set integrity + //to be the standard speargun timeout time. + ghostData->integrity = 20*ONE_FIXED; + + //play the sound for the bolt as well + Sound_Play(SID_SPEARGUN_HITTING_WALL,"d",&sbPtr->DynPtr->Position); + //and make the sparks + { + VECTORCH pos = sbPtr->DynPtr->Position; + pos.vx += sbPtr->DynPtr->OrientMat.mat31; + pos.vy += sbPtr->DynPtr->OrientMat.mat32; + pos.vz += sbPtr->DynPtr->OrientMat.mat33; + MakeFocusedExplosion(&(sbPtr->DynPtr->Position), &pos, 20, PARTICLE_SPARK); + } + + break; + default: + break; + } + LOCALASSERT(sbPtr->shapeIndex!=-1); + + } + + /* strategy block initialisation, after dynamics block creation */ + sbPtr->maintainVisibility = 1; + sbPtr->containingModule = myContainingModule; + + return sbPtr; +} + +int UseExtrapolation=1; +#if EXTRAPOLATION_TEST +void PlayerGhostExtrapolation() +{ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + + int sbIndex = 0; + STRATEGYBLOCK *sbPtr; + + + //search for all ghosts of players + while(sbIndex < NumActiveStBlocks) + { + sbPtr = ActiveStBlockList[sbIndex++]; + if(sbPtr->I_SBtype==I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + if(ghostData->type==I_BehaviourMarinePlayer || + ghostData->type==I_BehaviourAlienPlayer || + ghostData->type==I_BehaviourAlien || + ghostData->type==I_BehaviourPredatorPlayer) + { + int time; + DYNAMICSBLOCK* dynPtr= sbPtr->DynPtr; + if(ghostData->onlyValidFar) continue; + + if(UseExtrapolation) + { + + dynPtr->LinVelocity.vx=0; + dynPtr->LinVelocity.vy=0; + dynPtr->LinVelocity.vz=0; + + dynPtr->IsNetGhost=0; + + ghostData->extrapTimer+=NormalFrameTime; + if(ghostData->extrapTimer<0) ghostData->extrapTimer=0; + if(ghostData->extrapTimer>ONE_FIXED/2) ghostData->extrapTimer=ONE_FIXED/2; + + time=ghostData->extrapTimer-ghostData->extrapTimerLast; + ghostData->extrapTimerLast=ghostData->extrapTimer; + + if(ghostData->velocity.vx==0 && ghostData->velocity.vy==0 && ghostData->velocity.vz==0) + { + /* + Not moving , so alter the dynamics block settings to match those of a non-extrapolated + net ghost. + */ + dynPtr->LinImpulse.vx=0; + dynPtr->LinImpulse.vy=0; + dynPtr->LinImpulse.vz=0; + + ghostData->extrapTimerLast=ghostData->extrapTimer=0; + dynPtr->IsNetGhost=1; + dynPtr->UseStandardGravity=1; + sbPtr->DynPtr->ToppleForce=TOPPLE_FORCE_NONE; + } + else if(time>0) + { + dynPtr->LinVelocity=ghostData->velocity; + if(time!=NormalFrameTime) + { + //only doing interpolation for a fraction of a frame + //so we need to scale the velocity accordingly + dynPtr->LinVelocity.vx=WideMulNarrowDiv(dynPtr->LinVelocity.vx,time,NormalFrameTime); + dynPtr->LinVelocity.vy=WideMulNarrowDiv(dynPtr->LinVelocity.vy,time,NormalFrameTime); + dynPtr->LinVelocity.vz=WideMulNarrowDiv(dynPtr->LinVelocity.vz,time,NormalFrameTime); + } + } + + + /* + if(sbPtr->SBdptr) + { + sbPtr->SBdptr->ObRadius=1200; + } + */ + + } + else + { + //not using extrapolation , so make sure dynamics block + //contains normal ghost settings + dynPtr->LinImpulse.vx=0; + dynPtr->LinImpulse.vy=0; + dynPtr->LinImpulse.vz=0; + + dynPtr->LinVelocity.vx=0; + dynPtr->LinVelocity.vy=0; + dynPtr->LinVelocity.vz=0; + + dynPtr->UseStandardGravity=1; + + dynPtr->IsNetGhost=1; + + sbPtr->DynPtr->ToppleForce=TOPPLE_FORCE_NONE; + } + } + } + } +} + +void PostDynamicsExtrapolationUpdate() +{ + extern DPID MultiplayerObservedPlayer; + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + + int sbIndex = 0; + STRATEGYBLOCK *sbPtr; + + if(!UseExtrapolation) return; + + //search for all ghosts of players + while(sbIndex < NumActiveStBlocks) + { + sbPtr = ActiveStBlockList[sbIndex++]; + if(sbPtr->I_SBtype==I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + if(ghostData->type==I_BehaviourMarinePlayer || + ghostData->type==I_BehaviourAlienPlayer || + ghostData->type==I_BehaviourPredatorPlayer) + { + if(ghostData->myGunFlash) + { + HandleGhostGunFlashEffect(sbPtr, 3); + } + //are we currently following this player's movements + if(MultiplayerObservedPlayer) + { + if(MultiplayerObservedPlayer==ghostData->playerId) + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + Player->ObStrategyBlock->DynPtr->Position=sbPtr->DynPtr->Position; + Player->ObStrategyBlock->DynPtr->PrevPosition=sbPtr->DynPtr->Position; + + Player->ObStrategyBlock->DynPtr->OrientEuler = sbPtr->DynPtr->OrientEuler; + CreateEulerMatrix(&Player->ObStrategyBlock->DynPtr->OrientEuler,&Player->ObStrategyBlock->DynPtr->OrientMat); + TransposeMatrixCH(&Player->ObStrategyBlock->DynPtr->OrientMat); + + } + } + } + } + } +} +#endif //EXTRAPOLATION_TEST + +extern HIERARCHY_VARIANT_DATA* GetHierarchyAlternateShapeSetCollectionFromLibrary(const char* rif_name,int index); +void ChangeGhostMarineAccoutrementSet(HMODELCONTROLLER *HModelController,DPID playerId) +{ + + HIERARCHY_VARIANT_DATA* variant_data; + HIERARCHY_SHAPE_REPLACEMENT* replacement_array; + int index=0; + int a; + + LOCALASSERT(HModelController); + + //find the index for this player + if(playerId) + { + for(index=0;index<(NET_MAXPLAYERS);index++) + { + if(netGameData.playerData[index].playerId==playerId) + { + break; + } + } + } + + variant_data=GetHierarchyAlternateShapeSetCollectionFromLibrary("hnpcmarine",index+1); + + if (variant_data==NULL) { + return; + } + + + replacement_array=(HIERARCHY_SHAPE_REPLACEMENT*)variant_data->replacements; + + if (replacement_array==NULL) { + return; + } + + + a=0; + + while (replacement_array[a].replaced_section_name!=NULL) + { + SECTION_DATA *target_section; + + target_section=GetThisSectionData(HModelController->section_data, + replacement_array[a].replaced_section_name); + if (target_section) { + target_section->Shape=replacement_array[a].replacement_shape; + #if 1 + target_section->ShapeNum=replacement_array[a].replacement_shape_index; + #endif + + Setup_Texture_Animation_For_Section(target_section); + + } + a++; + } + +} + +void CreateMarineHModel(NETGHOSTDATABLOCK *ghostDataPtr, int weapon) +{ + SECTION *root_section; + + /* KJL 11:09:14 27/01/98 - pick which model to create based on the character's weapon */ + switch (weapon) + { + default: + case WEAPON_PULSERIFLE: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","marine with pulse rifle"); + break; + } + case WEAPON_TWO_PISTOLS: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","Two Pistol"); + break; + } + case WEAPON_MARINE_PISTOL: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","PISTOL"); + break; + } + case WEAPON_FLAMETHROWER: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","marine with flame thrower"); + break; + } + case WEAPON_SMARTGUN: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","marine with smart gun"); + break; + } + case WEAPON_MINIGUN: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","Marine with Mini Gun"); + break; + } + case WEAPON_SADAR: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","marine with SADAR"); + break; + } + case WEAPON_GRENADELAUNCHER: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","marine + grenade launcher"); + break; + } + case WEAPON_CUDGEL: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","Cudgel"); + break; + } + case WEAPON_FRISBEE_LAUNCHER: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","skeeter"); + break; + } + } + Create_HModel(&ghostDataPtr->HModelController,root_section); + ghostDataPtr->CurrentWeapon = weapon; + + ChangeGhostMarineAccoutrementSet(&ghostDataPtr->HModelController,ghostDataPtr->playerId); + + /* KJL 11:09:38 27/01/98 - set a default anim sequence to use */ + ghostDataPtr->currentAnimSequence = MSQ_Stand; + InitHModelSequence(&ghostDataPtr->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Standard,ONE_FIXED); + + /* KJL 11:09:52 27/01/98 - find the section which hold the muzzle flash data */ + ghostDataPtr->GunflashSectionPtr=GetThisSectionData(ghostDataPtr->HModelController.section_data,"dum flash"); + GLOBALASSERT(ghostDataPtr->GunflashSectionPtr); + + /* CDF 8/4/98 Elevation Delta Sequence. */ + { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&ghostDataPtr->HModelController,"Elevation",(int)HMSQT_MarineStand,(int)MSSS_Elevation,0); + GLOBALASSERT(delta); + delta->timer=32767; + } + //add hit delta + if (HModelSequence_Exists(&ghostDataPtr->HModelController,(int)HMSQT_MarineStand,(int)MSSS_HitChestFront)) + { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&ghostDataPtr->HModelController,"HitDelta",(int)HMSQT_MarineStand,(int)MSSS_HitChestFront,(ONE_FIXED>>2)); + GLOBALASSERT(delta); + delta->Playing=0; + } + + ghostDataPtr->hltable=(HITLOCATIONTABLE*)GetThisHitLocationTable("marine with pulse rifle"); + +} +void CreateAlienHModel(NETGHOSTDATABLOCK *ghostDataPtr,int alienType) +{ + SECTION *root_section; + + switch(alienType) + { + case AT_Predalien : + root_section=GetNamedHierarchyFromLibrary("hnpcpred_alien","TEMPLATE"); + ghostDataPtr->hltable=GetThisHitLocationTable("predalien"); + break; + case AT_Praetorian : + root_section=GetNamedHierarchyFromLibrary("hnpcpretorian","Template"); + ghostDataPtr->hltable=GetThisHitLocationTable("praetorian"); + break; + default : + root_section = GetNamedHierarchyFromLibrary("hnpcalien","alien"); + ghostDataPtr->hltable=GetThisHitLocationTable("alien"); + break; + } + + + Create_HModel(&ghostDataPtr->HModelController,root_section); + ghostDataPtr->currentAnimSequence = ASQ_Stand; + InitHModelSequence(&ghostDataPtr->HModelController,(int)HMSQT_AlienStand,(int)ASSS_Standard,ONE_FIXED); + + ghostDataPtr->CurrentWeapon = 0; + + /* CDF 12/4/98 Elevation Delta Sequence. */ + { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&ghostDataPtr->HModelController,"Elevation",(int)HMSQT_AlienStand,(int)ASSS_Standard_Elevation,0); + GLOBALASSERT(delta); + delta->timer=32767; + + delta->Active=0; /* Default for predator. */ + } +} +void CreatePredatorHModel(NETGHOSTDATABLOCK *ghostDataPtr, int weapon) +{ + SECTION *root_section; + /* KJL 11:09:14 27/01/98 - pick which model to create based on the character's weapon */ + switch (weapon) + { + default: + case WEAPON_PRED_WRISTBLADE: + { + root_section = GetNamedHierarchyFromLibrary("hnpcpredator","pred with wristblade"); + break; + } + case WEAPON_PRED_STAFF: + { + root_section = GetNamedHierarchyFromLibrary("hnpcpredator","pred with staff"); + break; + } + case WEAPON_PRED_RIFLE: + { + root_section = GetNamedHierarchyFromLibrary("hnpcpredator","Speargun"); + break; + } + case WEAPON_PRED_PISTOL: + { + root_section = GetNamedHierarchyFromLibrary("hnpcpredator","pred + pistol"); + break; + } + case WEAPON_PRED_SHOULDERCANNON: + { + root_section = GetNamedHierarchyFromLibrary("hnpcpredator","pred with Plasma Caster"); + break; + } + case WEAPON_PRED_DISC: + { + root_section = GetNamedHierarchyFromLibrary("hnpcpredator","pred with disk"); + break; + } + case WEAPON_PRED_MEDICOMP: + { + root_section = GetNamedHierarchyFromLibrary("hnpcpredator","medicomp"); + break; + } + + /* + WEAPON_PRED_RIFLE, + , + */ + } + + Create_HModel(&ghostDataPtr->HModelController,root_section); + ghostDataPtr->CurrentWeapon = weapon; + + GLOBALASSERT(ghostDataPtr->HModelController.Root_Section==root_section); + + InitHModelSequence(&ghostDataPtr->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_Standard,ONE_FIXED); + ghostDataPtr->currentAnimSequence = PredSQ_Stand; + +// ghostDataPtr->GunflashSectionPtr=GetThisSectionData(ghostDataPtr->HModelController.section_data,"dum flash"); +// GLOBALASSERT(ghostDataPtr->GunflashSectionPtr); + + /* CDF 11/4/98 Elevation Delta Sequence. */ + { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&ghostDataPtr->HModelController,"Elevation",(int)HMSQT_PredatorStand,(int)PSSS_Elevation,0); + GLOBALASSERT(delta); + delta->timer=32767; + + delta->Active=0; /* Default for predator. */ + } + + if (HModelSequence_Exists(&ghostDataPtr->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront)) + { + DELTA_CONTROLLER *delta; + delta=Add_Delta_Sequence(&ghostDataPtr->HModelController,"HitDelta",(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront,-1); + GLOBALASSERT(delta); + delta->Playing=0; + } + ghostDataPtr->hltable=GetThisHitLocationTable("predator"); +} + + +/* these functions are called directly by the visibility management system */ +void MakeGhostNear(STRATEGYBLOCK *sbPtr) +{ + extern MODULEMAPBLOCK AlienDefaultMap; + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + MODULE tempModule; + DISPLAYBLOCK *dPtr; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + SFXBLOCK *sfxPtr=0; + + LOCALASSERT(ghostData); + + /* KJL 11:56:09 08/05/98 - if shape doesn't exist, use a sfx */ + if ( (ghostData->type==I_BehaviourPredatorEnergyBolt) + ||(ghostData->type==I_BehaviourFrisbeeEnergyBolt) + ||(ghostData->type==I_BehaviourPPPlasmaBolt) ) + { + sfxPtr = AllocateSfxBlock(); + // if we haven't got a free sfx block, return */ + if (!sfxPtr) return; + } + + if(ghostData->onlyValidFar) + { + //Far alien ai , don't have enough information to make it near + return; + } + + LOCALASSERT(dynPtr); + LOCALASSERT(sbPtr->SBdptr == NULL); + + AlienDefaultMap.MapShape = sbPtr->shapeIndex; + tempModule.m_mapptr = &AlienDefaultMap; + tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; + tempModule.m_numlights = 0; + tempModule.m_lightarray = (struct lightblock *)0; + tempModule.m_extraitemdata = (struct extraitemdata *)0; + tempModule.m_dptr = NULL; /* this is important */ + AllocateModuleObject(&tempModule); + dPtr = tempModule.m_dptr; + if(dPtr==NULL) return; /* cannot create displayblock, so leave object "far" */ + + + sbPtr->SBdptr = dPtr; + dPtr->ObStrategyBlock = sbPtr; + dPtr->ObMyModule = NULL; + dPtr->HModelControlBlock=NULL; + + /* set the animation sequence, if we're a player ghost */ + if(ghostData->playerObjectId==GHOST_PLAYEROBJECTID) + { + LOCALASSERT((ghostData->type == I_BehaviourMarinePlayer)|| + (ghostData->type == I_BehaviourPredatorPlayer)|| + (ghostData->type == I_BehaviourAlienPlayer)); + + dPtr->HModelControlBlock=&ghostData->HModelController; + ProveHModel(dPtr->HModelControlBlock,dPtr); + } + else if ( + (ghostData->type == I_BehaviourAlien)|| + (ghostData->type == I_BehaviourPredatorDisc_SeekTrack)|| + (ghostData->type == I_BehaviourFrisbee)|| + (ghostData->type == I_BehaviourNetCorpse) + ) { + dPtr->HModelControlBlock=&ghostData->HModelController; + ProveHModel(dPtr->HModelControlBlock,dPtr); + } + + else dPtr->ShapeAnimControlBlock = NULL; + + /* need to initialise positional information in the new display block */ + dPtr->ObWorld = dynPtr->Position; + dPtr->ObEuler = dynPtr->OrientEuler; + dPtr->ObMat = dynPtr->OrientMat; + dPtr->SfxPtr = sfxPtr; + + /* finally, need to add lighting effects to the displayblock */ + switch(ghostData->type) + { + case(I_BehaviourPulseGrenade): + case(I_BehaviourRocket): + { + AddLightingEffectToObject(dPtr,LFX_ROCKETJET); + break; + } + case(I_BehaviourPredatorEnergyBolt): + { + sfxPtr->SfxID = SFX_PREDATOR_PLASMA_BOLT; + AddLightingEffectToObject(dPtr,LFX_PLASMA_BOLT); + break; + } + case(I_BehaviourFrisbeeEnergyBolt): + { + sfxPtr->SfxID = SFX_FRISBEE_PLASMA_BOLT; + AddLightingEffectToObject(dPtr,LFX_PLASMA_BOLT); + break; + } + case(I_BehaviourPPPlasmaBolt): + { + sfxPtr->SfxID = SFX_SMALL_PREDATOR_PLASMA_BOLT; + AddLightingEffectToObject(dPtr,LFX_PLASMA_BOLT); + break; + } + + case(I_BehaviourFlareGrenade): + { + AddLightingEffectToObject(dPtr,LFX_FLARE); + + break; + } + default: + break; + } +} + +void MakeGhostFar(STRATEGYBLOCK *sbPtr) +{ + int i; + LOCALASSERT(sbPtr->SBdptr != NULL); + + /* get rid of the displayblock */ + i = DestroyActiveObject(sbPtr->SBdptr); + LOCALASSERT(i==0); + sbPtr->SBdptr = NULL; +} + +/* this function handles damage to a netghost object: +basically, it just sends a network message, which should be picked up by the owning object */ +void DamageNetworkGhost(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, SECTION_DATA *section,VECTORCH* incoming) +{ + int sectionID; + int delta_seq=-1; + int delta_sub_seq=-1; + + LOCALASSERT(AvP.Network!=I_No_Network); + + if(section) + { + //get the appropriate delta sequence + NETGHOSTDATABLOCK *ghostData; + int frontback; + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + + if(ghostData->type==I_BehaviourMarinePlayer) + { + int CrouchSubSequence; + int StandSubSequence; + + if (incoming) { + if (incoming->vz>=0) { + frontback=0; + } else { + frontback=1; + } + } else { + /* Default to front. */ + frontback=1; + } + + + if (section==NULL) + { + if (frontback==0) + { + CrouchSubSequence=MCrSS_HitChestBack; + StandSubSequence=MSSS_HitChestBack; + } + else + { + CrouchSubSequence=MCrSS_HitChestFront; + StandSubSequence=MSSS_HitChestFront; + } + } else if (section->sempai->flags§ion_flag_head) + { + if (frontback==0) + { + CrouchSubSequence=MCrSS_HitHeadBack; + StandSubSequence=MSSS_HitHeadBack; + } + else + { + CrouchSubSequence=MCrSS_HitHeadFront; + StandSubSequence=MSSS_HitHeadFront; + } + } else if ((section->sempai->flags§ion_flag_left_arm) + ||(section->sempai->flags§ion_flag_left_hand)) + { + if (frontback==0) + { + CrouchSubSequence=MCrSS_HitRightArm; + StandSubSequence=MSSS_HitRightArm; + } + else + { + CrouchSubSequence=MCrSS_HitLeftArm; + StandSubSequence=MSSS_HitLeftArm; + } + } else if ((section->sempai->flags§ion_flag_right_arm) + ||(section->sempai->flags§ion_flag_right_hand)) + { + if (frontback==0) + { + CrouchSubSequence=MCrSS_HitLeftArm; + StandSubSequence=MSSS_HitLeftArm; + } + else + { + CrouchSubSequence=MCrSS_HitRightArm; + StandSubSequence=MSSS_HitRightArm; + } + + } else if ((section->sempai->flags§ion_flag_left_leg) + ||(section->sempai->flags§ion_flag_left_foot)) + { + CrouchSubSequence=MCrSS_HitLeftLeg; + StandSubSequence=MSSS_HitLeftLeg; + + } else if ((section->sempai->flags§ion_flag_right_leg) + ||(section->sempai->flags§ion_flag_right_foot)) + { + CrouchSubSequence=MCrSS_HitRightLeg; + StandSubSequence=MSSS_HitRightLeg; + + } else { + /* Chest or misc. hit. */ + if (frontback==0) { + CrouchSubSequence=MCrSS_HitChestBack; + StandSubSequence=MSSS_HitChestBack; + } else { + CrouchSubSequence=MCrSS_HitChestFront; + StandSubSequence=MSSS_HitChestFront; + } + } + + if(ghostData->currentAnimSequence==MSQ_Crawl || + ghostData->currentAnimSequence==MSQ_Crawl_Backwards || + ghostData->currentAnimSequence==MSQ_Crouch) + { + delta_seq=(int)HMSQT_MarineCrouch; + delta_sub_seq=(int)CrouchSubSequence; + } + else + { + delta_seq=(int)HMSQT_MarineStand; + delta_sub_seq=(int)StandSubSequence; + } + + PlayHitDeltaOnGhost(sbPtr,delta_seq,delta_sub_seq); + } + else if(ghostData->type==I_BehaviourPredatorPlayer) + { + int CrouchSubSequence; + int StandSubSequence; + + if (incoming) { + if (incoming->vz>=0) { + frontback=0; + } else { + frontback=1; + } + } else { + /* Default to front. */ + frontback=1; + } + + if (section==NULL) + { + if (frontback==0) + { + CrouchSubSequence=PCrSS_HitChestBack; + StandSubSequence=PSSS_HitChestBack; + } + else + { + CrouchSubSequence=PCrSS_HitChestFront; + StandSubSequence=PSSS_HitChestFront; + } + } else if (section->sempai->flags§ion_flag_head) + { + if (frontback==0) + { + CrouchSubSequence=PCrSS_HitHeadBack; + StandSubSequence=PSSS_HitHeadBack; + } + else + { + CrouchSubSequence=PCrSS_HitHeadFront; + StandSubSequence=PSSS_HitHeadFront; + } + } else if ((section->sempai->flags§ion_flag_left_arm) + ||(section->sempai->flags§ion_flag_left_hand)) + { + if (frontback==0) + { + CrouchSubSequence=PCrSS_HitRightArm; + StandSubSequence=PSSS_HitRightArm; + } + else + { + CrouchSubSequence=PCrSS_HitLeftArm; + StandSubSequence=PSSS_HitLeftArm; + } + + } else if ((section->sempai->flags§ion_flag_right_arm) + ||(section->sempai->flags§ion_flag_right_hand)) + { + if (frontback==0) + { + CrouchSubSequence=PCrSS_HitLeftArm; + StandSubSequence=PSSS_HitLeftArm; + } + else + { + CrouchSubSequence=PCrSS_HitRightArm; + StandSubSequence=PSSS_HitRightArm; + } + + } else if ((section->sempai->flags§ion_flag_left_leg) + ||(section->sempai->flags§ion_flag_left_foot)) { + CrouchSubSequence=PCrSS_HitLeftLeg; + StandSubSequence=PSSS_HitLeftLeg; + + } else if ((section->sempai->flags§ion_flag_right_leg) + ||(section->sempai->flags§ion_flag_right_foot)) { + CrouchSubSequence=PCrSS_HitRightLeg; + StandSubSequence=PSSS_HitRightLeg; + } else { + /* Chest or misc. hit. */ + if (frontback==0) { + CrouchSubSequence=PCrSS_HitChestBack; + StandSubSequence=PSSS_HitChestBack; + } else { + CrouchSubSequence=PCrSS_HitChestFront; + StandSubSequence=PSSS_HitChestFront; + } + } + + + if(ghostData->currentAnimSequence==PredSQ_Crawl || + ghostData->currentAnimSequence==PredSQ_Crawl_Backwards || + ghostData->currentAnimSequence==PredSQ_Crouch || + ghostData->currentAnimSequence==PredSQ_CrouchedSwipe || + ghostData->currentAnimSequence==PredSQ_CrawlingSwipe || + ghostData->currentAnimSequence==PredSQ_CrawlingSwipe_Backwards) + + { + delta_seq=(int)HMSQT_PredatorCrouch; + delta_sub_seq=(int)CrouchSubSequence; + } + else + { + delta_seq=(int)HMSQT_PredatorStand; + delta_sub_seq=(int)StandSubSequence; + } + + PlayHitDeltaOnGhost(sbPtr,delta_seq,delta_sub_seq); + + } + + } + + if (section) { + sectionID=section->sempai->IDnumber; + } else { + sectionID=-1; + } + AddNetMsg_LocalObjectDamaged(sbPtr, damage, multiple,sectionID,delta_seq,delta_sub_seq,incoming); +} + +/* This function maintains a player ghost's gunflash effect, and is called from +processmsg_playerstate(). It maintains the ghost given by index, and takes as a +parameter the state of the net-player's muzzle flash, as indicated in the last +network message. It */ +void HandleGhostGunFlashEffect(STRATEGYBLOCK *sbPtr, int gunFlashOn) +{ + NETGHOSTDATABLOCK *ghostData; + + LOCALASSERT(sbPtr); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + /* aliens shouldn't have gun flashes */ + if((ghostData->type == I_BehaviourAlienPlayer) + ||(ghostData->type == I_BehaviourPredatorPlayer)) + { + ghostData->myGunFlash = NULL; + return; + } + + LOCALASSERT((ghostData->type == I_BehaviourMarinePlayer)|| + (ghostData->type == I_BehaviourPredatorPlayer)); + + //ReleasePrintDebuggingText("Muzzle Flash %d\n",gunFlashOn); + + /* Handle two pistols? */ + if (ghostData->type == I_BehaviourMarinePlayer) { + if (gunFlashOn==2) { + ghostData->GunflashSectionPtr=GetThisSectionData(ghostData->HModelController.section_data,"dum L flash"); + if (ghostData->GunflashSectionPtr==NULL) { + ghostData->GunflashSectionPtr=GetThisSectionData(ghostData->HModelController.section_data,"dum flash"); + } + } else if (gunFlashOn==1) { + ghostData->GunflashSectionPtr=GetThisSectionData(ghostData->HModelController.section_data,"dum flash"); + } else if (gunFlashOn==3) { + /* Extrapolation. */ + } + } + + if(ghostData->myGunFlash) + { + /* I've already got a gun flash... */ + if(gunFlashOn) + { + /* Maintain existing gun flash */ + LOCALASSERT(ghostData->GunflashSectionPtr); + + if (sbPtr->SBdptr) + { + ProveHModel(&ghostData->HModelController,sbPtr->SBdptr); + MaintainNPCGunFlashEffect + ( + ghostData->myGunFlash, + &ghostData->GunflashSectionPtr->World_Offset, + &ghostData->GunflashSectionPtr->SecMat + ); + } + } + else + { + if (ghostData->GunFlashFrameStamp!=GlobalFrameCounter) { + /* Maintain for at least one frame. */ + RemoveNPCGunFlashEffect(ghostData->myGunFlash); + ghostData->myGunFlash = NULL; + } + } + } + else + { + if(gunFlashOn) + { + /* new flash */ + LOCALASSERT(ghostData->GunflashSectionPtr); + ghostData->GunFlashFrameStamp=GlobalFrameCounter; + if (sbPtr->SBdptr) + { + ProveHModel(&ghostData->HModelController,sbPtr->SBdptr); + + if (ghostData->CurrentWeapon==WEAPON_SMARTGUN) + { + ghostData->myGunFlash = AddNPCGunFlashEffect + ( + &ghostData->GunflashSectionPtr->World_Offset, + &ghostData->GunflashSectionPtr->SecMat, + SFX_MUZZLE_FLASH_SMARTGUN + ); + } + else if (ghostData->CurrentWeapon==WEAPON_FRISBEE_LAUNCHER) + { + ghostData->myGunFlash = AddNPCGunFlashEffect + ( + &ghostData->GunflashSectionPtr->World_Offset, + &ghostData->GunflashSectionPtr->SecMat, + SFX_MUZZLE_FLASH_SKEETER + ); + } + else + { + ghostData->myGunFlash = AddNPCGunFlashEffect + ( + &ghostData->GunflashSectionPtr->World_Offset, + &ghostData->GunflashSectionPtr->SecMat, + SFX_MUZZLE_FLASH_AMORPHOUS + ); + } + } + } + } + #if 0 + /* KJL 15:32:57 13/05/98 - Tracer code - isn't working too well */ + if(ghostData->GunflashSectionPtr && !(FastRandom()&15)) + { + VECTORCH endPosition = ghostData->GunflashSectionPtr->World_Offset; + endPosition.vx += ghostData->GunflashSectionPtr->SecMat.mat31>>3; + endPosition.vy += ghostData->GunflashSectionPtr->SecMat.mat32>>3; + endPosition.vz += ghostData->GunflashSectionPtr->SecMat.mat33>>3; + MakeParticle(&(ghostData->GunflashSectionPtr->World_Offset),&endPosition,PARTICLE_TRACER); + } + #endif + +} + + +/* Patrick 14/7/97 ----------------------------------------------------------- +Shape animation control functions for player ghosts: + +Init initilaises the character sequence, and should only be called when a new +player ghost is created, after the sb and datablock have been set up. + +Update changes the sequence if appropriate (and calls set if the sbPtr has a dptr) + +Set selects the correct sequence/type, infers the speed and follow-on sequences, +etc, and sets it. +------------------------------------------------------------------------------*/ +static void InitPlayerGhostAnimSequence(STRATEGYBLOCK *sbPtr) +{ + NETGHOSTDATABLOCK *ghostData; + AVP_BEHAVIOUR_TYPE type; + + LOCALASSERT(sbPtr); + LOCALASSERT(!(sbPtr->SBdptr)); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + type = ghostData->type; + + InitShapeAnimationController(&ghostData->ShpAnimCtrl, GetShapeData(sbPtr->shapeIndex)); + switch(type) + { + case(I_BehaviourMarinePlayer): + { + ghostData->currentAnimSequence = MSQ_Stand; + break; + } + case(I_BehaviourAlienPlayer): + { + ghostData->currentAnimSequence = ASQ_Stand; + break; + } + case(I_BehaviourPredatorPlayer): + { + ghostData->currentAnimSequence = PredSQ_Stand; + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } +} + +static void UpdatePlayerGhostAnimSequence(STRATEGYBLOCK *sbPtr, int sequence, int special) +{ + NETGHOSTDATABLOCK *ghostData; + + LOCALASSERT(sbPtr); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + switch(ghostData->type) + { + case(I_BehaviourMarinePlayer): + { + //ReleasePrintDebuggingText("Update Marine with Special %d\n",special); + /* if the current sequence is the same as the new sequence, do nothing */ + if (((MARINE_SEQUENCE)ghostData->currentAnimSequence == (MARINE_SEQUENCE)sequence) + &&(ghostData->CurrentWeapon!=WEAPON_TWO_PISTOLS) + &&(!((ghostData->CurrentWeapon==WEAPON_MARINE_PISTOL)&&(special))) + ) { + return; + } + /* if we're dead, and passed dying, do nothing */ + if(((MARINE_SEQUENCE)ghostData->currentAnimSequence == MSQ_StandDeadFront)&& + ((MARINE_SEQUENCE)sequence == MSQ_StandDieFront)) return; + if(((MARINE_SEQUENCE)ghostData->currentAnimSequence == MSQ_CrouchDead)&& + ((MARINE_SEQUENCE)sequence == MSQ_CrouchDie)) return; + /* need to update the anim sequence, then*/ + SetPlayerGhostAnimationSequence(sbPtr, sequence, special); + break; + } + case(I_BehaviourAlienPlayer): + { + /* if the current sequence is the same as the new sequence, do nothing */ + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) + { + if((ALIEN_SEQUENCE)ghostData->currentAnimSequence == (ALIEN_SEQUENCE)sequence) + { + if(ghostData->currentAnimSequence==ASQ_RunningAttack_Claw || + ghostData->currentAnimSequence==ASQ_RunningTailStrike || + ghostData->currentAnimSequence==ASQ_RunningAttack_Claw_Backwards || + ghostData->currentAnimSequence==ASQ_RunningTailStrike_Backwards || + ghostData->currentAnimSequence==ASQ_CrawlingAttack_Claw || + ghostData->currentAnimSequence==ASQ_CrawlingAttack_Claw_Backwards || + ghostData->currentAnimSequence==ASQ_CrawlingTailStrike || + ghostData->currentAnimSequence==ASQ_CrawlingTailStrike_Backwards) + { + ghostData->HModelController.Looped=1; + ghostData->HModelController.LoopAfterTweening=1; + } + + #if 0 + if(ghostData->currentAnimSequence==ASQ_RunningAttack_Claw || + ghostData->currentAnimSequence==ASQ_RunningTailStrike || + ghostData->currentAnimSequence==ASQ_RunningAttack_Claw_Backwards || + ghostData->currentAnimSequence==ASQ_RunningTailStrike_Backwards || + ghostData->currentAnimSequence==ASQ_CrawlingAttack_Claw || + ghostData->currentAnimSequence==ASQ_CrawlingAttack_Claw_Backwards || + ghostData->currentAnimSequence==ASQ_CrawlingTailStrike || + ghostData->currentAnimSequence==ASQ_CrawlingTailStrike_Backwards || + ghostData->currentAnimSequence==ASQ_Run || + ghostData->currentAnimSequence==ASQ_RunningTailPoise || + ghostData->currentAnimSequence==ASQ_Run_Backwards || + ghostData->currentAnimSequence==ASQ_RunningTailPoise_Backwards || + ghostData->currentAnimSequence==ASQ_Crawl || + ghostData->currentAnimSequence==ASQ_Scamper || + ghostData->currentAnimSequence==ASQ_CrawlingTailPoise || + ghostData->currentAnimSequence==ASQ_Crawl_Backwards || + ghostData->currentAnimSequence==ASQ_Scamper_Backwards || + ghostData->currentAnimSequence==ASQ_CrawlingTailPoise_Backwards) + + { + if(ghostData->HModelController.Tweening==Controller_NoTweening) + { + HModel_SetToolsRelativeSpeed(&ghostData->HModelController,(512*ONE_FIXED)/18000/*ALIEN_MOVESCALE*/); + } + } + #endif + + + return; + } + } + /* need to update the anim sequence, then*/ + SetPlayerGhostAnimationSequence(sbPtr, sequence, special); + break; + } + case(I_BehaviourPredatorPlayer): + { + /* if the current sequence is the same as the new sequence, do nothing */ + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) + { + if(ghostData->currentAnimSequence == sequence) + { + if(ghostData->currentAnimSequence==PredSQ_RunningSwipe || + ghostData->currentAnimSequence==PredSQ_RunningSwipe_Backwards || + ghostData->currentAnimSequence==PredSQ_CrawlingSwipe || + ghostData->currentAnimSequence==PredSQ_CrawlingSwipe_Backwards) + { + ghostData->HModelController.Looped=1; + ghostData->HModelController.LoopAfterTweening=1; + } + return; + } + } + /* if we're dead, and passed dying, do nothing */ + if(((PREDATOR_SEQUENCE)ghostData->currentAnimSequence == PredSQ_StandDead)&& + ((PREDATOR_SEQUENCE)sequence == PredSQ_StandDie)) return; + if(((PREDATOR_SEQUENCE)ghostData->currentAnimSequence == PredSQ_CrouchDead)&& + ((PREDATOR_SEQUENCE)sequence == PredSQ_CrouchDie)) return; + /* need to update the anim sequence, then*/ + SetPlayerGhostAnimationSequence(sbPtr, sequence, special); + break; + } + + case(I_BehaviourAlien): + { + /* if the current sequence is the same as the new sequence, do nothing */ + + if(ghostData->currentAnimSequence == sequence) return; + + /* need to update the anim sequence, then*/ + SetPlayerGhostAnimationSequence(sbPtr, sequence, special); + break; + } + + + default: + { + LOCALASSERT(1==0); + break; + } + } +} + +static void SetPlayerGhostAnimationSequence(STRATEGYBLOCK *sbPtr, int sequence, int special) +{ + NETGHOSTDATABLOCK *ghostData; + AVP_BEHAVIOUR_TYPE type; + + DELTA_CONTROLLER *FireLeft,*FireRight; + + LOCALASSERT(sbPtr); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + type = ghostData->type; + + if(!(sbPtr->SBdptr)) + { + /* update the ghost's current sequence: do this even if we don't have a displayblock */ + ghostData->currentAnimSequence = sequence; + return; /* no displayblock: can't actually set it */ + } + + switch(type) + { + case(I_BehaviourMarinePlayer): + { + switch((MARINE_SEQUENCE)sequence) + { + case(MSQ_Walk): + { + if (ghostData->CurrentWeapon==WEAPON_SMARTGUN) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineRun,(int)MRSS_Attack_Primary,(ONE_FIXED>>1),1); + } else if (ghostData->CurrentWeapon==WEAPON_MARINE_PISTOL) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineRun,(int)MRSS_Attack_Primary,(ONE_FIXED>>1),1); + } else if (ghostData->CurrentWeapon==WEAPON_TWO_PISTOLS) { + /* Oh, no. */ + if (special) { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineRun)||(ghostData->HModelController.Sub_Sequence!=MRSS_Fire_From_Hips)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineRun,(int)MRSS_Fire_From_Hips,(ONE_FIXED>>1),1); + } + } else { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineRun)||(ghostData->HModelController.Sub_Sequence!=MRSS_Standard)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineRun,(int)MRSS_Standard,(ONE_FIXED>>1),1); + } + } + } else { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineRun,(int)MRSS_Standard,(ONE_FIXED>>1),1); + } + break; + } + case(MSQ_Walk_Backwards): + { + if (ghostData->CurrentWeapon==WEAPON_SMARTGUN) { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Attack_Primary,(ONE_FIXED>>1)); + } else if (ghostData->CurrentWeapon==WEAPON_MARINE_PISTOL) { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Attack_Primary,(ONE_FIXED>>1)); + } else if (ghostData->CurrentWeapon==WEAPON_TWO_PISTOLS) { + /* Oh, no. */ + if (special) { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineRun)||(ghostData->HModelController.Sub_Sequence!=MRSS_Fire_From_Hips)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineRun,(int)MRSS_Fire_From_Hips,(ONE_FIXED>>1),1); + } + } else { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineRun)||(ghostData->HModelController.Sub_Sequence!=MRSS_Standard)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineRun,(int)MRSS_Standard,(ONE_FIXED>>1),1); + } + } + } else { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Standard,(ONE_FIXED>>1)); + } + ghostData->HModelController.Reversed=1; + break; + } + case(MSQ_RunningFire): + { + if (ghostData->CurrentWeapon==WEAPON_MARINE_PISTOL) { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Attack_Primary,(ONE_FIXED>>1)); + } else if (ghostData->CurrentWeapon==WEAPON_TWO_PISTOLS) { + + FireRight=Get_Delta_Sequence(&ghostData->HModelController,"FireRight"); + if (FireRight==NULL) { + FireRight=Add_Delta_Sequence(&ghostData->HModelController,"FireRight",HMSQT_MarineStand,MSSS_Attack_Primary,ONE_FIXED); + FireRight->Playing=0; + FireRight->Active=0; + } + + FireLeft=Get_Delta_Sequence(&ghostData->HModelController,"FireLeft"); + if (FireLeft==NULL) { + FireLeft=Add_Delta_Sequence(&ghostData->HModelController,"FireLeft",HMSQT_MarineStand,MSSS_Attack_Secondary,ONE_FIXED); + FireLeft->Playing=0; + FireLeft->Active=0; + } + + if (special) { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineRun)||(ghostData->HModelController.Sub_Sequence!=MRSS_Fire_From_Hips)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineRun,(int)MRSS_Fire_From_Hips,(ONE_FIXED>>1),1); + } + } else { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineRun)||(ghostData->HModelController.Sub_Sequence!=MRSS_Standard)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineRun,(int)MRSS_Standard,(ONE_FIXED>>1),1); + } + } + + Start_Delta_Sequence(FireRight,HMSQT_MarineStand,MSSS_Attack_Primary,-1); + FireRight->Playing=1; + FireRight->Active=1; + + } else { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Attack_Primary,(ONE_FIXED>>1)); + } + break; + } + case(MSQ_RunningFireSecondary): + { + if (ghostData->CurrentWeapon==WEAPON_MARINE_PISTOL) { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Attack_Primary,(ONE_FIXED>>1)); + } else if (ghostData->CurrentWeapon==WEAPON_TWO_PISTOLS) { + + FireRight=Get_Delta_Sequence(&ghostData->HModelController,"FireRight"); + if (FireRight==NULL) { + FireRight=Add_Delta_Sequence(&ghostData->HModelController,"FireRight",HMSQT_MarineStand,MSSS_Attack_Primary,ONE_FIXED); + FireRight->Playing=0; + FireRight->Active=0; + } + + FireLeft=Get_Delta_Sequence(&ghostData->HModelController,"FireLeft"); + if (FireLeft==NULL) { + FireLeft=Add_Delta_Sequence(&ghostData->HModelController,"FireLeft",HMSQT_MarineStand,MSSS_Attack_Secondary,ONE_FIXED); + FireLeft->Playing=0; + FireLeft->Active=0; + } + + if (special) { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineRun)||(ghostData->HModelController.Sub_Sequence!=MRSS_Fire_From_Hips)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineRun,(int)MRSS_Fire_From_Hips,(ONE_FIXED>>1),1); + } + } else { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineRun)||(ghostData->HModelController.Sub_Sequence!=MRSS_Standard)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineRun,(int)MRSS_Standard,(ONE_FIXED>>1),1); + } + } + + Start_Delta_Sequence(FireLeft,HMSQT_MarineStand,MSSS_Attack_Secondary,-1); + FireLeft->Playing=1; + FireLeft->Active=1; + + } else { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Attack_Primary,(ONE_FIXED>>1)); + } + break; + } + case(MSQ_RunningFire_Backwards): + { + if (ghostData->CurrentWeapon==WEAPON_MARINE_PISTOL) { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Attack_Primary,(ONE_FIXED>>1)); + ghostData->HModelController.Reversed=1; + } else if (ghostData->CurrentWeapon==WEAPON_TWO_PISTOLS) { + + FireRight=Get_Delta_Sequence(&ghostData->HModelController,"FireRight"); + if (FireRight==NULL) { + FireRight=Add_Delta_Sequence(&ghostData->HModelController,"FireRight",HMSQT_MarineStand,MSSS_Attack_Primary,ONE_FIXED); + FireRight->Playing=0; + FireRight->Active=0; + } + + FireLeft=Get_Delta_Sequence(&ghostData->HModelController,"FireLeft"); + if (FireLeft==NULL) { + FireLeft=Add_Delta_Sequence(&ghostData->HModelController,"FireLeft",HMSQT_MarineStand,MSSS_Attack_Secondary,ONE_FIXED); + FireLeft->Playing=0; + FireLeft->Active=0; + } + + if (special) { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineRun)||(ghostData->HModelController.Sub_Sequence!=MRSS_Fire_From_Hips)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineRun,(int)MRSS_Fire_From_Hips,(ONE_FIXED>>1),1); + ghostData->HModelController.Reversed=1; + } + } else { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineRun)||(ghostData->HModelController.Sub_Sequence!=MRSS_Standard)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineRun,(int)MRSS_Standard,(ONE_FIXED>>1),1); + ghostData->HModelController.Reversed=1; + } + } + + Start_Delta_Sequence(FireRight,HMSQT_MarineStand,MSSS_Attack_Primary,-1); + FireRight->Playing=1; + FireRight->Active=1; + + } else { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Attack_Primary,(ONE_FIXED>>1)); + ghostData->HModelController.Reversed=1; + } + break; + } + case(MSQ_RunningFireSecondary_Backwards): + { + if (ghostData->CurrentWeapon==WEAPON_MARINE_PISTOL) { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Attack_Primary,(ONE_FIXED>>1)); + ghostData->HModelController.Reversed=1; + } else if (ghostData->CurrentWeapon==WEAPON_TWO_PISTOLS) { + + FireRight=Get_Delta_Sequence(&ghostData->HModelController,"FireRight"); + if (FireRight==NULL) { + FireRight=Add_Delta_Sequence(&ghostData->HModelController,"FireRight",HMSQT_MarineStand,MSSS_Attack_Primary,ONE_FIXED); + FireRight->Playing=0; + FireRight->Active=0; + } + + FireLeft=Get_Delta_Sequence(&ghostData->HModelController,"FireLeft"); + if (FireLeft==NULL) { + FireLeft=Add_Delta_Sequence(&ghostData->HModelController,"FireLeft",HMSQT_MarineStand,MSSS_Attack_Secondary,ONE_FIXED); + FireLeft->Playing=0; + FireLeft->Active=0; + } + + if (special) { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineRun)||(ghostData->HModelController.Sub_Sequence!=MRSS_Fire_From_Hips)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineRun,(int)MRSS_Fire_From_Hips,(ONE_FIXED>>1),1); + ghostData->HModelController.Reversed=1; + } + } else { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineRun)||(ghostData->HModelController.Sub_Sequence!=MRSS_Standard)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineRun,(int)MRSS_Standard,(ONE_FIXED>>1),1); + ghostData->HModelController.Reversed=1; + } + } + + Start_Delta_Sequence(FireLeft,HMSQT_MarineStand,MSSS_Attack_Secondary,-1); + FireLeft->Playing=1; + FireLeft->Active=1; + + } else { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Attack_Primary,(ONE_FIXED>>1)); + ghostData->HModelController.Reversed=1; + } + break; + } + case(MSQ_StandingFire): + { + if (ghostData->CurrentWeapon==WEAPON_TWO_PISTOLS) { + + FireRight=Get_Delta_Sequence(&ghostData->HModelController,"FireRight"); + if (FireRight==NULL) { + FireRight=Add_Delta_Sequence(&ghostData->HModelController,"FireRight",HMSQT_MarineStand,MSSS_Attack_Primary,ONE_FIXED); + FireRight->Playing=0; + FireRight->Active=0; + } + + FireLeft=Get_Delta_Sequence(&ghostData->HModelController,"FireLeft"); + if (FireLeft==NULL) { + FireLeft=Add_Delta_Sequence(&ghostData->HModelController,"FireLeft",HMSQT_MarineStand,MSSS_Attack_Secondary,ONE_FIXED); + FireLeft->Playing=0; + FireLeft->Active=0; + } + + if (special) { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineStand)||(ghostData->HModelController.Sub_Sequence!=MSSS_FireFromHips)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineStand,(int)MSSS_FireFromHips,(ONE_FIXED>>1),1); + } + } else { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineStand)||(ghostData->HModelController.Sub_Sequence!=MSSS_Standard)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineStand,(int)MSSS_Standard,(ONE_FIXED>>1),1); + } + } + + Start_Delta_Sequence(FireRight,HMSQT_MarineStand,MSSS_Attack_Primary,-1); + FireRight->Playing=1; + FireRight->Active=1; + + } else { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Attack_Primary,ONE_FIXED); + } + break; + } + case(MSQ_StandingFireSecondary): + { + if (ghostData->CurrentWeapon==WEAPON_TWO_PISTOLS) { + + FireRight=Get_Delta_Sequence(&ghostData->HModelController,"FireRight"); + if (FireRight==NULL) { + FireRight=Add_Delta_Sequence(&ghostData->HModelController,"FireRight",HMSQT_MarineStand,MSSS_Attack_Primary,ONE_FIXED); + FireRight->Playing=0; + FireRight->Active=0; + } + + FireLeft=Get_Delta_Sequence(&ghostData->HModelController,"FireLeft"); + if (FireLeft==NULL) { + FireLeft=Add_Delta_Sequence(&ghostData->HModelController,"FireLeft",HMSQT_MarineStand,MSSS_Attack_Secondary,ONE_FIXED); + FireLeft->Playing=0; + FireLeft->Active=0; + } + + if (special) { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineStand)||(ghostData->HModelController.Sub_Sequence!=MSSS_FireFromHips)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineStand,(int)MSSS_FireFromHips,(ONE_FIXED>>1),1); + } + } else { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineStand)||(ghostData->HModelController.Sub_Sequence!=MSSS_Standard)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineStand,(int)MSSS_Standard,(ONE_FIXED>>1),1); + } + } + + Start_Delta_Sequence(FireLeft,HMSQT_MarineStand,MSSS_Attack_Secondary,-1); + FireLeft->Playing=1; + FireLeft->Active=1; + + } else { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Attack_Primary,ONE_FIXED); + } + break; + } + case(MSQ_Stand): + { + BOOL standing_attack=FALSE; + /* Removed the test for 'standing swipe'... */ + if(ghostData->currentAnimSequence>=MSQ_BaseOfCudgelAttacks) + { + if((ghostData->currentAnimSequence-MSQ_BaseOfCudgelAttacks)%2==1) + { + standing_attack=TRUE; + } + } + + if(standing_attack) + { + //if currently playing a standing attack allow it to finish first + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) return; + } + + if (ghostData->CurrentWeapon==WEAPON_TWO_PISTOLS) { + if (special) { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineStand)||(ghostData->HModelController.Sub_Sequence!=MSSS_FireFromHips)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineStand,(int)MSSS_FireFromHips,(ONE_FIXED>>1),1); + } + } else { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineStand)||(ghostData->HModelController.Sub_Sequence!=MSSS_Standard)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineStand,(int)MSSS_Standard,(ONE_FIXED>>1),1); + } + } + } else { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineStand,(int)MSSS_Standard,ONE_FIXED,1); + // InitHModelSequence(&ghostData->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Standard,ONE_FIXED); + } + break; + } + case(MSQ_Crawl): + { + if (ghostData->CurrentWeapon==WEAPON_TWO_PISTOLS) { + if (special) { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineCrawl)||(ghostData->HModelController.Sub_Sequence!=MCSS_FireFromHips)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineCrawl,(int)MCSS_FireFromHips,(ONE_FIXED>>1),1); + } + } else { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineCrawl)||(ghostData->HModelController.Sub_Sequence!=MCSS_Standard)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineCrawl,(int)MCSS_Standard,(ONE_FIXED>>1),1); + } + } + } else { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_MarineCrawl,(int)MCSS_Standard,(ONE_FIXED>>1),1); + } + break; + } + case(MSQ_Crawl_Backwards): + { + if (ghostData->CurrentWeapon==WEAPON_TWO_PISTOLS) { + if (special) { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineCrawl)||(ghostData->HModelController.Sub_Sequence!=MCSS_FireFromHips)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineCrawl,(int)MCSS_FireFromHips,(ONE_FIXED>>1),1); + } + } else { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineCrawl)||(ghostData->HModelController.Sub_Sequence!=MCSS_Standard)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineCrawl,(int)MCSS_Standard,(ONE_FIXED>>1),1); + } + } + } else { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_MarineCrawl,(int)MCSS_Standard,(ONE_FIXED>>1)); + } + ghostData->HModelController.Reversed=1; + break; + } + case(MSQ_Crouch): + { + BOOL crouched_attack=FALSE; + if(ghostData->currentAnimSequence>=MSQ_BaseOfCudgelAttacks) + { + if((ghostData->currentAnimSequence-MSQ_BaseOfCudgelAttacks)%2==0) + { + crouched_attack=TRUE; + } + } + + if(crouched_attack) + { + //if currently playing a standing attack allow it to finish first + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) return; + } + + if (ghostData->CurrentWeapon==WEAPON_TWO_PISTOLS) { + if (special) { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineCrouch)||(ghostData->HModelController.Sub_Sequence!=MCrSS_FireFromHips)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineCrouch,(int)MCrSS_FireFromHips,(ONE_FIXED>>1),1); + } + } else { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineCrouch)||(ghostData->HModelController.Sub_Sequence!=MCrSS_Standard)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineCrouch,(int)MCrSS_Standard,(ONE_FIXED>>1),1); + } + } + } else { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_MarineCrouch,(int)MCrSS_Standard,ONE_FIXED,1); + } + break; + } + case(MSQ_Jump): + { + if (HModelSequence_Exists(&ghostData->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Jump)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_MarineStand,(int)MSSS_Jump,(ONE_FIXED),0); + break; + } else { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineStand,(int)MSSS_Standard,ONE_FIXED,1); + break; + } + + } + case(MSQ_Taunt): + { + if (HModelSequence_Exists(&ghostData->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Taunt_One)) { + if ((ghostData->HModelController.Sequence_Type!=(int)HMSQT_MarineStand)||(ghostData->HModelController.Sub_Sequence!=MSSS_Taunt_One)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_MarineStand,(int)MSSS_Taunt_One,(TAUNT_LENGTH-(ONE_FIXED>>3)),0); + } + break; + } else { + /* Default. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_MarineStand,(int)MSSS_Standard,ONE_FIXED,1); + break; + } + + } + case(MSQ_StandDieFront): + case(MSQ_CrouchDie): + { + break; + } + default: + { + int attack; + /* Now includes cudgel attacks... */ + if ((int)sequence>=(int)MSQ_BaseOfCudgelAttacks) { + attack=(int)sequence-(int)MSQ_BaseOfCudgelAttacks; + + if(ghostData->currentAnimSequence>=MSQ_BaseOfCudgelAttacks) + { + //already playing some form of attack + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) return; + } + switch (attack) { + case 0: + /* Crouching Primary Fire. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>4),(int)HMSQT_MarineCrouch,(int)MCrSS_Attack_Primary,-1,0); + break; + case 1: + /* Standing Primary Fire. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>4),(int)HMSQT_MarineStand,(int)MSSS_Attack_Primary,-1,0); + break; + case 2: + /* Crouching Secondary Fire. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>4),(int)HMSQT_MarineCrouch,(int)MCrSS_Attack_Secondary,-1,0); + break; + case 3: + /* Standing Secondary Fire. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>4),(int)HMSQT_MarineStand,(int)MSSS_Attack_Secondary,-1,0); + break; + default: + /* KJL 16:56:15 26/11/98 - hmm. Any 'unknown' attacks will be replaced with a fast jab */ + { + if (attack&1) + { + /* Standing Fast Jab. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>4),(int)HMSQT_MarineStand,(int)MSSS_Attack_Primary,-1,0); + } + else + { + /* Crouching Fast Jab. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>4),(int)HMSQT_MarineCrouch,(int)MCrSS_Attack_Primary,-1,0); + } + break; + } + } + } else { + attack=(int)sequence-(int)MSQ_BaseOfCudgelAttacks; + + if (attack) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_PredatorCrouch,(int)PCrSS_Attack_Primary,-1,0); + } else { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_PredatorStand,(int)PSSS_Attack_Primary,-1,0); + } + } + break; + } + } + break; + } + case(I_BehaviourAlienPlayer): + case(I_BehaviourAlien): + { + switch((ALIEN_SEQUENCE)sequence) + { + case(ASQ_Stand): + case(ASQ_StandingTailPoise): + { + if(ghostData->currentAnimSequence==ASQ_StandingAttack_Claw || + ghostData->currentAnimSequence==ASQ_StandingTailStrike || + ghostData->currentAnimSequence==ASQ_Eat) + { + //if currently playing a standing attack allow it to finish first + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) return; + } + + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienStand,(int)ASSS_Standard,ONE_FIXED,1); + break; + } + case(ASQ_StandingAttack_Claw): + { + int chosenSequence; + + if(ghostData->currentAnimSequence==ASQ_StandingAttack_Claw || + ghostData->currentAnimSequence==ASQ_StandingTailStrike || + ghostData->currentAnimSequence==ASQ_Eat) + { + //if already playing a standing attack allow it to finish first + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) return; + } + + /*Pick a random claw attack*/ + switch(FastRandom()%6) + { + case 0: + chosenSequence=ASSS_Attack_Right_Swipe_In; + break; + case 1: + chosenSequence=ASSS_Attack_Left_Swipe_In; + break; + case 2: + chosenSequence=ASSS_Attack_Both_In; + break; + case 3: + chosenSequence=ASSS_Attack_Both_Down; + break; + case 4: + chosenSequence=ASSS_Attack_Low_Left_Swipe; + break; + case 5: + chosenSequence=ASSS_Attack_Low_Right_Swipe; + break; + + } + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienStand,chosenSequence,-1/*(ONE_FIXED/6)*/,0); + + break; + } + + case(ASQ_StandingTailStrike): + { + if(ghostData->currentAnimSequence==ASQ_StandingAttack_Claw || + ghostData->currentAnimSequence==ASQ_StandingTailStrike || + ghostData->currentAnimSequence==ASQ_Eat) + { + //if already playing a standing attack allow it to finish first + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) return; + } + + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienStand,(int)ASSS_Attack_Tail,-1/*(ONE_FIXED/6)*/,0); + break; + } + case(ASQ_Eat) : + { + if(ghostData->currentAnimSequence==ASQ_StandingAttack_Claw || + ghostData->currentAnimSequence==ASQ_StandingTailStrike || + ghostData->currentAnimSequence==ASQ_Eat) + { + //if already playing a standing attack allow it to finish first + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) return; + } + + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienStand,(int)ASSS_Attack_Bite,-1,0); + break; + } + + case(ASQ_Run): + case(ASQ_RunningTailPoise): + { + if(ghostData->currentAnimSequence==ASQ_RunningAttack_Claw || + ghostData->currentAnimSequence==ASQ_RunningTailStrike) + { + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) + { + ghostData->HModelController.Looped=0; + ghostData->HModelController.LoopAfterTweening=0; + return; + } + } + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienRun,(int)ARSS_Standard,ONE_FIXED,1); + break; + } + case(ASQ_Run_Backwards): + case(ASQ_RunningTailPoise_Backwards): + { + if(ghostData->currentAnimSequence==ASQ_RunningAttack_Claw_Backwards || + ghostData->currentAnimSequence==ASQ_RunningTailStrike_Backwards) + { + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) + { + ghostData->HModelController.Looped=0; + ghostData->HModelController.LoopAfterTweening=0; + return; + } + } + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_AlienRun,(int)ARSS_Standard,ONE_FIXED); + ghostData->HModelController.Reversed=1; + break; + } + case(ASQ_RunningAttack_Claw): + case(ASQ_RunningTailStrike): + { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienRun,(int)ARSS_Attack_Swipe,ONE_FIXED/*(ONE_FIXED/6)*/,1); + break; + } + case(ASQ_RunningAttack_Claw_Backwards): + case(ASQ_RunningTailStrike_Backwards): + { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_AlienRun,(int)ARSS_Attack_Swipe,ONE_FIXED/*(ONE_FIXED/6)*/); + ghostData->HModelController.Reversed=1; + ghostData->HModelController.Looped=1; + break; + } + case(ASQ_Crawl): + case(ASQ_CrawlingTailPoise): + { + if(ghostData->currentAnimSequence==ASQ_CrawlingAttack_Claw || + ghostData->currentAnimSequence==ASQ_CrawlingTailStrike) + { + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) + { + ghostData->HModelController.Looped=0; + ghostData->HModelController.LoopAfterTweening=0; + return; + } + } + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienCrawl,(int)ACSS_Standard,ONE_FIXED,1); + break; + } + case (ASQ_Scamper): + { + if(ghostData->currentAnimSequence==ASQ_CrawlingAttack_Claw || + ghostData->currentAnimSequence==ASQ_CrawlingTailStrike) + { + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) + { + ghostData->HModelController.Looped=0; + ghostData->HModelController.LoopAfterTweening=0; + return; + } + } + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienCrawl,(int)ACSS_Scamper,ONE_FIXED,1); + break; + } + + case(ASQ_Crawl_Backwards): + case(ASQ_CrawlingTailPoise_Backwards): + { + if(ghostData->currentAnimSequence==ASQ_CrawlingAttack_Claw_Backwards || + ghostData->currentAnimSequence==ASQ_CrawlingTailStrike_Backwards) + { + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) + { + ghostData->HModelController.Looped=0; + ghostData->HModelController.LoopAfterTweening=0; + return; + } + } + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_AlienCrawl,(int)ACSS_Standard,ONE_FIXED); + ghostData->HModelController.Reversed=1; + break; + } + case(ASQ_Scamper_Backwards): + { + if(ghostData->currentAnimSequence==ASQ_CrawlingAttack_Claw_Backwards || + ghostData->currentAnimSequence==ASQ_CrawlingTailStrike_Backwards) + { + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) + { + ghostData->HModelController.Looped=0; + ghostData->HModelController.LoopAfterTweening=0; + return; + } + } + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_AlienCrawl,(int)ACSS_Scamper,ONE_FIXED); + ghostData->HModelController.Reversed=1; + break; + } + + case(ASQ_CrawlingAttack_Claw): + case(ASQ_CrawlingTailStrike): + { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienCrouch,(int)ACrSS_Attack_Swipe,ONE_FIXED/*(ONE_FIXED/6)*/,1); + break; + } + case(ASQ_CrawlingAttack_Claw_Backwards): + case(ASQ_CrawlingTailStrike_Backwards): + { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_AlienCrouch,(int)ACrSS_Attack_Swipe,ONE_FIXED/*(ONE_FIXED/6)*/); + ghostData->HModelController.Reversed=1; + ghostData->HModelController.Looped=1; + break; + } + #if 0 + case(ASQ_CrawlingTailStrike): + { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienCrawl,(int)ACSS_Attack_Tail,ONE_FIXED/*(ONE_FIXED/6)*/,1); + break; + } + case(ASQ_CrawlingTailStrike_Backwards): + { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_AlienCrawl,(int)ACSS_Attack_Tail,ONE_FIXED/*(ONE_FIXED/6)*/); + ghostData->HModelController.Reversed=1; + ghostData->HModelController.Looped=1; + break; + } + #endif + case(ASQ_Crouch): + case(ASQ_CrouchedTailPoise): + { + if(ghostData->currentAnimSequence==ASQ_CrouchedAttack_Claw || + ghostData->currentAnimSequence==ASQ_CrouchEat|| + ghostData->currentAnimSequence==ASQ_CrouchedTailStrike) + { + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) return; + } + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienCrouch,(int)ACSS_Standard,ONE_FIXED,1); + break; + } + case(ASQ_CrouchedAttack_Claw): + { + if(ghostData->currentAnimSequence==ASQ_CrouchedAttack_Claw || + ghostData->currentAnimSequence==ASQ_CrouchedTailStrike || + ghostData->currentAnimSequence==ASQ_CrouchEat) + { + //if already playing a crouched attack allow it to finish first + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) return; + } + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienCrouch,(int)ACrSS_Attack_Swipe,-1/*(ONE_FIXED/6)*/,0); + break; + } + case(ASQ_CrouchedTailStrike): + { + if(ghostData->currentAnimSequence==ASQ_CrouchedAttack_Claw || + ghostData->currentAnimSequence==ASQ_CrouchedTailStrike || + ghostData->currentAnimSequence==ASQ_CrouchEat) + { + //if already playing a crouched attack allow it to finish first + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) return; + } + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienCrouch,(int)ACrSS_Attack_Tail,-1/*(ONE_FIXED/6)*/,0); + break; + } + case(ASQ_CrouchEat) : + { + if(ghostData->currentAnimSequence==ASQ_CrouchedAttack_Claw || + ghostData->currentAnimSequence==ASQ_CrouchedTailStrike || + ghostData->currentAnimSequence==ASQ_CrouchEat) + { + //if already playing a crouched attack allow it to finish first + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) return; + } + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienCrouch,(int)ACrSS_Attack_Bite,-1,0); + break; + } + case(ASQ_Jump): + case(ASQ_Pounce): + case(ASQ_JumpingTailPoise): + case(ASQ_JumpingTailStrike): + { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienRun,(int)ARSS_Jump,ONE_FIXED,1); + break; + } + case(ASQ_Taunt): + { + if (HModelSequence_Exists(&ghostData->HModelController,(int)HMSQT_AlienStand,(int)ASSS_Taunt)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_AlienStand,(int)ASSS_Taunt,(TAUNT_LENGTH-(ONE_FIXED>>3)),0); + break; + } else { + /* Default. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_AlienStand,(int)ASSS_Standard,ONE_FIXED,1); + break; + } + + } + default: + { + /* no other sequences should be set */ + LOCALASSERT("Unknown Alien anim sequence"==0); + break; + } + } + break; + } + case(I_BehaviourPredatorPlayer): + { + switch((PREDATOR_SEQUENCE)sequence) + { + case(PredSQ_Stand): + { + BOOL standing_attack=FALSE; + if(ghostData->currentAnimSequence==PredSQ_StandingSwipe) + { + standing_attack=TRUE; + } + else if(ghostData->currentAnimSequence>=PredSQ_BaseOfWristbladeAttacks) + { + if((ghostData->currentAnimSequence-PredSQ_BaseOfWristbladeAttacks)%2==1) + { + standing_attack=TRUE; + } + } + + if(standing_attack) + { + //if currently playing a standing attack allow it to finish first + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) return; + } + + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_PredatorStand,(int)PSSS_Standard,ONE_FIXED,1); + break; + } + case(PredSQ_StandingSwipe): + { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_PredatorStand,(int)PSSS_Attack_Primary,-1,0); + break; + } + + case(PredSQ_RunningSwipe): + { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_PredatorRun,(int)PRSS_Attack_Primary,(ONE_FIXED>>1)); + ghostData->HModelController.Looped=0; + break; + } + + case(PredSQ_RunningSwipe_Backwards): + { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_PredatorRun,(int)PRSS_Attack_Primary,(ONE_FIXED>>1)); + ghostData->HModelController.Looped=0; + ghostData->HModelController.Reversed=1; + break; + } + + case(PredSQ_Run): + { + if(ghostData->currentAnimSequence==PredSQ_RunningSwipe) + { + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) + { + ghostData->HModelController.Looped=0; + ghostData->HModelController.LoopAfterTweening=0; + return; + } + } + + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_PredatorRun,(int)PSSS_Standard,(ONE_FIXED>>1),1); + + break; + } + + case(PredSQ_Run_Backwards): + { + if(ghostData->currentAnimSequence==PredSQ_RunningSwipe_Backwards) + { + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) + { + ghostData->HModelController.Looped=0; + ghostData->HModelController.LoopAfterTweening=0; + return; + } + } + + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_PredatorRun,(int)PSSS_Standard,(ONE_FIXED>>1)); + ghostData->HModelController.Reversed=1; + break; + } + case(PredSQ_Crawl): + { + if(ghostData->currentAnimSequence==PredSQ_CrawlingSwipe) + { + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) + { + ghostData->HModelController.Looped=0; + ghostData->HModelController.LoopAfterTweening=0; + return; + } + } + + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_PredatorCrawl,(int)PCSS_Standard,(ONE_FIXED>>1),1); + break; + } + case(PredSQ_Crawl_Backwards): + { + if(ghostData->currentAnimSequence==PredSQ_CrawlingSwipe_Backwards) + { + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) + { + ghostData->HModelController.Looped=0; + ghostData->HModelController.LoopAfterTweening=0; + return; + } + } + + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_PredatorCrawl,(int)PCSS_Standard,(ONE_FIXED>>1)); + ghostData->HModelController.Reversed=1; + break; + } + case(PredSQ_Crouch): + { + BOOL crouched_attack=FALSE; + if(ghostData->currentAnimSequence==PredSQ_CrouchedSwipe) + { + crouched_attack=TRUE; + } + else if(ghostData->currentAnimSequence>=PredSQ_BaseOfWristbladeAttacks) + { + if((ghostData->currentAnimSequence-PredSQ_BaseOfWristbladeAttacks)%2==0) + { + crouched_attack=TRUE; + } + } + + if(crouched_attack) + { + //if currently playing a standing attack allow it to finish first + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) return; + } + + if(ghostData->currentAnimSequence==PredSQ_CrouchedSwipe) + { + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) + { + return; + } + } + + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_PredatorCrouch,(int)PCrSS_Standard,ONE_FIXED,1); + break; + } + case(PredSQ_CrouchedSwipe): + { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_PredatorCrouch,(int)PCrSS_Attack_Primary,-1,0); + break; + } + case(PredSQ_CrawlingSwipe): + { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_PredatorCrawl,(int)PCSS_Attack_Primary,(ONE_FIXED>>1)); + ghostData->HModelController.Looped=0; + break; + } + case(PredSQ_CrawlingSwipe_Backwards): + { + InitHModelSequence(&ghostData->HModelController,(int)HMSQT_PredatorCrawl,(int)PCSS_Attack_Primary,(ONE_FIXED>>1)); + ghostData->HModelController.Looped=0; + ghostData->HModelController.Reversed=1; + break; + } + case(PredSQ_Jump): + { + if (HModelSequence_Exists(&ghostData->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_Jump)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_PredatorStand,(int)PSSS_Jump,(ONE_FIXED),0); + break; + } else { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_PredatorStand,(int)PSSS_Standard,ONE_FIXED,1); + break; + } + + } + case(PredSQ_Taunt): + { + if (HModelSequence_Exists(&ghostData->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_Taunt_One)) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_PredatorStand,(int)PSSS_Taunt_One,(TAUNT_LENGTH-(ONE_FIXED>>3)),0); + break; + } else { + /* Default. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED)>>3,(int)HMSQT_PredatorStand,(int)PSSS_Standard,ONE_FIXED,1); + break; + } + + } + case(PredSQ_StandDie): + { + break; + } + case(PredSQ_CrouchDie): + { + break; + } + default: + { + int attack; + /* Must cover STAFF ATTACKS, and WRISTBLADE ATTACKS! */ + if ((int)sequence>=(int)PredSQ_BaseOfWristbladeAttacks) { + attack=(int)sequence-(int)PredSQ_BaseOfWristbladeAttacks; + + if(ghostData->currentAnimSequence>=PredSQ_BaseOfWristbladeAttacks) + { + //already playing some form of attack + if(!HModelAnimation_IsFinished(&ghostData->HModelController)) return; + } + switch (attack) { + case 0: + /* Crouching Fast Jab. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>4),(int)HMSQT_PredatorCrouch,(int)PCrSS_Attack_Primary,-1,0); + break; + case 1: + /* Standing Fast Jab. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>4),(int)HMSQT_PredatorStand,(int)PSSS_Attack_Quick_Jab,-1,0); + break; + case 2: + /* Crouching Slow Jab. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>4),(int)HMSQT_PredatorCrouch,(int)PCrSS_Attack_Primary,-1,0); + break; + case 3: + /* Standing Slow Jab. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>4),(int)HMSQT_PredatorStand,(int)PSSS_Attack_Primary,-1,0); + break; + case 4: + /* Crouching Uppercut. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>4),(int)HMSQT_PredatorCrouch,(int)PCrSS_Attack_Primary,-1,0); + break; + case 5: + /* Standing Uppercut. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>4),(int)HMSQT_PredatorStand,(int)PSSS_Attack_Uppercut,-1,0); + break; + default: + /* KJL 16:56:15 26/11/98 - hmm. Any 'unknown' attacks will be replaced with a fast jab */ + { + if (attack&1) + { + /* Standing Fast Jab. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>4),(int)HMSQT_PredatorStand,(int)PSSS_Attack_Quick_Jab,-1,0); + } + else + { + /* Crouching Fast Jab. */ + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>4),(int)HMSQT_PredatorCrouch,(int)PCrSS_Attack_Primary,-1,0); + } + break; + } + } + } else { + attack=(int)sequence-(int)PredSQ_BaseOfStaffAttacks; + + if (attack) { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_PredatorCrouch,(int)PCrSS_Attack_Primary,-1,0); + } else { + InitHModelTweening(&ghostData->HModelController,(ONE_FIXED>>3),(int)HMSQT_PredatorStand,(int)PSSS_Attack_Primary,-1,0); + } + } + break; + } + } + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + /* update the ghost's current sequence*/ + ghostData->currentAnimSequence = sequence; +} + + + +/* Patrick 5/8/97 -------------------------------------------------- +Handles the player's weapon sound effects... this should be called +after update ghost/create ghost has been called for player ghost +in processnetmsg_playerstate(). +---------------------------------------------------------------------*/ +void HandlePlayerGhostWeaponSound(STRATEGYBLOCK *sbPtr, int weapon, int firingPrimary, int firingSecondary) +{ + NETGHOSTDATABLOCK *ghostData; + AVP_BEHAVIOUR_TYPE type; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + LOCALASSERT(weapon>=0); + + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + type = ghostData->type; + + switch((enum WEAPON_ID)weapon) + { + case(NULL_WEAPON): + { + /* stop sound if we've got it */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + break; + } + case(WEAPON_CUDGEL): + { + //no sound for the moment. + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + break; + } + case(WEAPON_PULSERIFLE): + { + LOCALASSERT(type==I_BehaviourMarinePlayer); + if(firingPrimary) + { + if(ghostData->SoundHandle == SOUND_NOACTIVEINDEX) + Sound_Play(SID_PULSE_LOOP,"elhd",&(ghostData->SoundHandle),&(sbPtr->DynPtr->Position)); + else + Sound_Update3d(ghostData->SoundHandle, &(sbPtr->DynPtr->Position)); + } + else + { + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) + { + Sound_Stop(ghostData->SoundHandle); + Sound_Play(SID_PULSE_END,"hd",&(sbPtr->DynPtr->Position)); + } + if(firingSecondary) Sound_Play(SID_NADEFIRE,"hd",&(sbPtr->DynPtr->Position)); + } + break; + } + case(WEAPON_TWO_PISTOLS): + case(WEAPON_MARINE_PISTOL): + { + LOCALASSERT(type==I_BehaviourMarinePlayer); + /* stop sound if we've got it */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(ghostData->SoundHandle); + } + if ((firingPrimary)||(firingSecondary)) { + //ReleasePrintDebuggingText("Ghost Gunfire Sound!\n"); + Sound_Play(SID_SHOTGUN,"hd",&(sbPtr->DynPtr->Position)); + } + break; + } + case(WEAPON_AUTOSHOTGUN): + { + LOCALASSERT(type==I_BehaviourMarinePlayer); + /* stop sound if we've got it */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + if(firingPrimary) Sound_Play(SID_SHOTGUN,"hd",&(sbPtr->DynPtr->Position)); + break; + } + case(WEAPON_SMARTGUN): + { + LOCALASSERT(type==I_BehaviourMarinePlayer); + if(firingPrimary) + { + if(ghostData->SoundHandle == SOUND_NOACTIVEINDEX) + { + unsigned int rand=FastRandom() % 3; + switch (rand) + { + case(0): + { + Sound_Play(SID_SMART1,"ehpd",&(ghostData->SoundHandle),((FastRandom()&255)-128),&(sbPtr->DynPtr->Position)); + break; + } + case(1): + { + Sound_Play(SID_SMART2,"ehpd",&(ghostData->SoundHandle),((FastRandom()&255)-128),&(sbPtr->DynPtr->Position)); + break; + } + case(2): + { + Sound_Play(SID_SMART3,"ehpd",&(ghostData->SoundHandle),((FastRandom()&255)-128),&(sbPtr->DynPtr->Position)); + break; + } + default: + { + break; + } + } + } + else Sound_Update3d(ghostData->SoundHandle, &(sbPtr->DynPtr->Position)); + } + else + { + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + } + break; + } + case(WEAPON_FLAMETHROWER): + { + LOCALASSERT(type==I_BehaviourMarinePlayer); + if(firingPrimary) + { + if(ghostData->SoundHandle == SOUND_NOACTIVEINDEX) + Sound_Play(SID_INCIN_LOOP,"elhd",&(ghostData->SoundHandle),&(sbPtr->DynPtr->Position)); + else + Sound_Update3d(ghostData->SoundHandle, &(sbPtr->DynPtr->Position)); + } + else + { + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + } + if (firingPrimary) + { + if (sbPtr->SBdptr) + { + ProveHModel(&ghostData->HModelController,sbPtr->SBdptr); + FireNetGhostFlameThrower + ( + &ghostData->GunflashSectionPtr->World_Offset, + &ghostData->GunflashSectionPtr->SecMat + ); + /* Lighting? */ + if (sbPtr->SBdptr) { + AddLightingEffectToObject(sbPtr->SBdptr,LFX_MUZZLEFLASH); + } + } + } + break; + } + case(WEAPON_PLASMAGUN): + { + LOCALASSERT(type==I_BehaviourMarinePlayer); + /* stop sound if we've got it */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + break; + } + case(WEAPON_SADAR): + { + LOCALASSERT(type==I_BehaviourMarinePlayer); + /* stop sound if we've got it */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + if(firingPrimary) Sound_Play(SID_SADAR_FIRE,"hd",&(sbPtr->DynPtr->Position)); + break; + } + case(WEAPON_GRENADELAUNCHER): + { + LOCALASSERT(type==I_BehaviourMarinePlayer); + /* stop sound if we've got it */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + if(firingPrimary) Sound_Play(SID_ROCKFIRE,"hd",&(sbPtr->DynPtr->Position)); + break; + } + case(WEAPON_MINIGUN): + { + LOCALASSERT(type==I_BehaviourMarinePlayer); + if(firingPrimary) + { + if(ghostData->SoundHandle == SOUND_NOACTIVEINDEX) + Sound_Play(SID_MINIGUN_LOOP,"elhd",&(ghostData->SoundHandle),&(sbPtr->DynPtr->Position)); + else + Sound_Update3d(ghostData->SoundHandle, &(sbPtr->DynPtr->Position)); + } + else + { + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) + { + Sound_Stop(ghostData->SoundHandle); + Sound_Play(SID_MINIGUN_END,"hd",&(sbPtr->DynPtr->Position)); + } + } + break; + } + case(WEAPON_FRISBEE_LAUNCHER): + { + LOCALASSERT(type==I_BehaviourMarinePlayer); + /* stop sound if we've got it */ + if (firingPrimary) { + if (ghostData->SoundHandle!=SOUND_NOACTIVEINDEX) { + if (ActiveSounds[ghostData->SoundHandle].soundIndex!=SID_ED_SKEETERCHARGE) { + Sound_Stop(ghostData->SoundHandle); + } + } + if (ghostData->SoundHandle==SOUND_NOACTIVEINDEX) { + if (ghostData->soundStartFlag==0) { + Sound_Play(SID_ED_SKEETERCHARGE,"ehd",&ghostData->SoundHandle,&(sbPtr->DynPtr->Position)); + ghostData->soundStartFlag = 1; + } + } + } else { + ghostData->soundStartFlag = 0; + if (ghostData->SoundHandle != SOUND_NOACTIVEINDEX) { + Sound_Stop(ghostData->SoundHandle); + } + } + break; + } + case(WEAPON_PRED_WRISTBLADE): + case(WEAPON_PRED_STAFF): + { + LOCALASSERT(type==I_BehaviourPredatorPlayer); + /* stop sound if we've got it */ + //use the sounds connected to the hierarchy + #if 0 + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + if((firingPrimary)&&(ghostData->SoundHandle == SOUND_NOACTIVEINDEX)) + Sound_Play(SID_SWIPE,"ehd",&(ghostData->SoundHandle),&(sbPtr->DynPtr->Position)); + #endif + break; + } + case(WEAPON_PRED_PISTOL): + { + LOCALASSERT(type==I_BehaviourPredatorPlayer); + if(firingPrimary) + { + if(ghostData->SoundHandle == SOUND_NOACTIVEINDEX) { + Sound_Play(SID_PRED_PISTOL,"hd",&(sbPtr->DynPtr->Position)); + } + // Sound_Play(SID_PULSE_LOOP,"elhd",&(ghostData->SoundHandle),&(sbPtr->DynPtr->Position)); + //else + // Sound_Update3d(ghostData->SoundHandle, &(sbPtr->DynPtr->Position)); + #if 0 + if (sbPtr->SBdptr) + { + ProveHModel(&ghostData->HModelController,sbPtr->SBdptr); + //create the particles for the pistol firing + { + SECTION_DATA *muzzle; + VECTORCH null_vec; + + muzzle=GetThisSectionData(ghostData->HModelController.section_data,"dum flash"); + + null_vec.vx=0; + null_vec.vy=0; + null_vec.vz=0; + + GLOBALASSERT(muzzle); + +// FirePredPistolFlechettes(&muzzle->World_Offset,&null_vec,&muzzle->SecMat,0,&ghostData->timer,FALSE); +// CreatePPPlasmaBoltKernel(&muzzle->World_Offset,&muzzle->SecMat, 0); + } + } + #endif + } + else + { + //if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) + //{ + // Sound_Stop(ghostData->SoundHandle); + // Sound_Play(SID_PULSE_END,"hd",&(sbPtr->DynPtr->Position)); + //} + } + break; + } + case(WEAPON_PRED_RIFLE): + { + LOCALASSERT(type==I_BehaviourPredatorPlayer); + #if 0 + /* stop sound if we've got it */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + //sound is played by spear creation + #else + /* stop sound if we've got it */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + if(firingPrimary) Sound_Play(SID_PRED_LASER,"hd",&(sbPtr->DynPtr->Position)); + #endif + break; + } + case(WEAPON_PRED_SHOULDERCANNON): + { + LOCALASSERT(type==I_BehaviourPredatorPlayer); + /* stop sound if we've got it */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + //sound is caused by energy bolt creation + break; + } + case(WEAPON_PRED_DISC): + { + LOCALASSERT(type==I_BehaviourPredatorPlayer); + /* stop sound if we've got it */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + /* currently no sound for this */ + break; + } + case(WEAPON_ALIEN_CLAW): + { + //appropriate sounds should be triggered by the animation + #if 0 + LOCALASSERT(type==I_BehaviourAlienPlayer); + /* stop sound if we've got it */ + //if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + + if((firingPrimary)&&(ghostData->SoundHandle == SOUND_NOACTIVEINDEX)) + Sound_Play(SID_SWIPE,"ehd",&(ghostData->SoundHandle),&(sbPtr->DynPtr->Position)); + #endif + + break; + } + case(WEAPON_ALIEN_GRAB): + { + //appropriate sounds should be triggered by the animation + #if 0 + LOCALASSERT(type==I_BehaviourAlienPlayer); + /* stop sound if we've got it */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + if((firingPrimary)&&(ghostData->SoundHandle == SOUND_NOACTIVEINDEX)) + Sound_Play(SID_SWISH,"ehd",&(ghostData->SoundHandle),&(sbPtr->DynPtr->Position)); + #endif + break; + } + case(WEAPON_ALIEN_SPIT): + { + LOCALASSERT(type==I_BehaviourAlienPlayer); + /* stop sound if we've got it */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + if(firingPrimary) Sound_Play(SID_PRED_NEWROAR,"hd",&(sbPtr->DynPtr->Position)); + break; + } + case(WEAPON_PRED_MEDICOMP): + { + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + break; + } + default: + { + LOCALASSERT(1==0); + /* stop sound if we've got it */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + break; + } + } +} + +int ExtractTimerFromElevation(int elevation) { + + int fake_timer,angle1; + + if (elevation > 1024) elevation-=4096; + angle1=-elevation; + + GLOBALASSERT(angle1>=-1024); + GLOBALASSERT(angle1<=1024); + + fake_timer=1024-angle1; + fake_timer<<=5; + if (fake_timer==65536) fake_timer=65535; + + GLOBALASSERT(fake_timer>=0); + GLOBALASSERT(fake_timer<65536); + + return(fake_timer); +} + +/* KJL 17:11:43 26/01/98 - weapon elevation */ +void HandleWeaponElevation(STRATEGYBLOCK *sbPtr, int elevation, int weapon) +{ + NETGHOSTDATABLOCK *ghostDataPtr; + DELTA_CONTROLLER *elevation_controller; + + LOCALASSERT(sbPtr); + ghostDataPtr = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostDataPtr); + + + LOCALASSERT(elevation>=0); + LOCALASSERT(elevation<4096); + + if (ghostDataPtr->type == I_BehaviourMarinePlayer) + { + if (weapon != ghostDataPtr->CurrentWeapon) + { + Dispel_HModel(&ghostDataPtr->HModelController); + CreateMarineHModel(ghostDataPtr, weapon); + ProveHModel_Far(&ghostDataPtr->HModelController,sbPtr); + } + + elevation_controller=Get_Delta_Sequence(&ghostDataPtr->HModelController,"Elevation"); + /* Deal with elevation sequence. */ + GLOBALASSERT(elevation_controller); + elevation_controller->Active=1; + switch(ghostDataPtr->currentAnimSequence) { + case MSQ_StandDieFront: + case MSQ_StandDieBack: + case MSQ_StandDeadFront: + case MSQ_StandDeadBack: + case MSQ_CrouchDie: + case MSQ_CrouchDead: + case MSQ_Taunt: + { + /* Force no elevation. */ + elevation_controller->Active=0; + break; + } + case MSQ_RunningFire: + case MSQ_RunningFire_Backwards: + if (ghostDataPtr->CurrentWeapon==WEAPON_GRENADELAUNCHER) { + elevation_controller->Active=0; + ghostDataPtr->HModelController.Looped=0; + break; + } else if (ghostDataPtr->CurrentWeapon==WEAPON_TWO_PISTOLS) { + if (ghostDataPtr->HModelController.Sub_Sequence==MRSS_Fire_From_Hips) { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=(int)MSSS_Hip_Fire_Elevation; + } else { + if (HModelSequence_Exists(&ghostDataPtr->HModelController, + HMSQT_MarineRun,(int)MRSS_Elevation)) { + elevation_controller->sequence_type=HMSQT_MarineRun; + elevation_controller->sub_sequence=(int)MRSS_Elevation; + } else { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=(int)MSSS_Elevation; + } + } + elevation_controller->timer=ExtractTimerFromElevation(elevation); + } else { + if (HModelSequence_Exists(&ghostDataPtr->HModelController, + HMSQT_MarineRun,(int)MRSS_Elevation)) { + elevation_controller->sequence_type=HMSQT_MarineRun; + elevation_controller->sub_sequence=(int)MRSS_Elevation; + } else { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=(int)MSSS_Elevation; + } + elevation_controller->timer=ExtractTimerFromElevation(elevation); + break; + } + case MSQ_StandingFire: + if (ghostDataPtr->CurrentWeapon==WEAPON_GRENADELAUNCHER) { + elevation_controller->Active=0; + ghostDataPtr->HModelController.Looped=0; + break; + } else if (ghostDataPtr->CurrentWeapon==WEAPON_TWO_PISTOLS) { + if (ghostDataPtr->HModelController.Sub_Sequence==MSSS_FireFromHips) { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=(int)MSSS_Hip_Fire_Elevation; + } else { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=(int)MSSS_Elevation; + } + elevation_controller->timer=ExtractTimerFromElevation(elevation); + } else { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=(int)MSSS_Elevation; + elevation_controller->timer=ExtractTimerFromElevation(elevation); + break; + } + case MSQ_Walk: + case MSQ_Walk_Backwards: + { + if (ghostDataPtr->CurrentWeapon==WEAPON_TWO_PISTOLS) { + if (ghostDataPtr->HModelController.Sub_Sequence==MRSS_Fire_From_Hips) { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=(int)MSSS_Hip_Fire_Elevation; + } else { + if (HModelSequence_Exists(&ghostDataPtr->HModelController, + HMSQT_MarineRun,(int)MRSS_Elevation)) { + elevation_controller->sequence_type=HMSQT_MarineRun; + elevation_controller->sub_sequence=(int)MRSS_Elevation; + } else { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=(int)MSSS_Elevation; + } + } + elevation_controller->timer=ExtractTimerFromElevation(elevation); + } else { + if (HModelSequence_Exists(&ghostDataPtr->HModelController, + HMSQT_MarineRun,(int)MRSS_Elevation)) { + elevation_controller->sequence_type=HMSQT_MarineRun; + elevation_controller->sub_sequence=(int)MRSS_Elevation; + } else { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=(int)MSSS_Elevation; + } + elevation_controller->timer=ExtractTimerFromElevation(elevation); + } + break; + } + case MSQ_Crawl: + case MSQ_Crawl_Backwards: + { + if (ghostDataPtr->CurrentWeapon==WEAPON_TWO_PISTOLS) { + if (ghostDataPtr->HModelController.Sub_Sequence==MCSS_FireFromHips) { + elevation_controller->sequence_type=HMSQT_MarineCrouch; + elevation_controller->sub_sequence=(int)MCrSS_Hip_Fire_Elevation; + } else { + if (HModelSequence_Exists(&ghostDataPtr->HModelController, + HMSQT_MarineCrawl,(int)MCSS_Elevation)) { + elevation_controller->sequence_type=HMSQT_MarineCrawl; + elevation_controller->sub_sequence=(int)MCSS_Elevation; + } else { + elevation_controller->sequence_type=HMSQT_MarineCrouch; + elevation_controller->sub_sequence=(int)MCrSS_Elevation; + } + } + } else { + if (HModelSequence_Exists(&ghostDataPtr->HModelController, + HMSQT_MarineCrawl,(int)MCSS_Elevation)) { + elevation_controller->sequence_type=HMSQT_MarineCrawl; + elevation_controller->sub_sequence=(int)MCSS_Elevation; + } else { + elevation_controller->sequence_type=HMSQT_MarineCrouch; + elevation_controller->sub_sequence=(int)MCrSS_Elevation; + } + } + elevation_controller->timer=ExtractTimerFromElevation(elevation); + break; + } + case MSQ_Crouch: + { + if (ghostDataPtr->CurrentWeapon==WEAPON_TWO_PISTOLS) { + if (ghostDataPtr->HModelController.Sub_Sequence==MCrSS_FireFromHips) { + elevation_controller->sequence_type=HMSQT_MarineCrouch; + elevation_controller->sub_sequence=(int)MCrSS_Hip_Fire_Elevation; + } else { + elevation_controller->sequence_type=HMSQT_MarineCrouch; + elevation_controller->sub_sequence=(int)MCrSS_Elevation; + } + } else { + elevation_controller->sequence_type=HMSQT_MarineCrouch; + elevation_controller->sub_sequence=(int)MCrSS_Elevation; + } + elevation_controller->timer=ExtractTimerFromElevation(elevation); + break; + } + case MSQ_Stand: + case MSQ_Jump: + default: + { + if (ghostDataPtr->CurrentWeapon==WEAPON_TWO_PISTOLS) { + if (ghostDataPtr->HModelController.Sub_Sequence==MSSS_FireFromHips) { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=(int)MSSS_Hip_Fire_Elevation; + } else { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=(int)MSSS_Elevation; + } + } else { + elevation_controller->sequence_type=HMSQT_MarineStand; + elevation_controller->sub_sequence=(int)MSSS_Elevation; + } + elevation_controller->timer=ExtractTimerFromElevation(elevation); + } + break; + } + if ((HModelSequence_Exists(&ghostDataPtr->HModelController,elevation_controller->sequence_type,elevation_controller->sub_sequence)) + && (elevation_controller->Active)) { + elevation_controller->Active=1; + textprint("Using elevation delta.\n"); + } else { + elevation_controller->Active=0; + } + } + else if (ghostDataPtr->type == I_BehaviourPredatorPlayer) + { + if (weapon != ghostDataPtr->CurrentWeapon) + { + Dispel_HModel(&ghostDataPtr->HModelController); + CreatePredatorHModel(ghostDataPtr, weapon); + ProveHModel_Far(&ghostDataPtr->HModelController,sbPtr); + } + elevation_controller=Get_Delta_Sequence(&ghostDataPtr->HModelController,"Elevation"); + /* Deal with elevation sequence. */ + GLOBALASSERT(elevation_controller); + elevation_controller->Active=1; /* enabled? */ + switch(ghostDataPtr->currentAnimSequence) { + case PredSQ_Taunt: + case PredSQ_StandDie: + case PredSQ_StandDead: + case PredSQ_CrouchDie: + case PredSQ_CrouchDead: + { + elevation_controller->Active=0; + /* Force no elevation. */ + break; + } + case PredSQ_Run: + case PredSQ_Run_Backwards: + case PredSQ_RunningSwipe: + case PredSQ_RunningSwipe_Backwards: + { + elevation_controller->sequence_type=HMSQT_PredatorStand; + elevation_controller->sub_sequence=(int)PSSS_Elevation; + elevation_controller->timer=ExtractTimerFromElevation(elevation); + } + break; + case PredSQ_Crouch: + case PredSQ_CrouchedSwipe: + { + elevation_controller->sequence_type=HMSQT_PredatorCrouch; + elevation_controller->sub_sequence=(int)PCrSS_Elevation; + elevation_controller->timer=ExtractTimerFromElevation(elevation); + } + break; + case PredSQ_Crawl: + case PredSQ_CrawlingSwipe: + case PredSQ_Crawl_Backwards: + case PredSQ_CrawlingSwipe_Backwards: + { + elevation_controller->sequence_type=HMSQT_PredatorCrouch; + elevation_controller->sub_sequence=(int)PCrSS_Elevation; + elevation_controller->timer=ExtractTimerFromElevation(elevation); + } + break; + case PredSQ_Jump: + case PredSQ_Stand: + case PredSQ_StandingSwipe: + default: + { + elevation_controller->sequence_type=HMSQT_PredatorStand; + elevation_controller->sub_sequence=(int)PSSS_Elevation; + elevation_controller->timer=ExtractTimerFromElevation(elevation); + } + break; + } + if ((HModelSequence_Exists(&ghostDataPtr->HModelController,elevation_controller->sequence_type,elevation_controller->sub_sequence)) + && (elevation_controller->Active)) { + elevation_controller->Active=1; + } else { + elevation_controller->Active=0; + } + } + else if (ghostDataPtr->type == I_BehaviourAlienPlayer) + { + + if (ghostDataPtr->CurrentWeapon==-1) + { + //this only happens for aliens , if a player changes character + Dispel_HModel(&ghostDataPtr->HModelController); + CreateAlienHModel(ghostDataPtr,0); + ProveHModel_Far(&ghostDataPtr->HModelController,sbPtr); + } + + elevation_controller=Get_Delta_Sequence(&ghostDataPtr->HModelController,"Elevation"); + /* Deal with elevation sequence. */ + GLOBALASSERT(elevation_controller); + elevation_controller->Active=1; /* enabled? */ + switch(ghostDataPtr->currentAnimSequence) { + case ASQ_Pain: + case ASQ_Jump: + case ASQ_Eat: + case ASQ_Pounce: + case ASQ_JumpingTailPoise: + case ASQ_JumpingTailStrike: + case ASQ_Taunt: + { + elevation_controller->Active=0; + /* Force no elevation. */ + break; + } + case ASQ_Crouch: + case ASQ_CrouchedAttack_Claw: + case ASQ_CrouchedTailPoise: + case ASQ_CrouchedTailStrike: + case ASQ_Crawl: + case ASQ_CrawlingAttack_Claw: + case ASQ_CrawlingTailPoise: + case ASQ_CrawlingTailStrike: + case ASQ_Crawl_Backwards: + case ASQ_CrawlingTailPoise_Backwards: + case ASQ_CrawlingTailStrike_Backwards: + case ASQ_CrawlingAttack_Claw_Backwards: + case ASQ_Scamper: + case ASQ_Scamper_Backwards: + case ASQ_CrouchEat : + { + elevation_controller->sequence_type=HMSQT_AlienCrouch; + elevation_controller->sub_sequence=(int)ACrSS_Standard_Elevation; + elevation_controller->timer=ExtractTimerFromElevation(elevation); + break; + } + case ASQ_Run: + case ASQ_RunningAttack_Claw: + case ASQ_RunningTailPoise: + case ASQ_RunningTailStrike: + case ASQ_Run_Backwards: + case ASQ_RunningAttack_Claw_Backwards: + case ASQ_RunningTailPoise_Backwards: + case ASQ_RunningTailStrike_Backwards: + case ASQ_Stand: + case ASQ_StandingAttack_Claw: + case ASQ_StandingTailPoise: + case ASQ_StandingTailStrike: + { + elevation_controller->sequence_type=HMSQT_AlienStand; + elevation_controller->sub_sequence=(int)ASSS_Standard_Elevation; + elevation_controller->timer=ExtractTimerFromElevation(elevation); + break; + } + default: + { + elevation_controller->sequence_type=HMSQT_AlienStand; + elevation_controller->sub_sequence=(int)ASSS_Standard_Elevation; + elevation_controller->timer=ExtractTimerFromElevation(elevation); + } + break; + } + if ((HModelSequence_Exists(&ghostDataPtr->HModelController,elevation_controller->sequence_type,elevation_controller->sub_sequence)) + && (elevation_controller->Active)) { + elevation_controller->Active=1; + } else { + elevation_controller->Active=0; + } + } + + +} + + +/* Patrick 15/7/97 -------------------------------------------------- +Manages the ghost's integrities +---------------------------------------------------------------------*/ +void MaintainGhosts(void) +{ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + + int sbIndex = 0; + STRATEGYBLOCK *sbPtr; + + /* only do this when we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + while(sbIndex < NumActiveStBlocks) + { + sbPtr = ActiveStBlockList[sbIndex++]; + if(sbPtr->I_SBtype==I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + ghostData->integrity-=NormalFrameTime; + if(ghostData->integrity<0) { + RemoveGhost(sbPtr); + } + else switch (ghostData->type) + { + case I_BehaviourFlareGrenade: + { + if (ghostData->timer>ONE_FIXED*4) + { + ghostData->EventCounter += NormalFrameTime; + } + else + { + ghostData->EventCounter += MUL_FIXED(NormalFrameTime,ghostData->timer)/4; + } + + while (ghostData->EventCounter >= FLARE_PARTICLE_GENERATION_TIME) + { + ghostData->EventCounter -= FLARE_PARTICLE_GENERATION_TIME; + MakeFlareParticle(sbPtr->DynPtr); + } + + /* add lighting effect if near */ + if (sbPtr->SBdptr) + { + LIGHTBLOCK *lightPtr = sbPtr->SBdptr->ObLights[0]; + LOCALASSERT(sbPtr->SBdptr->ObNumLights==1); + LOCALASSERT(lightPtr); + lightPtr->LightBright = 1+MUL_FIXED + ( + (ONE_FIXED*4-(FastRandom()&32767)), + ghostData->timer/FLARE_LIFETIME + ); + } + ghostData->timer -= NormalFrameTime; + + //Stop flare from disappearing from lack of update messages. + //This is so the number of meessages sent can be reduced when the flare has stopped moving. + ghostData->integrity=ghostData->timer; + + break; + } + case I_BehaviourProximityGrenade: + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + LOCALASSERT(dynPtr); + if (ghostData->timer<=PROX_GRENADE_LIFETIME*ONE_FIXED) + { + { + int scale = ONE_FIXED-ghostData->timer/PROX_GRENADE_LIFETIME; + scale = MUL_FIXED(scale,scale); + scale = MUL_FIXED(scale,scale)*8; + ghostData->EventCounter += NormalFrameTime + MUL_FIXED(NormalFrameTime,scale); + } + while (ghostData->EventCounter >= PROX_GRENADE_SOUND_GENERATION_TIME) + { + ghostData->EventCounter -= PROX_GRENADE_SOUND_GENERATION_TIME; + Sound_Play(SID_PROX_GRENADE_ACTIVE,"d",&(dynPtr->Position)); + } + + ghostData->timer -= NormalFrameTime; + if (ghostData->timer<=PROX_GRENADE_TRIGGER_TIME && ghostData->SoundHandle==SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_PROX_GRENADE_READYTOBLOW,"de",&(dynPtr->Position),&ghostData->SoundHandle); + } + + //Stop flare from disappearing from lack of update messages. + //This is so the number of meessages sent can be reduced when the flare has stopped moving. + } + else + { + if(!(dynPtr->Position.vx!=dynPtr->PrevPosition.vx || + dynPtr->Position.vy!=dynPtr->PrevPosition.vy || + dynPtr->Position.vz!=dynPtr->PrevPosition.vz)) + { + ghostData->timer = PROX_GRENADE_LIFETIME*ONE_FIXED; + } + } + { + // scan for objects in proximity + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + int i = NumActiveStBlocks; + while(i--) + { + STRATEGYBLOCK *obstaclePtr = ActiveStBlockList[i]; + DYNAMICSBLOCK *obstacleDynPtr = obstaclePtr->DynPtr; + + if (obstacleDynPtr) + { + if(ValidTargetForProxMine(obstaclePtr)) + { + VECTORCH disp = obstacleDynPtr->Position; + disp.vx -= dynPtr->Position.vx; + disp.vy -= dynPtr->Position.vy; + disp.vz -= dynPtr->Position.vz; + + if (Approximate3dMagnitude(&disp)<=PROX_GRENADE_RANGE) + { + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) + { + if (ActiveSounds[ghostData->SoundHandle].soundIndex!=SID_PROX_GRENADE_READYTOBLOW) + { + Sound_Stop(ghostData->SoundHandle); + } + else + { + break; + } + } + Sound_Play(SID_PROX_GRENADE_READYTOBLOW,"de",&(dynPtr->Position),&ghostData->SoundHandle); + break; + } + } + } + } + } + + ghostData->integrity=ghostData->timer; + break; + } + default: + break; + } + } + } +} + +/* Patrick 13/10/97 -------------------------------------------------- +Added for autogun ghost support +---------------------------------------------------------------------*/ +#define AGUNGHOST_FIRINGPOINT_INFRONT 500 +#define AGUNGHOST_FIRINGPOINT_ACROSS 0 +#define AGUNGHOST_FIRINGPOINT_UP 200 + +void HandleGhostAutoGunMuzzleFlash(STRATEGYBLOCK *sbPtr, int firing) +{ + NETGHOSTDATABLOCK *ghostData; + + LOCALASSERT(sbPtr); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + LOCALASSERT(ghostData->type == I_BehaviourAutoGun); + + if(ghostData->myGunFlash) + { + /* I've already got a gun flash... */ + if(firing) + { + /* Maintain existing gun flash */ + VECTORCH position; + EULER orientation; + MATRIXCH mat; + CalculatePosnForGhostAutoGunMuzzleFlash(sbPtr, &position, &orientation); + + CreateEulerMatrix(&orientation, &mat); + TransposeMatrixCH(&mat); + + MaintainNPCGunFlashEffect(ghostData->myGunFlash, &position, &mat); + } + else + { + RemoveNPCGunFlashEffect(ghostData->myGunFlash); + ghostData->myGunFlash = NULL; + } + } + else + { + if(firing) + { + /* Need a new gun flash */ + VECTORCH position; + EULER orientation; + MATRIXCH mat; + CalculatePosnForGhostAutoGunMuzzleFlash(sbPtr, &position, &orientation); + CreateEulerMatrix(&orientation, &mat); + TransposeMatrixCH(&mat); + ghostData->myGunFlash = AddNPCGunFlashEffect(&position, &mat, SFX_MUZZLE_FLASH_AMORPHOUS); + } + } +} + +void HandleGhostAutoGunSound(STRATEGYBLOCK *sbPtr, int firing) +{ + NETGHOSTDATABLOCK *ghostData; + AVP_BEHAVIOUR_TYPE type; + + LOCALASSERT(sbPtr); + LOCALASSERT(sbPtr->DynPtr); + + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + type = ghostData->type; + LOCALASSERT(type==I_BehaviourAutoGun); + + if(firing) + { + if(ghostData->SoundHandle == SOUND_NOACTIVEINDEX) + Sound_Play(SID_SENTRY_GUN,"eld",&(ghostData->SoundHandle),&(sbPtr->DynPtr->Position)); + /* don't need sound update, as autoguns don't move */ + } + else if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) + { + Sound_Stop(ghostData->SoundHandle); + Sound_Play(SID_SENTRY_END,"hd",&(sbPtr->DynPtr->Position)); + } +} + +static void CalculatePosnForGhostAutoGunMuzzleFlash(STRATEGYBLOCK *sbPtr,VECTORCH *position, EULER *orientation) +{ + VECTORCH upNormal = {0,-65536,0}; + VECTORCH inFrontVec = {0,0,0}; + VECTORCH toSideVec = {0,0,0}; + EULER firingOrient = {0,0,0}; + + /* orientation is easy */ + firingOrient.EulerY = sbPtr->DynPtr->OrientEuler.EulerY; + *orientation = firingOrient; + + /* vector in front */ + inFrontVec.vx = GetSin(firingOrient.EulerY); + inFrontVec.vz = GetCos(firingOrient.EulerY); + Normalise(&inFrontVec); + + /* vectors in front, to side, and up */ + CrossProduct(&inFrontVec,&upNormal,&toSideVec); + LOCALASSERT(toSideVec.vy==0); + inFrontVec.vx = MUL_FIXED(inFrontVec.vx,AGUNGHOST_FIRINGPOINT_INFRONT); + inFrontVec.vz = MUL_FIXED(inFrontVec.vz,AGUNGHOST_FIRINGPOINT_INFRONT); + toSideVec.vx = MUL_FIXED(toSideVec.vx,AGUNGHOST_FIRINGPOINT_ACROSS); + toSideVec.vz = MUL_FIXED(toSideVec.vz,AGUNGHOST_FIRINGPOINT_ACROSS); + + position->vx = sbPtr->DynPtr->Position.vx + inFrontVec.vx + toSideVec.vx; + position->vy = sbPtr->DynPtr->Position.vy - AGUNGHOST_FIRINGPOINT_UP; + position->vz = sbPtr->DynPtr->Position.vz + inFrontVec.vz + toSideVec.vz; +} + +/* patrick 14/10/97 : added to support cloaked predators in net game */ +void MaintainGhostCloakingStatus(STRATEGYBLOCK *sbPtr, int IsCloaked) +{ + NETGHOSTDATABLOCK *ghostData; + AVP_BEHAVIOUR_TYPE type; + + LOCALASSERT(sbPtr); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + type = ghostData->type; + + if(type!=I_BehaviourPredatorPlayer) + { + ghostData->CloakingEffectiveness = 0; + return; + } + + /* Handle sound playing. */ + if (ghostData->CloakingEffectiveness) { + if (IsCloaked==0) { + /* Cloak turns off. */ + Sound_Play(SID_PRED_CLOAKOFF,"hd",&(sbPtr->DynPtr->Position)); + } + } else { + if (IsCloaked) { + /* Cloak turns on. */ + Sound_Play(SID_PRED_CLOAKON,"hd",&(sbPtr->DynPtr->Position)); + } + } + + ghostData->CloakingEffectiveness = IsCloaked; +} + + +/* KJL 14:18:32 27/01/98 - object behaviour for network ghosts */ +extern void NetGhostBehaviour(STRATEGYBLOCK *sbPtr) +{ + NETGHOSTDATABLOCK *ghostDataPtr; + + LOCALASSERT(sbPtr); + + ghostDataPtr = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostDataPtr); + + switch(ghostDataPtr->type) + { + case I_BehaviourNetCorpse: + { + /* A copy of the fn. for real ones, minus existance. */ + DISPLAYBLOCK *dispPtr = sbPtr->SBdptr; + + /* do we have a displayblock? */ + if (dispPtr) + { + dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND; + dispPtr->ObFlags2 = ghostDataPtr->timer/2; + + } + + /* Does the corpse that falls when not visible make no sound? */ + ProveHModel_Far(&ghostDataPtr->HModelController,sbPtr); + ghostDataPtr->timer-=NormalFrameTime; + break; + } + default: + break; + } + + if (sbPtr->SBdptr) { + if (sbPtr->SBdptr->HModelControlBlock) { + + /* Fire sound code. */ + if(ghostDataPtr->SoundHandle3!=SOUND_NOACTIVEINDEX) Sound_Update3d(ghostDataPtr->SoundHandle3,&(sbPtr->DynPtr->Position)); + if(ghostDataPtr->SoundHandle4!=SOUND_NOACTIVEINDEX) Sound_Update3d(ghostDataPtr->SoundHandle4,&(sbPtr->DynPtr->Position)); + + if (sbPtr->SBDamageBlock.IsOnFire) { + if (ghostDataPtr->IgnitionHandshaking==0) { + AddNetMsg_LocalObjectOnFire(sbPtr); + } + if (ghostDataPtr->SoundHandle3!=SOUND_NOACTIVEINDEX) { + if (ActiveSounds[ghostDataPtr->SoundHandle3].soundIndex!=SID_FIRE) { + Sound_Stop(ghostDataPtr->SoundHandle3); + Sound_Play(SID_FIRE,"dlev",&(sbPtr->DynPtr->Position),&ghostDataPtr->SoundHandle3,127); + } + } else { + Sound_Play(SID_FIRE,"dlev",&(sbPtr->DynPtr->Position),&ghostDataPtr->SoundHandle3,127); + } + } else { + if (ghostDataPtr->SoundHandle3!=SOUND_NOACTIVEINDEX) { + Sound_Stop(ghostDataPtr->SoundHandle3); + } + } + } + } + + if(ghostDataPtr->FlameHitCount) + { + //send a damage message for all the flame particles that have hit + CauseDamageToObject(sbPtr,&TemplateAmmo[AMMO_FLAMETHROWER].MaxDamage[AvP.Difficulty], (ONE_FIXED/400)*ghostDataPtr->FlameHitCount,NULL); + ghostDataPtr->FlameHitCount=0; + + } + if(ghostDataPtr->FlechetteHitCount) + { + //send a damage message for all the flechette particles that have hit + extern DAMAGE_PROFILE FlechetteDamage; + CauseDamageToObject(sbPtr,&FlechetteDamage,ONE_FIXED*ghostDataPtr->FlechetteHitCount,NULL); + ghostDataPtr->FlechetteHitCount=0; + + } +} + +void MaintainGhostFireStatus(STRATEGYBLOCK *sbPtr, int IsOnFire) +{ + NETGHOSTDATABLOCK *ghostData; + + LOCALASSERT(sbPtr); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + if (IsOnFire) { + if (ghostData->IgnitionHandshaking==0) { + /* Recieved confirmation. */ + ghostData->IgnitionHandshaking=1; + if (sbPtr->SBDamageBlock.IsOnFire==0) { + /* Set alight by something else? */ + sbPtr->SBDamageBlock.IsOnFire=1; + } + } else { + /* Corroberated - do nothing. */ + } + } else { + if (ghostData->IgnitionHandshaking==0) { + /* Corroberated - do nothing. */ + } else { + /* Fire gone out? */ + ghostData->IgnitionHandshaking=0; + sbPtr->SBDamageBlock.IsOnFire=0; + } + } +} + +void Engage_Template_Death(STRATEGYBLOCK *sbPtr,SECTION *root,HMODELCONTROLLER *controller,int type, int subtype, + int length, int tweening) { + + RemoveAllDeltas(controller); + Transmogrify_HModels(sbPtr,controller, root, 1, 0,0); + InitHModelTweening(controller,tweening,type,subtype,length,0); + +} + +void Create_Marine_Standing_Template_Death(STRATEGYBLOCK *sbPtr,HMODELCONTROLLER *controller,int type, int subtype, + int length, int tweening) { + + /* Standing template. */ + SECTION *root; + + /* This has gotta be considered weird. */ + InitHModelSequence(controller,(int)HMSQT_MarineStand, + (int)MSSS_Dies_Standard,(ONE_FIXED<<1)); + ProveHModel_Far(controller,sbPtr); + /* And now we change it. See? */ + + root=GetNamedHierarchyFromLibrary("hnpcmarine","Template"); + + Engage_Template_Death(sbPtr,root,controller,type,subtype,length,tweening); + +} + +void Create_Predator_Standing_Template_Death(STRATEGYBLOCK *sbPtr,HMODELCONTROLLER *controller,int type, int subtype, + int length, int tweening) { + + /* Standing template. */ + SECTION *root; + + /* This has gotta be considered weird. */ + InitHModelSequence(controller,(int)HMSQT_PredatorStand, + (int)PSSS_Dies_Standard,(ONE_FIXED<<1)); + ProveHModel_Far(controller,sbPtr); + /* And now we change it. See? */ + + root=GetNamedHierarchyFromLibrary("hnpcpredator","Template"); + + Engage_Template_Death(sbPtr,root,controller,type,subtype,length,tweening); +} + +/* Kills a ghost, to leave a corpse */ +void KillGhost(STRATEGYBLOCK *sbPtr,int objectId) +{ + NETGHOSTDATABLOCK *ghostData; + + LOCALASSERT(sbPtr); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + /* this is where we add fragmentation and explosion effects to destroyed ghosts */ + switch(ghostData->type) + { + case(I_BehaviourAlienPlayer): + case(I_BehaviourMarinePlayer): + case(I_BehaviourPredatorPlayer): + { + /* Drop through, for the moment. */ + #if EXTRAPOLATION_TEST + sbPtr->DynPtr->LinImpulse.vx=0; + sbPtr->DynPtr->LinImpulse.vy=0; + sbPtr->DynPtr->LinImpulse.vz=0; + + sbPtr->DynPtr->LinVelocity.vx=0; + sbPtr->DynPtr->LinVelocity.vy=0; + sbPtr->DynPtr->LinVelocity.vz=0; + + sbPtr->DynPtr->UseStandardGravity=1; + + sbPtr->DynPtr->IsNetGhost=1; + + sbPtr->DynPtr->ToppleForce=TOPPLE_FORCE_NONE; + + #endif + break; + } + case(I_BehaviourGrenade): + case(I_BehaviourRocket): + case(I_BehaviourProximityGrenade): + case(I_BehaviourFragmentationGrenade): + case(I_BehaviourClusterGrenade): + case(I_BehaviourPulseGrenade): + case(I_BehaviourNPCPredatorDisc): + case(I_BehaviourPredatorDisc_SeekTrack): + case(I_BehaviourAlienSpit): + case(I_BehaviourInanimateObject): + default: + { + /* Default to something else. */ + RemoveGhost(sbPtr); + return; + break; + } + } + + /* see if we've got a sound... */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + if(ghostData->SoundHandle2 != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle2); + if(ghostData->SoundHandle3 != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle3); + if(ghostData->SoundHandle4 != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle4); + + /* see if we've got a muzzle flash... */ + if(ghostData->myGunFlash) + { + RemoveNPCGunFlashEffect(ghostData->myGunFlash); + ghostData->myGunFlash = NULL; + } + + /* Now.. you're a ghost. Of a corpse. */ + +/*--------------------------------------------------------------------** +** The animation sequence we should use will come in a later message ** +**--------------------------------------------------------------------*/ + + ghostData->subtype=ghostData->type; + ghostData->type=I_BehaviourNetCorpse; + ghostData->IOType=IOT_Non; + ghostData->playerObjectId=objectId; + ghostData->timer=CORPSE_EXPIRY_TIME; /* Arbitrarily */ + + if (ghostData->HModelController.Deltas) { + RemoveAllDeltas(&ghostData->HModelController); + } + + sbPtr->DynPtr->OnlyCollideWithEnvironment = 1; + + //allow the corpse to fall to the floor + sbPtr->DynPtr->GravityOn=1; + + /* And the final touch. */ +// KillRandomSections(ghostData->HModelController.section_data,(ONE_FIXED>>2)); +} + +extern void ApplyGhostCorpseDeathAnim(STRATEGYBLOCK *sbPtr,int deathId) +{ + extern DEATH_DATA Marine_Deaths[]; + extern DEATH_DATA Alien_Deaths[]; + extern DEATH_DATA Predator_Deaths[]; + DEATH_DATA* this_death; + + NETGHOSTDATABLOCK *ghostData; + LOCALASSERT(sbPtr); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + if(ghostData->type!=I_BehaviourNetCorpse) return; + + switch(ghostData->subtype) + { + case I_BehaviourMarinePlayer : + { + this_death=GetThisDeath_FromCode(&ghostData->HModelController,&Marine_Deaths[0],deathId); + if (this_death->Template) + { + SECTION* template_root=GetNamedHierarchyFromLibrary("hnpcmarine","Template"); + LOCALASSERT(template_root); + /* Convert to template. */ + Transmogrify_HModels(sbPtr,&ghostData->HModelController, + template_root, 0, 0,0); + } + else + { + SECTION* template_root=GetNamedHierarchyFromLibrary("hnpcmarine","Template"); + LOCALASSERT(template_root); + /* Convert to template. */ + TrimToTemplate(sbPtr,&ghostData->HModelController, + template_root, 0); + } + } + break; + + case I_BehaviourPredatorPlayer : + { + this_death=GetThisDeath_FromCode(&ghostData->HModelController,&Predator_Deaths[0],deathId); + if (this_death->Template) + { + SECTION* template_root=GetNamedHierarchyFromLibrary("hnpcpredator","Template"); + LOCALASSERT(template_root); + /* Convert to template. */ + Transmogrify_HModels(sbPtr,&ghostData->HModelController, + template_root, 1, 0,0); + } + } + break; + + case I_BehaviourAlienPlayer : + { + this_death=GetThisDeath_FromCode(&ghostData->HModelController,&Alien_Deaths[0],deathId); + } + break; + + default : + return; + + } + + + if(this_death->TweeningTime<=0) + { + InitHModelSequence(&ghostData->HModelController,this_death->Sequence_Type,this_death->Sub_Sequence,this_death->Sequence_Length); + } + else + { + InitHModelTweening(&ghostData->HModelController, this_death->TweeningTime,this_death->Sequence_Type,this_death->Sub_Sequence,this_death->Sequence_Length,0); + } + + /* Electric death sound? */ + if (this_death->Electrical) { + Sound_Play(SID_ED_ELEC_DEATH,"de",&sbPtr->DynPtr->Position,&ghostData->SoundHandle4); + } + +} + +extern void ApplyCorpseDeathAnim(STRATEGYBLOCK *sbPtr,int deathId) +{ + extern DEATH_DATA Marine_Deaths[]; + extern DEATH_DATA Alien_Deaths[]; + extern DEATH_DATA Predator_Deaths[]; + DEATH_DATA* this_death; + + NETCORPSEDATABLOCK *corpseDataPtr=(NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + + switch(corpseDataPtr->Type) + { + case I_BehaviourMarinePlayer : + { + this_death=GetThisDeath_FromCode(&corpseDataPtr->HModelController,&Marine_Deaths[0],deathId); + if (this_death->Template) + { + SECTION* template_root=GetNamedHierarchyFromLibrary("hnpcmarine","Template"); + LOCALASSERT(template_root); + /* Convert to template. */ + Transmogrify_HModels(sbPtr,&corpseDataPtr->HModelController, + template_root, 0, 0,0); + } + else + { + SECTION* template_root=GetNamedHierarchyFromLibrary("hnpcmarine","Template"); + LOCALASSERT(template_root); + /* Convert to template. */ + TrimToTemplate(sbPtr,&corpseDataPtr->HModelController, + template_root, 0); + } + } + break; + + case I_BehaviourPredatorPlayer : + { + this_death=GetThisDeath_FromCode(&corpseDataPtr->HModelController,&Predator_Deaths[0],deathId); + if (this_death->Template) + { + SECTION* template_root=GetNamedHierarchyFromLibrary("hnpcpredator","Template"); + LOCALASSERT(template_root); + /* Convert to template. */ + Transmogrify_HModels(sbPtr,&corpseDataPtr->HModelController, + template_root, 1, 0,0); + } + } + break; + + case I_BehaviourAlienPlayer : + { + this_death=GetThisDeath_FromCode(&corpseDataPtr->HModelController,&Alien_Deaths[0],deathId); + } + break; + + default : + return; + + } + + + if(this_death->TweeningTime<=0) + { + InitHModelSequence(&corpseDataPtr->HModelController,this_death->Sequence_Type,this_death->Sub_Sequence,this_death->Sequence_Length); + } + else + { + InitHModelTweening(&corpseDataPtr->HModelController, this_death->TweeningTime,this_death->Sequence_Type,this_death->Sub_Sequence,this_death->Sequence_Length,0); + } + corpseDataPtr->This_Death=this_death; + + /* Electric death sound? */ + if (this_death->Electrical) { + Sound_Play(SID_ED_ELEC_DEATH,"de",&sbPtr->DynPtr->Position,&corpseDataPtr->SoundHandle4); + } + +} + +extern void KillAlienAIGhost(STRATEGYBLOCK *sbPtr,int death_code,int death_time,int GibbFactor) { + + NETGHOSTDATABLOCK *ghostData; + DEATH_DATA *this_death; + + LOCALASSERT(sbPtr); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + LOCALASSERT(ghostData); + + + /* To ensure we know what we're doing... */ + if (ghostData->type!=I_BehaviourAlien) { + GLOBALASSERT(0); + } + + if(ghostData->onlyValidFar) + { + RemoveGhost(sbPtr); + return; + } + + this_death=GetThisDeath_FromCode(&ghostData->HModelController,Alien_Deaths,death_code); + GLOBALASSERT(this_death); + + /* see if we've got a sound... */ + if(ghostData->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle); + if(ghostData->SoundHandle2 != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle2); + if(ghostData->SoundHandle3 != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle3); + if(ghostData->SoundHandle4 != SOUND_NOACTIVEINDEX) Sound_Stop(ghostData->SoundHandle4); + + /* see if we've got a muzzle flash... */ + if(ghostData->myGunFlash) + { + RemoveNPCGunFlashEffect(ghostData->myGunFlash); + ghostData->myGunFlash = NULL; + } + + /* Convert that sucker. */ + ghostData->type=I_BehaviourNetCorpse; + /* + Alien subtype (alien/predalien/praetorian) gets shuffled down into IOType. + Not entirely appropriate , but it will do... + */ + ghostData->IOType=ghostData->subtype; + ghostData->subtype=I_BehaviourAlien; + ghostData->timer=death_time; + + if (ghostData->HModelController.Deltas) { + RemoveAllDeltas(&ghostData->HModelController); + } + /* Now let's do the sequence. */ + UpdateAlienAIGhostAnimSequence(sbPtr,this_death->Sequence_Type,this_death->Sub_Sequence, + this_death->Sequence_Length,this_death->TweeningTime); + ghostData->HModelController.LoopAfterTweening=0; + + //Allow players to walk through the corpse + sbPtr->DynPtr->OnlyCollideWithEnvironment = 1; + + #if EXTRAPOLATION_TEST + sbPtr->DynPtr->LinImpulse.vx=0; + sbPtr->DynPtr->LinImpulse.vy=0; + sbPtr->DynPtr->LinImpulse.vz=0; + + sbPtr->DynPtr->LinVelocity.vx=0; + sbPtr->DynPtr->LinVelocity.vy=0; + sbPtr->DynPtr->LinVelocity.vz=0; + + sbPtr->DynPtr->UseStandardGravity=1; + + sbPtr->DynPtr->IsNetGhost=1; + + sbPtr->DynPtr->ToppleForce=TOPPLE_FORCE_NONE; + #endif + //allow the corpse to fall to the floor + sbPtr->DynPtr->GravityOn=1; + + /* Gibb the corpse? */ + if (GibbFactor) { + DoAlienLimbLossSound(&sbPtr->DynPtr->Position); + Extreme_Gibbing(sbPtr,ghostData->HModelController.section_data,GibbFactor); + } + + /* Electric death sound? */ + if (this_death->Electrical) { + Sound_Play(SID_ED_ELEC_DEATH,"de",&sbPtr->DynPtr->Position,&ghostData->SoundHandle4); + } + +} + +int Deduce_PlayerDeathSequence(void) { + + int a; + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr); + + a=((FastRandom()&65535)>>12)&14; /* 0,2,4,6,8,10,12,14 */ + if (playerStatusPtr->ShapeState == PMph_Crouching) { + return(a); + } else { + return(a+1); + } + +} + +int Deduce_PlayerMarineDeathSequence(STRATEGYBLOCK* sbPtr,DAMAGE_PROFILE* damage,int multiple,VECTORCH* incoming) +{ + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr); + NETCORPSEDATABLOCK *corpseDataPtr=(NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + + int deathtype,gibbFactor; + int a; + + SECTION_DATA *head; + + /* Set GibbFactor and death type*/ + gibbFactor=0; + { + int tkd; + + tkd=TotalKineticDamage(damage); + deathtype=0; + + if (damage->ExplosivePower==1) { + if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) { + /* Okay, you can gibb now. */ + gibbFactor=ONE_FIXED>>1; + deathtype=2; + } + } else if ((tkd>60)&&((multiple>>16)>1)) { + int newmult; + + newmult=DIV_FIXED(multiple,NormalFrameTime); + if (MUL_FIXED(tkd,newmult)>(500)) { + /* Loadsabullets! */ + gibbFactor=-(ONE_FIXED>>2); + deathtype=2; + } + } + + if ((damage->ExplosivePower==2)||(damage->ExplosivePower==6)) { + /* Basically SADARS only. */ + gibbFactor=ONE_FIXED; + deathtype=3; + } + } + + if (damage->ForceBoom) { + deathtype+=damage->ForceBoom; + } + + { + SECTION_DATA *chest; + + chest=GetThisSectionData(corpseDataPtr->HModelController.section_data,"chest"); + + if (chest==NULL) { + /* I'm impressed. */ + deathtype+=2; + } else if ((chest->flags§ion_data_notreal) + &&(chest->flags§ion_data_terminate_here)) { + /* That's gotta hurt. */ + deathtype++; + } + } + + + /* Now final stage. */ + { + DEATH_DATA *this_death; + HIT_FACING facing; + SECTION *root; + int burning,electrical; + int crouched; + + root=GetNamedHierarchyFromLibrary("hnpcmarine","Template"); + + facing.Front=0; + facing.Back=0; + facing.Left=0; + facing.Right=0; + + if (incoming) { + if (incoming->vz>0) { + facing.Back=1; + } else { + facing.Front=1; + } + if (incoming->vx>0) { + facing.Right=1; + } else { + facing.Left=1; + } + } + + if ((playerStatusPtr->fireTimer>0) + &&(damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire>0) + &&(damage->Electrical==0) + &&(damage->Acid==0) + ) { + burning=1; + } else { + burning=0; + } + + if ((damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire==0) + &&(damage->Electrical>0) + &&(damage->Acid==0) + ) { + electrical=1; + } else { + electrical=0; + } + + if (playerStatusPtr->ShapeState == PMph_Crouching) + { + crouched=1; + } + else + { + crouched=0; + } + + this_death=GetMarineDeathSequence(&corpseDataPtr->HModelController,root,corpseDataPtr->Wounds,corpseDataPtr->Wounds, + deathtype,&facing,burning,crouched,electrical); + + GLOBALASSERT(this_death); + + return this_death->Multiplayer_Code; + } +} + +int Deduce_PlayerAlienDeathSequence(STRATEGYBLOCK* sbPtr,DAMAGE_PROFILE* damage,int multiple,VECTORCH* incoming) +{ + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr); + NETCORPSEDATABLOCK *corpseDataPtr=(NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + + int tkd,deathtype; + + /* Get death type. */ + tkd=TotalKineticDamage(damage); + deathtype=0; + + if (damage->ExplosivePower==1) { + /* Explosion case. */ + if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) { + /* Okay, you can gibb now. */ + deathtype=2; + } + } else if ((tkd<40)&&((multiple>>16)>1)) { + int newmult; + + newmult=DIV_FIXED(multiple,NormalFrameTime); + if (MUL_FIXED(tkd,newmult)>700) { + /* Excessive bullets case 1. */ + deathtype=2; + } else if (MUL_FIXED(tkd,newmult)>250) { + /* Excessive bullets case 2. */ + deathtype=1; + } + } + + if ((damage->ExplosivePower==2)||(damage->ExplosivePower==6)) { + /* Basically SADARS only. */ + deathtype=3; + } + + if (damage->ForceBoom) { + deathtype+=damage->ForceBoom; + } + + { + SECTION_DATA *chest=GetThisSectionData(corpseDataPtr->HModelController.section_data,"chest"); + + if (chest==NULL) { + /* I'm impressed. */ + deathtype+=2; + } else if ((chest->flags§ion_data_notreal) + &&(chest->flags§ion_data_terminate_here)) { + /* That's gotta hurt. */ + deathtype++; + } + } + + { + + + DEATH_DATA *this_death; + HIT_FACING facing; + int crouched; + + facing.Front=0; + facing.Back=0; + facing.Left=0; + facing.Right=0; + + if (incoming) { + if (incoming->vz>0) { + facing.Back=1; + } else { + facing.Front=1; + } + if (incoming->vx>0) { + facing.Right=1; + } else { + facing.Left=1; + } + } + if (playerStatusPtr->ShapeState == PMph_Crouching) + { + crouched=1; + } + else + { + crouched=0; + } + + this_death=GetAlienDeathSequence(&corpseDataPtr->HModelController,NULL,corpseDataPtr->Wounds,corpseDataPtr->Wounds, + deathtype,&facing,0,crouched,0); + + return this_death->Multiplayer_Code; + } + +} + +int Deduce_PlayerPredatorDeathSequence(STRATEGYBLOCK* sbPtr,DAMAGE_PROFILE* damage,int multiple,VECTORCH* incoming) +{ + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr); + NETCORPSEDATABLOCK *corpseDataPtr=(NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + + int deathtype=0; + int tkd = TotalKineticDamage(damage); + + if (damage->ExplosivePower==1) { + if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) { + /* Okay, you can... splat now. */ + deathtype=2; + } + } else if ((tkd<40)&&((multiple>>16)>1)) { + int newmult; + + newmult=DIV_FIXED(multiple,NormalFrameTime); + if (MUL_FIXED(tkd,newmult)>(500)) { + deathtype=2; + } + } + + if ((damage->ExplosivePower==2)||(damage->ExplosivePower==6)) { + /* Basically SADARS only. */ + deathtype=3; + } + + if (damage->ForceBoom) { + deathtype+=damage->ForceBoom; + } + + { + SECTION_DATA *chest; + + chest=GetThisSectionData(corpseDataPtr->HModelController.section_data,"chest"); + + if (chest==NULL) { + /* I'm impressed. */ + deathtype+=2; + } else if ((chest->flags§ion_data_notreal) + &&(chest->flags§ion_data_terminate_here)) { + /* That's gotta hurt. */ + deathtype++; + } + } + + { + DEATH_DATA *this_death; + HIT_FACING facing; + SECTION *root; + int burning; + int wounds; + int crouched; + + root=GetNamedHierarchyFromLibrary("hnpcpredator","Template"); + + facing.Front=0; + facing.Back=0; + facing.Left=0; + facing.Right=0; + + if (incoming) { + if (incoming->vz>0) { + facing.Back=1; + } else { + facing.Front=1; + } + if (incoming->vx>0) { + facing.Right=1; + } else { + facing.Left=1; + } + } + + if ((damage->Impact==0) + &&(damage->Cutting==0) + &&(damage->Penetrative==0) + &&(damage->Fire>0) + &&(damage->Electrical==0) + &&(damage->Acid==0) + ) { + burning=1; + } else { + burning=0; + } + + if (playerStatusPtr->ShapeState == PMph_Crouching) + { + crouched=1; + } + else + { + crouched=0; + } + + this_death=GetPredatorDeathSequence(&corpseDataPtr->HModelController,root,corpseDataPtr->Wounds, + corpseDataPtr->Wounds,deathtype,&facing,burning,crouched,0); + + GLOBALASSERT(this_death); + + + return this_death->Multiplayer_Code; + } + +} + +STRATEGYBLOCK *MakeNewCorpse() +{ + int i; + STRATEGYBLOCK *sbPtr; + SECTION *root_section; + signed char weapon; + NETCORPSEDATABLOCK *corpseData; + PLAYER_WEAPON_DATA *weaponPtr; + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr); + + LOCALASSERT(playerStatusPtr); + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + weapon = (signed char)(weaponPtr->WeaponIDNumber); + + /* create a strategy block - same as for a ghost */ + sbPtr = CreateActiveStrategyBlock(); + if(!sbPtr) + { + /* allocation failed */ + return NULL; + } + InitialiseSBValues(sbPtr); + sbPtr->I_SBtype = I_BehaviourNetCorpse; + + for(i = 0; i < SB_NAME_LENGTH; i++) sbPtr->SBname[i] = '\0'; + AssignNewSBName(sbPtr); + + /* dynamics block */ + { + DYNAMICSBLOCK *dynPtr; + + /* need different templates for objects and sprites */ + dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_MARINE_PLAYER); + if(!dynPtr) + { + /* allocation failed */ + RemoveBehaviourStrategy(sbPtr); + return NULL; + } + dynPtr->CanClimbStairs = 0; + dynPtr->IgnoreThePlayer = 1; + + sbPtr->DynPtr = dynPtr; + /* zero linear velocity in dynamics block */ + dynPtr->LinVelocity.vx = dynPtr->LinVelocity.vy = dynPtr->LinVelocity.vz = 0; + dynPtr->LinImpulse.vx = dynPtr->LinImpulse.vy = dynPtr->LinImpulse.vz = 0; + dynPtr->GravityOn = 1; + dynPtr->UseStandardGravity = 1; + + dynPtr->Position = dynPtr->PrevPosition = Player->ObStrategyBlock->DynPtr->Position; + dynPtr->OrientEuler = Player->ObStrategyBlock->DynPtr->OrientEuler; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + + } + + sbPtr->maintainVisibility = 1; + sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), 0); + + /* data block */ + { + corpseData = AllocateMem(sizeof(NETCORPSEDATABLOCK)); + if(!corpseData) + { + /* allocation failed */ + RemoveBehaviourStrategy(sbPtr); + return NULL; + } + sbPtr->SBdataptr = (void *)corpseData; + corpseData->SoundHandle = SOUND_NOACTIVEINDEX; + corpseData->SoundHandle2 = SOUND_NOACTIVEINDEX; + corpseData->SoundHandle3 = SOUND_NOACTIVEINDEX; + corpseData->SoundHandle4 = SOUND_NOACTIVEINDEX; + + switch(AvP.PlayerType) + { + case I_Marine : + corpseData->Type=I_BehaviourMarinePlayer; + break; + case I_Alien : + corpseData->Type=I_BehaviourAlienPlayer; + break; + case I_Predator : + corpseData->Type=I_BehaviourPredatorPlayer; + break; + } + corpseData->GibbFactor=0; + corpseData->This_Death=NULL; + + /* Clear cloak data... */ + corpseData->CloakStatus = PCLOAK_Off; + corpseData->CloakTimer = 0; + corpseData->destructTimer = -1; + /* Clear deathfiring stuff... */ + corpseData->WeaponMisfireFunction=NULL; + corpseData->My_Gunflash_Section=NULL; + corpseData->weapon_variable=0; + corpseData->Android=0; + corpseData->TemplateRoot=NULL; + corpseData->DeathFiring=0; + corpseData->hltable=NULL; + + corpseData->Wounds=0; + + /* set the shape */ + switch(AvP.PlayerType) + { + case(I_Marine): + { + + corpseData->hltable=GetThisHitLocationTable("marine with pulse rifle"); + /* Select hierarchy from character's selected weapon. */ + //while we're at it , also deal with creating the pickupable weapon + { + + VECTORCH location=Player->ObStrategyBlock->DynPtr->Position; + STRATEGYBLOCK* weaponSbPtr = CreateMultiplayerWeaponPickup(&location,weapon,0); + if(weaponSbPtr) + { + //hide the newly created weapon from this player , until the player respawns + weaponSbPtr->maintainVisibility=0; + } + } + switch (weapon) + { + default: + case WEAPON_PULSERIFLE: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","marine with pulse rifle"); + break; + } + case WEAPON_TWO_PISTOLS: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","Two Pistol"); + break; + } + case WEAPON_MARINE_PISTOL: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","PISTOL"); + break; + } + case WEAPON_FLAMETHROWER: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","marine with flame thrower"); + break; + } + case WEAPON_SMARTGUN: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","marine with smart gun"); + break; + } + case WEAPON_MINIGUN: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","Marine with Mini Gun"); + break; + } + case WEAPON_SADAR: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","marine with SADAR"); + break; + } + case WEAPON_GRENADELAUNCHER: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","marine + grenade launcher"); + break; + } + case WEAPON_CUDGEL: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","Cudgel"); + break; + } + case WEAPON_FRISBEE_LAUNCHER: + { + root_section = GetNamedHierarchyFromLibrary("hnpcmarine","skeeter"); + break; + } + } + Create_HModel(&corpseData->HModelController,root_section); + { + extern DPID AVPDPNetID; + ChangeGhostMarineAccoutrementSet(&corpseData->HModelController,AVPDPNetID); + } + //choose a default sequence , the proper death anim will be set later + InitHModelSequence(&corpseData->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Standard,ONE_FIXED); + + break; + } + case(I_Alien): + { + corpseData->hltable=GetThisHitLocationTable("alien"); + + root_section = GetNamedHierarchyFromLibrary("hnpcalien","alien"); + Create_HModel(&corpseData->HModelController,root_section); + + //choose a default sequence , the proper death anim will be set later + InitHModelSequence(&corpseData->HModelController,(int)HMSQT_AlienStand,(int)ASSS_Standard,ONE_FIXED); + break; + } + case(I_Predator): + { + corpseData->hltable=GetThisHitLocationTable("predator"); + switch (weapon) + { + default: + case WEAPON_PRED_WRISTBLADE: + { + root_section = GetNamedHierarchyFromLibrary("hnpcpredator","pred with wristblade"); + break; + } + case WEAPON_PRED_RIFLE: + { + root_section = GetNamedHierarchyFromLibrary("hnpcpredator","Speargun"); + break; + } + case WEAPON_PRED_PISTOL: + { + root_section = GetNamedHierarchyFromLibrary("hnpcpredator","pred + pistol"); + break; + } + case WEAPON_PRED_SHOULDERCANNON: + { + root_section = GetNamedHierarchyFromLibrary("hnpcpredator","pred with Plasma Caster"); + break; + } + case WEAPON_PRED_DISC: + { + root_section = GetNamedHierarchyFromLibrary("hnpcpredator","pred with disk"); + break; + } + case WEAPON_PRED_MEDICOMP: + { + root_section = GetNamedHierarchyFromLibrary("hnpcpredator","medicomp"); + break; + } + } + Create_HModel(&corpseData->HModelController,root_section); + + //choose a default sequence , the proper death anim will be set later + InitHModelSequence(&corpseData->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_Elevation,ONE_FIXED); + break; + } + } + } + /* Now fix timer. */ + corpseData->timer=CORPSE_EXPIRY_TIME; /* Arbitrarily */ + corpseData->validityTimer=CORPSE_VALIDITY_TIME; + corpseData->HModelController.Looped=0; + ProveHModel_Far(&corpseData->HModelController,sbPtr); + MakeCorpseNear(sbPtr); + GLOBALASSERT(sbPtr->SBdptr); + sbPtr->SBdptr->ObFlags|=ObFlag_NotVis; + /* And the fire. */ + + if (Player->ObStrategyBlock->SBDamageBlock.IsOnFire) { + sbPtr->SBDamageBlock.IsOnFire=1; + } + /* Defaults to zero. */ + + if (playerStatusPtr->soundHandle3!=SOUND_NOACTIVEINDEX) { + if (ActiveSounds[playerStatusPtr->soundHandle3].soundIndex==SID_FIRE) { + /* Pass fire sound across. */ + corpseData->SoundHandle3=playerStatusPtr->soundHandle3; + playerStatusPtr->soundHandle3=SOUND_NOACTIVEINDEX; + } + } + + /* And the final touch. */ +// KillRandomSections(corpseData->HModelController.section_data,(ONE_FIXED>>2)); + + return(sbPtr); +} + +void UpdateAlienAIGhostAnimSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime) +{ + + NETGHOSTDATABLOCK *ghostData; + + LOCALASSERT(sbPtr); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + + GLOBALASSERT(length!=0); + + + + /* Are we already playing this one? */ + if ((ghostData->HModelController.Sequence_Type==type)&&(ghostData->HModelController.Sub_Sequence==subtype)) { + /* Yes, but... */ + /*I think we only want to change speed if we're not tweening*/ + if (tweeningtime<=0) + { + if (length!=ghostData->HModelController.Seconds_For_Sequence) { + HModel_ChangeSpeed(&ghostData->HModelController,length); + } + } + + } else if (tweeningtime<=0) { + InitHModelSequence(&ghostData->HModelController,(int)type,subtype,length); + } else { + InitHModelTweening(&ghostData->HModelController, tweeningtime, (int)type,subtype,length, 1); + } + + ghostData->HModelController.Playing=1; + /* Might be unset... */ +} + +/* This a copy of UpdateGhost, with extra parameters. */ +void UpdateAlienAIGhost(STRATEGYBLOCK *sbPtr,VECTORCH *position,EULER *orientation,int sequence_type,int sub_sequence, int sequence_length) +{ + NETGHOSTDATABLOCK *ghostData; + + LOCALASSERT(sbPtr); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + + /* for visibility support: as ghosts can be moved when invisible, we need to work out + which module they're in whenever we update them. We must be carefull, however, not + to set the containingModule to NULL if the object has moved outside the env, as + the visibility system expects that we at least know what module any object WAS in, + even if we do not now... thus, if we cannot find a containing module, we abort the update */ + + /* KJL 21:01:09 23/05/98 - I've put this test here because the player's image in a mirror goes + throught this code, and it's obviously going to be outside the environment */ + if (sbPtr->I_SBtype==I_BehaviourNetGhost) + { + MODULE *myContainingModule = ModuleFromPosition(position, (sbPtr->containingModule)); + if(myContainingModule==NULL) return; + sbPtr->containingModule = myContainingModule; + } + + + if (ghostData->type!=I_BehaviourAlien) { + GLOBALASSERT(0); + } + + //We have enough information to be able to make this alien near (should we want to) + ghostData->onlyValidFar=0; + + /* update the dynamics block */ + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + dynPtr->PrevPosition = dynPtr->Position; + dynPtr->PrevOrientMat = dynPtr->OrientMat; + dynPtr->Position = *position; + dynPtr->OrientEuler = *orientation; + CreateEulerMatrix(&dynPtr->OrientEuler,&dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + } + + /* KJL 16:58:04 17/06/98 - we want to update anims differently for NPCS */ + if ((sequence_type!=-1)&&(sub_sequence!=-1)) { + /* Not tweening! */ + UpdateAlienAIGhostAnimSequence(sbPtr,sequence_type,sub_sequence,sequence_length,(ONE_FIXED>>2)); + } + + /* refresh integrity */ + ghostData->integrity = GHOST_INTEGRITY; +} + +void Convert_DiscGhost_To_PickupGhost(STRATEGYBLOCK *sbPtr) { + + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + NETGHOSTDATABLOCK *ghostData= (NETGHOSTDATABLOCK * ) sbPtr->SBdataptr; + /* Transmogrify a disc ghost behaviour to a disc ammo pickup! */ + + /* Sort out dynamics block */ + dynPtr->LinVelocity.vx=0; + dynPtr->LinVelocity.vy=0; + dynPtr->LinVelocity.vz=0; + + dynPtr->LinImpulse.vx=0; + dynPtr->LinImpulse.vy=0; + dynPtr->LinImpulse.vz=0; + + ghostData->type=I_BehaviourInanimateObject; + ghostData->IOType=IOT_Ammo; + ghostData->subtype=AMMO_PRED_DISC; + + ghostData->HModelController.Playing=0; + /* Deal with flip up case? */ + + /* The final shape is NOT hierarchical. */ + { + SECTION_DATA *disc_section; + disc_section=GetThisSectionData(ghostData->HModelController.section_data,"disk"); + GLOBALASSERT(disc_section); + + sbPtr->shapeIndex=disc_section->sempai->ShapeNum; + Dispel_HModel(&ghostData->HModelController); + if (sbPtr->SBdptr) { + sbPtr->SBdptr->ObShape=disc_section->sempai->ShapeNum; + sbPtr->SBdptr->ObShapeData=disc_section->sempai->Shape; + sbPtr->SBdptr->HModelControlBlock=NULL; + } + } + + if(ghostData->SoundHandle!=SOUND_NOACTIVEINDEX) + { + Sound_Stop(ghostData->SoundHandle); + } + Sound_Play(SID_DISC_STICKSINWALL,"dp",&(sbPtr->DynPtr->Position),((FastRandom()&511)-255)); + + +} + + + +void PlayHitDeltaOnGhost(STRATEGYBLOCK *sbPtr,char delta_seq,char delta_sub_seq) +{ + DELTA_CONTROLLER *hitdelta; + NETGHOSTDATABLOCK *ghostData; + + LOCALASSERT(sbPtr); + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + + //only play hit deltas on marine and predator players + if(ghostData->type!=I_BehaviourMarinePlayer && ghostData->type!=I_BehaviourPredatorPlayer) return; + + hitdelta=Get_Delta_Sequence(&ghostData->HModelController,"HitDelta"); + + if(hitdelta) + { + if (HModelSequence_Exists(&ghostData->HModelController,(int)delta_seq,(int)delta_sub_seq)) + { + Start_Delta_Sequence(hitdelta,(int)delta_seq,(int) delta_sub_seq,ONE_FIXED/2); + hitdelta->Playing=1; + } + } + +} + +void PlayOtherSound(enum soundindex SoundIndex, VECTORCH *position, int explosion) { + + if (explosion) { + Ghost_Explosion_SoundData.position=*position; + Sound_Play(SoundIndex,"n",&Ghost_Explosion_SoundData); + } else { + Sound_Play(SoundIndex,"d",position); + } + +} + + + + + + + + + + + + diff --git a/3dc/avp/win95/Pldnet.c b/3dc/avp/win95/Pldnet.c new file mode 100644 index 0000000..e26236f --- /dev/null +++ b/3dc/avp/win95/Pldnet.c @@ -0,0 +1,11526 @@ +/* Patrick 19/3/97 ----------------------------------------------------- + Source for Multi-Player game support + ----------------------------------------------------------------------*/ + +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "dynblock.h" +#include "dynamics.h" +#include "menudefs.h" +#include "menugfx.h" +#include "bh_debri.h" +#include "pvisible.h" +#include "bh_plift.h" +#include "dplayext.h" +#include "pldnet.h" +#include "dp_func.h" +#include "pldghost.h" +#include "equipmnt.h" +#include "weapons.h" +#include "multmenu.h" +#include "bh_gener.h" +#include "psnd.h" +#include "kshape.h" +#include "pfarlocs.h" + +/* these required sequence enumerations...*/ +#include "bh_pred.h" +#include "bh_alien.h" +#include "bh_marin.h" +#include "bh_binsw.h" +#include "bh_agun.h" +#include "bh_weap.h" + +#include "bh_corpse.h" +#include "bh_light.h" + +#include "scream.h" + +#include "targeting.h" + +#include "iofocus.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "ShowCmds.h" +#define DB_LEVEL 3 +#include "db.h" + +#define CalculateBytesSentPerSecond 0 + +/*---------------------------------------------------------------------- + Some globals for use in this file + ----------------------------------------------------------------------*/ +NETGAME_GAMEDATA netGameData= +{ + 0, //NETGAME_STATES myGameState; + 0, //NETGAME_CHARACTERTYPE myCharacterType; + 0, //NETGAME_CHARACTERTYPE myNextCharacterType; //if player is currently dead and about to become a new character + 0, //NETGAME_SPECIALISTCHARACTERTYPE myCharacterSubType; + 0, //unsigned char myStartFlag; + {0,}, //NETGAME_PLAYERDATA playerData[NET_MAXPLAYERS]; + {0,}, //int teamScores[3]; + 0, //NETGAME_TYPE gameType; + 0, //unsigned char levelNumber; + 1000000, //unsigned int scoreLimit; + 255, //unsigned char timeLimit; + 5, //int invulnerableTime;//in seconds after respawn + 0, //int GameTimeElapsed; + + //scoring system stuff + {100,150,75}, //int characterKillValues[3]; + 100, //int baseKillValue; + TRUE, //BOOL useDynamicScoring; + TRUE, //BOOL useCharacterKillValues; + + {75,100,150}, //int aiKillValues[3]; + + //for last man standing game + -1, //int LMS_AlienIndex; + 0, //int LMS_RestartTimer; + + 0, //int stateCheckTimeDelay; + + /*following timer used to prevent the game description from being sent every frame*/ + 0, //int gameDescriptionTimeDelay; + + /*sendFrequencey - how often to send messages in fixed point seconds*/ + 0, //int sendFrequency; + 0, //int sendTimer; + + //player type limits + 8, //unsigned int maxPredator; + 8, //unsigned int maxAlien; + 8, //unsigned int maxMarine; + + 8, //unsigned int maxMarineGeneral; + 8, //unsigned int maxMarinePulseRifle; + 8, //unsigned int maxMarineSmartgun; + 8, //unsigned int maxMarineFlamer; + 8, //unsigned int maxMarineSadar; + 8, //unsigned int maxMarineGrenade; + 8, //unsigned int maxMarineMinigun; + 8, //unsigned int maxMarineSmartDisc; + 8, //unsigned int maxMarinePistols; + + //weapons allowed + TRUE, //BOOL allowSmartgun; + TRUE, //BOOL allowFlamer; + TRUE, //BOOL allowSadar; + TRUE, //BOOL allowGrenadeLauncher; + TRUE, //BOOL allowMinigun; + TRUE, //BOOL allowDisc; + TRUE, //BOOL allowPistol; + TRUE, //BOOL allowPlasmaCaster; + TRUE, //BOOL allowSpeargun; + TRUE, //BOOL allowMedicomp; + TRUE, //BOOL allowSmartDisc; + TRUE, //BOOL allowPistols; + + 0, //int maxLives; + FALSE, //BOOL useSharedLives; + {0,0,0},//int numDeaths[3]; + + 0, //int pointsForResapwn; + 40, //int timeForRespawn; //seconds + + 0, //int lastPointsBasedRespawn; + + TRUE, //BOOL sendDecals; + 0, //unsigned int needGameDescription :1; + FALSE, //BOOL skirmishMode + + -1, //char myLastScream; + + NETGAMESPEED_100PERCENT, //int gameSpeed; + 0, //BOOL preDestroyLights; + 0, //BOOL disableFriendlyFire; + 1, //BOOL fallingDamage; + 1, //BOOL pistolInfiniteAmmo; + 1, //BOOL specialistPistols; + 0, //int myStrategyCheckSum; + + 0, //unsigned int tcpip_available :1; + 0, //unsigned int ipx_available :1; + 0, //unsigned int modem_available :1; + 0, //unsigned int serial_available :1; + 0, //NETGAME_CONNECTIONTYPE connectionType; + + 0, //landingNoise:1; + 0, //int joiningGameStatus; + "", //char customLevelName[]; +}; + +void SetDefaultMultiplayerConfig() +{ + netGameData.scoreLimit=1000000; + netGameData.timeLimit=255; + netGameData.invulnerableTime=5; + netGameData.characterKillValues[0]=100; + netGameData.characterKillValues[1]=150; + netGameData.characterKillValues[2]=75; + + netGameData.baseKillValue=100; + netGameData.useDynamicScoring=1; + netGameData.useCharacterKillValues=1; + + netGameData.aiKillValues[0]=75; + netGameData.aiKillValues[1]=100; + netGameData.aiKillValues[2]=150; + + netGameData.maxMarine=8; + netGameData.maxAlien=8; + netGameData.maxPredator=8; + netGameData.maxMarineGeneral=8; + netGameData.maxMarinePulseRifle=8; + netGameData.maxMarineSmartgun=8; + netGameData.maxMarineFlamer=8; + netGameData.maxMarineSadar=8; + netGameData.maxMarineGrenade=8; + netGameData.maxMarineMinigun=8; + netGameData.maxMarineSmartDisc=8; + netGameData.maxMarinePistols=8; + + netGameData.allowSmartgun=1; + netGameData.allowFlamer=1; + netGameData.allowSadar=1; + netGameData.allowGrenadeLauncher=1; + netGameData.allowMinigun=1; + netGameData.allowDisc=1; + netGameData.allowPistol=1; + netGameData.allowPlasmaCaster=1; + netGameData.allowSpeargun=1; + netGameData.allowMedicomp=1; + netGameData.allowSmartDisc=1; + netGameData.allowPistols=1; + + netGameData.maxLives=0; + netGameData.useSharedLives=0; + netGameData.pointsForRespawn=0; + netGameData.timeForRespawn=40; + + netGameData.gameSpeed=NETGAMESPEED_100PERCENT; + + netGameData.preDestroyLights=FALSE; + netGameData.disableFriendlyFire=FALSE; + netGameData.fallingDamage=TRUE; + netGameData.pistolInfiniteAmmo=TRUE; + netGameData.specialistPistols=TRUE; +} + +int LobbiedGame=0; + + + + +static char sendBuffer[NET_MESSAGEBUFFERSIZE]; +static char *endSendBuffer; +static int netNextLocalObjectId = 1; +DPID myNetworkKillerId = NULL; +DPID myIgniterId = NULL; +int MyHitBodyPartId=-1; +DPID MultiplayerObservedPlayer=0; + +/* for testing */ +static int numMessagesReceived = 0; +static int numMessagesTransmitted = 0; + +static char OnScreenMessageBuffer[300]; + +static unsigned char FragmentalObjectStatus[NUMBER_OF_FRAGMENTAL_OBJECTS]; +static unsigned char StrategySynchArray[NUMBER_OF_STRATEGIES_TO_SYNCH>>2]; + +int numMarineStartPos=0; +int numAlienStartPos=0; +int numPredatorStartPos=0; + +MULTIPLAYER_START* marineStartPositions=0; +MULTIPLAYER_START* alienStartPositions=0; +MULTIPLAYER_START* predatorStartPositions=0; + + +int ShowMultiplayerScoreTimer=0; +int MultiplayerRestartSeed=0; + +static int GameTimeSinceLastSend=0; + +static unsigned int TimeCounterForExtrapolation=0; + +/*---------------------------------------------------------------------- + External globals (& protoypes) + ----------------------------------------------------------------------*/ +extern int NormalFrameTime; +extern int RealFrameTime; +extern int TimeScale; +extern int PrevNormalFrameTime; + +extern void UpdateAlienAIGhostAnimSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime); +extern void RemovePickedUpObject(STRATEGYBLOCK *objectPtr); +extern void PrintStringTableEntryInConsole(enum TEXTSTRING_ID string_id); +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; +extern int DebouncedGotAnyKey; +extern int LastHand; // For alien claws and two pistols + +extern void CreateSpearPossiblyWithFragment(DISPLAYBLOCK *dispPtr, VECTORCH *spearPositionPtr, VECTORCH *spearDirectionPtr); +extern void NewOnScreenMessage(unsigned char *messagePtr); +/*---------------------------------------------------------------------- + Some protoypes for this file + ----------------------------------------------------------------------*/ +static void ProcessSystemMessage(char *msgP,unsigned int msgSize); +static void ProcessGameMessage(DPID senderId, char *msgP,unsigned int msgSize); +static void AddPlayerToGame(DPID id, char*name); +static void AddPlayerAndObjectUpdateMessages(void); +static void UpdateNetworkGameScores(DPID playerKilledId, DPID killerId,NETGAME_CHARACTERTYPE playerKilledType,NETGAME_CHARACTERTYPE killerType); +static void InitFinalNetGameScores(void); +static void ConvertNetNameToUpperCase(char *strPtr); + +static void ProcessNetMsg_GameDescription(NETMESSAGE_GAMEDESCRIPTION *msgPtr); +static void ProcessNetMsg_PlayerDescription(NETMESSAGE_PLAYERDESCRIPTION *msgPtr, DPID senderId); +static void ProcessNetMsg_StartGame(void); +static void ProcessNetMsg_PlayerState(NETMESSAGE_PLAYERSTATE *msgPtr, DPID senderId); +static void ProcessNetMsg_PlayerState_Minimal(NETMESSAGE_PLAYERSTATE_MINIMAL *msgPtr, DPID senderId,BOOL orientation); +static void ProcessNetMsg_FrameTimer(unsigned short frame_time, DPID senderId); +static void ProcessNetMsg_PlayerKilled(NETMESSAGE_PLAYERKILLED *msgPtr, DPID senderId); +static void ProcessNetMsg_PlayerDeathAnim(NETMESSAGE_CORPSEDEATHANIM* messagePtr,DPID senderId); +static void ProcessNetMsg_PlayerLeaving(DPID senderId); +static void ProcessNetMsg_AllGameScores(NETMESSAGE_ALLGAMESCORES *msgPtr); +static void ProcessNetMsg_PlayerScores(NETMESSAGE_PLAYERSCORES *msgPtr); +static void ProcessNetMsg_SpeciesScores(NETMESSAGE_SPECIESSCORES *msgPtr); +static void ProcessNetMsg_LocalRicochet(NETMESSAGE_LOCALRICOCHET *msgPtr); +static void ProcessNetMsg_LocalObjectState(NETMESSAGE_LOBSTATE *msgPtr, DPID senderId); +static void ProcessNetMsg_LocalObjectDamaged(char *msgPtr, DPID senderId); +static void ProcessNetMsg_LocalObjectDestroyed(NETMESSAGE_LOBDESTROYED *msgPtr, DPID senderId); +static void ProcessNetMsg_ObjectPickedUp(NETMESSAGE_OBJECTPICKEDUP *messagePtr); +static void ProcessNetMsg_EndGame(void); +static void ProcessNetMsg_InanimateObjectDamaged(char *msgPtr); +static void ProcessNetMsg_InanimateObjectDestroyed(NETMESSAGE_INANIMATEDESTROYED *msgPtr); +static void ProcessNetMsg_LOSRequestBinarySwitch(NETMESSAGE_LOSREQUESTBINARYSWITCH *msgPtr); +static void ProcessNetMsg_PlatformLiftState(NETMESSAGE_PLATFORMLIFTSTATE *msgPtr); +static void ProcessNetMsg_RequestPlatformLiftActivate(NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE *msgPtr); +static void ProcessNetMsg_PlayerAutoGunState(NETMESSAGE_AGUNSTATE *msgPtr, DPID senderId); +static char *ProcessNetMsg_ChatBroadcast(char *subMessagePtr, DPID senderId); +static void ProcessNetMsg_MakeExplosion(NETMESSAGE_MAKEEXPLOSION *messagePtr); +static void ProcessNetMsg_MakeFlechetteExplosion(NETMESSAGE_MAKEFLECHETTEEXPLOSION *messagePtr); +static void ProcessNetMsg_MakePlasmaExplosion(NETMESSAGE_MAKEPLASMAEXPLOSION *messagePtr); +static void ProcessNetMsg_PredatorSights(NETMESSAGE_PREDATORSIGHTS *messagePtr, DPID senderId); +static void ProcessNetMsg_FragmentalObjectsStatus(NETMESSAGE_FRAGMENTALOBJECTSSTATUS *messagePtr); +static void ProcessNetMsg_StrategySynch(NETMESSAGE_STRATEGYSYNCH *messagePtr); +static void ProcessNetMsg_LocalObjectOnFire(NETMESSAGE_LOBONFIRE *messagePtr, DPID senderId); +static void ProcessNetMsg_AlienAIState(NETMESSAGE_ALIENAISTATE *messagePtr, DPID senderId); +static void ProcessNetMsg_FarAlienPosition(NETMESSAGE_FARALIENPOSITION *messagePtr, DPID senderId); +static void ProcessNetMsg_SpotAlienSound(NETMESSAGE_SPOTALIENSOUND *messagePtr, DPID senderId); +static void ProcessNetMsg_LocalObjectDestroyed_Request(NETMESSAGE_LOBDESTROYED_REQUEST *messagePtr, DPID senderId); +static void ProcessNetMsg_ScoreChange(NETMESSAGE_SCORECHANGE *messagePtr); +static void ProcessNetMsg_CreateWeapon(NETMESSAGE_CREATEWEAPON *messagePtr); +static void ProcessNetMsg_Gibbing(NETMESSAGE_GIBBING* messagePtr,DPID senderId); +static void ProcessNetMsg_GhostHierarchyDamaged(char *messagePtr, DPID senderId); +static void ProcessNetMsg_MakeDecal(NETMESSAGE_MAKEDECAL *messagePtr); +static void ProcessNetMsg_AlienAISequenceChange(NETMESSAGE_ALIENSEQUENCECHANGE *messagePtr, DPID senderId); +static void ProcessNetMsg_AlienAIKilled(NETMESSAGE_ALIENAIKILLED *messagePtr, DPID senderId); +static void ProcessNetMsg_SpotOtherSound(NETMESSAGE_SPOTOTHERSOUND *messagePtr, DPID senderId); +void StartOfGame_PlayerPlacement(STRATEGYBLOCK *playerSbPtr,int seed); + +static void CheckLastManStandingState(); +static void Handle_LastManStanding_Restart(DPID alienID,int seed); +static void Handle_LastManStanding_RestartInfo(DPID alienID); +static void Handle_LastManStanding_LastMan(DPID marineID); +static void Handle_LastManStanding_RestartTimer(unsigned char time); + +static void CheckSpeciesTagState(); +static void Handle_SpeciesTag_NewPersonIt(DPID predatorID); +static int CountPlayersOfType(NETGAME_CHARACTERTYPE species); + +static int GetSizeOfLocalObjectDamagedMessage(char* messagePtr); +static int GetSizeOfGhostHierarchyDamagedMessage(char* messagePtr); +static int GetSizeOfInanimateDamagedMessage(char *messagePtr); + +static STRATEGYBLOCK *FindObjectFromNetIndex(int obIndex); +static STRATEGYBLOCK *FindEnvironmentObjectFromName(char *name); +static void InitialiseSendMessageBuffer(void); + +static MARINE_SEQUENCE GetMyMarineSequence(void); +static ALIEN_SEQUENCE GetMyAlienSequence(void); +static PREDATOR_SEQUENCE GetMyPredatorSequence(void); + + +static void Inform_PlayerHasDied(DPID killer, DPID victim,NETGAME_CHARACTERTYPE killerType,char weaponIcon); +static void Inform_AiHasDied(DPID killer,ALIEN_TYPE type,char weaponIcon); +static void Inform_PlayerHasLeft(DPID player); +static void Inform_PlayerHasJoined(DPID player); +static void Inform_PlayerHasConnected(DPID player); +static void Inform_NewHost(void); + +static void WriteFragmentStatus(int fragmentNumber, int status); +static int ReadFragmentStatus(int fragmentNumber); + +static void WriteStrategySynch(int objectNumber, int status); +static int ReadStrategySynch(int objectNumber); + +static int GetStrategySynchObjectChecksum(); + +static int GetDynamicScoreMultiplier(int playerKilledIndex,int killerIndex); +static int GetNetScoreForKill(int playerKilledIndex,int killerIndex); + +static void NetworkGameConsoleMessage(enum TEXTSTRING_ID stringID,const char* name1,const char* name2); +static void NetworkGameConsoleMessageWithWeaponIcon(enum TEXTSTRING_ID stringID,const char* name1,const char* name2,const char* weaponSymbol); + +static void CheckForPointBasedObjectRespawn(); + +static int CalculateMyScore(); + +static void PeriodicScoreUpdate(); + +void CheckStateOfObservedPlayer(); +/*---------------------------------------------------------------------- + Initalisation of net game + ----------------------------------------------------------------------*/ +void InitAVPNetGame(void) +{ + extern int QuickStartMultiplayer; + /* init garry's dp extended */ + DpExtInit(0,0,0); + + /* init the send message buffer */ + InitialiseSendMessageBuffer(); + + /* base initialisation of game description */ + { + int i,j; + for(i=0;i<(NET_MAXPLAYERS);i++) + { + netGameData.playerData[i].playerId = NULL; + for(j=0;j<(NET_PLAYERNAMELENGTH);j++) netGameData.playerData[i].name[j] = '\0'; + netGameData.playerData[i].characterType = NGCT_Marine; + netGameData.playerData[i].characterSubType = NGSCT_General; + for(j=0;j<(NET_MAXPLAYERS);j++) netGameData.playerData[i].playerFrags[j] = 0; + netGameData.playerData[i].playerScore=0; + netGameData.playerData[i].playerScoreAgainst=0; + netGameData.playerData[i].aliensKilled[0]=0; + netGameData.playerData[i].aliensKilled[1]=0; + netGameData.playerData[i].aliensKilled[2]=0; + netGameData.playerData[i].deathsFromAI=0; + netGameData.playerData[i].playerAlive=1; + netGameData.playerData[i].playerHasLives=1; + netGameData.playerData[i].startFlag = 0; + } + for(j=0;j<3;j++) netGameData.teamScores[j] = 0; + netGameData.myGameState = NGS_Joining; + switch (QuickStartMultiplayer) + { + default: + case 1: + netGameData.myCharacterType = NGCT_Marine; + netGameData.myNextCharacterType = NGCT_Marine; + break; + + case 2: + netGameData.myCharacterType = NGCT_Alien; + netGameData.myNextCharacterType = NGCT_Alien; + break; + + case 3: + netGameData.myCharacterType = NGCT_Predator; + netGameData.myNextCharacterType = NGCT_Predator; + break; + } + + netGameData.myStartFlag = 0; + netGameData.gameType = NGT_Individual; + netGameData.levelNumber = 0; + netGameData.scoreLimit = 0; + netGameData.timeLimit = 0; + netGameData.invulnerableTime = 5; + netGameData.GameTimeElapsed = 0; + + netGameData.LMS_AlienIndex=-1; + netGameData.stateCheckTimeDelay=0; + netGameData.LMS_RestartTimer=0; + } + + myNetworkKillerId = AVPDPNetID; /* init global id of player who killed me last */ + netNextLocalObjectId = 1; /* init local object network id */ + numMessagesReceived = 0; /* these are for testing */ + numMessagesTransmitted = 0; + + /* If I'm the host, add myself to the game data */ + if(AvP.Network==I_Host) + { + netGameData.playerData[0].playerId = AVPDPNetID; + strncpy(netGameData.playerData[0].name,AVPDPplayerName.lpszShortNameA,NET_PLAYERNAMELENGTH-1); + netGameData.playerData[0].name[NET_PLAYERNAMELENGTH-1] = '\0'; +// ConvertNetNameToUpperCase(netGameData.playerData[0].name); + } + + InitNetLog(); +} + +void InitAVPNetGameForHost(int species, int gamestyle, int level) +{ + AvP.GameMode = I_GM_Playing; + AvP.Network = I_Host; + AvP.NetworkAIServer = (gamestyle==NGT_Coop); + /* init garry's dp extended */ + if(!netGameData.skirmishMode) + { + DpExtInit(0,0,0); + } + + /* init the send message buffer */ + InitialiseSendMessageBuffer(); + + netGameData.myGameState = NGS_Joining; + /* base initialisation of game description */ + { + int i,j; + for(i=0;i<(NET_MAXPLAYERS);i++) + { + netGameData.playerData[i].playerId = NULL; + for(j=0;j<(NET_PLAYERNAMELENGTH);j++) netGameData.playerData[i].name[j] = '\0'; + netGameData.playerData[i].characterType = NGCT_Marine; + netGameData.playerData[i].characterSubType = NGSCT_General; + for(j=0;j<(NET_MAXPLAYERS);j++) netGameData.playerData[i].playerFrags[j] = 0; + netGameData.playerData[i].playerScore = 0; + netGameData.playerData[i].playerScoreAgainst = 0; + netGameData.playerData[i].aliensKilled[0]=0; + netGameData.playerData[i].aliensKilled[1]=0; + netGameData.playerData[i].aliensKilled[2]=0; + netGameData.playerData[i].deathsFromAI=0; + netGameData.playerData[i].playerAlive=1; + netGameData.playerData[i].playerHasLives=1; + netGameData.playerData[i].startFlag = 0; + } + for(j=0;j<3;j++) netGameData.teamScores[j] = 0; +// netGameData.myGameState = NGS_Playing; + + + netGameData.myCharacterSubType=NGSCT_General; + switch (species) + { + default: + case 0: + netGameData.myCharacterType = NGCT_Marine; + netGameData.myNextCharacterType = NGCT_Marine; + AvP.PlayerType = I_Marine; + break; + case 1: + netGameData.myCharacterType = NGCT_Predator; + netGameData.myNextCharacterType = NGCT_Predator; + AvP.PlayerType = I_Predator; + break; + case 2: + netGameData.myCharacterType = NGCT_Alien; + netGameData.myNextCharacterType = NGCT_Alien; + AvP.PlayerType = I_Alien; + break; + case 3: //various marine subtypes + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + netGameData.myCharacterType = NGCT_Marine; + netGameData.myNextCharacterType = NGCT_Marine; + netGameData.myCharacterSubType =(NETGAME_SPECIALISTCHARACTERTYPE) (species-2); + AvP.PlayerType = I_Marine; + break; + } + + netGameData.myStartFlag = 0; + netGameData.gameType = gamestyle; + netGameData.levelNumber = level; +// netGameData.scoreLimit = 0; +// netGameData.timeLimit = 0; +// netGameData.invulnerableTime = 5; + netGameData.GameTimeElapsed = 0; + +// netGameData.characterKillValues[NGCT_Marine]=100; +// netGameData.characterKillValues[NGCT_Predator]=150; +// netGameData.characterKillValues[NGCT_Alien]=75; +// netGameData.baseKillValue=100; +// netGameData.useDynamicScoring=1; +// netGameData.useCharacterKillValues=1; + + netGameData.stateCheckTimeDelay=0; + netGameData.gameDescriptionTimeDelay=0; + + netGameData.sendTimer=0; + if(LobbiedGame || netGameData.connectionType==CONN_Modem) + { + netGameData.sendFrequency=ONE_FIXED/15; + netGameData.sendDecals=FALSE; + } + else + { + netGameData.sendFrequency=0;//ONE_FIXED/15; + netGameData.sendDecals=TRUE; + } + } + + myNetworkKillerId = AVPDPNetID; /* init global id of player who killed me last */ + netNextLocalObjectId = 1; /* init local object network id */ + numMessagesReceived = 0; /* these are for testing */ + numMessagesTransmitted = 0; + + /* If I'm the host, add myself to the game data */ + netGameData.playerData[0].playerId = AVPDPNetID; + strncpy(netGameData.playerData[0].name,AVPDPplayerName.lpszShortNameA,NET_PLAYERNAMELENGTH-1); + netGameData.playerData[0].name[NET_PLAYERNAMELENGTH-1] = '\0'; +// ConvertNetNameToUpperCase(netGameData.playerData[0].name); + + { + int myIndex; + myIndex = PlayerIdInPlayerList(AVPDPNetID); + LOCALASSERT(myIndex!=NET_IDNOTINPLAYERLIST); + netGameData.playerData[myIndex].characterType = netGameData.myCharacterType; + netGameData.playerData[myIndex].characterSubType = netGameData.myCharacterSubType; + } + + netGameData.LMS_AlienIndex=-1; + + InitNetLog(); + + //make sure our time scale is set correctly + switch(netGameData.gameSpeed) + { + case NETGAMESPEED_70PERCENT : + TimeScale=(ONE_FIXED*70)/100; + break; + + case NETGAMESPEED_80PERCENT : + TimeScale=(ONE_FIXED*80)/100; + break; + + case NETGAMESPEED_90PERCENT : + TimeScale=(ONE_FIXED*90)/100; + break; + + case NETGAMESPEED_100PERCENT : + TimeScale=(ONE_FIXED*100)/100; + break; + + } + + netGameData.myStrategyCheckSum=0; + + netGameData.numDeaths[0]=0; + netGameData.numDeaths[1]=0; + netGameData.numDeaths[2]=0; + +} +void InitAVPNetGameForJoin(void) +{ + AvP.GameMode = I_GM_Playing; + AvP.Network = I_Peer; + + AvP.NetworkAIServer = 0; + + /* init garry's dp extended */ + DpExtInit(0,0,0); + + /* init the send message buffer */ + InitialiseSendMessageBuffer(); + + netGameData.myGameState = NGS_Joining; + /* base initialisation of game description */ + { + int i,j; + for(i=0;i<(NET_MAXPLAYERS);i++) + { + netGameData.playerData[i].playerId = NULL; + for(j=0;j<(NET_PLAYERNAMELENGTH);j++) netGameData.playerData[i].name[j] = '\0'; + netGameData.playerData[i].characterType = NGCT_Marine; + netGameData.playerData[i].characterSubType = NGSCT_General; + for(j=0;j<(NET_MAXPLAYERS);j++) netGameData.playerData[i].playerFrags[j] = 0; + netGameData.playerData[i].playerScore = 0; + netGameData.playerData[i].playerScoreAgainst = 0; + netGameData.playerData[i].aliensKilled[0]=0; + netGameData.playerData[i].aliensKilled[1]=0; + netGameData.playerData[i].aliensKilled[2]=0; + netGameData.playerData[i].deathsFromAI=0; + netGameData.playerData[i].playerAlive=1; + netGameData.playerData[i].playerHasLives=1; + netGameData.playerData[i].startFlag = 0; + } + for(j=0;j<3;j++) netGameData.teamScores[j] = 0; + netGameData.myStartFlag = 0; + netGameData.myGameState = NGS_Joining; + + netGameData.myCharacterType = NGCT_Marine; + netGameData.myNextCharacterType = NGCT_Marine; + netGameData.myCharacterSubType=NGSCT_General; + + netGameData.stateCheckTimeDelay=0; + netGameData.gameDescriptionTimeDelay=0; + + if(LobbiedGame || netGameData.connectionType==CONN_Modem) + { + netGameData.sendFrequency=ONE_FIXED/15; + netGameData.sendDecals=FALSE; + } + else + { + netGameData.sendFrequency=0;//ONE_FIXED/15; + netGameData.sendDecals=TRUE; + } + netGameData.sendTimer=0; + + netGameData.needGameDescription=1; + } + + myNetworkKillerId = AVPDPNetID; /* init global id of player who killed me last */ + netNextLocalObjectId = 1; /* init local object network id */ + numMessagesReceived = 0; /* these are for testing */ + numMessagesTransmitted = 0; + InitNetLog(); + + + netGameData.myStrategyCheckSum=0; + + netGameData.numDeaths[0]=0; + netGameData.numDeaths[1]=0; + netGameData.numDeaths[2]=0; + + netGameData.joiningGameStatus = JOINNETGAME_WAITFORSTART; +} + +/*---------------------------------------------------------------------- + Core message collection function + ----------------------------------------------------------------------*/ +void MinimalNetCollectMessages(void) +{ + HRESULT res = DP_OK; + DPID dPlayFromId = NULL; + DPID dPlayToId = NULL; + unsigned char *msgP = NULL; + unsigned msgSize = 0; + + /* collects messages until something other than DP_OK is returned (eg DP_NoMessages) */ + if(!netGameData.skirmishMode) + { + while((res==DP_OK) && glpDP && AVPDPNetID) + { + res = DpExtRecv(glpDP,&dPlayFromId,&dPlayToId,DPRECEIVE_ALL,&msgP,(LPDWORD)&msgSize); + if(res==DP_OK) + { + /* process last message, if there is one */ + if(dPlayFromId == DPID_SYSMSG) + { + ProcessSystemMessage(msgP,msgSize); + } + else ProcessGameMessage(dPlayFromId,msgP,msgSize); + } + } + } +} +void NetCollectMessages(void) +{ + HRESULT res = DP_OK; + DPID dPlayFromId = NULL; + DPID dPlayToId = NULL; + unsigned char *msgP = NULL; + unsigned msgSize = 0; + + /* first off, some assertions about our game state */ + LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Leaving))); + LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Error_GameFull))); + LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Error_GameStarted))); + LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Error_HostLost))); + + /* only bother colecting messages under certain game conditions... */ + if((netGameData.myGameState!=NGS_StartUp)&&(netGameData.myGameState!=NGS_Playing)&&(netGameData.myGameState!=NGS_Joining)&&(netGameData.myGameState!=NGS_EndGameScreen)) return; + + InitNetLog(); + LogNetInfo("Collecting Messages... \n"); + + /* collects messages until something other than DP_OK is returned (eg DP_NoMessages) */ + if(!netGameData.skirmishMode) + { + while((res==DP_OK) && glpDP && AVPDPNetID) + { + res = DpExtRecv(glpDP,&dPlayFromId,&dPlayToId,DPRECEIVE_ALL,&msgP,(LPDWORD)&msgSize); + if(res==DP_OK) + { + numMessagesReceived++; + /* process last message, if there is one */ + if(dPlayFromId == DPID_SYSMSG) + { + ProcessSystemMessage(msgP,msgSize); + } + else ProcessGameMessage(dPlayFromId,msgP,msgSize); + } + } + } + LogNetInfo("... Finished collecting Messages\n"); + + /* check ghost integrities */ + MaintainGhosts(); + + /* time and score limit checks...*/ + { + //update timer + if(netGameData.myGameState==NGS_Playing) + { + netGameData.GameTimeElapsed += RealFrameTime; + } + + if((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Playing)) + { + if(netGameData.timeLimit>0) + { + if(((netGameData.GameTimeElapsed>>16)/60) >= netGameData.timeLimit) + { + /* game has timed-out */ + TransmitEndOfGameNetMsg(); + netGameData.myGameState = NGS_EndGameScreen; + // AvP.MainLoopRunning = 0; + } + } + if(netGameData.scoreLimit>0) + { + /* nb this doesn't check team scores */ + int i,j; + for(i=0;i= netGameData.scoreLimit || score>=netGameData.scoreLimit) + { + /* someone has reached the score limit */ + TransmitEndOfGameNetMsg(); + netGameData.myGameState = NGS_EndGameScreen; + break; + // AvP.MainLoopRunning = 0; + } + } + } + } + if(netGameData.maxLives>0) + { + int i; + int numPlayers=0; + int numPlayersWithLifeLeft=0; + int numAliens=0; + int numAliensWithLifeLeft=0; + int numMarines=0; + int numMarinesWithLifeLeft=0; + int numPredators=0; + int numPredatorsWithLifeLeft=0; + BOOL gameOver=FALSE; + for(i=0;i1) + { + //if in a deathmatch game and there is only one player with life , then thats it + gameOver=TRUE; + } + } + + if(netGameData.gameType==NGT_CoopDeathmatch) + { + /* + In a cooperative deathmatch ,the game ends when only one team has life left + */ + int numTeams=0; + int numTeamsWithLifeLeft=0; + + if(numAliens) numTeams++; + if(numAliensWithLifeLeft) numTeamsWithLifeLeft++; + if(numPredators) numTeams++; + if(numPredatorsWithLifeLeft) numTeamsWithLifeLeft++; + if(numMarines) numTeams++; + if(numMarinesWithLifeLeft) numTeamsWithLifeLeft++; + + if(numTeams>1 && numTeamsWithLifeLeft<=1) + { + gameOver=TRUE; + } + } + + if(gameOver) + { + TransmitEndOfGameNetMsg(); + netGameData.myGameState = NGS_EndGameScreen; + } + + } + } + } + + + /* print my score on the screen (temporary) */ + if(netGameData.myGameState==NGS_Playing) + { + #if 0 + int myScore; + int myIndex = PlayerIdInPlayerList(AVPDPNetID); + myScore = AddUpPlayerFrags(myIndex); + LOCALASSERT(myIndex!=NET_IDNOTINPLAYERLIST); + #if PreBeta + { + extern void jtextprint(const char *t,...); + jtextprint("NET GAME SCORE: %d \n", myScore); + } + #else + textprint("NET GAME SCORE: %d \n", myScore); + #endif + + #else + #endif + + #if EXTRAPOLATION_TEST + { + extern void PlayerGhostExtrapolation(); + PlayerGhostExtrapolation(); + } + #endif + } + + LogNetInfo("Finished message collection post-processing \n"); + + if(MultiplayerObservedPlayer) + { + CheckStateOfObservedPlayer(); + } + +} + +/*---------------------------------------------------------------------- + Functions for processing system messages + ----------------------------------------------------------------------*/ +static void ProcessSystemMessage(char *msgP,unsigned int msgSize) +{ + LPDPMSG_GENERIC systemMessage = (LPDPMSG_GENERIC)msgP; + + /* currently, only the host deals with system mesages */ + /* check for invalid parameters */ + if((msgSize==0)||(msgP==NULL)) return; + + switch(systemMessage->dwType) + { + case DPSYS_ADDPLAYERTOGROUP: + { + /* ignore */ + break; + } + case DPSYS_CREATEPLAYERORGROUP: + { + /* only useful during startup: during main game, connecting player should + detect game state and exit immediately */ + if((AvP.Network==I_Host)) + { + LPDPMSG_CREATEPLAYERORGROUP createMessage; + createMessage = (LPDPMSG_CREATEPLAYERORGROUP)systemMessage; + if(createMessage->dwPlayerType == DPPLAYERTYPE_PLAYER) + { + DPID id = createMessage->dpId; + char *name = &(createMessage->dpnName.lpszShortNameA[0]); + AddPlayerToGame(id,name); + } + } + LogNetInfo("system message: DPSYS_CREATEPLAYERORGROUP \n"); + break; + } + case DPSYS_DELETEPLAYERFROMGROUP: + { +// NewOnScreenMessage("A PLAYER HAS DISCONNECTED"); + /* ignore */ + break; + } + case DPSYS_DESTROYPLAYERORGROUP: + { + /* Aha. Either a player has left (should have sent a leaving message) + or s/he has exited abnormally. In either case, only need to act on + this during start-up. During the main game, the ghosts will time-out + anyway */ + if((AvP.Network==I_Host)) + { + LPDPMSG_DESTROYPLAYERORGROUP destroyMessage; + destroyMessage = (LPDPMSG_DESTROYPLAYERORGROUP)systemMessage; + if(destroyMessage->dwPlayerType == DPPLAYERTYPE_PLAYER) + { + DPID id = destroyMessage->dpId; + RemovePlayerFromGame(id); +// NewOnScreenMessage("A PLAYER HAS DISCONNECTED"); + } + } + LogNetInfo("system message: DPSYS_DESTROYPLAYERORGROUP \n"); + break; + } + case DPSYS_HOST: + { + /* Aha... the host has died, then. This is a terminal game state, + as the host was managing the game. Thefore, temporarily adopt host + duties for the purpose of ending the game... + This is most important during the playing state, but also happens in + startup. In startup, peers keep a host timeout which should fire before + this message arrives anyway. */ + LOCALASSERT(AvP.Network==I_Peer); + if((netGameData.myGameState==NGS_StartUp)||(netGameData.myGameState==NGS_Playing)||(netGameData.myGameState==NGS_Joining)||(netGameData.myGameState==NGS_EndGameScreen)) + { + AvP.Network=I_Host; + /* Eek, I guess the old AIs bite the dust? */ + //but the new host can create some more + AvP.NetworkAIServer = (netGameData.gameType==NGT_Coop); + Inform_NewHost(); +// TransmitEndOfGameNetMsg(); +// netGameData.myGameState = NGS_EndGame; +// AvP.MainLoopRunning = 0; + + if(LobbiedGame) + { + //no longer a lowly client + LobbiedGame=LobbiedGame_Server; + } + } + LogNetInfo("system message: DPSYS_HOST \n"); + break; + } + case DPSYS_SESSIONLOST: + { + /* Aha. I have lost my connection. Time to exit the game gracefully.*/ + NewOnScreenMessage("Session lost!!"); + /* + if((netGameData.myGameState==NGS_StartUp)||(netGameData.myGameState==NGS_Joining)||(netGameData.myGameState==NGS_Playing)) + { + netGameData.myGameState = NGS_Error_HostLost; + } + + LogNetInfo("system message: DPSYS_SESSIONLOST \n"); + */ + break; + } + case DPSYS_SETPLAYERORGROUPDATA: + { + /* ignore */ + break; + } + case DPSYS_SETPLAYERORGROUPNAME: + { + /* ignore */ + break; + } + default: + { + /* invalid system message type: ignore */ + break; + } + } +} + +static void AddPlayerToGame(DPID id, char* name) +{ + int freePlayerIndex; + + LOCALASSERT(AvP.Network==I_Host); + + + /* find a free slot for the player */ + freePlayerIndex = EmptySlotInPlayerList(); + if(freePlayerIndex == NET_NOEMPTYSLOTINPLAYERLIST) return; + + /* initialise the slot */ + netGameData.playerData[freePlayerIndex].playerId = id; + + strncpy(netGameData.playerData[freePlayerIndex].name,name,NET_PLAYERNAMELENGTH-1); + netGameData.playerData[freePlayerIndex].name[NET_PLAYERNAMELENGTH-1] = '\0'; +// ConvertNetNameToUpperCase(netGameData.playerData[freePlayerIndex].name); + + netGameData.playerData[freePlayerIndex].characterType = NGCT_Marine; + netGameData.playerData[freePlayerIndex].characterSubType = NGSCT_General; + netGameData.playerData[freePlayerIndex].startFlag = 0; + { + int i; + for(i=0;itype) + { + case(NetMT_GameDescription): + { + ProcessNetMsg_GameDescription((NETMESSAGE_GAMEDESCRIPTION *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_GAMEDESCRIPTION); + break; + } + case(NetMT_PlayerDescription): + { + ProcessNetMsg_PlayerDescription((NETMESSAGE_PLAYERDESCRIPTION *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_PLAYERDESCRIPTION); + break; + } + case(NetMT_StartGame): + { + ProcessNetMsg_StartGame(); + break; + } + case(NetMT_PlayerState): + { + ProcessNetMsg_PlayerState((NETMESSAGE_PLAYERSTATE *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_PLAYERSTATE); + break; + } + case(NetMT_PlayerState_Minimal): + { + ProcessNetMsg_PlayerState_Minimal((NETMESSAGE_PLAYERSTATE_MINIMAL *)subMessagePtr, senderId,FALSE); + subMessagePtr += sizeof(NETMESSAGE_PLAYERSTATE_MINIMAL); + break; + } + case(NetMT_PlayerState_Medium): + { + ProcessNetMsg_PlayerState_Minimal((NETMESSAGE_PLAYERSTATE_MINIMAL *)subMessagePtr, senderId,TRUE); + subMessagePtr += sizeof(NETMESSAGE_PLAYERSTATE_MEDIUM); + break; + } + case (NetMT_FrameTimer) : + { + ProcessNetMsg_FrameTimer(((NETMESSAGE_FRAMETIMER *)subMessagePtr)->frame_time, senderId); + subMessagePtr += sizeof(NETMESSAGE_FRAMETIMER); + break; + } + case(NetMT_PlayerKilled): + { + ProcessNetMsg_PlayerKilled((NETMESSAGE_PLAYERKILLED *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_PLAYERKILLED); + break; + } + case(NetMT_CorpseDeathAnim): + { + ProcessNetMsg_PlayerDeathAnim((NETMESSAGE_CORPSEDEATHANIM *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_CORPSEDEATHANIM); + break; + } + case(NetMT_PlayerLeaving): + { + ProcessNetMsg_PlayerLeaving(senderId); + break; + } + case(NetMT_AllGameScores): + { + ProcessNetMsg_AllGameScores((NETMESSAGE_ALLGAMESCORES *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_ALLGAMESCORES); + break; + } + case(NetMT_PlayerScores): + { + ProcessNetMsg_PlayerScores((NETMESSAGE_PLAYERSCORES *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_PLAYERSCORES); + break; + } + case(NetMT_LocalRicochet): + { + ProcessNetMsg_LocalRicochet((NETMESSAGE_LOCALRICOCHET *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_LOCALRICOCHET); + break; + } + case(NetMT_LocalObjectState): + { + ProcessNetMsg_LocalObjectState((NETMESSAGE_LOBSTATE *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_LOBSTATE); + break; + } + case(NetMT_LocalObjectDamaged): + { + ProcessNetMsg_LocalObjectDamaged((char*)subMessagePtr, senderId); + subMessagePtr += GetSizeOfLocalObjectDamagedMessage((char*)subMessagePtr); + break; + } + case(NetMT_LocalObjectDestroyed): + { + ProcessNetMsg_LocalObjectDestroyed((NETMESSAGE_LOBDESTROYED *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_LOBDESTROYED); + break; + } + case(NetMT_ObjectPickedUp): + { + ProcessNetMsg_ObjectPickedUp((NETMESSAGE_OBJECTPICKEDUP *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_OBJECTPICKEDUP); + break; + } + case(NetMT_EndGame): + { + ProcessNetMsg_EndGame(); + break; + } + case(NetMT_InanimateObjectDamaged): + { + ProcessNetMsg_InanimateObjectDamaged((char *)subMessagePtr); + subMessagePtr += GetSizeOfInanimateDamagedMessage((char *)subMessagePtr); + break; + } + case(NetMT_InanimateObjectDestroyed): + { + ProcessNetMsg_InanimateObjectDestroyed((NETMESSAGE_INANIMATEDESTROYED *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_INANIMATEDESTROYED); + break; + } + case(NetMT_LOSRequestBinarySwitch): + { + ProcessNetMsg_LOSRequestBinarySwitch((NETMESSAGE_LOSREQUESTBINARYSWITCH *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_LOSREQUESTBINARYSWITCH); + break; + } + case(NetMT_PlatformLiftState): + { + ProcessNetMsg_PlatformLiftState((NETMESSAGE_PLATFORMLIFTSTATE *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_PLATFORMLIFTSTATE); + break; + } + case(NetMT_RequestPlatformLiftActivate): + { + ProcessNetMsg_RequestPlatformLiftActivate((NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE); + break; + } + case(NetMT_PlayerAutoGunState): + { + ProcessNetMsg_PlayerAutoGunState((NETMESSAGE_AGUNSTATE *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_AGUNSTATE); + break; + } + case(NetMT_MakeDecal): + { + ProcessNetMsg_MakeDecal((NETMESSAGE_MAKEDECAL *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_MAKEDECAL); + break; + } + case(NetMT_ChatBroadcast): + { + subMessagePtr = ProcessNetMsg_ChatBroadcast(subMessagePtr, senderId); + break; + } + case(NetMT_MakeExplosion): + { + ProcessNetMsg_MakeExplosion((NETMESSAGE_MAKEEXPLOSION *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_MAKEEXPLOSION); + break; + } + case(NetMT_MakeFlechetteExplosion): + { + ProcessNetMsg_MakeFlechetteExplosion((NETMESSAGE_MAKEFLECHETTEEXPLOSION *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_MAKEFLECHETTEEXPLOSION); + break; + } + case(NetMT_MakePlasmaExplosion): + { + ProcessNetMsg_MakePlasmaExplosion((NETMESSAGE_MAKEPLASMAEXPLOSION *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_MAKEPLASMAEXPLOSION); + break; + } + case(NetMT_PredatorSights): + { + ProcessNetMsg_PredatorSights((NETMESSAGE_PREDATORSIGHTS *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_PREDATORSIGHTS); + break; + } + case(NetMT_LocalObjectOnFire): + { + ProcessNetMsg_LocalObjectOnFire((NETMESSAGE_LOBONFIRE *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_LOBONFIRE); + break; + } + case(NetMT_RestartNetworkGame): + { + RestartNetworkGame(((NETMESSAGE_RESTARTGAME*)subMessagePtr)->seed); + subMessagePtr += sizeof(NETMESSAGE_RESTARTGAME); + break; + } + case(NetMT_FragmentalObjectsStatus): + { + ProcessNetMsg_FragmentalObjectsStatus((NETMESSAGE_FRAGMENTALOBJECTSSTATUS *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_FRAGMENTALOBJECTSSTATUS); + break; + } + case(NetMT_StrategySynch): + { + ProcessNetMsg_StrategySynch((NETMESSAGE_STRATEGYSYNCH *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_STRATEGYSYNCH); + break; + } + case(NetMT_AlienAIState): + { + ProcessNetMsg_AlienAIState((NETMESSAGE_ALIENAISTATE *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_ALIENAISTATE); + break; + } + case(NetMT_AlienAISequenceChange): + { + ProcessNetMsg_AlienAISequenceChange((NETMESSAGE_ALIENSEQUENCECHANGE *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_ALIENSEQUENCECHANGE); + break; + } + case(NetMT_AlienAIKilled): + { + ProcessNetMsg_AlienAIKilled((NETMESSAGE_ALIENAIKILLED *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_ALIENAIKILLED); + break; + } + case(NetMT_FarAlienPosition): + { + ProcessNetMsg_FarAlienPosition((NETMESSAGE_FARALIENPOSITION *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_FARALIENPOSITION); + break; + } + case(NetMT_GhostHierarchyDamaged): + { + ProcessNetMsg_GhostHierarchyDamaged((char *)subMessagePtr, senderId); + subMessagePtr += GetSizeOfGhostHierarchyDamagedMessage((char *)subMessagePtr) ; + break; + } + case(NetMT_Gibbing): + { + ProcessNetMsg_Gibbing((NETMESSAGE_GIBBING *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_GIBBING); + break; + } + case(NetMT_SpotAlienSound): + { + ProcessNetMsg_SpotAlienSound((NETMESSAGE_SPOTALIENSOUND *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_SPOTALIENSOUND); + break; + } + case(NetMT_SpotOtherSound): + { + ProcessNetMsg_SpotOtherSound((NETMESSAGE_SPOTOTHERSOUND *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_SPOTOTHERSOUND); + break; + } + case(NetMT_LocalObjectDestroyed_Request): + { + ProcessNetMsg_LocalObjectDestroyed_Request((NETMESSAGE_LOBDESTROYED_REQUEST *)subMessagePtr, senderId); + subMessagePtr += sizeof(NETMESSAGE_LOBDESTROYED_REQUEST); + break; + } + + case(NetMT_LastManStanding_Restart): + { + Handle_LastManStanding_Restart(((NETMESSAGE_LMS_RESTART*)subMessagePtr)->playerID,((NETMESSAGE_LMS_RESTART*)subMessagePtr)->seed); + subMessagePtr += sizeof(NETMESSAGE_LMS_RESTART); + break; + } + + case(NetMT_LastManStanding_RestartInfo): + { + Handle_LastManStanding_RestartInfo(((NETMESSAGE_PLAYERID*)subMessagePtr)->playerID); + subMessagePtr += sizeof(NETMESSAGE_PLAYERID); + break; + } + + case(NetMT_LastManStanding_LastMan): + { + Handle_LastManStanding_LastMan(((NETMESSAGE_PLAYERID*)subMessagePtr)->playerID); + subMessagePtr += sizeof(NETMESSAGE_PLAYERID); + break; + } + + case(NetMT_LastManStanding_RestartCountDown): + { + Handle_LastManStanding_RestartTimer(((NETMESSAGE_LMS_RESTARTTIMER*)subMessagePtr)->timer); + subMessagePtr += sizeof(NETMESSAGE_LMS_RESTARTTIMER); + break; + } + + case(NetMT_PredatorTag_NewPredator): + { + Handle_SpeciesTag_NewPersonIt(((NETMESSAGE_PLAYERID*)subMessagePtr)->playerID); + subMessagePtr += sizeof(NETMESSAGE_PLAYERID); + break; + } + + case(NetMT_CreateWeapon): + { + ProcessNetMsg_CreateWeapon((NETMESSAGE_CREATEWEAPON*)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_CREATEWEAPON); + break; + } + case(NetMT_RespawnPickups): + { + if(netGameData.myGameState==NGS_Playing || + netGameData.myGameState==NGS_EndGameScreen) + { + RespawnAllPickups(); + PrintStringTableEntryInConsole(TEXTSTRING_MULTIPLAYER_WEAPON_RESPAWN); + } + break; + } + + case(NetMT_ScoreChange): + { + ProcessNetMsg_ScoreChange((NETMESSAGE_SCORECHANGE *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_SCORECHANGE); + break; + } + + case(NetMT_SpeciesScores): + { + ProcessNetMsg_SpeciesScores((NETMESSAGE_SPECIESSCORES *)subMessagePtr); + subMessagePtr += sizeof(NETMESSAGE_SPECIESSCORES); + break; + } + + default: + { + LOCALASSERT(1==0); + break; + } + } + } + /* if we have read the message correctly, the message pointer should be exactly + at the end of the message buffer*/ + LOCALASSERT(subMessagePtr==endOfMessage); + + LogNetInfo("Finished processing a game message \n"); + +} + +#if CalculateBytesSentPerSecond +int GetBytesPerSecond(int bytesThisFrame) +{ + static int times[100]; + static int bytes[100]; + static int next_index; + int i; + int totalBytes=0; + + times[next_index]=0; + bytes[next_index]=bytesThisFrame; + next_index=(next_index+1)%100; + + for(i=0;i<100;i++) + { + times[i]+=NormalFrameTime; + totalBytes+=bytes[i]; + } + + if(!times[next_index]) return 0; + + return(DIV_FIXED(totalBytes,times[next_index])); + +} +#endif + +/*---------------------------------------------------------------------- + Core function for sending messages + ----------------------------------------------------------------------*/ +void NetSendMessages(void) +{ + /* some assertions about our game state */ + //LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Leaving))); + LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Error_GameFull))); + LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Error_GameStarted))); + LOCALASSERT(!((AvP.Network==I_Host)&&(netGameData.myGameState==NGS_Error_HostLost))); + + + /* only bother sending messages under certain game conditions... */ + if((netGameData.myGameState!=NGS_StartUp)&&(netGameData.myGameState!=NGS_EndGameScreen)&&(netGameData.myGameState!=NGS_Playing)&&(netGameData.myGameState!=NGS_Joining)) return; + + LogNetInfo("Sending net messages... \n"); + + /* at this point, add player and other object updates... doing this here + ensures we are sending our most upto date info */ + if(netGameData.myGameState==NGS_Playing || + netGameData.myGameState==NGS_EndGameScreen) + { + netGameData.gameDescriptionTimeDelay-=RealFrameTime; + + GameTimeSinceLastSend+=NormalFrameTime; + TimeCounterForExtrapolation+=NormalFrameTime; + + #if EXTRAPOLATION_TEST + //update muzzle flashes here , since this happens after dynamics + { + extern void PostDynamicsExtrapolationUpdate(); + PostDynamicsExtrapolationUpdate(); + } + #endif + + if(netGameData.sendFrequency) + { + //check to see if messages should be sent this frame + netGameData.sendTimer-=RealFrameTime; + if(netGameData.sendTimer>0) + { + //don't send messages this frame + #if CalculateBytesSentPerSecond + PrintDebuggingText("Bytes/Second: %d\n",GetBytesPerSecond(0)); + #endif + return; + } + netGameData.sendTimer+=netGameData.sendFrequency; + netGameData.sendTimer=max(0,netGameData.sendTimer); + + } + + if(netGameData.myGameState==NGS_EndGameScreen) + { + if(AvP.Network==I_Host) + { + PeriodicScoreUpdate(); + //send game description once per second + if(netGameData.gameDescriptionTimeDelay<0) + { + netGameData.gameDescriptionTimeDelay+=2*ONE_FIXED; + AddNetMsg_GameDescription(); + + AddNetMsg_StrategySynch(); + + AddNetMsg_FragmentalObjectsStatus(); + } + } + } + else //game state is NGS_Playing + { + AddPlayerAndObjectUpdateMessages(); + if(AvP.Network==I_Host) + { + //send game description once per second + if(netGameData.gameDescriptionTimeDelay<0) + { + netGameData.gameDescriptionTimeDelay+=ONE_FIXED; + AddNetMsg_GameDescription(); + + AddNetMsg_StrategySynch(); + + AddNetMsg_FragmentalObjectsStatus(); + } + + PeriodicScoreUpdate(); + + if(netGameData.gameType==NGT_LastManStanding) + { + CheckLastManStandingState(); + } + else if(netGameData.gameType==NGT_PredatorTag || netGameData.gameType==NGT_AlienTag) + { + CheckSpeciesTagState(); + } + CheckForPointBasedObjectRespawn(); + } + } + } + else if(netGameData.myGameState==NGS_Leaving || + netGameData.myGameState==NGS_Joining || + netGameData.myGameState==NGS_StartUp) + { + if(AvP.Network==I_Host) + { + AddNetMsg_GameDescription(); + } + } + + { + /* send our message buffer... + NB it should always be non-empty, and always less than the maximum message size */ + HRESULT res; + int numBytes; + BOOL clearSendBuffer=TRUE; + numBytes = (int)(endSendBuffer - &sendBuffer[0]); + + if(netGameData.myGameState==NGS_EndGameScreen || netGameData.myGameState==NGS_Joining) + { + //there may not be any messages while showing the end game screen + if(numBytes==DPEXT_HEADER_SIZE) return; + } + + + LOCALASSERT(numBytes > DPEXT_HEADER_SIZE); + LOCALASSERT(numBytes <= NET_MESSAGEBUFFERSIZE); + if(!netGameData.skirmishMode) + { + if(glpDP && AVPDPNetID) + { + res = DpExtSend(glpDP,AVPDPNetID,DPID_ALLPLAYERS,0,&sendBuffer,numBytes); + if(res!=DP_OK) + { + //we have some problem sending... + switch(res) + { + case DPERR_BUSY : + /* + failed to send this frame , try preserving the contents of the send buffer , + unless it is getting to full. + */ + if(numBytesI_SBtype) + { + case(I_BehaviourMarinePlayer): + case(I_BehaviourAlienPlayer): + case(I_BehaviourPredatorPlayer): + { + /* the player update message */ + AddNetMsg_PlayerState(sbPtr); + break; + } + case(I_BehaviourRocket): + case(I_BehaviourGrenade): + case(I_BehaviourProximityGrenade): + case(I_BehaviourPulseGrenade): + case(I_BehaviourFragmentationGrenade): + case(I_BehaviourPredatorEnergyBolt): + case(I_BehaviourFrisbeeEnergyBolt): + case(I_BehaviourClusterGrenade): + case(I_BehaviourNPCPredatorDisc): + case(I_BehaviourPredatorDisc_SeekTrack): + case(I_BehaviourAlienSpit): + case(I_BehaviourNetCorpse): + case(I_BehaviourPPPlasmaBolt): + case(I_BehaviourFrisbee): +// case(I_BehaviourSpeargunBolt): //spear location is sent once , upon creation + { + + AddNetMsg_LocalObjectState(sbPtr); + break; + } + case(I_BehaviourFlareGrenade): + { + FLARE_BEHAV_BLOCK *bbPtr = (FLARE_BEHAV_BLOCK * ) sbPtr->SBdataptr; + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + //only send messages for flares while they are moving + if(!dynPtr->IsStatic || bbPtr->becomeStuck) + { + AddNetMsg_LocalObjectState(sbPtr); + } + break; + } + case(I_BehaviourInanimateObject): + { + INANIMATEOBJECT_STATUSBLOCK* objStatPtr = sbPtr->SBdataptr; + + if (objStatPtr->ghosted_object) { + AddNetMsg_LocalObjectState(sbPtr); + } + break; + } + case(I_BehaviourAutoGun): + { + /* this MUST be a player placed autogun */ + { + } + /* the autogun update message */ + AddNetMsg_PlayerAutoGunState(sbPtr); + break; + } + case(I_BehaviourAlien): + { + //only add alien details , if it is near (to someone) + if(sbPtr->SBdptr) + { + AddNetMsg_AlienAIState(sbPtr); + } + break; + } + + default: + break; + } + } +} + + + +/*---------------------------------------------------------------------- + End of network game clean up + ----------------------------------------------------------------------*/ +void EndAVPNetGame(void) +{ + HRESULT hres; + + /* garry's dp extended clean up */ + if(!netGameData.skirmishMode) + { + DpExtUnInit(); + } + + + //netGameData.myGameState=NGS_Leaving; + RemovePlayerFromGame(AVPDPNetID); + TransmitPlayerLeavingNetMsg(); + + if(!netGameData.skirmishMode) + { + DirectPlay_Disconnect(); + } + + #if 0 + /* terminate our player */ + if(AVPDPNetID) + { + hres = IDirectPlay4_DestroyPlayer(glpDP, AVPDPNetID); + AVPDPNetID = NULL; + } + /* terminate the dp object */ + if(glpDP) + { + hres = IDirectPlay4_Close(lpDPlay3AAVP); + IDirectPlay4_Release(lpDPlay3AAVP); + lpDPlay3AAVP = NULL; + } + #endif + + /* reset our game mode here */ + AvP.Network = I_No_Network; + AvP.NetworkAIServer = 0; + netGameData.skirmishMode=FALSE; + + TurnOffMultiplayerObserveMode(); + + //reset time scale to default value + TimeScale=ONE_FIXED; +} + +/*---------------------------------------------------------------------- + Functions for adding each message type to the send message buffer + ----------------------------------------------------------------------*/ +void AddNetMsg_GameDescription(void) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_GAMEDESCRIPTION *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_GAMEDESCRIPTION); + + /* some conditions */ + LOCALASSERT(AvP.Network==I_Host); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_GAMEDESCRIPTION *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_GameDescription; + + /*fill out the message */ + { int i; + for(i=0;iplayers[i].playerId = netGameData.playerData[i].playerId; + messagePtr->players[i].characterType = (unsigned char)netGameData.playerData[i].characterType; + messagePtr->players[i].characterSubType = (unsigned char)netGameData.playerData[i].characterSubType; + messagePtr->players[i].startFlag = netGameData.playerData[i].startFlag; + } + messagePtr->gameType = (unsigned char)netGameData.gameType; + messagePtr->levelNumber = (unsigned char)netGameData.levelNumber; + messagePtr->scoreLimit = netGameData.scoreLimit; + messagePtr->timeLimit = (unsigned char)netGameData.timeLimit; + messagePtr->invulnerableTime = (unsigned char)netGameData.invulnerableTime; + + for(i=0;i<3;i++) + { + messagePtr->characterKillValues[i]=(unsigned char)netGameData.characterKillValues[i]; + messagePtr->aiKillValues[i]=(unsigned char)netGameData.aiKillValues[i]; + } + messagePtr->baseKillValue=(unsigned char)netGameData.baseKillValue; + messagePtr->useDynamicScoring=(unsigned char)netGameData.useDynamicScoring; + messagePtr->useCharacterKillValues=(unsigned char)netGameData.useCharacterKillValues; + + + + messagePtr->sendDecals=netGameData.sendDecals; + + + messagePtr->allowSmartgun=netGameData.allowSmartgun; + messagePtr->allowFlamer=netGameData.allowFlamer; + messagePtr->allowSadar=netGameData.allowSadar; + messagePtr->allowGrenadeLauncher=netGameData.allowGrenadeLauncher; + messagePtr->allowMinigun=netGameData.allowMinigun; + messagePtr->allowDisc=netGameData.allowDisc; + messagePtr->allowPistol=netGameData.allowPistol; + messagePtr->allowPlasmaCaster=netGameData.allowPlasmaCaster; + messagePtr->allowSpeargun=netGameData.allowSpeargun; + messagePtr->allowMedicomp=netGameData.allowMedicomp; + messagePtr->allowSmartDisc=netGameData.allowSmartDisc; + messagePtr->allowPistols=netGameData.allowPistols; + + messagePtr->maxPredator=netGameData.maxPredator; + messagePtr->maxAlien=netGameData.maxAlien; + messagePtr->maxMarine=netGameData.maxMarine; + + messagePtr->maxMarineGeneral=netGameData.maxMarineGeneral; + messagePtr->maxMarinePulseRifle=netGameData.maxMarinePulseRifle; + messagePtr->maxMarineSmartgun=netGameData.maxMarineSmartgun; + messagePtr->maxMarineFlamer=netGameData.maxMarineFlamer; + messagePtr->maxMarineSadar=netGameData.maxMarineSadar; + messagePtr->maxMarineGrenade=netGameData.maxMarineGrenade; + messagePtr->maxMarineMinigun=netGameData.maxMarineMinigun; + messagePtr->maxMarineSmartDisc=netGameData.maxMarineSmartDisc; + messagePtr->maxMarinePistols=netGameData.maxMarinePistols; + + + messagePtr->useSharedLives=netGameData.useSharedLives; + messagePtr->maxLives=netGameData.maxLives; + messagePtr->numDeaths[0]=(unsigned char) min(netGameData.numDeaths[0],255); + messagePtr->numDeaths[1]=(unsigned char) min(netGameData.numDeaths[1],255); + messagePtr->numDeaths[2]=(unsigned char) min(netGameData.numDeaths[2],255); + + messagePtr->timeForRespawn=(unsigned char)netGameData.timeForRespawn; + messagePtr->pointsForRespawn=netGameData.pointsForRespawn; + + messagePtr->GameTimeElapsed=netGameData.GameTimeElapsed>>16; + + messagePtr->gameSpeed=netGameData.gameSpeed; + + messagePtr->preDestroyLights=netGameData.preDestroyLights; + messagePtr->disableFriendlyFire=netGameData.disableFriendlyFire; + messagePtr->fallingDamage=netGameData.fallingDamage; + messagePtr->pistolInfiniteAmmo=netGameData.pistolInfiniteAmmo; + messagePtr->specialistPistols=netGameData.specialistPistols; + + if(netGameData.myGameState==NGS_EndGameScreen) + messagePtr->endGame=1; + else + messagePtr->endGame=0; + + } +} + +void AddNetMsg_PlayerDescription(void) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_PLAYERDESCRIPTION *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_PLAYERDESCRIPTION); + + /* some conditions */ + LOCALASSERT(AvP.Network==I_Peer); + LOCALASSERT(netGameData.myGameState==NGS_Joining); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_PLAYERDESCRIPTION *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_PlayerDescription; + + /*fill out the message */ + { + messagePtr->characterType = (unsigned char)netGameData.myCharacterType; + messagePtr->characterSubType = (unsigned char)netGameData.myCharacterSubType; + messagePtr->startFlag = (unsigned char)netGameData.myStartFlag; + } +} + +void AddNetMsg_StartGame(void) +{ + NETMESSAGEHEADER *headerPtr; + int headerSize = sizeof(NETMESSAGEHEADER); + + /* some conditions */ + LOCALASSERT(AvP.Network==I_Host); + LOCALASSERT(netGameData.myGameState==NGS_Joining); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_StartGame; +} + +extern int UseExtrapolation; +void AddNetMsg_PlayerState(STRATEGYBLOCK *sbPtr) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_PLAYERSTATE *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_PLAYERSTATE); + int playerIndex; + + + if(netGameData.myGameState!=NGS_Playing) return; + + #if EXTRAPOLATION_TEST + if(UseExtrapolation && netGameData.sendFrequency) + { + //see if we can get away with sending reduced information about the player's state + static VECTORCH previousVelocity; + static EULER previousOrient; + static int previousWeapon; + static unsigned int TimeOfLastPlayerState; + BOOL sendMinimalState=TRUE; + + if(TimeCounterForExtrapolationONE_FIXED/4) + { + //It has been over 1/4 second since the last full update , so better do a full update now + sendMinimalState=FALSE; + } + + if(sendMinimalState) + { + if(sbPtr->DynPtr->LinImpulse.vx || + sbPtr->DynPtr->LinImpulse.vy || + sbPtr->DynPtr->LinImpulse.vz) + { + /* + The player is probably jumping. This screws up the extrapolation somewhat. + Therefore better send full player update. + */ + sendMinimalState=FALSE; + } + + } + + if(sendMinimalState) + { + VECTORCH diff=sbPtr->DynPtr->LinVelocity; + SubVector(&previousVelocity,&diff); + + if(Approximate3dMagnitude(&diff)>100) + { + //the player's velocity has changed , so need a full update. + sendMinimalState=FALSE; + } + } + + + if(sendMinimalState) + { + PLAYER_WEAPON_DATA *weaponPtr; + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + + if(weaponPtr->WeaponIDNumber!=previousWeapon) + { + //the player's weapon has changed ,so need a full update + previousWeapon=weaponPtr->WeaponIDNumber; + sendMinimalState=FALSE; + } + } + + if(sendMinimalState) + { + //don't need to send positional information , but has the player's orientation changed? + BOOL sendOrient=FALSE; + if(previousOrient.EulerX!=sbPtr->DynPtr->OrientEuler.EulerX || + previousOrient.EulerY!=sbPtr->DynPtr->OrientEuler.EulerY || + previousOrient.EulerZ!=sbPtr->DynPtr->OrientEuler.EulerZ) + { + previousOrient=sbPtr->DynPtr->OrientEuler; + //we better send the medium sized player state message + sendOrient=TRUE; + } + AddNetMsg_PlayerState_Minimal(sbPtr,sendOrient); + return; + } + else + { + previousVelocity=sbPtr->DynPtr->LinVelocity; + previousOrient=sbPtr->DynPtr->OrientEuler; + TimeOfLastPlayerState=TimeCounterForExtrapolation; + + } + } + #endif + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_PLAYERSTATE *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_PlayerState; + + //check our carrent character type + { + switch(AvP.PlayerType) + { + case I_Marine : + netGameData.myCharacterType=NGCT_Marine; + break; + + case I_Predator : + netGameData.myCharacterType=NGCT_Predator; + break; + + case I_Alien : + netGameData.myCharacterType=NGCT_Alien; + break; + } + + playerIndex = PlayerIdInPlayerList(AVPDPNetID); + GLOBALASSERT(playerIndex!=NET_IDNOTINPLAYERLIST); + + messagePtr->characterType=netGameData.myCharacterType; + messagePtr->characterSubType=netGameData.myCharacterSubType; + messagePtr->nextCharacterType=netGameData.myNextCharacterType; + netGameData.playerData[playerIndex].characterType=messagePtr->nextCharacterType; + + } + + /* fill out our position and orientation */ + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + + LOCALASSERT(dynPtr); + LOCALASSERT((dynPtr->OrientEuler.EulerX >=0 )&&(dynPtr->OrientEuler.EulerX < 4096)); /* 9 bits of signed data */ + LOCALASSERT((dynPtr->OrientEuler.EulerY >=0 )&&(dynPtr->OrientEuler.EulerY < 4096)); /* 9 bits of signed data */ + LOCALASSERT((dynPtr->OrientEuler.EulerZ >=0 )&&(dynPtr->OrientEuler.EulerZ < 4096)); /* 9 bits of signed data */ + + /* NB we can fit +-4194303 into 23 bits */ + if(dynPtr->Position.vx < -4100000) messagePtr->xPos = -4100000; + else if(dynPtr->Position.vx > 4100000) messagePtr->xPos = 4100000; + else messagePtr->xPos = dynPtr->Position.vx; + messagePtr->xOrient = (dynPtr->OrientEuler.EulerX>>NET_EULERSCALESHIFT); + + if(dynPtr->Position.vy < -4100000) messagePtr->yPos = -4100000; + else if(dynPtr->Position.vy > 4100000) messagePtr->yPos = 4100000; + else messagePtr->yPos = dynPtr->Position.vy; + messagePtr->yOrient = (dynPtr->OrientEuler.EulerY>>NET_EULERSCALESHIFT); + + if(dynPtr->Position.vz < -4100000) messagePtr->zPos = -4100000; + else if(dynPtr->Position.vz > 4100000) messagePtr->zPos = 4100000; + else messagePtr->zPos = dynPtr->Position.vz; + messagePtr->zOrient = (dynPtr->OrientEuler.EulerZ>>NET_EULERSCALESHIFT); + + + #if EXTRAPOLATION_TEST + messagePtr->velocity_x=dynPtr->LinVelocity.vx/100; + messagePtr->velocity_y=dynPtr->LinVelocity.vy/100; + messagePtr->velocity_z=dynPtr->LinVelocity.vz/100; + messagePtr->standard_gravity=dynPtr->UseStandardGravity; + #endif + } + + /* KJL 17:04:22 26/01/98 - elevation (for weapon, etc.) */ + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + messagePtr->Elevation = playerStatusPtr->ViewPanX; + + switch(AvP.PlayerType) + { + case(I_Marine): + { + messagePtr->sequence = (unsigned char)GetMyMarineSequence(); + /* Taunt handling. */ + if (playerStatusPtr->tauntTimer==-1) { + if (messagePtr->sequence!=MSQ_Taunt) { + /* Taunt overridden. */ + playerStatusPtr->tauntTimer=0; + } else { + /* Taunt is go. */ + playerStatusPtr->tauntTimer=TAUNT_LENGTH; + } + } else if (playerStatusPtr->tauntTimer!=0) { + if (messagePtr->sequence!=MSQ_Taunt) { + /* Taunt cancelled. */ + playerStatusPtr->tauntTimer=0; + } + } + break; + } + case(I_Predator): + { + messagePtr->sequence = (unsigned char)GetMyPredatorSequence(); + /* Taunt handling. */ + if (playerStatusPtr->tauntTimer==-1) { + if (messagePtr->sequence!=PredSQ_Taunt) { + /* Taunt overridden. */ + playerStatusPtr->tauntTimer=0; + } else { + /* Taunt is go. */ + playerStatusPtr->tauntTimer=TAUNT_LENGTH; + } + } else if (playerStatusPtr->tauntTimer!=0) { + if (messagePtr->sequence!=PredSQ_Taunt) { + /* Taunt cancelled. */ + playerStatusPtr->tauntTimer=0; + } + } + break; + } + case(I_Alien): + { + messagePtr->sequence = (unsigned char)GetMyAlienSequence(); + /* Taunt handling. */ + if (playerStatusPtr->tauntTimer==-1) { + if (messagePtr->sequence!=ASQ_Taunt) { + /* Taunt overridden. */ + playerStatusPtr->tauntTimer=0; + } else { + /* Taunt is go. */ + playerStatusPtr->tauntTimer=TAUNT_LENGTH; + } + } else if (playerStatusPtr->tauntTimer!=0) { + if (messagePtr->sequence!=ASQ_Taunt) { + /* Taunt cancelled. */ + playerStatusPtr->tauntTimer=0; + } + } + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + if(PlayerStatusPtr->ShapeState!=PMph_Standing) + { + messagePtr->IAmCrouched = 1; + } + else + { + messagePtr->IAmCrouched = 0; + } + } + + /* my current weapon id, and whether I am firing it... */ + { + PLAYER_WEAPON_DATA *weaponPtr; + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + messagePtr->currentWeapon = (signed char)(weaponPtr->WeaponIDNumber); + + if (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS) { + if(((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)||(weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY)) + &&(PlayerStatusPtr->IsAlive)) { + if (LastHand) { + messagePtr->IAmFiringPrimary = 0; + messagePtr->IAmFiringSecondary = 1; + } else { + messagePtr->IAmFiringPrimary = 1; + messagePtr->IAmFiringSecondary = 0; + } + } else { + messagePtr->IAmFiringPrimary = 0; + messagePtr->IAmFiringSecondary = 0; + } + /* Whether in tertiary fire */ + if (AreTwoPistolsInTertiaryFire()) { + messagePtr->Special=1; + } else { + messagePtr->Special=0; + } + /* whether or not I'm displaying a gun flash */ + messagePtr->IHaveAMuzzleFlash = MyPlayerHasAMuzzleFlash(sbPtr); + } else { + + if ((weaponPtr->WeaponIDNumber==WEAPON_MARINE_PISTOL) + &&((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)||(weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY)) + ) { + messagePtr->Special=1; + } else { + messagePtr->Special=0; + } + + if((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)&&(PlayerStatusPtr->IsAlive)) + messagePtr->IAmFiringPrimary = 1; + else messagePtr->IAmFiringPrimary = 0; + if((weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY)&&(PlayerStatusPtr->IsAlive)) + messagePtr->IAmFiringSecondary = 1; + else messagePtr->IAmFiringSecondary = 0; + /* whether or not I'm displaying a gun flash */ + if(MyPlayerHasAMuzzleFlash(sbPtr)) messagePtr->IHaveAMuzzleFlash = 1; + else messagePtr->IHaveAMuzzleFlash = 0; + } + } + /* whether or not I'm alive */ + if(PlayerStatusPtr->IsAlive) messagePtr->IAmAlive = 1; + else messagePtr->IAmAlive = 0; + + netGameData.playerData[playerIndex].playerAlive=messagePtr->IAmAlive; + + //Is the player alive or in possesion of extra lives? + if(messagePtr->IAmAlive) + { + messagePtr->IHaveLifeLeft=1; + } + else + { + messagePtr->IHaveLifeLeft=AreThereAnyLivesLeft(); + } + + netGameData.playerData[playerIndex].playerHasLives=messagePtr->IHaveLifeLeft; + + /*Am I currently invulnerable?*/ + if(PlayerStatusPtr->invulnerabilityTimer>0) + messagePtr->IAmInvulnerable=1; + else + messagePtr->IAmInvulnerable=0; + + + /* whether or not I'm the host */ +// if(AvP.Network==I_Host) messagePtr->IAmHost = 1; +// else messagePtr->IAmHost = 0; + + /* whether or not I'm a cloaked predator */ + { + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + if(playerStatusPtr->cloakOn) + { + LOCALASSERT(AvP.PlayerType==I_Predator); + + if (playerStatusPtr->CloakingEffectiveness>65535) + { + messagePtr->CloakingEffectiveness = 65535; + } + else + { + messagePtr->CloakingEffectiveness = (unsigned short)(playerStatusPtr->CloakingEffectiveness); + } + } + else messagePtr->CloakingEffectiveness = 0; + } + + /* Am I on fire? */ + if (sbPtr->SBDamageBlock.IsOnFire) { + messagePtr->IAmOnFire=1; + } else { + messagePtr->IAmOnFire=0; + } + /* Do I have a disk? Probably not. */ + messagePtr->IHaveADisk=0; + if (AvP.PlayerType==I_Predator) { + if (messagePtr->currentWeapon==WEAPON_PRED_DISC) { + if (PlayersWeapon.HModelControlBlock) { + SECTION_DATA *disc_section; + disc_section=GetThisSectionData(PlayersWeapon.HModelControlBlock->section_data,"disk"); + GLOBALASSERT(disc_section); + if ((disc_section->flags§ion_data_notreal)==0) { + /* We have a disk! */ + messagePtr->IHaveADisk=1; + } + } + } + } + + //have we been screaming? + if(netGameData.myLastScream!=-1) + { + messagePtr->scream=netGameData.myLastScream; + } + else + { + messagePtr->scream=31; + } + //reset last scream , so we don't keep sending it + netGameData.myLastScream=-1; + + /* CDF 21/4/99 Add landing noise? */ + messagePtr->landingNoise=netGameData.landingNoise; + //reset that too! + netGameData.landingNoise=0; + +} + +void AddNetMsg_PlayerState_Minimal(STRATEGYBLOCK *sbPtr,BOOL sendOrient) +{ + PLAYER_WEAPON_DATA *weaponPtr=0; + int playerIndex; + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_PLAYERSTATE_MINIMAL *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_PLAYERSTATE_MINIMAL); + if(sendOrient) + { + messageSize = sizeof(NETMESSAGE_PLAYERSTATE_MEDIUM); + } + + + + if(netGameData.myGameState!=NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_PLAYERSTATE_MINIMAL *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + if(sendOrient) + headerPtr->type = (unsigned char)NetMT_PlayerState_Medium; + else + headerPtr->type = (unsigned char)NetMT_PlayerState_Minimal; + + + playerIndex = PlayerIdInPlayerList(AVPDPNetID); + GLOBALASSERT(playerIndex!=NET_IDNOTINPLAYERLIST); + + /* KJL 17:04:22 26/01/98 - elevation (for weapon, etc.) */ + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + messagePtr->Elevation = playerStatusPtr->ViewPanX; + } + + /* my current weapon id, and whether I am firing it... */ + { + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + + if (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS) { + if((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)&&(PlayerStatusPtr->IsAlive)) { + if (LastHand) { + messagePtr->IAmFiringPrimary = 0; + messagePtr->IAmFiringSecondary = 1; + } else { + messagePtr->IAmFiringPrimary = 1; + messagePtr->IAmFiringSecondary = 0; + } + } else { + messagePtr->IAmFiringPrimary = 0; + messagePtr->IAmFiringSecondary = 0; + } + /* whether or not I'm displaying a gun flash */ + messagePtr->IHaveAMuzzleFlash = MyPlayerHasAMuzzleFlash(sbPtr); + } else { + if((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)&&(PlayerStatusPtr->IsAlive)) + messagePtr->IAmFiringPrimary = 1; + else messagePtr->IAmFiringPrimary = 0; + if((weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY)&&(PlayerStatusPtr->IsAlive)) + messagePtr->IAmFiringSecondary = 1; + else messagePtr->IAmFiringSecondary = 0; + /* whether or not I'm displaying a gun flash */ + if(MyPlayerHasAMuzzleFlash(sbPtr)) messagePtr->IHaveAMuzzleFlash = 1; + else messagePtr->IHaveAMuzzleFlash = 0; + } + } + + /* whether or not I'm alive */ + if(PlayerStatusPtr->IsAlive) messagePtr->IAmAlive = 1; + else messagePtr->IAmAlive = 0; + + netGameData.playerData[playerIndex].playerAlive=messagePtr->IAmAlive; + + //Is the player alive or in possesion of extra lives? + if(messagePtr->IAmAlive) + { + messagePtr->IHaveLifeLeft=1; + } + else + { + messagePtr->IHaveLifeLeft=AreThereAnyLivesLeft(); + } + + netGameData.playerData[playerIndex].playerHasLives=messagePtr->IHaveLifeLeft; + + + + + /* whether or not I'm a cloaked predator */ + { + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + if(playerStatusPtr->cloakOn) + { + LOCALASSERT(AvP.PlayerType==I_Predator); + + if (playerStatusPtr->CloakingEffectiveness>65535) + { + messagePtr->CloakingEffectiveness = 65535>>8; + } + else + { + messagePtr->CloakingEffectiveness = (unsigned short)(playerStatusPtr->CloakingEffectiveness>>8); + } + } + else messagePtr->CloakingEffectiveness = 0; + } + + + /* Am I on fire? */ + if (sbPtr->SBDamageBlock.IsOnFire) { + messagePtr->IAmOnFire=1; + } else { + messagePtr->IAmOnFire=0; + } + /* Do I have a disk? Probably not. */ + messagePtr->IHaveADisk=0; + if (AvP.PlayerType==I_Predator) { + if (weaponPtr->WeaponIDNumber==WEAPON_PRED_DISC) { + if (PlayersWeapon.HModelControlBlock) { + SECTION_DATA *disc_section; + disc_section=GetThisSectionData(PlayersWeapon.HModelControlBlock->section_data,"disk"); + GLOBALASSERT(disc_section); + if ((disc_section->flags§ion_data_notreal)==0) { + /* We have a disk! */ + messagePtr->IHaveADisk=1; + } + } + } + } + + if(sendOrient) + { + NETMESSAGE_PLAYERSTATE_MEDIUM* mediumMessage=(NETMESSAGE_PLAYERSTATE_MEDIUM*) messagePtr; + mediumMessage->xOrient = (sbPtr->DynPtr->OrientEuler.EulerX>>NET_EULERSCALESHIFT); + mediumMessage->yOrient = (sbPtr->DynPtr->OrientEuler.EulerY>>NET_EULERSCALESHIFT); + mediumMessage->zOrient = (sbPtr->DynPtr->OrientEuler.EulerZ>>NET_EULERSCALESHIFT); + } +} + +void AddNetMsg_FrameTimer() +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_FRAMETIMER *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_FRAMETIMER); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_FRAMETIMER *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_FrameTimer; + + /* fill out the message */ + messagePtr->frame_time = (unsigned short)GameTimeSinceLastSend; + GameTimeSinceLastSend=0; +} + +/* support function for addnetmsg_playerstate() */ +static int MyPlayerHasAMuzzleFlash(STRATEGYBLOCK *sbPtr) +{ + PLAYER_WEAPON_DATA *weaponPtr; + TEMPLATE_WEAPON_DATA *twPtr; + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + + /* first check if we are displaying a muzle flash ourselves */ + if(twPtr->MuzzleFlashShapeName == NULL) return 0; + if(twPtr->PrimaryIsMeleeWeapon) return 0; + + if (weaponPtr->WeaponIDNumber==WEAPON_TWO_PISTOLS) { + if (weaponPtr->CurrentState == WEAPONSTATE_FIRING_PRIMARY) { + if (LastHand) { + return 2; + } else { + return 1; + } + } else if (weaponPtr->CurrentState == WEAPONSTATE_FIRING_SECONDARY) { + if (LastHand) { + return 2; + } else { + return 1; + } + return 0; + } + } + + if (weaponPtr->WeaponIDNumber==WEAPON_MARINE_PISTOL) { + if ((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY) + ||(weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY)) { + //ReleasePrintDebuggingText("Pistol Muzzle Flash 1\n"); + return 1; + } else { + //ReleasePrintDebuggingText("Pistol Muzzle Flash 0\n"); + return 0; + } + } + + if (weaponPtr->CurrentState != WEAPONSTATE_FIRING_PRIMARY) { + return 0; + } + + /* even if we are displaying our own muzzle flash, we don't neccessarily want it to + be visible to other players (because it looks stupid) */ + if((weaponPtr->WeaponIDNumber==WEAPON_PULSERIFLE)|| + (weaponPtr->WeaponIDNumber==WEAPON_MARINE_PISTOL)|| + (weaponPtr->WeaponIDNumber==WEAPON_AUTOSHOTGUN)|| + (weaponPtr->WeaponIDNumber==WEAPON_SMARTGUN)|| + (weaponPtr->WeaponIDNumber==WEAPON_MINIGUN)|| + (weaponPtr->WeaponIDNumber==WEAPON_FRISBEE_LAUNCHER)|| + (weaponPtr->WeaponIDNumber==WEAPON_PRED_PISTOL)|| + (weaponPtr->WeaponIDNumber==WEAPON_PRED_RIFLE)) + { + /* if we get this far, we want to display a muzzle flash */ + return 1; + } + return 0; +} + +char GetWeaponIconFromDamage(DAMAGE_PROFILE* damage) +{ + #define ICON_CUDGEL 177 + #define ICON_PULSERIFLE 177 + #define ICON_PULSERIFLE_GRENADE 177 + #define ICON_SMARTGUN 138 + #define ICON_FLAMER 137 + #define ICON_SADAR 140 + #define ICON_GRENADE_STANDARD 139 + #define ICON_GRENADE_PROX 139 + #define ICON_GRENADE_FRAG 139 + #define ICON_MINIGUN 141 + #define ICON_SKEETER 143 + #define ICON_MARINE_PISTOL 142 + + #define ICON_CLAW 152 + #define ICON_TAIL 151 + #define ICON_JAWS 176 + + #define ICON_WRISTBLADE 154 + #define ICON_PRED_PISTOL 158 + #define ICON_SHOULDERCANNON 156 + #define ICON_SPEARGUN 155 + #define ICON_DISC 157 + + + if(!damage) return 0; + switch(damage->Id) + { + case AMMO_10MM_CULW : + return ICON_PULSERIFLE; + + case AMMO_PULSE_GRENADE : + case AMMO_PULSE_GRENADE_STRIKE : + return ICON_PULSERIFLE_GRENADE; + + case AMMO_SMARTGUN : + return ICON_SMARTGUN; + + case AMMO_FLAMETHROWER : + case AMMO_FIREDAMAGE_POSTMAX : + return ICON_FLAMER; + + case AMMO_SADAR_TOW : + case AMMO_SADAR_BLAST : + return ICON_SADAR; + + case AMMO_GRENADE : + return ICON_GRENADE_STANDARD; + + case AMMO_FRAGMENTATION_GRENADE : + case AMMO_FLECHETTE_POSTMAX : + return ICON_GRENADE_FRAG; + + case AMMO_PROXIMITY_GRENADE : + return ICON_GRENADE_PROX; + + case AMMO_MINIGUN : + return ICON_MINIGUN ; + + case AMMO_MARINE_PISTOL : + case AMMO_MARINE_PISTOL_PC : + return ICON_MARINE_PISTOL; + + case AMMO_CUDGEL : + return ICON_CUDGEL; + + case AMMO_FRISBEE : + case AMMO_FRISBEE_BLAST : + case AMMO_FRISBEE_FIRE : + return ICON_SKEETER; + + + case AMMO_PRED_WRISTBLADE : + case AMMO_HEAVY_PRED_WRISTBLADE : + case AMMO_PRED_TROPHY_KILLSECTION : + return ICON_WRISTBLADE; + + case AMMO_PRED_PISTOL : + return ICON_PRED_PISTOL; + + case AMMO_PRED_RIFLE : + return ICON_SPEARGUN; + + case AMMO_PRED_ENERGY_BOLT : + case AMMO_PLASMACASTER_NPCKILL : + case AMMO_PLASMACASTER_PCKILL : + return ICON_SHOULDERCANNON; + + case AMMO_PRED_DISC : + return ICON_DISC; + + case AMMO_PREDPISTOL_STRIKE : + return ICON_PRED_PISTOL; + + + case AMMO_ALIEN_CLAW : + return ICON_CLAW; + + case AMMO_ALIEN_TAIL : + return ICON_TAIL; + + case AMMO_ALIEN_BITE_KILLSECTION : + case AMMO_PC_ALIEN_BITE : + case AMMO_ALIEN_BITE_KILLSECTION_SUPER : + return ICON_JAWS; + } + + return 0; +} + +void AddNetMsg_PlayerKilled(int objectId,DAMAGE_PROFILE* damage) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_PLAYERKILLED *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_PLAYERKILLED); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* definitely should be actually dead */ + LOCALASSERT(PlayerStatusPtr->IsAlive==0); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_PLAYERKILLED *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_PlayerKilled; + + /* fill out the message: myNetworkkillerId should either be NULL indicating that player + has killed himself, or the DPID of the killer (which may in fact be the player's DPID)*/ + messagePtr->objectId=objectId; /* ID of the new corpse. */ + messagePtr->killerId = myNetworkKillerId; + messagePtr->myType=netGameData.myCharacterType; + + if(myNetworkKillerId) + { + int killer_index=PlayerIdInPlayerList(myNetworkKillerId); + if(killer_index!=NET_IDNOTINPLAYERLIST) + { + messagePtr->killerType=netGameData.playerData[killer_index].characterType; + } + else + { + //the player doing the damage has either left the game , or never existed. + //call it suicide then. + myNetworkKillerId=AVPDPNetID; + messagePtr->killerId=0; + } + } + + if(!myNetworkKillerId || myNetworkKillerId==AVPDPNetID) + { + //suicide (or killed by alien , in which case this will be corrected a few lines later) + messagePtr->killerType=messagePtr->myType; + } + + //find the icon for the weapon used + messagePtr->weaponIcon = GetWeaponIconFromDamage(damage); + + /*look at the damage type to see if the damage was done by an ai alien*/ + if(damage) + { + switch (damage->Id) + { + case AMMO_NPC_ALIEN_CLAW : + case AMMO_NPC_ALIEN_TAIL : + case AMMO_NPC_ALIEN_BITE : + messagePtr->killerType=NGCT_AI_Alien; + break; + + case AMMO_NPC_PREDALIEN_CLAW : + case AMMO_NPC_PREDALIEN_BITE : + case AMMO_NPC_PREDALIEN_TAIL : + messagePtr->killerType=NGCT_AI_Predalien; + break; + + case AMMO_NPC_PRAETORIAN_CLAW : + case AMMO_NPC_PRAETORIAN_BITE : + case AMMO_NPC_PRAETORIAN_TAIL : + messagePtr->killerType=NGCT_AI_Praetorian; + break; + } + } + Inform_PlayerHasDied(myNetworkKillerId,AVPDPNetID,messagePtr->killerType,messagePtr->weaponIcon); + + if(AvP.Network==I_Host) + { + DoNetScoresForHostDeath(messagePtr->myType,messagePtr->killerType); + } + +} + +void AddNetMsg_PlayerDeathAnim(int deathId,int objectId) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_CORPSEDEATHANIM *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_CORPSEDEATHANIM); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_CORPSEDEATHANIM *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_CorpseDeathAnim; + + messagePtr->objectId=objectId; /* ID of the new corpse. */ + messagePtr->deathId = deathId; + +} + +void AddNetMsg_PlayerLeaving(void) +{ + NETMESSAGEHEADER *headerPtr; + int headerSize = sizeof(NETMESSAGEHEADER); + + /* some conditions */ + //LOCALASSERT(AvP.Network==I_Peer); + /* yes: need to send this before changing state, as we need to know our previous state, + and sendMessage requires one of these two states anyway */ + LOCALASSERT((netGameData.myGameState==NGS_StartUp)||(netGameData.myGameState==NGS_Playing)||(netGameData.myGameState==NGS_Joining)||(netGameData.myGameState==NGS_EndGame)||(netGameData.myGameState==NGS_EndGameScreen)); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_PlayerLeaving; +} + +void AddNetMsg_AllGameScores(void) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_ALLGAMESCORES *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_ALLGAMESCORES); + + /* should be sent by host only, whilst in end game */ + LOCALASSERT(AvP.Network==I_Host); + LOCALASSERT((netGameData.myGameState==NGS_Playing)||(netGameData.myGameState==NGS_EndGameScreen)); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_ALLGAMESCORES *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_AllGameScores; + + /*fill out the message */ + { int i,j; + for(i=0;iplayerFrags[i][j] = netGameData.playerData[i].playerFrags[j]; + } + messagePtr->playerScores[i] = netGameData.playerData[i].playerScore; + messagePtr->playerScoresAgainst[i] = netGameData.playerData[i].playerScoreAgainst; + + for(j=0;j<3;j++) + { + messagePtr->aliensKilled[i][j]=netGameData.playerData[i].aliensKilled[j]; + } + + messagePtr->deathsFromAI[i] = netGameData.playerData[i].deathsFromAI; + } + } +} + +void AddNetMsg_PlayerScores(int playerId) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_PLAYERSCORES *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_PLAYERSCORES); + + /* should be sent by host only, whilst playing game */ + LOCALASSERT(AvP.Network==I_Host); + LOCALASSERT((netGameData.myGameState==NGS_Playing)); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_PLAYERSCORES *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_PlayerScores; + + /*fill out the message */ + messagePtr->playerId = (unsigned char)playerId; + { int i; + for(i=0;iplayerFrags[i] = netGameData.playerData[playerId].playerFrags[i]; + } + messagePtr->playerScore=netGameData.playerData[playerId].playerScore; + messagePtr->playerScoreAgainst=netGameData.playerData[playerId].playerScoreAgainst; + + for(i=0;i<3;i++) + { + messagePtr->aliensKilled[i]=netGameData.playerData[playerId].aliensKilled[i]; + } + + messagePtr->deathsFromAI=netGameData.playerData[playerId].deathsFromAI; + } +} + +void AddNetMsg_ScoreChange(int killerIndex,int victimIndex) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_SCORECHANGE *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_SCORECHANGE); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_SCORECHANGE *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_ScoreChange; + + /* Fill in message. */ + messagePtr->killerIndex=(unsigned char) killerIndex; + messagePtr->victimIndex=(unsigned char) victimIndex; + if(killerIndex==NET_MAXPLAYERS) + { + //killed by ai + messagePtr->fragCount=netGameData.playerData[victimIndex].deathsFromAI; + } + else + { + //killed by a player + messagePtr->fragCount=netGameData.playerData[killerIndex].playerFrags[victimIndex]; + messagePtr->killerScoreFor=netGameData.playerData[killerIndex].playerScore; + } + messagePtr->victimScoreAgainst=netGameData.playerData[victimIndex].playerScoreAgainst; + +} + +void AddNetMsg_SpeciesScores() +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_SPECIESSCORES *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_SPECIESSCORES); + int i; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_SPECIESSCORES *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_SpeciesScores; + + /* Fill in message. */ + for(i=0;i<3;i++) + { + messagePtr->teamScores[i]=netGameData.teamScores[i]; + } +} + +/* for sending information about bullet ricochets and plasma impacts */ +void AddNetMsg_LocalRicochet(AVP_BEHAVIOUR_TYPE behaviourType, VECTORCH *position, VECTORCH *direction) +{ +} + +void AddNetMsg_LocalObjectState(STRATEGYBLOCK *sbPtr) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_LOBSTATE *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_LOBSTATE); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_LOBSTATE *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_LocalObjectState; + + /* fill out the message */ + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + LOCALASSERT(dynPtr); +// LOCALASSERT((dynPtr->Position.vx < 4194304)&&(dynPtr->Position.vx > -4194304)); /* 23 bits of data */ +// LOCALASSERT((dynPtr->Position.vy < 4194304)&&(dynPtr->Position.vy > -4194304)); /* 23 bits of data */ +// LOCALASSERT((dynPtr->Position.vz < 4194304)&&(dynPtr->Position.vz > -4194304)); /* 23 bits of data */ + LOCALASSERT((dynPtr->OrientEuler.EulerX >=0 )&&(dynPtr->OrientEuler.EulerX < 4096)); /* 9 bits of signed data */ + LOCALASSERT((dynPtr->OrientEuler.EulerY >=0 )&&(dynPtr->OrientEuler.EulerY < 4096)); /* 9 bits of signed data */ + LOCALASSERT((dynPtr->OrientEuler.EulerZ >=0 )&&(dynPtr->OrientEuler.EulerZ < 4096)); /* 9 bits of signed data */ + + /* NB we can fit +-4194303 into 23 bits */ + if(dynPtr->Position.vx < -4100000) messagePtr->xPos = -4100000; + else if(dynPtr->Position.vx > 4100000) messagePtr->xPos = 4100000; + else messagePtr->xPos = dynPtr->Position.vx; + messagePtr->xOrient = (dynPtr->OrientEuler.EulerX>>NET_EULERSCALESHIFT); + + if(dynPtr->Position.vy < -4100000) messagePtr->yPos = -4100000; + else if(dynPtr->Position.vy > 4100000) messagePtr->yPos = 4100000; + else messagePtr->yPos = dynPtr->Position.vy; + messagePtr->yOrient = (dynPtr->OrientEuler.EulerY>>NET_EULERSCALESHIFT); + + if(dynPtr->Position.vz < -4100000) messagePtr->zPos = -4100000; + else if(dynPtr->Position.vz > 4100000) messagePtr->zPos = 4100000; + else messagePtr->zPos = dynPtr->Position.vz; + messagePtr->zOrient = (dynPtr->OrientEuler.EulerZ>>NET_EULERSCALESHIFT); + } + + { + int obId = *((int *)(&(sbPtr->SBname[4]))); +// LOCALASSERT((obId >= -NET_MAXOBJECTID)&&(obId <= NET_MAXOBJECTID)); + messagePtr->objectId = obId; + } + + messagePtr->event_flag=0; + + LOCALASSERT((sbPtr->I_SBtype >= 0)&&(sbPtr->I_SBtype < 256)); + messagePtr->type = (unsigned char)sbPtr->I_SBtype; + LOCALASSERT((sbPtr->I_SBtype == I_BehaviourRocket)|| + (sbPtr->I_SBtype == I_BehaviourPredatorEnergyBolt)|| + (sbPtr->I_SBtype == I_BehaviourFrisbeeEnergyBolt)|| + (sbPtr->I_SBtype == I_BehaviourPPPlasmaBolt)|| + (sbPtr->I_SBtype == I_BehaviourSpeargunBolt)|| + (sbPtr->I_SBtype == I_BehaviourGrenade)|| + (sbPtr->I_SBtype == I_BehaviourPulseGrenade)|| + (sbPtr->I_SBtype == I_BehaviourFlareGrenade)|| + (sbPtr->I_SBtype == I_BehaviourFragmentationGrenade)|| + (sbPtr->I_SBtype == I_BehaviourClusterGrenade)|| + (sbPtr->I_SBtype == I_BehaviourNPCPredatorDisc)|| + (sbPtr->I_SBtype == I_BehaviourPredatorDisc_SeekTrack)|| + (sbPtr->I_SBtype == I_BehaviourAlienSpit)|| + (sbPtr->I_SBtype == I_BehaviourProximityGrenade)|| + (sbPtr->I_SBtype == I_BehaviourInanimateObject)|| + (sbPtr->I_SBtype == I_BehaviourFrisbee)|| + (sbPtr->I_SBtype == I_BehaviourNetCorpse)); + + #if 1 + if (sbPtr->I_SBtype==I_BehaviourInanimateObject) { + INANIMATEOBJECT_STATUSBLOCK* objStatPtr = sbPtr->SBdataptr; + + messagePtr->IOType = (unsigned char)objStatPtr->typeId; + messagePtr->subtype = (unsigned char)objStatPtr->subType; + } else { + messagePtr->IOType = (unsigned char)IOT_Non; + messagePtr->subtype = (unsigned char)0; + } + #endif + + if (sbPtr->I_SBtype==I_BehaviourPredatorDisc_SeekTrack) { + PC_PRED_DISC_BEHAV_BLOCK *bbPtr = (PC_PRED_DISC_BEHAV_BLOCK * ) sbPtr->SBdataptr; + + if (bbPtr->Stuck) { + /* Signal stuck-ness. */ + messagePtr->event_flag=1; + } + else if(bbPtr->Bounced) + { + messagePtr->event_flag=2; + bbPtr->Bounced=0; + } + } + else if (sbPtr->I_SBtype==I_BehaviourFrisbee) { + FRISBEE_BEHAV_BLOCK *fbPtr = (FRISBEE_BEHAV_BLOCK * ) sbPtr->SBdataptr; + + if(fbPtr->Bounced) + { + messagePtr->event_flag=2; + fbPtr->Bounced=0; + } + } + else if(sbPtr->I_SBtype==I_BehaviourFlareGrenade) + { + FLARE_BEHAV_BLOCK *bbPtr = (FLARE_BEHAV_BLOCK * ) sbPtr->SBdataptr; + if(bbPtr->becomeStuck) + { + //set the event flag so that other players will start the flare noise + messagePtr->event_flag=1; + bbPtr->becomeStuck=0; + } + } + else if ((sbPtr->I_SBtype==I_BehaviourGrenade)||(sbPtr->I_SBtype==I_BehaviourClusterGrenade)) + { + GRENADE_BEHAV_BLOCK *bbPtr = (GRENADE_BEHAV_BLOCK * ) sbPtr->SBdataptr; + if (bbPtr->bouncelastframe) { + /* Set event flag to record bounce sound. */ + messagePtr->event_flag=1; + } + } +} + + +void AddNetMsg_LocalObjectDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int sectionID,int delta_seq,int delta_sub_seq,VECTORCH* incoming) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_LOBDAMAGED_HEADER *messageHeader=0; + NETMESSAGE_DAMAGE_PROFILE *messageProfile=0; + NETMESSAGE_DAMAGE_MULTIPLE *messageMultiple=0; + NETMESSAGE_DAMAGE_SECTION *messageSection=0; + NETMESSAGE_DAMAGE_DELTA *messageDelta=0; + NETMESSAGE_DAMAGE_DIRECTION *messageDirection=0; + + int headerSize = sizeof(NETMESSAGEHEADER); + int maxMessageSize = sizeof(NETMESSAGE_LOBDAMAGED_HEADER)+ + sizeof(NETMESSAGE_DAMAGE_PROFILE)+ + sizeof(NETMESSAGE_DAMAGE_MULTIPLE)+ + sizeof(NETMESSAGE_DAMAGE_SECTION)+ + sizeof(NETMESSAGE_DAMAGE_DELTA)+ + sizeof(NETMESSAGE_DAMAGE_DIRECTION); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + maxMessageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_LocalObjectDamaged; + + { + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + + LOCALASSERT(ghostData); + if(sbPtr->I_SBtype != I_BehaviourNetGhost) + { + LOCALASSERT(1==0); + } + +/*--------------------** +** set up the header ** +**--------------------*/ + messageHeader = (NETMESSAGE_LOBDAMAGED_HEADER *)endSendBuffer; + endSendBuffer += sizeof(NETMESSAGE_LOBDAMAGED_HEADER); + + messageHeader->playerId=ghostData->playerId; + messageHeader->objectId = ghostData->playerObjectId; + messageHeader->ammo_id=damage->Id; + +/*-----------------** +** damage profile ** +**-----------------*/ + messageHeader->damageProfile=1; + if(damage->Id>AMMO_NONE && damage->IdId].MaxDamage[AvP.Difficulty])) + { + messageHeader->damageProfile=0; + } + } + else if(damage->Id==AMMO_FLECHETTE_POSTMAX) + { + messageHeader->damageProfile=0; + } + if(messageHeader->damageProfile) + { + messageProfile = (NETMESSAGE_DAMAGE_PROFILE *)endSendBuffer; + endSendBuffer += sizeof(NETMESSAGE_DAMAGE_PROFILE); + + messageProfile->Impact = damage->Impact; + messageProfile->Cutting = damage->Cutting; + messageProfile->Penetrative = damage->Penetrative; + messageProfile->Fire = damage->Fire; + messageProfile->Electrical = damage->Electrical; + messageProfile->Acid = damage->Acid; + + messageProfile->ExplosivePower=damage->ExplosivePower; + messageProfile->Slicing=damage->Slicing; + messageProfile->ProduceBlood=damage->ProduceBlood; + messageProfile->ForceBoom=damage->ForceBoom; + + messageProfile->BlowUpSections=damage->BlowUpSections; + messageProfile->Special=damage->Special; + messageProfile->MakeExitWounds=damage->MakeExitWounds; + + } + +/*-----------------** +** damage multiple ** +**-----------------*/ + if(multiple!=ONE_FIXED) + { + messageHeader->multiple=1; + messageMultiple = (NETMESSAGE_DAMAGE_MULTIPLE *)endSendBuffer; + endSendBuffer += sizeof(NETMESSAGE_DAMAGE_MULTIPLE); + + messageMultiple->multiple=multiple; + + } + else + { + messageHeader->multiple=0; + } +/*------------** +** section id ** +**------------*/ + if(sectionID!=-1) + { + messageHeader->sectionID=1; + messageSection = (NETMESSAGE_DAMAGE_SECTION *)endSendBuffer; + endSendBuffer += sizeof(NETMESSAGE_DAMAGE_SECTION); + + messageSection->SectionID = (short)sectionID; + } + else + { + messageHeader->sectionID=0; + } + +/*----------------** +** delta sequence ** +**----------------*/ + if(delta_seq!=-1) + { + messageHeader->delta_seq=1; + messageDelta = (NETMESSAGE_DAMAGE_DELTA *)endSendBuffer; + endSendBuffer += sizeof(NETMESSAGE_DAMAGE_DELTA); + + messageDelta->Delta_Sequence=(char)delta_seq; + messageDelta->Delta_Sub_Sequence=(char)delta_sub_seq; + } + else + { + messageHeader->delta_seq=0; + } + +/*-------------------** +** direction ** +**-------------------*/ + + if(incoming && sbPtr->DynPtr) + { + VECTORCH direction=*incoming; + + messageHeader->direction=1; + messageDirection = (NETMESSAGE_DAMAGE_DIRECTION *)endSendBuffer; + endSendBuffer += sizeof(NETMESSAGE_DAMAGE_DIRECTION); + + //need to rotate the vector into world space + RotateVector(&direction,&sbPtr->DynPtr->OrientMat); + + //compress vector + messageDirection->direction_x=direction.vx>>7; + messageDirection->direction_y=direction.vy>>7; + messageDirection->direction_z=direction.vz>>7; + } + else + { + messageHeader->direction=0; + } + + } + //that's it +} + +void AddNetMsg_LocalObjectDestroyed_Request(STRATEGYBLOCK *sbPtr) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_LOBDESTROYED_REQUEST *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_LOBDESTROYED_REQUEST); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_LOBDESTROYED_REQUEST *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_LocalObjectDestroyed_Request; + + /* fill out message */ + { + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + + LOCALASSERT(ghostData); + if(sbPtr->I_SBtype != I_BehaviourNetGhost) + { + LOCALASSERT(1==0); + } + + messagePtr->playerId = ghostData->playerId; +/* + if((ghostData->playerObjectId < -NET_MAXOBJECTID)||(ghostData->playerObjectId > NET_MAXOBJECTID)) + { + LOCALASSERT(1==0); + } +*/ + messagePtr->objectId = ghostData->playerObjectId; + /* That's it. */ + } +} + +void AddNetMsg_LocalObjectDestroyed(STRATEGYBLOCK *sbPtr) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_LOBDESTROYED *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_LOBDESTROYED); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_LOBDESTROYED *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_LocalObjectDestroyed; + + /* fill out message */ + { + int obId = *((int *)(&(sbPtr->SBname[4]))); +// LOCALASSERT((obId >= -NET_MAXOBJECTID)&&(obId <= NET_MAXOBJECTID)); + messagePtr->objectId = obId; + } +} + +void AddNetMsg_InanimateObjectDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_INANIMATEDAMAGED_HEADER *messageHeader=0; + NETMESSAGE_DAMAGE_PROFILE *messageProfile=0; + NETMESSAGE_DAMAGE_MULTIPLE *messageMultiple=0; + + int headerSize = sizeof(NETMESSAGEHEADER); + int maxMessageSize = sizeof(NETMESSAGE_INANIMATEDAMAGED_HEADER)+ + sizeof(NETMESSAGE_DAMAGE_PROFILE)+ + sizeof(NETMESSAGE_DAMAGE_MULTIPLE); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + /* shouldn't be sending this if we are the host */ + LOCALASSERT(AvP.Network!=I_Host); + /* only send for inanimate objects*/ + LOCALASSERT(sbPtr->I_SBtype==I_BehaviourInanimateObject || + sbPtr->I_SBtype==I_BehaviourPlacedLight); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + maxMessageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_InanimateObjectDamaged; + +/*--------------------** +** set up the header ** +**--------------------*/ + messageHeader = (NETMESSAGE_INANIMATEDAMAGED_HEADER *)endSendBuffer; + endSendBuffer += sizeof(NETMESSAGE_INANIMATEDAMAGED_HEADER); + + COPY_NAME(&(messageHeader->name),&(sbPtr->SBname)); + messageHeader->ammo_id=damage->Id; + + +/*-----------------** +** damage profile ** +**-----------------*/ + messageHeader->damageProfile=1; + if(damage->Id>AMMO_NONE && damage->IdId].MaxDamage[AvP.Difficulty])) + { + messageHeader->damageProfile=0; + } + } + if(messageHeader->damageProfile) + { + messageProfile = (NETMESSAGE_DAMAGE_PROFILE *)endSendBuffer; + endSendBuffer += sizeof(NETMESSAGE_DAMAGE_PROFILE); + + messageProfile->Impact = damage->Impact; + messageProfile->Cutting = damage->Cutting; + messageProfile->Penetrative = damage->Penetrative; + messageProfile->Fire = damage->Fire; + messageProfile->Electrical = damage->Electrical; + messageProfile->Acid = damage->Acid; + + messageProfile->ExplosivePower=damage->ExplosivePower; + messageProfile->Slicing=damage->Slicing; + messageProfile->ProduceBlood=damage->ProduceBlood; + messageProfile->ForceBoom=damage->ForceBoom; + + messageProfile->BlowUpSections=damage->BlowUpSections; + messageProfile->Special=damage->Special; + messageProfile->MakeExitWounds=damage->MakeExitWounds; + + } +/*-----------------** +** damage multiple ** +**-----------------*/ + if(multiple!=ONE_FIXED) + { + messageHeader->multiple=1; + messageMultiple = (NETMESSAGE_DAMAGE_MULTIPLE *)endSendBuffer; + endSendBuffer += sizeof(NETMESSAGE_DAMAGE_MULTIPLE); + + messageMultiple->multiple=multiple; + + } + else + { + messageHeader->multiple=0; + } + +} + + +void AddNetMsg_InanimateObjectDestroyed(STRATEGYBLOCK *sbPtr) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_INANIMATEDESTROYED *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_INANIMATEDESTROYED); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* should only send if we're the host */ + LOCALASSERT(AvP.Network==I_Host); + LOCALASSERT(sbPtr->I_SBtype==I_BehaviourInanimateObject || + sbPtr->I_SBtype==I_BehaviourPlacedLight); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_INANIMATEDESTROYED *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_InanimateObjectDestroyed; + + /* fill out message */ + { + COPY_NAME(&(messagePtr->name),&(sbPtr->SBname)); + } +} + +void AddNetMsg_ObjectPickedUp(char* objectName) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_OBJECTPICKEDUP *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_OBJECTPICKEDUP); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_OBJECTPICKEDUP *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_ObjectPickedUp; + + /* fill out the message */ + COPY_NAME((&messagePtr->name[0]),objectName); +} + +void AddNetMsg_EndGame(void) +{ + NETMESSAGEHEADER *headerPtr; + int headerSize = sizeof(NETMESSAGEHEADER); + + /* should be sent by host only, in endGame state */ + LOCALASSERT(AvP.Network==I_Host); + /* yes: need to send this before changing state, as we need to know our previous state, + and sendMessage requires one of these two states anyway */ + LOCALASSERT((netGameData.myGameState==NGS_StartUp)||(netGameData.myGameState==NGS_Playing)||(netGameData.myGameState==NGS_Joining)); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_EndGame; +} + +void AddNetMsg_LOSRequestBinarySwitch(STRATEGYBLOCK *sbPtr) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_LOSREQUESTBINARYSWITCH *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_LOSREQUESTBINARYSWITCH); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* also, the object must be a binary switch */ + if(sbPtr->I_SBtype!=I_BehaviourBinarySwitch && sbPtr->I_SBtype!=I_BehaviourLinkSwitch) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_LOSREQUESTBINARYSWITCH *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_LOSRequestBinarySwitch; + + /* fill out the message */ + COPY_NAME((&messagePtr->name[0]),&(sbPtr->SBname)); +} + +void AddNetMsg_PlatformLiftState(STRATEGYBLOCK *sbPtr) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_PLATFORMLIFTSTATE *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_PLATFORMLIFTSTATE); + PLATFORMLIFT_BEHAVIOUR_BLOCK *platLiftData; + + /* only hosts should send this*/ + LOCALASSERT(AvP.Network==I_Host); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + if(sbPtr->I_SBtype!=I_BehaviourPlatform) return; + platLiftData = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(platLiftData); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_PLATFORMLIFTSTATE *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_PlatformLiftState; + + /* fill out the message */ + COPY_NAME((&messagePtr->name[0]),&(sbPtr->SBname)); + messagePtr->state = (char)(platLiftData->state); +} + +void AddNetMsg_RequestPlatformLiftActivate(STRATEGYBLOCK *sbPtr) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE); + PLATFORMLIFT_BEHAVIOUR_BLOCK *platLiftData; + + /* only peers should send this*/ + LOCALASSERT(AvP.Network==I_Peer); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + if(sbPtr->I_SBtype!=I_BehaviourPlatform) return; + platLiftData = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)sbPtr->SBdataptr; + LOCALASSERT(platLiftData); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_RequestPlatformLiftActivate; + + /* fill out the message */ + COPY_NAME((&messagePtr->name[0]),&(sbPtr->SBname)); +} + +void AddNetMsg_PlayerAutoGunState(STRATEGYBLOCK *sbPtr) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_AGUNSTATE *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_AGUNSTATE); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_AGUNSTATE *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_PlayerAutoGunState; + + /* fill out the message */ + { + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + + LOCALASSERT(dynPtr); + LOCALASSERT((dynPtr->Position.vx < 4194304)&&(dynPtr->Position.vx > -4194304)); /* 23 bits of data */ + LOCALASSERT((dynPtr->Position.vy < 4194304)&&(dynPtr->Position.vy > -4194304)); /* 23 bits of data */ + LOCALASSERT((dynPtr->Position.vz < 4194304)&&(dynPtr->Position.vz > -4194304)); /* 23 bits of data */ + LOCALASSERT((dynPtr->OrientEuler.EulerX >=0 )&&(dynPtr->OrientEuler.EulerX < 4096)); /* 9 bits of signed data */ + LOCALASSERT((dynPtr->OrientEuler.EulerY >=0 )&&(dynPtr->OrientEuler.EulerY < 4096)); /* 9 bits of signed data */ + LOCALASSERT((dynPtr->OrientEuler.EulerZ >=0 )&&(dynPtr->OrientEuler.EulerZ < 4096)); /* 9 bits of signed data */ + + /* NB we can fit +-4194303 into 23 bits */ + if(dynPtr->Position.vx < -4100000) messagePtr->xPos = -4100000; + else if(dynPtr->Position.vx > 4100000) messagePtr->xPos = 4100000; + else messagePtr->xPos = dynPtr->Position.vx; + messagePtr->xOrient = (dynPtr->OrientEuler.EulerX>>NET_EULERSCALESHIFT); + + if(dynPtr->Position.vy < -4100000) messagePtr->yPos = -4100000; + else if(dynPtr->Position.vy > 4100000) messagePtr->yPos = 4100000; + else messagePtr->yPos = dynPtr->Position.vy; + messagePtr->yOrient = (dynPtr->OrientEuler.EulerY>>NET_EULERSCALESHIFT); + + if(dynPtr->Position.vz < -4100000) messagePtr->zPos = -4100000; + else if(dynPtr->Position.vz > 4100000) messagePtr->zPos = 4100000; + else messagePtr->zPos = dynPtr->Position.vz; + messagePtr->zOrient = (dynPtr->OrientEuler.EulerZ>>NET_EULERSCALESHIFT); + } + + /* add the object Id */ + { + int obId = *((int *)(&(sbPtr->SBname[4]))); +// LOCALASSERT((obId >= -NET_MAXOBJECTID)&&(obId <= NET_MAXOBJECTID)); + messagePtr->objectId = obId; + } + + /* am I firing?? */ + { + AUTOGUN_STATUS_BLOCK *agData; + agData = (AUTOGUN_STATUS_BLOCK*)(sbPtr->SBdataptr); + LOCALASSERT(agData); + if(agData->Firing) messagePtr->IAmFiring = 1; + else messagePtr->IAmFiring = 0; + if(agData->behaviourState==I_disabled) messagePtr->IAmEnabled = 0; + else messagePtr->IAmEnabled = 1; + } +} + +/* KJL 17:49:31 20/01/98 - transmit make decal info */ +void AddNetMsg_MakeDecal(enum DECAL_ID decalID, VECTORCH *normalPtr, VECTORCH *positionPtr, int moduleIndex) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_MAKEDECAL *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_MAKEDECAL); + + extern int GlobalFrameCounter; + static int DecalCountThisFrame=0; + static int FrameStamp; + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + if(FrameStamp!=GlobalFrameCounter) + { + FrameStamp=GlobalFrameCounter; + DecalCountThisFrame=0; + } + + /*Limit the decal count per frame, even in lan games. Otherwise it is easy to get assertions from having tons + of alien blood particles*/ + if(DecalCountThisFrame>=10) + { + return; + } + DecalCountThisFrame++; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > (numBytesLeft-1000)) + { + // LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_MAKEDECAL *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_MakeDecal; + + /* fill out the message */ + messagePtr->DecalID = decalID; + messagePtr->Position = *positionPtr; + messagePtr->Direction = *normalPtr; + messagePtr->ModuleIndex = moduleIndex; +} + +/* KJL 14:34:45 08/04/98 - broadcast a message to the other players */ +void AddNetMsg_ChatBroadcast(char *string,BOOL same_species_only) +{ + NETMESSAGEHEADER *headerPtr; + char *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize; + unsigned char stringLength = 1; + + //remove the console (assuming it is on screen) + if(IOFOCUS_AcceptTyping()) + { + IOFOCUS_Toggle(); + } + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + + { + char *ptr = string; + while(*ptr && stringLength<255) + { + stringLength++; + ptr++; + } + } + + if (stringLength==1 || stringLength>=255) return; + + messageSize = stringLength+1; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_ChatBroadcast; + + /* fill out the message */ + { + char *ptr = string; + //first byte used to distinguish between SAY and SPECIES_SAY + *messagePtr++=(char)same_species_only; + + + do + { + *messagePtr++ = *ptr; + } + while(*ptr++); + } + + + { + sprintf(OnScreenMessageBuffer,"%s: %s",netGameData.playerData[PlayerIdInPlayerList(AVPDPNetID)].name,string); + NewOnScreenMessage(OnScreenMessageBuffer); + } + +} + +/* KJL 11:28:44 27/04/98 - make an explosion (just the sfx; damage is handled separately */ +void AddNetMsg_MakeExplosion(VECTORCH *positionPtr, enum EXPLOSION_ID explosionID) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_MAKEEXPLOSION *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_MAKEEXPLOSION); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_MAKEEXPLOSION *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_MakeExplosion; + + /* fill out the message */ + messagePtr->Position = *positionPtr; + messagePtr->ExplosionID = explosionID; +} +void AddNetMsg_MakeFlechetteExplosion(VECTORCH *positionPtr, int seed) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_MAKEFLECHETTEEXPLOSION *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_MAKEFLECHETTEEXPLOSION); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_MAKEFLECHETTEEXPLOSION *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_MakeFlechetteExplosion; + + /* fill out the message */ + messagePtr->Position = *positionPtr; + messagePtr->Seed = seed; +} + +void AddNetMsg_MakePlasmaExplosion(VECTORCH *positionPtr, VECTORCH *fromPositionPtr, enum EXPLOSION_ID explosionID) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_MAKEPLASMAEXPLOSION *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_MAKEPLASMAEXPLOSION); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_MAKEPLASMAEXPLOSION *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_MakePlasmaExplosion; + + /* fill out the message */ + messagePtr->Position = *positionPtr; + messagePtr->FromPosition = *fromPositionPtr; + messagePtr->ExplosionID = explosionID; +} + +/* KJL 11:27:47 20/05/98 - predator laser sights */ +void AddNetMsg_PredatorLaserSights(VECTORCH *positionPtr, VECTORCH *normalPtr, DISPLAYBLOCK *dispPtr) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_PREDATORSIGHTS *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_PREDATORSIGHTS); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_PREDATORSIGHTS *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_PredatorSights; + + /* fill out the message */ + { + MATRIXCH orientMat; + EULER orientation; + + MakeMatrixFromDirection(normalPtr,&orientMat); + MatrixToEuler(&orientMat, &orientation); + + /* NB we can fit +-4194303 into 23 bits */ + if(positionPtr->vx < -4100000) messagePtr->xPos = -4100000; + else if(positionPtr->vx > 4100000) messagePtr->xPos = 4100000; + else messagePtr->xPos = positionPtr->vx; + messagePtr->xOrient = (orientation.EulerX>>NET_EULERSCALESHIFT); + + if(positionPtr->vy < -4100000) messagePtr->yPos = -4100000; + else if(positionPtr->vy > 4100000) messagePtr->yPos = 4100000; + else messagePtr->yPos = positionPtr->vy; + messagePtr->yOrient = (orientation.EulerY>>NET_EULERSCALESHIFT); + + if(positionPtr->vz < -4100000) messagePtr->zPos = -4100000; + else if(positionPtr->vz > 4100000) messagePtr->zPos = 4100000; + else messagePtr->zPos = positionPtr->vz; + messagePtr->zOrient = (orientation.EulerZ>>NET_EULERSCALESHIFT); + + messagePtr->TargetID = 0; + if (dispPtr) + { + if (dispPtr->ObStrategyBlock) + { + if (dispPtr->ObStrategyBlock->I_SBtype == I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)dispPtr->ObStrategyBlock->SBdataptr; + + if (ghostDataPtr->playerObjectId==GHOST_PLAYEROBJECTID) + { + messagePtr->TargetID = ghostDataPtr->playerId; + } + } + } + } + } +} + +void AddNetMsg_LocalObjectOnFire(STRATEGYBLOCK *sbPtr) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_LOBONFIRE *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_LOBONFIRE); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_LOBONFIRE *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_LocalObjectOnFire; + + /* fill out message */ + { + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + + LOCALASSERT(ghostData); + if(sbPtr->I_SBtype != I_BehaviourNetGhost) + { + LOCALASSERT(1==0); + } + + messagePtr->playerId = ghostData->playerId; + /* LOCALASSERT((ghostData->playerObjectId >= -NET_MAXOBJECTID)&&(ghostData->playerObjectId <= NET_MAXOBJECTID)); */ +/* + if((ghostData->playerObjectId < -NET_MAXOBJECTID)||(ghostData->playerObjectId > NET_MAXOBJECTID)) + { + LOCALASSERT(1==0); + } +*/ + messagePtr->objectId = ghostData->playerObjectId; + + /* That's all, folks. This object is on fire. */ + } +} + +void AddNetMsg_RestartNetworkGame(int seed) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_RESTARTGAME *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_RESTARTGAME); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_RESTARTGAME *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = NetMT_RestartNetworkGame; + + /* Fill in message. */ + messagePtr->seed=seed; + +} + +void AddNetMsg_FragmentalObjectsStatus(void) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_FRAGMENTALOBJECTSSTATUS *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_FRAGMENTALOBJECTSSTATUS); + static int object_batch=0; + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* only the host should send this */ + LOCALASSERT(AvP.Network==I_Host); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_FRAGMENTALOBJECTSSTATUS *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_FragmentalObjectsStatus; + messagePtr->BatchNumber=object_batch; + + /* fill out the message */ + { + int i; + int fragNumber=0; + int objectsToSkip=object_batch*(NUMBER_OF_FRAGMENTAL_OBJECTS<<3); + int noPlacedLights=0; + + LOCALASSERT(AvP.Network!=I_No_Network); + + for (i=0; iI_SBtype == I_BehaviourInanimateObject) + { + INANIMATEOBJECT_STATUSBLOCK* objectStatusPtr = sbPtr->SBdataptr; + LOCALASSERT(objectStatusPtr); + + if((objectStatusPtr->typeId == IOT_Static) && (!objectStatusPtr->Indestructable) && (!objectStatusPtr->ghosted_object) && (!objectStatusPtr->lifespanTimer)) + { + if(objectsToSkip>0) + { + objectsToSkip--; + continue; + } + WriteFragmentStatus(fragNumber++,(objectStatusPtr->respawnTimer==0)); + } + } + else if (sbPtr->I_SBtype == I_BehaviourPlacedLight) + { + PLACED_LIGHT_BEHAV_BLOCK* pl_bhv = sbPtr->SBdataptr; + LOCALASSERT(pl_bhv); + + if(!pl_bhv->Indestructable) + { + if(objectsToSkip>0) + { + objectsToSkip--; + continue; + } + WriteFragmentStatus(fragNumber++,(pl_bhv->state!=Light_State_Broken)); + } + } + if(fragNumber>=(NUMBER_OF_FRAGMENTAL_OBJECTS<<3))break; + } + if(i==NumActiveStBlocks) + { + object_batch=0; + } + else + { + //there are more objects to look at , so increment batch + object_batch++; + } + + + textprint("noPlacedLights %d\n",noPlacedLights); + textprint("fragNumber %d\n",fragNumber); + + for (i=0; iStatusBitfield[i] = FragmentalObjectStatus[i]; + } + + + } +} + +void AddNetMsg_StrategySynch(void) +{ +/* + Scan through objects looking for strategies that may need to be synchronized between players. + Mainly switches and track objects + Only do 16 objects at a time , so as not to send too much data +*/ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_STRATEGYSYNCH *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_STRATEGYSYNCH); + static int object_batch=0; + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* only the host should send this */ + LOCALASSERT(AvP.Network==I_Host); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_STRATEGYSYNCH *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_StrategySynch; + messagePtr->BatchNumber=object_batch; + + /* fill out the message */ + { + int i; + int objectNumber=0; + int objectsToSkip=object_batch*(NUMBER_OF_STRATEGIES_TO_SYNCH); + + LOCALASSERT(AvP.Network!=I_No_Network); + + for (i=0; iI_SBtype == I_BehaviourBinarySwitch || + sbPtr->I_SBtype == I_BehaviourLinkSwitch || + sbPtr->I_SBtype == I_BehaviourTrackObject) + { + + if(objectsToSkip>0) + { + objectsToSkip--; + continue; + } + + switch(sbPtr->I_SBtype) + { + case I_BehaviourBinarySwitch : + WriteStrategySynch(objectNumber++,BinarySwitchGetSynchData(sbPtr)); + break; + case I_BehaviourLinkSwitch : + WriteStrategySynch(objectNumber++,LinkSwitchGetSynchData(sbPtr)); + break; + case I_BehaviourTrackObject : + WriteStrategySynch(objectNumber++,TrackObjectGetSynchData(sbPtr)); + break; + } + + } + if(objectNumber>=(NUMBER_OF_STRATEGIES_TO_SYNCH))break; + } + if(i==NumActiveStBlocks) + { + object_batch=0; + } + else + { + //there are more objects to look at , so increment batch + object_batch++; + } + + + for (i=0; i>2; i++) + { + messagePtr->StatusBitfield[i] = StrategySynchArray[i]; + } + + + } + + if(!netGameData.myStrategyCheckSum) netGameData.myStrategyCheckSum=GetStrategySynchObjectChecksum(); + messagePtr->strategyCheckSum=netGameData.myStrategyCheckSum; +} + +void AddNetMsg_CreateWeapon(char* objectName,int type,VECTORCH* location) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_CREATEWEAPON *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_CREATEWEAPON); + + /* only send this if we are playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_CREATEWEAPON *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_CreateWeapon; + + /* fill out the message */ + COPY_NAME((&messagePtr->name[0]),objectName); + messagePtr->location=*location; + messagePtr->type=type; +} +/* KJL 16:32:06 17/06/98 - alien AI network messages */ +void AddNetMsg_AlienAIState(STRATEGYBLOCK *sbPtr) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_ALIENAISTATE *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_ALIENAISTATE); + + DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; + ALIEN_STATUS_BLOCK *alienStatusPtr=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + LOCALASSERT(dynPtr); + GLOBALASSERT(alienStatusPtr); + + #if EXTRAPOLATION_TEST + if(UseExtrapolation && netGameData.sendFrequency) + { + BOOL updateRequired=FALSE; + VECTORCH facing; + //can we get away with not sending an update this frame + + //has it been a while since the last send + if(TimeCounterForExtrapolationtimeOfLastSend || + TimeCounterForExtrapolation-alienStatusPtr->timeOfLastSend>ONE_FIXED/4) + { + updateRequired=TRUE; + } + + if(dynPtr->LinImpulse.vx || dynPtr->LinImpulse.vy || dynPtr->LinImpulse.vz) + { + //alien is probably jumping , extrapolation doesn't work in this case + updateRequired=TRUE; + } + + //has the velocity changed + if(!updateRequired) + { + int diff=Magnitude(&dynPtr->LinVelocity)-Magnitude(&alienStatusPtr->lastVelocitySent); + if(diff>500 || -diff>500) + { + updateRequired=TRUE; + } + } + facing.vx=dynPtr->OrientMat.mat31; + facing.vy=dynPtr->OrientMat.mat32; + facing.vz=dynPtr->OrientMat.mat33; + + //has the facing changed + if(!updateRequired) + { + if(DotProduct(&facing,&alienStatusPtr->lastFacingSent)<64000) + { + updateRequired=TRUE; + } + } + + if(!updateRequired) return; + + //okay , we do need to send this frame + alienStatusPtr->timeOfLastSend=TimeCounterForExtrapolation; + alienStatusPtr->lastVelocitySent=dynPtr->LinVelocity; + alienStatusPtr->lastFacingSent=facing; + + } + #endif + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_ALIENAISTATE *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_AlienAIState; + + /* fill out our position and orientation */ + { + + LOCALASSERT((dynPtr->OrientEuler.EulerX >=0 )&&(dynPtr->OrientEuler.EulerX < 4096)); /* 9 bits of signed data */ + LOCALASSERT((dynPtr->OrientEuler.EulerY >=0 )&&(dynPtr->OrientEuler.EulerY < 4096)); /* 9 bits of signed data */ + LOCALASSERT((dynPtr->OrientEuler.EulerZ >=0 )&&(dynPtr->OrientEuler.EulerZ < 4096)); /* 9 bits of signed data */ + + /* NB we can fit +-4194303 into 23 bits */ + if(dynPtr->Position.vx < -4100000) messagePtr->xPos = -4100000; + else if(dynPtr->Position.vx > 4100000) messagePtr->xPos = 4100000; + else messagePtr->xPos = dynPtr->Position.vx; + messagePtr->xOrient = (dynPtr->OrientEuler.EulerX>>NET_EULERSCALESHIFT); + + if(dynPtr->Position.vy < -4100000) messagePtr->yPos = -4100000; + else if(dynPtr->Position.vy > 4100000) messagePtr->yPos = 4100000; + else messagePtr->yPos = dynPtr->Position.vy; + messagePtr->yOrient = (dynPtr->OrientEuler.EulerY>>NET_EULERSCALESHIFT); + + if(dynPtr->Position.vz < -4100000) messagePtr->zPos = -4100000; + else if(dynPtr->Position.vz > 4100000) messagePtr->zPos = 4100000; + else messagePtr->zPos = dynPtr->Position.vz; + messagePtr->zOrient = (dynPtr->OrientEuler.EulerZ>>NET_EULERSCALESHIFT); + + #if EXTRAPOLATION_TEST + messagePtr->standard_gravity=dynPtr->UseStandardGravity; + messagePtr->speed=Magnitude(&dynPtr->LinVelocity); + #endif + } + + /* fill out anim sequence */ + { + + + #if 1 + messagePtr->sequence_type = alienStatusPtr->HModelController.Sequence_Type; + messagePtr->sub_sequence = alienStatusPtr->HModelController.Sub_Sequence; + + //send the sequence length in 256ths of a second (instead of 65536ths) + GLOBALASSERT(alienStatusPtr->HModelController.Seconds_For_Sequence>=0 && alienStatusPtr->HModelController.Seconds_For_Sequence<32*ONE_FIXED); + messagePtr->sequence_length = alienStatusPtr->HModelController.Seconds_For_Sequence>>8; + + #else + if (alienStatusPtr->HModelController.Tweening==Controller_NoTweening) { + messagePtr->sequence_type = alienStatusPtr->HModelController.Sequence_Type; + messagePtr->sub_sequence = alienStatusPtr->HModelController.Sub_Sequence; + messagePtr->sequence_length = alienStatusPtr->HModelController.Seconds_For_Sequence; + } else { + /* Might be junk. */ + messagePtr->sequence_type = -1; + messagePtr->sub_sequence = -1; + messagePtr->sequence_length= -1; + } + #endif + messagePtr->AlienType = alienStatusPtr->Type; + } + + if (sbPtr->SBDamageBlock.IsOnFire) { + messagePtr->IAmOnFire=1; + } else { + messagePtr->IAmOnFire=0; + } + + /* fill out guid */ + { + int guid = *((int *)(&(sbPtr->SBname[4]))); +// LOCALASSERT((guid >= -NET_MAXOBJECTID)&&(guid <= NET_MAXOBJECTID)); + messagePtr->Guid = guid; + } + +} + +/* CDF 24/8/98 A better message. */ +void AddNetMsg_AlienAISeqChange(STRATEGYBLOCK *sbPtr,int sequence_type,int sub_sequence,int sequence_length,int tweening_time) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_ALIENSEQUENCECHANGE *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_ALIENSEQUENCECHANGE); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_ALIENSEQUENCECHANGE *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_AlienAISequenceChange; + + /* fill out anim sequence */ + + messagePtr->sequence_type =sequence_type ; + messagePtr->sub_sequence =sub_sequence ; + + //convert times into 256ths of a second + if(sequence_length==-1) + messagePtr->sequence_length=-1; + else + messagePtr->sequence_length=sequence_length>>8; + if(tweening_time==-1) + messagePtr->tweening_time =-1 ; + else + messagePtr->tweening_time =tweening_time>>8 ; + + /* fill out guid */ + { + int guid = *((int *)(&(sbPtr->SBname[4]))); +// LOCALASSERT((guid >= -NET_MAXOBJECTID)&&(guid <= NET_MAXOBJECTID)); + messagePtr->Guid = guid; + } + +} + +void AddNetMsg_AlienAIKilled(STRATEGYBLOCK *sbPtr,int death_code,int death_time, int GibbFactor,DAMAGE_PROFILE* damage) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_ALIENAIKILLED *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_ALIENAIKILLED); + + ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr; + + //don't do this if we aren't playing (possibly on end game screen) + if(netGameData.myGameState != NGS_Playing) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_ALIENAIKILLED *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_AlienAIKilled; + + /* fill out anim sequence */ + + messagePtr->death_code=death_code; + messagePtr->death_time=death_time; + messagePtr->GibbFactor=GibbFactor; + + messagePtr->killerId=myNetworkKillerId; + + + { + int killerIndex=PlayerIdInPlayerList(messagePtr->killerId); + if(killerIndex!=NET_IDNOTINPLAYERLIST) + { + netGameData.playerData[killerIndex].aliensKilled[alienStatus->Type]++; + messagePtr->killCount=netGameData.playerData[killerIndex].aliensKilled[alienStatus->Type]; + + //record ai's death for purposes of adjusting difficulty. + //(assuming that optionis being used) + GeneratorBalance_NoteAIDeath(); + } + else + { + /* + the player doing the damage has either left the game , or never existed. + call it suicide then. + (Could also be 'neutral' damage - flame jets) + */ + messagePtr->killerId=0; + messagePtr->killCount=0; + } + + } + + /* fill out guid */ + { + int guid = *((int *)(&(sbPtr->SBname[4]))); +// LOCALASSERT((guid >= -NET_MAXOBJECTID)&&(guid <= NET_MAXOBJECTID)); + messagePtr->Guid = guid; + } + + messagePtr->AlienType=alienStatus->Type; + + //find the icon for the weapon used + messagePtr->weaponIcon = GetWeaponIconFromDamage(damage); + + + Inform_AiHasDied(messagePtr->killerId,messagePtr->AlienType,messagePtr->weaponIcon); + +} + +void AddNetMsg_FarAlienPosition(STRATEGYBLOCK* sbPtr,int targetModuleIndex,int index,BOOL indexIsModuleIndex) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_FARALIENPOSITION *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_FARALIENPOSITION); + + ALIEN_STATUS_BLOCK *alienStatusPtr=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_FARALIENPOSITION *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_FarAlienPosition; + + /* fill out indeces */ + messagePtr->targetModuleIndex = targetModuleIndex; + messagePtr->index = index; + messagePtr->indexIsModuleIndex = indexIsModuleIndex; + + messagePtr->alienType = alienStatusPtr->Type; + + /* fill out guid */ + { + int guid = *((int *)(&(sbPtr->SBname[4]))); + messagePtr->Guid = guid; + } +} + +void AddNetMsg_GhostHierarchyDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int sectionID,VECTORCH* incoming) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER *messageHeader=0; + NETMESSAGE_DAMAGE_PROFILE *messageProfile=0; + NETMESSAGE_DAMAGE_MULTIPLE *messageMultiple=0; + NETMESSAGE_DAMAGE_SECTION *messageSection=0; + NETMESSAGE_DAMAGE_DIRECTION *messageDirection=0; + + int headerSize = sizeof(NETMESSAGEHEADER); + int maxMessageSize = sizeof(NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER)+ + sizeof(NETMESSAGE_DAMAGE_PROFILE)+ + sizeof(NETMESSAGE_DAMAGE_MULTIPLE)+ + sizeof(NETMESSAGE_DAMAGE_SECTION)+ + sizeof(NETMESSAGE_DAMAGE_DIRECTION); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + maxMessageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_GhostHierarchyDamaged; + + +/*--------------------** +** set up the header ** +**--------------------*/ + messageHeader = (NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER *)endSendBuffer; + endSendBuffer += sizeof(NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER); + + /* fill out guid */ + { + int guid = *((int *)(&(sbPtr->SBname[4]))); + messageHeader->Guid = guid; + } + messageHeader->ammo_id=damage->Id; + +/*-----------------** +** damage profile ** +**-----------------*/ + messageHeader->damageProfile=1; + if(damage->Id>AMMO_NONE && damage->IdId].MaxDamage[AvP.Difficulty])) + { + messageHeader->damageProfile=0; + } + } + if(messageHeader->damageProfile) + { + messageProfile = (NETMESSAGE_DAMAGE_PROFILE *)endSendBuffer; + endSendBuffer += sizeof(NETMESSAGE_DAMAGE_PROFILE); + + messageProfile->Impact = damage->Impact; + messageProfile->Cutting = damage->Cutting; + messageProfile->Penetrative = damage->Penetrative; + messageProfile->Fire = damage->Fire; + messageProfile->Electrical = damage->Electrical; + messageProfile->Acid = damage->Acid; + + messageProfile->ExplosivePower=damage->ExplosivePower; + messageProfile->Slicing=damage->Slicing; + messageProfile->ProduceBlood=damage->ProduceBlood; + messageProfile->ForceBoom=damage->ForceBoom; + + messageProfile->BlowUpSections=damage->BlowUpSections; + messageProfile->Special=damage->Special; + messageProfile->MakeExitWounds=damage->MakeExitWounds; + + } +/*-----------------** +** damage multiple ** +**-----------------*/ + if(multiple!=ONE_FIXED) + { + messageHeader->multiple=1; + messageMultiple = (NETMESSAGE_DAMAGE_MULTIPLE *)endSendBuffer; + endSendBuffer += sizeof(NETMESSAGE_DAMAGE_MULTIPLE); + + messageMultiple->multiple=multiple; + + } + else + { + messageHeader->multiple=0; + } + +/*------------** +** section id ** +**------------*/ + if(sectionID!=-1) + { + messageHeader->sectionID=1; + messageSection = (NETMESSAGE_DAMAGE_SECTION *)endSendBuffer; + endSendBuffer += sizeof(NETMESSAGE_DAMAGE_SECTION); + + messageSection->SectionID = (short)sectionID; + } + else + { + messageHeader->sectionID=0; + } + +/*-------------------** +** direction ** +**-------------------*/ + + if(incoming && sbPtr->DynPtr) + { + VECTORCH direction=*incoming; + + messageHeader->direction=1; + messageDirection = (NETMESSAGE_DAMAGE_DIRECTION *)endSendBuffer; + endSendBuffer += sizeof(NETMESSAGE_DAMAGE_DIRECTION); + + //need to rotate the vector into world space + RotateVector(&direction,&sbPtr->DynPtr->OrientMat); + + //compress vector + messageDirection->direction_x=direction.vx>>7; + messageDirection->direction_y=direction.vy>>7; + messageDirection->direction_z=direction.vz>>7; + } + else + { + messageHeader->direction=0; + } +} + + +void AddNetMsg_Gibbing(STRATEGYBLOCK *sbPtr,int gibbFactor,int seed) { + + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_GIBBING *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_GIBBING); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_GIBBING *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_Gibbing; + + messagePtr->gibbFactor=gibbFactor; + messagePtr->seed=seed; + + /* fill out guid */ + { + int guid = *((int *)(&(sbPtr->SBname[4]))); +// LOCALASSERT((guid >= -NET_MAXOBJECTID)&&(guid <= NET_MAXOBJECTID)); + messagePtr->Guid = guid; + } +} + + +void AddNetMsg_SpotAlienSound(int soundCategory,int alienType,int pitch,VECTORCH *position) { + + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_SPOTALIENSOUND *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_SPOTALIENSOUND); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_SPOTALIENSOUND *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_SpotAlienSound; + + /* Fill in message. */ + messagePtr->soundCategory=(unsigned char)soundCategory; + messagePtr->pitch=pitch; + messagePtr->alienType=(unsigned char)alienType; + + messagePtr->vx=position->vx; + messagePtr->vy=position->vy; + messagePtr->vz=position->vz; + +} +//for messages that just require a player id +void AddNetMsg_PlayerID(DPID playerID,unsigned char message) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_PLAYERID *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_PLAYERID); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_PLAYERID *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = message; + + /* Fill in message. */ + messagePtr->playerID=playerID; + +} + +void AddNetMsg_LastManStanding_RestartTimer(char time) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_LMS_RESTARTTIMER *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_LMS_RESTARTTIMER); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_LMS_RESTARTTIMER *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_LastManStanding_RestartCountDown; + + /* Fill in message. */ + messagePtr->timer=time; +} + +void AddNetMsg_LastManStanding_Restart(DPID alienID,int seed) +{ + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_LMS_RESTART *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_LMS_RESTART); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_LMS_RESTART *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = NetMT_LastManStanding_Restart; + + /* Fill in message. */ + messagePtr->playerID=alienID; + messagePtr->seed=seed; + +} + + +void AddNetMsg_RespawnPickups(void) +{ + NETMESSAGEHEADER *headerPtr; + int headerSize = sizeof(NETMESSAGEHEADER); + + /* only send this if we are playing or on the end game screen*/ + if(netGameData.myGameState!=NGS_Playing && netGameData.myGameState!=NGS_EndGameScreen) return; + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_RespawnPickups; +} + +void AddNetMsg_SpotOtherSound(enum soundindex SoundIndex,VECTORCH *position,int explosion) { + + NETMESSAGEHEADER *headerPtr; + NETMESSAGE_SPOTOTHERSOUND *messagePtr; + int headerSize = sizeof(NETMESSAGEHEADER); + int messageSize = sizeof(NETMESSAGE_SPOTOTHERSOUND); + + /* check there's enough room in the send buffer */ + { + int numBytesReqd = headerSize + messageSize; + int numBytesLeft = NET_MESSAGEBUFFERSIZE - ((int)(endSendBuffer - &sendBuffer[0])); + if(numBytesReqd > numBytesLeft) + { + LOCALASSERT(1==0); + /* don't add it */ + return; + } + } + + /* set up pointers to header and message structures */ + headerPtr = (NETMESSAGEHEADER *)endSendBuffer; + endSendBuffer += headerSize; + messagePtr = (NETMESSAGE_SPOTOTHERSOUND *)endSendBuffer; + endSendBuffer += messageSize; + + /* fill out the header */ + headerPtr->type = (unsigned char)NetMT_SpotOtherSound; + + /* Fill in message. */ + messagePtr->SoundIndex=SoundIndex; + if (explosion) { + messagePtr->explosion=1; + } else { + messagePtr->explosion=0; + } + + messagePtr->vx=position->vx; + messagePtr->vy=position->vy; + messagePtr->vz=position->vz; + +} + + + +/*---------------------------------------------------------------------- + Functions for processing each message type, as retrieved from the read + message buffer... + ----------------------------------------------------------------------*/ +static void ProcessNetMsg_GameDescription(NETMESSAGE_GAMEDESCRIPTION *messagePtr) +{ + /* should only get this if we're not the host, and we're in start-up state */ + if(AvP.Network!=I_Peer) + { + //Vaguely possible that a host could receive a message that is only intended for peers + //if this computer has only just become the host. + LOCALASSERT(AvP.Network==I_Host); + return; + } + + //if(netGameData.myGameState!=NGS_Joining) return; + + /* fill out the game description player list with the new player id's */ + { + int i; + for(i=0;iplayers[i].playerId) + ||(netGameData.playerData[i].startFlag != messagePtr->players[i].startFlag) ) + playerChanged=1; + + if (netGameData.myGameState==NGS_Playing && playerChanged) + { + if (messagePtr->players[i].playerId==NULL) + { + Inform_PlayerHasLeft(netGameData.playerData[i].playerId); + } + else if (messagePtr->players[i].startFlag) + { + Inform_PlayerHasJoined(messagePtr->players[i].playerId); + } + else + { + Inform_PlayerHasConnected(messagePtr->players[i].playerId); + } + } + + if(netGameData.playerData[i].playerId != messagePtr->players[i].playerId) + { + if(messagePtr->players[i].playerId) + { + DWORD size=0; + char* data; + HRESULT hr; + //need to find out this player's name + //first find the size of buffer required + hr=IDirectPlayX_GetPlayerName(glpDP,messagePtr->players[i].playerId,0,&size); + if(hr==DP_OK || hr==DPERR_BUFFERTOOSMALL) + { + //allocate buffer to recive the name + data=AllocateMem(size); + *data=0; + hr=IDirectPlayX_GetPlayerName(glpDP,messagePtr->players[i].playerId,data,&size); + + if(hr==DP_OK) + { + strncpy(netGameData.playerData[i].name,((DPNAME*)data)->lpszShortNameA,NET_PLAYERNAMELENGTH-1); + netGameData.playerData[i].name[NET_PLAYERNAMELENGTH-1]='\0'; + + } + DeallocateMem(data); + } + + } + else + { + netGameData.playerData[i].name[0]='\0'; + } + } + + netGameData.playerData[i].playerId = messagePtr->players[i].playerId; + netGameData.playerData[i].characterType = (NETGAME_CHARACTERTYPE)messagePtr->players[i].characterType; + netGameData.playerData[i].characterSubType = (NETGAME_CHARACTERTYPE)messagePtr->players[i].characterSubType; + netGameData.playerData[i].startFlag = messagePtr->players[i].startFlag; + } + netGameData.gameType = (NETGAME_TYPE)messagePtr->gameType; + //level number got from the session description instead + //netGameData.levelNumber = messagePtr->levelNumber; + netGameData.scoreLimit = messagePtr->scoreLimit; + netGameData.timeLimit = messagePtr->timeLimit; + netGameData.invulnerableTime = messagePtr->invulnerableTime; + + for(i=0;i<3;i++) + { + netGameData.characterKillValues[i]=messagePtr->characterKillValues[i]; + netGameData.aiKillValues[i]=messagePtr->aiKillValues[i]; + } + netGameData.baseKillValue=messagePtr->baseKillValue; + netGameData.useDynamicScoring=messagePtr->useDynamicScoring; + netGameData.useCharacterKillValues=messagePtr->useCharacterKillValues; + + netGameData.sendDecals=messagePtr->sendDecals; + + netGameData.gameSpeed=messagePtr->gameSpeed; + + netGameData.disableFriendlyFire=messagePtr->disableFriendlyFire; + netGameData.fallingDamage=messagePtr->fallingDamage; + netGameData.pistolInfiniteAmmo=messagePtr->pistolInfiniteAmmo; + netGameData.specialistPistols=messagePtr->specialistPistols; + + if(netGameData.needGameDescription) + { + /*We were waiting for the game description , best make sure that our player id appears + int the player list*/ + if(PlayerIdInPlayerList(AVPDPNetID)!=NET_IDNOTINPLAYERLIST) + { + /*we now have the game description, so we can stop waiting if we were + trying to join*/ + netGameData.needGameDescription=0; + /* + make sure our time scale is set correctly + (Only set it the once , so that it can be overridden for debugging purposes) + */ + switch(netGameData.gameSpeed) + { + case NETGAMESPEED_70PERCENT : + TimeScale=(ONE_FIXED*70)/100; + break; + + case NETGAMESPEED_80PERCENT : + TimeScale=(ONE_FIXED*80)/100; + break; + + case NETGAMESPEED_90PERCENT : + TimeScale=(ONE_FIXED*90)/100; + break; + + case NETGAMESPEED_100PERCENT : + TimeScale=(ONE_FIXED*100)/100; + break; + + } + + } + } + + netGameData.allowSmartgun=messagePtr->allowSmartgun; + netGameData.allowFlamer=messagePtr->allowFlamer; + netGameData.allowSadar=messagePtr->allowSadar; + netGameData.allowGrenadeLauncher=messagePtr->allowGrenadeLauncher; + netGameData.allowMinigun=messagePtr->allowMinigun; + netGameData.allowDisc=messagePtr->allowDisc; + netGameData.allowPistol=messagePtr->allowPistol; + netGameData.allowPlasmaCaster=messagePtr->allowPlasmaCaster; + netGameData.allowSpeargun=messagePtr->allowSpeargun; + netGameData.allowMedicomp=messagePtr->allowMedicomp; + netGameData.allowSmartDisc=messagePtr->allowSmartDisc; + netGameData.allowPistols=messagePtr->allowPistols; + + netGameData.maxPredator=messagePtr->maxPredator; + netGameData.maxAlien=messagePtr->maxAlien; + netGameData.maxMarine=messagePtr->maxMarine; + + netGameData.maxMarineGeneral=messagePtr->maxMarineGeneral; + netGameData.maxMarinePulseRifle=messagePtr->maxMarinePulseRifle; + netGameData.maxMarineSmartgun=messagePtr->maxMarineSmartgun; + netGameData.maxMarineFlamer=messagePtr->maxMarineFlamer; + netGameData.maxMarineSadar=messagePtr->maxMarineSadar; + netGameData.maxMarineGrenade=messagePtr->maxMarineGrenade; + netGameData.maxMarineMinigun=messagePtr->maxMarineMinigun; + netGameData.maxMarineSmartDisc=messagePtr->maxMarineSmartDisc; + netGameData.maxMarinePistols=messagePtr->maxMarinePistols; + + netGameData.useSharedLives=messagePtr->useSharedLives; + netGameData.maxLives=messagePtr->maxLives; + netGameData.numDeaths[0]=messagePtr->numDeaths[0]; + netGameData.numDeaths[1]=messagePtr->numDeaths[1]; + netGameData.numDeaths[2]=messagePtr->numDeaths[2]; + + + netGameData.timeForRespawn=messagePtr->timeForRespawn; + netGameData.pointsForRespawn=messagePtr->pointsForRespawn; + + { + //check to if the host's elapsed time is + //significantly different from our elapsed time value + int receivedTime=messagePtr->GameTimeElapsed; + int diff; + receivedTime<<=16; + + diff=netGameData.GameTimeElapsed-receivedTime; + + if(diff<-ONE_FIXED || diff>ONE_FIXED || netGameData.myGameState==NGS_EndGameScreen) + { + //best take the host's value + netGameData.GameTimeElapsed=receivedTime; + } + + } + + + } + + if(messagePtr->endGame) + { + if(netGameData.myGameState==NGS_Playing) + { + //we must have missed the end game message + netGameData.myGameState=NGS_EndGameScreen; + } + } + else + { + if(netGameData.myGameState==NGS_EndGameScreen) + { + //must have missed message to restart game + //therefore probably better restart now + RestartNetworkGame(0); + + } + } +} + +static void ProcessNetMsg_PlayerDescription(NETMESSAGE_PLAYERDESCRIPTION *messagePtr, DPID senderId) +{ + /* only act on this if we're the host and in start-up */ + if(AvP.Network!=I_Host) return; + + /* find the player and fill out their details from the message */ + { + int id = PlayerIdInPlayerList(senderId); + if(id==NET_IDNOTINPLAYERLIST) + { + /* player does not seem to be in the player list, so ignore it */ + return; + } + netGameData.playerData[id].characterType = (NETGAME_CHARACTERTYPE)messagePtr->characterType; + netGameData.playerData[id].characterSubType = (NETGAME_SPECIALISTCHARACTERTYPE)messagePtr->characterSubType; + + if (netGameData.myGameState==NGS_Playing) + { + if(messagePtr->startFlag && (netGameData.playerData[id].startFlag != messagePtr->startFlag) ) + Inform_PlayerHasJoined(netGameData.playerData[id].playerId); + } + netGameData.playerData[id].startFlag = messagePtr->startFlag; + + } +} + +static void ProcessNetMsg_StartGame(void) +{ + /* only act on this if we're a peer and in start-up */ + return; + if(AvP.Network!=I_Peer) return; + if(netGameData.myGameState!=NGS_Joining) return; + + /* switch our game state... if we are in the player list, switch to start, otherwise + switch to error */ + if(PlayerIdInPlayerList(AVPDPNetID)!=NET_IDNOTINPLAYERLIST) + netGameData.myGameState=NGS_Playing; + else + { + TransmitPlayerLeavingNetMsg(); + netGameData.myGameState=NGS_Error_HostLost; + AvP.MainLoopRunning = 0; + } +} + +static void ProcessNetMsg_PlayerState(NETMESSAGE_PLAYERSTATE *messagePtr, DPID senderId) +{ + VECTORCH position; + int playerIndex; + STRATEGYBLOCK *sbPtr; +#if 0 + /* state check: if we're in startup and we've received this message from the host, we + should go into an error state: */ + if((netGameData.myGameState==NGS_Joining)&&(messagePtr->IAmHost)) + { + TransmitPlayerLeavingNetMsg(); + netGameData.myGameState=NGS_Error_HostLost; + AvP.MainLoopRunning = 0; + } +#endif + + + position.vx = messagePtr->xPos; + position.vy = messagePtr->yPos; + position.vz = messagePtr->zPos; + { + //recored the players position , even if we aren't currntly playing + int playerIndex=PlayerIdInPlayerList(senderId); + if(playerIndex!=NET_IDNOTINPLAYERLIST) + { + netGameData.playerData[playerIndex].lastKnownPosition=position; + } + } + + /* if we're not playing, ignore it */ + if(netGameData.myGameState!=NGS_Playing) return; + + playerIndex = PlayerIdInPlayerList(senderId); + + /* KJL 14:47:22 06/04/98 - we don't seem to know about this person yet... ignore them */ + if (playerIndex==NET_IDNOTINPLAYERLIST) return; + + sbPtr = FindGhost(senderId, GHOST_PLAYEROBJECTID); + + //record whether the player is in the land of the living + netGameData.playerData[playerIndex].playerAlive=messagePtr->IAmAlive; + netGameData.playerData[playerIndex].playerHasLives=messagePtr->IHaveLifeLeft; + + //check the player type + //the value in the netgamedata should be set to next character type + netGameData.playerData[playerIndex].characterType=messagePtr->nextCharacterType; + netGameData.playerData[playerIndex].characterSubType=messagePtr->characterSubType; + if(sbPtr) + { + NETGHOSTDATABLOCK *ghostData; + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + GLOBALASSERT(ghostData); + + //here we need to use the current character type + switch(messagePtr->characterType) + { + case NGCT_Marine : + if(ghostData->type!=I_BehaviourMarinePlayer) + { + sbPtr->SBflags.please_destroy_me=1; + return; + } + break; + case NGCT_Predator : + if(ghostData->type!=I_BehaviourPredatorPlayer) + { + sbPtr->SBflags.please_destroy_me=1; + return; + } + break; + case NGCT_Alien : + if(ghostData->type!=I_BehaviourAlienPlayer) + { + sbPtr->SBflags.please_destroy_me=1; + return; + } + break; + } + + } + + if(!MultiplayerObservedPlayer) + { + if(sbPtr && sbPtr->SBdptr) + { + //make sure the model is visivle + sbPtr->SBdptr->ObFlags&=~ObFlag_NotVis; + } + } + + { + EULER orientation; + int sequence; + int weapon; + int firingPrimary; + int firingSecondary; + + orientation.EulerX = (messagePtr->xOrient<yOrient<zOrient<sequence; + weapon = (int)messagePtr->currentWeapon; + firingPrimary = (int)messagePtr->IAmFiringPrimary; + firingSecondary = (int)messagePtr->IAmFiringSecondary; + + //ReleasePrintDebuggingText("Primary %d Secondary %d\n",firingPrimary,firingSecondary); + + if(!sbPtr) + { + + /* If we are not a dead alien then we should have a ghost */ + // if(!(((!(messagePtr->IAmAlive)))&&(netGameData.playerData[playerIndex].characterType==NGCT_Alien))) + if (messagePtr->IAmAlive) + { + { + AVP_BEHAVIOUR_TYPE type; + if(messagePtr->characterType==NGCT_Marine) type = I_BehaviourMarinePlayer; + else if(messagePtr->characterType==NGCT_Alien) type = I_BehaviourAlienPlayer; + else type = I_BehaviourPredatorPlayer; + sbPtr = CreateNetGhost(senderId,GHOST_PLAYEROBJECTID,&position,&orientation,type,IOT_Non,0); + if(sbPtr) + { + HandleWeaponElevation(sbPtr,(int)messagePtr->Elevation,weapon); + //don't draw muzzle flash if observing from this player + if(MultiplayerObservedPlayer!=senderId) { + HandleGhostGunFlashEffect(sbPtr, messagePtr->IHaveAMuzzleFlash); + } else { + HandleGhostGunFlashEffect(sbPtr, 0); + } + HandlePlayerGhostWeaponSound(sbPtr,weapon,firingPrimary,firingSecondary); + MaintainGhostCloakingStatus(sbPtr,(int)messagePtr->CloakingEffectiveness); + MaintainGhostFireStatus(sbPtr,(int)messagePtr->IAmOnFire); + } + } + + } + } + else + { + + if(!(((!(messagePtr->IAmAlive)))&&(netGameData.playerData[playerIndex].characterType==NGCT_Alien))) + { + /* We are not a dead alien */ + HandleWeaponElevation(sbPtr,(int)messagePtr->Elevation,weapon); + UpdateGhost(sbPtr,&position,&orientation,sequence,messagePtr->Special); + //don't draw muzzle flash if observing from this player + if(MultiplayerObservedPlayer!=senderId) { + HandleGhostGunFlashEffect(sbPtr, messagePtr->IHaveAMuzzleFlash); + } else { + HandleGhostGunFlashEffect(sbPtr, 0); + } + HandlePlayerGhostWeaponSound(sbPtr,weapon,firingPrimary,firingSecondary); + MaintainGhostCloakingStatus(sbPtr,(int)messagePtr->CloakingEffectiveness); + MaintainGhostFireStatus(sbPtr,(int)messagePtr->IAmOnFire); + /* Now, more disc. */ + + if (messagePtr->IHaveADisk) { + + NETGHOSTDATABLOCK *ghostData; + SECTION_DATA *disc; + /* Find the thrower's ghost, and add his disc... */ + + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + GLOBALASSERT(ghostData); + GLOBALASSERT(ghostData->type==I_BehaviourPredatorPlayer); + disc=GetThisSectionData(ghostData->HModelController.section_data,"disk"); + if (disc) { + disc->flags&=~section_data_notreal; + } + } + } + else + { + /* We are a dead alien with a ghost */ + RemoveGhost(sbPtr); + return; + } + } + + if(sbPtr && messagePtr->IAmAlive) + { + NETGHOSTDATABLOCK *ghostData; + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + + ghostData->invulnerable=messagePtr->IAmInvulnerable; + + #if EXTRAPOLATION_TEST + { + VECTORCH velocity,diff; + int playerTimer=netGameData.playerData[playerIndex].timer; + + velocity.vx=messagePtr->velocity_x*100; + velocity.vy=messagePtr->velocity_y*100; + velocity.vz=messagePtr->velocity_z*100; + + diff=ghostData->velocity; + SubVector(&velocity,&diff); + + if(Approximate3dMagnitude(&diff)>1000) + { + //change in velocity , so reset extrapolation timer + ghostData->extrapTimer=-ONE_FIXED; + } + + ghostData->velocity=velocity; + ghostData->extrapTimerLast=0; + if(playerTimer>=ghostData->lastTimeRead) + { + ghostData->extrapTimer-=(playerTimer-ghostData->lastTimeRead); + } + else + { + ghostData->extrapTimer=-ONE_FIXED; + } + ghostData->lastTimeRead=playerTimer; + + } + + + if(ghostData->type==I_BehaviourAlienPlayer) + { + sbPtr->DynPtr->UseStandardGravity=messagePtr->standard_gravity; + if(!sbPtr->DynPtr->UseStandardGravity) + { + if(sbPtr->DynPtr->GravityDirection.vy==ONE_FIXED) + { + MATRIXCH mat; + //alien is crawling , so we need to get an appropriate gravity direction + CreateEulerMatrix(&orientation,&mat); + sbPtr->DynPtr->GravityDirection.vx=mat.mat12; + sbPtr->DynPtr->GravityDirection.vy=mat.mat22; + sbPtr->DynPtr->GravityDirection.vz=mat.mat32; + } + + sbPtr->DynPtr->LinImpulse.vx=0; + sbPtr->DynPtr->LinImpulse.vy=0; + sbPtr->DynPtr->LinImpulse.vz=0; + + sbPtr->DynPtr->ToppleForce=TOPPLE_FORCE_ALIEN; + } + } + #endif + + + if(messagePtr->scream!=31) + { + //this character is screaming + switch(messagePtr->characterType) + { + case NGCT_Marine : + PlayMarineScream(0,(SOUND_CATERGORY)messagePtr->scream,0,&ghostData->SoundHandle2,&position); + break; + + case NGCT_Alien : + PlayAlienSound(0,(ALIEN_SOUND_CATEGORY)messagePtr->scream,0,&ghostData->SoundHandle2,&position); + break; + + case NGCT_Predator : + if ((PREDATOR_SOUND_CATEGORY)messagePtr->scream==PSC_Medicomp_Special) { + Sound_Play(SID_PRED_NEWROAR,"de",&position,&ghostData->SoundHandle2); + } else { + PlayPredatorSound(0,(PREDATOR_SOUND_CATEGORY)messagePtr->scream,0,&ghostData->SoundHandle2,&position); + } + break; + } + } + + /* Landing noise. */ + if (messagePtr->landingNoise) { + switch(messagePtr->characterType) { + case NGCT_Marine : + Sound_Play(SID_MARINE_SMALLLANDING,"d",&position); + break; + case NGCT_Alien : + /* No sound for aliens. */ + break; + case NGCT_Predator : + Sound_Play(SID_PRED_SMALLLANDING,"d",&position); + break; + } + } + + //are we currently following this player's movements + if(MultiplayerObservedPlayer) + { + if(MultiplayerObservedPlayer==senderId) + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + playerStatusPtr->ViewPanX=messagePtr->Elevation; + Player->ObStrategyBlock->DynPtr->Position=position; + Player->ObStrategyBlock->DynPtr->PrevPosition=position; + + Player->ObStrategyBlock->DynPtr->OrientEuler = orientation; + CreateEulerMatrix(&Player->ObStrategyBlock->DynPtr->OrientEuler,&Player->ObStrategyBlock->DynPtr->OrientMat); + TransposeMatrixCH(&Player->ObStrategyBlock->DynPtr->OrientMat); + + if(messagePtr->IAmCrouched) + { + PlayerStatusPtr->ShapeState=PMph_Crouching; + } + else + { + PlayerStatusPtr->ShapeState=PMph_Standing; + } + + //don't draw the player we're observing + if(sbPtr && sbPtr->SBdptr) + { + sbPtr->SBdptr->ObFlags|=ObFlag_NotVis; + } + } + } + } + } +} +static void ProcessNetMsg_PlayerState_Minimal(NETMESSAGE_PLAYERSTATE_MINIMAL *messagePtr, DPID senderId,BOOL orientation) +{ + int playerIndex; + STRATEGYBLOCK *sbPtr; + + /* if we're not playing, ignore it */ + if(netGameData.myGameState!=NGS_Playing) return; + + playerIndex = PlayerIdInPlayerList(senderId); + + /* KJL 14:47:22 06/04/98 - we don't seem to know about this person yet... ignore them */ + if (playerIndex==NET_IDNOTINPLAYERLIST) return; + + sbPtr = FindGhost(senderId, GHOST_PLAYEROBJECTID); + + + //record whether the player is in the land of the living + netGameData.playerData[playerIndex].playerAlive=messagePtr->IAmAlive; + netGameData.playerData[playerIndex].playerHasLives=messagePtr->IHaveLifeLeft; + + if(!sbPtr) + { + //if we don't have a ghost for this player , wait for a full player state message + return; + } + + + if(!MultiplayerObservedPlayer) + { + if(sbPtr && sbPtr->SBdptr) + { + //make sure the model is visivle + sbPtr->SBdptr->ObFlags&=~ObFlag_NotVis; + } + } + + { + int firingPrimary; + int firingSecondary; + + firingPrimary = (int)messagePtr->IAmFiringPrimary; + firingSecondary = (int)messagePtr->IAmFiringSecondary; + + + + if(!(((!(messagePtr->IAmAlive)))&&(netGameData.playerData[playerIndex].characterType==NGCT_Alien))) + { + NETGHOSTDATABLOCK *ghostData; + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + GLOBALASSERT(ghostData); + + if(orientation) + { + NETMESSAGE_PLAYERSTATE_MEDIUM* mediumMessage=(NETMESSAGE_PLAYERSTATE_MEDIUM*) messagePtr; + EULER orientation; + orientation.EulerX = (mediumMessage->xOrient<yOrient<zOrient<DynPtr->Position,&orientation,-1,messagePtr->Special); + + } + + /* We are not a dead alien */ + HandleWeaponElevation(sbPtr,(int)messagePtr->Elevation,ghostData->CurrentWeapon); + //don't draw muzzle flash if observing from this player + if(MultiplayerObservedPlayer!=senderId) + HandleGhostGunFlashEffect(sbPtr, messagePtr->IHaveAMuzzleFlash); + else + HandleGhostGunFlashEffect(sbPtr, 0); + MaintainGhostCloakingStatus(sbPtr,(int)messagePtr->CloakingEffectiveness<<8); + MaintainGhostFireStatus(sbPtr,(int)messagePtr->IAmOnFire); + /* Now, more disc. */ + + if (messagePtr->IHaveADisk) { + + SECTION_DATA *disc; + /* Find the thrower's ghost, and add his disc... */ + + GLOBALASSERT(ghostData->type==I_BehaviourPredatorPlayer); + disc=GetThisSectionData(ghostData->HModelController.section_data,"disk"); + if (disc) { + disc->flags&=~section_data_notreal; + } + } + } + else + { + /* We are a dead alien with a ghost */ + RemoveGhost(sbPtr); + return; + } + + + if(sbPtr && messagePtr->IAmAlive) + { + NETGHOSTDATABLOCK *ghostData; + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + + //are we currently following this player's movements + if(MultiplayerObservedPlayer) + { + if(MultiplayerObservedPlayer==senderId) + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + playerStatusPtr->ViewPanX=messagePtr->Elevation; + + //don't draw the player we're observing + if(sbPtr && sbPtr->SBdptr) + { + sbPtr->SBdptr->ObFlags|=ObFlag_NotVis; + } + } + } + } + } +} + +static void ProcessNetMsg_FrameTimer(unsigned short frame_time,DPID senderId) +{ + int senderPlayerIndex; + /* if we're not playing, ignore it */ + if(netGameData.myGameState!=NGS_Playing) return; + + senderPlayerIndex = PlayerIdInPlayerList(senderId); + if(senderPlayerIndex==NET_IDNOTINPLAYERLIST) return; + + netGameData.playerData[senderPlayerIndex].timer+=frame_time; + + +} + +static void ProcessNetMsg_PlayerKilled(NETMESSAGE_PLAYERKILLED *messagePtr, DPID senderId) +{ + STRATEGYBLOCK *sbPtr; + int senderPlayerIndex; + + /* if we're not playing, ignore it */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* if this player is not in the play list, messages are probably out of order, + so just ignore it... */ + senderPlayerIndex = PlayerIdInPlayerList(senderId); + if(senderPlayerIndex==NET_IDNOTINPLAYERLIST) return; + + /* find the ghost for this player */ + sbPtr = FindGhost(senderId, GHOST_PLAYEROBJECTID); + if(!sbPtr) + { + /* we don't have a ghost for this player, which is odd, and implies that messages + have got dis-ordered... best just ignore it then */ + return; + } + + /* we have a ghost for this player: remove it if it's an alien */ +// if(netGameData.playerData[senderPlayerIndex].characterType==NGCT_Alien) + //RemoveGhost(sbPtr); + KillGhost(sbPtr,messagePtr->objectId); + + Inform_PlayerHasDied(messagePtr->killerId, senderId,messagePtr->killerType,messagePtr->weaponIcon); + + /* now attempt to update the scores */ + if(AvP.Network==I_Host) + { + UpdateNetworkGameScores(senderId, messagePtr->killerId,messagePtr->myType,messagePtr->killerType); + } + + + + /* do some sound... */ + LOCALASSERT(sbPtr->DynPtr); + switch(netGameData.playerData[senderPlayerIndex].characterType) + { + case(NGCT_Alien): + { + PlayAlienSound(0,ASC_Scream_Dying,0,NULL,&(sbPtr->DynPtr->Position)); + break; + } + case(NGCT_Marine): + { + PlayMarineScream(0,SC_Death,0,NULL,&(sbPtr->DynPtr->Position)); + break; + } + case(NGCT_Predator): + { + PlayPredatorSound(0,PSC_Scream_Dying,0,NULL,&(sbPtr->DynPtr->Position)); + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } +} + +static void ProcessNetMsg_PlayerDeathAnim(NETMESSAGE_CORPSEDEATHANIM *messagePtr,DPID senderId) +{ + STRATEGYBLOCK *sbPtr; + /* if we're not playing, ignore it */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* find the ghost for this player */ + sbPtr = FindGhost(senderId, messagePtr->objectId); + if(!sbPtr) + { + /* we don't have a ghost for this player, which is odd, and implies that messages + have got dis-ordered... best just ignore it then */ + return; + } + + //set the death animation for this player + ApplyGhostCorpseDeathAnim(sbPtr,messagePtr->deathId); + +} + +static void ProcessNetMsg_AllGameScores(NETMESSAGE_ALLGAMESCORES *messagePtr) +{ + /* should only get this if we're not the host */ + if(AvP.Network!=I_Peer) + { + //Vaguely possible that a host could receive a message that is only intended for peers + //if this computer has only just become the host. + LOCALASSERT(AvP.Network==I_Host); + return; + } + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* fill in the game scores from the message */ + { + int i,j; + + for(i=0;iplayerFrags[i][j]; + } + netGameData.playerData[i].playerScore = messagePtr->playerScores[i]; + netGameData.playerData[i].playerScoreAgainst = messagePtr->playerScoresAgainst[i]; + + for(j=0;j<3;j++) + { + netGameData.playerData[i].aliensKilled[j]=messagePtr->aliensKilled[i][j]; + } + + netGameData.playerData[i].deathsFromAI = messagePtr->deathsFromAI[i]; + } + } + + netGameData.myGameState=NGS_EndGameScreen; +} + +static void ProcessNetMsg_PlayerScores(NETMESSAGE_PLAYERSCORES *messagePtr) +{ + int playerId; + /* should only get this if we're not the host */ + if(AvP.Network!=I_Peer) + { + //Vaguely possible that a host could receive a message that is only intended for peers + //if this computer has only just become the host. + LOCALASSERT(AvP.Network==I_Host); + return; + } + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* find the player... */ + playerId = (int)messagePtr->playerId; + + /* fill in the player's scores from the message */ + { + int i; + + for(i=0;iplayerFrags[i]; + } + netGameData.playerData[playerId].playerScore = messagePtr->playerScore; + netGameData.playerData[playerId].playerScoreAgainst = messagePtr->playerScoreAgainst; + + for(i=0;i<3;i++) + { + netGameData.playerData[playerId].aliensKilled[i]=messagePtr->aliensKilled[i]; + } + netGameData.playerData[playerId].deathsFromAI = messagePtr->deathsFromAI; + } +} + +static void ProcessNetMsg_ScoreChange(NETMESSAGE_SCORECHANGE *messagePtr) +{ + /* should only get this if we're not the host */ + if(AvP.Network!=I_Peer) + { + //Vaguely possible that a host could receive a message that is only intended for peers + //if this computer has only just become the host. + LOCALASSERT(AvP.Network==I_Host); + return; + } + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + if(messagePtr->killerIndex == NET_MAXPLAYERS) + { + //killed by ai + netGameData.playerData[messagePtr->victimIndex].deathsFromAI=messagePtr->fragCount; + } + else + { + netGameData.playerData[messagePtr->killerIndex].playerFrags[messagePtr->victimIndex]=messagePtr->fragCount; + netGameData.playerData[messagePtr->killerIndex].playerScore=messagePtr->killerScoreFor; + } + netGameData.playerData[messagePtr->victimIndex].playerScoreAgainst=messagePtr->victimScoreAgainst; +} + +static void ProcessNetMsg_SpeciesScores(NETMESSAGE_SPECIESSCORES *messagePtr) +{ + int i; + /* should only get this if we're not the host */ + if(AvP.Network!=I_Peer) + { + //Vaguely possible that a host could receive a message that is only intended for peers + //if this computer has only just become the host. + LOCALASSERT(AvP.Network==I_Host); + return; + } + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + for(i=0;i<3;i++) + { + netGameData.teamScores[i]=messagePtr->teamScores[i]; + } + +} + +static void ProcessNetMsg_LocalRicochet(NETMESSAGE_LOCALRICOCHET *messagePtr) +{ +} + +static void ProcessNetMsg_LocalObjectState(NETMESSAGE_LOBSTATE *messagePtr, DPID senderId) +{ + STRATEGYBLOCK *sbPtr; + int objectId; + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* get the object id from the message */ + objectId = (int)messagePtr->objectId; + + sbPtr = FindGhost(senderId, objectId); + if(!sbPtr) + { + /* we don't seem to have a ghost for this object, so create one */ + VECTORCH position; + EULER orientation; + AVP_BEHAVIOUR_TYPE type; + + position.vx = messagePtr->xPos; + orientation.EulerX = (messagePtr->xOrient<yPos; + orientation.EulerY = (messagePtr->yOrient<zPos; + orientation.EulerZ = (messagePtr->zOrient<type; + + if (type==I_BehaviourNetCorpse) { + /* This *should* never happen... */ + textprint("IGNORED A CREATE CORPSE COMMAND.\n"); + return; + } + + /* NB there is no sequence required for local objects, so just pass zero */ + sbPtr = CreateNetGhost(senderId,objectId,&position,&orientation,type,messagePtr->IOType,messagePtr->subtype); + if (type==I_BehaviourPredatorDisc_SeekTrack) { + + NETGHOSTDATABLOCK *ghostData; + STRATEGYBLOCK *sbPtr2; + SECTION_DATA *disc; + int playerIndex; + /* Find the thrower's ghost, and rip off his disc :-) */ + + playerIndex = PlayerIdInPlayerList(senderId); + if (playerIndex==NET_IDNOTINPLAYERLIST) { + return; + } + sbPtr2 = FindGhost(senderId, GHOST_PLAYEROBJECTID); + if (!sbPtr2) { + return; + } + /* Got 'em. */ + ghostData = (NETGHOSTDATABLOCK *)sbPtr2->SBdataptr; + GLOBALASSERT(ghostData); + disc=GetThisSectionData(ghostData->HModelController.section_data,"disk"); + if (!disc) { + return; + } + disc->flags|=section_data_notreal; + } + } + else + { + /* update the ghost... */ + VECTORCH position; + EULER orientation; + + position.vx = messagePtr->xPos; + orientation.EulerX = (messagePtr->xOrient<yPos; + orientation.EulerY = (messagePtr->yOrient<zPos; + orientation.EulerZ = (messagePtr->zOrient<SBdataptr; + + if(messagePtr->event_flag) + { + if (ghostData->type==I_BehaviourPredatorDisc_SeekTrack) + { + if (messagePtr->event_flag==1) + { + /* Convert! */ + Convert_DiscGhost_To_PickupGhost(sbPtr); + //return; + } + else if(messagePtr->event_flag==2) + { + //disc has bounced off a wall , so play appropriate sound + Sound_Play(SID_PREDATOR_DISK_HITTING_WALL,"dp",&position,((FastRandom()&511)-255)); + } + } + else if(ghostData->type==I_BehaviourFrisbee) + { + if(messagePtr->event_flag==2) + { + //disc has bounced off a wall , so play appropriate sound + Sound_Play(SID_ED_SKEETERDISC_HITWALL,"dp",&position,((FastRandom()&511)-255)); + } + } + else if(ghostData->type==I_BehaviourFlareGrenade) + { + //flare has hit wall , so start the flare sound + if(ghostData->SoundHandle==SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_BURNING_FLARE,"dle",&position,&ghostData->SoundHandle); + } + } + else if ((ghostData->type==I_BehaviourGrenade)||(ghostData->type==I_BehaviourClusterGrenade)) + { + /* Bounce sound. */ + Sound_Play(SID_GRENADE_BOUNCE,"dp",&position,((FastRandom()&511)-255)); + } + } + /* NB there is no sequence required for local objects, so just pass zero */ + UpdateGhost(sbPtr,&position,&orientation,0,0); + } + } +} + +static int GetSizeOfLocalObjectDamagedMessage(char *messagePtr) +{ + int size=sizeof(NETMESSAGE_LOBDAMAGED_HEADER); + NETMESSAGE_LOBDAMAGED_HEADER *messageHeader = (NETMESSAGE_LOBDAMAGED_HEADER*) messagePtr;(NETMESSAGE_LOBDAMAGED_HEADER*) messagePtr; + + if(messageHeader->damageProfile) size+=sizeof(NETMESSAGE_DAMAGE_PROFILE); + if(messageHeader->multiple) size+=sizeof(NETMESSAGE_DAMAGE_MULTIPLE); + if(messageHeader->sectionID) size+=sizeof(NETMESSAGE_DAMAGE_SECTION); + if(messageHeader->delta_seq) size+=sizeof(NETMESSAGE_DAMAGE_DELTA); + if(messageHeader->direction) size+=sizeof(NETMESSAGE_DAMAGE_DIRECTION); + + return size; +} + +static void ProcessNetMsg_LocalObjectDamaged(char *messagePtr, DPID senderId) +{ + NETMESSAGE_LOBDAMAGED_HEADER *messageHeader=0; + NETMESSAGE_DAMAGE_PROFILE *messageProfile=0; + NETMESSAGE_DAMAGE_MULTIPLE *messageMultiple=0; + NETMESSAGE_DAMAGE_SECTION *messageSection=0; + NETMESSAGE_DAMAGE_DELTA *messageDelta=0; + NETMESSAGE_DAMAGE_DIRECTION *messageDirection=0; + + if(netGameData.myGameState!=NGS_Playing) return; + + + messageHeader=(NETMESSAGE_LOBDAMAGED_HEADER*) messagePtr; + messagePtr+=sizeof(NETMESSAGE_LOBDAMAGED_HEADER); + + //find out which elements of the damage message have been sent + if(messageHeader->damageProfile) + { + messageProfile=(NETMESSAGE_DAMAGE_PROFILE*) messagePtr; + messagePtr+=sizeof(NETMESSAGE_DAMAGE_PROFILE); + } + if(messageHeader->multiple) + { + messageMultiple=(NETMESSAGE_DAMAGE_MULTIPLE*) messagePtr; + messagePtr+=sizeof(NETMESSAGE_DAMAGE_MULTIPLE); + } + if(messageHeader->sectionID) + { + messageSection=(NETMESSAGE_DAMAGE_SECTION*) messagePtr; + messagePtr+=sizeof(NETMESSAGE_DAMAGE_SECTION); + } + if(messageHeader->delta_seq) + { + messageDelta=(NETMESSAGE_DAMAGE_DELTA*) messagePtr; + messagePtr+=sizeof(NETMESSAGE_DAMAGE_DELTA); + } + if(messageHeader->direction) + { + messageDirection=(NETMESSAGE_DAMAGE_DIRECTION*) messagePtr; + messagePtr+=sizeof(NETMESSAGE_DAMAGE_DIRECTION); + } + + /* This message is for the player who owns the object, so first check + if the message is meant for us */ + if(messageHeader->playerId != AVPDPNetID) + { + //however we may need to play a delta sequence on the ghost + if(messageDelta) + { + if(messageDelta->Delta_Sequence>0 && messageDelta->Delta_Sub_Sequence>0) + { + STRATEGYBLOCK *sbPtr; + sbPtr=FindGhost(messageHeader->playerId,(int)messageHeader->objectId); + if(sbPtr) + { + PlayHitDeltaOnGhost(sbPtr,messageDelta->Delta_Sequence,messageDelta->Delta_Sub_Sequence); + } + } + } + return; + } + + /* next we have to find this object in our strategyblock list */ + { + int objectId; + STRATEGYBLOCK *sbPtr; + DAMAGE_PROFILE damage; + SECTION_DATA *section_data; + HMODELCONTROLLER *controller; + int multiple; + VECTORCH incoming; + VECTORCH direction; + VECTORCH* incoming_ptr=0; + + objectId = (int)messageHeader->objectId; + sbPtr = FindObjectFromNetIndex(objectId); + + + + + /* we set this global to remember the id of the player who sent this damage message, + so that if the player is killed, we know the id of the killer. this is a bit of + a nasty hack, but means that we don't have to make any changes to the core damage functions */ + LOCALASSERT(myNetworkKillerId==NULL || myNetworkKillerId ==AVPDPNetID); + /* + Don't bother setting the killer id for molotov damage. This is because the only source of this damage + is explosions from flamethrowers. This damage will always come from the net host , and we don't want to credit the + host for all kills caused by this damage. + + Similarly all things that cause falling damage should count as suicide (in particular platform lifts) + */ + if(messageHeader->ammo_id!=AMMO_MOLOTOV && messageHeader->ammo_id!=AMMO_FALLING_POSTMAX) + { + myNetworkKillerId = senderId; + } + /* check if we have found an sb: if not the object has probably been + destroyed already, so just ignore it */ + if(sbPtr) + { + //fill out damage profile + damage.Id=messageHeader->ammo_id; + if(messageProfile) + { + damage.Impact = messageProfile->Impact; + damage.Cutting = messageProfile->Cutting; + damage.Penetrative = messageProfile->Penetrative; + damage.Fire = messageProfile->Fire; + damage.Electrical = messageProfile->Electrical; + damage.Acid = messageProfile->Acid; + + damage.ExplosivePower=messageProfile->ExplosivePower; + damage.Slicing=messageProfile->Slicing; + damage.ProduceBlood=messageProfile->ProduceBlood; + damage.ForceBoom=messageProfile->ForceBoom; + + damage.BlowUpSections=messageProfile->BlowUpSections; + damage.Special=messageProfile->Special; + damage.MakeExitWounds=messageProfile->MakeExitWounds; + } + else + { + if(damage.Id==AMMO_FLECHETTE_POSTMAX) + { + extern DAMAGE_PROFILE FlechetteDamage; + damage=FlechetteDamage; + } + else + { + GLOBALASSERT(damage.Id>AMMO_NONE && damage.Idmultiple; + } + else + { + multiple = ONE_FIXED; + } + + section_data=NULL; + controller=NULL; + + //get the direction vector if there is one + if(sbPtr->DynPtr && messageDirection) + { + if(messageDirection->direction_x || + messageDirection->direction_y || + messageDirection->direction_z) + { + MATRIXCH mat=sbPtr->DynPtr->OrientMat; + TransposeMatrixCH(&mat); + + //extract the direction vector + incoming.vx=messageDirection->direction_x; + incoming.vy=messageDirection->direction_y; + incoming.vz=messageDirection->direction_z; + //normalise it + Normalise(&incoming); + direction=incoming; + + //and rotate it from world space to the object's local space + RotateVector(&incoming,&mat); + + //set the incoming pointer + incoming_ptr=&incoming; + + } + + } + /*Record the id of the hit body part in a global variable. + This way , if this blow kill the player , we know which body part has been hit*/ + if(messageSection) + { + MyHitBodyPartId=messageSection->SectionID; + } + else + { + MyHitBodyPartId=-1; + } + + if (messageSection && messageSection->SectionID!=-1) { + /* Hmm. */ + if (sbPtr->I_SBtype==I_BehaviourAlien) { + /* Only allowed for aliens, right now. */ + ALIEN_STATUS_BLOCK *alienStatusPtr=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr); + + GLOBALASSERT(alienStatusPtr); + + controller=&alienStatusPtr->HModelController; + section_data=GetThisSectionData_FromID(alienStatusPtr->HModelController.section_data, + (int)messageSection->SectionID); + } + else if (sbPtr->I_SBtype==I_BehaviourNetCorpse) + { + NETCORPSEDATABLOCK *corpseData = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr; + + GLOBALASSERT(corpseData); + + controller=&corpseData->HModelController; + section_data=GetThisSectionData_FromID(corpseData->HModelController.section_data, + (int)messageSection->SectionID); + } + } + + if (section_data) + { + DISPLAYBLOCK *fragged_section=0; + fragged_section=CauseDamageToHModel(controller,sbPtr,(&damage), + multiple,section_data,incoming_ptr,NULL,0); + + if(fragged_section && damage.Id==AMMO_PRED_RIFLE && incoming_ptr) + { + //a speargun has fragged off a body part , so we need to create a spear + CreateSpearPossiblyWithFragment(fragged_section,&fragged_section->ObWorld,&direction); + } + + } + else + { + CauseDamageToObject(sbPtr, (&damage), multiple,incoming_ptr); + } + } + myNetworkKillerId = AVPDPNetID; + MyHitBodyPartId=-1; + } + + + +} + + +static void ProcessNetMsg_LocalObjectDestroyed_Request(NETMESSAGE_LOBDESTROYED_REQUEST *messagePtr, DPID senderId) +{ + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* This message is for the player who owns the object, so first check + if the message is meant for us */ + if(messagePtr->playerId != AVPDPNetID) return; + + /* next we have to find this object in our strategyblock list */ + { + int objectId; + STRATEGYBLOCK *sbPtr; + + objectId = (int)messagePtr->objectId; + sbPtr = FindObjectFromNetIndex(objectId); + + /* check if we have found an sb: if not the object has probably been + destroyed already, so just ignore it */ + + if(sbPtr) { + + /* Er... deal with it, okay? */ + if (sbPtr->I_SBtype==I_BehaviourInanimateObject) { + RemovePickedUpObject(sbPtr); + } else { + GLOBALASSERT(0); + } + + } + + } +} + +static void ProcessNetMsg_LocalObjectDestroyed(NETMESSAGE_LOBDESTROYED *messagePtr, DPID senderId) +{ + STRATEGYBLOCK *sbPtr; + int objectId; + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* this message is a cue to destroy a ghost... except for the player which has + a seperate 'playerkilled' message... */ + + /* start by finding the ghost for this object */ + objectId = (int)messagePtr->objectId; + sbPtr = FindGhost(senderId, objectId); + if(!sbPtr) + { + /* if we haven't got a ghost for this object things have gone wrong: eg, we haven't + yet received the object creation message. Just ignore it then... */ + return; + } + RemoveGhost(sbPtr); +} + + +static int GetSizeOfInanimateDamagedMessage(char *messagePtr) +{ + int size=sizeof(NETMESSAGE_INANIMATEDAMAGED_HEADER); + NETMESSAGE_INANIMATEDAMAGED_HEADER *messageHeader =(NETMESSAGE_INANIMATEDAMAGED_HEADER*) messagePtr; + + if(messageHeader->damageProfile) size+=sizeof(NETMESSAGE_DAMAGE_PROFILE); + if(messageHeader->multiple) size+=sizeof(NETMESSAGE_DAMAGE_MULTIPLE); + + return size; +} + +static void ProcessNetMsg_InanimateObjectDamaged(char *messagePtr) +{ + NETMESSAGE_INANIMATEDAMAGED_HEADER *messageHeader=0; + NETMESSAGE_DAMAGE_PROFILE *messageProfile=0; + NETMESSAGE_DAMAGE_MULTIPLE *messageMultiple=0; + + STRATEGYBLOCK *sbPtr; + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* only process this if we're the host*/ + if(AvP.Network!=I_Host) return; + + messageHeader=(NETMESSAGE_INANIMATEDAMAGED_HEADER*) messagePtr; + messagePtr+=sizeof(NETMESSAGE_INANIMATEDAMAGED_HEADER); + + //find out which elements of the damage message have been sent + if(messageHeader->damageProfile) + { + messageProfile=(NETMESSAGE_DAMAGE_PROFILE*) messagePtr; + messagePtr+=sizeof(NETMESSAGE_DAMAGE_PROFILE); + } + if(messageHeader->multiple) + { + messageMultiple=(NETMESSAGE_DAMAGE_MULTIPLE*) messagePtr; + messagePtr+=sizeof(NETMESSAGE_DAMAGE_MULTIPLE); + } + + /* start by finding the object */ + sbPtr = FindEnvironmentObjectFromName(messageHeader->name); + if(!sbPtr) + { + /* if we haven't got a ghost for this object things have gone wrong: eg, we haven't + yet received the object creation message. Just ignore it then... */ + return; + } + + /* ok: cause the damage */ + { + STRATEGYBLOCK *objectPtr = FindEnvironmentObjectFromName(messageHeader->name); + DAMAGE_PROFILE damage; + int multiple; + + if(!objectPtr) return; /* couldn't find it */ + + //fill out damage profile + damage.Id=messageHeader->ammo_id; + if(messageProfile) + { + damage.Impact = messageProfile->Impact; + damage.Cutting = messageProfile->Cutting; + damage.Penetrative = messageProfile->Penetrative; + damage.Fire = messageProfile->Fire; + damage.Electrical = messageProfile->Electrical; + damage.Acid = messageProfile->Acid; + + damage.ExplosivePower=messageProfile->ExplosivePower; + damage.Slicing=messageProfile->Slicing; + damage.ProduceBlood=messageProfile->ProduceBlood; + damage.ForceBoom=messageProfile->ForceBoom; + + damage.BlowUpSections=messageProfile->BlowUpSections; + damage.Special=messageProfile->Special; + damage.MakeExitWounds=messageProfile->MakeExitWounds; + } + else + { + GLOBALASSERT(damage.Id>AMMO_NONE && damage.Idmultiple; + } + else + { + multiple = ONE_FIXED; + } + + CauseDamageToObject(sbPtr, (&damage), multiple,NULL); + } +} + +static void ProcessNetMsg_InanimateObjectDestroyed(NETMESSAGE_INANIMATEDESTROYED *messagePtr) +{ + STRATEGYBLOCK *sbPtr; + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + /* only peers should get this */ + LOCALASSERT(AvP.Network!=I_Host); + + /* start by finding the object */ + sbPtr = FindEnvironmentObjectFromName(messagePtr->name); + if(!sbPtr) + { + /* if we haven't got a ghost for this object things have gone wrong: eg, we haven't + yet received the object creation message. Just ignore it then... */ + return; + } + + + /* ok: drop a nuke on it */ + { + extern int InanimateDamageFromNetHost; + + InanimateDamageFromNetHost = 1; + CauseDamageToObject(sbPtr, &certainDeath, ONE_FIXED,NULL); + InanimateDamageFromNetHost = 0; + } +} + +static void ProcessNetMsg_ObjectPickedUp(NETMESSAGE_OBJECTPICKEDUP *messagePtr) +{ + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + { + STRATEGYBLOCK *objectPtr = FindEnvironmentObjectFromName(messagePtr->name); + if(!objectPtr) return; /* couldn't find it */ + + LOCALASSERT(objectPtr->I_SBtype == I_BehaviourInanimateObject); + + /* Play an appropriate sound? */ + { + INANIMATEOBJECT_STATUSBLOCK* objStatPtr = objectPtr->SBdataptr; + + /* patrick, for e3- add a sound effect to explosions */ + if(objectPtr->DynPtr) + { + switch(objStatPtr->typeId) + { + case(IOT_Weapon): + /* Ignore predator case for now! */ + Sound_Play(SID_MARINE_PICKUP_WEAPON,"%d",&objectPtr->DynPtr->Position); + break; + case(IOT_Ammo): + Sound_Play(SID_MARINE_PICKUP_AMMO,"%d",&objectPtr->DynPtr->Position); + break; + case(IOT_Armour): + Sound_Play(SID_MARINE_PICKUP_ARMOUR,"%d",&objectPtr->DynPtr->Position); + break; + case(IOT_FieldCharge): + Sound_Play(SID_PREDATOR_PICKUP_FIELDCHARGE,"%d",&objectPtr->DynPtr->Position); + break; + default: + Sound_Play(SID_PICKUP,"%d",&objectPtr->DynPtr->Position); + break; + } + } + } + + KillInanimateObjectForRespawn(objectPtr); + } +} + +static void ProcessNetMsg_EndGame(void) +{ + /* should only get this if we're not the host */ + if(AvP.Network!=I_Peer) + { + //Vaguely possible that a host could receive a message that is only intended for peers + //if this computer has only just become the host. + LOCALASSERT(AvP.Network==I_Host); + } + + /* only do this if we're playing or in startup */ + /* check start flags on all players (including ourselves) */ + { + if(netGameData.playerData[PlayerIdInPlayerList(AVPDPNetID)].startFlag) + { + netGameData.myGameState = NGS_Playing; + } + } + if((netGameData.myGameState!=NGS_Playing)&&(netGameData.myGameState!=NGS_StartUp)&&(netGameData.myGameState!=NGS_Joining)) return; + + netGameData.myGameState = NGS_EndGame; + AvP.MainLoopRunning = 0; +} + +static void ProcessNetMsg_PlayerLeaving(DPID senderId) +{ + /* only do this if we're playing or in startup */ + if(netGameData.myGameState==NGS_Playing || netGameData.myGameState==NGS_EndGameScreen) + { + RemovePlayersGhosts(senderId); + } + + Inform_PlayerHasLeft(senderId); + + RemovePlayerFromGame(senderId); + +} + +static void ProcessNetMsg_LOSRequestBinarySwitch(NETMESSAGE_LOSREQUESTBINARYSWITCH *msgPtr) +{ + STRATEGYBLOCK *objectPtr; + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + objectPtr = FindEnvironmentObjectFromName(msgPtr->name); + if(!objectPtr) return; /* no object */ + if(objectPtr->I_SBtype!=I_BehaviourBinarySwitch && objectPtr->I_SBtype!=I_BehaviourLinkSwitch) return;/* we only do switches */ + + /* change the state of this object, then, via request state */ + RequestState(objectPtr,1,NULL); +} + +static void ProcessNetMsg_PlatformLiftState(NETMESSAGE_PLATFORMLIFTSTATE *msgPtr) +{ + STRATEGYBLOCK *objectPtr; + + /* only peers should get this */ + if(AvP.Network!=I_Peer) + { + //Vaguely possible that a host could receive a message that is only intended for peers + //if this computer has only just become the host. + LOCALASSERT(AvP.Network==I_Host); + return; + } + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + objectPtr = FindEnvironmentObjectFromName(msgPtr->name); + if(!objectPtr) return; /* no object */ + if(objectPtr->I_SBtype!=I_BehaviourPlatform) return;/* we only do binary switches */ + + /* update the lift state */ + { + extern void NetworkPeerChangePlatformLiftState(STRATEGYBLOCK* sbPtr,PLATFORMLIFT_STATES new_state); + NetworkPeerChangePlatformLiftState(objectPtr,(PLATFORMLIFT_STATES)(msgPtr->state)); + } +} + +static void ProcessNetMsg_RequestPlatformLiftActivate(NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE *msgPtr) +{ + STRATEGYBLOCK *objectPtr; + + /* only host should process this */ + if(AvP.Network!=I_Host) return; + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + objectPtr = FindEnvironmentObjectFromName(msgPtr->name); + if(!objectPtr) return; /* no object */ + if(objectPtr->I_SBtype!=I_BehaviourPlatform) return;/* we only do platform lifts */ + + /* update the lift state */ + { + PLATFORMLIFT_BEHAVIOUR_BLOCK *platLiftData = (PLATFORMLIFT_BEHAVIOUR_BLOCK *)objectPtr->SBdataptr; + LOCALASSERT(platLiftData); + if(platLiftData->state == PLBS_AtRest && platLiftData->Enabled) ActivatePlatformLift(objectPtr); + } +} + +static void ProcessNetMsg_PlayerAutoGunState(NETMESSAGE_AGUNSTATE *messagePtr, DPID senderId) +{ + STRATEGYBLOCK *sbPtr; + int objectId; + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* get the object id from the message */ + objectId = (int)messagePtr->objectId; + + sbPtr = FindGhost(senderId, objectId); + if(!sbPtr) + { + /* we don't seem to have a ghost for this autoGun, so create one */ + VECTORCH position; + EULER orientation; + + position.vx = messagePtr->xPos; + orientation.EulerX = (messagePtr->xOrient<yPos; + orientation.EulerY = (messagePtr->yOrient<zPos; + orientation.EulerZ = (messagePtr->zOrient<IAmFiring); + HandleGhostAutoGunSound(sbPtr, (int)messagePtr->IAmFiring); + } + + } + else + { + /* update the autogun ghost... */ + VECTORCH position; + EULER orientation; + + position.vx = messagePtr->xPos; + orientation.EulerX = (messagePtr->xOrient<yPos; + orientation.EulerY = (messagePtr->yOrient<zPos; + orientation.EulerZ = (messagePtr->zOrient<IAmFiring); + HandleGhostAutoGunSound(sbPtr,(int)messagePtr->IAmFiring); + } +} + + +static void ProcessNetMsg_MakeDecal(NETMESSAGE_MAKEDECAL *messagePtr) +{ + if(netGameData.myGameState!=NGS_Playing) return; + + AddDecal(messagePtr->DecalID,&(messagePtr->Direction),&(messagePtr->Position),messagePtr->ModuleIndex); +} + + +static char *ProcessNetMsg_ChatBroadcast(char *subMessagePtr, DPID senderId) +{ + + BOOL same_species_only; + /* get player index from dpid */ + char *ptr = subMessagePtr; + int stringLength=1; + + int playerIndex = PlayerIdInPlayerList(senderId); + + //get same_species flag + same_species_only=*ptr++; + + while(*ptr++ && stringLength<255) + { + stringLength++; + } + + if (stringLength==1 || stringLength>=255) + { + LOCALASSERT(0); + return ptr; + } + if(playerIndex==NET_IDNOTINPLAYERLIST) + { + return ptr; + } + + + if(netGameData.myGameState==NGS_Playing) + { + if(same_species_only) + { + //was a species say message , check to see if we are the correct species + if(netGameData.playerData[playerIndex].characterType != netGameData.myCharacterType ) return ptr; + } + + sprintf(OnScreenMessageBuffer,"%s: %s",netGameData.playerData[playerIndex].name,subMessagePtr+1); + NewOnScreenMessage(OnScreenMessageBuffer); + + /* KJL 99/2/5 - play 'incoming message' sound */ + switch(netGameData.playerData[playerIndex].characterType) + { + case NGCT_Marine: + { + Sound_Play(SID_CONSOLE_MARINEMESSAGE,NULL); + break; + } + case NGCT_Predator: + { + Sound_Play(SID_CONSOLE_PREDATORMESSAGE,NULL); + break; + } + case NGCT_Alien: + { + Sound_Play(SID_CONSOLE_ALIENMESSAGE,NULL); + break; + } + default: + break; + } + } + return ptr; + +} + +static void ProcessNetMsg_MakeExplosion(NETMESSAGE_MAKEEXPLOSION *messagePtr) +{ + if(netGameData.myGameState!=NGS_Playing) return; + MakeVolumetricExplosionAt(&(messagePtr->Position),messagePtr->ExplosionID); +} + +static void ProcessNetMsg_MakeFlechetteExplosion(NETMESSAGE_MAKEFLECHETTEEXPLOSION *messagePtr) +{ + extern void MakeFlechetteExplosionAt(VECTORCH *positionPtr,int seed); + if(netGameData.myGameState!=NGS_Playing) return; + MakeFlechetteExplosionAt(&(messagePtr->Position),messagePtr->Seed); +} + +static void ProcessNetMsg_MakePlasmaExplosion(NETMESSAGE_MAKEPLASMAEXPLOSION *messagePtr) +{ + if(netGameData.myGameState!=NGS_Playing) return; + MakePlasmaExplosion(&(messagePtr->Position),&(messagePtr->FromPosition),messagePtr->ExplosionID); +} + +static void ProcessNetMsg_PredatorSights(NETMESSAGE_PREDATORSIGHTS *messagePtr, DPID senderId) +{ + extern THREE_LASER_DOT_DESC PredatorLaserSights[]; + int playerIndex = PlayerIdInPlayerList(senderId); + + if(netGameData.myGameState!=NGS_Playing) return; + + if(playerIndex==NET_IDNOTINPLAYERLIST) + { + return; + } + + { + int i=2; + + VECTORCH offset[3] = + { + {0,-50,0}, + {43,25,0}, + {-43,25,0}, + }; + MATRIXCH matrix; + VECTORCH centre; + EULER orientation; + + + centre.vx = messagePtr->xPos; + orientation.EulerX = (messagePtr->xOrient<yPos; + orientation.EulerY = (messagePtr->yOrient<zPos; + orientation.EulerZ = (messagePtr->zOrient<TargetID; + } + + +} + +static void ProcessNetMsg_FragmentalObjectsStatus(NETMESSAGE_FRAGMENTALOBJECTSSTATUS *messagePtr) +{ + int i; + int fragNumber=0; + int objectsToSkip=messagePtr->BatchNumber*(NUMBER_OF_FRAGMENTAL_OBJECTS<<3); + + if(netGameData.myGameState!=NGS_Playing) return; + LOCALASSERT(AvP.Network!=I_No_Network); + + for (i=0; iStatusBitfield[i]; + } + + for (i=0; iI_SBtype == I_BehaviourInanimateObject) + { + INANIMATEOBJECT_STATUSBLOCK* objectStatusPtr = sbPtr->SBdataptr; + LOCALASSERT(objectStatusPtr); + + if((objectStatusPtr->typeId == IOT_Static) && (!objectStatusPtr->Indestructable) && (!objectStatusPtr->lifespanTimer)) + { + if(objectsToSkip>0) + { + objectsToSkip--; + continue; + } + status = ReadFragmentStatus(fragNumber++); + + if (status) /* should exist */ + { + #if 0 + /* so if it doesn't exist, respawn it */ + if(objectStatusPtr->respawnTimer!=0) + { + RespawnInanimateObject(sbPtr); + objectStatusPtr->respawnTimer=0; + } + #endif + } + else /* shouldn't exist */ + { + if(objectStatusPtr->respawnTimer==0) + { + extern void KillFragmentalObjectForRespawn(STRATEGYBLOCK *sbPtr); + KillFragmentalObjectForRespawn(sbPtr); + } + } + } + } + else if(sbPtr->I_SBtype == I_BehaviourPlacedLight) + { + PLACED_LIGHT_BEHAV_BLOCK* pl_bhv = sbPtr->SBdataptr; + LOCALASSERT(pl_bhv); + + if(!pl_bhv->Indestructable) + { + if(objectsToSkip>0) + { + objectsToSkip--; + continue; + } + status = ReadFragmentStatus(fragNumber++); + + if (status) /* should exist */ + { + #if 0 + /* so if it doesn't exist, respawn it */ + if(pl_bhv->state==Light_State_Broken) + { + RespawnInanimateObject(sbPtr); + objectStatusPtr->respawnTimer=0; + } + #endif + } + else /* shouldn't exist */ + { + if(pl_bhv->state!=Light_State_Broken) + { + KillLightForRespawn(sbPtr); + } + } + } + + } + + if(fragNumber>=(NUMBER_OF_FRAGMENTAL_OBJECTS<<3))break; + + } +} + +static void ProcessNetMsg_StrategySynch(NETMESSAGE_STRATEGYSYNCH *messagePtr) +{ + int i; + int objectNumber=0; + int objectsToSkip=messagePtr->BatchNumber*(NUMBER_OF_STRATEGIES_TO_SYNCH); + + if(netGameData.myGameState!=NGS_Playing) return; + LOCALASSERT(AvP.Network!=I_No_Network); + + if(!netGameData.myStrategyCheckSum) netGameData.myStrategyCheckSum=GetStrategySynchObjectChecksum(); + if(messagePtr->strategyCheckSum!=netGameData.myStrategyCheckSum) + { + //strategies are obviously different from those on the host's machine + textprint("Strategy checksums don't match"); + return; + } + + for (i=0; i>2; i++) + { + StrategySynchArray[i] = messagePtr->StatusBitfield[i]; + } + + for (i=0; iI_SBtype == I_BehaviourBinarySwitch || + sbPtr->I_SBtype == I_BehaviourLinkSwitch || + sbPtr->I_SBtype == I_BehaviourTrackObject) + { + + if(objectsToSkip>0) + { + objectsToSkip--; + continue; + } + + switch(sbPtr->I_SBtype) + { + case I_BehaviourBinarySwitch : + BinarySwitchSetSynchData(sbPtr,ReadStrategySynch(objectNumber++)); + break; + case I_BehaviourLinkSwitch : + LinkSwitchSetSynchData(sbPtr,ReadStrategySynch(objectNumber++)); + break; + case I_BehaviourTrackObject : + TrackObjectSetSynchData(sbPtr,ReadStrategySynch(objectNumber++)); + break; + } + + } + + if(objectNumber>=(NUMBER_OF_STRATEGIES_TO_SYNCH))break; + + } +} + +static void ProcessNetMsg_LocalObjectOnFire(NETMESSAGE_LOBONFIRE *messagePtr, DPID senderId) +{ + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* This message is for the player who owns the object, so first check + if the message is meant for us */ + if(messagePtr->playerId != AVPDPNetID) return; + + /* next we have to find this object in our strategyblock list */ + { + int objectId; + STRATEGYBLOCK *sbPtr; + + objectId = (int)messagePtr->objectId; + sbPtr = FindObjectFromNetIndex(objectId); + + /* check if we have found an sb: if not the object has probably been + destroyed already, so just ignore it */ + if(sbPtr) + { + sbPtr->SBDamageBlock.IsOnFire=1; + if (sbPtr == Player->ObStrategyBlock) + { + myIgniterId=senderId; + PlayerStatusPtr->fireTimer=PLAYER_ON_FIRE_TIME; + } + else if(sbPtr->I_SBtype==I_BehaviourAlien) + { + //need to note who burnt this alien + ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)sbPtr->SBdataptr; + alienStatus->aliensIgniterId=senderId; + } + } + } +} + +static void ProcessNetMsg_AlienAIState(NETMESSAGE_ALIENAISTATE *messagePtr, DPID senderId) +{ + STRATEGYBLOCK *sbPtr; + int objectId; + VECTORCH position; + EULER orientation; + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* get the object id from the message */ + objectId = (int)messagePtr->Guid; + + sbPtr = FindGhost(senderId, objectId); + + position.vx = messagePtr->xPos; + orientation.EulerX = (messagePtr->xOrient<yPos; + orientation.EulerY = (messagePtr->yOrient<zPos; + orientation.EulerZ = (messagePtr->zOrient<AlienType); + } + else + { + /* update the ghost... */ + MaintainGhostFireStatus(sbPtr,(int)messagePtr->IAmOnFire); + /* NB don't need to update the object type */ + UpdateAlienAIGhost(sbPtr,&position,&orientation,messagePtr->sequence_type,messagePtr->sub_sequence,messagePtr->sequence_length<<8); + } + + #if EXTRAPOLATION_TEST + if(sbPtr) + { + NETGHOSTDATABLOCK *ghostData; + VECTORCH velocity; + int diff; + int playerTimer; + int playerIndex = PlayerIdInPlayerList(senderId); + if (playerIndex==NET_IDNOTINPLAYERLIST) return; + + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + GLOBALASSERT(ghostData); + + playerTimer=netGameData.playerData[playerIndex].timer; + + velocity.vx=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat31,messagePtr->speed); + velocity.vy=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat32,messagePtr->speed); + velocity.vz=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat33,messagePtr->speed); + + diff=Approximate3dMagnitude(&ghostData->velocity)-Approximate3dMagnitude(&velocity); + + if(diff>1500 || -diff>1500) + { + //change in velocity , so reset extrapolation timer + ghostData->extrapTimer=-ONE_FIXED; + } + + ghostData->velocity=velocity; + ghostData->extrapTimerLast=0; + if(playerTimer>=ghostData->lastTimeRead) + { + ghostData->extrapTimer-=(playerTimer-ghostData->lastTimeRead); + } + else + { + ghostData->extrapTimer=-ONE_FIXED; + } + ghostData->lastTimeRead=playerTimer; + + sbPtr->DynPtr->UseStandardGravity=messagePtr->standard_gravity; + if(!sbPtr->DynPtr->UseStandardGravity) + { + if(sbPtr->DynPtr->GravityDirection.vy==ONE_FIXED) + { + MATRIXCH mat; + //alien is crawling , so we need to get an appropriate gravity direction + CreateEulerMatrix(&orientation,&mat); + sbPtr->DynPtr->GravityDirection.vx=mat.mat12; + sbPtr->DynPtr->GravityDirection.vy=mat.mat22; + sbPtr->DynPtr->GravityDirection.vz=mat.mat32; + } + + sbPtr->DynPtr->LinImpulse.vx=0; + sbPtr->DynPtr->LinImpulse.vy=0; + sbPtr->DynPtr->LinImpulse.vz=0; + + sbPtr->DynPtr->ToppleForce=TOPPLE_FORCE_ALIEN; + } + + } + #endif + +} + +/* CDF 24/8/98 A better message. */ +static void ProcessNetMsg_AlienAISequenceChange(NETMESSAGE_ALIENSEQUENCECHANGE *messagePtr, DPID senderId) +{ + STRATEGYBLOCK *sbPtr; + int objectId; + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* get the object id from the message */ + objectId = (int)messagePtr->Guid; + + sbPtr = FindGhost(senderId, objectId); + if(!sbPtr) + { + /* Gordon Bennet. Return, then. */ + return; + } + else + { + int sequence_length,tweening_time; + /* update the ghost... */ + + if(messagePtr->sequence_length==-1) + sequence_length=-1; + else + sequence_length=messagePtr->sequence_length<<8; + + if(messagePtr->tweening_time==-1) + tweening_time=-1; + else + tweening_time=messagePtr->tweening_time<<8; + + UpdateAlienAIGhostAnimSequence(sbPtr,messagePtr->sequence_type,messagePtr->sub_sequence,sequence_length,tweening_time); + } +} + +static void ProcessNetMsg_AlienAIKilled(NETMESSAGE_ALIENAIKILLED *messagePtr, DPID senderId) +{ + STRATEGYBLOCK *sbPtr; + int objectId; + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + Inform_AiHasDied(messagePtr->killerId,messagePtr->AlienType,messagePtr->weaponIcon); + + { + int killerIndex=PlayerIdInPlayerList(messagePtr->killerId); + if(killerIndex!=NET_IDNOTINPLAYERLIST) + { + netGameData.playerData[killerIndex].aliensKilled[messagePtr->AlienType]=messagePtr->killCount; + } + } + + /* get the object id from the message */ + objectId = (int)messagePtr->Guid; + + sbPtr = FindGhost(senderId, objectId); + if(!sbPtr) + { + /* Gordon Bennet. Return, then. It's not that important. */ + return; + } + else + { + /* 'update' the ghost... */ + KillAlienAIGhost(sbPtr,messagePtr->death_code,messagePtr->death_time,messagePtr->GibbFactor); + } +} + +static void ProcessNetMsg_FarAlienPosition(NETMESSAGE_FARALIENPOSITION *messagePtr, DPID senderId) +{ + STRATEGYBLOCK* sbPtr; + EULER orientation={0,0,0}; + VECTORCH position; + AIMODULE* targetModule=0; + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + //make sure the target module index is in range + if(messagePtr->targetModuleIndex>=AIModuleArraySize) return; + targetModule = &AIModuleArray[messagePtr->targetModuleIndex]; + + if(messagePtr->indexIsModuleIndex) + { + FARENTRYPOINT *targetEntryPoint; + AIMODULE *startModule=0; + //The alien is located at an entry point , the second index is the source module index + //Make sure it is a valid module index + if(messagePtr->index>=AIModuleArraySize) return; + startModule = &AIModuleArray[messagePtr->index]; + + //find the appropriate entry point + targetEntryPoint = GetAIModuleEP(targetModule,startModule); + + if(!targetEntryPoint) return; //forget it then + + //found the alien's location (relative to module) + position=targetEntryPoint->position; + + } + else + { + //The alien is at one of the modules auxilary locations + int noOfAuxLocs = FALLP_AuxLocs[messagePtr->targetModuleIndex].numLocations; + VECTORCH *auxLocsList = FALLP_AuxLocs[messagePtr->targetModuleIndex].locationsList; + + //make sure we have a valid index + if(messagePtr->index>=noOfAuxLocs) return; + + //found the alien's location (relative to module) + position=auxLocsList[messagePtr->index]; + } + //convert the position into a world position + position.vx += targetModule->m_world.vx; + position.vy += targetModule->m_world.vy; + position.vz += targetModule->m_world.vz; + + + //find the alien + sbPtr = FindGhost(senderId, messagePtr->Guid); + + if(!sbPtr) + { + //need to create a new ghost then + sbPtr = CreateNetGhost(senderId,messagePtr->Guid,&position,&orientation,I_BehaviourAlien, IOT_Non,messagePtr->alienType); + } + + if(sbPtr) + { + NETGHOSTDATABLOCK *ghostData; + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + GLOBALASSERT(ghostData); + //make sure this is a ghost of an alien + if(ghostData->type!=I_BehaviourAlien) return; + + //update the position , and mark it as valid for far use only + ghostData->onlyValidFar=1; + + sbPtr->DynPtr->Position=position; + sbPtr->DynPtr->PrevPosition=position; + + sbPtr->DynPtr->LinVelocity.vx=0; + sbPtr->DynPtr->LinVelocity.vy=0; + sbPtr->DynPtr->LinVelocity.vz=0; + + sbPtr->DynPtr->LinImpulse.vx=0; + sbPtr->DynPtr->LinImpulse.vy=0; + sbPtr->DynPtr->LinImpulse.vz=0; + + //make sure the alien is far + if(sbPtr->SBdptr) MakeGhostFar(sbPtr); + + } +} + +static int GetSizeOfGhostHierarchyDamagedMessage(char *messagePtr) +{ + int size=sizeof(NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER); + NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER *messageHeader =(NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER*) messagePtr; + + if(messageHeader->damageProfile) size+=sizeof(NETMESSAGE_DAMAGE_PROFILE); + if(messageHeader->multiple) size+=sizeof(NETMESSAGE_DAMAGE_MULTIPLE); + if(messageHeader->sectionID) size+=sizeof(NETMESSAGE_DAMAGE_SECTION); + if(messageHeader->direction) size+=sizeof(NETMESSAGE_DAMAGE_DIRECTION); + + return size; +} + +static void ProcessNetMsg_GhostHierarchyDamaged(char *messagePtr, DPID senderId) +{ + NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER *messageHeader=0; + NETMESSAGE_DAMAGE_PROFILE *messageProfile=0; + NETMESSAGE_DAMAGE_MULTIPLE *messageMultiple=0; + NETMESSAGE_DAMAGE_SECTION *messageSection=0; + NETMESSAGE_DAMAGE_DIRECTION *messageDirection=0; + + STRATEGYBLOCK *sbPtr; + int objectId; + NETGHOSTDATABLOCK *ghostData; + VECTORCH direction; + VECTORCH incoming; + VECTORCH* incoming_ptr=0; + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + messageHeader=(NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER*) messagePtr; + messagePtr+=sizeof(NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER); + + //find out which elements of the damage message have been sent + if(messageHeader->damageProfile) + { + messageProfile=(NETMESSAGE_DAMAGE_PROFILE*) messagePtr; + messagePtr+=sizeof(NETMESSAGE_DAMAGE_PROFILE); + } + if(messageHeader->multiple) + { + messageMultiple=(NETMESSAGE_DAMAGE_MULTIPLE*) messagePtr; + messagePtr+=sizeof(NETMESSAGE_DAMAGE_MULTIPLE); + } + if(messageHeader->sectionID) + { + messageSection=(NETMESSAGE_DAMAGE_SECTION*) messagePtr; + messagePtr+=sizeof(NETMESSAGE_DAMAGE_SECTION); + } + if(messageHeader->direction) + { + messageDirection=(NETMESSAGE_DAMAGE_DIRECTION*) messagePtr; + messagePtr+=sizeof(NETMESSAGE_DAMAGE_DIRECTION); + } + + /* get the object id from the message */ + objectId = (int)messageHeader->Guid; + + sbPtr = FindGhost(senderId, objectId); + if(!sbPtr) + { + /* Gordon Bennet. Return, then. It's not that important. */ + return; + } + else + { + DAMAGE_PROFILE damage; + int multiple; + + /* damage the ghost... */ + SECTION_DATA *section_data=NULL; + HMODELCONTROLLER *controller=NULL; + + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + + //fill out damage profile + damage.Id=messageHeader->ammo_id; + if(messageProfile) + { + damage.Impact = messageProfile->Impact; + damage.Cutting = messageProfile->Cutting; + damage.Penetrative = messageProfile->Penetrative; + damage.Fire = messageProfile->Fire; + damage.Electrical = messageProfile->Electrical; + damage.Acid = messageProfile->Acid; + + damage.ExplosivePower=messageProfile->ExplosivePower; + damage.Slicing=messageProfile->Slicing; + damage.ProduceBlood=messageProfile->ProduceBlood; + damage.ForceBoom=messageProfile->ForceBoom; + + damage.BlowUpSections=messageProfile->BlowUpSections; + damage.Special=messageProfile->Special; + damage.MakeExitWounds=messageProfile->MakeExitWounds; + } + else + { + GLOBALASSERT(damage.Id>AMMO_NONE && damage.Idmultiple; + } + else + { + multiple = ONE_FIXED; + } + + if(sbPtr->DynPtr && messageDirection) + { + + + if(messageDirection->direction_x || + messageDirection->direction_y || + messageDirection->direction_z) + { + MATRIXCH mat=sbPtr->DynPtr->OrientMat; + TransposeMatrixCH(&mat); + + //extract the direction vector + incoming.vx=messageDirection->direction_x; + incoming.vy=messageDirection->direction_y; + incoming.vz=messageDirection->direction_z; + //normalise it + Normalise(&incoming); + direction=incoming; + + //and rotate it from world space to the object's local space + RotateVector(&incoming,&mat); + + //set the incoming pointer + incoming_ptr=&incoming; + + } + + } + + + if (messageSection && messageSection->SectionID!=-1) { + /* Hmm. */ + + controller=&ghostData->HModelController; + section_data=GetThisSectionData_FromID(ghostData->HModelController.section_data, + messageSection->SectionID); + } + + if (section_data) + { + DISPLAYBLOCK *fragged_section=0; + + fragged_section=CauseDamageToHModel(controller,sbPtr,(&damage), + multiple,section_data,incoming_ptr,NULL,1); + + if(fragged_section && damage.Id==AMMO_PRED_RIFLE && incoming_ptr) + { + //a speargun has fragged off a body part , so we need to create a spear + CreateSpearPossiblyWithFragment(fragged_section,&fragged_section->ObWorld,&direction); + } + } + } +} + + +static void ProcessNetMsg_Gibbing(NETMESSAGE_GIBBING *messagePtr,DPID senderId) +{ + STRATEGYBLOCK *sbPtr; + int objectId; + NETGHOSTDATABLOCK *ghostData; + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* get the object id from the message */ + objectId = (int)messagePtr->Guid; + + sbPtr = FindGhost(senderId, objectId); + if(!sbPtr) + { + /* Gordon Bennet. Return, then. It's not that important. */ + return; + } + else + { + SECTION_DATA *section_data=NULL; + HMODELCONTROLLER *controller=NULL; + + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + + //only interested in gibbing corpses + if(ghostData->type!=I_BehaviourNetCorpse) return; + + //use the random number seed + SetSeededFastRandom(messagePtr->seed); + //now do the gibbing + if (messagePtr->gibbFactor>0) + { + Extreme_Gibbing(sbPtr,ghostData->HModelController.section_data,messagePtr->gibbFactor); + } + else if (messagePtr->gibbFactor<0) + { + KillRandomSections(ghostData->HModelController.section_data,-(messagePtr->gibbFactor)); + } + + } +} + +static void ProcessNetMsg_SpotAlienSound(NETMESSAGE_SPOTALIENSOUND *messagePtr, DPID senderId) +{ + VECTORCH position; + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* Just play the thing. */ + + + + position.vx=messagePtr->vx; + position.vy=messagePtr->vy; + position.vz=messagePtr->vz; + + PlayAlienSound((int)messagePtr->alienType,(int)messagePtr->soundCategory,messagePtr->pitch,NULL,&position); +} + +static void ProcessNetMsg_CreateWeapon(NETMESSAGE_CREATEWEAPON * messagePtr) +{ + /* if we're not playing, ignore it */ + if(netGameData.myGameState!=NGS_Playing) return; + + //create the weapon + CreateMultiplayerWeaponPickup(&messagePtr->location,messagePtr->type,&messagePtr->name[0]); +} + +static void ProcessNetMsg_SpotOtherSound(NETMESSAGE_SPOTOTHERSOUND *messagePtr, DPID senderId) +{ + VECTORCH position; + + /* only do this if we're playing */ + if(netGameData.myGameState!=NGS_Playing) return; + + /* Just play the thing. */ + + position.vx=messagePtr->vx; + position.vy=messagePtr->vy; + position.vz=messagePtr->vz; + + PlayOtherSound(messagePtr->SoundIndex,&position,messagePtr->explosion); +} + +/*---------------------------------------------------------------------- + These support functions are used to examine the current game state + ----------------------------------------------------------------------*/ + +/* returns index if the given DPID is in the player list */ +int PlayerIdInPlayerList(DPID Id) +{ + int i; + /* check first, if we've been passed a null id */ + if(Id==NULL) return NET_IDNOTINPLAYERLIST; + + /* check player list */ + for(i=0;iObStrategyBlock); + } + + while(sbIndex < NumActiveStBlocks) + { + STRATEGYBLOCK *sbPtr = ActiveStBlockList[sbIndex++]; + /* need to be careful here: netIndexes maybe the same as pre-assigned names + for global objects, therefore we must check the type of the object */ + if((sbPtr->I_SBtype == I_BehaviourRocket)|| + (sbPtr->I_SBtype == I_BehaviourGrenade)|| + (sbPtr->I_SBtype == I_BehaviourPulseGrenade)|| + (sbPtr->I_SBtype == I_BehaviourFragmentationGrenade)|| + (sbPtr->I_SBtype == I_BehaviourFlareGrenade)|| + (sbPtr->I_SBtype == I_BehaviourPredatorEnergyBolt)|| + (sbPtr->I_SBtype == I_BehaviourFrisbeeEnergyBolt)|| + (sbPtr->I_SBtype == I_BehaviourPPPlasmaBolt)|| + (sbPtr->I_SBtype == I_BehaviourSpeargunBolt)|| + (sbPtr->I_SBtype == I_BehaviourClusterGrenade)|| + (sbPtr->I_SBtype == I_BehaviourNPCPredatorDisc)|| + (sbPtr->I_SBtype == I_BehaviourPredatorDisc_SeekTrack)|| + (sbPtr->I_SBtype == I_BehaviourAlienSpit)|| + (sbPtr->I_SBtype == I_BehaviourAutoGun)|| + (sbPtr->I_SBtype == I_BehaviourAlien)|| + (sbPtr->I_SBtype == I_BehaviourNetCorpse)|| + (sbPtr->I_SBtype == I_BehaviourInanimateObject)|| + (sbPtr->I_SBtype == I_BehaviourProximityGrenade)) + { + int *sbIdPtr = (int *)(&(sbPtr->SBname[4])); + if(*sbIdPtr == obIndex) return sbPtr; + } + } + return (STRATEGYBLOCK *)0; +} + +/* Finds the inanimate objects strategy block who's name is passed */ +/* NB must be careful finding obejcts from their name: local and global objects may end up +with the same name, so we must make sure we differentiate between them... */ +static STRATEGYBLOCK *FindEnvironmentObjectFromName(char *name) +{ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + int sbIndex = 0; + + while(sbIndex < NumActiveStBlocks) + { + STRATEGYBLOCK *sbPtr = ActiveStBlockList[sbIndex++]; + + if((sbPtr->I_SBtype==I_BehaviourInanimateObject)|| + (sbPtr->I_SBtype==I_BehaviourPlatform)|| + (sbPtr->I_SBtype==I_BehaviourPlacedLight)|| + (sbPtr->I_SBtype==I_BehaviourBinarySwitch)) + { + if(NAME_ISEQUAL((&(sbPtr->SBname[0])),(name))) return sbPtr; + } + } + return (STRATEGYBLOCK *)0; +} + + +/* asigns an object id to a strategyblock, such as a projectile */ +#if 0 +void AddNetGameObjectID(STRATEGYBLOCK *sbPtr) +{ + int *sbIdPtr = (int *)(&(sbPtr->SBname[0])); + + *sbIdPtr = netNextLocalObjectId++; +} +#endif + + +/* called by host only: updates the scores for a described kill, and sends a +game score update message */ + +static void UpdateNetworkGameScores(DPID playerKilledId, DPID killerId,NETGAME_CHARACTERTYPE playerKilledType,NETGAME_CHARACTERTYPE killerType) +{ + int playerKilledIndex; + int killerIndex; + int scoreForKill; + int i; + + LOCALASSERT(AvP.Network==I_Host); + if(netGameData.myGameState != NGS_Playing) return; + + + /* get the index of the player who has been killed. If they're not in + the player list, can't have been killed ! */ + playerKilledIndex = PlayerIdInPlayerList(playerKilledId); + if(playerKilledIndex==NET_IDNOTINPLAYERLIST) return; + + if(killerId==NULL || killerId == playerKilledId || killerType>=NGCT_AI_Alien) + { + //suicide + killerIndex=playerKilledIndex; + + //record player's death for purposes of adjusting difficulty. + //(assuming that optionis being used) + GeneratorBalance_NotePlayerDeath(); + + } + else + { + killerIndex = PlayerIdInPlayerList(killerId); + if(killerIndex==NET_IDNOTINPLAYERLIST) return; + } + + if(killerType>=NGCT_AI_Alien) + { + //update deaths from AI; + netGameData.playerData[playerKilledIndex].deathsFromAI++; + + } + else + { + //update frag count; + netGameData.playerData[killerIndex].playerFrags[playerKilledIndex]++; + } + + //update overall number of kills + netGameData.numDeaths[playerKilledType]++; + + + if(netGameData.gameType==NGT_LastManStanding) + { + if(killerType==NGCT_Alien || killerIndex==playerKilledIndex) + { + if(playerKilledType!=NGCT_Alien) + { + int marineCount=0; + int marineIndex; + + //give a point to the alien for killing a marine + if(killerType==NGCT_Alien) + { + netGameData.playerData[killerIndex].playerScore+=1; + } + + //also give a point to every surviving marine + for(i=0;i0) + { + //note score against person being killed + netGameData.playerData[playerKilledIndex].playerScoreAgainst+=scoreForKill; + } + else + { + netGameData.playerData[killerIndex].playerScoreAgainst+=scoreForKill; + } + + if(netGameData.gameType==NGT_CoopDeathmatch) + { + //need to adjust the species scores as well + netGameData.teamScores[killerType]+=scoreForKill; + AddNetMsg_SpeciesScores(); + } + } + + if(killerType>=NGCT_AI_Alien) + { + //killed by alien ai + AddNetMsg_ScoreChange(NET_MAXPLAYERS,playerKilledIndex); + } + else + { + AddNetMsg_ScoreChange(killerIndex,playerKilledIndex); + } + + //AddNetMsg_PlayerScores(killerIndex); + + if(netGameData.gameType==NGT_PredatorTag || netGameData.gameType==NGT_AlienTag) + { + NETGAME_CHARACTERTYPE tagSpecies = NGCT_Predator; + if(netGameData.gameType==NGT_AlienTag) tagSpecies = NGCT_Alien; + + + //was the predator killed? + if(playerKilledType==tagSpecies) + { + if(CountPlayersOfType(tagSpecies)==1) + { + //select new predator + //if it wasn't suicide , choose killer + if(playerKilledIndex!=killerIndex) + { + AddNetMsg_PlayerID(killerId,NetMT_PredatorTag_NewPredator); + Handle_SpeciesTag_NewPersonIt(killerId); + } + else + { + //choose next player + for(i=playerKilledIndex+1;;i++) + { + i=i%NET_MAXPLAYERS; + if(netGameData.playerData[i].playerId) + { + /* + don't choose player if he was the previous predator + (In fact this should only happen if someone is silly enough to player single player + predator tag). + */ + if(i!=playerKilledIndex) + { + AddNetMsg_PlayerID(netGameData.playerData[i].playerId,NetMT_PredatorTag_NewPredator); + Handle_SpeciesTag_NewPersonIt(netGameData.playerData[i].playerId); + } + break; + } + } + + } + } + } + } +} + + +/* This function is a hook for the playerdead() function in player.c: +if we're the host, we need to update the scores seperately in the event that we have +been killed during a netgame. For other players, scores are updated (by the host) in +response to a 'playerKilled' message. However, the host will not receive it's own +playerKilled message, and must therefore do it seperately... */ +void DoNetScoresForHostDeath(NETGAME_CHARACTERTYPE myType,NETGAME_CHARACTERTYPE killerType) +{ + LOCALASSERT(AvP.Network==I_Host); + if(myNetworkKillerId) + { + int killer_index=PlayerIdInPlayerList(myNetworkKillerId); + if(killer_index==NET_IDNOTINPLAYERLIST) + { + //the player doing the damage has either left the game , or never existed. + //call it suicide then. + myNetworkKillerId=AVPDPNetID; + } + + } + UpdateNetworkGameScores(AVPDPNetID,myNetworkKillerId,myType,killerType); +} + +int AddUpPlayerFrags(int playerId) +{ + int score = 0; + int j; + LOCALASSERT(netGameData.playerData[playerId].playerId!=NULL); + for(j=0;j<(NET_MAXPLAYERS);j++) score+=netGameData.playerData[playerId].playerFrags[j]; + return score; +} + +static void ConvertNetNameToUpperCase(char *strPtr) +{ + int count = 0; + while((count<(NET_PLAYERNAMELENGTH-1))&&(strPtr[count]!='\0')) + { + strPtr[count] = toupper(strPtr[count]); + count++; + } + +} + + +/* Patrick 11/7/97 ---------------------------------------------- +Functions for determining our sequence for player update messages +-----------------------------------------------------------------*/ + +static MARINE_SEQUENCE GetMyMarineSequence(void) +{ + int playerIsMoving = 0; + int playerIsFiring = 0; + int playerIsCrouching = 0; + int playerIsAlive = 0; + int playerIsJumping = 0; + int usingCloseAttackWeapon; + extern int StaffAttack; + + /* sort out what state we're in */ + if(PlayerStatusPtr->IsAlive) playerIsAlive = 1; + else playerIsAlive = 0; + + if (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_Backward) { + playerIsMoving=-1; + } else if((PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_Forward)|| + (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepLeft)|| + (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepRight)) { + playerIsMoving = 1; + } else { + playerIsMoving = 0; + } + + if ( (Player->ObStrategyBlock->DynPtr->Position.vx==Player->ObStrategyBlock->DynPtr->PrevPosition.vx) + && (Player->ObStrategyBlock->DynPtr->Position.vy==Player->ObStrategyBlock->DynPtr->PrevPosition.vy) + && (Player->ObStrategyBlock->DynPtr->Position.vz==Player->ObStrategyBlock->DynPtr->PrevPosition.vz) ) { + /* Actually not moving - overruled! */ + playerIsMoving=0; + } + + if(PlayerStatusPtr->ShapeState!=PMph_Standing) + { + playerIsCrouching = 1; + } + else + { + playerIsCrouching = 0; + } + + if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_PRIMARY)|| + (PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_PRIMARY)) { + playerIsFiring = 1; + } else { + if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_MARINE_PISTOL) { + if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_SECONDARY)|| + (PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_SECONDARY)) { + playerIsFiring = 1; + } else { + playerIsFiring = 0; + } + } else { + playerIsFiring = 0; + } + } + + if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_CUDGEL) + usingCloseAttackWeapon = 1; + else usingCloseAttackWeapon = 0; + + /* Fix cudgel. */ + if (usingCloseAttackWeapon) { + if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_SECONDARY)|| + (PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_SECONDARY)) { + playerIsFiring = 1; + } + } + + /* KJL 14:27:14 10/29/97 - deal with jumping & falling */ + { + DYNAMICSBLOCK *dynPtr = Player->ObStrategyBlock->DynPtr; + if (!dynPtr->IsInContactWithFloor && (dynPtr->TimeNotInContactWithFloor==0)) + playerIsJumping=1; + } + + /* and deduce the sequence */ + if(playerIsAlive==0) + { + if(playerIsCrouching) { + return MSQ_CrouchDie; + } else { + return MSQ_StandDieFront; + } + } + + if(playerIsJumping) { + return MSQ_Jump; + } + + /* Put this in here... no running cudgel attacks yet. */ + if(playerIsFiring&&usingCloseAttackWeapon) { + /* Deal with cudgel case! */ + if (StaffAttack>=0) { + return(MSQ_BaseOfCudgelAttacks+StaffAttack); + } + } + + if(playerIsCrouching) + { + if(playerIsMoving>0) { + return MSQ_Crawl; + } else if (playerIsMoving<0) { + return MSQ_Crawl_Backwards; + } else { + return MSQ_Crouch; + } + } + + if(playerIsMoving>0) + { + if(playerIsFiring) { + if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_TWO_PISTOLS) + &&(LastHand)) { + return MSQ_RunningFireSecondary; + } else { + return MSQ_RunningFire; + } + } else { + return MSQ_Walk; + } + } else if (playerIsMoving<0) { + if(playerIsFiring) { + if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_TWO_PISTOLS) + &&(LastHand)) { + return MSQ_RunningFireSecondary_Backwards; + } else { + return MSQ_RunningFire_Backwards; + } + } else { + return MSQ_Walk_Backwards; + } + } + + if(playerIsFiring) { + if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_TWO_PISTOLS) + &&(LastHand)) { + return MSQ_StandingFireSecondary; + } else { + return MSQ_StandingFire; + } + } else { + if (PlayerStatusPtr->tauntTimer!=0) { + return MSQ_Taunt; + } else { + return MSQ_Stand; + } + } +} + +static ALIEN_SEQUENCE GetMyAlienSequence(void) +{ + extern STRATEGYBLOCK *Biting; + extern int Bit; + int playerIsMoving = 0; + int playerIsFiring = 0; + int playerIsCrouching = 0; + int playerIsAlive = 0; + int playerIsJumping = 0; + + /* sort out what state we're in */ + if(PlayerStatusPtr->IsAlive) playerIsAlive = 1; + else playerIsAlive = 0; + + if (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_Backward) { + playerIsMoving =-1; + } else if ((PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_Forward)|| + (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepLeft)|| + (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepRight)) { + playerIsMoving = 1; + } else { + playerIsMoving = 0; + } + + if ( (Player->ObStrategyBlock->DynPtr->Position.vx==Player->ObStrategyBlock->DynPtr->PrevPosition.vx) + && (Player->ObStrategyBlock->DynPtr->Position.vy==Player->ObStrategyBlock->DynPtr->PrevPosition.vy) + && (Player->ObStrategyBlock->DynPtr->Position.vz==Player->ObStrategyBlock->DynPtr->PrevPosition.vz) ) { + /* Actually not moving - overruled! */ + playerIsMoving=0; + } + + if(PlayerStatusPtr->ShapeState!=PMph_Standing) playerIsCrouching = 1; + else playerIsCrouching = 0; + + /* ChrisF 20/4/98: playerIsFiring now specifies alien weapon behaviour. */ + //if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_PRIMARY)|| + // (PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_PRIMARY)) + // playerIsFiring = 1; + //else playerIsFiring = 0; + // + //if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber!=WEAPON_ALIEN_SPIT) { + // usingCloseAttackWeapon = 1; + //} else { + // usingCloseAttackWeapon = 0; + //} + + switch(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState) { + case (WEAPONSTATE_FIRING_PRIMARY): + if(Biting) { + playerIsFiring=4; //Eat. + } else { + playerIsFiring=1; //Claw. + } + break; + case (WEAPONSTATE_FIRING_SECONDARY): + playerIsFiring=2; //Tail Poise. + break; + case (WEAPONSTATE_RECOIL_SECONDARY): + playerIsFiring=3; //Tail Strike. + break; + default: + playerIsFiring=0; //Nothing. + break; + } + + + /* KJL 14:27:14 10/29/97 - deal with jumping & falling */ + { + DYNAMICSBLOCK *dynPtr = Player->ObStrategyBlock->DynPtr; + if (!dynPtr->IsInContactWithFloor && (dynPtr->TimeNotInContactWithFloor==0)) + playerIsJumping=1; + } + + /* and deduce the sequence */ + if(playerIsAlive==0) + { + return ASQ_Stand; /* kind of irrelevant really */ + } + + if(playerIsJumping) /* TODO: consider jump & crouch */ + { + switch(playerIsFiring) { + case 1: + return ASQ_Pounce; + break; + case 2: + return ASQ_JumpingTailPoise; + break; + case 3: + return ASQ_JumpingTailStrike; + break; + case 4: + /* What the hell? */ + return ASQ_Eat; + break; + default: + return ASQ_Jump; + break; + } + } + + if(playerIsCrouching) + { + if(playerIsMoving>0) + { + switch(playerIsFiring) { + case 1: + return ASQ_CrawlingAttack_Claw; + break; + case 2: + return ASQ_CrawlingTailPoise; + break; + case 3: + return ASQ_CrawlingTailStrike; + break; + case 4: + /* What the hell? */ + return ASQ_CrouchEat; + break; + default: + if(Player->ObStrategyBlock->DynPtr->OrientMat.mat22>50000) + return ASQ_Scamper; + else + return ASQ_Crawl; + break; + } + } else if(playerIsMoving<0) { + switch(playerIsFiring) { + case 1: + return ASQ_CrawlingAttack_Claw_Backwards; + break; + case 2: + return ASQ_CrawlingTailPoise_Backwards; + break; + case 3: + return ASQ_CrawlingTailStrike_Backwards; + break; + case 4: + /* What the hell? */ + return ASQ_CrouchEat; + break; + default: + if(Player->ObStrategyBlock->DynPtr->OrientMat.mat22>50000) + return ASQ_Scamper_Backwards; + else + return ASQ_Crawl_Backwards; + break; + } + } + + switch(playerIsFiring) { + case 1: + return ASQ_CrouchedAttack_Claw; + break; + case 2: + return ASQ_CrouchedTailPoise; + break; + case 3: + return ASQ_CrouchedTailStrike; + break; + case 4: + return ASQ_Eat; + break; + default: + return ASQ_Crouch; + break; + } + } + + if(playerIsMoving>0) + { + switch(playerIsFiring) { + case 1: + return ASQ_RunningAttack_Claw; + break; + case 2: + return ASQ_RunningTailPoise; + break; + case 3: + return ASQ_RunningTailStrike; + break; + case 4: + /* What the hell? */ + return ASQ_Eat; + break; + default: + return ASQ_Run; + break; + } + } else if(playerIsMoving<0) { + switch(playerIsFiring) { + case 1: + return ASQ_RunningAttack_Claw_Backwards; + break; + case 2: + return ASQ_RunningTailPoise_Backwards; + break; + case 3: + return ASQ_RunningTailStrike_Backwards; + break; + case 4: + /* What the hell? */ + return ASQ_Eat; + break; + default: + return ASQ_Run_Backwards; + break; + } + } + + switch(playerIsFiring) { + case 1: + return ASQ_StandingAttack_Claw; + break; + case 2: + return ASQ_StandingTailPoise; + break; + case 3: + return ASQ_StandingTailStrike; + break; + case 4: + return ASQ_Eat; + break; + default: + if (PlayerStatusPtr->tauntTimer!=0) { + /* Second lowest priority ever. */ + return ASQ_Taunt; + } else { + return ASQ_Stand; + } + break; + } + +} + +static PREDATOR_SEQUENCE GetMyPredatorSequence(void) +{ + int playerIsMoving = 0; + int playerIsFiring = 0; + int playerIsCrouching = 0; + int playerIsAlive = 0; + int playerIsJumping = 0; + int usingCloseAttackWeapon; + extern int StaffAttack; + + /* sort out what state we're in */ + if(PlayerStatusPtr->IsAlive) playerIsAlive = 1; + else playerIsAlive = 0; + + if (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_Backward) { + playerIsMoving=-1; + } else if((PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_Forward)|| + (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepLeft)|| + (PlayerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepRight)) { + playerIsMoving = 1; + } else { + playerIsMoving = 0; + } + + if ( (Player->ObStrategyBlock->DynPtr->Position.vx==Player->ObStrategyBlock->DynPtr->PrevPosition.vx) + && (Player->ObStrategyBlock->DynPtr->Position.vy==Player->ObStrategyBlock->DynPtr->PrevPosition.vy) + && (Player->ObStrategyBlock->DynPtr->Position.vz==Player->ObStrategyBlock->DynPtr->PrevPosition.vz) ) { + /* Actually not moving - overruled! */ + playerIsMoving=0; + } + + if(PlayerStatusPtr->ShapeState!=PMph_Standing) playerIsCrouching = 1; + else playerIsCrouching = 0; + + playerIsFiring = 0; + + if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_PRED_SHOULDERCANNON) + { + //the shoulder cannon is fired during recoil (I think) + if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_PRIMARY) + { + playerIsFiring = 1; + } + } + else if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_PRED_WRISTBLADE) + { + if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_PRIMARY)|| + (PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_PRIMARY) || + (PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_SECONDARY)) + { + if(StaffAttack!=-1) + { + playerIsFiring = 1; + } + } + } + else + { + if((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_PRIMARY)|| + (PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_RECOIL_PRIMARY)) + { + playerIsFiring = 1; + } + } + + if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_PRED_WRISTBLADE) + usingCloseAttackWeapon = 3; + else if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_PRED_DISC) + usingCloseAttackWeapon = 1; + else if(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].WeaponIDNumber==WEAPON_PRED_STAFF) + usingCloseAttackWeapon = 2; + else usingCloseAttackWeapon = 0; + + /* KJL 14:27:14 10/29/97 - deal with jumping & falling */ + { + DYNAMICSBLOCK *dynPtr = Player->ObStrategyBlock->DynPtr; + if (!dynPtr->IsInContactWithFloor && (dynPtr->TimeNotInContactWithFloor==0)) + playerIsJumping=1; + } + + /* and deduce the sequence */ + if(playerIsAlive==0) + { + if(playerIsCrouching) { + return PredSQ_CrouchDie; + } else { + return PredSQ_StandDie; + } + } + + if(playerIsJumping) { + return(PredSQ_Jump); + } + + if(playerIsCrouching) + { + if(playerIsMoving>0) + { + if(playerIsFiring&&usingCloseAttackWeapon) { + /* Deal with staff case! */ + if (usingCloseAttackWeapon==2) { + if (StaffAttack>=0) { + return(PredSQ_BaseOfStaffAttacks+StaffAttack); + } + } else if (usingCloseAttackWeapon==3) { + if (StaffAttack>=0) { + return(PredSQ_BaseOfWristbladeAttacks+StaffAttack); + } + } + return PredSQ_CrawlingSwipe; + } else { + return PredSQ_Crawl; + } + } else if (playerIsMoving<0) { + if(playerIsFiring&&usingCloseAttackWeapon) { + /* Deal with staff case! */ + if (usingCloseAttackWeapon==2) { + if (StaffAttack>=0) { + return(PredSQ_BaseOfStaffAttacks+StaffAttack); + } + } else if (usingCloseAttackWeapon==3) { + if (StaffAttack>=0) { + return(PredSQ_BaseOfWristbladeAttacks+StaffAttack); + } + } + return PredSQ_CrawlingSwipe_Backwards; + } else { + return PredSQ_Crawl_Backwards; + } + } + if(playerIsFiring&&usingCloseAttackWeapon) { + /* Deal with staff case! */ + if (usingCloseAttackWeapon==2) { + if (StaffAttack>=0) { + return(PredSQ_BaseOfStaffAttacks+StaffAttack); + } + } else if (usingCloseAttackWeapon==3) { + if (StaffAttack>=0) { + return(PredSQ_BaseOfWristbladeAttacks+StaffAttack); + } + } + return PredSQ_CrouchedSwipe; + } else { + return PredSQ_Crouch; + } + } + + if(playerIsMoving>0) + { + if(playerIsFiring&&usingCloseAttackWeapon) { + /* Deal with staff case! */ + if (usingCloseAttackWeapon==2) { + if (StaffAttack>=0) { + return(PredSQ_BaseOfStaffAttacks+StaffAttack); + } + } else if (usingCloseAttackWeapon==3) { + if (StaffAttack>=0) { + return(PredSQ_BaseOfWristbladeAttacks+StaffAttack); + } + } + return PredSQ_RunningSwipe; + } else { + return PredSQ_Run; + } + } else if (playerIsMoving<0) { + if(playerIsFiring&&usingCloseAttackWeapon) { + /* Deal with staff case! */ + if (usingCloseAttackWeapon==2) { + if (StaffAttack>=0) { + return(PredSQ_BaseOfStaffAttacks+StaffAttack); + } + } else if (usingCloseAttackWeapon==3) { + if (StaffAttack>=0) { + return(PredSQ_BaseOfWristbladeAttacks+StaffAttack); + } + } + return PredSQ_RunningSwipe_Backwards; + } else { + return PredSQ_Run_Backwards; + } + } + + if(playerIsFiring&&usingCloseAttackWeapon) { + /* Deal with staff case! */ + if (usingCloseAttackWeapon==2) { + if (StaffAttack>=0) { + return(PredSQ_BaseOfStaffAttacks+StaffAttack); + } + } else if (usingCloseAttackWeapon==3) { + if (StaffAttack>=0) { + return(PredSQ_BaseOfWristbladeAttacks+StaffAttack); + } + } + return PredSQ_StandingSwipe; + } else { + if (PlayerStatusPtr->tauntTimer!=0) { + return PredSQ_Taunt; + } else { + return PredSQ_Stand; + } + } +} + +/* Patrick 11/7/97 ---------------------------------------------- +Functions for transmitting state changes +-----------------------------------------------------------------*/ +void TransmitEndOfGameNetMsg(void) +{ + int i; + /* first of, initialise the send buffer: this means that we may loose some stacked + messages, but this should be ok.*/ + InitialiseSendMessageBuffer(); + + netGameData.myGameState=NGS_EndGameScreen; + for(i=0;iSBdataptr; + + /* some basic checks */ + if(playerSbPtr==NULL) return; + if(playerSbPtr->DynPtr==NULL) return; + if(!ActiveStBlockList) return; + if(NumActiveStBlocks<=0) return; + + //set the players invulnerability timer + GLOBALASSERT(psPtr); + psPtr->invulnerabilityTimer=netGameData.invulnerableTime*ONE_FIXED; + + + //select the start positions for this character type + switch(AvP.PlayerType) + { + case I_Marine : + numStartPositions=numMarineStartPos; + startPositions=marineStartPositions; + break; + + case I_Predator : + numStartPositions=numPredatorStartPos; + startPositions=predatorStartPositions; + break; + + case I_Alien : + numStartPositions=numAlienStartPos; + startPositions=alienStartPositions; + break; + } + + + if(!numStartPositions) return; + + /* pick a starting point*/ + if(startOfGame) + { + numReadThro = (PlayerIdInPlayerList(AVPDPNetID))%8; + while(numReadThro<0) + { + //Probably haven't received the details of all the players yet + MinimalNetCollectMessages(); + numReadThro = (PlayerIdInPlayerList(AVPDPNetID))%8; + } + } + else numReadThro = FastRandom()%numStartPositions; + numConsidered = 0; + + /* and go through the list */ + for(start_index=numReadThro;!found;start_index++) + { + start_index%=numStartPositions; + + /* we are going to try this one: see if it's clear */ + { + int sbIndex2 = 0; + STRATEGYBLOCK *sbPtr2; + int obstructed = 0; + + while((sbIndex2 < NumActiveStBlocks)&&(!obstructed)) + { + sbPtr2 = ActiveStBlockList[sbIndex2++]; + if(sbPtr2->I_SBtype==I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)sbPtr2->SBdataptr; + LOCALASSERT(ghostData); + if((ghostData->type==I_BehaviourMarinePlayer)|| + (ghostData->type==I_BehaviourPredatorPlayer)|| + (ghostData->type==I_BehaviourAlienPlayer)) + { + VECTORCH seperationVec; + LOCALASSERT(sbPtr2->DynPtr); + seperationVec = sbPtr2->DynPtr->Position; + seperationVec.vx -= startPositions[start_index].vx; + seperationVec.vy -= startPositions[start_index].vy; + seperationVec.vz -= startPositions[start_index].vz; + if((Magnitude(&seperationVec)<2000)&&(numConsidered<8)) obstructed = 1; + } + } + } + + numConsidered++; + if(!obstructed) + { + /* found a clear start position */ + playerSbPtr->DynPtr->Position = playerSbPtr->DynPtr->PrevPosition = startPositions[start_index]; + found = 1; + + } + } + } +} +#else +void TeleportNetPlayerToAStartingPosition(STRATEGYBLOCK *playerSbPtr, int startOfGame) +{ + int numStartPositions; + MULTIPLAYER_START* startPositions; + + int sbIndex = 0; + + int start_index; + int numChecked=0; + int bestDistance=-1; + int bestIndex=-1; + + PLAYER_STATUS *psPtr=(PLAYER_STATUS*)playerSbPtr->SBdataptr; + + if(MultiplayerRestartSeed) + { + StartOfGame_PlayerPlacement(playerSbPtr,MultiplayerRestartSeed); + MultiplayerRestartSeed=0; + return; + } + + /* some basic checks */ + if(playerSbPtr==NULL) return; + if(playerSbPtr->DynPtr==NULL) return; + + //set the players invulnerability timer + GLOBALASSERT(psPtr); + psPtr->invulnerabilityTimer=netGameData.invulnerableTime*ONE_FIXED; + + + //select the start positions for this character type + switch(AvP.PlayerType) + { + case I_Marine : + numStartPositions=numMarineStartPos; + startPositions=marineStartPositions; + break; + + case I_Predator : + numStartPositions=numPredatorStartPos; + startPositions=predatorStartPositions; + break; + + case I_Alien : + numStartPositions=numAlienStartPos; + startPositions=alienStartPositions; + break; + } + + + if(!numStartPositions) return; + + for(start_index=FastRandom()%numStartPositions;numChecked=numStartPositions) start_index=0; + + //find the closest player to this start position + for(playerIndex=0;playerIndex20000) + { + //no player near this start position, so it will do + bestIndex=start_index; + break; + } + else if(closestDistance>bestDistance) + { + bestDistance=closestDistance; + bestIndex=start_index; + } + } + + if(bestIndex!=-1) + { + extern MODULE * playerPherModule; + DYNAMICSBLOCK *dynPtr = playerSbPtr->DynPtr; + //found a start postion + Player->ObWorld=dynPtr->Position = dynPtr->PrevPosition = startPositions[bestIndex].location; + dynPtr->OrientEuler = startPositions[bestIndex].orientation; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + + playerSbPtr->containingModule=ModuleFromPosition(&Player->ObWorld, (MODULE*)0); + playerPherModule=playerSbPtr->containingModule; + + + /* + After teleportation we need to update the visibilities , to ensure that + dynamics will work properly this frame. + */ + { + extern VIEWDESCRIPTORBLOCK* Global_VDB_Ptr; + Global_VDB_Ptr->VDB_World = Player->ObWorld; + AllNewModuleHandler(); + DoObjectVisibilities(); + } + + } + +} +#endif + +/*Works out everyone's starting positions . Use a shared random numer seed +in order to avoid having several players appearing at the same place*/ +void StartOfGame_PlayerPlacement(STRATEGYBLOCK *playerSbPtr,int seed) +{ + extern int NumActiveStBlocks; + extern STRATEGYBLOCK *ActiveStBlockList[]; + int numStartPositions; + MULTIPLAYER_START* startPositions; + PLAYER_STATUS *psPtr=(PLAYER_STATUS*)playerSbPtr->SBdataptr; + + VECTORCH ChosenPositions[NET_MAXPLAYERS]; + int NumChosen=0; + int i; + + //set the players invulnerability timer + GLOBALASSERT(psPtr); + psPtr->invulnerabilityTimer=netGameData.invulnerableTime*ONE_FIXED; + + SetSeededFastRandom(seed); + + for(i=0;i=numStartPositions) index=0; + + //see if anyone is at this position + for(j=0;j=numStartPositions) index=0; + + //we've either found a clear start position , or gone through the entire list + //without finding one.Either way take the starting position index that we reached + + ChosenPositions[NumChosen]=startPositions[index].location; + NumChosen++; + + if(netGameData.playerData[i].playerId==AVPDPNetID) + { + extern MODULE * playerPherModule; + //this was our new start position + DYNAMICSBLOCK *dynPtr = playerSbPtr->DynPtr; + //found a start postion + Player->ObWorld=dynPtr->Position = dynPtr->PrevPosition = startPositions[index].location; + dynPtr->OrientEuler = startPositions[index].orientation; + CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); + TransposeMatrixCH(&dynPtr->OrientMat); + + playerSbPtr->containingModule=ModuleFromPosition(&Player->ObWorld, (MODULE*)0); + playerPherModule=playerSbPtr->containingModule; + + /* + After teleportation we need to update the visibilities , to ensure that + dynamics will work properly this frame. + */ + { + extern VIEWDESCRIPTORBLOCK* Global_VDB_Ptr; + Global_VDB_Ptr->VDB_World = Player->ObWorld; + AllNewModuleHandler(); + DoObjectVisibilities(); + } + //don't care about the positioning of anyone further on in the list + return; + + } + + + } +} + +/* Patrick 4/8/97------------------------------------- + For testing purposes... + ---------------------------------------------------*/ +#define logNetGameProcesses 0 +#if logNetGameProcesses +static FILE *netLogfile; +#endif +void InitNetLog(void) +{ +#if logNetGameProcesses + netLogfile = fopen("NETINFO.TXT","w"); + fprintf(netLogfile, "NETGAME DEBUGGING LOG \n \n"); + fclose(netLogfile); +#endif +} + +void LogNetInfo(char *msg) +{ +#if logNetGameProcesses + if(!msg) return; + netLogfile = fopen("NETINFO.TXT","a"); + fprintf(netLogfile, msg); + fclose(netLogfile); +#endif +} + + + +DISPLAYBLOCK PlayersMirrorImage; +STRATEGYBLOCK PlayersMirrorImageSB; +NETGHOSTDATABLOCK PlayersMirrorGhost; +DYNAMICSBLOCK PlayersMirrorDynBlock; + +BOOL Current_Level_Requires_Mirror_Image() +{ + extern char LevelName[]; + if ( (!stricmp(LevelName,"e3demo")) || (!stricmp(LevelName,"e3demosp")) || (!stricmp(LevelName,"derelict")) ) + { + return TRUE; + } + return FALSE; +} + + +void CreatePlayersImageInMirror(void) +{ + AVP_BEHAVIOUR_TYPE type; + STRATEGYBLOCK *sbPtr = &PlayersMirrorImageSB; + NETGHOSTDATABLOCK *ghostData = &PlayersMirrorGhost; + PlayersMirrorImage.ObStrategyBlock = sbPtr; + + sbPtr->SBdptr = &PlayersMirrorImage; + + sbPtr->SBdataptr = (void *)ghostData; + sbPtr->DynPtr = &PlayersMirrorDynBlock; + + switch(AvP.PlayerType) + { + case(I_Marine): + { + type = I_BehaviourMarinePlayer; + break; + } + case(I_Predator): + { + type = I_BehaviourPredatorPlayer; + break; + } + case(I_Alien): + { + type = I_BehaviourAlienPlayer; + break; + } + } + ghostData->type = type; + ghostData->IOType=IOT_Non; + ghostData->subtype=0; + ghostData->myGunFlash = NULL; + ghostData->SoundHandle = SOUND_NOACTIVEINDEX; + ghostData->currentAnimSequence = 0; + ghostData->CloakingEffectiveness = 0; + ghostData->IgnitionHandshaking = 0; + ghostData->soundStartFlag = 0; + + if(AvP.Network == I_No_Network) + { + ghostData->playerId=0; + } + else + { + ghostData->playerId=AVPDPNetID; + } + + /* set the shape */ + + switch(type) + { + case(I_BehaviourMarinePlayer): + { + CreateMarineHModel(ghostData,WEAPON_PULSERIFLE); + break; + } + case(I_BehaviourAlienPlayer): + { + CreateAlienHModel(ghostData); + break; + } + case(I_BehaviourPredatorPlayer): + { + CreatePredatorHModel(ghostData,WEAPON_PRED_WRISTBLADE); + break; + } + } + sbPtr->SBdptr->HModelControlBlock=&ghostData->HModelController; + ProveHModel(sbPtr->SBdptr->HModelControlBlock,sbPtr->SBdptr); + +} + +void DeallocatePlayersMirrorImage() +{ + #if MIRRORING_ON + if(Current_Level_Requires_Mirror_Image()) + { + Dispel_HModel(&PlayersMirrorGhost.HModelController); + } + #endif +} + + +void RenderPlayersImageInMirror(void) +{ + STRATEGYBLOCK *sbPtr = &PlayersMirrorImageSB; + NETGHOSTDATABLOCK *ghostData = &PlayersMirrorGhost; + + int sequence; + int weapon; + int firingPrimary; + int firingSecondary; + + switch(AvP.PlayerType) + { + case(I_Marine): + { + sequence = (unsigned char)GetMyMarineSequence(); + //check for change of charcter type + if(ghostData->type!=I_BehaviourMarinePlayer) + { + ghostData->type=I_BehaviourMarinePlayer; + //settings currentweapon to -1 will forec the hmodel to be updated + ghostData->CurrentWeapon=-1; + } + + break; + } + case(I_Predator): + { + sequence = (unsigned char)GetMyPredatorSequence(); + //check for change of charcter type + if(ghostData->type!=I_BehaviourPredatorPlayer) + { + ghostData->type=I_BehaviourPredatorPlayer; + //settings currentweapon to -1 will forec the hmodel to be updated + ghostData->CurrentWeapon=-1; + } + break; + } + case(I_Alien): + { + sequence = (unsigned char)GetMyAlienSequence(); + //check for change of charcter type + if(ghostData->type!=I_BehaviourAlienPlayer) + { + ghostData->type=I_BehaviourAlienPlayer; + //setting currentweapon to -1 will force the hmodel to be updated + ghostData->CurrentWeapon=-1; + } + break; + } + default: + { + LOCALASSERT(1==0); + break; + } + } + /* my current weapon id, and whether I am firing it... */ + { + PLAYER_WEAPON_DATA *weaponPtr; + PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr); + LOCALASSERT(playerStatusPtr); + weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + weapon = (signed char)(weaponPtr->WeaponIDNumber); + + if((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)&&(playerStatusPtr->IsAlive)) + firingPrimary = 1; + else firingPrimary = 0; + if((weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY)&&(playerStatusPtr->IsAlive)) + firingSecondary = 1; + else firingSecondary = 0; + } + +// if(!(((!(messagePtr->IAmAlive)))&&(netGameData.playerData[playerIndex].characterType==NGCT_Alien))) + { + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + HandleWeaponElevation(sbPtr,playerStatusPtr->ViewPanX,weapon); + + UpdateGhost(sbPtr,&(Player->ObStrategyBlock->DynPtr->Position),&(Player->ObStrategyBlock->DynPtr->OrientEuler),sequence,AreTwoPistolsInTertiaryFire()); + + + MaintainGhostCloakingStatus(sbPtr,(int)playerStatusPtr->cloakOn); + } + } + { + extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + DISPLAYBLOCK *dPtr = &PlayersMirrorImage; + dPtr->ObWorld = PlayersMirrorDynBlock.Position; + dPtr->ObMat = PlayersMirrorDynBlock.OrientMat; + ReflectObject(dPtr); + + PlayersMirrorImage.ObStrategyBlock = 0; + + AddShape(dPtr,Global_VDB_Ptr); + PlayersMirrorImage.ObStrategyBlock = &PlayersMirrorImageSB; + + } + HandleGhostGunFlashEffect(sbPtr,MyPlayerHasAMuzzleFlash(sbPtr)); +} + + +/* KJL 15:32:17 24/05/98 - respawn all game objects that have been destroyed */ +void RestartNetworkGame(int seed) +{ + int i,j; + if(netGameData.myGameState!=NGS_Playing && netGameData.myGameState!=NGS_EndGameScreen) return; + + //reset all the scores + + for(i=0;i<(NET_MAXPLAYERS);i++) + { + for(j=0;j<(NET_MAXPLAYERS);j++) netGameData.playerData[i].playerFrags[j] = 0; + netGameData.playerData[i].playerScore = 0; + netGameData.playerData[i].playerScoreAgainst = 0; + netGameData.playerData[i].aliensKilled[0]=0; + netGameData.playerData[i].aliensKilled[1]=0; + netGameData.playerData[i].aliensKilled[2]=0; + netGameData.playerData[i].deathsFromAI=0; + netGameData.playerData[i].startFlag = 0; + netGameData.playerData[i].playerAlive = 1; + netGameData.playerData[i].playerHasLives = 1; + } + for(j=0;j<3;j++) netGameData.teamScores[j] = 0; + + netGameData.stateCheckTimeDelay=0; + netGameData.GameTimeElapsed = 0; + netGameData.LMS_AlienIndex=-1; + netGameData.LMS_RestartTimer=0; + netGameData.numDeaths[0]=0; + netGameData.numDeaths[1]=0; + netGameData.numDeaths[2]=0; + + + netGameData.lastPointsBasedRespawn=0; + + AvP.RestartLevel=1; + + + + if(netGameData.gameType==NGT_LastManStanding) + { + int i; + //in a last man standing game , turn everyone in marines to start with + extern void ChangeToMarine(); + ChangeToMarine(); + + for(i=0;iObStrategyBlock, seed); + + netGameData.myGameState=NGS_Playing; + + //record seed for later (used during restart level process) + MultiplayerRestartSeed=seed; + if(!MultiplayerRestartSeed) MultiplayerRestartSeed=1; + +} + + + + +/* KJL 15:46:19 09/04/98 - processing info pertaining to multiplayer games */ + +static void Inform_PlayerHasDied(DPID killer, DPID victim,NETGAME_CHARACTERTYPE killerType,char weaponIcon) +{ + int victimIndex = PlayerIdInPlayerList(victim); + + /* KJL 15:35:38 09/04/98 - not knowing who the victim is what make things a bit awkward... */ + if(victimIndex==NET_IDNOTINPLAYERLIST) return; + + + switch(killerType) + { + case NGCT_AI_Alien : + { + NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_KILLEDBY_ALIEN,netGameData.playerData[victimIndex].name,0); + break; + } + + case NGCT_AI_Predalien : + { + NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_KILLEDBY_PREDALIEN,netGameData.playerData[victimIndex].name,0); + break; + } + + case NGCT_AI_Praetorian : + { + NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_KILLEDBY_PRAETORIAN,netGameData.playerData[victimIndex].name,0); + break; + } + + default : + { + /* KJL 15:36:03 09/04/98 - killer should be set to null if it's a suicide */ + /*killer==vitim means suicide now ,as well*/ + if (killer && killer!=victim) + { + int killerIndex = PlayerIdInPlayerList(killer); + + if(killerIndex!=NET_IDNOTINPLAYERLIST) + { + char weaponSymbol[5]=""; + if(weaponIcon) + { + sprintf(weaponSymbol," %c",weaponIcon); + } + NetworkGameConsoleMessageWithWeaponIcon(TEXTSTRING_MULTIPLAYERCONSOLE_KILLEDBY,netGameData.playerData[victimIndex].name,netGameData.playerData[killerIndex].name,weaponSymbol); + } + } + else + { + NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_SUICIDE,netGameData.playerData[victimIndex].name,0); + } + break; + } + } +} + +static void Inform_AiHasDied(DPID killer,ALIEN_TYPE type,char weaponIcon) +{ + int killerIndex = PlayerIdInPlayerList(killer); + + if(killerIndex!=NET_IDNOTINPLAYERLIST) + { + char weaponSymbol[5]=""; + if(weaponIcon) + { + sprintf(weaponSymbol," %c",weaponIcon); + } + switch(type) + { + case AT_Standard : + { + NetworkGameConsoleMessageWithWeaponIcon(TEXTSTRING_MULTIPLAYERCONSOLE_ALIEN_KILLED,netGameData.playerData[killerIndex].name,0,weaponSymbol); + break; + } + + case AT_Predalien : + { + NetworkGameConsoleMessageWithWeaponIcon(TEXTSTRING_MULTIPLAYERCONSOLE_PREDALIEN_KILLED,netGameData.playerData[killerIndex].name,0,weaponSymbol); + break; + } + + case AT_Praetorian : + { + NetworkGameConsoleMessageWithWeaponIcon(TEXTSTRING_MULTIPLAYERCONSOLE_PRAETORIAN_KILLED,netGameData.playerData[killerIndex].name,0,weaponSymbol); + break; + } + } + } +} + +static void Inform_PlayerHasLeft(DPID player) +{ + int playerIndex = PlayerIdInPlayerList(player); + + /* KJL 15:35:38 09/04/98 - not knowing who the player is what make things a bit awkward... */ + if(playerIndex==NET_IDNOTINPLAYERLIST) return; + + NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_LEAVEGAME,netGameData.playerData[playerIndex].name,0); + +} +static void Inform_PlayerHasJoined(DPID player) +{ + int playerIndex = PlayerIdInPlayerList(player); + + /* KJL 15:35:38 09/04/98 - not knowing who the player is what make things a bit awkward... */ + if(playerIndex==NET_IDNOTINPLAYERLIST) return; + + NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_JOINGAME,netGameData.playerData[playerIndex].name,0); +} +static void Inform_PlayerHasConnected(DPID player) +{ + int playerIndex = PlayerIdInPlayerList(player); + + /* KJL 15:35:38 09/04/98 - not knowing who the player is what make things a bit awkward... */ + if(playerIndex==NET_IDNOTINPLAYERLIST) return; + + NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_CONNECTGAME,netGameData.playerData[playerIndex].name,0); +} + +static void Inform_NewHost(void) +{ + NewOnScreenMessage(GetTextString(TEXTSTRING_MULTIPLAYERCONSOLE_NEWHOST)); +} + + + + +static void WriteFragmentStatus(int fragmentNumber, int status) +{ + int n = fragmentNumber>>3; + int r = fragmentNumber - (n<<3); + unsigned char *ptr = &FragmentalObjectStatus[n]; + unsigned char mask = 1<>3; + int r = fragmentNumber - (n<<3); + unsigned char *ptr = &FragmentalObjectStatus[n]; + unsigned char mask = 1<>2; + int shift = (objectNumber - (n<<2))*2; + unsigned char *ptr = &StrategySynchArray[n]; + unsigned char mask = 3<>2; + int shift = (objectNumber - (n<<2))*2; + unsigned char *ptr = &StrategySynchArray[n]; + unsigned char mask = 3<>shift); +} + + + +#if 1 +static int GetDynamicScoreMultiplier(int playerKilledIndex,int killerIndex) +{ + int scoreFor; + int scoreAgainst; + int mult; + int playerCount=0; + int i; + + + GLOBALASSERT(playerKilledIndex!=killerIndex); + + scoreFor=netGameData.playerData[playerKilledIndex].playerScore; + scoreAgainst=netGameData.playerData[playerKilledIndex].playerScoreAgainst; + + scoreFor=max(500,scoreFor+500); + scoreAgainst=max(500,scoreAgainst+500); + + //count players + for(i=0;iscoreAgainst) + { + int ratio=DIV_FIXED(scoreFor,scoreAgainst); + mult=DIV_FIXED(10*ratio,9*ONE_FIXED+ratio); + if(multONE_FIXED) mult=ONE_FIXED; + } + + + return mult; + +} +#else +static int GetDynamicScoreMultiplier(int playerKilledIndex,int killerIndex) +{ + int i; + int scoreTotal=0; + int playerCount=0; + int playerKilledScore; + int mult; + + GLOBALASSERT(playerKilledIndex!=killerIndex); + + //add up score of all players + for(i=0;iscoreTotal) + { + int ratio=DIV_FIXED(playerKilledScore,scoreTotal); + mult=DIV_FIXED(10*ratio,10*ONE_FIXED+ratio); + if(multONE_FIXED) mult=ONE_FIXED; + } + + + return mult; + +} +#endif +static int GetNetScoreForKill(int playerKilledIndex,int killerIndex) +{ + NETGAME_CHARACTERTYPE killerType=netGameData.playerData[killerIndex].characterType; + NETGAME_CHARACTERTYPE playerKilledType=netGameData.playerData[playerKilledIndex].characterType; + + int score=netGameData.baseKillValue; + + if(playerKilledIndex==killerIndex) + { + //suicide + return -netGameData.baseKillValue; + } + + if(netGameData.gameType==NGT_PredatorTag) + { + //only the predator can score + if(killerType!=NGCT_Predator) return 0; + } + else if(netGameData.gameType==NGT_AlienTag) + { + //only the alien can score + if(killerType!=NGCT_Alien) return 0; + } + else if(netGameData.gameType==NGT_CoopDeathmatch) + { + //have we killed someone on the same team + if(killerType==playerKilledType) + { + return -netGameData.baseKillValue; + } + } + + if(netGameData.useCharacterKillValues) + { + score=netGameData.characterKillValues[playerKilledType]; + } + + if(netGameData.useDynamicScoring && score>0) + { + int dynamicScoreMult=GetDynamicScoreMultiplier(playerKilledIndex,killerIndex); + score=MUL_FIXED(score,dynamicScoreMult); + //make sure player gets at least one point + if(score<1) score=1; + } + + + return score; + +} + + +static void CheckLastManStandingState() +{ + //make sure that ther is at least 1 alien and 1 non-alien + int alienCount=0; + int nonAlienCount=0; + int alienIndex; + int i; + + if(netGameData.stateCheckTimeDelay>0) + { + //still too soon after last restart to check again + netGameData.stateCheckTimeDelay-=RealFrameTime; + return; + } + + for(i=0;i=NET_MAXPLAYERS) + { + //everyone has had a turn as an alien + TransmitEndOfGameNetMsg(); + netGameData.myGameState = NGS_EndGameScreen; + return; + } + + if(netGameData.playerData[alienIndex].playerId) + { + //this player will be our new alien + break; + } + } + + //game needs to be restarted. + //has the countdown started? + if(netGameData.LMS_RestartTimer>0) + { + int secondsBefore,secondsAfter; + secondsBefore=(netGameData.LMS_RestartTimer+ONE_FIXED-1)/ONE_FIXED; + netGameData.LMS_RestartTimer-=RealFrameTime; + secondsAfter=(netGameData.LMS_RestartTimer+ONE_FIXED-1)/ONE_FIXED; + + //has the timer reached 0? + if(netGameData.LMS_RestartTimer<0) + { + //get a random number seed for starting position + int seed=FastRandom(); + netGameData.LMS_RestartTimer=0; + + netGameData.LMS_AlienIndex=alienIndex; + + AddNetMsg_LastManStanding_Restart(netGameData.playerData[alienIndex].playerId,seed); + Handle_LastManStanding_Restart(netGameData.playerData[alienIndex].playerId,seed); + + //set time delay until we next check for need to restart + //this gives time for the other players to get their messages + netGameData.stateCheckTimeDelay=5*ONE_FIXED; + } + else + { + //if the timer has gone down another second , tell everyone + if(secondsAfterObStrategyBlock->SBdataptr); + if(psPtr->Mvt_InputRequests.Flags.Rqst_Operate) + { + + //say who the next alien will be + AddNetMsg_PlayerID(netGameData.playerData[alienIndex].playerId,NetMT_LastManStanding_RestartInfo); + Handle_LastManStanding_RestartInfo(netGameData.playerData[alienIndex].playerId); + + //start the restart timer + netGameData.LMS_RestartTimer=4*ONE_FIXED; + } + } + + } + +} + +static void Handle_LastManStanding_Restart(DPID alienID,int seed) +{ + int i; + /* if we're not playing, ignore it */ + if(netGameData.myGameState!=NGS_Playing) return; + if(AVPDPNetID==alienID) + { + //become an alien + extern void ChangeToAlien(); + ChangeToAlien(); + } + else + { + //become a marine + extern void ChangeToMarine(); + ChangeToMarine(); + } + + for(i=0;iObStrategyBlock,seed); + + //restore all the destroyed objects. + RespawnAllObjects(); + */ + + MultiplayerRestartSeed=seed; + AvP.RestartLevel=1; + + PrintStringTableEntryInConsole(TEXTSTRING_MULTIPLAYER_LMS_GO); +} + +static void Handle_LastManStanding_RestartInfo(DPID alienID) +{ + int i; + /* if we're not playing, ignore it */ + if(netGameData.myGameState!=NGS_Playing) return; + + //find the alien's name + for(i=0;i0) + { + netGameData.stateCheckTimeDelay-=RealFrameTime; + return; + } + + if(CountPlayersOfType(tagSpecies)) return; + + //we need to choose a predator player + //make it the person with the lowest score + { + DPID predID=0; + int lowScore=1000000000; + for(i=0;i<(NET_MAXPLAYERS);i++) + { + if(netGameData.playerData[i].playerId) + { + if(netGameData.playerData[i].playerScore='1' && string[1]<='9') + { + if(string[1]=='1' && name1) + { + strcpy(messageptr,name1); + messageptr+=strlen(name1); + } + if(string[1]=='2' && name2) + { + strcpy(messageptr,name2); + messageptr+=strlen(name2); + } + + string+=2; + continue; + } + } + *messageptr++=*string++; + } + *messageptr=0; + + NewOnScreenMessage(OnScreenMessageBuffer); +} + +static void NetworkGameConsoleMessageWithWeaponIcon(enum TEXTSTRING_ID stringID,const char* name1,const char* name2,const char* weaponSymbol) +{ + char* string; + char* messageptr=&OnScreenMessageBuffer[0]; + + string=GetTextString(stringID); + if(!string) return; + + while(*string) + { + if(string[0]=='%') + { + if(string[1]>='1' && string[1]<='9') + { + if(string[1]=='1' && name1) + { + strcpy(messageptr,name1); + messageptr+=strlen(name1); + } + if(string[1]=='2' && name2) + { + strcpy(messageptr,name2); + messageptr+=strlen(name2); + } + + + string+=2; + continue; + } + } + *messageptr++=*string++; + } + *messageptr=0; + + if(weaponSymbol) + { + strcat(OnScreenMessageBuffer,weaponSymbol); + } + + NewOnScreenMessage(OnScreenMessageBuffer); +} + +static int CharacterTypesAvailable[NUM_PC_TYPES]; +static int CharacterSubTypesAvailable[NUM_PC_SUBTYPES]; + +int DetermineAvailableCharacterTypes(BOOL ConsiderUsedCharacters) +{ + int i; + int maxMarines=0; + + //set limits for disallowed marine types to zero + if(!netGameData.allowSmartgun) netGameData.maxMarineSmartgun=0; + if(!netGameData.allowFlamer) netGameData.maxMarineFlamer=0; + if(!netGameData.allowMinigun) netGameData.maxMarineMinigun=0; + if(!netGameData.allowSadar) netGameData.maxMarineSadar=0; + if(!netGameData.allowGrenadeLauncher) netGameData.maxMarineGrenade=0; + if(!netGameData.allowSmartDisc) netGameData.maxMarineSmartDisc=0; + if(!netGameData.allowPistols) netGameData.maxMarinePistols=0; + + if(netGameData.gameType==NGT_PredatorTag) + { + //force limit of one predator + netGameData.maxPredator=1; + } + else if(netGameData.gameType==NGT_AlienTag) + { + //force limit of one alien + netGameData.maxAlien=1; + } + else if(netGameData.gameType==NGT_LastManStanding) + { + //no predators are allowed + netGameData.maxPredator=0; + //the host will be the first alien (and so is the only person that can select alien on the starting screen) + netGameData.maxAlien=1; + } + else if(netGameData.gameType==NGT_Coop) + { + //no pc aliens allowed in coop games + netGameData.maxAlien=0; + } + + if(netGameData.skirmishMode) + { + //Skirmish mode - player can be anything except an alien + netGameData.maxAlien = 0; + netGameData.maxPredator=8; + netGameData.maxMarine=8; + + netGameData.maxMarineGeneral=8; + netGameData.maxMarinePulseRifle=8; + netGameData.maxMarineSmartgun=8; + netGameData.maxMarineFlamer=8; + netGameData.maxMarineSadar=8; + netGameData.maxMarineGrenade=8; + netGameData.maxMarineMinigun=8; + netGameData.maxMarineSmartDisc=8; + netGameData.maxMarinePistols=8; + } + + CharacterTypesAvailable[NGCT_Marine]=netGameData.maxMarine; + CharacterTypesAvailable[NGCT_Alien]=netGameData.maxAlien; + CharacterTypesAvailable[NGCT_Predator]=netGameData.maxPredator; + + CharacterSubTypesAvailable[NGSCT_General]=netGameData.maxMarineGeneral; + CharacterSubTypesAvailable[NGSCT_PulseRifle]=netGameData.maxMarinePulseRifle; + CharacterSubTypesAvailable[NGSCT_Smartgun]=netGameData.maxMarineSmartgun; + CharacterSubTypesAvailable[NGSCT_Flamer]=netGameData.maxMarineFlamer; + CharacterSubTypesAvailable[NGSCT_Sadar]=netGameData.maxMarineSadar; + CharacterSubTypesAvailable[NGSCT_GrenadeLauncher]=netGameData.maxMarineGrenade; + CharacterSubTypesAvailable[NGSCT_Minigun]=netGameData.maxMarineMinigun; + CharacterSubTypesAvailable[NGSCT_Frisbee]=netGameData.maxMarineSmartDisc; + CharacterSubTypesAvailable[NGSCT_Pistols]=netGameData.maxMarinePistols; + + + //go through all the other players to see which character types are being used + if(ConsiderUsedCharacters) + { + if(AvP.Network!=I_No_Network) + { + //(it will still be I_No_Network while the host is setting things up) + for(i=0;i0) return; + break; + + case 1: //predator + if(CharacterTypesAvailable[NGCT_Predator]>0) return; + break; + + case 2: //alien + if(CharacterTypesAvailable[NGCT_Alien]>0) return; + break; + + case 3: //marine (pulse rifle) + if(CharacterSubTypesAvailable[NGSCT_PulseRifle]) return; + break; + + case 4: //marine (smartgun) + if(CharacterSubTypesAvailable[NGSCT_Smartgun]) return; + break; + + case 5: //marine (flamer) + if(CharacterSubTypesAvailable[NGSCT_Flamer]) return; + break; + + case 6: //marine (sadar) + if(CharacterSubTypesAvailable[NGSCT_Sadar]) return; + break; + + case 7: //marine (grenade) + if(CharacterSubTypesAvailable[NGSCT_GrenadeLauncher]) return; + break; + + case 8: //marine (minigun) + if(CharacterSubTypesAvailable[NGSCT_Minigun]) return; + break; + + case 9: //marine (frisbee) + if(CharacterSubTypesAvailable[NGSCT_Frisbee]) return; + break; + + case 10: //marine (pistols) + if(CharacterSubTypesAvailable[NGSCT_Pistols]) return; + break; + + } + + if(search_forwards) + { + (*species)++; + if(*species>10) *species=0; + } + else + { + (*species)--; + if(*species<0) *species=10; + } + count++; + + }while(count<9); + + //oh dear no allowable species + *species=0; + +} + +void SpeciesTag_DetermineMyNextCharacterType() +{ + NETGAME_CHARACTERTYPE tagSpecies; + NETGAME_CHARACTERTYPE otherSpecies; + if(netGameData.gameType==NGT_PredatorTag) + { + if(AvP.PlayerType!=I_Predator) return; + tagSpecies=NGCT_Predator; + otherSpecies=NGCT_Alien; + } + else + { + if(AvP.PlayerType!=I_Alien) return; + tagSpecies=NGCT_Alien; + otherSpecies=NGCT_Predator; + } + + + + if(myNetworkKillerId && myNetworkKillerId!=AVPDPNetID && CountPlayersOfType(tagSpecies)==1) + { + //become the character that killed me + int killer_index=PlayerIdInPlayerList(myNetworkKillerId); + if(killer_index!=NET_IDNOTINPLAYERLIST) + { + netGameData.myNextCharacterType=netGameData.playerData[killer_index].characterType; + netGameData.myCharacterSubType=netGameData.playerData[killer_index].characterSubType; + } + else + { + //the player doing the damage has either left the game , or never existed. + //call it suicide then. + myNetworkKillerId=0; + } + + } + + if(!(myNetworkKillerId && myNetworkKillerId!=AVPDPNetID && CountPlayersOfType(tagSpecies)==1)) + { + int total=0; + //either suicide , or we have too many predators for some reason + //pick marine/alien at random + + //first determine available character types + DetermineAvailableCharacterTypes(TRUE); + + total=CharacterTypesAvailable[NGCT_Marine]+ + CharacterTypesAvailable[otherSpecies]; + + if(total==0) + { + //hmm , no available character types + //in that case look at the character types that are allowed in the first place + DetermineAvailableCharacterTypes(FALSE); + + total=CharacterTypesAvailable[NGCT_Marine]+ + CharacterTypesAvailable[otherSpecies]; + } + + if(total>0) + { + int dieroll=(FastRandom() % total); + + if(dieroll0); + + dieroll=(FastRandom() % total); + + for(i=0;iObStrategyBlock; + + if (sbPtr && sbPtr->I_SBtype==I_BehaviourNetGhost) + { + NETGHOSTDATABLOCK *ghostData; + ghostData = (NETGHOSTDATABLOCK *)sbPtr->SBdataptr; + + //we're only interested in player netghosts + if(ghostData) + { + if(ghostData->type==I_BehaviourMarinePlayer || + ghostData->type==I_BehaviourPredatorPlayer || + ghostData->type==I_BehaviourAlienPlayer) + { + VECTORCH targetView; + SmartTarget_GetCofM(objectPtr,&targetView); + //get the players screen coordinates + if(targetView.vz>0) + { + int screenX = WideMulNarrowDiv + ( + targetView.vx, + Global_VDB_Ptr->VDB_ProjX, + targetView.vz + ); + + int screenY = WideMulNarrowDiv + ( + targetView.vy, + Global_VDB_Ptr->VDB_ProjY, + targetView.vz + ); + + if(screenX<0) screenX=-screenX; + if(screenY<0) screenY=-screenY; + + //make sure the player is in fact on screen + if(screenXVDB_World),1000000) ) + { + { + nearestDist=dist; + nearestID=ghostData->playerId; + } + } + } + } + + } + } + } + } + } + + { + int nearestIndex=PlayerIdInPlayerList(nearestID); + + if(nearestIndex!=NET_IDNOTINPLAYERLIST) + { + //we've found the nearest on screen player, so show the name in the console + NetworkGameConsoleMessage(TEXTSTRING_MULTIPLAYERCONSOLE_PLAYERSEEN,netGameData.playerData[nearestIndex].name,0); + } + } + +} + + +static void CheckForPointBasedObjectRespawn() +{ + int score=0; + int i; + if(netGameData.pointsForRespawn==0) return; + + + + for(i=0;i=(netGameData.lastPointsBasedRespawn + netGameData.pointsForRespawn)) + { + //time for pickups to respawn + AddNetMsg_RespawnPickups(); + + netGameData.lastPointsBasedRespawn=score-(score%netGameData.pointsForRespawn); + RespawnAllPickups(); + + PrintStringTableEntryInConsole(TEXTSTRING_MULTIPLAYER_WEAPON_RESPAWN); + + } + +} + + +static int CountMultiplayerLivesLeft() +{ + int i,j; + int livesUsed=0; + + + //count the lives used + if(netGameData.useSharedLives) + { + //lives used is equal to number of deaths + number of currently living players + if(netGameData.gameType==NGT_CoopDeathmatch) + { + //shared lives , are shared between team members + livesUsed=netGameData.numDeaths[netGameData.myCharacterType]; + } + else + { + livesUsed=netGameData.numDeaths[0]+netGameData.numDeaths[1]+netGameData.numDeaths[2]; + } + + + + for(i=0;inetGameData.maxLives) + { + return 0; + } + + return (netGameData.maxLives-livesUsed); +} + +BOOL AreThereAnyLivesLeft() +{ + + if(netGameData.maxLives==0) return TRUE; //infinite lives + + if(netGameData.gameType!=NGT_Individual && + netGameData.gameType!=NGT_Coop && + netGameData.gameType!=NGT_CoopDeathmatch) + return TRUE; //lives only affect some game types + + return (CountMultiplayerLivesLeft()>0); +} + +#define FONT_ALIENSYMBOL 176 +#define FONT_MARINESYMBOL 177 +#define FONT_PREDATORSYMBOL 178 +void DoMultiplayerEndGameScreen(void) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + int i,j; + int x,y; + char text[100]; + + if(netGameData.myGameState==NGS_EndGameScreen) + { + D3D_FadeDownScreen(16384,0); + } + else + { + ShowMultiplayerScoreTimer-=RealFrameTime; + if(ShowMultiplayerScoreTimer<=0)ShowMultiplayerScoreTimer=0; + } + +// RenderStringCentred("Test Endgame Screen",ScreenDescriptorBlock.SDB_Width/2,ScreenDescriptorBlock.SDB_Height/2,0xffffffff); + + + //draw headings + y=150; + x=120; + + for(i=0;i0) + { + netGameData.stateCheckTimeDelay-=RealFrameTime; + return; + } + netGameData.stateCheckTimeDelay=0; + + RenderStringCentred(GetTextString(TEXTSTRING_MULTIPLAYER_PRESSKEYTORESTARTGAME),ScreenDescriptorBlock.SDB_Width/2,ScreenDescriptorBlock.SDB_Height-20,0xffffffff); + if (DebouncedGotAnyKey) + { + int seed=FastRandom(); + RestartNetworkGame(seed); + AddNetMsg_RestartNetworkGame(seed); + } + } + else + { + RenderStringCentred(GetTextString(TEXTSTRING_MULTIPLAYER_WAITFORRESTARTGAME),ScreenDescriptorBlock.SDB_Width/2,ScreenDescriptorBlock.SDB_Height-20,0xffffffff); + } + } + else if(!playerStatusPtr->IsAlive) + { + if(AreThereAnyLivesLeft()) + { + RenderStringCentred(GetTextString(TEXTSTRING_MULTIPLAYER_OPERATETORESPAWN),ScreenDescriptorBlock.SDB_Width/2,ScreenDescriptorBlock.SDB_Height-20,0xffffffff); + } + else + { + RenderStringCentred(GetTextString(TEXTSTRING_MULTIPLAYER_OPERATETOOBSERVE),ScreenDescriptorBlock.SDB_Width/2,ScreenDescriptorBlock.SDB_Height-20,0xffffffff); + } + } +} + +static BOOL IsItPossibleToScore() +{ + + if(CalculateMyScore()) return TRUE; + + if(netGameData.gameType==NGT_LastManStanding) return TRUE; + if(netGameData.gameType==NGT_Coop) + { + if(netGameData.aiKillValues[0]) return TRUE; + if(netGameData.aiKillValues[1]) return TRUE; + if(netGameData.aiKillValues[2]) return TRUE; + return FALSE; + } + else + { + if(netGameData.baseKillValue == 0) return FALSE; + if(netGameData.useCharacterKillValues && !netGameData.useDynamicScoring) + { + if(netGameData.characterKillValues[0]) return TRUE; + if(netGameData.characterKillValues[1]) return TRUE; + if(netGameData.characterKillValues[2]) return TRUE; + return FALSE; + } + } + return TRUE; + +} + +void DoMultiplayerSpecificHud() +{ + + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + char text[200]; + + //Show score table if either + //1. Player has asked to + //2. Game is over + //3. Player is dead and not observing anyone + if(ShowMultiplayerScoreTimer>0 || + netGameData.myGameState==NGS_EndGameScreen || + (!playerStatusPtr->IsAlive && !MultiplayerObservedPlayer)) + { + DoMultiplayerEndGameScreen(); + } + else + { + + if(MultiplayerObservedPlayer) + { + //show the name of the observed player + int index=PlayerIdInPlayerList(MultiplayerObservedPlayer); + if(index!=NET_IDNOTINPLAYERLIST) + { + RenderStringCentred(netGameData.playerData[index].name,ScreenDescriptorBlock.SDB_Width/2,ScreenDescriptorBlock.SDB_Height/2,0xff0000ff); + } + } + + + /* + { + int i; + int myIndex = PlayerIdInPlayerList(AVPDPNetID); + LOCALASSERT(myIndex!=NET_IDNOTINPLAYERLIST); + for(i=0;i0) + { + int hoursLeft; + int minutesLeft; + int secondsLeft=(netGameData.timeLimit*60)-(netGameData.GameTimeElapsed>>16); + if(secondsLeft<0) secondsLeft=0; + + hoursLeft=secondsLeft/3600; + minutesLeft=(secondsLeft/60)%60; + secondsLeft%=60; + + //display time left as hh:mm:ss + sprintf(text,"%s : %02d:%02d:%02d",GetTextString(TEXTSTRING_MULTIPLAYER_TIME),hoursLeft,minutesLeft,secondsLeft); + + RenderString(text,5,20,0xffffffff); + + } + +} + + +void GetNextMultiplayerObservedPlayer() +{ + extern int GlobalFrameCounter; + static int LastFrameTried; + + //Use the frame counter to debounce changing player to observe + if(LastFrameTried==GlobalFrameCounter || LastFrameTried+1==GlobalFrameCounter) + { + //obviously tried last frame , so don't bother trying to find a player to watch + LastFrameTried=GlobalFrameCounter; + return; + } + else + { + int cur_index=PlayerIdInPlayerList(MultiplayerObservedPlayer); + int next_index; + int count=0; + + LastFrameTried=GlobalFrameCounter; + + for(next_index=cur_index+1;countObStrategyBlock->DynPtr; + MultiplayerObservedPlayer=netGameData.playerData[next_index].playerId; + //need to disable gravity , and make sure the playher isn't moving + //of his own accord + dynPtr->GravityOn=0; + + dynPtr->LinImpulse.vx=0; + dynPtr->LinImpulse.vy=0; + dynPtr->LinImpulse.vz=0; + + dynPtr->LinVelocity.vx=0; + dynPtr->LinVelocity.vy=0; + dynPtr->LinVelocity.vz=0; + + + return; + } + } + } + + //oh well , no one available to observe + TurnOffMultiplayerObserveMode(); + } +} + +void TurnOffMultiplayerObserveMode() +{ + if(MultiplayerObservedPlayer) + { + DYNAMICSBLOCK* dynPtr=Player->ObStrategyBlock->DynPtr; + + MultiplayerObservedPlayer=0; + + //need to turn gravity and collisions back on + dynPtr->GravityOn=1; + } +} + +void CheckStateOfObservedPlayer() +{ + int index=PlayerIdInPlayerList(MultiplayerObservedPlayer); + if(!MultiplayerObservedPlayer) return; + + //our observed player must exist + if(index==NET_IDNOTINPLAYERLIST) + { + TurnOffMultiplayerObserveMode(); + return; + } + + //he must also be alive + if(!netGameData.playerData[index].playerAlive) + { + TurnOffMultiplayerObserveMode(); + return; + } +} + + + +static int CalculateMyScore() +{ + int myIndex=PlayerIdInPlayerList(AVPDPNetID); + if(myIndex==NET_IDNOTINPLAYERLIST) return 0; + + if(netGameData.gameType==NGT_Coop) + { + int score=0; + int i; + for(i=0;i<3;i++) + { + score+=netGameData.playerData[myIndex].aliensKilled[i]*netGameData.aiKillValues[i]; + } + return score; + + } + else + { + return netGameData.playerData[myIndex].playerScore; + } +} + + + + +static void PeriodicScoreUpdate() +{ + static unsigned int timer=0; + static int playerIndex=0; + int count=0; + + //cycle through the players , sending scores every 2 seconds + timer+=RealFrameTime; + if(timer<2*ONE_FIXED) return; + timer=0; + + if(netGameData.myGameState!=NGS_Playing) return; + for(playerIndex++;count=NET_MAXPLAYERS && netGameData.gameType==NGT_CoopDeathmatch) + { + //for species deathmatch games also update team scores occasionly + AddNetMsg_SpeciesScores(); + } + + playerIndex%=NET_MAXPLAYERS; + if(netGameData.playerData[playerIndex].playerId) + { + AddNetMsg_PlayerScores(playerIndex); + return; + } + } +} + + + +static int GetStrategySynchObjectChecksum() +{ + /* + Generate a number from the sbnames of all the strategies that need to be synched + */ + int sum=0; + int position=0; + int i; + for (i=0; iI_SBtype == I_BehaviourBinarySwitch || + sbPtr->I_SBtype == I_BehaviourLinkSwitch || + sbPtr->I_SBtype == I_BehaviourTrackObject) + { + position++; + sum+=(*(int*)&sbPtr->SBname[0])*position; + } + } + if(sum==0) sum=1; + return sum; +} + + diff --git a/3dc/avp/win95/Pldnet.h b/3dc/avp/win95/Pldnet.h new file mode 100644 index 0000000..1ffc2cc --- /dev/null +++ b/3dc/avp/win95/Pldnet.h @@ -0,0 +1,1023 @@ +/* Patrick 10/7/97------------------------------------------------------ + Header for Multi-Player game support header + ----------------------------------------------------------------------*/ +#ifndef pldnet_h_included +#define pldnet_h_included +#ifdef __cplusplus +extern "C" { +#endif + +#define EXTRAPOLATION_TEST 1 + +/* Oh, for heaven's sake... */ +#include "psnd.h" +#include "particle.h" +/* --------------------------------------------------------------------- + Some defines for multiplayer games + ----------------------------------------------------------------------*/ +#define NET_MAXPLAYERS (8) +#define NET_MAXPLAYEROBJECTS (15) +#define NET_MAXPLAYERSCORE (500) +#define NET_MAXGAMETIME (255) /* minutes */ +#define NET_MESSAGEBUFFERSIZE (3072) /* an adequate number of bytes */ +#define NET_PLAYERNAMELENGTH (13) +#define NET_EULERSCALESHIFT (4) +#define NET_MAXOBJECTID (32767) +#define NET_MESSAGEITERATIONS (5) +#define NET_MAXTEAMS (4) + +#define NET_IDNOTINPLAYERLIST (-1) +#define NET_NOEMPTYSLOTINPLAYERLIST (-1) + +#define NET_STARTUPINTEGRITY (ONE_FIXED*2) + +#define NETGAMESPEED_70PERCENT 0 +#define NETGAMESPEED_80PERCENT 1 +#define NETGAMESPEED_90PERCENT 2 +#define NETGAMESPEED_100PERCENT 3 + +#define JOINNETGAME_WAITFORSTART 0 +#define JOINNETGAME_WAITFORDESC 1 +#define JOINNETGAME_WRONGAVPVERSION 2 +#define JOINNETGAME_DONTHAVELEVEL 3 + +/* --------------------------------------------------------------------- + Enum of message types + ----------------------------------------------------------------------*/ +typedef enum netmessagetype +{ + NetMT_GameDescription, + NetMT_PlayerDescription, + NetMT_StartGame, + NetMT_PlayerState, + NetMT_PlayerState_Minimal, + NetMT_PlayerState_Medium, + NetMT_PlayerKilled, + NetMT_PlayerLeaving, + NetMT_AllGameScores, + NetMT_PlayerScores, + NetMT_LocalRicochet, + NetMT_LocalObjectState, + NetMT_LocalObjectDamaged, + NetMT_LocalObjectDestroyed, + NetMT_ObjectPickedUp, + NetMT_InanimateObjectDamaged, + NetMT_InanimateObjectDestroyed, + NetMT_LOSRequestBinarySwitch, + NetMT_PlatformLiftState, + NetMT_RequestPlatformLiftActivate, + NetMT_PlayerAutoGunState, + NetMT_MakeDecal, + NetMT_ChatBroadcast, + NetMT_MakeExplosion, + NetMT_MakeFlechetteExplosion, + NetMT_MakePlasmaExplosion, + NetMT_PredatorSights, + NetMT_LocalObjectOnFire, + NetMT_RestartNetworkGame, + NetMT_FragmentalObjectsStatus, + NetMT_AlienAIState, + NetMT_AlienAISequenceChange, + NetMT_AlienAIKilled, + NetMT_GhostHierarchyDamaged, + NetMT_SpotAlienSound, + NetMT_LocalObjectDestroyed_Request, + NetMT_LastManStanding_Restart, + NetMT_LastManStanding_RestartInfo, + NetMT_LastManStanding_RestartCountDown, + NetMT_LastManStanding_LastMan, + NetMT_PredatorTag_NewPredator, //same message also used for alien tag + NetMT_EndGame, + NetMT_CreateWeapon, + NetMT_RespawnPickups, + NetMT_ScoreChange, + NetMT_Gibbing, + NetMT_CorpseDeathAnim, + NetMT_StrategySynch, + NetMT_FrameTimer, + NetMT_SpeciesScores, + NetMT_FarAlienPosition, + NetMT_SpotOtherSound, +}NETMESSAGETYPE; + +/* --------------------------------------------------------------------- + Enums of game types, and local game states + ----------------------------------------------------------------------*/ +typedef enum netgame_type +{ + NGT_Individual, + NGT_CoopDeathmatch, + NGT_LastManStanding, + NGT_PredatorTag, + NGT_Coop, + NGT_AlienTag +}NETGAME_TYPE; + +typedef enum netgame_states +{ + NGS_StartUp, + NGS_Joining, + NGS_Playing, + NGS_Leaving, + NGS_EndGame, + NGS_Error_GameFull, + NGS_Error_GameStarted, + NGS_Error_HostLost, + NGS_EndGameScreen, +}NETGAME_STATES; + + +#define NUM_PC_TYPES 3 +typedef enum netgame_charactertype +{ + NGCT_Marine, + NGCT_Predator, + NGCT_Alien, + NGCT_AI_Alien, + NGCT_AI_Predalien, + NGCT_AI_Praetorian, +}NETGAME_CHARACTERTYPE; + +#define NUM_PC_SUBTYPES 9 +typedef enum netgame_specialistcharactertype +{ + NGSCT_General, + NGSCT_PulseRifle, + NGSCT_Smartgun, + NGSCT_Flamer, + NGSCT_Sadar, + NGSCT_GrenadeLauncher, + NGSCT_Minigun, + NGSCT_Frisbee, + NGSCT_Pistols, +}NETGAME_SPECIALISTCHARACTERTYPE; + +typedef enum netgame_connectiontype +{ + CONN_TCPIP, + CONN_IPX, + CONN_Serial, + CONN_Modem, + CONN_Mplayer, +}NETGAME_CONNECTIONTYPE; + +/* --------------------------------------------------------------------- + Player data structure, and game description data structure + ----------------------------------------------------------------------*/ +typedef struct netgame_playerdata +{ + DPID playerId; + char name[NET_PLAYERNAMELENGTH]; + NETGAME_CHARACTERTYPE characterType; + NETGAME_SPECIALISTCHARACTERTYPE characterSubType; + int playerFrags[NET_MAXPLAYERS]; + int aliensKilled[3]; + int deathsFromAI; + int playerScore; + int playerScoreAgainst; //points scored by killing this player + + VECTORCH lastKnownPosition; + + unsigned int timer; //used by extrapolation stuff (doesn't matter that it isn't initialised) + + unsigned char startFlag; + unsigned char playerAlive:1; + unsigned char playerHasLives:1; + + +}NETGAME_PLAYERDATA; + +typedef struct netgame_gamedata +{ + NETGAME_STATES myGameState; + NETGAME_CHARACTERTYPE myCharacterType; + NETGAME_CHARACTERTYPE myNextCharacterType; //if player is currently dead and about to become a new character + NETGAME_SPECIALISTCHARACTERTYPE myCharacterSubType; + unsigned char myStartFlag; + NETGAME_PLAYERDATA playerData[NET_MAXPLAYERS]; + int teamScores[3]; + NETGAME_TYPE gameType; + int levelNumber; + int scoreLimit; + int timeLimit; + int invulnerableTime;//in seconds after respawn + int GameTimeElapsed; + + //scoring system stuff + int characterKillValues[3]; + int baseKillValue; + BOOL useDynamicScoring; + BOOL useCharacterKillValues; + + int aiKillValues[3]; + + //for last man standing game + int LMS_AlienIndex; + int LMS_RestartTimer; + + int stateCheckTimeDelay; + + /*following timer used to prevent the game description from being sent every frame*/ + int gameDescriptionTimeDelay; + + /*sendFrequencey - how often to send messages in fixed point seconds*/ + int sendFrequency; + int sendTimer; + + //player type limits + int maxPredator; + int maxAlien; + int maxMarine; + + int maxMarineGeneral; + int maxMarinePulseRifle; + int maxMarineSmartgun; + int maxMarineFlamer; + int maxMarineSadar; + int maxMarineGrenade; + int maxMarineMinigun; + int maxMarineSmartDisc; + int maxMarinePistols; + + //weapons allowed + BOOL allowSmartgun; + BOOL allowFlamer; + BOOL allowSadar; + BOOL allowGrenadeLauncher; + BOOL allowMinigun; + BOOL allowDisc; + BOOL allowPistol; + BOOL allowPlasmaCaster; + BOOL allowSpeargun; + BOOL allowMedicomp; + BOOL allowSmartDisc; + BOOL allowPistols; + + //lives + int maxLives; + BOOL useSharedLives; + int numDeaths[3]; //deaths for each species + + //object respawn + int pointsForRespawn; + int timeForRespawn; //seconds + + int lastPointsBasedRespawn; + + + + BOOL sendDecals; + unsigned int needGameDescription :1; + + BOOL skirmishMode; //for single player multiplayer games + + int myLastScream; + + int gameSpeed; //0 to 3 , for 70,80,90 or 100 percent speed + + BOOL preDestroyLights; + BOOL disableFriendlyFire; //stops people on the same team from hurting each other + BOOL fallingDamage; + BOOL pistolInfiniteAmmo; + BOOL specialistPistols; + + //don't bother tring to synch strategies if the checksum values are different + int myStrategyCheckSum; + + unsigned int tcpip_available :1; + unsigned int ipx_available :1; + unsigned int modem_available :1; + unsigned int serial_available :1; + + NETGAME_CONNECTIONTYPE connectionType; + + unsigned int landingNoise:1; + + int joiningGameStatus; + + char customLevelName[40]; + +}NETGAME_GAMEDATA; + +/* --------------------------------------------------------------------- + Individual message structures + ----------------------------------------------------------------------*/ +#pragma pack(push,1) + +typedef struct netmessageheader +{ + unsigned char type; +}NETMESSAGEHEADER; + +typedef struct gamedescription_playerdata +{ + DPID playerId; + unsigned char characterType:2; + unsigned char characterSubType:6; + unsigned char startFlag; +}GAMEDESCRIPTION_PLAYERDATA; + +typedef struct netmessage_gamedescription +{ + GAMEDESCRIPTION_PLAYERDATA players[NET_MAXPLAYERS]; + unsigned char gameType; + unsigned char levelNumber; + int scoreLimit; + unsigned char timeLimit; + unsigned char invulnerableTime; + + unsigned char maxLives; + unsigned char numDeaths[3]; + unsigned char timeForRespawn; + int pointsForRespawn; + + short GameTimeElapsed;//in seconds + + //scoring system stuff + unsigned char characterKillValues[3]; + unsigned char baseKillValue; + unsigned int useDynamicScoring:1; + unsigned int useCharacterKillValues:1; + + unsigned char aiKillValues[3]; + + unsigned int sendDecals :1; + //weapons allowed + unsigned int allowSmartgun:1; + unsigned int allowFlamer:1; + unsigned int allowSadar:1; + unsigned int allowGrenadeLauncher:1; + unsigned int allowMinigun:1; + unsigned int allowDisc:1; + unsigned int allowPistol:1; + unsigned int allowPlasmaCaster:1; + unsigned int allowSpeargun:1; + unsigned int allowMedicomp:1; + unsigned int allowSmartDisc:1; + unsigned int allowPistols:1; + + //player type limits + unsigned int maxPredator:4; + unsigned int maxAlien:4; + unsigned int maxMarine:4; + + unsigned int maxMarineGeneral:4; + unsigned int maxMarinePulseRifle:4; + unsigned int maxMarineSmartgun:4; + unsigned int maxMarineFlamer:4; + unsigned int maxMarineSadar:4; + unsigned int maxMarineGrenade:4; + unsigned int maxMarineMinigun:4; + unsigned int maxMarineSmartDisc:4; + unsigned int maxMarinePistols:4; + + unsigned int useSharedLives:1; + + unsigned int gameSpeed:2; + + unsigned int endGame:1; + + unsigned int preDestroyLights:1; + unsigned int disableFriendlyFire:1; + unsigned int fallingDamage:1; + unsigned int pistolInfiniteAmmo:1; + unsigned int specialistPistols:1; + +}NETMESSAGE_GAMEDESCRIPTION; + +typedef struct netmessage_playerdescription +{ + unsigned char characterType: 3; + unsigned char characterSubType: 4; + unsigned char startFlag: 1; +}NETMESSAGE_PLAYERDESCRIPTION; + +typedef struct netmessage_playerstate +{ + unsigned char characterType :2; //send character type each frame (in case it changes) + unsigned char nextCharacterType :2; //if player is currently dead and about to become a new character + unsigned char characterSubType :4; + signed int xPos: 23; + signed int xOrient: 9; + signed int yPos: 23; + signed int yOrient: 9; + signed int zPos: 23; + signed int zOrient: 9; + unsigned char sequence; + unsigned char currentWeapon; + unsigned short CloakingEffectiveness; + + unsigned int Elevation : 12; + unsigned int IHaveAMuzzleFlash: 2; + unsigned int IAmFiringPrimary: 1; + unsigned int IAmFiringSecondary: 1; + unsigned int IAmAlive: 1; +// unsigned int IAmHost: 1; + unsigned int IAmOnFire: 1; + unsigned int IHaveADisk: 1; + unsigned int IHaveLifeLeft:1; + unsigned int IAmCrouched:1; + unsigned int Special:1; + + unsigned int scream:5; + + unsigned int IAmInvulnerable:1; + +#if EXTRAPOLATION_TEST + //this lot will need to be sent more efficiently + int standard_gravity:1; + int velocity_x :10; //in 10's of cm/second + int velocity_y :10; //in 10's of cm/second + int velocity_z :10; //in 10's of cm/second +#endif + unsigned int landingNoise:1; + +}NETMESSAGE_PLAYERSTATE; + +typedef struct netmessage_playerstate_minimal +{ + unsigned short Elevation : 12; + unsigned short IHaveAMuzzleFlash: 2; + unsigned short IAmFiringPrimary: 1; + unsigned short IAmFiringSecondary: 1; + unsigned short IAmAlive: 1; + unsigned char IAmOnFire: 1; + unsigned char IHaveADisk: 1; + unsigned char IHaveLifeLeft:1; + unsigned char Special:1; + + unsigned char CloakingEffectiveness; +}NETMESSAGE_PLAYERSTATE_MINIMAL; + +typedef struct netmessage_playerstate_medium +{ + NETMESSAGE_PLAYERSTATE_MINIMAL minimalMessage; + + signed int xOrient: 9; + signed int yOrient: 9; + signed int zOrient: 9; + +}NETMESSAGE_PLAYERSTATE_MEDIUM; + +typedef struct netmessage_frametimer +{ + unsigned short frame_time; +}NETMESSAGE_FRAMETIMER; + +typedef struct netmessage_playerkilled +{ + int objectId; + DPID killerId; + NETGAME_CHARACTERTYPE myType; //take character types at time of death , in case they change + NETGAME_CHARACTERTYPE killerType; + char weaponIcon; +}NETMESSAGE_PLAYERKILLED; + +typedef struct netmessage_corpsedeathanim +{ + int objectId; + int deathId; +}NETMESSAGE_CORPSEDEATHANIM; + +typedef struct netmessage_allgamescores +{ + int playerFrags[NET_MAXPLAYERS][NET_MAXPLAYERS]; + int playerScores[NET_MAXPLAYERS]; + int playerScoresAgainst[NET_MAXPLAYERS]; + int aliensKilled[NET_MAXPLAYERS][3]; + int deathsFromAI[NET_MAXPLAYERS]; + +}NETMESSAGE_ALLGAMESCORES; + +typedef struct netmessage_speciesscores +{ + int teamScores[3]; +}NETMESSAGE_SPECIESSCORES; + +typedef struct netmessage_playerscores +{ + unsigned char playerId; + int playerFrags[NET_MAXPLAYERS]; + int playerScore; + int playerScoreAgainst; + int aliensKilled[3]; + int deathsFromAI; +}NETMESSAGE_PLAYERSCORES; + +typedef struct netmessage_scorechange +{ + unsigned char killerIndex; + unsigned char victimIndex; + int fragCount; + int killerScoreFor; + int victimScoreAgainst; +}NETMESSAGE_SCORECHANGE; + +typedef struct netmessage_localRicochet +{ + signed int xPos; + signed int yPos; + signed int zPos; + signed int xDirn; + signed int yDirn; + signed int zDirn; + unsigned char type; +}NETMESSAGE_LOCALRICOCHET; + +typedef struct netmessage_lobstate +{ + signed int xPos: 23; + signed int xOrient: 9; + signed int yPos: 23; + signed int yOrient: 9; + signed int zPos: 23; + signed int zOrient: 9; + signed int objectId; + unsigned char type; + unsigned char IOType; + unsigned char subtype; + unsigned char event_flag; +}NETMESSAGE_LOBSTATE; + + +//damage message is now split into multiple parts , to avoid sending +//stuff that isn't required +typedef struct netmessage_lobdamaged_header +{ + DPID playerId; + signed int objectId; + short ammo_id:11; + + short damageProfile:1; + short multiple:1; + short sectionID:1; + short delta_seq:1; + short direction:1; +}NETMESSAGE_LOBDAMAGED_HEADER; + +typedef struct netmessage_ghosthierarchydamaged_header +{ + signed int Guid; + short ammo_id:11; + + short damageProfile:1; + short multiple:1; + short sectionID:1; + short direction:1; +}NETMESSAGE_GHOSTHIERARCHYDAMAGED_HEADER; + +typedef struct netmessage_inanimatedamaged_header +{ + char name[8]; + short ammo_id:11; + + short damageProfile:1; + short multiple:1; +}NETMESSAGE_INANIMATEDAMAGED_HEADER; + +typedef struct netmessage_damage_profile +{ + short Impact; /* nb I have copied these, as I don't think*/ + short Cutting; /* the structure will pack if I insert it directly */ + short Penetrative; + short Fire; + short Electrical; + short Acid; + + unsigned int ExplosivePower :3; + unsigned int Slicing :2; + unsigned int ProduceBlood :1; + unsigned int ForceBoom :2; + unsigned int BlowUpSections :1; + unsigned int Special :1; + unsigned int MakeExitWounds :1; +}NETMESSAGE_DAMAGE_PROFILE; + +typedef struct netmessage_damage_multiple +{ + int multiple; +}NETMESSAGE_DAMAGE_MULTIPLE; + +typedef struct netmessage_damage_section +{ + short SectionID; +}NETMESSAGE_DAMAGE_SECTION; + +typedef struct netmessage_damage_delta +{ + char Delta_Sequence; + char Delta_Sub_Sequence; +}NETMESSAGE_DAMAGE_DELTA; + +typedef struct netmessage_damage_direction +{ + int direction_x:10; + int direction_y:10; + int direction_z:10; +}NETMESSAGE_DAMAGE_DIRECTION; +//that was the last part of the local object damage stuff + + +typedef struct netmessage_lobdestroyed_request +{ + DPID playerId; + signed int objectId; +}NETMESSAGE_LOBDESTROYED_REQUEST; + +typedef struct netmessage_lobdestroyed +{ + signed int objectId; +}NETMESSAGE_LOBDESTROYED; + +typedef struct netmessage_objectpickedup +{ + char name[8]; +}NETMESSAGE_OBJECTPICKEDUP; + +typedef struct netmessage_inanimatedamaged +{ + char name[8]; + short Impact; /* nb I have copied these, as I don't think*/ + short Cutting; /* the structure will pack if I insert it directly */ + short Penetrative; + short Fire; + short Electrical; + short Acid; + + unsigned int ExplosivePower :3; + unsigned int Slicing :2; + unsigned int ProduceBlood :1; + unsigned int ForceBoom :2; + unsigned int BlowUpSections :1; + unsigned int Special :1; + unsigned int MakeExitWounds :1; + + enum AMMO_ID ammo_id; + + int multiple; + +}NETMESSAGE_INANIMATEDAMAGED; + +typedef struct netmessage_inanimatedestroyed +{ + char name[8]; +}NETMESSAGE_INANIMATEDESTROYED; + +typedef struct netmessage_losrequestbinaryswitch +{ + char name[8]; +}NETMESSAGE_LOSREQUESTBINARYSWITCH; + +typedef struct netmessage_platformliftstate +{ + char name[8]; + char state; +}NETMESSAGE_PLATFORMLIFTSTATE; + +typedef struct netmessage_requestplatformliftactivate +{ + char name[8]; +}NETMESSAGE_REQUESTPLATFORMLIFTACTIVATE; + +typedef struct netmessage_agunstate +{ + signed int xPos: 23; + signed int xOrient: 9; + signed int yPos: 23; + signed int yOrient: 9; + signed int zPos: 23; + signed int zOrient: 9; + signed int objectId; + unsigned char IAmFiring: 1; + unsigned char IAmEnabled: 1; +}NETMESSAGE_AGUNSTATE; + +/* KJL 17:45:21 20/01/98 - make decal message */ +/* currently not optimised for space! */ +#include "decal.h" +typedef struct netmessage_makedecal +{ + enum DECAL_ID DecalID; + VECTORCH Position; + VECTORCH Direction; + int ModuleIndex; +}NETMESSAGE_MAKEDECAL; + +/* KJL 11:32:52 27/04/98 - explosions */ +typedef struct netmessage_makeexplosion +{ + enum EXPLOSION_ID ExplosionID; + VECTORCH Position; +}NETMESSAGE_MAKEEXPLOSION; + +typedef struct netmessage_makeflechetteexplosion +{ + VECTORCH Position; + int Seed; +}NETMESSAGE_MAKEFLECHETTEEXPLOSION; + +typedef struct netmessage_makeplasmaexplosion +{ + enum EXPLOSION_ID ExplosionID; + VECTORCH Position; + VECTORCH FromPosition; +}NETMESSAGE_MAKEPLASMAEXPLOSION; + +/* KJL 11:13:59 20/05/98 - pred laser sights */ +typedef struct netmessage_predatorsights +{ +// THREE_LASER_DOT_DESC Dots; +// was 85 bytes + + signed int xPos: 23; + signed int xOrient: 9; + signed int yPos: 23; + signed int yOrient: 9; + signed int zPos: 23; + signed int zOrient: 9; + + DPID TargetID; + + // 16 bytes (DPID 4 bytes?) + +} NETMESSAGE_PREDATORSIGHTS; + +typedef struct netmessage_lobonfire +{ + DPID playerId; + signed int objectId; + +}NETMESSAGE_LOBONFIRE; + +typedef struct netmessage_alienaistate +{ + signed int Guid; + + signed int xPos: 23; + signed int xOrient: 9; + signed int yPos: 23; + signed int yOrient: 9; + signed int zPos: 23; + signed int zOrient: 9; + + unsigned char sequence_type; + unsigned char sub_sequence; + unsigned short sequence_length:13; //in 256ths of a second , up to ~32 seconds + + #if 0 + unsigned int Elevation : 12; + unsigned char IAmFiringPrimary: 1; + unsigned char IAmFiringSecondary: 1; + #endif + unsigned short IAmOnFire: 1; + unsigned short AlienType: 2;//alien/predalien/praetorian + + #if EXTRAPOLATION_TEST + unsigned short speed:15; + unsigned short standard_gravity:1; + #endif + +}NETMESSAGE_ALIENAISTATE; + +typedef struct netmessage_aliensequencechange +{ + signed int Guid; + + unsigned char sequence_type; + unsigned char sub_sequence; + short sequence_length; //in 256ths of a second + short tweening_time; + +}NETMESSAGE_ALIENSEQUENCECHANGE; + +typedef struct netmessage_alienaikilled +{ + signed int Guid; + + int death_code; + int death_time; + int GibbFactor; + + DPID killerId; + int killCount; + unsigned char AlienType: 2;//alien/predalien/praetorian + + char weaponIcon; +}NETMESSAGE_ALIENAIKILLED; + +typedef struct netmessage_faralienposition +{ + signed int Guid; + + unsigned int targetModuleIndex:14; + unsigned int index:15; //index is either module index , or an index in the aux locations list + unsigned int indexIsModuleIndex:1; + unsigned int alienType:2; + + + +}NETMESSAGE_FARALIENPOSITION; + +typedef struct netmessage_gibbing +{ + signed int Guid; + int gibbFactor; + int seed; +}NETMESSAGE_GIBBING; + +typedef struct netmessage_spotaliensound +{ + unsigned char soundCategory:6; + unsigned char alienType:2; + int pitch; + int vx; + int vy; + int vz; + +} NETMESSAGE_SPOTALIENSOUND; + + +typedef struct netmessage_createweapon +{ + char name[8]; + VECTORCH location; + int type; + +}NETMESSAGE_CREATEWEAPON; + +#define NUMBER_OF_FRAGMENTAL_OBJECTS (64>>3) +typedef struct netmessage_fragmentalobjectsstatus +{ + unsigned char BatchNumber; //send object states over several frames + unsigned char StatusBitfield[NUMBER_OF_FRAGMENTAL_OBJECTS]; + +}NETMESSAGE_FRAGMENTALOBJECTSSTATUS; + +#define NUMBER_OF_STRATEGIES_TO_SYNCH 16 +typedef struct netmessage_strategysynch +{ + unsigned char BatchNumber; //send object states over several frames + int strategyCheckSum; + unsigned char StatusBitfield[NUMBER_OF_STRATEGIES_TO_SYNCH>>2]; //2bits per strategy + +}NETMESSAGE_STRATEGYSYNCH; + + +//for messages that just require a player id +typedef struct netmessage_playerid +{ + DPID playerID; +}NETMESSAGE_PLAYERID; + +typedef struct netmessage_lms_restart +{ + DPID playerID; + int seed; +}NETMESSAGE_LMS_RESTART; + +typedef struct netmessage_restartgame +{ + int seed; +}NETMESSAGE_RESTARTGAME; + +//countdown to restart +typedef struct netmessage_lms_restarttimer +{ + unsigned char timer; +}NETMESSAGE_LMS_RESTARTTIMER; + +typedef struct netmessage_spotothersound +{ + enum soundindex SoundIndex; + int vx; + int vy; + int vz; + int explosion:1; + +} NETMESSAGE_SPOTOTHERSOUND; + +typedef struct multiplayer_start +{ + VECTORCH location; + EULER orientation; +}MULTIPLAYER_START; + +#pragma pack(pop) + + +/* --------------------------------------------------------------------- + Some prototypes + ----------------------------------------------------------------------*/ +extern void InitAVPNetGame(void); +extern void NetCollectMessages(void); +extern void NetSendMessages(void); +extern void EndAVPNetGame(void); +extern int PlayerIdInPlayerList(DPID Id); +//use assignnewsbname instead of addnetgameobjectid +#define AddNetGameObjectID AssignNewSBName +extern void AddNetGameObjectID(STRATEGYBLOCK *sbPtr); +extern void RecordFinalNetGameScores(void); +extern void DoNetScoresForHostDeath(NETGAME_CHARACTERTYPE myType,NETGAME_CHARACTERTYPE killerType); +extern void RemovePlayerFromGame(DPID id); +extern int EmptySlotInPlayerList(void); +extern void TeleportNetPlayerToAStartingPosition(STRATEGYBLOCK *playerSbPtr, int startOfGame); +extern int AddUpPlayerFrags(int playerId); + +extern void AddNetMsg_GameDescription(void); +extern void AddNetMsg_PlayerDescription(void); +extern void AddNetMsg_StartGame(void); +extern void AddNetMsg_PlayerState(STRATEGYBLOCK *sbPtr); +extern void AddNetMsg_PlayerState_Minimal(STRATEGYBLOCK *sbPtr,BOOL sendOrient); +extern void AddNetMsg_FrameTimer(); +extern void AddNetMsg_PlayerKilled(int objectId,DAMAGE_PROFILE* damage); +extern void AddNetMsg_PlayerDeathAnim(int deathId, int objectId); +extern void AddNetMsg_PlayerLeaving(void); +extern void AddNetMsg_AllGameScores(void); +extern void AddNetMsg_PlayerScores(int playerId); +extern void AddNetMsg_SpeciesScores(); +extern void AddNetMsg_LocalRicochet(AVP_BEHAVIOUR_TYPE behaviourType, VECTORCH *position, VECTORCH *direction); +extern void AddNetMsg_LocalObjectState(STRATEGYBLOCK *sbPtr); +extern void AddNetMsg_LocalObjectDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int sectionID,int delta_seq,int delta_sub_seq,VECTORCH* incoming); +extern void AddNetMsg_LocalObjectDestroyed(STRATEGYBLOCK *sbPtr); +extern void AddNetMsg_ObjectPickedUp(char *objectName); +extern void AddNetMsg_InanimateObjectDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple); +extern void AddNetMsg_InanimateObjectDestroyed(STRATEGYBLOCK *sbPtr); +extern void AddNetMsg_LOSRequestBinarySwitch(STRATEGYBLOCK *sbPtr); +extern void AddNetMsg_PlatformLiftState(STRATEGYBLOCK *sbPtr); +extern void AddNetMsg_RequestPlatformLiftActivate(STRATEGYBLOCK *sbPtr); +extern void AddNetMsg_RequestPlatformLiftReverse(STRATEGYBLOCK *sbPtr); +extern void AddNetMsg_PlayerAutoGunState(STRATEGYBLOCK *sbPtr); +extern void AddNetMsg_EndGame(void); +extern void AddNetMsg_MakeDecal(enum DECAL_ID decalID, VECTORCH *normalPtr, VECTORCH *positionPtr, int moduleIndex); +extern void AddNetMsg_ChatBroadcast(char *string,BOOL same_species_only); +extern void AddNetMsg_MakeExplosion(VECTORCH *positionPtr, enum EXPLOSION_ID explosionID); +extern void AddNetMsg_MakeFlechetteExplosion(VECTORCH *positionPtr, int seed); +extern void AddNetMsg_MakePlasmaExplosion(VECTORCH *positionPtr, VECTORCH *fromPositionPtr, enum EXPLOSION_ID explosionID); +extern void AddNetMsg_PredatorLaserSights(VECTORCH *positionPtr, VECTORCH *normalPtr, DISPLAYBLOCK *dispPtr); +extern void AddNetMsg_LocalObjectOnFire(STRATEGYBLOCK *sbPtr); +extern void AddNetMsg_RestartNetworkGame(int seed); +extern void AddNetMsg_FragmentalObjectsStatus(void); +extern void AddNetMsg_StrategySynch(void); +extern void AddNetMsg_AlienAIState(STRATEGYBLOCK *sbPtr); +extern void AddNetMsg_AlienAISeqChange(STRATEGYBLOCK *sbPtr,int sequence_type,int sub_sequence,int sequence_length,int tweening_time); +extern void AddNetMsg_AlienAIKilled(STRATEGYBLOCK *sbPtr,int death_code,int death_time, int GibbFactor,DAMAGE_PROFILE* damage); +extern void AddNetMsg_FarAlienPosition(STRATEGYBLOCK* sbPtr,int targetModuleIndex,int index,BOOL indexIsModuleIndex); +extern void AddNetMsg_GhostHierarchyDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int sectionID,VECTORCH* incoming); +extern void AddNetMsg_SpotAlienSound(int soundCategory,int alienType,int pitch,VECTORCH *position); +extern void AddNetMsg_LocalObjectDestroyed_Request(STRATEGYBLOCK *sbPtr); +extern void AddNetMsg_ScoreChange(int killerIndex,int victimIndex); + +extern void AddNetMsg_PlayerID(DPID playerID,unsigned char message); +extern void AddNetMsg_LastManStanding_RestartTimer(unsigned char time); +extern void AddNetMsg_LastManStanding_Restart(DPID alienID,int seed); + +extern void AddNetMsg_CreateWeapon(char* objectName,int type,VECTORCH* location); + +extern void AddNetMsg_RespawnPickups(); + +extern void AddNetMsg_Gibbing(STRATEGYBLOCK* sbPtr,int gibbFactor,int seed); +extern void AddNetMsg_SpotOtherSound(enum soundindex SoundIndex,VECTORCH *position,int explosion); + +extern void TransmitEndOfGameNetMsg(void); +extern void TransmitPlayerLeavingNetMsg(void); +extern void TransmitStartGameNetMsg(void); + +extern void RestartNetworkGame(int seed); + +extern void DeallocatePlayersMirrorImage(); + +void InitNetLog(void); +void LogNetInfo(char *msg); + +extern BOOL AreThereAnyLivesLeft(); + +extern void DoMultiplayerSpecificHud(); + +extern void GetNextMultiplayerObservedPlayer(); +extern void TurnOffMultiplayerObserveMode(); +extern void CheckStateOfObservedPlayer(); + + +/* --------------------------------------------------------------------- + Some global references + ----------------------------------------------------------------------*/ +extern NETGAME_GAMEDATA netGameData; +extern int peerStartUpIntegrities[]; + +extern int numMarineStartPos; +extern int numAlienStartPos; +extern int numPredatorStartPos; + +extern MULTIPLAYER_START* marineStartPositions; +extern MULTIPLAYER_START* alienStartPositions; +extern MULTIPLAYER_START* predatorStartPositions; + +#define LobbiedGame_NotLobbied 0 +#define LobbiedGame_Server 1 +#define LobbiedGame_Client 2 +extern int LobbiedGame; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/3dc/avp/win95/Projload.cpp b/3dc/avp/win95/Projload.cpp new file mode 100644 index 0000000..783027b --- /dev/null +++ b/3dc/avp/win95/Projload.cpp @@ -0,0 +1,3521 @@ +#define DB_LEVEL 2 + +#include "3dc.h" +#include "inline.h" +#include "module.h" + +#include + +#include "list_tem.hpp" +#include "chnkload.hpp" +#include "projload.hpp" +#include "gamedef.h" +#include "shpchunk.hpp" +#include "envchunk.hpp" +#include "obchunk.hpp" +#include "chunkpal.hpp" +#include "bmpnames.hpp" +#include "chnktexi.h" +#include "strachnk.hpp" +#include "animchnk.hpp" +#include "ltchunk.hpp" +#include "avpchunk.hpp" +#include "pathchnk.hpp" + +#include "objsetup.hpp" +#include "npcsetup.h" +#include "sprchunk.hpp" +#include "pcmenus.h" +#include +#include "wpchunk.hpp" +#include "hierchnk.hpp" +#include "animobs.hpp" +#include "sequnces.h" +#include "fragchnk.hpp" +#include "hierplace.hpp" + +#include "pfarlocs.h" +#include "progress_bar.h" +#include "stratdef.h" +#include "equipmnt.h" +#include "bh_ais.h" +#include "bh_types.h" +#include "bh_plachier.h" +#include "bh_marin.h" +#include "pvisible.h" +#include "psndplat.h" +#include "jsndsup.h" +#include "AvpReg.hpp" +#include "ffstdio.h" + +#include "decal.h" +#include "mempool.h" +#include "db.h" +#include "pldnet.h" + +extern "C" { +#include "3dc.h" +#include "inventry.h" + +extern int VideoMode; +extern int ScanDrawMode; +extern int ZBufferMode; +extern unsigned char *PaletteRemapTable; +extern unsigned char **PaletteShadingTableArray; +extern int cosine[]; +extern int HWAccel; +#define remap_table_size (1 << (remap_table_rgb_bits * 3)) +extern VECTORCH PlayerStartLocation; +extern MATRIXCH PlayerStartMat; + +extern FARENTRYPOINTSHEADER *FALLP_EntryPoints; + +extern RIFFHANDLE env_rif; + +extern void NewOnScreenMessage(char *messagePtr); + +extern BOOL KeepMainRifFile; + +BOOL LevelHasStars; + +}; + +// these are to link with chnkimag.cpp +const char * ToolsTex_Directory = "\\\\Kate\\Kate Share\\avp\\ToolsTex\\"; +const char * GenTex_Directory = "\\\\Kate\\Kate Share\\avp\\GenG-Tex\\"; +const char * SubShps_Directory = "SubShps\\All\\"; +// const char * GenTex_Directory = 0; +const char * FixTex_Directory = "\\\\Kate\\Kate Share\\avp\\Fix-Tex\\"; +const char * GameTex_Directory = "\\\\Kate\\Kate Share\\avp\\game-tex\\"; +// these link with pcmenus.cpp +const char * GenTex4bit_Directory = "\\\\Kate\\Kate Share\\avp\\G4bitTex\\"; +const char * GenTex8bit_Directory = "\\\\Kate\\Kate Share\\avp\\GenG-Tex\\"; +const char * GenTex75pc_Directory = "\\\\Kate\\Kate Share\\avp\\Gen34Tex\\"; +const char * GenTex50pc_Directory = "\\\\Kate\\Kate Share\\avp\\Gen12Tex\\"; + +// new directories for new-style graphics - to be determined properly +char const * FirstTex_Directory = "Graphics"; // currently relative to cwd +char const * SecondTex_Directory = 0; // will be the src safe shadow for development builds + //used for cd graphics directory in final version + +char* Rif_Sound_Directory=0;//set for the main level rif + +static char * light_set_name = "NORMALLT"; + +static Object_Chunk * * o_chunk_array; +static int * aimodule_indeces; //array parallel to o_chunk_array + +extern void setup_placed_hierarchies(Environment_Data_Chunk * envd); +void setup_preplaced_decals(File_Chunk* fc,Environment_Data_Chunk* edc); +///////////////////////////////////////// +// Functions which operate on RIFFHANDLEs +///////////////////////////////////////// + +void setup_start_position(RIFFHANDLE h) +{ + Chunk * pChunk = h->envd->lookup_single_child("SPECLOBJ"); + AVP_Player_Start_Chunk* start_chunk=0; + if(pChunk) + { + List start_list; + ((Chunk_With_Children*)pChunk)->lookup_child("AVPSTART",start_list); + + if(start_list.size()) + start_chunk=(AVP_Player_Start_Chunk*)start_list.first_entry(); + + } + if(start_chunk) + { + PlayerStartLocation.vx=start_chunk->location.x*local_scale; + PlayerStartLocation.vy=start_chunk->location.y*local_scale; + PlayerStartLocation.vz=start_chunk->location.z*local_scale; + + PlayerStartMat.mat11=start_chunk->orientation.mat11; + PlayerStartMat.mat12=start_chunk->orientation.mat12; + PlayerStartMat.mat13=start_chunk->orientation.mat13; + PlayerStartMat.mat21=start_chunk->orientation.mat21; + PlayerStartMat.mat22=start_chunk->orientation.mat22; + PlayerStartMat.mat23=start_chunk->orientation.mat23; + PlayerStartMat.mat31=start_chunk->orientation.mat31; + PlayerStartMat.mat32=start_chunk->orientation.mat32; + PlayerStartMat.mat33=start_chunk->orientation.mat33; + } + else + { + PlayerStartLocation.vx=0; + PlayerStartLocation.vy=0; + PlayerStartLocation.vz=0; + + PlayerStartMat.mat11=65536; + PlayerStartMat.mat12=0; + PlayerStartMat.mat13=0; + PlayerStartMat.mat21=0; + PlayerStartMat.mat22=65536; + PlayerStartMat.mat23=0; + PlayerStartMat.mat31=0; + PlayerStartMat.mat32=0; + PlayerStartMat.mat33=65536; + } +} + +void setup_paths(RIFFHANDLE h) +{ + PathArraySize=0; + PathArray=0; + + Chunk * pChunk = h->envd->lookup_single_child("SPECLOBJ"); + if(!pChunk) return; + + List pathlist; + ((Chunk_With_Children*)pChunk)->lookup_child("AVPPATH2",pathlist); + + if(!pathlist.size()) return; + + //find the highest path index + for(LIF plif(&pathlist);!plif.done();plif.next()) + { + AVP_Path_Chunk* apc=(AVP_Path_Chunk*) plif(); + PathArraySize=max(PathArraySize,apc->PathID+1); + } + + PathArray=(PATHHEADER*)PoolAllocateMem(sizeof(PATHHEADER)*PathArraySize); + for(int i=0;iPathLength) continue; + + PATHHEADER* path=&PathArray[apc->PathID]; + + int length=apc->PathLength; + if(apc->flags & PathFlag_BackAndForth) + { + length=max(length,(length-1)*2); + } + + path->modules_in_path=(AIMODULE**)PoolAllocateMem(sizeof(AIMODULE*)*length); + + for(i=0;iPathLength;i++) + { + Object_Chunk* path_object=h->fc->get_object_by_index(apc->Path[i].module_index); + if(!path_object)continue; + if(path_object->program_object_index==-1) continue; + AIMODULE* path_module=&AIModuleArray[aimodule_indeces[path_object->program_object_index]]; + + //if this ai module is the same as the previous one in the path , ignore it + if(path->path_length) + { + if(path_module==path->modules_in_path[path->path_length-1])continue; + } + + path->modules_in_path[path->path_length]=path_module; + path->path_length++; + } + + if(apc->flags & PathFlag_BackAndForth) + { + for(i=path->path_length-2;i>0;i--) + { + path->modules_in_path[path->path_length]=path->modules_in_path[i]; + path->path_length++; + } + } + } + +} + +extern "C" +{ +extern int SkyColour_R; +extern int SkyColour_G; +extern int SkyColour_B; +}; + +void set_environment_properties(Environment_Data_Chunk* edc) +{ + GLOBALASSERT(edc); + AVP_Environment_Settings_Chunk* env_set=GetAVPEnvironmentSettings(edc); + GLOBALASSERT(env_set); + +//set sky colour + SkyColour_R=env_set->settings->sky_colour_red; + SkyColour_G=env_set->settings->sky_colour_green; + SkyColour_B=env_set->settings->sky_colour_blue; + + LevelHasStars=env_set->settings->stars_in_sky; + +//get starting equipment data + StartingEquipment.marine_jetpack=env_set->settings->marine_jetpack; + + StartingEquipment.predator_pistol=env_set->settings->predator_pistol; + StartingEquipment.predator_plasmacaster=env_set->settings->predator_plasmacaster; + StartingEquipment.predator_disc=env_set->settings->predator_disc; + StartingEquipment.predator_medicomp=env_set->settings->predator_medicomp; + StartingEquipment.predator_grappling_hook=env_set->settings->predator_grappling_hook; + StartingEquipment.predator_num_spears=env_set->settings->predator_num_spears; + + if(AvP.Network != I_No_Network) + { + StartingEquipment.predator_pistol=netGameData.allowPistol; + StartingEquipment.predator_plasmacaster=netGameData.allowPlasmaCaster; + StartingEquipment.predator_disc=netGameData.allowDisc; + StartingEquipment.predator_medicomp=netGameData.allowMedicomp; + + if(!netGameData.allowSpeargun) + { + StartingEquipment.predator_num_spears=0; + } + } + +} + + + +int ConvertObjectIndexToPathIndex(int path_index,int object_index) +{ + if(path_index<0 || path_index>=PathArraySize) + { + return -1; //path doesn't exist + } + + Object_Chunk* oc=env_rif->fc->get_object_by_index(object_index); + if(!oc) + { + return -1; //object doesn't exist + } + int module_index=oc->program_object_index; + if(module_index==-1) + { + return -1; //object isn't a module + } + int aimodule_index=aimodule_indeces[module_index]; + + + PATHHEADER* path=&PathArray[path_index]; + + for(int i=0;ipath_length;i++) + { + if(path->modules_in_path[i]==&AIModuleArray[aimodule_index]) + { + return i; //found the module in the path + } + } + + return -1; //module isn't in path + +} + + +void pre_process_shape (RIFFHANDLE, ChunkShape & cs, Chunk_With_Children * shape_chunk, int /*flags*/) +{ + Shape_Merge_Data_Chunk * smdc = 0; + + Chunk * pChunk = shape_chunk->lookup_single_child("SHPMRGDT"); + if (pChunk) + { + smdc = (Shape_Merge_Data_Chunk *) pChunk; + } + + if (smdc) + merge_polygons_in_chunkshape (cs,smdc); +} + +void set_local_scale(RIFFHANDLE h, int /*flags*/) +{ + local_scale = GlobalScale; + + if (h->envd) + { + Chunk * pChunk = h->envd->lookup_single_child ("ENVSDSCL"); + if (pChunk) + local_scale *= ((Environment_Scale_Chunk *)pChunk)->scale; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////// +//placed hierarchy stuff + +extern LOADED_SOUND const * GetSoundFromSoundPath(char* wavname); + + +extern void add_placed_hierarchy(Placed_Hierarchy_Chunk* phc,const char* fname,const char* hname); + +struct LoadedPlacedHierarchy +{ + void load_rif(); + void unload(); + + const char* file_name; + const char* hier_name; + RIFFHANDLE placed_rif; +}; + +#define NumPlacedHierarchy 3 +LoadedPlacedHierarchy PlacedHierarchyArray[NumPlacedHierarchy]= +{ + "dropship","dropship",INVALID_RIFFHANDLE, + "pred ship fury","pred ship fury",INVALID_RIFFHANDLE, + "pred ship ob","pred ship ob",INVALID_RIFFHANDLE, +}; + + +void LoadedPlacedHierarchy::load_rif() +{ + if(placed_rif!=INVALID_RIFFHANDLE) return; + char file_path[100]; + sprintf(file_path,"avp_huds\\%s.rif",file_name); + + placed_rif=avp_load_rif_non_env(file_path); + if(placed_rif!=INVALID_RIFFHANDLE) + { + #if MaxImageGroups>1 + SetCurrentImageGroup(2); // load into environment image group + #endif + copy_rif_data(placed_rif,CCF_IMAGEGROUPSET + CCF_LOAD_AS_HIERARCHY_IF_EXISTS+CCF_DONT_INITIALISE_TEXTURES,0,0); + unload_rif(placed_rif); + } +} +void LoadedPlacedHierarchy::unload() +{ + if(placed_rif!=INVALID_RIFFHANDLE) + { + avp_undo_rif_load(placed_rif); // destroys copied shapes + } + placed_rif=INVALID_RIFFHANDLE; +} + + + +void setup_placed_hierarchies(Environment_Data_Chunk * envd) +{ + GLOBALASSERT(envd); + Special_Objects_Chunk* soc=(Special_Objects_Chunk*)envd->lookup_single_child("SPECLOBJ"); + if(!soc) return; + + List chlist; + soc->lookup_child("PLACHIER",chlist); + + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + Placed_Hierarchy_Chunk* phc=(Placed_Hierarchy_Chunk*)chlif(); + Placed_Hierarchy_Data_Chunk* phdc=phc->get_data_chunk(); + + if(phdc->hierarchy_index<0 || phdc->hierarchy_index>=NumPlacedHierarchy) continue; + + //need to store the current sound directory , since it will get altered when loading the + //hierarchy rif file. + char* Temp_Rif_Sound_Directory = Rif_Sound_Directory; + + PlacedHierarchyArray[phdc->hierarchy_index].load_rif(); + + //restore the sound directory + Rif_Sound_Directory = Temp_Rif_Sound_Directory; + + add_placed_hierarchy(phc,PlacedHierarchyArray[phdc->hierarchy_index].file_name,PlacedHierarchyArray[phdc->hierarchy_index].hier_name); + + } +} + +void unload_placed_hierarchies() +{ + for(int i=0;i Global_Hierarchy_Library; +List Global_Hierarchy_Store::time_list; + +Global_Hierarchy_Store::Global_Hierarchy_Store (RIFFHANDLE h) +{ + GLOBALASSERT (h->envd); + + Chunk * pChunk = h->envd->lookup_single_child ("RIFFNAME"); + + RIF_Name_Chunk * rnc = (RIF_Name_Chunk *) pChunk; + + GLOBALASSERT (rnc); + + riffname = (char*) PoolAllocateMem(strlen (rnc->rif_name)+1); + strcpy (riffname, rnc->rif_name); + + rif_hand=h; + + sound_array=0; + + //load the sounds used by this file + List chlist; + h->fc->lookup_child("INDSOUND",chlist); + + //find the highest sound index + int max_index=-1; + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + Indexed_Sound_Chunk* isc=(Indexed_Sound_Chunk*)chlif(); + max_index=max(max_index,isc->index); + } + //now create a large enough array , and fill it in + num_sounds=max_index+1; + if(max_index>=0) + { + //find this rif's sound directory + Sound_Directory_Chunk* dir_chunk=(Sound_Directory_Chunk*) h->envd->lookup_single_child("SOUNDDIR"); + char wavname[200]; + + VECTORCH ZeroVector={0,0,0}; + + sound_array=(HIERARCHY_SOUND*) PoolAllocateMem(sizeof(HIERARCHY_SOUND)*(max_index+1)); + for(int i=0;i<=max_index;i++) + { + sound_array[i].sound_loaded=0; + } + + for(chlif.restart();!chlif.done();chlif.next()) + { + Indexed_Sound_Chunk* isc=(Indexed_Sound_Chunk*)chlif(); + int index=isc->index; + + GLOBALASSERT(sound_array[index].sound_loaded==0); + + sound_array[index].s3d.inner_range=isc->inner_range*local_scale; + sound_array[index].s3d.outer_range=isc->outer_range*local_scale; + sound_array[index].s3d.velocity=ZeroVector; + sound_array[index].s3d.position=ZeroVector; + + sound_array[index].pitch=isc->pitch; + sound_array[index].volume=isc->max_volume; + if(dir_chunk) + { + sprintf(wavname,"%s\\%s",dir_chunk->directory,isc->wav_name); + sound_array[index].sound_loaded=GetSound(wavname); + } + else + { + sound_array[index].sound_loaded=GetSound(isc->wav_name); + } + if(sound_array[index].sound_loaded) + { + sound_array[index].sound_index=(SOUNDINDEX)sound_array[index].sound_loaded->sound_num; + } + + + } + } + + + +} + + +Global_Hierarchy_Store::~Global_Hierarchy_Store() +{ + #if !USE_LEVEL_MEMORY_POOL + if (riffname) + { + DeallocateMem(riffname); + } + + + while (hierarchy_list.size()) + { + Hierarchy_Descriptor * hd = hierarchy_list.first_entry(); + + + if (hd->hierarchy_name) + DeallocateMem (hd->hierarchy_name); + + if (hd->hierarchy_root) + delete_section (hd->hierarchy_root); + + DeallocateMem (hd); + + hierarchy_list.delete_first_entry(); + } + + while(alternate_shape_set_list.size()) + { + Hierarchy_Alternate_Shape_Set* hass=alternate_shape_set_list.first_entry(); + HIERARCHY_SHAPE_REPLACEMENT* hsr=hass->replaced_shapes; + + while(hsr->replaced_section_name) + { + DeallocateMem (hsr->replaced_section_name); + hsr++; + } + + DeallocateMem (hass->replaced_shapes); + DeallocateMem (hass->shape_set_name); + DeallocateMem (hass); + alternate_shape_set_list.delete_first_entry(); + } + + if(shape_collections) + { + for(int i=0;i & osnp_lst, Object_Hierarchy_Chunk * ohc) +{ + List ohcl = ohc->list_h_children(); + + GLOBALASSERT (ohcl.size() == 1); + + + //check to see if this hierarchy has any sequences + { + Object_Hierarchy_Chunk* ohc=(Object_Hierarchy_Chunk*) ohcl.first_entry(); + if(!Get_Object_Animation_All_Sequence_Chunk(ohc)) + { + List seql; + Chunk * pChunk = ohc->lookup_single_child ("OBANSEQS"); + if (pChunk) + { + ((Object_Animation_Sequences_Chunk *)pChunk)->list_sequences(&seql); + } + if(!seql.size()) return; + } + } + + + Hierarchy_Descriptor * hd =(Hierarchy_Descriptor*) PoolAllocateMem(sizeof(Hierarchy_Descriptor)); + + Object_Hierarchy_Name_Chunk * ohnc = ohc->get_name(); + if (ohnc) + { + hd->hierarchy_name = (char*)PoolAllocateMem(strlen (ohnc->hierarchy_name) + 1); + strcpy (hd->hierarchy_name, ohnc->hierarchy_name); + } + else + { // throw back from old system, no new hierarchies should be created with no name + hd->hierarchy_name = (char*) PoolAllocateMem(strlen ("Template") + 1); + strcpy (hd->hierarchy_name, "Template"); + } + + + build_time_list(ohcl.first_entry()); + hd->hierarchy_root = build_hierarchy (ohcl.first_entry(),hd->hierarchy_name); + while(time_list.size()) + { + delete time_list.first_entry(); + time_list.delete_first_entry(); + } + + hd->hierarchy_root->flags |= section_is_master_root; + + + hierarchy_list.add_entry (hd); + + Preprocess_HModel (hd->hierarchy_root ,riffname); +} + +static List random_marine_texturings; +static List random_civilian_texturings; + +void Global_Hierarchy_Store::setup_alternate_shape_sets(List & osnp_lst, File_Chunk * fc) +{ + List chlist; + fc->lookup_child("OBHALTSH",chlist); + + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + Object_Hierarchy_Alternate_Shape_Set_Chunk* ohassc=(Object_Hierarchy_Alternate_Shape_Set_Chunk*) chlif(); + + Hierarchy_Alternate_Shape_Set* hass=(Hierarchy_Alternate_Shape_Set*) PoolAllocateMem(sizeof(Hierarchy_Alternate_Shape_Set)); + + hass->shape_set_name=(char*) PoolAllocateMem(strlen(ohassc->Shape_Set_Name)+1); + hass->index=ohassc->Shape_Set_Num; + hass->num_replaced_shapes=ohassc->Replaced_Shape_List.size(); + strcpy(hass->shape_set_name,ohassc->Shape_Set_Name); + + hass->flags=ohassc->flags; + + hass->replaced_shapes=(HIERARCHY_SHAPE_REPLACEMENT*) PoolAllocateMem(sizeof(HIERARCHY_SHAPE_REPLACEMENT)*(ohassc->Replaced_Shape_List.size()+1)); + + HIERARCHY_SHAPE_REPLACEMENT* hsr=hass->replaced_shapes; + for(LIF rlif(&ohassc->Replaced_Shape_List);!rlif.done();rlif.next(),hsr++) + { + hsr->replaced_section_name=(char*) PoolAllocateMem(strlen(rlif()->old_object_name)+1); + strcpy(hsr->replaced_section_name,rlif()->old_object_name); + + hsr->replacement_id = 0; + + //find the shape num for the new shape + for(LIF olif(&osnp_lst);!olif.done();olif.next()) + { + if(!strcmp(olif()->ob->object_data.o_name,rlif()->new_object_name)) + { + hsr->replacement_shape=mainshapelist[olif()->sh_num]; + hsr->replacement_shape_index=olif()->sh_num; + break; + } + } + if(olif.done()) + { + //alternate shape set removes this object + hsr->replacement_shape=0; + hsr->replacement_shape_index=0; + } + + } + hsr->replaced_section_name=0; + hsr->replacement_shape=0; + + alternate_shape_set_list.add_entry(hass); + } + + + num_shape_collections=0; + shape_collections=0; + + //now set up the shape set collections + List_Hierarchy_Shape_Set_Collection_Chunk(fc,chlist); + + //find the highest index + int max_index=-1; + for(chlif.restart();!chlif.done();chlif.next()) + { + Hierarchy_Shape_Set_Collection_Chunk* coll=(Hierarchy_Shape_Set_Collection_Chunk*)chlif(); + max_index=max(max_index,coll->Set_Collection_Num); + } + + if(max_index==-1) return; + + //allocate array for shape sets and initialise to zero + num_shape_collections=max_index+1; + shape_collections=(HIERARCHY_VARIANT_DATA*) PoolAllocateMem(sizeof(HIERARCHY_VARIANT_DATA)*num_shape_collections); + for(int i=0;i* ran_list=0; + if(!_stricmp(riffname,"hnpcmarine")) + { + if(random_marine_texturings.size()) ran_list=&random_marine_texturings; + } + else if(!_stricmp(riffname,"hnpc_civvie")) + { + if(random_civilian_texturings.size()) ran_list=&random_civilian_texturings; + } + + if(!ran_list || ran_list->contains(1)) + random_shape_colls.add_entry(1); + + //now go through the list of shape set collections again + Hierarchy_Alternate_Shape_Set* found_sets[20]; + int num_found_sets; + int num_shapes_to_replace; + LIF alt_lif(&alternate_shape_set_list); + for(chlif.restart();!chlif.done();chlif.next()) + { + Hierarchy_Shape_Set_Collection_Chunk* coll=(Hierarchy_Shape_Set_Collection_Chunk*)chlif(); + GLOBALASSERT(coll->Index_List.size()<20); + //locate the sets that this collections is using + num_found_sets=0; + num_shapes_to_replace=0; + int combined_flags=0; + + for(LIF ind_lif(&coll->Index_List);!ind_lif.done();ind_lif.next()) + { + for(alt_lif.restart();!alt_lif.done();alt_lif.next()) + { + if(ind_lif()==alt_lif()->index) + { + found_sets[num_found_sets]=alt_lif(); + num_found_sets++; + num_shapes_to_replace+=alt_lif()->num_replaced_shapes; + combined_flags|=alt_lif()->flags; + break; + } + } + } + + if(num_found_sets) + { + HIERARCHY_SHAPE_REPLACEMENT* hsr=(HIERARCHY_SHAPE_REPLACEMENT*) PoolAllocateMem(sizeof(HIERARCHY_SHAPE_REPLACEMENT)*(num_shapes_to_replace+1)); + shape_collections[coll->Set_Collection_Num].replacements=(struct hierarchy_shape_replacement*)hsr; + + if(combined_flags & Avp_ShapeSet_Flag_Female) + shape_collections[coll->Set_Collection_Num].female=1; + + shape_collections[coll->Set_Collection_Num].voice=coll->TypeIndex; + + + int pos=0; + for(i=0;inum_replaced_shapes;j++) + { + //just take a straight copy since the shape set collections won't deallocate the names + hsr[pos]=hass->replaced_shapes[j]; + hsr[pos].replacement_id = coll->Set_Collection_Num; + pos++; + } + + } + hsr[pos].replaced_section_name=0; + hsr[pos].replacement_shape=0; + } + + //see if this collection can appear randomly + if(!ran_list || ran_list->contains(coll->Set_Collection_Num)) + { + random_shape_colls.add_entry(coll->Set_Collection_Num); + } + } +} + +void Global_Hierarchy_Store::delete_section(SECTION * s2d) +{ + #if !USE_LEVEL_MEMORY_POOL + SECTION ** csp = &s2d->Children[0]; + if (csp) + { + while (*csp) + { + delete_section (*csp); + csp ++; + } + DeallocateMem ((void *)s2d->Children); + + } + + for (int i=0; inum_sequences; i++) + { + DeallocateMem (s2d->sequence_array[i].first_frame); + } + + DeallocateMem ((void *)s2d->sequence_array); + + if (s2d->Section_Name) + { + DeallocateMem ((void *)s2d->Section_Name); + } + + if (s2d->ShapeName) + { + DeallocateMem ((void *)s2d->ShapeName); + } + + DeallocateMem ((void *)s2d); + #endif +} + + +SECTION * Global_Hierarchy_Store::build_hierarchy (Object_Hierarchy_Chunk * ohc,char* hierarchy_name) +{ + // iterative bit + // should be called with the root node + // containing an object + + + + + Object_Hierarchy_Data_Chunk * ohdc = ohc->get_data(); + + GLOBALASSERT (ohdc); + GLOBALASSERT (ohdc->ob_name); + + + // make a section + + SECTION * currsection = (SECTION *)PoolAllocateMem (sizeof (SECTION)); + + currsection->flags = 0; + currsection->ShapeName = 0; + currsection->Hierarchy_Name=hierarchy_name; + currsection->Rif_Name=riffname; + + currsection->Section_Name = (char *)PoolAllocateMem (strlen (ohdc->ob_name) + 1); + strcpy (currsection->Section_Name, ohdc->ob_name); + + if (ohdc->object) + { + GLOBALASSERT(ohdc->object->program_object_index!=-1); + currsection->ShapeNum = ohdc->object->program_object_index; + currsection->Shape = mainshapelist[ohdc->object->program_object_index]; + } + else + { + currsection->ShapeNum = -1; + currsection->Shape = 0; + } + + Object_Animation_All_Sequence_Chunk* all_seq=Get_Object_Animation_All_Sequence_Chunk(ohc); + if(all_seq) + { + currsection->num_sequences=all_seq->num_sequences; + currsection->sequence_array = 0; + if(all_seq->num_sequences) + { + currsection->sequence_array = (SEQUENCE *)PoolAllocateMem (sizeof(SEQUENCE) * all_seq->num_sequences); + SEQUENCE * seqa_p = currsection->sequence_array; + + for(int i=0;inum_sequences;i++) + { + KEYFRAME_DATA ** next_frame_ptr=&seqa_p->first_frame; + KEYFRAME_DATA * delta_frame=0; + + Object_Animation_Sequence* seq=&all_seq->sequences[i]; + + seqa_p->sequence_id = GetSequenceID (seq->sequence_number, seq->sub_sequence_number); + seqa_p->Time = (seq->sequence_time*ONE_FIXED)/1000; + + + KEYFRAME_DATA * kfd=0; + + + for(int frame_no=0;frame_nonum_frames;) + { + Object_Animation_Frame* frame=&seq->frames[frame_no]; + + int flags=0; + HIERARCHY_SOUND* sound=0; + + //see if there are any flags or sounds on this frame + flags=frame->flags & HierarchyFrame_FlagMask; + int sound_index=frame->get_sound_index(); + if(sound_index>0 && sound_indexframe_has_extended_data=1; + kfd_extended->sound=sound; + kfd_extended->flags=flags; + + + } + else + { + //use standard keyframe + kfd =(KEYFRAME_DATA*) PoolAllocateMem(sizeof(KEYFRAME_DATA)); + + kfd->frame_has_extended_data=0; + } + + kfd->last_frame=0; //if this is in fact the last frame , then this will be changed later + + //set up previous frames next pointer + *next_frame_ptr=kfd; + next_frame_ptr=&kfd->Next_Frame; + + + if(frame->flags & HierarchyFrameFlag_DeltaFrame) + { + GLOBALASSERT(delta_frame==0); //should only be one frame with this flag + delta_frame=kfd; + } + + VECTORCH offset; + + offset.vx = frame->transform.x * local_scale; + offset.vy = frame->transform.y * local_scale; + offset.vz = frame->transform.z * local_scale; + + SetKeyFrameOffset(kfd,&offset); + + QUAT q; + + q.quatx = (int) -(frame->orientation.x*ONE_FIXED); + q.quaty = (int) -(frame->orientation.y*ONE_FIXED); + q.quatz = (int) -(frame->orientation.z*ONE_FIXED); + q.quatw = (int) (frame->orientation.w*ONE_FIXED); + + CopyIntQuatToShort(&q,&kfd->QOrient); + + + int this_frame_no = frame->at_frame_no; + + + + frame_no++; + + if (frame_nonum_frames) + { + //calculate sequence length , making sure it doesn't overflow an unsigned short + kfd->Sequence_Length =(unsigned short) min(seq->frames[frame_no].at_frame_no - this_frame_no,65535); + } + else + { + kfd->Sequence_Length =(unsigned short) min(65536 - this_frame_no,65535); + } + + } + //sort out some settings for the last frame + kfd->last_frame=1; + if(kfd->Sequence_Length<=6) + { + //this sequence doesn't loop + kfd->Next_Frame=kfd; + } + else + { + //this sequence loops + kfd->Next_Frame=seqa_p->first_frame; + } + + seqa_p->last_frame = kfd; + + + + if(delta_frame) + { + //this sequence is a delta sequence , so convert all frames to deltas relative + //to delta_frame + + QUAT inverse_delta; + + CopyShortQuatToInt(&delta_frame->QOrient,&inverse_delta); + + VECTORCH inverse_offset; + GetKeyFrameOffset(delta_frame,&inverse_offset); + + inverse_delta.quatx = -inverse_delta.quatx; + inverse_delta.quaty = -inverse_delta.quaty; + inverse_delta.quatz = -inverse_delta.quatz; + + inverse_offset.vx = -inverse_offset.vx; + inverse_offset.vy = -inverse_offset.vy; + inverse_offset.vz = -inverse_offset.vz; + + kfd = seqa_p->first_frame; + + while (1) + { + // do deltas + QUAT q; + + CopyShortQuatToInt(&kfd->QOrient,&q); + + MulQuat (&q, &inverse_delta, &q); + CopyIntQuatToShort(&q,&kfd->QOrient); + + VECTORCH offset; + GetKeyFrameOffset(kfd,&offset); + + offset.vx += inverse_offset.vx; + offset.vy += inverse_offset.vy; + offset.vz += inverse_offset.vz; + + SetKeyFrameOffset(kfd,&offset); + + if(kfd->last_frame) break; + + kfd = kfd->Next_Frame; + } + + + } + + + seqa_p ++; + } + + } + } + else + { + List seql; + + Chunk * pChunk = ohc->lookup_single_child ("OBANSEQS"); + + if (pChunk) + { + ((Object_Animation_Sequences_Chunk *)pChunk)->list_sequences(&seql); + } + + currsection->num_sequences = seql.size(); + currsection->sequence_array = 0; + + // fill in sequences + + + if (seql.size()) + { + currsection->sequence_array = (SEQUENCE *)PoolAllocateMem (sizeof(SEQUENCE) * seql.size()); + SEQUENCE * seqa_p = currsection->sequence_array; + + for (LIF seqi(&seql); !seqi.done(); seqi.next()) + { + + Object_Animation_Sequence_Header_Chunk * oashc = seqi()->get_header(); + GLOBALASSERT (oashc); + + seqa_p->sequence_id = GetSequenceID (oashc->sequence_number, oashc->sub_sequence_number); + seqa_p->Time = get_time_from_sequence_id(seqa_p->sequence_id); + + List f_list; + seqi()->get_frames(&f_list); + + GLOBALASSERT (f_list.size()); + + int num_frames=f_list.size(); + Object_Animation_Sequence_Frame_Chunk ** frame_array= new Object_Animation_Sequence_Frame_Chunk*[num_frames]; + + LIF fli(&f_list); + + + for (; !fli.done(); fli.next()) + { + GLOBALASSERT(fli()->frame_ref_noframe_ref_no]=fli(); + + } + KEYFRAME_DATA ** next_frame_ptr=&seqa_p->first_frame; + KEYFRAME_DATA * delta_frame=0; + + KEYFRAME_DATA * kfd=0; + + + for(int frame_no=0;frame_noflags & HierarchyFrame_FlagMask; + int sound_index=frame->get_sound_index(); + if(sound_index>0 && sound_indexframe_has_extended_data=1; + kfd_extended->sound=sound; + kfd_extended->flags=flags; + + } + else + { + //use standard keyframe + kfd =(KEYFRAME_DATA*) PoolAllocateMem(sizeof(KEYFRAME_DATA)); + + kfd->frame_has_extended_data=0; + + } + kfd->last_frame=0; //if this is in fact the last frame , then this will be changed later + + //set up previous frames next pointer + *next_frame_ptr=kfd; + next_frame_ptr=&kfd->Next_Frame; + + if(frame->flags & HierarchyFrameFlag_DeltaFrame) + { + GLOBALASSERT(delta_frame==0); //should only be one frame with this flag + delta_frame=kfd; + } + + VECTORCH offset; + + offset.vx = frame->transform.x * local_scale; + offset.vy = frame->transform.y * local_scale; + offset.vz = frame->transform.z * local_scale; + + SetKeyFrameOffset(kfd,&offset); + + QUAT q; + + q.quatx = (int) -(frame->orientation.x*ONE_FIXED); + q.quaty = (int) -(frame->orientation.y*ONE_FIXED); + q.quatz = (int) -(frame->orientation.z*ONE_FIXED); + q.quatw = (int) (frame->orientation.w*ONE_FIXED); + + + CopyIntQuatToShort(&q,&kfd->QOrient); + + int this_frame_no = frame->at_frame_no; + + frame_no++; + + if (frame_noSequence_Length =(unsigned short) min(frame_array[frame_no]->at_frame_no - this_frame_no,65535); + } + else + { + kfd->Sequence_Length =(unsigned short) min(65536 - this_frame_no , 65535); + } + } + //sort out some settings for the last frame + kfd->last_frame=1; + if(kfd->Sequence_Length<=6) + { + //this sequence doesn't loop + kfd->Next_Frame=kfd; + } + else + { + //this sequence loops + kfd->Next_Frame=seqa_p->first_frame; + } + seqa_p->last_frame = kfd; + + delete [] frame_array; + + + if(delta_frame) + { + //this sequence is a delta sequence , so convert all frames to deltas relative + //to the frame delta_frame + + QUAT inverse_delta; + CopyShortQuatToInt(&delta_frame->QOrient,&inverse_delta); + + VECTORCH inverse_offset; + GetKeyFrameOffset(delta_frame,&inverse_offset); + + + inverse_delta.quatx = -inverse_delta.quatx; + inverse_delta.quaty = -inverse_delta.quaty; + inverse_delta.quatz = -inverse_delta.quatz; + + inverse_offset.vx = -inverse_offset.vx; + inverse_offset.vy = -inverse_offset.vy; + inverse_offset.vz = -inverse_offset.vz; + + kfd = seqa_p->first_frame; + + while (1) + { + // do deltas + QUAT q; + + CopyShortQuatToInt(&kfd->QOrient,&q); + + MulQuat (&q, &inverse_delta, &q); + CopyIntQuatToShort(&q,&kfd->QOrient); + + VECTORCH offset; + GetKeyFrameOffset(kfd,&offset); + + offset.vx += inverse_offset.vx; + offset.vy += inverse_offset.vy; + offset.vz += inverse_offset.vz; + + SetKeyFrameOffset(kfd,&offset); + + if(kfd->last_frame) break; + + kfd = kfd->Next_Frame; + } + + } + + + seqa_p ++; + } + } + } + + currsection->Children = 0; + + List h_children = ohc->list_h_children(); + + if (h_children.size()) + { + currsection->Children = (SECTION **)PoolAllocateMem (sizeof (SECTION *) * (h_children.size()+1)); + + int i = 0; + + for (LIF hci(&h_children); !hci.done(); hci.next()) + { + if ((currsection->Children[i++] = build_hierarchy (hci(),hierarchy_name)) == 0) + return 0; + } + currsection->Children[i] = 0; + } + + + return(currsection); + +} + +void Global_Hierarchy_Store::build_time_list(Object_Hierarchy_Chunk* ohc) +{ + List seql; + Chunk * pChunk = ohc->lookup_single_child ("OBANSEQS"); + if (pChunk) + { + ((Object_Animation_Sequences_Chunk *)pChunk)->list_sequences(&seql); + } + + for (LIF seqi(&seql); !seqi.done(); seqi.next()) + { + Object_Animation_Sequence_Header_Chunk * oashc = seqi()->get_header(); + GLOBALASSERT (oashc); + + int id=GetSequenceID (oashc->sequence_number, oashc->sub_sequence_number); + int time=(seqi()->get_sequence_time()*ONE_FIXED)/1000; + if(time) + { + Hierarchy_ID_Time_Pair* id_time = new Hierarchy_ID_Time_Pair; + id_time->id=id; + id_time->time=time; + time_list.add_entry(id_time); + } + } +} + +int Global_Hierarchy_Store::get_time_from_sequence_id(int id) +{ + for(LIF tlif(&time_list);!tlif.done();tlif.next()) + { + if(tlif()->id==id) + { + return tlif()->time; + } + } + return 0; +} + + +static BOOL copy_rif_data_as_hierarchy (RIFFHANDLE h, int flags,int progress_start,int progress_interval) +{ + ////////////////////////// + // Sort out local scale // + ////////////////////////// + int i; + set_local_scale(h,flags); + + Set_Progress_Bar_Position(progress_start); + + //SelectGenTexDirectory(ITI_TEXTURE); + + #if 0 //disable the multiple image group stuff + if(!(flags & CCF_DONT_INITIALISE_TEXTURES)) + { + InitialiseTextures(); + } + #endif + + /*find this rif's sound directory*/ + Rif_Sound_Directory=0; + Sound_Directory_Chunk* dir_chunk=(Sound_Directory_Chunk*)h->envd->lookup_single_child("SOUNDDIR"); + if(dir_chunk) + { + Rif_Sound_Directory=dir_chunk->directory; + } + + + load_rif_bitmaps(h,flags); + + List osnp_list; + List low_osnp_list; + List obl; + h->fc->list_objects(&obl); + + int NumObjectsToLoad=obl.size(); //for progress_bar + int NumObjectsLoaded=0; + + for (LIF oli(&obl); !oli.done(); oli.next()) + { + if((NumObjectsLoaded &0xf)==0) + { + //update bar every 16 objects + Set_Progress_Bar_Position(progress_start+progress_interval*((.5*NumObjectsLoaded)/NumObjectsToLoad)); + } + NumObjectsLoaded++; + + + Shape_Chunk * tmpshp = oli()->get_assoc_shape(); + //ChunkShape cs = tmpshp->shape_data; + + CTM_ReturnType rt_temp = copy_to_mainshapelist(h,tmpshp,flags); + Object_ShapeNum_Pair * osnp = new Object_ShapeNum_Pair; + + osnp->sh_num = rt_temp.main_list_pos; + osnp->ob = oli(); + const char* ob_name=osnp->ob->object_data.o_name; + if(ob_name[0]=='L' && ob_name[1] && ob_name[2]=='#') + { + low_osnp_list.add_entry(osnp); + } + else + { + osnp_list.add_entry (osnp); + } + + osnp->ob->program_object_index=osnp->sh_num; + + + //add the prelighting data to the shape + + Shape_Vertex_Intensities_Chunk * svic = 0; + + List cl; + osnp->ob->lookup_child ("SHPVTINT",cl); + + for (LIF svici(&cl); !svici.done(); svici.next()) + { + Shape_Vertex_Intensities_Chunk * temp_svic = (Shape_Vertex_Intensities_Chunk *) svici(); + if (!strncmp(temp_svic->light_set_name, ::light_set_name, 8)) + { + svic = temp_svic; + break; + } + + } + + if (svic) + { + + mainshapelist[osnp->sh_num]->sh_extraitemdata = (EXTRAITEMDATA *)PoolAllocateMem(12 * svic->num_vertices); + if (!mainshapelist[osnp->sh_num]->sh_extraitemdata) + { + memoryInitialisationFailure = 1; + return FALSE; + } + + for (int vn = 0; vn < svic->num_vertices; vn++) + { + //convert coloured light to a brightness value + int ir=svic->intensity_array[vn]>>16; + int ig=svic->intensity_array[vn]>>8 &0xff; + int ib=svic->intensity_array[vn] &0xff; + int mag =sqrt((ir*ir+ig*ig+ib*ib)/3.0); + + mainshapelist[osnp->sh_num]->sh_extraitemdata[vn].EID_VertexI = svic->intensity_array[vn] + (mag<<24); + + } + + mainshapelist[osnp->sh_num]->shapeflags |= ShapeFlag_PreLit; + + } + + } + /*-----------------------------** + ** Load shapes with no objects ** + **-----------------------------*/ + + //don't want these to be scaled with the level + double temp_scale=local_scale; + local_scale=GlobalScale; + + List shps; + h->fc->lookup_child ("REBSHAPE",shps); + + for (LIF shplst(&shps) ; !shplst.done() ; shplst.next()) + { + + Shape_Chunk * tmpshp = (Shape_Chunk *)shplst(); + + if ( ! tmpshp->list_assoc_objs().size() ) + { + // ChunkShape cs = tmpshp->shape_data; + copy_to_mainshapelist(h,tmpshp,flags); + } + + } + local_scale=temp_scale; + + if(!(flags & CCF_DONT_INITIALISE_TEXTURES)) + { + //currently on the occasions this flag is used , the textures are shared with the level rif. + //therefore only clear the fast files if the flag is not set. + ffclose_almost_all(); + } + /*-----------------------------** + ** set up hierarchy related stuff ** + **-----------------------------*/ + + + Set_Progress_Bar_Position(progress_start+progress_interval*.5); + //get the distances at which the various detail levels should be used + int* distance_array=0; + Hierarchy_Degradation_Distance_Chunk* hddc=(Hierarchy_Degradation_Distance_Chunk*)h->fc->lookup_single_child("HIDEGDIS"); + if(hddc) + { + GLOBALASSERT(hddc->num_detail_levels==10); + distance_array=hddc->distance_array; + } + + //sort out the arrays of low detail shapes + SHAPEHEADER* low_detail_array[10]; + for(LIF osnp_lif(&osnp_list);!osnp_lif.done();osnp_lif.next()) + { + if(!low_osnp_list.size()) break; + + for(i=0;i<10;i++) + { + low_detail_array[i]=0; + } + int num_detail_level=0; + + Object_ShapeNum_Pair* osnp=osnp_lif(); + //find all the low detail shapes for this shape; + for(LIF low_osnp_lif(&low_osnp_list);!low_osnp_lif.done();) + { + Object_ShapeNum_Pair* low_osnp=low_osnp_lif(); + if(!strcmp(&low_osnp->ob->object_data.o_name[3],osnp->ob->object_data.o_name)) + { + low_osnp_lif.delete_current(); + int detail=low_osnp->ob->object_data.o_name[1]-'0'; + if(detail>=1 && detail <=9) + { + low_detail_array[detail]=mainshapelist[low_osnp->sh_num]; + num_detail_level++; + } + delete low_osnp; + } + else + { + low_osnp_lif.next(); + } + + } + + if(num_detail_level)//we have some lower detail shapes + { + SHAPEHEADER* main_shape=mainshapelist[osnp->sh_num]; + low_detail_array[0]=main_shape; //detail level 0 is the original shape + num_detail_level++; + + main_shape->shape_degradation_array=(ADAPTIVE_DEGRADATION_DESC*)PoolAllocateMem(sizeof(ADAPTIVE_DEGRADATION_DESC)*num_detail_level); + + ADAPTIVE_DEGRADATION_DESC* deg_ptr=main_shape->shape_degradation_array; + for(i=9;i>=0;i--) //shapes are entered in ascending order of detail. + { + if(low_detail_array[i]) + { + if(distance_array) + deg_ptr->distance=distance_array[i]; + else + deg_ptr->distance=i*10000; + deg_ptr->shape=low_detail_array[i]; + + if (i!=9) + { + deg_ptr->shapeCanBeUsedCloseUp = 1; + } + else + { + deg_ptr->shapeCanBeUsedCloseUp = 0; + } + deg_ptr++; + } + } + + + } + + } + //at this point low_osnp_list ought to be empty , but delete the rest anyway + while(low_osnp_list.size()) + { + delete low_osnp_list.first_entry(); + low_osnp_list.delete_first_entry(); + } + + + List cl; + h->fc->lookup_child ("OBJCHIER",cl); + + GLOBALASSERT (cl.size()); + + Global_Hierarchy_Store * ghs = new Global_Hierarchy_Store (h); + + int NumHierToLoad=cl.size(); + int NumHierLoaded=0; + + for (LIF cli (&cl); !cli.done(); cli.next()) + { + Set_Progress_Bar_Position(progress_start+progress_interval*(.7+(.2*NumHierLoaded)/NumHierToLoad)); + NumHierLoaded++; + + Object_Hierarchy_Chunk * ohc = (Object_Hierarchy_Chunk *)cli(); + + ghs->add_hierarchy (osnp_list, ohc); + } + + ghs->setup_alternate_shape_sets(osnp_list,h->fc); + + + while (osnp_list.size()) + { + delete osnp_list.first_entry(); + osnp_list.delete_first_entry(); + } + + Global_Hierarchy_Library.add_entry(ghs); + + Set_Progress_Bar_Position(progress_start+progress_interval*.9); + + //reset the sound directory + Rif_Sound_Directory=0; + + return(1); + + +} + +/////////////////////////////////////////////////////////////////////////////// +// Library management functions + +extern "C" +{ + +SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); + +SECTION * GetHierarchyFromLibrary(const char * rif_name) +{ + return (GetNamedHierarchyFromLibrary(rif_name, "Template")); +} + +SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name) +{ + for (LIF ghli(&Global_Hierarchy_Library); !ghli.done(); ghli.next()) + { + if (!_stricmp (ghli()->riffname, rif_name)) + { + for (LIF hdi (&ghli()->hierarchy_list); !hdi.done(); hdi.next()) + { + if (!strcmp (hdi()->hierarchy_name, hier_name)) + { + return(hdi()->hierarchy_root); + } + } + + } + } + return(0); +} + +HIERARCHY_SHAPE_REPLACEMENT* GetHierarchyAlternateShapeSetFromLibrary(const char* rif_name,const char* shape_set_name) +{ + for (LIF ghli(&Global_Hierarchy_Library); !ghli.done(); ghli.next()) + { + if (!_stricmp (ghli()->riffname, rif_name)) + { + for(LIF hlif(&ghli()->alternate_shape_set_list);!hlif.done();hlif.next()) + { + if(!_stricmp(hlif()->shape_set_name,shape_set_name)) + { + return hlif()->replaced_shapes; + } + } + return 0; + } + } + return(0); +} +HIERARCHY_VARIANT_DATA* GetHierarchyAlternateShapeSetCollectionFromLibrary(const char* rif_name,int collection_index) +{ + for (LIF ghli(&Global_Hierarchy_Library); !ghli.done(); ghli.next()) + { + + if (!_stricmp (ghli()->riffname, rif_name)) + { + //found the appropriate hierarchy library + Global_Hierarchy_Store * hier=ghli(); + + if(hier->num_shape_collections==0) return 0; + + if(collection_index<=0) + { + if(hier->random_shape_colls.size()==0) return 0; + + //pick a collection at random. + int random=FastRandom() % hier->random_shape_colls.size(); + collection_index=hier->random_shape_colls[random]; + } + + collection_index%=hier->num_shape_collections; + GLOBALASSERT(hier->shape_collections); + return &hier->shape_collections[collection_index]; + } + } + return(0); +} + +HIERARCHY_SHAPE_REPLACEMENT* GetHierarchyAlternateShapeFromId(const char* rif_name,int replacement_id,char* section_name) +{ + int collection_index = replacement_id; + if(collection_index == 0 ) return NULL; + + for (LIF ghli(&Global_Hierarchy_Library); !ghli.done(); ghli.next()) + { + + if (!_stricmp (ghli()->riffname, rif_name)) + { + //found the appropriate hierarchy library + Global_Hierarchy_Store * hier=ghli(); + + if(collection_index<0 || collection_index>=hier->num_shape_collections) return NULL; + + HIERARCHY_VARIANT_DATA* variant = &hier->shape_collections[collection_index]; + HIERARCHY_SHAPE_REPLACEMENT* replacement =(HIERARCHY_SHAPE_REPLACEMENT*) variant->replacements; + HIERARCHY_SHAPE_REPLACEMENT* returnval = NULL; + + /* + Search through the list of replacements for the desired shape. + We need to find the last replacement for a given shape. (One shape may be replaced twice) + */ + + while(replacement->replaced_section_name) + { + if(!strcmp(replacement->replaced_section_name,section_name)) + { + //found a replacement for this shape + returnval = replacement; + } + replacement++; + } + + return returnval; + } + } + return(0); +} + + +void EmptyHierarchyLibrary () +{ + while (Global_Hierarchy_Library.size()) + { + delete Global_Hierarchy_Library.first_entry(); + Global_Hierarchy_Library.delete_first_entry(); + } +} + +void DeleteHierarchyLibraryEntry(RIFFHANDLE h) +{ + for (LIF ghli(&Global_Hierarchy_Library); !ghli.done(); ghli.next()) + { + if(ghli()->rif_hand==h) + { + delete ghli(); + ghli.delete_current(); + break; + } + } +} + + +}; +/////////////////////////////////////////////////////////////////////////////// + + +extern void SetupFragmentType(Fragment_Type_Chunk* ftc); + +struct Adjacent_AIModule_EP +{ + VECTORCH entry_point; + int aimodule_index; + unsigned int alien_only :1; +}; + +// copies all shapes and objects etc +BOOL copy_rif_data (RIFFHANDLE h, int flags,int progress_start,int progress_interval) +{ + /*close all fastfiles so we don't end up with too many open at once*/ + if(!(flags & CCF_DONT_INITIALISE_TEXTURES)) + { + //currently on the occasions this flag is used , the textures are shared with the level rif. + //therefore only clear the fast files if the flag is not set. + ffclose_almost_all(); + } + + #if 0 //disable the multiple image group stuff + if (!(flags & CCF_IMAGEGROUPSET)) + { + GLOBALASSERT(flags & CCF_ENVIRONMENT); //image group should be set for everything else + #ifdef MaxImageGroups + #if MaxImageGroups > 2 + SetCurrentImageGroup(flags & CCF_ENVIRONMENT ? 2 : 0); + #else + if (flags & CCF_ENVIRONMENT) + GLOBALASSERT(0=="Requires MaxImageGroups to be > 2 (system.h)"); + #endif + #else + if (flags & CCF_ENVIRONMENT) + GLOBALASSERT(0=="Requires MaxImageGroups to be defined > 2 (system.h)"); + #endif + } + #endif + + if (INVALID_RIFFHANDLE == h || !h->fc) return(FALSE); + + if (flags & CCF_LOAD_AS_HIERARCHY_IF_EXISTS) + { + if (h->fc->count_children("OBJCHIER")) + return(copy_rif_data_as_hierarchy (h,flags,progress_start,progress_interval)); + } + + ////////////////////////// + // Sort out local scale // + ////////////////////////// + + set_local_scale(h,flags); + + /*find this rif's sound directory*/ + Rif_Sound_Directory=0; + Sound_Directory_Chunk* dir_chunk=(Sound_Directory_Chunk*)h->envd->lookup_single_child("SOUNDDIR"); + if(dir_chunk) + { + Rif_Sound_Directory=dir_chunk->directory; + } + +/*---------------** +** Load Textures ** +**---------------*/ + + //SelectGenTexDirectory(ITI_TEXTURE); + + #if 0 //disable the multiple image group stuff + if(!(flags & CCF_DONT_INITIALISE_TEXTURES)) + { + InitialiseTextures(); + } + #endif + + if (flags & CCF_ENVIRONMENT) + { + load_rif_bitmaps(h,flags); + + // Load in the palette, tlt, and set up lookup table for coloured polys + + PaletteMapTable = 0; + + if (h->envd) + { + set_quantization_event (h,flags); + + copy_rif_palette (h,flags); + + copy_rif_tlt (h,flags); + + get_rif_palette_remap_table (h,flags); + + } + + /*find the default sound settings */ + float env_reverb=-1; + int env_sound_type=0; + Environment_Acoustics_Chunk* env_ac=(Environment_Acoustics_Chunk*)h->envd->lookup_single_child("ENVACOUS"); + if(env_ac) + { + if(env_ac->reverb<=1) env_reverb=env_ac->reverb; + env_sound_type=env_ac->env_index; + } + + + /*-------------------------------------** + ** Load in shapes to the mainshapelist ** + **-------------------------------------*/ + + /*-----------------------------------** + ** Set up arrays of modules ** + ** ** + ** There should be two arrays, ** + ** one array of modules and a ** + ** pointer to an array of modules ** + **-----------------------------------*/ + + + //count the modules + int num_modules=0; + { + List object_list; + h->fc->list_objects(&object_list); + for(LIF oblif(&object_list);!oblif.done();oblif.next()) + { + if(!(oblif()->get_header()->flags & OBJECT_FLAG_PLACED_OBJECT)) + { + num_modules++; + } + } + + } + // One module per object at the moment + + MainScene.sm_module = (MODULE *) PoolAllocateMem (sizeof(MODULE) * (num_modules + 3)); + if (!MainScene.sm_module) + { + memoryInitialisationFailure = 1; + return FALSE; + } + + MainScene.sm_marray = (MODULE **) PoolAllocateMem (sizeof(MODULE) * (num_modules + 3)); + if (!MainScene.sm_marray) + { + memoryInitialisationFailure = 1; + return FALSE; + } + + // putting an infinite module at the beginning - followed by a term + // by cheating + + MODULE * sm_module_start = MainScene.sm_module; + MODULE ** sm_marray_start = MainScene.sm_marray; + + MainScene.sm_module += 2; + MainScene.sm_marray += 1; + + for (int i=0; i shape_list; + List object_list; + h->fc->list_shapes(&shape_list); + + int NumShapesToLoad=shape_list.size(); //for progress_bar + int NumShapesLoaded=0; + + for(LIF shplif(&shape_list);!shplif.done();shplif.next()) + { + + if((NumShapesLoaded & 0xf)==0) + { + //update bar every 16 objects + Set_Progress_Bar_Position(progress_start+progress_interval*((.6*NumShapesLoaded)/NumShapesToLoad)); + } + + NumShapesLoaded++; + + object_list=shplif()->list_assoc_objs(); + if(object_list.size()) + { + if(shplif()->get_header()->flags & SHAPE_FLAG_EXTERNALFILE) + { + //only create one copy of the shape for imported objects + + #if SupportMorphing && LOAD_MORPH_SHAPES + db_logf3(("Copying shape to shape list")); + CTM_ReturnType rt_temp = copy_to_mainshapelist(h,shplif(),flags,0); + int start_shape_no = rt_temp.start_list_pos; + int list_pos = rt_temp.main_list_pos; + db_logf3(("Shape copied to %d",list_pos)); + MORPHCTRL * mc = rt_temp.mc; + #else + int list_pos = copy_to_mainshapelist(h,shplif(),flags,&ob->object_data); + int start_shape_no = list_pos; + #endif + + int AnimationShape=-1; + if (shplif()->lookup_single_child("TEXTANIM")) + { + AnimationShape=list_pos; + } + + for(LIF oblif(&object_list);!oblif.done();oblif.next()) + { + Object_Chunk* ob=oblif(); + if (ob->get_header()->flags & OBJECT_FLAG_PLACED_OBJECT) + { + deal_with_placed_object(ob, start_shape_no, AnimationShape); + } + else + { + GLOBALASSERT(0=="Shouldn't be any modules using imported shapes"); + } + } + + } + else + { + //create one shape per object + for(LIF oblif(&object_list);!oblif.done();oblif.next()) + { + Object_Chunk* ob=oblif(); + #if SupportMorphing && LOAD_MORPH_SHAPES + db_logf3(("Copying shape for object %s",ob->object_data.o_name)); + CTM_ReturnType rt_temp = copy_to_mainshapelist(h,shplif(),flags,&ob->object_data); + int start_shape_no = rt_temp.start_list_pos; + int list_pos = rt_temp.main_list_pos; + db_logf3(("Shape copied to %d",list_pos)); + MORPHCTRL * mc = rt_temp.mc; + #else + int list_pos = copy_to_mainshapelist(h,shplif(),flags,&ob->object_data); + int start_shape_no = list_pos; + #endif + + //see if object has prelighting data + Shape_Vertex_Intensities_Chunk * svic = 0; + + List cl; + ob->lookup_child ("SHPVTINT",cl); + + for (LIF svici(&cl); !svici.done(); svici.next()) + { + Shape_Vertex_Intensities_Chunk * temp_svic = (Shape_Vertex_Intensities_Chunk *) svici(); + if (!strncmp(temp_svic->light_set_name, ::light_set_name, 8)) + { + svic = temp_svic; + break; + } + + } + + if (svic) + { + //this object has prelighting , so set up extra item data + mainshapelist[list_pos]->sh_extraitemdata = (EXTRAITEMDATA *)PoolAllocateMem(12 * svic->num_vertices); + if (!mainshapelist[list_pos]->sh_extraitemdata) + { + memoryInitialisationFailure = 1; + return FALSE; + } + + for (int vn = 0; vn < svic->num_vertices; vn++) + { + //convert coloured light to a brightness value + int ir=svic->intensity_array[vn]>>16; + int ig=svic->intensity_array[vn]>>8 &0xff; + int ib=svic->intensity_array[vn] &0xff; + int mag =sqrt((ir*ir+ig*ig+ib*ib)/3.0); + + mainshapelist[list_pos]->sh_extraitemdata[vn].EID_VertexI = svic->intensity_array[vn] + (mag<<24); + + } + + mainshapelist[list_pos]->shapeflags |= ShapeFlag_PreLit; + + } + #if 1 + int AnimationShape=-1; + if (shplif()->lookup_single_child("TEXTANIM")) + { + AnimationShape=list_pos; + } + #endif + + if (ob->get_header()->flags & OBJECT_FLAG_PLACED_OBJECT) + { + + deal_with_placed_object(ob, start_shape_no, AnimationShape); + } + else + { + + copy_to_module (ob, mod_pos, start_shape_no); + + int shape2 = -1; + if (mc) + { + if(mc->ObMorphHeader) + { + if(mc->ObMorphHeader->mph_frames) + { + shape2 = mc->ObMorphHeader->mph_frames[0].mf_shape2; + DeallocateMem (mc->ObMorphHeader->mph_frames); + } + DeallocateMem(mc->ObMorphHeader); + } + DeallocateMem (mc); + mc = 0; + } + deal_with_module_object (ob, start_shape_no, AnimationShape, shape2, &MainScene.sm_module[mod_pos]); + + Object_Module_Data_Chunk* omdc=(Object_Module_Data_Chunk*)ob->lookup_single_child("MODULEDT"); + if(omdc) + { + if(!omdc->lookup_single_child("AIMODSLA")) + AIModuleArraySize++; + } + else + AIModuleArraySize++; + o_chunk_array[mod_pos] = ob; //for finding object_chunk from module + ob->program_object_index=mod_pos; //for finding module from object_chunk + aimodule_indeces[mod_pos]=-1; + mod_pos ++; + } + } + } + } + else + { + //shape has no objects , load it , but don't scale it + double temp_scale=local_scale; + local_scale=GlobalScale; + + copy_to_mainshapelist(h,shplif(),flags); + + local_scale=temp_scale; + } + } + GLOBALASSERT(num_modules==mod_pos); + /*--------------** + ** Module Stuff ** + **--------------*/ + + if (flags & CCF_ENVIRONMENT) + { + Set_Progress_Bar_Position(progress_start+progress_interval*.6); + } + MainScene.sm_module[mod_pos] = Term_Module; + MainScene.sm_marray[mod_pos] = 0; + + AIModuleArraySize++; + AIModuleArray=(AIMODULE*)PoolAllocateMem(sizeof(AIMODULE)*AIModuleArraySize); + + AIModuleArray[0].m_link_ptrs=0; + AIModuleArray[0].m_module_ptrs=0; + AIModuleArray[0].m_waypoints=0; + AIModuleArray[0].m_index=0; + + + List* entry_points=new List[AIModuleArraySize]; + + int ai_mod_pos=1; + + //setup aimodules and the aimodule conversion array + for(i=0;ilookup_single_child("MODULEDT"); + AI_Module_Master_Chunk* ammc=0; + if(omdc) + { + if(omdc->lookup_single_child("AIMODSLA"))continue; + ammc=(AI_Module_Master_Chunk*)omdc->lookup_single_child("AIMODMAS"); + + } + + AIMODULE* aim=&AIModuleArray[ai_mod_pos]; + aim->m_index=ai_mod_pos; + aim->m_world=o_chunk_array[i]->object_data.location*local_scale; + + aim->m_link_ptrs=0; + if(ammc) + { + aim->m_module_ptrs=(MODULE**)PoolAllocateMem(sizeof(MODULE*)*(2+ammc->ModuleList.size())); + aim->m_module_ptrs[0]=&MainScene.sm_module[i]; + MainScene.sm_module[i].m_aimodule=aim; + aimodule_indeces[i]=ai_mod_pos; + + int pos=1; + for(LIF modlif(&ammc->ModuleList);!modlif.done();modlif.next()) + { + for(int obj=0;objm_module_ptrs[pos++]=&MainScene.sm_module[obj]; + MainScene.sm_module[obj].m_aimodule=aim; + aimodule_indeces[obj]=ai_mod_pos; + break; + } + + } + + } + aim->m_module_ptrs[pos++]=0; + } + else + { + aim->m_module_ptrs=(MODULE**)PoolAllocateMem(2*sizeof(MODULE*)); + + aim->m_module_ptrs[0]=&MainScene.sm_module[i]; + MainScene.sm_module[i].m_aimodule=aim; + aimodule_indeces[i]=ai_mod_pos; + + aim->m_module_ptrs[1]=0; + } + + ai_mod_pos++; + } + + FALLP_EntryPoints = (FARENTRYPOINTSHEADER *)AllocateMem(AIModuleArraySize*sizeof(FARENTRYPOINTSHEADER)); + if(!FALLP_EntryPoints) + { + memoryInitialisationFailure = 1; + return FALSE; + } + for(i=0;iget_assoc_shape(); + + mod->m_world=oc->object_data.location*local_scale; + + //extents calculated in this way so that if there are no gaps in the extents when stored as doubles , + //there shouldn't be any gaps after they have been converted to ints. + VECTORCH world_min=(oc->object_data.location+sc->shape_data.min)*local_scale; + VECTORCH world_max=(oc->object_data.location+sc->shape_data.max)*local_scale; + + mod->m_maxx=world_max.vx-mod->m_world.vx; + mod->m_maxy=world_max.vy-mod->m_world.vy; + mod->m_maxz=world_max.vz-mod->m_world.vz; + + mod->m_minx=world_min.vx-mod->m_world.vx; + mod->m_miny=world_min.vy-mod->m_world.vy; + mod->m_minz=world_min.vz-mod->m_world.vz; + } + + Chunk * pChunk = o_chunk_array[i]->lookup_single_child ("MODULEDT"); + if (pChunk) + { + omdc = (Object_Module_Data_Chunk *) pChunk; + } + + if (omdc) + { + pChunk = omdc->lookup_single_child("VMDARRAY"); + + if (pChunk) + { + vmac = (VModule_Array_Chunk *) pChunk; + } + + + amc=(Adjacent_Module_Entry_Points_Chunk*) omdc->lookup_single_child("ADJMDLEP"); + + if(omdc->lookup_single_child("ADJMDLST")) + { + GLOBALASSERT(0=="Please load this file into module adjacency so that entry points can be calculated."); + } + + pChunk = omdc->lookup_single_child("MODFLAGS"); + if(pChunk) + { + mfc = (Module_Flag_Chunk*)pChunk; + } + + pChunk = omdc->lookup_single_child("WAYPOINT"); + if(pChunk) + { + mwc = (Module_Waypoint_Chunk*)pChunk; + } + + /*see if this module has its own sound settings*/ + Module_Acoustics_Chunk* mod_ac=(Module_Acoustics_Chunk*)omdc->lookup_single_child("MODACOUS"); + if(mod_ac) + { + if(mod_ac->env_index>=0) + { + MainScene.sm_module[i].m_sound_env_index=mod_ac->env_index; + } + if(mod_ac->reverb>=0) + { + if(mod_ac->reverb>1) + MainScene.sm_module[i].m_sound_reverb=-1;//reverb depends on distance (I think) + else + MainScene.sm_module[i].m_sound_reverb=mod_ac->reverb; + } + } + + } + + //Deal with module linking + if (vmac) + { + if(KeepMainRifFile) + { + //use standard memory allocation , since this may need to be deallocated when updating module linking + MainScene.sm_module[i].m_vmptr = (VMODULE *)AllocateMem(sizeof(VMODULE) * (vmac->num_array_items+1)); + } + else + { + MainScene.sm_module[i].m_vmptr = (VMODULE *)PoolAllocateMem(sizeof(VMODULE) * (vmac->num_array_items+1)); + } + if (!MainScene.sm_module[i].m_vmptr) + { + memoryInitialisationFailure = 1; + return FALSE; + } + + int vmac_no = 0; + int vmod_no = 0; + while (vmac_no < vmac->num_array_items) + { + Object_Chunk* linked_module=h->fc->get_object_by_index(vmac->vmod_array[vmac_no].object_index); + + if (linked_module && linked_module->program_object_index!=-1) + { + + MainScene.sm_module[i].m_vmptr[vmod_no].vmod_type = vmtype_vmodule; + *((int *)MainScene.sm_module[i].m_vmptr[vmod_no].vmod_name) = vmac_no; + if (vmac->vmod_array[vmac_no].branch_no) + { + MainScene.sm_module[i].m_vmptr[vmod_no].vmod_instr = vmodi_bra_vc; + + #if (StandardStrategyAndCollisions || IntermediateSSACM) + MainScene.sm_module[j].m_mapptr->MapStrategy = StrategyI_DoorPROX; + #endif //(StandardStrategyAndCollisions || IntermediateSSACM) + } + else + { + MainScene.sm_module[i].m_vmptr[vmod_no].vmod_instr = vmodi_null; + } + + MainScene.sm_module[i].m_vmptr[vmod_no].vmod_data.vmodidata = vmac->vmod_array[vmac_no].branch_no; + + MainScene.sm_module[i].m_vmptr[vmod_no].vmod_mref.mref_ptr = &MainScene.sm_module[linked_module->program_object_index]; + MainScene.sm_module[i].m_vmptr[vmod_no].vmod_dir.vx = 0; + MainScene.sm_module[i].m_vmptr[vmod_no].vmod_dir.vy = 0; + MainScene.sm_module[i].m_vmptr[vmod_no].vmod_dir.vz = 0; + + MainScene.sm_module[i].m_vmptr[vmod_no].vmod_angle = 0; + MainScene.sm_module[i].m_vmptr[vmod_no].vmod_flags = vmac->vmod_array[vmac_no].flags; + vmod_no ++; + } + + vmac_no ++; + + } + MainScene.sm_module[i].m_vmptr[vmod_no].vmod_type = vmtype_term; + *((int *)MainScene.sm_module[i].m_vmptr[vmod_no].vmod_name) = vmac_no; + } + else + { + MainScene.sm_module[i].m_vmptr = (VMODULE *)PoolAllocateMem(sizeof(VMODULE) * (2)); + if (!MainScene.sm_module[i].m_vmptr) + { + memoryInitialisationFailure = 1; + return FALSE; + } + + MainScene.sm_module[i].m_vmptr[0].vmod_type = vmtype_vmodule; + *((int *)MainScene.sm_module[i].m_vmptr[0].vmod_name) = 0; + MainScene.sm_module[i].m_vmptr[0].vmod_instr = vmodi_null; + MainScene.sm_module[i].m_vmptr[0].vmod_data.vmodidata = 0; + + MainScene.sm_module[i].m_vmptr[0].vmod_mref.mref_ptr = &MainScene.sm_module[i]; + MainScene.sm_module[i].m_vmptr[0].vmod_dir.vx = 0; + MainScene.sm_module[i].m_vmptr[0].vmod_dir.vy = 0; + MainScene.sm_module[i].m_vmptr[0].vmod_dir.vz = 0; + + MainScene.sm_module[i].m_vmptr[0].vmod_angle = 0; + MainScene.sm_module[i].m_vmptr[0].vmod_flags = 0; + + MainScene.sm_module[i].m_vmptr[1].vmod_type = vmtype_term; + *((int *)MainScene.sm_module[i].m_vmptr[1].vmod_name) = 1; + } + MainScene.sm_module[i].m_link_ptrs=0; + + if(mfc) + { + MainScene.sm_module[i].m_flags|=mfc->Flags; + } + + AI_Module_Master_Chunk* ammc=0; + if(omdc) + { + if(omdc->lookup_single_child("AIMODSLA"))continue; + ammc=(AI_Module_Master_Chunk*)omdc->lookup_single_child("AIMODMAS"); + } + + int this_ai_module_index=aimodule_indeces[i]; + AIMODULE* aim=&AIModuleArray[this_ai_module_index]; + + + //build list of adjacent ai_modules + List adjacent_aimodule_list; + + if (amc) + { + + for (LIF ami(&amc->adjacent_modules_list); !ami.done(); ami.next()) + { + Object_Chunk* adjacent_module=h->fc->get_object_by_index(ami().object_index); + + if (adjacent_module && adjacent_module->program_object_index!=-1) + { + int adj_ai_module=aimodule_indeces[adjacent_module->program_object_index]; + if(adj_ai_module!=this_ai_module_index) + { + //make sure not already in list + for(LIF adjlif(&adjacent_aimodule_list);!adjlif.done();adjlif.next()) + { + if(adjlif()==adj_ai_module) break; + } + if(adjlif.done()) + { + if(ami().flags & AdjacentModuleFlag_InsideAdjacentModule) + { + continue; + } + if(ami().flags & AdjacentModuleFlag_AdjacentModuleInsideMe) + { + continue; + + } + Adjacent_AIModule_EP* ad_aim=new Adjacent_AIModule_EP; + ad_aim->entry_point=ami().entry_point*local_scale; + ad_aim->aimodule_index=this_ai_module_index; + ad_aim->alien_only=(ami().flags & AdjacentModuleFlag_Vertical)!=0; + + entry_points[adj_ai_module].add_entry(ad_aim); + adjacent_aimodule_list.add_entry(adj_ai_module); + + } + + } + } + + } + + + } + + if(ammc) + { + for(LIF oblif(&ammc->ModuleList);!oblif.done();oblif.next()) + { + Object_Module_Data_Chunk* omdc2=(Object_Module_Data_Chunk*)oblif()->lookup_single_child("MODULEDT"); + if(!omdc2)continue; + amc=(Adjacent_Module_Entry_Points_Chunk*)omdc2->lookup_single_child("ADJMDLEP"); + if(amc) + { + for (LIF ami(&amc->adjacent_modules_list); !ami.done(); ami.next()) + { + Object_Chunk* adjacent_module=h->fc->get_object_by_index(ami().object_index); + + if (adjacent_module && adjacent_module->program_object_index!=-1) + { + int adj_ai_module=aimodule_indeces[adjacent_module->program_object_index]; + if(adj_ai_module!=this_ai_module_index) + { + //make sure not already in list + for(LIF adjlif(&adjacent_aimodule_list);!adjlif.done();adjlif.next()) + { + if(adjlif()==adj_ai_module) break; + } + if(adjlif.done()) + { + if(ami().flags & AdjacentModuleFlag_InsideAdjacentModule) + { + continue; + } + if(ami().flags & AdjacentModuleFlag_AdjacentModuleInsideMe) + { + continue; + + } + + Adjacent_AIModule_EP* ad_aim=new Adjacent_AIModule_EP; + ad_aim->entry_point=(ami().entry_point)*local_scale; + ad_aim->aimodule_index=this_ai_module_index; + ad_aim->alien_only=(ami().flags & AdjacentModuleFlag_Vertical)!=0; + + entry_points[adj_ai_module].add_entry(ad_aim); + adjacent_aimodule_list.add_entry(adj_ai_module); + } + + } + } + + } + } + } + } + + //setup adjacent modules + int adj_pos=0; + aim->m_link_ptrs=(AIMODULE**)PoolAllocateMem(sizeof(AIMODULE*)*(1+adjacent_aimodule_list.size())); + if(adjacent_aimodule_list.size()) + { + + while(adjacent_aimodule_list.size()) + { + aim->m_link_ptrs[adj_pos]=&AIModuleArray[adjacent_aimodule_list.first_entry()]; + adj_pos++; + adjacent_aimodule_list.delete_first_entry(); + + } + } + aim->m_link_ptrs[adj_pos]=0; + + + + + //Deal with waypoints + if(mwc && mwc->NumAlienWaypoints) + { + WAYPOINT_HEADER* wh=(WAYPOINT_HEADER*)PoolAllocateMem(sizeof(WAYPOINT_HEADER)); + aim->m_waypoints=wh; + MainScene.sm_module[i].m_waypoints=wh;//temporary + + wh->num_waypoints=mwc->NumAlienWaypoints; + + wh->first_waypoint=(WAYPOINT_VOLUME*)PoolAllocateMem(sizeof(WAYPOINT_VOLUME)*wh->num_waypoints); + for(int j=0;jnum_waypoints;j++) + { + WAYPOINT_VOLUME* wv=&wh->first_waypoint[j]; + ChunkWaypoint* cw=&mwc->AlienWaypoints[j]; + + VECTORCH ObCentre=o_chunk_array[i]->object_data.location*local_scale; + wv->centre=cw->centre*local_scale; + wv->min_extents=cw->min*local_scale; + SubVector(&wv->centre,&wv->min_extents); + wv->max_extents=cw->max*local_scale; + SubVector(&wv->centre,&wv->max_extents); + wv->max_extents.vx--; + wv->max_extents.vy--; + wv->max_extents.vz--; + SubVector(&ObCentre,&wv->centre); + wv->flags=cw->flags; + wv->num_links=cw->NumWPLinks; + if(wv->num_links) + wv->first_link=(WAYPOINT_LINK*)PoolAllocateMem(sizeof(WAYPOINT_LINK)*wv->num_links); + else + wv->first_link=0; + for(int k=0;knum_links;k++) + { + wv->first_link[k].link_flags=cw->WayLinks[k].flags; + wv->first_link[k].link_target_index=cw->WayLinks[k].index; + } + wv->workspace=0; + wv->weighting=5; + } + + } + else + { + aim->m_waypoints=0; + } + + + } + + if (flags & CCF_ENVIRONMENT) + { + Set_Progress_Bar_Position(progress_start+progress_interval*.8); + } + //setup entry points + for(i=0;ientry_point; + SubVector(&AIModuleArray[i].m_world,&FALLP_EntryPoints[i].entryPointsList[adj_pos].position); + FALLP_EntryPoints[i].entryPointsList[adj_pos].donorIndex=ad_aim->aimodule_index; + FALLP_EntryPoints[i].entryPointsList[adj_pos].alien_only=ad_aim->alien_only; + + #if 0 + //test + { + VECTORCH loc=FALLP_EntryPoints[i].entryPointsList[adj_pos].position; + + MODULE* mod=AIModuleArray[i].m_module_ptrs[0]; + SHAPEHEADER* shp=mainshapelist[mod->m_mapptr->MapShape]; + + if(loc.vx< shp->shapeminx|| + loc.vy< shp->shapeminy|| + loc.vz< shp->shapeminz|| + loc.vx> shp->shapemaxx|| + loc.vy> shp->shapemaxy|| + loc.vz> shp->shapemaxz) + { + GLOBALASSERT(0=="The entry points probably need to be recalculated"); + } + } + #endif + adj_pos++; + entry_points[i].delete_first_entry(); + delete ad_aim; + } + } + } + delete [] entry_points; + + + // putting an infinite module at the beginning - followed by a term + // and setting the arrays back to point at them !! + + MainScene.sm_module = sm_module_start; + MainScene.sm_marray = sm_marray_start; + + MainScene.sm_module[0] = Empty_Module; + MainScene.sm_module[0].m_flags |= m_flag_infinite; + MainScene.sm_module[0].m_vptr.mref_ptr = &MainScene.sm_module[2]; + *((int *)MainScene.sm_module[0].m_name) = 1; + MainScene.sm_module[0].m_vmptr = (VMODULE *)PoolAllocateMem(sizeof(VMODULE) * (mod_pos+1)); + if (!MainScene.sm_module[0].m_vmptr) + { + memoryInitialisationFailure = 1; + return FALSE; + } + + for (i=0; im_flags|=m_flag_gotptrs; + } + + MainScene.sm_module[0].m_vmptr[i].vmod_type = vmtype_term; + *((int *)MainScene.sm_module[0].m_vmptr[i].vmod_name) = i + 1000; + + MainScene.sm_marray[0] = &MainScene.sm_module[0]; + + + MainScene.sm_module[1] = Term_Module; + *((int *)MainScene.sm_module[1].m_name) = 2; + + setup_start_position(h); + + //setup ai paths + setup_paths(h); + + setup_placed_hierarchies(h->envd); + + + //alien power cables + setup_cables(h->envd); + + //particle generators + setup_particle_generators(h->envd); + + // External lifts / airlocks + DealWithExternalObjectStategies (h->envd); + + setup_sounds (h->envd); + + setup_preplaced_decals(h->fc,h->envd); + + // create_strategies_from_list(); //now called later + + //set sky colour , and other envionmental properties + set_environment_properties(h->envd); + + + + Set_Progress_Bar_Position(progress_start+progress_interval*.9); + } + else + { + //not the environment rif , so just load shapes without objects + //don't want these to be scaled with the level + double temp_scale=local_scale; + local_scale=GlobalScale; + + List shps; + h->fc->lookup_child ("REBSHAPE",shps); + + for (LIF shplst(&shps) ; !shplst.done() ; shplst.next()) + { + + Shape_Chunk * tmpshp = (Shape_Chunk *)shplst(); + + if ( ! tmpshp->list_assoc_objs().size() ) + { + // ChunkShape cs = tmpshp->shape_data; + copy_to_mainshapelist(h,tmpshp,flags); + } + + } + local_scale=temp_scale; + } + +/*--------------** +** Load sprites ** +**--------------*/ + //SelectGenTexDirectory(ITI_SPRITE); + + Chunk * pChunk = h->fc->lookup_single_child ("RSPRITES"); + if (pChunk) + { + List sprs; + ((Chunk_With_Children *)pChunk)->lookup_child("SPRIHEAD",sprs); + for (LIF sprlst(&sprs) ; !sprlst.done() ; sprlst.next()) + { + Sprite_Header_Chunk* shc=(Sprite_Header_Chunk*)sprlst(); + + RIF_Name_Chunk * rnc = 0; + + pChunk = shc->lookup_single_child("RIFFNAME"); + if (pChunk) + { + rnc = (RIF_Name_Chunk *) pChunk; + } + else + { + GLOBALASSERT(0=="RIF name not found in sprite"); + } + + + copy_sprite_to_mainshapelist(h,shc,flags); + } + + } + + //setup shape fragments; + { + List chlist; + h->envd->lookup_child("FRAGTYPE",chlist); + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + SetupFragmentType((Fragment_Type_Chunk*)chlif()); + } + } + + if (flags & CCF_ENVIRONMENT) + { + SetUpRunTimeLights(); + // setup_generators ,and load hierarchies + //take copy of scale since it is changed by InitNPCs + setup_generators (h->envd); + + delete[] o_chunk_array; + delete[] aimodule_indeces; + + //find the marine/civvie types that can be randomly generated + List rlist; + h->envd->lookup_child("RANTEXID",rlist); + for(LIF rlif(&rlist);!rlif.done();rlif.next()) + { + Random_Texture_ID_Chunk* ran_chunk=(Random_Texture_ID_Chunk*)rlif(); + if(!_stricmp(ran_chunk->name,"hnpcmarine")) + { + random_marine_texturings=ran_chunk->random_types; + } + else if(!_stricmp(ran_chunk->name,"hnpc_civvie")) + { + random_civilian_texturings=ran_chunk->random_types; + } + } + + double env_scale=local_scale; + InitNPCs(h); + local_scale=env_scale; + + while (random_marine_texturings.size())random_marine_texturings.delete_first_entry(); + while (random_civilian_texturings.size())random_civilian_texturings.delete_first_entry(); + + ChangePalette(TestPalette); + /*ConvertToDDPalette(TestPalette, LPTestPalette, palch->width, 0);*/ + } + + //reset sound diretory pointer + Rif_Sound_Directory=0; + + return TRUE; +} + +// hook to load a bitmap - so you can load them from test directories, etc. should return tex index +int load_rif_bitmap (char const * fname, BMPN_Flags flags) +{ + return CL_LoadImageOnce + ( + fname, + (ScanDrawDirectDraw == ScanDrawMode ? LIO_CHIMAGE : LIO_D3DTEXTURE) + |(flags & ChunkBMPFlag_IFF ? LIO_RELATIVEPATH : LIO_RIFFPATH) + |(flags & ChunkBMPFlag_UsesTransparency ? LIO_TRANSPARENT : LIO_NONTRANSP) + |(flags & (cl_pszGameMode ? + ChunkBMPFlag_RequireGameMipMaps + : ChunkBMPFlag_RequireToolsMipMaps) + ? LIO_LOADMIPMAPS : LIO_NOMIPMAPS) + |LIO_RESTORABLE + ); +} + +//////////////////////////////////////////////////////////////////////// +// Functions which do not operate on RIFFHANDLEs and may become obsolete +//////////////////////////////////////////////////////////////////////// + +// these functions work on the current rif; they only remain for historical reasons +// copies all shapes and objects etc +BOOL copy_chunks_from_environment(int flags) +{ + return copy_rif_data(current_rif_handle,flags,0,0); +} + +///////////////////////////////////////////// +// Functions for handling the main shape list +///////////////////////////////////////////// + +static SHAPEHEADER null_shape; // static to ensure it is initialized to 0s + +#define FREE_SHAPE (&null_shape) + +int start_of_loaded_shapes; +static int msl_term_pos; +static int first_free_pos = GLS_NOTINLIST; + +// reserves the next avaialbe position in the main shape list and returns it +int GetMSLPos(void) +{ + if (GLS_NOTINLIST == first_free_pos) + first_free_pos = msl_term_pos = start_of_loaded_shapes = load_precompiled_shapes(); + + for (int pos = first_free_pos; pos < msl_term_pos && FREE_SHAPE != mainshapelist[pos]; ++pos) + ; + + first_free_pos = pos+1; + if (pos >= msl_term_pos) + { + msl_term_pos = first_free_pos; + if(msl_term_pos>=maxshapes) + { + //alocate another 50 slots on the mainshapelist + mainshapelist=(SHAPEHEADER**)realloc(mainshapelist,sizeof(SHAPEHEADER*)*(maxshapes+50)); + LOCALASSERT(mainshapelist); + if(!mainshapelist) + { + ReleaseDirect3D(); + exit(0x74363); + } + for(int i=maxshapes;i pos) first_free_pos = pos; + + if (pos+1 == msl_term_pos) + { + while (msl_term_pos > 0 && FREE_SHAPE == mainshapelist[msl_term_pos-1]) + { + mainshapelist[--msl_term_pos] = 0; + } + } +} + +//////////////////////////////////////////////// +// Functions retrieving data about loaded shapes +//////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////// +// Initializing, deallocating of shapes, mainly hooks for project specific fns +////////////////////////////////////////////////////////////////////////////// + +// hook to perhaps scale the uv coordinates - should return new value +int ProcessUVCoord(RIFFHANDLE,UVCOORDTYPE uvct,int uv_value,int /*image_num*/) +{ +// return (int)(uv_value*GetUVScale(UVC_SPRITE_U==uvct||UVC_SPRITE_V==uvct ? ITI_SPRITE : ITI_TEXTURE)); + return uv_value; +} + + +// perform initial post processing on shape just after loading +// note that the copy named shape functions will not call this +void post_process_shape (SHAPEHEADER * shp) +{ + for (int i=0; inumitems; i++) + { + switch (shp->items[i][0]) + { + case I_Polygon: + if (!(shp->items[i][2] & iflag_nolight)) + shp->items[i][0] = I_GouraudPolygon; + break; + case I_3dTexturedPolygon: + case I_2dTexturedPolygon: + case I_Gouraud3dTexturedPolygon: + case I_Gouraud2dTexturedPolygon: + if (shp->shapeflags & ShapeFlag_Sprite) + { + shp->items[i][0] = I_2dTexturedPolygon; + shp->items[i][2] &= ~iflag_tx2dor3d; + } + else + { + shp->items[i][0] = I_Gouraud3dTexturedPolygon; + shp->items[i][2] |= iflag_tx2dor3d; + } + } + shp->items[i][2] |= iflag_gsort_ptest | iflag_linear_s; + //shp->items[i][2] &= ~iflag_transparent; // this causes _translucency_ on direct 3d + //shp->items[i][2] &= ~iflag_drawtx3das2d; + + #if SupportZBuffering + if (ZBufferOn==ZBufferMode) + { + switch (shp->items[i][0]) + { + case I_Polygon: + shp->items[i][0] = I_ZB_Polygon; + break; + case I_GouraudPolygon: + shp->items[i][0] = I_ZB_GouraudPolygon; + break; + case I_PhongPolygon: + shp->items[i][0] = I_ZB_PhongPolygon; + break; + case I_2dTexturedPolygon: + shp->items[i][0] = I_ZB_2dTexturedPolygon; + break; + case I_Gouraud2dTexturedPolygon: + shp->items[i][0] = I_ZB_Gouraud2dTexturedPolygon; + break; + case I_3dTexturedPolygon: + shp->items[i][0] = I_ZB_3dTexturedPolygon; + break; + case I_Gouraud3dTexturedPolygon: + shp->items[i][0] = I_ZB_Gouraud3dTexturedPolygon; + break; + } + } + #endif + } + + shp->shapeflags |= ShapeFlag_AugZ | ShapeFlag_AugZ_Lite; +} + +// your function could perform any extra tidying up you need +void DeallocateLoadedShapeheader(SHAPEHEADER * shp) +{ + #if !NEW_DEALLOCATION_ORDER + DeallocateRifLoadedShapeheader(shp); + #endif +} + + +void DeallocateModules() +{ + + MODULE ** m_arrayPtr = MainScene.sm_marray; + + #if !USE_LEVEL_MEMORY_POOL + while (*m_arrayPtr) + { + List lights_for_this_module; + + MODULE * this_mod = *m_arrayPtr++; + + if(this_mod->m_mapptr) DeallocateMem(this_mod->m_mapptr); + this_mod->m_mapptr=0; + if(this_mod->name) DeallocateMem(this_mod->name); + this_mod->name=0; + if(this_mod->m_vmptr) DeallocateMem(this_mod->m_vmptr); + this_mod->m_vmptr=0; + if(this_mod->m_lightarray) DeallocateMem(this_mod->m_lightarray); + this_mod->m_lightarray=0; + } + if(MainScene.sm_module)DeallocateMem(MainScene.sm_module); + if(MainScene.sm_marray)DeallocateMem(MainScene.sm_marray); + #endif + MainScene.sm_module=0; + MainScene.sm_marray=0; + + + #if !USE_LEVEL_MEMORY_POOL + for(int i=0;im_link_ptrs) DeallocateMem(aim->m_link_ptrs); + if(aim->m_module_ptrs) DeallocateMem(aim->m_module_ptrs); + if(aim->m_waypoints) + { + WAYPOINT_HEADER* wh=aim->m_waypoints; + for(int j=0;jnum_waypoints;j++) + { + WAYPOINT_VOLUME* wv=&wh->first_waypoint[j]; + if(wv->first_link)DeallocateMem(wv->first_link); + } + if(wh->first_waypoint)DeallocateMem(wh->first_waypoint); + DeallocateMem(wh); + } + } + DeallocateMem(AIModuleArray); + #endif + AIModuleArray=0; + + //delete any paths + #if !USE_LEVEL_MEMORY_POOL + if(PathArray) + { + for(int i=0;iVDB_World,sizeof(VECTORCH),&byteswritten,0); + WriteFile(file,&Global_VDB_Ptr->VDB_Mat,sizeof(MATRIXCH),&byteswritten,0); + + CloseHandle(file); + + file = CreateFile ("avp_rifs\\module.aaa", GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, 0); + + if(file==INVALID_HANDLE_VALUE) return; + + if(!env_rif->fc) + { + CloseHandle(file); + NewOnScreenMessage("MODULE UPDATING REQUIRES -KEEPRIF OPTION."); + return; + } + + int file_size=GetFileSize(file,0); + GLOBALASSERT((file_size % 4)==0); + int pos=0; + unsigned long bytesread; + { + char name[60]; + ReadFile(file,name,60,&bytesread,0); + + int i=0; + char* name1=&name[0]; + while(name[i]) + { + if(name[i]=='\\' || name[i]==':') + { + name1=&name[i+1]; + } + i++; + } + i=0; + char* name2=&env_rif->fc->filename[0]; + while(env_rif->fc->filename[i]) + { + if(env_rif->fc->filename[i]=='\\' || env_rif->fc->filename[i]==':') + { + name2=&env_rif->fc->filename[i+1]; + } + i++; + } + + if(_stricmp(name1,name2)) + { + CloseHandle(file); + DeleteFile("avp_rifs\\module.aaa"); + return; + } + + } + pos+=60; + + + while(posfc->get_object_by_index(obj_index); + GLOBALASSERT(obj); + GLOBALASSERT(obj->program_object_index!=-1); + MODULE* this_mod=&MainScene.sm_module[obj->program_object_index+2]; + + int numlinks; + ReadFile(file,&numlinks,4,&bytesread,0); + pos+=4; + + if(!numlinks) continue; + + if(this_mod->m_vmptr) + DeallocateMem(this_mod->m_vmptr); + + this_mod->m_vmptr = (VMODULE *)AllocateMem(sizeof(VMODULE) * (numlinks+1)); + + + int vmac_no = 0; + int vmod_no = 0; + while (vmac_no < numlinks) + { + int linked_index; + int branch_no; + ReadFile(file,&linked_index,4,&bytesread,0); + ReadFile(file,&branch_no,4,&bytesread,0); + pos+=8; + + Object_Chunk* linked_module=env_rif->fc->get_object_by_index(linked_index); + + GLOBALASSERT(linked_module); + if (linked_module && linked_module->program_object_index!=-1) + { + + this_mod->m_vmptr[vmod_no].vmod_type = vmtype_vmodule; + *((int *)this_mod->m_vmptr[vmod_no].vmod_name) = vmac_no; + if (branch_no) + { + this_mod->m_vmptr[vmod_no].vmod_instr = vmodi_bra_vc; + } + else + { + this_mod->m_vmptr[vmod_no].vmod_instr = vmodi_null; + } + + this_mod->m_vmptr[vmod_no].vmod_data.vmodidata = branch_no; + + + this_mod->m_vmptr[vmod_no].vmod_mref.mref_ptr = &MainScene.sm_module[linked_module->program_object_index+2]; + this_mod->m_vmptr[vmod_no].vmod_dir.vx = 0; + this_mod->m_vmptr[vmod_no].vmod_dir.vy = 0; + this_mod->m_vmptr[vmod_no].vmod_dir.vz = 0; + + this_mod->m_vmptr[vmod_no].vmod_angle = 0; + this_mod->m_vmptr[vmod_no].vmod_flags = 0; + vmod_no ++; + } + + vmac_no ++; + + } + for(int j=0;jm_vmptr[j].vmod_data.vmodidata) + { + for(int k=j+1;km_vmptr[k].vmod_name)>=this_mod->m_vmptr[j].vmod_data.vmodidata) + { + this_mod->m_vmptr[j].vmod_data.vmodidata_ptr=&this_mod->m_vmptr[k]; + break; + } + } + if(k==vmod_no) + { + this_mod->m_vmptr[j].vmod_data.vmodidata_ptr=&this_mod->m_vmptr[k]; + } + } + } + this_mod->m_vmptr[vmod_no].vmod_type = vmtype_term; + *((int *)this_mod->m_vmptr[vmod_no].vmod_name) = vmac_no; + } + + CloseHandle(file); + DeleteFile("avp_rifs\\module.aaa"); +} +#endif + + + + + + +void setup_preplaced_decals(File_Chunk* fc,Environment_Data_Chunk* edc) +{ + NumFixedDecals=0; + CurrentFixedDecalIndex=0; + + GLOBALASSERT(edc); + GLOBALASSERT(fc); + + Special_Objects_Chunk* soc=(Special_Objects_Chunk*) edc->lookup_single_child("SPECLOBJ"); + if(!soc) return; + + AVP_Decal_Chunk* decal_chunk=(AVP_Decal_Chunk*) soc->lookup_single_child("AVPDECAL"); + if(!decal_chunk) return; + + GLOBALASSERT(decal_chunk->decals); + + NumFixedDecals=0; + + + for(int i=0;inum_decals;i++) + { + FIXED_DECAL* fd=&FixedDecalStorage[NumFixedDecals]; + AVP_Decal * ad=&decal_chunk->decals[i]; + + //find the decal's module + Object_Chunk* module=fc->get_object_by_index(ad->object_index) ; + if(!module) continue; //module not found + if(module->program_object_index==-1) continue; + + fd->DecalID=(DECAL_ID)ad->DecalID; + for(int j=0;j<4;j++) + { + fd->Vertices[j].vx=ad->Vertices[j].x; + fd->Vertices[j].vy=ad->Vertices[j].y; + fd->Vertices[j].vz=ad->Vertices[j].z; + } + + fd->UOffset=ad->UOffset; + fd->ModuleIndex=module->program_object_index+2; + + NumFixedDecals++; + } + + + CurrentFixedDecalIndex=NumFixedDecals; + +} + +int get_object_index_from_module_index(List& ob_list,int index) +{ + for(LIF ob_lif(&ob_list);!ob_lif.done();ob_lif.next()) + { + if(ob_lif()->program_object_index==index) + { + return ob_lif()->object_data.index_num; + } + } + return -1; +} + + +static BOOL WarnedAboutDiskSpace=FALSE; +static void MakeBackupFile(File_Chunk* fc) +{ + unsigned long spc,bps,numclust,total; + if(GetDiskFreeSpace(0,&spc,&bps,&numclust,&total)) + { + unsigned int freespace=spc*bps*numclust; + if(freespace<40000000) + { + if(!WarnedAboutDiskSpace) + { + WarnedAboutDiskSpace=TRUE; + NewOnScreenMessage("LESS THAN 40MB FREE DISC SPACE"); + NewOnScreenMessage("NO BACKUP WILL BE MADE"); + } + return; + } + } + WarnedAboutDiskSpace=FALSE; + + CreateDirectory("avp_rifs\\Backup",0); + int length=strlen(fc->filename); + int pos=length; + while(pos>=0 && fc->filename[pos]!='\\')pos--; + char* filename=&fc->filename[pos+1]; + length=strlen(filename)-4; + + char* Name1=new char[length+30]; + char* Name2=new char[length+30]; + strncpy(Name1,"avp_rifs\\Backup\\",16); + strncpy(&Name1[16],filename,length); + length+=16; + strncpy(Name2,Name1,length); + strncpy(&Name1[length],"B0.rif",7); + strncpy(&Name2[length],"B1.rif",7); + + DeleteFile(Name1); + + for (int i=0;i<9;i++) + { + Name1[length+1]=i+'0'; + Name2[length+1]=i+'1'; + MoveFile(Name2,Name1); + } + Name2[length+1]='9'; + CopyFile(fc->filename,Name2,FALSE); + + delete [] Name1; + delete [] Name2; +} +extern "C" +{ + + +void save_preplaced_decals() +{ + + GLOBALASSERT(env_rif); + if(!env_rif->fc) + { + NewOnScreenMessage("CAN'T SAVE DECALS. USE -KEEPRIF"); + return; + } + + { + + DWORD attributes = GetFileAttributes(env_rif->fc->filename); + if (0xffffffff!=attributes) + { + if (attributes & FILE_ATTRIBUTE_READONLY) + { + NewOnScreenMessage("CAN'T SAVE DECALS."); + NewOnScreenMessage("FILE IS READ ONLY"); + return; + } + } + } + MakeBackupFile(env_rif->fc); + + Environment_Data_Chunk* edc = env_rif->envd; + GLOBALASSERT(edc); + + Special_Objects_Chunk* soc=(Special_Objects_Chunk*) edc->lookup_single_child("SPECLOBJ"); + if(!soc) soc=new Special_Objects_Chunk(edc); + + //delete the old decal chunk + delete soc->lookup_single_child("AVPDECAL"); + + if(NumFixedDecals) + { + List ob_list; + env_rif->fc->list_objects(&ob_list); + + + AVP_Decal_Chunk* decal_chunk=new AVP_Decal_Chunk(soc,NumFixedDecals); + for(int i=0;inum_decals;i++) + { + FIXED_DECAL* fd=&FixedDecalStorage[i]; + AVP_Decal * ad=&decal_chunk->decals[i]; + + ad->DecalID=(int)fd->DecalID; + for(int j=0;j<4;j++) + { + ad->Vertices[j].x=fd->Vertices[j].vx; + ad->Vertices[j].y=fd->Vertices[j].vy; + ad->Vertices[j].z=fd->Vertices[j].vz; + + } + + ad->UOffset=fd->UOffset; + + ad->object_index=get_object_index_from_module_index(ob_list,fd->ModuleIndex-2); + } + + } + + if(!env_rif->fc->update_file()) + { + NewOnScreenMessage("ERROR SAVING DECALS!!!!!!"); + } + else + { + NewOnScreenMessage("DECALS SAVED."); + + } +} + + +void check_preplaced_decal_modules() +{ +/*-------------------------------------------------------------------------------** +** go through the list of decals and make sure their module indeces are correct ** +**-------------------------------------------------------------------------------*/ + + for(int index=0;indexModuleIndex]; + mod=ModuleFromPosition(&fd->Vertices[0],mod); + + if(mod) + { + fd->ModuleIndex=mod->m_index; + } + } +} + +}; + + +extern void DeallocateAllFragments(); +extern void LoseAllNonCommonSounds(); +extern void deallocate_behaviour_list(); +extern void PurgeMSLShapeList(); + +extern "C" +{ +void DeallocateSoundsAndPoolAllocatedMemory() +{ + deallocate_behaviour_list(); + + ClearMemoryPool(); + + LoseAllNonCommonSounds(); + + DeallocateAllFragments(); + + DeallocateAllImages(); + + PurgeMSLShapeList(); + +} +}; \ No newline at end of file diff --git a/3dc/avp/win95/Psndplat.c b/3dc/avp/win95/Psndplat.c new file mode 100644 index 0000000..0abfb69 --- /dev/null +++ b/3dc/avp/win95/Psndplat.c @@ -0,0 +1,2343 @@ +/* Patrick 5/6/97 ------------------------------------------------------------- + AvP platform specific sound management source + ----------------------------------------------------------------------------*/ + +#ifdef DAVEW + #define DB_LEVEL 4 +#else + #define DB_LEVEL 3 +#endif + +#include "3dc.h" +#include "inline.h" + + +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "dynamics.h" + +#include "psndplat.h" +#define UseLocalAssert Yes +#include "ourasert.h" +#include "db.h" +#include "dsound.h" +#include "eax.h" +#include "vmanpset.h" +#include +#include "ffstdio.h" +/* Davew 27/7/98 -------------------------------------------------------------- + Internal types. + --------------------------------------------------------------------------*/ +/* Defines for the flags. */ +#define SOUND_DEFAULT 0x00000000 +#define SOUND_VOICE_MGER 0x00000001 +#define SOUND_EAX 0x00000002 +#define SOUND_3DHW 0x00000004 +#define SOUND_USE_3DHW 0x00000008 + +struct SoundConfigTag +{ + unsigned int flags; + BOOL reverb_changed; + float reverb_mix; + unsigned int env_index; +}; + +#ifndef IUnknown_AddRef + #define IUnknown_AddRef(This) (This)->lpVtbl -> AddRef(This) +#endif +#ifndef IUnknown_Release + #define IUnknown_Release(This) (This)->lpVtbl -> Release(This) +#endif +#define GET_REF_COUNT(x) (x ? IUnknown_AddRef(x), IUnknown_Release(x) : -1) +#define LOG_RC() db_logf4(("DSO %i, DSPB %i, DS3DL %i, PS %i", GET_REF_COUNT(DSObject), GET_REF_COUNT(DSPrimaryBuffer), GET_REF_COUNT(DS3DListener), GET_REF_COUNT(PropSetP))); + +#ifndef DSBCAPS_CTRLDEFAULT + #define DSBCAPS_CTRLDEFAULT (DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY) +#endif + +/* Patrick 5/6/97 ------------------------------------------------------------- + Sound system globals + ----------------------------------------------------------------------------*/ +SOUNDSAMPLEDATA GameSounds[SID_MAXIMUM]; +ACTIVESOUNDSAMPLE ActiveSounds[SOUND_MAXACTIVE]; +SOUNDSAMPLEDATA BlankGameSound = {0,0,0,0,NULL,0,NULL}; +ACTIVESOUNDSAMPLE BlankActiveSound = {SID_NOSOUND,ASP_Minimum,0,0,NULL,0,0,0,0,0,{{0,0,0},0,0},NULL, NULL, NULL}; + +/* Patrick 5/6/97 ------------------------------------------------------------- + Direct sound globals + ----------------------------------------------------------------------------*/ +LPDIRECTSOUND DSObject = NULL; +LPDIRECTSOUNDBUFFER DSPrimaryBuffer = NULL; +LPDIRECTSOUND3DLISTENER DS3DListener = NULL; +LPKSPROPERTYSET PropSetP = NULL; +int SoundMinBufferFree; + +/* Patrick 5/6/97 ------------------------------------------------------------- + Internal global variables + ----------------------------------------------------------------------------*/ +struct SoundConfigTag SoundConfig; +static signed int vol_to_atten_table[] = +{ + -10000, -9922, -8502, -7672, -7083, -6626, -6252, -5936, + -5663, -5422, -5206, -5011, -4832, -4669, -4517, -4375, + -4243, -4119, -4002, -3891, -3786, -3686, -3591, -3500, + -3413, -3329, -3249, -3172, -3097, -3025, -2956, -2889, + -2824, -2761, -2700, -2640, -2582, -2526, -2472, -2419, + -2367, -2316, -2267, -2219, -2171, -2125, -2080, -2036, + -1993, -1951, -1910, -1869, -1829, -1790, -1752, -1714, + -1678, -1641, -1606, -1571, -1536, -1502, -1469, -1436, + -1404, -1372, -1341, -1310, -1280, -1250, -1221, -1191, + -1163, -1135, -1107, -1079, -1052, -1025, -999, -973, + -947, -922, -896, -872, -847, -823, -799, -775, + -752, -729, -706, -683, -661, -639, -617, -595, + -574, -552, -531, -511, -490, -470, -449, -429, + -410, -390, -371, -351, -332, -314, -295, -276, + -258, -240, -222, -204, -186, -168, -151, -134, + -117, -100, -83, -66, -49, -33, -17, 0, +}; + + +// this table plots the frequency change for +// 128/ths of a semitone for one octave (0-1535), +// divide or multiply by 2 to subtract or add an octave + +static float pitch_to_frequency_mult_table [] = +{ + 1.0F, 1.00045137F, 1.000902943F, 1.00135472F, 1.001806701F, 1.002258886F, 1.002711275F, 1.003163868F, + 1.003616666F, 1.004069668F, 1.004522874F, 1.004976285F, 1.005429901F, 1.005883722F, 1.006337747F, 1.006791977F, + 1.007246412F, 1.007701053F, 1.008155898F, 1.008610949F, 1.009066205F, 1.009521667F, 1.009977334F, 1.010433207F, + 1.010889286F, 1.011345571F, 1.011802061F, 1.012258758F, 1.012715661F, 1.01317277F, 1.013630085F, 1.014087607F, + 1.014545335F, 1.01500327F, 1.015461411F, 1.01591976F, 1.016378315F, 1.016837077F, 1.017296046F, 1.017755223F, + 1.018214607F, 1.018674198F, 1.019133996F, 1.019594002F, 1.020054216F, 1.020514637F, 1.020975266F, 1.021436104F, + 1.021897149F, 1.022358402F, 1.022819863F, 1.023281533F, 1.023743411F, 1.024205498F, 1.024667793F, 1.025130297F, + 1.025593009F, 1.026055931F, 1.026519061F, 1.026982401F, 1.027445949F, 1.027909707F, 1.028373674F, 1.028837851F, + 1.029302237F, 1.029766832F, 1.030231638F, 1.030696653F, 1.031161878F, 1.031627313F, 1.032092958F, 1.032558813F, + 1.033024879F, 1.033491155F, 1.033957641F, 1.034424338F, 1.034891246F, 1.035358364F, 1.035825694F, 1.036293234F, + 1.036760985F, 1.037228947F, 1.037697121F, 1.038165506F, 1.038634102F, 1.03910291F, 1.039571929F, 1.04004116F, + 1.040510603F, 1.040980258F, 1.041450125F, 1.041920204F, 1.042390495F, 1.042860998F, 1.043331714F, 1.043802642F, + 1.044273782F, 1.044745136F, 1.045216702F, 1.045688481F, 1.046160473F, 1.046632678F, 1.047105096F, 1.047577727F, + 1.048050572F, 1.04852363F, 1.048996902F, 1.049470387F, 1.049944086F, 1.050417999F, 1.050892125F, 1.051366466F, + 1.051841021F, 1.05231579F, 1.052790773F, 1.053265971F, 1.053741383F, 1.05421701F, 1.054692851F, 1.055168907F, + 1.055645178F, 1.056121664F, 1.056598366F, 1.057075282F, 1.057552413F, 1.05802976F, 1.058507323F, 1.058985101F, + 1.059463094F, 1.059941304F, 1.060419729F, 1.06089837F, 1.061377227F, 1.061856301F, 1.06233559F, 1.062815096F, + 1.063294818F, 1.063774757F, 1.064254913F, 1.064735285F, 1.065215874F, 1.06569668F, 1.066177703F, 1.066658943F, + 1.067140401F, 1.067622075F, 1.068103967F, 1.068586077F, 1.069068404F, 1.069550949F, 1.070033712F, 1.070516692F, + 1.070999891F, 1.071483308F, 1.071966943F, 1.072450796F, 1.072934868F, 1.073419158F, 1.073903666F, 1.074388394F, + 1.07487334F, 1.075358505F, 1.075843889F, 1.076329492F, 1.076815315F, 1.077301356F, 1.077787617F, 1.078274098F, + 1.078760798F, 1.079247718F, 1.079734857F, 1.080222216F, 1.080709796F, 1.081197595F, 1.081685615F, 1.082173855F, + 1.082662315F, 1.083150996F, 1.083639897F, 1.084129019F, 1.084618362F, 1.085107926F, 1.085597711F, 1.086087716F, + 1.086577943F, 1.087068391F, 1.087559061F, 1.088049952F, 1.088541065F, 1.089032399F, 1.089523955F, 1.090015733F, + 1.090507733F, 1.090999955F, 1.091492399F, 1.091985065F, 1.092477954F, 1.092971065F, 1.093464399F, 1.093957956F, + 1.094451735F, 1.094945737F, 1.095439962F, 1.09593441F, 1.096429082F, 1.096923976F, 1.097419095F, 1.097914436F, + 1.098410001F, 1.09890579F, 1.099401803F, 1.099898039F, 1.1003945F, 1.100891184F, 1.101388093F, 1.101885226F, + 1.102382583F, 1.102880165F, 1.103377972F, 1.103876003F, 1.104374259F, 1.10487274F, 1.105371446F, 1.105870377F, + 1.106369533F, 1.106868914F, 1.107368521F, 1.107868354F, 1.108368412F, 1.108868695F, 1.109369205F, 1.10986994F, + 1.110370902F, 1.11087209F, 1.111373503F, 1.111875143F, 1.11237701F, 1.112879103F, 1.113381423F, 1.113883969F, + 1.114386743F, 1.114889743F, 1.11539297F, 1.115896424F, 1.116400106F, 1.116904015F, 1.117408152F, 1.117912516F, + 1.118417107F, 1.118921927F, 1.119426974F, 1.119932249F, 1.120437752F, 1.120943484F, 1.121449444F, 1.121955632F, + 1.122462048F, 1.122968693F, 1.123475567F, 1.12398267F, 1.124490002F, 1.124997562F, 1.125505352F, 1.12601337F, + 1.126521619F, 1.127030096F, 1.127538803F, 1.12804774F, 1.128556906F, 1.129066302F, 1.129575929F, 1.130085785F, + 1.130595871F, 1.131106188F, 1.131616734F, 1.132127512F, 1.13263852F, 1.133149758F, 1.133661227F, 1.134172928F, + 1.134684859F, 1.135197021F, 1.135709414F, 1.136222039F, 1.136734895F, 1.137247982F, 1.137761301F, 1.138274852F, + 1.138788635F, 1.139302649F, 1.139816896F, 1.140331374F, 1.140846085F, 1.141361028F, 1.141876204F, 1.142391612F, + 1.142907253F, 1.143423126F, 1.143939233F, 1.144455572F, 1.144972144F, 1.14548895F, 1.146005989F, 1.146523261F, + 1.147040767F, 1.147558506F, 1.148076479F, 1.148594686F, 1.149113126F, 1.149631801F, 1.15015071F, 1.150669853F, + 1.15118923F, 1.151708842F, 1.152228688F, 1.152748769F, 1.153269085F, 1.153789635F, 1.154310421F, 1.154831441F, + 1.155352697F, 1.155874188F, 1.156395914F, 1.156917876F, 1.157440074F, 1.157962507F, 1.158485176F, 1.159008081F, + 1.159531222F, 1.160054599F, 1.160578212F, 1.161102062F, 1.161626148F, 1.16215047F, 1.16267503F, 1.163199826F, + 1.163724859F, 1.164250129F, 1.164775636F, 1.16530138F, 1.165827362F, 1.16635358F, 1.166880037F, 1.167406731F, + 1.167933663F, 1.168460833F, 1.16898824F, 1.169515886F, 1.17004377F, 1.170571892F, 1.171100252F, 1.171628851F, + 1.172157689F, 1.172686765F, 1.17321608F, 1.173745634F, 1.174275427F, 1.174805459F, 1.175335731F, 1.175866241F, + 1.176396992F, 1.176927981F, 1.177459211F, 1.17799068F, 1.178522389F, 1.179054338F, 1.179586527F, 1.180118957F, + 1.180651627F, 1.181184537F, 1.181717688F, 1.182251079F, 1.182784711F, 1.183318584F, 1.183852698F, 1.184387053F, + 1.184921649F, 1.185456487F, 1.185991566F, 1.186526886F, 1.187062448F, 1.187598252F, 1.188134298F, 1.188670585F, + 1.189207115F, 1.189743887F, 1.190280901F, 1.190818158F, 1.191355657F, 1.191893398F, 1.192431383F, 1.19296961F, + 1.19350808F, 1.194046793F, 1.194585749F, 1.195124949F, 1.195664392F, 1.196204079F, 1.196744009F, 1.197284182F, + 1.1978246F, 1.198365262F, 1.198906167F, 1.199447317F, 1.199988711F, 1.200530349F, 1.201072232F, 1.201614359F, + 1.202156731F, 1.202699348F, 1.20324221F, 1.203785317F, 1.204328669F, 1.204872266F, 1.205416109F, 1.205960197F, + 1.206504531F, 1.20704911F, 1.207593935F, 1.208139006F, 1.208684324F, 1.209229887F, 1.209775696F, 1.210321752F, + 1.210868055F, 1.211414604F, 1.211961399F, 1.212508442F, 1.213055731F, 1.213603267F, 1.214151051F, 1.214699082F, + 1.21524736F, 1.215795886F, 1.216344659F, 1.21689368F, 1.217442948F, 1.217992465F, 1.21854223F, 1.219092243F, + 1.219642504F, 1.220193013F, 1.220743771F, 1.221294778F, 1.221846033F, 1.222397537F, 1.22294929F, 1.223501292F, + 1.224053543F, 1.224606044F, 1.225158794F, 1.225711793F, 1.226265042F, 1.226818541F, 1.227372289F, 1.227926288F, + 1.228480536F, 1.229035035F, 1.229589784F, 1.230144783F, 1.230700033F, 1.231255533F, 1.231811285F, 1.232367287F, + 1.23292354F, 1.233480044F, 1.234036799F, 1.234593806F, 1.235151064F, 1.235708573F, 1.236266335F, 1.236824348F, + 1.237382612F, 1.237941129F, 1.238499898F, 1.239058919F, 1.239618193F, 1.240177719F, 1.240737497F, 1.241297528F, + 1.241857812F, 1.242418349F, 1.242979139F, 1.243540182F, 1.244101478F, 1.244663027F, 1.24522483F, 1.245786887F, + 1.246349197F, 1.246911761F, 1.247474579F, 1.248037651F, 1.248600977F, 1.249164558F, 1.249728392F, 1.250292482F, + 1.250856826F, 1.251421424F, 1.251986278F, 1.252551386F, 1.25311675F, 1.253682369F, 1.254248243F, 1.254814372F, + 1.255380757F, 1.255947398F, 1.256514294F, 1.257081446F, 1.257648855F, 1.258216519F, 1.25878444F, 1.259352616F, + 1.25992105F, 1.26048974F, 1.261058687F, 1.26162789F, 1.26219735F, 1.262767068F, 1.263337042F, 1.263907274F, + 1.264477763F, 1.26504851F, 1.265619515F, 1.266190777F, 1.266762297F, 1.267334075F, 1.26790611F, 1.268478405F, + 1.269050957F, 1.269623768F, 1.270196838F, 1.270770166F, 1.271343753F, 1.271917599F, 1.272491703F, 1.273066067F, + 1.273640691F, 1.274215573F, 1.274790715F, 1.275366117F, 1.275941778F, 1.2765177F, 1.277093881F, 1.277670322F, + 1.278247024F, 1.278823985F, 1.279401208F, 1.27997869F, 1.280556434F, 1.281134438F, 1.281712703F, 1.282291229F, + 1.282870016F, 1.283449065F, 1.284028374F, 1.284607946F, 1.285187778F, 1.285767873F, 1.28634823F, 1.286928848F, + 1.287509728F, 1.288090871F, 1.288672276F, 1.289253943F, 1.289835873F, 1.290418066F, 1.291000521F, 1.29158324F, + 1.292166221F, 1.292749466F, 1.293332973F, 1.293916744F, 1.294500779F, 1.295085077F, 1.295669639F, 1.296254465F, + 1.296839555F, 1.297424909F, 1.298010527F, 1.298596409F, 1.299182556F, 1.299768967F, 1.300355643F, 1.300942584F, + 1.30152979F, 1.302117261F, 1.302704997F, 1.303292998F, 1.303881265F, 1.304469797F, 1.305058595F, 1.305647659F, + 1.306236989F, 1.306826584F, 1.307416446F, 1.308006574F, 1.308596968F, 1.309187629F, 1.309778556F, 1.310369751F, + 1.310961212F, 1.311552939F, 1.312144935F, 1.312737197F, 1.313329726F, 1.313922523F, 1.314515588F, 1.31510892F, + 1.31570252F, 1.316296388F, 1.316890524F, 1.317484929F, 1.318079601F, 1.318674542F, 1.319269752F, 1.31986523F, + 1.320460977F, 1.321056993F, 1.321653278F, 1.322249832F, 1.322846655F, 1.323443748F, 1.32404111F, 1.324638742F, + 1.325236643F, 1.325834815F, 1.326433256F, 1.327031968F, 1.327630949F, 1.328230202F, 1.328829724F, 1.329429517F, + 1.330029581F, 1.330629916F, 1.331230522F, 1.331831399F, 1.332432547F, 1.333033967F, 1.333635657F, 1.33423762F, + 1.334839854F, 1.33544236F, 1.336045138F, 1.336648188F, 1.337251511F, 1.337855105F, 1.338458972F, 1.339063112F, + 1.339667524F, 1.340272209F, 1.340877167F, 1.341482398F, 1.342087903F, 1.34269368F, 1.343299731F, 1.343906056F, + 1.344512654F, 1.345119526F, 1.345726672F, 1.346334092F, 1.346941786F, 1.347549755F, 1.348157998F, 1.348766515F, + 1.349375307F, 1.349984374F, 1.350593716F, 1.351203333F, 1.351813225F, 1.352423392F, 1.353033835F, 1.353644553F, + 1.354255547F, 1.354866817F, 1.355478362F, 1.356090184F, 1.356702282F, 1.357314656F, 1.357927306F, 1.358540233F, + 1.359153437F, 1.359766917F, 1.360380675F, 1.360994709F, 1.361609021F, 1.362223609F, 1.362838476F, 1.363453619F, + 1.364069041F, 1.36468474F, 1.365300717F, 1.365916972F, 1.366533506F, 1.367150317F, 1.367767407F, 1.368384776F, + 1.369002423F, 1.369620349F, 1.370238554F, 1.370857038F, 1.371475801F, 1.372094843F, 1.372714165F, 1.373333766F, + 1.373953647F, 1.374573808F, 1.375194249F, 1.37581497F, 1.376435971F, 1.377057252F, 1.377678814F, 1.378300656F, + 1.378922779F, 1.379545183F, 1.380167867F, 1.380790833F, 1.38141408F, 1.382037608F, 1.382661418F, 1.383285509F, + 1.383909882F, 1.384534537F, 1.385159473F, 1.385784692F, 1.386410193F, 1.387035977F, 1.387662042F, 1.388288391F, + 1.388915022F, 1.389541936F, 1.390169133F, 1.390796613F, 1.391424376F, 1.392052422F, 1.392680752F, 1.393309366F, + 1.393938263F, 1.394567445F, 1.39519691F, 1.395826659F, 1.396456693F, 1.397087011F, 1.397717613F, 1.398348501F, + 1.398979673F, 1.399611129F, 1.400242871F, 1.400874898F, 1.40150721F, 1.402139808F, 1.402772691F, 1.40340586F, + 1.404039315F, 1.404673055F, 1.405307082F, 1.405941395F, 1.406575994F, 1.407210879F, 1.407846051F, 1.40848151F, + 1.409117256F, 1.409753289F, 1.410389608F, 1.411026215F, 1.411663109F, 1.412300291F, 1.41293776F, 1.413575517F, + 1.414213562F, 1.414851895F, 1.415490516F, 1.416129426F, 1.416768623F, 1.417408109F, 1.418047884F, 1.418687948F, + 1.4193283F, 1.419968942F, 1.420609873F, 1.421251093F, 1.421892602F, 1.422534401F, 1.42317649F, 1.423818868F, + 1.424461537F, 1.425104495F, 1.425747744F, 1.426391283F, 1.427035113F, 1.427679233F, 1.428323644F, 1.428968346F, + 1.429613338F, 1.430258622F, 1.430904197F, 1.431550064F, 1.432196222F, 1.432842672F, 1.433489413F, 1.434136447F, + 1.434783772F, 1.43543139F, 1.4360793F, 1.436727502F, 1.437375997F, 1.438024785F, 1.438673866F, 1.439323239F, + 1.439972906F, 1.440622866F, 1.441273119F, 1.441923666F, 1.442574506F, 1.44322564F, 1.443877069F, 1.444528791F, + 1.445180807F, 1.445833118F, 1.446485723F, 1.447138622F, 1.447791816F, 1.448445306F, 1.44909909F, 1.449753169F, + 1.450407543F, 1.451062213F, 1.451717178F, 1.452372439F, 1.453027996F, 1.453683848F, 1.454339997F, 1.454996442F, + 1.455653183F, 1.45631022F, 1.456967554F, 1.457625185F, 1.458283113F, 1.458941337F, 1.459599859F, 1.460258678F, + 1.460917794F, 1.461577208F, 1.462236919F, 1.462896929F, 1.463557236F, 1.464217841F, 1.464878744F, 1.465539946F, + 1.466201446F, 1.466863245F, 1.467525342F, 1.468187738F, 1.468850433F, 1.469513428F, 1.470176721F, 1.470840314F, + 1.471504207F, 1.472168399F, 1.472832891F, 1.473497683F, 1.474162775F, 1.474828167F, 1.475493859F, 1.476159852F, + 1.476826146F, 1.47749274F, 1.478159635F, 1.478826832F, 1.479494329F, 1.480162128F, 1.480830228F, 1.481498629F, + 1.482167333F, 1.482836338F, 1.483505645F, 1.484175254F, 1.484845166F, 1.48551538F, 1.486185896F, 1.486856715F, + 1.487527837F, 1.488199262F, 1.48887099F, 1.489543021F, 1.490215355F, 1.490887993F, 1.491560934F, 1.492234179F, + 1.492907728F, 1.493581581F, 1.494255739F, 1.4949302F, 1.495604966F, 1.496280037F, 1.496955412F, 1.497631092F, + 1.498307077F, 1.498983367F, 1.499659962F, 1.500336863F, 1.50101407F, 1.501691582F, 1.502369399F, 1.503047523F, + 1.503725953F, 1.504404689F, 1.505083732F, 1.505763081F, 1.506442736F, 1.507122698F, 1.507802968F, 1.508483544F, + 1.509164428F, 1.509845618F, 1.510527117F, 1.511208923F, 1.511891036F, 1.512573458F, 1.513256187F, 1.513939225F, + 1.514622571F, 1.515306226F, 1.515990189F, 1.516674461F, 1.517359041F, 1.518043931F, 1.51872913F, 1.519414638F, + 1.520100455F, 1.520786582F, 1.521473019F, 1.522159765F, 1.522846822F, 1.523534189F, 1.524221866F, 1.524909853F, + 1.525598151F, 1.526286759F, 1.526975679F, 1.527664909F, 1.52835445F, 1.529044303F, 1.529734467F, 1.530424942F, + 1.53111573F, 1.531806829F, 1.53249824F, 1.533189963F, 1.533881998F, 1.534574345F, 1.535267006F, 1.535959978F, + 1.536653264F, 1.537346862F, 1.538040774F, 1.538734999F, 1.539429537F, 1.540124388F, 1.540819553F, 1.541515032F, + 1.542210825F, 1.542906932F, 1.543603354F, 1.544300089F, 1.544997139F, 1.545694504F, 1.546392183F, 1.547090177F, + 1.547788487F, 1.548487111F, 1.549186051F, 1.549885307F, 1.550584878F, 1.551284764F, 1.551984967F, 1.552685486F, + 1.553386321F, 1.554087472F, 1.55478894F, 1.555490724F, 1.556192825F, 1.556895243F, 1.557597978F, 1.558301031F, + 1.5590044F, 1.559708087F, 1.560412092F, 1.561116415F, 1.561821055F, 1.562526013F, 1.56323129F, 1.563936885F, + 1.564642798F, 1.56534903F, 1.566055581F, 1.566762451F, 1.56746964F, 1.568177148F, 1.568884975F, 1.569593122F, + 1.570301589F, 1.571010375F, 1.571719481F, 1.572428908F, 1.573138654F, 1.573848721F, 1.574559108F, 1.575269816F, + 1.575980845F, 1.576692195F, 1.577403866F, 1.578115858F, 1.578828171F, 1.579540806F, 1.580253763F, 1.580967041F, + 1.581680641F, 1.582394564F, 1.583108809F, 1.583823376F, 1.584538265F, 1.585253478F, 1.585969013F, 1.586684871F, + 1.587401052F, 1.588117556F, 1.588834384F, 1.589551536F, 1.590269011F, 1.59098681F, 1.591704933F, 1.59242338F, + 1.593142151F, 1.593861247F, 1.594580668F, 1.595300413F, 1.596020483F, 1.596740878F, 1.597461598F, 1.598182643F, + 1.598904014F, 1.599625711F, 1.600347733F, 1.601070081F, 1.601792756F, 1.602515756F, 1.603239083F, 1.603962736F, + 1.604686716F, 1.605411023F, 1.606135656F, 1.606860617F, 1.607585905F, 1.60831152F, 1.609037463F, 1.609763734F, + 1.610490332F, 1.611217258F, 1.611944513F, 1.612672095F, 1.613400006F, 1.614128246F, 1.614856814F, 1.615585711F, + 1.616314938F, 1.617044493F, 1.617774377F, 1.618504592F, 1.619235135F, 1.619966009F, 1.620697212F, 1.621428745F, + 1.622160609F, 1.622892803F, 1.623625327F, 1.624358182F, 1.625091368F, 1.625824885F, 1.626558732F, 1.627292911F, + 1.628027422F, 1.628762264F, 1.629497437F, 1.630232943F, 1.63096878F, 1.63170495F, 1.632441452F, 1.633178286F, + 1.633915453F, 1.634652953F, 1.635390785F, 1.636128951F, 1.63686745F, 1.637606282F, 1.638345447F, 1.639084947F, + 1.63982478F, 1.640564947F, 1.641305448F, 1.642046283F, 1.642787453F, 1.643528957F, 1.644270796F, 1.645012969F, + 1.645755478F, 1.646498322F, 1.647241501F, 1.647985016F, 1.648728866F, 1.649473052F, 1.650217574F, 1.650962432F, + 1.651707626F, 1.652453156F, 1.653199024F, 1.653945227F, 1.654691768F, 1.655438645F, 1.65618586F, 1.656933412F, + 1.657681301F, 1.658429528F, 1.659178092F, 1.659926995F, 1.660676235F, 1.661425814F, 1.662175731F, 1.662925986F, + 1.66367658F, 1.664427513F, 1.665178785F, 1.665930396F, 1.666682346F, 1.667434636F, 1.668187265F, 1.668940234F, + 1.669693543F, 1.670447192F, 1.671201181F, 1.67195551F, 1.67271018F, 1.67346519F, 1.674220541F, 1.674976233F, + 1.675732267F, 1.676488641F, 1.677245357F, 1.678002414F, 1.678759814F, 1.679517555F, 1.680275638F, 1.681034063F, + 1.681792831F, 1.682551941F, 1.683311393F, 1.684071189F, 1.684831327F, 1.685591809F, 1.686352633F, 1.687113802F, + 1.687875313F, 1.688637169F, 1.689399368F, 1.690161912F, 1.690924799F, 1.691688031F, 1.692451608F, 1.693215529F, + 1.693979795F, 1.694744405F, 1.695509361F, 1.696274663F, 1.697040309F, 1.697806302F, 1.69857264F, 1.699339324F, + 1.700106354F, 1.70087373F, 1.701641453F, 1.702409522F, 1.703177937F, 1.7039467F, 1.70471581F, 1.705485266F, + 1.706255071F, 1.707025222F, 1.707795721F, 1.708566568F, 1.709337763F, 1.710109306F, 1.710881197F, 1.711653437F, + 1.712426025F, 1.713198962F, 1.713972248F, 1.714745883F, 1.715519867F, 1.7162942F, 1.717068883F, 1.717843916F, + 1.718619298F, 1.719395031F, 1.720171113F, 1.720947546F, 1.721724329F, 1.722501463F, 1.723278948F, 1.724056783F, + 1.72483497F, 1.725613508F, 1.726392397F, 1.727171638F, 1.727951231F, 1.728731176F, 1.729511472F, 1.730292121F, + 1.731073122F, 1.731854476F, 1.732636182F, 1.733418241F, 1.734200653F, 1.734983419F, 1.735766537F, 1.73655001F, + 1.737333835F, 1.738118015F, 1.738902548F, 1.739687436F, 1.740472678F, 1.741258274F, 1.742044225F, 1.742830531F, + 1.743617191F, 1.744404207F, 1.745191578F, 1.745979304F, 1.746767386F, 1.747555824F, 1.748344617F, 1.749133767F, + 1.749923272F, 1.750713134F, 1.751503353F, 1.752293928F, 1.75308486F, 1.753876149F, 1.754667796F, 1.755459799F, + 1.75625216F, 1.757044879F, 1.757837956F, 1.75863139F, 1.759425183F, 1.760219334F, 1.761013843F, 1.761808711F, + 1.762603938F, 1.763399524F, 1.764195468F, 1.764991772F, 1.765788436F, 1.766585459F, 1.767382842F, 1.768180585F, + 1.768978687F, 1.769777151F, 1.770575974F, 1.771375158F, 1.772174703F, 1.772974609F, 1.773774875F, 1.774575503F, + 1.775376493F, 1.776177843F, 1.776979556F, 1.77778163F, 1.778584067F, 1.779386865F, 1.780190027F, 1.78099355F, + 1.781797436F, 1.782601685F, 1.783406297F, 1.784211273F, 1.785016611F, 1.785822313F, 1.786628379F, 1.787434809F, + 1.788241602F, 1.78904876F, 1.789856282F, 1.790664169F, 1.79147242F, 1.792281036F, 1.793090017F, 1.793899363F, + 1.794709075F, 1.795519152F, 1.796329595F, 1.797140403F, 1.797951578F, 1.798763118F, 1.799575025F, 1.800387298F, + 1.801199938F, 1.802012945F, 1.802826319F, 1.80364006F, 1.804454168F, 1.805268643F, 1.806083487F, 1.806898698F, + 1.807714277F, 1.808530224F, 1.809346539F, 1.810163223F, 1.810980276F, 1.811797697F, 1.812615487F, 1.813433647F, + 1.814252176F, 1.815071074F, 1.815890341F, 1.816709979F, 1.817529987F, 1.818350364F, 1.819171112F, 1.819992231F, + 1.82081372F, 1.821635579F, 1.82245781F, 1.823280412F, 1.824103385F, 1.82492673F, 1.825750446F, 1.826574535F, + 1.827398995F, 1.828223827F, 1.829049031F, 1.829874608F, 1.830700558F, 1.831526881F, 1.832353576F, 1.833180645F, + 1.834008086F, 1.834835902F, 1.835664091F, 1.836492654F, 1.83732159F, 1.838150901F, 1.838980587F, 1.839810647F, + 1.840641081F, 1.84147189F, 1.842303075F, 1.843134634F, 1.843966569F, 1.844798879F, 1.845631565F, 1.846464627F, + 1.847298065F, 1.848131879F, 1.84896607F, 1.849800636F, 1.85063558F, 1.851470901F, 1.852306598F, 1.853142673F, + 1.853979125F, 1.854815955F, 1.855653162F, 1.856490747F, 1.857328711F, 1.858167052F, 1.859005772F, 1.859844871F, + 1.860684348F, 1.861524205F, 1.86236444F, 1.863205054F, 1.864046048F, 1.864887422F, 1.865729175F, 1.866571309F, + 1.867413822F, 1.868256716F, 1.86909999F, 1.869943645F, 1.87078768F, 1.871632097F, 1.872476895F, 1.873322074F, + 1.874167634F, 1.875013576F, 1.8758599F, 1.876706606F, 1.877553694F, 1.878401165F, 1.879249018F, 1.880097254F, + 1.880945872F, 1.881794874F, 1.882644259F, 1.883494027F, 1.884344179F, 1.885194715F, 1.886045634F, 1.886896938F, + 1.887748625F, 1.888600698F, 1.889453154F, 1.890305996F, 1.891159223F, 1.892012834F, 1.892866831F, 1.893721214F, + 1.894575982F, 1.895431135F, 1.896286675F, 1.897142601F, 1.897998914F, 1.898855613F, 1.899712698F, 1.900570171F, + 1.90142803F, 1.902286277F, 1.903144911F, 1.904003932F, 1.904863342F, 1.905723139F, 1.906583324F, 1.907443898F, + 1.90830486F, 1.909166211F, 1.91002795F, 1.910890079F, 1.911752596F, 1.912615503F, 1.913478799F, 1.914342486F, + 1.915206561F, 1.916071027F, 1.916935883F, 1.91780113F, 1.918666767F, 1.919532795F, 1.920399213F, 1.921266023F, + 1.922133224F, 1.923000816F, 1.9238688F, 1.924737176F, 1.925605944F, 1.926475103F, 1.927344656F, 1.9282146F, + 1.929084938F, 1.929955668F, 1.930826791F, 1.931698307F, 1.932570217F, 1.93344252F, 1.934315217F, 1.935188308F, + 1.936061793F, 1.936935673F, 1.937809947F, 1.938684615F, 1.939559678F, 1.940435136F, 1.94131099F, 1.942187238F, + 1.943063882F, 1.943940922F, 1.944818358F, 1.94569619F, 1.946574418F, 1.947453042F, 1.948332063F, 1.949211481F, + 1.950091295F, 1.950971507F, 1.951852116F, 1.952733123F, 1.953614527F, 1.954496329F, 1.955378529F, 1.956261128F, + 1.957144124F, 1.958027519F, 1.958911313F, 1.959795506F, 1.960680098F, 1.961565089F, 1.96245048F, 1.963336271F, + 1.964222461F, 1.965109051F, 1.965996041F, 1.966883432F, 1.967771223F, 1.968659415F, 1.969548008F, 1.970437002F, + 1.971326397F, 1.972216194F, 1.973106392F, 1.973996992F, 1.974887994F, 1.975779399F, 1.976671205F, 1.977563415F, + 1.978456026F, 1.979349041F, 1.980242459F, 1.98113628F, 1.982030505F, 1.982925133F, 1.983820165F, 1.984715601F, + 1.985611441F, 1.986507685F, 1.987404335F, 1.988301388F, 1.989198847F, 1.990096711F, 1.99099498F, 1.991893654F, + 1.992792734F, 1.99369222F, 1.994592112F, 1.99549241F, 1.996393115F, 1.997294226F, 1.998195744F, 1.999097668F, + +}; + +/* Enviromental Presets. */ +EAX_REVERBPROPERTIES Sound_Enviroments[] = +{ +/* Enviroment Volume Decay Damping */ + {EAX_ENVIRONMENT_GENERIC, 0.5F, 1.493F, 0.5F}, + {EAX_ENVIRONMENT_PADDEDCELL, 0.25F, 0.1F, 0.0F}, + {EAX_ENVIRONMENT_ROOM, 0.417F, 0.4F, 0.666F}, + {EAX_ENVIRONMENT_BATHROOM, 0.653F, 1.499F, 0.166F}, + {EAX_ENVIRONMENT_LIVINGROOM, 0.208F, 0.478F, 0.0F}, + {EAX_ENVIRONMENT_STONEROOM, 0.5F, 2.309F, 0.888F}, + {EAX_ENVIRONMENT_AUDITORIUM, 0.403F, 4.279F, 0.5F}, + {EAX_ENVIRONMENT_CONCERTHALL, 0.5F, 3.961F, 0.5F}, + {EAX_ENVIRONMENT_CAVE, 0.5F, 2.886F, 1.304F}, + {EAX_ENVIRONMENT_ARENA, 0.361F, 7.284F, 0.332F}, + {EAX_ENVIRONMENT_HANGAR, 0.5F, 10.0F, 0.3F}, + {EAX_ENVIRONMENT_CARPETEDHALLWAY, 0.153F, 0.259F, 2.0F}, + {EAX_ENVIRONMENT_HALLWAY, 0.361F, 1.493F, 0.0F}, + {EAX_ENVIRONMENT_STONECORRIDOR, 0.444F, 2.697F, 0.638F}, + {EAX_ENVIRONMENT_ALLEY, 0.25F, 1.752F, 0.776F}, + {EAX_ENVIRONMENT_FOREST, 0.111F, 3.145F, 0.472F}, + {EAX_ENVIRONMENT_CITY, 0.111F, 2.767F, 0.224F}, + {EAX_ENVIRONMENT_MOUNTAINS, 0.194F, 7.841F, 0.472F}, + {EAX_ENVIRONMENT_QUARRY, 1.0F, 1.499F, 0.5F}, + {EAX_ENVIRONMENT_PLAIN, 0.097F, 2.767F, 0.224F}, + {EAX_ENVIRONMENT_PARKINGLOT, 0.208F, 1.652F, 1.5F}, + {EAX_ENVIRONMENT_SEWERPIPE, 0.652F, 2.886F, 0.25F}, + {EAX_ENVIRONMENT_UNDERWATER, 1.0F, 1.499F, 0.0F}, + {EAX_ENVIRONMENT_DRUGGED, 0.875F, 8.392F, 1.388F}, + {EAX_ENVIRONMENT_DIZZY, 0.139F, 17.234F,0.666F}, + {EAX_ENVIRONMENT_PSYCHOTIC, 0.486F, 7.563F, 0.806F}, + {EAX_ENVIRONMENT_PLAIN, 0.0F, 0.1F, 0.5F} +}; + +// Extra enumeration we have made up. +enum +{ + EAX_ENVIRONMENT_DEFAULT = EAX_ENVIRONMENT_PSYCHOTIC + 1, + EAX_MAX +}; + +static unsigned int SoundMaxHW; +extern int GlobalFrameCounter; + +// Test. +LPDIRECTSOUNDBUFFER NullDSBufferP = NULL; +LPDIRECTSOUND3DBUFFER NullDS3DBufferP = NULL; +/* Patrick 5/6/97 ------------------------------------------------------------- + Internal functions + ----------------------------------------------------------------------------*/ +static int PlatChangeSoundPan(int activeIndex, int pan); +static int ToneToFrequency(int currentFrequency, int currentPitch, int newPitch); + +/* Patrick 5/6/97 ------------------------------------------------------------- + External references + ----------------------------------------------------------------------------*/ +extern HWND hWndMain; +extern DISPLAYBLOCK *Player; +extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + +/* Patrick 5/6/97 ------------------------------------------------------------- + Function definitions + ----------------------------------------------------------------------------*/ +int PlatStartSoundSys(void) +{ + HRESULT hres; + DSCAPS caps; + + db_log4("PlatStartSound called"); + LOG_RC(); + + /* Set the globals. */ + SoundConfig.flags = SOUND_DEFAULT; + SoundConfig.reverb_changed = TRUE; + SoundConfig.reverb_mix = 0.0F; + SoundConfig.env_index = 1000; + + /* Create the ds object */ + hres = DirectSoundCreate(NULL,&DSObject,NULL); + if(hres!=DS_OK) + { + PlatEndSoundSys(); + return 0; + } + + db_log5("Made DSO"); + LOG_RC(); + + /* Set cooperative level */ + hres = IDirectSound_SetCooperativeLevel(DSObject, hWndMain, DSSCL_PRIORITY); + if(hres!=DS_OK) + { + PlatEndSoundSys(); + return 0; + } + + /* Create primary buffer & set format */ + { + DSBUFFERDESC dsBuffDesc; + WAVEFORMATEX wfex; + + /* set format description */ + memset(&wfex, 0, sizeof(WAVEFORMATEX)); + wfex.wFormatTag = WAVE_FORMAT_PCM; + wfex.nChannels = 2; + wfex.nSamplesPerSec = 22050; + wfex.nBlockAlign = 4; + wfex.nAvgBytesPerSec = + wfex.nSamplesPerSec * wfex.nBlockAlign; + wfex.wBitsPerSample = 16; + wfex.cbSize = 0; + + /* set buffer description */ + memset(&dsBuffDesc,0,sizeof(DSBUFFERDESC)); + dsBuffDesc.dwSize = sizeof(DSBUFFERDESC); + dsBuffDesc.dwFlags = (DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D | DSBCAPS_LOCHARDWARE | DSBCAPS_CTRLVOLUME); + dsBuffDesc.dwBufferBytes = 0; + dsBuffDesc.lpwfxFormat = NULL; + + hres = IDirectSound_CreateSoundBuffer(DSObject, &dsBuffDesc, &DSPrimaryBuffer, NULL); + if(hres!=DS_OK) + { + PlatEndSoundSys(); + return 0; + } + + hres = IDirectSoundBuffer_SetFormat(DSPrimaryBuffer, &wfex); + /* If the format set failed just continue with the default format */ + } + + db_log5("Make DSPB"); + LOG_RC(); + + /* Get and log some caps. */ + ZeroMemory(&caps, sizeof(DSCAPS)); + caps.dwSize = sizeof(DSCAPS); + + IDirectSound_GetCaps(DSObject, &caps); + + db_logf1(("Number of HW buffers %i", caps.dwMaxHwMixingStaticBuffers)); + db_logf1(("Number of HW 3D buffers %i", caps.dwFreeHw3DStaticBuffers)); + if(caps.dwFreeHw3DStaticBuffers) + { + SoundConfig.flags |= (SOUND_3DHW | SOUND_USE_3DHW); + } + if(caps.dwMaxHwMixingStaticBuffers) + { + SoundMaxHW = min(caps.dwMaxHwMixingStaticBuffers - 1,SOUND_MAXACTIVE); // Always leave one free. + } + else + { + SoundMaxHW = 0; + } + SoundMinBufferFree = SoundMaxHW / 2; + + /* Create a Listener. */ + hres = IDirectSoundBuffer_QueryInterface(DSPrimaryBuffer, &IID_IDirectSound3DListener, (void **) &DS3DListener); + if(hres!=DS_OK) + { + PlatEndSoundSys(); + return 0; + } + + db_log5("Made a DS3DL"); + LOG_RC(); + + /* Set the Listener's data. */ + { + DS3DLISTENER listener; + memset(&listener, 0, sizeof(DS3DLISTENER)); + listener.dwSize = sizeof(DS3DLISTENER); + listener.vPosition.x = 0.0F; + listener.vPosition.y = 0.0F; + listener.vPosition.z = 0.0F; + listener.vVelocity.x = 0.0F; + listener.vVelocity.y = 0.0F; + listener.vVelocity.z = 0.0F; + listener.vOrientFront.x = 0.0F; + listener.vOrientFront.y = 0.0F; + listener.vOrientFront.z = 1.0F; + listener.vOrientTop.x = 0.0F; + listener.vOrientTop.y = -1.0F; + listener.vOrientTop.z = 0.0F; + listener.flDistanceFactor = 0.001F; + listener.flRolloffFactor = 0.0F; + listener.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR; + hres = IDirectSound3DListener_SetAllParameters(DS3DListener, &listener, DS3D_IMMEDIATE); + if(hres!=DS_OK) + { + PlatEndSoundSys(); + return 0; + } + } + + /* Create a NULL secondary buffer. */ + { + DSBUFFERDESC dsBuffDesc; + WAVEFORMATEX wfex; + + /* Set buffer desciption. */ + memset(&dsBuffDesc, 0, sizeof(DSBUFFERDESC)); + dsBuffDesc.dwSize = sizeof(DSBUFFERDESC); + dsBuffDesc.dwFlags = (DSBCAPS_STATIC | DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE); + dsBuffDesc.dwBufferBytes = 8; + dsBuffDesc.lpwfxFormat = &wfex; + + /* Set the format. */ + wfex.wFormatTag = WAVE_FORMAT_PCM; + wfex.nChannels = 1; + wfex.nSamplesPerSec = 11025; + wfex.nBlockAlign = 1; + wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign; + wfex.wBitsPerSample = 8; + wfex.cbSize = 0; + + hres = IDirectSound_CreateSoundBuffer(DSObject, &dsBuffDesc, &NullDSBufferP, NULL); + if(hres!=DS_OK) + { + PlatEndSoundSys(); + return 0; + } + + /* Get the 3D Buffer. */ + hres = IDirectSoundBuffer_QueryInterface(NullDSBufferP, &IID_IDirectSound3DBuffer, (void **) &NullDS3DBufferP); + if(hres!=DS_OK) + { + PlatEndSoundSys(); + return 0; + } + + IDirectSound_GetCaps(DSObject, &caps); + + db_logf1(("Number of HW buffers %i", caps.dwMaxHwMixingStaticBuffers)); + db_logf1(("Number of HW 3D buffers %i", caps.dwFreeHw3DStaticBuffers)); + + /* Get the Property set. */ + hres = IDirectSound3DBuffer_QueryInterface + ( + NullDS3DBufferP, + &IID_IKsPropertySet, + (void**) &PropSetP + ); + if(hres != DD_OK) + { + /* No property set. */ + db_log1("Error: Failed to get the property set."); + } + + db_log5("Made a PropSet"); + LOG_RC(); + + /* Test for the property set we want to use. */ + if(PropSetP) + { + unsigned long support; + + /* Voice Management. */ + IKsPropertySet_QuerySupport + ( + PropSetP, + &DSPROPSETID_VoiceManager, + DSPROPERTY_VMANAGER_MODE, + &support + ); + + if(support == (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET)) + { + VmMode mode = DSPROPERTY_VMANAGER_MODE_AUTO; + + db_log1("Voice Management active."); + SoundConfig.flags |= SOUND_VOICE_MGER; + + // Set the mode we want. + hres = IKsPropertySet_Set + ( + PropSetP, + &DSPROPSETID_VoiceManager, + DSPROPERTY_VMANAGER_MODE, + NULL, + 0, + &mode, + sizeof(VmMode) + ); + } + else + { + db_logf1(("No voice management. Support %x", support)); + } + + /* EAX support. */ + IKsPropertySet_QuerySupport + ( + PropSetP, + &DSPROPSETID_EAX_ReverbProperties, + DSPROPERTY_EAX_ALL, + &support + ); + + if(support == (KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET)) + { + db_log1("EAX suppport."); + SoundConfig.flags |= SOUND_EAX; + + // Set a default value. + PlatSetEnviroment(EAX_ENVIRONMENT_DEFAULT, EAX_REVERBMIX_USEDISTANCE); + } + else + { + db_logf1(("No EAX support. Support %x", support)); + } + } + + /* If we have Voice Management release everything and reaquire to free up one buffer. */ + if(SoundConfig.flags & SOUND_VOICE_MGER) + { + IDirectSound_GetCaps(DSObject, &caps); + + db_logf1(("Number of HW buffers %i", caps.dwMaxHwMixingStaticBuffers)); + db_logf1(("Number of HW 3D buffers %i", caps.dwFreeHw3DStaticBuffers)); + + /* Release the Property Set. */ + IKsPropertySet_Release(PropSetP); + PropSetP = NULL; + + /* Release the Null buffers. */ + if(NullDS3DBufferP) + { + IDirectSoundBuffer_Release(NullDS3DBufferP); + NullDS3DBufferP = NULL; + } + + if(NullDSBufferP) + { + IDirectSoundBuffer_Release(NullDSBufferP); + NullDSBufferP = NULL; + } + + /* Remake the buffers. */ + hres = IDirectSound_CreateSoundBuffer(DSObject, &dsBuffDesc, &NullDSBufferP, NULL); + if(hres!=DS_OK) + { + db_log1("Error: Remaking buffer."); + } + + hres = IDirectSoundBuffer_QueryInterface(NullDSBufferP, &IID_IDirectSound3DBuffer, (void **) &NullDS3DBufferP); + if(hres!=DS_OK) + { + db_log1("Error: Remaking buffer."); + } + + /* Get the Property set. */ + hres = IDirectSound3DBuffer_QueryInterface + ( + NullDS3DBufferP, + &IID_IKsPropertySet, + (void**) &PropSetP + ); + if(hres != DD_OK) + { + /* No property set. */ + db_log1("Error: Failed to get the property set again."); + } + + /* Now recheck the number of free buffers. */ + IDirectSound_GetCaps(DSObject, &caps); + + db_logf1(("Number of HW buffers %i", caps.dwMaxHwMixingStaticBuffers)); + db_logf1(("Number of HW 3D buffers %i", caps.dwFreeHw3DStaticBuffers)); + if(caps.dwMaxHwMixingStaticBuffers) + { + SoundMaxHW = min(caps.dwMaxHwMixingStaticBuffers - 1,SOUND_MAXACTIVE); // Always leave one free. + } + else + { + SoundMaxHW = 0; + } + SoundMinBufferFree = SoundMaxHW / 2; + } + + /* Do we need the property set. */ + if(PropSetP && (~SoundConfig.flags & SOUND_EAX) && (~SoundConfig.flags & SOUND_VOICE_MGER)) + { + IKsPropertySet_Release(PropSetP); + PropSetP = NULL; + db_log1("Releasing the property set."); + } + + } + + /* Play the primary buffer */ + hres = IDirectSoundBuffer_Play(DSPrimaryBuffer,0,0,DSBPLAY_LOOPING); + if(hres!=DS_OK) + { + PlatEndSoundSys(); + return 0; + } + + db_log4("PlatStartSound finished"); + LOG_RC(); + + return 1; +} +void ResetEaxEnvironment(void) +{ + // Set a default value. + PlatSetEnviroment(EAX_ENVIRONMENT_DEFAULT, EAX_REVERBMIX_USEDISTANCE); +} + +void PlatEndSoundSys(void) +{ + HRESULT hres; + + db_log3("PlatEndSoundSys called."); + LOG_RC(); + + if(PropSetP) + { + IKsPropertySet_Release(PropSetP); + PropSetP = NULL; + } + + db_log5("Released the PS"); + LOG_RC(); + + if(DS3DListener) + { + IDirectSound3DListener_Release(DS3DListener); + DS3DListener = NULL; + } + + db_log5("Released the DSL"); + LOG_RC(); + + if(NullDS3DBufferP) + { + IDirectSoundBuffer_Release(NullDS3DBufferP); + NullDS3DBufferP = NULL; + } + + if(NullDSBufferP) + { + IDirectSoundBuffer_Release(NullDSBufferP); + NullDSBufferP = NULL; + } + + db_log5("Released the last buffers"); + LOG_RC(); + + if(DSPrimaryBuffer) + { + hres = IDirectSoundBuffer_Stop(DSPrimaryBuffer); + hres = IDirectSoundBuffer_Release(DSPrimaryBuffer); + DSPrimaryBuffer = NULL; + } + + db_log5("Released the Primary Buffer."); + LOG_RC(); + + if(DSObject) + { + hres = IDirectSound_Release(DSObject); + DSObject = NULL; + } + + db_log5("Released the sodding lot."); + LOG_RC(); + + db_log3("PlatEndSoundSys finished."); +} + +int PlatChangeGlobalVolume(volume) +{ + int attenuation; + HRESULT hres; + LOCALASSERT((volume>=VOLUME_MIN)&&(volume<=VOLUME_MAX)); + + /* convert from intensity to attenuation: + see comment for PLATCHANGEVOLUME to see how this works */ + if(volume == VOLUME_MIN) attenuation = VOLUME_MINPLAT; + else if(volume == VOLUME_MAX) attenuation = VOLUME_MAXPLAT; + else if(volume <(VOLUME_MAX>>4)) attenuation = ((3000*volume)>>3)-7000; + else if(volume <(VOLUME_MAX>>3)) attenuation = ((1000*(volume-(VOLUME_MAX>>4)))>>3)-4000; + else if(volume <(VOLUME_MAX>>2)) attenuation = ((1000*(volume-(VOLUME_MAX>>3)))>>4)-3000; + else if(volume <(VOLUME_MAX>>1)) attenuation = ((1000*(volume-(VOLUME_MAX>>2)))>>5)-2000; + else if(volume >1)))>>6)-1000; + + if(attenuation>VOLUME_MAXPLAT) attenuation=VOLUME_MAXPLAT; + if(attenuation=0)||(activeIndex=0)&&(gameIndex>7; + ActiveSounds[activeIndex].volume = newVolume; + + ok = PlatChangeSoundVolume(activeIndex, ActiveSounds[activeIndex].volume); + if(ok==SOUND_PLATFORMERROR) + { + PlatStopSound(activeIndex); + return SOUND_PLATFORMERROR; + } + } + + if(ActiveSounds[activeIndex].PropSetP) + { + HRESULT res; + if(!ActiveSounds[activeIndex].reverb_off) + { + res = IKsPropertySet_Set + ( + ActiveSounds[activeIndex].PropSetP, + &DSPROPSETID_EAXBUFFER_ReverbProperties, + DSPROPERTY_EAXBUFFER_REVERBMIX, + NULL, + 0, + &SoundConfig.reverb_mix, + sizeof(float) + ); + } + else + { + float temp =0; + res = IKsPropertySet_Set + ( + ActiveSounds[activeIndex].PropSetP, + &DSPROPSETID_EAXBUFFER_ReverbProperties, + DSPROPERTY_EAXBUFFER_REVERBMIX, + NULL, + 0, + &temp, + sizeof(float) + ); + } + + if(res != DD_OK) + { + db_logf3(("Error: Failed to set the buffer property set at play start. res %x", res)); + } + } + + db_logf4(("RefCount after PlaySound %i, Active Inst %i, activeIndex %i", GET_REF_COUNT(ActiveSounds[activeIndex].PropSetP), GameSounds[gameIndex].activeInstances, activeIndex)); + + // IDirectSound3DListener_CommitDeferredSettings(DS3DListener); + + /* play the buffer then... */ + if (!ActiveSounds[activeIndex].paused) + { + DWORD flags = 0; + if(ActiveSounds[activeIndex].loop) + { + flags|= DSBPLAY_LOOPING; + } + hres = IDirectSoundBuffer_Play(ActiveSounds[activeIndex].dsBufferP,0,0,flags); + if(hres!=DS_OK) + { + if(GameSounds[gameIndex].flags & SAMPLE_IN_HW) + { + db_log3("Failed to play a sample in Hardware"); + } + else + { + db_log3("Failed to play a sample from Software."); + } + return SOUND_PLATFORMERROR; + } + + /* success */ + if(ActiveSounds[activeIndex].loop) + { + db_logf5(("Playing Sound %i looping in slot %i on frame %i", ActiveSounds[activeIndex].soundIndex, activeIndex, GlobalFrameCounter)); + } + else + { + db_logf5(("Playing Sound %i once in slot %i on frame %i", ActiveSounds[activeIndex].soundIndex, activeIndex, GlobalFrameCounter)); + } + } + + return 1; + +} + +void PlatStopSound(int activeIndex) +{ + HRESULT hres; + + db_logf5(("Stopping Sound %i in slot %i on frame %i", ActiveSounds[activeIndex].soundIndex, activeIndex, GlobalFrameCounter)); + + if(!(ActiveSounds[activeIndex].dsBufferP)) return; + + if (!ActiveSounds[activeIndex].paused) + hres = IDirectSoundBuffer_Stop(ActiveSounds[activeIndex].dsBufferP); + + db_logf4(("RefCount before StopSound %i, activeIndex %i", GET_REF_COUNT(ActiveSounds[activeIndex].PropSetP), activeIndex)); + if(ActiveSounds[activeIndex].PropSetP) + { + IKsPropertySet_Release(ActiveSounds[activeIndex].PropSetP); + ActiveSounds[activeIndex].PropSetP = NULL; + } + + if(ActiveSounds[activeIndex].ds3DBufferP) + { + IDirectSound3DBuffer_Release(ActiveSounds[activeIndex].ds3DBufferP); + ActiveSounds[activeIndex].ds3DBufferP = NULL; + } + + IDirectSoundBuffer_Release(ActiveSounds[activeIndex].dsBufferP); + ActiveSounds[activeIndex].dsBufferP = NULL; +} + +/* Patrick 15/6/97 ------------------------------------------------------------- + The standard volume interface in PSND is a linear intensity scale, matching the + PSX's scale. However, ds uses a logarithmic scale: + Atenuation = 10 log(2) (I/I0). + We should therefore convert from intensity to attenuation... + I have cheated here, and used a sequence of linear approximations between + power-of-two intensity values.... + NB an attenuation of 70db is about 1% of full volume; + ----------------------------------------------------------------------------*/ +int PlatChangeSoundVolume(int activeIndex, int volume) +{ + signed int attenuation; + HRESULT hres; + LOCALASSERT(ActiveSounds[activeIndex].dsBufferP); + if(volumeVOLUME_MAX) volume=VOLUME_MAX; + + /* convert from intensity to attenuation */ + attenuation = vol_to_atten_table[volume]; + + if(attenuation>VOLUME_MAXPLAT) attenuation=VOLUME_MAXPLAT; + if(attenuation=PITCH_MIN)&&(pitch<=PITCH_MAX)); + + /* calculate new frequency from base pitch for game sound + (NB don't need to scale pitch values...) */ + + /* default pitch is a special case in ds */ + if(pitch==PITCH_DEFAULTPLAT) frequency=0; + else + { + SOUNDINDEX gameSoundIndex = ActiveSounds[activeIndex].soundIndex; + frequency = ToneToFrequency(GameSounds[gameSoundIndex].dsFrequency, + GameSounds[gameSoundIndex].pitch, pitch); + } + + ActiveSounds[activeIndex].pitch = pitch; + hres = IDirectSoundBuffer_SetFrequency(ActiveSounds[activeIndex].dsBufferP,frequency); + if(hres==DS_OK) return 1; + else return SOUND_PLATFORMERROR; + return 1; +} + +int PlatSoundHasStopped(int activeIndex) +{ + HRESULT hres; + DWORD status = 0; + + LOCALASSERT(ActiveSounds[activeIndex].dsBufferP); + hres = IDirectSoundBuffer_GetStatus(ActiveSounds[activeIndex].dsBufferP,&status); + if(hres==DS_OK) + { + if(status&DSBSTATUS_BUFFERLOST) + { + return SOUND_PLATFORMERROR; + } + if(status&DSBSTATUS_PLAYING) + { + return 0; + } + else + { + return 1; + } + } + + return SOUND_PLATFORMERROR; +} + +int PlatDo3dSound(int activeIndex) +{ + int distance; + VECTORCH relativePosn; + HRESULT hres; + int newVolume; + int newPan; + + /* find the distance of the sound */ + relativePosn.vx = ActiveSounds[activeIndex].threedeedata.position.vx - Global_VDB_Ptr->VDB_World.vx; + relativePosn.vy = ActiveSounds[activeIndex].threedeedata.position.vy - Global_VDB_Ptr->VDB_World.vy; + relativePosn.vz = ActiveSounds[activeIndex].threedeedata.position.vz - Global_VDB_Ptr->VDB_World.vz; + distance = Magnitude(&relativePosn); + + db_logf5(("Sound Index %i", ActiveSounds[activeIndex].soundIndex)); + db_logf5(("Global Player Posn (%i, %i, %i)", Global_VDB_Ptr->VDB_World.vx, Global_VDB_Ptr->VDB_World.vy, Global_VDB_Ptr->VDB_World.vz)); + db_logf5(("Sound Posn (%i, %i, %i)", ActiveSounds[activeIndex].threedeedata.position.vx, ActiveSounds[activeIndex].threedeedata.position.vy, ActiveSounds[activeIndex].threedeedata.position.vz)); + db_logf5(("Relative Posn (%i, %i, %i)", relativePosn.vx, relativePosn.vy, relativePosn.vz)); + db_logf5(("distance %i", distance)); + db_logf5(("range (%i, %i)", ActiveSounds[activeIndex].threedeedata.inner_range, ActiveSounds[activeIndex].threedeedata.outer_range)); + + /* Deal with paused looping sounds. */ + if(ActiveSounds[activeIndex].paused) + { + if(distance < (ActiveSounds[activeIndex].threedeedata.outer_range + SOUND_DEACTIVATERANGE)) + { + DWORD flags = 0; + GLOBALASSERT (ActiveSounds[activeIndex].dsBufferP); + if(ActiveSounds[activeIndex].loop) + { + flags|= DSBPLAY_LOOPING; + } + IDirectSoundBuffer_Play(ActiveSounds[activeIndex].dsBufferP,0,0,flags); + newVolume = 0; + ActiveSounds[activeIndex].paused = 0; + } + else + { + return 1; + } + } + + if(distance < ActiveSounds[activeIndex].threedeedata.inner_range) + { + newVolume = ActiveSounds[activeIndex].volume; + } + else + { + if(distance < ActiveSounds[activeIndex].threedeedata.outer_range) + { + /* Use proper 3D, but our own attenuation. */ + float in_to_dis_to_out = ActiveSounds[activeIndex].threedeedata.outer_range - distance; + float in_to_out = ActiveSounds[activeIndex].threedeedata.outer_range - ActiveSounds[activeIndex].threedeedata.inner_range; + + if (in_to_out > 0.0) + { + newVolume = (int) + ((float)ActiveSounds[activeIndex].volume * (in_to_dis_to_out / in_to_out)); + } + else + { + newVolume = 0; + } + } + else + { + newVolume = 0; + + /* Deal with looping sounds. */ + if((distance < (ActiveSounds[activeIndex].threedeedata.outer_range + SOUND_DEACTIVATERANGE)) && + ActiveSounds[activeIndex].loop) + { + hres = IDirectSoundBuffer_Stop(ActiveSounds[activeIndex].dsBufferP); + if (hres == DS_OK) + { + ActiveSounds[activeIndex].paused = 1; + } + else + { + textprint ("Error stopping sound\n"); + } + } + } + } + + if(newVolume>VOLUME_MAX) newVolume=VOLUME_MAX; + if(newVolume=Player->ObEuler.EulerY) angle-=Player->ObEuler.EulerY; + else angle += (4096-Player->ObEuler.EulerY); + LOCALASSERT((angle>=0)&&(angle<=4095)); + + /* map angle to range +- 1024 */ + if(angle>1024) + { + if(angle<=3072) angle = (2048-angle); /*quadrants 2 & 3*/ + else angle = (angle-4096); /* quadrant 4 */ + } + LOCALASSERT((angle>=-1024)&&(angle<=1024)); + /* now scale pan to angle */ + newPan = (PAN_MAXPLAT*angle)>>10; + + /* now damp pan for close objects, so we don't get such a sharp contrast moving + through a 3d object. */ + if((distance=SID_MAXIMUM)) return; /* no such sound */ + LOCALASSERT(GameSounds[index].loaded); + LOCALASSERT(GameSounds[index].dsBufferP); + if(GameSounds[index].dsBufferP) + { + IDirectSoundBuffer_Release(GameSounds[index].dsBufferP); + GameSounds[index].dsBufferP = NULL; + } + GameSounds[index].dsFrequency = 0; + GameSounds[index].loaded = 0; + if (GameSounds[index].wavName) + { + DeallocateMem (GameSounds[index].wavName); + GameSounds[index].wavName=0; + } +} + +/* Patrick 5/6/97 ------------------------------------------------------------- + Change pan function is internal to this file, since it is only needed for + doing 3d effects. Consequently, the parameter is not scaled to external + values, but to platform range. + ----------------------------------------------------------------------------*/ +static int PlatChangeSoundPan(int activeIndex, int pan) +{ + HRESULT hres; + LOCALASSERT(ActiveSounds[activeIndex].dsBufferP); + + if(pan>PAN_MAXPLAT) pan=PAN_MAXPLAT; + if(panPITCH_MAXPLAT) GameSounds[soundNum].pitch=PITCH_MAXPLAT; + if(GameSounds[soundNum].pitch SOUND_MAXSIZE)) + { + LOCALASSERT(1==0); + fclose(myFile); + return 0; + } + if(myWaveFormat.wFormatTag != WAVE_FORMAT_PCM) + { + LOCALASSERT(1==0); + fclose(myFile); + return 0; + } + if((myWaveFormat.nChannels != 1)&&(myWaveFormat.nChannels != 2)) + { + LOCALASSERT(1==0); + fclose(myFile); + return 0; + } + if((myWaveFormat.wBitsPerSample != 8)&&(myWaveFormat.wBitsPerSample != 16)) + { + LOCALASSERT(1==0); + fclose(myFile); + return 0; + } + + { + /* Now set the buffer description and make a sound object */ + DSBUFFERDESC dsBuffDesc; + LPDIRECTSOUNDBUFFER sndBuffer; + HRESULT hres; + LPVOID audioPtr1; + DWORD audioBytes1; + LPVOID audioPtr2; + DWORD audioBytes2; + + memset(&dsBuffDesc,0,sizeof(DSBUFFERDESC)); + dsBuffDesc.dwSize = sizeof(DSBUFFERDESC); + dsBuffDesc.dwFlags = (DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC); + dsBuffDesc.dwBufferBytes = myChunkHeader.chunkLength; + dsBuffDesc.lpwfxFormat = &myWaveFormat; + + /* Do we need to specify 3D. */ + if(SoundConfig.flags & SOUND_3DHW) + { + dsBuffDesc.dwFlags |= DSBCAPS_CTRL3D; + } + + /* If we have no Voice Manager support we must leave some hardware buffers free. */ + if(SoundConfig.flags & SOUND_VOICE_MGER) + { + // Do nothing for the moment. + } + else + { + /* No Voice Manager. */ + DSCAPS caps; + ZeroMemory(&caps, sizeof(DSCAPS)); + caps.dwSize = sizeof(DSCAPS); + + IDirectSound_GetCaps(DSObject, &caps); + db_logf5(("caps.dwFreeHwMixingStaticBuffers %i SoundMinBufferFree %i",caps.dwFreeHwMixingStaticBuffers, SoundMinBufferFree)); + if(caps.dwFreeHwMixingStaticBuffers < SoundMinBufferFree) + { + /* Force to software. */ + db_log3("Forcing buffer to software."); + dsBuffDesc.dwFlags |= DSBCAPS_LOCSOFTWARE; + } + } + + /* Create the Direct Sound buffer for this sound */ + hres = IDirectSound_CreateSoundBuffer(DSObject,&dsBuffDesc,&sndBuffer,NULL); + if(hres != DS_OK) + { + LOCALASSERT(1==0); + fclose(myFile); + return 0; + } + + /* Lock the buffer to allow the write */ + hres = IDirectSoundBuffer_Lock(sndBuffer,0,myChunkHeader.chunkLength, + &audioPtr1,&audioBytes1,&audioPtr2,&audioBytes2,0); + if((hres!=DS_OK)||(audioPtr2 != NULL)) + { + LOCALASSERT(1==0); + IDirectSoundBuffer_Release(sndBuffer); + fclose(myFile); + return 0; + } + + /* Read data from file to buffer */ + res = fread(audioPtr1,1,myChunkHeader.chunkLength,myFile); + if(res != (size_t)myChunkHeader.chunkLength) + { + LOCALASSERT(1==0); + IDirectSoundBuffer_Release(sndBuffer); + fclose(myFile); + return 0; + } + /* then unlock it and close the file */ + hres = IDirectSoundBuffer_Unlock(sndBuffer,audioPtr1,audioBytes1,audioPtr2,audioBytes2); + if (hres!=DS_OK) + { + LOCALASSERT(1==0); + IDirectSoundBuffer_Release(sndBuffer); + fclose(myFile); + return 0; + } + /* Finally, put a pointer the the buffer into the sound data */ + GameSounds[soundNum].dsBufferP = sndBuffer; + { + char * wavname = strrchr (wavFileName, '\\'); + if (wavname) + { + wavname ++; + } + else + { + wavname = wavFileName; + } + + GameSounds[soundNum].wavName = (char *)AllocateMem (strlen (wavname) + 1); + strcpy (GameSounds[soundNum].wavName, wavname); + } + + /* Log it's position. */ + { + DSBCAPS caps; + ZeroMemory(&caps, sizeof(DSBCAPS)); + caps.dwSize = sizeof(DSBCAPS); + IDirectSoundBuffer_GetCaps(sndBuffer, &caps); + + if(caps.dwFlags & DSBCAPS_LOCHARDWARE) + { + GameSounds[soundNum].flags = SAMPLE_IN_HW; + db_logf3(("Sound %s loaded into hardware slot %i by LoadWavFile.", GameSounds[soundNum].wavName, soundNum)); + } + else + { + GameSounds[soundNum].flags = SAMPLE_IN_SW; + db_logf3(("Sound %s loaded into software slot %i by LoadWavFile.", GameSounds[soundNum].wavName, soundNum)); + } + } + GameSounds[soundNum].length=lengthInSeconds; + } + + fclose(myFile); + return 1; +} +/*identical to above function except it loads from fast files*/ +int LoadWavFromFastFile(int soundNum, char * wavFileName) +{ + PWAVCHUNKHEADER myChunkHeader; + PWAVRIFFHEADER myRiffHeader; + FFILE *myFile; + WAVEFORMATEX myWaveFormat; + size_t res; + int lengthInSeconds; + + myFile = ffopen(wavFileName,"rb"); + if(!myFile) + { + GLOBALASSERT (0); + return(0); + } + + /* Read the WAV RIFF header */ + res = ffread(&myChunkHeader,sizeof(PWAVCHUNKHEADER),1,myFile); + res = ffread(&myRiffHeader,sizeof(PWAVRIFFHEADER),1,myFile); + + /* Read the WAV format chunk */ + res = ffread(&myChunkHeader,sizeof(PWAVCHUNKHEADER),1,myFile); + if(myChunkHeader.chunkLength==16) + { + /* a standard PCM wave format chunk */ + PCMWAVEFORMAT tmpWaveFormat; + res = ffread(&tmpWaveFormat,sizeof(PCMWAVEFORMAT),1,myFile); + myWaveFormat.wFormatTag = tmpWaveFormat.wf.wFormatTag; + myWaveFormat.nChannels = tmpWaveFormat.wf.nChannels; + myWaveFormat.nSamplesPerSec = tmpWaveFormat.wf.nSamplesPerSec;; + myWaveFormat.nAvgBytesPerSec = tmpWaveFormat.wf.nAvgBytesPerSec; + myWaveFormat.nBlockAlign = tmpWaveFormat.wf.nBlockAlign; + myWaveFormat.wBitsPerSample = tmpWaveFormat.wBitsPerSample; + myWaveFormat.cbSize = 0; + } + else if(myChunkHeader.chunkLength==18) + { + /* an extended PCM wave format chunk */ + res = ffread(&myWaveFormat,sizeof(WAVEFORMATEX),1,myFile); + myWaveFormat.cbSize = 0; + } + else + { + /* uh oh: a different chunk type */ + LOCALASSERT(1==0); + ffclose(myFile); + return 0; + } + + /* Read the data chunk header */ + //skip chunks until we reach the 'data' chunk + do + { + /* Read the data chunk header */ + res = ffread(&myChunkHeader,sizeof(PWAVCHUNKHEADER),1,myFile); + if((myChunkHeader.chunkName[0]=='d')&&(myChunkHeader.chunkName[1]=='a')&& + (myChunkHeader.chunkName[2]=='t')&&(myChunkHeader.chunkName[3]=='a')) + { + break; + } + + ffseek(myFile,myChunkHeader.chunkLength,SEEK_CUR); + }while(res); + + /* Now do a few checks */ + if((myChunkHeader.chunkName[0]!='d')||(myChunkHeader.chunkName[1]!='a')|| + (myChunkHeader.chunkName[2]!='t')||(myChunkHeader.chunkName[3]!='a')) + { + /* chunk alignment disaster */ + LOCALASSERT(1==0); + ffclose(myFile); + return 0; + } + + //calculate length of sample + lengthInSeconds=DIV_FIXED(myChunkHeader.chunkLength,myWaveFormat.nAvgBytesPerSec); + + if((myChunkHeader.chunkLength<0)||(myChunkHeader.chunkLength > SOUND_MAXSIZE)) + { + LOCALASSERT(1==0); + ffclose(myFile); + return 0; + } + if(myWaveFormat.wFormatTag != WAVE_FORMAT_PCM) + { + LOCALASSERT(1==0); + ffclose(myFile); + return 0; + } + if((myWaveFormat.nChannels != 1)&&(myWaveFormat.nChannels != 2)) + { + LOCALASSERT(1==0); + ffclose(myFile); + return 0; + } + if((myWaveFormat.wBitsPerSample != 8)&&(myWaveFormat.wBitsPerSample != 16)) + { + LOCALASSERT(1==0); + ffclose(myFile); + return 0; + } + + { + /* Now set the buffer description and make a sound object */ + DSBUFFERDESC dsBuffDesc; + LPDIRECTSOUNDBUFFER sndBuffer; + HRESULT hres; + LPVOID audioPtr1; + DWORD audioBytes1; + LPVOID audioPtr2; + DWORD audioBytes2; + + memset(&dsBuffDesc,0,sizeof(DSBUFFERDESC)); + dsBuffDesc.dwSize = sizeof(DSBUFFERDESC); + dsBuffDesc.dwFlags = (DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC); + dsBuffDesc.dwBufferBytes = myChunkHeader.chunkLength; + dsBuffDesc.lpwfxFormat = &myWaveFormat; + + /* Do we need to specify 3D. */ + if(SoundConfig.flags & SOUND_3DHW) + { + dsBuffDesc.dwFlags |= DSBCAPS_CTRL3D; + } + + /* If we have no Voice Manager support we must leave some hardware buffers free. */ + if(SoundConfig.flags & SOUND_VOICE_MGER) + { + // Do nothing for the moment. + } + else + { + /* No Voice Manager. */ + DSCAPS caps; + ZeroMemory(&caps, sizeof(DSCAPS)); + caps.dwSize = sizeof(DSCAPS); + + IDirectSound_GetCaps(DSObject, &caps); + db_logf5(("caps.dwFreeHwMixingStaticBuffers %i SoundMinBufferFree %i",caps.dwFreeHwMixingStaticBuffers, SoundMinBufferFree)); + if(caps.dwFreeHwMixingStaticBuffers < SoundMinBufferFree) + { + /* Force to software. */ + db_log3("Forcing buffer to software."); + dsBuffDesc.dwFlags |= DSBCAPS_LOCSOFTWARE; + } + } + + /* Create the Direct Sound buffer for this sound */ + hres = IDirectSound_CreateSoundBuffer(DSObject,&dsBuffDesc,&sndBuffer,NULL); + if(hres != DS_OK) + { + LOCALASSERT(1==0); + ffclose(myFile); + return 0; + } + + /* Lock the buffer to allow the write */ + hres = IDirectSoundBuffer_Lock(sndBuffer,0,myChunkHeader.chunkLength, + &audioPtr1,&audioBytes1,&audioPtr2,&audioBytes2,0); + if((hres!=DS_OK)||(audioPtr2 != NULL)) + { + LOCALASSERT(1==0); + IDirectSoundBuffer_Release(sndBuffer); + ffclose(myFile); + return 0; + } + + /* Read data from file to buffer */ + res = ffread(audioPtr1,1,myChunkHeader.chunkLength,myFile); + if(res != (size_t)myChunkHeader.chunkLength) + { + LOCALASSERT(1==0); + IDirectSoundBuffer_Release(sndBuffer); + ffclose(myFile); + return 0; + } + /* then unlock it and close the file */ + hres = IDirectSoundBuffer_Unlock(sndBuffer,audioPtr1,audioBytes1,audioPtr2,audioBytes2); + if (hres!=DS_OK) + { + LOCALASSERT(1==0); + IDirectSoundBuffer_Release(sndBuffer); + ffclose(myFile); + return 0; + } + /* Finally, put a pointer the the buffer into the sound data */ + GameSounds[soundNum].dsBufferP = sndBuffer; + { + char * wavname = strrchr (wavFileName, '\\'); + if (wavname) + { + wavname ++; + } + else + { + wavname = wavFileName; + } + + GameSounds[soundNum].wavName = (char *)AllocateMem (strlen (wavname) + 1); + strcpy (GameSounds[soundNum].wavName, wavname); + } + + /* Log it's position. */ + { + DSBCAPS caps; + ZeroMemory(&caps, sizeof(DSBCAPS)); + caps.dwSize = sizeof(DSBCAPS); + IDirectSoundBuffer_GetCaps(sndBuffer, &caps); + + if(caps.dwFlags & DSBCAPS_LOCHARDWARE) + { + GameSounds[soundNum].flags = SAMPLE_IN_HW; + db_logf3(("Sound %s loaded into hardware slot %i by LoadWavFromFastFile.", GameSounds[soundNum].wavName, soundNum)); + } + else + { + GameSounds[soundNum].flags = SAMPLE_IN_SW; + db_logf3(("Sound %s loaded into software slot %i by LoadWavFromFastFile.", GameSounds[soundNum].wavName, soundNum)); + } + } + GameSounds[soundNum].length=lengthInSeconds; + } + + ffclose(myFile); + return 1; +} + +/* Patrick 13/6/97 ------------------------------------------------------------- + Stuff for converting pitch semi-tones into frequencies: + The common sound interface in PSND uses 1/128ths of a semi-tone increments to + change sounds (like the PSX) however, DS uses frequency shifts. We must therefore + convert semi-tone shifts into frequency shifts. The conversion formula is: + f = f0 * 2^(P-P0) + ----------------------------------------------------------------------------*/ +static int ToneToFrequency(int currentFrequency, int currentPitch, int newPitch) +{ + int newFrequency = currentFrequency; + + LOCALASSERT((currentPitch>=PITCH_MINPLAT)&&(currentPitch<=PITCH_MAXPLAT)); + LOCALASSERT((currentFrequency>=FREQUENCY_MINPLAT)&&(currentPitch<=FREQUENCY_MAXPLAT)); + + /* limit pitch */ + if(newPitch>PITCH_MAXPLAT) newPitch=PITCH_MAXPLAT; + if(newPitchcurrentPitch) + { + /* scale up */ + int numOctaves, numTones; + numOctaves = (newPitch-currentPitch)/1536; + numTones = (newPitch-currentPitch)%1536; + + newFrequency<<=numOctaves; + if(newFrequency>FREQUENCY_MAXPLAT) newFrequency=FREQUENCY_MAXPLAT; + + if(numTones>0) newFrequency = (int)((float)(newFrequency)*pitch_to_frequency_mult_table[numTones]); + if(newFrequency>FREQUENCY_MAXPLAT) newFrequency=FREQUENCY_MAXPLAT; + } + else + { + /* scale down */ + int numOctaves, numTones; + numOctaves = (currentPitch-newPitch)/1536; + numTones = (currentPitch-newPitch)%1536; + + newFrequency>>=numOctaves; + if(newFrequency0) newFrequency = (int)((float)(newFrequency)/pitch_to_frequency_mult_table[numTones]); + if(newFrequencyVDB_World.vx, + (D3DVALUE) Global_VDB_Ptr->VDB_World.vy, + (D3DVALUE) Global_VDB_Ptr->VDB_World.vz, + DS3D_DEFERRED + ); +#endif + if (Global_VDB_Ptr) + { + extern int NormalFrameTime; + extern int DopplerShiftIsOn; + + if(AvP.PlayerType != I_Alien) + { + IDirectSound3DListener_SetOrientation + ( + DS3DListener, + (D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat13) / 65536.0F), + (D3DVALUE) 0, + (D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat33) / 65536.0F), + (D3DVALUE) 0, + (D3DVALUE) 1, + (D3DVALUE) 0, + DS3D_DEFERRED + ); + } + else + { + IDirectSound3DListener_SetOrientation + ( + DS3DListener, + (D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat13) / 65536.0F), + (D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat23) / 65536.0F), + (D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat33) / 65536.0F), + (D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat12) / 65536.0F), + (D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat22) / 65536.0F), + (D3DVALUE) (float) ((Global_VDB_Ptr->VDB_Mat.mat32) / 65536.0F), + DS3D_DEFERRED + ); + } + + if (AvP.PlayerType == I_Alien && DopplerShiftIsOn && NormalFrameTime) + { + DYNAMICSBLOCK *dynPtr=Player->ObStrategyBlock->DynPtr; + float vx,vy,vz; + float invFrameTime = 100000.0f/(float)NormalFrameTime; + + vx = (float)(dynPtr->Position.vx - dynPtr->PrevPosition.vx)*invFrameTime; + vy = (float)(dynPtr->Position.vy - dynPtr->PrevPosition.vy)*invFrameTime; + vz = (float)(dynPtr->Position.vz - dynPtr->PrevPosition.vz)*invFrameTime; + + + IDirectSound3DListener_SetVelocity + ( + DS3DListener, + vx,vy,vz, + DS3D_DEFERRED + ); + } + else + { + IDirectSound3DListener_SetVelocity + ( + DS3DListener, + 0.0f,0.0f,0.0f, + DS3D_DEFERRED + ); + + } + } + + if(SoundConfig.reverb_changed) + { + unsigned int count = SoundMaxHW; + + // Go through every sound setting the reverb + while(count--) + { + if(ActiveSounds[count].PropSetP) + { + HRESULT res; + if(!ActiveSounds[count].reverb_off) + { + res = IKsPropertySet_Set + ( + ActiveSounds[count].PropSetP, + &DSPROPSETID_EAXBUFFER_ReverbProperties, + DSPROPERTY_EAXBUFFER_REVERBMIX, + NULL, + 0, + &SoundConfig.reverb_mix, + sizeof(float) + ); + } + else + { + float temp = 0; + res = IKsPropertySet_Set + ( + ActiveSounds[count].PropSetP, + &DSPROPSETID_EAXBUFFER_ReverbProperties, + DSPROPERTY_EAXBUFFER_REVERBMIX, + NULL, + 0, + &temp, + sizeof(float) + ); + } + + if(res != DD_OK) + { + db_logf3(("Error: Failed to set the property set. %x", res)); + } + } + } + SoundConfig.reverb_changed = FALSE; + } + + IDirectSound3DListener_CommitDeferredSettings(DS3DListener); +} + +void PlatSetEnviroment(unsigned int env_index, float reverb_mix) +{ + HRESULT res; + + if(~SoundConfig.flags & SOUND_EAX) + { + return; + } + + db_assert3(env_index < EAX_MAX); + db_assert3(PropSetP); + + /* Set up the enviroment. */ + if(SoundConfig.env_index != env_index) + { + res = IKsPropertySet_Set + ( + PropSetP, + &DSPROPSETID_EAX_ReverbProperties, + DSPROPERTY_EAX_ALL, + NULL, + 0, + &Sound_Enviroments[env_index], + sizeof(EAX_REVERBPROPERTIES) + ); + + SoundConfig.env_index = env_index; + + db_logf3(("Set the Enviroment to %i", env_index)); + + if(res != DD_OK) + { + db_logf3(("Error: Failed to set the enviroment. %x", res)); + } + } + + if(reverb_mix == SoundConfig.reverb_mix) + { + return; + } + + if((reverb_mix < 0.0F) || (reverb_mix > 1.0F)) + { + db_log3("Using EAX,"); + SoundConfig.reverb_mix = EAX_REVERBMIX_USEDISTANCE; + } + else + { + db_log3("Using reverb_mix,"); + SoundConfig.reverb_mix = reverb_mix; + } + + SoundConfig.reverb_changed = TRUE; +} + + + + +#define RebSndRead(dest,size,n,src)\ +{\ + unsigned char *d = (unsigned char*)(dest);\ + int i = (n)*(size);\ + do\ + {\ + *d++ = *(src)++;\ + }\ + while(--i);\ +} + +/* KJL 17:06:46 01/09/98 - ExtractWavFile does basically the same job as LoadWavFile, +except that it takes data from a memory buffer, rather than through file access. */ +extern unsigned char *ExtractWavFile(int soundIndex, unsigned char *bufferPtr) +{ + PWAVCHUNKHEADER myChunkHeader; + PWAVRIFFHEADER myRiffHeader; + WAVEFORMATEX myWaveFormat; + unsigned char *endOfBufferPtr; + int lengthInSeconds; + + { + int length = strlen (bufferPtr) + 1; + GameSounds[soundIndex].wavName = (char *)AllocateMem (length); + strcpy (GameSounds[soundIndex].wavName, bufferPtr); + bufferPtr += length; + } + + /* Read the WAV RIFF header */ + RebSndRead(&myChunkHeader,sizeof(PWAVCHUNKHEADER),1,bufferPtr); + endOfBufferPtr = bufferPtr+myChunkHeader.chunkLength; + + RebSndRead(&myRiffHeader,sizeof(PWAVRIFFHEADER),1,bufferPtr); + + /* Read the WAV format chunk */ + RebSndRead(&myChunkHeader,sizeof(PWAVCHUNKHEADER),1,bufferPtr); + if(myChunkHeader.chunkLength==16) + { + /* a standard PCM wave format chunk */ + PCMWAVEFORMAT tmpWaveFormat; + RebSndRead(&tmpWaveFormat,sizeof(PCMWAVEFORMAT),1,bufferPtr); + myWaveFormat.wFormatTag = tmpWaveFormat.wf.wFormatTag; + myWaveFormat.nChannels = tmpWaveFormat.wf.nChannels; + myWaveFormat.nSamplesPerSec = tmpWaveFormat.wf.nSamplesPerSec;; + myWaveFormat.nAvgBytesPerSec = tmpWaveFormat.wf.nAvgBytesPerSec; + myWaveFormat.nBlockAlign = tmpWaveFormat.wf.nBlockAlign; + myWaveFormat.wBitsPerSample = tmpWaveFormat.wBitsPerSample; + myWaveFormat.cbSize = 0; + } + else if(myChunkHeader.chunkLength==18) + { + /* an extended PCM wave format chunk */ + RebSndRead(&myWaveFormat,sizeof(WAVEFORMATEX),1,bufferPtr); + myWaveFormat.cbSize = 0; + } + else + { + /* uh oh: a different chunk type */ + LOCALASSERT(1==0); + return 0; + } + + /* Read the data chunk header */ + //skip chunks until we reach the 'data' chunk + do + { + /* Read the data chunk header */ + RebSndRead(&myChunkHeader,sizeof(PWAVCHUNKHEADER),1,bufferPtr); + if((myChunkHeader.chunkName[0]=='d')&&(myChunkHeader.chunkName[1]=='a')&& + (myChunkHeader.chunkName[2]=='t')&&(myChunkHeader.chunkName[3]=='a')) + { + break; + } + //skip to next chunk + bufferPtr+=myChunkHeader.chunkLength; + }while(TRUE); + + /* Now do a few checks */ + if((myChunkHeader.chunkName[0]!='d')||(myChunkHeader.chunkName[1]!='a')|| + (myChunkHeader.chunkName[2]!='t')||(myChunkHeader.chunkName[3]!='a')) + { + /* chunk alignment disaster */ + LOCALASSERT(1==0); + return 0; + } + + //calculate length of sample + lengthInSeconds=DIV_FIXED(myChunkHeader.chunkLength,myWaveFormat.nAvgBytesPerSec); + + if((myChunkHeader.chunkLength<0)||(myChunkHeader.chunkLength > SOUND_MAXSIZE)) + { + LOCALASSERT(1==0); + return 0; + } + if(myWaveFormat.wFormatTag != WAVE_FORMAT_PCM) + { + LOCALASSERT(1==0); + return 0; + } + if((myWaveFormat.nChannels != 1)&&(myWaveFormat.nChannels != 2)) + { + LOCALASSERT(1==0); + return 0; + } + if((myWaveFormat.wBitsPerSample != 8)&&(myWaveFormat.wBitsPerSample != 16)) + { + LOCALASSERT(1==0); + return 0; + } + + { + /* Now set the buffer description and make a sound object */ + DSBUFFERDESC dsBuffDesc; + LPDIRECTSOUNDBUFFER sndBuffer; + HRESULT hres; + LPVOID audioPtr1; + DWORD audioBytes1; + LPVOID audioPtr2; + DWORD audioBytes2; + + memset(&dsBuffDesc,0,sizeof(DSBUFFERDESC)); + dsBuffDesc.dwSize = sizeof(DSBUFFERDESC); + dsBuffDesc.dwFlags = (DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC); + dsBuffDesc.dwBufferBytes = myChunkHeader.chunkLength; + dsBuffDesc.lpwfxFormat = &myWaveFormat; + + /* Do we need to specify 3D. */ + if(SoundConfig.flags & SOUND_3DHW) + { + dsBuffDesc.dwFlags |= DSBCAPS_CTRL3D; + } + + /* If we have no Voice Manager support we must leave some hardware buffers free. */ + if(SoundConfig.flags & SOUND_VOICE_MGER) + { + // Do nothing for the moment. + } + else + { + /* No Voice Manager. */ + DSCAPS caps; + ZeroMemory(&caps, sizeof(DSCAPS)); + caps.dwSize = sizeof(DSCAPS); + + IDirectSound_GetCaps(DSObject, &caps); + db_logf5(("caps.dwFreeHwMixingStaticBuffers %i SoundMinBufferFree %i",caps.dwFreeHwMixingStaticBuffers, SoundMinBufferFree)); + if(caps.dwFreeHwMixingStaticBuffers < SoundMinBufferFree) + { + /* Force to software. */ + db_log3("Forcing buffer to software."); + dsBuffDesc.dwFlags |= DSBCAPS_LOCSOFTWARE; + } + } + + /* Create the Direct Sound buffer for this sound */ + hres = IDirectSound_CreateSoundBuffer(DSObject,&dsBuffDesc,&sndBuffer,NULL); + if(hres != DS_OK) + { + LOCALASSERT(1==0); + return 0; + } + + /* Lock the buffer to allow the write */ + hres = IDirectSoundBuffer_Lock(sndBuffer,0,myChunkHeader.chunkLength, + &audioPtr1,&audioBytes1,&audioPtr2,&audioBytes2,0); + if((hres!=DS_OK)||(audioPtr2 != NULL)) + { + LOCALASSERT(1==0); + IDirectSoundBuffer_Release(sndBuffer); + return 0; + } + + /* Read data from file to buffer */ + RebSndRead(audioPtr1,1,myChunkHeader.chunkLength,bufferPtr); + #if 0 + if(res != (size_t)myChunkHeader.chunkLength) + { + LOCALASSERT(1==0); + IDirectSoundBuffer_Release(sndBuffer); + return 0; + } + #endif + /* then unlock it and close the file */ + hres = IDirectSoundBuffer_Unlock(sndBuffer,audioPtr1,audioBytes1,audioPtr2,audioBytes2); + if (hres!=DS_OK) + { + LOCALASSERT(1==0); + IDirectSoundBuffer_Release(sndBuffer); + return 0; + } + /* Finally, put a pointer the the buffer into the sound data */ + GameSounds[soundIndex].dsBufferP = sndBuffer; + + /* Log it's position. */ + { + DSBCAPS caps; + ZeroMemory(&caps, sizeof(DSBCAPS)); + caps.dwSize = sizeof(DSBCAPS); + IDirectSoundBuffer_GetCaps(sndBuffer, &caps); + + if(caps.dwFlags & DSBCAPS_LOCHARDWARE) + { + GameSounds[soundIndex].flags = SAMPLE_IN_HW; + db_logf3(("Sound %s loaded into hardware slot %i by ExtractWavFile.", GameSounds[soundIndex].wavName, soundIndex)); + } + else + { + GameSounds[soundIndex].flags = SAMPLE_IN_SW; + db_logf3(("Sound %s loaded into software slot %i by ExtractWavFile.", GameSounds[soundIndex].wavName, soundIndex)); + } + } + GameSounds[soundIndex].length=lengthInSeconds; + } + + return endOfBufferPtr; +} + +int PlatUse3DSoundHW() +{ + unsigned int count = SoundMaxHW; + + if(SoundConfig.flags & SOUND_USE_3DHW) + { + db_log1("Sound system already using 3DHW."); + return 2; + } + + if(~SoundConfig.flags & SOUND_3DHW) + { + db_log1("Sound system does not have any 3DHW to use."); + return -1; + } + + SoundConfig.flags |= SOUND_USE_3DHW; + + // Go through and get 3DBuffers for all active sounds. + while(count--) + { + if(ActiveSounds[count].dsBufferP) + { + HRESULT hres = IDirectSoundBuffer_QueryInterface + ( + ActiveSounds[count].dsBufferP, + &IID_IDirectSound3DBuffer, + &ActiveSounds[count].ds3DBufferP + ); + + if(hres != DD_OK) + { + db_logf3(("Error: Failed to get a DirectSound3DBuffer. res %x", hres)); + } + } + } + + return 1; +} + +int PlatDontUse3DSoundHW() +{ + unsigned int count = SoundMaxHW; + + if(~SoundConfig.flags & SOUND_USE_3DHW) + { + db_log1("Sound system already not using 3DHW."); + return 2; + } + + SoundConfig.flags &= ~SOUND_USE_3DHW; + + // Go through and release 3DBuffers for all active sounds. + while(count--) + { + if(ActiveSounds[count].ds3DBufferP) + { + IDirectSound3DBuffer_Release(ActiveSounds[count].ds3DBufferP); + ActiveSounds[count].ds3DBufferP = NULL; + } + } + + return 1; +} +#if 1 +void UpdateSoundFrequencies(void) +{ + extern int SoundSwitchedOn; + extern int TimeScale; + int i; + + if(!SoundSwitchedOn) return; + + for(i=0;i +#include "scrshot.hpp" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "ourasert.h" +#include "frontend\avp_menus.h" +extern "C"{ + extern DDPIXELFORMAT DisplayPixelFormat; + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + extern int VideoModeTypeScreen; + extern long BackBufferPitch; + extern unsigned char *ScreenBuffer; + extern unsigned char TestPalette[]; + extern unsigned char KeyboardInput[]; + extern unsigned char DebouncedKeyboardInput[]; + extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + extern MODULE* playerPherModule; +}; + +typedef VOID (*PutWord_F)(WORD, FILE *); +typedef VOID (*PutDword_F)(DWORD, FILE *); + +extern void LoadModuleData(); + +void LogCameraPosForModuleLinking() +{ + if(!playerPherModule) return; + if(!playerPherModule->name) return; + + char Filename[100]={"avp_rifs\\"}; + + strcat(Filename,Env_List[AvP.CurrentEnv]->main); + strcat(Filename,".mlf"); + + FILE* file=fopen(Filename,"ab"); + if(!file)return; + + char output_buffer[300]; + int length=0; + + strcpy(output_buffer,playerPherModule->name); + length+=(strlen(playerPherModule->name)+4)&~3; + + *(VECTORCH*)&output_buffer[length]=playerPherModule->m_world; + length+=sizeof(VECTORCH); + *(MATRIXCH*)&output_buffer[length]=Global_VDB_Ptr->VDB_Mat; + length+=sizeof(MATRIXCH); + *(VECTORCH*)&output_buffer[length]=Global_VDB_Ptr->VDB_World; + length+=sizeof(VECTORCH); + + if(length%4 !=0) + { + GLOBALASSERT(0); + } + + fwrite(&output_buffer[0],4,length/4,file); + fclose(file); + textprint("Saving camera for module links"); +} +int SaveCameraPosKeyPressed=0; +static BOOL ModuleLinkAssist=FALSE; + +void HandleScreenShot() +{ + #ifdef AVP_DEBUG_VERSION + + if (DebouncedKeyboardInput[KEY_F8]) + ScreenShot(); + + if (KeyboardInput[KEY_F7]) + { + if(!SaveCameraPosKeyPressed) + { + if(KeyboardInput[KEY_LEFTSHIFT]||KeyboardInput[KEY_RIGHTSHIFT]) + { + ModuleLinkAssist=TRUE; + DeleteFile("avp_rifs\\module.aaa"); + } + else + { + LogCameraPosForModuleLinking(); + SaveCameraPosKeyPressed=1; + } + } + } + else + SaveCameraPosKeyPressed=0; + + if(AvP.MainLoopRunning && ModuleLinkAssist)LoadModuleData(); + + #endif +} + +void ScreenShot() +{ + char Name[40]; + strcpy(Name,"AVP"); + int length=strlen(Name); + strncpy(&Name[length],"00.bmp",8); + for(int i=0;i<100;i++) + { + Name[length]=i/10+'0'; + Name[length+1]=(i%10)+'0'; + FILE* tempfp=fopen(Name,"r"); + if(!tempfp)break; + else + { + fclose(tempfp); + } + } + if(i==100) return; + + + FILE * fp = fopen(Name,"wb"); + if (!fp) + { + return; + } + + BMPHEADER2 h; + + // fill out header + + h.Header.Type = 'B'+'M'*256; + h.Header.Reserved1 = 0; + h.Header.Reserved2 = 0; + h.Header.Offset = 14+40+0; + + /* + ** The type of information found in a BMP structure is indicated by + ** the Size (Information Headere Size) field with a non-zero value. + */ + h.PmInfo.Size = 0; + h.Pm2Info.Size = 0; + + h.WinInfo.Size = 40; + h.WinInfo.Width = ScreenDescriptorBlock.SDB_Width; + h.WinInfo.Height = ScreenDescriptorBlock.SDB_Height; + h.WinInfo.Planes = 1; + h.WinInfo.BitCount = 24; + h.WinInfo.Compression = 0; + h.WinInfo.SizeImage = h.WinInfo.Width*h.WinInfo.Height*3; + h.WinInfo.XPelsPerMeter = h.WinInfo.Width; + h.WinInfo.YPelsPerMeter = h.WinInfo.Height; + h.WinInfo.ClrUsed = 0; + h.WinInfo.ClrImportant = 0; + + h.Header.FileSize = h.WinInfo.SizeImage + h.Header.Offset + 8; + + // write header + + PutWord_F PutWord = PutLittleWord; + PutDword_F PutDword = PutLittleDword; + + PutWord(h.Header.Type, fp); + PutDword(h.Header.FileSize, fp); + PutWord(h.Header.Reserved1, fp); + PutWord(h.Header.Reserved2, fp); + PutDword(h.Header.Offset, fp); + + PutDword(h.WinInfo.Size, fp); + + PutDword(h.WinInfo.Width, fp); + PutDword(h.WinInfo.Height, fp); + PutWord(h.WinInfo.Planes, fp); + PutWord(h.WinInfo.BitCount, fp); + PutDword(h.WinInfo.Compression, fp); + PutDword(h.WinInfo.SizeImage, fp); + PutDword(h.WinInfo.XPelsPerMeter, fp); + PutDword(h.WinInfo.YPelsPerMeter, fp); + PutDword(h.WinInfo.ClrUsed, fp); + PutDword(h.WinInfo.ClrImportant, fp); + + + int red_shift,red_scale,green_shift,green_scale,blue_shift,blue_scale; + if(VideoModeTypeScreen==VideoModeType_15) + { + int m; + for (red_shift = 0, m = DisplayPixelFormat.dwRBitMask; + !(m & 1); red_shift++, m >>= 1); + red_scale=255/m; + + for (green_shift = 0, m = DisplayPixelFormat.dwGBitMask; + !(m & 1); green_shift++, m >>= 1); + green_scale=255/m; + + for (blue_shift = 0, m = DisplayPixelFormat.dwBBitMask; + !(m & 1); blue_shift++, m >>= 1); + blue_scale=255/m; + + } + + // write 24 bit image + + LockSurfaceAndGetBufferPointer(); + unsigned char* BufferPtr=ScreenBuffer+BackBufferPitch*(h.WinInfo.Height-1); + for (i=h.WinInfo.Height-1; i>=0; --i) + { + int j; + if(VideoModeTypeScreen==VideoModeType_8) + { + for (j=0; j>blue_shift)*blue_scale),fp); //b + PutByte((BYTE)(((colour & DisplayPixelFormat.dwGBitMask)>>green_shift)*green_scale),fp); //g + PutByte((BYTE)(((colour & DisplayPixelFormat.dwRBitMask)>>red_shift)*red_scale),fp); //r + } + } + else if(VideoModeTypeScreen==VideoModeType_24) + { + for (j=0; jmake_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; +} + +size_t AVP_Strategy_Chunk::size_chunk() +{ + chunk_size=20+Strategy->GetStrategySize(); + return chunk_size; +} + +void AVP_Strategy_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = index; + data_start += 4; + *((int *) data_start) = spare2; + data_start += 4; + + Strategy->fill_data_block(data_start); +} + +//////////////////////////////////////////////////////// +//Class AvP_External_Strategy_Chunk +RIF_IMPLEMENT_DYNCREATE("AVPEXSTR",AVP_External_Strategy_Chunk) + +AVP_External_Strategy_Chunk::AVP_External_Strategy_Chunk(Chunk_With_Children* parent,const char* data,size_t datasize) +:Chunk(parent,"AVPEXSTR") +{ + ObjID=*(ObjectID*)data; + data+=8; + ExtEnvNum=*(int*)data; + data+=4; + ThisEnvNum= *(int*)data; + data+=4; + spare= *(int*)data; + data+=4; + + int type=*((int*)data); + switch(type) + { + case StratLift : + Strategy=new LiftStrategy(data,datasize-8); + break; + case StratDoor : + Strategy=new DoorStrategy(data,datasize-8); + break; + case StratBinSwitch : + Strategy=new BinSwitchStrategy(data,datasize-8); + break; + case StratSimpleObject : + Strategy=new AvpStrat(data); + break; + case StratPlatLift : + Strategy=new PlatLiftStrategy(data,datasize-8); + break; + default : + Strategy=new MiscStrategy(data,datasize-8); + } +} + +AVP_External_Strategy_Chunk::AVP_External_Strategy_Chunk(Chunk_With_Children* parent) +:Chunk(parent,"AVPEXSTR") +{ + ObjID.id1=ObjID.id2=0; + ExtEnvNum=0; + Strategy=0; + ThisEnvNum=0; + spare=0; +} + +AVP_External_Strategy_Chunk::~AVP_External_Strategy_Chunk() +{ + delete Strategy; +} + +BOOL AVP_External_Strategy_Chunk::output_chunk (HANDLE &hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = this->make_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; +} + +size_t AVP_External_Strategy_Chunk::size_chunk() +{ + chunk_size=32+Strategy->GetStrategySize(); + return chunk_size; +} + +void AVP_External_Strategy_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((ObjectID *) data_start) =ObjID; + data_start += 8; + *((int *) data_start) = ExtEnvNum; + data_start += 4; + *((int *) data_start) = ThisEnvNum; + data_start += 4; + *((int *) data_start) = spare; + data_start += 4; + + Strategy->fill_data_block(data_start); +} +///////////////////////////////////////////////////////////// +//Class Virtual_Object_Chunk + +RIF_IMPLEMENT_DYNCREATE("VIOBJECT",Virtual_Object_Chunk) +CHUNK_WITH_CHILDREN_LOADER("VIOBJECT",Virtual_Object_Chunk) + +/* +Children for Virtual_Object_Chunk + +"AVPSTRAT" AVP_Strategy_Chunk +"VOBJPROP" Virtual_Object_Properties_Chunk +*/ + +//////////////////////////////////////////////////////// +//Class Virtual_Object_Properties_Chunk + +RIF_IMPLEMENT_DYNCREATE("VOBJPROP",Virtual_Object_Properties_Chunk) + +ObjectID Virtual_Object_Properties_Chunk::CalculateID() +{ + ID.id1=ID.id2=0; + + char Name[100]; + + /*Add on a few extra letters so that I don't have to worry about having the same name + as any normal objects etc*/ + strcpy(Name,"VirtOb"); + strcat(Name,name); + + char buffer[16]; + md5_buffer(Name,strlen(Name),&buffer[0]); + buffer[7]=0; + ID = *(ObjectID*)&buffer[0]; + return ID; + +} + +Virtual_Object_Properties_Chunk::Virtual_Object_Properties_Chunk(Chunk_With_Children* parent,const char* _name) +:Chunk(parent,"VOBJPROP") +{ + location.x=location.y=location.z=0; + size=1000; + pad1=pad2=0; + name=new char[strlen(_name)+1]; + strcpy(name,_name); + CalculateID(); +} + +#if UseOldChunkLoader +Virtual_Object_Properties_Chunk::Virtual_Object_Properties_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk(parent,"VOBJPROP") +{ + location=*(ChunkVector*)data; + data+=sizeof(ChunkVector); + size=*(double*)data; + data+=sizeof(double); + + int length=strlen(data); + name=new char[length+1]; + strcpy(name,data); + data+=(length+4)&~3; + + ID=*(ObjectID*)data; + data+=sizeof(ObjectID); + + pad1=*(int*)data; + data+=sizeof(int); + pad2=*(int*)data; + data+=sizeof(int); +} +#else +Virtual_Object_Properties_Chunk::Virtual_Object_Properties_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk(parent,"VOBJPROP") +{ + location=*(ChunkVectorInt*)data; + data+=sizeof(ChunkVectorInt); + size=*(int*)data; + data+=sizeof(int); + + int length=strlen(data); + name=new char[length+1]; + strcpy(name,data); + data+=(length+4)&~3; + + ID=*(ObjectID*)data; + data+=sizeof(ObjectID); + + pad1=*(int*)data; + data+=sizeof(int); + pad2=*(int*)data; + data+=sizeof(int); +} +#endif + +Virtual_Object_Properties_Chunk::~Virtual_Object_Properties_Chunk() +{ + if(name)delete name; +} + +size_t Virtual_Object_Properties_Chunk::size_chunk() +{ + chunk_size=12+sizeof(ChunkVectorInt)+3*sizeof(int)+sizeof(ObjectID); + chunk_size+=(strlen(name)+4)&~3; + return chunk_size; +} + +void Virtual_Object_Properties_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + *(ChunkVectorInt*)data_start=location; + data_start+=sizeof(ChunkVectorInt); + *(int*)data_start=size; + data_start+=sizeof(int); + + strcpy(data_start,name); + data_start+=(strlen(name)+4)&~3; + + *(ObjectID*)data_start=ID; + data_start+=sizeof(ObjectID); + + *(int*)data_start=pad1; + data_start+=sizeof(int); + *(int*)data_start=pad2; + data_start+=sizeof(int); + +} + +///////////////////////////////////////////////////////////// + + +AvpStrat::AvpStrat(const char* data_start) +{ + StrategyType=*((int*)data_start); + data_start+=4; + Type=*((int*)data_start); + data_start+=4; + ExtraData=*((int*)data_start); + +} + +AvpStrat::AvpStrat(int _StrategyType) +{ + StrategyType = _StrategyType; + Type=ExtraData=0; +} + +size_t AvpStrat::GetStrategySize() +{ + return 12; +} + +void AvpStrat::fill_data_block(char* data) +{ + *(int*)data=StrategyType; + data+=4; + *(int*)data=Type; + data+=4; + *(int*)data=ExtraData; +} + +MiscStrategy::MiscStrategy(const char* data_start,size_t size) +:AvpStrat(data_start) +{ + data_start+=AvpStrat::GetStrategySize(); + blocksize=size-AvpStrat::GetStrategySize(); + if(blocksize) + { + datablock=new char[blocksize]; + memcpy(datablock,data_start,blocksize); + } + else + datablock=0; +} + + +MiscStrategy::~MiscStrategy() +{ + delete [] datablock; +} + +size_t MiscStrategy::GetStrategySize() +{ + return blocksize+AvpStrat::GetStrategySize(); +} + +void MiscStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + memcpy(data,datablock,blocksize); +} +////////////////////////////////////////////////////////////////// +SimpleStrategy::SimpleStrategy(const char * data_start,size_t) +:AvpStrat(data_start) +{ + data_start+=AvpStrat::GetStrategySize(); + + Type = *((int *)data_start); + data_start +=4; + + ExtraData = *((int *)data_start); + data_start +=4; + + mass = *((int *)data_start); + data_start +=4; + + integrity = *((int *)data_start); + data_start +=4; + + flags = *((int *)data_start); + data_start +=4; + + target_request = *((int *)data_start); + data_start +=4; + + targetID = *((ObjectID *)data_start); + + if(!(integrity & SimpleStrategy_SparesDontContainJunk)) + { + integrity|=SimpleStrategy_SparesDontContainJunk; + flags=0; + target_request=0; + targetID.id1=0; + targetID.id2=0; + } + +} + +size_t SimpleStrategy::GetStrategySize() +{ + return 32+AvpStrat::GetStrategySize(); +} + +void SimpleStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + *((int *)data) = Type; + data +=4; + + *((int *)data) = ExtraData; + data +=4; + + *((int *)data) = mass; + data +=4; + + *((int *)data) = integrity; + data +=4; + + *((int *)data) = flags; + data +=4; + + *((int *)data) = target_request; + data +=4; + + *((ObjectID *)data) = targetID; +} + +unsigned int SimpleStrategy::get_r6_integrity() +{ + if(integrity & SimpleStrategy_R6IntegrityValid) + { + return integrity & SimpleStrategy_R6IntegrityMask; + } + else + { + return 100; + } +} +void SimpleStrategy::set_r6_integrity(unsigned int integ) +{ + if(integ>100) integ = 100; + + integrity &=~SimpleStrategy_R6IntegrityMask; + integrity |= integ | SimpleStrategy_R6IntegrityValid; +} + +unsigned int SimpleStrategy::get_r6_destruction_type() +{ + return (integrity & SimpleStrategy_R6DestTypeMask) >> SimpleStrategy_R6DestTypeShift; +} + +void SimpleStrategy::set_r6_destruction_type(unsigned int dest_type) +{ + if(dest_type>200) dest_type = 200; + + integrity &=~ SimpleStrategy_R6DestTypeMask; + integrity |= dest_type << SimpleStrategy_R6DestTypeShift; +} + +////////////////////////////////////////////// +#if InterfaceEngine +R6SimpleStrategy::R6SimpleStrategy(int _Type, int _ExtraData, int _mass, int _integrity) +:SimpleStrategy(_Type,_ExtraData,_mass,_integrity) +{ + StrategyType = StratR6SimpleObject; + + r6SoundID.id1 = 0; + r6SoundID.id2 = 0; + r6_spare1 = 0; + r6_spare2 = 0; + r6_spare3 = 0; + r6_spare4 = 0; + r6_spare5 = 0; + r6_spare6 = 0; +} + +R6SimpleStrategy::R6SimpleStrategy(SimpleStrategy* ss) +:SimpleStrategy(0,0,0,0) +{ + StrategyType = StratR6SimpleObject; + + Type = ss->Type; + ExtraData = ss->ExtraData; + mass = ss->mass; + integrity = ss->integrity; + flags = ss->flags; + target_request = ss->target_request; + targetID = ss->targetID; + + r6SoundID.id1 = 0; + r6SoundID.id2 = 0; + r6_spare1 = 0; + r6_spare2 = 0; + r6_spare3 = 0; + r6_spare4 = 0; + r6_spare5 = 0; + r6_spare6 = 0; + +} +#endif + +R6SimpleStrategy::R6SimpleStrategy(const char * data,size_t size) +:SimpleStrategy(data,size) +{ + data+=SimpleStrategy::GetStrategySize(); + + CHUNK_EXTRACT(r6SoundID,ObjectID); + CHUNK_EXTRACT(r6_spare1,int); + CHUNK_EXTRACT(r6_spare2,int); + CHUNK_EXTRACT(r6_spare3,int); + CHUNK_EXTRACT(r6_spare4,int); + CHUNK_EXTRACT(r6_spare5,int); + CHUNK_EXTRACT(r6_spare6,int); + +} + +size_t R6SimpleStrategy::GetStrategySize() +{ + return 6*sizeof(int)+sizeof(ObjectID) + SimpleStrategy::GetStrategySize(); +} + +void R6SimpleStrategy::fill_data_block(char* data) +{ + SimpleStrategy::fill_data_block(data); + data+=SimpleStrategy::GetStrategySize(); + + CHUNK_FILL(r6SoundID,ObjectID); + CHUNK_FILL(r6_spare1,int); + CHUNK_FILL(r6_spare2,int); + CHUNK_FILL(r6_spare3,int); + CHUNK_FILL(r6_spare4,int); + CHUNK_FILL(r6_spare5,int); + CHUNK_FILL(r6_spare6,int); + +} + + +////////////////////////////////////////////// + +LiftStrategy::LiftStrategy(const char* data_start,size_t /*size*/) +:AvpStrat(data_start) +{ + + data_start+=AvpStrat::GetStrategySize(); + + NumAssocLifts=*(int*)data_start; + data_start+=4; + if(NumAssocLifts) + { + AssocLifts=new ObjectID[NumAssocLifts]; + for(int i=0;i=pad1) + Targets[i].request=1; + else + Targets[i].request=0; + } + pad1=0; + flags|=MultiSwitchFlag_SwitchUpdated; + } + + + +} + +MultiSwitchStrategy::~MultiSwitchStrategy() +{ + if(Targets)delete Targets; + if(LinkedSwitches)delete LinkedSwitches; +} + + + +size_t MultiSwitchStrategy::GetStrategySize() +{ + return AvpStrat::GetStrategySize()+32+NumTargets*12+NumLinks*8; + +} + +void MultiSwitchStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + *(int*)data=RestState; + data+=4; + *(int*)data=Mode; + data+=4; + *(int*)data=Time; + data+=4; + *(int*)data=Security; + data+=4; + + *(int*)data=NumTargets; + data+=4; + for(int i=0;ipoint_no=*(int*)data_start; + data_start+=4; + tpe->pad1=*(int*)data_start; + data_start+=4; + tpe->num_targets=*(int*)data_start; + data_start+=4; + + if(tpe->num_targets) + { + tpe->targets=new TrackRequestTarget[tpe->num_targets]; + for(int j=0;jnum_targets;j++) + { + tpe->targets[j]=*(TrackRequestTarget*)data_start; + data_start+=sizeof(TrackRequestTarget); + } + } + else + tpe->targets=0; + + } + } + else + point_effects=0; + + pad1=*(int*)data_start; + data_start+=4; + pad2=*(int*)data_start; + +} + +TrackStrategy::~TrackStrategy() +{ + for(int i=0;inum_targets; + } + return retval; +} + +void TrackStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + *(int*)data=num_point_effects; + data+=4; + + for(int i=0;ipoint_no; + data+=4; + *(int*)data=tpe->pad1; + data+=4; + *(int*)data=tpe->num_targets; + data+=4; + + for(int j=0;jnum_targets;j++) + { + *(TrackRequestTarget*)data=tpe->targets[j]; + data+=sizeof(TrackRequestTarget); + } + + + } + + *(int*)data=pad1; + data+=4; + *(int*)data=pad2; +} + +///////////////////////////////////////////////////////////// +TrackDestructStrategy::TrackDestructStrategy(const char* data_start,size_t size) +:TrackStrategy(data_start,size) +{ + data_start+=TrackStrategy::GetStrategySize(); + + integrity=*(int*)data_start; + data_start+=4; + + target_request=*(int*)data_start; + data_start+=4; + + targetID=*(ObjectID*)data_start; +} + +void TrackDestructStrategy::fill_data_block(char* data) +{ + TrackStrategy::fill_data_block(data); + data+=TrackStrategy::GetStrategySize(); + + *(int*) data=integrity; + data+=4; + + *(int*) data = target_request; + data+=4; + + *(ObjectID*) data= targetID; + +} + +size_t TrackDestructStrategy::GetStrategySize() +{ + size_t retval=TrackStrategy::GetStrategySize(); + retval+=8+sizeof(ObjectID); + return retval; +} + +//////////////////////////////////////////////////////////// +HierarchyStrategy::HierarchyStrategy(const char* data_start,size_t /*size*/ ) +:AvpStrat(data_start) +{ + data_start+=AvpStrat::GetStrategySize(); + + num_point_effects=*(int*)data_start; + data_start+=4; + + if(num_point_effects) + { + point_effects=new TrackPointEffect*[num_point_effects]; + for(int i=0;ipoint_no=*(int*)data_start; + data_start+=4; + tpe->pad1=*(int*)data_start; + data_start+=4; + tpe->num_targets=*(int*)data_start; + data_start+=4; + + if(tpe->num_targets) + { + tpe->targets=new TrackRequestTarget[tpe->num_targets]; + for(int j=0;jnum_targets;j++) + { + tpe->targets[j]=*(TrackRequestTarget*)data_start; + data_start+=sizeof(TrackRequestTarget); + } + } + else + tpe->targets=0; + + } + } + else + point_effects=0; + + pad1=*(int*)data_start; + data_start+=4; + pad2=*(int*)data_start; + +} + +HierarchyStrategy::~HierarchyStrategy() +{ + for(int i=0;inum_targets; + } + return retval; +} + +void HierarchyStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + *(int*)data=num_point_effects; + data+=4; + + for(int i=0;ipoint_no; + data+=4; + *(int*)data=tpe->pad1; + data+=4; + *(int*)data=tpe->num_targets; + data+=4; + + for(int j=0;jnum_targets;j++) + { + *(TrackRequestTarget*)data=tpe->targets[j]; + data+=sizeof(TrackRequestTarget); + } + + + } + + *(int*)data=pad1; + data+=4; + *(int*)data=pad2; +} + +///////////////////////////////////////////////////////////// + +FanStrategy::FanStrategy(const char* data_start,size_t /*size*/ ) +:AvpStrat(data_start) +{ + data_start+=AvpStrat::GetStrategySize(); + + speed_up_time=*(int*)data_start; + data_start+=4; + slow_down_time=*(int*)data_start; + data_start+=4; + + fan_wind_strength=*(int*)data_start; + data_start+=4; + pad2=*(int*)data_start; + +} + + +size_t FanStrategy::GetStrategySize() +{ + return AvpStrat::GetStrategySize()+16; +} + +void FanStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + *(int*)data=speed_up_time; + data+=4; + *(int*)data=slow_down_time; + data+=4; + + *(int*)data=fan_wind_strength; + data+=4; + *(int*)data=pad2; +} + +///////////////////////////////////////////////////////////// + +DeathVolumeStrategy::DeathVolumeStrategy(const char* data_start,size_t /*size*/ ) +:AvpStrat(data_start) +{ + data_start+=AvpStrat::GetStrategySize(); + + volume_min=*(ChunkVectorInt*)data_start; + data_start+=sizeof(ChunkVectorInt); + volume_max=*(ChunkVectorInt*)data_start; + data_start+=sizeof(ChunkVectorInt); + + flags=*(int*)data_start; + data_start+=4; + damage=*(int*)data_start; + data_start+=4; + pad2=*(int*)data_start; + +} + + +size_t DeathVolumeStrategy::GetStrategySize() +{ + return AvpStrat::GetStrategySize()+12+2*sizeof(ChunkVectorInt); +} + +void DeathVolumeStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + *(ChunkVectorInt*)data=volume_min; + data+=sizeof(ChunkVectorInt); + *(ChunkVectorInt*)data=volume_max; + data+=sizeof(ChunkVectorInt); + + *(int*)data=flags; + data+=4; + *(int*)data=damage; + data+=4; + *(int*)data=pad2; +} + +///////////////////////////////////////////////////////////// + +SelfDestructStrategy::SelfDestructStrategy(const char* data_start,size_t /*size*/ ) +:AvpStrat(data_start) +{ + data_start+=AvpStrat::GetStrategySize(); + + timer=*(int*)data_start; + data_start+=4; + for(int i=0;i<4;i++) + { + pad[i]=*(int*)data_start; + data_start+=4; + } +} + + +size_t SelfDestructStrategy::GetStrategySize() +{ + return AvpStrat::GetStrategySize()+20; +} + +void SelfDestructStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + *(int*)data=timer; + data+=4; + + for(int i=0;i<4;i++) + { + *(int*)data=pad[i]; + data+=4; + } +} + + + +/////////////////////rainbow 6 strategy alert///////////////////////// + +SwingDoorStrategy::SwingDoorStrategy(const char* data,size_t) +:AvpStrat(data) +{ + data+=AvpStrat::GetStrategySize(); + + CHUNK_EXTRACT(time_open,int); + CHUNK_EXTRACT(paired_door,ObjectID); + CHUNK_EXTRACT(doorway_module,ObjectID); + CHUNK_EXTRACT(flags,int); + CHUNK_EXTRACT(time_to_pick,int); + CHUNK_EXTRACT(spare3,int); + CHUNK_EXTRACT(spare4,int); + + //need to see if this door has been updated to give it the + //new default time_open value of 0; + if(!(flags & SwingDoorFlag_UpdatedTime)) + { + flags|=SwingDoorFlag_UpdatedTime; + time_open=0; + } +} + +size_t SwingDoorStrategy::GetStrategySize() +{ + return AvpStrat::GetStrategySize()+20+2*sizeof(ObjectID); +} + +void SwingDoorStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + CHUNK_FILL(time_open,int); + CHUNK_FILL(paired_door,ObjectID); + CHUNK_FILL(doorway_module,ObjectID); + CHUNK_FILL(flags,int); + CHUNK_FILL(time_to_pick,int); + CHUNK_FILL(spare3,int); + CHUNK_FILL(spare4,int); +} + + +////////////////////////////////////////////// + + +PlacedBombStrategy::PlacedBombStrategy(const char* data,size_t) +:AvpStrat(data) +{ + data+=AvpStrat::GetStrategySize(); + + CHUNK_EXTRACT(type,int); + CHUNK_EXTRACT(time,int); + CHUNK_EXTRACT(flags,int); + CHUNK_EXTRACT(integrity,int); + + CHUNK_EXTRACT(objective_number,unsigned char); + CHUNK_EXTRACT(time_to_pick,unsigned short); + + CHUNK_EXTRACT(pad,unsigned char); + CHUNK_EXTRACT(spare2,int); + CHUNK_EXTRACT(spare3,int); + CHUNK_EXTRACT(spare4,int); +} + +size_t PlacedBombStrategy::GetStrategySize() +{ + return AvpStrat::GetStrategySize()+8*4; +} + +void PlacedBombStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + CHUNK_FILL(type,int); + CHUNK_FILL(time,int); + CHUNK_FILL(flags,int); + CHUNK_FILL(integrity,int); + CHUNK_FILL(objective_number,unsigned char); + CHUNK_FILL(time_to_pick,unsigned short); + + CHUNK_FILL(pad,unsigned char); + CHUNK_FILL(spare2,int); + CHUNK_FILL(spare3,int); + CHUNK_FILL(spare4,int); +} + + +////////////////////////////////////////////// + + +R6SwitchStrategy::R6SwitchStrategy(const char* data,size_t) +:AvpStrat(data) +{ + data+=AvpStrat::GetStrategySize(); + + CHUNK_EXTRACT(TargetID,ObjectID); + + CHUNK_EXTRACT(spare1,int); + CHUNK_EXTRACT(spare2,int); + CHUNK_EXTRACT(spare3,int); + CHUNK_EXTRACT(spare4,int); +} + +size_t R6SwitchStrategy::GetStrategySize() +{ + return AvpStrat::GetStrategySize()+8*4; +} + +void R6SwitchStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + CHUNK_FILL(TargetID,ObjectID); + + CHUNK_FILL(spare1,int); + CHUNK_FILL(spare2,int); + CHUNK_FILL(spare3,int); + CHUNK_FILL(spare4,int); +} + + + +////////////////////////////////////////////// + +MummyInanimateStrategy::MummyInanimateStrategy() +:AvpStrat(StratMummyInanimate) +{ + destructionType = 0; + health = 100; + generatedPickups[0] = 0; + generatedPickups[1] = 0; + generatedPickups[2] = 0; + generatedPickups[3] = 0; + linkedSoundID.id1 = 0; + linkedSoundID.id2 = 0; + activateID = linkedSoundID; + spare1 = 0; + spare2 = 0; + spare3 = 0; + spare4 = 0; +} + + +MummyInanimateStrategy::MummyInanimateStrategy(const char* data,size_t) +:AvpStrat(data) +{ + data+=AvpStrat::GetStrategySize(); + + CHUNK_EXTRACT(destructionType,int); + CHUNK_EXTRACT(health,int); + CHUNK_EXTRACT(generatedPickups[0],char); + CHUNK_EXTRACT(generatedPickups[1],char); + CHUNK_EXTRACT(generatedPickups[2],char); + CHUNK_EXTRACT(generatedPickups[3],char); + CHUNK_EXTRACT(linkedSoundID,ObjectID); + CHUNK_EXTRACT(activateID,ObjectID); + + CHUNK_EXTRACT(spare1,int); + CHUNK_EXTRACT(spare2,int); + CHUNK_EXTRACT(spare3,int); + CHUNK_EXTRACT(spare4,int); +} + +size_t MummyInanimateStrategy::GetStrategySize() +{ + size_t retval = AvpStrat::GetStrategySize(); + retval += 2*sizeof(int) + 4*sizeof(char) + 2*sizeof(ObjectID); + retval += 4*sizeof(int); + return retval; +} + +void MummyInanimateStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + CHUNK_FILL(destructionType,int); + CHUNK_FILL(health,int); + CHUNK_FILL(generatedPickups[0],char); + CHUNK_FILL(generatedPickups[1],char); + CHUNK_FILL(generatedPickups[2],char); + CHUNK_FILL(generatedPickups[3],char); + CHUNK_FILL(linkedSoundID,ObjectID); + CHUNK_FILL(activateID,ObjectID); + + CHUNK_FILL(spare1,int); + CHUNK_FILL(spare2,int); + CHUNK_FILL(spare3,int); + CHUNK_FILL(spare4,int); +} + + +////////////////////////////////////////////// +MummyPickupStrategy::MummyPickupStrategy() +:AvpStrat(StratMummyPickup) +{ + pickupType = 0; + inactiveAtStart = 0; + spare1 = 0; + spare2 = 0; + spare3 = 0; + spare4 = 0; +} + +MummyPickupStrategy::MummyPickupStrategy(const char* data,size_t) +:AvpStrat(data) +{ + data+=AvpStrat::GetStrategySize(); + + CHUNK_EXTRACT(pickupType,int); + CHUNK_EXTRACT(inactiveAtStart,BOOL); + + CHUNK_EXTRACT(spare1,int); + CHUNK_EXTRACT(spare2,int); + CHUNK_EXTRACT(spare3,int); + CHUNK_EXTRACT(spare4,int); +} + +size_t MummyPickupStrategy::GetStrategySize() +{ + return AvpStrat::GetStrategySize()+6*4; +} + +void MummyPickupStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + CHUNK_FILL(pickupType,int); + CHUNK_FILL(inactiveAtStart,BOOL); + + CHUNK_FILL(spare1,int); + CHUNK_FILL(spare2,int); + CHUNK_FILL(spare3,int); + CHUNK_FILL(spare4,int); +} + +////////////////////////////////////////////// +MummyTriggerVolumeStrategy::MummyTriggerVolumeStrategy(const char* data,size_t) +:AvpStrat(data) +{ + data+=AvpStrat::GetStrategySize(); + + CHUNK_EXTRACT(trigger_min,ChunkVectorInt); + CHUNK_EXTRACT(trigger_max,ChunkVectorInt); + CHUNK_EXTRACT(targetID,ObjectID); + + CHUNK_EXTRACT(spare1,int); + CHUNK_EXTRACT(spare2,int); + CHUNK_EXTRACT(spare3,int); + CHUNK_EXTRACT(spare4,int); +} + +size_t MummyTriggerVolumeStrategy::GetStrategySize() +{ + return AvpStrat::GetStrategySize()+4*4 + sizeof(ChunkVectorInt)*2 + sizeof(ObjectID); +} + +void MummyTriggerVolumeStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + CHUNK_FILL(trigger_min,ChunkVectorInt); + CHUNK_FILL(trigger_max,ChunkVectorInt); + CHUNK_FILL(targetID,ObjectID); + + CHUNK_FILL(spare1,int); + CHUNK_FILL(spare2,int); + CHUNK_FILL(spare3,int); + CHUNK_FILL(spare4,int); +} + + +////////////////////////////////////////////// +MummyPivotObjectStrategy::MummyPivotObjectStrategy(const char* data,size_t) +:AvpStrat(data) +{ + data+=AvpStrat::GetStrategySize(); + + CHUNK_EXTRACT(typeID,int); + CHUNK_EXTRACT(triggerDelay,int); + CHUNK_EXTRACT(targetID,ObjectID); + + CHUNK_EXTRACT(spare1,int); + CHUNK_EXTRACT(spare2,int); + + //now need to see whether this is the upgraded version of the strategy + if(StrategyType == StratMummyPivotObject_Old) + { + //need to add the trigger volume stuff then + trigger_min.x=trigger_min.y=trigger_min.z=0; + trigger_max = trigger_min; + + //change the type to the new version + StrategyType = StratMummyPivotObject; + + } + else + { + CHUNK_EXTRACT(trigger_min,ChunkVectorInt); + CHUNK_EXTRACT(trigger_max,ChunkVectorInt); + } +} + +size_t MummyPivotObjectStrategy::GetStrategySize() +{ + return AvpStrat::GetStrategySize()+4*sizeof(int) + sizeof(ObjectID) + 2*sizeof(ChunkVectorInt); +} + +void MummyPivotObjectStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + CHUNK_FILL(typeID,int); + CHUNK_FILL(triggerDelay,int); + CHUNK_FILL(targetID,ObjectID); + + CHUNK_FILL(spare1,int); + CHUNK_FILL(spare2,int); + + CHUNK_FILL(trigger_min,ChunkVectorInt); + CHUNK_FILL(trigger_max,ChunkVectorInt); +} + +////////////////////////////////////////////// +MummyChestStrategy::MummyChestStrategy(const char* data,size_t) +:AvpStrat(data) +{ + data+=AvpStrat::GetStrategySize(); + + CHUNK_EXTRACT(objectives[0],unsigned char); + CHUNK_EXTRACT(objectives[1],unsigned char); + CHUNK_EXTRACT(objectives[2],unsigned char); + CHUNK_EXTRACT(objectives[3],unsigned char); + + CHUNK_EXTRACT(camera_location,ChunkVectorInt); + CHUNK_EXTRACT(spare,int); +} + +size_t MummyChestStrategy::GetStrategySize() +{ + return AvpStrat::GetStrategySize()+4*sizeof(int) + 4*sizeof(unsigned char); +} + +void MummyChestStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + CHUNK_FILL(objectives[0],unsigned char); + CHUNK_FILL(objectives[1],unsigned char); + CHUNK_FILL(objectives[2],unsigned char); + CHUNK_FILL(objectives[3],unsigned char); + + CHUNK_FILL(camera_location,ChunkVectorInt); + CHUNK_FILL(spare,int); +} + +////////////////////////////////////////////// +MummyAlterCameraRangeStrategy::MummyAlterCameraRangeStrategy(const char* data,size_t) +:AvpStrat(data) +{ + data+=AvpStrat::GetStrategySize(); + + CHUNK_EXTRACT(zone_min,ChunkVectorInt) + CHUNK_EXTRACT(zone_max,ChunkVectorInt) + + CHUNK_EXTRACT(enter_range,int) + CHUNK_EXTRACT(exit_range,int) + CHUNK_EXTRACT(axis,int) + + CHUNK_EXTRACT(spare1,int) + CHUNK_EXTRACT(spare2,int) + CHUNK_EXTRACT(spare3,int) + CHUNK_EXTRACT(spare4,int) + +} + +size_t MummyAlterCameraRangeStrategy::GetStrategySize() +{ + return AvpStrat::GetStrategySize()+7*sizeof(int) + 2*sizeof(ChunkVectorInt); +} + +void MummyAlterCameraRangeStrategy::fill_data_block(char* data) +{ + AvpStrat::fill_data_block(data); + data+=AvpStrat::GetStrategySize(); + + CHUNK_FILL(zone_min,ChunkVectorInt) + CHUNK_FILL(zone_max,ChunkVectorInt) + + CHUNK_FILL(enter_range,int) + CHUNK_FILL(exit_range,int) + CHUNK_FILL(axis,int) + + CHUNK_FILL(spare1,int) + CHUNK_FILL(spare2,int) + CHUNK_FILL(spare3,int) + CHUNK_FILL(spare4,int) +} diff --git a/3dc/avp/win95/Strachnk.hpp b/3dc/avp/win95/Strachnk.hpp new file mode 100644 index 0000000..e9521eb --- /dev/null +++ b/3dc/avp/win95/Strachnk.hpp @@ -0,0 +1,1142 @@ +#ifndef strachnk_hpp +#define strachnk_hpp 1 + + +#include "chunk.hpp" +#include "chnktype.hpp" +#include "ltfx_exp.h" + + +#define StratDoor 50 +#define StratLift 51 +#define StratBinSwitch 52 +#define StratSimpleObject 53 +#define StratPlatLift 54 +#define StratAirlock 57 +#define StratSwitchDoor 59 +#define StratLiftNoTel 60 +#define StratLinkSwitch 61 +#define StratNewSimpleObject 62 +#define StratConsole 63 +#define StratLighting 64 +#define StratMultiSwitch 66 +#define StratTeleport 67 +#define StratAreaSwitch 68 +#define StratEnemy 69 +#define StratMissionObjective 70 +#define StratMissionHint 71 +#define StratTrack 72 +#define StratMessage 73 +#define StratFan 75 +#define StratHierarchy 76 +#define StratDeathVolume 77 +#define StratSelfDestruct 78 +#define StratGenerator 79 +#define StratTrackDestruct 80 + +#define StratSwingDoor 1000 +#define StratPlacedBomb 1001 +#define StratR6Switch 1002 +#define StratR6SimpleObject 1003 + +#define StratMummyInanimate 2000 +#define StratMummyPickup 2001 +#define StratMummySimple 2002 +#define StratMummyTriggerVolume 2003 +#define StratMummyPivotObject_Old 2004 +#define StratMummyChest 2005 +#define StratMummyAlterCameraRange 2006 +#define StratMummyPivotObject 2007 + + +class AvpStrat; + +class AVP_Strategy_Chunk :public Chunk +{ + public: + AVP_Strategy_Chunk(Chunk_With_Children* ,const char*,size_t); + AVP_Strategy_Chunk(Chunk_With_Children*); + ~AVP_Strategy_Chunk(); + + virtual BOOL output_chunk (HANDLE &hand); + virtual size_t size_chunk(); + virtual void fill_data_block(char* data_start); + + int index;// for matching strategy up with the object it belongs to, currently only used by for light strategies + int spare2; + + AvpStrat* Strategy; +}; + +#if InterfaceEngine +class StrategyObject; +#endif + +class AVP_External_Strategy_Chunk :public Chunk +{ + public: + AVP_External_Strategy_Chunk(Chunk_With_Children* ,const char*,size_t); + AVP_External_Strategy_Chunk(Chunk_With_Children*); + ~AVP_External_Strategy_Chunk(); + + virtual BOOL output_chunk (HANDLE &hand); + virtual size_t size_chunk(); + virtual void fill_data_block(char* data_start); + + ObjectID ObjID; + int ExtEnvNum; + int ThisEnvNum; + int spare; + + AvpStrat* Strategy; +}; + +// for attaching strategies to +class Virtual_Object_Chunk :public Chunk_With_Children +{ +public: + + Virtual_Object_Chunk(Chunk_With_Children * parent) + : Chunk_With_Children (parent, "VIOBJECT") + {} + + + // constructor from buffer + Virtual_Object_Chunk (Chunk_With_Children * const parent,const char *, size_t const); + + +}; +class Virtual_Object_Properties_Chunk: public Chunk +{ + public : + Virtual_Object_Properties_Chunk(Chunk_With_Children* parent,const char* _name); + Virtual_Object_Properties_Chunk(Chunk_With_Children* parent,const char*,size_t); + ~Virtual_Object_Properties_Chunk(); + + virtual size_t size_chunk(); + virtual void fill_data_block(char* data_start); + + + ChunkVectorInt location; + int size; + char* name; + ObjectID ID; + int pad1,pad2; + + ObjectID CalculateID(); +}; + + +class AvpStrat +{ + public: + AvpStrat(const char* data_start); + AvpStrat(int _StrategyType); + virtual ~AvpStrat(){} + int StrategyType; + + int Type,ExtraData; + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + +#if InterfaceEngine + StrategyObject* SObject; + AvpStrat(int type,StrategyObject* dptr); + virtual int CopyStrategy(AVP_Strategy_Chunk*,StrategyObject*);//copy strategy to the chunk + virtual BOOL CanCopyStrategy(){return 0;}; + virtual int EditStrategy(int Edit);//if Edit=0 only view it + virtual int VerifyStrategy(){return 1;}; + virtual void _EditSwitchRequest(int& request); + virtual void RemoveInvalidTargets(){}; +#endif +}; + +class MiscStrategy :public AvpStrat +{ + public: + MiscStrategy(const char* data_start,size_t size); + virtual ~MiscStrategy(); + + int blocksize; + char* datablock; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + +#if InterfaceEngine + virtual int EditStrategy(int Edit); +#endif +}; + + +#define SimStratFlag_NotifyTargetOnDestruction 0x00000001 +#define SimStratFlag_NotifyTargetOnPickup 0x00000002 + +#define SimStratFlag_SmallExplosion 0x00000010 //explosive barrel type things +#define SimStratFlag_BigExplosion 0x00000020 +#define SimStratFlag_MolotovExplosion 0x00000030 + +#define SimStratFlag_ExplosionMask 0x00000030 +#define SimStratFlag_ExplosionShift 4 + +//contained within the integrity +#define SimpleStrategy_SparesDontContainJunk 0x80000000 + +//and for r6 +#define SimpleStrategy_R6IntegrityValid 0x40000000 +#define SimpleStrategy_R6IntegrityMask 0xffff +#define SimpleStrategy_R6DestTypeMask 0xff0000 +#define SimpleStrategy_R6DestTypeShift 16 + + +class SimpleStrategy : public AvpStrat +{ +public: + SimpleStrategy(const char* data_start,size_t size); + + int Type,ExtraData; + + int mass; + int integrity; + + int flags; + int target_request; + union + { + ObjectID targetID; + unsigned char R6_Linked_Guards[4]; + }; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + unsigned int get_integrity() {return integrity &~ SimpleStrategy_SparesDontContainJunk;} + + unsigned int get_r6_integrity(); + void set_r6_integrity(unsigned int); + unsigned int get_r6_destruction_type(); + void set_r6_destruction_type(unsigned int); + +#if InterfaceEngine + SimpleStrategy (int _Type, int _ExtraData, int _mass, int _integrity) + : AvpStrat (StratNewSimpleObject,0), Type(_Type), ExtraData(_ExtraData), + mass (_mass), integrity (_integrity) + { + flags=SimStratFlag_NotifyTargetOnDestruction; + target_request=0; + targetID.id1=targetID.id2=0; + integrity|=SimpleStrategy_SparesDontContainJunk; + } + SimpleStrategy(StrategyObject*); + virtual int EditStrategy(int Edit); + virtual BOOL CanCopyStrategy(){return 1;}; + virtual int CopyStrategy(AVP_Strategy_Chunk*,StrategyObject*); + void EditTarget(); + virtual void _EditSwitchRequest(int& request); + virtual void RemoveInvalidTargets(); +#endif + +}; + +class R6SimpleStrategy : public SimpleStrategy +{ +public : + R6SimpleStrategy(const char* data_start,size_t); + + ObjectID r6SoundID; // id of a linked sound + int r6_spare1; + int r6_spare2; + int r6_spare3; + int r6_spare4; + int r6_spare5; + int r6_spare6; + + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + R6SimpleStrategy (int _Type, int _ExtraData, int _mass, int _integrity); + R6SimpleStrategy (SimpleStrategy* ss); + #endif +}; + + + +#define LiftFlag_Here 0x00000001 +#define LiftFlag_Airlock 0x00000002 +#define LiftFlag_NoTel 0x00000004 //switches aren't teleported +#define LiftFlag_ExitOtherSide 0x00000008 +struct ExtLift +{ + int EnvNum; + int junk[4]; + ObjectID LiftID; +}; + +class LiftStrategy :public AvpStrat +{ + public: + LiftStrategy(const char* data_start,size_t size); + virtual ~LiftStrategy(); + + int NumAssocLifts; + ObjectID* AssocLifts; + + ObjectID AssocDoor; + ObjectID AssocCallSwitch; + ObjectID AssocFloorSwitch; + int LiftFlags; + int Floor; + int NumExternalLifts; + ExtLift* ExternalLifts; + + int Facing; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + const char* GetStartName(); + void GetStartPos(int& FileNum,ObjectID& StartID); + + LiftStrategy(StrategyObject* dptr); + LiftStrategy(LiftStrategy* ls); + virtual int EditStrategy(int Edit); + virtual int VerifyStrategy(); + + void EditAssocLifts(int Edit); + void EditAssocDoor(int Edit); + void EditAssocCallSwitch(int Edit); + void EditAssocFloorSwitch(int Edit); + void CalculateFloor(int FileNum,ObjectID liftid); + int EditExternalLifts(int FileNum,int Edit,int sel); + void AlterOtherPos(); + void GetFloorSwitch(File_Chunk* fc,ObjectID LiftID); + #endif + +}; + +#define PlatformLiftFlags_Disabled 0x00000001 +#define PlatformLiftFlags_OneUse 0x00000002 +class PlatLiftStrategy :public AvpStrat +{ + public: + PlatLiftStrategy(const char* data_start,size_t size); + + int flags; + int spare[5]; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + + PlatLiftStrategy(StrategyObject* dptr); + virtual int EditStrategy(int Edit); + virtual int VerifyStrategy(); + + #endif + +}; + +#define DoorFlag_Locked 0x00000001 +#define DoorFlag_Proximity 0x00000002 +#define DoorFlag_Open 0x00000004 +#define DoorFlag_Lift 0x00000008 +#define DoorFlag_Horizontal 0x00000010 //door lying horizontal + +class DoorStrategy :public AvpStrat +{ + public: + DoorStrategy(const char* data_start,size_t); + + int DoorFlags; + unsigned char TimeToOpen; //in tenths of a second + unsigned char TimeToClose; //in tenths of a second + short spare; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + DoorStrategy(StrategyObject*); + virtual int CopyStrategy(AVP_Strategy_Chunk*,StrategyObject*); + BOOL CanCopyStrategy(){return 1;}; + virtual int VerifyStrategy(); + virtual int EditStrategy(int Edit); + #endif +}; + +#define R6SwitchDoorFlag_SwitchOperated 0x00000001 + + +class SwitchDoorStrategy : public AvpStrat +{ + public: + SwitchDoorStrategy(const char* data_start,size_t); + + ObjectID AssocDoor; + union + { + int spare1; + struct + { + unsigned int r6_flags:20; + unsigned int r6_open_time:6; //in tenths of a second + unsigned int r6_close_time:6; //in tenths of a second + }; + }; + + int spare2; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + SwitchDoorStrategy(StrategyObject*); + virtual int VerifyStrategy(); + virtual int EditStrategy(int Edit); + void EditAssocDoor(int Edit); + #endif + +}; + +struct SwitchTarget +{ + ObjectID ID; + int request; +}; + +#define BinSwitchFlag_StartsOn 0x00000001 +#define BinSwitchFlag_OffMessageSame 0x00000002 +#define BinSwitchFlag_OffMessageNone 0x00000004 + +class BinSwitchStrategy :public AvpStrat +{ + public : + BinSwitchStrategy(const char* data_start,size_t); + virtual ~BinSwitchStrategy(){}; + + int flags; + int Mode; + int Time; + int Security; + SwitchTarget Target; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + BinSwitchStrategy(StrategyObject*); + BinSwitchStrategy(StrategyObject*,BinSwitchStrategy*); + virtual int CopyStrategy(AVP_Strategy_Chunk*,StrategyObject*); + BOOL CanCopyStrategy(){return 1;}; + virtual int EditStrategy(int Edit); + virtual int VerifyStrategy(); + int EditTarget(int Edit); + virtual void RemoveInvalidTargets(); + #endif +}; + +class LinkSwitchStrategy :public BinSwitchStrategy +{ + public : + LinkSwitchStrategy(const char* data_start,size_t); + virtual ~LinkSwitchStrategy(); + + int NumLinks; + ObjectID* LinkedSwitches; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + LinkSwitchStrategy(StrategyObject*); + virtual int EditStrategy(int Edit); + virtual int VerifyStrategy(); + #endif + +}; +#define MultiSwitchFlag_SwitchUpdated 0x80000000 +#define MultiSwitchFlag_OffMessageSame 0x00000002 +#define MultiSwitchFlag_OffMessageNone 0x00000004 + +#define MultiSwitchRequest_LinkedSwitch 0x00000002 +class MultiSwitchStrategy :public AvpStrat +{ + public : + MultiSwitchStrategy(const char* data_start,size_t); + virtual ~MultiSwitchStrategy(); + + int RestState; + int Mode; + int Time; + int Security; + + int NumTargets; + SwitchTarget* Targets; + + int NumLinks; + ObjectID* LinkedSwitches; + + int pad1; //used to be UseRestStateAfter , so possible conversion upon load + int flags; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + MultiSwitchStrategy(StrategyObject*); + MultiSwitchStrategy(StrategyObject*,MultiSwitchStrategy*); + virtual int CopyStrategy(AVP_Strategy_Chunk*,StrategyObject*); + BOOL CanCopyStrategy(){return 1;}; + virtual int EditStrategy(int Edit); + virtual int VerifyStrategy(); + void EditTargets(int Edit,int envnum); + void add_target(ObjectID targetid,int envnum); + void duplicate_target(int index); + void remove_target(int index); + virtual void _EditSwitchRequest(int& request); + virtual void RemoveInvalidTargets(); + #endif + +}; + +class AreaSwitchStrategy :public MultiSwitchStrategy +{ + public : + AreaSwitchStrategy(const char* data_start,size_t); + + ChunkVectorInt trigger_min,trigger_max; + int area_pad1,area_pad2; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + AreaSwitchStrategy(StrategyObject*); + AreaSwitchStrategy(StrategyObject*,AreaSwitchStrategy*); + virtual int CopyStrategy(AVP_Strategy_Chunk*,StrategyObject*); + BOOL CanCopyStrategy(){return 1;}; + void EditTriggerVolume(); + #endif + +}; + + + +class ConsoleStrategy :public AvpStrat +{ + public : + ConsoleStrategy(const char* data_start,size_t); + + int ConsoleNum; + int spare1,spare2; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + ConsoleStrategy(StrategyObject*); + virtual int EditStrategy(int Edit); +// virtual int VerifyStrategy(); + #endif +}; + +class LightingStrategy : public AvpStrat +{ + public : + LightingStrategy(const char* data_start,size_t); + + LightFXData LightData; + + int pad1,pad2,pad3; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + LightingStrategy(StrategyObject*); + LightingStrategy(LightingStrategy*,StrategyObject*); + virtual int CopyStrategy(AVP_Strategy_Chunk*,StrategyObject*); + BOOL CanCopyStrategy(){return 1;}; + virtual int EditStrategy(int Edit); + #endif + +}; + +#define Teleport_All 0 +#define Teleport_Marine 1 +#define Teleport_Alien 2 +#define Teleport_Predator 3 + +class TeleportStrategy : public AvpStrat +{ + public: + TeleportStrategy(const char* data_start,size_t); + + ObjectID TeleportTo; + int Type; + int spare1,spare2; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + TeleportStrategy(StrategyObject*); + virtual int VerifyStrategy(); + virtual int EditStrategy(int Edit); + void EditTeleportTo(int Edit); + #endif + +}; + + +class EnemyStrategy : public AvpStrat +{ + public: + EnemyStrategy(const char* data_start,size_t); + + int MissionType; + int target_request; + ObjectID DeathTarget; + + int ExtraMissionData; + int spares[3]; + + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + EnemyStrategy(StrategyObject*); + EnemyStrategy(StrategyObject*,EnemyStrategy*); + virtual int EditStrategy(int Edit); + virtual int CopyStrategy(AVP_Strategy_Chunk*,StrategyObject*); + int EditTarget(int Edit); + virtual void RemoveInvalidTargets(); + #endif + +}; + +class GeneratorStrategy : public AvpStrat +{ + public: + GeneratorStrategy(const char* data_start,size_t); + + int MissionType; + int ExtraMissionData; + + int spares[6]; + + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + GeneratorStrategy(StrategyObject*); + virtual int EditStrategy(int Edit); + #endif + +}; + + +#define MissionFlag_Visible 0x00000001 +#define MissionFlag_CurrentlyPossible 0x00000002 + +#define MissionTrigger_MakeVisible 0x00000001 +#define MissionTrigger_MakePossible 0x00000002 +#define MissionTrigger_DontComplete 0x00000004 + +enum MissionCompletionEffects +{ + MCE_None, + MCE_CompleteLevel, + MCE_Last, +}; + +struct MissionMessage +{ + ObjectID target_mission; + int effect_on_target; +}; + +struct RequestTarget +{ + ObjectID target; + int request; +}; + +class MissionObjectiveStrategy : public AvpStrat +{ + public: + MissionObjectiveStrategy(const char* data_start,size_t); + + //indeces in english.txt + int mission_description_string; + int mission_complete_string; + int mission_number; + + int flags; + + int mission_completion_effect; + + int num_mission_targets; + MissionMessage* mission_targets; + + int num_request_targets; + RequestTarget* request_targets; + + int pad1,pad2; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + #if InterfaceEngine + MissionObjectiveStrategy(StrategyObject*); + virtual int EditStrategy(int Edit); + void EditMissionTargets(); + virtual void _EditSwitchRequest(int& request); + virtual void RemoveInvalidTargets(); + #endif + +}; + +class MissionHintStrategy : public AvpStrat +{ + public: + MissionHintStrategy(const char* data_start,size_t); + + int mission_hint_string; + int mission_number; + int flags; + + int pad1,pad2; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + #if InterfaceEngine + MissionHintStrategy(StrategyObject*); + virtual int EditStrategy(int Edit); + #endif +}; + +#define TextMessageFlag_NotActiveAtStart 0x00000001 + +class TextMessageStrategy : public AvpStrat +{ + public: + TextMessageStrategy(const char* data_start,size_t); + + int message_string; + + int flags,pad2; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + #if InterfaceEngine + TextMessageStrategy(StrategyObject*); + virtual int EditStrategy(int Edit); + virtual void _EditSwitchRequest(int& request); + #endif +}; + + +#define TrackRequestFlag_ActiveForward 0x00000001 +#define TrackRequestFlag_ActiveBackward 0x00000002 +#define TrackRequestFlag_OppositeBackward 0x00000004 + +struct TrackRequestTarget +{ + ObjectID targetID; + int request; + int flags; +}; + +struct TrackPointEffect +{ + int point_no; + int num_targets; + TrackRequestTarget* targets; + int pad1; + + ~TrackPointEffect() + { + if(targets) delete [] targets; + } + + +}; + +class TrackStrategy : public AvpStrat +{ + public: + TrackStrategy(const char* data_start,size_t); + ~TrackStrategy(); + + int num_point_effects; + TrackPointEffect** point_effects; + + int pad1; + int pad2; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + #if InterfaceEngine + TrackStrategy(StrategyObject*); + int EditStrategy(int Edit); + void EditTargets(TrackPointEffect*); + void _EditSwitchRequest(int& request); + virtual void RemoveInvalidTargets(); + #endif + +}; + +class TrackDestructStrategy : public TrackStrategy +{ + public: + TrackDestructStrategy(const char* data_start,size_t); + + int integrity; + int target_request; + ObjectID targetID; //target when blown up + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + #if InterfaceEngine + TrackDestructStrategy(StrategyObject*); + virtual void RemoveInvalidTargets(); + void EditTarget(); + #endif + +}; + +class HierarchyStrategy : public AvpStrat +{ + public: + HierarchyStrategy(const char* data_start,size_t); + ~HierarchyStrategy(); + + int num_point_effects; + TrackPointEffect** point_effects; + + int pad1; + int pad2; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + #if InterfaceEngine + HierarchyStrategy(StrategyObject*); + int EditStrategy(int Edit); + void EditTargets(TrackPointEffect*); + virtual void RemoveInvalidTargets(); + #endif +}; + +class FanStrategy : public AvpStrat +{ + public: + FanStrategy(const char* data_start,size_t); + + int speed_up_time; + int slow_down_time; + int fan_wind_strength; + int pad2; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + #if InterfaceEngine + FanStrategy(StrategyObject*); + int EditStrategy(int Edit); + #endif +}; + +#define DeathVolumeFlag_StartsOn 0x00000001 +#define DeathVolumeFlag_CollisionNotRequired 0x00000002 +class DeathVolumeStrategy : public AvpStrat +{ + public: + DeathVolumeStrategy(const char* data_start,size_t); + + ChunkVectorInt volume_min; + ChunkVectorInt volume_max; + int flags; + int damage; //damage per second , 0 = infinite + int pad2; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + #if InterfaceEngine + DeathVolumeStrategy(StrategyObject*); + int EditStrategy(int Edit); + #endif +}; + +class SelfDestructStrategy : public AvpStrat +{ + public: + SelfDestructStrategy(const char* data_start,size_t); + + int timer;//in seconds + int pad[4]; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + #if InterfaceEngine + SelfDestructStrategy(StrategyObject*); + int EditStrategy(int Edit); + #endif +}; + + + + + + +/////////////////////rainbow 6 strategy alert///////////////////////// + +#define SwingDoorFlag_Open 0x00000001 +#define SwingDoorFlag_Locked 0x00000002 +//flag set to show time_open has been set to the new default of 0 +#define SwingDoorFlag_UpdatedTime 0x80000000 +class SwingDoorStrategy : public AvpStrat +{ + public: + SwingDoorStrategy(const char* data_start,size_t); + + int time_open;//in milliseconds + ObjectID paired_door; + ObjectID doorway_module; + int flags; + int time_to_pick;//in milliseconds + int spare3; + int spare4; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + #if InterfaceEngine + SwingDoorStrategy(StrategyObject*); + int EditStrategy(int Edit); + void EditPairedDoor(); + void EditDoorwayModule(); + #endif +}; + + + +#define BombFlag_TerroristActivate 0x00000001 +#define BombFlag_Armed 0x00000002 + +#define BombType_Bomb 0 +#define BombType_SecurityConsole 1 +#define BombType_VirusCapsule 2 +#define BombType_Computer 3 +#define BombType_NonCriticalAlarm 4 + + +class PlacedBombStrategy : public AvpStrat +{ + public: + PlacedBombStrategy(const char* data_start,size_t); + + int type; + int time;//seconds + int flags; + int integrity; + + + unsigned char objective_number; //a value from 0 to 4 + unsigned short time_to_pick; //seconds + unsigned char pad; + + int spare2,spare3,spare4; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + #if InterfaceEngine + PlacedBombStrategy(StrategyObject*); + int EditStrategy(int Edit); + #endif +}; + +class R6SwitchStrategy : public AvpStrat +{ + public: + R6SwitchStrategy(const char* data_start,size_t); + + ObjectID TargetID; + + + int spare1,spare2,spare3,spare4; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + R6SwitchStrategy(StrategyObject*); + int EditStrategy(int Edit); + void EditTarget(); + virtual void RemoveInvalidTargets(); + #endif +}; + +/////////////////////Mummy strategy alert///////////////////////// +class MummyInanimateStrategy : public AvpStrat +{ +public : + MummyInanimateStrategy(const char* data_start,size_t); + MummyInanimateStrategy(); + + int destructionType; + int health; //0 to 100 + char generatedPickups[4]; + ObjectID linkedSoundID; + ObjectID activateID; + + int spare1,spare2,spare3,spare4; + + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + MummyInanimateStrategy(StrategyObject*); + int EditStrategy(int Edit); + virtual void RemoveInvalidTargets(); + void EditTarget(); + void EditLinkedSound(); + #endif + +}; + + +class MummyPickupStrategy : public AvpStrat +{ +public : + MummyPickupStrategy(const char* data_start,size_t); + MummyPickupStrategy(); + + int pickupType; + BOOL inactiveAtStart; + int spare1,spare2,spare3,spare4; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine +// MummyPickupStrategy(StrategyObject*); + int EditStrategy(int Edit){return 0;}; +// virtual void RemoveInvalidTargets(); + #endif + +}; + +class MummyTriggerVolumeStrategy : public AvpStrat +{ +public : + MummyTriggerVolumeStrategy(const char* data_start,size_t); + + ChunkVectorInt trigger_min,trigger_max; + ObjectID targetID; + + int spare1,spare2,spare3,spare4; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + MummyTriggerVolumeStrategy(StrategyObject*); + int EditStrategy(int Edit); + void EditTriggerVolume(); + void EditTarget(); + virtual void RemoveInvalidTargets(); + #endif + +}; + +#define MummyPivotObject_Pillar 0 +#define MummyPivotObject_Flagstone 1 + +class MummyPivotObjectStrategy : public AvpStrat +{ +public : + MummyPivotObjectStrategy(const char* data_start,size_t); + + int typeID; //pillar or flagstone + int triggerDelay; //in milliseconds (fixed point seconds in game) + ObjectID targetID; + + int spare1,spare2; + + ChunkVectorInt trigger_min,trigger_max; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + MummyPivotObjectStrategy(StrategyObject*); + int EditStrategy(int Edit); + void EditTarget(); + virtual void RemoveInvalidTargets(); + void EditTriggerVolume(); + #endif + +}; + +class MummyChestStrategy : public AvpStrat +{ +public : + MummyChestStrategy(const char* data_start,size_t); + + unsigned char objectives[4]; + + ChunkVectorInt camera_location; + int spare; + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + MummyChestStrategy(StrategyObject*); + int EditStrategy(int Edit); + void EditObjective(int index); + void EditCameraLocation(); + #endif + +}; + + +#define MUMMY_CAMERA_AXIS_MIN_X 0 +#define MUMMY_CAMERA_AXIS_MAX_X 1 +#define MUMMY_CAMERA_AXIS_MIN_Z 2 +#define MUMMY_CAMERA_AXIS_MAX_Z 3 + +class MummyAlterCameraRangeStrategy : public AvpStrat +{ +public : + MummyAlterCameraRangeStrategy(const char* data_start,size_t); + + ChunkVectorInt zone_min,zone_max; + int enter_range; // camera range in mm for one side of he zone + int exit_range; // ditto for opposite side + + int axis; //axis that the change happens across + + int spare1,spare2,spare3,spare4; + + + virtual size_t GetStrategySize(); + virtual void fill_data_block(char* data); + + #if InterfaceEngine + MummyAlterCameraRangeStrategy(StrategyObject*); + int EditStrategy(int Edit); + void EditTriggerVolume(); + #endif + +}; + +#endif + + + diff --git a/3dc/avp/win95/System.bak b/3dc/avp/win95/System.bak new file mode 100644 index 0000000..e0bd69b --- /dev/null +++ b/3dc/avp/win95/System.bak @@ -0,0 +1,353 @@ +#ifndef SYSTEM_INCLUDED + +/* AVP - WIN95 + + Project Specific System Equates etc. + +*/ + + +#ifdef __cplusplus + +extern "C" { + +#endif + + + +/********************* SYSTEM, PLATFORM AND GAME************/ + +#define Yes 1 +#define No 0 + +#ifdef _DEBUG /* standard compiler command line debugging-ON switch */ + #define debug Yes +#elif defined(NDEBUG) /* standard compiler command line debugging-OFF switch */ + #define debug No +#else /* default switch */ + #define debug Yes +#endif + +#define SuppressWarnings Yes + +#define SupportWindows95 Yes +#define Saturn No +#define PSX No +#define platform_pc Yes +#define InterfaceEngine No + +#define Term -1 + + + +/******************** General *****************************/ + +#define SupportFPMathsFunctions Yes +#define SupportFPSquareRoot Yes + +#define GlobalScale 1 + + + +#define one14 16383 + +#define ONE_FIXED 65536 +#define ONE_FIXED_SHIFT 16 + +#define Analogue Yes +#define Digital No + + +/* Offsets from *** int pointer *** for vectors and vertices */ + +typedef enum { + + ix, + iy, + iz + +} PTARRAYINDICES; + +#define StopCompilationOnMultipleInclusions No +#define UseProjPlatAssert Yes /* assert fired functions are in dxlog.c */ + + +/*************** CAMERA AND VIEW VOL********************/ +#define NearZ 1024 +#define FarZ ONE_FIXED + +#define SupportMultiCamModules Yes + + + +/************* Timer and Frame Rate Independence *************/ + +#define TimerFrame 1000 +#define TimerFrame10 10000 +#define NormalFrame ONE_FIXED +#define NormalFrameShift ONE_FIXED_SHIFT + +#define UseAlarmTimer No + + + +/******************** Clip Outcodes *****************/ + +#define ClipTerm 0x1fffffff + +#define oc_left 0x00000001 +#define oc_right 0x00000002 +#define oc_up 0x00000004 +#define oc_down 0x00000008 +#define oc_z 0x00000010 + +#define oc_pntrot 0x00000020 +#define oc_xrot 0x00000040 +#define oc_yrot 0x00000080 +#define oc_zrot 0x00000100 + +#define oc_z_lt_h1 0x00000200 +#define oc_z_gte_h2 0x00000400 +#define oc_z_haze 0x00000800 +#define oc_clampz 0x00001000 + +/* Outcodes can be cast to this struct */ + +typedef struct oc_entry { + + int OC_Flags1; + int OC_Flags2; + int OC_HazeAlpha; + +} OC_ENTRY; + +/* now defunct - see next four defines*/ +#define Hardware2dTextureClipping No + +#define Texture3dClamping No +#define Texture2dClamping No +#define Texture3dSubdivide No + +#define SaturnHazing No + +/***************** Angles and VALUES ******************/ + +#define deg10 114 +#define deg22pt5 256 +#define deg45 512 +#define deg90 1024 +#define deg180 2048 +#define deg270 3072 +#define deg315 3584 +#define deg337pt5 3840 +#define deg350 3980 +#define deg360 4096 +#define wrap360 4095 + +#define Cosine45 46341 /* 46340.95001 cosine(45deg)*/ +#define DefaultSlope 46341 + +#define bigint 1<<30 /* max int size*/ +#define smallint -(bigint) /* smallest int size*/ + +#define BigLowY 100000 /* Must be bigger than any Screen Y */ + + + +/****************** BUFFER SIZES **********************/ + +#define maxvdbs 1 +#define maxobjects 750 +extern int maxshapes; +#define maxstblocks 1000 + +#define maxrotpts 10000 + +//tuning for morph sizes +#define maxmorphPts 1024 +#define maxmorphNormals 1024 +#define maxmorphVNormals 1024 + +#define maxpolys 4000 +#define maxpolyptrs maxpolys +#define maxpolypts 9 /* Translates as number of vectors */ +#define maxvsize 6 /* 3d Phong is x,y,z,nx,ny,nz */ + +#define pointsarraysize maxpolypts*maxvsize + +#define avgpolysize (1 + 1 + 1 + 1 + (6 * 4) + 1) /* 3d guard poly*/ + +#define maxscansize 8 /* e.g. Tx, U1, V1, U2, V2, X1, X2, Y */ +#define vsize 3 /* Scale for polygon vertex indices */ +#define numfreebspblocks 1 +#define maxbspnodeitems 1 + +#if 0 +#define MaxImages 80 /* Was 400, but now we only have one NPC in each image group */ +#define MaxImageGroups 15 /* Right: One for the ENV one for the CHARACTER, one for each NPC (max 4, though only MPS4 ever has as many as 3 at present) */ +#else +#define MaxImages 400 +#define MaxImageGroups 1 +#endif + +#define oversample_8bitg_threshold 256 + + + +/************** Some Shell and Loading Platform Compiler Options ******************/ + +#define binary_loading No +#undef RIFF_SYSTEM +#define RIFF_SYSTEM +#define TestRiffLoaders Yes +#define SupportFarStrategyModel No +#define LoadingMapsShapesAndTexturesEtc No + +#define pc_backdrops No + +#define flic_player Yes + +#define SaturnCDQueueSystem No + +#define DynamicAdaptationToFrameRate No + + +/***************** DRAW SORT *******************/ + + + + +#define SupportTrackOptimisation No + + +#define SupportBSP No + +#define SupportZBuffering Yes +#define ZBufferTest No + + + + + +/***************** SHAPE DATA DEFINES************/ + +#define StandardShapeLanguage Yes + +#define CalcShapeExtents No +#define SupportModules Yes +#define IncludeModuleFunctionPrototypes Yes +#define SupportDynamicModuleObjects Yes + + +#define SupportMorphing Yes +#define LazyEvaluationForMorphing No + + + +/* Default Scale for Shape Vertices */ + +#define pscale 1 + + + +/***************** COLLISION DEFINES*************/ +#define StandardStrategyAndCollisions No +#define IntermediateSSACM No /* User preference */ + + + +/************** TEXTURE DEFINES*******************/ + + +#define LoadPGMPalettesFromAnywhere Yes + + +#define maxTxAnimblocks 100 + +/* Texture usage of the colour int */ + +#define TxDefn 16 /* Shift up for texture definition index */ +#define TxLocal 0x8000 /* Set bit 15 to signify a local index */ +#define ClrTxIndex 0xffff0000 /* AND with this to clear the low 16-bits */ +#define ClrTxDefn 0x0000ffff /* AND with this to clear the high 16-bits */ + +#define draw_palette No + +#define AssumeTextures256Wide Yes + +#define remap_table_rgb_bits 4 /* Gives 4,096 entries */ + +#define Remap24BitBMPFilesInRaw256Mode No +#define Remap8BitBMPFilesInRaw256Mode No + +#define SupportMIPMapping No +#define UseMIPMax No +#define UseMIPMin No +#define UseMIPAvg Yes + +/* Jake's addition to mip-mapping */ +/* improves resolution of mip images chosen for the scandraws */ +/* 0 is the worstt resoloution, best anti-aliasing 6 the best*/ +#define MIP_INDEX_SUBTRACT 1 +/* What to do if the images are not the most suitable size for mip mapping ... */ +/* Set this if you have inappropriately sized images and you want */ +/* the mip maps' sizes to be rounded up eg. 161x82 -> 81x41 -> 21x11 -> 11x6 -> 6x3 -> 3x2 -> 2x1 */ +#define MIP_ROUNDUP Yes + +#if 0 +#define num_shadetable_entries 256 +#define shadetable_shift 8 /* 65,535 -> 255 */ +#endif + +#if 1 +#define num_shadetable_entries 1024 +#define shadetable_shift 6 +#endif + +/* + 3d textures + This defines the amount by which we can scale up U/Z, V/Z & 1/Z + It is defined in terms of the maximum UV size and the size of an int + A value of 10 gives a scale of 31 - 10 = 21 + 1/Z, the critical value, reaches 0 at 2^21 = 2km + Since we know that z STARTS at no less than 2^8, we can increase this value + by 8, giving 2^29 + 1/Z now reaches 0 at 2^29 = 537km +*/ + +#define support3dtextures Yes +#define int3dtextures No /* there is no D3D Zbuffer support for int 3d textures */ +#define SupportGouraud3dTextures Yes + + + + + +/*************************** WINDOWS 95 *********************/ + +#define SUPPORT_MMX 0 + +#define MaxD3DInstructions 1000 // includes state change instructions!!! +#define MaxD3DVertices 256 + +#define optimiseflip No /* unstable at present */ +#define optimiseblit Yes /* unstable at present */ + + + +/******************** PLAYSTATION ********************/ + + + + + +#ifdef __cplusplus + + }; + +#endif + +#define SYSTEM_INCLUDED + +#endif + diff --git a/3dc/avp/win95/System.h b/3dc/avp/win95/System.h new file mode 100644 index 0000000..7efd59b --- /dev/null +++ b/3dc/avp/win95/System.h @@ -0,0 +1,357 @@ +#ifndef SYSTEM_INCLUDED + +/* AVP - WIN95 + + Project Specific System Equates etc. + +*/ + + +#ifdef __cplusplus + +extern "C" { + +#endif + + + +/********************* SYSTEM, PLATFORM AND GAME************/ + +#define Yes 1 +#define No 0 + +#ifdef _DEBUG /* standard compiler command line debugging-ON switch */ + #define debug Yes +#elif defined(NDEBUG) /* standard compiler command line debugging-OFF switch */ + #define debug No +#else /* default switch */ + #define debug Yes +#endif + +#define SuppressWarnings Yes + +#define SupportWindows95 Yes +#define Saturn No +#define PSX No +#define platform_pc Yes +#define InterfaceEngine No + +#define Term -1 + + + +/******************** General *****************************/ + +#define SupportFPMathsFunctions Yes +#define SupportFPSquareRoot Yes + +#define GlobalScale 1 + + + +#define one14 16383 + +#define ONE_FIXED 65536 +#define ONE_FIXED_SHIFT 16 + +#define Analogue Yes +#define Digital No + + +/* Offsets from *** int pointer *** for vectors and vertices */ + +typedef enum { + + ix, + iy, + iz + +} PTARRAYINDICES; + +#define StopCompilationOnMultipleInclusions No +#define UseProjPlatAssert Yes /* assert fired functions are in dxlog.c */ + + +/*************** CAMERA AND VIEW VOL********************/ +#define NearZ 1024 +#define FarZ ONE_FIXED + +#define SupportMultiCamModules Yes + + + +/************* Timer and Frame Rate Independence *************/ + +#define TimerFrame 1000 +#define TimerFrame10 10000 +#define NormalFrame ONE_FIXED +#define NormalFrameShift ONE_FIXED_SHIFT + +#define UseAlarmTimer No + + + +/******************** Clip Outcodes *****************/ + +#define ClipTerm 0x1fffffff + +#define oc_left 0x00000001 +#define oc_right 0x00000002 +#define oc_up 0x00000004 +#define oc_down 0x00000008 +#define oc_z 0x00000010 + +#define oc_pntrot 0x00000020 +#define oc_xrot 0x00000040 +#define oc_yrot 0x00000080 +#define oc_zrot 0x00000100 + +#define oc_z_lt_h1 0x00000200 +#define oc_z_gte_h2 0x00000400 +#define oc_z_haze 0x00000800 +#define oc_clampz 0x00001000 + +/* Outcodes can be cast to this struct */ + +typedef struct oc_entry { + + int OC_Flags1; + int OC_Flags2; + int OC_HazeAlpha; + +} OC_ENTRY; + +/* now defunct - see next four defines*/ +#define Hardware2dTextureClipping No + +#define Texture3dClamping No +#define Texture2dClamping No +#define Texture3dSubdivide No + +#define SaturnHazing No + +/***************** Angles and VALUES ******************/ + +#define deg10 114 +#define deg22pt5 256 +#define deg45 512 +#define deg90 1024 +#define deg180 2048 +#define deg270 3072 +#define deg315 3584 +#define deg337pt5 3840 +#define deg350 3980 +#define deg360 4096 +#define wrap360 4095 + +#define Cosine45 46341 /* 46340.95001 cosine(45deg)*/ +#define DefaultSlope 46341 + +#define bigint 1<<30 /* max int size*/ +#define smallint -(bigint) /* smallest int size*/ + +#define BigLowY 100000 /* Must be bigger than any Screen Y */ + + + +/****************** BUFFER SIZES **********************/ + +#define maxvdbs 1 +#define maxobjects 750 +extern int maxshapes; +#define maxstblocks 1000 + +#define maxrotpts 10000 + +//tuning for morph sizes +#define maxmorphPts 1024 +#define maxmorphNormals 1024 +#define maxmorphVNormals 1024 + +#define maxpolys 4000 +#define maxpolyptrs maxpolys +#define maxpolypts 9 /* Translates as number of vectors */ +#define maxvsize 6 /* 3d Phong is x,y,z,nx,ny,nz */ + +#define pointsarraysize maxpolypts*maxvsize + +#define avgpolysize (1 + 1 + 1 + 1 + (6 * 4) + 1) /* 3d guard poly*/ + +#define maxscansize 8 /* e.g. Tx, U1, V1, U2, V2, X1, X2, Y */ +#define vsize 3 /* Scale for polygon vertex indices */ +#define numfreebspblocks 1 +#define maxbspnodeitems 1 + +#if 0 +#define MaxImages 80 /* Was 400, but now we only have one NPC in each image group */ +#define MaxImageGroups 15 /* Right: One for the ENV one for the CHARACTER, one for each NPC (max 4, though only MPS4 ever has as many as 3 at present) */ +#else +#define MaxImages 400 +#define MaxImageGroups 1 +#endif + +#define oversample_8bitg_threshold 256 + + + +/************** Some Shell and Loading Platform Compiler Options ******************/ + +#define binary_loading No +#undef RIFF_SYSTEM +#define RIFF_SYSTEM +#define TestRiffLoaders Yes +#define SupportFarStrategyModel No +#define LoadingMapsShapesAndTexturesEtc No + +#define pc_backdrops No + +#define flic_player Yes + +#define SaturnCDQueueSystem No + +#define DynamicAdaptationToFrameRate No + + +/***************** DRAW SORT *******************/ + + + + +#define SupportTrackOptimisation No + + +#define SupportBSP No + +#define SupportZBuffering Yes +#define ZBufferTest No + + + + + +/***************** SHAPE DATA DEFINES************/ + +#define StandardShapeLanguage Yes + +#define CalcShapeExtents No +#define SupportModules Yes +#define IncludeModuleFunctionPrototypes Yes +#define SupportDynamicModuleObjects Yes + + +#define SupportMorphing Yes +#define LazyEvaluationForMorphing No + + + +/* Default Scale for Shape Vertices */ + +#define pscale 1 + + + +/***************** COLLISION DEFINES*************/ +#define StandardStrategyAndCollisions No +#define IntermediateSSACM No /* User preference */ + + + +/************** TEXTURE DEFINES*******************/ + + +#define LoadPGMPalettesFromAnywhere Yes + + +#define maxTxAnimblocks 100 + +/* Texture usage of the colour int */ + +#define TxDefn 16 /* Shift up for texture definition index */ +#define TxLocal 0x8000 /* Set bit 15 to signify a local index */ +#define ClrTxIndex 0xffff0000 /* AND with this to clear the low 16-bits */ +#define ClrTxDefn 0x0000ffff /* AND with this to clear the high 16-bits */ + +#define draw_palette No + +#define AssumeTextures256Wide Yes + +#define remap_table_rgb_bits 4 /* Gives 4,096 entries */ + +#define Remap24BitBMPFilesInRaw256Mode No +#define Remap8BitBMPFilesInRaw256Mode No + +#define SupportMIPMapping No +#define UseMIPMax No +#define UseMIPMin No +#define UseMIPAvg Yes + +/* Jake's addition to mip-mapping */ +/* improves resolution of mip images chosen for the scandraws */ +/* 0 is the worstt resoloution, best anti-aliasing 6 the best*/ +#define MIP_INDEX_SUBTRACT 1 +/* What to do if the images are not the most suitable size for mip mapping ... */ +/* Set this if you have inappropriately sized images and you want */ +/* the mip maps' sizes to be rounded up eg. 161x82 -> 81x41 -> 21x11 -> 11x6 -> 6x3 -> 3x2 -> 2x1 */ +#define MIP_ROUNDUP Yes + +#if 0 +#define num_shadetable_entries 256 +#define shadetable_shift 8 /* 65,535 -> 255 */ +#endif + +#if 1 +#define num_shadetable_entries 1024 +#define shadetable_shift 6 +#endif + +/* + 3d textures + This defines the amount by which we can scale up U/Z, V/Z & 1/Z + It is defined in terms of the maximum UV size and the size of an int + A value of 10 gives a scale of 31 - 10 = 21 + 1/Z, the critical value, reaches 0 at 2^21 = 2km + Since we know that z STARTS at no less than 2^8, we can increase this value + by 8, giving 2^29 + 1/Z now reaches 0 at 2^29 = 537km +*/ + +#define support3dtextures Yes +#define int3dtextures No /* there is no D3D Zbuffer support for int 3d textures */ +#define SupportGouraud3dTextures Yes + + + + + +/*************************** WINDOWS 95 *********************/ + +#ifdef _MSC_VER +#define SUPPORT_MMX 0 +#else +#define SUPPORT_MMX 1 +#endif + +#define MaxD3DInstructions 1000 // includes state change instructions!!! +#define MaxD3DVertices 256 + +#define optimiseflip No /* unstable at present */ +#define optimiseblit Yes /* unstable at present */ + + + +/******************** PLAYSTATION ********************/ + + + + + +#ifdef __cplusplus + + }; + +#endif + +#define SYSTEM_INCLUDED + +#endif + diff --git a/3dc/avp/win95/USR_IO.C b/3dc/avp/win95/USR_IO.C new file mode 100644 index 0000000..92d3f70 --- /dev/null +++ b/3dc/avp/win95/USR_IO.C @@ -0,0 +1,1748 @@ +/*------------------------------- Patrick 21/10/96 ------------------------------ + Source for reading player inputs. + Note that whilst ReadUserInput() reads raw input data, the functions in this + file map those inputs onto the player movement structures (defined in Player + Status). This is, of course, entirely platform dependant. Consoles will + need their own equivalent functions.... + + -------------------------------------------------------------------------------*/ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "gameplat.h" + +#include "bh_types.h" +#include "ourasert.h" +#include "comp_shp.h" + +#include "pmove.h" +#include "usr_io.h" +#include "hud_map.h" +#include "krender.h" + +#include "iofocus.h" + +#include "paintball.h" +#include "avp_menus.h" + +extern int InGameMenusAreRunning(void); +extern void AvP_TriggerInGameMenus(void); +extern void Recall_Disc(void); +extern void ShowMultiplayerScores(void); + + +extern int NormalFrameTime; + +FIXED_INPUT_CONFIGURATION FixedInputConfig = +{ + KEY_1, // Weapon1; + KEY_2, // Weapon2; + KEY_3, // Weapon3; + KEY_4, // Weapon4; + KEY_5, // Weapon5; + KEY_6, // Weapon6; + KEY_7, // Weapon7; + KEY_8, // Weapon8; + KEY_9, // Weapon9; + KEY_0, // Weapon10; + KEY_ESCAPE, // PauseGame; + +}; + +PLAYER_INPUT_CONFIGURATION MarineInputPrimaryConfig; +PLAYER_INPUT_CONFIGURATION MarineInputSecondaryConfig; +PLAYER_INPUT_CONFIGURATION PredatorInputPrimaryConfig; +PLAYER_INPUT_CONFIGURATION PredatorInputSecondaryConfig; +PLAYER_INPUT_CONFIGURATION AlienInputPrimaryConfig; +PLAYER_INPUT_CONFIGURATION AlienInputSecondaryConfig; + + +#if 1 // English +PLAYER_INPUT_CONFIGURATION DefaultMarineInputPrimaryConfig = +{ + KEY_UP, // Forward; + KEY_DOWN, // Backward; + KEY_NUMPAD4, // Left; + KEY_NUMPAD6, // Right; + + KEY_RIGHTALT, // Strafe; + KEY_LEFT, // StrafeLeft; + KEY_RIGHT, // StrafeRight; + + KEY_Q, // LookUp; + KEY_Z, // LookDown; + KEY_A, // CentreView; + + KEY_LEFTSHIFT, // Walk; + KEY_RIGHTCTRL, // Crouch; + KEY_RIGHTSHIFT, // Jump; + + KEY_SPACE, // Operate; + + KEY_LMOUSE, // FirePrimaryWeapon; + KEY_RMOUSE, // FireSecondaryWeapon; + + KEY_RBRACKET, // NextWeapon; + KEY_LBRACKET, // PreviousWeapon; + KEY_BACKSPACE, // FlashbackWeapon; + + KEY_SLASH, // ImageIntensifier; + KEY_FSTOP, // ThrowFlare; + KEY_APOSTROPHE, // Jetpack; + KEY_SEMICOLON, // Taunt + KEY_F1, + KEY_F11, + KEY_F12, + KEY_TAB, +}; +PLAYER_INPUT_CONFIGURATION DefaultPredatorInputPrimaryConfig = +{ + KEY_UP, // Forward; + KEY_DOWN, // Backward; + KEY_NUMPAD4, // Left; + KEY_NUMPAD6, // Right; + + KEY_RIGHTALT, // Strafe; + KEY_LEFT, // StrafeLeft; + KEY_RIGHT, // StrafeRight; + + KEY_Q, // LookUp; + KEY_Z, // LookDown; + KEY_A, // CentreView; + + KEY_LEFTSHIFT, // Walk; + KEY_RIGHTCTRL, // Crouch; + KEY_RIGHTSHIFT, // Jump; + + KEY_SPACE, // Operate; + + KEY_LMOUSE, // FirePrimaryWeapon; + KEY_RMOUSE, // FireSecondaryWeapon; + + KEY_RBRACKET, // NextWeapon; + KEY_LBRACKET, // PreviousWeapon; + KEY_BACKSPACE, // FlashbackWeapon; + + KEY_FSTOP, // Cloak; + KEY_SLASH, // CycleVisionMode; + KEY_PAGEUP, // ZoomIn; + KEY_PAGEDOWN, // ZoomOut; + KEY_APOSTROPHE, // GrapplingHook + KEY_COMMA, // RecallDisk + KEY_SEMICOLON, // Taunt + KEY_F1, + KEY_F11, + KEY_F12, + KEY_TAB, +}; + +PLAYER_INPUT_CONFIGURATION DefaultAlienInputPrimaryConfig = +{ + KEY_UP, // Forward; + KEY_DOWN, // Backward; + KEY_NUMPAD4, // Left; + KEY_NUMPAD6, // Right; + + KEY_RIGHTALT, // Strafe; + KEY_LEFT, // StrafeLeft; + KEY_RIGHT, // StrafeRight; + + KEY_Q, // LookUp; + KEY_Z, // LookDown; + KEY_A, // CentreView; + + KEY_LEFTSHIFT, // Walk; + KEY_RIGHTCTRL, // Crouch; + KEY_RIGHTSHIFT, // Jump; + + KEY_SPACE, // Operate; + + KEY_LMOUSE, // FirePrimaryWeapon; + KEY_RMOUSE, // FireSecondaryWeapon; + + KEY_SLASH, // AlternateVision; + KEY_FSTOP, // Taunt; + KEY_F1, + KEY_F11, + KEY_F12, + KEY_TAB, +}; +#elif 0 // Dutch +PLAYER_INPUT_CONFIGURATION DefaultMarineInputPrimaryConfig = +{ + KEY_UP, // Forward; + KEY_DOWN, // Backward; + KEY_NUMPAD4, // Left; + KEY_NUMPAD6, // Right; + + KEY_RIGHTALT, // Strafe; + KEY_LEFT, // StrafeLeft; + KEY_RIGHT, // StrafeRight; + + KEY_Q, // LookUp; + KEY_Z, // LookDown; + KEY_A, // CentreView; + + KEY_LEFTSHIFT, // Walk; + KEY_RIGHTCTRL, // Crouch; + KEY_RIGHTSHIFT, // Jump; + + KEY_SPACE, // Operate; + + KEY_LMOUSE, // FirePrimaryWeapon; + KEY_RMOUSE, // FireSecondaryWeapon; + + KEY_ASTERISK, // NextWeapon; + KEY_DIACRITIC_UMLAUT,// PreviousWeapon; + KEY_BACKSPACE, // FlashbackWeapon; + + KEY_MINUS, // ImageIntensifier; + KEY_FSTOP, // ThrowFlare; + KEY_DIACRITIC_ACUTE, // Jetpack; + KEY_PLUS, // Taunt + KEY_F1, + KEY_F11, + KEY_F12, + KEY_TAB, +}; +PLAYER_INPUT_CONFIGURATION DefaultPredatorInputPrimaryConfig = +{ + KEY_UP, // Forward; + KEY_DOWN, // Backward; + KEY_NUMPAD4, // Left; + KEY_NUMPAD6, // Right; + + KEY_RIGHTALT, // Strafe; + KEY_LEFT, // StrafeLeft; + KEY_RIGHT, // StrafeRight; + + KEY_Q, // LookUp; + KEY_Z, // LookDown; + KEY_A, // CentreView; + + KEY_LEFTSHIFT, // Walk; + KEY_RIGHTCTRL, // Crouch; + KEY_RIGHTSHIFT, // Jump; + + KEY_SPACE, // Operate; + + KEY_LMOUSE, // FirePrimaryWeapon; + KEY_RMOUSE, // FireSecondaryWeapon; + + KEY_ASTERISK, // NextWeapon; + KEY_DIACRITIC_UMLAUT,// PreviousWeapon; + KEY_BACKSPACE, // FlashbackWeapon; + + KEY_FSTOP, // Cloak; + KEY_MINUS, // CycleVisionMode; + KEY_PAGEUP, // ZoomIn; + KEY_PAGEDOWN, // ZoomOut; + KEY_DIACRITIC_ACUTE, // GrapplingHook + KEY_COMMA, // RecallDisk + KEY_PLUS, // Taunt + KEY_F1, + KEY_F11, + KEY_F12, + KEY_TAB, +}; + +PLAYER_INPUT_CONFIGURATION DefaultAlienInputPrimaryConfig = +{ + KEY_UP, // Forward; + KEY_DOWN, // Backward; + KEY_NUMPAD4, // Left; + KEY_NUMPAD6, // Right; + + KEY_RIGHTALT, // Strafe; + KEY_LEFT, // StrafeLeft; + KEY_RIGHT, // StrafeRight; + + KEY_Q, // LookUp; + KEY_Z, // LookDown; + KEY_A, // CentreView; + + KEY_LEFTSHIFT, // Walk; + KEY_RIGHTCTRL, // Crouch; + KEY_RIGHTSHIFT, // Jump; + + KEY_SPACE, // Operate; + + KEY_LMOUSE, // FirePrimaryWeapon; + KEY_RMOUSE, // FireSecondaryWeapon; + + KEY_MINUS, // AlternateVision; + KEY_FSTOP, // Taunt; + KEY_F1, + KEY_F11, + KEY_F12, + KEY_TAB, +}; +#elif 0 // French +PLAYER_INPUT_CONFIGURATION DefaultMarineInputPrimaryConfig = +{ + KEY_UP, // Forward; + KEY_DOWN, // Backward; + KEY_NUMPAD4, // Left; + KEY_NUMPAD6, // Right; + + KEY_RIGHTALT, // Strafe; + KEY_LEFT, // StrafeLeft; + KEY_RIGHT, // StrafeRight; + + KEY_A, // LookUp; + KEY_W, // LookDown; + KEY_Q, // CentreView; + + KEY_LEFTSHIFT, // Walk; + KEY_RIGHTCTRL, // Crouch; + KEY_RIGHTSHIFT, // Jump; + + KEY_SPACE, // Operate; + + KEY_LMOUSE, // FirePrimaryWeapon; + KEY_RMOUSE, // FireSecondaryWeapon; + + KEY_DOLLAR, // NextWeapon; + KEY_DIACRITIC_CARET, // PreviousWeapon; + KEY_BACKSPACE, // FlashbackWeapon; + + KEY_EXCLAMATION, // ImageIntensifier; + KEY_COLON, // ThrowFlare; + KEY_U_GRAVE, // Jetpack; + KEY_M, // Taunt + KEY_F1, + KEY_F11, + KEY_F12, + KEY_TAB, +}; +PLAYER_INPUT_CONFIGURATION DefaultPredatorInputPrimaryConfig = +{ + KEY_UP, // Forward; + KEY_DOWN, // Backward; + KEY_NUMPAD4, // Left; + KEY_NUMPAD6, // Right; + + KEY_RIGHTALT, // Strafe; + KEY_LEFT, // StrafeLeft; + KEY_RIGHT, // StrafeRight; + + KEY_A, // LookUp; + KEY_W, // LookDown; + KEY_Q, // CentreView; + + KEY_LEFTSHIFT, // Walk; + KEY_RIGHTCTRL, // Crouch; + KEY_RIGHTSHIFT, // Jump; + + KEY_SPACE, // Operate; + + KEY_LMOUSE, // FirePrimaryWeapon; + KEY_RMOUSE, // FireSecondaryWeapon; + + KEY_DOLLAR, // NextWeapon; + KEY_DIACRITIC_CARET, // PreviousWeapon; + KEY_BACKSPACE, // FlashbackWeapon; + + KEY_COLON, // Cloak; + KEY_EXCLAMATION, // CycleVisionMode; + KEY_PAGEUP, // ZoomIn; + KEY_PAGEDOWN, // ZoomOut; + KEY_U_GRAVE, // GrapplingHook + KEY_SEMICOLON, // RecallDisk + KEY_M, // Taunt + KEY_F1, + KEY_F11, + KEY_F12, + KEY_TAB, +}; + +PLAYER_INPUT_CONFIGURATION DefaultAlienInputPrimaryConfig = +{ + KEY_UP, // Forward; + KEY_DOWN, // Backward; + KEY_NUMPAD4, // Left; + KEY_NUMPAD6, // Right; + + KEY_RIGHTALT, // Strafe; + KEY_LEFT, // StrafeLeft; + KEY_RIGHT, // StrafeRight; + + KEY_A, // LookUp; + KEY_W, // LookDown; + KEY_Q, // CentreView; + + KEY_LEFTSHIFT, // Walk; + KEY_RIGHTCTRL, // Crouch; + KEY_RIGHTSHIFT, // Jump; + + KEY_SPACE, // Operate; + + KEY_LMOUSE, // FirePrimaryWeapon; + KEY_RMOUSE, // FireSecondaryWeapon; + + KEY_EXCLAMATION, // AlternateVision; + KEY_SEMICOLON, // Taunt; + KEY_F1, + KEY_F11, + KEY_F12, + KEY_TAB, +}; +#elif 0 // German +PLAYER_INPUT_CONFIGURATION DefaultMarineInputPrimaryConfig = +{ + KEY_UP, // Forward; + KEY_DOWN, // Backward; + KEY_NUMPAD4, // Left; + KEY_NUMPAD6, // Right; + + KEY_RIGHTALT, // Strafe; + KEY_LEFT, // StrafeLeft; + KEY_RIGHT, // StrafeRight; + + KEY_Q, // LookUp; + KEY_Y, // LookDown; + KEY_A, // CentreView; + + KEY_LEFTSHIFT, // Walk; + KEY_RIGHTCTRL, // Crouch; + KEY_RIGHTSHIFT, // Jump; + + KEY_SPACE, // Operate; + + KEY_LMOUSE, // FirePrimaryWeapon; + KEY_RMOUSE, // FireSecondaryWeapon; + + KEY_PLUS, // NextWeapon; + KEY_U_UMLAUT, // PreviousWeapon; + KEY_BACKSPACE, // FlashbackWeapon; + + KEY_MINUS, // ImageIntensifier; + KEY_FSTOP, // ThrowFlare; + KEY_A_UMLAUT, // Jetpack; + KEY_O_UMLAUT, // Taunt + KEY_F1, + KEY_F11, + KEY_F12, + KEY_TAB, +}; +PLAYER_INPUT_CONFIGURATION DefaultPredatorInputPrimaryConfig = +{ + KEY_UP, // Forward; + KEY_DOWN, // Backward; + KEY_NUMPAD4, // Left; + KEY_NUMPAD6, // Right; + + KEY_RIGHTALT, // Strafe; + KEY_LEFT, // StrafeLeft; + KEY_RIGHT, // StrafeRight; + + KEY_Q, // LookUp; + KEY_Y, // LookDown; + KEY_A, // CentreView; + + KEY_LEFTSHIFT, // Walk; + KEY_RIGHTCTRL, // Crouch; + KEY_RIGHTSHIFT, // Jump; + + KEY_SPACE, // Operate; + + KEY_LMOUSE, // FirePrimaryWeapon; + KEY_RMOUSE, // FireSecondaryWeapon; + + KEY_PLUS, // NextWeapon; + KEY_U_UMLAUT, // PreviousWeapon; + KEY_BACKSPACE, // FlashbackWeapon; + + KEY_FSTOP, // Cloak; + KEY_MINUS, // CycleVisionMode; + KEY_PAGEUP, // ZoomIn; + KEY_PAGEDOWN, // ZoomOut; + KEY_A_UMLAUT, // GrapplingHook + KEY_COMMA, // RecallDisk + KEY_O_UMLAUT, // Taunt + KEY_F1, + KEY_F11, + KEY_F12, + KEY_TAB, +}; + +PLAYER_INPUT_CONFIGURATION DefaultAlienInputPrimaryConfig = +{ + KEY_UP, // Forward; + KEY_DOWN, // Backward; + KEY_NUMPAD4, // Left; + KEY_NUMPAD6, // Right; + + KEY_RIGHTALT, // Strafe; + KEY_LEFT, // StrafeLeft; + KEY_RIGHT, // StrafeRight; + + KEY_Q, // LookUp; + KEY_Y, // LookDown; + KEY_A, // CentreView; + + KEY_LEFTSHIFT, // Walk; + KEY_RIGHTCTRL, // Crouch; + KEY_RIGHTSHIFT, // Jump; + + KEY_SPACE, // Operate; + + KEY_LMOUSE, // FirePrimaryWeapon; + KEY_RMOUSE, // FireSecondaryWeapon; + + KEY_MINUS, // AlternateVision; + KEY_FSTOP, // Taunt; + KEY_F1, + KEY_F11, + KEY_F12, + KEY_TAB, +}; +#elif 0 // Spanish +PLAYER_INPUT_CONFIGURATION DefaultMarineInputPrimaryConfig = +{ + KEY_UP, // Forward; + KEY_DOWN, // Backward; + KEY_NUMPAD4, // Left; + KEY_NUMPAD6, // Right; + + KEY_RIGHTALT, // Strafe; + KEY_LEFT, // StrafeLeft; + KEY_RIGHT, // StrafeRight; + + KEY_Q, // LookUp; + KEY_Z, // LookDown; + KEY_A, // CentreView; + + KEY_LEFTSHIFT, // Walk; + KEY_RIGHTCTRL, // Crouch; + KEY_RIGHTSHIFT, // Jump; + + KEY_SPACE, // Operate; + + KEY_LMOUSE, // FirePrimaryWeapon; + KEY_RMOUSE, // FireSecondaryWeapon; + + KEY_PLUS, // NextWeapon; + KEY_DIACRITIC_GRAVE, // PreviousWeapon; + KEY_BACKSPACE, // FlashbackWeapon; + + KEY_MINUS, // ImageIntensifier; + KEY_FSTOP, // ThrowFlare; + KEY_DIACRITIC_ACUTE, // Jetpack; + KEY_N_TILDE, // Taunt + KEY_F1, + KEY_F11, + KEY_F12, + KEY_TAB, +}; +PLAYER_INPUT_CONFIGURATION DefaultPredatorInputPrimaryConfig = +{ + KEY_UP, // Forward; + KEY_DOWN, // Backward; + KEY_NUMPAD4, // Left; + KEY_NUMPAD6, // Right; + + KEY_RIGHTALT, // Strafe; + KEY_LEFT, // StrafeLeft; + KEY_RIGHT, // StrafeRight; + + KEY_Q, // LookUp; + KEY_Z, // LookDown; + KEY_A, // CentreView; + + KEY_LEFTSHIFT, // Walk; + KEY_RIGHTCTRL, // Crouch; + KEY_RIGHTSHIFT, // Jump; + + KEY_SPACE, // Operate; + + KEY_LMOUSE, // FirePrimaryWeapon; + KEY_RMOUSE, // FireSecondaryWeapon; + + KEY_PLUS, // NextWeapon; + KEY_DIACRITIC_GRAVE, // PreviousWeapon; + KEY_BACKSPACE, // FlashbackWeapon; + + KEY_FSTOP, // Cloak; + KEY_MINUS, // CycleVisionMode; + KEY_PAGEUP, // ZoomIn; + KEY_PAGEDOWN, // ZoomOut; + KEY_DIACRITIC_ACUTE, // GrapplingHook + KEY_COMMA, // RecallDisk + KEY_N_TILDE, // Taunt + KEY_F1, + KEY_F11, + KEY_F12, + KEY_TAB, +}; + +PLAYER_INPUT_CONFIGURATION DefaultAlienInputPrimaryConfig = +{ + KEY_UP, // Forward; + KEY_DOWN, // Backward; + KEY_NUMPAD4, // Left; + KEY_NUMPAD6, // Right; + + KEY_RIGHTALT, // Strafe; + KEY_LEFT, // StrafeLeft; + KEY_RIGHT, // StrafeRight; + + KEY_Q, // LookUp; + KEY_Z, // LookDown; + KEY_A, // CentreView; + + KEY_LEFTSHIFT, // Walk; + KEY_RIGHTCTRL, // Crouch; + KEY_RIGHTSHIFT, // Jump; + + KEY_SPACE, // Operate; + + KEY_LMOUSE, // FirePrimaryWeapon; + KEY_RMOUSE, // FireSecondaryWeapon; + + KEY_MINUS, // AlternateVision; + KEY_FSTOP, // Taunt; + KEY_F1, + KEY_F11, + KEY_F12, + KEY_TAB, +}; +#endif +PLAYER_INPUT_CONFIGURATION DefaultMarineInputSecondaryConfig = +{ + KEY_VOID, // Forward; + KEY_VOID, // Backward; + KEY_VOID, // Left; + KEY_VOID, // Right; + + KEY_VOID, // Strafe; + KEY_VOID, // StrafeLeft; + KEY_VOID, // StrafeRight; + + KEY_NUMPAD8, // LookUp; + KEY_NUMPAD2, // LookDown; + KEY_NUMPAD5, // CentreView; + + KEY_VOID, // Walk; + KEY_VOID, // Crouch; + KEY_MMOUSE, // Jump; + + KEY_CR, // Operate; + + KEY_NUMPAD0, // FirePrimaryWeapon; + KEY_NUMPADDEL, // FireSecondaryWeapon; + + KEY_MOUSEWHEELUP, // NextWeapon; + KEY_MOUSEWHEELDOWN, // PreviousWeapon; + KEY_VOID, // FlashbackWeapon; + + KEY_VOID, // ImageIntensifier; + KEY_VOID, // ThrowFlare; + KEY_VOID, // Jetpack; + KEY_VOID, // Taunt + + KEY_VOID, + KEY_VOID, + KEY_VOID, + KEY_VOID, +}; + + + + +PLAYER_INPUT_CONFIGURATION DefaultPredatorInputSecondaryConfig = +{ + KEY_VOID, // Forward; + KEY_VOID, // Backward; + KEY_VOID, // Left; + KEY_VOID, // Right; + + KEY_VOID, // Strafe; + KEY_VOID, // StrafeLeft; + KEY_VOID, // StrafeRight; + + KEY_NUMPAD8, // LookUp; + KEY_NUMPAD2, // LookDown; + KEY_NUMPAD5, // CentreView; + + KEY_VOID, // Walk; + KEY_VOID, // Crouch; + KEY_MMOUSE, // Jump; + + KEY_CR, // Operate; + + KEY_NUMPAD0, // FirePrimaryWeapon; + KEY_NUMPADDEL, // FireSecondaryWeapon; + + KEY_VOID, // NextWeapon; + KEY_VOID, // PreviousWeapon; + KEY_VOID, // FlashbackWeapon; + + KEY_VOID, // Cloak; + KEY_VOID, // CycleVisionMode; + KEY_MOUSEWHEELUP, // ZoomIn; + KEY_MOUSEWHEELDOWN, // ZoomOut; + KEY_VOID, // GrapplingHook; + KEY_VOID, // RecallDisk + KEY_VOID, // Taunt + + KEY_VOID, + KEY_VOID, + KEY_VOID, + KEY_VOID, + +}; + +PLAYER_INPUT_CONFIGURATION DefaultAlienInputSecondaryConfig = +{ + KEY_VOID, // Forward; + KEY_VOID, // Backward; + KEY_VOID, // Left; + KEY_VOID, // Right; + + KEY_VOID, // Strafe; + KEY_VOID, // StrafeLeft; + KEY_VOID, // StrafeRight; + + KEY_NUMPAD8, // LookUp; + KEY_NUMPAD2, // LookDown; + KEY_NUMPAD5, // CentreView; + + KEY_VOID, // Walk; + KEY_VOID, // Crouch; + KEY_MMOUSE, // Jump; + + KEY_CR, // Operate; + + KEY_NUMPAD0, // FirePrimaryWeapon; + KEY_NUMPADDEL, // FireSecondaryWeapon; + + KEY_VOID, // AlternateVision; + KEY_VOID, // Taunt; + KEY_VOID, + KEY_VOID, + KEY_VOID, + KEY_VOID, +}; + + +CONTROL_METHODS ControlMethods = +{ + /* analogue stuff */ + DEFAULT_MOUSEX_SENSITIVITY, //unsigned int MouseXSensitivity; + DEFAULT_MOUSEY_SENSITIVITY, //unsigned int MouseYSensitivity; + + 0,//unsigned int VAxisIsMovement :1; // else it's looking + 1,//unsigned int HAxisIsTurning :1; // else it's sidestepping + + 0,//unsigned int FlipVerticalAxis :1; + + /* general stuff */ + 0,//unsigned int AutoCentreOnMovement :1; +}; + +CONTROL_METHODS DefaultControlMethods = +{ + /* analogue stuff */ + DEFAULT_MOUSEX_SENSITIVITY, //unsigned int MouseXSensitivity; + DEFAULT_MOUSEY_SENSITIVITY, //unsigned int MouseYSensitivity; + + 0,//unsigned int VAxisIsMovement :1; // else it's looking + 1,//unsigned int HAxisIsTurning :1; // else it's sidestepping + + 0,//unsigned int FlipVerticalAxis :1; + + /* general stuff */ + 0,//unsigned int AutoCentreOnMovement :1; +}; + +JOYSTICK_CONTROL_METHODS JoystickControlMethods = +{ + 0,//unsigned int JoystickEnabled; + + 1,//unsigned int JoystickVAxisIsMovement; // else it's looking + 1,//unsigned int JoystickHAxisIsTurning; // else it's sidestepping + 0,//unsigned int JoystickFlipVerticalAxis; + + 0,//unsigned int JoystickPOVVAxisIsMovement; // else it's looking + 0,//unsigned int JoystickPOVHAxisIsTurning; // else it's sidestepping + 0,//unsigned int JoystickPOVFlipVerticalAxis; + + 0,//unsigned int JoystickRudderEnabled; + 0,//unsigned int JoystickRudderAxisIsTurning; // else it's sidestepping + + 0,//unsigned int JoystickTrackerBallEnabled; + 0,//unsigned int JoystickTrackerBallFlipVerticalAxis; + DEFAULT_TRACKERBALL_HORIZONTAL_SENSITIVITY,//unsigned int JoystickTrackerBallHorizontalSensitivity; + DEFAULT_TRACKERBALL_VERTICAL_SENSITIVITY,//unsigned int JoystickTrackerBallVerticalSensitivity; + +}; +JOYSTICK_CONTROL_METHODS DefaultJoystickControlMethods = +{ + 0,//unsigned int JoystickEnabled; + + 1,//unsigned int JoystickVAxisIsMovement; // else it's looking + 1,//unsigned int JoystickHAxisIsTurning; // else it's sidestepping + 0,//unsigned int JoystickFlipVerticalAxis; + + 0,//unsigned int JoystickPOVVAxisIsMovement; // else it's looking + 0,//unsigned int JoystickPOVHAxisIsTurning; // else it's sidestepping + 0,//unsigned int JoystickPOVFlipVerticalAxis; + + 0,//unsigned int JoystickRudderEnabled; + 0,//unsigned int JoystickRudderAxisIsTurning; // else it's sidestepping + + 0,//unsigned int JoystickTrackerBallEnabled; + 0,//unsigned int JoystickTrackerBallFlipVerticalAxis; + DEFAULT_TRACKERBALL_HORIZONTAL_SENSITIVITY,//unsigned int JoystickTrackerBallHorizontalSensitivity; + DEFAULT_TRACKERBALL_VERTICAL_SENSITIVITY,//unsigned int JoystickTrackerBallVerticalSensitivity; +}; + +/* Extern for global keyboard buffer */ +extern unsigned char KeyboardInput[]; +extern unsigned char DebouncedKeyboardInput[]; +extern int GotJoystick; +extern int GotMouse; + +/* initialise the player input structure(s) in the player_status block */ +void InitPlayerGameInput(STRATEGYBLOCK* sbPtr) +{ + PLAYER_STATUS *playerStatusPtr; + + /* get the player status block ... */ + playerStatusPtr = (PLAYER_STATUS *) (sbPtr->SBdataptr); + LOCALASSERT(playerStatusPtr); + + + /* analogue type inputs */ + playerStatusPtr->Mvt_MotionIncrement = 0; + playerStatusPtr->Mvt_TurnIncrement = 0; + playerStatusPtr->Mvt_PitchIncrement = 0; + playerStatusPtr->Mvt_AnalogueTurning = 0; + playerStatusPtr->Mvt_AnaloguePitching = 0; + playerStatusPtr->Mvt_SideStepIncrement = 0; + + /* request flags */ + playerStatusPtr->Mvt_InputRequests.Mask = 0; + playerStatusPtr->Mvt_InputRequests.Mask2 = 0; + + /* KJL 14:23:54 8/7/97 - default to run */ + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Faster = 1; + +} + + +/* This function maps raw inputs onto the players movement attributes in + the player_status block. It is called from the ExecuteFreeMovement + function. + NB Currently, only keyboard input is supported. */ +void ReadPlayerGameInput(STRATEGYBLOCK* sbPtr) +{ + PLAYER_INPUT_CONFIGURATION *primaryInput; + PLAYER_INPUT_CONFIGURATION *secondaryInput; + PLAYER_STATUS *playerStatusPtr; + + /* get the player status block ... */ + playerStatusPtr = (PLAYER_STATUS *) (sbPtr->SBdataptr); + LOCALASSERT(playerStatusPtr); + + /* start off by initialising the inputs */ + InitPlayerGameInput(sbPtr); + + switch (AvP.PlayerType) + { + case I_Marine: + { + primaryInput = &MarineInputPrimaryConfig; + secondaryInput = &MarineInputSecondaryConfig; + break; + } + case I_Predator: + { + primaryInput = &PredatorInputPrimaryConfig; + secondaryInput = &PredatorInputSecondaryConfig; + break; + } + case I_Alien: + { + primaryInput = &AlienInputPrimaryConfig; + secondaryInput = &AlienInputSecondaryConfig; + break; + } + } + + if ( IOFOCUS_AcceptControls() && !InGameMenusAreRunning()) + { + /* now do forward,backward,left,right,up and down + IMPORTANT: The request flag and the movement + increment must BOTH be set! + */ + if(KeyboardInput[primaryInput->Forward] + ||KeyboardInput[secondaryInput->Forward]) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Forward = 1; + playerStatusPtr->Mvt_MotionIncrement = ONE_FIXED; + } + if(KeyboardInput[primaryInput->Backward] + ||KeyboardInput[secondaryInput->Backward]) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Backward = 1; + playerStatusPtr->Mvt_MotionIncrement = -ONE_FIXED; + } + if(KeyboardInput[primaryInput->Left] + ||KeyboardInput[secondaryInput->Left]) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_TurnLeft = 1; + playerStatusPtr->Mvt_TurnIncrement = -ONE_FIXED; + } + if(KeyboardInput[primaryInput->Right] + ||KeyboardInput[secondaryInput->Right]) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_TurnRight = 1; + playerStatusPtr->Mvt_TurnIncrement = ONE_FIXED; + } + + if(KeyboardInput[primaryInput->StrafeLeft] + ||KeyboardInput[secondaryInput->StrafeLeft]) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepLeft = 1; + playerStatusPtr->Mvt_SideStepIncrement = -ONE_FIXED; + } + if(KeyboardInput[primaryInput->StrafeRight] + ||KeyboardInput[secondaryInput->StrafeRight]) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepRight = 1; + playerStatusPtr->Mvt_SideStepIncrement = ONE_FIXED; + } + if(KeyboardInput[primaryInput->Walk] + ||KeyboardInput[secondaryInput->Walk]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Faster = 0; + + if(KeyboardInput[primaryInput->Strafe] + ||KeyboardInput[secondaryInput->Strafe]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Strafe = 1; + + if(KeyboardInput[primaryInput->Crouch] + ||KeyboardInput[secondaryInput->Crouch]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Crouch = 1; + + if(KeyboardInput[primaryInput->Jump] + ||KeyboardInput[secondaryInput->Jump]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Jump = 1; + + if(KeyboardInput[primaryInput->Operate] + ||KeyboardInput[secondaryInput->Operate]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Operate = 1; + + /* check for character specific abilities */ + if (playerStatusPtr->IsAlive) + switch (AvP.PlayerType) + { + case I_Marine: + { + if(KeyboardInput[primaryInput->ImageIntensifier] + ||KeyboardInput[secondaryInput->ImageIntensifier]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_ChangeVision = 1; + + if(DebouncedKeyboardInput[primaryInput->ThrowFlare] + ||DebouncedKeyboardInput[secondaryInput->ThrowFlare]) + ThrowAFlare(); + + #if !(MARINE_DEMO||DEATHMATCH_DEMO) + if(KeyboardInput[primaryInput->Jetpack] + ||KeyboardInput[secondaryInput->Jetpack]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Jetpack = 1; + #endif + + if(KeyboardInput[primaryInput->MarineTaunt] + ||KeyboardInput[secondaryInput->MarineTaunt]) + StartPlayerTaunt(); + + if(DebouncedKeyboardInput[primaryInput->Marine_MessageHistory] + ||DebouncedKeyboardInput[secondaryInput->Marine_MessageHistory]) + MessageHistory_DisplayPrevious(); + + if(DebouncedKeyboardInput[primaryInput->Marine_Say] + ||DebouncedKeyboardInput[secondaryInput->Marine_Say]) + BringDownConsoleWithSayTypedIn(); + + if(DebouncedKeyboardInput[primaryInput->Marine_SpeciesSay] + ||DebouncedKeyboardInput[secondaryInput->Marine_SpeciesSay]) + BringDownConsoleWithSaySpeciesTypedIn(); + + if(KeyboardInput[primaryInput->Marine_ShowScores] + ||KeyboardInput[secondaryInput->Marine_ShowScores]) + ShowMultiplayerScores(); + + + break; + } + case I_Predator: + { + extern int CameraZoomLevel; + + if(KeyboardInput[primaryInput->Cloak] + ||KeyboardInput[secondaryInput->Cloak]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_ChangeVision = 1; + + if(DebouncedKeyboardInput[primaryInput->CycleVisionMode] + ||DebouncedKeyboardInput[secondaryInput->CycleVisionMode]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_CycleVisionMode = 1; + + #if !(PREDATOR_DEMO||DEATHMATCH_DEMO) + if(DebouncedKeyboardInput[primaryInput->GrapplingHook] + ||DebouncedKeyboardInput[secondaryInput->GrapplingHook]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_GrapplingHook = 1; + #endif + + if(DebouncedKeyboardInput[primaryInput->ZoomIn] + ||DebouncedKeyboardInput[secondaryInput->ZoomIn]) + { + if (CameraZoomLevel<3) CameraZoomLevel++; + } + if(DebouncedKeyboardInput[primaryInput->ZoomOut] + ||DebouncedKeyboardInput[secondaryInput->ZoomOut]) + { + if (CameraZoomLevel>0) CameraZoomLevel--; + } + + MaintainZoomingLevel(); + + if(KeyboardInput[primaryInput->PredatorTaunt] + ||KeyboardInput[secondaryInput->PredatorTaunt]) + StartPlayerTaunt(); + + if(KeyboardInput[primaryInput->RecallDisc] + ||KeyboardInput[secondaryInput->RecallDisc]) + Recall_Disc(); + + if(DebouncedKeyboardInput[primaryInput->Predator_MessageHistory] + ||DebouncedKeyboardInput[secondaryInput->Predator_MessageHistory]) + MessageHistory_DisplayPrevious(); + + if(DebouncedKeyboardInput[primaryInput->Predator_Say] + ||DebouncedKeyboardInput[secondaryInput->Predator_Say]) + BringDownConsoleWithSayTypedIn(); + + if(DebouncedKeyboardInput[primaryInput->Predator_SpeciesSay] + ||DebouncedKeyboardInput[secondaryInput->Predator_SpeciesSay]) + BringDownConsoleWithSaySpeciesTypedIn(); + + if(KeyboardInput[primaryInput->Predator_ShowScores] + ||KeyboardInput[secondaryInput->Predator_ShowScores]) + ShowMultiplayerScores(); + + break; + } + + case I_Alien: + { + if(KeyboardInput[primaryInput->AlternateVision] + ||KeyboardInput[secondaryInput->AlternateVision]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_ChangeVision = 1; + + if(KeyboardInput[primaryInput->Taunt] + ||KeyboardInput[secondaryInput->Taunt]) + StartPlayerTaunt(); + + if(DebouncedKeyboardInput[primaryInput->Alien_MessageHistory] + ||DebouncedKeyboardInput[secondaryInput->Alien_MessageHistory]) + MessageHistory_DisplayPrevious(); + + if(DebouncedKeyboardInput[primaryInput->Alien_Say] + ||DebouncedKeyboardInput[secondaryInput->Alien_Say]) + BringDownConsoleWithSayTypedIn(); + + if(DebouncedKeyboardInput[primaryInput->Alien_SpeciesSay] + ||DebouncedKeyboardInput[secondaryInput->Alien_SpeciesSay]) + BringDownConsoleWithSaySpeciesTypedIn(); + + if(KeyboardInput[primaryInput->Alien_ShowScores] + ||KeyboardInput[secondaryInput->Alien_ShowScores]) + ShowMultiplayerScores(); + + break; + } + } + + if(DebouncedKeyboardInput[FixedInputConfig.PauseGame]) + AvP_TriggerInGameMenus(); + // playerStatusPtr->Mvt_InputRequests.Flags.Rqst_QuitGame = 1; +// playerStatusPtr->Mvt_InputRequests.Flags.Rqst_PauseGame = 1; + + if(!PaintBallMode.IsOn) + { + if(KeyboardInput[primaryInput->FirePrimaryWeapon] + ||KeyboardInput[secondaryInput->FirePrimaryWeapon]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FirePrimaryWeapon = 1; + + if(KeyboardInput[primaryInput->LookUp] + ||KeyboardInput[secondaryInput->LookUp]) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_LookUp = 1; + playerStatusPtr->Mvt_PitchIncrement = -ONE_FIXED; + } + else if(KeyboardInput[primaryInput->LookDown] + ||KeyboardInput[secondaryInput->LookDown]) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_LookDown = 1; + playerStatusPtr->Mvt_PitchIncrement = ONE_FIXED; + } + + if(KeyboardInput[primaryInput->CentreView] + ||KeyboardInput[secondaryInput->CentreView]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_CentreView = 1; + + if(KeyboardInput[primaryInput->NextWeapon] + ||KeyboardInput[secondaryInput->NextWeapon]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_NextWeapon = 1; + + if(KeyboardInput[primaryInput->PreviousWeapon] + ||KeyboardInput[secondaryInput->PreviousWeapon]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_PreviousWeapon = 1; + + if(DebouncedKeyboardInput[primaryInput->FlashbackWeapon] + ||DebouncedKeyboardInput[secondaryInput->FlashbackWeapon]) + { + if (playerStatusPtr->PreviouslySelectedWeaponSlot!=playerStatusPtr->SelectedWeaponSlot) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo = playerStatusPtr->PreviouslySelectedWeaponSlot+1; + } + } + + if(KeyboardInput[primaryInput->FireSecondaryWeapon] + ||KeyboardInput[secondaryInput->FireSecondaryWeapon]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FireSecondaryWeapon = 1; + + /* fixed controls */ + if(KeyboardInput[FixedInputConfig.Weapon1]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo = 1; + + #if !PREDATOR_DEMO + if(KeyboardInput[FixedInputConfig.Weapon2]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo = 2; + #else + if(DebouncedKeyboardInput[FixedInputConfig.Weapon2]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo = 2; + #endif + if(KeyboardInput[FixedInputConfig.Weapon3]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo = 3; + + #if !(MARINE_DEMO) + if(KeyboardInput[FixedInputConfig.Weapon4]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo = 4; + #else + if(DebouncedKeyboardInput[FixedInputConfig.Weapon4]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo = 4; + #endif + + #if !(PREDATOR_DEMO||MARINE_DEMO) + if(KeyboardInput[FixedInputConfig.Weapon5]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo = 5; + #else + if(DebouncedKeyboardInput[FixedInputConfig.Weapon5]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo = 5; + #endif + + #if !(MARINE_DEMO) + if(KeyboardInput[FixedInputConfig.Weapon6]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo = 6; + #else + if(DebouncedKeyboardInput[FixedInputConfig.Weapon6]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo = 6; + #endif + + if(KeyboardInput[FixedInputConfig.Weapon7]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo = 7; + + if(KeyboardInput[FixedInputConfig.Weapon8]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo = 8; + + if(KeyboardInput[FixedInputConfig.Weapon9]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo = 9; + + if(KeyboardInput[FixedInputConfig.Weapon10]) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_WeaponNo = 10; + + + } + #if !(PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO||DEATHMATCH_DEMO) + else // Cool - paintball mode ` + { + if(DebouncedKeyboardInput[primaryInput->NextWeapon] + ||DebouncedKeyboardInput[secondaryInput->NextWeapon]) + { + PaintBallMode_ChangeSelectedDecalID(+1); + } + + if(DebouncedKeyboardInput[primaryInput->PreviousWeapon] + ||DebouncedKeyboardInput[secondaryInput->PreviousWeapon]) + { + PaintBallMode_ChangeSelectedDecalID(-1); + } + + if(KeyboardInput[primaryInput->LookUp] + ||KeyboardInput[secondaryInput->LookUp]) + { + PaintBallMode_ChangeSize(+1); + } + + if(KeyboardInput[primaryInput->LookDown] + ||KeyboardInput[secondaryInput->LookDown]) + { + PaintBallMode_ChangeSize(-1); + } + + if(KeyboardInput[primaryInput->CentreView] + ||KeyboardInput[secondaryInput->CentreView]) + { + PaintBallMode_Rotate(); + } + + if(DebouncedKeyboardInput[FixedInputConfig.Weapon1]) + { + PaintBallMode_ChangeSubclass(+1); + } + + if(DebouncedKeyboardInput[FixedInputConfig.Weapon2]) + { + PaintBallMode_ChangeSubclass(-1); + } + + if(DebouncedKeyboardInput[FixedInputConfig.Weapon3]) + { + PaintBallMode.DecalIsInverted = ~PaintBallMode.DecalIsInverted; + } + + if(DebouncedKeyboardInput[FixedInputConfig.Weapon4]) + { + PaintBallMode_Randomise(); + } + + if(DebouncedKeyboardInput[FixedInputConfig.Weapon10]) + { + extern void save_preplaced_decals(); + save_preplaced_decals(); + } + + + if(DebouncedKeyboardInput[primaryInput->FirePrimaryWeapon] + ||DebouncedKeyboardInput[secondaryInput->FirePrimaryWeapon]) + { + PaintBallMode_AddDecal(); + } + if(DebouncedKeyboardInput[primaryInput->FireSecondaryWeapon] + ||DebouncedKeyboardInput[secondaryInput->FireSecondaryWeapon]) + { + PaintBallMode_RemoveDecal(); + } + + } + #endif + } + /* end of block conditional on input focus */ + + + /* KJL 10:16:49 04/29/97 - mouse control */ + + + + + if (GotMouse) + { + extern int MouseVelX; + extern int MouseVelY; + + + if(ControlMethods.HAxisIsTurning) + { + if(MouseVelX<0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_TurnLeft = 1; + playerStatusPtr->Mvt_AnalogueTurning = 1; + playerStatusPtr->Mvt_TurnIncrement = ((int)MouseVelX)*ControlMethods.MouseXSensitivity; + + } + else if(MouseVelX>0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_TurnRight = 1; + playerStatusPtr->Mvt_AnalogueTurning = 1; + playerStatusPtr->Mvt_TurnIncrement = ((int)MouseVelX)*ControlMethods.MouseXSensitivity; + } + + /* KJL 17:36:37 9/9/97 - cap values if strafing */ + if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Strafe) + { + if(playerStatusPtr->Mvt_TurnIncrement < -ONE_FIXED) + playerStatusPtr->Mvt_TurnIncrement = -ONE_FIXED; + if(playerStatusPtr->Mvt_TurnIncrement > ONE_FIXED) + playerStatusPtr->Mvt_TurnIncrement = ONE_FIXED; + } + + } + else // it's sidestep + { + if(MouseVelX<0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepLeft = 1; + playerStatusPtr->Mvt_SideStepIncrement = ((int)MouseVelX)*ControlMethods.MouseXSensitivity; + } + else if(MouseVelX>0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepRight = 1; + playerStatusPtr->Mvt_SideStepIncrement = ((int)MouseVelX)*ControlMethods.MouseXSensitivity; + } + + if(playerStatusPtr->Mvt_SideStepIncrement < -ONE_FIXED) + playerStatusPtr->Mvt_SideStepIncrement = -ONE_FIXED; + if(playerStatusPtr->Mvt_SideStepIncrement > ONE_FIXED) + playerStatusPtr->Mvt_SideStepIncrement = ONE_FIXED; + + + } + + if(ControlMethods.VAxisIsMovement) + { + + if(MouseVelY<0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Forward = 1; + playerStatusPtr->Mvt_MotionIncrement = -((int)MouseVelY)*ControlMethods.MouseYSensitivity; + } + else if(MouseVelY>0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Backward = 1; + playerStatusPtr->Mvt_MotionIncrement = -((int)MouseVelY)*ControlMethods.MouseYSensitivity; + } + + if(playerStatusPtr->Mvt_MotionIncrement < -ONE_FIXED) + playerStatusPtr->Mvt_MotionIncrement = -ONE_FIXED; + if(playerStatusPtr->Mvt_MotionIncrement > ONE_FIXED) + playerStatusPtr->Mvt_MotionIncrement = ONE_FIXED; + } + else // it's looking + { + int newMouseVelY; + + if (ControlMethods.FlipVerticalAxis) newMouseVelY = -MouseVelY; + else newMouseVelY = MouseVelY; + + if(newMouseVelY<0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_LookUp = 1; + playerStatusPtr->Mvt_AnaloguePitching = 1; + playerStatusPtr->Mvt_PitchIncrement = ((int)newMouseVelY)*ControlMethods.MouseYSensitivity; + } + else if(newMouseVelY>0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_LookDown = 1; + playerStatusPtr->Mvt_AnaloguePitching = 1; + playerStatusPtr->Mvt_PitchIncrement = ((int)newMouseVelY)*ControlMethods.MouseYSensitivity; + } + } + + } + + /* KJL 18:27:34 04/29/97 - joystick control */ + if (GotJoystick) + { + #define JOYSTICK_DEAD_ZONE 12000 + extern int GotJoystick; + extern JOYINFOEX JoystickData; + extern JOYCAPS JoystickCaps; + + + int yAxis = (32768-JoystickData.dwYpos)*2; + int xAxis = (JoystickData.dwXpos-32768)*2; + + if(JoystickControlMethods.JoystickVAxisIsMovement) + { + if(JoystickControlMethods.JoystickFlipVerticalAxis) yAxis=-yAxis; + + if(yAxis>JOYSTICK_DEAD_ZONE) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Forward = 1; + playerStatusPtr->Mvt_MotionIncrement = yAxis; + } + else if(yAxis<-JOYSTICK_DEAD_ZONE) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Backward = 1; + playerStatusPtr->Mvt_MotionIncrement = yAxis; + } + } + else // looking up/down + { + if(!JoystickControlMethods.JoystickFlipVerticalAxis) yAxis=-yAxis; + + if(yAxis>JOYSTICK_DEAD_ZONE) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_LookDown = 1; + playerStatusPtr->Mvt_AnaloguePitching = 1; + playerStatusPtr->Mvt_PitchIncrement = yAxis; + } + else if(yAxis<-JOYSTICK_DEAD_ZONE) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_LookUp = 1; + playerStatusPtr->Mvt_AnaloguePitching = 1; + playerStatusPtr->Mvt_PitchIncrement = yAxis; + } + } + + if (JoystickControlMethods.JoystickHAxisIsTurning) + { + if(xAxis<-JOYSTICK_DEAD_ZONE) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_TurnLeft = 1; + playerStatusPtr->Mvt_AnalogueTurning = 1; + playerStatusPtr->Mvt_TurnIncrement = xAxis; + } + else if(xAxis>JOYSTICK_DEAD_ZONE) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_TurnRight = 1; + playerStatusPtr->Mvt_AnalogueTurning = 1; + playerStatusPtr->Mvt_TurnIncrement = xAxis; + } + } + else // strafing + { + if(xAxis<-JOYSTICK_DEAD_ZONE) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepLeft = 1; + playerStatusPtr->Mvt_SideStepIncrement = xAxis; + } + else if(xAxis>JOYSTICK_DEAD_ZONE) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepRight = 1; + playerStatusPtr->Mvt_SideStepIncrement = xAxis; + } + } + + /* check for rudder */ + if ((JoystickCaps.wCaps & JOYCAPS_HASR) && JoystickControlMethods.JoystickRudderEnabled) + { + int rAxis = (JoystickData.dwRpos-32768)*2; + if (JoystickControlMethods.JoystickRudderAxisIsTurning) + { + if(rAxis>JOYSTICK_DEAD_ZONE) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_TurnRight = 1; + playerStatusPtr->Mvt_AnalogueTurning = 1; + playerStatusPtr->Mvt_TurnIncrement = rAxis; + } + else if(rAxis<-JOYSTICK_DEAD_ZONE) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_TurnLeft = 1; + playerStatusPtr->Mvt_AnalogueTurning = 1; + playerStatusPtr->Mvt_TurnIncrement = rAxis; + } + } + else + { + if(rAxis>JOYSTICK_DEAD_ZONE) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Strafe = 1; + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_TurnRight = 1; + playerStatusPtr->Mvt_AnalogueTurning = 1; + playerStatusPtr->Mvt_TurnIncrement = rAxis; + } + else if(rAxis<-JOYSTICK_DEAD_ZONE) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Strafe = 1; + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_TurnLeft = 1; + playerStatusPtr->Mvt_AnalogueTurning = 1; + playerStatusPtr->Mvt_TurnIncrement = rAxis; + } + } + } + + /* check joystick buttons */ + #if 0 + if(JoystickData.dwButtons & JOY_BUTTON1) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FirePrimaryWeapon = 1; + else if(JoystickData.dwButtons & JOY_BUTTON2) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FireSecondaryWeapon = 1; + else if(JoystickData.dwButtons & JOY_BUTTON3) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_NextWeapon = 1; + else if(JoystickData.dwButtons & JOY_BUTTON4) + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_PreviousWeapon = 1; + #endif + + /* Point Of View Hat */ + if (JoystickData.dwPOV<36000) + { + int theta = ((JoystickData.dwPOV * 4096) /36000); + int verticalAxis = GetCos(theta); + int horizontalAxis = GetSin(theta); + + if (JoystickControlMethods.JoystickPOVFlipVerticalAxis) + { + verticalAxis = -verticalAxis; + } + + if (JoystickControlMethods.JoystickPOVVAxisIsMovement) + { + if(verticalAxis>0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Forward = 1; + playerStatusPtr->Mvt_MotionIncrement = verticalAxis; + } + else if(verticalAxis<0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_Backward = 1; + playerStatusPtr->Mvt_MotionIncrement = verticalAxis; + } + } + else + { + if(verticalAxis>0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_LookUp = 1; + playerStatusPtr->Mvt_PitchIncrement -= verticalAxis; + } + else if(verticalAxis<0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_LookDown = 1; + playerStatusPtr->Mvt_PitchIncrement -= verticalAxis; + } + } + if (JoystickControlMethods.JoystickPOVHAxisIsTurning) + { + if(horizontalAxis>0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_TurnRight = 1; + playerStatusPtr->Mvt_AnalogueTurning = 1; + playerStatusPtr->Mvt_TurnIncrement = horizontalAxis; + } + else if(horizontalAxis<0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_TurnLeft = 1; + playerStatusPtr->Mvt_AnalogueTurning = 1; + playerStatusPtr->Mvt_TurnIncrement = horizontalAxis; + } + } + else // strafing + { + if(horizontalAxis>0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepRight = 1; + playerStatusPtr->Mvt_SideStepIncrement = horizontalAxis; + } + else if(horizontalAxis<0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_SideStepLeft = 1; + playerStatusPtr->Mvt_SideStepIncrement = horizontalAxis; + } + } + } + if (JoystickControlMethods.JoystickTrackerBallEnabled) + { + int trackerballH = JoystickData.dwUpos - 32768; + int trackerballV = JoystickData.dwVpos - 32768; + + if (JoystickControlMethods.JoystickTrackerBallFlipVerticalAxis) + { + trackerballV = -trackerballV; + } + + if(trackerballH<0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_TurnLeft = 1; + playerStatusPtr->Mvt_AnalogueTurning = 1; + playerStatusPtr->Mvt_TurnIncrement = trackerballH*JoystickControlMethods.JoystickTrackerBallHorizontalSensitivity; + + } + else if(trackerballH>0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_TurnRight = 1; + playerStatusPtr->Mvt_AnalogueTurning = 1; + playerStatusPtr->Mvt_TurnIncrement = trackerballH*JoystickControlMethods.JoystickTrackerBallHorizontalSensitivity; + + } + if(trackerballV<0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_LookUp = 1; + playerStatusPtr->Mvt_AnaloguePitching = 1; + playerStatusPtr->Mvt_PitchIncrement = trackerballV*JoystickControlMethods.JoystickTrackerBallVerticalSensitivity; + } + else if(trackerballV>0) + { + playerStatusPtr->Mvt_InputRequests.Flags.Rqst_LookDown = 1; + playerStatusPtr->Mvt_AnaloguePitching = 1; + playerStatusPtr->Mvt_PitchIncrement = trackerballV*JoystickControlMethods.JoystickTrackerBallVerticalSensitivity;; + } + + } + + #if 1 + textprint("%d\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n", + JoystickData.dwXpos, + JoystickData.dwYpos, + JoystickData.dwZpos, + JoystickData.dwRpos, + JoystickData.dwUpos, + JoystickData.dwVpos, + JoystickData.dwButtons, + JoystickData.dwPOV); + #endif + } + + /* KJL 16:03:06 05/11/97 - Handle map options */ + #if 0 + if(KeyboardInput[KEY_NUMPADADD]) + HUDMapOn(); + else if(KeyboardInput[KEY_NUMPADSUB]) + HUDMapOff(); + if(KeyboardInput[KEY_NUMPAD7]) + HUDMapZoomIn(); + else if(KeyboardInput[KEY_NUMPAD9]) + HUDMapZoomOut(); + if(KeyboardInput[KEY_NUMPAD1]) + HUDMapSmaller(); + else if(KeyboardInput[KEY_NUMPAD3]) + HUDMapLarger(); + if(KeyboardInput[KEY_NUMPAD4]) + HUDMapLeft(); + else if(KeyboardInput[KEY_NUMPAD6]) + HUDMapRight(); + if(KeyboardInput[KEY_NUMPAD8]) + HUDMapUp(); + else if(KeyboardInput[KEY_NUMPAD2]) + HUDMapDown(); + #endif + + /* KJL 10:55:22 10/9/97 - HUD transparency */ + #if 0 + { + extern signed int HUDTranslucencyLevel; + + if (KeyboardInput[KEY_F1]) + { + HUDTranslucencyLevel-=NormalFrameTime>>9; + if (HUDTranslucencyLevel<0) HUDTranslucencyLevel=0; + } + else if (KeyboardInput[KEY_F2]) + { + HUDTranslucencyLevel+=NormalFrameTime>>9; + if (HUDTranslucencyLevel>255) HUDTranslucencyLevel=255; + } + } + #endif + /* KJL 10:55:32 10/9/97 - screen size */ + #if 0 + if(KeyboardInput[KEY_F3]) + MakeViewingWindowLarger(); + else if(KeyboardInput[KEY_F4]) + MakeViewingWindowSmaller(); + #endif + #if 0 + if (DebouncedKeyboardInput[KEY_F3]) + { + MessageHistory_DisplayPrevious(); + } + #endif + if (DebouncedKeyboardInput[KEY_GRAVE]) IOFOCUS_Toggle(); +} + +void LoadKeyConfiguration(void) +{ + #if ALIEN_DEMO + LoadAKeyConfiguration("alienavpkey.cfg"); + #else + LoadAKeyConfiguration("avpkey.cfg"); + #endif + +} + +void SaveKeyConfiguration(void) +{ + #if ALIEN_DEMO + SaveAKeyConfiguration("alienavpkey.cfg"); + #else + SaveAKeyConfiguration("avpkey.cfg"); + #endif +} + +void LoadAKeyConfiguration(char* Filename) +{ + #if 0 + FILE* file=fopen(Filename,"rb"); + if(!file) + { + MarineInputPrimaryConfig = DefaultMarineInputPrimaryConfig; + MarineInputSecondaryConfig = DefaultMarineInputSecondaryConfig; + PredatorInputPrimaryConfig = DefaultPredatorInputPrimaryConfig; + PredatorInputSecondaryConfig = DefaultPredatorInputSecondaryConfig; + AlienInputPrimaryConfig = DefaultAlienInputPrimaryConfig; + AlienInputSecondaryConfig = DefaultAlienInputSecondaryConfig; + return; + } + fread(&MarineInputPrimaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + fread(&MarineInputSecondaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + fread(&PredatorInputPrimaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + fread(&PredatorInputSecondaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + fread(&AlienInputPrimaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + fread(&AlienInputSecondaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + + fread(&ControlMethods,sizeof(CONTROL_METHODS),1,file); + fread(&JoystickControlMethods,sizeof(JOYSTICK_CONTROL_METHODS),1,file); + + fclose(file); + #endif +} + +void SaveAKeyConfiguration(char* Filename) +{ + #if 0 + FILE* file=fopen(Filename,"wb"); + if(!file) return; + + fwrite(&MarineInputPrimaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + fwrite(&MarineInputSecondaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + fwrite(&PredatorInputPrimaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + fwrite(&PredatorInputSecondaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + fwrite(&AlienInputPrimaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + fwrite(&AlienInputSecondaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + + fwrite(&ControlMethods,sizeof(CONTROL_METHODS),1,file); + fwrite(&JoystickControlMethods,sizeof(JOYSTICK_CONTROL_METHODS),1,file); + + fclose(file); + #endif +} + +void SaveDefaultPrimaryConfigs(void) +{ + FILE* file=fopen("default.cfg","wb"); + if(!file) return; + + fwrite(&DefaultMarineInputPrimaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + fwrite(&DefaultPredatorInputPrimaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + fwrite(&DefaultAlienInputPrimaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + + fclose(file); +} +void LoadDefaultPrimaryConfigs(void) +{ + FILE* file=fopen("default.cfg","rb"); + if(!file) return; + + fread(&DefaultMarineInputPrimaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + fread(&DefaultPredatorInputPrimaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + fread(&DefaultAlienInputPrimaryConfig,sizeof(PLAYER_INPUT_CONFIGURATION),1,file); + + fclose(file); +} + + + + + + + + + + + diff --git a/3dc/avp/win95/USR_IO.H b/3dc/avp/win95/USR_IO.H new file mode 100644 index 0000000..935de83 --- /dev/null +++ b/3dc/avp/win95/USR_IO.H @@ -0,0 +1,320 @@ +#ifndef _usr_io_h_ +#define _usr_io_h_ 1 +/*-------------- Patrick 21/10/96 ----------------- + Header File for User Input functions, structures, + etc. This is basically all platform dependant, + and console versions should have they're own + versions of the functions prototyped here. + (win 95 source is in avp/win95/usr_io.c). + -------------------------------------------------*/ + + +/*-------------- Patrick 21/10/96 ----------------- + Configuration structure for Win95 keyboard + reading stuff. Console versions can proabably + use the same structure, but don't have to. + + NB Entries in the configuration structure + correspond to request flags in the player status + block. However, each request flag does not + necessarily need a config entry (eg lie down, + which is only activated by special moves). If you + don't want to implement a particular request flag + functionality, leave it out of the config, and don't + set it in ReadPlayerGameInput. + -------------------------------------------------*/ +#include "avp_menus.h" +#if 0 +typedef struct player_input_configuration +{ + unsigned char Forward; + unsigned char Backward; + unsigned char Left; + unsigned char Right; + + unsigned char Strafe; + unsigned char StrafeLeft; + unsigned char StrafeRight; + + unsigned char LookUp; + unsigned char LookDown; + unsigned char CentreView; + + unsigned char Walk; + unsigned char Crouch; + unsigned char Jump; + + unsigned char Operate; + + unsigned char NextWeapon; + unsigned char PreviousWeapon; + unsigned char FirePrimaryWeapon; + unsigned char FireSecondaryWeapon; + + #ifdef __cplusplus + // C++ only stuff, added by DHM 17/3/98 to ease rewrite of the + // key configuration screens: + // (definitions are in REBITEMS.HPP) + unsigned char GetMethod( enum KeyConfigItems theEffect ) const; + void SetMethod + ( + enum KeyConfigItems theEffect, + unsigned char newMethod + ); + #endif + +}PLAYER_INPUT_CONFIGURATION; +#endif +enum PLAYER_INPUT_ID +{ + PLAYER_INPUT_FORWARD, + PLAYER_INPUT_BACKWARD, + PLAYER_INPUT_LEFT, + PLAYER_INPUT_RIGHT, + + PLAYER_INPUT_STRAFE, + PLAYER_INPUT_STRAFELEFT, + PLAYER_INPUT_STRAFERIGHT, + + PLAYER_INPUT_LOOKUP, + PLAYER_INPUT_LOOKDOWN, + PLAYER_INPUT_CENTREVIEW, + + PLAYER_INPUT_WALK, + PLAYER_INPUT_CROUCH, + PLAYER_INPUT_JUMP, + + PLAYER_INPUT_OPERATE, + PLAYER_INPUT_CHANGEVISION, + + PLAYER_INPUT_NEXTWEAPON, + PLAYER_INPUT_PREVIOUSWEAPON, + PLAYER_INPUT_FIREPRIMARYWEAPON, + PLAYER_INPUT_FIRESECONDARYWEAPON, + + PLAYER_INPUT_ZOOMIN, + PLAYER_INPUT_ZOOMOUT, + + PLAYER_INPUT_BONUSABILITY, + + MAX_NO_OF_PLAYER_INPUTS +}; + +#if PREDATOR_DEMO||DEATHMATCH_DEMO +#define NUMBER_OF_PREDATOR_INPUTS 30 +#else +#define NUMBER_OF_PREDATOR_INPUTS 30 +#endif + +#if MARINE_DEMO||DEATHMATCH_DEMO +#define NUMBER_OF_MARINE_INPUTS 27 +#else +#define NUMBER_OF_MARINE_INPUTS 27 +#endif + +#if ALIEN_DEMO||DEATHMATCH_DEMO +#define NUMBER_OF_ALIEN_INPUTS 21 +#else +#define NUMBER_OF_ALIEN_INPUTS 22 +#endif + +typedef struct fixed_input_configuration +{ + unsigned char Weapon1; + unsigned char Weapon2; + unsigned char Weapon3; + unsigned char Weapon4; + unsigned char Weapon5; + unsigned char Weapon6; + unsigned char Weapon7; + unsigned char Weapon8; + unsigned char Weapon9; + unsigned char Weapon10; + unsigned char PauseGame; + +}FIXED_INPUT_CONFIGURATION; + + +typedef struct +{ + unsigned char Forward; + unsigned char Backward; + unsigned char Left; + unsigned char Right; + + unsigned char Strafe; + unsigned char StrafeLeft; + unsigned char StrafeRight; + unsigned char LookUp; + + unsigned char LookDown; + unsigned char CentreView; + unsigned char Walk; + unsigned char Crouch; + + unsigned char Jump; + unsigned char Operate; + unsigned char FirePrimaryWeapon; + unsigned char FireSecondaryWeapon; + + union + { + unsigned char NextWeapon; // Predator & Marine + unsigned char AlternateVision; // Alien + }; + + union + { + unsigned char PreviousWeapon; // Predator & Marine + unsigned char Taunt; // Alien + }; + + union + { + unsigned char FlashbackWeapon; // Predator & Marine + unsigned char Alien_MessageHistory; // Alien + }; + + union + { + unsigned char Cloak; // Predator + unsigned char ImageIntensifier; // Marine + unsigned char Alien_Say; // Alien + }; + + union + { + unsigned char CycleVisionMode; // Predator + unsigned char ThrowFlare; // Marine + unsigned char Alien_SpeciesSay; // Alien + }; + union + { + unsigned char ZoomIn; // Predator + unsigned char Jetpack; // Marine + unsigned char Alien_ShowScores; // Alien + }; + union + { + unsigned char ZoomOut; // Predator + unsigned char MarineTaunt; // Marine + }; + union + { + unsigned char GrapplingHook; // Predator + unsigned char Marine_MessageHistory; // Marine + }; + union + { + unsigned char RecallDisc; // Predator + unsigned char Marine_Say; // Marine + }; + union + { + unsigned char PredatorTaunt; // Predator + unsigned char Marine_SpeciesSay; // Marine + }; + union + { + unsigned char Predator_MessageHistory; // Predator + unsigned char Marine_ShowScores; // Marine + }; + unsigned char Predator_Say; + unsigned char Predator_SpeciesSay; + unsigned char Predator_ShowScores; + unsigned char ExpansionSpace7; + unsigned char ExpansionSpace8; + +} PLAYER_INPUT_CONFIGURATION; + +typedef struct +{ + /* analogue stuff */ + unsigned int MouseXSensitivity; + unsigned int MouseYSensitivity; + + unsigned int VAxisIsMovement; // else it's looking + unsigned int HAxisIsTurning; // else it's sidestepping + + unsigned int FlipVerticalAxis; + + /* general stuff */ + unsigned int AutoCentreOnMovement; + +}CONTROL_METHODS; + +typedef struct +{ + /* joystick stuff */ + unsigned int JoystickEnabled; + + unsigned int JoystickVAxisIsMovement; // else it's looking + unsigned int JoystickHAxisIsTurning; // else it's sidestepping + unsigned int JoystickFlipVerticalAxis; + + unsigned int JoystickPOVVAxisIsMovement; // else it's looking + unsigned int JoystickPOVHAxisIsTurning; // else it's sidestepping + unsigned int JoystickPOVFlipVerticalAxis; + + unsigned int JoystickRudderEnabled; + unsigned int JoystickRudderAxisIsTurning; // else it's sidestepping + + unsigned int JoystickTrackerBallEnabled; + unsigned int JoystickTrackerBallFlipVerticalAxis; + unsigned int JoystickTrackerBallHorizontalSensitivity; + unsigned int JoystickTrackerBallVerticalSensitivity; + +}JOYSTICK_CONTROL_METHODS; + +#define DEFAULT_MOUSEX_SENSITIVITY 64 +#define DEFAULT_MOUSEY_SENSITIVITY 64 + +#define DEFAULT_TRACKERBALL_HORIZONTAL_SENSITIVITY 32 +#define DEFAULT_TRACKERBALL_VERTICAL_SENSITIVITY 32 + +/* Global Variables */ +#ifdef __cplusplus + // Linkage wrapping added by DHM 17/3/98: + extern "C" + { +#endif + + /* Globals */ + extern PLAYER_INPUT_CONFIGURATION MarineInputPrimaryConfig; + extern PLAYER_INPUT_CONFIGURATION MarineInputSecondaryConfig; + extern PLAYER_INPUT_CONFIGURATION AlienInputPrimaryConfig; + extern PLAYER_INPUT_CONFIGURATION AlienInputSecondaryConfig; + extern PLAYER_INPUT_CONFIGURATION PredatorInputPrimaryConfig; + extern PLAYER_INPUT_CONFIGURATION PredatorInputSecondaryConfig; + extern PLAYER_INPUT_CONFIGURATION DefaultMarineInputPrimaryConfig; + extern PLAYER_INPUT_CONFIGURATION DefaultMarineInputSecondaryConfig; + extern PLAYER_INPUT_CONFIGURATION DefaultAlienInputPrimaryConfig; + extern PLAYER_INPUT_CONFIGURATION DefaultAlienInputSecondaryConfig; + extern PLAYER_INPUT_CONFIGURATION DefaultPredatorInputPrimaryConfig; + extern PLAYER_INPUT_CONFIGURATION DefaultPredatorInputSecondaryConfig; + extern CONTROL_METHODS ControlMethods; + extern CONTROL_METHODS DefaultControlMethods; + extern JOYSTICK_CONTROL_METHODS JoystickControlMethods; + extern JOYSTICK_CONTROL_METHODS DefaultJoystickControlMethods; + + /* Prototypes */ + extern void InitPlayerGameInput(STRATEGYBLOCK* sbPtr); + extern void ReadPlayerGameInput(STRATEGYBLOCK* sbPtr); + + /* + DHM 1/4/98: Added prototypes for these functions; changing so + that filename to use is passed to them, rather than being hardcoded + as "avp.key" so that we can have multiple keyconfig files + */ + extern void LoadKeyConfiguration(void); + extern void SaveKeyConfiguration(void); + + extern void LoadAKeyConfiguration(char* Filename); + extern void SaveAKeyConfiguration(char* Filename); + +#ifdef __cplusplus + }; + // ...linkage wrapping added by DHM 17/3/98 +#endif + +#endif \ No newline at end of file diff --git a/3dc/avp/win95/VISION.C b/3dc/avp/win95/VISION.C new file mode 100644 index 0000000..6cc9e3c --- /dev/null +++ b/3dc/avp/win95/VISION.C @@ -0,0 +1,354 @@ +/*KJL**************************************************************************************** +* hud.c * +****************************************************************************************KJL*/ + +#include "3dc.h" +#include "module.h" +#include "inline.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "huddefs.h" + +/* patrick's sound include */ +#include "psnd.h" +#include "psndplat.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ +#include "vision.h" +#include "krender.h" +#include "frustrum.h" +#include "avpview.h" +#include "game_statistics.h" + +/*KJL**************************************************************************************** +* G L O B A L S * +****************************************************************************************KJL*/ +enum VISION_MODE_ID CurrentVisionMode; + +static visionModeDebounced=0; + +extern ACTIVESOUNDSAMPLE ActiveSounds[]; +int predOVision_SoundHandle; + +extern int FMVParticleColour; +extern int LogosAlphaLevel; +int PredatorVisionChangeCounter; + +static struct PredOVisionDescriptor PredOVision; +static struct MarineOVisionDescriptor MarineOVision; +extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; +extern int NormalFrameTime; +extern int GlobalAmbience; +/* JH 29/5/97 - to control how D3D does the lighting */ +struct D3DLightColourControl d3d_light_ctrl; +struct D3DOverlayColourControl d3d_overlay_ctrl; +/*KJL**************************************************************************************** +* F U N C T I O N S * +****************************************************************************************KJL*/ +void SetupVision(void); + +extern void DrawNoiseOverlay(int t); + +void SetupVision(void) +{ + /* KJL 16:33:47 01/10/97 - change view for alien; + this must be called after ProcessSystemObjects() */ + if(AvP.PlayerType == I_Alien) + { + /* setup wide-angle lens */ + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + + LOCALASSERT(VDBPtr); + + /* change clipping planes for new field of view */ + /* KJL 12:00:54 07/04/97 - new projection angles */ + VDBPtr->VDB_ProjX = ScreenDescriptorBlock.SDB_Width/4; + VDBPtr->VDB_ProjY = (ScreenDescriptorBlock.SDB_Height)/4; + + /* KJL 17:37:51 7/17/97 - frustrum setup */ + SetFrustrumType(FRUSTRUM_TYPE_WIDE); + } + else if (AvP.PlayerType == I_Predator) + { + /* setup normal-angle lens */ + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + + LOCALASSERT(VDBPtr); + + /* change clipping planes for new field of view */ + VDBPtr->VDB_ProjX = ScreenDescriptorBlock.SDB_Width/2; + VDBPtr->VDB_ProjY = (ScreenDescriptorBlock.SDB_Height)/2; + + SetupPredOVision(); + /* KJL 17:37:51 7/17/97 - frustrum setup */ + SetFrustrumType(FRUSTRUM_TYPE_NORMAL); + } + else + { + /* setup normal-angle lens */ + extern VIEWDESCRIPTORBLOCK *ActiveVDBList[]; + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0]; + + LOCALASSERT(VDBPtr); + + /* change clipping planes for new field of view */ + VDBPtr->VDB_ProjX = ScreenDescriptorBlock.SDB_Width/2; + VDBPtr->VDB_ProjY = (ScreenDescriptorBlock.SDB_Height)/2; + + SetupMarineOVision(); + /* KJL 17:37:51 7/17/97 - frustrum setup */ + SetFrustrumType(FRUSTRUM_TYPE_NORMAL); + } + + InitCameraValues(); + + /* KJL 12:01:09 16/02/98 - init visionmode */ + CurrentVisionMode = VISION_MODE_NORMAL; + + predOVision_SoundHandle=SOUND_NOACTIVEINDEX; + PredatorVisionChangeCounter=0; + + FMVParticleColour = RGBA_MAKE(255,255,255,128); + LogosAlphaLevel = 3*ONE_FIXED; +} + +/* +IMPORTANT NOTE OF KNOWN BUG NOT YET FIXED +Note that there is a potential problem in that +if the game exits with *-o-vision on or in transition, +the next instance of playing the game with the +alien character will still have the same vision settings. +- JH +*/ + +/* Pred-O-Vision */ +void SetupPredOVision(void) +{ + + /* setup in-game data */ + PredOVision.VisionMode = PREDOVISION_NORMAL; + PredOVision.VisionIsChanging=0; + /* JH - 29/5/97 for d3d */ + d3d_light_ctrl.ctrl = LCCM_NORMAL; +} + + +void HandlePredOVision(void) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + if (playerStatusPtr->IsAlive) { + CurrentGameStats_VisionMode(CurrentVisionMode); + } + + if (playerStatusPtr->cloakOn) + { + DrawNoiseOverlay(16); + } + if (CurrentVisionMode==VISION_MODE_PRED_SEEPREDTECH) + { + D3D_PredatorScreenInversionOverlay(); + } + + if (CurrentVisionMode==VISION_MODE_NORMAL) + { + if (predOVision_SoundHandle!=SOUND_NOACTIVEINDEX) + { + Sound_Stop(predOVision_SoundHandle); + } + } + else + { + if (predOVision_SoundHandle!=SOUND_NOACTIVEINDEX) + { + if (ActiveSounds[predOVision_SoundHandle].soundIndex!=SID_PREDATOR_CLOAKING_ACTIVE) + { + Sound_Stop(predOVision_SoundHandle); + } + } + if (predOVision_SoundHandle==SOUND_NOACTIVEINDEX) + { + Sound_Play(SID_PREDATOR_CLOAKING_ACTIVE,"elh",&predOVision_SoundHandle); + } + } + + if (PredatorVisionChangeCounter) + { + D3D_FadeDownScreen(ONE_FIXED-PredatorVisionChangeCounter,0xffffffff); + PredatorVisionChangeCounter -= NormalFrameTime*4; + + if (PredatorVisionChangeCounter<0) + { + PredatorVisionChangeCounter=0; + } + } + +} + +extern void ChangePredatorVisionMode(void) +{ + switch (CurrentVisionMode) + { + case VISION_MODE_NORMAL: + { + CurrentVisionMode=VISION_MODE_PRED_THERMAL; + break; + } + case VISION_MODE_PRED_THERMAL: + { + CurrentVisionMode=VISION_MODE_PRED_SEEALIENS; + break; + } + case VISION_MODE_PRED_SEEALIENS: + { + CurrentVisionMode=VISION_MODE_PRED_SEEPREDTECH; + break; + } + case VISION_MODE_PRED_SEEPREDTECH: + { + CurrentVisionMode=VISION_MODE_NORMAL; + break; + } + } + Sound_Play(SID_VISION_ON,"h"); + PredatorVisionChangeCounter=ONE_FIXED; +} + + +/* Marine-O-Vision */ + +void SetupMarineOVision(void) +{ + /* setup in-game data */ + MarineOVision.VisionMode = MARINEOVISION_NORMAL; + MarineOVision.VisionIsChanging=0; + /* JH - 29/5/97 for d3d */ + d3d_light_ctrl.ctrl = LCCM_NORMAL; +} + + +void HandleMarineOVision(void) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + if (playerStatusPtr->IsAlive) { + CurrentGameStats_VisionMode(CurrentVisionMode); + } + + if (CurrentVisionMode == VISION_MODE_IMAGEINTENSIFIER) + { + DrawNoiseOverlay(64); + } + + /* We might have just morphed. */ + if (predOVision_SoundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(predOVision_SoundHandle); + } + + if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_ChangeVision) + { + if (visionModeDebounced) + { + visionModeDebounced = 0; + if (CurrentVisionMode == VISION_MODE_IMAGEINTENSIFIER) + { + /* then we'll be changing to normal vision */ + NewOnScreenMessage(GetTextString(TEXTSTRING_INGAME_INTENSIFIEROFF)); + CurrentVisionMode = VISION_MODE_NORMAL; + FMVParticleColour = RGBA_MAKE(255,255,255,128); + Sound_Play(SID_IMAGE_OFF,"h"); + } + else + { + /* then we'll be changing to intensified vision */ + NewOnScreenMessage(GetTextString(TEXTSTRING_INGAME_INTENSIFIERON)); + CurrentVisionMode = VISION_MODE_IMAGEINTENSIFIER; + FMVParticleColour = RGBA_MAKE(0,255,0,128); + Sound_Play(SID_IMAGE,"h"); + } + } + } + else + { + visionModeDebounced = 1; + } + + +} + + +void HandleAlienOVision(void) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + if (playerStatusPtr->IsAlive) { + CurrentGameStats_VisionMode(CurrentVisionMode); + } + + if (CurrentVisionMode == VISION_MODE_ALIEN_SENSE) + { + D3D_ScreenInversionOverlay(); + } + + /* We might have just morphed. */ + if (predOVision_SoundHandle!=SOUND_NOACTIVEINDEX) { + Sound_Stop(predOVision_SoundHandle); + } + + if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_ChangeVision) + { + if (visionModeDebounced) + { + visionModeDebounced = 0; + if (CurrentVisionMode == VISION_MODE_ALIEN_SENSE) + { + /* then we'll be changing to normal vision */ + CurrentVisionMode = VISION_MODE_NORMAL; + FMVParticleColour = RGBA_MAKE(255,255,255,128); + } + else + { + /* then we'll be changing to alien sense */ + CurrentVisionMode = VISION_MODE_ALIEN_SENSE; + FMVParticleColour = RGBA_MAKE(255,255,255,128); + } + } + } + else + { + visionModeDebounced = 1; + } + +} +/* used when the palette has been changed, eg. by database screens */ + + +int IsVisionChanging(void) +{ + switch (AvP.PlayerType) + { + case I_Marine: + return (MarineOVision.VisionIsChanging); + break; + case I_Predator: + return (PredOVision.VisionIsChanging); + break; + case I_Alien: + return(0); + break; + default: + return(0); + break; + } +} diff --git a/3dc/avp/win95/VISION.H b/3dc/avp/win95/VISION.H new file mode 100644 index 0000000..0d7e523 --- /dev/null +++ b/3dc/avp/win95/VISION.H @@ -0,0 +1,121 @@ +#ifndef _included_vision_h_ +#define _included_vision_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "d3_func.h" + +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ +enum PREDOVISION_ID +{ + PREDOVISION_NORMAL, + PREDOVISION_SPECTRUM +}; +struct PredOVisionDescriptor +{ + enum PREDOVISION_ID VisionMode; + int FadeLevel; + unsigned char VisionIsChanging :1; + unsigned char FadingToWhite :1; +}; + +enum MARINEOVISION_ID +{ + MARINEOVISION_NORMAL, + MARINEOVISION_INTENSIFIED +}; +struct MarineOVisionDescriptor +{ + enum MARINEOVISION_ID VisionMode; + int FadeLevel; + unsigned char VisionIsChanging :1; + unsigned char FadingToWhite :1; +}; + +/* JH 29/5/97 - define a structure to control how D3D does the lighting */ +enum D3DLCC_Mode +{ + LCCM_NORMAL, /* default behaviour, white light - all other parms ignored */ + LCCM_CONSTCOLOUR, /* r,g,b specify a colour of a light to use instead of white */ + LCCM_FUNCTIONOFINTENSITY /* GetR, GetG, GetB are function pointers to get r,g,b as function of intensity */ +}; +struct D3DLightColourControl +{ + enum D3DLCC_Mode ctrl; + + /* these should be in [0..ONE_FIXED] */ + int r; + int g; + int b; + + /* these should return from [0..255] + their parameters are [0..255] */ + int (*GetR)(int); + int (*GetG)(int); + int (*GetB)(int); +}; +extern struct D3DLightColourControl d3d_light_ctrl; + +/* JH 6/4/97 - define a structure to control an alpha channelled coloured overlay */ +extern D3DINFO d3d; +#define d3d_overlays_available ((d3d.ThisDriver.dpcTriCaps.dwSrcBlendCaps & (D3DPBLENDCAPS_SRCALPHA|D3DPBLENDCAPS_INVSRCALPHA))==(D3DPBLENDCAPS_SRCALPHA|D3DPBLENDCAPS_INVSRCALPHA)) + +enum D3DOCC_Mode +{ + OCCM_NORMAL, /* default behaviour - all other parms ignored */ + OCCM_ON, /* r,g,b,alpha specify a colour of a light to use instead of white */ +}; +struct D3DOverlayColourControl +{ + enum D3DOCC_Mode ctrl; + + /* these should be in [0..255] */ + int r; + int g; + int b; + int alpha; +}; + + +/* KJL 17:07:29 10/02/98 - all new vision modes */ +enum VISION_MODE_ID +{ + VISION_MODE_NORMAL, + VISION_MODE_ALIEN_SENSE, + + VISION_MODE_IMAGEINTENSIFIER, + VISION_MODE_PRED_THERMAL, + VISION_MODE_PRED_SEEALIENS, + VISION_MODE_PRED_SEEPREDTECH, + + NUMBER_OF_VISION_MODES +}; + +extern enum VISION_MODE_ID CurrentVisionMode; + + + +extern struct D3DOverlayColourControl d3d_overlay_ctrl; +extern void HandleD3DScreenFading(void); + +extern void SetupPredOVision(void); +extern void HandlePredOVision(void); +extern void SetupMarineOVision(void); +extern void HandleMarineOVision(void); +extern void HandleAlienOVision(void); + +extern int IsVisionChanging(void); + +extern void ChangePredatorVisionMode(void); + + +extern void SetupVision(void); +#ifdef __cplusplus +} +#endif + +#endif /* ! _included_vision_h_ */ diff --git a/3dc/avp/win95/VMANPSET.H b/3dc/avp/win95/VMANPSET.H new file mode 100644 index 0000000..4c31470 --- /dev/null +++ b/3dc/avp/win95/VMANPSET.H @@ -0,0 +1,66 @@ +/*****************************************************************************/ +/* */ +/* */ +/* Abstract: */ +/* */ +/* DirectSound3D Voice Manager property set definitions. */ +/* April 24, 1998 */ +/*****************************************************************************/ + + +#ifndef _VMANPSET_H_ +#define _VMANPSET_H_ + + +/******************************************************************************/ +/* */ +/* G l o b a l t y p e d e f s */ +/* */ +/******************************************************************************/ + + +typedef enum +{ + DSPROPERTY_VMANAGER_MODE = 0, + DSPROPERTY_VMANAGER_PRIORITY, + DSPROPERTY_VMANAGER_STATE +} DSPROPERTY_VMANAGER; + + +typedef enum +{ + DSPROPERTY_VMANAGER_MODE_DEFAULT = 0, + DSPROPERTY_VMANAGER_MODE_AUTO, + DSPROPERTY_VMANAGER_MODE_REPORT, + DSPROPERTY_VMANAGER_MODE_USER +} VmMode; + + +typedef enum +{ + DSPROPERTY_VMANAGER_STATE_PLAYING3DHW = 0, + DSPROPERTY_VMANAGER_STATE_SILENT, + DSPROPERTY_VMANAGER_STATE_BUMPED, + DSPROPERTY_VMANAGER_STATE_PLAYFAILED +} VmState; + + + + + + +#ifdef __cplusplus +extern "C" +{ +#endif + +// {62A69BAE-DF9D-11d1-99A6-00C04FC99D46} +DEFINE_GUID(DSPROPSETID_VoiceManager, +0x62a69bae, 0xdf9d, 0x11d1, 0x99, 0xa6, 0x0, 0xc0, 0x4f, 0xc9, 0x9d, 0x46); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/3dc/avp/win95/chtcodes.cpp b/3dc/avp/win95/chtcodes.cpp new file mode 100644 index 0000000..28d9b47 --- /dev/null +++ b/3dc/avp/win95/chtcodes.cpp @@ -0,0 +1,362 @@ +/******************************************************************* + * + * DESCRIPTION: chtcodes.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 28/11/97 by moving the cheat code processor + * from out of SCSTRING.CPP + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "scstring.hpp" +#include "gadget.h" +#include "strutil.h" + +#include "module.h" +#include "stratdef.h" +#include "dynblock.h" +#include "equipmnt.h" +#include "rootgadg.hpp" +#include "hudgadg.hpp" +//#include "introut.hpp" +#include "modcmds.hpp" + +#include "bh_types.h" + +#include "consvar.hpp" + +#include "missions.hpp" + +#include "textexp.hpp" + +#include "refobj.hpp" + +#include "debuglog.hpp" + +#include "trepgadg.hpp" + +#include "conscmnd.hpp" + +#include "consbind.hpp" + +extern "C" +{ + #include "weapons.h" + #include "avp_menus.h" +}; + + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + extern int DebuggingCommandsActive; + + extern int bEnableTextprint; + + extern SCENE Global_Scene; + + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + namespace Cheats + { + void ToggleImmortality(void); + void CommitSuicide(void); + }; + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +void SCString :: ProcessAnyCheatCodes(void) +{ + #if UseGadgets + + #if 0 + { + char Msg[256]; + sprintf + ( + Msg, + "Process for cheat codes \"%s\"", + pProjCh_Val + ); + GADGET_NewOnScreenMessage(Msg); + } + #endif + // Processing for the "console variable" system: + { + if + ( + ConsoleVariable :: Process( pProjCh_Val ) + ) + { + // then this has been processed; stop + return; + } + } + + // Processing for the "console commands" system: + { + if + ( + ConsoleCommand :: Process( pProjCh_Val ) + ) + { + // then this has been processed; stop + return; + } + } + // Expansion-related commands: + { + if + ( + 0 == _strnicmp + ( + pProjCh_Val, + "EXP+ ", + 5 + ) + ) + { + TextExpansion :: AddExpansion + ( + pProjCh_Val+5 + // ProjChar* pProjCh_ToParse + ); + return; + } + if + ( + 0 == _strnicmp + ( + pProjCh_Val, + "EXP- ", + 5 + ) + ) + { + TextExpansion :: TryToRemoveExpansion + ( + pProjCh_Val+5 + // ProjChar* pProjCh_ToParse + ); + return; + } + } + + // Key-binding related commands: + { + if + ( + 0 == _strnicmp + ( + pProjCh_Val, + "BIND ", + 5 + ) + ) + { + KeyBinding :: ParseBindCommand + ( + pProjCh_Val+5 + // ProjChar* pProjCh_ToParse + ); + return; + } + if + ( + 0 == _strnicmp + ( + pProjCh_Val, + "UNBIND ", + 7 + ) + ) + { + KeyBinding :: ParseUnbindCommand + ( + pProjCh_Val+7 + // ProjChar* pProjCh_ToParse + ); + return; + } + } + #ifndef AVP_DEBUG_VERSION // allow debug commands without -debug + #ifndef AVP_DEBUG_FOR_FOX // allow debug commands without -debug + if (DebuggingCommandsActive) + #endif + #endif + { + if + ( + #ifndef AVP_DEBUG_VERSION + STRUTIL_SC_Strequal + ( + pProjCh_Val, + "GOD" //ProjChar* pProjCh_2 + ) + #else // allow case insensitive + STRUTIL_SC_Strequal_Insensitive + ( + pProjCh_Val, + "GOD" //ProjChar* pProjCh_2 + ) + #endif + ) + { + Cheats :: ToggleImmortality(); + return; + } + } + #if CONSOLE_DEBUGGING_COMMANDS_ACTIVATED + // Module commands: + { + if + ( + 0 == _strnicmp + ( + pProjCh_Val, + "MODULE ", + 7 + ) + ) + { + // Then pass the rest of the string as an argument to the module + // teleport code: + + ModuleCommands :: TryToTeleport + ( + pProjCh_Val+7 + //char* UpperCasePotentialModuleName + ); + return; + } + if + ( + 0 == _strnicmp + ( + pProjCh_Val, + "MOD ", + 4 + ) + ) + { + // Then pass the rest of the string as an argument to the module + // teleport code: + + ModuleCommands :: TryToTeleport + ( + pProjCh_Val+4 + //char* UpperCasePotentialModuleName + ); + return; + } + } + + + + if + ( + STRUTIL_SC_Strequal_Insensitive + ( + pProjCh_Val, + "SUICIDE" //ProjChar* pProjCh_2 + ) + ) + { + Cheats :: CommitSuicide(); + return; + } + + + + + + if + ( + STRUTIL_SC_Strequal_Insensitive + ( + pProjCh_Val, + "DONE IT" //ProjChar* pProjCh_2 + ) + ) + { + MissionObjective :: TestCompleteNext(); + } + + + // Unimplemented cheat code ideas: + //empty + + + #endif + #endif // UseGadgets +} + +/* Internal function definitions ***********************************/ +// namespace Cheats +void Cheats :: ToggleImmortality(void) +{ + // immortality cheat + #if 1 + if ( PlayerStatusPtr->IsImmortal ) + { + GADGET_NewOnScreenMessage("IMMORTALITY DISABLED"); + // LOCALISEME(); + PlayerStatusPtr->IsImmortal = 0; + } + else + { + GADGET_NewOnScreenMessage("IMMORTALITY ENABLED"); + // LOCALISEME(); + PlayerStatusPtr->IsImmortal = 1; + } + #endif +} + +void Cheats :: CommitSuicide(void) +{ + // First, disable immortality: + PlayerStatusPtr->IsImmortal = 0; + + + // Then apply lots of damage: + + CauseDamageToObject(Player->ObStrategyBlock, &certainDeath, ONE_FIXED,NULL); +} \ No newline at end of file diff --git a/3dc/avp/win95/d3d_hud.cpp b/3dc/avp/win95/d3d_hud.cpp new file mode 100644 index 0000000..2c7fb7b --- /dev/null +++ b/3dc/avp/win95/d3d_hud.cpp @@ -0,0 +1,952 @@ +/* KJL 14:43:27 10/6/97 - d3d_hud.cpp + + Things just got too messy with ddplat.cpp & d3_func.cpp, + so this file will hold all Direct 3D hud code. + + */ +extern "C" { + +// Mysterious definition required by objbase.h +// (included via one of the include files below) +// to start definition of obscure unique in the +// universe IDs required by Direct3D before it +// will deign to cough up with anything useful... + +#include "3dc.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "d3dmacs.h" +//#include "string.h" + +#include "hudgfx.h" +#include "huddefs.h" +//#include "hud_data.h" +#include "kshape.h" +#include "chnktexi.h" + + +#include "HUD_layout.h" +#include "language.h" + + + +extern "C++" +{ +#include "r2base.h" +#include "pcmenus.h" +//#include "projload.hpp" // c++ header which ignores class definitions/member functions if __cplusplus is not defined ? +#include "chnkload.hpp" // c++ header which ignores class definitions/member functions if __cplusplus is not defined ? +extern void D3D_RenderHUDString_Centred(char *stringPtr, int centreX, int y, int colour); +extern void D3D_RenderHUDNumber_Centred(unsigned int number,int x,int y,int colour); + +}; + +#include "d3d_hud.h" + + +#define UseLocalAssert No +#include "ourasert.h" + + +#include "vision.h" +#define RGBLIGHT_MAKE(rr,gg,bb) \ +( \ + LCCM_NORMAL == d3d_light_ctrl.ctrl ? \ + RGB_MAKE(rr,gg,bb) \ + : LCCM_CONSTCOLOUR == d3d_light_ctrl.ctrl ? \ + RGB_MAKE(MUL_FIXED(rr,d3d_light_ctrl.r),MUL_FIXED(gg,d3d_light_ctrl.g),MUL_FIXED(bb,d3d_light_ctrl.b)) \ + : \ + RGB_MAKE(d3d_light_ctrl.GetR(rr),d3d_light_ctrl.GetG(gg),d3d_light_ctrl.GetB(bb)) \ +) +#define RGBALIGHT_MAKE(rr,gg,bb,aa) \ +( \ + RGBA_MAKE(rr,gg,bb,aa) \ +) +#include "kshape.h" + + + +void D3D_DrawHUDFontCharacter(HUDCharDesc *charDescPtr); +void D3D_DrawHUDDigit(HUDCharDesc *charDescPtr); + +extern void YClipMotionTrackerVertices(struct VertexTag *v1, struct VertexTag *v2); +extern void XClipMotionTrackerVertices(struct VertexTag *v1, struct VertexTag *v2); +/* HUD globals */ +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; +extern int sine[],cosine[]; + +extern enum HUD_RES_ID HUDResolution; + +signed int HUDTranslucencyLevel=64; + +static int MotionTrackerHalfWidth; +static int MotionTrackerTextureSize; +static int MotionTrackerCentreY; +static int MotionTrackerCentreX; +static int MT_BlipHeight; +static int MT_BlipWidth; +static HUDImageDesc BlueBar; + + +int HUDImageNumber; +int SpecialFXImageNumber; +int SmokyImageNumber; +int ChromeImageNumber; +int CloudyImageNumber; +int BurningImageNumber; +int HUDFontsImageNumber; +int RebellionLogoImageNumber; +int FoxLogoImageNumber; +int MotionTrackerScale; +int PredatorVisionChangeImageNumber; +int PredatorNumbersImageNumber; +int StaticImageNumber; +int AlienTongueImageNumber; +int AAFontImageNumber; +int WaterShaftImageNumber; + + +int HUDScaleFactor; + +static struct HUDFontDescTag HUDFontDesc[] = +{ + //MARINE_HUD_FONT_BLUE, + { + 225,//XOffset + 24,//Height + 16,//Width + }, + //MARINE_HUD_FONT_RED, + { + 242,//XOffset + 24,//Height + 14,//Width + }, + //MARINE_HUD_FONT_MT_SMALL, + { + 232,//XOffset + 12,//Height + 8,//Width + }, + //MARINE_HUD_FONT_MT_BIG, + { + 241,//XOffset + 24,//Height + 14,//Width + }, +}; +#define BLUE_BAR_WIDTH ((203-0)+1) +#define BLUE_BAR_HEIGHT ((226-195)+1) + +void D3D_BLTDigitToHUD(char digit, int x, int y, int font); + + +void Draw_HUDImage(HUDImageDesc *imageDescPtr) +{ + struct VertexTag quadVertices[4]; + int scaledWidth; + int scaledHeight; + + if (imageDescPtr->Scale == ONE_FIXED) + { + scaledWidth = imageDescPtr->Width; + scaledHeight = imageDescPtr->Height; + } + else + { + scaledWidth = MUL_FIXED(imageDescPtr->Scale,imageDescPtr->Width); + scaledHeight = MUL_FIXED(imageDescPtr->Scale,imageDescPtr->Height); + } + + quadVertices[0].U = imageDescPtr->TopLeftU; + quadVertices[0].V = imageDescPtr->TopLeftV; + quadVertices[1].U = imageDescPtr->TopLeftU + imageDescPtr->Width; + quadVertices[1].V = imageDescPtr->TopLeftV; + quadVertices[2].U = imageDescPtr->TopLeftU + imageDescPtr->Width; + quadVertices[2].V = imageDescPtr->TopLeftV + imageDescPtr->Height; + quadVertices[3].U = imageDescPtr->TopLeftU; + quadVertices[3].V = imageDescPtr->TopLeftV + imageDescPtr->Height; + + quadVertices[0].X = imageDescPtr->TopLeftX; + quadVertices[0].Y = imageDescPtr->TopLeftY; + quadVertices[1].X = imageDescPtr->TopLeftX + scaledWidth; + quadVertices[1].Y = imageDescPtr->TopLeftY; + quadVertices[2].X = imageDescPtr->TopLeftX + scaledWidth; + quadVertices[2].Y = imageDescPtr->TopLeftY + scaledHeight; + quadVertices[3].X = imageDescPtr->TopLeftX; + quadVertices[3].Y = imageDescPtr->TopLeftY + scaledHeight; + + D3D_HUDQuad_Output + ( + imageDescPtr->ImageNumber, + quadVertices, + RGBALIGHT_MAKE + ( + imageDescPtr->Red, + imageDescPtr->Green, + imageDescPtr->Blue, + imageDescPtr->Translucency + ) + ); +} + + +void D3D_InitialiseMarineHUD(void) +{ + //SelectGenTexDirectory(ITI_TEXTURE); + + extern unsigned char *ScreenBuffer; + + /* set game mode: different though for multiplayer game */ + if(AvP.Network==I_No_Network) + cl_pszGameMode = "marine"; + else + cl_pszGameMode = "multip"; + + /* load HUD gfx of correct resolution */ + { + HUDResolution = HUD_RES_MED; + HUDImageNumber = CL_LoadImageOnce("Huds\\Marine\\MarineHUD.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE); + MotionTrackerHalfWidth = 127/2; + MotionTrackerTextureSize = 128; + + BlueBar.ImageNumber = HUDImageNumber; + BlueBar.TopLeftX = 0; + BlueBar.TopLeftY = ScreenDescriptorBlock.SDB_Height-40; + BlueBar.TopLeftU = 1; + BlueBar.TopLeftV = 223; + BlueBar.Red = 255; + BlueBar.Green = 255; + BlueBar.Blue = 255; + + BlueBar.Height = BLUE_BAR_HEIGHT; + BlueBar.Width = BLUE_BAR_WIDTH; + + /* motion tracker blips */ + MT_BlipHeight = 12; + MT_BlipWidth = 12; + + /* load in sfx */ + SpecialFXImageNumber = CL_LoadImageOnce("Common\\partclfx.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE); + +// SpecialFXImageNumber = CL_LoadImageOnceEx("flame1",IRF_D3D,DDSCAPS_SYSTEMMEMORY,0);; +// SpecialFXImageNumber = CL_LoadImageOnceEx("star",IRF_D3D,DDSCAPS_SYSTEMMEMORY,0);; +// SmokyImageNumber = CL_LoadImageOnceEx("smoky",IRF_D3D,DDSCAPS_SYSTEMMEMORY,0); + + } + + /* centre of motion tracker */ + MotionTrackerCentreY = BlueBar.TopLeftY; + MotionTrackerCentreX = BlueBar.TopLeftX+(BlueBar.Width/2); + MotionTrackerScale = 65536; + + HUDScaleFactor = DIV_FIXED(ScreenDescriptorBlock.SDB_Width,640); + + #if UseGadgets +// MotionTrackerGadget::SetCentre(r2pos(100,100)); + #endif +} + +void LoadCommonTextures(void) +{ +// PredatorVisionChangeImageNumber = CL_LoadImageOnce("HUDs\\Predator\\predvisfx.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE); + if(AvP.Network==I_No_Network) + { + switch(AvP.PlayerType) + { + case I_Predator: + { + PredatorNumbersImageNumber = CL_LoadImageOnce("HUDs\\Predator\\predNumbers.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE); + StaticImageNumber = CL_LoadImageOnce("Common\\static.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE|LIO_TRANSPARENT); + break; + } + case I_Alien: + { + AlienTongueImageNumber = CL_LoadImageOnce("HUDs\\Alien\\AlienTongue.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE); + break; + } + case I_Marine: + { + StaticImageNumber = CL_LoadImageOnce("Common\\static.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE|LIO_TRANSPARENT); +// ChromeImageNumber = CL_LoadImageOnce("Common\\water2.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE|LIO_TRANSPARENT); + break; + } + default: + break; + } + } + else + { + PredatorNumbersImageNumber = CL_LoadImageOnce("HUDs\\Predator\\predNumbers.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE); + StaticImageNumber = CL_LoadImageOnce("Common\\static.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE|LIO_TRANSPARENT); + AlienTongueImageNumber = CL_LoadImageOnce("HUDs\\Alien\\AlienTongue.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE); + // ChromeImageNumber = CL_LoadImageOnce("Common\\water2.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE|LIO_TRANSPARENT); + } + + HUDFontsImageNumber = CL_LoadImageOnce("Common\\HUDfonts.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE); + SpecialFXImageNumber = CL_LoadImageOnce("Common\\partclfx.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE/*|LIO_TRANSPARENT*/); + CloudyImageNumber = CL_LoadImageOnce("Common\\cloudy.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE); + BurningImageNumber = CL_LoadImageOnce("Common\\burn.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE); +// RebellionLogoImageNumber = CL_LoadImageOnce("Common\\logo.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE|LIO_TRANSPARENT); +// FoxLogoImageNumber = CL_LoadImageOnce("Common\\foxlogo.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE|LIO_TRANSPARENT); + + + { + extern char LevelName[]; + if (!strcmp(LevelName,"invasion_a")) + { + ChromeImageNumber = CL_LoadImageOnce("Envrnmts\\Invasion\\water2.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE|LIO_TRANSPARENT); + WaterShaftImageNumber = CL_LoadImageOnce("Envrnmts\\Invasion\\water-shaft.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE|LIO_TRANSPARENT); + } + else if (!strcmp(LevelName,"genshd1")) + { + WaterShaftImageNumber = CL_LoadImageOnce("Envrnmts\\GenShd1\\colonywater.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE|LIO_TRANSPARENT); + } + else if (!strcmp(LevelName,"fall")||!strcmp(LevelName,"fall_m")) + { + ChromeImageNumber = CL_LoadImageOnce("Envrnmts\\fall\\stream_water.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE|LIO_TRANSPARENT); + } + else if (!strcmp(LevelName,"derelict")) + { + ChromeImageNumber = CL_LoadImageOnce("Envrnmts\\derelict\\water.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE|LIO_TRANSPARENT); + } + + } + + #if 1 + { + extern void InitDrawTest(void); + InitDrawTest(); + } + #endif + +} +void D3D_BLTMotionTrackerToHUD(int scanLineSize) +{ + + struct VertexTag quadVertices[4]; + int widthCos,widthSin; + extern int CloakingPhase; + + BlueBar.TopLeftY = ScreenDescriptorBlock.SDB_Height-MUL_FIXED(MotionTrackerScale,40); + MotionTrackerCentreY = BlueBar.TopLeftY; + MotionTrackerCentreX = BlueBar.TopLeftX+MUL_FIXED(MotionTrackerScale,(BlueBar.Width/2)); + BlueBar.Scale = MotionTrackerScale; + + int motionTrackerScaledHalfWidth = MUL_FIXED(MotionTrackerScale*3,MotionTrackerHalfWidth/2); + + { + int angle = 4095 - Player->ObEuler.EulerY; + + widthCos = MUL_FIXED + ( + motionTrackerScaledHalfWidth, + GetCos(angle) + ); + widthSin = MUL_FIXED + ( + motionTrackerScaledHalfWidth, + GetSin(angle) + ); + } + + /* I've put these -1s in here to help clipping 45 degree cases, + where two vertices can end up around the clipping line of Y=0 */ + quadVertices[0].X = (-widthCos - (-widthSin)); + quadVertices[0].Y = (-widthSin + (-widthCos)) -1; + quadVertices[0].U = 1; + quadVertices[0].V = 1; + quadVertices[1].X = (widthCos - (-widthSin)); + quadVertices[1].Y = (widthSin + (-widthCos)) -1; + quadVertices[1].U = 1+MotionTrackerTextureSize; + quadVertices[1].V = 1; + quadVertices[2].X = (widthCos - widthSin); + quadVertices[2].Y = (widthSin + widthCos) -1; + quadVertices[2].U = 1+MotionTrackerTextureSize; + quadVertices[2].V = 1+MotionTrackerTextureSize; + quadVertices[3].X = ((-widthCos) - widthSin); + quadVertices[3].Y = ((-widthSin) + widthCos) -1; + quadVertices[3].U = 1; + quadVertices[3].V = 1+MotionTrackerTextureSize; + + /* clip to Y<=0 */ + YClipMotionTrackerVertices(&quadVertices[0],&quadVertices[1]); + YClipMotionTrackerVertices(&quadVertices[1],&quadVertices[2]); + YClipMotionTrackerVertices(&quadVertices[2],&quadVertices[3]); + YClipMotionTrackerVertices(&quadVertices[3],&quadVertices[0]); + + /* translate into screen coords */ + quadVertices[0].X += MotionTrackerCentreX; + quadVertices[1].X += MotionTrackerCentreX; + quadVertices[2].X += MotionTrackerCentreX; + quadVertices[3].X += MotionTrackerCentreX; + quadVertices[0].Y += MotionTrackerCentreY; + quadVertices[1].Y += MotionTrackerCentreY; + quadVertices[2].Y += MotionTrackerCentreY; + quadVertices[3].Y += MotionTrackerCentreY; + + /* dodgy offset 'cos I'm not x clipping */ + if (quadVertices[0].X==-1) quadVertices[0].X = 0; + if (quadVertices[1].X==-1) quadVertices[1].X = 0; + if (quadVertices[2].X==-1) quadVertices[2].X = 0; + if (quadVertices[3].X==-1) quadVertices[3].X = 0; + + /* check u & v are >0 */ + if (quadVertices[0].V<0) quadVertices[0].V = 0; + if (quadVertices[1].V<0) quadVertices[1].V = 0; + if (quadVertices[2].V<0) quadVertices[2].V = 0; + if (quadVertices[3].V<0) quadVertices[3].V = 0; + + if (quadVertices[0].U<0) quadVertices[0].U = 0; + if (quadVertices[1].U<0) quadVertices[1].U = 0; + if (quadVertices[2].U<0) quadVertices[2].U = 0; + if (quadVertices[3].U<0) quadVertices[3].U = 0; + + D3D_HUD_Setup(); + D3D_HUDQuad_Output(HUDImageNumber,quadVertices,RGBALIGHT_MAKE(255,255,255,HUDTranslucencyLevel)); + + #if 1 + { + HUDImageDesc imageDesc; + + imageDesc.ImageNumber = HUDImageNumber; + imageDesc.Scale = MUL_FIXED(MotionTrackerScale*3,scanLineSize/2); + imageDesc.TopLeftX = MotionTrackerCentreX - MUL_FIXED(motionTrackerScaledHalfWidth,scanLineSize); + imageDesc.TopLeftY = MotionTrackerCentreY - MUL_FIXED(motionTrackerScaledHalfWidth,scanLineSize); + imageDesc.TopLeftU = 1; + imageDesc.TopLeftV = 132; + imageDesc.Height = 64; + imageDesc.Width = 128; + imageDesc.Red = 255; + imageDesc.Green = 255; + imageDesc.Blue = 255; + imageDesc.Translucency = HUDTranslucencyLevel; + + Draw_HUDImage(&imageDesc); + } + #endif + + /* KJL 16:14:29 30/01/98 - draw bottom bar of MT */ + { + BlueBar.Translucency = HUDTranslucencyLevel; + Draw_HUDImage(&BlueBar); + } + + D3D_BLTDigitToHUD(ValueOfHUDDigit[MARINE_HUD_MOTIONTRACKER_UNITS],17, -4, MARINE_HUD_FONT_MT_SMALL); + D3D_BLTDigitToHUD(ValueOfHUDDigit[MARINE_HUD_MOTIONTRACKER_TENS],9, -4, MARINE_HUD_FONT_MT_SMALL); + D3D_BLTDigitToHUD(ValueOfHUDDigit[MARINE_HUD_MOTIONTRACKER_HUNDREDS],-9, -4, MARINE_HUD_FONT_MT_BIG); + D3D_BLTDigitToHUD(ValueOfHUDDigit[MARINE_HUD_MOTIONTRACKER_THOUSANDS],-25, -4,MARINE_HUD_FONT_MT_BIG); +} + + +void D3D_BLTMotionTrackerBlipToHUD(int x, int y, int brightness) +{ + HUDImageDesc imageDesc; + int screenX,screenY; /* in 16.16 */ + int frame; + int motionTrackerScaledHalfWidth = MUL_FIXED(MotionTrackerScale*3,MotionTrackerHalfWidth/2); + + GLOBALASSERT(brightness<=65536); + + frame = (brightness*5)/65537; + GLOBALASSERT(frame>=0 && frame<5); + + frame = 4 - frame; // frames bloody wrong way round + imageDesc.ImageNumber = HUDImageNumber; + imageDesc.Scale = MUL_FIXED(MotionTrackerScale*3,(brightness+ONE_FIXED)/4); + imageDesc.TopLeftX = MotionTrackerCentreX - MUL_FIXED(MT_BlipWidth/2,imageDesc.Scale) + MUL_FIXED(x,motionTrackerScaledHalfWidth); + imageDesc.TopLeftY = MotionTrackerCentreY - MUL_FIXED(MT_BlipHeight/2,imageDesc.Scale) - MUL_FIXED(y,motionTrackerScaledHalfWidth); + imageDesc.TopLeftU = 227; + imageDesc.TopLeftV = 187; + imageDesc.Height = MT_BlipHeight; + imageDesc.Width = MT_BlipWidth; + { + int trans = MUL_FIXED(brightness*2,HUDTranslucencyLevel); + if (trans>255) trans = 255; + imageDesc.Translucency = trans; + } + imageDesc.Red = 255; + imageDesc.Green = 255; + imageDesc.Blue = 255; + if (imageDesc.TopLeftX<0) /* then we need to clip */ + { + imageDesc.Width += imageDesc.TopLeftX; + imageDesc.TopLeftU -= imageDesc.TopLeftX; + imageDesc.TopLeftX = 0; + } + Draw_HUDImage(&imageDesc); +} +extern void D3D_BlitWhiteChar(int x, int y, unsigned char c) +{ + HUDImageDesc imageDesc; + +// if (c>='a' && c<='z') c-='a'-'A'; + +// if (c<' ' || c>'_') return; + if (c==' ') return; + + #if 0 + imageDesc.ImageNumber = HUDFontsImageNumber; + + imageDesc.TopLeftX = x; + imageDesc.TopLeftY = y; + imageDesc.TopLeftU = 1+((c-32)&15)*7; + imageDesc.TopLeftV = 2+((c-32)>>4)*11; + imageDesc.Height = 8; + imageDesc.Width = 5; + #else + imageDesc.ImageNumber = AAFontImageNumber; + + imageDesc.TopLeftX = x; + imageDesc.TopLeftY = y; + imageDesc.TopLeftU = 1+((c-32)&15)*16; + imageDesc.TopLeftV = 1+((c-32)>>4)*16; + imageDesc.Height = 15; + imageDesc.Width = 15; + #endif + imageDesc.Scale = ONE_FIXED; + imageDesc.Translucency = 255; + imageDesc.Red = 255; + imageDesc.Green = 255; + imageDesc.Blue = 255; + + Draw_HUDImage(&imageDesc); +} + +void D3D_DrawHUDFontCharacter(HUDCharDesc *charDescPtr) +{ + HUDImageDesc imageDesc; + + // if (charDescPtr->Character<' ' || charDescPtr->Character>'_') return; + if (charDescPtr->Character == ' ') return; + + imageDesc.ImageNumber = AAFontImageNumber; + + imageDesc.TopLeftX = charDescPtr->X-1; + imageDesc.TopLeftY = charDescPtr->Y-1; + imageDesc.TopLeftU = 0+((charDescPtr->Character-32)&15)*16; + imageDesc.TopLeftV = 0+((charDescPtr->Character-32)>>4)*16; + imageDesc.Height = HUD_FONT_HEIGHT+2; + imageDesc.Width = HUD_FONT_WIDTH+2; + + imageDesc.Scale = ONE_FIXED; + imageDesc.Translucency = charDescPtr->Alpha; + imageDesc.Red = charDescPtr->Red; + imageDesc.Green = charDescPtr->Green; + imageDesc.Blue = charDescPtr->Blue; + + Draw_HUDImage(&imageDesc); + +} +void D3D_DrawHUDDigit(HUDCharDesc *charDescPtr) +{ + HUDImageDesc imageDesc; + + imageDesc.ImageNumber = HUDFontsImageNumber; + + imageDesc.TopLeftX = charDescPtr->X; + imageDesc.TopLeftY = charDescPtr->Y; + + if (charDescPtr->Character<8) + { + imageDesc.TopLeftU = 1+(charDescPtr->Character)*16; + imageDesc.TopLeftV = 81; + } + else + { + imageDesc.TopLeftU = 1+(charDescPtr->Character-8)*16; + imageDesc.TopLeftV = 81+24; + } + + + imageDesc.Height = HUD_DIGITAL_NUMBERS_HEIGHT; + imageDesc.Width = HUD_DIGITAL_NUMBERS_WIDTH; + imageDesc.Scale = ONE_FIXED; + imageDesc.Translucency = charDescPtr->Alpha; + imageDesc.Red = charDescPtr->Red; + imageDesc.Green = charDescPtr->Green; + imageDesc.Blue = charDescPtr->Blue; + + Draw_HUDImage(&imageDesc); + +} +void D3D_DrawHUDPredatorDigit(HUDCharDesc *charDescPtr, int scale) +{ + HUDImageDesc imageDesc; + + imageDesc.ImageNumber = PredatorNumbersImageNumber; + + imageDesc.TopLeftX = charDescPtr->X; + imageDesc.TopLeftY = charDescPtr->Y; + + if (charDescPtr->Character<5) + { + imageDesc.TopLeftU = (charDescPtr->Character)*51; + imageDesc.TopLeftV = 1; + } + else + { + imageDesc.TopLeftU = (charDescPtr->Character-5)*51; + imageDesc.TopLeftV = 52; + } + + + imageDesc.Height = 50; + imageDesc.Width = 50; + imageDesc.Scale = scale; + imageDesc.Translucency = charDescPtr->Alpha; + imageDesc.Red = charDescPtr->Red; + imageDesc.Green = charDescPtr->Green; + imageDesc.Blue = charDescPtr->Blue; + + Draw_HUDImage(&imageDesc); + +} + +void D3D_BLTDigitToHUD(char digit, int x, int y, int font) +{ + HUDImageDesc imageDesc; + struct HUDFontDescTag *FontDescPtr; + int gfxID; + + switch (font) + { + case MARINE_HUD_FONT_MT_SMALL: + case MARINE_HUD_FONT_MT_BIG: + { + gfxID = MARINE_HUD_GFX_TRACKERFONT; + imageDesc.Scale = MotionTrackerScale; + x = MUL_FIXED(x,MotionTrackerScale) + MotionTrackerCentreX; + y = MUL_FIXED(y,MotionTrackerScale) + MotionTrackerCentreY; + break; + } + case MARINE_HUD_FONT_RED: + case MARINE_HUD_FONT_BLUE: + { + if (x<0) x+=ScreenDescriptorBlock.SDB_Width; + gfxID = MARINE_HUD_GFX_NUMERALS; + imageDesc.Scale=ONE_FIXED; + break; + } + case ALIEN_HUD_FONT: + { + gfxID = ALIEN_HUD_GFX_NUMBERS; + imageDesc.Scale=ONE_FIXED; + break; + } + default: + LOCALASSERT(0); + break; + } + + + if (HUDResolution == HUD_RES_LO) + { + FontDescPtr = &HUDFontDesc[font]; + } + else if (HUDResolution == HUD_RES_MED) + { + FontDescPtr = &HUDFontDesc[font]; + } + else + { + FontDescPtr = &HUDFontDesc[font]; + } + + + + imageDesc.ImageNumber = HUDImageNumber; + imageDesc.TopLeftX = x; + imageDesc.TopLeftY = y; + imageDesc.TopLeftU = FontDescPtr->XOffset; + imageDesc.TopLeftV = digit*(FontDescPtr->Height+1)+1; + + imageDesc.Height = FontDescPtr->Height; + imageDesc.Width = FontDescPtr->Width; + imageDesc.Translucency = HUDTranslucencyLevel; + imageDesc.Red = 255; + imageDesc.Green = 255; + imageDesc.Blue = 255; + + Draw_HUDImage(&imageDesc); + +} + +void D3D_BLTGunSightToHUD(int screenX, int screenY, enum GUNSIGHT_SHAPE gunsightShape) +{ + HUDImageDesc imageDesc; + int gunsightSize=13; + + screenX = (screenX-(gunsightSize/2)); + screenY = (screenY-(gunsightSize/2)); + + imageDesc.ImageNumber = HUDImageNumber; + imageDesc.TopLeftX = screenX; + imageDesc.TopLeftY = screenY; + imageDesc.TopLeftU = 227; + imageDesc.TopLeftV = 131+(gunsightShape*(gunsightSize+1)); + imageDesc.Height = gunsightSize; + imageDesc.Width = gunsightSize; + imageDesc.Scale = ONE_FIXED; + imageDesc.Translucency = 128; + imageDesc.Red = 255; + imageDesc.Green = 255; + imageDesc.Blue = 255; + + Draw_HUDImage(&imageDesc); +} + +void LoadBackdropImage(void) +{ +#if 1 + extern int BackdropImage; + extern char LevelName[]; + if (!strcmp(LevelName,"pred03")) + BackdropImage = CL_LoadImageOnce("Envrnmts\\Pred03\\backdrop.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE); +#endif +} + + +void Render_HealthAndArmour(unsigned int health, unsigned int armour) +{ + HUDCharDesc charDesc; + int i=MAX_NO_OF_COMMON_HUD_DIGITS; + unsigned int healthColour; + unsigned int armourColour; + + if (AvP.PlayerType == I_Marine) + { + int xCentre = MUL_FIXED(HUDLayout_RightmostTextCentre,HUDScaleFactor)+ScreenDescriptorBlock.SDB_Width; + healthColour = HUDLayout_Colour_MarineGreen; + armourColour = HUDLayout_Colour_MarineGreen; + D3D_RenderHUDString_Centred + ( + GetTextString(TEXTSTRING_INGAME_HEALTH), + xCentre, + MUL_FIXED(HUDLayout_Health_TopY,HUDScaleFactor), + HUDLayout_Colour_BrightWhite + ); + D3D_RenderHUDNumber_Centred + ( + health, + xCentre, + MUL_FIXED(HUDLayout_Health_TopY+HUDLayout_Linespacing,HUDScaleFactor), + healthColour + ); + D3D_RenderHUDString_Centred + ( + GetTextString(TEXTSTRING_INGAME_ARMOUR), + xCentre, + MUL_FIXED(HUDLayout_Armour_TopY,HUDScaleFactor), + HUDLayout_Colour_BrightWhite + ); + D3D_RenderHUDNumber_Centred + ( + armour, + xCentre, + MUL_FIXED(HUDLayout_Armour_TopY+HUDLayout_Linespacing,HUDScaleFactor), + armourColour + ); + } + else + { + if (health>100) + { + healthColour = HUDLayout_Colour_BrightWhite; + } + else + { + int r = ((health)*128)/100; + healthColour = 0xff000000 + ((128-r)<<16) + (r<<8); + } + if (armour>100) + { + armourColour = HUDLayout_Colour_BrightWhite; + } + else + { + int r = ((armour)*128)/100; + armourColour = 0xff000000 + ((128-r)<<16) + (r<<8); + } + + { + + struct VertexTag quadVertices[4]; + int scaledWidth; + int scaledHeight; + int x,y; + + if (health<100) + { + scaledWidth = WideMulNarrowDiv(ScreenDescriptorBlock.SDB_Width,health,100); + scaledHeight = scaledWidth/32; + } + else + { + scaledWidth = ScreenDescriptorBlock.SDB_Width; + scaledHeight = scaledWidth/32; + } + x = (ScreenDescriptorBlock.SDB_Width - scaledWidth)/2; + y = ScreenDescriptorBlock.SDB_Height - ScreenDescriptorBlock.SDB_Width/32 + x/32; + + quadVertices[0].U = 8; + quadVertices[0].V = 5; + quadVertices[1].U = 57;//255; + quadVertices[1].V = 5; + quadVertices[2].U = 57;//255; + quadVertices[2].V = 55;//255; + quadVertices[3].U = 8; + quadVertices[3].V = 55;//255; + + quadVertices[0].X = x; + quadVertices[0].Y = y; + quadVertices[1].X = x + scaledWidth; + quadVertices[1].Y = y; + quadVertices[2].X = x + scaledWidth; + quadVertices[2].Y = y + scaledHeight; + quadVertices[3].X = x; + quadVertices[3].Y = y + scaledHeight; + + D3D_HUDQuad_Output + ( + SpecialFXImageNumber,// AlienEnergyBarImageNumber, + quadVertices, + 0xff003fff + ); + + health = (health/2); + if (health<0) health=0; + + if (health<100) + { + scaledWidth = WideMulNarrowDiv(ScreenDescriptorBlock.SDB_Width,health,100); + scaledHeight = scaledWidth/32; + } + else + { + scaledWidth = ScreenDescriptorBlock.SDB_Width; + scaledHeight = scaledWidth/32; + } + + x = (ScreenDescriptorBlock.SDB_Width - scaledWidth)/2; + y = ScreenDescriptorBlock.SDB_Height - ScreenDescriptorBlock.SDB_Width/32 + x/32; + + quadVertices[0].X = x; + quadVertices[0].Y = y; + quadVertices[1].X = x + scaledWidth; + quadVertices[1].Y = y; + quadVertices[2].X = x + scaledWidth; + quadVertices[2].Y = y + scaledHeight; + quadVertices[3].X = x; + quadVertices[3].Y = y + scaledHeight; + + D3D_HUDQuad_Output + ( + SpecialFXImageNumber,// AlienEnergyBarImageNumber, + quadVertices, + 0xffffffff + ); + + } + + } + + + +} +void Render_MarineAmmo(enum TEXTSTRING_ID ammoText, enum TEXTSTRING_ID magazinesText, unsigned int magazines, enum TEXTSTRING_ID roundsText, unsigned int rounds, int primaryAmmo) +{ + HUDCharDesc charDesc; + int i=MAX_NO_OF_COMMON_HUD_DIGITS; + int xCentre = MUL_FIXED(HUDLayout_RightmostTextCentre,HUDScaleFactor)+ScreenDescriptorBlock.SDB_Width; + if(!primaryAmmo) xCentre+=MUL_FIXED(HUDScaleFactor,HUDLayout_RightmostTextCentre*2); + + D3D_RenderHUDString_Centred + ( + GetTextString(ammoText), + xCentre, + ScreenDescriptorBlock.SDB_Height - MUL_FIXED(HUDScaleFactor,HUDLayout_AmmoDesc_TopY), + HUDLayout_Colour_BrightWhite + ); + D3D_RenderHUDString_Centred + ( + GetTextString(magazinesText), + xCentre, + ScreenDescriptorBlock.SDB_Height -MUL_FIXED(HUDScaleFactor, HUDLayout_Magazines_TopY), + HUDLayout_Colour_BrightWhite + ); + D3D_RenderHUDNumber_Centred + ( + magazines, + xCentre, + ScreenDescriptorBlock.SDB_Height - MUL_FIXED(HUDScaleFactor,HUDLayout_Magazines_TopY - HUDLayout_Linespacing), + HUDLayout_Colour_MarineRed + ); + D3D_RenderHUDString_Centred + ( + GetTextString(roundsText), + xCentre, + ScreenDescriptorBlock.SDB_Height - MUL_FIXED(HUDScaleFactor,HUDLayout_Rounds_TopY), + HUDLayout_Colour_BrightWhite + ); + D3D_RenderHUDNumber_Centred + ( + rounds, + xCentre, + ScreenDescriptorBlock.SDB_Height - MUL_FIXED(HUDScaleFactor,HUDLayout_Rounds_TopY - HUDLayout_Linespacing), + HUDLayout_Colour_MarineRed + ); + + +} +void DrawPredatorEnergyBar(void) +{ + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + int maxHeight = ScreenDescriptorBlock.SDB_Height*3/4; + int h; + { + h = MUL_FIXED(DIV_FIXED(playerStatusPtr->FieldCharge,PLAYERCLOAK_MAXENERGY),maxHeight); + + r2rect rectangle + ( + ScreenDescriptorBlock.SDB_Width+HUDLayout_RightmostTextCentre*3/2, + ScreenDescriptorBlock.SDB_Height-h, + ScreenDescriptorBlock.SDB_Width+HUDLayout_RightmostTextCentre/2, + ScreenDescriptorBlock.SDB_Height + + ); + rectangle . AlphaFill + ( + 0xff, // unsigned char R, + 0x00,// unsigned char G, + 0x00,// unsigned char B, + 128 // unsigned char translucency + ); + } + if (weaponPtr->WeaponIDNumber == WEAPON_PRED_SHOULDERCANNON) + { + h = MUL_FIXED(playerStatusPtr->PlasmaCasterCharge,maxHeight); + + r2rect rectangle + ( + ScreenDescriptorBlock.SDB_Width+HUDLayout_RightmostTextCentre*3, + ScreenDescriptorBlock.SDB_Height-h, + ScreenDescriptorBlock.SDB_Width+HUDLayout_RightmostTextCentre*2, + ScreenDescriptorBlock.SDB_Height + + ); + rectangle . AlphaFill + ( + 0x00, // unsigned char R, + 0xff,// unsigned char G, + 0xff,// unsigned char B, + 128 // unsigned char translucency + ); + } + +} + +}; diff --git a/3dc/avp/win95/d3d_hud.h b/3dc/avp/win95/d3d_hud.h new file mode 100644 index 0000000..3371d30 --- /dev/null +++ b/3dc/avp/win95/d3d_hud.h @@ -0,0 +1,66 @@ +#include "langenum.h" +extern void D3D_HUD_Setup(void); +extern void D3D_HUDQuad_Output(int imageNumber,struct VertexTag *quadVerticesPtr,unsigned int colour); + + +extern int TransparencyLevelOfHUD; +/* takes values of 0 (not drawn) to 255 (opaque) */ + + +struct VertexTag +{ + int X; + int Y; + int U; + int V; +}; + +typedef struct +{ + int ImageNumber; + + int TopLeftX; + int TopLeftY; + + int TopLeftU; + int TopLeftV; + + int Width; + int Height; + + int Scale; + + unsigned char Red; + unsigned char Green; + unsigned char Blue; + unsigned char Translucency; /* 0 == invisible, 255 == opaque */ + +} HUDImageDesc; + + +typedef struct +{ + char Character; + int X; + int Y; + + unsigned char Red; + unsigned char Green; + unsigned char Blue; + unsigned char Alpha; + +} HUDCharDesc; + + + +extern void D3D_DrawHUDFontCharacter(HUDCharDesc *charDescPtr); +extern void D3D_DrawHUDDigit(HUDCharDesc *charDescPtr); + + +extern void D3D_BlitWhiteChar(int x, int y, unsigned char c); + + + +/* KJL 17:55:48 18/04/98 - called by HUD.c */ +extern void Render_HealthAndArmour(unsigned int health, unsigned int armour); +extern void Render_MarineAmmo(enum TEXTSTRING_ID ammoText, enum TEXTSTRING_ID magazinesText, unsigned int magazines, enum TEXTSTRING_ID roundsText, unsigned int rounds, int primaryAmmo); diff --git a/3dc/avp/win95/d3d_render.cpp b/3dc/avp/win95/d3d_render.cpp new file mode 100644 index 0000000..c33e803 --- /dev/null +++ b/3dc/avp/win95/d3d_render.cpp @@ -0,0 +1,8976 @@ +extern "C" { + +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "gamedef.h" +#include "stratdef.h" +#include "vramtime.h" + +#include "dxlog.h" + +#include "d3_func.h" +#include "d3dmacs.h" + +#include "string.h" + +#include "kshape.h" +#include "frustrum.h" + +#include "d3d_hud.h" +#include "gamedef.h" + +#include "particle.h" + +#define UseLocalAssert No +#include "ourasert.h" +extern "C++"{ +#include "r2base.h" +#include // for sqrt +}; +#include "HUD_layout.h" +#define HAVE_VISION_H 1 +#include "vision.h" +#include "lighting.h" +#include "showcmds.h" +#include "frustrum.h" +#include "smacker.h" +#include "d3d_render.h" +#include "avp_userprofile.h" +#include "bh_types.h" + +#include + + +#define RGBLIGHT_MAKE(r,g,b) RGB_MAKE(r,g,b) +#define RGBALIGHT_MAKE(r,g,b,a) RGBA_MAKE(r,g,b,a) + + +// Set to Yes to make default texture filter bilinear averaging rather +// than nearest +extern BOOL BilinearTextureFilter; + + + +#define FMV_ON 0 +#define FMV_EVERYWHERE 0 +#define WIBBLY_FMV_ON 0 +#define FMV_SIZE 128 +VECTORCH FmvPosition = {42985-3500,2765-5000,-35457}; + +#define FOG_ON 0 +#if 1 + +#define FOG_COLOUR 0x7f7f7f //0x404040 +#define FOG_SCALE 512 +#else +#define FOG_COLOUR 0x7f7f7f//0xd282828 //0x404040 +#define FOG_SCALE 256 +#endif + +#define TriangleVertices 3 + +#define LineVertices 2 + +#define DefaultVertexIntensity 200 +#define TransparentAlphaValue 128 + +#define DefaultColour (RGBLIGHT_MAKE(DefaultVertexIntensity,DefaultVertexIntensity,DefaultVertexIntensity)) +#define DefaultAlphaColour (RGBALIGHT_MAKE(DefaultVertexIntensity,DefaultVertexIntensity,DefaultVertexIntensity,TransparentAlphaValue)) + + +#if 0 +#define TxIntensityLShift 4 +#else +#define TxIntensityLShift 0 +#endif + +#define TxIntensityLimit 255 + +#define MaxVerticesInExecuteBuffer (MaxD3DVertices) +// Colour is a 24-bit RGB colour, standard engine +// internal format. +// a is an 8 bit alpha value. +#define MAKE_ALPHACOLOUR(colour, a) ((D3DCOLOR) (((a) << 24) | (colour))) + +extern int SpecialFXImageNumber; +extern int SmokyImageNumber; +extern int ChromeImageNumber; +extern int HUDFontsImageNumber; +extern int BurningImageNumber; +extern int PredatorVisionChangeImageNumber; +extern int PredatorNumbersImageNumber; +extern int StaticImageNumber; +extern int AAFontImageNumber; +extern int WaterShaftImageNumber; + +D3DTEXTUREHANDLE FMVTextureHandle[4]; +D3DTEXTUREHANDLE NoiseTextureHandle; + +int LightIntensityAtPoint(VECTORCH *pointPtr); + +// Externs + +extern int VideoMode; +extern int WindowMode; +extern int ScanDrawMode; +extern int DXMemoryMode; +extern int ZBufferRequestMode; +extern int RasterisationRequestMode; +extern int SoftwareScanDrawRequestMode; +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; +extern VIEWDESCRIPTORBLOCK* Global_VDB_Ptr; + + +extern IMAGEHEADER ImageHeaderArray[]; +extern int NumImagesArray[]; + +extern LPDIRECTDRAW lpDD; +extern LPDIRECTDRAWSURFACE lpDDSPrimary; +extern BOOL MMXAvailable; +extern int NormalFrameTime; +int WireFrameMode; + +extern int HUDScaleFactor; + +//Globals + +int D3DDriverMode; +int NumVertices; + +static LPVOID ExecuteBufferDataArea; +static LPVOID ExecuteBufferInstArea; +static LPVOID ExecBufDataPtr; +static LPVOID ExecBufInstPtr; +static LPVOID ExecBufStartInstPtr; +#if SupportZBuffering +#endif + + +static unsigned char D3DShadingMode; +static unsigned char D3DTexturePerspective; +static unsigned char D3DTBlendMode; +static unsigned char D3DAlphaMode; +static D3DTEXTUREHANDLE CurrTextureHandle; +static unsigned char DefaultD3DTextureFilterMin; +static unsigned char DefaultD3DTextureFilterMax; +// Globals for frame by frame definition of +// coloured materials for D3D rendering interface + + + + +static int NumberOfRenderedTriangles=0; +int NumberOfLandscapePolygons; +RENDERSTATES CurrentRenderStates; +extern HRESULT LastError; + + +void ChangeTranslucencyMode(enum TRANSLUCENCY_TYPE translucencyRequired); +void ChangeFilteringMode(enum FILTERING_MODE_ID filteringRequired); + +#define CheckTranslucencyModeIsCorrect(x) \ +if (CurrentRenderStates.TranslucencyMode!=(x)) \ + ChangeTranslucencyMode((x)); + +#define CheckFilteringModeIsCorrect(x) \ +if (CurrentRenderStates.FilteringMode!=(x)) \ + ChangeFilteringMode((x)); + + + +extern D3DINFO d3d; + +extern int ExBufSize; +extern LPDIRECT3DEXECUTEBUFFER lpD3DExecCmdBuf; + + + + + +/* KJL 15:12:02 10/05/98 - FMV stuff */ +static PALETTEENTRY FMVPalette[4][256]; + +void D3D_DrawFMVOnWater(int xOrigin, int yOrigin, int zOrigin); +static void UpdateFMVTextures(int maxTextureNumberToUpdate); +extern int NextFMVFrame(void*bufferPtr, int x, int y, int w, int h, int fmvNumber); +extern void UpdateFMVPalette(PALETTEENTRY *FMVPalette, int fmvNumber); + +void D3D_DrawFMV(int xOrigin, int yOrigin, int zOrigin); + +VECTORCH FMVParticleAbsPosition[450]; +VECTORCH FMVParticlePosition[450]; +int FMVParticleColour; + +void D3D_DrawSwirlyFMV(int xOrigin, int yOrigin, int zOrigin); +void D3D_FMVParticle_Output(RENDERVERTEX *renderVerticesPtr); + + +void DrawFBM(void); + + + +void D3D_DrawCable(VECTORCH *centrePtr, MATRIXCH *orientationPtr); + + +int WaterXOrigin; +int WaterZOrigin; +float WaterUScale; +float WaterVScale; + +BOOL SetExecuteBufferDefaults(void) + +{ + D3DEXECUTEBUFFERDESC d3dexDesc; + D3DEXECUTEDATA d3dExecData; + + memset(&d3dexDesc, 0, sizeof(D3DEXECUTEBUFFERDESC)); + d3dexDesc.dwSize = sizeof(D3DEXECUTEBUFFERDESC); + + // Acquire lock on execute buffer + LastError = lpD3DExecCmdBuf->Lock(&d3dexDesc); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + + // Zero buffer and acquire pointers to start of areas + memset(d3dexDesc.lpData, 0, ExBufSize); + + // Initialise pointers to data areas within buffer + ExecuteBufferDataArea = d3dexDesc.lpData; + ExecuteBufferInstArea = (LPVOID) + ((int) ExecuteBufferDataArea + + (int) (sizeof(D3DTLVERTEX) * MaxVerticesInExecuteBuffer)); + + ExecBufDataPtr = ExecuteBufferDataArea; + ExecBufInstPtr = ExecuteBufferInstArea; + + NumVertices = 0; + +// If we can, we want to turn off culling at the level of the rasterisation +// module. Note that Microsoft's software renderers do not support this, +// unfortunately. + #if 1 + if (ScanDrawMode == ScanDrawD3DHardwareRGB) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_CULLMODE, D3DCULL_NONE, ExecBufInstPtr); + } + #endif + + #if SupportZBuffering + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZENABLE, TRUE, ExecBufInstPtr); + + + // Certainly necess for new mixed HSR model!!! + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZWRITEENABLE, TRUE, ExecBufInstPtr); + + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL, ExecBufInstPtr); + + #endif + + // Set default alpha modes with blending off + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SRCBLEND, + D3DBLEND_SRCALPHA, ExecBufInstPtr); + + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_DESTBLEND, + D3DBLEND_INVSRCALPHA, ExecBufInstPtr); + + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ALPHABLENDENABLE, + FALSE, ExecBufInstPtr); + + #if FOG_ON + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_FOGENABLE, TRUE, ExecBufInstPtr); + + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_FOGCOLOR, FOG_COLOUR, ExecBufInstPtr); + #endif + #if 0 + { + float fogStart = 2000.0f; // these values work on a Voodoo2, but not a G200. Hmm. + float fogEnd = 32000.0f; + OP_STATE_RENDER(2, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_FOGENABLE, TRUE, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_FOGCOLOR, 0x7f7f7f, ExecBufInstPtr); + + #if 1 + OP_STATE_RENDER(3, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_FOGTABLEMODE, D3DFOG_LINEAR, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_FOGTABLESTART, *(DWORD*)(&fogStart), ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_FOGTABLEEND, *(DWORD*)(&fogEnd), ExecBufInstPtr); + #endif +// STATE_DATA(D3DRENDERSTATE_SPECULARENABLE, FALSE, ExecBufInstPtr); + } + #endif + + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATE, ExecBufInstPtr); + + OP_EXIT(ExecBufInstPtr); + + // Unlock buffer + LastError = lpD3DExecCmdBuf->Unlock(); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + + // Setup for execution + memset(&d3dExecData, 0, sizeof(D3DEXECUTEDATA)); + d3dExecData.dwSize = sizeof(D3DEXECUTEDATA); + // Vertices start at beginning of buffer, i.e. + // at ExecuteBufferDataArea, so there is no + // Vertex Offset. + d3dExecData.dwVertexCount = NumVertices; + + d3dExecData.dwInstructionOffset = (ULONG) ((char*) ExecuteBufferInstArea + - (char*) ExecuteBufferDataArea); + d3dExecData.dwInstructionLength = (ULONG) ((char*)ExecBufInstPtr + - (char*) ExecuteBufferInstArea); + + // Do the actual set up + LastError = lpD3DExecCmdBuf->SetExecuteData(&d3dExecData); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + + LastError = d3d.lpD3DDevice->BeginScene(); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + + // Execute buffer + // We will specify no clipping since the engine + // already clips to the VDB. Eventually we might + // try for no culling as well...if we're feeling + // really daring... + LastError = d3d.lpD3DDevice->Execute(lpD3DExecCmdBuf, + d3d.lpD3DViewport, D3DEXECUTE_UNCLIPPED); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + + // End scene + LastError = d3d.lpD3DDevice->EndScene(); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + + return TRUE; +} +static int NeedToClearExecuteBuffer=1; +BOOL LockExecuteBuffer(void) + +{ + D3DEXECUTEBUFFERDESC d3dexDesc; + + memset(&d3dexDesc, 0, sizeof(D3DEXECUTEBUFFERDESC)); + d3dexDesc.dwSize = sizeof(D3DEXECUTEBUFFERDESC); + + // Acquire lock on execute buffer + LastError = lpD3DExecCmdBuf->Lock(&d3dexDesc); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + + // Zero buffer and acquire pointers to start of areas +// memset(d3dexDesc.lpData, 0, ExBufSize); + // if(NeedToClearExecuteBuffer) + { + memset(d3dexDesc.lpData, 0, ExBufSize); + // NeedToClearExecuteBuffer=0; + } + //textprint("ExBufSize %d %d %d %d\n",ExBufSize,sizeof(D3DINSTRUCTION),sizeof(D3DTRIANGLE),sizeof(D3DTLVERTEX) ); + // Two lines below should really be in init routine, + // but are here for the moment in case locking has + // weird side effects. + // FIXME!!!! + // Initialise pointers to data areas within buffer + ExecuteBufferDataArea = d3dexDesc.lpData; + // Hmmm.... + ExecuteBufferInstArea = (LPVOID) + ((int) ExecuteBufferDataArea + + (int) (sizeof(D3DTLVERTEX) * MaxVerticesInExecuteBuffer)); + + ExecBufDataPtr = ExecuteBufferDataArea; + ExecBufInstPtr = ExecuteBufferInstArea; + NumVertices = 0; + +// Force initialisation of render states during +// first call to Write functions + D3DShadingMode = 0xff; + D3DTexturePerspective = 0xff; + D3DAlphaMode = 0xff; + +// Other initialisations + CurrTextureHandle = (D3DTEXTUREHANDLE) 0xff; + + +// Save pointer to execute buffer and +// wind that pointer on by the +// amount of a process vertices data opcode and +// associated data + ExecBufStartInstPtr = ExecBufInstPtr; + ExecBufInstPtr = (void*)(((LPD3DINSTRUCTION) ExecBufInstPtr) + 1); + ExecBufInstPtr = (void*)(((LPD3DPROCESSVERTICES) ExecBufInstPtr) + 1); + + #if 0 + // Set default texture filter for this frame + // NOTE THAT BILINEAR BEHAVIOUR MIGHT EVENTUALLY BE BEST + // MOVED TO AN ITEM FLAG, NOT A COMPILE OPTION + // Note at present no support for averaging between + // mip-maps!!! May well not exist on all (or most) accelerators + // anyway!!! + if (BilinearTextureFilter) + { + if (ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP) + { + DefaultD3DTextureFilterMin = D3DFILTER_MIPLINEAR; + DefaultD3DTextureFilterMax = D3DFILTER_MIPLINEAR; + } + else + { + DefaultD3DTextureFilterMin = D3DFILTER_LINEAR; + DefaultD3DTextureFilterMax = D3DFILTER_LINEAR; + } + } + else + { + if (ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP) + { + DefaultD3DTextureFilterMin = D3DFILTER_MIPNEAREST; + DefaultD3DTextureFilterMax = D3DFILTER_MIPNEAREST; + } + else + { + DefaultD3DTextureFilterMin = D3DFILTER_NEAREST; + DefaultD3DTextureFilterMax = D3DFILTER_NEAREST; + } + } + // Actually set default texture filters + + OP_STATE_RENDER(2, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREMAG, DefaultD3DTextureFilterMax, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREMIN, DefaultD3DTextureFilterMin, ExecBufInstPtr); + #endif + return TRUE; +} + + +BOOL UnlockExecuteBufferAndPrepareForUse(void) + +{ + D3DEXECUTEDATA d3dExecData; + + // Unlock buffer + LastError = lpD3DExecCmdBuf->Unlock(); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + + // Setup for execution + memset(&d3dExecData, 0, sizeof(D3DEXECUTEDATA)); + d3dExecData.dwSize = sizeof(D3DEXECUTEDATA); + // Vertices start at beginning of buffer, i.e. + // at ExecuteBufferDataArea, so there is no + // Vertex Offset. + d3dExecData.dwVertexCount = NumVertices; + + d3dExecData.dwInstructionOffset = (ULONG) ((char*) ExecuteBufferInstArea + - (char*) ExecuteBufferDataArea); + d3dExecData.dwInstructionLength = (ULONG) ((char*)ExecBufInstPtr + - (char*) ExecuteBufferInstArea); + + // Do the actual set up + LastError = lpD3DExecCmdBuf->SetExecuteData(&d3dExecData); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + + return TRUE; +} + +// Test for multiple execute buffers!!!! +BOOL BeginD3DScene(void) + +{ +#if SOFTWARE_RENDERER + LockSurfaceAndGetBufferPointer(); + + return TRUE; +#else + NumberOfRenderedTriangles=0; + LastError = d3d.lpD3DDevice->BeginScene(); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + else + return TRUE; +#endif +} +void D3D_SetupSceneDefaults(void) +{ + /* force translucency state to be reset */ + CurrentRenderStates.TranslucencyMode = TRANSLUCENCY_NOT_SET; + CurrentRenderStates.FilteringMode = FILTERING_NOT_SET; + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_ON); + CheckWireFrameMode(0); + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_DITHERENABLE, TRUE, ExecBufInstPtr); +} +BOOL EndD3DScene(void) + +{ +#if SOFTWARE_RENDERER + UnlockSurface(); + return TRUE; +#else + extern int NormalFrameTime; + + LastError = d3d.lpD3DDevice->EndScene(); + LOGDXERR(LastError); + if (ShowDebuggingText.PolyCount) + { + ReleasePrintDebuggingText("NumberOfLandscapePolygons: %d\n",NumberOfLandscapePolygons); + ReleasePrintDebuggingText("NumberOfRenderedTriangles: %d\n",NumberOfRenderedTriangles); + } +// textprint ("NumberOfRenderedTrianglesPerSecond: %d\n",DIV_FIXED(NumberOfRenderedTriangles,NormalFrameTime)); + NumberOfLandscapePolygons=0; + + if (LastError != D3D_OK) + return FALSE; + else + return TRUE; +#endif + +} +void WriteEndCodeToExecuteBuffer(void) +{ + // Initialise execute buffer by specifying + // that all operations will be rasterisation + // only (this optimises the immediate mode interface + // behaviour, since it knows that it will not + // be asked to perform geometry transformations + // or lighting operations). + // Write process vertices instruction + // to the START of the execute buffer, + // now that we know how many vertices + // there are. + + OP_PROCESS_VERTICES(1, ExecBufStartInstPtr); + PROCESSVERTICES_DATA(D3DPROCESSVERTICES_COPY, 0, NumVertices, ExecBufStartInstPtr); + + // Write single termination opcode to buffer + OP_EXIT(ExecBufInstPtr); +} + +#include "pentime.h" +BOOL ExecuteBuffer(void) + +{ +#if SOFTWARE_RENDERER + return TRUE; +#else + + // textprint("%d\n",sizeof(D3DINSTRUCTION) + sizeof(D3DTRIANGLE)); +// textprint("NumVertices %d\n Instructions %d",NumVertices,(char*)ExecBufInstPtr-(char*)ExecBufStartInstPtr); +//ProfileStart(); + LastError = d3d.lpD3DDevice->Execute(lpD3DExecCmdBuf, + d3d.lpD3DViewport, D3DEXECUTE_UNCLIPPED); + LOGDXERR(LastError); +//ProfileStop("execute buffer"); + if (LastError != D3D_OK) + return FALSE; + else + return TRUE; +#endif +} + +void CheckRenderStatesForModule(MODULE *modulePtr) +{ +// textprint("fog %d\n",CurrentRenderStates.FogIsOn); + + if (modulePtr->m_flags & MODULEFLAG_FOG) + { +// CurrentRenderStates.FogIsOn = 1; + } + else + { +// CurrentRenderStates.FogIsOn = 0; + } +} + +void SetFogDistance(int fogDistance) +{ + if (fogDistance>10000) fogDistance = 10000; + fogDistance+=5000; + fogDistance=2000; + CurrentRenderStates.FogDistance = fogDistance; +// textprint("fog distance %d\n",fogDistance); + +} + +void ChangeTranslucencyMode(enum TRANSLUCENCY_TYPE translucencyRequired) +{ + +// OP_STATE_RENDER(1, ExecBufInstPtr); +// STATE_DATA(D3DRENDERSTATE_STIPPLEDALPHA,FALSE, ExecBufInstPtr); +// OP_STATE_RENDER(1, ExecBufInstPtr); +// STATE_DATA(D3DRENDERSTATE_STIPPLEENABLE,FALSE, ExecBufInstPtr); +// if (CurrentRenderStates.TranslucencyMode!=(translucencyRequired)) + { + CurrentRenderStates.TranslucencyMode=translucencyRequired; + switch(CurrentRenderStates.TranslucencyMode) + { + case TRANSLUCENCY_OFF: + { + if (TRIPTASTIC_CHEATMODE||MOTIONBLUR_CHEATMODE) + { + if (D3DAlphaMode != Yes) + { + D3DAlphaMode = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE, ExecBufInstPtr); + } + OP_STATE_RENDER(2, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SRCBLEND,D3DBLEND_INVSRCALPHA, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_DESTBLEND,D3DBLEND_SRCALPHA, ExecBufInstPtr); + } + else + { + if (D3DAlphaMode != No) + { + D3DAlphaMode = No; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ALPHABLENDENABLE, FALSE, ExecBufInstPtr); + } + OP_STATE_RENDER(2, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ZERO, ExecBufInstPtr); + } + + break; + } + case TRANSLUCENCY_NORMAL: + { + if (D3DAlphaMode != Yes) + { + D3DAlphaMode = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE, ExecBufInstPtr); + } + OP_STATE_RENDER(2, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA, ExecBufInstPtr); + + + + break; + } + case TRANSLUCENCY_COLOUR: + { + if (D3DAlphaMode != Yes) + { + D3DAlphaMode = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE, ExecBufInstPtr); + } + OP_STATE_RENDER(2, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ZERO, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_DESTBLEND,D3DBLEND_SRCCOLOR, ExecBufInstPtr); + break; + } + case TRANSLUCENCY_INVCOLOUR: + { + if (D3DAlphaMode != Yes) + { + D3DAlphaMode = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE, ExecBufInstPtr); + } + OP_STATE_RENDER(2, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ZERO, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCCOLOR, ExecBufInstPtr); + break; + } + case TRANSLUCENCY_GLOWING: + { + if (D3DAlphaMode != Yes) + { + D3DAlphaMode = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE, ExecBufInstPtr); + } + OP_STATE_RENDER(2, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE, ExecBufInstPtr); + break; + } + case TRANSLUCENCY_DARKENINGCOLOUR: + { + if (D3DAlphaMode != Yes) + { + D3DAlphaMode = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE, ExecBufInstPtr); + } + OP_STATE_RENDER(2, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SRCBLEND,D3DBLEND_INVDESTCOLOR, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ZERO, ExecBufInstPtr); + break; + } + case TRANSLUCENCY_JUSTSETZ: + { + if (D3DAlphaMode != Yes) + { + D3DAlphaMode = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE, ExecBufInstPtr); + } + OP_STATE_RENDER(2, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ZERO, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE, ExecBufInstPtr); + } + + default: + break; + } + } +} + +void ChangeFilteringMode(enum FILTERING_MODE_ID filteringRequired) +{ + CurrentRenderStates.FilteringMode = filteringRequired; + + switch(CurrentRenderStates.FilteringMode) + { + case FILTERING_BILINEAR_OFF: + { + OP_STATE_RENDER(2, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_NEAREST, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_NEAREST, ExecBufInstPtr); + break; + } + case FILTERING_BILINEAR_ON: + { + OP_STATE_RENDER(2, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_LINEAR, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_LINEAR, ExecBufInstPtr); + break; + } + default: + { + LOCALASSERT("Unrecognized filtering mode"==0); + break; + } + } +} + +extern void CheckWireFrameMode(int shouldBeOn) +{ + if (shouldBeOn) shouldBeOn=1; + if(CurrentRenderStates.WireFrameModeIsOn!=shouldBeOn) + { + CurrentRenderStates.WireFrameModeIsOn=shouldBeOn; + if (shouldBeOn) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_FILLMODE, D3DFILL_WIREFRAME, ExecBufInstPtr); + } + else + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_FILLMODE, D3DFILL_SOLID, ExecBufInstPtr); + } + + } + +} +void D3D_Line(VECTOR2D* LineStart, VECTOR2D* LineEnd, int LineColour) +{ + if (d3d.ThisDriver.dpcLineCaps.dwShadeCaps & D3DPSHADECAPS_COLORFLATRGB) + { + int x1, x2, y1, y2; + + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + + // Test!!! + // LineColour = 0xffffffff; + vertexPtr->sx = LineStart->vx; + vertexPtr->sy = LineStart->vy; + vertexPtr[1].sx = LineEnd->vx; + vertexPtr[1].sy = LineEnd->vy; + + NumVertices+=2; + + vertexPtr->color = LineColour; + vertexPtr[1].color = LineColour; + + // Always turn off translucency for the moment + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_OFF); + + // Turn OFF texturing if it is on... + if (CurrTextureHandle != NULL) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NULL, ExecBufInstPtr); + CurrTextureHandle = NULL; + } + + OP_LINE_LIST(1, ExecBufInstPtr); + ((LPD3DLINE)ExecBufInstPtr)->v1 = (NumVertices-2); // vertex index + ((LPD3DLINE)ExecBufInstPtr)->v2 = (NumVertices-1); // vertex index + ExecBufInstPtr = ((char*)ExecBufInstPtr) + sizeof(D3DLINE); + } + + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } +} + +static void D3D_OutputTriangles(void); +void D3D_BackdropPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr) +{ + int flags; + int texoffset; + + D3DTEXTUREHANDLE TextureHandle; + + float ZNear; + float RecipW, RecipH; + + // Get ZNear + ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + + // Take header information + flags = inputPolyPtr->PolyFlags; + + // We assume bit 15 (TxLocal) HAS been + // properly cleared this time... + texoffset = (inputPolyPtr->PolyColour & ClrTxDefn); + + TextureHandle = (D3DTEXTUREHANDLE) + ImageHeaderArray[texoffset].D3DHandle; + + // Check for textures that have not loaded + // properly + + if (TextureHandle == (D3DTEXTUREHANDLE) 0) + return; + + if(ImageHeaderArray[texoffset].ImageWidth==128) + { + RecipW = 1.0 /128.0; + } + else + { + float width = (float) ImageHeaderArray[texoffset].ImageWidth; + RecipW = (1.0 / width); + } + if(ImageHeaderArray[texoffset].ImageHeight==128) + { + RecipH = 1.0 / 128.0; + } + else + { + float height = (float) ImageHeaderArray[texoffset].ImageHeight; + RecipH = (1.0 / height); + } + + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + float oneOverZ; + oneOverZ = (1.0)/vertices->Z; + float zvalue; + + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + + } + vertexPtr->tu = ((float)(vertices->U>>16)+.5) * RecipW; + vertexPtr->tv = ((float)(vertices->V>>16)+.5) * RecipH; + vertexPtr->rhw = oneOverZ; + + vertexPtr->color = RGBLIGHT_MAKE(vertices->R,vertices->G,vertices->B); + vertexPtr->sz = 1.0; + + vertexPtr->specular=RGBALIGHT_MAKE(0,0,0,255); + + vertices++; + NumVertices++; + } + while(--i); + } + + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_OFF); + + // Insert state change for shading model if required + if (D3DShadingMode != D3DSHADE_GOURAUD) + { + D3DShadingMode = D3DSHADE_GOURAUD; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SHADEMODE, + D3DSHADE_GOURAUD, ExecBufInstPtr); + } + +// Insert state change for texturing perspective value +// Note that drawtx3das2d options have ONLY been allowed for here, +// not when the rhw values are generated. This is a deliberate choice, +// based on the assumption that drawtx3das2d will not be used very often +// and the extra branching at the top of this function will impose a +// greater cost than the (rare) savings in floating pt divisions are worth. +// Or so I claim... + + if (D3DTexturePerspective != Yes) + { + D3DTexturePerspective = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, ExecBufInstPtr); + } + + if (TextureHandle != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + + + D3D_OutputTriangles(); +} + +void D3D_ZBufferedGouraudTexturedPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr) +{ + int flags; + int texoffset; + + D3DTEXTUREHANDLE TextureHandle; + + float ZNear; + float RecipW, RecipH; + + // Get ZNear + ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + + // Take header information + flags = inputPolyPtr->PolyFlags; + + // We assume bit 15 (TxLocal) HAS been + // properly cleared this time... + texoffset = (inputPolyPtr->PolyColour & ClrTxDefn); + if (texoffset) + { + TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[texoffset].D3DHandle; + } + else + { + TextureHandle = CurrTextureHandle; + } + + // Check for textures that have not loaded + // properly + +// if (TextureHandle == (D3DTEXTUREHANDLE) 0) + // return; + + #ifdef AVP_DEBUG_VERSION + if(ImageHeaderArray[texoffset].ImageWidth==128) + { + RecipW = (1.0f /128.0f)/65536.0f; + } + else + { + float width = (float) ImageHeaderArray[texoffset].ImageWidth; + RecipW = (1.0f / width)/65536.0f; + } + if(ImageHeaderArray[texoffset].ImageHeight==128) + { + RecipH = (1.0f / 128.0f)/65536.0f; + } + else + { + float height = (float) ImageHeaderArray[texoffset].ImageHeight; + RecipH = (1.0f / height)/65536.0f; + } + #else + RecipW = (1.0f/65536.0f)/128.0f; + RecipH = (1.0f/65536.0f)/128.0f; + #endif +// RecipW = (1.0/65536.0)/(float) ImageHeaderArray[texoffset].ImageWidth; +// RecipH = (1.0/65536.0)/(float) ImageHeaderArray[texoffset].ImageHeight; + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + float oneOverZ; + oneOverZ = (1.0f)/(vertices->Z); + float zvalue; + + vertexPtr->tu = ((float)vertices->U) * RecipW + (1.0f/256.0f); + vertexPtr->tv = ((float)vertices->V) * RecipH + (1.0f/256.0f); + vertexPtr->rhw = oneOverZ; + + { + zvalue = vertices->Z+HeadUpDisplayZOffset; + // zvalue /= 65536.0; + zvalue = 1.0f - ZNear/zvalue; + } + + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + + #if 1 + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + #endif + vertexPtr->sx=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + + #if 1 + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + #endif + vertexPtr->sy=y; + + } +// vertexPtr->tu = ((float)(vertices->U>>16)+0.5) * RecipW; +// vertexPtr->tv = ((float)(vertices->V>>16)+0.5) * RecipH; +// vertexPtr->rhw = oneOverZ; + + { + extern unsigned char GammaValues[256]; + vertexPtr->color = RGBALIGHT_MAKE(GammaValues[vertices->R],GammaValues[vertices->G],GammaValues[vertices->B],vertices->A); + } + + vertexPtr->sz = zvalue; + #if 0//FOG_ON + { + extern unsigned char GammaValues[256]; + int r = GammaValues[vertices->SpecularR]; + int g = GammaValues[vertices->SpecularG]; + int b = GammaValues[vertices->SpecularB]; + + if(CurrentRenderStates.FogIsOn && vertices->Z>5000)//CurrentRenderStates.FogDistance) + { +// extern int sine[]; +// extern int CloakingPhase; + int brightness = (vertices->R+vertices->G+vertices->B)*86*3; + + int fog = ((vertices->Z-5000/*-CurrentRenderStates.FogDistance*/)*4); + if (fog<0) fog=0; + if (fog>brightness) fog = brightness; + if (fog>ONE_FIXED) fog=ONE_FIXED; + + { + extern int SkyColour_R; + int rfog = MUL_FIXED(fog,SkyColour_R); + if (rspecular=RGBALIGHT_MAKE(r,g,b,255); + } + #else + #if 0 + if (RenderPolygon.TranslucencyMode != TRANSLUCENCY_OFF) + { + vertexPtr->specular=0; + } + else + #endif + { + extern unsigned char GammaValues[256]; + vertexPtr->specular=RGBALIGHT_MAKE(GammaValues[vertices->SpecularR],GammaValues[vertices->SpecularG],GammaValues[vertices->SpecularB],255); + } + #endif + + vertices++; + NumVertices++; + } + while(--i); + } + CheckTranslucencyModeIsCorrect(RenderPolygon.TranslucencyMode); + + // Insert state change for shading model if required + if (D3DShadingMode != D3DSHADE_GOURAUD) + { + D3DShadingMode = D3DSHADE_GOURAUD; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SHADEMODE, + D3DSHADE_GOURAUD, ExecBufInstPtr); + } + +// Insert state change for texturing perspective value +// Note that drawtx3das2d options have ONLY been allowed for here, +// not when the rhw values are generated. This is a deliberate choice, +// based on the assumption that drawtx3das2d will not be used very often +// and the extra branching at the top of this function will impose a +// greater cost than the (rare) savings in floating pt divisions are worth. +// Or so I claim... + + if (D3DTexturePerspective != Yes) + { + D3DTexturePerspective = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, ExecBufInstPtr); + } + + #if FMV_EVERYWHERE + TextureHandle = FMVTextureHandle[0]; + #endif + if (TextureHandle != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + + + D3D_OutputTriangles(); +} +void D3D_ZBufferedGouraudPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr) +{ + int flags; + + float ZNear; + + // Get ZNear + ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + // Take header information + flags = inputPolyPtr->PolyFlags; + + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + float oneOverZ; + oneOverZ = (1.0)/vertices->Z; + float zvalue; + + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + } + { + zvalue = vertices->Z+HeadUpDisplayZOffset; + zvalue = ((zvalue-ZNear)/zvalue); + } + + { + if (flags & iflag_transparent) + { + vertexPtr->color = RGBALIGHT_MAKE(vertices->R,vertices->G,vertices->B, vertices->A); + } + else + { + vertexPtr->color = RGBLIGHT_MAKE(vertices->R,vertices->G,vertices->B); + } + } + vertexPtr->sz = zvalue; + vertices++; + NumVertices++; + } + while(--i); + } + CheckTranslucencyModeIsCorrect(RenderPolygon.TranslucencyMode); + + // Insert state change for shading model if required + if (D3DShadingMode != D3DSHADE_GOURAUD) + { + D3DShadingMode = D3DSHADE_GOURAUD; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SHADEMODE, + D3DSHADE_GOURAUD, ExecBufInstPtr); + } + + // Turn OFF texturing if it is on... + if (CurrTextureHandle != NULL) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NULL, ExecBufInstPtr); + CurrTextureHandle = NULL; + } + + D3D_OutputTriangles(); +} +void D3D_PredatorThermalVisionPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr) +{ + float ZNear; + + // Get ZNear + ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + float oneOverZ; + oneOverZ = (1.0)/vertices->Z; + float zvalue; + + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + } + { + zvalue = vertices->Z+HeadUpDisplayZOffset; + zvalue = ((zvalue-ZNear)/zvalue); + } + + vertexPtr->color = RGBALIGHT_MAKE(vertices->R,vertices->G,vertices->B,vertices->A);//RGBALIGHT_MAKE(255,255,255,255); + vertexPtr->sz = zvalue; + vertexPtr->rhw = zvalue; + vertices++; + NumVertices++; + } + while(--i); + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_OFF); + + // Insert state change for shading model if required + if (D3DShadingMode != D3DSHADE_GOURAUD) + { + D3DShadingMode = D3DSHADE_GOURAUD; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SHADEMODE, + D3DSHADE_GOURAUD, ExecBufInstPtr); + } + + // Turn OFF texturing if it is on... + if (CurrTextureHandle != NULL) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NULL, ExecBufInstPtr); + CurrTextureHandle = NULL; + } + D3D_OutputTriangles(); +} + +void D3D_PredatorSeeAliensVisionPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr) +{ + float ZNear; + + // Get ZNear + ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + float oneOverZ; + oneOverZ = (1.0)/vertices->Z; + float zvalue; + + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + } + { + zvalue = vertices->Z+HeadUpDisplayZOffset; + zvalue = ((zvalue-ZNear)/zvalue); + } + + vertexPtr->color = RGBALIGHT_MAKE(255,0,0,255);//255,255,255,255); + vertexPtr->sz = zvalue; + vertexPtr->rhw = zvalue; + vertices++; + NumVertices++; + } + while(--i); + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_GLOWING)//JUSTSETZ); + + + // Turn OFF texturing if it is on... + if (CurrTextureHandle != NULL) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NULL, ExecBufInstPtr); + CurrTextureHandle = NULL; + } + + D3D_OutputTriangles(); +} +void D3D_ZBufferedCloakedPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr) +{ + extern int CloakingMode; + extern char CloakedPredatorIsMoving; + int uOffset = FastRandom()&255; + int vOffset = FastRandom()&255; + + int flags; + int texoffset; + + D3DTEXTUREHANDLE TextureHandle; + + float ZNear; + float RecipW, RecipH; + + // Get ZNear + ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + + // Take header information + flags = inputPolyPtr->PolyFlags; + + // We assume bit 15 (TxLocal) HAS been + // properly cleared this time... + texoffset = (inputPolyPtr->PolyColour & ClrTxDefn); + + TextureHandle = (D3DTEXTUREHANDLE) + ImageHeaderArray[texoffset].D3DHandle; + // Check for textures that have not loaded + // properly + + if (TextureHandle == (D3DTEXTUREHANDLE) 0) + return; + + + if(ImageHeaderArray[texoffset].ImageWidth==128) + { + RecipW = 1.0 /128.0; + } + else + { + float width = (float) ImageHeaderArray[texoffset].ImageWidth; + RecipW = (1.0 / width); + } + if(ImageHeaderArray[texoffset].ImageHeight==128) + { + RecipH = 1.0 / 128.0; + } + else + { + float height = (float) ImageHeaderArray[texoffset].ImageHeight; + RecipH = (1.0 / height); + } + + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + float oneOverZ; + oneOverZ = (1.0)/vertices->Z; + float zvalue; + + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + } + + vertexPtr->tu = ((float)(vertices->U>>16)+0.5) * RecipW; + vertexPtr->tv = ((float)(vertices->V>>16)+0.5) * RecipH; + + if (CloakedPredatorIsMoving) + { + vertexPtr->color = RGBALIGHT_MAKE(vertices->R,vertices->G,vertices->B,vertices->A); + } + else + { + vertexPtr->color = RGBALIGHT_MAKE(vertices->R,vertices->G,vertices->B,vertices->A); + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL); + + vertexPtr->rhw = oneOverZ; + + { + zvalue = vertices->Z+HeadUpDisplayZOffset; + zvalue = ((zvalue-ZNear)/zvalue); + } + + vertexPtr->sz = zvalue; + +// vertexPtr->specular=RGBALIGHT_MAKE(vertices->SpecularR,vertices->SpecularG,vertices->SpecularB,255); + vertexPtr->specular=RGBALIGHT_MAKE(0,0,0,255); + + vertices++; + NumVertices++; + } + while(--i); + } + + // Insert state change for shading model if required + if (D3DShadingMode != D3DSHADE_GOURAUD) + { + D3DShadingMode = D3DSHADE_GOURAUD; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SHADEMODE, + D3DSHADE_GOURAUD, ExecBufInstPtr); + } + +// Insert state change for texturing perspective value +// Note that drawtx3das2d options have ONLY been allowed for here, +// not when the rhw values are generated. This is a deliberate choice, +// based on the assumption that drawtx3das2d will not be used very often +// and the extra branching at the top of this function will impose a +// greater cost than the (rare) savings in floating pt divisions are worth. +// Or so I claim... + + if (D3DTexturePerspective != Yes) + { + D3DTexturePerspective = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, ExecBufInstPtr); + } + if (TextureHandle != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + /* + if (TextureHandle != NULL) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NULL, ExecBufInstPtr); + CurrTextureHandle = NULL; + } + */ + + D3D_OutputTriangles(); +} +void D3D_CloakedPredatorPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr) +{ + float ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + int texoffset = SpecialFXImageNumber; + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[texoffset].D3DHandle; + float RecipW, RecipH; + + if(ImageHeaderArray[texoffset].ImageWidth==256) + { + RecipW = 1.0 /256.0; + } + else + { + float width = (float) ImageHeaderArray[texoffset].ImageWidth; + RecipW = (1.0 / width); + } + if(ImageHeaderArray[texoffset].ImageHeight==256) + { + RecipH = 1.0 / 256.0; + } + else + { + float height = (float) ImageHeaderArray[texoffset].ImageHeight; + RecipH = (1.0 / height); + } + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + float oneOverZ; + oneOverZ = (1.0)/(vertices->Z); + float zvalue; + + vertexPtr->tu = ((float)vertices->U) * RecipW; + vertexPtr->tv = ((float)vertices->V) * RecipH; + vertexPtr->rhw = oneOverZ; + + { + zvalue = vertices->Z+HeadUpDisplayZOffset; + // zvalue /= 65536.0; + zvalue = 1.0 - ZNear/zvalue; + } + + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + + #if 1 + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + #endif + vertexPtr->sx=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + + #if 1 + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + #endif + vertexPtr->sy=y; + + } + vertexPtr->color = RGBALIGHT_MAKE(255,255,255,32); + vertexPtr->sz = zvalue; + + vertices++; + NumVertices++; + } + while(--i); + } + + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_GLOWING); + + // Insert state change for shading model if required + if (D3DShadingMode != D3DSHADE_GOURAUD) + { + D3DShadingMode = D3DSHADE_GOURAUD; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SHADEMODE, + D3DSHADE_GOURAUD, ExecBufInstPtr); + } + +// Insert state change for texturing perspective value +// Note that drawtx3das2d options have ONLY been allowed for here, +// not when the rhw values are generated. This is a deliberate choice, +// based on the assumption that drawtx3das2d will not be used very often +// and the extra branching at the top of this function will impose a +// greater cost than the (rare) savings in floating pt divisions are worth. +// Or so I claim... + + if (D3DTexturePerspective != Yes) + { + D3DTexturePerspective = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, ExecBufInstPtr); + } + + #if 1 + if (TextureHandle != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + #else + if (CurrTextureHandle != NoiseTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NoiseTextureHandle, ExecBufInstPtr); + CurrTextureHandle = NoiseTextureHandle; + } + #endif + + D3D_OutputTriangles(); +} + +void D3D_ZBufferedTexturedPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr) +{ + int flags; + int texoffset; + int intensity; + + D3DTEXTUREHANDLE TextureHandle; + + float ZNear; + float RecipW, RecipH; + + // Get ZNear + ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + + // Take header information + flags = inputPolyPtr->PolyFlags; + + intensity = (inputPolyPtr->PolyColour >> TxDefn); + intensity >>= TxDefn; + + // We assume bit 15 (TxLocal) HAS been + // properly cleared this time... + texoffset = (inputPolyPtr->PolyColour & ClrTxDefn); + + TextureHandle = (D3DTEXTUREHANDLE) + ImageHeaderArray[texoffset].D3DHandle; + + // Check for textures that have not loaded + // properly + + if (TextureHandle == (D3DTEXTUREHANDLE) 0) + return; + + if(ImageHeaderArray[texoffset].ImageWidth==128) + { + RecipW = 1.0 /128.0; + } + else + { + float width = (float) ImageHeaderArray[texoffset].ImageWidth; + RecipW = (1.0 / width); + } + if(ImageHeaderArray[texoffset].ImageHeight==128) + { + RecipH = 1.0 / 128.0; + } + else + { + float height = (float) ImageHeaderArray[texoffset].ImageHeight; + RecipH = (1.0 / height); + } + + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + float oneOverZ; + oneOverZ = (1.0)/vertices->Z; + float zvalue; + + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + } + vertexPtr->tu = ((float)(vertices->U>>16)+0.5) * RecipW; + vertexPtr->tv = ((float)(vertices->V>>16)+0.5) * RecipH; + vertexPtr->rhw = oneOverZ; + + { + zvalue = vertices->Z+HeadUpDisplayZOffset; + zvalue = ((zvalue-ZNear)/zvalue); + } + + // Different behaviour for different driver modes + switch (D3DDriverMode) + { + case D3DSoftwareRGBDriver: + { + if (flags & iflag_nolight) + { + vertexPtr->color = DefaultColour; + } + else + { + int i1shift = intensity; + vertexPtr->color = RGBLIGHT_MAKE(i1shift, i1shift,i1shift); + } + break; + } + + case D3DSoftwareRampDriver: + { + // Blue component only valid for ramp driver + if (flags & iflag_nolight) + { + vertexPtr->color = RGB_MAKE(0,0,DefaultVertexIntensity); + } + else + { + vertexPtr->color = RGB_MAKE(0,0,intensity); + } + + break; + } + + case D3DHardwareRGBDriver: + { + if (flags & iflag_transparent) + { + if (flags & iflag_nolight) + { + vertexPtr->color = DefaultAlphaColour; + } + else + { + vertexPtr->color = RGBALIGHT_MAKE(intensity,intensity,intensity, TransparentAlphaValue); + } + } + else + { + if (flags & iflag_nolight) + { + vertexPtr->color = DefaultColour; + } + else + { + vertexPtr->color = RGBLIGHT_MAKE(intensity,intensity,intensity); + } + } + break; + } + + + default: + { + vertexPtr->color = 0; + break; + } + } + vertexPtr->sz = zvalue; + vertexPtr->specular=RGBALIGHT_MAKE(0,0,0,255); + vertices++; + NumVertices++; + } + while(--i); + } + + if (flags & iflag_transparent) + { + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL); + } + else + { + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_OFF); + } + + // Insert state change for shading model if required + if (D3DShadingMode != D3DSHADE_GOURAUD) + { + D3DShadingMode = D3DSHADE_GOURAUD; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SHADEMODE, + D3DSHADE_GOURAUD, ExecBufInstPtr); + } + +// Insert state change for texturing perspective value +// Note that drawtx3das2d options have ONLY been allowed for here, +// not when the rhw values are generated. This is a deliberate choice, +// based on the assumption that drawtx3das2d will not be used very often +// and the extra branching at the top of this function will impose a +// greater cost than the (rare) savings in floating pt divisions are worth. +// Or so I claim... + + if ((flags & iflag_drawtx3das2d) || + (Global_VDB_Ptr->VDB_Flags & ViewDB_Flag_drawtx3das2d)) + { + if (D3DTexturePerspective != No) + { + D3DTexturePerspective = No; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREPERSPECTIVE, + FALSE, ExecBufInstPtr); + } + } + else + { + if (D3DTexturePerspective != Yes) + { + D3DTexturePerspective = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREPERSPECTIVE, + TRUE, ExecBufInstPtr); + } + } + + if (TextureHandle != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + D3D_OutputTriangles(); +} +#define OUTPUT_TRIANGLE(a,b,c,n) \ +((LPD3DTRIANGLE)ExecBufInstPtr)->v1 = (NumVertices+(a)-(n)); \ +((LPD3DTRIANGLE)ExecBufInstPtr)->v2 = (NumVertices+(b)-(n)); \ +((LPD3DTRIANGLE)ExecBufInstPtr)->v3 = (NumVertices+(c)-(n)); \ +((LPD3DTRIANGLE)ExecBufInstPtr)->wFlags = D3DTRIFLAG_EDGEENABLETRIANGLE; \ +ExecBufInstPtr = ((char*)ExecBufInstPtr) + sizeof(D3DTRIANGLE); \ +NumberOfRenderedTriangles++; + +static void D3D_OutputTriangles(void) +{ + #if 0 + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NULL, ExecBufInstPtr); + #endif + + #if 0 + /* KJL 18:17:54 24/02/98 - doesn't seem to make any difference! */ + if (QWORD_ALIGNED(ExecBufInstPtr)) + { + OP_NOP(ExecBufInstPtr); + } + #endif + + switch(RenderPolygon.NumberOfVertices) + { + default: + case 3: + { + OP_TRIANGLE_LIST(1, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,2,1, 3); + break; + } + case 4: + { + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,2, 4); + OUTPUT_TRIANGLE(0,2,3, 4); + break; + } + case 5: + { + OP_TRIANGLE_LIST(3, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,4, 5); + OUTPUT_TRIANGLE(1,3,4, 5); + OUTPUT_TRIANGLE(1,2,3, 5); + break; + } + case 6: + { + OP_TRIANGLE_LIST(4, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,4,5, 6); + OUTPUT_TRIANGLE(0,3,4, 6); + OUTPUT_TRIANGLE(0,2,3, 6); + OUTPUT_TRIANGLE(0,1,2, 6); + break; + } + case 7: + { + OP_TRIANGLE_LIST(5, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,5,6, 7); + OUTPUT_TRIANGLE(0,4,5, 7); + OUTPUT_TRIANGLE(0,3,4, 7); + OUTPUT_TRIANGLE(0,2,3, 7); + OUTPUT_TRIANGLE(0,1,2, 7); + break; + } + case 8: + { + OP_TRIANGLE_LIST(6, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,6,7, 8); + OUTPUT_TRIANGLE(0,5,6, 8); + OUTPUT_TRIANGLE(0,4,5, 8); + OUTPUT_TRIANGLE(0,3,4, 8); + OUTPUT_TRIANGLE(0,2,3, 8); + OUTPUT_TRIANGLE(0,1,2, 8); + break; + } + + + } + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } +} + +void D3D_HUD_Setup(void) +{ + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_GLOWING); + + // turn off perspective drawing + if (D3DTexturePerspective != No) + { + D3DTexturePerspective = No; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREPERSPECTIVE, FALSE, ExecBufInstPtr); + } + +/* + OP_STATE_RENDER(2, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_NEAREST, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_NEAREST, ExecBufInstPtr); + OP_STATE_RENDER(2, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREMAG, DefaultD3DTextureFilterMax, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREMIN, DefaultD3DTextureFilterMin, ExecBufInstPtr); +*/ + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL, ExecBufInstPtr); + +} + + +void D3D_HUDQuad_Output(int imageNumber,struct VertexTag *quadVerticesPtr, unsigned int colour) +{ + float RecipW, RecipH; + + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[imageNumber].D3DHandle; + + // Check for textures that have not loaded properly + LOCALASSERT(TextureHandle != (D3DTEXTUREHANDLE) 0); + + if(ImageHeaderArray[imageNumber].ImageWidth==128) + { + RecipW = 1.0f / 128.0f; + } + else + { + float width = (float) ImageHeaderArray[imageNumber].ImageWidth - 0.0f; + RecipW = (1.0f / width); + } + if(ImageHeaderArray[imageNumber].ImageHeight==128) + { + RecipH = 1.0f / 128.0f; + } + else + { + float height = (float) ImageHeaderArray[imageNumber].ImageHeight - 0.0f; + RecipH = (1.0f / height); + } + + + /* OUTPUT quadVerticesPtr TO EXECUTE BUFFER */ + { + int i = 4; + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + +// textprint("x %d, y %d, u %d, v %d\n",quadVerticesPtr->X,quadVerticesPtr->Y,quadVerticesPtr->U,quadVerticesPtr->V); + vertexPtr->sx=quadVerticesPtr->X; + vertexPtr->sy=quadVerticesPtr->Y; + vertexPtr->tu = ((float)(quadVerticesPtr->U)) * RecipW; + vertexPtr->tv = ((float)(quadVerticesPtr->V)) * RecipH; + vertexPtr->rhw = 1.0f; + vertexPtr->color = colour; + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + + quadVerticesPtr++; + NumVertices++; + } + while(--i); + } + + // set correct texture handle + if (TextureHandle != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_GLOWING); + + + /* output triangles to execute buffer */ + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + + /* check to see if buffer is getting full */ + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } +} + + +void D3D_DrawRebellionLogo(unsigned int alpha) +{ + extern int RebellionLogoImageNumber; + extern int FoxLogoImageNumber; + float scale = ScreenDescriptorBlock.SDB_Width/640.0f; + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[FoxLogoImageNumber].D3DHandle; + int colour = 0xffffff+((alpha>>8)<<24); + // Check for textures that have not loaded properly + LOCALASSERT(TextureHandle != (D3DTEXTUREHANDLE) 0); + + /* OUTPUT quadVerticesPtr TO EXECUTE BUFFER */ + { + float x[] = {0.0f,1.0f,1.0f,0.0f}; + float y[] = {0.0f,0.0f,1.0f,1.0f}; + int i; + for (i=0; i<4; i++) + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + vertexPtr->sx = (x[i]*63.0f+64.0f)*scale; + vertexPtr->sy = (y[i]*63.0f+4.0f)*scale; + vertexPtr->sz = 0.0f; + vertexPtr->tu = x[i]; + vertexPtr->tv = y[i]; + vertexPtr->rhw = 1.0; + vertexPtr->color = colour; + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + + NumVertices++; + } + } + // set correct texture handle + if (TextureHandle != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL); + + + /* output triangles to execute buffer */ + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + + /* check to see if buffer is getting full */ + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + + TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[RebellionLogoImageNumber].D3DHandle; + + { + float x[] = {0.0f,1.0f,1.0f,0.0f}; + float y[] = {0.0f,0.0f,1.0f,1.0f}; + int i; + for (i=0; i<4; i++) + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + vertexPtr->sx = (x[i]*127.0f+4.0f+130.0f)*scale; + vertexPtr->sy = (y[i]*63.0f+4.0f)*scale; + vertexPtr->sz = 0.0f; + vertexPtr->tu = x[i]; + vertexPtr->tv = y[i]; + vertexPtr->rhw = 1.0; + vertexPtr->color = colour; + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + + NumVertices++; + } + } + + // set correct texture handle + if (TextureHandle != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL); + + + /* output triangles to execute buffer */ + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + + /* check to see if buffer is getting full */ + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } +} + + +void D3D_DrawParticle_Rain(PARTICLE *particlePtr,VECTORCH *prevPositionPtr) +{ + VECTORCH vertices[3]; + vertices[0] = *prevPositionPtr; + + /* translate second vertex into view space */ + TranslatePointIntoViewspace(&vertices[0]); + + /* is particle within normal view frustrum ? */ + if((-vertices[0].vx <= vertices[0].vz) + &&(vertices[0].vx <= vertices[0].vz) + &&(-vertices[0].vy <= vertices[0].vz) + &&(vertices[0].vy <= vertices[0].vz)) + { + + vertices[1] = particlePtr->Position; + vertices[2] = particlePtr->Position; + vertices[1].vx += particlePtr->Offset.vx; + vertices[2].vx -= particlePtr->Offset.vx; + vertices[1].vz += particlePtr->Offset.vz; + vertices[2].vz -= particlePtr->Offset.vz; + + /* translate particle into view space */ + TranslatePointIntoViewspace(&vertices[1]); + TranslatePointIntoViewspace(&vertices[2]); + + float ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + int i = 3; + VECTORCH *verticesPtr = vertices; + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + int x = (verticesPtr->vx*(Global_VDB_Ptr->VDB_ProjX))/verticesPtr->vz+Global_VDB_Ptr->VDB_CentreX; + int y = (verticesPtr->vy*(Global_VDB_Ptr->VDB_ProjY))/verticesPtr->vz+Global_VDB_Ptr->VDB_CentreY; + { + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + } + + float oneOverZ = ((float)verticesPtr->vz-ZNear)/(float)verticesPtr->vz; + + if (i==3) vertexPtr->color = RGBALIGHT_MAKE(0,255,255,32); + else vertexPtr->color = RGBALIGHT_MAKE(255,255,255,32); + + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + vertexPtr->sz = oneOverZ; + NumVertices++; + verticesPtr++; + } + while(--i); + } + if (CurrTextureHandle != NULL) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NULL, ExecBufInstPtr); + CurrTextureHandle = NULL; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL); + + + OP_TRIANGLE_LIST(1, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,2,1, 3); + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + } + +} + +void D3D_DrawParticle_Smoke(PARTICLE *particlePtr) +{ + VECTORCH vertices[3]; + vertices[0] = particlePtr->Position; + + /* translate second vertex into view space */ + TranslatePointIntoViewspace(&vertices[0]); + + /* is particle within normal view frustrum ? */ + int inView = 0; + + if(AvP.PlayerType == I_Alien) + { + if((-vertices[0].vx <= vertices[0].vz*2) + &&(vertices[0].vx <= vertices[0].vz*2) + &&(-vertices[0].vy <= vertices[0].vz*2) + &&(vertices[0].vy <= vertices[0].vz*2)) + { + inView = 1; + } + } + else + { + if((-vertices[0].vx <= vertices[0].vz) + &&(vertices[0].vx <= vertices[0].vz) + &&(-vertices[0].vy <= vertices[0].vz) + &&(vertices[0].vy <= vertices[0].vz)) + { + inView = 1; + } + } + + if (inView) + { + + vertices[1] = particlePtr->Position; + vertices[2] = particlePtr->Position; + vertices[1].vx += ((FastRandom()&15)-8)*2; + vertices[1].vy += ((FastRandom()&15)-8)*2; + vertices[1].vz += ((FastRandom()&15)-8)*2; + vertices[2].vx += ((FastRandom()&15)-8)*2; + vertices[2].vy += ((FastRandom()&15)-8)*2; + vertices[2].vz += ((FastRandom()&15)-8)*2; + + /* translate particle into view space */ + TranslatePointIntoViewspace(&vertices[1]); + TranslatePointIntoViewspace(&vertices[2]); + + float ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + int i = 3; + VECTORCH *verticesPtr = vertices; + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + int x = (verticesPtr->vx*(Global_VDB_Ptr->VDB_ProjX))/verticesPtr->vz+Global_VDB_Ptr->VDB_CentreX; + int y = (verticesPtr->vy*(Global_VDB_Ptr->VDB_ProjY))/verticesPtr->vz+Global_VDB_Ptr->VDB_CentreY; + { + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + } + + float zvalue = (vertices->vz)+HeadUpDisplayZOffset; + zvalue = ((zvalue-ZNear)/zvalue); + + // Different behaviour for different driver modes + switch (D3DDriverMode) + { + default: + case D3DSoftwareRGBDriver: + case D3DSoftwareRampDriver: + break; + case D3DHardwareRGBDriver: + { + vertexPtr->color = RGBALIGHT_MAKE((particlePtr->LifeTime>>8),(particlePtr->LifeTime>>8),0,(particlePtr->LifeTime>>7)+64); + break; + } + } + vertexPtr->sz = zvalue; + NumVertices++; + verticesPtr++; + } + while(--i); + } + OP_TRIANGLE_LIST(1, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,2,1, 3); + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + } + +} + + +void D3D_DecalSystem_Setup(void) +{ +#if 1 + OP_STATE_RENDER(1, ExecBufInstPtr); +// STATE_DATA(D3DRENDERSTATE_DITHERENABLE, FALSE, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZWRITEENABLE, FALSE, ExecBufInstPtr); +#endif +} +void D3D_DecalSystem_End(void) +{ +#if 1 + OP_STATE_RENDER(1, ExecBufInstPtr); +// STATE_DATA(D3DRENDERSTATE_DITHERENABLE, TRUE, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZWRITEENABLE, TRUE, ExecBufInstPtr); +#endif +} + +void D3D_Decal_Output(DECAL *decalPtr,RENDERVERTEX *renderVerticesPtr) +{ + DECAL_DESC *decalDescPtr = &DecalDescription[decalPtr->DecalID]; + + int texoffset; + D3DTEXTUREHANDLE TextureHandle; + + float ZNear; + float RecipW, RecipH; + int colour; + int specular=RGBALIGHT_MAKE(0,0,0,0);//255); + + // Get ZNear + ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + if (decalPtr->DecalID == DECAL_FMV) + { + #if !FMV_ON + return; + #endif + TextureHandle=FMVTextureHandle[decalPtr->Centre.vx]; + RecipW = 1.0 /128.0; + RecipH = 1.0 /128.0; + if (TextureHandle != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + } + else if (decalPtr->DecalID == DECAL_SHAFTOFLIGHT||decalPtr->DecalID == DECAL_SHAFTOFLIGHT_OUTER) + { + if (NULL != CurrTextureHandle) + { + CurrTextureHandle = NULL; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NULL, ExecBufInstPtr); + } + } + else + { + texoffset = SpecialFXImageNumber; + TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[texoffset].D3DHandle; + + // Check for textures that have not loaded + // properly + + if (TextureHandle == (D3DTEXTUREHANDLE) 0) + return; + + if(ImageHeaderArray[texoffset].ImageWidth==256) + { + RecipW = 1.0 /256.0; + } + else + { + float width = (float) ImageHeaderArray[texoffset].ImageWidth; + RecipW = (1.0 / width); + } + if(ImageHeaderArray[texoffset].ImageHeight==256) + { + RecipH = 1.0 / 256.0; + } + else + { + float height = (float) ImageHeaderArray[texoffset].ImageHeight; + RecipH = (1.0 / height); + } + if (TextureHandle != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + } + + if (decalDescPtr->IsLit) + { + int intensity = LightIntensityAtPoint(decalPtr->Vertices); + colour = RGBALIGHT_MAKE + ( + MUL_FIXED(intensity,decalDescPtr->RedScale[CurrentVisionMode]), + MUL_FIXED(intensity,decalDescPtr->GreenScale[CurrentVisionMode]), + MUL_FIXED(intensity,decalDescPtr->BlueScale[CurrentVisionMode]), + decalDescPtr->Alpha + ); + } + else + { + colour = RGBALIGHT_MAKE + ( + decalDescPtr->RedScale[CurrentVisionMode], + decalDescPtr->GreenScale[CurrentVisionMode], + decalDescPtr->BlueScale[CurrentVisionMode], + decalDescPtr->Alpha + ); + } + + if (RAINBOWBLOOD_CHEATMODE) + { + colour = RGBALIGHT_MAKE + ( + FastRandom()&255, + FastRandom()&255, + FastRandom()&255, + decalDescPtr->Alpha + ); + } + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + float oneOverZ; + oneOverZ = (1.0)/vertices->Z; + float zvalue; + + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + + } + vertexPtr->tu = ((float)(vertices->U>>16)+.5) * RecipW; + vertexPtr->tv = ((float)(vertices->V>>16)+.5) * RecipH; + vertexPtr->rhw = oneOverZ; + + { + zvalue = (vertices->Z)+HeadUpDisplayZOffset-50; + zvalue = ((zvalue-ZNear)/zvalue); + } + + vertexPtr->color = colour; + + vertexPtr->sz = zvalue; + + vertexPtr->specular= specular;//RGBALIGHT_MAKE(vertices->SpecularR,vertices->SpecularG,vertices->SpecularB,fog); + + + vertices++; + NumVertices++; + } + while(--i); + } + + /* Check translucency mode */ + CheckTranslucencyModeIsCorrect(decalDescPtr->TranslucencyType); + + + if (D3DTexturePerspective != Yes) + { + D3DTexturePerspective = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, ExecBufInstPtr); + } + + + + D3D_OutputTriangles(); +} +void D3D_Particle_Output(PARTICLE *particlePtr,RENDERVERTEX *renderVerticesPtr) +{ + #if 1 + PARTICLE_DESC *particleDescPtr = &ParticleDescription[particlePtr->ParticleID]; + + int texoffset = SpecialFXImageNumber; + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[texoffset].D3DHandle; + float RecipW, RecipH; + + + // Check for textures that have not loaded + // properly + + if (TextureHandle == (D3DTEXTUREHANDLE) 0) + return; + + if(ImageHeaderArray[texoffset].ImageWidth==256) + { + RecipW = 1.0 /256.0; + } + else + { + float width = (float) ImageHeaderArray[texoffset].ImageWidth; + RecipW = (1.0 / width); + } + if(ImageHeaderArray[texoffset].ImageHeight==256) + { + RecipH = 1.0 / 256.0; + } + else + { + float height = (float) ImageHeaderArray[texoffset].ImageHeight; + RecipH = (1.0 / height); + } + + int colour; + + if (particleDescPtr->IsLit && !(particlePtr->ParticleID==PARTICLE_ALIEN_BLOOD && CurrentVisionMode==VISION_MODE_PRED_SEEALIENS) ) + { + int intensity = LightIntensityAtPoint(&particlePtr->Position); + if (particlePtr->ParticleID==PARTICLE_SMOKECLOUD || particlePtr->ParticleID==PARTICLE_ANDROID_BLOOD) + { + colour = RGBALIGHT_MAKE + ( + MUL_FIXED(intensity,particlePtr->ColourComponents.Red), + MUL_FIXED(intensity,particlePtr->ColourComponents.Green), + MUL_FIXED(intensity,particlePtr->ColourComponents.Blue), + particlePtr->ColourComponents.Alpha + ); + + } + else + { + colour = RGBALIGHT_MAKE + ( + MUL_FIXED(intensity,particleDescPtr->RedScale[CurrentVisionMode]), + MUL_FIXED(intensity,particleDescPtr->GreenScale[CurrentVisionMode]), + MUL_FIXED(intensity,particleDescPtr->BlueScale[CurrentVisionMode]), + particleDescPtr->Alpha + ); + } + } + else + { + colour = particlePtr->Colour; + } + if (RAINBOWBLOOD_CHEATMODE) + { + colour = RGBALIGHT_MAKE + ( + FastRandom()&255, + FastRandom()&255, + FastRandom()&255, + particleDescPtr->Alpha + ); + } + + + { + float ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + float oneOverZ = (1.0)/vertices->Z; + float zvalue; + + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + + } + vertexPtr->tu = ((float)(vertices->U>>16)+.5) * RecipW; + vertexPtr->tv = ((float)(vertices->V>>16)+.5) * RecipH; + vertexPtr->rhw = oneOverZ; + if (particleDescPtr->IsDrawnInFront) + { + zvalue = 0.0f; + } + else if (particleDescPtr->IsDrawnAtBack) + { + zvalue = 1.0f; + } + else + { + zvalue = 1.0f - ZNear*oneOverZ; + } + + vertexPtr->color = colour; + vertexPtr->sz = zvalue; + vertexPtr->specular=RGBALIGHT_MAKE(0,0,0,255);//RGBALIGHT_MAKE(vertices->SpecularR,vertices->SpecularG,vertices->SpecularB,fog); + + NumVertices++; + vertices++; + } + while(--i); + } + + // set correct texture handle + if (TextureHandle != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + + CheckTranslucencyModeIsCorrect(particleDescPtr->TranslucencyType); + + if (D3DTexturePerspective != Yes) + { + D3DTexturePerspective = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, ExecBufInstPtr); + } + + + + D3D_OutputTriangles(); + + } + #endif +} +void D3D_FMVParticle_Output(RENDERVERTEX *renderVerticesPtr) +{ + D3DTEXTUREHANDLE TextureHandle = FMVTextureHandle[0]; + float RecipW, RecipH; + + RecipW = 1.0 /128.0; + RecipH = 1.0 /128.0; + + int colour = FMVParticleColour&0xffffff; + + { + float ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + float oneOverZ = (1.0)/vertices->Z; + float zvalue; + + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + + } + vertexPtr->tu = ((float)(vertices->U>>16)) * RecipW; + vertexPtr->tv = ((float)(vertices->V>>16)) * RecipH; + vertexPtr->rhw = oneOverZ; + zvalue = 1.0 - ZNear*oneOverZ; + +// vertexPtr->color = colour; + vertexPtr->color = (colour)+(vertices->A<<24); + vertexPtr->sz = zvalue; + vertexPtr->specular=RGBALIGHT_MAKE(0,0,0,255);//RGBALIGHT_MAKE(vertices->SpecularR,vertices->SpecularG,vertices->SpecularB,fog); + + NumVertices++; + vertices++; + } + while(--i); + } + + // set correct texture handle + if (TextureHandle != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL); + + if (D3DTexturePerspective != Yes) + { + D3DTexturePerspective = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, ExecBufInstPtr); + } + + + + D3D_OutputTriangles(); + + } +} + + +extern int CloakingPhase; +extern int sine[]; +extern int cosine[]; +extern int NumActiveBlocks; +extern DISPLAYBLOCK *ActiveBlockList[]; +extern int GlobalAmbience; +extern unsigned char *ScreenBuffer; +extern long BackBufferPitch; + +unsigned short FlameFunction(int x, int y); +void InitRandomArrays(void); +int Turbulence(int x, int y, int t); + +void UpdateForceField(void); +void D3D_DrawForceField(int xOrigin, int yOrigin, int zOrigin, int fieldType); + +void UpdateWaterFall(void); +void D3D_DrawWaterFall(int xOrigin, int yOrigin, int zOrigin); +void D3D_DrawPowerFence(int xOrigin, int yOrigin, int zOrigin, int xScale, int yScale, int zScale); +void D3D_DrawExplosion(int xOrigin, int yOrigin, int zOrigin, int size); + +void D3D_DrawWaterPatch(int xOrigin, int yOrigin, int zOrigin); + +void D3D_DrawWaterOctagonPatch(int xOrigin, int yOrigin, int zOrigin, int xOffset, int zOffset); + +int LightSourceWaterPoint(VECTORCH *pointPtr,int offset); +void D3D_DrawWaterMesh_Unclipped(void); +void D3D_DrawWaterMesh_Clipped(void); + + +void D3D_DrawMoltenMetal(int xOrigin, int yOrigin, int zOrigin); +void D3D_DrawMoltenMetalMesh_Unclipped(void); +void D3D_DrawMoltenMetalMesh_Clipped(void); + + +//#define WATER_POLY_SCALE 256 +int MeshXScale; +int MeshZScale; +int WaterFallBase; +void PostLandscapeRendering(void) +{ + extern int NumOnScreenBlocks; + extern DISPLAYBLOCK *OnScreenBlockList[]; + int numOfObjects = NumOnScreenBlocks; + + extern char LevelName[]; + + CurrentRenderStates.FogIsOn = 1; + + if (!strcmp(LevelName,"fall")||!strcmp(LevelName,"fall_m")) + { + char drawWaterFall = 0; + char drawStream = 0; + + while(numOfObjects) + { + DISPLAYBLOCK *objectPtr = OnScreenBlockList[--numOfObjects]; + MODULE *modulePtr = objectPtr->ObMyModule; + + /* if it's a module, which isn't inside another module */ + if (modulePtr && modulePtr->name) + { + if( (!strcmp(modulePtr->name,"fall01")) + ||(!strcmp(modulePtr->name,"well01")) + ||(!strcmp(modulePtr->name,"well02")) + ||(!strcmp(modulePtr->name,"well03")) + ||(!strcmp(modulePtr->name,"well04")) + ||(!strcmp(modulePtr->name,"well05")) + ||(!strcmp(modulePtr->name,"well06")) + ||(!strcmp(modulePtr->name,"well07")) + ||(!strcmp(modulePtr->name,"well08")) + ||(!strcmp(modulePtr->name,"well"))) + { + drawWaterFall = 1; + } + else if( (!strcmp(modulePtr->name,"stream02")) + ||(!strcmp(modulePtr->name,"stream03")) + ||(!strcmp(modulePtr->name,"watergate"))) + { + drawStream = 1; + } + } + } + + if (drawWaterFall) + { + // Turn OFF texturing if it is on... + if (CurrTextureHandle != NULL) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NULL, ExecBufInstPtr); + CurrTextureHandle = NULL; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL); + if (NumVertices) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + OP_STATE_RENDER(1, ExecBufInstPtr); + //STATE_DATA(D3DRENDERSTATE_ZFUNC, D3DCMP_ALWAYS, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZWRITEENABLE, FALSE, ExecBufInstPtr); + + //UpdateWaterFall(); + WaterFallBase = 109952; + + MeshZScale = (66572-51026)/15; + MeshXScale = (109952+3039)/45; + + D3D_DrawWaterFall(175545,-3039,51026); +// MeshZScale = -(538490-392169); +// MeshXScale = 55000; + // D3D_DrawWaterPatch(-100000, WaterFallBase, 538490); + + OP_STATE_RENDER(1, ExecBufInstPtr); + //STATE_DATA(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZWRITEENABLE, TRUE, ExecBufInstPtr); + } + if (drawStream) + { + int x = 68581; + int y = 12925; + int z = 93696; + MeshXScale = (87869-68581); + MeshZScale = (105385-93696); + { + extern void CheckForObjectsInWater(int minX, int maxX, int minZ, int maxZ, int averageY); + CheckForObjectsInWater(x, x+MeshXScale, z, z+MeshZScale, y); + } + + WaterXOrigin=x; + WaterZOrigin=z; + WaterUScale = 4.0f/(float)MeshXScale; + WaterVScale = 4.0f/(float)MeshZScale; + MeshXScale/=4; + MeshZScale/=2; + + // Turn OFF texturing if it is on... + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[ChromeImageNumber].D3DHandle; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL); + if (NumVertices) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + D3D_DrawWaterPatch(x, y, z); + D3D_DrawWaterPatch(x+MeshXScale, y, z); + D3D_DrawWaterPatch(x+MeshXScale*2, y, z); + D3D_DrawWaterPatch(x+MeshXScale*3, y, z); + D3D_DrawWaterPatch(x, y, z+MeshZScale); + D3D_DrawWaterPatch(x+MeshXScale, y, z+MeshZScale); + D3D_DrawWaterPatch(x+MeshXScale*2, y, z+MeshZScale); + D3D_DrawWaterPatch(x+MeshXScale*3, y, z+MeshZScale); + } + } + #if 0 + else if ( (!__stricmp(LevelName,"e3demo")) || (!__stricmp(LevelName,"e3demosp")) ) + { + int drawOctagonPool = -1; + int drawFMV = -1; + int drawPredatorFMV = -1; + int drawSwirlyFMV = -1; + int drawSwirlyFMV2 = -1; + int drawSwirlyFMV3 = -1; + while(numOfObjects) + { + DISPLAYBLOCK *objectPtr = OnScreenBlockList[--numOfObjects]; + MODULE *modulePtr = objectPtr->ObMyModule; + + /* if it's a module, which isn't inside another module */ + if (modulePtr && modulePtr->name) + { + if(!__stricmp(modulePtr->name,"water1")) + { + drawOctagonPool = modulePtr->m_index; + } + else if(!__stricmp(modulePtr->name,"marine01b")) + { + drawFMV = modulePtr->m_index; + } + else if(!_stricmp(modulePtr->name,"predator01")) + { + drawPredatorFMV = modulePtr->m_index; + } + else if(!_stricmp(modulePtr->name,"toptopgr01")) + { + drawSwirlyFMV = modulePtr->m_index; + } + else if(!_stricmp(modulePtr->name,"grille04")) + { + drawSwirlyFMV2 = modulePtr->m_index; + } + #if 0 + else if(!_stricmp(modulePtr->name,"marine05")) + { + drawSwirlyFMV3 = modulePtr->m_index; + } + #endif + } + } + #if FMV_ON +// UpdateFMVTextures(3); + + + if (drawFMV!=-1) + { + DECAL fmvDecal = + { + DECAL_FMV, + }; + fmvDecal.ModuleIndex = drawFMV; + fmvDecal.UOffset = 0; + + UpdateFMVTextures(4); + + for (int z=0; z<6; z++) + { + for (int y=0; y<3; y++) + { + fmvDecal.Vertices[0].vx = -149; + fmvDecal.Vertices[1].vx = -149; + fmvDecal.Vertices[2].vx = -149; + fmvDecal.Vertices[3].vx = -149; + + fmvDecal.Vertices[0].vy = -3254+y*744; + fmvDecal.Vertices[1].vy = -3254+y*744; + fmvDecal.Vertices[2].vy = -3254+y*744+744; + fmvDecal.Vertices[3].vy = -3254+y*744+744; + + fmvDecal.Vertices[0].vz = 49440+z*993; + fmvDecal.Vertices[1].vz = 49440+z*993+993; + fmvDecal.Vertices[2].vz = 49440+z*993+993; + fmvDecal.Vertices[3].vz = 49440+z*993; + fmvDecal.Centre.vx = ((z+y)%3)+1; + RenderDecal(&fmvDecal); + } + } + } + if (drawPredatorFMV!=-1) + { + DECAL fmvDecal = + { + DECAL_FMV, + }; + fmvDecal.ModuleIndex = drawPredatorFMV; + fmvDecal.UOffset = 0; + + UpdateFMVTextures(4); + + for (int z=0; z<12; z++) + { + for (int y=0; y<7; y++) + { + fmvDecal.Vertices[0].vx = -7164; + fmvDecal.Vertices[1].vx = -7164; + fmvDecal.Vertices[2].vx = -7164; + fmvDecal.Vertices[3].vx = -7164; + + fmvDecal.Vertices[0].vy = -20360+y*362; + fmvDecal.Vertices[1].vy = -20360+y*362; + fmvDecal.Vertices[2].vy = -20360+y*362+362; + fmvDecal.Vertices[3].vy = -20360+y*362+362; + + fmvDecal.Vertices[0].vz = 1271+z*483+483; + fmvDecal.Vertices[1].vz = 1271+z*483; + fmvDecal.Vertices[2].vz = 1271+z*483; + fmvDecal.Vertices[3].vz = 1271+z*483+483; + fmvDecal.Centre.vx = (z+y)%3; + RenderDecal(&fmvDecal); + } + } + } + + #endif + + if (drawSwirlyFMV!=-1) + { + UpdateFMVTextures(1); + D3D_DrawSwirlyFMV(30000,-12500,0); + } + if (drawSwirlyFMV2!=-1) + { + UpdateFMVTextures(1); + D3D_DrawSwirlyFMV(2605,-6267-2000,17394-3200); + } + + if (drawSwirlyFMV3!=-1) + { +// UpdateFMVTextures(1); + D3D_DrawSwirlyFMV(5117,3456-3000,52710-2000); + } + if (drawOctagonPool!=-1) + { + #if FMV_ON + UpdateFMVTextures(1); + + MeshXScale = (3000); + MeshZScale = (4000); + D3D_DrawFMVOnWater(-1000,3400,22000); + { + DECAL fmvDecal = + { + DECAL_FMV, + { + {0,-2500,29000}, + {2000,-2500,29000}, + {2000,-2500+750*2,29000}, + {0,-2500+750*2,29000} + }, + 0 + }; + fmvDecal.ModuleIndex = drawOctagonPool; + fmvDecal.Centre.vx = 0; + fmvDecal.UOffset = 0; + + RenderDecal(&fmvDecal); + } + #endif + + int highDetailRequired = 1; + int x = 1023; + int y = 3400; + int z = 27536; + + { + int dx = Player->ObWorld.vx - x; + if (dx< -8000 || dx > 8000) + { + highDetailRequired = 0; + } + else + { + int dz = Player->ObWorld.vz - z; + if (dz< -8000 || dz > 8000) + { + highDetailRequired = 0; + } + } + } + MeshXScale = 7700; + MeshZScale = 7700; + { + extern void CheckForObjectsInWater(int minX, int maxX, int minZ, int maxZ, int averageY); + CheckForObjectsInWater(x-MeshXScale, x+MeshXScale, z-MeshZScale, z+MeshZScale, y); + } + + MeshXScale /=15; + MeshZScale /=15; + + // Turn OFF texturing if it is on... + D3DTEXTUREHANDLE TextureHandle = NULL; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL); + if (NumVertices) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + if (highDetailRequired) + { + MeshXScale /= 2; + MeshZScale /= 2; + D3D_DrawWaterOctagonPatch(x,y,z,0,0); + D3D_DrawWaterOctagonPatch(x,y,z,15,0); + D3D_DrawWaterOctagonPatch(x,y,z,0,15); + D3D_DrawWaterOctagonPatch(x,y,z,15,15); + MeshXScale = -MeshXScale; + D3D_DrawWaterOctagonPatch(x,y,z,0,0); + D3D_DrawWaterOctagonPatch(x,y,z,15,0); + D3D_DrawWaterOctagonPatch(x,y,z,0,15); + D3D_DrawWaterOctagonPatch(x,y,z,15,15); + MeshZScale = -MeshZScale; + D3D_DrawWaterOctagonPatch(x,y,z,0,0); + D3D_DrawWaterOctagonPatch(x,y,z,15,0); + D3D_DrawWaterOctagonPatch(x,y,z,0,15); + D3D_DrawWaterOctagonPatch(x,y,z,15,15); + MeshXScale = -MeshXScale; + D3D_DrawWaterOctagonPatch(x,y,z,0,0); + D3D_DrawWaterOctagonPatch(x,y,z,15,0); + D3D_DrawWaterOctagonPatch(x,y,z,0,15); + D3D_DrawWaterOctagonPatch(x,y,z,15,15); + } + else + { + D3D_DrawWaterOctagonPatch(x,y,z,0,0); + MeshXScale = -MeshXScale; + D3D_DrawWaterOctagonPatch(x,y,z,0,0); + MeshZScale = -MeshZScale; + D3D_DrawWaterOctagonPatch(x,y,z,0,0); + MeshXScale = -MeshXScale; + D3D_DrawWaterOctagonPatch(x,y,z,0,0); + } + + } + } + #endif + else if (!_stricmp(LevelName,"hangar")) + { + #if FMV_ON + #if WIBBLY_FMV_ON + UpdateFMVTextures(1); + D3D_DrawFMV(FmvPosition.vx,FmvPosition.vy,FmvPosition.vz); + #endif + #endif + #if 0 + { + VECTORCH v = {49937,-4000,-37709}; // hangar + D3D_DrawCable(&v); + } + #endif + } + else if (!_stricmp(LevelName,"invasion_a")) + { + char drawWater = 0; + char drawEndWater = 0; + + while(numOfObjects) + { + DISPLAYBLOCK *objectPtr = OnScreenBlockList[--numOfObjects]; + MODULE *modulePtr = objectPtr->ObMyModule; + + /* if it's a module, which isn't inside another module */ + if (modulePtr && modulePtr->name) + { + if( (!strcmp(modulePtr->name,"hivepool")) + ||(!strcmp(modulePtr->name,"hivepool04"))) + { + drawWater = 1; + break; + } + else + { + if(!strcmp(modulePtr->name,"shaftbot")) + { + drawEndWater = 1; + } + if((!_stricmp(modulePtr->name,"shaft01")) + ||(!_stricmp(modulePtr->name,"shaft02")) + ||(!_stricmp(modulePtr->name,"shaft03")) + ||(!_stricmp(modulePtr->name,"shaft04")) + ||(!_stricmp(modulePtr->name,"shaft05")) + ||(!_stricmp(modulePtr->name,"shaft06"))) + { + extern void HandleRainShaft(MODULE *modulePtr, int bottomY, int topY, int numberOfRaindrops); + HandleRainShaft(modulePtr, -11726,-107080,10); + drawEndWater = 1; + break; + } + } + } + + } + + if (drawWater) + { + int x = 20767; + int y = -36000+200; + int z = 30238; + MeshXScale = (36353-20767); + MeshZScale = (41927-30238); + { + extern void CheckForObjectsInWater(int minX, int maxX, int minZ, int maxZ, int averageY); + CheckForObjectsInWater(x, x+MeshXScale, z, z+MeshZScale, y); + } + + WaterXOrigin=x; + WaterZOrigin=z; + WaterUScale = 4.0f/(float)MeshXScale; + WaterVScale = 4.0f/(float)MeshZScale; + MeshXScale/=4; + MeshZScale/=2; + + // Turn OFF texturing if it is on... + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[ChromeImageNumber].D3DHandle; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL); + if (NumVertices) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + D3D_DrawWaterPatch(x, y, z); + D3D_DrawWaterPatch(x+MeshXScale, y, z); + D3D_DrawWaterPatch(x+MeshXScale*2, y, z); + D3D_DrawWaterPatch(x+MeshXScale*3, y, z); + D3D_DrawWaterPatch(x, y, z+MeshZScale); + D3D_DrawWaterPatch(x+MeshXScale, y, z+MeshZScale); + D3D_DrawWaterPatch(x+MeshXScale*2, y, z+MeshZScale); + D3D_DrawWaterPatch(x+MeshXScale*3, y, z+MeshZScale); + } + else if (drawEndWater) + { + int x = -15471; + int y = -11720-500; + int z = -55875; + MeshXScale = (15471-1800); + MeshZScale = (55875-36392); + { + extern void CheckForObjectsInWater(int minX, int maxX, int minZ, int maxZ, int averageY); + CheckForObjectsInWater(x, x+MeshXScale, z, z+MeshZScale, y); + } + WaterXOrigin=x; + WaterZOrigin=z; + WaterUScale = 4.0f/(float)(MeshXScale+1800-3782); + WaterVScale = 4.0f/(float)MeshZScale; + MeshXScale/=4; + MeshZScale/=2; + + // Turn OFF texturing if it is on... + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[WaterShaftImageNumber].D3DHandle; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL); + if (NumVertices) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + D3D_DrawWaterPatch(x, y, z); + D3D_DrawWaterPatch(x+MeshXScale, y, z); + D3D_DrawWaterPatch(x+MeshXScale*2, y, z); + D3D_DrawWaterPatch(x+MeshXScale*3, y, z); + D3D_DrawWaterPatch(x, y, z+MeshZScale); + D3D_DrawWaterPatch(x+MeshXScale, y, z+MeshZScale); + D3D_DrawWaterPatch(x+MeshXScale*2, y, z+MeshZScale); + D3D_DrawWaterPatch(x+MeshXScale*3, y, z+MeshZScale); + } + } + #if 1 + else if (!_stricmp(LevelName,"derelict")) + { + char drawMirrorSurfaces = 0; + char drawWater = 0; + + while(numOfObjects) + { + DISPLAYBLOCK *objectPtr = OnScreenBlockList[--numOfObjects]; + MODULE *modulePtr = objectPtr->ObMyModule; + + /* if it's a module, which isn't inside another module */ + if (modulePtr && modulePtr->name) + { + if( (!_stricmp(modulePtr->name,"start-en01")) + ||(!_stricmp(modulePtr->name,"start"))) + { + drawMirrorSurfaces = 1; + } + else if (!_stricmp(modulePtr->name,"water-01")) + { + extern void HandleRainShaft(MODULE *modulePtr, int bottomY, int topY, int numberOfRaindrops); + drawWater = 1; + HandleRainShaft(modulePtr, 32000, 0, 16); + } + } + } + + if (drawMirrorSurfaces) + { + extern void RenderMirrorSurface(void); + extern void RenderMirrorSurface2(void); + extern void RenderParticlesInMirror(void); + RenderParticlesInMirror(); + RenderMirrorSurface(); + RenderMirrorSurface2(); + } + if (drawWater) + { + int x = -102799; + int y = 32000; + int z = -200964; + MeshXScale = (102799-87216); + MeshZScale = (200964-180986); + { + extern void CheckForObjectsInWater(int minX, int maxX, int minZ, int maxZ, int averageY); + CheckForObjectsInWater(x, x+MeshXScale, z, z+MeshZScale, y); + } + + WaterXOrigin=x; + WaterZOrigin=z; + WaterUScale = 4.0f/(float)MeshXScale; + WaterVScale = 4.0f/(float)MeshZScale; + MeshXScale/=2; + MeshZScale/=2; + + // Turn OFF texturing if it is on... + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[ChromeImageNumber].D3DHandle; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL); + if (NumVertices) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + D3D_DrawWaterPatch(x, y, z); + D3D_DrawWaterPatch(x+MeshXScale, y, z); + D3D_DrawWaterPatch(x, y, z+MeshZScale); + D3D_DrawWaterPatch(x+MeshXScale, y, z+MeshZScale); + } + + } + #endif + else if (!_stricmp(LevelName,"genshd1")) + { + char drawWater = 0; + + while(numOfObjects) + { + DISPLAYBLOCK *objectPtr = OnScreenBlockList[--numOfObjects]; + MODULE *modulePtr = objectPtr->ObMyModule; + + /* if it's a module, which isn't inside another module */ + if (modulePtr && modulePtr->name) + { + if( (!_stricmp(modulePtr->name,"largespace")) + ||(!_stricmp(modulePtr->name,"proc13")) + ||(!_stricmp(modulePtr->name,"trench01")) + ||(!_stricmp(modulePtr->name,"trench02")) + ||(!_stricmp(modulePtr->name,"trench03")) + ||(!_stricmp(modulePtr->name,"trench04")) + ||(!_stricmp(modulePtr->name,"trench05")) + ||(!_stricmp(modulePtr->name,"trench06")) + ||(!_stricmp(modulePtr->name,"trench07")) + ||(!_stricmp(modulePtr->name,"trench08")) + ||(!_stricmp(modulePtr->name,"trench09"))) + { + extern void HandleRain(int numberOfRaindrops); + HandleRain(999); + break; + } + } + + } + } +} + +void D3D_DrawWaterTest(MODULE *testModulePtr) +{ + extern char LevelName[]; + if (!strcmp(LevelName,"genshd1")) + { + extern DISPLAYBLOCK *Player; + +// DISPLAYBLOCK *objectPtr = OnScreenBlockList[numOfObjects]; + MODULE *modulePtr = testModulePtr;//objectPtr->ObMyModule; +#if 0 + if (testModulePtr && testModulePtr->name) + if(!strcmp(testModulePtr->name,"LargeSpace")) + { + extern void HandleRain(int numberOfRaindrops); + HandleRain(999); + } +#endif + if (modulePtr && modulePtr->name) + { + if (!strcmp(modulePtr->name,"05")) + { + int y = modulePtr->m_maxy+modulePtr->m_world.vy-500; + int x = modulePtr->m_minx+modulePtr->m_world.vx; + int z = modulePtr->m_minz+modulePtr->m_world.vz; + MeshXScale = (7791 - -7794); + MeshZScale = (23378 - 7793); + { + extern void CheckForObjectsInWater(int minX, int maxX, int minZ, int maxZ, int averageY); + CheckForObjectsInWater(x, x+MeshXScale, z, z+MeshZScale, y); + } + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[WaterShaftImageNumber].D3DHandle; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL); + if (NumVertices) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + WaterXOrigin=x; + WaterZOrigin=z; + WaterUScale = 4.0f/(float)(MeshXScale); + WaterVScale = 4.0f/(float)MeshZScale; + #if 1 + MeshXScale/=2; + MeshZScale/=2; + D3D_DrawWaterPatch(x, y, z); + D3D_DrawWaterPatch(x+MeshXScale, y, z); + D3D_DrawWaterPatch(x, y, z+MeshZScale); + D3D_DrawWaterPatch(x+MeshXScale, y, z+MeshZScale); + + extern void HandleRainShaft(MODULE *modulePtr, int bottomY, int topY, int numberOfRaindrops); + HandleRainShaft(modulePtr, y,-21000,1); + #else + MeshXScale/=4; + MeshZScale/=4; + D3D_DrawWaterPatch(x, y, z); + D3D_DrawWaterPatch(x, y, z+MeshZScale); + D3D_DrawWaterPatch(x, y, z+MeshZScale*2); + D3D_DrawWaterPatch(x, y, z+MeshZScale*3); + D3D_DrawWaterPatch(x+MeshXScale, y, z); + D3D_DrawWaterPatch(x+MeshXScale, y, z+MeshZScale); + D3D_DrawWaterPatch(x+MeshXScale, y, z+MeshZScale*2); + D3D_DrawWaterPatch(x+MeshXScale, y, z+MeshZScale*3); + D3D_DrawWaterPatch(x+MeshXScale*2, y, z); + D3D_DrawWaterPatch(x+MeshXScale*2, y, z+MeshZScale); + D3D_DrawWaterPatch(x+MeshXScale*2, y, z+MeshZScale*2); + D3D_DrawWaterPatch(x+MeshXScale*2, y, z+MeshZScale*3); + D3D_DrawWaterPatch(x+MeshXScale*3, y, z); + D3D_DrawWaterPatch(x+MeshXScale*3, y, z+MeshZScale); + D3D_DrawWaterPatch(x+MeshXScale*3, y, z+MeshZScale*2); + D3D_DrawWaterPatch(x+MeshXScale*3, y, z+MeshZScale*3); + HandleRainDrops(modulePtr,2); + #endif + } + } + } + #if 0 + else if ( (!_stricmp(LevelName,"e3demo")) || (!_stricmp(LevelName,"e3demosp")) ) + { + if (testModulePtr && testModulePtr->name) + { + #if 0 + if(!_stricmp(testModulePtr->name,"watermid")) + { + DECAL fmvDecal = + { + DECAL_FMV, + { + {0,-2500,29000}, + {2000,-2500,29000}, + {2000,-2500+750*2,29000}, + {0,-2500+750*2,29000} + }, + 0 + }; + fmvDecal.ModuleIndex = testModulePtr->m_index; + fmvDecal.Centre.vx = 0; + fmvDecal.UOffset = 0; + + RenderDecal(&fmvDecal); + } + #endif + if(!_stricmp(testModulePtr->name,"lowlowlo03")) + { + VECTORCH position = {6894,469,-13203}; + VECTORCH disp = position; + int i,d; + + disp.vx -= Player->ObWorld.vx; + disp.vy -= Player->ObWorld.vy; + disp.vz -= Player->ObWorld.vz; + d = ONE_FIXED - Approximate3dMagnitude(&disp)*2; + if (d<0) d = 0; + + i = MUL_FIXED(10,d); + while(i--) + { + VECTORCH velocity; + velocity.vx = ((FastRandom()&1023) - 512); + velocity.vy = ((FastRandom()&1023) - 512)+2000; + velocity.vz = (1000+(FastRandom()&255))*2; + MakeParticle(&(position),&(velocity),PARTICLE_STEAM); + } + } + } + } + #endif + +} + +VECTORCH MeshVertex[256]; +#define TEXTURE_WATER 0 + +VECTORCH MeshWorldVertex[256]; +unsigned int MeshVertexColour[256]; +unsigned int MeshVertexSpecular[256]; +char MeshVertexOutcode[256]; +void D3D_DrawWaterPatch(int xOrigin, int yOrigin, int zOrigin) +{ + int i=0; + int x; + for (x=0; x<16; x++) + { + int z; + for(z=0; z<16; z++) + { + VECTORCH *point = &MeshVertex[i]; + + point->vx = xOrigin+(x*MeshXScale)/15; + point->vz = zOrigin+(z*MeshZScale)/15; + + + int offset=0; + + #if 1 + /* basic noise ripples */ +// offset = MUL_FIXED(32,GetSin( (point->vx+point->vz+CloakingPhase)&4095 ) ); +// offset += MUL_FIXED(16,GetSin( (point->vx-point->vz*2+CloakingPhase/2)&4095 ) ); + + { + offset += EffectOfRipples(point); + } + #endif + // if (offset>450) offset = 450; + // if (offset<-450) offset = -450; + point->vy = yOrigin+offset; + + #if 0 + MeshVertexColour[i] = LightSourceWaterPoint(point,offset); + #else + { + int alpha = 128-offset/4; + // if (alpha>255) alpha = 255; + // if (alpha<128) alpha = 128; + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { +// MeshVertexColour[i] = RGBALIGHT_MAKE(10,51,28,alpha); + MeshVertexColour[i] = RGBALIGHT_MAKE(255,255,255,alpha); + #if 0 + #if 1 + VECTORCH pos = {24087,yOrigin,39165}; + int c = (8191-VectorDistance(&pos,point)); + if (c<0) c=0; + else + { + int s = GetSin((CloakingPhase/2)&4095); + s = MUL_FIXED(s,s)/64; + c = MUL_FIXED(s,c); + } + MeshVertexSpecular[i] = (c<<16)+(((c/4)<<8)&0xff00) + (c/4); + #else + if (!(FastRandom()&1023)) + { + MeshVertexSpecular[i] = 0xc04040; + } + else + { + MeshVertexSpecular[i] = 0; + } + #endif + #endif + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + MeshVertexColour[i] = RGBALIGHT_MAKE(0,51,0,alpha); + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + MeshVertexColour[i] = RGBALIGHT_MAKE(0,0,28,alpha); + break; + } + } + + } + #endif + + #if 1 + MeshWorldVertex[i].vx = ((point->vx-WaterXOrigin)/4+MUL_FIXED(GetSin((point->vy*16)&4095),128)); + MeshWorldVertex[i].vy = ((point->vz-WaterZOrigin)/4+MUL_FIXED(GetSin((point->vy*16+200)&4095),128)); + #endif + + #if 1 + TranslatePointIntoViewspace(point); + #else + point->vx -= Global_VDB_Ptr->VDB_World.vx; + point->vy -= Global_VDB_Ptr->VDB_World.vy; + point->vz -= Global_VDB_Ptr->VDB_World.vz; + RotateVector(point,&(Global_VDB_Ptr->VDB_Mat)); + point->vy = MUL_FIXED(point->vy,87381); + + #endif + /* is particle within normal view frustrum ? */ + if(AvP.PlayerType==I_Alien) /* wide frustrum */ + { + if(( (-point->vx <= point->vz*2) + &&(point->vx <= point->vz*2) + &&(-point->vy <= point->vz*2) + &&(point->vy <= point->vz*2) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + else + { + if(( (-point->vx <= point->vz) + &&(point->vx <= point->vz) + &&(-point->vy <= point->vz) + &&(point->vy <= point->vz) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + + i++; + } + } + + if ((MeshVertexOutcode[0]&&MeshVertexOutcode[15]&&MeshVertexOutcode[240]&&MeshVertexOutcode[255])) + { + D3D_DrawMoltenMetalMesh_Unclipped(); +// D3D_DrawWaterMesh_Unclipped(); + } + else +// else if (MeshVertexOutcode[0]||MeshVertexOutcode[15]||MeshVertexOutcode[240]||MeshVertexOutcode[255]) + { + D3D_DrawMoltenMetalMesh_Clipped(); +// D3D_DrawWaterMesh_Clipped(); + } + + +} + +void D3D_DrawWaterMesh_Unclipped(void) +{ + float ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + VECTORCH *point = MeshVertex; + #if TEXTURE_WATER + VECTORCH *pointWS = MeshWorldVertex; + #endif + int i; + for (i=0; i<256; i++) + { + + if (point->vz<=1) point->vz = 1; + int x = (point->vx*(Global_VDB_Ptr->VDB_ProjX))/point->vz+Global_VDB_Ptr->VDB_CentreX; + int y = (point->vy*(Global_VDB_Ptr->VDB_ProjY))/point->vz+Global_VDB_Ptr->VDB_CentreY; + // textprint("%d, %d\n",x,y); + #if 1 + { + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + } + #else + vertexPtr->sx=x; + vertexPtr->sy=y; + #endif + #if FOG_ON + { + int fog = (point->vz)/FOG_SCALE; + if (fog<0) fog=0; + if (fog>254) fog=254; + fog=255-fog; + vertexPtr->specular=RGBALIGHT_MAKE(0,0,0,fog); + } + #endif + point->vz+=HeadUpDisplayZOffset; + float oneOverZ = ((float)(point->vz)-ZNear)/(float)(point->vz); + //vertexPtr->color = RGBALIGHT_MAKE(66,70,0,127+(FastRandom()&63)); + vertexPtr->color = MeshVertexColour[i]; + vertexPtr->sz = oneOverZ; + #if TEXTURE_WATER + vertexPtr->tu = pointWS->vx/128.0; + vertexPtr->tv = pointWS->vz/128.0; + #endif + + + NumVertices++; + vertexPtr++; + point++; + #if TEXTURE_WATER + pointWS++; + #endif + } + } + // textprint("numvertices %d\n",NumVertices); + + + /* + * Make sure that the triangle data (not OP) will be QWORD aligned + */ + if (QWORD_ALIGNED(ExecBufInstPtr)) + { + OP_NOP(ExecBufInstPtr); + } + + OP_TRIANGLE_LIST(450, ExecBufInstPtr); + /* CONSTRUCT POLYS */ + { + int x; + for (x=0; x<15; x++) + { + int y; + for(y=0; y<15; y++) + { + OUTPUT_TRIANGLE(0+x+(16*y),1+x+(16*y),16+x+(16*y), 256); + OUTPUT_TRIANGLE(1+x+(16*y),17+x+(16*y),16+x+(16*y), 256); + } + } + } + #if 1 + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + #endif +} +void D3D_DrawWaterMesh_Clipped(void) +{ + float ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + VECTORCH *point = MeshVertex; + #if TEXTURE_WATER + VECTORCH *pointWS = MeshWorldVertex; + #endif + int i; + for (i=0; i<256; i++) + { + { + if (point->vz<=1) point->vz = 1; + int x = (point->vx*(Global_VDB_Ptr->VDB_ProjX))/point->vz+Global_VDB_Ptr->VDB_CentreX; + int y = (point->vy*(Global_VDB_Ptr->VDB_ProjY))/point->vz+Global_VDB_Ptr->VDB_CentreY; + #if 1 + { + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + } + #else + vertexPtr->sx=x; + vertexPtr->sy=y; + #endif + #if FOG_ON + { + int fog = ((point->vz)/FOG_SCALE); + if (fog<0) fog=0; + if (fog>254) fog=254; + fog=255-fog; + vertexPtr->specular=RGBALIGHT_MAKE(0,0,0,fog); + } + #endif + #if TEXTURE_WATER + vertexPtr->tu = pointWS->vx/128.0; + vertexPtr->tv = pointWS->vz/128.0; + #endif + point->vz+=HeadUpDisplayZOffset; + float oneOverZ = ((float)(point->vz)-ZNear)/(float)(point->vz); + // vertexPtr->color = RGBALIGHT_MAKE(66,70,0,127+(FastRandom()&63)); + vertexPtr->color = MeshVertexColour[i]; + vertexPtr->sz = oneOverZ; + } + NumVertices++; + vertexPtr++; + point++; + #if TEXTURE_WATER + pointWS++; + #endif + } + } +// textprint("numvertices %d\n",NumVertices); + /* CONSTRUCT POLYS */ + { + int x; + for (x=0; x<15; x++) + { + int y; + for(y=0; y<15; y++) + { + #if 1 + int p1 = 0+x+(16*y); + int p2 = 1+x+(16*y); + int p3 = 16+x+(16*y); + int p4 = 17+x+(16*y); + + if (MeshVertexOutcode[p1]||MeshVertexOutcode[p2]||MeshVertexOutcode[p3]) + { + OP_TRIANGLE_LIST(1, ExecBufInstPtr); + OUTPUT_TRIANGLE(p1,p2,p3, 256); + } + if (MeshVertexOutcode[p2]||MeshVertexOutcode[p3]||MeshVertexOutcode[p4]) + { + OP_TRIANGLE_LIST(1, ExecBufInstPtr); + OUTPUT_TRIANGLE(p2,p4,p3, 256); + } + #else + int p2 = 1+x+(16*y); + int p3 = 16+x+(16*y); + + if (MeshVertexOutcode[p2]&&MeshVertexOutcode[p3]) + { + int p1 = 0+x+(16*y); + int p4 = 17+x+(16*y); + if (MeshVertexOutcode[p1]) + { + OP_TRIANGLE_LIST(1, ExecBufInstPtr); + OUTPUT_TRIANGLE(p1,p2,p3, 256); + } + if (MeshVertexOutcode[p4]) + { + OP_TRIANGLE_LIST(1, ExecBufInstPtr); + OUTPUT_TRIANGLE(p2,p4,p3, 256); + } + } + #endif + } + } + } + #if 1 + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + #endif +} + + +int LightSourceWaterPoint(VECTORCH *pointPtr,int offset) +{ + // this needs a rewrite... + // make a list of lights which will affect some part of the mesh + // and go throught that for each point. + +// int intensity=0; + int redI=0,greenI=0,blueI=0; + + #if 0 + int alpha = 207-offset; + if (alpha>255) alpha = 255; + if (alpha<160) alpha = 160; + + return RGBALIGHT_MAKE(128,128,255,alpha); + #else + + DISPLAYBLOCK **activeBlockListPtr = ActiveBlockList; + for(int i = NumActiveBlocks; i!=0; i--) + { + DISPLAYBLOCK *dispPtr = *activeBlockListPtr++; + + if(dispPtr->ObNumLights) + { + for(int j = 0; j < dispPtr->ObNumLights; j++) + { + LIGHTBLOCK *lptr = dispPtr->ObLights[j]; + + VECTORCH disp = lptr->LightWorld; + disp.vx -= pointPtr->vx; + disp.vy -= pointPtr->vy; + disp.vz -= pointPtr->vz; + + int dist = Approximate3dMagnitude(&disp); + + if (distLightRange) + { + int brightness = MUL_FIXED(lptr->BrightnessOverRange,lptr->LightRange-dist); + redI += MUL_FIXED(brightness,lptr->RedScale); + greenI += MUL_FIXED(brightness,lptr->GreenScale); + blueI += MUL_FIXED(brightness,lptr->BlueScale); + } + } + } + } + if (redI>ONE_FIXED) redI=ONE_FIXED; + else if (redIONE_FIXED) greenI=ONE_FIXED; + else if (greenIONE_FIXED) blueI=ONE_FIXED; + else if (blueI255) alpha = 255; + if (alpha<128) alpha = 128; + +// return RGBALIGHT_MAKE(MUL_FIXED(64+(offset&128),redI),MUL_FIXED(64+(offset&128),greenI),MUL_FIXED(64+(offset&128),blueI),alpha); +// return RGBALIGHT_MAKE(MUL_FIXED(50,redI),MUL_FIXED(255,greenI),MUL_FIXED(140,blueI),alpha); + return RGBALIGHT_MAKE(MUL_FIXED(10,redI),MUL_FIXED(51,greenI),MUL_FIXED(28,blueI),alpha); +// return RGBALIGHT_MAKE(MUL_FIXED(128,redI),MUL_FIXED(128,greenI),MUL_FIXED(255,blueI),alpha); + #endif +} +int LightIntensityAtPoint(VECTORCH *pointPtr) +{ + int intensity=0; + + DISPLAYBLOCK **activeBlockListPtr = ActiveBlockList; + for(int i = NumActiveBlocks; i!=0; i--) + { + DISPLAYBLOCK *dispPtr = *activeBlockListPtr++; + + if(dispPtr->ObNumLights) + { + for(int j = 0; j < dispPtr->ObNumLights; j++) + { + LIGHTBLOCK *lptr = dispPtr->ObLights[j]; + + VECTORCH disp = lptr->LightWorld; + disp.vx -= pointPtr->vx; + disp.vy -= pointPtr->vy; + disp.vz -= pointPtr->vz; + + int dist = Approximate3dMagnitude(&disp); + + if (distLightRange) + { + intensity += WideMulNarrowDiv(lptr->LightBright,lptr->LightRange-dist,lptr->LightRange); + } + } + } + } + if (intensity>ONE_FIXED) intensity=ONE_FIXED; + else if (intensity>6; + ForceFieldPhase+=NormalFrameTime>>5; + int x; + for (x=1; x<15*3; x++) + { + int y; + for (y=1; y<15; y++) + { + + int acceleration =32*(-8*ForceFieldPointDisplacement[x][y] + +ForceFieldPointDisplacement[x-1][y-1] + +ForceFieldPointDisplacement[x-1][y] + +ForceFieldPointDisplacement[x-1][y+1] + +ForceFieldPointDisplacement[x][y-1] + +ForceFieldPointDisplacement[x][y+1] +#if 0 + ) +#else + + +ForceFieldPointDisplacement[x+1][y-1] + +ForceFieldPointDisplacement[x+1][y] + +ForceFieldPointDisplacement[x+1][y+1]) +#endif + -(ForceFieldPointVelocity[x][y]*5); + + ForceFieldPointVelocity[x][y] += MUL_FIXED(acceleration,NormalFrameTime); + ForceFieldPointDisplacement2[x][y] += MUL_FIXED(ForceFieldPointVelocity[x][y],NormalFrameTime); +#if 1 + if(ForceFieldPointDisplacement2[x][y]>200) ForceFieldPointDisplacement2[x][y]=200; + if(ForceFieldPointDisplacement2[x][y]<-200) ForceFieldPointDisplacement2[x][y]=-200; +#else + if(ForceFieldPointDisplacement2[x][y]>512) ForceFieldPointDisplacement2[x][y]=512; + if(ForceFieldPointDisplacement2[x][y]<-512) ForceFieldPointDisplacement2[x][y]=-512; + +#endif + { + int offset = ForceFieldPointDisplacement2[x][y]; + int colour = ForceFieldPointVelocity[x][y]/4; + + if (offset<0) offset =-offset; + if (colour<0) colour =-colour; + colour=(colour+offset)/2; + + if(colour>255) colour=255; + colour++; + + ForceFieldPointColour1[x][y]=FastRandom()%colour; + ForceFieldPointColour2[x][y]=FastRandom()%colour; + } + } + + } + for (x=1; x<15*3; x++) + { + int y; + for (y=1; y<15; y++) + { + ForceFieldPointDisplacement[x][y] = ForceFieldPointDisplacement2[x][y]; + } + } + { + #if 1 + if(ForceFieldPhase>1000) + { + ForceFieldPhase=0; + int x = 1+(FastRandom()%(15*3-2)); + int y = 1+(FastRandom()%13); + ForceFieldPointVelocity[x][y] = 10000; + ForceFieldPointVelocity[x][y+1] = 10000; + ForceFieldPointVelocity[x+1][y] = 10000; + ForceFieldPointVelocity[x+1][y+1] = 10000; + } + #else + // if(ForceFieldPhase>1000) + { + ForceFieldPhase=0; + int x = 1+(FastRandom()%(15*3-2)); + int y = 1+(FastRandom()%13); + ForceFieldPointVelocity[x][y] = (FastRandom()&16383)+8192; + } + #endif + } + #else + int x; + int y; + for (y=0; y<=15; y++) + { + ForceFieldPointDisplacement[0][y] += (FastRandom()&127)-64; + if(ForceFieldPointDisplacement[0][y]>512) ForceFieldPointDisplacement[0][y]=512; + if(ForceFieldPointDisplacement[0][y]<-512) ForceFieldPointDisplacement[0][y]=-512; + ForceFieldPointVelocity[0][y] = (FastRandom()&16383)-8192; + } + for (x=15*3-1; x>0; x--) + { + for (y=0; y<=15; y++) + { + ForceFieldPointDisplacement[x][y] = ForceFieldPointDisplacement[x-1][y]; + ForceFieldPointVelocity[x][y] = ForceFieldPointVelocity[x-1][y]; + } + + } + for (x=15*3-1; x>1; x--) + { + y = FastRandom()&15; + ForceFieldPointDisplacement[x][y] = ForceFieldPointDisplacement[x-1][y]; + y = (FastRandom()&15)-1; + ForceFieldPointDisplacement[x][y] = ForceFieldPointDisplacement[x-1][y]; + } + #endif +} +void UpdateWaterFall(void) +{ + int x; + int y; + for (y=0; y<=15; y++) + { + ForceFieldPointDisplacement[0][y] += (FastRandom()&127)-64; + if(ForceFieldPointDisplacement[0][y]>512) ForceFieldPointDisplacement[0][y]=512; + if(ForceFieldPointDisplacement[0][y]<-512) ForceFieldPointDisplacement[0][y]=-512; + ForceFieldPointVelocity[0][y] = (FastRandom()&16383)-8192; + } + for (x=15*3-1; x>0; x--) + { + for (y=0; y<=15; y++) + { + ForceFieldPointDisplacement[x][y] = ForceFieldPointDisplacement[x-1][y]; + ForceFieldPointVelocity[x][y] = ForceFieldPointVelocity[x-1][y]; + } + + } + for (x=15*3-1; x>1; x--) + { + y = FastRandom()&15; + ForceFieldPointDisplacement[x][y] = ForceFieldPointDisplacement[x-1][y]; + y = (FastRandom()&15)-1; + ForceFieldPointDisplacement[x][y] = ForceFieldPointDisplacement[x-1][y]; + } +} + +#endif +void D3D_DrawForceField(int xOrigin, int yOrigin, int zOrigin, int fieldType) +{ + MeshXScale = 4096/16; + MeshZScale = 4096/16; + + for (int field=0; field<3; field++) + { + int i=0; + int x; + for (x=(0+field*15); x<(16+field*15); x++) + { + int z; + for(z=0; z<16; z++) + { + VECTORCH *point = &MeshVertex[i]; + int offset = ForceFieldPointDisplacement[x][z]; + + switch(fieldType) + { + case 0: + { + point->vx = xOrigin+(x*MeshXScale); + point->vy = yOrigin+(z*MeshZScale); + point->vz = zOrigin+offset; + break; + } + case 1: + { + + int theta = (z*4095)/15; + int u = (x*65536)/45; + + int b = MUL_FIXED(2*u,(65536-u)); + int c = MUL_FIXED(u,u); + int phi = (Phase&4095); + int x3 = (GetSin(phi))/64; + int y3 = 5000-(GetCos((phi*3+1000)&4095)/128); + int z3 = (GetSin((3*phi+1324)&4095))/32; + int x2 = -x3/2; + int y2 = 3000; + int z2 = -z3/4; + int innerRadius = 100;//GetSin(u/32)/16+offset; + + point->vx = xOrigin+(b*x2+c*x3)/65536+MUL_FIXED(innerRadius,GetSin(theta)); + point->vy = yOrigin-5000+(b*y2+c*y3)/65536; + point->vz = zOrigin+(b*z2+c*z3)/65536+MUL_FIXED(innerRadius,GetCos(theta)); + break; + } + case 2: + { + int theta = (z*4095)/15; + int phi = (x*4095)/45; + int innerRadius = 1000+offset; + int outerRadius = 4000; + + + point->vx = xOrigin+MUL_FIXED(outerRadius-MUL_FIXED(innerRadius,GetSin(theta)),GetCos(phi)); + point->vy = yOrigin+MUL_FIXED(innerRadius,GetCos(theta)); + point->vz = zOrigin+MUL_FIXED(outerRadius-MUL_FIXED(innerRadius,GetSin(theta)),GetSin(phi)); + break; + } + case 3: + { + + int theta = (x*4095)/45; + int radius = offset+2000; + point->vx = xOrigin+MUL_FIXED(radius,GetCos(theta)); + point->vy = yOrigin+(z*MeshZScale); + point->vz = zOrigin+MUL_FIXED(radius,GetSin(theta)); + break; + } + } + + if (offset<0) offset =-offset; + offset+=16; + +// offset-=32; +// if (offset<0) offset = 0; + + if(offset>255) offset=255; + + MeshVertexColour[i] = RGBALIGHT_MAKE(ForceFieldPointColour1[x][z],ForceFieldPointColour2[x][z],255,offset); + #if TEXTURE_WATER + MeshWorldVertex[i].vx = point->vx; + MeshWorldVertex[i].vz = point->vz; + #endif + + TranslatePointIntoViewspace(point); + + /* is particle within normal view frustrum ? */ + if(AvP.PlayerType==I_Alien) /* wide frustrum */ + { + if(( (-point->vx <= point->vz*2) + &&(point->vx <= point->vz*2) + &&(-point->vy <= point->vz*2) + &&(point->vy <= point->vz*2) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + else + { + if(( (-point->vx <= point->vz) + &&(point->vx <= point->vz) + &&(-point->vy <= point->vz) + &&(point->vy <= point->vz) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + + i++; + } + } + //textprint("\n"); + if ((MeshVertexOutcode[0]&&MeshVertexOutcode[15]&&MeshVertexOutcode[240]&&MeshVertexOutcode[255])) + { + D3D_DrawWaterMesh_Unclipped(); + } + else +// else if (MeshVertexOutcode[0]||MeshVertexOutcode[15]||MeshVertexOutcode[240]||MeshVertexOutcode[255]) + { + D3D_DrawWaterMesh_Clipped(); + } + } +} + + +void D3D_DrawPowerFence(int xOrigin, int yOrigin, int zOrigin, int xScale, int yScale, int zScale) +{ + for (int field=0; field<3; field++) + { + int i=0; + int x; + for (x=(0+field*15); x<(16+field*15); x++) + { + int z; + for(z=0; z<16; z++) + { + VECTORCH *point = &MeshVertex[i]; + int offset = ForceFieldPointDisplacement[x][z]; + + point->vx = xOrigin+(x*xScale); + point->vy = yOrigin+(z*yScale); + point->vz = zOrigin+(x*zScale); + + if (offset<0) offset =-offset; + offset+=16; + + if(offset>255) offset=255; + + MeshVertexColour[i] = RGBALIGHT_MAKE(ForceFieldPointColour1[x][z],ForceFieldPointColour2[x][z],255,offset); + + /* translate particle into view space */ + TranslatePointIntoViewspace(point); + + /* is particle within normal view frustrum ? */ + if(AvP.PlayerType==I_Alien) /* wide frustrum */ + { + if(( (-point->vx <= point->vz*2) + &&(point->vx <= point->vz*2) + &&(-point->vy <= point->vz*2) + &&(point->vy <= point->vz*2) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + else + { + if(( (-point->vx <= point->vz) + &&(point->vx <= point->vz) + &&(-point->vy <= point->vz) + &&(point->vy <= point->vz) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + + i++; + } + } + //textprint("\n"); + if ((MeshVertexOutcode[0]&&MeshVertexOutcode[15]&&MeshVertexOutcode[240]&&MeshVertexOutcode[255])) + { + D3D_DrawWaterMesh_Unclipped(); + } + else +// else if (MeshVertexOutcode[0]||MeshVertexOutcode[15]||MeshVertexOutcode[240]||MeshVertexOutcode[255]) + { + D3D_DrawWaterMesh_Clipped(); + } + } +} + +void D3D_DrawWaterFall(int xOrigin, int yOrigin, int zOrigin) +{ + { + int noRequired = MUL_FIXED(250,NormalFrameTime); + for (int i=0; ivx = xOrigin+MUL_FIXED(b,x2)+MUL_FIXED(c,x3)+offset; + point->vy = yOrigin+MUL_FIXED(b,y2)+MUL_FIXED(c,y3); + point->vz = zOrigin+(z*MeshZScale); + + if (point->vy>4742) + { + if (z<=4) + { + point->vy-=MeshXScale; + if (point->vy<4742) point->vy=4742; + if (point->vx<179427) point->vx=179427; + } + else if (z<=8) + { + point->vx+=(8-z)*1000; + } + } + + #else + if (offset<0) offset =-offset; + point->vx = xOrigin-offset; + point->vy = yOrigin+(x*MeshXScale); + point->vz = zOrigin+(z*MeshZScale); + #endif + + + + + offset= (offset/4)+127; + +// offset-=32; +// if (offset<0) offset = 0; + + if(offset>255) offset=255; + + MeshVertexColour[i] = RGBALIGHT_MAKE(offset,offset,255,offset/2); + #if TEXTURE_WATER + MeshWorldVertex[i].vx = point->vx; + MeshWorldVertex[i].vz = point->vz; + #endif + + /* translate particle into view space */ + TranslatePointIntoViewspace(point); + + /* is particle within normal view frustrum ? */ + if(AvP.PlayerType==I_Alien) /* wide frustrum */ + { + if(( (-point->vx <= point->vz*2) + &&(point->vx <= point->vz*2) + &&(-point->vy <= point->vz*2) + &&(point->vy <= point->vz*2) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + else + { + if(( (-point->vx <= point->vz) + &&(point->vx <= point->vz) + &&(-point->vy <= point->vz) + &&(point->vy <= point->vz) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + + i++; + } + } + //textprint("\n"); + if ((MeshVertexOutcode[0]&&MeshVertexOutcode[15]&&MeshVertexOutcode[240]&&MeshVertexOutcode[255])) + { + D3D_DrawWaterMesh_Unclipped(); + } + else +// else if (MeshVertexOutcode[0]||MeshVertexOutcode[15]||MeshVertexOutcode[240]||MeshVertexOutcode[255]) + { + D3D_DrawWaterMesh_Clipped(); + } + } +} + +void D3D_DrawParticleBeam(DISPLAYBLOCK *muzzlePtr, VECTORCH *targetPositionPtr) +{ + VECTORCH vertices[6]; + int beamRadius = 45+(FastRandom()&15); + vertices[0] = *targetPositionPtr; + vertices[1] = *targetPositionPtr; + vertices[2] = *targetPositionPtr; + + vertices[3] = muzzlePtr->ObWorld; + vertices[4] = muzzlePtr->ObWorld; + vertices[5] = muzzlePtr->ObWorld; + + vertices[1].vy += beamRadius; + vertices[2].vy -= beamRadius; + vertices[4].vy += beamRadius; + vertices[5].vy -= beamRadius; + + /* translate vertices into vxew space */ + TranslatePointIntoViewspace(&vertices[0]); + TranslatePointIntoViewspace(&vertices[1]); + TranslatePointIntoViewspace(&vertices[2]); + TranslatePointIntoViewspace(&vertices[3]); + TranslatePointIntoViewspace(&vertices[4]); + TranslatePointIntoViewspace(&vertices[5]); + + float ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + int i = 6; + VECTORCH *verticesPtr = vertices; + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + int x = (verticesPtr->vx*(Global_VDB_Ptr->VDB_ProjX))/verticesPtr->vz+Global_VDB_Ptr->VDB_CentreX; + int y = (verticesPtr->vy*(Global_VDB_Ptr->VDB_ProjY))/verticesPtr->vz+Global_VDB_Ptr->VDB_CentreY; + { + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + } + + float oneOverZ = ((float)verticesPtr->vz-ZNear)/(float)verticesPtr->vz; + + // Different behavxour for different driver modes + switch (D3DDriverMode) + { + default: + case D3DSoftwareRGBDriver: + case D3DSoftwareRampDriver: + break; + case D3DHardwareRGBDriver: + { + if (i==6 || i==3) vertexPtr->color = RGBALIGHT_MAKE(255,255,255,255); + else vertexPtr->color = RGBALIGHT_MAKE(0,0,255,32); + + break; + } + } + vertexPtr->sz = oneOverZ; + NumVertices++; + verticesPtr++; + } + while(--i); + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_GLOWING); + + OP_TRIANGLE_LIST(4, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,3,5, 6); + OUTPUT_TRIANGLE(0,3,4, 6); + OUTPUT_TRIANGLE(0,2,5, 6); + OUTPUT_TRIANGLE(0,1,4, 6); + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } +} +void D3D_DrawExplosion(int xOrigin, int yOrigin, int zOrigin, int size) +{ + if (NumVertices) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + + // Turn OFF texturing if it is on... + if (CurrTextureHandle != NULL) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NULL, ExecBufInstPtr); + CurrTextureHandle = NULL; + } + + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_GLOWING); + + + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZWRITEENABLE, FALSE, ExecBufInstPtr); + MeshXScale = 4096/16; + MeshZScale = 4096/16; + + int i=0; + int x; + for (x=0; x<16; x++) + { + int z; + for(z=0; z<16; z++) + { + VECTORCH *point = &MeshVertex[i]; + int offset;// = MUL_FIXED((FastRandom()&1023)-512,CloakingPhase&65535);//MUL_FIXED(255,GetSin((point->vx+point->vy+point->vz+CloakingPhase)&4095)); + int sd; + { + int theta = ((z*2048)/15)&4095; + int phi = ((x*4096)/15)&4095; + if (theta==0) sd = 0; + else sd = phi+theta; + if (phi==0 || phi==2048) sd = 0; + else sd = phi+theta; + + int outerRadius = MUL_FIXED(4000,size); + + if (sd) + offset = MUL_FIXED((FastRandom()&511)-255,size); + + offset=0; + + point->vx = xOrigin+MUL_FIXED(outerRadius+offset,MUL_FIXED(GetSin(theta),GetCos(phi))); + point->vy = yOrigin+MUL_FIXED(outerRadius+offset,MUL_FIXED(GetSin(theta),GetSin(phi))); + point->vz = zOrigin+MUL_FIXED(outerRadius+offset,GetCos(theta)); + } + + if(offset<0) offset = -offset; + MeshVertexColour[i] = RGBALIGHT_MAKE(255,GetSin((sd+CloakingPhase)&4095)&255,0,32); + + TranslatePointIntoViewspace(point); + + /* is particle within normal view frustrum ? */ + if(AvP.PlayerType==I_Alien) /* wide frustrum */ + { + if(( (-point->vx <= point->vz*2) + &&(point->vx <= point->vz*2) + &&(-point->vy <= point->vz*2) + &&(point->vy <= point->vz*2) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + else + { + if(( (-point->vx <= point->vz) + &&(point->vx <= point->vz) + &&(-point->vy <= point->vz) + &&(point->vy <= point->vz) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + + i++; + } + } + textprint("drawing explosion\n"); + if ((MeshVertexOutcode[0]&&MeshVertexOutcode[15]&&MeshVertexOutcode[240]&&MeshVertexOutcode[255])) + { + D3D_DrawWaterMesh_Unclipped(); + } + else +// else if (MeshVertexOutcode[0]||MeshVertexOutcode[15]||MeshVertexOutcode[240]||MeshVertexOutcode[255]) + { + D3D_DrawWaterMesh_Clipped(); + } + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZWRITEENABLE, TRUE, ExecBufInstPtr); + +} + + +void DrawFrameRateBar(void) +{ + extern int NormalFrameTime; + #if 1 + { + int width = DIV_FIXED(ScreenDescriptorBlock.SDB_Width/120,NormalFrameTime); + if (width>ScreenDescriptorBlock.SDB_Width) width=ScreenDescriptorBlock.SDB_Width; + + r2rect rectangle + ( + 0,0, + width, + 24 + ); + textprint("width %d\n",width); + + rectangle . AlphaFill + ( + 0xff, // unsigned char R, + 0x00,// unsigned char G, + 0x00,// unsigned char B, + 128 // unsigned char translucency + ); + } + #endif +} +void D3D_DrawAlienRedBlipIndicatingJawAttack(void) +{ + r2rect rectangle + ( + 16,16, + 32, + 32 + ); + + rectangle . AlphaFill + ( + 0xff, // unsigned char R, + 0x00,// unsigned char G, + 0x00,// unsigned char B, + 128 // unsigned char translucency + ); +} +void D3D_DrawBackdrop(void) +{ + extern char LevelName[]; + + if (TRIPTASTIC_CHEATMODE||MOTIONBLUR_CHEATMODE) return; + + if(WireFrameMode) + { + ColourFillBackBuffer(0); + return; + } + else if(ShowDebuggingText.Tears) + { + ColourFillBackBuffer((63<<5)); + return; + } + + { + int needToDrawBackdrop=0; + extern int NumActiveBlocks; + extern DISPLAYBLOCK *ActiveBlockList[]; + + int numOfObjects = NumActiveBlocks; + while(numOfObjects--) + { + DISPLAYBLOCK *objectPtr = ActiveBlockList[numOfObjects]; + MODULE *modulePtr = objectPtr->ObMyModule; + + + if (modulePtr && (ModuleCurrVisArray[modulePtr->m_index] == 2) &&modulePtr->m_flags&MODULEFLAG_SKY) + { + needToDrawBackdrop=1; + break; + } + } + if(needToDrawBackdrop) + { + extern BOOL LevelHasStars; + extern void RenderSky(void); + + ColourFillBackBuffer(0); + + if (LevelHasStars) + { + extern void RenderStarfield(void); + RenderStarfield(); + } + else + { + RenderSky(); + } + return; + } + } + + + /* if the player is outside the environment, clear the screen! */ + { + extern MODULE *playerPherModule; + if (!playerPherModule) + { + ColourFillBackBuffer(0); + return; + } + } + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + if (!playerStatusPtr->IsAlive || FREEFALL_CHEATMODE) + { + // minimise effects of camera glitches + ColourFillBackBuffer(0); + return; + } + } +} + +void MakeNoiseTexture(void) +{ +// return; + DDSURFACEDESC ddsd; + LPDIRECTDRAWSURFACE tempSurface; + LPDIRECT3DTEXTURE tempTexture; + + LPDIRECTDRAWSURFACE destSurface; + LPDIRECT3DTEXTURE destTexture; + + + memcpy(&ddsd, &(d3d.TextureFormat[d3d.CurrentTextureFormat].ddsd), sizeof(ddsd)); + + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT); + ddsd.ddsCaps.dwCaps = (DDSCAPS_SYSTEMMEMORY|DDSCAPS_TEXTURE); + + ddsd.dwHeight = 256; + ddsd.dwWidth = 256; + + LastError = lpDD->CreateSurface(&ddsd, &tempSurface, NULL); + LOGDXERR(LastError); + + + + LastError = tempSurface->QueryInterface(IID_IDirect3DTexture, (LPVOID*) &tempTexture); + LOGDXERR(LastError); + + // Query destination surface for a texture interface. + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + + LastError = tempSurface->GetSurfaceDesc(&ddsd); + LOGDXERR(LastError); + + ddsd.dwFlags = (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT); + ddsd.ddsCaps.dwCaps = (DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD ); + + LastError = lpDD->CreateSurface(&ddsd, &destSurface, NULL); + LOGDXERR(LastError); + + /* KJL 11:59:21 09/02/98 - check for palettised modes */ + { + int PalCaps; + + if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) + { + PalCaps = (DDPCAPS_8BIT | DDPCAPS_ALLOW256); + } + #if 0 + else if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) + { + PalCaps = DDPCAPS_4BIT; + } + else + #endif + { + PalCaps = 0; + } + + if (PalCaps) + { + LPDIRECTDRAWPALETTE destPalette = NULL; + PALETTEENTRY palette[256]; + memset(palette, 0, sizeof(PALETTEENTRY) * 256); + for(int i=0;i<256;i++) + { + palette[i].peRed = i; + palette[i].peGreen = i; + palette[i].peBlue = i; + } + + LastError = lpDD->CreatePalette(PalCaps, palette, &destPalette, NULL); + LOGDXERR(LastError); + + LastError = destSurface->SetPalette(destPalette); + LastError = tempSurface->SetPalette(destPalette); + LOGDXERR(LastError); + { + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + LastError = tempSurface->Lock(NULL, &ddsd, 0, NULL); + LOGDXERR(LastError); + + + unsigned char *dst = (unsigned char *)ddsd.lpSurface; + LOCALASSERT(dst); + for(int i = 0; i < 256; i ++) + { + for(int j = 0; j < 256; j ++) + { + int c = FastRandom()&255; + *dst++ = (c); + } + /* move the pitch to width difference */ + //dst += ddsd.lPitch - 256; + } + + LastError = tempSurface->Unlock(NULL); + LOGDXERR(LastError); + } + } + else + { + { + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + LastError = tempSurface->Lock(NULL, &ddsd, 0, NULL); + LOGDXERR(LastError); + + + unsigned short *dst = (unsigned short *)ddsd.lpSurface; + LOCALASSERT(dst); + for(int i = 0; i < 256; i ++) + { + int density = FastRandom()&31; + { + for(int j = 0; j < 256; j ++) + { + int c = FastRandom()&31; + *dst++ = (c)+(c<<6)+(c<<11); + } + } + /* move the pitch to width difference */ + //dst += ddsd.lPitch - 256; + } + + LastError = tempSurface->Unlock(NULL); + LOGDXERR(LastError); + } + } + } + + LastError = destSurface->QueryInterface(IID_IDirect3DTexture,(LPVOID*) &destTexture); + LOGDXERR(LastError); + + LastError = destTexture->Load(tempTexture); + LOGDXERR(LastError); + + // Clean up surfaces etc +// RELEASE(SrcTexture); + LastError = destTexture->GetHandle(d3d.lpD3DDevice, &NoiseTextureHandle); + RELEASE(tempSurface); + RELEASE(tempTexture); + +} +void DrawNoiseOverlay(int t) +{ +// return; + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + + extern float CameraZoomScale; + float u = FastRandom()&255; + float v = FastRandom()&255; + int c = 255; + int size = 256;//*CameraZoomScale; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = u/256.0; + vertexPtr->tv = v/256.0; + vertexPtr->color = RGBALIGHT_MAKE(c,c,c,t); + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = (u+size)/256.0; + vertexPtr->tv = v/256.0; + vertexPtr->color = RGBALIGHT_MAKE(c,c,c,t); + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = (u+size)/256.0; + vertexPtr->tv = (v+size)/256.0; + vertexPtr->color = RGBALIGHT_MAKE(c,c,c,t); + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = u/256.0; + vertexPtr->tv = (v+size)/256.0; + vertexPtr->color = RGBALIGHT_MAKE(c,c,c,t); + + NumVertices+=4; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_GLOWING); + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_ON); + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZFUNC, D3DCMP_ALWAYS, ExecBufInstPtr); + + NoiseTextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[StaticImageNumber].D3DHandle; + if (CurrTextureHandle != NoiseTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NoiseTextureHandle, ExecBufInstPtr); + CurrTextureHandle = NoiseTextureHandle; + } + if (D3DTexturePerspective != No) + { + D3DTexturePerspective = No; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREPERSPECTIVE, FALSE, ExecBufInstPtr); + } + + + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL, ExecBufInstPtr); + + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + +} +void DrawScanlinesOverlay(float level) +{ +// return; + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + + float u = 0.0f;//FastRandom()&255; + float v = 128.0f;//FastRandom()&255; + int c = 255; + extern float CameraZoomScale; + int t; + f2i(t,64.0f+level*64.0f); + + float size = 128.0f*(1.0f-level*0.8f);//*CameraZoomScale; + + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = (v-size)/256.0f; + vertexPtr->tv = 1.0f; + vertexPtr->color = RGBALIGHT_MAKE(c,c,c,t); + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = (v-size)/256.0f; + vertexPtr->tv = 1.0f; + vertexPtr->color = RGBALIGHT_MAKE(c,c,c,t); + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = (v+size)/256.0f; + vertexPtr->tv = 1.0f; + vertexPtr->color = RGBALIGHT_MAKE(c,c,c,t); + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = (v+size)/256.0f; + vertexPtr->tv = 1.0f; + vertexPtr->color = RGBALIGHT_MAKE(c,c,c,t); + + NumVertices+=4; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL); + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_ON); + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZFUNC, D3DCMP_ALWAYS, ExecBufInstPtr); + + NoiseTextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[PredatorNumbersImageNumber].D3DHandle; + if (CurrTextureHandle != NoiseTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NoiseTextureHandle, ExecBufInstPtr); + CurrTextureHandle = NoiseTextureHandle; + } + if (D3DTexturePerspective != No) + { + D3DTexturePerspective = No; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREPERSPECTIVE, FALSE, ExecBufInstPtr); + } + + + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL, ExecBufInstPtr); + + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + + if (level==1.0f) DrawNoiseOverlay(128); +} +void DrawPredatorVisionChangeOverlay(int time) +{ +// return; + { + if (time>ONE_FIXED) + for(int i=0; i<8; i++) + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + int t = (time-ONE_FIXED-((i+3)&7)*2048)*2; + if (t<0) t = 0; + + float rightU; + float leftU; + if (t>ONE_FIXED) + { + leftU = 0.0f; + rightU = 0.5f; + } + else if (t>ONE_FIXED/2) + { + leftU = 1.0f - ((float)(t))/65536.0f; + rightU = 1.0f - ((float)(t-ONE_FIXED/2))/65536.0f; + } + else + { + leftU = 1.0f - ((float)(t))/65536.0f; + rightU = 1.0f; + } + + float topV = 44.0f/128.0f; + float bottomV = 119.0f/128.0f; + if (leftU<0) leftU=0; + PrintDebuggingText("%f %f\n",leftU,rightU); + int rightX = MUL_FIXED((Global_VDB_Ptr->VDB_ClipRight-Global_VDB_Ptr->VDB_ClipLeft),t)+Global_VDB_Ptr->VDB_ClipLeft; + if (rightX>Global_VDB_Ptr->VDB_ClipRight) rightX = Global_VDB_Ptr->VDB_ClipRight; + int y = i*60; + int h = 60;//+MUL_FIXED(10,time-ONE_FIXED); + int c = 255; + + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = y; + vertexPtr->sz = 0; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = leftU; + vertexPtr->tv = topV; + vertexPtr->color = RGBALIGHT_MAKE(c,c,c,255); + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + vertexPtr++; + vertexPtr->sx = rightX; + vertexPtr->sy = y; + vertexPtr->sz = 0; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = rightU; + vertexPtr->tv = topV; + vertexPtr->color = RGBALIGHT_MAKE(c,c,c,255); + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + vertexPtr++; + vertexPtr->sx = rightX; + vertexPtr->sy = y+h; + vertexPtr->sz = 0; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = rightU; + vertexPtr->tv = bottomV; + vertexPtr->color = RGBALIGHT_MAKE(c,c,c,255); + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = y+h; + vertexPtr->sz = 0; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = leftU; + vertexPtr->tv = bottomV; + vertexPtr->color = RGBALIGHT_MAKE(255,255,255,255); + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + + NumVertices+=4; + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_COLOUR); + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_OFF); + + // NoiseTextureHandle = 0; + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[PredatorVisionChangeImageNumber].D3DHandle; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + } + } + + { + if (time>ONE_FIXED+8192) time = ONE_FIXED+8192; + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + + + float rightU = 1.0f; + float leftU = 1.0f - ((float)time)/65536.0f; + float v = 0; + if (leftU<0) leftU=0; + PrintDebuggingText("%f %f\n",leftU,rightU); + int rightX = MUL_FIXED((Global_VDB_Ptr->VDB_ClipRight-Global_VDB_Ptr->VDB_ClipLeft),time)+Global_VDB_Ptr->VDB_ClipLeft; + int c=128; + + int size = 256/4; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 0.001; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = leftU; + vertexPtr->tv = v/256.0; + vertexPtr->color = RGBALIGHT_MAKE(c,c,c,255); + vertexPtr->specular = 0; + vertexPtr++; + vertexPtr->sx = rightX; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 0.001; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = rightU; + vertexPtr->tv = v/256.0; + vertexPtr->color = RGBALIGHT_MAKE(c,c,c,255); + vertexPtr->specular = 0; + vertexPtr++; + vertexPtr->sx = rightX; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 0.001; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = rightU; + vertexPtr->tv = (v+size)/256.0; + vertexPtr->color = RGBALIGHT_MAKE(c,c,c,255); + vertexPtr->specular = 0; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 0.001; + vertexPtr->rhw = 1.0f; + vertexPtr->tu = leftU; + vertexPtr->tv = (v+size)/256.0; + vertexPtr->color = RGBALIGHT_MAKE(c,c,c,255); + vertexPtr->specular = 0; + + NumVertices+=4; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_OFF); + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_ON); + + // NoiseTextureHandle = 0; + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[PredatorVisionChangeImageNumber].D3DHandle; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + } + +} +#if 0 +#define OCTAVES 1 +float u[OCTAVES]; +float v[OCTAVES]; +float du[OCTAVES]; +float dv[OCTAVES]; +int setup=0; +void DrawFBM(void) +{ + extern int CloudyImageNumber; + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[CloudyImageNumber].D3DHandle; +// return; 1 + int i; + int size = 256; +// float u = FastRandom()&255; +// float v = FastRandom()&255; + int t =255; + if(!setup) + { + setup=1; + for(i=OCTAVES-1;i>=0;i--) + { + du[i] = ( (float)((FastRandom()&65535)-32768)*(i+1) )/16384.0; + dv[i] = ( (float)((FastRandom()&65535)-32768)*(i+1) )/16384.0; + } + } + + float timeScale = ((float)NormalFrameTime)/65536.0; + for(i=0; iVDB_Mat); + VECTORCH v[4]= + { + {-ONE_FIXED,-ONE_FIXED,ONE_FIXED}, + { ONE_FIXED,-ONE_FIXED,ONE_FIXED}, + { ONE_FIXED, 0, ONE_FIXED}, + {-ONE_FIXED, 0, ONE_FIXED}, + }; + TransposeMatrixCH(&mat); + RotateVector(&v[0],&mat); + RotateVector(&v[1],&mat); + RotateVector(&v[2],&mat); + RotateVector(&v[3],&mat); + if (v[0].vy=0) v[0].vy=-1; + if (v[1].vy=0) v[1].vy=-1; + if (v[2].vy=0) v[2].vy=-1; + if (v[3].vy=0) v[3].vy=-1; + if (v[0].vy>0) v[0].vy=-v[0].vy; + if (v[1].vy>0) v[1].vy=-v[1].vy; + if (v[2].vy>0) v[2].vy=-v[2].vy; + if (v[3].vy>0) v[3].vy=-v[3].vy; + + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 1; + vertexPtr->tu = -((float)v[0].vx)/((float)v[0].vy)/1.0; + vertexPtr->tv = -((float)v[0].vz)/((float)v[0].vy)/1.0; + vertexPtr->color = RGBALIGHT_MAKE(200,255,255,t); + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 1; + vertexPtr->tu = -((float)v[1].vx)/((float)v[1].vy)/1.0; + vertexPtr->tv = -((float)v[1].vz)/((float)v[1].vy)/1.0; + vertexPtr->color = RGBALIGHT_MAKE(200,255,255,t); + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = (Global_VDB_Ptr->VDB_ClipUp+Global_VDB_Ptr->VDB_ClipDown)/2; + vertexPtr->sz = 1; + vertexPtr->tu = -((float)v[2].vx)/((float)v[2].vy)/1.0; + vertexPtr->tv = -((float)v[2].vz)/((float)v[2].vy)/1.0; + vertexPtr->color = RGBALIGHT_MAKE(200,255,255,t); + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = (Global_VDB_Ptr->VDB_ClipUp+Global_VDB_Ptr->VDB_ClipDown)/2; + vertexPtr->sz = 1; + vertexPtr->tu = -((float)v[3].vx)/((float)v[3].vy)/1.0; + vertexPtr->tv = -((float)v[3].vz)/((float)v[3].vy)/1.0; + vertexPtr->color = RGBALIGHT_MAKE(200,255,255,t); + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + + NumVertices+=4; + } + + #else + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 1; + vertexPtr->tu = u[i]/256.0; + vertexPtr->tv = v[i]/256.0; + vertexPtr->color = RGBALIGHT_MAKE(200,255,255,t); + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 1; + vertexPtr->tu = (u[i]+size)/256.0; + vertexPtr->tv = v[i]/256.0; + vertexPtr->color = RGBALIGHT_MAKE(200,255,255,t); + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 1; + vertexPtr->tu = (u[i]+size)/256.0; + vertexPtr->tv = (v[i]+size)/256.0; + vertexPtr->color = RGBALIGHT_MAKE(200,255,255,t); + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 1; + vertexPtr->tu = u[i]/256.0; + vertexPtr->tv = (v[i]+size)/256.0; + vertexPtr->color = RGBALIGHT_MAKE(200,255,255,t); + vertexPtr->specular = RGBALIGHT_MAKE(0,0,0,255); + + NumVertices+=4; + } + #endif + size*=2; + t/=2; + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_GLOWING); + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_ON); + + // NoiseTextureHandle = 0; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = NoiseTextureHandle; + } + if (D3DTexturePerspective != No) + { + D3DTexturePerspective = No; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREPERSPECTIVE, FALSE, ExecBufInstPtr); + } + + + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + } + +} +#endif +void D3D_SkyPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr) +{ + int flags; + int texoffset; + + D3DTEXTUREHANDLE TextureHandle; + + float ZNear; + float RecipW, RecipH; + + // Get ZNear + ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + + // Take header information + flags = inputPolyPtr->PolyFlags; + + // We assume bit 15 (TxLocal) HAS been + // properly cleared this time... + texoffset = (inputPolyPtr->PolyColour & ClrTxDefn); + + TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[texoffset].D3DHandle; + + // Check for textures that have not loaded + // properly + +// if (TextureHandle == (D3DTEXTUREHANDLE) 0) + // return; + + #ifdef AVP_DEBUG_VERSION + if(ImageHeaderArray[texoffset].ImageWidth==128) + { + RecipW = (1.0 /128.0)/65536.0f; + } + else + { + float width = (float) ImageHeaderArray[texoffset].ImageWidth; + RecipW = (1.0 / width)/65536.0f; + } + if(ImageHeaderArray[texoffset].ImageHeight==128) + { + RecipH = (1.0 / 128.0)/65536.0f; + } + else + { + float height = (float) ImageHeaderArray[texoffset].ImageHeight; + RecipH = (1.0 / height)/65536.0f; + } + #else + RecipW = (1.0/65536.0)/128.0; + RecipH = (1.0/65536.0)/128.0; + #endif +// RecipW = (1.0/65536.0)/(float) ImageHeaderArray[texoffset].ImageWidth; +// RecipH = (1.0/65536.0)/(float) ImageHeaderArray[texoffset].ImageHeight; + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + float oneOverZ; + oneOverZ = (1.0)/(vertices->Z); + float zvalue; + + vertexPtr->tu = ((float)vertices->U) * RecipW + (1.0/256.0); + vertexPtr->tv = ((float)vertices->V) * RecipH + (1.0/256.0); + vertexPtr->rhw = oneOverZ; + + { + zvalue = vertices->Z+HeadUpDisplayZOffset; + // zvalue /= 65536.0; + zvalue = 1.0 - ZNear/zvalue; + } + + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + + #if 1 + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + #endif + vertexPtr->sx=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + + #if 1 + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + #endif + vertexPtr->sy=y; + + } +// vertexPtr->tu = ((float)(vertices->U>>16)+0.5) * RecipW; +// vertexPtr->tv = ((float)(vertices->V>>16)+0.5) * RecipH; +// vertexPtr->rhw = oneOverZ; + + + vertexPtr->color = RGBALIGHT_MAKE(vertices->R,vertices->G,vertices->B,vertices->A); + + vertexPtr->sz = 1.0; + vertexPtr->specular=RGBALIGHT_MAKE(0,0,0,255); + vertices++; + NumVertices++; + } + while(--i); + } + + CheckTranslucencyModeIsCorrect(RenderPolygon.TranslucencyMode); + // Insert state change for shading model if required + if (D3DShadingMode != D3DSHADE_GOURAUD) + { + D3DShadingMode = D3DSHADE_GOURAUD; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_SHADEMODE, + D3DSHADE_GOURAUD, ExecBufInstPtr); + } + +// Insert state change for texturing perspective value +// Note that drawtx3das2d options have ONLY been allowed for here, +// not when the rhw values are generated. This is a deliberate choice, +// based on the assumption that drawtx3das2d will not be used very often +// and the extra branching at the top of this function will impose a +// greater cost than the (rare) savings in floating pt divisions are worth. +// Or so I claim... + + if (D3DTexturePerspective != Yes) + { + D3DTexturePerspective = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, ExecBufInstPtr); + } + + #if FMV_EVERYWHERE + TextureHandle = FMVTextureHandle[0]; + #endif + + if (TextureHandle != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + + + D3D_OutputTriangles(); +} + +void D3D_DrawFMVOnWater(int xOrigin, int yOrigin, int zOrigin) +{ + int colour; + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + colour = RGBLIGHT_MAKE(128,128,128); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + colour = RGBLIGHT_MAKE(0,255,0); + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + colour = RGBLIGHT_MAKE(128,0,128); + break; + } + } + int i=0; + int x; + for (x=0; x<16; x++) + { + int z; + for(z=0; z<16; z++) + { + VECTORCH *point = &MeshVertex[i]; + + point->vz = zOrigin + (z*MeshZScale)/15; + point->vz += (FastRandom()&31); + + point->vx = (x*MeshXScale)/15; + point->vx -= MeshXScale/2; + point->vx = (point->vx * (32-z))/16 + (FastRandom()&31); + point->vx += xOrigin + MeshXScale/2; + + int offset = EffectOfRipples(point); + point->vy = yOrigin+offset; + + + { + int alpha = 192-offset*4; + if (alpha>255) alpha = 255; + if (alpha<128) alpha = 128; + MeshVertexColour[i] = colour + (alpha<<24); + } + + #if 1 + TranslatePointIntoViewspace(point); + #else + point->vx -= Global_VDB_Ptr->VDB_World.vx; + point->vy -= Global_VDB_Ptr->VDB_World.vy; + point->vz -= Global_VDB_Ptr->VDB_World.vz; + MeshWorldVertex[i] = *point; + RotateVector(point,&(Global_VDB_Ptr->VDB_Mat)); + point->vy = MUL_FIXED(point->vy,87381); + + #endif + /* is particle within normal view frustrum ? */ + if(AvP.PlayerType==I_Alien) /* wide frustrum */ + { + if(( (-point->vx <= point->vz*2) + &&(point->vx <= point->vz*2) + &&(-point->vy <= point->vz*2) + &&(point->vy <= point->vz*2) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + else + { + if(( (-point->vx <= point->vz) + &&(point->vx <= point->vz) + &&(-point->vy <= point->vz) + &&(point->vy <= point->vz) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + + { + // u + MeshWorldVertex[i].vx = (x*4096)/15; + // v + MeshWorldVertex[i].vy = (z*2048)/20; + + } + i++; + } + } + + D3DTEXTUREHANDLE TextureHandle = FMVTextureHandle[0]; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_GLOWING); + if (NumVertices) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZWRITEENABLE, FALSE, ExecBufInstPtr); + + if ((MeshVertexOutcode[0]&&MeshVertexOutcode[15]&&MeshVertexOutcode[240]&&MeshVertexOutcode[255])) + { + D3D_DrawMoltenMetalMesh_Unclipped(); + } + else +// else if (MeshVertexOutcode[0]||MeshVertexOutcode[15]||MeshVertexOutcode[240]||MeshVertexOutcode[255]) + { + D3D_DrawMoltenMetalMesh_Clipped(); + } + + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZWRITEENABLE, TRUE, ExecBufInstPtr); + +} + +void D3D_DrawMoltenMetal(int xOrigin, int yOrigin, int zOrigin) +{ + int i=0; + int x; + for (x=0; x<16; x++) + { + int z; + for(z=0; z<16; z++) + { + VECTORCH *point = &MeshVertex[i]; + + point->vx = xOrigin+(x*MeshXScale)/15; + point->vz = zOrigin+(z*MeshZScale)/15; + #if 0 + + int offset=0; + + offset = MUL_FIXED(32,GetSin( (point->vx+point->vz+CloakingPhase)&4095 ) ); + offset += MUL_FIXED(16,GetSin( (point->vx-point->vz*2+CloakingPhase/2)&4095 ) ); + { + float dx=point->vx-22704; + float dz=point->vz+20652; + float a = dx*dx+dz*dz; + a=sqrt(a); + + offset+= MUL_FIXED(200,GetSin( (((int)a-CloakingPhase)&4095) )); + } + #endif + #if 1 + int offset=0; + + /* basic noise ripples */ + offset = MUL_FIXED(128,GetSin( ((point->vx+point->vz)/16+CloakingPhase)&4095 ) ); + offset += MUL_FIXED(64,GetSin( ((point->vx-point->vz*2)/4+CloakingPhase/2)&4095 ) ); + offset += MUL_FIXED(64,GetSin( ((point->vx*5-point->vz)/32+CloakingPhase/5)&4095 ) ); + + #endif + if (offset>450) offset = 450; + if (offset<-1000) offset = -1000; + point->vy = yOrigin+offset; + + { + int shade = 191+(offset+256)/8; + MeshVertexColour[i] = RGBLIGHT_MAKE(shade,shade,shade); + } + + #if 1 + TranslatePointIntoViewspace(point); + #else + point->vx -= Global_VDB_Ptr->VDB_World.vx; + point->vy -= Global_VDB_Ptr->VDB_World.vy; + point->vz -= Global_VDB_Ptr->VDB_World.vz; + MeshWorldVertex[i] = *point; + RotateVector(point,&(Global_VDB_Ptr->VDB_Mat)); + point->vy = MUL_FIXED(point->vy,87381); + + #endif + /* is particle within normal view frustrum ? */ + if(AvP.PlayerType==I_Alien) /* wide frustrum */ + { + if(( (-point->vx <= point->vz*2) + &&(point->vx <= point->vz*2) + &&(-point->vy <= point->vz*2) + &&(point->vy <= point->vz*2) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + else + { + if(( (-point->vx <= point->vz) + &&(point->vx <= point->vz) + &&(-point->vy <= point->vz) + &&(point->vy <= point->vz) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + + #if 0 + { + // v + MeshWorldVertex[i].vy = (offset+256)*4; + // u + MeshWorldVertex[i].vx = ((MeshWorldVertex[i].vx)&4095); + + } + #else + { + Normalise(&MeshWorldVertex[i]); + // v + int theta = (MeshWorldVertex[i].vy+offset); + if (theta<0) theta=0; + if (theta>ONE_FIXED) theta=ONE_FIXED; + + // u + int arctan = ((atan2((double)MeshWorldVertex[i].vx,(double)MeshWorldVertex[i].vz)/ 6.28318530718))*4095; + MeshWorldVertex[i].vx = (arctan+offset)&4095; + + MeshWorldVertex[i].vy = ArcCos(theta); + + } + #endif + + + i++; + } + } + + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[StaticImageNumber].D3DHandle; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_OFF); + if (NumVertices) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + if ((MeshVertexOutcode[0]&&MeshVertexOutcode[15]&&MeshVertexOutcode[240]&&MeshVertexOutcode[255])) + { + D3D_DrawMoltenMetalMesh_Unclipped(); + } + else +// else if (MeshVertexOutcode[0]||MeshVertexOutcode[15]||MeshVertexOutcode[240]||MeshVertexOutcode[255]) + { + D3D_DrawMoltenMetalMesh_Clipped(); + } + + +} + +void D3D_DrawMoltenMetalMesh_Unclipped(void) +{ + float ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + VECTORCH *point = MeshVertex; + + VECTORCH *pointWS = MeshWorldVertex; + + int i; + for (i=0; i<256; i++) + { + + if (point->vz<=1) point->vz = 1; + int x = (point->vx*(Global_VDB_Ptr->VDB_ProjX+1))/point->vz+Global_VDB_Ptr->VDB_CentreX; + int y = (point->vy*(Global_VDB_Ptr->VDB_ProjY+1))/point->vz+Global_VDB_Ptr->VDB_CentreY; + // textprint("%d, %d\n",x,y); + #if 1 + { + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + } + #else + vertexPtr->sx=x; + vertexPtr->sy=y; + #endif + + + point->vz+=HeadUpDisplayZOffset; + float oneOverZ = ((float)(point->vz)-ZNear)/(float)(point->vz); + vertexPtr->color = MeshVertexColour[i]; + vertexPtr->specular = 0; + vertexPtr->sz = oneOverZ; + + vertexPtr->tu = pointWS->vx*WaterUScale+(1.0f/256.0f); + vertexPtr->tv = pointWS->vy*WaterVScale+(1.0f/256.0f); + vertexPtr->rhw = 1.0/point->vz; + + + NumVertices++; + vertexPtr++; + point++; + + pointWS++; + } + } + // textprint("numvertices %d\n",NumVertices); + + + /* + * Make sure that the triangle data (not OP) will be QWORD aligned + */ + if (QWORD_ALIGNED(ExecBufInstPtr)) + { + OP_NOP(ExecBufInstPtr); + } + + OP_TRIANGLE_LIST(450, ExecBufInstPtr); + /* CONSTRUCT POLYS */ + { + int x; + for (x=0; x<15; x++) + { + int y; + for(y=0; y<15; y++) + { + OUTPUT_TRIANGLE(0+x+(16*y),1+x+(16*y),16+x+(16*y), 256); + OUTPUT_TRIANGLE(1+x+(16*y),17+x+(16*y),16+x+(16*y), 256); + } + } + } + #if 1 + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + #endif +} +void D3D_DrawMoltenMetalMesh_Clipped(void) +{ + float ZNear = (float) (Global_VDB_Ptr->VDB_ClipZ * GlobalScale); + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + VECTORCH *point = MeshVertex; + + VECTORCH *pointWS = MeshWorldVertex; + + int i; + for (i=0; i<256; i++) + { + { + int z = point->vz; + if (z<=0) z = 1; + int x = (point->vx*(Global_VDB_Ptr->VDB_ProjX+1))/z+Global_VDB_Ptr->VDB_CentreX; + int y = (point->vy*(Global_VDB_Ptr->VDB_ProjY+1))/z+Global_VDB_Ptr->VDB_CentreY; + #if 1 + { + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + } + #else + vertexPtr->sx=x; + vertexPtr->sy=y; + #endif + + vertexPtr->tu = pointWS->vx*WaterUScale+(1.0f/256.0f); + vertexPtr->tv = pointWS->vy*WaterVScale+(1.0f/256.0f); + + point->vz+=HeadUpDisplayZOffset; + float oneOverZ = ((float)(z)-ZNear)/(float)(z); + vertexPtr->color = MeshVertexColour[i]; + vertexPtr->specular = 0; + vertexPtr->sz = oneOverZ; + vertexPtr->rhw = 1.0f/(float)z; + + } + NumVertices++; + vertexPtr++; + point++; + + pointWS++; + } + } +// textprint("numvertices %d\n",NumVertices); + /* CONSTRUCT POLYS */ + { +// OP_TRIANGLE_LIST(450, ExecBufInstPtr); + int x; + for (x=0; x<15; x++) + { + int y; + for(y=0; y<15; y++) + { + int p1 = 0+x+(16*y); + int p2 = 1+x+(16*y); + int p3 = 16+x+(16*y); + int p4 = 17+x+(16*y); + + #if 0 + if (MeshVertexOutcode[p1]&&MeshVertexOutcode[p2]&&MeshVertexOutcode[p3]) + { + OP_TRIANGLE_LIST(1, ExecBufInstPtr); + OUTPUT_TRIANGLE(p1,p2,p3, 256); + } + if (MeshVertexOutcode[p2]&&MeshVertexOutcode[p3]&&MeshVertexOutcode[p4]) + { + OP_TRIANGLE_LIST(1, ExecBufInstPtr); + OUTPUT_TRIANGLE(p2,p4,p3, 256); + } + #else + if (MeshVertexOutcode[p1]&&MeshVertexOutcode[p2]&&MeshVertexOutcode[p3]&&MeshVertexOutcode[p4]) + { + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(p1,p2,p3, 256); + OUTPUT_TRIANGLE(p2,p4,p3, 256); + } + + #endif + } + } + } + #if 1 + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + #endif + #if 1 + { +// OP_TRIANGLE_LIST(450, ExecBufInstPtr); + POLYHEADER fakeHeader; + + fakeHeader.PolyFlags = 0; + fakeHeader.PolyColour = 0; + RenderPolygon.TranslucencyMode = TRANSLUCENCY_NORMAL; + int x; + for (x=0; x<15; x++) + { + int y; + for(y=0; y<15; y++) + { + int p[4]; + p[0] = 0+x+(16*y); + p[1] = 1+x+(16*y); + p[2] = 17+x+(16*y); + p[3] = 16+x+(16*y); + + if (!(MeshVertexOutcode[p[0]]&&MeshVertexOutcode[p[1]]&&MeshVertexOutcode[p[2]]&&MeshVertexOutcode[p[3]])) + { + { + int i; + for (i=0; i<4; i++) + { + VerticesBuffer[i].X = MeshVertex[p[i]].vx; + VerticesBuffer[i].Y = MeshVertex[p[i]].vy; + VerticesBuffer[i].Z = MeshVertex[p[i]].vz; + VerticesBuffer[i].U = MeshWorldVertex[p[i]].vx*(WaterUScale*128.0f*65536.0f); + VerticesBuffer[i].V = MeshWorldVertex[p[i]].vy*(WaterVScale*128.0f*65536.0f); + + VerticesBuffer[i].A = (MeshVertexColour[p[i]]&0xff000000)>>24; + VerticesBuffer[i].R = (MeshVertexColour[p[i]]&0x00ff0000)>>16; + VerticesBuffer[i].G = (MeshVertexColour[p[i]]&0x0000ff00)>>8; + VerticesBuffer[i].B = MeshVertexColour[p[i]]&0x000000ff; + VerticesBuffer[i].SpecularR = 0; + VerticesBuffer[i].SpecularG = 0; + VerticesBuffer[i].SpecularB = 0; + } + RenderPolygon.NumberOfVertices=4; + } + { + int outcode = QuadWithinFrustrum(); + + if (outcode) + { + GouraudTexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) continue; + GouraudTexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) continue; + // D3D_ZBufferedGouraudPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + D3D_ZBufferedGouraudTexturedPolygon_Output(&fakeHeader,RenderPolygon.Vertices); + } + } + } + } + } + } + #endif + #if 1 + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + #endif +} + +void *DynamicImagePtr; + +#define NUMBER_OF_SMACK_SURFACES 4 +LPDIRECTDRAWSURFACE SrcDDSurface[NUMBER_OF_SMACK_SURFACES]; +LPDIRECT3DTEXTURE SrcTexture[NUMBER_OF_SMACK_SURFACES]; +void *SrcSurfacePtr[NUMBER_OF_SMACK_SURFACES]; + +LPDIRECTDRAWSURFACE DstDDSurface[NUMBER_OF_SMACK_SURFACES]={0,0,0}; +LPDIRECT3DTEXTURE DstTexture[NUMBER_OF_SMACK_SURFACES]={0,0,0}; +int CurrentSurface; + +void InitDrawTest(void) +{ +#if FMV_ON + DDSURFACEDESC ddsd; + int surface = NUMBER_OF_SMACK_SURFACES; + + while(surface--) + { + memcpy(&ddsd, &(d3d.TextureFormat[d3d.CurrentTextureFormat].ddsd), sizeof(ddsd)); + + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT); + ddsd.ddsCaps.dwCaps = (DDSCAPS_SYSTEMMEMORY|DDSCAPS_TEXTURE); + + ddsd.dwHeight = FMV_SIZE; + ddsd.dwWidth = FMV_SIZE; + + LastError = lpDD->CreateSurface(&ddsd, &SrcDDSurface[surface], NULL); + LOGDXERR(LastError); + + DDBLTFX ddbltfx; + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0;// (2<<11)+(26<<5)+8; + LastError=SrcDDSurface[surface]->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); + LOGDXERR(LastError); + + LastError = SrcDDSurface[surface]->QueryInterface(IID_IDirect3DTexture, (LPVOID*) &SrcTexture[surface]); + LOGDXERR(LastError); + + + { + int PalCaps; + + if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) + { + PalCaps = (DDPCAPS_8BIT | DDPCAPS_ALLOW256); + } + else if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) + { + PalCaps = DDPCAPS_4BIT; + } + else + { + PalCaps = 0; + } + + if (PalCaps) + { + LPDIRECTDRAWPALETTE destPalette = NULL; + LastError = lpDD->CreatePalette(PalCaps, FMVPalette[surface], &destPalette, NULL); + LOGDXERR(LastError); + + LastError = SrcDDSurface[surface]->SetPalette(destPalette); +// LastError = tempSurface->SetPalette(destPalette); + LOGDXERR(LastError); + } + } + + + + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + LastError = SrcDDSurface[surface]->Lock(NULL,&ddsd,0,NULL); + LOGDXERR(LastError); + + SrcSurfacePtr[surface] = (void*)ddsd.lpSurface; + + LastError = SrcDDSurface[surface]->Unlock(NULL); + LOGDXERR(LastError); + } + CurrentSurface=0; + + { + extern void InitFMV(void); + InitFMV(); + } + + FMVTextureHandle[0]=0; + FMVTextureHandle[1]=0; + FMVTextureHandle[2]=0; +#endif + +} + +void D3D_DrawFMV(int xOrigin, int yOrigin, int zOrigin) +{ + MeshXScale = 4096/8/3; + MeshZScale = 4096/8/3; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZWRITEENABLE, FALSE, ExecBufInstPtr); + + for (int field=0; field<3; field++) + { + for (int zfield=0; zfield<3; zfield++) + { + int i=0; + int x; + + for (x=(0+field*15); x<(16+field*15); x++) + { + int z; + for(z=0+zfield*15; z<16+zfield*15; z++) + { + VECTORCH *point = &MeshVertex[i]; + + point->vx = xOrigin+(x*MeshXScale); + point->vy = yOrigin+(z*MeshZScale); + + int offset; + offset = MUL_FIXED(128,GetSin( ((point->vx+point->vy)+CloakingPhase)&4095 ) ); + offset += MUL_FIXED(64,GetSin( ((point->vx-point->vy*2)+CloakingPhase/2)&4095 ) ); + offset += MUL_FIXED(64,GetSin( ((point->vx*5-point->vy)/2+CloakingPhase/5)&4095 ) ); + + point->vz = zOrigin+offset; + + { + int shade = 127+(offset+256)/4; + MeshVertexColour[i] = RGBALIGHT_MAKE(shade,shade,shade,192); + } + #if 0 + { + int sd; + int size=65536; + int theta = ((z*4096)/45)&4095; + int phi = ((x*2048)/45)&4095; + if (theta==0) sd = 0; + else sd = phi+theta; + if (phi==0 || phi==2048) sd = 0; + else sd = phi+theta; + + int outerRadius = MUL_FIXED(4000+offset,size); + + if (sd) + offset = MUL_FIXED((FastRandom()&511)-255,size); + + offset=0; + + point->vx = xOrigin+2000+MUL_FIXED(outerRadius+offset,MUL_FIXED(GetSin(theta),GetCos(phi))); + point->vy = yOrigin+MUL_FIXED(outerRadius+offset,MUL_FIXED(GetSin(theta),GetSin(phi))); + point->vz = zOrigin+MUL_FIXED(outerRadius+offset,GetCos(theta)); + } + #endif + MeshWorldVertex[i].vx = (x*4096/45); + MeshWorldVertex[i].vy = (z*2048/45); + + TranslatePointIntoViewspace(point); + + /* is particle within normal view frustrum ? */ + if(AvP.PlayerType==I_Alien) /* wide frustrum */ + { + if(( (-point->vx <= point->vz*2) + &&(point->vx <= point->vz*2) + &&(-point->vy <= point->vz*2) + &&(point->vy <= point->vz*2) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + else + { + if(( (-point->vx <= point->vz) + &&(point->vx <= point->vz) + &&(-point->vy <= point->vz) + &&(point->vy <= point->vz) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + + i++; + } + } + //textprint("\n"); + D3DTEXTUREHANDLE TextureHandle = FMVTextureHandle[0]; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL);//GLOWING); + if (NumVertices) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + if ((MeshVertexOutcode[0]&&MeshVertexOutcode[15]&&MeshVertexOutcode[240]&&MeshVertexOutcode[255])) + { + D3D_DrawMoltenMetalMesh_Unclipped(); + } + else +// else if (MeshVertexOutcode[0]||MeshVertexOutcode[15]||MeshVertexOutcode[240]||MeshVertexOutcode[255]) + { + D3D_DrawMoltenMetalMesh_Clipped(); + } +} } + + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZWRITEENABLE, TRUE, ExecBufInstPtr); +} + + +void RenderFMVParticle(int t, int o, VECTORCH *offsetPtr) +{ + { + VECTORCH translatedPosition = MeshVertex[o+t]; + translatedPosition.vx += offsetPtr->vx; + translatedPosition.vy += offsetPtr->vy; + translatedPosition.vz += offsetPtr->vz; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[0].X = translatedPosition.vx; + VerticesBuffer[0].Y = translatedPosition.vy; + VerticesBuffer[0].Z = translatedPosition.vz; + } + { + VECTORCH translatedPosition = MeshVertex[1+t]; + translatedPosition.vx += offsetPtr->vx; + translatedPosition.vy += offsetPtr->vy; + translatedPosition.vz += offsetPtr->vz; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[1].X = translatedPosition.vx; + VerticesBuffer[1].Y = translatedPosition.vy; + VerticesBuffer[1].Z = translatedPosition.vz; + } + { + VECTORCH translatedPosition = MeshVertex[16+t]; + translatedPosition.vx += offsetPtr->vx; + translatedPosition.vy += offsetPtr->vy; + translatedPosition.vz += offsetPtr->vz; + TranslatePointIntoViewspace(&translatedPosition); + VerticesBuffer[2].X = translatedPosition.vx; + VerticesBuffer[2].Y = translatedPosition.vy; + VerticesBuffer[2].Z = translatedPosition.vz; + } + { + int outcode = TriangleWithinFrustrum(); + + if (outcode) + { + /* setup */ + RenderPolygon.NumberOfVertices=3; + + VerticesBuffer[0].U = MeshWorldVertex[o+t].vx; + VerticesBuffer[0].V = MeshWorldVertex[o+t].vy; + VerticesBuffer[0].A = 192; + + VerticesBuffer[1].U = MeshWorldVertex[1+t].vx; + VerticesBuffer[1].V = MeshWorldVertex[1+t].vy; + VerticesBuffer[1].A = 192; + + VerticesBuffer[2].U = MeshWorldVertex[16+t].vx; + VerticesBuffer[2].V = MeshWorldVertex[16+t].vy; + VerticesBuffer[2].A = 192; + + + if (outcode!=2) + { + TexturedPolygon_ClipWithZ(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeX(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithNegativeY(); + if(RenderPolygon.NumberOfVertices<3) return; + TexturedPolygon_ClipWithPositiveX(); + if(RenderPolygon.NumberOfVertices<3) return; + D3D_FMVParticle_Output(RenderPolygon.Vertices); + } + else D3D_FMVParticle_Output(VerticesBuffer); + } + } +} + + +void D3D_DrawSwirlyFMV(int xOrigin, int yOrigin, int zOrigin) +{ + MeshXScale = 2048/8; + MeshZScale = (2048*3)/8/4; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZWRITEENABLE, FALSE, ExecBufInstPtr); + + int i=0; + int x; + + for (x=0; x<16; x++) + { + int z; + for(z=0; z<16; z++) + { + VECTORCH *point = &MeshVertex[i]; + + point->vz = zOrigin+(x*MeshXScale); + point->vy = yOrigin+(z*MeshZScale); + + int offset; + offset = MUL_FIXED(128,GetSin( ((point->vz+point->vy)+CloakingPhase)&4095 ) ); + offset += MUL_FIXED(64,GetSin( ((point->vz-point->vy*2)+CloakingPhase/2)&4095 ) ); + offset += MUL_FIXED(64,GetSin( ((point->vz*5-point->vy)/2+CloakingPhase/5)&4095 ) ); + + point->vx = xOrigin+offset; + + MeshWorldVertex[i].vx = ((15-x)*65536*128)/15; + MeshWorldVertex[i].vy = (z*49152*128)/15; + + + i++; + } + } + + for (x=0; x<15; x++) + { + int y; + for(y=0; y<15; y++) + { + int a = (x+y*15)*2; + int b = 1; + int o = x+y*16; + int t = 0; + do + { + int p = a+b; + + #if 1 + RenderFMVParticle(o,t,&FMVParticlePosition[p]); + #else + { + PARTICLE particle; + particle.ParticleID = PARTICLE_NONCOLLIDINGFLAME; + particle.Position = FMVParticleAbsPosition[p]; + particle.Colour = RGBA_MAKE(255,255,255,16); + particle.Size = 3000; + RenderParticle(&particle); + } + #endif + + FMVParticleAbsPosition[p] = MeshVertex[o+t]; + FMVParticleAbsPosition[p].vx += FMVParticlePosition[p].vx; + FMVParticleAbsPosition[p].vy += FMVParticlePosition[p].vy; + FMVParticleAbsPosition[p].vz += FMVParticlePosition[p].vz; + + t=17; + } + while(b--); + } + } + for(int p=0; p<450; p++) + { + #if 0 + if ((CloakingPhase&32767) > 16383) + { + int n=p+52; + int o=p+76; + if (n>449) n-=449; + if (o>449) o-=449; + + FMVParticlePosition[p].vx -= MUL_FIXED(FMVParticleAbsPosition[p].vx - FMVParticleAbsPosition[n].vx,NormalFrameTime*8); + FMVParticlePosition[p].vy -= MUL_FIXED(FMVParticleAbsPosition[p].vy - FMVParticleAbsPosition[n].vy,NormalFrameTime*8); + FMVParticlePosition[p].vz -= MUL_FIXED(FMVParticleAbsPosition[p].vz - FMVParticleAbsPosition[n].vz,NormalFrameTime*8); + FMVParticlePosition[p].vx += MUL_FIXED(FMVParticleAbsPosition[p].vx - FMVParticleAbsPosition[o].vx,NormalFrameTime/4); + FMVParticlePosition[p].vy += MUL_FIXED(FMVParticleAbsPosition[p].vy - FMVParticleAbsPosition[o].vy,NormalFrameTime/4); + FMVParticlePosition[p].vz += MUL_FIXED(FMVParticleAbsPosition[p].vz - FMVParticleAbsPosition[o].vz,NormalFrameTime/4); + + } + else + { + + FMVParticlePosition[p].vx -= MUL_FIXED(FMVParticlePosition[p].vx,NormalFrameTime*4); + FMVParticlePosition[p].vy -= MUL_FIXED(FMVParticlePosition[p].vy,NormalFrameTime*4); + FMVParticlePosition[p].vz -= MUL_FIXED(FMVParticlePosition[p].vz,NormalFrameTime*4); + + int m = Approximate3dMagnitude(&FMVParticlePosition[p]); + + if (m<=20) + { + FMVParticlePosition[p].vx = 0; + FMVParticlePosition[p].vy = 0; + FMVParticlePosition[p].vz = 0; + } + + } + #else + FMVParticlePosition[p].vx = 0; + FMVParticlePosition[p].vy = 0; + FMVParticlePosition[p].vz = 0; + #endif + } + + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZWRITEENABLE, TRUE, ExecBufInstPtr); +} + +static void UpdateFMVTextures(int maxTextureNumberToUpdate) +{ +#if FMV_ON + int surfaceNumber=maxTextureNumberToUpdate; + while(surfaceNumber--) + { + DDSURFACEDESC ddsd; + + + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + LastError = SrcDDSurface[surfaceNumber]->Lock(NULL,&ddsd,DDLOCK_WAIT,NULL); + LOGDXERR(LastError); + + { + if (!NextFMVFrame(SrcSurfacePtr[surfaceNumber],0,0,128,96, surfaceNumber)) + { + LastError = SrcDDSurface[surfaceNumber]->Unlock(NULL); + LOGDXERR(LastError); + return; + } + } + + LastError = SrcDDSurface[surfaceNumber]->Unlock(NULL); + LOGDXERR(LastError); + + if (DstDDSurface[surfaceNumber]) ReleaseDDSurface(DstDDSurface[surfaceNumber]); + if (DstTexture[surfaceNumber]) ReleaseD3DTexture(DstTexture[surfaceNumber]); + + // Query destination surface for a texture interface. + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + + LastError = SrcDDSurface[surfaceNumber]->GetSurfaceDesc(&ddsd); + LOGDXERR(LastError); + + ddsd.dwFlags = (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT); + ddsd.ddsCaps.dwCaps = (DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD ); + + LastError = lpDD->CreateSurface(&ddsd, &DstDDSurface[surfaceNumber], NULL); + LOGDXERR(LastError); + { + int PalCaps; + + if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) + { + PalCaps = (DDPCAPS_8BIT | DDPCAPS_ALLOW256); + } + else if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) + { + PalCaps = DDPCAPS_4BIT; + } + else + { + PalCaps = 0; + } + + if (PalCaps) + { + LPDIRECTDRAWPALETTE destPalette = NULL; + + LastError = lpDD->CreatePalette(PalCaps, FMVPalette[surfaceNumber], &destPalette, NULL); + LOGDXERR(LastError); + + UpdateFMVPalette(FMVPalette[surfaceNumber],surfaceNumber); + LastError = DstDDSurface[surfaceNumber]->SetPalette(destPalette); + LOGDXERR(LastError); + LastError = SrcDDSurface[surfaceNumber]->SetPalette(destPalette); + LOGDXERR(LastError); + + } + } + LastError = DstDDSurface[surfaceNumber]->QueryInterface(IID_IDirect3DTexture,(LPVOID*) &DstTexture[surfaceNumber]); + LOGDXERR(LastError); + + LastError = DstTexture[surfaceNumber]->Load(SrcTexture[surfaceNumber]); + LOGDXERR(LastError); + + LastError = DstTexture[surfaceNumber]->GetHandle(d3d.lpD3DDevice, &FMVTextureHandle[surfaceNumber]); + LOGDXERR(LastError); + } +#endif +} + + +void KillFMVTexture(void) +{ + int surface = NUMBER_OF_SMACK_SURFACES; + + while(surface--) + { + RELEASE(SrcDDSurface[surface]); + RELEASE(SrcTexture[surface]); + RELEASE(DstDDSurface[surface]); + RELEASE(DstTexture[surface]); + } + +} + + +void ThisFramesRenderingHasBegun(void) +{ + if (ScanDrawMode != ScanDrawDirectDraw) + { + BeginD3DScene(); + LockExecuteBuffer(); + D3D_SetupSceneDefaults(); + } + else + { + LockSurfaceAndGetBufferPointer(); + } +} + +void ThisFramesRenderingHasFinished(void) +{ + if (ScanDrawMode != ScanDrawDirectDraw) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + EndD3DScene(); + } + + /* KJL 11:46:56 01/16/97 - kill off any lights which are fated to be removed */ + LightBlockDeallocation(); + +} +void D3D_DrawWaterOctagonPatch(int xOrigin, int yOrigin, int zOrigin, int xOffset, int zOffset) +{ + float grad = 2.414213562373; + int i=0; + int x; + for (x=xOffset; x<16+xOffset; x++) + { + int z; + for(z=zOffset; z<16+zOffset; z++) + { + VECTORCH *point = &MeshVertex[i]; + + if (x>z) + { + float m,xs; + if (x!=0) + { + m = (float)(z)/(float)(x); + xs = grad/(grad+m); + } + else + { + xs = 0; + } + #if 1 + f2i(point->vx , xs*x*MeshXScale); + f2i(point->vz , (grad-grad*xs)*x*MeshZScale); + #else + point->vx = xs*x*MeshXScale; + point->vz = (grad-grad*xs)*x*MeshZScale; + #endif + } + else + { + float m,xs; + if (z!=0) + { + m = (float)(x)/(float)(z); + xs = grad/(grad+m); + } + else + { + xs = 0; + } + #if 1 + f2i(point->vz , xs*z*MeshZScale); + f2i(point->vx , (grad-grad*xs)*z*MeshXScale); + #else + point->vz = xs*z*MeshZScale; + point->vx = (grad-grad*xs)*z*MeshXScale; + #endif + } + + point->vx += xOrigin; + point->vz += zOrigin; + + int offset = EffectOfRipples(point); + + point->vy = yOrigin+offset; + + #if 0 + MeshVertexColour[i] = LightSourceWaterPoint(point,offset); + #else + { + int alpha = 128-offset/4; + // if (alpha>255) alpha = 255; + // if (alpha<128) alpha = 128; + switch (CurrentVisionMode) + { + default: + case VISION_MODE_NORMAL: + { + MeshVertexColour[i] = RGBALIGHT_MAKE(10,51,28,alpha); + break; + } + case VISION_MODE_IMAGEINTENSIFIER: + { + MeshVertexColour[i] = RGBALIGHT_MAKE(0,51,0,alpha); + break; + } + case VISION_MODE_PRED_THERMAL: + case VISION_MODE_PRED_SEEALIENS: + case VISION_MODE_PRED_SEEPREDTECH: + { + MeshVertexColour[i] = RGBALIGHT_MAKE(0,0,28,alpha); + break; + } + } + + } + #endif + TranslatePointIntoViewspace(point); + /* is particle within normal view frustrum ? */ + if(AvP.PlayerType==I_Alien) /* wide frustrum */ + { + if(( (-point->vx <= point->vz*2) + &&(point->vx <= point->vz*2) + &&(-point->vy <= point->vz*2) + &&(point->vy <= point->vz*2) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + else + { + if(( (-point->vx <= point->vz) + &&(point->vx <= point->vz) + &&(-point->vy <= point->vz) + &&(point->vy <= point->vz) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + + i++; + } + } + + if ((MeshVertexOutcode[0]&&MeshVertexOutcode[15]&&MeshVertexOutcode[240]&&MeshVertexOutcode[255])) + { + D3D_DrawWaterMesh_Unclipped(); + } + else +// else if (MeshVertexOutcode[0]||MeshVertexOutcode[15]||MeshVertexOutcode[240]||MeshVertexOutcode[255]) + { + D3D_DrawWaterMesh_Clipped(); + } + + +} + + +extern void D3D_DrawSliderBar(int x, int y, int alpha) +{ + struct VertexTag quadVertices[4]; + int sliderHeight = 11; + unsigned int colour = alpha>>8; + + if (colour>255) colour = 255; + colour = (colour<<24)+0xffffff; + + quadVertices[0].Y = y; + quadVertices[1].Y = y; + quadVertices[2].Y = y + sliderHeight; + quadVertices[3].Y = y + sliderHeight; + + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_OFF); + { + int topLeftU = 1; + int topLeftV = 68; + + quadVertices[0].U = topLeftU; + quadVertices[0].V = topLeftV; + quadVertices[1].U = topLeftU + 2; + quadVertices[1].V = topLeftV; + quadVertices[2].U = topLeftU + 2; + quadVertices[2].V = topLeftV + sliderHeight; + quadVertices[3].U = topLeftU; + quadVertices[3].V = topLeftV + sliderHeight; + + quadVertices[0].X = x; + quadVertices[3].X = x; + quadVertices[1].X = x + 2; + quadVertices[2].X = x + 2; + + D3D_HUDQuad_Output + ( + HUDFontsImageNumber, + quadVertices, + colour + ); + } + { + int topLeftU = 7; + int topLeftV = 68; + + quadVertices[0].U = topLeftU; + quadVertices[0].V = topLeftV; + quadVertices[1].U = topLeftU + 2; + quadVertices[1].V = topLeftV; + quadVertices[2].U = topLeftU + 2; + quadVertices[2].V = topLeftV + sliderHeight; + quadVertices[3].U = topLeftU; + quadVertices[3].V = topLeftV + sliderHeight; + + quadVertices[0].X = x+213+2; + quadVertices[3].X = x+213+2; + quadVertices[1].X = x+2 +213+2; + quadVertices[2].X = x+2 +213+2; + + D3D_HUDQuad_Output + ( + HUDFontsImageNumber, + quadVertices, + colour + ); + } + quadVertices[2].Y = y + 2; + quadVertices[3].Y = y + 2; + + { + int topLeftU = 5; + int topLeftV = 77; + + quadVertices[0].U = topLeftU; + quadVertices[0].V = topLeftV; + quadVertices[1].U = topLeftU; + quadVertices[1].V = topLeftV; + quadVertices[2].U = topLeftU; + quadVertices[2].V = topLeftV + 2; + quadVertices[3].U = topLeftU; + quadVertices[3].V = topLeftV + 2; + + quadVertices[0].X = x + 2; + quadVertices[3].X = x + 2; + quadVertices[1].X = x + 215; + quadVertices[2].X = x + 215; + + D3D_HUDQuad_Output + ( + HUDFontsImageNumber, + quadVertices, + colour + ); + } + quadVertices[0].Y = y + 9; + quadVertices[1].Y = y + 9; + quadVertices[2].Y = y + 11; + quadVertices[3].Y = y + 11; + + { + int topLeftU = 5; + int topLeftV = 77; + + quadVertices[0].U = topLeftU; + quadVertices[0].V = topLeftV; + quadVertices[1].U = topLeftU; + quadVertices[1].V = topLeftV; + quadVertices[2].U = topLeftU; + quadVertices[2].V = topLeftV + 2; + quadVertices[3].U = topLeftU; + quadVertices[3].V = topLeftV + 2; + + quadVertices[0].X = x + 2; + quadVertices[3].X = x + 2; + quadVertices[1].X = x + 215; + quadVertices[2].X = x + 215; + + D3D_HUDQuad_Output + ( + HUDFontsImageNumber, + quadVertices, + colour + ); + } + + + +} + +extern void D3D_DrawSlider(int x, int y, int alpha) +{ + struct VertexTag quadVertices[4]; + int sliderHeight = 5; + unsigned int colour = alpha>>8; + + if (colour>255) colour = 255; + colour = (colour<<24)+0xffffff; + + quadVertices[0].Y = y; + quadVertices[1].Y = y; + quadVertices[2].Y = y + sliderHeight; + quadVertices[3].Y = y + sliderHeight; + + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_OFF); + { + int topLeftU = 11; + int topLeftV = 74; + + quadVertices[0].U = topLeftU; + quadVertices[0].V = topLeftV; + quadVertices[1].U = topLeftU + 9; + quadVertices[1].V = topLeftV; + quadVertices[2].U = topLeftU + 9; + quadVertices[2].V = topLeftV + sliderHeight; + quadVertices[3].U = topLeftU; + quadVertices[3].V = topLeftV + sliderHeight; + + quadVertices[0].X = x; + quadVertices[3].X = x; + quadVertices[1].X = x + 9; + quadVertices[2].X = x + 9; + + D3D_HUDQuad_Output + ( + HUDFontsImageNumber, + quadVertices, + colour + ); + } +} + +void DrawFontTest(void) +{ + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_OFF); + + struct VertexTag quadVertices[4]; + + quadVertices[0].Y = 0; + quadVertices[1].Y = 0; + quadVertices[2].Y = 256; + quadVertices[3].Y = 256; + + quadVertices[0].U = 0; + quadVertices[0].V = 0; + quadVertices[1].U = 256; + quadVertices[1].V = 0; + quadVertices[2].U = 256; + quadVertices[2].V = 256; + quadVertices[3].U = 0; + quadVertices[3].V = 256; + + quadVertices[0].X = 0; + quadVertices[3].X = 0; + quadVertices[1].X = 256; + quadVertices[2].X = 256; + + D3D_HUDQuad_Output + ( + AAFontImageNumber, + quadVertices, + 0xffffffff + ); +} +extern void D3D_DrawRectangle(int x, int y, int w, int h, int alpha) +{ + struct VertexTag quadVertices[4]; + int sliderHeight = 11; + unsigned int colour = alpha>>8; + + if (colour>255) colour = 255; + colour = (colour<<24)+0xffffff; + + quadVertices[0].Y = y; + quadVertices[1].Y = y; + quadVertices[2].Y = y + 6; + quadVertices[3].Y = y + 6; + + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_OFF); + /* top left corner */ + { + int topLeftU = 1; + int topLeftV = 238; + + quadVertices[0].U = topLeftU; + quadVertices[0].V = topLeftV; + quadVertices[1].U = topLeftU + 6; + quadVertices[1].V = topLeftV; + quadVertices[2].U = topLeftU + 6; + quadVertices[2].V = topLeftV + 6; + quadVertices[3].U = topLeftU; + quadVertices[3].V = topLeftV + 6; + + quadVertices[0].X = x; + quadVertices[3].X = x; + quadVertices[1].X = x + 6; + quadVertices[2].X = x + 6; + + D3D_HUDQuad_Output + ( + AAFontImageNumber, + quadVertices, + colour + ); + } + /* top */ + { + int topLeftU = 9; + int topLeftV = 238; + + quadVertices[0].U = topLeftU; + quadVertices[0].V = topLeftV; + quadVertices[1].U = topLeftU; + quadVertices[1].V = topLeftV; + quadVertices[2].U = topLeftU; + quadVertices[2].V = topLeftV + 6; + quadVertices[3].U = topLeftU; + quadVertices[3].V = topLeftV + 6; + + quadVertices[0].X = x+6; + quadVertices[3].X = x+6; + quadVertices[1].X = x+6 + w-12; + quadVertices[2].X = x+6 + w-12; + + D3D_HUDQuad_Output + ( + AAFontImageNumber, + quadVertices, + colour + ); + } + /* top right corner */ + { + int topLeftU = 11; + int topLeftV = 238; + + quadVertices[0].U = topLeftU; + quadVertices[0].V = topLeftV; + quadVertices[1].U = topLeftU + 6; + quadVertices[1].V = topLeftV; + quadVertices[2].U = topLeftU + 6; + quadVertices[2].V = topLeftV + 6; + quadVertices[3].U = topLeftU; + quadVertices[3].V = topLeftV + 6; + + quadVertices[0].X = x + w - 6; + quadVertices[3].X = x + w - 6; + quadVertices[1].X = x + w; + quadVertices[2].X = x + w; + + D3D_HUDQuad_Output + ( + AAFontImageNumber, + quadVertices, + colour + ); + } + quadVertices[0].Y = y + 6; + quadVertices[1].Y = y + 6; + quadVertices[2].Y = y + h - 6; + quadVertices[3].Y = y + h - 6; + /* right */ + { + int topLeftU = 1; + int topLeftV = 246; + + quadVertices[0].U = topLeftU; + quadVertices[0].V = topLeftV; + quadVertices[1].U = topLeftU + 6; + quadVertices[1].V = topLeftV; + quadVertices[2].U = topLeftU + 6; + quadVertices[2].V = topLeftV; + quadVertices[3].U = topLeftU; + quadVertices[3].V = topLeftV; + + D3D_HUDQuad_Output + ( + AAFontImageNumber, + quadVertices, + colour + ); + } + /* left */ + { + int topLeftU = 1; + int topLeftV = 246; + + quadVertices[0].U = topLeftU; + quadVertices[0].V = topLeftV; + quadVertices[1].U = topLeftU + 6; + quadVertices[1].V = topLeftV; + quadVertices[2].U = topLeftU + 6; + quadVertices[2].V = topLeftV; + quadVertices[3].U = topLeftU; + quadVertices[3].V = topLeftV; + + quadVertices[0].X = x; + quadVertices[3].X = x; + quadVertices[1].X = x + 6; + quadVertices[2].X = x + 6; + + D3D_HUDQuad_Output + ( + AAFontImageNumber, + quadVertices, + colour + ); + } + quadVertices[0].Y = y + h - 6; + quadVertices[1].Y = y + h - 6; + quadVertices[2].Y = y + h; + quadVertices[3].Y = y + h; + /* bottom left corner */ + { + int topLeftU = 1; + int topLeftV = 248; + + quadVertices[0].U = topLeftU; + quadVertices[0].V = topLeftV; + quadVertices[1].U = topLeftU + 6; + quadVertices[1].V = topLeftV; + quadVertices[2].U = topLeftU + 6; + quadVertices[2].V = topLeftV + 6; + quadVertices[3].U = topLeftU; + quadVertices[3].V = topLeftV + 6; + + quadVertices[0].X = x; + quadVertices[3].X = x; + quadVertices[1].X = x + 6; + quadVertices[2].X = x + 6; + + D3D_HUDQuad_Output + ( + AAFontImageNumber, + quadVertices, + colour + ); + } + /* bottom */ + { + int topLeftU = 9; + int topLeftV = 238; + + quadVertices[0].U = topLeftU; + quadVertices[0].V = topLeftV; + quadVertices[1].U = topLeftU; + quadVertices[1].V = topLeftV; + quadVertices[2].U = topLeftU; + quadVertices[2].V = topLeftV + 6; + quadVertices[3].U = topLeftU; + quadVertices[3].V = topLeftV + 6; + + quadVertices[0].X = x+6; + quadVertices[3].X = x+6; + quadVertices[1].X = x+6 + w-12; + quadVertices[2].X = x+6 + w-12; + + D3D_HUDQuad_Output + ( + AAFontImageNumber, + quadVertices, + colour + ); + } + /* bottom right corner */ + { + int topLeftU = 11; + int topLeftV = 248; + + quadVertices[0].U = topLeftU; + quadVertices[0].V = topLeftV; + quadVertices[1].U = topLeftU + 6; + quadVertices[1].V = topLeftV; + quadVertices[2].U = topLeftU + 6; + quadVertices[2].V = topLeftV + 6; + quadVertices[3].U = topLeftU; + quadVertices[3].V = topLeftV + 6; + + quadVertices[0].X = x + w - 6; + quadVertices[3].X = x + w - 6; + quadVertices[1].X = x + w; + quadVertices[2].X = x + w; + + D3D_HUDQuad_Output + ( + AAFontImageNumber, + quadVertices, + colour + ); + } + + +} +extern void D3D_DrawColourBar(int yTop, int yBottom, int rScale, int gScale, int bScale) +{ + extern unsigned char GammaValues[256]; + + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_OFF); + if (CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NULL, ExecBufInstPtr); + CurrTextureHandle = NULL; + } + + for (int i=0; i<255; ) + { + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + unsigned int colour; + unsigned int c; + + c = GammaValues[i]; + colour = RGBA_MAKE(MUL_FIXED(c,rScale),MUL_FIXED(c,gScale),MUL_FIXED(c,bScale),0); + vertexPtr->sx = (Global_VDB_Ptr->VDB_ClipRight*i)/255; + vertexPtr->sy = yTop; + vertexPtr->sz = 0; + vertexPtr->color = colour; + vertexPtr++; + vertexPtr->sx = (Global_VDB_Ptr->VDB_ClipRight*i)/255; + vertexPtr->sy = yBottom; + vertexPtr->sz = 0; + vertexPtr->color = colour; + vertexPtr++; + + i++; + c = GammaValues[i]; + colour = RGBA_MAKE(MUL_FIXED(c,rScale),MUL_FIXED(c,gScale),MUL_FIXED(c,bScale),0); + vertexPtr->sx = (Global_VDB_Ptr->VDB_ClipRight*i)/255; + vertexPtr->sy = yBottom; + vertexPtr->sz = 0; + vertexPtr->color = colour; + vertexPtr++; + vertexPtr->sx = (Global_VDB_Ptr->VDB_ClipRight*i)/255; + vertexPtr->sy = yTop; + vertexPtr->sz = 0; + vertexPtr->color = colour; + vertexPtr++; + + NumVertices+=4; + } + + + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + } +} + + +extern void D3D_FadeDownScreen(int brightness, int colour) +{ + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + int t = 255 - (brightness>>8); + if (t<0) t = 0; + + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 0; + vertexPtr->color = (t<<24)+colour; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 0; + vertexPtr->color = (t<<24)+colour; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 0; + vertexPtr->color = (t<<24)+colour; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 0; + vertexPtr->color = (t<<24)+colour; + + NumVertices+=4; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_NORMAL); +// CheckFilteringModeIsCorrect(FILTERING_BILINEAR_ON); + + // NoiseTextureHandle = 0; + if (CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NULL, ExecBufInstPtr); + CurrTextureHandle = NULL; + } + + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } +} +extern void ClearZBufferWithPolygon(void) +{ + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1; + vertexPtr->color = 0; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1; + vertexPtr->color = 0; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1; + vertexPtr->color = 0; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1; + vertexPtr->color = 0; + + NumVertices+=4; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_JUSTSETZ); + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZFUNC, D3DCMP_ALWAYS, ExecBufInstPtr); + + D3DTEXTUREHANDLE TextureHandle = 0; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL, ExecBufInstPtr); + + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } +} + +extern void D3D_PlayerOnFireOverlay(void) +{ + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + int t = 128; + int colour = (FMVParticleColour&0xffffff)+(t<<24); + + float u = (FastRandom()&255)/256.0f; + float v = (FastRandom()&255)/256.0f; + + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 0; + vertexPtr->rhw = 1; + vertexPtr->tu = u; + vertexPtr->tv = v; + vertexPtr->color = colour; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 0; + vertexPtr->rhw = 1; + vertexPtr->tu = u+1.0f; + vertexPtr->tv = v; + vertexPtr->color = colour; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 0; + vertexPtr->rhw = 1; + vertexPtr->tu = u+1.0f; + vertexPtr->tv = v+1.0f; + vertexPtr->color = colour; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 0; + vertexPtr->rhw = 1; + vertexPtr->tu = u; + vertexPtr->tv = v+1.0f; + vertexPtr->color = colour; + + NumVertices+=4; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_GLOWING); + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_ON); + + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[BurningImageNumber].D3DHandle; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } +} +extern void D3D_ScreenInversionOverlay(void) +{ + int theta[2]; + int colour = 0xffffffff; + int i; + + theta[0] = (CloakingPhase/8)&4095; + theta[1] = (800-CloakingPhase/8)&4095; + + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_DARKENINGCOLOUR); + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_ON); + + for (i=0; i<2; i++) + { + float sin = (GetSin(theta[i]))/65536.0f/16.0f; + float cos = (GetCos(theta[i]))/65536.0f/16.0f; + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 0; + vertexPtr->rhw = 1; + vertexPtr->tu = 0.375 + (cos*(-1) - sin*(-1)); + vertexPtr->tv = 0.375 + (sin*(-1) + cos*(-1)); + vertexPtr->color = colour; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 0; + vertexPtr->rhw = 1; + vertexPtr->tu = .375 + (cos*(+1) - sin*(-1)); + vertexPtr->tv = .375 + (sin*(+1) + cos*(-1)); + vertexPtr->color = colour; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 0; + vertexPtr->rhw = 1; + vertexPtr->tu = .375 + (cos*(+1) - sin*(+1)); + vertexPtr->tv = .375 + (sin*(+1) + cos*(+1)); + vertexPtr->color = colour; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 0; + vertexPtr->rhw = 1; + vertexPtr->tu = .375 + (cos*(-1) - sin*(+1)); + vertexPtr->tv = .375 + (sin*(-1) + cos*(+1)); + vertexPtr->color = colour; + + NumVertices+=4; + } + + // D3DTEXTUREHANDLE TextureHandle = NULL; + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[SpecialFXImageNumber].D3DHandle; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_COLOUR); + } +} +extern void D3D_PredatorScreenInversionOverlay(void) +{ + int colour = 0xffffffff; + int i; + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1.0f; + vertexPtr->color = colour; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1.0f; + vertexPtr->color = colour; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1.0f; + vertexPtr->color = colour; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 1.0f; + vertexPtr->rhw = 1.0f; + vertexPtr->color = colour; + + NumVertices+=4; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_DARKENINGCOLOUR); + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_ON); + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZFUNC, D3DCMP_ALWAYS, ExecBufInstPtr); + +// D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[StaticImageNumber].D3DHandle; + D3DTEXTUREHANDLE TextureHandle = NULL; +// D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[SpecialFXImageNumber].D3DHandle; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZFUNC, D3DCMP_LESSEQUAL, ExecBufInstPtr); + + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } +} +extern void D3D_PlayerDamagedOverlay(int intensity) +{ + int theta[2]; +// int colour = 0x00ffff + (intensity<<24); + int colour,baseColour; + int i; + + theta[0] = (CloakingPhase/8)&4095; + theta[1] = (800-CloakingPhase/8)&4095; + + switch(AvP.PlayerType) + { + default: + LOCALASSERT(0); + /* if no debug then fall through to marine */ + case I_Marine: + baseColour = 0xff0000; + break; + + case I_Alien: + baseColour = 0xffff00; + break; + + case I_Predator: + baseColour = 0x00ff00; + break; + } + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_INVCOLOUR); + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_ON); + colour = 0xffffff - baseColour + (intensity<<24); + for(i=0; i<=1; i++) + { + float sin = (GetSin(theta[i]))/65536.0f/16.0f; + float cos = (GetCos(theta[i]))/65536.0f/16.0f; + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 0; + vertexPtr->rhw = 1; + vertexPtr->tu = 0.875 + (cos*(-1) - sin*(-1)); + vertexPtr->tv = 0.375 + (sin*(-1) + cos*(-1)); + vertexPtr->color = colour; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipUp; + vertexPtr->sz = 0; + vertexPtr->rhw = 1; + vertexPtr->tu = .875 + (cos*(+1) - sin*(-1)); + vertexPtr->tv = .375 + (sin*(+1) + cos*(-1)); + vertexPtr->color = colour; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipRight; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 0; + vertexPtr->rhw = 1; + vertexPtr->tu = .875 + (cos*(+1) - sin*(+1)); + vertexPtr->tv = .375 + (sin*(+1) + cos*(+1)); + vertexPtr->color = colour; + vertexPtr++; + vertexPtr->sx = Global_VDB_Ptr->VDB_ClipLeft; + vertexPtr->sy = Global_VDB_Ptr->VDB_ClipDown; + vertexPtr->sz = 0; + vertexPtr->rhw = 1; + vertexPtr->tu = .875 + (cos*(-1) - sin*(+1)); + vertexPtr->tv = .375 + (sin*(-1) + cos*(+1)); + vertexPtr->color = colour; + + NumVertices+=4; + } + + // D3DTEXTUREHANDLE TextureHandle = NULL; + D3DTEXTUREHANDLE TextureHandle = (D3DTEXTUREHANDLE)ImageHeaderArray[SpecialFXImageNumber].D3DHandle; + if (CurrTextureHandle != TextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + +// colour = 0xff0000+(intensity<<24); + colour = baseColour +(intensity<<24); + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_GLOWING); + } +} + +#define NUMBER_OF_CABLE_SEGMENTS 25 +int CableTheta[NUMBER_OF_CABLE_SEGMENTS]; +int CablePhi[NUMBER_OF_CABLE_SEGMENTS]; + +int CableThetaVelocity[NUMBER_OF_CABLE_SEGMENTS]; +int CablePhiVelocity[NUMBER_OF_CABLE_SEGMENTS]; + +VECTORCH CableForce[NUMBER_OF_CABLE_SEGMENTS]; +VECTORCH CableDirection[NUMBER_OF_CABLE_SEGMENTS]; +VECTORCH CableThetaDirection[NUMBER_OF_CABLE_SEGMENTS]; +VECTORCH CablePhiDirection[NUMBER_OF_CABLE_SEGMENTS]; + +extern void MakeMatrixFromDirection(VECTORCH *directionPtr, MATRIXCH *matrixPtr); + +void D3D_DrawCable(VECTORCH *centrePtr, MATRIXCH *orientationPtr) +{ + { + // Turn OFF texturing if it is on... + if (CurrTextureHandle != NULL) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, NULL, ExecBufInstPtr); + CurrTextureHandle = NULL; + } + + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_GLOWING); + + if (NumVertices) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZWRITEENABLE, FALSE, ExecBufInstPtr); + + } + MeshXScale = 4096/16; + MeshZScale = 4096/16; + + for (int field=0; field<3; field++) + { + int i=0; + int x; + for (x=(0+field*15); x<(16+field*15); x++) + { + int z; + for(z=0; z<16; z++) + { + VECTORCH *point = &MeshVertex[i]; + { + int innerRadius = 20; + VECTORCH radius; + int theta = ((4096*z)/15)&4095; + int rOffset = GetSin((x*64+theta/32-CloakingPhase)&4095); + rOffset = MUL_FIXED(rOffset,rOffset)/512; + + + radius.vx = MUL_FIXED(innerRadius+rOffset/8,GetSin(theta)); + radius.vy = MUL_FIXED(innerRadius+rOffset/8,GetCos(theta)); + radius.vz = 0; + + RotateVector(&radius,orientationPtr); + + point->vx = centrePtr[x].vx+radius.vx; + point->vy = centrePtr[x].vy+radius.vy; + point->vz = centrePtr[x].vz+radius.vz; + + MeshVertexColour[i] = RGBALIGHT_MAKE(0,rOffset,255,128); + + } + + TranslatePointIntoViewspace(point); + + /* is particle within normal view frustrum ? */ + if(AvP.PlayerType==I_Alien) /* wide frustrum */ + { + if(( (-point->vx <= point->vz*2) + &&(point->vx <= point->vz*2) + &&(-point->vy <= point->vz*2) + &&(point->vy <= point->vz*2) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + else + { + if(( (-point->vx <= point->vz) + &&(point->vx <= point->vz) + &&(-point->vy <= point->vz) + &&(point->vy <= point->vz) )) + { + MeshVertexOutcode[i]=1; + } + else + { + MeshVertexOutcode[i]=0; + } + } + + i++; + } + } + //textprint("\n"); + if ((MeshVertexOutcode[0]&&MeshVertexOutcode[15]&&MeshVertexOutcode[240]&&MeshVertexOutcode[255])) + { + D3D_DrawMoltenMetalMesh_Unclipped(); + // D3D_DrawWaterMesh_Unclipped(); + } + else +// else if (MeshVertexOutcode[0]||MeshVertexOutcode[15]||MeshVertexOutcode[240]||MeshVertexOutcode[255]) + { + D3D_DrawMoltenMetalMesh_Clipped(); + // D3D_DrawWaterMesh_Clipped(); + } + } + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_ZWRITEENABLE, TRUE, ExecBufInstPtr); +} + + + +void SetupFMVTexture(FMVTEXTURE *ftPtr) +{ + DDSURFACEDESC ddsd; + memcpy(&ddsd, &(d3d.TextureFormat[d3d.CurrentTextureFormat].ddsd), sizeof(ddsd)); + + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT); + ddsd.ddsCaps.dwCaps = (DDSCAPS_SYSTEMMEMORY|DDSCAPS_TEXTURE); + + ddsd.dwHeight = FMV_SIZE; + ddsd.dwWidth = FMV_SIZE; + + LastError = lpDD->CreateSurface(&ddsd, &(ftPtr->SrcSurface), NULL); + LOGDXERR(LastError); + + DDBLTFX ddbltfx; + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0;// (2<<11)+(26<<5)+8; + LastError=(ftPtr->SrcSurface)->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); + LOGDXERR(LastError); + + LastError = (ftPtr->SrcSurface)->QueryInterface(IID_IDirect3DTexture, (LPVOID*) &(ftPtr->SrcTexture)); + LOGDXERR(LastError); + + + { + int PalCaps; + + if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) + { + PalCaps = (DDPCAPS_8BIT | DDPCAPS_ALLOW256); + } + else if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) + { + PalCaps = DDPCAPS_4BIT; + } + else + { + PalCaps = 0; + } + + if (PalCaps) + { + LPDIRECTDRAWPALETTE destPalette = NULL; + LastError = lpDD->CreatePalette(PalCaps, ftPtr->SrcPalette, &destPalette, NULL); + LOGDXERR(LastError); + + LastError = (ftPtr->SrcSurface)->SetPalette(destPalette); +// LastError = tempSurface->SetPalette(destPalette); + LOGDXERR(LastError); + } + } + ftPtr->DestTexture = 0; + ftPtr->SoundVolume = 0; +} + + + +void UpdateFMVTexture(FMVTEXTURE *ftPtr) +{ + LPDIRECTDRAWSURFACE destSurface = NULL; + LOCALASSERT(ftPtr); + LOCALASSERT(ftPtr->ImagePtr); + LPDIRECTDRAWSURFACE srcSurface = ftPtr->SrcSurface; + LPDIRECT3DTEXTURE srcTexture = ftPtr->SrcTexture; + + LOCALASSERT(srcSurface); + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + + LastError = srcSurface->Lock(NULL,&ddsd,DDLOCK_WAIT,NULL); + + // check for success + { + if (!NextFMVTextureFrame(ftPtr,(void*)ddsd.lpSurface)) + { + LastError = srcSurface->Unlock(NULL); + LOGDXERR(LastError); + return; + } + } + + LastError = srcSurface->Unlock(NULL); + LOGDXERR(LastError); + + if (ftPtr->DestTexture) + { + ReleaseD3DTexture(ftPtr->DestTexture); + ftPtr->DestTexture = 0; + } + + // Query destination surface for a texture interface. + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + + LastError = srcSurface->GetSurfaceDesc(&ddsd); + LOGDXERR(LastError); + + ddsd.dwFlags = (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT); + ddsd.ddsCaps.dwCaps = (DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD ); + + LastError = lpDD->CreateSurface(&ddsd, &destSurface, NULL); + LOGDXERR(LastError); + { + int PalCaps; + + if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) + { + PalCaps = (DDPCAPS_8BIT | DDPCAPS_ALLOW256); + } + else if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) + { + PalCaps = DDPCAPS_4BIT; + } + else + { + PalCaps = 0; + } + + #if 1 + if (PalCaps) + { + LPDIRECTDRAWPALETTE destPalette = NULL; + + LastError = lpDD->CreatePalette(PalCaps, ftPtr->SrcPalette, &destPalette, NULL); + LOGDXERR(LastError); + UpdateFMVTexturePalette(ftPtr); + LastError = destSurface->SetPalette(destPalette); + LOGDXERR(LastError); + LastError = srcSurface->SetPalette(destPalette); + LOGDXERR(LastError); + + destPalette->Release(); + } + #endif + } + LastError = destSurface->QueryInterface(IID_IDirect3DTexture,(LPVOID*) &(ftPtr->DestTexture)); + LOGDXERR(LastError); + + LastError = (ftPtr->DestTexture)->Load(srcTexture); + LOGDXERR(LastError); + + LastError = (ftPtr->DestTexture)->GetHandle(d3d.lpD3DDevice, &(ftPtr->ImagePtr->D3DHandle)); + LOGDXERR(LastError); + + // ftPtr->ImagePtr->DDSurface = destSurface; +// ftPtr->ImagePtr->D3DTexture = (ftPtr->DestTexture); + if (destSurface) ReleaseDDSurface(destSurface); +} +#if 0 +static int GammaSetting; +void UpdateGammaSettings(int g, int forceUpdate) +{ + LPDIRECTDRAWGAMMACONTROL handle; + DDGAMMARAMP gammaValues; + + if (g==GammaSetting && !forceUpdate) return; + + lpDDSPrimary->QueryInterface(IID_IDirectDrawGammaControl,(LPVOID*)&handle); + +// handle->GetGammaRamp(0,&gammaValues); + for (int i=0; i<=255; i++) + { + int u = ((i*65536)/255); + int m = MUL_FIXED(u,u); + int l = MUL_FIXED(2*u,ONE_FIXED-u); + + int a; + + a = m/256+MUL_FIXED(g,l); + if (a<0) a=0; + if (a>255) a=255; + + gammaValues.red[i]=a*256; + gammaValues.green[i]=a*256; + gammaValues.blue[i]=a*256; + } +// handle->SetGammaRamp(0,&gammaValues); + handle->SetGammaRamp(DDSGR_CALIBRATE,&gammaValues); + GammaSetting=g; +// handle->SetGammaRamp(DDSGR_CALIBRATE,&gammaValues); + //handle->GetGammaRamp(0,&gammaValues); + RELEASE(handle); +} +#endif + + + +// For extern "C" + +}; + + + + + + + + + + + + + + + + + + + + + + + + + + +#if 0 +void D3D_Polygon_Output(RENDERVERTEX *renderVerticesPtr) +{ + D3DTEXTUREHANDLE TextureHandle; + + float ZNear; + float RecipW, RecipH; + + + if(RenderPolygon.IsTextured) + { + int texoffset = RenderPolygon.ImageIndex; + TextureHandle = (D3DTEXTUREHANDLE) ImageHeaderArray[texoffset].D3DHandle; + if(ImageHeaderArray[texoffset].ImageWidth==128) + { + RecipW = 1.0 /128.0; + } + else + { + float width = (float) ImageHeaderArray[texoffset].ImageWidth; + RecipW = (1.0 / width); + } + if(ImageHeaderArray[texoffset].ImageHeight==128) + { + RecipH = 1.0 / 128.0; + } + else + { + float height = (float) ImageHeaderArray[texoffset].ImageHeight; + RecipH = (1.0 / height); + } + } + + + /* OUTPUT VERTICES TO EXECUTE BUFFER */ + { + int i = RenderPolygon.NumberOfVertices; + RENDERVERTEX *vertices = renderVerticesPtr; + + do + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + float oneOverZ; + oneOverZ = (1.0)/vertices->Z; + float zvalue; + + { + int x = (vertices->X*(Global_VDB_Ptr->VDB_ProjX+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreX; + + if (xVDB_ClipLeft) + { + x=Global_VDB_Ptr->VDB_ClipLeft; + } + else if (x>Global_VDB_Ptr->VDB_ClipRight) + { + x=Global_VDB_Ptr->VDB_ClipRight; + } + + vertexPtr->sx=x; + } + { + int y = (vertices->Y*(Global_VDB_Ptr->VDB_ProjY+1))/vertices->Z+Global_VDB_Ptr->VDB_CentreY; + + if (yVDB_ClipUp) + { + y=Global_VDB_Ptr->VDB_ClipUp; + } + else if (y>Global_VDB_Ptr->VDB_ClipDown) + { + y=Global_VDB_Ptr->VDB_ClipDown; + } + vertexPtr->sy=y; + + } + + if (RenderPolygon.IsTextured) + { + vertexPtr->tu = ((float)(vertices->U>>16)+0.5) * RecipW; + vertexPtr->tv = ((float)(vertices->V>>16)+0.5) * RecipH; + vertexPtr->rhw = oneOverZ; + } + + { + zvalue = vertices->Z+HeadUpDisplayZOffset; + // zvalue /= 65536.0; + zvalue = ((zvalue-ZNear)/zvalue); + } + + if (RenderPolygon.TranslucencyMode!=TRANSLUCENCY_OFF) + { + vertexPtr->color = RGBALIGHT_MAKE(vertices->R,vertices->G,vertices->B, vertices->A); + } + else + { + vertexPtr->color = RGBLIGHT_MAKE(vertices->R,vertices->G,vertices->B); + } + + if (RenderPolygon.IsSpecularLit) + { + vertexPtr->specular = RGBALIGHT_MAKE(vertices->R/2,vertices->G/2,vertices->B/2, 0); + } + else + { + vertexPtr->specular=0; + } + + vertexPtr->sz = zvalue; + + #if FOG_ON + if(CurrentRenderStates.FogIsOn) + { + if (vertices->Z>CurrentRenderStates.FogDistance) + { + int fog = ((vertices->Z-CurrentRenderStates.FogDistance)/FOG_SCALE); + if (fog<0) fog=0; + if (fog>254) fog=254; + fog=255-fog; + vertexPtr->specular|=RGBALIGHT_MAKE(0,0,0,fog); + } + else + { + vertexPtr->specular|=RGBALIGHT_MAKE(0,0,0,255); + } + } + #endif + + vertices++; + NumVertices++; + } + while(--i); + } + + CheckTranslucencyModeIsCorrect(RenderPolygon.TranslucencyMode); + + if (D3DTexturePerspective != Yes) + { + D3DTexturePerspective = Yes; + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE, ExecBufInstPtr); + } + + if (TextureHandle != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, TextureHandle, ExecBufInstPtr); + CurrTextureHandle = TextureHandle; + } + + + D3D_OutputTriangles(); +} + +#endif + + + + + + +void r2rect :: AlphaFill +( + unsigned char R, + unsigned char G, + unsigned char B, + unsigned char translucency +) const +{ + GLOBALASSERT + ( + bValidPhys() + ); + if (y1<=y0) return; + #if 1 + /* OUTPUT quadVerticesPtr TO EXECUTE BUFFER */ + { + D3DCOLOR Colour; + + Colour = RGBALIGHT_MAKE(R,G,B,translucency); + + { + D3DTLVERTEX *vertexPtr = &((LPD3DTLVERTEX)ExecuteBufferDataArea)[NumVertices]; + + /* Vertex 0 = Top left */ + vertexPtr->sx= x0; + vertexPtr->sy= y0; + vertexPtr->color = Colour; + + NumVertices++; + vertexPtr++; + + /* Vertex 1 = Top right */ + vertexPtr->sx=( x1 - 1); + vertexPtr->sy=( y0 ); + vertexPtr->color = Colour; + + NumVertices++; + vertexPtr++; + + /* Vertex 2 = Bottom right */ + vertexPtr->sx=( x1 - 1); + vertexPtr->sy=( y1 - 1); + vertexPtr->color = Colour; + + NumVertices++; + vertexPtr++; + + /* Vertex 3 = Bottom left */ + vertexPtr->sx=x0; + vertexPtr->sy=( y1 - 1); + vertexPtr->color = Colour; + + NumVertices++; + } + } + // set correct texture handle + if (0 != CurrTextureHandle) + { + OP_STATE_RENDER(1, ExecBufInstPtr); + STATE_DATA(D3DRENDERSTATE_TEXTUREHANDLE, 0, ExecBufInstPtr); + CurrTextureHandle = 0; + } + + CheckTranslucencyModeIsCorrect(TRANSLUCENCY_GLOWING); + /* output triangles to execute buffer */ + OP_TRIANGLE_LIST(2, ExecBufInstPtr); + OUTPUT_TRIANGLE(0,1,3, 4); + OUTPUT_TRIANGLE(1,2,3, 4); + + /* check to see if buffer is getting full */ + if (NumVertices > (MaxVerticesInExecuteBuffer-12)) + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + #endif +} +extern void D3D_RenderHUDNumber_Centred(unsigned int number,int x,int y,int colour); +extern void D3D_RenderHUDString(char *stringPtr,int x,int y,int colour); +extern void D3D_RenderHUDString_Clipped(char *stringPtr,int x,int y,int colour); +extern void D3D_RenderHUDString_Centred(char *stringPtr, int centreX, int y, int colour); + +extern void D3D_RenderHUDNumber_Centred(unsigned int number,int x,int y,int colour) +{ + struct VertexTag quadVertices[4]; + int noOfDigits=3; + int h = MUL_FIXED(HUDScaleFactor,HUD_DIGITAL_NUMBERS_HEIGHT); + int w = MUL_FIXED(HUDScaleFactor,HUD_DIGITAL_NUMBERS_WIDTH); + + quadVertices[0].Y = y; + quadVertices[1].Y = y; + quadVertices[2].Y = y + h; + quadVertices[3].Y = y + h; + + x += (3*w)/2; + + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_OFF); + + do + { + int digit = number%10; + number/=10; + { + int topLeftU; + int topLeftV; + if (digit<8) + { + topLeftU = 1+(digit)*16; + topLeftV = 1; + } + else + { + topLeftU = 1+(digit-8)*16; + topLeftV = 1+24; + } + if (AvP.PlayerType == I_Marine) topLeftV+=80; + + quadVertices[0].U = topLeftU; + quadVertices[0].V = topLeftV; + quadVertices[1].U = topLeftU + HUD_DIGITAL_NUMBERS_WIDTH; + quadVertices[1].V = topLeftV; + quadVertices[2].U = topLeftU + HUD_DIGITAL_NUMBERS_WIDTH; + quadVertices[2].V = topLeftV + HUD_DIGITAL_NUMBERS_HEIGHT; + quadVertices[3].U = topLeftU; + quadVertices[3].V = topLeftV + HUD_DIGITAL_NUMBERS_HEIGHT; + + x -= 1+w; + quadVertices[0].X = x; + quadVertices[3].X = x; + quadVertices[1].X = x + w; + quadVertices[2].X = x + w; + + D3D_HUDQuad_Output + ( + HUDFontsImageNumber, + quadVertices, + colour + ); + } + } + while(--noOfDigits); + +} + + +extern void D3D_RenderHUDString(char *stringPtr,int x,int y,int colour) +{ + struct VertexTag quadVertices[4]; + + quadVertices[0].Y = y-1; + quadVertices[1].Y = y-1; + quadVertices[2].Y = y + HUD_FONT_HEIGHT + 1; + quadVertices[3].Y = y + HUD_FONT_HEIGHT + 1; + + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_OFF); + while( *stringPtr ) + { + char c = *stringPtr++; + + { + int topLeftU = 1+((c-32)&15)*16; + int topLeftV = 1+((c-32)>>4)*16; + + quadVertices[0].U = topLeftU - 1; + quadVertices[0].V = topLeftV - 1; + quadVertices[1].U = topLeftU + HUD_FONT_WIDTH + 1; + quadVertices[1].V = topLeftV - 1; + quadVertices[2].U = topLeftU + HUD_FONT_WIDTH + 1; + quadVertices[2].V = topLeftV + HUD_FONT_HEIGHT + 1; + quadVertices[3].U = topLeftU - 1; + quadVertices[3].V = topLeftV + HUD_FONT_HEIGHT + 1; + + quadVertices[0].X = x - 1; + quadVertices[3].X = x - 1; + quadVertices[1].X = x + HUD_FONT_WIDTH + 1; + quadVertices[2].X = x + HUD_FONT_WIDTH + 1; + + D3D_HUDQuad_Output + ( + AAFontImageNumber, + quadVertices, + colour + ); + } + x += AAFontWidths[c]; + } +} +extern void D3D_RenderHUDString_Clipped(char *stringPtr,int x,int y,int colour) +{ + struct VertexTag quadVertices[4]; + + LOCALASSERT(y<=0); + + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_OFF); + + quadVertices[2].Y = y + HUD_FONT_HEIGHT + 1; + quadVertices[3].Y = y + HUD_FONT_HEIGHT + 1; + + quadVertices[0].Y = 0; + quadVertices[1].Y = 0; + + while ( *stringPtr ) + { + char c = *stringPtr++; + + { + int topLeftU = 1+((c-32)&15)*16; + int topLeftV = 1+((c-32)>>4)*16; + + quadVertices[0].U = topLeftU - 1; + quadVertices[0].V = topLeftV - y; + quadVertices[1].U = topLeftU + HUD_FONT_WIDTH+1; + quadVertices[1].V = topLeftV - y; + quadVertices[2].U = topLeftU + HUD_FONT_WIDTH+1; + quadVertices[2].V = topLeftV + HUD_FONT_HEIGHT+1; + quadVertices[3].U = topLeftU - 1; + quadVertices[3].V = topLeftV + HUD_FONT_HEIGHT+1; + + quadVertices[0].X = x - 1; + quadVertices[3].X = x - 1; + quadVertices[1].X = x + HUD_FONT_WIDTH + 1; + quadVertices[2].X = x + HUD_FONT_WIDTH + 1; + + D3D_HUDQuad_Output + ( + AAFontImageNumber, + quadVertices, + colour + ); + } + x += AAFontWidths[c]; + } +} + +void D3D_RenderHUDString_Centred(char *stringPtr, int centreX, int y, int colour) +{ + int length = 0; + char *ptr = stringPtr; + + while(*ptr) + { + length+=AAFontWidths[*ptr++]; + } + length = MUL_FIXED(HUDScaleFactor,length); +// D3D_RenderHUDString(stringPtr,centreX-length/2,y,colour); + + int x = centreX-length/2; +{ + struct VertexTag quadVertices[4]; + + quadVertices[0].Y = y-MUL_FIXED(HUDScaleFactor,1); + quadVertices[1].Y = y-MUL_FIXED(HUDScaleFactor,1); + quadVertices[2].Y = y + MUL_FIXED(HUDScaleFactor,HUD_FONT_HEIGHT + 1); + quadVertices[3].Y = y + MUL_FIXED(HUDScaleFactor,HUD_FONT_HEIGHT + 1); + + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_OFF); + while( *stringPtr ) + { + char c = *stringPtr++; + + { + int topLeftU = 1+((c-32)&15)*16; + int topLeftV = 1+((c-32)>>4)*16; + #if 1 + quadVertices[0].U = topLeftU - 1; + quadVertices[0].V = topLeftV - 1; + quadVertices[1].U = topLeftU + HUD_FONT_WIDTH + 1; + quadVertices[1].V = topLeftV - 1; + quadVertices[2].U = topLeftU + HUD_FONT_WIDTH + 1; + quadVertices[2].V = topLeftV + HUD_FONT_HEIGHT + 1; + quadVertices[3].U = topLeftU - 1; + quadVertices[3].V = topLeftV + HUD_FONT_HEIGHT + 1; + #else + quadVertices[0].U = topLeftU ; + quadVertices[0].V = topLeftV ; + quadVertices[1].U = topLeftU + HUD_FONT_WIDTH ; + quadVertices[1].V = topLeftV ; + quadVertices[2].U = topLeftU + HUD_FONT_WIDTH ; + quadVertices[2].V = topLeftV + HUD_FONT_HEIGHT ; + quadVertices[3].U = topLeftU ; + quadVertices[3].V = topLeftV + HUD_FONT_HEIGHT ; + #endif + quadVertices[0].X = x - MUL_FIXED(HUDScaleFactor,1); + quadVertices[3].X = x - MUL_FIXED(HUDScaleFactor,1); + quadVertices[1].X = x + MUL_FIXED(HUDScaleFactor,HUD_FONT_WIDTH + 1); + quadVertices[2].X = x + MUL_FIXED(HUDScaleFactor,HUD_FONT_WIDTH + 1); + + D3D_HUDQuad_Output + ( + AAFontImageNumber, + quadVertices, + colour + ); + } + x += MUL_FIXED(HUDScaleFactor,AAFontWidths[c]); + } +} +} + +extern "C" +{ + +extern void RenderString(char *stringPtr, int x, int y, int colour) +{ + D3D_RenderHUDString(stringPtr,x,y,colour); +} + +extern void RenderStringCentred(char *stringPtr, int centreX, int y, int colour) +{ + int length = 0; + char *ptr = stringPtr; + + while(*ptr) + { + length+=AAFontWidths[*ptr++]; + } + D3D_RenderHUDString(stringPtr,centreX-length/2,y,colour); +} + +extern void RenderStringVertically(char *stringPtr, int centreX, int bottomY, int colour) +{ + struct VertexTag quadVertices[4]; + int y = bottomY; + + quadVertices[0].X = centreX - (HUD_FONT_HEIGHT/2) - 1; + quadVertices[1].X = quadVertices[0].X; + quadVertices[2].X = quadVertices[0].X+2+HUD_FONT_HEIGHT*1; + quadVertices[3].X = quadVertices[2].X; + + CheckFilteringModeIsCorrect(FILTERING_BILINEAR_OFF); + while( *stringPtr ) + { + char c = *stringPtr++; + + { + int topLeftU = 1+((c-32)&15)*16; + int topLeftV = 1+((c-32)>>4)*16; + + quadVertices[0].U = topLeftU - 1; + quadVertices[0].V = topLeftV - 1; + quadVertices[1].U = topLeftU + HUD_FONT_WIDTH; + quadVertices[1].V = topLeftV - 1; + quadVertices[2].U = topLeftU + HUD_FONT_WIDTH; + quadVertices[2].V = topLeftV + HUD_FONT_HEIGHT + 1; + quadVertices[3].U = topLeftU - 1; + quadVertices[3].V = topLeftV + HUD_FONT_HEIGHT + 1; + + quadVertices[0].Y = y ; + quadVertices[1].Y = y - HUD_FONT_WIDTH*1 -1; + quadVertices[2].Y = y - HUD_FONT_WIDTH*1 -1; + quadVertices[3].Y = y ; + + D3D_HUDQuad_Output + ( + AAFontImageNumber, + quadVertices, + colour + ); + } + y -= AAFontWidths[c]; + } +} + +}; + + diff --git a/3dc/avp/win95/d3d_render.h b/3dc/avp/win95/d3d_render.h new file mode 100644 index 0000000..66d89c7 --- /dev/null +++ b/3dc/avp/win95/d3d_render.h @@ -0,0 +1,32 @@ +#ifndef _included_d3d_render_h_ /* Is this your first time? */ +#define _included_d3d_render_h_ 1 +#include "particle.h" + +extern void D3D_SetupSceneDefaults(void); +extern void D3D_DrawBackdrop(void); +extern void PostLandscapeRendering(void); +extern void D3D_DrawWaterTest(MODULE *testModulePtr); + + +extern void D3D_ZBufferedCloakedPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr); +extern void D3D_ZBufferedGouraudTexturedPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr); +extern void D3D_ZBufferedGouraudPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr); +extern void D3D_ZBufferedTexturedPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr); +extern void D3D_PredatorThermalVisionPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr); + +extern void D3D_BackdropPolygon_Output(POLYHEADER *inputPolyPtr,RENDERVERTEX *renderVerticesPtr); +extern void D3D_Decal_Output(DECAL *decalPtr,RENDERVERTEX *renderVerticesPtr); +extern void D3D_Particle_Output(PARTICLE *particlePtr,RENDERVERTEX *renderVerticesPtr); +extern void D3D_DrawParticle_Rain(PARTICLE *particlePtr,VECTORCH *prevPositionPtr); + +extern void D3D_DecalSystem_Setup(void); +extern void D3D_DecalSystem_End(void); + +extern void D3D_FadeDownScreen(int brightness, int colour); +extern void D3D_PlayerOnFireOverlay(void); + + +extern void CheckWireFrameMode(int shouldBeOn); + +extern void InitForceField(void); +#endif \ No newline at end of file diff --git a/3dc/avp/win95/datatype.h b/3dc/avp/win95/datatype.h new file mode 100644 index 0000000..cb0d3ea --- /dev/null +++ b/3dc/avp/win95/datatype.h @@ -0,0 +1,7 @@ +#define CHAR char +#define BYTE unsigned char +#define WORD unsigned short +#define DWORD unsigned int + +#define SHORT short +#define VOID void diff --git a/3dc/avp/win95/dbdefs.h b/3dc/avp/win95/dbdefs.h new file mode 100644 index 0000000..bf01ffb --- /dev/null +++ b/3dc/avp/win95/dbdefs.h @@ -0,0 +1,118 @@ +// enums for the number of information screens we have +// data description + +typedef enum maps{ + I_No_Map, + I_Map_Gen1, I_Map_Gen2, I_Map_Gen3, I_Map_Gen4, + I_Map_Cmc1, I_Map_Cmc2, I_Map_Cmc3, I_Map_Cmc4, I_Map_Cmc5, I_Map_Cmc6, + I_Map_Rnd1, I_Map_Rnd2, I_Map_Rnd3, I_Map_Rnd4, + I_Map_Mps1, I_Map_Mps2, I_Map_Mps3, I_Map_Mps4, + I_Map_Sp1, I_Map_Sp2, I_Map_Sp3, + I_Map_Surface, I_Map_Medlab, + I_Num_Maps +}DATABASE_MAP; + +typedef enum +{ + I_Floor_0 = 0, + I_Floor_1, + I_Floor_2, + I_Floor_3, + I_Floor_4, + I_Floor_5, + I_Max_Num_Floors, + +}FLOOR_NUM; + +typedef enum +{ + I_No_Weapon, + I_Weapon_Pulse, + I_Num_Weapons + +}DATABASE_WEAPON; + + +typedef enum +{ + I_No_Message, + I_Message_1, + I_Num_Messages, + +}DATABASE_MESSAGE; + +typedef struct dbasedesc +{ + int floor; + DATABASE_MAP map_enum; + DATABASE_WEAPON weap_enum; + DATABASE_MESSAGE message_enum; + short pixel_x; + short pixel_y; + +}DBASEDESC; + +// enums to control flow of the database screens +// data base states - each one is associated with a +// enum to describes the option from the satae + +typedef enum +{ + DB_STATE_SELECT, + DB_STATE_MAP, + DB_STATE_MESSAGE, + DB_STATE_WEAPON, + DB_STATE_LOAD, + DB_STATE_SAVE, + DB_STATE_END, + NUM_DB_STATES, + +}DB_MENU_STATE; + + + +typedef enum database_options +{ + DB_MAP_OPTION, + DB_MESSAGE_OPTION, + DB_WEAPON_OPTION, + DB_LOAD_OPTION, + DB_SAVE_OPTION, + DB_LOGOFF_OPTION, + DB_QUIT_OPTION, + DB_NUM_OPTIONS + +}DB_MENU_OPTIONS; + + +typedef enum map_screen_options +{ + DB_MAP_EXIT_OPTION, + DB_MAP_LOGOFF_OPTION, + DB_NUM_MAP_OPTIONS, + +}DB_MAP_OPTIONS; + +typedef enum +{ + DB_WEAPON_EXIT_OPTION, + DB_WEAPON_LOGOFF_OPTION, + DB_NUM_WEAPON_OPTIONS, + +}DB_WEAPON_OPTIONS; + +typedef enum +{ + DB_MESSAGE_PLAY_OPTION, + DB_MESSAGE_STOP_OPTION, + DB_MESSAGE_EXIT_OPTION, + DB_MESSAGE_LOGOFF_OPTION, + DB_NUM_MESSAGE_OPTIONS, + +}DB_MESSAGE_OPTIONS; + + +extern void DatabaseMenus(DATABASE_BLOCK*); + +extern void PlatformSpecificEnteringDatabase(); +extern void PlatformSpecificExitingDatabase(); diff --git a/3dc/avp/win95/dp_Sprh.h b/3dc/avp/win95/dp_Sprh.h new file mode 100644 index 0000000..24f4514 --- /dev/null +++ b/3dc/avp/win95/dp_Sprh.h @@ -0,0 +1,75 @@ +/*--------------------Patrick 18/3/97-------------------- + Dave's square peg round hole interface for direct + play gdi dialog stuff +---------------------------------------------------------*/ + +#ifndef _dpsprh_h_ +#define _dpsprh_h_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + + + +/* Type definitions *****************************************************/ + + typedef struct exchangeddatatype + { + /* Output fields from DLL*/ + LPDIRECTPLAY2A lpDP2A_Returned; + /* + pointer to direct play object + Will be NULL if an error occurred, or a "Cancel" + */ + + BOOL bWasHost; + /* + set to TRUE or FALSE + */ + + LPTSTR lptszFormalPlayerName_Out; + unsigned int FormalName_MaxSize; + + LPTSTR lptszFriendlyPlayerName_Out; + unsigned int FriendlyName_MaxSize; + /* + These must be non-NULL pointers to buffers in yuor EXE with > 0 attached + sizes. The DLL will write the requested names to these buffers, truncating + if necessary. Note that the size includes any zero termination character. + */ + + + + /* Input fields to DLL */ + HWND hWndMain; + HINSTANCE hInst; + + LPTSTR lptszFormalPlayerName_In; + LPTSTR lptszFriendlyPlayerName_In; + /* + Both of these are allowed to be NULL; + if non-NULL they point to zero-terminated ANSI strings + */ + + } ExchangedDataType; + /* + We pass a 4-byte pointer to one of these to the DLL; + some are read as inputs, some written to as outputs. + + Assumes Watcom and Visual C++ access structures in the + same way... + */ + + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ +extern WINAPI InvokeDavesDirectPlayDLL(ExchangedDataType* pExchangedData); + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/win95/dplayext.c b/3dc/avp/win95/dplayext.c new file mode 100644 index 0000000..617f85f --- /dev/null +++ b/3dc/avp/win95/dplayext.c @@ -0,0 +1,392 @@ +/* ******************************************************************** * + * * + * DPLAYEXT.C - DirectPlay multi-player code extensions. * + * * + * By: Garry Lancaster Version: 0.1 * + * * + * ******************************************************************** */ + +/* N O T E S ---------------------------------------------------------- */ + +/* Define USE_DB here to use my db.c debugging file. If you wish to use + * another debugging system you will have to redefine the ASSERT macro to + * use your debugging system or turn off assertions by defining NDEBUG. + * - Garry. + */ + +/* This code marks an experimental departure for me into Hungarian variable + * names. Enjoy! (or perhaps not.) + */ + +/* I N C L U D E S ---------------------------------------------------- */ + +/* OS includes. */ +#include + +/* Include for this file. */ +#include "dplayext.h" + +/* Custom includes. */ +#define UseLocalAssert Yes +#include "ourasert.h" + +/* C O N S T A N T S -------------------------------------------------- */ + +/* The maximum length of a message that can be received by the system, in + * bytes. DPEXT_MAX_MSG_SIZE bytes will be required to hold the message, so + * you can't just set this to a huge number. + */ +#define DPEXT_MAX_MSG_SIZE 3072 + +/* This msg is not guaranteed. */ +#define DPEXT_NOT_GUARANTEED 1 + +/* M A C R O S -------------------------------------------------------- */ + + +/* Advance the guaranteed msg count. Wraps around to 1 when the maximum + * +ve value for a signed int is passed. + */ +#define DPEXT_NEXT_GRNTD_MSG_COUNT() \ + if( ++gnCurrGrntdMsgId < 1 ) gnCurrGrntdMsgId = 1 + +/* Generate the msg stamp for a reply to a msg with a specified + * guaranteed msg id. + */ +#define DPEXT_TO_REPLY_STAMP( iSentStamp ) ( -( iSentStamp ) ) + +/* Identify the original msg stamp given a reply stamp. */ +#define DPEXT_TO_ORIGINAL_STAMP( iReplyStamp ) \ + DPEXT_GET_REPLY_STAMP( iReplyStamp ) + +/* T Y P E S ---------------------------------------------------------- */ + +struct DpExtGrntdMsgInfo +{ + void **abufPending; + DWORD cBuffers; + DWORD iLastUsed; +}; + +/* G L O B A L S . . . ------------------------------------------------ */ + +/* ...with external scope. */ + +/* ...with internal (static) scope. */ + +/* Buffer used to store incoming messages. */ +static unsigned char gbufDpExtRecv[ DPEXT_MAX_MSG_SIZE ]; + +/* Are we expected to add our own error checking? */ +static BOOL gbDpExtDoErrChcks = FALSE; + +/* Are we expected to implement guaranteed message sending? */ +static BOOL gbDpExtDoGrntdMsgs = FALSE; + +/* The current count of guaranteed msgs. Zero is reserved for msgs that + * aren't guaranteed (using DPEXT_NOT_GUARANTEED) and negative numbers are + * reserved for replies to guaranteed messages. + */ +static int gnCurrGrntdMsgId = 1; + +/* Storage for guaranteed msgs and replies to guaranteed msgs. */ +static struct DpExtGrntdMsgInfo ggmiMsgs = { NULL, 0, 0 }; +static struct DpExtGrntdMsgInfo ggmiReplies = { NULL, 0, 0 }; + +/* P R O T O S -------------------------------------------------------- */ + +/* Should all be static. */ + +/* Perform any required processing on a received msg. No processing is + * required if neither DpExt guaranteed msg system or the DpExt error + * checking system are on. Returns TRUE if the message was internal only, + * FALSE if it should be passed to the user. + */ +static BOOL DpExtProcessRecvdMsg(BOOL bIsSystemMsg, LPVOID lpData, + DWORD dwDataSize); + +/* Generates and returns a checksum for the supplied buffer. The algorithm + * used ignores the first 4 bytes of the buffer (this is where the checksum + * should eventually be stored) and is sensitive to the order of the bytes + * and long words stored as well as lost data, added data, duplicated data, + * and standard corruption. + */ +static DWORD DpExtChecksumMsg(LPVOID lpData, DWORD dwDataSize); + +/* Use a destroy msg to try and free up nodes in the guaranteed msg list + * that will never now be freed in the usual manner i.e. by a reply to or + * a re-send from the player. + */ +static void DpExtUseDestroyMsg(LPDPMSG_DESTROYPLAYERORGROUP pmsgDestroy); + +/* -------------------------------------------------------------------- * + * * + * F U N C T I O N S * + * * + * -------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------- * + * I N T E R F A C E F N S - with external scope. * + * -------------------------------------------------------------------- */ + + +/* Call this fn to initialise the DpExt module. cGrntdBufs sets the number + * of guaranteed message buffers to use and cBytesPerBuf is the number of + * bytes to allocate to each buffer, and thus the maximum length + * (including DpExt header) for a guaranteed msg. cGrntdBufs should be 0 + * if you don't want DpExt's guaranteed msg sending system to be turned on. + * bErrChcks should be TRUE if you require DpExt's error checking system, + * otherwise FALSE. + */ +BOOL DpExtInit(DWORD cGrntdBufs, DWORD cBytesPerBuf, + BOOL bErrChcks) +{ + return TRUE; +} + + +/* Un-initialises the DpExt module. */ +void DpExtUnInit(void) +{ +} + + +/* This fn has the same parameters as the standard DirectPlay Send() fn. + * However, you *must* leave DPEXT_HEADER_SIZE bytes free at the start of + * your data buffer. The dwDataSize byte count must includes these bytes. + */ +HRESULT DpExtSend +( + LPDIRECTPLAY4 lpDP2A, /* IN: Ptr to IDirectPlay3A (DBCS) interface. */ + DPID idFrom, /* IN: ID of sending player (you) */ + DPID idTo, /* IN: ID of destination player. */ + DWORD dwFlags, /* IN: DirectPlay Flags. */ + LPVOID lpData, /* IN: Ptr to start of message. */ + DWORD dwDataSize /* IN: Byte count of message. */ +) +{ + HRESULT hrSend; + + /* Assert input conditions that the DirectPlay call may not check. */ + LOCALASSERT( lpDP2A ); + LOCALASSERT( lpData ); + LOCALASSERT( dwDataSize >= DPEXT_HEADER_SIZE ); + + /* Add header information. */ + { + struct DpExtHeader *pmsghdr = (struct DpExtHeader *) lpData; + + if( gbDpExtDoGrntdMsgs && ( DPSEND_GUARANTEED & dwFlags ) ) + { + /* Add guaranteed msg stamp. */ + pmsghdr->dwMsgStamp = gnCurrGrntdMsgId; + DPEXT_NEXT_GRNTD_MSG_COUNT(); + } + else + { + pmsghdr->dwMsgStamp = DPEXT_NOT_GUARANTEED; + } + if( gbDpExtDoErrChcks ) + { + pmsghdr->dwChecksum = DpExtChecksumMsg( lpData, dwDataSize ); + } + } + + hrSend = IDirectPlay3_Send( lpDP2A, idFrom, idTo, dwFlags, lpData, + dwDataSize ); + + return hrSend; +} + + +/* This fn has similar parameters to the standard DirectPlay Receive() + * fn. Be aware that the 2 id parameters, the lplpData parameter and the + * lpdwDataSize parameters are only valid as inputs if the + * appropriate flags are used in the dwFlags parameter. They are always + * valid as outputs. + * + * The main difference from the standard Receive() is that the LPVOID + * lpData field has changed to LPVOID *lplpData. Now instead of supplying + * the buffer for the message and having the fn fail if the buffer isn't + * big enough, the buffer is allocated for you and you get a pointer to it. + * I re-use the same buffer each time DpExtRecv() is called, so the pointer + * is only valid until the next time you call this fn. + * + * If you want to maintain the message longer than that you can (a) copy the + * message data to your own buffer or (b) more efficiently, pass a ptr to + * a ptr to your own allocated data buffer in lplpData, a ptr to its size + * in lpdwDataSize and set the flag DPEXT_USER_BUFFER in dwFlags - this is + * more like the original DirectPlay Receive() fn behaviour. In the case of + * (b), you must leave DPEXT_HEADER_SIZE bytes free at the start of your + * user buffer and include these bytes in *lpdwDataSize. + * + * All non-system messages received will use their first DPEXT_HEADER_SIZE + * bytes for header information. Your message proper begins after this + * header. + */ +HRESULT DpExtRecv +( + LPDIRECTPLAY4 lpDP2A, /* IN: Ptr to IDirectPlay3A (DBCS) interface. */ + LPDPID lpidFrom, /* IN/OUT: Ptr to from player id. */ + LPDPID lpidTo, /* IN/OUT: Ptr to to player id. */ + DWORD dwFlags, /* IN: DirectPlay flags. */ + LPVOID *lplpData, /* IN/OUT: Ptr to ptr to message data. */ + LPDWORD lpdwDataSize /* IN/OUT: Ptr to byte count of message. */ +) +{ + HRESULT hrRecv; + BOOL bInternalOnly; + BOOL bIsSysMsg; + + /* Assert input conditions that the DirectPlay call may not check. */ + LOCALASSERT( lpDP2A ); + LOCALASSERT( lpidFrom ); + LOCALASSERT( lpidTo ); + LOCALASSERT( lpdwDataSize ); + + /* Did the user want to use their own data buffer? + * N.B. Does this need to go in the loop? + */ + if( !( DPEXT_USER_BUFFER & dwFlags ) ) + { + /* No. Set parameters to write to internal buffer. */ + *lplpData = gbufDpExtRecv; + *lpdwDataSize = DPEXT_MAX_MSG_SIZE; + } + + do + { + bInternalOnly = FALSE; /* Default. */ + + hrRecv = IDirectPlay3_Receive( lpDP2A, lpidFrom, lpidTo, dwFlags, + *lplpData, lpdwDataSize ); + + /* DirectPlay bug work-around. *lpdwDataSize does not get filled in + * automatically for some system messages. + */ + if( ( DPID_SYSMSG == *lpidFrom ) && + ( DP_OK == hrRecv ) ) + { + DPMSG_GENERIC msgGenSys = *( (LPDPMSG_GENERIC) *lplpData ); + + bIsSysMsg = TRUE; + switch( msgGenSys.dwType ) + { + case DPSYS_ADDPLAYERTOGROUP: + case DPSYS_DELETEPLAYERFROMGROUP: + /* Didn't test for bug - possibly okay. */ + *lpdwDataSize = sizeof( DPMSG_ADDPLAYERTOGROUP ); + break; + case DPSYS_CREATEPLAYERORGROUP: + /* Not necessary - bug doesn't affect this message. */ + break; + case DPSYS_DESTROYPLAYERORGROUP: + *lpdwDataSize = sizeof( DPMSG_DESTROYPLAYERORGROUP ); + break; + case DPSYS_SETPLAYERORGROUPDATA: + /* Didn't test for bug - possibly okay. */ + *lpdwDataSize = sizeof( DPMSG_SETPLAYERORGROUPDATA ); + break; + case DPSYS_SETPLAYERORGROUPNAME: + /* Didn't test for bug - possibly okay. */ + *lpdwDataSize = sizeof( DPMSG_SETPLAYERORGROUPNAME ); + break; + case DPSYS_HOST: + case DPSYS_SESSIONLOST: + *lpdwDataSize = sizeof( DPMSG_GENERIC ); + break; + } + } + else bIsSysMsg = FALSE; + + /* Might we need to process this message? */ + if( ( DP_OK == hrRecv ) && + ( gbDpExtDoGrntdMsgs || gbDpExtDoErrChcks ) ) + { + bInternalOnly = DpExtProcessRecvdMsg + ( + bIsSysMsg, + *lplpData, + *lpdwDataSize + ); + } + } + while( bInternalOnly ); + + return hrRecv; +} + + +/* -------------------------------------------------------------------- * + * S T A T I C F N S - with internal scope. * + * -------------------------------------------------------------------- */ + + +/* Perform any required processing on a received msg. No processing is + * required if neither DpExt guaranteed msg system or the DpExt error + * checking system are on. Returns TRUE if the message was internal only, + * FALSE if it should be passed to the user. + */ +static BOOL DpExtProcessRecvdMsg(BOOL bIsSystemMsg, LPVOID lpData, + DWORD dwDataSize) +{ + /* Is this a system message? */ + if( bIsSystemMsg ) + { + /* Yes. Do we need to intercept any system messages for our own + * nefarious purposes? + */ + if( gbDpExtDoGrntdMsgs ) + { + /* Yes, we need to intercept messages about deleted players or + * groups. Is this one? + */ + DPMSG_GENERIC *pmsgGeneric = (DPMSG_GENERIC *) lpData; + + if( DPSYS_DESTROYPLAYERORGROUP == pmsgGeneric->dwType ) + { + DpExtUseDestroyMsg( (LPDPMSG_DESTROYPLAYERORGROUP) + pmsgGeneric ); + } + } + } + else + { + /* No, this isn't a system message. Use DpExt header... */ + struct DpExtHeader *pmsghdr = (struct DpExtHeader *) lpData; + + LOCALASSERT( dwDataSize >= DPEXT_HEADER_SIZE ); + + /* ...Should we check this message for errors? */ + if( gbDpExtDoErrChcks ) + { + + } + + /* ...Was this message sent by the DpExt guaranteed message system? */ + } + + return FALSE; +} + + +/* Generates and returns a checksum for the supplied buffer. The algorithm + * used ignores the first 4 bytes of the buffer (this is where the checksum + * should eventually be stored) and is sensitive to the order of the bytes + * and long words stored as well as lost data, added data, duplicated data, + * and standard corruption. + */ +static DWORD DpExtChecksumMsg(LPVOID lpData, DWORD dwDataSize) +{ + return 0; /* No implementation yet. */ +} + + +/* Use a destroy msg to try and free up nodes in the guaranteed msg list + * that will never now be freed in the usual manner i.e. by a reply to or + * a re-send from the player. + */ +static void DpExtUseDestroyMsg(LPDPMSG_DESTROYPLAYERORGROUP pmsgDestroy) +{ + /* No implementation yet. */ +} \ No newline at end of file diff --git a/3dc/avp/win95/dplayext.h b/3dc/avp/win95/dplayext.h new file mode 100644 index 0000000..50cee62 --- /dev/null +++ b/3dc/avp/win95/dplayext.h @@ -0,0 +1,131 @@ +/* ******************************************************************** * + * * + * DPLAYEXT.H - Header for DirectPlay extensions. * + * * + * By: Garry Lancaster Version: 0.1 * + * * + * ******************************************************************** */ + +/* N O T E S ---------------------------------------------------------- */ + +/* S T A R T W R A P P E R ------------------------------------------ */ + +/* Avoid multiple inclusions of this file in a single source file. */ +#ifndef DPLAYEXT_H_INCLUDED +#define DPLAYEXT_H_INCLUDED + +/* Permit use in a C++ source file. */ +#ifdef __cplusplus +extern "C" { +#endif + +/* I N C L U D E S ---------------------------------------------------- */ + +/* DirectPlay include. */ +#include "dplay.h" + +/* C O N S T A N T S -------------------------------------------------- */ + +/* All messages sent and all non-system messages received will have the + * first DPEXT_HEADER_SIZE bytes used for header information. Therefore, + * you must make all buffers at least this big and not use these bytes + * yourself. + */ +#define DPEXT_HEADER_SIZE ( sizeof( struct DpExtHeader) ) + +/* This flag alters the DpExtRecv() function behaviour to allow the user + * to provide the buffer that the message will be copied to. This is more + * like the original DirectPlay Receive() fn behaviour than the default. + */ +#define DPEXT_USER_BUFFER 0x10000000 + +/* M A C R O S -------------------------------------------------------- */ + +/* T Y P E S ---------------------------------------------------------- */ + +/* This structure is supplied so that you can treat it as a base class + * for your messages in C++ if you wish. + */ +struct DpExtHeader +{ + DWORD dwChecksum; /* Error checking information. */ + DWORD dwMsgStamp; /* Contains guaranteed msg info. */ +}; + +/* G L O B A L S ------------------------------------------------------ */ + +/* All declarations. NO definitions. */ + +/* P R O T O S -------------------------------------------------------- */ + +/* Call this fn to initialise the DpExt module. cGrntdBufs sets the number + * of guaranteed message buffers to use and cBytesPerBuf is the number of + * bytes to allocate to each buffer, and thus the maximum length + * (including DpExt header) for a guaranteed msg. cGrntdBufs should be 0 + * if you don't want DpExt's guaranteed msg sending system to be turned on. + * bErrChcks should be TRUE if you require DpExt's error checking system, + * otherwise FALSE. + */ +extern BOOL DpExtInit(DWORD cGrntdBufs, DWORD cBytesPerBuf, BOOL bErrChcks); + +/* Un-initialises the DpExt module. */ +extern void DpExtUnInit(void); + +/* This fn has the same parameters as the standard DirectPlay Send() fn. + * However, you *must* leave DPEXT_HEADER_SIZE bytes free at the start of + * your data buffer. The dwDataSize byte count must includes these bytes. + */ +extern HRESULT DpExtSend +( + LPDIRECTPLAY4 lpDP2A, /* IN: Ptr to IDirectPlay2A (DBCS) interface. */ + DPID idFrom, /* IN: ID of sending player (you) */ + DPID idTo, /* IN: ID of destination player. */ + DWORD dwFlags, /* IN: DirectPlay Flags. */ + LPVOID lpData, /* IN: Ptr to start of message. */ + DWORD dwDataSize /* IN: Byte count of message. */ +); + +/* This fn has similar parameters to the standard DirectPlay Receive() + * fn. Be aware that the 2 id parameters, the lplpData parameter and the + * lpdwDataSize parameters are only valid as inputs if the + * appropriate flags are used in the dwFlags parameter. They are always + * valid as outputs. + * + * The main difference from the standard Receive() is that the LPVOID + * lpData field has changed to LPVOID *lplpData. Now instead of supplying + * the buffer for the message and having the fn fail if the buffer isn't + * big enough, the buffer is allocated for you and you get a pointer to it. + * I re-use the same buffer each time DpExtRecv() is called, so the pointer + * is only valid until the next time you call this fn. + * + * If you want to maintain the message longer than that you can (a) copy the + * message data to your own buffer or (b) more efficiently, pass a ptr to + * a ptr to your own allocated data buffer in lplpData, a ptr to its size + * in lpdwDataSize and set the flag DPEXT_USER_BUFFER in dwFlags - this is + * more like the original DirectPlay Receive() fn behaviour. In the case of + * (b), you must leave DPEXT_HEADER_SIZE bytes free at the start of your + * user buffer and include these bytes in *lpdwDataSize. + * + * All non-system messages received will use their first DPEXT_HEADER_SIZE + * bytes for header information. Your message proper begins after this + * header. + */ +extern HRESULT DpExtRecv +( + LPDIRECTPLAY4 lpDP2A, /* IN: Ptr to IDirectPlay2A (DBCS) interface. */ + LPDPID lpidFrom, /* IN/OUT: Ptr to from player id. */ + LPDPID lpidTo, /* IN/OUT: Ptr to to player id. */ + DWORD dwFlags, /* IN: DirectPlay flags. */ + LPVOID *lplpData, /* IN/OUT: Ptr to ptr to message data. */ + LPDWORD lpdwDataSize /* IN/OUT: Ptr to byte count of message. */ +); + +/* E N D W R A P P E R ---------------------------------------------- */ + +/* Permit use in a C++ source file. */ +#ifdef __cplusplus +} +#endif + +/* Avoid multiple inclusions of this file in a single source file. */ +#endif diff --git a/3dc/avp/win95/dx_proj.cpp b/3dc/avp/win95/dx_proj.cpp new file mode 100644 index 0000000..b01db10 --- /dev/null +++ b/3dc/avp/win95/dx_proj.cpp @@ -0,0 +1,710 @@ +// Project specific parts of the Win95 DirectX system, +// largely concerned with the rules for selecting a driver, +// draw mode, memory mode etc during system initialisation, which +// cannot readily be decided at a project independent level. + +// Must link to C code in main engine system + +// Note that TestInitD3DObject is called during InitialiseSystem, immediately +// after initialisation of the basic DirectDraw object. It is normally used +// to detect the hardware acceleration capabilities of a system, by creating a Direct3D +// object which is then collapsed again, so that the information can be passed to e.g. +// menu software to provide recommended options. The video mode can potentially +// be rewritten here, so that a 320x200x8 request mode is interpreted as e.g. 640x480x15 +// if hardware acceleration is detected and it is decided that it will be used. + +// Note that the ProcessorType global should be valid at this stage. + + +// TestMemoryAccess is run immediately after TestInitD3DObject in InitialiseSystem, +// and is used to determine whether the back buffer should be in system or video memory. +// Note that if you intend to use MMX scan draws the back buffer should be in system memory, +// if you are running with hardware accelerated draws it MUST be in video memory, and otherwise +// I would recommend video memory except in extreme circumstances (i.e. very old video cards +// with very slow VRAM access). Note that whether or not we will boot on hardware should have been +// decided by this stage. + +// NOTE THAT THE REQUESTSYSTEMMEMORYALWAYS OPTION IS A DEBUGGING FEATURE, SINCE THE WATCOM +// DEBUGGER CAN ONLY BE USED ON FUNCTIOSN WITHIN DRAWITEMLISTCONTENTS ETC IF THE RENDERING +// TARGET IS IN SYSTEM MEMORY AND THE SYSTEM DOES NOT HAVE TO TAKE A WIN16 LOCK TO +// REACH THE SURFACE. THIS REQUEST MODE OPTION REPLACES FORCEBUFFERSINTOSYSTEMMEMORY, WHICH +// WAS AT THE TOP OF DD_FUNC.CPP + +// SelectD3DDriverAndDrawMode is the final selection function for hardware acceleration, z buffering +// etc, run during SetVideoMode from InitialiseDirect3DImmediateMode. Note that your target video +// mode must have been selected before you enter this routine. This routine is separate so that a call +// to ChangeDisplayModes (in io.c) can be used to change the video mode, driver etc. + +// NOTE: USE OF CHANGEDISPLAYMODES MUST BE INTEGRATED WITH USE OF THE CHUNK SYSTEM, SINCE IT WILL +// REQUIRE A TEXTURE RELOAD AND PROBABLY A SHAPE RELOAD. + +// NOTE: IF YOU INTEND TO LET THE USER OVERRIDE VIDEO MODE, DRIVER ETC SETTINGS FROM MENUS RUN +// (UNAVOIDABLY, I SUSPECT) AFTER INITIALISESYSTEM, YOU MUST CALL SETVIDEOMODE BEFORE THE MENUS +// IF YOU WANT THEM TO BE DISPLAYED USING ENGINE (DIRECTX) FUNCTIONS AND THEN CALL CHANGEDISPLAYMODES +// TO CHANGE THE MODES TO THE FINAL ONES. DO NOT CALL SETVIDEOMODE TWICE DURING A SINGLE PROGRAM RUN. +// CHANGEDISPLAYMODES WILL CALL YOUR VERSION OF SELECTD3DDRIVERANDDRAWMODE FOR YOU, BUT TESTMEMORYACCESS +// AND TESTINITD3DOBJECT WILL NOT BE CALLED AGAIN. IF YOU WANT TO RESELECT THE MEMORY MODE OR RETEST +// HARDWARE ACCELERATION CAPABILITIES, YOU MUST DO IT YOURSELF IN THE MENUS SYSTEM. + +// NOTE: TO CHANGE PALETTE IN A PALETTISED MODE, CALL CHANGEPALETTE IN IO.C, NOT CHANGEDISPLAYMODES. + +extern "C" { + +#include "system.h" +#include "equates.h" +#include "platform.h" +#include "shape.h" +#include "prototyp.h" +#include "inline.h" + +#include "d3_func.h" +#include "d3dmacs.h" + +extern "C++" +{ +#include "pcmenus.h" +}; + +#include "dxlog.h" + +// Tell system to prefer palettised formats +// for textures. The alternative is to prefer +// non-palettised modes. +// Note that non-palettised modes certainly seem +// to look better on the software RGB driver, anyway, +// leading me to suspect that my runtime ppm quantiser +// is, ahem, less than totally perfect... +#define PreferPalettisedTextures Yes + +// Test hack to force driver zero (mono +// rather than RGB), plus others. Should +// all be No in theory. Turn on only one +// at a time!!! +#define ForceRampDriver No +#define ForceRGBDriver No +#define ForceHardwareDriver No +#define ForceDirectDraw No + +// Externs + +extern int VideoMode; +extern int VideoModeColourDepth; +extern int WindowMode; +extern int DrawMode; +extern int ScanDrawMode; +extern int ZBufferMode; +extern int DXMemoryMode; +extern int DXMemoryRequestMode; +extern int ZBufferRequestMode; +extern int RasterisationRequestMode; +extern int SoftwareScanDrawRequestMode; +extern int D3DDriverMode; +extern BOOL D3DHardwareAvailable; +extern D3DINFO d3d; +extern int StartDriver; +extern int StartFormat; +extern HRESULT LastError; +extern BOOL MMXAvailable; +extern LPDIRECTDRAW lpDD; + +// Globals +// Test only!!! +int TestHw = No; + + +// Callback function to enumerate texture +// formats available on the current D3D +// driver. Obviously this should be run +// AFTER the driver callback, and after +// a driver has been selected. +// A palette will be picked as the default +// (with preference given to palettized +// formats) and returned via the lpContext. + +HRESULT CALLBACK TextureFormatsEnumerator + (LPDDSURFACEDESC lpDDSD, LPVOID lpContext) +{ + unsigned long m; + int r, g, b; + int *lpStartFormat = (int*) lpContext; + + /* + Record the DDSURFACEDESC of this texture format + */ + + memset(&d3d.TextureFormat[d3d.NumTextureFormats], 0, + sizeof(D3DTEXTUREFORMAT)); + memcpy(&d3d.TextureFormat[d3d.NumTextureFormats].ddsd, + lpDDSD, sizeof(DDSURFACEDESC)); + + /* + Is this format palettized? How many bits? Otherwise, how many RGB + bits? + */ + + if (lpDDSD->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) + { + d3d.TextureFormat[d3d.NumTextureFormats].Palette = Yes; + d3d.TextureFormat[d3d.NumTextureFormats].IndexBPP = 8; + } + else if (lpDDSD->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) + { + d3d.TextureFormat[d3d.NumTextureFormats].Palette = Yes; + d3d.TextureFormat[d3d.NumTextureFormats].IndexBPP = 4; + } + else if (lpDDSD->ddpfPixelFormat.dwFlags & (DDPF_ALPHA|DDPF_ALPHAPIXELS|DDPF_FOURCC)) + { + return DDENUMRET_OK; + } + else if (lpDDSD->ddpfPixelFormat.dwFlags & DDPF_RGB) + { + // This bit is all fiendishly cunning, Dr Tringham, + // but one has to wonder if it actually, as such, + // works... + d3d.TextureFormat[d3d.NumTextureFormats].Palette = No; + d3d.TextureFormat[d3d.NumTextureFormats].IndexBPP = 0; + for (r = 0, m = lpDDSD->ddpfPixelFormat.dwRBitMask; + !(m & 1); r++, m >>= 1); + for (r = 0; m & 1; r++, m >>= 1); + for (g = 0, m = lpDDSD->ddpfPixelFormat.dwGBitMask; + !(m & 1); g++, m >>= 1); + for (g = 0; m & 1; g++, m >>= 1); + for (b = 0, m = lpDDSD->ddpfPixelFormat.dwBBitMask; + !(m & 1); b++, m >>= 1); + for (b = 0; m & 1; b++, m >>= 1); + d3d.TextureFormat[d3d.NumTextureFormats].RedBPP = r; + d3d.TextureFormat[d3d.NumTextureFormats].GreenBPP = g; + d3d.TextureFormat[d3d.NumTextureFormats].BlueBPP = b; + } + else + { + return DDENUMRET_OK; + } + + /* + If lpStartFormat is -1, this is the first format. + Select it. + */ + + if (*lpStartFormat == -1) + *lpStartFormat = d3d.NumTextureFormats; + else + { + if (PreferTextureFormat(&d3d.TextureFormat[*lpStartFormat],&d3d.TextureFormat[d3d.NumTextureFormats])) + *lpStartFormat = d3d.NumTextureFormats; + } + + d3d.NumTextureFormats++; + return DDENUMRET_OK; +} + + +// Code to pick a driver and scan draw mode +// based on what hardware is present on the +// system and the current request modes +// (specified by default in the InitialVideoMode +// call). +// The basic rules are that a hardware driver will +// always be picked if one is available unless +// software only rasterisation has been requested, +// in which case we will get a software driver anyway, +// and that hardware rgb scan draws will be picked if +// we are running on hardware, but otherwise the ramp +// software scan draw mode will be picked unless DirectDraw +// scan draws have been specifically requested. + +// Note that since rewrites to the VideoMode really ought +// to be done BEFORE SetVideoMode is run, this function's +// effects must be combined with those of +// InitialiseDirectDrawObject and TestInitD3DObject!!!! + +void SelectD3DDriverAndDrawMode(void) + +{ +// Note that if we have requested default rasterisation and hw is +// available, we may want to pick the software RGB driver if MMXAvailable +// is Yes!!! Fix later!!! + if ((D3DHardwareAvailable) + && (RasterisationRequestMode != RequestSoftwareRasterisation)) + { + int i=0; + BOOL EarlyExit = No; + + do + { + if (d3d.Driver[i].Hardware) + { + d3d.CurrentDriver = i; + EarlyExit = Yes; + } + } + while ((++i < d3d.NumDrivers) && !EarlyExit); + + D3DDriverMode = D3DHardwareRGBDriver; + ScanDrawMode = ScanDrawD3DHardwareRGB; + } +// Note that we may want to select the software RGB driver if default scan +// draws have been requested, should MMXAvailable be Yes... + else if (SoftwareScanDrawRequestMode == RequestScanDrawSoftwareRGB) + { + int i=0; + BOOL EarlyExit = No; + + do + { + if ((!d3d.Driver[i].Hardware) && + (d3d.Driver[i].Desc.dcmColorModel == D3DCOLOR_RGB)) + { + d3d.CurrentDriver = i; + EarlyExit = Yes; + } + } + while ((++i < d3d.NumDrivers) && !EarlyExit); + + D3DDriverMode = D3DSoftwareRGBDriver; + ScanDrawMode = ScanDrawD3DSoftwareRGB; + } +// Note that once everything, like, works, and Microsoft's code +// is dead fast and doesn't crash or anything, the default software +// scan draw mode should be changed from DirectDraw to Ramp. +// Probably. + else if (SoftwareScanDrawRequestMode == RequestScanDrawRamp) + { + int i=0; + BOOL EarlyExit = No; + + do + { + if ((!d3d.Driver[i].Hardware) && + (d3d.Driver[i].Desc.dcmColorModel == D3DCOLOR_MONO)) + { + d3d.CurrentDriver = i; + EarlyExit = Yes; + } + } + while ((++i < d3d.NumDrivers) && !EarlyExit); + + D3DDriverMode = D3DSoftwareRampDriver; + ScanDrawMode = ScanDrawD3DRamp; + } + else if ((SoftwareScanDrawRequestMode == RequestScanDrawDirectDraw) + || (SoftwareScanDrawRequestMode == RequestScanDrawDefault)) + { + int i=0; + BOOL EarlyExit = No; + + // Set ramp driver anyway for convenience + do + { + if ((!d3d.Driver[i].Hardware) && + (d3d.Driver[i].Desc.dcmColorModel == D3DCOLOR_MONO)) + { + d3d.CurrentDriver = i; + EarlyExit = Yes; + } + } + while ((++i < d3d.NumDrivers) && !EarlyExit); + + D3DDriverMode = D3DSoftwareRampDriver; + ScanDrawMode = ScanDrawDirectDraw; + } + else // bollocks + { + ReleaseDirect3D(); + exit(0xdeaf); + } + + #if SupportZBuffering + if (ZBufferRequestMode == RequestZBufferAlways) + { + if (d3d.Driver[d3d.CurrentDriver].ZBuffer) + ZBufferMode = ZBufferOn; + else + ZBufferMode = ZBufferOff; + } + else if (ZBufferRequestMode == RequestZBufferDefault) + { + if ((d3d.Driver[d3d.CurrentDriver].ZBuffer) + && (d3d.Driver[d3d.CurrentDriver].Hardware)) + ZBufferMode = ZBufferOn; + else + ZBufferMode = ZBufferOff; + } + else + ZBufferMode = ZBufferOff; + #endif + + + // Overrides for test purposes only + + #if ForceRampDriver + d3d.CurrentDriver = 0; + D3DDriverMode = D3DSoftwareRampDriver; + ScanDrawMode = ScanDrawD3DRamp; + #endif + + #if ForceRGBDriver + d3d.CurrentDriver = 1; + D3DDriverMode = D3DSoftwareRGBDriver; + ScanDrawMode = ScanDrawD3DSoftwareRGB; + #endif + + #if ForceHardwareDriver + d3d.CurrentDriver = 2; + D3DDriverMode = D3DHardwareRGBDriver; + ScanDrawMode = ScanDrawD3DHardwareRGB; + #endif + + #if ForceDirectDraw + d3d.CurrentDriver = 0; + D3DDriverMode = D3DSoftwareRampDriver; + ScanDrawMode = ScanDrawDirectDraw; + #endif + +} + +#if SUPPORT_MMX +int use_mmx_math; +void SelectMMXOptions(void) +{ + if (MMXAvailable) + use_mmx_math = 1; + else + use_mmx_math = 0; +} +#endif + +// Initialise temporary D3D object and then destroy +// it again, SOLELY for the purpose of determining +// whether hardware acceleration is available + +// NOTE THIS -->MUST<-- BE RUN -->AFTER<-- +// InitialiseDirectDrawObject!!! + +BOOL TestInitD3DObject(void) +{ + // Zero hardware available global + D3DHardwareAvailable = No; + +// Zero d3d structure + memset(&d3d, 0, sizeof(D3DINFO)); + +// Set up Direct3D interface object + LastError = lpDD->QueryInterface(IID_IDirect3D, (LPVOID*) &d3d.lpD3D); + + if (LastError != DD_OK) + return FALSE; + +// Use callback function to enumerate available devices on system +// and acquire device GUIDs etc + + LastError = d3d.lpD3D->EnumDevices(DeviceEnumerator, (LPVOID)&StartDriver); + + if (LastError != D3D_OK) + return FALSE; + + // select the usual driver - get its description + int old_rrm = RasterisationRequestMode; + RasterisationRequestMode = RequestDefaultRasterisation; + SelectD3DDriverAndDrawMode(); + d3d.ThisDriver = d3d.Driver[d3d.CurrentDriver].Desc; + RasterisationRequestMode = old_rrm; + +// THE TEXTURE FORMATS ENUMERATOR COULD ALSO BE CALLED HERE TO DETERMINE +// WHETHER PALETTISED FORMATS ETC ARE AVAILABLE. + +// NOTE THAT GETAVAILABLEVIDEOMEMORY (IN DD_FUNC.CPP) CAN BE USED TO REPORT +// THE FREE VIDEO MEMORY AT ANY TIME. + + +// Eliminate Direct3D object again + RELEASE(d3d.lpD3D); + +// Code to reset video mode depending on +// presence of hardware acceleration should +// go here. NOTE THAT AT A LATER DATE THIS CODE +// MUST ALSO TAKE ACCOUNT OF THE SETTING OF +// MMXAVAILABLE AND SUCH INFORMATION IN THE D3DINFO +// STRUCTURE AS DOES THE DRIVER DO TEXTURES +// OR Z-BUFFERING. FIXME!!! + + #if 0 + if ((D3DHardwareAvailable) && + (RasterisationRequestMode == RequestDefaultRasterisation)) + { + if ((VideoMode == VideoMode_DX_320x200x8) || + (VideoMode == VideoMode_DX_320x240x8)) + { + if (CheckForVideoModes(VideoMode_DX_320x200x15)) + { + VideoMode = VideoMode_DX_320x200x15; + return TRUE; + } + else if (CheckForVideoModes(VideoMode_DX_640x480x15)) + { + VideoMode = VideoMode_DX_640x480x15; + return TRUE; + } + else + return FALSE; + } + else if (VideoMode == VideoMode_DX_640x480x8) + { + if (CheckForVideoModes(VideoMode_DX_640x480x15)) + { + VideoMode = VideoMode_DX_640x480x15; + return TRUE; + } + else + return FALSE; + } + } + #else + // test only!!! + { + if (D3DHardwareAvailable) + TestHw = Yes; + else + TestHw = No; + } + #endif + + return TRUE; +} + +// Function to test access speed of VRAM +// against system memory using the DD blt +// members, and set DXMemoryMode using this +// result and the DXMemoryRequestMode as a basis. +// Note that we must allow for bank flipping +// speed. +// Potentially we should also test processor +// copy against video card blitter if the blitter +// is in hardware, since some blitters can be slower +// than the system processor. + +// THIS FUNCTION HAS NOT YET BEEN DONE, SEEING AS IT +// DOESN'T ACTUALLY MAKE MUCH DIFFERENCE TO THE SPEED +// IN PRACTICE. + +// NOTE ALSO that DXMemoryMode has itself +// not yet been fully implemented, since with +// all buffers forced into system memory DD +// doesn't seem to work properly anyway... + +// NOTE, HOWEVER, THAT THIS FUNCTION MUST READ +// MMXAvailable and D3DHardwareAvailable, +// since if MMX driver is picked we want the +// back buffer in SYSTEM memory, not video +// (as of 26 / 7 / 96). + +// MUST PUT BACK BUFFER IN VIDEO MEMORY ON +// AN ACCELERATOR!!! + +BOOL TestMemoryAccess(void) + +{ + // We take this request AT IT'S WORD, i.e. to mean + // that we will always do our best to provide a system + // memory target. Note that this means that if we then + // go on to boot up on hardware nothing will actually appear + // on the screen, though the debugger should work (in SubWindow + // mode, obviously). A more subtle test might be appropriate here, + // though it IS a debugging thing... + if (DXMemoryRequestMode == RequestSystemMemoryAlways) + DXMemoryMode = SystemMemoryPreferred; + else // assume default + { + // Note that at this stage we have a DirectDraw object on which + // to run GetCaps, we have detected the processor type and we have run + // TestInitD3DObject, so we have determined whether or not hardware + // acceleration is available. + + // Rendering target must be in VRAM if we are to run accelerated. + // Note that we really want to know whether we are going to run + // accelerated, not whether we can do, but this requires integration + // with the project's rules for deciding on its running mode. + // This function should probably be moved to d3_proj.cpp along + // with SelectD3DDriverAndMode and TestInitD3DObject... + if (D3DHardwareAvailable) + DXMemoryMode = VideoMemoryPreferred; + // For MMX we are currently assuming a high scan draw throughput, + // as VideoModeType_15 is likely to be the optimal solution, which + // is liable to result in a system gated by VRAM speed for a video + // memory rendering target. For this system we therfore want a system + // memory target. + else if (MMXAvailable) + DXMemoryMode = SystemMemoryPreferred; + // We are now assuming a DirectDraw software solution with our + // scan draws, on a standard(ish) video card. At this point we need + // to make an intelligent decision, remembering that in practice + // system memory targets are rarely faster than video memory ones + // for this situation. + else + { + // On the basis of experiment, these are the important + // video card capabilities for 3dc. + BOOL Flip; + BOOL BlitSysMem; + BOOL BlitVidMem; + BOOL BlitFloodFill; + BOOL BlitAsyncQueue; + BOOL BankSwitched; + // Timing factors + int TimeForVramWrite; + int TimeForSysMemWrite; + unsigned char* SurfacePtr; + // DirectX intfc + DDCAPS ddcaps; + HRESULT ddrval; + LPDIRECTDRAWSURFACE lpTestSurf; + DDSURFACEDESC ddsd; + // etc + int i; + int TestSurfHeight = 480; + int TestSurfWidth = 640; + + // Get caps on the DirectDraw object + memset(&ddcaps, 0, sizeof(ddcaps)); + ddcaps.dwSize = sizeof(ddcaps); + ddrval = lpDD->GetCaps(&ddcaps, NULL); + LOGDXERR(ddrval); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(ddrval); + } + #else + { + return FALSE; + } + #endif + + if (ddcaps.dwCaps & DDCAPS_BLT) + BlitVidMem = TRUE; + else + BlitVidMem = FALSE; + + if (ddcaps.dwCaps & DDCAPS_BANKSWITCHED) + BankSwitched = TRUE; + else + BankSwitched = FALSE; + + if (ddcaps.dwCaps & DDCAPS_BLTCOLORFILL) + BlitFloodFill = TRUE; + else + BlitFloodFill = FALSE; + + if (ddcaps.dwCaps & DDCAPS_BLTQUEUE) + BlitAsyncQueue = TRUE; + else + BlitAsyncQueue = FALSE; + + if (ddcaps.dwCaps & DDCAPS_CANBLTSYSMEM) + BlitSysMem = TRUE; + else + BlitSysMem = FALSE; + + if (ddcaps.ddsCaps.dwCaps & DDSCAPS_FLIP) + Flip = TRUE; + else + Flip = FALSE; + + // Creating surfaces like this before setting exclusive mode + // und so weiter seems to REALLY UPSET IT. So for now, we + // shall say sod it and decide purely on the basis of the caps. + #if 0 + // Create a DD surface in Vram + memset(&ddsd,0,sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + // 640 x 480 would be a typical screen + ddsd.dwHeight = TestSurfHeight; + ddsd.dwWidth = TestSurfWidth; + ddsd.ddsCaps.dwCaps= (DDSCAPS_OFFSCREENPLAIN); + + ddrval = lpDD->CreateSurface(&ddsd, &lpTestSurf, NULL); + LOGDXERR(ddrval); + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(ddrval); + } + #else + return FALSE; + #endif + + SurfacePtr = (unsigned char*) ddsd.lpSurface; + + // Time write + TimeForVramWrite = timeGetTime(); + for (i=0; iCreateSurface(&ddsd, &lpTestSurf, NULL); + LOGDXERR(ddrval); + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(ddrval); + } + #else + return FALSE; + #endif + + SurfacePtr = (unsigned char*) ddsd.lpSurface; + + // Time write + TimeForSysMemWrite = timeGetTime(); + for (i=0; i> 8) & 0xff; + fputc(c1, fp); + fputc(c2, fp); +} + +VOID PutLittleDword(DWORD v, FILE *fp) +{ + unsigned char c1 = v & 0xff; + unsigned char c2 = (v >> 8) & 0xff; + unsigned char c3 = (v >> 16) & 0xff; + unsigned char c4 = (v >> 24) & 0xff; + + fputc(c1, fp); + fputc(c2, fp); + fputc(c3, fp); + fputc(c4, fp); +} diff --git a/3dc/avp/win95/endianio.h b/3dc/avp/win95/endianio.h new file mode 100644 index 0000000..42346b8 --- /dev/null +++ b/3dc/avp/win95/endianio.h @@ -0,0 +1,25 @@ +#ifndef _included_endianio_h_ +#define _included_endianio_h_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include + +#include "datatype.h" + +BYTE GetByte(FILE *fp); +WORD GetLittleWord(FILE *fp); +DWORD GetLittleDword(FILE *fp); + +VOID PutByte(BYTE v, FILE *fp); +VOID PutLittleWord(WORD v, FILE *fp); +VOID PutLittleDword(DWORD v, FILE *fp); + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ + +#endif /* _included_endianio_h_ */ + diff --git a/3dc/avp/win95/font.h b/3dc/avp/win95/font.h new file mode 100644 index 0000000..10fda20 --- /dev/null +++ b/3dc/avp/win95/font.h @@ -0,0 +1,219 @@ +#ifndef _font_h_included +#define _font_h_included 1 + + #ifdef __cplusplus + // Necessary header files for the C++ stuff: + #ifndef _projtext + #include "projtext.h" + #endif + #endif + +#include "aw.h" + +/************* fonts. not set up yet************/ + +typedef enum fonts +{ + MENU_FONT_1, + DATABASE_FONT_DARK, + DATABASE_FONT_LITE, + DATABASE_MESSAGE_FONT, + + IntroFont_Dark, + IntroFont_Light, + + NUM_FONTS, + +}AVP_FONTS; + +#define MAXNUM_CHARS_IN_FONT (0x7e) + + +/* platform dependent character descriptor + +we dont need give any info apart from the size and src of the +thing to BLT for W95. The textprint routines will handle the +position of the surface on the screen + +*/ + +typedef enum font_types +{ + I_FONT_NUMERIC, + I_FONT_UC_NUMERIC, + I_FONT_UCLC_NUMERIC, +}FONT_TYPE; + +/* NUMERIC - COUNTS FROM ASCII 0x30 to 0x39 inc*/ +/* UC NUMERIC 0x20 t0 0x5A */ +/* UCLC_NUMERIC 0cx20 to 0x7E inc */ + + +// menu strings - printed to the creen with a certain +// justification + +typedef enum font_justification +{ + FJ_LEFT_JUST, + FJ_CENTRED, + FJ_RIGHT_JUST, +}FONT_JUST; + + +// this prints a string packet + +typedef struct font_desc { + int fontnum; // see list of PFFONTS; + char *string; // this will eventually point into a resource fileMENU_GRAPHIC_ITEM Gamestart_MenuItems[] = { + short destx; + short desty; + FONT_JUST just; + short width; // width - the width we have to print + // the font in - overrides onto next line +} FONT_DESC; + + +// bitfield of flags + +typedef struct +{ + unsigned int loaded : 1; + +}FONT_FLAGS; + + +typedef struct pffont +{ + LPDIRECTDRAWSURFACE data; /*LPDIRECTDRAWSURFACE, etc - fill out*/ + char filename[100]; /*compile in -filename */ + int fontHeight; /* max height of chars */ + int num_chars_in_font; /*number of chars in this font */ + FONT_TYPE font_type; + FONT_FLAGS flags; + RECT_AVP srcRect[MAXNUM_CHARS_IN_FONT]; /*source rectangles*/ + + + int fttexWidth; /* filled in during loading */ + int fttexHeight; + int fttexBitDepth; + unsigned hotSpotValue; + AW_BACKUPTEXTUREHANDLE hBackup; + + #ifdef __cplusplus + // C++ methods: //////////////////////////////// + int GetHeight(void) const; + int GetWidth(const ProjChar ProjCh) const; + int bPrintable(const ProjChar ProjCh) const; + int ProjCharToOffset(const ProjChar ProjCh) const; + + int GetOffset(void) const; + // DHM 25/11/97: + // Returns offset for subtracting from ASCII code to get + // to index into the font + int GetMinChar(void) const; + int GetMaxChar(void) const; + // returns extent within the ASCII set that can be printed (inclusive of boundary values) + + #endif // __cplusplus + +}PFFONT; + +#ifdef __cplusplus + + // Inline method implementations: + inline int pffont::GetHeight(void) const + { + return fontHeight; + } + inline int pffont::GetWidth(const ProjChar ProjCh) const + { + if ( bPrintable(ProjCh) ) + { + const RECT_AVP& charRect = srcRect[ ProjCharToOffset(ProjCh) ] ; + + return (charRect . right - charRect . left); + } + else + { + return 0; + } + } + inline int pffont::bPrintable(const ProjChar ProjCh) const + { + const int Offset = GetOffset(); + + if ( (int)ProjCh < Offset ) + { + return No; + } + if ( (int)ProjCh >= Offset + num_chars_in_font ) + { + return No; + } + return Yes; + } + inline int pffont::ProjCharToOffset(const ProjChar ProjCh) const + { + return ((int)ProjCh - GetOffset()); + } + inline int pffont::GetOffset(void) const + { + // DHM 25/11/97: + // Returns offset for subtracting from ASCII code to get + // to index into the font + if (font_type == I_FONT_NUMERIC) + { + return 0x30; + } + else + { + return 0x20; + } + } + inline int pffont::GetMinChar(void) const + { + return GetOffset(); + } + inline int pffont::GetMaxChar(void) const + { + return (GetOffset() + num_chars_in_font -1); + } + + + extern "C" { +#endif + +// platform independent externs +extern void LoadAllFonts(); +extern void LoadPFFont(int fontnum); + + // platform dependent callbacks for loading +extern void LoadFont(PFFONT *pffont); +extern void UnloadFont(PFFONT *pffont); + +extern void FillCharacterSlot(int u, int v, int width, int height, + int charnum, PFFONT *font); + +extern int BLTFontOffsetToHUD(PFFONT* font , int xdest, int ydest, int offset); + + +/* to lock a font and get the raw data - pPitch receives the pitch of the surface */ +extern void * FontLock(PFFONT const * pFont, unsigned * pPitch); +extern void FontUnlock(PFFONT const * pFont); + + +// drawing functions + +extern void BLTWholeFont(int fontnum, int x , int y, int win_width); +extern void BLTString(FONT_DESC str_packet); + + +// the array of all the Fonts int the game +extern PFFONT AvpFonts[]; + +#ifdef __cplusplus + }; +#endif + +#endif /* _font_h_included */ + diff --git a/3dc/avp/win95/gadgets/ahudgadg.cpp b/3dc/avp/win95/gadgets/ahudgadg.cpp new file mode 100644 index 0000000..bd88df6 --- /dev/null +++ b/3dc/avp/win95/gadgets/ahudgadg.cpp @@ -0,0 +1,315 @@ +/******************************************************************* + * + * DESCRIPTION: ahudgadg.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 14/11/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "ahudgadg.hpp" + + #if UseGadgets + #include "trepgadg.hpp" + #include "t_ingadg.hpp" + #include "iofocus.h" + #endif + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +#if UseGadgets +// class AlienHUDGadget : public HUDGadget +// public: +void AlienHUDGadget :: Render +( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha +) +{ + #if 0 + textprint + ( + "AlienHUDGadget :: Render at (%i,%i) clipped (%i,%i,%i,%i) alpha=%i\n", + R2Pos . x, + R2Pos . y, + R2Rect_Clip . x0, + R2Rect_Clip . y0, + R2Rect_Clip . x1, + R2Rect_Clip . y1, + FixP_Alpha + ); + #endif + + pTextReportGadg -> UpdateLineTimes(); + + struct r2pos R2Pos_TextReport = pTextReportGadg -> GetPos_Rel + ( + R2Rect_Clip + ); + + GLOBALASSERT( pTextReportGadg ); + { + pTextReportGadg -> Render + ( + R2Pos_TextReport, + R2Rect_Clip, + FixP_Alpha + ); + } + + // Render the text entry line iff input focus is set to text entry: + GLOBALASSERT( pTextEntryGadg ); + if + ( + IOFOCUS_AcceptTyping() + ) + { + // Force the text report gadget onto the screen + pTextReportGadg -> ForceOnScreen(); + + // Render the text entry gadget: + pTextEntryGadg -> Render + ( + r2pos + ( + R2Pos_TextReport . x, + R2Pos_TextReport . y + pTextReportGadg -> GetSize + ( + R2Rect_Clip + ) . h + ), + R2Rect_Clip, + FixP_Alpha + ); + } + else + { + // Tell the text entry gadget it's not being rendered + // (so it can fade out internally; however nothing will appear on-screen) + pTextEntryGadg -> DontRender(); + } + +} + +AlienHUDGadget :: AlienHUDGadget +( +) : HUDGadget + ( + #if debug + "AlienHUDGadget" + #endif + ) +{ + pTextReportGadg = new TextReportGadget(); + + pTextEntryGadg = new TextEntryGadget(); + +} + + +AlienHUDGadget :: ~AlienHUDGadget() +{ + delete pTextEntryGadg; + delete pTextReportGadg; +} + +void AlienHUDGadget :: AddTextReport +( + SCString* pSCString_ToAdd + // ultimately turn into an MCString +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pSCString_ToAdd ); + + GLOBALASSERT( pTextReportGadg ); + } + + /* CODE */ + { + pTextReportGadg -> AddTextReport + ( + pSCString_ToAdd + ); + } +} +void AlienHUDGadget :: ClearTheTextReportQueue(void) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pTextReportGadg ); + } + + /* CODE */ + { + pTextReportGadg -> ClearQueue(); + } +} + +#if EnableStatusPanels +void AlienHUDGadget :: RequestStatusPanel +( + enum StatusPanelIndex I_StatusPanel +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( I_StatusPanel < NUM_STATUS_PANELS ); + } + + /* CODE */ + { + // empty for the moment + } +} + +void AlienHUDGadget :: NoRequestedPanel(void) +{ + // empty for the moment +} +#endif // EnableStatusPanels + +void AlienHUDGadget :: CharTyped +( + char Ch + // note that this _is _ a char +) +{ + GLOBALASSERT( pTextEntryGadg ); + + pTextEntryGadg -> CharTyped + ( + Ch + ); +} + +void AlienHUDGadget :: Key_Backspace(void) +{ + GLOBALASSERT( pTextEntryGadg ); + pTextEntryGadg -> Key_Backspace(); +} +void AlienHUDGadget :: Key_End(void) +{ + GLOBALASSERT( pTextEntryGadg ); + pTextEntryGadg -> Key_End(); +} +void AlienHUDGadget :: Key_Home(void) +{ + GLOBALASSERT( pTextEntryGadg ); + pTextEntryGadg -> Key_Home(); +} +void AlienHUDGadget :: Key_Left(void) +{ + GLOBALASSERT( pTextEntryGadg ); + pTextEntryGadg -> Key_Left(); +} +void AlienHUDGadget :: Key_Up(void) +{ + GLOBALASSERT( pTextEntryGadg ); + pTextEntryGadg -> Key_Up(); +} +void AlienHUDGadget :: Key_Right(void) +{ + GLOBALASSERT( pTextEntryGadg ); + pTextEntryGadg -> Key_Right(); +} +void AlienHUDGadget :: Key_Down(void) +{ + GLOBALASSERT( pTextEntryGadg ); + pTextEntryGadg -> Key_Down(); +} +void AlienHUDGadget :: Key_Delete(void) +{ + GLOBALASSERT( pTextEntryGadg ); + pTextEntryGadg -> Key_Delete(); +} +void AlienHUDGadget :: Key_Tab(void) +{ + GLOBALASSERT( pTextEntryGadg ); + pTextEntryGadg -> Key_Tab(); +} + +void AlienHUDGadget :: Jitter(int FixP_Magnitude) +{ + // empty for now +} + +void AlienHUDGadget :: SetString(const char* text) +{ + SCString* string = new SCString(text); + pTextEntryGadg -> SetString(*string); + string->R_Release(); +} + + +extern "C" +{ +void BringDownConsoleWithSayTypedIn() +{ + //bring down console if it isn't already down + if(!IOFOCUS_AcceptTyping()) IOFOCUS_Toggle(); + + //put "SAY " in the console + ((AlienHUDGadget*)HUDGadget :: GetHUD())->SetString("SAY "); +} + +void BringDownConsoleWithSaySpeciesTypedIn() +{ + //bring down console if it isn't already down + if(!IOFOCUS_AcceptTyping()) IOFOCUS_Toggle(); + + //put "SAY_SPECIES " in the console + ((AlienHUDGadget*)HUDGadget :: GetHUD())->SetString("SAY_SPECIES "); +} +}; + +// private: +#endif // UseGadgets + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/win95/gadgets/ahudgadg.hpp b/3dc/avp/win95/gadgets/ahudgadg.hpp new file mode 100644 index 0000000..c193068 --- /dev/null +++ b/3dc/avp/win95/gadgets/ahudgadg.hpp @@ -0,0 +1,101 @@ +/* + + ahudgadg.hpp + + Alien HUD gadget; a concrete derived class of abstract class "HUDGadget" + +*/ + +#ifndef _ahudgadg +#define _ahudgadg 1 + + #ifndef _hudgadg + #include "hudgadg.hpp" + #endif + + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + #if UseGadgets + class TextEntryGadget; // fully declared in TEXTIN.HPP + + class AlienHUDGadget : public HUDGadget + { + public: + void Render + ( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha + ); + + AlienHUDGadget(); + ~AlienHUDGadget(); + + void AddTextReport + ( + SCString* pSCString_ToAdd + // ultimately turn into an MCString + ); + void ClearTheTextReportQueue(void); + + #if EnableStatusPanels + void RequestStatusPanel + ( + enum StatusPanelIndex I_StatusPanel + ); + + void NoRequestedPanel(void); + #endif + + void CharTyped + ( + char Ch + // note that this _is _ a char + ); + void Key_Backspace(void); + void Key_End(void); + void Key_Home(void); + void Key_Left(void); + void Key_Up(void); + void Key_Right(void); + void Key_Down(void); + void Key_Delete(void); + void Key_Tab(void); + + void SetString(const char* text); + + void Jitter(int FixP_Magnitude); + + TextReportGadget* pTextReportGadg; + private: + // not allowed to be NULL + + TextEntryGadget* pTextEntryGadg; + // not allowed to be NULL + }; + #endif // UseGadgets + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/win95/gadgets/conscmnd.cpp b/3dc/avp/win95/gadgets/conscmnd.cpp new file mode 100644 index 0000000..b279302 --- /dev/null +++ b/3dc/avp/win95/gadgets/conscmnd.cpp @@ -0,0 +1,513 @@ +/******************************************************************* + * + * DESCRIPTION: conscmnd.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 28/1/98 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "conscmnd.hpp" +#include "strutil.h" + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + /*static*/ List ConsoleCommand :: List_pConsoleCommand; + +/* Internal type definitions ***************************************/ + + class ConsoleCommand_VoidVoid : public ConsoleCommand + { + public: + ConsoleCommand_VoidVoid + ( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + void (*f) (void), + OurBool Cheat = FALSE + ); + void Execute(ProjChar* pProjCh_In); + + private: + void (*theFn) (void); + }; + class ConsoleCommand_VoidInt : public ConsoleCommand + { + public: + ConsoleCommand_VoidInt + ( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + void (*f) (int), + OurBool Cheat = FALSE + ); + void Execute(ProjChar* pProjCh_In); + private: + void (*theFn) (int); + }; + class ConsoleCommand_IntVoid : public ConsoleCommand + { + public: + ConsoleCommand_IntVoid + ( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + int (*f) (void), + OurBool Cheat = FALSE + ); + void Execute(ProjChar* pProjCh_In); + private: + int (*theFn) (void); + }; + class ConsoleCommand_IntInt : public ConsoleCommand + { + public: + ConsoleCommand_IntInt + ( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + int (*f) (int), + OurBool Cheat = FALSE + ); + void Execute(ProjChar* pProjCh_In); + private: + int (*theFn) (int); + }; + class ConsoleCommand_VoidCharP : public ConsoleCommand + { + public: + ConsoleCommand_VoidCharP + ( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + void (*f) (char*), + OurBool Cheat = FALSE + ); + void Execute(ProjChar* pProjCh_In); + private: + void (*theFn) (char*); + }; + + +/* Internal function ProjChar* pProjCh_In*/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +// class ConsoleCommand : public ConsoleSymbol +// public: + +// Various factory methods: +/*static*/ void ConsoleCommand :: Make +( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + void (&f) (void), + OurBool Cheat +) +{ + new ConsoleCommand_VoidVoid + ( + pProjCh_ToUse, + pProjCh_Description_ToUse, + f, + Cheat + ); +} +/*static*/ void ConsoleCommand :: Make +( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + void (&f) (int), + OurBool Cheat +) +{ + new ConsoleCommand_VoidInt + ( + pProjCh_ToUse, + pProjCh_Description_ToUse, + f, + Cheat + ); +} +/*static*/ void ConsoleCommand :: Make +( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + int (&f) (void), + OurBool Cheat + +) +{ + new ConsoleCommand_IntVoid + ( + pProjCh_ToUse, + pProjCh_Description_ToUse, + f, + Cheat + ); +} + +/*static*/ void ConsoleCommand :: Make +( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + int (&f) (int), + OurBool Cheat +) +{ + new ConsoleCommand_IntInt + ( + pProjCh_ToUse, + pProjCh_Description_ToUse, + f, + Cheat + ); +} +/*static*/ void ConsoleCommand :: Make +( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + void (&f) (char*), + OurBool Cheat +) +{ + new ConsoleCommand_VoidCharP + ( + pProjCh_ToUse, + pProjCh_Description_ToUse, + f, + Cheat + ); +} + +/*static*/ OurBool ConsoleCommand :: Process( ProjChar* pProjCh_In ) +{ + // used for proccesing input text. + // return value = was any processing performed? + + GLOBALASSERT( pProjCh_In ); + + OurBool bProcessed = No; + + // Parse into words; find the first word. Iterate through the commands + // looking for a match: + + { + ProjChar *commandPtr = pProjCh_In; + ProjChar *argumentPtr = pProjCh_In; + + while(*argumentPtr!=0 && *argumentPtr!=' ') + { + argumentPtr++; + } + + // if we found a space at the end of the first word + // change it to a terminator, and point to the text after it + if (*argumentPtr) *argumentPtr++=0; + + // otherwise we'll be pointing to a terminator anyway + + + if ( *commandPtr ) + { + // Iterate through the console commands; looking for a match + { + for + ( + LIF oi(&List_pConsoleCommand); + !oi . done(); + oi . next() + ) + { + GLOBALASSERT(oi()); + GLOBALASSERT(oi()-> pSCString_Symbol ); + + + if + ( + oi()->ThisIsACheat ? + + STRUTIL_SC_Strequal //case sensitive comparisons for cheats + ( + oi() -> pSCString_Symbol -> pProjCh(), + commandPtr + ) + : + STRUTIL_SC_Strequal_Insensitive //case insensitive otherwise + ( + oi() -> pSCString_Symbol -> pProjCh(), + commandPtr + ) + ) + { + // Got match + bProcessed = Yes; + + // Execute the function: + { + oi() -> Execute(argumentPtr); + } + } + } + } + if (*argumentPtr) *(--argumentPtr)=' '; + } + + + } + + return bProcessed; +} + + +/*static*/ void ConsoleCommand :: ListAll(void) +{ + SCString* pSCString_Temp = new SCString("LIST OF ALL CONSOLE COMMANDS:"); + // LOCALISEME() + + pSCString_Temp -> SendToScreen(); + + pSCString_Temp ->R_Release(); + + for + ( + LIF oi(&List_pConsoleCommand); + !oi.done(); + oi.next() + ) + { + oi() -> Display(); + } +} + +/*virtual*/ ConsoleCommand :: ~ConsoleCommand() +{ + pSCString_Description -> R_Release(); + + List_pConsoleCommand . delete_entry(this); + +} + +void ConsoleCommand :: Display(void) const +{ + SCString* pSCString_Temp1 = new SCString("\""); + SCString* pSCString_Temp2 = new SCString("\" "); + + SCString* pSCString_Feedback = new SCString + ( + pSCString_Temp1, + pSCString_Symbol, + pSCString_Temp2, + pSCString_Description + ); + + pSCString_Temp2 -> R_Release(); + pSCString_Temp1 -> R_Release(); + + pSCString_Feedback -> SendToScreen(); + + pSCString_Feedback -> R_Release(); +} + + +// protected: +ConsoleCommand :: ConsoleCommand +( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + OurBool Cheat +) : ConsoleSymbol(pProjCh_ToUse), + pSCString_Description( new SCString(pProjCh_Description_ToUse) ) +{ + ThisIsACheat = Cheat; + List_pConsoleCommand . add_entry(this); +} + +void ConsoleCommand :: EchoResult(int Result) +{ + SCString* pSCString_Feedback = new SCString(Result); + pSCString_Feedback -> SendToScreen(); + pSCString_Feedback -> R_Release(); +} + +int ConsoleCommand :: GetArg(ProjChar* pProjCh_Arg) +{ + GLOBALASSERT( pProjCh_Arg ); + + return atoi(pProjCh_Arg); +} + + +/* Internal function definitions ***********************************/ +// class ConsoleCommand_VoidVoid : public ConsoleCommand +// public: +ConsoleCommand_VoidVoid :: ConsoleCommand_VoidVoid +( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + void (*f) (void), + OurBool Cheat + +) : ConsoleCommand + ( + pProjCh_ToUse, + pProjCh_Description_ToUse, + Cheat + ), + theFn(f) +{ +} +void ConsoleCommand_VoidVoid :: Execute(ProjChar* pProjCh_In) +{ + GLOBALASSERT(theFn); + GLOBALASSERT(pProjCh_In); + (*theFn)(); +} +// class ConsoleCommand_VoidInt : public ConsoleCommand +// public: +ConsoleCommand_VoidInt :: ConsoleCommand_VoidInt +( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + void (*f) (int), + OurBool Cheat + +) : ConsoleCommand + ( + pProjCh_ToUse, + pProjCh_Description_ToUse, + Cheat + ), + theFn(f) +{ +} +void ConsoleCommand_VoidInt :: Execute(ProjChar* pProjCh_In) +{ + GLOBALASSERT(theFn); + GLOBALASSERT(pProjCh_In); + (*theFn) + ( + GetArg(pProjCh_In) + ); +} +// class ConsoleCommand_IntVoid : public ConsoleCommand +// public: +ConsoleCommand_IntVoid :: ConsoleCommand_IntVoid +( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + int (*f) (void), + OurBool Cheat + +) : ConsoleCommand + ( + pProjCh_ToUse, + pProjCh_Description_ToUse, + Cheat + ), + theFn(f) +{ +} +void ConsoleCommand_IntVoid :: Execute(ProjChar* pProjCh_In) +{ + GLOBALASSERT(theFn); + GLOBALASSERT(pProjCh_In); + EchoResult + ( + (*theFn)() + ); +} +// class ConsoleCommand_IntInt : public ConsoleCommand +// public: +ConsoleCommand_IntInt :: ConsoleCommand_IntInt +( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + int (*f) (int), + OurBool Cheat +) : ConsoleCommand + ( + pProjCh_ToUse, + pProjCh_Description_ToUse, + Cheat + ), + theFn(f) +{ +} +void ConsoleCommand_IntInt :: Execute(ProjChar* pProjCh_In) +{ + GLOBALASSERT(theFn); + GLOBALASSERT(pProjCh_In); + + EchoResult + ( + (*theFn) + ( + GetArg(pProjCh_In) + ) + ); +} + + +ConsoleCommand_VoidCharP :: ConsoleCommand_VoidCharP +( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + void (*f) (char*), + OurBool Cheat + +) : ConsoleCommand + ( + pProjCh_ToUse, + pProjCh_Description_ToUse, + Cheat + ), + theFn(f) +{ +} +void ConsoleCommand_VoidCharP :: Execute(ProjChar* pProjCh_In) +{ + GLOBALASSERT(theFn); + GLOBALASSERT(pProjCh_In); + (*theFn) + ( + pProjCh_In + ); +} diff --git a/3dc/avp/win95/gadgets/conscmnd.hpp b/3dc/avp/win95/gadgets/conscmnd.hpp new file mode 100644 index 0000000..c52a3ad --- /dev/null +++ b/3dc/avp/win95/gadgets/conscmnd.hpp @@ -0,0 +1,116 @@ +/* + + conscmnd.hpp + +*/ + +#ifndef _conscmnd +#define _conscmnd 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + + #ifndef _conssym_hpp + #include "conssym.hpp" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + class ConsoleCommand : public ConsoleSymbol + { + public: + static void CreateAll(void); + + // Various factory methods: + static void Make + ( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + void (&f) (void), + OurBool Cheat = FALSE + ); + static void Make + ( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + void (&f) (int), + OurBool Cheat = FALSE + ); + static void Make + ( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + int (&f) (void), + OurBool Cheat = FALSE + ); + static void Make + ( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + int (&f) (int), + OurBool Cheat = FALSE + ); + static void Make + ( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + void (&f) (char*), + OurBool Cheat = FALSE + ); + + static OurBool Process( ProjChar* pProjCh_In ); + // used for proccesing input text. + // return value = was any processing performed? + + static void ListAll(void); + + virtual void Execute( ProjChar* pProjCh_In ) = 0; + + virtual ~ConsoleCommand(); + + void Display(void) const; + + + protected: + ConsoleCommand + ( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + OurBool Cheat = FALSE + ); + + void EchoResult(int Result); + int GetArg(ProjChar* pProjCh_Arg); + + private: + SCString* pSCString_Description; + + static List List_pConsoleCommand; + + }; + + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/win95/gadgets/conssym.cpp b/3dc/avp/win95/gadgets/conssym.cpp new file mode 100644 index 0000000..bf70a78 --- /dev/null +++ b/3dc/avp/win95/gadgets/conssym.cpp @@ -0,0 +1,92 @@ +/******************************************************************* + * + * DESCRIPTION: conssym.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 26/1/98 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "conssym.hpp" + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + /*static*/ List ConsoleSymbol :: List_pConsoleSym; + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +// class ConsoleSymbol +// public: + +// protected: +ConsoleSymbol :: ConsoleSymbol +( + ProjChar* pProjCh_ToUse +) : pSCString_Symbol + ( + new SCString( pProjCh_ToUse ) + // constructor for the SCString adds the required reference + ) +{ + List_pConsoleSym . add_entry + ( + this + ); +} + +ConsoleSymbol :: ~ConsoleSymbol() +{ + pSCString_Symbol ->R_Release(); + + // remove from the list + List_pConsoleSym . delete_entry + ( + this + ); +} + + + + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/win95/gadgets/conssym.hpp b/3dc/avp/win95/gadgets/conssym.hpp new file mode 100644 index 0000000..a3e8161 --- /dev/null +++ b/3dc/avp/win95/gadgets/conssym.hpp @@ -0,0 +1,82 @@ +/* + + conssym.hpp + + "Console symbols" - a base class for managing auto-completion of typing. + + Console commands and variables are derived from this class + +*/ + +#ifndef _conssym_hpp +#define _conssym_hpp 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + + #ifndef _scstring + #include "scstring.hpp" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + class ConsoleSymbol + { + friend class TextInputState; + /* WARNING! + + TextInputState objects can refer to the list of ConsoleSymbols + in order to iterate through possible completion strings. For + this reason, don't destroy ConsoleSymbol objects if TextInputState + objects exist... + (I believe I've asserted against all such possible failures) + */ + + public: + + OurBool ThisIsACheat; + protected: + ConsoleSymbol + ( + ProjChar* pProjCh_ToUse + ); + virtual ~ConsoleSymbol(); + + SCString* pSCString_Symbol; + + + public: + SCString* GetpSCString(void) const + { + return pSCString_Symbol; + } + + + private: + static List List_pConsoleSym; + }; // suggested naming: "ConsoleSym" + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/win95/gadgets/consvar.cpp b/3dc/avp/win95/gadgets/consvar.cpp new file mode 100644 index 0000000..4e0ab84 --- /dev/null +++ b/3dc/avp/win95/gadgets/consvar.cpp @@ -0,0 +1,727 @@ +/******************************************************************* + * + * DESCRIPTION: consvar.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 17/12/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "consvar.hpp" +#include "strutil.h" + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + /*static*/ List ConsoleVariable :: List_pConsoleVar; + +/* Internal type definitions ***************************************/ + class ConsoleVariable_Simple_Int : public ConsoleVariable + { + public: + ConsoleVariable_Simple_Int + ( + int& Value_ToUse, + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + int MinVal_New, + int MaxVal_New, + OurBool Cheat = FALSE + + ); + + int GetValue(void) const; + void SetValue(int Val_New); + void SetValue(float Val_New); + + private: + SCString* MakeRangeString(void); + SCString* MakeValueString(int Val); + + private: + int& theValue; + }; + + class ConsoleVariable_Simple_FixP : public ConsoleVariable + { + public: + ConsoleVariable_Simple_FixP + ( + int& Value_ToUse, + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + int MinVal_New, + int MaxVal_New, + OurBool Cheat = FALSE + + ); + + int GetValue(void) const; + void SetValue(int Val_New); + void SetValue(float Val_New); + + private: + SCString* MakeRangeString(void); + SCString* MakeValueString(int Val); + + static float FixP2Float(int FixP) + { + return + ( + ((float) FixP) / (ONE_FIXED) + ); + } + + private: + int& theValue; + }; + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +// class ConsoleVariable +// Factory method: +/*static*/ ConsoleVariable* ConsoleVariable :: MakeSimpleConsoleVariable_Int +( + int& Value_ToUse, + ProjChar* pProjCh_Symbol_ToUse, + ProjChar* pProjCh_Description_ToUse, + int MinVal_New, + int MaxVal_New, + OurBool Cheat + +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pProjCh_Symbol_ToUse ); + GLOBALASSERT( pProjCh_Description_ToUse ); + } + + /* CODE */ + { + return new ConsoleVariable_Simple_Int + ( + Value_ToUse, + pProjCh_Symbol_ToUse, + pProjCh_Description_ToUse, + MinVal_New, + MaxVal_New, + Cheat + ); + } +} + +/*static*/ ConsoleVariable* ConsoleVariable :: MakeSimpleConsoleVariable_FixP +( + int& Value_ToUse, + ProjChar* pProjCh_Symbol_ToUse, + ProjChar* pProjCh_Description_ToUse, + int MinVal_New, + int MaxVal_New, + OurBool Cheat + +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pProjCh_Symbol_ToUse ); + GLOBALASSERT( pProjCh_Description_ToUse ); + } + + /* CODE */ + { + return new ConsoleVariable_Simple_FixP + ( + Value_ToUse, + pProjCh_Symbol_ToUse, + pProjCh_Description_ToUse, + MinVal_New, + MaxVal_New, + Cheat + ); + } +} + +ConsoleVariable :: ~ConsoleVariable() +{ + pSCString_Description ->R_Release(); + + // remove from the list + List_pConsoleVar . delete_entry + ( + this + ); +} + +/*static*/ OurBool ConsoleVariable :: Process( ProjChar* pProjCh_In ) +{ + // used for proccesing input text. Could decide that the user + // was requesting the value of a variable, or was setting a new + // value etc; if so, acts accordingly. + // return value = was any processing performed? + + // Check to see if there's a match between the entire + // input string and each console command + { + for + ( + LIF oi(&List_pConsoleVar); + !oi.done(); + oi.next() + ) + { + if + ( + oi() -> ThisIsACheat + ? + STRUTIL_SC_Strequal //case sensitive comparisons for cheats + ( + pProjCh_In, + oi() -> pSCString_Symbol -> pProjCh() + ) + : + STRUTIL_SC_Strequal_Insensitive + ( + pProjCh_In, + oi() -> pSCString_Symbol -> pProjCh() + ) + ) + { + oi() -> Display(); + return Yes; + } + } + } + + // Otherwise check to see if there's a match between the front + // of the console command up to the first space (if any) + // with the rest being treated as a number + { + // Find the point in the input text where the first word + // ends (if there is one...): + ProjChar* pProjCh_Search = pProjCh_In; + int NumChars = 0; + + while + ( + (*pProjCh_Search != '\0') + && + (*pProjCh_Search != ' ') + ) + { + pProjCh_Search++; + NumChars++; + } + + if ( *pProjCh_Search == '\0' ) + { + // then there were no word breaks; stop + + return No; + } + + if ( NumChars < 1 ) + { + return No; + } + + for + ( + LIF oi(&List_pConsoleVar); + !oi.done(); + oi.next() + ) + { + + // LOCALISEME(): + if + ( + 0 == strncmp + ( + pProjCh_In, + oi() -> pSCString_Symbol -> pProjCh(), + NumChars + ) + ) + { + if (strchr(pProjCh_Search,'.')) + { + // interpret as fraction + float NewValue = atof(pProjCh_Search); + + oi() -> ProcessSetValue( NewValue ); + + return Yes; + } + else + { + // interpret as int + int NewValue = atoi(pProjCh_Search); + + oi() -> ProcessSetValue( NewValue ); + + return Yes; + + } + } + } + } + + + // If you get here, no processing has been performed: + return No; + +} + +/*static*/ void ConsoleVariable :: ListAllVariables(void) +{ + SCString* pSCString_Temp = new SCString("LIST OF ALL CONSOLE VARIABLES:"); + + pSCString_Temp -> SendToScreen(); + + pSCString_Temp ->R_Release(); + + for + ( + LIF oi(&List_pConsoleVar); + !oi.done(); + oi.next() + ) + { + oi() -> Display(); + } +} +// protected: +ConsoleVariable :: ConsoleVariable +( + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + int MinVal_New, + int MaxVal_New, + OurBool Cheat + +) : ConsoleSymbol + ( + pProjCh_ToUse + ), + pSCString_Description + ( + new SCString( pProjCh_Description_ToUse ) + // constructor for the SCString adds the required reference + ), + MinVal(MinVal_New), + MaxVal(MaxVal_New) +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + ThisIsACheat = Cheat; + + // add to list of all console variables + List_pConsoleVar . add_entry + ( + this + ); + } +} + +// private: +void ConsoleVariable :: Display(void) +{ + // used by the list display and to interrogate an individual variable + SCString* pSCString_Temp1 = new SCString + ( + " = " + ); + + SCString* pSCString_Temp2 = MakeValueString( GetValue() ); + + SCString* pSCString_Temp3 = MakeRangeString(); + + SCString* pSCString_Out = new SCString + ( + pSCString_Symbol, + pSCString_Temp1, + pSCString_Temp2, + pSCString_Temp3, + pSCString_Description + ); + + pSCString_Temp3 ->R_Release(); + pSCString_Temp2 ->R_Release(); + pSCString_Temp1 ->R_Release(); + + pSCString_Out -> SendToScreen(); + + pSCString_Out ->R_Release(); +} + + +void ConsoleVariable :: ProcessSetValue +( + int Val_New +) +{ + // used by command processor; sets the value and outputs + // a message + + int OldValue = GetValue(); + + SetValue( Val_New ); + + OutputResultOfSetValue( OldValue ); + +} + +void ConsoleVariable :: ProcessSetValue +( + float Val_New +) +{ + // used by command processor; sets the value and outputs + // a message + + int OldValue = GetValue(); + + SetValue( Val_New ); + + OutputResultOfSetValue( OldValue ); +} + +void ConsoleVariable :: OutputResultOfSetValue( int OldVal ) +{ + int NewValue = GetValue(); + + // Output result + { + SCString* pSCString_Temp1 = new SCString + ( + " " + ); + + SCString* pSCString_Temp2 = MakeValueString + ( + OldVal + ); + + SCString* pSCString_Temp3 = new SCString + ( + " -> " + ); + + SCString* pSCString_Temp4 = MakeValueString + ( + NewValue + ); + + SCString* pSCString_Out = new SCString + ( + pSCString_Symbol, + pSCString_Temp1, + pSCString_Temp2, + pSCString_Temp3, + pSCString_Temp4 + ); + + pSCString_Temp4 ->R_Release(); + pSCString_Temp3 ->R_Release(); + pSCString_Temp2 ->R_Release(); + pSCString_Temp1 ->R_Release(); + + pSCString_Out -> SendToScreen(); + + pSCString_Out ->R_Release(); + + } + +} + + +/* Internal function definitions ***********************************/ +ConsoleVariable_Simple_Int :: ConsoleVariable_Simple_Int +( + int& Value_ToUse, + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + int MinVal_New, + int MaxVal_New, + OurBool Cheat +) : theValue( Value_ToUse ), + ConsoleVariable + ( + pProjCh_ToUse, + pProjCh_Description_ToUse, + MinVal_New, + MaxVal_New, + Cheat + ) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pProjCh_ToUse ); + GLOBALASSERT( pProjCh_Description_ToUse ); + } + + /* CODE */ + { + } +} + +int ConsoleVariable_Simple_Int :: GetValue(void) const +{ + return theValue; +} + +void ConsoleVariable_Simple_Int :: SetValue(int Val_New) +{ + // Ensure bounded: + if ( Val_New > MaxVal ) + { + Val_New = MaxVal; + } + + if ( Val_New < MinVal ) + { + Val_New = MinVal; + } + + theValue = Val_New; +} + +void ConsoleVariable_Simple_Int :: SetValue(float Val_New_F ) +{ + int Val_New = int(Val_New_F); + + // Ensure bounded: + if ( Val_New > MaxVal ) + { + Val_New = MaxVal; + } + + if ( Val_New < MinVal ) + { + Val_New = MinVal; + } + + theValue = Val_New; +} + +// private: +SCString* ConsoleVariable_Simple_Int :: MakeRangeString(void) +{ + SCString* pSCString_Temp2_1 = new SCString + ( + " INT:(" + ); + + SCString* pSCString_Temp2_2 = MakeValueString + ( + MinVal + ); + + SCString* pSCString_Temp2_3 = new SCString + ( + "," + ); + + SCString* pSCString_Temp2_4 = MakeValueString + ( + MaxVal + ); + + SCString* pSCString_Temp2_5 = new SCString + ( + ") " + ); + + SCString* pSCString_Return = new SCString + ( + pSCString_Temp2_1, + pSCString_Temp2_2, + pSCString_Temp2_3, + pSCString_Temp2_4, + pSCString_Temp2_5 + ); + + pSCString_Temp2_5 ->R_Release(); + pSCString_Temp2_4 ->R_Release(); + pSCString_Temp2_3 ->R_Release(); + pSCString_Temp2_2 ->R_Release(); + pSCString_Temp2_1 ->R_Release(); + + return pSCString_Return; +} + +SCString* ConsoleVariable_Simple_Int :: MakeValueString(int Val) +{ + return new SCString + ( + Val + ); +} + + +ConsoleVariable_Simple_FixP :: ConsoleVariable_Simple_FixP +( + int& Value_ToUse, + ProjChar* pProjCh_ToUse, + ProjChar* pProjCh_Description_ToUse, + int MinVal_New, + int MaxVal_New, + OurBool Cheat +) : theValue( Value_ToUse ), + ConsoleVariable + ( + pProjCh_ToUse, + pProjCh_Description_ToUse, + MinVal_New, + MaxVal_New, + Cheat + ) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pProjCh_ToUse ); + GLOBALASSERT( pProjCh_Description_ToUse ); + } + + /* CODE */ + { + } +} + +int ConsoleVariable_Simple_FixP :: GetValue(void) const +{ + return theValue; +} + +void ConsoleVariable_Simple_FixP :: SetValue(int Val_New) +{ + Val_New *= ONE_FIXED; + + // Ensure bounded: + if ( Val_New > MaxVal ) + { + Val_New = MaxVal; + } + + if ( Val_New < MinVal ) + { + Val_New = MinVal; + } + + theValue = Val_New; +} + +void ConsoleVariable_Simple_FixP :: SetValue(float Val_New_F ) +{ + int Val_New = int(Val_New_F * ONE_FIXED); + + // Ensure bounded: + if ( Val_New > MaxVal ) + { + Val_New = MaxVal; + } + + if ( Val_New < MinVal ) + { + Val_New = MinVal; + } + + theValue = Val_New; +} + +// private: +SCString* ConsoleVariable_Simple_FixP :: MakeRangeString(void) +{ + SCString* pSCString_Temp2_1 = new SCString + ( + " FRAC:(" + ); + + SCString* pSCString_Temp2_2 = MakeValueString + ( + MinVal + ); + + SCString* pSCString_Temp2_3 = new SCString + ( + "," + ); + + SCString* pSCString_Temp2_4 = MakeValueString + ( + MaxVal + ); + + SCString* pSCString_Temp2_5 = new SCString + ( + ") " + ); + + SCString* pSCString_Return = new SCString + ( + pSCString_Temp2_1, + pSCString_Temp2_2, + pSCString_Temp2_3, + pSCString_Temp2_4, + pSCString_Temp2_5 + ); + + pSCString_Temp2_5 ->R_Release(); + pSCString_Temp2_4 ->R_Release(); + pSCString_Temp2_3 ->R_Release(); + pSCString_Temp2_2 ->R_Release(); + pSCString_Temp2_1 ->R_Release(); + + return pSCString_Return; +} + +SCString* ConsoleVariable_Simple_FixP :: MakeValueString(int Val) +{ + return new SCString + ( + FixP2Float( Val ) + ); +} diff --git a/3dc/avp/win95/gadgets/consvar.hpp b/3dc/avp/win95/gadgets/consvar.hpp new file mode 100644 index 0000000..0b42eec --- /dev/null +++ b/3dc/avp/win95/gadgets/consvar.hpp @@ -0,0 +1,138 @@ +/* + + consvar.hpp + + Console variables : i.e. values that can be adjusted at the console + +*/ + +#ifndef _consvar_hpp +#define _consvar_hpp 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + + #ifndef _conssym_hpp + #include "conssym.hpp" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + + // Abstract base class of console variable + // It's abstract because the Get/SetValue functions are pure virtual. + // There's a "standard" derived class defined within CONSVAR.CPP + // which has a direct link to a global int, and allows direct set/get + // For other variables (which might require additional processing), + // derive another class from the base and implement the Set/Get pairs + + // Use single words only as symbols; the command interpreter looks + // for spaces + + class ConsoleVariable : public ConsoleSymbol + { + public: + // Factory method: + static ConsoleVariable* MakeSimpleConsoleVariable_Int + ( + int& Value_ToUse, + ProjChar* pProjCh_Symbol_ToUse, + ProjChar* pProjCh_Description_ToUse, + int MinVal_New, + int MaxVal_New, + OurBool Cheat = FALSE + ); + static ConsoleVariable* MakeSimpleConsoleVariable_FixP + ( + int& Value_ToUse, + ProjChar* pProjCh_Symbol_ToUse, + ProjChar* pProjCh_Description_ToUse, + int MinVal_New, // fixed point value + int MaxVal_New, // fixed point value + OurBool Cheat = FALSE + ); + + ~ConsoleVariable(); + + virtual int GetValue(void) const = 0; + virtual void SetValue(int Val_New) = 0; + virtual void SetValue(float Val_New) = 0; + + static OurBool Process( ProjChar* pProjCh_In ); + // used for proccesing input text. Could decide that the user + // was requesting the value of a variable, or was setting a new + // value etc; if so, acts accordingly. + // return value = was any processing performed? + + static void ListAllVariables(void); + + static void CreateAll(void); + // hook to create all the console variables + // (to make it easy to add new ones) + + protected: + ConsoleVariable + ( + ProjChar* pProjCh_Symbol_ToUse, + ProjChar* pProjCh_Description_ToUse, + int MinVal_New, + int MaxVal_New, + OurBool Cheat = FALSE + ); + + private: + void Display(void); + // used by the list display and to interrogate an individual variable + + void ProcessSetValue + ( + int Val_New + ); + void ProcessSetValue + ( + float Val_New + ); + // used by command processor; sets the value and outputs + // a message + + void OutputResultOfSetValue( int OldVal ); + + virtual SCString* MakeRangeString(void) = 0; + virtual SCString* MakeValueString(int Val) = 0; + + + // Data: + protected: + int MinVal; + int MaxVal; + + private: + SCString* pSCString_Description; + + static List List_pConsoleVar; + }; // suggested naming: "ConsoleVar" + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/win95/gadgets/gadget.bak b/3dc/avp/win95/gadgets/gadget.bak new file mode 100644 index 0000000..22076bd --- /dev/null +++ b/3dc/avp/win95/gadgets/gadget.bak @@ -0,0 +1,206 @@ +/* + + gadget.h + + Base header file for Dave Malcolm's user interface "gadget" code. + + Note to "C" programmers: look at the bottom of this file + +*/ + +#ifndef _gadget +#define _gadget 1 + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + #define UseGadgets Yes + /* If this is set to No all gadget code collapses to void macros */ + + #define EnableStatusPanels No + +/* Constants ***********************************************************/ + #define HUD_SPACING 20 + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + #if UseGadgets + + #ifndef _projtext + #include "projtext.h" + #endif + + #ifdef __cplusplus + + #ifndef _r2base + #include "r2base.h" + #endif + + class Gadget + { + public: + // Pure virtual render method: + virtual void Render + ( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha + ) = 0; + // Render yourself at the coordinates given, clipped by the clipping rectangle + // Note that the position need not be at all related to the clipping rectangle; + // it's up to the implementation to behave for these cases. + // Both the coordinate and the clipping rectangle are in absolute screen coordinates + // The alpha value to use is "absolute" + + virtual ~Gadget(); + // ensure virtual destructor + + #if debug + char* GetDebugName(void); + void Render_Report + ( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha + ); + // use to textprint useful information about a call to "Render" + #endif + + protected: + // Protected constructor since abstract base class + #if debug + Gadget + ( + char* DebugName_New + ) : DebugName( DebugName_New ) + { + // empty + } + #else + Gadget(){} + #endif + + private: + #if debug + char* DebugName; + #endif + + }; // end of class Gadget + + // Inline methods: + #if debug + inline char* Gadget::GetDebugName(void) + { + return DebugName; + } + #endif + + #if 0 + class GadgetWithSize : public Gadget + { + // Friends + + // Protected data: + protected: + r2size R2Size_Val; + + // Public methods: + public: + r2size GetSize(void) const; + + void SetSize(r2size R2Size); + virtual void SetSize_PostProcessing(void) {} + + // Protected methods: + protected: + // Protected constructor since abstract class + // (It's abstract since Render() remains pure virtual ) + GadgetWithSize + ( + #if debug + char* DebugName_New, + #endif + r2size R2Size_New + ) : Gadget + ( + #if debug + DebugName_New + #endif + ), + R2Size_Val( R2Size_New ) {} + + // Private methods: + private: + + // Private data: + private: + + // Inline methods: + public: + r2size GetSize(void) const + { + return R2Size_Val; + } + void SetSize( r2size R2Size_New ) + { + R2Size_Val = R2Size_New; + SetSize_PostProcessing(); + } + protected: + private: + + }; // end of class GadgetWithSize + #endif + + #endif /* __cplusplus */ + #endif /* UseGadgets */ + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + #if UseGadgets + + extern void GADGET_Init(void); + /* expects to be called at program boot-up time */ + + extern void GADGET_UnInit(void); + /* expects to be called at program shutdown time */ + + extern void GADGET_Render(void); + /* expects to be called within the rendering part of the main loop */ + + extern void GADGET_ScreenModeChange_Setup(void); + /* expects to be called immediately before anything happens to the screen + mode */ + + extern void GADGET_ScreenModeChange_Cleanup(void); + /* expects to be called immediately after anything happens to the screen + mode */ + + extern void GADGET_NewOnScreenMessage( ProjChar* messagePtr ); + + extern void RemoveTheConsolePlease(void); + + #else /* UseGadgets */ + + #define GADGET_Init() ((void) 0) + #define GADGET_UnInit() ((void) 0) + #define GADGET_Render() ((void) 0) + #define GADGET_ScreenModeChange_Setup() ((void) 0) + #define GADGET_ScreenModeChange_Cleanup() ((void) 0) + #define GADGET_NewOnScreenMessage(x) ((void) 0) + + #endif /* UseGadgets */ + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/win95/gadgets/gadget.cpp b/3dc/avp/win95/gadgets/gadget.cpp new file mode 100644 index 0000000..b6d77f7 --- /dev/null +++ b/3dc/avp/win95/gadgets/gadget.cpp @@ -0,0 +1,280 @@ +/******************************************************************* + * + * DESCRIPTION: gadget.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 13/11/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "gadget.h" +#include "rootgadg.hpp" +#include "r2base.h" +#include "hudgadg.hpp" +#include "ahudgadg.hpp" +#include "indexfnt.hpp" +#include "trepgadg.hpp" + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +#if UseGadgets + +// class Gadget +// public: + +/*virtual*/ Gadget :: ~Gadget() +{ + // ensure virtual destructor + + // empty +} + +#if debug +void Gadget :: Render_Report +( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha +) +{ + // use to textprint useful information about a call to "Render" + textprint + ( + "%s::Render at(%i,%i) clip(%i,%i,%i,%i) a=%i\n", + DebugName, + R2Pos . x, + R2Pos . y, + R2Rect_Clip . x0, + R2Rect_Clip . y0, + R2Rect_Clip . x1, + R2Rect_Clip . y1, + FixP_Alpha + ); +} +#endif + +// protected: + +// end of class Gadget + +extern void GADGET_Init(void) +{ + /* expects to be called at program boot-up time */ + + /* PRECONDITION */ + { + GLOBALASSERT( RootGadget :: GetRoot() == NULL ); + } + + /* CODE */ + { + new RootGadget; + } +} + + +extern void GADGET_UnInit(void) +{ + /* expects to be called at program shutdown time */ + + /* PRECONDITION */ + { + GLOBALASSERT( RootGadget :: GetRoot() ); + } + + /* CODE */ + { + delete RootGadget :: GetRoot(); + } +} + + +extern void GADGET_Render(void) +{ + /* expects to be called within the rendering part of the main loop */ + + /* PRECONDITION */ + { + } + + /* CODE */ + { + #if 0 + textprint("GADGET_Render()\n"); + #endif + + // under construction... + GLOBALASSERT( RootGadget :: GetRoot() ); + RootGadget :: GetRoot() -> Render + ( + r2pos :: Origin, // const struct r2pos& R2Pos, + r2rect :: PhysicalScreen(), // const struct r2rect& R2Rect_Clip, + ONE_FIXED // int FixP_Alpha + ); + + #if 0 + // Test all the fonts: + { + SCString* pSCString_Test = new SCString("FONT TEST STRING"); + + for (int i=0;i Render_Unclipped + ( + R2Pos_TempCursor, // struct r2pos& R2Pos_Cursor, + ONE_FIXED, // int FixP_Alpha, + *pSCString_Test// const SCString& SCStr + ); + } + + pSCString_Test -> R_Release(); + } + #endif + } +} + + +extern void GADGET_ScreenModeChange_Setup(void) +{ + /* expects to be called immediately before anything happens to the screen + mode */ + + /* PRECONDITION */ + { + } + + /* CODE */ + { + } +} + + +extern void GADGET_ScreenModeChange_Cleanup(void) +{ + /* expects to be called immediately after anything happens to the screen + mode */ + + + /* PRECONDITION */ + { + GLOBALASSERT( RootGadget :: GetRoot() ); + } + + /* CODE */ + { + RootGadget :: GetRoot() -> RefreshHUD(); + } +} + +extern void GADGET_NewOnScreenMessage( ProjChar* messagePtr ) +{ + /* PRECONDITION */ + { + GLOBALASSERT( messagePtr ); + GLOBALASSERT( RootGadget :: GetRoot() ); + } + + /* CODE */ + { + if ( RootGadget :: GetRoot() -> GetHUD() ) + { + SCString* pSCString_New = new SCString( messagePtr ); + + RootGadget :: GetRoot() -> GetHUD() -> AddTextReport + ( + pSCString_New + ); + + pSCString_New -> R_Release(); + } + } +} + +extern void RemoveTheConsolePlease(void) +{ + AlienHUDGadget *HUD = (AlienHUDGadget*)RootGadget::GetRoot()->GetHUD(); + HUD->pTextReportGadg->Disappear(); +} + + +#endif // UseGadgets + +void SCString :: SendToScreen(void) +{ + // adds this as a new on-screen message + #if UseGadgets + /* PRECONDITION */ + { + GLOBALASSERT( RootGadget :: GetRoot() ); + } + + /* CODE */ + { + if ( RootGadget :: GetRoot() -> GetHUD() ) + { + RootGadget :: GetRoot() -> GetHUD() -> AddTextReport + ( + this + ); + } + } + #else + { + // do nothing + } + #endif // UseGadgets +} + + + + + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/win95/gadgets/gadget.h b/3dc/avp/win95/gadgets/gadget.h new file mode 100644 index 0000000..9ca8506 --- /dev/null +++ b/3dc/avp/win95/gadgets/gadget.h @@ -0,0 +1,206 @@ +/* + + gadget.h + + Base header file for Dave Malcolm's user interface "gadget" code. + + Note to "C" programmers: look at the bottom of this file + +*/ + +#ifndef _gadget +#define _gadget 1 + + +/* Version settings *****************************************************/ + #define UseGadgets Yes + /* If this is set to No all gadget code collapses to void macros */ + + #define EnableStatusPanels No + +/* Constants ***********************************************************/ + #define HUD_SPACING 20 + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + #if UseGadgets + + #ifndef _projtext + #include "projtext.h" + #endif + + #ifdef __cplusplus + + #ifndef _r2base + #include "r2base.h" + #endif + + class Gadget + { + public: + // Pure virtual render method: + virtual void Render + ( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha + ) = 0; + // Render yourself at the coordinates given, clipped by the clipping rectangle + // Note that the position need not be at all related to the clipping rectangle; + // it's up to the implementation to behave for these cases. + // Both the coordinate and the clipping rectangle are in absolute screen coordinates + // The alpha value to use is "absolute" + + virtual ~Gadget(); + // ensure virtual destructor + + #if debug + char* GetDebugName(void); + void Render_Report + ( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha + ); + // use to textprint useful information about a call to "Render" + #endif + + protected: + // Protected constructor since abstract base class + #if debug + Gadget + ( + char* DebugName_New + ) : DebugName( DebugName_New ) + { + // empty + } + #else + Gadget(){} + #endif + + private: + #if debug + char* DebugName; + #endif + + }; // end of class Gadget + + // Inline methods: + #if debug + inline char* Gadget::GetDebugName(void) + { + return DebugName; + } + #endif + + #if 0 + class GadgetWithSize : public Gadget + { + // Friends + + // Protected data: + protected: + r2size R2Size_Val; + + // Public methods: + public: + r2size GetSize(void) const; + + void SetSize(r2size R2Size); + virtual void SetSize_PostProcessing(void) {} + + // Protected methods: + protected: + // Protected constructor since abstract class + // (It's abstract since Render() remains pure virtual ) + GadgetWithSize + ( + #if debug + char* DebugName_New, + #endif + r2size R2Size_New + ) : Gadget + ( + #if debug + DebugName_New + #endif + ), + R2Size_Val( R2Size_New ) {} + + // Private methods: + private: + + // Private data: + private: + + // Inline methods: + public: + r2size GetSize(void) const + { + return R2Size_Val; + } + void SetSize( r2size R2Size_New ) + { + R2Size_Val = R2Size_New; + SetSize_PostProcessing(); + } + protected: + private: + + }; // end of class GadgetWithSize + #endif + + #endif /* __cplusplus */ + #endif /* UseGadgets */ + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ +#ifdef __cplusplus + extern "C" { +#endif + #if UseGadgets + + extern void GADGET_Init(void); + /* expects to be called at program boot-up time */ + + extern void GADGET_UnInit(void); + /* expects to be called at program shutdown time */ + + extern void GADGET_Render(void); + /* expects to be called within the rendering part of the main loop */ + + extern void GADGET_ScreenModeChange_Setup(void); + /* expects to be called immediately before anything happens to the screen + mode */ + + extern void GADGET_ScreenModeChange_Cleanup(void); + /* expects to be called immediately after anything happens to the screen + mode */ + + extern void GADGET_NewOnScreenMessage( ProjChar* messagePtr ); + + extern void RemoveTheConsolePlease(void); + + #else /* UseGadgets */ + + #define GADGET_Init() ((void) 0) + #define GADGET_UnInit() ((void) 0) + #define GADGET_Render() ((void) 0) + #define GADGET_ScreenModeChange_Setup() ((void) 0) + #define GADGET_ScreenModeChange_Cleanup() ((void) 0) + #define GADGET_NewOnScreenMessage(x) ((void) 0) + + #endif /* UseGadgets */ + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/win95/gadgets/hudgadg.cpp b/3dc/avp/win95/gadgets/hudgadg.cpp new file mode 100644 index 0000000..537ef1b --- /dev/null +++ b/3dc/avp/win95/gadgets/hudgadg.cpp @@ -0,0 +1,152 @@ +/******************************************************************* + * + * DESCRIPTION: hudgadg.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 14/11/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "hudgadg.hpp" +//#include "mhudgadg.hpp" +#include "ahudgadg.hpp" +//#include "phudgadg.hpp" +#include "trepgadg.hpp" + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ +#if UseGadgets + // private: + /*static*/ HUDGadget* HUDGadget :: pSingleton; +#endif + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +#if UseGadgets +// HUD Gadget is an abstract base class for 3 types of HUD; one for each species +// It's abstract because the Render() method remains pure virtual +// class HUDGadget : public Gadget +// public: + +// Factory method: +/*static*/ HUDGadget* HUDGadget :: MakeHUD +( + I_PLAYER_TYPE IPlayerType_ToMake +) +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + #if 0 + switch ( IPlayerType_ToMake ) + { + case I_Marine: + return new MarineHUDGadget(); + + case I_Predator: + return new PredatorHUDGadget(); + + case I_Alien: + return new AlienHUDGadget(); + + default: + GLOBALASSERT(0); + return NULL; + } + #else + return new AlienHUDGadget(); + #endif + } +} + + +// Destructor: +/*virtual*/ HUDGadget :: ~HUDGadget() +{ + /* PRECONDITION */ + { + GLOBALASSERT( this == pSingleton ); + } + + /* CODE */ + { + pSingleton = NULL; + } +} + + +// protected: +// Constructor is protected since an abstract class +HUDGadget :: HUDGadget +( + #if debug + char* DebugName + #endif +) : Gadget + ( + #if debug + DebugName + #endif + ) +{ + /* PRECONDITION */ + { + GLOBALASSERT( NULL == pSingleton ); + } + + /* CODE */ + { + #if 0 + pSCString_Current = NULL; + #endif + + pSingleton = this; + } +} +#endif // UseGadgets + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/win95/gadgets/hudgadg.hpp b/3dc/avp/win95/gadgets/hudgadg.hpp new file mode 100644 index 0000000..38e0c52 --- /dev/null +++ b/3dc/avp/win95/gadgets/hudgadg.hpp @@ -0,0 +1,144 @@ +/* + + hudgadg.hpp + +*/ + +#ifndef _hudgadg +#define _hudgadg 1 + + #ifndef _gadget + #include "gadget.h" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + #if UseGadgets + + #ifndef GAMEDEF_INCLUDED + + #ifndef MODULE_INCLUDED + #include "module.h" + #endif + // irritatingly, GAMEDEF.H assumes MODULE.H has already been included... + + #include "gamedef.h" + #endif + + #ifndef _scstring + #ifdef __cplusplus + extern "C++" { + // JH 140298 - C++ header can only be included in C++ source and must have C++ linkage + #include "scstring.hpp" + } + #endif + #endif + + #ifndef _statpane_h + #include "statpane.h" + #endif + + class TextReportGadget; // fully declared in TREPGADG.HPP + + // HUD Gadget is an abstract base class for 3 types of HUD; one for each species + // It's abstract because the Render() method remains pure virtual + class HUDGadget : public Gadget + { + public: + static HUDGadget* GetHUD(void); + + // Factory method: + static HUDGadget* MakeHUD + ( + I_PLAYER_TYPE IPlayerType_ToMake + ); + + virtual void AddTextReport + ( + SCString* pSCString_ToAdd + // ultimately turn into an MCString + ) = 0; + + virtual void ClearTheTextReportQueue(void) = 0; + + + #if EnableStatusPanels + virtual void RequestStatusPanel + ( + enum StatusPanelIndex I_StatusPanel + ) = 0; + virtual void NoRequestedPanel(void) = 0; + #endif + + virtual void CharTyped + ( + char Ch + // note that this _is _ a char + ) = 0; + + virtual void Key_Backspace(void) = 0; + virtual void Key_End(void) = 0; + virtual void Key_Home(void) = 0; + virtual void Key_Left(void) = 0; + virtual void Key_Up(void) = 0; + virtual void Key_Right(void) = 0; + virtual void Key_Down(void) = 0; + virtual void Key_Delete(void) = 0; + virtual void Key_Tab(void) = 0; + + virtual void Jitter(int FixP_Magnitude) = 0; + + + // Destructor: + virtual ~HUDGadget(); + + protected: + // Constructor is protected since an abstract class + HUDGadget + ( + #if debug + char* DebugName + #endif + ); + + private: + static HUDGadget* pSingleton; + + #if 0 + // Temporary text feedback implementation: + protected: + SCString* pSCString_Current; + #endif + + }; + + // Inline methods: + inline /*static*/ HUDGadget* HUDGadget::GetHUD(void) + { + return pSingleton; + } + #endif // UseGadgets + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/win95/gadgets/rootgadg.cpp b/3dc/avp/win95/gadgets/rootgadg.cpp new file mode 100644 index 0000000..c73f231 --- /dev/null +++ b/3dc/avp/win95/gadgets/rootgadg.cpp @@ -0,0 +1,203 @@ +/******************************************************************* + * + * DESCRIPTION: rootgadg.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 14/11/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "rootgadg.hpp" + +#if UseGadgets + #include "hudgadg.hpp" + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + extern signed int HUDTranslucencyLevel; + // ranges from 0 to 255 inclusive ; convert to fixed point... + + + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + + // private: + /*static*/ RootGadget* RootGadget :: pSingleton = NULL; + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +// class RootGadget : public Gadget +// friend extern void GADGET_Init(void); +// friend extern void GADGET_UnInit(void); + // friend functions: these get permission in order to allow + // construction/destruction + +// public: +void RootGadget :: Render +( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha +) +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + #if 0 + textprint + ( + "RootGadget :: Render at (%i,%i) clipped (%i,%i,%i,%i) alpha=%i\n", + R2Pos . x, + R2Pos . y, + R2Rect_Clip . x0, + R2Rect_Clip . y0, + R2Rect_Clip . x1, + R2Rect_Clip . y1, + FixP_Alpha + ); + #endif + + if ( pHUDGadg ) + { + // HUDTranslucencyLevel ranges from 0 to 255 inclusive ; convert to fixed point... + + GLOBALASSERT( HUDTranslucencyLevel >= 0); + GLOBALASSERT( HUDTranslucencyLevel <= 255 ); + + pHUDGadg -> Render + ( + R2Pos, + R2Rect_Clip, + (HUDTranslucencyLevel << 8) // int FixP_Alpha + ); + } + } +} + +void RootGadget :: RefreshHUD(void) +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + // For the moment, destroy any HUD: + if ( pHUDGadg ) + { + delete pHUDGadg; + pHUDGadg = NULL; + } + + GLOBALASSERT( NULL == pHUDGadg ); + + // And then recreate if necessary: + { + extern AVP_GAME_DESC AvP; /* game description */ + + if + ( + AvP.GameMode == I_GM_Playing + ) + { + pHUDGadg = HUDGadget :: MakeHUD + ( + AvP.PlayerType // I_PLAYER_TYPE IPlayerType_ToMake + ); + } + } + } +} + + + +// private: +RootGadget :: RootGadget +( +) : Gadget + ( + #if debug + "RootGadget" + #endif + ) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pSingleton == NULL ); + } + + /* CODE */ + { + pHUDGadg = NULL; + + pSingleton = this; + } +} + +RootGadget :: ~RootGadget() +{ + /* PRECONDITION */ + { + GLOBALASSERT( pSingleton == this ); + } + + /* CODE */ + { + pSingleton = NULL; + + if ( pHUDGadg ) + { + delete pHUDGadg; + } + } +} + + + +/* Internal function definitions ***********************************/ + + + +#endif // UseGadgets diff --git a/3dc/avp/win95/gadgets/rootgadg.hpp b/3dc/avp/win95/gadgets/rootgadg.hpp new file mode 100644 index 0000000..573473e --- /dev/null +++ b/3dc/avp/win95/gadgets/rootgadg.hpp @@ -0,0 +1,86 @@ +/* + + rootgadg.hpp + +*/ + +#ifndef _rootgadg +#define _rootgadg 1 + + #ifndef _gadget + #include "gadget.h" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + + #if UseGadgets + class HUDGadget; // fully declared in HUDGADG.HPP + + class RootGadget : public Gadget + { + friend void GADGET_Init(void); + friend void GADGET_UnInit(void); + // friend functions: these get permission in order to allow + // construction/destruction + + public: + void Render + ( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha + ); + + static RootGadget* GetRoot(void); + + HUDGadget* GetHUD(void); + + void RefreshHUD(void); + + private: + RootGadget(); + ~RootGadget(); + + private: + static RootGadget* pSingleton; + + HUDGadget* pHUDGadg; + // allowed to be NULL if no head-up-display e.g. when not in a game + + }; + + // Inline methods: + inline /*static*/ RootGadget* RootGadget::GetRoot(void) + { + return pSingleton; + } + inline HUDGadget* RootGadget::GetHUD(void) + { + return pHUDGadg; + } + #endif // UseGadgets + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/win95/gadgets/t_ingadg.cpp b/3dc/avp/win95/gadgets/t_ingadg.cpp new file mode 100644 index 0000000..1c98074 --- /dev/null +++ b/3dc/avp/win95/gadgets/t_ingadg.cpp @@ -0,0 +1,521 @@ +/******************************************************************* + * + * DESCRIPTION: t_ingadg.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 23/1/98 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "t_ingadg.hpp" + + #if UseGadgets + #include "indexfnt.hpp" + #include "coordstr.hpp" + #include "inline.h" + #include "trepgadg.hpp" + #endif + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + #define I_Font_TextEntry (DATABASE_MESSAGE_FONT) + #define WIDTH_OF_INSERTION_CARET (2) + #define FIXP_SPEED_OF_FADEIN ((ONE_FIXED * 3) / 4) + + #define WIDTH_OF_TEXT_ENTRY_LINE (TEXT_REPORT_MAX_W) + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +#if UseGadgets +// class AVPTextInputState : public TextInputState +// public: +void AVPTextInputState :: Key_Up(void) +{ + #if SupportHistory + History_SelectPrv(); + #else + // empty for the moment + #endif +} +void AVPTextInputState :: Key_Down(void) +{ + #if SupportHistory + History_SelectNxt(); + #else + // empty for the moment + #endif +} + +void AVPTextInputState :: Key_Tab(void) +{ + #if SupportCompletion + Completion_SelectNxt(); + #endif +} + +// AVP-specific processing for carriage return: +void AVPTextInputState :: ProcessCarriageReturn(void) +{ + SCString* pSCStr = &GetCurrentState(); + + Clear(); + + #if SupportHistory + AddToHistory + ( + *pSCStr + ); + #endif + + pSCStr -> ProcessAnyCheatCodes(); + + pSCStr -> R_Release(); +} + +void AVPTextInputState :: TextEntryError(void) +{ + // called e.g. when no more text can be typed, or no more deleted + // may make a beep noise + + textprint("TextEntryError()\n"); + // replace with a beep? +} + +// class TextEntryGadget : public Gadget +// public: +void TextEntryGadget :: Render +( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha +) +{ + #if 0 + textprint + ( + "TextEntryGadget :: Render at (%i,%i) clipped (%i,%i,%i,%i) alpha=%i\n", + R2Pos . x, + R2Pos . y, + R2Rect_Clip . x0, + R2Rect_Clip . y0, + R2Rect_Clip . x1, + R2Rect_Clip . y1, + FixP_Alpha + ); + #endif + + // If you're being rendered, then you ought to be fading in + p666_FadeIn -> SetTarget_FixP + ( + ONE_FIXED + ); + + IndexedFont* pLetterFont = IndexedFont :: GetFont( I_Font_TextEntry ); + GLOBALASSERT( pLetterFont ); + + // Calculate number of lines required: + int NumberOfLines = 0; + + #if LimitedLineLength + { + NumberOfLines = 1; + + int widthLeft = WIDTH_OF_TEXT_ENTRY_LINE; + + const ProjChar* pProjCh = theState . GetProjChar(); + + //go through the characters in the string , working out how much space is required + while ( *pProjCh ) + { + widthLeft -= pLetterFont->GetWidth(*pProjCh); + + pProjCh++; + + if (pLetterFont->GetMaxWidth()>=widthLeft) + { + // need to go to the next line: + widthLeft = WIDTH_OF_TEXT_ENTRY_LINE; + NumberOfLines++; + } + } + if (NumberOfLines<1) { NumberOfLines = 1; } + if (NumberOfLines>5) { NumberOfLines = 5; } + } + #else + { + int TotalWidthGuess = theState . GetNumChars() * (pLetterFont -> GetMaxWidth()+1); + + if (TotalWidthGuess>0) + { + NumberOfLines = ( TotalWidthGuess / WIDTH_OF_TEXT_ENTRY_LINE )+1; + } + + if (NumberOfLines<1) { NumberOfLines = 1; } + if (NumberOfLines>5) { NumberOfLines = 5; } + } + #endif + + // Work out the area the gadget occupies, clipped with the passed clip area: + r2rect R2Rect_Area + ( + R2Pos, + WIDTH_OF_TEXT_ENTRY_LINE, + ( pLetterFont -> GetHeight() * NumberOfLines ) + ); + + R2Rect_Clip . Clip( R2Rect_Area ); + + // Add alpha-channeled poly: + { + int translucency = + ( + MUL_FIXED + ( + p666_FadeIn -> GetCoord_FixP(), + FixP_Alpha + ) + >> 8 + ); + + if (translucency<0) translucency = 0; + if (translucency>255) translucency = 255; + + R2Rect_Area . AlphaFill + ( + 0xbf, // unsigned char R, + 0xbf, // unsigned char G, + 0, // unsigned char B, + translucency + ); + } + + struct r2pos R2Pos_Char = R2Pos; + int i = 0; + + #if LimitedLineLength + { + int X_EndOfLine = R2Pos.x + WIDTH_OF_TEXT_ENTRY_LINE; + + const ProjChar* pProjCh = theState . GetProjChar(); + + while ( *pProjCh ) + { + if ( i == theState . GetCursorPos() ) + { + // Add cursor to the left of this character + r2rect R2Rect_Cursor + ( + R2Pos_Char, + // r2size: + ( + TextInputState :: bOverwrite() + ? + ( + pLetterFont -> CalcSize( *pProjCh ) + ) + : + r2size + ( + WIDTH_OF_INSERTION_CARET, + pLetterFont -> GetHeight() + ) + ) + ); + + R2Rect_Area . Clip( R2Rect_Cursor ); + + if + ( + R2Rect_Cursor . bValidPhys() + && + R2Rect_Cursor . bHasArea() + ) + { + R2Rect_Cursor . AlphaFill + ( + 255, // unsigned char R, + 255, // unsigned char G, + 255, // unsigned char B, + (FixP_Alpha * 2 / (256*3))// unsigned char translucency + ); + } + } + + pLetterFont -> RenderChar_Clipped + ( + R2Pos_Char, + R2Rect_Area, + FixP_Alpha, + *pProjCh // ProjChar ProjCh + ); + + i++; + pProjCh++; + + if (R2Pos_Char.x+pLetterFont->GetMaxWidth()>=X_EndOfLine) + { + // wrap to next line: + R2Pos_Char.x = R2Pos.x; + R2Pos_Char.y += pLetterFont -> GetHeight(); + } + } + } + #else // LimitedLineLength + { + for + ( + LIF oi(&(List_ProjChar)); + !oi.done(); + oi.next() + ) + { + #if 1 + if ( i == theState . GetCursorPos() ) + { + // Add cursor to the left of this character + r2rect R2Rect_Cursor + ( + R2Pos_Char, + // r2size: + ( + bOverwrite + ? + ( + pLetterFont -> CalcSize( oi() ) + ) + : + r2size + ( + WIDTH_OF_INSERTION_CARET, + pLetterFont -> GetHeight() + ) + ) + ); + + R2Rect_Area . Clip( R2Rect_Cursor ); + + R2Rect_Cursor . AlphaFill + ( + 255, // unsigned char R, + 255, // unsigned char G, + 255, // unsigned char B, + (FixP_Alpha * 2 / (256*3))// unsigned char translucency + ); + } + + pLetterFont -> RenderString_Clipped + ( + R2Pos_Char, + R2Rect_Area, + FixP_Alpha, + oi() // ProjChar ProjCh + ); + + #else + textprintXY + ( + R2Pos_Char . x, + R2Pos_Char . y, + "%c",oi() + ); + + R2Pos_Char . x += 10; + // LOCALISEME(); + #endif + + i++; + } + } + #endif // LimitedLineLength + + if ( i == theState . GetCursorPos() ) + { + // Add cursor after the end of the characters: + r2rect R2Rect_Cursor + ( + R2Pos_Char, + r2size + ( + ( + TextInputState :: bOverwrite() + ? + pLetterFont -> GetMaxWidth() + : + WIDTH_OF_INSERTION_CARET + ), + pLetterFont -> GetHeight() + ) + ); + + R2Rect_Area . Clip( R2Rect_Cursor ); + + if + ( + R2Rect_Cursor . bValidPhys() + && + R2Rect_Cursor . bHasArea() + ) + { + R2Rect_Cursor . AlphaFill + ( + 255, // unsigned char R, + 255, // unsigned char G, + 255, // unsigned char B, + (FixP_Alpha * 2 / (256*3))// unsigned char translucency + ); + } + } + + #if 0 + // For the moment, add the cursor on the line below... + textprintXY + ( + R2Pos . x + (CursorPos * 10), + R2Pos . y + 10, + "^%s", + ( + bOverwrite + ? + "(ovr)" + : + "(ins)" + ) + ); + #endif + + // Diagnostics: + #if 0 + { + #if LimitedLineLength + { + textprint + ( + "CursorPos=%i NumChars=%i\n", + CursorPos, + NumChars + ); + + for (unsigned int i=0;i SetTarget_FixP + ( + 0 + ); +} + + +TextEntryGadget :: TextEntryGadget +( +) : Gadget + ( + #if debug + "TextEntryGadget" + #endif + ), + p666_FadeIn + ( + new AcyclicFixedSpeedHoming + ( + 0, // int Int_InitialCoord, + 0, // int Int_TargetCoord, + FIXP_SPEED_OF_FADEIN // int FixP_Speed + // must be >= zero + ) + ), + theState() +{ +} + + +TextEntryGadget :: ~TextEntryGadget() +{ + delete p666_FadeIn; +} + +#endif // UseGadgets + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/win95/gadgets/t_ingadg.hpp b/3dc/avp/win95/gadgets/t_ingadg.hpp new file mode 100644 index 0000000..258adb0 --- /dev/null +++ b/3dc/avp/win95/gadgets/t_ingadg.hpp @@ -0,0 +1,157 @@ +/* + + t_ingadg.hpp + +*/ + +#ifndef _t_ingadg_hpp +#define _t_ingadg_hpp 1 + + #if ( defined( __WATCOMC__ ) || defined( _MSC_VER ) ) + #pragma once + #endif + + #ifndef _gadget + #include "gadget.h" + #endif + + #if UseGadgets + #ifndef _textin_hpp + #include "textin.hpp" + #endif + + #ifndef _scstring + #include "scstring.hpp" + #endif + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + #if UseGadgets + class AcyclicFixedSpeedHoming; // fully declared in COORDSTR.HPP + + class AVPTextInputState : public TextInputState + { + public: + AVPTextInputState() : + TextInputState + ( + Yes, // OurBool bForceUpperCase, + "" // const char* pProjCh_Init + ) + { + } + + void Key_Up(void); + void Key_Down(void); + void Key_Tab(void); + + // Virtual function implementations: + public: + void ProcessCarriageReturn(void); + protected: + void TextEntryError(void); + }; + + + class TextEntryGadget : public Gadget + { + private: + AcyclicFixedSpeedHoming* p666_FadeIn; + // Add an alpha channeled-box; with a fade-up + // The daemon has a fixed point "relative" alpha value + + AVPTextInputState theState; + + public: + void Render + ( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha + ); + void DontRender(void); + // inform it that it's not being rendered (so it can fade out) + + TextEntryGadget(); + + ~TextEntryGadget(); + + SCString& GetCurrentState(void); + // returns a ref to a copy of the "string under construction" in its current state + + void CharTyped + ( + char Ch + // note that this _is _ a char + ) + { + theState . CharTyped( Ch ); + } + void Key_Backspace(void) + { + theState . Key_Backspace(); + } + void Key_End(void) + { + theState . Key_End(); + } + void Key_Home(void) + { + theState . Key_Home(); + } + void Key_Left(void) + { + theState . Key_Left(); + } + void Key_Up(void) + { + theState . Key_Up(); + } + void Key_Right(void) + { + theState . Key_Right(); + } + void Key_Down(void) + { + theState . Key_Down(); + } + void Key_Delete(void) + { + theState . Key_Delete(); + } + void Key_Tab(void) + { + theState . Key_Tab(); + } + + void SetString(SCString& SCString_ToUse) + { + theState . SetString(SCString_ToUse); + } + }; + #endif // UseGadgets + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/win95/gadgets/teletype.cpp b/3dc/avp/win95/gadgets/teletype.cpp new file mode 100644 index 0000000..e7d4a7c --- /dev/null +++ b/3dc/avp/win95/gadgets/teletype.cpp @@ -0,0 +1,457 @@ +/******************************************************************* + * + * DESCRIPTION: teletype.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 17/11/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "teletype.hpp" +#include "daemon.h" +#include "inline.h" +#include "trepgadg.hpp" + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + #define SupportTeletypeSound Yes + + #if UseGadgets + #include "indexfnt.hpp" + + #if SupportTeletypeSound + #include "psnd.h" + #include "psndproj.h" + #endif + #endif + +/* Constants *******************************************************/ + #define FIXP_PIXELS_PER_SECOND (ONE_FIXED * 768 * 16) + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ +#if UseGadgets +class TeletypeDaemon : public Daemon +{ +public: + TeletypeDaemon + ( + TeletypeGadget* pTeletypeGadg + ); + ~TeletypeDaemon(); + + ACTIVITY_RETURN_TYPE Activity(ACTIVITY_INPUT); + + OurBool HasFinishedPrinting(void); + // so it can trigger next line to print... + + int CursorXOffset(void); + +private: + TeletypeGadget* pTeletypeGadg_Val; + OurBool fFinished_Val; + int FixP_TotalPixels; + // total pixels within the string to be drawn + + int FixP_PixelsCovered; + // pixels covered so far; also equals the x-offset of the cursor. + + #if SupportTeletypeSound + int SoundHandle; + #endif + +}; +// Inline functions: + inline OurBool TeletypeDaemon::HasFinishedPrinting(void) + { + // so it can trigger next line to print... + return fFinished_Val; + } + inline int TeletypeDaemon::CursorXOffset(void) + { + return OUR_FIXED_TO_INT( FixP_PixelsCovered ); + } + +namespace TeletypeCursor +{ + void Render + ( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha + ); +}; + +#endif // UseGadgets + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +#if UseGadgets +// class TeletypeGadget : public Gadget +// public: +void TeletypeGadget :: Render +( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha +) +{ + #if 0 + Render_Report + ( + R2Pos, + R2Rect_Clip, + FixP_Alpha + ); + #endif + #if 0 + textprint + ( + "Teletype:\"%s\"\n", + pSCString_Val -> pProjCh() + ); + #endif + + GLOBALASSERT( p666 ); + int Int_CursorXOffset = p666 -> CursorXOffset(); + + IndexedFont* pLetterFont = IndexedFont :: GetFont( I_Font_TeletypeLettering ); + GLOBALASSERT( pLetterFont ); + + r2pos R2Pos_Temp_Cursor = R2Pos; + + r2rect R2Rect_TeletypeClip = R2Rect_Clip; + + if + ( + R2Rect_TeletypeClip . Width() > Int_CursorXOffset + ) + { + R2Rect_TeletypeClip . SetWidth( Int_CursorXOffset ); + } + + pLetterFont -> RenderString_Clipped + ( + R2Pos_Temp_Cursor, + R2Rect_TeletypeClip, + FixP_Alpha, + *pSCString_Val + ); + + if + ( + !p666 -> HasFinishedPrinting() + ) + { + // then render cursor: + struct r2pos R2Pos_Cursor = R2Pos; + R2Pos_Cursor . x += Int_CursorXOffset; + + TeletypeCursor :: Render + ( + R2Pos_Cursor, + R2Rect_Clip, + FixP_Alpha + ); + } +} + +TeletypeGadget :: TeletypeGadget +( + TextReportGadget* pTextReportGadg, + // parent + SCString* pSCString +) : Gadget + ( + #if debug + "TeletypeGadget" + #endif + ) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pTextReportGadg ); + GLOBALASSERT( pSCString ); + } + + /* CODE */ + { + pTextReportGadg_Val = pTextReportGadg; + pSCString_Val = pSCString; + pSCString_Val -> R_AddRef(); + + p666 = new TeletypeDaemon + ( + this + ); + GLOBALASSERT( p666 ); + } +} + +TeletypeGadget :: ~TeletypeGadget() +{ + pSCString_Val -> R_Release(); + + GLOBALASSERT( p666 ); + + delete p666; +} + +OurBool TeletypeGadget :: HasFinishedPrinting(void) +{ + // so that the next line knows when to begin + GLOBALASSERT( p666 ); + return p666 -> HasFinishedPrinting(); +} + +void TeletypeGadget :: InformParentOfTeletypeCompletion(void) +{ + pTextReportGadg_Val -> TeletypeCompletionHook(); +} + +void TeletypeGadget :: DirectRenderCursor +( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha +) +{ + // called by parent so that it can render its cursor even if + // it's finished printing - so that the last message can have + // a flashing cursor + + GLOBALASSERT( HasFinishedPrinting() ); + + GLOBALASSERT( p666 ); + + int Int_CursorXOffset = p666 -> CursorXOffset(); + + struct r2pos R2Pos_Cursor = R2Pos; + R2Pos_Cursor . x += Int_CursorXOffset; + + TeletypeCursor :: Render + ( + R2Pos_Cursor, + R2Rect_Clip, + FixP_Alpha + ); +} + + +// private: + +#endif // UseGadgets + +/* Internal function definitions ***********************************/ +#if UseGadgets +// class TeletypeDaemon : public CoordinateWithStrategy +// public: +TeletypeDaemon :: TeletypeDaemon +( + TeletypeGadget* pTeletypeGadg +) : Daemon + ( + Yes // OurBool fActive + ) +{ + GLOBALASSERT( pTeletypeGadg ); + + pTeletypeGadg_Val = pTeletypeGadg; + + fFinished_Val = No; + + FixP_TotalPixels = + #if 1 + OUR_INT_TO_FIXED + ( + pTeletypeGadg -> GetStringWithoutReference() -> CalcSize + ( + I_Font_TeletypeLettering + ) . w + ); + #else + OUR_INT_TO_FIXED + ( + 10 + * + pTeletypeGadg -> GetStringWithoutReference() -> GetNumChars() + + ); + #endif + + FixP_PixelsCovered = 0; + + #if SupportTeletypeSound + // Try to start looping teletype sound: + Sound_Play + ( + SID_TELETEXT, + "el", + &SoundHandle + ); + // SOUND_NOACTIVEINDEX used as error value + #endif //SupportTeletypeSound +} + +TeletypeDaemon :: ~TeletypeDaemon() +{ + #if SupportTeletypeSound + if ( SoundHandle != SOUND_NOACTIVEINDEX ) + { + Sound_Stop + ( + SoundHandle + ); + + SoundHandle = SOUND_NOACTIVEINDEX; + } + #endif // SupportTeletypeSound +} + +ACTIVITY_RETURN_TYPE TeletypeDaemon :: Activity(ACTIVITY_INPUT) +{ + #if 0 + textprint("TeletypeDaemon :: Activity(%i)\n",FixP_Time); + #endif + + int FixP_PixelsThisFrame = MUL_FIXED(FIXP_PIXELS_PER_SECOND,FixP_Time); + + #if 0 + textprint + ( + "FixP_PixelsToPrint = %i\n",FixP_PixelsThisFrame + ); + + textprint + ( + "FixP_TotalPixels = %i\n",FixP_TotalPixels + ); + #endif + + FixP_PixelsCovered += FixP_PixelsThisFrame; + + + + if + ( + FixP_PixelsCovered >= FixP_TotalPixels + ) + { + // Teletype has finished: + FixP_PixelsCovered = FixP_TotalPixels; + + fFinished_Val = Yes; + + Stop(); + + #if SupportTeletypeSound + if ( SoundHandle != SOUND_NOACTIVEINDEX ) + { + Sound_Stop + ( + SoundHandle + ); + SoundHandle = SOUND_NOACTIVEINDEX; + } + #endif // SupportTeletypeSound + + // Tell text report line that it can trigger next string in the queue + // (if there is one): + pTeletypeGadg_Val -> InformParentOfTeletypeCompletion(); + + } + + ACTIVITY_RVAL_CHANGE +} +// private: + + +// namespace TeletypeCursor +void TeletypeCursor :: Render +( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha +) +{ + #if 1 + #define TELETYPE_CURSOR_WIDTH (10) + IndexedFont* pLetterFont = IndexedFont :: GetFont( I_Font_TeletypeLettering ); + GLOBALASSERT( pLetterFont ); + + r2rect R2Rect_Area = r2rect + ( + R2Pos, + TELETYPE_CURSOR_WIDTH, + pLetterFont -> GetHeight() + ); + + R2Rect_Clip . Clip + ( + R2Rect_Area + ); + + if + ( + R2Rect_Area . bHasArea() + ) + { + #if 0 + textprint + ( + "TeletypeCursor R2Rect_Area = (%i,%i,%i,%i)\n", + R2Rect_Area . x0, + R2Rect_Area . y0, + R2Rect_Area . x1, + R2Rect_Area . y1 + ); + #endif + + R2Rect_Area . AlphaFill + ( + 255, // unsigned char R, + 255, // unsigned char G, + 255, // unsigned char B, + (FixP_Alpha/256) // unsigned char translucency + ); + } + #endif +} + +#endif // UseGadgets diff --git a/3dc/avp/win95/gadgets/teletype.hpp b/3dc/avp/win95/gadgets/teletype.hpp new file mode 100644 index 0000000..12edc5f --- /dev/null +++ b/3dc/avp/win95/gadgets/teletype.hpp @@ -0,0 +1,108 @@ +/* + + teletype.hpp + + Created 17/11/97 by David Malcolm + +*/ + +#ifndef _teletype +#define _teletype 1 + + #ifndef _gadget + #include "gadget.h" + #endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + #define I_Font_TeletypeLettering (DATABASE_MESSAGE_FONT) + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + #if UseGadgets + #ifndef _ourbool + #include "ourbool.h" + #endif + + #ifndef _scstring + #include "scstring.hpp" + #endif + +// moved wrapper here since scstring.hpp is a C++ header and templates can't have C linkage +#ifdef __cplusplus + extern "C" { +#endif + + class TeletypeDaemon; // fully declared in TELETYPE.CPP + class TextReportGadget; // fully declared in TREPGADG.HPP + + class TeletypeGadget : public Gadget + { + public: + void Render + ( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha + ); + TeletypeGadget + ( + TextReportGadget* pTextReportGadg, + // parent + SCString* pSCString + ); + ~TeletypeGadget(); + + OurBool HasFinishedPrinting(void); + // so that the next line knows when to begin + + SCString* GetStringWithoutReference(void); + // Doesn't bother adding to reference count: + + void InformParentOfTeletypeCompletion(void); + + void DirectRenderCursor + ( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha + ); + // called by parent so that it can render its cursor even if + // it's finished printing - so that the last message can have + // a flashing cursor + + private: + TextReportGadget* pTextReportGadg_Val; + // so that when the daemon finishes it can inform the parent; the + // parent can then start displaying any further lines in the queue... + + SCString* pSCString_Val; + + TeletypeDaemon* p666; + + }; + + inline SCString* TeletypeGadget::GetStringWithoutReference(void) + { + // Doesn't bother adding to reference count: + return pSCString_Val; + } + + #endif // UseGadgets + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/win95/gadgets/textexp.cpp b/3dc/avp/win95/gadgets/textexp.cpp new file mode 100644 index 0000000..691b0bf --- /dev/null +++ b/3dc/avp/win95/gadgets/textexp.cpp @@ -0,0 +1,461 @@ +/******************************************************************* + * + * DESCRIPTION: textexp.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 18/12/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "textexp.hpp" + + #include "strutil.h" + #include "textin.hpp" + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + /*static*/ List TextExpansion :: List_pTextExp; + /*static*/ int TextExpansion :: bVerbose = No; + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +// class TextExpansion +// public: +TextExpansion :: ~TextExpansion() +{ + pSCString_Short_Val -> R_Release(); + pSCString_Expansion_Val -> R_Release(); + + pSCString_Description_Val -> R_Release(); + + List_pTextExp . delete_entry( this ); +} + +void TextExpansion :: Display(void) +{ + // sends info on this expansion to the screen + pSCString_Description_Val -> SendToScreen(); +} + +/*static*/ void TextExpansion :: AddExpansion +( + ProjChar* pProjCh_ToParse +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pProjCh_ToParse ); + } + + /* CODE */ + { + List List_pSCString = SCString :: Parse + ( + pProjCh_ToParse + ); + + if ( List_pSCString . size () == 2) + { + TextExpansion* pTextExp_New = new TextExpansion + ( + List_pSCString[0], // pSCString_Short + List_pSCString[1] // pSCString_Expansion + ); + + { + SCString* pSCString_Temp = new SCString("EXPANSION DEFINED: "); + // LOCALISEME(); + + SCString* pSCString_Feedback = new SCString + ( + pSCString_Temp, + pTextExp_New -> pSCString_Description_Val + ); + + pSCString_Temp -> R_Release(); + + pSCString_Feedback -> SendToScreen(); + pSCString_Feedback -> R_Release(); + } + } + else + { + SCString* pSCString_Feedback = new SCString("EXPECTING TWO ARGUMENTS"); + // LOCALISEME(); + pSCString_Feedback -> SendToScreen(); + pSCString_Feedback -> R_Release(); + } + + for + ( + LIF oi(&List_pSCString); + !oi.done(); + oi.next() + ) + { + oi() -> R_Release(); + } + } +} + +/*static*/ void TextExpansion :: TryToRemoveExpansion +( + ProjChar* pProjCh_ToParse +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pProjCh_ToParse ); + } + + /* CODE */ + { + List List_pSCString = SCString :: Parse + ( + pProjCh_ToParse + ); + + for + ( + LIF oi(&List_pSCString); + !oi.done(); + oi.next() + ) + { + TryToRemoveExpansion + ( + oi() + ); + oi() -> R_Release(); + } + } +} + +/*static*/ void TextExpansion :: TestForExpansions +( + TextInputState* pTextInputState_In +) +{ + // Called by the typing code whenever a word is completed + // This function is a friend to the class TextEntryGadget + + /* PRECONDITION */ + { + GLOBALASSERT( pTextInputState_In ); + } + + /* CODE */ + { + #if LimitedLineLength + { + // Find the word that's just been typed: + int StartOfWordPos = pTextInputState_In -> CursorPos; + int EndOfWordPos = pTextInputState_In -> CursorPos; + + do + { + if ( StartOfWordPos > 0) + { + StartOfWordPos--; + } + else + { + // Reached beginning of line: + break; + } + + if ( pTextInputState_In -> ProjCh[ StartOfWordPos ] == ' ' ) + { + // Reached start of word: + StartOfWordPos++; + break; + } + + } while ( 1 ); + + GLOBALASSERT( StartOfWordPos <= EndOfWordPos ); + + if ( StartOfWordPos == EndOfWordPos ) + { + // Empty string + return; + } + + // See if it matches an expansion; if so, replace as much as you can: + // (watch out for the string getting too long) + + SCString* pSCString_Compare = new SCString + ( + &( pTextInputState_In -> ProjCh[ StartOfWordPos ]), + ( EndOfWordPos - StartOfWordPos ) + ); + + TextExpansion* pTextExp_Found = NULL; + + for + ( + LIF oi(&List_pTextExp); + ( + !( oi.done() || pTextExp_Found ) + ); + oi.next() + ) + { + if + ( + STRUTIL_SC_Strequal + ( + oi() -> pSCString_Short_Val -> pProjCh(), + pSCString_Compare -> pProjCh() + ) + ) + { + pTextExp_Found = oi(); + } + } + + pSCString_Compare -> R_Release(); + + if ( !pTextExp_Found ) + { + // No matches found: + return; + } + + // Got a match; now try to actually replace the short form + // with the long form: + { + if ( bVerbose ) + { + SCString* pSCString_Temp = new SCString + ( + "EXPANDING: " + ); + // LOCALISEME(); + + SCString* pSCString_Feedback = new SCString + ( + pSCString_Temp, + pTextExp_Found -> pSCString_Expansion_Val + ); + + pSCString_Temp -> R_Release(); + + pSCString_Feedback -> SendToScreen(); + pSCString_Feedback -> R_Release(); + } + // for now + + // Delete the shorthand version: + { + int NumToDelete = EndOfWordPos - StartOfWordPos; + + GLOBALASSERT( NumToDelete > 0 ); + + while ( NumToDelete-- ) + { + pTextInputState_In -> DeleteAt + ( + StartOfWordPos + ); + } + } + + // Try to insert the longer version: + { + pTextInputState_In -> TryToInsertAt + ( + pTextExp_Found -> pSCString_Expansion_Val, + StartOfWordPos + ); + } + } + + } + #else + { + #error Not yet implemented + } + #endif + } +} + +/*static*/ void TextExpansion :: ListAll(void) +{ + for + ( + LIF oi(&List_pTextExp); + !oi.done(); + oi.next() + ) + { + oi() -> Display(); + } + +} + +// private: +TextExpansion :: TextExpansion +( + SCString* pSCString_Short, + SCString* pSCString_Expansion +) : pSCString_Short_Val( pSCString_Short ), + pSCString_Expansion_Val( pSCString_Expansion ) +{ + pSCString_Short_Val -> R_AddRef(); + pSCString_Expansion_Val -> R_AddRef(); + + // Build description string: + { + SCString* pSCString_Temp1 = new SCString + ( + "\"" + ); + + SCString* pSCString_Temp2 = new SCString + ( + "\" -> \"" + ); + + pSCString_Description_Val = new SCString + ( + pSCString_Temp1, + pSCString_Short_Val, + pSCString_Temp2, + pSCString_Expansion_Val, + pSCString_Temp1 + ); + + pSCString_Temp2 -> R_Release(); + pSCString_Temp1 -> R_Release(); + } + + + List_pTextExp . add_entry( this ); +} + +/*static*/ void TextExpansion :: TryToRemoveExpansion +( + SCString* pSCString_Word +) +{ + // assumed the word is already parsed/doesn't contain whitespace + + /* PRECONDITION */ + { + GLOBALASSERT( pSCString_Word ); + } + + /* CODE */ + { + TextExpansion* pTextExp_ToKill = NULL; + + // Find the one to be removed; removed later to avoid confusing the + // list iteration code + for + ( + LIF oi(&List_pTextExp); + ( + !( oi.done() || pTextExp_ToKill ) + ); + oi.next() + ) + { + if + ( + STRUTIL_SC_Strequal + ( + oi() -> pSCString_Short_Val -> pProjCh(), + pSCString_Word -> pProjCh() + ) + ) + { + pTextExp_ToKill = oi(); + continue; + } + if + ( + STRUTIL_SC_Strequal + ( + oi() -> pSCString_Expansion_Val -> pProjCh(), + pSCString_Word -> pProjCh() + ) + ) + { + pTextExp_ToKill = oi(); + continue; + } + } + + if ( pTextExp_ToKill ) + { + { + SCString* pSCString_Temp = new SCString("EXPANSION REMOVED: "); + // LOCALISEME(); + + SCString* pSCString_Feedback = new SCString + ( + pSCString_Temp, + pTextExp_ToKill -> pSCString_Description_Val + ); + + pSCString_Temp -> R_Release(); + + pSCString_Feedback -> SendToScreen(); + pSCString_Feedback -> R_Release(); + + } + + delete pTextExp_ToKill; + } + else + { + // unrecognised + } + } +} + + + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/win95/gadgets/textexp.hpp b/3dc/avp/win95/gadgets/textexp.hpp new file mode 100644 index 0000000..fc08ccc --- /dev/null +++ b/3dc/avp/win95/gadgets/textexp.hpp @@ -0,0 +1,103 @@ +/* + + textexp.hpp + + Text Expansions for typing + +*/ + +#ifndef _textexp +#define _textexp 1 + + #ifndef _scstring + #include "scstring.hpp" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + // When typing, whenever space is pressed, the program searches + // the last word typed to see if it matches one of the expansions + // If it does, then the word is replaced by the expanded version + // E.g. "SG" could be defined to expand to "SENTRYGUN" + + class TextInputState; // fully declared in TEXTIN.HPP + + class TextExpansion + { + public: + ~TextExpansion(); + + void Display(void); + // sends info on this expansion to the screen + + static void AddExpansion + ( + ProjChar* pProjCh_ToParse + ); + static void TryToRemoveExpansion + ( + ProjChar* pProjCh_ToParse + ); + + static void TestForExpansions + ( + TextInputState* pTextInputState_In + ); + // Called by the typing code whenever a word is completed + // This function is a friend to the class TextInputState + + static void ListAll(void); + + static int bVerbose; + // public global so it can be accessed via a console variable + + private: + TextExpansion + ( + SCString* pSCString_Short, + SCString* pSCString_Expansion + ); + + static void TryToRemoveExpansion + ( + SCString* pSCString_Word + ); + // assumed the word is already parsed/doesn't contain whitespace + + SCString* pSCString_Short_Val; + SCString* pSCString_Expansion_Val; + + SCString* pSCString_Description_Val; + // a string of the form: "" -> "" + + static List List_pTextExp; + + }; // suggested naming: TextExp + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + + + +#endif diff --git a/3dc/avp/win95/gadgets/textin.cpp b/3dc/avp/win95/gadgets/textin.cpp new file mode 100644 index 0000000..a5ba230 --- /dev/null +++ b/3dc/avp/win95/gadgets/textin.cpp @@ -0,0 +1,1354 @@ +/******************************************************************* + * + * DESCRIPTION: textin.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 21/11/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "textin.hpp" + + #if SupportCompletion + #include "conssym.hpp" + #endif + + #if LimitedLineLength + #include "strutil.h" + #endif + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + /*static*/ OurBool TextInputState :: bOverwrite_Val = No; + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +TextInputState :: ~TextInputState() +{ + #if SupportHistory + while ( List_pSCString_History. size() > 0) + { + List_pSCString_History . first_entry() -> R_Release(); + + List_pSCString_History . delete_first_entry(); + } + #endif +} + +SCString& TextInputState :: GetCurrentState(void) +{ + // returns a ref to a copy of the "string under construction" in its current state + + #if LimitedLineLength + return + ( + *( + new SCString( &ProjCh[0] ) + ) + ); + #else + return + ( + *( + new SCString + ( + List_ProjChar + ) + ) + ); + #endif +} + +void TextInputState :: CharTyped +( + char Ch + // note that this _is _ a char +) +{ + // Need to spot special characters... + // Convert to ProjChars??? + + // LOCALISEME(); + + if ( Ch == '\r' ) + { + ProcessCarriageReturn(); + // Special processing for carriage return: + return; + } + + // Reject certain characters using : + #if 0 + if + ( + ( !isgraph(Ch) ) + && + ( Ch != ' ' ) + ) + { + return; + } + + // Should only be printable characters, with only SPACE accepted + // for marking space (i.e. no tabs, carriage returns etc.) + + // Potentially convert to upper case: + if ( bForceUpperCase_Val ) + { + Ch = toupper(Ch); + } + #endif + if (Ch<32) return; + // LOCALISEME(); + // we assume ProjChar == char at about this point... + + // It also ought not to be a null character: + GLOBALASSERT( Ch ); + + if ( Ch == ' ' ) + { + // When a space is typed, check to see if there's an expansion string + // (and continue processing): + TextExpansion :: TestForExpansions + ( + this + ); + } + + + // add to list at cursor point... + #if LimitedLineLength + { + GLOBALASSERT( CursorPos >= 0 ); + GLOBALASSERT( CursorPos <= NumChars ); + + GLOBALASSERT( 0 == ProjCh[ NumChars ] ); + GLOBALASSERT( NumChars <= MAX_LENGTH_INPUT ); + + if ( bOverwrite() ) + { + if + ( + bOvertypeAt + ( + Ch, // ProjChar ProjCh_ToInsert, + CursorPos // int Pos + ) + ) + { + CursorPos++; + } + else + { + // can't overtype; the line is full + // some kind of error beep? + TextEntryError(); + } + } + else + { + if + ( + bInsertAt + ( + Ch, // ProjChar ProjCh_ToInsert, + CursorPos // int Pos + ) + ) + { + // cursor pos is updated internally by the fn call + } + else + { + // can't insert; the line is full + // some kind of error beep? + TextEntryError(); + } + } + #if 0 + if ( CursorPos == NumChars ) + { + GLOBALASSERT( 0 == ProjCh[ CursorPos ] ); + + // insert character at the end if you can: + if ( NumChars < MAX_LENGTH_INPUT ) + { + NumChars++; + ProjCh[ CursorPos++ ] = Ch; + ProjCh[ CursorPos ] = 0; + } + else + { + // can't insert; the line is full + // some kind of error beep? + TextEntryError(); + } + } + else + { + GLOBALASSERT( 0 != ProjCh[ CursorPos ] ); + + if ( bOverwrite ) + { + // overwrite character at this point in the list + // and move cursor to the right + ProjCh[ CursorPos++ ] = Ch; + } + else + { + // Try to insert the character within the string; is there space? + if ( NumChars < MAX_LENGTH_INPUT ) + { + // Advance all to the right of the cursor, starting with the final + // character in the string: + + for + ( + int i=NumChars; + i>=CursorPos; + i-- + ) + { + ProjCh[ i + 1 ] = ProjCh[ i ]; + } + + ProjCh[ CursorPos++ ] = Ch; + NumChars++; + } + else + { + // can't insert; the line is full + // some kind of error beep? + TextEntryError(); + } + } + } + #endif + } + #else // LimitedLineLength + { + GLOBALASSERT( CursorPos <= List_ProjChar . size() ); + + if ( CursorPos == List_ProjChar . size() ) + { + // insert character at the end + List_ProjChar . add_entry_end( Ch ); + + CursorPos++; + } + else + { + GLOBALASSERT( CursorPos < List_ProjChar . size() ); + + if ( bOverwrite ) + { + // overwrite character at this point in the list + // and move cursor to the right + } + else + { + #if 0 + // insert character inside the list + // and move cursor to the right + List_ProjChar[ CursorPos ] . + + add_entry_end( Ch ); + #endif + } + } + } + #endif // LimitedLineLength +} + +void TextInputState :: Key_Backspace(void) +{ + if ( CursorPos > 0) + { + -- CursorPos; + + Key_Delete(); + } + else + { + TextEntryError(); + } +} +void TextInputState :: Key_End(void) +{ + // Put cursor to far right of input text: + #if LimitedLineLength + if (NumChars > 0) + { + CursorPos = NumChars; + + } + else + { + GLOBALASSERT( CursorPos == 0); + } + #else + CursorPos = List_ProjChar . size(); + #endif +} +void TextInputState :: Key_Home(void) +{ + // Put cursor to far left of input text: + CursorPos = 0; +} +void TextInputState :: Key_Left(void) +{ + // Move cursor to left, if possible: + if ( CursorPos > 0) + { + -- CursorPos; + } +} +void TextInputState :: Key_Right(void) +{ + // Move cursor to right, if possible: + #if LimitedLineLength + if ( CursorPos < NumChars ) + { + ++ CursorPos; + + } + #else + if ( CursorPos < List_ProjChar . size() ) + { + ++ CursorPos; + } + #endif +} +void TextInputState :: Key_Delete(void) +{ + #if LimitedLineLength + { + if + ( + ( NumChars > 0 ) + && + ( CursorPos < NumChars ) + ) + { + DeleteAt( CursorPos ); + } + else + { + // No characters to delete: + TextEntryError(); + } + } + #else + { + // empty for the moment + } + #endif +} + +/*static*/ void TextInputState :: ToggleTypingMode(void) +{ + // toggles overwrite/insert mode + bOverwrite_Val = !bOverwrite_Val; + + // UNIMPLEMENTED: Notification of this as a "cursor change" +} + +// Protected methods: +TextInputState :: TextInputState +( + OurBool bForceUpperCase, + char* pProjCh_Init +) : + #if LimitedLineLength + NumChars(0), + #else + List_ProjChar(), + #endif + #if SupportHistory + List_pSCString_History(), + pSCString_CurrentHistory(NULL), + #endif + #if SupportAutomation + ManualPos(0), + #endif + #if SupportCompletion + pConsoleSym_CurrentCompletion(NULL), + #endif + CursorPos(0), + bForceUpperCase_Val( bForceUpperCase ) +{ + GLOBALASSERT( pProjCh_Init ); + + #if LimitedLineLength + { + STRUTIL_SC_SafeCopy + ( + &ProjCh[0], + MAX_SIZE_INPUT, // unsigned int MaxSize, + + pProjCh_Init + ); + + // Set number of characters from the internal value rather than + // from the input in case of truncation: + NumChars = STRUTIL_SC_Strlen(&ProjCh[0]); + GLOBALASSERT( NumChars < MAX_LENGTH_INPUT ); + } + #else + #error Unimplemented + #endif +} + +void TextInputState :: TryToInsertAt +( + SCString* pSCString_ToInsert, + int Pos +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pSCString_ToInsert ); + + GLOBALASSERT( Pos >= 0 ); + + #if LimitedLineLength + GLOBALASSERT( Pos <= MAX_LENGTH_INPUT ); + #endif + } + + /* CODE */ + { + #if LimitedLineLength + { + ProjChar* pProjCh_I = pSCString_ToInsert -> pProjCh(); + + while + ( + ( *pProjCh_I ) + && + ( Pos < MAX_LENGTH_INPUT ) + ) + { + bInsertAt + ( + *(pProjCh_I++), + Pos++ + ); + } + } + #else + { + #error Not implemented + } + #endif + } +} + +int TextInputState :: bOvertypeAt +( + ProjChar ProjCh_In, + int Pos_Where +) +{ + // return value: was overtype succesful? + + /* PRECONDITION */ + { + // Function parameter validity: + GLOBALASSERT( ProjCh_In ); + // mustn't be a null terminator + + GLOBALASSERT( Pos_Where >= 0 ); + + #if LimitedLineLength + GLOBALASSERT( Pos_Where <= MAX_LENGTH_INPUT ); + #endif + + // The data-representation invariant: + #if LimitedLineLength + GLOBALASSERT( CursorPos >= 0 ); + GLOBALASSERT( CursorPos <= NumChars ); + + GLOBALASSERT( 0 == ProjCh[ NumChars ] ); + GLOBALASSERT( NumChars <= MAX_LENGTH_INPUT ); + #endif + } + + /* CODE */ + { + #if LimitedLineLength + { + if ( Pos_Where == NumChars ) + { + GLOBALASSERT( 0 == ProjCh[ Pos_Where ] ); + + // insert character at the end if you can: + if ( NumChars < MAX_LENGTH_INPUT ) + { + NumChars++; + ProjCh[ Pos_Where ] = ProjCh_In; + ProjCh[ Pos_Where+1 ] = 0; + + #if SupportAutomation + FullyManual(); + #endif + + return Yes; + } + else + { + // can't; the line is full + return No; + } + } + else + { + GLOBALASSERT( 0 != ProjCh[ Pos_Where ] ); + + // overwrite character at this point in the list + ProjCh[ Pos_Where ] = ProjCh_In; + + #if SupportAutomation + FullyManual(); + #endif + + return Yes; + } + } + #else + { + #error Not implemented + } + #endif + } +} + + +int TextInputState :: bInsertAt +( + ProjChar ProjCh_In, + int Pos_Where +) +{ + // return value: was insertion succesful? + + /* PRECONDITION */ + { + // Function parameter validity: + GLOBALASSERT( ProjCh_In ); + // mustn't be a null terminator + + GLOBALASSERT( Pos_Where >= 0 ); + + #if LimitedLineLength + GLOBALASSERT( Pos_Where <= MAX_LENGTH_INPUT ); + #endif + + // The data-representation invariant: + #if LimitedLineLength + GLOBALASSERT( CursorPos >= 0 ); + GLOBALASSERT( CursorPos <= NumChars ); + + GLOBALASSERT( 0 == ProjCh[ NumChars ] ); + GLOBALASSERT( NumChars <= MAX_LENGTH_INPUT ); + #endif + } + + /* CODE */ + { + #if LimitedLineLength + { + if ( Pos_Where == NumChars ) + { + GLOBALASSERT( 0 == ProjCh[ Pos_Where ] ); + + // insert character at the end if you can: + if ( NumChars < MAX_LENGTH_INPUT ) + { + NumChars++; + ProjCh[ Pos_Where ] = ProjCh_In; + ProjCh[ Pos_Where+1 ] = 0; + + // The cursor may also get dragged along: + if ( CursorPos >= Pos_Where ) + { + CursorPos++; + } + + #if SupportAutomation + FullyManual(); + #endif + + return Yes; + } + else + { + // can't; the line is full + return No; + } + } + else + { + GLOBALASSERT( 0 != ProjCh[ Pos_Where ] ); + + // Try to insert the character within the string; is there space? + if ( NumChars < MAX_LENGTH_INPUT ) + { + // Advance all to the right of the cursor, starting with the final + // character in the string: + + for + ( + int i=NumChars; + i>=Pos_Where; + i-- + ) + { + ProjCh[ i + 1 ] = ProjCh[ i ]; + } + + ProjCh[ Pos_Where ] = ProjCh_In; + NumChars++; + + // The cursor may also get dragged along: + if ( CursorPos >= Pos_Where ) + { + CursorPos++; + } + + #if SupportAutomation + FullyManual(); + #endif + + return Yes; + } + else + { + // can't insert; the line is full + return No; + } + } + } + #else + { + #error Not implemented + } + #endif + } +} + +void TextInputState :: DeleteAt( int Pos ) +{ + #if LimitedLineLength + { + GLOBALASSERT( NumChars > 0 ); + GLOBALASSERT( Pos < NumChars ); + + // Move all characters to the right of the deletion point one space to the left + // (this will overwrite the character at the deletion point ) + + for + ( + int i=Pos; + i Pos ) + { + CursorPos--; + } + + #if SupportAutomation + FullyManual(); + #endif + + } + #else + { + #error Not implemented + } + #endif +} + +void TextInputState :: Clear(void) +{ + #if LimitedLineLength + NumChars = 0; + ProjCh[0] = 0; + #else + while ( List_ProjChar . size() > 0 ) + { + List_ProjChar . delete_first_entry(); + } + #endif + + CursorPos = 0; + + #if SupportAutomation + FullyManual(); + #endif +} + +void TextInputState :: SetString +( + SCString& SCString_ToUse +) +{ + // does not affect ManualPos() + + STRUTIL_SC_SafeCopy + ( + &ProjCh[0], + MAX_SIZE_INPUT, // unsigned int MaxSize, + + SCString_ToUse . pProjCh() + ); + + if + ( + SCString_ToUse . GetNumChars() < MAX_SIZE_INPUT + ) + { + NumChars = SCString_ToUse . GetNumChars(); + } + else + { + NumChars = MAX_LENGTH_INPUT; + } + + CursorPos = NumChars; +} + +#if SupportHistory +void TextInputState :: History_SelectNxt(void) +{ + textprint("TextInputState :: History_SelectNxt()\n"); + + if ( List_pSCString_History . size() > 0) + { + // Iterate through until we find the next match of all the manually typed + // characters with this history position, or we get back to where we started... + SCString* pSCString_History_New = GetNxtMatchingHistory(); + + if ( pSCString_History_New ) + { + pSCString_CurrentHistory = pSCString_History_New; + + // Set to the chosen historic string: + SetString + ( + *pSCString_CurrentHistory // SCString& SCString_ToUse + ); + } + else + { + TextEntryError(); + } + } + else + { + // No history available: + GLOBALASSERT( NULL == pSCString_CurrentHistory ); + + TextEntryError(); + } +} + +void TextInputState :: History_SelectPrv(void) +{ + textprint("TextInputState :: History_SelectPrv()\n"); + +#if 1 + if ( List_pSCString_History . size() > 0) + { + // Iterate through until we find the next match of all the manually typed + // characters with this history position, or we get back to where we started... + SCString* pSCString_History_New = GetPrvMatchingHistory(); + + if ( pSCString_History_New ) + { + pSCString_CurrentHistory = pSCString_History_New; + + // Set to the chosen historic string: + SetString + ( + *pSCString_CurrentHistory // SCString& SCString_ToUse + ); + } + else + { + TextEntryError(); + } + } + else + { + // No history available: + GLOBALASSERT( NULL == pSCString_CurrentHistory ); + + TextEntryError(); + } +#else + if ( List_pSCString_History . size() > 0) + { + // Are we already cycling through the list of history: + if ( pSCString_CurrentHistory ) + { + if + ( + pSCString_CurrentHistory == List_pSCString_History . first_entry() + ) + { + pSCString_CurrentHistory = List_pSCString_History . last_entry(); + } + else + { + pSCString_CurrentHistory = List_pSCString_History . prev_entry( pSCString_CurrentHistory ); + } + } + else + { + pSCString_CurrentHistory = List_pSCString_History . last_entry(); + } + + // Set to the chosen historic string: + SetString + ( + *pSCString_CurrentHistory // SCString& SCString_ToUse + ); + } + else + { + // No history available: + GLOBALASSERT( NULL == pSCString_CurrentHistory ); + + TextEntryError(); + } +#endif + +} + +void TextInputState :: AddToHistory +( + SCString& SCString_ToAdd +) +{ + if ( SCString_ToAdd . GetNumChars() < 1) + { + // Reject adding empty strings to the history + return; + } + + SCString* StringCopy = new SCString(SCString_ToAdd.pProjCh()); + + List_pSCString_History . add_entry_end( StringCopy ); + + if ( List_pSCString_History . size() > MAX_LINES_HISTORY ) + { + List_pSCString_History . first_entry() -> R_Release(); + List_pSCString_History . delete_first_entry(); + } + + pSCString_CurrentHistory = NULL; +} +#endif + +#if SupportAutomation +void TextInputState :: FullyManual(void) +{ + ManualPos = NumChars; + + #if SupportHistory + pSCString_CurrentHistory = NULL; + #endif + + #if SupportCompletion + pConsoleSym_CurrentCompletion = NULL; + #endif +} +OurBool TextInputState :: bManualMatch +( + ProjChar* pProjCh +) const +{ + /* Returns true iff there's a match with the manually-typed prefix of + the current state string and the input comparison string + */ + + GLOBALASSERT( pProjCh ); + + int Count = ManualPos; + + const ProjChar* String1 = pProjCh; + const ProjChar* String2 = &ProjCh[0]; + + + while + ( + ( Count > 0 ) + && + (*String1!='\0') + && + (*String2!='\0') + ) + { + if + ( + (*String1) + != + (*String2) + ) + { + return No; + } + String1++; + String2++; + Count--; + } + + if ( Count > 0 ) + { + // One or more of the strings has terminated... + return + ( + (*String1) + == + (*String2) + ); + } + else + { + // There was a match in the first n characters... + return Yes; + } + +} +OurBool TextInputState :: bManualMatchInsensitive +( + ProjChar* pProjCh +) const +{ + /* Returns true iff there's a match with the manually-typed prefix of + the current state string and the input comparison string + */ + + GLOBALASSERT( pProjCh ); + + int Count = ManualPos; + + const ProjChar* String1 = pProjCh; + const ProjChar* String2 = &ProjCh[0]; + + + while + ( + ( Count > 0 ) + && + (*String1!='\0') + && + (*String2!='\0') + ) + { + if + ( + (tolower(*String1)) + != + (tolower(*String2)) + ) + { + return No; + } + String1++; + String2++; + Count--; + } + + if ( Count > 0 ) + { + // One or more of the strings has terminated... + return + ( + (tolower(*String1)) + == + (tolower(*String2)) + ); + } + else + { + // There was a match in the first n characters... + return Yes; + } + +} + +#endif + +#if SupportCompletion +void TextInputState :: Completion_SelectNxt(void) +{ + #if 1 + textprint("TextInputState :: Completion_SelectNxt()\n"); + #endif + + ConsoleSymbol* pConsoleSym_Completion_New = GetNxtMatchingCompletion(); + + if ( pConsoleSym_Completion_New ) + { + pConsoleSym_CurrentCompletion = pConsoleSym_Completion_New; + + // Set to the chosen completion string: + SetString + ( + *(pConsoleSym_Completion_New->GetpSCString()) // SCString& SCString_ToUse + ); + } + else + { + TextEntryError(); + } +} +void TextInputState :: Completion_SelectPrv(void) +{ + #if 1 + textprint("TextInputState :: Completion_SelectPrv()\n"); + #endif + + ConsoleSymbol* pConsoleSym_Completion_New = GetPrvMatchingCompletion(); + + if ( pConsoleSym_Completion_New ) + { + pConsoleSym_CurrentCompletion = pConsoleSym_Completion_New; + + // Set to the chosen completion string: + SetString + ( + *(pConsoleSym_Completion_New->GetpSCString()) // SCString& SCString_ToUse + ); + } + else + { + TextEntryError(); + } + +} +#endif + + +#if SupportHistory +// private: +SCString* TextInputState :: GetNxtMatchingHistory(void) const +{ + SCString* pSCString_Return = NULL; + + if ( pSCString_CurrentHistory ) + { + // Find next matching one: + SCString* pSCString_I = pSCString_CurrentHistory; + + while ( 1 ) + { + // Advance to next entry (in a circular fashion) + if + ( + pSCString_I == List_pSCString_History . last_entry() + ) + { + pSCString_I = List_pSCString_History . first_entry(); + } + else + { + pSCString_I = List_pSCString_History . next_entry( pSCString_I ); + } + + // Break if you've wrapped around: + if ( pSCString_I == pSCString_CurrentHistory ) + { + break; + } + else + { + // Check for a match: + if + ( + bManualMatchInsensitive( pSCString_I -> pProjCh() ) + ) + { + pSCString_Return = pSCString_I; + break; + } + } + } + + } + else + { + // Find first matching one: + CLIF oi(&List_pSCString_History); + + while ( 1 ) + { + if ( oi . done() ) + { + break; + } + + if + ( + bManualMatchInsensitive( oi() -> pProjCh() ) + ) + { + pSCString_Return = oi(); + break; + } + else + { + oi . next(); + } + } + } + + return pSCString_Return; +} + +SCString* TextInputState :: GetPrvMatchingHistory(void) const +{ + SCString* pSCString_Return = NULL; + + if ( pSCString_CurrentHistory ) + { + // Find prev matching one: + SCString* pSCString_I = pSCString_CurrentHistory; + + while ( 1 ) + { + // Back to prev entry (in a circular fashion) + if + ( + pSCString_I == List_pSCString_History . first_entry() + ) + { + pSCString_I = List_pSCString_History . last_entry(); + } + else + { + pSCString_I = List_pSCString_History . prev_entry( pSCString_I ); + } + + // Break if you've wrapped around: + if ( pSCString_I == pSCString_CurrentHistory ) + { + break; + } + else + { + // Check for a match: + if + ( + bManualMatchInsensitive( pSCString_I -> pProjCh() ) + ) + { + pSCString_Return = pSCString_I; + break; + } + } + } + + } + else + { + // Find final matching one: + CLIB oi(&List_pSCString_History); + + while ( 1 ) + { + if ( oi . done() ) + { + break; + } + + if + ( + bManualMatchInsensitive( oi() -> pProjCh() ) + ) + { + pSCString_Return = oi(); + break; + } + else + { + oi . next(); + } + } + } + + return pSCString_Return; +} +#endif + +#if SupportCompletion +// private: +ConsoleSymbol* TextInputState :: GetNxtMatchingCompletion(void) const +{ + ConsoleSymbol* pConsoleSym_Return = NULL; + + if ( pConsoleSym_CurrentCompletion ) + { + GLOBALASSERT( ConsoleSymbol :: List_pConsoleSym . contains(pConsoleSym_CurrentCompletion ) ); + + // Find next matching one: + ConsoleSymbol* pConsoleSym_I = pConsoleSym_CurrentCompletion; + + while ( 1 ) + { + // Advance to next entry (in a circular fashion) + if + ( + pConsoleSym_I == ConsoleSymbol :: List_pConsoleSym . last_entry() + ) + { + pConsoleSym_I = ConsoleSymbol :: List_pConsoleSym . first_entry(); + } + else + { + pConsoleSym_I = ConsoleSymbol :: List_pConsoleSym . next_entry( pConsoleSym_I ); + } + + // Break if you've wrapped around: + if ( pConsoleSym_I == pConsoleSym_CurrentCompletion ) + { + break; + } + else + { + // Check for a match: + if + ( + pConsoleSym_I->ThisIsACheat + ? + bManualMatch( pConsoleSym_I -> GetpSCString() -> pProjCh() ) + : + bManualMatchInsensitive( pConsoleSym_I -> GetpSCString() -> pProjCh() ) + ) + { + pConsoleSym_Return = pConsoleSym_I; + break; + } + } + } + + } + else + { + // Find first matching one: + CLIF oi(&ConsoleSymbol :: List_pConsoleSym); + + while ( 1 ) + { + if ( oi . done() ) + { + break; + } + + if + ( + oi()->ThisIsACheat + ? + bManualMatch( oi() -> GetpSCString() -> pProjCh() ) + : + bManualMatchInsensitive( oi() -> GetpSCString() -> pProjCh() ) + ) + { + pConsoleSym_Return = oi(); + break; + } + else + { + oi . next(); + } + } + } + + return pConsoleSym_Return; +} +ConsoleSymbol* TextInputState :: GetPrvMatchingCompletion(void) const +{ + return NULL; + // don't implement until you do a full rewrite with templates for circular + // iteration through lists... +} +#endif + + +/* Internal function definitions ***********************************/ +#if 0 + + while (1) + { + // Check for match: + if + ( + bManualMatch + ( + pSCString_I -> pProjCh() + ) + ) + { + // acceptable + break; + } + else + { // not acceptable; try next + } + + // Find next: + } + + +#endif \ No newline at end of file diff --git a/3dc/avp/win95/gadgets/textin.hpp b/3dc/avp/win95/gadgets/textin.hpp new file mode 100644 index 0000000..5bacf35 --- /dev/null +++ b/3dc/avp/win95/gadgets/textin.hpp @@ -0,0 +1,297 @@ +/* + + textin.hpp + + Created by DHM. + + DHM 23/1/98: + ------------ + + Defines a abstract project-independent TextInputState class that can react to typing, + special keys like "backspace" etc. in a sensible fashion. + + The idea is that each project can derive project-specific concrete classes and + embed them in objects for that project's user interface system + + e.g. + - into a TextEntryGadget for AvP + - into a TELObject for HeadHunter + + etc. + + The pure virtual functions are to process carriage returns, and to provide feedback + on errors (e.g. typing backspace when there's nothing left). + + There's a version setting: "LimitedLineLength": + + - If this is set to true, the implementation involves a fixed-size + array of ProjChars. + + - If it's set to false, there's an unfinished implementation involving a + linked list of ProjChars; don't use this option. + +*/ + +#ifndef _textin_hpp +#define _textin_hpp 1 + + #ifndef _textexp + #include "textexp.hpp" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + #define LimitedLineLength Yes + + #define SupportHistory Yes + + #define SupportAutomation Yes + + #define SupportCompletion Yes + + #if !LimitedLineLength + + #ifndef list_template_hpp + #include "list_tem.hpp" + #endif + + #endif + + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + #if SupportCompletion + class ConsoleSymbol; // fully declared in CONSSYM.HPP + #endif + + class TextInputState + { + // Friends: + friend void TextExpansion :: TestForExpansions + ( + TextInputState* pTextInputState_In + ); + + // Constants: + private: + #if LimitedLineLength + enum + { + MAX_LENGTH_INPUT = 250, + // doesn't include a terminator character + + MAX_SIZE_INPUT = (MAX_LENGTH_INPUT + 1) + // does include a terminator character + }; + #endif // Limited line length + + #if SupportHistory + enum + { + MAX_LINES_HISTORY = 32 + }; + #endif + + // Private data: + private: + #if LimitedLineLength + ProjChar ProjCh[ MAX_SIZE_INPUT ]; + // Null-terminated string "in-place" + + int NumChars; + // number of chars befire the null terminator + #else + List List_ProjChar; + #endif + + #if SupportHistory + List List_pSCString_History; + SCString* pSCString_CurrentHistory; + // Can be NULL; indicates no cycling through the history has yet occurred. + // This does NOT own a reference to the string. + #endif + + #if SupportAutomation + int ManualPos; + // all characters with index less than this were + // typed "by hand", as opposed to being automatically + // generated by completion-guessing or by histories + #endif + + #if SupportCompletion + ConsoleSymbol* pConsoleSym_CurrentCompletion; + // Can be NULL; indicates no cycling through the history has yet occurred. + #endif + + + int CursorPos; + // cursor is to the left of the character with this index + + OurBool bForceUpperCase_Val; + static OurBool bOverwrite_Val; + // otherise it's insert mode + + public: + virtual ~TextInputState(); + + SCString& GetCurrentState(void); + // returns a ref to a copy of the "string under construction" in its current state + + void CharTyped + ( + char Ch + // note that this _is _ a char + ); + void Key_Backspace(void); + void Key_End(void); + void Key_Home(void); + void Key_Left(void); + void Key_Right(void); + void Key_Delete(void); + + static OurBool bOverwrite(void) + { + return bOverwrite_Val; + } + static void ToggleTypingMode(void); + // toggles overwrite/insert mode + + + public: + virtual void ProcessCarriageReturn(void) = 0; + + protected: + virtual void TextEntryError(void) = 0; + // called e.g. when no more text can be typed, or no more deleted + // may make a beep noise + + // Protected methods: + protected: + // Constructor is protected since it's an abstract base class + TextInputState + ( + OurBool bForceUpperCase, + char* pProjCh_Init + // could be const + ); + + void TryToInsertAt + ( + SCString* pSCString_ToInsert, + int Pos_Where + ); + + int bOvertypeAt + ( + ProjChar ProjCh_In, + int Pos_Where + ); + // return value: was overtype succesful? + int bInsertAt + ( + ProjChar ProjCh_In, + int Pos_Where + ); + // return value: was insertion succesful? + + void DeleteAt( int Pos ); + + void Clear(void); + + + #if SupportHistory + void History_SelectNxt(void); + void History_SelectPrv(void); + + void AddToHistory + ( + SCString& SCString_ToAdd + ); + #endif + + #if SupportAutomation + void FullyManual(void); + /* + Flags the string as if all its content has been manually + typed (call when the user types something that signifies he/she + accepts something that might have been generated by completion/history + code). + */ + OurBool bManualMatch + ( + ProjChar* pProjCh + ) const; + OurBool bManualMatchInsensitive + ( + ProjChar* pProjCh + ) const; + /* Returns true iff there's a match with the manually-typed prefix of + the current state string and the input comparison string + */ + #endif + + #if SupportCompletion + void Completion_SelectNxt(void); + void Completion_SelectPrv(void); + #endif + + + // I'm not sure what interface I should supply; this is a stopgap so that I can write + // rendering functions for AvP + public: + void SetString + ( + SCString& SCString_ToUse + ); + #if LimitedLineLength + const ProjChar* GetProjChar(void) const + { + return &ProjCh[0]; + } + int GetCursorPos(void) const + { + return CursorPos; + } + int GetNumChars(void) const + { + return NumChars; + } + #endif + + #if SupportHistory + private: + SCString* GetNxtMatchingHistory(void) const; + SCString* GetPrvMatchingHistory(void) const; + // will return NULL if it wraps around internally i.e. no matches + #endif + + #if SupportCompletion + private: + ConsoleSymbol* GetNxtMatchingCompletion(void) const; + ConsoleSymbol* GetPrvMatchingCompletion(void) const; + // will return NULL if it wraps around internally i.e. no matches + #endif + + + }; // end of class TextInputState + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/win95/gadgets/trepgadg.cpp b/3dc/avp/win95/gadgets/trepgadg.cpp new file mode 100644 index 0000000..0f513f7 --- /dev/null +++ b/3dc/avp/win95/gadgets/trepgadg.cpp @@ -0,0 +1,995 @@ +/******************************************************************* + * + * DESCRIPTION: trepgadg.cpp - text report gadget + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 14/11/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "trepgadg.hpp" +#include "teletype.hpp" +#include "coordstr.hpp" +#include "trig666.hpp" + +#include "indexfnt.hpp" + +#include "wrapstr.hpp" + +#include "inline.h" + +#include "iofocus.h" + +#include "ConsoleLog.hpp" + + #include "rootgadg.hpp" + #include "hudgadg.hpp" + // for ClearTheQueue() + + #include "font.h" + // for the font tests + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + #define MAX_MESSAGES_TO_DISPLAY (20) + #define PARTIAL_MESSAGES_TO_DISPLAY (5) + + #define FIXP_SECONDS_UNTIL_TEXT_REPORTS_DISAPPEAR (ONE_FIXED * 5) + #define FIXP_CHEESY_FLASH_RATE (ONE_FIXED * 6) + #define INT_CHEESY_FLASH_DURATION (1) + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif + extern int RealFrameTime; +#ifdef __cplusplus + }; +#endif + + +static int NumberOfLinesToDisplay=0; + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ + #if UseGadgets + class TextReportDaemon_Scroll : public AcyclicHomingCoordinate + { + public: + TextReportDaemon_Scroll + ( + TextReportGadget* pTextReportGadg + ); + ~TextReportDaemon_Scroll(); + private: + }; + class TextReportDaemon_Disappear : public PulsingTriggerDaemon + { + public: + TextReportDaemon_Disappear + ( + TextReportGadget* pTextReportGadg + ); + + ~TextReportDaemon_Disappear(); + + void Triggered(void); + + private: + TextReportGadget* pTextReportGadg_Val; + }; + class CheesyDaemon_Flash : public CyclicPulsingCoordinate + { + public: + CheesyDaemon_Flash(); + private: + }; + + class CheesyDaemon_Lifetime : public AcyclicFixedSpeedHoming + { + public: + CheesyDaemon_Lifetime(); + OurBool bStillAlive(void); + void Reset(void); + }; + + #endif // UseGadgets + +/* Internal function prototypes ************************************/ +#if UseGadgets +void TestStringRender_Unclipped +( + r2pos& R2Pos_Cursor, + // start position for string; + // gets written back to with final position + + // Renders as a single line; it is asserted that the result is fully within + // the physical screen (i.e. already clipped) + const SCString& SCStr +); +#endif + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ +#if UseGadgets +// class TextReportGadget : public Gadget +// public: +void TextReportGadget :: Render +( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha +) +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + #if 0 + BLTFontOffsetToHUD + ( + // PFFONT* font , + 400, // int xdest, + 100, // int ydest, + 0 // int offset + ); + #endif + + #if 0 + BLTWholeFont + ( + 3, // int fontnum, + 30, // int x , + 130, // int y, + 100 // int win_width + ); + #endif + + #if 0 + textprint + ( + "TextReportGadget :: Render at (%i,%i) clipped (%i,%i,%i,%i) alpha=%i\n", + R2Pos . x, + R2Pos . y, + R2Rect_Clip . x0, + R2Rect_Clip . y0, + R2Rect_Clip . x1, + R2Rect_Clip . y1, + FixP_Alpha + ); + #endif + + IndexedFont* pLetterFont = IndexedFont :: GetFont( I_Font_TeletypeLettering ); + GLOBALASSERT( pLetterFont ); + + int FontHeight = pLetterFont -> GetHeight(); + + struct r2rect R2Rect_ClipForText = r2rect + ( + R2Pos, + TEXT_REPORT_MAX_W, + ( MAX_MESSAGES_TO_DISPLAY * FontHeight ) + ); + + // Clip this rectangle with the passed clip rectangle: + R2Rect_Clip . Clip( R2Rect_ClipForText ); + + // Alpha mounting poly: + { + R2Rect_ClipForText . AlphaFill + ( + 0, + 64, + 0, + (FixP_Alpha * 2 / (256 * 3)) + // unsigned char translucency + ); + } + + #if 0 + { + SCString* pSCStr_Temp = new SCString("PLACEHOLDER STRING"); + r2pos R2Pos_Cursor = R2Rect_ClipForText . GetPos(); + + TestStringRender_Unclipped + ( + R2Pos_Cursor, // r2pos& R2Pos_Cursor, + // start position for string; + // gets written back to with final position + + // Renders as a single line; it is asserted that the result is fully within + // the physical screen (i.e. already clipped) + *pSCStr_Temp // const SCString& SCStr + ); + + pSCStr_Temp -> R_Release(); + } + #endif + + // Calculate y-displacement based upon number of lines: + int HeightOfLines = (List_pTeletypeGadg_Displaying . size() * FontHeight); + + struct r2pos R2Pos_Teletype = R2Pos; + + // displace up so that last line is just at bottom of view: + R2Pos_Teletype . y -= (HeightOfLines - ( MAX_MESSAGES_TO_DISPLAY * FontHeight ) ); + + // Iterate through the teletype gadgets: + { + for + ( + List_Iterator_Forward oi(&(List_pTeletypeGadg_Displaying)); + !oi.done(); + oi.next() + ) + { + #if 1 + oi() -> Render + ( + R2Pos_Teletype, // const struct r2pos& R2Pos, + R2Rect_ClipForText, // const struct r2rect& R2Rect_Clip, + FixP_Alpha // int FixP_Alpha + ); + R2Pos_Teletype . y += FontHeight; + #else + textprint + ( + "Textline:\"%s\"\n", + oi() -> pProjCh() + ); + #endif + } + } + + // If the last one has finished; add a cheesy flashing cursor: + if ( List_pTeletypeGadg_Displaying . size() > 0) + { + TeletypeGadget* pLast = List_pTeletypeGadg_Displaying . last_entry(); + + GLOBALASSERT( pLast ); + + if ( pLast -> HasFinishedPrinting() ) + { + + if ( p666_CheeseLifetime -> bStillAlive() ) + { + pLast -> DirectRenderCursor + ( + r2pos(R2Pos_Teletype.x,R2Pos_Teletype.y-FontHeight), + R2Rect_ClipForText, + MUL_FIXED( FixP_Alpha, p666_CheeseFlash -> GetCoord_FixP() ) + ); + } + } + } + + + #if 0 + // Diagnostic on queuing messages: + { + textprint("Text report queue:\n"); + for + ( + List_Iterator_Forward oi(&(List_pSCString_ToAppear)); + // a _pointer_ + // to the list. + !oi.done(); + oi.next() + ) + { + textprint + ( + "Queuing:\"%s\"\n", + oi() -> pProjCh() + ); + } + } + #endif + + } +} + +struct r2pos TextReportGadget :: GetPos_Rel +( + const struct r2rect& R2Rect_Parent +) const +{ + return r2pos + ( + (R2Rect_Parent . Width() - TEXT_REPORT_MAX_W)/2, + p666_Scroll -> GetCoord_Int() + ); +} + +r2size TextReportGadget :: GetSize +( + const struct r2rect& // R2Rect_Parent +) const +{ + IndexedFont* pLetterFont = IndexedFont :: GetFont( I_Font_TeletypeLettering ); + GLOBALASSERT( pLetterFont ); + + return r2size + ( + TEXT_REPORT_MAX_W, + ( MAX_MESSAGES_TO_DISPLAY * pLetterFont -> GetHeight() ) + ); +} + + +TextReportGadget :: TextReportGadget +( +) : Gadget + ( + #if debug + "TextReportGadget" + #endif + ), + RefList_SCString_ToAppear(), + List_pTeletypeGadg_Displaying() +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + #if 0 + pSCString_Current = NULL; + #endif + + p666_Scroll = new TextReportDaemon_Scroll + ( + this + ); + p666_Disappear = new TextReportDaemon_Disappear + ( + this + ); + + p666_CheeseFlash = new CheesyDaemon_Flash(); + p666_CheeseLifetime = new CheesyDaemon_Lifetime(); + } +} + +TextReportGadget :: ~TextReportGadget() +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + #if 1 + { + for + ( + List_Iterator_Forward oi(&(List_pTeletypeGadg_Displaying)); + !oi.done(); + oi.next() + ) + { + // Delete the teletype objects: + delete( oi() ); + } + } + #else + if ( pSCString_Current ) + { + pSCString_Current -> R_Release(); + } + #endif + + delete p666_Scroll; + delete p666_Disappear; + delete p666_CheeseFlash; + delete p666_CheeseLifetime; + + } + NumberOfLinesToDisplay=0; +} + +void TextReportGadget :: AddTextReport +( + SCString* pSCString_ToAdd +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pSCString_ToAdd ); + } + + /* CODE */ + { + #if 1 + IndexedFont* pLetterFont = IndexedFont :: GetFont( I_Font_TeletypeLettering ); + GLOBALASSERT( pLetterFont ); + + List* pList_pSCString_Wrapped = WordWrap :: DeprecatedMake + ( + *pSCString_ToAdd, // const SCString& SCString_In, + + *pLetterFont, // const IndexedFont& IndexedFnt_In, + + TEXT_REPORT_MAX_W, // int W_FirstLine_In, + TEXT_REPORT_MAX_W // int W_Subsequently_In + ); + + // Iterate through list of strings, adding each as teletype gadgets to the report, + // then releasing the strings: +// NumberOfLinesToDisplay=0; + for + ( + LIF oi( pList_pSCString_Wrapped ); + !oi.done(); + oi.next() + ) + { + GLOBALASSERT( oi() ); + AddTeletypeLine( oi() ); + oi() -> R_Release(); + NumberOfLinesToDisplay++; + } + { + p666_Scroll -> SetTarget_Int + ( + ( IOFOCUS_AcceptTyping() ) + ? + ( GetFullyOnScreenScrollCoord() ) + : + ( GetPartiallyOnScreenScrollCoord() ) + ); + p666_Disappear -> Stop(); + } + + + delete pList_pSCString_Wrapped; + #else + AddTeletypeLine + ( + pSCString_ToAdd + ); + #endif + } +} + +void TextReportGadget :: ClearQueue(void) +{ + // clears the queue of buffered messages; could be handy if you've + // started a listing of 300 module names + + int NumKilled = RefList_SCString_ToAppear . NumEntries(); + + RefList_SCString_ToAppear . EmptyYourself(); + + #if 0 + { + SCString* pSCString_Temp1 = new SCString("CLEARED MESSAGE DISPLAY QUEUE; NUM LINES="); + // LOCALISEME() + SCString* pSCString_Temp2 = new SCString(NumKilled); + + SCString* pSCString_Feedback = new SCString + ( + pSCString_Temp1, + pSCString_Temp2 + ); + + pSCString_Temp2 -> R_Release(); + pSCString_Temp1 -> R_Release(); + + pSCString_Feedback -> SendToScreen(); + + pSCString_Feedback -> R_Release(); + } + #endif +} + +/*static*/ void TextReportGadget :: ClearTheQueue(void) +{ + // tries to find the (singleton) queue and clears it + + GLOBALASSERT( RootGadget :: GetRoot() ); + + if ( RootGadget :: GetRoot() -> GetHUD() ) + { + RootGadget :: GetRoot() -> GetHUD() -> ClearTheTextReportQueue(); + } +} + + +void TextReportGadget :: TeletypeCompletionHook(void) +{ + // If the queue is non-empty, add first string as new teletype object: + + // Destructive read the first string in the queue: + SCString* pSCString_FirstInQueue = RefList_SCString_ToAppear . GetYourFirst(); + + if + ( + pSCString_FirstInQueue + ) + { + DirectAddTeletypeLine + ( + pSCString_FirstInQueue + ); + + // GetYourFirst() leaves us holding the reference... + pSCString_FirstInQueue -> R_Release(); + } + else + { + // No more messages; + // Reset disappearance time, and "arm" the disappearance: + p666_Disappear -> SetFuse_FixP + ( + FIXP_SECONDS_UNTIL_TEXT_REPORTS_DISAPPEAR // int FixP_Fuse // time until it next triggers; doesn't change the period + ); + + p666_Disappear -> Start(); + + p666_CheeseLifetime -> Reset(); + } + + //add a timer for this line of text + LineTimes.add_entry(FIXP_SECONDS_UNTIL_TEXT_REPORTS_DISAPPEAR); +} + +int TextReportGadget :: GetFullyOnScreenScrollCoord(void) +{ + return 0; +} + +int TextReportGadget :: GetPartiallyOnScreenScrollCoord(void) +{ + IndexedFont* pLetterFont = IndexedFont :: GetFont( I_Font_TeletypeLettering ); + GLOBALASSERT( pLetterFont ); + + + return -((MAX_MESSAGES_TO_DISPLAY - NumberOfLinesToDisplay) * pLetterFont -> GetHeight() ); +} + +int TextReportGadget :: GetOffScreenScrollCoord(void) +{ + IndexedFont* pLetterFont = IndexedFont :: GetFont( I_Font_TeletypeLettering ); + GLOBALASSERT( pLetterFont ); + + return -(MAX_MESSAGES_TO_DISPLAY * pLetterFont -> GetHeight() ); +} + +void TextReportGadget :: Disappear(void) +{ + // to be called only by TextReportDaemon_Disappear + //clear the list of timers for when individual lines should disappear + NumberOfLinesToDisplay = 0; + while(LineTimes.size()) LineTimes.delete_first_entry(); + + p666_Scroll -> SetTarget_Int + ( + GetOffScreenScrollCoord() + // int Int_TargetCoord + ); + p666_Disappear -> Stop(); +} + +void TextReportGadget :: ForceOnScreen(void) +{ + // called by the marine HUD gadget if input focus set to typing + // to stop the object scrolling away + p666_Scroll -> SetTarget_Int + ( + GetFullyOnScreenScrollCoord() + // int Int_TargetCoord + ); + p666_Disappear -> Stop(); +} + + + +//private: +void TextReportGadget :: AddTeletypeLine +( + SCString* pSCString_ToAdd +) +{ + // Either to queue, or direct + + /* PRECONDITION */ + { + GLOBALASSERT( pSCString_ToAdd ); + } + + /* CODE */ + { + /* KJL 11:33:13 30/03/98 - duplicate output to log file */ + OutputToConsoleLogfile( pSCString_ToAdd -> pProjCh() ); + + // If finished displaying last message; immediately display this one, otherwise + // add to list. The message display daemon should process the queue: + if ( List_pTeletypeGadg_Displaying . size() > 0 ) + { + if + ( + !List_pTeletypeGadg_Displaying . last_entry() -> HasFinishedPrinting() + ) + { + // Can't add a new teletype object yet; there's an existing one which + // hasn't finished yet; add to queue: + + RefList_SCString_ToAppear . AddToEnd + ( + *pSCString_ToAdd + ); + + return; + } + } + + // Otherwise you can add the teletype object: + { + DirectAddTeletypeLine + ( + pSCString_ToAdd + ); + } + } +} + +void TextReportGadget :: DirectAddTeletypeLine +( + SCString* pSCString_ToAdd +) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pSCString_ToAdd ); + } + + /* CODE */ + { + // You no longer own a reference to this string + #if 0 + { + IndexedFont* pLetterFont = IndexedFont :: GetFont( I_Font_TeletypeLettering ); + GLOBALASSERT( pLetterFont ); + + List* pList_pSCString_Wrapped = WordWrap :: Make + ( + *pSCString_ToAdd, // const SCString& SCString_In, + + *pLetterFont, // const IndexedFont& IndexedFnt_In, + + TEXT_REPORT_MAX_W, // int W_FirstLine_In, + TEXT_REPORT_MAX_W // int W_Subsequently_In + ); + + pSCString_ToAdd -> R_Release(); + + // Iterate through list of strings, adding each as teletype gadgets to the report, + // then releasing the strings: + for + ( + LIF oi( pList_pSCString_Wrapped ); + !oi.done(); + oi.next() + ) + { + List_pTeletypeGadg_Displaying . add_entry_end + ( + new TeletypeGadget + ( + this, // TextReportGadget* pTextReportGadg, + oi() // SCString* pSCString + ) + ); + oi() -> R_Release(); + } + + delete pList_pSCString_Wrapped; + } + #else + { + List_pTeletypeGadg_Displaying . add_entry_end + ( + new TeletypeGadget + ( + this, // TextReportGadget* pTextReportGadg, + pSCString_ToAdd // SCString* pSCString + ) + ); + } + #endif + + PostprocessForAddingTeletypeLine(); + } +} + +void TextReportGadget :: PostprocessForAddingTeletypeLine(void) +{ + if ( List_pTeletypeGadg_Displaying . size() > MAX_MESSAGES_TO_DISPLAY ) + { + TeletypeGadget* pTeletypeGadg = List_pTeletypeGadg_Displaying . first_entry(); + + GLOBALASSERT( pTeletypeGadg ); + + delete pTeletypeGadg; + + List_pTeletypeGadg_Displaying . delete_first_entry(); + } + + // Make it visible, either fully or partially, depending on input focus: + { + p666_Scroll -> SetTarget_Int + ( + ( IOFOCUS_AcceptTyping() ) + ? + ( GetFullyOnScreenScrollCoord() ) + : + ( GetPartiallyOnScreenScrollCoord() ) + ); + } + + p666_Disappear -> Stop(); +} + + +// need a daemon for handling scrolling, disposal of old messages, etc. + +int TextReportGadget :: MinYDisplacement(void) +{ + return 0; + // for now +} + +int TextReportGadget :: MaxYDisplacement(void) +{ + return 0; + // for now +} + +void TextReportGadget :: UpdateLineTimes() +{ + int time; + + //if we are currently displaying to many lines ,g et rifd of the earliest ones + while(NumberOfLinesToDisplay > MAX_MESSAGES_TO_DISPLAY) + { + if(LineTimes.size()) LineTimes.delete_first_entry(); + NumberOfLinesToDisplay--; + } + + //go through our list of timers for each line , updating them + for(LIF timelif(&LineTimes);!timelif.done();) + { + time=timelif()-RealFrameTime; + if(time<=0) + { + //this timer has expired , so reduce the number of lines displayed by one + //also delete this timer from the list + timelif.delete_current(); + NumberOfLinesToDisplay--; + if(NumberOfLinesToDisplay<0) + { + NumberOfLinesToDisplay=0; + } + + //update the sceen coordinates (assuming the console isn't off screen) + { + p666_Scroll -> SetTarget_Int + ( + ( IOFOCUS_AcceptTyping() ) + ? + ( GetFullyOnScreenScrollCoord() ) + : + ( GetPartiallyOnScreenScrollCoord() ) + ); + } + + } + else + { + //update this timer + timelif.change_current(time); + timelif.next(); + } + } +} + +#endif //UseGadgets + +/* Internal function definitions ***********************************/ +#if UseGadgets +// class TextReportDaemon_Scroll : public AcyclicHomingCoordinate +// public: +TextReportDaemon_Scroll :: TextReportDaemon_Scroll +( + TextReportGadget* pTextReportGadg +) : AcyclicHomingCoordinate + ( + pTextReportGadg -> GetOffScreenScrollCoord(), //int Int_InitialCoord, + pTextReportGadg -> GetOffScreenScrollCoord() // int Int_TargetCoord + ) +{ +} + +TextReportDaemon_Scroll :: ~TextReportDaemon_Scroll() +{ +} +// private: +// class TextReportDaemon_Disappear : public PulsingTriggerDaemon +// public: +TextReportDaemon_Disappear :: TextReportDaemon_Disappear +( + TextReportGadget* pTextReportGadg +) : PulsingTriggerDaemon + ( + Yes, // OurBool fActive, + FIXP_SECONDS_UNTIL_TEXT_REPORTS_DISAPPEAR // int FixP_Period // interval between triggers in seconds + ) +{ + GLOBALASSERT( pTextReportGadg ); + pTextReportGadg_Val = pTextReportGadg; +} + +TextReportDaemon_Disappear :: ~TextReportDaemon_Disappear() +{ +} + +void TextReportDaemon_Disappear :: Triggered(void) +{ + // Set the homing coordinate for the text report gadget so it disappears off the screen + // again + + + pTextReportGadg_Val -> Disappear(); +} + + +// class CheesyFlashDaemon : public CyclicPulsingCoordinate +// public: +CheesyDaemon_Flash :: CheesyDaemon_Flash +( +) : CyclicPulsingCoordinate + ( + 0, // int Int_InitialCoord, + 1, // int Int_SecondCoord, + (ONE_FIXED * 4), // int FixP_Velocity, + Yes // OurBool fActive + ) +{ + // empty +} + +// class CheesyDaemon_Lifetime : public AcyclicFixedSpeedHoming +// public: +CheesyDaemon_Lifetime :: CheesyDaemon_Lifetime +( +) : AcyclicFixedSpeedHoming + ( + INT_CHEESY_FLASH_DURATION, // int Int_InitialCoord, + 0, // int Int_TargetCoord, + ONE_FIXED // int FixP_Speed + ) +{ + // empty +} + +OurBool CheesyDaemon_Lifetime :: bStillAlive(void) +{ + return ( GetCoord_FixP() > 0); +} + +void CheesyDaemon_Lifetime :: Reset(void) +{ + SetCoord_Int( INT_CHEESY_FLASH_DURATION ); +} + + + +#endif // UseGadgets + + + + + + + + +#if UseGadgets && 0 + // test code + #define FONT_INDEX (3) + +void TestStringRender_Unclipped +( + r2pos& R2Pos_Cursor, + // start position for string; + // gets written back to with final position + + // Renders as a single line; it is asserted that the result is fully within + // the physical screen (i.e. already clipped) + const SCString& SCStr +) +{ + /* PRECONDITION */ + { + } + + /* CODE */ + { + // GetOffset: + const pffont& PFFont = AvpFonts[FONT_INDEX]; + + ProjChar* pProjChar_I = SCStr . pProjCh(); + + while ( *pProjChar_I ) + { + const ProjChar ProjCh = *pProjChar_I; + + if + ( + PFFont . bPrintable( ProjCh ) + ) + { + #if 0 + textprint("printable \'%c\'\n",ProjCh); + #endif + + R2Pos_Cursor . x += 1+BLTFontOffsetToHUD + ( + (PFFONT*)&PFFont, // PFFONT* font, + // "cast away the const-ness" for the moment + R2Pos_Cursor . x, // int xdest, + R2Pos_Cursor . y, // int ydest, + PFFont . ProjCharToOffset( ProjCh ) // int offset + ); + // appears to return the width of the character... + } + else + { + #if 0 + textprint("unprintable \'%c\'\n",ProjCh); + #endif + } + + pProjChar_I++; + } + } +} + +void TestStringRender_Clipped +( + r2pos& R2Pos_Cursor, + const r2rect& R2Rect_Clip, + const SCString& SCStr +) +{ +} +#endif // test code diff --git a/3dc/avp/win95/gadgets/trepgadg.hpp b/3dc/avp/win95/gadgets/trepgadg.hpp new file mode 100644 index 0000000..ef26ec8 --- /dev/null +++ b/3dc/avp/win95/gadgets/trepgadg.hpp @@ -0,0 +1,163 @@ +/* + + trepgadg.hpp + + TextReportGadget : a class for the text report area of the HUD +*/ + +#ifndef _trepgadg +#define _trepgadg 1 + + #ifndef _gadget + #include "gadget.h" + #endif + + #if UseGadgets + #ifndef list_template_hpp + #include "list_tem.hpp" + #endif + + #ifndef _scstring + #include "scstring.hpp" + #endif + + #ifndef _reflist_hpp + #include "reflist.hpp" + #endif + + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + #define TEXT_REPORT_MAX_W (300) + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + #if UseGadgets + + + class TeletypeGadget; // fully declared in TELETYPE.HPP + + class TextReportDaemon_Scroll; // fully declared in MHUDGADG.HPP + class TextReportDaemon_Disappear; // fully declared in MHUDGADG.HPP + + class CheesyDaemon_Flash; // fully declared in TREPGADG.CPP + class CheesyDaemon_Lifetime; // fully declared in TREPGADG.CPP + + class TextReportGadget : public Gadget + { + public: + void Render + ( + const struct r2pos& R2Pos, + const struct r2rect& R2Rect_Clip, + int FixP_Alpha + ); + + struct r2pos TextReportGadget :: GetPos_Rel + ( + const struct r2rect& R2Rect_Parent + ) const; + + r2size TextReportGadget :: GetSize + ( + const struct r2rect& R2Rect_Parent + ) const; + + TextReportGadget(); + ~TextReportGadget(); + + void AddTextReport + ( + SCString* pSCString_ToAdd + ); + + void ClearQueue(void); + // clears the queue of buffered messages; could be handy if you've + // started a listing of 300 module names + + static void ClearTheQueue(void); + // tries to find the (singleton) queue and clears it + + void TeletypeCompletionHook(void); + // called by the teletyp object when it has finished displaying itself + + int GetFullyOnScreenScrollCoord(void); + int GetPartiallyOnScreenScrollCoord(void); + int GetOffScreenScrollCoord(void); + // coordinates for scroll daemons for putting the text report either on the screen + // or off it ( in integer rather than not fixed point) + + void Disappear(void); + // to be called only by TextReportDaemon_Disappear + + void ForceOnScreen(void); + // called by the marine HUD gadget if input focus set to typing + // to stop the object scrolling away + + void UpdateLineTimes(); + private: + void AddTeletypeLine + ( + SCString* pSCString_ToAdd + ); + + void DirectAddTeletypeLine + ( + SCString* pSCString_ToAdd + ); + + void PostprocessForAddingTeletypeLine(void); + + // need a daemon for handling scrolling, disposal of old messages, etc. + + int MinYDisplacement(void); + int MaxYDisplacement(void); + + #if 1 + // Queue of messages waiting to appear: + RefList RefList_SCString_ToAppear; + + // Queue of messages that are being displayed: + List List_pTeletypeGadg_Displaying; + + //time left to display each teletype line thingy + List LineTimes; + + CheesyDaemon_Flash* p666_CheeseFlash; + CheesyDaemon_Lifetime* p666_CheeseLifetime; + + #else + // primitive implementation: + SCString* pSCString_Current; + #endif + + TextReportDaemon_Scroll* p666_Scroll; + // scrolling the text box, making it appear and disappear + + TextReportDaemon_Disappear* p666_Disappear; + // countdown for making the text box disappear + + }; + #endif //UseGadgets + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/win95/gadgets/vssver.scc b/3dc/avp/win95/gadgets/vssver.scc new file mode 100644 index 0000000..092b64f Binary files /dev/null and b/3dc/avp/win95/gadgets/vssver.scc differ diff --git a/3dc/avp/win95/gflwplat.c b/3dc/avp/win95/gflwplat.c new file mode 100644 index 0000000..309686b --- /dev/null +++ b/3dc/avp/win95/gflwplat.c @@ -0,0 +1,235 @@ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "gameplat.h" +#include "gameflow.h" + +static char * messages[PlayerMissions_Last]= +{ +"BASE COMMANDER:\n\ +WOAH, CAN'T SPEAK NOW, THERE'S \n\ +SOME MAJOR SHIT GOING DOWN. GET\n\ +YOUR ARSE TO GENERAL.", + +"BASE COMMANDER:\n\ +HEADS UP TROOP WE'RE IN SOME PRETTY \n\ +SHIT. TAKE OUT THE 4 VEHICLE LIFT \n\ +MANUAL OVERRIDE CONTROLS IN \n\ +LIVING QUARTERS AND HANGAR ONE. WE'LL \n\ +OPEN ACCESS TO THE LIFT OUT. THEY'RE\n\ +THE ONES WITH THE COMPUTER TERMINAL AT\n\ +THE TOP AND A YELLOW STRIPED PIPE AT\n\ +THE BOTTOM. OH, AND, WATCH YOUR BACK,\n\ +THERE IS SOME ER.. EXPERIMENTAL TECH\n\ +STUFF LOOSE IN THE BASE.", + +"BASE COMMANDER:\n\ +TROOP, FURTHER ORDERS FROM ON HIGH.\n\ +GET TO SECURITY 2, THERE'S SOME AMMO\n\ +WAITING. BASE COM OUT.", + +"BASE COMMANDER:\n\ +BASE COM HERE. I DON'T LIKE THIS MUCH, \n\ +BUT THIS PRETTY LI'L LADY WON'T TAKE\n\ +NO FOR AN ANSWER. THE SCI TECH STUFF,\n\ +ITS WORSE THAN WE THOUGHT, 'SPECIALLY\n\ +IN R'N'D LABS. WE CAN'T ALLOW ACCESS\n\ +TO THE LIFT. I GUESS THE ONLY OPTION\n\ +IS TO GO THE LONG WAY ROUND. WATCH\n\ +YOUR BACK, AND TRY TO KILL AS MANY AS\n\ +YOU CAN, OK?", + +"BASE COMMANDER:\n\ +AN ESCAPE SHIP IS PREPPED, WE'LL WAIT\n\ +AS LONG AS WE CAN. MEET POINT IS MY \n\ +OFFICE IN MAIN CONTROL, GET HERE ASAP.", + +"BASE COMMANDER:\n\ +SHIT, TROOP WE COULDN'T WAIT. WE'RE \n\ +NOW IN MAIN ARMOURY. ACCESS TO GENERAL \n\ +AND MAIN CONTROL IS SEALED OFF. WE'LL \n\ +HOLD DOWN IN HANGAR TWO FOR YOU.\n\ +WATCH OUT FOR SENTRY GUNS, WE'VE\n\ +PLACED THEM TO COVER OUR BACKS. THE\n\ +ARMOURY IS STILL FULL OF AMMO.", + +"CORPORATION WOMAN:\n\ +WE ARE NOW IN ORBIT. YOUR ONLY CHANCE\n\ +TO SURVIVE IS TO REACH THE EMERGENCY \n\ +SHUTTLE, BUT IT WILL ONLY WORK IF THE \n\ +BASE SELF-DESTRUCT IS SET. YOU CAN \n\ +REACH THE DESTRUCT CORE IN MAIN \n\ +REACTOR. ONCE YOU'VE SET IT, YOU \n\ +CAN GET OUT ACROSS THE SURFACE TO THE\n\ +SHUTTLE.", + +"CONGRATULATIONS, YOU HAVE WON.\n\ +ENJOY THE SURFACE LEVEL.", + + + + +"DESTROY THE COMPUTERS IN MAIN CONTROL\n", + +"RECOVER SHIP PART FROM HANGAR ONE\n", + +"RECOVER SHIP PART FROM HANGAR TWO\n", + +"KILL PREDATOR ALIENS\n", + +"KILL ALIEN QUEEN AND SET SELF-\n\ +DESTRUCT IN MAIN REACTOR\n", + +"RETURN TO SHIP IN NON-TERRESTRIAL\n\ +TECHNOLOGY LAB.\n", + + + + + 0, + 0, + 0, + 0, + +}; + +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + + +void DoStartMissionSequence (PLAYERMISSION mission) +{ + + char buffer[1024]; + + sprintf(buffer, "%s\n\nPress Return\n", messages[mission]); + + ColourFillBackBuffer(0); +#if PreBeta + jtextprint ("%s", buffer); + FlipBuffers(); +#elif debug + textprint ("%s", buffer); + FlushTextprintBuffer(); + FlipBuffers(); +#endif + +} + +char * GetCurrentMissionString () +{ + if (PlayerStatusPtr->CurrentMission < PlayerMissions_Last) + { + return(messages[PlayerStatusPtr->CurrentMission]); + } + else + { + return(0); + } +} + +void ShowMissionMessage () +{ + char buffer[1024]; + + if (!messages[PlayerStatusPtr->CurrentMission]) + { + return; + } + + sprintf(buffer, "%s\nSecurity %x Flags %x\n", messages[PlayerStatusPtr->CurrentMission], + PlayerStatusPtr->securityClearances, + PlayerStatusPtr->StateChangeObjectFlags); + +#if PreBeta + jtextprint ("%s", buffer); +#elif debug + textprint ("%s", buffer); +#endif +} + +// this will only print one string from the top of the screen + +static int CharWidthInPixels(char Ch) +{ + if + ( + ( + (Ch>=FontStart) + && + (Ch<=FontEnd) + ) + || + (' '==Ch) + + ) + { + return CharWidth; + } + else + { + return 0; + } +} + +static int LastDisplayableXForChars(void) +{ + return ScreenDescriptorBlock.SDB_Width-CharWidth; +} + +void jtextprint (const char* t, ...) +{ + char buffer [1024]; + /* + Get message string from arguments into buffer... + */ + { + va_list ap; + + va_start(ap, t); + vsprintf(&buffer[0], t, ap); + va_end(ap); + } + + { + int x=0,y=0; + char * cptr = &buffer[0]; + + while (*cptr != 0) + { + switch (*cptr) + { + case '\n': + { + y += CharVertSep; + x = 0; + break; + } + + default: + { + BlitWin95Char (x, y, *cptr); + + x+=CharWidthInPixels(*cptr); + if (x>LastDisplayableXForChars()) + { + y += CharVertSep; + x = 0; + } + + break; + } + } + + cptr ++; + } + + + } + + + +} diff --git a/3dc/avp/win95/hierplace.cpp b/3dc/avp/win95/hierplace.cpp new file mode 100644 index 0000000..2830257 --- /dev/null +++ b/3dc/avp/win95/hierplace.cpp @@ -0,0 +1,296 @@ +#include "hierplace.hpp" +#include "md5.h" + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(hierplace) + +//////////////////////////////////////////////// +//Class Placed_Hiearchy_Chunk + + +RIF_IMPLEMENT_DYNCREATE("PLACHIER",Placed_Hierarchy_Chunk) + +CHUNK_WITH_CHILDREN_LOADER("PLACHIER",Placed_Hierarchy_Chunk) +/* +Children for Placed_Hiearchy_Chunk : + +"PLACHIDT" Placed_Hierarchy_Data_Chunk +"PLHISEQU" Placed_Hierarchy_Sequence_Chunk +"INDSOUND" Indexed_Sound_Chunk +"AVPSTRAT" AVP_Strategy_Chunk +*/ + + + +Placed_Hierarchy_Chunk::Placed_Hierarchy_Chunk(Chunk_With_Children* parent,const char* _name,int _hierarchy_index,ChunkVectorInt& _location,ChunkQuat& _orientation) +:Chunk_With_Children(parent,"PLACHIER") +{ + new Placed_Hierarchy_Data_Chunk(this,_name,_hierarchy_index,_location,_orientation); +} + +/////////////////////////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("PLACHIDT",Placed_Hierarchy_Data_Chunk) + +Placed_Hierarchy_Data_Chunk::Placed_Hierarchy_Data_Chunk(Chunk_With_Children* parent,const char* data, const size_t) +:Chunk(parent,"PLACHIDT") +{ + int length=strlen(data); + + if(length) + { + name=new char[length+1]; + strcpy(name,data); + } + else + { + name=0; + } + data+=(length+4)&~3; + + hierarchy_index=*(int*)data; + data+=4; + + location=*(ChunkVectorInt*)data; + data+=sizeof(ChunkVectorInt); + + orientation=*(ChunkQuat*)data; + data+=sizeof(ChunkQuat); + + id=*(ObjectID*)data; + data+=sizeof(ObjectID); + + num_extra_data=*(int*) data; + data+=4; + + if(num_extra_data) + { + extra_data=new int[num_extra_data]; + for(int i=0;i 7*ONE_FIXED) + { + DrawGraphicWithFadingLevel(&Starfield_Backdrop,timeRemaining-7*ONE_FIXED); + } + else if (timeRemaining > 6*ONE_FIXED) + { + BLTMenuToScreen(&Starfield_Backdrop); + } + else if (timeRemaining > 5*ONE_FIXED) + { + BLTMenuToScreen(&Starfield_Backdrop); + DrawGraphicWithAlphaChannel(&Presents,timeRemaining-5*ONE_FIXED); + } + else if (timeRemaining > 4*ONE_FIXED) + { + BLTMenuToScreen(&Starfield_Backdrop); + DrawGraphicWithAlphaChannel(&Presents,0); + } + else if (timeRemaining > 3*ONE_FIXED) + { + BLTMenuToScreen(&Starfield_Backdrop); + DrawGraphicWithAlphaChannel(&Presents,4*ONE_FIXED-timeRemaining); + } + else + { + BLTMenuToScreen(&Starfield_Backdrop); + } + + FlipBuffers(); + } + DirectReadKeyboard(); + FrameCounterHandler(); + timeRemaining-=NormalFrameTime; + } + while(timeRemaining>0 && !GotAnyKey); +} + +void Show_ARebellionGame(void) +{ + int timeRemaining = 7*ONE_FIXED; + do + { + { + BLTMenuToScreen(&Starfield_Backdrop); + PlayMenuMusic(); + + if (timeRemaining > 13*ONE_FIXED/2) + { + DrawGraphicWithAlphaChannel(&RebellionLogo,timeRemaining*2-13*ONE_FIXED); + } + else if (timeRemaining > 5*ONE_FIXED) + { + DrawGraphicWithAlphaChannel(&RebellionLogo,0); + } + else if (timeRemaining > 3*ONE_FIXED) + { + DrawGraphicWithAlphaChannel(&RebellionLogo, ONE_FIXED - (timeRemaining-3*ONE_FIXED)/2); + } + + FlipBuffers(); + } + DirectReadKeyboard(); + FrameCounterHandler(); + timeRemaining-=NormalFrameTime; + } + while(timeRemaining>ONE_FIXED/4 && !GotAnyKey); +} +void Show_AvPLogo(void) +{ + int timeRemaining = 5*ONE_FIXED; + do + { + { + BLTMenuToScreen(&Starfield_Backdrop); + PlayMenuMusic(); + + if (timeRemaining > 9*ONE_FIXED/2) + { + DrawGraphicWithAlphaChannel(&AvPLogo,timeRemaining*2-9*ONE_FIXED); + } + else if (timeRemaining > 4*ONE_FIXED) + { + DrawGraphicWithAlphaChannel(&AvPLogo,0); + } + else + { + DrawGraphicWithAlphaChannel(&AvPLogo, ONE_FIXED - timeRemaining/4); + } + + FlipBuffers(); + } + DirectReadKeyboard(); + FrameCounterHandler(); + timeRemaining-=NormalFrameTime; + } + while(timeRemaining>0 && !GotAnyKey); +} + + + + +void DrawGraphicWithAlphaChannel(MENUGRAPHIC *image, int alpha) +{ + DDSURFACEDESC ddsdback, ddsdimage; + + unsigned short *srcPtr; + unsigned short *destPtr; + + long destPitch; + + memset(&ddsdback, 0, sizeof(ddsdback)); + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdback.dwSize = sizeof(ddsdback); + ddsdimage.dwSize = sizeof(ddsdimage); + + alpha = ONE_FIXED-alpha; + + + /* lock the image */ + while ((image->image_ptr)->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + /* lock the backbuffer */ + while (lpDDSBack->Lock(NULL, &ddsdback, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + destPtr = (unsigned short *)ddsdimage.lpSurface; + destPitch = ddsdimage.lPitch - ddsdimage.dwWidth; + + // okay, now we have the surfaces, we can copy from one to the other, + // darkening pixels as we go + { + int x,y; + + for (y=(ScreenDescriptorBlock.SDB_Height - image->height)/2; y<(ScreenDescriptorBlock.SDB_Height - image->height)/2+image->height; y++) + { + srcPtr = (unsigned short *)ddsdback.lpSurface + (ScreenDescriptorBlock.SDB_Width - image->width)/2; + srcPtr += y*ddsdback.lPitch/2; + + for (x=0; xwidth; x++) + { + + if (*destPtr) + { + unsigned int srcR,srcG,srcB; + unsigned int destR,destG,destB; + + srcR = (int)(*srcPtr) & DisplayPixelFormat.dwRBitMask; + srcG = (int)(*srcPtr) & DisplayPixelFormat.dwGBitMask; + srcB = (int)(*srcPtr) & DisplayPixelFormat.dwBBitMask; + + destR = (int)(*destPtr) & DisplayPixelFormat.dwRBitMask; + destG = (int)(*destPtr) & DisplayPixelFormat.dwGBitMask; + destB = (int)(*destPtr) & DisplayPixelFormat.dwBBitMask; + #if 0 + srcR = destR + MUL_FIXED(alpha,srcR - destR); + if (srcR>DisplayPixelFormat.dwRBitMask) srcR = DisplayPixelFormat.dwRBitMask; + else srcR &= DisplayPixelFormat.dwRBitMask; + + srcG = destG + MUL_FIXED(alpha,srcG - destG); + if (srcG>DisplayPixelFormat.dwGBitMask) srcG = DisplayPixelFormat.dwGBitMask; + else srcG &= DisplayPixelFormat.dwGBitMask; + + srcB = destB + MUL_FIXED(alpha,srcB - destB); + if (srcB>DisplayPixelFormat.dwBBitMask) srcB = DisplayPixelFormat.dwBBitMask; + else srcB &= DisplayPixelFormat.dwBBitMask; + #else + srcR += MUL_FIXED(alpha,destR); + if (srcR>DisplayPixelFormat.dwRBitMask) srcR = DisplayPixelFormat.dwRBitMask; + else srcR &= DisplayPixelFormat.dwRBitMask; + + srcG += MUL_FIXED(alpha,destG); + if (srcG>DisplayPixelFormat.dwGBitMask) srcG = DisplayPixelFormat.dwGBitMask; + else srcG &= DisplayPixelFormat.dwGBitMask; + + srcB += MUL_FIXED(alpha,destB); + if (srcB>DisplayPixelFormat.dwBBitMask) srcB = DisplayPixelFormat.dwBBitMask; + else srcB &= DisplayPixelFormat.dwBBitMask; + #endif + *srcPtr = (short)(srcR|srcG|srcB); + } + srcPtr++; + destPtr++; + } + destPtr += (ddsdimage.lPitch/2) - image->width; + } + } + + lpDDSBack->Unlock((LPVOID)ddsdback.lpSurface); + (image->image_ptr)->Unlock((LPVOID)ddsdimage.lpSurface); + +} +void DrawGraphicWithFadingLevel(MENUGRAPHIC *image, int alpha) +{ + DDSURFACEDESC ddsdback, ddsdimage; + + unsigned short *srcPtr; + unsigned short *destPtr; + + long destPitch; + + memset(&ddsdback, 0, sizeof(ddsdback)); + memset(&ddsdimage, 0, sizeof(ddsdimage)); + ddsdback.dwSize = sizeof(ddsdback); + ddsdimage.dwSize = sizeof(ddsdimage); + + alpha = ONE_FIXED-alpha; + + + /* lock the image */ + while ((image->image_ptr)->Lock(NULL, &ddsdimage, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + /* lock the backbuffer */ + while (lpDDSBack->Lock(NULL, &ddsdback, DDLOCK_WAIT, NULL) == DDERR_WASSTILLDRAWING); + + destPtr = (unsigned short *)ddsdimage.lpSurface; + destPitch = ddsdimage.lPitch - ddsdimage.dwWidth; + + // okay, now we have the surfaces, we can copy from one to the other, + // darkening pixels as we go + { + int x,y; + + for (y=(ScreenDescriptorBlock.SDB_Height - image->height)/2; y<(ScreenDescriptorBlock.SDB_Height - image->height)/2+image->height; y++) + { + srcPtr = (unsigned short *)ddsdback.lpSurface + (ScreenDescriptorBlock.SDB_Width - image->width)/2; + srcPtr += y*ddsdback.lPitch/2; + + for (x=0; xwidth; x++) + { + + if (*destPtr) + { + unsigned int srcR,srcG,srcB; + + srcR = (int)(*destPtr) & DisplayPixelFormat.dwRBitMask; + srcG = (int)(*destPtr) & DisplayPixelFormat.dwGBitMask; + srcB = (int)(*destPtr) & DisplayPixelFormat.dwBBitMask; + + srcR = MUL_FIXED(alpha,srcR); + srcR &= DisplayPixelFormat.dwRBitMask; + + srcG = MUL_FIXED(alpha,srcG); + srcG &= DisplayPixelFormat.dwGBitMask; + + srcB = MUL_FIXED(alpha,srcB); + srcB &= DisplayPixelFormat.dwBBitMask; + + *srcPtr = (short)(srcR|srcG|srcB); + } + else + { + *srcPtr = 0; + } + srcPtr++; + destPtr++; + } + destPtr += (ddsdimage.lPitch/2) - image->width; + } + } + + lpDDSBack->Unlock((LPVOID)ddsdback.lpSurface); + (image->image_ptr)->Unlock((LPVOID)ddsdimage.lpSurface); + +} +#endif \ No newline at end of file diff --git a/3dc/avp/win95/intro.hpp b/3dc/avp/win95/intro.hpp new file mode 100644 index 0000000..e795290 --- /dev/null +++ b/3dc/avp/win95/intro.hpp @@ -0,0 +1,10 @@ +extern void PlayIntroSequence(void); + +#ifdef __cplusplus +extern "C" +{ +#endif + extern void WeWantAnIntro(void); +#ifdef __cplusplus +}; +#endif diff --git a/3dc/avp/win95/iofocus.cpp b/3dc/avp/win95/iofocus.cpp new file mode 100644 index 0000000..e51aca2 --- /dev/null +++ b/3dc/avp/win95/iofocus.cpp @@ -0,0 +1,76 @@ +/******************************************************************* + * + * DESCRIPTION: iofocus.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 21/11/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "iofocus.h" +#include "gadget.h" +#include "avp_menus.h" +#include "psnd.h" +extern "C" +{ + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ +extern int InGameMenusAreRunning(void); + +/* Imported data ***************************************************/ + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + static OurBool iofocus_AcceptTyping = No; + +/* Exported function definitions ***********************************/ +OurBool IOFOCUS_AcceptControls(void) +{ + return !iofocus_AcceptTyping; +} + +OurBool IOFOCUS_AcceptTyping(void) +{ + return iofocus_AcceptTyping; +} + +void IOFOCUS_Toggle(void) +{ + #if CONSOLE_DEBUGGING_COMMANDS_ACTIVATED||!(PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO) + if(InGameMenusAreRunning()) return;; + + iofocus_AcceptTyping = !iofocus_AcceptTyping; + if (iofocus_AcceptTyping) + { + Sound_Play(SID_CONSOLE_ACTIVATES,NULL); + } + else + { + Sound_Play(SID_CONSOLE_DEACTIVATES,NULL); + RemoveTheConsolePlease(); + } + #endif +} + + +/* Internal function definitions ***********************************/ + +}; \ No newline at end of file diff --git a/3dc/avp/win95/iofocus.h b/3dc/avp/win95/iofocus.h new file mode 100644 index 0000000..2ffb1e8 --- /dev/null +++ b/3dc/avp/win95/iofocus.h @@ -0,0 +1,56 @@ +/* + + iofocus.h + + Created 21/11/97 by DHM: is input focus set to normal controls, + or to typing? +*/ + +#ifndef _iofocus +#define _iofocus 1 + + #ifndef _ourbool + #include "ourbool.h" + #endif + + #ifndef _gadget + #include "gadget.h" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + #if UseGadgets + extern OurBool IOFOCUS_AcceptControls(void); + extern OurBool IOFOCUS_AcceptTyping(void); + + extern void IOFOCUS_Toggle(void); + #else + /* Otherwise: the functions collapse to macros: */ + #define IOFOCUS_AcceptControls() (1) + #define IOFOCUS_AcceptTyping() (0) + + #define IOFOCUS_Toggle() ((void) 0) + #endif /* UseGadgets */ + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/win95/jsndsup.cpp b/3dc/avp/win95/jsndsup.cpp new file mode 100644 index 0000000..1268818 --- /dev/null +++ b/3dc/avp/win95/jsndsup.cpp @@ -0,0 +1,184 @@ +#include "3dc.h" +#include "inline.h" +#include "module.h" + +#define UseLocalAssert Yes +#include "ourasert.h" +#include "psndplat.h" + +#include "list_tem.hpp" +#include "jsndsup.h" + +extern "C" +{ + extern LPDIRECTSOUND DSObject; + extern int SoundSwitchedOn; + // Pat sets this up +}; + +List loaded_sounds; + +void LoseSound (LOADED_SOUND const * ls) +{ + LOADED_SOUND ** ucls_p = (LOADED_SOUND **) &ls; + LOADED_SOUND * ucls = *ucls_p; + + if (loaded_sounds.contains (ucls)) + { + LOADED_SOUND * ls_in_list = loaded_sounds.similar_entry (ucls); + ls_in_list->num_attached --; + + if (ls_in_list->permanent == 1) + { + if (ls_in_list->num_attached <= 0) + { + loaded_sounds.delete_entry (ls_in_list); + DeallocateMem (ls_in_list->wavname); + DeallocateMem (ls_in_list); + } + + return; + } + + if (ls_in_list->num_attached <= 0) + { + PlatEndGameSound ((SOUNDINDEX)ls_in_list->sound_num); + loaded_sounds.delete_entry (ls_in_list); + DeallocateMem (ls_in_list->wavname); + DeallocateMem (ls_in_list); + } + } + else + { + GLOBALASSERT (0); + } +} + +void LoseAllNonCommonSounds() +{ + LOADED_SOUND* ls; + while(loaded_sounds.size()) + { + ls=loaded_sounds.first_entry(); + loaded_sounds.delete_first_entry(); + + if(!ls->permanent) + { + PlatEndGameSound ((SOUNDINDEX)ls->sound_num); + } + + DeallocateMem (ls->wavname); + DeallocateMem (ls); + } +} + +static int find_empty_game_sound() +{ + if(!SoundSwitchedOn) return (-1); + + for (int i=SID_STARTOF_LOADSLOTS; i<=SID_ENDOF_LOADSLOTS; i++) + { + if (GameSounds[i].loaded == 0) + { + return(i); + } + } + return(-1); + +} + +static int find_permanent_game_sound(char * wavname) +{ + if(!SoundSwitchedOn) return (-1); + + for (int i=0; i lsi(&loaded_sounds); !lsi.done(); lsi.next()) + { + if (!_stricmp (lsi()->wavname, wavname)) + { + lsi()->num_attached ++; + return(lsi()); + } + } + + LOADED_SOUND * ls = 0; + + int perm_snum = find_permanent_game_sound (wavname); + + if (perm_snum != -1) + { + ls = (LOADED_SOUND *) AllocateMem(sizeof (LOADED_SOUND)); + + ls->sound_num = perm_snum; + ls->wavname = (char *) AllocateMem(sizeof (char) * (strlen (wavname)+1)); + strcpy (ls->wavname, wavname); + ls->num_attached = 1; + ls->permanent = 1; + loaded_sounds.add_entry (ls); + return (ls); + } + + // not loaded, so try and load it + + int soundNum = find_empty_game_sound(); + if (soundNum == -1) + { + GLOBALASSERT(0=="Run out of sound slots"); + return(0); + } + + int ok = FindAndLoadWavFile (soundNum, (char *)fname); + + + if (ok) + { + GameSounds[soundNum].loaded = 1; + GameSounds[soundNum].activeInstances = 0;; + GameSounds[soundNum].volume = VOLUME_DEFAULT; + GameSounds[soundNum].pitch = 0; + InitialiseBaseFrequency((SOUNDINDEX)soundNum); + + ls = (LOADED_SOUND *) AllocateMem(sizeof (LOADED_SOUND)); + + ls->sound_num = soundNum; + ls->wavname = (char *)AllocateMem(sizeof (char) * (strlen (wavname)+1)); + strcpy (ls->wavname, wavname); + ls->num_attached = 1; + ls->permanent = 0; + loaded_sounds.add_entry (ls); + } + + return(ls); + +} diff --git a/3dc/avp/win95/jsndsup.h b/3dc/avp/win95/jsndsup.h new file mode 100644 index 0000000..73e4a2a --- /dev/null +++ b/3dc/avp/win95/jsndsup.h @@ -0,0 +1,36 @@ +#ifndef _jsndsup_h +#define _jsndsup_h 1 + +#include "3dc.h" +#include "inline.h" +#include "module.h" + +#ifdef __cplusplus + + extern "C" { + +#endif + +typedef struct loaded_sound +{ + int sound_num; + + char * wavname; + int num_attached; + + unsigned long permanent :1; + +} LOADED_SOUND; + + +void LoseSound (LOADED_SOUND const * ls); +LOADED_SOUND const * GetSound (char const * fname); + +#ifdef __cplusplus + + }; // end of extern "c" + +#endif + + +#endif \ No newline at end of file diff --git a/3dc/avp/win95/menugfx.h b/3dc/avp/win95/menugfx.h new file mode 100644 index 0000000..b81ab0b --- /dev/null +++ b/3dc/avp/win95/menugfx.h @@ -0,0 +1,78 @@ +#ifndef _included_menugfx_h_ +#define _included_menugfx_h_ + +#include "aw.h" +#ifdef __cplusplus +extern "C" { +#endif +#include "langenum.h" +// structures used for the menu code + +typedef struct menugraphic { + char *filename; + int image_number; + LPDIRECTDRAWSURFACE image_ptr; + AW_BACKUPTEXTUREHANDLE hBackup; + short destx; + short desty; + short width; + short height; + +} MENUGRAPHIC; + +/* JH 12/5/97 these were static in menuplat.cpp - but they're quite useful functions */ +extern void LoadMenuGraphic(MENUGRAPHIC* menugraphptr); +extern void BLTMenuToScreen(MENUGRAPHIC* menuptr); +extern void ReleaseMenuGraphic(MENUGRAPHIC* mptr); + +typedef struct menu_graphic_item{ + int id; + MENUGRAPHIC On; + MENUGRAPHIC Off; +} MENU_GRAPHIC_ITEM; + + + +/* KJL 15:23:39 05/03/97 - new menu_text_item, which +looks as much like the menu_font_item as possible +while enabling me to add language internationalization */ +typedef struct menu_text_item +{ + int id; + enum TEXTSTRING_ID StringID; + char *SecondStringPtr; + int X; + int Y; +} MENU_TEXT_ITEM; + + + +// OVERALL menus - this describes one menu screen + +typedef struct avp_menu +{ + MENUGRAPHIC *backdrop; + MENU_GRAPHIC_ITEM *menugitems; + MENU_TEXT_ITEM *menufitems; + int previous_selection; + int default_selection; + +} AVP_MENU; + + +#define BASEX 112 +#define BASEY 43 + + +extern AVP_MENU *Current_Menu; +extern void ProcessGraphicForLoading(AVP_MENU *menu_to_load); +extern void ProcessGraphicForUnloading(AVP_MENU *menu_to_load); + +extern void PlatformSpecificEnteringDatabase(void); +extern void PlatformSpecificExitingDatabase(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ! _included_menugfx_h_ */ diff --git a/3dc/avp/win95/modcmds.cpp b/3dc/avp/win95/modcmds.cpp new file mode 100644 index 0000000..2e29d09 --- /dev/null +++ b/3dc/avp/win95/modcmds.cpp @@ -0,0 +1,364 @@ +/******************************************************************* + * + * DESCRIPTION: modcmds.cpp + * + * AUTHOR: David Malcolm + * + * HISTORY: Created 27/11/97 + * + *******************************************************************/ + +/* Includes ********************************************************/ +#include "3dc.h" +#include "gadget.h" + + #if UseGadgets + #include "module.h" + #include "modcmds.hpp" + #include "stratdef.h" + #include "dynblock.h" + #endif + + #define UseLocalAssert Yes + #include "ourasert.h" + +/* Version settings ************************************************/ + +/* Constants *******************************************************/ + +/* Macros **********************************************************/ + +/* Imported function prototypes ************************************/ + +/* Imported data ***************************************************/ +#ifdef __cplusplus + extern "C" + { +#endif + #if UseGadgets + extern SCENEMODULE **Global_ModulePtr; + extern DISPLAYBLOCK* Player; + #endif + + #if 0 + extern OurBool DaveDebugOn; + extern FDIEXTENSIONTAG FDIET_Dummy; + extern IFEXTENSIONTAG IFET_Dummy; + extern FDIQUAD FDIQuad_WholeScreen; + extern FDIPOS FDIPos_Origin; + extern FDIPOS FDIPos_ScreenCentre; + extern IFOBJECTLOCATION IFObjLoc_Origin; + extern UncompressedGlobalPlotAtomID UGPAID_StandardNull; + extern IFCOLOUR IFColour_Dummy; + extern IFVECTOR IFVec_Zero; + #endif +#ifdef __cplusplus + }; +#endif + + + +/* Exported globals ************************************************/ + +/* Internal type definitions ***************************************/ + +/* Internal function prototypes ************************************/ + +/* Internal globals ************************************************/ + +/* Exported function definitions ***********************************/ + +#if UseGadgets +// namespace ModuleCommands +void ModuleCommands :: ListModules(void) +{ + + char Msg[256]; + + if + ( + Global_ModulePtr + ) + { + SCENEMODULE* pSceneModule = Global_ModulePtr[0]; + + if ( pSceneModule ) + { + MODULE** ppModule_I = pSceneModule -> sm_marray; + + if ( ppModule_I ) + { + GADGET_NewOnScreenMessage( "MODULE LISTING (CASE INSENSITIVE):" ); + + int Index=0; + + // Iterate through NULL-terminated list of MODULE*s + while ( *ppModule_I ) + { + MODULE* pModule = *ppModule_I; + + // Diagnostic on pModule: + { + if + ( + pModule -> name + ) + { + // Get upper-case module name: + char TempName[256]; + char* pCh_Dst = &TempName[0]; + char* pCh_Src = pModule -> name; + int CharCount = 0; + while ( (*pCh_Src) && (CharCount < 255) ) + { + *(pCh_Dst++) = toupper( *(pCh_Src++)); + CharCount++; + } + + *pCh_Dst = 0; + + sprintf + ( + Msg, + "MODULE:%3i \"%s\"", + Index, + TempName + ); + } + else + { + sprintf + ( + Msg, + "MODULE:%3i NULL NAME", + Index, + pModule -> name + ); + } + + + GADGET_NewOnScreenMessage( Msg ); + + } + + // Advance to next MODULE* + (ppModule_I++); + Index++; + + } + + sprintf + ( + Msg, + "END OF MODULE LISTING (%i MODULES)", + ModuleArraySize + ); + GADGET_NewOnScreenMessage( Msg ); + + } + else + { + GADGET_NewOnScreenMessage( "CANNOT LIST MODULES; SM_MARRAY IS NULL" ); + } + } + else + { + GADGET_NewOnScreenMessage( "CANNOT LIST MODULES; GLOBALMODULEPTR[0] IS NULL" ); + } + } + else + { + GADGET_NewOnScreenMessage( "CANNOT LIST MODULES; GLOBALMODULEPTR IS NULL" ); + } +} + +void ModuleCommands :: TryToTeleport(char* UpperCasePotentialModuleName) +{ + // the test name is in upper case (since its been typed in) + // we must test against the module names without actually + // converting them to upper case + + // If we find a match we try to teleport the player... + + /* PRECONDITION */ + { + GLOBALASSERT( UpperCasePotentialModuleName ); + } + + /* CODE */ + { + char Msg[256]; + + { + sprintf + ( + Msg, + "TELEPORT REQUEST TO MODULE \"%s\"", + UpperCasePotentialModuleName + ); + + GADGET_NewOnScreenMessage( Msg ); + } + + MODULE* pModule_Targ = FindModule( UpperCasePotentialModuleName ); + + if ( !pModule_Targ ) + { + GADGET_NewOnScreenMessage( "UNRECOGNISED MODULE" ); + return; + } + + GLOBALASSERT( pModule_Targ ); + + #if 1 + GADGET_NewOnScreenMessage( "(FOUND THE MODULE)" ); + #endif + + TeleportPlayerToModule + ( + pModule_Targ + ); + } +} + +MODULE* ModuleCommands :: FindModule(char* UpperCasePotentialModuleName) +{ + // allowed to return NULL if no match + GLOBALASSERT( UpperCasePotentialModuleName ); + + MODULE* pModule_Found = NULL; + + if + ( + Global_ModulePtr + ) + { + SCENEMODULE* pSceneModule = Global_ModulePtr[0]; + + if ( pSceneModule ) + { + MODULE** ppModule_I = pSceneModule -> sm_marray; + + if ( ppModule_I ) + { + int Index=0; + + // Iterate through NULL-terminated list of MODULE*s + while ( *ppModule_I ) + { + MODULE* pModule = *ppModule_I; + + // Diagnostic on pModule: + { + if + ( + pModule -> name + ) + { + //use a case insensitive comparison instead of converting + //to upper case + #if 0 + // Get upper-case module name: + char TempName[256]; + char* pCh_Dst = &TempName[0]; + char* pCh_Src = pModule -> name; + int CharCount = 0; + while ( (*pCh_Src) && (CharCount < 255) ) + { + *(pCh_Dst++) = toupper( *(pCh_Src++)); + CharCount++; + } + + *pCh_Dst = 0; + #endif + + #if 1 + if + ( + 0 == _stricmp + ( + pModule -> name, + UpperCasePotentialModuleName + ) + ) + { + // Got a match: + pModule_Found = pModule; + } + #else + sprintf + ( + Msg, + "MODULE:%3i \"%s\"", + Index, + TempName + ); + #endif + } + } + + // Advance to next MODULE* + (ppModule_I++); + Index++; + + } + } + else + { + GADGET_NewOnScreenMessage( "CANNOT FIND MODULES; SM_MARRAY IS NULL" ); + } + } + else + { + GADGET_NewOnScreenMessage( "CANNOT FIND MODULES; GLOBALMODULEPTR[0] IS NULL" ); + } + } + else + { + GADGET_NewOnScreenMessage( "CANNOT FIND MODULES; GLOBALMODULEPTR IS NULL" ); + } + + return pModule_Found; +} + +void ModuleCommands :: TeleportPlayerToModule(MODULE* pModule_Dst) +{ + /* PRECONDITION */ + { + GLOBALASSERT( pModule_Dst ); + } + + /* CODE */ + { + if (Player ) + { + if ( Player -> ObStrategyBlock ) + { + // Code based around fn EmergencyPlaceObjectInModule() in PVISIBLE.C: + + if ( Player -> ObStrategyBlock -> DynPtr ) + { + DYNAMICSBLOCK* dynPtr = Player -> ObStrategyBlock -> DynPtr; + + dynPtr -> Position.vx = pModule_Dst -> m_world.vx; + dynPtr -> Position.vy = pModule_Dst -> m_world.vy; + dynPtr -> Position.vz = pModule_Dst -> m_world.vz; + dynPtr->LinImpulse.vx = 0; + dynPtr->LinImpulse.vy = 0; + dynPtr->LinImpulse.vz = 0; + dynPtr -> PrevPosition = dynPtr -> Position; + + } + + /* finally, update the sb's module */ + Player -> ObStrategyBlock -> containingModule = pModule_Dst; + } + } + + } +} +#endif // UseGadgets + + + +/* Internal function definitions ***********************************/ diff --git a/3dc/avp/win95/modcmds.hpp b/3dc/avp/win95/modcmds.hpp new file mode 100644 index 0000000..3e1ddf6 --- /dev/null +++ b/3dc/avp/win95/modcmds.hpp @@ -0,0 +1,50 @@ +/* + + modcmds.hpp + +*/ + +#ifndef _modcmds +#define _modcmds 1 + + #ifndef MODULE_INCLUDED + #include "module.h" + #endif + +#ifdef __cplusplus + extern "C" { +#endif + +/* Version settings *****************************************************/ + +/* Constants ***********************************************************/ + +/* Macros ***************************************************************/ + +/* Type definitions *****************************************************/ + +/* Exported globals *****************************************************/ + +/* Function prototypes **************************************************/ + namespace ModuleCommands + { + void ListModules(void); + + void TryToTeleport(char* UpperCasePotentialModuleName); + + MODULE* FindModule(char* UpperCasePotentialModuleName); + // allowed to return NULL if no match + + void TeleportPlayerToModule(MODULE* pModule_Dst); + }; + + + +/* End of the header ****************************************************/ + + +#ifdef __cplusplus + }; +#endif + +#endif diff --git a/3dc/avp/win95/progress_bar.cpp b/3dc/avp/win95/progress_bar.cpp new file mode 100644 index 0000000..85a0a6f --- /dev/null +++ b/3dc/avp/win95/progress_bar.cpp @@ -0,0 +1,341 @@ +#include "3dc.h" +#include "module.h" +#include "platform.h" +#include "kshape.h" +#include "progress_bar.h" +#include "chnktexi.h" +#include "awtexld.h" +#include "ffstdio.h" +#include "inline.h" +#include "gamedef.h" +#include "psnd.h" +extern "C" +{ +#include "language.h" +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; +extern LPDIRECTDRAWSURFACE lpDDSBack; // DirectDraw back surface +extern int DebouncedGotAnyKey; + +extern void MinimalNetCollectMessages(void); +extern void NetSendMessages(void); +extern void RenderGrabbedScreen(void); + +extern void ThisFramesRenderingHasBegun(void); +extern void ThisFramesRenderingHasFinished(void); + +extern int AAFontImageNumber; +extern int FadingGameInAfterLoading; +extern void RenderBriefingText(int centreY, int brightness); +}; + +static int CurrentPosition=0; +static int BarLeft; +static int BarRight; +static int BarTop; +static int BarBottom; + +static const char* Loading_Image_Name="Menus\\Loading.rim"; +static const char* Loading_Bar_Empty_Image_Name="Menus\\Loadingbar_empty.rim"; +static const char* Loading_Bar_Full_Image_Name="Menus\\Loadingbar_full.rim"; + +DDSurface *LoadingBarEmpty; +DDSurface *LoadingBarFull; +RECT LoadingBarEmpty_DestRect; +RECT LoadingBarEmpty_SrcRect; +RECT LoadingBarFull_DestRect; +RECT LoadingBarFull_SrcRect; + + + +void Start_Progress_Bar() +{ + AAFontImageNumber = CL_LoadImageOnce("Common\\aa_font.RIM",LIO_D3DTEXTURE|LIO_RELATIVEPATH|LIO_RESTORABLE); + + /* load other graphics */ + { + char buffer[100]; + CL_GetImageFileName(buffer, 100,Loading_Bar_Empty_Image_Name, LIO_RELATIVEPATH); + + //see if graphic can be found in fast file + unsigned int fastFileLength; + void const * pFastFileData = ffreadbuf(buffer,&fastFileLength); + + if(pFastFileData) + { + //load from fast file + LoadingBarEmpty = AwCreateSurface + ( + "pxf", + pFastFileData, + fastFileLength, + 0 + ); + } + else + { + //load graphic from rim file + LoadingBarEmpty = AwCreateSurface + ( + "sf", + buffer, + 0 + ); + } + } + { + char buffer[100]; + CL_GetImageFileName(buffer, 100,Loading_Bar_Full_Image_Name, LIO_RELATIVEPATH); + + //see if graphic can be found in fast file + unsigned int fastFileLength; + void const * pFastFileData = ffreadbuf(buffer,&fastFileLength); + + if(pFastFileData) + { + //load from fast file + LoadingBarFull = AwCreateSurface + ( + "pxf", + pFastFileData, + fastFileLength, + 0 + ); + } + else + { + //load graphic from rim file + LoadingBarFull = AwCreateSurface + ( + "sf", + buffer, + 0 + ); + } + } + DDSurface* image=0; + + //set progress bar dimensions + BarLeft=ScreenDescriptorBlock.SDB_Width/6; + BarRight=(ScreenDescriptorBlock.SDB_Width*5)/6; + BarTop=(ScreenDescriptorBlock.SDB_Height*19)/22; + BarBottom=(ScreenDescriptorBlock.SDB_Height*21)/22; + + //load background image for bar + char buffer[100]; + CL_GetImageFileName(buffer, 100,Loading_Image_Name, LIO_RELATIVEPATH); + + + //see if graphic can be found in fast file + unsigned int fastFileLength; + void const * pFastFileData = ffreadbuf(buffer,&fastFileLength); + + if(pFastFileData) + { + //load from fast file + image = AwCreateSurface + ( + "pxf", + pFastFileData, + fastFileLength, + 0 + ); + } + else + { + //load graphic from rim file + image = AwCreateSurface + ( + "sf", + buffer, + 0 + ); + } + #if 0 + if(image) + { + //draw background image + lpDDSBack->Blt(0,image,0,DDBLT_WAIT,0); + } + else + { + //failed to load background graphic , make do with black background + ColourFillBackBuffer(0); + } + #endif + // RenderGrabbedScreen(); + //draw initial progress bar + + LoadingBarEmpty_SrcRect.left=0; + LoadingBarEmpty_SrcRect.right=639; + LoadingBarEmpty_SrcRect.top=0; + LoadingBarEmpty_SrcRect.bottom=39; + LoadingBarEmpty_DestRect.left=0; + LoadingBarEmpty_DestRect.right=ScreenDescriptorBlock.SDB_Width-1; + LoadingBarEmpty_DestRect.top=(ScreenDescriptorBlock.SDB_Height *11)/12; + LoadingBarEmpty_DestRect.bottom=ScreenDescriptorBlock.SDB_Height-1; + + + for (int i=0; i<2; i++) + { + ColourFillBackBuffer(0); + if (LoadingBarEmpty) lpDDSBack->Blt(&LoadingBarEmpty_DestRect,LoadingBarEmpty,&LoadingBarEmpty_SrcRect,DDBLT_WAIT,0); + + #if SOFTWARE_RENDERER + FlushSoftwareZBuffer(); + #else + FlushD3DZBuffer(); + #endif + + ThisFramesRenderingHasBegun(); + + RenderBriefingText(ScreenDescriptorBlock.SDB_Height/2, ONE_FIXED); + + ThisFramesRenderingHasFinished(); + + FlipBuffers(); + } + + if(image) + { + ReleaseDDSurface(image); + } + if (LoadingBarEmpty) + { + ReleaseDDSurface(LoadingBarEmpty); + } + CurrentPosition=0; + + +} + +void Set_Progress_Bar_Position(int pos) +{ +// int NewPosition=((BarRight-BarLeft)*pos)/PBAR_LENGTH; + int NewPosition = DIV_FIXED(pos,PBAR_LENGTH); + if(NewPosition>CurrentPosition) + { + CurrentPosition=NewPosition; +// ColourFillBackBufferQuad(GetSingleColourForPrimary(0xff0000),BarLeft,BarTop,BarLeft+CurrentPosition,BarBottom); + LoadingBarFull_SrcRect.left=0; + LoadingBarFull_SrcRect.right=MUL_FIXED(639,NewPosition); + LoadingBarFull_SrcRect.top=0; + LoadingBarFull_SrcRect.bottom=39; + LoadingBarFull_DestRect.left=0; + LoadingBarFull_DestRect.right=MUL_FIXED(ScreenDescriptorBlock.SDB_Width-1,NewPosition); + LoadingBarFull_DestRect.top=(ScreenDescriptorBlock.SDB_Height *11)/12; + LoadingBarFull_DestRect.bottom=ScreenDescriptorBlock.SDB_Height-1; + + if (LoadingBarFull) lpDDSBack->Blt(&LoadingBarFull_DestRect,LoadingBarFull,&LoadingBarFull_SrcRect,DDBLT_WAIT,0); + FlipBuffers(); + + /* + If this is a network game , then check the received network messages from + time to time (~every second). + Has nothing to do with the progress bar , but this is a convenient place to + do the check. + */ + + if(AvP.Network != I_No_Network) + { + static int LastSendTime; + int time=GetTickCount(); + if(time-LastSendTime>1000 || timeBlt(&LoadingBarFull_DestRect,LoadingBarFull,&LoadingBarFull_SrcRect,DDBLT_WAIT,0); + f-=NormalFrameTime; + if (f<0) f=0; + } + { + extern void ThisFramesRenderingHasBegun(void); + ThisFramesRenderingHasBegun(); + } + RenderStringCentred(GetTextString(TEXTSTRING_INGAME_PRESSANYKEYTOCONTINUE), ScreenDescriptorBlock.SDB_Width/2, (ScreenDescriptorBlock.SDB_Height*23)/24-9, 0xffffffff); + { + /* after this call, no more graphics can be drawn until the next frame */ + extern void ThisFramesRenderingHasFinished(void); + ThisFramesRenderingHasFinished(); + } + + FlipBuffers(); + FrameCounterHandler(); + + + /* If in a network game then we may as well check the network messages while waiting*/ + if(AvP.Network != I_No_Network) + { + MinimalNetCollectMessages(); + //send messages , mainly needed so that the host will send the game description + //allowing people to join while the host is loading + NetSendMessages(); + + } + + } + while(!DebouncedGotAnyKey); + + FadingGameInAfterLoading=ONE_FIXED; + + + if (LoadingBarFull) + { + ReleaseDDSurface(LoadingBarFull); + } +} + + +}; \ No newline at end of file diff --git a/3dc/avp/win95/progress_bar.h b/3dc/avp/win95/progress_bar.h new file mode 100644 index 0000000..d8c4c82 --- /dev/null +++ b/3dc/avp/win95/progress_bar.h @@ -0,0 +1,28 @@ + +#ifndef _progress_bar_h +#define _progress_bar_h + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define PBAR_HUD_START 0 +#define PBAR_LEVEL_START 1000 +#define PBAR_NPC_START 3000 +#define PBAR_LENGTH 5000 + +#define PBAR_HUD_INTERVAL (PBAR_LEVEL_START) +#define PBAR_LEVEL_INTERVAL (PBAR_NPC_START-PBAR_LEVEL_START) +#define PBAR_NPC_INTERVAL (PBAR_LENGTH-PBAR_NPC_START) + +void Start_Progress_Bar(); +void Set_Progress_Bar_Position(int pos); + +#ifdef __cplusplus +}; +#endif + + + +#endif \ No newline at end of file diff --git a/3dc/avp/win95/system.c b/3dc/avp/win95/system.c new file mode 100644 index 0000000..eaff75d --- /dev/null +++ b/3dc/avp/win95/system.c @@ -0,0 +1,1036 @@ +/* inits the system and controls environment and player loading */ + +#include "3dc.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "gameplat.h" +#define UseLocalAssert Yes +#include "ourasert.h" + +/* patrick 5/12/96 */ +#include "bh_far.h" +#include "pheromon.h" +#include "huddefs.h" +#include "hudgfx.h" +#include "font.h" +#include "bh_gener.h" +#include "pvisible.h" + +#include "projload.hpp" // c++ header which ignores class definitions/member functions if __cplusplus is not defined ? +#include "chnkload.hpp" // c++ header which ignores class definitions/member functions if __cplusplus is not defined ? + +#include "ffstdio.h" // fast file stdio +#include "avp_menus.h" + +/*------------Patrick 1/6/97--------------- +New sound system +-------------------------------------------*/ +#include "psndplat.h" +#include "progress_bar.h" +#include "bh_rubberduck.h" +#include "game_statistics.h" +#include "CDTrackSelection.h" + + +// EXTERNS + + + +extern int WindowMode; +extern int VideoMode; + +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + +extern SHAPEHEADER** mainshapelist; + +extern int NumActiveBlocks; +extern int NumOnScreenBlocks; +extern DISPLAYBLOCK *ActiveBlockList[]; + +extern MODULEMAPBLOCK AvpCompiledMaps[]; +extern MAPHEADER TestMap[]; +extern MAPHEADER Map[]; +extern MAPHEADER * staticmaplist[]; +extern MAPBLOCK8 Player_and_Camera_Type8[]; + +extern SCENEMODULE **Global_ModulePtr; +extern SCENEMODULE *MainSceneArray[]; + +extern void (*SetVideoMode[]) (void); +extern int HWAccel; +extern int Resolution; +extern void SetupVision(void); +extern void ReInitHUD(void); +extern void CheckCDStatus(void); + +extern void DeallocateSoundsAndPoolAllocatedMemory(); + + +/*Globals */ + +int WindowRequestMode; +int VideoRequestMode; +int ZBufferRequestMode; +int RasterisationRequestMode; +int SoftwareScanDrawRequestMode; +int DXMemoryRequestMode; +WINSCALEXY TopLeftSubWindow; +WINSCALEXY ExtentXYSubWindow; + + +// static + +int ReadModuleMapList(MODULEMAPBLOCK *mmbptr); +RIFFHANDLE env_rif = INVALID_RIFFHANDLE; +RIFFHANDLE player_rif = INVALID_RIFFHANDLE; +RIFFHANDLE alien_weapon_rif = INVALID_RIFFHANDLE; +RIFFHANDLE marine_weapon_rif = INVALID_RIFFHANDLE; +RIFFHANDLE predator_weapon_rif = INVALID_RIFFHANDLE; + +void ProcessSystemObjects(); + +/* + + Video Mode at start-up + + The source to set up the initial video mode obviously + depends on the platform, and so this routine is best placed + in this file + +*/ + +/* THIS IS FOR THE MENU SCREEN */ + +void InitialVideoMode(void) + +{ +/* + Note that video modes are now only + REQUESTED, not set. + Sound will also be dealt with in the + same way. +*/ + + + ScreenDescriptorBlock.SDB_Flags = SDB_Flag_Raw256 | SDB_Flag_MIP; + + /* + Setup for Windows mode. Note that + TopLeftSubWindow and ExtentXYSubWindow + should be set to sensible defaults even + if we are in FullScreen mode. + Also: TopLeftSubWindow and ExtentXYSubWindow + are proportions of the current Windows display + extents, set in floating point in a range of + 0.0-1.0 THIS CODE IS INTENDED FOR PENTIUM TARGETS + ONLY, AND THEREFORE USES FLOATING PT. IT MUST + NOT + LEAK. + */ + + /* + Note this is now only a request mode. + */ + + #if 1 + WindowRequestMode = WindowModeFullScreen; + #else + WindowRequestMode = WindowModeSubWindow; + #endif + + TopLeftSubWindow.x = 0.3; + TopLeftSubWindow.y = 0.3; + ExtentXYSubWindow.x = 0.6; + ExtentXYSubWindow.y = 0.6; + +/* + Experimental settings for other + request modes affecting rendering. +*/ + + /*VideoRequestMode = VideoMode_DX_640x480x8; for menus - is this guaranteed? */ + VideoRequestMode = AvP.MenuVideoRequestMode; + + /* JH 20/5/97 + begin in minmal h/w configuration - for menus + - don't need any h/w 3d, but do need to know + about h/w direct draw and what video modes + will be available */ + + ZBufferRequestMode = RequestZBufferNever; + + RasterisationRequestMode = RequestDefaultRasterisation; + + SoftwareScanDrawRequestMode = RequestScanDrawDirectDraw; + + DXMemoryRequestMode = RequestSystemMemoryAlways; + + /* + IMPORTANT!!!! In the Windows 95 version, + SetVideoMode MUST NOT be called from this + routine, since InitialVideoMode is called + first in WinMain to prepare for windows + initialisation and the actual DirectX + initialisation (done through SetVideoMode) + must be done after windows initialisation + */ + +} + + + + +/****************** AVP Change Display Modes*/ + +/* + This function is intended to allow YOU, + the user, to obtain your heart's fondest desires + by one simple call. Money? Love? A better job? + It's all here, you have only to ask... + No, I was lying actually. + In fact, this should allow you to change + display modes cleanly. Pass your request modes + (as normally set up in system.c). For all entries + which you do not want to change, simply pass + the current global value (e.g. ZBufferRequestMode + in the NewZBufferMode entry). + + Note that the function must always be passed the + HINSTANCE and nCmdShow from winmain. +*/ + +/* + Note that this function will NOT + reinitialise the DirectDraw object + or switch to or from a hardware DD + device, but it will release and rebuild + all the Direct3D objects. +*/ + +/* + Note that you MUST be in the right + directory for a texture reload before you + call this, and normal operations CAN change + the directory... +*/ + +/* + NOTE!!! If you start in DirectDraw mode + and go to Direct3D mode, this function + CANNOT POSSIBLY WORK WITHOUT A FULL SHAPE + RELOAD, since the shape data is overwritten + during DirectDraw initialisation!!!! + + NOTE ALSO: TEXTURE RELOAD MAY BE DODGY + WITHOUT A SHAPE RELOAD!!! +*/ + + +int AVP_ChangeDisplayMode + ( + HINSTANCE hInst, + int nCmd, + int NewVideoMode, + int NewWindowMode, + int NewZBufferMode, + int NewRasterisationMode, + int NewSoftwareScanDrawMode, + int NewDXMemoryMode + ) +{ + BOOL ChangeWindow = No; + + /* + Shut down DirectX objects and destroy + the current window, if necessary. + */ + + if (NewWindowMode != WindowMode) + { + ChangeWindow = Yes; + } + + /* JH 30/5/97 - added this line back in so that d3d is cleaned up properly when the + display is changed back to 8-but for the menus */ + /* JH 3/6/97 - don't quit kill off the images - still keep buffers in system memory + that are not linked to direct draw */ + MinimizeAllImages(); + MinimizeAllDDGraphics(); + ReleaseDirect3DNotDDOrImages(); + + finiObjectsExceptDD(); + + if (ChangeWindow) + ExitWindowsSystem(); + + + /* + Set the request modes and actual modes + according to the passed values. + */ + + VideoRequestMode = NewVideoMode; + WindowRequestMode = NewWindowMode; + ZBufferRequestMode = NewZBufferMode; + RasterisationRequestMode = NewRasterisationMode; + SoftwareScanDrawRequestMode = NewSoftwareScanDrawMode; + DXMemoryRequestMode = NewDXMemoryMode; + + VideoMode = VideoRequestMode; + WindowMode = WindowRequestMode; + + /* this may reconstruct the dd object depending + on the rasterisation request mode and whether + a hardware dd driver is selected or could be + available - JH 20/5/97 */ + ChangeDirectDrawObject(); + + /* + Recreate the window, allowing + for possible change in WindowMode. + */ + + if (ChangeWindow) + { + BOOL rc = InitialiseWindowsSystem + ( + hInst, + nCmd, + WinInitChange + ); + + if (rc == FALSE) + return rc; + } + + /* + Set the video mode again. This + will handle all changes to DirectDraw + objects, all Direct3D initialisation, + and other request modes such as + zbuffering. + */ + + SetVideoMode[VideoMode](); + + + + return TRUE; +} + + +//void ReleaseDirect3DNotDDOrImages(void) +//{ +// RELEASE(d3d.lpD3DViewport); +// RELEASE(d3d.lpD3DDevice); +// RELEASE(d3d.lpD3D); +//} + + +//empty functions for hooks +// hooks for doing stuff after drawing and +// after a flip + +void ProjectSpecificItemListPostProcessing(void){;} +void ProjectSpecificBufferFlipPostProcessing(void){;} + + + +/*******************************************************************************************/ +/*******************************************************************************************/ + +/*************** GAME AND ENIVROMENT CONTROL **************************/ + + + +void InitCharacter() +{ + /*** RWH cleans up the character initialisation + it would be nice if this can be called when + we load up a game of a different character + ***/ + + // load charcater specific rif and sounds + + + if(player_rif != INVALID_RIFFHANDLE) + { + // we already have a player loaded - delete the bastard + avp_undo_rif_load(player_rif); + } + if(alien_weapon_rif != INVALID_RIFFHANDLE) + { + // we already have a player loaded - delete the bastard + avp_undo_rif_load(alien_weapon_rif); + } + if(marine_weapon_rif != INVALID_RIFFHANDLE) + { + // we already have a player loaded - delete the bastard + avp_undo_rif_load(marine_weapon_rif); + } + if(predator_weapon_rif != INVALID_RIFFHANDLE) + { + // we already have a player loaded - delete the bastard + avp_undo_rif_load(predator_weapon_rif); + } + + #if MaxImageGroups==1 + InitialiseTextures(); + #else + SetCurrentImageGroup(0); + DeallocateCurrentImages(); + #endif + + Start_Progress_Bar(); + + + Set_Progress_Bar_Position(PBAR_HUD_START); + + switch(AvP.Network) + { + case I_No_Network: + { + + + // set up the standard single player game + switch(AvP.PlayerType) + { + case I_Marine: + { + marine_weapon_rif = avp_load_rif("avp_huds\\marwep.rif"); + Set_Progress_Bar_Position(PBAR_HUD_START+PBAR_HUD_INTERVAL*.25); + player_rif = avp_load_rif("avp_huds\\marine.rif"); + break; + } + case I_Predator: + { + predator_weapon_rif = avp_load_rif("avp_huds\\pred_hud.rif"); + Set_Progress_Bar_Position(PBAR_HUD_START+PBAR_HUD_INTERVAL*.25); + player_rif = avp_load_rif("avp_huds\\predator.rif"); + break; + } + + case I_Alien: + { + #if ALIEN_DEMO + alien_weapon_rif = avp_load_rif("alienavp_huds\\alien_hud.rif"); + Set_Progress_Bar_Position(PBAR_HUD_START+PBAR_HUD_INTERVAL*.25); + player_rif = avp_load_rif("alienavp_huds\\alien.rif"); + #else + alien_weapon_rif = avp_load_rif("avp_huds\\alien_hud.rif"); + Set_Progress_Bar_Position(PBAR_HUD_START+PBAR_HUD_INTERVAL*.25); + player_rif = avp_load_rif("avp_huds\\alien.rif"); + #endif + break; + } + default: + { + GLOBALASSERT(2<1); + } + } + break; + } + default: + { + + + + // set up a multiplayer game - here becuse we might end + // up with a cooperative game + //load all weapon rifs + marine_weapon_rif = avp_load_rif("avp_huds\\marwep.rif"); + predator_weapon_rif = avp_load_rif("avp_huds\\pred_hud.rif"); + alien_weapon_rif = avp_load_rif("avp_huds\\alien_hud.rif"); + + Set_Progress_Bar_Position(PBAR_HUD_START+PBAR_HUD_INTERVAL*.25); + player_rif = avp_load_rif("avp_huds\\multip.rif"); + } + } + Set_Progress_Bar_Position(PBAR_HUD_START+PBAR_HUD_INTERVAL*.5); + + #if MaxImageGroups>1 + SetCurrentImageGroup(0); + #endif + copy_rif_data(player_rif,CCF_IMAGEGROUPSET,PBAR_HUD_START+PBAR_HUD_INTERVAL*.5,PBAR_HUD_INTERVAL*.25); + + Set_Progress_Bar_Position(PBAR_HUD_START+PBAR_HUD_INTERVAL*.75); + + + if(alien_weapon_rif!=INVALID_RIFFHANDLE) + copy_rif_data(alien_weapon_rif,CCF_LOAD_AS_HIERARCHY_IF_EXISTS|CCF_IMAGEGROUPSET+CCF_DONT_INITIALISE_TEXTURES,PBAR_HUD_START+PBAR_HUD_INTERVAL*.5,PBAR_HUD_INTERVAL*.25); + + if(marine_weapon_rif!=INVALID_RIFFHANDLE) + copy_rif_data(marine_weapon_rif,CCF_LOAD_AS_HIERARCHY_IF_EXISTS|CCF_IMAGEGROUPSET+CCF_DONT_INITIALISE_TEXTURES,PBAR_HUD_START+PBAR_HUD_INTERVAL*.5,PBAR_HUD_INTERVAL*.25); + + if(predator_weapon_rif!=INVALID_RIFFHANDLE) + copy_rif_data(predator_weapon_rif,CCF_LOAD_AS_HIERARCHY_IF_EXISTS|CCF_IMAGEGROUPSET+CCF_DONT_INITIALISE_TEXTURES,PBAR_HUD_START+PBAR_HUD_INTERVAL*.5,PBAR_HUD_INTERVAL*.25); + + Set_Progress_Bar_Position(PBAR_HUD_START+PBAR_HUD_INTERVAL); + //copy_chunks_from_environment(0); + + /*KJL************************************* + * Setup generic data for weapons etc * + *************************************KJL*/ + + InitialiseEquipment(); + InitHUD(); + +} + +extern void create_strategies_from_list (); +extern void AssignAllSBNames(); + +void RestartLevel() +{ + //get the cd to start again at the beginning of the play list. + ResetCDPlayForLevel(); + + CleanUpPheromoneSystem(); + // now deallocate the module vis array + DeallocateModuleVisArrays(); + + /* destroy the VDB list */ + InitialiseVDBs(); + InitialiseTxAnimBlocks(); + + + // deallocate strategy and display blocks + { + int i ; + + i = maxstblocks; + DestroyAllStrategyBlocks(); + while(i--) + ActiveStBlockList[i] = NULL; + + i = maxobjects; + InitialiseObjectBlocks(); + while(i --) + ActiveBlockList[i] = NULL; + } + + //stop all sound + SoundSys_StopAll(); + + //reset the displayblock for modules to 0 + { + int i=2; + while(MainScene.sm_module[i].m_type!=mtype_term) + { + MainScene.sm_module[i].m_dptr=0; + i++; + } + + } + + // set the Onscreenbloock lsit to zero + NumOnScreenBlocks = 0; + + //start reinitialising stuff + +// InitialiseEquipment(); +// InitHUD(); + + ProcessSystemObjects(); + + create_strategies_from_list (); + AssignAllSBNames(); + + SetupVision(); + InitObjectVisibilities(); + InitPheromoneSystem(); + InitHive(); + InitSquad(); + + /* KJL 14:22:41 17/11/98 - reset HUD data, such as where the crosshair is, + whether the Alien jaw is on-screen, and so on */ + ReInitHUD(); + + InitialiseParticleSystem(); + InitialiseSfxBlocks(); + InitialiseLightElementSystem(); + CreateRubberDucks(); + InitialiseTriggeredFMVs(); + + CheckCDStatus(); + + /*Make sure we don't get a slow frame when we restart , since this can cause problems*/ + ResetFrameCounter(); + + CurrentGameStats_Initialise(); + MessageHistory_Initialise(); + + if(AvP.Network!=I_No_Network) + { + TeleportNetPlayerToAStartingPosition(Player->ObStrategyBlock,1); + } + else + { + //make sure the visibilities are up to date + extern VIEWDESCRIPTORBLOCK* Global_VDB_Ptr; + Global_VDB_Ptr->VDB_World = Player->ObWorld; + AllNewModuleHandler(); + DoObjectVisibilities(); + } +} + + +ELO Gen1 = {"GEN1"}; +ELO Gen2 = {"GEN2"}; +ELO Gen3 = {"GEN3"}; +ELO Gen4 = {"GEN4"}; +ELO Medlab = { "MEDLAB"}; +ELO Cmc1 = {"CMC1"}; +ELO Cmc2 = {"CMC2"}; +ELO Cmc3 = {"CMC3"}; +ELO Cmc4 = {"CMC4"}; +ELO Cmc5 = {"CMC5"}; + +ELO Cmc6 = {"CMC6"}; +ELO Sp1 = {"SP1"}; +ELO Sp2 = {"SP2"}; +ELO Sp3 = {"SP3"}; +ELO Rnd1 = {"RND1"}; +ELO Rnd2 = {"RND2"}; +ELO Rnd3 = {"RND3"}; +ELO Rnd4 = {"RND4"}; +ELO Mps1 = {"MPS01"}; +ELO Mps2 = {"MPS02"}; + +ELO Mps3 = {"MPS3"}; +ELO Mps4 = {"MPS4"}; +ELO Surface = {"SURFACE"}; +ELO Entrance = {"ENTRANCE"}; +ELO Dm1 = {"VERTIGO"}; +ELO Dm2 = {"TOWERS"}; +ELO Dm3 = {"INVASION"}; +ELO Dm4 = {"SHAFTED"}; +ELO Dm5 = {"RANCOUR"}; +ELO Dm6 = {"DM6"}; +ELO Dm7 = {"DM7"}; +ELO Dm8 = {"DM8"}; +ELO Dm9 = {"DM9"}; +ELO Dm10 = {"DM10"}; + + + + + // Modified by Edmond for Mplayer Demo + ELO* Env_List[I_Num_Environments] = + { + #ifndef MPLAYER_DEMO + &Gen1, &Gen2, + &Gen3, &Gen4, + &Medlab, &Cmc1, + &Cmc2, &Cmc3, + &Cmc4, &Cmc5, // 10 + &Cmc6, &Sp1, + &Sp2, &Sp3, + &Rnd1, &Rnd2, + &Rnd3, &Rnd4, + &Mps1, &Mps2, // 20 + &Mps3, &Mps4, + &Surface, &Entrance, + &Dm1, &Dm2, + &Dm3, &Dm4, + &Dm5, &Dm6, // 30 + &Dm7, &Dm8, + &Dm9, + #endif + &Dm10 + }; + +/**** Construct filename and go for it ***************/ + +void catpathandextension(char*, char*); +void DestroyActiveBlockList(void); +void InitialiseObjectBlocks(void); + + +char EnvFileName[100]; +char LevelDir[100]; + +void ProcessSystemObjects() +{ + int i; + + MODULEMAPBLOCK* mmbptr= &AvpCompiledMaps[0]; + STRATEGYBLOCK* sbptr; + + /* PC Loading. + 1 LoadRif File + a sets up precompiled shapes + b sets up other loaded shapes + c sets maps ans SBs for loaded maps + + 2 + */ + + + #if TestRiffLoaders + ReadMap(Map); /* for chunck loader*/ + ReadModuleMapList(mmbptr); + #else + #if SupportModules + ReadModuleMapList(mmbptr); + #endif /*SupportModules*/ + ReadMap(Map); + #endif + + /*HACK HACK*/ + + sbptr = AttachNewStratBlock((MODULE*)NULL, + (MODULEMAPBLOCK*)&Player_and_Camera_Type8[0], + Player); + AssignRunTimeBehaviours(sbptr); + + #if SupportModules + + Global_ModulePtr = MainSceneArray; + PreprocessAllModules(); + i = GetModuleVisArrays(); + if(i == No) textprint("GetModuleVisArrays() failed\n"); + + + /*WaitForReturn();*/ + + #endif +} + +int ReadModuleMapList(MODULEMAPBLOCK *mmbptr) +{ + MODULE m_temp; + + DISPLAYBLOCK *dptr; + STRATEGYBLOCK *sbptr; + /* this automatically attaches sbs to dbs */ + + while(mmbptr->MapType != MapType_Term) + { + m_temp.m_mapptr = mmbptr; + m_temp.m_sbptr = (STRATEGYBLOCK*)NULL; + m_temp.m_dptr = NULL; + AllocateModuleObject(&m_temp); + dptr = m_temp.m_dptr; + LOCALASSERT(dptr); /* if this fires, cannot allocate displayblock */ + dptr->ObMyModule = NULL; + sbptr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dptr); + /* enable compile in behaviours here */ + AssignRunTimeBehaviours(sbptr); + + mmbptr++; + } + + return(0); +} + + +void UnloadRifFile() +{ + unload_rif(env_rif); +} + + +void ChangeEnvironmentToEnv(I_AVP_ENVIRONMENTS env_to_load) +{ + + GLOBALASSERT(env_to_load != AvP.CurrentEnv); + + GLOBALASSERT(Env_List[env_to_load]); + + Destroy_CurrentEnvironment(); + /* Patrick: 26/6/97 + Stop and remove all sounds here */ + SoundSys_StopAll(); + SoundSys_RemoveAll(); + CDDA_Stop(); + + // Loading functions + AvP.CurrentEnv = env_to_load; + LoadRifFile(); + +} + + +void IntegrateNewEnvironment() +{ + int i; + MODULEMAPBLOCK* mmbptr= &AvpCompiledMaps[0]; + + // elements we need form processsystemobjects + + ReadMap(Map); /* for chunck loader*/ + ReadModuleMapList(mmbptr); + + Global_ModulePtr = MainSceneArray; + PreprocessAllModules(); + i = GetModuleVisArrays(); + if(i == No) textprint("GetModuleVisArrays() failed\n"); + + + // elements from start game for AI + + InitObjectVisibilities(); + InitPheromoneSystem(); + BuildFarModuleLocs(); + InitHive(); + + AssignAllSBNames(); + + /* KJL 20:54:55 05/15/97 - setup player vision (alien wideangle, etc) */ + SetupVision(); + + UnloadRifFile();//deletes environment File_Chunk since it is no longer needed + + /* Patrick: 26/6/97 + Load our sounds for the new env */ + LoadSounds("PLAYER"); + + /* remove resident loaded 'fast' files */ + ffcloseall(); + + ResetFrameCounter(); +} + + +const char GameDataDirName[20] = {"AVP_RIFS"}; +const char FileNameExtension[5] = {".RIF"}; + +void LoadRifFile() +{ + + char file_and_path[100]; + int i = 0; + + Set_Progress_Bar_Position(PBAR_LEVEL_START); + + // clear the dir names + + for(i = 0; i < 100; i++) + { + file_and_path[i] = (char)0; + EnvFileName[i] = (char)0; + LevelDir[i] = (char)0; + } + + // Set up the dirname for the Rif load + + catpathandextension(&file_and_path[0], (char *)&GameDataDirName[0]); + catpathandextension(&file_and_path[0], Env_List[AvP.CurrentEnv]->main); /* root of the file name,smae as dir*/ + catpathandextension(&file_and_path[0], (char *)&FileNameExtension[0]); /* extension*/ + + env_rif = avp_load_rif((const char*)&file_and_path[0]); + Set_Progress_Bar_Position(PBAR_LEVEL_START+PBAR_LEVEL_INTERVAL*.4); + + if(INVALID_RIFFHANDLE == env_rif) + { + finiObjects(); + exit(0x3421); + + }; + +// #ifdef __WATCOMC__ +// #pragma message("Note: use copy_chunks_from_envronment(CCF_ENVIRONMENT) iff a character rif is loaded") +// #endif + + #if MaxImageGroups>1 + SetCurrentImageGroup(2); // FOR ENV + #endif + copy_rif_data(env_rif,CCF_ENVIRONMENT,PBAR_LEVEL_START+PBAR_LEVEL_INTERVAL*.4,PBAR_LEVEL_INTERVAL*.6); + //setup_shading_tables(); + //LoadBackdropImage(); +} +int Destroy_CurrentEnvironment(void) +{ + // RWH destroys all en specific data + + // function to change environment when we + // are playing a game - environmnet reset + + // this stores all info we need + + TimeStampedMessage("Beginning Destroy_CurrentEnvironment"); + //CreateLevelMetablocks(AvP.CurrentEnv); + TimeStampedMessage("After CreateLevelMetablocks"); + + /*----------------------Patrick 14/3/97----------------------- + Clean up AI systems at end of level + --------------------------------------------------------------*/ + + { + int i ; + + i = maxstblocks; + DestroyAllStrategyBlocks(); + while(i--) + ActiveStBlockList[i] = NULL; + + i = maxobjects; + InitialiseObjectBlocks(); + while(i --) + ActiveBlockList[i] = NULL; + } + TimeStampedMessage("After object blocks"); + + //Get rid of all sounds + //Deallocate memory for all shapes and hierarchy animations + DeallocateSoundsAndPoolAllocatedMemory(); + + KillFarModuleLocs(); + TimeStampedMessage("After KillFarModuleLocs"); + CleanUpPheromoneSystem(); + TimeStampedMessage("After CleanUpPheromoneSystem"); + + #if MaxImageGroups>1 + SetCurrentImageGroup(2); // FOR ENV + TimeStampedMessage("After SetCurrentImageGroup"); + + DeallocateCurrentImages(); + TimeStampedMessage("After DeallocateCurrentImages"); + #endif + // now deasllocate the module vis array + DeallocateModuleVisArrays(); + TimeStampedMessage("After DeallocateModuleVisArrays"); + + + + /* destroy the VDB list */ + InitialiseVDBs(); + TimeStampedMessage("After InitialiseVDBs"); + + + InitialiseTxAnimBlocks(); // RUN THE npcS ON OUR OWN + TimeStampedMessage("After InitialiseTxAnimBlocks"); + + + /* frees the memory from the env load*/ + DeallocateModules(); + TimeStampedMessage("After DeallocateModules"); + + avp_undo_rif_load(env_rif); + TimeStampedMessage("After avp_undo_rif_load"); + + + // set the Onscreenbloock lsit to zero + NumOnScreenBlocks = 0; + + return(0); +} + + + +#if 0 +void InitEnvironmentFromLoad(void) +{ + // in DB menus - we only destroy the current environment + // after we have selected a leve, to load - WE could + // be going TO ANY ENV or CHARACTER here (ughh) + + // this is an entire game destroy (with no save) killing + // both the env and the character followed by a complete + // game restart + + // environment clean up - sets up the load info + Destroy_CurrentEnvironment(); + // then the REST + DestroyAllStrategyBlocks(); + #if MaxImageGroups>1 + SetCurrentImageGroup(0); // FOR ENV + DeallocateCurrentImages(); + #endif + /* Patrick: 26/6/97 + Stop and remove all sounds here */ + SoundSys_StopAll(); + SoundSys_RemoveAll(); + CDDA_Stop(); + + // start the loading - we load the player + InitCharacter(); // intis the char + LoadRifFile(); // env + + // do all the ness processing + // start games calles FormatSaveBuffer and + // Process System Objects + + AssignAllSBNames(); + + // Set the timer, or we have just taken + // 10 secs for the frame + + /***** No need to do frame counter stuff in a computer! *****/ + + /* Patrick: 26/6/97 + Load our sounds for the new env */ + LoadSounds("PLAYER"); +} + + + +/************************ SAVE AND LOAD **********************/ + + + + + + + + +void LoadGameFromFile(void) +{ + // now we right to a file + char * savename = "slot1.AvP"; + FILE* fp = fopen(savename, "rb"); + if(fp == NULL) + return; + fread(&AvP, sizeof(AVP_GAME_DESC), 1, fp); + fread(&save_game_buffer, SAVEBUFFERSIZE, 1, fp); + UnpackSaveBuffer(); + fclose(fp); +} + + +void SaveGameToFile(void) +{ + char * savename = "slot1.AvP"; + FILE* fp = fopen(savename, "wb"); + CreateLevelMetablocks(AvP.CurrentEnv); + PackSaveBuffer(); + fwrite(&AvP, sizeof(AVP_GAME_DESC), 1, fp); + fwrite(&save_game_buffer, SAVEBUFFERSIZE, 1, fp); + fclose(fp); +} + +#endif + +// project spec game exit +void ExitGame(void) +{ + if(player_rif != INVALID_RIFFHANDLE) + { + avp_undo_rif_load(player_rif); + player_rif=INVALID_RIFFHANDLE; + + } + + if(alien_weapon_rif != INVALID_RIFFHANDLE) + { + avp_undo_rif_load(alien_weapon_rif); + alien_weapon_rif=INVALID_RIFFHANDLE; + } + if(marine_weapon_rif != INVALID_RIFFHANDLE) + { + avp_undo_rif_load(marine_weapon_rif); + marine_weapon_rif=INVALID_RIFFHANDLE; + } + if(predator_weapon_rif != INVALID_RIFFHANDLE) + { + avp_undo_rif_load(predator_weapon_rif); + predator_weapon_rif=INVALID_RIFFHANDLE; + } + #if MaxImageGroups>1 + SetCurrentImageGroup(0); + DeallocateCurrentImages(); + #endif +} diff --git a/3dc/avp/win95/vssver.scc b/3dc/avp/win95/vssver.scc new file mode 100644 index 0000000..cb0bd05 Binary files /dev/null and b/3dc/avp/win95/vssver.scc differ diff --git a/3dc/avp/win95/win_proj.cpp b/3dc/avp/win95/win_proj.cpp new file mode 100644 index 0000000..afc76ed --- /dev/null +++ b/3dc/avp/win95/win_proj.cpp @@ -0,0 +1,682 @@ +/**** + +Project specific (or potentially +project specific) windows functionality + +****/ + +// To link code to main C functions + +extern "C" { + +#include "3dc.h" +#include "inline.h" +#include "cd_player.h" +#include "psndplat.h" + +#include "rentrntq.h" + // Added 21/11/97 by DHM: support for a queue of Windows + // messages to avoid problems with re-entrancy due to WinProc() + +#include "alt_tab.h" + +#include "dxlog.h" +#include "zmouse.h" + +void MakeToAsciiTable(void); + +// mousewheel msg id +UINT const RWM_MOUSEWHEEL = RegisterWindowMessage(MSH_MOUSEWHEEL); +signed int MouseWheelStatus; + +extern LPDIRECTDRAWSURFACE lpDDSBack; +extern LPDIRECTDRAWSURFACE lpDDSPrimary; +extern LPDIRECTDRAWSURFACE lpZBuffer; +extern LPDIRECTDRAWSURFACE lpDDBackdrop; + +unsigned char ksarray[256]; +unsigned char ToAsciiTable[256][256]; + +// Dubious +#define grabmousecapture No + +/* + Name of project window etc for Win95 interface + Project specific (fairly obviously...). + Determines the default menu in which the application + appears (altho' other code will undoubtedly be needed + as well...), so that a NULL here should ensure no menu. +*/ + +#define NAME "AvP" +#define TITLE "AvP" + +// Necessary globals + +HWND hWndMain; +BOOL bActive = TRUE; // is application active? + +// Parameters for main (assumed full screen) window +int WinLeftX, WinRightX, WinTopY, WinBotY; +int WinWidth, WinHeight; + +// Externs + + + +extern int VideoMode; +extern int WindowMode; +extern WINSCALEXY TopLeftSubWindow; +extern WINSCALEXY ExtentXYSubWindow; + +// Window procedure (to run continuously while WinMain is active). +// Only necessary functions are handling keyboard input (for the moment +// at least - cf. DirectInput) and dealing with important system +// messages, e.g. WM_PAINT. + +// Remember to support all the keys you need for your project +// for both KEYUP and KEYDOWN messages!!! + +// IMPORTANT!!! The WindowProc is project specific +// by default, since various nifty hacks can always +// be implemented directly via the windows procedure + +#define RESTORE_SURFACE(lpDDS) { \ + if (lpDDS) { \ + if (DDERR_SURFACELOST == (lpDDS)->IsLost()) { \ + HRESULT hResult = (lpDDS)->Restore(); \ + LOGDXFMT(("%s surface was restored", #lpDDS )); \ + LOGDXERR(hResult); \ + } else { \ + LOGDXFMT(("%s surface wasn't lost", #lpDDS )); \ + } \ + } \ + else { \ + LOGDXFMT(("?&@#! no %s surface", #lpDDS )); \ + } \ +} + +extern void KeyboardEntryQueue_Add(char c); +extern IngameKeyboardInput_KeyDown(unsigned char key); +extern IngameKeyboardInput_KeyUp(unsigned char key); +extern IngameKeyboardInput_ClearBuffer(void); + + +long FAR PASCAL WindowProc(HWND hWnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + PAINTSTRUCT ps; + HDC hdc; + RECT NewWindCoord; + + if (message==RWM_MOUSEWHEEL) + { + message = WM_MOUSEWHEEL; + wParam <<= 16; + } + + + switch(message) + { + + case WM_MOUSEWHEEL: + { + MouseWheelStatus = wParam; + MouseWheelStatus>>=16; + return 0; + } + + // 21/11/97 DHM: Added porcessing of WM_CHAR messages: + case WM_CHAR: + RE_ENTRANT_QUEUE_WinProc_AddMessage_WM_CHAR + ( + (char) wParam + ); + KeyboardEntryQueue_Add((char)wParam); + return 0; + case WM_KEYDOWN: + RE_ENTRANT_QUEUE_WinProc_AddMessage_WM_KEYDOWN + ( + wParam + ); + // it's intentional for this case to fall through to WM_SYSKEYDOWN + case WM_SYSKEYDOWN: + { + int scancode = (lParam>>16)&255; + unsigned char vkcode = (wParam&255); + + // ignore the status of caps lock + //ksarray[VK_CAPITAL] = 0; + //ksarray[VK_CAPITAL] = GetKeyState(VK_CAPITAL); + if (vkcode!=VK_CAPITAL && vkcode!=VK_SCROLL) + { + #if 0 + WORD output; + if (ToAscii(vkcode,scancode,&ksarray[0],&output,0)) + { + IngameKeyboardInput_KeyDown((unsigned char)(output)); + } + #else + if (ToAsciiTable[vkcode][scancode]) + { + IngameKeyboardInput_KeyDown(ToAsciiTable[vkcode][scancode]); + } + #endif + } + // reset caps lock status + //ksarray[VK_CAPITAL] = GetKeyState(VK_CAPITAL); + //ToAscii(wParam&255,scancode,&ksarray[0],&output,0); + } + return 0; + + case WM_SYSKEYUP: + case WM_KEYUP: + { + int scancode = (lParam>>16)&255; + unsigned char vkcode = (wParam&255); + + + // ignore the status of caps lock + //ksarray[VK_CAPITAL] = 0; +//MakeToAsciiTable(); + //ksarray[VK_CAPITAL] = GetKeyState(VK_CAPITAL); + if (vkcode!=VK_CAPITAL && vkcode!=VK_SCROLL) + { + #if 0 + WORD output; + unsigned char z = ToAscii(vkcode,scancode,&ksarray[0],&output,0); + unsigned char a = (unsigned char)output; + unsigned char b = ToAsciiTable[vkcode][scancode]; + #endif + #if 0 + WORD output; + if (ToAscii(vkcode,scancode,&ksarray[0],&output,0)) + { + IngameKeyboardInput_KeyUp((unsigned char)(output)); + } + #else + if (ToAsciiTable[vkcode][scancode]) + { + IngameKeyboardInput_KeyUp(ToAsciiTable[vkcode][scancode]); + } + #endif + } + // reset caps lock status + //ksarray[VK_CAPITAL] = GetKeyState(VK_CAPITAL); + //ToAscii(wParam&255,scancode,&ksarray[0],&output,0); + } + return 0; + + // This, in combination with code in win_func, + // will hopefully disable Alt-Tabbing... + case WM_ACTIVATEAPP: + bActive = (BOOL) wParam; + + LOGDXFMT(("WM_ACTIVATEAPP msg: bActive = %d",(int)bActive)); + + if (bActive) + { + // need to restore all surfaces - do the special ones first + RESTORE_SURFACE(lpDDSPrimary) + RESTORE_SURFACE(lpDDSBack) + RESTORE_SURFACE(lpZBuffer) + // dodgy, this is meant to be graphic, so it'll really need to be reloaded + RESTORE_SURFACE(lpDDBackdrop) + // now do all the graphics surfaces and textures, etc. + ATOnAppReactivate(); + } + IngameKeyboardInput_ClearBuffer(); + + return 0; + + // Three below are for safety, to turn off + // as much as possible of the more annoying + // functionality of the default Windows + // procedure handler + + case WM_ACTIVATE: + return 0; +#if 0 + case WM_SYSKEYUP: + return 0; + + case WM_SYSKEYDOWN: + return 0; +#endif + case WM_CREATE: + break; + + case WM_MOVE: + // Necessary to stop it crashing in 640x480 + // FullScreen modes on window initialisation + if (WindowMode == WindowModeSubWindow) + { + GetWindowRect(hWndMain, &NewWindCoord); + WinLeftX = NewWindCoord.left; + WinTopY = NewWindCoord.top; + WinRightX = NewWindCoord.right; + WinBotY = NewWindCoord.bottom; + } + break; + + case WM_SIZE: + // Necessary to stop it crashing in 640x480 + // FullScreen modes on window initialisation + if (WindowMode == WindowModeSubWindow) + + { + GetWindowRect(hWndMain, &NewWindCoord); + WinLeftX = NewWindCoord.left; + WinTopY = NewWindCoord.top; + WinRightX = NewWindCoord.right; + WinBotY = NewWindCoord.bottom; + } + break; + + case WM_SETCURSOR: + SetCursor(NULL); + return TRUE; + + case WM_ERASEBKGND: + return TRUE; + + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + EndPaint(hWnd, &ps); + return TRUE; + + /* Patrick 11/6/97: this to detects the end of a cdda track */ + case MM_MCINOTIFY: + PlatCDDAManagementCallBack(wParam, lParam); + break; + + case WM_DESTROY: + // Calls ReleaseDirect3D DIRECTLY, + // so as to avoid calling ExitSystem and exiting the + // Windows system inside the windows procedure + // IMPORTANT!!! For this to work, release functions + // must be re-entrant. Since this may be causing + // problems under obscure cirumstances, I am removing + // this now (25/7/96). + // And putting it back... (20/9/96) + ReleaseDirect3D(); + /* patrick 9/6/97: hmmmmm.... */ + PlatEndSoundSys(); + + PostQuitMessage(0); + break; + } + + return DefWindowProc(hWnd, message, wParam, lParam); +} + +/* + Persuade Win95 to give us the window we want and, like, + TOTAL CONTROL, and then shut up, stop whinging and + go away. + Or at least as much control as we can get.. safely... + elegantly... ummm... +*/ + +// IMPORTANT!!! Windows initialisation is project specific, +// because of the project name and title if nothing else + +// This function now takes a mode which is +// set to full or change. Full should be +// run ONLY when the system is starting. +// Change is used to change the window +// characteristics during a run, e.g. to +// change from SubWindow to FullScreen +// mode, and will not attempt to register +// the windows class. + +BOOL InitialiseWindowsSystem(HANDLE hInstance, int nCmdShow, + int WinInitMode) +{ + WNDCLASS wc; + BOOL rc; + + MakeToAsciiTable(); +/* + Set up the width and height we want from + the VideoMode, taking account of WindowMode. +*/ + +// This has now been modified to just set the +// size to the current system metrics, which +// may or may not be ideal. Surprisingly, it +// seems not to make much difference. + + if (WindowMode == WindowModeSubWindow) + { + + //force window to be 640x480 to avoid stretch blits. + WinWidth=640; + WinHeight=480; + + WinLeftX = (int) (TopLeftSubWindow.x * + (float) GetSystemMetrics(SM_CXSCREEN)); + WinTopY = (int) (TopLeftSubWindow.y * + (float) GetSystemMetrics(SM_CYSCREEN)); + WinRightX = (WinLeftX + WinWidth); + WinBotY = (WinTopY + WinHeight); + } + else if (WindowMode == WindowModeFullScreen) + { + #if 1 + WinWidth = GetSystemMetrics(SM_CXSCREEN); + WinHeight = GetSystemMetrics(SM_CYSCREEN); + #else + // This version of the code MUST be + // kept up to date with new video modes!!! + if ((VideoMode == VideoMode_DX_320x200x8) || + (VideoMode == VideoMode_DX_320x200x8T)) + { + WinWidth = 320; + WinHeight = 200; + } + else if (VideoMode == VideoMode_DX_320x240x8) + { + WinWidth = 320; + WinHeight = 240; + } + else // Default to 640x480 + { + WinWidth = 640; + WinHeight = 480; + } + #endif + + // Set up globals for window corners + WinLeftX = 0; + WinTopY = 0; + WinRightX = WinWidth; + WinBotY = WinHeight; + } + else + return FALSE; + +// We only want to register the class in +// WinInitFull mode!!! + + if (WinInitMode == WinInitFull) + { + +/* + Set up and register window class +*/ +// get double click messages from mouse if user double-clicks it + wc.style = CS_DBLCLKS; +// Name of window procedure (see above) + wc.lpfnWndProc = WindowProc; +/* + Extra bytes for obscure purposes bearing a sordid relationship to + dialog box conventions. Zero for us. +*/ + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; +// Instance which window is within + wc.hInstance = (HINSTANCE) hInstance; +/* + System icon resource. This one is generic. For an actual + game this icon will be project specific. +*/ + #if 1 + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + #else + wc.hIcon = NULL; + #endif +// System cursor resource. This one is generic. + #if 1 + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + #else + wc.hCursor = NULL; + #endif +/* + NULL background forces application to redraw + the background ITSELF when it receives a WM_ERASEBKGND + message, leaving graphical control with the engine +*/ + wc.hbrBackground = NULL; +// Project name and class for windows menus etc. + wc.lpszMenuName = NAME; + wc.lpszClassName = NAME; +/* + Register the class we have constructed as a valid window that + can then be created. Return code indicates success or + failure. +*/ + rc = RegisterClass(&wc); + + if (!rc) + return FALSE; + } + +/* + Create a window (extended function call) and return + handle. Before returning, WM_CREATE, WM_GETMINMAXINFO + and WM_NCCREATE messages will be sent to the window + procedure. + + NOTE!!! AT present even with debug on we get a + topmost full screen window. +*/ + +#if debug + if (WindowMode == WindowModeSubWindow) + { + hWndMain = CreateWindowEx( + 0, // WS_EX_TOPMOST + NAME, // Name of class (registered by RegisterClass call above) + TITLE, // Name of window + WS_OVERLAPPED | + WS_CAPTION | + WS_THICKFRAME, +/* + Initial horizontal and vertical position. For a pop-up window, + these are the coordinates of the upper left corner. +*/ + WinLeftX, + WinTopY, +/* + Width and height of window. These are set to the current full + screen widths as determined by a Win32 GetSystemMetrics call + (GetSystemMetrics(SM_CXSCREEN) and + GetSystemMetrics(SM_CYSCREEN)). +*/ + WinWidth, + WinHeight, +// Parent window (could possibly be set in tools system?) + NULL, +// Child/menu window (could possibly be set in tools system?) + NULL, +// Handle for module associated with window + (HINSTANCE)hInstance, +// Parameter for associated structure (null in this case) + NULL); + } + else if (WindowMode == WindowModeFullScreen) + { + hWndMain = CreateWindowEx( +/* + WS_EX_TOPMOST forces this window to be topmost except + for other topmost windows, even when deactivated. +*/ + WS_EX_TOPMOST, + NAME, // Name of class (registered by RegisterClass call above) + TITLE, // Name of window + WS_VISIBLE | // kills Alt-Space and strews its entrails over fifteen miles. Heh heh heh. + WS_POPUP, // i.e. specify window is style pop up, i.e. non-application +/* + Initial horizontal and vertical position. For a pop-up window, + these are the coordinates of the upper left corner. +*/ + WinLeftX, + WinTopY, +/* + Width and height of window. These are set to the current full + screen widths as determined by a Win32 GetSystemMetrics call + (GetSystemMetrics(SM_CXSCREEN) and + GetSystemMetrics(SM_CYSCREEN)). +*/ + WinWidth, + WinHeight, +// Parent window (null for a full screen game) + NULL, +// Child/menu window (null for a full screen game) + NULL, +// Handle for module associated with window + (HINSTANCE)hInstance, +// Parameter for associated structure (null in this case) + NULL); + } + else + return FALSE; + +#else + if (WindowMode == WindowModeSubWindow) + { + hWndMain = CreateWindowEx( + 0, // WS_EX_TOPMOST + NAME, // Name of class (registered by RegisterClass call above) + TITLE, // Name of window + WS_OVERLAPPED | + WS_CAPTION | + WS_THICKFRAME, +/* + Initial horizontal and vertical position. For a pop-up window, + these are the coordinates of the upper left corner. +*/ + WinLeftX, + WinTopY, +/* + Width and height of window. These are set to the current full + screen widths as determined by a Win32 GetSystemMetrics call + (GetSystemMetrics(SM_CXSCREEN) and + GetSystemMetrics(SM_CYSCREEN)). +*/ + WinWidth, + WinHeight, +// Parent window (could be set in tools system?) + NULL, +// Child/menu window (could be set in tools system?) + NULL, +// Handle for module associated with window + hInstance, +// Parameter for associated structure (null in this case) + NULL); + } + else if (WindowMode == WindowModeFullScreen) + { + hWndMain = CreateWindowEx( +/* + WS_EX_TOPMOST forces this window to be topmost except + for other topmost windows, even when deactivated. +*/ + WS_EX_TOPMOST, + NAME, // Name of class (registered by RegisterClass call above) + TITLE, // Name of window + WS_VISIBLE | // kills Alt-Space and strews its entrails for fifteen miles. Heh heh heh. + WS_POPUP, // Specify window is style pop up, i.e. non-application +/* + Initial horizontal and vertical position. For a pop-up window, + these are the coordinates of the upper left corner. +*/ + WinLeftX, + WinTopY, +/* + Width and height of window. These are set to the current full + screen widths as determined by a Win32 GetSystemMetrics call + (GetSystemMetrics(SM_CXSCREEN) and + GetSystemMetrics(SM_CYSCREEN)). +*/ + WinWidth, + WinHeight, +// Parent window (null for a full screen game) + NULL, +// Child/menu window (null for a full screen game) + NULL, +// Handle for module associated with window + hInstance, +// Parameter for associated structure (null in this case) + NULL); + } + else + return FALSE; + +#endif + + if (!hWndMain) + return FALSE; + +// Experiment only!!!! + +// Set the window up to be displayed + ShowWindow(hWndMain, nCmdShow); +// Update once (i.e. send WM_PAINT message to the window procedure) + UpdateWindow(hWndMain); + +// Grab ALL mouse messages for our window. +// Note this will only work if the window is +// foreground (as it is... ). This ensures that +// we will still get MOUSEMOVE etc messages even +// if the mouse is out of the defined window area. + + #if grabmousecapture + SetCapture(hWndMain); +// Load null cursor shape + SetCursor(NULL); + #endif + MakeToAsciiTable(); + + return TRUE; + +} + +// Project specific to go with the initialiser + +BOOL ExitWindowsSystem(void) + +{ + BOOL rc = TRUE; + + // Release dedicated mouse capture + #if grabmousecapture + ReleaseCapture(); + #endif + + rc = DestroyWindow(hWndMain); + + return rc; +} + +void MakeToAsciiTable(void) +{ + WORD output; + for (int k=0; k<=255; k++) + { + ksarray[k]=0; + } + + for (int i=0; i<=255; i++) + { + for (int s=0; s<=255; s++) + { + if(ToAscii(i,s,&ksarray[0],&output,0)!=0) + { + ToAsciiTable[i][s] = (unsigned char)output; + } + else + { + ToAsciiTable[i][s] = 0; + } + } + } +} +// End of extern C declaration + +}; + + + + diff --git a/3dc/avp/win95/winmain.bak b/3dc/avp/win95/winmain.bak new file mode 100644 index 0000000..b85447f --- /dev/null +++ b/3dc/avp/win95/winmain.bak @@ -0,0 +1,834 @@ +/* Main designed spec for use with windows95*/ + +#include "3dc.h" +#include "module.h" +#include "inline.h" +#include "stratdef.h" +#include "gamedef.h" +#include "gameplat.h" + +#include "bh_types.h" +#include "usr_io.h" +#include "font.h" + +/* JH 27/1/97 */ +#include "comp_shp.h" + +#include "chnkload.hpp" +#include "npcsetup.h" /* JH 30/4/97 */ +#include "krender.h" +#include "pldnet.h" +#include "avpview.h" +#include "scrshot.hpp" +#include "language.h" +#include "huddefs.h" +#include "vision.h" +#include "pcmenus.h" +#include "multmenu.h" +#include "menudefs.h" +#include "database.h" +#include "avp_menus.h" +#include "kshape.h" +#define UseLocalAssert Yes + +#include "ourasert.h" + +#include "ffstdio.h" // fast file stdio + +#include "davehook.h" + +#include "rebmenus.hpp" +#include "intro.hpp" +#include "showcmds.h" + +#include "consbind.hpp" + +#include "AvpReg.hpp" +#include "mempool.h" +#include "GammaControl.h" + +#include "CDTrackSelection.h" + +/*------------Patrick 1/6/97--------------- +New sound system +-------------------------------------------*/ +#include "psndplat.h" + +#define FRAMEAV 100 + +#include "AvP_UserProfile.h" + +#define PROFILING_ON 0 +#if PROFILING_ON +#include "pentime.h" +#endif + +#if 0 +#undef PrintDebuggingText +extern int PrintDebuggingText(const char* t, ...); +#endif + +/* + + externs for commonly used global variables and arrays + +*/ +extern int VideoMode; +extern void (*UpdateScreen[]) (void); +extern DISPLAYBLOCK* ActiveBlockList[]; +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; +extern void (*SetVideoMode[]) (void); +extern int FrameRate; + +extern int WindowRequestMode; + +extern int NumActiveBlocks; +int HWAccel = 0; + +#if debug +#define MainTextPrint 1 +extern int alloc_cnt, deall_cnt; +extern int ItemCount; +int DebugFontLoaded = 0; + +extern BOOL ForceLoad_Alien; +extern BOOL ForceLoad_Marine; +extern BOOL ForceLoad_Predator; +extern BOOL ForceLoad_Hugger; +extern BOOL ForceLoad_Queen; +extern BOOL ForceLoad_Civvie; +extern BOOL ForceLoad_PredAlien; +extern BOOL ForceLoad_Xenoborg; +extern BOOL ForceLoad_Pretorian; +extern BOOL ForceLoad_SentryGun; + + +BOOL UseMouseCentreing = FALSE; +#else +#define MainTextPrint 0 +#endif + +BOOL KeepMainRifFile=FALSE; + +extern void LoadKeyConfiguration(); +extern void DeInitialisePlayer(); + +extern int AvP_MainMenus(void); +extern int AvP_InGameMenus(void); + +extern IngameKeyboardInput_ClearBuffer(void); + +HINSTANCE AVP_HInstance, hInst; +int AVP_NCmd; + +extern unsigned long TotalMemAllocated; + +char LevelName[] = {"predbit6\0QuiteALongNameActually"}; +static ELO ELOLevelToLoad = {&LevelName}; + +int QuickStartMultiplayer=1; + +int VideoModeNotAvailable=0; + +extern int DebuggingCommandsActive; + + +extern int WindowMode; +void exit_break_point_fucntion () +{ + #if debug + if (WindowMode == WindowModeSubWindow) + { + __asm int 3; + } + #endif +} + + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpCmdLine, int nCmdShow) +{ + char * instr; + #if debug + int level_to_load = I_Num_Environments; + char * command_line = lpCmdLine; + #endif + + AVP_HInstance = hInst = hInstance; + AVP_NCmd = nCmdShow; + + AutorunOff(); + + EnumerateCardsAndVideoModes(); + + LoadCDTrackList(); //load list of cd tracks assigned to levels , from a text file + +// CDDA_Start(); +// CDDA_Play(1); + + SetFastRandom(); + + /**** init game now ONLY sets up varibles for the whole + game. If you want to put something in it it must + be something that only needs to be called once + ****/ + #if debug && 1//!PREDATOR_DEMO + { + #if OverrideOldMenus + { + HWAccel = 1; + } + #else + if(strstr(command_line, "-h")) + { + HWAccel = 1; + } + #endif + + //see if any extra npc rif files should be loaded + { + char* strpos=strstr(command_line, "-l"); + if(strpos) + { + while(strpos) + { + strpos+=2; + if(*strpos>='a' && *strpos<='z') + { + while(*strpos>='a' && *strpos<='z') + { + switch (*strpos) + { + case 'a': + ForceLoad_Alien = TRUE; + break; + case 'm': + ForceLoad_Marine = TRUE; + break; + case 'p': + ForceLoad_Predator = TRUE; + break; + case 'h': + ForceLoad_Hugger = TRUE; + break; + case 'q': + ForceLoad_Queen = TRUE; + break; + case 'c': + ForceLoad_Civvie = TRUE; + break; + case 'x': + ForceLoad_Xenoborg = TRUE; + break; + case 't': + ForceLoad_Pretorian = TRUE; + break; + case 'r': + ForceLoad_PredAlien = TRUE; + break; + case 's': + ForceLoad_SentryGun = TRUE; + break; + } + strpos++; + } + } + else + { + ForceLoad_Alien = TRUE; + } + strpos=strstr(strpos,"-l"); + } + } + } + + #ifdef AVP_DEBUG_VERSION + if (strstr(command_line, "-i")) WeWantAnIntro(); + if (strstr(command_line, "-qm")) + { + QuickStartMultiplayer = 1; + } + else if (strstr(command_line, "-qa")) + { + QuickStartMultiplayer = 2; + } + else if (strstr(command_line, "-qp")) + { + QuickStartMultiplayer = 3; + } + else + { + QuickStartMultiplayer = 0; + } + + if(strstr(command_line,"-keeprif")) + { + KeepMainRifFile=TRUE; + } + + if (strstr(command_line, "-m")) + { + UseMouseCentreing = 1; + } + #endif //AVP_DEBUG_VERSION + } + #else + { + #if OverrideOldMenus + { + HWAccel = 1; + } + #endif + } + #endif + + if(strstr(command_line,"-server")) + { + extern int DirectPlay_InitLobbiedGame(); + //game has been launched by mplayer , we best humour it + LobbiedGame=LobbiedGame_Server; + if(!DirectPlay_InitLobbiedGame()) + { + exit(0x6364); + } + } + else if(strstr(command_line,"-client")) + { + extern int DirectPlay_InitLobbiedGame(); + //ditto + LobbiedGame=LobbiedGame_Client; + if(!DirectPlay_InitLobbiedGame()) + { + exit(0x6364); + } + } + else if (strstr(command_line, "-debug")) + { + DebuggingCommandsActive = 1; + } + + // Modified by Edmond for mplayer demo + #if MPLAYER_DEMO + if (!LobbiedGame) + { + MessageBox(NULL, "This demo can only be launched from Mplayer.", "Oh no!", MB_OK); + exit(33445); + } + #endif + + #if PLAY_INTRO//(MARINE_DEMO||ALIEN_DEMO||PREDATOR_DEMO) + if (!LobbiedGame) // Edmond + WeWantAnIntro(); + #endif + GetPathFromRegistry(); + + /* JH 28/5/97 */ + /* Initialise 'fast' file system */ + #if MARINE_DEMO + ffInit("fastfile\\mffinfo.txt","fastfile\\"); + #elif ALIEN_DEMO + ffInit("alienfastfile\\ffinfo.txt","alienfastfile\\"); + #else + ffInit("fastfile\\ffinfo.txt","fastfile\\"); + #endif + + InitGame(); + + + /*** Define video mode for windows initialisation ***/ + InitialVideoMode(); + + /****** Put in by John to sort out easy sub window mode ******/ + /****** REMOVE FOR GAME!!!!! ******/ + + #if debug && 1//!PREDATOR_DEMO + if(strstr(command_line, "-w")) + { + WindowRequestMode = WindowModeSubWindow; + if (!HWAccel) + RasterisationRequestMode = RequestSoftwareRasterisation; + } + if(instr = strstr(command_line, "-s")) + sscanf(instr, "-s%d", &level_to_load); + + #endif + + Env_List[0] = &(ELOLevelToLoad); + level_to_load = 0; + + /******* System initialisation **********/ + InitialiseSystem(hInstance, nCmdShow); + InitialiseRenderer(); + + InitOptionsMenu(); /* by this time we know all about the video card, etc */ + + LoadKeyConfiguration(); + /********** Grab The Video mode **********/ + /* JH - nope, not yet; not until we start the menus + (or if debugging, start the game), do we need to + set the initial video mode */ + + + /*-------------------Patrick 2/6/97----------------------- + Start the sound system + ----------------------------------------------------------*/ + SoundSys_Start(); + CDDA_Start(); + + /* kill mouse cursor */ + SetCursor(NULL); + + /* load language file and setup text string access */ + InitTextStrings(); + + ChangeDirectDrawObject(); + AvP.LevelCompleted = 0; + LoadSounds("PLAYER"); + + #if PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO + if(AvP_MainMenus()) + #else + while(AvP_MainMenus()) + #endif + { + int menusActive=0; + int thisLevelHasBeenCompleted=0; + #if !(PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO) + if(instr = strstr(command_line, "-n")) + { + sscanf(instr, "-n %s", &LevelName); + } + #endif + + #if debug + if(UseMouseCentreing) + { + //Start thread that recentres mouse , making it easier to play + //in subwindow mode + InitCentreMouseThread(); + } + #endif +// Env_List[0] = &(ELOLevelToLoad); +// level_to_load = 0; +// AvP.PlayerType = I_Marine; + + + /* turn off any special effects */ + d3d_light_ctrl.ctrl = LCCM_NORMAL; + d3d_overlay_ctrl.ctrl = OCCM_NORMAL; + + /* JH 20/5/97 + The video mode is no longer set when exiting the menus + (not necessary if user selects EXIT) + So it is set here */ + + /********** Grab The Video mode **********/ + GetCorrectDirectDrawObject(); + + if(!SetGameVideoMode()) + { + VideoModeNotAvailable=1; + continue; + } + + /* Dubious restart hack for DirectDraw problems */ + /* JH - I'm not sure this is really necessary + - it only comes into play if you try and set + a video mode which is not supported + BUT we are never going to try and do that + - or are we? */ + HandleVideoModeRestarts(hInstance, nCmdShow); + + + /* Check Gamma Settings are correct after video mode change */ + InitialiseGammaSettings(RequestedGammaSetting); + + + + + /**** init the chunk loaders ***************/ + + // no longer required here + + // Load precompiled shapes + start_of_loaded_shapes = load_precompiled_shapes(); + + /*********** Load up the character stuff *******/ + + InitCharacter(); + + /* KJL 17:56:14 26/02/98 - load a font required for Dave's HUD */ +// LoadPFFont(DATABASE_MESSAGE_FONT); + + /*********** Read in the env Map **************/ + + #if debug + if(level_to_load != I_Num_Environments) + { + if((level_to_load < 0) || (level_to_load > I_Num_Environments)) + #ifdef MPLAYER_DEMO + level_to_load = I_Dml1; + #else + level_to_load = I_Sp1; + #endif + + AvP.CurrentEnv = AvP.StartingEnv = level_to_load; + } + #endif + + LoadRifFile(); /* sets up a map*/ + #if debug + DebugFontLoaded = 1; + #endif + + /*********** Process the data ************/ + AssignAllSBNames(); + StartGame(); + +// UnloadRifFile();//deletes environment File_Chunk since it is no longer needed + + + /* Patrick 26/6/97 + Load the game sounds here: should be done after loading everthing + else, incase sounds take up system memory */ +// LoadSounds("PLAYER"); + + /* JH 28/5/97 */ + /* remove resident loaded 'fast' files */ + ffcloseall(); + /*********** Play the game ***************/ + + /* KJL 15:43:25 03/11/97 - run until this boolean is set to 0 */ + AvP.MainLoopRunning = 1; + + ScanImagesForFMVs(); + + ResetFrameCounter(); + Game_Has_Loaded(); + ResetFrameCounter(); + + if(AvP.Network!=I_No_Network) + { + /*Need to choose a starting position for the player , but first we must look + through the network messages to find out which generator spots are currently clear*/ + netGameData.myGameState = NGS_Playing; + MinimalNetCollectMessages(); + TeleportNetPlayerToAStartingPosition(Player->ObStrategyBlock,1); + } + + IngameKeyboardInput_ClearBuffer(); + while(AvP.MainLoopRunning) + { + + #if debug + #if 0 + DumpBoundsCheckInfo(DUMPTOSCREEN); + #endif + #endif + + CheckForWindowsMessages(); + CursorHome(); + + #if debug + if (memoryInitialisationFailure) + { + textprint("Initialisation not completed - out of memory!\n"); + GLOBALASSERT(1 == 0); + } + #endif + + switch(AvP.GameMode) + { + case I_GM_Playing: + { + if ((!menusActive || (AvP.Network!=I_No_Network && !netGameData.skirmishMode)) && !AvP.LevelCompleted) + { + #if MainTextPrint /* debugging stuff */ + { + + if (ShowDebuggingText.FPS) ReleasePrintDebuggingText("FrameRate = %d fps\n",FrameRate); + if (ShowDebuggingText.Environment) ReleasePrintDebuggingText("Environment %s\n", Env_List[AvP.CurrentEnv]->main); + if (ShowDebuggingText.Coords) ReleasePrintDebuggingText("Player World Coords: %d,%d,%d\n",Player->ObWorld.vx,Player->ObWorld.vy,Player->ObWorld.vz); + + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + if (ShowDebuggingText.GunPos) + { + PrintDebuggingText("Gun Position x:%d,y:%d,z:%d\n",twPtr->RestPosition.vx,twPtr->RestPosition.vy,twPtr->RestPosition.vz); + } + } + } + #endif /* MainTextPrint */ + + DoAllShapeAnimations(); + + UpdateGame(); + + #if 1 + #if PROFILING_ON + ProfileStart(); + #endif + AvpShowViews(); + #if PROFILING_ON + ProfileStop("SHOW VIEW"); + #endif + + //Do screen shot here so that text and hud graphics aren't shown + #if PROFILING_ON + ProfileStart(); + #endif + MaintainHUD(); + #if PROFILING_ON + ProfileStop("RENDER HUD"); + #endif + + #if debug + FlushTextprintBuffer(); + #endif + + //check cd status + CheckCDAndChooseTrackIfNeeded(); + + // check to see if we're pausing the game; + // if so kill off any sound effects + if(InGameMenusAreRunning() && ( (AvP.Network!=I_No_Network && netGameData.skirmishMode) || (AvP.Network==I_No_Network)) ) + SoundSys_StopAll(); + } + else + { + ReadUserInput(); +// UpdateAllFMVTextures(); + SoundSys_Management(); + #if SOFTWARE_RENDERER + FlushSoftwareZBuffer(); + #else + FlushD3DZBuffer(); + #endifÿ + { + extern void ThisFramesRenderingHasBegun(void); + ThisFramesRenderingHasBegun(); + } + } + + { + menusActive = AvP_InGameMenus(); + if(AvP.RestartLevel) menusActive=0; + } + if (AvP.LevelCompleted) + { + SoundSys_FadeOutFast(); + DoCompletedLevelStatisticsScreen(); + thisLevelHasBeenCompleted = 1; + } + + { + /* after this call, no more graphics can be drawn until the next frame */ + extern void ThisFramesRenderingHasFinished(void); + ThisFramesRenderingHasFinished(); + } + + /* JH 5/6/97 - this function may draw translucent polygons to the whole screen */ + //HandleD3DScreenFading(); + #else + { + + ColourFillBackBuffer(0); + } + #endif + + + InGameFlipBuffers(); + + FrameCounterHandler(); + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + if (!menusActive && playerStatusPtr->IsAlive && !AvP.LevelCompleted) + { + DealWithElapsedTime(); + } + } + break; + } + case I_GM_Menus: + { + AvP.GameMode = I_GM_Playing; + //StartGameMenus(); + LOCALASSERT(AvP.Network == I_No_Network); + //AccessDatabase(0); + break; + } + #if 0 + case I_GM_Paused: + { + { + extern void DoPcPause(void); + DoPcPause(); + } + break; + } + #endif + + default: + { + GLOBALASSERT(2<1); + break; + } + } + + if(AvP.RestartLevel) + { + AvP.RestartLevel=0; + AvP.LevelCompleted = 0; + FixCheatModesInUserProfile(UserProfilePtr); + RestartLevel(); + } + + + }// end of main game loop + { + AvP.LevelCompleted = thisLevelHasBeenCompleted; + } + + FixCheatModesInUserProfile(UserProfilePtr); + + #if !(PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO) + TimeStampedMessage("We're out of the main loop"); + + /* KJL 17:56:14 26/02/98 - unload a font required for Dave's HUD */ +// UnloadFont(&AvpFonts[DATABASE_MESSAGE_FONT]); + #if 1 + { + extern void CloseFMV(void); + CloseFMV(); + ReleaseAllFMVTextures(); + } + #endif + + /* DHM 23/3/98 */ +// REBMENUS_ProjectSpecific_EndOfMainLoopHook(); + + /* DHM 8/4/98 */ + CONSBIND_WriteKeyBindingsToConfigFile(); + TimeStampedMessage("After key bindings writen"); + + /* CDF 2/10/97 */ + DeInitialisePlayer(); + TimeStampedMessage("After DeInitialisePlayer"); + + DeallocatePlayersMirrorImage(); + TimeStampedMessage("After DeallocatePlayersMirrorImage"); + + /* KJL 15:26:43 03/12/97 - clear data */ + KillHUD(); + TimeStampedMessage("After KillHUD"); + + Destroy_CurrentEnvironment(); + TimeStampedMessage("After Destroy_CurrentEnvironment"); + DeallocateAllImages(); + TimeStampedMessage("After DeallocateAllImages"); + EndNPCs(); /* JH 30/4/97 - unload npc rifs */ + TimeStampedMessage("After EndNPCs"); + ExitGame(); + #endif + /* Patrick 26/6/97 + Stop and remove all game sounds here, since we are returning to the menus */ + SoundSys_StopAll(); + ResetEaxEnvironment(); + //make sure the volume gets reset for the menus + SoundSys_ResetFadeLevel(); + + TimeStampedMessage("After SoundSys_StopAll"); + +// SoundSys_RemoveAll(); + + TimeStampedMessage("After SoundSys_RemoveAll"); + CDDA_Stop(); + TimeStampedMessage("After CDDA_Stop"); + + /* netgame support */ + #if SupportWindows95 /* call me paranoid */ + if(AvP.Network != I_No_Network) + { + /* we cleanup and reset our game mode here, at the end of the game loop, as other + clean-up functions need to know if we've just exited a netgame */ + EndAVPNetGame(); + //EndOfNetworkGameScreen(); + } + #endif + + //need to get rid of the player rifs before we can clear the memory pool + + ClearMemoryPool(); + + #if debug + if(UseMouseCentreing) + { + //Stop thread that recentres mouse , making it easier to play + //in subwindow mode + FinishCentreMouseThread(); + } + #endif + + if(LobbiedGame) + { + /* + We have been playing a lobbied game , and have now diconnected. + Since we can't start a new multiplayer game , exit to avoid confusion + */ + break; + } + } + #if !(PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO) + TimeStampedMessage("After Menus"); + + /* Added 28/1/98 by DHM: hook for my code on program shutdown */ + { + DAVEHOOK_UnInit(); + } + TimeStampedMessage("After DAVEHOOK_UnInit"); + + /*-------------------Patrick 2/6/97----------------------- + End the sound system + ----------------------------------------------------------*/ + SoundSys_StopAll(); + SoundSys_RemoveAll(); + + + + + + #else + QuickSplashScreens(); + #endif + #if !(PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO) + TimeStampedMessage("After SoundSys_End"); + TimeStampedMessage("After CDDA_End"); + /* unload language file */ +// KillTextStrings(); +// TimeStampedMessage("After KillTextStrings"); + ExitSystem(); + TimeStampedMessage("After ExitSystem"); + +// ffKill(); /* to avoid misreported memory leaks */ + TimeStampedMessage("After ffKill"); + #else + SoundSys_End(); + ReleaseDirect3D(); + //TimeStampedMessage("after ReleaseDirect3D"); + + /* Kill windows procedures */ + ExitWindowsSystem(); + //TimeStampedMessage("after ExitWindowsSystem"); + + #endif + CDDA_End(); + ClearMemoryPool(); + + AutorunOn(); + + return(0); +} + diff --git a/3dc/avp/win95/winmain.c b/3dc/avp/win95/winmain.c new file mode 100644 index 0000000..072703a --- /dev/null +++ b/3dc/avp/win95/winmain.c @@ -0,0 +1,845 @@ +/* Main designed spec for use with windows95*/ + +#include "3dc.h" +#include "module.h" +#include "inline.h" +#include "stratdef.h" +#include "gamedef.h" +#include "gameplat.h" + +#include "bh_types.h" +#include "usr_io.h" +#include "font.h" + +/* JH 27/1/97 */ +#include "comp_shp.h" + +#include "chnkload.hpp" +#include "npcsetup.h" /* JH 30/4/97 */ +#include "krender.h" +#include "pldnet.h" +#include "avpview.h" +#include "scrshot.hpp" +#include "language.h" +#include "huddefs.h" +#include "vision.h" +#include "pcmenus.h" +#include "multmenu.h" +#include "menudefs.h" +#include "database.h" +#include "avp_menus.h" +#include "kshape.h" +#define UseLocalAssert Yes + +#include "ourasert.h" + +#include "ffstdio.h" // fast file stdio + +#include "davehook.h" + +#include "rebmenus.hpp" +#include "intro.hpp" +#include "showcmds.h" + +#include "consbind.hpp" + +#include "AvpReg.hpp" +#include "mempool.h" +#include "GammaControl.h" + +#include "CDTrackSelection.h" + +/*------------Patrick 1/6/97--------------- +New sound system +-------------------------------------------*/ +#include "psndplat.h" + +#define FRAMEAV 100 + +#include "AvP_UserProfile.h" + +#define PROFILING_ON 0 +#if PROFILING_ON +#include "pentime.h" +#endif + +#if 0 +#undef PrintDebuggingText +extern int PrintDebuggingText(const char* t, ...); +#endif + +/* + + externs for commonly used global variables and arrays + +*/ +extern int VideoMode; +extern void (*UpdateScreen[]) (void); +extern DISPLAYBLOCK* ActiveBlockList[]; +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; +extern void (*SetVideoMode[]) (void); +extern int FrameRate; + +extern int WindowRequestMode; + +extern int NumActiveBlocks; +int HWAccel = 0; + +#if debug +#define MainTextPrint 1 +extern int alloc_cnt, deall_cnt; +extern int ItemCount; +int DebugFontLoaded = 0; + +extern BOOL ForceLoad_Alien; +extern BOOL ForceLoad_Marine; +extern BOOL ForceLoad_Predator; +extern BOOL ForceLoad_Hugger; +extern BOOL ForceLoad_Queen; +extern BOOL ForceLoad_Civvie; +extern BOOL ForceLoad_PredAlien; +extern BOOL ForceLoad_Xenoborg; +extern BOOL ForceLoad_Pretorian; +extern BOOL ForceLoad_SentryGun; + + +BOOL UseMouseCentreing = FALSE; +#else +#define MainTextPrint 0 +#endif + +BOOL KeepMainRifFile=FALSE; + +extern void LoadKeyConfiguration(); +extern void DeInitialisePlayer(); + +extern int AvP_MainMenus(void); +extern int AvP_InGameMenus(void); + +extern IngameKeyboardInput_ClearBuffer(void); + +HINSTANCE AVP_HInstance, hInst; +int AVP_NCmd; + +extern unsigned long TotalMemAllocated; + +char LevelName[] = {"predbit6\0QuiteALongNameActually"}; +static ELO ELOLevelToLoad = {&LevelName}; + +int QuickStartMultiplayer=1; + +int VideoModeNotAvailable=0; + +extern int DebuggingCommandsActive; + +extern void BuildMultiplayerLevelNameArray(); + +extern int WindowMode; +void exit_break_point_fucntion () +{ + #if debug + if (WindowMode == WindowModeSubWindow) + { + __asm int 3; + } + #endif +} + + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpCmdLine, int nCmdShow) +{ + char * instr; + #if debug + int level_to_load = I_Num_Environments; + char * command_line = lpCmdLine; + #endif + + AVP_HInstance = hInst = hInstance; + AVP_NCmd = nCmdShow; + + EnumerateCardsAndVideoModes(); + + LoadCDTrackList(); //load list of cd tracks assigned to levels , from a text file + + +// CDDA_Start(); +// CDDA_Play(1); + + SetFastRandom(); + + /**** init game now ONLY sets up varibles for the whole + game. If you want to put something in it it must + be something that only needs to be called once + ****/ + #if debug && 1//!PREDATOR_DEMO + { + #if OverrideOldMenus + { + HWAccel = 1; + } + #else + if(strstr(command_line, "-h")) + { + HWAccel = 1; + } + #endif + + //see if any extra npc rif files should be loaded + { + char* strpos=strstr(command_line, "-l"); + if(strpos) + { + while(strpos) + { + strpos+=2; + if(*strpos>='a' && *strpos<='z') + { + while(*strpos>='a' && *strpos<='z') + { + switch (*strpos) + { + case 'a': + ForceLoad_Alien = TRUE; + break; + case 'm': + ForceLoad_Marine = TRUE; + break; + case 'p': + ForceLoad_Predator = TRUE; + break; + case 'h': + ForceLoad_Hugger = TRUE; + break; + case 'q': + ForceLoad_Queen = TRUE; + break; + case 'c': + ForceLoad_Civvie = TRUE; + break; + case 'x': + ForceLoad_Xenoborg = TRUE; + break; + case 't': + ForceLoad_Pretorian = TRUE; + break; + case 'r': + ForceLoad_PredAlien = TRUE; + break; + case 's': + ForceLoad_SentryGun = TRUE; + break; + } + strpos++; + } + } + else + { + ForceLoad_Alien = TRUE; + } + strpos=strstr(strpos,"-l"); + } + } + } + + #ifdef AVP_DEBUG_VERSION + if (strstr(command_line, "-intro")) WeWantAnIntro(); + if (strstr(command_line, "-qm")) + { + QuickStartMultiplayer = 1; + } + else if (strstr(command_line, "-qa")) + { + QuickStartMultiplayer = 2; + } + else if (strstr(command_line, "-qp")) + { + QuickStartMultiplayer = 3; + } + else + { + QuickStartMultiplayer = 0; + } + + if(strstr(command_line,"-keeprif")) + { + KeepMainRifFile=TRUE; + } + + if (strstr(command_line, "-m")) + { + UseMouseCentreing = 1; + } + #endif //AVP_DEBUG_VERSION + } + #else + { + #if OverrideOldMenus + { + HWAccel = 1; + } + #endif + } + #endif + + if(strstr(command_line,"-server")) + { + extern int DirectPlay_InitLobbiedGame(); + //game has been launched by mplayer , we best humour it + LobbiedGame=LobbiedGame_Server; + if(!DirectPlay_InitLobbiedGame()) + { + exit(0x6364); + } + } + else if(strstr(command_line,"-client")) + { + extern int DirectPlay_InitLobbiedGame(); + //ditto + LobbiedGame=LobbiedGame_Client; + if(!DirectPlay_InitLobbiedGame()) + { + exit(0x6364); + } + } + else if (strstr(command_line, "-debug")) + { + DebuggingCommandsActive = 1; + } + + if(instr = strstr(command_line, "-ip")) + { + char buffer[100]; + extern char CommandLineIPAddressString[]; + + sscanf(instr, "-ip %s", &buffer); + strncpy(CommandLineIPAddressString,buffer,15); + CommandLineIPAddressString[15] = 0; + } + + + // Modified by Edmond for mplayer demo + #if MPLAYER_DEMO + if (!LobbiedGame) + { + MessageBox(NULL, "This demo can only be launched from Mplayer.", "Oh no!", MB_OK); + exit(33445); + } + #endif + + #if PLAY_INTRO//(MARINE_DEMO||ALIEN_DEMO||PREDATOR_DEMO) + if (!LobbiedGame) // Edmond + WeWantAnIntro(); + #endif + GetPathFromRegistry(); + + /* JH 28/5/97 */ + /* Initialise 'fast' file system */ + #if MARINE_DEMO + ffInit("fastfile\\mffinfo.txt","fastfile\\"); + #elif ALIEN_DEMO + ffInit("alienfastfile\\ffinfo.txt","alienfastfile\\"); + #else + ffInit("fastfile\\ffinfo.txt","fastfile\\"); + #endif + + InitGame(); + + + /*** Define video mode for windows initialisation ***/ + InitialVideoMode(); + + /****** Put in by John to sort out easy sub window mode ******/ + /****** REMOVE FOR GAME!!!!! ******/ + + #if debug && 1//!PREDATOR_DEMO + if(strstr(command_line, "-w")) + { + WindowRequestMode = WindowModeSubWindow; + if (!HWAccel) + RasterisationRequestMode = RequestSoftwareRasterisation; + } + if(instr = strstr(command_line, "-s")) + sscanf(instr, "-s%d", &level_to_load); + + #endif + + Env_List[0] = &(ELOLevelToLoad); + level_to_load = 0; + + /******* System initialisation **********/ + InitialiseSystem(hInstance, nCmdShow); + InitialiseRenderer(); + + InitOptionsMenu(); /* by this time we know all about the video card, etc */ + + LoadKeyConfiguration(); + /********** Grab The Video mode **********/ + /* JH - nope, not yet; not until we start the menus + (or if debugging, start the game), do we need to + set the initial video mode */ + + + /*-------------------Patrick 2/6/97----------------------- + Start the sound system + ----------------------------------------------------------*/ + SoundSys_Start(); + CDDA_Start(); + + /* kill mouse cursor */ + SetCursor(NULL); + + /* load language file and setup text string access */ + InitTextStrings(); + + BuildMultiplayerLevelNameArray();//sort out multiplayer level names + + ChangeDirectDrawObject(); + AvP.LevelCompleted = 0; + LoadSounds("PLAYER"); + + #if PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO + if(AvP_MainMenus()) + #else + while(AvP_MainMenus()) + #endif + { + int menusActive=0; + int thisLevelHasBeenCompleted=0; + #if !(PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO) + if(instr = strstr(command_line, "-n")) + { + sscanf(instr, "-n %s", &LevelName); + } + #endif + + #if debug + if(UseMouseCentreing) + { + //Start thread that recentres mouse , making it easier to play + //in subwindow mode + InitCentreMouseThread(); + } + #endif +// Env_List[0] = &(ELOLevelToLoad); +// level_to_load = 0; +// AvP.PlayerType = I_Marine; + + + /* turn off any special effects */ + d3d_light_ctrl.ctrl = LCCM_NORMAL; + d3d_overlay_ctrl.ctrl = OCCM_NORMAL; + + /* JH 20/5/97 + The video mode is no longer set when exiting the menus + (not necessary if user selects EXIT) + So it is set here */ + + /********** Grab The Video mode **********/ + GetCorrectDirectDrawObject(); + + if(!SetGameVideoMode()) + { + VideoModeNotAvailable=1; + continue; + } + + /* Dubious restart hack for DirectDraw problems */ + /* JH - I'm not sure this is really necessary + - it only comes into play if you try and set + a video mode which is not supported + BUT we are never going to try and do that + - or are we? */ + HandleVideoModeRestarts(hInstance, nCmdShow); + + + /* Check Gamma Settings are correct after video mode change */ + InitialiseGammaSettings(RequestedGammaSetting); + + + + + /**** init the chunk loaders ***************/ + + // no longer required here + + // Load precompiled shapes + start_of_loaded_shapes = load_precompiled_shapes(); + + /*********** Load up the character stuff *******/ + + InitCharacter(); + + /* KJL 17:56:14 26/02/98 - load a font required for Dave's HUD */ +// LoadPFFont(DATABASE_MESSAGE_FONT); + + /*********** Read in the env Map **************/ + + #if debug + if(level_to_load != I_Num_Environments) + { + if((level_to_load < 0) || (level_to_load > I_Num_Environments)) + #ifdef MPLAYER_DEMO + level_to_load = I_Dml1; + #else + level_to_load = I_Sp1; + #endif + + AvP.CurrentEnv = AvP.StartingEnv = level_to_load; + } + #endif + + LoadRifFile(); /* sets up a map*/ + #if debug + DebugFontLoaded = 1; + #endif + + /*********** Process the data ************/ + AssignAllSBNames(); + StartGame(); + +// UnloadRifFile();//deletes environment File_Chunk since it is no longer needed + + + /* Patrick 26/6/97 + Load the game sounds here: should be done after loading everthing + else, incase sounds take up system memory */ +// LoadSounds("PLAYER"); + + /* JH 28/5/97 */ + /* remove resident loaded 'fast' files */ + ffcloseall(); + /*********** Play the game ***************/ + + /* KJL 15:43:25 03/11/97 - run until this boolean is set to 0 */ + AvP.MainLoopRunning = 1; + + ScanImagesForFMVs(); + + ResetFrameCounter(); + Game_Has_Loaded(); + ResetFrameCounter(); + + if(AvP.Network!=I_No_Network) + { + /*Need to choose a starting position for the player , but first we must look + through the network messages to find out which generator spots are currently clear*/ + netGameData.myGameState = NGS_Playing; + MinimalNetCollectMessages(); + TeleportNetPlayerToAStartingPosition(Player->ObStrategyBlock,1); + } + + IngameKeyboardInput_ClearBuffer(); + while(AvP.MainLoopRunning) + { + + #if debug + #if 0 + DumpBoundsCheckInfo(DUMPTOSCREEN); + #endif + #endif + + CheckForWindowsMessages(); + CursorHome(); + + #if debug + if (memoryInitialisationFailure) + { + textprint("Initialisation not completed - out of memory!\n"); + GLOBALASSERT(1 == 0); + } + #endif + + switch(AvP.GameMode) + { + case I_GM_Playing: + { + if ((!menusActive || (AvP.Network!=I_No_Network && !netGameData.skirmishMode)) && !AvP.LevelCompleted) + { + #if MainTextPrint /* debugging stuff */ + { + + if (ShowDebuggingText.FPS) ReleasePrintDebuggingText("FrameRate = %d fps\n",FrameRate); + if (ShowDebuggingText.Environment) ReleasePrintDebuggingText("Environment %s\n", Env_List[AvP.CurrentEnv]->main); + if (ShowDebuggingText.Coords) ReleasePrintDebuggingText("Player World Coords: %d,%d,%d\n",Player->ObWorld.vx,Player->ObWorld.vy,Player->ObWorld.vz); + + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); + TEMPLATE_WEAPON_DATA *twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; + if (ShowDebuggingText.GunPos) + { + PrintDebuggingText("Gun Position x:%d,y:%d,z:%d\n",twPtr->RestPosition.vx,twPtr->RestPosition.vy,twPtr->RestPosition.vz); + } + } + } + #endif /* MainTextPrint */ + + DoAllShapeAnimations(); + + UpdateGame(); + + #if 1 + #if PROFILING_ON + ProfileStart(); + #endif + AvpShowViews(); + #if PROFILING_ON + ProfileStop("SHOW VIEW"); + #endif + + //Do screen shot here so that text and hud graphics aren't shown + #if PROFILING_ON + ProfileStart(); + #endif + MaintainHUD(); + #if PROFILING_ON + ProfileStop("RENDER HUD"); + #endif + + #if debug + FlushTextprintBuffer(); + #endif + + //check cd status + CheckCDAndChooseTrackIfNeeded(); + + // check to see if we're pausing the game; + // if so kill off any sound effects + if(InGameMenusAreRunning() && ( (AvP.Network!=I_No_Network && netGameData.skirmishMode) || (AvP.Network==I_No_Network)) ) + SoundSys_StopAll(); + } + else + { + ReadUserInput(); +// UpdateAllFMVTextures(); + SoundSys_Management(); + #if SOFTWARE_RENDERER + FlushSoftwareZBuffer(); + #else + FlushD3DZBuffer(); + #endifÿ + { + extern void ThisFramesRenderingHasBegun(void); + ThisFramesRenderingHasBegun(); + } + } + + { + menusActive = AvP_InGameMenus(); + if(AvP.RestartLevel) menusActive=0; + } + if (AvP.LevelCompleted) + { + SoundSys_FadeOutFast(); + DoCompletedLevelStatisticsScreen(); + thisLevelHasBeenCompleted = 1; + } + + { + /* after this call, no more graphics can be drawn until the next frame */ + extern void ThisFramesRenderingHasFinished(void); + ThisFramesRenderingHasFinished(); + } + + /* JH 5/6/97 - this function may draw translucent polygons to the whole screen */ + //HandleD3DScreenFading(); + #else + { + + ColourFillBackBuffer(0); + } + #endif + + + InGameFlipBuffers(); + + FrameCounterHandler(); + { + PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); + + if (!menusActive && playerStatusPtr->IsAlive && !AvP.LevelCompleted) + { + DealWithElapsedTime(); + } + } + break; + } + case I_GM_Menus: + { + AvP.GameMode = I_GM_Playing; + //StartGameMenus(); + LOCALASSERT(AvP.Network == I_No_Network); + //AccessDatabase(0); + break; + } + #if 0 + case I_GM_Paused: + { + { + extern void DoPcPause(void); + DoPcPause(); + } + break; + } + #endif + + default: + { + GLOBALASSERT(2<1); + break; + } + } + + if(AvP.RestartLevel) + { + AvP.RestartLevel=0; + AvP.LevelCompleted = 0; + FixCheatModesInUserProfile(UserProfilePtr); + RestartLevel(); + } + + + }// end of main game loop + { + AvP.LevelCompleted = thisLevelHasBeenCompleted; + } + + FixCheatModesInUserProfile(UserProfilePtr); + + #if !(PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO) + TimeStampedMessage("We're out of the main loop"); + + /* KJL 17:56:14 26/02/98 - unload a font required for Dave's HUD */ +// UnloadFont(&AvpFonts[DATABASE_MESSAGE_FONT]); + #if 1 + { + extern void CloseFMV(void); + CloseFMV(); + ReleaseAllFMVTextures(); + } + #endif + + /* DHM 23/3/98 */ +// REBMENUS_ProjectSpecific_EndOfMainLoopHook(); + + /* DHM 8/4/98 */ + CONSBIND_WriteKeyBindingsToConfigFile(); + TimeStampedMessage("After key bindings writen"); + + /* CDF 2/10/97 */ + DeInitialisePlayer(); + TimeStampedMessage("After DeInitialisePlayer"); + + DeallocatePlayersMirrorImage(); + TimeStampedMessage("After DeallocatePlayersMirrorImage"); + + /* KJL 15:26:43 03/12/97 - clear data */ + KillHUD(); + TimeStampedMessage("After KillHUD"); + + Destroy_CurrentEnvironment(); + TimeStampedMessage("After Destroy_CurrentEnvironment"); + DeallocateAllImages(); + TimeStampedMessage("After DeallocateAllImages"); + EndNPCs(); /* JH 30/4/97 - unload npc rifs */ + TimeStampedMessage("After EndNPCs"); + ExitGame(); + #endif + /* Patrick 26/6/97 + Stop and remove all game sounds here, since we are returning to the menus */ + SoundSys_StopAll(); + ResetEaxEnvironment(); + //make sure the volume gets reset for the menus + SoundSys_ResetFadeLevel(); + + TimeStampedMessage("After SoundSys_StopAll"); + +// SoundSys_RemoveAll(); + + TimeStampedMessage("After SoundSys_RemoveAll"); + CDDA_Stop(); + TimeStampedMessage("After CDDA_Stop"); + + /* netgame support */ + #if SupportWindows95 /* call me paranoid */ + if(AvP.Network != I_No_Network) + { + /* we cleanup and reset our game mode here, at the end of the game loop, as other + clean-up functions need to know if we've just exited a netgame */ + EndAVPNetGame(); + //EndOfNetworkGameScreen(); + } + #endif + + //need to get rid of the player rifs before we can clear the memory pool + + ClearMemoryPool(); + + #if debug + if(UseMouseCentreing) + { + //Stop thread that recentres mouse , making it easier to play + //in subwindow mode + FinishCentreMouseThread(); + } + #endif + + if(LobbiedGame) + { + /* + We have been playing a lobbied game , and have now diconnected. + Since we can't start a new multiplayer game , exit to avoid confusion + */ + break; + } + } + #if !(PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO) + TimeStampedMessage("After Menus"); + + /* Added 28/1/98 by DHM: hook for my code on program shutdown */ + { + DAVEHOOK_UnInit(); + } + TimeStampedMessage("After DAVEHOOK_UnInit"); + + /*-------------------Patrick 2/6/97----------------------- + End the sound system + ----------------------------------------------------------*/ + SoundSys_StopAll(); + SoundSys_RemoveAll(); + + + + + + #else + QuickSplashScreens(); + #endif + #if !(PREDATOR_DEMO||MARINE_DEMO||ALIEN_DEMO) + TimeStampedMessage("After SoundSys_End"); + TimeStampedMessage("After CDDA_End"); + /* unload language file */ +// KillTextStrings(); +// TimeStampedMessage("After KillTextStrings"); + ExitSystem(); + TimeStampedMessage("After ExitSystem"); + +// ffKill(); /* to avoid misreported memory leaks */ + TimeStampedMessage("After ffKill"); + #else + SoundSys_End(); + ReleaseDirect3D(); + //TimeStampedMessage("after ReleaseDirect3D"); + + /* Kill windows procedures */ + ExitWindowsSystem(); + //TimeStampedMessage("after ExitWindowsSystem"); + + #endif + CDDA_End(); + ClearMemoryPool(); + + return(0); +} + diff --git a/3dc/binkw32.dll b/3dc/binkw32.dll new file mode 100644 index 0000000..8ea0230 Binary files /dev/null and b/3dc/binkw32.dll differ diff --git a/3dc/binkw32.lib b/3dc/binkw32.lib new file mode 100644 index 0000000..9b6ba53 Binary files /dev/null and b/3dc/binkw32.lib differ diff --git a/3dc/default.cfg b/3dc/default.cfg new file mode 100644 index 0000000..ab08607 Binary files /dev/null and b/3dc/default.cfg differ diff --git a/3dc/dialog.dll b/3dc/dialog.dll new file mode 100644 index 0000000..d45fbc0 Binary files /dev/null and b/3dc/dialog.dll differ diff --git a/3dc/dialog.lib b/3dc/dialog.lib new file mode 100644 index 0000000..9fbdb8d Binary files /dev/null and b/3dc/dialog.lib differ diff --git a/3dc/fontbr.pgm b/3dc/fontbr.pgm new file mode 100644 index 0000000..b66111b Binary files /dev/null and b/3dc/fontbr.pgm differ diff --git a/3dc/frustrum.c b/3dc/frustrum.c new file mode 100644 index 0000000..d3e929d --- /dev/null +++ b/3dc/frustrum.c @@ -0,0 +1,1275 @@ +/* + * KJL 15:13:43 7/17/97 - frustrum.c + * + * Contains all the functions connected + * to the view frustrum and clipping + * + */ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "stratdef.h" +#include "gamedef.h" + +#include "kshape.h" +#include "kzsort.h" +#include "frustrum.h" + +#include "particle.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +/*KJL**************************************************************************************** +* G L O B A L S * +****************************************************************************************KJL*/ +extern VECTORCH RotatedPts[]; + +extern DISPLAYBLOCK *Global_ODB_Ptr; +extern SHAPEHEADER *Global_ShapeHeaderPtr; +extern int *Global_ShapePoints; +extern int *Global_ShapeNormals; + +extern VECTORCH LocalView; + +#define FAR_Z_CLIP 0 +#define FAR_Z_CLIP_RANGE 49000 +/*KJL**************************************************************************************** +* P R O T O T Y P E S * +****************************************************************************************KJL*/ +/* GOURAUD POLYGON CLIPPING */ +void (*GouraudPolygon_ClipWithNegativeX)(void); +void (*GouraudPolygon_ClipWithPositiveY)(void); +void (*GouraudPolygon_ClipWithNegativeY)(void); +void (*GouraudPolygon_ClipWithPositiveX)(void); + +/* TEXTURED POLYGON CLIPPING */ +void (*TexturedPolygon_ClipWithNegativeX)(void); +void (*TexturedPolygon_ClipWithPositiveY)(void); +void (*TexturedPolygon_ClipWithNegativeY)(void); +void (*TexturedPolygon_ClipWithPositiveX)(void); + +/* GOURAUD TEXTURED POLYGON CLIPPING */ +void (*GouraudTexturedPolygon_ClipWithNegativeX)(void); +void (*GouraudTexturedPolygon_ClipWithPositiveY)(void); +void (*GouraudTexturedPolygon_ClipWithNegativeY)(void); +void (*GouraudTexturedPolygon_ClipWithPositiveX)(void); + +/* FRUSTRUM TESTS */ +int (*ObjectWithinFrustrum)(DISPLAYBLOCK *dbPtr); +int (*ObjectCompletelyWithinFrustrum)(DISPLAYBLOCK *dbPtr); +int (*VertexWithinFrustrum)(RENDERVERTEX *vertexPtr); +void (*TestVerticesWithFrustrum)(void); + + +static void GouraudPolygon_Norm_ClipWithNegativeX(void); +static void GouraudPolygon_Wide_ClipWithNegativeX(void); +static void GouraudPolygon_Norm_ClipWithPositiveY(void); +static void GouraudPolygon_Wide_ClipWithPositiveY(void); +static void GouraudPolygon_Norm_ClipWithNegativeY(void); +static void GouraudPolygon_Wide_ClipWithNegativeY(void); +static void GouraudPolygon_Norm_ClipWithPositiveX(void); +static void GouraudPolygon_Wide_ClipWithPositiveX(void); + +static void TexturedPolygon_Norm_ClipWithNegativeX(void); +static void TexturedPolygon_Wide_ClipWithNegativeX(void); +static void TexturedPolygon_Norm_ClipWithPositiveY(void); +static void TexturedPolygon_Wide_ClipWithPositiveY(void); +static void TexturedPolygon_Norm_ClipWithNegativeY(void); +static void TexturedPolygon_Wide_ClipWithNegativeY(void); +static void TexturedPolygon_Norm_ClipWithPositiveX(void); +static void TexturedPolygon_Wide_ClipWithPositiveX(void); + +static void GouraudTexturedPolygon_Norm_ClipWithNegativeX(void); +static void GouraudTexturedPolygon_Wide_ClipWithNegativeX(void); +static void GouraudTexturedPolygon_Norm_ClipWithPositiveY(void); +static void GouraudTexturedPolygon_Wide_ClipWithPositiveY(void); +static void GouraudTexturedPolygon_Norm_ClipWithNegativeY(void); +static void GouraudTexturedPolygon_Wide_ClipWithNegativeY(void); +static void GouraudTexturedPolygon_Norm_ClipWithPositiveX(void); +static void GouraudTexturedPolygon_Wide_ClipWithPositiveX(void); + +static int VertexWithin_Norm_Frustrum(RENDERVERTEX *vertexPtr); +static int VertexWithin_Wide_Frustrum(RENDERVERTEX *vertexPtr); +static int ObjectWithin_Norm_Frustrum(DISPLAYBLOCK *dbPtr); +static int ObjectWithin_Wide_Frustrum(DISPLAYBLOCK *dbPtr); +static int ObjectCompletelyWithin_Norm_Frustrum(DISPLAYBLOCK *dbPtr); +static int ObjectCompletelyWithin_Wide_Frustrum(DISPLAYBLOCK *dbPtr); +static void TestVerticesWith_Norm_Frustrum(void); +static void TestVerticesWith_Wide_Frustrum(void); + +/*KJL**************************************************************************************** +* F U N C T I O N S * +****************************************************************************************KJL*/ +void SetFrustrumType(enum FrustrumType frustrumType) +{ + switch (frustrumType) + { + default: + case FRUSTRUM_TYPE_NORMAL: + { + /* GOURAUD POLYGON CLIPPING */ + GouraudPolygon_ClipWithNegativeX = GouraudPolygon_Norm_ClipWithNegativeX; + GouraudPolygon_ClipWithPositiveY = GouraudPolygon_Norm_ClipWithPositiveY; + GouraudPolygon_ClipWithNegativeY = GouraudPolygon_Norm_ClipWithNegativeY; + GouraudPolygon_ClipWithPositiveX = GouraudPolygon_Norm_ClipWithPositiveX; + + /* TEXTURED POLYGON CLIPPING */ + TexturedPolygon_ClipWithNegativeX = TexturedPolygon_Norm_ClipWithNegativeX; + TexturedPolygon_ClipWithPositiveY = TexturedPolygon_Norm_ClipWithPositiveY; + TexturedPolygon_ClipWithNegativeY = TexturedPolygon_Norm_ClipWithNegativeY; + TexturedPolygon_ClipWithPositiveX = TexturedPolygon_Norm_ClipWithPositiveX; + + /* GOURAUD TEXTURED POLYGON CLIPPING */ + GouraudTexturedPolygon_ClipWithNegativeX = GouraudTexturedPolygon_Norm_ClipWithNegativeX; + GouraudTexturedPolygon_ClipWithPositiveY = GouraudTexturedPolygon_Norm_ClipWithPositiveY; + GouraudTexturedPolygon_ClipWithNegativeY = GouraudTexturedPolygon_Norm_ClipWithNegativeY; + GouraudTexturedPolygon_ClipWithPositiveX = GouraudTexturedPolygon_Norm_ClipWithPositiveX; + + /* FRUSTRUM TESTS */ + TestVerticesWithFrustrum = TestVerticesWith_Norm_Frustrum; + ObjectWithinFrustrum = ObjectWithin_Norm_Frustrum; + ObjectCompletelyWithinFrustrum = ObjectCompletelyWithin_Norm_Frustrum; + VertexWithinFrustrum = VertexWithin_Norm_Frustrum; + + break; + } + + case FRUSTRUM_TYPE_WIDE: + { + /* GOURAUD POLYGON CLIPPING */ + GouraudPolygon_ClipWithNegativeX = GouraudPolygon_Wide_ClipWithNegativeX; + GouraudPolygon_ClipWithPositiveY = GouraudPolygon_Wide_ClipWithPositiveY; + GouraudPolygon_ClipWithNegativeY = GouraudPolygon_Wide_ClipWithNegativeY; + GouraudPolygon_ClipWithPositiveX = GouraudPolygon_Wide_ClipWithPositiveX; + + /* TEXTURED POLYGON CLIPPING */ + TexturedPolygon_ClipWithNegativeX = TexturedPolygon_Wide_ClipWithNegativeX; + TexturedPolygon_ClipWithPositiveY = TexturedPolygon_Wide_ClipWithPositiveY; + TexturedPolygon_ClipWithNegativeY = TexturedPolygon_Wide_ClipWithNegativeY; + TexturedPolygon_ClipWithPositiveX = TexturedPolygon_Wide_ClipWithPositiveX; + + /* GOURAUD TEXTURED POLYGON CLIPPING */ + GouraudTexturedPolygon_ClipWithNegativeX = GouraudTexturedPolygon_Wide_ClipWithNegativeX; + GouraudTexturedPolygon_ClipWithPositiveY = GouraudTexturedPolygon_Wide_ClipWithPositiveY; + GouraudTexturedPolygon_ClipWithNegativeY = GouraudTexturedPolygon_Wide_ClipWithNegativeY; + GouraudTexturedPolygon_ClipWithPositiveX = GouraudTexturedPolygon_Wide_ClipWithPositiveX; + + /* FRUSTRUM TESTS */ + TestVerticesWithFrustrum = TestVerticesWith_Wide_Frustrum; + ObjectWithinFrustrum = ObjectWithin_Wide_Frustrum; + ObjectCompletelyWithinFrustrum = ObjectCompletelyWithin_Wide_Frustrum; + VertexWithinFrustrum = VertexWithin_Wide_Frustrum; + + break; + } + } +} + +/* clipping code macros - these are used as building blocks to assemble +clipping fns for different polygon types with the minimum of fuss */ +#define ZCLIPPINGVALUE 4 +//64 +#define Clip_Z_Test(v) (ZCLIPPINGVALUE <= (v)->Z) +#define Clip_NX_Test(v) (-(v)->X <= (v)->Z) +#define Clip_PX_Test(v) ((v)->X <= (v)->Z) +#define Clip_NY_Test(v) (-(v)->Y <= (v)->Z) +#define Clip_PY_Test(v) ((v)->Y <= (v)->Z) + + +#define Clip_LoopStart(b) \ + do \ + { \ + RENDERVERTEX *nextVertexPtr; \ + int nextVertexInside; \ + \ + /* setup pointer to next vertex, wrapping round if necessary */ \ + if (!--verticesLeft) \ + { \ + nextVertexPtr = (b); \ + } \ + else \ + { \ + nextVertexPtr = curVertexPtr+1; \ + } \ + \ + /* if current vertex is inside the plane, output it */ \ + if (curVertexInside) \ + { \ + numberOfPointsOutputted++; \ + *outputVerticesPtr++ = *curVertexPtr; \ + } \ + \ + /* test if next vertex is inside the plane */ \ + nextVertexInside = + +#define Clip_Z_OutputXYZ \ + /* if one is in, and the other is out, output a clipped vertex */ \ + if (nextVertexInside != curVertexInside) \ + { \ + int lambda; \ + \ + lambda = DIV_FIXED \ + ( \ + (ZCLIPPINGVALUE - curVertexPtr->Z), \ + (nextVertexPtr->Z - curVertexPtr->Z) \ + ); \ + \ + outputVerticesPtr->X = curVertexPtr->X + MUL_FIXED(lambda,nextVertexPtr->X-curVertexPtr->X); \ + outputVerticesPtr->Y = curVertexPtr->Y + MUL_FIXED(lambda,nextVertexPtr->Y-curVertexPtr->Y); \ + outputVerticesPtr->Z = ZCLIPPINGVALUE; + +#define Clip_NX_OutputXYZ \ + /* if one is in, and the other is out, output a clipped vertex */ \ + if (nextVertexInside != curVertexInside) \ + { \ + int lambda; \ + \ + lambda = DIV_FIXED \ + ( \ + (curVertexPtr->Z + curVertexPtr->X), \ + -(nextVertexPtr->X-curVertexPtr->X) - (nextVertexPtr->Z-curVertexPtr->Z) \ + ); \ + \ + outputVerticesPtr->X = curVertexPtr->X + MUL_FIXED(lambda,nextVertexPtr->X-curVertexPtr->X); \ + outputVerticesPtr->Z = -outputVerticesPtr->X; \ + outputVerticesPtr->Y = curVertexPtr->Y + MUL_FIXED(lambda,nextVertexPtr->Y-curVertexPtr->Y); + +#define Clip_PX_OutputXYZ \ + /* if one is in, and the other is out, output a clipped vertex */ \ + if (nextVertexInside != curVertexInside) \ + { \ + int lambda; \ + \ + lambda = DIV_FIXED \ + ( \ + (curVertexPtr->Z - curVertexPtr->X), \ + (nextVertexPtr->X-curVertexPtr->X) - (nextVertexPtr->Z-curVertexPtr->Z) \ + ); \ + \ + outputVerticesPtr->X = curVertexPtr->X + MUL_FIXED(lambda,nextVertexPtr->X-curVertexPtr->X); \ + outputVerticesPtr->Z = outputVerticesPtr->X; \ + outputVerticesPtr->Y = curVertexPtr->Y + MUL_FIXED(lambda,nextVertexPtr->Y-curVertexPtr->Y); + +#define Clip_NY_OutputXYZ \ + /* if one is in, and the other is out, output a clipped vertex */ \ + if (nextVertexInside != curVertexInside) \ + { \ + int lambda; \ + \ + lambda = DIV_FIXED \ + ( \ + (curVertexPtr->Z + curVertexPtr->Y), \ + -(nextVertexPtr->Y-curVertexPtr->Y) - (nextVertexPtr->Z-curVertexPtr->Z) \ + ); \ + \ + outputVerticesPtr->Z = curVertexPtr->Z + MUL_FIXED(lambda,nextVertexPtr->Z-curVertexPtr->Z); \ + outputVerticesPtr->Y = -(outputVerticesPtr->Z); \ + outputVerticesPtr->X = curVertexPtr->X + MUL_FIXED(lambda,nextVertexPtr->X-curVertexPtr->X); + +#define Clip_PY_OutputXYZ \ + /* if one is in, and the other is out, output a clipped vertex */ \ + if (nextVertexInside != curVertexInside) \ + { \ + int lambda; \ + \ + lambda = DIV_FIXED \ + ( \ + (curVertexPtr->Z - curVertexPtr->Y), \ + (nextVertexPtr->Y-curVertexPtr->Y) - (nextVertexPtr->Z-curVertexPtr->Z) \ + ); \ + \ + outputVerticesPtr->Z = curVertexPtr->Z + MUL_FIXED(lambda,nextVertexPtr->Z-curVertexPtr->Z); \ + outputVerticesPtr->Y = (outputVerticesPtr->Z); \ + outputVerticesPtr->X = curVertexPtr->X + MUL_FIXED(lambda,nextVertexPtr->X-curVertexPtr->X); + +#define Clip_OutputUV \ + outputVerticesPtr->U = curVertexPtr->U + MUL_FIXED(lambda,nextVertexPtr->U-curVertexPtr->U); \ + outputVerticesPtr->V = curVertexPtr->V + MUL_FIXED(lambda,nextVertexPtr->V-curVertexPtr->V); + +#define Clip_OutputI \ + outputVerticesPtr->A = curVertexPtr->A + MUL_FIXED(lambda,nextVertexPtr->A-curVertexPtr->A); \ + outputVerticesPtr->R = curVertexPtr->R + MUL_FIXED(lambda,nextVertexPtr->R-curVertexPtr->R); \ + outputVerticesPtr->G = curVertexPtr->G + MUL_FIXED(lambda,nextVertexPtr->G-curVertexPtr->G); \ + outputVerticesPtr->B = curVertexPtr->B + MUL_FIXED(lambda,nextVertexPtr->B-curVertexPtr->B); \ + outputVerticesPtr->SpecularR = curVertexPtr->SpecularR + MUL_FIXED(lambda,nextVertexPtr->SpecularR-curVertexPtr->SpecularR); \ + outputVerticesPtr->SpecularG = curVertexPtr->SpecularG + MUL_FIXED(lambda,nextVertexPtr->SpecularG-curVertexPtr->SpecularG); \ + outputVerticesPtr->SpecularB = curVertexPtr->SpecularB + MUL_FIXED(lambda,nextVertexPtr->SpecularB-curVertexPtr->SpecularB); + +#define Clip_LoopEnd(b) \ + numberOfPointsOutputted++; \ + outputVerticesPtr++; \ + } \ + \ + /* okay, now the current vertex becomes what was the next vertex */ \ + curVertexPtr = nextVertexPtr; \ + curVertexInside = nextVertexInside; \ + } \ + while(verticesLeft); \ + \ + RenderPolygon.NumberOfVertices = numberOfPointsOutputted; + +/* Wide screen versions of clip macros */ + +#define Clip_Wide_NX_Test(v) (-(v)->X <= (v)->Z*2) +#define Clip_Wide_PX_Test(v) ((v)->X <= (v)->Z*2) +#define Clip_Wide_NY_Test(v) (-(v)->Y <= (v)->Z*2) +#define Clip_Wide_PY_Test(v) ((v)->Y <= (v)->Z*2) +#define Clip_Wide_NX_OutputXYZ \ + /* if one is in, and the other is out, output a clipped vertex */ \ + if (nextVertexInside != curVertexInside) \ + { \ + int lambda; \ + \ + lambda = DIV_FIXED \ + ( \ + (-2*curVertexPtr->Z - curVertexPtr->X), \ + (nextVertexPtr->X-curVertexPtr->X) - (-2)*(nextVertexPtr->Z-curVertexPtr->Z) \ + ); \ + \ + outputVerticesPtr->X = curVertexPtr->X + MUL_FIXED(lambda,nextVertexPtr->X-curVertexPtr->X); \ + outputVerticesPtr->Z = -outputVerticesPtr->X/2; \ + outputVerticesPtr->Y = curVertexPtr->Y + MUL_FIXED(lambda,nextVertexPtr->Y-curVertexPtr->Y); + +#define Clip_Wide_PX_OutputXYZ \ + /* if one is in, and the other is out, output a clipped vertex */ \ + if (nextVertexInside != curVertexInside) \ + { \ + int lambda; \ + \ + lambda = DIV_FIXED \ + ( \ + (2*curVertexPtr->Z - curVertexPtr->X), \ + (nextVertexPtr->X-curVertexPtr->X) - 2*(nextVertexPtr->Z-curVertexPtr->Z) \ + ); \ + \ + outputVerticesPtr->X = curVertexPtr->X + MUL_FIXED(lambda,nextVertexPtr->X-curVertexPtr->X); \ + outputVerticesPtr->Z = outputVerticesPtr->X/2; \ + outputVerticesPtr->Y = curVertexPtr->Y + MUL_FIXED(lambda,nextVertexPtr->Y-curVertexPtr->Y); + +#define Clip_Wide_NY_OutputXYZ \ + /* if one is in, and the other is out, output a clipped vertex */ \ + if (nextVertexInside != curVertexInside) \ + { \ + int lambda; \ + \ + lambda = DIV_FIXED \ + ( \ + (2*curVertexPtr->Z + curVertexPtr->Y), \ + -(nextVertexPtr->Y-curVertexPtr->Y) - 2*(nextVertexPtr->Z-curVertexPtr->Z) \ + ); \ + \ + outputVerticesPtr->Z = curVertexPtr->Z + MUL_FIXED(lambda,nextVertexPtr->Z-curVertexPtr->Z); \ + outputVerticesPtr->Y = -(outputVerticesPtr->Z*2); \ + outputVerticesPtr->X = curVertexPtr->X + MUL_FIXED(lambda,nextVertexPtr->X-curVertexPtr->X); + +#define Clip_Wide_PY_OutputXYZ \ + /* if one is in, and the other is out, output a clipped vertex */ \ + if (nextVertexInside != curVertexInside) \ + { \ + int lambda; \ + \ + lambda = DIV_FIXED \ + ( \ + (2*curVertexPtr->Z - curVertexPtr->Y), \ + (nextVertexPtr->Y-curVertexPtr->Y) - 2*(nextVertexPtr->Z-curVertexPtr->Z) \ + ); \ + \ + outputVerticesPtr->Z = curVertexPtr->Z + MUL_FIXED(lambda,nextVertexPtr->Z-curVertexPtr->Z); \ + outputVerticesPtr->Y = (outputVerticesPtr->Z*2); \ + outputVerticesPtr->X = curVertexPtr->X + MUL_FIXED(lambda,nextVertexPtr->X-curVertexPtr->X); + + +/*KJL************** +* GOURAUD POLYGON * +**************KJL*/ + +/* Clip against Z plane */ +void GouraudPolygon_ClipWithZ(void) +{ + RENDERVERTEX *curVertexPtr = VerticesBuffer; + RENDERVERTEX *outputVerticesPtr = (RenderPolygon.Vertices); + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_Z_Test(curVertexPtr); + + Clip_LoopStart(VerticesBuffer) + Clip_Z_Test(nextVertexPtr); + Clip_Z_OutputXYZ + Clip_OutputI + Clip_LoopEnd((RenderPolygon.Vertices)) +} + + +/* Clip against negative X plane */ +static void GouraudPolygon_Norm_ClipWithNegativeX(void) +{ + RENDERVERTEX *curVertexPtr = (RenderPolygon.Vertices); + RENDERVERTEX *outputVerticesPtr = VerticesBuffer; + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_NX_Test(curVertexPtr); + + Clip_LoopStart((RenderPolygon.Vertices)) + Clip_NX_Test(nextVertexPtr); + Clip_NX_OutputXYZ + Clip_OutputI + Clip_LoopEnd(VerticesBuffer) +} +static void GouraudPolygon_Wide_ClipWithNegativeX(void) +{ + RENDERVERTEX *curVertexPtr = (RenderPolygon.Vertices); + RENDERVERTEX *outputVerticesPtr = VerticesBuffer; + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_Wide_NX_Test(curVertexPtr); + + Clip_LoopStart((RenderPolygon.Vertices)) + Clip_Wide_NX_Test(nextVertexPtr); + Clip_Wide_NX_OutputXYZ + Clip_OutputI + Clip_LoopEnd(VerticesBuffer) +} + +/* Clip against positive Y plane*/ +static void GouraudPolygon_Norm_ClipWithPositiveY(void) +{ + RENDERVERTEX *curVertexPtr = VerticesBuffer; + RENDERVERTEX *outputVerticesPtr = (RenderPolygon.Vertices); + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_PY_Test(curVertexPtr); + + Clip_LoopStart(VerticesBuffer) + Clip_PY_Test(nextVertexPtr); + Clip_PY_OutputXYZ + Clip_OutputI + Clip_LoopEnd((RenderPolygon.Vertices)) +} +static void GouraudPolygon_Wide_ClipWithPositiveY(void) +{ + RENDERVERTEX *curVertexPtr = VerticesBuffer; + RENDERVERTEX *outputVerticesPtr = (RenderPolygon.Vertices); + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_Wide_PY_Test(curVertexPtr); + + Clip_LoopStart(VerticesBuffer) + Clip_Wide_PY_Test(nextVertexPtr); + Clip_Wide_PY_OutputXYZ + Clip_OutputI + Clip_LoopEnd((RenderPolygon.Vertices)) +} + +/* Clip against negative Y plane*/ +static void GouraudPolygon_Norm_ClipWithNegativeY(void) +{ + RENDERVERTEX *curVertexPtr = (RenderPolygon.Vertices); + RENDERVERTEX *outputVerticesPtr = VerticesBuffer; + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_NY_Test(curVertexPtr); + + Clip_LoopStart((RenderPolygon.Vertices)) + Clip_NY_Test(nextVertexPtr); + Clip_NY_OutputXYZ + Clip_OutputI + Clip_LoopEnd(VerticesBuffer) +} +static void GouraudPolygon_Wide_ClipWithNegativeY(void) +{ + RENDERVERTEX *curVertexPtr = (RenderPolygon.Vertices); + RENDERVERTEX *outputVerticesPtr = VerticesBuffer; + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_Wide_NY_Test(curVertexPtr); + + Clip_LoopStart((RenderPolygon.Vertices)) + Clip_Wide_NY_Test(nextVertexPtr); + Clip_Wide_NY_OutputXYZ + Clip_OutputI + Clip_LoopEnd(VerticesBuffer) +} + +/* Clip against positive X plane */ +static void GouraudPolygon_Norm_ClipWithPositiveX(void) +{ + RENDERVERTEX *curVertexPtr = VerticesBuffer; + RENDERVERTEX *outputVerticesPtr = (RenderPolygon.Vertices); + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_PX_Test(curVertexPtr); + + Clip_LoopStart(VerticesBuffer) + Clip_PX_Test(nextVertexPtr); + Clip_PX_OutputXYZ + Clip_OutputI + Clip_LoopEnd((RenderPolygon.Vertices)) +} +static void GouraudPolygon_Wide_ClipWithPositiveX(void) +{ + RENDERVERTEX *curVertexPtr = VerticesBuffer; + RENDERVERTEX *outputVerticesPtr = (RenderPolygon.Vertices); + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_Wide_PX_Test(curVertexPtr); + + Clip_LoopStart(VerticesBuffer) + Clip_Wide_PX_Test(nextVertexPtr); + Clip_Wide_PX_OutputXYZ + Clip_OutputI + Clip_LoopEnd((RenderPolygon.Vertices)) +} + +/*KJL*************** +* TEXTURED POLYGON * +***************KJL*/ + +/* Clip against Z plane */ +void TexturedPolygon_ClipWithZ(void) +{ + RENDERVERTEX *curVertexPtr = VerticesBuffer; + RENDERVERTEX *outputVerticesPtr = (RenderPolygon.Vertices); + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_Z_Test(curVertexPtr); + + Clip_LoopStart(VerticesBuffer) + Clip_Z_Test(nextVertexPtr); + Clip_Z_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd((RenderPolygon.Vertices)) +} + +/* Clip against negative X plane */ +static void TexturedPolygon_Norm_ClipWithNegativeX(void) +{ + RENDERVERTEX *curVertexPtr = (RenderPolygon.Vertices); + RENDERVERTEX *outputVerticesPtr = VerticesBuffer; + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_NX_Test(curVertexPtr); + + Clip_LoopStart((RenderPolygon.Vertices)) + Clip_NX_Test(nextVertexPtr); + Clip_NX_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd(VerticesBuffer) +} +static void TexturedPolygon_Wide_ClipWithNegativeX(void) +{ + RENDERVERTEX *curVertexPtr = (RenderPolygon.Vertices); + RENDERVERTEX *outputVerticesPtr = VerticesBuffer; + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_Wide_NX_Test(curVertexPtr); + + Clip_LoopStart((RenderPolygon.Vertices)) + Clip_Wide_NX_Test(nextVertexPtr); + Clip_Wide_NX_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd(VerticesBuffer) +} + +/* Clip against positive Y plane*/ +static void TexturedPolygon_Norm_ClipWithPositiveY(void) +{ + RENDERVERTEX *curVertexPtr = VerticesBuffer; + RENDERVERTEX *outputVerticesPtr = (RenderPolygon.Vertices); + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_PY_Test(curVertexPtr); + + Clip_LoopStart(VerticesBuffer) + Clip_PY_Test(nextVertexPtr); + Clip_PY_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd((RenderPolygon.Vertices)) +} +static void TexturedPolygon_Wide_ClipWithPositiveY(void) +{ + RENDERVERTEX *curVertexPtr = VerticesBuffer; + RENDERVERTEX *outputVerticesPtr = (RenderPolygon.Vertices); + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_Wide_PY_Test(curVertexPtr); + + Clip_LoopStart(VerticesBuffer) + Clip_Wide_PY_Test(nextVertexPtr); + Clip_Wide_PY_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd((RenderPolygon.Vertices)) +} + +/* Clip against negative Y plane*/ +static void TexturedPolygon_Norm_ClipWithNegativeY(void) +{ + RENDERVERTEX *curVertexPtr = (RenderPolygon.Vertices); + RENDERVERTEX *outputVerticesPtr = VerticesBuffer; + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_NY_Test(curVertexPtr); + + Clip_LoopStart((RenderPolygon.Vertices)) + Clip_NY_Test(nextVertexPtr); + Clip_NY_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd(VerticesBuffer) +} +static void TexturedPolygon_Wide_ClipWithNegativeY(void) +{ + RENDERVERTEX *curVertexPtr = (RenderPolygon.Vertices); + RENDERVERTEX *outputVerticesPtr = VerticesBuffer; + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_Wide_NY_Test(curVertexPtr); + + Clip_LoopStart((RenderPolygon.Vertices)) + Clip_Wide_NY_Test(nextVertexPtr); + Clip_Wide_NY_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd(VerticesBuffer) +} + +/* Clip against positive X plane */ +static void TexturedPolygon_Norm_ClipWithPositiveX(void) +{ + RENDERVERTEX *curVertexPtr = VerticesBuffer; + RENDERVERTEX *outputVerticesPtr = (RenderPolygon.Vertices); + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_PX_Test(curVertexPtr); + + Clip_LoopStart(VerticesBuffer) + Clip_PX_Test(nextVertexPtr); + Clip_PX_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd((RenderPolygon.Vertices)) +} +static void TexturedPolygon_Wide_ClipWithPositiveX(void) +{ + RENDERVERTEX *curVertexPtr = VerticesBuffer; + RENDERVERTEX *outputVerticesPtr = (RenderPolygon.Vertices); + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_Wide_PX_Test(curVertexPtr); + + Clip_LoopStart(VerticesBuffer) + Clip_Wide_PX_Test(nextVertexPtr); + Clip_Wide_PX_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd((RenderPolygon.Vertices)) +} + + + + +/*KJL************************ +* GOURAUD TEXTURED POLYGONS * +************************KJL*/ + +/* Clip against Z plane */ +void GouraudTexturedPolygon_ClipWithZ(void) +{ + RENDERVERTEX *curVertexPtr = VerticesBuffer; + RENDERVERTEX *outputVerticesPtr = (RenderPolygon.Vertices); + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_Z_Test(curVertexPtr); + + Clip_LoopStart(VerticesBuffer) + Clip_Z_Test(nextVertexPtr); + Clip_Z_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd((RenderPolygon.Vertices)) +} + +/* Clip against negative X plane */ +static void GouraudTexturedPolygon_Norm_ClipWithNegativeX(void) +{ + RENDERVERTEX *curVertexPtr = (RenderPolygon.Vertices); + RENDERVERTEX *outputVerticesPtr = VerticesBuffer; + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_NX_Test(curVertexPtr); + + Clip_LoopStart((RenderPolygon.Vertices)) + Clip_NX_Test(nextVertexPtr); + Clip_NX_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd(VerticesBuffer) +} +static void GouraudTexturedPolygon_Wide_ClipWithNegativeX(void) +{ + RENDERVERTEX *curVertexPtr = (RenderPolygon.Vertices); + RENDERVERTEX *outputVerticesPtr = VerticesBuffer; + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_Wide_NX_Test(curVertexPtr); + + Clip_LoopStart((RenderPolygon.Vertices)) + Clip_Wide_NX_Test(nextVertexPtr); + Clip_Wide_NX_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd(VerticesBuffer) +} + +/* Clip against positive Y plane*/ +static void GouraudTexturedPolygon_Norm_ClipWithPositiveY(void) +{ + RENDERVERTEX *curVertexPtr = VerticesBuffer; + RENDERVERTEX *outputVerticesPtr = (RenderPolygon.Vertices); + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_PY_Test(curVertexPtr); + + Clip_LoopStart(VerticesBuffer) + Clip_PY_Test(nextVertexPtr); + Clip_PY_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd((RenderPolygon.Vertices)) +} +static void GouraudTexturedPolygon_Wide_ClipWithPositiveY(void) +{ + RENDERVERTEX *curVertexPtr = VerticesBuffer; + RENDERVERTEX *outputVerticesPtr = (RenderPolygon.Vertices); + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_Wide_PY_Test(curVertexPtr); + + Clip_LoopStart(VerticesBuffer) + Clip_Wide_PY_Test(nextVertexPtr); + Clip_Wide_PY_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd((RenderPolygon.Vertices)) +} + +/* Clip against negative Y plane*/ +static void GouraudTexturedPolygon_Norm_ClipWithNegativeY(void) +{ + RENDERVERTEX *curVertexPtr = (RenderPolygon.Vertices); + RENDERVERTEX *outputVerticesPtr = VerticesBuffer; + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_NY_Test(curVertexPtr); + + Clip_LoopStart((RenderPolygon.Vertices)) + Clip_NY_Test(nextVertexPtr); + Clip_NY_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd(VerticesBuffer) +} +static void GouraudTexturedPolygon_Wide_ClipWithNegativeY(void) +{ + RENDERVERTEX *curVertexPtr = (RenderPolygon.Vertices); + RENDERVERTEX *outputVerticesPtr = VerticesBuffer; + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_Wide_NY_Test(curVertexPtr); + + Clip_LoopStart((RenderPolygon.Vertices)) + Clip_Wide_NY_Test(nextVertexPtr); + Clip_Wide_NY_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd(VerticesBuffer) +} + +/* Clip against positive X plane */ +static void GouraudTexturedPolygon_Norm_ClipWithPositiveX(void) +{ + RENDERVERTEX *curVertexPtr = VerticesBuffer; + RENDERVERTEX *outputVerticesPtr = (RenderPolygon.Vertices); + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_PX_Test(curVertexPtr); + + Clip_LoopStart(VerticesBuffer) + Clip_PX_Test(nextVertexPtr); + Clip_PX_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd((RenderPolygon.Vertices)) +} +static void GouraudTexturedPolygon_Wide_ClipWithPositiveX(void) +{ + RENDERVERTEX *curVertexPtr = VerticesBuffer; + RENDERVERTEX *outputVerticesPtr = (RenderPolygon.Vertices); + int verticesLeft = RenderPolygon.NumberOfVertices; + int numberOfPointsOutputted=0; + + int curVertexInside = Clip_Wide_PX_Test(curVertexPtr); + + Clip_LoopStart(VerticesBuffer) + Clip_Wide_PX_Test(nextVertexPtr); + Clip_Wide_PX_OutputXYZ + Clip_OutputUV + Clip_OutputI + Clip_LoopEnd((RenderPolygon.Vertices)) +} + + + + + + + +int PolygonWithinFrustrum(POLYHEADER *polyPtr) +{ + char inFrustrumFlag=0; + char noClippingFlag=INSIDE_FRUSTRUM; + int *vertexNumberPtr = &polyPtr->Poly1stPt; + + if (polyPtr->PolyFlags & iflag_notvis) return 0; + + RenderPolygon.NumberOfVertices=0; + while(*vertexNumberPtr != Term) + { + int vertexNumber = *vertexNumberPtr++; + + inFrustrumFlag |= FrustrumFlagForVertex[vertexNumber]; + noClippingFlag &= FrustrumFlagForVertex[vertexNumber]; + + /* count the number of points in the polygon; this is used for all the loops that follow */ + RenderPolygon.NumberOfVertices++; + } + + if (inFrustrumFlag != INSIDE_FRUSTRUM) return 0; + + /* at this point we know that the poly is inside the view frustrum */ + + /* if not a sprite, test direction of poly */ + if (!( (Global_ShapeHeaderPtr->shapeflags&ShapeFlag_Sprite) || (polyPtr->PolyFlags & iflag_no_bfc) )) + { + VECTORCH pop; + VECTORCH *normalPtr = (VECTORCH*)(Global_ShapeNormals + polyPtr->PolyNormalIndex); + + #if 1 + if(Global_ODB_Ptr->ObMorphCtrl) + { + extern MORPHDISPLAY MorphDisplay; + SHAPEHEADER *shape1Ptr; + VECTORCH *shape1PointsPtr; + VECTORCH *shape2PointsPtr; + + /* Set up the morph data */ + GetMorphDisplay(&MorphDisplay, Global_ODB_Ptr); + + shape1Ptr = MorphDisplay.md_sptr1; + + if(MorphDisplay.md_lerp == 0x0000) + { + shape1PointsPtr = (VECTORCH *)*shape1Ptr->points; + pop = shape1PointsPtr[polyPtr->Poly1stPt]; + + } + else if(MorphDisplay.md_lerp == 0xffff) + { + SHAPEHEADER *shape2Ptr = MorphDisplay.md_sptr2; + + shape2PointsPtr = (VECTORCH *)*shape2Ptr->points; + pop = shape2PointsPtr[polyPtr->Poly1stPt]; + } + else + { + SHAPEHEADER *shape2Ptr = MorphDisplay.md_sptr2; + + shape1PointsPtr = (VECTORCH *)(*shape1Ptr->points); + shape2PointsPtr = (VECTORCH *)(*shape2Ptr->points); + + { + VECTORCH vertex1 = shape1PointsPtr[polyPtr->Poly1stPt]; + VECTORCH vertex2 = shape2PointsPtr[polyPtr->Poly1stPt]; + + if( (vertex1.vx == vertex2.vx && vertex1.vy == vertex2.vy && vertex1.vz == vertex2.vz) ) + { + pop = vertex1; + } + else + { + /* KJL 15:27:20 05/22/97 - I've changed this to speed things up, If a vertex + component has a magnitude greater than 32768 things will go wrong. */ + pop.vx = vertex1.vx + (((vertex2.vx-vertex1.vx)*MorphDisplay.md_lerp)>>16); + pop.vy = vertex1.vy + (((vertex2.vy-vertex1.vy)*MorphDisplay.md_lerp)>>16); + pop.vz = vertex1.vz + (((vertex2.vz-vertex1.vz)*MorphDisplay.md_lerp)>>16); + } + } + } + } + else + #endif + { + /* Get the 1st polygon point as the POP */ + VECTORCH *pointsArray = (VECTORCH*)(Global_ShapePoints); + pop = pointsArray[polyPtr->Poly1stPt]; + } + pop.vx -= LocalView.vx; + pop.vy -= LocalView.vy; + pop.vz -= LocalView.vz; + + if (Dot(&pop, normalPtr)>0) return 0; + } + + if (noClippingFlag == INSIDE_FRUSTRUM) return 2; + + /* yes, we need to draw poly */ + return 1; +} + +int PolygonShouldBeDrawn(POLYHEADER *polyPtr) +{ + + /* at this point we know that the poly is inside the view frustrum */ + if (polyPtr->PolyFlags & iflag_notvis) return 0; + + #if 1 + /* if not a sprite, test direction of poly */ + if (!( (Global_ShapeHeaderPtr->shapeflags&ShapeFlag_Sprite) || (polyPtr->PolyFlags & iflag_no_bfc) )) + { + /* KJL 16:49:14 7/10/97 - + + ***** MORPHED NORMALS SUPPORT NOT YET ADDED ***** + + */ + VECTORCH pop; + VECTORCH *normalPtr = (VECTORCH*)(Global_ShapeNormals + polyPtr->PolyNormalIndex); + VECTORCH *pointsArray = (VECTORCH*)(Global_ShapePoints); + /* Get the 1st polygon point as the POP */ + + pop.vx = pointsArray[polyPtr->Poly1stPt].vx - LocalView.vx; + pop.vy = pointsArray[polyPtr->Poly1stPt].vy - LocalView.vy; + pop.vz = pointsArray[polyPtr->Poly1stPt].vz - LocalView.vz; + + if (Dot(&pop, normalPtr)>0) return 0; + } + #endif + #if 0 + { + int *vertexNumberPtr = &polyPtr->Poly1stPt; + RenderPolygon.NumberOfVertices=0; + while(*vertexNumberPtr++ != Term) + { + /* count the number of points in the polygon; this is used for all the loops that follow */ + RenderPolygon.NumberOfVertices++; + } + } + #elif 0 + RenderPolygon.NumberOfVertices = 3; + #else + { + int *vertexNumberPtr = &polyPtr->Poly1stPt; + if (vertexNumberPtr[3] == Term) + { + RenderPolygon.NumberOfVertices = 3; + } + else + { + RenderPolygon.NumberOfVertices = 4; + } + } + #endif + + return 2; +} + +/* KJL 16:18:59 7/7/97 - simple vertex test to be used in first +pass of subdividing code */ +static int VertexWithin_Norm_Frustrum(RENDERVERTEX *vertexPtr) +{ + int vertexFlag = 0; + + if(Clip_Z_Test(vertexPtr)) vertexFlag |= INSIDE_FRUSTRUM_Z_PLANE; + if(Clip_PX_Test(vertexPtr)) vertexFlag |= INSIDE_FRUSTRUM_PX_PLANE; + if(Clip_NX_Test(vertexPtr)) vertexFlag |= INSIDE_FRUSTRUM_NX_PLANE; + if(Clip_PY_Test(vertexPtr)) vertexFlag |= INSIDE_FRUSTRUM_PY_PLANE; + if(Clip_NY_Test(vertexPtr)) vertexFlag |= INSIDE_FRUSTRUM_NY_PLANE; + + return vertexFlag; +} + +static int VertexWithin_Wide_Frustrum(RENDERVERTEX *vertexPtr) +{ + int vertexFlag = 0; + + if(Clip_Z_Test(vertexPtr)) vertexFlag |= INSIDE_FRUSTRUM_Z_PLANE; + if(Clip_Wide_PX_Test(vertexPtr)) vertexFlag |= INSIDE_FRUSTRUM_PX_PLANE; + if(Clip_Wide_NX_Test(vertexPtr)) vertexFlag |= INSIDE_FRUSTRUM_NX_PLANE; + if(Clip_Wide_PY_Test(vertexPtr)) vertexFlag |= INSIDE_FRUSTRUM_PY_PLANE; + if(Clip_Wide_NY_Test(vertexPtr)) vertexFlag |= INSIDE_FRUSTRUM_NY_PLANE; + + return vertexFlag; +} + + +/* KJL 15:32:52 7/17/97 - Test to see if an object is in the view frustrum */ +static int ObjectWithin_Norm_Frustrum(DISPLAYBLOCK *dbPtr) +{ + // LOCALASSERT(dbPtr->ObShapeData->shaperadius); + +#if FAR_Z_CLIP + if(dbPtr->ObView.vz-dbPtr->ObShapeData->shaperadius<=FAR_Z_CLIP_RANGE) +#endif + if (dbPtr->ObView.vz+dbPtr->ObShapeData->shaperadius>=ZCLIPPINGVALUE) + { + /* scale radius by square root of 2 */ + int radius = MUL_FIXED(92682,dbPtr->ObShapeData->shaperadius); + + if ((dbPtr->ObView.vx-dbPtr->ObView.vz)<=radius) + if ((-dbPtr->ObView.vx-dbPtr->ObView.vz)<=radius) + if ((dbPtr->ObView.vy-dbPtr->ObView.vz)<=radius) + if ((-dbPtr->ObView.vy-dbPtr->ObView.vz)<=radius) + return 1; + } + return 0; +} +static int ObjectCompletelyWithin_Norm_Frustrum(DISPLAYBLOCK *dbPtr) +{ + // LOCALASSERT(dbPtr->ObShapeData->shaperadius); + if (dbPtr->ObView.vz-dbPtr->ObShapeData->shaperadius>=ZCLIPPINGVALUE) + { + /* scale radius by square root of 2 */ + int radius = MUL_FIXED(92682,dbPtr->ObShapeData->shaperadius); + + if ((dbPtr->ObView.vz-dbPtr->ObView.vx)>=radius) + if ((dbPtr->ObView.vz+dbPtr->ObView.vx)>=radius) + if ((dbPtr->ObView.vz-dbPtr->ObView.vy)>=radius) + if ((dbPtr->ObView.vz+dbPtr->ObView.vy)>=radius) + return 1; + } + return 0; +} +static int ObjectCompletelyWithin_Wide_Frustrum(DISPLAYBLOCK *dbPtr) +{ + return 0; +} + +static int ObjectWithin_Wide_Frustrum(DISPLAYBLOCK *dbPtr) +{ + if (dbPtr->ObView.vz+dbPtr->ObShapeData->shaperadius>=ZCLIPPINGVALUE) + { + /* scale radius by square root of 5 */ + int radius = MUL_FIXED(146543,dbPtr->ObShapeData->shaperadius); + + if ((dbPtr->ObView.vx-2*dbPtr->ObView.vz)<=radius) + if ((-dbPtr->ObView.vx-2*dbPtr->ObView.vz)<=radius) + if ((dbPtr->ObView.vy-2*dbPtr->ObView.vz)<=radius) + if ((-dbPtr->ObView.vy-2*dbPtr->ObView.vz)<=radius) + return 1; + } + return 0; +} + + +char FrustrumFlagForVertex[maxrotpts]; + +void TestVerticesWith_Norm_Frustrum(void) +{ + int v = Global_ShapeHeaderPtr->numpoints; + + GLOBALASSERT(v>0); + + while(v--) + { + char vertexFlag = 0; + +#if FAR_Z_CLIP + if(ZCLIPPINGVALUE <= RotatedPts[v].vz && RotatedPts[v].vz<=FAR_Z_CLIP_RANGE) +#else + if(ZCLIPPINGVALUE <= RotatedPts[v].vz) +#endif + vertexFlag |= INSIDE_FRUSTRUM_Z_PLANE; + + if(-RotatedPts[v].vx <= RotatedPts[v].vz) + vertexFlag |= INSIDE_FRUSTRUM_PX_PLANE; + + if(RotatedPts[v].vx <= RotatedPts[v].vz) + vertexFlag |= INSIDE_FRUSTRUM_NX_PLANE; + + if(-RotatedPts[v].vy <= RotatedPts[v].vz) + vertexFlag |= INSIDE_FRUSTRUM_PY_PLANE; + + if(RotatedPts[v].vy <= RotatedPts[v].vz) + vertexFlag |= INSIDE_FRUSTRUM_NY_PLANE; + + FrustrumFlagForVertex[v] = vertexFlag; + } +} +void TestVerticesWith_Wide_Frustrum(void) +{ + int v = Global_ShapeHeaderPtr->numpoints; + + GLOBALASSERT(v>0); + + while(v--) + { + char vertexFlag = 0; + + if(ZCLIPPINGVALUE <= RotatedPts[v].vz) + vertexFlag |= INSIDE_FRUSTRUM_Z_PLANE; + + if(-RotatedPts[v].vx <= RotatedPts[v].vz*2) + vertexFlag |= INSIDE_FRUSTRUM_PX_PLANE; + + if(RotatedPts[v].vx <= RotatedPts[v].vz*2) + vertexFlag |= INSIDE_FRUSTRUM_NX_PLANE; + + if(-RotatedPts[v].vy <= RotatedPts[v].vz*2) + vertexFlag |= INSIDE_FRUSTRUM_PY_PLANE; + + if(RotatedPts[v].vy <= RotatedPts[v].vz*2) + vertexFlag |= INSIDE_FRUSTRUM_NY_PLANE; + + FrustrumFlagForVertex[v] = vertexFlag; + } +} + + + +int DecalWithinFrustrum(DECAL *decalPtr) +{ + char inFrustrumFlag; + char noClippingFlag; + + if(ModuleCurrVisArray[decalPtr->ModuleIndex] != 2) return 0; + + inFrustrumFlag=0; + noClippingFlag=INSIDE_FRUSTRUM; + + { + int vertexFlag = VertexWithinFrustrum(&VerticesBuffer[0]); + inFrustrumFlag |= vertexFlag; + noClippingFlag &= vertexFlag; + } + { + int vertexFlag = VertexWithinFrustrum(&VerticesBuffer[1]); + inFrustrumFlag |= vertexFlag; + noClippingFlag &= vertexFlag; + } + { + int vertexFlag = VertexWithinFrustrum(&VerticesBuffer[2]); + inFrustrumFlag |= vertexFlag; + noClippingFlag &= vertexFlag; + } + { + int vertexFlag = VertexWithinFrustrum(&VerticesBuffer[3]); + inFrustrumFlag |= vertexFlag; + noClippingFlag &= vertexFlag; + } + + if (inFrustrumFlag != INSIDE_FRUSTRUM) return 0; + if (noClippingFlag == INSIDE_FRUSTRUM) return 2; + + /* yes, we need to draw poly */ + return 1; +} + +int QuadWithinFrustrum(void) +{ + char inFrustrumFlag; + char noClippingFlag; + + inFrustrumFlag=0; + noClippingFlag=INSIDE_FRUSTRUM; + + { + int vertexFlag = VertexWithinFrustrum(&VerticesBuffer[0]); + inFrustrumFlag |= vertexFlag; + noClippingFlag &= vertexFlag; + } + { + int vertexFlag = VertexWithinFrustrum(&VerticesBuffer[1]); + inFrustrumFlag |= vertexFlag; + noClippingFlag &= vertexFlag; + } + { + int vertexFlag = VertexWithinFrustrum(&VerticesBuffer[2]); + inFrustrumFlag |= vertexFlag; + noClippingFlag &= vertexFlag; + } + { + int vertexFlag = VertexWithinFrustrum(&VerticesBuffer[3]); + inFrustrumFlag |= vertexFlag; + noClippingFlag &= vertexFlag; + } + + if (inFrustrumFlag != INSIDE_FRUSTRUM) return 0; + if (noClippingFlag == INSIDE_FRUSTRUM) return 2; + + /* yes, we need to draw poly */ + return 1; +} + +int TriangleWithinFrustrum(void) +{ + char inFrustrumFlag; + char noClippingFlag; + + inFrustrumFlag=0; + noClippingFlag=INSIDE_FRUSTRUM; + + { + int vertexFlag = VertexWithinFrustrum(&VerticesBuffer[0]); + inFrustrumFlag |= vertexFlag; + noClippingFlag &= vertexFlag; + } + { + int vertexFlag = VertexWithinFrustrum(&VerticesBuffer[1]); + inFrustrumFlag |= vertexFlag; + noClippingFlag &= vertexFlag; + } + { + int vertexFlag = VertexWithinFrustrum(&VerticesBuffer[2]); + inFrustrumFlag |= vertexFlag; + noClippingFlag &= vertexFlag; + } + + if (inFrustrumFlag != INSIDE_FRUSTRUM) return 0; + if (noClippingFlag == INSIDE_FRUSTRUM) return 2; + + /* yes, we need to draw poly */ + return 1; +} + + \ No newline at end of file diff --git a/3dc/frustrum.h b/3dc/frustrum.h new file mode 100644 index 0000000..faf7795 --- /dev/null +++ b/3dc/frustrum.h @@ -0,0 +1,68 @@ +#ifndef _frustrum_h_ /* Is this your first time? */ +#define _frustrum_h_ 1 + +#include "kshape.h" +/* + * KJL 15:13:43 7/17/97 - frustrum.h + * + * function prototypes & pointers for things connected + * to the view frustrum and clipping + * + */ + +enum FrustrumType +{ + FRUSTRUM_TYPE_NORMAL, + FRUSTRUM_TYPE_WIDE +}; + +extern void SetFrustrumType(enum FrustrumType frustrumType); + +/* GOURAUD POLYGON CLIPPING */ +extern void GouraudPolygon_ClipWithZ(void); +extern void (*GouraudPolygon_ClipWithNegativeX)(void); +extern void (*GouraudPolygon_ClipWithPositiveY)(void); +extern void (*GouraudPolygon_ClipWithNegativeY)(void); +extern void (*GouraudPolygon_ClipWithPositiveX)(void); + +/* TEXTURED POLYGON CLIPPING */ +extern void TexturedPolygon_ClipWithZ(void); +extern void (*TexturedPolygon_ClipWithNegativeX)(void); +extern void (*TexturedPolygon_ClipWithPositiveY)(void); +extern void (*TexturedPolygon_ClipWithNegativeY)(void); +extern void (*TexturedPolygon_ClipWithPositiveX)(void); + +/* GOURAUD TEXTURED POLYGON CLIPPING */ +extern void GouraudTexturedPolygon_ClipWithZ(void); +extern void (*GouraudTexturedPolygon_ClipWithNegativeX)(void); +extern void (*GouraudTexturedPolygon_ClipWithPositiveY)(void); +extern void (*GouraudTexturedPolygon_ClipWithNegativeY)(void); +extern void (*GouraudTexturedPolygon_ClipWithPositiveX)(void); + +/* FRUSTRUM TESTS */ +extern int PolygonWithinFrustrum(POLYHEADER *polyPtr); +extern int PolygonShouldBeDrawn(POLYHEADER *polyPtr); +extern int (*ObjectWithinFrustrum)(DISPLAYBLOCK *dbPtr); +extern int (*ObjectCompletelyWithinFrustrum)(DISPLAYBLOCK *dbPtr); +extern int (*VertexWithinFrustrum)(RENDERVERTEX *vertexPtr); +extern void (*TestVerticesWithFrustrum)(void); + +extern int DecalWithinFrustrum(DECAL *decalPtr); +extern int QuadWithinFrustrum(void); +extern int TriangleWithinFrustrum(void); + + +/* pass a pointer to a vertex to be tested; results are returned in an int, +using the following defines */ +#define INSIDE_FRUSTRUM_Z_PLANE 1 +#define INSIDE_FRUSTRUM_PX_PLANE 2 +#define INSIDE_FRUSTRUM_NX_PLANE 4 +#define INSIDE_FRUSTRUM_PY_PLANE 8 +#define INSIDE_FRUSTRUM_NY_PLANE 16 +#define INSIDE_FRUSTRUM 31 + +extern char FrustrumFlagForVertex[maxrotpts]; + +#define USE_FOV_53 0 + +#endif diff --git a/3dc/ia3d.lib b/3dc/ia3d.lib new file mode 100644 index 0000000..9429eb7 Binary files /dev/null and b/3dc/ia3d.lib differ diff --git a/3dc/include/3dc.h b/3dc/include/3dc.h new file mode 100644 index 0000000..a738fd7 --- /dev/null +++ b/3dc/include/3dc.h @@ -0,0 +1,9 @@ +#include +#include +#include + +#include "system.h" +#include "equates.h" +#include "platform.h" +#include "shape.h" +#include "prototyp.h" diff --git a/3dc/include/mem3dc.h b/3dc/include/mem3dc.h new file mode 100644 index 0000000..958960d --- /dev/null +++ b/3dc/include/mem3dc.h @@ -0,0 +1,183 @@ +/* mem3dc.h */ +#ifndef MEM3DC_H_INCLUDED +#define MEM3DC_H_INCLUDED + +#ifdef __cplusplus + + extern "C" { + +#endif + +#include "system.h" +#include + +/* defines */ +#if Saturn +#define DBGMALLOC 1 +#endif + +#if SupportWindows95 +#if 1 +#define DBGMALLOC 0 +#else + #ifdef _DEBUG /* standard compiler command line debugging-ON switch */ + #define DBGMALLOC 1 + #elif defined(NDEBUG) /* standard compiler command line debugging-OFF switch */ + #define DBGMALLOC 0 + #elif defined(_DBGMALLOC) /* alternate compiler command line switch */ + #define DBGMALLOC _DBGMALLOC + #else /* default switch */ + #define DBGMALLOC 1 + #endif +#endif +#endif + +#if PSX +#define DBGMALLOC 0 +#endif + +/* parameters for DumpMallocInfo */ +#define PARTIALDUMP 0 /* print outstanding mallocs number and total memory allocated */ +#define DUMPTOSCREEN 1 /* print all outstanding mallocs to screen */ +#define DUMPTOFILE 2 /* write outstanding malloc details to file (filename defined with MALLOCDUMPFILE) */ +#define CPPGLOBAL 0x100000 /* line numbers offset by this value if the malloc is as part of a constructor for a C++ global whose dealloc may not be recorded */ + +/* JH - 30.5.97 +I noticed that the MALLOC_RECORD structure has char[40] +for the filename. Since I know that on the PC, the __FILE__ +macro results in a string compiled into the executable, and +evaulates to a pointer to that string, we do not need to make +a separate copy of the string for each malloc - just store the +pointer. +So, on PC this reduces the data size for the malloc records from 1.04Mb to 320K ! */ + +#if SupportWindows95 || PSX +#define COPY_FILENAME 0 /* new behavior */ +#else +#define COPY_FILENAME 1 /* previous behavior */ +#endif + +/* platform specific memory allocation and deallocation declarations */ +extern void *AllocMem(size_t __size); +extern void DeallocMem(void *__ptr); + +/* mem.c public functions */ +#if COPY_FILENAME +extern void record_free(void *ptr, char string[], unsigned long lineno); +extern void *record_malloc(long size, char string[], unsigned long lineno); +#else /* new prototypes to take just pointers - dunno if it's really necessary */ +extern void record_free(void *ptr, char const * string, unsigned long lineno); +extern void *record_malloc(long size, char const * string, unsigned long lineno); +#endif +extern void DumpMallocInfo(int type); +extern void DumpBoundsCheckInfo(int type); +extern void DumpInfo(int type); + +#if DBGMALLOC +#define AllocateMem(x) record_malloc(x,__FILE__, __LINE__) +#define DeallocateMem(x) record_free(x,__FILE__, __LINE__) + +#ifdef __cplusplus + +/* JH 30/5/97 - 2/6/97 +Overloaded new and delete to use record_malloc and record_free +Notes: +1. +Although these are declared as inline, C++ files which do not include this +header will still use the overloaded operators new and delete (as long as at +least one C++ file includes this header), although the lack of the macro for +new will mean that you will not have file and line number information in the +malloc record. +2. +Since it is not possible to have a user defined delete operator which takes +extra parameters, the malloc record will not be able to track the file and +line number of delete operations. For this reason, it is also necessary to +overload the default operator new, so that corresponding delete operations +(which will go through the record_free function) cause the memory to be +deallocated in the same way. +3. +Global C++ objects may have constructors which call new and delete. +Since their deconstructors will only be called after the function 'main' or +'WinMain' has returned and after all functions specified with calls to atexit +have returned, it is not possible to gruarantee a dump of the malloc info +after they have been destroyed. I have introduced a global C++ object with a +constructor and decostructor, which turn malloc recording on and off +respectively. This will help prevent misreported memory leaks, because global +objects contructed before this special object will be destroyed after it, +hence any associated memory allocation and deallocation will not be recorded +in the same way. A malloc dump called from the destructor of this special +object will not misreport memory leaks for some global objects (those which +happen to be constructed after the special object and deconstructed before +it), though it will report the outstanding allocations as being from the +constructor of a global C++ object. This is a intended as a warning - these +outstanding allocations are probably not leaks, since they will be +deconstructed fully before the program terminates. +*/ + +extern "C++" { + +extern int __cpp_new_recording; + +inline void * operator new(size_t s, char const * file, unsigned long line) +{ + return + __cpp_new_recording + ? record_malloc(s,file,line) + : record_malloc(s,file,line+CPPGLOBAL) + ; +} +inline void * operator new(size_t s) +{ + return + __cpp_new_recording + ? record_malloc(s,"Unknown file (C++ new)",0) + : record_malloc(s,"Unknown file (C++ new)",CPPGLOBAL) + ; +} +inline void operator delete(void * p) +{ + record_free(p,"Unknown file (C++ delete)",0); +} +#ifndef _MSC_VER +inline void * operator new[](size_t s, char const * file, unsigned long line) +{ + return + __cpp_new_recording + ? record_malloc(s,file,line) + : record_malloc(s,file,line+CPPGLOBAL) + ; +} +inline void * operator new[](size_t s) +{ + return + __cpp_new_recording + ? record_malloc(s,"Unknown file (C++ new[])",0) + : record_malloc(s,"Unknown file (C++ new[])",CPPGLOBAL) + ; +} +inline void operator delete[](void * p) +{ + record_free(p,"Unknown file (C++ delete[])",0); +} +#endif + +#define new new(__FILE__,__LINE__) + +} + +#endif + +#else +#define AllocateMem(x) AllocMem(x) +#define DeallocateMem(x) DeallocMem(x) +#endif + + +#ifdef __cplusplus + + }; + +#endif + + +#endif diff --git a/3dc/include/module.h b/3dc/include/module.h new file mode 100644 index 0000000..a42a6ca --- /dev/null +++ b/3dc/include/module.h @@ -0,0 +1,484 @@ +#ifndef MODULE_INCLUDED + + +/* + + Modules + +*/ + + +#ifdef __cplusplus + + extern "C" { + +#endif + + + #if SupportModules + + +#include "bh_waypt.h" + +typedef struct moduletableheader { + + int mth_xsize; /* Extents in world space */ + int mth_ysize; + int mth_zsize; + + int mth_numx; /* Number of modules along each axis */ + int mth_numy; + int mth_numz; + + /* Pointer to an array of pointers to modules */ + + struct module **mth_moduletable; + +} MODULETABLEHEADER; + + +/* + + NOTES + + There are no pointers to strategy and/or animation data structures yet. + These will be added as and when they are needed. + +*/ + +typedef enum { + + mtype_module, + mtype_term + +} MODULETYPE; + + +typedef union mref { + + char mref_name[4]; /* Module name */ + struct module *mref_ptr; /* Module pointer */ + +} MREF; + + +typedef enum { + + vmtype_vmodule, + vmtype_term + +} VMODULETYPE; + + +typedef enum { + + vmodi_null, /* Null instruction */ + vmodi_bra_vc /* Branch if viewport closed */ + +} VMODI; + +typedef union _vmodidata { + + char vmodidata_label[4]; + struct vmodule *vmodidata_ptr; + int vmodidata; + +} VMODIDATA; + + +typedef struct vmodule { + + VMODULETYPE vmod_type; + char vmod_name[4]; /* Unique name for this VMODULE */ + VMODI vmod_instr; + VMODIDATA vmod_data; + MREF vmod_mref; + VECTORCH vmod_dir; + int vmod_angle; + int vmod_flags; + +} VMODULE; + + +#define vm_flag_gotptrs 0x00000001 /* VMODULE references have + been converted from + names to pointers */ + + +#if 0 + +typedef enum { + + vptype_viewport, + vptype_term + +} VIEWPORTTYPE; + + +typedef struct viewport { + + VIEWPORTTYPE vp_type; + + int vp_flags; + + VECTORCH vp0; + VECTORCH vp1; + VECTORCH vp2; + VECTORCH vp3; + +} VIEWPORT; + +#endif + + +/* + + This is the map block for module objects. It was originally based on the + MAPBLOCK8 structure. + +*/ + +typedef struct modulemapblock { + + int MapType; + int MapShape; + + #if LoadingMapsShapesAndTexturesEtc + + int MapFNameIndex; + char **MapFNameArray; + SHAPEHEADER **MapShapeDataArray; + + #endif + + VECTORCH MapWorld; + + EULER MapEuler; + + int MapFlags; + int MapFlags2; + int MapFlags3; + + + + MAPSETVDB *MapVDBData; + + int MapInteriorType; + + #if InterfaceEngine + + /* This will point to the Object_Chunk, it will have to be */ + /* cast within C++ though */ + + void * o_chunk; + + #endif + + int MapLightType; /* See LIGHTTYPES */ + + + VECTORCH MapOrigin; /* Origin of Rotation */ + + SIMSHAPELIST *MapSimShapes; + + int MapViewType; /* See "VDB_ViewType" */ + + + struct displayblock **MapMPtr; /* Write our dptr here as mother */ + struct displayblock **MapDPtr; /* Read our dptr here as daughter */ + + VECTORCH MapMOffset; /* Offset from mother */ + + #if SupportMorphing + MORPHHEADER *MapMorphHeader; + #endif + +} MODULEMAPBLOCK; + + +/* + + Module functions called either when the module is visible or when the view + is inside the module. + +*/ + +typedef enum { + + mfun_null, + +} MFUNCTION; + + +/* + + This is the MODULE structure + +*/ + +struct aimodule; + +typedef struct module { + + MODULETYPE m_type; + + char m_name[4]; /* Unique name for this MODULE */ + + int m_index; /* Unique module index */ + + int m_flags; + + VECTORCH m_world; /* World location */ + + MREF m_ext; /* Get module extents from the shape + found through this other module */ + + int m_ext_scale; /* Scale extents by this value (fp) */ + + int m_maxx; /* Module extents */ + int m_minx; + int m_maxy; + int m_miny; + int m_maxz; + int m_minz; + + MODULEMAPBLOCK *m_mapptr; /* Map data for the module object */ + struct displayblock *m_dptr; /* Display block (not constant) */ + + MREF m_vptr; /* Vertical pointer to module array */ + + VMODULE *m_vmptr; /* Pointer to an array of VMODULE, or + "visible module" structures */ + + MREF *m_link_ptrs; /* Pointer to an arbitrary sized array + of module references - the array is + zero terminated */ + /*should be got rid of soon*/ + + + + MODULETABLEHEADER *m_table; /* A hash table whose creation is + triggered by a threshold value set by + "system.h". This is to speed up module + list traversal */ + + MFUNCTION m_ifvisible; /* Function called if module visible */ + MFUNCTION m_ifvinside; /* Function called if view inside */ + MREF m_funref; /* Function access to another module */ + + struct strategyblock *m_sbptr; /* Project supplies structure */ + + int m_numlights; /* # light blocks in array */ + struct lightblock *m_lightarray; /* Ptr. to array of light blocks */ + + struct extraitemdata *m_extraitemdata; + + MATRIXCH m_mat; /* Internal use only */ + + #if SupportWindows95 + char * name; + #endif + + WAYPOINT_HEADER *m_waypoints; + + struct aimodule *m_aimodule; /* the aimodule that this module is a part of*/ + + float m_sound_reverb; /*settings for the way sound should */ + int m_sound_env_index;/*be played in this module*/ + +} MODULE; + + +/* Flags */ + +#define m_flag_infinite 0x00000001 /* No extent test, the + view is always in this + module */ + +#define m_flag_gotptrs 0x00000002 /* Module references have + been converted from + names to pointers */ + +#define m_flag_open 0x00000004 /* The viewport/Door is + open. This state is + read from the "dptr" + morphing frame if it is + present and if it is + appropriate to do so */ + +#define m_flag_dormant 0x00000008 /* The module is not active */ + + +#define m_flag_gotmat 0x00000010 /* Internal use only */ + +#define m_flag_visible_on_map 0x00000020 /* Flag for Kevin's map stuff */ + +#define m_flag_slipped_inside 0x00000040 /* Another flag 4 Kevin */ + +#define MODULEFLAG_AIRDUCT 0x80000000 +#define MODULEFLAG_STAIRS 0x40000000 +#define MODULEFLAG_SKY 0x20000000 +#define MODULEFLAG_FOG 0x10000000 +#define MODULEFLAG_HORIZONTALDOOR 0x08000000 + + +typedef struct aimodule +{ + int m_index; //the index in AIModuleArray + + VECTORCH m_world; /* World location */ + + //adjacent aimodules - null terminated array + struct aimodule **m_link_ptrs; + + //the render modules that make up this ai module - null terminated array + MODULE **m_module_ptrs; + + WAYPOINT_HEADER *m_waypoints; + + /* CDF 1/6/98 - Routefinder Globals */ + int RouteFinder_FrameStamp; + int RouteFinder_IterationNumber; + +}AIMODULE; + + +/* + Module Scene Structure + +*/ + +typedef struct scenemodule { + + MODULE *sm_module; /* Pointer to module structure for this scene */ + MODULE **sm_marray; /* Pointer to array of pointers to all modules */ + +} SCENEMODULE; + + +/* + + "The View" + + The "View Finder" accesses the view location and orientation through this + global structure. This is so that views can be passed to other functions as + a single pointer if required. + +*/ + +typedef struct aview { + + VECTORCH vloc; + MATRIXCH vmat; + struct viewdescriptorblock *vvdb; + +} AVIEW; + + + + +/* + + Module Function Prototypes + +*/ + +#if IncludeModuleFunctionPrototypes + +void ModuleHandler(VIEWDESCRIPTORBLOCK *vdb); +void ProcessModules(VIEWDESCRIPTORBLOCK *vdb, MODULE *mptr); +void ViewFinder(MODULE *mptr); +void ReadVMODULEArrays(VMODULE *vptr); + + +void UpdateModules(void); +void ModuleFunctions(MODULE *mptr, MFUNCTION mf); +void AllocateModuleObject(MODULE *mptr); +void DeallocateModuleObject(MODULE *mptr); + + +/* + + A project supplied function. The display block has been successfuly + allocated and has been fully initialised. + +*/ + +void ModuleObjectJustAllocated(MODULE *mptr); + + +/* + + A project supplied function. The display block is about to be deallocated. + +*/ + +void ModuleObjectAboutToBeDeallocated(MODULE *mptr); + + +/* + + A project supplied function. These are the new and old modules this ???? + +*/ + +void NewAndOldModules(int num_new, MODULE **m_new, + int num_old, MODULE **m_old, char *m_currvis); + + + +#if SupportMultiCamModules +void InitGlobalVMA(void); +void DeallocateGlobalVMA(void); +#if SupportMultiCamModules +void UpdateDynamicModuleObjects(void); +#endif +#endif + +void PreprocessAllModules(void); +void PreprocessModuleArray(MODULE **m_array_ptr); +void PreprocessVMODIDATA(VMODULE *v_ptr); + +void DeallocateModuleVisArrays(void); +int GetModuleVisArrays(void); +int InsideModule(MODULE *mptr); + +void ConvertModuleNameToPointer(MREF *mref_ptr, MODULE **m_array_ptr); +void ConvertVModuleNameToPointer(VMODIDATA *vmodidata_ptr, VMODULE *v_array_ptr); + +int CompareName(char *name1, char *name2); +void PrintName(char *name); + +int SaveModuleArray(MODULE *mptr, char *filename); +MODULE* LoadModuleArray(MODULE *mptr, int size, char *filename); + +int IsModuleVisibleFromModule(MODULE *source, MODULE *target); + +#endif /* IncludeModuleFunctionPrototypes */ + +extern SCENEMODULE **Global_ModulePtr; +extern SCENEMODULE *MainSceneArray[]; +extern AVIEW ModuleView; +extern MODULE *Global_MotherModule; +extern char *ModuleCurrVisArray; +extern char *ModulePrevVisArray; +extern char *ModuleTempArray; +extern char *ModuleLocalVisArray; +extern int ModuleArraySize; + +extern int AIModuleArraySize; +extern AIMODULE *AIModuleArray; + + +#endif /* SupportModules */ + + +#ifdef __cplusplus + + }; + +#endif + +#define MODULE_INCLUDED + +#endif diff --git a/3dc/include/prototyp.h b/3dc/include/prototyp.h new file mode 100644 index 0000000..6405685 --- /dev/null +++ b/3dc/include/prototyp.h @@ -0,0 +1,2991 @@ +#ifndef PROTOTYP_INCLUDED + +/* + + Global Functions, Structures and Variables are prototyped here + +*/ + + +#include "shpanim.h" + +#ifdef __cplusplus + + extern "C" { + +#endif + + + +#include "mem3dc.h" + + + + +/* + + Structures, Unions & Enums + +*/ + + + +/* Grrr!! That's the last time these will be missing! */ +/* Oh, CDF 18/12/97 */ + +#if platform_pc +extern int sine[]; +extern int cosine[]; +#endif + +/* + + A general system file header structure, storing the TYPE of the file as a + four character string, and the SIZE of the file as an unsigned 32-bit value. + +*/ + +typedef struct fileheaderch { + + char fh_type[4]; + unsigned int fh_size; + +} FILEHEADERCH; + + +typedef struct vectorch { + + int vx; + int vy; + int vz; + +} VECTORCH; + +typedef struct quat { + + int quatw; + int quatx; + int quaty; + int quatz; + +} QUAT; + +#if SupportFPMathsFunctions + +typedef struct vectorchf { + + float vx; + float vy; + float vz; + +} VECTORCHF; + +void FNormalise(VECTORCHF *n); + +#endif + + +typedef struct vector2d { + + int vx; + int vy; + +} VECTOR2D; + + +#if SupportFPMathsFunctions + +typedef struct vector2df { + + float vx; + float vy; + +} VECTOR2DF; + +void FNormalise2d(VECTOR2DF *n); + +#endif + + +typedef struct line { + + VECTORCH v0; + VECTORCH v1; + +} LINE; + + + + + + +typedef struct euler { + + int EulerX; + int EulerY; + int EulerZ; + +} EULER; + + +typedef struct angularvelocity { + + EULER AngV; + + int PitchCount; + int YawCount; + int RollCount; + +} ANGULARVELOCITY; + + +typedef struct matrixch { + + int mat11; + int mat12; + int mat13; + + int mat21; + int mat22; + int mat23; + + int mat31; + int mat32; + int mat33; + +} MATRIXCH; + + +#if SupportFPMathsFunctions + +typedef struct matrixchf { + + float mat11; + float mat12; + float mat13; + + float mat21; + float mat22; + float mat23; + + float mat31; + float mat32; + float mat33; + +} MATRIXCHF; + +#endif + + +/* Sorry about this... */ + +//#include "hmodel.h" + +struct hmodelcontroller; + + +/* + + This structure is used by map function "MapSetVDB()" to pass parameters + to the "SetVDB()" function. + +*/ + +typedef struct mapsetvdb { + + int SVDB_Flags; + int SVDB_ViewType; + + int SVDB_Depth; + + int SVDB_CentreX; + int SVDB_CentreY; + + int SVDB_ProjX; + int SVDB_ProjY; + int SVDB_MaxProj; + + int SVDB_ClipLeft; + int SVDB_ClipRight; + int SVDB_ClipUp; + int SVDB_ClipDown; + + int SVDB_H1; + int SVDB_H2; + int SVDB_HInterval; + int SVDB_HColour; + int SVDB_Ambience; + + int SVDB_ObViewState; + int SVDB_ObViewDistance; + int SVDB_ObPanX; + int SVDB_ObPanY; + + +} MAPSETVDB; + + +/* + + Simplified Shapes + + The array of shapes MUST be terminated by "-1" + +*/ + +typedef struct simshapelist { + + int SSL_Threshold; /* 1st trans. for proj. r */ + int *SSL_Shapes; /* ptr to array of shapes */ + +} SIMSHAPELIST; + + +/* + + Map Structures + + Each map is made up of a collection of arrays of these different block + types. Access to them is provided by the header block (see below). + + Map TYPES are defined in the project specific file "equates.h" + +*/ + + + +typedef struct mapblock1 { + + int MapType; + + #if LoadingMapsShapesAndTexturesEtc + + int MapFNameIndex; + char **MapFNameArray; + SHAPEHEADER **MapShapeDataArray; + + #endif + +} MAPBLOCK1; + + +typedef struct mapblock2 { + + int MapType; + int MapShape; + + #if LoadingMapsShapesAndTexturesEtc + + int MapFNameIndex; + char **MapFNameArray; + SHAPEHEADER **MapShapeDataArray; + + #endif + +} MAPBLOCK2; + + +typedef struct mapblock3 { + + int MapType; + int MapShape; + + #if LoadingMapsShapesAndTexturesEtc + + int MapFNameIndex; + char **MapFNameArray; + SHAPEHEADER **MapShapeDataArray; + + #endif + + VECTORCH MapWorld; + +} MAPBLOCK3; + + +typedef struct mapblock4 { + + int MapType; + int MapShape; + + #if LoadingMapsShapesAndTexturesEtc + + int MapFNameIndex; + char **MapFNameArray; + SHAPEHEADER **MapShapeDataArray; + + #endif + + VECTORCH MapWorld; + + EULER MapEuler; + +} MAPBLOCK4; + + +typedef struct mapblock5 { + + int MapType; + int MapShape; + + #if LoadingMapsShapesAndTexturesEtc + + int MapFNameIndex; + char **MapFNameArray; + SHAPEHEADER **MapShapeDataArray; + + #endif + + VECTORCH MapWorld; + + EULER MapEuler; + + int MapFlags; + + +} MAPBLOCK5; + + +typedef struct mapblock6 { + + int MapType; + int MapShape; + + #if LoadingMapsShapesAndTexturesEtc + + int MapFNameIndex; + char **MapFNameArray; + SHAPEHEADER **MapShapeDataArray; + + #endif + + VECTORCH MapWorld; + + EULER MapEuler; + + int MapFlags; + + + MAPSETVDB *MapVDBData; + + int MapInteriorType; + + #if InterfaceEngine + + /* This will point to the Object_Chunk, it will have to be */ + /* cast within C++ though */ + + void * o_chunk; + + #endif + +} MAPBLOCK6; + + +typedef struct mapblock7 { + + int MapType; + int MapShape; + + #if LoadingMapsShapesAndTexturesEtc + + int MapFNameIndex; + char **MapFNameArray; + SHAPEHEADER **MapShapeDataArray; + + #endif + + VECTORCH MapWorld; + + EULER MapEuler; + + int MapFlags; + int MapFlags2; + int MapFlags3; + + + MAPSETVDB *MapVDBData; + + int MapInteriorType; + + #if InterfaceEngine + + /* This will point to the Object_Chunk, it will have to be */ + /* cast within C++ though */ + + void * o_chunk; + + #endif + + int MapLightType; /* See LIGHTTYPES */ + + + VECTORCH MapOrigin; /* Origin of Rotation */ + + SIMSHAPELIST *MapSimShapes; + + int MapViewType; /* See "VDB_ViewType" */ + + +} MAPBLOCK7; + + +typedef struct mapblock8 { + + int MapType; + int MapShape; + + VECTORCH MapWorld; + + EULER MapEuler; + + int MapFlags; + int MapFlags2; + int MapFlags3; + + MAPSETVDB *MapVDBData; + + int MapInteriorType; + + int MapLightType; /* See LIGHTTYPES */ + + + VECTORCH MapOrigin; /* Origin of Rotation */ + + SIMSHAPELIST *MapSimShapes; + + int MapViewType; /* See "VDB_ViewType" */ + + struct displayblock **MapMPtr; /* Write our dptr here as mother */ + struct displayblock **MapDPtr; /* Read our dptr here as daughter */ + + VECTORCH MapMOffset; /* Offset from mother */ + +} MAPBLOCK8; + + +/* + + Map Header Block + +*/ + +typedef struct mapheader { + + MAPBLOCK1 *MapType1Objects; + MAPBLOCK2 *MapType2Objects; + MAPBLOCK3 *MapType3Objects; + MAPBLOCK4 *MapType4Objects; + MAPBLOCK5 *MapType5Objects; + MAPBLOCK6 *MapType6Objects; + MAPBLOCK7 *MapType7Objects; + MAPBLOCK8 *MapType8Objects; + +} MAPHEADER; + + + +/* + + Physical Screen Descriptor Block + + Only one of these exists and it is filled out by the Video Mode Set + function. + + Functions use these parameters in conjunction with those in the + View Descriptor Block to calculate Screen and View scaling factors. + +*/ + +typedef struct screendescriptorblock { + + int SDB_Width; + int SDB_Height; + int SDB_Depth; + #if SupportWindows95 + int SDB_ScreenDepth; + #endif + int SDB_Size; + + int SDB_DiagonalWidth; + + int SDB_CentreX; + int SDB_CentreY; + + int SDB_ProjX; + int SDB_ProjY; + int SDB_MaxProj; + + int SDB_ClipLeft; + int SDB_ClipRight; + int SDB_ClipUp; + int SDB_ClipDown; + + int SDB_Flags; + + int SDB_ViewAngle; + int SDB_ViewAngleCos; + + unsigned int TLTSize; + unsigned int TLTShift; + +} SCREENDESCRIPTORBLOCK; + + +/* + + Screen Descriptor Block Flags + + Set these BEFORE setting the video mode + +*/ + +#define SDB_Flag_222 0x00000001 /* 8-bit mode 222 texture palette */ +#define SDB_Flag_Raw256 0x00000002 /* 8-bit mode, no texture remap */ + +#define SDB_Flag_MIP 0x00000004 /* Create MIP maps for images */ + +#define SDB_Flag_SuperSample2x2 0x00000008 /* 8T and 24 only */ + +#define SDB_Flag_DrawFrontToBack 0x00000010 /* Useful if Z-Buffering */ + +#define SDB_Flag_TLTPalette 0x00000020 /* 8Raw only, Images may have ih_flag_tlt and the tlt maps colours from an abstract palette to the screen palette */ +#define SDB_Flag_TLTSize 0x00000040 /* The TLTSize member is valid, o/w TLTSize is 256 */ +#define SDB_Flag_TLTShift 0x00000080 /* The TLTShift member is valid because the TLTSize is a power of two */ + + + +/* + + Clip Plane Block + +*/ + +typedef struct clipplaneblock { + + VECTORCH CPB_Normal; + VECTORCH CPB_POP; + +} CLIPPLANEBLOCK; + + +/* + + Clip Plane Points + +*/ + +typedef struct clipplanepoints { + + VECTORCH cpp1; + VECTORCH cpp2; + VECTORCH cpp3; + +} CLIPPLANEPOINTS; + +/* + + View Descriptor Block + + View location and orientation will come from the currently designated view + object. A pointer to an object block will not be essential, which is why I + have added a location to the viewport block. The matrix exists in the + viewport block because it is not the same matrix that appears in the object + block. The object block has a matrix that takes it from local space to world + space. I need the transpose of this matrix to create a world space to view + space transformation. + + See "3dc\docs\c*.doc" for more information. + +*/ + +typedef struct viewdescriptorblock { + + struct viewdescriptorblock *VDB_HigherP; + struct viewdescriptorblock *VDB_LowerP; + + int VDB_ViewType; /* To match ObViewType, used by image backdrops */ + + int VDB_Priority; /* Determines draw order */ + + int VDB_Flags; + + int VDB_ViewAngle; + int VDB_ViewAngleCos; + + int VDB_Width; + int VDB_Height; + int VDB_Depth; + #if SupportWindows95 + int VDB_ScreenDepth; + #endif + + int VDB_CentreX; + int VDB_CentreY; + + int VDB_ProjX; + int VDB_ProjY; + int VDB_MaxProj; + + int VDB_ClipZ; + int VDB_ClipLeft; + int VDB_ClipRight; + int VDB_ClipUp; + int VDB_ClipDown; + + CLIPPLANEBLOCK VDB_ClipZPlane; + CLIPPLANEBLOCK VDB_ClipLeftPlane; + CLIPPLANEBLOCK VDB_ClipRightPlane; + CLIPPLANEBLOCK VDB_ClipUpPlane; + CLIPPLANEBLOCK VDB_ClipDownPlane; + + struct displayblock *VDB_ViewObject; + + VECTORCH VDB_World; + + MATRIXCH VDB_Mat; + MATRIXCH VDB_HorizonMat; + MATRIXCH VDB_SpriteMat; + + EULER VDB_MatrixEuler; + + + int VDB_H1; + int VDB_H2; + int VDB_HInterval; + + int VDB_HColour; /* "Sky" */ + int VDB_HColour8; /* For 8-bit colour indirected modes */ + + int VDB_HGColour; /* "Ground" */ + int VDB_HGColour8; /* For 8-bit colour indirected modes */ + + int VDB_Ambience; + + #if pc_backdrops + BACKDROPTYPE VDB_BackdropType; + unsigned short VDB_ProjectorXOffsets[MaxScreenWidth]; + #endif + + #if ProjectSpecificVDBs + void* VDB_ProjectSpecificHook; + #endif + +} VIEWDESCRIPTORBLOCK; + + +/* Flags */ + +#define ViewDB_Flag_SingleBuffer 0x00000001 +#define ViewDB_Flag_DoubleBuffer 0x00000002 +#define ViewDB_Flag_FullSize 0x00000004 /* Use fast screen clear */ +#define ViewDB_Flag_NoBackdrop 0x00000008 + +#define ViewDB_Flag_LTrunc 0x00000010 /* Informs the VDB creator */ +#define ViewDB_Flag_RTrunc 0x00000020 /* that a physical screen */ +#define ViewDB_Flag_UTrunc 0x00000040 /* violation has forced a */ +#define ViewDB_Flag_DTrunc 0x00000080 /* truncation of the viewport */ + +#define ViewDB_Flag_Hazing 0x00000100 +#define ViewDB_Flag_DontDraw 0x00000200 +#define ViewDB_Flag_AdjustScale 0x00000400 /* Scale 320x200 definition up to equivalent size for the mode */ +#define ViewDB_Flag_AddSubject 0x00000800 /* For MapSetVDB, telling it to add dptr_last to the dptr */ + +#define ViewDB_Flag_NeedToFlushZ 0x00001000 /* Cleared by flush function */ + + +#define ViewDB_Flag_ImageBackdrop 0x00004000 /* This requires a backdrop + image array, accessed through + "Global_SceneBackdropPtr" */ + +#define ViewDB_Flag_Horizon 0x00008000 /* Draw a "traditional" + Sky/Ground horizon - before + the backdrop is drawn */ + +#define ViewDB_Flag_UseBackdropImageColoursForHorizon 0x00010000 + +#define ViewDB_Flag_NoScreenClear 0x00020000 + +#define ViewDB_Flag_NoModules 0x00040000 + + +/* + + A VDB global "iflag_drawtx3das2d" that forces all 3d textures to be drawn as 2d + according to the "iflag_drawtx3das2d" pipeline. + + WARNING! + + Only use this when drawing per object or per vdb as it uses the global vdb pointer + +*/ + +#define ViewDB_Flag_drawtx3das2d 0x00080000 + + +/* + Neal - for starfields (currently only available + on Windows 95, all modes) +*/ + + +#define ViewDB_Flag_Starfield 0x00100000 + + +/* test the flags with "& VDB_Trunc" to see if any truncation occurred */ + +#define VDB_Trunc (ViewDB_Flag_LTrunc | ViewDB_Flag_RTrunc | ViewDB_Flag_UTrunc | ViewDB_Flag_DTrunc) + + + +/* + + Light Source Data Structures + +*/ + + +/* + + Light Types + +*/ + +typedef enum { + + LightType_Infinite, /* Default */ + LightType_PerObject, + LightType_PerVertex + +} LIGHTTYPES; + + +typedef struct lightblock { + + int LightFlags; + int LightType; + + VECTORCH LightWorld; /* World space light position */ + + VECTORCH LocalLP; /* Light position in object local space */ + + int LightBright; /* 0->1 Fixed Point */ + int LightRange; + + int BrightnessOverRange; + + /* these RGB components take values 0-65536 */ + int RedScale; + int GreenScale; + int BlueScale; + + int LightBrightStore; + +} LIGHTBLOCK; + +/* + + Light Flags + +*/ + +#define LFlag_CosAtten 0x00000001 /* Cosine attenuation */ +#define LFlag_CosSpreadAtten 0x00000002 /* Cosine spread attenuation */ +#define LFlag_Omni 0x00000004 /* Omnidirectional */ +#define LFlag_Deallocate 0x00000008 /* Deallocate at frame end */ +#define LFlag_NoShadows 0x00000010 /* Prelighting - No Shadows */ +#define LFlag_Off 0x00000020 /* Prelighting - Light OFF */ + +#define LFlag_PreLitSource 0x00000040 /* WARNING: Not obj. specific */ + +#define LFlag_WasNotAllocated 0x00000080 /* Supplied by another */ + +#define LFlag_AbsPos 0x00000100 /* Pos. not rel. to parent */ +#define LFlag_AbsOff 0x00000200 /* Offset not rel. to parent */ + +#define LFlag_AbsLightDir 0x00000400 /* Light dir. not rel. to p. */ + +#define LFlag_NoSpecular 0x00000800 + +#define LFlag_Electrical 0x00001000 +#define LFlag_Thermal 0x00002000 + +/* KJL 16:17:42 01/10/98 - used to specify no specular component to the light; +avoids unnecessary texture wash-out. */ + +#if SupportMorphing + + +/* + + Morph Frame + +*/ + +typedef struct morphframe { + + int mf_shape1; + int mf_shape2; + +} MORPHFRAME; + + +/* + + Morph Header + +*/ + +typedef struct morphheader { + + int mph_numframes; + int mph_maxframes; + MORPHFRAME *mph_frames; + +} MORPHHEADER; + + +/* + + Display Pipeline Structure + +*/ + +typedef struct morphdisplay { + + int md_lerp; + int md_one_minus_lerp; + int md_shape1; + int md_shape2; + SHAPEHEADER *md_sptr1; + SHAPEHEADER *md_sptr2; + +} MORPHDISPLAY; + + +/* + + Morph Control Structure + +*/ + +typedef struct morphctrl { + + int ObMorphCurrFrame; + int ObMorphFlags; + int ObMorphSpeed; + MORPHHEADER *ObMorphHeader; + +} MORPHCTRL; + + +#endif /* SupportMorphing */ + + + +/* + + Object Display Block + +*/ + +typedef struct displayblock +{ + int ObShape; + + struct sfxblock *SfxPtr; + + SHAPEHEADER* ObShapeData; + + #if SupportWindows95 + char * name; + #endif + + #if (SupportMorphing && LazyEvaluationForMorphing) + VECTORCH *ObMorphedPts; + #endif + + VECTORCH ObWorld; /* World Space Location */ + EULER ObEuler; /* Euler Orientation */ + MATRIXCH ObMat; /* Local -> World Orientation Matrix */ + + int ObFlags; + int ObFlags2; + int ObFlags3; + + /* Lights */ + int ObNumLights; + LIGHTBLOCK *ObLights[MaxObjectLights]; + + #if SupportModules + struct module *ObMyModule; /* This is our module */ + struct module *ObModule; /* We are in this module */ + #endif + + VECTORCH ObView; /* View Space Location */ + + struct viewdescriptorblock *ObVDBPtr; + + /* Lights */ + int ObLightType; /* See LIGHTTYPES above */ + + /* Extent */ + int ObRadius; /* max(sqr(x^2+y^2+z^2)) */ + int ObMaxX; + int ObMinX; + int ObMaxY; + int ObMinY; + int ObMaxZ; + int ObMinZ; + + struct txactrlblk *ObTxAnimCtrlBlks; + + EXTRAITEMDATA *ObEIDPtr; /* Overrides shape EID pointer */ + + #if SupportMorphing + MORPHCTRL *ObMorphCtrl; /* Structure provided by project */ + #endif + + /* The Strategy Block Pointer */ + struct strategyblock *ObStrategyBlock; /* Defined in stratdef.h */ + + SHAPEANIMATIONCONTROLLER * ShapeAnimControlBlock; + + struct hmodelcontroller * HModelControlBlock; + + unsigned int SpecialFXFlags; + +} DISPLAYBLOCK; + + +/* + + Flags + +*/ + +#define ObFlag_InRange 0x00000001 +#define ObFlag_OnScreen 0x00000002 +#define ObFlag_NotVis 0x00000004 + + + + +#define ObFlag_VertexHazing 0x00000020 /* For I_Gouraud, interpolate hue + across the polygon */ + + +#define ObFlag_TypeZ 0x00000080 /* Shape uses Z Sort */ + + + + +#define ObFlag_SortFarZ 0x00008000 /* Z + Radius */ + +#define ObFlag_ArbRot 0x00010000 /* Internal use ONLY */ + +#define ObFlag_MultLSrc 0x00020000 /* Use Multiple Light Sources */ +#define ObFlag_NoInfLSrc 0x00040000 /* Ignore Infinite Light Sources */ +#define ObFlag_OnlyInfLSrc 0x00080000 /* Only Infinite Light Sources */ + + + + + + +#define ObFlag_ZBuffer 0x08000000 /* Request item z-buffering */ + +#define ObFlag_BFCRO 0x10000000 /* Back Face Cull Rot. Optimise */ +#define ObFlag_RSP 0x20000000 /* Radius Space Partitioning - + requires RFC data in shape */ + + +#define ObFlag_ParrallelBFC 0x80000000 /* Roxby's scu dsp flag */ + + +/* + + Flags 2 + +*/ + +#define ObFlag2_Deallocate 0x00000001 /* Deallocate block at frame end */ +#define ObFlag2_ObjLevelHaze 0x00000002 /* Hazing at object level */ + + +#define ObFlag2_AugZ 0x00000008 /* Augmented Z-Sort */ + + + + +#define ObFlag2_NoBFC 0x00000400 /* Disables Back Face Cull */ + + + + +#define ObFlag2_NotYetPos 0x00080000 /* Internal, for sub-objects */ + + +#define ObFlag2_NoSubObjectUpdate 0x00200000 /* If you are using your own + functions to position and + orient sub-objects, set this + flag and the sub-object in + question will be ignored by + the update function */ + + + + + + +#define ObFlag2_SortNearZ 0x20000000 /* Z - Radius */ + + + + +#define ObFlag2_SortD 0x80000000 /* Use distance rather than Z */ + + + +/* + + Flags 3 + +*/ + +#define ObFlag3_DynamicModuleObject 0x00000001 /* Allocate module objects + around this object as if + it were a camera */ + +#define ObFlag3_ObjectSortedItems 0x00000002 /* Used by the Global Sort */ + +#define ObFlag3_NoLightDot 0x00000004 /* Surface/Point is lit the + same from all angles */ + + +#define ObFlag3_Teleport 0x00000040 /* No motion vector! */ + +#define ObFlag3_SurfaceAlignDeluxe 0x00000080 /* Better but slower */ + +#define ObFlag3_PreLit 0x00000100 /* Not source specific */ + +#define ObFlag3_JustCreated 0x00000200 /* Teleport status for just + one frame */ + +#define ObFlag3_DontDrawIfOurModuleIsNotVis 0x00000400 /* If the module we + visible, don't + draw us */ +#define ObFlag3_AlwaysDynamic 0x00000800 /* Overrides auto-detect */ + + + + +#if SupportMorphing + +/* + + Morphing Flags + +*/ + +#define mph_flag_play 0x00000001 +#define mph_flag_reverse 0x00000002 +#define mph_flag_noloop 0x00000004 + +/* + + These four are set so that functions can be informed as to the state of + a sequence. They must be acknowledged and cleared for them to be of any + lasting use. The "start" and "end" flags are always set when the sequence + wraps. Depending on whether the sequence is looping or not, the "looped" or + "finished" flags will be set respectively. + +*/ + +#define mph_flag_start 0x00000008 +#define mph_flag_end 0x00000010 +#define mph_flag_finished 0x00000020 +#define mph_flag_looped 0x00000040 + +#endif + + + +/* + + Standard Points + +*/ + +typedef struct p2d { + + VECTOR2D point2d; + +} P2D; + +typedef struct p3d { + + VECTORCH point3d; + +} P3D; + + +/* + + Standard Points - Z-Buffered + +*/ + +#if ZBufferTest + +typedef struct p2d_zb { + + VECTOR2D point2d; + int z2d; + +} P2D_ZB; + +typedef struct p3d_zb { + + VECTORCH point3d; + int z3d; + +} P3D_ZB; + +#endif + +#if SupportZBuffering + +typedef struct p2d_zb { + + VECTOR2D point2d; + float z2d; + +} P2D_ZB; + +typedef struct p3d_zb { + + VECTORCH point3d; + float z3d; + +} P3D_ZB; + +#endif + + +/* + + Gouraud Points + +*/ + +typedef struct p2d_gouraud { + + VECTOR2D point2d; + int i2d; + +} P2D_GOURAUD; + +typedef struct p3d_gouraud { + + VECTORCH point3d; + int i3d; + +} P3D_GOURAUD; + + +/* + + Gouraud Points - Z-Buffered + +*/ + +#if ZBufferTest + +typedef struct p2d_gouraud_zb { + + VECTOR2D point2d; + int i2d; + int zg2d; + +} P2D_GOURAUD_ZB; + +typedef struct p3d_gouraud_zb { + + VECTORCH point3d; + int i3d; + int zg3d; + +} P3D_GOURAUD_ZB; + +#endif + +#if SupportZBuffering + +typedef struct p2d_gouraud_zb { + + VECTOR2D point2d; + int i2d; + float zg2d; + +} P2D_GOURAUD_ZB; + +typedef struct p3d_gouraud_zb { + + VECTORCH point3d; + int i3d; + float zg3d; + +} P3D_GOURAUD_ZB; + +#endif + + + +/* + + Phong Points + +*/ + +typedef struct p2d_phong { + + VECTOR2D point2d; + VECTORCH phong_normal2d; + +} P2D_PHONG; + + +typedef struct p3d_phong { + + VECTORCH point3d; + VECTORCH phong_normal3d; + +} P3D_PHONG; + + +/* + + Texture 2d Points + +*/ + +typedef struct p2d_texture2d { + + VECTOR2D point2d; + int u2d_2d; + int v2d_2d; + +} P2D_TEXTURE2D; + + +typedef struct p3d_texture2d { + + VECTORCH point3d; + int u3d_2d; + int v3d_2d; + +} P3D_TEXTURE2D; + + +/* + + Texture 2d Points - Z-Buffered + +*/ + +#if SupportZBuffering + +typedef struct p2d_texture2d_zb { + + VECTOR2D point2d; + int u2d_2d; + int v2d_2d; + float z2d_2d; + +} P2D_TEXTURE2D_ZB; + + +typedef struct p3d_texture2d_zb { + + VECTORCH point3d; + int u3d_2d; + int v3d_2d; + float z3d_2d; + +} P3D_TEXTURE2D_ZB; + +#endif + + +/* + + Texture 3d Points + +*/ + +#if support3dtextures + +#if int3dtextures + +typedef struct p2d_texture3d { + + VECTOR2D point2d; + int u2d_tx3d; + int v2d_tx3d; + int z2d_tx3d; + +} P2D_TEXTURE3D; + + +typedef struct p3d_texture3d { + + VECTORCH point3d; + int u3d_tx3d; + int v3d_tx3d; + +} P3D_TEXTURE3D; + +#else + +typedef struct p2d_texture3d { + + VECTOR2D point2d; + float u2d_tx3d; + float v2d_tx3d; + float z2d_tx3d; + +} P2D_TEXTURE3D; + + +typedef struct p3d_texture3d { + + VECTORCH point3d; + int u3d_tx3d; + int v3d_tx3d; + +} P3D_TEXTURE3D; + +#endif + +#endif + + +/* + + Texture 3d Points - Z-Buffered + +*/ + +#if 0 +#if (support3dtextures && SupportZBuffering) + +typedef struct p2d_texture3d_zb { + + VECTOR2D point2d; + float u2d_tx3d; + float v2d_tx3d; + float z2d_tx3d; + +} P2D_TEXTURE3D_ZB; + + +typedef struct p3d_texture3d_zb { + + VECTORCH point3d; + float u3d_tx3d; + float v3d_tx3d; + float z3d_tx3d; + +} P3D_TEXTURE3D_ZB; + +#endif +#endif + + +/* + + Gouraud Texture 2d Points + +*/ + +typedef struct p2d_gouraudtexture2d { + + VECTOR2D point2d; + int u2d_2d; + int v2d_2d; + int i2d_2d; + +} P2D_GOURAUDTEXTURE2D; + + +typedef struct p3d_gouraudtexture2d { + + VECTORCH point3d; + int u3d_2d; + int v3d_2d; + int i3d_2d; + +} P3D_GOURAUDTEXTURE2D; + + +/* + + Gouraud Texture 2d Points - Z-Buffered + +*/ + +#if SupportZBuffering + +typedef struct p2d_gouraudtexture2d_zb { + + VECTOR2D point2d; + int u2d_gtx2d; + int v2d_gtx2d; + int i2d_gtx2d; + float z2d_gtx2d; + +} P2D_GOURAUDTEXTURE2D_ZB; + + +typedef struct p3d_gouraudtexture2d_zb { + + VECTORCH point3d; + int u3d_gtx2d; + int v3d_gtx2d; + int i3d_gtx2d; + float z3d_gtx2d; + +} P3D_GOURAUDTEXTURE2D_ZB; + +#endif + + +#if SupportGouraud3dTextures + +/* + + Gouraud Texture 3d Points + +*/ + +typedef struct p2d_gouraudtexture3d { + + VECTOR2D point2d; + float u2d_gtx3d; + float v2d_gtx3d; + float z2d_gtx3d; + int i2d_gtx3d; + +} P2D_GOURAUDTEXTURE3D; + + +typedef struct p3d_gouraudtexture3d { + + VECTORCH point3d; + int u3d_gtx3d; + int v3d_gtx3d; + int i3d_gtx3d; + +} P3D_GOURAUDTEXTURE3D; + +#endif /* SupportGouraud3dTextures */ + + + +/* + + Polygon Points. + + These are the points as they appear to a Scan Convertor. Item pointers are + cast as these structs by the SC to make their life easier. + +*/ + + +/* + + I_Polygon + +*/ + +typedef struct i_polygon_pt { + + int i_x; + int i_y; + +} I_POLYGON_PT; + + +/* + + I_Polygon_ZBuffer + +*/ + +#if ZBufferTest + +typedef struct i_polygon_zbuffer_pt { + + int i_x; + int i_y; + int i_z; + +} I_POLYGON_ZBUFFER_PT; + +#endif + +#if SupportZBuffering + +typedef struct i_polygon_zbuffer_pt { + + int i_x; + int i_y; + float i_z; + +} I_POLYGON_ZBUFFER_PT; + +#endif + + +/* + + I_GouraudPolygon + +*/ + +typedef struct i_gouraudpolygon_pt { + + int i_x; + int i_y; + int i_int; + +} I_GOURAUDPOLYGON_PT; + + +/* + + I_GouraudPolygon_ZBuffer + +*/ + +#if ZBufferTest + +typedef struct i_gouraudpolygon_zbuffer_pt { + + int i_x; + int i_y; + int i_int; + int i_gz; + +} I_GOURAUDPOLYGON_ZBUFFER_PT; + +#endif + +#if SupportZBuffering + +typedef struct i_gouraudpolygon_zbuffer_pt { + + int i_x; + int i_y; + int i_int; + float i_gz; + +} I_GOURAUDPOLYGON_ZBUFFER_PT; + +#endif + + +/* + + I_PhongPolygon + +*/ + +typedef struct i_phongpolygon_pt { + + int i_x; + int i_y; + + VECTORCH i_n; + +} I_PHONGPOLYGON_PT; + +#if SupportZBuffering + +typedef struct i_phongpolygon_zbuffer_pt { + + int i_x; + int i_y; + + VECTORCH i_n; + + float i_pz; + +} I_PHONGPOLYGON_ZBUFFER_PT; + +#endif + + +/* + + I_2dTexturePolygon + +*/ + +typedef struct i_2dtexturepolygon_pt { + + int i_x; + int i_y; + + int i_u; + int i_v; + +} I_2DTEXTUREPOLYGON_PT; + +#if SupportZBuffering + +typedef struct i_2dtexturepolygon_zbuffer_pt { + + int i_x; + int i_y; + + int i_u; + int i_v; + + float i_tx2dz; + +} I_2DTEXTUREPOLYGON_ZBUFFER_PT; + +#endif + + +/* + + I_3dTexturePolygon + +*/ + +#if support3dtextures + +#if int3dtextures + +typedef struct i_3dtexturepolygon_pt { + + int i_x; + int i_y; + + int i_tx3d_u; + int i_tx3d_v; + int i_tx3d_z; + +} I_3DTEXTUREPOLYGON_PT; + +#else + +typedef struct i_3dtexturepolygon_pt { + + int i_x; + int i_y; + + float i_tx3d_u; + float i_tx3d_v; + float i_tx3d_z; + +} I_3DTEXTUREPOLYGON_PT; + +#endif + +#if SupportZBuffering + +typedef struct i_3dtexturepolygon_zbuffer_pt { + + int i_x; + int i_y; + + float i_tx3d_u; + float i_tx3d_v; + float i_tx3d_z; + +} I_3DTEXTUREPOLYGON_ZBUFFER_PT; + +#endif + +#endif + + +/* + + I_Gouraud2dTexturePolygon + +*/ + +typedef struct i_gouraud2dtexturepolygon_pt { + + int i_x; + int i_y; + + int i_u; + int i_v; + + int i_i; + +} I_GOURAUD2DTEXTUREPOLYGON_PT; + + +#if SupportZBuffering + +typedef struct i_gouraud2dtexturepolygon_zbuffer_pt { + + int i_x; + int i_y; + + int i_u; + int i_v; + + int i_i; + + float i_gtx2dz; + +} I_GOURAUD2DTEXTUREPOLYGON_ZBUFFER_PT; + +#endif + + +#if SupportGouraud3dTextures + +/* + + I_Gouraud3dTexturePolygon + +*/ + +typedef struct i_gouraud3dtexturepolygon_pt { + + int i_x; + int i_y; + + float i_gtx3d_u; + float i_gtx3d_v; + float i_gtx3d_z; + + int i_gtx3d_i; + +} I_GOURAUD3DTEXTUREPOLYGON_PT; + +#endif /* SupportGouraud3dTextures */ + + +/* + + Clip Point Structure. + + Points P, S, F and I use this structure. + +*/ + +typedef struct clip_point { + + VECTORCH ClipPoint; + VECTORCH ClipNormal; + TEXEL ClipTexel; + int ClipInt; + int ClipZBuffer; + +} CLIP_POINT; + + +#if support3dtextures + +#if int3dtextures + +typedef struct clip_point_f { + + VECTORCH ClipPointF; + VECTORCH ClipNormalF; + TEXELF ClipTexelF; + int ClipIntF; + int ClipZBufferF; + +} CLIP_POINT_F; + +#else + +typedef struct clip_point_f { + + VECTORCH ClipPointF; + VECTORCH ClipNormalF; + TEXELF ClipTexelF; + int ClipIntF; + float ClipZBufferF; + +} CLIP_POINT_F; + +#endif + +#endif + + +#if SupportGouraud3dTextures + +typedef struct clip_point_gtx3d { + + VECTORCH ClipPointF; + VECTORCH ClipNormalF; + TEXELGTX3D ClipTexelF; + int ClipIntF; + float ClipZBufferF; + +} CLIP_POINT_GTX3D; + +#endif + + + + +/* + + Scan Data Blocks. + + These are the structures in ScanData[] that the SC outputs. Memory is + allocated from ScanData[] as int* but is cast to the following structures + by the SC for ease of use. + +*/ + +typedef struct i_polygon_scan { + + int ips_colour; + int ips_x1; + int ips_x2; + int ips_y; + +} I_POLYGON_SCAN; + +#if ZBufferTest + +typedef struct i_polygon_zbuffer_scan { + + int ips_colour; + int ips_x1; + int ips_x2; + int ips_y; + int ips_z1; + int ips_z2; + +} I_POLYGON_ZBUFFER_SCAN; + +#endif + +#if SupportZBuffering + +typedef struct i_polygon_zbuffer_scan { + + int ips_colour; + int ips_x1; + int ips_x2; + int ips_y; + float ips_z1; + float ips_z2; + +} I_POLYGON_ZBUFFER_SCAN; + +#endif + + +typedef struct i_gouraudpolygon_scan { + + int igs_c1; + int igs_c2; + + int igs_x1; + int igs_x2; + + int igs_y; + +} I_GOURAUDPOLYGON_SCAN; + +#if ZBufferTest + +typedef struct i_gouraudpolygon_zbuffer_scan { + + int igs_c1; + int igs_c2; + + int igs_x1; + int igs_x2; + + int igs_y; + + int igs_z1; + int igs_z2; + +} I_GOURAUDPOLYGON_ZBUFFER_SCAN; + +#endif + +#if SupportZBuffering + +typedef struct i_gouraudpolygon_zbuffer_scan { + + int igs_c1; + int igs_c2; + + int igs_x1; + int igs_x2; + + int igs_y; + + float igs_z1; + float igs_z2; + +} I_GOURAUDPOLYGON_ZBUFFER_SCAN; + +#endif + + +typedef struct i_phongpolygon_scan { + + VECTORCH ips_n1; + VECTORCH ips_n2; + + int ips_x1; + int ips_x2; + + int ips_y; + +} I_PHONGPOLYGON_SCAN; + +#if SupportZBuffering + +typedef struct i_phongpolygon_zbuffer_scan { + + VECTORCH ips_n1; + VECTORCH ips_n2; + + int ips_x1; + int ips_x2; + + int ips_y; + + float ips_z1; + float ips_z2; + +} I_PHONGPOLYGON_ZBUFFER_SCAN; + +#endif + + +typedef struct i_2dtexturepolygon_scan { + + int i2s_u1; + int i2s_v1; + + int i2s_u2; + int i2s_v2; + + int i2s_x1; + int i2s_x2; + + int i2s_y; + +} I_2DTEXTUREPOLYGON_SCAN; + +#if SupportZBuffering + +typedef struct i_2dtexturepolygon_zbuffer_scan { + + int i2s_u1; + int i2s_v1; + + int i2s_u2; + int i2s_v2; + + int i2s_x1; + int i2s_x2; + + int i2s_y; + + float i2s_z1; + float i2s_z2; + +} I_2DTEXTUREPOLYGON_ZBUFFER_SCAN; + +#endif + + +#if support3dtextures + +#if int3dtextures + +typedef struct i_3dtexturepolygon_scan { + + int i3s_u1; + int i3s_v1; + int i3s_z1; + + int i3s_u2; + int i3s_v2; + int i3s_z2; + + int i3s_x1; + int i3s_x2; + + int i3s_y; + +} I_3DTEXTUREPOLYGON_SCAN; + +#else + +typedef struct i_3dtexturepolygon_scan { + + float i3s_u1; + float i3s_v1; + float i3s_z1; + + float i3s_u2; + float i3s_v2; + float i3s_z2; + + int i3s_x1; + int i3s_x2; + + int i3s_y; + +} I_3DTEXTUREPOLYGON_SCAN; + +#endif + +#if SupportZBuffering + +typedef struct i_3dtexturepolygon_zbuffer_scan { + + float i3s_u1; + float i3s_v1; + float i3s_z1; + + float i3s_u2; + float i3s_v2; + float i3s_z2; + + int i3s_x1; + int i3s_x2; + + int i3s_y; + +} I_3DTEXTUREPOLYGON_ZBUFFER_SCAN; + +#endif + +#endif + + +typedef struct i_gouraud2dtexturepolygon_scan { + + int ig2s_u1; + int ig2s_v1; + int ig2s_c1; + + int ig2s_u2; + int ig2s_v2; + int ig2s_c2; + + int ig2s_x1; + int ig2s_x2; + + int ig2s_y; + +} I_GOURAUD2DTEXTUREPOLYGON_SCAN; + +#if SupportZBuffering + +typedef struct i_gouraud2dtexturepolygon_zbuffer_scan { + + int ig2s_u1; + int ig2s_v1; + int ig2s_c1; + + int ig2s_u2; + int ig2s_v2; + int ig2s_c2; + + int ig2s_x1; + int ig2s_x2; + + int ig2s_y; + + float ig2s_z1; + float ig2s_z2; + +} I_GOURAUD2DTEXTUREPOLYGON_ZBUFFER_SCAN; + +#endif + + +#if SupportGouraud3dTextures + +typedef struct i_gouraud3dtexturepolygon_scan { + + float ig3s_u1; + float ig3s_v1; + float ig3s_z1; + int ig3s_c1; + + float ig3s_u2; + float ig3s_v2; + float ig3s_z2; + int ig3s_c2; + + int ig3s_x1; + int ig3s_x2; + + int ig3s_y; + +} I_GOURAUD3DTEXTUREPOLYGON_SCAN; + +#endif /* SupportGouraud3dTextures */ + + + + +/* + + Functions + +*/ + +#if SupportWindows95 +void ClearScreen(SCREENDESCRIPTORBLOCK *sdb, int Colour); +#endif + + +void PlatformSpecificShowViewEntry(VIEWDESCRIPTORBLOCK *vdb, SCREENDESCRIPTORBLOCK *sdb); +void PlatformSpecificShowViewExit(VIEWDESCRIPTORBLOCK *vdb, SCREENDESCRIPTORBLOCK *sdb); +void AddShape(DISPLAYBLOCK *dblockptr, VIEWDESCRIPTORBLOCK *VDB_Ptr); +void PrepareVDBForShowView(VIEWDESCRIPTORBLOCK *VDB_Ptr); + + +void SetupLight( + LIGHTBLOCK *lptr, + int sl_flags, + int sl_type, + VECTORCH *sl_world, + VECTORCH *sl_dir, + int sl_panx, + int sl_pany, + int sl_bright, + int sl_spread, + int sl_range +); + +void UpdateObjectLights(DISPLAYBLOCK *dptr); + +DISPLAYBLOCK* ReadMap(MAPHEADER *mapptr); + +void MapPostProcessing(DISPLAYBLOCK *dptr); +void ObjectQuatAndMat(DISPLAYBLOCK *dblockptr); +void MapBlockInit(DISPLAYBLOCK *dblockptr); +void MapSetVDB(DISPLAYBLOCK *dptr, MAPSETVDB *mapvdbdata); + +#if ProjectSpecificVDBs +void ProjectSpecificVDBDestroy(VIEWDESCRIPTORBLOCK *vdb); +void ProjectSpecificVDBInit(VIEWDESCRIPTORBLOCK *vdb); +#endif + + +void UpdateGame(void); + + + + + +SHAPEHEADER* GetShapeData(int shapenum); + + +#if flic_player + +/* + + FLIC File Player and Options + +*/ + +int PlayFLICFile(char *fname, int fflags, int floops, unsigned char *pal); + +#define FFlag_DiskPlay 0x00000001 /* Force a disk play */ + +#define FFlag_FadeDownFirst 0x00000002 /* First FLIC only */ + +#define FFlag_RestoreScreen 0x00000004 /* Last FLIC only - + Copy the current contents + of the screen buffer back to + the video memory and fade up + the old palette */ + +#define FFlag_EnableFade 0x00000008 /* NOT fading is the default */ + + #endif + + + + + + + +void InitialiseObjectBlocks(void); + +DISPLAYBLOCK* AllocateObjectBlock(void); +void DeallocateObjectBlock(DISPLAYBLOCK *dblockptr); + +DISPLAYBLOCK* CreateActiveObject(void); +int DestroyActiveObject(DISPLAYBLOCK *dblockptr); + + +void InitialiseStrategyBlocks(void); +struct strategyblock* AllocateStrategyBlock(void); +void DeallocateStrategyBlock(struct strategyblock *sptr); + +struct strategyblock* CreateActiveStrategyBlock(void); +int DestroyActiveStrategyBlock(struct strategyblock*dblockptr); + + + + +void InitialiseTxAnimBlocks(void); +TXACTRLBLK* AllocateTxAnimBlock(void); +void DeallocateTxAnimBlock(TXACTRLBLK *TxAnimblockptr); +void AddTxAnimBlock(DISPLAYBLOCK *dptr, TXACTRLBLK *taptr); +TXANIMHEADER* GetTxAnimHeaderFromShape(TXACTRLBLK *taptr, int shape); +void UpdateTxAnim(TXANIMHEADER *txah); +void ChangeSequence(TXANIMHEADER *txah_old, TXANIMHEADER *txah_new); +void ControlTextureAnimation(DISPLAYBLOCK *dptr); + + + + + +int DisplayAndLightBlockDeallocation(void); + + +void InitialiseLightBlocks(void); + +LIGHTBLOCK* AllocateLightBlock(void); +void DeallocateLightBlock(LIGHTBLOCK *lptr); + +LIGHTBLOCK* AddLightBlock(DISPLAYBLOCK *dptr, LIGHTBLOCK *lptr_to_add); +void DeleteLightBlock(LIGHTBLOCK *lptr, DISPLAYBLOCK *dptr); + + + +void VDBClipPlanes(VIEWDESCRIPTORBLOCK *vdb); + +void MakeClipPlane( + +VIEWDESCRIPTORBLOCK *vdb, +CLIPPLANEBLOCK *cpb, +CLIPPLANEPOINTS *cpp); + +void SetVDB(VIEWDESCRIPTORBLOCK *vdb, + + int fl, + int ty, + + int d, + + int cx, + int cy, + + int prx, + int pry, + int mxp, + + int cl, + int cr, + int cu, + int cd, + + int h1, + int h2, + int hcolour, + int ambience + ); + + +void InitialiseVDBs(void); + +VIEWDESCRIPTORBLOCK* AllocateVDB(void); +void DeallocateVDB(VIEWDESCRIPTORBLOCK *dblockptr); + +VIEWDESCRIPTORBLOCK* CreateActiveVDB(void); +int DestroyActiveVDB(VIEWDESCRIPTORBLOCK *dblockptr); + +void PlatformSpecificVDBInit(VIEWDESCRIPTORBLOCK *vdb); + + +int SqRoot32(int A); +int SqRoot64(LONGLONGCH *A); +/* CDF 4/2/98 */ +int GetOneOverSin(int a); +/* CDF 4/2/98 */ +int _DotProduct(VECTORCH *v1, VECTORCH *v2); + +int DotProduct2d(VECTOR2D *v1, VECTOR2D *v2); + + +void MakeNormal( + +VECTORCH *v1, +VECTORCH *v2, +VECTORCH *v3, +VECTORCH *v4); + +void GetNormalVector(VECTORCH *v1, VECTORCH *v2, VECTORCH *v3); + +void Normalise(VECTORCH *nvector); +void MNormalise(MATRIXCH *m); + +void Normalise2d(VECTOR2D *nvector); + +int LineColinearity(LINE *l0, LINE *l1); + +void Renormalise(VECTORCH *nvector); + +int Magnitude(VECTORCH *v); + + + +int VectorDistance(VECTORCH *v1, VECTORCH *v2); +int OutcodeVectorDistance(VECTORCH *v1, VECTORCH *v2, int d); + +void MatrixFromZVector(VECTORCH *v, MATRIXCH *m); + + +int PointInPolygon(int *point, int *polygon, int c, int ppsize); + +void PolyAveragePoint(POLYHEADER *pheader, int *spts, VECTORCH *apt); + +int FindShift32(int value, int limit); +int FindShift64(LONGLONGCH *value, LONGLONGCH *limit); + +void MaxLONGLONGCH(LONGLONGCH *llarrayptr, int llarraysize, LONGLONGCH *llmax); + +int MaxInt(int *iarray, int iarraysize); +int MinInt(int *iarray, int iarraysize); + + + + +/* + + Some Maths Functions + +*/ + +void CreateEulerMatrix(EULER *e, MATRIXCH *m1); +void CreateEulerVector(EULER *e, VECTORCH *v); + + + +void MatrixMultiply( + +MATRIXCH *m1, +MATRIXCH *m2, +MATRIXCH *m3); + +void TransposeMatrixCH(MATRIXCH *m1); + +void CopyVector(VECTORCH *v1, VECTORCH *v2); +void CopyLocation(VECTORCH *v1, VECTORCH *v2); + + +void CopyEuler(EULER *e1, EULER *e2); +void CopyMatrix(MATRIXCH *m1, MATRIXCH *m2); + +void MakeVector(VECTORCH *v1, VECTORCH *v2, VECTORCH *v3); +void AddVector(VECTORCH *v1, VECTORCH *v2); +void SubVector(VECTORCH *v1, VECTORCH *v2); +void QuatToMat(QUAT *q,MATRIXCH *m); + + +void _RotateVector( + + VECTORCH *v, + MATRIXCH *m); + + +void _RotateAndCopyVector( + + VECTORCH *v1, + VECTORCH *v2, + MATRIXCH *m); + + +void MakeVectorLocal(VECTORCH *v1, VECTORCH *v2, VECTORCH *v3, MATRIXCH *m); + + + + + +void MatrixToEuler(MATRIXCH *m, EULER *e); +void MatrixToEuler2(MATRIXCH *m, EULER *e); + +int ArcCos(int); +int ArcSin(int); +int ArcTan(int, int); + +int FandVD_Distance_2d(VECTOR2D *v0, VECTOR2D *v1); +int FandVD_Distance_3d(VECTORCH *v0, VECTORCH *v1); + +int Distance_2d(VECTOR2D *v0, VECTOR2D *v1); +int Distance_3d(VECTORCH *v0, VECTORCH *v1); + + +/* + + Shape Language Functions + + Each function requires a pointer to SHAPEINSTR + +*/ + +void SetupShapeLanguage(SHAPEHEADER *shapeheaderptr); + +void ShapePointsInstr(SHAPEINSTR *shapeinstrptr); + + +void ShapeSpritePointsInstr(SHAPEINSTR *shapeinstrptr); +void ShapeSpriteRPointsInstr(SHAPEINSTR *shapeinstrptr); + + +void BackFaceCullPointOutcodeFlagging(void); + + + + + + +/* + + Platform Specific Functions + +*/ + +#if SupportWindows95 +void InitialiseSystem(HINSTANCE hInstance, int nCmdShow); +#else +void InitialiseSystem(void); +#endif + +void InitialiseRenderer(void); + +void ExitSystem(void); + +void InitialVideoMode(void); + +void ResetFrameCounter(void); +void FrameCounterHandler(void); + +#if SupportWindows95 +void DirectWriteD3DLine(VECTOR2D* LineStart, VECTOR2D* LineEnd, int LineColour); +void* LoadImageIntoDirectDrawSurface(char *fname, IMAGEHEADER *iheader, + int ImageLoadMode, BOOL Sysmem); +void* LoadImageIntoD3DImmediateSurface(char *fname, IMAGEHEADER *iheader, + int TextureFileType); +void* LoadImageIntoD3DTexture(char *fname, IMAGEHEADER *iheader, + int TextureFileType); +void ReloadImageIntoD3DImmediateSurface(IMAGEHEADER* iheader); +void* ReloadImageIntoD3DTexture(IMAGEHEADER* iheader); +int GetTextureHandle(IMAGEHEADER *imageHeaderPtr); + +void* LoadFontIntoDirectDrawSurface(char *fname, IMAGEHEADER *iheader); +void ClearScreen(SCREENDESCRIPTORBLOCK* sdb, int Colour); +#ifdef __cplusplus +LPDIRECTDRAWSURFACE LoadPPMInD3DMode(char* fname, + LPDDSURFACEDESC lpFormat, IMAGEHEADER* iheader, + int MemoryType); +LPDIRECTDRAWSURFACE LoadPPMIntoDDSurface(LPDIRECTDRAWSURFACE lpDDS, + DDSURFACEDESC format, int Height, int Width, + IMAGEHEADER* iheader, BOOL Quantise, FILE* fp, + int psize, int pcaps, char* fname, int MipNum); +LPDIRECTDRAWSURFACE LoadPGMInD3DMode(char* fname, + LPDDSURFACEDESC lpFormat, IMAGEHEADER* iheader, + int MemoryType); +#endif // for __cplusplus +#endif // for SupportWindows95 + +void InitGame(void); +void StartGame(void); +void ExitGame(void); + +void InitialiseParallelStrategy(void); +void UpdateParallelStrategy(void); + +unsigned char* AllocateScreenBuffer(int sbuffersize); + + +#if 0 + +#if 0 +void *AllocateMem(size_t __size); +void DeallocateMem(void *__ptr); +#endif + +#if PSX + #ifdef DBGMALLOC + extern void *record_malloc(long size, char string[], unsigned long lineno); + extern void record_free(void *ptr,char string[], unsigned long lineno); + #define AllocateMem(x) record_malloc(x,__FILE__, __LINE__) + #define DeallocateMem(x) record_free(x,__FILE__, __LINE__) + #else + void *AllocateMem(size_t __size); + void DeallocateMem(void *__ptr); + #endif +#else +void *AllocateMem(size_t __size); +void DeallocateMem(void *__ptr); +#endif + +#endif + + +void ScanDraw_Item_Polygon_VideoModeType_8(int *itemptr); +void ScanDraw_Item_Polygon_VideoModeType_15(int *itemptr); +void ScanDraw_Item_Polygon_VideoModeType_24(int *itemptr); +void ScanDraw_Item_Polygon_VideoModeType_8T(int *itemptr); + +#if (ZBufferTest || SupportZBuffering) +void ScanDraw_Item_Polygon_ZBuffer_VideoModeType_8(int *itemptr); +void ScanDraw_Item_Polygon_ZBuffer_VideoModeType_15(int *itemptr); +void ScanDraw_Item_Polygon_ZBuffer_VideoModeType_24(int *itemptr); +void ScanDraw_Item_Polygon_ZBuffer_VideoModeType_8T(int *itemptr); +#endif + +void ScanDraw_Item_GouraudPolygon_VideoModeType_8(int *itemptr); +void ScanDraw_Item_GouraudPolygon_VideoModeType_15(int *itemptr); +void ScanDraw_Item_GouraudPolygon_VideoModeType_24(int *itemptr); +void ScanDraw_Item_GouraudPolygon_VideoModeType_8T(int *itemptr); + +void ScanDraw_Item_GouraudPolygon_HPV_VideoModeType_15(int *itemptr); +void ScanDraw_Item_GouraudPolygon_HPV_VideoModeType_24(int *itemptr); +void ScanDraw_Item_GouraudPolygon_HPV_VideoModeType_8T(int *itemptr); + +#if ZBufferTest +void ScanDraw_Item_GouraudPolygon_ZBuffer_VideoModeType_8(int *itemptr); +void ScanDraw_Item_GouraudPolygon_ZBuffer_VideoModeType_15(int *itemptr); +void ScanDraw_Item_GouraudPolygon_ZBuffer_VideoModeType_24(int *itemptr); +void ScanDraw_Item_GouraudPolygon_ZBuffer_VideoModeType_8T(int *itemptr); +#endif + +#if SupportZBuffering +void ScanDraw_ZB_Item_GouraudPolygon_VideoModeType_8(int *itemptr); +void ScanDraw_ZB_Item_GouraudPolygon_VideoModeType_15(int *itemptr); +void ScanDraw_ZB_Item_GouraudPolygon_VideoModeType_24(int *itemptr); +void ScanDraw_ZB_Item_GouraudPolygon_VideoModeType_8T(int *itemptr); +#endif + +void ScanDraw_Item_2dTexturePolygon_VideoModeType_8(int *itemptr); +void ScanDraw_Item_2dTexturePolygon_VideoModeType_15(int *itemptr); +void ScanDraw_Item_2dTexturePolygon_VideoModeType_24(int *itemptr); +void ScanDraw_Item_2dTexturePolygon_VideoModeType_8T(int *itemptr); + +#if SupportZBuffering +void ScanDraw_ZB_Item_2dTexturePolygon_VideoModeType_8(int *itemptr); +void ScanDraw_ZB_Item_2dTexturePolygon_VideoModeType_15(int *itemptr); +void ScanDraw_ZB_Item_2dTexturePolygon_VideoModeType_24(int *itemptr); +void ScanDraw_ZB_Item_2dTexturePolygon_VideoModeType_8T(int *itemptr); +#endif + +void ScanDraw_Item_Gouraud2dTexturePolygon_VideoModeType_8(int *itemptr); +void ScanDraw_Item_Gouraud2dTexturePolygon_VideoModeType_15(int *itemptr); +void ScanDraw_Item_Gouraud2dTexturePolygon_VideoModeType_24(int *itemptr); +void ScanDraw_Item_Gouraud2dTexturePolygon_VideoModeType_8T(int *itemptr); + +void ScanDraw_Item_ZB_Gouraud2dTexturePolygon_VideoModeType_8(int *itemptr); +void ScanDraw_Item_ZB_Gouraud2dTexturePolygon_VideoModeType_15(int *itemptr); +void ScanDraw_Item_ZB_Gouraud2dTexturePolygon_VideoModeType_24(int *itemptr); +void ScanDraw_Item_ZB_Gouraud2dTexturePolygon_VideoModeType_8T(int *itemptr); + + +#if support3dtextures +void ScanDraw_Item_3dTexturePolygon_VideoModeType_8(int *itemptr); +void ScanDraw_Item_3dTexturePolygon_VideoModeType_15(int *itemptr); +void ScanDraw_Item_3dTexturePolygon_VideoModeType_24(int *itemptr); +void ScanDraw_Item_3dTexturePolygon_VideoModeType_8T(int *itemptr); +#endif + +#if SupportGouraud3dTextures + +void ScanDraw_Item_Gouraud3dTexturePolygon_VideoModeType_8(int *itemptr); +void ScanDraw_Item_Gouraud3dTexturePolygon_VideoModeType_15(int *itemptr); +void ScanDraw_Item_Gouraud3dTexturePolygon_VideoModeType_24(int *itemptr); +void ScanDraw_Item_Gouraud3dTexturePolygon_VideoModeType_8T(int *itemptr); + +void ScanDraw_Item_Gouraud3dTexturePolygon_Linear_VideoModeType_8(int *itemptr); +void ScanDraw_Item_Gouraud3dTexturePolygon_Linear_VideoModeType_15(int *itemptr); +void ScanDraw_Item_Gouraud3dTexturePolygon_Linear_VideoModeType_24(int *itemptr); +void ScanDraw_Item_Gouraud3dTexturePolygon_Linear_VideoModeType_8T(int *itemptr); + +void ScanDraw_Item_Gouraud3dTexturePolygon_Linear_S_VideoModeType_8(int *itemptr); +void ScanDraw_Item_Gouraud3dTexturePolygon_Linear_S_VideoModeType_15(int *itemptr); +void ScanDraw_Item_Gouraud3dTexturePolygon_Linear_S_VideoModeType_24(int *itemptr); +void ScanDraw_Item_Gouraud3dTexturePolygon_Linear_S_VideoModeType_8T(int *itemptr); + +#if SupportZBuffering + +void ScanDraw_Item_ZB_Gouraud3dTexturePolygon_VideoModeType_8(int *itemptr); +void ScanDraw_Item_ZB_Gouraud3dTexturePolygon_VideoModeType_15(int *itemptr); +void ScanDraw_Item_ZB_Gouraud3dTexturePolygon_VideoModeType_24(int *itemptr); +void ScanDraw_Item_ZB_Gouraud3dTexturePolygon_VideoModeType_8T(int *itemptr); + +void ScanDraw_Item_ZB_Gouraud3dTexturePolygon_Linear_VideoModeType_8(int *itemptr); +void ScanDraw_Item_ZB_Gouraud3dTexturePolygon_Linear_VideoModeType_15(int *itemptr); +void ScanDraw_Item_ZB_Gouraud3dTexturePolygon_Linear_VideoModeType_24(int *itemptr); +void ScanDraw_Item_ZB_Gouraud3dTexturePolygon_Linear_VideoModeType_8T(int *itemptr); + +void ScanDraw_Item_ZB_Gouraud3dTexturePolygon_Linear_S_VideoModeType_8(int *itemptr); +void ScanDraw_Item_ZB_Gouraud3dTexturePolygon_Linear_S_VideoModeType_15(int *itemptr); +void ScanDraw_Item_ZB_Gouraud3dTexturePolygon_Linear_S_VideoModeType_24(int *itemptr); +void ScanDraw_Item_ZB_Gouraud3dTexturePolygon_Linear_S_VideoModeType_8T(int *itemptr); + +#endif /* SupportZBuffering */ + +#endif /* SupportGouraud3dTextures */ + +#if support3dtextures + +#if SupportZBuffering +void ScanDraw_Item_ZB_3dTexturePolygon_VideoModeType_8(int *itemptr); +void ScanDraw_Item_ZB_3dTexturePolygon_VideoModeType_15(int *itemptr); +void ScanDraw_Item_ZB_3dTexturePolygon_VideoModeType_24(int *itemptr); +void ScanDraw_Item_ZB_3dTexturePolygon_VideoModeType_8T(int *itemptr); +#endif + +void ScanDraw_Item_3dTexturePolygon_QuadI_VideoModeType_8(int *itemptr); +void ScanDraw_Item_3dTexturePolygon_QuadI_VideoModeType_15(int *itemptr); +void ScanDraw_Item_3dTexturePolygon_QuadI_VideoModeType_24(int *itemptr); +void ScanDraw_Item_3dTexturePolygon_QuadI_VideoModeType_8T(int *itemptr); + +#if SupportZBuffering +void ScanDraw_ZB_Item_3dTexturePolygon_QuadI_VideoModeType_8(int *itemptr); +void ScanDraw_ZB_Item_3dTexturePolygon_QuadI_VideoModeType_15(int *itemptr); +void ScanDraw_ZB_Item_3dTexturePolygon_QuadI_VideoModeType_24(int *itemptr); +void ScanDraw_ZB_Item_3dTexturePolygon_QuadI_VideoModeType_8T(int *itemptr); +#endif + +void ScanDraw_Item_3dTexturePolygon_Linear_VideoModeType_8(int *itemptr); +void ScanDraw_Item_3dTexturePolygon_Linear_VideoModeType_15(int *itemptr); +void ScanDraw_Item_3dTexturePolygon_Linear_VideoModeType_24(int *itemptr); +void ScanDraw_Item_3dTexturePolygon_Linear_VideoModeType_8T(int *itemptr); + +#if SupportZBuffering +void ScanDraw_Item_ZB_3dTexturePolygon_Linear_VideoModeType_8(int *itemptr); +void ScanDraw_Item_ZB_3dTexturePolygon_Linear_VideoModeType_15(int *itemptr); +void ScanDraw_Item_ZB_3dTexturePolygon_Linear_VideoModeType_24(int *itemptr); +void ScanDraw_Item_ZB_3dTexturePolygon_Linear_VideoModeType_8T(int *itemptr); +#endif + +void ScanDraw_Item_3dTexturePolygon_Linear_S_VideoModeType_8(int *itemptr); +void ScanDraw_Item_3dTexturePolygon_Linear_S_VideoModeType_15(int *itemptr); +void ScanDraw_Item_3dTexturePolygon_Linear_S_VideoModeType_24(int *itemptr); +void ScanDraw_Item_3dTexturePolygon_Linear_S_VideoModeType_8T(int *itemptr); + +#if SupportZBuffering +void ScanDraw_Item_ZB_3dTexturePolygon_Linear_S_VideoModeType_8(int *itemptr); +void ScanDraw_Item_ZB_3dTexturePolygon_Linear_S_VideoModeType_15(int *itemptr); +void ScanDraw_Item_ZB_3dTexturePolygon_Linear_S_VideoModeType_24(int *itemptr); +void ScanDraw_Item_ZB_3dTexturePolygon_Linear_S_VideoModeType_8T(int *itemptr); +#endif + +#endif /* support3dtextures */ + +void ScanDraw_Item_Polyline_VideoModeType_8(int *itemptr); +void ScanDraw_Item_Polyline_VideoModeType_15(int *itemptr); +void ScanDraw_Item_Polyline_VideoModeType_24(int *itemptr); +void ScanDraw_Item_Polyline_VideoModeType_8T(int *itemptr); + +void ScanDraw_Item_FilledPolyline_VideoModeType_8(int *itemptr); +void ScanDraw_Item_FilledPolyline_VideoModeType_15(int *itemptr); +void ScanDraw_Item_FilledPolyline_VideoModeType_24(int *itemptr); +void ScanDraw_Item_FilledPolyline_VideoModeType_8T(int *itemptr); + +void ScanDraw_Item_Wireframe_VideoModeType_8(int *itemptr); +void ScanDraw_Item_Wireframe_VideoModeType_15(int *itemptr); +void ScanDraw_Item_Wireframe_VideoModeType_24(int *itemptr); +void ScanDraw_Item_Wireframe_VideoModeType_8T(int *itemptr); + +#if 0 +void ScanDraw_Item_HUDPolyline_VideoModeType_8(int *itemptr); +void ScanDraw_Item_HUDPolyline_VideoModeType_15(int *itemptr); +void ScanDraw_Item_HUDPolyline_VideoModeType_24(int *itemptr); +void ScanDraw_Item_HUDPolyline_VideoModeType_8T(int *itemptr); +#endif + +void SetPalette(unsigned char *palette); + +void MakeTextureLightingTable6(void); +void MakeTextureLightingTable6G(void); +void MakeTextureLightingTable15(void); +void MakeTextureLightingTable24(void); +void MakeTextureLightingTable8T(void); + +void CreatePaletteRemapTable(unsigned char *palette); +unsigned char GetRemappedPaletteColour(int r, int g, int b, int bitsize); + +int NearestColour(int rs, int gs, int bs, unsigned char *palette); + +#if LoadingMapsShapesAndTexturesEtc + +void InitialiseImageHeaders(void); +int LoadImagesForShapes(SHAPEHEADER **shapelist); + +#else + +int InitialiseTextures(void); + +#endif + +void MakeShapeTexturesGlobal(SHAPEHEADER *shptr, int TxIndex, int LTxIndex); +void MakeTxAnimFrameTexturesGlobal(SHAPEHEADER *sptr, + POLYHEADER *pheader, + int LTxIndex, int TxIndex); + +void SpriteResizing(SHAPEHEADER *sptr); + +void FindImageExtents(IMAGEHEADER *ihdr, int numuvs, int *uvdata, IMAGEEXTENTS *e, IMAGEEXTENTS *e_curr); + + +int GetMVSIndex(TXANIMHEADER *txah, EULER *e); + + +IMAGEHEADER* GetImageHeader(void); + +void* GetTexture(int texindex); + +TEXTURE* GetTextureMemory(int txsize); +void ReturnTextureMemory(TEXTURE *txptr); + + +/* Backdrops */ + +#if pc_backdrops +int UpdateBackdrops(SCENE Scene); +int DeallocateBackdrops(SCENE Scene); +int LoadBackdrop(char *image, IMAGEHEADER *ihdr); +#endif + + +void GetProjectFilename(char *fname, char *image); + + +int CompareStringCH(char *string1, char *string2); + +void GetDOSFilename(char *fnameptr); +int CompareFilenameCH(char *string1, char *string2); + +void CopyMemoryCH(void *source, void *dest, int c); + +TEXTURE* LoadImageCH(char *fname, IMAGEHEADER *iheader); +TEXTURE* LoadBMP(char *fname, IMAGEHEADER *iheader); +TEXTURE* LoadPGM(char *fname, IMAGEHEADER *iheader); +int LoadPGMPalette(char *fname, unsigned char *palette); +int LoadPGMPaletteLightingTable(char *filename, unsigned char *palette); +void MakeTextureLightingTableRaw256(unsigned char *palette); + +void Create_MIP_Map(IMAGEHEADER *iheader); + + +int** ShadingTables(SHAPEHEADER **sh_list); +PALCREATIONDATA* CreatePaletteCH(SHAPEHEADER **sh_list, int pstart, int pent, unsigned char *pal); +PALCREATIONDATA* CreateRaw256PaletteCH(SHAPEHEADER **sh_list, unsigned char *pal); +void RemapShapesForCreatePaletteCH(SHAPEHEADER **sh_list); + +void ClearShadingTables(void); +void ClearPaletteShadingTables(void); + +int NextLowPower2(int i); + + +void PlotPixelTest(int x, int y, unsigned char col); + + +/* User Input */ + +void ReadUserInput(void); + +void InitMouse(void); +void ReadMouse(void); + + + +typedef struct mousedata { + + short MouseDataX; + short MouseDataY; + unsigned short MouseDataButton; + short MouseDataVelX; + short MouseDataVelY; + +} MOUSEDATA; + + +void ReadKeyboard(void); + + +#if 0 +void ReadEmulatedSaturnControlPad(void); +unsigned int CheckPad(void); +void ExaminePad(void); +/* + Saturn Control Pad + See pad.h + Model S Pad, direct mode +*/ +#define PAD_DOWN 0x0001 +#define PAD_UP 0x0002 +#define PAD_LEFT 0x0004 +#define PAD_RIGHT 0x0008 +#define PAD_BUTC 0x0010 +#define PAD_BUTB 0x0020 +#define PAD_BUTA 0x0040 +#define PAD_START 0x0080 +#define PAD_BUTZ 0x0100 +#define PAD_BUTY 0x0200 +#define PAD_BUTX 0x0400 +#define PAD_MODE 0x0800 +#define PAD_R 0x0800 +#define PAD_L 0x1000 +#endif + + +void WaitForReturn(void); + +void CursorHome(void); + +void InitialiseItemLists(void); + +void InitialiseItemPointers(void); +void InitialiseItemData(void); + +void* AllocateItemData(int itemsize); + + +int GetZForZBuffer(int z); +void FlushZBuffer(VIEWDESCRIPTORBLOCK *vdb); + + +/* Draw Item */ + +void Draw_Item_GouraudPolygon(int *itemptr); +void Draw_Item_2dTexturePolygon(int *itemptr); +void Draw_Item_Gouraud2dTexturePolygon(int *itemptr); +void Draw_Item_Gouraud3dTexturePolygon(int *itemptr); + +void Draw_Item_ZB_GouraudPolygon(int *itemptr); +void Draw_Item_ZB_2dTexturePolygon(int *itemptr); +void Draw_Item_ZB_Gouraud2dTexturePolygon(int *itemptr); +void Draw_Item_ZB_Gouraud3dTexturePolygon(int *itemptr); + + +/* + + Texture Animation + +*/ + +int* GetTxAnimArrayZ(int shape, int item); +TXANIMHEADER* GetTxAnimDataZ(int shape, int item, int sequence); + +#if SupportBSP +TXANIMHEADER* GetTxAnimDataBSP(int shape, int node, int item, int sequence); +#endif + + +int GT_LL(LONGLONGCH *a, LONGLONGCH *b); +int LT_LL(LONGLONGCH *a, LONGLONGCH *b); + + +void SetFastRandom(void); +int FastRandom(void); + + +void DrawPalette(int x0, int y0, int x1, int y1); + + +/* + + Equates and Enums + +*/ + +typedef enum { + + DrawPerFrame, + DrawPerVDB, + DrawPerObject + +} DRAWMODES; + + +typedef enum { + + Boundary_Left, + Boundary_Right, + Boundary_Up, + Boundary_Down, + Boundary_Z + +} CLIP2DBOUNDARIES; + + + +#if SupportMorphing + +void UpdateMorphing(MORPHCTRL *mcptr); +void UpdateMorphingDptr(DISPLAYBLOCK *dptr); +void GetMorphDisplay(MORPHDISPLAY *md, DISPLAYBLOCK *dptr); +void CopyMorphCtrl(MORPHCTRL *src, MORPHCTRL *dst); + +VECTORCH* GetMorphedPts(DISPLAYBLOCK *dptr, MORPHDISPLAY *md); + +#if LazyEvaluationForMorphing +void FreeMorphArrays(void); +#endif + +#endif + + + + + + + + +/* KJL 15:07:39 01/08/97 - Returns the magnitude of the + cross product of two vectors a and b. */ +int MagnitudeOfCrossProduct(VECTORCH *a, VECTORCH *b); + +/* KJL 15:08:01 01/08/97 - sets the vector c to be the + cross product of the vectors a and b. */ +void CrossProduct(VECTORCH *a, VECTORCH *b, VECTORCH *c); + +/* KJL 12:01:08 7/16/97 - returns the magnitude of a vector - max error about 13%, though average error + less than half this. Very fast compared to other approaches. */ +int Approximate3dMagnitude(VECTORCH *v); + + + + + + + + +#ifdef __cplusplus + + }; + +#endif + + +#define PROTOTYP_INCLUDED + +#endif diff --git a/3dc/include/shape.h b/3dc/include/shape.h new file mode 100644 index 0000000..f0acdf4 --- /dev/null +++ b/3dc/include/shape.h @@ -0,0 +1,1110 @@ +#ifndef SHAPE_INCLUDED + +/* + + Header File for Shape Data + +*/ + +#ifndef SupportWindows95 + #if defined(_WIN32)||defined(WIN32) + #define SupportWindows95 1 + #else + #define SupportWindows95 0 + #endif +#endif +#if SupportWindows95 + #include + #include + #include "aw.h" +#endif +#include "shpanim.h" + + +#ifdef __cplusplus + + extern "C" { + +#endif + + +/* + + Macros for Defining Colours + +*/ + +#define col6(r, g, b) ((r << 4) + (g << 2) + b) +#define col8T(r, g, b) ((r << 5) + (g << 2) + b) +#define col15(r, g, b) ((r << 10) + (g << 5) + b) +#define col24(r, g, b) ((r << 16) + (g << 8) + b) + + +/* + + Maximum number shading tables. + + This equate might have to be moved to "system.h" + +*/ + +#define MaxShadingTables 4096 + + + +/* + + Palette Creation Function Structure + +*/ + +typedef struct palcreationdata { + + unsigned char** PCD_ArrayPtr; + int PCD_NumHues; + int PCD_ShadesPerHue; + int PCD_NumColsUsed; + +} PALCREATIONDATA; + + + + + + +/* + + Shape Item Function Array Indices + +*/ + +typedef enum { + + I_Pixel, + I_Line, + + I_Polygon, + I_GouraudPolygon, + I_PhongPolygon, + I_2dTexturedPolygon, + I_Gouraud2dTexturedPolygon, + I_3dTexturedPolygon, + + I_UnscaledSprite, + I_ScaledSprite, + I_SimpleShadedSphere, + I_ShadedSphere, + + I_CloakedPolygon, + I_Pad2, + + I_Polyline, + I_FilledPolyline, + I_Wireframe, + + I_Pad3, + + /* Z-Buffered */ + + I_ZB_Polygon, + I_ZB_GouraudPolygon, + I_ZB_PhongPolygon, + I_ZB_2dTexturedPolygon, + I_ZB_Gouraud2dTexturedPolygon, + I_ZB_3dTexturedPolygon, + + /* Others */ + + I_Gouraud3dTexturedPolygon, + I_ZB_Gouraud3dTexturedPolygon, + + I_Last + +} ShapeItems; + + +/* + + "shape.c" has been updated so that shapes without normals are outcoded + using the "scaled sprite" outcoding function, which looks at clip outcodes + but does not perform a back face cull. + +*/ + +#define I_ZB_ScaledSprite I_ZB_2dTexturedPolygon + + + +/* + + Structs for Shape Data + +*/ + + +/* + + BSP Block + +*/ + +#define bsp_mid_block 0 + +/* + + This struct is the one that ends up being walked. + It is also used by z-trees, hence its unconditional inclusion. + +*/ + +typedef struct bsp_block { + + void *frontblock; /* +ve side of normal */ + void *backblock; /* -ve side of normal */ + + #if bsp_mid_block + void *middleblock; /* For inclusion of another tree */ + #endif + + int bsp_block_z; /* For inclusion of z sorted data */ + + int bsp_block_flags; + + int *bsp_block_data; /* Polygon or other */ + +} BSP_BLOCK; + + + +/* + + This struct is the form that Static BSP Tree blocks are allocated in + +*/ + +typedef struct static_bsp_block { + + void *frontblock; /* +ve side of normal */ + void *backblock; /* -ve side of normal */ + + #if bsp_mid_block + void *middleblock; /* For inclusion of another tree */ + #endif + + int bsp_numitems; /* # items in array */ + + int bsp_block_flags; + + int **bsp_block_data; /* Pointer to item pointer array */ + +} STATIC_BSP_BLOCK; + + + + + + + + + + + +/* + + Shape Instruction Block + +*/ + +typedef struct shapeinstr { + + int sh_instr; /* int data */ + int sh_numitems; + int **sh_instr_data; /* ptr to int data */ + +} SHAPEINSTR; + + + + + + +/* + + ZSP Header Block + +*/ + +typedef struct zspheader { + + int zsp_x; /* ZSP Array dimensions */ + int zsp_y; + int zsp_z; + + int zsp_edge; /* Cube edge extent */ + int zsp_diagonal; /* Cube diagonal extent */ + + struct zspzone *zsp_zone_array; + +} ZSPHEADER; + + + +/* + + ZSP Zone Structure + +*/ + +typedef struct zspzone { + + int zsp_numitems; + int **zsp_item_array_ptr; + + int zsp_numpoints; + int *zsp_vertex_array_ptr; + +} ZSPZONE; + + +/* + + RSP plane outcode flags + +*/ + +#define rsp_oc_x0 0x00000001 +#define rsp_oc_x1 0x00000002 +#define rsp_oc_y0 0x00000004 +#define rsp_oc_y1 0x00000008 +#define rsp_oc_z0 0x00000010 +#define rsp_oc_z1 0x00000020 + + + + + +/* + + Shape Header Block + +*/ + + +#if StandardShapeLanguage + + +/* + + Extra Item Data. + + As well as item extensions, items can have extra data in a parallel array. + This data can be accessed using the normal index. + +*/ + +typedef struct extraitemdata { + + int EID_VertexI; /* Prelighting Intensity for each Vertex */ + +} EXTRAITEMDATA; + + +/* it might be a good idea to put in an instruction field here + so that each fragment can have an instruction telling it what + to do e.g. a remain around instruction */ + +typedef struct shapefragment +{ + + int ShapeIndex; + int NumFrags; + + int x_offset; + int y_offset; + int z_offset; + +} SHAPEFRAGMENT; + +struct loaded_sound; + +typedef struct shapefragmentsound +{ + unsigned long inner_range; + unsigned long outer_range; + int max_volume; + int pitch; + struct loaded_sound const * sound_loaded; + +} SHAPEFRAGMENTSOUND; + +typedef struct shapefragmentdesc +{ + /* array of shape fragment indices terminated with + ShapeIndex = NumFrags = -1 */ + SHAPEFRAGMENT* sh_frags; + SHAPEFRAGMENTSOUND* sh_fragsound; +} SHAPEFRAGMENTDESC; + +typedef struct Adaptive_Degradation_Desc +{ + struct shapeheader* shape; + int distance;/*The shape should be used if the distance is greater than or equal to this distance*/ + + /* KJL - some models are extremely low poly, and *only* work if they are drawn small on screen. */ + int shapeCanBeUsedCloseUp; + +}ADAPTIVE_DEGRADATION_DESC; + +typedef struct shapeheader { + + int numpoints; /* Total #points in shape */ + int numitems; /* Total #items in shape */ + + int shapeflags; /* Various Display Options */ + + int **points; + int **items; + + int **sh_normals; + int **sh_vnormals; + + int **sh_textures; /* Polygon u,v definitions */ + char **sh_localtextures; /* Array of ptrs to filenames */ + + SHAPEFRAGMENTDESC * sh_fragdesc; + + EXTRAITEMDATA *sh_extraitemdata; + + int sh_num_subshapes; /* General use - NEVER use as test for + the data being present */ + int shaperadius; /* max(sqr(x^2+y^2+z^2)) */ + int shapemaxx; + int shapeminx; + int shapemaxy; + int shapeminy; + int shapemaxz; + int shapeminz; + + SHAPEINSTR *sh_instruction; /* ptr to shape instr struct */ + + char * sh_name; + + ZSPHEADER *sh_zsp_header; /* ptr to zsp header structure */ + + SHAPEANIMATIONHEADER * animation_header; + + /*if shape_degradation_array is not null then it is terminated with an entry whose distance is 0 + and whose shape is this shapeheader*/ + /*the shapes are listed in ascending order of complexity*/ + ADAPTIVE_DEGRADATION_DESC* shape_degradation_array; + +} SHAPEHEADER; + + +/* Shape Flags */ + +#define ShapeFlag_3DS_AxisFlip 0x00000001 +#define ShapeFlag_RSP 0x00000002 /* Run time creation */ +#define ShapeFlag_Detail 0x00000004 /* Run time creation */ + + +#define ShapeFlag_AugZ 0x00000010 /* For the Preprocessor */ +#define ShapeFlag_AugZ_Lite 0x00000020 /* No points array */ + +#define ShapeFlag_Free1 0x00000040 + +#define ShapeFlag_SizeSortItems 0x00000080 /* For PP, AugZ only */ +#define ShapeFlag_VSC_tx3d 0x00000100 /* Test for VSC usage */ +#define ShapeFlag_ZSP 0x00000200 /* Run time creation */ +#define ShapeFlag_Sprite 0x00000400 /* Object is a sprite */ +#define ShapeFlag_SpriteR 0x00000800 /* It's a rotated sprite */ +#define ShapeFlag_PreLit 0x00001000 /* Use EID prelighting data */ +#define ShapeFlag_Cylinder 0x00002000 /* For binary loaders */ + + +#define ShapeFlag_SpriteResizing 0x00008000 /* Resize polygon */ + +#define ShapeFlag_MultiViewSprite 0x00010000 /* See "c7.doc" */ + +#define ShapeFlag_UnrotatedPoints 0x00020000 /* Ignores "ObMat" */ +#define ShapeFlag_HasTextureAnimation 0x00040000 /*at least one of the polygons has texture animation*/ + + + +#else /* StandardShapeLanguage */ + + + /* + + If not using the standard shape language, place your own version of the + shape header in the following include file. + + */ + + #include "sheader.h" + + +#endif /* StandardShapeLanguage */ + + + +/* + + Outcode Return Structure + +*/ + +typedef struct ocs_block { + + int ocs_flags; /* For general flagged messages */ + int ocs_viewdot; + int ocs_clip_or; + int ocs_clip_and; + int ocs_clipstate; + int ocs_ptsoutstate; + +} OCS_BLOCK; + +#define ocs_flag_outcoded 0x00000001 +#define ocs_flag_nobfc 0x00000002 +#define ocs_flag_noclipoc 0x00000004 +#define ocs_flag_hazed 0x00000008 +#define ocs_flag_hazehue_n0 0x00000010 +#define ocs_flag_cwise 0x00000020 + + +typedef enum { + + ocs_cs_totally_off, /* Item will be flagged as outcoded */ + ocs_cs_partially_on, + ocs_cs_totally_on, + +} OCS_CLIPSTATES; + + +typedef enum { + + ocs_pout_2d, /* "ocs_cs_partially_on" or "ocs_cs_totally_on" */ + ocs_pout_3d /* "ocs_cs_partially_on" */ + +} OCS_PTSOUTSTATES; + + +/* + + Polygon Header Block + + Polygon Data is as generic as any item. However it might be useful to cast + the initial fixed part of its data to the following struct. + +*/ + + +#if StandardShapeLanguage + + +#define IHdrSize 4 +#define ITrmSize 1 + +typedef struct polyheader { + + int PolyItemType; + int PolyNormalIndex; + int PolyFlags; + int PolyColour; + int Poly1stPt; + +} POLYHEADER; + +#if InterfaceEngine + +/* + + Little structure for use creating + merge lists + +*/ + +typedef struct merged_poly +{ + int other_poly; + int num_verts; + int vert_ind[4]; +} MERGED_POLY; + +#endif + + + +/* + + Item Flags + + Some Item Flags can be shared, others are unique to a group of one or + more items. + +*/ + +#define iflag_notvis 0x00000001 /* Don't draw this item */ +#define iflag_nolight 0x00000002 /* Take colour as is */ +#define iflag_ignore0 0x00000004 /* Don't draw colour 0 - textures */ + +#if (SupportViewports && SupportViewportClipping && 0) +#define iflag_noviewportclip 0x00000008 /* See object level option too */ +#endif + +#define iflag_nosubdiv 0x00000008 // polygon too small to need sub dividing + +#define iflag_transparent 0x00000010 /* Function depends on Video Mode */ +#define iflag_no_bfc 0x00000020 /* No Back Face Cull */ +#define iflag_hazing 0x00000040 /* Haze / Depth Cue colour */ + +#if InterfaceEngine + + #define iflag_selected 0x00000080 /* It's a tools thing */ + +#else + + #if Saturn + #define iflag_sattexture 0x00000080 /* Outcode if outside frame buffer or behind z plane, else just draw */ + #endif + + #if platform_pc + #define iflag_zbuffer_w 0x00000080 /* Z-Buffer, Write-Only */ + #endif + +#endif /* InterfaceEngine */ + +#define iflag_shadingtable 0x00000100 /* Hue is a table index */ +#define iflag_tab_gour_8 0x00000200 /* Gour. for 8-bit modes uses tab. */ +#define iflag_extended 0x00000400 /* N. Index ptr to item ext. blk */ + +#define iflag_verticaledges 0x00000800 /* A collision option whereby the + item is treated as if it is a + prism of infinite extent formed + by extrusion of its world xz + projection in the y-axis */ + +#define iflag_mirror 0x00001000 /* polygon is a mirror polygon. Now there's a suprise*/ +#define iflag_viewdotpos 0x00002000 /* Used by BFCRO */ + +#define iflag_hue_per_vertex 0x00004000 /* INTERNAL USE ONLY! */ + +#define iflag_no_mip 0x00008000 /* Use Index #0 */ + +#if platform_pc +#define iflag_zbuffer_r 0x00010000 /* Z-Buffer, Read-Only */ +#endif + +#define iflag_linear 0x00020000 /* Linear Interpolation */ + +#define iflag_sortnearz 0x00040000 /* Use minz for depth value */ + +#define iflag_detail 0x00080000 /* Item can be range outcoded */ +#define iflag_dtest_not_done 0x00100000 /* Ensure just one range test */ + +#define iflag_augz_planetest 0x00200000 /* Plane Test to help build tree */ + +#define iflag_tx2dor3d 0x00400000 /* Decide each frame which it is */ + +#define iflag_linear_s 0x00800000 /* Subdivided linear scans for + 3d textured polygons */ + +#define iflag_gsort_ptest 0x01000000 /* Global sort, use plane test */ + +#define iflag_drawtx3das2d 0x02000000 /* 3d until SC, draw as 2d */ + +#define iflag_sortfarz 0x04000000 /* Use maxz for depth value */ + +#define iflag_bufferxy 0x08000000 /* Internal - Saturn Only + - for xy clamped item */ + +#define iflag_clampz 0x10000000 /* Internal - Saturn Only + - for z clamped item */ + +#define iflag_light_corona 0x20000000 /* For use by the placed light strategy */ + +#define iflag_txanim 0x40000000 /* UV array has animation data */ + +// Taken this flag +#if SupportViewports && 0 +#define iflag_viewport 0x80000000 +#endif + +#define iflag_cwise 0x80000000 /* Polygon is clockwise */ + +/* + + Item Extension + +*/ + +typedef struct itemextension { + + int ie_nindex; + + int ie_nx; /* view space normal */ + int ie_ny; + int ie_nz; + + int ie_popx; /* view space pop */ + int ie_popy; + int ie_popz; + + int ie_d; /* distance of plane from view */ + + int ie_bigz; + int ie_smallz; + int ie_midz; + + int ie_axis_state; + + int ie_numpoints; + int *ie_points_array; + +} ITEMEXTENSION; + + +/* + + Poly Header for Extended Items + +*/ + +typedef struct polyheader_ie { + + int PolyItemType; + ITEMEXTENSION *PolyItemExtension; + int PolyFlags; + int PolyColour; + int Poly1stPt; + +} POLYHEADER_IE; + + + +#if SupportViewports + + +/* + + Poly Header for Viewport Polygons + + Viewport polygons have "iflag_viewport" set. They can only be accessed + through the structure below when they have had their Clip Window structure + allocated. + +*/ + +typedef struct polyheader_vp { + + int PolyItemType; + int PolyNormalIndex; + int PolyFlags; + struct viewportclipwindow *PolyViewportClipWindow; + int Poly1stPt; + +} POLYHEADER_VP; + + +#endif /* SupportViewports */ + + + + + +#else /* StandardShapeLanguage */ + + + /* + + If not using the standard shape language, place your own version of the + item/polygon header in the following include file. + + */ + + #include "pheader.h" + + +#endif /* StandardShapeLanguage */ + + +typedef enum { + + axis_yz, /* x axis plane - normal x biggest */ + axis_xz, /* y axis plane - normal y biggest */ + axis_xy /* z axis plane - normal z biggest */ + +} AXISSTATES; + + +/* + + Structure for Item Size Sort + +*/ + +typedef struct itemsizeblock { + + struct itemsizeblock *isb_lower; + struct itemsizeblock *isb_higher; + int *isb_itemptr; + int isb_itemsize; + +} ITEMSIZEBLOCK; + + + + +/* + + Texels + +*/ + +typedef struct texel { + + int uuu; + int vee; + +} TEXEL; + + +#if support3dtextures + +#if int3dtextures + +typedef struct texelf { + + int uuuf; + int veef; + +} TEXELF; + +#else + +typedef struct texelf { + + float uuuf; + float veef; + +} TEXELF; + +#endif + +#endif + + +#if SupportGouraud3dTextures + +typedef struct texelgtx3d { + + float uuuf; + float veef; + +} TEXELGTX3D; + +#endif + + +/* + + Internal Image Structure + +*/ + + +#if StandardShapeLanguage + + +typedef unsigned char TEXTURE; + +#if Saturn +#define ImageNameSize 16 +#else +#define ImageNameSize 128+1 +#endif + + +typedef struct imageheader { + + int ImageWidth; + + int ImageWidthShift; /* Image Width as a power of 2 */ + + TEXTURE *ImagePtr; /* Pointer to texture in memory */ + + #if SupportWindows95 + + LPDIRECTDRAWSURFACE DDSurface; + + LPDIRECT3DTEXTURE D3DTexture; + + D3DTEXTUREHANDLE D3DHandle; + + AW_BACKUPTEXTUREHANDLE hBackup; + + #endif + + int ImageNum; /* # MIP images */ + char ImageName[ImageNameSize]; /* Filename */ + + int ImageHeight; /* Height, Pixels */ + + int ImageSize; /* Size of Image Data in bytes */ + int ImageFlags; /* Load / Display Options */ + + +} IMAGEHEADER; + + +/* Image Header Flags */ + +#define ih_flag_mip 0x00000001 /* MIP map data is available */ +#define ih_flag_nochromakey 0x00000002 /* internal load flag indicating that d3_func should NOT set chroma keying for this image */ +#define ih_flag_tlt 0x00000004 /* image pixels must be remapped through the tlt to get the screen palette entry */ +#define ih_flag_16bit 0x00000008 /* in conjunction with ih_flag_tlt, the image is 16bit and the tlt has more entries to correspond */ + + +#else /* StandardShapeLanguage */ + + + /* + + If not using the standard shape language, place your own version of the + image header in the following include file. + + */ + + #include "iheader.h" + + +#endif /* StandardShapeLanguage */ + + +typedef struct imageextents { + + int u_low; + int v_low; + + int u_high; + int v_high; + +} IMAGEEXTENTS; + + +typedef struct imagepolyextents { + + int x_low; + int y_low; + + int x_high; + int y_high; + +} IMAGEPOLYEXTENTS; + + +/* + + Structure for accessing 24-bit images + +*/ + +typedef struct texture24 { + + unsigned char r24; + unsigned char g24; + unsigned char b24; + +} TEXTURE24; + + +/* + + Texture and Sprite Animation + +*/ + + +#if StandardShapeLanguage + + +/* + + Texture Animation Header Structure + + The data is stored as an array of ints and so the pointer must be recast + to this structure for access, just as item pointers must be. + +*/ + +typedef struct txanimheader { + + int txa_flags; + int txa_state; + int txa_numframes; + struct txanimframe *txa_framedata; + int txa_currentframe; + int txa_maxframe; + int txa_speed; + int txa_anim_id; //this will be the same for all sequences on a given polygon + + int txa_num_mvs_images; /* Multi-View Sprites - TOTAL number of images */ + int txa_eulerxshift; /* Multi-View Sprites, scale Euler X for index */ + int txa_euleryshift; /* As above, for Euler Y */ + +} TXANIMHEADER; + +#define txa_flag_play 0x00000001 +#define txa_flag_reverse 0x00000002 +#define txa_flag_noloop 0x00000004 +#define txa_flag_interpolate_uvs 0x00000008 +#define txa_flag_quantiseframetime 0x00000010 + + +/* + + Texture Animation Frame Structure + + The header has a pointer to an array of these structures + UV data for each frame is held in a separate int array + +*/ + +typedef struct txanimframe { + + int txf_flags; + int txf_scale; + int txf_scalex; + int txf_scaley; + int txf_orient; + int txf_orientx; + int txf_orienty; + int txf_numuvs; + int *txf_uvdata; + int txf_image; + +} TXANIMFRAME; + + +/* For a multi-view sprite use this structure instead */ + +typedef struct txanimframe_mvs { + + int txf_flags; + int txf_scale; + int txf_scalex; + int txf_scaley; + int txf_orient; + int txf_orientx; + int txf_orienty; + int txf_numuvs; + + int **txf_uvdata; /* Pointer to array of pointers to UV array per image */ + + int *txf_images; /* Pointer to a 2d array of image indices */ + +} TXANIMFRAME_MVS; + + +/* + + Display Block Texture Animation Control Block + + An arbitrary number of these can be attached through a linked list to the + display block. + +*/ + +typedef struct txactrlblk { + + int tac_flags; + int tac_item; + int tac_sequence; + int tac_node; + int *tac_txarray; + TXANIMHEADER tac_txah; + TXANIMHEADER *tac_txah_s; + struct txactrlblk *tac_next; + int tac_anim_id; + +} TXACTRLBLK; + + + + +/* + + Shape Instruction Function Array Indices + +*/ + +typedef enum { + + I_ShapePoints, + I_ShapeProject, + I_ShapeNormals, + I_ShapeVNormals, + I_ShapeItems, + + I_ShapeFree5, + I_ShapeFree6, + + I_ShapeEnd, + + I_ShapeAugZItems, + + I_ShapeFree1, + I_ShapeFree2, + I_ShapeFree3, + I_ShapeFree4, + + I_ShapeSpritePoints, + I_ShapeSpriteRPoints, + + I_Shape_ZSP_Points, + I_Shape_ZSP_Project, + I_Shape_ZSP_VNormals, + I_Shape_ZSP_Items, + + I_ShapeCylinder, + + I_ShapeTransformLightRender, + + I_ShapeViewFacingPolys, + + I_ShapeUnrotatedPoints, + + I_ShapeBackdropPoints, + + I_Shape_LastInstr + +} SHAPEFUNCTION; + + +#else /* StandardShapeLanguage */ + + + /* + + If not using the standard shape language, place your own version of the + texture animation control block in the following include file. + + */ + + #include "theader.h" + + +#endif /* StandardShapeLanguage */ + + +#ifdef __cplusplus + + }; + +#endif + +#define SHAPE_INCLUDED + +#endif + diff --git a/3dc/include/vssver.scc b/3dc/include/vssver.scc new file mode 100644 index 0000000..e5a08a3 Binary files /dev/null and b/3dc/include/vssver.scc differ diff --git a/3dc/mem3dc.c b/3dc/mem3dc.c new file mode 100644 index 0000000..d0da027 --- /dev/null +++ b/3dc/mem3dc.c @@ -0,0 +1,824 @@ + +/******************************************************************* + * + * DESCRIPTION: mem3dc.c + * + * AUTHOR: Rob Rodger + * + * HISTORY: 23/12/96 + * + *******************************************************************/ + + +/* mem3dc.c simply keeps a record of all memory allocations called by */ +/* AllocateMem() and checks if DeallocateMem() calls are legitimate */ +/* i.e. the address freed has been allocated. This record */ +/* includes the address, size, filename and line number for the associated */ +/* AllocateMem() call. */ +/* */ +/* Also, fills in MALLOC_FILL_VALUE in memory malloced and FREE_FILL_VALUE */ +/* in memory freed. */ +/* */ +/* A record is kept of the total amount of allocated memory outstanding in */ +/* global TotalMemAllocated as well as the total number of outstanding mallocs */ +/* in the global TotalMallocNum. Finally, a call to DumpMallocInfo(DUMPTOSCREEN) */ +/* will give a textprint of each outstanding malloc record while */ +/* while DumpMallocInfo(DUMPTOFILE) writes malloc records to a file with */ +/* filename defined by MALLOCDUMPFILE define. Set APPEND_TO_DUMPFILE to 1 */ +/* in define below if you wish to append malloc info to MALLOCDUMPFILE rather */ +/* than over writing file each time. */ +/* */ +/* To use, define DBGMALLOC as 1 in "mem3dc.h". Obviously for final code */ +/* set DBGMALLOC to 0. */ +/* */ +/* Note, must use AllocateMem() and DeallocateMem() in code - Do not */ +/* make direct calls to AllocMem()/DeallocMem() contained in platform */ +/* file our_mem.c */ + +#include "3dc.h" + +#include +#include "mem3dc.h" /* contains extern declarations for platform + specific memory allocation/deallocation. + Also contains DBGMALLOC define */ + +#if DBGMALLOC + +#include "ourasert.h" + +#if PSX || Saturn + #define MAXMALLOCS 600 +#else + #define MAXMALLOCS 2500000 + /* assertion fires if max exceeded */ + /* changed to 1000000 by DHM 7/4/98; was 70001 */ +#endif + +#define MALLOC_FILL_VALUE 0x21 +#define FREE_FILL_VALUE 0x89 +#define MALLOCDUMPFILE "dbgdump.txt" +#define APPEND_TO_DUMPFILE 0 /* define as 0 if overwrite dbgdump.txt rather than append */ +#define FREEING_MEMORY -1 + +#define AllowedToDeleteNULL Yes + /* + Option added 7/4/98 by DHM: + --------------------------- + This option checks for NULL in record_free() and doesn't update the records. + + According to 2nd and 3rd edition Stroustrup, it's legal to "delete NULL", and it + has no effect (see e.g. 3rd Edition Stroustrup, p128 paragraph 2). + According to Appendix B of K&R, free NULL has no effect. + */ + +#if APPEND_TO_DUMPFILE +#define FILEPERM "a" +#else +#define FILEPERM "w" +#endif + +#if SupportWindows95 && !defined(_MSC_VER) /* not required for MS C since MS C has CRT debugging available */ +#define OVERRUN_SIZEMIN 2 +#define OVERRUN_SIZEMAX 128 +#define OVERRUN_SIZEFACTOR 2 /* this is a shift down */ + +#define OVERRUN_SIZE(sz) ((sz)>OVERRUN_SIZEMAX<>OVERRUN_SIZEFACTOR) +/* I just selected these at random - the 0 term is necessary for wrap around */ +static unsigned char const overrun_code [] = { 0xef, 0x94, 0x56, 0x27, 0xf6, 0x76, 0x23, 0x43, 0 }; + +#else +#undef OVERRUN_SIZE +#endif + + + +typedef struct{ + unsigned long addr; + unsigned long size; + #if COPY_FILENAME + char filename[40]; + #else + char const * filename; /* JH 30/5/97 - since __FILE__ generates a string in the executable, to which we get passed a pointer, we don't need to make another copy unnecessarily wasting 720K of space on PC !! */ + #endif + unsigned long linenum; +}MALLOC_RECORD; + +/* globals */ +MALLOC_RECORD MallocRecord[MAXMALLOCS]; +unsigned long TotalMemAllocated = 0; +unsigned long TotalMallocNum = 0; + +/* extern function declarations */ +extern int textprint(const char* string, ...); +extern void ExitSystem(void); +extern void WaitForReturn(void); + +/* textprint on psx impacts frame rate massively if not +used just for error messages, so it is often turned off. +Hence the use of textprint2 below */ + +#if PSX +#define textprint2 printf +#else +#define textprint2 textprint +#endif + +/* function declarations */ +#if COPY_FILENAME +void record_free(void *ptr, char string[], unsigned long lineno); +void *record_malloc(long size, char string[], unsigned long lineno); +static int AdjustMallocRecord(unsigned long addr, long size, char string[], unsigned long lineno); +#else /* new prototypes to take just pointers - dunno if it's really necessary */ +void record_free(void *ptr, char const * string, unsigned long lineno); +void *record_malloc(long size, char const * string, unsigned long lineno); +static int AdjustMallocRecord(unsigned long addr, long size, char const * string, unsigned long lineno); +#endif +void DumpMallocInfo(int type); +static void InitMallocRecords(void); + +/* function definitions */ + +#if COPY_FILENAME +void *record_malloc(long size, char string[], unsigned long lineno) +#else +void *record_malloc(long size, char const * string, unsigned long lineno) +#endif +{ + #ifdef OVERRUN_SIZE + void *ptr = (void *)AllocMem((size_t) size + OVERRUN_SIZE(size)); + #else + void *ptr = (void *)AllocMem((size_t) size); + #endif + if(ptr==NULL) + { + textprint2("\nMalloc Error! %d bytes attempted\n", size); + return((void *)NULL); + } + + GLOBALASSERT(size>0); /* should be redundant cos picked up by above malloc attempt */ + + AdjustMallocRecord((long)ptr,size, string, lineno); + + return(ptr); +} + +#if COPY_FILENAME +void record_free(void *ptr, char string[], unsigned long lineno) +#else +void record_free(void *ptr, char const * string, unsigned long lineno) +#endif +{ + if(AdjustMallocRecord((long)ptr,FREEING_MEMORY, string, lineno)) + DeallocMem((void *)ptr); /* free previously malloced ptr */ + return; +} + +#if PSX || Saturn + +#if COPY_FILENAME +static int AdjustMallocRecord(unsigned long addr, long size, char string[], unsigned long lineno) +#else +static int AdjustMallocRecord(unsigned long addr, long size, char const * string, unsigned long lineno) +#endif + +{ + + int i=0; + char *ptr = (char *)addr; + static int no_record_init = 1; + MALLOC_RECORD *recordPtr = MallocRecord; + + if(no_record_init) + { + InitMallocRecords(); + no_record_init = 0; + } + + + if(size==FREEING_MEMORY) /* must be freeing memory */ + { + GLOBALASSERT(addr); /* ensure not null addr */ + + while(iaddr==addr) + { + TotalMallocNum--; + + size = recordPtr->size; + + while (size--) + { + *ptr++ = FREE_FILL_VALUE; + } + #ifdef OVERRUN_SIZE + { + char const * overrun_ptr = overrun_code; + int ov_cnt = OVERRUN_SIZE(recordPtr->size); + do /* a memcmp - dunno if its supported on all platforms */ + { + if (!*overrun_ptr) overrun_ptr = overrun_code; /* repeat */ + if (*overrun_ptr++ != *ptr++) + { + textprint2("\nOut of Bounds!\n%lu bytes allocated to %p\nat %s, line %lu\n", recordPtr->size,(void *)recordPtr->addr,recordPtr->filename,recordPtr->linenum); + GLOBALASSERT(!"OUT OF BOUNDS detected in FREE"); + } + } + while (--ov_cnt); + } + #endif + + recordPtr->addr = 0; + TotalMemAllocated -= recordPtr->size; + recordPtr->size = 0; + #if COPY_FILENAME + recordPtr->filename[0] = 0; + #else + recordPtr->filename = ""; + #endif + recordPtr->linenum = 0; + break; /* exit while loop */ + } + i++; + recordPtr++; + } + + if(i>=MAXMALLOCS) + { + textprint2("\n\n\n\nFree Error! %s, line %d\n", string, (int)lineno); + GLOBALASSERT(0); + return(0); + } + + } + + else /* must be mallocing memory */ + { + TotalMallocNum++; + GLOBALASSERT(TotalMallocNumaddr == addr) + { + GLOBALASSERT(0); + } + i++; + recordPtr++; + } + i = 0; + recordPtr = MallocRecord; + while(iaddr==0) + { + recordPtr->addr = addr; + recordPtr->size = size; + TotalMemAllocated += size; + #if COPY_FILENAME + strcpy(recordPtr->filename, string); + #else + recordPtr->filename = string; + #endif + recordPtr->linenum = lineno; + while (size--) + { + *ptr++ = MALLOC_FILL_VALUE; + } + #ifdef OVERRUN_SIZE + { + char const * overrun_ptr = overrun_code; + int ov_cnt = OVERRUN_SIZE(recordPtr->size); + do /* a memcpy */ + { + if (!*overrun_ptr) overrun_ptr = overrun_code; /* repeat */ + *ptr++ = *overrun_ptr++; + } + while (--ov_cnt); + } + #endif + break; /* exit while loop */ + } + i++; + recordPtr++; + } + + GLOBALASSERT(iaddr==addr) + { + TotalMallocNum--; + + size = recordPtr->size; + + while (size--) + { + *ptr++ = FREE_FILL_VALUE; + } + #ifdef OVERRUN_SIZE + { + char const * overrun_ptr = overrun_code; + int ov_cnt = OVERRUN_SIZE(recordPtr->size); + do /* a memcmp - dunno if its supported on all platforms */ + { + if (!*overrun_ptr) overrun_ptr = overrun_code; /* repeat */ + if (*overrun_ptr++ != *ptr++) + { + textprint2("\nOut of Bounds!\n%lu bytes allocated to %p\nat %s, line %lu\n", recordPtr->size,(void *)recordPtr->addr,recordPtr->filename,recordPtr->linenum); + GLOBALASSERT(!"OUT OF BOUNDS detected in FREE"); + } + } + while (--ov_cnt); + } + #endif + + recordPtr->addr = 0; + TotalMemAllocated -= recordPtr->size; + recordPtr->size = 0; + #if COPY_FILENAME + recordPtr->filename[0] = 0; + #else + recordPtr->filename = ""; + #endif + recordPtr->linenum = 0; + break; /* exit while loop */ + } + i++; + recordPtr++; + } + if(i==MAXMALLOCS) + { + i=0; + recordPtr=&MallocRecord[0]; + + while(iaddr==addr) + { + TotalMallocNum--; + + size = recordPtr->size; + + while (size--) + { + *ptr++ = FREE_FILL_VALUE; + } + #ifdef OVERRUN_SIZE + { + char const * overrun_ptr = overrun_code; + int ov_cnt = OVERRUN_SIZE(recordPtr->size); + do /* a memcmp - dunno if its supported on all platforms */ + { + if (!*overrun_ptr) overrun_ptr = overrun_code; /* repeat */ + if (*overrun_ptr++ != *ptr++) + { + textprint2("\nOut of Bounds!\n%lu bytes allocated to %p\nat %s, line %lu\n", recordPtr->size,(void *)recordPtr->addr,recordPtr->filename,recordPtr->linenum); + GLOBALASSERT(!"OUT OF BOUNDS detected in FREE"); + } + } + while (--ov_cnt); + } + #endif + + recordPtr->addr = 0; + TotalMemAllocated -= recordPtr->size; + recordPtr->size = 0; + #if COPY_FILENAME + recordPtr->filename[0] = 0; + #else + recordPtr->filename = ""; + #endif + recordPtr->linenum = 0; + break; /* exit while loop */ + } + i++; + recordPtr++; + } + if(i>=Starti) + { + textprint2("\n\n\n\nFree Error! %s, line %d\n", string, (int)lineno); + GLOBALASSERT(0); + return(0); + } + } + } + + else /* must be mallocing memory */ + { + TotalMallocNum++; + GLOBALASSERT(TotalMallocNumaddr==0) + { + recordPtr->addr = addr; + recordPtr->size = size; + TotalMemAllocated += size; + #if COPY_FILENAME + strcpy(recordPtr->filename, string); + #else + recordPtr->filename = string; + #endif + recordPtr->linenum = lineno; + while (size--) + { + *ptr++ = MALLOC_FILL_VALUE; + } + #ifdef OVERRUN_SIZE + { + char const * overrun_ptr = overrun_code; + int ov_cnt = OVERRUN_SIZE(recordPtr->size); + do /* a memcpy */ + { + if (!*overrun_ptr) overrun_ptr = overrun_code; /* repeat */ + *ptr++ = *overrun_ptr++; + } + while (--ov_cnt); + } + #endif + break; /* exit while loop */ + } + i++; + recordPtr++; + } + if(i>=MAXMALLOCS) + { + i=0; + recordPtr=&MallocRecord[0]; + while(iaddr==0) + { + recordPtr->addr = addr; + recordPtr->size = size; + TotalMemAllocated += size; + #if COPY_FILENAME + strcpy(recordPtr->filename, string); + #else + recordPtr->filename = string; + #endif + recordPtr->linenum = lineno; + while (size--) + { + *ptr++ = MALLOC_FILL_VALUE; + } + #ifdef OVERRUN_SIZE + { + char const * overrun_ptr = overrun_code; + int ov_cnt = OVERRUN_SIZE(recordPtr->size); + do /* a memcpy */ + { + if (!*overrun_ptr) overrun_ptr = overrun_code; /* repeat */ + *ptr++ = *overrun_ptr++; + } + while (--ov_cnt); + } + #endif + break; /* exit while loop */ + } + i++; + recordPtr++; + } + GLOBALASSERT(iaddr + recordPtr->size; + int ov_cnt = OVERRUN_SIZE(recordPtr->size); + do /* a memcmp - dunno if its supported on all platforms */ + { + if (!*overrun_ptr) overrun_ptr = overrun_code; /* repeat */ + if (*overrun_ptr++ != *ptr++) + { + textprint2("\nOut of Bounds!\n%lu bytes allocated to %p\nat %s, line %lu\n", recordPtr->size,(void *)recordPtr->addr,recordPtr->filename,recordPtr->linenum); + ++bc_errcnt; + break; + } + } + while (--ov_cnt); + } + } + if (bc_errcnt) + WaitForReturn(); + else + textprint2("No bounds errors detected\n"); + + } + else if (type==DUMPTOFILE) + { + + #if SupportWindows95 + FILE *fp; + + if( (fp = fopen(MALLOCDUMPFILE,FILEPERM))== (FILE *)NULL) + { + textprint2("\n\n\nfile open error %s", MALLOCDUMPFILE); + } + else + { + fprintf(fp,"\n\n\n\nBOUNDS CHECK PROBLEMS\n\n"); + for (i=0;iaddr + recordPtr->size; + int ov_cnt = OVERRUN_SIZE(recordPtr->size); + do /* a memcmp - dunno if its supported on all platforms */ + { + if (!*overrun_ptr) overrun_ptr = overrun_code; /* repeat */ + if (*overrun_ptr++ != *ptr++) + { + fprintf(fp,"\nOut of Bounds!\n%lu bytes allocated to %p\nat %s, line %lu\n", recordPtr->size,(void *)recordPtr->addr,recordPtr->filename,recordPtr->linenum); + break; + } + } + while (--ov_cnt); + } + } + fprintf(fp,"\n\nTotalMemAllocated: %d\nTotalMallocNum: %d\n", + (int)TotalMemAllocated, (int)TotalMallocNum); + + fclose(fp); + } + #endif + + #if PSX + long fd; + + fd = PCopen(MALLOCDUMPFILE,1,0); + if(fd<0) + { + fd = PCcreat(MALLOCDUMPFILE,0); + PCclose(fd); + fd = PCopen(MALLOCDUMPFILE,1,0); + } + + if(fd<0) + { + textprint2("\n\n\nfile open error %s", MALLOCDUMPFILE); + } + else + { + char stringbuf[200]; + sprintf(stringbuf,"\n\n\n\nBOUNDS_CHECK_PROBLEMS\n\n"); + #if APPEND_TO_DUMPFILE + PClseek(fd,0,2); + #endif + PCwrite(fd,stringbuf,strlen(stringbuf)); + for (i=0;iaddr + recordPtr->size; + int ov_cnt = OVERRUN_SIZE(recordPtr->size); + do /* a memcmp - dunno if its supported on all platforms */ + { + if (!*overrun_ptr) overrun_ptr = overrun_code; /* repeat */ + if (*overrun_ptr++ != *ptr++) + { + sprintf(stringbuf,"\nOut of Bounds!\n%lu bytes allocated to %p\nat %s, line %lu\n", recordPtr->size,(void *)recordPtr->addr,recordPtr->filename,recordPtr->linenum); + PCwrite(fd,stringbuf,strlen(stringbuf)); + break; + } + } + while (--ov_cnt); + } + } + + PCclose(fd); + + + } + + #endif + + } + + #endif +} + +void InitMallocRecords(void) +{ + int i; + MALLOC_RECORD *recordPtr = MallocRecord; + + for (i=0;iaddr = 0; + recordPtr->size = 0; + #if COPY_FILENAME + recordPtr->filename[0] = 0; + #else + recordPtr->filename = ""; + #endif + recordPtr->linenum = 0; + } + + return; +} + +#else +void DumpMallocInfo(int type); +void DumpMallocInfo(int type) +{ + /* empty if not debugging */ +} +void DumpBoundsCheckInfo(int type) +{} +#endif diff --git a/3dc/movement.txt b/3dc/movement.txt new file mode 100644 index 0000000..efce36d --- /dev/null +++ b/3dc/movement.txt @@ -0,0 +1,43 @@ +Movement Speeds + +Feel free to experiment with the values. +(10000 mm per second means the player +can cover 100m in 10 seconds.) + +You MUST leave the # signs in front of the numbers; +please do not change this file in any other way! + + +* Alien Movement Values * + +Running speed, (mm per second) +#18000 +Side-step speed, (mm per second) +#18000 +Turning speed, (revolutions per second * 4096) +#2000 +Jumping speed, (mm per second) +#9000 + +* Predator Movement Values * + +Running speed, (mm per second) +#16000 +Side-step speed, (mm per second) +#16000 +Turning speed, (revolutions per second * 4096) +#2000 +Jumping speed, (mm per second) +#9000 + + +* Marine Movement Values * + +Running speed, (mm per second) +#15000 +Side-step speed, (mm per second) +#15000 +Turning speed, (revolutions per second * 4096) +#2000 +Jumping speed, (mm per second) +#9000 diff --git a/3dc/plddpvc.dll b/3dc/plddpvc.dll new file mode 100644 index 0000000..b7295a7 Binary files /dev/null and b/3dc/plddpvc.dll differ diff --git a/3dc/plddpvc.lnk b/3dc/plddpvc.lnk new file mode 100644 index 0000000..92e6d8f --- /dev/null +++ b/3dc/plddpvc.lnk @@ -0,0 +1 @@ +import '_InvokeDavesDirectPlayDLL@4' plddpvc.InvokeDavesDirectPlayDLL \ No newline at end of file diff --git a/3dc/readme.txt b/3dc/readme.txt new file mode 100644 index 0000000..ca5a186 --- /dev/null +++ b/3dc/readme.txt @@ -0,0 +1,147 @@ + *********************************************************************** + + + + ALIENS VERSUS PREDATOR GOLD + + + *********************************************************************** + +About This Document: + +This document contains last-minute information about Aliens versus Predator, if you have any questions, check to see if it is addressed here first. + ************************************************************************ + +I. MINIMUM REQUIREMENTS +II. GENERAL TECHNICAL ISSUES +III. TROUBLE SHOOTING GENERAL GAME ISSUES +IV. MULTI-PLAYER +V. CONTACTING FOX INTERACTIVE + + +I: MINIMUM REQUIREMENTS + +The following information is the minimum hardware requirement needed to run Aliens vs. Predator. + +Pentium 200 MMX, 32 MB RAM +Windows 95/98 +300MB Hard Disk space +4x CD ROM +Direct3D Supported 3D Graphics Card, at least 4MB video memory. +DirectSound compatible sound card. +Mouse, Keyboard and any DirectX supported controllers +Internet access (only required for multi-player games), TCP/IP, IPX LAN Card or minimum 33.6 kbps modem. + +Aliens versus Predator requires DirectX 6 or higher to run properly. If you already have DirectX 6 choose no when prompted during the installation. Should you decide to install it at a later time you can run the DXSETUP program located in the DirectX folder on Aliens versus Predator, Disc 1. + + + +II: GENERAL TECHNICAL ISSUES + +Here is a list of some of the known technical problems you might encounter. + + + +Graphics Cards: + + Aliens versus Predator detects multiple Graphics cards and the resolution settings they are capable of. Although the user can select the highest resolution setting possible, the game may not be able to run due to memory limitations on the video card. For example: users with only one Voodoo2 card will be see the option to select 1024 x 768, but will not be able to play the game in this resolution. In order to run at that resolution two Voodoo2 cards are needed. To fix this simply select the next resolution down until you find one which will work. + + +ATI RAGE128 chipsets: + + With the drivers that shipped with some cards, there may be graphical corruption such as in the Main Menu. The game may also crash when the user tries to enter the game. ATI Technologies is aware of this problem and there are drivers that correct it. Go to http://www.atitech.ca/ca_us/betadrv to obtain the latest drivers. + +Nvidia Riva128 chipsets: + + Aliens versus Predator makes use of blend modes that are not simultaneously supported by the Riva chipset. Nvidia is aware of this problem and are looking into providing support with new drivers. Go to http://www.nvidia.com to obtain the latest drivers. + +Voodoo 1 in combination with SR 9 (Savage 4): + + Texture corruption is sometimes observed in game when the Voodoo 1 card is selected. We recommend using the SR 9 card instead as this does not exhibit the same problems in this situation. + + + +Sound Cards: + +Creative Labs SoundBlaster Live: + + Currently when exiting the game, windows 95/98 will sometimes crash with a blue screen error message. This problem has been corrected and Creative Labs have released a new driver that corrects this problem. Go to http://www.sblive.com + + + + +Peripherals: + + Logitech Mouse with 3rd button mouse wheel - when trying to assign a key to the middle mouse button, it may assign this function to "Mouse1" or "Mouse2". To function as a third mouse button "Mouse3" make sure that you have the latest drivers from Logitech (http://www.logitech.com). Also access the Windows Control Panel and double-click Mouse (Click Start, Settings, Control Panel, Mouse) to access Logitech Mouse Properties and click on the buttons tab. Go into the "Button Assignment 2" menu and select "Middle Button". This will enable the 3rd mouse button within Aliens versus Predator. + + + + +Microsoft Sidewinder Force Feedback Controllers: + + Although these controllers function without any known problems, Force Feedback is not currently supported in Aliens versus Predator. + + + +NOTE: Make sure you have installed the most recent drivers for all your hardware before playing Aliens Versus Predator, this will help avoid most issues. + + + +Windows 95/98 Issues: + +When pressing ALT+TAB and/or the Windows Key on keyboards Aliens versus Predator will minimize. Problems may occur when minimizing Single and Multiplayer games so this is NOT recommended. + +Because Alien Vs Predator is using Red Book audio (CD music) there is an occasional pause when ever the CD seeks to a new track. This is a general Windows problem, there is no work around for this. + + + + +III: TROUBLE SHOOTING GENERAL GAME ISSUES + +Question: I'm getting low frame rate when playing Aliens vs. Predator what's wrong? + +a) Did you try defragging your hard drive before installing Aliens versus Predator? +b) Do you have multiple applications running in the background on WIN 95/98? Check your taskbar and see if applications can be closed or disabled like Virus Scanners and other utilities in Windows. Programs running in your task bar use system resources, to check your system resources, right click your mouse over the My Computer icon, select properties, Performance, if it's less than 80% you may encounter some problems. +c) Select a lower screen resolution setting in the game. +d) Did you set all the Details Settings to Very Low or Off? + +Question: I put in the Music CD but I'm not hearing any background music. + +a) Is autoplay enabled for your CD-ROM? If so, chances are that Windows Music Player or other Audio player was initiated. This frequently occurs when the Music CD is inserted before executing Aliens versus Predator. Simply exit out of the audio player before starting Aliens vs. Predator. +b) Check and make sure that the CD Volume Slider in Aliens versus Predator is all the way to the right. If you still don't hear any music while your in the game, exit out to Windows and go into the Control Panel (Start, Setting, Control Panel). Now double click the Multimedia Icon and select the "CD Music" tab. Make sure that the volume slider is all the way to the right. +c)If your machine has multiple CD-ROM drives (CD-Writers, DVD-ROMS) they are sometimes selected as the main audio source. Even though systems may play music CD's just fine when not playing the game, make sure you assign the correct Drive letter to be your source drive to hear in-game music. You can do this by going to the Start Menu, Settings, Control Panel, Multimedia. Now select the CD-Music tab and change the drive letter accordingly to where you placed your music CD. + +Question: My game keeps pausing for a second, what's going on? + +a)Because Alien versus Predator uses Red Book audio (CD music), there is an occasional pause whenever the CD seeks to a new track. This is a general Windows problem, there is no known work around for this. + +Question: What can I do if the game is too dark?. + +a) By nature the Alien versus Predator environments are meant to be dark and scary. Certain sections of the game are designed to be so dark that you are forced to use different vision modes to compensate. If you are having trouble seeing things generally you will find a gamma correction utility in the Video Options menu in the game. Try different settings until you find one you like. + + + + +IV. MULTI-PLAYER + +Aliens Versus Predator has an eight player maximum limit. Because of the amount of information being transferred some lower end machines might experience lag and very choppy game play. Some things can be done to help this, however, the basis of a fast game is still dependant on the host's machine speed. The faster the machine the better the play. +To compensate for laggy network play the host can designate several resource-saving options. When you get ready to host a multi-player game, there is a large list of options for tweaking, every machine is different and responds better or worse to specific changes. Things like locking out the use of the flamethrower will help reduce slow down on all machines. We recommend trying out different settings until you find the one that best fits you machine. + + + + +V. CONTACTING FOX INTERACTIVE + + In the rare case that you should receive a defective disc or discs, you should first attempt to return it to the store from which you bought it, taking with you your receipt. If, however, you fail in your quest, you can write to us, call us or email us at the following locations. + +Fox Interactive +P.O. Box 900 +Beverly Hills, Ca 90213-0900 + +Or call 970-522-5369 + +For more information visit our web site. +www.foxinteractive.com + + +Fox Interactive would like to thank you for purchasing this title. diff --git a/3dc/shpanim.c b/3dc/shpanim.c new file mode 100644 index 0000000..37fb6fc --- /dev/null +++ b/3dc/shpanim.c @@ -0,0 +1,486 @@ +#include "3dc.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +extern int NormalFrameTime; +extern int NumActiveBlocks; +extern DISPLAYBLOCK * ActiveBlockList[]; + + +void CopyAnimationFrameToShape (SHAPEANIMATIONCONTROLDATA *sacd, DISPLAYBLOCK * dptr) +{ + SHAPEHEADER * shp = dptr->ObShapeData; + + GLOBALASSERT (sacd->current_frame >= 0); + GLOBALASSERT (sacd->current_frame < (signed)sacd->sequence->num_frames); + + shp->points[0] = sacd->sequence->anim_frames[sacd->current_frame].vertices; + shp->sh_normals[0] = sacd->sequence->anim_frames[sacd->current_frame].item_normals; +} + +static void CopyAnimationSequenceDataToObject (SHAPEANIMATIONSEQUENCE * sas, DISPLAYBLOCK * dptr) +{ + dptr->ObRadius = sas->radius; + + dptr->ObMaxX = sas->max_x; + dptr->ObMinX = sas->min_x; + + dptr->ObMaxY = sas->max_y; + dptr->ObMinY = sas->min_y; + + dptr->ObMaxZ = sas->max_z; + dptr->ObMinZ = sas->min_z; +} + +static void ChooseNextFrame (SHAPEANIMATIONCONTROLDATA *current) +{ + while (current->time_to_next_frame <= 0) + { + current->time_to_next_frame += current->seconds_per_frame; + + if (current->reversed) + current->current_frame --; + else + current->current_frame ++; + + current->done_a_frame = 1; + + if (current->current_frame >= (signed)current->sequence->num_frames) + current->current_frame = 0; + else if (current->current_frame < 0) + current->current_frame = current->sequence->num_frames-1; + + if (current->current_frame == (signed)current->end_frame + && current->done_a_frame + && (current->stop_at_end || current->pause_at_end)) + { + break; + } + } +} + +void DoShapeAnimation (DISPLAYBLOCK * dptr) +{ + SHAPEANIMATIONCONTROLLER * sac = dptr->ShapeAnimControlBlock; + SHAPEANIMATIONCONTROLDATA * active_sequence = &sac->current; + + GLOBALASSERT (sac); + + if (!sac->playing) + return; + + if (active_sequence->empty) + return; + + active_sequence->time_to_next_frame -= NormalFrameTime; + + if (active_sequence->time_to_next_frame > 0) + return; + + // At this point we may have switched to the last frame + // but still had a bit of time left on it + + if ((active_sequence->current_frame == (signed)active_sequence->end_frame + && active_sequence->done_a_frame + && active_sequence->stop_at_end) || active_sequence->stop_now) + { + // set to next, or finished + if (sac->next.empty) + { + sac->finished = 1; + sac->playing = 0; + return; + } + else + { + sac->next.time_to_next_frame = sac->current.time_to_next_frame; + sac->current = sac->next; + sac->next.empty = 1; + + active_sequence->time_to_next_frame += active_sequence->seconds_per_frame; + ChooseNextFrame (active_sequence); + + CopyAnimationSequenceDataToObject (active_sequence->sequence, dptr); + return; + } + } + else if ( active_sequence->current_frame == (signed)active_sequence->end_frame + && active_sequence->done_a_frame + && active_sequence->pause_at_end) + { + active_sequence->pause_at_end = 0; + sac->playing = 0; + active_sequence->done_a_frame = 0; + return; + } + + ChooseNextFrame (active_sequence); + + // if we have reached the last frame and we still have time + // continue else swap sequences + + if (active_sequence->time_to_next_frame <= 0) + { + if (active_sequence->current_frame == (signed)active_sequence->end_frame + && active_sequence->done_a_frame + && active_sequence->stop_at_end) + { + // set to next, or finished + if (sac->next.empty) + { + sac->finished = 1; + sac->playing = 0; + return; + } + else + { + sac->next.time_to_next_frame = sac->current.time_to_next_frame; + + // this will change the active_sequence pointers contents + sac->current = sac->next; + CopyAnimationSequenceDataToObject (active_sequence->sequence, dptr); + + + // If I had a linked list (or queue) of sequences + // I may want to put the next bit of code differently + + active_sequence->time_to_next_frame += active_sequence->seconds_per_frame; + + ChooseNextFrame (active_sequence); + + return; + } + } + else if ( active_sequence->current_frame == (signed)active_sequence->end_frame + && active_sequence->done_a_frame + && active_sequence->pause_at_end) + { + active_sequence->pause_at_end = 0; + sac->playing = 0; + active_sequence->done_a_frame = 0; + return; + } + else + { + // Shouldn't be here + GLOBALASSERT (0); + } + } + +} + + +void DoAllShapeAnimations () +{ + int i; + + for (i=0; iShapeAnimControlBlock) + { + DoShapeAnimation(dptr); + } + + } + +} + + +unsigned int SetShapeAnimationSequence (DISPLAYBLOCK * dptr, SHAPEANIMATIONCONTROLDATA * sacd) +{ + SHAPEANIMATIONCONTROLLER * sac = dptr->ShapeAnimControlBlock; + + GLOBALASSERT(sac); + GLOBALASSERT(sacd); + GLOBALASSERT(sacd->sequence_no < sac->anim_header->num_sequences); + + sac->next.empty = 1; + + sac->playing = 1; + sac->finished = 0; + + sac->current.sequence_no = sacd->sequence_no; + + sac->current.reversed = sacd->reversed; + sac->current.stop_at_end = sacd->stop_at_end; + + + sac->current.empty = 0; + sac->current.done_a_frame = 0; + sac->current.sequence = &sac->anim_header->anim_sequences[sacd->sequence_no]; + sac->current.stop_now = 0; + sac->current.pause_at_end = 0; + + if (sacd->default_start_and_end_frames) + { + if (sacd->reversed) + { + sac->current.start_frame = sac->current.sequence->num_frames-1; + sac->current.end_frame = 0; + } + else + { + sac->current.start_frame = 0; + sac->current.end_frame = sac->current.sequence->num_frames-1; + } + } + else + { + sac->current.start_frame = sacd->start_frame; + sac->current.end_frame = sacd->end_frame; + } + + sac->current.seconds_per_frame = sacd->seconds_per_frame; + + sac->current.current_frame = sac->current.start_frame; + + sac->current.time_to_next_frame = sac->current.seconds_per_frame; + + CopyAnimationSequenceDataToObject (sac->current.sequence, dptr); + + return(1); + + +} + + +unsigned int SetNextShapeAnimationSequence (DISPLAYBLOCK * dptr, SHAPEANIMATIONCONTROLDATA * sacd) +{ + SHAPEANIMATIONCONTROLLER * sac = dptr->ShapeAnimControlBlock; + + GLOBALASSERT(sac); + GLOBALASSERT(sacd); + GLOBALASSERT(sacd->sequence_no < sac->anim_header->num_sequences); + + + if (sac->current.empty) + { + return(SetShapeAnimationSequence (dptr,sacd)); + } + + if (sac->finished) + { + return(0); + } + + + sac->next.sequence_no = sacd->sequence_no; + + sac->next.reversed = sacd->reversed; + sac->next.stop_at_end = sacd->stop_at_end; + + + sac->next.empty = 0; + sac->next.done_a_frame = 0; + sac->next.sequence = &sac->anim_header->anim_sequences[sacd->sequence_no]; + sac->next.stop_now = 0; + sac->next.pause_at_end = 0; + + if (sacd->default_start_and_end_frames) + { + if (sacd->reversed) + { + sac->next.start_frame = sac->next.sequence->num_frames-1; + sac->next.end_frame = 0; + } + else + { + sac->next.start_frame = 0; + sac->next.end_frame = sac->next.sequence->num_frames-1; + } + } + else + { + sac->next.start_frame = sacd->start_frame; + sac->next.end_frame = sacd->end_frame; + } + + sac->next.seconds_per_frame = sacd->seconds_per_frame; + + sac->next.current_frame = sac->next.start_frame; + + sac->next.time_to_next_frame = sac->next.seconds_per_frame; + + return(1); + + +} + +void InitShapeAnimationController (SHAPEANIMATIONCONTROLLER * sac, SHAPEHEADER * shd) +{ + GLOBALASSERT(shd); + GLOBALASSERT(shd->animation_header); + + sac->current.empty = 1; + sac->next.empty = 1; + + sac->anim_header = shd->animation_header; + + sac->playing = 0; + +} + +void SetCurrentShapeAnimationToStop (DISPLAYBLOCK * dptr, unsigned long stop_now, signed long end_frame) +{ + SHAPEANIMATIONCONTROLLER * sac = dptr->ShapeAnimControlBlock; + + GLOBALASSERT(sac); + + if (stop_now) + { + sac->current.stop_now = 1; + return; + } + + if (end_frame != -1) + { + GLOBALASSERT (end_frame >= 0); + GLOBALASSERT (end_frame < (signed)sac->current.sequence->num_frames); + + sac->current.end_frame = end_frame; + } + + sac->current.stop_at_end = 1; + +} + + +SHAPEANIMATIONCONTROLDATA const * GetCurrentShapeAnimationSequenceData (DISPLAYBLOCK * dptr) +{ + SHAPEANIMATIONCONTROLLER * sac = dptr->ShapeAnimControlBlock; + + if (sac) + { + if (!sac->current.empty) + return(&sac->current); + } + + return(0); +} + + +SHAPEANIMATIONCONTROLDATA const * GetNextShapeAnimationSequenceData (DISPLAYBLOCK * dptr) +{ + SHAPEANIMATIONCONTROLLER * sac = dptr->ShapeAnimControlBlock; + + if (sac) + { + if (!sac->next.empty) + return(&sac->next); + } + + return(0); + +} + + +void PauseCurrentShapeAnimation (DISPLAYBLOCK * dptr, unsigned long pause_now, signed long end_frame) +{ + SHAPEANIMATIONCONTROLLER * sac = dptr->ShapeAnimControlBlock; + + GLOBALASSERT(sac); + + if (pause_now) + { + sac->playing = 0; + return; + } + + if (end_frame != -1) + { + GLOBALASSERT (end_frame >= 0); + GLOBALASSERT (end_frame < (signed)sac->current.sequence->num_frames); + + sac->current.end_frame = end_frame; + } + + sac->current.pause_at_end = 1; + +} + +void RestartCurrentShapeAnimation (DISPLAYBLOCK * dptr) +{ + SHAPEANIMATIONCONTROLLER * sac = dptr->ShapeAnimControlBlock; + + GLOBALASSERT(sac); + + sac->playing = 1; + + sac->current.pause_at_end = 0; + +} + + +void InitShapeAnimationControlData (SHAPEANIMATIONCONTROLDATA * sacd) +{ + GLOBALASSERT(sacd); + + sacd->seconds_per_frame = 8192; + + sacd->sequence_no = 0; + + sacd->default_start_and_end_frames = 1; + sacd->reversed = 0; + + sacd->stop_at_end = 0; + +} + +unsigned int SetOrphanedShapeAnimationSequence (SHAPEANIMATIONCONTROLLER * sac, SHAPEANIMATIONCONTROLDATA * sacd) +{ + + GLOBALASSERT(sac); + GLOBALASSERT(sacd); + GLOBALASSERT(sacd->sequence_no < sac->anim_header->num_sequences); + + sac->next.empty = 1; + + sac->playing = 1; + sac->finished = 0; + + sac->current.sequence_no = sacd->sequence_no; + + sac->current.reversed = sacd->reversed; + sac->current.stop_at_end = sacd->stop_at_end; + + + sac->current.empty = 0; + sac->current.done_a_frame = 0; + sac->current.sequence = &sac->anim_header->anim_sequences[sacd->sequence_no]; + sac->current.stop_now = 0; + sac->current.pause_at_end = 0; + + if (sacd->default_start_and_end_frames) + { + if (sacd->reversed) + { + sac->current.start_frame = sac->current.sequence->num_frames-1; + sac->current.end_frame = 0; + } + else + { + sac->current.start_frame = 0; + sac->current.end_frame = sac->current.sequence->num_frames-1; + } + } + else + { + sac->current.start_frame = sacd->start_frame; + sac->current.end_frame = sacd->end_frame; + } + + sac->current.seconds_per_frame = sacd->seconds_per_frame; + + sac->current.current_frame = sac->current.start_frame; + + sac->current.time_to_next_frame = sac->current.seconds_per_frame; + + /* CopyAnimationSequenceDataToObject (sac->current.sequence, dptr); */ + + return(1); + + +} diff --git a/3dc/sphere.c b/3dc/sphere.c new file mode 100644 index 0000000..b5ef4bc --- /dev/null +++ b/3dc/sphere.c @@ -0,0 +1,257 @@ +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "sphere.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + + +#define MakeVertex(o,x,y,z) \ +{ \ + o->vx=(x); \ + o->vy=(y); \ + o->vz=(z); \ + o++; \ +} + +#define MakeFace(f,a,b,c) \ +{ \ + f->v[0] = (a); \ + f->v[1] = (b); \ + f->v[2] = (c); \ + f++; \ +} + +VECTORCH OctantVertex[(SPHERE_ORDER+1)*(SPHERE_ORDER+2)/2]; +VECTORCH SphereVertex[SPHERE_VERTICES]; + +VECTORCH SphereRotatedVertex[SPHERE_VERTICES]; +VECTORCH SphereAtmosRotatedVertex[SPHERE_VERTICES]; +int SphereAtmosU[SPHERE_VERTICES]; +int SphereAtmosV[SPHERE_VERTICES]; + + +TRI_FACE SphereFace[SPHERE_FACES]; +int SphereVertexHeight[SPHERE_VERTICES]; + +static void Generate_SphereOctant(void) +{ + int i,j; + + VECTORCH *o = OctantVertex; + + /* i=0, j=0 */ + MakeVertex(o,0,0,SPHERE_RADIUS); + + for (i=1; i cosTheta = 1, sinTheta = 0 */ + MakeVertex(o,sinPhi,0,cosPhi); + + for (j=1; j=0; o++, v++) + { + *v = *o; + } + /* 2nd Quadrant */ + for (j=i; --j>=0; o--, v++) + { + v->vx = -o->vx; + v->vy = o->vy; + v->vz = o->vz; + } + /* 3rd Quadrant */ + for (j=i; --j>=0; o++, v++) + { + v->vx = -o->vx; + v->vy = -o->vy; + v->vz = o->vz; + } + /* 4th Quadrant */ + for (j=i; --j>=0; o--, v++) + { + v->vx = o->vx; + v->vy = -o->vy; + v->vz = o->vz; + } + } + for (; --i>1;) + { + o -= i; + /* 5th Quadrant */ + for (j=i; --j>0; o++, v++) + { + v->vx = o->vx; + v->vy = o->vy; + v->vz = -o->vz; + } + /* 6th Quadrant */ + for (j=i; --j>0; o--, v++) + { + v->vx = -o->vx; + v->vy = o->vy; + v->vz = -o->vz; + } + /* 7th Quadrant */ + for (j=i; --j>0; o++, v++) + { + v->vx = -o->vx; + v->vy = -o->vy; + v->vz = -o->vz; + } + /* 8th Quadrant */ + for (j=i; --j>0; o--, v++) + { + v->vx = o->vx; + v->vy = -o->vy; + v->vz = -o->vz; + } + } + o--; + /* south pole */ + v->vx = -o->vx; + v->vy = -o->vy; + v->vz = -o->vz; + } + + /* now generate face data */ + { + TRI_FACE *f = SphereFace; + int kv,kw,ko,kv0,kw0,i,j; + + kv = 0, kw = 1; + + for(i=0; i=0;) + { + kv0=kv,kw0=kw; + for(ko=5;ko<=7;ko++) + { + for (j=i;; j--) + { + MakeFace(f,kv,kw,++kv); + if (j==0) break; + MakeFace(f,kv,kw,++kw); + } + } + for (j=i;;j--) + { + if (j==0) + { + MakeFace(f,kv,kw0,kv0); + kv++; + kw++; + break; + } + MakeFace(f,kv,kw,++kv); + if (j==1) + { + MakeFace(f,kv,kw,kw0); + } + else MakeFace(f,kv,kw,++kw); + } + } + } + { + int i; + VECTORCH *vSphere = SphereVertex; + for(i=0;ivx*vSphere->vx+vSphere->vz*vSphere->vz; +// if (radius<16384) radius = 16384; + +// SphereAtmosU[i] = DIV_FIXED(ArcCos(vSphere->vy)*32*128*8,radius); + SphereAtmosV[i] = ArcCos(vSphere->vy)*32*128*SPHERE_TEXTURE_WRAP;//*8; + SphereAtmosU[i] = ArcTan(vSphere->vz,vSphere->vx)*16*128*SPHERE_TEXTURE_WRAP;//*8; + } + } +} diff --git a/3dc/sphere.h b/3dc/sphere.h new file mode 100644 index 0000000..0d16717 --- /dev/null +++ b/3dc/sphere.h @@ -0,0 +1,40 @@ +#ifndef _included_sphere_h_ /* Is this your first time? */ +#define _included_sphere_h_ 1 + + +typedef struct +{ + int v[3]; +} TRI_FACE; + +#define SPHERE_ORDER 6 +#define SPHERE_RADIUS ONE_FIXED +#define SPHERE_FACES (8*SPHERE_ORDER*SPHERE_ORDER) +#define SPHERE_VERTICES (4*SPHERE_ORDER*SPHERE_ORDER+2) +#define SPHERE_TEXTURE_WRAP 4 +extern VECTORCH SphereVertex[]; +extern VECTORCH SphereRotatedVertex[]; +extern VECTORCH SphereAtmosRotatedVertex[]; +extern int SphereAtmosU[]; +extern int SphereAtmosV[]; +extern TRI_FACE SphereFace[]; +extern int SphereVertexHeight[]; + +typedef struct +{ + VECTORCH Position[SPHERE_VERTICES]; + VECTORCH Velocity[SPHERE_VERTICES]; + int RipplePhase[SPHERE_VERTICES]; + int BeenStopped[SPHERE_VERTICES]; + + int ExplosionPhase; + int NumberVerticesMoving; + int LifeTime; + int UseCollisions; + +} VOLUMETRIC_EXPLOSION; + +extern void Generate_Sphere(void); + + +#endif \ No newline at end of file diff --git a/3dc/version.c b/3dc/version.c new file mode 100644 index 0000000..0dcc229 --- /dev/null +++ b/3dc/version.c @@ -0,0 +1,15 @@ +/* KJL 16:41:33 29/03/98 - not the most complicated code I've ever written... */ +#include "version.h" +extern void NewOnScreenMessage(unsigned char *messagePtr); + + +void GiveVersionDetails(void) +{ + /* KJL 15:54:25 29/03/98 - give version details; this is not language localised since I thought that would be a little odd */ +// NewOnScreenMessage("ALIENS VS PREDATOR - DEATHMATCH DEMO V1.0 - REBELLION DEVELOPMENTS 1998/11/28"); +// NewOnScreenMessage("Aliens vs Predator - Alien Demo V1.3 - Rebellion Developments 1999/1/25"); +// NewOnScreenMessage("Aliens vs Predator - \n Build 103 \n Rebellion Developments 1999/7/13 \n (European Release)"); +// NewOnScreenMessage("Aliens vs Predator - \n Build 103 \n Rebellion Developments 1999/7/13 \n (American Release)"); + NewOnScreenMessage("Aliens vs Predator - Gold\n Build 116 \n Rebellion Developments 2000/16/3 \n"); //11:25 + +} diff --git a/3dc/version.h b/3dc/version.h new file mode 100644 index 0000000..d532e58 --- /dev/null +++ b/3dc/version.h @@ -0,0 +1,3 @@ +/* KJL 15:56:24 29/03/98 - this function supplies a text +description of the current build, and the build date. */ +extern void GiveVersionDetails(void); \ No newline at end of file diff --git a/3dc/vssver.scc b/3dc/vssver.scc new file mode 100644 index 0000000..b8acc32 Binary files /dev/null and b/3dc/vssver.scc differ diff --git a/3dc/win95/ANIMCHNK.CPP b/3dc/win95/ANIMCHNK.CPP new file mode 100644 index 0000000..3f5d87a --- /dev/null +++ b/3dc/win95/ANIMCHNK.CPP @@ -0,0 +1,270 @@ +#include "animchnk.hpp" + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(animchnk) + +RIF_IMPLEMENT_DYNCREATE("TEXTANIM",Animation_Chunk) + +Animation_Chunk::Animation_Chunk(Chunk_With_Children* parent) +: Chunk(parent, "TEXTANIM") +{ + NumPolys=0; + AnimList=0; +} +Animation_Chunk::Animation_Chunk(Chunk_With_Children* parent,const char* data,size_t /*datasize*/) +: Chunk(parent, "TEXTANIM") +{ + NumPolys=*((int*)data); + data+=4; + if(NumPolys) + { + AnimList=(TEXANIM**)malloc(NumPolys*sizeof(TEXANIM*)); + for(int i=0;ipoly=*((int*)data); + data+=4; + ta->ID=*((int*)data); + data+=4; + ta->NumSeq=*((int*)data); + data+=4; + ta->NumVerts=*((int*)data); + data+=4; + ta->AnimFlags=*((int*)data); + data+=4; + ta->Identifier=*((int*)data); + data+=4; + ta->CurSeq=0; + ta->Seq=new FrameList*[ta->NumSeq]; + for(int j=0;jNumSeq;j++) + { + ta->Seq[j]=new FrameList(ta); + FrameList* fl=ta->Seq[j]; + fl->Speed=*((int*)data); + data+=4; + fl->Flags=*((int*)data); + data+=4; + + fl->NumFrames=*((int*)data); + data+=4; + fl->spare1=*((int*)data); + data+=4; + fl->spare2=*((int*)data); + data+=4; + fl->CurFrame=0; + + fl->Textures=new int[fl->NumFrames]; + fl->UVCoords=new int[(2*ta->NumVerts)*fl->NumFrames]; + for(int k=0;kNumFrames;k++) + { + fl->Textures[k]=*((int*)data); + data+=4; + } + for(k=0;k<(2*ta->NumVerts)*fl->NumFrames;k++) + { + fl->UVCoords[k]=*((int*)data); + data+=4; + } + } + + } + } + else + AnimList=0; + +} + +Animation_Chunk::~Animation_Chunk() +{ + for(int i=0;iNumSeq;j++) + { + chunk_size+=20; + chunk_size+=4*(1+2*ta->NumVerts)*ta->Seq[j]->NumFrames; + } + } + return chunk_size; +} + +BOOL Animation_Chunk::output_chunk (HANDLE &hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = this->make_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; +} + +void Animation_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *(int*)data_start=NumPolys; + data_start+=4; + for(int i=0;ipoly; + data_start+=4; + *(int*)data_start=ta->ID; + data_start+=4; + *(int*)data_start=ta->NumSeq; + data_start+=4; + *(int*)data_start=ta->NumVerts; + data_start+=4; + *(int*)data_start=ta->AnimFlags; + data_start+=4; + *(int*)data_start=ta->Identifier; + data_start+=4; + + for(int j=0;jNumSeq;j++) + { + FrameList* fl=ta->Seq[j]; + *(int*)data_start=fl->Speed; + data_start+=4; + *(int*)data_start=fl->Flags; + data_start+=4; + *(int*)data_start=fl->NumFrames; + data_start+=4; + *(int*)data_start=fl->spare1; + data_start+=4; + *(int*)data_start=fl->spare2; + data_start+=4; + for(int k=0;kNumFrames;k++) + { + *(int*)data_start=fl->Textures[k]; + data_start+=4; + } + for(k=0;k<(2*ta->NumVerts)*fl->NumFrames;k++) + { + *(int*)data_start=fl->UVCoords[k]; + data_start+=4; + } + } + + } +} + +FrameList::FrameList(TEXANIM* p) +{ + Speed=65536; + Flags=0; + NumFrames=0; + CurFrame=-1; + parent=p; + Textures=0; + UVCoords=0; + spare1=spare2=0; +} +FrameList::FrameList(TEXANIM* p,FrameList* fl,int* conv) +{ + Speed=fl->Speed; + Flags=fl->Flags; + NumFrames=fl->NumFrames; + parent=p; + Textures=new int[NumFrames]; + UVCoords=new int[NumFrames*2*p->NumVerts]; + spare1=fl->spare1; + spare2=fl->spare2; + if(conv) + { + for(int i=0;iTextures[i]]; + } + } + else + { + for(int i=0;iTextures[i]; + } + } + for(int i=0;iNumVerts;i++) + { + UVCoords[i]=fl->UVCoords[i]; + } + CurFrame=0; +} +FrameList::~FrameList() +{ + delete [] Textures; + delete UVCoords; +} + +TEXANIM::TEXANIM() +{ + shape=0; + NumSeq=0; + CurSeq=-1; + Seq=0; + NumVerts=3; + AnimFlags=Identifier=0; +} +TEXANIM::TEXANIM(TEXANIM* ta) +{ + shape=0; + NumSeq=0; + CurSeq=-1; + Seq=0; + NumVerts=3; + AnimFlags=Identifier=0; + CopyAnimData(ta,0); +} + +TEXANIM::~TEXANIM() +{ + for(int i=0;ishape; + poly=ta->poly; + ID=ta->ID; + NumSeq=ta->NumSeq; + CurSeq=0; + Seq=new FrameList*[NumSeq]; + NumVerts=ta->NumVerts; + AnimFlags=ta->AnimFlags; + Identifier=ta->Identifier; + for(int i=0;iSeq[i],conv); + } + +} + diff --git a/3dc/win95/ANIMCHNK.HPP b/3dc/win95/ANIMCHNK.HPP new file mode 100644 index 0000000..9c30cbc --- /dev/null +++ b/3dc/win95/ANIMCHNK.HPP @@ -0,0 +1,88 @@ +#ifndef _animchnk_hpp +#define _animchnk_hpp +#include "chunk.hpp" +#include "Chnktype.hpp" + +struct TEXANIM; + + +class Animation_Chunk : public Chunk +{ +public : + Animation_Chunk(Chunk_With_Children* parent,const char*,size_t); + Animation_Chunk(Chunk_With_Children* parent); + ~Animation_Chunk(); + + virtual BOOL output_chunk (HANDLE &hand); + + virtual size_t size_chunk(); + + virtual void fill_data_block(char* data_start); + + int NumPolys; //with animation in this shape + TEXANIM** AnimList; + +}; + +#define txa_flag_nointerptofirst 0x80000000 + +struct FrameList +{ + ~FrameList(); + FrameList(TEXANIM*); + #if InterfaceEngine + FrameList(TEXANIM* p,FrameList* templ); + #endif + FrameList(TEXANIM* p,FrameList* fl,int* conv); + int Speed; + int Flags; + + int NumFrames; + int CurFrame; + TEXANIM* parent; + + int* Textures; + int* UVCoords; + int spare1,spare2; + + + #if InterfaceEngine + void CopyToSID(int shape,int poly); + void CopyFromSID(int shape,int poly); + void AddFrame(); + void RemoveFrame(); + #endif +}; + +#define AnimFlag_NotPlaying 0x00000001 +struct TEXANIM +{ + TEXANIM(TEXANIM*); + TEXANIM(); + ~TEXANIM(); + + #if InterfaceEngine + TEXANIM(int s,int p,int id); + //construct a TEXANIM using templ as a template. + TEXANIM(int s,int p,TEXANIM* templ); + #endif + int shape; + int poly; + int NumVerts; + int ID; + int NumSeq;//number of sequences + int CurSeq; + int AnimFlags; + int Identifier; + FrameList** Seq; + + #if InterfaceEngine + void ChangeFrame(int newseq,int newframe); + void AddSeq(); + void RemoveSeq(); + void CopySeq(int seq_num); + #endif + void CopyAnimData(TEXANIM* ta,int* conv); +}; + +#endif diff --git a/3dc/win95/BMPNAMES.CPP b/3dc/win95/BMPNAMES.CPP new file mode 100644 index 0000000..1918033 --- /dev/null +++ b/3dc/win95/BMPNAMES.CPP @@ -0,0 +1,964 @@ +#include +#include "bmpnames.hpp" +#include "mishchnk.hpp" + +#if engine +#define UseLocalAssert No +#include "ourasert.h" +#define assert(x) GLOBALASSERT(x) +#else +#if cencon +#include "ccassert.h" +#else +#include +#endif +#endif + +#ifdef cencon +#define new my_new +#endif + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(bmpnames) + + +BMP_Name::BMP_Name (const char * fname, int const gbnc_version) +: flags((BMPN_Flags)DEFAULT_BMPN_FLAGS), index(0), version_num (gbnc_version << BMPNAME_PARENT_VER_SHIFT), priority (DEFAULT_BMPN_PRIORITY), transparency_colour_union(0), enum_id(0) +#if cencon +, md5val(0) +#endif +{ + filename = new char [strlen(fname)+1]; + strcpy (filename, fname); +} + +BMP_Name::BMP_Name (const char * fname) +: flags((BMPN_Flags)DEFAULT_BMPN_FLAGS), index(0), version_num (0), priority (DEFAULT_BMPN_PRIORITY), transparency_colour_union(0), enum_id(0) +#if cencon +, md5val(0) +#endif +{ + filename = new char [strlen(fname)+1]; + strcpy (filename, fname); +} + +BMP_Name::~BMP_Name () +{ + if (filename) + delete [] filename; +} + +BMP_Name::BMP_Name (const BMP_Name & bn) +{ + if (&bn == this) return; + + filename = new char [strlen(bn.filename)+1]; + strcpy (filename, bn.filename); + flags = bn.flags; + index = bn.index; + version_num = bn.version_num; + enum_id = bn.enum_id; + priority = bn.priority; + transparency_colour_union = bn.transparency_colour_union; + #if cencon + md5val = bn.md5val; + #endif +} + +void BMP_Name::Validate(void) +{ + if (flags & ChunkBMPFlag_PriorityAndTransparencyAreValid) return; + + priority = DEFAULT_BMPN_PRIORITY; + flags = (BMPN_Flags)(flags | DEFAULT_BMPN_FLAGS); +} + +const BMP_Name & BMP_Name::operator=(const BMP_Name & bn) +{ + if (&bn == this) return(*this); + + if (filename) + delete [] filename; + + filename = new char [strlen(bn.filename)+1]; + strcpy (filename, bn.filename); + flags = bn.flags; + index = bn.index; + version_num = bn.version_num; + enum_id = bn.enum_id; + priority = bn.priority; + transparency_colour_union = bn.transparency_colour_union; + #if cencon + md5val = bn.md5val; + #endif + + return(*this); + + +} + + + +BOOL operator==(const BMP_Name &o1, const BMP_Name &o2) +{ + if (o1.filename && o2.filename) return _stricmp(o1.filename,o2.filename) ? FALSE : TRUE; + else return &o1 == &o2; +} + +BOOL operator!=(const BMP_Name &o1, const BMP_Name &o2) +{ + if (o1.filename && o2.filename) return _stricmp(o1.filename,o2.filename) ? TRUE : FALSE; + else return &o1 != &o2; +} + + +/////////////////////////////////////// + +// Class Chunk_With_BMPs functions + + + +Chunk_With_BMPs::Chunk_With_BMPs (Chunk_With_Children * parent, const char * const ident, const char * bdata, size_t /*bsize*/) +: Chunk (parent, ident), max_index (0) +{ + int temp = *(int *)bdata; + + int num = temp & 0xffff; + + int ver_num = temp >> 16 & 0xffff; // the remains of a previous mistake - not really necessary anymore + + bdata += 4; + + for (int i=0; i> BMPNAME_ENUMID_SHIFT); + bn.priority = d2; + bn.transparency_colour_union = d3; + + max_index = max (bn.index, max_index); + + bmps.add_entry (bn); + } + + if (ver_num) + { + set_version_num(ver_num); + } +} + + +size_t Chunk_With_BMPs::size_chunk () +{ + int sz = 12 + 4; + + for (LIF bl(&bmps); !bl.done(); bl.next()) + { + sz += (4-strlen(bl().filename)%4) + strlen(bl().filename) + 20; + } + + chunk_size = sz; + + return (chunk_size); + +} + +void Chunk_With_BMPs::fill_data_block (char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = bmps.size(); + + data_start += 4; + + for (LIF bl(&bmps); !bl.done(); bl.next()) + { + *((int *) data_start) = bl().flags; + data_start += 4; + *((int *) data_start) = bl().index; + data_start += 4; + *((int *) data_start) = bl().version_num & BMPNAME_VERSION_NUM_MASK | bl().enum_id << BMPNAME_ENUMID_SHIFT; + data_start += 4; + *((int *) data_start) = bl().priority; + data_start += 4; + *((int *) data_start) = bl().transparency_colour_union; + data_start += 4; + + strcpy (data_start, bl().filename); + data_start += (4-strlen(bl().filename)%4) + strlen(bl().filename); + } + +} + +int Chunk_With_BMPs::get_version_num(void) +{ + if (parent) + { + List verlist; + parent->lookup_child("BMNAMVER",verlist); + while (verlist.size()>1) + { + Chunk * v1 = verlist.first_entry(); + Chunk * v2 = verlist[1]; + if (((BMP_Names_Version_Chunk *)v1)->version_num > ((BMP_Names_Version_Chunk *)v2)->version_num) + { + delete verlist.last_entry(); + verlist.delete_last_entry(); + } + else + { + delete v1; + verlist.delete_first_entry(); + } + } + if (verlist.size()) + { + int rv = ((BMP_Names_Version_Chunk *)verlist.first_entry())->version_num; + return rv; + } + } + return 0; +} + +void Chunk_With_BMPs::set_version_num(int v) +{ + if (parent) + { + List verlist; + parent->lookup_child("BMNAMVER",verlist); + while (verlist.size()>1) + { + Chunk * v1 = verlist.first_entry(); + Chunk * v2 = verlist[1]; + if (((BMP_Names_Version_Chunk *)v1)->version_num > ((BMP_Names_Version_Chunk *)v2)->version_num) + { + delete verlist.last_entry(); + verlist.delete_last_entry(); + } + else + { + delete v1; + verlist.delete_first_entry(); + } + } + if (verlist.size()) + { + ((BMP_Names_Version_Chunk *)verlist.first_entry())->version_num = v; + return; + } + + (new BMP_Names_Version_Chunk(parent))->version_num = v; + } +} + +void Chunk_With_BMPs::inc_version_num(void) +{ + if (parent) + { + List verlist; + parent->lookup_child("BMNAMVER",verlist); + while (verlist.size()>1) + { + Chunk * v1 = verlist.first_entry(); + Chunk * v2 = verlist[1]; + if (((BMP_Names_Version_Chunk *)v1)->version_num > ((BMP_Names_Version_Chunk *)v2)->version_num) + { + delete verlist.last_entry(); + verlist.delete_last_entry(); + } + else + { + delete v1; + verlist.delete_first_entry(); + } + } + if (verlist.size()) + { + ((BMP_Names_Version_Chunk *)verlist.first_entry())->version_num ++; + return; + } + + (new BMP_Names_Version_Chunk(parent))->version_num ++; + } +} + +BMP_Names_ExtraData * Chunk_With_BMPs::GetExtendedData(void) +{ + if (parent) + { + List verlist; + parent->lookup_child("BMNAMEXT",verlist); + if (verlist.size()) + { + return (BMP_Names_ExtraData_Chunk *) verlist.first_entry(); + } + return new BMP_Names_ExtraData_Chunk(parent); + } + return 0; +} + +int const * Chunk_With_BMPs::GetMD5Val(BMP_Name const & rcbmp) +{ + Bitmap_MD5_Chunk * md5c = GetMD5Chunk(rcbmp.filename); + if (md5c) + if (rcbmp.version_num == md5c->version_num) + return md5c->md5_val; + return 0; +} + +void Chunk_With_BMPs::RemoveMD5Val(char const * bname) +{ + Bitmap_MD5_Chunk * md5c = GetMD5Chunk(bname); + if (md5c) + delete md5c; +} + +void Chunk_With_BMPs::SetMD5Val(BMP_Name const & rcbmp, int const * md5id) +{ + Bitmap_MD5_Chunk * md5c = GetMD5Chunk(rcbmp.filename); + if (md5c) + { + if (rcbmp.version_num == md5c->version_num) + { + memcpy(md5c->md5_val,md5id,16); + return; + } + else + delete md5c; + } + CreateMD5Chunk(rcbmp,md5id); +} + + +///////////////////////////////////// +// Global_BMP_Name_Chunk +///////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("BMPNAMES",Global_BMP_Name_Chunk) + +Bitmap_MD5_Chunk * Global_BMP_Name_Chunk::GetMD5Chunk(char const * bname) +{ + List chlst; + parent->lookup_child("BMPMD5ID",chlst); + + for (LIF i_chlst(&chlst); !i_chlst.done(); i_chlst.next()) + { + Bitmap_MD5_Chunk * md5c = (Bitmap_MD5_Chunk *)i_chlst(); + + if (!strcmp(md5c->bmpname,bname)) + if (!(md5c->rifname ? *md5c->rifname : 1) && !(md5c->shapename ? *md5c->shapename : 1)) + return md5c; + } + + return 0; +} + +void Global_BMP_Name_Chunk::CreateMD5Chunk(BMP_Name const & rcbmp, int const * md5id) +{ + new Bitmap_MD5_Chunk(parent,md5id,rcbmp); +} + +///////////////////////////////////// +// Bitmap_List_Store_Chunk +///////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("BMPLSTST",Bitmap_List_Store_Chunk) + +Bitmap_MD5_Chunk * Bitmap_List_Store_Chunk::GetMD5Chunk(char const * bname) +{ + List chlst; + parent->lookup_child("BMPMD5ID",chlst); + + List rnlst; + parent->lookup_child("RIFFNAME",rnlst); + char const * rname = 0; + if (rnlst.size()) + { + rname = ((RIF_Name_Chunk *)rnlst.first_entry())->rif_name; + } + + for (LIF i_chlst(&chlst); !i_chlst.done(); i_chlst.next()) + { + Bitmap_MD5_Chunk * md5c = (Bitmap_MD5_Chunk *)i_chlst(); + + if (!strcmp(md5c->bmpname,bname)) + if (!(md5c->rifname ? rname ? strcmp(rname,md5c->rifname) : *md5c->rifname : rname ? *rname : 0) && + !(md5c->shapename ? *md5c->shapename : 1)) + return md5c; + } + + return 0; +} + +void Bitmap_List_Store_Chunk::CreateMD5Chunk(BMP_Name const & rcbmp, int const * md5id) +{ + List rnlst; + parent->lookup_child("RIFFNAME",rnlst); + char const * rname = 0; + if (rnlst.size()) + { + rname = ((RIF_Name_Chunk *)rnlst.first_entry())->rif_name; + } + new Bitmap_MD5_Chunk(parent,md5id,rcbmp,rname); +} + + + +/////////////////////////////////////// + +// Class BMP_Names_Version_Chunk functions + +RIF_IMPLEMENT_DYNCREATE("BMNAMVER",BMP_Names_Version_Chunk) + + +size_t BMP_Names_Version_Chunk::size_chunk () +{ + chunk_size = 12+4; + + return (chunk_size); + +} + +void BMP_Names_Version_Chunk::fill_data_block (char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = version_num; + +} + + + +/////////////////////////////////////// + +// Class BMP_Names_ExtraData_Chunk functions + +RIF_IMPLEMENT_DYNCREATE("BMNAMEXT",BMP_Names_ExtraData_Chunk) + + +size_t BMP_Names_ExtraData_Chunk::size_chunk () +{ + chunk_size = 12+52; + + return (chunk_size); + +} + +void BMP_Names_ExtraData_Chunk::fill_data_block (char * data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + + *((int *) data_start) = chunk_size; + data_start += 4; + + *((int *) data_start) = flags; + data_start += 4; + + for (int i=0; i<12; ++i, data_start+=4) + { + *(int *)data_start = reserved[i]; + } + +} + +/////////////////////////////////////// + +// Class External_Shape_BMPs_Store_Chunk functions +RIF_IMPLEMENT_DYNCREATE("SHBMPNAM",External_Shape_BMPs_Store_Chunk) + +External_Shape_BMPs_Store_Chunk::External_Shape_BMPs_Store_Chunk (Chunk_With_Children * parent, char const * rifn, char const * shapen) +: Chunk_With_BMPs (parent, "SHBMPNAM"), rifname(0), shapename(0), version_num(0) +{ + for (int i=0; i<12; ++i) + reserved[i] = 0; + + flags = GBF_NONE; + + if (rifn) + { + rifname = new char [strlen(rifn)+1]; + strcpy(rifname,rifn); + } + if (shapen) + { + shapename = new char [strlen(shapen)+1]; + strcpy(shapename,shapen); + } +} + +External_Shape_BMPs_Store_Chunk::~External_Shape_BMPs_Store_Chunk() +{ + if (rifname) delete[] rifname; + if (shapename) delete[] shapename; +} + +void External_Shape_BMPs_Store_Chunk::fill_data_block(char * data_start) +{ + Chunk_With_BMPs::fill_data_block(data_start); + data_start += Chunk_With_BMPs::size_chunk(); + size_chunk(); // resize it just in case + + strcpy(data_start,rifname ? rifname : ""); + unsigned int const l1 = rifname ? strlen(rifname)+1 : 1; + + strcpy(data_start+l1,shapename ? shapename : ""); + unsigned int const l2 = shapename ? strlen(shapename)+1 : 1; + + data_start += l1+l2 +3&~3; + + *(int *)data_start = flags; + data_start+=4; + + *(int *)data_start = version_num; + data_start+=4; + + for (int i=0; i<12; ++i, data_start+=4) + *(int *)data_start = reserved[i]; +} + +External_Shape_BMPs_Store_Chunk::External_Shape_BMPs_Store_Chunk (Chunk_With_Children * parent, const char * sdata, size_t ssize) +: Chunk_With_BMPs (parent, "SHBMPNAM", sdata, ssize) +{ + sdata += Chunk_With_BMPs::size_chunk() -12; + unsigned int const l1 = strlen(sdata)+1; + rifname = new char [l1]; + strcpy(rifname,sdata); + unsigned int const l2 = strlen(sdata+l1)+1; + shapename = new char [l2]; + strcpy(shapename,sdata+l1); + + sdata += l1+l2 +3&~3; + + flags = (GlobalBMPFlags)(*(int *)sdata & GBF_MASK); + sdata+=4; + + version_num = *(int *)sdata; + sdata+=4; + + for (int i=0; i<12; ++i, sdata+=4) + reserved[i] = *(int *)sdata; +} + + +Bitmap_MD5_Chunk * External_Shape_BMPs_Store_Chunk::GetMD5Chunk(char const * bname) +{ + List chlst; + parent->lookup_child("BMPMD5ID",chlst); + + for (LIF i_chlst(&chlst); !i_chlst.done(); i_chlst.next()) + { + Bitmap_MD5_Chunk * md5c = (Bitmap_MD5_Chunk *)i_chlst(); + + if (!strcmp(md5c->bmpname,bname)) + if (!(md5c->rifname ? rifname ? strcmp(rifname,md5c->rifname) : *md5c->rifname : rifname ? *rifname : 0) && + !(md5c->shapename ? shapename ? strcmp(shapename,md5c->shapename) : *md5c->shapename : shapename ? *shapename : 0) && + (flags & GBF_SPRITE && md5c->flags & BMD5F_SPRITE || !(flags & GBF_SPRITE) && !(md5c->flags & BMD5F_SPRITE))) + + return md5c; + } + + return 0; +} + +void External_Shape_BMPs_Store_Chunk::CreateMD5Chunk(BMP_Name const & rcbmp, int const * md5id) +{ + Bitmap_MD5_Chunk * md5c = new Bitmap_MD5_Chunk(parent,md5id,rcbmp,rifname,shapename); + md5c->flags = flags & GBF_SPRITE ? BMD5F_SPRITE : BMD5F_0; +} + + +/*************************/ +/* matching images stuff */ +/*************************/ + +// class ImageDescriptor +// --------------------- +ImageDescriptor::ImageDescriptor() +: filename(0) +, rifname(0) +, fixrifname(0) +{ +} + +ImageDescriptor::ImageDescriptor(ImageDescriptor const & id2) +: flags(id2.flags) +, filename(0) +, rifname(0) +, fixrifname(0) +{ + spares[0] = id2.spares[0]; + spares[1] = id2.spares[1]; + spares[2] = id2.spares[2]; + + if (id2.filename) + { + filename = new char [strlen(id2.filename)+1]; + strcpy(filename,id2.filename); + } + if (id2.rifname) + { + rifname = new char [strlen(id2.rifname)+1]; + strcpy(rifname,id2.rifname); + } + if (id2.fixrifname) + { + fixrifname = new char [strlen(id2.fixrifname)+1]; + strcpy(fixrifname,id2.fixrifname); + } +} + +ImageDescriptor::ImageDescriptor(IDscFlags idscf, char const * fname, char const * rname, char const * xname) +: flags(idscf) +, filename(0) +, rifname(0) +, fixrifname(0) +{ + spares[0] = 0; + spares[1] = 0; + spares[2] = 0; + + if (fname) + { + filename = new char [strlen(fname)+1]; + strcpy(filename,fname); + } + if (rname) + { + rifname = new char [strlen(rname)+1]; + strcpy(rifname,rname); + } + if (xname) + { + fixrifname = new char [strlen(xname)+1]; + strcpy(fixrifname,xname); + } +} + +ImageDescriptor::~ImageDescriptor() +{ + if (filename) delete[] filename; + if (rifname) delete[] rifname; + if (fixrifname) delete[] fixrifname; +} + +ImageDescriptor & ImageDescriptor::operator = (ImageDescriptor const & id2) +{ + if (&id2 != this) + { + flags = id2.flags; + spares[0] = id2.spares[0]; + spares[1] = id2.spares[1]; + spares[2] = id2.spares[2]; + + if (filename) + { + delete[] filename; + filename = 0; + } + if (rifname) + { + delete[] rifname; + rifname = 0; + } + if (fixrifname) + { + delete[] fixrifname; + fixrifname = 0; + } + + if (id2.filename) + { + filename = new char [strlen(id2.filename)+1]; + strcpy(filename,id2.filename); + } + if (id2.rifname) + { + rifname = new char [strlen(id2.rifname)+1]; + strcpy(rifname,id2.rifname); + } + if (id2.fixrifname) + { + fixrifname = new char [strlen(id2.fixrifname)+1]; + strcpy(fixrifname,id2.fixrifname); + } + } + return *this; +} + + +// I/O +ImageDescriptor::ImageDescriptor(char const * datablock) +: flags((IDscFlags)(*(int const *)datablock & IDSCF_MASK)) +{ + spares[0] = *(int const *)(datablock+4); + spares[1] = *(int const *)(datablock+8); + spares[2] = *(int const *)(datablock+12); + datablock += 16; + + size_t len = strlen(datablock)+1; + filename = new char[len]; + strcpy(filename,datablock); + datablock += len; + + len = strlen(datablock)+1; + rifname = new char[len]; + strcpy(rifname,datablock); + datablock += len; + + len = strlen(datablock)+1; + fixrifname = new char[len]; + strcpy(fixrifname,datablock); +} + +size_t ImageDescriptor::Size() const +{ + return 16 + + (filename ? strlen(filename) : 0) + + (rifname ? strlen(rifname) : 0) + + (fixrifname ? strlen(fixrifname) : 0) + + 3 + +3&~3; +} + +void ImageDescriptor::WriteData(char * datablock) const +{ + *(int *)datablock = flags; + *(int *)(datablock+4) = spares[0]; + *(int *)(datablock+8) = spares[1]; + *(int *)(datablock+12) = spares[2]; + datablock+=16; + + strcpy(datablock,filename ? filename : ""); + datablock += strlen(datablock)+1; + + strcpy(datablock,rifname ? rifname : ""); + datablock += strlen(datablock)+1; + + strcpy(datablock,fixrifname ? fixrifname : ""); +} + +// operators +BOOL ImageDescriptor::operator == (ImageDescriptor const & id2) const +{ + if (flags!=id2.flags) return FALSE; + if (_stricmp(filename ? filename : "",id2.filename ? id2.filename : "")) return FALSE; + if (_stricmp(rifname ? rifname : "",id2.rifname ? id2.rifname : "")) return FALSE; + if (_stricmp(fixrifname ? fixrifname : "",id2.fixrifname ? id2.fixrifname : "")) return FALSE; + return TRUE; +} + +// class MatchingImages +// -------------------- + +// constructos; +MatchingImages::MatchingImages(ImageDescriptor const & _load, ImageDescriptor const & _insteadof) +: load(_load) +, insteadof(_insteadof) +{ + spares[0] = 0; + spares[1] = 0; + spares[2] = 0; +} + +// I/O +MatchingImages::MatchingImages(char const * datablock) +: load(datablock+12) +, insteadof(datablock+12+load.Size()) +{ + spares[0] = *(int const *)datablock; + spares[1] = *(int const *)(datablock+4); + spares[2] = *(int const *)(datablock+8); +} + +size_t MatchingImages::Size() const +{ + return 12 + load.Size() + insteadof.Size(); +} + +void MatchingImages::WriteData(char * datablock) const +{ + *(int *)datablock = spares[0]; + *(int *)(datablock+4) = spares[1]; + *(int *)(datablock+8) = spares[2]; + + load.WriteData(datablock+12); + insteadof.WriteData(datablock+12+load.Size()); +} + + +// class Matching_Images_Chunk : public Chunk +// ------------------------------------------ +RIF_IMPLEMENT_DYNCREATE("MATCHIMG",Matching_Images_Chunk) + +// I/O +Matching_Images_Chunk::Matching_Images_Chunk(Chunk_With_Children * parent, char const * datablock, size_t size) +: Chunk(parent,"MATCHIMG") +, flags ((MICFlags)(*(int *)(datablock+8) & MICF_MASK)) +{ + char const * datastart = datablock; + + spares[0] = *(int *)datablock; + spares[1] = *(int *)(datablock+4); + + int listsize = *(int *)(datablock+12); + datablock += 16; + + for (;listsize; --listsize) + { + mlist.add_entry_end(datablock); + datablock += mlist.last_entry().Size(); + } + + assert(datastart + size == datablock); +} + +size_t Matching_Images_Chunk::size_chunk() +{ + chunk_size = 28; // 2dw spares, 1dw flags, 1dw list size, 12b header + + for (LIF mlit(&mlist); !mlit.done(); mlit.next()) + { + chunk_size += mlit().Size(); + } + + return chunk_size; +} + +void Matching_Images_Chunk::fill_data_block(char * data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *(int *) data_start = chunk_size; + data_start += 4; + + *(int *)data_start = spares[0]; + *(int *)(data_start+4) = spares[1]; + *(int *)(data_start+8) = flags; + + *(int *)(data_start+12) = mlist.size(); + + data_start += 16; + + for (LIF mlit(&mlist); !mlit.done(); mlit.next()) + { + mlit().WriteData(data_start); + data_start += mlit().Size(); + } +} + +ImageDescriptor const & Matching_Images_Chunk::GetLoadImage(ImageDescriptor const & _insteadof) +{ + for (LIF mlit(&mlist); !mlit.done(); mlit.next()) + { + if (_insteadof == mlit().insteadof) return mlit().load; + } + return _insteadof; +} + +// Bitmap MD5 Chunk +RIF_IMPLEMENT_DYNCREATE("BMPMD5ID",Bitmap_MD5_Chunk) + +Bitmap_MD5_Chunk::Bitmap_MD5_Chunk(Chunk_With_Children * parent, int const * md5id, BMP_Name const & rcbmp, char const * rname, char const * sname) +: Chunk(parent,"BMPMD5ID"), spare(0), flags(BMD5F_0), version_num(rcbmp.version_num) +{ + memcpy(md5_val,md5id,16); + + char const * bname = rcbmp.filename; + if (!bname) bname = ""; + bmpname = new char[strlen(bname)+1]; + strcpy(bmpname,bname); + + if (!rname) rname = ""; + rifname = new char[strlen(rname)+1]; + strcpy(rifname,rname); + + if (!sname) sname = ""; + shapename = new char[strlen(sname)+1]; + strcpy(shapename,sname); +} + +Bitmap_MD5_Chunk::Bitmap_MD5_Chunk(Chunk_With_Children * parent, char const * datablock, size_t) +: Chunk(parent,"BMPMD5ID"), spare(*(int *)datablock), flags((BMPMD5_Flags)(*(int *)(datablock+4) & BMD5F_MASK)), version_num(*(int *)(datablock+8)) +{ + memcpy(md5_val,datablock+12,16); + datablock += 28; + unsigned int const blen = strlen(datablock)+1; + bmpname = new char [blen]; + strcpy(bmpname,datablock); + datablock += blen; + unsigned int const rlen = strlen(datablock)+1; + rifname = new char [rlen]; + strcpy(rifname,datablock); + datablock += rlen; + unsigned int const slen = strlen(datablock)+1; + shapename = new char [slen]; + strcpy(shapename,datablock); +} + +Bitmap_MD5_Chunk::~Bitmap_MD5_Chunk() +{ + delete [] bmpname; + delete [] rifname; + delete [] shapename; +} + +void Bitmap_MD5_Chunk::fill_data_block(char * datastart) +{ + strncpy (datastart, identifier, 8); + datastart += 8; + *((int *) datastart) = chunk_size; + datastart += 4; + + *(int *)datastart = spare; + *(int *)(datastart+4) = flags; + *(int *)(datastart+8) = version_num; + memcpy(datastart+12,md5_val,16); + datastart += 28; + strcpy(datastart,bmpname ? bmpname : ""); + datastart += strlen(datastart)+1; + strcpy(datastart,rifname ? rifname : ""); + datastart += strlen(datastart)+1; + strcpy(datastart,shapename ? shapename : ""); +} + +size_t Bitmap_MD5_Chunk::size_chunk() +{ + return chunk_size = 12+28 + +(bmpname ? strlen(bmpname) : 0) + +(rifname ? strlen(rifname) : 0) + +(shapename ? strlen(shapename) : 0) + +3 +3&~3; +} + + + + diff --git a/3dc/win95/BMPNAMES.HPP b/3dc/win95/BMPNAMES.HPP new file mode 100644 index 0000000..5616b12 --- /dev/null +++ b/3dc/win95/BMPNAMES.HPP @@ -0,0 +1,727 @@ +#ifndef _bmpnames_hpp_ +#define _bmpnames_hpp_ + +#include "chunk.hpp" + +// for assert +#if engine + +#define UseLocalAssert No +#include "ourasert.h" +#define assert(x) GLOBALASSERT(x) + +#else + +#if cencon +#include "ccassert.h" +#else +#include +#endif + +#endif + +enum BMPN_Flags +{ + ChunkBMPFlag_Null = 0x00000000, // all flags reset + ChunkBMPFlag_NotInShape = 0x00000001, // not a texture map, maybe a sprite or hud graphic + ChunkBMPFlag_UsesTransparency = 0x00000002, // transparency_colour defines invisible pixels + ChunkBMPFlag_RequireGameMipMaps = 0x00000004, // mip maps are required for the game + ChunkBMPFlag_RequireToolsMipMaps = 0x00000008, // mip maps are required for the interface engine + ChunkBMPFlag_MipMapsExist = 0x00000010, // internal mip maps are up to date + ChunkBMPFlag_NotLit = 0x00000020, // not light sourced (eg. hud, iflag_nolight), so do not put darker colours into palette + ChunkBMPFlag_FixedPalette = 0x00000040, // will be quantized once only to a fixed sub-palette of each main palette + ChunkBMPFlag_Quantized = 0x00000080, // .PG0 exists which corresponds to the palette + // See below 0x00000100 + ChunkBMPFlag_MipMapsQuantized = 0x00000200, // .PG1-.PG6 exist which correspond to the palette and are mip maps + ChunkBMPFlag_PP0Exists = 0x00000400, // internal .PP0 exists + ChunkBMPFlag_NotInPC = 0x00000800, // for reduced memory, reduced features on some platforms + ChunkBMPFlag_NotInSaturn = 0x00001000, // for reduced memory, reduced features on some platforms + ChunkBMPFlag_NotInPlaystation = 0x00002000, // for reduced memory, reduced features on some platforms + ChunkBMPFlag_BM0Exists = 0x00004000, // 256 colour palettized texture for hw accelerators exists + ChunkBMPFlag_BMnsExist = 0x00008000, // mip mapped versions of 256 colour palettized texture exist + ChunkBMP_Dither = 0x00070000, // + ChunkBMP_DitherFloyd = 0x00010000, // + ChunkBMP_DitherFloydDamp1 = 0x00020000, // + ChunkBMP_DitherFloydDamp2 = 0x00030000, // 3 bits to control the type of error diffusion (if any) + ChunkBMP_DitherJarvis = 0x00040000, // + ChunkBMP_DitherJarvisDamp1 = 0x00050000, // + ChunkBMP_DitherJarvisDamp2 = 0x00060000, // + ChunkBMPFlag_RqQuantLUV = 0x00080000, // Remap in LUV colour space + ChunkBMPFlag_HistogramExists = 0x00100000, // used by cencon in palette generation - help by outputting .HST files + ChunkBMPFlag_HistogramV2Exists = 0x00200000, // used by cencon in palette generation - help by outputting .HS2 files (non-lit histograms for lit bitmaps with conceptual tlt palette) + ChunkBMPFlag_CopiedGenMipMaps = 0x00400000, // mip map HW generic textures have been copied to final dest + ChunkBMPFlag_CopiedGenBaseTex = 0x00800000, // base (non-mip) HW generic textures have been copied to final dest + + ChunkBMPFlag_IFF = 0x01000000, // a very important flag indeed: + // when this flag is set, the file is an IFF file and the filename stores a + // full relative path from the 'textures-root' directory for the project + // all other flags are complete bollocks when this flag is set + // (except for the NotIn.... flags) + // all this data will be in the file itself (transparency data anyway,,,) + // the file can be updated without the use of cencon, so for this reason + // I'll store the widths and heights where the transparent colour used + // to be. I'll also provide member-access functions to access this data + // which will check the flag is correct + +// This flag will be set on newer RIF files, because older ones will have priorities of 0 which is not ideal! +// When a chunk with these flag not set is detected, default values are filled in and the old values are not used. + ChunkBMPFlag_PriorityAndTransparencyAreValid = 0x00000100 + +}; + +//I have removed transparency from the default flags at the request of the artists + +// default flags for new bitmaps +#define DEFAULT_BMPN_FLAGS ((BMPN_Flags) ( \ + ChunkBMPFlag_PriorityAndTransparencyAreValid | \ + ChunkBMPFlag_RequireToolsMipMaps | /* test */ \ + ChunkBMPFlag_RequireGameMipMaps )) + +// user flags that should correspond for corresponding bitmaps +#define COPY_BMPN_FLAGS ((BMPN_Flags) ( \ + ChunkBMPFlag_NotInShape | \ + ChunkBMPFlag_UsesTransparency | \ + ChunkBMPFlag_RequireToolsMipMaps | \ + ChunkBMPFlag_RequireGameMipMaps | \ + ChunkBMPFlag_MipMapsExist | \ + ChunkBMPFlag_BMnsExist | \ + ChunkBMPFlag_BM0Exists | \ + ChunkBMPFlag_PP0Exists | \ + ChunkBMPFlag_NotLit | \ + ChunkBMPFlag_FixedPalette | \ + ChunkBMPFlag_NotInPC | \ + ChunkBMPFlag_NotInSaturn | \ + ChunkBMPFlag_NotInPlaystation | \ + ChunkBMP_Dither | \ + ChunkBMPFlag_RqQuantLUV | \ + ChunkBMPFlag_IFF)) + +// flags that when changed require requantizing +#define CHECKMODIFY_BMPN_FLAGS ((BMPN_Flags) ( \ + ChunkBMPFlag_UsesTransparency | \ + ChunkBMPFlag_FixedPalette /* not sure */ | \ + ChunkBMP_Dither | \ + ChunkBMPFlag_RqQuantLUV )) + +// flags to reset if a bitmap needs requantizing +#define QUANTIZED_BMPN_FLAGS ((BMPN_Flags) ( \ + ChunkBMPFlag_Quantized | \ + ChunkBMPFlag_MipMapsQuantized )) + +#define COMPLETED_BMPN_FLAGS ((BMPN_Flags) ( \ + ChunkBMPFlag_CopiedGenBaseTex | \ + ChunkBMPFlag_CopiedGenMipMaps | \ + QUANTIZED_BMPN_FLAGS )) + +#define DEFAULT_BMPN_PRIORITY 6 + + +extern void Palette_Outdated(Chunk_With_Children * parent); // decalred here, defined in chunkpal to avoid extra compiler dependencies +extern void FixedPalette_Outdated(Chunk_With_Children * parent); // decalred here, defined in chunkpal to avoid extra compiler dependencies +extern BOOL IsFixedPalette(Chunk_With_Children * parent); + + +class BMP_Name +{ +public: + + BMP_Name(const char * fname, int const gbnc_version); + ~BMP_Name(); + + BMP_Name(const BMP_Name &); + const BMP_Name & operator=(const BMP_Name &); + + char * filename; + + BMPN_Flags flags; + int index; + int version_num; + int enum_id; + #define BMPNAME_PARENT_VER_SHIFT 8 + // version num contains bmp version num (incremental on update) + // and Global_BMP_Name_Chunk version (at the time of creation) num shifted up + // This is so that if a bitmap is removed and then added, its + // version num will still be greater than that of the removed version + #define BMPNAME_VERSION_NUM_MASK 0x000fffff + #define BMPNAME_ENUMID_SHIFT 20 + // the top 12 bits of the previously spare data item (data1) + // contain an enumeration constant (max 4095) + // and the bottom 20 bits are available for version numbers + // a bit cramped and not ideal, but we are running out of storage space + // there are still two bytes free(0) in the priority data + + #define MAX_PC_PRIORITY 0xff + #define MAX_PSX_PRIORITY 0xff + inline int get_pc_priority(void) const { return priority & 0xff; } + inline int get_psx_priority(void) const { return priority >> 8 & 0xff; } + inline void set_pc_priority(int const p) { priority &= ~0xff; priority |= p & 0xff; } + inline void set_psx_priority(int const p) { priority &= ~0xff00; priority |= (p & 0xff) << 8; } + + friend BOOL operator==(const BMP_Name &o1, const BMP_Name &o2); + friend BOOL operator!=(const BMP_Name &o1, const BMP_Name &o2); + + BMP_Name() + : filename(0), flags((BMPN_Flags)DEFAULT_BMPN_FLAGS), index(0), version_num (0), priority (DEFAULT_BMPN_PRIORITY), transparency_colour_union(0) {} + + void Validate(void); + + #if cencon + int const * md5val; // space to put a pointer + + void DeleteAssociatedFiles() const; + void DeleteAssociatedMipFiles() const; + // changes the filename member, returns FALSE on failure + BOOL Rename(char const * newname); + + // use these to prevent DeleteAssociatedMipFiles & DeleteAssociatedFiles + // from deleting specific files + static void PreventDeleteFile(char const * pszFileName); + static void ReallowDeleteFile(char const * pszFileName); + private: + static List ms_listFilesCantDelete; + static void DeleteFileProt(char const * pszFileName); + public: + #endif + + unsigned GetTranspRedVal() const; + unsigned GetTranspGreenVal() const; + unsigned GetTranspBlueVal() const; + unsigned GetWidth() const; + unsigned GetHeight() const; + + void SetTranspRedVal(unsigned); + void SetTranspGreenVal(unsigned); + void SetTranspBlueVal(unsigned); + void SetWidth(unsigned); + void SetHeight(unsigned); + + // copy all data + void CopyUnionDataFrom(BMP_Name const & rBmp); + bool DifferentTransparencyColour(BMP_Name const & rBmp) const; + + enum + { + MAXVAL_RGB = 0xff, + MAXVAL_WH = 0xffff + }; + +private: + + int priority; // contains pc palettized mode palette generating priority as well as 16/256 colour priority for attahced palettes + + enum + { + SHIFT_R = 22, + SHIFT_G = 12, + SHIFT_B = 2, + + SHIFT_W = 0, + SHIFT_H = 16 + }; + + unsigned transparency_colour_union; // == r<<22 + g<<12 + b << 2 ; r,g,b <- [0..255], but don't assume this'll always be the case + // or H<<16 + W + + BMP_Name(const char * fname); + // initial part of constructor from buffer. + // GBNC and BLSC loaders find the rest of the data + // and put it into the BMP_Name object constructed with this constructor + + friend class Chunk_With_BMPs; + friend class BMP_Flags; +}; + +// functions to access the union transparency_colour_union which isn't a real C/C++ union +// they will check that you're performing valid accesses (ie. using the right part of the union) +// if you're a friend class, please ensure you use these access functions or know what you're doing +inline unsigned BMP_Name::GetTranspRedVal() const +{ + assert(!(flags & ChunkBMPFlag_IFF)); // not available for IFF files - it's in the file + return transparency_colour_union >> SHIFT_R & MAXVAL_RGB; +} + +inline unsigned BMP_Name::GetTranspGreenVal() const +{ + assert(!(flags & ChunkBMPFlag_IFF)); // not available for IFF files - it's in the file + return transparency_colour_union >> SHIFT_G & MAXVAL_RGB; +} + +inline unsigned BMP_Name::GetTranspBlueVal() const +{ + assert(!(flags & ChunkBMPFlag_IFF)); // not available for IFF files - it's in the file + return transparency_colour_union >> SHIFT_B & MAXVAL_RGB; +} + +inline unsigned BMP_Name::GetWidth() const +{ + assert(flags & ChunkBMPFlag_IFF); // only available for IFF files - required since they can be modified externally + return transparency_colour_union >> SHIFT_W & MAXVAL_WH; +} + +inline unsigned BMP_Name::GetHeight() const +{ + assert(flags & ChunkBMPFlag_IFF); // only available for IFF files - required since they can be modified externally + return transparency_colour_union >> SHIFT_H & MAXVAL_WH; +} + +inline void BMP_Name::SetTranspRedVal(unsigned v) +{ + assert(!(flags & ChunkBMPFlag_IFF)); // not available for IFF files - it's in the file + assert(v<=MAXVAL_RGB); // sensible value + + transparency_colour_union &= ~(MAXVAL_RGB << SHIFT_R); + transparency_colour_union |= v << SHIFT_R; +} + +inline void BMP_Name::SetTranspGreenVal(unsigned v) +{ + assert(!(flags & ChunkBMPFlag_IFF)); // not available for IFF files - it's in the file + assert(v<=MAXVAL_RGB); // sensible value + + transparency_colour_union &= ~(MAXVAL_RGB << SHIFT_G); + transparency_colour_union |= v << SHIFT_G; +} + +inline void BMP_Name::SetTranspBlueVal(unsigned v) +{ + assert(!(flags & ChunkBMPFlag_IFF)); // not available for IFF files - it's in the file + assert(v<=MAXVAL_RGB); // sensible value + + transparency_colour_union &= ~(MAXVAL_RGB << SHIFT_B); + transparency_colour_union |= v << SHIFT_B; +} + +inline void BMP_Name::SetWidth(unsigned v) +{ + assert(flags & ChunkBMPFlag_IFF); // only available for IFF files - required since they can be modified externally + assert(v<=MAXVAL_WH); // sensible value + + transparency_colour_union &= ~(MAXVAL_WH << SHIFT_W); + transparency_colour_union |= v << SHIFT_W; +} + +inline void BMP_Name::SetHeight(unsigned v) +{ + assert(flags & ChunkBMPFlag_IFF); // only available for IFF files - required since they can be modified externally + assert(v<=MAXVAL_WH); // sensible value + + transparency_colour_union &= ~(MAXVAL_WH << SHIFT_H); + transparency_colour_union |= v << SHIFT_H; +} + +inline void BMP_Name::CopyUnionDataFrom(BMP_Name const & rBmp) +{ + assert((flags & ChunkBMPFlag_IFF)==(rBmp.flags & ChunkBMPFlag_IFF)); + + transparency_colour_union = rBmp.transparency_colour_union; +} + +inline bool BMP_Name::DifferentTransparencyColour(BMP_Name const & rBmp) const +{ + assert(!(flags & ChunkBMPFlag_IFF) && !(rBmp.flags & ChunkBMPFlag_IFF)); + + return transparency_colour_union != rBmp.transparency_colour_union; +} + + +/////////////////////////////////////////////// + +class BMP_Names_ExtraData; +class Bitmap_MD5_Chunk; + +class Chunk_With_BMPs : public Chunk +{ +public: + + int max_index; + + List bmps; + + virtual int get_version_num(void); + virtual void set_version_num(int); + virtual void inc_version_num(void); + virtual BMP_Names_ExtraData * GetExtendedData(void); + + virtual int const * GetMD5Val(BMP_Name const & rcbmp); + virtual void SetMD5Val(BMP_Name const & rcbmp, int const * md5id); + virtual void RemoveMD5Val(char const * bname); + + friend class BMP_Group; // for cencon + friend class BMP_Info; // for cencon + +protected: + virtual Bitmap_MD5_Chunk * GetMD5Chunk(char const * bname) = 0; + virtual void CreateMD5Chunk(BMP_Name const & rcbmp, int const * md5id) = 0; + + virtual size_t size_chunk (); + virtual void fill_data_block (char * data_start); + + Chunk_With_BMPs (Chunk_With_Children * parent, const char * const ident) : Chunk(parent,ident), max_index(0) {} + Chunk_With_BMPs (Chunk_With_Children * parent, const char * const ident, const char * sdata, size_t ssize); + +}; + + +class Global_BMP_Name_Chunk : public Chunk_With_BMPs +{ +public: + + Global_BMP_Name_Chunk (Chunk_With_Children * parent) + : Chunk_With_BMPs (parent, "BMPNAMES") + {} + // constructor from buffer + Global_BMP_Name_Chunk (Chunk_With_Children * parent, const char * sdata, size_t ssize) + : Chunk_With_BMPs (parent, "BMPNAMES", sdata, ssize) {} +private: + virtual Bitmap_MD5_Chunk * GetMD5Chunk(char const * bname); + virtual void CreateMD5Chunk(BMP_Name const & rcbmp, int const * md5id); + + friend class Environment_Data_Chunk; + + + + +}; + + +class Bitmap_List_Store_Chunk : public Chunk_With_BMPs +{ +public: + + Bitmap_List_Store_Chunk (Chunk_With_Children * parent) + : Chunk_With_BMPs (parent, "BMPLSTST") + {} + + // constructor from buffer + // not private, so that it is easy to get to + Bitmap_List_Store_Chunk (Chunk_With_Children * parent, const char * sdata, size_t ssize) + : Chunk_With_BMPs (parent, "BMPLSTST", sdata, ssize) {} + +private: + virtual Bitmap_MD5_Chunk * GetMD5Chunk(char const * bname); + virtual void CreateMD5Chunk(BMP_Name const & rcbmp, int const * md5id); + + friend class Shape_External_File_Chunk; + +}; + + + +class BMP_Names_Version_Chunk : public Chunk +{ +public: + + BMP_Names_Version_Chunk (Chunk_With_Children * parent) + : Chunk (parent, "BMNAMVER"), version_num (0) + {} + // constructor from buffer + BMP_Names_Version_Chunk (Chunk_With_Children * parent, const char * sdata, size_t /*ssize*/) + : Chunk (parent, "BMNAMVER"), version_num(*(int *)sdata) + {} + + virtual size_t size_chunk (); + + virtual void fill_data_block (char * data_start); + +private: + + int version_num; + + friend class Environment_Data_Chunk; + friend class Chunk_With_BMPs; + friend class Shape_External_File_Chunk; + friend class Sprite_Header_Chunk; + + +}; + +enum GlobalBMPFlags +{ + GBF_FIXEDPALETTE = 0x00000001, + GBF_SPRITE = 0x00000002, + GBF_HISTOGRAMEXISTS = 0x00000004, + GBF_HISTOGRAMV2EXISTS = 0x00000008, + + GBF_NONE = 0, + + // IMPORTANT + // since enums are not guaranteed to assume any particular + // storage class, code compiled on different compilers or + // with different settings may result in enums to be written + // to the data block as a char and read back in as an int, + // with the three most significant bytes containing junk. + // THIS MASK MUST BE KEPT UP TO DATE AS THE ENUM IS EXTENDED; + // ALSO ENSURE THAT NEW FILES LOADED INTO OLD SOFTWARE WILL + // NOT HAVE THEIR ENUM VALUE OVER-MASKED; THE MASK IS ONLY + // HERE TO ATTEMPT TO REMOVE PROBLEMS FROM FILES MADE + // PRIOR TO ITS INTRODUCTION + GBF_MASK = 0x000000ff +}; + +class BMP_Names_ExtraData +{ +public: + GlobalBMPFlags flags; +protected: + int reserved[12]; +}; + + +class BMP_Names_ExtraData_Chunk : public Chunk, public BMP_Names_ExtraData +{ +public: + + BMP_Names_ExtraData_Chunk (Chunk_With_Children * parent) + : Chunk (parent, "BMNAMEXT") + { + for (int i=0; i<12; ++i) reserved[i] = 0; + flags = GBF_NONE; + } + + // constructor from buffer + BMP_Names_ExtraData_Chunk (Chunk_With_Children * parent, const char * sdata, size_t /*ssize*/) + : Chunk (parent, "BMNAMEXT") + { + flags = (GlobalBMPFlags)(*(int *)sdata & GBF_MASK); + sdata += 4; + for (int i=0; i<12; ++i, sdata+=4) reserved[i] = *(int *)sdata; + } + +private: + + virtual size_t size_chunk (); + + virtual void fill_data_block (char * data_start); + + friend class Environment_Data_Chunk; + friend class Shape_External_File_Chunk; + friend class Sprite_Header_Chunk; + + +}; + + +class External_Shape_BMPs_Store_Chunk : public Chunk_With_BMPs, protected BMP_Names_ExtraData +{ +public: + char * rifname; // to match one in RIF_Child_Chunk + char * shapename; // matches rif name of original shape + + External_Shape_BMPs_Store_Chunk (Chunk_With_Children * parent, char const * rifn, char const * shapen); + External_Shape_BMPs_Store_Chunk (Chunk_With_Children * parent, const char * sdata, size_t ssize); + ~External_Shape_BMPs_Store_Chunk(); + + virtual int get_version_num(void) { return version_num; } + virtual void set_version_num(int v) { version_num = v; } + virtual void inc_version_num(void) { ++version_num; } + virtual BMP_Names_ExtraData * GetExtendedData(void) { return this; } + +private: + virtual Bitmap_MD5_Chunk * GetMD5Chunk(char const * bname); + virtual void CreateMD5Chunk(BMP_Name const & rcbmp, int const * md5id); + + int version_num; + + virtual size_t size_chunk() + { + return chunk_size = Chunk_With_BMPs::size_chunk() + ((rifname ? strlen(rifname) : 0) + (shapename ? strlen(shapename) : 0)+2 +3&~3) + 56; + } + + virtual void fill_data_block(char * data_start); + + + + friend class Environment_Game_Mode_Chunk; +}; + + +// for dealing with matching images + +enum IDscFlags +{ + IDSCF_SPRITE = 0x00000001, // image is in a sprite + IDSCF_INCLUDED = 0x00000002, // image is from another rif file + IDSCF_FIXEDPALETTE = 0x00000004, // image has pgms for fixed palette + IDSCF_SUBSHAPE = 0x00000008, // image for shape included from another file + + IDSCF_0 = 0, + + // IMPORTANT + // since enums are not guaranteed to assume any particular + // storage class, code compiled on different compilers or + // with different settings may result in enums to be written + // to the data block as a char and read back in as an int, + // with the three most significant bytes containing junk. + // THIS MASK MUST BE KEPT UP TO DATE AS THE ENUM IS EXTENDED; + // ALSO ENSURE THAT NEW FILES LOADED INTO OLD SOFTWARE WILL + // NOT HAVE THEIR ENUM VALUE OVER-MASKED; THE MASK IS ONLY + // HERE TO ATTEMPT TO REMOVE PROBLEMS FROM FILES MADE + // PRIOR TO ITS INTRODUCTION + IDSCF_MASK = 0x000000ff +}; + +class ImageDescriptor +{ +public: + // constructos; + ImageDescriptor(); + ImageDescriptor(ImageDescriptor const &); + ImageDescriptor(IDscFlags, char const * fname, char const * rname = 0, char const * xname = 0); + ~ImageDescriptor(); + ImageDescriptor & operator = (ImageDescriptor const &); + + // operators + BOOL operator == (ImageDescriptor const &) const; + inline BOOL operator != (ImageDescriptor const & id2) const + { return ! operator == (id2); } + + // members + IDscFlags flags; + + char * filename; // name.bmp + char * rifname; // only if IDSCF_INCLUDED is set + char * fixrifname; // only if IDSCF_FIXEDPALETTE is set + +private: + // I/O + ImageDescriptor(char const * datablock); + size_t Size() const; + void WriteData(char * datablock) const; + + friend class MatchingImages; + + int spares[3]; +}; + +class MatchingImages +{ +public: + // constructos; + MatchingImages() {} + MatchingImages(ImageDescriptor const & _load, ImageDescriptor const & _insteadof); + + // operators + inline BOOL operator == (MatchingImages const & m2) + { return load == m2.load && insteadof == m2.insteadof; } + inline BOOL operator != (MatchingImages const & m2) + { return load != m2.load || insteadof != m2.insteadof; } + + // members + ImageDescriptor load; + ImageDescriptor insteadof; + +private: + + // I/O + MatchingImages(char const * datablock); + size_t Size() const; + void WriteData(char * datablock) const; + + friend class Matching_Images_Chunk; + + int spares[3]; + +}; + +enum MICFlags +{ + MICF_0 = 0, + + MICF_FIXEDPALETTE = 0x00000001, + + // IMPORTANT + // since enums are not guaranteed to assume any particular + // storage class, code compiled on different compilers or + // with different settings may result in enums to be written + // to the data block as a char and read back in as an int, + // with the three most significant bytes containing junk. + // THIS MASK MUST BE KEPT UP TO DATE AS THE ENUM IS EXTENDED; + // ALSO ENSURE THAT NEW FILES LOADED INTO OLD SOFTWARE WILL + // NOT HAVE THEIR ENUM VALUE OVER-MASKED; THE MASK IS ONLY + // HERE TO ATTEMPT TO REMOVE PROBLEMS FROM FILES MADE + // PRIOR TO ITS INTRODUCTION + MICF_MASK = 0x000000ff +}; + +class Matching_Images_Chunk : public Chunk +{ +public: + // constructors + Matching_Images_Chunk(Chunk_With_Children * parent) : Chunk(parent,"MATCHIMG"), flags(MICF_0) + { spares[0]=0; spares[1]=0; } // empty list + // I/O + Matching_Images_Chunk(Chunk_With_Children * parent, char const * datablock, size_t); + // members + List mlist; + + MICFlags flags; + + // methods + ImageDescriptor const & GetLoadImage(ImageDescriptor const &); + +private: + int spares[2]; + + + virtual size_t size_chunk(); + virtual void fill_data_block(char * data_start); + + friend class Environment_Data_Chunk; + friend class Environment_Game_Mode_Chunk; +}; + +enum BMPMD5_Flags +{ + BMD5F_0 = 0, + + BMD5F_SPRITE = 0x00000001, + + // IMPORTANT + // since enums are not guaranteed to assume any particular + // storage class, code compiled on different compilers or + // with different settings may result in enums to be written + // to the data block as a char and read back in as an int, + // with the three most significant bytes containing junk. + // THIS MASK MUST BE KEPT UP TO DATE AS THE ENUM IS EXTENDED; + // ALSO ENSURE THAT NEW FILES LOADED INTO OLD SOFTWARE WILL + // NOT HAVE THEIR ENUM VALUE OVER-MASKED; THE MASK IS ONLY + // HERE TO ATTEMPT TO REMOVE PROBLEMS FROM FILES MADE + // PRIOR TO ITS INTRODUCTION + BMD5F_MASK = 0x000000ff +}; + +class Bitmap_MD5_Chunk : public Chunk +{ +public : + Bitmap_MD5_Chunk(Chunk_With_Children * parent, char const * datablock, size_t); +private: + Bitmap_MD5_Chunk(Chunk_With_Children * parent, int const * md5id, BMP_Name const & rcbmp, char const * rname = 0, char const * sname = 0); + ~Bitmap_MD5_Chunk(); + int md5_val[4]; + char * bmpname; + char * rifname; + char * shapename; + BMPMD5_Flags flags; + int version_num; + + int spare; + + virtual size_t size_chunk(); + virtual void fill_data_block(char * data_start); + + // your parents are your friends + friend class Environment_Data_Chunk; + friend class Environment_Game_Mode_Chunk; + friend class Shape_External_File_Chunk; + friend class Sprite_Header_Chunk; + // some of your siblings are friends as well + friend class Chunk_With_BMPs; + friend class Global_BMP_Name_Chunk; + friend class Bitmap_List_Store_Chunk; + friend class External_Shape_BMPs_Store_Chunk; + friend class RIF_Child_Chunk; +}; + + + +#endif \ No newline at end of file diff --git a/3dc/win95/CD_player.c b/3dc/win95/CD_player.c new file mode 100644 index 0000000..f6e2861 --- /dev/null +++ b/3dc/win95/CD_player.c @@ -0,0 +1,602 @@ +#include "3dc.h" +#include "inline.h" +#include "psndplat.h" +#include "cd_player.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +/* KJL 12:40:35 07/05/98 - This is code derived from Patrick's original stuff & +moved into it's own file. */ + +/* Patrick 10/6/97 ------------------------------------------------------------- + CDDA Support + ----------------------------------------------------------------------------*/ +#define NO_DEVICE -1 +int cdDeviceID = NO_DEVICE; +int cdAuxDeviceID = NO_DEVICE; + +/* Patrick 9/6/97 ------------------------------------------------------------- + ---------------------------------------------------------------------------- + CDDA Support + ----------------------------------------------------------------------------- + -----------------------------------------------------------------------------*/ +static int CDDASwitchedOn = 0; +static int CDDAIsInitialised = 0; +static int CDDAVolume = CDDA_VOLUME_DEFAULT; +CDOPERATIONSTATES CDDAState; + +static DWORD PreGameCDVolume;//windows cd volume before the game started + +static CDTRACKID TrackBeingPlayed; +static enum CDCOMMANDID LastCommandGiven; + +extern HWND hWndMain; + +int CDPlayerVolume; // volume control from menus + +int CDTrackMax=-1; //highest track number on cd + +void CDDA_Start(void) +{ + CDDAVolume = CDDA_VOLUME_DEFAULT; + CDPlayerVolume = CDDAVolume; + CDDAState = CDOp_Idle; + CDDAIsInitialised = 0; + if(PlatStartCDDA()!=SOUND_PLATFORMERROR) + { + CDDAIsInitialised = 1; + CDDA_SwitchOn(); + CDDA_ChangeVolume(CDDAVolume); /* init the volume */ + CDDA_CheckNumberOfTracks(); + } + LastCommandGiven = CDCOMMANDID_Start; +} + +void CDDA_End(void) +{ + if(!CDDAIsInitialised) return; + + CDDA_Stop(); + PlatChangeCDDAVolume(CDDA_VOLUME_RESTOREPREGAMEVALUE); + PlatEndCDDA(); + CDDA_SwitchOff(); + CDDAIsInitialised = 0; + + LastCommandGiven = CDCOMMANDID_End; +} + +void CDDA_Management(void) +{ + if(!CDDASwitchedOn) return; /* CDDA is off */ + if(CDDAState==CDOp_Playing) return; /* already playing */ + PlatCDDAManagement(); +} + +void CDDA_Play(int CDDATrack) +{ + int ok; + + if(!CDDASwitchedOn) return; /* CDDA is off */ + if(CDDAState==CDOp_Playing) return; /* already playing */ + if((CDDATrack<=0)||(CDDATrack>=CDTrackMax)) return; /* no such track */ + + ok = PlatPlayCDDA((int)CDDATrack); + if(ok!=SOUND_PLATFORMERROR) + { + CDDAState=CDOp_Playing; + LastCommandGiven = CDCOMMANDID_Play; + TrackBeingPlayed = CDDATrack; + } +} +void CDDA_PlayLoop(int CDDATrack) +{ + int ok; + + if(!CDDASwitchedOn) return; /* CDDA is off */ + if(CDDAState==CDOp_Playing) return; /* already playing */ + if((CDDATrack<=0)||(CDDATrack>=CDTrackMax)) return; /* no such track */ + + ok = PlatPlayCDDA((int)CDDATrack); + if(ok!=SOUND_PLATFORMERROR) + { + CDDAState=CDOp_Playing; + LastCommandGiven = CDCOMMANDID_PlayLoop; + TrackBeingPlayed = CDDATrack; + } +} + +extern void CheckCDVolume(void) +{ + if (CDDAVolume != CDPlayerVolume) + { + CDDA_ChangeVolume(CDPlayerVolume); + } +} +void CDDA_ChangeVolume(int volume) +{ + if(!CDDASwitchedOn) return; /* CDDA is off */ + if(volumeCDDA_VOLUME_MAX) return; + + if(CDDA_IsOn()) + { + if(PlatChangeCDDAVolume(volume)) + { + CDDAVolume=volume; + CDPlayerVolume = volume; + LastCommandGiven = CDCOMMANDID_ChangeVolume; + } + } +} + +int CDDA_GetCurrentVolumeSetting(void) +{ + return CDDAVolume; +} + +void CDDA_Stop() +{ + int ok; + if(!CDDASwitchedOn) return; /* CDDA is off */ + if(CDDAState!=CDOp_Playing) return; /* nothing playing */ + ok = PlatStopCDDA(); + CDDAState=CDOp_Idle; + LastCommandGiven = CDCOMMANDID_Stop; +} + +void CDDA_SwitchOn() +{ + LOCALASSERT(!CDDA_IsPlaying()); + if(CDDAIsInitialised) CDDASwitchedOn = 1; +} + +void CDDA_SwitchOff() +{ + if(!CDDASwitchedOn) return; /* CDDA is off already */ + if(CDDA_IsPlaying()) CDDA_Stop(); + CDDASwitchedOn = 0; +} + +int CDDA_IsOn() +{ + return CDDASwitchedOn; +} + +int CDDA_IsPlaying() +{ + if(CDDAState==CDOp_Playing) + { + LOCALASSERT(CDDASwitchedOn); + return 1; + } + return 0; +} + +int CDDA_CheckNumberOfTracks() +{ + int numTracks=0; + + if(CDDA_IsOn()) + { + PlatGetNumberOfCDTracks(&numTracks); + + //if there is only one track , then it probably can't be used anyway + if(numTracks==1) numTracks=0; + + //store the maximum allowed track number + CDTrackMax=numTracks; + } + return numTracks; +} + + + +/* win95 specific */ + +int PlatStartCDDA(void) +{ + static void PlatGetCDDAVolumeControl(void); + DWORD dwReturn; + MCI_OPEN_PARMS mciOpenParms; + + /* Initialise device handles */ + cdDeviceID = NO_DEVICE; + cdAuxDeviceID = NO_DEVICE; + + /* try to open mci cd-audio device */ + mciOpenParms.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_CD_AUDIO; + dwReturn = mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID,(DWORD)(LPVOID)&mciOpenParms); + if(dwReturn) + { + /* error */ + cdDeviceID = NO_DEVICE; + return SOUND_PLATFORMERROR; + } + cdDeviceID = mciOpenParms.wDeviceID; + + /* now try to get the cd volume control, by obtaining the auxiliary device id for + the cd-audio player*/ + PlatGetCDDAVolumeControl(); + return 0; +} + +/* this is a support function for PlatStartCDDA() */ +#if 0 +static void PlatGetCDDAVolumeControl(void) +{ + MMRESULT mmres; + unsigned int numAuxDevs,i; + + numAuxDevs = auxGetNumDevs(); + /* search the auxilary device list for the cd player */ + for(i=0;i VOLUME_CDDA_MAXPLAT) channelVolume = VOLUME_CDDA_MAXPLAT; + + /* set left and right channels (if there is only one channel, + should still work ok)*/ + newVolume = channelVolume|(channelVolume<<16); + } + PlatGetCDDAVolumeControl(); + + mmres = auxSetVolume((UINT)cdAuxDeviceID,(DWORD)newVolume); + if(mmres==MMSYSERR_NOERROR) return 1; + else return SOUND_PLATFORMERROR; +} +#else +int PlatChangeCDDAVolume(int volume) +{ + MMRESULT mmres; + unsigned int newVolume; + int i; + int numDev = mixerGetNumDevs(); + + /* check the cdDeviceId */ + if(cdDeviceID==NO_DEVICE) return SOUND_PLATFORMERROR; + + //go through the mixer devices searching for one that can deal with the cd volume + for(i=0;icontrol.Bounds.dwMaximum) newVolume=control.Bounds.dwMaximum; + } + //fill in the volume in the control details structure + detailValue.dwValue=newVolume; + + + mmres = mixerSetControlDetails(handle,&details,MIXER_SETCONTROLDETAILSF_VALUE); + mixerClose(handle); + + if(mmres==MMSYSERR_NOERROR) return 1; + else return SOUND_PLATFORMERROR; + + } + } + + + mixerClose(handle); + } + + } + + return SOUND_PLATFORMERROR; +} + +#endif + + + + +void PlatCDDAManagement(void) +{ + /* does nothing for Win95: use call back instead */ +} + +void PlatCDDAManagementCallBack(WPARAM flags, LONG deviceId) +{ + extern CDOPERATIONSTATES CDDAState; + + /* check the cdDeviceId */ + if(cdDeviceID==NO_DEVICE) return; + /* compare with the passed device id */ + if((UINT)deviceId!=(UINT)cdDeviceID) return; + + if(flags&MCI_NOTIFY_SUCCESSFUL) + { + CDDAState = CDOp_Idle; + //NewOnScreenMessage("CD COMMAND RETURNED WITH SUCCESSFUL"); + /* Play it again, sam */ + if (LastCommandGiven == CDCOMMANDID_PlayLoop) + { + CDDA_PlayLoop(TrackBeingPlayed); + } + } + else if(flags&MCI_NOTIFY_FAILURE) + { + /* error while playing: abnormal termination */ + //NewOnScreenMessage("CD COMMAND FAILED"); + CDDAState = CDOp_Idle; + } + else if(flags&MCI_NOTIFY_SUPERSEDED) + { + //NewOnScreenMessage("CD COMMAND SUPERSEDED"); + } + else if(flags&MCI_NOTIFY_ABORTED) + { + /* aborted or superceeded: try and stop the device */ + //NewOnScreenMessage("CD COMMAND ABORTED(?)"); + // CDDA_Stop(); + } + else + { + //NewOnScreenMessage("CD COMMAND RETURNED WITH UNKNOWN MESSAGE"); + } +} diff --git a/3dc/win95/CD_player.h b/3dc/win95/CD_player.h new file mode 100644 index 0000000..70e8a2e --- /dev/null +++ b/3dc/win95/CD_player.h @@ -0,0 +1,110 @@ +/* KJL 12:40:35 07/05/98 - This is code derived from Patrick's original stuff & +moved into it's own file. */ + + +/* Patrick 10/6/97 -------------------------------------------------------------- + SUPPORT FOR CDDA SYSTEM + -----------------------------------------------------------------------------*/ + +/* Patrick 10/6/97 -------------------------------------------------------------- + Some Volume defines + -----------------------------------------------------------------------------*/ +#define CDDA_VOLUME_MAX (127) +#define CDDA_VOLUME_MIN (0) +#define CDDA_VOLUME_DEFAULT (127) +#define CDDA_VOLUME_RESTOREPREGAMEVALUE (-100) + +/* Patrick 10/6/97 -------------------------------------------------------------- + Enumeration of CD player states + -----------------------------------------------------------------------------*/ +typedef enum cdoperationstates +{ + CDOp_Idle, + CDOp_Playing, +} +CDOPERATIONSTATES; + +/* Patrick 10/6/97 -------------------------------------------------------------- + CDDA_Start/End are used to initialise and de-initialise the CDDA system. + No CDDA operations have any effect until the system has been initialised. + -----------------------------------------------------------------------------*/ +extern void CDDA_Start(void); +extern void CDDA_End(void); +/* Patrick 10/6/97 -------------------------------------------------------------- + This is provided to allow platform specific polling/management of the CD device + whilst playing. It should be called during the main game loop. + -----------------------------------------------------------------------------*/ +extern void CDDA_Management(void); +/* Patrick 10/6/97 -------------------------------------------------------------- + Play , change volume, and stop are the basic CDDA operations provided. An + enumeration of tracks should be provided in the platform header. + -----------------------------------------------------------------------------*/ +extern void CDDA_Play(int CDDATrack); +extern void CDDA_PlayLoop(int CDDATrack); +extern void CDDA_ChangeVolume(int volume); +extern void CDDA_Stop(void); +extern int CDDA_CheckNumberOfTracks(void); +/* Patrick 23/6/97 -------------------------------------------------------------- + Returns the current CDDA volume setting. NB if the cd player has not been + initialised the volume setting can still be obtained by calling this function, + though it may not be changed using CDDA_ChangeVolume(). + -----------------------------------------------------------------------------*/ +extern int CDDA_GetCurrentVolumeSetting(void); +/* Patrick 10/6/97 -------------------------------------------------------------- + Switch on and switch off may be used to stop and start the CDDA system after + initialisation. They are provided to allow the user to stop and start CDDA + during a game. + -----------------------------------------------------------------------------*/ +extern void CDDA_SwitchOn(void); +extern void CDDA_SwitchOff(void); +/* Patrick 10/6/97 -------------------------------------------------------------- + These are provided to interrogate the state of the CDDA system. + -----------------------------------------------------------------------------*/ +extern int CDDA_IsOn(void); +extern int CDDA_IsPlaying(void); + + + +enum CDCOMMANDID +{ + CDCOMMANDID_Start, + CDCOMMANDID_End, + CDCOMMANDID_Play, + CDCOMMANDID_PlayLoop, + CDCOMMANDID_ChangeVolume, + CDCOMMANDID_Stop, +}; + +/* CDDA SUPPORT */ + +#define VOLUME_CDDA_MAXPLAT (65535) +#define VOLUME_CDDA_MINPLAT (0) + +/* Patrick 10/6/97 ------------------------------------------------------------- + Start and end functions provide any platform specific initialisation for + the CD player. The start function returns SOUND_PLATFORM error if unsucessful, + or zero otherwise. + ----------------------------------------------------------------------------*/ +extern int PlatStartCDDA(void); +extern void PlatEndCDDA(void); +/* Patrick 10/6/97 ------------------------------------------------------------- + Platform specific play, stop, and change volume functions. NB the volume + is scaled to the platform limits defined above. + These functions return SOUND_PLATFORM error if unsucessful, or 0 otherwise. + ----------------------------------------------------------------------------*/ +extern int PlatPlayCDDA(int track); +extern int PlatStopCDDA(void); +extern int PlatChangeCDDAVolume(int volume); +int PlatGetNumberOfCDTracks(int* numTracks); +/* Patrick 10/6/97 ------------------------------------------------------------- + Management functions are provided for platform specific detection of changes + in the cd player state (ie finishing a track, or an error). The basic + management function is provided for consoles, who need to poll the device, + whilst the call back is provided for intercepting WIN95 MCI call backs. + ----------------------------------------------------------------------------*/ +extern void PlatCDDAManagement(void); +extern void PlatCDDAManagementCallBack(WPARAM flags, LONG deviceId); + + + +extern int CDPlayerVolume; \ No newline at end of file diff --git a/3dc/win95/CHNKIMAG.CPP b/3dc/win95/CHNKIMAG.CPP new file mode 100644 index 0000000..a2f703a --- /dev/null +++ b/3dc/win95/CHNKIMAG.CPP @@ -0,0 +1,699 @@ +#include + +#define TRY_OLD_DIRS 0 // obsolete +#define ALLOW_LOAD_ORIGINAL 0 + +#if TRY_OLD_DIRS // temporary until all textures go into subshps directory +#include "ffstdio.h" +#endif + +#include "chnkimag.hpp" + +#include "list_tem.hpp" +#include "envchunk.hpp" +#include "chunkpal.hpp" +#include "bmpnames.hpp" + +#include "chnkload.hpp" + +char const * CL_RIFFImage::game_mode = 0; + +// useful filename handling functions + +// returns pointer into string pointing to filename without dirname +template // C can be char or char const +static C * strip_path(C * n) +{ + C * rm = strrchr(n,':'); + if (rm) n = rm+1; + rm = strrchr(n,'/'); + if (rm) n = rm+1; + rm = strrchr(n,'\\'); + if (rm) n = rm+1; + + return n; +} + +// removes any .extension from filename by inserting null character +static void strip_file_extension(char * n) +{ + char * dotpos = strrchr(n,'.'); + if (dotpos) *dotpos = 0; +} + +static char * strip_file_extension(char const * n) +{ + char * nn = new char[strlen(n)+1]; + strcpy(nn,n); + strip_file_extension(nn); + return nn; +} + +//////////////////////// +// +// riff file interface +// +//////////////////////// + + +// get the directory associated with the riff - free with delete[] +static char * riff_basename(Chunk_With_Children * envd) +{ + RIF_Name_Chunk * rnc = 0; + + List chlst = envd->lookup_child("RIFFNAME"); + + if (chlst.size()) + { + rnc = (RIF_Name_Chunk *)chlst.first_entry(); + const char * rif_name = strip_path(rnc->rif_name); + + char * basename = new char[strlen(rif_name)+1]; + strcpy(basename,rif_name); + strip_file_extension(basename); + + return basename; + } + const char * deflt = "empty"; + char * basename = new char [strlen(deflt)+1]; + strcpy(basename,deflt); + + return basename; +} + +#if OUTPUT_LOG +#define _LOGID CL_LogFile.lprintf("%s:%d :: ",__FILE__,__LINE__) +#define _LOGPUT(s) _LOGID,CL_LogFile.lputs(s) +#define _LOGPRINT(args) _LOGID,CL_LogFile.lprintf args +#else +#define _LOGPUT(s) (void)0 +#define _LOGPRINT(args) (void)0 +#endif + +void CL_RIFFImage::GetPath(ImageDescriptor const & idsc, Environment_Data_Chunk * envd, BMPN_Flags bflags) +{ + if (fname) delete[] fname; + fname = 0; + + // set the name + if (name) delete[] name; + char * nptr = strip_path(idsc.filename); + name = new char[strlen(nptr)+1]; + strcpy(name,nptr); + #if 0 + char orig_ext[32]; + char const * oeP = strrchr(name,'.'); + if (!oeP) eoP = ""; + strcpy(orig_ext,oeP); + #endif + strip_file_extension(name); + + // load this image + char const * pg0ext = ".PG0"; + switch (imode) + { + case CLM_16BIT: + case CLM_24BIT: + case CLM_32BIT: + #if ALLOW_LOAD_ORIGINAL + { + char const * dir2 = idsc.flags & IDSCF_SPRITE ? "Sprites\\" : ""; + char * riffname = riff_basename(envd); + char const * dir3 = idsc.flags & IDSCF_INCLUDED ? idsc.rifname : riffname; + fname = new char[strlen(ToolsTex_Directory)+strlen(dir2)+strlen(dir3)+1+strlen(name)+5]; + strcpy(fname,ToolsTex_Directory); + strcat(fname,dir2); + strcat(fname,dir3); + strcat(fname,"\\"); + strcat(fname,name); + strcat(fname,".PP0"); + delete[] riffname; + break; + } + #endif + case CLM_ATTACHEDPALETTE: + { + char const * dir2 = idsc.flags & IDSCF_SPRITE ? "Sprites\\" : idsc.flags & IDSCF_SUBSHAPE ? "SubShps\\All\\" : ""; + char * riffname = riff_basename(envd); + char const * dir3 = idsc.flags & IDSCF_INCLUDED ? idsc.rifname : riffname; + fname = new char[strlen(GenTex_Directory)+strlen(dir2)+strlen(dir3)+1+strlen(name)+5]; + strcpy(fname,GenTex_Directory); + strcat(fname,dir2); + strcat(fname,dir3); + strcat(fname,"\\"); + strcat(fname,name); + strcat(fname,".BM0"); + delete[] riffname; + #if TRY_OLD_DIRS // temporary until all textures go into subshps directory + FFILE * ftest = ffopen(fname,"rb"); + if (ftest) ffclose(ftest); + else + { + _LOGPUT("WARNING! Not found in SubShps directory\n"); + char const * dir2 = idsc.flags & IDSCF_SPRITE ? "Sprites\\" : ""; + char * riffname = riff_basename(envd); + char const * dir3 = idsc.flags & IDSCF_INCLUDED ? idsc.rifname : riffname; + delete[] fname; + fname = new char[strlen(GenTex_Directory)+strlen(dir2)+strlen(dir3)+1+strlen(name)+5]; + strcpy(fname,GenTex_Directory); + strcat(fname,dir2); + strcat(fname,dir3); + strcat(fname,"\\"); + strcat(fname,name); + strcat(fname,".BM0"); + delete[] riffname; + } + #endif + break; + } + case CLM_TLTPALETTE: + if (!(bflags & ChunkBMPFlag_NotLit)) + { + pg0ext = ".PW0"; + flags.tltpalette = 1; + } + case CLM_GLOBALPALETTE: + { + if (idsc.flags & IDSCF_FIXEDPALETTE) + { + char const * dir2 = idsc.fixrifname ? *idsc.fixrifname ? idsc.fixrifname : 0 : 0; + char const * dir3 = idsc.flags & IDSCF_SPRITE ? "Sprites\\" : ""; + char * riffname = riff_basename(envd); + char const * dir4 = idsc.flags & IDSCF_INCLUDED ? idsc.rifname : riffname; + fname = new char[strlen(FixTex_Directory)+(dir2 ? strlen(dir2)+1 : 0)+strlen(dir3)+strlen(dir4)+1+strlen(name)+5]; + strcpy(fname,FixTex_Directory); + if (dir2) + { + strcat(fname,dir2); + strcat(fname,"\\"); + } + strcat(fname,dir3); + strcat(fname,dir4); + strcat(fname,"\\"); + strcat(fname,name); + strcat(fname,pg0ext); + delete[] riffname; + } + else + { + char const * dir1 = game_mode ? GameTex_Directory : ToolsTex_Directory; + char * dir2 = riff_basename(envd); + char const * dir4 = idsc.flags & IDSCF_SPRITE ? "Sprites\\" : ""; + char const * dir5 = idsc.flags & IDSCF_INCLUDED ? idsc.rifname : 0; + fname = new char[strlen(dir1)+strlen(dir2)+1+(game_mode ? strlen(game_mode)+1 : 0)+strlen(dir4)+(dir5 ? strlen(dir5)+1 : 0)+strlen(name)+5]; + strcpy(fname,dir1); + strcat(fname,dir2); + strcat(fname,"\\"); + if (game_mode) + { + strcat(fname,game_mode); + strcat(fname,"\\"); + } + strcat(fname,dir4); + if (dir5) + { + strcat(fname,dir5); + strcat(fname,"\\"); + } + strcat(fname,name); + strcat(fname,pg0ext); + delete[] dir2; + } + break; + } + } + + if (!fname) + { + _LOGPUT("WARNING! GetPath returning NULL pointer\n"); + } + else + _LOGPRINT(("file expected to be %s\n",fname)); +} + + +CL_Error CL_RIFFImage::Locate(char const * iname, int const enum_id) +{ + _LOGPRINT(("RIF File image finder called for %s, id %d\n",iname,enum_id)); + + if (!Env_Chunk) + _LOGPUT("WARNING! no .RIF file loaded\n"); + + if (!Env_Chunk) return CLE_RIFFERROR; + + switch (imode) + { + case CLM_ATTACHEDPALETTE: + case CLM_16BIT: + case CLM_24BIT: + case CLM_32BIT: + case CLM_GLOBALPALETTE: + case CLM_TLTPALETTE: + break; + default: + _LOGPUT("WARNING! undefined video mode\n"); + return CLE_INVALIDDXMODE; + } + + // remove projectsubdirectory from start of image name if it is there + unsigned int const psdirlen = strlen(projectsubdirectory); + if (!strncmp(projectsubdirectory,iname,psdirlen)) + iname += psdirlen; + + List envdl (Env_Chunk->lookup_child("REBENVDT")); + + if (!envdl.size()) + { + _LOGPUT("WARNING! no environment data chunk\n"); + return CLE_RIFFERROR; + } + + Environment_Data_Chunk * envd = (Environment_Data_Chunk *) envdl.first_entry(); + + CL_Error retval = CLE_OK; + Environment_Game_Mode_Chunk * egmc = 0; + if (game_mode) + { + if (*game_mode) + { + List egmcl (envd->lookup_child("GAMEMODE")); + + for (LIF egmci(&egmcl); !egmci.done(); egmci.next()) + { + Environment_Game_Mode_Chunk * egmcm = (Environment_Game_Mode_Chunk *) egmci(); + if (egmcm->id_equals(game_mode)) + { + egmc = egmcm; + break; + } + } + + if (!egmc) retval = CLE_INVALIDGAMEMODE; + // only returns this error if the game mode cannot be found *and* the image is not listed + } + } + + if (name) + { + delete[] name; + name = 0; + } + if (iname) name = strip_file_extension(strip_path(iname)); + + char * rcname = 0; + if (iname) + { + if (strchr(iname,'\\')) + { + rcname = new char[strlen(iname)+1]; + strcpy(rcname,iname); + *strchr(rcname,'\\')=0; + } + else if (strchr(iname,'/')) + { + rcname = new char[strlen(iname)+1]; + strcpy(rcname,iname); + *strchr(rcname,'/')=0; + } + } + + if (egmc) + { + int shapefoundingm = rcname ? 0 : 1; + // Get the matching image 'Processor' chunk + List micl = egmc->lookup_child("MATCHIMG"); + + Matching_Images_Chunk * mic = 0; + if (micl.size()) mic = (Matching_Images_Chunk *)micl.first_entry(); + + List rcl = egmc->lookup_child("RIFCHILD"); + + for (LIF rci(&rcl); !rci.done(); rci.next()) + { + RIF_Child_Chunk * rcm = (RIF_Child_Chunk *) rci(); + + if (rcname) + { + if (_stricmp(rcname,rcm->rifname) && (*rcname || *rcm->filename)) + continue; + shapefoundingm = 1; + } + + for (LIF bmpfi(&rcm->bmps); !bmpfi.done(); bmpfi.next()) + { + BMP_Flags bmpft(bmpfi()); + strip_file_extension(bmpft.filename); + + if (iname ? !_stricmp(name,strip_path(bmpft.filename)) : enum_id == bmpft.enum_id) + { + // select image descriptor + ImageDescriptor const idsc + ( + *rcm->filename ? + (IDscFlags)((bmpft.flags & ChunkBMPFlag_FixedPalette ? + IDSCF_FIXEDPALETTE + : + IDSCF_0) + |IDSCF_INCLUDED) + : + IDSCF_0, + bmpfi().filename, + *rcm->filename ? rcm->rifname : 0 + ); + ImageDescriptor const * p_idsc = &idsc; + + if (mic) p_idsc = &mic->GetLoadImage(idsc); + else _LOGPRINT(("WARNING! no rule to find matching images in game mode %s\n",egmc->header->mode_identifier)); + + // load this image + GetPath(*p_idsc,envd,bmpft.flags); + + if (fname) + { + if (rcname) + { + delete[] rcname; + rcname = 0; + } + flags.located = 1; + return CLE_OK; + } + } + } + } + + List ssc = egmc->lookup_child("SHBMPNAM"); + + for (LIF ssi(&ssc); !ssi.done(); ssi.next()) + { + External_Shape_BMPs_Store_Chunk * ss = (External_Shape_BMPs_Store_Chunk *) ssi(); + + if (rcname) + if (_stricmp(rcname,ss->shapename) && *rcname) + continue; + + for (LIF bmpfi(&ss->bmps); !bmpfi.done(); bmpfi.next()) + { + BMP_Name bmpft(bmpfi()); + strip_file_extension(bmpft.filename); + + if (iname ? !_stricmp(name,strip_path(bmpft.filename)) : enum_id == bmpft.enum_id) + { + + // select image descriptor + ImageDescriptor const idsc + ( + (IDscFlags)((bmpft.flags & ChunkBMPFlag_FixedPalette ? + IDSCF_FIXEDPALETTE + : + IDSCF_0) + |(ss->GetExtendedData()->flags & GBF_SPRITE ? + IDSCF_SPRITE + : + IDSCF_SUBSHAPE) + |IDSCF_INCLUDED), + bmpfi().filename, + ss->shapename, + bmpft.flags & ChunkBMPFlag_FixedPalette ? ss->rifname : 0 + ); + ImageDescriptor const * p_idsc = &idsc; + + if (mic) p_idsc = &mic->GetLoadImage(idsc); + else _LOGPRINT(("WARNING! no rule to find matching images in game mode %s\n",egmc->header->mode_identifier)); + + #if TRY_OLD_DIRS // temporary until all textures move to SubShps/All directory + if (*p_idsc == idsc) + { + // select image descriptor + ImageDescriptor const idsc2 + ( + (IDscFlags)((bmpft.flags & ChunkBMPFlag_FixedPalette ? + IDSCF_FIXEDPALETTE + : + IDSCF_0) + |(ss->GetExtendedData()->flags & GBF_SPRITE ? + IDSCF_SPRITE + : + IDSCF_0) + |IDSCF_INCLUDED), + bmpfi().filename, + ss->shapename, + bmpft.flags & ChunkBMPFlag_FixedPalette ? ss->rifname : 0 + ); + ImageDescriptor const * p_idsc2 = &idsc2; + + if (mic) p_idsc2 = &mic->GetLoadImage(idsc2); + else _LOGPRINT(("WARNING! no rule to find matching images in game mode %s\n",egmc->header->mode_identifier)); + + if (*p_idsc2 != idsc2) + { + _LOGPUT("WARNING! Not listed as in SubShps directory\n"); + p_idsc = p_idsc2; + } + } + #endif + + // load this image + GetPath(*p_idsc,envd,bmpft.flags); + + if (fname) + { + if (rcname) + { + delete[] rcname; + rcname = 0; + } + flags.located = 1; + return CLE_OK; + } + } + } + } + + if (rcname) + { + if (!shapefoundingm) + _LOGPRINT(("WARNING! shape/sprite %s not found in this RIF file\n",rcname)); + else + _LOGPRINT(("WARNING! shape/sprite %s does not appear to list %s\n",rcname,name)); + } + + } + + List micl = envd->lookup_child("MATCHIMG"); + + Matching_Images_Chunk * mic_fix = 0; + Matching_Images_Chunk * mic_nrm = 0; + + for (LIF mici(&micl); !mici.done(); mici.next()) + { + Matching_Images_Chunk * mic = (Matching_Images_Chunk *)mici(); + if (mic->flags & MICF_FIXEDPALETTE) + mic_fix = mic; + else + mic_nrm = mic; + } + + List shapesandsprites; + + List shlst = Env_Chunk->lookup_child("REBSHAPE"); + for (LIF shLIF(&shlst); !shLIF.done(); shLIF.next()) + { + List shxflst = ((Shape_Chunk *)shLIF())->lookup_child("SHPEXTFL"); + if (shxflst.size()) + { + shapesandsprites.add_entry( (Shape_External_File_Chunk *)shxflst.first_entry() ); + } + } + shlst = Env_Chunk->lookup_child("RSPRITES"); + if (shlst.size()) + { + List splst = ((Chunk_With_Children *)shlst.first_entry())->lookup_child("SPRIHEAD"); + + for (LIF spLIF(&splst); !spLIF.done(); spLIF.next()) + { + shapesandsprites.add_entry( (Chunk_With_Children *)spLIF() ); + } + } + + int shapefound = rcname ? 0 : 1; + + for (LIF sasLIF(&shapesandsprites); !sasLIF.done(); sasLIF.next()) + { + char * subrifname = riff_basename(sasLIF()); + + if (rcname) + { + if (_stricmp(subrifname,rcname)) // must match shapes name exactly + { + delete[] subrifname; + continue; + } + shapefound = 1; + } + + List blsclst = sasLIF()->lookup_child("BMPLSTST"); + if (blsclst.size()) + { + Bitmap_List_Store_Chunk * gbnc = (Bitmap_List_Store_Chunk *) blsclst.first_entry(); + + for (LIF bmpni(&gbnc->bmps); !bmpni.done(); bmpni.next()) + { + BMP_Name bmpnt(bmpni()); + strip_file_extension(bmpnt.filename); + + if (iname ? !_stricmp(name,strip_path(bmpnt.filename)) : enum_id == bmpnt.enum_id) + { + + // select image descriptor + char * riffname = riff_basename(envd); + ImageDescriptor const idsc + ( + (IDscFlags)((bmpnt.flags & ChunkBMPFlag_FixedPalette ? + IDSCF_FIXEDPALETTE + : + IDSCF_0) + |(gbnc->GetExtendedData()->flags & GBF_SPRITE ? + IDSCF_SPRITE + : + IDSCF_SUBSHAPE) + |IDSCF_INCLUDED), + bmpni().filename, + subrifname, + bmpnt.flags & ChunkBMPFlag_FixedPalette ? riffname : 0 + ); + ImageDescriptor const * p_idsc = &idsc; + delete[] riffname; + + if (bmpnt.flags & ChunkBMPFlag_FixedPalette) + { + if (mic_fix) p_idsc = &mic_fix->GetLoadImage(idsc); + else _LOGPUT("WARNING! no rule to find fixed palette matching images in environment data\n"); + } + else + { + if (mic_nrm) p_idsc = &mic_nrm->GetLoadImage(idsc); + else _LOGPUT("WARNING! no rule to find matching images in environment data (interface engine?)\n"); + } + + #if TRY_OLD_DIRS // temporary until all textures move to SubShps/All directory + if (*p_idsc == idsc) + { + // select image descriptor + char * riffname = riff_basename(envd); + ImageDescriptor const idsc2 + ( + (IDscFlags)((bmpnt.flags & ChunkBMPFlag_FixedPalette ? + IDSCF_FIXEDPALETTE + : + IDSCF_0) + |(gbnc->GetExtendedData()->flags & GBF_SPRITE ? + IDSCF_SPRITE + : + IDSCF_0) + |IDSCF_INCLUDED), + bmpni().filename, + subrifname, + bmpnt.flags & ChunkBMPFlag_FixedPalette ? riffname : 0 + ); + ImageDescriptor const * p_idsc2 = &idsc2; + delete[] riffname; + + if (bmpnt.flags & ChunkBMPFlag_FixedPalette) + { + if (mic_fix) p_idsc2 = &mic_fix->GetLoadImage(idsc2); + else _LOGPUT("WARNING! no rule to find fixed palette matching images in environment data\n"); + } + else + { + if (mic_nrm) p_idsc2 = &mic_nrm->GetLoadImage(idsc2); + else _LOGPUT("WARNING! no rule to find matching images in environment data (interface engine?)\n"); + } + if (*p_idsc2 != idsc2) + { + _LOGPUT("WARNING! Not listed as in SubShps directory\n"); + p_idsc = p_idsc2; + } + } + #endif + + // load this image + GetPath(*p_idsc,envd,bmpnt.flags); + + if (fname) + { + delete[] subrifname; + if (rcname) + { + delete[] rcname; + rcname = 0; + } + flags.located = 1; + return CLE_OK; + } + } + } + } + delete[] subrifname; + } + + if (rcname) + { + if (!shapefound) + _LOGPRINT(("WARNING! shape/sprite %s not found in this RIF file\n",rcname)); + else + _LOGPRINT(("WARNING! shape/sprite %s does not appear to list %s\n",rcname,name)); + delete[] rcname; + rcname = 0; + } + + // not found in game textures, so look in default + + else // but only if there is no virtual shape directory + { + List gbncl = envd->lookup_child("BMPNAMES"); + if (gbncl.size()) + { + Global_BMP_Name_Chunk * gbnc = (Global_BMP_Name_Chunk *) gbncl.first_entry(); + + for (LIF bmpni(&gbnc->bmps); !bmpni.done(); bmpni.next()) + { + BMP_Name bmpnt(bmpni()); + strip_file_extension(bmpnt.filename); + + if (iname ? !_stricmp(name,strip_path(bmpnt.filename)) : enum_id == bmpnt.enum_id) + { + // select image descriptor + ImageDescriptor const idsc (bmpnt.flags & ChunkBMPFlag_FixedPalette ? IDSCF_FIXEDPALETTE : IDSCF_0, bmpni().filename); + ImageDescriptor const * p_idsc = &idsc; + + if (bmpnt.flags & ChunkBMPFlag_FixedPalette) + { + if (mic_fix) p_idsc = &mic_fix->GetLoadImage(idsc); + else _LOGPUT("WARNING! no rule to find fixed palette matching images in environment data\n"); + } + else + { + if (mic_nrm) p_idsc = &mic_nrm->GetLoadImage(idsc); + else _LOGPUT("WARNING! no rule to find matching images in environment data (interface engine?)\n"); + } + + // load this image + GetPath(*p_idsc,envd,bmpnt.flags); + + if (fname) + { + flags.located = 1; + return CLE_OK; + } + } + } + } + } + + if (retval != CLE_OK) return retval; + return CLE_FINDERROR; +} + + + diff --git a/3dc/win95/CHNKIMAG.HPP b/3dc/win95/CHNKIMAG.HPP new file mode 100644 index 0000000..df0dc62 --- /dev/null +++ b/3dc/win95/CHNKIMAG.HPP @@ -0,0 +1,33 @@ +#ifndef _included__chnkimag_hpp_ +#define _included__chnkimag_hpp_ + +#error "This file is obsolete" + +#include + +#include "d3_image.hpp" +#include "mishchnk.hpp" +#include "bmpnames.hpp" + +extern "C" extern char projectsubdirectory[]; + +extern char const * GameTex_Directory; +extern char const * GenTex_Directory; +extern char const * FixTex_Directory; +extern char const * ToolsTex_Directory; + +struct CL_RIFFImage : public CL_Image +{ +public: + static char const * game_mode; // game mode defines palette and set of graphics - can be null or "" for default + + CL_RIFFImage() : CL_Image() {} + CL_RIFFImage(CL_Image const & base) : CL_Image(base) {} + +private: + virtual CL_Error Locate(char const * iname, int const enum_id); + + void GetPath(ImageDescriptor const & idsc, Environment_Data_Chunk * envd, BMPN_Flags bflags); +}; + +#endif // !_included__chnkimag_hpp_ diff --git a/3dc/win95/CHNKLOAD.H b/3dc/win95/CHNKLOAD.H new file mode 100644 index 0000000..55fd754 --- /dev/null +++ b/3dc/win95/CHNKLOAD.H @@ -0,0 +1,233 @@ +#ifndef _chnkload_h_ +#define _chnkload_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "system.h" +#include "equates.h" +#include "platform.h" +#include "shape.h" +#include "prototyp.h" +#include "module.h" + +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + +#define GLS_NOTINLIST (-1) + +/////////////////// +// RIF Loading, etc +/////////////////// + +typedef struct _RifHandle * RIFFHANDLE; +#define INVALID_RIFFHANDLE 0 + +// flags - project specific ones start at lsb +// - generic ones to start from msb + +#define CCF_NOMORPH 0x80000000 + +typedef enum UVCoordType +{ + UVC_SPRITE_U, + UVC_SPRITE_V, + UVC_POLY_U, + UVC_POLY_V, + +} UVCOORDTYPE; + +// Note: for aesthetic reasons, macros enable one to have all one's fuctions in lower case or captialized, to suit one's style! + +// For clarity, functions which are to be defined in project specific files +// are here declared with extern + +///////////////////////////////////////// +// Functions which operate on RIFFHANDLEs +///////////////////////////////////////// + +// load a rif file into memory +RIFFHANDLE load_rif (const char * fname); +RIFFHANDLE load_rif_non_env (const char * fname); +#define LoadRIF(s) load_rif(s) + +// deallocate the shapes, unload the rif, close the handle +void undo_rif_load (RIFFHANDLE); +#define UndoRIFLoad(h) undo_rif_load(h) + +// deallocate the shapes copied from the rif +void deallocate_loaded_shapes (RIFFHANDLE); +#define DeallocateLoadedShapes(h) deallocate_loaded_shapes(h) + +// unloads the rif but keeps the handle and associated copied shapes +void unload_rif (RIFFHANDLE); +#define UnloadRIF(h) unload_rif(h); + +// close the handle - performs tidying up and memory deallocation +void close_rif_handle (RIFFHANDLE); +#define CloseRIFHandle(h) close_rif_handle(h) + +// load textures for environment +BOOL load_rif_bitmaps (RIFFHANDLE, int flags); +#define LoadRIFBitmaps(h,f) load_rif_bitmaps(h,f) + +// set the quantization event depending on CL_RIFFImage::game_mode +BOOL set_quantization_event(RIFFHANDLE, int flags); +#define SetQuantizationEvent(h,f) set_quantization_event(h,f) + +// copy palette +BOOL copy_rif_palette (RIFFHANDLE, int flags); +#define CopyRIFPalette(h,f) copy_rif_palette(h,f) + +// copy texture lighting table +BOOL copy_rif_tlt (RIFFHANDLE, int flags); +#define CopyRIFTLT(h,f) copy_rif_tlt(h,f) + +// copy palette remap table (15-bit) - post_process_shape may use it +BOOL get_rif_palette_remap_table (RIFFHANDLE, int flags); +#define GetRIFPaletteRemapTable(h,f) get_rif_palette_remap_table(h,f) + +// copy one named shape or sprite; does not put in main shape list, needs deallocating +SHAPEHEADER * CopyNamedShapePtr (RIFFHANDLE, char const * shapename); +#define copy_named_shape_ptr(h,s) CopyNamedShapePtr(h,s) + +// copy one named shape or sprite; put it in the main shape list +int CopyNamedShapeMSL (RIFFHANDLE, char const * shapename); +#define copy_named_shape_msl(h,s) CopyNamedShapeMSL(h,s) + +//////////////////////////////////////////////////////////////////////// +// Functions which do not operate on RIFFHANDLEs and may become obsolete +//////////////////////////////////////////////////////////////////////// + +// these functions work on the current rif; they only remain for historical reasons +extern RIFFHANDLE current_rif_handle; +// returns NULL on fail; does not put it in the mainshapelist +SHAPEHEADER * CopyNamedShape (char const * shapename); + +///////////////////////////////////////////// +// Functions for handling the main shape list +///////////////////////////////////////////// + +// reserves the next avaialbe position in the main shape list and returns it +extern int GetMSLPos(void); +#define get_msl_pos() GetMSLPos() + +// frees a position in the main shape list +extern void FreeMSLPos(int); +#define free_msl_pos(i) FreeMSLPos(i) + +//////////////////////////////////////////////// +// Functions retrieving data about loaded shapes +//////////////////////////////////////////////// + +// gets the main shape list position of a shape loaded into the msl +int GetLoadedShapeMSL(char const * shapename); +#define get_loaded_shape_msl(s) GetLoadedShapeMSL(s) +// ditto, but returns a pointer; the shape need not be in the msl +SHAPEHEADER * GetLoadedShapePtr(char const * shapename); +#define get_loaded_shape_ptr(s) GetLoadedShapePtr(s) + +// gets name of shape from msl pos +char const * GetMSLLoadedShapeName(int listpos); +#define get_msl_loaded_shape_name(i) GetMSLLoadedShapeName(i) +// gets name of shape from pointer; the shape need not be in msl +char const * GetPtrLoadedShapeName(SHAPEHEADER *); +#define get_ptr_loaded_shape_name(p) GetPtrLoadedShapeName(p) + +// free a reference to a named shape if it exists - not necessary since these are all tidied up +void FreeShapeNameReference(SHAPEHEADER * shptr); +#define free_shape_name_reference(p) FreeShapeNameReference(p) + +////////////////////////////////////////////////////////////////////////////// +// Initializing, deallocating of shapes, mainly hooks for project specific fns +////////////////////////////////////////////////////////////////////////////// + +// perform initial post processing on shape just after loading +// note that the copy named shape functions will not call this +extern void post_process_shape (SHAPEHEADER *); +#define PostProcessShape(p) post_process_shape(p) + +// hook to perhaps scale the uv coordinates - should return new value +extern int ProcessUVCoord(RIFFHANDLE,UVCOORDTYPE,int uv_value,int image_num); +#define process_uv_coord(h,t,u,i) ProcessUVCoord(h,t,u,i) + +// delete a shape by the shapeheader +void DeallocateLoadedShapePtr(SHAPEHEADER *); +#define deallocate_loaded_shape_ptr(h,p) DeallocateLoadedShapePtr(h,p) + +// delete a shape by the shape list number +void DeallocateLoadedShapeMSL(RIFFHANDLE, int); +#define deallocate_loaded_shape_msl(h,i) DeallocateLoadedShapeMSL(h,i) + +// your function could perform any extra tidying up you need +extern void DeallocateLoadedShapeheader(SHAPEHEADER *); +#define deallocate_loaded_shapeheader(p) DeallocateLoadedShapeHeader(p) + +// your function should call this function which undoes the allocation done when copied from rif data +void DeallocateRifLoadedShapeheader(SHAPEHEADER *); +#define deallocate_rif_loaded_shapeheader(p) DeallocateRifLoadedShapeHeader(p) + +/////// +// Misc +/////// + +// return TRUE if the poly item type corresponds to a textured polygon +BOOL is_textured(int); +#define IsTextured(i) is_textured(i) + +///////////////////// +// Rif loader globals +///////////////////// + +extern unsigned char const * PaletteMapTable; + +///////////////// +// Engine globals +///////////////// + +extern int start_of_loaded_shapes; + +extern unsigned char *TextureLightingTable; + +#if defined(InterfaceEngine) && InterfaceEngine +// this is of crucial importance!! +extern SHAPEHEADER * mainshapelist[]; +#else +extern SHAPEHEADER ** mainshapelist; +#endif + +extern MAPHEADER Map[]; + +extern MAPBLOCK8 Player_and_Camera_Type8[]; +extern MAPBLOCK6 Empty_Landscape_Type6; +extern MAPBLOCK6 Empty_Object_Type6; +extern MAPBLOCK6 Term_Type6; + +extern unsigned char TestPalette[]; + +extern unsigned char LPTestPalette[]; /* to cast to lp*/ + +#if 0 +extern int NumImages; /* # current images */ +extern IMAGEHEADER *ImageHeaderPtrs[]; /* Ptrs to Image Header Blocks */ +extern IMAGEHEADER ImageHeaderArray[]; /* Array of Image Headers */ +extern IMAGEHEADER *NextFreeImageHeaderPtr; +#endif + +#if SupportModules + +extern SCENEMODULE MainScene; +extern MODULE Empty_Module; +extern MODULE Term_Module; + +extern MODULEMAPBLOCK Empty_Module_Map; + +#endif + +#ifdef __cplusplus + +} + +#endif + +#endif diff --git a/3dc/win95/CHNKLOAD.HPP b/3dc/win95/CHNKLOAD.HPP new file mode 100644 index 0000000..19325dc --- /dev/null +++ b/3dc/win95/CHNKLOAD.HPP @@ -0,0 +1,106 @@ +#ifndef _chnkload_hpp +#define _chnkload_hpp 1 + +#include "chnkload.h" + +#ifdef __cplusplus + +#include "chunk.hpp" +#include "shpchunk.hpp" +#include "obchunk.hpp" +#include "bmpnames.hpp" +#include "projload.hpp" + +#if 0 +extern BOOL copy_to_mainshpl (Shape_Chunk *shape, int list_pos); +extern BOOL copy_to_mainshpl (Shape_Sub_Shape_Chunk *shape, int list_pos); +#endif + +extern void copy_to_module (Object_Chunk * ob, int mod_pos, int shplst_pos); + +extern BOOL copy_to_shapeheader ( + RIFFHANDLE, + ChunkShape const & cshp, + SHAPEHEADER *& shphd, + Chunk_With_Children * shape, + int flags, + int local_max_index, + int * local_tex_index_nos, + int listpos = GLS_NOTINLIST, + const ChunkObject* object=0 //object used so that conversion from float to int can be done in world coordinates + ); +extern BOOL copy_preprocessed_to_shapeheader ( + RIFFHANDLE, + Shape_Preprocessed_Data_Chunk*, + SHAPEHEADER *& shphd, + Chunk_With_Children * shape, + int flags, + int local_max_index, + int * local_tex_index_nos, + int listpos = GLS_NOTINLIST, + const ChunkObject* object=0 //object used so that conversion from float to int can be done in world coordinates + ); + +extern BOOL copy_sprite_to_shapeheader (RIFFHANDLE, SHAPEHEADER *& shphd,Sprite_Header_Chunk* shc, int listpos = GLS_NOTINLIST); + + +extern BOOL copy_to_map6(Object_Chunk *,MAPBLOCK6*, int shplst_pos); + +extern void merge_polygons_in_chunkshape (ChunkShape & shp, Shape_Merge_Data_Chunk * smdc); + +extern File_Chunk * Env_Chunk; + +extern double local_scale; + +// copies shape to msl +#if SupportMorphing && LOAD_MORPH_SHAPES +typedef struct +{ + int start_list_pos; + int main_list_pos; + MORPHCTRL * mc; + +} CTM_ReturnType; +#else +typedef int CTM_ReturnType; +#endif + +CTM_ReturnType copy_to_mainshapelist(RIFFHANDLE, Shape_Chunk *, int flags,const ChunkObject* object=0); +#define CopyToMainshapelist(h,r,p,f) copy_to_mainshapelist(h,r,p,f) + +// copies sprite to msl +int copy_sprite_to_mainshapelist(RIFFHANDLE, Sprite_Header_Chunk *, int flags); +#define CopySpriteToMainshapelist(h,p,f) copy_sprite_to_mainshapelist(h,p,f) + +// hook to load a bitmap - so you can load them from test directories, etc. should return tex index +extern int load_rif_bitmap (char const * fname, BMPN_Flags flags); +#define LoadRIFBitmap(s,f) load_rif_bitmap(s,f) + +// project specific shape pre processing - usually merge polys +extern void pre_process_shape (RIFFHANDLE, ChunkShape &, Chunk_With_Children * shape_chunk, int flags); +#define PreProcessShape(h,r,p,f) pre_process_shape(h,r,p,f) + + +struct _RifHandle : Project_RifHandle +{ + File_Chunk * fc; + Environment_Data_Chunk * envd; + Chunk_With_Children * palparent; + List shape_nums; + int max_index; + int * tex_index_nos; + + ~_RifHandle() + {} + _RifHandle() + : fc(0) + , envd(0) + , max_index(0) + , tex_index_nos(0) + , palparent(0) + {} +}; + +#endif + +#endif diff --git a/3dc/win95/CHNKTEXI.CPP b/3dc/win95/CHNKTEXI.CPP new file mode 100644 index 0000000..640f011 --- /dev/null +++ b/3dc/win95/CHNKTEXI.CPP @@ -0,0 +1,940 @@ +#include +#include +#include +#ifndef DB_LEVEL + #define DB_LEVEL 4 +#endif +#include "db.h" +#include "awTexLd.h" +#include "chnkload.hpp" +#include "chunkpal.hpp" + +#ifndef CL_SUPPORT_FASTFILE + #error "Please #define CL_SUPPORT_FASTFILE to 0 or 1 in projload.hpp" +#endif +#if CL_SUPPORT_FASTFILE + #include "ffstdio.h" +#endif + +#ifndef CL_SUPPORT_ALTTAB + #error "Please #define CL_SUPPORT_ALTTAB to 0 or 1 in projload.hpp" +#endif +#if CL_SUPPORT_ALTTAB + #include "alt_tab.h" +#endif + +#include "chnktexi.h" + +#if !defined(NDEBUG) && defined(_CPPRTTI) + #include +#else + #define dynamic_cast static_cast +#endif + +char const * cl_pszGameMode = NULL; + +// used to determine if the display is palettized +// currently assuming that if this is <= 8 then all +// surfaces et. except d3d textures have a global palette +extern "C" extern int VideoModeColourDepth; + +// useful filename handling functions + +// returns pointer into string pointing to filename without dirname +template // C can be char or char const +static C * StripPath(C * n) +{ + C * rm = strrchr(n,':'); + if (rm) n = rm+1; + rm = strrchr(n,'/'); + if (rm) n = rm+1; + rm = strrchr(n,'\\'); + if (rm) n = rm+1; + + return n; +} + +// removes any .extension from filename by inserting null character +static void StripFileExtension(char * n) +{ + char * dotpos = strrchr(n,'.'); + if (dotpos) *dotpos = 0; +} + +static char * StripFileExtension(char const * n) +{ + char * nn = new char[strlen(n)+1]; + strcpy(nn,n); + StripFileExtension(nn); + return nn; +} + +// get the directory associated with the riff - free with delete[] +static char * RiffBasename(Chunk_With_Children * pEnvDataChunk) +{ + Chunk * pChunk = pEnvDataChunk->lookup_single_child("RIFFNAME"); + + if (pChunk) + { + RIF_Name_Chunk * pRifNameChunk = dynamic_cast(pChunk); + + const char * pszRifName = StripPath(pRifNameChunk->rif_name); + + char * pszBaseName = new char[strlen(pszRifName)+1]; + strcpy(pszBaseName,pszRifName); + StripFileExtension(pszBaseName); + + return pszBaseName; + } + const char * pszDefault = "empty"; + char * pszBaseName = new char [strlen(pszDefault)+1]; + strcpy(pszBaseName,pszDefault); + + return pszBaseName; +} + +#if CL_SUPPORT_FASTFILE +static inline bool IsFileInFastFile(char const * pszFileName) +{ + unsigned nLen; + return ffreadbuf(pszFileName,&nLen) ? true : false; +} +#endif + +static bool DoesFileExist(char const * pszFileName) +{ + DWORD dwFileAttributes = GetFileAttributes(pszFileName); + + if (0xffffffff == dwFileAttributes || dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + return false; + else + return true; +} + +static char * GetPath(char * pszFileNameBuf, unsigned nBufSize, ImageDescriptor const & idsc, Chunk_With_Children * pEnvDataChunk, bool bGloballyPalettized) +{ + // set the name + char const * pszRawName = StripPath(idsc.filename); + char * pszName = new char[strlen(pszRawName)+1]; + strcpy(pszName,pszRawName); + StripFileExtension(pszName); + + // load this image + char const * pg0ext = ".PG0"; + + if (!bGloballyPalettized) + { + char const * dir2 = idsc.flags & IDSCF_SPRITE ? "Sprites\\" : idsc.flags & IDSCF_SUBSHAPE ? SubShps_Directory : ""; + char * riffname = RiffBasename(pEnvDataChunk); + char const * dir3 = idsc.flags & IDSCF_INCLUDED ? idsc.rifname : riffname; + if (nBufSize < strlen(GenTex_Directory)+strlen(dir2)+strlen(dir3)+1+strlen(pszName)+5) + { + db_log1("CL_LoadImageOnce(): ERROR: buffer not big enough for filename"); + pszFileNameBuf = NULL; + } + else + { + strcpy(pszFileNameBuf,GenTex_Directory); + strcat(pszFileNameBuf,dir2); + strcat(pszFileNameBuf,dir3); + strcat(pszFileNameBuf,"\\"); + strcat(pszFileNameBuf,pszName); + strcat(pszFileNameBuf,".BM0"); + } + delete[] riffname; + } + else + { + if (idsc.flags & IDSCF_FIXEDPALETTE) + { + char const * dir2 = idsc.fixrifname ? *idsc.fixrifname ? idsc.fixrifname : 0 : 0; + char const * dir3 = idsc.flags & IDSCF_SPRITE ? "Sprites\\" : ""; + char * riffname = RiffBasename(pEnvDataChunk); + char const * dir4 = idsc.flags & IDSCF_INCLUDED ? idsc.rifname : riffname; + if (nBufSize < strlen(FixTex_Directory)+(dir2 ? strlen(dir2)+1 : 0)+strlen(dir3)+strlen(dir4)+1+strlen(pszName)+5) + { + db_log1("CL_LoadImageOnce(): ERROR: buffer not big enough for filename"); + pszFileNameBuf = NULL; + } + else + { + strcpy(pszFileNameBuf,FixTex_Directory); + if (dir2) + { + strcat(pszFileNameBuf,dir2); + strcat(pszFileNameBuf,"\\"); + } + strcat(pszFileNameBuf,dir3); + strcat(pszFileNameBuf,dir4); + strcat(pszFileNameBuf,"\\"); + strcat(pszFileNameBuf,pszName); + strcat(pszFileNameBuf,pg0ext); + } + delete[] riffname; + } + else + { + char const * dir1 = cl_pszGameMode ? GameTex_Directory : ToolsTex_Directory; + char * dir2 = RiffBasename(pEnvDataChunk); + char const * dir4 = idsc.flags & IDSCF_SPRITE ? "Sprites\\" : ""; + char const * dir5 = idsc.flags & IDSCF_INCLUDED ? idsc.rifname : 0; + if (nBufSize < strlen(dir1)+strlen(dir2)+1+(cl_pszGameMode ? strlen(cl_pszGameMode)+1 : 0)+strlen(dir4)+(dir5 ? strlen(dir5)+1 : 0)+strlen(pszName)+5) + { + db_log1("CL_LoadImageOnce(): ERROR: buffer not big enough for filename"); + pszFileNameBuf = NULL; + } + else + { + strcpy(pszFileNameBuf,dir1); + strcat(pszFileNameBuf,dir2); + strcat(pszFileNameBuf,"\\"); + if (cl_pszGameMode) + { + strcat(pszFileNameBuf,cl_pszGameMode); + strcat(pszFileNameBuf,"\\"); + } + strcat(pszFileNameBuf,dir4); + if (dir5) + { + strcat(pszFileNameBuf,dir5); + strcat(pszFileNameBuf,"\\"); + } + strcat(pszFileNameBuf,pszName); + strcat(pszFileNameBuf,pg0ext); + } + delete[] dir2; + } + } + + if (pszFileNameBuf) + db_logf4(("\tfile expected to be '%s'",pszFileNameBuf)); + + delete[] pszName; + + return pszFileNameBuf; +} + +char * CL_GetImageFileName(char * pszDestBuf, unsigned nBufSize, char const * pszFileName, unsigned fFlagsEtc) +{ + db_assert1(pszFileName); + db_assert1(pszDestBuf); + db_assert1(nBufSize>0); + db_logf4(("CL_LoadImageOnce(): Getting the full pathname for %s",pszFileName)); + switch (fFlagsEtc & _LIO_PATHTYPEMASK) + { + case LIO_ABSOLUTEPATH: + db_log4("\t(which is an absolute path)"); + if (strlen(pszFileName)", + SecondTex_Directory ? SecondTex_Directory : "")); + #define _GET_RELATIVE_PATH(pszDirectory,fnDoesExist) \ + if (pszDirectory) { \ + String str = pszDirectory; \ + if (str.length()) { \ + int chLast = str.get_at(str.length()-1); \ + if (chLast != '\\' && chLast != '/') \ + str += '\\'; \ + str += pszFileName; \ + if (fnDoesExist(str)) { \ + if (str.length() < nBufSize) { \ + strcpy(pszDestBuf,str); \ + return pszDestBuf; \ + } else { \ + db_log1("CL_LoadImageOnce(): ERROR: buffer not large enough to hold filename"); \ + return NULL; /* fail because the buffer isnt big enough */ \ + } } } } + + #if CL_SUPPORT_FASTFILE + _GET_RELATIVE_PATH(FirstTex_Directory,IsFileInFastFile) + _GET_RELATIVE_PATH(SecondTex_Directory,IsFileInFastFile) + #endif + #if !defined(CL_SUPPORTONLY_FASTFILE) || !CL_SUPPORTONLY_FASTFILE + _GET_RELATIVE_PATH(FirstTex_Directory,DoesFileExist) + _GET_RELATIVE_PATH(SecondTex_Directory,DoesFileExist) + #endif + db_log1("CL_LoadImageOnce(): ERROR: file not found in relative path"); + return NULL; + case LIO_RIFFPATH: + { + int enum_id = -1; // may be supported at a later date, valid when pszFileName is NULL + + bool bGloballyPalettized = VideoModeColourDepth <= 8 && (fFlagsEtc & _LIO_SURFTYPEMASK) != LIO_D3DTEXTURE; + + db_log4("\t(whose path is determined by the current .RIF file)"); + if (!Env_Chunk) + { + db_log1("CL_LoadImageOnce(): ERROR: no RIF file"); + return NULL; + } + Chunk * pChunk = Env_Chunk->lookup_single_child("REBENVDT"); + if (!pChunk) + { + db_log1("CL_LoadImageOnce(): ERROR: no environment data chunk"); + return NULL; + } + Chunk_With_Children * pEnvDataChunk = dynamic_cast(pChunk); + db_assert1(pEnvDataChunk); + + Environment_Game_Mode_Chunk * pGameModeChunk = NULL; + if (cl_pszGameMode) + { + if (*cl_pszGameMode) + { + List listGmChunks; + pEnvDataChunk->lookup_child("GAMEMODE",listGmChunks); + + for (LIF itGmChunks(&listGmChunks); !itGmChunks.done(); itGmChunks.next()) + { + Environment_Game_Mode_Chunk * pGmChunk = dynamic_cast(itGmChunks()); + db_assert1(pGmChunk); + if (pGmChunk->id_equals(cl_pszGameMode)) + { + pGameModeChunk = pGmChunk; + break; + } + } + + if (!pGameModeChunk) + db_logf3(("CL_LoadImageOnce(): WARNING: Game Mode '%s' not found",cl_pszGameMode)); + } + } + + char * pszName = StripFileExtension(StripPath(pszFileName)); + + char * pszSubName = 0; + if (pszFileName) + { + if (strchr(pszFileName,'\\')) + { + pszSubName = new char[strlen(pszFileName)+1]; + strcpy(pszSubName,pszFileName); + *strchr(pszSubName,'\\')=0; + } + else if (strchr(pszFileName,'/')) + { + pszSubName = new char[strlen(pszFileName)+1]; + strcpy(pszSubName,pszFileName); + *strchr(pszSubName,'/')=0; + } + } + + if (pGameModeChunk) + { + bool bShapeInGm = pszSubName ? false : true; + // Get the matching image 'Processor' chunk + Chunk * pMiChunk = pGameModeChunk->lookup_single_child("MATCHIMG"); + Matching_Images_Chunk * pMatchImageChunk = NULL; + + if (pMiChunk) + { + pMatchImageChunk = dynamic_cast(pMiChunk); + db_assert1(pMatchImageChunk); + } + + List listRifChildChunks; + pGameModeChunk->lookup_child("RIFCHILD",listRifChildChunks); + + for (LIF itRifChildChunks(&listRifChildChunks); !itRifChildChunks.done(); itRifChildChunks.next()) + { + RIF_Child_Chunk * pRifChildChunk = dynamic_cast(itRifChildChunks()); + db_assert1(pRifChildChunk); + + if (pszSubName) + { + if (_stricmp(pszSubName,pRifChildChunk->rifname) && (*pszSubName || *pRifChildChunk->filename)) + continue; + bShapeInGm = true; + } + + for (LIF itBmpFlags(&pRifChildChunk->bmps); !itBmpFlags.done(); itBmpFlags.next()) + { + BMP_Flags bmpfTemp(itBmpFlags()); + StripFileExtension(bmpfTemp.filename); + + if (pszFileName ? !_stricmp(pszName,StripPath(bmpfTemp.filename)) : enum_id == bmpfTemp.enum_id) + { + // select image descriptor + ImageDescriptor const idsc + ( + *pRifChildChunk->filename ? + (IDscFlags)((bmpfTemp.flags & ChunkBMPFlag_FixedPalette ? + IDSCF_FIXEDPALETTE + : + IDSCF_0) + |IDSCF_INCLUDED) + : + IDSCF_0, + itBmpFlags().filename, + *pRifChildChunk->filename ? pRifChildChunk->rifname : 0 + ); + ImageDescriptor const * pIdsc = &idsc; + + if (pMatchImageChunk) pIdsc = &pMatchImageChunk->GetLoadImage(idsc); + else db_logf3(("CL_LoadImageOnce(): WARNING! no rule to find matching images in game mode '%s'\n",pGameModeChunk->header->mode_identifier)); + + // load this image + if (GetPath(pszDestBuf,nBufSize,*pIdsc,pEnvDataChunk,bGloballyPalettized)) + { + if (pszSubName) + { + delete[] pszSubName; + } + delete[] pszName; + return pszDestBuf; + } + } + } + } + + List listExtShapes; + pGameModeChunk->lookup_child("SHBMPNAM",listExtShapes); + + for (LIF itExtShapes(&listExtShapes); !itExtShapes.done(); itExtShapes.next()) + { + External_Shape_BMPs_Store_Chunk * pShapeBmpsChunk = dynamic_cast(itExtShapes()); + db_assert1(pShapeBmpsChunk); + + if (pszSubName) + if (_stricmp(pszSubName,pShapeBmpsChunk->shapename) && *pszSubName) + continue; + + for (LIF itBmpNames(&pShapeBmpsChunk->bmps); !itBmpNames.done(); itBmpNames.next()) + { + BMP_Name bmpnTemp(itBmpNames()); + StripFileExtension(bmpnTemp.filename); + + if (pszFileName ? !_stricmp(pszName,StripPath(bmpnTemp.filename)) : enum_id == bmpnTemp.enum_id) + { + + // select image descriptor + ImageDescriptor const idsc + ( + (IDscFlags)((bmpnTemp.flags & ChunkBMPFlag_FixedPalette ? + IDSCF_FIXEDPALETTE + : + IDSCF_0) + |(pShapeBmpsChunk->GetExtendedData()->flags & GBF_SPRITE ? + IDSCF_SPRITE + : + IDSCF_SUBSHAPE) + |IDSCF_INCLUDED), + itBmpNames().filename, + pShapeBmpsChunk->shapename, + bmpnTemp.flags & ChunkBMPFlag_FixedPalette ? pShapeBmpsChunk->rifname : 0 + ); + ImageDescriptor const * pIdsc = &idsc; + + if (pMatchImageChunk) pIdsc = &pMatchImageChunk->GetLoadImage(idsc); + else db_logf3(("WARNING! no rule to find matching images in game mode %s\n",pGameModeChunk->header->mode_identifier)); + + // load this image + if (GetPath(pszDestBuf,nBufSize,*pIdsc,pEnvDataChunk,bGloballyPalettized)) + { + if (pszSubName) + { + delete[] pszSubName; + } + delete[] pszName; + return pszDestBuf; + } + } + } + } + + if (pszSubName) + { + if (!bShapeInGm) + db_logf3(("CL_LoadImageOnce(): WARNING! shape/sprite %s not found in this RIF file\n",pszSubName)); + else + db_logf3(("CL_LoadImageOnce(): WARNING! shape/sprite %s does not appear to list %s\n",pszSubName,pszName)); + } + + } + + List listMatchImageChunk; + pEnvDataChunk->lookup_child("MATCHIMG",listMatchImageChunk); + + Matching_Images_Chunk * pMicFix = NULL; + Matching_Images_Chunk * pMicNorm = NULL; + + for (LIF itMatchImageChunk(&listMatchImageChunk); !itMatchImageChunk.done(); itMatchImageChunk.next()) + { + Matching_Images_Chunk * pMatchImageChunk = dynamic_cast(itMatchImageChunk()); + db_assert1(pMatchImageChunk); + if (pMatchImageChunk->flags & MICF_FIXEDPALETTE) + pMicFix = pMatchImageChunk; + else + pMicNorm = pMatchImageChunk; + } + + List listShapesSprites; + + List listShapes; + Env_Chunk->lookup_child("REBSHAPE",listShapes); + for (LIF itShapes(&listShapes); !itShapes.done(); itShapes.next()) + { + Shape_Chunk * pShapeChunk = dynamic_cast(itShapes()); + db_assert1(pShapeChunk); + Chunk * pSxfnChunk = pShapeChunk->lookup_single_child("SHPEXTFL"); + if (pSxfnChunk) + { + Shape_External_File_Chunk * pShpExtFnameChunk = dynamic_cast(pSxfnChunk); + db_assert1(pShpExtFnameChunk); + listShapesSprites.add_entry(pShpExtFnameChunk); + } + } + Chunk * pSprChunk = Env_Chunk->lookup_single_child("RSPRITES"); + if (pSprChunk) + { + Chunk_With_Children * pSpritesChunk = dynamic_cast(pSprChunk); + db_assert1(pSpritesChunk); + + List listSprHeadChunks; + pSpritesChunk->lookup_child("SPRIHEAD",listSprHeadChunks); + + for (LIF itSprites(&listSprHeadChunks); !itSprites.done(); itSprites.next()) + { + Chunk_With_Children * pSpriteHead = dynamic_cast(itSprites()); + db_assert1(pSpriteHead); + listShapesSprites.add_entry(pSpriteHead); + } + } + + int bShapeFound = pszSubName ? false : true; + + for (LIF itShapesSprites(&listShapesSprites); !itShapesSprites.done(); itShapesSprites.next()) + { + char * pszSubRifName = RiffBasename(itShapesSprites()); + + if (pszSubName) + { + if (_stricmp(pszSubRifName,pszSubName)) // must match shapes name exactly + { + delete[] pszSubRifName; + continue; + } + bShapeFound = true; + } + + Chunk * pBmpLstStChunk = itShapesSprites()->lookup_single_child("BMPLSTST"); + if (pBmpLstStChunk) + { + Bitmap_List_Store_Chunk * pBmpListStoreChunk = dynamic_cast(pBmpLstStChunk); + db_assert1(pBmpListStoreChunk); + + for (LIF itBmpName(&pBmpListStoreChunk->bmps); !itBmpName.done(); itBmpName.next()) + { + BMP_Name bmpnTemp(itBmpName()); + StripFileExtension(bmpnTemp.filename); + + if (pszFileName ? !_stricmp(pszName,StripPath(bmpnTemp.filename)) : enum_id == bmpnTemp.enum_id) + { + + // select image descriptor + char * pszRifName = RiffBasename(pEnvDataChunk); + ImageDescriptor const idsc + ( + (IDscFlags)((bmpnTemp.flags & ChunkBMPFlag_FixedPalette ? + IDSCF_FIXEDPALETTE + : + IDSCF_0) + |(pBmpListStoreChunk->GetExtendedData()->flags & GBF_SPRITE ? + IDSCF_SPRITE + : + IDSCF_SUBSHAPE) + |IDSCF_INCLUDED), + itBmpName().filename, + pszSubRifName, + bmpnTemp.flags & ChunkBMPFlag_FixedPalette ? pszRifName : 0 + ); + ImageDescriptor const * pIdsc = &idsc; + delete[] pszRifName; + + if (bmpnTemp.flags & ChunkBMPFlag_FixedPalette) + { + if (pMicFix) pIdsc = &pMicFix->GetLoadImage(idsc); + else db_log3("CL_LoadImageOnce(): WARNING! no rule to find fixed palette matching images in environment data\n"); + } + else + { + if (pMicNorm) pIdsc = &pMicNorm->GetLoadImage(idsc); + else db_log3("CL_LoadImageOnce(): WARNING! no rule to find matching images in environment data (interface engine?)\n"); + } + + // load this image + if (GetPath(pszDestBuf,nBufSize,*pIdsc,pEnvDataChunk,bGloballyPalettized)) + { + delete[] pszSubRifName; + if (pszSubName) + { + delete[] pszSubName; + } + delete[] pszName; + return pszDestBuf; + } + } + } + } + delete[] pszSubRifName; + } + + if (pszSubName) + { + if (!bShapeFound) + db_logf3(("CL_LoadImageOnce(): WARNING! shape/sprite %s not found in this RIF file\n",pszSubName)); + else + db_logf3(("CL_LoadImageOnce(): WARNING! shape/sprite %s does not appear to list %s\n",pszSubName,pszName)); + delete[] pszSubName; + } + + // not found in game textures, so look in default + + else // but only if there is no virtual shape directory + { + Chunk * pBmpNames = pEnvDataChunk->lookup_single_child("BMPNAMES"); + if (pBmpNames) + { + Global_BMP_Name_Chunk * pGbnc = dynamic_cast(pBmpNames); + db_assert1(pGbnc); + + for (LIF itBmpName(&pGbnc->bmps); !itBmpName.done(); itBmpName.next()) + { + BMP_Name bmpnTemp(itBmpName()); + StripFileExtension(bmpnTemp.filename); + + if (pszFileName ? !_stricmp(pszName,StripPath(bmpnTemp.filename)) : enum_id == bmpnTemp.enum_id) + { + // select image descriptor + ImageDescriptor const idsc (bmpnTemp.flags & ChunkBMPFlag_FixedPalette ? IDSCF_FIXEDPALETTE : IDSCF_0, itBmpName().filename); + ImageDescriptor const * pIdsc = &idsc; + + if (bmpnTemp.flags & ChunkBMPFlag_FixedPalette) + { + if (pMicFix) pIdsc = &pMicFix->GetLoadImage(idsc); + else db_log3("CL_LoadImageOnce(): WARNING! no rule to find fixed palette matching images in environment data\n"); + } + else + { + if (pMicNorm) pIdsc = &pMicNorm->GetLoadImage(idsc); + else db_log3("CL_LoadImageOnce(): WARNING! no rule to find matching images in environment data (interface engine?)\n"); + } + + // load this image + if (GetPath(pszDestBuf,nBufSize,*pIdsc,pEnvDataChunk,bGloballyPalettized)) + { + delete[] pszName; + return pszDestBuf; + } + } + } + } + } + delete[] pszName; + return NULL; + } + default: // invalid arguments + db_log1("CL_LoadImageOnce(): ERROR: invalid parameter passed to CL_GetImageFileName()"); + return NULL; + } +} + +extern "C" extern void CheckForWindowsMessages(void); + +int CL_LoadImageOnce(char const * pszFileName, unsigned fFlagsEtc) +{ + // safe to handle windows messages at this point (I think - JCWH) + CheckForWindowsMessages(); + + // get the filename + char szBuf[MAX_PATH]; + if (!CL_GetImageFileName(szBuf,sizeof szBuf/sizeof szBuf[0],pszFileName,fFlagsEtc)) + { + db_log1("CL_LoadImageOnce(): ERROR: unable to determine path of file"); + return GEI_NOTLOADED; + } + + db_logf4(("\tLoading '%s'",szBuf)); + + // already loaded ? + int iExistingImage = GetExistingImageNum(szBuf); + if (GEI_NOTLOADED != iExistingImage) + { + db_logf4(("\tImage already loaded to image number %d",iExistingImage)); + return iExistingImage; + } + + // what flags do we want? + unsigned fAwLoad = AW_TLF_DEFAULT; + if (fFlagsEtc & LIO_VIDMEM) + fAwLoad |= AW_TLF_VIDMEM; + if (fFlagsEtc & LIO_TRANSPARENT) + fAwLoad |= AW_TLF_TRANSP; + if (fFlagsEtc & LIO_CHROMAKEY) + fAwLoad |= AW_TLF_CHROMAKEY; + if (fFlagsEtc & LIO_LOADMIPMAPS) + db_log1("CL_LoadImageOnce(): WARNING: mip maps not supported yet - will not be created/loaded"); + + // what are we loading into ? + switch (fFlagsEtc & _LIO_SURFTYPEMASK) + { + case LIO_CHIMAGE: + { + db_log1("CL_LoadImageOnce(): WARNING: having to call LoadImageCH()"); + IMAGEHEADER * pImageHdr = GetImageHeader(); + db_assert1(pImageHdr); + memset(pImageHdr,0,sizeof(IMAGEHEADER)); + if (LoadImageCH(szBuf,pImageHdr)) + return NumImages-1; + else + { + db_log1("CL_LoadImageOnce(): ERROR: LoadImageCH() failed"); + return GEI_NOTLOADED; + } + } + case LIO_DDSURFACE: + { + #if CL_SUPPORT_FASTFILE + unsigned nFastFileLen; + void const * pFastFileData = ffreadbuf(szBuf,&nFastFileLen); + if (pFastFileData) + { + db_log4("\tfile is in a fast file"); + unsigned nWidth, nHeight; + AW_BACKUPTEXTUREHANDLE hBackup = NULL; + DDSurface * pSurface = + AwCreateSurface + ( + fFlagsEtc & LIO_RESTORABLE ? "pxfXYB" : "pxfXY", + pFastFileData, + nFastFileLen, + fAwLoad, + &nWidth, + &nHeight, + &hBackup + ); + if (pSurface) + { + IMAGEHEADER * pImageHdr = GetImageHeader(); + db_assert1(pImageHdr); + memset(pImageHdr,0,sizeof(IMAGEHEADER)); + pImageHdr->ImageWidth = nWidth; + pImageHdr->ImageHeight = nHeight; + db_assert1(sizeof pImageHdr->ImageName / sizeof pImageHdr->ImageName[0] > strlen(szBuf)); + strcpy(pImageHdr->ImageName,szBuf); + pImageHdr->DDSurface = pSurface; + pImageHdr->hBackup = hBackup; + db_logf4(("\tloaded to image number %d",NumImages-1)); + #if CL_SUPPORT_ALTTAB + if (fFlagsEtc & LIO_RESTORABLE) + #ifdef NDEBUG + ATIncludeSurface(pSurface,hBackup); + #else + { + char szDbInf[512]; + sprintf(szDbInf,"Name \"%s\" Number %d",szBuf,NumImages-1); + ATIncludeSurfaceDb(pSurface,hBackup,szDbInf); + } + #endif + #endif // CL_SUPPORT_ALTTAB + return NumImages-1; + } + else + { + db_log1("CL_LoadImageOnce(): ERROR copying data to surface"); + return GEI_NOTLOADED; + } + } + else + #endif // CL_SUPPORT_FASTFILE + { + #if !defined(CL_SUPPORTONLY_FASTFILE) || !CL_SUPPORTONLY_FASTFILE + db_log4("\tloading the actual file"); + unsigned nWidth, nHeight; + AW_BACKUPTEXTUREHANDLE hBackup = NULL; + DDSurface * pSurface = + AwCreateSurface + ( + fFlagsEtc & LIO_RESTORABLE ? "sfXYB" : "sfXY", + &szBuf[0], + fAwLoad, + &nWidth, + &nHeight, + &hBackup + ); + if (pSurface) + { + IMAGEHEADER * pImageHdr = GetImageHeader(); + db_assert1(pImageHdr); + memset(pImageHdr,0,sizeof(IMAGEHEADER)); + pImageHdr->ImageWidth = nWidth; + pImageHdr->ImageHeight = nHeight; + db_assert1(sizeof pImageHdr->ImageName / sizeof pImageHdr->ImageName[0] > strlen(szBuf)); + strcpy(pImageHdr->ImageName,szBuf); + pImageHdr->DDSurface = pSurface; + pImageHdr->hBackup = hBackup; + db_logf4(("\tloaded to image number %d",NumImages-1)); + db_logf4(("\t\tsurface:%p",pSurface)); + #if CL_SUPPORT_ALTTAB + if (fFlagsEtc & LIO_RESTORABLE) + #ifdef NDEBUG + ATIncludeSurface(pSurface,hBackup); + #else + { + char szDbInf[512]; + sprintf(szDbInf,"Name \"%s\" Number %d",szBuf,NumImages-1); + ATIncludeSurfaceDb(pSurface,hBackup,szDbInf); + } + #endif + #endif // CL_SUPPORT_ALTTAB + return NumImages-1; + } + else + { + db_log1("CL_LoadImageOnce(): ERROR copying data to surface"); + return GEI_NOTLOADED; + } + #elif !CL_SUPPORT_FASTFILE + #error "CL_SUPPORTONLY_FASTFILE set but CL_SUPPORT_FASTFILE not set" + #endif // !CL_SUPPORTONLY_FASTFILE + } + //db_msg1("THIS CODE SHOULD BE UNREACHABLE"); + } + case LIO_D3DTEXTURE: + { + fAwLoad |= AW_TLF_COMPRESS; // required on some cards!! + #if CL_SUPPORT_FASTFILE + unsigned nFastFileLen; + void const * pFastFileData = ffreadbuf(szBuf,&nFastFileLen); + if (pFastFileData) + { + db_log4("\tfile is in a fast file"); + unsigned nWidth, nHeight; + AW_BACKUPTEXTUREHANDLE hBackup = NULL; + D3DTexture * pTexture = + AwCreateTexture + ( + fFlagsEtc & LIO_RESTORABLE ? "pxfWHB" : "pxfWH", + pFastFileData, + nFastFileLen, + fAwLoad, + &nWidth, + &nHeight, + &hBackup + ); + if (pTexture) + { + IMAGEHEADER * pImageHdr = GetImageHeader(); + db_assert1(pImageHdr); + memset(pImageHdr,0,sizeof(IMAGEHEADER)); + pImageHdr->ImageWidth = nWidth; + pImageHdr->ImageHeight = nHeight; + db_assert1(sizeof pImageHdr->ImageName / sizeof pImageHdr->ImageName[0] > strlen(szBuf)); + strcpy(pImageHdr->ImageName,szBuf); + pImageHdr->D3DTexture = pTexture; + pImageHdr->hBackup = hBackup; + db_logf4(("\tloaded to image number %d",NumImages-1)); + + /* KJL 16:05:50 26/02/98 - attempt to get a texture handle */ + { + int gotTextureHandle = GetTextureHandle(pImageHdr); + db_assert1(gotTextureHandle==TRUE); + } + + #if CL_SUPPORT_ALTTAB + if (fFlagsEtc & LIO_RESTORABLE) + #ifdef NDEBUG + ATIncludeTexture(pTexture,hBackup); + #else + { + char szDbInf[512]; + sprintf(szDbInf,"Name \"%s\" Number %d",szBuf,NumImages-1); + ATIncludeTextureDb(pTexture,hBackup,szDbInf); + } + #endif + #endif // CL_SUPPORT_ALTTAB + return NumImages-1; + } + else + { + db_log1("CL_LoadImageOnce(): ERROR copying data to texture"); + return GEI_NOTLOADED; + } + } + else + #endif // CL_SUPPORT_FASTFILE + { + #if !defined(CL_SUPPORTONLY_FASTFILE) || !CL_SUPPORTONLY_FASTFILE + db_log4("\tloading the actual file"); + unsigned nWidth, nHeight; + AW_BACKUPTEXTUREHANDLE hBackup = NULL; + D3DTexture * pTexture = + AwCreateTexture + ( + fFlagsEtc & LIO_RESTORABLE ? "sfWHB" : "sfWH", + &szBuf[0], + fAwLoad, + &nWidth, + &nHeight, + &hBackup + ); + if (pTexture) + { + IMAGEHEADER * pImageHdr = GetImageHeader(); + db_assert1(pImageHdr); + memset(pImageHdr,0,sizeof(IMAGEHEADER)); + pImageHdr->ImageWidth = nWidth; + pImageHdr->ImageHeight = nHeight; + db_assert1(sizeof pImageHdr->ImageName / sizeof pImageHdr->ImageName[0] > strlen(szBuf)); + strcpy(pImageHdr->ImageName,szBuf); + pImageHdr->D3DTexture = pTexture; + pImageHdr->hBackup = hBackup; + db_logf4(("\tloaded to image number %d",NumImages-1)); + + /* KJL 16:05:50 26/02/98 - attempt to get a texture handle */ + { + int gotTextureHandle = GetTextureHandle(pImageHdr); + db_assert1(gotTextureHandle==TRUE); + } + + #if CL_SUPPORT_ALTTAB + if (fFlagsEtc & LIO_RESTORABLE) + #ifdef NDEBUG + ATIncludeTexture(pTexture,hBackup); + #else + { + char szDbInf[512]; + sprintf(szDbInf,"Name \"%s\" Number %d",szBuf,NumImages-1); + ATIncludeTextureDb(pTexture,hBackup,szDbInf); + } + #endif + #endif // CL_SUPPORT_ALTTAB + return NumImages-1; + } + else + { + db_log1("CL_LoadImageOnce(): ERROR copying data to texture"); + return GEI_NOTLOADED; + } + #elif !CL_SUPPORT_FASTFILE + #error "CL_SUPPORTONLY_FASTFILE set but CL_SUPPORT_FASTFILE not set" + #endif // !CL_SUPPORTONLY_FASTFILE + } + //db_msg1("THIS CODE SHOULD BE UNREACHABLE"); + } + default: + db_log1("CL_LoadImageOnce(): ERROR: Invalid destination surface specification"); + return GEI_NOTLOADED; + } +} + diff --git a/3dc/win95/CHNKTEXI.H b/3dc/win95/CHNKTEXI.H new file mode 100644 index 0000000..88a6b7e --- /dev/null +++ b/3dc/win95/CHNKTEXI.H @@ -0,0 +1,70 @@ +#ifndef _INCLUDED_CHNKTEXI_H_ +#define _INCLUDED_CHNKTEXI_H_ + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +/* image number for already loaded image - really an internal function */ +#define GEI_NOTLOADED (-1) +extern int GetExistingImageNum(char const * pszActualFileName); + +enum /* flags, etc */ +{ + /* destination surface type */ + LIO_CHIMAGE = 0x00000000U, /* Chris Humphries texture */ + LIO_DDSURFACE = 0x00000001U, /* Direct Draw Surface */ + LIO_D3DTEXTURE = 0x00000002U, /* Direct 3D Texture */ + _LIO_SURFTYPEMASK= 0x00000003U, + /* target memory type for DDSURFACE only - D3DTextures dest depends on driver */ + LIO_SYSMEM = 0x00000000U, /* system memory */ + LIO_VIDMEM = 0x00000004U, /* video memory */ + /* transparency flags - unless specified in the file */ + LIO_NONTRANSP = 0x00000000U, /* no transparency */ + LIO_TRANSPARENT = 0x00000008U, /* has transparency */ + /* alpha or chroma key? */ + LIO_USEALPHA = 0x00000000U, /* use alpha mask if available instead of chroma keying */ + LIO_CHROMAKEY = 0x00000010U, /* use chroma key even if surface has alpha channel */ + /* path flags */ + LIO_ABSOLUTEPATH = 0x00000000U, /* path is correct */ + LIO_RELATIVEPATH = 0x00000020U, /* path is relative to a textures directory */ + LIO_RIFFPATH = 0x00000040U, /* current RIF file used to build path and extension */ + _LIO_PATHTYPEMASK= 0x00000060U, + /* mip maps? */ + LIO_NOMIPMAPS = 0x00000000U, /* no mip maps */ + LIO_LOADMIPMAPS = 0x00000080U, /* load mip maps if available */ + /* restorable ? */ + LIO_NORESTORE = 0x00000000U, /* not going to be restorable */ + LIO_RESTORABLE = 0x00000100U, /* put something in imageheader to allow restoring */ +}; + +/* CL_LoadImageOnce relies on this value to be 1 greater + than the index of the last loaded image */ +extern int NumImages; + +/* directories used with the LIO_RIFFPATH flag */ +extern char const * GameTex_Directory; +extern char const * SubShps_Directory; +extern char const * GenTex_Directory; +extern char const * FixTex_Directory; +extern char const * ToolsTex_Directory; + +/* game mode for use with the above */ +extern char const * cl_pszGameMode; + +/* directories used with the LIO_RELATIVEPATH flag + these are searched in order*/ +extern char const * FirstTex_Directory; +extern char const * SecondTex_Directory; + +/* returns GEI_NOTLOADED on failure */ +extern int CL_LoadImageOnce(char const * pszFileName, unsigned fFlagsEtc); + +/* returns NULL on failure, or pointer to pszDestBuf on success, nBufSize includes nul terminator */ +extern char * CL_GetImageFileName(char * pszDestBuf, unsigned nBufSize, char const * pszFileName, unsigned fFlagsEtc); + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif /* !_INCLUDED_CHNKTEXI_H_ */ diff --git a/3dc/win95/CHNKTYPE.CPP b/3dc/win95/CHNKTYPE.CPP new file mode 100644 index 0000000..bddaaae --- /dev/null +++ b/3dc/win95/CHNKTYPE.CPP @@ -0,0 +1,1221 @@ +#include "chunk.hpp" +#include +#include "chnktype.hpp" + +#if engine + +#define UseLocalAssert No +#include "ourasert.h" +#define assert(x) GLOBALASSERT(x) + +#else + +#if cencon +#include "ccassert.h" +#else +#include +#endif + +#endif + +#ifdef cencon +#define new my_new +#endif + +// misc data structures functions +BOOL operator==(const obinfile &o1, const obinfile &o2) +{ + return (&o1 == &o2); +} +BOOL operator!=(const obinfile &o1, const obinfile &o2) +{ + return (&o1 != &o2); +} + +BOOL operator==(const shpinfile &s1, const shpinfile &s2) +{ + return (&s1 == &s2); +} +BOOL operator!=(const shpinfile &s1, const shpinfile &s2) +{ + return (&s1 != &s2); +} + +BOOL operator== (const ChunkUV_List &c1, const ChunkUV_List &c2) +{ + return(&c1 == &c2); +} + +BOOL operator!= (const ChunkUV_List &c1, const ChunkUV_List &c2) +{ + return(&c1 != &c2); +} + +BOOL operator== (const ObjectID &o1, const ObjectID &o2) +{ + return((o1.id1==o2.id1) && (o1.id2==o2.id2)); +} + +BOOL operator!= (const ObjectID &o1, const ObjectID &o2) +{ + return((o1.id1!=o2.id1) || (o1.id2!=o2.id2)); +} + +ObjectID Minimum(const ObjectID &o1,const ObjectID &o2) +{ + if(o1.id1o2.id1) return o2; + if(o1.id2> 16); + + return uv_index; + } + else + { + //uvindex is just in the top 16 bits + return (colour >> 16); + } + +} + +unsigned int ChunkPoly::GetTextureIndex() +{ + return (colour & CHUNK_TEXTUREINDEX_MASK); +} + +void ChunkPoly::SetUVIndex(unsigned int uv_index) +{ + assert(uv_index<=CHUNK_MAX_UVINDEX); + //clear the old uvindex + colour &=~CHUNK_UVINDEX_MASK; + + if(uv_index<65536) + { + //fit uv index into the top 16 bits if it will fit , to maintain compatibility with + //old chunk loaders + colour |= (uv_index<<16); + } + else + { + //put the bottom 16 bits of the uv_index in the top 16 bits of the colour + colour |= (uv_index & 0xffff) << 16; + //put the next 4 bits of the uv_index in the lower middle 4 bits of the colour + uv_index>>=16; + colour |= (uv_index <<12); + } + +} + +void ChunkPoly::SetTextureIndex(unsigned int texture_index) +{ + assert(texture_index<=CHUNK_MAX_TEXTUREINDEX); + + colour &=~ CHUNK_TEXTUREINDEX_MASK; + colour |= texture_index; +} + + + +////////////////////////////////////////////// + +ChunkVector operator+(const ChunkVector& a, const ChunkVector& b) +{ + ChunkVector v; + v.x=a.x+b.x; + v.y=a.y+b.y; + v.z=a.z+b.z; + return v; +} + + +ChunkVector operator-(const ChunkVector& a, const ChunkVector& b) +{ + ChunkVector v; + v.x=a.x-b.x; + v.y=a.y-b.y; + v.z=a.z-b.z; + return v; +} + +ChunkVector& ChunkVector::operator+=(const ChunkVector& a) +{ + x += a.x; + y += a.y; + z += a.z; + + return *this; +} + + + +ChunkVector& ChunkVector::operator-=(const ChunkVector& a) +{ + x -= a.x; + y -= a.y; + z -= a.z; + + return *this; +} + + + +#if engine +ChunkVector::operator VECTORCH () const +{ + VECTORCH v; + v.vx = x; + v.vy = y; + v.vz = z; + + return(v); +} +#endif +ChunkVector::operator ChunkVectorInt () const +{ + ChunkVectorInt v; + v.x = (int)x; + v.y = (int)y; + v.z = (int)z; + + return(v); +} +ChunkVector::operator ChunkVectorFloat () const +{ + ChunkVectorFloat v; + v.x = (float)x; + v.y = (float)y; + v.z = (float)z; + + return(v); +} + +ChunkVector operator*(const ChunkVector & a, const double s) +{ + ChunkVector v; + v.x = a.x * s; + v.y = a.y * s; + v.z = a.z * s; + return(v); + +} + +ChunkVector operator/(const ChunkVector & a, const double s) +{ + ChunkVector v; + v.x = a.x / s; + v.y = a.y / s; + v.z = a.z / s; + return(v); +} + +ChunkVector operator*(const ChunkVector& a, const ChunkVector& b) +{ + ChunkVector v; + v.x=a.y*b.z - a.z*b.y; + v.y=a.z*b.x - a.x*b.z; + v.z=a.x*b.y - a.y*b.x; + return v; +} + + +double dot(const ChunkVector& a, const ChunkVector& b) +{ + return(a.x*b.x + a.y*b.y + a.z*b.z); +} + +double mod(const ChunkVector& a) +{ + return(sqrt(dot(a,a))); +} + +int ChunkVector::norm() +{ + double modulos = mod(*this); + + if(modulos == 0)return(0); + + x /=modulos; + y /= modulos; + z /= modulos; + + return(1); + +} +////////////////////////////////////////////// +ChunkVectorInt operator+(const ChunkVectorInt& a, const ChunkVectorInt& b) +{ + ChunkVectorInt v; + v.x=a.x+b.x; + v.y=a.y+b.y; + v.z=a.z+b.z; + return v; +} + + +ChunkVectorInt operator-(const ChunkVectorInt& a, const ChunkVectorInt& b) +{ + ChunkVectorInt v; + v.x=a.x-b.x; + v.y=a.y-b.y; + v.z=a.z-b.z; + return v; +} + +ChunkVectorInt& ChunkVectorInt::operator+=(const ChunkVectorInt& a) +{ + x += a.x; + y += a.y; + z += a.z; + + return *this; +} + + + +ChunkVectorInt& ChunkVectorInt::operator-=(const ChunkVectorInt& a) +{ + x -= a.x; + y -= a.y; + z -= a.z; + + return *this; +} + + + +#if engine +ChunkVectorInt::operator VECTORCH () const +{ + VECTORCH v; + v.vx = x; + v.vy = y; + v.vz = z; + + return(v); +} +#endif + +ChunkVectorInt operator*(const ChunkVectorInt & a, const double s) +{ + ChunkVectorInt v; + v.x =(int) (a.x * s); + v.y =(int) (a.y * s); + v.z =(int) (a.z * s); + return(v); + +} + +ChunkVectorInt operator/(const ChunkVectorInt & a, const double s) +{ + ChunkVectorInt v; + v.x =(int) (a.x / s); + v.y =(int) (a.y / s); + v.z =(int) (a.z / s); + return(v); +} + +double mod(const ChunkVectorInt& a) +{ + return(sqrt((double)a.x*(double)a.x+(double)a.y*(double)a.y+(double)a.z*(double)a.z)); +} + +int ChunkVectorInt::norm() +{ + double modulos = mod(*this) /65536.0; + + if(modulos == 0)return(0); + + x =(int) (x/modulos); + y =(int) (y/modulos); + z =(int) (z/modulos); + + return(1); + +} +//////////////////////////////////////////////////////// +ChunkVectorFloat operator+(const ChunkVectorFloat& a, const ChunkVectorFloat& b) +{ + ChunkVectorFloat v; + v.x=a.x+b.x; + v.y=a.y+b.y; + v.z=a.z+b.z; + return v; +} + + +ChunkVectorFloat operator-(const ChunkVectorFloat& a, const ChunkVectorFloat& b) +{ + ChunkVectorFloat v; + v.x=a.x-b.x; + v.y=a.y-b.y; + v.z=a.z-b.z; + return v; +} + +ChunkVectorFloat& ChunkVectorFloat::operator+=(const ChunkVectorFloat& a) +{ + x += a.x; + y += a.y; + z += a.z; + + return *this; +} + + + +ChunkVectorFloat& ChunkVectorFloat::operator-=(const ChunkVectorFloat& a) +{ + x -= a.x; + y -= a.y; + z -= a.z; + + return *this; +} + +ChunkVectorFloat operator*(const ChunkVectorFloat & a, const double s) +{ + ChunkVectorFloat v; + v.x =(float) (a.x * s); + v.y =(float) (a.y * s); + v.z =(float) (a.z * s); + return(v); + +} + +ChunkVectorFloat operator/(const ChunkVectorFloat & a, const double s) +{ + ChunkVectorFloat v; + v.x =(float) (a.x / s); + v.y =(float) (a.y / s); + v.z =(float) (a.z / s); + return(v); +} + +#if engine +ChunkVectorFloat::operator VECTORCH () const +{ + VECTORCH v; + v.vx =(int) (x*65536); + v.vy =(int) (y*65536); + v.vz =(int) (z*65536); + + return(v); +} +#endif +int ChunkVectorFloat::norm() +{ + float modulos =(float) mod(*this); + + if(modulos == 0)return(0); + + x /= modulos; + y /= modulos; + z /= modulos; + + return(1); +} +double mod(const ChunkVectorFloat& a) +{ + return(sqrt((double)a.x*(double)a.x+(double)a.y*(double)a.y+(double)a.z*(double)a.z)); +} +//////////////////////////////////////////////////////// +ChunkShape::~ChunkShape() +{ + + if (v_list) delete [] v_list; + if (v_normal_list) delete [] v_normal_list; + if (p_normal_list) delete [] p_normal_list; + if (poly_list) delete [] poly_list; + if (uv_list) delete [] uv_list; + if (texture_fns) + for (int i = 0; inum_polys; + num_verts=startframe->num_verts; + flags=startframe->flags|animframeflag_interpolated_frame; + num_interp_frames=0; + pad3=0; + pad4=0; + + v_list=new ChunkVector[num_verts]; + p_normal_list=new ChunkVector[num_polys]; + + double start_mult=startwt/(double)(startwt+endwt); + double end_mult=endwt/(double)(startwt+endwt); + + for(int i=0;iv_list[i].x*start_mult+endframe->v_list[i].x*end_mult; + v_list[i].y=startframe->v_list[i].y*start_mult+endframe->v_list[i].y*end_mult; + v_list[i].z=startframe->v_list[i].z*start_mult+endframe->v_list[i].z*end_mult; + } + + for(i=0;iv_list[cs->poly_list[i].vert_ind[1]]-cs->v_list[cs->poly_list[i].vert_ind[0]]; + ChunkVector v2=cs->v_list[cs->poly_list[i].vert_ind[2]]-cs->v_list[cs->poly_list[i].vert_ind[0]]; + ChunkVector norm; + norm.x=v1.y*v2.z-v1.z*v2.y; + norm.y=v1.z*v2.x-v1.x*v2.z; + norm.z=v1.x*v2.y-v1.y*v2.x; + double length=sqrt(norm.x*norm.x+norm.y*norm.y+norm.z*norm.z); + cs->p_normal_list[i]=norm*(1/length); + } + +} +*/ +ChunkAnimFrame& ChunkAnimFrame::operator=(const ChunkAnimFrame &frm) +{ + + if(name) delete [] name; + if(v_list) delete [] v_list; + if(p_normal_list) delete [] p_normal_list; + + + if(frm.name) + { + name=new char[strlen(frm.name)+1]; + strcpy(name,frm.name); + } + else + name=0; + + num_polys=frm.num_polys; + num_verts=frm.num_verts; + + if(num_polys) + { + p_normal_list=new ChunkVectorFloat[num_polys]; + for(int i=0;i* poly_not_in_bb) +{ + if(!cs) return; + num_verts=cs->num_verts; + if(!v_normal_list)v_normal_list=new ChunkVectorFloat[cs->num_verts]; + for(int i=0;inum_polys;i++) + { + const ChunkPoly* cp=&cs->poly_list[i]; + for(int j=0;jnum_verts;j++) + { + int vi=cp->vert_ind[j]; + for(int k=0;kp_normal_list[i]; + } + } + } + for(i=0;inum_verts]; + for(i=0;inum_verts;i++) + { + vert_in_bb[i]=0; + } + for(i=0;inum_polys;i++) + { + if(poly_not_in_bb->contains(i))continue; + const ChunkPoly* cp=&cs->poly_list[i]; + for(int j=0;jnum_verts;j++) + { + vert_in_bb[cp->vert_ind[j]]=1; + } + + } + } + for(i=0;inum_verts; j++) + { + if(vert_in_bb && !vert_in_bb[j]) continue; + max.x = max(max.x, caf->v_list[j].x); + max.y = max(max.y, caf->v_list[j].y); + max.z = max(max.z, caf->v_list[j].z); + + min.x = min(min.x, caf->v_list[j].x); + min.y = min(min.y, caf->v_list[j].y); + min.z = min(min.z, caf->v_list[j].z); + + double temp_rad = mod(caf->v_list[j]); + + radius = max (radius, (float)temp_rad); + } + } + if(vert_in_bb) delete [] vert_in_bb; +} + +void ChunkAnimSequence::DeleteInterpolatedFrames() +{ + int NewNumFrames=NumFrames; + for(int i=0;iflags & animframeflag_interpolated_frame)NewNumFrames--; + } + if(NewNumFrames==NumFrames)return; + + int framepos=0; + for(i=0;iflags & animframeflag_interpolated_frame) continue; + Frames[framepos++]=Frames[i]; + } + NumFrames=NewNumFrames; + Frames=(ChunkAnimFrame**)realloc(Frames,sizeof(ChunkAnimFrame*)*NumFrames); + +} + +void ChunkAnimSequence::GenerateInterpolatedFrames(ChunkShape const *cs) +{ + DeleteInterpolatedFrames(); + /* + int NewNumFrames=NumFrames; + for(int i=0;inum_interp_frames; + } + if(NewNumFrames==NumFrames) return; + + ChunkAnimFrame** NewFrames=new ChunkAnimFrame*[NewNumFrames]; + + int framepos=0; + for( i=0;inum_interp_frames==0)continue; + + ChunkAnimFrame* startframe=Frames[i]; + ChunkAnimFrame* endframe=Frames[(i+1)%NumFrames]; + + for(int j=0;jnum_interp_frames;j++) + { + NewFrames[framepos++]=new ChunkAnimFrame(startframe,endframe,startframe->num_interp_frames-j,j+1,cs); + } + } + delete [] Frames; + Frames=NewFrames; + NumFrames=NewNumFrames; + */ +} \ No newline at end of file diff --git a/3dc/win95/CHNKTYPE.HPP b/3dc/win95/CHNKTYPE.HPP new file mode 100644 index 0000000..9a3a57d --- /dev/null +++ b/3dc/win95/CHNKTYPE.HPP @@ -0,0 +1,396 @@ +#ifndef _chnktype_hpp +#define _chnktype_hpp 1 + +#if engine +#include "3dc.h" +#endif +#include "list_tem.hpp" + +struct ChunkVectorInt; +struct ChunkVectorFloat; + +struct ChunkVector +{ + + double x; + double y; + double z; + + + ChunkVector friend operator+(const ChunkVector&, const ChunkVector&); + ChunkVector friend operator-(const ChunkVector&, const ChunkVector&); + ChunkVector& operator+=(const ChunkVector&); + ChunkVector& operator-=(const ChunkVector&); + + ChunkVector friend operator*(const ChunkVector&, const double); + ChunkVector friend operator/(const ChunkVector&, const double); + + ChunkVector friend operator*(const ChunkVector&, const ChunkVector&); //cross prod + + + + #if engine + operator VECTORCH () const; + #endif + operator ChunkVectorInt () const; + operator ChunkVectorFloat () const; + + friend double dot(const ChunkVector&, const ChunkVector&);//dot product + friend double mod(const ChunkVector&);//magnitude of vector + int norm(); //normalize +}; + +struct ChunkVectorInt +{ + + int x; + int y; + int z; + + + ChunkVectorInt friend operator+(const ChunkVectorInt&, const ChunkVectorInt&); + ChunkVectorInt friend operator-(const ChunkVectorInt&, const ChunkVectorInt&); + ChunkVectorInt& operator+=(const ChunkVectorInt&); + ChunkVectorInt& operator-=(const ChunkVectorInt&); + + ChunkVectorInt friend operator*(const ChunkVectorInt&, const double); + ChunkVectorInt friend operator/(const ChunkVectorInt&, const double); + + //ChunkVectorInt friend operator*(const ChunkVectorInt&, const ChunkVectorInt&); //cross prod + + + + #if engine + operator VECTORCH () const; + #endif + + //friend double dot(const ChunkVector&, const ChunkVector&);//dot product + friend double mod(const ChunkVectorInt&);//magnitude of vector + int norm(); //normalize to 65536 +}; +struct ChunkVectorFloat +{ + + float x; + float y; + float z; + + ChunkVectorFloat friend operator+(const ChunkVectorFloat&, const ChunkVectorFloat&); + ChunkVectorFloat friend operator-(const ChunkVectorFloat&, const ChunkVectorFloat&); + ChunkVectorFloat& operator+=(const ChunkVectorFloat&); + ChunkVectorFloat& operator-=(const ChunkVectorFloat&); + + ChunkVectorFloat friend operator*(const ChunkVectorFloat&, const double); + ChunkVectorFloat friend operator/(const ChunkVectorFloat&, const double); + + //ChunkVectorInt friend operator*(const ChunkVectorInt&, const ChunkVectorInt&); //cross prod + #if engine + operator VECTORCH () const; + #endif + + //friend double dot(const ChunkVector&, const ChunkVector&);//dot product + friend double mod(const ChunkVectorFloat&);//magnitude of vector + int norm(); //normalize to 1 +}; + +struct ChunkUV +{ + + float u; + float v; + +}; + +// in integers I suppose + +struct ChunkMatrix +{ + + int mat11; + int mat12; + int mat13; + + int mat21; + int mat22; + int mat23; + + int mat31; + int mat32; + int mat33; + +}; + + +struct ChunkUV_List +{ + int num_verts; + ChunkUV vert[4]; + + // for list iterator + friend BOOL operator== (const ChunkUV_List &, const ChunkUV_List &); + friend BOOL operator!= (const ChunkUV_List &, const ChunkUV_List &); + +}; + +class ChunkPoly +{ +public: + + int engine_type; + int normal_index; + int flags; + unsigned int colour; + + int num_verts; + + int vert_ind[4]; + + + //functions for gettings and setting texture and uv indeces in the colour + unsigned int GetUVIndex(); + unsigned int GetTextureIndex(); + + void SetUVIndex(unsigned int uv_index); + void SetTextureIndex(unsigned int texture_index); + + +}; + + +struct ChunkShape +{ + ChunkShape(); + ~ChunkShape(); + + ChunkShape (const ChunkShape &); + ChunkShape& operator=(const ChunkShape &); + + + float radius; //radius of points about 0,0,0 + + ChunkVectorInt max; + ChunkVectorInt min; + + ChunkVectorInt centre; //average of min and max + float radius_about_centre; + + int num_verts; + ChunkVectorInt * v_list; + + #if UseOldChunkLoader + ChunkVector * float_v_list; + #endif + + //int num_vert_normals; //I don't think num_vert_normals is ever used + ChunkVectorFloat * v_normal_list; + + int num_polys; + ChunkPoly * poly_list; + ChunkVectorFloat * p_normal_list; + + int num_uvs; + ChunkUV_List * uv_list; + + int num_texfiles; + char ** texture_fns; + + void rescale (double); + +}; + +struct ChunkQuat +{ + float x,y,z,w; +}; + + +struct ObjectID +{ + int id1; + int id2; + + friend BOOL operator== (const ObjectID &, const ObjectID &); + friend BOOL operator!= (const ObjectID &, const ObjectID &); + friend ObjectID Minimum(const ObjectID &,const ObjectID &); + +}; + +struct ChunkObject +{ + + ChunkVectorInt location; + + #if UseOldChunkLoader + ChunkVector float_location; + #endif + + ChunkQuat orientation; + + BOOL is_base_object; + + char o_name[50]; + + int index_num; //this won't get changed by update_my_chunkobject + + ObjectID ID; + +}; + + +struct VMod_Arr_Item +{ + VMod_Arr_Item(); + ~VMod_Arr_Item(); + + VMod_Arr_Item(const VMod_Arr_Item & vma); + VMod_Arr_Item & operator=(const VMod_Arr_Item & vma); + + int branch_no; + int flags; + int spare; + int object_index; + + #if UseOldChunkLoader + char * o_name; //replaced by object_index + #endif + + friend BOOL operator==(const VMod_Arr_Item &, const VMod_Arr_Item &); + friend BOOL operator!=(const VMod_Arr_Item &, const VMod_Arr_Item &); + +}; + +struct Adjacent_Module +{ + Adjacent_Module(); + ~Adjacent_Module(); + + Adjacent_Module(const Adjacent_Module & vma); + Adjacent_Module & operator=(const Adjacent_Module & vma); + + int flags; + ChunkVectorInt entry_point; + int object_index; + + #if UseOldChunkLoader + char * o_name; + #endif + + friend BOOL operator==(const Adjacent_Module & am1, const Adjacent_Module & am2); + friend BOOL operator!=(const Adjacent_Module & am1, const Adjacent_Module & am2); + +}; + +class Shape_Chunk; +class Shape_Sub_Shape_Chunk; + +struct a_frame +{ + a_frame() + : shape1a (0), shape1b(0), shape2a(0), shape2b(0) + {} + + Shape_Sub_Shape_Chunk * shape1a; + Shape_Chunk * shape1b; + Shape_Sub_Shape_Chunk * shape2a; + Shape_Chunk * shape2b; + int spare; +}; + + +// Data structures for bits and pieces + +struct obinfile +{ + int filepos; + char name[50]; + size_t length; + + friend BOOL operator==(const obinfile &o1, const obinfile &o2); + friend BOOL operator!=(const obinfile &o1, const obinfile &o2); +}; + +struct shpinfile +{ + int filepos; + int id; + size_t length; + + friend BOOL operator==(const shpinfile &s1, const shpinfile &s2); + friend BOOL operator!=(const shpinfile &s1, const shpinfile &s2); +}; + + +struct poly_change_info +{ + int poly_num; + int vert_num_before; + int vert_num_after; + + friend BOOL operator==(poly_change_info const &f1, poly_change_info const &f2); + friend BOOL operator!=(poly_change_info const &f1, poly_change_info const &f2); +}; + + + +#define animframeflag_not_in_psx 0x00000001 +#define animframeflag_not_in_saturn 0x00000002 +#define animframeflag_interpolated_frame 0x00000004 +struct ChunkAnimFrame +{ + ChunkAnimFrame(); + ~ChunkAnimFrame(); + + ChunkAnimFrame(const ChunkAnimFrame &); + //constructor for interpolated frame + //ChunkAnimFrame(ChunkAnimFrame* startframe,ChunkAnimFrame* endframe,int startwt,int endwt,ChunkShape const *cs); + ChunkAnimFrame& operator=(const ChunkAnimFrame &); + + + char* name; + + int num_polys; + int num_verts; + + ChunkVectorInt * v_list; + ChunkVectorFloat * p_normal_list; + + int flags; + int num_interp_frames; + int pad3,pad4; +}; + + +#define animseqflag_not_in_psx 0x00000001 +#define animseqflag_not_in_saturn 0x00000002 + + +struct ChunkAnimSequence +{ + ChunkAnimSequence(); + ~ChunkAnimSequence(); + + ChunkAnimSequence (const ChunkAnimSequence &); + ChunkAnimSequence& operator=(const ChunkAnimSequence &); + + void DeleteInterpolatedFrames(); + void GenerateInterpolatedFrames(ChunkShape const *cs); + + void UpdateNormalsAndExtents(ChunkShape const *cs,List* poly_not_in_bb=0); + + int SequenceNum; + char* name; + + int NumFrames; + ChunkAnimFrame** Frames; + + int flags; + int pad2,pad3,pad4; + + ChunkVectorInt min; + ChunkVectorInt max; + float radius; + + int num_verts; + ChunkVectorFloat* v_normal_list; +}; +#endif \ No newline at end of file diff --git a/3dc/win95/CHUNKPAL.CPP b/3dc/win95/CHUNKPAL.CPP new file mode 100644 index 0000000..0cf1185 --- /dev/null +++ b/3dc/win95/CHUNKPAL.CPP @@ -0,0 +1,1007 @@ +#include "chunkpal.hpp" +#include "mishchnk.hpp" + +#if engine + +#ifndef UseLocalAssert +#define UseLocalAssert 1 +#endif +#include "ourasert.h" +#define assert(x) GLOBALASSERT(x) + +#else + +#if cencon +#include "ccassert.h" +#else +#include +#endif + +#endif +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(chunkpal) + +/////////////////////////////////////// + +// Class Environment_Palette_Chunk functions + + +void Palette_Outdated(Chunk_With_Children * parent) +{ + if (parent) + { + List plist; + parent->lookup_child("ENVPALET",plist); + for (LIF plit(&plist); !plit.done(); plit.next()) + { + ((Environment_Palette_Chunk *)plit())->flags &= ~EnvPalFlag_UpToDate; + } + } +} + +void FixedPalette_Outdated(Chunk_With_Children * parent) +{ + if (parent) + { + List plist; + parent->lookup_child("PRSETPAL",plist); + for (LIF plit(&plist); !plit.done(); plit.next()) + { + for (LIF findconst(&((Preset_Palette_Chunk *)plit())->pplist); !findconst.done(); findconst.next()) + { + Preset_Palette temp = findconst(); + if (temp.flags & PrePalFlag_Reserved) + { + temp.flags &= ~PrePalFlag_UpToDate; + findconst.change_current(temp); + } + } + } + } +} + +BOOL IsFixedPalette(Chunk_With_Children * parent) +{ + if (parent) + { + List plist; + parent->lookup_child("PRSETPAL",plist); + for (LIF plit(&plist); !plit.done(); plit.next()) + { + for (LIF findconst(&((Preset_Palette_Chunk *)plit())->pplist); !findconst.done(); findconst.next()) + { + if (findconst().flags & PrePalFlag_Reserved) + { + return TRUE; + } + } + } + parent->lookup_child("SETPALST",plist); + for (plit = LIF (&plist); !plit.done(); plit.next()) + { + for (LIF findconst(&((Preset_Palette_Store_Chunk *)plit())->pplist); !findconst.done(); findconst.next()) + { + if (findconst().flags & PrePalFlag_Reserved) + { + return TRUE; + } + } + } + } + return FALSE; +} + +RIF_IMPLEMENT_DYNCREATE("ENVPALET",Environment_Palette_Chunk) + +Environment_Palette_Chunk::~Environment_Palette_Chunk () +{ + if (pixel_data) + { + unsigned char * temp_pd = (unsigned char *)pixel_data; + delete [] temp_pd; + } +} + +size_t Environment_Palette_Chunk::size_chunk() +{ + chunk_size = 12 + 8 + (width * height * 3 + 3 & ~3); + return chunk_size; +} + +void Environment_Palette_Chunk::fill_data_block (char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int*)data_start) = width * height; + *((int*)(data_start+4)) = flags; + + data_start += 8; + + for (int i=0; i<(width*height*3); i++) + { + data_start[i] = pixel_data[i]; + } + +} + + +/////////////////////////////////////// + +// Class Preset_Palette_Chunk functions + + +Preset_Palette::~Preset_Palette () +{ + if (pixel_data) + { + unsigned char * temp_pd = (unsigned char *)pixel_data; + delete [] temp_pd; + } + if (name) delete[] name; +} + +Preset_Palette::Preset_Palette (Preset_Palette const & c) +: size(c.size) +, flags(c.flags) +, reserved1(c.reserved1) +, reserved2(c.reserved2) +, startpos(c.startpos) +, pixel_data(grab_pixel_data(c.size, c.pixel_data)) +, name(0) +{ + if (c.name) + { + name = new char[strlen(c.name)+1]; + strcpy(name,c.name); + } +} + +Preset_Palette & Preset_Palette::operator = (Preset_Palette const & c) +{ + if (pixel_data) + { + unsigned char * temp_pd = (unsigned char *)pixel_data; + delete [] temp_pd; + } + if (name) + { + delete[] name; + name = 0; + } + if (c.name) + { + name = new char[strlen(c.name)+1]; + strcpy(name,c.name); + } + + *(int *)&size = c.size; + *(int *)&flags = c.flags; + *(int *)&reserved1 = c.reserved1; + *(int *)&reserved2 = c.reserved2; + *(int *)&startpos = c.startpos; + + *(const unsigned char * *)&pixel_data = grab_pixel_data(c.size,c.pixel_data); + + return *this; +} + + + +size_t Preset_Palette::size_chunk() const +{ + return 20 + (size * 3 + (name ? strlen(name)+1 : 8) +3 &~3); +} + +void Preset_Palette::fill_data_block (char * data_start) +{ + *(int*)data_start = size; + *(int*)(data_start+4) = flags; + *(int*)(data_start+8) = reserved1; + *(int*)(data_start+12) = reserved2; + *(int*)(data_start+16) = startpos; + + data_start += 20; + + unsigned char const * sptr = pixel_data; + + for (int i=size*3; i; --i, ++sptr, ++data_start) + { + *data_start = *sptr; + } + strcpy(data_start,name ? name : "unnamed"); +} + +RIF_IMPLEMENT_DYNCREATE("PRSETPAL",Preset_Palette_Chunk) + +Preset_Palette_Chunk::Preset_Palette_Chunk(Chunk_With_Children * const parent, char const * sdata, size_t const /*ssize*/) +: Chunk(parent,"PRSETPAL") +, version_num(*(int *)sdata) +, flags(*(int *)(sdata+4)) +, reserved1(*(int *)(sdata+8)) +, reserved2(*(int *)(sdata+12)) +, reserved3(*(int *)(sdata+16)) +{ + int const pplistsize = *(int *)(sdata+20); + sdata += 24; + + for (int i = pplistsize; i; --i) + { + Preset_Palette current(sdata); + sdata += current.size_chunk(); + pplist.add_entry(current); + } +} + + +size_t Preset_Palette_Chunk::size_chunk () +{ + chunk_size = 12 + 24; + + for (LIF li(&pplist); !li.done(); li.next()) + { + chunk_size += li().size_chunk(); + } + + return chunk_size; +} + +void Preset_Palette_Chunk::fill_data_block (char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *(int *) data_start = chunk_size; + + data_start += 4; + + *(int*)data_start = version_num; + *(int*)(data_start+4) = flags; + *(int*)(data_start+8) = reserved1; + *(int*)(data_start+12) = reserved2; + *(int*)(data_start+16) = reserved3; + *(int*)(data_start+20) = pplist.size(); + + data_start += 24; + + for (LIF li(&pplist); !li.done(); li.next()) + { + Preset_Palette current(li()); + + current.fill_data_block(data_start); + data_start += current.size_chunk(); + } +} + + +/////////////////////////////////////// + +// Class Environment_TLT_Chunk functions + + +RIF_IMPLEMENT_DYNCREATE("ENVTXLIT",Environment_TLT_Chunk) + +Environment_TLT_Chunk::Environment_TLT_Chunk (Chunk_With_Children * parent, const char * sdata, size_t ssize) +: Chunk (parent, "ENVTXLIT"), width (*((int*)(sdata))), + num_levels (*((int*)(sdata+4))), flags(*(int *)(sdata+28)), table (0), filename(0) +{ + for (int i=0; i= 32 + width*num_levels) + { + table = new unsigned char [width*num_levels]; + unsigned char * tableptr = table; + unsigned char const * sdataptr = (unsigned char *)(sdata+32); + for (i=width*num_levels; i; --i) + { + *tableptr++ = *sdataptr++; + } + } + +} + +Environment_TLT_Chunk::~Environment_TLT_Chunk () +{ + if (table) delete[] table; + if (filename) delete[] filename; +} + +size_t Environment_TLT_Chunk::size_chunk() +{ + if (flags & ChunkTLTFlag_ExternalFile) + { + if (filename) + { + chunk_size = 12 + 32 + (strlen(filename)+4 & ~3); + } + else + { + chunk_size = 12 + 32 + 4; + } + } + else + { + chunk_size = 12 + 32 + width * num_levels; + } + return(chunk_size); + +} + +void Environment_TLT_Chunk::fill_data_block (char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int*)data_start) = width; + *((int*)(data_start+4)) = num_levels; + + data_start += 8; + + for (int i=0; i < ChunkTLT_NumReserved ; ++i, data_start+=4) + *((int *)data_start) = reserved[i]; + + *(int *)data_start = flags; + data_start+=4; + + if (flags & ChunkTLTFlag_ExternalFile) + { + if (filename) + strcpy(data_start,filename); + else + *data_start = 0; + } + else + { + if (table) + { + unsigned char * tableptr = table; + + for (i=width*num_levels; i; --i) + { + *data_start++ = *tableptr++; + } + } + else + { + for (i=width*num_levels; i; --i) + { + *data_start++ = 0; + } + } + } +} + + +/////////////////////////////////////// + +// Class TLT_Config_Chunk functions + +TLTCC_Flags::TLTCC_Flags(unsigned int data) +: allow_v2 (data & 0x00000001 ? 1 : 0) +, nodefault (data & 0x00000002 ? 1 : 0) +{ +} + +TLTCC_Flags::operator unsigned int () const +{ + return + allow_v2 * 0x00000001 + + nodefault * 0x00000002 ; +} + +RIF_IMPLEMENT_DYNCREATE("TLTCONFG",TLT_Config_Chunk) + +TLT_Config_Chunk::TLT_Config_Chunk (Chunk_With_Children * parent, const char * sdata, size_t ssize) +: Chunk (parent, "TLTCONFG") +, num_shades_white(*(unsigned int const *)sdata) +, table_size(*(unsigned int const *)(sdata+4)) +, flags(*(unsigned int const *)(sdata+8)) +, palette_size(*(unsigned int const *)(sdata+12)) +{ + if (!table_size) table_size = 256; + + sdata+=16; + + for (int i=0; i<3; ++i, sdata+=4) reserved[i] = *(int *)sdata; + + unsigned int const len = strlen(sdata)+4&~3; + srcrifname = new char[len]; + memcpy(srcrifname,sdata,len); + sdata += len; + + unsigned int listsize = *(int *)sdata; + sdata += 4; + + while (listsize) + { + TLTConfigBlock block(sdata); + sdata += block.Size(); + blocks.add_entry_end(block); + listsize--; + } + + // hmm, size_chunk was wrong so allow sizes which were wrong in that way to pass + assert (ssize + 12 == size_chunk() || ssize + 12 + (44+strlen(srcrifname)+4&~3) - (44+strlen(srcrifname)+4&~4) == size_chunk()); +} + +size_t TLT_Config_Chunk::size_chunk() +{ + chunk_size = 44 + (srcrifname ? strlen(srcrifname) : 0) + 4 &~3; + for (LIF tbli(&blocks); !tbli.done(); tbli.next()) + { + chunk_size += tbli().Size(); + } + return chunk_size; +} + +void TLT_Config_Chunk::fill_data_block (char * data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + + *((int *) data_start) = chunk_size; + data_start += 4; + + *(unsigned int *)data_start = num_shades_white; + data_start += 4; + + *(unsigned int *)data_start = table_size; + data_start += 4; + + *(unsigned int *)data_start = flags; + data_start += 4; + + *(unsigned int *)data_start = palette_size; + data_start += 4; + + for (int i=0; i<3 ; ++i, data_start+=4) + *(int *)data_start = reserved[i]; + + strcpy(data_start,srcrifname ? srcrifname : ""); + + data_start += strlen(data_start) + 4 &~3; + + *(int *)data_start = blocks.size(); + data_start+=4; + + for (LIF tbli(&blocks); !tbli.done(); tbli.next()) + { + tbli().WriteData(data_start); + data_start += tbli().Size(); + } +} + + +/////////////////////////////////////// + +// Class Environment_Data_Chunk functions + +// constructor from buffer + +RIF_IMPLEMENT_DYNCREATE("GAMEMODE",Environment_Game_Mode_Chunk) + +/* +Children For Environment_Game_Mode_Chunk : + + +"GMODHEAD" Environment_Game_Mode_Header_Chunk +"ENVPALET" Environment_Palette_Chunk +"ENVTXLIT" Environment_TLT_Chunk +"TLTCONFG" TLT_Config_Chunk +"CLRLOOKP" Coloured_Polygons_Lookup_Chunk +"MATCHIMG" Matching_Images_Chunk +"SHBMPNAM" External_Shape_BMPs_Store_Chunk +"RIFCHILD" RIF_Child_Chunk +"SETPALST" Preset_Palette_Store_Chunk +"BMPMD5ID" Bitmap_MD5_Chunk +*/ + + +Environment_Game_Mode_Chunk::Environment_Game_Mode_Chunk(Chunk_With_Children* const parent,const char* data,size_t const size) +:Chunk_With_Children(parent,"GAMEMODE") , envd_parent((Environment_Data_Chunk *)parent) +{ + const char * buffer_ptr = data; + while ((data-buffer_ptr)< (signed) size) { + if ((*(int *)(data + 8)) + (data-buffer_ptr) > (signed) size) { + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + + DynCreate(data); + data += *(int *)(data + 8); + } +} + +char * Environment_Game_Mode_Chunk::ExpandedIdentifier() const +{ + char const * full_fname = header->flags & GameModeFlag_Editable ? ((File_Chunk *)GetRootChunk())->filename : header->get_safe_source(); + char const * skip = strrchr(full_fname,'\\'); + if (skip) full_fname = skip+1; + skip = strrchr(full_fname,'/'); + if (skip) full_fname = skip+1; + skip = strrchr(full_fname,':'); + if (skip) full_fname = skip+1; + char * retp = new char[strlen(full_fname)+strlen(header->mode_identifier)+3]; + strcpy(retp,full_fname); + char * dotpos = strrchr(retp,'.'); + if (dotpos) *dotpos = 0; + strcat(retp,"::"); + strcat(retp,header->mode_identifier); + return retp; +} + +// header chunk +RIF_IMPLEMENT_DYNCREATE("GMODHEAD",Environment_Game_Mode_Header_Chunk) + +Environment_Game_Mode_Header_Chunk::Environment_Game_Mode_Header_Chunk(Chunk_With_Children * const parent, const char * pdata, size_t const /*psize*/) +: Chunk (parent, "GMODHEAD"), flags(0), rif_files() +{ + flags = *((int *) pdata); + + pdata+=4; + + for (int i=0; iheader = this; +} + + +Environment_Game_Mode_Header_Chunk::~Environment_Game_Mode_Header_Chunk() +{ + if (mode_identifier) delete[] mode_identifier; + + while (rif_files.size()) + { + delete [] rif_files.first_entry(); + rif_files.delete_first_entry(); + } +} + + + +void Environment_Game_Mode_Header_Chunk::fill_data_block ( char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = flags; + data_start+=4; + + for (int i=0; i li(&rif_files); !li.done(); li.next()) + { + strcpy(data_start,li()); + + data_start += strlen(li())+1; + } + + *data_start = 0; // double 0-byte terminator +} + + +size_t Environment_Game_Mode_Header_Chunk::size_chunk () +{ + chunk_size = 12+20+(strlen(mode_identifier)+1); + + for (LIF li(&rif_files); !li.done(); li.next()) + { + chunk_size += strlen(li())+1; + } + + chunk_size += 4; // 1 byte terminator, 3(max) to pad + chunk_size &= ~3; + return chunk_size; +} + + + +//////////////////////////////////////// + +// Class RIF_Child_Chunk - for RIFs in game modes containing graphics +RIF_IMPLEMENT_DYNCREATE("RIFCHILD",RIF_Child_Chunk) + +RIF_Child_Chunk::~RIF_Child_Chunk() +{ + if (filename) delete[] filename; + if (rifname) delete[] rifname; +} + +size_t RIF_Child_Chunk::size_chunk() +{ + chunk_size = 12 + 12 + (strlen(rifname)+1 +3 &~3) + 4 + (strlen(filename)+1 +3 &~3) + 4; + + for (LIF li(&bmps); !li.done(); li.next()) + { + chunk_size += 8 + strlen(li().filename)+1 +3 & ~3; + } + + return chunk_size; +} + +void RIF_Child_Chunk::fill_data_block(char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + for (int i=0; i li(&bmps); !li.done(); li.next()) + { + *((int *) data_start) = li().flags; + data_start += 4; + *((int *) data_start) = li().version_num & BMPFLAGS_VERSION_NUM_MASK | li().enum_id << BMPFLAGS_ENUMID_SHIFT; + data_start += 4; + + strcpy(data_start, li().filename); + data_start += strlen(li().filename)+1 +3 &~3; + } + +} + +int const * RIF_Child_Chunk::GetMD5Val(BMP_Flags const & rcbmp) +{ + Bitmap_MD5_Chunk * md5c = GetMD5Chunk(rcbmp.filename); + if (md5c) + if (rcbmp.version_num == md5c->version_num) + return md5c->md5_val; + return 0; +} + +void RIF_Child_Chunk::RemoveMD5Val(char const * bname) +{ + Bitmap_MD5_Chunk * md5c = GetMD5Chunk(bname); + if (md5c) + delete md5c; +} + +void RIF_Child_Chunk::SetMD5Val(BMP_Flags const & rcbmp, int const * md5id) +{ + Bitmap_MD5_Chunk * md5c = GetMD5Chunk(rcbmp.filename); + if (md5c) + { + if (rcbmp.version_num == md5c->version_num) + { + memcpy(md5c->md5_val,md5id,16); + return; + } + else + delete md5c; + } + CreateMD5Chunk(rcbmp,md5id); +} + +Bitmap_MD5_Chunk * RIF_Child_Chunk::GetMD5Chunk(char const * bname) +{ + List chlst; + parent->lookup_child("BMPMD5ID",chlst); + + for (LIF i_chlst(&chlst); !i_chlst.done(); i_chlst.next()) + { + Bitmap_MD5_Chunk * md5c = (Bitmap_MD5_Chunk *)i_chlst(); + + if (!strcmp(md5c->bmpname,bname)) + if (!(md5c->rifname ? rifname ? strcmp(rifname,md5c->rifname) : *md5c->rifname : rifname ? *rifname : 0) && + !(md5c->shapename ? *md5c->shapename : 1)) + return md5c; + } + + return 0; +} + +void RIF_Child_Chunk::CreateMD5Chunk(BMP_Flags const & rcbmp, int const * md5id) +{ + new Bitmap_MD5_Chunk(parent,md5id,rcbmp,rifname); +} + +RIF_Child_Chunk::RIF_Child_Chunk (Chunk_With_Children * const parent, const char * sdata, size_t const /*ssize*/) +: Chunk(parent,"RIFCHILD"), egm_parent((Environment_Game_Mode_Chunk * const)parent) +{ + for (int i=0; i> BMPFLAGS_ENUMID_SHIFT); + temp.version_num = *(int *)sdata & BMPFLAGS_VERSION_NUM_MASK; + sdata += 4; + + len = strlen(sdata)+1; + temp.filename = new char[len]; + strcpy(temp.filename,sdata); + sdata += len+3 &~3; + + bmps.add_entry(temp); + } + +} + +///////////////////////////////// +// Preset_Palette_Store_Chunk +// ties in with RIF_Child_Chunk +// the filenames (-dirname) should match + +RIF_IMPLEMENT_DYNCREATE("SETPALST",Preset_Palette_Store_Chunk) + +Preset_Palette_Store_Chunk::Preset_Palette_Store_Chunk(Chunk_With_Children * const parent, char const * sdata, size_t const /*ssize*/) +: Chunk(parent,"SETPALST") +, version_num(*(int *)sdata) +, flags(*(int *)(sdata+4)) +, reserved1(*(int *)(sdata+8)) +, reserved2(*(int *)(sdata+12)) +, reserved3(*(int *)(sdata+16)) +{ + sdata += 20; + + unsigned int const len = strlen(sdata)+1; + rifname = new char[len]; + strcpy(rifname,sdata); + sdata += len + 3 &~3; + + int const pplistsize = *(int *)sdata; + sdata += 4; + + for (int i = pplistsize; i; --i) + { + Preset_Palette current(sdata); + sdata += current.size_chunk(); + pplist.add_entry(current); + } +} + + +size_t Preset_Palette_Store_Chunk::size_chunk () +{ + chunk_size = 12 + 24 + strlen(rifname)+1+3 &~3; + + for (LIF li(&pplist); !li.done(); li.next()) + { + chunk_size += li().size_chunk(); + } + + return chunk_size; +} + +void Preset_Palette_Store_Chunk::fill_data_block (char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *(int *) data_start = chunk_size; + + data_start += 4; + + *(int*)data_start = version_num; + *(int*)(data_start+4) = flags; + *(int*)(data_start+8) = reserved1; + *(int*)(data_start+12) = reserved2; + *(int*)(data_start+16) = reserved3; + data_start += 20; + + strcpy(data_start,rifname); + data_start+=strlen(rifname)+1+3 &~3; + + *(int*)(data_start) = pplist.size(); + data_start += 4; + + for (LIF li(&pplist); !li.done(); li.next()) + { + Preset_Palette current(li()); + + current.fill_data_block(data_start); + data_start += current.size_chunk(); + } +} + + + + + +/////////////////////////////////////// + +// Class Coloured_Polygons_Lookup_Chunk functions + +// simple 32K tables for palettes to quickly map coloured +// polygons to the right palette colour on loading, with 15-bit definition + + +RIF_IMPLEMENT_DYNCREATE("CLRLOOKP",Coloured_Polygons_Lookup_Chunk) + +Coloured_Polygons_Lookup_Chunk::Coloured_Polygons_Lookup_Chunk (Chunk_With_Children * parent, const char * sdata, size_t /*ssize*/) +: Chunk (parent, "CLRLOOKP"), flags (*((int*)(sdata))), + filename(0), table (0) +{ + for (int i=0; i pplist; + + +private: + + friend class Environment_Data_Chunk; + + +}; + + + + +class Environment_TLT_Chunk : public Chunk +{ + +public: + +#if cencon + // constructor using palette - defined in genpal + Environment_TLT_Chunk (Chunk_With_Children * parent, PPM_Header * palette, PPM_Header * tlt_palette, Lighting_Style const * ls); +#endif + // constructor from buffer + Environment_TLT_Chunk (Chunk_With_Children * parent, const char * sdata, size_t ssize); + + ~Environment_TLT_Chunk (); + + virtual size_t size_chunk (); + + virtual void fill_data_block (char * data_start); + + int width; // should be == palette size, though may well have to be 256 due to the way 3dc lookup works + int num_levels; // usually 256, for 256 "different" shades of each colour + + #define ChunkTLT_NumReserved 5 + int reserved[ ChunkTLT_NumReserved ]; + + int flags; // either expect filename or table + #define ChunkTLTFlag_ExternalFile 0x00000001 + #define ChunkTLTFlag_OptionsChanged 0x00000002 + #define ChunkTLTFlag_V2 0x00000004 // version 2: may have width != 256, flagged so we can distinguish between two tables in chunk + + char * filename; // either a filename + + unsigned char * table; // or an actual table in memory + +private: + + friend class Environment_Data_Chunk; + friend class Environment_Game_Mode_Chunk; + + + +}; + + +class TLTConfigBlock +{ +public: + // constructos; + TLTConfigBlock() + { + spares[0]=0; + spares[1]=0; + spares[2]=0; + spares[3]=0; + } + + TLTConfigBlock(double const & iistart, double const & oistart, double const & iiend, double const & oiend) + : input_intensity_start(iistart) + , output_intensity_start(oistart) + , input_intensity_end(iiend) + , output_intensity_end(oiend) + { + spares[0]=0; + spares[1]=0; + spares[2]=0; + spares[3]=0; + } + + // I/O + TLTConfigBlock(char const * datablock) + : input_intensity_start(*(double *)datablock) + , output_intensity_start(*(double *)(datablock+8)) + , input_intensity_end(*(double *)(datablock+16)) + , output_intensity_end(*(double *)(datablock+24)) + { + memcpy(spares,datablock+32,16); + } + inline size_t Size() const { return 48; } + inline void WriteData(char * datablock) const + { + *(double *)datablock = input_intensity_start; + datablock += 8; + *(double *)datablock = output_intensity_start; + datablock += 8; + *(double *)datablock = input_intensity_end; + datablock += 8; + *(double *)datablock = output_intensity_end; + datablock += 8; + memcpy(datablock,spares,16); + } + + // operators + inline BOOL operator == (TLTConfigBlock const & tcb2) const + { + return input_intensity_start == tcb2.input_intensity_start + && output_intensity_start == tcb2.output_intensity_start + && input_intensity_end == tcb2.input_intensity_end + && output_intensity_end == tcb2.output_intensity_end; + } + inline BOOL operator != (TLTConfigBlock const & tcb2) const + { return ! operator == (tcb2); } + + // members + double input_intensity_start; + double output_intensity_start; + double input_intensity_end; + double output_intensity_end; + +private: + + int spares[4]; + +}; + +struct TLTCC_Flags +{ + TLTCC_Flags(unsigned int data = 0); + + operator unsigned int () const; + + unsigned int allow_v2 : 1; // palette size refers to bigger size table + unsigned int nodefault : 1; // suppress normal 256 colour tlts +}; + +class TLT_Config_Chunk : public Chunk +{ + +public: + +#if cencon + // constructor for default + TLT_Config_Chunk (Chunk_With_Children * parent, char const * rifname = 0) + : Chunk (parent, "TLTCONFG") + , num_shades_white(16) + , srcrifname(rifname ? new char [strlen(rifname)+1] : 0) + , blocks(TLTConfigBlock(0,0,1,1)) + , table_size(256) + , palette_size(0) + { + for (int i=0; i<3; ++i) reserved[i]=0; + if (rifname) strcpy(srcrifname,rifname); + } +#endif + // constructor from buffer + TLT_Config_Chunk (Chunk_With_Children * parent, const char * sdata, size_t ssize); + + ~TLT_Config_Chunk() + { if (srcrifname) delete[] srcrifname; } + + virtual size_t size_chunk (); + + virtual void fill_data_block (char * data_start); + + char * srcrifname; + + unsigned int num_shades_white; + + unsigned int table_size; + + List blocks; + + unsigned int palette_size; // for version 2 palettes and big tlt + + TLTCC_Flags flags; + + inline BOOL operator == (TLT_Config_Chunk const & tcc2) const + { return blocks == tcc2.blocks && num_shades_white == tcc2.num_shades_white && table_size == tcc2.table_size && flags == tcc2.flags && (!flags.allow_v2 || palette_size == tcc2.palette_size); } + inline BOOL operator != (TLT_Config_Chunk const & tcc2) const + { return ! operator == (tcc2); } + inline BOOL NeedFullRemake(TLT_Config_Chunk const & tcc_old) const + { return blocks != tcc_old.blocks || num_shades_white != tcc_old.num_shades_white; } + inline BOOL NeedNewTLTPalette(TLT_Config_Chunk const & tcc_old) const + { return flags != tcc_old.flags || flags.allow_v2 && palette_size != tcc_old.palette_size; } + +private: + int reserved[3]; + + friend class Environment_Data_Chunk; + friend class Environment_Game_Mode_Chunk; + + + +}; + +#if cencon +extern TLT_Config_Chunk Default_TLT_Config_Chunk; +#endif + + + + +// Multi-Palettes for one environment + +// Coloured polygons will be set on load-up +// If 15 bit is good-enough, we can use a 32K +// lookup table for the coloured polygons, +// otherwise we'll have to do the slower +// distance comparisons + +// We need a new chunk which is a child of the REBENVDT environment data chunk + +// this will be a GAMEMODE chunk with children, and there may be more than one +// in the case where there are several palettes available for the environment + +// there will be an identifying string in the gamepalette chunk. +// the "REBENVDT"->lookup_child("GAMPALET") will return a list of these chunks, +// so you can look through them to find the one you want +// There should be some sort of convention/restriction/communication +// about the + +// most of the information will be in its children, which can be any of the following + +// ENVPALET + +// RIFCHILD(s) - the name of RIF file(s) +// this is basically a RIF_Name_Chunk, but named differently so as to distinguish it from its own file's name +// which should have a REBENVDT chunk with BMPNAMES and/or RIFCHILD(s) (even more RIFs) +// specifying what non-environment specific bitmaps are used, and probably much more data, +// - they could be sprites, etc. +// then all the data could be automatically included (but not loaded) by the inclusion of one file + +// ENVTXLIT - texture lighting table, +// but maybe this should a filename to load if required + +// CLRLOOKP - 15-bit r;g;b lookup table to get palette entries for coloured polygons on load +// can have a table or a reference file + +// other relevant chunks to be added later +// we may need some sort of BMPNAMES chunk, for flags about which bmps are quantized, etc. + + +// HOW TO USE - example (supplied without warranty) +// ---------- + +/* +File_Chunk * environment = $current environment$; + +List envdatalist = environment->lookup_child("REBENVDT"); + +if (envdatalist.size()) +{ + Environment_Data_Chunk * envdata = (Environment_Data_Chunk *)envdatalist.first_entry(); + + List gamemodelist = envdata->lookup_child("GAMEMODE"); + + Environment_Game_Mode_Chunk * selected = 0; + + for(LIF li(&gamemodelist); !li.done(); li.next()) + { + Environment_Game_Mode_Chunk * try_this = (Environment_Game_Mode_Chunk *) li(); + if (try_this->id_equals((const char *)$your identifier$)) + { + selected = try_this; + break; + } + } + + if (selected) + { + List bmpgrouplist = selected->lookup_child("RIFCHILD"); + + String subdir; + + List rifnamechunk = envdata->lookup_child("RIFFNAME"); + if (rifnamechunk.size()) + subdir = ((RIF_Name_Chunk *) rifnamechunk.first_entry())->rif_name; + else + subdir = "empty"; + + // load graphics loop + for (LIF g(&bmpgrouplist); !g.done(); g.next()) + { + RIF_Child_Chunk * current = (RIF_Child_Chunk *)g(); + + const char * mipmap_0; + const char * mipmap_n; + String dir; + + if ($loading pgms$) + { + dir = (String)"Game-Textures\\" + subdir + "\\" + (String)$your identifier$ + "\\"; + if (*current->filename) + { + dir += (String)current->rifname + "\\"; + } + mipmap_0 = ".pg0"; + mipmap_n = ".pg%1d"; + } + else // loading bm0 to bm6 + { + dir = (String)"Generic-Textures\\" + current->rifname + "\\"; + mipmap_0 = ".pg0"; + mipmap_n = ".pg%1d"; + } + + // load graphics-set loop + for (LIF img(¤t->bmps); !img.done(); img.next()) + { + BMP_Flags bmp = img(); + + char * imname = new char[strlen(bmp.filename)+5]; + strcpy(imname,bmp.filename); + char * dotpos = strrchr(imname,'.'); + if (!dotpos) dotpos = imname + strlen(imname); + strcpy(dotpos,mipmap_0); + + String filename = dir + imname; + + $load image$(filename) + + if (bmp.flags & ChunkBMPFlag_MipMapsQuantized) + { + // load mipmaps loop + for (int i = 1 ; i<=6 ; ++i) + { + sprintf(dotpos,mipmap_n,i); + filename = dir + imname; + $load image$(filename) + } + } + delete [] imname; + } + } + } + else + { + // your identifier is not valid + } +} +else +{ + // no data +} + + + +*/ + + +#define GameModeFlag_Editable 0x00000001 // game modes are not editable if they are included from another RIF +#define GameModeFlag_Deleted 0x00000002 // so you can click on cancel and invisibly no updating will be done +#define GameModeFlag_Added 0x00000004 // ditto + +class Environment_Game_Mode_Chunk; +class Environment_Game_Mode_Header_Chunk; + + + +class Environment_Game_Mode_Chunk : public Chunk_With_Children +{ + +public: + +#if cencon + // constructor from data + Environment_Game_Mode_Chunk (Environment_Data_Chunk * const parent, const char * _mode_id); + + // defined in gmodlink + void remove(class CWnd * const pWnd); // update this copy by finding its original + void update(class CWnd * const pWnd, BOOL bDoSoftwareTex); // update this copy by finding its original + void been_updated(class CWnd * const pWnd, BOOL bDoSoftwareTex); // find and update copies from this original + void definite_update(Environment_Game_Mode_Chunk const * const src, class CWnd * const pWnd, Environment_Data_Chunk * envd, BOOL bDoSoftwareTex); + +#endif + // constructor from buffer + Environment_Game_Mode_Chunk (Chunk_With_Children * const parent, const char * sdata, size_t const ssize); + + ~Environment_Game_Mode_Chunk(){} + + Environment_Game_Mode_Header_Chunk * header; + Environment_Data_Chunk * const envd_parent; + + char * ExpandedIdentifier() const; // must delete return value + + inline BOOL operator == (Environment_Game_Mode_Chunk const & m) const; + inline BOOL operator != (Environment_Game_Mode_Chunk const & m) const; + // public function for people to check if they have the game mode they want + inline BOOL id_equals(const char * s) const; + +private: + + friend class Environment_Data_Chunk; + + + +}; + +class Environment_Game_Mode_Chunk_Pointer +{ +private: + Environment_Game_Mode_Chunk * p; + // poor lonely thing has no friends and never will -- aaaahh + +private: + inline Environment_Game_Mode_Chunk_Pointer(void) : p(0) {}; + friend struct List_Member; + +public: + // copy constructor from another of this type + //inline Environment_Game_Mode_Chunk_Pointer(Environment_Game_Mode_Chunk_Pointer const & cp) : p(cp.p) {}; + // cast constructor from C pointer + inline Environment_Game_Mode_Chunk_Pointer(Environment_Game_Mode_Chunk * const cp) : p(cp) {}; + // cast to C pointer operator + inline operator Environment_Game_Mode_Chunk * (void) const { return p; } + // no empty constructor -- p must always be valid + + // equavalence based on contents of pointer, not addresses being the same + inline BOOL operator == (Environment_Game_Mode_Chunk_Pointer const m) const + { + if (!p || !m.p) return 0; + return *p == *m.p; + } + inline BOOL operator != (Environment_Game_Mode_Chunk_Pointer const m) const + { + if (!p || !m.p) return 1; + return *p != *m.p; + } + +}; + + +/////////////////////////////////////////////// + + + + +class Environment_Game_Mode_Header_Chunk : public Chunk +{ +public: + // constructor from buffer + Environment_Game_Mode_Header_Chunk (Chunk_With_Children * const parent, const char * pdata, size_t const psize); + virtual size_t size_chunk (); + + virtual void fill_data_block (char * data_start); + + inline BOOL id_equals(const char * s) + { + if (_stricmp(s,mode_identifier)) + return FALSE; + else + return TRUE; + } + + int flags; + char * mode_identifier; + + inline void add_rif_entry(char const * f) + { + char * n = new char[strlen(f)+1]; + strcpy(n,f); + rif_files.add_entry(n); + } + inline const char * get_safe_source(void) + { + if (flags & GameModeFlag_Editable) + return "this.rif"; + if (!rif_files.size()) + return "unknown.rif"; + return rif_files.first_entry(); + } + +private: + + friend class Environment_Game_Mode_Chunk; + friend class Cwm_GAMEMODEDlg; + friend class Cwm_GAMEMODClicked116Dlg; + friend class GameModeDlg; + friend class GameModeRifDlg; + + List rif_files; // where the game mode goes to or comes from + + #define ChunkGMod_NumReserved 3 + int reserved[ChunkGMod_NumReserved]; + + int version_num; + + + #if cencon + // constructor from parent + Environment_Game_Mode_Header_Chunk (Environment_Game_Mode_Chunk * const parent, const char * const _mode_id) + : Chunk (parent, "GMODHEAD"), version_num(0), + flags (0), rif_files() + { + for (int i=0; iheader = this; + } + + inline Environment_Game_Mode_Header_Chunk const & operator = (Environment_Game_Mode_Header_Chunk & s) + { + flags = s.flags; + while (rif_files.size()) + { + delete[] rif_files.first_entry(); + rif_files.delete_first_entry(); + } + if (mode_identifier) delete[] mode_identifier; + + mode_identifier = new char[strlen(s.mode_identifier)+1]; + strcpy(mode_identifier,s.mode_identifier); + + for (LIF src(&s.rif_files); !src.done(); src.next()) + { + add_rif_entry(src()); + } + + version_num = s.version_num; + + return *this; + + } + #endif + + // deconstructor + ~Environment_Game_Mode_Header_Chunk(); + + + +}; + +////////////////// + +inline BOOL Environment_Game_Mode_Chunk::operator == (Environment_Game_Mode_Chunk const & m) const +{ + if ((header->flags | m.header->flags) & GameModeFlag_Deleted) return FALSE; + return !_stricmp(header->mode_identifier,m.header->mode_identifier); +} +inline BOOL Environment_Game_Mode_Chunk::operator != (Environment_Game_Mode_Chunk const & m) const +{ + if ((header->flags | m.header->flags) & GameModeFlag_Deleted) return TRUE; + return _stricmp(header->mode_identifier,m.header->mode_identifier); +} +inline BOOL Environment_Game_Mode_Chunk::id_equals(const char * s) const +{ + return header->id_equals(s); +} + + +/////////////////////////////////////////////// + + +class RIF_Child_Chunk; + +class BMP_Flags +{ +public: + BMP_Flags(void) : filename(0), enum_id(0), version_num(0), flags((BMPN_Flags)0){} + BMP_Flags(const char * const fname) : enum_id(0), version_num(0), flags((BMPN_Flags)0), filename(0) + { + if (fname) + { + filename = new char[strlen(fname)+1]; + strcpy(filename,fname); + } + } + BMP_Flags(BMP_Name const & bn) : enum_id(bn.enum_id), version_num(bn.version_num), flags((BMPN_Flags)(bn.flags & COPY_BMPN_FLAGS)), filename(0) + { + if (bn.filename) + { + filename = new char[strlen(bn.filename)+1]; + strcpy(filename,bn.filename); + } + } + BMP_Flags(BMP_Flags const & c) : filename(0), enum_id(c.enum_id), version_num(c.version_num), flags(c.flags) + { + if (c.filename) + { + filename = new char[strlen(c.filename)+1]; + strcpy(filename,c.filename); + } + } + operator BMP_Name () const + { + BMP_Name cast(filename); + cast.flags = flags; + cast.version_num = version_num; + cast.enum_id = enum_id; + return cast; + } + ~BMP_Flags() + { + if (filename) delete[] filename; + } + + BMP_Flags & operator = (BMP_Flags const & c) + { + if (filename) delete[] filename; + if (c.filename) + { + filename = new char[strlen(c.filename)+1]; + strcpy(filename,c.filename); + } + else + filename = 0; + flags = c.flags; + version_num = c.version_num; + enum_id = c.enum_id; + return *this; + } + + + char * filename; + BMPN_Flags flags; + #define BMPFLAGS_VERSION_NUM_MASK 0x000fffff + #define BMPFLAGS_ENUMID_SHIFT 20 + int version_num; + int enum_id; + + inline BOOL operator == (BMP_Flags const & c) const + { + return !_stricmp(filename,c.filename); + } + inline BOOL operator != (BMP_Flags const & c) const + { + return _stricmp(filename,c.filename); + } + + #if cencon + void DeleteAssociatedFiles(RIF_Child_Chunk const *, Environment_Data_Chunk *) const; + #endif +}; + +enum RCC_Flags { + RCCF_EXTERNSHAPE = 0x00000001, // bitmaps from shape which is in game mode solely because it was an external shape added to the environment with this game mode + RCCF_FIXEDPALETTE = 0x00000002, // pgms are quantized with a fixed constant palette + RCCF_HISTOGRAMEXISTS = 0x00000004, + RCCF_HISTOGRAMV2EXISTS = 0x00000008, + + RCCF_DEFAULT = 0 +}; + +class RIF_Child_Chunk : public Chunk +{ +public: + +#if cencon + RIF_Child_Chunk(Environment_Game_Mode_Chunk * const parent, const char * fname, class CWnd * const pWnd, BOOL bDoSoftwareTex); + + void update(class CWnd * const, BOOL bDoSoftwareTex); + void update(class Environment * e, BOOL bDoSoftwareTex); // for where the environment is already loaded + void DeleteAssociatedFiles(Environment_Data_Chunk *) const; +#endif +// constructor from buffer + RIF_Child_Chunk (Chunk_With_Children * const parent, const char * sdata, size_t const ssize); + ~RIF_Child_Chunk(); + + virtual size_t size_chunk (); + + virtual void fill_data_block (char * data_start); + + int const * GetMD5Val(BMP_Flags const & rcbmp); + void SetMD5Val(BMP_Flags const & rcbmp, int const * md5id); + void RemoveMD5Val(char const * bname); + Bitmap_MD5_Chunk * GetMD5Chunk(char const * bname); + void CreateMD5Chunk(BMP_Flags const & rcbmp, int const * md5id); + + Environment_Game_Mode_Chunk * const egm_parent; + + int version_num; + + char * filename; + char * rifname; + + inline BOOL operator == (RIF_Child_Chunk const & c) const + { + return !strcmp(rifname,c.rifname); + } + inline BOOL operator != (RIF_Child_Chunk const & c) const + { + return strcmp(rifname,c.rifname); + } + + List bmps; + + RCC_Flags flags; + + #define ChunkRIFChild_NumReserved 2 + int reserved[ChunkRIFChild_NumReserved]; + + +private: + + friend class Environment_Game_Mode_Chunk; + + +}; + + + +class Preset_Palette_Store_Chunk : public Chunk +{ +public: + +#if cencon + // constructor from Preset_Palette_Chunk + Preset_Palette_Store_Chunk (Chunk_With_Children * const parent, Preset_Palette_Chunk const * const schunk, const char * const srname) + : Chunk (parent,"SETPALST") + , flags(schunk->flags) + , version_num(schunk->version_num) + , reserved1(schunk->reserved1) + , reserved2(schunk->reserved2) + , reserved3(schunk->reserved3) + , rifname(new char[strlen(srname)+1]) + , pplist(schunk->pplist) + { + strcpy(rifname,srname); + } + + // empty constructor + Preset_Palette_Store_Chunk (Chunk_With_Children * const parent, const char * const srname) + : Chunk (parent,"SETPALST") + , flags(0) + , version_num(0) + , reserved1(0) + , reserved2(0) + , reserved3(0) + , rifname(new char[strlen(srname)+1]) + { + strcpy(rifname,srname); + } + +#endif + // constructor from buffer + Preset_Palette_Store_Chunk (Chunk_With_Children * const parent, char const * sdata, size_t const ssize); + ~Preset_Palette_Store_Chunk () + { + if (rifname) delete[] rifname; + } + + virtual size_t size_chunk (); + + virtual void fill_data_block (char * data_start); + + int flags; + int version_num; + + const int reserved1; + const int reserved2; + const int reserved3; + + char * rifname; + + inline BOOL operator == (Preset_Palette_Store_Chunk const & c) const + { + return !strcmp(rifname,c.rifname); + } + inline BOOL operator != (Preset_Palette_Store_Chunk const & c) const + { + return strcmp(rifname,c.rifname); + } + + List pplist; + + +private: + + friend class Environment_Game_Mode_Chunk; + + +}; + + + + + +/////////////////////////////////////////////// + + + +class Coloured_Polygons_Lookup_Chunk : public Chunk +{ +public: + +#if cencon + // constructor from data - defined in cencon + Coloured_Polygons_Lookup_Chunk (Chunk_With_Children * parent, PPM_Header * const palette); +#endif + // constructor from buffer + Coloured_Polygons_Lookup_Chunk (Chunk_With_Children * parent, const char * sdata, size_t ssize); + + ~Coloured_Polygons_Lookup_Chunk (); + + virtual size_t size_chunk (); + + virtual void fill_data_block (char * data_start); + + int flags; + #define ChunkCPLUFlag_ExternalFile 0x00000001 + + #define ChunkCPLU_NumReserved 7 + int reserved[ ChunkCPLU_NumReserved ]; + + char * filename; + unsigned char * table; + +private: + + friend class Environment_Game_Mode_Chunk; + friend class Environment_Data_Chunk; + + +}; + + + + + +#endif // !included + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/3dc/win95/CL_INIT.CPP b/3dc/win95/CL_INIT.CPP new file mode 100644 index 0000000..beab242 --- /dev/null +++ b/3dc/win95/CL_INIT.CPP @@ -0,0 +1,34 @@ +#include "cl_init.h" +#include "system.h" // because the 3dc header files don't automatically include the ones they need +#include "equates.h" // because the 3dc header files don't automatically include the ones they need +#include "platform.h" // for VideoModeTypes +#include "shape.h" // because the 3dc header files don't automatically include the ones they need +#include "prototyp.h" // for SDB +#include "d3_image.hpp" // for init functions + +extern "C" extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + +void CL_Init_All(void) +{ + switch (VideoModeTypeScreen) + { + case VideoModeType_8: + if (ScreenDescriptorBlock.SDB_Flags & SDB_Flag_TLTPalette) + CL_Init_DirectDrawMode(CLV_8TLT); + else + CL_Init_DirectDrawMode(CLV_8); + break; + case VideoModeType_15: + CL_Init_DirectDrawMode(CLV_15); + break; + case VideoModeType_24: + CL_Init_DirectDrawMode(CLV_24); + break; + case VideoModeType_8T: + CL_Init_DirectDrawMode(CLV_8T); + break; + } + + if (ScanDrawDirectDraw != ScanDrawMode) + CL_Init_D3DMode(&(d3d.TextureFormat[d3d.CurrentTextureFormat].ddsd)); +} diff --git a/3dc/win95/CL_INIT.H b/3dc/win95/CL_INIT.H new file mode 100644 index 0000000..79cfba2 --- /dev/null +++ b/3dc/win95/CL_INIT.H @@ -0,0 +1,23 @@ +#ifndef _included_cl_init_h_ +#define _included_cl_init_h_ + +#error "This file is obsolete" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "d3d.h" // required by d3_func.hpp +#include "d3_func.h" // for D3DINFO definition + +extern int VideoModeTypeScreen; +extern int ScanDrawMode; +extern D3DINFO d3d; + +void CL_Init_All(void); + +#ifdef __cplusplus +}; +#endif + +#endif // !_included_cl_init_h_ \ No newline at end of file diff --git a/3dc/win95/Chunk.cpp b/3dc/win95/Chunk.cpp new file mode 100644 index 0000000..a123ba0 --- /dev/null +++ b/3dc/win95/Chunk.cpp @@ -0,0 +1,599 @@ +#include + +#include "chunk.hpp" + +#if engine + +#define UseLocalAssert No +#include "ourasert.h" +#define assert(x) GLOBALASSERT(x) + +#else + +#if cencon +#include "ccassert.h" +#else +#include +#endif + +#endif + + +#if cencon +#include "environs.hpp" +#else +#define twprintf printf + +#ifdef cencon +#define new my_new +#endif + +char * users_name = "Player"; +#endif + +#include "hash_tem.hpp" +Chunk * Parent_File; + +// Non class functions ( only one as yet ) + +void list_chunks_in_file(List * pList, HANDLE hand, char const * chunk_id) +{ + unsigned long bytes_read; + + char buffer[8]; + BOOL ok = TRUE; + + while (pList->size()) + pList->delete_first_entry(); + + // assuming we start at the front of a parent chunk, + // containing the child chunk specified + + int init_file_pos = SetFilePointer (hand,0,0,FILE_CURRENT); + int file_pos; + int file_length = GetFileSize(hand, 0); + + SetFilePointer (hand,8,0,FILE_CURRENT); + + int chunk_length; + int sub_chunk_ln; + + ReadFile (hand, (long *) &chunk_length, 4, &bytes_read, 0); + + if ((init_file_pos + chunk_length) > file_length) return; + + while ((file_pos = SetFilePointer (hand,0,0,FILE_CURRENT)) + < (init_file_pos + chunk_length) && ok) { + + ok = ReadFile (hand, (long *) buffer, 8, &bytes_read, 0); + if (strncmp(buffer, chunk_id, 8) == 0) + pList->add_entry(file_pos); + + ok = ReadFile (hand, (long *) &sub_chunk_ln, 4, &bytes_read, 0); + + SetFilePointer (hand,sub_chunk_ln-12,0,FILE_CURRENT); + } +} + +#ifndef RIFF_OPTIMIZE +List list_chunks_in_file (HANDLE & hand, const char * chunk_id) +{ + + List chunk_list; + + list_chunks_in_file(&chunk_list, hand, chunk_id); + + return chunk_list; +} +#endif + +////////////////////////////////////////////// + + +// Class Chunk functions + +Chunk::~Chunk() +{ + if (parent) { + if (parent->children == this) { + parent->children = next; + if (next) + next->previous = previous; + } + else { + if (previous) + previous->next = next; + if (next) + next->previous = previous; + } + } +} + +Chunk::Chunk(Chunk_With_Children * _parent, const char * _identifier) +: error_code(0) +{ + strncpy (identifier_store, _identifier, 8); + identifier_store[8] = 0; + identifier = identifier_store; + parent = _parent; + next = NULL; + previous = NULL; + + if (parent){ + if (parent->children) { + Chunk * pTail = parent->children; + while (pTail->next) + pTail = pTail->next; + pTail->next = this; + previous = pTail; + } + else + parent->children = this; + } +} + +BOOL Chunk::output_chunk (HANDLE & hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = make_data_block_from_chunk(); + + if (data_block) + { + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + delete [] data_block; + + if (!ok) return FALSE; + } + else if (chunk_size) + { + return(FALSE); + } + return TRUE; +} + + + +char * Chunk::make_data_block_from_chunk () +{ + char * data_block; + size_t block_size; + + block_size = size_chunk(); + + if (!chunk_size) + { + return(0); + } + + data_block = new char [block_size]; + + this->fill_data_block(data_block); + + return data_block; +} + +char * Chunk::make_data_block_for_process () +{ + char * data_block; + size_t block_size; + + block_size = size_chunk_for_process(); + + if (!chunk_size) + { + return(0); + } + + data_block = new char [block_size]; + + fill_data_block_for_process(data_block); + + return data_block; +} + + +size_t Chunk::size_chunk_for_process() +{ + return size_chunk(); +} + + +void Chunk::fill_data_block_for_process(char * data_start) +{ + fill_data_block(data_start); +} + +Chunk_With_Children * Chunk::GetRootChunk(void) +{ + Chunk * retp = this; + + while (retp->parent) retp = retp->parent; + + return (Chunk_With_Children *) retp; +} + +Chunk_With_Children const * Chunk::GetRootChunk(void) const +{ + Chunk const * retp = this; + + while (retp->parent) retp = retp->parent; + + return (Chunk_With_Children const *) retp; +} + + +/////////////////////////////////////// + +// Class Miscellaneous_Chunk functions + +Miscellaneous_Chunk::Miscellaneous_Chunk (Chunk_With_Children * parent, const char * identifier, + const char * _data, size_t _data_size) +: Chunk (parent, identifier), +data(NULL), data_size (_data_size) +{ + if (data_size) + { + data_store = new char [data_size]; + + *((char **) &data) = data_store; + + for (int i = 0; i < (signed)data_size; i++) + data_store[i] = _data[i]; + } + else + { + data_store = NULL; + } + +} + +void Miscellaneous_Chunk::fill_data_block (char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + for (int i = 0; i<(signed)(chunk_size-12); i++) + data_start[i] = data[i]; +} + +Miscellaneous_Chunk::~Miscellaneous_Chunk () +{ + delete [] data_store; +} + +/////////////////////////////////////// + +// Class Chunk_With_Children functions + +Chunk_With_Children::~Chunk_With_Children() +{ + while (children) + delete children; +} + +size_t Chunk_With_Children::size_chunk () +{ + Chunk * child_ptr = children; + + chunk_size = 12; // identifier + length + + if (children) + while (child_ptr != NULL) { + chunk_size += child_ptr->size_chunk(); + child_ptr = child_ptr->next; + } + + return chunk_size; + +} + +BOOL Chunk_With_Children::output_chunk (HANDLE &hand) +{ + unsigned long junk; + Chunk * child_ptr = children; + BOOL ok; + + ok = WriteFile (hand, (long *) identifier, 8, &junk, 0); + + if (!ok) return FALSE; + + ok = WriteFile (hand, (long *) &chunk_size, 4, &junk, 0); + + if (!ok) return FALSE; + + if (children) + while (child_ptr != NULL && ok){ + ok = child_ptr->output_chunk(hand); + child_ptr = child_ptr->next; + } + + if (!ok) return FALSE; + + return TRUE; + + +} + + +size_t Chunk_With_Children::size_chunk_for_process() +{ + Chunk * child_ptr = children; + + chunk_size = 12; // identifier + length + + if (children) + while (child_ptr != NULL) { + chunk_size += child_ptr->size_chunk_for_process(); + child_ptr = child_ptr->next; + } + + return chunk_size; + +} + + +void Chunk_With_Children::fill_data_block_for_process(char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + Chunk * child_ptr = children; + + if (children) + while (child_ptr != NULL) { + child_ptr->fill_data_block_for_process (data_start); + data_start += child_ptr->chunk_size; + child_ptr = child_ptr->next; + } + +} + + + +void Chunk_With_Children::fill_data_block(char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + Chunk * child_ptr = children; + + if (children) + while (child_ptr != NULL) { + child_ptr->fill_data_block (data_start); + data_start += child_ptr->chunk_size; + child_ptr = child_ptr->next; + } + +} + +#ifndef RIFF_OPTIMIZE +List Chunk_With_Children::lookup_child (const char * class_ident) const +{ + List child_list; + + lookup_child(class_ident,child_list); + + return child_list; +} +#endif + +void Chunk_With_Children::lookup_child (const char * class_ident,List& child_list) const +{ + //make sure the list is empty first + while(child_list.size()) + { + child_list.delete_first_entry(); + } + + Chunk * child_ptr = children; + + if (children) + while (child_ptr != NULL) { + if (strncmp (class_ident, child_ptr->identifier, 8) == NULL) + { + assert (!child_ptr->r_u_miscellaneous()); + child_list.add_entry(child_ptr); + } + child_ptr = child_ptr->next; + } + + +} + +unsigned Chunk_With_Children::count_children (char const * class_ident) const +{ + unsigned nChildren = 0; + + Chunk * child_ptr = children; + + if (children) + while (child_ptr != NULL) { + if (strncmp (class_ident, child_ptr->identifier, 8) == NULL) + { + assert (!child_ptr->r_u_miscellaneous()); + ++ nChildren; + } + child_ptr = child_ptr->next; + } + + return nChildren; +} + +Chunk* Chunk_With_Children::lookup_single_child (const char * class_ident) const +{ + #if debug + //if debug make sure there is at most one of the required chunk type + Chunk * child_ptr = children; + Chunk * chunk_found=0; + if (children) + while (child_ptr != NULL) { + if (strncmp (class_ident, child_ptr->identifier, 8) == NULL) + { + assert (!child_ptr->r_u_miscellaneous()); + assert(!chunk_found); + chunk_found=child_ptr; + } + child_ptr = child_ptr->next; + } + return chunk_found; + #else + Chunk * child_ptr = children; + + if (children) + while (child_ptr != NULL) { + if (strncmp (class_ident, child_ptr->identifier, 8) == NULL) + { + assert (!child_ptr->r_u_miscellaneous()); + return child_ptr; + } + child_ptr = child_ptr->next; + } + return 0; + #endif + + + +} + +void Chunk_With_Children::prepare_for_output() +{ + Chunk * child_ptr = children; + if (children) + while (child_ptr != NULL){ + child_ptr->prepare_for_output (); + child_ptr = child_ptr->next; + } +} + +void Chunk_With_Children::post_input_processing() +{ + Chunk * child_ptr = children; + if (children) + while (child_ptr != NULL){ + child_ptr->post_input_processing (); + child_ptr = child_ptr->next; + } +} + +/////////////////////////////////////////////////// +//Chunk registering stuff + + +class RifRegEntry +{ + public: + int chunk_id_1; + int chunk_id_2; + int parent_id_1; + int parent_id_2; + Chunk * (* m_pfnCreate) (Chunk_With_Children* parent,const char* data); + + + /* + For two members of this class to be considered similar there chunk_is members must match. + If both parent_id members are zero for one of the objects being compared , then they are considered + equal regardless of the parent_id members of the other object. + Otherwise the parent_id members of the two objects must match. + (This is done because not all of the constructors insist on a given parent) + */ + inline bool operator == (RifRegEntry const & rEntry) const + { + if(chunk_id_1 != rEntry.chunk_id_1 || chunk_id_2 != rEntry.chunk_id_2) return FALSE; + if(parent_id_1 == 0 && parent_id_2 == 0) return TRUE; + if(rEntry.parent_id_1 == 0 && rEntry.parent_id_2 == 0) return TRUE; + return parent_id_1 == rEntry.parent_id_1 && parent_id_2 == rEntry.parent_id_2; + } + inline bool operator != (RifRegEntry const & rEntry) const + { + return ! operator == (rEntry); + } +}; + +inline unsigned HashFunction(RifRegEntry const & rEntry) +{ + return HashFunction(rEntry.chunk_id_1 + rEntry.chunk_id_2); +} + +static HashTable * g_pRifRegister = NULL; + +void Chunk::Register(const char* idChunk,const char* idParent, Chunk * (* pfnCreate) (Chunk_With_Children* parent,const char* data) ) +{ + static HashTable reg; + char temp_id[8]; + + g_pRifRegister = ® + + RifRegEntry entry; + + strncpy(temp_id,idChunk,8); + entry.chunk_id_1 = *(int*) &temp_id[0]; + entry.chunk_id_2 = *(int*) &temp_id[4]; + entry.m_pfnCreate = pfnCreate; + + if(idParent) + { + strncpy(temp_id,idParent,8); + entry.parent_id_1 = *(int*) &temp_id[0]; + entry.parent_id_2 = *(int*) &temp_id[4]; + } + else + { + entry.parent_id_1 = 0; + entry.parent_id_2 = 0; + } + + reg.AddAsserted(entry); +} + +Chunk* Chunk_With_Children::DynCreate(const char* data) +{ + /* + Look in hash tables for a constructor for this block + If none exists , create a Miscellaneous_Chunk + */ + if (g_pRifRegister) + { + RifRegEntry test; + test.chunk_id_1 = *(int*) data; + test.chunk_id_2 = *(int*) &data[4]; + test.parent_id_1 = *(int*) identifier; + test.parent_id_2 = *(int*) &identifier[4]; + test.m_pfnCreate = NULL; + + RifRegEntry const * pEntry = g_pRifRegister->Contains(test); + if (pEntry) + { + return pEntry->m_pfnCreate(this,data); + } + } + return new Miscellaneous_Chunk(this,data,(data + 12), (*(int *) (data + 8))-12); +} + + + + + + + + + + + diff --git a/3dc/win95/Chunk.hpp b/3dc/win95/Chunk.hpp new file mode 100644 index 0000000..e7afcb4 --- /dev/null +++ b/3dc/win95/Chunk.hpp @@ -0,0 +1,687 @@ +// Chunk library + +#ifndef _chunk_hpp +#define _chunk_hpp 1 + + +#if engine + + #include "3dc.h" + #include "mem3dc.h" // for debug new and delete + + + #include "inline.h" + +#if SupportModules + + #include "module.h" + +#endif + + #include "list_tem.hpp" + + +#endif + +#if cencon + +#include "AFXWIN.H" + +#ifdef _DEBUG +#undef new +#define new DEBUG_NEW +#define my_new DEBUG_NEW +#else +#define my_new new +#endif + +#include "list_tem.hpp" + +#endif + +#if objedit || sprite_edit || ANIMEXP +#include "StdAfx.h" +#include "list_tem.hpp" +#endif + +#if shpedit +#include "stdafx.h" +#include "list_tem.hpp" +#endif + +#if standard +#include "advwin32.h" +#include +#include "list_tem.hpp" +#endif + + +#define CHUNK_FAILED_ON_LOAD -1 +#define CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED -2 +#define CHUNK_FAILED_ON_WRITE -3 +#define CHECK_FAILED_NOT_OPEN -4 + +#define DisableLock 1 + +#define GENERAL_FLAG_LOCKED 0x0000001 + +// Non class functions ( only one as yet ) + +// The function will return a list of file pointers +// for the starting position of each chunk within a chunk +// File pointers are offset from the start of the file. + +// we start at the header of the chunk we are in +// so that we can stop at the end of the chunk + +#if cencon +extern char users_name[]; +#endif + +#ifndef RIFF_OPTIMIZE // define this to get compiler errors where you are calling the old slow functions +extern List list_chunks_in_file (HANDLE &, const char * chunk_id); +#endif +extern void list_chunks_in_file (List * pList, HANDLE, const char * chunk_id); + +// Structures for interfacing with the outside application +// these are going to be basically very C-ee so that C +// functions can also read them + + + +// The basic chunk class structure is as follows +// +// Base_Chunk +// | | +// Chunk_With_Children Data Chunks +// | +// File_Chunk +// + +// Most chunk classes are either derived from the Chunk +// class or the Chunk_With_Children class. + +// A chunk with data is derived from the Chunk class as follows + +// class Sample_Data_Chunk : public Chunk +// { +// public: +// +// // Constructors are placed either here or may be private +// // The constructors for most shape data chunks are private +// // as only the Shape_Chunk can call them. This is because +// // the shape chunk deals with the data. +// // +// // Any constuctor should initialise class chunk with the +// // correct identifier for the current chunk. +// // +// // There are normally two constructors - one for constructing +// // from interface data one for constructing from raw data. +// // +// // A destructor can also be placed here or may not be needed +// // +// // Any variables that are made available for the user should also +// // be placed here. +// // +// // The next three functions are vital for the io functions +// // +// virtual BOOL output_chunk (HANDLE &hand); +// // This function will write the chunk data to the file specified +// // by the windows file handle - hand. +// // +// virtual size_t size_chunk (); +// // This function will return the size of the chunk (including the header). +// // IT MUST SET the variable chunk_size to the size it returns +// // +// virtual fill_data_block (char * data_start); +// // This function will fill a data block with data. The data will be +// // the same as the file data. The data is assumed to be pre-allocated +// // with the size given by the size_chunk function. +// // +// } + +// A chunk with children is derived from the Chunk_With_Children class +// as follows +// +// class Sample_Chunk_With_Children : public Chunk +// { +// public: +// +// // Constructors may be used to construct child chunks from +// // interface data. A parsing constructor should be used for +// // constructing from raw data (look at Shape_Chunk). +// // +// // Any constructor should initialise class Chunk_With_Children with +// // the correct identifier for the current chunk. +// // +// // The Destructor does not need to destroy child chunks as the +// // Chunk_With_Children destructor will automatically do this. +// // +// // The three functions (size_chunk, output_chunk and fill_data_block) +// // are not needed as Chunk_With_Children can deal with these - but may +// // be put in. +// // +// } + +// +// + + +// The logic behind the locking is as follows. + +// There are two functions for locking and unlocking chunks +// these are currently only in the shape and object chunks + +// lock_chunk(File_Chunk &) +// will lock a chunk, this must only be called once +// and will return false if it tries to lock a chunk +// that has already been locked by anyone. + +// unlock_chunk (File_Chunk &, BOOL updatedyn) +// will unlock the chunk locally and in the file if it is not to be updated +// If it is to be updated, it will set the updated flag and +// the chunk can only be locked again once it is written to a file. + +// The user may call File_Chunk::update_file() whenever +// (either after every chunk update, or once a minute) +// Note that this fully unlocks locally locked chunks +// that are being written to the file. + +// Another function File_Chunk::update_chunks_from_file() +// will reload those chunks that have been externally upadted +// This must be done with care!! + +// The objects are associated with shapes primarily +// When a shape is being edited, a list of objects will +// be with that shape in the header. These objects will be locked +// also. + + + +/////////////////////////////////////////////// + +class Chunk +{ +public: + + //destructor + virtual ~Chunk (); + + // constructors + Chunk (class Chunk_With_Children * parent, const char * ident); + + virtual size_t size_chunk () = 0; + + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start) = 0; + + // this function is virtual, but will probably not be used elsewhere + virtual char * make_data_block_from_chunk (); + + + // Selective output functions, these are similar to the normal ones + // and will normally call the equivalents. + // special chunks will have there own functions which will only respond + // if they have a flag set + + virtual char * make_data_block_for_process(); + + virtual size_t size_chunk_for_process(); + + virtual void fill_data_block_for_process(char * data_start); + + // these functions are virtual, but will only be used sparingly + + virtual void prepare_for_output() + {} + + virtual void post_input_processing() + {} + + const char * identifier; + + int error_code; + + // this allows chunks with children to trap miscellaneous chunks + // that shouldn't be miscellaneous !!! + virtual BOOL r_u_miscellaneous() + { return FALSE; } + + static void Register(const char* idChunk,const char* idParent ,Chunk * (* pfnCreate) (Chunk_With_Children* parent,const char* data) ); + +private: + + // copy - private to stop chunks + // from being copied + Chunk (const Chunk &); + // ditto + void operator=(const Chunk &); + + // pointers to siblings + + friend class Chunk_With_Children; + friend class Sprite_Header_Chunk; // sprite updating needs to scan through all child chunks + friend class File_Chunk; + friend class RIF_File_Chunk; + friend class Shape_Chunk; + + Chunk * next; + Chunk * previous; + + // identifier store + + char identifier_store[9]; + +protected: + + size_t chunk_size; + + // pointer to parent + class Chunk_With_Children * parent; + +public : + + class Chunk_With_Children * GetRootChunk(void); + class Chunk_With_Children const * GetRootChunk(void) const; + +}; + + +/////////////////////////////////////////////// + +class Miscellaneous_Chunk : public Chunk +{ +public: + + Miscellaneous_Chunk (Chunk_With_Children * parent, const char * identifier, + const char * _data, size_t _data_size); + + + virtual ~Miscellaneous_Chunk (); + + virtual size_t size_chunk () + { + return (chunk_size = (data_size + 12)); + } + + virtual void fill_data_block (char * data_start); + + const size_t data_size; + const char * const data; + + // this allows chunks with children to trap miscellaneous chunks + // that shouldn't be miscellaneous !!! + virtual BOOL r_u_miscellaneous() + { return TRUE; } + +private: + + char * data_store; + +}; + + +/////////////////////////////////////////////// + +class Chunk_With_Children : public Chunk +{ + +public: + + virtual ~Chunk_With_Children(); + + Chunk_With_Children (Chunk_With_Children * parent, const char * identifier) + : Chunk (parent, identifier), children (NULL) {} + + virtual size_t size_chunk (); + + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start); + + virtual void prepare_for_output(); + + virtual void post_input_processing(); + + // look for child chunk(s) + #ifndef RIFF_OPTIMIZE // define this to get compiler errors where you are calling the old slow functions + List lookup_child (const char *) const; + #endif + void lookup_child (const char *,List&) const; + Chunk* lookup_single_child(const char*) const; + unsigned count_children(char const *) const; + + // Selective output functions, these are similar to the normal ones + // and will normally call the equivalents. + // special chunks will have there own functions which will only respond + // if they have a flag set + + virtual size_t size_chunk_for_process(); + + virtual void fill_data_block_for_process(char * data_start); + + + Chunk* Chunk_With_Children::DynCreate(const char* data); + +protected: + + friend class Chunk; + friend class File_Chunk; + + // points to a doubly linked list + Chunk * children; + +}; + +///////////////////////////////////////////// +// macros to save typing for chunk with children loader + +extern Chunk * Parent_File; + +#define CHUNK_WITH_CHILDREN_LOADER_PARENT __parent + +#define CHUNK_WITH_CHILDREN_LOADER_INIT_PT1(id,chunkclass) \ +chunkclass::chunkclass(Chunk_With_Children * const CHUNK_WITH_CHILDREN_LOADER_PARENT, char const * __data, size_t const __size) \ +:Chunk_With_Children(CHUNK_WITH_CHILDREN_LOADER_PARENT,id) + +#define CHUNK_WITH_CHILDREN_LOADER_INIT_PT2 { \ + const char * const __buffer_ptr = __data; \ + while (__data - __buffer_ptr < (signed)__size){ \ + if (*(int *)(__data + 8) + (__data-__buffer_ptr) > (signed)__size){ \ + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; \ + break;} + +#define LOCKABLE_CHUNK_WITH_CHILDREN_LOADER_INIT_PT1(id,chunkclass) \ +chunkclass::chunkclass(Chunk_With_Children * const CHUNK_WITH_CHILDREN_LOADER_PARENT, char const * __data, size_t const __size) \ +:Lockable_Chunk_With_Children(CHUNK_WITH_CHILDREN_LOADER_PARENT,id) + +#define LOCKABLE_CHUNK_WITH_CHILDREN_LOADER_INIT_PT2 { \ + const char * const __buffer_ptr = __data; \ + while (__data - __buffer_ptr < (signed) __size){ \ + if (*(int *)(__data + 8) + (__data-__buffer_ptr) > (signed) __size){ \ + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; \ + break;} + +#define CHUNK_WITH_CHILDREN_LOADER_INIT(id,chunkclass) \ + CHUNK_WITH_CHILDREN_LOADER_INIT_PT1(id,chunkclass) \ + CHUNK_WITH_CHILDREN_LOADER_INIT_PT2 + +#define LOCKABLE_CHUNK_WITH_CHILDREN_LOADER_INIT(id,chunkclass) \ + LOCKABLE_CHUNK_WITH_CHILDREN_LOADER_INIT_PT1(id,chunkclass) \ + LOCKABLE_CHUNK_WITH_CHILDREN_LOADER_INIT_PT2 + +#define CHUNK_WITH_CHILDREN_LOADER_FOR(id,chunkclass) \ + else if (!strncmp(__data,id,8)){ \ + new chunkclass(this,__data+12,*(int *)(__data+8)-12); \ + __data += *(int *)(__data+8);} + +#define CHUNK_WITH_CHILDREN_LOADER_END \ + else { \ + new Miscellaneous_Chunk (this, __data, (__data + 12), (*(int *) (__data + 8)) -12 ); \ + __data += *(int *)(__data + 8);}}} + +// example: +// +// CHUNK_WITH_CHILDREN_LOADER_INIT("GAMEMODE",Environment_Game_Mode_Chunk) +// CHUNK_WITH_CHILDREN_LOADER_FOR("ENVPALET",Environment_Palette_Chunk) +// CHUNK_WITH_CHILDREN_LOADER_FOR("ENVTXLIT",Environment_TLT_Chunk) +// CHUNK_WITH_CHILDREN_LOADER_FOR("CLRLOOKP",Coloured_Polygons_Lookup_Chunk) +// CHUNK_WITH_CHILDREN_LOADER_FOR("RIFCHILD",RIF_Name_Chunk) +// CHUNK_WITH_CHILDREN_LOADER_END + +/////////////////////////////////////////////// +//macros for use in chunk construction from buffer, assume buffer is called data + +//read variable of type 'type' +#define CHUNK_EXTRACT(var,type) \ + var=*(type*)data; \ + data+=sizeof(type); + +//read 4 byte aligned string +#define CHUNK_EXTRACT_STRING(var) { \ + int __length=strlen(data); \ + if(__length) \ + { \ + var=new char[__length+1]; \ + strcpy(var,data); \ + } \ + else var=0; \ + data+=(__length+4) &~3 ;} + +//read array +//length is an int (filled in by macro) +//pointer is a pointer of type 'type' +#define CHUNK_EXTRACT_ARRAY(length,pointer,type){\ + CHUNK_EXTRACT(length,int) \ + if(length) \ + { \ + pointer=new type[length]; \ + for(int __i=0;__i (signed) __size) {\ + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;\ + break;\ + }\ + \ + DynCreate(__data);\ + __data += *(int *)(__data + 8);\ + }\ +} +/* +Load from buffer function for standard Lockable_Chunk_With_Children +*/ + +#define LOCKABLE_CHUNK_WITH_CHILDREN_LOADER(id,chunk_class) \ +chunk_class::chunk_class(Chunk_With_Children * const parent,char const * __data, size_t const __size)\ +:Lockable_Chunk_With_Children(parent,id)\ +{\ + const char * __buffer_ptr = __data;\ + while ((__data-__buffer_ptr)< (signed) __size) {\ + if ((*(int *)(__data + 8)) + (__data-__buffer_ptr) > (signed) __size) {\ + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;\ + break;\ + }\ + \ + DynCreate(__data);\ + __data += *(int *)(__data + 8);\ + }\ +} + + +//macros for forcing inclusion of chunk files from a library +#define FORCE_CHUNK_INCLUDE_START //not needed anymore + +#define FORCE_CHUNK_INCLUDE(filename)\ + extern int __Chunk_Include_##filename;\ + int* p__Chunk_Include_##filename =& __Chunk_Include_##filename; + +#define FORCE_CHUNK_INCLUDE_END //not needed anymore + + +#define FORCE_CHUNK_INCLUDE_IMPLEMENT(filename) int __Chunk_Include_##filename; + +/* +//eg. +FORCE_CHUNK_INCLUDE_START +FORCE_CHUNK_INCLUDE(mishchnk) +FORCE_CHUNK_INCLUDE(shpchunk) +FORCE_CHUNK_INCLUDE(obchunk) +FORCE_CHUNK_INCLUDE(envchunk) +FORCE_CHUNK_INCLUDE(animchnk) +FORCE_CHUNK_INCLUDE(hierchnk) +FORCE_CHUNK_INCLUDE(animobs) +FORCE_CHUNK_INCLUDE(sndchunk) +FORCE_CHUNK_INCLUDE(avpchunk) +FORCE_CHUNK_INCLUDE(bmpnames) +FORCE_CHUNK_INCLUDE(chunkpal) +FORCE_CHUNK_INCLUDE(dummyobjectchunk) +FORCE_CHUNK_INCLUDE(enumchnk) +FORCE_CHUNK_INCLUDE(enumsch) +FORCE_CHUNK_INCLUDE(fragchnk) +FORCE_CHUNK_INCLUDE(gsprchnk) +FORCE_CHUNK_INCLUDE(hierplace) +FORCE_CHUNK_INCLUDE(ltchunk) +FORCE_CHUNK_INCLUDE(oechunk) +FORCE_CHUNK_INCLUDE(pathchnk) +FORCE_CHUNK_INCLUDE(sprchunk) +FORCE_CHUNK_INCLUDE(strachnk) +FORCE_CHUNK_INCLUDE(toolchnk) +FORCE_CHUNK_INCLUDE(wpchunk) +FORCE_CHUNK_INCLUDE_END +*/ + +#endif // !included + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/3dc/win95/D3_IMAGE.CPP b/3dc/win95/D3_IMAGE.CPP new file mode 100644 index 0000000..c068b82 --- /dev/null +++ b/3dc/win95/D3_IMAGE.CPP @@ -0,0 +1,2491 @@ +#include +#include + +#include "d3_image.hpp" +#include "platform.h" + +// define = 1 if you dont have pre-quantized images to load into palettized D3D texture surfaces +#define QUANTISE_ON_LOAD 0 + +#if debug +#define DEBUG_TRANSPARENCY 1 +#else +#define DEBUG_TRANSPARENCY 0 +#endif + +// image loader stuff + +#if OUTPUT_LOG +#include "debuglog.hpp" +LogFile CL_LogFile("DB_IMLD.LOG"); +#endif + +#if TIME_LOADS +unsigned int OpenTime; +unsigned int CloseTime; +unsigned int ReadTime; +#endif + +static inline unsigned long read_le_dword(D3I_FILE * f) +{ + unsigned char d1,d2,d3,d4; + d3i_fread(&d1,1,1,f); + d3i_fread(&d2,1,1,f); + d3i_fread(&d3,1,1,f); + d3i_fread(&d4,1,1,f); + + return (unsigned long)d1 | (unsigned long)d2<<8 | (unsigned long)d3<<16 | (unsigned long)d4<<24; +} + +static inline unsigned short read_le_word(D3I_FILE * f) +{ + unsigned char d1,d2; + d3i_fread(&d1,1,1,f); + d3i_fread(&d2,1,1,f); + + return (unsigned short)d1 | (unsigned short)((unsigned short)d2<<8); +} + +// some default globals +CL_ImageMode CL_Image::imode = CLM_GLOBALPALETTE; +CL_ImageMode CL_Image::imode_d3d = CLM_ATTACHEDPALETTE; +CL_ImageMode CL_Image::imode_ddraw = CLM_GLOBALPALETTE; +LPDDSURFACEDESC CL_Image::format = 0; +unsigned int CL_Image::bitsperpixel; +unsigned int CL_Image::bitsperpixel_d3d; +unsigned int CL_Image::bitsperpixel_ddraw; +CL_LoadMode CL_Image::lmode = CLL_DDSURFACE; + +CL_DX_Format CL_Pixel_32::f; +CL_DX_Format CL_Pixel_32::f_d3d; +CL_DX_Format CL_Pixel_32::f_ddraw; +CL_DX_Format CL_Pixel_16::f; +CL_DX_Format CL_Pixel_16::f_d3d; +CL_DX_Format CL_Pixel_16::f_ddraw; + + +void CL_Image::DeleteNotMips(void) +{ + if (im24) + { + delete[] *im24; + delete[] im24; + im24 = 0; + } + if (im16) + { + delete[] *im16; + delete[] im16; + im16 = 0; + } + if (im8) + { + delete[] *im8; + delete[] im8; + im8 = 0; + } + if (palette) + { + delete[] palette; + palette = 0; + palette_size = 0; + } + flags.loaded = 0; + flags.raw16bit = 0; +} + +void CL_Image::Delete(void) +{ + DeleteNotMips(); + while (mipmaps.size()) + { + delete mipmaps.last_entry(); + mipmaps.delete_last_entry(); + } +} + + +void CL_Image::Copy(CL_Image const & i2) +{ + if (i2.im24) + { + im24 = new CL_Pixel_24 * [height]; + *im24 = new CL_Pixel_24 [size]; + + CL_Pixel_24 const * sptr = *i2.im24; + CL_Pixel_24 * dptr = *im24; + + for (int i=size; i; --i) + { + *dptr++ = *sptr++; + } + + CL_Pixel_24 const * * dptrptr = (CL_Pixel_24 const * *) im24; + CL_Pixel_24 const * aptr = *im24; + for (i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + } + + if (i2.im16) + { + im16 = new CL_Pixel_16 * [height]; + *im16 = new CL_Pixel_16 [size]; + + CL_Pixel_16 const * sptr = *i2.im16; + CL_Pixel_16 * dptr = *im16; + + for (int i=size; i; --i) + { + *dptr++ = *sptr++; + } + + CL_Pixel_16 const * * dptrptr = (CL_Pixel_16 const * *) im16; + CL_Pixel_16 const * aptr = *im16; + for (i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + } + + if (i2.im8) + { + im8 = new unsigned char * [height]; + *im8 = new unsigned char [size]; + + unsigned char const * sptr = *i2.im8; + unsigned char * dptr = *im8; + + for (int i=size; i; --i) + { + *dptr++ = *sptr++; + } + + unsigned char const * * dptrptr = (unsigned char const * *) im8; + unsigned char const * aptr = *im8; + for (i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + } + + if (i2.palette) + { + palette = new CL_Pixel_24 [palette_size]; + + CL_Pixel_24 const * sptr = i2.palette; + CL_Pixel_24 * dptr = palette; + + for (int i=palette_size; i; --i) + { + *dptr++ = *sptr; + } + } + + if (i2.name) + { + name = new char [strlen(i2.name)+1]; + strcpy(name,i2.name); + } + + if (i2.fname) + { + fname = new char [strlen(i2.fname)+1]; + strcpy(fname,i2.fname); + } + + for (CLIF i_mip(&i2.mipmaps); !i_mip.done(); i_mip.next()) + { + mipmaps.add_entry_end(new CL_Image(*i_mip())); + } +} + + +CL_Image::~CL_Image() +{ + Delete(); + if (fname) delete[] fname; + if (name) delete[] name; +} + + +CL_Image::CL_Image(CL_Image const & i2) +: width(i2.width) +, height(i2.height) +, size(i2.size) +, im24(0) +, im16(0) +, im8(0) +, palette(0) +, palette_size(i2.palette_size) +, fname(0) +, name(0) +, flags(i2.flags) +{ + Copy(i2); +} + + +CL_Image & CL_Image::operator = (CL_Image const & i2) +{ + if (&i2 != this) + { + Delete(); + if (fname) delete[] fname; + if (name) delete[] name; + + width = i2.width; + height = i2.height; + size = i2.size; + palette_size = i2.palette_size; + + fname = 0; + name = 0; + + flags = i2.flags; + + Copy(i2); + } + return *this; +} + + +CL_Error CL_Image::Make(int const _width, int const _height) +{ + Delete(); + + width = _width; + height = _height; + palette_size = 0; + size = width*height; + + switch (imode) + { + case CLM_ATTACHEDPALETTE: + { + palette_size = 256; + palette = new CL_Pixel_24 [palette_size]; + } + case CLM_GLOBALPALETTE: + case CLM_TLTPALETTE: + { + im8 = new unsigned char * [height]; + *im8 = new unsigned char [size]; + + unsigned char const * * dptrptr = (unsigned char const * *) im8; + unsigned char * dptr = *im8; + for (int i=height; i; --i, dptr+=width) + { + *dptrptr++ = dptr; + } + + break; + } + case CLM_24BIT: + { + im24 = new CL_Pixel_24 * [height]; + *im24 = new CL_Pixel_24 [size]; + + CL_Pixel_24 const * * dptrptr = (CL_Pixel_24 const * *) im24; + CL_Pixel_24 const * aptr = *im24; + for (int i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + + break; + } + case CLM_16BIT: + { + im16 = new CL_Pixel_16 * [height]; + *im16 = new CL_Pixel_16 [size]; + + CL_Pixel_16 const * * dptrptr = (CL_Pixel_16 const * *) im16; + CL_Pixel_16 const * aptr = *im16; + for (int i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + + break; + } + case CLM_32BIT: + { + im32 = new CL_Pixel_32 * [height]; + *im32 = new CL_Pixel_32 [size]; + + CL_Pixel_32 const * * dptrptr = (CL_Pixel_32 const * *) im32; + CL_Pixel_32 const * aptr = *im32; + for (int i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + + break; + } + default: + return CLE_INVALIDDXMODE; + } + + flags.loaded = 1; + return CLE_OK; +} + + +CL_Error CL_Image::MakeRandom(int const _width, int const _height, int const seed) +{ + Delete(); + + if (-1!=seed) srand((unsigned int)seed); + + width = _width; + height = _height; + size = width*height; + palette_size = 0; + + switch (imode) + { + case CLM_ATTACHEDPALETTE: + { + palette_size = 256; + palette = new CL_Pixel_24 [palette_size]; + CL_Pixel_24 * palP = palette; + for (int i=palette_size; i; --i, ++palP) + { + *palP = CL_Pixel_24(rand()&255,rand()&255,rand()&255); + } + } + case CLM_GLOBALPALETTE: + case CLM_TLTPALETTE: + { + im8 = new unsigned char * [height]; + *im8 = new unsigned char [size]; + + unsigned char const * * dptrptr = (unsigned char const * *) im8; + unsigned char * dptr = *im8; + for (int i=height; i; --i) + { + *dptrptr++ = dptr; + for (int j=width; j; --j, ++dptr) + *dptr = (unsigned char)(rand()&(palette_size-1)); + } + + break; + } + case CLM_24BIT: + { + im24 = new CL_Pixel_24 * [height]; + *im24 = new CL_Pixel_24 [size]; + + CL_Pixel_24 const * * dptrptr = (CL_Pixel_24 const * *) im24; + CL_Pixel_24 * aptr = *im24; + for (int i=height; i; --i) + { + *dptrptr++ = aptr; + for (int j=width; j; --j, ++aptr) + *aptr = CL_Pixel_24(rand()&255,rand()&255,rand()&255); + } + + break; + } + case CLM_16BIT: + { + im16 = new CL_Pixel_16 * [height]; + *im16 = new CL_Pixel_16 [size]; + + CL_Pixel_16 const * * dptrptr = (CL_Pixel_16 const * *) im16; + CL_Pixel_16 * aptr = *im16; + for (int i=height; i; --i) + { + *dptrptr++ = aptr; + for (int j=width; j; --j, ++aptr) + *aptr = CL_Pixel_24(rand()&255,rand()&255,rand()&255); + } + + break; + } + case CLM_32BIT: + { + im32 = new CL_Pixel_32 * [height]; + *im32 = new CL_Pixel_32 [size]; + + CL_Pixel_32 const * * dptrptr = (CL_Pixel_32 const * *) im32; + CL_Pixel_32 * aptr = *im32; + for (int i=height; i; --i) + { + *dptrptr++ = aptr; + for (int j=width; j; --j, ++aptr) + *aptr = CL_Pixel_24(rand()&255,rand()&255,rand()&255); + } + + break; + } + default: + return CLE_INVALIDDXMODE; + } + + flags.loaded = 1; + return CLE_OK; +} + + +CL_Error CL_Image::Load_BMP(D3I_FILE * f) +{ + if (!f) return CLE_OPENERROR; + + DeleteNotMips(); + + switch (imode) + { + case CLM_ATTACHEDPALETTE: + case CLM_24BIT: + case CLM_16BIT: + case CLM_32BIT: + break; + default: + return CLE_INVALIDDXMODE; + } + + d3i_fseek(f,0,SEEK_SET); + unsigned short magic; + d3i_fread(&magic,2,1,f); + if (magic != *(unsigned short const *)"BM") return CLE_LOADERROR; + + size_t filesize = read_le_dword(f); + d3i_fseek(f,4,SEEK_CUR); + size_t offset = read_le_dword(f); + size_t headsize = read_le_dword(f); + + unsigned short bitdepth; + + if (12 == headsize) // OS/2 1.x + { + width = read_le_word(f); + height = read_le_word(f); + size = width * height; + if (!width || !height) return CLE_LOADERROR; + unsigned short planes = read_le_word(f); + if (1 != planes) return CLE_LOADERROR; + bitdepth = read_le_word(f); + + if (bitdepth != 24) + { + palette_size = 1<Read(f,CLF_BGR); + } + } + } + else if (40 == headsize || 64 == headsize) // Windows 3.x || OS/2 2.x + { + width = read_le_dword(f); + height = read_le_dword(f); + unsigned short planes = read_le_word(f); + if (1 != planes) return CLE_LOADERROR; + bitdepth = read_le_word(f); + + if (read_le_dword(f)) return CLE_LOADERROR; // compressed bmps not supported + + size = read_le_dword(f); + + d3i_fseek(f,8,SEEK_CUR); + palette_size = read_le_dword(f); + if (!palette_size && bitdepth != 24) palette_size = 1<Read(f,CLF_BGRX); + } + } + } + else return CLE_LOADERROR; + + d3i_fseek(f,offset,SEEK_SET); + + if (palette_size) + { + if (bitdepth < 4) + { + delete[] palette; + palette_size = 0; + return CLE_LOADERROR; + } + + im8 = new unsigned char * [height]; + *im8 = new unsigned char [size]; + + unsigned char const * * dptrptr = (unsigned char const * *) im8; + unsigned char * dptr = *im8; + for (int i=height; i; --i, dptr+=width) + { + *dptrptr++ = dptr; + } + + #if DEBUG_TRANSPARENCY + int num_tps=0; + #endif + for (i=height-1; i>=0; --i) + { + dptr = im8[i]; + + if (4==bitdepth) + { + for (int i=width>>1; i; --i) + { + unsigned char byte; + d3i_fread(&byte,1,1,f); + #if DEBUG_TRANSPARENCY + *dptr = (unsigned char)(byte >> 4 & 0xf); + if (!*dptr) num_tps++; + *++dptr = (unsigned char)(byte & 0xf); + if (!*dptr) num_tps++; + ++dptr; + #else + *dptr++ = (unsigned char)(byte >> 4 & 0xf); + *dptr++ = (unsigned char)(byte & 0xf); + #endif + } + if (width & 1) + { + d3i_fread(dptr,1,1,f); + *dptr &= 0xf; + #if DEBUG_TRANSPARENCY + if (!*dptr) num_tps++; + #endif + } + + d3i_fseek(f,(~(width-1) & 7)>>1,SEEK_CUR); + } + else + { + for (int i=width; i; --i) + { + #if DEBUG_TRANSPARENCY + d3i_fread(dptr,1,1,f); + if (!*dptr) num_tps++; + dptr++; + #else + d3i_fread(dptr++,1,1,f); + #endif + } + d3i_fseek(f,~(width-1) & 3,SEEK_CUR); + } + } + #if DEBUG_TRANSPARENCY + if (num_tps) CL_LogFile.lprintf("-- %d TRANSPARENT PIXELS FOUND\n",num_tps); + #endif + } + else if (CLM_16BIT == imode) + { + im16 = new CL_Pixel_16 * [height]; + *im16 = new CL_Pixel_16 [size]; + + CL_Pixel_16 const * * dptrptr = (CL_Pixel_16 const * *) im16; + CL_Pixel_16 const * aptr = *im16; + for (int i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + + for (i=height-1; i>=0; --i) + { + CL_Pixel_16 * dptr = im16[i]; + + for (int i=width; i; --i) + { + dptr++->Read(f,CLF_BGR); + } + d3i_fseek(f,~(width*3-1) & 3,SEEK_CUR); + } + + } + else if (CLM_32BIT == imode) + { + im32 = new CL_Pixel_32 * [height]; + *im32 = new CL_Pixel_32 [size]; + + CL_Pixel_32 const * * dptrptr = (CL_Pixel_32 const * *) im32; + CL_Pixel_32 const * aptr = *im32; + for (int i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + + for (i=height-1; i>=0; --i) + { + CL_Pixel_32 * dptr = im32[i]; + + for (int i=width; i; --i) + { + dptr++->Read(f,CLF_BGR); + } + d3i_fseek(f,~(width*3-1) & 3,SEEK_CUR); + } + + } + else if (CLM_24BIT == imode) + { + im24 = new CL_Pixel_24 * [height]; + *im24 = new CL_Pixel_24 [size]; + + CL_Pixel_24 const * * dptrptr = (CL_Pixel_24 const * *) im24; + CL_Pixel_24 const * aptr = *im24; + for (int i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + + for (i=height-1; i>=0; --i) + { + CL_Pixel_24 * dptr = im24[i]; + + for (int i=width; i; --i) + { + dptr++->Read(f,CLF_BGR); + } + d3i_fseek(f,~(width*3-1) & 3,SEEK_CUR); + } + + } + else return CLE_INVALIDDXMODE; + + if (palette_size && CLM_ATTACHEDPALETTE != imode) + { + if (CLM_16BIT == imode) + { + im16 = new CL_Pixel_16 * [height]; + *im16 = new CL_Pixel_16 [size]; + + unsigned char const * sptr = *im8; + CL_Pixel_16 * dptr = *im16; + + for (int i=size; i; --i, ++dptr,++sptr) + { + if (*sptr && !palette[*sptr]) + *dptr = dptr->f.dx_black; + else + *dptr = palette[*sptr]; + } + + CL_Pixel_16 const * * dptrptr = (CL_Pixel_16 const * *) im16; + CL_Pixel_16 const * aptr = *im16; + for (i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + } + else if (CLM_32BIT == imode) + { + im32 = new CL_Pixel_32 * [height]; + *im32 = new CL_Pixel_32 [size]; + + unsigned char const * sptr = *im8; + CL_Pixel_32 * dptr = *im32; + + for (int i=size; i; --i, ++dptr,++sptr) + { + if (*sptr && !palette[*sptr]) + *dptr = dptr->f.dx_black; + else + *dptr = palette[*sptr]; + } + + CL_Pixel_32 const * * dptrptr = (CL_Pixel_32 const * *) im32; + CL_Pixel_32 const * aptr = *im32; + for (i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + } + else + { + im24 = new CL_Pixel_24 * [height]; + *im24 = new CL_Pixel_24 [size]; + + unsigned char const * sptr = *im8; + CL_Pixel_24 * dptr = *im24; + + for (int i=size; i; --i, ++dptr,++sptr) + { + if (*sptr && !palette[*sptr]) + *dptr = CL_Pixel_24(0,1,0); + else + *dptr = palette[*sptr]; + } + + CL_Pixel_24 const * * dptrptr = (CL_Pixel_24 const * *) im24; + CL_Pixel_24 const * aptr = *im24; + for (i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + } + + delete[] palette; + palette = 0; + palette_size = 0; + delete[] *im8; + delete[] im8; + im8 = 0; + } + + if (d3i_ferror(f) || d3i_feof(f)) + { + DeleteNotMips(); + return CLE_LOADERROR; + } + + flags.loaded = 1; + return CLE_OK; +} + + +CL_Error CL_Image::Load_PPM(D3I_FILE * f) +{ + if (!f) return CLE_OPENERROR; + + DeleteNotMips(); + + switch (imode) + { + case CLM_24BIT: + case CLM_16BIT: + case CLM_32BIT: + break; + default: + return CLE_INVALIDDXMODE; + } + + d3i_fseek(f,0,SEEK_SET); + unsigned short magic; + d3i_fread(&magic,2,1,f); + if (magic != *(unsigned short const *)"P6") return CLE_LOADERROR; + + d3i_fseek(f,1,SEEK_CUR); + char buf[256]; + char * bufptr = buf; + unsigned int fields[5]; + unsigned int fields_read = 0; + while (fields_read < 3 && bufptr) + { + do bufptr = d3i_fgets(buf, sizeof buf, f); + while ('#'==buf[0] && bufptr); + + int num_fields_read = sscanf(buf,"%u %u %u",&fields[fields_read],&fields[fields_read+1],&fields[fields_read+2]); + if (EOF != num_fields_read) fields_read += num_fields_read; + } + if (fields_read < 3) return CLE_LOADERROR; + width = fields[0]; + height = fields[1]; + unsigned int maxval = fields[2]; + if (maxval > 255) return CLE_LOADERROR; + + size = width * height; + + if (CLM_16BIT == imode) + { + im16 = new CL_Pixel_16 * [height]; + *im16 = new CL_Pixel_16 [size]; + + CL_Pixel_16 * rptr = *im16; + for (int i=size; i; --i) + { + rptr++->Read(f,CLF_RGB,maxval); + } + + CL_Pixel_16 const * * dptrptr = (CL_Pixel_16 const * *) im16; + CL_Pixel_16 const * aptr = *im16; + for (i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + } + else if (CLM_32BIT == imode) + { + im32 = new CL_Pixel_32 * [height]; + *im32 = new CL_Pixel_32 [size]; + + CL_Pixel_32 * rptr = *im32; + for (int i=size; i; --i) + { + rptr++->Read(f,CLF_RGB,maxval); + } + + CL_Pixel_32 const * * dptrptr = (CL_Pixel_32 const * *) im32; + CL_Pixel_32 const * aptr = *im32; + for (i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + } + else + { + im24 = new CL_Pixel_24 * [height]; + *im24 = new CL_Pixel_24 [size]; + + CL_Pixel_24 * rptr = *im24; + for (int i=size; i; --i) + { + rptr++->Read(f,CLF_RGB,maxval); + } + + CL_Pixel_24 const * * dptrptr = (CL_Pixel_24 const * *) im24; + CL_Pixel_24 const * aptr = *im24; + for (i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + } + + if (d3i_ferror(f) || d3i_feof(f)) + { + DeleteNotMips(); + return CLE_LOADERROR; + } + + flags.loaded = 1; + return CLE_OK; +} + + +CL_Error CL_Image::Load_PGM(D3I_FILE * f) +{ + if (!f) return CLE_OPENERROR; + + DeleteNotMips(); + + switch (imode) + { + case CLM_GLOBALPALETTE: + case CLM_TLTPALETTE: + break; + default: + return CLE_INVALIDDXMODE; + } + + d3i_fseek(f,0,SEEK_SET); + unsigned short magic; + d3i_fread(&magic,2,1,f); + if (magic != *(unsigned short const *)"P5") return CLE_LOADERROR; + + d3i_fseek(f,1,SEEK_CUR); + char buf[256]; + char * bufptr = buf; + unsigned int fields[5]; + unsigned int fields_read = 0; + while (fields_read < 3 && bufptr) + { + do bufptr = d3i_fgets(buf, sizeof buf, f); + while ('#'==buf[0] && bufptr); + + int num_fields_read = sscanf(buf,"%u %u %u",&fields[fields_read],&fields[fields_read+1],&fields[fields_read+2]); + if (EOF != num_fields_read) fields_read += num_fields_read; + } + if (fields_read < 3) return CLE_LOADERROR; + width = fields[0]; + height = fields[1]; + unsigned int maxval = fields[2]; + if (maxval > 255) return CLE_LOADERROR; + + size = width * height; + + im8 = new unsigned char * [height]; + *im8 = new unsigned char [size]; + + d3i_fread(*im8,1,size,f); + + unsigned char const * * dptrptr = (unsigned char const * *) im8; + unsigned char const * aptr = *im8; + for (int i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + + if (d3i_ferror(f) || d3i_feof(f)) + { + DeleteNotMips(); + return CLE_LOADERROR; + } + + flags.loaded = 1; + return CLE_OK; +} + + +CL_Error CL_Image::Load_PWM(D3I_FILE * f) +{ + if (!f) return CLE_OPENERROR; + + DeleteNotMips(); + + switch (imode) + { + case CLM_TLTPALETTE: + break; + default: + return CLE_INVALIDDXMODE; + } + + d3i_fseek(f,0,SEEK_SET); + unsigned short magic; + d3i_fread(&magic,2,1,f); + if (magic != *(unsigned short const *)"P8") return CLE_LOADERROR; + + d3i_fseek(f,1,SEEK_CUR); + char buf[256]; + char * bufptr = buf; + unsigned int fields[5]; + unsigned int fields_read = 0; + while (fields_read < 3 && bufptr) + { + do bufptr = d3i_fgets(buf, sizeof buf, f); + while ('#'==buf[0] && bufptr); + + int num_fields_read = sscanf(buf,"%u %u %u",&fields[fields_read],&fields[fields_read+1],&fields[fields_read+2]); + if (EOF != num_fields_read) fields_read += num_fields_read; + } + if (fields_read < 3) return CLE_LOADERROR; + width = fields[0]; + height = fields[1]; + unsigned int maxval = fields[2]; + if (maxval > 65535) return CLE_LOADERROR; + + size = width * height; + + im16raw = new unsigned short * [height]; + *im16raw = new unsigned short [size]; + + d3i_fread(*im16raw,2,size,f); + + unsigned short const * * dptrptr = (unsigned short const * *) im16raw; + unsigned short const * aptr = *im16raw; + for (int i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + + if (d3i_ferror(f) || d3i_feof(f)) + { + DeleteNotMips(); + return CLE_LOADERROR; + } + + flags.loaded = 1; + flags.raw16bit = 1; + return CLE_OK; +} + + + +CL_Error CL_Image::GetBitsPerPixel(unsigned int* bpp) +{ + *bpp = bitsperpixel; + return CLE_OK; +} + +CL_Error CL_Image::Load_Image(D3I_FILE * f) +{ + if (!f) return CLE_OPENERROR; + + CL_Error retval = CLE_LOADERROR; + + START_TIMER + + d3i_fseek(f,0,SEEK_SET); + unsigned short magic; + d3i_fread(&magic,2,1,f); + + if ( *(unsigned short const *)"BM" == magic) + retval = Load_BMP(f); + else if ( *(unsigned short const *)"P6" == magic) + retval = Load_PPM(f); + else if ( *(unsigned short const *)"P5" == magic) + retval = Load_PGM(f); + else if ( *(unsigned short const *)"P8" == magic) + retval = Load_PWM(f); + #if OUTPUT_LOG + else CL_LogFile.lputs("** ERROR: Not a recognized file format\n"); + #endif + + END_TIMER(ReadTime) + + #if OUTPUT_LOG + #if TIME_LOADS + CL_LogFile.lprintf("-- Timer Stats (ms): Open %d Read %d Close %d\n",OpenTime,ReadTime,CloseTime); + #endif + #endif + + return retval; +} + + +void CL_Image::PadTo(int const width_unit,int const height_unit) +{ + if (!flags.loaded) return; + + unsigned int const owidth = width; + unsigned int const oheight = height; + + width += width_unit-1; + width &= ~(width_unit-1); + height += height_unit-1; + height &= ~(height_unit-1); + + if (width == owidth && height == oheight) return; // already in spec + + size = width * height; + + CL_Pixel_32 * * const oim32 = im32; + CL_Pixel_16 * * const oim16 = im16; + unsigned char * * const oim8 = im8; + + if (oim32) + { + im32 = new CL_Pixel_32 * [height]; + *im32 = new CL_Pixel_32 [size]; + + CL_Pixel_32 const * * dptrptr = (CL_Pixel_32 const * *) im32; + CL_Pixel_32 const * aptr = *im32; + for (unsigned int i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + + for (unsigned int y = 0; y < oheight; ++y) + { + CL_Pixel_32 const * sptr = oim32[y]; + CL_Pixel_32 * dptr = im32[y]; + + for (unsigned int x = 0; x < owidth; ++x, ++dptr, ++sptr) + *dptr = *sptr; + + for (; x < width; ++x, ++dptr) + *dptr = CL_Pixel_24(0,0,0); + } + + for (; y < height; ++y) + { + CL_Pixel_32 * dptr = im32[y]; + for (unsigned int x = 0; x < width; ++x, ++dptr) + *dptr = CL_Pixel_24(0,0,0); + } + + delete[] *oim32; + delete[] oim32; + } + + if (oim16) + { + im16 = new CL_Pixel_16 * [height]; + *im16 = new CL_Pixel_16 [size]; + + CL_Pixel_16 const * * dptrptr = (CL_Pixel_16 const * *) im16; + CL_Pixel_16 const * aptr = *im16; + for (unsigned int i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + + for (unsigned int y = 0; y < oheight; ++y) + { + CL_Pixel_16 const * sptr = oim16[y]; + CL_Pixel_16 * dptr = im16[y]; + + for (unsigned int x = 0; x < owidth; ++x, ++dptr, ++sptr) + *dptr = *sptr; + + for (; x < width; ++x, ++dptr) + *dptr = CL_Pixel_24(0,0,0); + } + + for (; y < height; ++y) + { + CL_Pixel_16 * dptr = im16[y]; + for (unsigned int x = 0; x < width; ++x, ++dptr) + *dptr = CL_Pixel_24(0,0,0); + } + + delete[] *oim16; + delete[] oim16; + } + + if (oim8) + { + im8 = new unsigned char * [height]; + *im8 = new unsigned char [size]; + + unsigned char const * * dptrptr = (unsigned char const * *) im8; + unsigned char const * aptr = *im8; + for (unsigned int i=height; i; --i, aptr+=width) + { + *dptrptr++ = aptr; + } + + for (unsigned int y = 0; y < oheight; ++y) + { + unsigned char const * sptr = oim8[y]; + unsigned char * dptr = im8[y]; + + for (unsigned int x = 0; x < owidth; ++x, ++dptr, ++sptr) + *dptr = *sptr; + + for (; x < width; ++x, ++dptr) + *dptr = 0; + } + + for (; y < height; ++y) + { + unsigned char * dptr = im8[y]; + for (unsigned int x = 0; x < width; ++x, ++dptr) + *dptr = 0; + } + + delete[] *oim8; + delete[] oim8; + } +} + +// implementation of the 'popularity algorithm' for reducing palette + +unsigned int CL_Pixel_24::FVD_Distance(CL_Pixel_24 const & p2) const +{ + unsigned int dg = g > p2.g ? g - p2.g : p2.g - g; + unsigned int db = b > p2.b ? b - p2.b : p2.b - b; + + unsigned int dgb = dg + db + ((dg > db ? dg : db)<<1); + + unsigned int dr = r > p2.r ? r - p2.r : p2.r - r; + dr += dr<<1; // *= 3 + + return dr + dgb + ((dr > dgb ? dr : dgb)<<1); +} + +struct _CL_palpixcnt +{ + unsigned int cnt; + unsigned int palpos; +}; + +int _CL_cmp_palpixcnt(void const * e1, void const * e2) +{ + return ((_CL_palpixcnt *)e2)->cnt - ((_CL_palpixcnt *)e1)->cnt; +} + +CL_Error CL_Image::ReducePalette(unsigned int const num_colours) +{ + if (!flags.loaded) return CLE_LOADERROR; + + if (!palette) return CLE_INVALIDDXMODE; + if (!im8) return CLE_INVALIDDXMODE; + + if (palette_size <= num_colours) return CLE_OK; + + _CL_palpixcnt * const sortarray = new _CL_palpixcnt[palette_size]; + + for (unsigned int i=0; iname = new char[strlen(name)+1]; + mip_n->fname = new char[strlen(fname)+1]; + strcpy(mip_n->name,name); + strcpy(mip_n->fname,fname); + + char * dotpos = strrchr(mip_n->fname,'.'); + if (!dotpos) + { + delete mip_n; + break; + } + sprintf(dotpos+3,"%1d",mip_idx); + + mip_n->flags.located = 1; + + if (CLE_OK!=mip_n->Load()) + { + delete mip_n; + break; + } + + if (mip_n->width << mip_idx < width || mip_n->height << mip_idx < height) + { + delete mip_n; + #if OUTPUT_LOG + CL_LogFile.lputs("** Warning: less than half size\n"); + #endif + break; + } + + mipmaps.add_entry_end(mip_n); + } + return CLE_OK; +} + +void CL_Select_Mode(CL_LoadMode const lmode) +{ + switch (lmode) + { + case CLL_D3DTEXTURE: + CL_Image::imode = CL_Image::imode_d3d; + CL_Image::bitsperpixel = CL_Image::bitsperpixel_d3d; + CL_Pixel_16::f = CL_Pixel_16::f_d3d; + CL_Pixel_32::f = CL_Pixel_32::f_d3d; + break; + case CLL_DDSURFACE: + CL_Image::imode = CL_Image::imode_ddraw; + CL_Image::bitsperpixel = CL_Image::bitsperpixel_ddraw; + CL_Pixel_16::f = CL_Pixel_16::f_ddraw; + CL_Pixel_32::f = CL_Pixel_32::f_ddraw; + break; + } + CL_Image::lmode = lmode; +} + +// 3DC interface + +void CL_Init_DirectDrawMode(CL_VideoMode const vmode) +{ + switch (vmode) + { + case CLV_8: + CL_Image::bitsperpixel_ddraw = 8; + CL_Image::imode_ddraw = CLM_GLOBALPALETTE; + break; + case CLV_8TLT: + CL_Image::bitsperpixel_ddraw = 8; + CL_Image::imode_ddraw = CLM_TLTPALETTE; + break; + case CLV_15: + CL_Image::bitsperpixel_ddraw = 16; + CL_Image::imode_ddraw = CLM_16BIT; + CL_Pixel_16::f_ddraw.Init + ( + DisplayPixelFormat.dwRBitMask, + DisplayPixelFormat.dwGBitMask, + DisplayPixelFormat.dwBBitMask + ); + break; + case CLV_24: + CL_Image::bitsperpixel_ddraw = DisplayPixelFormat.dwRGBBitCount; + if (24 == CL_Image::bitsperpixel_ddraw) + CL_Image::imode_ddraw = CLM_24BIT; + else + { + CL_Image::imode_ddraw = CLM_32BIT; + CL_Pixel_32::f_ddraw.Init + ( + DisplayPixelFormat.dwRBitMask, + DisplayPixelFormat.dwGBitMask, + DisplayPixelFormat.dwBBitMask + ); + } + break; + case CLV_8T: + CL_Image::bitsperpixel_ddraw = 8; + CL_Image::imode_ddraw = CLM_16BIT; + CL_Pixel_16::f_ddraw.Init(7<<5,7<<2,3); + break; + } + CL_Select_Mode(CLL_DDSURFACE); +} + + +CL_Error CL_Image::CopyToScanDrawTexture(unsigned char * * const ImagePtrA [], unsigned int n_mips_max) +{ + if (!flags.loaded) return CLE_LOADERROR; + + if (CLL_DDSURFACE != lmode) CL_Select_Mode(CLL_DDSURFACE); + + if (n_mips_max > mipmaps.size()+1) n_mips_max = mipmaps.size()+1; + + if (!*ImagePtrA[0]) + { + if (flags.raw16bit) + { + if (n_mips_max>1) + *ImagePtrA[0] = (unsigned char *) AllocateMem((2*width+1)*(2*height+1)*2/3+(n_mips_max-3)*2); // slightly more than 4/3 w*h*bytedepth + else + *ImagePtrA[0] = (unsigned char *) AllocateMem(width*height*2); + } + else + { + if (n_mips_max>1) + *ImagePtrA[0] = (unsigned char *) AllocateMem((2*width+1)*(2*height+1)*bitsperpixel/24+(n_mips_max-3)*(bitsperpixel/8)); // slightly more than 4/3 w*h*bytedepth + else + *ImagePtrA[0] = (unsigned char *) AllocateMem(width*height*(bitsperpixel>>3)); + } + } + if (!*ImagePtrA[0]) + return CLE_ALLOCFAIL; + + unsigned int my_bitsperpixel = bitsperpixel; + + switch (imode) + { + unsigned char * tptr; + unsigned short * tSptr; + unsigned long * tLptr; + + case CLM_GLOBALPALETTE: + case CLM_TLTPALETTE: + if (flags.raw16bit) + { + my_bitsperpixel = 16; + tSptr = (unsigned short *)*ImagePtrA[0]; + if (tSptr) + { + for (int i=0; ib; + *tptr++ = i24ptr->g; + *tptr++ = i24ptr->r; + i24ptr++; + } + } + } + break; + case 32: + tLptr = (unsigned long *)*ImagePtrA[0]; + if (tLptr) + { + for (int i=0; i i_mip(&mipmaps); + for (int i=1; iwidth*last_mipP->height*(my_bitsperpixel>>3); + CL_Error thismipmaperror = i_mip()->CopyToScanDrawTexture(&ImagePtrA[i],1); + if (CLE_OK != thismipmaperror) return thismipmaperror; + last_mipP = i_mip(); + } + return CLE_OK; +} + + + +// Direct X interface + +void CL_Init_D3DMode(LPDDSURFACEDESC const format) +{ + CL_Image::format = format; + + if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) + { + #if QUANTISE_ON_LOAD + CL_Image::imode_d3d = CLM_24BIT; + #else + CL_Image::imode_d3d = CLM_ATTACHEDPALETTE; + #endif + CL_Image::bitsperpixel_d3d = 8; + } + else if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) + { + #if QUANTISE_ON_LOAD + CL_Image::imode_d3d = CLM_24BIT; + #else + CL_Image::imode_d3d = CLM_ATTACHEDPALETTE; + #endif + CL_Image::bitsperpixel_d3d = 4; + } + else if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED2) + { + #if QUANTISE_ON_LOAD + CL_Image::imode_d3d = CLM_24BIT; + #else + CL_Image::imode_d3d = CLM_ATTACHEDPALETTE; + #endif + CL_Image::bitsperpixel_d3d = 2; + } + else if (format->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED1) + { + #if QUANTISE_ON_LOAD + CL_Image::imode_d3d = CLM_24BIT; + #else + CL_Image::imode_d3d = CLM_ATTACHEDPALETTE; + #endif + CL_Image::bitsperpixel_d3d = 1; + } + else + { + CL_Image::bitsperpixel_d3d = format->ddpfPixelFormat.dwRGBBitCount; + if (format->ddpfPixelFormat.dwRGBBitCount > 16) + { + CL_Image::imode_d3d = CLM_32BIT; + CL_Pixel_32::f_d3d.Init + ( + format->ddpfPixelFormat.dwRBitMask, + format->ddpfPixelFormat.dwGBitMask, + format->ddpfPixelFormat.dwBBitMask + ); + } + else + { + CL_Image::imode_d3d = CLM_16BIT; + CL_Pixel_16::f_d3d.Init + ( + format->ddpfPixelFormat.dwRBitMask, + format->ddpfPixelFormat.dwGBitMask, + format->ddpfPixelFormat.dwBBitMask + ); + } + } + CL_Select_Mode(CLL_D3DTEXTURE); +} + + +CL_Error CL_Image::CopyToD3DTexture(LPDIRECTDRAWSURFACE * const DDPtrA [], LPVOID * const DDSurfaceA [], int const MemoryType, unsigned int n_mips_max) +{ + if (!flags.loaded) return CLE_LOADERROR; + + WaitForVRamReady(VWS_D3DTEXCREATE); + + if (CLL_D3DTEXTURE != lmode) CL_Select_Mode(CLL_D3DTEXTURE); + + LPDIRECTDRAWSURFACE lpDDS; + DDSURFACEDESC ddsd; + HRESULT ddrval; + + // Check for image being 4 byte aligned + // and fail if it is not + if (width & 3 || height & 3) + { + // return error code + return CLE_DXERROR; + } + + + // Set up the surface description. starting + // with the passed texture format and then + // incorporating the information read from the + // ppm. + memcpy(&ddsd, format, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT); + ddsd.ddsCaps.dwCaps = (DDSCAPS_TEXTURE | MemoryType); + ddsd.dwHeight = height; + ddsd.dwWidth = width; + + if (n_mips_max > mipmaps.size()+1) n_mips_max = mipmaps.size()+1; + + if (n_mips_max>1) + { + ddsd.dwFlags |= DDSD_MIPMAPCOUNT; + ddsd.ddsCaps.dwCaps |= DDSCAPS_MIPMAP | DDSCAPS_COMPLEX; + ddsd.dwMipMapCount = n_mips_max; + } + + // Create the surface + ddrval = lpDD->CreateSurface(&ddsd, &lpDDS, NULL); + + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + lpDDS->Release(); + return CLE_DXERROR; + #endif + } + + + // now do mipmaps if avail + + if (n_mips_max>1) + { + // We must now traverse the mip-map chain from highest to lowest + // resolutions, For each surface AFTER the first one, we must + // load a new file, using a name obtained from the mip map number + + int MipMapNum = 0; + LPDIRECTDRAWSURFACE lpThisMipMap, lpNextMipMap; + DDSCAPS ddsCaps; + + + lpThisMipMap = lpDDS; + // Component Object Model, increase reference count on + // mip-map surface by one. + lpThisMipMap->AddRef(); + ddsCaps.dwCaps = (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP); + ddrval = DD_OK; + + LIF i_mip(&mipmaps); + + CL_Image * last_mipP = this; + + while ((ddrval == DD_OK) && (MipMapNum < n_mips_max)) // both tests in case... + { + // Call LoadPPMIntoDDSurface with lpThisMipMap, new file name, and + // other values. + + *DDSurfaceA[MipMapNum] = last_mipP->CopyToDDSurface(lpThisMipMap); + + // Death trap + if (!*DDSurfaceA[MipMapNum]) + { + return CLE_DXERROR; + } + *DDPtrA[MipMapNum] = lpThisMipMap; + + // Proceed to the next level. + // Collect bonus rings. + ddrval = lpThisMipMap->GetAttachedSurface(&ddsCaps, &lpNextMipMap); + // Necessary to match the manual increment of the reference count on the + // COM texture. I think. + lpThisMipMap->Release(); + // ?? lpNextMipMap = lpThisMipMap; + lpThisMipMap = lpNextMipMap; + + MipMapNum++; + if (!i_mip.done()) + { + last_mipP = i_mip(); + i_mip.next(); + } + } + } + else + { + *DDSurfaceA[0] = CopyToDDSurface(lpDDS); + + if (!*DDSurfaceA[0]) return CLE_DXERROR; + + *DDPtrA[0] = lpDDS; + } + + return CLE_OK; +} + + +CL_Error CL_Image::CopyToDirectDrawSurface(LPDIRECTDRAWSURFACE * const DDPtrA [], LPVOID * const DDSurfaceA [], int const MemoryType, unsigned int n_mips_max) +{ + if (!flags.loaded) return CLE_LOADERROR; + + WaitForVRamReady(VWS_DDCREATE); + + if (CLL_DDSURFACE != lmode) CL_Select_Mode(CLL_DDSURFACE); + + LPDIRECTDRAWSURFACE lpDDS; + DDSURFACEDESC ddsd; + HRESULT ddrval; + + // Check for image being 4 byte aligned + // and fail if it is not + if (width & 3 || height & 3) + { + // return error code + return CLE_DXERROR; + } + + if (n_mips_max > mipmaps.size()+1) n_mips_max = mipmaps.size()+1; + + // Set up the surface description. starting + // with the passed texture format and then + // incorporating the information read from the + // ppm. + memset(&ddsd, 0, sizeof ddsd); + ddsd.dwSize = sizeof ddsd; + ddsd.dwFlags = (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT); + // Ensure that created surface has same pixel desription + // as primary + memcpy(&ddsd.ddpfPixelFormat, &DisplayPixelFormat, sizeof(DDPIXELFORMAT)); + ddsd.ddsCaps.dwCaps = (DDSCAPS_OFFSCREENPLAIN | MemoryType); + ddsd.dwHeight = height; + ddsd.dwWidth = width; + + if (n_mips_max>1) + { + ddsd.dwFlags |= DDSD_MIPMAPCOUNT; + ddsd.ddsCaps.dwCaps |= DDSCAPS_MIPMAP | DDSCAPS_COMPLEX; + ddsd.dwMipMapCount = n_mips_max; + } + + // Create the surface + ddrval = lpDD->CreateSurface(&ddsd, &lpDDS, NULL); + + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + lpDDS->Release(); + return CLE_DXERROR; + #endif + } + + DDCOLORKEY set_zero = {0,0}; + ddrval = lpDDS->SetColorKey(DDCKEY_SRCBLT, &set_zero); + + LOGDXERR(ddrval); + if(ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + lpDDS->Release(); + return CLE_DXERROR; + #endif + } + + + // now do mipmaps if avail + + if (n_mips_max>1) + { + // We must now traverse the mip-map chain from highest to lowest + // resolutions, For each surface AFTER the first one, we must + // load a new file, using a name obtained from the mip map number + + int MipMapNum = 0; + LPDIRECTDRAWSURFACE lpThisMipMap, lpNextMipMap; + DDSCAPS ddsCaps; + + + lpThisMipMap = lpDDS; + // Component Object Model, increase reference count on + // mip-map surface by one. + lpThisMipMap->AddRef(); + ddsCaps.dwCaps = (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP); + ddrval = DD_OK; + + LIF i_mip(&mipmaps); + + CL_Image * last_mipP = this; + + while ((ddrval == DD_OK) && (MipMapNum < n_mips_max)) // both tests in case... + { + // Call LoadPPMIntoDDSurface with lpThisMipMap, new file name, and + // other values. + + *DDSurfaceA[MipMapNum] = last_mipP->CopyToDDSurface(lpThisMipMap); + + // Death trap + if (!*DDSurfaceA[MipMapNum]) + { + return CLE_DXERROR; + } + *DDPtrA[MipMapNum] = lpThisMipMap; + + // Proceed to the next level. + // Collect bonus rings. + ddrval = lpThisMipMap->GetAttachedSurface(&ddsCaps, &lpNextMipMap); + // Necessary to match the manual increment of the reference count on the + // COM texture. I think. + lpThisMipMap->Release(); + // ?? lpNextMipMap = lpThisMipMap; + lpThisMipMap = lpNextMipMap; + + MipMapNum++; + if (!i_mip.done()) + { + last_mipP = i_mip(); + i_mip.next(); + } + } + } + else + { + *DDSurfaceA[0] = CopyToDDSurface(lpDDS); + + if (!*DDSurfaceA[0]) return CLE_DXERROR; + + *DDPtrA[0] = lpDDS; + } + + return CLE_OK; +} + + +LPVOID CL_Image::CopyToDDSurface(LPDIRECTDRAWSURFACE lpDDS) +{ + if (!flags.loaded) return 0; + + LPDIRECTDRAWPALETTE lpDDPPMPal; + PALETTEENTRY ppe[256]; + DDSURFACEDESC ddsd; + #if QUANTISE_ON_LOAD + D3DCOLOR colors[256]; + D3DCOLOR c; + int color_count; + #endif + int psize; + char *lpC; + HRESULT ddrval; + unsigned int i, j; + unsigned int pcaps; + + // Lock the surface so it can be filled with the PPM file + + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddrval = lpDDS->Lock(NULL, &ddsd, 0, NULL); + + if (!ddsd.lpSurface) + { + lpDDS->Unlock(NULL); + lpDDS->Release(); + LOGDXSTR("No surface"); + return 0; + } + + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + lpDDS->Release(); + return 0; + #endif + } + + // The method of loading depends on the pixel format of the dest surface + + switch (imode) + { + case CLM_32BIT: + switch (bitsperpixel) + { + case 32: + for (j = 0; j < height; j++) + { + // Point to next row in texture surface + unsigned long * lpLP = (unsigned long*)((char*)ddsd.lpSurface + + ddsd.lPitch * j); + CL_Pixel_32 * lpP32 = im32[j]; + for (i = width; i; --i) + { + *lpLP++ = *lpP32++; + } + } + break; + case 24: + for (j = 0; j < height; j++) + { + // Point to next row in texture surface + unsigned char * lpCP = (unsigned char*)ddsd.lpSurface + + ddsd.lPitch * j; + CL_Pixel_32 * lpP32 = im32[j]; + for (i = width; i; --i) + { + unsigned long lv = *lpP32++; + unsigned char const * lpSrcCP = (unsigned char const *)&lv; + // dodgy - makes assumtions about 24-bit values... + *lpCP++ = *lpSrcCP++; + *lpCP++ = *lpSrcCP++; + *lpCP++ = *lpSrcCP++; + } + } + break; + default: + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + lpDDS->Unlock(NULL); + lpDDS->Release(); + return 0; + #endif + } + lpDDS->Unlock(NULL); + break; + case CLM_16BIT: + switch (bitsperpixel) + { + case 16: + for (j = 0; j < height; j++) + { + // Point to next row in texture surface + unsigned short * lpSP = (unsigned short*)((char*)ddsd.lpSurface + + ddsd.lPitch * j); + CL_Pixel_16 * lpP16 = im16[j]; + for (i = width; i; --i) + { + *lpSP++ = *lpP16++; + } + } + break; + case 8: + for (j = 0; j < height; j++) + { + // Point to next row in texture surface + unsigned char * lpCP = (unsigned char*)ddsd.lpSurface + + ddsd.lPitch * j; + CL_Pixel_16 * lpP16 = im16[j]; + for (i = width; i; --i) + { + *lpCP++ = *lpP16++; + } + } + break; + default: + // Everything's gone pear-shaped... + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + lpDDS->Unlock(NULL); + lpDDS->Release(); + return 0; + #endif + } + lpDDS->Unlock(NULL); + break; + case CLM_24BIT: + if (24==bitsperpixel) + { + for (j = 0; j < height; j++) + { + // Point to next row in surface + unsigned char * lpCP = ((unsigned char*)ddsd.lpSurface) + ddsd.lPitch * j; + CL_Pixel_24 * lpP24 = im24[j]; + for (i = 0; i < width; i++) + { + // making an assumption about the ordering of r,g,b on the video card + *lpCP++ = lpP24->b; + *lpCP++ = lpP24->g; + *lpCP++ = lpP24->r; + lpP24++; + } + } + lpDDS->Unlock(NULL); + } + else + { + #if QUANTISE_ON_LOAD // Neal's quantize on load stuff + + // Paletted target texture surface + psize = 1<r, lpP24->g, lpP24->b); + // Search for this color in a table of colors in this texture + for (k = 0; k < color_count; k++) + if (c == colors[k]) break; + if (k == color_count) + { + // This is a new color, so add it to the list + color_count++; + // More than 256 and we fail (8-bit) + if (color_count > psize) + { + color_count--; + k = color_count - 1; + } + colors[k] = c; + } + // Set the "pixel" value on the surface to be the index into the + // color table + if (psize<256) + { + unsigned int bitmask; + switch (psize) + { + default: + bitmask = 1; + break; + case 4: + bitmask = 3; + break; + case 2: + bitmask = 7; + break; + } + if ((i & bitmask) == 0) + *lpC = (char)(k & (psize-1)); + else + *lpC |= (char)((k & (psize-1)) << (i & (psize-1))); + if ((~i & bitmask) == 0) + lpC++; + } + else + { + *lpC = (char)k; + lpC++; + } + } + } + + // Close the file and unlock the surface + + lpDDS->Unlock(NULL); + + if (color_count > psize) + { + // If there are more than 256 colors, we overran our palette + #if debug + ReleaseDirect3D(); + exit(0x321123); + #else + lpDDS->Release(); + return 0; + #endif + } + + // Create a palette with the colors in our color table + + memset(ppe, 0, sizeof(PALETTEENTRY) * 256); + for (i = 0; i < color_count; i++) + { + ppe[i].peRed = (unsigned char)RGB_GETRED(colors[i]); + ppe[i].peGreen = (unsigned char)RGB_GETGREEN(colors[i]); + ppe[i].peBlue = (unsigned char)RGB_GETBLUE(colors[i]); + } + + // Set all remaining entry flags to D3DPAL_RESERVED, which are ignored by + // the renderer. + + for (; i < 256; i++) + ppe[i].peFlags = D3DPAL_RESERVED; + + // Create the palette with the DDPCAPS_ALLOW256 flag because we want to + // have access to all entries. + + switch (bitsperpixel) + { + default: + pcaps = DDPCAPS_8BIT | DDPCAPS_ALLOW256; + break; + case 4: + pcaps = DDPCAPS_4BIT; + break; + case 2: + pcaps = DDPCAPS_2BIT; + break; + case 1: + pcaps = DDPCAPS_1BIT; + break; + } + + ddrval = lpDD->CreatePalette + (DDPCAPS_INITIALIZE | pcaps, + ppe, &lpDDPPMPal, NULL); + LOGDXERR(ddrval); + + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + lpDDS->Release(); + return 0; + #endif + } + + // Finally, bind the palette to the surface + + ddrval = lpDDS->SetPalette(lpDDPPMPal); + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + lpDDS->Release(); + lpDDPPMPal->Release(); + return 0; + #endif + } + + lpDDPPMPal->Release(); + } + break; + #else + // Everything's gone pear-shaped... + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + lpDDS->Unlock(NULL); + lpDDS->Release(); + return 0; + #endif + } + break; + case CLM_ATTACHEDPALETTE: + #endif + case CLM_GLOBALPALETTE: + case CLM_TLTPALETTE: + // Paletted target texture surface + + psize = 1<> nextpixelshift; + for (i = 0; i < width; i++) + { + unsigned char k = *lpP8++; + // Set the "pixel" value on the surface to be the index into the + // color table + if ((i & bitmask) == 0) + *lpC = (char) (k & (psize-1)); + else + *lpC |= (char) ((k & (psize-1)) << ((i & bitmask)<Unlock(NULL); + + // Create a palette with the colors in our color table + + memset(ppe, 0, sizeof(PALETTEENTRY) * 256); + for (i = 0; i < palette_size; i++) + { + ppe[i].peRed = palette[i].r; + ppe[i].peGreen = palette[i].g; + ppe[i].peBlue = palette[i].b; + } + + // Set all remaining entry flags to D3DPAL_RESERVED, which are ignored by + // the renderer. + + for (; i < 256; i++) + ppe[i].peFlags = D3DPAL_RESERVED; + + // Create the palette with the DDPCAPS_ALLOW256 flag because we want to + // have access to all entries. + + switch (bitsperpixel) + { + default: + pcaps = DDPCAPS_8BIT | DDPCAPS_ALLOW256; + break; + case 4: + pcaps = DDPCAPS_4BIT; + break; + case 2: + pcaps = DDPCAPS_2BIT; + break; + case 1: + pcaps = DDPCAPS_1BIT; + break; + } + + ddrval = lpDD->CreatePalette + (DDPCAPS_INITIALIZE | pcaps, + ppe, &lpDDPPMPal, NULL); + LOGDXERR(ddrval); + + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + lpDDS->Release(); + return 0; + #endif + } + + // Finally, bind the palette to the surface + + ddrval = lpDDS->SetPalette(lpDDPPMPal); + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + lpDDS->Release(); + lpDDPPMPal->Release(); + return 0; + #endif + } + + lpDDPPMPal->Release(); + break; + default: + // Everything's gone pear-shaped... + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + lpDDS->Unlock(NULL); + lpDDS->Release(); + return 0; + #endif + + + } + + return ddsd.lpSurface; +} + + diff --git a/3dc/win95/D3_IMAGE.HPP b/3dc/win95/D3_IMAGE.HPP new file mode 100644 index 0000000..a2bc639 --- /dev/null +++ b/3dc/win95/D3_IMAGE.HPP @@ -0,0 +1,1223 @@ +#ifndef _included__d3_image_hpp_ +#define _included__d3_image_hpp_ + +#error "This file is obsolete" + +#include +#include +#include + +#include "list_tem.hpp" + +#include "ddraw.h" +#include "d3d.h" +#include "vramtime.h" + +#include "system.h" +#include "mem3dc.h" + +#include "dxlog.h" +// define = 1 if you want an output log file of all texture files loaded and for which DD surface format +#if debug +#define OUTPUT_LOG 1 +#else +#define OUTPUT_LOG 0 +#endif + +// define = 1 to use fast files for loading (will still try normal files if fastfile doesn't contain correct data) +#define USE_FASTFILE 1 + +#if USE_FASTFILE + +#include "ffstdio.h" +#define D3I_FILE FFILE +#define d3i_fpos_t ffpos_t +#define d3i_fclearerr ffclearerr +#define d3i_fclose ffclose +#define d3i_fcloseall ffcloseall +#define d3i_feof ffeof +#define d3i_ferror fferror +#define d3i_fgetc ffgetc +#define d3i_fgetpos ffgetpos +#define d3i_fgets ffgets +#define d3i_flook fflook +#define d3i_flookb fflookb +#define d3i_fopen ffopen +#define d3i_fread ffread +#define d3i_freadb ffreadb +#define d3i_fseek ffseek +#define d3i_fsetpos ffsetpos +#define d3i_ftell fftell + +#else + +#define D3I_FILE FILE +#define d3i_fpos_t fpos_t +#define d3i_fclearerr fclearerr +#define d3i_fclose fclose +#define d3i_fcloseall fcloseall +#define d3i_feof feof +#define d3i_ferror ferror +#define d3i_fgetc fgetc +#define d3i_fgetpos fgetpos +#define d3i_fgets fgets +#define d3i_fopen fopen +#define d3i_fread fread +#define d3i_fseek fseek +#define d3i_fsetpos fsetpos +#define d3i_ftell ftell + +#endif + + +// define = 1 if you do not want to handle the error return codes, and require a load failure to cause an exit +#define EXIT_ON_LOAD_FAIL 0 + +// define = 1 if you are locating images through rif files and expect this to always succeed +// works like EXIT_ON_LOAD_FAIL, and only if EXIT_ON_LOAD_FAIL is set, but most failures are handled +// by assuming the given name to be a complete path and filename +#define EXIT_ON_LOCATE_FAIL 0 + +// define = 1 to time file opens, file closes and file reads +#define TIME_LOADS 0 + +// I tested the times with a typically complex set of images from AVP, +// loaded over a nework. +// Opening took 16secs, Reading 38secs and Closing 2secs for approx +// for about 500 images (including mip maps) + +#if TIME_LOADS +#include +#define START_TIMER {clock_t __stime = clock(); +#define END_TIMER(__var) __var += (unsigned int) ((clock() - __stime) * 1000 / CLOCKS_PER_SEC);} +#else +#define START_TIMER +#define END_TIMER(__var) +#endif + +#if TIME_LOADS +extern unsigned int OpenTime; +extern unsigned int CloseTime; +extern unsigned int ReadTime; +#endif + +#if OUTPUT_LOG +#include "debuglog.hpp" +extern LogFile CL_LogFile; +#endif + +// externs for 3dc things +extern "C" { + extern LPDIRECTDRAW lpDD; + extern DDPIXELFORMAT DisplayPixelFormat; +}; + +enum CL_RGBFormat // for loading from files +{ + CLF_RGB, CLF_BGR, CLF_BGRX +}; + +struct CL_Pixel_24 +{ + union + { + struct + { + unsigned char r,g,b; + unsigned char xx; + }; + unsigned long l; + }; + + CL_Pixel_24() : l(0) {} + CL_Pixel_24(unsigned char const r,unsigned char const g,unsigned char const b) : r(r),g(g),b(b),xx(0) {} + CL_Pixel_24(CL_Pixel_24 const & p24) : l(p24.l) {} + CL_Pixel_24(unsigned long const i) : l(i) {} + + operator unsigned long (void) const { return l; } + + inline void Read (D3I_FILE * const f, CL_RGBFormat const t) + { + switch(t) + { + case CLF_RGB: + d3i_fread(&r,1,1,f); + d3i_fread(&g,1,1,f); + d3i_fread(&b,1,1,f); + break; + case CLF_BGR: + d3i_fread(&b,1,1,f); + d3i_fread(&g,1,1,f); + d3i_fread(&r,1,1,f); + break; + case CLF_BGRX: + d3i_fread(&b,1,1,f); + d3i_fread(&g,1,1,f); + d3i_fread(&r,1,1,f); + d3i_fseek(f,1,SEEK_CUR); + default: + break; + } + } + + inline void Read (D3I_FILE * const f, CL_RGBFormat const t, unsigned int const maxval) + { + Read(f,t); + if (maxval != 255) + { + r = (unsigned char) ( ((unsigned int)r << 8) / (maxval+1) ); + g = (unsigned char) ( ((unsigned int)g << 8) / (maxval+1) ); + b = (unsigned char) ( ((unsigned int)b << 8) / (maxval+1) ); + } + } + + unsigned int FVD_Distance(CL_Pixel_24 const & p2) const; +}; + + +struct CL_DX_Format +{ + unsigned int + red_mask, + red_shift, + red_bits, + red_bits_gt8, + red_bits_lt8, + blue_mask, + blue_shift, + blue_bits, + blue_bits_gt8, + blue_bits_lt8, + green_mask, + green_shift, + green_bits, + green_bits_gt8, + green_bits_lt8; + + CL_Pixel_24 dx_black; + + inline void Init(unsigned int rmask,unsigned int gmask,unsigned int bmask) + { + red_mask = rmask; + blue_mask = bmask; + green_mask = gmask; + for (red_shift = 0; !(rmask & 1); red_shift++, rmask>>=1); + for (green_shift = 0; !(gmask & 1); green_shift++, gmask>>=1); + for (blue_shift = 0; !(bmask & 1); blue_shift++, bmask>>=1); + for (red_bits = 0; rmask; red_bits++, rmask>>=1); + for (green_bits = 0; gmask; green_bits++, gmask>>=1); + for (blue_bits = 0; bmask; blue_bits++, bmask>>=1); + if (blue_bits >= green_bits && blue_bits >= red_bits) + { + dx_black = CL_Pixel_24(0,0,1); + } + else if (red_bits >= green_bits) + { + dx_black = CL_Pixel_24(1,0,0); + } + else + { + dx_black = CL_Pixel_24(0,1,0); + } + if (red_bits >= 8) + { + red_bits_gt8 = red_bits-8; + red_bits_lt8 = 0; + } + else + { + red_bits_lt8 = 8-red_bits; + red_bits_gt8 = 0; + } + if (green_bits >= 8) + { + green_bits_gt8 = green_bits-8; + green_bits_lt8 = 0; + } + else + { + green_bits_lt8 = 8-green_bits; + green_bits_gt8 = 0; + } + if (blue_bits >= 8) + { + blue_bits_gt8 = blue_bits-8; + blue_bits_lt8 = 0; + } + else + { + blue_bits_lt8 = 8-blue_bits; + blue_bits_gt8 = 0; + } + } +}; + + +// for 32 bit and 24 bit DirectX formats +template +struct CL_Pixel_T +{ + static CL_DX_Format f; + static CL_DX_Format f_d3d; + static CL_DX_Format f_ddraw; + + S p; + + inline S r(void) const { return (S)((p & f.red_mask)>>f.red_shift); } + inline S g(void) const { return (S)((p & f.green_mask)>>f.green_shift); } + inline S b(void) const { return (S)((p & f.blue_mask)>>f.blue_shift); } + + CL_Pixel_T() {} + CL_Pixel_T(CL_Pixel_T const & p32) : p(p32.p) {} + CL_Pixel_T(CL_Pixel_24 const & p24) + : p((S)( + (S)p24.r>>f.red_bits_lt8<>f.green_bits_lt8<>f.blue_bits_lt8<>f.red_bits_gt8<>f.green_bits_gt8<>f.blue_bits_gt8<=r()<=g()<=g()<)p24; + } + + inline void Read (D3I_FILE * const f, CL_RGBFormat const t, unsigned int const maxval) + { + CL_Pixel_24 p24; + p24.Read(f,t,maxval); + *this = (CL_Pixel_T)p24; + } +}; + + +typedef CL_Pixel_T CL_Pixel_32; +typedef CL_Pixel_T CL_Pixel_16; + + +enum CL_Error +{ + CLE_OK, + CLE_LOADERROR, // file cannot be loaded - format is wrong + CLE_OPENERROR, // file cannot be opened - does not exist? + CLE_FINDERROR, // file cannot be found - not listed in .RIF file + CLE_RIFFERROR, // rif file not loaded, or invalid + CLE_INVALIDGAMEMODE, // specified game mode does not exist + CLE_INVALIDDXMODE, // video mode is invalid + CLE_DXERROR, // other direct X related error + CLE_ALLOCFAIL // failed memory allocation +}; + + +enum CL_ImageMode { + + CLM_GLOBALPALETTE, // image shares a global palette in a palettized mode + CLM_TLTPALETTE, // images may also share an abstract palette which remaps via a tlt to a global display palette + CLM_ATTACHEDPALETTE, // 256 colour image with attached palette + CLM_16BIT, // 16 bit in specified RGB format + CLM_32BIT, // 32 bit in specified RGB format + CLM_24BIT // 24 bit truecolour image in 888 format +}; +// Note: +// currently 24-bit and 16-bit image formats are not output. +// If the desired format is 24-bit or 16-bit then 256 colour BMPs are loaded +// and 'unquantized' to generate the required format. + + +enum CL_LoadMode { + + CLL_D3DTEXTURE, + CLL_DDSURFACE +}; + +void CL_Select_Mode(CL_LoadMode const lmode); + + +void CL_Init_D3DMode(LPDDSURFACEDESC const format); + +enum CL_VideoMode { + + CLV_8, + CLV_15, + CLV_24, + CLV_8T, + CLV_8TLT +}; + +void CL_Init_DirectDrawMode(CL_VideoMode const vmode); + + + +// test!!! +#if HwTextureHack +static int craptest = 0; +#endif + +#if EXIT_ON_LOAD_FAIL + extern "C" + { + #include "3dc.h" + } + #if EXIT_ON_LOCATE_FAIL + #define EXITONLOCATEFAIL(__errcode,__iname,__enum_id) \ + if (CLE_RIFFERROR != __errcode) { \ + if (__iname) textprint("Cannot figure path for:\n%s\n",__iname); \ + else textprint("Cannot figure path for:\nImage ID %d\n",__enum_id); \ + WaitForReturn(); \ + ExitSystem(); \ + exit(0x10cafa11); \ + } + #else + #define EXITONLOCATEFAIL(__errcode,__iname,__enum_id) + #endif + #define EXITONLOADFAIL(__iname) \ + { \ + textprint("Cannot open:\n%s\n",__iname); \ + WaitForReturn(); \ + ExitSystem(); \ + exit(0x10adfa11); \ + } + #define EXITONREADFAIL(__iname) \ + { \ + textprint("Cannot read:\n%s\n",__iname); \ + WaitForReturn(); \ + ExitSystem(); \ + exit(0x10adfa11); \ + } +#else + #define EXITONLOCATEFAIL(__errcode,__iname,__enum_id) + #define EXITONLOADFAIL(__iname) + #define EXITONREADFAIL(__iname) +#endif + +struct CL_Flags +{ + unsigned int loaded : 1; + unsigned int located : 1; + unsigned int raw16bit : 1; + unsigned int tltpalette : 1; + + CL_Flags() + : loaded(0) + , located(0) + , tltpalette(0) + , raw16bit(0) + {} +}; + +#define CL_EID_INVALID (-1) + + +#if 0 +template +class CL_MIP_Image +{ +public: + unsigned int num_mipmaps; + I * * mipmaps; // array of CL_Image pointers of decreasing image size + + unsigned int width; // == mipmaps[0]->width + unsigned int height; // == mipmaps[0]->height + unsigned int size; // == mipmaps[0]->size + + char * fname; // full filename (including directory/path) of mipmap with index 0 + char * name; // name of image without directory/path or extension + + CL_MIP_Image() : mipmaps(0), num_mipmaps(0), fname(0), name(0) {} + ~CL_MIP_Image() { Delete(); } + + CL_MIP_Image(CL_MIP_Image const & i2) + : width (i2.width) + , height (i2.height) + , size (i2.size) + , num_mipmaps (i2.num_mipmaps) + { Copy(i2); } + + CL_MIP_Image & operator = (CL_MIP_Image const & i2) + { + if (&i2 != this) + { + Delete(); + + width = i2.width; + height = i2.height; + size = i2.size; + num_mipmaps = i2.num_mipmaps; + + Copy(i2); + } + return *this; + } + +private: + void Copy(CL_MIP_Image const & i2) + { + if (i2.mipmaps) + { + mipmaps = new I * [num_mipmaps]; + for (int i=0; iwidth*mipmaps[i-1]->height*(I::bitsperpixel>>3); + CL_Error thismipmaperror = mipmaps[i]->CopyToScanDrawTexture(ImagePtrA[i]); + if (CLE_OK != thismipmaperror) return thismipmaperror; + } + return CLE_OK; + } + + CL_Error CopyToD3DTexture(LPDIRECTDRAWSURFACE * const DDPtrA [], LPVOID * const DDSurfaceA [], unsigned int maxnummips, int const MemoryType) + { + if (!flags.loaded) return CLE_LOADERROR; + + WaitForVRamReady(VWS_D3DTEXCREATE); + + if (CLL_D3DTEXTURE != I::lmode) CL_Select_Mode(CLL_D3DTEXTURE); + + LPDIRECTDRAWSURFACE lpDDS; + DDSURFACEDESC ddsd; + HRESULT ddrval; + + if (width & 3 || height & 3) + { + // return error code + return CLE_DXERROR; + } + + /* test !!! */ + { + #if HwTextureHack + craptest++; + if (craptest > 10) + return CLE_DXERROR; + #endif + } + + + if (num_mipmaps < maxnummips) maxnummips = num_mipmaps; + // Set up the mip-mapped surface description. starting + // with the passed texture format and then + // incorporating the information read from the + // ppm. + memcpy(&ddsd, I::format, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT + | DDSD_MIPMAPCOUNT); + ddsd.dwMipMapCount = maxnummips; // engine standard, primary plus six mip-maps + ddsd.ddsCaps.dwCaps = (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP + | DDSCAPS_COMPLEX | MemoryType); + ddsd.dwHeight = height; + ddsd.dwWidth = width; + + + // Create the surface + ddrval = lpDD->CreateSurface(&ddsd, &lpDDS, NULL); + LOGDXERR(ddrval); + + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + lpDDS->Release(); + return CLE_DXERROR; + #endif + } + + // We must now traverse the mip-map chain from highest to lowest + // resolutions, For each surface AFTER the first one, we must + // load a new file, using a name obtained from the mip map number + + int MipMapNum = 0; + LPDIRECTDRAWSURFACE lpThisMipMap, lpNextMipMap; + DDSCAPS ddsCaps; + + + lpThisMipMap = lpDDS; + // Component Object Model, increase reference count on + // mip-map surface by one. + lpThisMipMap->AddRef(); + ddsCaps.dwCaps = (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP); + ddrval = DD_OK; + + while ((ddrval == DD_OK) && (MipMapNum < maxnummips)) // both tests in case... + { + // Call LoadPPMIntoDDSurface with lpThisMipMap, new file name, and + // other values. + + *DDSurfaceA[MipMapNum] = mipmaps[MipMapNum]->CopyToDDSurface(lpThisMipMap); + + // Death trap + if (!*DDSurfaceA[MipMapNum]) + { + return CLE_DXERROR; + } + *DDPtrA[MipMapNum] = lpThisMipMap; + + // Proceed to the next level. + // Collect bonus rings. + ddrval = lpThisMipMap->GetAttachedSurface(&ddsCaps, &lpNextMipMap); + // Necessary to match the manual increment of the reference count on the + // COM texture. I think. + lpThisMipMap->Release(); + // ?? lpNextMipMap = lpThisMipMap; + lpThisMipMap = lpNextMipMap; + + MipMapNum++; + } + + return CLE_OK; + + } + + CL_Error CopyToDirectDrawSurface(LPDIRECTDRAWSURFACE * const DDPtrA [], LPVOID * const DDSurfaceA [], unsigned int maxnummips, int const MemoryType) + { + if (!flags.loaded) return CLE_LOADERROR; + + WaitForVRamReady(VWS_DDCREATE); + + if (CLL_DDSURFACE != I::lmode) CL_Select_Mode(CLL_DDSURFACE); + + LPDIRECTDRAWSURFACE lpDDS; + DDSURFACEDESC ddsd; + HRESULT ddrval; + + if (width & 3 || height & 3) + { + // return error code + return CLE_DXERROR; + } + + if (num_mipmaps < maxnummips) maxnummips = num_mipmaps; + // Set up the mip-mapped surface description. starting + // with the passed texture format and then + // incorporating the information read from the + // ppm. + memset(&ddsd, 0, sizeof ddsd); + ddsd.dwSize = sizeof ddsd; + ddsd.dwFlags = (DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT + | DDSD_MIPMAPCOUNT); + ddsd.dwMipMapCount = maxnummips; // engine standard, primary plus six mip-maps + ddsd.ddsCaps.dwCaps = (DDSCAPS_OFFSCREENPLAIN | DDSCAPS_MIPMAP + | DDSCAPS_COMPLEX | MemoryType); + ddsd.dwHeight = height; + ddsd.dwWidth = width; + + + // Create the surface + ddrval = lpDD->CreateSurface(&ddsd, &lpDDS, NULL); + + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + lpDDS->Release(); + return CLE_DXERROR; + #endif + } + + DDCOLORKEY set_zero = {0,0}; + ddrval = lpDDS->SetColorKey(DDCKEY_SRCBLT, &set_zero); + + LOGDXERR(ddrval); + if(ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + lpDDS->Release(); + return CLE_DXERROR; + #endif + } + + // We must now traverse the mip-map chain from highest to lowest + // resolutions, For each surface AFTER the first one, we must + // load a new file, using a name obtained from the mip map number + + int MipMapNum = 0; + LPDIRECTDRAWSURFACE lpThisMipMap, lpNextMipMap; + DDSCAPS ddsCaps; + + + lpThisMipMap = lpDDS; + // Component Object Model, increase reference count on + // mip-map surface by one. + lpThisMipMap->AddRef(); + ddsCaps.dwCaps = (DDSCAPS_TEXTURE | DDSCAPS_MIPMAP); + ddrval = DD_OK; + + while ((ddrval == DD_OK) && (MipMapNum < maxnummips)) // both tests in case... + { + // Call LoadPPMIntoDDSurface with lpThisMipMap, new file name, and + // other values. + + *DDSurfaceA[MipMapNum] = mipmaps[MipMapNum]->CopyToDDSurface(lpThisMipMap); + + // Death trap + if (!*DDSurfaceA[MipMapNum]) + { + return CLE_DXERROR; + } + *DDPtrA[MipMapNum] = lpThisMipMap; + + // Proceed to the next level. + // Collect bonus rings. + ddrval = lpThisMipMap->GetAttachedSurface(&ddsCaps, &lpNextMipMap); + // Necessary to match the manual increment of the reference count on the + // COM texture. I think. + lpThisMipMap->Release(); + // ?? lpNextMipMap = lpThisMipMap; + lpThisMipMap = lpNextMipMap; + + MipMapNum++; + } + + return CLE_OK; + + } + +private: + // I was using Dan's list template for this, + // but since it is not a standard part of 3DC, + // I have had to write a specific simple list handler + struct TempListMember + { + I * mip; + TempListMember * next; + TempListMember(I * data) : mip(data), next(0) {} + //TempListMember() : next(0) {} + ~TempListMember() { if (next) delete next; } + }; + struct TempList + { + unsigned int n_entries; + TempListMember * first; + TempListMember * last; + TempList(I * data) : first(new TempListMember(data)), n_entries(1) { last = first; } + TempList & operator += (I * data) + { + if (!first) + { + first = new TempListMember(data); + last = first; + } + else + { + last->next = new TempListMember(data); + last = last->next; + } + ++ n_entries; + return *this; + } + ~TempList() + { + if (first) delete first; + } + }; + + CL_Error Load(char const * const iname, int const enum_id) + { + if (iname || CL_EID_INVALID != enum_id) flags.located = 0; + + I * mip0; + + if (flags.located && mipmaps) + { + mip0 = mipmaps[0]; + // we have grabbed the previously allocated pointer + // it will now be treated as if it were allocated here, + // so we must remove it from the class, in case the + // deconstructor tries to deallocate it + delete[] mipmaps; + mipmaps = 0; + } + else + { + mip0 = new I; + + CL_Error locate_err = mip0->Locate(iname,enum_id); + + if (locate_err != CLE_OK) + { + delete mip0; + EXITONLOCATEFAIL(locate_err,iname,enum_id) + return locate_err; + } + } + + #if OUTPUT_LOG + char const * texformat; + unsigned int redbits = 8; + unsigned int greenbits = 8; + unsigned int bluebits = 8; + switch (I::imode) + { + case CLM_GLOBALPALETTE: + case CLM_TLTPALETTE: + texformat = "Palettized Display"; + break; + case CLM_ATTACHEDPALETTE: + texformat = "Palettized Textures"; + break; + case CLM_32BIT: + texformat = "32BIT DX"; + redbits += CL_Pixel_32::f.red_bits_gt8; + redbits -= CL_Pixel_32::f.red_bits_lt8; + greenbits += CL_Pixel_32::f.green_bits_gt8; + greenbits -= CL_Pixel_32::f.green_bits_lt8; + bluebits += CL_Pixel_32::f.blue_bits_gt8; + bluebits -= CL_Pixel_32::f.blue_bits_lt8; + break; + case CLM_24BIT: + texformat = "24-bit for runtime conversion"; + break; + case CLM_16BIT: + texformat = "16BIT DX"; + redbits += CL_Pixel_16::f.red_bits_gt8; + redbits -= CL_Pixel_16::f.red_bits_lt8; + greenbits += CL_Pixel_16::f.green_bits_gt8; + greenbits -= CL_Pixel_16::f.green_bits_lt8; + bluebits += CL_Pixel_16::f.blue_bits_gt8; + bluebits -= CL_Pixel_16::f.blue_bits_lt8; + break; + } + CL_LogFile.lprintf("--%s %s (%u-bit, %u-%u-%u)\n",mip0->fname,texformat,I::bitsperpixel,redbits,greenbits,bluebits); + #endif + + START_TIMER + D3I_FILE * fp = d3i_fopen(mip0->fname,"rb"); + END_TIMER(OpenTime) + + if (!fp) + { + #if OUTPUT_LOG + CL_LogFile.lputs("** ERROR: unable to open\n"); + #endif + EXITONLOADFAIL(mip0->fname) + delete mip0; + return CLE_OPENERROR; + } + + CL_Error load_err = mip0->Load_Image(fp); + START_TIMER + d3i_fclose(fp); + END_TIMER(CloseTime) + + if (load_err != CLE_OK) + { + if (!flags.located) delete mip0; + #if OUTPUT_LOG + CL_LogFile.lputs("** ERROR: unable to read\n"); + #endif + EXITONREADFAIL(mip0->fname) + return load_err; + } + + TempList miplist(mip0); + + width = mip0->width; + height = mip0->height; + size = mip0->size; + + if (!flags.located) + { + if (fname) delete[] fname; + if (name) delete[] name; + fname = new char[strlen(mip0->fname)+1]; + name = new char[strlen(mip0->name)+1]; + strcpy(fname,mip0->fname); + strcpy(name,mip0->name); + } + + for (int mip_idx = 1; mip_idx < 7; ++mip_idx) + { + I * mip_n; + + mip_n = new I; + mip_n->name = new char[strlen(name)+1]; + mip_n->fname = new char[strlen(fname)+1]; + strcpy(mip_n->name,name); + strcpy(mip_n->fname,fname); + + char * dotpos = strrchr(mip_n->fname,'.'); + if (!dotpos) + { + delete mip_n; + break; + } + sprintf(dotpos+3,"%1d",mip_idx); + + #if OUTPUT_LOG + char const * texformat; + unsigned int redbits = 8; + unsigned int greenbits = 8; + unsigned int bluebits = 8; + switch (I::imode) + { + case CLM_GLOBALPALETTE: + case CLM_TLTPALETTE: + texformat = "Palettized Display"; + break; + case CLM_ATTACHEDPALETTE: + texformat = "Palettized Textures"; + break; + case CLM_32BIT: + texformat = "32BIT DX"; + redbits += CL_Pixel_32::f.red_bits_gt8; + redbits -= CL_Pixel_32::f.red_bits_lt8; + greenbits += CL_Pixel_32::f.green_bits_gt8; + greenbits -= CL_Pixel_32::f.green_bits_lt8; + bluebits += CL_Pixel_32::f.blue_bits_gt8; + bluebits -= CL_Pixel_32::f.blue_bits_lt8; + break; + case CLM_24BIT: + texformat = "24-bit for runtime conversion"; + break; + case CLM_16BIT: + texformat = "16BIT DX"; + redbits += CL_Pixel_16::f.red_bits_gt8; + redbits -= CL_Pixel_16::f.red_bits_lt8; + greenbits += CL_Pixel_16::f.green_bits_gt8; + greenbits -= CL_Pixel_16::f.green_bits_lt8; + bluebits += CL_Pixel_16::f.blue_bits_gt8; + bluebits -= CL_Pixel_16::f.blue_bits_lt8; + break; + } + CL_LogFile.lprintf("--%s %s (%u-bit, %u-%u-%u)\n",mip_n->fname,texformat,I::bitsperpixel,redbits,greenbits,bluebits); + #endif + + START_TIMER + fp = d3i_fopen(mip_n->fname,"rb"); + END_TIMER(OpenTime) + + if (!fp) + { + delete mip_n; + #if OUTPUT_LOG + CL_LogFile.lputs("** Warning: unable to open\n"); + #endif + break; + } + + load_err = mip_n->Load_Image(fp); + START_TIMER + d3i_fclose(fp); + END_TIMER(CloseTime) + + if (load_err != CLE_OK) + { + delete mip_n; + #if OUTPUT_LOG + CL_LogFile.lputs("** Warning: unable to read\n"); + #endif + break; + } + + if (mip_n->width << mip_idx < width || mip_n->height << mip_idx < height) + { + delete mip_n; + #if OUTPUT_LOG + CL_LogFile.lputs("** Warning: less than half size\n"); + #endif + break; + } + + miplist += mip_n; + } + + if (mipmaps) + { + for (int i = 0; imip; + listP = listP->next; + } + + flags.loaded = 1; + flags.located = 1; + return CLE_OK; + } + + CL_Error PreLoad(char const * const iname, int const enum_id) + { + I * mip0 = new I; + + CL_Error locate_err = mip0->Locate(iname,enum_id); + + if (locate_err != CLE_OK) + { + delete mip0; + return locate_err; + } + + if (fname) delete[] fname; + if (name) delete[] name; + fname = new char[strlen(mip0->fname)+1]; + name = new char[strlen(mip0->name)+1]; + strcpy(fname,mip0->fname); + strcpy(name,mip0->name); + + if (mipmaps) + { + for (int i=0; i mipmaps; + + CL_Image() : im8(0),im16(0),im24(0),palette(0),palette_size(0),fname(0),name(0) {} + virtual ~CL_Image(); + + CL_Image(CL_Image const &); + CL_Image & operator = (CL_Image const &); + + inline CL_Error Load(char const * const iname) // looks at rif file and video mode to determine which file to load + { + return Load(iname,CL_EID_INVALID); + } + inline CL_Error Load(int const enum_id) // looks at rif file and video mode to determine which file to load + { + return Load(0,enum_id); + } + inline CL_Error Load() // assumes preload has been called + { + return Load(0,CL_EID_INVALID); + } + + inline CL_Error PreLoad(char const * const iname) // looks at rif file and video mode to determine which file to load + { + return PreLoad(iname,CL_EID_INVALID); + } + inline CL_Error PreLoad(int const enum_id) // looks at rif file and video mode to determine which file to load + { + return PreLoad(0,enum_id); + } + + CL_Error LoadMipMaps(int const n_mips = 7); // assumes locating has been done (ie. PreLoad or Load has been called) + + CL_Error Load_BMP(D3I_FILE * f); // videomode != CLM_GLOBALPALETTE + CL_Error Load_PPM(D3I_FILE * f); // videomode == CLM_16BIT || CLM_24BIT + CL_Error Load_PGM(D3I_FILE * f); // videomode == CLM_GLOBALPALETTE + CL_Error Load_PWM(D3I_FILE * f); // videomode == CLM_GLOBALPALETTE + + CL_Error Load_Image(D3I_FILE * f); // calls one of the above if correct format + + CL_Error GetBitsPerPixel(unsigned int* bpp); //returns bitsperpixel; + + // needs CL_Init_D3DMode((LPDDSURFACEDESC)format) to have been called + inline CL_Error CopyToD3DTexture(LPDIRECTDRAWSURFACE * const DDPtrA, LPVOID * const DDSurfaceA, int const MemoryType) + { + return CopyToD3DTexture(&DDPtrA,&DDSurfaceA,MemoryType); + } + CL_Error CopyToD3DTexture(LPDIRECTDRAWSURFACE * const DDPtrA [], LPVOID * const DDSurfaceA [], int const MemoryType, unsigned int n_mips_max = 1); + // needs CL_Init_ScanDrawMode((CL_VideoMode) videomode) to have been called + inline CL_Error CopyToDirectDrawSurface(LPDIRECTDRAWSURFACE * const DDPtrA, LPVOID * const DDSurfaceA, int const MemoryType) + { + return CopyToDirectDrawSurface(&DDPtrA,&DDSurfaceA,MemoryType); + } + CL_Error CopyToDirectDrawSurface(LPDIRECTDRAWSURFACE * const DDPtrA [], LPVOID * const DDSurfaceA [], int const MemoryType, unsigned int n_mips_max = 1); + // needs CL_Init_ScanDrawMode((CL_VideoMode) videomode) to have been called + inline CL_Error CopyToScanDrawTexture(unsigned char * * const ImagePtrA) + { + return CopyToScanDrawTexture(&ImagePtrA); + } + CL_Error CopyToScanDrawTexture(unsigned char * * const ImagePtrA [], unsigned int n_mips_max = 1); + // create an empty image for user manipulation + CL_Error Make(int const _width,int const _height); + // create an empty random image for user manipulation + CL_Error MakeRandom(int const _width,int const _height,int const seed = -1); + // ensure with and height are multiples of given units + void PadTo(int const width_unit,int const height_unit); + + inline CL_Flags const & GetFlags() const + { + return flags; + } +protected: + CL_Flags flags; + + virtual CL_Error Locate(char const * iname, int const enum_id); + CL_Error Load(char const * const iname, int const enum_id); + CL_Error PreLoad(char const * const iname, int const enum_id); + + CL_Error ReducePalette(unsigned int const num_colours); + + // returns DDSURFACEDESC.lpSurface + // does what LoadPPMIntoDDSurface did + LPVOID CopyToDDSurface(LPDIRECTDRAWSURFACE lpDDS); + +private: + void Copy(CL_Image const &); + void Delete(void); + void DeleteNotMips(void); +}; + +#endif // !_included__d3_image_hpp_ diff --git a/3dc/win95/DB.H b/3dc/win95/DB.H new file mode 100644 index 0000000..10e5d4d --- /dev/null +++ b/3dc/win95/DB.H @@ -0,0 +1,363 @@ +/* ******************************************************************** * + * * + * DB.H - Header for debugging functions and macros. * + * * + * By: Garry Lancaster Version: 2.0 * + * * + * ******************************************************************** */ + +/* N O T E S ********************************************************** */ + +/* Define NDEBUG here to switch off all debugging. */ + +/* Set the DB_LEVEL here or before this file is included. Most db macros + * have a level from 1 to 5. They + * will only compile to code if the DB_LEVEL is at or greater than their + * level, otherwise they will be translated to ((void) 0) (i.e. no + * code.). The levels should be used as follows: + * + * 1 - Very low cost debugging. Negligible speed penalty. Could easily + * be left in a finished game. + * 2 - Low cost debugging. Small speed penalty. Use during development + * for well-tested code. + * 3 - Medium cost debugging. Obvious but tolerable speed penalty. Use + * during development most of the time. + * 4 - High cost debugging. Large speed penalty. Use during development + * when actively bug hunting. + * 5 - Very high cost debugging. Massive speed penalty. Use when trying + * to track down one of THOSE bugs. + * + * The level of a macro is part of its name e.g. to code a db_assert + * that fires at level 3 or above, use db_assert3(). + */ + +#pragma once + +/* If you do not set the DB_LEVEL, it is set for you: to 3 */ +#ifndef DB_LEVEL + #define DB_LEVEL 3 +#endif + +/* N.B. If NDEBUG is set, it over-rides DB_LEVEL and switches off all + * debugging. + */ +#ifdef NDEBUG + #undef DB_LEVEL + #define DB_LEVEL 0 +#endif + +/* Some db macros can be made optional dependent on the setting of the + * global variable db_option by appending _opt e.g. db_assert_opt(). The + * only code that is executed for any _opt macro if db_option is zero is + * + * if(db_option) + * + * However, this is still more than the macros controlled by the DB_LEVEL + * - if they are above the current DB_LEVEL they cause no code execution + * whatsoever. Therefore, avoid using _opt type macros inside extremely + * time critical code - use macros contolled by the DB_LEVEL instead, + * unless you are prepared to put up with the speed penalty. + * The only time that _opt type macros generate no code is when NDEBUG is + * defined. + */ + +/* S T A R T W R A P P E R ****************************************** */ + +/* Avoid multiple inclusions of this file in a single source file. */ +#ifndef DB_H_INCLUDED +#define DB_H_INCLUDED + +/* I N C L U D E D S ************************************************** */ +#include "advwin32.h" +#ifndef DB_NOWINDOWS + #include + #include "advwin32.h" +#endif + +/* Permit use in a C++ source file. */ +#ifdef __cplusplus +extern "C" { +#endif + +/* ******************************************************************** * + * * + * I N T E R F A C E - both internal and external. * + * * + * ******************************************************************** */ + +/* C O N S T A N T S ************************************************** */ + +/* Possible values for the global variable, db_display_type. */ +#define DB_DOS 0 +#define DB_WINDOWS 1 +#define DB_DIRECTDRAW 2 + +/* Possible values for the bltOrFlip field of db_dd_mode_tag structure. */ +#define DB_FLIP 0 +#define DB_BLT 1 + +/* M A C R O S ******************************************************** */ + +#if (!defined(DB_NOASSUME)) && defined(_MSC_VER) && (_MSC_VER >= 1200) + #define _db_assume(x) __assume(x) +#else + #define _db_assume(x) ((void)0) +#endif + +#if DB_LEVEL >= 1 + /* Fn like macro. */ + #define db_set_mode(md, miP) db_set_mode_ex(md, miP, NULL) + #define db_set_log_file(strP) db_set_log_file_ex(strP) +#else + #define db_set_mode(md, miP) ((void) 0) + #define db_set_log_file(strP) ((void) 0) +#endif + +/* Final use macros after testing of DB_LEVEL / db_option. */ +#define db_assert_final(expr) \ + ((expr) ? ((void) 0) : db_assert_fail(#expr, __FILE__, __LINE__)) + +/* Macros whose compilation is conditional on the value of DB_LEVEL. */ +#if DB_LEVEL >= 1 + #define db_assert1(expr) db_assert_final(expr) + #define db_onlyassert1(expr) db_assert_final(expr) + #define db_verify1(expr) db_assert_final(expr) + #define db_print1(x, y, strP) db_print_fired(x, y, strP) + #define db_msg1(strP) db_msg_fired(strP) + #define db_log1(strP) db_log_fired(strP) + #define db_code1(code) code + #define db_printf1(params) db_printf_fired params + #define db_msgf1(params) db_msgf_fired params + #define db_logf1(params) db_logf_fired params +#else + #define db_assert1(expr) _db_assume(expr) + #define db_onlyassert1(__ignore) ((void) 0) + #define db_verify1(expr) (expr) + #define db_print1(x, y, __ignore) ((void) 0) + #define db_msg1(__ignore) _db_assume(0) + #define db_log1(__ignore) ((void) 0) + #define db_code1(__ignore) + #define db_printf1(x, y, __ignore) ((void) 0) + #define db_msgf1(__ignore) _db_assume(0) + #define db_logf1(__ignore) ((void) 0) +#endif +#if DB_LEVEL >= 2 + #define db_assert2(expr) db_assert_final(expr) + #define db_onlyassert2(expr) db_assert_final(expr) + #define db_verify2(expr) db_assert_final(expr) + #define db_print2(x, y, strP) db_print_fired(x, y, strP) + #define db_msg2(strP) db_msg_fired(strP) + #define db_log2(strP) db_log_fired(strP) + #define db_code2(code) code + #define db_printf2(params) db_printf_fired params + #define db_msgf2(params) db_msgf_fired params + #define db_logf2(params) db_logf_fired params +#else + #define db_assert2(expr) _db_assume(expr) + #define db_onlyassert2(__ignore) ((void) 0) + #define db_verify2(expr) (expr) + #define db_print2(x, y, __ignore) ((void) 0) + #define db_msg2(__ignore) _db_assume(0) + #define db_log2(__ignore) ((void) 0) + #define db_code2(__ignore) + #define db_printf2(x, y, __ignore) ((void) 0) + #define db_msgf2(__ignore) _db_assume(0) + #define db_logf2(__ignore) ((void) 0) +#endif +#if DB_LEVEL >= 3 + #define db_assert3(expr) db_assert_final(expr) + #define db_onlyassert3(expr) db_assert_final(expr) + #define db_verify3(expr) db_assert_final(expr) + #define db_print3(x, y, strP) db_print_fired(x, y, strP) + #define db_msg3(strP) db_msg_fired(strP) + #define db_log3(strP) db_log_fired(strP) + #define db_code3(code) code + #define db_printf3(params) db_printf_fired params + #define db_msgf3(params) db_msgf_fired params + #define db_logf3(params) db_logf_fired params +#else + #define db_assert3(expr) _db_assume(expr) + #define db_onlyassert3(__ignore) ((void) 0) + #define db_verify3(expr) (expr) + #define db_print3(x, y, __ignore) ((void) 0) + #define db_msg3(__ignore) _db_assume(0) + #define db_log3(__ignore) ((void) 0) + #define db_code3(__ignore) + #define db_printf3(x, y, __ignore) ((void) 0) + #define db_msgf3(__ignore) _db_assume(0) + #define db_logf3(__ignore) ((void) 0) +#endif +#if DB_LEVEL >= 4 + #define db_assert4(expr) db_assert_final(expr) + #define db_onlyassert4(expr) db_assert_final(expr) + #define db_verify4(expr) db_assert_final(expr) + #define db_print4(x, y, strP) db_print_fired(x, y, strP) + #define db_msg4(strP) db_msg_fired(strP) + #define db_log4(strP) db_log_fired(strP) + #define db_code4(code) code + #define db_printf4(params) db_printf_fired params + #define db_msgf4(params) db_msgf_fired params + #define db_logf4(params) db_logf_fired params +#else + #define db_assert4(expr) _db_assume(expr) + #define db_onlyassert4(__ignore) ((void) 0) + #define db_verify4(expr) (expr) + #define db_print4(x, y, __ignore) ((void) 0) + #define db_msg4(__ignore) _db_assume(0) + #define db_log4(__ignore) ((void) 0) + #define db_code4(__ignore) + #define db_printf4(x, y, __ignore) ((void) 0) + #define db_msgf4(__ignore) _db_assume(0) + #define db_logf4(__ignore) ((void) 0) +#endif +#if DB_LEVEL >= 5 + #define db_assert5(expr) db_assert_final(expr) + #define db_onlyassert5(expr) db_assert_final(expr) + #define db_verify5(expr) db_assert_final(expr) + #define db_print5(x, y, strP) db_print_fired(x, y, strP) + #define db_msg5(strP) db_msg_fired(strP) + #define db_log5(strP) db_log_fired(strP) + #define db_code5(code) code + #define db_printf5(params) db_printf_fired params + #define db_msgf5(params) db_msgf_fired params + #define db_logf5(params) db_logf_fired params +#else + #define db_assert5(expr) _db_assume(expr) + #define db_onlyassert5(__ignore) ((void) 0) + #define db_verify5(expr) (expr) + #define db_print5(x, y, __ignore) ((void) 0) + #define db_msg5(__ignore) _db_assume(0) + #define db_log5(__ignore) ((void) 0) + #define db_code5(__ignore) + #define db_printf5(x, y, __ignore) ((void) 0) + #define db_msgf5(__ignore) _db_assume(0) + #define db_logf5(__ignore) ((void) 0) +#endif + +/* Macros which fire if db_option is non-zero (and NDEBUG is not + * defined). + */ +#ifndef NDEBUG + #define db_assert_opt(expr) if(db_option) db_assert_final(expr) + #define db_onlyassert_opt(expr) if(db_option) db_assert_final(expr) + #define db_verify_opt(expr) ((db_option) ? db_assert_final(expr) : (expr)) + #define db_print_opt(x, y, strP) if(db_option) db_print_fired(x, y, strP) + #define db_msg_opt(strP) if(db_option) db_msg_fired(strP) + #define db_log_opt(strP) if(db_option) db_log_fired(strP) + #define db_code_opt(code) if(db_option) code + #define db_printf_opt(params) if(db_option) db_printf_fired params + #define db_msgf_opt(params) if(db_option) db_msgf_fired params + #define db_logf_opt(params) if(db_option) db_logf_fired params +#else + #define db_assert_opt(expr) _db_assume(expr) + #define db_onlyassert_opt(__ignore) ((void) 0) + #define db_verify_opt(expr) (expr) + #define db_print_opt(x,y,__ignore) ((void) 0) + #define db_msg_opt(__ignore) _db_assume(0) + #define db_log_opt(__ignore) ((void) 0) + #define db_code_opt(code) + #define db_printf_opt(params) ((void) 0) + #define db_msgf_opt(params) _db_assume(0) + #define db_logf_opt(params) ((void) 0) +#endif + +/* Macros for setting and getting db_option. */ +#ifndef NDEBUG + #define db_option_set(status) db_option = (status) + #define db_option_on() db_option = 1 + #define db_option_off() db_option = 0 + #define db_option_get() (db_option) +#else + #define db_option_set(__ignore) ((void) 0) + #define db_option_on() ((void) 0) + #define db_option_off() ((void) 0) + #define db_option_get() (0) +#endif + +/* T Y P E S ********************************************************** */ + +struct db_dd_mode_tag +{ + void *directDrawP; + void *visibleSurfaceP; + void *drawSurfaceP; + int width, height, bitsPerPixel; + unsigned short foreCol, backCol; + int bltOrFlip; + int bltXOffset, bltYOffset; +}; + +/* P R O T O S ******************************************************** */ + +/* Don't prototype anything or declare globals if NDEBUG is defined. */ +#ifndef NDEBUG + +/* New formatted debugging fns. */ +extern void __cdecl db_logf_fired(const char *fmtStrP, ...); +extern void __cdecl db_printf_fired(int x, int y, const char *fmtStrP, ...); +extern void __cdecl db_msgf_fired(const char *fmtStrP, ...); + +/* Called whenever an assertion fails. */ +extern void db_assert_fail(const char *exprP, const char *fileP, int line); + +/* Displays a message and has the program pause until the user responds + * to it. + */ +extern void db_msg_fired(const char *strP); + +/* Displays a message (on platforms that support positioning, at (x, y)) + * and continues program execution immediately. + */ +extern void db_print_fired(int x, int y, const char *strP); + +/* Writes a message to a log file. */ +extern void db_log_fired(const char *strP); + +/* Deletes the old log file, so that the log file only contains messages + * saved from this point on. Use ONCE at the start of any program that + * uses any of the db_log macros. + */ +extern void db_log_init(void); + +/* Gets the current infomation needed for the display mode. Used to enable + * other code to use the same debugging stuff. The return value is modeInfoP + */ +extern int db_get_mode(void **modeInfoPP, void **FontPP); + +/* Changes the log file name */ +extern void db_set_log_file_ex(const char *strP); + +/* Sets the display mode for the debugging functions to use. mode must + * be one of DB_DOS, DB_WINDOWS or DB_DIRECTDRAW. The modeInfoP parameter + * is NULL except for Direct Draw. The Last parameter can be NULL. + */ +extern void db_set_mode_ex(int mode, void *modeInfoP, void *newFontP); + +/* Called to set whether exceptions or brakepoints are called. */ +extern void DbUseBrakepoints(BOOL use_brakepoints); + +/* Call this to de-allocate memory used to store the debugging font. This + * fn does nothing unless you are in DirectDraw mode, since this is the + * only mode which loads its own font. Calling this fn is not strictly + * necessary since the OS will de-allocate a process' outstanding dynamic + * memory allocations when it ends anyway. However, calling this fn is + * cleaner and avoids BoundsChecker hits. + */ +extern void db_uninit(void); + + /* G L O B A L S ****************************************************** */ + +/* Should we expand _opt type macros? */ +extern int db_option; + +#endif /* of #ifndef NDEBUG */ + +/* E N D W R A P P E R ********************************************** */ + +/* Permit use in a C++ source file. */ +#ifdef __cplusplus +} +#endif + +/* Avoid multiple inclusions of this file in a single source file. */ +#endif diff --git a/3dc/win95/DD_FUNC.CPP b/3dc/win95/DD_FUNC.CPP new file mode 100644 index 0000000..3be2188 --- /dev/null +++ b/3dc/win95/DD_FUNC.CPP @@ -0,0 +1,2260 @@ +extern "C" { + +#include "3dc.h" +#include "vramtime.h" +#include "dxlog.h" +#include "inline.h" +#include "scrshot.hpp" +#include "awTexLd.h" // to set the surface format for Aw gfx dd surface loads + +#define UseLocalAssert No +#include "ourasert.h" + + +// for 640x480x8 experiment +#define InterlaceExperiment No + + +// In as separate define to debug because we +// might want to leave it even in a published +// game. +#define AllowReboot Yes + +// In as #define since there is no +// obvious good behaviour on failure +#define CheckForModeXInSubWindow No + +// Temporary hack! +#define NoPalette No +extern void TimeStampedMessage(char *s); + +// Nasty hack to try and fix non-appearance of font +// on some machines, probably due to there not being +// enough video memory for the font and BltFast +// not working outside display memory. +// According to Roxby, source colour keying won't work +// on Blt in the Beta 3, so expect a grotty font with this on. +// PS Source colour keying works, but the font +// still doesn't appear on my machine in SubWindow +// mode... Ho hum... +#define NoBltFastOnFont No + + +// Check to see if video mode is valid +// and rewrite it if it isn't reported + +#define CheckVideoMode No + +/* + Globals +*/ + +LPDIRECTDRAW lpDD; // DirectDraw object +LPDIRECTDRAWSURFACE lpDDSPrimary; // DirectDraw primary surface +LPDIRECTDRAWSURFACE lpDDSBack; // DirectDraw back surface +LPDIRECTDRAWSURFACE lpDDSHiddenBack; // for system memory rendering target, stable configuration +LPDIRECTDRAWPALETTE lpDDPal[MaxPalettes]; // DirectDraw palette +#if debug || PreBeta +LPDIRECTDRAWSURFACE lpDDDbgFont; // Debugging font, specific to current video mode +#endif +// For SubWindow mode +LPDIRECTDRAWCLIPPER lpDDClipper; +// DirectDraw gdi surface +LPDIRECTDRAWSURFACE lpDDGDI; +int VideoModeColourDepth; +long BackBufferPitch; +// To describe available video hardware +int TotalVideoMemory; +int NumAvailableVideoModes; +VIDEOMODEINFO AvailableVideoModes[MaxAvailableVideoModes]; +// Must be kept up to date with jump table!!!! +VIDEOMODEINFO EngineVideoModes[] = { + // Mode 320x200x8 + 320, // width + 200, // height + 8, // colour depth (bits per pixel) + // Mode 320x200x8T + 320, // width + 200, // height + 8, // colour depth (bits per pixel) + // Mode 320x200x15 + 320, // width + 200, // height + 16, // colour depth (bits per pixel) + // Mode 320x240x8 + 320, // width + 240, // height + 8, // colour depth (bits per pixel) + // Mode 640x480x8 + 640, // width + 480, // height + 8, // colour depth (bits per pixel) + // Mode 640x480x8T + 640, // width + 480, // height + 8, // colour depth (bits per pixel) + // Mode 640x480x15 + 640, // width + 480, // height + 16, // colour depth (bits per pixel) + // Mode 640x480x24 + 640, // width + 480, // height + 24 // colour depth (bits per pixel) + }; + +// Flag for backdrop composition + +// for 640x480x8 experiment +#if InterlaceExperiment +int oddDraw; +#endif + + +// Surface for Backdrop composition +LPDIRECTDRAWSURFACE lpDDBackdrop; +// Pointer into Backdrop DD surface +unsigned char* BackScreenBuffer; +// Pitch on auxilliary backdrop surface +static long BackScreenPitch; +DDPIXELFORMAT DisplayPixelFormat; + +// For locking against other processes, e.g. +// mouse pointer display +unsigned char GlobalFlipLock = No; + +/* Externs */ + +extern int VideoMode; +extern int VideoModeTypeScreen; +extern int VideoModeType; +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; +extern unsigned char *ScreenBuffer; +extern HWND hWndMain; +extern unsigned char LPTestPalette[]; +extern unsigned char TestPalette[]; +extern int WindowMode; +extern WINSCALEXY TopLeftSubWindow; +extern WINSCALEXY ExtentXYSubWindow; +extern int WinWidth; +extern int WinHeight; +extern int WinLeftX; +extern int WinTopY; +extern int WinRightX; +extern int WinBotY; +extern int DXMemoryMode; +extern int RasterisationRequestMode; +extern int DXMemoryRequestMode; +extern int WindowRequestMode; +extern int VideoRequestMode; +extern int ZBufferRequestMode; +extern int SoftwareScanDrawRequestMode; +extern unsigned char AttemptVideoModeRestart; +extern VIDEORESTARTMODES VideoRestartMode; +extern BOOL MMXAvailable; +extern BOOL D3DHardwareAvailable; +extern int cosine[]; +extern int sine[]; + +BOOL really_32_bit = 0; + +void GenerateDirectDrawSurface() + +{ + + DDCAPS ddcaps; + HRESULT ddrval; + DDSURFACEDESC ddsd; + DDSCAPS ddscaps; + unsigned char Mode8T; + + // Check for combination of a MODEX type mode + // and SubWindowing + + #if AllowReboot + // THIS MAY NOT WORK!!! + if (WindowMode == WindowModeSubWindow) + ddrval = lpDD->SetCooperativeLevel(hWndMain, + DDSCL_NORMAL); + else + ddrval = lpDD->SetCooperativeLevel(hWndMain, + DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT ); + + LOGDXERR(ddrval); + #else + // More stable even if crashes cannot be booted + // out of? + if (WindowMode == WindowModeSubWindow) + ddrval = lpDD->SetCooperativeLevel(hWndMain, + DDSCL_NORMAL); + else + ddrval = lpDD->SetCooperativeLevel(hWndMain, + DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX); + LOGDXERR(ddrval); + #endif + + TimeStampedMessage("Allow reboot thingy"); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(0x2); + } + #else + return; + #endif + + switch (ScreenDescriptorBlock.SDB_ScreenDepth) + { + case VideoModeType_8: + VideoModeColourDepth = 8; + Mode8T = No; + break; + case VideoModeType_15: + VideoModeColourDepth = 16; + Mode8T = No; + break; + case VideoModeType_24: + if (really_32_bit) + VideoModeColourDepth = 32; + else + VideoModeColourDepth = 24; + Mode8T = No; + break; + case VideoModeType_8T: + VideoModeColourDepth = 8; + Mode8T = Yes; + break; + default: + VideoModeColourDepth = 16; // default is 16 bit colour + break; + } + + // Note that SetDisplayMode is now technically part + // of the DirectDraw2 COM interface, not DirectDraw. + // However, as long as we do not wish to change + // monitor refresh rates we do not need to use the + // DirectDraw2 version or set up a separate secondary + // DD interface object, which be just plain fiddly. + + // MAY NOT WORK LIKE THIS IN SUBWINDOW MODE!!!! + if (WindowMode == WindowModeFullScreen) + { + ddrval = lpDD->SetDisplayMode(ScreenDescriptorBlock.SDB_Width, + ScreenDescriptorBlock.SDB_Height, VideoModeColourDepth); + LOGDXERR(ddrval); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(ddrval); + } + #else + { + if ((ddrval == DDERR_INVALIDMODE) || + (ddrval == DDERR_GENERIC) || + (ddrval == DDERR_INVALIDPIXELFORMAT)) + { + AttemptVideoModeRestart = Yes; + VideoRestartMode = RestartDisplayModeNotAvailable; + } + return; + } + #endif + } + TimeStampedMessage("after SetDisplayMode"); + + // Create primary surface and back buffer + // IMPORTANT!!! Currently no support for triple + // buffering in SubWindow mode!!! + + if (WindowMode == WindowModeSubWindow) + { + // Create primary + memset(&ddsd,0,sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_CAPS; + + // Request a 3D capable device so that + // Direct3D accesses will work + // note primary must be in video memory + ddsd.ddsCaps.dwCaps = (DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE); + + ddrval = lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL); + LOGDXERR(ddrval); + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(0x41); + } + #else + return; + #endif + + // Create back buffer + memset(&ddsd,0,sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.dwHeight = ScreenDescriptorBlock.SDB_Height; + ddsd.dwWidth = ScreenDescriptorBlock.SDB_Width; + + // Request a 3D capable device so that + // Direct3D accesses will work + if (DXMemoryMode == SystemMemoryPreferred) + ddsd.ddsCaps.dwCaps = (DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE); + else // video memory if possible + ddsd.ddsCaps.dwCaps= (DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE); + + ddrval = lpDD->CreateSurface(&ddsd, &lpDDSBack, NULL); + LOGDXERR(ddrval); + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(0x5); + } + #else + return; + #endif + + // Create clipper objects + ddrval = lpDD->CreateClipper(0, &lpDDClipper, NULL); + LOGDXERR(ddrval); + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(0x55); + } + #else + return; + #endif + + ddrval = lpDDClipper->SetHWnd(0, hWndMain); + LOGDXERR(ddrval); + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(0x51); + } + #else + return; + #endif + + ddrval = lpDDSPrimary->SetClipper(lpDDClipper); + LOGDXERR(ddrval); + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(0x52); + } + #else + return; + #endif + } + else // default to FullScreen... + { + TimeStampedMessage("after 'default to FullScreen'"); + if (DXMemoryMode == VideoMemoryPreferred) + { + ddcaps.dwSize = sizeof (ddcaps); + memset (&ddsd, 0, sizeof (ddsd)); + ddsd.dwSize = sizeof (ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + + // Request a 3D capable device so that + // Direct3D accesses will work + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | + DDSCAPS_FLIP | + DDSCAPS_COMPLEX | + DDSCAPS_3DDEVICE; + + ddsd.dwBackBufferCount = 1; + + ddrval = lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL); + LOGDXERR(ddrval); + TimeStampedMessage("after vm CreateSurface"); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(0x41); + } + #else + { + // For dubious modex emulation + // problem fix and dubious driver + // cannot change to different bit depths + // fix. + // Note that this must be kept up to date!!!! + if ((ddrval == DDERR_OUTOFVIDEOMEMORY) && + ((VideoMode == VideoMode_DX_320x200x8) || + (VideoMode == VideoMode_DX_320x200x8T) || + (VideoMode == VideoMode_DX_320x240x8) || + (VideoMode == VideoMode_DX_320x200x15))) + { + AttemptVideoModeRestart = Yes; + VideoRestartMode = RestartOutOfVidMemForPrimary; + } + else if ((ddrval == DDERR_INVALIDMODE) || + (ddrval == DDERR_GENERIC) || + (ddrval == DDERR_INVALIDPIXELFORMAT)) + { + AttemptVideoModeRestart = Yes; + VideoRestartMode = RestartDisplayModeNotAvailable; + } + + return; + } + #endif + + // get a pointer to the back buffer + // DO I NEED TO SET A SIZE FIELD HERE?? + // SEEMS I _CAN'T_, ANYWAY... + ddscaps.dwCaps = DDSCAPS_BACKBUFFER; + + ddrval = lpDDSPrimary->GetAttachedSurface(&ddscaps,&lpDDSBack); + LOGDXERR(ddrval); + TimeStampedMessage("after vm GetAttachedSurface"); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(0x5); + } + #else + return; + #endif + } + // assume we want a system memory + // rendering target, e.g. for MMX + else + { + DDPIXELFORMAT TempPixelFormat; + + // Make primary, with back buffer in video memory + ddcaps.dwSize = sizeof (ddcaps); + memset (&ddsd, 0, sizeof (ddsd)); + ddsd.dwSize = sizeof (ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + + // Request a 3D capable device so that + // Direct3D accesses will work + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | + DDSCAPS_FLIP | + DDSCAPS_COMPLEX | + DDSCAPS_3DDEVICE; + + ddsd.dwBackBufferCount = 1; + + ddrval = lpDD->CreateSurface(&ddsd, &lpDDSPrimary, NULL); + LOGDXERR(ddrval); + TimeStampedMessage("after vm CreateSurface"); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(ddrval); + } + #else + { + return; + } + #endif + + // get a pointer to the back buffer + // Note that in this configuration the back + // buffer is hidden from the rendering system, + // since other configurations do not seem to be + // stable in ModeX emulation modes + ddscaps.dwCaps = DDSCAPS_BACKBUFFER; + + ddrval = lpDDSPrimary->GetAttachedSurface( + &ddscaps, + &lpDDSHiddenBack); + LOGDXERR(ddrval); + TimeStampedMessage("after vm GetAttachedSurface"); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(ddrval); + } + #else + return; + #endif + + // Save pixel format of primary + memcpy(&TempPixelFormat, &ddsd.ddpfPixelFormat, + sizeof(DDPIXELFORMAT)); + TimeStampedMessage("after memcpy 1"); + + // Create rendering target + memset(&ddsd,0,sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.dwHeight = ScreenDescriptorBlock.SDB_Height; + ddsd.dwWidth = ScreenDescriptorBlock.SDB_Width; + + // Ensure rendering target has same format as primary + memcpy(&ddsd.ddpfPixelFormat, &TempPixelFormat, + sizeof(DDPIXELFORMAT)); + TimeStampedMessage("after memcpy 2"); + + // Request a 3D capable device so that + // Direct3D accesses will work + ddsd.ddsCaps.dwCaps = (DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY | DDSCAPS_3DDEVICE); + + ddrval = lpDD->CreateSurface(&ddsd, &lpDDSBack, NULL); + TimeStampedMessage("after CreateSurface"); + LOGDXERR(ddrval); + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(ddrval); + } + #else + return; + #endif + } + } + + // Set the Colour Palette (paletted modes only) + #if NoPalette + #else + if (VideoModeColourDepth == 8) + { + + TimeStampedMessage("SHOULD NEVER GET HERE"); + + if (WindowMode == WindowModeSubWindow) + // Use system palette in a SubWindow case + { + // Standard windows RGB + flags palette + // structure prototyped in various versions + // (Though not, apparently, others) of objbase.h + PALETTEENTRY SystemPalette[256]; + // Get system palette via GDI device context + HDC hdc = GetDC(NULL); + GetSystemPaletteEntries(hdc, 0, (1 << 8), SystemPalette); + // Restrict system to two palette entries only. + SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC); + ReleaseDC(NULL, hdc); + + // Flag system palette entries + // Will this work? + // I sure hope so... + { + int i; + // Take all but 20 basic entries for our + // greedy little sod of a game window + for (i=0; i<1; i++) + SystemPalette[i].peFlags = PC_EXPLICIT; + for (i=1; i<(256-1); i++) + { + SystemPalette[i].peRed = LPTestPalette[i*4]; + SystemPalette[i].peGreen = LPTestPalette[(i*4)+1]; + SystemPalette[i].peBlue = LPTestPalette[(i*4)+2]; + SystemPalette[i].peFlags = PC_RESERVED; + } + for (i=(256-1); i<256; i++) + SystemPalette[i].peFlags = PC_EXPLICIT; + } + + // Create the palette within DirectDraw, using + // DD palette initialisation rather than ours + ddrval = lpDD->CreatePalette(DDPCAPS_8BIT | DDPCAPS_ALLOW256, + SystemPalette, &lpDDPal[0], NULL); + LOGDXERR(ddrval); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(0x7); + } + #else + return; + #endif + + // Set palette on both buffers + ddrval = lpDDSBack->SetPalette(lpDDPal[0]); + LOGDXERR(ddrval); + ddrval = lpDDSPrimary->SetPalette(lpDDPal[0]); + LOGDXERR(ddrval); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(ddrval); + } + #else + return; + #endif + // Save palette in internal format for + // use later + // Out because it causes problems with + // window mode swapping. + // ConvertDDToInternalPalette((unsigned char*) SystemPalette, TestPalette, 256); + } + else // default to FullScreen + { + if ((ScreenDescriptorBlock.SDB_Flags + & SDB_Flag_Raw256) || (Mode8T))// full 256 colours + ddrval = lpDD->CreatePalette((DDPCAPS_8BIT | DDPCAPS_ALLOW256), + (LPPALETTEENTRY)(LPTestPalette), + &lpDDPal[0], + NULL); + else // default is 222 + ddrval = lpDD->CreatePalette((DDPCAPS_8BIT), + (LPPALETTEENTRY)(LPTestPalette), + &lpDDPal[0], + NULL); + LOGDXERR(ddrval); + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(0x7); + } + #else + return; + #endif + + ddrval = lpDDSPrimary->SetPalette(lpDDPal[0]); + LOGDXERR(ddrval); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(0x8); + } + #else + return; + #endif + +// Set palette on BOTH buffers to work around +// bug in Direct3D initialisation!!! + ddrval = lpDDSBack->SetPalette(lpDDPal[0]); + LOGDXERR(ddrval); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(0x8); + } + #else + return; + #endif + } + } + #endif // for NoPalette + + // Get the surface desc for AW DDSurface loads + + memset(&ddsd,0,sizeof ddsd); + ddsd.dwSize = sizeof ddsd; + ddrval = lpDDSPrimary->GetSurfaceDesc(&ddsd); + LOGDXERR(ddrval); + GLOBALASSERT(DD_OK==ddrval); + TimeStampedMessage("after memset"); + AwSetSurfaceFormat(&ddsd); + TimeStampedMessage("after AwSetSurfaceFormat"); + + // Do an initial lock and unlock on the back buffer + // to pull out vital information such as the + // surface description + LockSurfaceAndGetBufferPointer(); + UnlockSurface(); + TimeStampedMessage("after Lock & Unlock"); + +} + +// Lock back buffer and get screen pointer + +void LockSurfaceAndGetBufferPointer() +{ + DDSURFACEDESC ddsdback; + HRESULT ddrval; + int count = 0; + + #if optimiseblit + while (lpDDSBack->GetBltStatus(DDGBS_ISBLTDONE) != DD_OK); + #endif + + memset(&ddsdback, 0, sizeof(ddsdback)); + ddsdback.dwSize = sizeof(ddsdback); + + // DDLOCK_WAIT is another safety option that + // should in theory be removable by using + // the GetBltStatus call above. + // Or of course the while loop... + while ((ddrval = lpDDSBack->Lock(NULL, &ddsdback, DDLOCK_WAIT, NULL)) == DDERR_WASSTILLDRAWING) + { + count++; + if (count>1) // was 10000, for test purposes ONLY!!! + { + LOGDXERR(ddrval); + ReleaseDirect3D(); + exit(0x2001); + } + } + + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + return; + #endif + } + + /* ddsdback now contains my lpSurface)*/ + + ScreenBuffer = (unsigned char *)ddsdback.lpSurface; + BackBufferPitch = ddsdback.lPitch; + + // Get pixel format description of + // rendering target + memcpy(&DisplayPixelFormat, &ddsdback.ddpfPixelFormat, + sizeof(DDPIXELFORMAT)); +} + +void UnlockSurface(void) +{ + HRESULT ddrval; + + ddrval = lpDDSBack->Unlock((LPVOID)ScreenBuffer); + LOGDXERR(ddrval); + + #if debug + if (ddrval != DD_OK) + { + ReleaseDirect3D(); + exit(ddrval); + } + #endif +} + +void FlipBuffers(void) +{ + HRESULT ddrval; + + // for locking against other draw processes, + // e.g. mouse pointer + GlobalFlipLock = Yes; + + // IMPORTANT!!! OptimiseFlip, Blit are + // not supported in SubWindow mode!!! + + if (WindowMode == WindowModeSubWindow) + { + RECT dest; + + // For SubWindow mode, we cannot flip, but + // must instead do a (stretched, in principle) + // blit to the front buffer to combine with GDI + // surfaces. + // The whole back buffer should be taken. + dest.left = WinLeftX; + dest.top = WinTopY; + dest.right = WinRightX; + dest.bottom = WinBotY; + ddrval = lpDDSPrimary->Blt(&dest, lpDDSBack, + NULL, DDBLT_WAIT, NULL); + } + else // default to FullScreen + { + // we hope to flip, and flip to hope + // we are the tumbling jongleurs... + if (DXMemoryMode == VideoMemoryPreferred) + { + #if optimiseflip + while (lpDDSBack->GetFlipStatus(DDGFS_ISFLIPDONE) == DDERR_WASSTILLDRAWING) + ProcessProjectWhileWaitingToBeFlippable(); + #endif + + // we are going to flip with DDFLIP_WAIT on + // even if optimiseflip is set. + // IT'S THE ONLY WAY TO BE SURE. + ddrval = lpDDSPrimary->Flip(NULL, DDFLIP_WAIT); + + while(1) + { + if (ddrval == DD_OK) + break; + if (ddrval == DDERR_SURFACELOST) + { + ddrval = lpDDSPrimary->Restore(); + if (ddrval != DD_OK) + break; + } + if (ddrval != DDERR_WASSTILLDRAWING) + break; + } + } + else // assume system memory rendering target + { + // Take rendering target to back buffer + // Rendering target should map fully onto back buffer + ddrval = lpDDSHiddenBack->Blt(NULL, lpDDSBack, + NULL, DDBLT_WAIT, NULL); + + // And now do a standard flip + #if optimiseflip + while (lpDDSBack->GetFlipStatus(DDGFS_ISFLIPDONE) == DDERR_WASSTILLDRAWING) + ProcessProjectWhileWaitingToBeFlippable(); + #endif + + // we are going to flip with DDFLIP_WAIT on + // even if optimiseflip is set. + // IT'S THE ONLY WAY TO BE SURE. + ddrval = lpDDSPrimary->Flip(NULL, DDFLIP_WAIT); + + while(1) + { + if (ddrval == DD_OK) + break; + if (ddrval == DDERR_SURFACELOST) + { + ddrval = lpDDSPrimary->Restore(); + if (ddrval != DD_OK) + break; + } + if (ddrval != DDERR_WASSTILLDRAWING) + break; + } + } + } + + GlobalFlipLock = No; + + ProjectSpecificBufferFlipPostProcessing(); + + HandleScreenShot(); + + #if InterlaceExperiment + oddDraw ^= 1; + #endif +} + +void InGameFlipBuffers(void) +{ + FlipBuffers(); + return; + HRESULT ddrval; + + // for locking against other draw processes, + // e.g. mouse pointer + GlobalFlipLock = Yes; + + // IMPORTANT!!! OptimiseFlip, Blit are + // not supported in SubWindow mode!!! + + if (WindowMode == WindowModeSubWindow) + { + RECT dest; + + // For SubWindow mode, we cannot flip, but + // must instead do a (stretched, in principle) + // blit to the front buffer to combine with GDI + // surfaces. + // The whole back buffer should be taken. + dest.left = WinLeftX; + dest.top = WinTopY; + dest.right = WinRightX; + dest.bottom = WinBotY; + ddrval = lpDDSPrimary->Blt(&dest, lpDDSBack, + NULL, DDBLT_WAIT, NULL); + } + else // default to FullScreen + { + // we hope to flip, and flip to hope + // we are the tumbling jongleurs... + if (DXMemoryMode == VideoMemoryPreferred) + { + #if optimiseflip + while (lpDDSBack->GetFlipStatus(DDGFS_ISFLIPDONE) == DDERR_WASSTILLDRAWING) + ProcessProjectWhileWaitingToBeFlippable(); + #endif + + // we are going to flip with DDFLIP_WAIT on + // even if optimiseflip is set. + // IT'S THE ONLY WAY TO BE SURE. + ddrval = lpDDSPrimary->Flip(NULL, 0); + + while(0) + { + if (ddrval == DD_OK) + break; + if (ddrval == DDERR_SURFACELOST) + { + ddrval = lpDDSPrimary->Restore(); + if (ddrval != DD_OK) + break; + } + if (ddrval != DDERR_WASSTILLDRAWING) + break; + } + } + else // assume system memory rendering target + { + LOCALASSERT(0); + // Take rendering target to back buffer + // Rendering target should map fully onto back buffer + ddrval = lpDDSHiddenBack->Blt(NULL, lpDDSBack, + NULL, DDBLT_WAIT, NULL); + + // And now do a standard flip + #if optimiseflip + while (lpDDSBack->GetFlipStatus(DDGFS_ISFLIPDONE) == DDERR_WASSTILLDRAWING) + ProcessProjectWhileWaitingToBeFlippable(); + #endif + + // we are going to flip with DDFLIP_WAIT on + // even if optimiseflip is set. + // IT'S THE ONLY WAY TO BE SURE. + ddrval = lpDDSPrimary->Flip(NULL, DDFLIP_WAIT); + + while(1) + { + if (ddrval == DD_OK) + break; + if (ddrval == DDERR_SURFACELOST) + { + ddrval = lpDDSPrimary->Restore(); + if (ddrval != DD_OK) + break; + } + if (ddrval != DDERR_WASSTILLDRAWING) + break; + } + } + } + + GlobalFlipLock = No; + + ProjectSpecificBufferFlipPostProcessing(); + + HandleScreenShot(); + + #if InterlaceExperiment + oddDraw ^= 1; + #endif +} + +// As of 29/4/96, slightly later in the day, +// it now deallocates NOTHING explcitly, but +// just calls Release on the entire DD object, +// which seems a better approach. Ho hum. + +// This function is now OBSOLETE (25 / 7 / 96) +// CALL RELEASEDIRECT3D INSTEAD!!! + +void finiObjects(void) +{ + if (lpDD != NULL) + { + lpDD->Release(); + lpDD = NULL; + } +} + +// Release ONE direct draw surface, to be used +// when replacing images via imageheader array, +// e.g. in LoadBackdrop. + +void ReleaseDDSurface(void* DDSurface) + +{ + LPDIRECTDRAWSURFACE lpSurface; + + WaitForVRamReady(VWS_DDRELEASE); + + lpSurface = (LPDIRECTDRAWSURFACE) DDSurface; + + if (lpSurface != NULL) + { + lpSurface->Release(); + lpSurface = NULL; + } +} + + +// Blt member is used rather BltFast because BltFast does not +// allow a colour fill + +void ColourFillBackBuffer(int FillColour) + +{ + HRESULT ddrval; + DDBLTFX ddbltfx; + + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = FillColour; + + /* lets blt a color to the surface*/ + #if optimiseblit + while (lpDDSBack->GetBltStatus(DDGBS_CANBLT) != DD_OK); + #endif + + #if optimiseblit + ddrval = lpDDSBack->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_ASYNC, &ddbltfx); + + if (ddrval == DDERR_WASSTILLDRAWING) + ddrval = lpDDSBack->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, + &ddbltfx); + #else + ddrval = lpDDSBack->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); + #endif + + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + return; + #endif + } +} + +// Blt member is used rather BltFast because BltFast does not +// allow a colour fill + +void ColourFillBackBufferQuad(int FillColour, int LeftX, + int TopY, int RightX, int BotY) + +{ + HRESULT ddrval; + DDBLTFX ddbltfx; + RECT destRect; + + destRect.left = LeftX; + destRect.top = TopY; + destRect.right = RightX; + destRect.bottom = BotY; + + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = FillColour; + + /* lets blt a color to the surface*/ + #if optimiseblit + while (lpDDSBack->GetBltStatus(DDGBS_CANBLT) != DD_OK); + #endif + + #if optimiseblit + ddrval = lpDDSBack->Blt(&destRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_ASYNC, &ddbltfx); + + if (ddrval == DDERR_WASSTILLDRAWING) + ddrval = lpDDSBack->Blt(&destRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); + #else + ddrval = lpDDSBack->Blt(&destRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); + #endif + + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + return; + #endif + } +} + +// Note Blt is used rather than BltFast because BltFast will +// always attempt to invoke an asynchronous blit and this appears +// to be unstable at present (cf. problems with optimiseblit) +// CHECK THIS -- WITH DDBLTFASTWAIT??? +// COMMENT ABOVE NOW OBSOLETE... + +void BlitToBackBuffer(void* lpBackground, RECT* destRectPtr, RECT* srcRectPtr) + +{ + HRESULT ddrval; + + #if optimiseblit + while (lpDDSBack->GetBltStatus(DDGBS_CANBLT) != DD_OK); + #endif + + #if optimiseblit + ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground, + srcRectPtr, DDBLT_ASYNC, NULL); + + if (ddrval == DDERR_WASSTILLDRAWING) + ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground, + srcRectPtr, DDBLT_WAIT, NULL); + #else + ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground, + srcRectPtr, DDBLT_WAIT, NULL); + #endif + + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + return; + #endif + } +} + +// Note Blt is used rather than BltFast because BltFast does not +// support DDBLTFX and therefore cannot be used to attempt to +// prevent tearing + +void BlitToBackBufferWithoutTearing(void* lpBackground, RECT* destRectPtr, RECT* srcRectPtr) + +{ + HRESULT ddrval; + DDBLTFX ddbltfx; + + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwDDFX = DDBLTFX_NOTEARING; + + #if optimiseblit + while (lpDDSBack->GetBltStatus(DDGBS_CANBLT) != DD_OK); + #endif + + #if optimiseblit + ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground, + srcRectPtr, DDBLT_ASYNC | DDBLT_DDFX, &ddbltfx); + + if (ddrval == DDERR_WASSTILLDRAWING) + ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground, + srcRectPtr, DDBLT_WAIT | DDBLT_DDFX, &ddbltfx); + #else + ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground, + srcRectPtr, DDBLT_WAIT | DDBLT_DDFX, &ddbltfx); + #endif + + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + return; + #endif + } +} + +#if 0 + +// Note Blt is used rather than BltFast because BltFast does +// not support the DDBLTFX structure and therefore cannot accept +// a rotated blit + +void RotatedBlitToBackBuffer(void* lpBackground, RECT* destRectPtr, RECT* srcRectPtr, int RollZ) + +{ + HRESULT ddrval; + DDBLTFX ddbltfx; + + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwRotationAngle = RollZ; + + #if optimiseblit + while (lpDDSBack->GetBltStatus(DDGBS_CANBLT) != DD_OK); + #endif + + #if optimiseblit + ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground, + srcRectPtr, DDBLT_ASYNC | DDBLT_ROTATIONANGLE, &ddbltfx); + + if (ddrval == DDERR_WASSTILLDRAWING) + ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground, + srcRectPtr, DDBLT_WAIT | DDBLT_ROTATIONANGLE, &ddbltfx); + #else + ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground, + srcRectPtr, DDBLT_WAIT | DDBLT_ROTATIONANGLE, &ddbltfx); + #endif + + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + return; + #endif + } +} + +// Note Blt is used rather than BltFast because BltFast does not +// support DDBLTFX and therefore cannot be used to attempt to +// prevent tearing + +void RotatedBlitToBackBufferWithoutTearing(void* lpBackground, RECT* destRectPtr, RECT* srcRectPtr, int RollZ) + +{ + HRESULT ddrval; + DDBLTFX ddbltfx; + + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwDDFX = DDBLTFX_NOTEARING; + ddbltfx.dwRotationAngle = RollZ; + + #if optimiseblit + while (lpDDSBack->GetBltStatus(DDGBS_CANBLT) != DD_OK); + #endif + + #if optimiseblit + ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground, + srcRectPtr, DDBLT_ASYNC | DDBLT_DDFX | DDBLT_ROTATIONANGLE, &ddbltfx); + + if (ddrval == DDERR_WASSTILLDRAWING) + ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground, + srcRectPtr, DDBLT_WAIT | DDBLT_DDFX | DDBLT_ROTATIONANGLE, &ddbltfx); + #else + ddrval = lpDDSBack->Blt(destRectPtr, (LPDIRECTDRAWSURFACE) lpBackground, + srcRectPtr, DDBLT_WAIT | DDBLT_DDFX | DDBLT_ROTATIONANGLE, &ddbltfx); + #endif + + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + return; + #endif + } +} + +#endif + + +// Note x, y are assumed to be TOP LEFT of character +// BltFast is used here, partially as an experiment (ahem...) + +// THIS FUNCTION ASSUMES A VERTICAL FONT BRUSH!!! + +// FIXME!!! This function does not always seem to +// produce visible text in SubWindow mode; i.e. +// as of 29/4/96 it works on Roxby's and fails on +// mine. I suspect this is because we are using +// BltFast, which 'works only on display memory', +// and there isn't enough video RAM on my card +// to put the debug font in video memory in SubWindow +// mode. Or something. +// At present I have done nothing about this, since Roxby +// claims that as of Beta 3 he can't get source colour +// keying working on the blitter without using BltFast, and +// we need source colour keying to get the font to +// look right. +// Will have to be looked at at some stage, 'tho. + +#if debug || PreBeta +void BlitWin95Char(int x, int y, unsigned char toprint) + +{ + static int bltwin95char_ok=1; + if (!bltwin95char_ok) return; + + int FontIndex; + RECT source; + HRESULT ddrval; + #if NoBltFastOnFont + RECT destination; + #endif + + // Check for data out of range for font + if ((toprint < FontStart) || (toprint > FontEnd)) + return; + + // Check for character being on screen + if ((x < ScreenDescriptorBlock.SDB_ClipLeft) || + ((x + CharWidth) > ScreenDescriptorBlock.SDB_ClipRight) || + (y < ScreenDescriptorBlock.SDB_ClipUp) || + ((y + CharHeight) > ScreenDescriptorBlock.SDB_ClipDown)) + return; + + // Generate font index and source rectangle + // Assumes vertical brush + FontIndex = (toprint - FontStart); + + source.left = 0; + source.top = (FontIndex * CharHeight); + source.right = CharWidth; + source.bottom = ((FontIndex + 1) * CharHeight); + + // Do blit + #if NoBltFastOnFont + destination.left = x; + destination.top = y; + destination.right = (x+CharWidth); + destination.bottom = (y+CharHeight); + ddrval = lpDDSBack->Blt(&destination, lpDDDbgFont, + &source, DDBLT_WAIT | DDBLT_KEYSRC, NULL); + #else + ddrval = lpDDSBack->BltFast(x, y, + lpDDDbgFont, &source, + DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); + #endif + + LOGDXERR(ddrval); + if (ddrval != DD_OK) + #if debug && 0 + { + ReleaseDirect3D(); + exit(0x11); + } + #else + bltwin95char_ok = 0; + return; + #endif +} + +#else +void BlitWin95Char(int x, int y, unsigned char toprint) +{ +} +#endif + +// IMPORTANT!!! FIXME!!!! + +// This function has been hacked to FORCE images into +// system memory due to what appears to be a bug in +// DirectDraw's defaulting to system memory... + +// Has HOPEFULLY now been fixed to deal with non 8 bit +// images... but I wouldn't count on it... + +// If SysMem is TRUE, the image should go into system memory. If it is +// FALSE, we will try for video memory. And may God walk at our side in +// the valley of the shadow. + + + +// This callback enumerates all the DirectDraw +// devices present on a system searching for one +// with hardware 3D support available. If such +// a device is present, it will always be selected. +// Otherwise, no valid device will be returned. + +static BOOL bHardwareDDObj = FALSE; +static BOOL bNoHardwareDD = FALSE; + + +BOOL FAR PASCAL EnumDDObjectsCallback(GUID FAR* lpGUID, LPSTR lpDriverDesc, + LPSTR lpDriverName, LPVOID lpContext) +{ + LPDIRECTDRAW lpDDTest; + DDCAPS DriverCaps, HELCaps; + HRESULT ddrval; + + /* + A NULL GUID* indicates the DirectDraw HEL which we are not interested + in at the moment, because we are cruel and heartless and really + really nasty people, after all. + */ + + if (lpGUID) + { + // Create the DirectDraw device using this driver. If it fails, + // just move on to the next driver. + + ddrval = DirectDrawCreate(lpGUID, &lpDDTest, NULL); + LOGDXERR(ddrval); + if (ddrval != DD_OK) + return DDENUMRET_OK; + + // Get the capabilities of this DirectDraw driver. If it fails, + // just move on to the next driver. + + memset(&DriverCaps, 0, sizeof(DDCAPS)); + DriverCaps.dwSize = sizeof(DDCAPS); + memset(&HELCaps, 0, sizeof(DDCAPS)); + HELCaps.dwSize = sizeof(DDCAPS); + + ddrval = lpDDTest->GetCaps(&DriverCaps, &HELCaps); + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + lpDDTest->Release(); + return DDENUMRET_OK; + } + + // JH - changed so that debugging in a window works if you've got two cards or something + if (DriverCaps.dwCaps & DDCAPS_3D && WindowRequestMode != WindowModeSubWindow) + { + // We have found a 3d hardware device. Return the DD object + // and stop enumeration. + // This assumes that 3d capable DD hardware + // drivers cannot operate in a window. + // True? CHECKME!!! + WindowMode = WindowModeFullScreen; + *(LPDIRECTDRAW*)lpContext = lpDDTest; + return DDENUMRET_CANCEL; + } + lpDDTest->Release(); + } + return DDENUMRET_OK; +} + + +// Set up the DirectDraw object for the +// system. Using this we can determine the +// system capabilities. The DirectDraw object +// in question should never be released until +// ExitSystem, even if window or video modes +// are changed. Note that as well as checking +// for valid video modes etc, this function will +// also search for hardware DirectDraw objects +// and use one if appropriate. + +// Note that GenerateDirectDrawSurface and +// SetVideoMode now just set a video mode, +// rather than (as previously) initialising the +// DirectDraw model. + +// This function should be called +// during InitialiseSystem, so that we can +// be sure that SetVideoMode (called later) +// will be setting a valid mode. The function +// must be called after InitialVideoMode (which +// sets the mode it validates) and before +// InitialiseWindowsSystem, since in the +// current version that needs to know the +// WindowMode, not the VideoMode. Note that +// InitialiseWindowsSystem itself must be called +// after InitialVideoMode (it is currently +// called at the start of InitialiseSystem). + +DDCAPS direct_draw_caps; + +BOOL InitialiseDirectDrawObject(void) + +{ + HRESULT ddrval; + LPDIRECTDRAW lpDDHardware = NULL; + + // Set up DirectDraw object. + + // If we are not in emulation only mode, + // search for a hardware 3D capable DirectDraw + // driver and use it. If this fails, or if we + // are in emulation, go straight for the HEL. + if (RasterisationRequestMode != RequestSoftwareRasterisation) + { + ddrval = DirectDrawEnumerate(EnumDDObjectsCallback, &lpDDHardware); + LOGDXERR(ddrval); + if (ddrval != DD_OK) + { + #if debug + ReleaseDirect3D(); + exit(ddrval); + #else + return FALSE; + #endif + } + } + + // If we don't have a hardware driver, either + // because there wasn't one or because we are in + // HEL... then make one. + + if (!lpDDHardware) + { + if (RasterisationRequestMode != RequestSoftwareRasterisation) + bNoHardwareDD = TRUE; + bHardwareDDObj = FALSE; + ddrval = DirectDrawCreate(NULL, &lpDD, NULL); + LOGDXERR(ddrval); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(ddrval); + } + #else + { + ReleaseDirect3D(); // for safety + return FALSE; + } + #endif + } + else + { + bHardwareDDObj = TRUE; + lpDD = lpDDHardware; + } + + AwSetDDObject(lpDD); + + // Get caps for hardware DD driver/HEL layer + memset(&direct_draw_caps, 0, sizeof(direct_draw_caps)); + direct_draw_caps.dwSize = sizeof(direct_draw_caps); + ddrval = lpDD->GetCaps(&direct_draw_caps, NULL); + LOGDXERR(ddrval); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(ddrval); + } + #else + { + ReleaseDirect3D(); // for safety + return FALSE; + } + #endif + + // Put statistics into globals + TotalVideoMemory = (int) (direct_draw_caps.dwVidMemTotal); + // At some stage, we should set up a proper + // structure here with the general system + // capabilities in it. + // Notably, we may need to check DD surface + // alignment values and the stride. + + // NOTE THAT AS GARRY HAS POINTED OUT, TOTAL + // FREE VIDMEM CAN CHANGE AFTER SETTING THE + // VIDEO MODE OR COOPERATIVE LEVEL, SO WE + // SHOULD REALLY BE RUNNING THIS GETCAPS MEMBER + // ON THE DDOBJECT AGAIN AFTER GENERATESURFACE, OR + // POSSIBLY WHENEVER THE USER WANTS. + // ***FIXME!!!*** + + // Run the display modes enumerator + // Note that NULL in the second entry + // means enumerate all available display + // modes on the driver. + NumAvailableVideoModes = 0; + ddrval = lpDD->EnumDisplayModes(0, NULL, 0, EnumDisplayModesCallback); + LOGDXERR(ddrval); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(ddrval); + } + #else + { + ReleaseDirect3D(); // for safety + return FALSE; + } + #endif + + // Check that the video mode asked + // for (initially at least in + // InitialVideoMode) is actually + // available. If it is not, attempt to + // default to 640x480x8 and 640x480x15 + // (liable to be the most common modes) + // and if that fails, exit altogether + // with a failure code. + + // Note!!! This only matters in FullScreen + // mode. In SubWindow mode we must use the + // Windows display mode anyway. Obviously + // initialisation of the video mode will fail + // in SubWindow mode if the colour depth of + // the Windows display is different to the + // VideoMode colour depth, but I have not bothered + // to check for this since SubWindow mode is + // only intended for debugging and the failure + // case exits with an appropriate DirectDraw + // error anyway. + #if CheckVideoMode + if (WindowMode == WindowModeFullScreen) + { + if (!(CheckForVideoModes(VideoMode))) + { + VideoMode = VideoMode_DX_640x480x8; + if (!(CheckForVideoModes(VideoMode))) + { + VideoMode = VideoMode_DX_640x480x15; + if (!(CheckForVideoModes(VideoMode))) + { + ReleaseDirect3D(); // for safety + return FALSE; + } + } + } + } + #endif // for CheckVideoMode + + return TRUE; // Successful completion +} + + +// return TRUE on success + +static BOOL ReallyChangeDDObj(void) +{ + finiObjects(); + + if (InitialiseDirectDrawObject() + == FALSE) + /* + If we cannot get a video mode, + fail. No point in a non debugging option + for this. + */ + { + #if debug + ReleaseDirect3D(); + exit(0x997798); + #else + return FALSE; + #endif + } + + /* + Initialise global to say whether + we think there is an onboard 3D + acceleration card / motherboard + built-in + */ + #if 0 + TestInitD3DObject(); + +/* + This is (HOPEFULLY!!) now the right + place to put this call. Note that it is + not absolutely certain that we can do test + blits from DirectDraw without setting + a cooperative level, however... And note also + that MMX works better with the back buffer in + system memory... +*/ + TestMemoryAccess(); + #endif + return TRUE; +} + +int SelectDirectDrawObject(LPGUID pGUID) +{ + HRESULT ddrval; + LPDIRECTDRAW lpDDHardware = NULL; + + // Set up DirectDraw object. + bNoHardwareDD = TRUE; + bHardwareDDObj = FALSE; + ddrval = DirectDrawCreate(pGUID, &lpDD, NULL); + + AwSetDDObject(lpDD); + + // Get caps for hardware DD driver/HEL layer + memset(&direct_draw_caps, 0, sizeof(direct_draw_caps)); + direct_draw_caps.dwSize = sizeof(direct_draw_caps); + ddrval = lpDD->GetCaps(&direct_draw_caps, NULL); + LOGDXERR(ddrval); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(ddrval); + } + #else + { + ReleaseDirect3D(); // for safety + return FALSE; + } + #endif + + // Put statistics into globals + TotalVideoMemory = (int) (direct_draw_caps.dwVidMemTotal); + // At some stage, we should set up a proper + // structure here with the general system + // capabilities in it. + // Notably, we may need to check DD surface + // alignment values and the stride. + + // NOTE THAT AS GARRY HAS POINTED OUT, TOTAL + // FREE VIDMEM CAN CHANGE AFTER SETTING THE + // VIDEO MODE OR COOPERATIVE LEVEL, SO WE + // SHOULD REALLY BE RUNNING THIS GETCAPS MEMBER + // ON THE DDOBJECT AGAIN AFTER GENERATESURFACE, OR + // POSSIBLY WHENEVER THE USER WANTS. + // ***FIXME!!!*** + + // Run the display modes enumerator + // Note that NULL in the second entry + // means enumerate all available display + // modes on the driver. + NumAvailableVideoModes = 0; + ddrval = lpDD->EnumDisplayModes(0, NULL, 0, EnumDisplayModesCallback); + LOGDXERR(ddrval); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(ddrval); + } + #else + { + ReleaseDirect3D(); // for safety + return FALSE; + } + #endif + + // Check that the video mode asked + // for (initially at least in + // InitialVideoMode) is actually + // available. If it is not, attempt to + // default to 640x480x8 and 640x480x15 + // (liable to be the most common modes) + // and if that fails, exit altogether + // with a failure code. + + // Note!!! This only matters in FullScreen + // mode. In SubWindow mode we must use the + // Windows display mode anyway. Obviously + // initialisation of the video mode will fail + // in SubWindow mode if the colour depth of + // the Windows display is different to the + // VideoMode colour depth, but I have not bothered + // to check for this since SubWindow mode is + // only intended for debugging and the failure + // case exits with an appropriate DirectDraw + // error anyway. + #if CheckVideoMode + if (WindowMode == WindowModeFullScreen) + { + if (!(CheckForVideoModes(VideoMode))) + { + VideoMode = VideoMode_DX_640x480x8; + if (!(CheckForVideoModes(VideoMode))) + { + VideoMode = VideoMode_DX_640x480x15; + if (!(CheckForVideoModes(VideoMode))) + { + ReleaseDirect3D(); // for safety + return FALSE; + } + } + } + } + #endif // for CheckVideoMode + + return TRUE; // Successful completion +} + + + +BOOL ChangeDirectDrawObject(void) +{ + if (RequestSoftwareRasterisation==RasterisationRequestMode) + { + // software modes required + if (bHardwareDDObj) + { + // but was previously hardware DD + return ReallyChangeDDObj(); + } + } + else + { + // hardware modes requested if available + if (!bHardwareDDObj && !bNoHardwareDD) + { + // but was previously software DD and + // we haven't established that hardware isn't available + return ReallyChangeDDObj(); + } + } + + return TRUE; +} + + + +BOOL CheckForVideoModes(int TestVideoMode) + +{ + int i=0; + BOOL EarlyExit = FALSE; + + do + { + if ((EngineVideoModes[TestVideoMode].Width + == AvailableVideoModes[i].Width) && + (EngineVideoModes[TestVideoMode].Height + == AvailableVideoModes[i].Height) && + (EngineVideoModes[TestVideoMode].ColourDepth + == AvailableVideoModes[i].ColourDepth)) + EarlyExit = TRUE; + else + i++; + } + while ((i < NumAvailableVideoModes) && + (!EarlyExit)); + + return(EarlyExit); +} + +HRESULT CALLBACK EnumDisplayModesCallback(LPDDSURFACEDESC pddsd, LPVOID Context) +{ + AvailableVideoModes[NumAvailableVideoModes].Width = pddsd->dwWidth; + AvailableVideoModes[NumAvailableVideoModes].Height = pddsd->dwHeight; + AvailableVideoModes[NumAvailableVideoModes].ColourDepth = pddsd->ddpfPixelFormat.dwRGBBitCount; + NumAvailableVideoModes++; + + if (NumAvailableVideoModes < MaxAvailableVideoModes) + return DDENUMRET_OK; + else + return DDENUMRET_CANCEL; +} + +// Deallocate all objects except the basic +// DirectDraw objects, which we want to do +// before shifting display modes or window +// mode. Note that ExitWindowsSystem must be +// called separately. Note also that ExitSystem +// should be called for a full system shutdown. + +// FIXME!!! BACKDROPS?!?!? -- done in +// DeallocateAllImages (called from ReleaseDirect3D +// and ReleaseDirect3DNotDD) + +// Note that getting the right sequence for releases +// here is CRUCIAL. Note also that the font surface +// is NOT explicitly deallocated; hopefully it will just +// go when we kill the primary (as an offscreen surface). +// Could this cause problems for DeallocateAllImages?? +// Um, err, I sure hope not... + + +void finiObjectsExceptDD(void) +{ + if (WindowMode == WindowModeSubWindow) + { + if (lpDDClipper != NULL) + { + lpDDClipper->Release(); + lpDDClipper = NULL; + } + } + + if (lpDDPal[0] != NULL) // should be killed neway??? + { + lpDDPal[0]->Release(); + lpDDPal[0] = NULL; + } + + if (lpDDSBack != NULL) + { + lpDDSBack->Release(); + lpDDSBack = NULL; + } + + if (lpDDSPrimary != NULL) + { + lpDDSPrimary->Release(); + lpDDSPrimary = NULL; + } +} + + +// This will hopefully allow us to change +// the palette at runtime, assuming that +// we are in a palettised mode. It will +// wait for vertical blank to make it work +// on all video cards (I hope). Note that +// the palette should be passed in engine +// internal format, i.e. 6 bits, and will be +// converted to the DirectDraw format internally. + +// Note we assume entry 0 in the lpDDPal array!!! + +// Note for 222 mode we set the FIRST 64 entries!!! +// Not certain that's right, actually... + +int ChangePalette (unsigned char* NewPalette) + +{ + unsigned char DDPalette[1024]; // 256 colours, 4 bytes each + int NumEntries; + + // Check for palettised mode + // Note we must use VideoModeTypeScreen + // due to nature of Direct3D ramp driver + // interface. + + if ((VideoModeTypeScreen != VideoModeType_8) && + (VideoModeTypeScreen != VideoModeType_8T)) + return No; + + // Check for FullScreen mode + // if (WindowMode != WindowModeFullScreen) + // return No; + + // Set up number of entries to change + if (ScreenDescriptorBlock.SDB_Flags & SDB_Flag_222) + NumEntries = 256; // actually, this seems to be right... + else if ((ScreenDescriptorBlock.SDB_Flags & SDB_Flag_Raw256) + || (VideoModeTypeScreen == VideoModeType_8T)) + NumEntries = 256; + else + return No; // undefined behaviour + + // Convert to DirectDraw 4 bytes, 8 bit format + // with all flag entries set to zero + + ConvertToDDPalette(NewPalette, DDPalette, NumEntries, 0); + + // Wait for beginning of next vertical + // blanking interval + lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL); + + // Set all entries in palette to new values + lpDDPal[0]->SetEntries(0,0,NumEntries,(LPPALETTEENTRY) + DDPalette); + + return Yes; +} + +// At some stage it may be worth expanding this function +// to get more than video memory, or replacing it +// with one that uses GetCaps to fill out a general +// structure. + +int GetAvailableVideoMemory(void) +{ + DDCAPS ddcaps; + HRESULT ddrval; + + // Get caps for DirectDraw object + memset(&ddcaps, 0, sizeof(ddcaps)); + ddcaps.dwSize = sizeof(ddcaps); + ddrval = lpDD->GetCaps(&ddcaps, NULL); + LOGDXERR(ddrval); + + if (ddrval != DD_OK) + #if debug + { + ReleaseDirect3D(); + exit(ddrval); + } + #else + return -1; + #endif + + return (int) (ddcaps.dwVidMemFree); +} + +/* + This is designed to allow for ModeX + emulation failures where the system + boots up in a low memory cost mode + which actually takes up much more than + a high cost mode because GDI cannot be + evicted. Note that the VideoMode reset + done here is in any case a last ditch + measure, since the higher res version will + be much slower as well as (normally) more + costly in terms of memory. + + It will also now do start errors due to the + driver not being able to change to a mode of + a different colour depth, and this not being reported + by the DirectDraw object's enum display modes + callback. Hopefully. + + NOTE THAT THIS MUST BE CALLED FROM YOUR WINMAIN + AFTER SETVIDEOMODE IF IT IS TO WORK. + + NOTE ALSO THAT THE ACTIVATION CODE FOR THIS IS + IN GENERATEDIRECTDRAWSURFACE AND WILL NOT BE TURNED + ON UNLESS -->DEBUG<-- IS -->OFF<--. +*/ + +void HandleVideoModeRestarts(HINSTANCE hInstance, int nCmdShow) +{ + if (AttemptVideoModeRestart) + { + switch (VideoRestartMode) + { + case RestartDisplayModeNotAvailable: + { + // Rewrite mode as equivalent resolution, + // different bit depth, before trying again. + // Note this must be kept up to date!!! + switch (VideoMode) + { + case VideoMode_DX_320x200x8: + { + ReleaseDirect3D(); + exit(0xfedd); + } + VideoMode = VideoMode_DX_320x200x15; + break; + + case VideoMode_DX_320x200x8T: + VideoMode = VideoMode_DX_320x200x15; + break; + + case VideoMode_DX_320x200x15: + VideoMode = VideoMode_DX_320x200x8T; + break; + + case VideoMode_DX_320x240x8: + VideoMode = VideoMode_DX_320x200x15; + break; + + case VideoMode_DX_640x480x8: + VideoMode = VideoMode_DX_640x480x15; + break; + + case VideoMode_DX_640x480x8T: + VideoMode = VideoMode_DX_640x480x15; + break; + + case VideoMode_DX_640x480x15: + VideoMode = VideoMode_DX_640x480x8T; + break; + + case VideoMode_DX_640x480x24: + VideoMode = VideoMode_DX_640x480x15; + break; + + default: // hmm... + break; + } + + // Clear variables + AttemptVideoModeRestart = No; + VideoRestartMode = NoRestartRequired; + + ChangeDisplayModes(hInstance, nCmdShow, + VideoMode, WindowRequestMode, + ZBufferRequestMode, RasterisationRequestMode, + SoftwareScanDrawRequestMode, DXMemoryRequestMode); + } + break; + + case RestartOutOfVidMemForPrimary: + { + // Guess mode reset + // Note this must be kept up to date!!! + if ((VideoMode == VideoMode_DX_320x200x8) || + (VideoMode == VideoMode_DX_320x200x8T) || + (VideoMode == VideoMode_DX_320x240x8)) + VideoMode = VideoMode_DX_640x480x8; + else if (VideoMode == VideoMode_DX_320x200x15) + VideoMode = VideoMode_DX_640x480x15; + + // Clear variables + AttemptVideoModeRestart = No; + VideoRestartMode = NoRestartRequired; + + ChangeDisplayModes(hInstance, nCmdShow, + VideoMode, WindowRequestMode, + ZBufferRequestMode, RasterisationRequestMode, + SoftwareScanDrawRequestMode, DXMemoryRequestMode); + } + break; + + default: // err... + break; + } + } +} + + +// Take a 24 bit RGB colour and return it in the +// correct format for the current primary surface +// We will assume that the primary is NOT in a +// palettised mode, since the mapping if we have +// already set a palette is undefined. + +int GetSingleColourForPrimary(int Colour) + +{ + unsigned long m; + int s; + int red_shift, red_scale; + int green_shift, green_scale; + int blue_shift, blue_scale; + int RetVal = 0; + int r, g ,b; + + // Fail for palettised modes + if ((VideoModeTypeScreen == VideoModeType_8) + || (VideoModeTypeScreen == VideoModeType_8T)) + return -1; + + // Extra! check for palettised modes + if ((DisplayPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) + || (DisplayPixelFormat.dwFlags & DDPF_PALETTEINDEXED4)) + return -1; + + // Determine r, g, b masks and scale + for (s = 0, m = DisplayPixelFormat.dwRBitMask; + !(m & 1); s++, m >>= 1); + + red_shift = s; + red_scale = 255 / (DisplayPixelFormat.dwRBitMask >> s); + + for (s = 0, m = DisplayPixelFormat.dwGBitMask; + !(m & 1); s++, m >>= 1); + + green_shift = s; + green_scale = 255 / (DisplayPixelFormat.dwGBitMask >> s); + + for (s = 0, m = DisplayPixelFormat.dwBBitMask; + !(m & 1); s++, m >>= 1); + + blue_shift = s; + blue_scale = 255 / (DisplayPixelFormat.dwBBitMask >> s); + + // Extract r,g,b components from input colour + r = (Colour >> 16) & 0xff; + g = (Colour >> 8) & 0xff; + b = Colour & 0xff; + + // Scale and shift each value + r /= red_scale; + g /= green_scale; + b /= blue_scale; + RetVal = (r << red_shift) | (g << green_shift) + | (b << blue_shift); + + return(RetVal); +} + +#if triplebuffer +// NOTE TRIPLE BUFFERING SUPPORT HAS BEEN -->REMOVED<-- +// ON THE GROUNDS THAT THE SECOND BACK BUFFER TAKES UP +// EXTRA MEMORY AND IT'S NOT GOING TO GO ANY FASTER +// ANYWAY UNLESS YOUR VIDEO CARD FLIPS IN HARDWARE AND +// TAKES MORE THAN ABOUT 10 MILLISECONDS TO DO IT. +// WHICH I CERTAINLY HOPE ISN'T TRUE... + +// NOTE ALSO: THIS FUNCTION DOESN'T WORK! (DESPITE +// THE DOCUMENTATION). YOU NEED TO USE GETATTACHEDSURFACE +// TWICE INSTEAD. SEE ARSEWIPE CODE FOR A WORKING +// EXAMPLE (NOTE THAT TRIPLE BUFFERING CAN BE OPTIMAL +// IN ARSEWIPE BECAUSE IT'S 2D, AND THE TIME TO THE NEXT +// SURFACE LOCK IN A RENDERING CYCLE CAN THUS BE MUCH LESS +// THAN IN 3DC). + +// defines this function as FAR PASCAL, i.e. +// using Windows standard parameter passing convention, +// which will be neecessary for all callbacks + +HRESULT WINAPI InitTripleBuffers(LPDIRECTDRAWSURFACE lpdd, + LPDDSURFACEDESC lpsd, LPVOID lpc) +{ + if ((lpsd->ddsCaps.dwCaps & DDSCAPS_FLIP) && + (!(lpsd->ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER)) + && (BackBufferEnum < MaxBackBuffers)) + lpDDSBack[BackBufferEnum++] = lpdd; + + if (BackBufferEnum == MaxBackBuffers) + return(DDENUMRET_CANCEL); + else + return(DDENUMRET_OK); +} +#endif + + + +/* new versions of these functions, provided by neil */ +static GDIObjectReferenceCount = 0; +BOOL GetGDISurface(void) +{ + HRESULT hr = DD_OK; + + if(WindowMode == WindowModeSubWindow) return TRUE; + + if(!lpDDGDI) + { + hr = lpDD->GetGDISurface(&lpDDGDI); + if(hr != DD_OK) + { + ReleaseDirect3D(); + exit(hr); + } + } + + // flip the buffer to the GDI surface + hr = lpDD->FlipToGDISurface(); + if(hr != DD_OK) + { + ReleaseDirect3D(); + exit(hr); + } + + GDIObjectReferenceCount++; + + // release windows palette entries - + // whenever we flip to the GDI surface, + // we will want the full palette. + + if (VideoModeColourDepth == 8) + { + HDC hdc = GetDC(NULL); + SetSystemPaletteUse(hdc, SYSPAL_STATIC); + ReleaseDC(NULL, hdc); + } + + return TRUE; +} + + +BOOL LeaveGDISurface(void) +{ + HRESULT hr = DD_OK; + + if(WindowMode == WindowModeSubWindow) return TRUE; + + if (GDIObjectReferenceCount <= 1) + { + ReleaseDDSurface(lpDDGDI); + } + + // recapture system static palette + // entries (see note above in + // GetGDISurface... ) + + if (VideoModeColourDepth == 8) + { + HDC hdc = GetDC(NULL); + SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC); + ReleaseDC(NULL, hdc); + } + + return TRUE; +} + +/************ for extern "C"*****************/ + +}; + diff --git a/3dc/win95/DEBUGLOG.CPP b/3dc/win95/DEBUGLOG.CPP new file mode 100644 index 0000000..2e76b9f --- /dev/null +++ b/3dc/win95/DEBUGLOG.CPP @@ -0,0 +1,122 @@ +#include +#include +#include +#include "debuglog.hpp" + +LogFile::LogFile(char const * const _fname) : fname(0) , ever_written(0) +{ + FILE * fp = fopen(_fname,"w"); + if (fp) + { + fclose(fp); + fname = new char[strlen(_fname)+1]; + strcpy(fname,_fname); + return; + } + char const * path = getenv("TEMP"); + if (!path) path = getenv("TMP"); + if (!path) return; + fname = new char[strlen(path)+1+strlen(_fname)+1]; + strcpy(fname,path); + strncat(fname,"\\",1); + strcat(fname,_fname); + fp = fopen(fname,"w"); + if (fp) + fclose(fp); + else + { + delete[] fname; + fname = 0; + } +} + +LogFile::~LogFile() +{ + if (unwritten.size()) + { + FILE * fp = fopen(fname,"a"); + for (int attempt=0; !fp && attempt<10; ++attempt) + { + Sleep(100); + fp = fopen(fname,"a"); + } + if (fp) + { + FlushOut(fp); + fclose(fp); + } + } + if (fname) delete[] fname; +} + +LogFile & LogFile::operator = (LogFile const & l) +{ + if (&l != this) + { + if (fname) delete[] fname; + if (l.fname) + { + fname = new char[strlen(l.fname)+1]; + strcpy(fname,l.fname); + } + else + fname = 0; + + unwritten = l.unwritten; + ever_written = l.ever_written; + } + return *this; +} + +LogFile::LogFile(LogFile const & l) +: unwritten(l.unwritten) +, ever_written(l.ever_written) +{ + if (l.fname) + { + fname = new char[strlen(l.fname)+1]; + strcpy(fname,l.fname); + } + else + fname = 0; +} + +void LogFile::FlushOut(FILE * fp) +{ + while (unwritten.size()) + { + char * str = unwritten.first_entry(); + unwritten.delete_first_entry(); + fputs(str,fp); + delete[] str; + } +} + +int vlfprintf(LOGFILE * lfp, char const * format, va_list args ) +{ + return lfp->vlprintf(format,args); +} + +int lfprintf(LOGFILE * lfp, char const * format, ... ) +{ + va_list ap; + va_start(ap, format); + int rv = lfp->vlprintf(format,ap); + va_end(ap); + return rv; +} + +int lfputs(LOGFILE * lfp, char const * str) +{ + return lfp->lputs(str); +} + +LOGFILE * lfopen(char const * fname) +{ + return new LogFile(fname); +} + +void lfclose(LOGFILE * lfp) +{ + delete lfp; +} diff --git a/3dc/win95/DEBUGLOG.H b/3dc/win95/DEBUGLOG.H new file mode 100644 index 0000000..2079406 --- /dev/null +++ b/3dc/win95/DEBUGLOG.H @@ -0,0 +1,26 @@ +#ifndef _included_debuglog_h_ +#define _included_debuglog_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct LogFile LOGFILE; + +int vlfprintf(LOGFILE * lfp, char const * format, va_list args ); + +int lfprintf(LOGFILE * lfp, char const * format, ... ); + +int lfputs(LOGFILE * lfp, char const * str); + +LOGFILE * lfopen(char const * fname); + +void lfclose(LOGFILE * lfp); + +#ifdef __cplusplus +} +#endif + +#endif /* ! _included_debuglog_h_ */ diff --git a/3dc/win95/DEBUGLOG.HPP b/3dc/win95/DEBUGLOG.HPP new file mode 100644 index 0000000..5a0087e --- /dev/null +++ b/3dc/win95/DEBUGLOG.HPP @@ -0,0 +1,179 @@ +#ifndef _included_debuglog_hpp_ +#define _included_debuglog_hpp_ + +#include +#include "debuglog.h" +#include "list_tem.hpp" + +/* Changed 27/1/98 by DHM: + ----------------------- + + Made LogFile derived from R_DumpContext rather than being a base class. + + This is in order to give a clean interface for debug dumps to e.g. the + screen, with the same interface as to a log file. This base class will + perform an analagous role to the class CDumpContext in the Microsoft + Foundation Class library. + + The virtual functions dputs(), dprintf() and vdprintf() will eventually replace + lputs(), lprintf() and vlprintf(). + + For the moment I've copied and pasted the implementations of both. I would prefer + in the short term to make one call the other, but this isn't easy with variable + arguments. In the long term I want to eliminate the l* functions (lputs() etc) + but can't because of heritage code (and heritage libraries). +*/ + + #ifndef _dcontext_hpp + #include "dcontext.hpp" + #endif + +struct LogFile : public R_DumpContext +{ +private: + char * fname; + List unwritten; + int ever_written; + void FlushOut(FILE * fp); + +public: + LogFile(char const * const _fname); + virtual ~LogFile(); + LogFile & operator = (LogFile const & l); + LogFile(LogFile const & l); + + // {{{ Virtual dump implementations: + inline int dputs(char const * const buf) + { + if (!fname) return EOF; + FILE * fp = fopen(fname,"a"); + if (!fp) + { + if (!ever_written) return EOF; + char * newtxt = new char [strlen(buf)+1]; + strcpy(newtxt,buf); + unwritten.add_entry_end(newtxt); + return 0; + } + if (unwritten.size()) FlushOut(fp); + ever_written = 1; + int rv = fputs(buf,fp); + fclose(fp); + return rv; + } + + inline int dprintf(char const * format, ... ) + { + if (!fname) return -1; + FILE * fp = fopen(fname,"a"); + if (!fp && !ever_written) return -1; + va_list ap; + va_start(ap, format); + int rv; + if (fp) + { + if (unwritten.size()) FlushOut(fp); + rv = vfprintf(fp,format,ap); + ever_written = 1; + } + else + { + char buf[4096]; + rv = vsprintf(buf,format,ap); + char * newtxt = new char [strlen(buf)+1]; + strcpy(newtxt,buf); + unwritten.add_entry_end(newtxt); + } + va_end(ap); + if (fp) fclose(fp); + return rv; + } + + inline int vdprintf(char const * format, va_list ap) + { + if (!fname) return -1; + FILE * fp = fopen(fname,"a"); + if (!fp && !ever_written) return -1; + + int rv; + if (fp) + { + if (unwritten.size()) FlushOut(fp); + rv = vfprintf(fp,format,ap); + ever_written = 1; + fclose(fp); + } + else + { + char buf[4096]; + rv = vsprintf(buf,format,ap); + char * newtxt = new char [strlen(buf)+1]; + strcpy(newtxt,buf); + unwritten.add_entry_end(newtxt); + } + return rv; + } + // }}} + + // {{{ Deprecated logging functions: + inline int lputs(char const * const buf) + { + return dputs(buf); + } + + inline int lprintf(char const * format, ... ) + { + if (!fname) return -1; + FILE * fp = fopen(fname,"a"); + if (!fp && !ever_written) return -1; + va_list ap; + va_start(ap, format); + int rv; + if (fp) + { + if (unwritten.size()) FlushOut(fp); + rv = vfprintf(fp,format,ap); + ever_written = 1; + } + else + { + char buf[4096]; + rv = vsprintf(buf,format,ap); + char * newtxt = new char [strlen(buf)+1]; + strcpy(newtxt,buf); + unwritten.add_entry_end(newtxt); + } + va_end(ap); + if (fp) fclose(fp); + return rv; + } + + inline int vlprintf(char const * format, va_list ap) + { + if (!fname) return -1; + FILE * fp = fopen(fname,"a"); + if (!fp && !ever_written) return -1; + + int rv; + if (fp) + { + if (unwritten.size()) FlushOut(fp); + rv = vfprintf(fp,format,ap); + ever_written = 1; + fclose(fp); + } + else + { + char buf[4096]; + rv = vsprintf(buf,format,ap); + char * newtxt = new char [strlen(buf)+1]; + strcpy(newtxt,buf); + unwritten.add_entry_end(newtxt); + } + return rv; + } + // }}} + +}; + +#endif // ! _included_debuglog_hpp_ diff --git a/3dc/win95/DXLOG.C b/3dc/win95/DXLOG.C new file mode 100644 index 0000000..d95bd51 --- /dev/null +++ b/3dc/win95/DXLOG.C @@ -0,0 +1,389 @@ +#include "3dc.h" + +#if debug + +#include "ourasert.h" +#include "dxlog.h" +#include "debuglog.h" + +/* + * D3DAppErrorToString + */ +static char* +D3DAppErrorToString(HRESULT error) +{ + switch(error) { + case DD_OK: + return "No error.\0"; + case DDERR_ALREADYINITIALIZED: + return "This object is already initialized.\0"; + case DDERR_BLTFASTCANTCLIP: + return "Return if a clipper object is attached to the source surface passed into a BltFast call.\0"; + case DDERR_CANNOTATTACHSURFACE: + return "This surface can not be attached to the requested surface.\0"; + case DDERR_CANNOTDETACHSURFACE: + return "This surface can not be detached from the requested surface.\0"; + case DDERR_CANTCREATEDC: + return "Windows can not create any more DCs.\0"; + case DDERR_CANTDUPLICATE: + return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created.\0"; + case DDERR_CLIPPERISUSINGHWND: + return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd.\0"; + case DDERR_COLORKEYNOTSET: + return "No src color key specified for this operation.\0"; + case DDERR_CURRENTLYNOTAVAIL: + return "Support is currently not available.\0"; + case DDERR_DIRECTDRAWALREADYCREATED: + return "A DirectDraw object representing this driver has already been created for this process.\0"; + case DDERR_EXCEPTION: + return "An exception was encountered while performing the requested operation.\0"; + case DDERR_EXCLUSIVEMODEALREADYSET: + return "An attempt was made to set the cooperative level when it was already set to exclusive.\0"; + case DDERR_GENERIC: + return "Generic failure.\0"; + case DDERR_HEIGHTALIGN: + return "Height of rectangle provided is not a multiple of reqd alignment.\0"; + case DDERR_HWNDALREADYSET: + return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or palettes created.\0"; + case DDERR_HWNDSUBCLASSED: + return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring state.\0"; + case DDERR_IMPLICITLYCREATED: + return "This surface can not be restored because it is an implicitly created surface.\0"; + case DDERR_INCOMPATIBLEPRIMARY: + return "Unable to match primary surface creation request with existing primary surface.\0"; + case DDERR_INVALIDCAPS: + return "One or more of the caps bits passed to the callback are incorrect.\0"; + case DDERR_INVALIDCLIPLIST: + return "DirectDraw does not support the provided cliplist.\0"; + case DDERR_INVALIDDIRECTDRAWGUID: + return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier.\0"; + case DDERR_INVALIDMODE: + return "DirectDraw does not support the requested mode.\0"; + case DDERR_INVALIDOBJECT: + return "DirectDraw received a pointer that was an invalid DIRECTDRAW object.\0"; + case DDERR_INVALIDPARAMS: + return "One or more of the parameters passed to the function are incorrect.\0"; + case DDERR_INVALIDPIXELFORMAT: + return "The pixel format was invalid as specified.\0"; + case DDERR_INVALIDPOSITION: + return "Returned when the position of the overlay on the destination is no longer legal for that destination.\0"; + case DDERR_INVALIDRECT: + return "Rectangle provided was invalid.\0"; + case DDERR_LOCKEDSURFACES: + return "Operation could not be carried out because one or more surfaces are locked.\0"; + case DDERR_NO3D: + return "There is no 3D present.\0"; + case DDERR_NOALPHAHW: + return "Operation could not be carried out because there is no alpha accleration hardware present or available.\0"; + case DDERR_NOBLTHW: + return "No blitter hardware present.\0"; + case DDERR_NOCLIPLIST: + return "No cliplist available.\0"; + case DDERR_NOCLIPPERATTACHED: + return "No clipper object attached to surface object.\0"; + case DDERR_NOCOLORCONVHW: + return "Operation could not be carried out because there is no color conversion hardware present or available.\0"; + case DDERR_NOCOLORKEY: + return "Surface doesn't currently have a color key\0"; + case DDERR_NOCOLORKEYHW: + return "Operation could not be carried out because there is no hardware support of the destination color key.\0"; + case DDERR_NOCOOPERATIVELEVELSET: + return "Create function called without DirectDraw object method SetCooperativeLevel being called.\0"; + case DDERR_NODC: + return "No DC was ever created for this surface.\0"; + case DDERR_NODDROPSHW: + return "No DirectDraw ROP hardware.\0"; + case DDERR_NODIRECTDRAWHW: + return "A hardware-only DirectDraw object creation was attempted but the driver did not support any hardware.\0"; + case DDERR_NOEMULATION: + return "Software emulation not available.\0"; + case DDERR_NOEXCLUSIVEMODE: + return "Operation requires the application to have exclusive mode but the application does not have exclusive mode.\0"; + case DDERR_NOFLIPHW: + return "Flipping visible surfaces is not supported.\0"; + case DDERR_NOGDI: + return "There is no GDI present.\0"; + case DDERR_NOHWND: + return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel HWND.\0"; + case DDERR_NOMIRRORHW: + return "Operation could not be carried out because there is no hardware present or available.\0"; + case DDERR_NOOVERLAYDEST: + return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on to establish a destination.\0"; + case DDERR_NOOVERLAYHW: + return "Operation could not be carried out because there is no overlay hardware present or available.\0"; + case DDERR_NOPALETTEATTACHED: + return "No palette object attached to this surface.\0"; + case DDERR_NOPALETTEHW: + return "No hardware support for 16 or 256 color palettes.\0"; + case DDERR_NORASTEROPHW: + return "Operation could not be carried out because there is no appropriate raster op hardware present or available.\0"; + case DDERR_NOROTATIONHW: + return "Operation could not be carried out because there is no rotation hardware present or available.\0"; + case DDERR_NOSTRETCHHW: + return "Operation could not be carried out because there is no hardware support for stretching.\0"; + case DDERR_NOT4BITCOLOR: + return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color palette.\0"; + case DDERR_NOT4BITCOLORINDEX: + return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color index palette.\0"; + case DDERR_NOT8BITCOLOR: + return "DirectDrawSurface is not in 8 bit color mode and the requested operation requires 8 bit color.\0"; + case DDERR_NOTAOVERLAYSURFACE: + return "Returned when an overlay member is called for a non-overlay surface.\0"; + case DDERR_NOTEXTUREHW: + return "Operation could not be carried out because there is no texture mapping hardware present or available.\0"; + case DDERR_NOTFLIPPABLE: + return "An attempt has been made to flip a surface that is not flippable.\0"; + case DDERR_NOTFOUND: + return "Requested item was not found.\0"; + case DDERR_NOTLOCKED: + return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this process, has been attempted.\0"; + case DDERR_NOTPALETTIZED: + return "The surface being used is not a palette-based surface.\0"; + case DDERR_NOVSYNCHW: + return "Operation could not be carried out because there is no hardware support for vertical blank synchronized operations.\0"; + case DDERR_NOZBUFFERHW: + return "Operation could not be carried out because there is no hardware support for zbuffer blitting.\0"; + case DDERR_NOZOVERLAYHW: + return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z layering of overlays.\0"; + case DDERR_OUTOFCAPS: + return "The hardware needed for the requested operation has already been allocated.\0"; + case DDERR_OUTOFMEMORY: + return "DirectDraw does not have enough memory to perform the operation.\0"; + case DDERR_OUTOFVIDEOMEMORY: + return "DirectDraw does not have enough video memory to perform the operation.\0"; + case DDERR_OVERLAYCANTCLIP: + return "The hardware does not support clipped overlays.\0"; + case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: + return "Can only have ony color key active at one time for overlays.\0"; + case DDERR_OVERLAYNOTVISIBLE: + return "Returned when GetOverlayPosition is called on a hidden overlay.\0"; + case DDERR_PALETTEBUSY: + return "Access to this palette is being refused because the palette is already locked by another thread.\0"; + case DDERR_PRIMARYSURFACEALREADYEXISTS: + return "This process already has created a primary surface.\0"; + case DDERR_REGIONTOOSMALL: + return "Region passed to Clipper::GetClipList is too small.\0"; + case DDERR_SURFACEALREADYATTACHED: + return "This surface is already attached to the surface it is being attached to.\0"; + case DDERR_SURFACEALREADYDEPENDENT: + return "This surface is already a dependency of the surface it is being made a dependency of.\0"; + case DDERR_SURFACEBUSY: + return "Access to this surface is being refused because the surface is already locked by another thread.\0"; + case DDERR_SURFACEISOBSCURED: + return "Access to surface refused because the surface is obscured.\0"; + case DDERR_SURFACELOST: + return "Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface object representing this surface should have Restore called on it.\0"; + case DDERR_SURFACENOTATTACHED: + return "The requested surface is not attached.\0"; + case DDERR_TOOBIGHEIGHT: + return "Height requested by DirectDraw is too large.\0"; + case DDERR_TOOBIGSIZE: + return "Size requested by DirectDraw is too large, but the individual height and width are OK.\0"; + case DDERR_TOOBIGWIDTH: + return "Width requested by DirectDraw is too large.\0"; + case DDERR_UNSUPPORTED: + return "Action not supported.\0"; + case DDERR_UNSUPPORTEDFORMAT: + return "FOURCC format requested is unsupported by DirectDraw.\0"; + case DDERR_UNSUPPORTEDMASK: + return "Bitmask in the pixel format requested is unsupported by DirectDraw.\0"; + case DDERR_VERTICALBLANKINPROGRESS: + return "Vertical blank is in progress.\0"; + case DDERR_WASSTILLDRAWING: + return "Informs DirectDraw that the previous Blt which is transfering information to or from this Surface is incomplete.\0"; + case DDERR_WRONGMODE: + return "This surface can not be restored because it was created in a different mode.\0"; + case DDERR_XALIGN: + return "Rectangle provided was not horizontally aligned on required boundary.\0"; + case D3DERR_BADMAJORVERSION: + return "D3DERR_BADMAJORVERSION\0"; + case D3DERR_BADMINORVERSION: + return "D3DERR_BADMINORVERSION\0"; + case D3DERR_EXECUTE_LOCKED: + return "D3DERR_EXECUTE_LOCKED\0"; + case D3DERR_EXECUTE_NOT_LOCKED: + return "D3DERR_EXECUTE_NOT_LOCKED\0"; + case D3DERR_EXECUTE_CREATE_FAILED: + return "D3DERR_EXECUTE_CREATE_FAILED\0"; + case D3DERR_EXECUTE_DESTROY_FAILED: + return "D3DERR_EXECUTE_DESTROY_FAILED\0"; + case D3DERR_EXECUTE_LOCK_FAILED: + return "D3DERR_EXECUTE_LOCK_FAILED\0"; + case D3DERR_EXECUTE_UNLOCK_FAILED: + return "D3DERR_EXECUTE_UNLOCK_FAILED\0"; + case D3DERR_EXECUTE_FAILED: + return "D3DERR_EXECUTE_FAILED\0"; + case D3DERR_EXECUTE_CLIPPED_FAILED: + return "D3DERR_EXECUTE_CLIPPED_FAILED\0"; + case D3DERR_TEXTURE_NO_SUPPORT: + return "D3DERR_TEXTURE_NO_SUPPORT\0"; + case D3DERR_TEXTURE_NOT_LOCKED: + return "D3DERR_TEXTURE_NOT_LOCKED\0"; + case D3DERR_TEXTURE_LOCKED: + return "D3DERR_TEXTURELOCKED\0"; + case D3DERR_TEXTURE_CREATE_FAILED: + return "D3DERR_TEXTURE_CREATE_FAILED\0"; + case D3DERR_TEXTURE_DESTROY_FAILED: + return "D3DERR_TEXTURE_DESTROY_FAILED\0"; + case D3DERR_TEXTURE_LOCK_FAILED: + return "D3DERR_TEXTURE_LOCK_FAILED\0"; + case D3DERR_TEXTURE_UNLOCK_FAILED: + return "D3DERR_TEXTURE_UNLOCK_FAILED\0"; + case D3DERR_TEXTURE_LOAD_FAILED: + return "D3DERR_TEXTURE_LOAD_FAILED\0"; + case D3DERR_MATRIX_CREATE_FAILED: + return "D3DERR_MATRIX_CREATE_FAILED\0"; + case D3DERR_MATRIX_DESTROY_FAILED: + return "D3DERR_MATRIX_DESTROY_FAILED\0"; + case D3DERR_MATRIX_SETDATA_FAILED: + return "D3DERR_MATRIX_SETDATA_FAILED\0"; + case D3DERR_SETVIEWPORTDATA_FAILED: + return "D3DERR_SETVIEWPORTDATA_FAILED\0"; + case D3DERR_MATERIAL_CREATE_FAILED: + return "D3DERR_MATERIAL_CREATE_FAILED\0"; + case D3DERR_MATERIAL_DESTROY_FAILED: + return "D3DERR_MATERIAL_DESTROY_FAILED\0"; + case D3DERR_MATERIAL_SETDATA_FAILED: + return "D3DERR_MATERIAL_SETDATA_FAILED\0"; + case D3DERR_LIGHT_SET_FAILED: + return "D3DERR_LIGHT_SET_FAILED\0"; + case D3DRMERR_BADOBJECT: + return "D3DRMERR_BADOBJECT\0"; + case D3DRMERR_BADTYPE: + return "D3DRMERR_BADTYPE\0"; + case D3DRMERR_BADALLOC: + return "D3DRMERR_BADALLOC\0"; + case D3DRMERR_FACEUSED: + return "D3DRMERR_FACEUSED\0"; + case D3DRMERR_NOTFOUND: + return "D3DRMERR_NOTFOUND\0"; + case D3DRMERR_NOTDONEYET: + return "D3DRMERR_NOTDONEYET\0"; + case D3DRMERR_FILENOTFOUND: + return "The file was not found.\0"; + case D3DRMERR_BADFILE: + return "D3DRMERR_BADFILE\0"; + case D3DRMERR_BADDEVICE: + return "D3DRMERR_BADDEVICE\0"; + case D3DRMERR_BADVALUE: + return "D3DRMERR_BADVALUE\0"; + case D3DRMERR_BADMAJORVERSION: + return "D3DRMERR_BADMAJORVERSION\0"; + case D3DRMERR_BADMINORVERSION: + return "D3DRMERR_BADMINORVERSION\0"; + case D3DRMERR_UNABLETOEXECUTE: + return "D3DRMERR_UNABLETOEXECUTE\0"; + default: + return "Unrecognized error value.\0"; + } +} + +#ifdef __WATCOMC__ + #define LOGFILE_NAME "dx_error.log" +#else + #define LOGFILE_NAME "dx_errorM.log" +#endif + +static LOGFILE * dxlog = 0; +static int closed_once = 0; + +void dx_err_log(HRESULT error, int line, char const * file) +{ + if (DD_OK==error) return; + if (closed_once) return; + + + if (!dxlog) dxlog = lfopen(LOGFILE_NAME); + + lfprintf(dxlog,"Line %d of %s:\n%s\n\n",line,file,D3DAppErrorToString(error)); +} + +void dx_str_log(char const * str, int line, char const * file) +{ + if (closed_once) return; + if (!dxlog) dxlog = lfopen(LOGFILE_NAME); + + lfprintf(dxlog,"Line %d of %s:\n%s\n\n",line,file,str); +} + +void dx_line_log(int line, char const * file) +{ + if (closed_once) return; + if (!dxlog) dxlog = lfopen(LOGFILE_NAME); + + lfprintf(dxlog,"Line %d of %s:\n",line,file); +} + +void dx_strf_log(char const * fmt, ... ) +{ + if (closed_once) return; + if (!dxlog) dxlog = lfopen(LOGFILE_NAME); + { + va_list ap; + va_start(ap, fmt); + vlfprintf(dxlog,fmt,ap); + va_end(ap); + } + lfputs(dxlog,"\n\n"); +} + +#undef exit +int GlobalAssertFired(char * Filename, int LineNum,char * Condition) +{ + extern void exit_break_point_fucntion (); + exit_break_point_fucntion(); + if (closed_once) return 0; + if (!dxlog) dxlog = lfopen(LOGFILE_NAME); + + lfprintf(dxlog,"Line %d of %s:\nGAF: %s\n",LineNum,Filename,Condition); + lfclose(dxlog); + closed_once = 1; + textprint("Line %d of %s:\nGAF: %s\n",LineNum,Filename,Condition); + WaitForReturn(); + + ExitSystem(); + exit(0xffff); +} + +int LocalAssertFired(char * Filename, int LineNum,char * Condition) +{ + extern void exit_break_point_fucntion (); + exit_break_point_fucntion(); + if (closed_once) return 0; + if (!dxlog) dxlog = lfopen(LOGFILE_NAME); + + lfprintf(dxlog,"Line %d of %s:\nLAF: %s\n",LineNum,Filename,Condition); + lfclose(dxlog); + closed_once = 1; + textprint("Line %d of %s:\nLAF: %s\n",LineNum,Filename,Condition); + WaitForReturn(); + + ExitSystem(); + exit(0xfffe); +} + + +void DXLOGHandleCompilerWarningMessage(void) +{ + int temp; + + temp = D3DRMMAP_PERSPCORRECT; + temp = D3DRMMAP_WRAPU; + temp = D3DRMMAP_WRAPV; + temp = D3DRMGROUP_ALLGROUPS; +} + +void ExitFired(char* Filename, int LineNum, int ExitCode) +{ + extern void exit_break_point_fucntion (); + exit_break_point_fucntion(); + if (closed_once) return ; + if (!dxlog) dxlog = lfopen(LOGFILE_NAME); + + lfprintf(dxlog,"Line %d of %s:\nExit: %x\n",LineNum,Filename,ExitCode); + lfclose(dxlog); + closed_once = 1; + + exit(ExitCode); +} +#endif diff --git a/3dc/win95/DXLOG.H b/3dc/win95/DXLOG.H new file mode 100644 index 0000000..d67b57c --- /dev/null +++ b/3dc/win95/DXLOG.H @@ -0,0 +1,37 @@ +#ifndef _included_dxlog_h_ +#define _included_dxlog_h_ + +#include "system.h" +#include "ddraw.h" +#include "d3d.h" +#include "d3drm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if debug + +void dx_err_log(HRESULT error, int line, char const * file); +void dx_str_log(char const * str, int line, char const * file); +void dx_line_log(int line, char const * file); +void dx_strf_log(char const * fmt, ...); + +#define LOGDXERR(error) dx_err_log(error,__LINE__,__FILE__) +#define LOGDXSTR(str) dx_str_log(str,__LINE__,__FILE__) +#define LOGDXFMT(args) (dx_line_log(__LINE__,__FILE__),dx_strf_log args) + +#else + +#define LOGDXERR(error) (void)0 +#define LOGDXSTR(str) (void)0 +#define LOGDXFMT(args) (void)0 + +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* ! _included_dxlog_h_ */ diff --git a/3dc/win95/Di_func.cpp b/3dc/win95/Di_func.cpp new file mode 100644 index 0000000..c29b4c1 --- /dev/null +++ b/3dc/win95/Di_func.cpp @@ -0,0 +1,1344 @@ +// Interface functions (written in C++) for +// Direct3D immediate mode system + +// Must link to C code in main engine system + +extern "C" { + +// Note: INITGUID has NOT been defined here, +// since the definition in d3_func.cpp is amply +// sufficient. + +#include "3dc.h" +#include "module.h" +#include "inline.h" +#include "stratdef.h" +#include "gamedef.h" +#include "gameplat.h" +#include "usr_io.h" +extern "C++"{ +#include "iofocus.h" +}; + +#include "showcmds.h" + +// DirectInput key down value +#define DikOn 0x80 + +// Internal DirectInput driver +// buffer Size for direct mouse read +#define DMouse_BufferSize 128 + +// Maximum number of buffered events retrievable +// from a mouse data acquisition +#define DMouse_RetrieveSize 128 + +/* + These are (hopefully) temporary #defines, + introduced as a hack because the curious + FIELD_OFFSET macros in the dinput.h header + don't appear to compile, at least in Watcom 10.6. + They will obviously have to be kept up to date + with changes in the DIMOUSESTATE structure manually. +*/ + +#define DIMouseXOffset 0 + +#define DIMouseYOffset 4 +#define DIMouseZOffset 8 + +#define DIMouseButton0Offset 12 + +#define DIMouseButton1Offset 13 + +#define DIMouseButton2Offset 14 + +#define DIMouseButton3Offset 15 + + +/* + Globals +*/ + + +static LPDIRECTINPUT lpdi; // DirectInput interface +static LPDIRECTINPUTDEVICE lpdiKeyboard; // keyboard device interface +static LPDIRECTINPUTDEVICE lpdiMouse; // mouse device interface +static BOOL DIKeyboardOkay; // Is the keyboard acquired? + +static IDirectInputDevice* g_pJoystick = NULL; +static IDirectInputDevice2* g_pJoystickDevice2 = NULL; // needed to poll joystick + + static char bGravePressed = No; + // added 14/1/98 by DHM as a temporary hack to debounce the GRAVE key + +/* + Externs for input communication +*/ + +extern HINSTANCE hInst; +extern HWND hWndMain; + +int GotMouse; +unsigned int MouseButton; +int MouseVelX; +int MouseVelY; +int MouseVelZ; +int MouseX; +int MouseY; +int MouseZ; + +extern unsigned char KeyboardInput[]; +extern unsigned char GotAnyKey; +static unsigned char LastGotAnyKey; +unsigned char DebouncedGotAnyKey; + +int GotJoystick; +JOYCAPS JoystickCaps; +JOYINFOEX JoystickData; +int JoystickEnabled; + +DIJOYSTATE JoystickState; // DirectInput joystick state + + +/* + 8/4/98 DHM: A new array, analagous to KeyboardInput, except it's debounced +*/ +extern "C" +{ + unsigned char DebouncedKeyboardInput[MAX_NUMBER_OF_INPUT_KEYS]; +} + +// Implementation of the debounced KeyboardInput +// There's probably a more efficient way of getting it direct from DirectInput +// but it's getting late and I can't face reading any more Microsoft documentation... +static unsigned char LastFramesKeyboardInput[MAX_NUMBER_OF_INPUT_KEYS]; + + +extern int NormalFrameTime; + +static char IngameKeyboardInput[256]; +extern IngameKeyboardInput_KeyDown(unsigned char key); +extern IngameKeyboardInput_KeyUp(unsigned char key); +extern IngameKeyboardInput_ClearBuffer(void); + +/* + + Create DirectInput via CoCreateInstance + +*/ + + +BOOL InitialiseDirectInput(void) + +{ + // try to create di object + if (DirectInputCreate(hInst, DIRECTINPUT_VERSION, &lpdi, NULL) != DI_OK) + { + #if debug + ReleaseDirect3D(); + exit(0x4111); + #else + return FALSE; + #endif + } + + return TRUE; +} + +/* + + Release DirectInput object + +*/ + + +void ReleaseDirectInput(void) + +{ + if (lpdi!= NULL) + { + lpdi->Release(); + lpdi = NULL; + } +} + + + + +// see comments below + +#define UseForegroundKeyboard No + +GUID guid = GUID_SysKeyboard; +BOOL InitialiseDirectKeyboard() + +{ + HRESULT hRes; + + // try to create keyboard device + if (lpdi->CreateDevice(guid, &lpdiKeyboard, NULL) !=DI_OK) + { + #if debug + ReleaseDirect3D(); + exit(0x4112); + #else + return FALSE; + #endif + } + + // Tell DirectInput that we want to receive data in keyboard format + if (lpdiKeyboard->SetDataFormat(&c_dfDIKeyboard) != DI_OK) + { + #if debug + ReleaseDirect3D(); + exit(0x4113); + #else + return FALSE; + #endif + } + + // set cooperative level + // this level is the most likely to work across + // multiple hardware targets + // (i.e. this is probably best for a production + // release) + #if UseForegroundKeyboard + if (lpdiKeyboard->SetCooperativeLevel(hWndMain, + DISCL_NONEXCLUSIVE | DISCL_FOREGROUND) != DI_OK) + #else + // this level makes alt-tabbing multiple instances in + // SunWindow mode possible without receiving lots + // of false inputs + if (lpdiKeyboard->SetCooperativeLevel(hWndMain, + DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) + #endif + { + #if debug + ReleaseDirect3D(); + exit(0x4114); + #else + return FALSE; + #endif + } + + // try to acquire the keyboard + hRes = lpdiKeyboard->Acquire(); + if (hRes == DI_OK) + { + // keyboard was acquired + DIKeyboardOkay = TRUE; + } + else + { + // keyboard was NOT acquired + DIKeyboardOkay = FALSE; + } + + // if we get here, all objects were created successfully + return TRUE; +} + + + +/* + + Use DirectInput to read keyboard + + PS: I know this function involves an + apparently unnecessary layer of translation + between one keyboard array and another one. + This is to allow people to swap from a windows + procedure keyboard handler to a DirectInput one + without having to change their IDemand functions. + + I can't think of a faster way to do the translation + below, but given that it only runs once per frame + it shouldn't be too bad. BUT NOTE THAT IT DOES + ONLY RUN ONCE PER FRAME (FROM READUSERINPUT) AND + SO YOU MUST HAVE A DECENT FRAME RATE IF KEYS ARE NOT + TO BE MISSED. + + NOTE ALSO THAT IF YOU ARE USING THIS SYSTEM YOU CAN + ACCESS THE KEYBOARD ARRAY IN A TIGHT LOOP WHILE CALLING + READUSERINPUT BUT -->NOT<-- CHECKWINDOWSMESSAGES (AS REQUIRED + FOR THE WINPROC HANDLER). BUT CHECKFORWINDOWSMESSAGES WON'T DO + ANY HARM. +*/ + +void DirectReadKeyboard(void) +{ + // Local array for map of all 256 characters on + // keyboard + BYTE DiKeybd[256]; + HRESULT hRes; + + // Get keyboard state + hRes = lpdiKeyboard->GetDeviceState(sizeof(DiKeybd), DiKeybd); + if (hRes != DI_OK) + { + if (hRes == DIERR_INPUTLOST) + { + // keyboard control lost; try to reacquire + DIKeyboardOkay = FALSE; + hRes = lpdiKeyboard->Acquire(); + if (hRes == DI_OK) + DIKeyboardOkay = TRUE; + } + } + + // Check for error values on routine exit + if (hRes != DI_OK) + { + // failed to read the keyboard + #if debug + ReleaseDirect3D(); + exit(0x999774); + #else + return; + #endif + } + + // Take a copy of last frame's inputs: + memcpy((void*)LastFramesKeyboardInput, (void*)KeyboardInput, MAX_NUMBER_OF_INPUT_KEYS); + LastGotAnyKey=GotAnyKey; + + // Zero current inputs (i.e. set all keys to FALSE, + // or not pressed) + memset((void*)KeyboardInput, FALSE, MAX_NUMBER_OF_INPUT_KEYS); + GotAnyKey = FALSE; + + #if 1 + { + int c; + + for (c='a'; c<='z'; c++) + { + if (IngameKeyboardInput[c]) + { + KeyboardInput[KEY_A + c - 'a'] = TRUE; + GotAnyKey = TRUE; + } + } + if (IngameKeyboardInput[246]) + { + KeyboardInput[KEY_O_UMLAUT] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[228]) + { + KeyboardInput[KEY_A_UMLAUT] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[252]) + { + KeyboardInput[KEY_U_UMLAUT] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[223]) + { + KeyboardInput[KEY_BETA] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput['+']) + { + KeyboardInput[KEY_PLUS] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput['#']) + { + KeyboardInput[KEY_HASH] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[161]) + { + KeyboardInput[KEY_UPSIDEDOWNEXCLAMATION] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[231]) + { + KeyboardInput[KEY_C_CEDILLA] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[241]) + { + KeyboardInput[KEY_N_TILDE] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[')']) + { + KeyboardInput[KEY_RIGHTBRACKET] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput['*']) + { + KeyboardInput[KEY_ASTERISK] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput['$']) + { + KeyboardInput[KEY_DOLLAR] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[249]) + { + KeyboardInput[KEY_U_GRAVE] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput['!']) + { + KeyboardInput[KEY_EXCLAMATION] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[':']) + { + KeyboardInput[KEY_COLON] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[96]) + { + KeyboardInput[KEY_DIACRITIC_GRAVE] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[180]) + { + KeyboardInput[KEY_DIACRITIC_ACUTE] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[94]) + { + KeyboardInput[KEY_DIACRITIC_CARET] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[168]) + { + KeyboardInput[KEY_DIACRITIC_UMLAUT] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput['<']) + { + KeyboardInput[KEY_LESSTHAN] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[176]) + { + KeyboardInput[KEY_ORDINAL] = TRUE; + GotAnyKey = TRUE; + } + + + if (IngameKeyboardInput['[']) + { + KeyboardInput[KEY_LBRACKET] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[']']) + { + KeyboardInput[KEY_RBRACKET] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[';']) + { + KeyboardInput[KEY_SEMICOLON] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput['\'']) + { + KeyboardInput[KEY_APOSTROPHE] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput['\\']) + { + KeyboardInput[KEY_BACKSLASH] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput['/']) + { + KeyboardInput[KEY_SLASH] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput['-']) + { + KeyboardInput[KEY_MINUS] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput['=']) + { + KeyboardInput[KEY_EQUALS] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput[',']) + { + KeyboardInput[KEY_COMMA] = TRUE; + GotAnyKey = TRUE; + } + if (IngameKeyboardInput['.']) + { + KeyboardInput[KEY_FSTOP] = TRUE; + GotAnyKey = TRUE; + } + + } + + #endif + + // Check and set keyboard array + // (test checks only for the moment) + if (DiKeybd[DIK_LEFT] & DikOn) + { + KeyboardInput[KEY_LEFT] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_RIGHT] & DikOn) + { + KeyboardInput[KEY_RIGHT] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_UP] & DikOn) + { + KeyboardInput[KEY_UP] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_DOWN] & DikOn) + { + KeyboardInput[KEY_DOWN] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_ESCAPE] & DikOn) + { + KeyboardInput[KEY_ESCAPE] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_RETURN] & DikOn) + { + KeyboardInput[KEY_CR] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_TAB] & DikOn) + { + KeyboardInput[KEY_TAB] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_F1] & DikOn) + { + KeyboardInput[KEY_F1] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_F2] & DikOn) + { + KeyboardInput[KEY_F2] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_F3] & DikOn) + { + KeyboardInput[KEY_F3] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_F4] & DikOn) + { + KeyboardInput[KEY_F4] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_F5] & DikOn) + { + KeyboardInput[KEY_F5] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_F6] & DikOn) + { + KeyboardInput[KEY_F6] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_F7] & DikOn) + { + KeyboardInput[KEY_F7] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_F8] & DikOn) + { + KeyboardInput[KEY_F8] = TRUE; +/* KJL 14:51:38 21/04/98 - F8 does screen shots, and so this is a hack +to make F8 not count in a 'press any key' situation */ +// GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_F9] & DikOn) + { + KeyboardInput[KEY_F9] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_F10] & DikOn) + { + KeyboardInput[KEY_F10] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_F11] & DikOn) + { + KeyboardInput[KEY_F11] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_F12] & DikOn) + { + KeyboardInput[KEY_F12] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_INSERT] & DikOn) + { + KeyboardInput[KEY_INS] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_DELETE] & DikOn) + { + KeyboardInput[KEY_DEL] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_END] & DikOn) + { + KeyboardInput[KEY_END] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_HOME] & DikOn) + { + KeyboardInput[KEY_HOME] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_PRIOR] & DikOn) + { + KeyboardInput[KEY_PAGEUP] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_NEXT] & DikOn) + { + KeyboardInput[KEY_PAGEDOWN] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_BACK] & DikOn) + { + KeyboardInput[KEY_BACKSPACE] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_SPACE] & DikOn) + { + KeyboardInput[KEY_SPACE] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_LSHIFT] & DikOn) + { + KeyboardInput[KEY_LEFTSHIFT] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_RSHIFT] & DikOn) + { + KeyboardInput[KEY_RIGHTSHIFT] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_LCONTROL] & DikOn) + { + KeyboardInput[KEY_LEFTCTRL] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_RCONTROL] & DikOn) + { + KeyboardInput[KEY_RIGHTCTRL] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_CAPSLOCK] & DikOn) + { + KeyboardInput[KEY_CAPS] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_NUMLOCK] & DikOn) + { + KeyboardInput[KEY_NUMLOCK] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_SCROLL] & DikOn) + { + KeyboardInput[KEY_SCROLLOK] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_LMENU] & DikOn) + { + KeyboardInput[KEY_LEFTALT] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_RMENU] & DikOn) + { + KeyboardInput[KEY_RIGHTALT] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_0] & DikOn) + { + KeyboardInput[KEY_0] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_1] & DikOn) + { + KeyboardInput[KEY_1] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_2] & DikOn) + { + KeyboardInput[KEY_2] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_3] & DikOn) + { + KeyboardInput[KEY_3] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_4] & DikOn) + { + KeyboardInput[KEY_4] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_5] & DikOn) + { + KeyboardInput[KEY_5] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_6] & DikOn) + { + KeyboardInput[KEY_6] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_7] & DikOn) + { + KeyboardInput[KEY_7] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_8] & DikOn) + { + KeyboardInput[KEY_8] = TRUE; + GotAnyKey = TRUE; + } + + if (DiKeybd[DIK_9] & DikOn) + { + KeyboardInput[KEY_9] = TRUE; + GotAnyKey = TRUE; + } + + + /* KJL 16:12:19 05/11/97 - numeric pad follows */ + if (DiKeybd[DIK_NUMPAD7] & DikOn) + { + KeyboardInput[KEY_NUMPAD7] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_NUMPAD8] & DikOn) + { + KeyboardInput[KEY_NUMPAD8] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_NUMPAD9] & DikOn) + { + KeyboardInput[KEY_NUMPAD9] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_SUBTRACT] & DikOn) + { + KeyboardInput[KEY_NUMPADSUB] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_NUMPAD4] & DikOn) + { + KeyboardInput[KEY_NUMPAD4] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_NUMPAD5] & DikOn) + { + KeyboardInput[KEY_NUMPAD5] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_NUMPAD6] & DikOn) + { + KeyboardInput[KEY_NUMPAD6] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_ADD] & DikOn) + { + KeyboardInput[KEY_NUMPADADD] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_NUMPAD1] & DikOn) + { + KeyboardInput[KEY_NUMPAD1] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_NUMPAD2] & DikOn) + { + KeyboardInput[KEY_NUMPAD2] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_NUMPAD3] & DikOn) + { + KeyboardInput[KEY_NUMPAD3] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_NUMPAD0] & DikOn) + { + KeyboardInput[KEY_NUMPAD0] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_DECIMAL] & DikOn) + { + KeyboardInput[KEY_NUMPADDEL] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_NUMPADENTER] & DikOn) + { + KeyboardInput[KEY_NUMPADENTER] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_DIVIDE] & DikOn) + { + KeyboardInput[KEY_NUMPADDIVIDE] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_MULTIPLY] & DikOn) + { + KeyboardInput[KEY_NUMPADMULTIPLY] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_CAPITAL] & DikOn) + { + KeyboardInput[KEY_CAPITAL] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_LWIN] & DikOn) + { + KeyboardInput[KEY_LWIN] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_RWIN] & DikOn) + { + KeyboardInput[KEY_RWIN] = TRUE; + GotAnyKey = TRUE; + } + if (DiKeybd[DIK_APPS] & DikOn) + { + KeyboardInput[KEY_APPS] = TRUE; + GotAnyKey = TRUE; + } + + + #if 0 + // Added 14/1/98 by DHM: Process the grave key (known to some as the tilde key) + // Done this way as a bit of a hack to avoid touching PLATFORM.H + // which would force big recompiles + if (DiKeybd[DIK_GRAVE] & DikOn) + { + if ( !bGravePressed ) + { + IOFOCUS_Toggle(); + } + + bGravePressed = Yes; + + GotAnyKey = TRUE; + } + else + { + bGravePressed = No; + } + #else + if (DiKeybd[DIK_GRAVE] & DikOn) + { + KeyboardInput[KEY_GRAVE] = TRUE; + } + #endif + + /* mouse keys */ + if (MouseButton & LeftButton) + { + KeyboardInput[KEY_LMOUSE] = TRUE; + GotAnyKey = TRUE; + } + if (MouseButton & MiddleButton) + { + KeyboardInput[KEY_MMOUSE] = TRUE; + GotAnyKey = TRUE; + } + if (MouseButton & RightButton) + { + KeyboardInput[KEY_RMOUSE] = TRUE; + GotAnyKey = TRUE; + } + + /* mouse wheel - read using windows messages */ + { + extern signed int MouseWheelStatus; + if (MouseWheelStatus>0) + { + KeyboardInput[KEY_MOUSEWHEELUP] = TRUE; + GotAnyKey = TRUE; + } + else if (MouseWheelStatus<0) + { + KeyboardInput[KEY_MOUSEWHEELDOWN] = TRUE; + GotAnyKey = TRUE; + } + } + + + /* joystick buttons */ + if (GotJoystick) + { + unsigned int n,bit; + + for (n=0,bit=1; n<16; n++,bit*=2) + { + if(JoystickData.dwButtons&bit) + { + KeyboardInput[KEY_JOYSTICK_BUTTON_1+n]=TRUE; + GotAnyKey = TRUE; + } + } + + } + + + /* update debounced keys array */ + { + for (int i=0;iUnacquire(); + DIKeyboardOkay = FALSE; + } + + if (lpdiKeyboard != NULL) + { + lpdiKeyboard->Release(); + lpdiKeyboard = NULL; + } +} + + +BOOL InitialiseDirectMouse() + +{ + GUID guid = GUID_SysMouse; + HRESULT hres; + + //MouseButton = 0; + + // Obtain an interface to the system mouse device. + hres = lpdi->CreateDevice(guid, &lpdiMouse, NULL); + if (hres != DI_OK) return FALSE; + + // Set the data format to "mouse format". + hres = lpdiMouse->SetDataFormat(&c_dfDIMouse); + if (hres != DI_OK) return FALSE; + + // Set the cooperativity level. + + #if debug + // This level should allow the debugger to actually work + // not to mention drop 'n' drag in sub-window mode + hres = lpdiMouse->SetCooperativeLevel(hWndMain, + DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); + #else + // this level is the most likely to work across + // multiple mouse drivers + hres = lpdiMouse->SetCooperativeLevel(hWndMain, + DISCL_EXCLUSIVE | DISCL_FOREGROUND); + #endif + if (hres != DI_OK) return FALSE; + + // Set the buffer size for reading the mouse to + // DMouse_BufferSize elements + // mouse-type should be relative by default, so there + // is no need to change axis mode. + DIPROPDWORD dipdw = + { + { + sizeof(DIPROPDWORD), // diph.dwSize + sizeof(DIPROPHEADER), // diph.dwHeaderSize + 0, // diph.dwObj + DIPH_DEVICE, // diph.dwHow + }, + DMouse_BufferSize, // dwData + }; + + hres = lpdiMouse->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph); + + if (hres != DI_OK) return FALSE; + + // try to acquire the mouse + hres = lpdiMouse->Acquire(); + + return TRUE; +} + +void DirectReadMouse(void) +{ + DIDEVICEOBJECTDATA od[DMouse_RetrieveSize]; + DWORD dwElements = DMouse_RetrieveSize; + HRESULT hres; + int OldMouseX, OldMouseY, OldMouseZ; + + GotMouse = No; + MouseVelX = 0; + MouseVelY = 0; + MouseVelZ = 0; + + hres = lpdiMouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),&od[0],&dwElements, 0); + + + if (hres == DIERR_INPUTLOST || hres==DIERR_NOTACQUIRED) + { + // We had acquisition, but lost it. Try to reacquire it. + hres = lpdiMouse->Acquire(); + // No data this time + return; + } + + // Unable to read data + if (hres != DI_OK) return; + + // Check for any data being picked up + GotMouse = Yes; + if (dwElements == 0) return; + + // Save mouse x and y for velocity determination + OldMouseX = MouseX; + OldMouseY = MouseY; + OldMouseZ = MouseZ; + + // Process all recovered elements and + // make appropriate modifications to mouse + // status variables. + + int i; + + for (i=0; iRelease(); + lpdiMouse = NULL; + } +} + + + +/*KJL**************************************************************** +* * +* JOYSTICK SUPPORT - I've moved all joystick support to here. * +* * +****************************************************************KJL*/ + + +/* KJL 11:32:46 04/30/97 - + + Okay, this has been changed for the sake of AvP. I know that this + isn't in AvP\win95\..., but moving this file probably isn't worth + the trouble. + + This code is designed to read only one joystick. + +*/ + + +/* + Decide which (if any) joysticks + exist, access capabilities, + initialise internal variables. +*/ +#if 1 +void InitJoysticks(void) +{ + JoystickData.dwFlags = (JOY_RETURNALL | JOY_RETURNCENTERED | JOY_USEDEADZONE); + JoystickData.dwSize = sizeof(JoystickData); + + GotJoystick = CheckForJoystick(); +} + +void ReadJoysticks(void) +{ + GotJoystick = ReadJoystick(); +} + +int ReadJoystick(void) +{ + MMRESULT joyreturn; + + if(!JoystickControlMethods.JoystickEnabled) return No; + + joyreturn = joyGetPosEx(JOYSTICKID1,&JoystickData); + + if (joyreturn == JOYERR_NOERROR) return Yes; + + return No; +} + +int CheckForJoystick(void) +{ + MMRESULT joyreturn; + + joyreturn = joyGetDevCaps(JOYSTICKID1, + &JoystickCaps, + sizeof(JOYCAPS)); + + if (joyreturn == JOYERR_NOERROR) return Yes; + + return No; +} +#else +// Eleventh hour rewrite of joystick code, to support PantherXL trackerball. +// Typical. KJL, 99/5/1 +BOOL CALLBACK EnumJoysticksCallback( LPCDIDEVICEINSTANCE pInst, LPVOID lpvContext ); + + +void InitJoysticks(void) +{ + HRESULT hr; + GotJoystick = No; + g_pJoystick = NULL; + + hr = lpdi->EnumDevices(DIDEVTYPE_JOYSTICK, EnumJoysticksCallback, NULL, DIEDFL_ATTACHEDONLY); + if ( FAILED(hr) ) return; + + hr = g_pJoystick->SetDataFormat( &c_dfDIJoystick ); + if ( FAILED(hr) ) return; + + hr = g_pJoystick->SetCooperativeLevel( hWndMain, DISCL_EXCLUSIVE | DISCL_FOREGROUND); + if ( FAILED(hr) ) return; + + GotJoystick = Yes; +} + +void ReadJoysticks(void) +{ + + GotJoystick = No; + + if(!JoystickControlMethods.JoystickEnabled || g_pJoystick==NULL) + { + return; + } + + HRESULT hr = DIERR_INPUTLOST; + + // if input is lost then acquire and keep trying + while ( DIERR_INPUTLOST == hr ) + { + // poll the joystick to read the current state + hr = g_pJoystickDevice2->Poll(); + if ( FAILED(hr) ) return; + + // get the input's device state, and put the state in dims + hr = g_pJoystick->GetDeviceState( sizeof(DIJOYSTATE), &JoystickState ); + + if ( hr == DIERR_INPUTLOST ) + { + // DirectInput is telling us that the input stream has + // been interrupted. We aren't tracking any state + // between polls, so we don't have any special reset + // that needs to be done. We just re-acquire and + // try again. + hr = g_pJoystick->Acquire(); + if ( FAILED(hr) ) return; + } + } + + if ( FAILED(hr) ) return; + + GotJoystick = Yes; + PrintDebuggingText("%d %d\n",JoystickState.rglSlider[0],JoystickState.rglSlider[1]); + +} +//----------------------------------------------------------------------------- +// Function: EnumJoysticksCallback +// +// Description: +// Called once for each enumerated joystick. If we find one, +// create a device interface on it so we can play with it. +// +//----------------------------------------------------------------------------- +BOOL CALLBACK EnumJoysticksCallback( LPCDIDEVICEINSTANCE pInst, + LPVOID lpvContext ) +{ + HRESULT hr; + LPDIRECTINPUTDEVICE pDevice; + + // obtain an interface to the enumerated force feedback joystick. + hr = lpdi->CreateDevice( pInst->guidInstance, &pDevice, NULL ); + + // if it failed, then we can't use this joystick for some + // bizarre reason. (Maybe the user unplugged it while we + // were in the middle of enumerating it.) So continue enumerating + if ( FAILED(hr) ) + return DIENUM_CONTINUE; + + // we successfully created an IDirectInputDevice. So stop looking + // for another one. + g_pJoystick = pDevice; + + // query for IDirectInputDevice2 - we need this to poll the joystick + pDevice->QueryInterface( IID_IDirectInputDevice2, (LPVOID *)&g_pJoystickDevice2 ); + + return DIENUM_STOP; +} +#endif + + +extern IngameKeyboardInput_KeyDown(unsigned char key) +{ + IngameKeyboardInput[key] = 1; +} + +extern IngameKeyboardInput_KeyUp(unsigned char key) +{ + IngameKeyboardInput[key] = 0; +} + +extern IngameKeyboardInput_ClearBuffer(void) +{ + int i; + + for (i=0; i<=255; i++) + { + IngameKeyboardInput[i] = 0; + } +} + +// For extern "C" +}; + + + diff --git a/3dc/win95/DummyObjectChunk.cpp b/3dc/win95/DummyObjectChunk.cpp new file mode 100644 index 0000000..7fa86c9 --- /dev/null +++ b/3dc/win95/DummyObjectChunk.cpp @@ -0,0 +1,181 @@ +#include "DummyObjectChunk.hpp" + +#ifdef cencon +#define new my_new +#endif + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(dummyobjectchunk) + + +RIF_IMPLEMENT_DYNCREATE("DUMMYOBJ",Dummy_Object_Chunk) + +CHUNK_WITH_CHILDREN_LOADER("DUMMYOBJ",Dummy_Object_Chunk) +/* +Children for Dummy_Object_Chunk : + +"DUMOBJDT" Dummy_Object_Data_Chunk +"DUMOBJTX" Dummy_Object_Text_Chunk +*/ + + + +Dummy_Object_Chunk::Dummy_Object_Chunk(Chunk_With_Children* parent,const char* _name,ChunkVectorInt& _location,ChunkVectorInt& min ,ChunkVectorInt& max ,ChunkQuat& orient) +:Chunk_With_Children(parent,"DUMMYOBJ") +{ + new Dummy_Object_Data_Chunk(this,_name,_location,min,max,orient); +} + +Dummy_Object_Data_Chunk* Dummy_Object_Chunk::get_data_chunk() +{ + return (Dummy_Object_Data_Chunk*) lookup_single_child("DUMOBJDT"); +} + + +const char* Dummy_Object_Chunk::get_text() +{ + //find the text + Dummy_Object_Text_Chunk* text_chunk = (Dummy_Object_Text_Chunk*) lookup_single_child("DUMOBJTX"); + if(!text_chunk) + { + //no text + return NULL; + } + + return text_chunk->get_text(); +} + +void Dummy_Object_Chunk::set_text(const char* text) +{ + //find the text chunk + Dummy_Object_Text_Chunk* text_chunk = (Dummy_Object_Text_Chunk*) lookup_single_child("DUMOBJTX"); + + if(!text || strlen(text)==0) + { + //delete the text chunk if it exists + delete text_chunk; + } + else + { + if(text_chunk) + { + //alter the existing text + text_chunk->set_text(text); + } + else + { + //create a new text chunk + new Dummy_Object_Text_Chunk(this,text); + } + } +} + + +//////////////////////////////Dummy_Object_Data_Chunk//////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("DUMOBJDT",Dummy_Object_Data_Chunk) + +Dummy_Object_Data_Chunk::Dummy_Object_Data_Chunk(Dummy_Object_Chunk* parent,const char* _name ,ChunkVectorInt& _location,ChunkVectorInt& min ,ChunkVectorInt& max ,ChunkQuat& orient) +:Chunk(parent,"DUMOBJDT") +{ + location=_location; + min_extents=min; + max_extents=max; + orientation=orient; + + name=new char[strlen(_name)+1]; + strcpy(name,_name); +} + + +Dummy_Object_Data_Chunk::Dummy_Object_Data_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk(parent,"DUMOBJDT") +{ + CHUNK_EXTRACT(location,ChunkVectorInt) + CHUNK_EXTRACT(min_extents,ChunkVectorInt) + CHUNK_EXTRACT(max_extents,ChunkVectorInt) + CHUNK_EXTRACT(orientation,ChunkQuat) + CHUNK_EXTRACT_STRING(name) +} + + +Dummy_Object_Data_Chunk::~Dummy_Object_Data_Chunk() +{ + if(name) delete [] name; +} + + +void Dummy_Object_Data_Chunk::fill_data_block(char* data) +{ + CHUNK_FILL_START + + CHUNK_FILL(location,ChunkVectorInt) + CHUNK_FILL(min_extents,ChunkVectorInt) + CHUNK_FILL(max_extents,ChunkVectorInt) + CHUNK_FILL(orientation,ChunkQuat) + CHUNK_FILL_STRING(name) + +} + + +size_t Dummy_Object_Data_Chunk::size_chunk() +{ + chunk_size=12+3*sizeof(ChunkVectorInt)+sizeof(ChunkQuat); + chunk_size+=(strlen(name)+4)&~3; + return chunk_size; +} + +///////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////Dummy_Object_Text_Chunk//////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("DUMOBJTX",Dummy_Object_Text_Chunk) + +Dummy_Object_Text_Chunk::Dummy_Object_Text_Chunk(Dummy_Object_Chunk* parent,const char* _text) +:Chunk(parent,"DUMOBJTX"),text(NULL) +{ + set_text(_text); +} + +Dummy_Object_Text_Chunk::Dummy_Object_Text_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk(parent,"DUMOBJTX") +{ + CHUNK_EXTRACT_STRING(text) +} + + +Dummy_Object_Text_Chunk::~Dummy_Object_Text_Chunk() +{ + delete [] text; +} + +void Dummy_Object_Text_Chunk::fill_data_block(char* data) +{ + CHUNK_FILL_START + + CHUNK_FILL_STRING(text) +} + +void Dummy_Object_Text_Chunk::set_text(const char* _text) +{ + char* new_text = NULL; + if(_text) + { + new_text = new char[strlen(_text)+1]; + strcpy(new_text,_text); + } + + delete [] text; + text = new_text; + +} + + +size_t Dummy_Object_Text_Chunk::size_chunk() +{ + chunk_size=12; + if(text) + chunk_size+=(strlen(text)+4)&~3; + else + chunk_size+=4; + return chunk_size; +} diff --git a/3dc/win95/DummyObjectChunk.hpp b/3dc/win95/DummyObjectChunk.hpp new file mode 100644 index 0000000..adb3a93 --- /dev/null +++ b/3dc/win95/DummyObjectChunk.hpp @@ -0,0 +1,81 @@ + +#ifndef _DummyObjectChunk_hpp +#define _DummyObjectChunk_hpp 1 + +#include "chunk.hpp" +#include "list_tem.hpp" +#include "chnktype.hpp" + +class Dummy_Object_Data_Chunk; + +class Dummy_Object_Chunk : public Chunk_With_Children +{ +public: + + Dummy_Object_Chunk(Chunk_With_Children* parent,const char* _name ,ChunkVectorInt& _location,ChunkVectorInt& min ,ChunkVectorInt& max ,ChunkQuat& orient); + + // constructor from buffer + Dummy_Object_Chunk (Chunk_With_Children * const parent,const char *, size_t const); + + Dummy_Object_Data_Chunk * get_data_chunk();//gets data chunk (name and location) + + const char* get_text(); //get text attached to a dummy object + void set_text(const char* text); //change the text attached to a dummy object + +}; + +//chunk containing name and location of dummy object +class Dummy_Object_Data_Chunk : public Chunk +{ +public : + Dummy_Object_Data_Chunk(Dummy_Object_Chunk* parent,const char* _name ,ChunkVectorInt& _location,ChunkVectorInt& min ,ChunkVectorInt& max ,ChunkQuat& orient); + Dummy_Object_Data_Chunk (Chunk_With_Children * parent, const char * data, size_t ); + ~Dummy_Object_Data_Chunk(); + + +/*------------------------** +** Main dummy object data ** +**------------------------*/ + char* name; + + ChunkVectorInt location; + ChunkQuat orientation; + + ChunkVectorInt min_extents; + ChunkVectorInt max_extents; +/*------------------------** +** Main dummy object data ** +**------------------------*/ + + size_t size_chunk(); + void fill_data_block (char * data); + +private : + + friend class Dummy_Object_Chunk; + +}; + + +//contains the 'user text' from 3dsmax +class Dummy_Object_Text_Chunk : public Chunk +{ +public : + Dummy_Object_Text_Chunk(Dummy_Object_Chunk* parent,const char* _text); + Dummy_Object_Text_Chunk(Chunk_With_Children * parent, const char * data, size_t ); + ~Dummy_Object_Text_Chunk(); + + size_t size_chunk(); + void fill_data_block (char * data); + + + const char* get_text() {return text;} + void set_text(const char* _text); + +private : + char* text; + +}; + + +#endif \ No newline at end of file diff --git a/3dc/win95/ENUMCHNK.CPP b/3dc/win95/ENUMCHNK.CPP new file mode 100644 index 0000000..6b6a3e7 --- /dev/null +++ b/3dc/win95/ENUMCHNK.CPP @@ -0,0 +1,131 @@ +#include "enumchnk.hpp" +//#include "enumsch.hpp" + +#ifdef cencon +#define new my_new +#endif + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(enumchnk) + +// Class Enum_Chunk functions + +RIF_IMPLEMENT_DYNCREATE("REBENUMS",Enum_Chunk) +// constructor from buffer +LOCKABLE_CHUNK_WITH_CHILDREN_LOADER("REBENUMS",Enum_Chunk) +/* +Children for Enum_Chunk : + +"ENUMHEAD" Enum_Header_Chunk +"BMPENUMS" BMP_Enums_Chunk +*/ + + + +// empty constructor +Enum_Chunk::Enum_Chunk (Chunk_With_Children * parent) +:Lockable_Chunk_With_Children (parent, "REBENUMS") +{ + // as necessary, generated automatically + new Enum_Header_Chunk (this); +} + + +BOOL Enum_Chunk::file_equals (HANDLE & /*rif_file*/) +{ + return(TRUE); +} + +Enum_Header_Chunk * Enum_Chunk::get_header() +{ + + return (Enum_Header_Chunk *) this->lookup_single_child ("ENUMHEAD"); +} + +const char * Enum_Chunk::get_head_id() +{ + Enum_Header_Chunk * hdptr = get_header(); + + if (!hdptr) return (0); + + return(hdptr->identifier); + +} + +void Enum_Chunk::set_lock_user (char * user) +{ + Enum_Header_Chunk * hdptr = get_header(); + + if (!hdptr) return; + + strncpy (hdptr->lock_user, user,16); + + hdptr->lock_user[16] = 0; +} + +void Enum_Chunk::post_input_processing() +{ + if (get_header()) + if (get_header()->flags & GENERAL_FLAG_LOCKED) + external_lock = TRUE; + + Chunk_With_Children::post_input_processing(); + +} + +/////////////////////////////////////// + +// Class Enum_Header_Chunk functions +RIF_IMPLEMENT_DYNCREATE("ENUMHEAD",Enum_Header_Chunk) + +// from buffer +Enum_Header_Chunk::Enum_Header_Chunk (Chunk_With_Children * parent, const char * hdata, size_t /*hsize*/) + : Chunk (parent, "ENUMHEAD"), + flags (0), version_no (0) +{ + flags = *((int *) hdata); + + strncpy (lock_user, (hdata + 4), 16); + lock_user[16] = '\0'; + + version_no = *((int *) (hdata + 20)); +} + +BOOL Enum_Header_Chunk::output_chunk (HANDLE & hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = make_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; +} + +void Enum_Header_Chunk::fill_data_block ( char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = flags; + strncpy ((data_start + 4), lock_user, 16); + + *((int *) (data_start+20)) = version_no; +} + +void Enum_Header_Chunk::prepare_for_output() +{ + version_no ++; +} + diff --git a/3dc/win95/ENUMCHNK.HPP b/3dc/win95/ENUMCHNK.HPP new file mode 100644 index 0000000..a29bf16 --- /dev/null +++ b/3dc/win95/ENUMCHNK.HPP @@ -0,0 +1,82 @@ +#ifndef _included_enumchnk_hpp_ +#define _included_enumchnk_hpp_ + +#include "chunk.hpp" +#include "mishchnk.hpp" + +class Enum_Header_Chunk; + +class Enum_Chunk : public Lockable_Chunk_With_Children +{ +public: + + // empty constructor + Enum_Chunk (Chunk_With_Children * parent); + + // constructor from buffer + Enum_Chunk (Chunk_With_Children * const parent,const char *, size_t const); + + Enum_Header_Chunk * get_header(); + + // functions for the locking functionality + + BOOL file_equals (HANDLE &); + const char * get_head_id(); + void set_lock_user(char *); + + void post_input_processing(); + +private: + + friend class File_Chunk; + friend class GodFather_Chunk; + + + + +}; + +/////////////////////////////////////////////// + +class Enum_Header_Chunk : public Chunk +{ +public: + // constructor from buffer + Enum_Header_Chunk (Chunk_With_Children * parent, const char * pdata, size_t psize); + + virtual size_t size_chunk () + { + chunk_size = 36; + return chunk_size; + } + + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start); + + void prepare_for_output(); + +private: + + friend class Enum_Chunk; + friend class File_Chunk; + + int flags; + + int version_no; + + char lock_user[17]; + + + // constructor from parent + Enum_Header_Chunk (Enum_Chunk * parent) + : Chunk (parent, "ENUMHEAD"), + flags (0), version_no (0) + {} + +}; + + + + +#endif // _included_enumchnk_hpp_ \ No newline at end of file diff --git a/3dc/win95/ENUMSCH.CPP b/3dc/win95/ENUMSCH.CPP new file mode 100644 index 0000000..0138cab --- /dev/null +++ b/3dc/win95/ENUMSCH.CPP @@ -0,0 +1,163 @@ +#include + +#include "enumsch.hpp" + +#ifdef cencon +#define new my_new +#endif + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(enumsch) + +Enum_Constant::Enum_Constant(char const * const _cname, int const _value) : cname(0), value(_value), reserved(0) +{ + if (_cname) + { + cname = new char[strlen(_cname)+1]; + strcpy(cname,_cname); + } +} + +Enum_Constant::Enum_Constant(Enum_Constant const & ec2) : reserved(ec2.reserved), value(ec2.value), cname(0) +{ + if (ec2.cname) + { + cname = new char[strlen(ec2.cname)+1]; + strcpy(cname,ec2.cname); + } +} + +Enum_Constant & Enum_Constant::operator = (Enum_Constant const & ec2) +{ + if (cname) delete[] cname; + cname = 0; + value = ec2.value; + reserved = ec2.reserved; + if (ec2.cname) + { + cname = new char[strlen(ec2.cname)+1]; + strcpy(cname,ec2.cname); + } + + return *this; +} + +BOOL Enum_Constant::operator == (Enum_Constant const & ec2) const +{ + if (cname && ec2.cname) + if (!strcmp(cname,ec2.cname)) return TRUE; + return FALSE; +} + +BOOL Enum_Constant::operator != (Enum_Constant const & ec2) const +{ + if (cname && ec2.cname) + if (!strcmp(cname,ec2.cname)) return FALSE; + return TRUE; +} + +BOOL Enum_Constant::operator < (Enum_Constant const & ec2) const +{ + if (cname && ec2.cname) + if (strcmp(cname,ec2.cname)<0) return TRUE; + return FALSE; +} + + +Enum_Constant::Enum_Constant(char const * sdata) +: value(*(int *)sdata), reserved(*(int *)(sdata+4)), cname(0) +{ + sdata+=8; + if (*sdata) + { + cname = new char[strlen(sdata)+1]; + strcpy(cname,sdata); + } +} + +size_t Enum_Constant::size_chunk() const +{ + return 8 + ((cname ? strlen(cname)+1 : 1) +3 &~3); +} + +void Enum_Constant::fill_data_block (char * data_start) +{ + *(int*)data_start = value; + *(int*)(data_start+4) = reserved; + + data_start += 8; + + strcpy(data_start,cname ? cname : ""); +} + + +/////// +RIF_IMPLEMENT_DYNCREATE("BMPENUMS",BMP_Enums_Chunk) + +BMP_Enums_Chunk::BMP_Enums_Chunk(Chunk_With_Children * const parent, char const * sdata, size_t const /*ssize*/) +: Chunk(parent,"BMPENUMS") +, reserved1(*(int *)sdata) +, reserved2(*(int *)(sdata+4)) +, ctype(0) +{ + sdata+=8; + unsigned int const len = strlen(sdata)+1; + + if (len>1) + { + ctype = new char[len]; + strcpy(ctype,sdata); + } + + sdata += len + 3 &~3; + + unsigned int const enlistsize = *(int *)sdata; + sdata += 4; + + for (unsigned int i = enlistsize; i; --i) + { + Enum_Constant current(sdata); + sdata += current.size_chunk(); + enums.add_entry(current); + } +} + +size_t BMP_Enums_Chunk::size_chunk () +{ + chunk_size = 12 + 8 + (ctype ? strlen(ctype)+1 : 1) + 4 +3 &~3; + + for (LIF li(&enums); !li.done(); li.next()) + { + chunk_size += li().size_chunk(); + } + return chunk_size; +} + +void BMP_Enums_Chunk::fill_data_block (char * data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + + *(int *) data_start = chunk_size; + data_start += 4; + + *(int*)data_start = reserved1; + *(int*)(data_start+4) = reserved2; + data_start += 8; + + strcpy(data_start,ctype ? ctype : ""); + data_start += strlen(data_start)+1 +3 &~3; + + *(int *)data_start = enums.size(); + data_start += 4; + + for (LIF li(&enums); !li.done(); li.next()) + { + Enum_Constant current(li()); + + current.fill_data_block(data_start); + data_start += current.size_chunk(); + } + +} + diff --git a/3dc/win95/ENUMSCH.HPP b/3dc/win95/ENUMSCH.HPP new file mode 100644 index 0000000..a332b84 --- /dev/null +++ b/3dc/win95/ENUMSCH.HPP @@ -0,0 +1,91 @@ +#ifndef _included_enumsch_hpp_ +#define _included_enumsch_hpp_ + +#include "chunk.hpp" + +class Enum_Constant +{ +public: + char * cname; + int value; + int reserved; + + Enum_Constant() : cname(0), value(0), reserved(0) {} + + ~Enum_Constant() + { + if (cname) delete[] cname; + } + + Enum_Constant(char const * const _cname, int const _value); + Enum_Constant(Enum_Constant const & ec2); + + Enum_Constant & operator = (Enum_Constant const & ec2); + + BOOL operator == (Enum_Constant const & ec2) const; + BOOL operator != (Enum_Constant const & ec2) const; + BOOL operator < (Enum_Constant const & ec2) const; + +private: + + friend class BMP_Enums_Chunk; + + // constructor from buffer + Enum_Constant(char const * sdata); + + size_t size_chunk() const; + + void fill_data_block(char * data_start); +}; + + +class Enum_Const_List +{ +public: + List enums; + + virtual ~Enum_Const_List(){} +#if cencon + int lowest_free_index(void); + void Sort_By_Name(void); +#endif +}; + + +class BMP_Enums_Chunk : public Chunk, public Enum_Const_List +{ +public: + // constructor from buffer + BMP_Enums_Chunk (Chunk_With_Children * const parent, char const * sdata, size_t const ssize); + +#if cencon + // empty constructor + BMP_Enums_Chunk (Chunk_With_Children * const parent) + : Chunk(parent,"BMPENUMS") + , ctype(0) + , reserved1(0) + , reserved2(0) + {} +#endif + + ~BMP_Enums_Chunk () + { + if (ctype) delete[] ctype; + } + + virtual size_t size_chunk (); + virtual void fill_data_block (char * data_start); + + char * ctype; + int reserved1; + int reserved2; + // List enums; + +private: + + friend class Enum_Chunk; + +}; + + +#endif // !_included_enumsch_hpp_ diff --git a/3dc/win95/ENVCHUNK.CPP b/3dc/win95/ENVCHUNK.CPP new file mode 100644 index 0000000..04cc292 --- /dev/null +++ b/3dc/win95/ENVCHUNK.CPP @@ -0,0 +1,325 @@ +#include "chunk.hpp" +#include "envchunk.hpp" + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(envchunk) + +// Class Environment_Data_Chunk functions +RIF_IMPLEMENT_DYNCREATE("REBENVDT",Environment_Data_Chunk) + +// constructor from buffer +LOCKABLE_CHUNK_WITH_CHILDREN_LOADER("REBENVDT",Environment_Data_Chunk) +/* +Children for Enviornment_Data_Chunk : + +"ENVSDSCL" Environment_Scale_Chunk +"GAMEMODE" Environment_Game_Mode_Chunk +"ENVPALET" Environment_Palette_Chunk +"ENVTXLIT" Environment_TLT_Chunk +"TLTCONFG" TLT_Config_Chunk +"CLRLOOKP" Coloured_Polygons_Lookup_Chunk +"MATCHIMG" Matching_Images_Chunk +"BMPNAMES" Global_BMP_Name_Chunk +"BMNAMVER" BMP_Names_Version_Chunk +"BMNAMEXT" BMP_Names_ExtraData_Chunk +"RIFFNAME" RIF_Name_Chunk +"ENDTHEAD" Environment_Data_Header_Chunk +"LIGHTSET" Light_Set_Chunk +"PRSETPAL" Preset_Palette_Chunk +"SPECLOBJ" Special_Objects_Chunk +"AVPEXSTR" AVP_External_Strategy_Chunk +"BMPMD5ID" Bitmap_MD5_Chunk +"GLOGENDC" Global_Generator_Data_Chunk +"FRAGTYPE" Fragment_Type_Chunk +"ENVACOUS" Environment_Acoustics_Chunk +"AVPENVIR" AVP_Environment_Settings_Chunk +"SOUNDDIR" Sound_Directory_Chunk +"RANTEXID" Random_Texture_ID_Chunk +*/ + + + + +// empty constructor +Environment_Data_Chunk::Environment_Data_Chunk (Chunk_With_Children * parent) +:Lockable_Chunk_With_Children (parent, "REBENVDT") +{ + // as necessary, generated automatically + new Environment_Data_Header_Chunk (this); +} + + +BOOL Environment_Data_Chunk::file_equals (HANDLE & /*rif_file*/) +{ + return(TRUE); +} + +Environment_Data_Header_Chunk * Environment_Data_Chunk::get_header() +{ + return (Environment_Data_Header_Chunk *) this->lookup_single_child ("ENDTHEAD"); +} + +const char * Environment_Data_Chunk::get_head_id() +{ + Environment_Data_Header_Chunk * hdptr = get_header(); + + if (!hdptr) return (0); + + return(hdptr->identifier); + +} + +void Environment_Data_Chunk::set_lock_user (char * user) +{ + Environment_Data_Header_Chunk * hdptr = get_header(); + + if (!hdptr) return; + + strncpy (hdptr->lock_user, user,16); + + hdptr->lock_user[16] = 0; +} + +void Environment_Data_Chunk::post_input_processing() +{ + if (get_header()) + if (get_header()->flags & GENERAL_FLAG_LOCKED) + external_lock = TRUE; + + Chunk_With_Children::post_input_processing(); + +} + +/////////////////////////////////////// + +// Class Environment_Data_Header_Chunk functions +RIF_IMPLEMENT_DYNCREATE("ENDTHEAD",Environment_Data_Header_Chunk) + +// from buffer +Environment_Data_Header_Chunk::Environment_Data_Header_Chunk (Chunk_With_Children * parent, const char * hdata, size_t /*hsize*/) + : Chunk (parent, "ENDTHEAD"), + flags (0), version_no (0) +{ + flags = *((int *) hdata); + + strncpy (lock_user, (hdata + 4), 16); + lock_user[16] = '\0'; + + version_no = *((int *) (hdata + 20)); +} + +BOOL Environment_Data_Header_Chunk::output_chunk (HANDLE & hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = make_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; +} + +void Environment_Data_Header_Chunk::fill_data_block ( char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = flags; + strncpy ((data_start + 4), lock_user, 16); + + *((int *) (data_start+20)) = version_no; +} + +void Environment_Data_Header_Chunk::prepare_for_output() +{ + version_no ++; +} + +/////////////////////////////////////// + +// Class Environment_Scale_Chunk functions +RIF_IMPLEMENT_DYNCREATE("ENVSDSCL",Environment_Scale_Chunk) + +void Environment_Scale_Chunk::fill_data_block ( char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((double *) data_start) = scale; +} + +/////////////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("ENVACOUS",Environment_Acoustics_Chunk) + +Environment_Acoustics_Chunk::Environment_Acoustics_Chunk(Environment_Data_Chunk* parent) +:Chunk(parent,"ENVACOUS") +{ + env_index=0; + reverb=2; + spare=0; +} + +Environment_Acoustics_Chunk::Environment_Acoustics_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk(parent,"ENVACOUS") +{ + env_index=*(int*)data; + data+=4; + reverb=*(float*)data; + data+=4; + spare=*(int*)data; +} + +void Environment_Acoustics_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *(int*)data_start=env_index; + data_start+=4; + *(float*)data_start=reverb; + data_start+=4; + *(int*)data_start=spare; + +} +/////////////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("SOUNDDIR",Sound_Directory_Chunk) + +Sound_Directory_Chunk::Sound_Directory_Chunk(Environment_Data_Chunk* parent,const char* dir) +:Chunk(parent,"SOUNDDIR") +{ + directory=new char[strlen(dir)+1]; + strcpy(directory,dir); +} + +Sound_Directory_Chunk::Sound_Directory_Chunk(Chunk_With_Children * const parent, const char* data, size_t const ) +:Chunk(parent,"SOUNDDIR") +{ + directory=new char[strlen(data)+1]; + strcpy(directory,data); +} + +Sound_Directory_Chunk::~Sound_Directory_Chunk() +{ + delete [] directory; +} + +void Sound_Directory_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + strcpy(data_start,directory); +} + + +/////////////////////////////////////// +/////////////////////Available shape set collections//////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("RANTEXID",Random_Texture_ID_Chunk) + +Random_Texture_ID_Chunk::Random_Texture_ID_Chunk(Chunk_With_Children* parent,const char* _name) +:Chunk(parent,"RANTEXID") +{ + name=new char[strlen(_name)+1]; + strcpy(name,_name); + spare1=spare2=0; +} + + +Random_Texture_ID_Chunk::Random_Texture_ID_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk(parent,"RANTEXID") +{ + CHUNK_EXTRACT_STRING(name); + + int num_types,type; + CHUNK_EXTRACT(num_types,int); + for(int i=0;i rlif(&random_types);!rlif.done();rlif.next()) + { + CHUNK_FILL(rlif(),int) + } + + CHUNK_FILL(spare1,int) + CHUNK_FILL(spare2,int) + +} + +size_t Random_Texture_ID_Chunk::size_chunk() +{ + chunk_size=12+12+random_types.size()*4; + chunk_size+=(strlen(name)+4)&~3; + return chunk_size; +} +/////////////////////////////////////// + + + + +//Class Special_Objects_Chunk : +RIF_IMPLEMENT_DYNCREATE("SPECLOBJ",Special_Objects_Chunk) + +CHUNK_WITH_CHILDREN_LOADER("SPECLOBJ",Special_Objects_Chunk) +/* +Children for Special_Objects_Chunk : +"AVPGENER" AVP_Generator_Chunk +"SOUNDOB2" Sound_Object_Chunk +"VIOBJECT" Virtual_Object_Chunk +"AVPCABLE" AVP_Power_Cable_Chunk +"AVPSTART" AVP_Player_Start_Chunk +"AVPPATH2" AVP_Path_Chunk +"AVPGENEX" AVP_Generator_Extra_Data_Chunk +"SOUNDEXD" Sound_Object_Extra_Data_Chunk +"PARGENER" AVP_Particle_Generator_Chunk +"PLACHIER" Placed_Hierarchy_Chunk +"CAMORIGN" Camera_Origin_Chunk +"AVPDECAL" AVP_Decal_Chunk +"R6WAYPNT" R6_Waypoint_Chunk + +*/ + + diff --git a/3dc/win95/ENVCHUNK.HPP b/3dc/win95/ENVCHUNK.HPP new file mode 100644 index 0000000..ee4b578 --- /dev/null +++ b/3dc/win95/ENVCHUNK.HPP @@ -0,0 +1,201 @@ +#ifndef _envchunk_hpp +#define _envchunk_hpp 1 + +#include "chunk.hpp" +#include "chnktype.hpp" +#include "mishchnk.hpp" + + +class Environment_Data_Header_Chunk; + +class Environment_Data_Chunk : public Lockable_Chunk_With_Children +{ +public: + + // empty constructor + Environment_Data_Chunk (Chunk_With_Children * parent); + // constructor from buffer + Environment_Data_Chunk (Chunk_With_Children * const parent,const char *, size_t const); + + Environment_Data_Header_Chunk * get_header(); + + // functions for the locking functionality + + BOOL file_equals (HANDLE &); + const char * get_head_id(); + void set_lock_user(char *); + + void post_input_processing(); + +private: + + friend class File_Chunk; + friend class GodFather_Chunk; + friend class RIF_File_Chunk; + + + + +}; + +/////////////////////////////////////////////// + +class Environment_Data_Header_Chunk : public Chunk +{ +public: + // constructor from buffer + Environment_Data_Header_Chunk (Chunk_With_Children * parent, const char * pdata, size_t psize); + + virtual size_t size_chunk () + { + chunk_size = 36; + return chunk_size; + } + + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start); + + void prepare_for_output(); + +private: + + friend class Environment_Data_Chunk; + friend class File_Chunk; + + int flags; + + int version_no; + + char lock_user[17]; + + + // constructor from parent + Environment_Data_Header_Chunk (Environment_Data_Chunk * parent) + : Chunk (parent, "ENDTHEAD"), + flags (0), version_no (0) + {} + +}; + +/////////////////////////////////////////////// + +class Environment_Scale_Chunk : public Chunk +{ + +public: + + // constructor from data + Environment_Scale_Chunk (Environment_Data_Chunk * parent, double _scale) + : Chunk (parent, "ENVSDSCL"), + scale (_scale) + {} + + // constructor from buffer + Environment_Scale_Chunk (Chunk_With_Children * parent, const char * sdata, size_t /*ssize*/) + : Chunk (parent, "ENVSDSCL"), + scale ( *((double *) sdata) ) + {} + + virtual size_t size_chunk () + { + chunk_size = 20; + return chunk_size; + } + + virtual void fill_data_block (char * data_start); + + const double scale; + +private: + + friend class Environment_Data_Chunk; + + + + +}; + +/////////////////////////////////////////////// + +class Special_Objects_Chunk : public Chunk_With_Children +{ + +public: + + Special_Objects_Chunk(Chunk_With_Children * parent) + : Chunk_With_Children (parent, "SPECLOBJ") + {} + // constructor from buffer + Special_Objects_Chunk (Chunk_With_Children * const parent,const char *, size_t const); +private: + + friend class Environment_Data_Chunk; + friend class AVP_Generator_Chunk; + + + +}; + +/////////////////////////////////////////////// +class Environment_Acoustics_Chunk : public Chunk +{ +public: + Environment_Acoustics_Chunk(Environment_Data_Chunk * parent); + Environment_Acoustics_Chunk(Chunk_With_Children* parent, const char * data, size_t ); + virtual void fill_data_block(char*); + virtual size_t size_chunk() + {return chunk_size=24;} + + int env_index; + float reverb; + int spare; +private: + friend class Environment_Data_Chunk; + + + +}; +/////////////////////////////////////////////// +class Sound_Directory_Chunk : public Chunk +{ +public : + Sound_Directory_Chunk(Environment_Data_Chunk* parent,const char* dir); + ~Sound_Directory_Chunk(); + // constructor from buffer + Sound_Directory_Chunk (Chunk_With_Children * const parent,const char *, size_t const); + char* directory; + + size_t size_chunk() + { + return (chunk_size =12 + ((strlen (directory)+4)&~3)); + } + + void fill_data_block(char* data_start); + +private: + + friend class Environment_Data_Chunk; + + + +}; + +/////////////////////Available shape set collections//////////////////////////////////////// +class Random_Texture_ID_Chunk : public Chunk +{ +public : + Random_Texture_ID_Chunk(Chunk_With_Children* parent,const char* _name); + Random_Texture_ID_Chunk(Chunk_With_Children* parent,const char* data, size_t); + ~Random_Texture_ID_Chunk(); + + void fill_data_block(char* data); + size_t size_chunk(); + + char* name; + List random_types; + + int spare1,spare2; + +}; +#endif \ No newline at end of file diff --git a/3dc/win95/GSPRCHNK.CPP b/3dc/win95/GSPRCHNK.CPP new file mode 100644 index 0000000..b20293f --- /dev/null +++ b/3dc/win95/GSPRCHNK.CPP @@ -0,0 +1,130 @@ +#include "gsprchnk.hpp" + +#ifdef cencon +#define new my_new +#endif + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(gsprchnk) + +// Class AllSprites_Chunk functions + +RIF_IMPLEMENT_DYNCREATE("RSPRITES",AllSprites_Chunk) +// constructor from buffer +LOCKABLE_CHUNK_WITH_CHILDREN_LOADER("RSPRITES",AllSprites_Chunk) + +/* +Children for AllSprites_Chunk : + +"ASPRHEAD" AllSprites_Header_Chunk +"SPRIHEAD" Sprite_Header_Chunk +*/ + + + +// empty constructor +AllSprites_Chunk::AllSprites_Chunk (Chunk_With_Children * parent) +:Lockable_Chunk_With_Children (parent, "RSPRITES") +{ + // as necessary, generated automatically + new AllSprites_Header_Chunk (this); +} + + +BOOL AllSprites_Chunk::file_equals (HANDLE & /*rif_file*/) +{ + return(TRUE); +} + +AllSprites_Header_Chunk * AllSprites_Chunk::get_header() +{ + return (AllSprites_Header_Chunk *) this->lookup_single_child ("ASPRHEAD"); +} + +const char * AllSprites_Chunk::get_head_id() +{ + AllSprites_Header_Chunk * hdptr = get_header(); + + if (!hdptr) return (0); + + return(hdptr->identifier); + +} + +void AllSprites_Chunk::set_lock_user (char * user) +{ + AllSprites_Header_Chunk * hdptr = get_header(); + + if (!hdptr) return; + + strncpy (hdptr->lock_user, user,16); + + hdptr->lock_user[16] = 0; +} + +void AllSprites_Chunk::post_input_processing() +{ + if (get_header()) + if (get_header()->flags & GENERAL_FLAG_LOCKED) + external_lock = TRUE; + + Chunk_With_Children::post_input_processing(); + +} + +/////////////////////////////////////// + +// Class AllSprites_Header_Chunk functions +RIF_IMPLEMENT_DYNCREATE("ASPRHEAD",AllSprites_Header_Chunk) + +// from buffer +AllSprites_Header_Chunk::AllSprites_Header_Chunk (Chunk_With_Children * parent, const char * hdata, size_t /*hsize*/) + : Chunk (parent, "ASPRHEAD"), + flags (0), version_no (0) +{ + flags = *((int *) hdata); + + strncpy (lock_user, (hdata + 4), 16); + lock_user[16] = '\0'; + + version_no = *((int *) (hdata + 20)); +} + +BOOL AllSprites_Header_Chunk::output_chunk (HANDLE & hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = make_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; +} + +void AllSprites_Header_Chunk::fill_data_block ( char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = flags; + strncpy ((data_start + 4), lock_user, 16); + + *((int *) (data_start+20)) = version_no; +} + +void AllSprites_Header_Chunk::prepare_for_output() +{ + version_no ++; +} + diff --git a/3dc/win95/GSPRCHNK.HPP b/3dc/win95/GSPRCHNK.HPP new file mode 100644 index 0000000..ede6395 --- /dev/null +++ b/3dc/win95/GSPRCHNK.HPP @@ -0,0 +1,82 @@ +#ifndef _included_gsprchnk_hpp_ +#define _included_gsprchnk_hpp_ + +#include "chunk.hpp" +#include "mishchnk.hpp" + +class AllSprites_Header_Chunk; + +class AllSprites_Chunk : public Lockable_Chunk_With_Children +{ +public: + + // empty constructor + AllSprites_Chunk (Chunk_With_Children * parent); + // constructor from buffer + AllSprites_Chunk (Chunk_With_Children * const parent,const char *, size_t const); + + AllSprites_Header_Chunk * get_header(); + + // functions for the locking functionality + + BOOL file_equals (HANDLE &); + const char * get_head_id(); + void set_lock_user(char *); + + void post_input_processing(); + +private: + + friend class File_Chunk; + friend class GodFather_Chunk; + + + + +}; + +/////////////////////////////////////////////// + +class AllSprites_Header_Chunk : public Chunk +{ +public: + // constructor from buffer + AllSprites_Header_Chunk (Chunk_With_Children * parent, const char * pdata, size_t psize); + + virtual size_t size_chunk () + { + chunk_size = 36; + return chunk_size; + } + + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start); + + void prepare_for_output(); + +private: + + friend class AllSprites_Chunk; + friend class File_Chunk; + + int flags; + + int version_no; + + char lock_user[17]; + + + + // constructor from parent + AllSprites_Header_Chunk (AllSprites_Chunk * parent) + : Chunk (parent, "ASPRHEAD"), + flags (0), version_no (0) + {} + +}; + + + + +#endif // _included_gsprchnk_hpp_ \ No newline at end of file diff --git a/3dc/win95/Hash_tem.hpp b/3dc/win95/Hash_tem.hpp new file mode 100644 index 0000000..279c65d --- /dev/null +++ b/3dc/win95/Hash_tem.hpp @@ -0,0 +1,882 @@ +/********************************************************/ +/* Hash Table template class - v1.2 */ +/* */ +/* Author: Jake Hotson */ +/* */ +/* construct a hash table for objects of type TYPE */ +/* */ +/* HashTable(unsigned initialTableSizeShift */ +/* = HT_DEFAULTTABLESIZESHIFT); */ +/* */ +/* TYPE must have boolean operator == defined, and */ +/* there must be an overload of the function */ +/* HashFunction() which acts as a hash */ +/* function for the TYPE, taking an argument of type */ +/* TYPE or a suitable conversion thereof, and returning */ +/* unsigned */ +/* Also, if a==b then HashFunction(a)==HashFunction(b) */ +/* Additionally, TYPE must have valid assignment */ +/* operator and copy constructor */ +/****************************************************Jake*/ + +/************************************************************/ +/* */ +/* v1.0 public classes and functions and macros */ +/* */ +/* HASH_TEMPLATE_VERSION */ +/* */ +/* major version * 100 + minor version */ +/* in this version (1.0) the value is 100 */ +/* */ +/* HT_NODEFAULTFNS */ +/* */ +/* #define to not compile default hash functions */ +/* */ +/* HT_DEFAULTABLESIZESHIFT */ +/* */ +/* #define to override default table size shift */ +/* of 6 (which gives a default table size of 64) */ +/* */ +/* HT_FAIL(sP) */ +/* */ +/* this macro should expand to a function (which */ +/* takes a char const * parameter) to be called */ +/* in the event of an error */ +/* */ +/* HashFunction(unsigned) */ +/* */ +/* default hash function for integers */ +/* */ +/* HashFunction(void const *) */ +/* */ +/* default hash function for pointers */ +/* */ +/* HashFunction(char const *) */ +/* */ +/* default hash function for strings */ +/* */ +/* class HashTable */ +/* */ +/* hash table template class */ +/* TYPE should have == operator defined and an */ +/* overloaded HashFunction() defined which can */ +/* take an argument type TYPE or suitable */ +/* conversion thereof */ +/* */ +/* HashTable::HashTable() */ +/* */ +/* constructs an empty table with default table */ +/* size */ +/* */ +/* HashTable::HashTable(unsigned) */ +/* */ +/* constructs an empty table with specific */ +/* table size determined by 2^arg */ +/* */ +/* bool HashTable::AddChecked(TYPE) */ +/* */ +/* adds object to hash table unless it already */ +/* contains it. Returns non-zero if object was */ +/* added, and zero if it was already contained */ +/* */ +/* void HashTable::AddRegardless(TYPE) */ +/* */ +/* adds object to hash table but does not check */ +/* if it already exists, so duplicates could */ +/* occur */ +/* */ +/* void HashTable::AddAsserted(TYPE) */ +/* */ +/* adds object to hash table but throws a failure if it */ +/* already exists unless NDEBUG is defined in which case */ +/* this function is identical to AddRegardless */ +/* */ +/* TYPE const * HashTable::Contains(TYPE) const */ +/* */ +/* returns pointer to equivalent entry in table, */ +/* or NULL, if none exists */ +/* */ +/* bool HashTable::Remove(TYPE) */ +/* */ +/* removes object from table if it exists. */ +/* Returns non-zero if object was removed, or */ +/* zero if object was not contained */ +/* */ +/* void HashTable::RemoveAll() */ +/* */ +/* empties the table */ +/* */ +/* void HashTable::RemoveAsserted(TYPE) */ +/* */ +/* removes object from table, but throws a */ +/* failure if object was not contained */ +/* */ +/* unsigned HashTable::Size() const */ +/* */ +/* returns number of objects in table */ +/* */ +/* class HashTable::ConstIterator */ +/* */ +/* class for iterating through objects contained */ +/* in hash table, without modifying the contents */ +/* of the table */ +/* */ +/* HashTable::ConstIterator::ConstIterator(HashTable const) */ +/* */ +/* constructs an iterator linked to a table, */ +/* ready for a Get() */ +/* */ +/* TYPE const & HashTable::ConstIterator::Get() const */ +/* HashTable::ConstIterator::operator TYPE const & () const */ +/* */ +/* gets a constant reference to the object in */ +/* the table pointed to by the iterator object */ +/* */ +/* bool HashTable::ConstIterator::Done() const */ +/* */ +/* returns non-zero only if there is no more */ +/* iterating to do */ +/* */ +/* void HashTable::ConstIterator::Next() */ +/* */ +/* moves iterator to a fresh entry in the table */ +/* */ +/* class HashTable::Iterator */ +/* */ +/* class for iterating through objects contained */ +/* in hash table, allowing their removal */ +/* */ +/* HashTable::Iterator::Iterator(HashTable) */ +/* */ +/* constructs an iterator linked to a table, */ +/* ready for a Get() */ +/* */ +/* HashTable::Iterator::Remove() */ +/* */ +/* removes the current object pointed to by the */ +/* iterator from the table, and advances the */ +/* iterator to the next entry */ +/* */ +/*******************************************************Jake*/ + +/************************************************************/ +/* */ +/* v1.1 - v1.11 extended functionality */ +/* */ +/* class HashTable::Node */ +/* */ +/* this is the internal class for nodes in the table */ +/* */ +/* TYPE HashTable::Node::d */ +/* */ +/* this is the value of a node's data */ +/* */ +/* Node * HashTable::NewNode() */ +/* */ +/* allocates a node without inserting it into the table; */ +/* you are expected to set Node::d to the required value */ +/* to be added to the table, and call one of these methods */ +/* to link the node into the table */ +/* */ +/* void HashTable::AddAsserted(Node *) */ +/* */ +/* like AddAsserted(TYPE const &) but takes a Node * */ +/* created with NewNode(); do not use the Node * pointer */ +/* after calling this method */ +/* */ +/* void HashTable::AddRegardless(Node *) */ +/* */ +/* like AddRegardless(TYPE const &) but takes a Node * */ +/* created with NewNode(); do not use the Node * pointer */ +/* after calling this method */ +/* */ +/* bool HashTable::AddChecked(Node *) */ +/* */ +/* like AddChecked(TYPE const &) but takes a Node * */ +/* created with NewNode(); do not use the Node * pointer */ +/* after calling this method if it returns true, but if it */ +/* returns false (i.e. the Node was not added, then you */ +/* can re-use the Node or use the following function to */ +/* delete it. */ +/* */ +/* void HashTable::DeleteNode(Node *) */ +/* */ +/* destroys a Node created with NewNode. Use this only if */ +/* the node created was not added to the hash table */ +/* */ +/*******************************************************Jake*/ + +/************************************************************/ +/* */ +/* v1.2 */ +/* */ +/* HashTable::Iterator::Restart() */ +/* restarts the iterator */ +/* */ +/* HashTable::HashTable(HashTable) */ +/* copy constructor */ +/* */ +/* HashTable::ValueIterator(unsigned) */ +/* iterate through all entries of a specific hashvalue */ +/* */ +/*******************************************************Alex*/ + +#ifndef HASH_TEMPLATE_VERSION +#define HASH_TEMPLATE_VERSION 12 // v1.2 + +#include +#include // for toupper + +// v1,0 Default Hash Functions defined: +// HashFunction(unsigned), HashFunction(void const *), HashFunction(char const *) +// you can disable the default hash functions by defining HT_NODEFAULTFNS + +#ifndef HT_NODEFAULTFNS + // a hash function for integral (unsigned) values + inline unsigned HashFunction(unsigned const _i) + { + return _i ^ _i>>4 ^ _i>>9 ^ _i>>15 ^ _i>>22; + } + + // a hash function for pointers + inline unsigned HashFunction(void const * const _vP) + { + // treat as integer + return HashFunction(reinterpret_cast(_vP)); + } + + // a hash function for strings + inline unsigned HashFunction(char const * _sP) + { + unsigned rv = 0; + while (*_sP) rv += toupper(*_sP++); + return rv; + } +#endif + +// v1,0 Default (initial) table size (log2 of) +// Define this to another value if you like, +// or just override in the constructor. +// in v1.0, the table is not self-expanding, +// but if this feature is implememted, then +// this value will become the log2(initial table size), +// and if table becomes is self-contracting, +// this value will also give the minimum table size + +#ifndef HT_DEFAULTTABLESIZESHIFT + #define HT_DEFAULTTABLESIZESHIFT 6 +#endif + +// for asserted functions, define HT_FAIL to be your function +// to be triggered upon a failure, eg. +// #define HT_FAIL(strP) fprintf(stderr,"%s\n",strP) +#ifndef HT_FAIL + #define HT_FAIL(strP) ((void)0) +#endif + +template +class _base_HashTable +{ + public: + class Iterator; + class ConstIterator; + class ValueIterator; + class Node; + + public: + // V1.0 Functionality + + // empty constructor, with argument specifying initial table size (log2 of) + _base_HashTable(unsigned = HT_DEFAULTTABLESIZESHIFT); + + // destructor + ~_base_HashTable(); + + // copy constructor and assignment not provided in v1.0 + _base_HashTable(_base_HashTable const &); + _base_HashTable & operator = (_base_HashTable const &); + + // add, checking that an equivalent entry does not already exist + // returns non-zero if entry was added + bool AddChecked(ARG_TYPE); + + // add, regardless of whether an equivalent entry already exists + void AddRegardless(ARG_TYPE); + + // add, checking that an equivalent entry does not already exist + // triggering fail function if one does + void AddAsserted(ARG_TYPE); + + // see if entry exists, get pointer to it if it does + TYPE const * Contains(CMP_ARG_TYPE) const; + + // remove an entry (once only in the case of equivalent entries listed multiple times) + // returns non-zero if entry existed and was removed + bool Remove(CMP_ARG_TYPE); + + // remove an entry (once only in the case of equivalent entries listed multiple times) + // triggers fail function if no entry existed to remove + void RemoveAsserted(CMP_ARG_TYPE); + + // empty the table + void RemoveAll(); + + // return num entries in table + unsigned Size() const; + + // a _base_HashTable const iterator + class ConstIterator + { + // Nested class functions apparently have to be declared here for MSVC compatability + public: + // construct from const hash table + ConstIterator(_base_HashTable const & tableR) + : chainPP(tableR.chainPA) + , nChainsRemaining(tableR.tableSize) + , nEntriesRemaining(tableR.nEntries) + { + if (nEntriesRemaining) + { + while (!*chainPP) + { + ++ chainPP; + -- nChainsRemaining; + } + nodePP = chainPP; + } + } + + // returns non-zero if there are no more entries to get + inline bool Done() const + { + return ! nEntriesRemaining; + } + + inline void Restart(_base_HashTable const & tableR) + { + chainPP = tableR.chainPA; + nChainsRemaining = tableR.tableSize; + nEntriesRemaining = tableR.nEntries; + + if (nEntriesRemaining) + { + while (!*chainPP) + { + ++ chainPP; + -- nChainsRemaining; + } + nodePP = chainPP; + } + } + + // get the current entry pointed to, either with Get() or cast operator + inline operator ARG_TYPE () const + { + return Get(); + } + inline ARG_TYPE Get() const + { + if( Done() ) + { + HT_FAIL("HTT: Tried to Get() from an iterator which was Done()"); + } + return (*nodePP)->d; + } + + // advance to the next entry + void Next() + { + if (!nEntriesRemaining) + { + HT_FAIL("HTT: Tried to do Next() on an iterator which was Done()"); + } + if ((*nodePP)->nextP) + { + nodePP = &(*nodePP)->nextP; + } + else + { + do + { + ++ chainPP; + -- nChainsRemaining; + } + while (nChainsRemaining && !*chainPP); + nodePP = chainPP; + } + -- nEntriesRemaining; + } + + private: + + Node * * chainPP; + Node * * nodePP; + unsigned nChainsRemaining; + unsigned nEntriesRemaining; + + friend class Iterator; + }; + + // a _base_HashTable non-const iterator - can remove entry pointed to + class Iterator : public ConstIterator + { + // Nested class functions apparently have to be declared here for MSVC compatability + public: + // construct from hash table + inline Iterator(_base_HashTable & tableR) + : ConstIterator(tableR) + , tableNEntriesP(&tableR.nEntries) + { + } + + // remove the current entry pointed to, advancing to the next + void Remove() + { + if (!nEntriesRemaining) + { + HT_FAIL("HTT: Tried to Remove() via an iterator which was Done()"); + } + Node * oldP = *nodePP; + *nodePP = oldP->nextP; + delete oldP; + if (!*nodePP) + { + do + { + ++ chainPP; + -- nChainsRemaining; + } + while (nChainsRemaining && !*chainPP); + nodePP = chainPP; + } + -- nEntriesRemaining; + -- *tableNEntriesP; + } + + private: + unsigned * tableNEntriesP; + }; + + // v1.2 extended functionality + // a _base_HashTable iterator through a specific hash value + class ValueIterator + { + // Nested class functions apparently have to be declared here for MSVC compatability + public: + // construct from const hash table + ValueIterator(_base_HashTable & tableR, unsigned value) + : chainPP(tableR.chainPA) + , value(value) + , tableNEntriesP(&tableR.nEntries) + { + chainPP += (value & tableR.tableSizeMask); + nodePP = chainPP; + } + + // returns non-zero if there are no more entries to get + inline bool Done() const + { + return( !(*nodePP) ); + } + + inline operator ARG_TYPE () const + { + return Get(); + } + inline ARG_TYPE Get() const + { + if( Done() ) + { + HT_FAIL("HTT: Tried to Get() from an iterator which was Done()"); + } + return (*nodePP)->d; + } + + inline void Restart(_base_HashTable const & tableR) + { + chainPP = tableR.chainPA + (value & tableR.tableSizeMask); + nodePP = chainPP; + } + + // advance to the next entry + void Next() + { + if( *nodePP ) + { + nodePP = &(*nodePP)->nextP; // even if it's NULL for ValueIterator + } + else + { + HT_FAIL("HTT: Tried to do Next() on a Value iterator which was Done()"); + } + } + + // remove the current entry pointed to, advancing to the next + void Remove() + { + if( *nodePP ) + { + Node * oldP = *nodePP; + *nodePP = oldP->nextP; + delete oldP; + -- *tableNEntriesP; + } + else + { + HT_FAIL("HTT: Tried to Remove() via an iterator which was Done()"); + } + } + + private: + + Node * * chainPP; + Node * * nodePP; + + unsigned value; + unsigned * tableNEntriesP; + }; + + // V1.1 extended functionality + // allow user to create nodes, change + // the data using this pointer, + // then insert the node into the + // correct chain, without having + // to create a copy of the data to + // be added on the stack + virtual Node * NewNode(); + // add, checking that an equivalent entry does not already exist + // triggering fail function if one does + void AddAsserted(Node *); + // add, regardless of whether an equivalent entry already exists + void AddRegardless(Node *); + // V1.11 allows AddChecked for the Node-adding interface + bool AddChecked(Node *); + // if add checked fails, you should avoid the memory leak with this function + virtual void DeleteNode(Node *); + + class Node + { + public: + TYPE d; + private: + Node * nextP; + // Nested class functions apparently have to be declared here for MSVC compatability + inline Node(ARG_TYPE _dataR,Node * _nextP) + : d(_dataR) + , nextP(_nextP) + { + } + inline Node() + { + } + inline ~Node() + { + } + void DeleteChain() + { + if (nextP) nextP->DeleteChain(); + delete this; + } + + friend class ConstIterator; + friend class Iterator; + friend class ValueIterator; + friend class _base_HashTable; + }; + + private: + // virtual functions for future expansion + virtual Node * NewNode(ARG_TYPE,Node *); + + unsigned nEntries; + unsigned tableSize; + unsigned tableSizeMask; + Node * * chainPA; + + friend class ConstIterator; + friend class Iterator; + friend class ValueIterator; + + inline void Xx(){} +}; + +/*******************/ +/* Defined to Fail */ +/**************Jake*/ + +template +inline _base_HashTable & _base_HashTable::operator = (_base_HashTable const &) +{ + HT_FAIL("HTT: assignment operator not allowed in this version"); + return *this; +} + +/*******************************/ +/* Inline Function Definitions */ +/**************************Jake*/ + +template +inline void _base_HashTable::AddRegardless(ARG_TYPE _dataR) +{ + Node * & chainPR = chainPA[HashFunction(_dataR) & tableSizeMask]; + chainPR = new Node(_dataR,chainPR); + ++ nEntries; +} + +template +inline void _base_HashTable::AddRegardless(Node * _nodeP) +{ + Node * & chainPR = chainPA[HashFunction(_nodeP->d) & tableSizeMask]; + _nodeP->nextP = chainPR; + chainPR = _nodeP; + ++ nEntries; +} + +// with NDEBUG on these functions evaluate to be identical to AddRegardless +#ifdef NDEBUG +template +inline void _base_HashTable::AddAsserted(ARG_TYPE _dataR) +{ + AddRegardless(_dataR); +} + +template +inline void _base_HashTable::AddAsserted(Node * _nodeP) +{ + AddRegardless(_nodeP); +} +#endif + +template +inline TYPE const * _base_HashTable::Contains(CMP_ARG_TYPE _dataR) const +{ + for (Node const * nodeP = chainPA[HashFunction(_dataR) & tableSizeMask]; nodeP; nodeP = nodeP->nextP) + { + if (nodeP->d == _dataR) return &nodeP->d; + } + return NULL; +} + +template +inline unsigned _base_HashTable::Size() const +{ + return nEntries; +} + +template +inline void _base_HashTable::RemoveAll() +{ + for (unsigned i=0; iDeleteChain(); + chainPA[i] = NULL; + } + nEntries = 0; +} + +/*************************************************************/ +/* Non inlines declared here since neither Watcom nor */ +/* MS Visual C will link if they're in their own source file */ +/********************************************************Jake*/ + +template +_base_HashTable::_base_HashTable(unsigned _initialTableSizeShift) + : nEntries(0) + , tableSize(1<<_initialTableSizeShift) + , tableSizeMask(tableSize-1) + , chainPA(new Node * [tableSize]) +{ + for (unsigned i=0; i +inline _base_HashTable::_base_HashTable(_base_HashTable const & ht) + : nEntries(0) + , tableSize(ht.tableSize) + , tableSizeMask(tableSize-1) + , chainPA(new Node * [tableSize]) +{ + for (unsigned i=0; i::ConstIterator it(ht); !it.Done(); it.Next() ) + { + AddRegardless( it.Get() ); + } +} + +template +_base_HashTable::~_base_HashTable() +{ + for (unsigned i=0; iDeleteChain(); + delete[] chainPA; +} + +template +bool _base_HashTable::AddChecked(ARG_TYPE _dataR) +{ + Node * & chainPR = chainPA[HashFunction(_dataR) & tableSizeMask]; + for (Node const * nodeP = chainPR; nodeP; nodeP = nodeP->nextP) + { + if (nodeP->d == _dataR) return false; + } + chainPR = new Node(_dataR,chainPR); + ++ nEntries; + return true; +} + +template +bool _base_HashTable::AddChecked(Node * _nodeP) +{ + Node * & chainPR = chainPA[HashFunction(_nodeP->d) & tableSizeMask]; + for (Node const * nodeP = chainPR; nodeP; nodeP = nodeP->nextP) + { + if (nodeP->d == _nodeP->d) return false; + } + _nodeP->nextP = chainPR; + chainPR = _nodeP; + ++ nEntries; + return true; +} + +// with NDEBUG on these functions evaluate to be identical to AddRegardless +#ifndef NDEBUG +template +void _base_HashTable::AddAsserted(ARG_TYPE _dataR) +{ + Node * & chainPR = chainPA[HashFunction(_dataR) & tableSizeMask]; + for (Node const * nodeP = chainPR; nodeP; nodeP = nodeP->nextP) + { + if (nodeP->d == _dataR) + { + HT_FAIL("HTT: Tried to add entry which was already contained in table"); + } + } + chainPR = new Node(_dataR,chainPR); + ++ nEntries; +} + +template +void _base_HashTable::AddAsserted(Node * _nodeP) +{ + Node * & chainPR = chainPA[HashFunction(_nodeP->d) & tableSizeMask]; + for (Node const * nodeP = chainPR; nodeP; nodeP = nodeP->nextP) + { + if (nodeP->d == _nodeP->d) + { + HT_FAIL("HTT: Tried to add entry which was already contained in table"); + } + } + _nodeP->nextP = chainPR; + chainPR = _nodeP; + ++ nEntries; +} +#endif + +template +bool _base_HashTable::Remove(CMP_ARG_TYPE _dataR) +{ + for (Node * * nodePP = &chainPA[HashFunction(_dataR) & tableSizeMask]; (*nodePP); nodePP = &(*nodePP)->nextP) + { + if ((*nodePP)->d == _dataR) + { + Node * oldP = *nodePP; + *nodePP = oldP->nextP; + delete oldP; + -- nEntries; + return true; + } + } + return false; +} + +template +void _base_HashTable::RemoveAsserted(CMP_ARG_TYPE _dataR) +{ + for (Node * * nodePP = &chainPA[HashFunction(_dataR) & tableSizeMask]; (*nodePP); nodePP = &(*nodePP)->nextP) + { + if ((*nodePP)->d == _dataR) + { + Node * oldP = *nodePP; + *nodePP = oldP->nextP; + delete oldP; + -- nEntries; + return; + } + } + HT_FAIL("HTT: Tried to remove entry which was not contained in table"); +} + +template +_base_HashTable::Node * _base_HashTable::NewNode(ARG_TYPE _dataR,Node * _nextP) +{ + return new Node(_dataR,_nextP); +} + +template +_base_HashTable::Node * _base_HashTable::NewNode() +{ + return new Node; +} + +template +void _base_HashTable::DeleteNode(Node * _nodeP) +{ + delete _nodeP; +} + +template class HashTable; + +#define HT_DEFINITION(T1,T2,T3) \ + : public _base_HashTable { public: HashTable(unsigned _initialTableSizeShift = HT_DEFAULTTABLESIZESHIFT) : _base_HashTable(_initialTableSizeShift){} }; + +// for simple types +#define HT_WATCOM_DEFINE_FOR_SIMPLE_TYPE(TYPE) \ + class HashTable HT_DEFINITION(TYPE,TYPE,TYPE) + +#ifdef __WATCOMC__ + +//watcom generartes errors if template<> is added to the start of the line - Richard. +#define HT_DEFINE_FOR_SIMPLE_TYPE(SIMPLE_TYPE) HT_WATCOM_DEFINE_FOR_SIMPLE_TYPE(SIMPLE_TYPE) + +#else + +#define HT_DEFINE_FOR_SIMPLE_TYPE(SIMPLE_TYPE) template<> HT_WATCOM_DEFINE_FOR_SIMPLE_TYPE(SIMPLE_TYPE) + +#endif + +HT_DEFINE_FOR_SIMPLE_TYPE(unsigned long) +HT_DEFINE_FOR_SIMPLE_TYPE(signed long) +HT_DEFINE_FOR_SIMPLE_TYPE(unsigned) +HT_DEFINE_FOR_SIMPLE_TYPE(signed) +HT_DEFINE_FOR_SIMPLE_TYPE(unsigned short) +HT_DEFINE_FOR_SIMPLE_TYPE(signed short) +HT_DEFINE_FOR_SIMPLE_TYPE(unsigned char) +HT_DEFINE_FOR_SIMPLE_TYPE(signed char) +HT_DEFINE_FOR_SIMPLE_TYPE(char) +HT_DEFINE_FOR_SIMPLE_TYPE(float) + +#undef HT_DEFINE_FOR_SIMPLE_TYPE +#undef HT_WATCOM_DEFINE_FOR_SIMPLE_TYPE + +// for pointer types +#if 0 // doesnt't compile!! +template +class HashTable HT_DEFINITION(TYPE *, TYPE *, TYPE const *) + +template +class HashTable HT_DEFINITION(TYPE const *, TYPE const *, TYPE const *) +#endif + +// for other types +template +class HashTable HT_DEFINITION(TYPE,TYPE const &, TYPE const &) + +//template class HashTable : public _base_HashTable {}; + +#undef HT_DEFINITION + +#endif // ! HASH_TEMPLATE_VERSION diff --git a/3dc/win95/ILBM_ext.cpp b/3dc/win95/ILBM_ext.cpp new file mode 100644 index 0000000..e1d8a4d --- /dev/null +++ b/3dc/win95/ILBM_ext.cpp @@ -0,0 +1,87 @@ +#include "ILBM_ext.hpp" + +IFF_IMPLEMENT_DYNCREATE("ILBM","TRAN",IlbmTranChunk) +IFF_IMPLEMENT_DYNCREATE("ILBM","ALPH",IlbmAlphChunk) +IFF_IMPLEMENT_DYNCREATE("MIPM","CONT",MipmContChunk) +IFF_IMPLEMENT_DYNCREATE("ILBM","S3TC",IlbmS3tcChunk) +IFF_IMPLEMENT_DYNCREATE("MIPM","FLAG",MipmFlagChunk) + +namespace IFF +{ + void IlbmTranChunk::Serialize(Archive * pArchv) + { + pArchv->Transfer(eTransType); + pArchv->Transfer(xPos); + pArchv->Transfer(yPos); + pArchv->Transfer(rgb); + } + + void IlbmAlphChunk::Serialize(Archive * pArchv) + { + pArchv->Transfer(width); + pArchv->Transfer(height); + pArchv->Transfer(nBitPlanes); + pArchv->Transfer(eCompression); + + IlbmBodyChunk::Serialize(pArchv); + } + + bool IlbmAlphChunk::GetHeaderInfo() const + { + IlbmBodyChunk::nWidth = width; + IlbmBodyChunk::eCompression = eCompression; + IlbmBodyChunk::nBitPlanes = nBitPlanes; + return true; + } + + void MipmContChunk::Serialize(Archive * pArchv) + { + pArchv->Transfer(nMipMaps); + pArchv->Transfer(eFilter); + } + + void MipmFlagChunk::Serialize(Archive * pArchv) + { + pArchv->Transfer(flags); + } + + IlbmS3tcChunk::IlbmS3tcChunk() + { + m_idCk = "S3TC"; + + pData = NULL; + dataSize = 0; + } + + IlbmS3tcChunk::~IlbmS3tcChunk() + { + if(pData) delete [] pData; + pData = NULL; + } + + void IlbmS3tcChunk::Serialize(Archive * pArchv) + { + pArchv->Transfer(flags); + pArchv->Transfer(fourCC); + pArchv->Transfer(redWeight); + pArchv->Transfer(blueWeight); + pArchv->Transfer(greenWeight); + pArchv->Transfer(width); + pArchv->Transfer(height); + + pArchv->Transfer(dataSize); + + if (pArchv->m_bIsLoading) + { + if(pData) delete [] pData; + pData = new UBYTE[dataSize]; + } + + UBYTE *pDataPos = pData; + for(unsigned i=0;iTransfer(*pDataPos++); + } + } + +} \ No newline at end of file diff --git a/3dc/win95/ILBM_ext.hpp b/3dc/win95/ILBM_ext.hpp new file mode 100644 index 0000000..3aefce7 --- /dev/null +++ b/3dc/win95/ILBM_ext.hpp @@ -0,0 +1,117 @@ +#ifndef _INCLUDED_ILBM_EXT_HPP_ +#define _INCLUDED_ILBM_EXT_HPP_ + +#include "iff.hpp" +#include "iff_ILBM.hpp" + +namespace IFF +{ + class IlbmTranChunk : public Chunk + { + public: + enum + { + TRANS_NONE = 0, + TRANS_TOPLEFT = 1, + TRANS_BOTTOMLEFT = 2, + TRANS_TOPRIGHT = 3, + TRANS_BOTTOMRIGHT = 4, + TRANS_XY = 5, + TRANS_RGB = 6 + }; + UBYTE eTransType; + UINT16 xPos; + UINT16 yPos; + RGBTriple rgb; + + IlbmTranChunk() { m_idCk = "TRAN"; } + + protected: + virtual void Serialize(Archive * pArchv); + }; + + class IlbmAlphChunk : public IlbmBodyChunk // uses same encoding methodology + { + public: + UINT16 width; + UINT16 height; + UBYTE nBitPlanes; + UBYTE eCompression; + + IlbmAlphChunk() + { m_idCk = "ALPH"; } + + protected: + virtual void Serialize(Archive * pArchv); + + virtual bool GetHeaderInfo() const; + }; + + class IlbmS3tcChunk : public Chunk + { + public: + IlbmS3tcChunk(); + virtual ~IlbmS3tcChunk(); + + + + UINT32 flags; // none at the moment + UINT32 fourCC; //the fourcc code 'DXT1' - 'DXT5' + + UINT16 redWeight; //weighting values used in compression + UINT16 blueWeight; + UINT16 greenWeight; + + UINT16 width; + UINT16 height; + + UINT32 dataSize; + UBYTE* pData; //the compressed texture itself + + protected: + virtual void Serialize(Archive * pArchv); + }; + + + class MipmContChunk : public Chunk + { + public: + enum + { + FILTER_DEFAULT = 0, + FILTER_BOX = 1, + FILTER_TRIANGLE = 2, + FILTER_BELL = 3, + FILTER_BSPLINE = 4, + FILTER_LANCZOS3 = 5, + FILTER_MITCHELL = 6 + }; + UBYTE nMipMaps; + UBYTE eFilter; + + MipmContChunk() + { m_idCk = "CONT"; } + + protected: + virtual void Serialize(Archive * pArchv); + }; + + class MipmFlagChunk : public Chunk + { + public: + enum + { + FLAG_MANUAL_MIPS = 0x00000001,//some of the mip maps have been set by hand + }; + UINT32 flags; + + MipmFlagChunk() + { m_idCk = "FLAG"; flags = 0;} + + protected: + virtual void Serialize(Archive * pArchv); + }; + +} + +#endif diff --git a/3dc/win95/INLINE.H b/3dc/win95/INLINE.H new file mode 100644 index 0000000..fdc5c60 --- /dev/null +++ b/3dc/win95/INLINE.H @@ -0,0 +1,1246 @@ +#ifndef INLINE_INCLUDED + +#if SUPPORT_MMX +#include "mmx_math.h" +#endif + +/* + + + Watcom PC Inline Functions. + + Watcom Standard C does not support the C++ "inline" directive, so these + functions have been written as inline assembler instead. + +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + Standard macros. Note that FIXED_TO_INT + and INT_TO_FIXED are very suboptimal in + this version!!! + Also, MUL_INT and ISR are ONLY intended + to be used in Win95 so that Saturn versions + of the same code can be compiled using calls + to hand optimised assembler functions, i.e. + for code that is never intended to be run on + a Saturn they are unnecessary. +*/ + +#define OUR_ABS(x) (((x) < 0) ? -(x) : (x)) +#define OUR_SIGN(x) (((x) < 0) ? -1 : +1) +#define OUR_INT_TO_FIXED(x) (int) ((x) * (65536)) +#define OUR_FIXED_TO_INT(x) (int) ((x) / (65536)) +#define OUR_MUL_INT(a, b) ((a) * (b)) +#define OUR_ISR(a, shift) ((a) >> (shift)) + + +/* + + win95\item.c functions + +*/ + +void InitialiseTriangleArrayData(void); +void* AllocateTriangleArrayData(int tasize); + + +/* + + General Triangle Array Handler Null Case / Error + +*/ + +void TriangleArrayNullOrError(TRIANGLEARRAY *tarr); + + +/* + + Item Polygon Triangle Array Functions + +*/ + +void Item_Polygon_PrepareTriangleArray_3(TRIANGLEARRAY *qarr); +void Item_Polygon_PrepareTriangleArray_4(TRIANGLEARRAY *qarr); +void Item_Polygon_PrepareTriangleArray_5(TRIANGLEARRAY *qarr); +void Item_Polygon_PrepareTriangleArray_6(TRIANGLEARRAY *qarr); +void Item_Polygon_PrepareTriangleArray_7(TRIANGLEARRAY *qarr); +void Item_Polygon_PrepareTriangleArray_8(TRIANGLEARRAY *qarr); +void Item_Polygon_PrepareTriangleArray_9(TRIANGLEARRAY *qarr); + + +/* + + Item Gouraud Polygon Triangle Array Functions + +*/ + +void Item_GouraudPolygon_PrepareTriangleArray_3(TRIANGLEARRAY *qarr); +void Item_GouraudPolygon_PrepareTriangleArray_4(TRIANGLEARRAY *qarr); +void Item_GouraudPolygon_PrepareTriangleArray_5(TRIANGLEARRAY *qarr); +void Item_GouraudPolygon_PrepareTriangleArray_6(TRIANGLEARRAY *qarr); +void Item_GouraudPolygon_PrepareTriangleArray_7(TRIANGLEARRAY *qarr); +void Item_GouraudPolygon_PrepareTriangleArray_8(TRIANGLEARRAY *qarr); +void Item_GouraudPolygon_PrepareTriangleArray_9(TRIANGLEARRAY *qarr); + +/* + + Item 2d Textured Polygon Triangle Array Functions + +*/ + +void Item_2dTexturedPolygon_PrepareTriangleArray_3(TRIANGLEARRAY *qarr); +void Item_2dTexturedPolygon_PrepareTriangleArray_4(TRIANGLEARRAY *qarr); +void Item_2dTexturedPolygon_PrepareTriangleArray_5(TRIANGLEARRAY *qarr); +void Item_2dTexturedPolygon_PrepareTriangleArray_6(TRIANGLEARRAY *qarr); +void Item_2dTexturedPolygon_PrepareTriangleArray_7(TRIANGLEARRAY *qarr); +void Item_2dTexturedPolygon_PrepareTriangleArray_8(TRIANGLEARRAY *qarr); +void Item_2dTexturedPolygon_PrepareTriangleArray_9(TRIANGLEARRAY *qarr); + +/* + + Item Gouraud 2d Textured Polygon Triangle Array Functions + +*/ + +void Item_Gouraud2dTexturedPolygon_PrepareTriangleArray_3(TRIANGLEARRAY *qarr); +void Item_Gouraud2dTexturedPolygon_PrepareTriangleArray_4(TRIANGLEARRAY *qarr); +void Item_Gouraud2dTexturedPolygon_PrepareTriangleArray_5(TRIANGLEARRAY *qarr); +void Item_Gouraud2dTexturedPolygon_PrepareTriangleArray_6(TRIANGLEARRAY *qarr); +void Item_Gouraud2dTexturedPolygon_PrepareTriangleArray_7(TRIANGLEARRAY *qarr); +void Item_Gouraud2dTexturedPolygon_PrepareTriangleArray_8(TRIANGLEARRAY *qarr); +void Item_Gouraud2dTexturedPolygon_PrepareTriangleArray_9(TRIANGLEARRAY *qarr); + + +/* + + Item 3d Textured Polygon Triangle Array Functions + +*/ + +void Item_3dTexturedPolygon_PrepareTriangleArray_3(TRIANGLEARRAY *qarr); +void Item_3dTexturedPolygon_PrepareTriangleArray_4(TRIANGLEARRAY *qarr); +void Item_3dTexturedPolygon_PrepareTriangleArray_5(TRIANGLEARRAY *qarr); +void Item_3dTexturedPolygon_PrepareTriangleArray_6(TRIANGLEARRAY *qarr); +void Item_3dTexturedPolygon_PrepareTriangleArray_7(TRIANGLEARRAY *qarr); +void Item_3dTexturedPolygon_PrepareTriangleArray_8(TRIANGLEARRAY *qarr); +void Item_3dTexturedPolygon_PrepareTriangleArray_9(TRIANGLEARRAY *qarr); + +/* + + Item Gouraud 3d Textured Polygon Triangle Array Functions + +*/ + +void Item_Gouraud3dTexturedPolygon_PrepareTriangleArray_3(TRIANGLEARRAY *qarr); +void Item_Gouraud3dTexturedPolygon_PrepareTriangleArray_4(TRIANGLEARRAY *qarr); +void Item_Gouraud3dTexturedPolygon_PrepareTriangleArray_5(TRIANGLEARRAY *qarr); +void Item_Gouraud3dTexturedPolygon_PrepareTriangleArray_6(TRIANGLEARRAY *qarr); +void Item_Gouraud3dTexturedPolygon_PrepareTriangleArray_7(TRIANGLEARRAY *qarr); +void Item_Gouraud3dTexturedPolygon_PrepareTriangleArray_8(TRIANGLEARRAY *qarr); +void Item_Gouraud3dTexturedPolygon_PrepareTriangleArray_9(TRIANGLEARRAY *qarr); + +/* + + Platform Specific 64-Bit Operator Functions + + Not all compilers support 64-bit operations, and some platforms may not + even support 64-bit numbers. Support for 64-bit operations is therefore + provided in the platform specific fucntions below. + + For C++ a mew class could be defined. However the current system is not + compiled as C++ and the Cygnus GNU C++ is not currently working. + +*/ + + +/* + These functions have been checked for suitability for + a Pentium and look as if they would pair up okay. + Might be worth a more detailed look at optimising + them though. + Obviously there is a problem with values not being + loaded into registers for these functions, but this + may be unavoidable for 64 bit values on a Watcom + platform. +*/ + + +#ifdef __WATCOMC__ /* inline assember for the Watcom compiler */ + +/* ADD */ + +void ADD_LL(LONGLONGCH *a, LONGLONGCH *b, LONGLONGCH *c); +# pragma aux ADD_LL = \ +"mov eax,[esi]" \ +"mov edx,[esi+4]" \ +"add eax,[edi]" \ +"adc edx,[edi+4]" \ +"mov [ebx],eax" \ +"mov [ebx+4],edx" \ +parm[esi] [edi] [ebx] \ +modify[eax edx]; + + +/* ADD ++ */ + +void ADD_LL_PP(LONGLONGCH *c, LONGLONGCH *a); +# pragma aux ADD_LL_PP = \ +"mov eax,[esi]" \ +"mov edx,[esi+4]" \ +"add [edi],eax" \ +"adc [edi+4],edx" \ +parm[edi] [esi] \ +modify[eax edx]; + + +/* SUB */ + +void SUB_LL(LONGLONGCH *a, LONGLONGCH *b, LONGLONGCH *c); +# pragma aux SUB_LL = \ +"mov eax,[esi]" \ +"mov edx,[esi+4]" \ +"sub eax,[edi]" \ +"sbb edx,[edi+4]" \ +"mov [ebx],eax" \ +"mov [ebx+4],edx" \ +parm[esi] [edi] [ebx] \ +modify[eax edx]; + + + +/* SUB -- */ + +void SUB_LL_MM(LONGLONGCH *c, LONGLONGCH *a); +# pragma aux SUB_LL_MM = \ +"mov eax,[esi]" \ +"mov edx,[esi+4]" \ +"sub [edi],eax" \ +"sbb [edi+4],edx" \ +parm[edi] [esi] \ +modify[eax edx]; + + +/* + + MUL + + This is the multiply we use, the 32 x 32 = 64 widening version + +*/ + +void MUL_I_WIDE(int a, int b, LONGLONGCH *c); +# pragma aux MUL_I_WIDE = \ +"imul edx"\ +"mov [ebx],eax" \ +"mov [ebx+4],edx" \ +parm[eax] [edx] [ebx] \ +modify[eax edx]; + + + +/* + + CMP + + This substitutes for ==, >, <, >=, <= + +*/ + +int CMP_LL(LONGLONGCH *a, LONGLONGCH *b); +# pragma aux CMP_LL = \ +"mov eax,[ebx]" \ +"mov edx,[ebx+4]" \ +"sub eax,[ecx]" \ +"sbb edx,[ecx+4]" \ +"and edx,edx" \ +"jne llnz" \ +"and eax,eax" \ +"jne llnz" \ +"xor eax,eax" \ +"jmp llgs" \ +"llnz:" \ +"mov eax,1" \ +"and edx,edx" \ +"jge llgs" \ +"neg eax" \ +"llgs:" \ +parm[ebx] [ecx] \ +value[eax] \ +modify[edx]; + + + + +/* EQUALS */ + +void EQUALS_LL(LONGLONGCH *a, LONGLONGCH *b); +# pragma aux EQUALS_LL = \ +"mov eax,[esi]" \ +"mov edx,[esi+4]" \ +"mov [edi],eax" \ +"mov [edi+4],edx" \ +parm[edi] [esi] \ +modify[eax edx]; + + +/* NEGATE */ + +void NEG_LL(LONGLONGCH *a); +# pragma aux NEG_LL = \ +"not dword ptr[esi]" \ +"not dword ptr[esi+4]" \ +"add dword ptr[esi],1" \ +"adc dword ptr[esi+4],0" \ +parm[esi]; + + +/* ASR */ + +void ASR_LL(LONGLONGCH *a, int shift); +# pragma aux ASR_LL = \ +"and eax,eax" \ +"jle asrdn" \ +"asrlp:" \ +"sar dword ptr[esi+4],1" \ +"rcr dword ptr[esi],1" \ +"dec eax" \ +"jne asrlp" \ +"asrdn:" \ +parm[esi] [eax]; + + +/* Convert int to LONGLONGCH */ + +void IntToLL(LONGLONGCH *a, int *b); +# pragma aux IntToLL = \ +"mov eax,[esi]" \ +"cdq" \ +"mov [edi],eax" \ +"mov [edi+4],edx" \ +parm[edi] [esi] \ +modify[eax edx]; + + + + + + + + + +/* + + Fixed Point Multiply. + + + 16.16 * 16.16 -> 16.16 + or + 16.16 * 0.32 -> 0.32 + + A proper version of this function ought to read + 16.16 * 16.16 -> 32.16 + but this would require a long long result + + Algorithm: + + Take the mid 32 bits of the 64 bit result + +*/ + +/* + These functions have been checked for suitability for + a Pentium and look as if they would work adequately. + Might be worth a more detailed look at optimising + them though. +*/ + +#if 0 + +int MUL_FIXED(int a, int b); +# pragma aux MUL_FIXED = \ +"imul edx" \ +"mov ax,dx" \ +"rol eax,16" \ +parm[eax] [edx] \ +value[eax] \ +modify[edx]; + +#else + +int MUL_FIXED(int a, int b); +# pragma aux MUL_FIXED = \ +"imul edx" \ +"shrd eax,edx,16" \ +parm[eax] [edx] \ +value[eax] \ +modify[edx]; + +#endif + + +/* + + Fixed Point Divide - returns a / b + +*/ + +int DIV_FIXED(int a, int b); +# pragma aux DIV_FIXED = \ +"cdq" \ +"rol eax,16" \ +"mov dx,ax" \ +"xor ax,ax" \ +"idiv ebx" \ +parm[eax] [ebx] \ +value[eax] \ +modify[edx]; + + + + +/* + + Multiply and Divide Functions. + +*/ + + +/* + + 32/32 division + + This macro is a function on some other platforms + +*/ + +#define DIV_INT(a, b) ((a) / (b)) + + + + +/* + + A Narrowing 64/32 Division + +*/ + +int NarrowDivide(LONGLONGCH *a, int b); +# pragma aux NarrowDivide = \ +"mov eax,[esi]" \ +"mov edx,[esi+4]" \ +"idiv ebx" \ +parm[esi] [ebx] \ +value[eax] \ +modify[edx]; + + + +/* + + This function performs a Widening Multiply followed by a Narrowing Divide. + + a = (a * b) / c + +*/ + +int WideMulNarrowDiv(int a, int b, int c); +# pragma aux WideMulNarrowDiv = \ +"imul edx"\ +"idiv ebx" \ +parm[eax] [edx] [ebx] \ +value[eax]; + + + +/* + + Function to rotate a VECTORCH using a MATRIXCH + + This is the C function + + x = MUL_FIXED(m->mat11, v->vx); + x += MUL_FIXED(m->mat21, v->vy); + x += MUL_FIXED(m->mat31, v->vz); + + y = MUL_FIXED(m->mat12, v->vx); + y += MUL_FIXED(m->mat22, v->vy); + y += MUL_FIXED(m->mat32, v->vz); + + z = MUL_FIXED(m->mat13, v->vx); + z += MUL_FIXED(m->mat23, v->vy); + z += MUL_FIXED(m->mat33, v->vz); + + v->vx = x; + v->vy = y; + v->vz = z; + + This is the MUL_FIXED inline assembler function + + imul edx + shrd eax,edx,16 + + +typedef struct matrixch { + + int mat11; 0 + int mat12; 4 + int mat13; 8 + + int mat21; 12 + int mat22; 16 + int mat23; 20 + + int mat31; 24 + int mat32; 28 + int mat33; 32 + +} MATRIXCH; + +*/ + +void RotateVector_ASM(VECTORCH *v, MATRIXCH *m); +# pragma aux RotateVector_ASM = \ +\ +"push eax" \ +"push ebx" \ +"push ecx" \ +"push edx" \ +"push ebp" \ +\ +"mov eax,[edi + 0]" \ +"imul DWORD PTR [esi + 0]" \ +"shrd eax,edx,16" \ +"mov ecx,eax"\ +"mov eax,[edi + 12]" \ +"imul DWORD PTR [esi + 4]" \ +"shrd eax,edx,16" \ +"add ecx,eax" \ +"mov eax,[edi + 24]" \ +"imul DWORD PTR [esi + 8]" \ +"shrd eax,edx,16" \ +"add ecx,eax" \ +\ +"mov eax,[edi + 4]" \ +"imul DWORD PTR [esi + 0]" \ +"shrd eax,edx,16" \ +"mov ebx,eax"\ +"mov eax,[edi + 16]" \ +"imul DWORD PTR [esi + 4]" \ +"shrd eax,edx,16" \ +"add ebx,eax" \ +"mov eax,[edi + 28]" \ +"imul DWORD PTR [esi + 8]" \ +"shrd eax,edx,16" \ +"add ebx,eax" \ +\ +"mov eax,[edi + 8]" \ +"imul DWORD PTR [esi + 0]" \ +"shrd eax,edx,16" \ +"mov ebp,eax"\ +"mov eax,[edi + 20]" \ +"imul DWORD PTR [esi + 4]" \ +"shrd eax,edx,16" \ +"add ebp,eax" \ +"mov eax,[edi + 32]" \ +"imul DWORD PTR [esi + 8]" \ +"shrd eax,edx,16" \ +"add ebp,eax" \ +\ +"mov [esi + 0],ecx" \ +"mov [esi + 4],ebx" \ +"mov [esi + 8],ebp" \ +\ +"pop ebp" \ +"pop edx" \ +"pop ecx" \ +"pop ebx" \ +"pop eax" \ +\ +parm[esi] [edi]; + + +/* + + Here is the same function, this time copying the result to a second vector + +*/ + +void RotateAndCopyVector_ASM(VECTORCH *v1, VECTORCH *v2, MATRIXCH *m); +# pragma aux RotateAndCopyVector_ASM = \ +\ +"push eax" \ +"push ebx" \ +"push ecx" \ +"push ebp" \ +\ +"push edx" \ +"mov eax,[edi + 0]" \ +"imul DWORD PTR [esi + 0]" \ +"shrd eax,edx,16" \ +"mov ecx,eax"\ +"mov eax,[edi + 12]" \ +"imul DWORD PTR [esi + 4]" \ +"shrd eax,edx,16" \ +"add ecx,eax" \ +"mov eax,[edi + 24]" \ +"imul DWORD PTR [esi + 8]" \ +"shrd eax,edx,16" \ +"add ecx,eax" \ +\ +"mov eax,[edi + 4]" \ +"imul DWORD PTR [esi + 0]" \ +"shrd eax,edx,16" \ +"mov ebx,eax"\ +"mov eax,[edi + 16]" \ +"imul DWORD PTR [esi + 4]" \ +"shrd eax,edx,16" \ +"add ebx,eax" \ +"mov eax,[edi + 28]" \ +"imul DWORD PTR [esi + 8]" \ +"shrd eax,edx,16" \ +"add ebx,eax" \ +\ +"mov eax,[edi + 8]" \ +"imul DWORD PTR [esi + 0]" \ +"shrd eax,edx,16" \ +"mov ebp,eax"\ +"mov eax,[edi + 20]" \ +"imul DWORD PTR [esi + 4]" \ +"shrd eax,edx,16" \ +"add ebp,eax" \ +"mov eax,[edi + 32]" \ +"imul DWORD PTR [esi + 8]" \ +"shrd eax,edx,16" \ +"add ebp,eax" \ +\ +"pop edx" \ +"mov [edx + 0],ecx" \ +"mov [edx + 4],ebx" \ +"mov [edx + 8],ebp" \ +\ +"pop ebp" \ +"pop ecx" \ +"pop ebx" \ +"pop eax" \ +\ +parm[esi] [edx] [edi]; + + + + +#if (SupportFPMathsFunctions || SupportFPSquareRoot) + +/* + + Square Root + + Returns the Square Root of a 32-bit number + +*/ + +static long temp; +static long temp2; + +int SqRoot32(int A); +# pragma aux SqRoot32 = \ +"finit" \ +"mov temp,eax" \ +"fild temp" \ +"fsqrt" \ +"fistp temp2" \ +"fwait" \ +"mov eax,temp2" \ +parm[eax] \ +value[eax]; + +#endif + + +/* + + This may look ugly (it is) but it is a MUCH faster way to convert "float" into "int" than + the function call "CHP" used by the WATCOM compiler. + +*/ + +static float fptmp; +static int itmp; + +void FloatToInt(void); +# pragma aux FloatToInt = \ +"fld fptmp" \ +"fistp itmp"; + +/* + + This macro makes usage of the above function easier and more elegant + +*/ + +#define f2i(a, b) { \ +fptmp = (b); \ +FloatToInt(); \ +a = itmp;} + +#elif defined(_MSC_VER) /* inline assember for the Microsoft compiler */ + +/* ADD */ + +static void ADD_LL(LONGLONGCH *a, LONGLONGCH *b, LONGLONGCH *c) +{ + _asm + { + mov esi,a + mov edi,b + mov ebx,c + mov eax,[esi] + mov edx,[esi+4] + add eax,[edi] + adc edx,[edi+4] + mov [ebx],eax + mov [ebx+4],edx + } +} + +/* ADD ++ */ + +static void ADD_LL_PP(LONGLONGCH *c, LONGLONGCH *a) +{ + _asm + { + mov edi,c + mov esi,a + mov eax,[esi] + mov edx,[esi+4] + add [edi],eax + adc [edi+4],edx + } +} + +/* SUB */ + +static void SUB_LL(LONGLONGCH *a, LONGLONGCH *b, LONGLONGCH *c) +{ + _asm + { + mov esi,a + mov edi,b + mov ebx,c + mov eax,[esi] + mov edx,[esi+4] + sub eax,[edi] + sbb edx,[edi+4] + mov [ebx],eax + mov [ebx+4],edx + } +} + +/* SUB -- */ + +static void SUB_LL_MM(LONGLONGCH *c, LONGLONGCH *a) +{ + _asm + { + mov edi,c + mov esi,a + mov eax,[esi] + mov edx,[esi+4] + sub [edi],eax + sbb [edi+4],edx + } +} + +/* + + MUL + + This is the multiply we use, the 32 x 32 = 64 widening version + +*/ + +static void MUL_I_WIDE(int a, int b, LONGLONGCH *c) +{ + _asm + { + mov eax,a + mov ebx,c + imul b + mov [ebx],eax + mov [ebx+4],edx + } +} + +/* + + CMP + + This substitutes for ==, >, <, >=, <= + +*/ + +static int CMP_LL(LONGLONGCH *a, LONGLONGCH *b) +{ + int retval = 0; + _asm + { + mov ebx,a + mov ecx,b + mov eax,[ebx] + mov edx,[ebx+4] + sub eax,[ecx] + sbb edx,[ecx+4] + and edx,edx + jne llnz + and eax,eax + je llgs + llnz: + mov retval,1 + and edx,edx + jge llgs + neg retval + llgs: + } + return retval; +} + +/* EQUALS */ + +static void EQUALS_LL(LONGLONGCH *a, LONGLONGCH *b) +{ + _asm + { + mov edi,a + mov esi,b + mov eax,[esi] + mov edx,[esi+4] + mov [edi],eax + mov [edi+4],edx + } +} + +/* NEGATE */ + +static void NEG_LL(LONGLONGCH *a) +{ + _asm + { + mov esi,a + not dword ptr[esi] + not dword ptr[esi+4] + add dword ptr[esi],1 + adc dword ptr[esi+4],0 + } +} + +/* ASR */ + +static void ASR_LL(LONGLONGCH *a, int shift) +{ + _asm + { + mov esi,a + mov eax,shift + and eax,eax + jle asrdn + asrlp: + sar dword ptr[esi+4],1 + rcr dword ptr[esi],1 + dec eax + jne asrlp + asrdn: + } +} + +/* Convert int to LONGLONGCH */ + +static void IntToLL(LONGLONGCH *a, int *b) +{ + _asm + { + mov esi,b + mov edi,a + mov eax,[esi] + cdq + mov [edi],eax + mov [edi+4],edx + } +} + +/* + + Fixed Point Multiply. + + + 16.16 * 16.16 -> 16.16 + or + 16.16 * 0.32 -> 0.32 + + A proper version of this function ought to read + 16.16 * 16.16 -> 32.16 + but this would require a long long result + + Algorithm: + + Take the mid 32 bits of the 64 bit result + +*/ + +/* + These functions have been checked for suitability for + a Pentium and look as if they would work adequately. + Might be worth a more detailed look at optimising + them though. +*/ + +static int MUL_FIXED(int a, int b) +{ + int retval; + _asm + { + mov eax,a + imul b + shrd eax,edx,16 + mov retval,eax + } + return retval; +} + +/* + + Fixed Point Divide - returns a / b + +*/ + +static int DIV_FIXED(int a, int b) +{ + int retval; + _asm + { + mov eax,a + cdq + rol eax,16 + mov dx,ax + xor ax,ax + idiv b + mov retval,eax + } + return retval; +} + +/* + + Multiply and Divide Functions. + +*/ + + +/* + + 32/32 division + + This macro is a function on some other platforms + +*/ + +#define DIV_INT(a, b) ((a) / (b)) + +/* + + A Narrowing 64/32 Division + +*/ + +static int NarrowDivide(LONGLONGCH *a, int b) +{ + int retval; + _asm + { + mov esi,a + mov eax,[esi] + mov edx,[esi+4] + idiv b + mov retval,eax + } + return retval; +} + +/* + + This function performs a Widening Multiply followed by a Narrowing Divide. + + a = (a * b) / c + +*/ + +static int WideMulNarrowDiv(int a, int b, int c) +{ + int retval; + _asm + { + mov eax,a + imul b + idiv c + mov retval,eax + } + return retval; +} + +/* + + Function to rotate a VECTORCH using a MATRIXCH + + This is the C function + + x = MUL_FIXED(m->mat11, v->vx); + x += MUL_FIXED(m->mat21, v->vy); + x += MUL_FIXED(m->mat31, v->vz); + + y = MUL_FIXED(m->mat12, v->vx); + y += MUL_FIXED(m->mat22, v->vy); + y += MUL_FIXED(m->mat32, v->vz); + + z = MUL_FIXED(m->mat13, v->vx); + z += MUL_FIXED(m->mat23, v->vy); + z += MUL_FIXED(m->mat33, v->vz); + + v->vx = x; + v->vy = y; + v->vz = z; + + This is the MUL_FIXED inline assembler function + + imul edx + shrd eax,edx,16 + + +typedef struct matrixch { + + int mat11; 0 + int mat12; 4 + int mat13; 8 + + int mat21; 12 + int mat22; 16 + int mat23; 20 + + int mat31; 24 + int mat32; 28 + int mat33; 32 + +} MATRIXCH; + +*/ + +static void RotateVector_ASM(VECTORCH *v, MATRIXCH *m) +{ + _asm + { + mov esi,v + mov edi,m + + mov eax,[edi + 0] + imul DWORD PTR [esi + 0] + shrd eax,edx,16 + mov ecx,eax + mov eax,[edi + 12] + imul DWORD PTR [esi + 4] + shrd eax,edx,16 + add ecx,eax + mov eax,[edi + 24] + imul DWORD PTR [esi + 8] + shrd eax,edx,16 + add ecx,eax + + mov eax,[edi + 4] + imul DWORD PTR [esi + 0] + shrd eax,edx,16 + mov ebx,eax + mov eax,[edi + 16] + imul DWORD PTR [esi + 4] + shrd eax,edx,16 + add ebx,eax + mov eax,[edi + 28] + imul DWORD PTR [esi + 8] + shrd eax,edx,16 + add ebx,eax + + mov eax,[edi + 8] + imul DWORD PTR [esi + 0] + shrd eax,edx,16 + mov ebp,eax + mov eax,[edi + 20] + imul DWORD PTR [esi + 4] + shrd eax,edx,16 + add ebp,eax + mov eax,[edi + 32] + imul DWORD PTR [esi + 8] + shrd eax,edx,16 + add ebp,eax + + mov [esi + 0],ecx + mov [esi + 4],ebx + mov [esi + 8],ebp + } +} + +/* + + Here is the same function, this time copying the result to a second vector + +*/ + +static void RotateAndCopyVector_ASM(VECTORCH *v1, VECTORCH *v2, MATRIXCH *m) +{ + _asm + { + mov esi,v1 + mov edi,m + + mov eax,[edi + 0] + imul DWORD PTR [esi + 0] + shrd eax,edx,16 + mov ecx,eax + mov eax,[edi + 12] + imul DWORD PTR [esi + 4] + shrd eax,edx,16 + add ecx,eax + mov eax,[edi + 24] + imul DWORD PTR [esi + 8] + shrd eax,edx,16 + add ecx,eax + + mov eax,[edi + 4] + imul DWORD PTR [esi + 0] + shrd eax,edx,16 + mov ebx,eax + mov eax,[edi + 16] + imul DWORD PTR [esi + 4] + shrd eax,edx,16 + add ebx,eax + mov eax,[edi + 28] + imul DWORD PTR [esi + 8] + shrd eax,edx,16 + add ebx,eax + + mov eax,[edi + 8] + imul DWORD PTR [esi + 0] + shrd eax,edx,16 + mov ebp,eax + mov eax,[edi + 20] + imul DWORD PTR [esi + 4] + shrd eax,edx,16 + add ebp,eax + mov eax,[edi + 32] + imul DWORD PTR [esi + 8] + shrd eax,edx,16 + add ebp,eax + + mov edx,v2 + mov [edx + 0],ecx + mov [edx + 4],ebx + mov [edx + 8],ebp + } +} + +#if (SupportFPMathsFunctions || SupportFPSquareRoot) + +/* + + Square Root + + Returns the Square Root of a 32-bit number + +*/ + +static long temp; +static long temp2; + +static int SqRoot32(int A) +{ + _asm + { + finit + fild A + fsqrt + fistp temp2 + fwait + } + return (int)temp2; +} + +#endif + + +/* + + This may look ugly (it is) but it is a MUCH faster way to convert "float" into "int" than + the function call "CHP" used by the WATCOM compiler. + +*/ + +static float fptmp; +static int itmp; + +static void FloatToInt(void) +{ + _asm + { + fld fptmp + fistp itmp + } +} + +/* + + This macro makes usage of the above function easier and more elegant + +*/ + +#define f2i(a, b) { \ +fptmp = (b); \ +FloatToInt(); \ +a = itmp;} + +#else /* other compiler ? */ + +#error "Unknown compiler" + +#endif + + +/* These functions are in plspecfn.c */ + +int WideMul2NarrowDiv(int a, int b, int c, int d, int e); +int _Dot(VECTORCH *vptr1, VECTORCH *vptr2); +void MakeV(VECTORCH *v1, VECTORCH *v2, VECTORCH *v3); +void AddV(VECTORCH *v1, VECTORCH *v2); +void RotVect(VECTORCH *v, MATRIXCH *m); +void CopyClipPoint(CLIP_POINT *cp1, CLIP_POINT *cp2); + +#if SUPPORT_MMX + +#define RotateVector(v,m) (use_mmx_math ? MMX_VectorTransform((v),(m)) : _RotateVector((v),(m))) +#define RotateAndCopyVector(v_in,v_out,m) (use_mmx_math ? MMX_VectorTransformed((v_out),(v_in),(m)) : _RotateAndCopyVector((v_in),(v_out),(m))) +#define Dot(v1,v2) (use_mmx_math ? MMXInline_VectorDot((v1),(v2)) : _Dot((v1),(v2))) +#define DotProduct(v1,v2) (use_mmx_math ? MMX_VectorDot((v1),(v2)) : _DotProduct((v1),(v2))) + +#else /* ! SUPPORT_MMX */ + +#define RotateVector(v,m) (_RotateVector((v),(m))) +#define RotateAndCopyVector(v_in,v_out,m) (_RotateAndCopyVector((v_in),(v_out),(m))) +#define Dot(v1,v2) (_Dot((v1),(v2))) +#define DotProduct(v1,v2) (_DotProduct((v1),(v2))) + +#endif /* ? SUPPORT_MMX */ + +#ifdef __cplusplus +} +#endif + +#define INLINE_INCLUDED +#endif + diff --git a/3dc/win95/KRENDER.H b/3dc/win95/KRENDER.H new file mode 100644 index 0000000..ebd5dc1 --- /dev/null +++ b/3dc/win95/KRENDER.H @@ -0,0 +1,55 @@ +/* If this define is set to a non-zero value then the new scandraws will be used */ +#define KRENDER_ON 1 + +/* prototypes of the replacement scandraw functions */ +extern void KR_ScanDraw_Item_2dTexturePolygon_VideoModeType_8(int *itemptr); +extern void KR_ScanDraw_Item_Gouraud2dTexturePolygon_VideoModeType_8(int *itemptr); +extern void KR_ScanDraw_Item_Gouraud3dTexturePolygon_Linear_S_VideoModeType_8(int *itemptr); +extern void MotionTrackerRotateBlit(void); +extern void MotionTrackerRotateBlit8(void); + + +/*KJL***************************************************** +* Palette fading; a value of 65536 corresponds to normal * +* palette, 0 is completely other (eg. all white). * +*****************************************************KJL*/ +extern void SetPaletteFadeLevel(int fadeLevel); +extern void FadeBetweenPalettes(unsigned char *palPtr, int fadeLevel); +extern void FadePaletteToWhite(unsigned char *palPtr,int fadeLevel); + +/*KJL********************************************* +* Fill the screen with black & flip then repeat. * +*********************************************KJL*/ +extern void BlankScreen(void); + + +/* KJL 16:06:24 04/04/97 - To choose between laced and full screen modes */ +extern int KRenderDrawMode; + + + + + + +extern void KDraw_Item_GouraudPolygon(int *itemptr); +extern void KDraw_Item_2dTexturePolygon(int *itemptr); +extern void KDraw_Item_Gouraud2dTexturePolygon(int *itemptr); +extern void KDraw_Item_Gouraud3dTexturePolygon(int *itemptr); + + + + + + + + + + + + +extern void MakeViewingWindowSmaller(void); +extern void MakeViewingWindowLarger(void); + +/* routines to draw a star filled sky */ +extern void CreateStarArray(void); +extern void DrawStarfilledSky(void); \ No newline at end of file diff --git a/3dc/win95/Krender.c b/3dc/win95/Krender.c new file mode 100644 index 0000000..a52c1d5 --- /dev/null +++ b/3dc/win95/Krender.c @@ -0,0 +1,2830 @@ +/*KJL********************************************************************* +* krender.c - Kevin's scandrawing code. (New render, new danger.) * +* * +* The new scandraws are called by patching the functions below into the * +* jumptables used in item.c. If the KRENDER_ON flag in krender.h is zero * +* then the old scandraws will be used. * +*********************************************************************KJL*/ + +/* this file is a bit messy at the moment, but I'll be back later... */ +#include "3dc.h" +#include "inline.h" +#include "module.h" +#include "gamedef.h" +#include "krender.h" +#include "vision.h" + +#define UseLocalAssert Yes +#include "ourasert.h" + +#define PENTIUM_PROFILING_ON 0 +#if PENTIUM_PROFILING_ON +#include "pentime.h" +#else +#define ProfileStart(); +#define ProfileStop(x); +#endif + +int ReciprocalTable[321]; +#if 1 +#define DIVIDE(a,b) ((a)/(b)) +#else +#define DIVIDE(a,b) (MUL_FIXED((a),ReciprocalTable[(b)])) +#endif + + +int Transparent; + +/* assembler fns */ +extern void ScanDraw2D_Gouraud(void); +extern void ScanDraw2D_GouraudTransparent(void); +extern void ScanDraw2D_VAlignedTransparent(void); +extern void ScanDraw2D_VAlignedOpaque(void); +extern void ScanDraw2D_Transparent(void); +extern void ScanDraw2D_TransparentLit(void); +extern void ScanDraw2D_Opaque(void); +extern void ScanDraw_GouraudScan(void); +extern void ScanDrawF3D_Gouraud(void); + +/* globals accessed by the assembler routines */ +unsigned char *SCASM_Lighting; +unsigned char *SCASM_Destination; +unsigned char *SCASM_Bitmap; +int SCASM_StartU; +int SCASM_StartV; +int SCASM_StartI; +int SCASM_DeltaU; +int SCASM_DeltaV; +int SCASM_DeltaI; +int SCASM_ScanLength; +int SCASM_ShadingTableSize; +int SCASM_TextureDeltaScan; + +/* things from item.c */ +extern int NumScans; +extern int ItemColour; +extern IMAGEHEADER *ImageHeaderPtrs[MaxImages]; +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; +extern unsigned char *TextureLightingTable; +extern int MIP_Index; +extern int ScanData[maxpolys*maxscansize]; +extern unsigned char *ScreenBuffer; +extern long BackBufferPitch; + +void Draw_Gouraud3dTexture_Spans(int *itemptr); + +int KRenderDrawMode = 0; + +/***********/ + +void KR_ScanDraw_Item_Gouraud2dTexturePolygon_VideoModeType_8(int *itemptr) +{ + POLYHEADER *pheader = (POLYHEADER *) itemptr; + I_GOURAUD2DTEXTUREPOLYGON_SCAN *sptr; + + if(NumScans) + { + int y = NumScans; + /* Get the Image Data required for the Draw */ + { + IMAGEHEADER *ImageHdr; + { + int TxIndex = ItemColour & ClrTxDefn; + ImageHdr = ImageHeaderPtrs[TxIndex]; + } + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip) + { + TEXTURE **TxImagePtr = &ImageHdr->ImagePtr; + SCASM_Bitmap = TxImagePtr[MIP_Index]; + GLOBALASSERT(SCASM_Bitmap); + SCASM_TextureDeltaScan = ImageHdr->ImageWidth >> MIP_Index; + #if MIP_ROUNDUP + if (ImageHdr->ImageWidth & (1<ImageWidth; + SCASM_Bitmap = ImageHdr->ImagePtr; + GLOBALASSERT(SCASM_Bitmap); + } + } + SCASM_Lighting = TextureLightingTable; + + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_Raw256) SCASM_ShadingTableSize = 256; + else SCASM_ShadingTableSize = 64; + + sptr = (I_GOURAUD2DTEXTUREPOLYGON_SCAN *) ScanData; + do + { + int dx = sptr->ig2s_x2 - sptr->ig2s_x1; + if (dx>0 && !(sptr->ig2s_y & KRenderDrawMode) ) + { + /* Fixed Point U for Interpolation */ + { + int StartU = sptr->ig2s_u1; + SCASM_DeltaU = DIVIDE((sptr->ig2s_u2 - StartU),dx); + SCASM_StartU = StartU; + } + + /* Fixed Point V for Interpolation */ + { + int StartV = sptr->ig2s_v1; + SCASM_DeltaV = DIVIDE((sptr->ig2s_v2 - StartV),dx); + SCASM_StartV = StartV; + } + /* Fixed Point I for Interpolation */ + { + int StartI = sptr->ig2s_c1; + SCASM_DeltaI = DIVIDE((sptr->ig2s_c2 - StartI),dx); + SCASM_StartI = StartI; + } + /* Draw the Gouraud 2d Texture Scan */ + + SCASM_Destination = ScreenBuffer + (sptr->ig2s_y * BackBufferPitch) + sptr->ig2s_x1; + SCASM_ScanLength = dx; + + if(pheader->PolyFlags & iflag_ignore0) + { + ScanDraw2D_GouraudTransparent(); + } + else + { + ScanDraw2D_Gouraud(); + } + } + sptr++; + y--; + } + while(y); + } + +} + +void Draw3DScan(I_GOURAUD3DTEXTUREPOLYGON_SCAN *scanPtr, POLYHEADER *pheader) +{ + int dx = scanPtr->ig3s_x2 - scanPtr->ig3s_x1; + + if(dx > 0) + { + float uf; + float vf; + float uf2; + float vf2; + /* Get start and end UVs */ + { + float ooz1; + ooz1 = 65536.0 / scanPtr->ig3s_z1; + uf = scanPtr->ig3s_u1 * ooz1; + vf = scanPtr->ig3s_v1 * ooz1; + } + { + float ooz2; + ooz2 = 65536.0 / scanPtr->ig3s_z2; + uf2 = scanPtr->ig3s_u2 * ooz2; + vf2 = scanPtr->ig3s_v2 * ooz2; + } + if ( (uf>16700000.0) + ||(uf<0.0) + ||(vf>16700000.0) + ||(vf<0.0) ) + { + textprint("WARNING: UV coords invalid\n"); + // LOCALASSERT(0); + return; + } + if ( (uf2>16700000.0) + ||(uf2<0.0) + ||(vf2>16700000.0) + ||(vf2<0.0) ) + { + textprint("WARNING: UV coords invalid\n"); + // LOCALASSERT(0); + return; + } + /* For UV interpolation */ + f2i(SCASM_StartU,uf); + f2i(SCASM_StartV,vf); + { + int EndU,EndV; + f2i(EndU,uf2); + f2i(EndV,vf2); + SCASM_DeltaU =(EndU-SCASM_StartU)/dx; + SCASM_DeltaV =(EndV-SCASM_StartV)/dx; + } + + /* Fixed Point I for Interpolation */ + { + int StartI = scanPtr->ig3s_c1; + SCASM_DeltaI = (scanPtr->ig3s_c2 - StartI)/dx; + SCASM_StartI = StartI; + } + + /* Draw the 3d Texture Scan */ + SCASM_Destination = ScreenBuffer + (scanPtr->ig3s_y * BackBufferPitch) + scanPtr->ig3s_x1; + SCASM_ScanLength = dx; + + if(pheader->PolyFlags & iflag_ignore0) + { + ScanDraw2D_GouraudTransparent(); + } + else + { + ScanDraw2D_Gouraud(); + } + } +} + + +void KR_ScanDraw_Item_Gouraud3dTexturePolygon_Linear_S_VideoModeType_8(int *itemptr) +{ + POLYHEADER *pheader = (POLYHEADER *) itemptr; + + int num_scans_s; + I_GOURAUD3DTEXTUREPOLYGON_SCAN *sptr_array_ptr; + I_GOURAUD3DTEXTUREPOLYGON_SCAN *next_free_sptr; + I_GOURAUD3DTEXTUREPOLYGON_SCAN sptr_array[lin_s_max + 1]; + int StillSubdividing; + int i; + + + if(NumScans) + { + I_GOURAUD3DTEXTUREPOLYGON_SCAN *sptr; + int y; + /* Get the Image Data required for the Draw */ + { + IMAGEHEADER *ImageHdr; + { + int TxIndex = ItemColour & ClrTxDefn; + ImageHdr = ImageHeaderPtrs[TxIndex]; + } + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip) + { + TEXTURE **TxImagePtr = &ImageHdr->ImagePtr; + SCASM_Bitmap = TxImagePtr[MIP_Index]; + GLOBALASSERT(SCASM_Bitmap); + SCASM_TextureDeltaScan = ImageHdr->ImageWidth >> MIP_Index; + #if MIP_ROUNDUP + if (ImageHdr->ImageWidth & (1<ImageWidth; + SCASM_Bitmap = ImageHdr->ImagePtr; + GLOBALASSERT(SCASM_Bitmap); + } + } + SCASM_Lighting = TextureLightingTable; + + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_Raw256) SCASM_ShadingTableSize = 256; + else SCASM_ShadingTableSize = 64; + + + sptr = (I_GOURAUD3DTEXTUREPOLYGON_SCAN *) ScanData; + + for(y = NumScans; y!=0; y--) + { + int dx = sptr->ig3s_x2 - sptr->ig3s_x1; + if (dx>0 && !(sptr->ig3s_y & KRenderDrawMode) ) + { + float zmax, zmin, z_ratio; + + /* Have a look at the z-ratio */ + if(sptr->ig3s_z1 > sptr->ig3s_z2) + { + zmax = sptr->ig3s_z1; + zmin = sptr->ig3s_z2; + } + else + { + zmax = sptr->ig3s_z2; + zmin = sptr->ig3s_z1; + } + z_ratio = (zmax * 256); + + + /* Draw if the z ratio is inside the threshold */ + if(z_ratio < lin_s_zthr*zmin) + { + Draw3DScan(sptr,pheader); + } + /* Else subdivide until scan segments are inside threshold */ + else + { + /* Copy the current scan to the subdivision array */ + sptr_array_ptr = sptr_array; + num_scans_s = 1; + + sptr_array_ptr->ig3s_u1 = sptr->ig3s_u1; + sptr_array_ptr->ig3s_v1 = sptr->ig3s_v1; + sptr_array_ptr->ig3s_z1 = sptr->ig3s_z1; + sptr_array_ptr->ig3s_c1 = sptr->ig3s_c1; + + sptr_array_ptr->ig3s_u2 = sptr->ig3s_u2; + sptr_array_ptr->ig3s_v2 = sptr->ig3s_v2; + sptr_array_ptr->ig3s_z2 = sptr->ig3s_z2; + sptr_array_ptr->ig3s_c2 = sptr->ig3s_c2; + + sptr_array_ptr->ig3s_x1 = sptr->ig3s_x1; + sptr_array_ptr->ig3s_x2 = sptr->ig3s_x2; + + sptr_array_ptr->ig3s_y = sptr->ig3s_y; + + + /* Subdivide until no further divisions are needed */ + + next_free_sptr = sptr_array_ptr + 1; + do + { + sptr_array_ptr = sptr_array; + + StillSubdividing = No; /* Assume not */ + + for(i = num_scans_s; i!=0; i--) + { + #if 0 + /* z ratio of this scan */ + if(sptr_array_ptr->ig3s_z1 > sptr_array_ptr->ig3s_z2) + { + z_ratio = (sptr_array_ptr->ig3s_z1 * 256) / + sptr_array_ptr->ig3s_z2; + } + else + { + z_ratio = (sptr_array_ptr->ig3s_z2 * 256) / + sptr_array_ptr->ig3s_z1; + } + /* Is it within the threshold? */ + if(z_ratio > lin_s_zthr && num_scans_s < lin_s_max) + #endif + int overThreshold=0; + /* z ratio of this scan */ + if(sptr_array_ptr->ig3s_z1 > sptr_array_ptr->ig3s_z2) + { + if ( (sptr_array_ptr->ig3s_z1 * 256) > (lin_s_zthr*sptr_array_ptr->ig3s_z2)) + overThreshold=1; + } + else + { + if ( (sptr_array_ptr->ig3s_z2 * 256) > (lin_s_zthr*sptr_array_ptr->ig3s_z1)) + overThreshold=1; + } + /* Is it within the threshold? */ + if(overThreshold && num_scans_s < lin_s_max) + { + int mid_x, mid_c; + float mid_u, mid_v, mid_z; + /* No - subdivide */ + StillSubdividing = Yes; + + mid_u = (sptr_array_ptr->ig3s_u1 + sptr_array_ptr->ig3s_u2) / 2; + + mid_v = (sptr_array_ptr->ig3s_v1 + sptr_array_ptr->ig3s_v2) / 2; + + mid_z = (sptr_array_ptr->ig3s_z1 + sptr_array_ptr->ig3s_z2) / 2; + + mid_c = (sptr_array_ptr->ig3s_c1 + sptr_array_ptr->ig3s_c2) / 2; + + mid_x = (sptr_array_ptr->ig3s_x1 + sptr_array_ptr->ig3s_x2) / 2; + + /* Create new scan */ + + next_free_sptr->ig3s_u1 = mid_u; + next_free_sptr->ig3s_v1 = mid_v; + next_free_sptr->ig3s_z1 = mid_z; + next_free_sptr->ig3s_c1 = mid_c; + next_free_sptr->ig3s_x1 = mid_x; + next_free_sptr->ig3s_u2 = sptr_array_ptr->ig3s_u2; + next_free_sptr->ig3s_v2 = sptr_array_ptr->ig3s_v2; + next_free_sptr->ig3s_z2 = sptr_array_ptr->ig3s_z2; + next_free_sptr->ig3s_c2 = sptr_array_ptr->ig3s_c2; + next_free_sptr->ig3s_x2 = sptr_array_ptr->ig3s_x2; + next_free_sptr->ig3s_y = sptr_array_ptr->ig3s_y; + /* Redefine old scan */ + + sptr_array_ptr->ig3s_u2 = mid_u; + sptr_array_ptr->ig3s_v2 = mid_v; + sptr_array_ptr->ig3s_z2 = mid_z; + sptr_array_ptr->ig3s_c2 = mid_c; + sptr_array_ptr->ig3s_x2 = mid_x; + + /* Update pointer and counter */ + + next_free_sptr++; + num_scans_s++; + + } + sptr_array_ptr++; + } + + } + while(StillSubdividing); + + /* Draw the scan array */ + sptr_array_ptr = sptr_array; + for(i = num_scans_s; i!=0; i--) + { + Draw3DScan(sptr_array_ptr,pheader); + sptr_array_ptr++; + } + } + } + sptr++; + } + } +} + + + +void KR_ScanDraw_Item_2dTexturePolygon_VideoModeType_8(int *itemptr) +{ + POLYHEADER *pheader = (POLYHEADER *) itemptr; + if(NumScans) + { + if(pheader->PolyFlags & iflag_nolight) + { + int y; + I_2DTEXTUREPOLYGON_SCAN *sptr = (I_2DTEXTUREPOLYGON_SCAN *) ScanData; + + /* Offset in Screen Buffer */ + { + IMAGEHEADER *ImageHdr; + { + int TxIndex = ItemColour & ClrTxDefn; + ImageHdr = ImageHeaderPtrs[TxIndex]; + } + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip) + { + TEXTURE **TxImagePtr = &ImageHdr->ImagePtr; + SCASM_Bitmap = TxImagePtr[MIP_Index]; + GLOBALASSERT(SCASM_Bitmap); + SCASM_TextureDeltaScan = ImageHdr->ImageWidth >> MIP_Index; + #if MIP_ROUNDUP + if (ImageHdr->ImageWidth & (1<ImageWidth; + SCASM_Bitmap = ImageHdr->ImagePtr; + GLOBALASSERT(SCASM_Bitmap); + } + } + + /* Get the Image Data required for the Draw */ + for(y=NumScans; y!=0; y--) + { + int dx = sptr->i2s_x2 - sptr->i2s_x1; + + if (dx>0 && !(sptr->i2s_y & KRenderDrawMode) ) + { + /* Fixed Point U for Interpolation */ + { + int StartU = sptr->i2s_u1; + SCASM_DeltaU = (sptr->i2s_u2 - StartU)/dx; + SCASM_StartU = StartU; + } + + /* Fixed Point V for Interpolation */ + { + int StartV = sptr->i2s_v1; + SCASM_DeltaV = (sptr->i2s_v2 - StartV)/dx; + SCASM_StartV = StartV; + } + + SCASM_Destination = ScreenBuffer + (sptr->i2s_y * BackBufferPitch) + sptr->i2s_x1; + SCASM_ScanLength = dx; + + + /* Is VDelta = 0? */ + if(SCASM_DeltaV == 0) + { + if(pheader->PolyFlags & iflag_ignore0) + { + ScanDraw2D_VAlignedTransparent(); + } + else + { + ScanDraw2D_VAlignedOpaque(); + } + + } + else + { + if(pheader->PolyFlags & iflag_ignore0) + { + ScanDraw2D_Transparent(); + } + else + { + ScanDraw2D_Opaque(); + } + } + } + sptr++; + } + } + #if 1 + else + { + int y; + I_2DTEXTUREPOLYGON_SCAN *sptr = (I_2DTEXTUREPOLYGON_SCAN *) ScanData; + /* Offset in Screen Buffer */ + { + IMAGEHEADER *ImageHdr; + { + int TxIndex = ItemColour & ClrTxDefn; + ImageHdr = ImageHeaderPtrs[TxIndex]; + } + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip) + { + TEXTURE **TxImagePtr = &ImageHdr->ImagePtr; + SCASM_Bitmap = TxImagePtr[MIP_Index]; + GLOBALASSERT(SCASM_Bitmap); + SCASM_TextureDeltaScan = ImageHdr->ImageWidth >> MIP_Index; + #if MIP_ROUNDUP + if (ImageHdr->ImageWidth & (1<ImageWidth; + SCASM_Bitmap = ImageHdr->ImagePtr; + GLOBALASSERT(SCASM_Bitmap); + } + } + SCASM_StartI = ItemColour >> TxDefn; + + SCASM_Lighting = TextureLightingTable; + + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_Raw256) SCASM_ShadingTableSize = 256; + else SCASM_ShadingTableSize = 64; + + + /* Get the Image Data required for the Draw */ + for(y=NumScans; y!=0; y--) + { + int dx = sptr->i2s_x2 - sptr->i2s_x1; + if (dx>0 && !(sptr->i2s_y & KRenderDrawMode) ) + { + /* Fixed Point U for Interpolation */ + { + int StartU = sptr->i2s_u1; + SCASM_DeltaU = (sptr->i2s_u2 - StartU)/dx; + SCASM_StartU = StartU; + } + + /* Fixed Point V for Interpolation */ + { + int StartV = sptr->i2s_v1; + SCASM_DeltaV = (sptr->i2s_v2 - StartV)/dx; + SCASM_StartV = StartV; + } + + SCASM_Destination = ScreenBuffer + (sptr->i2s_y * BackBufferPitch) + sptr->i2s_x1; + SCASM_ScanLength = dx; + + ScanDraw2D_TransparentLit(); + // PredatorScanDraw(); + } + sptr++; + } + + + } + #endif + } + +} +unsigned char LighterTable[255]; +int predatorTimer = 0; +void ScanDraw_CloakedScan(void) +{ + unsigned char *screen = SCASM_Destination; + int x = SCASM_ScanLength; + + unsigned char buffer[1000]; + do + { + buffer[x] = *screen++; + } + while(--x); + + screen = SCASM_Destination; + x = SCASM_ScanLength; + + if (FastRandom()&3==3 && x>2) + { + x--; + screen++; + } + if (FastRandom()&3==3 && x>2) + { + x--; + } + + do + { + { + extern sine[]; + extern cosine[]; + unsigned char colour; + int offset = (GetCos( ((x*2047)/SCASM_ScanLength + predatorTimer)&4095 )+65536)/2; + offset = MUL_FIXED(offset,offset); + colour = (buffer[SCASM_ScanLength-x+1]); + // colour = (buffer[x]); + #if 0 + int i; + for (i=0; i<=255;i++) + { + if (colour==*(TextureLightingTable + 256*200 + i)) break; + } + #endif + colour=*(TextureLightingTable + 256*(60+MUL_FIXED(4,GetCos(predatorTimer&4095)) ) + colour); + *screen++ = colour; + + } + } + while(--x); + +} +#if 0 +void PredatorScanDraw(void) +{ + unsigned char *screen = SCASM_Destination; + unsigned char *source; + + do + { + source = SCASM_Bitmap+ (SCASM_StartU>>16) + (SCASM_StartV>>16)*SCASM_TextureDeltaScan; + + *screen++ = *source++; + + SCASM_StartU += SCASM_DeltaU; + SCASM_StartV += SCASM_DeltaV; + } + while(--SCASM_ScanLength); + +} +#else +void PredatorScanDraw(void) +{ + unsigned char *screen = SCASM_Destination; + unsigned char *source; + int x = SCASM_ScanLength; + do + { + source = SCASM_Bitmap+ (SCASM_StartU>>16) + (SCASM_StartV>>16)*SCASM_TextureDeltaScan; + + if (*source) + { + extern sine[]; + extern cosine[]; + unsigned char colour = *(screen); + *screen = LighterTable[colour]; + } + screen++; + SCASM_StartU += SCASM_DeltaU; + SCASM_StartV += SCASM_DeltaV; + } + while(--x); + +} +#endif + +void Draw_Item_CloakedPolygon(int *itemptr) +{ + POLYHEADER *pheader = (POLYHEADER *)itemptr; + int minYVertex = 0; + int maxYVertex = 0; + int maxVertexNum = 0; + + { + I_GOURAUDPOLYGON_PT *vertexPtr = (I_GOURAUDPOLYGON_PT*)&pheader->Poly1stPt; + int minY = vertexPtr->i_y; + int maxY = vertexPtr->i_y; + vertexPtr++; + + do + { + maxVertexNum++; + + if (minY > vertexPtr->i_y) + { + minY = vertexPtr->i_y; + minYVertex = maxVertexNum; + } + else if (maxY < vertexPtr->i_y) + { + maxY = vertexPtr->i_y; + maxYVertex = maxVertexNum; + } + vertexPtr++; + } + while(vertexPtr->i_x != Term); + + } + + + /* Initialise the Scan Data Buffer */ + { + I_GOURAUDPOLYGON_PT *vertexPtr = (I_GOURAUDPOLYGON_PT*)&pheader->Poly1stPt; + I_GOURAUDPOLYGON_SCAN *polyScan; + int curVertex; + int SecondOpinion=0; + + NumScans=0; + /* scan out the right edge */ + polyScan = (I_GOURAUDPOLYGON_SCAN*)ScanData; + curVertex = minYVertex; + do + { + int height; + int i,x,y; + int deltaX,deltaI; + + int nextVertex = curVertex-1; + if (nextVertex<0) nextVertex = maxVertexNum; + + height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y; + if (height!=0) + { + int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x; + int contrast = vertexPtr[nextVertex].i_int - vertexPtr[curVertex].i_int; + + deltaX = (width<<16)/height; + deltaI = contrast/height; + + x = vertexPtr[curVertex].i_x<<16; + i = vertexPtr[curVertex].i_int; + + for (y=vertexPtr[curVertex].i_y; yigs_x2 = x>>16; + x+=deltaX; + polyScan->igs_c2 = i; + i+=deltaI; + + polyScan->igs_y = y; + NumScans++; + polyScan++; + } + } + curVertex--; + if (curVertex<0) curVertex = maxVertexNum; + + } + while(curVertex!=maxYVertex); + + /* scan out the left edge */ + polyScan = (I_GOURAUDPOLYGON_SCAN*)ScanData; + curVertex = minYVertex; + do + { + int height; + int i,x,y; + int deltaX,deltaI; + + int nextVertex = curVertex+1; + if (nextVertex>maxVertexNum) nextVertex = 0; + + height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y; + if (height!=0) + { + int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x; + int contrast = vertexPtr[nextVertex].i_int - vertexPtr[curVertex].i_int; + + deltaX = (width<<16)/height; + deltaI = contrast/height; + + x = vertexPtr[curVertex].i_x<<16; + i = vertexPtr[curVertex].i_int; + + for (y=vertexPtr[curVertex].i_y; yigs_x1 = x>>16; + x+=deltaX; + polyScan->igs_c1 = i; + i+=deltaI; + + SecondOpinion++; + polyScan++; + } + } + curVertex++; + if (curVertex>maxVertexNum) curVertex = 0; + + } + while(curVertex!=maxYVertex); + + if (SecondOpinionPolyColour; + I_GOURAUDPOLYGON_SCAN *polyScan; + polyScan = (I_GOURAUDPOLYGON_SCAN*)ScanData; + SCASM_Lighting = TextureLightingTable+colour; + SCASM_ShadingTableSize = 256; + + while(NumScans) + { + int dx = polyScan->igs_x2 - polyScan->igs_x1; + if (dx>0) + { + SCASM_Destination = ScreenBuffer+(polyScan->igs_y * BackBufferPitch) + polyScan->igs_x1; + SCASM_ScanLength = dx; + SCASM_DeltaI = (polyScan->igs_c2-polyScan->igs_c1)/dx; + SCASM_StartI = polyScan->igs_c1; + ScanDraw_CloakedScan(); + } + NumScans--; + polyScan++; + } + } +} +#if 1 +void KDraw_Item_GouraudPolygon(int *itemptr) +{ + POLYHEADER *pheader = (POLYHEADER *)itemptr; + int minYVertex = 0; + int maxYVertex = 0; + int maxVertexNum = 0; + + { + I_GOURAUDPOLYGON_PT *vertexPtr = (I_GOURAUDPOLYGON_PT*)&pheader->Poly1stPt; + int minY = vertexPtr->i_y; + int maxY = vertexPtr->i_y; + vertexPtr++; + + do + { + maxVertexNum++; + + if (minY > vertexPtr->i_y) + { + minY = vertexPtr->i_y; + minYVertex = maxVertexNum; + } + else if (maxY < vertexPtr->i_y) + { + maxY = vertexPtr->i_y; + maxYVertex = maxVertexNum; + } + vertexPtr++; + } + while(vertexPtr->i_x != Term); + + } + + + /* Initialise the Scan Data Buffer */ + { + I_GOURAUDPOLYGON_PT *vertexPtr = (I_GOURAUDPOLYGON_PT*)&pheader->Poly1stPt; + I_GOURAUDPOLYGON_SCAN *polyScan; + int curVertex; + int SecondOpinion=0; + + NumScans=0; + /* scan out the right edge */ + polyScan = (I_GOURAUDPOLYGON_SCAN*)ScanData; + curVertex = minYVertex; + do + { + int height; + int i,x,y; + int deltaX,deltaI; + + int nextVertex = curVertex-1; + if (nextVertex<0) nextVertex = maxVertexNum; + + height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y; + if (height!=0) + { + int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x; + int contrast = vertexPtr[nextVertex].i_int - vertexPtr[curVertex].i_int; + + deltaX = (width<<16)/height; + deltaI = contrast/height; + + x = vertexPtr[curVertex].i_x<<16; + i = vertexPtr[curVertex].i_int; + + for (y=vertexPtr[curVertex].i_y; yigs_x2 = x>>16; + x+=deltaX; + polyScan->igs_c2 = i; + i+=deltaI; + + polyScan->igs_y = y; + NumScans++; + polyScan++; + } + } + curVertex--; + if (curVertex<0) curVertex = maxVertexNum; + + } + while(curVertex!=maxYVertex); + + /* scan out the left edge */ + polyScan = (I_GOURAUDPOLYGON_SCAN*)ScanData; + curVertex = minYVertex; + do + { + int height; + int i,x,y; + int deltaX,deltaI; + + int nextVertex = curVertex+1; + if (nextVertex>maxVertexNum) nextVertex = 0; + + height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y; + if (height!=0) + { + int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x; + int contrast = vertexPtr[nextVertex].i_int - vertexPtr[curVertex].i_int; + + deltaX = (width<<16)/height; + deltaI = contrast/height; + + x = vertexPtr[curVertex].i_x<<16; + i = vertexPtr[curVertex].i_int; + + for (y=vertexPtr[curVertex].i_y; yigs_x1 = x>>16; + x+=deltaX; + polyScan->igs_c1 = i; + i+=deltaI; + + SecondOpinion++; + polyScan++; + } + } + curVertex++; + if (curVertex>maxVertexNum) curVertex = 0; + + } + while(curVertex!=maxYVertex); + + if (SecondOpinionPolyColour; + I_GOURAUDPOLYGON_SCAN *polyScan; + polyScan = (I_GOURAUDPOLYGON_SCAN*)ScanData; + SCASM_Lighting = TextureLightingTable+colour; + SCASM_ShadingTableSize = 256; + + while(NumScans) + { + int dx = polyScan->igs_x2 - polyScan->igs_x1; + if (dx>0) + { + SCASM_Destination = ScreenBuffer+(polyScan->igs_y * BackBufferPitch) + polyScan->igs_x1; + SCASM_ScanLength = dx; + SCASM_DeltaI = (polyScan->igs_c2-polyScan->igs_c1)/dx; + SCASM_StartI = polyScan->igs_c1; + ScanDraw_GouraudScan(); + } + NumScans--; + polyScan++; + } + } +} +void KDraw_Item_2dTexturePolygon(int *itemptr) +{ + + POLYHEADER *pheader = (POLYHEADER *) itemptr; + int TxIndex; + IMAGEHEADER *ImageHdr; + ItemColour = pheader->PolyColour; + + TxIndex = ItemColour & ClrTxDefn; + ImageHdr = ImageHeaderPtrs[TxIndex]; + + + /* Colour */ + + /* If MIP Mapping, calculate the scale */ + + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip) + { + I_2DTEXTUREPOLYGON_PT *vector1; + I_2DTEXTUREPOLYGON_PT *vector2; + I_2DTEXTUREPOLYGON_PT *vector3; + int mip1, mip2; + int xyd, uvd; + VECTOR2D s0, s1; + VECTOR2D t0, t1; + + + /* Screen and Texture Space Vectors */ + /* Express the "uvd / xyd" ratio as a binary scale */ + + vector1 = (I_2DTEXTUREPOLYGON_PT *) &pheader->Poly1stPt; + vector2 = &vector1[1]; + vector3 = &vector1[2]; + + + /* Vector 1 */ + + s0.vx = vector1->i_x; + s0.vy = vector1->i_y; + s1.vx = vector2->i_x; + s1.vy = vector2->i_y; + + t0.vx = vector1->i_u >> 16; + t0.vy = vector1->i_v >> 16; + t1.vx = vector2->i_u >> 16; + t1.vy = vector2->i_v >> 16; + + xyd = FandVD_Distance_2d(&s0, &s1); + uvd = FandVD_Distance_2d(&t0, &t1); + + mip1 = FindShift32(uvd, xyd); + + + /* Vector 2 */ + + s0.vx = vector2->i_x; + s0.vy = vector2->i_y; + s1.vx = vector3->i_x; + s1.vy = vector3->i_y; + + t0.vx = t1.vx; + t0.vy = t1.vy; + t1.vx = vector3->i_u >> 16; + t1.vy = vector3->i_v >> 16; + + xyd = FandVD_Distance_2d(&s0, &s1); + uvd = FandVD_Distance_2d(&t0, &t1); + + mip2 = FindShift32(uvd, xyd); + + + /* Choose the larger of the two */ + + if(pheader->PolyFlags & iflag_no_mip) { + + MIP_Index = 0; + + } + + else { + + #if UseMIPMax + if(mip1 > mip2) + MIP_Index = mip1; + else + MIP_Index = mip2; + #endif + + #if UseMIPMin + if(mip1 > mip2) + MIP_Index = mip2; + else + MIP_Index = mip1; + #endif + + #if UseMIPAvg + MIP_Index = (mip1 + mip2) >> 1; + #endif + + } + + + /* Clamp "MIP_Index" */ + + #if MIP_INDEX_SUBTRACT + + MIP_Index -= MIP_INDEX_SUBTRACT; + if(MIP_Index < 0) MIP_Index = 0; + else if(MIP_Index > 6) MIP_Index = 6; + + #else + + if(MIP_Index > 6) MIP_Index = 6; + + #endif + + } + + { + int minYVertex = 0; + int maxYVertex = 0; + int maxVertexNum = 0; + + { + I_2DTEXTUREPOLYGON_PT *vertexPtr = (I_2DTEXTUREPOLYGON_PT*)&pheader->Poly1stPt; + int minY = vertexPtr->i_y; + int maxY = vertexPtr->i_y; + + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip) + { + vertexPtr->i_u >>= MIP_Index; + vertexPtr->i_v >>= MIP_Index; + } + vertexPtr++; + + do + { + maxVertexNum++; + + if (minY > vertexPtr->i_y) + { + minY = vertexPtr->i_y; + minYVertex = maxVertexNum; + } + else if (maxY < vertexPtr->i_y) + { + maxY = vertexPtr->i_y; + maxYVertex = maxVertexNum; + } + + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip) + { + vertexPtr->i_u >>= MIP_Index; + vertexPtr->i_v >>= MIP_Index; + } + + vertexPtr++; + } + while(vertexPtr->i_x != Term); + + } + + + /* Initialise the Scan Data Buffer */ + { + I_2DTEXTUREPOLYGON_PT *vertexPtr = (I_2DTEXTUREPOLYGON_PT*)&pheader->Poly1stPt; + I_2DTEXTUREPOLYGON_SCAN *polyScan; + int curVertex; + int SecondOpinion = 0; + + NumScans=0; + /* scan out the right edge */ + polyScan = (I_2DTEXTUREPOLYGON_SCAN*)ScanData; + curVertex = minYVertex; + do + { + int height; + + int nextVertex = curVertex-1; + if (nextVertex<0) nextVertex = maxVertexNum; + + height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y; + if (height!=0) + { + int x,y,u,v; + int deltaX,deltaU,deltaV; + int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x; + int widthU = vertexPtr[nextVertex].i_u - vertexPtr[curVertex].i_u; + int widthV = vertexPtr[nextVertex].i_v - vertexPtr[curVertex].i_v; + + deltaX = (width<<16)/height; + deltaU = widthU/height; + deltaV = widthV/height; + + x = vertexPtr[curVertex].i_x<<16; + u = vertexPtr[curVertex].i_u; + v = vertexPtr[curVertex].i_v; + + for (y=vertexPtr[curVertex].i_y; yi2s_x2 = x>>16; + x+=deltaX; + polyScan->i2s_u2 = u; + u+=deltaU; + polyScan->i2s_v2 = v; + v+=deltaV; + + polyScan->i2s_y = y; + NumScans++; + polyScan++; + } + } + curVertex--; + if (curVertex<0) curVertex = maxVertexNum; + + } + while(curVertex!=maxYVertex); + + /* scan out the left edge */ + polyScan = (I_2DTEXTUREPOLYGON_SCAN*)ScanData; + curVertex = minYVertex; + do + { + int height; + + int nextVertex = curVertex+1; + if (nextVertex>maxVertexNum) nextVertex = 0; + + height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y; + if (height!=0) + { + int x,y,u,v; + int deltaX,deltaU,deltaV; + int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x; + int widthU = vertexPtr[nextVertex].i_u - vertexPtr[curVertex].i_u; + int widthV = vertexPtr[nextVertex].i_v - vertexPtr[curVertex].i_v; + + deltaX = (width<<16)/height; + deltaU = widthU/height; + deltaV = widthV/height; + + x = vertexPtr[curVertex].i_x<<16; + u = vertexPtr[curVertex].i_u; + v = vertexPtr[curVertex].i_v; + + for (y=vertexPtr[curVertex].i_y; yi2s_x1 = x>>16; + x+=deltaX; + polyScan->i2s_u1 = u; + u+=deltaU; + polyScan->i2s_v1 = v; + v+=deltaV; + + SecondOpinion++; + polyScan++; + } + } + curVertex++; + if (curVertex>maxVertexNum) curVertex = 0; + + } + while(curVertex!=maxYVertex); + + if (SecondOpinionPolyColour; + + TxIndex = ItemColour & ClrTxDefn; + ImageHdr = ImageHeaderPtrs[TxIndex]; + + + + /* Colour */ + + + /* If MIP Mapping, calculate the scale */ + + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip) + { + I_GOURAUD2DTEXTUREPOLYGON_PT *vector1; + I_GOURAUD2DTEXTUREPOLYGON_PT *vector2; + I_GOURAUD2DTEXTUREPOLYGON_PT *vector3; + int mip1, mip2; + int xyd, uvd; + VECTOR2D s0, s1; + VECTOR2D t0, t1; + + + /* Screen and Texture Space Vectors */ + /* Express the "uvd / xyd" ratio as a binary scale */ + + vector1 = (I_GOURAUD2DTEXTUREPOLYGON_PT *) &pheader->Poly1stPt; + vector2 = &vector1[1]; + vector3 = &vector1[2]; + + + /* Vector 1 */ + + s0.vx = vector1->i_x; + s0.vy = vector1->i_y; + s1.vx = vector2->i_x; + s1.vy = vector2->i_y; + + t0.vx = vector1->i_u >> 16; + t0.vy = vector1->i_v >> 16; + t1.vx = vector2->i_u >> 16; + t1.vy = vector2->i_v >> 16; + + xyd = FandVD_Distance_2d(&s0, &s1); + uvd = FandVD_Distance_2d(&t0, &t1); + + mip1 = FindShift32(uvd, xyd); + + + /* Vector 2 */ + + s0.vx = vector2->i_x; + s0.vy = vector2->i_y; + s1.vx = vector3->i_x; + s1.vy = vector3->i_y; + + t0.vx = t1.vx; + t0.vy = t1.vy; + t1.vx = vector3->i_u >> 16; + t1.vy = vector3->i_v >> 16; + + xyd = FandVD_Distance_2d(&s0, &s1); + uvd = FandVD_Distance_2d(&t0, &t1); + + mip2 = FindShift32(uvd, xyd); + + + /* Choose the larger of the two */ + + if(pheader->PolyFlags & iflag_no_mip) { + + MIP_Index = 0; + + } + + else { + + #if UseMIPMax + if(mip1 > mip2) + MIP_Index = mip1; + else + MIP_Index = mip2; + #endif + + #if UseMIPMin + if(mip1 > mip2) + MIP_Index = mip2; + else + MIP_Index = mip1; + #endif + + #if UseMIPAvg + MIP_Index = (mip1 + mip2) >> 1; + #endif + + } + + + /* Clamp "MIP_Index" */ + + #if MIP_INDEX_SUBTRACT + + MIP_Index -= MIP_INDEX_SUBTRACT; + if(MIP_Index < 0) MIP_Index = 0; + else if(MIP_Index > 6) MIP_Index = 6; + + #else + + if(MIP_Index > 6) MIP_Index = 6; + + #endif + + } + + { + int minYVertex = 0; + int maxYVertex = 0; + int maxVertexNum = 0; + + { + I_GOURAUD2DTEXTUREPOLYGON_PT *vertexPtr = (I_GOURAUD2DTEXTUREPOLYGON_PT*)&pheader->Poly1stPt; + int minY = vertexPtr->i_y; + int maxY = vertexPtr->i_y; + + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip) + { + vertexPtr->i_u >>= MIP_Index; + vertexPtr->i_v >>= MIP_Index; + } + vertexPtr++; + + do + { + maxVertexNum++; + + if (minY > vertexPtr->i_y) + { + minY = vertexPtr->i_y; + minYVertex = maxVertexNum; + } + else if (maxY < vertexPtr->i_y) + { + maxY = vertexPtr->i_y; + maxYVertex = maxVertexNum; + } + + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip) + { + vertexPtr->i_u >>= MIP_Index; + vertexPtr->i_v >>= MIP_Index; + } + + vertexPtr++; + } + while(vertexPtr->i_x != Term); + + } + + + /* Initialise the Scan Data Buffer */ + { + I_GOURAUD2DTEXTUREPOLYGON_PT *vertexPtr = (I_GOURAUD2DTEXTUREPOLYGON_PT*)&pheader->Poly1stPt; + I_GOURAUD2DTEXTUREPOLYGON_SCAN *polyScan; + int curVertex; + int SecondOpinion=0; + + NumScans=0; + /* scan out the right edge */ + polyScan = (I_GOURAUD2DTEXTUREPOLYGON_SCAN*)ScanData; + curVertex = minYVertex; + do + { + int height; + + int nextVertex = curVertex-1; + if (nextVertex<0) nextVertex = maxVertexNum; + + height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y; + if (height!=0) + { + int i,x,y,u,v; + int deltaX,deltaI,deltaU,deltaV; + int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x; + int contrast = vertexPtr[nextVertex].i_i - vertexPtr[curVertex].i_i; + int widthU = vertexPtr[nextVertex].i_u - vertexPtr[curVertex].i_u; + int widthV = vertexPtr[nextVertex].i_v - vertexPtr[curVertex].i_v; + + deltaX = (width<<16)/height; + deltaI = contrast/height; + deltaU = widthU/height; + deltaV = widthV/height; + + x = vertexPtr[curVertex].i_x<<16; + i = vertexPtr[curVertex].i_i; + u = vertexPtr[curVertex].i_u; + v = vertexPtr[curVertex].i_v; + + for (y=vertexPtr[curVertex].i_y; yig2s_x2 = x>>16; + x+=deltaX; + polyScan->ig2s_c2 = i; + i+=deltaI; + polyScan->ig2s_u2 = u; + u+=deltaU; + polyScan->ig2s_v2 = v; + v+=deltaV; + + polyScan->ig2s_y = y; + NumScans++; + polyScan++; + } + } + curVertex--; + if (curVertex<0) curVertex = maxVertexNum; + + } + while(curVertex!=maxYVertex); + + /* scan out the left edge */ + polyScan = (I_GOURAUD2DTEXTUREPOLYGON_SCAN*)ScanData; + curVertex = minYVertex; + do + { + int height; + + int nextVertex = curVertex+1; + if (nextVertex>maxVertexNum) nextVertex = 0; + + height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y; + if (height!=0) + { + int i,x,y,u,v; + int deltaX,deltaI,deltaU,deltaV; + int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x; + int contrast = vertexPtr[nextVertex].i_i - vertexPtr[curVertex].i_i; + int widthU = vertexPtr[nextVertex].i_u - vertexPtr[curVertex].i_u; + int widthV = vertexPtr[nextVertex].i_v - vertexPtr[curVertex].i_v; + + deltaX = (width<<16)/height; + deltaI = contrast/height; + deltaU = widthU/height; + deltaV = widthV/height; + + x = vertexPtr[curVertex].i_x<<16; + i = vertexPtr[curVertex].i_i; + u = vertexPtr[curVertex].i_u; + v = vertexPtr[curVertex].i_v; + + for (y=vertexPtr[curVertex].i_y; yig2s_x1 = x>>16; + x+=deltaX; + polyScan->ig2s_c1 = i; + i+=deltaI; + polyScan->ig2s_u1 = u; + u+=deltaU; + polyScan->ig2s_v1 = v; + v+=deltaV; + + SecondOpinion++; + polyScan++; + } + } + curVertex++; + if (curVertex>maxVertexNum) curVertex = 0; + + } + while(curVertex!=maxYVertex); + + if (SecondOpinionPolyColour; + I_GOURAUD2DTEXTUREPOLYGON_SCAN *polyScan; + polyScan = (I_GOURAUD2DTEXTUREPOLYGON_SCAN*)ScanData; + SCASM_Lighting = TextureLightingTable+colour; + SCASM_ShadingTableSize = 256; + + while(NumScans) + { + int dx = polyScan->ig2s_x2 - polyScan->ig2s_x1; + if (dx>0) + { + SCASM_Destination = ScreenBuffer+(polyScan->ig2s_y * BackBufferPitch) + polyScan->ig2s_x1; + SCASM_ScanLength = dx; + SCASM_DeltaI = (polyScan->ig2s_c2-polyScan->ig2s_c1)/dx; + SCASM_StartI = polyScan->ig2s_c1; + ScanDraw_GouraudScan(); + } + NumScans--; + polyScan++; + } + } + #endif + } +} +#endif +#if 0 +void KDraw_Item_Gouraud3dTexturePolygon(int *itemptr) +{ + POLYHEADER *pheader = (POLYHEADER *) itemptr; + int TxIndex; + IMAGEHEADER *ImageHdr; + ItemColour = pheader->PolyColour; + + TxIndex = ItemColour & ClrTxDefn; + ImageHdr = ImageHeaderPtrs[TxIndex]; + + + + /* Colour */ + + + /* If MIP Mapping, calculate the scale */ + + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip) + { + I_GOURAUD3DTEXTUREPOLYGON_PT *vector1; + I_GOURAUD3DTEXTUREPOLYGON_PT *vector2; + I_GOURAUD3DTEXTUREPOLYGON_PT *vector3; + int mip1, mip2; + int xyd, uvd; + VECTOR2D s0, s1; + VECTOR2D t0, t1; + + + /* Screen and Texture Space Vectors */ + /* Express the "uvd / xyd" ratio as a binary scale */ + + vector1 = (I_GOURAUD3DTEXTUREPOLYGON_PT *) &pheader->Poly1stPt; + vector2 = &vector1[1]; + vector3 = &vector1[2]; + + + /* Vector 1 */ + + s0.vx = vector1->i_x; + s0.vy = vector1->i_y; + s1.vx = vector2->i_x; + s1.vy = vector2->i_y; + + t0.vx = vector1->i_gtx3d_u / vector1->i_gtx3d_z; + t0.vy = vector1->i_gtx3d_v / vector1->i_gtx3d_z; + t1.vx = vector2->i_gtx3d_u / vector2->i_gtx3d_z; + t1.vy = vector2->i_gtx3d_v / vector2->i_gtx3d_z; + + xyd = FandVD_Distance_2d(&s0, &s1); + uvd = FandVD_Distance_2d(&t0, &t1); + + mip1 = FindShift32(uvd, xyd); + + + /* Vector 2 */ + + s0.vx = vector2->i_x; + s0.vy = vector2->i_y; + s1.vx = vector3->i_x; + s1.vy = vector3->i_y; + + t0.vx = t1.vx; + t0.vy = t1.vy; + t1.vx = vector3->i_gtx3d_u / vector3->i_gtx3d_z; + t1.vy = vector3->i_gtx3d_v / vector3->i_gtx3d_z; + + xyd = FandVD_Distance_2d(&s0, &s1); + uvd = FandVD_Distance_2d(&t0, &t1); + + mip2 = FindShift32(uvd, xyd); + + + /* Choose the larger of the two */ + + if(pheader->PolyFlags & iflag_no_mip) { + + MIP_Index = 0; + + } + + else { + + #if UseMIPMax + if(mip1 > mip2) + MIP_Index = mip1; + else + MIP_Index = mip2; + #endif + + #if UseMIPMin + if(mip1 > mip2) + MIP_Index = mip2; + else + MIP_Index = mip1; + #endif + + #if UseMIPAvg + MIP_Index = (mip1 + mip2) >> 1; + #endif + + } + + + /* Clamp "MIP_Index" */ + + #if MIP_INDEX_SUBTRACT + + MIP_Index -= MIP_INDEX_SUBTRACT; + if(MIP_Index < 0) MIP_Index = 0; + else if(MIP_Index > 6) MIP_Index = 6; + + #else + + if(MIP_Index > 6) MIP_Index = 6; + + #endif + + } + + { + int minYVertex = 0; + int maxYVertex = 0; + int maxVertexNum = 0; + float MIP_Divide = 1<Poly1stPt; + int minY = vertexPtr->i_y; + int maxY = vertexPtr->i_y; + + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip) + { + vertexPtr->i_gtx3d_u /= MIP_Divide; + vertexPtr->i_gtx3d_v /= MIP_Divide; + } + vertexPtr++; + + do + { + maxVertexNum++; + + if (minY > vertexPtr->i_y) + { + minY = vertexPtr->i_y; + minYVertex = maxVertexNum; + } + else if (maxY < vertexPtr->i_y) + { + maxY = vertexPtr->i_y; + maxYVertex = maxVertexNum; + } + + if(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_MIP && ImageHdr->ImageFlags & ih_flag_mip) + { + vertexPtr->i_gtx3d_u /= MIP_Divide; + vertexPtr->i_gtx3d_v /= MIP_Divide; + } + + vertexPtr++; + } + while(vertexPtr->i_x != Term); + + } + + + /* Initialise the Scan Data Buffer */ + { + I_GOURAUD3DTEXTUREPOLYGON_PT *vertexPtr = (I_GOURAUD3DTEXTUREPOLYGON_PT*)&pheader->Poly1stPt; + I_GOURAUD3DTEXTUREPOLYGON_SCAN *polyScan; + int curVertex; + int SecondOpinion=0; + + NumScans=0; + + /* scan out the right edge */ + polyScan = (I_GOURAUD3DTEXTUREPOLYGON_SCAN*)ScanData; + curVertex = minYVertex; + do + { + int height; + + int nextVertex = curVertex-1; + if (nextVertex<0) nextVertex = maxVertexNum; + + height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y; + if (height!=0) + { + int i,x,y; + float u,v,z; + int deltaX,deltaI; + float deltaU,deltaV,deltaZ; + + int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x; + int contrast = vertexPtr[nextVertex].i_gtx3d_i - vertexPtr[curVertex].i_gtx3d_i; + float widthU = vertexPtr[nextVertex].i_gtx3d_u - vertexPtr[curVertex].i_gtx3d_u; + float widthV = vertexPtr[nextVertex].i_gtx3d_v - vertexPtr[curVertex].i_gtx3d_v; + float widthZ = vertexPtr[nextVertex].i_gtx3d_z - vertexPtr[curVertex].i_gtx3d_z; + + deltaX = (width<<16)/height; + deltaI = contrast/height; + deltaU = widthU/height; + deltaV = widthV/height; + deltaZ = widthZ/height; + + x = vertexPtr[curVertex].i_x<<16; + i = vertexPtr[curVertex].i_gtx3d_i; + u = vertexPtr[curVertex].i_gtx3d_u; + v = vertexPtr[curVertex].i_gtx3d_v; + z = vertexPtr[curVertex].i_gtx3d_z; + + for (y=vertexPtr[curVertex].i_y; yig3s_x2 = x>>16; + x+=deltaX; + polyScan->ig3s_c2 = i; + i+=deltaI; + polyScan->ig3s_u2 = u; + u+=deltaU; + polyScan->ig3s_v2 = v; + v+=deltaV; + polyScan->ig3s_z2 = z; + z+=deltaZ; + + polyScan->ig3s_y = y; + NumScans++; + polyScan++; + } + } + curVertex--; + if (curVertex<0) curVertex = maxVertexNum; + + } + while(curVertex!=maxYVertex); + + /* scan out the left edge */ + polyScan = (I_GOURAUD3DTEXTUREPOLYGON_SCAN*)ScanData; + curVertex = minYVertex; + do + { + int height; + + int nextVertex = curVertex+1; + if (nextVertex>maxVertexNum) nextVertex = 0; + + height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y; + if (height!=0) + { + int i,x,y; + float u,v,z; + int deltaX,deltaI; + float deltaU,deltaV,deltaZ; + + int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x; + int contrast = vertexPtr[nextVertex].i_gtx3d_i - vertexPtr[curVertex].i_gtx3d_i; + float widthU = vertexPtr[nextVertex].i_gtx3d_u - vertexPtr[curVertex].i_gtx3d_u; + float widthV = vertexPtr[nextVertex].i_gtx3d_v - vertexPtr[curVertex].i_gtx3d_v; + float widthZ = vertexPtr[nextVertex].i_gtx3d_z - vertexPtr[curVertex].i_gtx3d_z; + + deltaX = (width<<16)/height; + deltaI = contrast/height; + deltaU = widthU/height; + deltaV = widthV/height; + deltaZ = widthZ/height; + + x = vertexPtr[curVertex].i_x<<16; + i = vertexPtr[curVertex].i_gtx3d_i; + u = vertexPtr[curVertex].i_gtx3d_u; + v = vertexPtr[curVertex].i_gtx3d_v; + z = vertexPtr[curVertex].i_gtx3d_z; + + for (y=vertexPtr[curVertex].i_y; yig3s_x1 = x>>16; + x+=deltaX; + polyScan->ig3s_c1 = i; + i+=deltaI; + polyScan->ig3s_u1 = u; + u+=deltaU; + polyScan->ig3s_v1 = v; + v+=deltaV; + polyScan->ig3s_z1 = z; + z+=deltaZ; + + SecondOpinion++; + polyScan++; + } + } + curVertex++; + if (curVertex>maxVertexNum) curVertex = 0; + + } + while(curVertex!=maxYVertex); + + if (SecondOpinionPolyColour; + + TxIndex = ItemColour & ClrTxDefn; + ImageHdr = ImageHeaderPtrs[TxIndex]; + + + + { + int minYVertex = 0; + int maxYVertex = 0; + int maxVertexNum = 0; + + + { + I_GOURAUD3DTEXTUREPOLYGON_PT *vertexPtr = (I_GOURAUD3DTEXTUREPOLYGON_PT*)&pheader->Poly1stPt; + int minY = vertexPtr->i_y; + int maxY = vertexPtr->i_y; + + vertexPtr++; + + do + { + maxVertexNum++; + + if (minY > vertexPtr->i_y) + { + minY = vertexPtr->i_y; + minYVertex = maxVertexNum; + } + else if (maxY < vertexPtr->i_y) + { + maxY = vertexPtr->i_y; + maxYVertex = maxVertexNum; + } + + vertexPtr++; + } + while(vertexPtr->i_x != Term); + + } + + + /* Initialise the Scan Data Buffer */ + { + I_GOURAUD3DTEXTUREPOLYGON_PT *vertexPtr = (I_GOURAUD3DTEXTUREPOLYGON_PT*)&pheader->Poly1stPt; + I_GOURAUD3DTEXTUREPOLYGON_SCAN *polyScan; + int curVertex; + int SecondOpinion=0; + + NumScans=0; + + /* scan out the right edge */ + polyScan = (I_GOURAUD3DTEXTUREPOLYGON_SCAN*)ScanData; + curVertex = minYVertex; + do + { + int height; + + int nextVertex = curVertex-1; + if (nextVertex<0) nextVertex = maxVertexNum; + + height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y; + if (height!=0) + { + int i,x,y; + float u,v,z; + int deltaX,deltaI; + float deltaU,deltaV,deltaZ; + + int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x; + int contrast = vertexPtr[nextVertex].i_gtx3d_i - vertexPtr[curVertex].i_gtx3d_i; + float widthU = vertexPtr[nextVertex].i_gtx3d_u - vertexPtr[curVertex].i_gtx3d_u; + float widthV = vertexPtr[nextVertex].i_gtx3d_v - vertexPtr[curVertex].i_gtx3d_v; + float widthZ = vertexPtr[nextVertex].i_gtx3d_z - vertexPtr[curVertex].i_gtx3d_z; + + deltaX = (width<<16)/height; + deltaI = contrast/height; + deltaU = widthU/height; + deltaV = widthV/height; + deltaZ = widthZ/height; + + x = vertexPtr[curVertex].i_x<<16; + i = vertexPtr[curVertex].i_gtx3d_i; + u = vertexPtr[curVertex].i_gtx3d_u; + v = vertexPtr[curVertex].i_gtx3d_v; + z = vertexPtr[curVertex].i_gtx3d_z; + + for (y=vertexPtr[curVertex].i_y; yig3s_x2 = x>>16; + x+=deltaX; + polyScan->ig3s_c2 = i; + i+=deltaI; + polyScan->ig3s_u2 = u; + u+=deltaU; + polyScan->ig3s_v2 = v; + v+=deltaV; + polyScan->ig3s_z2 = z; + z+=deltaZ; + + polyScan->ig3s_y = y; + NumScans++; + polyScan++; + } + } + curVertex--; + if (curVertex<0) curVertex = maxVertexNum; + + } + while(curVertex!=maxYVertex); + + /* scan out the left edge */ + polyScan = (I_GOURAUD3DTEXTUREPOLYGON_SCAN*)ScanData; + curVertex = minYVertex; + do + { + int height; + + int nextVertex = curVertex+1; + if (nextVertex>maxVertexNum) nextVertex = 0; + + height = vertexPtr[nextVertex].i_y - vertexPtr[curVertex].i_y; + if (height!=0) + { + int i,x,y; + float u,v,z; + int deltaX,deltaI; + float deltaU,deltaV,deltaZ; + + int width = vertexPtr[nextVertex].i_x - vertexPtr[curVertex].i_x; + int contrast = vertexPtr[nextVertex].i_gtx3d_i - vertexPtr[curVertex].i_gtx3d_i; + float widthU = vertexPtr[nextVertex].i_gtx3d_u - vertexPtr[curVertex].i_gtx3d_u; + float widthV = vertexPtr[nextVertex].i_gtx3d_v - vertexPtr[curVertex].i_gtx3d_v; + float widthZ = vertexPtr[nextVertex].i_gtx3d_z - vertexPtr[curVertex].i_gtx3d_z; + + deltaX = (width<<16)/height; + deltaI = contrast/height; + deltaU = widthU/height; + deltaV = widthV/height; + deltaZ = widthZ/height; + + x = vertexPtr[curVertex].i_x<<16; + i = vertexPtr[curVertex].i_gtx3d_i; + u = vertexPtr[curVertex].i_gtx3d_u; + v = vertexPtr[curVertex].i_gtx3d_v; + z = vertexPtr[curVertex].i_gtx3d_z; + + for (y=vertexPtr[curVertex].i_y; yig3s_x1 = x>>16; + x+=deltaX; + polyScan->ig3s_c1 = i; + i+=deltaI; + polyScan->ig3s_u1 = u; + u+=deltaU; + polyScan->ig3s_v1 = v; + v+=deltaV; + polyScan->ig3s_z1 = z; + z+=deltaZ; + + SecondOpinion++; + polyScan++; + } + } + curVertex++; + if (curVertex>maxVertexNum) curVertex = 0; + + } + while(curVertex!=maxYVertex); + + if (SecondOpinionImageWidth; + SCASM_Bitmap = ImageHdr->ImagePtr; + GLOBALASSERT(SCASM_Bitmap); + } + } + SCASM_Lighting = TextureLightingTable; + + sptr = (I_GOURAUD3DTEXTUREPOLYGON_SCAN *) ScanData; + do + { + int length = sptr->ig3s_x2 - sptr->ig3s_x1; + int dx=length; + + if (dx>0 && !(sptr->ig3s_y & KRenderDrawMode) ) + { + float deltaZ; + float endZ; + + float endU,endV; + float deltaU,deltaV; + + { + int StartI = sptr->ig3s_c1; + SCASM_DeltaI = (sptr->ig3s_c2 - StartI)/dx; + SCASM_StartI = StartI; + } + + SCASM_Destination = ScreenBuffer + (sptr->ig3s_y * BackBufferPitch) + sptr->ig3s_x1; + SCASM_ScanLength = PERS_STEP; + + { + float oneOverdx = 1.0/dx; + + endZ = sptr->ig3s_z1; + deltaZ = (sptr->ig3s_z2 - endZ)*oneOverdx; + + endU = sptr->ig3s_u1; + deltaU = (sptr->ig3s_u2 - endU)*oneOverdx; + + endV = sptr->ig3s_v1; + deltaV = (sptr->ig3s_v2 - endV)*oneOverdx; + } + { + float z = 65536.0/endZ; + SCASM_StartU = endU*z; + SCASM_StartV = endV*z; + } + while(dx>PERS_STEP) + { + /* subdivide! */ + int u,v; + + dx -= PERS_STEP; + + endZ += PERS_STEP*deltaZ; + endU += PERS_STEP*deltaU; + endV += PERS_STEP*deltaV; + + { + float z = 65536.0/endZ; + u = endU*z; + v = endV*z; + } + SCASM_DeltaU = (u-SCASM_StartU)/PERS_STEP; + SCASM_DeltaV = (v-SCASM_StartV)/PERS_STEP; + + /* draw PERS_STEP pixels */ + ScanDraw2D_Gouraud(); + + SCASM_StartU = u; + SCASM_StartV = v; + + SCASM_Destination +=PERS_STEP; + SCASM_StartI += PERS_STEP*SCASM_DeltaI; + } + if (dx>0) + { + int u,v; + SCASM_ScanLength = dx; + { + float z = 65536.0/sptr->ig3s_z2; + u = sptr->ig3s_u2*z; + v = sptr->ig3s_v2*z; + } + SCASM_DeltaU = (u-SCASM_StartU)/dx; + SCASM_DeltaV = (v-SCASM_StartV)/dx; + + /* draw 8 pixels */ + ScanDraw2D_Gouraud(); + } + + + + + + } + sptr++; + y--; + } + while(y); + } + +} +#endif + + + + + + + + + + + +#if 0 +void MakeInverseLightingTable(void) +{ + int lookingForColour; + + for(lookingForColour=1; lookingForColour<=255; lookingForColour++) + { + int exit =0; + int table; + for (table=128; (table>0 && (!exit)); table--) + { + int entry; + for(entry=1; (entry<=255 && (!exit)); entry++) + { + if(lookingForColour == *(TextureLightingTable + 256*(table) + entry)) + { + LighterTable[lookingForColour] = entry; + exit=1; + } + } + } + if (exit==0) LighterTable[lookingForColour] = 255; + } +} +#endif +struct ColourVector +{ + VECTORCH Direction; + int Magnitude; +}; + +struct ColourVector ColourTable[256]; + +void MakeInverseLightingTable(void) +{ + extern unsigned char TestPalette[]; + unsigned char *palPtr = TestPalette; + int i; + + for(i = 0; i < 256; i++) + { + VECTORCH colour; + int mag; + + colour.vx = *palPtr++; + colour.vy = *palPtr++; + colour.vz = *palPtr++; + mag = Magnitude(&colour); + + if (mag!=0) + { + colour.vx = (colour.vx*32)/mag; + colour.vy = (colour.vy*32)/mag; + colour.vz = (colour.vz*32)/mag; + } + ColourTable[i].Magnitude = mag; + ColourTable[i].Direction = colour; + } + + for(i = 0; i < 256; i++) + { + int entry; + int brightest=0; + + for(entry = 0; entry < 256; entry++) + { + VECTORCH v1 = ColourTable[i].Direction; + VECTORCH v2 = ColourTable[entry].Direction; + + if ((v1.vx == v2.vx) + &&(v1.vy == v2.vy) + &&(v1.vz == v2.vz) + &&(ColourTable[i].Magnitude < ColourTable[entry].Magnitude) + &&(ColourTable[brightest].Magnitude > ColourTable[entry].Magnitude ||(!brightest))) + brightest = entry; + } + if (brightest==0) + { + for(entry = 0; entry < 256; entry++) + { + VECTORCH v1 = ColourTable[i].Direction; + VECTORCH v2 = ColourTable[entry].Direction; + + if ((v1.vx>>2 == v2.vx>>1) + &&(v1.vy>>2 == v2.vy>>1) + &&(v1.vz>>2 == v2.vz>>1) + &&(ColourTable[i].Magnitude < ColourTable[entry].Magnitude) + &&(ColourTable[brightest].Magnitude > ColourTable[entry].Magnitude ||(!brightest))) + + brightest = entry; + } + } + + if (brightest==0) + { + for(entry = 0; entry < 256; entry++) + { + VECTORCH v1 = ColourTable[i].Direction; + VECTORCH v2 = ColourTable[entry].Direction; + + if ((v1.vx>>2 == v2.vx>>2) + &&(v1.vy>>2 == v2.vy>>2) + &&(v1.vz>>2 == v2.vz>>2) + &&(ColourTable[i].Magnitude < ColourTable[entry].Magnitude) + &&(ColourTable[brightest].Magnitude > ColourTable[entry].Magnitude ||(!brightest))) + brightest = entry; + } + } + #if 0 + if (brightest==0) + { + for(entry = 0; entry < 256; entry++) + { + VECTORCH v1 = ColourTable[i].Direction; + VECTORCH v2 = ColourTable[entry].Direction; + + if ((v1.vx>>3 == v2.vx>>3) + &&(v1.vy>>3 == v2.vy>>3) + &&(v1.vz>>3 == v2.vz>>3) + &&(ColourTable[i].Magnitude < ColourTable[entry].Magnitude) + &&(ColourTable[brightest].Magnitude > ColourTable[entry].Magnitude ||(!brightest))) + brightest = entry; + } + } + + #endif + if (brightest==0) brightest = i; + + LighterTable[i] = brightest; + } + + +} + + +void DrawPaletteScreen(void) +{ + int sortedColours[256]; + { + extern unsigned char TestPalette[]; + unsigned char *palPtr = TestPalette; + int i; + + for(i = 0; i < 256; i++) + { + VECTORCH colour; + int mag; + + colour.vx = *palPtr++; + colour.vy = *palPtr++; + colour.vz = *palPtr++; + mag = Magnitude(&colour); + + if (mag!=0) + { + colour.vx = (colour.vx*7)/mag; + colour.vy = (colour.vy*7)/mag; + colour.vz = (colour.vz*7)/mag; + } + ColourTable[i].Magnitude = mag; + ColourTable[i].Direction = colour; + } + + for(i = 0; i<256; i++) + { + int e; + int maxKey=-1; + int selectedEntry=0; + + for (e=0; e<256; e++) + { + int key = ColourTable[e].Direction.vx + ColourTable[e].Direction.vy*64+ColourTable[e].Direction.vz*64*64; + if (key>maxKey) + { + maxKey = key; + selectedEntry = e; + } + else if (key==maxKey) + { + if (ColourTable[e].MagnitudemaxKey) + { + maxKey = key; + selectedEntry = e; + } + else if (key==maxKey) + { + int key2 = ColourTable[e].Direction.vx + ColourTable[e].Direction.vy*64+ColourTable[e].Direction.vz*64*64; + int key3 = ColourTable[selectedEntry].Direction.vx + + ColourTable[selectedEntry].Direction.vy*64 + + ColourTable[selectedEntry].Direction.vz*64*64; + + if (key2>16; + } + } + ChangePalette(TestPalette2); + } + else + { + d3d_light_ctrl.ctrl = LCCM_CONSTCOLOUR; + d3d_light_ctrl.r = fadeLevel; + d3d_light_ctrl.g = fadeLevel; + d3d_light_ctrl.b = fadeLevel; + } +} + +void FadeBetweenPalettes(unsigned char *palPtr, int fadeLevel) +{ + extern unsigned char TestPalette[]; + unsigned char TestPalette3[768]; + { + int x; + for (x=0; x<768; x++) + { + TestPalette3[x] = ( (unsigned int)TestPalette[x]*fadeLevel + (unsigned int)(palPtr[x])*(65536-fadeLevel) )>>16; + } + } + ChangePalette(TestPalette3); +} +void FadePaletteToWhite(unsigned char *palPtr,int fadeLevel) +{ + unsigned char TestPalette3[768]; + { + int x; + for (x=0; x<768; x++) + { + TestPalette3[x] = ( (unsigned int)(palPtr[x])*fadeLevel + 63*(65536-fadeLevel) )>>16; + } + } + ChangePalette(TestPalette3); +} + + +void BlankScreen(void) +{ + extern int ScanDrawMode; + + if (ScanDrawDirectDraw==ScanDrawMode) + { + extern unsigned char *ScreenBuffer; + extern unsigned char TestPalette[]; + unsigned int *screenPtr; + int i; + + screenPtr = (unsigned int *)ScreenBuffer; + i = ScreenDescriptorBlock.SDB_Width * ScreenDescriptorBlock.SDB_Height /4; + do + { + *screenPtr++=0; + } + while(--i); + } + else + { + ColourFillBackBuffer(0); + } + + // FlipBuffers(); +} + + + + +void GenerateReciprocalTable(void) +{ + int i=320; + + do + { + ReciprocalTable[i] = 65536/i; + } + while(--i); +} + + + + +#if 0 +#define NO_OF_STARS 500 +typedef struct +{ + VECTORCH Position; + int Colour; + +} STARDESC; +static STARDESC StarArray[NO_OF_STARS]; +#endif +void CreateStarArray(void) +{ + #if 0 + int i; + extern int sine[],cosine[]; + for(i=0; iVDB_Mat)); + + /* is star within alien (wide) view frustrum ? */ + if((-rotatedPosition.vx <= rotatedPosition.vz*2) + &&(rotatedPosition.vx <= rotatedPosition.vz*2) + &&(-rotatedPosition.vy*2 <= rotatedPosition.vz*3) + &&(rotatedPosition.vy*2 <= rotatedPosition.vz*3)) + { + /* project into screen space */ + int y = (rotatedPosition.vy*(Global_VDB_Ptr->VDB_ProjY))/rotatedPosition.vz+Global_VDB_Ptr->VDB_CentreY; + int x = (rotatedPosition.vx*(Global_VDB_Ptr->VDB_ProjX))/rotatedPosition.vz+Global_VDB_Ptr->VDB_CentreX; + + /* draw pixel of required bit depth */ + if (ScanDrawMode == ScanDrawDirectDraw) + { + /* 8 bit mode */ + *(ScreenBuffer + x + y*BackBufferPitch) = StarArray[i].Colour&255; + } + else + { + /* 16 bit mode */ + *(unsigned short*)(ScreenBuffer + (x*2 + y*BackBufferPitch)) = StarArray[i].Colour; + } + } + } + } + else /* normal frustrum */ + { + for(i=0; iVDB_Mat)); + + /* is star within normal view frustrum ? */ + if((-rotatedPosition.vx <= rotatedPosition.vz) + &&(rotatedPosition.vx <= rotatedPosition.vz) + &&(-rotatedPosition.vy*4 <= rotatedPosition.vz*3) + &&(rotatedPosition.vy*4 <= rotatedPosition.vz*3)) + { + /* project into screen space */ + int y = (rotatedPosition.vy*(Global_VDB_Ptr->VDB_ProjY))/rotatedPosition.vz+Global_VDB_Ptr->VDB_CentreY; + int x = (rotatedPosition.vx*(Global_VDB_Ptr->VDB_ProjX))/rotatedPosition.vz+Global_VDB_Ptr->VDB_CentreX; + + /* draw pixel of required bit depth */ + if (ScanDrawMode == ScanDrawDirectDraw) + { + /* 8 bit mode */ + *(ScreenBuffer + x + y*BackBufferPitch) = StarArray[i].Colour&255; + } + else + { + /* 16 bit mode */ + *(unsigned short*)(ScreenBuffer + (x*2 + y*BackBufferPitch)) = StarArray[i].Colour; + } + } + } + } + + UnlockSurface(); + #endif +} \ No newline at end of file diff --git a/3dc/win95/LTCHUNK.CPP b/3dc/win95/LTCHUNK.CPP new file mode 100644 index 0000000..b000a9c --- /dev/null +++ b/3dc/win95/LTCHUNK.CPP @@ -0,0 +1,489 @@ +#include "chunk.hpp" + +#include "ltchunk.hpp" + + +#ifdef cencon +#define new my_new +#endif + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(ltchunk) + +//////////////////////////////////////////////////////////////////////////////////// +//Class Light_Set_Chunk + +RIF_IMPLEMENT_DYNCREATE("LIGHTSET",Light_Set_Chunk) + +CHUNK_WITH_CHILDREN_LOADER("LIGHTSET",Light_Set_Chunk) + +/* +Children for Light_Set_Chunk : + +"LTSETHDR" Light_Set_Header_Chunk +"STDLIGHT" Light_Chunk +"AMBIENCE" Lighting_Ambience_Chunk +"LITSCALE" Light_Scale_Chunk +"AVPSTRAT" AVP_Strategy_Chunk +*/ + +Light_Set_Chunk::Light_Set_Chunk (Chunk_With_Children * parent, char * light_set_name) +: Chunk_With_Children (parent, "LIGHTSET") +{ + new Light_Set_Header_Chunk (this, light_set_name); +} + + + +//////////////////////////////////////////////////////////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("LTSETHDR",Light_Set_Header_Chunk) + +Light_Set_Header_Chunk::Light_Set_Header_Chunk (Light_Set_Chunk * parent, char l_set_name[8]) +: Chunk (parent, "LTSETHDR"), pad (0) +{ + strncpy (light_set_name, l_set_name, 8); +} + +void Light_Set_Header_Chunk::fill_data_block ( char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + strncpy (data_start, light_set_name, 8); + + data_start += 8; + + *((int *) data_start) = pad; +} + +Light_Set_Header_Chunk::Light_Set_Header_Chunk (Chunk_With_Children * parent, const char * data, size_t const /*size*/) +: Chunk (parent, "LTSETHDR") +{ + strncpy (light_set_name, data, 8); + + data += 8; + + pad = *((int *) data); +} + + +//////////////////////////////////////////////////////////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("STDLIGHT",Light_Chunk) + + +void Light_Chunk::fill_data_block ( char * data_start) +{ + + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = light.light_number; + data_start += 4; + + *((ChunkVectorInt *) data_start) = light.location; + data_start += sizeof(ChunkVectorInt); + + *((ChunkMatrix *) data_start) = light.orientation; + data_start += sizeof(ChunkMatrix); + + *((int *) data_start) = light.brightness; + data_start += 4; + *((int *) data_start) = light.spread; + data_start += 4; + *((int *) data_start) = light.range; + data_start += 4; + + *((int *) data_start) = light.colour; + data_start += 4; + + *((int *) data_start) = light.engine_light_flags; + data_start += 4; + *((int *) data_start) = light.local_light_flags; + data_start += 4; + + *((int *) data_start) = light.pad1; + data_start += 4; + *((int *) data_start) = light.pad2; + +} +#if UseOldChunkLoader +Light_Chunk::Light_Chunk(Light_Set_Chunk * parent, const char * data, size_t const /*size*/) +: Chunk (parent, "STDLIGHT") +{ + light.light_number = *((int *) data); + data += 4; + + light.location = *((ChunkVector *) data); + data += sizeof(ChunkVector); + + light.orientation.mat11 = (int) *((double *) data); + data += 8; + light.orientation.mat12 = (int) *((double *) data); + data += 8; + light.orientation.mat13 = (int) *((double *) data); + data += 8; + light.orientation.mat21 = (int) *((double *) data); + data += 8; + light.orientation.mat22 = (int) *((double *) data); + data += 8; + light.orientation.mat23 = (int) *((double *) data); + data += 8; + light.orientation.mat31 = (int) *((double *) data); + data += 8; + light.orientation.mat32 = (int) *((double *) data); + data += 8; + light.orientation.mat33 = (int) *((double *) data); + data += 8; + + light.brightness = *((int *) data); + data += 4; + light.spread = *((int *) data); + data += 4; + light.range = *((int *) data); + data += 4; + + light.colour = *((int *) data); + data += 4; + + light.engine_light_flags = *((int *) data); + data += 4; + light.local_light_flags = *((int *) data); + data += 4; + + light.pad1 = *((int *) data); + data += 4; + light.pad2 = *((int *) data); + + #if engine || cencon + light_added_to_module = FALSE; + #endif + +} +#else +Light_Chunk::Light_Chunk(Chunk_With_Children * parent, const char * data, size_t const /*size*/) +: Chunk (parent, "STDLIGHT") +{ + light.light_number = *((int *) data); + data += 4; + + light.location = *((ChunkVectorInt *) data); + data += sizeof(ChunkVectorInt); + + light.orientation = *((ChunkMatrix *) data); + data += sizeof(ChunkMatrix); + + light.brightness = *((int *) data); + data += 4; + light.spread = *((int *) data); + data += 4; + light.range = *((int *) data); + data += 4; + + light.colour = *((int *) data); + data += 4; + + light.engine_light_flags = *((int *) data); + data += 4; + light.local_light_flags = *((int *) data); + data += 4; + + light.pad1 = *((int *) data); + data += 4; + light.pad2 = *((int *) data); + + #if engine || cencon + light_added_to_module = FALSE; + #endif + +} +#endif + +#if InterfaceEngine +AVP_Strategy_Chunk* Light_Chunk::GetStrategyChunk() +{ + List chlist; + parent->lookup_child("AVPSTRAT",chlist); + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + AVP_Strategy_Chunk* asc=(AVP_Strategy_Chunk*)chlif(); + if(asc->index==light.light_number) return asc; + } + return 0; +} + +AVP_Strategy_Chunk* Light_Chunk::CreateStrategyChunk() +{ + AVP_Strategy_Chunk* asc=GetStrategyChunk(); + if(asc) return asc; + + asc=new AVP_Strategy_Chunk(parent); + asc->index=light.light_number; + return asc; +} +#endif + +//////////////////////////////////////////////////////////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("SHPVTINT",Shape_Vertex_Intensities_Chunk) + + +Shape_Vertex_Intensities_Chunk::Shape_Vertex_Intensities_Chunk +(Chunk_With_Children *parent, char *lsn, int num_v, int * i_array) +: Chunk (parent, "SHPVTINT"), num_vertices(num_v), pad (0) +{ + strncpy (light_set_name, lsn, 8); + + intensity_array = new int [num_v]; + + for (int i=0; i + +#ifdef cencon +#define new my_new +#endif + + +// Class Lockable_Chunk_With_Children functions + +#if cencon +#else +extern char * users_name; +#endif + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(mishchnk) + +BOOL Lockable_Chunk_With_Children::lock_chunk(File_Chunk & fchunk) +{ + if (!fchunk.filename) return FALSE; + + if (local_lock) return FALSE; // you can't lock a chunk twice + + #if DisableLock + if(external_lock) return FALSE; + local_lock = TRUE; + set_lock_user (users_name); + return TRUE; + #else + if (!fchunk.check_file()) return FALSE; + if (updated_outside || external_lock) return FALSE; + + HANDLE rif_file; + unsigned long bytes_read; + + int tries = 0; + + rif_file = CreateFile (fchunk.filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, 0); + + while(rif_file == INVALID_HANDLE_VALUE && tries<10) + { + rif_file = CreateFile (fchunk.filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, 0); + tries ++; + clock_t ctime = clock(); + double secs = (double)ctime / (double)CLOCKS_PER_SEC; + double secsgone; + do + { + ctime = clock(); + secsgone = (double)ctime / (double)CLOCKS_PER_SEC; + } + while( (secsgone-secs)<1); + } + + if (rif_file == INVALID_HANDLE_VALUE) { + return FALSE; + } + + SetFilePointer (rif_file,0,0,FILE_BEGIN); + + List chfptrs; + list_chunks_in_file(& chfptrs, rif_file, identifier); + + LIF cfpl(&chfptrs); + + if (chfptrs.size()) { + for (; !cfpl.done(); cfpl.next()) { + + SetFilePointer (rif_file, cfpl(),0,FILE_BEGIN); + + if (file_equals(rif_file)) break; + } + } + + if (!cfpl.done()) { + + // go to start of chunk + SetFilePointer (rif_file,cfpl(),0,FILE_BEGIN); + + // get header list + if (get_head_id()) + { + List obhead; + list_chunks_in_file(& obhead, rif_file, get_head_id()); + + assert (obhead.size() == 1); + + int flags; + + // go to lock status in header + SetFilePointer(rif_file,obhead.first_entry() + 12,0,FILE_BEGIN); + ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0); + SetFilePointer(rif_file,-4,0,FILE_CURRENT); + flags |= GENERAL_FLAG_LOCKED; + WriteFile (rif_file, (long *) &flags, 4, &bytes_read, 0); + WriteFile (rif_file, (long *) &users_name[0], 16, &bytes_read, 0); + } + + } + + local_lock = TRUE; + + set_lock_user (users_name); + + CloseHandle (rif_file); + return TRUE; + #endif + +} + +BOOL Lockable_Chunk_With_Children::unlock_chunk (File_Chunk & fchunk, BOOL updateyn) +{ + if (updateyn) { + updated = TRUE; + } + #if DisableLock + local_lock = FALSE; + (void)fchunk; + #else + else + { + fchunk.check_file(); + if (updated_outside || external_lock) return FALSE; + + HANDLE rif_file; + unsigned long bytes_read; + + rif_file = CreateFile (fchunk.filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, 0); + + if (rif_file == INVALID_HANDLE_VALUE) { + return FALSE; + } + + SetFilePointer (rif_file,0,0,FILE_BEGIN); + + List chfptrs; + list_chunks_in_file(& chfptrs, rif_file, identifier); + + List obs; + + char name[50]; + + LIF ofpl(&chfptrs); + + if (chfptrs.size()) { + for (; !ofpl.done(); ofpl.next()) { + + SetFilePointer (rif_file, ofpl(),0,FILE_BEGIN); + + if (file_equals(rif_file)) break; + } + } + + if (!ofpl.done()) { + + // go to start of chunk + SetFilePointer (rif_file,ofpl(),0,FILE_BEGIN); + + // get header list + if (get_head_id()) + { + List obhead; + list_chunks_in_file(& obhead, rif_file, get_head_id()); + + assert (obhead.size() == 1); + + int flags; + + // go to lock status in header + SetFilePointer(rif_file,obhead.first_entry() + 12,0,FILE_BEGIN); + ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0); + SetFilePointer(rif_file,-4,0,FILE_CURRENT); + flags &= ~GENERAL_FLAG_LOCKED; + WriteFile (rif_file, (long *) &flags, 4, &bytes_read, 0); + WriteFile (rif_file, (long *) &users_name[0], 16, &bytes_read, 0); + } + + } + + local_lock = FALSE; + + CloseHandle (rif_file); + } + #endif + + + return TRUE; + +} + + +BOOL Lockable_Chunk_With_Children::update_chunk_in_file(HANDLE &rif_file) +{ + + unsigned long bytes_read; + int length = 0; + + const char * hd_id = get_head_id(); + + if (!hd_id) return FALSE; + + SetFilePointer (rif_file,0,0,FILE_BEGIN); + + //twprintf("\nLooking for chunks in file\n"); + + List shpfptrs; + list_chunks_in_file(& shpfptrs, rif_file, identifier); + + // look through chunks for the save of our current chunk + + //twprintf("Checking each chunk\n"); + + LIF sfpl(&shpfptrs); + + if (shpfptrs.size()) { + for (; !sfpl.done(); sfpl.next()) { + + SetFilePointer (rif_file, sfpl()+8,0,FILE_BEGIN); + + ReadFile (rif_file, (long *) &(length), 4, &bytes_read, 0); + + SetFilePointer (rif_file, sfpl(),0,FILE_BEGIN); + if (file_equals(rif_file)) break; + } + } + + // then load the file after that chunk into a buffer, + // output the chunk and write the buffer + // unless the chunk is the last one in the file + + //twprintf("Updating file\n"); + + if (!sfpl.done()) + { + + int file_length = GetFileSize(rif_file,0); + + if (file_length > (sfpl() + length)) { + + SetFilePointer (rif_file, sfpl() + length,0,FILE_BEGIN); + + char * tempbuffer; + tempbuffer = new char [file_length - (sfpl() + length)]; + + ReadFile (rif_file, (long *) tempbuffer, (file_length - (sfpl() + length)), &bytes_read, 0); + + SetFilePointer (rif_file, sfpl() ,0,FILE_BEGIN); + + if (!deleted) + { + size_chunk(); + output_chunk(rif_file); + } + + WriteFile (rif_file, (long *) tempbuffer, (file_length - (sfpl() + length)), &bytes_read, 0); + + delete [] tempbuffer; + + SetEndOfFile (rif_file); + } + else{ + + SetFilePointer (rif_file, sfpl() ,0,FILE_BEGIN); + if (!deleted) + { + size_chunk(); + output_chunk(rif_file); + } + SetEndOfFile (rif_file); + } + + } + else { + + SetFilePointer (rif_file,0 ,0,FILE_END); + if (!deleted) + { + size_chunk(); + output_chunk(rif_file); + } + SetEndOfFile (rif_file); + } + + local_lock = FALSE; + + updated = FALSE; + + int file_length = GetFileSize(rif_file,0); + SetFilePointer (rif_file,8,0,FILE_BEGIN); + + WriteFile (rif_file, (long *) &file_length, 4, &bytes_read, 0); + + + // DO NOT PUT ANY CODE AFTER THIS + + if (deleted) delete this; + + // OR ELSE !!! + + return TRUE; + +} + + +size_t Lockable_Chunk_With_Children::size_chunk_for_process() +{ + if (output_chunk_for_process) + return size_chunk(); + return(chunk_size = 0); +} + + +void Lockable_Chunk_With_Children::fill_data_block_for_process(char * data_start) +{ + if (output_chunk_for_process) + { + fill_data_block(data_start); + output_chunk_for_process = FALSE; + } +} + + + + +/////////////////////////////////////// + +// Class File_Chunk functions + +/* +Children for File_Chunk : +"REBSHAPE" Shape_Chunk +"RSPRITES" AllSprites_Chunk +"RBOBJECT" Object_Chunk +"RIFVERIN" RIF_Version_Num_Chunk +"REBENVDT" Environment_Data_Chunk +"REBENUMS" Enum_Chunk +"OBJCHIER" Object_Hierarchy_Chunk +"OBHALTSH" Object_Hierarchy_Alternate_Shape_Set_Chunk +"HIDEGDIS" Hierarchy_Degradation_Distance_Chunk +"INDSOUND" Indexed_Sound_Chunk +"HSETCOLL" Hierarchy_Shape_Set_Collection_Chunk +"DUMMYOBJ" Dummy_Object_Chunk + +*/ + +File_Chunk::File_Chunk(const char * file_name) +: Chunk_With_Children (NULL, "REBINFF2") +{ +// Load in whole chunk and traverse + char rifIsCompressed = FALSE; + char *uncompressedData = NULL; + HANDLE rif_file; + DWORD file_size; + DWORD file_size_from_file; + unsigned long bytes_read; + char * buffer; + char * buffer_ptr; + char id_buffer[9]; + + Parent_File = this; + + error_code = 0; + object_array_size=0; + object_array=0; + + filename = new char [strlen(file_name) + 1]; + + strcpy (filename, file_name); + + rif_file = CreateFileA (file_name, GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, 0); + + if (rif_file == INVALID_HANDLE_VALUE) { + error_code = CHUNK_FAILED_ON_LOAD; + return; + } + + file_size = GetFileSize (rif_file, NULL); + + + if (!ReadFile(rif_file, id_buffer, 8, &bytes_read, 0)) { + error_code = CHUNK_FAILED_ON_LOAD; + CloseHandle (rif_file); + return; + } + + #if UseOldChunkLoader + if (strncmp (id_buffer, "REBINFLF", 8)) { + error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + CloseHandle (rif_file); + return; + } + #else + /* KJL 16:46:14 19/09/98 - check for a compressed rif */ + if (!strncmp (id_buffer, COMPRESSED_RIF_IDENTIFIER, 8)) + { + rifIsCompressed = TRUE; + } + else if (strncmp (id_buffer, "REBINFF2", 8)) + { + error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + CloseHandle (rif_file); + return; + } + #endif + buffer = new char [file_size]; + + /* KJL 17:57:44 19/09/98 - if the rif is compressed, we must load the whole + file in and then pass it to the decompression routine, which will return a + pointer to the original data. */ + if (rifIsCompressed) + { + if (!ReadFile(rif_file, buffer+8, (file_size-8), &bytes_read, 0)) + { + error_code = CHUNK_FAILED_ON_LOAD; + CloseHandle (rif_file); + return; + } + uncompressedData = HuffmanDecompress((HuffmanPackage*)buffer); + file_size = ((HuffmanPackage*)buffer)->UncompressedDataSize; + + delete [] buffer; // kill the buffer the compressed file was loaded into + + buffer_ptr = buffer = uncompressedData+12; // skip header data + } + else // the normal uncompressed approach: + { + if (!ReadFile(rif_file, &file_size_from_file, 4, &bytes_read, 0)) { + error_code = CHUNK_FAILED_ON_LOAD; + CloseHandle (rif_file); + return; + } + + if (file_size != file_size_from_file) { + error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + CloseHandle (rif_file); + return; + } + + if (!ReadFile(rif_file, buffer, (file_size-12), &bytes_read, 0)) + { + error_code = CHUNK_FAILED_ON_LOAD; + CloseHandle (rif_file); + return; + } + buffer_ptr = buffer; + } + + // Process the RIF + // The start of the first chunk + + while ((buffer_ptr-buffer)< ((signed) file_size-12) && !error_code) { + + if ((*(int *)(buffer_ptr + 8)) + (buffer_ptr-buffer) > ((signed)file_size-12)) { + error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + + DynCreate(buffer_ptr); + buffer_ptr += *(int *)(buffer_ptr + 8); + + } + + /* KJL 17:59:42 19/09/98 - release the memory holding the rif */ + if (rifIsCompressed) + { + free(uncompressedData); + } + else + { + delete [] buffer; + } + + CloseHandle (rif_file); + + post_input_processing(); + +} + +File_Chunk::File_Chunk() +: Chunk_With_Children (NULL, "REBINFF2") +{ +// Empty File chunk + new RIF_Version_Num_Chunk (this); + filename = 0; + + object_array_size=0; + object_array=0; +} + + +File_Chunk::~File_Chunk() +{ + if (filename) + delete [] filename; + + if(object_array) + free(object_array); +} + +#define SAVE_USING_COMPRESSION 1 + +BOOL File_Chunk::write_file (const char * fname) +{ + if(!fname) return FALSE; + //if a read_only file exists with this filename , then abort attempt to save + DWORD attributes = GetFileAttributesA(fname); + if (0xffffffff!=attributes) + { + if (attributes & FILE_ATTRIBUTE_READONLY) + { + return FALSE; + } + } + + + + HANDLE rif_file; + + if (filename) delete [] filename; + + filename = new char [strlen(fname) + 1]; + strcpy (filename, fname); + + //save under a temporary name in case a crash occurs during save; + int filename_start_pos=0; + int pos=0; + while(fname[pos]) + { + if(fname[pos]=='\\' || fname[pos]==':') + { + filename_start_pos=pos+1; + } + //go to next MBCS character in string + pos+=_mbclen((unsigned const char*)&fname[pos]); + } + if(!fname[filename_start_pos]) return FALSE; + + char* temp_name=new char[strlen(fname)+7]; + strcpy(temp_name,fname); + strcpy(&temp_name[filename_start_pos],"~temp~"); + strcpy(&temp_name[filename_start_pos+6],&fname[filename_start_pos]); + + prepare_for_output(); + + + #if SAVE_USING_COMPRESSION + //create a block containing the uncompressed rif file + unsigned char* uncompressedData = (unsigned char*) make_data_block_from_chunk(); + if(!uncompressedData) return FALSE; + + //do the compression thing + HuffmanPackage *outPackage = HuffmanCompression(uncompressedData,chunk_size); + delete [] uncompressedData; + if(!outPackage) return FALSE; + + //and now try to write the file + rif_file = CreateFileA (temp_name, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_FLAG_RANDOM_ACCESS, 0); + + if (rif_file == INVALID_HANDLE_VALUE) { + delete [] temp_name; + free (outPackage); + return FALSE; + } + + unsigned long junk; + BOOL ok; + + ok = WriteFile (rif_file, (long *) outPackage,outPackage->CompressedDataSize+sizeof(HuffmanPackage), &junk, 0); + + CloseHandle (rif_file); + + free (outPackage); + + if(!ok) return FALSE; + + + #else + size_chunk(); + + rif_file = CreateFileA (temp_name, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_FLAG_RANDOM_ACCESS, 0); + + if (rif_file == INVALID_HANDLE_VALUE) { + delete [] temp_name; + return FALSE; + } + + if (!(this->output_chunk(rif_file))) + { + CloseHandle (rif_file); + delete [] temp_name; + return FALSE; + } + + CloseHandle (rif_file); + #endif + + //Delete the old file with this name (if it exists) , and rename the temprary file + DeleteFileA(fname); + MoveFileA(temp_name,fname); + + delete [] temp_name; + + return TRUE; +} + +// the file_chunk must link all of its shapes & objects together + +void File_Chunk::post_input_processing() +{ + List shplist; + List objlist; + + List child_lists; + + lookup_child("REBSHAPE",child_lists); + + while (child_lists.size()) { + shplist.add_entry((Shape_Chunk *)child_lists.first_entry()); + child_lists.delete_first_entry(); + } + + lookup_child("RBOBJECT",child_lists); + + while (child_lists.size()) { + objlist.add_entry((Object_Chunk *)child_lists.first_entry()); + child_lists.delete_first_entry(); + } + + for (LIF sli(&shplist); !sli.done(); sli.next()) + { + Shape_Chunk::max_id = max (Shape_Chunk::max_id,sli()->get_header()->file_id_num); + } + Shape_Chunk** shape_array=new Shape_Chunk*[Shape_Chunk::max_id+1]; + + for(sli.restart();!sli.done();sli.next()) + { + shape_array[sli()->get_header()->file_id_num]=sli(); + } + + for (LIF ol(&objlist); !ol.done(); ol.next()) + { + ol()->assoc_with_shape(shape_array[ol()->get_header()->shape_id_no]); + } + + delete shape_array; + + + Chunk_With_Children::post_input_processing(); +} + + + +BOOL File_Chunk::check_file() +{ + if (!filename) return TRUE; + + #if DisableLock + return(TRUE); + #else + + int flags; + int v_no; + char locker[17]; + + + HANDLE rif_file; + unsigned long bytes_read; + + int tries = 0; + + rif_file = CreateFileA (filename, GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, 0); + + while(rif_file == INVALID_HANDLE_VALUE && tries<10) + { + rif_file = CreateFileA (filename, GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, 0); + tries ++; + clock_t ctime = clock(); + double secs = (double)ctime / (double)CLOCKS_PER_SEC; + double secsgone; + do + { + ctime = clock(); + secsgone = (double)ctime / (double)CLOCKS_PER_SEC; + } + while( (secsgone-secs)<1); + } + + if (rif_file == INVALID_HANDLE_VALUE) { + error_code = CHECK_FAILED_NOT_OPEN; + return FALSE; + } + + + if (rif_file == INVALID_HANDLE_VALUE) { + error_code = CHECK_FAILED_NOT_OPEN; + return FALSE; + } + + SetFilePointer (rif_file,0,0,FILE_BEGIN); + + List obfptrs; + list_chunks_in_file(& obfptrs, rif_file, "RBOBJECT"); + +// ok, go through the objects, first locate the header and find +// the associated object. + + if (obfptrs.size()) { + + for (LIF obflst(&obfptrs); !obflst.done(); obflst.next()) { + + // go to start of chunk + SetFilePointer (rif_file,obflst(),0,FILE_BEGIN); + + // get header list + List obhead; + list_chunks_in_file(& obhead, rif_file, "OBJHEAD1"); + + assert (obhead.size() == 1); + + // go to lock status in header + SetFilePointer(rif_file,obhead.first_entry() + 12,0,FILE_BEGIN); + ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0); + ReadFile (rif_file, (long *) locker, 16, &bytes_read, 0); + + // go to version number + SetFilePointer(rif_file,obhead.first_entry() + 88,0,FILE_BEGIN); + ReadFile (rif_file, (long *) &v_no, 4, &bytes_read, 0); + + char name[50]; + + // get object identifier + SetFilePointer(rif_file,obhead.first_entry() + 96,0,FILE_BEGIN); + int i = 0; + do ReadFile (rif_file, (long *) (name + i), 1, &bytes_read, 0); + while (name[i++] != 0); + + Object_Chunk * tmpob; + Object_Header_Chunk * tmpobh; + List obchs; + lookup_child ("RBOBJECT",obchs); + + if (obchs.size()){ + for (LIF obchls(&obchs); !obchls.done(); obchls.next()){ + tmpob = (Object_Chunk *)obchls(); + // if this is the same object + if (!strcmp (name, tmpob->object_data.o_name)) break; + } + if (!obchls.done()) { + tmpobh = tmpob->get_header(); + if (tmpobh) { + if (tmpobh->version_no < v_no) + tmpob->updated_outside = TRUE; + if (flags & GENERAL_FLAG_LOCKED) { + // do the lock check + if (!tmpob->local_lock) { + tmpob->external_lock = TRUE; + strncpy(tmpobh->lock_user, locker,16); + tmpobh->lock_user[16] = '\0'; + } + else if (strncmp(tmpobh->lock_user, locker,16)) { + tmpob->external_lock = TRUE; + strncpy(tmpobh->lock_user, locker,16); + tmpobh->lock_user[16] = '\0'; + } + } + } + + } + + } + + } + + } + + // shapes + + SetFilePointer (rif_file,0,0,FILE_BEGIN); + + List shpfptrs; + list_chunks_in_file(& shpfptrs, rif_file, "REBSHAPE"); + + if (shpfptrs.size()) { + + for (LIF shpflst(&shpfptrs); !shpflst.done(); shpflst.next()) { + + // go to start of chunk + SetFilePointer (rif_file,shpflst(),0,FILE_BEGIN); + + // get header list + List shphead; + list_chunks_in_file(& shphead, rif_file, "SHPHEAD1"); + + assert (shphead.size() == 1); + + // go to lock status in header + SetFilePointer(rif_file,shphead.first_entry() + 12,0,FILE_BEGIN); + ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0); + ReadFile (rif_file, (long *) locker, 16, &bytes_read, 0); + + int id; + // get shape identifier + ReadFile (rif_file, (long *) &id, 4, &bytes_read, 0); + + + // Here we update max_id + Shape_Chunk::max_id = max (Shape_Chunk::max_id,id); + + // go to version number + SetFilePointer(rif_file,shphead.first_entry() + 100,0,FILE_BEGIN); + ReadFile (rif_file, (long *) &v_no, 4, &bytes_read, 0); + + Shape_Chunk * tmpshp; + Shape_Header_Chunk * tmpshph; + List shpchs; + lookup_child ("REBSHAPE",shpchs); + + if (shpchs.size()){ + for (LIF shpchls(&shpchs); !shpchls.done(); shpchls.next()){ + tmpshp = (Shape_Chunk *)shpchls(); + tmpshph = tmpshp->get_header(); + // if this is the same object + if (tmpshph) + if (id == tmpshph->file_id_num) break; + } + if (!shpchls.done()) { + if (tmpshph->version_no < v_no) + tmpshp->updated_outside = TRUE; + if (flags & GENERAL_FLAG_LOCKED) { + // do the lock check + if (!tmpshp->local_lock) { + tmpshp->external_lock = TRUE; + strncpy(tmpshph->lock_user, locker,16); + tmpshph->lock_user[16] = '\0'; + } + else if (strncmp(tmpshph->lock_user, locker,16)) { + tmpshp->external_lock = TRUE; + strncpy(tmpshph->lock_user, locker,16); + tmpshph->lock_user[16] = '\0'; + } + } + + } + + } + + } + + } + + // sprites + + SetFilePointer (rif_file,0,0,FILE_BEGIN); + + List sprfptrs; + list_chunks_in_file(& sprfptrs, rif_file, "RSPRITES"); + List sprchlst; + lookup_child("RSPRITES",sprchlst); + + AllSprites_Chunk * sprch; + AllSprites_Header_Chunk * sprhead = 0; + + if (sprchlst.size()) + { + sprch = (AllSprites_Chunk *)sprchlst.first_entry(); + sprhead = sprch->get_header(); + } + + if (sprhead) + { + if (sprfptrs.size()) + { + SetFilePointer (rif_file,sprfptrs.first_entry(),0,FILE_BEGIN); + + // get header list + List sprchhl; + list_chunks_in_file(& sprchhl, rif_file, "ASPRHEAD"); + + assert (sprchhl.size() == 1); + + // go to lock status in header + SetFilePointer(rif_file,sprchhl.first_entry() + 12,0,FILE_BEGIN); + ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0); + ReadFile (rif_file, (long *) locker, 16, &bytes_read, 0); + + // go to version number + SetFilePointer(rif_file,sprchhl.first_entry() + 32,0,FILE_BEGIN); + ReadFile (rif_file, (long *) &v_no, 4, &bytes_read, 0); + + if (sprhead->version_no < v_no) + { + sprch->updated_outside = TRUE; + } + if (flags & GENERAL_FLAG_LOCKED) + { + if (!sprch->local_lock) { + sprch->external_lock = TRUE; + strncpy(sprhead->lock_user, locker,16); + sprhead->lock_user[16] = '\0'; + } + else if (strncmp(sprhead->lock_user, locker,16)) { + sprch->external_lock = TRUE; + strncpy(sprhead->lock_user, locker,16); + sprhead->lock_user[16] = '\0'; + } + } + } + } + + // environment data + + SetFilePointer (rif_file,0,0,FILE_BEGIN); + + List edfptrs; + list_chunks_in_file(& edfptrs, rif_file, "REBENVDT"); + + Environment_Data_Chunk * ed; + Environment_Data_Header_Chunk * edhead = 0; + + + ed = (Environment_Data_Chunk *)lookup_single_child("REBENVDT"); + if (ed) + { + edhead = ed->get_header(); + } + + if (edhead) + { + if (edfptrs.size()) + { + SetFilePointer (rif_file,edfptrs.first_entry(),0,FILE_BEGIN); + + // get header list + List edhl; list_chunks_in_file(& edhl, rif_file, "ENDTHEAD"); + + assert (edhl.size() == 1); + + // go to lock status in header + SetFilePointer(rif_file,edhl.first_entry() + 12,0,FILE_BEGIN); + ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0); + ReadFile (rif_file, (long *) locker, 16, &bytes_read, 0); + + // go to version number + SetFilePointer(rif_file,edhl.first_entry() + 32,0,FILE_BEGIN); + ReadFile (rif_file, (long *) &v_no, 4, &bytes_read, 0); + + if (edhead->version_no < v_no) + { + ed->updated_outside = TRUE; + } + if (flags & GENERAL_FLAG_LOCKED) + { + if (!ed->local_lock) { + ed->external_lock = TRUE; + strncpy(edhead->lock_user, locker,16); + edhead->lock_user[16] = '\0'; + } + else if (strncmp(edhead->lock_user, locker,16)) { + ed->external_lock = TRUE; + strncpy(edhead->lock_user, locker,16); + edhead->lock_user[16] = '\0'; + } + } + } + } + + // check file for REBENUMS chunk + + SetFilePointer (rif_file,0,0,FILE_BEGIN); + + List enumfptrs; list_chunks_in_file(& enumfptrs, rif_file, "REBENUMS"); + + Enum_Chunk * enumch; + Enum_Header_Chunk * enumhead = 0; + + enumch = (Enum_Chunk *)lookup_single_child("REBENUMS"); + if (enumch) + { + enumhead = enumch->get_header(); + } + + if (enumhead) + { + if (enumfptrs.size()) + { + SetFilePointer (rif_file,enumfptrs.first_entry(),0,FILE_BEGIN); + + // get header list + List enumchhl; list_chunks_in_file(& enumchhl, rif_file, "ENUMHEAD"); + + assert (enumchhl.size() == 1); + + // go to lock status in header + SetFilePointer(rif_file,enumchhl.first_entry() + 12,0,FILE_BEGIN); + ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0); + ReadFile (rif_file, (long *) locker, 16, &bytes_read, 0); + + // go to version number + SetFilePointer(rif_file,enumchhl.first_entry() + 32,0,FILE_BEGIN); + ReadFile (rif_file, (long *) &v_no, 4, &bytes_read, 0); + + if (enumhead->version_no < v_no) + { + enumch->updated_outside = TRUE; + } + if (flags & GENERAL_FLAG_LOCKED) + { + if (!enumch->local_lock) { + enumch->external_lock = TRUE; + strncpy(enumhead->lock_user, locker,16); + enumhead->lock_user[16] = '\0'; + } + else if (strncmp(enumhead->lock_user, locker,16)) { + enumch->external_lock = TRUE; + strncpy(enumhead->lock_user, locker,16); + enumhead->lock_user[16] = '\0'; + } + } + } + } + + CloseHandle (rif_file); + + return TRUE; + #endif +} + + +#if InterfaceEngine + + extern File_Chunk * Env_Chunk; + +#endif + +BOOL File_Chunk::update_file() +{ + + #if DisableLock + if (!filename) return FALSE; + + char tempname [256]; + strcpy (tempname, filename); + + List slist; + list_shapes(&slist); + List olist; + list_objects(&olist); + + for (LIF sli(&slist); !sli.done(); sli.next()) + { + if (sli()->deleted) + { + delete sli(); + } + } + + for (LIF oli(&olist); !oli.done(); oli.next()) + { + if (oli()->deleted) + { + delete oli(); + } + } + + + return(write_file(tempname)); + + #else + +#if InterfaceEngine + + // log, to track error + char fname [256]; + char * dotpos; + + strcpy (fname, filename); + + dotpos = strrchr (fname, '.'); + + sprintf (dotpos, ".log"); + + FILE * log = fopen (fname, "a"); + +#endif + + if (!filename) return FALSE; + + twprintf("Updating %s\n",filename); + + check_file(); + + HANDLE rif_file; + unsigned long bytes_read; + + int tries = 0; + + //twprintf("Opening file\n"); + + rif_file = CreateFileA (filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, 0); + + if (rif_file == INVALID_HANDLE_VALUE) + { + DWORD error_num = GetLastError(); + switch (error_num) + { + case ERROR_SHARING_VIOLATION: + twprintf("Sharing violation - retrying\n"); + break; + case ERROR_ACCESS_DENIED: + twprintf("File is Read Only\n"); + return FALSE; + default: + twprintf("Unknown error updating file, Error code %#08x\n",error_num); + return FALSE; + } + } + + while(rif_file == INVALID_HANDLE_VALUE && tries<10) + { + twprintf("Again...\n"); + rif_file = CreateFileA (filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, 0); + tries ++; + clock_t ctime = clock(); + double secs = (double)ctime / (double)CLOCKS_PER_SEC; + double secsgone; + do + { + ctime = clock(); + secsgone = (double)ctime / (double)CLOCKS_PER_SEC; + } + while( (secsgone-secs)<1); + } + + if (rif_file == INVALID_HANDLE_VALUE) { + error_code = CHECK_FAILED_NOT_OPEN; + twprintf("ERROR - SHARING VIOLATION UNRESOLVED\n\n"); + return FALSE; + } + + //twprintf("Opened\n\n"); + + prepare_for_output(); + + SetFilePointer (rif_file,0,0,FILE_BEGIN); + + //twprintf("Version info\n"); + + List verinf; list_chunks_in_file(& verinf, rif_file, "RIFVERIN"); + +// taking first entry of this list, if there are more - tough ha ha +// there shouldn't be + +// Just increment it by one and reoutput +// check_file sets the internal copy of the chunk to the current file +// setting, so we need to increment that as well + + if (verinf.size()) { + + int f_version_num; + SetFilePointer (rif_file,verinf.first_entry() + 12,0,FILE_BEGIN); + ReadFile (rif_file, (long *) &f_version_num, 4, &bytes_read, 0); + + SetFilePointer (rif_file,verinf.first_entry() + 12,0,FILE_BEGIN); + + RIF_Version_Num_Chunk* rvnc=(RIF_Version_Num_Chunk*)lookup_single_child ("RIFVERIN"); + + if (rvnc) + rvnc->file_version_no++; + + f_version_num++; + + WriteFile (rif_file, (long *) &f_version_num, 4, &bytes_read, 0); + + } + +// go through the list of shape chunks looking for shape chunks to output + //twprintf("\nShapes\n"); + + List shplst; + lookup_child ("REBSHAPE",shplst); + + if (shplst.size()) + for (LIF sli(&shplst); !sli.done(); sli.next()) { + + Shape_Chunk * tmpshpptr = ((Shape_Chunk *)sli()); + + if (tmpshpptr->updated && + !(tmpshpptr->updated_outside || tmpshpptr->external_lock)) + tmpshpptr->update_chunk_in_file(rif_file); + } + + +// go through the list of object chunks looking for chunks to output + //twprintf("\nObjects\n"); + + List oblst; + lookup_child ("RBOBJECT",oblst); + + if (oblst.size()) + for (LIF oli(&oblst); !oli.done(); oli.next()) { + + Object_Chunk * tmpobptr = ((Object_Chunk *)oli()); + + if (tmpobptr->updated && !(tmpobptr->updated_outside || tmpobptr->external_lock)) + tmpobptr->update_chunk_in_file(rif_file); + + } + + + //twprintf("\nSprites\n"); + + List sprfptrs; + lookup_child ("RSPRITES",sprfptrs); + AllSprites_Chunk * sprch; + + if (sprfptrs.size()) + { + sprch = (AllSprites_Chunk *)sprfptrs.first_entry(); + if (sprch->updated && + !(sprch->updated_outside || sprch->external_lock)) + sprch->update_chunk_in_file(rif_file); + } + + //twprintf("\nEnvironment data\n"); + + Environment_Data_Chunk * ed; + + ed = (Environment_Data_Chunk *)lookup_single_child ("REBENVDT"); + if (ed) + { + +#if InterfaceEngine + + fprintf (log, "Env_Data %d %d %d %d", ed->updated, ed->local_lock, ed->updated_outside, ed->external_lock); + +#endif + + if (ed->updated && + !(ed->updated_outside || ed->external_lock)) + ed->update_chunk_in_file(rif_file); + } + + //twprintf("\nEnum data\n"); + + List enumfptrs; + lookup_child ("REBENUMS",enumfptrs); + Enum_Chunk * enumch; + + if (enumfptrs.size()) + { + enumch = (Enum_Chunk *)enumfptrs.first_entry(); + if (enumch->updated && + !(enumch->updated_outside || enumch->external_lock)) + enumch->update_chunk_in_file(rif_file); + } + + // + + int file_length = GetFileSize(rif_file,0); + SetFilePointer (rif_file,8,0,FILE_BEGIN); + + WriteFile (rif_file, (long *) &file_length, 4, &bytes_read, 0); + + CloseHandle (rif_file); + +#if InterfaceEngine + + fclose (log); + +#endif + return TRUE; + + #endif //DisableLock +} + +BOOL File_Chunk::update_chunks_from_file() +{ + #if DisableLock + return(TRUE); + #endif + + if (!filename) return FALSE; + check_file(); + + HANDLE rif_file; + unsigned long bytes_read; + + rif_file = CreateFileA (filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, 0); + + if (rif_file == INVALID_HANDLE_VALUE) { + error_code = CHECK_FAILED_NOT_OPEN; + return FALSE; + } + + SetFilePointer (rif_file,0,0,FILE_BEGIN); + + List verinf; list_chunks_in_file(& verinf, rif_file, "RIFVERIN"); + + if (verinf.size()) { + + int f_version_num; + SetFilePointer (rif_file,verinf.first_entry() + 12,0,FILE_BEGIN); + ReadFile (rif_file, (long *) &f_version_num, 4, &bytes_read, 0); + + SetFilePointer (rif_file,verinf.first_entry() + 12,0,FILE_BEGIN); + + List lverinf; + lookup_child ("RIFVERIN",lverinf); + + if (lverinf.size()) + if (f_version_num == ((RIF_Version_Num_Chunk *)(lverinf.first_entry()))->file_version_no){ + CloseHandle (rif_file); + return TRUE; + } + + } + + // go through the list of object chunks looking for chunks to input + + List oblst; + lookup_child ("RBOBJECT",oblst); + + if (oblst.size()) + for (LIF oli(&oblst); !oli.done(); oli.next()) { + + Object_Chunk * tmpobptr = ((Object_Chunk *)oli()); + + if (tmpobptr->updated_outside) { + // find the chunk, then input it to a buffer and create a new object + // from the buffer + SetFilePointer (rif_file,0,0,FILE_BEGIN); + + List obfptrs; list_chunks_in_file(& obfptrs, rif_file, "RBOBJECT"); + + char name[50]; + + LIF ofpl(&obfptrs); + + if (obfptrs.size()) { + for (; !ofpl.done(); ofpl.next()) { + + SetFilePointer (rif_file, ofpl(),0,FILE_BEGIN); + // get header list + List obhead; list_chunks_in_file(& obhead, rif_file, "OBJHEAD1"); + + assert (obhead.size() == 1); + + // get object identifier + SetFilePointer(rif_file,obhead.first_entry() + 96,0,FILE_BEGIN); + int i = 0; + do ReadFile (rif_file, (long *) (name + i), 1, &bytes_read, 0); + while (name[i++] != 0); + + if (!strcmp(name, tmpobptr->object_data.o_name)) break; + } + } + + if (!ofpl.done()) { + + char * buffer; + + SetFilePointer (rif_file,ofpl()+8,0,FILE_BEGIN); + int length; + ReadFile(rif_file, (long *) &length, 4, &bytes_read, 0); + buffer = new char [length]; + ReadFile(rif_file, (long *) buffer, length-12, &bytes_read, 0); + new Object_Chunk (this, buffer, length-12); + delete [] buffer; + if (tmpobptr->get_header()) + if (tmpobptr->get_header()->associated_shape) + tmpobptr->deassoc_with_shape(tmpobptr->get_header()->associated_shape); + delete tmpobptr; + + } + + + } + + } + +// go through the list of shape chunks looking for shape chunks to input + + List shplst; + lookup_child ("REBSHAPE",shplst); + + if (shplst.size()) + for (LIF sli(&shplst); !sli.done(); sli.next()) { + + Shape_Chunk * tmpshpptr = ((Shape_Chunk *)sli()); + + Shape_Header_Chunk * shhead = tmpshpptr->get_header(); + + if (!shhead) continue; + + if (tmpshpptr->updated_outside) { + // find the chunk, then input it to a buffer and create a new object + // from the buffer + SetFilePointer (rif_file,0,0,FILE_BEGIN); + + List shfptrs; list_chunks_in_file(& shfptrs, rif_file, "REBSHAPE"); + + LIF sfpl(&shfptrs); + + if (shfptrs.size()) { + for (sfpl.restart(); !sfpl.done(); sfpl.next()) { + + SetFilePointer (rif_file, sfpl(),0,FILE_BEGIN); + // get header list + List shphead; list_chunks_in_file(& shphead, rif_file, "SHPHEAD1"); + + assert (shphead.size() == 1); + + // get object identifier + SetFilePointer(rif_file,shphead.first_entry() + 32,0,FILE_BEGIN); + int sh_number; + ReadFile (rif_file, (long *) &sh_number, 4, &bytes_read, 0); + + if (sh_number == shhead->file_id_num) break; + } + } + + if (!sfpl.done()) { + + char * buffer; + + SetFilePointer (rif_file,sfpl()+8,0,FILE_BEGIN); + int length; + ReadFile(rif_file, (long *) &length, 4, &bytes_read, 0); + buffer = new char [length]; + ReadFile(rif_file, (long *) buffer, length-12, &bytes_read, 0); + new Shape_Chunk (this, buffer, length-12); + delete [] buffer; + // Associate with the new objects + if ((shhead->associated_objects_store).size()) + { + for (LIF aol(&(shhead->associated_objects_store)); !aol.done(); aol.next()) + { + tmpshpptr->deassoc_with_object(aol()); + } + } + delete tmpshpptr; + } + } + } + + post_input_processing(); + + CloseHandle(rif_file); + + return TRUE; + +} + +void File_Chunk::list_objects(List * pList) +{ + Chunk * child_ptr = children; + + while (pList->size()) + pList->delete_first_entry(); + + if (children) + while (child_ptr != NULL) { + if (strncmp ("RBOBJECT", child_ptr->identifier, 8) == NULL) + { + assert (!child_ptr->r_u_miscellaneous()); + pList->add_entry((Object_Chunk *)child_ptr); + } + child_ptr = child_ptr->next; + } + +} + +void File_Chunk::list_shapes(List * pList) +{ + Chunk * child_ptr = children; + + while (pList->size()) + pList->delete_first_entry(); + + if (children) + while (child_ptr != NULL) { + if (strncmp ("REBSHAPE", child_ptr->identifier, 8) == NULL) + { + assert (!child_ptr->r_u_miscellaneous()); + pList->add_entry((Shape_Chunk *)child_ptr); + } + child_ptr = child_ptr->next; + } + +} + +void File_Chunk::list_dummy_objects(List * pList){ + Chunk * child_ptr = children; + + while (pList->size()) + pList->delete_first_entry(); + + if (children) + while (child_ptr != NULL) { + if (strncmp ("DUMMYOBJ", child_ptr->identifier, 8) == NULL) + { + assert (!child_ptr->r_u_miscellaneous()); + pList->add_entry((Dummy_Object_Chunk *)child_ptr); + } + child_ptr = child_ptr->next; + } + +} + +Environment_Data_Chunk * File_Chunk::get_env_data() +{ + List e_list; + Chunk * child_ptr = children; + + if (children) + while (child_ptr != NULL) { + if (strncmp ("REBENVDT", child_ptr->identifier, 8) == NULL) + { + assert (!child_ptr->r_u_miscellaneous()); + e_list.add_entry((Environment_Data_Chunk *)child_ptr); + } + child_ptr = child_ptr->next; + } + + // There can be only ONE. + assert (e_list.size() < 2); + + if (e_list.size()) + return e_list.first_entry(); + else + { + return(0); + } +} + +void File_Chunk::build_object_array() +{ + List oblist; + list_objects(&oblist); + + if(object_array) + { + free(object_array); + object_array=0; + } + object_array_size=0; + + LIF oblif(&oblist); + + //find the highest object index + for(oblif.restart();!oblif.done();oblif.next()) + { + object_array_size=max(object_array_size,oblif()->object_data.index_num+1); + } + + if(object_array_size<=0) return; + + object_array = (Object_Chunk**) malloc(sizeof(Object_Chunk*)*object_array_size); + for(int i=0;iobject_data.index_num; + if(index>=0) + { + object_array[index]=oblif(); + } + } +} + +Object_Chunk* File_Chunk::get_object_by_index(int index) +{ + if(!object_array) build_object_array(); + if(index<0 || index>=object_array_size)return 0; + return object_array[index]; +} + +void File_Chunk::assign_index_to_object(Object_Chunk* object) +{ + assert(object); + + if(!object_array) build_object_array(); + //see if there is a free index + + for(int i=0;iobject_data_store->index_num=i; + object_array[i]=object; + return; + } + } + + //add a new entry on the end of the array + object_array_size++; + + object_array=(Object_Chunk**) realloc(object_array,sizeof(Object_Chunk*)*object_array_size); + + + object->object_data_store->index_num=object_array_size-1;; + object_array[object_array_size-1]=object; +} + +///////////////////////////////////////// + +// Class GodFather_Chunk functions + +/* +Children for GodFather_Chunk : +"REBSHAPE" Shape_Chunk +"RSPRITES" AllSprites_Chunk +"RBOBJECT" Object_Chunk +"RIFVERIN" RIF_Version_Num_Chunk +"REBENVDT" Environment_Data_Chunk +"REBENUMS" Enum_Chunk +"OBJCHIER" Object_Hierarchy_Chunk +"OBHALTSH" Object_Hierarchy_Alternate_Shape_Set_Chunk + +*/ + +GodFather_Chunk::GodFather_Chunk(char * buffer, size_t size) +: Chunk_With_Children (NULL, "REBINFF2") +{ + Parent_File = this; + + char * buffer_ptr = buffer; + + // The start of the first chunk + + while ((buffer_ptr-buffer)< ((signed)size-12) && !error_code) { + + if ((*(int *)(buffer_ptr + 8)) + (buffer_ptr-buffer) > ((signed)size-12)) { + error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + + DynCreate(buffer_ptr); + buffer_ptr += *(int *)(buffer_ptr + 8); + + } + +} + +///////////////////////////////////////// + +// Class RIF_Version_Num_Chunk functions + +RIF_IMPLEMENT_DYNCREATE("RIFVERIN",RIF_Version_Num_Chunk) + +void RIF_Version_Num_Chunk::fill_data_block(char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = file_version_no; + +} + + +///////////////////////////////////////// + +// Class RIF_Name_Chunk functions +RIF_IMPLEMENT_DYNCREATE("RIFFNAME",RIF_Name_Chunk) + +RIF_Name_Chunk::RIF_Name_Chunk (Chunk_With_Children * parent, const char * rname) +: Chunk (parent, "RIFFNAME") +{ + rif_name = new char [strlen(rname)+1]; + strcpy (rif_name, rname); +} + +RIF_Name_Chunk::RIF_Name_Chunk (Chunk_With_Children * parent, const char * rdata, size_t /*rsize*/) +: Chunk (parent, "RIFFNAME") +{ + rif_name = new char [strlen(rdata)+1]; + strcpy (rif_name, rdata); +} + +RIF_Name_Chunk::~RIF_Name_Chunk () +{ + if (rif_name) + delete [] rif_name; +} + + +void RIF_Name_Chunk::fill_data_block (char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + strcpy (data_start, rif_name); + +} + + +/////////////////////////////////////// + +/* +Children for RIF_File_Chunk : +"REBSHAPE" Shape_Chunk +"RSPRITES" AllSprites_Chunk +"RBOBJECT" Object_Chunk +"RIFVERIN" RIF_Version_Num_Chunk +"REBENVDT" Environment_Data_Chunk +"OBJCHIER" Object_Hierarchy_Chunk +"OBHALTSH" Object_Hierarchy_Alternate_Shape_Set_Chunk + +*/ + + +RIF_File_Chunk::RIF_File_Chunk (Chunk_With_Children * parent, const char * file_name) +: Chunk_With_Children (parent, "SUBRIFFL") +{ + char rifIsCompressed = FALSE; + char *uncompressedData = NULL; + HANDLE rif_file; + DWORD file_size; + DWORD file_size_from_file; + unsigned long bytes_read; + char * buffer; + char * buffer_ptr; + char id_buffer[9]; + + + Chunk * ParentFileStore = Parent_File; + + Parent_File = this; + + error_code = 0; + + rif_file = CreateFileA (file_name, GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, 0); + + + if (rif_file == INVALID_HANDLE_VALUE) { + error_code = CHUNK_FAILED_ON_LOAD; + Parent_File = ParentFileStore; + return; + } + + file_size = GetFileSize (rif_file, NULL); + + if (!ReadFile(rif_file, id_buffer, 8, &bytes_read, 0)) { + error_code = CHUNK_FAILED_ON_LOAD; + CloseHandle (rif_file); + Parent_File = ParentFileStore; + return; + } + + //check for compressed rif + if (!strncmp (id_buffer, COMPRESSED_RIF_IDENTIFIER, 8)) + { + rifIsCompressed = TRUE; + } + else if (strncmp (id_buffer, "REBINFF2", 8)) { + error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + CloseHandle (rif_file); + Parent_File = ParentFileStore; + return; + } + + buffer = new char [file_size]; + + /* KJL 17:57:44 19/09/98 - if the rif is compressed, we must load the whole + file in and then pass it to the decompression routine, which will return a + pointer to the original data. */ + if (rifIsCompressed) + { + if (!ReadFile(rif_file, buffer+8, (file_size-8), &bytes_read, 0)) + { + error_code = CHUNK_FAILED_ON_LOAD; + CloseHandle (rif_file); + Parent_File = ParentFileStore; + delete [] buffer; + return; + } + uncompressedData = HuffmanDecompress((HuffmanPackage*)buffer); + file_size = ((HuffmanPackage*)buffer)->UncompressedDataSize; + + delete [] buffer; // kill the buffer the compressed file was loaded into + + buffer_ptr = buffer = uncompressedData+12; // skip header data + } + else // the normal uncompressed approach: + { + //get the file size stored in the rif file + if (!ReadFile(rif_file, &file_size_from_file, 4, &bytes_read, 0)) { + error_code = CHUNK_FAILED_ON_LOAD; + CloseHandle (rif_file); + Parent_File = ParentFileStore; + delete [] buffer; + return; + } + + //and compare with the actual file size + if (file_size != file_size_from_file) { + error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + CloseHandle (rif_file); + Parent_File = ParentFileStore; + delete [] buffer; + return; + } + + //read the rest of the file into the buffer + if (!ReadFile(rif_file, buffer, (file_size-12), &bytes_read, 0)) + { + error_code = CHUNK_FAILED_ON_LOAD; + CloseHandle (rif_file); + Parent_File = ParentFileStore; + delete [] buffer; + return; + } + buffer_ptr = buffer; + } + + + + + // Process the RIF + + // The start of the first chunk + + while ((buffer_ptr-buffer)< ((signed) file_size-12) && !error_code) { + + if ((*(int *)(buffer_ptr + 8)) + (buffer_ptr-buffer) > ((signed)file_size-12)) { + error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + + DynCreate(buffer_ptr); + buffer_ptr += *(int *)(buffer_ptr + 8); + } + + /* KJL 17:59:42 19/09/98 - release the memory holding the rif */ + if (rifIsCompressed) + { + free(uncompressedData); + } + else + { + delete [] buffer; + } + + CloseHandle (rif_file); + + post_input_processing(); + + Parent_File = ParentFileStore; + +} + +void RIF_File_Chunk::post_input_processing() +{ + List shplist; + List objlist; + + List child_lists; + + lookup_child("REBSHAPE",child_lists); + + while (child_lists.size()) { + shplist.add_entry((Shape_Chunk *)child_lists.first_entry()); + child_lists.delete_first_entry(); + } + + lookup_child("RBOBJECT",child_lists); + + + while (child_lists.size()) { + objlist.add_entry((Object_Chunk *)child_lists.first_entry()); + child_lists.delete_first_entry(); + } + + for (LIF ol(&objlist); !ol.done(); ol.next()) { + + if (ol()->get_header()) { + + for (LIF sl(&shplist); + !sl.done(); sl.next()) { + if (sl()->get_header()) + if (sl()->get_header()->file_id_num == ol()->get_header()->shape_id_no){ + ol()->assoc_with_shape(sl()); + break; + } + } + } + + } + + for (LIF sli(&shplist); !sli.done(); sli.next()) + { + Shape_Chunk::max_id = max (Shape_Chunk::max_id,sli()->get_header()->file_id_num); + } + + Chunk_With_Children::post_input_processing(); +} + + +void RIF_File_Chunk::list_objects(List * pList) +{ + Chunk * child_ptr = children; + + while (pList->size()) + pList->delete_first_entry(); + + if (children) + while (child_ptr != NULL) { + if (strncmp ("RBOBJECT", child_ptr->identifier, 8) == NULL) + { + assert (!child_ptr->r_u_miscellaneous()); + pList->add_entry((Object_Chunk *)child_ptr); + } + child_ptr = child_ptr->next; + } +} + +void RIF_File_Chunk::list_shapes(List * pList) +{ + Chunk * child_ptr = children; + + while (pList->size()) + pList->delete_first_entry(); + + if (children) + while (child_ptr != NULL) { + if (strncmp ("REBSHAPE", child_ptr->identifier, 8) == NULL) + { + assert (!child_ptr->r_u_miscellaneous()); + pList->add_entry((Shape_Chunk *)child_ptr); + } + child_ptr = child_ptr->next; + } + +} + +Environment_Data_Chunk * RIF_File_Chunk::get_env_data() +{ + List e_list; + Chunk * child_ptr = children; + + if (children) + while (child_ptr != NULL) { + if (strncmp ("REBENVDT", child_ptr->identifier, 8) == NULL) + { + assert (!child_ptr->r_u_miscellaneous()); + e_list.add_entry((Environment_Data_Chunk *)child_ptr); + } + child_ptr = child_ptr->next; + } + + // There can be only ONE. + assert (e_list.size() < 2); + + if (e_list.size()) + return e_list.first_entry(); + else + { + return(0); + } +} diff --git a/3dc/win95/MISHCHNK.HPP b/3dc/win95/MISHCHNK.HPP new file mode 100644 index 0000000..957398e --- /dev/null +++ b/3dc/win95/MISHCHNK.HPP @@ -0,0 +1,250 @@ +#ifndef _miscchunk_hpp +#define _miscchunk_hpp 1 + +#include +#include "chunk.hpp" + +#include "chnktype.hpp" + +#if engine + +#define UseLocalAssert No +#include "ourasert.h" +#define assert(x) GLOBALASSERT(x) + +#else + +#if cencon +#include "ccassert.h" +#else +#include +#endif + +#endif + +#if cencon +#include "output.hpp" +#else +#define twprintf printf + +extern char * users_name; +#endif + +class File_Chunk; + +class Lockable_Chunk_With_Children : public Chunk_With_Children +{ + +public: + + Lockable_Chunk_With_Children (Chunk_With_Children * parent, const char * identifier) + : Chunk_With_Children (parent, identifier), + updated (FALSE),updated_outside (FALSE),local_lock (FALSE),external_lock(FALSE), + output_chunk_for_process (FALSE), deleted (FALSE) + {} + + +// derived classes from this class must have the +// following functions (or it won't compile)!! + + virtual BOOL file_equals(HANDLE &) = 0; + // the file equals function knows to look in + // the file from the start of the current chunk + // to see if the current chunk is the same one + + virtual const char * get_head_id() = 0; + virtual void set_lock_user(char *) = 0; + +// this function will lock the chunk if it can - +// will return true on success or if the chunk has +// already been locked locally. + + BOOL lock_chunk(File_Chunk &); + +// The unlock_chunk will unlock the chunk +// if the updateyn flag is set, the updated flag will be set +// internally and the chunk may be updated on the next file update +// If there is no update, the chunk will be unlocked in the file + + BOOL unlock_chunk (File_Chunk &, BOOL updateyn); + + BOOL update_chunk_in_file(HANDLE &rif_file); + + // Selective output functions, + // These will output on condition of the flag, the flag will be set + // to FALSE + + BOOL output_chunk_for_process; + + virtual size_t size_chunk_for_process(); + + virtual void fill_data_block_for_process(char * data_start); + + + BOOL updated; + BOOL updated_outside; + BOOL local_lock; + BOOL external_lock; + + BOOL deleted; + +}; + + +/////////////////////////////////////////////// + +class Object_Chunk; +class Shape_Chunk; +class Dummy_Object_Chunk; +class Environment_Data_Chunk; + +class File_Chunk : public Chunk_With_Children +{ +public: + + //constructor + File_Chunk (const char * filename); + File_Chunk (); + + //destructor + ~File_Chunk (); + + // file handling + BOOL update_file (); + BOOL write_file (const char *); + + BOOL check_file(); + + BOOL update_chunks_from_file(); + + // the file_chunk must link all of its shapes & objects together + // in post_input_processing + + virtual void post_input_processing(); + + // copy string when constructed + // to this variable + char * filename; + + + // some easy access functions + + void list_objects(List * pList); + void list_shapes(List * pList); + void list_dummy_objects(List * pList); + + Environment_Data_Chunk * get_env_data(); + + Object_Chunk* get_object_by_index(int index); + void assign_index_to_object(Object_Chunk* object); + +private: + + friend class Shape_Chunk; + friend class Object_Chunk; + friend class Lockable_Chunk_With_Children; + + int flags; + + int object_array_size; + Object_Chunk** object_array; + + void build_object_array(); +}; + +/////////////////////////////////////////////// + + +class RIF_Version_Num_Chunk : public Chunk +{ +public: + RIF_Version_Num_Chunk (Chunk_With_Children * parent, const char *data, size_t /*size*/) + : Chunk (parent,"RIFVERIN"), file_version_no (*((int *) data)) + {} + + int file_version_no; + +// output_chunk updates the above + + virtual void fill_data_block (char * data_start); + + virtual size_t size_chunk () + { + chunk_size = 16; + return 16; + } + +private: + + friend class File_Chunk; + friend class GodFather_Chunk; + friend class RIF_File_Chunk; + + + + RIF_Version_Num_Chunk (Chunk_With_Children * parent) + : Chunk (parent,"RIFVERIN"), file_version_no (0) + {} +}; + +/////////////////////////////////////////////// + +class RIF_File_Chunk : public Chunk_With_Children +{ +public: + + // This is a special chunk which does not output itself + + RIF_File_Chunk (Chunk_With_Children * parent, const char * fname); + + size_t size_chunk() + { + return chunk_size = 0; + } + + virtual void post_input_processing(); + + BOOL output_chunk (HANDLE & /*h*/){return TRUE;}; + void fill_data_block (char * /*c*/){}; + + void list_objects(List * pList); + void list_shapes(List * pList); + Environment_Data_Chunk * get_env_data(); + +}; + +/////////////////////////////////////////////// + +class RIF_Name_Chunk : public Chunk +{ +public: + + RIF_Name_Chunk (Chunk_With_Children * parent, const char * rname); + ~RIF_Name_Chunk(); + // constructor from buffer + RIF_Name_Chunk (Chunk_With_Children * parent, const char * sdata, size_t ssize); + char * rif_name; + + virtual size_t size_chunk () + { + return (chunk_size = 12 + strlen (rif_name) + 4 - strlen (rif_name)%4); + } + + virtual void fill_data_block (char * data_start); + +private: + + friend class Environment_Data_Chunk; + friend class Environment_Game_Mode_Chunk; + friend class Shape_External_File_Chunk; + friend class Sprite_Header_Chunk; + + + +}; + + + + + +#endif \ No newline at end of file diff --git a/3dc/win95/MMX_MATH.H b/3dc/win95/MMX_MATH.H new file mode 100644 index 0000000..594ac0e --- /dev/null +++ b/3dc/win95/MMX_MATH.H @@ -0,0 +1,469 @@ +#ifndef _included_mmx_math_h_ +#define _included_mmx_math_h_ + +#if SUPPORT_MMX + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* +Calling-convention independent +definitions of inline MMX assembler +functions and declarations for non- +inline MMX assembler functions +*/ + +/* SPECIFICATION */ +/* +Dot Product and Vector Transform functions take +arguments referencing matrices or vectors whose +elements are 32 bit signed integers and arranged as +follows. All integers (including the results) are +in 16.16 fixed point form - ie. The 64-bit results +are shifted down 16 bits (divided by 65536) before +being written back as 32-bit values. Results are +rounded down (towards negative infinity). + +the matrix structure looks like this (not ideal!) +[ +00 +0c +18 ] +[ +04 +10 +1c ] +[ +08 +14 +20 ] + +and the vector structure looks like this +[ +00 ] +[ +04 ] +[ +08 ] +*/ + +/* TYPICAL CHARACTERISTICS */ +/* +Accuracy + +Internal rounding errors may be propogated, and +the results may not be exact. For the Dot Product +result and the Vector Transform results (x,y and z +independently), the error distributions are all +the same, as follows: + +Exact: 25% +-1: 50% +-2: 25% + +Better accuracy can be obtained by adding 1 to each integer result, +but this will produce poor results in the case of nice simple round +numbers, eg Dot({1.0,0.0,0.0},{0.0,1.0,0.0}) gives 1 not 0! + +Speed + +The DotProduct Takes 33 cycles (not including call instruction) +The inline DotProduct takes 30+1 cycles (the last instruction is pairable) +All Vector transforms take 63 cycles. These figures assume no +stalls due to cache misses or misaligned data. A matrix multiply +or cross product could be supplied if it is thought they would +be necessary + + +For optimal performance, it is recommended that vector and +matrix structures should be aligned to EIGHT byte boundaries. +To ensure this in arrays of vectors/matrices, the structure +should contain a dummy padding 32-bit value (recommended). +*/ + +/* storage class specifier for assembler calls */ + +#ifdef __WATCOMC__ +#define _asmcall +#define _asminline +#elif defined(_MSC_VER) +#define _asmcall static __inline +#define _asminline static __inline +#else +#error "Unknown compiler" +#endif + +/* forward reference declared in global scope */ +struct vectorch; +struct matrixch; + +/***********************/ +/* F-U-N-C-T-I-O-N */ +/* P-R-O-T-O-T-Y-P-E-S */ +/* F-O-R A-L-L */ +/* P-U-B-L-I-C */ +/* F-U-N-C-T-I-O-N-S */ +/***********************/ + +/* overwrites the input vector with the new vector */ +_asmcall void MMX_VectorTransform(struct vectorch * vector, struct matrixch const * matrix); +/* fills a new vector with the result of the input vector transformed by the matrix */ +_asmcall void MMX_VectorTransformed(struct vectorch * v_result, struct vectorch const * v_parm, struct matrixch const * matrix); +/* overwrites the input vector with the new vector, then adds another vector */ +_asmcall void MMX_VectorTransformAndAdd(struct vectorch * vector, struct matrixch const * matrix, struct vectorch const * v_add); +/* fills a new vector with the result of the input vector transformed by the matrix then added to another vector */ +_asmcall void MMX_VectorTransformedAndAdd(struct vectorch * v_result, struct vectorch const * v_parm, struct matrixch const * matrix, struct vectorch const * v_add); +/* compute dot product */ +_asmcall signed MMX_VectorDot(struct vectorch const * v1, struct vectorch const * v2); +/* this one assumes all the input vector elements are in the range [-32768,32767] */ +_asmcall signed MMX_VectorDot16(struct vectorch const * v1, struct vectorch const * v2); + +/* inline versions */ +_asminline signed MMXInline_VectorDot(struct vectorch const * v1, struct vectorch const * v2); +_asminline signed MMXInline_VectorDot16(struct vectorch const * v1, struct vectorch const * v2); + +/*****************/ +/* PRIVATE PARTS */ +/*****************/ + +/* Assembler labels */ +extern void MMXAsm_VectorTransform(void); +extern void MMXAsm_VectorTransformed(void); +extern void MMXAsm_VectorTransformAndAdd(void); +extern void MMXAsm_VectorTransformedAndAdd(void); +extern void MMXAsm_VectorDot(void); +extern void MMXAsm_VectorDot16(void); + +/* inline calls to MMX functions with correct parameters set */ +#ifdef __WATCOMC__ + +#pragma aux MMX_VectorTransform = "call MMXAsm_VectorTransform" parm [eax] [edx]; +#pragma aux MMX_VectorTransformed = "call MMXAsm_VectorTransformed" parm [eax] [edx] [ecx]; +#pragma aux MMX_VectorTransformAndAdd = "call MMXAsm_VectorTransformAndAdd" parm [eax] [edx] [ecx]; +#pragma aux MMX_VectorTransformedAndAdd = "call MMXAsm_VectorTransformedAndAdd" parm [eax] [edx] [ecx] [ebx]; +#pragma aux MMX_VectorDot = "call MMXAsm_VectorDot" parm [eax] [edx] value [eax]; +#pragma aux MMX_VectorDot16 = "call MMXAsm_VectorDot16" parm [eax] [edx] value [eax]; + +#elif defined(_MSC_VER) + +_asmcall void MMX_VectorTransform(struct vectorch * vector, struct matrixch const * matrix) +{ + _asm + { + mov eax,vector + mov edx,matrix + call MMXAsm_VectorTransform + } +} +_asmcall void MMX_VectorTransformed(struct vectorch * v_result, struct vectorch const * v_parm, struct matrixch const * matrix) +{ + _asm + { + mov eax,v_result + mov edx,v_parm + mov ecx,matrix + call MMXAsm_VectorTransformed + } +} +_asmcall void MMX_VectorTransformAndAdd(struct vectorch * vector, struct matrixch const * matrix, struct vectorch const * v_add) +{ + _asm + { + mov eax,vector + mov edx,matrix + mov ecx,v_add + call MMXAsm_VectorTransformAndAdd + } +} +_asmcall void MMX_VectorTransformedAndAdd(struct vectorch * v_result, struct vectorch const * v_parm, struct matrixch const * matrix, struct vectorch const * v_add) +{ + _asm + { + mov eax,v_result + mov edx,v_parm + mov ecx,matrix + mov ebx,v_add + call MMXAsm_VectorTransformedAndAdd + } +} +_asmcall signed MMX_VectorDot(struct vectorch const * v1, struct vectorch const * v2) +{ + signed retval; + _asm + { + mov eax,v1 + mov edx,v2 + call MMXAsm_VectorDot + mov retval,eax + } + return retval; +} +_asmcall signed MMX_VectorDot16(struct vectorch const * v1, struct vectorch const * v2) +{ + signed retval; + _asm + { + mov eax,v1 + mov edx,v2 + call MMXAsm_VectorDot16 + mov retval,eax + } + return retval; +} + +#else + +#error "Unknown compiler" + +#endif + + +/* Cross product? Mod? MatrixMultiply? */ + +/* globals */ + +extern int use_mmx_math; + +/* inline functions - no call */ + +extern __int64 const mmx_sign_mask; +extern __int64 const mmx_one_fixed_h; + +#ifdef __WATCOMC__ + +#pragma aux MMXInline_VectorDot = \ +\ +" movq mm0,[edx]" \ +\ +" movd mm2,[edx+08h]" \ +" movq mm4,mm0" \ +\ +" pand mm4,mmx_sign_mask" \ +" movq mm6,mm2" \ +\ +" movq mm1,[eax]" \ +" paddd mm4,mm4" \ +\ +" movd mm3,[eax+08h]" \ +" movq mm5,mm1" \ +\ +" pand mm6,mmx_sign_mask" \ +" movq mm7,mm3" \ +\ +" pand mm5,mmx_sign_mask" \ +" paddd mm6,mm6" \ +\ +" pand mm7,mmx_sign_mask" \ +" paddd mm5,mm5" \ +\ +" paddd mm0,mm4" \ +" paddd mm2,mm6" \ +\ +" paddd mm7,mm7" \ +" movq mm4,mm2" \ +\ +" punpcklwd mm4,mm0" \ +" paddd mm1,mm5" \ +\ +" punpckhwd mm2,mm0" \ +" paddd mm3,mm7" \ +\ +" movq mm5,mm3" \ +" punpckhwd mm3,mm1" \ +\ +" punpcklwd mm5,mm1" \ +" movq mm0,mm2" \ +\ +" movq mm1,mm4" \ +" pmaddwd mm0,mm3" \ +\ +" movq mm6,mm3" \ +" psrlq mm3,32" \ +\ +" movq mm7,mm5" \ +" punpckldq mm3,mm6" \ +\ +" pmaddwd mm1,mm5" \ +" psrlq mm5,32" \ +\ +" punpckldq mm5,mm7" \ +" pmaddwd mm2,mm3" \ +\ +" pmaddwd mm4,mm5" \ +" movq mm3,mm0" \ +\ +" punpckldq mm0,mm1" \ +\ +" psubd mm0,mmx_one_fixed_h" \ +" punpckhdq mm1,mm3" \ +\ +" psrad mm0,16" \ +" paddd mm2,mm4" \ +\ +" pslld mm1,16" \ +" paddd mm2,mm0" \ +\ +" paddd mm2,mm1" \ +\ +" movq mm1,mm2" \ +" psrlq mm2,32" \ +\ +" paddd mm1,mm2" \ +\ +" movd eax,mm1" \ +\ +" emms" \ +\ +" inc eax" \ +\ +parm [eax] [edx] value [eax]; + +#pragma aux MMXInline_VectorDot16 = \ +\ +" movd mm0,[edx+08h]" \ +\ +" packssdw mm0,[edx]" \ +\ +" movd mm1,[eax+08h]" \ +\ +" packssdw mm1,[eax]" \ +\ +" pmaddwd mm0,mm1" \ +\ +" movq mm1,mm0" \ +" psrlq mm0,32" \ +\ +" paddd mm0,mm1" \ +\ +" movd eax,mm0" \ +\ +" emms" \ +\ +parm [eax] [edx] value [eax]; + +#elif defined(_MSC_VER) + +_asminline signed MMXInline_VectorDot(struct vectorch const * v1, struct vectorch const * v2) +{ + signed retval; + _asm + { + mov edx,v1 + mov eax,v2 + + movq mm0,[edx] + + movd mm2,[edx+08h] + movq mm4,mm0 + + pand mm4,mmx_sign_mask + movq mm6,mm2 + + movq mm1,[eax] + paddd mm4,mm4 + + movd mm3,[eax+08h] + movq mm5,mm1 + + pand mm6,mmx_sign_mask + movq mm7,mm3 + + pand mm5,mmx_sign_mask + paddd mm6,mm6 + + pand mm7,mmx_sign_mask + paddd mm5,mm5 + + paddd mm0,mm4 + paddd mm2,mm6 + + paddd mm7,mm7 + movq mm4,mm2 + + punpcklwd mm4,mm0 + paddd mm1,mm5 + + punpckhwd mm2,mm0 + paddd mm3,mm7 + + movq mm5,mm3 + punpckhwd mm3,mm1 + + punpcklwd mm5,mm1 + movq mm0,mm2 + + movq mm1,mm4 + pmaddwd mm0,mm3 + + movq mm6,mm3 + psrlq mm3,32 + + movq mm7,mm5 + punpckldq mm3,mm6 + + pmaddwd mm1,mm5 + psrlq mm5,32 + + punpckldq mm5,mm7 + pmaddwd mm2,mm3 + + pmaddwd mm4,mm5 + movq mm3,mm0 + + punpckldq mm0,mm1 + + psubd mm0,mmx_one_fixed_h + punpckhdq mm1,mm3 + + psrad mm0,16 + paddd mm2,mm4 + + pslld mm1,16 + paddd mm2,mm0 + + paddd mm2,mm1 + + movq mm1,mm2 + psrlq mm2,32 + + paddd mm1,mm2 + + movd retval,mm1 + + emms + } + return retval+1; +} + +_asminline signed MMXInline_VectorDot16(struct vectorch const * v1, struct vectorch const * v2) +{ + signed retval; + _asm + { + mov eax,v1 + mov edx,v2 + + movd mm0,[edx+08h] + + packssdw mm0,[edx] + + movd mm1,[eax+08h] + + packssdw mm1,[eax] + + pmaddwd mm0,mm1 + + movq mm1,mm0 + psrlq mm0,32 + + paddd mm0,mm1 + + movd retval,mm0 + + emms + } + return retval; +} + +#else + +#error "Unknown compiler" + +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SUPPORT_MMX */ + +#endif /* ! _included_mmx_math_h_ */ diff --git a/3dc/win95/Mmx_math.asm b/3dc/win95/Mmx_math.asm new file mode 100644 index 0000000..ce5cb46 --- /dev/null +++ b/3dc/win95/Mmx_math.asm @@ -0,0 +1,1272 @@ +; want 8-byte alignment really!! +_DATA SEGMENT DWORD PUBLIC 'DATA' + + + PUBLIC _use_mmx_math + PUBLIC _mmx_sign_mask + PUBLIC _mmx_one_fixed_h + + align + _mmx_sign_mask:QWORD 0000800000008000h + _mmx_one_fixed_h:QWORD 0001000000000000h + _mmx_one_fixed_hl:QWORD 0001000000010000h + _mmx_one_hl:QWORD 0000000100000001h + store1:QWORD ? + _use_mmx_math:DWORD 1 + + + +_DATA ENDS + + + +; want 16-byte alignment really!! +_TEXT SEGMENT DWORD PUBLIC 'CODE' + ASSUME cs:_TEXT, ds:_DATA + +.586 + + PUBLIC MMXAsm_VectorDot_ + PUBLIC MMXAsm_VectorDot16_ + PUBLIC MMXAsm_VectorTransformed_ + PUBLIC MMXAsm_VectorTransform_ + PUBLIC MMXAsm_VectorTransformedAndAdd_ + PUBLIC MMXAsm_VectorTransformAndAdd_ + + PUBLIC _MMXAsm_VectorDot + PUBLIC _MMXAsm_VectorDot16 + PUBLIC _MMXAsm_VectorTransformed + PUBLIC _MMXAsm_VectorTransform + PUBLIC _MMXAsm_VectorTransformedAndAdd + PUBLIC _MMXAsm_VectorTransformAndAdd + + align +_MMXAsm_VectorDot: +MMXAsm_VectorDot_: + +if 0 + ; This is the unoptimized version + + ; get the data + movq mm0,[edx] + movq mm1,[eax] + movd mm2,[edx+08h] + movd mm3,[eax+08h] + + + ; get it into signed fixed format + movq mm4,mm0 + movq mm5,mm1 + movq mm6,mm2 + movq mm7,mm3 + + pand mm4,_mmx_sign_mask + pand mm5,_mmx_sign_mask + pand mm6,_mmx_sign_mask + pand mm7,_mmx_sign_mask + + paddd mm4,mm4 + paddd mm5,mm5 + paddd mm6,mm6 + paddd mm7,mm7 + + paddd mm0,mm4 + paddd mm1,mm5 + paddd mm2,mm6 + paddd mm3,mm7 + + ; at this point we have split all 32 bit values + ; into 16-bit pairs, high and low, both signed + + ; mm0: y1h y1l x1h x1l + ; mm1: y2h y2l x2h x2l + ; mm2: 0 0 z1h z1l + ; mm3: 0 0 z2h z2l + + ; swap 1st and 2nd words in mm0,mm1,mm2,mm3 ?? + movq mm4,mm2 + movq mm5,mm3 + punpcklwd mm4,mm0 + ; mm4: x1h z1h x1l z1l + punpcklwd mm5,mm1 + ; mm5: x2h z2h x2l z2l + punpckhwd mm2,mm0 + ; mm2: y1h 0 y1l 0 + punpckhwd mm3,mm1 + ; mm3: y2h 0 y2l 0 + + ; get the high and low products: x1h*x2h, x1l*x2l, etc + movq mm0,mm2 + pmaddwd mm0,mm3 + ; mm0: y1h*y2h y1l*y2l + movq mm1,mm4 + pmaddwd mm1,mm5 + ; mm1: x1h*x2h+z1h*z2h x1l*x2l+z1l*z2l + + ; exchange dwords in mm3 and mm5 + movq mm6,mm3 + movq mm7,mm5 + psrlq mm3,32 + psrlq mm5,32 + punpckldq mm3,mm6 + punpckldq mm5,mm7 + ; mm5: x2l z2l x2h z2h + ; mm3: y2l 0 y2h 0 + + ; compute the products x1h*x2l, x1l*x2h, etc + pmaddwd mm2,mm3 + ; mm2: y1h*y2l y1l*y2h + pmaddwd mm4,mm5 + ; mm4: x1h*x2l+z1h*z2l x1l*x2h+z1l*z2h + + paddd mm2,mm4 + ; mm2: x1h*x2l+y1h*y2l+z1h*z2l x1l*x2h+y1l*y2h+z1l*z2h + + ; get the low order dwords of mm0,mm1 + movq mm3,mm0 + punpckldq mm0,mm1 + ; mm0: x1l*x2l+z1l*z2l y1l*y2l + + ; unfortunately, at this point it is possible to have the + ; wrong value in mm0: if x1l,x2l,x1l,x2l + ; are all -0x8000, the result should + ; be +0x80000000, but of course this becomes + ; -0x80000000 + ; in fact the largest +ve value we could have is + ; +0x80000000 + ; and the lowest -ve value we could have is + ; -0x7fff0000 + ; = 0x80010000 + ; so subtracting ONE at this stage gives us a value + ; which is out by ONE, but twos-complement correct + psubd mm0,_mmx_one_fixed_h + + ; and the high order dwords + punpckhdq mm1,mm3 + ; mm1: x1h*x2h+z1h*z2h y1h*y2h + ; in fact it is swapped, but it doesn't matter + + ; shift the low order dwords down + psrad mm0,16 + ; and the high order dwords up + pslld mm1,16 + ; mm0: x1l*x2l+z1l*z2l>>16 -1 y1l*y2l>>16 + ; mm1: x1h*x2h+z1h*z2h<<16 y1h*y2h<<16 + ;(mm2) x1h*x2l+y1h*y2l+z1h*z2l x1l*x2h+y1l*y2h+z1l*z2h + + ; sum up + paddd mm2,mm0 + paddd mm2,mm1 + movq mm1,mm2 + psrlq mm2,32 + paddd mm1,mm2 + movd eax,mm1 + + emms + inc eax + ret + +else + ; + ; Now the optimized version + + movq mm0,[edx] + + movd mm2,[edx+08h] + movq mm4,mm0 + + + pand mm4,_mmx_sign_mask + movq mm6,mm2 + + movq mm1,[eax] + paddd mm4,mm4 + + movd mm3,[eax+08h] + movq mm5,mm1 + + pand mm6,_mmx_sign_mask + movq mm7,mm3 + + pand mm5,_mmx_sign_mask + paddd mm6,mm6 + + pand mm7,_mmx_sign_mask + paddd mm5,mm5 + + paddd mm0,mm4 + paddd mm2,mm6 + + paddd mm7,mm7 + movq mm4,mm2 + + punpcklwd mm4,mm0 + paddd mm1,mm5 + + punpckhwd mm2,mm0 + paddd mm3,mm7 + + movq mm5,mm3 + punpckhwd mm3,mm1 + + punpcklwd mm5,mm1 + movq mm0,mm2 + + movq mm1,mm4 + pmaddwd mm0,mm3 + + movq mm6,mm3 + psrlq mm3,32 + + movq mm7,mm5 + punpckldq mm3,mm6 + + pmaddwd mm1,mm5 + psrlq mm5,32 + + punpckldq mm5,mm7 + pmaddwd mm2,mm3 + + pmaddwd mm4,mm5 + movq mm3,mm0 + + ; these instructions won't pair and I have no instructions I can pair them with + punpckldq mm0,mm1 + + psubd mm0,_mmx_one_fixed_h + punpckhdq mm1,mm3 + + psrad mm0,16 + paddd mm2,mm4 + + pslld mm1,16 + paddd mm2,mm0 + + ; complete pairing is not possible at this stage - there are too many dependencies + paddd mm2,mm1 + + movq mm1,mm2 + psrlq mm2,32 + + paddd mm1,mm2 + + movd eax,mm1 + + emms + + inc eax + ret + +endif + + ; This takes 33 cycles, the orignal C -> nonMMX version takes 80 cycles + + align +_MMXAsm_VectorDot16: +MMXAsm_VectorDot16_: + + movd mm0,[edx+08h] + + packssdw mm0,[edx] + + movd mm1,[eax+08h] + + packssdw mm1,[eax] + + pmaddwd mm0,mm1 + + movq mm1,mm0 + psrlq mm0,32 + + paddd mm0,mm1 + + movd eax,mm0 + + emms + + ret + ; taking 14 cycles but assuming 16bit input vector fields + + + align +_MMXAsm_VectorTransformed: +MMXAsm_VectorTransformed_: + +if 0 + ; eax ptr to result + ; edx ptr to vector xh, xl, yh, yl, zh, zl + ; ecx ptr to matrix a11h, a11l, a12h, etc + + ; unoptimized version + + ; NOTE: in the Dot Product there was a problem + ; of an internal overflow where -32768*-32768 + -32768*-32768 gave 0x80000000 + ; which is -ve in two's complement + ; the additions and subtractions of ONE to resolve this problem + ; are marked '******' + + movq mm0,[edx] + movq mm1,mm0 + pand mm1,_mmx_sign_mask + paddd mm1,mm1 + paddd mm0,mm1 + ; mm0: yh yl xh xl + + movq mm2,[ecx] + movq mm3,mm2 + pand mm3,_mmx_sign_mask + paddd mm3,mm3 + paddd mm2,mm3 + ; mm2: a21h a21l a11h a11l + + movd mm4,[edx+08h] + movq mm5,mm4 + pand mm5,_mmx_sign_mask + paddd mm5,mm5 + paddd mm4,mm5 + ; mm4: 0 0 zh zl + + movq mm6,[ecx+18h] + movq mm7,mm6 + pand mm7,_mmx_sign_mask + paddd mm7,mm7 + paddd mm6,mm7 + ; mm6: a23h a23l a13h a13l + + ; interleave + + movq mm1,mm0 + punpckhwd mm0,mm4 + ; mm0: 0 yh 0 yl + punpcklwd mm1,mm4 + ; mm1: zh xh zl xl + + movq mm3,mm2 + punpckhwd mm2,mm6 + ; mm2: a23h a21h a23l a21l + punpcklwd mm3,mm6 + ; mm3: a13h a11h a13l a11l + + ; get a13*z, a11*x; a23*z a21*x, high and low products + movq mm4,mm1 + pmaddwd mm1,mm2 + movq mm6,mm4 + pmaddwd mm4,mm3 + ; mm0: 0 yh 0 yl + ; mm6: zh xh zl xl + ; mm2: a23h a21h a23l a21l + ; mm3: a13h a11h a13l a11l + ; mm1: zh*a23h+xh*a21h zl*a23l+xl*a21l + ; mm4: zh*a13h+xh*a11h zl*a13l+xl*a11l + + ; exchange dwords in mm6 + movq mm7,mm6 + psrlq mm6,32 + punpckldq mm6,mm7 + ; mm6: zl xl zh xh + ; mm7: zh xh zl xl + + ; get the high-low 'cross' products + pmaddwd mm2,mm6 + pmaddwd mm3,mm6 + ; mm2: a23h*zl+a21h*xl a23l*zh+a21l*xh + ; mm3: a13h*zl+a11h*xl a13l*zh+a11l*xh + + ; interleave mm1,mm4 and mm2,mm3 + movq mm5,mm4 + punpckldq mm4,mm1 + punpckhdq mm5,mm1 + ; mm4: zl*a23l+xl*a21l zl*a13l+xl*a11l ****** + ; mm5: zh*a23h+xh*a21h zh*a13h+xh*a11h + + ; ****** + psubd mm4,_mmx_one_fixed_hl + + + movq mm1,mm3 + punpckldq mm3,mm2 + punpckhdq mm1,mm2 + ; mm1: zl*a23h+xl*a21h zl*a13h+xl*a11h + ; mm3: zh*a23l+xh*a21l zh*a13l+xh*a11l + ; sum + paddd mm1,mm3 + ; shift the low order dwords down + psrad mm4,16 + ; and the high order dwords up + pslld mm5,16 + ; sum + paddd mm1,mm4 + paddd mm1,mm5 + ; mm1 holding x and y of the result + ; mm0: 0 yh 0 yl + ; mm1: z*a23+x*a21 z*a13+x*a11 + ; mm2: + ; mm3: + ; mm4: + ; mm5: + ; mm6: zl xl zh xh + ; mm7: zh xh zl xl + + ; grab some more of the matrix + movq mm2,[ecx+08h] + movq mm3,mm2 + pand mm3,_mmx_sign_mask + paddd mm3,mm3 + paddd mm2,mm3 ; mm7 not mm2 in optimized version + ; mm2: a12h a12l a31h a31l + + movd mm4,[ecx+20h] + movq mm5,mm4 + pand mm5,_mmx_sign_mask + paddd mm5,mm5 + paddd mm4,mm5 + ; mm4: 0 0 a33h a33l + + ; interleave + movq mm3,mm2 + punpcklwd mm2,mm4 + ; mm2: a33h a31h a33l a31l + psrlq mm3,32 + ; mm3: 0 0 a12h a12l + + ; compute mm2 * mm6/7 + movq mm4,mm2 + pmaddwd mm2,mm7 + pmaddwd mm4,mm6 + ; mm2: a33h*zh+a31h*xh a33l*zl+a31l*xl ****** + ; mm4: a33h*zl+a31h*xl a33l*zh+a31l*xh + movq mm7,mm2 + + ; ****** + psubd mm7,_mmx_one_fixed_hl + + pslld mm2,16 + psrad mm7,16 + paddd mm2,mm4 + paddd mm7,mm4 + psrlq mm2,32 + paddd mm2,mm7 + ; mm2: ? a33*z+a31*x + + + + ; get the rest of the matrix + movq mm5,[ecx+010h] + movq mm6,mm5 + pand mm6,_mmx_sign_mask + paddd mm6,mm6 + paddd mm5,mm6 + ; mm5: a32h a32l a22h a22l + ; mm3: 0 0 a12h a12l + + ; mm0: 0 yh 0 yl + movq mm7,mm0 + psrlq mm0,32 + punpcklwd mm0,mm7 + ; mm0: 0 0 yl yh + punpckldq mm0,mm0 + + ; mm0: yl yh yl yh + movq mm7,mm0 + pmaddwd mm0,mm3 + movq mm6,mm7 + pmaddwd mm7,mm5 + ; mm0: 0 yl*a12h+yh*a12l + ; mm7: yl*a32h+yh*a32l yl*a22h+yh*a22l + ; mm6: yl yh yl yh + punpckldq mm0,mm7 + ; mm0: yl*a22h+yh*a22l yl*a12h+yh*a12l + paddd mm1,mm0 + ; mm1: z*a23+x*a21+yl*a22h+yh*a22l z*a13+x*a11+yl*a12h+yh*a12l + psrlq mm7,32 + paddd mm2,mm7 + ; mm2: ? a33*z+a31*x+yl*a32h+yh*a32l + + + + ; mm5: a32h a32l a22h a22l + ; mm3: 0 0 a12h a12l + ; mm6: yl yh yl yh + + + + ; get all h and l separate + movq mm4,mm3 + punpcklwd mm3,mm5 + ; mm3: a22h a12h a22l a12l + punpckhwd mm5,mm4 + ; mm5: 0 a32h 0 a32l + movq mm4,mm3 + punpckhdq mm3,mm5 + ; mm3: 0 a32h a22h a12h + punpckldq mm4,mm5 + ; mm4: 0 a32l a22l a12l + punpckhwd mm6,mm6 + ; mm6: yl yl yh yh + movq mm0,mm6 + punpckhdq mm6,mm6 + ; mm6: yl yl yl yl + punpckldq mm0,mm0 + ; mm0: yh yh yh yh + pmullw mm3,mm0 + pmulhw mm4,mm6 + ; mm3: 0 a32h*yh a22h*yh a12h*yh + ; mm4: 0 a32l*yl>>16 a22l*yl>>16 a12l*yl>>16 + pxor mm7,mm7 + pcmpgtw mm7,mm4 + paddw mm3,mm7 + + movq mm5,mm4 + punpcklwd mm4,mm3 + punpckhwd mm5,mm3 + paddd mm1,mm4 + paddd mm2,mm5 + + ; ****** + paddd mm1,_mmx_one_hl + paddd mm2,_mmx_one_hl + + movq [eax],mm1 + movd [eax+08h],mm2 + + emms + ret + +else + ; + ; optimized version + + movq mm0,[edx] + + movd mm4,[edx+08h] + movq mm1,mm0 + + movq mm2,[ecx] + movq mm5,mm4 + + pand mm1,_mmx_sign_mask + movq mm3,mm2 + + pand mm5,_mmx_sign_mask + paddd mm1,mm1 + + movq mm6,[ecx+18h] + paddd mm5,mm5 + + pand mm3,_mmx_sign_mask + movq mm7,mm6 + + paddd mm0,mm1 + paddd mm3,mm3 + + pand mm7,_mmx_sign_mask + paddd mm2,mm3 + + movq mm1,mm0 + punpckhwd mm0,mm4 + + paddd mm4,mm5 + paddd mm7,mm7 + + paddd mm6,mm7 + punpcklwd mm1,mm4 + + movq mm3,mm2 + punpckhwd mm2,mm6 + + punpcklwd mm3,mm6 + movq mm4,mm1 + + movq mm6,mm1 + pmaddwd mm4,mm3 + + movq mm7,mm6 + psrlq mm6,32 + + pmaddwd mm1,mm2 + punpckldq mm6,mm7 + + movq store1,mm7 + pmaddwd mm3,mm6 + + movq mm7,[ecx+08h] + pmaddwd mm2,mm6 + + movq mm5,mm4 + punpckldq mm4,mm1 + + psubd mm4,_mmx_one_fixed_hl + punpckhdq mm5,mm1 + + movq mm1,mm7 + psrad mm4,16 + + pand mm1,_mmx_sign_mask + pslld mm5,16 + + paddd mm1,mm1 + paddd mm5,mm4 + + paddd mm7,mm1 + movq mm1,mm3 + + movd mm4,[ecx+20h] + punpckldq mm3,mm2 + + paddd mm3,mm5 + movq mm5,mm4 + + pand mm5,_mmx_sign_mask + punpckhdq mm1,mm2 + + paddd mm1,mm3 + paddd mm5,mm5 + + movq mm2,[ecx+010h] + movq mm3,mm7 + + paddd mm4,mm5 + movq mm5,mm2 + + pand mm2,_mmx_sign_mask + punpcklwd mm7,mm4 + + movq mm4,mm7 + psrlq mm3,32 + + pmaddwd mm7,store1 + paddd mm2,mm2 + + pmaddwd mm4,mm6 + movq mm6,mm0 + + psrlq mm0,32 + paddd mm5,mm2 + + punpcklwd mm0,mm6 + movq mm2,mm7 + + psubd mm7,_mmx_one_fixed_hl + pslld mm2,16 + + psrad mm7,16 + paddd mm2,mm4 + + paddd mm7,mm4 + punpckldq mm0,mm0 + + movq mm6,mm0 + psrlq mm2,32 + + paddd mm2,mm7 + movq mm7,mm6 + + pmaddwd mm0,mm3 + punpckhwd mm7,mm7 + + pmaddwd mm6,mm5 + movq mm4,mm3 + + punpcklwd mm3,mm5 + + punpckhwd mm5,mm4 + movq mm4,mm7 + + punpckldq mm0,mm6 + + paddd mm1,mm0 + punpckhdq mm7,mm7 + + movq mm0,mm3 + punpckldq mm3,mm5 + + pmulhw mm3,mm7 + punpckhdq mm0,mm5 + + punpckldq mm4,mm4 + + pmullw mm0,mm4 + psrlq mm6,32 + + paddd mm2,mm6 + pxor mm6,mm6 + + pcmpgtw mm6,mm3 + movq mm5,mm3 + + paddd mm1,_mmx_one_hl + paddw mm0,mm6 + + paddd mm2,_mmx_one_hl + punpcklwd mm3,mm0 + + paddd mm1,mm3 + punpckhwd mm5,mm0 + + paddd mm2,mm5 + + movq [eax],mm1 + + movd [eax+08h],mm2 + + emms + ret + ; 63 cycles compared with 204 for the C-nonMMX version +endif + + align +_MMXAsm_VectorTransform: +MMXAsm_VectorTransform_: + + movq mm0,[eax] + + movd mm4,[eax+08h] + movq mm1,mm0 + + movq mm2,[edx] + movq mm5,mm4 + + pand mm1,_mmx_sign_mask + movq mm3,mm2 + + pand mm5,_mmx_sign_mask + paddd mm1,mm1 + + movq mm6,[edx+18h] + paddd mm5,mm5 + + pand mm3,_mmx_sign_mask + movq mm7,mm6 + + paddd mm0,mm1 + paddd mm3,mm3 + + pand mm7,_mmx_sign_mask + paddd mm2,mm3 + + movq mm1,mm0 + punpckhwd mm0,mm4 + + paddd mm4,mm5 + paddd mm7,mm7 + + paddd mm6,mm7 + punpcklwd mm1,mm4 + + movq mm3,mm2 + punpckhwd mm2,mm6 + + punpcklwd mm3,mm6 + movq mm4,mm1 + + movq mm6,mm1 + pmaddwd mm4,mm3 + + movq mm7,mm6 + psrlq mm6,32 + + pmaddwd mm1,mm2 + punpckldq mm6,mm7 + + movq store1,mm7 + pmaddwd mm3,mm6 + + movq mm7,[edx+08h] + pmaddwd mm2,mm6 + + movq mm5,mm4 + punpckldq mm4,mm1 + + psubd mm4,_mmx_one_fixed_hl + punpckhdq mm5,mm1 + + movq mm1,mm7 + psrad mm4,16 + + pand mm1,_mmx_sign_mask + pslld mm5,16 + + paddd mm1,mm1 + paddd mm5,mm4 + + paddd mm7,mm1 + movq mm1,mm3 + + movd mm4,[edx+20h] + punpckldq mm3,mm2 + + paddd mm3,mm5 + movq mm5,mm4 + + pand mm5,_mmx_sign_mask + punpckhdq mm1,mm2 + + paddd mm1,mm3 + paddd mm5,mm5 + + movq mm2,[edx+010h] + movq mm3,mm7 + + paddd mm4,mm5 + movq mm5,mm2 + + pand mm2,_mmx_sign_mask + punpcklwd mm7,mm4 + + movq mm4,mm7 + psrlq mm3,32 + + pmaddwd mm7,store1 + paddd mm2,mm2 + + pmaddwd mm4,mm6 + movq mm6,mm0 + + psrlq mm0,32 + paddd mm5,mm2 + + punpcklwd mm0,mm6 + movq mm2,mm7 + + psubd mm7,_mmx_one_fixed_hl + pslld mm2,16 + + psrad mm7,16 + paddd mm2,mm4 + + paddd mm7,mm4 + punpckldq mm0,mm0 + + movq mm6,mm0 + psrlq mm2,32 + + paddd mm2,mm7 + movq mm7,mm6 + + pmaddwd mm0,mm3 + punpckhwd mm7,mm7 + + pmaddwd mm6,mm5 + movq mm4,mm3 + + punpcklwd mm3,mm5 + + punpckhwd mm5,mm4 + movq mm4,mm7 + + punpckldq mm0,mm6 + + paddd mm1,mm0 + punpckhdq mm7,mm7 + + movq mm0,mm3 + punpckldq mm3,mm5 + + pmulhw mm3,mm7 + punpckhdq mm0,mm5 + + punpckldq mm4,mm4 + + pmullw mm0,mm4 + psrlq mm6,32 + + paddd mm2,mm6 + pxor mm6,mm6 + + pcmpgtw mm6,mm3 + movq mm5,mm3 + + paddd mm1,_mmx_one_hl + paddw mm0,mm6 + + paddd mm2,_mmx_one_hl + punpcklwd mm3,mm0 + + paddd mm1,mm3 + punpckhwd mm5,mm0 + + paddd mm2,mm5 + + movq [eax],mm1 + + movd [eax+08h],mm2 + + emms + ret + ; 63 cycles compared with 204 for the C-nonMMX version + + + align +_MMXAsm_VectorTransformedAndAdd: +MMXAsm_VectorTransformedAndAdd_: + + movq mm0,[edx] + + movd mm4,[edx+08h] + movq mm1,mm0 + + movq mm2,[ecx] + movq mm5,mm4 + + pand mm1,_mmx_sign_mask + movq mm3,mm2 + + pand mm5,_mmx_sign_mask + paddd mm1,mm1 + + movq mm6,[ecx+18h] + paddd mm5,mm5 + + pand mm3,_mmx_sign_mask + movq mm7,mm6 + + paddd mm0,mm1 + paddd mm3,mm3 + + pand mm7,_mmx_sign_mask + paddd mm2,mm3 + + movq mm1,mm0 + punpckhwd mm0,mm4 + + paddd mm4,mm5 + paddd mm7,mm7 + + paddd mm6,mm7 + punpcklwd mm1,mm4 + + movq mm3,mm2 + punpckhwd mm2,mm6 + + punpcklwd mm3,mm6 + movq mm4,mm1 + + movq mm6,mm1 + pmaddwd mm4,mm3 + + movq mm7,mm6 + psrlq mm6,32 + + pmaddwd mm1,mm2 + punpckldq mm6,mm7 + + movq store1,mm7 + pmaddwd mm3,mm6 + + movq mm7,[ecx+08h] + pmaddwd mm2,mm6 + + movq mm5,mm4 + punpckldq mm4,mm1 + + psubd mm4,_mmx_one_fixed_hl + punpckhdq mm5,mm1 + + movq mm1,mm7 + psrad mm4,16 + + pand mm1,_mmx_sign_mask + pslld mm5,16 + + paddd mm1,mm1 + paddd mm5,mm4 + + paddd mm7,mm1 + movq mm1,mm3 + + movd mm4,[ecx+20h] + punpckldq mm3,mm2 + + paddd mm3,mm5 + movq mm5,mm4 + + pand mm5,_mmx_sign_mask + punpckhdq mm1,mm2 + + paddd mm1,mm3 + paddd mm5,mm5 + + movq mm2,[ecx+010h] + movq mm3,mm7 + + paddd mm4,mm5 + movq mm5,mm2 + + pand mm2,_mmx_sign_mask + punpcklwd mm7,mm4 + + movq mm4,mm7 + psrlq mm3,32 + + pmaddwd mm7,store1 + paddd mm2,mm2 + + pmaddwd mm4,mm6 + movq mm6,mm0 + + psrlq mm0,32 + paddd mm5,mm2 + + punpcklwd mm0,mm6 + movq mm2,mm7 + + psubd mm7,_mmx_one_fixed_hl + pslld mm2,16 + + psrad mm7,16 + paddd mm2,mm4 + + paddd mm7,mm4 + punpckldq mm0,mm0 + + movq mm6,mm0 + psrlq mm2,32 + + paddd mm2,mm7 + movq mm7,mm6 + + pmaddwd mm0,mm3 + punpckhwd mm7,mm7 + + pmaddwd mm6,mm5 + movq mm4,mm3 + + paddd mm1,_mmx_one_hl + punpcklwd mm3,mm5 + + punpckhwd mm5,mm4 + movq mm4,mm7 + + paddd mm2,_mmx_one_hl + punpckldq mm0,mm6 + + paddd mm1,mm0 + punpckhdq mm7,mm7 + + movq mm0,mm3 + punpckldq mm3,mm5 + + pmulhw mm3,mm7 + punpckhdq mm0,mm5 + + paddd mm1,[ebx] + punpckldq mm4,mm4 + + pmullw mm0,mm4 + psrlq mm6,32 + + paddd mm2,mm6 + pxor mm6,mm6 + + pcmpgtw mm6,mm3 + movq mm5,mm3 + + movd mm4,[ebx+08h] + paddw mm0,mm6 + + paddd mm2,mm4 + punpcklwd mm3,mm0 + + paddd mm1,mm3 + punpckhwd mm5,mm0 + + paddd mm2,mm5 + + movq [eax],mm1 + + movd [eax+08h],mm2 + + emms + ret + ; 63 cycles compared with 204 for the C-nonMMX version + + + align +_MMXAsm_VectorTransformAndAdd: +MMXAsm_VectorTransformAndAdd_: + + movq mm0,[eax] + + movd mm4,[eax+08h] + movq mm1,mm0 + + movq mm2,[edx] + movq mm5,mm4 + + pand mm1,_mmx_sign_mask + movq mm3,mm2 + + pand mm5,_mmx_sign_mask + paddd mm1,mm1 + + movq mm6,[edx+18h] + paddd mm5,mm5 + + pand mm3,_mmx_sign_mask + movq mm7,mm6 + + paddd mm0,mm1 + paddd mm3,mm3 + + pand mm7,_mmx_sign_mask + paddd mm2,mm3 + + movq mm1,mm0 + punpckhwd mm0,mm4 + + paddd mm4,mm5 + paddd mm7,mm7 + + paddd mm6,mm7 + punpcklwd mm1,mm4 + + movq mm3,mm2 + punpckhwd mm2,mm6 + + punpcklwd mm3,mm6 + movq mm4,mm1 + + movq mm6,mm1 + pmaddwd mm4,mm3 + + movq mm7,mm6 + psrlq mm6,32 + + pmaddwd mm1,mm2 + punpckldq mm6,mm7 + + movq store1,mm7 + pmaddwd mm3,mm6 + + movq mm7,[edx+08h] + pmaddwd mm2,mm6 + + movq mm5,mm4 + punpckldq mm4,mm1 + + psubd mm4,_mmx_one_fixed_hl + punpckhdq mm5,mm1 + + movq mm1,mm7 + psrad mm4,16 + + pand mm1,_mmx_sign_mask + pslld mm5,16 + + paddd mm1,mm1 + paddd mm5,mm4 + + paddd mm7,mm1 + movq mm1,mm3 + + movd mm4,[edx+20h] + punpckldq mm3,mm2 + + paddd mm3,mm5 + movq mm5,mm4 + + pand mm5,_mmx_sign_mask + punpckhdq mm1,mm2 + + paddd mm1,mm3 + paddd mm5,mm5 + + movq mm2,[edx+010h] + movq mm3,mm7 + + paddd mm4,mm5 + movq mm5,mm2 + + pand mm2,_mmx_sign_mask + punpcklwd mm7,mm4 + + movq mm4,mm7 + psrlq mm3,32 + + pmaddwd mm7,store1 + paddd mm2,mm2 + + pmaddwd mm4,mm6 + movq mm6,mm0 + + psrlq mm0,32 + paddd mm5,mm2 + + punpcklwd mm0,mm6 + movq mm2,mm7 + + psubd mm7,_mmx_one_fixed_hl + pslld mm2,16 + + psrad mm7,16 + paddd mm2,mm4 + + paddd mm7,mm4 + punpckldq mm0,mm0 + + movq mm6,mm0 + psrlq mm2,32 + + paddd mm2,mm7 + movq mm7,mm6 + + pmaddwd mm0,mm3 + punpckhwd mm7,mm7 + + pmaddwd mm6,mm5 + movq mm4,mm3 + + paddd mm1,_mmx_one_hl + punpcklwd mm3,mm5 + + punpckhwd mm5,mm4 + movq mm4,mm7 + + paddd mm2,_mmx_one_hl + punpckldq mm0,mm6 + + paddd mm1,mm0 + punpckhdq mm7,mm7 + + movq mm0,mm3 + punpckldq mm3,mm5 + + pmulhw mm3,mm7 + punpckhdq mm0,mm5 + + paddd mm1,[ecx] + punpckldq mm4,mm4 + + pmullw mm0,mm4 + psrlq mm6,32 + + paddd mm2,mm6 + pxor mm6,mm6 + + pcmpgtw mm6,mm3 + movq mm5,mm3 + + movd mm4,[ecx+08h] + paddw mm0,mm6 + + paddd mm2,mm4 + punpcklwd mm3,mm0 + + paddd mm1,mm3 + punpckhwd mm5,mm0 + + paddd mm2,mm5 + + movq [eax],mm1 + + movd [eax+08h],mm2 + + emms + ret + ; 63 cycles compared with 204 for the C-nonMMX version + + +_TEXT ENDS + +END + diff --git a/3dc/win95/OBCHUNK.CPP b/3dc/win95/OBCHUNK.CPP new file mode 100644 index 0000000..86e8857 --- /dev/null +++ b/3dc/win95/OBCHUNK.CPP @@ -0,0 +1,1434 @@ +#include "chunk.hpp" +#include "chnktype.hpp" +#include "mishchnk.hpp" +#include "obchunk.hpp" +#include "shpchunk.hpp" +#include "envchunk.hpp" +#include "md5.h" +// Class Object_Chunk functions + +#ifdef cencon +#define new my_new +#endif +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(obchunk) + +RIF_IMPLEMENT_DYNCREATE("RBOBJECT",Object_Chunk) + +/* +Children for Object_Chunk : + +"OBJHEAD1" Object_Header_Chunk +"OBINTDT" Object_Interface_Data_Chunk +"OBJPRJDT" Object_Project_Data_Chunk +"MODULEDT" Object_Module_Data_Chunk +"SHPVTINT" Shape_Vertex_Intensities_Chunk +"OBJTRAK2" Object_Track_Chunk2 +"TRAKSOUN" Object_Track_Sound_Chunk +"OBANSEQS" Object_Animation_Sequences_Chunk +"PLOBJLIT" Placed_Object_Light_Chunk +"ALTLOCAT" Object_Alternate_Locations_Chunk +*/ + + + + + +// from buffer +Object_Chunk::Object_Chunk(Chunk_With_Children * parent, const char *data, size_t size) +: Lockable_Chunk_With_Children (parent, "RBOBJECT"), + object_data () +{ + const char * buffer_ptr = data; + + object_data_store = (ChunkObject *) &object_data; + + while ((data-buffer_ptr)< (signed) size) { + + if ((*(int *)(data + 8)) + (data-buffer_ptr) > (signed) size) { + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + + DynCreate(data); + data += *(int *)(data + 8); + + } + + program_object_index=-1; + +} + +// from data +Object_Chunk::Object_Chunk (Chunk_With_Children * parent, ChunkObject &obj) +: Lockable_Chunk_With_Children (parent, "RBOBJECT"), + object_data (obj) +{ + object_data_store = (ChunkObject *) &object_data; + object_data_store->index_num=-1; + + new Object_Header_Chunk(this); + new Object_Interface_Data_Chunk(this); + + //if the parent is a file_chunk get an object index + if(!strcmp(parent->identifier,"REBINFF2")) + { + ((File_Chunk*)parent)->assign_index_to_object(this); + } + program_object_index=-1; + + CalculateID(); +} + +Object_Chunk::~Object_Chunk() +{ +} + +Object_Header_Chunk * Object_Chunk::get_header() +{ + + return (Object_Header_Chunk *) this->lookup_single_child ("OBJHEAD1"); + + +} + +Shape_Chunk * Object_Chunk::get_assoc_shape() +{ + if (!get_header()) return 0; + + return get_header()->associated_shape; + +} + +BOOL Object_Chunk::assoc_with_shape (Shape_Chunk * shpch) +{ + Object_Header_Chunk * obhead = get_header(); + + if (!obhead) return 0; + + // check that we are not already associated with this shape + + if (obhead->associated_shape == shpch) return 1; + + Shape_Header_Chunk * shphead = shpch->get_header(); + + if (!shphead) return 0; + + // deassociate with the old shape + + if (obhead->associated_shape) + deassoc_with_shape (obhead->associated_shape); + + // associate with the new + + obhead->associated_shape = shpch; + + if (!shphead->associated_objects_store.contains(this)) + shphead->associated_objects_store.add_entry(this); + + return 1; + +} + +BOOL Object_Chunk::deassoc_with_shape (Shape_Chunk * shpch) +{ + Shape_Header_Chunk * shphead = shpch->get_header(); + + if (!shphead) return 0; + + if (shphead->associated_objects_store.contains(this)) + shphead->associated_objects_store.delete_entry(this); + + Object_Header_Chunk * obhead = get_header(); + + obhead->associated_shape = 0; + + return 1; + +} + +BOOL Object_Chunk::file_equals(HANDLE &rif_file) +{ + unsigned long bytes_read; + char name[50]; + + // get header list + List obhead; + list_chunks_in_file (&obhead, rif_file, "OBJHEAD1"); + + if (obhead.size() != 1) return FALSE; + + // get object identifier + SetFilePointer(rif_file,obhead.first_entry() + 96,0,FILE_BEGIN); + int i = 0; + do ReadFile (rif_file, (long *) (name + i), 1, &bytes_read, 0); + while (name[i++] != 0); + + if (!strcmp(name, object_data.o_name) ) return (TRUE); + + return (FALSE); +} + +const char * Object_Chunk::get_head_id() +{ + Object_Header_Chunk * hdptr = get_header(); + + if (!hdptr) return (0); + + return(hdptr->identifier); +} + +void Object_Chunk::set_lock_user (char * user) +{ + Object_Header_Chunk * hdptr = get_header(); + + if (!hdptr) return; + + strncpy (hdptr->lock_user, user,16); + + hdptr->lock_user[16] = 0; +} + + +BOOL Object_Chunk::inc_v_no () +{ + Object_Header_Chunk * hdptr = get_header(); + + if (!hdptr) return (FALSE); + + hdptr->version_no++; + + return (TRUE); +} + +BOOL Object_Chunk::same_and_updated(Object_Chunk & obj) +{ + + Object_Header_Chunk * hd1ptr = get_header(); + + if (!hd1ptr) return (0); + + Object_Header_Chunk * hd2ptr = obj.get_header(); + + if (!hd2ptr) return (0); + + return (hd1ptr->version_no < hd2ptr->version_no && + (!strcmp(obj.object_data.o_name, object_data.o_name)) ); + +} + +BOOL Object_Chunk::assoc_with_shape_no(File_Chunk *fc) +{ + Object_Header_Chunk * hdptr = get_header(); + Shape_Chunk * shp = NULL; + Shape_Header_Chunk * shphd; + + if (!hdptr) return (FALSE); + + List chlst; + fc->lookup_child("REBSHAPE",chlst); + + for (LIF l(&chlst); !l.done(); l.next()) + { + shp = (Shape_Chunk *)l(); + shphd = shp->get_header(); + if (shphd) + { + if (hdptr->shape_id_no == shphd->file_id_num) + break; + } + } + if (!l.done()) + { + assoc_with_shape(shp); + } + else + { + return(FALSE); + } + + return(TRUE); + + +} + + + + +void Object_Chunk::post_input_processing() +{ + CalculateID(); + + if (get_header()) + if (get_header()->flags & GENERAL_FLAG_LOCKED) + external_lock = TRUE; + + Chunk_With_Children::post_input_processing(); + +} + + +VModule_Array_Chunk * Object_Chunk::get_vmod_chunk() +{ + Object_Module_Data_Chunk * omdc = 0; + + omdc = (Object_Module_Data_Chunk *) lookup_single_child ("MODULEDT"); + + + if (omdc) + { + VModule_Array_Chunk * vmac = 0; + vmac = (VModule_Array_Chunk *)omdc->lookup_single_child ("VMDARRAY") ; + + if (vmac) return(vmac); + } + + return(0); + + +} + +void Object_Chunk::destroy(File_Chunk * fc) +{ + List cl; + fc->lookup_child("RBOBJECT",cl); + + for (LIF cli(&cl); !cli.done(); cli.next()) + { + Object_Chunk * ob = (Object_Chunk *)cli(); + if (ob == this) continue; + + VModule_Array_Chunk * vmac = ob->get_vmod_chunk(); + + BOOL in_object_va = FALSE; + + if (vmac) + { + int pos=0; + for(int i=0;inum_array_items;i++) + { + + if (vmac->vmod_array[i].object_index==object_data.index_num) + { + in_object_va=TRUE; + //update branch indeces for branches that go beyond this point + for(int j=0;jnum_array_items;j++) + { + if(vmac->vmod_array[j].branch_no> pos) + vmac->vmod_array[j].branch_no--; + } + } + else + { + if(pos!=i) + { + vmac->vmod_array[pos]=vmac->vmod_array[i]; + } + pos++; + } + } + + if(in_object_va) + { + if(pos==0) + { + delete vmac; + } + else + { + //excess entries should be properly deleted when the array is deleted + vmac->num_array_items=pos; + } + + } + + } + + //now remove this object from any adjacency data + + Object_Module_Data_Chunk* omdc=(Object_Module_Data_Chunk*)ob->lookup_single_child("MODULEDT"); + if(omdc) + { + Adjacent_Module_Entry_Points_Chunk* amepc=(Adjacent_Module_Entry_Points_Chunk*)omdc->lookup_single_child("ADJMDLEP"); + + if(amepc) + { + for(LIF ad_lif(&amepc->adjacent_modules_list);!ad_lif.done();) + { + if(ad_lif().object_index==object_data.index_num) + ad_lif.delete_current(); + else + ad_lif.next(); + + } + } + } + + + } + + Shape_Chunk * shp = get_assoc_shape(); + + deassoc_with_shape (shp); + + lock_chunk(*fc); + + deleted = TRUE; + + unlock_chunk(*fc,TRUE); + +} + + +void Object_Chunk::update_my_chunkobject(ChunkObject & cob) +{ + //store the object's index , so that it doesn't get lost + int object_index=object_data_store->index_num; + *object_data_store = cob; + //replace the object index + object_data_store->index_num=object_index; + //recalculate the object's id in case the name has changed + CalculateID(); +} + +ObjectID Object_Chunk::CalculateID() +{ + ObjectID retval={0,0}; + List chlist; + parent->lookup_child("REBENVDT",chlist); + if(!chlist.size()) return retval; + ((Environment_Data_Chunk*)chlist.first_entry())->lookup_child("RIFFNAME",chlist); + if(!chlist.size()) return retval; + char Name[100]; + + #if InterfaceEngine||cencon + //need to check for console specific rif files,and skip the 'sat' or 'psx' + //so that they get the same ids as the pc + const char* r_name=((RIF_Name_Chunk*)chlist.first_entry())->rif_name; + if(tolower(r_name[0])=='p' && tolower(r_name[1])=='s' && tolower(r_name[2])=='x' ) + strcpy(Name,&r_name[3]); + else if (tolower(r_name[0])=='s' && tolower(r_name[1])=='a' && tolower(r_name[2])=='t' ) + strcpy(Name,&r_name[3]); + else + strcpy(Name,r_name); + #else + strcpy(Name,((RIF_Name_Chunk*)chlist.first_entry())->rif_name); + #endif + + strcat(Name,object_data.o_name); + char buffer[16]; + md5_buffer(Name,strlen(Name),&buffer[0]); + buffer[7]=0; + object_data_store->ID=*(ObjectID*)&buffer[0]; + return object_data_store->ID; + +} + +///////////////////////////////////////// + +// Class Object_Header_Chunk functions +RIF_IMPLEMENT_DYNCREATE("OBJHEAD1",Object_Header_Chunk) + +// from buffer +#if UseOldChunkLoader +Object_Header_Chunk::Object_Header_Chunk(Object_Chunk * parent, const char * hdata, size_t /*hsize*/) +: Chunk (parent, "OBJHEAD1"), object_data (parent->object_data_store), +flags(0), version_no (0), associated_shape (0) +{ + flags = *((int *) hdata); + + if (flags & OBJECT_FLAG_BASE_OBJECT) + parent->object_data_store->is_base_object = TRUE; + else + { + parent->object_data_store->is_base_object = FALSE; + } + + strncpy (lock_user, (hdata + 4), 16); + lock_user[16] = '\0'; + + parent->object_data_store->float_location = *((ChunkVector *) (hdata + 20)); + parent->object_data_store->location = parent->object_data_store->float_location; + + parent->object_data_store->orientation.x =- *((double *) (hdata + 44)); + parent->object_data_store->orientation.y =- *((double *) (hdata + 52)); + parent->object_data_store->orientation.z =- *((double *) (hdata + 60)); + parent->object_data_store->orientation.w = *((double *) (hdata + 68)); + + version_no = *((int *) (hdata + 76)); + + shape_id_no = *((int *) (hdata + 80)); + + strcpy (parent->object_data_store->o_name, (hdata + 84)); + parent->object_data_store->ID.id1=0; + parent->object_data_store->ID.id2=0; + parent->object_data_store->index_num=-1; +} +#else +Object_Header_Chunk::Object_Header_Chunk(Chunk_With_Children * parent, const char * hdata, size_t /*hsize*/) +: Chunk (parent, "OBJHEAD1"), object_data (((Object_Chunk*)parent)->object_data_store), +flags(0), version_no (0), associated_shape (0) +{ + Object_Chunk* parent_object = (Object_Chunk*) parent; + + flags = *((int *) hdata); + + if (flags & OBJECT_FLAG_BASE_OBJECT) + parent_object->object_data_store->is_base_object = TRUE; + else + { + parent_object->object_data_store->is_base_object = FALSE; + } + + strncpy (lock_user, (hdata + 4), 16); + lock_user[16] = '\0'; + + hdata+=20; + + parent_object->object_data_store->location = *(ChunkVectorInt*) hdata; + hdata+=sizeof(ChunkVectorInt); + + parent_object->object_data_store->orientation = *((ChunkQuat *) hdata); + hdata+=sizeof(ChunkQuat); + + parent_object->object_data_store->index_num = *(int *) hdata; + hdata+=4; + + version_no = *((int *) hdata); + hdata+=4; + + shape_id_no = *((int *) hdata); + hdata+=4; + + strcpy (parent_object->object_data_store->o_name, hdata); + parent_object->object_data_store->ID.id1=0; + parent_object->object_data_store->ID.id2=0; +} +#endif + +//from data + +Object_Header_Chunk::Object_Header_Chunk (Object_Chunk * parent) +: Chunk (parent, "OBJHEAD1"), +object_data (parent->object_data_store), +flags (0), version_no (0), associated_shape(0) +{ + if (object_data->is_base_object) { + flags = OBJECT_FLAG_BASE_OBJECT; + } +} + + +size_t Object_Header_Chunk::size_chunk() +{ + int length = 72; + + length += (strlen(object_data->o_name)+1); + + length += (4-length%4)%4; + + chunk_size = length; + + return length; +} + +BOOL Object_Header_Chunk::output_chunk (HANDLE & hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = make_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; +} + +void Object_Header_Chunk::fill_data_block ( char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = flags; + strncpy ((data_start + 4), lock_user, 16); + data_start+=20; + + *((ChunkVectorInt *) (data_start)) = object_data->location; + data_start+=sizeof(ChunkVectorInt); + + *((ChunkQuat *) (data_start)) = object_data->orientation; + data_start+=sizeof(ChunkQuat); + + *(int*) data_start=object_data->index_num; + data_start+=4; + + *((int *) data_start) = version_no; + data_start+=4; + + *((int *) data_start) = shape_id_no; + data_start+=4; + + strcpy (data_start, object_data->o_name); +} + +void Object_Header_Chunk::prepare_for_output() +{ + version_no ++; +} + +///////////////////////////////////////// + +// Class Object_Interface_Data_Chunk functions +RIF_IMPLEMENT_DYNCREATE("OBINTDT",Object_Interface_Data_Chunk) + +/* +Children for Object_Interface_Data_Chunk : + +"OBJNOTES" Object_Notes_Chunk +*/ + +// from buffer +Object_Interface_Data_Chunk::Object_Interface_Data_Chunk(Chunk_With_Children * parent, const char *data, size_t size) +: Chunk_With_Children (parent, "OBINTDT") +{ + const char * buffer_ptr = data; + + while ((data-buffer_ptr)< (signed) size) { + + if ((*(int *)(data + 8)) + (data-buffer_ptr) > (signed) size) { + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + + DynCreate(data); + data += *(int *)(data + 8); + } +} + +Object_Interface_Data_Chunk::Object_Interface_Data_Chunk (Object_Chunk * parent) +: Chunk_With_Children (parent, "OBINTDT") +{ + new Object_Notes_Chunk (this, "Enter notes here", strlen("Enter notes here") + 1); +} + + +/////////////////////////////////////// + +// Class Object_Notes_Chunk functions +RIF_IMPLEMENT_DYNCREATE("OBJNOTES",Object_Notes_Chunk) + +Object_Notes_Chunk::Object_Notes_Chunk (Chunk_With_Children * parent, + const char * _data, size_t _data_size) +: Chunk(parent, "OBJNOTES"), +data(NULL), data_size(_data_size) +{ + data_store = new char [data_size]; + + *((char **) &data) = data_store; + + for (int i = 0; i<(signed) data_size; i++) + data_store[i] = _data[i]; + +} + +void Object_Notes_Chunk::fill_data_block (char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + for (int i = 0; i<((signed) chunk_size-12); i++) + data_start[i] = data[i]; +} + +Object_Notes_Chunk::~Object_Notes_Chunk () +{ + delete [] data_store; +} + +BOOL Object_Notes_Chunk::output_chunk (HANDLE &hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = make_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; +} + + +/////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("MODULEDT",Object_Module_Data_Chunk) + +/* +Children For Object_Module_Data_Chunk : + +"VMDARRAY" VModule_Array_Chunk +"ADJMDLEP" Adjacent_Module_Entry_Points_Chunk +"MODFLAGS" Module_Flag_Chunk +"WAYPOINT" Module_Waypoint_Chunk +"MODACOUS" Module_Acoustics_Chunk +"AIMODMAS" AI_Module_Master_Chunk +"AIMODSLA" AI_Module_Slave_Chunk + +*/ + +Object_Module_Data_Chunk::Object_Module_Data_Chunk (Chunk_With_Children * parent,const char * mdata, size_t msize) +: Chunk_With_Children (parent, "MODULEDT") +{ + const char * buffer_ptr = mdata; + + while ((mdata-buffer_ptr)< (signed) msize) { + + if ((*(int *)(mdata + 8)) + (mdata-buffer_ptr) > (signed) msize) { + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + DynCreate(mdata); + mdata += *(int *)(mdata + 8); + + } + +} + +/////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("VMDARRAY",VModule_Array_Chunk) + +VModule_Array_Chunk::VModule_Array_Chunk(Object_Module_Data_Chunk * parent, VMod_Arr_Item * vma, int num_in_vma) +: Chunk (parent, "VMDARRAY") +{ + int i; + + num_array_items = num_in_vma; + + vmod_array = new VMod_Arr_Item [num_in_vma]; + + for (i=0; i ami(&adjacent_modules_list); !ami.done(); ami.next()) + { + + *((int *) data_start) = 0; + data_start += 4; + + *((int *) data_start) = 0; + data_start += 4; + + strcpy (data_start, ami().o_name); + data_start += (strlen(ami().o_name) + 1) + (4-(strlen(ami().o_name) + 1)%4)%4; + + } + +} + +size_t Adjacent_Modules_Chunk::size_chunk() +{ + int size = 16; + + for (LIF ami(&adjacent_modules_list); !ami.done(); ami.next()) + { + size += 8; + size += (strlen(ami().o_name) + 1) + (4-(strlen(ami().o_name) + 1)%4)%4; + } + + chunk_size = size; + return(size); + +} + +Adjacent_Modules_Chunk::Adjacent_Modules_Chunk (Object_Module_Data_Chunk * parent, const char * data, size_t /*size*/) +: Chunk (parent, "ADJMDLST") +{ + int num_array_items = *((int *) data); + + data += 4; + + for (int i=0; i ami(&adjacent_modules_list); !ami.done(); ami.next()) + { + + *((int *) data_start) = ami().object_index; + data_start += 4; + + *((int *) data_start) = ami().flags; + data_start += 4; + + *((ChunkVectorInt *) data_start) = ami().entry_point; + data_start += sizeof(ChunkVectorInt); + + + } + +} + + +size_t Adjacent_Module_Entry_Points_Chunk::size_chunk() +{ + chunk_size = 16+adjacent_modules_list.size()*20; + return(chunk_size); +} + +#if UseOldChunkLoader +Adjacent_Module_Entry_Points_Chunk::Adjacent_Module_Entry_Points_Chunk (Object_Module_Data_Chunk * parent, const char * data, size_t /*size*/) +: Chunk (parent, "ADJMDLEP") +{ + int num_array_items = *((int *) data); + + data += 4; + + for (int i=0; i aml) + : Chunk (parent, "ADJMDLST"), adjacent_modules_list (aml) + {} + + List adjacent_modules_list; + + virtual void fill_data_block (char *); + virtual size_t size_chunk (); + + +private: + + friend class Object_Module_Data_Chunk; + + Adjacent_Modules_Chunk(Object_Module_Data_Chunk * parent, const char * data, size_t size); + +}; +#endif + +//a replacement for adjacent_modules_chunk +#define AdjacentModuleFlag_EntryPointSetByHand 0x00000001 +#define AdjacentModuleFlag_InsideAdjacentModule 0x00000002 +#define AdjacentModuleFlag_AdjacentModuleInsideMe 0x00000004 +#define AdjacentModuleFlag_Vertical 0x00000008 + +class Adjacent_Module_Entry_Points_Chunk : public Chunk +{ +public: + + Adjacent_Module_Entry_Points_Chunk(Object_Module_Data_Chunk * parent, List aml) + : Chunk (parent, "ADJMDLEP"), adjacent_modules_list (aml) + {} + Adjacent_Module_Entry_Points_Chunk(Chunk_With_Children * parent, const char * data, size_t size); + List adjacent_modules_list; + + virtual void fill_data_block (char *); + virtual size_t size_chunk (); + + +private: + + friend class Object_Module_Data_Chunk; + + + +}; + + +/////////////////////////////////////////////// + +class Module_Flag_Chunk : public Chunk +{ +public: + Module_Flag_Chunk(Object_Module_Data_Chunk * parent); + Module_Flag_Chunk(Chunk_With_Children* parent, const char * data, size_t ); + + virtual void fill_data_block(char*); + virtual size_t size_chunk() + {return chunk_size=20;} + + int Flags; + int spare; +private: + friend class Object_Module_Data_Chunk; + + + +}; +/////////////////////////////////////////////// + +class Module_Zone_Chunk : public Chunk +{ +public: + Module_Zone_Chunk(Object_Module_Data_Chunk * parent); + Module_Zone_Chunk(Chunk_With_Children* parent, const char * data, size_t ); + + virtual void fill_data_block(char*); + virtual size_t size_chunk() + {return chunk_size=20;} + + int Zone; + int spare; +private: + friend class Object_Module_Data_Chunk; +}; + + +/////////////////////////////////////////////// +class Module_Acoustics_Chunk : public Chunk +{ +public: + Module_Acoustics_Chunk(Object_Module_Data_Chunk * parent); + Module_Acoustics_Chunk(Chunk_With_Children* parent, const char * data, size_t ); + + virtual void fill_data_block(char*); + virtual size_t size_chunk() + {return chunk_size=24;} + + int env_index; + float reverb; + int spare; +private: + friend class Object_Module_Data_Chunk; + + + +}; +/////////////////////////////////////////////// + +class Object_Project_Data_Chunk : public Chunk_With_Children +{ +public: + + // constructor from Object_Chunks + Object_Project_Data_Chunk (Object_Chunk * parent) + : Chunk_With_Children (parent, "OBJPRJDT") + {} + // constructor from buffer + Object_Project_Data_Chunk (Chunk_With_Children * const parent,const char *,const size_t); +private: + + friend class Object_Chunk; + + + +}; + + + +/////////////////////////////////////////////// + + + +struct ChunkTrackSection +{ + + ChunkQuat quat_start; + ChunkQuat quat_end; + + ChunkVectorInt pivot_start; + ChunkVectorInt pivot_end; + + ChunkVectorInt object_offset; + + int time_for_section; + + int spare; + + +}; + +#define TrackFlag_Loop 0x00000001 +#define TrackFlag_PlayingAtStart 0x00000002 +#define TrackFlag_LoopBackAndForth 0x00000004 +#define TrackFlag_UseTrackSmoothing 0x00000008 +#define TrackFlag_QuatProblemSorted 0x80000000 + +class Object_Track_Chunk2 : public Chunk +{ +public: + + Object_Track_Chunk2 (Object_Chunk * parent); + Object_Track_Chunk2 (Chunk_With_Children * parent,const char *, size_t); + + ~Object_Track_Chunk2(); + + int num_sections; + ChunkTrackSection * sections; + + int flags; + int timer_start; + + virtual void fill_data_block (char *); + virtual size_t size_chunk (); + +private: + + friend class Object_Chunk; + + +}; + +#define TrackSoundFlag_Loop 0x00000001 +class Object_Track_Sound_Chunk : public Chunk +{ + public : + + Object_Track_Sound_Chunk(Chunk_With_Children* parent); + Object_Track_Sound_Chunk (Chunk_With_Children * const parent,const char *, size_t const); + ~Object_Track_Sound_Chunk(); + + size_t size_chunk (); + void fill_data_block (char * data_start); + + char* wav_name; + unsigned long inner_range; + unsigned long outer_range; + int max_volume; + int pitch; + int flags; + int index; + +}; + +/////////////////////////////////////////////// + + +struct AltObjectLocation +{ + ChunkVectorInt position; + ChunkQuat orientation; + int spare1,spare2; +}; + + +//chunk for storing list of possible alternate locations for an object +//use for placed objects and generators and possibly sounds +class Object_Alternate_Locations_Chunk : public Chunk +{ +public : + Object_Alternate_Locations_Chunk(Chunk_With_Children* parent,const char* data, size_t); + Object_Alternate_Locations_Chunk(Chunk_With_Children* parent); + ~Object_Alternate_Locations_Chunk(); + + void fill_data_block(char* data); + size_t size_chunk(); + + int num_locations; + AltObjectLocation* locations; + + int group; //objects with the same group (other than 0) share the same die roll + + int spare2; +}; + +#endif \ No newline at end of file diff --git a/3dc/win95/OEChunk.cpp b/3dc/win95/OEChunk.cpp new file mode 100644 index 0000000..86f3d87 --- /dev/null +++ b/3dc/win95/OEChunk.cpp @@ -0,0 +1,167 @@ +#if objedit +#include "Template.hpp" +#endif + +#include "OEChunk.h" +#include "Chunk.hpp" + +#ifdef cencon +#define new my_new +#endif +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(oechunk) + +extern Chunk *Parent_File; + +RIF_IMPLEMENT_DYNCREATE("MAPBLOCK",Map_Block_Chunk) + +Map_Block_Chunk::Map_Block_Chunk(Chunk_With_Children * parent,const char* data,size_t) + :Chunk(parent,"MAPBLOCK") +{ + strncpy(map_data.TemplateName,data,20); + strncpy(map_data.TemplateNotes,data+20,100); + map_data.MapType=*((int*)(data+120)); + map_data.MapShape=*((int*)(data+124)); + map_data.MapFlags=*((int*)(data+128)); + map_data.MapFlags2=*((int*)(data+132)); + map_data.MapFlags3=*((int*)(data+136)); + map_data.MapCType=*((int*)(data+140)); + map_data.MapCGameType=*((int*)(data+144)); + map_data.MapCStrategyS=*((int*)(data+148)); + map_data.MapCStrategyL=*((int*)(data+152)); + map_data.MapInteriorType=*((int*)(data+126)); + map_data.MapLightType=*((int*)(data+160)); + map_data.MapMass=*((int*)(data+164)); + map_data.MapNewtonV.vx=*((int*)(data+168)); + map_data.MapNewtonV.vy=*((int*)(data+172)); + map_data.MapNewtonV.vz=*((int*)(data+176)); + map_data.MapOrigin.vx=*((int*)(data+180)); + map_data.MapOrigin.vy=*((int*)(data+184)); + map_data.MapOrigin.vz=*((int*)(data+188)); + map_data.MapViewType=*((int*)(data+192)); + map_data.MapVDBData=*((int*)(data+196)); + map_data.SimShapeList=*((int*)(data+200)); +} + +RIF_IMPLEMENT_DYNCREATE("STRATEGY",Strategy_Chunk) + +Strategy_Chunk::Strategy_Chunk(Chunk_With_Children * parent,const char * data,size_t) + :Chunk(parent,"STRATEGY") +{ + strncpy(strategy_data.StrategyName,data,20); + strncpy(strategy_data.StrategyNotes,data+20,100); + strategy_data.Strategy=*((int*)(data+120)); +} + +void Map_Block_Chunk::fill_data_block (char* data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + strncpy (data_start,map_data.TemplateName,20); + data_start+=20; + strncpy (data_start,map_data.TemplateNotes,100); + data_start+=100; + + *((int*)data_start)=map_data.MapType; + data_start += 4; + + *((int*)data_start)=map_data.MapShape; + data_start += 4; + *((int*)data_start)=map_data.MapFlags; + data_start += 4; + *((int*)data_start)=map_data.MapFlags2; + data_start += 4; + *((int*)data_start)=map_data.MapFlags3; + data_start += 4; + *((int*)data_start)=map_data.MapCType; + data_start += 4; + *((int*)data_start)=map_data.MapCGameType; + data_start += 4; + *((int*)data_start)=map_data.MapCStrategyS; + data_start+=4; + *((int*)data_start)=map_data.MapCStrategyL;; + data_start+=4; + *((int*)data_start)=map_data.MapInteriorType; + data_start+=4; + *((int*)data_start)=map_data.MapLightType; + data_start+=4; + *((int*)data_start)=map_data.MapMass; + data_start+=4; + *((int*)data_start)=map_data.MapNewtonV.vx; + data_start+=4; + *((int*)data_start)=map_data.MapNewtonV.vy; + data_start+=4; + *((int*)data_start)=map_data.MapNewtonV.vz; + data_start+=4; + *((int*)data_start)=map_data.MapOrigin.vx; + data_start+=4; + *((int*)data_start)=map_data.MapOrigin.vy; + data_start+=4; + *((int*)data_start)=map_data.MapOrigin.vz; + data_start+=4; + *((int*)data_start)=map_data.MapViewType; + data_start+=4; + *((int*)data_start)=map_data.MapVDBData; + data_start+=4; + *((int*)data_start)=map_data.SimShapeList; +} + +void Strategy_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + strncpy (data_start,strategy_data.StrategyName,20); + data_start+=20; + strncpy (data_start,strategy_data.StrategyNotes,100); + data_start+=100; + + *((int*)data_start)=strategy_data.Strategy; +} + +BOOL Map_Block_Chunk::output_chunk(HANDLE &hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = this->make_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; +} + +BOOL Strategy_Chunk::output_chunk(HANDLE &hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = this->make_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; +} + + diff --git a/3dc/win95/OEChunk.h b/3dc/win95/OEChunk.h new file mode 100644 index 0000000..92aa840 --- /dev/null +++ b/3dc/win95/OEChunk.h @@ -0,0 +1,99 @@ +#ifndef _oechunk_h_ +#define _oechunk_h_ 1 + +#include "Chunk.hpp" +#include "obchunk.hpp" + +#if objedit +#include "Template.hpp" +#endif +//#if engine +//#define VECTOR VECTORCH +//#endif + +#if engine +#else +struct VECTORCH +{ + int vx, vy, vz; +}; +#endif + +struct ChunkMapBlock +{ + char TemplateName[20]; + char TemplateNotes[100]; + int MapType; + int MapShape; + int MapFlags; + int MapFlags2; + int MapFlags3; + int MapCType; + int MapCGameType; + int MapCStrategyS; + int MapCStrategyL; + int MapInteriorType; + int MapLightType; + int MapMass; + VECTORCH MapNewtonV; + VECTORCH MapOrigin; + int MapViewType; + + int MapVDBData; + int SimShapeList; + + + +}; + +class Map_Block_Chunk : public Chunk +{ +public: + virtual size_t size_chunk() + { + return (chunk_size=216); + } + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start); + + ChunkMapBlock map_data; + friend class Object_Project_Data_Chunk; + + Map_Block_Chunk (Object_Project_Data_Chunk * parent) + :Chunk(parent,"MAPBLOCK") + {} + + //constructor from buffer + Map_Block_Chunk (Chunk_With_Children * parent,const char* data,size_t); +}; + +struct ChunkStrategy +{ + char StrategyName[20]; + char StrategyNotes[100]; + int Strategy; +}; + +class Strategy_Chunk : public Chunk +{ +public : + virtual size_t size_chunk() + { + return (chunk_size=136); + } + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start); + + ChunkStrategy strategy_data; + friend class Object_Project_Data_Chunk; + + Strategy_Chunk(Object_Project_Data_Chunk *parent) + :Chunk(parent,"STRATEGY") + {} + + //constructor from buffer + Strategy_Chunk (Chunk_With_Children * parent,const char* data,size_t); +}; +#endif \ No newline at end of file diff --git a/3dc/win95/OURASERT.H b/3dc/win95/OURASERT.H new file mode 100644 index 0000000..6ffa3de --- /dev/null +++ b/3dc/win95/OURASERT.H @@ -0,0 +1,138 @@ + +/* + This is our assert file for the Win95 + platform, with Dave's global/local assert + distinctions. +*/ + +/* + Note that WaitForReturn now calls FlushTextprintBuffer + and FlipBuffers implicitly. +*/ + +/* + Modified 10th December 1996 by Dave Malcolm. Now can be set so that + functions are supplied by the project/platform to fire when an assertion + fires. + + Also is set so that the compiler will generate an error message if you manage to + include the file more than once (with confusing definitons of UseLocalAssert); + this can be disabled. +*/ + + +#ifdef _OURASERT + #if StopCompilationOnMultipleInclusions + #error OURASERT.H included more than once + #endif +#else + #define _OURASERT 1 +#endif + + +#ifdef AVP_DEBUG_VERSION + #define ASSERT_SYSTEM_ON 1 +#else + #define ASSERT_SYSTEM_ON 0 +#endif + + +#if UseProjPlatAssert +/* New assertions system */ + + #ifdef __cplusplus + extern "C" { + #endif + int GlobalAssertFired(char* Filename, int LineNum, char* Condition); + int LocalAssertFired(char* Filename, int LineNum, char* Condition); + void ExitFired(char* Filename, int LineNum, int ExitCode); + #ifdef __cplusplus + }; + #endif + + + #if ASSERT_SYSTEM_ON + + #define GLOBALASSERT(x) \ + (void)( (x) ? 1 : \ + ( \ + GlobalAssertFired \ + ( \ + __FILE__, \ + __LINE__, \ + #x \ + ) \ + ) \ + ) + + #if UseLocalAssert + + #define LOCALASSERT(x) \ + (void)( (x) ? 1 : \ + ( \ + LocalAssertFired \ + ( \ + __FILE__, \ + __LINE__, \ + #x \ + ) \ + ) \ + ) + + #else + + #define LOCALASSERT(ignore) + + #endif + + + #define exit(x) ExitFired(__FILE__,__LINE__,x) + + #else + + #define GLOBALASSERT(ignore) ((void)0) + + #define LOCALASSERT(ignore) ((void)0) + + #endif + + +#else +/* Old assertions system */ + + #define GlobalAssertCode 0xffff + #define LocalAssertCode 0xfffe + + + #if 0//debug + + #define GLOBALASSERT(x) \ + (void)((x) ? 1 : \ + (textprint("\nGAF " #x "\nLINE %d\nFILE'%s'\n", \ + __LINE__, __FILE__), WaitForReturn(), \ + ExitSystem(), exit(GlobalAssertCode), \ + 0)) + + #if UseLocalAssert + + #define LOCALASSERT(x) \ + (void)((x) ? 1 : \ + (textprint("\nLAF " #x "LINE %d\nFILE'%s'\n", \ + __LINE__, __FILE__), WaitForReturn(), \ + ExitSystem(), exit(LocalAssertCode), \ + 0)) + + #else + + #define LOCALASSERT(ignore) + + #endif + + #else + + #define GLOBALASSERT(ignore) + + #define LOCALASSERT(ignore) + + #endif +#endif diff --git a/3dc/win95/OUR_MEM.C b/3dc/win95/OUR_MEM.C new file mode 100644 index 0000000..32a81ec --- /dev/null +++ b/3dc/win95/OUR_MEM.C @@ -0,0 +1,54 @@ +#include "3dc.h" + +#include + +#define UseLocalAssert No + +#include "ourasert.h" + +#if debug +int alloc_cnt = 0; +int deall_cnt = 0; +#endif + +void *AllocMem(size_t __size); +void DeallocMem(void *__ptr); + +/* Note: Never use AllocMem directly ! */ +/* Instead use AllocateMem() which is a */ +/* macro defined in mem3dc.h that allows */ +/* for debugging info. */ + +void *AllocMem(size_t __size) +{ + GLOBALASSERT(__size>0); + #if debug + alloc_cnt++; + #endif + + return malloc(__size); +}; + +/* Note: Never use DeallocMem directly ! */ +/* Instead use DeallocateMem() which is a */ +/* macro defined in mem3dc.h that allows */ +/* for debugging info. */ + +void DeallocMem(void *__ptr) +{ + #if debug + deall_cnt++; + #endif + + if(__ptr) free(__ptr); + + #if debug + else { + + textprint("ERROR - freeing null ptr\n"); + WaitForReturn(); + + } + #endif +}; + diff --git a/3dc/win95/PENTIME.H b/3dc/win95/PENTIME.H new file mode 100644 index 0000000..8c66961 --- /dev/null +++ b/3dc/win95/PENTIME.H @@ -0,0 +1,64 @@ +/* pentime.h */ +extern unsigned long int rdtsc_lo(void); +extern unsigned long int rdtsc_hi(void); +extern unsigned long int rdtsc_mid(void); + +#define ProfileStart() \ +{ \ + int time = rdtsc_lo(); +#define ProfileStop(x) \ + textprint("%s %d\n",x,rdtsc_lo()-time); \ +} + +#pragma aux rdtsc_lo = \ + "db 0fh, 31h" \ + value [eax] \ + modify [edx]; + +#pragma aux rdtsc_hi = \ + "db 0fh, 31h" \ + value [edx] \ + modify [eax]; + +#pragma aux rdtsc_mid = \ + "db 0fh, 31h" \ + "shr eax, 10h" \ + "shl edx, 10h" \ + "add eax, edx" \ + value [eax] \ + modify [edx]; + +/* Test to see if we have a Pentium or not. Note that this test is reliable + * enough for a tools project (where we can put in an overide switch) but not + * for a released product. + */ +extern unsigned char Pentium(void); +#pragma aux Pentium = \ + "pushfd" \ + "pop eax" \ + "or eax, 00200000h" \ + "push eax" \ + "popfd" \ + "pushfd" \ + "pop eax" \ + "mov ecx, eax" \ + "and eax, 00200000h" \ + "cmp eax, 0" \ + "je not_Pentium" \ + "mov eax, ecx" \ + "and eax, 0ffdfffffh" \ + "push eax" \ + "popfd" \ + "pushfd" \ + "pop eax" \ + "and eax, 00200000h" \ + "cmp eax, 0" \ + "jne not_Pentium" \ + "is_Pentium: mov al, 1" \ + "jmp finish" \ + "not_Pentium: mov al, 0" \ + "finish: nop" \ + value [al] \ + modify [eax ecx] + + diff --git a/3dc/win95/RAD.H b/3dc/win95/RAD.H new file mode 100644 index 0000000..3fdce40 --- /dev/null +++ b/3dc/win95/RAD.H @@ -0,0 +1,606 @@ +#ifndef __RAD__ +#define __RAD__ + +#define RADCOPYRIGHT "Copyright (C) 1994-98 RAD Game Tools, Inc." + +#ifndef __RADRES__ + +// __RADDOS__ means DOS code (16 or 32 bit) +// __RAD16__ means 16 bit code (Win16) +// __RAD32__ means 32 bit code (DOS, Win386, Win32s, Mac) +// __RADWIN__ means Windows code (Win16, Win386, Win32s) +// __RADWINEXT__ means Windows 386 extender (Win386) +// __RADNT__ means Win32s code +// __RADMAC__ means Macintosh +// __RAD68K__ means 68K Macintosh +// __RADPPC__ means PowerMac + + +#if (defined(__MWERKS__) && !defined(__INTEL__)) || defined(THINK_C) || defined(powerc) || defined(macintosh) || defined(__powerc) + + #define __RADMAC__ + #if defined(powerc) || defined(__powerc) + #define __RADPPC__ + #else + #define __RAD68K__ + #endif + + #define __RAD32__ + +#else + + #ifdef __DOS__ + #define __RADDOS__ + #endif + + #ifdef __386__ + #define __RAD32__ + #endif + + #ifdef _Windows //For Borland + #ifdef __WIN32__ + #define WIN32 + #else + #define __WINDOWS__ + #endif + #endif + + #ifdef _WINDOWS //For MS + #ifndef _WIN32 + #define __WINDOWS__ + #endif + #endif + + #ifdef _WIN32 + #define __RADWIN__ + #define __RADNT__ + #define __RAD32__ + #else + #ifdef __NT__ + #define __RADWIN__ + #define __RADNT__ + #define __RAD32__ + #else + #ifdef __WINDOWS_386__ + #define __RADWIN__ + #define __RADWINEXT__ + #define __RAD32__ + #else + #ifdef __WINDOWS__ + #define __RADWIN__ + #define __RAD16__ + #else + #ifdef WIN32 + #define __RADWIN__ + #define __RADNT__ + #define __RAD32__ + #endif + #endif + #endif + #endif + #endif + +#endif + +#if (!defined(__RADDOS__) && !defined(__RADWIN__) && !defined(__RADMAC__)) + #error RAD.H did not detect your platform. Define __DOS__, __WINDOWS__, WIN32, macintosh, or powerc. +#endif + +#ifdef __RADMAC__ + + // this define is for CodeWarrior 11's stupid new libs (even though + // we don't use longlong's). + + #define __MSL_LONGLONG_SUPPORT__ + + #define RADLINK + #define RADEXPLINK + + #ifdef __CFM68K__ + #ifdef __RADINDLL__ + #define RADEXPFUNC RADDEFFUNC __declspec(export) + #else + #define RADEXPFUNC RADDEFFUNC __declspec(import) + #endif + #else + #define RADEXPFUNC RADDEFFUNC + #endif + #define RADASMLINK + +#else + + #ifdef __RADNT__ + #ifndef _WIN32 + #define _WIN32 + #endif + #ifndef WIN32 + #define WIN32 + #endif + #endif + + #ifdef __RADWIN__ + #ifdef __RAD32__ + #ifdef __RADNT__ + + #define RADLINK __stdcall + #define RADEXPLINK __stdcall + + #ifdef __RADINEXE__ + #define RADEXPFUNC RADDEFFUNC + #else + #ifndef __RADINDLL__ + #define RADEXPFUNC RADDEFFUNC __declspec(dllimport) + #ifdef __BORLANDC__ + #if __BORLANDC__<=0x460 + #undef RADEXPFUNC + #define RADEXPFUNC RADDEFFUNC + #endif + #endif + #else + #define RADEXPFUNC RADDEFFUNC __declspec(dllexport) + #endif + #endif + #else + #define RADLINK __pascal + #define RADEXPLINK __far __pascal + #define RADEXPFUNC RADDEFFUNC + #endif + #else + #define RADLINK __pascal + #define RADEXPLINK __far __pascal __export + #define RADEXPFUNC RADDEFFUNC + #endif + #else + #define RADLINK __pascal + #define RADEXPLINK __pascal + #define RADEXPFUNC RADDEFFUNC + #endif + + #define RADASMLINK __cdecl + +#endif + +#ifdef __RADWIN__ + #ifndef _WINDOWS + #define _WINDOWS + #endif +#endif + +#ifdef __cplusplus + #define RADDEFFUNC extern "C" + #define RADDEFSTART extern "C" { + #define RADDEFEND } +#else + #define RADDEFFUNC + #define RADDEFSTART + #define RADDEFEND +#endif + + +RADDEFSTART + +#define s8 signed char +#define u8 unsigned char +#define u32 unsigned long +#define s32 signed long + +#ifdef __RAD32__ + #define PTR4 + + #define u16 unsigned short + #define s16 signed short + + #ifdef __RADMAC__ + + #include + #include + #include + + #define radstrlen strlen + + #define radmemset memset + + #define radmemcmp memcmp + + #define radmemcpy(dest,source,size) BlockMoveData((Ptr)(source),(Ptr)(dest),size) + + #define radmemcpydb(dest,source,size) BlockMoveData((Ptr)(source),(Ptr)(dest),size) + + #define radstrcat strcat + + #define radstrcpy strcpy + + static u32 inline radsqr(s32 a) { return(a*a); } + + #ifdef __RAD68K__ + + #pragma parameter __D0 mult64anddiv(__D0,__D1,__D2) + u32 mult64anddiv(u32 m1,u32 m2,u32 d) ={0x4C01,0x0C01,0x4C42,0x0C01}; + // muls.l d1,d1:d0 divs.l d2,d1:d0 + + #pragma parameter radconv32a(__A0,__D0) + void radconv32a(void* p,u32 n) ={0x4A80,0x600C,0x2210,0xE059,0x4841,0xE059,0x20C1,0x5380,0x6EF2}; + // tst.l d0 bra.s @loope @loop: move.l (a0),d1 ror.w #8,d1 swap d1 ror.w #8,d1 move.l d1,(a0)+ sub.l #1,d0 bgt.s @loop @loope: + + #else + + u32 mult64anddiv(u32 m1,u32 m2,u32 d); + + void radconv32a(void* p,u32 n); + + #endif + + #else + + #ifdef __WATCOMC__ + + u32 radsqr(s32 a); + #pragma aux radsqr = "mul eax" parm [eax] modify [EDX eax]; + + u32 mult64anddiv(u32 m1,u32 m2,u32 d); + #pragma aux mult64anddiv = "mul ecx" "div ebx" parm [eax] [ecx] [ebx] modify [EDX eax]; + + s32 radabs(s32 ab); + #pragma aux radabs = "test eax,eax" "jge skip" "neg eax" "skip:" parm [eax]; + + #define radabs32 radabs + + u32 DOSOut(const char* str); + #pragma aux DOSOut = "cld" "mov ecx,0xffffffff" "xor eax,eax" "mov edx,edi" "repne scasb" "not ecx" "dec ecx" "mov ebx,1" "mov ah,0x40" "int 0x21" parm [EDI] modify [EAX EBX ECX EDX EDI] value [ecx]; + + void DOSOutNum(const char* str,u32 len); + #pragma aux DOSOutNum = "mov ah,0x40" "mov ebx,1" "int 0x21" parm [edx] [ecx] modify [eax ebx]; + + u32 ErrOut(const char* str); + #pragma aux ErrOut = "cld" "mov ecx,0xffffffff" "xor eax,eax" "mov edx,edi" "repne scasb" "not ecx" "dec ecx" "xor ebx,ebx" "mov ah,0x40" "int 0x21" parm [EDI] modify [EAX EBX ECX EDX EDI] value [ecx]; + + void ErrOutNum(const char* str,u32 len); + #pragma aux ErrOutNum = "mov ah,0x40" "xor ebx,ebx" "int 0x21" parm [edx] [ecx] modify [eax ebx]; + + void radmemset16(void* dest,u16 value,u32 size); + #pragma aux radmemset16 = "cld" "mov bx,ax" "shl eax,16" "mov ax,bx" "mov bl,cl" "shr ecx,1" "rep stosd" "mov cl,bl" "and cl,1" "rep stosw" parm [EDI] [EAX] [ECX] modify [EAX EDX EBX ECX EDI]; + + void radmemset(void* dest,u8 value,u32 size); + #pragma aux radmemset = "cld" "mov ah,al" "mov bx,ax" "shl eax,16" "mov ax,bx" "mov bl,cl" "shr ecx,2" "and bl,3" "rep stosd" "mov cl,bl" "rep stosb" parm [EDI] [AL] [ECX] modify [EAX EDX EBX ECX EDI]; + + void radmemset32(void* dest,u32 value,u32 size); + #pragma aux radmemset32 = "cld" "rep stosd" parm [EDI] [EAX] [ECX] modify [EAX EDX EBX ECX EDI]; + + void radmemcpy(void* dest,const void* source,u32 size); + #pragma aux radmemcpy = "cld" "mov bl,cl" "shr ecx,2" "rep movsd" "mov cl,bl" "and cl,3" "rep movsb" parm [EDI] [ESI] [ECX] modify [EBX ECX EDI ESI]; + + void __far *radfmemcpy(void __far* dest,const void __far* source,u32 size); + #pragma aux radfmemcpy = "cld" "push es" "push ds" "mov es,cx" "mov ds,dx" "mov ecx,eax" "shr ecx,2" "rep movsd" "mov cl,al" "and cl,3" "rep movsb" "pop ds" "pop es" parm [CX EDI] [DX ESI] [EAX] modify [ECX EDI ESI] value [CX EDI]; + + void radmemcpydb(void* dest,const void* source,u32 size); //Destination bigger + #pragma aux radmemcpydb = "std" "mov bl,cl" "lea esi,[esi+ecx-4]" "lea edi,[edi+ecx-4]" "shr ecx,2" "rep movsd" "and bl,3" "jz dne" "add esi,3" "add edi,3" "mov cl,bl" "rep movsb" "dne:" "cld" parm [EDI] [ESI] [ECX] modify [EBX ECX EDI ESI]; + + char* radstrcpy(void* dest,const void* source); + #pragma aux radstrcpy = "cld" "mov edx,edi" "lp:" "mov al,[esi]" "inc esi" "mov [edi],al" "inc edi" "cmp al,0" "jne lp" parm [EDI] [ESI] modify [EAX EDX EDI ESI] value [EDX]; + + char __far* radfstrcpy(void __far* dest,const void __far* source); + #pragma aux radfstrcpy = "cld" "push es" "push ds" "mov es,cx" "mov ds,dx" "mov edx,edi" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "pop ds" "pop es" parm [CX EDI] [DX ESI] modify [EAX EDX EDI ESI] value [CX EDX]; + + char* radstpcpy(void* dest,const void* source); + #pragma aux radstpcpy = "cld" "lp:" "mov al,[esi]" "inc esi" "mov [edi],al" "inc edi" "cmp al,0" "jne lp" "dec edi" parm [EDI] [ESI] modify [EAX EDI ESI] value [EDI]; + + char* radstpcpyrs(void* dest,const void* source); + #pragma aux radstpcpyrs = "cld" "lp:" "mov al,[esi]" "inc esi" "mov [edi],al" "inc edi" "cmp al,0" "jne lp" "dec esi" parm [EDI] [ESI] modify [EAX EDI ESI] value [ESI]; + + u32 radstrlen(const void* dest); + #pragma aux radstrlen = "cld" "mov ecx,0xffffffff" "xor eax,eax" "repne scasb" "not ecx" "dec ecx" parm [EDI] modify [EAX ECX EDI] value [ECX]; + + char* radstrcat(void* dest,const void* source); + #pragma aux radstrcat = "cld" "mov ecx,0xffffffff" "mov edx,edi" "xor eax,eax" "repne scasb" "dec edi" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" \ + parm [EDI] [ESI] modify [EAX ECX EDI ESI] value [EDX]; + + char* radstrchr(const void* dest,char chr); + #pragma aux radstrchr = "cld" "lp:" "lodsb" "cmp al,dl" "je fnd" "cmp al,0" "jnz lp" "mov esi,1" "fnd:" "dec esi" parm [ESI] [DL] modify [EAX ESI] value [esi]; + + s8 radmemcmp(const void* s1,const void* s2,u32 len); + #pragma aux radmemcmp = "cld" "rep cmpsb" "setne al" "jbe end" "neg al" "end:" parm [EDI] [ESI] [ECX] modify [ECX EDI ESI]; + + s8 radstrcmp(const void* s1,const void* s2); + #pragma aux radstrcmp = "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,ah" "jne set" "cmp al,0" "je set" "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" \ + parm [EDI] [ESI] modify [EAX EDI ESI]; + + s8 radstricmp(const void* s1,const void* s2); + #pragma aux radstricmp = "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" "cmp ah,'a'" "jb c2" "cmp ah,'z'" "ja c2" "sub ah,32" "c2:" "cmp al,ah" "jne set" "cmp al,0" "je set" \ + "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" \ + parm [EDI] [ESI] modify [EAX EDI ESI]; + + s8 radstrnicmp(const void* s1,const void* s2,u32 len); + #pragma aux radstrnicmp = "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" "cmp ah,'a'" "jb c2" "cmp ah,'z'" "ja c2" "sub ah,32" "c2:" "cmp al,ah" "jne set" "cmp al,0" "je set" \ + "dec ecx" "jz set" "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" \ + parm [EDI] [ESI] [ECX] modify [EAX ECX EDI ESI]; + + char* radstrupr(void* s1); + #pragma aux radstrupr = "mov ecx,edi" "lp:" "mov al,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub [edi],32" "c1:" "inc edi" "cmp al,0" "jne lp" parm [EDI] modify [EAX EDI] value [ecx]; + + char* radstrlwr(void* s1); + #pragma aux radstrlwr = "mov ecx,edi" "lp:" "mov al,[edi]" "cmp al,'A'" "jb c1" "cmp al,'Z'" "ja c1" "add [edi],32" "c1:" "inc edi" "cmp al,0" "jne lp" parm [EDI] modify [EAX EDI] value [ecx]; + + u32 radstru32(const void* dest); + #pragma aux radstru32 = "cld" "xor ecx,ecx" "xor ebx,ebx" "xor edi,edi" "lodsb" "cmp al,45" "jne skip2" "mov edi,1" "jmp skip" "lp:" "mov eax,10" "mul ecx" "lea ecx,[eax+ebx]" \ + "skip:" "lodsb" "skip2:" "cmp al,0x39" "ja dne" "cmp al,0x30" "jb dne" "mov bl,al" "sub bl,0x30" "jmp lp" "dne:" "test edi,1" "jz pos" "neg ecx" "pos:" \ + parm [ESI] modify [EAX EBX EDX EDI ESI] value [ecx]; + + u16 GetDS(); + #pragma aux GetDS = "mov ax,ds" value [ax]; + + #ifdef __RADWINEXT__ + + #define _16To32(ptr16) ((void*)(((GetSelectorBase((u16)(((u32)(ptr16))>>16))+((u16)(u32)(ptr16)))-GetSelectorBase(GetDS())))) + + #endif + + #ifndef __RADWIN__ + #define int86 int386 + #define int86x int386x + #endif + + #define u32regs x + #define u16regs w + + #else + + #define radstrcpy strcpy + #define radstrcat strcat + #define radmemcpy memcpy + #define radmemcpydb memmove + #define radmemcmp memcmp + #define radmemset memset + #define radstrlen strlen + #define radstrchr strchr + #define radtoupper toupper + #define radstru32(s) ((u32)atol(s)) + #define radstricmp _stricmp + #define radstrcmp strcmp + #define radstrupr _strupr + #define radstrlwr _strlwr + #define BreakPoint() _asm {int 3} + + #ifdef _MSC_VER + + #pragma warning( disable : 4035) + + typedef char* RADPCHAR; + + u32 __inline radsqr(u32 m) { + _asm { + mov eax,[m] + mul eax + } + } + + u32 __inline mult64anddiv(u32 m1,u32 m2, u32 d) { + _asm { + mov eax,[m1] + mov ecx,[m2] + mul ecx + mov ecx,[d] + div ecx + } + } + + s32 __inline radabs(s32 ab) { + _asm { + mov eax,[ab] + test eax,eax + jge skip + neg eax + skip: + } + } + + u8 __inline radinp(u16 p) { + _asm { + mov dx,[p] + in al,dx + } + } + + void __inline radoutp(u16 p,u8 v) { + _asm { + mov dx,[p] + mov al,[v] + out dx,al + } + } + + RADPCHAR __inline radstpcpy(char* p1, char* p2) { + _asm { + mov edx,[p1] + mov ecx,[p2] + cld + lp: + mov al,[ecx] + inc ecx + mov [edx],al + inc edx + cmp al,0 + jne lp + dec edx + mov eax,edx + } + } + + RADPCHAR __inline radstpcpyrs(char* p1, char* p2) { + _asm { + mov edx,[p1] + mov ecx,[p2] + cld + lp: + mov al,[ecx] + inc ecx + mov [edx],al + inc edx + cmp al,0 + jne lp + dec ecx + mov eax,ecx + } + } + + void __inline radmemset16(void* dest,u16 value,u32 sizeb) { + _asm { + mov edi,[dest] + mov ax,[value] + mov ecx,[sizeb] + shl eax,16 + cld + mov ax,[value] + mov bl,cl + shr ecx,1 + rep stosd + mov cl,bl + and cl,1 + rep stosw + } + } + + void __inline radmemset32(void* dest,u32 value,u32 sizeb) { + _asm { + mov edi,[dest] + mov eax,[value] + mov ecx,[sizeb] + cld + rep stosd + } + } + + #pragma warning( default : 4035) + + #endif + + #endif + + #endif + +#else + + #define PTR4 __far + + #define u16 unsigned int + #define s16 signed int + + #ifdef __WATCOMC__ + + u32 radsqr(s32 a); + #pragma aux radsqr = "shl edx,16" "mov dx,ax" "mov eax,edx" "xor edx,edx" "mul eax" "shld edx,eax,16" parm [dx ax] modify [DX ax] value [dx ax]; + + s16 radabs(s16 ab); + #pragma aux radabs = "test ax,ax" "jge skip" "neg ax" "skip:" parm [ax] value [ax]; + + s32 radabs32(s32 ab); + #pragma aux radabs32 = "test dx,dx" "jge skip" "neg dx" "neg ax" "sbb dx,0" "skip:" parm [dx ax] value [dx ax]; + + u32 DOSOut(const char far* dest); + #pragma aux DOSOut = "cld" "and edi,0xffff" "mov dx,di" "mov ecx,0xffffffff" "xor eax,eax" 0x67 "repne scasb" "not ecx" "dec ecx" "mov bx,1" "push ds" "push es" "pop ds" "mov ah,0x40" "int 0x21" "pop ds" "movzx eax,cx" "shr ecx,16" \ + parm [ES DI] modify [AX BX CX DX DI ES] value [CX AX]; + + void DOSOutNum(const char far* str,u16 len); + #pragma aux DOSOutNum = "push ds" "mov ds,cx" "mov cx,bx" "mov ah,0x40" "mov bx,1" "int 0x21" "pop ds" parm [cx dx] [bx] modify [ax bx cx]; + + u32 ErrOut(const char far* dest); + #pragma aux ErrOut = "cld" "and edi,0xffff" "mov dx,di" "mov ecx,0xffffffff" "xor eax,eax" 0x67 "repne scasb" "not ecx" "dec ecx" "xor bx,bx" "push ds" "push es" "pop ds" "mov ah,0x40" "int 0x21" "pop ds" "movzx eax,cx" "shr ecx,16" \ + parm [ES DI] modify [AX BX CX DX DI ES] value [CX AX]; + + void ErrOutNum(const char far* str,u16 len); + #pragma aux ErrOutNum = "push ds" "mov ds,cx" "mov cx,bx" "mov ah,0x40" "xor bx,bx" "int 0x21" "pop ds" parm [cx dx] [bx] modify [ax bx cx]; + + void radmemset(void far *dest,u8 value,u32 size); + #pragma aux radmemset = "cld" "and edi,0ffffh" "shl ecx,16" "mov cx,bx" "mov ah,al" "mov bx,ax" "shl eax,16" "mov ax,bx" "mov bl,cl" "shr ecx,2" 0x67 "rep stosd" "mov cl,bl" "and cl,3" "rep stosb" parm [ES DI] [AL] [CX BX]; + + void radmemset16(void far* dest,u16 value,u32 size); + #pragma aux radmemset16 = "cld" "and edi,0ffffh" "shl ecx,16" "mov cx,bx" "mov bx,ax" "shl eax,16" "mov ax,bx" "mov bl,cl" "shr ecx,1" "rep stosd" "mov cl,bl" "and cl,1" "rep stosw" parm [ES DI] [AX] [CX BX]; + + void radmemcpy(void far* dest,const void far* source,u32 size); + #pragma aux radmemcpy = "cld" "push ds" "mov ds,dx" "and esi,0ffffh" "and edi,0ffffh" "shl ecx,16" "mov cx,bx" "shr ecx,2" 0x67 "rep movsd" "mov cl,bl" "and cl,3" "rep movsb" "pop ds" parm [ES DI] [DX SI] [CX BX] modify [CX SI DI ES]; + + s8 radmemcmp(const void far* s1,const void far* s2,u32 len); + #pragma aux radmemcmp = "cld" "push ds" "mov ds,dx" "shl ecx,16" "mov cx,bx" "rep cmpsb" "setne al" "jbe end" "neg al" "end:" "pop ds" parm [ES DI] [DX SI] [CX BX] modify [CX SI DI ES]; + + char far* radstrcpy(void far* dest,const void far* source); + #pragma aux radstrcpy = "cld" "push ds" "mov ds,dx" "and esi,0xffff" "and edi,0xffff" "mov dx,di" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "pop ds" parm [ES DI] [DX SI] modify [AX DX DI SI ES] value [es dx]; + + char far* radstpcpy(void far* dest,const void far* source); + #pragma aux radstpcpy = "cld" "push ds" "mov ds,dx" "and esi,0xffff" "and edi,0xffff" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "dec di" "pop ds" parm [ES DI] [DX SI] modify [DI SI ES] value [es di]; + + u32 radstrlen(const void far* dest); + #pragma aux radstrlen = "cld" "and edi,0xffff" "mov ecx,0xffffffff" "xor eax,eax" 0x67 "repne scasb" "not ecx" "dec ecx" "movzx eax,cx" "shr ecx,16" parm [ES DI] modify [AX CX DI ES] value [CX AX]; + + char far* radstrcat(void far* dest,const void far* source); + #pragma aux radstrcat = "cld" "and edi,0xffff" "mov ecx,0xffffffff" "and esi,0xffff" "push ds" "mov ds,dx" "mov dx,di" "xor eax,eax" 0x67 "repne scasb" "dec edi" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "pop ds" \ + parm [ES DI] [DX SI] modify [AX CX DI SI ES] value [es dx]; + + char far* radstrchr(const void far* dest,char chr); + #pragma aux radstrchr = "cld" "lp:" 0x26 "lodsb" "cmp al,dl" "je fnd" "cmp al,0" "jnz lp" "xor ax,ax" "mov es,ax" "mov si,1" "fnd:" "dec si" parm [ES SI] [DL] modify [AX SI ES] value [es si]; + + s8 radstricmp(const void far* s1,const void far* s2); + #pragma aux radstricmp = "and edi,0xffff" "push ds" "mov ds,dx" "and esi,0xffff" "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" \ + "cmp ah,'a'" "jb c2" "cmp ah,'z'" "ja c2" "sub ah,32" "c2:" "cmp al,ah" "jne set" "cmp al,0" "je set" \ + "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" "pop ds" \ + parm [ES DI] [DX SI] modify [AX DI SI]; + + u32 radstru32(const void far* dest); + #pragma aux radstru32 = "cld" "xor ecx,ecx" "xor ebx,ebx" "xor edi,edi" 0x26 "lodsb" "cmp al,45" "jne skip2" "mov edi,1" "jmp skip" "lp:" "mov eax,10" "mul ecx" "lea ecx,[eax+ebx]" \ + "skip:" 0x26 "lodsb" "skip2:" "cmp al,0x39" "ja dne" "cmp al,0x30" "jb dne" "mov bl,al" "sub bl,0x30" "jmp lp" "dne:" "test edi,1" "jz pos" "neg ecx" "pos:" \ + "movzx eax,cx" "shr ecx,16" parm [ES SI] modify [AX BX DX DI SI] value [cx ax]; + + u32 mult64anddiv(u32 m1,u32 m2,u32 d); + #pragma aux mult64anddiv = "shl ecx,16" "mov cx,ax" "shrd eax,edx,16" "mov ax,si" "mul ecx" "shl edi,16" "mov di,bx" "div edi" "shld edx,eax,16" "and edx,0xffff" "and eax,0xffff" parm [cx ax] [dx si] [di bx] \ + modify [ax bx cx dx si di] value [dx ax]; + + #endif + +#endif + +RADDEFEND + +#define u32neg1 ((u32)(s32)-1) +#define RAD_align(var) var; u8 junk##var[4-(sizeof(var)&3)]; +#define RAD_align_after(var) u8 junk##var[4-(sizeof(var)&3)]={0}; +#define RAD_align_init(var,val) var=val; u8 junk##var[4-(sizeof(var)&3)]={0}; +#define RAD_align_array(var,num) var[num]; u8 junk##var[4-(sizeof(var)&3)]; +#define RAD_align_string(var,str) char var[]=str; u8 junk##var[4-(sizeof(var)&3)]={0}; + +RADEXPFUNC void PTR4* RADEXPLINK radmalloc(u32 numbytes); +RADEXPFUNC void RADEXPLINK radfree(void PTR4* ptr); + +#ifdef __WATCOMC__ + + char bkbhit(); + #pragma aux bkbhit = "mov ah,1" "int 0x16" "lahf" "shr eax,14" "and eax,1" "xor al,1" ; + + char bgetch(); + #pragma aux bgetch = "xor ah,ah" "int 0x16" "test al,0xff" "jnz done" "mov al,ah" "or al,0x80" "done:" modify [AX]; + + void BreakPoint(); + #pragma aux BreakPoint = "int 3"; + + u8 radinp(u16 p); + #pragma aux radinp = "in al,dx" parm [DX]; + + u8 radtoupper(u8 p); + #pragma aux radtoupper = "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" parm [al] value [al]; + + void radoutp(u16 p,u8 v); + #pragma aux radoutp = "out dx,al" parm [DX] [AL]; + +#endif + +// for multi-processor machines + +#ifdef __RADNT__ + #define LockedIncrement(var) _asm { lock inc [var] } + #define LockedDecrement(var) _asm { lock dec [var] } +#else + #define LockedIncrement(var) _asm { inc [var] } + #define LockedDecrement(var) _asm { dec [var] } +#endif + +#endif + +#endif + diff --git a/3dc/win95/SCANDRAW.ASM b/3dc/win95/SCANDRAW.ASM new file mode 100644 index 0000000..aca3c4b --- /dev/null +++ b/3dc/win95/SCANDRAW.ASM @@ -0,0 +1,2096 @@ +;.586 +;.8087 +; +; Assembly scandraws - designed for Pentiums/Pentium Pros but should work ok +; on 486s and strange hybrid processors. +; +; (C) Kevin Lea 12:03:17 96/12/05 +; +; Please excuse the mess, I haven't tidied up yet. Only the inner loops are +; well coded, since these take far more runtime than initialisation routines. +; + + +SOURCE_SBITSV EQU 16 +SOURCE_SBITSU EQU 7 + +_DATA SEGMENT DWORD PUBLIC 'DATA' + + EXTRN _SCASM_Lighting:DWORD + EXTRN _SCASM_Destination:DWORD + EXTRN _SCASM_Bitmap:DWORD + EXTRN _SCASM_StartU:DWORD + EXTRN _SCASM_StartV:DWORD + EXTRN _SCASM_StartI:DWORD + EXTRN _SCASM_DeltaU:DWORD + EXTRN _SCASM_DeltaV:DWORD + EXTRN _SCASM_DeltaI:DWORD + EXTRN _SCASM_ScanLength:DWORD + EXTRN _SCASM_ShadingTableSize:DWORD + EXTRN _SCASM_TextureDeltaScan:DWORD +; EXTRN _TLT:BYTE PTR + +if 0 + EXTRN _sine:DWORD ; + EXTRN _cosine:DWORD ; these 2 in 3D engine already + EXTRN _MTRB_Bitmap:DWORD + EXTRN _MTRB_Destination:DWORD + EXTRN _MTRB_ScanOffset:DWORD + EXTRN _MTRB_Angle:DWORD; + EXTRN _MTRB_InvScale:DWORD; + EXTRN _MTRB_ScreenHeight:DWORD; equ 48 + EXTRN _MTRB_ScreenWidth:DWORD; equ (49*2+1) + EXTRN _MTRB_ScreenCentreX:DWORD; equ (MTRB_ScreenWidth/2+1) + EXTRN _MTRB_ScreenCentreY:DWORD; equ MTRB_ScreenHeight + EXTRN _MTRB_CentreU:DWORD + EXTRN _MTRB_CentreV:DWORD +endif + + align + + + FixedScale dd 65536.0 + FixedScale8 dd 8192.0 ; 2^16 / 8 + One dd 1.0 + FloatTemp dd ? + FPUCW word ? + OldFPUCW word ? + + DeltaUFrac dd ? + DeltaVFrac dd ? + DeltaIFrac dd ? + Wholesections dd ? + PixelsRemaining dd ? + UVintVfracStepVCarry dd ? + UVintVfracStepVNoCarry dd ? + UVintVfracStep equ UVintVfracStepVNoCarry + IintWithCarry dd ? + IintNoCarry dd ? + IintStep equ IintNoCarry + + StackStore dd ? + + ShadeTable equ _TextureLightingTable + + + + aspectAdjust dd (6 SHL 16) / 5 + startingU dd 0 + startingV dd 0 + dUCol dd 0 + dVCol dd 0 + dURow dd 0 + dVRow dd 0 + rowCount dd 0 + + + + + +_DATA ENDS + +_TEXT SEGMENT BYTE PUBLIC 'CODE' + ASSUME cs:_TEXT, ds:_DATA + +.586 + +if 0 +align +PUBLIC _ScanDraw_GouraudScan +PUBLIC ScanDraw_GouraudScan_ +ScanDraw_GouraudScan_: +_ScanDraw_GouraudScan: + +; calculate horizontal deltas + pushad + ; mov [StackStore],esp + + mov eax,_SCASM_ScanLength + mov ebp,eax + + and eax,7 + shr ebp,3 + + mov [PixelsRemaining],eax + mov [Wholesections],ebp ; store widths + + + ; setup initial coordinates + mov ebx,_SCASM_DeltaI ; get i 16.16 step + mov eax,ebx ; copy it + sar eax,16 ; get i int step + shl ebx,16 ; get i frac step + imul eax,_SCASM_ShadingTableSize + mov IintNoCarry,eax ; save whole step in non-i-carry slot + add eax,_SCASM_ShadingTableSize ; calculate whole step + i carry + mov IintWithCarry,eax ; save in i-carry slot + + mov esi,_SCASM_StartI + mov edx,esi + sar esi,16 + shl edx,16 + imul esi,_SCASM_ShadingTableSize + add esi,_SCASM_Lighting + + xor eax,eax + mov edi,_SCASM_Destination + + test ebp,ebp + + jz GS_EndPixels +if 1 +GS_ScanLoop: + ; 8 pixel span code + ; edi = dest dib bits at current pixel + ; esi = lighting pointer + ; edx = i fraction 0.32 + ; ebp = carry scratch + + +; mov al,[esi] +; add edx,DeltaIFrac +; sbb ebp,ebp +; add esi,[4*ebp + IintStep] +; mov [edi],al + + mov al,[esi] ;get colour to draw + + add edx,ebx ;increase intensity + sbb ebp,ebp ;check for overflow + + add esi,[4*ebp + IintStep] ;add to esi required change + add edx,ebx ;increase intensity + + sbb ebp,ebp ;check for overflow + mov [edi+0],al ;draw out pixel + + mov al,[esi] + + add esi,[4*ebp + IintStep] + add edx,ebx + + sbb ebp,ebp + mov [edi+1],al + + mov al,[esi] + + add esi,[4*ebp + IintStep] + add edx,ebx + + sbb ebp,ebp + mov [edi+2],al + + mov al,[esi] + + add esi,[4*ebp + IintStep] + add edx,ebx + + sbb ebp,ebp + mov [edi+3],al + + mov al,[esi] + + add esi,[4*ebp + IintStep] + add edx,ebx + + sbb ebp,ebp + mov [edi+4],al + + mov al,[esi] + + add esi,[4*ebp + IintStep] + add edx,ebx + + sbb ebp,ebp + mov [edi+5],al + + mov al,[esi] + + add esi,[4*ebp + IintStep] + add edx,ebx + + sbb ebp,ebp + mov [edi+6],al + + mov al,[esi] + + add esi,[4*ebp + IintStep] + mov [edi+7],al + + + lea edi,[edi+8] + dec Wholesections ; decrement span count + + jnz GS_ScanLoop ; loop back +endif + + mov eax,[PixelsRemaining] + test eax,eax + jz GS_finish +GS_EndPixels: + + mov al,[esi] ; get texture pixel + + lea edi,[edi+1] + + add edx,ebx + sbb ebp,ebp + mov [edi-1],al + + add esi,[4*ebp + IintStep] + dec [PixelsRemaining] + + jnz GS_EndPixels +GS_finish: +; mov esp, [StackStore] + popad + ret +endif + +if 1 +align +PUBLIC _ScanDraw_GouraudScan +PUBLIC ScanDraw_GouraudScan_ +ScanDraw_GouraudScan_: +_ScanDraw_GouraudScan: + +; calculate horizontal deltas + pushad + mov [StackStore],esp + + mov eax,_SCASM_ScanLength + mov ecx,eax + + ; and ecx,7 + shr eax,3 + + mov [PixelsRemaining],ecx + mov [Wholesections],eax ; store widths + + + ; setup initial coordinates + mov esp,_SCASM_DeltaI ; get i 16.16 step +; sar esp,8 ; get i frac step + + mov ebx,_SCASM_StartI +; sar ebx,8 + mov edx,ebx + sar edx,8 + and edx,0xff00h + + mov esi,_SCASM_Lighting + + mov edi,_SCASM_Destination + add edi,ecx + ; test eax,eax + neg ecx + sub eax,eax + jz GS_EndPixels +if 1 + mov ecx,eax +GS_ScanLoop: + + + mov al,[esi+edx] + mov edx,ebx + + add ebx,esp + and edx,0xff00h + + mov [edi+0],al + nop + + lea edi,[edi+8] + dec ecx ; decrement span count + + jnz GS_ScanLoop ; loop back +endif + + mov ecx,[PixelsRemaining] + test ecx,ecx + jz GS_finish +GS_EndPixels: + + + + mov al,[esi+edx] + mov edx,ebx + + sar edx,8 + add ebx,esp + + and edx,0xff00h + mov [edi+ecx],al + + inc ecx + jnz GS_EndPixels +GS_finish: + mov esp, [StackStore] + popad + ret +endif + +align +; Drawing a 2D polygon which has DeltaV=0 and is transparent +PUBLIC _ScanDraw2D_VAlignedTransparent +PUBLIC ScanDraw2D_VAlignedTransparent_ +_ScanDraw2D_VAlignedTransparent: +ScanDraw2D_VAlignedTransparent_: + + pushad + mov [StackStore],esp + mov edx,_SCASM_ScanLength + + mov esi,_SCASM_StartU ; get u 16.16 fixedpoint coordinate + mov esp,esi ; copy it + sar esi,16 ; get integer part + shl esp,16 ; get fractional part + + mov eax,_SCASM_StartV ; get v 16.16 fixedpoint coordinate + sar eax,16 ; get integer part + imul eax,_SCASM_TextureDeltaScan ; calc texture scanline address + add esi,eax ; calc texture offset + add esi,_SCASM_Bitmap ; calc address + + mov edi,_SCASM_Destination + mov ebx,_SCASM_DeltaU ; get u 16.16 step + mov ecx,ebx ; copy it + sar ebx,16 ; get u int step + shl ecx,16 ; get u frac step + + ; ebx u int delta + ; ecx u frac delta + ; esp u frac total + ; edi dest + ; esi source + ; edx pixels to draw +VAT_ScanLoop: + mov al,[esi] ; get texture pixel 0 + add esp,ecx + + adc esi,ebx + inc edi + + test al,al + jz VAT_SkipPixel + + mov [edi-1],al + VAT_SkipPixel: + + dec edx ; decrement span count + jnz VAT_ScanLoop ; loop back + + mov esp, [StackStore] + popad + ret + +; Drawing a 2D polygon which has DeltaV=0 and is opaque +align +PUBLIC ScanDraw2D_VAlignedOpaque_ +PUBLIC _ScanDraw2D_VAlignedOpaque +ScanDraw2D_VAlignedOpaque_: +_ScanDraw2D_VAlignedOpaque: + + pushad + mov [StackStore],esp + mov edx,_SCASM_ScanLength + + mov esi,_SCASM_StartU ; get u 16.16 fixedpoint coordinate + mov esp,esi ; copy it + sar esi,16 ; get integer part + shl esp,16 ; get fractional part + + mov eax,_SCASM_StartV ; get v 16.16 fixedpoint coordinate + sar eax,16 ; get integer part + imul eax,_SCASM_TextureDeltaScan ; calc texture scanline address + add esi,eax ; calc texture offset + add esi,_SCASM_Bitmap ; calc address + + mov edi,_SCASM_Destination + + mov ebx,_SCASM_DeltaU ; get u 16.16 step + mov ecx,ebx ; copy it + sar ebx,16 ; get u int step + shl ecx,16 ; get u frac step + + ; ebx u int delta + ; ecx u frac delta + ; esp u frac total + ; edi dest + ; esi source + ; edx pixels to draw +VAO_ScanLoop: + mov al,[esi] ; get texture pixel 0 + add esp,ecx + + adc esi,ebx + dec edx ; decrement span count + + mov [edi],al + lea edi,[edi+1] + + jnz VAO_ScanLoop ; loop back + + mov esp, [StackStore] + popad + ret + + +; +; 2d case with shading +; +; mov eax,_SCASM_DeltaU + ; mov bl,ah +; mov eax,_SCASM_DeltaV + ; mov cl,ah + +if 0 +align +PUBLIC ScanDraw2D_Gouraud_ +PUBLIC _ScanDraw2D_Gouraud +ScanDraw2D_Gouraud_: +_ScanDraw2D_Gouraud: + +; calculate horizontal deltas + pushad + + mov [StackStore],esp + mov eax,_SCASM_ScanLength + + mov ebp,eax + ; and eax,7 + + shr ebp,3 + mov [PixelsRemaining],eax + + mov [Wholesections],ebp ; store widths + mov eax,_SCASM_DeltaV ; C1 1 ; get v 16.16 step + + mov edx,_SCASM_DeltaU ; C2 1 ; get u 16.16 step + mov ebx,eax ; C1 2 ; copy v 16.16 step + + sar eax,16 ; C1 3 ; get v int step + mov ecx,edx ; C2 2 ; copy u 16.16 step + + shl ebx,16 ; C1 4 ; get v frac step + mov esi,_SCASM_DeltaI ; C3 1 ; get i 16.16 step + + sar edx,16 ; C2 3 ; get u int step + mov esp,esi ; C3 2 ; copy i 16.16 step + + shl ecx,16 ; C2 4 ; get u frac step + mov DeltaVFrac,ebx ; C1 5 ; store it + + imul eax,_SCASM_TextureDeltaScan ; C1 6 ; calculate texture step for v int step + + sar esp,16-8 ; C3 3 ; get i int step + mov DeltaUFrac,ecx ; C2 5 ; store it + + sar esi,8 ; C3 4 ; get i frac step + add eax,edx ; C1+C2 1 ; calculate uint + vint step + + mov DeltaIFrac,esi ; C3 5 ; store it + mov UVintVfracStepVNoCarry,eax ; C1+C2 2 ; save whole step in non-v-carry slot + + and esp,0xffffff00h ; C3 6 + add eax,_SCASM_TextureDeltaScan ; C1+C2 3 ; calculate whole step + v carry + + mov IintNoCarry,esp ; C3 7 ; save whole step in non-i-carry slot + mov edi,_SCASM_Destination + + mov UVintVfracStepVCarry,eax ; C1+C2 4 ; save in v-carry slot + add esp,256 ; C3 8 ; calculate whole step + i carry + + mov IintWithCarry,esp ; C3 9 ; save in i-carry slot + mov esp,_SCASM_StartI ; C4 1 + + mov edx,esp ; C4 2 + mov esi,_SCASM_StartU ; C5 1 ; get u 16.16 fixedpoint coordinate + + sar esp,16-8 ; C4 3 + mov ebx,esi ; C5 2 ; copy it + + sar edx,8 ; C4 4 + mov ecx,_SCASM_StartV ; C6 1 ; get v 16.16 fixedpoint coordinate + + sar esi,16 ; C5 3 ; get integer part + mov eax,[edi] ; preread destination + + shl ebx,16 ; C5 4 ; get fractional part + mov eax,ecx ; C6 2 ; copy it + + sar eax,16 ; C6 3 ; get integer part + and esp,0xffffff00h ; C4 5 + + shl ecx,16 ; C6 4 ; get fractional part shift [tears removal] + add esp,_SCASM_Lighting ; C4 6 + + imul eax,_SCASM_TextureDeltaScan ; C6 5 ; calc texture scanline address + + + add esi,eax ; C7 1 ; calc texture offset + xor eax,eax + + add esi,_SCASM_Bitmap ; C7 2 ; calc address + test ebp,ebp + + + sar ebx,16 + sar ecx,16 + + mov eax,_SCASM_DeltaU + mov bl,ah + mov eax,_SCASM_DeltaV + mov cl,ah + + mov esp,[PixelsRemaining] + add edi,esp + neg esp +; mov eax,edx +; add ch,cl + + + jmp G3D_EndPixels + jz G3D_EndPixels +if 1 +G3D_ScanLoop: + ; 8 pixel span code + ; edi = dest dib bits at current pixel + ; esi = texture pointer at current u,v + ; esp = lighting pointer + ; ebx = u fraction 0.32 + ; ecx = v fraction 0.32 + ; edx = i fraction 0.32 + ; ebp = carry scratch + +; mov al,[edi] ; preread the destination cache line + + mov al,[esi] ; get texture pixel 0 + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + add ebx,DeltaUFrac + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + mov [edi],al ; store pixel 0 + + add ebx,DeltaUFrac + mov al,[esi] ; get texture pixel 1 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + mov [edi+1],al ; store pixel 1 + + add ebx,DeltaUFrac + mov al,[esi] ; get texture pixel 2 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + mov [edi+2],al ; store pixel 2 + + add ebx,DeltaUFrac + mov al,[esi] ; get texture pixel 3 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + mov [edi+3],al ; store pixel 3 + + add ebx,DeltaUFrac + mov al,[esi] ; get texture pixel 4 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + mov [edi+4],al ; store pixel 4 + + add ebx,DeltaUFrac + mov al,[esi] ; get texture pixel 5 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + mov [edi+5],al ; store pixel 5 + + add ebx,DeltaUFrac + mov al,[esi] ; get texture pixel 6 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + mov [edi+6],al ; store pixel 6 + + add ebx,DeltaUFrac + mov al,[esi] ; get texture pixel 7 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] + dec Wholesections ; decrement span count + + mov [edi+7],al ; store pixel 7 + lea edi,[edi+8] + + jnz G3D_ScanLoop ; loop back +endif + + mov eax,[PixelsRemaining] + test eax,eax + jz G3D_finish +G3D_EndPixels: + + add ch,cl + mov eax,edx + + sbb ebp,ebp ; get -1 if carry + mov al,[esi] + + inc esp + add bh,bl + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + mov al,[eax+_TLT] + test esp,esp + + mov [edi+esp],al + jnz G3D_EndPixels +G3D_finish: + mov esp, [StackStore] + popad + ret + +endif + + +; +; +; NEW CODE +; +; + +if 1 +align +PUBLIC ScanDraw2D_Gouraud_ +PUBLIC _ScanDraw2D_Gouraud +ScanDraw2D_Gouraud_: +_ScanDraw2D_Gouraud: + +; calculate horizontal deltas + pushad + + mov [StackStore],esp + mov eax,_SCASM_ScanLength + + mov ebp,eax + and eax,7 + + shr ebp,3 + mov [PixelsRemaining],eax + + mov [Wholesections],ebp ; store widths + mov eax,_SCASM_DeltaV ; C1 1 ; get v 16.16 step + + mov edx,_SCASM_DeltaU ; C2 1 ; get u 16.16 step + mov ebx,eax ; C1 2 ; copy v 16.16 step + + sar eax,16 ; C1 3 ; get v int step + mov ecx,edx ; C2 2 ; copy u 16.16 step + + shl ebx,16 ; C1 4 ; get v frac step + mov esi,_SCASM_DeltaI ; C3 1 ; get i 16.16 step + + sar edx,16 ; C2 3 ; get u int step + mov esp,esi ; C3 2 ; copy i 16.16 step + + shl ecx,16 ; C2 4 ; get u frac step + mov DeltaVFrac,ebx ; C1 5 ; store it + + imul eax,_SCASM_TextureDeltaScan ; C1 6 ; calculate texture step for v int step + + sar esp,16-8 ; C3 3 ; get i int step + mov DeltaUFrac,ecx ; C2 5 ; store it + + shl esi,16 ; C3 4 ; get i frac step + add eax,edx ; C1+C2 1 ; calculate uint + vint step + + mov DeltaIFrac,esi ; C3 5 ; store it + mov UVintVfracStepVNoCarry,eax ; C1+C2 2 ; save whole step in non-v-carry slot + + and esp,0xffffff00h ; C3 6 + add eax,_SCASM_TextureDeltaScan ; C1+C2 3 ; calculate whole step + v carry + + mov IintNoCarry,esp ; C3 7 ; save whole step in non-i-carry slot + mov edi,_SCASM_Destination + + mov UVintVfracStepVCarry,eax ; C1+C2 4 ; save in v-carry slot + add esp,256 ; C3 8 ; calculate whole step + i carry + + mov IintWithCarry,esp ; C3 9 ; save in i-carry slot + mov esp,_SCASM_StartI ; C4 1 + + mov edx,esp ; C4 2 + mov esi,_SCASM_StartU ; C5 1 ; get u 16.16 fixedpoint coordinate + + sar esp,16-8 ; C4 3 + mov ebx,esi ; C5 2 ; copy it + + shl edx,16 ; C4 4 + mov ecx,_SCASM_StartV ; C6 1 ; get v 16.16 fixedpoint coordinate + + sar esi,16 ; C5 3 ; get integer part + mov eax,[edi] ; preread destination + + ; shl ebx,16 ; C5 4 ; get fractional part + and ebx,0xffffh + mov eax,ecx ; C6 2 ; copy it + + sar eax,16 ; C6 3 ; get integer part + and esp,0xffffff00h ; C4 5 + +; shl ecx,16 ; C6 4 ; get fractional part shift [tears removal] + and ecx,0xffffh + add esp,_SCASM_Lighting ; C4 6 + + imul eax,_SCASM_TextureDeltaScan ; C6 5 ; calc texture scanline address + + + add esi,eax ; C7 1 ; calc texture offset + mov eax,_SCASM_DeltaU + + mov bl,ah + mov eax,_SCASM_DeltaV + + mov cl,ah + xor eax,eax + + add esi,_SCASM_Bitmap ; C7 2 ; calc address + test ebp,ebp + + ; jmp G3D_EndPixels + jz G3D_EndPixels +if 1 +G3D_ScanLoop: + ; 8 pixel span code + ; edi = dest dib bits at current pixel + ; esi = texture pointer at current u,v + ; esp = lighting pointer + ; ebx = u fraction 0.32 + ; ecx = v fraction 0.32 + ; edx = i fraction 0.32 + ; ebp = carry scratch + +; mov al,[edi] ; preread the destination cache line + + mov al,[esi] ; get texture pixel 0 + ; add ecx,DeltaVFrac;test to remove tears + add ch,cl + + sbb ebp,ebp ; get -1 if carry +; add ebx,DeltaUFrac + add bh,bl + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] + ; add ecx,DeltaVFrac;test to remove tears + add ch,cl + + sbb ebp,ebp ; get -1 if carry + mov [edi],al ; store pixel 0 + +; add ebx,DeltaUFrac + add bh,bl + mov al,[esi] ; get texture pixel 1 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] +; add ecx,DeltaVFrac;test to remove tears + add ch,cl + + sbb ebp,ebp ; get -1 if carry + mov [edi+1],al ; store pixel 1 + + ; add ebx,DeltaUFrac + add bh,bl + mov al,[esi] ; get texture pixel 2 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] + ; add ecx,DeltaVFrac;test to remove tears + add ch,cl + + sbb ebp,ebp ; get -1 if carry + mov [edi+2],al ; store pixel 2 + +; add ebx,DeltaUFrac + add bh,bl + mov al,[esi] ; get texture pixel 3 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] +; add ecx,DeltaVFrac;test to remove tears + add ch,cl + + sbb ebp,ebp ; get -1 if carry + mov [edi+3],al ; store pixel 3 + +; add ebx,DeltaUFrac + add bh,bl + mov al,[esi] ; get texture pixel 4 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] + ; add ecx,DeltaVFrac;test to remove tears + add ch,cl + + sbb ebp,ebp ; get -1 if carry + mov [edi+4],al ; store pixel 4 + +; add ebx,DeltaUFrac + add bh,bl + mov al,[esi] ; get texture pixel 5 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] + ; add ecx,DeltaVFrac;test to remove tears + add ch,cl + + sbb ebp,ebp ; get -1 if carry + mov [edi+5],al ; store pixel 5 + +; add ebx,DeltaUFrac + add bh,bl + mov al,[esi] ; get texture pixel 6 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] +; add ecx,DeltaVFrac;test to remove tears + add ch,cl + + sbb ebp,ebp ; get -1 if carry + mov [edi+6],al ; store pixel 6 + + ; add ebx,DeltaUFrac + add bh,bl + mov al,[esi] ; get texture pixel 7 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + add esp,[4*ebp + IintStep] + dec Wholesections ; decrement span count + + mov [edi+7],al ; store pixel 7 + lea edi,[edi+8] + + jnz G3D_ScanLoop ; loop back +endif + + mov eax,[PixelsRemaining] + test eax,eax + jz G3D_finish +G3D_EndPixels: + + mov eax,[esi] + add ch,cl +; add ecx,DeltaVFrac + + sbb ebp,ebp ; get -1 if carry + and eax,0xffh + + add bh,bl +; add ebx,DeltaUFrac + lea edi,[edi+1] + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov al,[esp+eax] + + mov [edi-1],al + mov eax,[PixelsRemaining] + + add esp,[4*ebp + IintStep] + dec eax +; dec [PixelsRemaining] + + mov [PixelsRemaining],eax + jnz G3D_EndPixels +G3D_finish: + mov esp, [StackStore] + popad + ret +endif +; +; +; NEW CODE +; +; + +align +PUBLIC ScanDraw2D_GouraudTransparent_ +PUBLIC _ScanDraw2D_GouraudTransparent +ScanDraw2D_GouraudTransparent_: +_ScanDraw2D_GouraudTransparent: + +; calculate horizontal deltas + pushad + mov [StackStore],esp + + mov eax,_SCASM_ScanLength + mov [PixelsRemaining],eax + + mov eax,_SCASM_DeltaV ; get v 16.16 step + mov ebx,eax ; copy it + sar eax,16 ; get v int step + shl ebx,16 ; get v frac step + mov DeltaVFrac,ebx ; store it + + imul eax,_SCASM_TextureDeltaScan ; calculate texture step for v int step + + mov ebx,_SCASM_DeltaU ; get u 16.16 step + mov ecx,ebx ; copy it + sar ebx,16 ; get u int step + shl ecx,16 ; get u frac step + + mov DeltaUFrac,ecx ; store it + add eax,ebx ; calculate uint + vint step + mov UVintVfracStepVNoCarry,eax; save whole step in non-v-carry slot + add eax,_SCASM_TextureDeltaScan ; calculate whole step + v carry + mov UVintVfracStepVCarry,eax ; save in v-carry slot + + ; setup initial coordinates + mov edx,_SCASM_DeltaI ; get i 16.16 step + mov eax,edx ; copy it + sar eax,16 ; get i int step + shl edx,16 ; get i frac step + mov DeltaIFrac,edx ; store it + imul eax,_SCASM_ShadingTableSize + mov IintNoCarry,eax ; save whole step in non-i-carry slot + add eax,_SCASM_ShadingTableSize ; calculate whole step + i carry + mov IintWithCarry,eax ; save in i-carry slot + + mov esp,_SCASM_StartI + mov edx,esp + sar esp,16 + shl edx,16 + imul esp,_SCASM_ShadingTableSize + add esp,_SCASM_Lighting + + mov esi,_SCASM_StartU ; get u 16.16 fixedpoint coordinate + mov ebx,esi ; copy it + sar esi,16 ; get integer part + shl ebx,16 ; get fractional part + + mov ecx,_SCASM_StartV ; get v 16.16 fixedpoint coordinate + mov eax,ecx ; copy it + sar eax,16 ; get integer part + shl ecx,16 ; get fractional part shift [tears removal] + imul eax,_SCASM_TextureDeltaScan ; calc texture scanline address + add esi,eax ; calc texture offset + add esi,_SCASM_Bitmap ; calc address + + +; mov eax,_SCASM_DeltaU + ; mov bl,ah +; mov eax,_SCASM_DeltaV + ; mov cl,ah + + xor eax,eax + mov edi,_SCASM_Destination + +G2DT_EndPixels: + + mov al,[esi] ; get texture pixel + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + test eax,eax + + jz G2DT_SkipPixel + + mov al,[esp+eax] ; store pixel 0 + mov [edi],al + + + G2DT_SkipPixel: + + lea edi,[edi+1] + add ebx,DeltaUFrac + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + add esp,[4*ebp + IintStep] + + dec [PixelsRemaining] + jnz G2DT_EndPixels + + mov esp, [StackStore] + popad + ret + + + + + + + +align +PUBLIC ScanDraw2D_Opaque_ +PUBLIC _ScanDraw2D_Opaque +ScanDraw2D_Opaque_: +_ScanDraw2D_Opaque: + +; calculate horizontal deltas + pushad + mov [StackStore],esp + + mov eax,_SCASM_ScanLength + mov ebp,eax + + and eax,7 + shr ebp,3 + + mov [PixelsRemaining],eax + mov [Wholesections],ebp ; store widths + + + mov eax,_SCASM_DeltaV ; get v 16.16 step + mov ebx,eax ; copy it + sar eax,16 ; get v int step + shl ebx,16 ; get v frac step + mov DeltaVFrac,ebx ; store it + ;shl eax,7 + imul eax,_SCASM_TextureDeltaScan ; calculate texture step for v int step + + mov ebx,_SCASM_DeltaU ; get u 16.16 step + mov ecx,ebx ; copy it + sar ebx,16 ; get u int step + shl ecx,16 ; get u frac step + mov DeltaUFrac,ecx ; store it + add eax,ebx ; calculate uint + vint step + mov UVintVfracStepVNoCarry,eax; save whole step in non-v-carry slot + add eax,_SCASM_TextureDeltaScan ; calculate whole step + v carry + mov UVintVfracStepVCarry,eax ; save in v-carry slot + + ; setup initial coordinates + + mov esi,_SCASM_StartU ; get u 16.16 fixedpoint coordinate + mov ebx,esi ; copy it + sar esi,16 ; get integer part + shl ebx,16 ; get fractional part + + mov ecx,_SCASM_StartV ; get v 16.16 fixedpoint coordinate + mov edx,ecx ; copy it + sar edx,16 ; get integer part + shl ecx,16 ; get fractional part + ; shl edx,7 + imul edx,_SCASM_TextureDeltaScan ; calc texture scanline address + add esi,edx ; calc texture offset + add esi,_SCASM_Bitmap ; calc address + + mov edx,DeltaUFrac ; get register copy + mov esp,DeltaVFrac + mov edi,_SCASM_Destination + + test ebp,ebp + jz O2D_EndPixels + +if 1 +O2D_ScanLoop: + ; 8 pixel span code + ; edi = dest dib bits at current pixel + ; esi = texture pointer at current u,v + ; ebx = u fraction 0.32 + ; ecx = v fraction 0.32 + ; edx = u frac step + ; ebp = v carry scratch + +; mov al,[edi] ; preread the destination cache line + + mov al,[esi] ; get texture pixel 0 + + add ecx,esp ; increment v fraction + sbb ebp,ebp ; get -1 if carry + add ebx,edx ; increment u fraction + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add ecx,esp ; increment v fraction + + sbb ebp,ebp ; get -1 if carry + mov [edi+0],al ; store pixel 0 + + add ebx,edx ; increment u fraction + mov al,[esi] ; get texture pixel 1 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add ecx,esp ; increment v fraction + + sbb ebp,ebp ; get -1 if carry + mov [edi+1],al ; store pixel 1 + + add ebx,edx ; increment u fraction + mov al,[esi] ; get texture pixel 2 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add ecx,esp ; increment v fraction + + sbb ebp,ebp ; get -1 if carry + mov [edi+2],al ; store pixel 2 + + add ebx,edx ; increment u fraction + mov al,[esi] ; get texture pixel 3 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add ecx,esp ; increment v fraction + + sbb ebp,ebp ; get -1 if carry + mov [edi+3],al ; store pixel 3 + + add ebx,edx ; increment u fraction + mov al,[esi] ; get texture pixel 4 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add ecx,esp ; increment v fraction + + sbb ebp,ebp ; get -1 if carry + mov [edi+4],al ; store pixel 4 + + add ebx,edx ; increment u fraction + mov al,[esi] ; get texture pixel 5 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add ecx,esp ; increment v fraction + + sbb ebp,ebp ; get -1 if carry + mov [edi+5],al ; store pixel 5 + + add ebx,edx ; increment u fraction + mov al,[esi] ; get texture pixel 6 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add ecx,esp ; increment v fraction + + sbb ebp,ebp ; get -1 if carry + mov [edi+6],al ; store pixel 6 + + add ebx,edx ; increment u fraction + mov al,[esi] ; get texture pixel 7 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + + mov [edi+7],al ; store pixel 7 + + + add edi,8 ; increment to next span + dec Wholesections ; decrement span count + jnz O2D_ScanLoop ; loop back +endif + + mov eax,[PixelsRemaining] + test eax,eax + jz O2D_finish +O2D_EndPixels: + + mov al,[esi] ; get texture pixel + add ecx,esp ; increment v fraction + + sbb ebp,ebp ; get -1 if carry + add ebx,edx ; increment u fraction + + mov [edi],al ; store pixel + lea edi,[edi+1] + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + dec [PixelsRemaining] + + jnz O2D_EndPixels + + + +O2D_finish: + mov esp, [StackStore] + popad + ret + + +align +PUBLIC ScanDraw2D_Transparent_ +PUBLIC _ScanDraw2D_Transparent +ScanDraw2D_Transparent_: +_ScanDraw2D_Transparent: + +; calculate horizontal deltas + pushad + mov [StackStore],esp + + mov ebp,_SCASM_ScanLength + mov [PixelsRemaining],ebp + + mov eax,_SCASM_DeltaV ; get v 16.16 step + mov ebx,eax ; copy it + sar eax,16 ; get v int step + shl ebx,16 ; get v frac step + mov DeltaVFrac,ebx ; store it + ;shl eax,7 + imul eax,_SCASM_TextureDeltaScan ; calculate texture step for v int step + + mov ebx,_SCASM_DeltaU ; get u 16.16 step + mov ecx,ebx ; copy it + sar ebx,16 ; get u int step + shl ecx,16 ; get u frac step + mov DeltaUFrac,ecx ; store it + add eax,ebx ; calculate uint + vint step + mov UVintVfracStepVNoCarry,eax; save whole step in non-v-carry slot + add eax,_SCASM_TextureDeltaScan ; calculate whole step + v carry + mov UVintVfracStepVCarry,eax ; save in v-carry slot + + ; setup initial coordinates + + mov esi,_SCASM_StartU ; get u 16.16 fixedpoint coordinate + mov ebx,esi ; copy it + sar esi,16 ; get integer part + shl ebx,16 ; get fractional part + + mov ecx,_SCASM_StartV ; get v 16.16 fixedpoint coordinate + mov edx,ecx ; copy it + sar edx,16 ; get integer part + shl ecx,16 ; get fractional part + ; shl edx,7 + imul edx,_SCASM_TextureDeltaScan ; calc texture scanline address + add esi,edx ; calc texture offset + add esi,_SCASM_Bitmap ; calc address + + mov edx,DeltaUFrac ; get register copy + mov esp,DeltaVFrac + mov edi,_SCASM_Destination + +T2D_EndPixels: + + mov al,[esi] ; get texture pixel + add ecx,esp ; increment v fraction + + sbb ebp,ebp ; get -1 if carry + test al,al + + jz T2D_SkipPixel + + mov [edi],al ; store pixel + T2D_SkipPixel: + + lea edi,[edi+1] + add ebx,edx ; increment u fraction + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + dec [PixelsRemaining] + + jnz T2D_EndPixels + + mov esp, [StackStore] + popad + ret + +align +PUBLIC ScanDraw2D_TransparentLit_ +PUBLIC _ScanDraw2D_TransparentLit +ScanDraw2D_TransparentLit_: +_ScanDraw2D_TransparentLit: + +; calculate horizontal deltas + pushad + mov [StackStore],esp + + mov ebp,_SCASM_ScanLength + mov [PixelsRemaining],ebp + + mov esp,_SCASM_StartI + imul esp,_SCASM_ShadingTableSize + add esp,_SCASM_Lighting + + mov eax,_SCASM_DeltaV ; get v 16.16 step + mov ebx,eax ; copy it + sar eax,16 ; get v int step + shl ebx,16 ; get v frac step + mov DeltaVFrac,ebx ; store it + ;shl eax,7 + imul eax,_SCASM_TextureDeltaScan ; calculate texture step for v int step + + mov ebx,_SCASM_DeltaU ; get u 16.16 step + mov ecx,ebx ; copy it + sar ebx,16 ; get u int step + shl ecx,16 ; get u frac step + mov DeltaUFrac,ecx ; store it + add eax,ebx ; calculate uint + vint step + mov UVintVfracStepVNoCarry,eax; save whole step in non-v-carry slot + add eax,_SCASM_TextureDeltaScan ; calculate whole step + v carry + mov UVintVfracStepVCarry,eax ; save in v-carry slot + + ; setup initial coordinates + + mov esi,_SCASM_StartU ; get u 16.16 fixedpoint coordinate + mov ebx,esi ; copy it + sar esi,16 ; get integer part + shl ebx,16 ; get fractional part + + mov ecx,_SCASM_StartV ; get v 16.16 fixedpoint coordinate + mov edx,ecx ; copy it + sar edx,16 ; get integer part + shl ecx,16 ; get fractional part + ; shl edx,7 + imul edx,_SCASM_TextureDeltaScan ; calc texture scanline address + add esi,edx ; calc texture offset + add esi,_SCASM_Bitmap ; calc address + + mov edx,DeltaUFrac ; get register copy + ; mov esp,DeltaVFrac + mov edi,_SCASM_Destination + xor eax,eax + +TL2D_EndPixels: + + mov al,[esi] ; get texture pixel + add ecx,DeltaVFrac ; increment v fraction + + sbb ebp,ebp ; get -1 if carry + test al,al + + jz TL2D_SkipPixel + + mov al,[eax+esp] + mov [edi],al ; store pixel + TL2D_SkipPixel: + + lea edi,[edi+1] + add ebx,edx ; increment u fraction + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + dec [PixelsRemaining] + + jnz TL2D_EndPixels + + mov esp, [StackStore] + popad + ret + +if 0 +PUBLIC MotionTrackerRotateBlit_ +MotionTrackerRotateBlit_: + +; calculate horizontal deltas + pushad + mov [StackStore],esp + + + mov eax,_MTRB_Angle + mov eax,[_cosine + eax * 4] + shl eax,16 - 7 + imul [_MTRB_InvScale] + shrd eax,edx,16 + mov [dUCol],eax + + + mov eax,[_MTRB_Angle] + mov eax,[_sine + eax * 4] + shl eax,16 - 7 + imul [_MTRB_InvScale] + shrd eax,edx,16 + mov [dVCol],eax + mov esp,eax +; calculate vertical deltas + + mov eax,[dVCol] + neg eax + ; imul [aspectAdjust] + ; shrd eax,edx,16 + mov [dURow],eax + + mov eax,[dUCol] +; imul [aspectAdjust] +; shrd eax,edx,16 + mov [dVRow],eax + + mov eax,_MTRB_CentreU ; put CentreU&V in 16.16 for now + shl eax,16-7 + mov [startingU],eax + mov eax,_MTRB_CentreV + shl eax,16-7 + mov [startingV],eax + + +; move up by yOrg + + mov eax,[dUCol] + imul eax,_MTRB_ScreenCentreX + sub [startingU],eax + + mov eax,[dURow] + imul eax,_MTRB_ScreenCentreY + sub [startingU],eax + + mov eax,[dVCol] + imul eax,_MTRB_ScreenCentreX + sub [startingV],eax + + mov eax,[dVRow] + imul eax,_MTRB_ScreenCentreY + sub [startingV],eax + +; fixup end of row deltas + + mov eax,[dUCol] + imul eax,_MTRB_ScreenWidth + neg eax + add eax,[dURow] + mov [dURow],eax + + + mov eax,[dVCol] + imul eax,_MTRB_ScreenWidth + neg eax + add eax,[dVRow] + mov [dVRow],eax + + + + mov esi,[_MTRB_Bitmap] + mov edi,[_MTRB_Destination] + + mov ecx,[startingU] + mov edx,[startingV] + + mov ebx,_MTRB_ScreenHeight ; initialize row count + mov ah,bl +MTRB_RowLoop: + mov ebx,_MTRB_ScreenWidth ; initialize column count + +MTRB_ColLoop: + mov ebp,edx + shr ebp,32 - 7 + shld ebp,ecx,7 + + add edx,esp + add ecx,[dUCol] + + mov al,[esi+ebp] + test al,al + jz MTRB_SkipPixel + mov [edi],al + MTRB_SkipPixel: + + lea edi,[edi+1] + + dec ebx + + jnz MTRB_ColLoop + + add ecx,[dURow] + add edx,[dVRow] + add edi,[_MTRB_ScanOffset] + + dec ah + jnz MTRB_RowLoop + + + mov esp, [StackStore] + popad + ret + +PUBLIC MotionTrackerRotateBlit8_ +PUBLIC _MotionTrackerRotateBlit8 +MotionTrackerRotateBlit8_: +_MotionTrackerRotateBlit8: + +; calculate horizontal deltas + pushad + mov [StackStore],esp + + + mov eax,_MTRB_Angle + mov eax,[_cosine + eax * 4] + shl eax,16 - 8 + imul [_MTRB_InvScale] + shrd eax,edx,16 + mov [dUCol],eax + + + mov eax,[_MTRB_Angle] + mov eax,[_sine + eax * 4] + shl eax,16 - 8 + imul [_MTRB_InvScale] + shrd eax,edx,16 + mov [dVCol],eax + mov esp,eax +; calculate vertical deltas + + mov eax,[dVCol] + neg eax + ; imul [aspectAdjust] + ; shrd eax,edx,16 + mov [dURow],eax + + mov eax,[dUCol] +; imul [aspectAdjust] +; shrd eax,edx,16 + mov [dVRow],eax + + mov eax,_MTRB_CentreU ; put CentreU&V in 16.16 for now + shl eax,16-8 + mov [startingU],eax + mov eax,_MTRB_CentreV + shl eax,16-8 + mov [startingV],eax + + +; move up by yOrg + + mov eax,[dUCol] + imul eax,_MTRB_ScreenCentreX + sub [startingU],eax + + mov eax,[dURow] + imul eax,_MTRB_ScreenCentreY + sub [startingU],eax + + mov eax,[dVCol] + imul eax,_MTRB_ScreenCentreX + sub [startingV],eax + + mov eax,[dVRow] + imul eax,_MTRB_ScreenCentreY + sub [startingV],eax + +; fixup end of row deltas + + mov eax,[dUCol] + imul eax,_MTRB_ScreenWidth + neg eax + add eax,[dURow] + mov [dURow],eax + + + mov eax,[dVCol] + imul eax,_MTRB_ScreenWidth + neg eax + add eax,[dVRow] + mov [dVRow],eax + + + + mov esi,[_MTRB_Bitmap] + mov edi,[_MTRB_Destination] + + mov ecx,[startingU] + mov edx,[startingV] + + mov ebx,_MTRB_ScreenHeight ; initialize row count + mov ah,bl +MTRB_RowLoop8: + mov ebx,_MTRB_ScreenWidth ; initialize column count + +MTRB_ColLoop8: + mov ebp,edx + shr ebp,32 - 8 + shld ebp,ecx,8 + + add edx,esp + add ecx,[dUCol] + + mov al,[esi+ebp] + test al,al + jz MTRB_SkipPixel8 + mov [edi],al + MTRB_SkipPixel8: + + lea edi,[edi+1] + + dec ebx + + jnz MTRB_ColLoop8 + + add ecx,[dURow] + add edx,[dVRow] + add edi,[_MTRB_ScanOffset] + + dec ah + jnz MTRB_RowLoop8 + + + mov esp, [StackStore] + popad + ret +endif + + + + + + +; floating point test area +if 0 + +PUBLIC ScanDrawF3D_Gouraud_ +ScanDrawF3D_Gouraud_: + +; calculate horizontal deltas + + pushad + + ; put the FPU in 32 bit mode + ; @todo move this out of here! +; fstcw [OldFPUCW] ; store copy of CW + ; mov ax,OldFPUCW ; get it in ax +; and eax,NOT 1100000000y ; 24 bit precision +; mov [FPUCW],ax ; store it +; fldcw [FPUCW] ; load the FPU + finit + ; mov [StackStore],esp + + mov eax,_SCASM_ScanLength + mov ebp,eax + + and eax,7 + shr ebp,3 + + mov [PixelsRemaining],eax + mov [Wholesections],ebp ; store widths + +if 0 + ; setup initial coordinates + mov edx,_SCASM_DeltaI ; get i 16.16 step + mov eax,edx ; copy it + sar eax,16 ; get i int step + shl edx,16 ; get i frac step + mov DeltaIFrac,edx ; store it + imul eax,_SCASM_ShadingTableSize + mov IintNoCarry,eax ; save whole step in non-i-carry slot + add eax,_SCASM_ShadingTableSize ; calculate whole step + i carry + mov IintWithCarry,eax ; save in i-carry slot + + mov esp,_SCASM_StartI + mov edx,esp + sar esp,16 + shl edx,16 + imul esp,_SCASM_ShadingTableSize + add esp,_SCASM_Lighting +endif + ;****************************************************************************************** + mov ebx,_ScanDescPtr + + ; calculate ULeft and VLeft ; FPU Stack (ZL = ZLeft) + ; st0 st1 st2 st3 st4 st5 st6 st7 + fld DWORD PTR [ebx+4] ; V/ZL + fld DWORD PTR [ebx] ; U/ZL V/ZL + fld DWORD PTR [ebx+8] ; 1/ZL U/ZL V/ZL + fld1 ; 1 1/ZL U/ZL V/ZL + fdiv st,st(1) ; ZL 1/ZL U/ZL V/ZL + fld st ; ZL ZL 1/ZL U/ZL V/ZL + fmul st,st(4) ; VL ZL 1/ZL U/ZL V/ZL + fxch st(1) ; ZL VL 1/ZL U/ZL V/ZL + fmul st,st(3) ; UL VL 1/ZL U/ZL V/ZL + + fstp st(5) ; VL 1/ZL U/ZL V/ZL UL + fstp st(5) ; 1/ZL U/ZL V/ZL UL VL + + ; calculate right side OverZ terms ; st0 st1 st2 st3 st4 st5 st6 st7 + + fadd DWORD PTR [ebx+20] ; 1/ZR U/ZL V/ZL UL VL + fxch st(1) ; U/ZL 1/ZR V/ZL UL VL + fadd DWORD PTR [ebx+12] ; U/ZR 1/ZR V/ZL UL VL + fxch st(2) ; V/ZL 1/ZR U/ZR UL VL + fadd DWORD PTR [ebx+16] ; V/ZR 1/ZR U/ZR UL VL + + ; calculate right side coords ; st0 st1 st2 st3 st4 st5 st6 st7 + + fld1 ; 1 V/ZR 1/ZR U/ZR UL VL + ; @todo overlap this guy + fdiv st,st(2) ; ZR V/ZR 1/ZR U/ZR UL VL + fld st ; ZR ZR V/ZR 1/ZR U/ZR UL VL + fmul st,st(2) ; VR ZR V/ZR 1/ZR U/ZR UL VL + fxch st(1) ; ZR VR V/ZR 1/ZR U/ZR UL VL + fmul st,st(4) ; UR VR V/ZR 1/ZR U/ZR UL VL + ;****************************************************************************************** + xor eax,eax + mov edi,_SCASM_Destination + + test ebp,ebp + jz GF3D_EndPixels + +GF3D_ScanLoop: + ; at this point the FPU contains ; st0 st1 st2 st3 st4 st5 st6 st7 + ; UR VR V/ZR 1/ZR U/ZR UL VL + + ; convert left side coords + + fld st(5) ; UL UR VR V/ZR 1/ZR U/ZR UL VL + fmul [FixedScale] ; UL16 UR VR V/ZR 1/ZR U/ZR UL VL + fistp [_SCASM_StartU] ; UR VR V/ZR 1/ZR U/ZR UL VL + + fld st(6) ; VL UR VR V/ZR 1/ZR U/ZR UL VL + fmul [FixedScale] ; VL16 UR VR V/ZR 1/ZR U/ZR UL VL + fistp [_SCASM_StartV] ; UR VR V/ZR 1/ZR U/ZR UL VL + + ; calculate deltas ; st0 st1 st2 st3 st4 st5 st6 st7 + + fsubr st(5),st ; UR VR V/ZR 1/ZR U/ZR dU VL + fxch st(1) ; VR UR V/ZR 1/ZR U/ZR dU VL + fsubr st(6),st ; VR UR V/ZR 1/ZR U/ZR dU dV + fxch st(6) ; dV UR V/ZR 1/ZR U/ZR dU VR + + fmul [FixedScale8] ; dV8 UR V/ZR 1/ZR U/ZR dU VR + fistp [_SCASM_DeltaV] ; UR V/ZR 1/ZR U/ZR dU VR + + fxch st(4) ; dU V/ZR 1/ZR U/ZR UR VR + fmul [FixedScale8] ; dU8 V/ZR 1/ZR U/ZR UR VR + fistp [_SCASM_DeltaU] ; V/ZR 1/ZR U/ZR UR VR + + ; increment terms for next span ; st0 st1 st2 st3 st4 st5 st6 st7 + ; Right terms become Left terms---->; V/ZL 1/ZL U/ZL UL VL + + mov ebx,_ScanDescPtr + fadd DWORD PTR [ebx+16] ; V/ZR 1/ZL U/ZL UL VL + fxch st(1) ; 1/ZL V/ZR U/ZL UL VL + fadd DWORD PTR [ebx+20] ; 1/ZR V/ZR U/ZL UL VL + fxch st(2) ; U/ZL V/ZR 1/ZR UL VL + fadd DWORD PTR [ebx+12] ; U/ZR V/ZR 1/ZR UL VL + fxch st(2) ; 1/ZR V/ZR U/ZR UL VL + fxch st(1) ; V/ZR 1/ZR U/ZR UL VL + + ; calculate right side coords ; st0 st1 st2 st3 st4 st5 st6 st7 + + fld1 ; 1 V/ZR 1/ZR U/ZR UL VL + fdiv st,st(2) ; ZR V/ZR 1/ZR U/ZR UL VL + + ; set up affine registers + + ; setup delta values + + mov eax,_SCASM_DeltaV ; get v 16.16 step + mov ebx,eax ; copy it + sar eax,16 ; get v int step + shl ebx,16 ; get v frac step + mov DeltaVFrac,ebx ; store it + + imul eax,_SCASM_TextureDeltaScan ; calculate texture step for v int step + + mov ebx,_SCASM_DeltaU ; get u 16.16 step + mov ecx,ebx ; copy it + sar ebx,16 ; get u int step + shl ecx,16 ; get u frac step + + mov DeltaUFrac,ecx ; store it + add eax,ebx ; calculate uint + vint step + mov UVintVfracStepVNoCarry,eax; save whole step in non-v-carry slot + add eax,_SCASM_TextureDeltaScan ; calculate whole step + v carry + mov UVintVfracStepVCarry,eax ; save in v-carry slot + + + mov esi,_SCASM_StartU ; get u 16.16 fixedpoint coordinate + mov ebx,esi ; copy it + sar esi,16 ; get integer part + shl ebx,16 ; get fractional part + + mov ecx,_SCASM_StartV ; get v 16.16 fixedpoint coordinate + mov eax,ecx ; copy it + sar eax,16 ; get integer part + shl ecx,16 ; get fractional part shift [tears removal] + imul eax,_SCASM_TextureDeltaScan ; calc texture scanline address + add esi,eax ; calc texture offset + add esi,_SCASM_Bitmap ; calc address + + + ; 8 pixel span code + ; edi = dest dib bits at current pixel + ; esi = texture pointer at current u,v + ; esp = lighting pointer + ; ebx = u fraction 0.32 + ; ecx = v fraction 0.32 + ; edx = i fraction 0.32 + ; ebp = carry scratch + +; mov al,[edi] ; preread the destination cache line + + mov al,[esi] ; get texture pixel 0 + + add ecx,DeltaVFrac;test to remove tears + sbb ebp,ebp ; get -1 if carry + add ebx,DeltaUFrac + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + +; add edx,DeltaIFrac +; sbb ebp,ebp +; mov al,[esp+eax] +; add esp,[4*ebp + IintStep] + + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + mov [edi],al ; store pixel 0 + + add ebx,DeltaUFrac + mov al,[esi] ; get texture pixel 1 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + +; add edx,DeltaIFrac +; sbb ebp,ebp +; mov al,[esp+eax] +; add esp,[4*ebp + IintStep] + + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + mov [edi+1],al ; store pixel 1 + + add ebx,DeltaUFrac + mov al,[esi] ; get texture pixel 2 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + +; add edx,DeltaIFrac +; sbb ebp,ebp +; mov al,[esp+eax] +; add esp,[4*ebp + IintStep] + + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + mov [edi+2],al ; store pixel 2 + + add ebx,DeltaUFrac + mov al,[esi] ; get texture pixel 3 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + +; add edx,DeltaIFrac +; sbb ebp,ebp +; mov al,[esp+eax] +; add esp,[4*ebp + IintStep] + + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + mov [edi+3],al ; store pixel 3 + + add ebx,DeltaUFrac + mov al,[esi] ; get texture pixel 4 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + +; add edx,DeltaIFrac +; sbb ebp,ebp +; mov al,[esp+eax] +; add esp,[4*ebp + IintStep] + + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + mov [edi+4],al ; store pixel 4 + + add ebx,DeltaUFrac + mov al,[esi] ; get texture pixel 5 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + +; add edx,DeltaIFrac +; sbb ebp,ebp +; mov al,[esp+eax] +; add esp,[4*ebp + IintStep] + + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + mov [edi+5],al ; store pixel 5 + + add ebx,DeltaUFrac + mov al,[esi] ; get texture pixel 6 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + +; add edx,DeltaIFrac +; sbb ebp,ebp +; mov al,[esp+eax] +; add esp,[4*ebp + IintStep] + + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + mov [edi+6],al ; store pixel 6 + + add ebx,DeltaUFrac + mov al,[esi] ; get texture pixel 7 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + +; add edx,DeltaIFrac +; sbb ebp,ebp +; mov al,[esp+eax] +; add esp,[4*ebp + IintStep] + dec Wholesections ; decrement span count + + + mov [edi+7],al ; store pixel 7 + lea edi,[edi+8] + + + ; the fdiv is done, finish right ; st0 st1 st2 st3 st4 st5 st6 st7 + ; ZR V/ZR 1/ZR U/ZR UL VL + + fld st ; ZR ZR V/ZR 1/ZR U/ZR UL VL + fmul st,st(2) ; VR ZR V/ZR 1/ZR U/ZR UL VL + fxch st(1) ; ZR VR V/ZR 1/ZR U/ZR UL VL + fmul st,st(4) ; UR VR V/ZR 1/ZR U/ZR UL VL + + jnz GF3D_ScanLoop ; loop back + + mov eax,[PixelsRemaining] + test eax,eax + jz GF3D_finish +GF3D_EndPixels: +if 0 + mov al,[esi] ; get texture pixel + add ecx,DeltaVFrac;test to remove tears + + sbb ebp,ebp ; get -1 if carry + add ebx,DeltaUFrac + + lea edi,[edi+1] + mov al,[esp+eax] ; store pixel 0 + + adc esi,[4*ebp+UVintVfracStep] ; add in step ints & carries + add edx,DeltaIFrac + + sbb ebp,ebp + mov [edi-1],al + + add esp,[4*ebp + IintStep] + dec [PixelsRemaining] + + jnz GF3D_EndPixels +endif + +FPUReturn: + + ; busy FPU registers: ; st0 st1 st2 st3 st4 st5 st6 st7 + ; xxx xxx xxx xxx xxx xxx xxx + ffree st(0) + ffree st(1) + ffree st(2) + ffree st(3) + ffree st(4) + ffree st(5) + ffree st(6) + finit +; fldcw [OldFPUCW] ; restore the FPU + +GF3D_finish: +; mov esp, [StackStore] + popad + ret + +endif + + + + +_TEXT ENDS + +END diff --git a/3dc/win95/SHPCHUNK.CPP b/3dc/win95/SHPCHUNK.CPP new file mode 100644 index 0000000..a494767 --- /dev/null +++ b/3dc/win95/SHPCHUNK.CPP @@ -0,0 +1,3869 @@ +#include + +#include "chunk.hpp" +#include "chnktype.hpp" +#include "shpchunk.hpp" +#include "obchunk.hpp" + + +#if cencon || InterfaceEngine +#include "fnamefnc.hpp" +#include "zsp.hpp" +#include "bmpnames.hpp" +#include "envchunk.hpp" +#include "animchnk.hpp" +#include "chunkpal.hpp" +#include "fragchnk.hpp" +#endif + +#ifdef cencon +#define new my_new +#endif +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(shpchunk) + +RIF_IMPLEMENT_DYNCREATE("REBSHAPE",Shape_Chunk) + +int Shape_Chunk::max_id = 0; +BOOL Shape_External_File_Chunk::UpdatingExternalShape=FALSE; + +// Class Shape_Chunk functions + +/* +Children for Shape_Chunk : + +"SHPRAWVT" Shape_Vertex_Chunk +"SHPPOLYS" Shape_Polygon_Chunk +"SHPHEAD1" Shape_Header_Chunk +"SHPVNORM" Shape_Vertex_Normal_Chunk +"SHPPNORM" Shape_Polygon_Normal_Chunk +"SHPTEXFN" Shape_Texture_Filenames_Chunk +"SHPUVCRD" Shape_UV_Coord_Chunk +"SHPMRGDT" Shape_Merge_Data_Chunk +"SHPCENTR" Shape_Centre_Chunk +"SHPMORPH" Shape_Morphing_Data_Chunk +"SHPEXTFL" Shape_External_File_Chunk +"SHPPCINF" Shape_Poly_Change_Info_Chunk +"TEXTANIM" Animation_Chunk +"SHPFRAGS" Shape_Fragments_Chunk +"ANIMSEQU" Anim_Shape_Sequence_Chunk +"PNOTINBB" Poly_Not_In_Bounding_Box_Chunk +"ANSHCEN2" Anim_Shape_Centre_Chunk +"ASALTTEX" Anim_Shape_Alternate_Texturing_Chunk +"SHPPRPRO" Shape_Preprocessed_Data_Chunk +*/ + +Shape_Chunk::Shape_Chunk(Chunk_With_Children * parent, const char *data, size_t size) +: Lockable_Chunk_With_Children (parent, "REBSHAPE"), shape_data () +{ + const char * buffer_ptr = data; + + shape_data_store = (ChunkShape *) &shape_data; + + while ((data-buffer_ptr)< (signed)size) { + + if ((*(int *)(data + 8)) + (data-buffer_ptr) > (signed)size) { + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + +/*--------------------------------------------------------------------** +** N.B. all changes to shape formats should be made to the sub shapes ** +**--------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------** +** And of course the external file post input processing function should be ** +** changed so that any new chunks will be copied over ** +**--------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------** +** Oy READ THE NOTES, also destroy_auxiliary_chunks should be changed as well ** +**----------------------------------------------------------------------------*/ + + DynCreate(data); + data += *(int *)(data + 8); + +/*--------------------------------------------------------------------** +** N.B. all changes to shape formats should be made to the sub shapes ** +**--------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------** +** And of course the external file post input processing function should be ** +** changed so that any new chunks will be copied over ** +**--------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------** +** Oy READ THE NOTES, also destroy_auxiliary_chunks should be changed as well ** +**----------------------------------------------------------------------------*/ + + } + #if cencon || InterfaceEngine + Listchlist; + lookup_child("CONSHAPE",chlist); + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + ((Console_Shape_Chunk*)chlif())->generate_console_chunkshape(); + } + #endif +} + +Shape_Chunk::Shape_Chunk (Chunk_With_Children * parent, ChunkShape &shp_dat) +: Lockable_Chunk_With_Children (parent, "REBSHAPE"), shape_data (shp_dat) +{ + shape_data_store = (ChunkShape *) &shape_data; + + new Shape_Header_Chunk (this); + + if (shape_data.v_list) new Shape_Vertex_Chunk (this, shape_data.num_verts); + if (shape_data.v_normal_list) new Shape_Vertex_Normal_Chunk (this, shape_data.num_verts); + if (shape_data.p_normal_list) new Shape_Polygon_Normal_Chunk (this, shape_data.num_polys); + if (shape_data.poly_list) new Shape_Polygon_Chunk (this, shape_data.num_polys); + if (shape_data.uv_list) new Shape_UV_Coord_Chunk (this, shape_data.num_uvs); + if (shape_data.texture_fns) new Shape_Texture_Filenames_Chunk (this, shape_data.num_texfiles); + + + + //calculate the shape's centre and radius_about_centre + shape_data_store->centre=(shape_data_store->min+shape_data_store->max)/2; + shape_data_store->radius_about_centre=0; + for(int i=0;inum_verts;i++) + { + float length = (float) mod(shape_data_store->v_list[i]-shape_data_store->centre); + if(length>shape_data_store->radius_about_centre) + { + shape_data_store->radius_about_centre=length; + } + } + + //if the shape hasn't got a Shape_Centre_Chunk , create one. + + if(!lookup_single_child("SHPCENTR")) + { + new Shape_Centre_Chunk(this); + } +} + +Shape_Chunk::~Shape_Chunk () +{ +} + +Shape_Chunk* Shape_Chunk::make_copy_of_chunk() +{ + char* Data=this->make_data_block_from_chunk(); + Shape_Chunk* NewShape=new Shape_Chunk(parent,Data+12,this->size_chunk()-12); + delete [] Data; + delete NewShape->get_header(); + new Shape_Header_Chunk(NewShape); + //need to call post_input_processing in order to copy morphing data correctly + NewShape->post_input_processing(); + NewShape->updated=TRUE; + return NewShape; +} + +Shape_Header_Chunk * Shape_Chunk::get_header() +{ + + return (Shape_Header_Chunk *) this->lookup_single_child ("SHPHEAD1"); + +} + +List const & Shape_Chunk::list_assoc_objs() +{ + if (!get_header()) + { + static List empty_list; + return empty_list; + } + + return get_header()->associated_objects_store; +} + +BOOL Shape_Chunk::assoc_with_object (Object_Chunk *obch) +{ + return obch->assoc_with_shape(this); +} + +BOOL Shape_Chunk::deassoc_with_object (Object_Chunk *obch) +{ + return obch->deassoc_with_shape(this); +} + + +void Shape_Chunk::post_input_processing() +{ + if (get_header()) + if (get_header()->flags & GENERAL_FLAG_LOCKED) + external_lock = TRUE; + +#if 0 //shouldn't need to recalculate extents each time shape is loaded + // recalculate the shape extents + + ChunkVector max, min; + + max.x = -1000000000; + max.y = -1000000000; + max.z = -1000000000; + + min.x = 1000000000; + min.y = 1000000000; + min.z = 1000000000; + + float radius = 0; + + for (int i=0; inum_verts; i++) + { + max.x = max(max.x, shape_data_store->v_list[i].x); + max.y = max(max.y, shape_data_store->v_list[i].y); + max.z = max(max.z, shape_data_store->v_list[i].z); + + min.x = min(min.x, shape_data_store->v_list[i].x); + min.y = min(min.y, shape_data_store->v_list[i].y); + min.z = min(min.z, shape_data_store->v_list[i].z); + + float temp_rad =(float) mod(shape_data_store->v_list[i]); + + radius = max (radius, temp_rad); + } + + shape_data_store->max = max; + shape_data_store->min = min; + shape_data_store->radius = radius; +#endif + + + Chunk_With_Children::post_input_processing(); + +} + +void Shape_Chunk::destroy_auxiliary_chunks() +{ + //split up into different blocks to stop compiler crashing when optimizations are turned on + + List chlst; + + lookup_child("SHPZSPDT",chlst); + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + lookup_child("SHPMRGDT",chlst); + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + + lookup_child("SHPMORPH",chlst); + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + + lookup_child("TEXTANIM",chlst); + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + + lookup_child("SHPPCINF",chlst); + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + lookup_child("SHPFRAGS",chlst); + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + lookup_child("ANIMSEQU",chlst); + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + lookup_child("PNOTINBB",chlst); + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + lookup_child("ANSHCEN2",chlst); + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + lookup_child("CONSHAPE",chlst); + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + lookup_child("ASALTTEX",chlst); + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + lookup_child("SHPPRPRO",chlst); + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + +} + + + +BOOL Shape_Chunk::file_equals(HANDLE &rif_file) +{ + unsigned long bytes_read; + int id; + Shape_Header_Chunk * hdptr = get_header(); + + if (!hdptr) return (FALSE); + + // get header list + List obhead; + list_chunks_in_file (&obhead, rif_file, "SHPHEAD1"); + + if (obhead.size() != 1) return FALSE; + + // get object identifier + SetFilePointer(rif_file,obhead.first_entry() + 32,0,FILE_BEGIN); + ReadFile (rif_file, (long *) &(id), 4, &bytes_read, 0); + + if (hdptr->file_id_num == id) return TRUE; + + return (FALSE); +} + +const char * Shape_Chunk::get_head_id() +{ + Shape_Header_Chunk * hdptr = get_header(); + + if (!hdptr) return (0); + + return(hdptr->identifier); +} + +void Shape_Chunk::set_lock_user (char * user) +{ + Shape_Header_Chunk * hdptr = get_header(); + + if (!hdptr) return; + + strncpy (hdptr->lock_user, user,16); + + hdptr->lock_user[16] = 0; +} + +BOOL Shape_Chunk::inc_v_no () +{ + Shape_Header_Chunk * hdptr = get_header(); + + if (!hdptr) return (FALSE); + + hdptr->version_no++; + + return (TRUE); +} + +BOOL Shape_Chunk::same_and_updated(Shape_Chunk & shp) +{ + + Shape_Header_Chunk * hd1ptr = get_header(); + + if (!hd1ptr) return (0); + + Shape_Header_Chunk * hd2ptr = shp.get_header(); + + if (!hd2ptr) return (0); + + return (hd1ptr->version_no < hd2ptr->version_no && hd1ptr->file_id_num == hd2ptr->file_id_num); + +} + +BOOL Shape_Chunk::assoc_with_object_list(File_Chunk *fc) +{ + Shape_Header_Chunk * hdptr = get_header(); + Object_Chunk * ob = NULL; + + if (!hdptr) return (FALSE); + + List chlst; + fc->lookup_child("RBOBJECT",chlst); + + for (LIF n(&(hdptr->object_names_store)); !n.done(); n.next()) + { + for (LIF l(&chlst); !l.done(); l.next()) + { + ob = (Object_Chunk *)l(); + if ( !strcmp(ob->object_data.o_name, n()) ) + break; + } + if (!l.done()) + assoc_with_object(ob); + else + { + return(FALSE); + } + } + return(TRUE); + + +} + +BOOL Shape_Chunk::update_my_chunkshape (ChunkShape & cshp) +{ + // Firstly lose all the chunks that were with + // the old chunk shape + List chlst; + + lookup_child ("SHPRAWVT",chlst); + + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + lookup_child ("SHPVNORM",chlst); + + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + lookup_child ("SHPPNORM",chlst); + + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + lookup_child ("SHPPOLYS",chlst); + + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + lookup_child ("SHPUVCRD",chlst); + + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + lookup_child ("SHPTEXFN",chlst); + + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + *shape_data_store = cshp; + + if (shape_data.v_list) new Shape_Vertex_Chunk (this, shape_data.num_verts); + if (shape_data.v_normal_list) new Shape_Vertex_Normal_Chunk (this, shape_data.num_verts); + if (shape_data.p_normal_list) new Shape_Polygon_Normal_Chunk (this, shape_data.num_polys); + if (shape_data.poly_list) new Shape_Polygon_Chunk (this, shape_data.num_polys); + if (shape_data.uv_list) new Shape_UV_Coord_Chunk (this, shape_data.num_uvs); + if (shape_data.texture_fns) new Shape_Texture_Filenames_Chunk (this, shape_data.num_texfiles); + + + //calculate the shape's centre and radius_about_centre + shape_data_store->centre=(shape_data_store->min+shape_data_store->max)/2; + shape_data_store->radius_about_centre=0; + for(int i=0;inum_verts;i++) + { + float length = (float) mod(shape_data_store->v_list[i]-shape_data_store->centre); + if(length>shape_data_store->radius_about_centre) + { + shape_data_store->radius_about_centre=length; + } + } + + //if the shape hasn't got a Shape_Centre_Chunk , create one. + + if(!lookup_single_child("SHPCENTR")) + { + new Shape_Centre_Chunk(this); + } + + + return TRUE; +} + +Console_Shape_Chunk* Shape_Chunk::get_console_shape_data(Console_Type ct) +{ + List chlist; + lookup_child("CONSHAPE",chlist); + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + Console_Shape_Chunk* csc=(Console_Shape_Chunk*)chlif(); + List chlist2; + csc->lookup_child("CONSTYPE",chlist2); + if(chlist2.size()) + { + if(((Console_Type_Chunk*)chlist2.first_entry())->console==ct) + return csc; + } + } + + return 0;//no console specific shape data +} + +///////////////////////////////////////// + +// Class Shape_Vertex_Chunk functions + +// These can only be children of Shape_Chunks +// the shape chunks data will automatically be updated by it is created + +// from buffer + +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("SHPRAWVT",Shape_Vertex_Chunk,"REBSHAPE",Shape_Chunk) +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("SHPRAWVT",Shape_Vertex_Chunk,"SUBSHAPE",Shape_Sub_Shape_Chunk) +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("SHPRAWVT",Shape_Vertex_Chunk,"ANIMFRAM",Anim_Shape_Frame_Chunk) + +Shape_Vertex_Chunk::Shape_Vertex_Chunk(Shape_Chunk * parent, const char * vtdata , size_t vtsize) +: Chunk (parent, "SHPRAWVT"), vert_data (NULL), + num_verts (vtsize / 12) // 12 bytes per vertex +{ + int i; + + parent->shape_data_store->v_list = new ChunkVectorInt[num_verts]; + parent->shape_data_store->num_verts = num_verts; + + *((ChunkVectorInt**) &vert_data) = parent->shape_data_store->v_list; + + for (i=0;ishape_data_store->v_list[i] = *((ChunkVectorInt *) vtdata ); + vtdata+=sizeof(ChunkVectorInt); + } + +} + + +Shape_Vertex_Chunk::Shape_Vertex_Chunk(Shape_Sub_Shape_Chunk * parent, const char * vtdata , size_t vtsize) +: Chunk (parent, "SHPRAWVT"), vert_data (NULL), + num_verts (vtsize / 12) // 12 bytes per vertex +{ + int i; + + parent->shape_data_store->v_list = new ChunkVectorInt[num_verts]; + parent->shape_data_store->num_verts = num_verts; + + *((ChunkVectorInt**) &vert_data) = parent->shape_data_store->v_list; + + for (i=0;ishape_data_store->v_list[i] = *((ChunkVectorInt *) vtdata ); + vtdata+=sizeof(ChunkVectorInt); + } + +} + + +Shape_Vertex_Chunk::Shape_Vertex_Chunk(Anim_Shape_Frame_Chunk * parent, const char * vtdata , size_t vtsize) +: Chunk (parent, "SHPRAWVT"), vert_data (NULL), + num_verts (vtsize / 12) // 12 bytes per vertex +{ + int i; + + ChunkVectorInt* v_list = new ChunkVectorInt[num_verts]; + *(ChunkVectorInt**)&vert_data=v_list; + + for (i=0;imake_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; + +} + +void Shape_Vertex_Chunk::fill_data_block(char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + for (int i=0;ishape_data_store->v_normal_list = new ChunkVectorFloat[num_verts]; + *((ChunkVectorFloat**) &vert_norm_data) = parent->shape_data_store->v_normal_list; + + for (i=0;ishape_data_store->v_normal_list[i] = *((ChunkVectorFloat *) vtdata); + vtdata+=sizeof(ChunkVectorFloat); + } + +} + +Shape_Vertex_Normal_Chunk::Shape_Vertex_Normal_Chunk(Shape_Sub_Shape_Chunk * parent, const char * vtdata , size_t vtsize) +: Chunk (parent, "SHPVNORM"), vert_norm_data (NULL), + num_verts (vtsize / sizeof(ChunkVectorInt)) +{ + int i; + + parent->shape_data_store->v_normal_list = new ChunkVectorFloat[num_verts]; + *((ChunkVectorFloat**) &vert_norm_data) = parent->shape_data_store->v_normal_list; + + for (i=0;ishape_data_store->v_normal_list[i] = *((ChunkVectorFloat *) vtdata ); + vtdata+=sizeof(ChunkVectorFloat); + } + +} + +BOOL Shape_Vertex_Normal_Chunk::output_chunk (HANDLE &hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = this->make_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; + +} + +void Shape_Vertex_Normal_Chunk::fill_data_block(char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + for (int i=0;ishape_data_store->p_normal_list = new ChunkVectorFloat[num_polys]; + *((ChunkVectorFloat**) &poly_norm_data) = parent->shape_data_store->p_normal_list; + + for (i=0;ishape_data_store->p_normal_list[i] = *((ChunkVectorFloat *) pndata ); + pndata+=sizeof(ChunkVectorFloat); + } + +} + +Shape_Polygon_Normal_Chunk::Shape_Polygon_Normal_Chunk(Shape_Sub_Shape_Chunk * parent, const char * pndata , size_t pnsize) +: Chunk (parent, "SHPPNORM"), poly_norm_data (NULL), + num_polys (pnsize / sizeof(ChunkVectorFloat)) +{ + int i; + + parent->shape_data_store->p_normal_list = new ChunkVectorFloat[num_polys]; + *((ChunkVectorFloat**) &poly_norm_data) = parent->shape_data_store->p_normal_list; + + for (i=0;ishape_data_store->p_normal_list[i] = *((ChunkVectorFloat *) pndata ); + pndata+=sizeof(ChunkVectorFloat); + } + +} + +Shape_Polygon_Normal_Chunk::Shape_Polygon_Normal_Chunk(Anim_Shape_Frame_Chunk * parent, const char * pndata , size_t pnsize) +: Chunk (parent, "SHPPNORM"), poly_norm_data (NULL), + num_polys (pnsize / sizeof(ChunkVectorFloat)) +{ + int i; + + ChunkVectorFloat* p_normal_list = new ChunkVectorFloat[num_polys]; + *((ChunkVectorFloat**) &poly_norm_data) = p_normal_list; + + for (i=0;imake_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; + +} + +void Shape_Polygon_Normal_Chunk::fill_data_block(char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + for (int i=0;ishape_data_store->poly_list), num_polys (psize / 36) // 9 * 4 bytes per polygon +{ + int i, j; + + parent->shape_data_store->poly_list = new ChunkPoly [num_polys]; + parent->shape_data_store->num_polys = num_polys; + + *((ChunkPoly **) &poly_data) = parent->shape_data_store->poly_list; + + for (i=0; ishape_data_store->poly_list[i].engine_type = *((int *) (pdata + (36*i))); + parent->shape_data_store->poly_list[i].normal_index = *((int *) (pdata + (36*i) + 4)); + parent->shape_data_store->poly_list[i].flags = *((int *) (pdata + (36*i) + 8)); + parent->shape_data_store->poly_list[i].colour = *((int *) (pdata + (36*i) + 12)); + + parent->shape_data_store->poly_list[i].num_verts = 0; + + for (j=0; *((int *) (pdata + (36*i) + 16 + (j*4))) != -1; j++) + { + parent->shape_data_store->poly_list[i].vert_ind[j] = *((int *) (pdata + (36*i) + 16 + (j*4))); + parent->shape_data_store->poly_list[i].num_verts++; + } + + } + +} + +Shape_Polygon_Chunk::Shape_Polygon_Chunk (Shape_Sub_Shape_Chunk * parent, const char * pdata, size_t psize) +: Chunk (parent, "SHPPOLYS"), + poly_data (parent->shape_data_store->poly_list), num_polys (psize / 36) // 9 * 4 bytes per polygon +{ + int i, j; + + parent->shape_data_store->poly_list = new ChunkPoly [num_polys]; + parent->shape_data_store->num_polys = num_polys; + + *((ChunkPoly **) &poly_data) = parent->shape_data_store->poly_list; + + for (i=0; ishape_data_store->poly_list[i].engine_type = *((int *) (pdata + (36*i))); + parent->shape_data_store->poly_list[i].normal_index = *((int *) (pdata + (36*i) + 4)); + parent->shape_data_store->poly_list[i].flags = *((int *) (pdata + (36*i) + 8)); + parent->shape_data_store->poly_list[i].colour = *((int *) (pdata + (36*i) + 12)); + + parent->shape_data_store->poly_list[i].num_verts = 0; + + for (j=0; *((int *) (pdata + (36*i) + 16 + (j*4))) != -1; j++) + { + parent->shape_data_store->poly_list[i].vert_ind[j] = *((int *) (pdata + (36*i) + 16 + (j*4))); + parent->shape_data_store->poly_list[i].num_verts++; + } + + } + +} + +Shape_Polygon_Chunk::Shape_Polygon_Chunk (Console_Shape_Chunk * parent, const char * pdata, size_t psize) +: Chunk (parent, "SHPPOLYS"), + poly_data(0), num_polys (psize / 36) // 9 * 4 bytes per polygon +{ + int i, j; + + ChunkPoly* poly_list = new ChunkPoly [num_polys]; + + *((ChunkPoly **) &poly_data) =poly_list; + + for (i=0; imake_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; + +} + +void Shape_Polygon_Chunk::fill_data_block(char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + for (int i=0;iidentifier,"REBSHAPE")) + { + cs=((Shape_Chunk*)parent)->shape_data_store; + } + else if(!strcmp(parent->identifier,"SUBSHAPE")) + { + cs=((Shape_Sub_Shape_Chunk*)parent)->shape_data_store; + } + assert(cs); + + //fill in the appropriate entries + cs->centre=*(ChunkVectorInt*)data; + data+=sizeof(ChunkVectorInt); + + cs->radius_about_centre=*(float*)data; +} + +void Shape_Centre_Chunk::fill_data_block(char * data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + //find parent's chunkshape + ChunkShape* cs=0; + if(!strcmp(parent->identifier,"REBSHAPE")) + { + cs=((Shape_Chunk*)parent)->shape_data_store; + } + else if(!strcmp(parent->identifier,"SUBSHAPE")) + { + cs=((Shape_Sub_Shape_Chunk*)parent)->shape_data_store; + } + assert(cs); + + + *(ChunkVectorInt*)data_start=cs->centre; + data_start+=sizeof(ChunkVectorInt); + + *(float*)data_start=cs->radius; +} + + +///////////////////////////////////////// + +// Class Shape_UV_Coord_Chunk functions + +// These can only be children of Shape_Chunks +// the shape chunks data will automatically be updated by it is created +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("SHPUVCRD",Shape_UV_Coord_Chunk,"REBSHAPE",Shape_Chunk) +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("SHPUVCRD",Shape_UV_Coord_Chunk,"SUBSHAPE",Shape_Sub_Shape_Chunk) +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("SHPUVCRD",Shape_UV_Coord_Chunk,"CONSHAPE",Console_Shape_Chunk) + +// from buffer +Shape_UV_Coord_Chunk::Shape_UV_Coord_Chunk (Shape_Chunk * parent, const char * uvdata, size_t /*uvsize*/) +: Chunk (parent, "SHPUVCRD"), +uv_data (NULL), num_uvs (*((int *) uvdata)) +{ + int i,j; + + if (num_uvs) + { + parent->shape_data_store->uv_list = new ChunkUV_List[num_uvs]; + } + else + { + parent->shape_data_store->uv_list = 0; + } + *((ChunkUV_List**) &uv_data) = parent->shape_data_store->uv_list; + + parent->shape_data_store->num_uvs = num_uvs; + + uvdata += 4; + + for (i=0;ishape_data_store->uv_list[i].num_verts = *((int *) uvdata); + uvdata += 4; + + for (j=0; jshape_data_store->uv_list[i].num_verts; j++) + { + parent->shape_data_store->uv_list[i].vert[j] = *((ChunkUV *)uvdata); + uvdata += sizeof(ChunkUV); + } + } + +} + +Shape_UV_Coord_Chunk::Shape_UV_Coord_Chunk (Shape_Sub_Shape_Chunk * parent, const char * uvdata, size_t /*uvsize*/) +: Chunk (parent, "SHPUVCRD"), +uv_data (NULL), num_uvs (*((int *) uvdata)) +{ + int i,j; + + parent->shape_data_store->uv_list = new ChunkUV_List[num_uvs]; + *((ChunkUV_List**) &uv_data) = parent->shape_data_store->uv_list; + + parent->shape_data_store->num_uvs = num_uvs; + + uvdata += 4; + + for (i=0;ishape_data_store->uv_list[i].num_verts = *((int *) uvdata); + uvdata += 4; + + for (j=0; jshape_data_store->uv_list[i].num_verts; j++) + { + parent->shape_data_store->uv_list[i].vert[j] = *((ChunkUV *)uvdata); + uvdata += sizeof(ChunkUV); + } + } + +} + +Shape_UV_Coord_Chunk::Shape_UV_Coord_Chunk (Console_Shape_Chunk * parent, const char * uvdata, size_t /*uvsize*/) +: Chunk (parent, "SHPUVCRD"), +uv_data (NULL), num_uvs (*((int *) uvdata)) +{ + int i,j; + + ChunkUV_List* uv_list= new ChunkUV_List[num_uvs]; + *((ChunkUV_List**) &uv_data) = uv_list; + + uvdata += 4; + + for (i=0;imake_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; + +} + + +void Shape_UV_Coord_Chunk::fill_data_block(char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = num_uvs; + + data_start += 4; + + for (int i=0;ishape_data_store->texture_fns = new char * [num_tex_fns]; + *((char***) &tex_fns) = parent->shape_data_store->texture_fns; + + parent->shape_data_store->num_texfiles = num_tex_fns; + + tfndata += 4; + + for (i=0; ishape_data_store->texture_fns[i] = new char [strlen(tfndata)+1]; + strcpy (parent->shape_data_store->texture_fns[i], tfndata); + tfndata += (strlen(tfndata)+1); + } + +} + +Shape_Texture_Filenames_Chunk::Shape_Texture_Filenames_Chunk (Shape_Sub_Shape_Chunk * parent, const char * tfndata, size_t /*tfnsize*/) +: Chunk (parent, "SHPTEXFN"), +tex_fns (), num_tex_fns (*((int *) tfndata)) +{ + int i; + + parent->shape_data_store->texture_fns = new char * [num_tex_fns]; + *((char***) &tex_fns) = parent->shape_data_store->texture_fns; + + parent->shape_data_store->num_texfiles = num_tex_fns; + + tfndata += 4; + + for (i=0; ishape_data_store->texture_fns[i] = new char [strlen(tfndata)+1]; + strcpy (parent->shape_data_store->texture_fns[i], tfndata); + tfndata += (strlen(tfndata)+1); + } + +} + +Shape_Texture_Filenames_Chunk::output_chunk (HANDLE &hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = this->make_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; + +} + + +void Shape_Texture_Filenames_Chunk::fill_data_block(char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = num_tex_fns; + + data_start += 4; + + for (int i=0;ishape_data_store) +{ + int num_as_obj; + + flags = *((int *) hdata); + + strncpy (lock_user, (hdata + 4), 16); + lock_user[16] = '\0'; + hdata+=20; + + file_id_num = *((int *) hdata ); + hdata+=4; + + + parent->shape_data_store->num_verts = *((int *) hdata ); + hdata+=4; + parent->shape_data_store->num_polys = *((int *) hdata ); + hdata+=4; + + parent->shape_data_store->radius = *((float *) hdata); + hdata+=4; + + parent->shape_data_store->max.x = *((int *) hdata); + hdata+=4; + parent->shape_data_store->min.x = *((int *) hdata); + hdata+=4; + + parent->shape_data_store->max.y = *((int *) hdata); + hdata+=4; + parent->shape_data_store->min.y = *((int *) hdata); + hdata+=4; + + parent->shape_data_store->max.z = *((int *) hdata); + hdata+=4; + parent->shape_data_store->min.z = *((int *) hdata); + hdata+=4; + + version_no = *((int *) hdata); + hdata+=4; + + num_as_obj = *((int *) hdata); + hdata+=4; + + char * obj_store; + + for (int i = 0; i< num_as_obj; i++) + { + obj_store = new char [strlen (hdata) +1]; + strcpy (obj_store, (hdata)); + object_names_store.add_entry(obj_store); + hdata += (strlen (hdata)+1); + } + +} + +Shape_Header_Chunk::~Shape_Header_Chunk() +{ + for (LIF aon(&object_names_store); + !aon.done(); aon.next() ) + delete [] aon(); +} + +size_t Shape_Header_Chunk::size_chunk() +{ + int length = 80; + + for (LIF aon(&object_names_store); + !aon.done(); aon.next() ) + length += (strlen (aon()) + 1); + + length += (4-length%4)%4; + + chunk_size = length; + + return length; +} + +BOOL Shape_Header_Chunk::output_chunk(HANDLE & hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = this->make_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; +} + +void Shape_Header_Chunk::fill_data_block(char * data_start) +{ + + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = flags; + strncpy ((data_start + 4), lock_user, 16); + *((int *) (data_start+20)) = file_id_num; + data_start+=24; + + *((int *) data_start) = shape_data->num_verts; + data_start+=4; + *((int *) data_start) = shape_data->num_polys; + data_start+=4; + + *((float *) data_start) = shape_data->radius; + data_start+=4; + + *((int *) data_start) = shape_data->max.x; + data_start+=4; + *((int *) data_start) = shape_data->min.x; + data_start+=4; + + *((int *) data_start) = shape_data->max.y; + data_start+=4; + *((int *) data_start) = shape_data->min.y; + data_start+=4; + + *((int *) data_start) = shape_data->max.z; + data_start+=4; + *((int *) data_start) = shape_data->min.z; + data_start+=4; + + *((int *) data_start) = version_no; + data_start+=4; + + *((int *) data_start) = object_names_store.size(); + data_start+=4; + + + for (LIF ons(&object_names_store); !ons.done(); ons.next()) + { + strcpy (data_start, ons()); + data_start += (strlen(ons())+1); + } + +} + + +void Shape_Header_Chunk::prepare_for_output() +{ +// this will also set the object chunks numbers as well, +// so that it is done in the right order + + char * str; + + if (file_id_num == -1) file_id_num = ++(Shape_Chunk::max_id); + + while (object_names_store.size()) { + delete [] object_names_store.first_entry(); + object_names_store.delete_first_entry(); + } + + for (LIF aosl(&associated_objects_store); + !aosl.done(); aosl.next() ) { + + if (aosl()->get_header()) + aosl()->get_header()->shape_id_no = file_id_num; + + str = new char [strlen(aosl()->object_data.o_name) + 1]; + strcpy(str, aosl()->object_data.o_name); + object_names_store.add_entry(str); + + } + + Shape_Chunk::max_id = max(Shape_Chunk::max_id, file_id_num); + +// this should always be the last thing + + version_no ++; +} + + + +///////////////////////////////////////// + +// Class Shape_Merge_Data_Chunk functions + +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("SHPMRGDT",Shape_Merge_Data_Chunk,"REBSHAPE",Shape_Chunk) +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("SHPMRGDT",Shape_Merge_Data_Chunk,"SUBSHAPE",Shape_Sub_Shape_Chunk) + +Shape_Merge_Data_Chunk::Shape_Merge_Data_Chunk(Shape_Chunk * parent, int * m_dt, int n_ps) +: Chunk (parent, "SHPMRGDT"), num_polys (n_ps) +{ + merge_data = new int [n_ps]; + for (int i=0; iparent->lookup_single_child("REBENVDT"); + + BOOL fixpal = IsFixedPalette(envd); + + List chlst; + lookup_child("SHPEXTFN",chlst); + + if (chlst.size()) + { + UpdatingExternalShape=TRUE; + + Shape_External_Filename_Chunk * sefc = (Shape_External_Filename_Chunk *)chlst.first_entry(); + + #if cencon + twprintf("Locating %s\n",sefc->file_name); + char * locatedfile = FindExistingFileInPath_PreferWriteable(CWnd::GetActiveWindow(),sefc->file_name,"RifSearchPath"); + twprintf("Loading %s\n",locatedfile ? locatedfile : sefc->file_name); + RIF_File_Chunk * rfc = new RIF_File_Chunk (this, locatedfile ? locatedfile : sefc->file_name); + #elif InterfaceEngine + RIF_File_Chunk * rfc; + char * locatedfile = FindExistingFile_PreferWriteable(sefc->file_name,"RifSearchPath",FALSE); + if (locatedfile) + { + rfc = new RIF_File_Chunk (this, locatedfile); + } + else + { + UpdatingExternalShape=FALSE; + return; + } + #endif + + //Now loaded external file,so UpdatingExternalShape can now be reset + UpdatingExternalShape=FALSE; + + if (rfc->error_code != 0) + { + #if cencon + extern BOOL SuppressFailedToFindShapeRifErrors; + + if(!SuppressFailedToFindShapeRifErrors) + { + char message[300]; + sprintf(message,"Error loading shape rif : %s",locatedfile ? locatedfile : sefc->file_name); + twMessageBox(CWnd::GetActiveWindow(),message,"Tools Control Area", MB_TASKMODAL+MB_OK+MB_ICONHAND); + } + #endif + if (locatedfile) + { + delete[] locatedfile; + } + delete rfc; + return; + } + + Shape_Chunk* shp=0; + lookup_child("EXTOBJNM",chlst); + + + if(chlst.size()) + { + //we have an object name so we need to search for the correct object in the file + Shape_External_Object_Name_Chunk* seonm=(Shape_External_Object_Name_Chunk*) chlst.first_entry(); + + rfc->lookup_child("RBOBJECT",chlst); + for(LIF chlif(&chlst);!chlif.done();chlif.next()) + { + Object_Chunk* oc=(Object_Chunk*)chlif(); + if(!strcmp(oc->object_data.o_name,seonm->object_name))break; + } + if(chlif.done()) + { + //can't find the object + #if cencon + char message[300]; + sprintf(message,"Failed to find %s in %s\n(There may be several different rif files with the same name)",seonm->object_name,locatedfile); + twMessageBox(CWnd::GetActiveWindow(),message,"Tools Control Area", MB_TASKMODAL+MB_OK+MB_ICONHAND); + #endif + delete [] locatedfile; + delete rfc; + return; + } + + shp=((Object_Chunk*)chlif())->get_assoc_shape(); + } + else + { + //no object name,so there has to be just one shape in the file + rfc->lookup_child("REBSHAPE",chlst); + + if (chlst.size() != 1) + { + #if cencon + char message[300]; + sprintf(message,"There are %d shapes in %s\n(There should only be one)\n",chlst.size(),locatedfile); + twMessageBox(CWnd::GetActiveWindow(),message,"Tools Control Area", MB_TASKMODAL+MB_OK+MB_ICONHAND); + #endif + Environment_Data_Chunk * edc = 0; + edc = (Environment_Data_Chunk *)rfc->lookup_single_child("REBENVDT"); + if(edc) + { + lookup_child("RIFFNAME",chlst); + + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + edc->lookup_child("RIFFNAME",chlst); + + if (chlst.size()) + { + new RIF_Name_Chunk (this, ((RIF_Name_Chunk *)chlst.first_entry())->rif_name); + } + } + delete [] locatedfile; + delete rfc; + return; + } + + shp = (Shape_Chunk *)chlst.first_entry(); + } + delete [] locatedfile; + locatedfile=0; + + // set so that it updates it whatever + + if (shp->get_header()->version_no != sefc->version_no || TRUE) + { + //if the shape doesn't have any associated objects,get scale from external file's + //environment scale chunk. + //also get scale if force_scale_update is true + if(parent_shp->list_assoc_objs().size()==0 || force_scale_update) + { + if(force_scale_update) + { + sefc->rescale=1; + } + List chlist=rfc->lookup_child("REBENVDT"); + if(chlist.size()) + { + chlist=((Chunk_With_Children*)chlist.first_entry())->lookup_child("ENVSDSCL"); + if(chlist.size()) + { + Environment_Scale_Chunk* esc =(Environment_Scale_Chunk*)chlist.first_entry(); + sefc->rescale=esc->scale; + } + } + } + // copy all the data over from the loaded shape into the parent + ChunkShape cs = shp->shape_data; + + cs.rescale(sefc->rescale); + + + // here we may want to sort out texture index nos. + + + // hmmm fix me + // definitely fixme... + // everytime the file is loaded, + // the shape is updated, and its bmps + // and thus the palette-up-to-date flag is reset, + // and the machine reckons on a new palette. + + parent_shp->local_lock = TRUE; + + parent_shp->update_my_chunkshape (cs); + + parent_shp->local_lock = FALSE; + + // delete all other chunks in the parent shape + // apart form the header !!!! + + parent_shp->destroy_auxiliary_chunks(); + + char * tempbuffer; + Chunk* child_chunk; + + child_chunk=shp->lookup_single_child("SHPZSPDT"); + if (child_chunk) + { + tempbuffer = child_chunk->make_data_block_from_chunk(); + new Shape_ZSP_Data_Chunk (parent_shp, (tempbuffer + 12), (*(int *) (tempbuffer + 8))-12); + delete [] tempbuffer; + } + + child_chunk = shp->lookup_single_child("SHPMRGDT"); + if (child_chunk) + { + tempbuffer = child_chunk->make_data_block_from_chunk(); + new Shape_Merge_Data_Chunk (parent_shp, (tempbuffer + 12), (*(int *) (tempbuffer + 8))-12); + delete [] tempbuffer; + } + + child_chunk = shp->lookup_single_child("SHPMORPH"); + if (child_chunk) + { + tempbuffer = child_chunk->make_data_block_from_chunk(); + new Shape_Morphing_Data_Chunk (parent_shp, (tempbuffer + 12), (*(int *) (tempbuffer + 8))-12); + delete [] tempbuffer; + } + + child_chunk = shp->lookup_single_child("TEXTANIM"); + if (child_chunk) + { + tempbuffer = child_chunk->make_data_block_from_chunk(); + new Animation_Chunk (parent_shp, (tempbuffer + 12), (*(int *) (tempbuffer + 8))-12); + delete [] tempbuffer; + } + + child_chunk = shp->lookup_single_child("SHPPCINF"); + if (child_chunk) + { + tempbuffer = child_chunk->make_data_block_from_chunk(); + new Shape_Poly_Change_Info_Chunk (parent_shp, (tempbuffer + 12), (*(int *) (tempbuffer + 8))-12); + delete [] tempbuffer; + } + + + child_chunk = shp->lookup_single_child("SHPFRAGS"); + if (child_chunk) + { + tempbuffer = child_chunk->make_data_block_from_chunk(); + Shape_Fragments_Chunk * sfc = new Shape_Fragments_Chunk (parent_shp, (tempbuffer + 12), (*(int *) (tempbuffer + 8))-12); + + List cl2; + sfc->lookup_child("SUBSHAPE",cl2); + + for (LIF cli2(&cl2); !cli2.done(); cli2.next()) + { + Shape_Sub_Shape_Chunk * sssc = (Shape_Sub_Shape_Chunk *)cli2(); + + ChunkShape sscs = sssc->shape_data; + sscs.rescale(sefc->rescale); + sssc->update_my_chunkshape (sscs); + + Shape_Fragment_Location_Chunk * sflc = (Shape_Fragment_Location_Chunk *)sssc->lookup_single_child("FRAGLOCN"); + if (sflc) + { + sflc->frag_loc.x =(int) (sflc->frag_loc.x*sefc->rescale); + sflc->frag_loc.y =(int) (sflc->frag_loc.y*sefc->rescale); + sflc->frag_loc.z =(int) (sflc->frag_loc.z*sefc->rescale); + } + + } + + delete [] tempbuffer; + } + + shp->lookup_child("ANIMSEQU",chlst); + for(LIF chlif(&chlst);!chlif.done();chlif.next()) + { + Anim_Shape_Sequence_Chunk* assc=(Anim_Shape_Sequence_Chunk*)chlif(); + new Anim_Shape_Sequence_Chunk(parent_shp,&assc->sequence_data); + } + + child_chunk = shp->lookup_single_child("PNOTINBB"); + if(child_chunk) + { + tempbuffer = child_chunk->make_data_block_from_chunk(); + new Poly_Not_In_Bounding_Box_Chunk (parent_shp, (tempbuffer + 12), (*(int *) (tempbuffer + 8))-12); + delete [] tempbuffer; + } + child_chunk = shp->lookup_single_child("ANSHCEN2"); + if(child_chunk) + { + tempbuffer = child_chunk->make_data_block_from_chunk(); + new Anim_Shape_Centre_Chunk (parent_shp, (tempbuffer + 12), (*(int *) (tempbuffer + 8))-12); + delete [] tempbuffer; + } + child_chunk = shp->lookup_single_child("ASALTTEX"); + if(child_chunk) + { + tempbuffer = child_chunk->make_data_block_from_chunk(); + new Anim_Shape_Alternate_Texturing_Chunk (parent_shp, (tempbuffer + 12), (*(int *) (tempbuffer + 8))-12); + delete [] tempbuffer; + } + shp->lookup_child("CONSHAPE",chlst); + for(chlif.restart();!chlif.done();chlif.next()) + { + tempbuffer = chlif()->make_data_block_from_chunk(); + Console_Shape_Chunk* csc=new Console_Shape_Chunk (parent_shp, (tempbuffer + 12), (*(int *) (tempbuffer + 8))-12); + csc->generate_console_chunkshape(); + delete [] tempbuffer; + } + + parent_shp->updated = TRUE; + + sefc->version_no = shp->get_header()->version_no; + + } + + Bitmap_List_Store_Chunk * blsc = 0; + + Global_BMP_Name_Chunk * gbnc = 0; + + Environment_Data_Chunk * edc = 0; + + edc = (Environment_Data_Chunk *)rfc->lookup_single_child("REBENVDT"); + + + if (edc) + { + gbnc = (Global_BMP_Name_Chunk *) edc->lookup_single_child("BMPNAMES"); + if (gbnc) + { + if (!gbnc->bmps.size()) gbnc = 0; + } + + List oldlst; + lookup_child("BMPLSTST",oldlst); + if (oldlst.size()>1) + { + while (oldlst.size()) + { + delete oldlst.first_entry(); + oldlst.delete_first_entry(); + } + } + + if (oldlst.size()) + { + blsc = (Bitmap_List_Store_Chunk *)oldlst.first_entry(); + } + else + { + if (gbnc) blsc = new Bitmap_List_Store_Chunk(this); + } + + BMP_Names_ExtraData * extended = 0; + if (blsc) + { + extended = blsc->GetExtendedData(); + if (fixpal) + extended->flags = (GlobalBMPFlags)(extended->flags | GBF_FIXEDPALETTE); + else + extended->flags = (GlobalBMPFlags)(extended->flags & ~GBF_FIXEDPALETTE); + } + if (gbnc) + { + //if ((gbnc->get_version_num()!=blsc->get_version_num()) || (gbnc->bmps.size() != blsc->bmps.size())) + /*update regardless of version number*/ + { // other checks could be done as well + if (blsc->bmps.size()) + { + BOOL neednewpalette = FALSE; + + List newlist = gbnc->bmps; + for (LIF newLIF(&newlist); !newLIF.done(); newLIF.next()) + { + BMP_Name newcur = newLIF(); + newcur.flags = (BMPN_Flags) (newcur.flags & ~(COMPLETED_BMPN_FLAGS | ChunkBMPFlag_FixedPalette)); + if (fixpal) newcur.flags = (BMPN_Flags) (newcur.flags | ChunkBMPFlag_FixedPalette); + for (LIF oldLIF(&blsc->bmps); !oldLIF.done(); oldLIF.next()) + { + BMP_Name oldcur = oldLIF(); + if (newcur == oldcur) + { + // do we need to requantize? + if ((oldcur.flags ^ newcur.flags) & CHECKMODIFY_BMPN_FLAGS + || newcur.flags & ChunkBMPFlag_UsesTransparency + && !(newcur.flags & ChunkBMPFlag_IFF) + && !(oldcur.flags & ChunkBMPFlag_IFF) + && oldcur.DifferentTransparencyColour(newcur)) + oldcur.flags = (BMPN_Flags)(oldcur.flags & ~COMPLETED_BMPN_FLAGS); + // keep some of the old flags - the ones that can differ + newcur.flags = (BMPN_Flags)(newcur.flags & COPY_BMPN_FLAGS); + newcur.flags = (BMPN_Flags)(newcur.flags | oldcur.flags & ~COPY_BMPN_FLAGS); + if (oldcur.version_num != newcur.version_num) + { + neednewpalette = TRUE; + newcur.flags = (BMPN_Flags)(newcur.flags & ~ChunkBMPFlag_HistogramExists); + extended->flags = (GlobalBMPFlags)(extended->flags & ~GBF_HISTOGRAMEXISTS); + } + break; + } + } + if (oldLIF.done()) + { + // reset palette up to date flag + neednewpalette = TRUE; + newcur.flags = (BMPN_Flags)(newcur.flags & ~(ChunkBMPFlag_HistogramExists | COMPLETED_BMPN_FLAGS)); + extended->flags = (GlobalBMPFlags)(extended->flags & ~GBF_HISTOGRAMEXISTS); + } + newLIF.change_current(newcur); + } + + // check if any bitmaps have been removed + for (LIF bli(&blsc->bmps); !bli.done(); bli.next()) + { + if (!newlist.contains(bli())) + { + // delete assoc files + neednewpalette = TRUE; + extended->flags = (GlobalBMPFlags)(extended->flags & ~GBF_HISTOGRAMEXISTS); + } + } + + if (neednewpalette) + { + Palette_Outdated(envd); + if (fixpal) FixedPalette_Outdated(envd); + envd->updated = TRUE; + } + blsc->bmps = newlist; + } + else + { + blsc->bmps = gbnc->bmps; + for (LIF flagresetLIF(&blsc->bmps); !flagresetLIF.done(); flagresetLIF.next()) + { + BMP_Name current = flagresetLIF(); + current.flags = (BMPN_Flags)(current.flags & (COPY_BMPN_FLAGS & ~ChunkBMPFlag_FixedPalette)); + if (fixpal) current.flags = (BMPN_Flags) (current.flags | ChunkBMPFlag_FixedPalette); + flagresetLIF.change_current(current); + } + // reset palette up to date flag + extended->flags = (GlobalBMPFlags)(extended->flags & ~GBF_HISTOGRAMEXISTS); + Palette_Outdated(envd); + if (fixpal) FixedPalette_Outdated(envd); + envd->updated = TRUE; + } + blsc->max_index = gbnc->max_index; + blsc->set_version_num(gbnc->get_version_num()); + parent_shp->updated = TRUE; + } + } + else + { + if (blsc) + { + if (blsc->bmps.size()) + { + // reset palette up to date flag + extended->flags = (GlobalBMPFlags)(extended->flags & ~GBF_HISTOGRAMEXISTS); + Palette_Outdated(envd); + if (fixpal) FixedPalette_Outdated(envd); + envd->updated = TRUE; + parent_shp->updated = TRUE; + } + delete blsc; + } + } + } + + lookup_child("RIFFNAME",chlst); + + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + if (edc) + { + edc->lookup_child("RIFFNAME",chlst); + + if (chlst.size()) + { + new RIF_Name_Chunk (this, ((RIF_Name_Chunk *)chlst.first_entry())->rif_name); + } + + } + + delete rfc; + } + +} + +void Shape_External_File_Chunk::post_input_processing() +{ + + update_from_external_rif(FALSE); + Chunk_With_Children::post_input_processing(); + +} +#else +void Shape_External_File_Chunk::post_input_processing() +{ + Chunk_With_Children::post_input_processing(); +} +#endif + +const char* Shape_External_File_Chunk::get_shape_name() +{ + Shape_External_Object_Name_Chunk* seonc=(Shape_External_Object_Name_Chunk*)lookup_single_child("EXTOBJNM"); + if(seonc) + { + return seonc->shape_name; + } + + RIF_Name_Chunk* rnc=(RIF_Name_Chunk*)lookup_single_child("RIFFNAME"); + if(rnc) + { + return rnc->rif_name; + } + + return 0; + +} + +///////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("SHPEXTFN",Shape_External_Filename_Chunk) + +Shape_External_Filename_Chunk::Shape_External_Filename_Chunk(Chunk_With_Children * parent, const char * fname) +: Chunk (parent, "SHPEXTFN") +{ + file_name = new char [strlen(fname)+1]; + strcpy (file_name, fname); + + rescale = 1; + version_no = -1; + +} + +Shape_External_Filename_Chunk::Shape_External_Filename_Chunk (Chunk_With_Children * parent, const char *fdata, size_t /*fsize*/) +: Chunk (parent, "SHPEXTFN") +{ + rescale = *((double *) fdata); + fdata += 8; + version_no = *((int *) fdata); + fdata += 4; + file_name = new char [strlen(fdata)+1]; + strcpy (file_name, fdata); +} + +Shape_External_Filename_Chunk::~Shape_External_Filename_Chunk() +{ + if (file_name) + delete [] file_name; +} + +void Shape_External_Filename_Chunk::fill_data_block (char *data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((double *) data_start) = rescale; + + data_start += 8; + + *((int *) data_start) = version_no; + + data_start += 4; + + strcpy (data_start, file_name); + +} + +/////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("EXTOBJNM",Shape_External_Object_Name_Chunk) + +Shape_External_Object_Name_Chunk::Shape_External_Object_Name_Chunk(Chunk_With_Children * parent, const char * oname) +: Chunk (parent, "EXTOBJNM") +{ + object_name = new char [strlen(oname)+1]; + shape_name=0; + strcpy (object_name, oname); + pad=0; + + RIF_Name_Chunk* rnc=(RIF_Name_Chunk*)parent->lookup_single_child("RIFFNAME"); + if(rnc) + { + shape_name=new char[strlen(object_name)+strlen(rnc->rif_name)+2]; + sprintf(shape_name,"%s@%s",object_name,rnc->rif_name); + } + else + { + shape_name=new char[strlen(object_name)+10+2]; + sprintf(shape_name,"%s@*NotFound*",object_name); + } +} + +Shape_External_Object_Name_Chunk::Shape_External_Object_Name_Chunk (Chunk_With_Children * parent, const char *data, size_t /*fsize*/) +: Chunk (parent, "EXTOBJNM") +{ + pad=*(int*)data; + data+=4; + object_name = new char [strlen(data)+1]; + strcpy (object_name, data); + shape_name=0; +} + +Shape_External_Object_Name_Chunk::~Shape_External_Object_Name_Chunk() +{ + if (object_name) + delete [] object_name; + if(shape_name) + delete [] shape_name; +} + +void Shape_External_Object_Name_Chunk::post_input_processing() +{ + RIF_Name_Chunk* rnc=(RIF_Name_Chunk*)parent->lookup_single_child("RIFFNAME"); + if(rnc) + { + shape_name=new char[strlen(object_name)+strlen(rnc->rif_name)+2]; + sprintf(shape_name,"%s@%s",object_name,rnc->rif_name); + } + else + { + shape_name=new char[strlen(object_name)+10+2]; + sprintf(shape_name,"%s@*NotFound*",object_name); + } +} + +void Shape_External_Object_Name_Chunk::fill_data_block (char *data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *(int*)data_start =pad; + + data_start+=4; + + strcpy (data_start, object_name); + +} + +/////////////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("SHPMORPH",Shape_Morphing_Data_Chunk,"REBSHAPE",Shape_Chunk) +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("SHPMORPH",Shape_Morphing_Data_Chunk,"SUBSHAPE",Shape_Sub_Shape_Chunk) + +/* +Children for Shape_Morphing_Data_Chunk : + +"SUBSHAPE" Shape_Sub_Shape_Chunk +"FRMMORPH" Shape_Morphing_Frame_Data_Chunk +*/ + + +Shape_Morphing_Data_Chunk::Shape_Morphing_Data_Chunk (Shape_Chunk * parent, const char *data, size_t size) +: Chunk_With_Children (parent, "SHPMORPH"), parent_shape (parent), parent_sub_shape (0) +{ + const char * buffer_ptr = data; + + while ((data-buffer_ptr)< (signed)size) { + + if ((*(int *)(data + 8)) + (data-buffer_ptr) > (signed)size) { + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + + DynCreate(data); + data += *(int *)(data + 8); + + } + +} +Shape_Morphing_Data_Chunk::Shape_Morphing_Data_Chunk (Shape_Sub_Shape_Chunk * parent, const char *data, size_t size) +: Chunk_With_Children (parent, "SHPMORPH"), parent_sub_shape (parent), parent_shape (0) +{ + const char * buffer_ptr = data; + + while ((data-buffer_ptr)< (signed)size) { + + if ((*(int *)(data + 8)) + (data-buffer_ptr) > (signed)size) { + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + DynCreate(data); + data += *(int *)(data + 8); + + + } + +} + + +void Shape_Morphing_Data_Chunk::prepare_for_output() +{ + int max_id = 0; + + List cl; + lookup_child("SUBSHAPE",cl); + + for (LIF cli(&cl); !cli.done(); cli.next()) + { + max_id = max (max_id, ((Shape_Sub_Shape_Chunk *)cli())->get_header()->file_id_num); + } + + for (cli.restart(); !cli.done(); cli.next()) + { + if (((Shape_Sub_Shape_Chunk *)cli())->get_header()->file_id_num == -1) + { + ((Shape_Sub_Shape_Chunk *)cli())->get_header()->file_id_num = ++max_id; + } + } + Chunk_With_Children::prepare_for_output(); + +} + +/////////////////////////////////////// + +#ifdef new +#pragma message("new defined") +#endif + +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("FRMMORPH",Shape_Morphing_Frame_Data_Chunk,"SHPMORPH",Shape_Morphing_Data_Chunk) + +Shape_Morphing_Frame_Data_Chunk::Shape_Morphing_Frame_Data_Chunk (Shape_Morphing_Data_Chunk * parent,const char *data, size_t /*size*/) +: Chunk (parent, "FRMMORPH") +{ + a_flags = *((int *)data); + data +=4; + a_speed = *((int *)data); + data +=4; + num_frames = *((int *)data); + data +=4; + + if (num_frames) + frame_store = new int [num_frames * 3]; + else + frame_store=0; + for (int i=0; i afi(&anim_frames); !afi.done(); afi.next()) + { + int s1no, s2no; + if (afi()->shape1a) + s1no = afi()->shape1a->get_header()->file_id_num; + else + s1no = -1; + if (afi()->shape2a) + s2no = afi()->shape2a->get_header()->file_id_num; + else + s2no = -1; + + frame_store[num_f] = s1no; + frame_store[num_f+1] = s2no; + frame_store[num_f+2] = afi()->spare; + num_f ++; + } + num_frames = num_f; +} + + +void Shape_Morphing_Frame_Data_Chunk::post_input_processing() +{ + List shplist; + List child_lists; + + Shape_Morphing_Data_Chunk * pchnk = (Shape_Morphing_Data_Chunk *) parent; + + pchnk->lookup_child("SUBSHAPE",child_lists); + + while (child_lists.size()) { + shplist.add_entry((Shape_Sub_Shape_Chunk *)child_lists.first_entry()); + child_lists.delete_first_entry(); + } + + LIF sl(&shplist); + + for (int i = 0; iparent_shape; + } + else + { + for (; !sl.done(); sl.next()) { + if (sl()->get_header()) + if (sl()->get_header()->file_id_num == frame_store[i]) + break; + } + if (!sl.done()) + { + sh1a = sl(); + } + } + + if (frame_store[i*2+1] == -1) + { + sh2b = pchnk->parent_shape; + } + else + { + for (sl.restart(); !sl.done(); sl.next()) { + if (sl()->get_header()) + if (sl()->get_header()->file_id_num == frame_store[i+1]) + break; + } + if (!sl.done()) + { + sh2a = sl(); + } + } + if ((sh1a || sh1b) && (sh2a || sh2b)) + { + fr = new a_frame; + if (sh1a) + fr->shape1a = sh1a; + else if (sh1b) + fr->shape1b = sh1b; + + if (sh2a) + fr->shape2a = sh2a; + else if (sh2b) + fr->shape2b = sh2b; + + fr->spare = frame_store[i+2]; + anim_frames.add_entry(fr); + } + + } +} + +///////////////////////////////////////// + +// Class Shape_Sub_Shape_Chunk functions + + +RIF_IMPLEMENT_DYNCREATE("SUBSHAPE",Shape_Sub_Shape_Chunk) +/* +Children for Shape_Sub_Shape_Chunk : + +"SHPRAWVT" Shape_Vertex_Chunk +"SHPPOLYS" Shape_Polygon_Chunk +"SUBSHPHD" Shape_Sub_Shape_Header_Chunk +"SHPVNORM" Shape_Vertex_Normal_Chunk +"SHPPNORM" Shape_Polygon_Normal_Chunk +"SHPTEXFN" Shape_Texture_Filenames_Chunk +"SHPUVCRD" Shape_UV_Coord_Chunk +"SHPMRGDT" Shape_Merge_Data_Chunk +"SHPCENTR" Shape_Centre_Chunk +"SHPMORPH" Shape_Morphing_Data_Chunk +"SHPEXTFL" Shape_External_File_Chunk +"SHPPCINF" Shape_Poly_Change_Info_Chunk +"TEXTANIM" Animation_Chunk +"SHPFRAGS" Shape_Fragments_Chunk +"ANIMSEQU" Anim_Shape_Sequence_Chunk +"PNOTINBB" Poly_Not_In_Bounding_Box_Chunk +"ANSHCEN2" Anim_Shape_Centre_Chunk +"ASALTTEX" Anim_Shape_Alternate_Texturing_Chunk +"SHPPRPRO" Shape_Preprocessed_Data_Chunk + + +"SHPFNAME" Shape_Name_Chunk +"FRAGDATA" Shape_Fragments_Data_Chunk +"FRAGLOCN" Shape_Fragment_Location_Chunk +*/ + +Shape_Sub_Shape_Chunk::Shape_Sub_Shape_Chunk(Chunk_With_Children * parent, const char *data, size_t size) +: Chunk_With_Children (parent, "SUBSHAPE"), shape_data () +{ + const char * buffer_ptr = data; + + shape_data_store = (ChunkShape *) &shape_data; + + while ((data-buffer_ptr)< (signed)size) { + + if ((*(int *)(data + 8)) + (data-buffer_ptr) > (signed)size) { + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + + DynCreate(data); + data += *(int *)(data + 8); + + } + #if cencon || InterfaceEngine + Listchlist; + lookup_child("CONSHAPE",chlist); + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + ((Console_Shape_Chunk*)chlif())->generate_console_chunkshape(); + } + #endif +} + +Shape_Sub_Shape_Chunk::Shape_Sub_Shape_Chunk (Chunk_With_Children * parent, ChunkShape &shp_dat) +: Chunk_With_Children (parent, "SUBSHAPE"), shape_data (shp_dat) +{ + shape_data_store = (ChunkShape *) &shape_data; + + new Shape_Sub_Shape_Header_Chunk (this); + + if (shape_data.v_list) new Shape_Vertex_Chunk (this, shape_data.num_verts); + if (shape_data.v_normal_list) new Shape_Vertex_Normal_Chunk (this, shape_data.num_verts); + if (shape_data.p_normal_list) new Shape_Polygon_Normal_Chunk (this, shape_data.num_polys); + if (shape_data.poly_list) new Shape_Polygon_Chunk (this, shape_data.num_polys); + if (shape_data.uv_list) new Shape_UV_Coord_Chunk (this, shape_data.num_uvs); + if (shape_data.texture_fns) new Shape_Texture_Filenames_Chunk (this, shape_data.num_texfiles); + + //calculate the shape's centre and radius_about_centre + shape_data_store->centre=(shape_data_store->min+shape_data_store->max)/2; + shape_data_store->radius_about_centre=0; + for(int i=0;inum_verts;i++) + { + float length = (float) mod(shape_data_store->v_list[i]-shape_data_store->centre); + if(length>shape_data_store->radius_about_centre) + { + shape_data_store->radius_about_centre=length; + } + } + + //if the shape hasn't got a Shape_Centre_Chunk , create one. + + if(!lookup_single_child("SHPCENTR")) + { + new Shape_Centre_Chunk(this); + } +} + +Shape_Sub_Shape_Chunk::~Shape_Sub_Shape_Chunk () +{ +} + +Shape_Sub_Shape_Chunk* Shape_Sub_Shape_Chunk::make_copy_of_chunk() +{ + char* Data=this->make_data_block_from_chunk(); + Shape_Sub_Shape_Chunk* NewShape=new Shape_Sub_Shape_Chunk(parent,Data+12,this->size_chunk()-12); + delete [] Data; + delete NewShape->get_header(); + new Shape_Sub_Shape_Header_Chunk(NewShape); + return NewShape; +} + +Shape_Sub_Shape_Header_Chunk * Shape_Sub_Shape_Chunk::get_header() +{ + + return (Shape_Sub_Shape_Header_Chunk *) this->lookup_single_child ("SUBSHPHD"); + +} + +BOOL Shape_Sub_Shape_Chunk::update_my_chunkshape (ChunkShape & cshp) +{ + // Firstly lose all the chunks that were with + // the old chunk shape + List chlst; + + lookup_child ("SHPRAWVT",chlst); + + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + lookup_child ("SHPVNORM",chlst); + + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + lookup_child ("SHPPNORM",chlst); + + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + lookup_child ("SHPPOLYS",chlst); + + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + lookup_child ("SHPUVCRD",chlst); + + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + + lookup_child ("SHPTEXFN",chlst); + + while (chlst.size()) + { + delete chlst.first_entry(); + chlst.delete_first_entry(); + } + + *shape_data_store = cshp; + + if (shape_data.v_list) new Shape_Vertex_Chunk (this, shape_data.num_verts); + if (shape_data.v_normal_list) new Shape_Vertex_Normal_Chunk (this, shape_data.num_verts); + if (shape_data.p_normal_list) new Shape_Polygon_Normal_Chunk (this, shape_data.num_polys); + if (shape_data.poly_list) new Shape_Polygon_Chunk (this, shape_data.num_polys); + if (shape_data.uv_list) new Shape_UV_Coord_Chunk (this, shape_data.num_uvs); + if (shape_data.texture_fns) new Shape_Texture_Filenames_Chunk (this, shape_data.num_texfiles); + + //calculate the shape's centre and radius_about_centre + shape_data_store->centre=(shape_data_store->min+shape_data_store->max)/2; + shape_data_store->radius_about_centre=0; + for(int i=0;inum_verts;i++) + { + float length=(float)mod(shape_data_store->v_list[i]-shape_data_store->centre); + if(length>shape_data_store->radius_about_centre) + { + shape_data_store->radius_about_centre=length; + } + } + + //if the shape hasn't got a Shape_Centre_Chunk , create one. + + if(!lookup_single_child("SHPCENTR")) + { + new Shape_Centre_Chunk(this); + } + + + return TRUE; +} + + +const char * Shape_Sub_Shape_Chunk::get_shape_name() +{ + Shape_Name_Chunk* snc=(Shape_Name_Chunk*)lookup_single_child("SHPFNAME"); + if (snc) + { + return snc->shape_name; + } + else + { + return(0); + } +} + +Console_Shape_Chunk* Shape_Sub_Shape_Chunk::get_console_shape_data(Console_Type ct) +{ + List chlist; + lookup_child("CONSHAPE",chlist); + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + Console_Shape_Chunk* csc=(Console_Shape_Chunk*)chlif(); + List chlist2; + csc->lookup_child("CONSTYPE",chlist2); + if(chlist2.size()) + { + if(((Console_Type_Chunk*)chlist2.first_entry())->console==ct) + return csc; + } + } + + return 0;//no console specific shape data +} + +///////////////////////////////////////// + +// Class Shape_Sub_Shape_Header_Chunk functions + +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("SUBSHPHD",Shape_Sub_Shape_Header_Chunk,"SUBSHAPE",Shape_Sub_Shape_Chunk) + +// These can only be children of Shape_Sub_Shape_Chunks +// the shape chunks data will automatically be updated by it is created + +Shape_Sub_Shape_Header_Chunk::Shape_Sub_Shape_Header_Chunk (Shape_Sub_Shape_Chunk * parent, const char * hdata, size_t /*hsize*/) + : Chunk (parent, "SUBSHPHD"), + shape_data (parent->shape_data_store) +{ + flags = *((int *) hdata); + hdata += 4; + + file_id_num = *((int *) (hdata)); + hdata += 4; + + parent->shape_data_store->num_verts = *((int *) (hdata)); + hdata += 4; + parent->shape_data_store->num_polys = *((int *) (hdata)); + hdata += 4; + + parent->shape_data_store->radius = *((float *) (hdata)); + hdata += 4; + + parent->shape_data_store->max.x = *((int *) (hdata)); + hdata += 4; + parent->shape_data_store->min.x = *((int *) (hdata)); + hdata += 4; + + parent->shape_data_store->max.y = *((int *) (hdata)); + hdata += 4; + parent->shape_data_store->min.y = *((int *) (hdata)); + hdata += 4; + + parent->shape_data_store->max.z = *((int *) (hdata)); + hdata += 4; + parent->shape_data_store->min.z = *((int *) (hdata)); +} + +Shape_Sub_Shape_Header_Chunk::~Shape_Sub_Shape_Header_Chunk() +{ +} + +size_t Shape_Sub_Shape_Header_Chunk::size_chunk() +{ + return chunk_size = 44 + 12; +} + + +void Shape_Sub_Shape_Header_Chunk::fill_data_block(char * data_start) +{ + + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = flags; + data_start += 4; + + *((int *) (data_start)) = file_id_num; + data_start += 4; + + *((int *) (data_start)) = shape_data->num_verts; + data_start += 4; + *((int *) (data_start)) = shape_data->num_polys; + data_start += 4; + + *((float *) (data_start)) = shape_data->radius; + data_start += 4; + + *((int *) (data_start)) = shape_data->max.x; + data_start += 4; + *((int *) (data_start)) = shape_data->min.x; + data_start += 4; + + *((int *) (data_start)) = shape_data->max.y; + data_start += 4; + *((int *) (data_start)) = shape_data->min.y; + data_start += 4; + + *((int *) (data_start)) = shape_data->max.z; + data_start += 4; + *((int *) (data_start)) = shape_data->min.z; + +} + +///////////////////////////////////////// + + +// Class Shape_Poly_Change_Info_Chunk functions + +RIF_IMPLEMENT_DYNCREATE("SHPPCINF",Shape_Poly_Change_Info_Chunk) + +void Shape_Poly_Change_Info_Chunk::fill_data_block(char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = original_num_verts; + + data_start += 4; + + *((int *) data_start) = change_list.size(); + + data_start += 4; + + for (LIF pcii(&change_list); !pcii.done(); pcii.next()) + { + *((int *) data_start) = pcii().poly_num; + + data_start += 4; + + *((int *) data_start) = pcii().vert_num_before; + + data_start += 4; + + *((int *) data_start) = pcii().vert_num_after; + + data_start += 4; + } + + +} + +Shape_Poly_Change_Info_Chunk::Shape_Poly_Change_Info_Chunk (Chunk_With_Children * parent,const char * data, size_t /*size*/) +: Chunk (parent, "SHPPCINF") +{ + original_num_verts = *((int *) data); + + data += 4; + + int n_entries = *((int *) data); + + data += 4; + + for (int i=0; i (signed)size) { + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + + DynCreate(data); + data += *(int *)(data + 8); + + } + if(!ConstructSequenceDataFromChildren()) + { + //this sequence is no longer valid + delete this; + } +} +Anim_Shape_Sequence_Chunk::Anim_Shape_Sequence_Chunk(Chunk_With_Children * const parent, int sequencenum,const char* name) +: Chunk_With_Children (parent, "ANIMSEQU") +{ + + sequence_data_store=(ChunkAnimSequence*)&sequence_data; + + sequence_data_store->SequenceNum=sequencenum; + sequence_data_store->name=new char[strlen(name)+1]; + strcpy(sequence_data_store->name,name); + RegenerateChildChunks(); +} + +Anim_Shape_Sequence_Chunk::Anim_Shape_Sequence_Chunk(Chunk_With_Children * const parent, ChunkAnimSequence const* cas ) +: Chunk_With_Children (parent, "ANIMSEQU") +{ + + sequence_data_store=(ChunkAnimSequence*)&sequence_data; + *(ChunkAnimSequence*)&sequence_data=*cas; + RegenerateChildChunks(); +} + + +int Anim_Shape_Sequence_Chunk::ConstructSequenceDataFromChildren() +{ + Anim_Shape_Sequence_Data_Chunk* assdc=(Anim_Shape_Sequence_Data_Chunk*)lookup_single_child("ANISEQDT"); + if(!assdc) + { + return 0; + } + sequence_data_store->name=assdc->name; + sequence_data_store->SequenceNum=assdc->SequenceNum; + sequence_data_store->flags=assdc->flags; + sequence_data_store->pad2=assdc->pad2; + sequence_data_store->pad3=assdc->pad3; + sequence_data_store->pad4=assdc->pad4; + + List chlist; + lookup_child("ANIMFRAM",chlist); + sequence_data_store->NumFrames=chlist.size(); + if(sequence_data_store->NumFrames) + { + sequence_data_store->Frames=new ChunkAnimFrame*[sequence_data_store->NumFrames]; + for(int i=0;iNumFrames;i++) + { + sequence_data_store->Frames[i]=0; + } + } + for(LIF chlif(& chlist);!chlif.done();chlif.next()) + { + Anim_Shape_Frame_Chunk* asfc=(Anim_Shape_Frame_Chunk*)chlif(); + + Anim_Shape_Frame_Data_Chunk* asfdc=(Anim_Shape_Frame_Data_Chunk*)asfc->lookup_single_child("ANIFRADT"); + if(!asfdc) return 0; + if(asfdc->FrameNum>=sequence_data_store->NumFrames) return 0; + + if(sequence_data_store->Frames[asfdc->FrameNum])return 0; + sequence_data_store->Frames[asfdc->FrameNum]=new ChunkAnimFrame; + ChunkAnimFrame* caf=sequence_data_store->Frames[asfdc->FrameNum]; + + Shape_Vertex_Chunk* svc=(Shape_Vertex_Chunk*) asfc->lookup_single_child("SHPRAWVT"); + if(!svc)return 0; + + Shape_Polygon_Normal_Chunk* spnc=(Shape_Polygon_Normal_Chunk*)asfc->lookup_single_child("SHPPNORM"); + if(!spnc) return 0; + + caf->name=asfdc->name; + caf->flags=asfdc->flags; + caf->num_interp_frames=asfdc->num_interp_frames; + caf->pad3=asfdc->pad3; + caf->pad4=asfdc->pad4; + + caf->num_verts=svc->num_verts; + caf->v_list=(ChunkVectorInt*)svc->vert_data; + + caf->num_polys=spnc->num_polys; + caf->p_normal_list=(ChunkVectorFloat*)spnc->poly_norm_data; + + } + return 1; +} +void Anim_Shape_Sequence_Chunk::post_input_processing() +{ + + List* poly_not_in_bb=0; + List chlist; + parent->lookup_child("PNOTINBB",chlist); + if(chlist.size()) + poly_not_in_bb=&((Poly_Not_In_Bounding_Box_Chunk*)chlist.first_entry())->poly_no; + if(!strcmp(parent->identifier,"REBSHAPE")) + { + sequence_data_store->UpdateNormalsAndExtents(&((Shape_Chunk*)parent)->shape_data,poly_not_in_bb); + } + else if(!strcmp(parent->identifier,"SUBSHAPE")) + { + sequence_data_store->UpdateNormalsAndExtents(&((Shape_Sub_Shape_Chunk*)parent)->shape_data,poly_not_in_bb); + } + + Chunk_With_Children::post_input_processing(); +} + + +void Anim_Shape_Sequence_Chunk::update_my_sequencedata(ChunkAnimSequence & seq) +{ + *sequence_data_store=seq; + RegenerateChildChunks(); +} + +void Anim_Shape_Sequence_Chunk::set_sequence_flags(int flags) +{ + sequence_data_store->flags=flags; +} +void Anim_Shape_Sequence_Chunk::set_frame_flags(int frameno,int flags) +{ + if(frameno< sequence_data_store->NumFrames) + { + if(sequence_data_store->Frames[frameno]) + { + sequence_data_store->Frames[frameno]->flags=flags; + } + } +} + +void Anim_Shape_Sequence_Chunk::RegenerateChildChunks() +{ + List chlist; + lookup_child("ANISEQDT",chlist); + while(chlist.size()) + { + delete chlist.first_entry(); + chlist.delete_first_entry(); + } + lookup_child("ANIMFRAM",chlist); + while(chlist.size()) + { + delete chlist.first_entry(); + chlist.delete_first_entry(); + } + + new Anim_Shape_Sequence_Data_Chunk(this,sequence_data_store); + for(int i=0;iNumFrames;i++) + { + if(sequence_data_store->Frames[i]->flags & animframeflag_interpolated_frame)continue; + new Anim_Shape_Frame_Chunk(this,sequence_data_store->Frames[i],i); + } +} + +void Anim_Shape_Sequence_Chunk::GenerateInterpolatedFrames() +{ + + if(!strcmp(parent->identifier,"REBSHAPE")) + { + sequence_data_store->GenerateInterpolatedFrames(&((Shape_Chunk*)parent)->shape_data); + } + else if(!strcmp(parent->identifier,"SUBSHAPE")) + { + sequence_data_store->GenerateInterpolatedFrames(&((Shape_Sub_Shape_Chunk*)parent)->shape_data); + } +} +///////////////////////////////////////// + +// Class Anim_Shape_Frame_Chunk functions +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("ANIMFRAM",Anim_Shape_Frame_Chunk,"ANIMSEQU",Anim_Shape_Sequence_Chunk) + +/* +Children for Anim_Shape_Frame_Chunk : + +"ANIFRADT" Anim_Shape_Frame_Data_Chunk +"SHPPNORM" Shape_Polygon_Normal_Chunk +"SHPRAWVT" Shape_Vertex_Chunk +*/ + +Anim_Shape_Frame_Chunk::Anim_Shape_Frame_Chunk(Anim_Shape_Sequence_Chunk *const parent, const char *data, size_t const size) +: Chunk_With_Children (parent, "ANIMFRAM") +{ + const char * buffer_ptr = data; + + while ((data-buffer_ptr)< (signed)size) { + + if ((*(int *)(data + 8)) + (data-buffer_ptr) > (signed)size) { + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + DynCreate(data); + data += *(int *)(data + 8); + } +} + + +Anim_Shape_Frame_Chunk::Anim_Shape_Frame_Chunk(Anim_Shape_Sequence_Chunk * const parent,ChunkAnimFrame* caf,int frameno) +: Chunk_With_Children (parent, "ANIMFRAM") +{ + new Anim_Shape_Frame_Data_Chunk(this,caf,frameno); + new Shape_Vertex_Chunk(this,caf->v_list,caf->num_verts); + new Shape_Polygon_Normal_Chunk(this,caf->p_normal_list,caf->num_polys); + +} +///////////////////////////////////////// + +// Class Anim_Shape_Sequence_Data_Chunk functions + +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("ANISEQDT",Anim_Shape_Sequence_Data_Chunk,"ANIMSEQU",Anim_Shape_Sequence_Chunk) + +Anim_Shape_Sequence_Data_Chunk::Anim_Shape_Sequence_Data_Chunk(Anim_Shape_Sequence_Chunk* const parent,const char* data,size_t const/*datasize*/) +: Chunk(parent, "ANISEQDT") +{ + SequenceNum=*(int*)data; + data+=4; + flags=*(int*)data; + data+=4; + pad2=*(int*)data; + data+=4; + pad3=*(int*)data; + data+=4; + pad4=*(int*)data; + data+=4; + name=new char[strlen(data)+1]; + strcpy(name,data); + +} + +Anim_Shape_Sequence_Data_Chunk::Anim_Shape_Sequence_Data_Chunk(Anim_Shape_Sequence_Chunk* const parent,ChunkAnimSequence* cas) +: Chunk(parent, "ANISEQDT") +{ + SequenceNum=cas->SequenceNum; + name=cas->name; + flags=cas->flags; + pad2=cas->pad2; + pad3=cas->pad3; + pad4=cas->pad4; + +} + +void Anim_Shape_Sequence_Data_Chunk::fill_data_block(char* datastart) +{ + strncpy (datastart, identifier, 8); + datastart += 8; + *((int *) datastart) = chunk_size; + datastart += 4; + + *(int*)datastart=SequenceNum; + datastart+=4; + *(int*)datastart=flags; + datastart+=4; + *(int*)datastart=pad2; + datastart+=4; + *(int*)datastart=pad3; + datastart+=4; + *(int*)datastart=pad4; + datastart+=4; + + strcpy(datastart,name ? name : ""); + +} + +size_t Anim_Shape_Sequence_Data_Chunk::size_chunk() +{ + return chunk_size = 12+20 + +(name ? strlen(name) : 0) + +3 +3&~3; +} + + +///////////////////////////////////////// + +// Class Anim_Shape_Frame_Data_Chunk functions +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("ANIFRADT",Anim_Shape_Frame_Data_Chunk,"ANIMFRAM",Anim_Shape_Frame_Chunk) + +Anim_Shape_Frame_Data_Chunk::Anim_Shape_Frame_Data_Chunk(Anim_Shape_Frame_Chunk* const parent,const char* data,size_t const /*datasize*/) +: Chunk(parent, "ANIFRADT") +{ + FrameNum=*(int*)data; + data+=4; + flags=*(int*)data; + data+=4; + num_interp_frames=*(int*)data; + data+=4; + pad3=*(int*)data; + data+=4; + pad4=*(int*)data; + data+=4; + name=new char[strlen(data)+1]; + strcpy(name,data); + +} + +Anim_Shape_Frame_Data_Chunk::Anim_Shape_Frame_Data_Chunk(Anim_Shape_Frame_Chunk* const parent,ChunkAnimFrame* caf,int frameno) +: Chunk(parent, "ANIFRADT") +{ + FrameNum=frameno; + name=caf->name; + flags=caf->flags; + num_interp_frames=caf->num_interp_frames; + pad3=caf->pad3; + pad4=caf->pad4; + +} + + +void Anim_Shape_Frame_Data_Chunk::fill_data_block(char* datastart) +{ + strncpy (datastart, identifier, 8); + datastart += 8; + *((int *) datastart) = chunk_size; + datastart += 4; + + *(int*)datastart=FrameNum; + datastart+=4; + *(int*)datastart=flags; + datastart+=4; + *(int*)datastart=num_interp_frames; + datastart+=4; + *(int*)datastart=pad3; + datastart+=4; + *(int*)datastart=pad4; + datastart+=4; + + strcpy(datastart,name ? name : ""); + +} + +size_t Anim_Shape_Frame_Data_Chunk::size_chunk() +{ + return chunk_size = 12+20 + +(name ? strlen(name) : 0) + +3 +3&~3; +} + +///////////////////////////////////////// + +// Class Anim_Shape_Alternate_Texturing_Chunk functions +RIF_IMPLEMENT_DYNCREATE("ASALTTEX",Anim_Shape_Alternate_Texturing_Chunk) + +/* +Children for Anim_Shape_Alternate_Texturing_Chunk : +"SUBSHAPE" Shape_Sub_Shape_Chunk +*/ + +Anim_Shape_Alternate_Texturing_Chunk::Anim_Shape_Alternate_Texturing_Chunk(Chunk_With_Children *const parent, const char *data, size_t const size) +: Chunk_With_Children (parent, "ASALTTEX") +{ + const char * buffer_ptr = data; + + while ((data-buffer_ptr)< (signed)size) { + + if ((*(int *)(data + 8)) + (data-buffer_ptr) > (signed)size) { + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + DynCreate(data); + data += *(int *)(data + 8); + } +} + +Shape_Sub_Shape_Chunk* Anim_Shape_Alternate_Texturing_Chunk::CreateNewSubShape(const char* name) +{ + if(!name) return 0; + //check to make sure that name isn't already in use + List chlist; + lookup_child("SUBSHAPE",chlist); + for(LIF chlif(& chlist);!chlif.done();chlif.next()) + { + Shape_Sub_Shape_Chunk* sssc=(Shape_Sub_Shape_Chunk*) chlif(); + if(!_stricmp(name,sssc->get_shape_name()))return 0; + } + ChunkShape cs; + if(!_stricmp(parent->identifier,"REBSHAPE")) + cs=((Shape_Chunk*)parent)->shape_data; + else if(!_stricmp(parent->identifier,"SUBSHAPE")) + cs=((Shape_Sub_Shape_Chunk*)parent)->shape_data; + else + return 0; + Shape_Sub_Shape_Chunk* sssc=new Shape_Sub_Shape_Chunk(this,cs); + new Shape_Name_Chunk(sssc,name); + + + //copy the texture animation data + Chunk_With_Children* anim_chunk=(Chunk_With_Children*)parent->lookup_single_child("TEXTANIM"); + if(anim_chunk) + { + char * tempbuffer = anim_chunk->make_data_block_from_chunk(); + sssc->DynCreate(tempbuffer); + delete [] tempbuffer; + + } + + Shape_Merge_Data_Chunk* smdc=(Shape_Merge_Data_Chunk*)parent->lookup_single_child("SHPMRGDT"); + if(smdc) + { + new Shape_Merge_Data_Chunk(sssc,smdc->merge_data,smdc->num_polys); + } + return sssc; + +} + +///////////////////////////////////////// + +// Class Poly_Not_In_Bounding_Box_Chunk functions +RIF_IMPLEMENT_DYNCREATE("PNOTINBB",Poly_Not_In_Bounding_Box_Chunk) + +Poly_Not_In_Bounding_Box_Chunk::Poly_Not_In_Bounding_Box_Chunk(Chunk_With_Children* const parent,const char* data,size_t const datasize) +:Chunk(parent,"PNOTINBB") +{ + for(int i=0;i<( ( (signed)datasize ) /4)-2;i++) + { + poly_no.add_entry(*(int*)data); + data+=4; + } + pad1=*(int*)data; + data+=4; + pad2=*(int*)data; + +} + +Poly_Not_In_Bounding_Box_Chunk::Poly_Not_In_Bounding_Box_Chunk(Chunk_With_Children* const parent) +:Chunk(parent,"PNOTINBB") +{ + pad1=pad2=0; +} + +size_t Poly_Not_In_Bounding_Box_Chunk::size_chunk() +{ + return chunk_size=(20+4*poly_no.size()); +} + +void Poly_Not_In_Bounding_Box_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + for(LIF plif(&poly_no);!plif.done();plif.next()) + { + *(int*)data_start=plif(); + data_start+=4; + } + *(int*)data_start=pad1; + data_start+=4; + *(int*)data_start=pad2; +} + + +///////////////////////////////////////// + +// Class Anim_Shape_Centre_Chunk functions + +RIF_IMPLEMENT_DYNCREATE("ANSHCEN2",Anim_Shape_Centre_Chunk) + +Anim_Shape_Centre_Chunk::Anim_Shape_Centre_Chunk(Chunk_With_Children* const parent,const char* data,size_t const /*datasize*/) +:Chunk(parent,"ANSHCEN2") +{ + Centre=*(ChunkVectorInt*)data; + data+=sizeof(ChunkVectorInt); + flags=*(int*)data; + data+=4; + pad2=*(int*)data; + +} + +Anim_Shape_Centre_Chunk::Anim_Shape_Centre_Chunk(Chunk_With_Children* const parent) +:Chunk(parent,"ANSHCEN2") +{ + Centre.x=0; + Centre.y=0; + Centre.z=0; + flags=pad2=0; +} + +size_t Anim_Shape_Centre_Chunk::size_chunk() +{ + return chunk_size=(20+sizeof(ChunkVectorInt)); +} + +void Anim_Shape_Centre_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + *(ChunkVectorInt*)data_start=Centre; + data_start+=sizeof(ChunkVectorInt); + *(int*)data_start=flags; + data_start+=4; + *(int*)data_start=pad2; + +} + + + +///////////////////////////////////////// + +// Class Console_Shape_Chunk functions + +/* +Children for Console_Shape_Chunk : + +"SHPPOLYS" Shape_Polygon_Chunk +"SHPUVCRD" Shape_UV_Coord_Chunk +"TEXTANIM" Animation_Chunk + +"CONSTYPE" Console_Type_Chunk +*/ + + +Console_Shape_Chunk::Console_Shape_Chunk(Chunk_With_Children * const parent, const char *data, size_t size) +: Chunk_With_Children (parent, "CONSHAPE") +{ + + shape_data_store=(ChunkShape*)&shape_data; + + const char * buffer_ptr = data; + + while ((data-buffer_ptr)< (signed)size) { + + if ((*(int *)(data + 8)) + (data-buffer_ptr) > (signed)size) { + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + + DynCreate(data); + data += *(int *)(data + 8); + } + } + +} + +Console_Shape_Chunk::Console_Shape_Chunk(Chunk_With_Children* const parent,Console_Type ct) +:Chunk_With_Children(parent,"CONSHAPE") +{ + shape_data_store=(ChunkShape*)&shape_data; + new Console_Type_Chunk(this,ct); +} +void Console_Shape_Chunk::generate_console_chunkshape() +{ + //sort out the chunkshape + if(!strcmp(parent->identifier,"REBSHAPE")) + { + *shape_data_store=((Shape_Chunk*)parent)->shape_data; + } + else if(!strcmp(parent->identifier,"SUBSHAPE")) + { + *shape_data_store=((Shape_Sub_Shape_Chunk*)parent)->shape_data; + } + else + { + delete this; + return; + } + + Shape_Polygon_Chunk* spc=(Shape_Polygon_Chunk*)lookup_single_child("SHPPOLYS"); + if(spc) + { + if(spc->num_polys!=shape_data_store->num_polys) + { + //console shape is no longer valid.kill it. + delete this; + return; + } + + ChunkPoly* poly_list=shape_data_store->poly_list; + shape_data_store->poly_list=(ChunkPoly*)spc->poly_data; + for(int i=0;inum_polys;i++) + { + for(int j=0;j<4;j++) + { + shape_data_store->poly_list[i].vert_ind[j]=poly_list[i].vert_ind[j]; + } + } + delete [] poly_list; + } + Shape_UV_Coord_Chunk* succ=(Shape_UV_Coord_Chunk*)lookup_single_child("SHPUVCRD"); + if(succ) + { + delete [] shape_data_store->uv_list; + shape_data_store->uv_list=(ChunkUV_List*)succ->uv_data; + shape_data_store->num_uvs=succ->num_uvs; + } +} + +void Console_Shape_Chunk::update_my_chunkshape(ChunkShape & cshp) +{ + List chlist; + lookup_child("SHPUVCRD",chlist); + while(chlist.size()) + { + delete chlist.first_entry(); + chlist.delete_first_entry(); + } + lookup_child("SHPPOLYS",chlist); + while(chlist.size()) + { + delete chlist.first_entry(); + chlist.delete_first_entry(); + } + *shape_data_store=cshp; + if (shape_data.poly_list) new Shape_Polygon_Chunk (this, shape_data.num_polys); + if (shape_data.uv_list) new Shape_UV_Coord_Chunk (this, shape_data.num_uvs); + +} + + +///////////////////////////////////////// + +// Class Console_Type_Chunk functions +RIF_IMPLEMENT_DYNCREATE("CONSTYPE",Console_Type_Chunk) + +void Console_Type_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + *(int*)data_start=(int)console; +} + + +///////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("SHPPRPRO",Shape_Preprocessed_Data_Chunk) + +Shape_Preprocessed_Data_Chunk::Shape_Preprocessed_Data_Chunk (Chunk_With_Children * parent, const char * data, size_t ) +:Chunk(parent,"SHPPRPRO") +{ + block_size=*(int*)data; + data+=4; + first_pointer=*(int*)data; + data+=4; + + if(block_size) + { + memory_block=new unsigned int[block_size]; + memcpy(memory_block,data,block_size*4); + data+=block_size*4; + } + else + { + memory_block=0; + } + + num_extra_data=*(int*)data; + data+=4; + + if(num_extra_data) + { + extra_data=new int[num_extra_data]; + memcpy(extra_data,data,num_extra_data*4); + } + else + { + extra_data=0; + } +} + +Shape_Preprocessed_Data_Chunk::Shape_Preprocessed_Data_Chunk (Chunk_With_Children * parent,int _block_size,int _first_pointer,unsigned int* _memory_block) +:Chunk(parent,"SHPPRPRO") +{ + num_extra_data=0; + extra_data=0; + block_size=_block_size; + first_pointer=_first_pointer; + + if(block_size) + { + memory_block=new unsigned int[block_size]; + memcpy(memory_block,_memory_block,block_size*4); + } + else + { + memory_block=0; + } + +} + +void Shape_Preprocessed_Data_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + *(int*)data_start=block_size; + data_start+=4; + *(int*)data_start=first_pointer; + data_start+=4; + + memcpy(data_start,memory_block,4*block_size); + data_start+=4*block_size; + + *(int*)data_start=num_extra_data; + data_start+=4; + memcpy(data_start,extra_data,4*num_extra_data); +} + +void* Shape_Preprocessed_Data_Chunk::GetMemoryBlock() +{ + void* retval=memory_block; + + unsigned int* current=(unsigned int*)&first_pointer; + unsigned int* next; + while((*current>>16)!=0xffff) + { + next=&memory_block[(*current)>>16]; + *current=(unsigned int)&memory_block[(*current)&0xffff]; + current=next; + } + *current=(unsigned int)&memory_block[(*current)&0xffff]; + + memory_block=0; + block_size=0; + return retval; +} + diff --git a/3dc/win95/SHPCHUNK.HPP b/3dc/win95/SHPCHUNK.HPP new file mode 100644 index 0000000..1529d19 --- /dev/null +++ b/3dc/win95/SHPCHUNK.HPP @@ -0,0 +1,1095 @@ +#ifndef _shpchunk_hpp +#define _shpchunk_hpp 1 + +#include "chunk.hpp" + +#include "chnktype.hpp" +#include "mishchnk.hpp" + +// shape flags + +#define SHAPE_FLAG_PALETTISED 0x0000100 +#define SHAPE_FLAG_USEZSP 0x0000200 +#define SHAPE_FLAG_USEAUGZS 0x0000400 +#define SHAPE_FLAG_USEAUGZSL 0x0000800 +#define SHAPE_FLAG_EXTERNALFILE 0x0001000 +#define SHAPE_FLAG_RECENTRED 0x0002000 + + +#define SHAPE_FLAG_UNSTABLEBOUND_ZPOS 0x00004000 +#define SHAPE_FLAG_UNSTABLEBOUND_ZNEG 0x00008000 +#define SHAPE_FLAG_UNSTABLEBOUND_YPOS 0x00010000 +#define SHAPE_FLAG_UNSTABLEBOUND_YNEG 0x00020000 +#define SHAPE_FLAG_UNSTABLEBOUND_XPOS 0x00040000 +#define SHAPE_FLAG_UNSTABLEBOUND_XNEG 0x00080000 + +#define SHAPE_FLAG_PSX_SUBDIVIDE 0x80000000 + +//flags that need to be removed before being copied into the shapeheaders +#define ChunkInternalItemFlags 0x00000000 + +class Object_Chunk; +class Shape_Header_Chunk; +class Anim_Shape_Frame_Chunk; +class Console_Shape_Chunk; +// flags structure + +struct shape_flags +{ + unsigned int locked : 1; +// add more flags here as they are needed +}; + +enum Console_Type +{ + CT_PSX=0, + CT_Saturn=1, + + // IMPORTANT + // since enums are not guaranteed to assume any particular + // storage class, code compiled on different compilers or + // with different settings may result in enums to be written + // to the data block as a char and read back in as an int, + // with the three most significant bytes containing junk. + // THIS MASK MUST BE KEPT UP TO DATE AS THE ENUM IS EXTENDED; + // ALSO ENSURE THAT NEW FILES LOADED INTO OLD SOFTWARE WILL + // NOT HAVE THEIR ENUM VALUE OVER-MASKED; THE MASK IS ONLY + // HERE TO ATTEMPT TO REMOVE PROBLEMS FROM FILES MADE + // PRIOR TO ITS INTRODUCTION + CT_MASK=0xff +}; + +// The shape chunk contains and handles all the interface data for the +// child chunks that it recognises in ChunkShape + +/*--------------------------------------------------------------------** +** N.B. all changes to shape formats should be made to the sub shapes ** +**--------------------------------------------------------------------*/ + +class Shape_Chunk : public Lockable_Chunk_With_Children +{ +public: + + // constructor from buffer + Shape_Chunk (Chunk_With_Children * parent, const char *, size_t); + + // constructor from data (public so that other shape tools can call) + Shape_Chunk (Chunk_With_Children * parent, ChunkShape &shp_dat); + + // I want the external file load to be as transparent as possible + // i.e. we have a shape which is loaded as usaul - it should then + // load the shape which is its main copy and copy itself over !!! + + // Problems will be encountered with the texturing data though - + // but this stuff should onyl be worked with with a hardware + // accelerator - so that should solve many of the problems + + // destructor + virtual ~Shape_Chunk(); + + const ChunkShape shape_data; + + Shape_Header_Chunk * get_header(); + + Shape_Chunk* make_copy_of_chunk(); + + List const & list_assoc_objs(); + + BOOL assoc_with_object(Object_Chunk *); + + BOOL deassoc_with_object(Object_Chunk *); + + // destroy all auxiliary chunks + // that is all except the header and the chunkshape + void destroy_auxiliary_chunks(); + + // functions for the locking functionality + + BOOL file_equals (HANDLE &); + const char * get_head_id(); + void set_lock_user(char *); + + virtual void post_input_processing(); + + Console_Shape_Chunk* get_console_shape_data(Console_Type); + + BOOL inc_v_no(); + + BOOL same_and_updated(Shape_Chunk &); + + BOOL assoc_with_object_list(File_Chunk *); + + BOOL update_my_chunkshape (ChunkShape & cshp); + + // THIS IS A HACK, DO NOT USE AFTER AVP AUGUST DEMO + + BOOL has_door; + +private: + + friend class Object_Chunk; + friend class Shape_Vertex_Chunk; + friend class Shape_Vertex_Normal_Chunk; + friend class Shape_Polygon_Normal_Chunk; + friend class Shape_Polygon_Chunk; + friend class Shape_Texture_Filenames_Chunk; + friend class Shape_UV_Coord_Chunk; + friend class Shape_Header_Chunk; + friend class Shape_External_File_Chunk; + friend class RIF_File_Chunk; + friend class File_Chunk; + friend class Shape_Centre_Chunk; + + ChunkShape * shape_data_store; + + static int max_id; // for id checking + +}; + +/////////////////////////////////////////////// + +class Shape_Sub_Shape_Header_Chunk; + +class Shape_Sub_Shape_Chunk : public Chunk_With_Children +{ +public: + + // constructor from buffer + Shape_Sub_Shape_Chunk (Chunk_With_Children * parent, const char *, size_t); + + // constructor from data (public so that other shape tools can call) + Shape_Sub_Shape_Chunk (Chunk_With_Children * parent, ChunkShape &shp_dat); + + // destructor + virtual ~Shape_Sub_Shape_Chunk(); + + const ChunkShape shape_data; + + Shape_Sub_Shape_Header_Chunk * get_header(); + + Shape_Sub_Shape_Chunk* make_copy_of_chunk(); + + BOOL update_my_chunkshape (ChunkShape & cshp); + + const char * get_shape_name(); + + Console_Shape_Chunk* get_console_shape_data(Console_Type); + + // Number stored for list_pos when loading + + int list_pos_number; + +private: + + friend class Shape_Vertex_Chunk; + friend class Shape_Vertex_Normal_Chunk; + friend class Shape_Polygon_Normal_Chunk; + friend class Shape_Polygon_Chunk; + friend class Shape_Texture_Filenames_Chunk; + friend class Shape_UV_Coord_Chunk; + friend class Shape_Sub_Shape_Header_Chunk; + friend class Shape_Centre_Chunk; + + ChunkShape * shape_data_store; + +}; + +/////////////////////////////////////////////// + +class Shape_Sub_Shape_Header_Chunk : public Chunk +{ +public: + // constructor from buffer + Shape_Sub_Shape_Header_Chunk (Shape_Sub_Shape_Chunk * parent, const char * pdata, size_t psize); + + ~Shape_Sub_Shape_Header_Chunk(); + + virtual size_t size_chunk (); + + virtual void fill_data_block (char * data_start); + + const ChunkShape * const shape_data; + + int file_id_num; + + int flags; + +private: + + friend class Shape_Sub_Shape_Chunk; + friend class Shape_Morphing_Frame_Data_Chunk; + + + + // constructor from data + Shape_Sub_Shape_Header_Chunk (Shape_Sub_Shape_Chunk * parent) + : Chunk (parent, "SUBSHPHD"), + shape_data (parent->shape_data_store), + flags (0), file_id_num (-1) + {} + +}; + + +/////////////////////////////////////////////// +#define AnimCentreFlag_CentreSetByUser 0x00000001 //centre should not be recalculated from the extents of the sequences + +class Anim_Shape_Centre_Chunk : public Chunk +{ + public: + Anim_Shape_Centre_Chunk(Chunk_With_Children* const parent,const char*,size_t const); + Anim_Shape_Centre_Chunk(Chunk_With_Children* const parent); + + ChunkVectorInt Centre; + int flags; + int pad2; + + virtual void fill_data_block(char* data_start); + virtual size_t size_chunk(); +}; +/////////////////////////////////////////////// +class Anim_Shape_Sequence_Chunk :public Chunk_With_Children +{ + public: +//if the first constructor is used then the vertex normals and extents won't be calculated +//unless the post_input_processing function is called + Anim_Shape_Sequence_Chunk(Chunk_With_Children* const parent,const char*,size_t const); + Anim_Shape_Sequence_Chunk(Chunk_With_Children* const parent,int sequencenum,const char* name); + Anim_Shape_Sequence_Chunk(Chunk_With_Children* const parent,ChunkAnimSequence const* cas); + + virtual void post_input_processing(); + + const ChunkAnimSequence sequence_data; + + void update_my_sequencedata (ChunkAnimSequence &); + + void set_sequence_flags(int flags); + void set_frame_flags(int frameno,int flags); + + void GenerateInterpolatedFrames(); + + private : + ChunkAnimSequence *sequence_data_store; + + int ConstructSequenceDataFromChildren();//copies everyting into the sequence_data + void RegenerateChildChunks(); +}; + +/////////////////////////////////////////////// +class Anim_Shape_Sequence_Data_Chunk:public Chunk +{ + public: + Anim_Shape_Sequence_Data_Chunk(Anim_Shape_Sequence_Chunk* const parent,const char*,size_t const); + Anim_Shape_Sequence_Data_Chunk(Anim_Shape_Sequence_Chunk* const parent,ChunkAnimSequence* cas); + + private: + friend class Anim_Shape_Sequence_Chunk; + + int SequenceNum; + int flags,pad2,pad3,pad4; + char* name; + + virtual size_t size_chunk(); + + virtual void fill_data_block(char* data_start); +}; + +/////////////////////////////////////////////// +class Anim_Shape_Frame_Chunk : public Chunk_With_Children +{ + public: + Anim_Shape_Frame_Chunk(Anim_Shape_Sequence_Chunk* const parent,const char*,size_t const); + Anim_Shape_Frame_Chunk(Anim_Shape_Sequence_Chunk * const parent,ChunkAnimFrame* caf,int frameno); +}; + +/////////////////////////////////////////////// +class Anim_Shape_Frame_Data_Chunk : public Chunk +{ + public: + Anim_Shape_Frame_Data_Chunk(Anim_Shape_Frame_Chunk* const parent,const char*,size_t const); + Anim_Shape_Frame_Data_Chunk(Anim_Shape_Frame_Chunk* const parent,ChunkAnimFrame* caf,int frameno); + + private: + friend class Anim_Shape_Frame_Chunk; + friend class Anim_Shape_Sequence_Chunk; + + int FrameNum; + int flags,num_interp_frames,pad3,pad4; + char* name;//name of asc file for frame + + virtual size_t size_chunk(); + + virtual void fill_data_block(char* data_start); +}; +/////////////////////////////////////////////// +class Anim_Shape_Alternate_Texturing_Chunk : public Chunk_With_Children +{ + public : + Anim_Shape_Alternate_Texturing_Chunk(Chunk_With_Children* const parent,const char*,size_t const); + Anim_Shape_Alternate_Texturing_Chunk(Chunk_With_Children* const parent) + :Chunk_With_Children(parent,"ASALTTEX") + {} + + Shape_Sub_Shape_Chunk* CreateNewSubShape(const char* name); +}; +/////////////////////////////////////////////// +class Poly_Not_In_Bounding_Box_Chunk : public Chunk +{ + public : + Poly_Not_In_Bounding_Box_Chunk(Chunk_With_Children* const parent,const char*,size_t const); + Poly_Not_In_Bounding_Box_Chunk(Chunk_With_Children* const parent); + + virtual size_t size_chunk(); + + virtual void fill_data_block(char* data_start); + + + List poly_no; + int pad1,pad2; +}; +/////////////////////////////////////////////// + +class Console_Type_Chunk: public Chunk +{ + public : + Console_Type_Chunk(Chunk_With_Children* const parent,const char* data,size_t) + :Chunk(parent,"CONSTYPE"),console((Console_Type)(*(int*)data & CT_MASK)) + {} + Console_Type_Chunk(Chunk_With_Children* const parent,Console_Type ct) + :Chunk(parent,"CONSTYPE"),console(ct) + {} + + Console_Type console; + + virtual size_t size_chunk() + {return chunk_size=16;} + + virtual void fill_data_block(char * data_start); +}; +/////////////////////////////////////////////// +class Console_Shape_Chunk : public Chunk_With_Children +{ + public : + Console_Shape_Chunk(Chunk_With_Children* const parent,const char*,size_t); + Console_Shape_Chunk(Chunk_With_Children* const parent,Console_Type ct); + + const ChunkShape shape_data; + + void generate_console_chunkshape();//needs parent's chunkshape to be set up first + + void update_my_chunkshape(ChunkShape&); + private: + friend class Shape_Polygon_Chunk; + friend class Shape_UV_Coord_Chunk; + ChunkShape * shape_data_store; +}; +/////////////////////////////////////////////// + +class Shape_Vertex_Chunk : public Chunk +{ +public: + + + virtual size_t size_chunk () + { + return (chunk_size = (12 + (num_verts*sizeof(ChunkVectorInt)))); + } + + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start); + + const ChunkVectorInt * const vert_data; + + const int num_verts; + + // constructor from buffer + Shape_Vertex_Chunk (Shape_Sub_Shape_Chunk * parent, const char * vtdata, size_t vtsize); + Shape_Vertex_Chunk (Shape_Chunk * parent, const char * vtdata, size_t vtsize); + Shape_Vertex_Chunk (Anim_Shape_Frame_Chunk * parent, const char * vtdata, size_t vtsize); +private: + + friend class Shape_Chunk; + friend class Shape_Sub_Shape_Chunk; + friend class Anim_Shape_Frame_Chunk; + + + // constructor from data + Shape_Vertex_Chunk (Shape_Sub_Shape_Chunk * parent, int n_verts) + : Chunk (parent, "SHPRAWVT"), + vert_data (parent->shape_data_store->v_list), num_verts (n_verts) + {} + + Shape_Vertex_Chunk (Shape_Chunk * parent, int n_verts) + : Chunk (parent, "SHPRAWVT"), + vert_data (parent->shape_data_store->v_list), num_verts (n_verts) + {} + + Shape_Vertex_Chunk (Anim_Shape_Frame_Chunk * parent,ChunkVectorInt* v_list ,int n_verts) + : Chunk (parent, "SHPRAWVT"), + vert_data (v_list), num_verts (n_verts) + {} + +}; + + +/////////////////////////////////////////////// + +class Shape_Vertex_Normal_Chunk: public Chunk +{ +public: + // constructor from buffer + Shape_Vertex_Normal_Chunk (Shape_Sub_Shape_Chunk * parent, const char * vtdata, size_t vtsize); + Shape_Vertex_Normal_Chunk (Shape_Chunk * parent, const char * vtdata, size_t vtsize); + + virtual size_t size_chunk () + { + return (chunk_size = (12 + (num_verts*sizeof(ChunkVectorFloat)))); + } + + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start); + + const ChunkVectorFloat * const vert_norm_data; + + const int num_verts; + +private: + + friend class Shape_Chunk; + friend class Shape_Sub_Shape_Chunk; + + + // constructor from data + Shape_Vertex_Normal_Chunk (Shape_Sub_Shape_Chunk * parent, int n_verts) + : Chunk (parent, "SHPVNORM"), + vert_norm_data (parent->shape_data_store->v_normal_list), num_verts (n_verts) + {} + + Shape_Vertex_Normal_Chunk (Shape_Chunk * parent, int n_verts) + : Chunk (parent, "SHPVNORM"), + vert_norm_data (parent->shape_data_store->v_normal_list), num_verts (n_verts) + {} + +}; + + +/////////////////////////////////////////////// + +class Shape_Polygon_Normal_Chunk: public Chunk +{ +public: + // constructor from buffer + Shape_Polygon_Normal_Chunk (Shape_Sub_Shape_Chunk * parent, const char * pndata, size_t pnsize); + Shape_Polygon_Normal_Chunk (Shape_Chunk * parent, const char * pndata, size_t pnsize); + Shape_Polygon_Normal_Chunk (Anim_Shape_Frame_Chunk * parent, const char * pndata, size_t pnsize); + + virtual size_t size_chunk () + { + return (chunk_size = (12 + (num_polys*sizeof(ChunkVectorFloat)))); + } + + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start); + + const ChunkVectorFloat * const poly_norm_data; + + const int num_polys; + +private: + + friend class Shape_Chunk; + friend class Shape_Sub_Shape_Chunk; + friend class Anim_Shape_Frame_Chunk; + + + + // constructor from data + Shape_Polygon_Normal_Chunk (Shape_Sub_Shape_Chunk * parent, int n_polys) + : Chunk (parent, "SHPPNORM"), + poly_norm_data (parent->shape_data_store->p_normal_list), num_polys (n_polys) + {} + + Shape_Polygon_Normal_Chunk (Shape_Chunk * parent, int n_polys) + : Chunk (parent, "SHPPNORM"), + poly_norm_data (parent->shape_data_store->p_normal_list), num_polys (n_polys) + {} + + Shape_Polygon_Normal_Chunk (Anim_Shape_Frame_Chunk * parent,ChunkVectorFloat* p_normal_list ,int n_polys) + : Chunk (parent, "SHPPNORM"), + poly_norm_data (p_normal_list), num_polys (n_polys) + {} + +}; + + +/////////////////////////////////////////////// + +class Shape_Polygon_Chunk : public Chunk +{ +public: + // constructor from buffer + Shape_Polygon_Chunk (Shape_Sub_Shape_Chunk * parent, const char * pdata, size_t psize); + Shape_Polygon_Chunk (Shape_Chunk * parent, const char * pdata, size_t psize); + Shape_Polygon_Chunk (Console_Shape_Chunk * parent, const char * pdata, size_t psize); + + virtual size_t size_chunk () + { + return (chunk_size = (12 + (num_polys*36)));// 36 bytes per vertex + } + + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start); + + const ChunkPoly * const poly_data; + + const int num_polys; + +private: + + friend class Shape_Chunk; + friend class Shape_Sub_Shape_Chunk; + friend class Console_Shape_Chunk; + + + + // constructor from data + Shape_Polygon_Chunk (Shape_Sub_Shape_Chunk * parent, int n_polys) + : Chunk (parent, "SHPPOLYS"), + poly_data (parent->shape_data_store->poly_list), num_polys (n_polys) + {} + + Shape_Polygon_Chunk (Shape_Chunk * parent, int n_polys) + : Chunk (parent, "SHPPOLYS"), + poly_data (parent->shape_data_store->poly_list), num_polys (n_polys) + {} + + Shape_Polygon_Chunk (Console_Shape_Chunk * parent, int n_polys) + : Chunk (parent, "SHPPOLYS"), + poly_data (parent->shape_data_store->poly_list), num_polys (n_polys) + {} + +}; + +/////////////////////////////////////////////// + +class Shape_Header_Chunk : public Chunk +{ +public: + // constructor from buffer + Shape_Header_Chunk (Shape_Chunk * parent, const char * pdata, size_t psize); + + ~Shape_Header_Chunk(); + + virtual size_t size_chunk (); + + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start); + + const ChunkShape * const shape_data; + + virtual void prepare_for_output(); + + char lock_user[17]; + + List object_names_store; + + int flags; + +private: + + friend class Shape_Chunk; + friend class Object_Chunk; + friend class RIF_File_Chunk; + friend class File_Chunk; + friend class Environment; + friend class Shape_Morphing_Frame_Data_Chunk; + friend class Shape_External_File_Chunk; + + int version_no; + + int file_id_num; + + List associated_objects_store; + + + + // constructor from data + Shape_Header_Chunk (Shape_Chunk * parent) + : Chunk (parent, "SHPHEAD1"), + shape_data (parent->shape_data_store), + flags (0), file_id_num (-1), version_no (0) + {} + +}; +/////////////////////////////////////////////// +class Shape_Centre_Chunk : public Chunk +{ +public : + // constructor from buffer + Shape_Centre_Chunk (Chunk_With_Children * parent, const char * data, size_t datasize); + + virtual size_t size_chunk () + {return chunk_size=4*4+12;} + + virtual void fill_data_block (char * data_start); + +private: + + friend class Shape_Chunk; + friend class Shape_Sub_Shape_Chunk; + + + // constructor from data + Shape_Centre_Chunk (Chunk_With_Children * parent) + : Chunk (parent, "SHPCENTR") + {} + + //the data for this chunk is stored in its parent's ChunkShape +}; +/////////////////////////////////////////////// + +class Shape_UV_Coord_Chunk : public Chunk +{ +public: + // constructor from buffer + Shape_UV_Coord_Chunk (Shape_Sub_Shape_Chunk * parent, const char * uvdata, size_t uvsize); + Shape_UV_Coord_Chunk (Shape_Chunk * parent, const char * uvdata, size_t uvsize); + Shape_UV_Coord_Chunk (Console_Shape_Chunk * parent, const char * uvdata, size_t uvsize); + + virtual size_t size_chunk (); + + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start); + + const ChunkUV_List * const uv_data; + + const int num_uvs; + +private: + + friend class Shape_Chunk; + friend class Shape_Sub_Shape_Chunk; + friend class Console_Shape_Chunk; + + + // constructor from data + Shape_UV_Coord_Chunk (Shape_Sub_Shape_Chunk * parent, int n_uvs) + : Chunk (parent, "SHPUVCRD"), + uv_data (parent->shape_data_store->uv_list), num_uvs (n_uvs) + {} + + Shape_UV_Coord_Chunk (Shape_Chunk * parent, int n_uvs) + : Chunk (parent, "SHPUVCRD"), + uv_data (parent->shape_data_store->uv_list), num_uvs (n_uvs) + {} + + Shape_UV_Coord_Chunk (Console_Shape_Chunk * parent, int n_uvs) + : Chunk (parent, "SHPUVCRD"), + uv_data (parent->shape_data_store->uv_list), num_uvs (n_uvs) + {} + +}; + +/////////////////////////////////////////////// + +class Shape_Texture_Filenames_Chunk : public Chunk +{ +public: + // constructor from buffer + Shape_Texture_Filenames_Chunk (Shape_Sub_Shape_Chunk * parent, const char * tfndata, size_t tfnsize); + Shape_Texture_Filenames_Chunk (Shape_Chunk * parent, const char * tfndata, size_t tfnsize); + + virtual size_t size_chunk (); + + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start); + + char ** tex_fns; + + const int num_tex_fns; + +private: + + friend class Shape_Chunk; + friend class Shape_Sub_Shape_Chunk; + + + // constructor from data + Shape_Texture_Filenames_Chunk (Shape_Sub_Shape_Chunk * parent, int n_tfns) + : Chunk (parent, "SHPTEXFN"), + tex_fns (parent->shape_data_store->texture_fns), num_tex_fns (n_tfns) + {} + + Shape_Texture_Filenames_Chunk (Shape_Chunk * parent, int n_tfns) + : Chunk (parent, "SHPTEXFN"), + tex_fns (parent->shape_data_store->texture_fns), num_tex_fns (n_tfns) + {} + + +}; + + + +/////////////////////////////////////////////// + +class Shape_Merge_Data_Chunk : public Chunk +{ +public: + + Shape_Merge_Data_Chunk (Shape_Sub_Shape_Chunk * parent, int *, int); + Shape_Merge_Data_Chunk (Shape_Chunk * parent, int *, int); + + ~Shape_Merge_Data_Chunk (); + + int * merge_data; + int num_polys; + + size_t size_chunk() + { + return chunk_size = 12 + num_polys*4; + } + + void fill_data_block (char *); + + Shape_Merge_Data_Chunk (Shape_Sub_Shape_Chunk * parent, const char *, size_t); + Shape_Merge_Data_Chunk (Shape_Chunk * parent, const char *, size_t); + +}; + + +/////////////////////////////////////////////// + +class Shape_External_File_Chunk : public Chunk_With_Children +{ +public: + + Shape_External_File_Chunk (Chunk_With_Children * parent, const char * fname); + Shape_External_File_Chunk (Chunk_With_Children * const parent, const char *, size_t const); + + void post_input_processing(); + + #if cencon || InterfaceEngine + void update_from_external_rif(BOOL force_scale_update); + #endif + + //gets name from shape_external_object_name_chunk if it has one + //otherwise takes name from rif_name_chunk + const char * get_shape_name(); +private: + + friend class Shape_Chunk; + friend class Shape_Sub_Shape_Chunk; + + //Used to avoid updating external shapes in files that have been loaded + //by Shape_External_File_Chunk::post_input_processing + static BOOL UpdatingExternalShape; + +}; + + +/////////////////////////////////////////////// + + +class Shape_External_Filename_Chunk : public Chunk +{ +public: + + Shape_External_Filename_Chunk (Chunk_With_Children * parent, const char * fname); + Shape_External_Filename_Chunk (Chunk_With_Children * parent, const char *, size_t); + ~Shape_External_Filename_Chunk (); + + // Here is stored the shape name, rescale value and version number. + + char * file_name; + + double rescale; + + int version_no; + + size_t size_chunk() + { + return chunk_size = 12 + 8 + 4 + strlen(file_name) + (4-strlen(file_name)%4); + } + + void fill_data_block (char *); + + +private: + + friend class Shape_External_File_Chunk; + friend class Sprite_Header_Chunk; + + +}; + + + +/////////////////////////////////////////////// + +//This is needed if more than one shape is being imported from a rif file +class Shape_External_Object_Name_Chunk : public Chunk +{ +public : + Shape_External_Object_Name_Chunk(Chunk_With_Children * parent, const char * fname); + Shape_External_Object_Name_Chunk (Chunk_With_Children * parent, const char *, size_t); + ~Shape_External_Object_Name_Chunk(); + + int pad; + char* object_name; + char* shape_name; //a combination of object and file name + size_t size_chunk() + { + return chunk_size = 12 +4+ strlen(object_name) + (4-strlen(object_name)%4); + } + + void post_input_processing(); + + void fill_data_block (char *); + +private: + + friend class Shape_External_File_Chunk; + +}; + +/////////////////////////////////////////////// + +class Shape_Morphing_Data_Chunk : public Chunk_With_Children +{ +public: + + Shape_Morphing_Data_Chunk (Shape_Chunk * parent) + : Chunk_With_Children (parent, "SHPMORPH"), parent_shape (parent) {} + + Shape_Chunk * parent_shape; + Shape_Sub_Shape_Chunk * parent_sub_shape; + + virtual void prepare_for_output(); + + Shape_Morphing_Data_Chunk (Shape_Chunk * parent, const char *, size_t); + Shape_Morphing_Data_Chunk (Shape_Sub_Shape_Chunk * parent, const char *, size_t); + +}; + + +/////////////////////////////////////////////// + +class Shape_Morphing_Frame_Data_Chunk : public Chunk +{ +public: + + // constructor from wherever + Shape_Morphing_Frame_Data_Chunk (Shape_Morphing_Data_Chunk * parent) + : Chunk (parent, "FRMMORPH"), frame_store (0), num_frames(0) + {} + // constructor from buffer + Shape_Morphing_Frame_Data_Chunk (Shape_Morphing_Data_Chunk * parent,const char *, size_t); + + ~Shape_Morphing_Frame_Data_Chunk(); + + int a_flags; + int a_speed; + + List anim_frames; + + virtual void fill_data_block (char *); + virtual size_t size_chunk () + { + return (chunk_size = 12 + 12 + num_frames * 12); + } + + virtual void prepare_for_output(); + virtual void post_input_processing(); + +private: + + int num_frames; + int * frame_store; + + friend class Shape_Morphing_Data_Chunk; + + +}; + +/////////////////////////////////////////////// + +class Shape_Poly_Change_Info_Chunk : public Chunk +{ +public: + + Shape_Poly_Change_Info_Chunk (Shape_Chunk * parent, List & pci, int orig_num_v) + : Chunk (parent, "SHPPCINF"), change_list (pci), original_num_verts (orig_num_v) + {} + + int original_num_verts; + List change_list; + + virtual void fill_data_block (char *); + virtual size_t size_chunk () + { + return (chunk_size = 12 + 4 + 4 + change_list.size() * 12); + } + + Shape_Poly_Change_Info_Chunk (Chunk_With_Children * parent,const char *, size_t); +}; + +/////////////////////////////////////////////// + +class Shape_Name_Chunk : public Chunk +{ +public: + Shape_Name_Chunk (Chunk_With_Children * parent, const char * rname); + // constructor from buffer + Shape_Name_Chunk (Chunk_With_Children * parent, const char * sdata, size_t ssize); + ~Shape_Name_Chunk(); + + char * shape_name; + + virtual size_t size_chunk () + { + return (chunk_size = 12 + strlen (shape_name) + 4 - strlen (shape_name)%4); + } + + virtual void fill_data_block (char * data_start); + +private: + + friend class Shape_Sub_Shape_Chunk; + +}; + +/////////////////////////////////////////////// + +class Shape_Fragments_Chunk : public Chunk_With_Children +{ +public: + + Shape_Fragments_Chunk (Chunk_With_Children * parent) + : Chunk_With_Children (parent, "SHPFRAGS") + {} + + Shape_Fragments_Chunk (Chunk_With_Children * const parent, char const *, const size_t); + +}; + +/////////////////////////////////////////////// +class Shape_Fragment_Type_Chunk : public Chunk +{ +public : + Shape_Fragment_Type_Chunk(Chunk_With_Children* parent,const char* name); + Shape_Fragment_Type_Chunk (Chunk_With_Children * const parent,const char *, size_t const); + ~Shape_Fragment_Type_Chunk(); + + size_t size_chunk (); + void fill_data_block (char * data_start); + + char* frag_type_name; + int pad1,pad2; + + + +}; +/////////////////////////////////////////////// + +class Shape_Fragments_Data_Chunk : public Chunk +{ +public: + + Shape_Fragments_Data_Chunk (Chunk_With_Children * parent, int num_frags) + : Chunk (parent, "FRAGDATA"), num_fragments (num_frags), + pad1(0), pad2(0), pad3(0) + {} + Shape_Fragments_Data_Chunk (Chunk_With_Children * parent, const char * sdata, size_t ssize); + + int num_fragments; + + int pad1, pad2, pad3; + + virtual size_t size_chunk () + { + return (chunk_size = 12 + 16); + } + + virtual void fill_data_block (char *); + +private: + + friend class Shape_Sub_Shape_Chunk; + + +}; + +/////////////////////////////////////////////// + +class Shape_Fragment_Location_Chunk : public Chunk +{ +public: + + Shape_Fragment_Location_Chunk (Chunk_With_Children * parent, ChunkVectorInt & location) + : Chunk (parent, "FRAGLOCN"), frag_loc (location), + pad1(0), pad2(0), pad3(0), pad4(0) + {} + Shape_Fragment_Location_Chunk (Chunk_With_Children * parent, const char * sdata, size_t ssize); + + ChunkVectorInt frag_loc; + + int pad1, pad2, pad3, pad4; + + virtual size_t size_chunk () + { + return (chunk_size = 12 + 28); + } + + virtual void fill_data_block (char *); + +private: + + friend class Shape_Sub_Shape_Chunk; + + +}; + +/////////////////////////////////////////////// +class Shape_Preprocessed_Data_Chunk : public Chunk +{ +public: + + Shape_Preprocessed_Data_Chunk (Chunk_With_Children * parent,int _blocksize,int _first_pointer,unsigned int* _memory_block); + Shape_Preprocessed_Data_Chunk (Chunk_With_Children * parent, const char * data, size_t ssize); + ~Shape_Preprocessed_Data_Chunk () + { + if(extra_data) delete extra_data; + if(memory_block) delete memory_block; + } + + virtual size_t size_chunk () + { + return (chunk_size = 12 + 12+block_size*4+num_extra_data*4); + } + + virtual void fill_data_block (char *); + + + int num_extra_data; + int* extra_data; + + void* GetMemoryBlock(); + +private: + + int block_size; + int first_pointer; + unsigned int* memory_block; + + friend class Shape_Chunk; + friend class Shape_Sub_Shape_Chunk; + +}; +#endif \ No newline at end of file diff --git a/3dc/win95/SMACK.H b/3dc/win95/SMACK.H new file mode 100644 index 0000000..fcab4cb --- /dev/null +++ b/3dc/win95/SMACK.H @@ -0,0 +1,433 @@ +#ifndef SMACKH +#define SMACKH + +#define SMACKVERSION "3.1s" + +#ifndef __RADRES__ + +#include "rad.h" + +RADDEFSTART + +typedef struct SmackTag { + u32 Version; // SMK2 only right now + u32 Width; // Width (1 based, 640 for example) + u32 Height; // Height (1 based, 480 for example) + u32 Frames; // Number of frames (1 based, 100 = 100 frames) + u32 MSPerFrame; // Frame Rate + u32 SmackerType; // bit 0 set=ring frame + u32 LargestInTrack[7]; // Largest single size for each track + u32 tablesize; // Size of the init tables + u32 codesize; // Compression info + u32 absize; // ditto + u32 detailsize; // ditto + u32 typesize; // ditto + u32 TrackType[7]; // high byte=0x80-Comp,0x40-PCM data,0x20-16 bit,0x10-stereo + u32 extra; // extra value (should be zero) + u32 NewPalette; // set to one if the palette changed + u8 Palette[772]; // palette data + u32 PalType; // type of palette + u32 FrameNum; // Frame Number to be displayed + u32 FrameSize; // The current frame's size in bytes + u32 SndSize; // The current frame sound tracks' size in bytes + s32 LastRectx; // Rect set in from SmackToBufferRect (X coord) + s32 LastRecty; // Rect set in from SmackToBufferRect (Y coord) + s32 LastRectw; // Rect set in from SmackToBufferRect (Width) + s32 LastRecth; // Rect set in from SmackToBufferRect (Height) + u32 OpenFlags; // flags used on open + u32 LeftOfs; // Left Offset used in SmackTo + u32 TopOfs; // Top Offset used in SmackTo + u32 LargestFrameSize; // Largest frame size + u32 Highest1SecRate; // Highest 1 sec data rate + u32 Highest1SecFrame; // Highest 1 sec data rate starting frame + u32 ReadError; // Set to non-zero if a read error has ocurred + u32 addr32; // translated address for 16 bit interface +} Smack; + +#define SmackHeaderSize(smk) ((((u8*)&((smk)->extra))-((u8*)(smk)))+4) + +typedef struct SmackSumTag { + u32 TotalTime; // total time + u32 MS100PerFrame; // MS*100 per frame (100000/MS100PerFrame=Frames/Sec) + u32 TotalOpenTime; // Time to open and prepare for decompression + u32 TotalFrames; // Total Frames displayed + u32 SkippedFrames; // Total number of skipped frames + u32 SoundSkips; // Total number of sound skips + u32 TotalBlitTime; // Total time spent blitting + u32 TotalReadTime; // Total time spent reading + u32 TotalDecompTime; // Total time spent decompressing + u32 TotalBackReadTime; // Total time spent reading in background + u32 TotalReadSpeed; // Total io speed (bytes/second) + u32 SlowestFrameTime; // Slowest single frame time + u32 Slowest2FrameTime; // Second slowest single frame time + u32 SlowestFrameNum; // Slowest single frame number + u32 Slowest2FrameNum; // Second slowest single frame number + u32 AverageFrameSize; // Average size of the frame + u32 HighestMemAmount; // Highest amount of memory allocated + u32 TotalExtraMemory; // Total extra memory allocated + u32 HighestExtraUsed; // Highest extra memory actually used +} SmackSum; + + +//======================================================================= +#define SMACKNEEDPAN 0x00020L // Will be setting the pan +#define SMACKNEEDVOLUME 0x00040L // Will be setting the volume +#define SMACKFRAMERATE 0x00080L // Override fr (call SmackFrameRate first) +#define SMACKLOADEXTRA 0x00100L // Load the extra buffer during SmackOpen +#define SMACKPRELOADALL 0x00200L // Preload the entire animation +#define SMACKNOSKIP 0x00400L // Don't skip frames if falling behind +#define SMACKSIMULATE 0x00800L // Simulate the speed (call SmackSim first) +#define SMACKFILEHANDLE 0x01000L // Use when passing in a file handle +#define SMACKTRACK1 0x02000L // Play audio track 1 +#define SMACKTRACK2 0x04000L // Play audio track 2 +#define SMACKTRACK3 0x08000L // Play audio track 3 +#define SMACKTRACK4 0x10000L // Play audio track 4 +#define SMACKTRACK5 0x20000L // Play audio track 5 +#define SMACKTRACK6 0x40000L // Play audio track 6 +#define SMACKTRACK7 0x80000L // Play audio track 7 +#define SMACKTRACKS (SMACKTRACK1|SMACKTRACK2|SMACKTRACK3|SMACKTRACK4|SMACKTRACK5|SMACKTRACK6|SMACKTRACK7) + +#define SMACKBUFFERREVERSED 0x00000001 +#define SMACKBUFFER555 0x80000000 +#define SMACKBUFFER565 0xc0000000 +#define SMACKBUFFER16 (SMACKBUFFER555|SMACKBUFFER565) + +#define SMACKYINTERLACE 0x100000L // Force interleaving Y scaling +#define SMACKYDOUBLE 0x200000L // Force doubling Y scaling +#define SMACKYNONE (SMACKYINTERLACE|SMACKYDOUBLE) // Force normal Y scaling +#define SMACKFILEISSMK 0x2000000L // Internal flag for 16 to 32 bit thunking + +#define SMACKAUTOEXTRA 0xffffffffL // NOT A FLAG! - Use as extrabuf param +//======================================================================= + +#define SMACKSURFACEFAST 0 +#define SMACKSURFACESLOW 1 +#define SMACKSURFACEDIRECT 2 + +RADEXPFUNC Smack PTR4* RADEXPLINK SmackOpen(const char PTR4* name,u32 flags,u32 extrabuf); + +#ifdef __RADMAC__ + #include + + RADEXPFUNC Smack PTR4* RADEXPLINK SmackMacOpen(FSSpec* fsp,u32 flags,u32 extrabuf); +#endif + +RADEXPFUNC u32 RADEXPLINK SmackDoFrame(Smack PTR4* smk); +RADEXPFUNC void RADEXPLINK SmackNextFrame(Smack PTR4* smk); +RADEXPFUNC u32 RADEXPLINK SmackWait(Smack PTR4* smk); +RADEXPFUNC void RADEXPLINK SmackClose(Smack PTR4* smk); + +RADEXPFUNC void RADEXPLINK SmackVolumePan(Smack PTR4* smk, u32 trackflag,u32 volume,u32 pan); + +RADEXPFUNC void RADEXPLINK SmackSummary(Smack PTR4* smk,SmackSum PTR4* sum); + +RADEXPFUNC u32 RADEXPLINK SmackSoundInTrack(Smack PTR4* smk,u32 trackflags); +RADEXPFUNC u32 RADEXPLINK SmackSoundOnOff(Smack PTR4* smk,u32 on); + +#ifndef __RADMAC__ +RADEXPFUNC void RADEXPLINK SmackToScreen(Smack PTR4* smk,u32 left,u32 top,u32 BytePS,const u16 PTR4* WinTbl,void* SetBank,u32 Flags); +#endif + +RADEXPFUNC void RADEXPLINK SmackToBuffer(Smack PTR4* smk,u32 left,u32 top,u32 Pitch,u32 destheight,const void PTR4* buf,u32 Flags); +RADEXPFUNC u32 RADEXPLINK SmackToBufferRect(Smack PTR4* smk, u32 SmackSurface); + +RADEXPFUNC void RADEXPLINK SmackGoto(Smack PTR4* smk,u32 frame); +RADEXPFUNC void RADEXPLINK SmackColorRemap(Smack PTR4* smk,const void PTR4* remappal,u32 numcolors,u32 paltype); +RADEXPFUNC void RADEXPLINK SmackColorTrans(Smack PTR4* smk,const void PTR4* trans); +RADEXPFUNC void RADEXPLINK SmackFrameRate(u32 forcerate); +RADEXPFUNC void RADEXPLINK SmackSimulate(u32 sim); + +RADEXPFUNC u32 RADEXPLINK SmackGetTrackData(Smack PTR4* smk,void PTR4* dest,u32 trackflag); + +RADEXPFUNC void RADEXPLINK SmackSoundCheck(void); + + +//====================================================================== + +// the functions for the new SmackBlit API + +typedef struct _SMACKBLIT PTR4* HSMACKBLIT; + +typedef struct _SMACKBLIT { + u32 Flags; + u8 PTR4* Palette; + u32 PalType; + u16 PTR4* SmoothTable; + u16 PTR4* Conv8to16Table; + u32 whichmode; + u32 palindex; + u32 t16index; + u32 smoothindex; + u32 smoothtype; + u32 firstpalette; +} SMACKBLIT; + +#define SMACKBLIT1X 1 +#define SMACKBLIT2X 2 +#define SMACKBLIT2XSMOOTHING 4 +#define SMACKBLIT2XINTERLACE 8 + +RADEXPFUNC HSMACKBLIT RADEXPLINK SmackBlitOpen(u32 flags); +RADEXPFUNC void RADEXPLINK SmackBlitSetPalette(HSMACKBLIT sblit, void PTR4* Palette,u32 PalType); +RADEXPFUNC u32 RADEXPLINK SmackBlitSetFlags(HSMACKBLIT sblit,u32 flags); +RADEXPFUNC void RADEXPLINK SmackBlit(HSMACKBLIT sblit,void PTR4* dest, u32 destpitch, u32 destx, u32 desty, void PTR4* src, u32 srcpitch, u32 srcx, u32 srcy, u32 srcw, u32 srch); +RADEXPFUNC void RADEXPLINK SmackBlitClear(HSMACKBLIT sblit,void PTR4* dest, u32 destpitch, u32 destx, u32 desty, u32 destw, u32 desth, s32 color); +RADEXPFUNC void RADEXPLINK SmackBlitClose(HSMACKBLIT sblit); +RADEXPFUNC void RADEXPLINK SmackBlitTrans(HSMACKBLIT sblit,void PTR4* dest, u32 destpitch, u32 destx, u32 desty, void PTR4* src, u32 srcpitch, u32 srcx, u32 srcy, u32 srcw, u32 srch, u32 trans); +RADEXPFUNC void RADEXPLINK SmackBlitMask(HSMACKBLIT sblit,void PTR4* dest, u32 destpitch, u32 destx, u32 desty, void PTR4* src, u32 srcpitch, u32 srcx, u32 srcy, u32 srcw, u32 srch, u32 trans,void PTR4* mask); +RADEXPFUNC void RADEXPLINK SmackBlitMerge(HSMACKBLIT sblit,void PTR4* dest, u32 destpitch, u32 destx, u32 desty, void PTR4* src, u32 srcpitch, u32 srcx, u32 srcy, u32 srcw, u32 srch, u32 trans,void PTR4* back); +RADEXPFUNC char PTR4* RADEXPLINK SmackBlitString(HSMACKBLIT sblit,char PTR4* dest); + +#ifndef __RADMAC__ +RADEXPFUNC u32 RADEXPLINK SmackUseMMX(u32 flag); //0=off, 1=on, 2=query current +#endif + +//====================================================================== +#ifdef __RADDOS__ + + #define SMACKSOUNDNONE -1 + + extern void* SmackTimerSetupAddr; + extern void* SmackTimerReadAddr; + extern void* SmackTimerDoneAddr; + + typedef void RADEXPLINK (*SmackTimerSetupType)(void); + typedef u32 RADEXPLINK (*SmackTimerReadType)(void); + typedef void RADEXPLINK (*SmackTimerDoneType)(void); + + #define SmackTimerSetup() ((SmackTimerSetupType)(SmackTimerSetupAddr))() + #define SmackTimerRead() ((SmackTimerReadType)(SmackTimerReadAddr))() + #define SmackTimerDone() ((SmackTimerDoneType)(SmackTimerDoneAddr))() + + RADEXPFUNC u8 RADEXPLINK SmackSoundUseMSS(void* DigDriver); + + #ifndef AIL_startup + #ifdef __SW_3R + extern s32 cdecl AIL_startup_reg(void); + #define AIL_startup AIL_startup_reg + #else + extern s32 cdecl AIL_startup_stack(void); + #define AIL_startup AIL_startup_stack + #endif + #endif + #define SmackSoundMSSLiteInit() SmackSoundMSSLiteInitWithStart(&AIL_startup); + RADEXPFUNC void RADEXPLINK SmackSoundMSSLiteInitWithStart(void* start); + RADEXPFUNC void RADEXPLINK SmackSoundMSSLiteDone(void); + + RADEXPFUNC u8 RADEXPLINK SmackSoundUseSOS3r(u32 SOSDriver,u32 MaxTimerSpeed); + RADEXPFUNC u8 RADEXPLINK SmackSoundUseSOS3s(u32 SOSDriver,u32 MaxTimerSpeed); + RADEXPFUNC u8 RADEXPLINK SmackSoundUseSOS4r(u32 SOSDriver,u32 MaxTimerSpeed); + RADEXPFUNC u8 RADEXPLINK SmackSoundUseSOS4s(u32 SOSDriver,u32 MaxTimerSpeed); + + #ifdef __SW_3R + #define SmackSoundUseSOS3 SmackSoundUseSOS3r + #define SmackSoundUseSOS4 SmackSoundUseSOS4r + #else + #define SmackSoundUseSOS3 SmackSoundUseSOS3s + #define SmackSoundUseSOS4 SmackSoundUseSOS4s + #endif + +#else + + #define SMACKRESRESET 0 + #define SMACKRES640X400 1 + #define SMACKRES640X480 2 + #define SMACKRES800X600 3 + #define SMACKRES1024X768 4 + + RADEXPFUNC u32 RADEXPLINK SmackSetSystemRes(u32 mode); // use SMACKRES* values + + #define SMACKNOCUSTOMBLIT 128 + #define SMACKSMOOTHBLIT 256 + #define SMACKINTERLACEBLIT 512 + + #ifdef __RADMAC__ + + #include + #include + #include + + #define SmackTimerSetup() + #define SmackTimerDone() + RADEXPFUNC u32 RADEXPLINK SmackTimerRead(void); + + RADEXPFUNC s32 RADEXPLINK SmackGDSurfaceType( GDHandle gd ); + + #define SMACKAUTOBLIT 0 + #define SMACKDIRECTBLIT 1 + #define SMACKGWORLDBLIT 2 + + typedef struct SmackBufTag { + u32 Reversed; + u32 SurfaceType; // SMACKSURFACExxxxxx + u32 BlitType; // SMACKxxxxxBLIT + u32 Width; + u32 Height; + u32 Pitch; + u32 Zoomed; + u32 ZWidth; + u32 ZHeight; + u32 DispColors; // colors on screen + u32 MaxPalColors; + u32 PalColorsInUse; + u32 StartPalColor; + u32 EndPalColor; + void* Buffer; + void* Palette; + u32 PalType; + u32 SoftwareCursor; + + WindowPtr wp; + GWorldPtr gwp; + CTabHandle cth; + PaletteHandle palh; + + GDHandle gd; + u32 gdSurfaceType; + HSMACKBLIT sblit; + void * ScreenAddr; + u32 ScreenPitch; + + s32 manyblits; + s32 PTR4* blitrects; + s32 PTR4* rectsptr; + s32 maxrects; + s32 numrects; + + } SmackBuf; + + #else + + #ifdef __RADWIN__ + + #define INCLUDE_MMSYSTEM_H + #include "windows.h" + #include "windowsx.h" + + #ifdef __RADNT__ // to combat WIN32_LEAN_AND_MEAN + + #include "mmsystem.h" + + RADEXPFUNC s32 RADEXPLINK SmackDDSurfaceType(void* lpDDS); + + #endif + + #define SMACKAUTOBLIT 0 + #define SMACKFULL320X240BLIT 1 + #define SMACKFULL320X200BLIT 2 + #define SMACKFULL320X200DIRECTBLIT 3 + #define SMACKSTANDARDBLIT 4 + #define SMACKWINGBLIT 5 + #define SMACKDIBSECTIONBLIT 5 + + #define WM_SMACKACTIVATE WM_USER+0x5678 + + typedef struct SmackBufTag { + u32 Reversed; // 1 if the buffer is upside down + u32 SurfaceType; // SMACKSURFACExxxx defines + u32 BlitType; // SMACKxxxxBLIT defines + u32 FullScreen; // 1 if full-screen + u32 Width; + u32 Height; + u32 Pitch; + u32 Zoomed; + u32 ZWidth; + u32 ZHeight; + u32 DispColors; // colors on the screen + u32 MaxPalColors; // total possible colors in palette (usually 256) + u32 PalColorsInUse; // Used colors in palette (usually 236) + u32 StartPalColor; // first usable color index (usually 10) + u32 EndPalColor; // last usable color index (usually 246) + RGBQUAD Palette[256]; + u32 PalType; + u32 forceredraw; // force a complete redraw on next blit (for >8bit) + u32 didapalette; // force an invalidate on the next palette change + + void PTR4* Buffer; + void PTR4* DIBRestore; + u32 OurBitmap; + u32 OrigBitmap; + u32 OurPalette; + u32 WinGDC; + u32 FullFocused; + u32 ParentHwnd; + u32 OldParWndProc; + u32 OldDispWndProc; + u32 DispHwnd; + u32 WinGBufHandle; + void PTR4* lpDD; + void PTR4* lpDDSP; + u32 DDSurfaceType; + HSMACKBLIT DDblit; + s32 ddSoftwarecur; + s32 didaddblit; + s32 lastwasdd; + RECT ddscreen; + s32 manyblits; + s32 PTR4* blitrects; + s32 PTR4* rectsptr; + s32 maxrects; + s32 numrects; + HDC lastdc; + } SmackBuf; + + RADEXPFUNC void RADEXPLINK SmackGet(Smack PTR4* smk,void PTR4* dest); + RADEXPFUNC void RADEXPLINK SmackBufferGet( SmackBuf PTR4* sbuf, void PTR4* dest); + + RADEXPFUNC u8 RADEXPLINK SmackSoundUseMSS(void PTR4* dd); + RADEXPFUNC u8 RADEXPLINK SmackSoundUseDirectSound(void PTR4* dd); // NULL=Create + RADEXPFUNC void RADEXPLINK SmackSoundSetDirectSoundHWND(HWND hw); + RADEXPFUNC u8 RADEXPLINK SmackSoundUseDW(u32 openfreq, u32 openbits, u32 openchans); + + #define SmackTimerSetup() + #define SmackTimerDone() + #define SmackTimerRead timeGetTime + + #endif + + #endif + + #ifdef __RADMAC__ + RADEXPFUNC SmackBuf PTR4* RADEXPLINK SmackBufferOpen( WindowPtr wp, u32 BlitType, u32 width, u32 height, u32 ZoomW, u32 ZoomH ); + RADEXPFUNC u32 RADEXPLINK SmackBufferBlit( SmackBuf PTR4* sbuf, s32 hwndx, s32 hwndy, s32 subx, s32 suby, s32 subw, s32 subh ); + RADEXPFUNC void RADEXPLINK SmackBufferFromScreen( SmackBuf PTR4* destbuf, s32 x, s32 y); + + RADEXPFUNC s32 RADEXPLINK SmackIsSoftwareCursor(GDHandle gd); + RADEXPFUNC s32 RADEXPLINK SmackCheckCursor(WindowPtr wp,s32 x,s32 y,s32 w,s32 h); + RADEXPFUNC void RADEXPLINK SmackRestoreCursor(s32 checkcount); + #else + RADEXPFUNC SmackBuf PTR4* RADEXPLINK SmackBufferOpen( HWND wnd, u32 BlitType, u32 width, u32 height, u32 ZoomW, u32 ZoomH ); + RADEXPFUNC u32 RADEXPLINK SmackBufferBlit( SmackBuf PTR4* sbuf, HDC dc, s32 hwndx, s32 hwndy, s32 subx, s32 suby, s32 subw, s32 subh ); + RADEXPFUNC void RADEXPLINK SmackBufferFromScreen( SmackBuf PTR4* destbuf, HWND hw, s32 x, s32 y); + + RADEXPFUNC s32 RADEXPLINK SmackIsSoftwareCursor(void* lpDDSP,HCURSOR cur); + RADEXPFUNC s32 RADEXPLINK SmackCheckCursor(HWND wnd,s32 x,s32 y,s32 w,s32 h); + RADEXPFUNC void RADEXPLINK SmackRestoreCursor(s32 checkcount); + #endif + + RADEXPFUNC void RADEXPLINK SmackBufferStartMultipleBlits( SmackBuf PTR4* sbuf ); + RADEXPFUNC void RADEXPLINK SmackBufferEndMultipleBlits( SmackBuf PTR4* sbuf ); + + RADEXPFUNC char PTR4* RADEXPLINK SmackBufferString(SmackBuf PTR4* sb,char PTR4* dest); + + RADEXPFUNC void RADEXPLINK SmackBufferNewPalette( SmackBuf PTR4* sbuf, const void PTR4* pal, u32 paltype ); + RADEXPFUNC u32 RADEXPLINK SmackBufferSetPalette( SmackBuf PTR4* sbuf ); + RADEXPFUNC void RADEXPLINK SmackBufferClose( SmackBuf PTR4* sbuf ); + + RADEXPFUNC void RADEXPLINK SmackBufferClear( SmackBuf PTR4* destbuf, u32 color); + + RADEXPFUNC void RADEXPLINK SmackBufferToBuffer( SmackBuf PTR4* destbuf, s32 destx, s32 desty, const SmackBuf PTR4* sourcebuf,s32 sourcex,s32 sourcey,s32 sourcew,s32 sourceh); + RADEXPFUNC void RADEXPLINK SmackBufferToBufferTrans( SmackBuf PTR4* destbuf, s32 destx, s32 desty, const SmackBuf PTR4* sourcebuf,s32 sourcex,s32 sourcey,s32 sourcew,s32 sourceh,u32 TransColor); + RADEXPFUNC void RADEXPLINK SmackBufferToBufferMask( SmackBuf PTR4* destbuf, s32 destx, s32 desty, const SmackBuf PTR4* sourcebuf,s32 sourcex,s32 sourcey,s32 sourcew,s32 sourceh,u32 TransColor,const SmackBuf PTR4* maskbuf); + RADEXPFUNC void RADEXPLINK SmackBufferToBufferMerge( SmackBuf PTR4* destbuf, s32 destx, s32 desty, const SmackBuf PTR4* sourcebuf,s32 sourcex,s32 sourcey,s32 sourcew,s32 sourceh,u32 TransColor,const SmackBuf PTR4* mergebuf); + RADEXPFUNC void RADEXPLINK SmackBufferCopyPalette( SmackBuf PTR4* destbuf, SmackBuf PTR4* sourcebuf, u32 remap); + + RADEXPFUNC u32 RADEXPLINK SmackBufferFocused( SmackBuf PTR4* sbuf); + +#endif + +RADDEFEND + +#endif + +#endif diff --git a/3dc/win95/SMSOPT.H b/3dc/win95/SMSOPT.H new file mode 100644 index 0000000..614b415 --- /dev/null +++ b/3dc/win95/SMSOPT.H @@ -0,0 +1,40 @@ +//------------------------------------------------------------------- +// DESCRIPTION: SMSOPT.H - Options for SMS compilation +// +// AUTHOR: Mark Tolley +// +// HISTORY: Created 19th Sept 1996 +// +//------------------------------------------------------------------- + +// Incorporated into sndmanag.h and xxxxxsnd.h + +#ifndef SMSOPT_H +#define SMSOPT_H + + +// #DEFINES +// General switches +#define SOUND_ON 0 // Compile sound commands in main game code +#define SOUND_3D 1 // Compile 3D sound functions + + // (NB switching this off makes SMS independent of 3DC) + +// Platform switches - ONLY ONE OF THESE SHOULD BE ON!! +#define SMS_SATURN 0 // Compile SMS for Saturn +#define SMS_PSX 0 // Compile SMS for PSX +#define SMS_PCDOS 0 // Compile SMS for PC-DOS +#define SMS_WIN32 1 // Compile SMS for PC-Win95 + +// Sound source switches +#define MIDI_ON 1 // Compile MIDI-specific code +#define DIGI_ON 1 // Compile WAV-specific code +#define CDDA_ON 1 // Compile CDDA-specific code + +// Any other sound-specific compiler switches +#define SMS_FORCE_PENTIUM_TO_DOS_QUALITY 0 // Forces Pentium to use + // DOS quality sound. May help to speed things + // up... NB 3D SOUND WON'T WORK PROPERLY +#define SMS_TIMER 1 // Implement timing for ONEHI. Relies on NormalFrameTime +#endif // SMSOPT_H +// END OF FILE diff --git a/3dc/win95/SNDCHUNK.CPP b/3dc/win95/SNDCHUNK.CPP new file mode 100644 index 0000000..c0e08d3 --- /dev/null +++ b/3dc/win95/SNDCHUNK.CPP @@ -0,0 +1,351 @@ +#include "chunk.hpp" +#include "envchunk.hpp" +#include "sndchunk.hpp" +#include "obchunk.hpp" +#include "md5.h" + +#ifdef cencon +#define new my_new +#endif +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(sndchunk) + +RIF_IMPLEMENT_DYNCREATE("SOUNDOB2",Sound_Object_Chunk) + +Sound_Object_Chunk::Sound_Object_Chunk (Chunk_With_Children * parent, + ChunkVectorInt & pos, + const char * _name + ) +: Chunk (parent, "SOUNDOB2"), position (pos), + inner_range (0), outer_range (0), max_volume (0), pitch (0), + flags (0), probability (0), pad3 (0), + snd_name (0), wav_name (0) +{ + if (_name) + { + snd_name = new char [strlen(_name)+1]; + strcpy (snd_name, _name); + } + else + { + snd_name = new char [1]; + snd_name [0] = 0; + } +} + +Sound_Object_Chunk::~Sound_Object_Chunk() +{ + if (snd_name) + delete [] snd_name; + if (wav_name) + delete [] wav_name; +} + +Sound_Object_Chunk::Sound_Object_Chunk (Chunk_With_Children * parent, const char * data, size_t /*ssize*/) +: Chunk (parent, "SOUNDOB2"), snd_name (0), wav_name (0) +{ + position = *((ChunkVectorInt *) data); + data += sizeof(ChunkVectorInt); + + inner_range = *((int *)data); + data += 4; + outer_range = *((int *)data); + data += 4; + max_volume = *((int *)data); + data += 4; + pitch = *((int *)data); + data += 4; + flags = *((int *)data); + data += 4; + probability = *((int *)data); + data += 4; + pad3 = *((int *)data); + data += 4; + snd_name = new char [strlen (data) + 1]; + strcpy (snd_name, data); + data += strlen (data) + 1; + if (strlen(data)) + { + wav_name = new char [strlen (data) + 1]; + strcpy (wav_name, data); + } +} + +void Sound_Object_Chunk::fill_data_block ( char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((ChunkVectorInt *) data_start) = position; + data_start += sizeof(ChunkVectorInt); + + + *((int *)data_start) = inner_range; + data_start += 4; + *((int *)data_start) = outer_range; + data_start += 4; + *((int *)data_start) = max_volume; + data_start += 4; + *((int *)data_start) = pitch; + data_start += 4; + *((int *)data_start) = flags; + data_start += 4; + *((int *)data_start) = probability; + data_start += 4; + *((int *)data_start) = pad3; + data_start += 4; + + sprintf (data_start, "%s", snd_name); + data_start += strlen (snd_name) + 1; + if (wav_name) + { + sprintf (data_start, "%s", wav_name); + } + else + { + *data_start = 0; + } +} + + +ObjectID Sound_Object_Chunk::CalculateID() +{ + ObjectID retval={0,0}; + + char buffer[16]; + md5_buffer(snd_name,strlen(snd_name),&buffer[0]); + buffer[7]=0; + retval = *(ObjectID*)&buffer[0]; + return retval; +} + +Sound_Object_Extra_Data_Chunk* Sound_Object_Chunk::get_extra_data_chunk() +{ + List chlist; + parent->lookup_child("SOUNDEXD",chlist); + if(!chlist.size())return 0; + + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + Sound_Object_Extra_Data_Chunk* soedc=(Sound_Object_Extra_Data_Chunk*)chlif(); + Sound_Object_Extra_Name_Chunk* sname=(Sound_Object_Extra_Name_Chunk*) soedc->lookup_single_child("SOUNDNAM"); + + if(sname) + { + if(!strcmp(snd_name,sname->name)) + { + return soedc; + } + } + } + //no extra data chunk found + return 0; + +} +Sound_Object_Extra_Data_Chunk* Sound_Object_Chunk::create_extra_data_chunk() +{ + Sound_Object_Extra_Data_Chunk* soedc=get_extra_data_chunk(); + if(soedc)return soedc; + + return new Sound_Object_Extra_Data_Chunk(parent,this); +} + +Object_Alternate_Locations_Chunk* Sound_Object_Chunk::get_alternate_locations_chunk() +{ + Sound_Object_Extra_Data_Chunk* soedc=get_extra_data_chunk(); + if(!soedc) return 0; + return (Object_Alternate_Locations_Chunk*)soedc->lookup_single_child("ALTLOCAT"); +} + +Object_Alternate_Locations_Chunk* Sound_Object_Chunk::create_alternate_locations_chunk() +{ + Sound_Object_Extra_Data_Chunk* soedc=create_extra_data_chunk(); + + Object_Alternate_Locations_Chunk* loc_chunk=(Object_Alternate_Locations_Chunk*)soedc->lookup_single_child("ALTLOCAT"); + if(loc_chunk) return loc_chunk; + + return new Object_Alternate_Locations_Chunk(soedc); +} + + +///////////////////////////////////////////////////////////////////////////////////// +//class Sound_Object_Extra_Data_Chunk +RIF_IMPLEMENT_DYNCREATE("SOUNDEXD",Sound_Object_Extra_Data_Chunk) + +CHUNK_WITH_CHILDREN_LOADER("SOUNDEXD",Sound_Object_Extra_Data_Chunk) + +/* +Children for Sound_Object_Extra_Data_Chunk : + +"SOUNDNAM" Sound_Object_Extra_Name_Chunk +"ALTLOCAT" Object_Alternate_Locations_Chunk +*/ + + +Sound_Object_Extra_Data_Chunk::Sound_Object_Extra_Data_Chunk(Chunk_With_Children* parent,Sound_Object_Chunk* soc) +:Chunk_With_Children(parent,"SOUNDEXD") +{ + new Sound_Object_Extra_Name_Chunk(this,soc->snd_name); +} + +Sound_Object_Chunk* Sound_Object_Extra_Data_Chunk::get_sound_chunk() +{ + List chlist; + + lookup_child("SOUNDNAM",chlist); + if(!chlist.size()) return 0; + const char* name=((Sound_Object_Extra_Name_Chunk*)chlist.first_entry())->name; + + parent->lookup_child("SOUNDEXD",chlist); + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + Sound_Object_Chunk* soc=(Sound_Object_Chunk*)chlif(); + if(!strcmp(soc->snd_name,name)) + { + return soc; + } + } + //no sound chunk found + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("SOUNDNAM",Sound_Object_Extra_Name_Chunk) + +Sound_Object_Extra_Name_Chunk::Sound_Object_Extra_Name_Chunk(Chunk_With_Children * parent, const char * data, size_t /*size*/) +:Chunk(parent,"SOUNDNAM") +{ + int length=strlen(data); + name=new char[length+1]; + strcpy(name,data); +} + +Sound_Object_Extra_Name_Chunk::Sound_Object_Extra_Name_Chunk(Chunk_With_Children * parent, const char * _name) +:Chunk(parent,"SOUNDNAM") +{ + name=new char[strlen(_name)+1]; + strcpy(name,_name); +} + +Sound_Object_Extra_Name_Chunk::~Sound_Object_Extra_Name_Chunk() +{ + delete name; +} + +void Sound_Object_Extra_Name_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + strcpy(data_start,name); +} + + +size_t Sound_Object_Extra_Name_Chunk::size_chunk() +{ + chunk_size=12; + chunk_size+=(strlen(name)+4)&~3; + return chunk_size; +} +///////////////////////////////////////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("INDSOUND",Indexed_Sound_Chunk) + +Indexed_Sound_Chunk::Indexed_Sound_Chunk(Chunk_With_Children* parent,const char* data,const size_t) +:Chunk(parent,"INDSOUND") +{ + CHUNK_EXTRACT(index,int) + CHUNK_EXTRACT_STRING(wav_name) + CHUNK_EXTRACT(inner_range,int) + CHUNK_EXTRACT(outer_range,int) + CHUNK_EXTRACT(max_volume,int) + CHUNK_EXTRACT(pitch,int) + CHUNK_EXTRACT(flags,int) + CHUNK_EXTRACT_ARRAY(num_extra_data,extra_data,int) +} + +Indexed_Sound_Chunk::Indexed_Sound_Chunk(Chunk_With_Children* parent) +:Chunk(parent,"INDSOUND") +{ + index=0; + wav_name=0; + num_extra_data=0; + extra_data=0; +} + +Indexed_Sound_Chunk::~Indexed_Sound_Chunk() +{ + if(extra_data) delete [] extra_data; + if(wav_name) delete [] wav_name; +} + +void Indexed_Sound_Chunk::fill_data_block(char * data) +{ + CHUNK_FILL_START + CHUNK_FILL(index,int) + CHUNK_FILL_STRING(wav_name) + CHUNK_FILL(inner_range,int) + CHUNK_FILL(outer_range,int) + CHUNK_FILL(max_volume,int) + CHUNK_FILL(pitch,int) + CHUNK_FILL(flags,int) + CHUNK_FILL_ARRAY(num_extra_data,extra_data,int) + +} + +size_t Indexed_Sound_Chunk::size_chunk() +{ + chunk_size=12+24; + chunk_size+=4+4*num_extra_data; + if(wav_name) + chunk_size+=(strlen(wav_name)+4)&~3; + else + chunk_size+=4; + + return chunk_size; +} + +///////////////////////////////////////////////////////////////////////////////////// +/* +Sound_Collection_Chunk::Sound_Collection_Chunk(Chunk_With_Children* parent,const char* data,const size_t) +:Chunk(parent,"SOUNDCOL") +{ + CHUNK_EXTRACT(index,int) + CHUNK_EXTRACT_ARRAY(num_sounds,sounds,ChunkSoundWeighting) + CHUNK_EXTRACT(spare,int) +} + +Sound_Collection_Chunk::Sound_Collection_Chunk(Chunk_With_Children* parent) +:Chunk(parent,"SOUNDCOL") +{ + index=-1; + num_sounds=0; + sounds=0; + spare=0; +} + +Sound_Collection_Chunk::~Sound_Collection_Chunk() +{ + if(sounds) delete [] sounds; +} + +void Sound_Collection_Chunk::fill_data_block(char* data) +{ + CHUNK_FILL_START + CHUNK_FILL(index,int) + CHUNK_FILL_ARRAY(num_sounds,sounds,ChunkSoundWeighting) + CHUNK_FILL(spare,int) +} + +size_t Sound_Collection_Chunk::size_chunk() +{ + chunk_size=12+12+num_sounds*sizeof(ChunkSoundWeighting); + return chunk_size; +} +*/ \ No newline at end of file diff --git a/3dc/win95/SNDCHUNK.HPP b/3dc/win95/SNDCHUNK.HPP new file mode 100644 index 0000000..86483e5 --- /dev/null +++ b/3dc/win95/SNDCHUNK.HPP @@ -0,0 +1,156 @@ +#ifndef _sndchunk_hpp +#define _sndchunk_hpp 1 +#include "chnktype.hpp" + +#define SoundObjectFlag_NotPlayingAtStart 0x00000001 +#define SoundObjectFlag_NoLoop 0x00000002 + +class Object_Alternate_Locations_Chunk; +class Sound_Object_Extra_Data_Chunk; + +class Sound_Object_Chunk : public Chunk +{ +public: + + Sound_Object_Chunk (Chunk_With_Children * parent, + ChunkVectorInt & pos, + const char * name + ); + // constructor from buffer + Sound_Object_Chunk (Chunk_With_Children * parent, const char * sdata, size_t /*ssize*/); + + ~Sound_Object_Chunk (); + + ChunkVectorInt position; + + unsigned long inner_range; //millimetres + unsigned long outer_range; //millimetres + int max_volume; //from 0 to 127 + int pitch; //pitch shift in 1/1536ths of an actave + + int flags; + int probability; + int pad3; + + char * snd_name; + char * wav_name; + + size_t size_chunk () + { + chunk_size = 12 + 3*4 + 7*4 + strlen(snd_name) + 1; + if (wav_name) + { + chunk_size += strlen (wav_name); + } + else + { + chunk_size += 1; + } + + chunk_size += 4 - chunk_size%4; + return (chunk_size); + } + + void fill_data_block (char *); + + ObjectID CalculateID(); + + Sound_Object_Extra_Data_Chunk* get_extra_data_chunk(); + Sound_Object_Extra_Data_Chunk* create_extra_data_chunk(); //gets chunk if it exists , otherwise creates a new one + + Object_Alternate_Locations_Chunk* get_alternate_locations_chunk(); + Object_Alternate_Locations_Chunk* create_alternate_locations_chunk(); //gets chunk if it exists , otherwise creates a new one + +private: + + friend class Special_Objects_Chunk; + + + +}; + +//For attaching extra data to the sound objects +class Sound_Object_Extra_Data_Chunk : public Chunk_With_Children +{ +public: + Sound_Object_Extra_Data_Chunk (Chunk_With_Children * const parent,const char *, size_t const); + Sound_Object_Extra_Data_Chunk (Chunk_With_Children * parent,Sound_Object_Chunk*); + + Sound_Object_Chunk* get_sound_chunk(); +}; + +//Needed so I can match the extra data chunk with the appropriate sound chunk +class Sound_Object_Extra_Name_Chunk : public Chunk +{ +public : + Sound_Object_Extra_Name_Chunk(Chunk_With_Children* parent,const char*,size_t); + Sound_Object_Extra_Name_Chunk(Chunk_With_Children* parent,const char* _name); + ~Sound_Object_Extra_Name_Chunk(); + + char* name; + + + virtual size_t size_chunk(); + virtual void fill_data_block(char* data_start); +}; + + + +#define IndexedSoundFlag_Loop 0x00000001 +class Indexed_Sound_Chunk : public Chunk +{ +public : + + Indexed_Sound_Chunk(Chunk_With_Children* parent,const char*,const size_t); + Indexed_Sound_Chunk(Chunk_With_Children* parent); + ~Indexed_Sound_Chunk(); + + size_t size_chunk(); + void fill_data_block(char*); + + int index; + char* wav_name; + unsigned long inner_range; //millimetres + unsigned long outer_range; //millimetres + int max_volume; //from 0 to 127 + int pitch; //pitch shift in 1/1536ths of an actave + int flags; + + int num_extra_data; + int* extra_data; +}; + + + +/* +struct ChunkSoundWeighting +{ + int index; + int weighting; +}; + +//a collection of indeces of possible sounds to play +class Sound_Collection_Chunk : public Chunk +{ +public : + + Sound_Collection_Chunk(Chunk_With_Children* parent,const char*,const size_t); + Sound_Collection_Chunk(Chunk_With_Children* parent); + ~Sound_Collection_Chunk(); + + size_t size_chunk(); + void fill_data_block(char*); + + int index; + + int num_sounds; + ChunkSoundWeighting* sounds; + + int spare; + + +}; +*/ + + +#endif diff --git a/3dc/win95/STRING.CPP b/3dc/win95/STRING.CPP new file mode 100644 index 0000000..4ea96b5 --- /dev/null +++ b/3dc/win95/STRING.CPP @@ -0,0 +1,305 @@ +#include +#include +#include +#include "string.hpp" + +String::String() +: rep(0) +, len(0) +, cstring(0) +{ +} + +String::String(char const * str, size_t maxlen) +: rep(0) +, len(strlen(str)) +, cstring(0) +{ + if (len > maxlen) len = maxlen; + if (!len) return; + rep = (char *)malloc(len*sizeof(char)); + memcpy(rep,str,len*sizeof(char)); +} + +String::String(String const & str, size_t start, size_t leng) +: rep(0) +, len(leng) +, cstring(0) +{ + if (start>str.len) return; + if (start+len>str.len) len=str.len-start; + if (!len) return; + rep = (char *)malloc(len*sizeof(char)); + memcpy(rep,&str.rep[start],len*sizeof(char)); +} + +String::String(char c, size_t n) +: rep(0) +, len(n) +, cstring(0) +{ + if (len) + { + rep = (char *)malloc(len*sizeof(char)); + for (size_t p=0; p=) +STRING_COMPARES(<) +STRING_COMPARES(>) + +void String::put_at(size_t pos, char c) +{ + if (pos=len || pos>=str.len || rep[pos] != str.rep[pos]) return (int)pos; + } + return -1; +} + +int String::match(char const * str) const +{ + for (size_t pos = 0; pos=len || !*str || rep[pos] != *str) return (int)pos; + } + return -1; +} + +int String::index(String const & str, size_t pos) const +{ + if (!str.len) return (int)pos; + for (size_t spos = 0, rpos = pos; pos= str.len) return (int)rpos; + } + else spos = 0; + } + return -1; +} + +int String::index(char const * str, size_t pos) const +{ + if (!*str) return (int)pos; + char const * strP = str; + for (size_t rpos = pos; pos +#else + +#ifndef __cplusplus +#error "string.hpp requires C++ compilation" +#endif + +#include + +//const size_t NPOS = (size_t) -1; +#define _BIGSIZET ((size_t)-1) + +class String +{ +public: + String(); + String(char const *, size_t = _BIGSIZET); + String(String const &, size_t = 0, size_t = _BIGSIZET); + String(char, size_t = 1); + + ~String(); + + inline operator char const * () const; + char const * c_str() const; + //operator char () const; + + String & operator = (String const &); + String & operator = (char const *); + + String & operator += (String const &); + String & operator += (char const *); + + inline String operator () (size_t, size_t) const; + inline char & operator () (size_t); + inline char const & operator () (size_t) const; + inline char & operator [] (size_t); + inline char const & operator [] (size_t) const; + + friend int operator == (String const &, String const &); + friend int operator == (String const &, char const *); + friend int operator == (char const *, String const &); + friend int operator == (String const &, char); + friend int operator == (char, String const &); + + friend int operator != (String const &, String const &); + friend int operator != (String const &, char const *); + friend int operator != (char const *, String const &); + friend int operator != (String const &, char); + friend int operator != (char, String const &); + + friend int operator <= (String const &, String const &); + friend int operator <= (String const &, char const *); + friend int operator <= (char const *, String const &); + friend int operator <= (String const &, char); + friend int operator <= (char, String const &); + + friend int operator >= (String const &, String const &); + friend int operator >= (String const &, char const *); + friend int operator >= (char const *, String const &); + friend int operator >= (String const &, char); + friend int operator >= (char, String const &); + + friend int operator < (String const &, String const &); + friend int operator < (String const &, char const *); + friend int operator < (char const *, String const &); + friend int operator < (String const &, char); + friend int operator < (char, String const &); + + friend int operator > (String const &, String const &); + friend int operator > (String const &, char const *); + friend int operator > (char const *, String const &); + friend int operator > (String const &, char); + friend int operator > (char, String const &); + + friend inline String operator + (String const &, String const &); + friend inline String operator + (String const &, char const *); + friend inline String operator + (char const *, String const &); + friend inline String operator + (String const &, char); + friend inline String operator + (char, String const &); + + inline size_t length() const; + + inline char const & get_at(size_t) const; + void put_at(size_t, char); + + int match(String const &) const; + int match(char const *) const; + + int index(String const &, size_t = 0) const; + int index(char const *, size_t = 0 ) const; + + String upper() const; + String lower() const; + + inline int operator ! () const; + inline int valid() const; + friend inline int valid(String const &); + +private: + String(String const &, String const &); + String(char const *, String const &); + String(String const &, char const *); + String(char, String const &); + String(String const &, char); + + char * rep; + size_t len; + char * cstring; +}; + +inline String::operator char const * () const +{ + return c_str(); +} + +inline String String::operator () (size_t start, size_t leng) const +{ + return String(*this,start,leng); +} + +inline char & String::operator () (size_t pos) +{ + return operator [] (pos); +} + +inline char const & String::operator () (size_t pos) const +{ + return operator [] (pos); +} + +inline char & String::operator [] (size_t pos) +{ + return rep[pos]; +} + +inline char const & String::operator [] (size_t pos) const +{ + return rep[pos]; +} + +#define STRING_CONSTRCAT(arg1,arg2) \ +inline String operator + (arg1 a1,arg2 a2) \ +{ \ + return String(a1,a2); \ +} +STRING_CONSTRCAT(String const &, String const &) +STRING_CONSTRCAT(char const *, String const &) +STRING_CONSTRCAT(String const &, char const *) +STRING_CONSTRCAT(char , String const &) +STRING_CONSTRCAT(String const &, char) + +inline size_t String::length() const +{ + return len; +} + +inline char const & String::get_at(size_t pos) const +{ + return operator [] (pos); +} + +inline int String::operator ! () const +{ + return !valid(); +} + +inline int String::valid() const +{ + return 1; +} + +inline int valid(String const & str) +{ + return str.valid(); +} + +#endif + +#endif \ No newline at end of file diff --git a/3dc/win95/ShowCmds.h b/3dc/win95/ShowCmds.h new file mode 100644 index 0000000..bbb1d41 --- /dev/null +++ b/3dc/win95/ShowCmds.h @@ -0,0 +1,43 @@ +/* KJL 14:42:10 29/03/98 - ShowCmds.h + + defines the variables that describe the status of the debugging text + + + eg. if ShowDebuggingText.FPS == 1, then the frame-rate show be displayed. + +*/ +struct DEBUGGINGTEXTOPTIONS +{ + unsigned int FPS :1; + unsigned int Environment :1; + unsigned int Coords :1; + unsigned int Module :1; + unsigned int Target :1; + + unsigned int Networking: 1; + unsigned int Dynamics :1; + unsigned int GunPos :1; + unsigned int Tears :1; + unsigned int PolyCount :1; + unsigned int Sounds :1; +}; + +extern struct DEBUGGINGTEXTOPTIONS ShowDebuggingText; + +#ifdef AVP_DEBUG_VERSION + #define DEBUGGING_TEXT_ON 1 +#else + #define DEBUGGING_TEXT_ON 0 +#endif + +#if DEBUGGING_TEXT_ON +extern int PrintDebuggingText(const char* t, ...); +#else +#define PrintDebuggingText(ignore) +#endif + +#if 1 +extern int ReleasePrintDebuggingText(const char* t, ...); +#else +#define PrintDebuggingText(ignore) +#endif diff --git a/3dc/win95/Sprchunk.cpp b/3dc/win95/Sprchunk.cpp new file mode 100644 index 0000000..c8f74f3 --- /dev/null +++ b/3dc/win95/Sprchunk.cpp @@ -0,0 +1,964 @@ +#include "sprchunk.hpp" +#include "mishchnk.hpp" + +#if cencon +#include "fnamefnc.hpp" +#include "bmpnames.hpp" +#include "shpchunk.hpp" +#endif + +#ifdef cencon +#define new my_new +#endif +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(sprchunk) + +extern Chunk* Parent_File; + +RIF_IMPLEMENT_DYNCREATE("SPRACTIO",Sprite_Action_Chunk) + +Sprite_Action_Chunk::Sprite_Action_Chunk(Chunk_With_Children* parent,const char* data,size_t /*datasize*/) +: Chunk(parent, "SPRACTIO") +{ + Action=*((int*)data); + data+=4; + NumYaw=*((int*)data); + data+=4; + NumPitch=*((int*)data); + data+=4; + NumFrames=*((int*)data); + data+=4; + Flags=*((int*)data); + data+=4; + FrameTime=*((int*)data); + data+=4; + FrameList=new Frame**[NumYaw]; + for(int i=0;iTexture=*((int*)data); + data+=4; + f->CentreX=*((int*)data); + data+=4; + f->CentreY=*((int*)data); + data+=4; + for(int l=0;l<4;l++) + { + f->UVCoords[l][0]=*((int*)data); + data+=4; + f->UVCoords[l][1]=*((int*)data); + data+=4; + } + } + } + } +} +Sprite_Action_Chunk::Sprite_Action_Chunk(Chunk_With_Children* parent) +: Chunk(parent, "SPRACTIO") +{ + Action=-1; + NumPitch=0; + NumYaw=0; + NumFrames=0; + FrameList=0; + Flags=0; + FrameTime=200; +} +size_t Sprite_Action_Chunk::size_chunk() +{ + chunk_size=36+NumFrames*NumPitch*NumYaw*44; + return chunk_size; +} + +Sprite_Action_Chunk::~Sprite_Action_Chunk() +{ + for(int i=0;imake_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; +} + +void Sprite_Action_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *(int*)data_start=Action; + data_start += 4; + *(int*)data_start=NumYaw; + data_start += 4; + *(int*)data_start=NumPitch; + data_start += 4; + *(int*)data_start=NumFrames; + data_start += 4; + *(int*)data_start=Flags; + data_start += 4; + *(int*)data_start=FrameTime; + data_start += 4; + + for(int i=0;iTexture; + data_start += 4; + *(int*)data_start=f->CentreX; + data_start +=4; + *(int*)data_start=f->CentreY; + data_start +=4; + for(int l=0;l<4;l++) + { + *(int*)data_start=f->UVCoords[l][0]; + data_start+=4; + *(int*)data_start=f->UVCoords[l][1]; + data_start+=4; + } + } + } + } +} + +////////////////////////////////////////////////// +//Class Sprite_Header_Chunk +RIF_IMPLEMENT_DYNCREATE("SPRIHEAD",Sprite_Header_Chunk) +CHUNK_WITH_CHILDREN_LOADER("SPRIHEAD",Sprite_Header_Chunk) + +/* +Children for Sprite_Header_Chunk : + +"SPRITVER" Sprite_Version_Number_Chunk +"SPRITEPC" PC_Sprite_Chunk +"SPRITEPS" Playstation_Sprite_Chunk +"SPRITESA" Saturn_Sprite_Chunk +"BMPLSTST" Bitmap_List_Store_Chunk +"BMNAMVER" BMP_Names_Version_Chunk +"BMNAMEXT" BMP_Names_ExtraData_Chunk +"RIFFNAME" RIF_Name_Chunk +"SHPEXTFN" Shape_External_Filename_Chunk +"SPRISIZE" Sprite_Size_Chunk +"BMPMD5ID" Bitmap_MD5_Chunk +"SPRBMPSC" Sprite_Bitmap_Scale_Chunk +"SPRBMPCE" Sprite_Bitmap_Centre_Chunk +"SPREXTEN" Sprite_Extent_Chunk +*/ + + +Sprite_Header_Chunk::Sprite_Header_Chunk(const char * file_name, Chunk_With_Children * parent) +: Chunk_With_Children(parent,"SPRIHEAD") +{ +// Load in whole chunk and traverse + HANDLE rif_file; + DWORD file_size; + DWORD file_size_from_file; + unsigned long bytes_read; + char * buffer; + char * buffer_ptr; + char id_buffer[9]; + + Parent_File = this; + + error_code = 0; + + + rif_file = CreateFileA (file_name, GENERIC_READ, 0, 0, OPEN_EXISTING, + FILE_FLAG_RANDOM_ACCESS, 0); + + if (rif_file == INVALID_HANDLE_VALUE) { + return; + } + + file_size = GetFileSize (rif_file, NULL); + + + if (!ReadFile(rif_file, id_buffer, 8, &bytes_read, 0)) { + error_code = CHUNK_FAILED_ON_LOAD; + CloseHandle (rif_file); + return; + } + + if (strncmp (id_buffer, "SPRIHEAD", 8)) { + error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + CloseHandle (rif_file); + return; + } + + if (!ReadFile(rif_file, &file_size_from_file, 4, &bytes_read, 0)) { + error_code = CHUNK_FAILED_ON_LOAD; + CloseHandle (rif_file); + return; + } + + if (file_size != file_size_from_file) { + error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + CloseHandle (rif_file); + return; + } + + + buffer = new char [file_size]; + + if (!ReadFile(rif_file, buffer, (file_size-12), &bytes_read, 0)) { + error_code = CHUNK_FAILED_ON_LOAD; + CloseHandle (rif_file); + return; + } + + // Process the file + + buffer_ptr = buffer; + + + // The start of the first chunk + + while ((buffer_ptr-buffer)< ((signed) file_size-12) && !error_code) { + + if ((*(int *)(buffer_ptr + 8)) + (buffer_ptr-buffer) > ((signed) file_size-12)) { + error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + + DynCreate(buffer_ptr); + buffer_ptr += *(int *)(buffer_ptr + 8); + + } + + delete [] buffer; + + CloseHandle (rif_file); + +} + + +Sprite_Header_Chunk::write_file(const char* fname) +{ + HANDLE rif_file; + + rif_file = CreateFileA (fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_FLAG_RANDOM_ACCESS, 0); + + if (rif_file == INVALID_HANDLE_VALUE) { + return CHUNK_FAILED_ON_WRITE; + } + + size_chunk(); + + if (!(this->output_chunk(rif_file))) + return CHUNK_FAILED_ON_WRITE; + + CloseHandle (rif_file); + + return 0; +} + +Sprite_Header_Chunk::output_chunk(HANDLE & hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = this->make_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; +} + +#if cencon +void Sprite_Header_Chunk::post_input_processing() +{ + if (parent) + { + List chlst; + GetRootChunk()->lookup_child("REBENVDT",chlst); + Lockable_Chunk_With_Children * envd = 0; + if (chlst.size()) envd = (Lockable_Chunk_With_Children *) chlst.first_entry(); + + BOOL fixpal = IsFixedPalette(envd); + + lookup_child("SHPEXTFN",chlst); + + if (chlst.size()) + { + Shape_External_Filename_Chunk * sefc = (Shape_External_Filename_Chunk *)chlst.first_entry(); + + #if cencon + twprintf("Locating %s\n",sefc->file_name); + char * locatedfile = FindExistingFileInPath_PreferWriteable(CWnd::GetActiveWindow(),sefc->file_name,"RifSearchPath"); + twprintf("Loading %s\n",locatedfile ? locatedfile : sefc->file_name); + Sprite_Header_Chunk rfc(locatedfile ? locatedfile : sefc->file_name); + if (locatedfile) + { + delete[] locatedfile; + } + #else + Sprite_Header_Chunk rfc(sefc->file_name); + #endif + + if (rfc.error_code != 0) + { + return; + } + + lookup_child("SPRITVER",chlst); + int myver = -2; + if (chlst.size()) + { + Sprite_Version_Number_Chunk * svnc = (Sprite_Version_Number_Chunk *)chlst.first_entry(); + myver = svnc->version_num; + } + rfc.lookup_child("SPRITVER",chlst); + int yourver = -1; + if (chlst.size()) + { + Sprite_Version_Number_Chunk * svnc = (Sprite_Version_Number_Chunk *)chlst.first_entry(); + yourver = svnc->version_num; + } + + if (yourver != myver) + { + #define NOT_A_BITMAP_RELATED_CHUNK \ + strncmp ("BMPLSTST", child_ptr->identifier, 8) && \ + strncmp ("BMNAMVER", child_ptr->identifier, 8) && \ + strncmp ("BMNAMEXT", child_ptr->identifier, 8) && \ + strncmp ("RIFFNAME", child_ptr->identifier, 8) && \ + strncmp ("SHPEXTFN", child_ptr->identifier, 8) && \ + strncmp ("BMPMD5ID", child_ptr->identifier, 8) + + Chunk * child_ptr = children; + List chunks_to_delete; + while (child_ptr != NULL) + { + if (NOT_A_BITMAP_RELATED_CHUNK) + { + chunks_to_delete.add_entry(child_ptr); + } + child_ptr = child_ptr->next; + } + for (LIF delchunks(&chunks_to_delete); !delchunks.done(); delchunks.next()) + { + delete delchunks(); + } + + child_ptr = rfc.children; + while (child_ptr != NULL) + { + if (NOT_A_BITMAP_RELATED_CHUNK) + { + #define CREATE_CHUNK_END(_datablock) \ + new Miscellaneous_Chunk(this,_datablock,_datablock+12,*(int *)(_datablock+8)-12); + + #define CREATE_CHUNK_FOR(_datablock,_id,_chunkclass) \ + if (!strncmp(_datablock,_id,8)) { \ + new _chunkclass(this,_datablock+12,*(int *)(_datablock+8)-12); \ + } else + + child_ptr->prepare_for_output(); + char * datablock = child_ptr->make_data_block_from_chunk(); + + CREATE_CHUNK_FOR(datablock,"SPRITVER",Sprite_Version_Number_Chunk) + CREATE_CHUNK_FOR(datablock,"SPRITEPC",PC_Sprite_Chunk) + CREATE_CHUNK_FOR(datablock,"SPRITEPS",Playstation_Sprite_Chunk) + CREATE_CHUNK_FOR(datablock,"SPRITESA",Saturn_Sprite_Chunk) + CREATE_CHUNK_FOR(datablock,"SPRISIZE",Sprite_Size_Chunk) + CREATE_CHUNK_FOR(datablock,"SPRBMPSC",Sprite_Bitmap_Scale_Chunk) + CREATE_CHUNK_FOR(datablock,"SPRBMPCE",Sprite_Bitmap_Centre_Chunk) + CREATE_CHUNK_FOR(datablock,"SPREXTEN",Sprite_Extent_Chunk) + CREATE_CHUNK_END(datablock) + + delete[] datablock; + } + child_ptr = child_ptr->next; + } + + } + + Chunk_With_BMPs * blsc = 0; + Chunk_With_BMPs * gbnc = 0; + + rfc.lookup_child("BMPLSTST",chlst); + if (chlst.size()) + { + gbnc = (Chunk_With_BMPs *) chlst.first_entry(); + if (!gbnc->bmps.size()) gbnc = 0; + } + + List oldlst; + lookup_child("BMPLSTST",oldlst); + assert (oldlst.size()<2); + + if (oldlst.size()) + { + blsc = (Bitmap_List_Store_Chunk *)oldlst.first_entry(); + } + else + { + if (gbnc) blsc = new Bitmap_List_Store_Chunk(this); + } + + BMP_Names_ExtraData * extended = 0; + if (blsc) + { + extended = blsc->GetExtendedData(); + if (fixpal) + extended->flags = (GlobalBMPFlags)(extended->flags | GBF_FIXEDPALETTE); + else + extended->flags = (GlobalBMPFlags)(extended->flags & ~GBF_FIXEDPALETTE); + } + if (gbnc) + { + if ((gbnc->get_version_num()!=blsc->get_version_num()) || (gbnc->bmps.size() != blsc->bmps.size())) + { // other checks could be done as well + if (blsc->bmps.size()) + { + BOOL neednewpalette = FALSE; + + List newlist = gbnc->bmps; + for (LIF newLIF(&newlist); !newLIF.done(); newLIF.next()) + { + BMP_Name newcur = newLIF(); + newcur.flags = (BMPN_Flags) (newcur.flags & ~(COMPLETED_BMPN_FLAGS | ChunkBMPFlag_FixedPalette)); + if (fixpal) newcur.flags = (BMPN_Flags) (newcur.flags | ChunkBMPFlag_FixedPalette); + for (LIF oldLIF(&blsc->bmps); !oldLIF.done(); oldLIF.next()) + { + BMP_Name oldcur = oldLIF(); + if (newcur == oldcur) + { + // do we need to requantize? + if ((oldcur.flags ^ newcur.flags) & CHECKMODIFY_BMPN_FLAGS + || newcur.flags & ChunkBMPFlag_UsesTransparency + && !(newcur.flags & ChunkBMPFlag_IFF) + && !(oldcur.flags & ChunkBMPFlag_IFF) + && oldcur.DifferentTransparencyColour(newcur)) + oldcur.flags = (BMPN_Flags)(oldcur.flags & ~COMPLETED_BMPN_FLAGS); + // keep some of the old flags - the ones that can differ + newcur.flags = (BMPN_Flags)(newcur.flags & COPY_BMPN_FLAGS); + newcur.flags = (BMPN_Flags)(newcur.flags | oldcur.flags & ~COPY_BMPN_FLAGS); + if (oldcur.version_num != newcur.version_num) + { + neednewpalette = TRUE; + newcur.flags = (BMPN_Flags)(newcur.flags & ~ChunkBMPFlag_HistogramExists); + extended->flags = (GlobalBMPFlags)(extended->flags & ~GBF_HISTOGRAMEXISTS); + } + break; + } + } + if (oldLIF.done()) + { + // reset palette up to date flag + neednewpalette = TRUE; + newcur.flags = (BMPN_Flags)(newcur.flags & ~(ChunkBMPFlag_HistogramExists | COMPLETED_BMPN_FLAGS)); + extended->flags = (GlobalBMPFlags)(extended->flags & ~GBF_HISTOGRAMEXISTS); + } + newLIF.change_current(newcur); + } + + // check if any bitmaps have been removed + for (LIF bli(&blsc->bmps); !bli.done(); bli.next()) + { + if (!newlist.contains(bli())) + { + // delete assoc files + neednewpalette = TRUE; + extended->flags = (GlobalBMPFlags)(extended->flags & ~GBF_HISTOGRAMEXISTS); + } + } + + if (neednewpalette) + { + Palette_Outdated(envd); + if (fixpal) FixedPalette_Outdated(envd); + envd->updated = TRUE; + } + blsc->bmps = newlist; + } + else + { + blsc->bmps = gbnc->bmps; + for (LIF flagresetLIF(&blsc->bmps); !flagresetLIF.done(); flagresetLIF.next()) + { + BMP_Name current = flagresetLIF(); + current.flags = (BMPN_Flags)(current.flags & (COPY_BMPN_FLAGS & ~ChunkBMPFlag_FixedPalette)); + if (fixpal) current.flags = (BMPN_Flags) (current.flags | ChunkBMPFlag_FixedPalette); + flagresetLIF.change_current(current); + } + // reset palette up to date flag + extended->flags = (GlobalBMPFlags)(extended->flags & ~GBF_HISTOGRAMEXISTS); + Palette_Outdated(envd); + if (fixpal) FixedPalette_Outdated(envd); + envd->updated = TRUE; + } + blsc->max_index = gbnc->max_index; + blsc->set_version_num(gbnc->get_version_num()); + assert (!strcmp("RSPRITES",parent->identifier)); + ((Lockable_Chunk_With_Children *)parent)->updated = TRUE; + } + } + else + { + if (blsc) + { + if (blsc->bmps.size()) + { + // reset palette up to date flag + extended->flags = (GlobalBMPFlags)(extended->flags & ~GBF_HISTOGRAMEXISTS); + Palette_Outdated(envd); + if (fixpal) FixedPalette_Outdated(envd); + envd->updated = TRUE; + assert (!strcmp("RSPRITES",parent->identifier)); + ((Lockable_Chunk_With_Children *)parent)->updated = TRUE; + } + delete blsc; + } + } + + } + + } + Chunk_With_Children::post_input_processing(); +} +#endif +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("SPRITEPC",PC_Sprite_Chunk,"SPRIHEAD",Sprite_Header_Chunk) + +PC_Sprite_Chunk::PC_Sprite_Chunk(Sprite_Header_Chunk* parent,const char* data,size_t datasize) +:Chunk_With_Children(parent,"SPRITEPC") +{ + const char * buffer_ptr = data; + + + while ((data-buffer_ptr)< (signed) datasize) { + + if ((*(int *)(data + 8)) + (data-buffer_ptr) > (signed) datasize) { + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + + if (!strncmp(data, "SPRACTIO",8)) { + new Sprite_Action_Chunk (this, (data + 12), (*(int *) (data + 8))-12); + data += *(int *)(data + 8); + } + else { + new Miscellaneous_Chunk (this, data, (data + 12), (*(int *) (data + 8)) -12 ); + data += *(int *)(data + 8); + } + + } +} +///////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("SPRITESA",Saturn_Sprite_Chunk,"SPRIHEAD",Sprite_Header_Chunk) + + +Saturn_Sprite_Chunk::Saturn_Sprite_Chunk(Sprite_Header_Chunk* parent,const char* data,size_t datasize) +:Chunk_With_Children(parent,"SPRITESA") +{ + const char * buffer_ptr = data; + + + while ((data-buffer_ptr)< (signed) datasize) { + + if ((*(int *)(data + 8)) + (data-buffer_ptr) > (signed) datasize) { + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + + if (!strncmp(data, "SPRACTIO",8)) { + new Sprite_Action_Chunk (this, (data + 12), (*(int *) (data + 8))-12); + data += *(int *)(data + 8); + } + else { + new Miscellaneous_Chunk (this, data, (data + 12), (*(int *) (data + 8)) -12 ); + data += *(int *)(data + 8); + } + + } +} +///////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE_DECLARE_PARENT("SPRITEPS",Playstation_Sprite_Chunk,"SPRIHEAD",Sprite_Header_Chunk) + +Playstation_Sprite_Chunk::Playstation_Sprite_Chunk(Sprite_Header_Chunk* parent,const char* data,size_t datasize) +:Chunk_With_Children(parent,"SPRITEPS") +{ + const char * buffer_ptr = data; + + + while ((data-buffer_ptr)< (signed) datasize) { + + if ((*(int *)(data + 8)) + (data-buffer_ptr) > (signed) datasize) { + Parent_File->error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED; + break; + } + + if (!strncmp(data, "SPRACTIO",8)) { + new Sprite_Action_Chunk (this, (data + 12), (*(int *) (data + 8))-12); + data += *(int *)(data + 8); + } + else { + new Miscellaneous_Chunk (this, data, (data + 12), (*(int *) (data + 8)) -12 ); + data += *(int *)(data + 8); + } + + } +} + + + +//////////////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("SPRISIZE",Sprite_Size_Chunk) + + +Sprite_Size_Chunk::Sprite_Size_Chunk(Chunk_With_Children* parent,const char* data,size_t /*datasize*/) +: Chunk(parent, "SPRISIZE") +{ + scale=*(double*)data; + data+=8; + maxy=*(double*)data; + data+=8; + maxx=*(double*)data; + data+=8; + radius=*(int*)data; + data+=4; + Flags=*(int*)data; + data+=4; +} + +Sprite_Size_Chunk::Sprite_Size_Chunk(Chunk_With_Children* parent) +: Chunk(parent, "SPRISIZE") +{ + scale=15.625; + maxy=1000; + maxx=500; + radius=0; + Flags=0; +} + +BOOL Sprite_Size_Chunk::output_chunk (HANDLE &hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = this->make_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; +} + +size_t Sprite_Size_Chunk::size_chunk() +{ + chunk_size=44; + return chunk_size; +} + +void Sprite_Size_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *(double*)data_start=scale; + data_start+=8; + *(double*)data_start=maxy; + data_start+=8; + *(double*)data_start=maxx; + data_start+=8; + *(int*)data_start=radius; + data_start+=4; + *(int*)data_start=Flags; + data_start+=4; +} +/////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("SPRITVER",Sprite_Version_Number_Chunk) + +Sprite_Version_Number_Chunk::Sprite_Version_Number_Chunk(Chunk_With_Children* parent,const char* data,size_t /*datasize*/) +: Chunk(parent, "SPRITVER") +{ + version_num=*(int*)data; + data+=4; +} + +Sprite_Version_Number_Chunk::Sprite_Version_Number_Chunk(Chunk_With_Children* parent) +: Chunk(parent, "SPRITVER") +{ + version_num=0; +} + +BOOL Sprite_Version_Number_Chunk::output_chunk (HANDLE &hand) +{ + unsigned long junk; + BOOL ok; + char * data_block; + + data_block = this->make_data_block_from_chunk(); + + ok = WriteFile (hand, (long *) data_block, (unsigned long) chunk_size, &junk, 0); + + delete [] data_block; + + if (!ok) return FALSE; + + return TRUE; +} + +size_t Sprite_Version_Number_Chunk::size_chunk() +{ + chunk_size=16; + return chunk_size; +} + +void Sprite_Version_Number_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *(int*)data_start=version_num; +} + + +////////////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("SPRBMPSC",Sprite_Bitmap_Scale_Chunk) + + +Sprite_Bitmap_Scale_Chunk::Sprite_Bitmap_Scale_Chunk(Chunk_With_Children* parent,const char* data,size_t /*datasize*/) +: Chunk(parent, "SPRBMPSC") +{ + NumBitmaps=*(int*)data; + data+=4; + if(NumBitmaps) + { + Scale=new float[NumBitmaps]; + for(int i=0;i +#include + +#include "inline.h" + +#ifdef RIFF_SYSTEM +#include "chnktexi.h" +#endif + +#define UseLocalAssert 0 +#include "ourasert.h" + +#else + +#include +#include +#include + +#include "system.h" +#include "equates.h" +#include "platform.h" +#include "shape.h" +#include "prototyp.h" +#include "inline.h" + +#ifdef RIFF_SYSTEM +#include "chnktexi.h" +#endif + + +#endif + + +#include "awTexLd.h" +#include "alt_tab.h" + +/* + #define for experimental purposes + ONLY!!! +*/ + +#define DefinedTextureType TextureTypePPM + + +#if 0 +#if debug +int tripa = 100; +int tripb = 100; +int tripc = 0; +#define trip_up tripa = tripb / tripc; +#endif +#endif + + +/* + + externs for commonly used global variables and arrays + +*/ + + extern SHAPEHEADER **mainshapelist; + extern (*ShapeLanguageFunctions[])(SHAPEINSTR *shapeinstrptr); + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + extern unsigned char *ScreenBuffer; + extern char projectsubdirectory[]; + extern int ScanDrawMode; + extern int VideoModeType; + +/* + + Global Variables for PC Functions + +*/ + + TEXTURE *ImageBuffer; /* Memory Resident Image Data */ + + #ifdef MaxImageGroups + #if MaxImageGroups < 2 /* optimize if this multiple groups are not required */ + #undef MaxImageGroups + #endif /* MaxImageGroups < 2 */ + #endif /* MaxImageGroups */ + + #ifdef MaxImageGroups + + #include "txioctrl.h" + + /* + basically, I want there to be more than one image header array + so that I can load some images once only, then load shapes, call + InitializeTextures, DeallocateAllImages, etc. and only the images associated + with the shapes load are deallocated. + I might want to load shapes in two blocks, calling InitializeTextures + for each load. + + There will need to be as many slots for ImageHeaderArrays as MaxImageGroups + + I want this to be completely invisible to anyone except programmers on + PC projects that require this feature + + Jake. + */ + + /* these three globals must behave the same */ + int NumImages = 0; /* # current images */ + IMAGEHEADER *ImageHeaderPtrs[MaxImageGroups*MaxImages]; /* Ptrs to Image Header Blocks */ + IMAGEHEADER ImageHeaderArray[MaxImageGroups*MaxImages]; /* Array of Image Headers */ + + int NumImagesArray[MaxImageGroups]; /* must be static to ensure initialization to zero */ + static int CurrentImageGroup = 0; + static IMAGEHEADER *NextFreeImageHeaderPtr[MaxImageGroups]; + + #else /* ! MaxImageGroups */ + + int NumImages = 0; /* # current images */ + IMAGEHEADER *ImageHeaderPtrs[MaxImages]; /* Ptrs to Image Header Blocks */ + IMAGEHEADER ImageHeaderArray[MaxImages]; /* Array of Image Headers */ + + static IMAGEHEADER *NextFreeImageHeaderPtr; + + #endif /* ! MaxImageGroups */ + + +/* + + Initialise General Texture Data Structures and Variables + +*/ + + +#if LoadingMapsShapesAndTexturesEtc + + +void InitialiseImageHeaders(void) + +{ + #ifdef MaxImageGroups + + NumImages = CurrentImageGroup * MaxImages; + NextFreeImageHeaderPtr[CurrentImageGroup] = &ImageHeaderArray[CurrentImageGroup*MaxImages]; + + #else + + NumImages = 0; + NextFreeImageHeaderPtr = ImageHeaderArray; + + #endif +} + + +int LoadImageCHsForShapes(SHAPEHEADER **shapelist) + +{ + + SHAPEHEADER **shlistptr; + SHAPEHEADER *shptr; + char **txfiles; + int TxIndex; + int LTxIndex; + + +/* + + Build the Texture List + +*/ + + shlistptr = shapelist; + + while(*shlistptr) { + + shptr = *shlistptr++; + + /* If the shape has textures */ + + if(shptr->sh_localtextures) { + + txfiles = shptr->sh_localtextures; + + LTxIndex = 0; + + while(*txfiles) { + + /* The RIFF Image loaders have changed to support not loading the same image twice - JH 17-2-96 */ + + char *src; + char *dst; + char fname[ImageNameSize]; + char *texfilesptr; + #ifndef RIFF_SYSTEM + int i, j, NewImage; + char *iname; + IMAGEHEADER *ihptr; + IMAGEHEADER *new_ihptr; + void* im; + #endif + + txfilesptr = *txfiles++; + + /* + + "txfilesptr" is in the form "textures\". We need to + prefix that text with the name of the current textures path. + + Soon this path may be varied but for now it is just the name of + the current project subdirectory. + + */ + + src = projectsubdirectory; + dst = fname; + + while(*src) + *dst++ = *src++; + + src = txfilesptr; + + while(*src) + *dst++ = *src++; + + *dst = 0; + + #ifdef RIFF_SYSTEM + + /* This function calls GetExistingImageHeader to figure out if the image is already loaded */ + TxIndex = CL_LoadImageOnce(fname,(ScanDrawDirectDraw == ScanDrawMode ? LIO_CHIMAGE : LIO_D3DTEXTURE)|LIO_TRANSPARENT|LIO_RELATIVEPATH|LIO_RESTORABLE); + GLOBALASSERT(GEI_NOTLOADED != TxIndex); + + #else + + /* If there are already images, try and find this one */ + + NewImage = Yes; + + #ifdef MaxImageGroups + + TxIndex = CurrentImageGroup * MaxImages; /* Assume image 0 */ + + if(NumImagesArray[CurrentImageGroup]) { + + for(i=NumImagesArray[CurrentImageGroup]; i!=0 && NewImage!=No; i--) { + + #else + + TxIndex = 0; /* Assume image 0 */ + + if(NumImages) { + + for(i=NumImages; i!=0 && NewImage!=No; i--) { + + #endif + + ihptr = ImageHeaderPtrs[TxIndex]; + + iname = &ihptr->ImageName[0]; + + j = CompareFilenameCH(txfilesptr, iname); + + if(j) NewImage = No; + + else TxIndex++; + + } + + } + + + /* If this is a new image, add it */ + + if(NewImage) { + + /* Get an Image Header */ + + new_ihptr = GetImageHeader(); + + if(new_ihptr) { + + if (ScanDrawMode == ScanDrawDirectDraw) + im = (void*) LoadImageCH(&fname[0], new_ihptr); + else + im = LoadImageIntoD3DImmediateSurface + (&fname[0], new_ihptr, DefinedTextureType); + + } + + } + + #endif + + /* + + The local index for this image in this shape is + "LTxIndex". + + The global index for the image is "TxIndex". + + We must go through the shape's items and change all the + local references to global. + + */ + + MakeShapeTexturesGlobal(shptr, TxIndex, LTxIndex); + + LTxIndex++; /* Next Local Texture */ + + } + + /* Is this shape a sprite that requires resizing? */ + + if((shptr->shapeflags & ShapeFlag_Sprite) && + (shptr->shapeflags & ShapeFlag_SpriteResizing)) { + + SpriteResizing(shptr); + + } + + } + + } + + + return Yes; + + +} + + +#else + + +#define InitTexPrnt No + +int InitialiseTextures(void) + +{ + + SHAPEHEADER **shlistptr; + SHAPEHEADER *shptr; + char **txfiles; + int TxIndex; + int LTxIndex; + + /* + + Free up any currently loaded images + + The caller is responsible for any other structures which might refer + to the currently loaded images + + */ + + #ifdef MaxImageGroups + + DeallocateCurrentImages(); + + NumImages = CurrentImageGroup * MaxImages; + NextFreeImageHeaderPtr[CurrentImageGroup] = &ImageHeaderArray[CurrentImageGroup*MaxImages]; + + #else + + DeallocateAllImages(); + + /* Initialise Image Header Variables */ + + NumImages = 0; + NextFreeImageHeaderPtr = ImageHeaderArray; + + #endif + + /* Added 23/3/98 by DHM so that this can be called without loading any + shapes (to get textprint working in the menus): + */ + if ( NULL == mainshapelist ) + { + return Yes; + // early exit + } + + /* Build the Texture List */ + + shlistptr = &mainshapelist[0]; + + while(*shlistptr) { + + shptr = *shlistptr++; + + /* If the shape has textures */ + + if(shptr->sh_localtextures) { + + #if InitTexPrnt + textprint("This shape has textures\n"); + #endif + + txfiles = shptr->sh_localtextures; + + LTxIndex = 0; + + while(*txfiles) { + + /* The RIFF Image loaders have changed to support not loading the same image twice - JH 17-2-96 */ + + char *src; + char *dst; + char fname[ImageNameSize]; + char *txfilesptr; + #ifndef RIFF_SYSTEM + int i, j, NewImage; + char *iname; + IMAGEHEADER *ihptr; + IMAGEHEADER *new_ihptr; + void* im; + #endif + + txfilesptr = *txfiles++; + + /* + + "txfilesptr" is in the form "textures\". We need to + prefix that text with the name of the current textures path. + + Soon this path may be varied but for now it is just the name of + the current project subdirectory. + + */ + + src = projectsubdirectory; + dst = fname; + + while(*src) + *dst++ = *src++; + + src = txfilesptr; + + while(*src) + *dst++ = *src++; + + *dst = 0; + + + #if InitTexPrnt + textprint(" A Texture\n"); + #endif + + + #ifdef RIFF_SYSTEM + + /* This function calls GetExistingImageHeader to figure out if the image is already loaded */ + TxIndex = CL_LoadImageOnce(fname,(ScanDrawDirectDraw == ScanDrawMode ? LIO_CHIMAGE : LIO_D3DTEXTURE)|LIO_TRANSPARENT|LIO_RELATIVEPATH|LIO_RESTORABLE); + GLOBALASSERT(GEI_NOTLOADED != TxIndex); + + #else + + /* If there are already images, try and find this one */ + + NewImage = Yes; + + #ifdef MaxImageGroups + + TxIndex = CurrentImageGroup * MaxImages; /* Assume image 0 */ + + if(NumImagesArray[CurrentImageGroup]) { + + for(i=NumImagesArray[CurrentImageGroup]; i!=0 && NewImage!=No; i--) { + + #else + + TxIndex = 0; /* Assume image 0 */ + + if(NumImages) { + + for(i=NumImages; i!=0 && NewImage!=No; i--) { + + #endif + + ihptr = ImageHeaderPtrs[TxIndex]; + + iname = &ihptr->ImageName[0]; + + j = CompareFilenameCH(txfilesptr, iname); + + if(j) NewImage = No; + + else TxIndex++; + + } + + } + + + /* If this is a new image, add it */ + + if(NewImage) { + + #if InitTexPrnt + textprint("New Image\n"); + WaitForReturn(); + #endif + + /* Get an Image Header */ + + new_ihptr = GetImageHeader(); + + if(new_ihptr) { + + if (ScanDrawMode == ScanDrawDirectDraw) + im = (void*) LoadImageCH(&fname[0], new_ihptr); + else + im = LoadImageIntoD3DImmediateSurface + (&fname[0], new_ihptr, DefinedTextureType); + + if(im) { + + #if InitTexPrnt + textprint("Load OK, NumImages = %d\n", NumImages); + WaitForReturn(); + #endif + + } + + } + + } + + + /* test */ + + #if InitTexPrnt + else textprint("Image Already Exists\n"); + #endif + + #endif + + /* + + The local index for this image in this shape is + "LTxIndex". + + The global index for the image is "TxIndex". + + We must go through the shape's items and change all the + local references to global. + + */ + + #if InitTexPrnt + textprint("\nLocal to Global for Shape\n"); + #endif + + MakeShapeTexturesGlobal(shptr, TxIndex, LTxIndex); + + LTxIndex++; /* Next Local Texture */ + + } + + /* Is this shape a sprite that requires resizing? */ + + if((shptr->shapeflags & ShapeFlag_Sprite) && + (shptr->shapeflags & ShapeFlag_SpriteResizing)) { + + SpriteResizing(shptr); + + } + + } + + } + + #if InitTexPrnt + textprint("\nFinished PP for textures\n"); + + WaitForReturn(); + + #endif + + + return Yes; + + +} + + +#endif + + +/* + + This function accepts a shape header, a global texture index and a local + index. It searches through all the items that use textures and converts all + local references to a texture to global references. + + The index to a texture that refers to the IMAGEHEADER pointer array is in + the low word of the colour int. + + Bit #15 is set if this index refers to a local texture. + + Here is an example of a textured item: + + +int CUBE_item3[]={ + + I_2dTexturedPolygon,3*vsize,0, + + (3<items) { + + #if InitTexPrnt + textprint("Item Array\n"); + #endif + + ShapeItemArrayPtr = shptr->items; + + for(i = shptr->numitems; i!=0; i--) { + + ShapeItemPtr = (POLYHEADER *) *ShapeItemArrayPtr++; + + #if SupportZBuffering + + if(ShapeItemPtr->PolyItemType == I_2dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_ZB_2dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_Gouraud2dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_ZB_Gouraud2dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_Gouraud3dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_ZB_Gouraud3dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_ScaledSprite + || ShapeItemPtr->PolyItemType == I_3dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_ZB_3dTexturedPolygon) { + #else + if(ShapeItemPtr->PolyItemType == I_2dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_Gouraud2dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_Gouraud3dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_ScaledSprite + || ShapeItemPtr->PolyItemType == I_3dTexturedPolygon){ + #endif /* SupportZBuffering */ + + if(ShapeItemPtr->PolyFlags & iflag_txanim) { + + MakeTxAnimFrameTexturesGlobal(shptr, ShapeItemPtr, + LTxIndex, TxIndex); + + } + + if(ShapeItemPtr->PolyColour & TxLocal) { + + txi = ShapeItemPtr->PolyColour; + txi &= ~TxLocal; /* Clear Flag */ + txi &= ClrTxDefn; /* Clear UV array index */ + + /* Is this the local index? */ + + if(txi == LTxIndex) { + + /* Clear low word, OR in global index */ + + ShapeItemPtr->PolyColour &= ClrTxIndex; + ShapeItemPtr->PolyColour |= TxIndex; + + } + + } + + } + + } + + } + + #if SupportBSP + + /* Or are they in a BSP block array? */ + + else if(shptr->sh_bsp_blocks) { + + #if InitTexPrnt + textprint("BSP Block Array\n"); + #endif + + #if 0 + /* Find the BSP Instruction */ + ShInstrPtr = shptr->sh_instruction; + num_bsp_blocks = 0; + while(ShInstrPtr->sh_instr != I_ShapeEnd) { + if(ShInstrPtr->sh_instr == I_ShapeBSPTree) { + num_bsp_blocks = ShInstrPtr->sh_numitems; + } + ShInstrPtr++; + } + #endif + + num_bsp_blocks = FindNumBSPNodes(shptr); + + + #if InitTexPrnt + textprint("Number of BSP blocks = %d\n", num_bsp_blocks); + #endif + + if(num_bsp_blocks) { + + ShapeBSPPtr = shptr->sh_bsp_blocks; + + for(k=num_bsp_blocks; k!=0; k--) { + + ShapeItemArrayPtr = ShapeBSPPtr->bsp_block_data; + + for(j=ShapeBSPPtr->bsp_numitems; j!=0; j--) { + + ShapeItemPtr = (POLYHEADER *) *ShapeItemArrayPtr++; + + #if InitTexPrnt + textprint("shape item\n"); + #endif + + if(ShapeItemPtr->PolyItemType == I_2dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_ZB_2dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_Gouraud2dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_ZB_Gouraud2dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_Gouraud3dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_ZB_Gouraud3dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_ScaledSprite + || ShapeItemPtr->PolyItemType == I_3dTexturedPolygon + || ShapeItemPtr->PolyItemType == I_ZB_3dTexturedPolygon) { + + if(ShapeItemPtr->PolyFlags & iflag_txanim) { + + MakeTxAnimFrameTexturesGlobal(shptr, ShapeItemPtr, + LTxIndex, TxIndex); + + } + + #if InitTexPrnt + textprint(" - textured\n"); + #endif + + if(ShapeItemPtr->PolyColour & TxLocal) { + + #if InitTexPrnt + textprint(" - local index\n"); + #endif + + txi = ShapeItemPtr->PolyColour; + txi &= ~(TxLocal); /* Clear Flag */ + txi &= ClrTxDefn; /* Clear Defn */ + + #if InitTexPrnt + textprint(" - is %d\n", txi); + textprint(" - LTxIndex is %d\n", LTxIndex); + #endif + + /* Is this the local index? */ + + if(txi == LTxIndex) { + + /* Clear low word, OR in global index */ + + ShapeItemPtr->PolyColour &= ClrTxIndex; + ShapeItemPtr->PolyColour |= TxIndex; + + #if InitTexPrnt + textprint("Local %d, Global %d\n", LTxIndex, TxIndex); + #endif + + } + + } + + } + + } + + ShapeBSPPtr++; + + } + + } + + } + + #endif /* SupportBSP */ + + /* Otherwise the shape has no item data */ + + +} + + +/* + + The animated texture frames each have a local image index in their frame + header structure. Convert these to global texture list indices in the same + way that the item function does. + +*/ + +void MakeTxAnimFrameTexturesGlobal(SHAPEHEADER *sptr, + POLYHEADER *pheader, + int LTxIndex, int TxIndex) + +{ + + TXANIMHEADER **txah_ptr; + TXANIMHEADER *txah; + TXANIMFRAME *txaf; + int **shape_textures; + int *txf_imageptr; + int texture_defn_index; + int i, txi, image; + + + #if 0 + textprint("LTxIndex = %d, TxIndex = %d\n", LTxIndex, TxIndex); + WaitForReturn(); + #endif + + + /* Get the animation sequence header */ + + shape_textures = sptr->sh_textures; + texture_defn_index = (pheader->PolyColour >> TxDefn); + txah_ptr = (TXANIMHEADER **) shape_textures[texture_defn_index]; + + + /* The first array element is the sequence shadow, which we skip here */ + + txah_ptr++; + + + /* Process the animation sequences */ + + while(*txah_ptr) { + + /* Get the animation header */ + + txah = *txah_ptr++; + + /* Process the animation frames */ + + if(txah && txah->txa_numframes) { + + txaf = txah->txa_framedata; + + for(i = txah->txa_numframes; i!=0; i--) { + + /* Multi-View Sprite? */ + + if(sptr->shapeflags & ShapeFlag_MultiViewSprite) { + + txf_imageptr = (int *) txaf->txf_image; + + for(image = txah->txa_num_mvs_images; image!=0; image--) { + + if(*txf_imageptr & TxLocal) { + + txi = *txf_imageptr; + txi &= ~TxLocal; /* Clear Flag */ + + if(txi == LTxIndex) { + + *txf_imageptr = TxIndex; + + } + + } + + txf_imageptr++; + + } + + } + + else { + + if(txaf->txf_image & TxLocal) { + + txi = txaf->txf_image; + txi &= ~TxLocal; /* Clear Flag */ + + if(txi == LTxIndex) { + + txaf->txf_image = TxIndex; + + } + + } + + } + + txaf++; + + } + + } + + } + +} + + + +/* + + Sprite Resizing + + or + + An Optimisation For Sprite Images + + This shape is a sprite which has requested the UV rescaling optimisation. + The UV array is resized to fit the sprite image bounding rectangle, and + after the UV array, in the space provided (don't forget that!), is a new + shape local space XY array of points which overwrite the standard values + when the shape is displayed. + +*/ + +#define sr_print No + +void SpriteResizing(SHAPEHEADER *sptr) + +{ + + TXANIMHEADER **txah_ptr; + TXANIMHEADER *txah; + TXANIMFRAME *txaf; + int **shape_textures; + IMAGEHEADER *ihdr; + IMAGEEXTENTS e; + IMAGEEXTENTS e_curr; + IMAGEPOLYEXTENTS e_poly; + int *uvptr; + int texture_defn_index; + int **item_array_ptr; + int *item_ptr; + POLYHEADER *pheader; + int i, f; + int polypts[4 * vsize]; + int *iptr; + int *iptr2; + int *mypolystart; + int *ShapePoints = *(sptr->points); + VECTOR2D cen_poly; + VECTOR2D size_poly; + VECTOR2D cen_uv_curr; + VECTOR2D size_uv_curr; + VECTOR2D cen_uv; + VECTOR2D size_uv; + VECTOR2D tv; + int *txf_imageptr; + int **txf_uvarrayptr; + int *txf_uvarray; + int image; + int num_images; + + + #if sr_print + textprint("\nSprite Resize Shape\n\n"); + #endif + + + /* Get the animation sequence header */ + + shape_textures = sptr->sh_textures; + + item_array_ptr = sptr->items; /* Assume item array */ + item_ptr = item_array_ptr[0]; /* Assume only one polygon */ + pheader = (POLYHEADER *) item_ptr; + + + /* Get the polygon points, and at the same time the extents, assuming an XY plane polygon */ + + e_poly.x_low = bigint; + e_poly.y_low = bigint; + + e_poly.x_high = smallint; + e_poly.y_high = smallint; + + iptr = polypts; + mypolystart = &pheader->Poly1stPt; + + for(i = 4; i!=0; i--) { + + iptr[ix] = ((VECTORCH*)ShapePoints)[*mypolystart].vx; + iptr[iy] = ((VECTORCH*)ShapePoints)[*mypolystart].vy; + iptr[iz] = ((VECTORCH*)ShapePoints)[*mypolystart].vz; + + if(iptr[ix] < e_poly.x_low) e_poly.x_low = iptr[ix]; + if(iptr[iy] < e_poly.y_low) e_poly.y_low = iptr[iy]; + if(iptr[ix] > e_poly.x_high) e_poly.x_high = iptr[ix]; + if(iptr[iy] > e_poly.y_high) e_poly.y_high = iptr[iy]; + + iptr += vsize; + mypolystart++; + + } + + + /* TEST */ + /*trip_up;*/ + + + texture_defn_index = (pheader->PolyColour >> TxDefn); + txah_ptr = (TXANIMHEADER **) shape_textures[texture_defn_index]; + + + /* The first array element is the sequence shadow, which we skip here */ + + txah_ptr++; + + + /* Process the animation sequences */ + + while(*txah_ptr) { + + /* Get the animation header */ + + txah = *txah_ptr++; + + /* Process the animation frames */ + + if(txah && txah->txa_numframes) { + + txaf = txah->txa_framedata; + + for(f = txah->txa_numframes; f!=0; f--) { + + + /* Multi-View Sprite? */ + + if(sptr->shapeflags & ShapeFlag_MultiViewSprite) { + + txf_imageptr = (int *) txaf->txf_image; + num_images = txah->txa_num_mvs_images; + + txf_uvarrayptr = (int **) txaf->txf_uvdata; + + } + + /* A standard "Single View" Sprite has just one image */ + + else { + + txf_imageptr = &txaf->txf_image; + num_images = 1; + + txf_uvarrayptr = &txaf->txf_uvdata; + + } + + + for(image = 0; image < num_images; image++) { + + + #if sr_print + textprint("image %d of %d \n", (image + 1), num_images); + #endif + + + /* Get the image */ + + ihdr = ImageHeaderPtrs[txf_imageptr[image]]; + + /* Get the uv array ptr */ + + txf_uvarray = txf_uvarrayptr[image]; + + /* Find the extents of the image, assuming transparency */ + + #if 0 + FindImageExtents(ihdr, txaf->txf_numuvs, txaf->txf_uvdata, &e, &e_curr); + #else + FindImageExtents(ihdr, txaf->txf_numuvs, txf_uvarray, &e, &e_curr); + #endif + + /* Convert the image extents to fixed point */ + + #if sr_print + textprint("extents = %d, %d\n", e.u_low, e.v_low); + textprint(" %d, %d\n", e.u_high, e.v_high); + WaitForReturn(); + #endif + + e.u_low <<= 16; + e.v_low <<= 16; + e.u_high <<= 16; + e.v_high <<= 16; + + /* + + We now have all the information needed to create a NEW UV array and a NEW + polygon points XY array. + + */ + + /* Centre of the polygon */ + + cen_poly.vx = (e_poly.x_low + e_poly.x_high) / 2; + cen_poly.vy = (e_poly.y_low + e_poly.y_high) / 2; + + /* Size of the polygon */ + + size_poly.vx = e_poly.x_high - e_poly.x_low; + size_poly.vy = e_poly.y_high - e_poly.y_low; + + + /* Centre of the current cookie */ + + cen_uv_curr.vx = (e_curr.u_low + e_curr.u_high) / 2; + cen_uv_curr.vy = (e_curr.v_low + e_curr.v_high) / 2; + + /* Size of the current cookie */ + + size_uv_curr.vx = e_curr.u_high - e_curr.u_low; + size_uv_curr.vy = e_curr.v_high - e_curr.v_low; + + + /* Centre of the new cookie */ + + cen_uv.vx = (e.u_low + e.u_high) / 2; + cen_uv.vy = (e.v_low + e.v_high) / 2; + + /* Size of the new cookie */ + + size_uv.vx = e.u_high - e.u_low; + size_uv.vy = e.v_high - e.v_low; + + + /* Write out the new UV data */ + + #if 0 + uvptr = txaf->txf_uvdata; + #else + uvptr = txf_uvarray; + #endif + + + /* + + Convert the duplicate UV array to this new scale + ASSUME that the format is "TL, BL, BR, TR" + + */ + + uvptr[0] = e.u_low; + uvptr[1] = e.v_low; + + uvptr[2] = e.u_low; + uvptr[3] = e.v_high; + + uvptr[4] = e.u_high; + uvptr[5] = e.v_high; + + uvptr[6] = e.u_high; + uvptr[7] = e.v_low; + + + /* + + Create the new polygon XY array + + */ + + uvptr += (txaf->txf_numuvs * 2); /* Advance the pointer past the UV array */ + + + /* Copy the polygon points (XY only) to the UV array space */ + + iptr = polypts; + iptr2 = uvptr; + + for(i = 4; i!=0; i--) { + + iptr2[0] = iptr[ix]; + iptr2[1] = iptr[iy]; + + iptr += vsize; + iptr2 += 2; + + } + + + /* Scale the polygon points */ + + iptr = uvptr; + + for(i = 4; i!=0; i--) { + + iptr[0] = WideMulNarrowDiv(iptr[0], size_uv.vx, size_uv_curr.vx); + iptr[1] = WideMulNarrowDiv(iptr[1], size_uv.vy, size_uv_curr.vy); + + iptr += 2; + + } + + + /* The translation vector in UV space */ + + tv.vx = cen_uv.vx - cen_uv_curr.vx; + tv.vy = cen_uv.vy - cen_uv_curr.vy; + + + /* And now in world space */ + + tv.vx = WideMulNarrowDiv(tv.vx, size_poly.vx, size_uv_curr.vx); + tv.vy = WideMulNarrowDiv(tv.vy, size_poly.vy, size_uv_curr.vy); + + + /* Translate the polygon points */ + + iptr = uvptr; + + for(i = 4; i!=0; i--) { + + iptr[0] += tv.vx; + iptr[1] += tv.vy; + + iptr += 2; + + } + + + #if sr_print + textprint(" (image done)\n"); + #endif + + + } + + + #if sr_print + textprint("\n"); + #endif + + + /* Next Texture Animation Frame */ + + txaf++; + + } + + } + + } + + + #if sr_print + textprint("\nResize done\n\n"); + #endif + +} + + +/* + + This function is for animated sprites, although it has been given an interface that would + allow anyone to call it for their own purposes. It assumes that colour 0 is transparent and + then calculates the actual maximum extents of the image. + + NOTE: + + The image scanned is that given by the CURRENT UV ARRAY and may therefore be smaller than + the actual image. This allows for animation sequences with frames on the same image. + +*/ + +void FindImageExtents(IMAGEHEADER *ihdr, int numuvs, int *uvdata, IMAGEEXTENTS *e, IMAGEEXTENTS *e_curr) + +{ + + int i; + int *uvptr; + int u, v; + int startu, endu; + int startv, endv; + + + /* Find the current UV extents */ + + e_curr->u_low = bigint; + e_curr->v_low = bigint; + + e_curr->u_high = smallint; + e_curr->v_high = smallint; + + uvptr = uvdata; + + for(i = numuvs; i!=0; i--) { + + if(uvptr[0] < e_curr->u_low) e_curr->u_low = uvptr[0]; + if(uvptr[1] < e_curr->v_low) e_curr->v_low = uvptr[1]; + + if(uvptr[0] > e_curr->u_high) e_curr->u_high = uvptr[0]; + if(uvptr[1] > e_curr->v_high) e_curr->v_high = uvptr[1]; + + uvptr += 2; + + } + + + /* Look for the actual UV extents, assuming that colour 0 is transparent */ + + switch(VideoModeType) { + + case VideoModeType_8: + + { + + TEXTURE *tptr = ihdr->ImagePtr; + TEXTURE texel; + + + /* Search for u_low and v_low */ + + e->u_low = bigint; + e->v_low = bigint; + + startv = e_curr->v_low >> 16; + endv = e_curr->v_high >> 16; + startu = e_curr->u_low >> 16; + endu = e_curr->u_high >> 16; + + for(v = startv; v <= endv; v++) { + + for(u = startu; u <= endu; u++) { + + texel = tptr[(v * ihdr->ImageWidth) + u]; + + if(texel) { + + if(u < e->u_low) e->u_low = u; + if(v < e->v_low) e->v_low = v; + + } + + } + + } + + if(e->u_low == bigint) e->u_low = e_curr->u_low; + if(e->v_low == bigint) e->v_low = e_curr->v_low; + + + /* Search for u_high and v_high */ + + e->u_high = smallint; + e->v_high = smallint; + + for(v = endv; v >= startv; v--) { + + for(u = endu; u >= startu; u--) { + + texel = tptr[(v * ihdr->ImageWidth) + u]; + + if(texel) { + + if(u > e->u_high) e->u_high = u; + if(v > e->v_high) e->v_high = v; + + } + + } + + } + + if(e->u_high == smallint) e->u_high = e_curr->u_high; + if(e->v_high == smallint) e->v_high = e_curr->v_high; + + + /* TEST */ + /*trip_up;*/ + + } + + break; + + case VideoModeType_15: + break; + + case VideoModeType_24: + break; + + case VideoModeType_8T: + break; + + } + +} + + + +/* + + Return a pointer to the next image header + +*/ + + +IMAGEHEADER* GetImageHeader(void) +{ + + IMAGEHEADER *iheader; + + #ifdef MaxImageGroups + + /* NumImages always points to the correct point in the array */ + do + { + iheader = NextFreeImageHeaderPtr[CurrentImageGroup]++; + } + while (IsImageInUse(CurrentImageGroup,NumImagesArray[CurrentImageGroup]++) ? ++NumImages : 0); + + GLOBALASSERT(NumImagesArray[CurrentImageGroup] < MaxImages); + + #else + + iheader = NextFreeImageHeaderPtr++; + GLOBALASSERT(NumImages < MaxImages); + + #endif + + /* ensure flags are zero */ + memset(iheader,0,sizeof(IMAGEHEADER)); + + ImageHeaderPtrs[NumImages] = iheader; + NumImages++; + + return iheader; + +} + + +/* + + Return the address of a texture image in memory, else null + +*/ + +#if 0 +void* GetTexture(int texindex) + +{ + + /* Ahem... */ + + return No; + +} +#endif + +/* + + Allocate memory for a Texture Image + +*/ + +#if 0 +TEXTURE* GetTextureMemory(int txsize) + +{ + + /* Err... */ + return No; + +} +#endif + +/* + + Deallocate memory for a Texture Image + +*/ + +#if 0 +void ReturnTextureMemory(TEXTURE *txptr) + +{ + +} +#endif + +static void DeallocateImageHeader(IMAGEHEADER * ihptr) +{ + if (ihptr->hBackup) + { + if (ihptr->DDSurface) + { + GLOBALASSERT(!ihptr->D3DTexture); + ATRemoveSurface(ihptr->DDSurface); + } + else if (ihptr->D3DTexture) + { + GLOBALASSERT(!ihptr->DDSurface); + ATRemoveTexture(ihptr->D3DTexture); + } + + AwDestroyBackupTexture(ihptr->hBackup); + ihptr->hBackup = 0; + } + + if (ihptr->ImagePtr) + { + DeallocateMem(ihptr->ImagePtr); + ihptr->ImagePtr = 0; + } + + if (ihptr->DDSurface) + { + ReleaseDDSurface(ihptr->DDSurface); + ihptr->DDSurface = (void*) 0; + } + + if (ihptr->D3DTexture) + { + ReleaseD3DTexture(ihptr->D3DTexture); + ihptr->D3DTexture = (void*) 0; + ihptr->D3DHandle = (void*) 0; + } +} + +static void MinimizeImageHeader(IMAGEHEADER * ihptr) +{ + if (ihptr->DDSurface) + { + ReleaseDDSurface(ihptr->DDSurface); + ihptr->DDSurface = (void*) 0; + } + + if (ihptr->D3DTexture) + { + ReleaseD3DTexture(ihptr->D3DTexture); + ihptr->D3DTexture = (void*) 0; + ihptr->D3DHandle = (void*) 0; + } +} + +static void RestoreImageHeader(IMAGEHEADER * ihptr) +{ + if (ScanDrawDirectDraw != ScanDrawMode) + ReloadImageIntoD3DImmediateSurface(ihptr); +} + +#ifdef MaxImageGroups + +void SetCurrentImageGroup(unsigned int group) +{ + GLOBALASSERT(group < MaxImageGroups); + CurrentImageGroup = group; + NumImages = group*MaxImages + NumImagesArray[group]; +} + +int DeallocateCurrentImages(void) +{ + int i; + IMAGEHEADER *ihptr; + + if (NumImagesArray[CurrentImageGroup]) + { + ihptr = &ImageHeaderArray[CurrentImageGroup*MaxImages]; + for (i = 0; i < NumImagesArray[CurrentImageGroup]; ++i) + { + if (CanDeleteImage(CurrentImageGroup,i)) + DeallocateImageHeader(ihptr); + ++ihptr; + } + NumImagesArray[CurrentImageGroup] = 0; + NumImages = CurrentImageGroup * MaxImages; + NextFreeImageHeaderPtr[CurrentImageGroup] = &ImageHeaderArray[CurrentImageGroup*MaxImages]; + ImageGroupFreed(CurrentImageGroup); + } + + return Yes; /* ok for the moment */ +} + +void NowDeleteImage(int img_group, int img_num_offset) +{ + DeallocateImageHeader(&ImageHeaderArray[img_group*MaxImages+img_num_offset]); +} + +int DeallocateAllImages(void) +{ + int i, j; + IMAGEHEADER *ihptr; + + for (j=0; jImageWidth * ImageHeaderPtrs[g*MaxImages+i]->ImageHeight; +} + +void ImageGroupsDebugPrintInit(void) +{ + int g; + for (g=0; gImageWidth * ImageHeaderPtrs[g*MaxImages+i]->ImageHeight; + } + } +} + +void ImageGroupsDebugPrint(void) +{ + int g; + textprint("IMAGE GROUP DEBUG INFO\nGP N_IMG N_SHR N_LFT N_TEXELS\n"); + for (g=0; gImageName,fname)) + { + if (g!=CurrentImageGroup) + MarkImageInUseByGroup(g,i,CurrentImageGroup); + return i+g*MaxImages; + } + } + } + + #else + + for (i=0, iharrayptr = ImageHeaderArray; iImageName,fname)) return i; + } + + #endif + + return GEI_NOTLOADED; +} + +#endif + diff --git a/3dc/win95/TOOLCHNK.CPP b/3dc/win95/TOOLCHNK.CPP new file mode 100644 index 0000000..b4a897b --- /dev/null +++ b/3dc/win95/TOOLCHNK.CPP @@ -0,0 +1,41 @@ +#include "toolchnk.hpp" + +#ifdef cencon +#define new my_new +#endif + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(toolchnk) + +RIF_IMPLEMENT_DYNCREATE("CAMORIGN",Camera_Origin_Chunk) + +Camera_Origin_Chunk::Camera_Origin_Chunk(Chunk_With_Children* parent) +:Chunk(parent,"CAMORIGN") +{ + location.x=0; + location.y=0; + location.z=0; + ChunkMatrix identity={1,0,0,0,1,0,0,0,1}; + orientation=identity; +} + +Camera_Origin_Chunk::Camera_Origin_Chunk(Chunk_With_Children* parent,const char* data,size_t ) +:Chunk(parent,"CAMORIGN") +{ + location=*(ChunkVector*)data; + data+=sizeof(ChunkVector); + orientation=*(ChunkMatrix*)data; +} + +void Camera_Origin_Chunk::fill_data_block(char * data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + *(ChunkVector*)data_start=location; + data_start+=sizeof(ChunkVector); + *(ChunkMatrix*)data_start=orientation; +} + diff --git a/3dc/win95/TOOLCHNK.HPP b/3dc/win95/TOOLCHNK.HPP new file mode 100644 index 0000000..f266d72 --- /dev/null +++ b/3dc/win95/TOOLCHNK.HPP @@ -0,0 +1,23 @@ +#ifndef _toolchnk_hpp +#define _toolchnk_hpp + +#include "chunk.hpp" +#include "chnktype.hpp" + +class Camera_Origin_Chunk :public Chunk +{ +public : + Camera_Origin_Chunk(Chunk_With_Children* parent); + Camera_Origin_Chunk(Chunk_With_Children * parent,const char* data,size_t size); + + ChunkVector location; + ChunkMatrix orientation;//not used yet + + virtual void fill_data_block (char * data_start); + virtual size_t size_chunk (){return chunk_size=12+sizeof(ChunkVector)+sizeof(ChunkMatrix); } + + +}; + + +#endif \ No newline at end of file diff --git a/3dc/win95/TXIOCTRL.CPP b/3dc/win95/TXIOCTRL.CPP new file mode 100644 index 0000000..53aded5 --- /dev/null +++ b/3dc/win95/TXIOCTRL.CPP @@ -0,0 +1,110 @@ +#include "txioctrl.h" + +#ifdef MaxImageGroups + +#include "list_tem.hpp" + +struct ImageNumber +{ + int group; + int offset; + + ImageNumber(){} + ImageNumber(int g,int o) : group(g), offset(o) {} + + inline int operator == (ImageNumber const & in2) const + { return group==in2.group && offset==in2.offset; } + inline int operator != (ImageNumber const & in2) const + { return ! operator == (in2); } +}; + +static List imgs_used_by_group[MaxImageGroups]; + +static List * grps_used_by_image[MaxImageGroups][MaxImages]; + +void MarkImageInUseByGroup(int img_group, int img_num_offset, int group_using) +{ + if (imgs_used_by_group[group_using].contains(ImageNumber(img_group,img_num_offset))) return; + + imgs_used_by_group[group_using].add_entry(ImageNumber(img_group,img_num_offset)); + + List * & grps_used_by_imageR = grps_used_by_image[img_group][img_num_offset]; + + if (!grps_used_by_imageR) + grps_used_by_imageR = new List(img_group); // includes itself + + if (!grps_used_by_imageR->contains(group_using)) + grps_used_by_imageR->add_entry(group_using); +} + +int IsImageInUse(int img_group, int img_num_offset) +{ + if (grps_used_by_image[img_group][img_num_offset]) + return 1; + else + return 0; +} + +int CanDeleteImage(int img_group, int img_num_offset) +{ + if (grps_used_by_image[img_group][img_num_offset]) + { + if (grps_used_by_image[img_group][img_num_offset]->contains(img_group)) + { + grps_used_by_image[img_group][img_num_offset]->delete_entry(img_group); // remove itself + if (!grps_used_by_image[img_group][img_num_offset]->size()) + { + delete grps_used_by_image[img_group][img_num_offset]; + grps_used_by_image[img_group][img_num_offset] = 0; + return 1; + } + else + return 0; + } + else + return 0; + } + else + return 1; +} + +void ImageGroupFreed(int img_group) +{ + while (imgs_used_by_group[img_group].size()) + { + ImageNumber used = imgs_used_by_group[img_group].first_entry(); + + List * & grps_used_by_imageR = grps_used_by_image[used.group][used.offset]; + + grps_used_by_imageR->delete_entry(img_group); + + if (!grps_used_by_imageR->size()) + { + NowDeleteImage(used.group,used.offset); + delete grps_used_by_imageR; + grps_used_by_imageR = 0; + } + + imgs_used_by_group[img_group].delete_first_entry(); + } +} + +void EnumSharedImages(int group_num, int numimages, ImageNumberCallbackFunction callback_fn, void * user) +{ + for (int i=0; i + +#include "vramtime.h" + +static DWORD transition_times_matrix[][VWS_MAXSTATES] = +{ +/* from DDRELEASE */ + { 0, 20, 0, 100, 100 }, +/* from D3DTEXRELEASE */ + { 20, 0, 100, 100, 100 }, +/* from DDCREATE */ + { 0, 100, 0, 20, 100 }, +/* from D3DTEXCREATE */ + { 20, 100, 20, 20, 100 }, +/* from UNKNOWN */ + { 100, 100, 100, 100, 100 } +}; + + +void WaitForVRamReady(VRAM_WAIT_STATE vws) +{ + static DWORD old_time = 0; + static VRAM_WAIT_STATE old_vws = VWS_UNKNOWN; + + DWORD new_time; + + if (0==old_time) old_time = timeGetTime(); + + do new_time = timeGetTime(); while (new_time - old_time < transition_times_matrix[old_vws][vws]); + + old_time = new_time; + old_vws = vws; +} diff --git a/3dc/win95/VRAMTIME.H b/3dc/win95/VRAMTIME.H new file mode 100644 index 0000000..aa740c2 --- /dev/null +++ b/3dc/win95/VRAMTIME.H @@ -0,0 +1,25 @@ +#ifndef _included_vramtime_h_ +#define _included_vramtime_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum VramWaitState +{ + VWS_DDRELEASE, + VWS_D3DTEXRELEASE, + VWS_DDCREATE, + VWS_D3DTEXCREATE, + VWS_UNKNOWN, + VWS_MAXSTATES + +} VRAM_WAIT_STATE; + +void WaitForVRamReady(VRAM_WAIT_STATE); + +#ifdef __cplusplus +} +#endif + +#endif /* ! _included_vramtime_h_ */ diff --git a/3dc/win95/VideoModes.cpp b/3dc/win95/VideoModes.cpp new file mode 100644 index 0000000..a91af42 --- /dev/null +++ b/3dc/win95/VideoModes.cpp @@ -0,0 +1,387 @@ +extern "C" +{ + +#include "3dc.h" +#include "videomodes.h" +#include "awTexLd.h" // to set the surface format for Aw gfx dd surface loads + +extern LPDIRECTDRAW lpDD; +DEVICEANDVIDEOMODESDESC DeviceDescriptions[MAX_DEVICES]; +int NumberOfDevices; +int CurrentlySelectedDevice=0; +int CurrentlySelectedVideoMode=0; + +D3DDEVICEDESC D3DDeviceDesc; +int D3DDeviceDescIsValid; + + + +extern void GetDeviceAndVideoModePrefences(void); +static void SelectBasicDeviceAndVideoMode(void); +static void SetDeviceAndVideoModePreferences(void); +extern void SaveDeviceAndVideoModePreferences(void); +extern void LoadDeviceAndVideoModePreferences(void); + +HRESULT WINAPI D3DDeviceEnumerator(LPGUID lpGuid, + LPSTR lpDeviceDescription, LPSTR lpDeviceName, + LPD3DDEVICEDESC lpHWDesc, LPD3DDEVICEDESC lpHELDesc, LPVOID lpContext) +{ + /* hardware only please */ + if (!lpHWDesc->dcmColorModel) + { + return D3DENUMRET_OK; + } + + /* that'll do */ + D3DDeviceDesc = *lpHWDesc; + D3DDeviceDescIsValid = 1; + + return D3DENUMRET_CANCEL; +} + + + + + +HRESULT WINAPI EnumVideoModesCallback(LPDDSURFACEDESC2 pddsd, LPVOID Context) +{ + DEVICEANDVIDEOMODESDESC *dPtr = &DeviceDescriptions[NumberOfDevices]; + VIDEOMODEDESC *vmPtr = &(dPtr->VideoModes[dPtr->NumberOfVideoModes]); + + vmPtr->Width = pddsd->dwWidth; + vmPtr->Height = pddsd->dwHeight; + vmPtr->ColourDepth = pddsd->ddpfPixelFormat.dwRGBBitCount; + + if (vmPtr->ColourDepth<=8 || vmPtr->Width<512 || vmPtr->Height<384) + return DDENUMRET_OK; + + if (vmPtr->ColourDepth<=16) + { + if (!(D3DDeviceDesc.dwDeviceRenderBitDepth & DDBD_16)) + { + return DDENUMRET_OK; + } + } + else if (vmPtr->ColourDepth<=24) + { + if (!(D3DDeviceDesc.dwDeviceRenderBitDepth & DDBD_24)) + { + return DDENUMRET_OK; + } + } + else if (vmPtr->ColourDepth<=32) + { + if (!(D3DDeviceDesc.dwDeviceRenderBitDepth & DDBD_32)) + { + return DDENUMRET_OK; + } + } + + dPtr->NumberOfVideoModes++; + + if (dPtr->NumberOfVideoModes < MAX_VIDEOMODES) + { + return DDENUMRET_OK; + } + else + { + return DDENUMRET_CANCEL; + } +} + + +//----------------------------------------------------------------------------- +// Name: DDEnumCallbackEx() +// Desc: This callback gets the information for each device enumerated +//----------------------------------------------------------------------------- +BOOL WINAPI DDEnumCallbackEx(GUID *pGUID, LPSTR pDescription, LPSTR pName, LPVOID pContext, HMONITOR hm) +{ + LPDIRECTDRAW pDD; // DD1 interface, used to get DD4 interface + LPDIRECTDRAW4 pDD4 = NULL; // DirectDraw4 interface + LPDIRECT3D pD3D = NULL; + HRESULT hRet; + DDCAPS HELCaps; + + // Create the main DirectDraw object + hRet = DirectDrawCreate(pGUID, &pDD, NULL); + if (hRet != DD_OK) + { + return DDENUMRET_CANCEL; + } + + // Fetch DirectDraw4 interface + hRet = pDD->QueryInterface(IID_IDirectDraw4, (LPVOID *)&pDD4); + if (hRet != DD_OK) + { + return DDENUMRET_CANCEL; + } + + memset(&DeviceDescriptions[NumberOfDevices].DriverCaps, 0, sizeof(DDCAPS)); + DeviceDescriptions[NumberOfDevices].DriverCaps.dwSize = sizeof(DDCAPS); + memset(&HELCaps, 0, sizeof(DDCAPS)); + HELCaps.dwSize = sizeof(DDCAPS); + + hRet = pDD->GetCaps(&DeviceDescriptions[NumberOfDevices].DriverCaps, &HELCaps); + + if ((hRet != DD_OK) || !(DeviceDescriptions[NumberOfDevices].DriverCaps.dwCaps & DDCAPS_3D)) + { + // Finished with the DirectDraw object, so release it + if (pDD4) pDD4->Release(); + return DDENUMRET_OK; + } + + // Get the device information and save it + if (pGUID) + { + DeviceDescriptions[NumberOfDevices].DDGUID = *pGUID; + DeviceDescriptions[NumberOfDevices].DDGUIDIsSet = 1; + } + else + { + DeviceDescriptions[NumberOfDevices].DDGUIDIsSet = 0; + } + hRet = pDD4->GetDeviceIdentifier(&DeviceDescriptions[NumberOfDevices].DeviceInfo,0); + hRet = pDD4->GetDeviceIdentifier(&DeviceDescriptions[NumberOfDevices].DeviceInfoHost,DDGDI_GETHOSTIDENTIFIER); + + // check available video modes + DeviceDescriptions[NumberOfDevices].NumberOfVideoModes = 0; + + hRet = pDD->QueryInterface(IID_IDirect3D, (LPVOID*) &pD3D); + + hRet = pD3D->EnumDevices(D3DDeviceEnumerator, NULL); + if (pD3D) pD3D->Release(); + + if (!D3DDeviceDescIsValid) + { + // Finished with the DirectDraw object, so release it + if (pDD4) pDD4->Release(); + return DDENUMRET_OK; + } + + + hRet = pDD4->EnumDisplayModes(0, NULL, 0, EnumVideoModesCallback); + + + // Finished with the DirectDraw object, so release it + if (pDD4) pDD4->Release(); + + // Bump to the next open slot or finish the callbacks if full + if (NumberOfDevices < MAX_DEVICES) + NumberOfDevices++; + else + return DDENUMRET_CANCEL; + return DDENUMRET_OK; +} + + + + +int EnumerateCardsAndVideoModes(void) +{ + LPDIRECTDRAWENUMERATEEX pDirectDrawEnumerateEx; + HINSTANCE hDDrawDLL; + + NumberOfDevices=0; + + // Do a GetModuleHandle and GetProcAddress in order to get the + // DirectDrawEnumerateEx function + hDDrawDLL = GetModuleHandle("DDRAW"); + if (!hDDrawDLL) + { + return -1; + } + pDirectDrawEnumerateEx = (LPDIRECTDRAWENUMERATEEX )GetProcAddress(hDDrawDLL,"DirectDrawEnumerateExA"); + if (pDirectDrawEnumerateEx) + { + pDirectDrawEnumerateEx(DDEnumCallbackEx, NULL, + DDENUM_ATTACHEDSECONDARYDEVICES | + DDENUM_DETACHEDSECONDARYDEVICES | + DDENUM_NONDISPLAYDEVICES); + } + else + { + return -1; + } + + if (0 == NumberOfDevices) + { + return -1; + } + + LoadDeviceAndVideoModePreferences(); + return 0; +} + +char buffer[32]; +extern char *GetVideoModeDescription2(void) +{ + strncpy(buffer, DeviceDescriptions[CurrentlySelectedDevice].DeviceInfo.szDescription,24); + buffer[24] = 0; + return buffer; +} + +extern char *GetVideoModeDescription3(void) +{ + DEVICEANDVIDEOMODESDESC *dPtr = &DeviceDescriptions[CurrentlySelectedDevice]; + VIDEOMODEDESC *vmPtr = &(dPtr->VideoModes[CurrentlySelectedVideoMode]); + sprintf(buffer,"%dx%dx%d",vmPtr->Width,vmPtr->Height,vmPtr->ColourDepth); + return buffer; +} + +extern void PreviousVideoMode2(void) +{ + if (CurrentlySelectedVideoMode--<=0) + { + if(CurrentlySelectedDevice--<=0) + { + CurrentlySelectedDevice = NumberOfDevices-1; + } + CurrentlySelectedVideoMode = DeviceDescriptions[CurrentlySelectedDevice].NumberOfVideoModes-1; + } +} + +extern void NextVideoMode2(void) +{ + if (++CurrentlySelectedVideoMode>=DeviceDescriptions[CurrentlySelectedDevice].NumberOfVideoModes) + { + CurrentlySelectedVideoMode = 0; + if(++CurrentlySelectedDevice>=NumberOfDevices) + { + CurrentlySelectedDevice = 0; + } + } +} + +void GetCorrectDirectDrawObject(void) +{ + extern int SelectDirectDrawObject(LPGUID pGUID); + finiObjectsExceptDD(); + finiObjects(); + + if(DeviceDescriptions[CurrentlySelectedDevice].DDGUIDIsSet) + { + SelectDirectDrawObject(&DeviceDescriptions[CurrentlySelectedDevice].DDGUID); + } + else + { + SelectDirectDrawObject(NULL); + } + TestInitD3DObject(); +} + + +DEVICEANDVIDEOMODE PreferredDeviceAndVideoMode; + +extern void GetDeviceAndVideoModePrefences(void) +{ + int i; + + CurrentlySelectedDevice = -1; + CurrentlySelectedVideoMode = -1; + + for (i=0; iNumberOfVideoModes; i++) + { + if ((PreferredDeviceAndVideoMode.Width == dPtr->VideoModes[i].Width) + &&(PreferredDeviceAndVideoMode.Height == dPtr->VideoModes[i].Height) + &&(PreferredDeviceAndVideoMode.ColourDepth == dPtr->VideoModes[i].ColourDepth)) + { + CurrentlySelectedVideoMode = i; + break; + } + } + if (CurrentlySelectedDevice==-1) + { + SelectBasicDeviceAndVideoMode(); + return; + } + + SetDeviceAndVideoModePreferences(); +} + + +static void SelectBasicDeviceAndVideoMode(void) +{ + CurrentlySelectedDevice = -1; + CurrentlySelectedVideoMode = -1; + + /* look for a basic 640x480x16 bit mode */ + for (int d=0; dNumberOfVideoModes; i++) + { + if ((640 == dPtr->VideoModes[i].Width) + &&(480 == dPtr->VideoModes[i].Height) + &&(16 == dPtr->VideoModes[i].ColourDepth)) + { + CurrentlySelectedVideoMode = i; + CurrentlySelectedDevice = d; + break; + /* note this only breaks out of the video mode loop; + all drivers are scanned through */ + } + } + } + + if (CurrentlySelectedDevice==-1) + { + /* good grief, just pick the first possible thing */ + CurrentlySelectedDevice = 0; + CurrentlySelectedVideoMode = 0; + } + + SetDeviceAndVideoModePreferences(); +} + +static void SetDeviceAndVideoModePreferences(void) +{ + DEVICEANDVIDEOMODESDESC *dPtr = &DeviceDescriptions[CurrentlySelectedDevice]; + VIDEOMODEDESC *vmPtr = &(dPtr->VideoModes[CurrentlySelectedVideoMode]); + + PreferredDeviceAndVideoMode.DDGUID = dPtr->DDGUID; + PreferredDeviceAndVideoMode.DDGUIDIsSet = dPtr->DDGUIDIsSet; + PreferredDeviceAndVideoMode.Width = vmPtr->Width; + PreferredDeviceAndVideoMode.Height = vmPtr->Height; + PreferredDeviceAndVideoMode.ColourDepth = vmPtr->ColourDepth; + +} + +extern void SaveDeviceAndVideoModePreferences(void) +{ + SetDeviceAndVideoModePreferences(); + + FILE* file=fopen("AvP_Video.cfg","wb"); + if(!file) return; + fwrite(&PreferredDeviceAndVideoMode,sizeof(DEVICEANDVIDEOMODE),1,file); + fclose(file); +} +extern void LoadDeviceAndVideoModePreferences(void) +{ + FILE* file=fopen("AvP_Video.cfg","rb"); + if(!file) + { + SelectBasicDeviceAndVideoMode(); + return; + } + fread(&PreferredDeviceAndVideoMode,sizeof(DEVICEANDVIDEOMODE),1,file); + fclose(file); + GetDeviceAndVideoModePrefences(); +} + +}; \ No newline at end of file diff --git a/3dc/win95/VideoModes.h b/3dc/win95/VideoModes.h new file mode 100644 index 0000000..1e18200 --- /dev/null +++ b/3dc/win95/VideoModes.h @@ -0,0 +1,40 @@ +#define MAX_DEVICES 4 +#define MAX_VIDEOMODES 100 + + +typedef struct +{ + int Width; + int Height; + int ColourDepth; +} VIDEOMODEDESC; + +typedef struct +{ + GUID DDGUID; + int DDGUIDIsSet; + + DDDEVICEIDENTIFIER DeviceInfo; + DDDEVICEIDENTIFIER DeviceInfoHost; + DDCAPS DriverCaps; + + VIDEOMODEDESC VideoModes[MAX_VIDEOMODES]; + int NumberOfVideoModes; + +} DEVICEANDVIDEOMODESDESC; + +typedef struct +{ + GUID DDGUID; + int DDGUIDIsSet; + int Width; + int Height; + int ColourDepth; + +} DEVICEANDVIDEOMODE; + +extern DEVICEANDVIDEOMODESDESC DeviceDescriptions[MAX_DEVICES]; +extern int NumberOfDevices; +extern int CurrentlySelectedDevice; +extern int CurrentlySelectedVideoMode; + diff --git a/3dc/win95/ZMOUSE.H b/3dc/win95/ZMOUSE.H new file mode 100644 index 0000000..5064b31 --- /dev/null +++ b/3dc/win95/ZMOUSE.H @@ -0,0 +1,164 @@ +/**************************************************************************** +* * +* ZMOUSE.H -- Include file for IntelliMouse(tm) 1.0 * +* * +* NOTE: Zmouse.h contains #defines required when providing IntelliMouse * +* wheel support for Windows95 and NT3.51. Wheel is supported * +* natively in WinNT4.0, please refer to the NT4.0 SDK for more info * +* on providing support for IntelliMouse in NT4.0. * +* * +* Copyright (c) 1983-1996, Microsoft Corp. All rights reserved. * +* * +\***************************************************************************/ + + +/************************************************************************** + Client Appplication (API) Defines for Wheel rolling +***************************************************************************/ + + +// Apps need to call RegisterWindowMessage using the #define below to +// get the message number that is sent to the foreground window +// when a wheel roll occurs + +#ifdef UNICODE +#define MSH_MOUSEWHEEL L"MSWHEEL_ROLLMSG" +#else +#define MSH_MOUSEWHEEL "MSWHEEL_ROLLMSG" +#endif + // wParam = wheel rotation expressed in multiples of WHEEL_DELTA + // lParam is the mouse coordinates + +#define WHEEL_DELTA 120 // Default value for rolling one notch + + +#ifndef WM_MOUSEWHEEL +#define WM_MOUSEWHEEL (WM_MOUSELAST+1) // message that will be supported + // by the OS +#endif + + +/************************************************************************** + Client Appplication (API) Defines for + * determining if wheel support active + * determining # of Scroll Lines +***************************************************************************/ + +// Class name for MSWHEEL.EXE's invisible window +// use FindWindow to get hwnd to MSWHEEL +#ifdef UNICODE +#define MOUSEZ_CLASSNAME L"MouseZ" // wheel window class +#define MOUSEZ_TITLE L"Magellan MSWHEEL" // wheel window title +#else +#define MOUSEZ_CLASSNAME "MouseZ" // wheel window class +#define MOUSEZ_TITLE "Magellan MSWHEEL" // wheel window title +#endif + +#define MSH_WHEELMODULE_CLASS (MOUSEZ_CLASSNAME) +#define MSH_WHEELMODULE_TITLE (MOUSEZ_TITLE) + +// Apps need to call RegisterWindowMessage using the #defines +// below to get the message numbers for: +// 1) the message that can be sent to the MSWHEEL window to +// query if wheel support is active (MSH_WHEELSUPPORT)> +// 2) the message to query for the number of scroll lines +// (MSH_SCROLL_LINES) +// +// To send a message to MSWheel window, use FindWindow with the #defines +// for CLASS and TITLE above. If FindWindow fails to find the MSWHEEL +// window or the return from SendMessage is false, then Wheel support +// is not currently available. + +#ifdef UNICODE +#define MSH_WHEELSUPPORT L"MSH_WHEELSUPPORT_MSG" // name of msg to send + // to query for wheel support +#else +#define MSH_WHEELSUPPORT "MSH_WHEELSUPPORT_MSG" // name of msg to send + // to query for wheel support +#endif + +// MSH_WHEELSUPPORT +// wParam - not used +// lParam - not used +// returns BOOL - TRUE if wheel support is active, FALSE otherwise + + +#ifdef UNICODE +#define MSH_SCROLL_LINES L"MSH_SCROLL_LINES_MSG" +#else +#define MSH_SCROLL_LINES "MSH_SCROLL_LINES_MSG" +#endif + +// MSH_SCROLL_LINES +// wParam - not used +// lParam - not used +// returns int - number of lines to scroll on a wheel roll + +#ifndef WHEEL_PAGESCROLL +#define WHEEL_PAGESCROLL (UINT_MAX) // signifies to scroll a page, also + // defined in winuser.h in the + // NT4.0 SDK +#endif + +#ifndef SPI_SETWHEELSCROLLLINES +#define SPI_SETWHEELSCROLLLINES 105 // Also defined in winuser.h in the + // NT4.0 SDK, please see the NT4.0 SDK + // documentation for NT4.0 implementation + // specifics. + // For Win95 and WinNT3.51, + // Mswheel broadcasts the message + // WM_SETTINGCHANGE (equivalent to + // WM_WININICHANGE) when the scroll + // lines has changed. Applications + // will recieve the WM_SETTINGCHANGE + // message with the wParam set to + // SPI_SETWHEELSCROLLLINES. When + // this message is recieved the application + // should query Mswheel for the new + // setting. +#endif + + +/********************************************************************* +* INLINE FUNCTION: HwndMsWheel +* Purpose : Get a reference to MSWheel Window, the registered messages, +* wheel support active setting, and number of scrollLines +* Params : PUINT puiMsh_MsgMouseWheel - address of UINT to contain returned registered wheel message +* PUINT puiMsh_Msg3DSupport - address of UINT to contain wheel support registered message +* PUINT puiMsh_MsgScrollLines - address of UINT to contain Scroll lines registered message +* PBOOL pf3DSupport - address of BOOL to contain returned flag for wheel support active +* PINT piScrollLines - address of int to contain returned scroll lines +* Returns : HWND handle to the MsWheel window +* Note : The return value for pf3DSupport and piScrollLines is dependant +* on the POINT32 module. If POINT32 module is not running then +* the values returned for these parameters will be +* FALSE and 3, respectively. +*********************************************************************/ +__inline HWND HwndMSWheel( + PUINT puiMsh_MsgMouseWheel, + PUINT puiMsh_Msg3DSupport, + PUINT puiMsh_MsgScrollLines, + PBOOL pf3DSupport, + PINT piScrollLines +) +{ + HWND hdlMsWheel; + + hdlMsWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE); + + *puiMsh_MsgMouseWheel = RegisterWindowMessage(MSH_MOUSEWHEEL); + *puiMsh_Msg3DSupport = RegisterWindowMessage(MSH_WHEELSUPPORT); + *puiMsh_MsgScrollLines = RegisterWindowMessage(MSH_SCROLL_LINES); + + if (*puiMsh_Msg3DSupport) + *pf3DSupport = (BOOL)SendMessage(hdlMsWheel, *puiMsh_Msg3DSupport, 0, 0); + else + *pf3DSupport = FALSE; // default to FALSE + + if (*puiMsh_MsgScrollLines) + *piScrollLines = (int)SendMessage(hdlMsWheel, *puiMsh_MsgScrollLines, 0, 0); + else + *piScrollLines = 3; // default + + return(hdlMsWheel); +} diff --git a/3dc/win95/Zsp.cpp b/3dc/win95/Zsp.cpp new file mode 100644 index 0000000..1484812 --- /dev/null +++ b/3dc/win95/Zsp.cpp @@ -0,0 +1,511 @@ +#include + +#if cencon +#include "AFXWIN.H" +#include "list_tem.hpp" + +#include "Vectors.hpp" +#include "environs.hpp" +#include "shpchunk.hpp" +#elif shpedit +#include "list_tem.hpp" +#include "Vectors.hpp" +#else +#include "list_tem.hpp" +#endif + +#include "zsp.hpp" + +#ifdef cencon +#define new my_new +#endif + +#if shpedit +#define twprintf printf +#endif + +// ZSP creation functions + +#if cencon +void generate_zsp_data (int num_cubes, CWnd * pWnd) +{ + Shape_Chunk * shpch = Sel_Obj->get_assoc_shape(); + + if (!shpch->lock_chunk(*(Main_Env.environment))) + { + char message[300]; + char * locker = "Unknown"; + + Shape_Header_Chunk * head = shpch->get_header(); + if (head) + locker = head->lock_user; + + sprintf (message, "Shape locked by %s\n can not continue", locker); + + pWnd->MessageBox (message, "Tools Control Area", + MB_ICONHAND + MB_OK + MB_TASKMODAL); + return; + } + start_text_window(pWnd); + + + ZSP_Data * zsp = new ZSP_Data (shpch->shape_data, num_cubes); + new Shape_ZSP_Data_Chunk (shpch, *zsp); + + shpch->unlock_chunk (*(Main_Env.environment), TRUE); + stop_text_window(); + + delete zsp; +} +#endif + +#if cencon || shpedit + +ZSP_Data::ZSP_Data (const ChunkShape & shp, int num_cubes) +{ + double xsize,ysize,zsize; + double max_size; + Vector cube_vector; + int num_subshapes; + + xsize = fabs(shp.max.x) + fabs(shp.min.x); + ysize = fabs(shp.max.y) + fabs(shp.min.y); + zsize = fabs(shp.max.z) + fabs(shp.min.z); + + max_size=max(xsize,ysize); + max_size=max(max_size,zsize); + + cube_size = max_size / num_cubes; + + int nc = num_cubes+2; + + num_x_cubes = nc-(int) ( nc-(xsize / cube_size) ); + num_y_cubes = nc-(int) ( nc-(ysize / cube_size) ); + num_z_cubes = nc-(int) ( nc-(zsize / cube_size) ); + + cube_vector.x = cube_size / 2; + cube_vector.y = cube_size / 2; + cube_vector.z = cube_size / 2; + cube_radius = mod(cube_vector); + + num_subshapes = num_x_cubes * num_y_cubes * num_z_cubes; + + int i,j,k; + double xstart, ystart, zstart; + double xstart_tmp, ystart_tmp, zstart_tmp; + + + xstart = shp.min.x; + ystart = shp.min.y; + zstart = shp.min.z; + + xstart_tmp = xstart; + + twprintf ("Number of zones is \n",num_subshapes); + + for(i = 0; i < num_x_cubes; i++) { + + twprintf ("x = %d\n",i); + + ystart_tmp = ystart; + + for(j = 0; j < num_y_cubes; j++) { + + twprintf ("y = %d\nz = ",j); + + zstart_tmp = zstart; + + for(k = 0; k < num_z_cubes; k++) { + + twprintf ("%d ",k); + + /* Process the subshape and update the ZSP pointer array */ + + ZSP_zone temp_zone(shp, xstart_tmp, ystart_tmp, + zstart_tmp, cube_size); + + zone_array.add_entry(temp_zone); + + zstart_tmp += cube_size; + + } + + twprintf ("\n"); + + ystart_tmp += cube_size; + + } + + xstart_tmp += cube_size; + + } + + + +} + + + +static int zone_polygons[20000]; +static unsigned char vertex_outcode [20000]; + +ZSP_zone::ZSP_zone (const ChunkShape & shp, double xstart, double ystart, + double zstart, double cube_size) +{ + double xplane0, xplane1; + double yplane0, yplane1; + double zplane0, zplane1; + int i,j; + int outcode_or, outcode_and; + int vert_outcode; + + num_z_polys = 0; + num_z_verts = 0; + + /* Bounding planes in terms of axis limits */ + + xplane0 = xstart; + xplane1 = xstart + cube_size; + + yplane0 = ystart; + yplane1 = ystart + cube_size; + + zplane0 = zstart; + zplane1 = zstart + cube_size; + + for (i=0; i xplane1) vert_outcode |= rsp_oc_x1; + if(shp.v_list[point_no].y < yplane0) vert_outcode |= rsp_oc_y0; + if(shp.v_list[point_no].y > yplane1) vert_outcode |= rsp_oc_y1; + if(shp.v_list[point_no].z < zplane0) vert_outcode |= rsp_oc_z0; + if(shp.v_list[point_no].z > zplane1) vert_outcode |= rsp_oc_z1; + + if(j==0) { + + outcode_or = vert_outcode; + outcode_and = vert_outcode; + + } + + else { + + outcode_or |= vert_outcode; + outcode_and &= vert_outcode; + + } + + } + + if (outcode_and == 0) + { + zone_polygons[num_z_polys] = i; + num_z_polys++; + } + + } + + if (!num_z_polys) + { + z_poly_list=0; + z_vert_list=0; + return; + } + + z_poly_list = new int [num_z_polys]; + for (i=0; i znl(&zdata->zone_array); !znl.done(); znl.next()) + { + sz += 8 + (znl().num_z_polys * 4) + (znl().num_z_verts * 4); + } + + return (chunk_size = sz); +} + +void Shape_ZSP_Data_Chunk::fill_data_block ( char * data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = zspdata.num_x_cubes; + data_start += 4; + + *((int *) data_start) = zspdata.num_y_cubes; + data_start += 4; + + *((int *) data_start) = zspdata.num_z_cubes; + data_start += 4; + + *((double *) data_start) = zspdata.cube_size; + data_start += 8; + + *((double *) data_start) = zspdata.cube_radius; + data_start += 8; + + ZSP_Data * zdata = (ZSP_Data *)(&zspdata); + + for (LIF znl(&zdata->zone_array); !znl.done(); znl.next()) + { + *((int *) data_start) = znl().num_z_polys; + data_start += 4; + + *((int *) data_start) = znl().num_z_verts; + data_start += 4; + + int i; + for (i=0; i zone_array; + + +}; + + +///////////////////////////////////////// + +class Shape_ZSP_Data_Chunk : public Chunk +{ +public: + +#if cencon || shpedit + Shape_ZSP_Data_Chunk (Shape_Sub_Shape_Chunk * parent, ZSP_Data zspin) + : Chunk(parent, "SHPZSPDT"), zspdata (zspin) + {} + + Shape_ZSP_Data_Chunk (Shape_Chunk * parent, ZSP_Data zspin) + : Chunk(parent, "SHPZSPDT"), zspdata (zspin) + {} +#endif + + const ZSP_Data zspdata; + + size_t size_chunk (); + void fill_data_block (char *); + + Shape_ZSP_Data_Chunk (Shape_Sub_Shape_Chunk * parent, const char * zdata, size_t zsize) + : Chunk (parent, "SHPZSPDT"), zspdata (zdata, zsize) + {} + + Shape_ZSP_Data_Chunk (Shape_Chunk * parent, const char * zdata, size_t zsize) + : Chunk (parent, "SHPZSPDT"), zspdata (zdata, zsize) + {} + +}; + + + + + + + + + + + +#endif diff --git a/3dc/win95/advwin32.h b/3dc/win95/advwin32.h new file mode 100644 index 0000000..da57f87 --- /dev/null +++ b/3dc/win95/advwin32.h @@ -0,0 +1,111 @@ +/************************************************************* +Module name: AdvWin32.H +Notices: Copyright (c) 1995 Jeffrey Richter +*************************************************************/ + +#ifndef ADVWIN32_H_INCLUDED +#define ADVWIN32_H_INCLUDED + +/* Disable Visual C++ warnings which fire when reading Windows OS headers. */ +#ifndef __WATCOMC__ + +/* Disable ridiculous warnings so that the code */ +/* compiles cleanly using warning level 4. */ + +/* nonstandard extension 'single line comment' was used */ +#pragma warning(disable: 4001) + +// nonstandard extension used : nameless struct/union +#pragma warning(disable: 4201) + +// nonstandard extension used : bit field types other than int +#pragma warning(disable: 4214) + +// Note: Creating precompiled header +#pragma warning(disable: 4699) + +// unreferenced inline function has been removed +#pragma warning(disable: 4514) + +// unreferenced formal parameter +#pragma warning(disable: 4100) + +// 'type' differs in indirection to slightly different base +// types from 'other type' +#pragma warning(disable: 4057) + +// named type definition in parentheses +#pragma warning(disable: 4115) + +// nonstandard extension used : benign typedef redefinition +#pragma warning(disable: 4209) + +// conditional expression is constant : used to differentiate between internal and external versions +#pragma warning(disable: 4127) + +// comma operator in array index, disabled due to assertions in array indicies +#pragma warning(disable: 4709) + +// assignment operator could not be generated, disable as often the operator isn't used. +#pragma warning(disable: 4512) + +// 'function' selected for automatic inline expansion - when a function not declared inline was inlined: well done compiler, aren't you clever! +#pragma warning(disable: 4711) + +// 'function' not expanded. +#pragma warning(disable: 4710) + +#pragma warning(disable: 4032) + +#pragma warning(disable: 4702) + +///////////////////////////////////////////////////////////// + +// Create an ARRAY_SIZE macro that returns the number of +// elements in an array. This is a handy macro that I use +// frequently throughout the sample applications. +#define ARRAY_SIZE(Array) \ + (sizeof(Array) / sizeof((Array)[0])) + +///////////////////////////////////////////////////////////// + +// Create a BEGINTHREADEX macro that calls the C run-time's +// _beginthreadex function. The C run-time library doesn't +// want to have any reliance on Win32 data types such as +// HANDLE. This means that a Win32 programmer needs to cast +// the return value to a HANDLE. This is terribly inconvenient, +// so I have created this macro to perform the casting. +typedef unsigned (__stdcall *PTHREAD_START) (void *); + +#define BEGINTHREADEX(lpsa, cbStack, lpStartAddr, \ + lpvThreadParm, fdwCreate, lpIDThread) \ + ((HANDLE)_beginthreadex( \ + (void *) (lpsa), \ + (unsigned) (cbStack), \ + (PTHREAD_START) (lpStartAddr), \ + (void *) (lpvThreadParm), \ + (unsigned) (fdwCreate), \ + (unsigned *) (lpIDThread))) + + +///////////////////////////////////////////////////////////// + + +// Compile all CONTEXT structures to use 32-bit members +// instead of 16-bit members. Currently, the only sample +// application that requires this is TInjLib.16 in order +// for it to work correctly on the DEC Alpha AXP. +#define _PORTABLE_32BIT_CONTEXT + +#endif /* ifndef __WATCOMC__ */ + +///////////////////////////////////////////////////////////// + +// Force all EXEs/DLLs to use STRICT type checking. +#ifndef STRICT + #define STRICT 1 +#endif + +#endif /* ifndef ADVWIN32_H_INCLUDED */ + +////////////////////////// End Of File ////////////////////// diff --git a/3dc/win95/alt_tab.cpp b/3dc/win95/alt_tab.cpp new file mode 100644 index 0000000..529abcb --- /dev/null +++ b/3dc/win95/alt_tab.cpp @@ -0,0 +1,390 @@ +#ifndef DB_LEVEL + #define DB_LEVEL 5 +#endif +#include "db.h" + +#ifndef HT_FAIL + #define HT_FAIL db_msg1 +#endif +#include "hash_tem.hpp" + +#ifdef _CPPRTTI + #include +#endif + +#include "awTexLd.h" + +#include "alt_tab.h" + +template +class AltTabRestore +{ + public: + virtual ~AltTabRestore(){} + virtual void DoRestore(DX_PTR * pDxGraphic) = 0; +}; + +template +class AltTabAwRestore : public AltTabRestore +{ + public: + AltTabAwRestore(AW_BACKUPTEXTUREHANDLE hBackup) : m_hBackup(hBackup) {} + private: + AW_BACKUPTEXTUREHANDLE m_hBackup; + protected: + virtual void DoRestore(DX_PTR * pDxGraphic); +}; + +void AltTabAwRestore::DoRestore(DDSurface * pSurface) +{ + DDSurface * pNewSurface = AwCreateSurface("rtf",m_hBackup,pSurface,AW_TLF_PREVSRCALL); + // should have succeeded + db_assert1(pNewSurface); + // should return the same pointer! + db_assert1(pNewSurface == pSurface); + // don't need both references + pNewSurface->Release(); +} + +void AltTabAwRestore::DoRestore(D3DTexture * pTexture) +{ + D3DTexture * pNewTexture = AwCreateTexture("rtf",m_hBackup,pTexture,AW_TLF_PREVSRCALL); + // should have succeeded + db_assert1(pNewTexture); + // should return the same pointer! + db_assert1(pNewTexture == pTexture); + // don't need both references + pNewTexture->Release(); +} + +template +class AltTabUserRestore : public AltTabRestore +{ + public: + typedef void (* PFN_RESTORE) (DX_PTR * pDxGraphic, void * pUser); + #ifdef NDEBUG + AltTabUserRestore(PFN_RESTORE pfnRestore, void * pUser) : m_pfnRestore(pfnRestore), m_pUser(pUser) {} + #else + AltTabUserRestore(PFN_RESTORE pfnRestore, void * pUser, char const * pszFuncName) : m_pfnRestore(pfnRestore), m_pUser(pUser), m_pszFuncName(pszFuncName) {} + #endif + private: + PFN_RESTORE m_pfnRestore; + void * m_pUser; + char const * m_pszFuncName; + protected: + virtual void DoRestore(DX_PTR * pDxGraphic); +}; + +template +void AltTabUserRestore::DoRestore(DX_PTR * pDxGraphic) +{ + #ifdef _CPPRTTI + db_logf4(("\t\tCalling User Restore Function %s = %p (%s * = %p, void * = %p)",m_pszFuncName,m_pfnRestore,typeid(*pDxGraphic).name(),pDxGraphic,m_pUser)); + #else + db_logf4(("\t\tCalling User Restore Function %s = %p (IUnknown * = %p, void * = %p)",m_pszFuncName,m_pfnRestore,pDxGraphic,m_pUser)); + #endif + + m_pfnRestore(pDxGraphic, m_pUser); +} + +template +struct AltTabEntry +{ + DX_PTR * m_pDxGraphic; + AltTabRestore * m_pRestore; + #ifndef NDEBUG + char const * m_pszFile; + unsigned m_nLine; + char * m_pszDebugString; + #endif + + inline bool operator == (AltTabEntry const & rEntry) const + { return m_pDxGraphic == rEntry.m_pDxGraphic; } + inline bool operator != (AltTabEntry const & rEntry) const + { return ! operator == (rEntry); } + + friend inline HashFunction(AltTabEntry const & rEntry) + { return HashFunction(rEntry.m_pDxGraphic); } +}; + +struct AltTabLists +{ + HashTable > m_listTextures; + HashTable > m_listSurfaces; +}; + +#ifdef NDEBUG +static AltTabLists g_atlists; +#else +static +struct AltTabDebugLists : AltTabLists +{ + ~AltTabDebugLists() + { + // destructor for derived class will be called before destructor + // for base class, so we can make assersions about the base class: + // everything *should* have been removed from these lists before exiting + if (m_listSurfaces.Size()) + { + db_logf1(("ERROR: AltTab lists still referring to %u surface(s) on exiting",m_listSurfaces.Size())); + unsigned i = 1; + for + ( + HashTable >::ConstIterator itSurfaces(m_listSurfaces); + !itSurfaces.Done(); itSurfaces.Next() + ) + { + db_logf1(("\t%u. Included in line %u of %s (details: %s)",i++,itSurfaces.Get().m_nLine,itSurfaces.Get().m_pszFile,itSurfaces.Get().m_pszDebugString ? itSurfaces.Get().m_pszDebugString : "n/a")); + } + + } + else + { + db_logf1(("OK on exiting: AltTab surface lists are clean")); + } + if (m_listTextures.Size()) + { + db_logf1(("ERROR: AltTab lists still referring to %u texture(s) on exiting",m_listTextures.Size())); + unsigned i = 1; + for + ( + HashTable >::ConstIterator itTextures(m_listTextures); + !itTextures.Done(); itTextures.Next() + ) + { + db_logf1(("\t%u. Included in line %u of %s (details: %s)",i++,itTextures.Get().m_nLine,itTextures.Get().m_pszFile,itTextures.Get().m_pszDebugString ? itTextures.Get().m_pszDebugString : "n/a")); + } + } + else + { + db_logf1(("OK on exiting: AltTab texture lists are clean")); + } + } +} + g_atlists; +#endif + +#ifdef NDEBUG + void ATIncludeTexture(D3DTexture * pTexture, AW_BACKUPTEXTUREHANDLE hBackup) +#else + void _ATIncludeTexture(D3DTexture * pTexture, AW_BACKUPTEXTUREHANDLE hBackup, char const * pszFile, unsigned nLine, char const * pszDebugString) +#endif +{ + db_assert1(pTexture); + db_assert1(hBackup); + HashTable >::Node * pNewNode = g_atlists.m_listTextures.NewNode(); + pNewNode->d.m_pDxGraphic = pTexture; + pNewNode->d.m_pRestore = new AltTabAwRestore(hBackup); + #ifndef NDEBUG + pNewNode->d.m_pszFile = pszFile; + pNewNode->d.m_nLine = nLine; + if (pszDebugString) + { + pNewNode->d.m_pszDebugString = new char [strlen(pszDebugString)+1]; + strcpy(pNewNode->d.m_pszDebugString,pszDebugString); + } + else + pNewNode->d.m_pszDebugString = NULL; + #endif + g_atlists.m_listTextures.AddAsserted(pNewNode); +} + +#ifdef NDEBUG + void ATIncludeSurface(DDSurface * pSurface, AW_BACKUPTEXTUREHANDLE hBackup) +#else + void _ATIncludeSurface(DDSurface * pSurface, AW_BACKUPTEXTUREHANDLE hBackup, char const * pszFile, unsigned nLine, char const * pszDebugString) +#endif +{ + db_assert1(pSurface); + db_assert1(hBackup); + HashTable >::Node * pNewNode = g_atlists.m_listSurfaces.NewNode(); + pNewNode->d.m_pDxGraphic = pSurface; + pNewNode->d.m_pRestore = new AltTabAwRestore(hBackup); + #ifndef NDEBUG + pNewNode->d.m_pszFile = pszFile; + pNewNode->d.m_nLine = nLine; + if (pszDebugString) + { + pNewNode->d.m_pszDebugString = new char [strlen(pszDebugString)+1]; + strcpy(pNewNode->d.m_pszDebugString,pszDebugString); + } + else + pNewNode->d.m_pszDebugString = NULL; + #endif + g_atlists.m_listSurfaces.AddAsserted(pNewNode); +} + +#ifdef NDEBUG + void ATIncludeTextureEx(D3DTexture * pTexture, AT_PFN_RESTORETEXTURE pfnRestore, void * pUser) +#else + void _ATIncludeTextureEx(D3DTexture * pTexture, AT_PFN_RESTORETEXTURE pfnRestore, void * pUser, char const * pszFile, unsigned nLine, char const * pszFuncName, char const * pszDebugString) +#endif +{ + db_assert1(pTexture); + db_assert1(pfnRestore); + HashTable >::Node * pNewNode = g_atlists.m_listTextures.NewNode(); + pNewNode->d.m_pDxGraphic = pTexture; + #ifndef NDEBUG + pNewNode->d.m_pRestore = new AltTabUserRestore(pfnRestore,pUser,pszFuncName); + pNewNode->d.m_pszFile = pszFile; + pNewNode->d.m_nLine = nLine; + if (pszDebugString) + { + pNewNode->d.m_pszDebugString = new char [strlen(pszDebugString)+1]; + strcpy(pNewNode->d.m_pszDebugString,pszDebugString); + } + else + pNewNode->d.m_pszDebugString = NULL; + #else + pNewNode->d.m_pRestore = new AltTabUserRestore(pfnRestore,pUser); + #endif + g_atlists.m_listTextures.AddAsserted(pNewNode); +} + +#ifdef NDEBUG + void ATIncludeSurfaceEx(DDSurface * pSurface, AT_PFN_RESTORESURFACE pfnRestore, void * pUser) +#else + void _ATIncludeSurfaceEx(DDSurface * pSurface, AT_PFN_RESTORESURFACE pfnRestore, void * pUser, char const * pszFile, unsigned nLine, char const * pszFuncName, char const * pszDebugString) +#endif +{ + db_assert1(pSurface); + db_assert1(pfnRestore); + HashTable >::Node * pNewNode = g_atlists.m_listSurfaces.NewNode(); + pNewNode->d.m_pDxGraphic = pSurface; + #ifndef NDEBUG + pNewNode->d.m_pRestore = new AltTabUserRestore(pfnRestore,pUser,pszFuncName); + pNewNode->d.m_pszFile = pszFile; + pNewNode->d.m_nLine = nLine; + if (pszDebugString) + { + pNewNode->d.m_pszDebugString = new char [strlen(pszDebugString)+1]; + strcpy(pNewNode->d.m_pszDebugString,pszDebugString); + } + else + pNewNode->d.m_pszDebugString = NULL; + #else + pNewNode->d.m_pRestore = new AltTabUserRestore(pfnRestore,pUser); + #endif + g_atlists.m_listSurfaces.AddAsserted(pNewNode); +} + +void ATRemoveTexture(D3DTexture * pTexture) +{ + db_assert1(pTexture); + AltTabEntry ateRemove; + ateRemove.m_pDxGraphic = pTexture; + AltTabEntry const * pEntry = g_atlists.m_listTextures.Contains(ateRemove); + db_assert1(pEntry); + db_assert1(pEntry->m_pRestore); + delete pEntry->m_pRestore; + #ifndef NDEBUG + if (pEntry->m_pszDebugString) + delete[] pEntry->m_pszDebugString; + #endif + g_atlists.m_listTextures.RemoveAsserted(ateRemove); +} + +void ATRemoveSurface(DDSurface * pSurface) +{ + db_assert1(pSurface); + AltTabEntry ateRemove; + ateRemove.m_pDxGraphic = pSurface; + AltTabEntry const * pEntry = g_atlists.m_listSurfaces.Contains(ateRemove); + db_assert1(pEntry); + db_assert1(pEntry->m_pRestore); + delete pEntry->m_pRestore; + #ifndef NDEBUG + if (pEntry->m_pszDebugString) + delete[] pEntry->m_pszDebugString; + #endif + g_atlists.m_listSurfaces.RemoveAsserted(ateRemove); +} + +void ATOnAppReactivate() +{ + db_log1("ATOnAppReactivate() called"); + // surfaces + for + ( + HashTable >::ConstIterator itSurfaces(g_atlists.m_listSurfaces); + !itSurfaces.Done(); itSurfaces.Next() + ) + { + DDSurface * pSurface = itSurfaces.Get().m_pDxGraphic; + db_logf5(("\tIs surface %p lost?? [included at line %u of %s (details: %s)]",pSurface,itSurfaces.Get().m_nLine,itSurfaces.Get().m_pszFile,itSurfaces.Get().m_pszDebugString ? itSurfaces.Get().m_pszDebugString : "n/a")); + HRESULT hResult = pSurface->IsLost(); + if (DDERR_SURFACELOST == hResult) + { + db_logf4(("\t\tSurface %p is lost - restoring",pSurface)); + hResult = pSurface->Restore(); + if (DD_OK == hResult) + { + db_logf5(("\t\tRestore() returned DD_OK",pSurface)); + db_assert1(itSurfaces.Get().m_pRestore); + itSurfaces.Get().m_pRestore->DoRestore(pSurface); + } + else + { + db_logf1(("\t\tERROR [%p->Restore()] %s",pSurface,AwDxErrorToString(hResult))); + } + } + else if (DD_OK != hResult) + { + db_logf1(("\t\tERROR [%p->IsLost()] %s",pSurface,AwDxErrorToString(hResult))); + } + else + { + db_logf5(("\t\tSurface %p wasn't lost",pSurface)); + } + } + + // textures + for + ( + HashTable >::ConstIterator itTextures(g_atlists.m_listTextures); + !itTextures.Done(); itTextures.Next() + ) + { + D3DTexture * pTexture = itTextures.Get().m_pDxGraphic; + db_logf5(("\tIs texture %p lost?? [included at line %u of %s (details: %s)]",pTexture,itTextures.Get().m_nLine,itTextures.Get().m_pszFile,itTextures.Get().m_pszDebugString ? itTextures.Get().m_pszDebugString : "n/a")); + DDSurface * pSurface; + HRESULT hResult = pTexture->QueryInterface(GUID_DD_SURFACE,reinterpret_cast(&pSurface)); + if (DD_OK != hResult) + { + db_logf1(("\t\tERROR [%p->QueryInterface(GUID_DD_SURFACE,%p)] %s",pTexture,&pSurface,AwDxErrorToString(hResult))); + } + else + { + hResult = pSurface->IsLost(); + if (DDERR_SURFACELOST == hResult) + { + db_logf4(("\t\tTexture %p is lost - restoring",pTexture)); + hResult = pSurface->Restore(); + if (DD_OK == hResult) + { + db_logf5(("\t\tRestore() returned DD_OK",pTexture)); + db_assert1(itTextures.Get().m_pRestore); + itTextures.Get().m_pRestore->DoRestore(pTexture); + } + else + { + db_logf1(("\t\tERROR [%p->Restore()] %s",pTexture,AwDxErrorToString(hResult))); + } + } + else if (DD_OK != hResult) + { + db_logf1(("\t\tERROR [%p->IsLost()] %s",pTexture,AwDxErrorToString(hResult))); + } + else + { + db_logf5(("\t\tTexture %p wasn't lost",pTexture)); + } + // don't need this reference anymore + pSurface->Release(); + } + } + + db_log1("ATOnAppReactivate() returning"); +} + + diff --git a/3dc/win95/alt_tab.h b/3dc/win95/alt_tab.h new file mode 100644 index 0000000..4e91bb7 --- /dev/null +++ b/3dc/win95/alt_tab.h @@ -0,0 +1,47 @@ +/* +JH - 18/02/98 +Deal with lost surfaces and textures - restore them when the application is re-activated +*/ + +#ifndef _INCLUDED_ALT_TAB_H_ +#define _INCLUDED_ALT_TAB_H_ + +#include "aw.h" + +#ifdef __cplusplus + extern "C" { +#endif + +typedef void (* AT_PFN_RESTORETEXTURE) (D3DTexture * pTexture, void * pUser); +typedef void (* AT_PFN_RESTORESURFACE) (DDSurface * pSurface, void * pUser); + +#ifdef NDEBUG + extern void ATIncludeTexture(D3DTexture * pTexture, AW_BACKUPTEXTUREHANDLE hBackup); + extern void ATIncludeTextureEx(D3DTexture * pTexture, AT_PFN_RESTORETEXTURE pfnRestore, void * pUser); + extern void ATIncludeSurface(DDSurface * pSurface, AW_BACKUPTEXTUREHANDLE hBackup); + extern void ATIncludeSurfaceEx(DDSurface * pSurface, AT_PFN_RESTORESURFACE pfnRestore, void * pUser); +#else + extern void _ATIncludeTexture(D3DTexture * pTexture, AW_BACKUPTEXTUREHANDLE hBackup, char const * pszFile, unsigned nLine, char const * pszDebugString); + extern void _ATIncludeTextureEx(D3DTexture * pTexture, AT_PFN_RESTORETEXTURE pfnRestore, void * pUser, char const * pszFile, unsigned nLine, char const * pszFuncName, char const * pszDebugString); + extern void _ATIncludeSurface(DDSurface * pSurface, AW_BACKUPTEXTUREHANDLE hBackup, char const * pszFile, unsigned nLine, char const * pszDebugString); + extern void _ATIncludeSurfaceEx(DDSurface * pSurface, AT_PFN_RESTORESURFACE pfnRestore, void * pUser, char const * pszFile, unsigned nLine, char const * pszFuncName, char const * pszDebugString); + #define ATIncludeTexture(p,h) _ATIncludeTexture(p,h,__FILE__,__LINE__,NULL) + #define ATIncludeTextureEx(p,f,u) _ATIncludeTextureEx(p,f,u,__FILE__,__LINE__,#f ,NULL) + #define ATIncludeSurface(p,h) _ATIncludeSurface(p,h,__FILE__,__LINE__,NULL) + #define ATIncludeSurfaceEx(p,f,u) _ATIncludeSurfaceEx(p,f,u,__FILE__,__LINE__,#f ,NULL) + #define ATIncludeTextureDb(p,h,d) _ATIncludeTexture(p,h,__FILE__,__LINE__,d) + #define ATIncludeTextureExDb(p,f,u,d) _ATIncludeTextureEx(p,f,u,__FILE__,__LINE__,#f ,d) + #define ATIncludeSurfaceDb(p,h,d) _ATIncludeSurface(p,h,__FILE__,__LINE__,d) + #define ATIncludeSurfaceExDb(p,f,u,d) _ATIncludeSurfaceEx(p,f,u,__FILE__,__LINE__,#f ,d) +#endif + +extern void ATRemoveTexture(D3DTexture * pTexture); +extern void ATRemoveSurface(DDSurface * pSurface); + +extern void ATOnAppReactivate(); + +#ifdef __cplusplus + } +#endif + +#endif /* ! _INCLUDED_ALT_TAB_H_ */ diff --git a/3dc/win95/animobs.cpp b/3dc/win95/animobs.cpp new file mode 100644 index 0000000..f85001f --- /dev/null +++ b/3dc/win95/animobs.cpp @@ -0,0 +1,593 @@ +#include "hierchnk.hpp" +#include "Animobs.hpp" +#include "list_tem.hpp" +#include + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(animobs) + +RIF_IMPLEMENT_DYNCREATE("OBASEQFR",Object_Animation_Sequence_Frame_Chunk) + +void Object_Animation_Sequence_Frame_Chunk::fill_data_block (char *data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + + *((float *) data_start) = orientation.x; + data_start += 4; + *((float *) data_start) = orientation.y; + data_start += 4; + *((float *) data_start) = orientation.z; + data_start += 4; + *((float *) data_start) = orientation.w; + data_start += 4; + + *((int *) data_start) = transform.x; + data_start += 4; + *((int *) data_start) = transform.y; + data_start += 4; + *((int *) data_start) = transform.z; + data_start += 4; + + *((int *) data_start) = at_frame_no; + data_start += 4; + + *((int *) data_start) = frame_ref_no; + data_start += 4; + + *((int *) data_start) = flags; + data_start += 4; + + *(int*) data_start=num_extra_data; + data_start+=4; + + for (int i=0; i=0 && ind<=127) + { + flags &=~HierarchyFrame_SoundIndexMask; + flags |= (ind<<24); + } +} + +RIF_IMPLEMENT_DYNCREATE("OBASEQHD",Object_Animation_Sequence_Header_Chunk) + +void Object_Animation_Sequence_Header_Chunk::fill_data_block (char *data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *((int *) data_start) = num_frames; + data_start += 4; + + *((int *) data_start) = sequence_number; + data_start += 4; + + *((int *) data_start) = sub_sequence_number; + data_start += 4; + + *(int*)data_start=num_extra_data; + data_start+=4; + + for (int i=0; i *pList) +{ + List cl; + lookup_child ("OBASEQFR",cl); + + for (LIF cli(&cl); !cli.done(); cli.next()) + { + pList->add_entry((Object_Animation_Sequence_Frame_Chunk *)cli()); + } + +} + +//////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("OBANSEQS",Object_Animation_Sequences_Chunk) + +void Object_Animation_Sequences_Chunk::list_sequences(List * pList) +{ + List cl; + lookup_child ("OBANSEQC",cl); + + for (LIF cli(&cl); !cli.done(); cli.next()) + { + pList->add_entry((Object_Animation_Sequence_Chunk *)cli()); + } +} + + +Object_Animation_Sequence_Chunk::Object_Animation_Sequence_Chunk(Object_Animation_Sequences_Chunk* parent,Object_Animation_Sequence_Chunk* template_seq,ChunkQuat & orient ,ChunkVectorInt & trans) +:Chunk_With_Children (parent, "OBANSEQC") +{ + Object_Animation_Sequence_Header_Chunk* template_header=template_seq->get_header(); + Object_Animation_Sequence_Header_Chunk* header=new Object_Animation_Sequence_Header_Chunk(this); + + header->num_frames=65536; + header->sequence_number=template_header->sequence_number; + header->sub_sequence_number=template_header->sub_sequence_number; + header->sequence_name=new char[strlen(template_header->sequence_name)+1]; + strcpy(header->sequence_name,template_header->sequence_name); + + Object_Animation_Sequence_Frame_Chunk* oasfc=new Object_Animation_Sequence_Frame_Chunk(this); + + oasfc->orientation=orient; + oasfc->transform=trans; + oasfc->at_frame_no=0; + oasfc->frame_ref_no=0; + + //see if template sequence is a delta sequence + List framelist; + template_seq->get_frames(&framelist); + while(framelist.size()) + { + if(framelist.first_entry()->flags & HierarchyFrameFlag_DeltaFrame) + { + oasfc->flags=HierarchyFrameFlag_DeltaFrame; + break; + } + framelist.delete_first_entry(); + } + + +} + +Object_Animation_Sequence_Chunk * Object_Animation_Sequences_Chunk::get_sequence (int num, int subnum) +{ + List seq_list; + list_sequences(&seq_list); + + for (LIF sli(&seq_list); !sli.done(); sli.next()) + { + Object_Animation_Sequence_Header_Chunk * oashc = sli()->get_header(); + if (oashc) + { + if (oashc->sequence_number == num && oashc->sub_sequence_number == subnum) + { + break; + } + } + } + + if (!sli.done()) + { + return(sli()); + } + else + { + return(0); + } +} + +int Object_Animation_Sequence_Chunk::get_sequence_time() +{ + Object_Animation_Sequence_Time_Chunk* time_chunk=(Object_Animation_Sequence_Time_Chunk*)lookup_single_child("OBASEQTM"); + if(time_chunk) + { + return time_chunk->sequence_time; + } + return 0; +} + +int Object_Animation_Sequence_Chunk::get_sequence_speed() +{ + Object_Animation_Sequence_Speed_Chunk* speed_chunk=(Object_Animation_Sequence_Speed_Chunk*)lookup_single_child("OBASEQSP"); + if(speed_chunk) + { + return speed_chunk->sequence_speed; + } + return 0; +} + +BOOL Object_Animation_Sequence_Chunk::get_sequence_vector(ChunkVectorFloat* direction) +{ + if(!direction) return FALSE; + + //default direction is forwards + direction->x=0; + direction->y=0; + direction->z=1; + + + Object_Animation_Sequence_Speed_Chunk* speed_chunk=(Object_Animation_Sequence_Speed_Chunk*)lookup_single_child("OBASEQSP"); + if(speed_chunk) + { + double radian_angle=(speed_chunk->angle/360.0)*2*3.1415278; + direction->x =(float) sin(radian_angle); + direction->z =(float) cos(radian_angle); + + return TRUE; + } + else + { + return FALSE; + } +} + +int Object_Animation_Sequence_Chunk::get_sequence_flags() +{ + Object_Animation_Sequence_Flags_Chunk* flag_chunk=(Object_Animation_Sequence_Flags_Chunk*)lookup_single_child("OBASEQFL"); + if(flag_chunk) + { + return flag_chunk->flags; + } + return 0; +} + +void Object_Animation_Sequence_Chunk::set_sequence_flags(int new_flags) +{ + //find existing flag_chunk , or create a new one + Object_Animation_Sequence_Flags_Chunk* flag_chunk=(Object_Animation_Sequence_Flags_Chunk*)lookup_single_child("OBASEQFL"); + if(flag_chunk) + { + //set the flags + flag_chunk->flags = new_flags; + } + else + { + //create a new chunk then + new Object_Animation_Sequence_Flags_Chunk(this,new_flags); + } +} + +Hierarchy_Bounding_Box_Chunk* Object_Animation_Sequence_Chunk::get_bounding_box() +{ + return (Hierarchy_Bounding_Box_Chunk*)lookup_single_child("HIERBBOX"); +} + +//////////////////////////////////////////////////////////////////////////////// + /*--------------------------------------** + ** Object_Animation_Sequence_Time_Chunk ** + **--------------------------------------*/ + +RIF_IMPLEMENT_DYNCREATE("OBASEQTM",Object_Animation_Sequence_Time_Chunk) + +Object_Animation_Sequence_Time_Chunk::Object_Animation_Sequence_Time_Chunk (Chunk_With_Children * parent,const char * data_start, size_t) +: Chunk (parent, "OBASEQTM") +{ + sequence_time=*(unsigned int*) data_start; +} + +void Object_Animation_Sequence_Time_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + *(unsigned int*) data_start = sequence_time; +} + +//////////////////////////////////////////////////////////////////////////////// + /*---------------------------------------** + ** Object_Animation_Sequence_Speed_Chunk ** + **---------------------------------------*/ + +RIF_IMPLEMENT_DYNCREATE("OBASEQSP",Object_Animation_Sequence_Speed_Chunk) + +Object_Animation_Sequence_Speed_Chunk::Object_Animation_Sequence_Speed_Chunk (Chunk_With_Children * parent,const char * data, size_t) +: Chunk (parent, "OBASEQSP") +{ + CHUNK_EXTRACT(sequence_speed,int) + CHUNK_EXTRACT(angle,int) + CHUNK_EXTRACT(spare,int) +} + +void Object_Animation_Sequence_Speed_Chunk::fill_data_block(char* data) +{ + CHUNK_FILL_START + CHUNK_FILL(sequence_speed,int) + CHUNK_FILL(angle,int) + CHUNK_FILL(spare,int) +} + +//////////////////////////////////////////////////////////////////////////////// + /*---------------------------------------** + ** Object_Animation_Sequence_Flags_Chunk ** + **---------------------------------------*/ + + +RIF_IMPLEMENT_DYNCREATE("OBASEQFL",Object_Animation_Sequence_Flags_Chunk) + +Object_Animation_Sequence_Flags_Chunk::Object_Animation_Sequence_Flags_Chunk (Chunk_With_Children * parent,const char * data, size_t) +: Chunk (parent, "OBASEQFL") +{ + CHUNK_EXTRACT(flags,int) +} + +void Object_Animation_Sequence_Flags_Chunk::fill_data_block(char* data) +{ + CHUNK_FILL_START + CHUNK_FILL(flags,int) +} + +//////////////////////////////////////////////////////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("OBANALLS",Object_Animation_All_Sequence_Chunk) + +Object_Animation_All_Sequence_Chunk::Object_Animation_All_Sequence_Chunk(Chunk_With_Children* parent) +:Chunk(parent,"OBANALLS") +{ + num_sequences=0; + sequences=0; +} + +Object_Animation_All_Sequence_Chunk::Object_Animation_All_Sequence_Chunk(Chunk_With_Children * const parent,const char * data, const size_t) +:Chunk(parent,"OBANALLS") +{ + num_sequences=*(int*)data; + data+=4; + + if(num_sequences) sequences=new Object_Animation_Sequence[num_sequences]; + else sequences=0; + + for(int i=0;inum_frames=*(int*)data; + data+=4; + seq->sequence_number=*(int*)data; + data+=4; + seq->sub_sequence_number=*(int*)data; + data+=4; + seq->sequence_time=*(int*)data; + data+=4; + + if(seq->num_frames) seq->frames=new Object_Animation_Frame[seq->num_frames]; + else seq->frames=0; + + for(unsigned j=0;jnum_frames;j++) + { + seq->frames[j]=*(Object_Animation_Frame*)data; + data+=sizeof(Object_Animation_Frame); + } + } +} + +void Object_Animation_All_Sequence_Chunk::fill_data_block(char* data) +{ + strncpy (data, identifier, 8); + data += 8; + *((int *) data) = chunk_size; + data += 4; + + *(int*)data=num_sequences; + data+=4; + + for(int i=0;inum_frames; + data+=4; + *(int*)data=seq->sequence_number; + data+=4; + *(int*)data=seq->sub_sequence_number; + data+=4; + *(int*)data=seq->sequence_time; + data+=4; + + for(unsigned j=0;jnum_frames;j++) + { + *(Object_Animation_Frame*)data=seq->frames[j]; + data+=sizeof(Object_Animation_Frame); + } + + } +} + +size_t Object_Animation_All_Sequence_Chunk::size_chunk() +{ + chunk_size=12+4; + chunk_size+=num_sequences*16; + for(int i=0;i * pList); + + Object_Animation_Sequence_Chunk * get_sequence (int num, int sub_num); + +private: + + friend class Object_Chunk; + friend class Object_Hierarchy_Chunk; + + +}; + + + + +class Object_Animation_Sequence_Chunk : public Chunk_With_Children +{ +public: + + Object_Animation_Sequence_Chunk (Object_Animation_Sequences_Chunk * parent) + : Chunk_With_Children (parent, "OBANSEQC") + {} + Object_Animation_Sequence_Chunk (Chunk_With_Children * const parent,const char *, const size_t); + + //creates sequence of one frame ,with name taken from template_seq + Object_Animation_Sequence_Chunk(Object_Animation_Sequences_Chunk * parent,Object_Animation_Sequence_Chunk* template_seq,ChunkQuat& orient,ChunkVectorInt& trans); + + Object_Animation_Sequence_Header_Chunk * get_header(); + + void get_frames(List * ); + + int get_sequence_time(); //gets time in ms + int get_sequence_speed(); //gets movement speed in mm/second + + //get (normalised) direction of movement for sequence + //if no direction has been set then returns false , and sets direction to a forward vector + BOOL get_sequence_vector(ChunkVectorFloat* direction); + + //getting and setting flags for this sequence + int get_sequence_flags(); + void set_sequence_flags(int new_flags); + + Hierarchy_Bounding_Box_Chunk* get_bounding_box(); //gets the chunk with the bounding box for the sequence +private: + + friend class Object_Animation_Sequences_Chunk; + + +}; + + + +#define HierarchyFrameFlag_DeltaFrame 0x80000000 +#define HierarchyFrame_SoundIndexMask 0x7f000000 +#define HierarchyFrame_FlagMask 0x00ffffff + +class Object_Animation_Sequence_Frame_Chunk : public Chunk +{ +public: + + Object_Animation_Sequence_Frame_Chunk (Object_Animation_Sequence_Chunk * parent) + : Chunk (parent, "OBASEQFR"), at_frame_no (-1), frame_ref_no (-1) + { + ChunkQuat identity = {0,0,0,1}; + orientation = identity; + + transform.x = 0; + transform.y = 0; + transform.z = 0; + + flags =0; + + num_extra_data=0; + extra_data=0; + } + Object_Animation_Sequence_Frame_Chunk (Chunk_With_Children * parent,const char *, size_t); + + ~Object_Animation_Sequence_Frame_Chunk(){if(extra_data) delete extra_data;} + + ChunkQuat orientation; + ChunkVectorInt transform; + + signed long at_frame_no; //frame start time (0-65535) + + signed long frame_ref_no; //frame index number + + int flags; + + int num_extra_data; + int* extra_data; + + virtual void fill_data_block (char *); + virtual size_t size_chunk () + { + return(chunk_size = 12 + 4*4 + 3*4 + 4 + 4 + 8+4*num_extra_data); + } + + void set_sound_index(int ind); + int get_sound_index(){return ((flags & HierarchyFrame_SoundIndexMask )>>24);} + +private: + + friend class Object_Animation_Sequence_Chunk; + + +}; + + + + +class Object_Animation_Sequence_Header_Chunk : public Chunk +{ +public: + + Object_Animation_Sequence_Header_Chunk(Chunk_With_Children * parent) + : Chunk (parent, "OBASEQHD"), num_frames (0), sequence_number (-1), + sub_sequence_number (-1), sequence_name (0) + { + num_extra_data=0; + extra_data=0; + } + Object_Animation_Sequence_Header_Chunk (Chunk_With_Children * parent,const char *, size_t); + + ~Object_Animation_Sequence_Header_Chunk(); + + unsigned long num_frames; + + signed long sequence_number; + signed long sub_sequence_number; + + int num_extra_data; + int* extra_data; + + char * sequence_name; + + virtual void fill_data_block (char *); + virtual size_t size_chunk () + { + if (sequence_name) + { + return(chunk_size = 12 + 16 + 4*num_extra_data + strlen(sequence_name) + 4 - strlen(sequence_name)%4); + } + else + { + return(chunk_size = 12 + 16 + 4*num_extra_data + 4); + } + } + +private: + + friend class Object_Animation_Sequence_Chunk; + + +}; + +class Object_Animation_Sequence_Time_Chunk : public Chunk +{ +public : + Object_Animation_Sequence_Time_Chunk(Chunk_With_Children* parent) + : Chunk (parent,"OBASEQTM") , sequence_time(0) + { + } + Object_Animation_Sequence_Time_Chunk (Chunk_With_Children * parent,const char *, size_t); + + unsigned int sequence_time; //in milliseconds + + virtual void fill_data_block (char *); + virtual size_t size_chunk (){ return chunk_size=16;} + +private: + + friend class Object_Animation_Sequence_Chunk; + + +}; + + +class Object_Animation_Sequence_Speed_Chunk : public Chunk +{ +public : + Object_Animation_Sequence_Speed_Chunk(Chunk_With_Children* parent) + : Chunk (parent,"OBASEQSP") , sequence_speed(0) ,angle(0),spare(0) + { + } + Object_Animation_Sequence_Speed_Chunk (Chunk_With_Children * parent,const char *, size_t); + + int sequence_speed; //in mm/second + int angle; //in degrees (mainly for tools use) + int spare; + + virtual void fill_data_block (char *); + virtual size_t size_chunk (){ return chunk_size=24;} + +private: + + friend class Object_Animation_Sequence_Chunk; + + +}; + +#define MummySequenceFlag_UpperSequence 0x00000001 +#define MummySequenceFlag_LowerSequence 0x00000002 +#define SequenceFlag_Loops 0x00000004 +#define SequenceFlag_NoLoop 0x00000008 +#define SequenceFlag_NoInterpolation 0x00000010 +#define SequenceFlag_HalfFrameRate 0x00000020 + +class Object_Animation_Sequence_Flags_Chunk : public Chunk +{ +public : + Object_Animation_Sequence_Flags_Chunk(Chunk_With_Children* parent,int _flags) + : Chunk (parent,"OBASEQFL") , flags(_flags) + { + } + Object_Animation_Sequence_Flags_Chunk (Chunk_With_Children * parent,const char *, size_t); + + int flags; + + virtual void fill_data_block (char *); + virtual size_t size_chunk (){ return chunk_size=16;} + +}; + + +struct Object_Animation_Frame +{ + ChunkQuat orientation; + ChunkVectorInt transform; + signed long at_frame_no; //frame start time (0-65535) + int flags; + + int get_sound_index(){return ((flags & HierarchyFrame_SoundIndexMask )>>24);} + +}; + +struct Object_Animation_Sequence +{ + ~Object_Animation_Sequence(){delete [] frames;} + + unsigned long num_frames; + signed long sequence_number; + signed long sub_sequence_number; + unsigned int sequence_time; //in milliseconds + Object_Animation_Frame* frames; +}; + +#define Get_Object_Animation_All_Sequence_Chunk(parent) (Object_Animation_All_Sequence_Chunk*)(parent)->lookup_single_child("OBANALLS") + +//a more compact version of the sequence and frame data +//this format isn't recognized by any of the tools however. +class Object_Animation_All_Sequence_Chunk : public Chunk +{ +public: + + Object_Animation_All_Sequence_Chunk (Chunk_With_Children * parent); + Object_Animation_All_Sequence_Chunk (Chunk_With_Children * const parent,const char *, const size_t); + ~Object_Animation_All_Sequence_Chunk () {delete [] sequences;} + + virtual void fill_data_block (char *); + virtual size_t size_chunk (); + + int num_sequences; + Object_Animation_Sequence* sequences; + +}; +#endif \ No newline at end of file diff --git a/3dc/win95/aw.h b/3dc/win95/aw.h new file mode 100644 index 0000000..8e43f33 --- /dev/null +++ b/3dc/win95/aw.h @@ -0,0 +1,21 @@ +#ifndef _INCLUDED_AW_H_ +#define _INCLUDED_AW_H_ + +#include + +typedef IDirectDraw DDObject; +typedef IDirect3DDevice D3DDevice; +typedef IDirect3DTexture D3DTexture; +typedef IDirectDrawSurface DDSurface; +typedef IDirectDrawPalette DDPalette; + +#define GUID_D3D_TEXTURE IID_IDirect3DTexture +#define GUID_DD_SURFACE IID_IDirectDrawSurface + +typedef DDSURFACEDESC DD_SURFACE_DESC; +typedef DDSCAPS DD_S_CAPS; + +struct AwBackupTexture; +typedef struct AwBackupTexture * AW_BACKUPTEXTUREHANDLE; + +#endif /* _INCLUDED_AW_H_ */ \ No newline at end of file diff --git a/3dc/win95/awBmpLd.cpp b/3dc/win95/awBmpLd.cpp new file mode 100644 index 0000000..375e1d7 --- /dev/null +++ b/3dc/win95/awBmpLd.cpp @@ -0,0 +1,192 @@ +#include "advwin32.h" +#ifndef DB_LEVEL +#define DB_LEVEL 4 +#endif +#include "db.h" + +#include "awTexLd.hpp" + +// BMP Loader + +class AwBmpLoader : public AwTl::TypicalTexFileLoader +{ + protected: + virtual void LoadHeaderInfo(MediaMedium * pMedium); + virtual AwTl::Colour * GetPalette(); + virtual bool AreRowsReversed(); + virtual void LoadNextRow(AwTl::PtrUnion pRow); + + WORD bmp_bitdepth; + DWORD bmp_offset; + DWORD bmp_headsize; + + unsigned bmp_filepitchpad; + unsigned bmp_bitmask; + + MediaMedium * m_pMedium; +}; + +void AwBmpLoader::LoadHeaderInfo(MediaMedium * pMedium) +{ + m_pMedium = pMedium; // store for later + + db_log4("\tLoading a BMP file"); + + pMedium->MovePos(+10); // 2 bytes BM (magic) and 4 bytes bmp_filesize and 4 bytes reserved + + MediaRead(pMedium,&bmp_offset); + MediaRead(pMedium,&bmp_headsize); + // 12 for OS/2 1.x 40 for Windows, 64 for OS/2 2.x + if (12 != bmp_headsize && 40 != bmp_headsize && 64 != bmp_headsize) + { + awTlLastErr = AW_TLE_BADFILEFORMAT; + db_logf3(("AwCreateTexture(): ERROR: BMP_headersize (%u) is not a recognized BMP format",bmp_headsize)); + } + #if DB_LEVEL >= 4 + switch (bmp_headsize) + { + case 12: + db_log4("\tBMP format is OS/2 1.x"); + break; + case 40: + db_log4("\tBMP format is Windows 3.x"); + break; + case 64: + db_log4("\tBMP format is OS/2 2.x"); + } + #endif + if (bmp_headsize >= 40) + { + DWORD width, height; + MediaRead(pMedium,&width); + MediaRead(pMedium,&height); + m_nWidth = width; + m_nHeight = height; + } + else + { + WORD width, height; + MediaRead(pMedium,&width); + MediaRead(pMedium,&height); + m_nWidth = width; + m_nHeight = height; + } + // next WORD is planes and should == 1 + WORD bmp_planes = 0; // ALEX: added in initialization to prevent compiler warnings + MediaRead(pMedium,&bmp_planes); + if (1!=bmp_planes) + { + awTlLastErr = AW_TLE_BADFILEDATA; + db_log3("AwCreateTexture(): ERROR: BMP_planes should be 1"); + } + MediaRead(pMedium,&bmp_bitdepth); + db_logf4(("\tBMP_bitdepth is %hd",bmp_bitdepth)); + if (1!=bmp_bitdepth && 2!=bmp_bitdepth && 4!=bmp_bitdepth && 8!=bmp_bitdepth && 24!=bmp_bitdepth) + { + awTlLastErr = AW_TLE_BADFILEDATA; + db_logf3(("AwCreateTexture(): ERROR: BMP_bitdepth (%u) should be 1,2,4,8 or 24",bmp_bitdepth)); + } + if (bmp_headsize >= 40) + { + // next DWORD is compression, not supported so only accept 0 + DWORD compression = 0; + MediaRead(pMedium,&compression); + if (compression) + { + db_log3("AwCreateTexture(): ERROR: Cannont read compressed BMP files"); + awTlLastErr = AW_TLE_BADFILEFORMAT; + } + // DWORD bmp_size - ignored, 2xDWORDS ignored + pMedium->MovePos(+12); + DWORD palette_size = 0; // ALEX: added in initialization to prevent compiler warnings + MediaRead(pMedium,&palette_size); + m_nPaletteSize = palette_size; + // skip to the start of the palette if there would be one + pMedium->MovePos(bmp_headsize-36); + } + else + { + m_nPaletteSize = 0; + } + bmp_offset -= (bmp_headsize+14); + if (!m_nPaletteSize && bmp_bitdepth<=8) + m_nPaletteSize = 1<= 40 ? m_nPaletteSize*4 : m_nPaletteSize*3; + + db_logf4(("\tBMP_palettesize is %u",m_nPaletteSize)); + bmp_filepitchpad = (~(m_nWidth*bmp_bitdepth-1))/8 & 3; + db_logf4(("\tBMP has %u bytes padding per row",bmp_filepitchpad)); + + bmp_bitmask = (1< 256) + { + awTlLastErr = AW_TLE_BADFILEDATA; + db_log3("AwCreateTexture(): ERROR: BMP_palettesize is too large"); + } + else + { + AwTl::Colour * pmP = m_pPalette; + for (unsigned pc = m_nPaletteSize; pc; --pc,++pmP) + { + MediaRead(m_pMedium,&pmP->b); + MediaRead(m_pMedium,&pmP->g); + MediaRead(m_pMedium,&pmP->r); + if (bmp_headsize >= 40) m_pMedium->MovePos(+1); + } + } + // skip to the start of the pixel data + m_pMedium->MovePos(bmp_offset); + + return m_pPalette; +} + +bool AwBmpLoader::AreRowsReversed() +{ + return true; +} + +void AwBmpLoader::LoadNextRow(AwTl::PtrUnion pRow) +{ + if (m_nPaletteSize) + { + unsigned shift = 0; + BYTE byte = 0; // Not needed. + + for (unsigned colcount = m_nWidth; colcount; --colcount) + { + if (!shift) + { + shift = 8; + MediaRead(m_pMedium, &byte); + } + shift -= bmp_bitdepth; + *pRow.byteP++ = static_cast(byte>>shift & bmp_bitmask); + } + } + else + { + for (unsigned colcount = m_nWidth; colcount; --colcount) + { + MediaRead(m_pMedium,&pRow.colourP->b); + MediaRead(m_pMedium,&pRow.colourP->g); + MediaRead(m_pMedium,&pRow.colourP->r); + ++pRow.colourP; + } + } + m_pMedium->MovePos(bmp_filepitchpad); +} + +#ifdef _MSC_VER + // VC5.0 tries to compile out code that is in a library + // and it thinks isn't being used + #line 186 +#endif +AWTEXLD_IMPLEMENT_DYNCREATE("BM",AwBmpLoader) diff --git a/3dc/win95/awIffLd.cpp b/3dc/win95/awIffLd.cpp new file mode 100644 index 0000000..de3be19 --- /dev/null +++ b/3dc/win95/awIffLd.cpp @@ -0,0 +1,507 @@ +#include "advwin32.h" +#ifndef DB_LEVEL +#define DB_LEVEL 4 +#endif +#include "db.h" +#ifndef DB_COMMA + #define DB_COMMA , +#endif + +#pragma warning(disable: 4701) +#include "awTexLd.hpp" +#pragma warning(default: 4701) + +#include "iff.hpp" +#include "iff_ILBM.hpp" + +#include "list_tem.hpp" + +#include + +// conversion functors for IFF loader +class AwIffConvNull +{ + public: + static inline unsigned DoConv (unsigned const * _colP, AwTl::Colour const * db_code1(DB_COMMA unsigned)) + { + db_assert1(AwTl::pixelFormat.palettizedB); + return *_colP; + } +}; + +class AwIffConvNonTransp : public AwTl::Colour::ConvNonTransp +{ + public: + static inline unsigned DoConv(unsigned const * pCol, AwTl::Colour const * pPalette db_code1(DB_COMMA unsigned nPaletteSize)) + { + db_assert1(pPalette); + db_onlyassert1(*pCol < nPaletteSize); + return AwTl::Colour::ConvNonTransp::DoConv(&pPalette[*pCol]); + } +}; + +class AwIffConvTransp +{ + public: + static unsigned iTranspCol; // the index of the transparent colour + static unsigned rawTranspCol; // the value of a transparent pixel on the surface + + static inline unsigned DoConv(unsigned const * pCol, AwTl::Colour const * pPalette db_code1(DB_COMMA unsigned nPaletteSize)) + { + using namespace AwTl; + + if (*pCol == iTranspCol) return rawTranspCol; + unsigned rv = AwIffConvNonTransp::DoConv(pCol,pPalette db_code1(DB_COMMA nPaletteSize)); + if (rv != rawTranspCol) return rv; + + // make the colour non-transparent (nb: only an occasional case) + + // OK, Here's the plan: + + // First, suppose that I were to decrease either the Red, Green or Blue + // component in order to make the colour non-transparent. + // Taking Red as an example, I'll work out what the resultant red value + // will be if I decrease red to achieve a non-transparent colour + // I'll compare this to the actual red value of the colour in question + // The lower the difference, the better it'll be (ie. closer to the + // original colour). + // Obviously, I'll do the same for Green and Blue + // Then I'll repeat the process but this time considering increasing + // the components. + // I'll then have six values which are scores (the lower the better) + // for what colour component to change and how to change it. + // If any of the components cannot be decreased (ie. their resulting + // value is already zero) or increased (ie. their resulting value + // is at maximum), then I'll set the corresponding score to + // UINT_MAX so that that colour-changing operation won't be selected + // (because that'll be the one that buggers everything up). + + unsigned nRedDiffDown = + (pPalette[*pCol].r < 1<= (255 & ~((1<= (255 & ~((1<= (255 & ~((1<= 1100 + // VC5.0 gives inane warnings when += type operators + // are used on types smaller than int (even with + // explicit casting!) + #pragma warning(disable:4244) + #endif + if + ( + nBlueDiffUp <= nBlueDiffDown + && nBlueDiffUp <= nRedDiffUp + && nBlueDiffUp <= nRedDiffDown + && nBlueDiffUp <= nGreenDiffUp + && nBlueDiffUp <= nGreenDiffDown + ) + { + colAdj.b += static_cast(1<(1<(1<(1<(1<(1< m_listBodyChunks; + + // smallest and largest palette sizes of versions of this image + unsigned m_nMaxPaletteSize; + unsigned m_nMinPaletteSize; + + // buffer for palette - + // since the IFF cmap table is in a different format to what the Aw loaders require + // (maybe should think about standardizing the data types?) + AwTl::Colour * m_pPalette; + + // iff data + IFF::File m_ifData; + IFF::IlbmBmhdChunk * m_pHdr; + IFF::IlbmCmapChunk * m_pCmap; + IFF::IlbmBodyChunk * m_pBody; + + bool m_bDecoding; +}; + +AwIffLoader::~AwIffLoader() +{ + if (m_pPalette) delete[] m_pPalette; +} + +void AwIffLoader::LoadHeaderInfo(MediaMedium * pMedium) +{ + db_log4("\tLoading an IFF file"); + + while (m_listBodyChunks.size()) + m_listBodyChunks.delete_first_entry(); + + if (!m_ifData.Load(pMedium) || !m_ifData.GetContents()) + { + if (NO_ERROR == (awTlLastWinErr = GetLastError())) + awTlLastErr = AW_TLE_BADFILEDATA; + else + awTlLastErr = AW_TLE_CANTREADFILE; + + db_log3("AwCreateTexture(): ERROR: IFF file load failed"); + } + else + { + m_nMinPaletteSize = UINT_MAX; + m_nMaxPaletteSize = 0; + m_ifData.GetContents()->EnumChildren("ILBM","BODY",Enumerator,this); + } +} + +unsigned AwIffLoader::GetNumColours() +{ + return m_nMaxPaletteSize; +} + +unsigned AwIffLoader::GetMinPaletteSize() +{ + return m_nMinPaletteSize; +} + +void AwIffLoader::AllocateBuffers(bool /*bWantBackup*/, unsigned nMaxPaletteSize) +{ + // we will need to allocate buffers when restoring as well as first-time loading + // so allocate buffers in OnBeginRestoring() which we'll call here + + OnBeginRestoring(nMaxPaletteSize); +} + +bool AwIffLoader::Enumerator(IFF::Chunk * pChunk, void * pData) +{ + db_assert1(pChunk); + db_assert1(pData); + AwIffLoader * pThis = static_cast(pData); + + IFF::Chunk * pCmap = pChunk->GetProperty("CMAP"); + IFF::Chunk * pHdr = pChunk->GetProperty("BMHD"); + if (pCmap && pHdr) // must have these two properties + { + unsigned nThisPaletteSize = static_cast(pCmap)->nEntries; + db_logf4(("\tfound a %u colour %scompressed IFF body chunk",nThisPaletteSize,static_cast(pHdr)->eCompression ? "" : "un")); + + pThis->m_listBodyChunks.add_entry(static_cast(pChunk)); + + if (nThisPaletteSize < pThis->m_nMinPaletteSize) + pThis->m_nMinPaletteSize = nThisPaletteSize; + + if (nThisPaletteSize > pThis->m_nMaxPaletteSize) + pThis->m_nMaxPaletteSize = nThisPaletteSize; + } + else db_log3("AwCreateTexture(): WARNING: IFF body chunk found with insufficient associated property chunks"); + + return true; // continue enumeration +} + +void AwIffLoader::OnBeginRestoring(unsigned nMaxPaletteSize) +{ + using namespace AwTl; + + if (m_listBodyChunks.size()) + { + // if decodeing, m_pBody will be valid + if (m_bDecoding) + { + m_pBody->EndDecode(); + m_bDecoding = false; + } + + m_pBody = NULL; + unsigned nBestPaletteSize = 0; + + for (LIF itChunks(&m_listBodyChunks); !itChunks.done(); itChunks.next()) + { + IFF::IlbmCmapChunk * pCmap = static_cast(itChunks()->GetProperty("CMAP")); + db_assert1(pCmap); + + if ((!nMaxPaletteSize || pCmap->nEntries <= nMaxPaletteSize) && pCmap->nEntries > nBestPaletteSize) + { + m_pBody = itChunks(); + m_pCmap = pCmap; + nBestPaletteSize = pCmap->nEntries; + } + } + + if (m_pBody) + { + m_pHdr = static_cast(m_pBody->GetProperty("BMHD")); + // delete old buffers + if (m_pPalette) delete[] m_pPalette; + // allocate buffer for palette, make it extra big to cope with corrupt files + unsigned nAllocPaletteSize = m_pCmap->nEntries; + unsigned nAllocPaletteSizeShift = 0; + while (0!=(nAllocPaletteSize >>= 1)) + { + ++nAllocPaletteSizeShift; + } + m_pPalette = new Colour [2<nEntries]; + // copy the palette + for (unsigned i=0; inEntries; ++i) + { + // hacked testa + m_pPalette[i].r = m_pCmap->pTable[i].r; + m_pPalette[i].g = m_pCmap->pTable[i].g; + m_pPalette[i].b = m_pCmap->pTable[i].b; + } + // set the width height and palette size in the base class + m_nPaletteSize = m_pCmap->nEntries; + m_nWidth = m_pHdr->width; + m_nHeight = m_pHdr->height; + // prepare to decode the data + m_pBody->BeginDecode(); + m_bDecoding = true; + // set the transparent mask colours + switch (m_pHdr->eMasking) + { + case IFF::IlbmBmhdChunk::MASK_NONE: + break; + case IFF::IlbmBmhdChunk::MASK_TRANSPARENTCOL: + AwIffConvTransp::iTranspCol = m_pHdr->iTranspCol; + if (pixelFormat.palettizedB) + AwIffConvTransp::rawTranspCol = AwIffConvTransp::iTranspCol; + else + AwIffConvTransp::rawTranspCol = + static_cast(m_pPalette[AwIffConvTransp::iTranspCol].r)>>pixelFormat.redRightShift<(m_pPalette[AwIffConvTransp::iTranspCol].g)>>pixelFormat.greenRightShift<(m_pPalette[AwIffConvTransp::iTranspCol].b)>>pixelFormat.blueRightShift<(m_listBodyChunks.first_entry()->GetProperty("BMHD")); + db_assert1(pHdr); + return (IFF::IlbmBmhdChunk::MASK_TRANSPARENTCOL == pHdr->eMasking); + } + else + return bDefault; +} + +DWORD AwIffLoader::GetTransparentColour() +{ + return AwIffConvTransp::rawTranspCol; +} + +AwTl::PtrUnion AwIffLoader::GetRowPtr(unsigned /*nRow*/) +{ + // the iff object has an internal buffer to which a pointer + // is returned when we decode each row + // unfortunately we have to cast constness away, but never mind + return const_cast(m_pBody->DecodeNextRow()); +} + +void AwIffLoader::LoadNextRow(AwTl::PtrUnion /*pRow*/) +{ + // GetRowPtr() has called DecodeNextRow() + // which has filled in the data already + // so do nothing here +} + +void AwIffLoader::ConvertRow(AwTl::PtrUnion pDest, unsigned nDestWidth, AwTl::PtrUnionConst pSrc, unsigned nSrcOffset, unsigned nSrcWidth, AwTl::Colour * pPalette db_code1(DB_COMMA unsigned nPaletteSize)) +{ + using namespace AwTl; + + // we have overridden this function for two reasons: + // 1. The data type for each texel in the row is unsigned int + // to allow for the fact that all images are palettized + // with no limit on the palette size. The default + // implementation would assume BYTE (unsigned char) + // 2. The transparency flag and colour is stored in the + // file and the transparency flag passed to AwCreateTexture() + // is ignored. The transparent colour does not have to be 0,0,0 + // either + + db_assert1(pPalette); + db_assert1(pPalette == m_pPalette); + // we can still use GenericConvertRow though, using the conversion functors above + + if (pixelFormat.palettizedB) + { + GenericConvertRow::Do(pDest, nDestWidth, pSrc.uintP+nSrcOffset, nSrcWidth); + } + else + { + switch (m_pHdr->eMasking) + { + case IFF::IlbmBmhdChunk::MASK_NONE: + GenericConvertRow::Do(pDest, nDestWidth, pSrc.uintP+nSrcOffset, nSrcWidth, pPalette db_code1(DB_COMMA nPaletteSize)); + break; + case IFF::IlbmBmhdChunk::MASK_TRANSPARENTCOL: + GenericConvertRow::Do(pDest, nDestWidth, pSrc.uintP+nSrcOffset, nSrcWidth, pPalette db_code1(DB_COMMA nPaletteSize)); + break; + default: + db_log3("AwCreateTexture(): ERROR: IFF mask field wrong"); + awTlLastErr = AW_TLE_BADFILEDATA; + } + } +} + +void AwIffLoader::OnFinishLoading(bool /*bSuccess*/) +{ + if (m_bDecoding) + { + m_pBody->EndDecode(); + m_bDecoding = false; + } +} + +void AwIffLoader::OnFinishRestoring(bool /*bSuccess*/) +{ + if (m_bDecoding) + { + m_pBody->EndDecode(); + m_bDecoding = false; + } +} + +AwBackupTexture * AwIffLoader::CreateBackupTexture() +{ + // use the same object for restoring + AddRef(); + return this; +} + +// Valid file ID fields: 'FORM' 'LIST' 'CAT ' - we can load them all +#ifdef _MSC_VER + // VC5.0 tries to compile out code that is in a library + // and it thinks isn't being used + #line 427 +#endif +AWTEXLD_IMPLEMENT_DYNCREATE("FORM",AwIffLoader) +AWTEXLD_IMPLEMENT_DYNCREATE("LIST",AwIffLoader) +AWTEXLD_IMPLEMENT_DYNCREATE("CAT ",AwIffLoader) diff --git a/3dc/win95/awPnmLd.cpp b/3dc/win95/awPnmLd.cpp new file mode 100644 index 0000000..4e54f2e --- /dev/null +++ b/3dc/win95/awPnmLd.cpp @@ -0,0 +1,239 @@ +#include "advwin32.h" +#ifndef DB_LEVEL +#define DB_LEVEL 4 +#endif +#include "db.h" + +#include "awTexLd.hpp" + +// PNM loaders + +class AwPnmLoader : public AwTl::TypicalTexFileLoader +{ + protected: + void _AWTL_VARARG ParseHeader(unsigned nFields,...); + + MediaMedium * m_pMedium; +}; + +void _AWTL_VARARG AwPnmLoader::ParseHeader(unsigned nFields,...) +{ + va_list ap; + va_start(ap,nFields); + + m_pMedium->MovePos(+2); // skip past magic + + BYTE c = 0; + while (nFields) + { + unsigned * fieldP = va_arg(ap,unsigned *); + bool comment = false; + bool done = false; + do + { + MediaRead(m_pMedium, &c); + switch (c) + { + case '\n': + comment = false; + break; + case '#': + comment = true; + break; + default: + if (!comment && !isspace(c)) + done = true; + } + } + while (!done); + char bufA[512]; + char * bufP = bufA; + do + { + *bufP++ = c; + MediaRead(m_pMedium, &c); + } + while (!isspace(c)); + *bufP = 0; + *fieldP = atoi(bufA); + + -- nFields; + } + // c should now be a newline character + if ('\n'!=c) + awTlLastErr = AW_TLE_BADFILEDATA; + + va_end(ap); +} + +class AwPpmLoader : public AwPnmLoader +{ + protected: + virtual void LoadHeaderInfo(MediaMedium * pMedium); + virtual AwTl::Colour * GetPalette(); + virtual void LoadNextRow(AwTl::PtrUnion pRow); + + unsigned pm_maxval; +}; + +void AwPpmLoader::LoadHeaderInfo(MediaMedium * pMedium) +{ + m_pMedium = pMedium; + + db_log4("\tLoading a PPM file"); + + ParseHeader(3,&m_nWidth,&m_nHeight,&pm_maxval); + + db_logf4(("\tPPM_maxval is %u",pm_maxval)); + if (pm_maxval > 255) + { + awTlLastErr = AW_TLE_BADFILEFORMAT; + db_log3("AwCreateTexture(): PPM_maxval too large"); + } + + m_nPaletteSize = 0; +} + +AwTl::Colour * AwPpmLoader::GetPalette() +{ + // never palettized + return NULL; +} + +void AwPpmLoader::LoadNextRow(AwTl::PtrUnion pRow) +{ + if (pm_maxval != 255) + for (unsigned colcount = m_nWidth; colcount; --colcount) + { + BYTE byte; + MediaRead(m_pMedium,&byte); + pRow.colourP->r = static_cast(static_cast(byte)*255/pm_maxval); + MediaRead(m_pMedium,&byte); + pRow.colourP->g = static_cast(static_cast(byte)*255/pm_maxval); + MediaRead(m_pMedium,&byte); + pRow.colourP->b = static_cast(static_cast(byte)*255/pm_maxval); + ++pRow.colourP; + } + else + for (unsigned colcount = m_nWidth; colcount; --colcount) + { + MediaRead(m_pMedium,&pRow.colourP->r); + MediaRead(m_pMedium,&pRow.colourP->g); + MediaRead(m_pMedium,&pRow.colourP->b); + ++pRow.colourP; + } +} + + +class AwPgmLoader : public AwPnmLoader +{ + protected: + virtual void LoadHeaderInfo(MediaMedium * pMedium); + virtual AwTl::Colour * GetPalette(); + virtual void LoadNextRow(AwTl::PtrUnion pRow); + + unsigned pm_maxval; +}; + +void AwPgmLoader::LoadHeaderInfo(MediaMedium * pMedium) +{ + m_pMedium = pMedium; + + db_log4("\tLoading a PGM file"); + + ParseHeader(3,&m_nWidth,&m_nHeight,&pm_maxval); + + db_logf4(("\tPGM_maxval is %u",pm_maxval)); + if (pm_maxval > 255) + { + awTlLastErr = AW_TLE_BADFILEFORMAT; + db_log3("AwCreateTexture(): PGM_maxval too large"); + } + + m_nPaletteSize = pm_maxval+1; +} + +AwTl::Colour * AwPgmLoader::GetPalette() +{ + db_assert1(m_nPaletteSize); + db_assert1(m_pPalette); + + unsigned step8 = (256*255)/pm_maxval; + unsigned val8 = 127; + AwTl::Colour * pmP = m_pPalette; + for (unsigned pc = m_nPaletteSize; pc; --pc,++pmP,val8+=step8) + pmP->r = pmP->g = pmP->b = static_cast(val8/256); + + return m_pPalette; +} + +void AwPgmLoader::LoadNextRow(AwTl::PtrUnion pRow) +{ + m_pMedium->ReadBlock(pRow,m_nWidth); +} + + +class AwPbmLoader : public AwPnmLoader +{ + protected: + virtual void LoadHeaderInfo(MediaMedium * pMedium); + virtual AwTl::Colour * GetPalette(); + virtual void LoadNextRow(AwTl::PtrUnion pRow); +}; + + +void AwPbmLoader::LoadHeaderInfo(MediaMedium * pMedium) +{ + m_pMedium = pMedium; + + db_log4("\tLoading a PBM file"); + + ParseHeader(2,&m_nWidth,&m_nHeight); + + m_nPaletteSize = 2; +} + +AwTl::Colour * AwPbmLoader::GetPalette() +{ + db_assert1(m_nPaletteSize); + db_assert1(m_pPalette); + + m_pPalette[0].r = 0; + m_pPalette[0].g = 0; + m_pPalette[0].b = 0; + m_pPalette[1].r = 255; + m_pPalette[1].g = 255; + m_pPalette[1].b = 255; + + return m_pPalette; +} + +void AwPbmLoader::LoadNextRow(AwTl::PtrUnion pRow) +{ + unsigned shift = 0; + BYTE byte = 0; + + for (unsigned colcount = m_nWidth; colcount; --colcount) + { + if (!shift) + { + shift = 8; + MediaRead(m_pMedium,&byte); + byte = (BYTE) ~byte; + } + --shift; + *pRow.byteP++ = static_cast(byte>>shift & 1); + } +} + +#ifdef _MSC_VER + // VC5.0 tries to compile out code that is in a library + // and it thinks isn't being used + #line 228 +#endif +AWTEXLD_IMPLEMENT_DYNCREATE("P6",AwPpmLoader) +AWTEXLD_IMPLEMENT_DYNCREATE("P5",AwPgmLoader) +AWTEXLD_IMPLEMENT_DYNCREATE("P4",AwPbmLoader) + + + diff --git a/3dc/win95/awTexLd.cpp b/3dc/win95/awTexLd.cpp new file mode 100644 index 0000000..65f4b7a --- /dev/null +++ b/3dc/win95/awTexLd.cpp @@ -0,0 +1,2974 @@ +#include "advwin32.h" +#ifndef DB_LEVEL +#define DB_LEVEL 4 +#endif +#include "db.h" + +#ifndef NDEBUG + #define HT_FAIL db_log1 + #include "hash_tem.hpp" // for the backup surfaces memory leak checking +#endif + +#ifdef _MSC_VER + #include "iff.hpp" +#endif + +#include "list_tem.hpp" + +#include +#include +#include + +#include "awTexLd.h" +#pragma warning(disable: 4701) +#include "awTexLd.hpp" +#pragma warning(default: 4701) + +#ifdef _CPPRTTI + #include +#endif + +/* awTexLd.cpp - Author: Jake Hotson */ + +/*****************************************/ +/* Preprocessor switches for experiments */ +/*****************************************/ + +#define MIPMAPTEST 0 // experiment to create mip map surfaces for textures, but doesn't bother putting any data into them + +/*****************************/ +/* DB_LEVEL dependent macros */ +/*****************************/ + +#if DB_LEVEL >= 5 +#define inline // prevent function inlining at level 5 debugging +#endif + +/*****************************************************/ +/* ZEROFILL and SETDWSIZE macros ensure that I won't */ +/* accidentally get the parameters wrong */ +/*****************************************************/ + +#if 1 // which do you prefer? + +// zero mem +template +static inline void ZEROFILL(X & x) +{ + memset(&x,0,sizeof(X)); +} + +// set dwSize +template +static inline void SETDWSIZE(X & x) +{ + x.dwSize = sizeof(X); +} + +template +static inline void INITDXSTRUCT(X & x) +{ + ZEROFILL(x); + SETDWSIZE(x); +} + +#else + +#define ZEROFILL(x) (memset(&x,0,sizeof x)) +#define SETDWSIZE(x) (x.dwSize = sizeof x) +#define INITDXSTRUCT(x) (ZEROFILL(x),SETDWSIZE(x)) + +#endif + +/*****************************************************************/ +/* Put everything I can in a namespace to avoid naming conflicts */ +/*****************************************************************/ + +namespace AwTl +{ + /**************************************************/ + /* Allow breakpoints to be potentially hard coded */ + /* into macros and template functions */ + /**************************************************/ + + db_code5(void BrkPt(){}) + #define BREAKPOINT db_code5(::AwTl::BrkPt();) + + #if DB_LEVEL > 4 + static unsigned GetRefCount(IUnknown * pUnknown) + { + if (!pUnknown) return 0; + pUnknown->AddRef(); + return static_cast(pUnknown->Release()); + } + #endif + + /*********************************/ + /* Pixel format global structure */ + /*********************************/ + + PixelFormat pixelFormat; + + PixelFormat pfTextureFormat; + PixelFormat pfSurfaceFormat; + + static inline void SetBitShifts(unsigned * leftShift,unsigned * rightShift,unsigned mask) + { + if (!mask) + *leftShift = 0; + else + for (*leftShift = 0; !(mask & 1); ++*leftShift, mask>>=1) + ; + for (*rightShift = 8; mask; --*rightShift, mask>>=1) + ; + } + + /************************************/ + /* D3D Driver info global structure */ + /************************************/ + + static + struct DriverDesc + { + DriverDesc() : validB(false), ddP(NULL) {} + + bool validB : 1; + bool needSquareB : 1; + bool needPow2B : 1; + + unsigned minWidth; + unsigned minHeight; + unsigned maxWidth; + unsigned maxHeight; + + DWORD memFlag; + + DDObject * ddP; + } + driverDesc; + + /*************************************************************************/ + /* Class used to hold all the parameters for the CreateTexture functions */ + /*************************************************************************/ + + class CreateTextureParms + { + public: + inline CreateTextureParms() + : fileNameS(NULL) + , fileH(INVALID_HANDLE_VALUE) + , dataP(NULL) + , restoreH(NULL) + , maxReadBytes(UINT_MAX) + , bytesReadP(NULL) + , flags(AW_TLF_DEFAULT) + , originalWidthP(NULL) + , originalHeightP(NULL) + , widthP(NULL) + , heightP(NULL) + , backupHP(NULL) + , prevTexP(static_cast(NULL)) + , prevTexB(false) + , loadTextureB(false) + , callbackF(NULL) + , rectA(NULL) + { + } + + SurfUnion DoCreate() const; + + bool loadTextureB; + + LPCTSTR fileNameS; + HANDLE fileH; + PtrUnionConst dataP; + AW_BACKUPTEXTUREHANDLE restoreH; + + unsigned maxReadBytes; + unsigned * bytesReadP; + + unsigned flags; + + unsigned * widthP; + unsigned * heightP; + + unsigned * originalWidthP; + unsigned * originalHeightP; + + AW_BACKUPTEXTUREHANDLE * backupHP; + + SurfUnion prevTexP; + bool prevTexB; // used when rectA is non-NULL, otherwise prevTexP is used + + AW_TL_PFN_CALLBACK callbackF; + void * callbackParam; + + unsigned numRects; + AwCreateGraphicRegion * rectA; + }; + + + /****************************************/ + /* Reference Count Object Debug Support */ + /****************************************/ + + #ifndef NDEBUG + + static bool g_bAllocListActive = false; + + class AllocList : public ::HashTable + { + public: + AllocList() + { + g_bAllocListActive = true; + } + ~AllocList() + { + if (Size()) + { + db_log1(("AW: Potential Memory Leaks Detected!!!")); + } + #ifdef _CPPRTTI + #pragma message("Run-Time Type Identification (RTTI) is enabled") + for (Iterator itLeak(*this) ; !itLeak.Done() ; itLeak.Next()) + { + db_logf1(("\tAW Object not deallocated: Type: %s RefCnt: %u",typeid(*itLeak.Get()).name(),itLeak.Get()->m_nRefCnt)); + } + if (Size()) + { + db_log1(("AW: Object dump complete")); + } + #else // ! _CPPRTTI + #pragma message("Run-Time Type Identification (RTTI) is not enabled - memory leak checking will not report types") + unsigned nRefs(0); + for (Iterator itLeak(*this) ; !itLeak.Done() ; itLeak.Next()) + { + nRefs += itLeak.Get()->m_nRefCnt; + } + if (Size()) + { + db_logf1(("AW: Objects not deallocated: Number of Objects: %u Number of References: %u",Size(),nRefs)); + } + #endif // ! _CPPRTTI + g_bAllocListActive = false; + } + }; + + static AllocList g_listAllocated; + + void DbRemember(RefCntObj * pObj) + { + g_listAllocated.AddAsserted(pObj); + } + + void DbForget(RefCntObj * pObj) + { + if (g_bAllocListActive) + g_listAllocated.RemoveAsserted(pObj); + } + + #endif // ! NDEBUG + + /********************************************/ + /* structure to contain loading information */ + /********************************************/ + + struct LoadInfo + { + DDSurface * surfaceP; + bool surface_lockedB; + DDSurface * dst_surfaceP; + D3DTexture * textureP; + D3DTexture * dst_textureP; + + unsigned surface_width; + unsigned surface_height; + PtrUnion surface_dataP; + LONG surface_pitch; + DWORD dwCapsCaps; + + unsigned * widthP; + unsigned * heightP; + SurfUnion prevTexP; + SurfUnion resultP; + unsigned top,left,bottom,right; + unsigned width,height; // set to right-left and bottom-top + + AwCreateGraphicRegion * rectP; + + bool skipB; // used to indicate that a surface/texture was not lost and .`. does not need restoring + + LoadInfo() + : surfaceP(NULL) + , surface_lockedB(false) + , dst_surfaceP(NULL) + , textureP(NULL) + , dst_textureP(NULL) + , skipB(false) + { + } + }; + + /*******************************/ + /* additiional texture formats */ + /*******************************/ + + struct AdditionalPixelFormat : PixelFormat + { + bool canDoTranspB; + unsigned maxColours; + + // for List + bool operator == (AdditionalPixelFormat const &) const { return false; } + bool operator != (AdditionalPixelFormat const &) const { return true; } + }; + + static List listTextureFormats; + +} // namespace AwTl + +/*******************/ +/* Generic Loaders */ +/*******************/ + +#define HANDLE_DXERROR(s) \ + if (DD_OK != awTlLastDxErr) { \ + awTlLastErr = AW_TLE_DXERROR; \ + db_logf3(("AwCreateGraphic() failed whilst %s",s)); \ + db_log1("AwCreateGraphic(): ERROR: DirectX SDK call failed"); \ + goto EXIT_WITH_ERROR; \ + } else { \ + db_logf5(("\tsuccessfully completed %s",s)); \ + } + +#define ON_ERROR_RETURN_NULL(s) \ + if (awTlLastErr != AW_TLE_OK) { \ + db_logf3(("AwCreateGraphic() failed whilst %s",s)); \ + db_logf1(("AwCreateGraphic(): ERROR: %s",AwTlErrorToString())); \ + return static_cast(NULL); \ + } else { \ + db_logf5(("\tsuccessfully completed %s",s)); \ + } + +#define CHECK_MEDIA_ERRORS(s) \ + if (pMedium->m_fError) { \ + db_logf3(("AwCreateGraphic(): The following media errors occurred whilst %s",s)); \ + if (pMedium->m_fError & MediaMedium::MME_VEOFMET) { \ + db_log3("\tA virtual end of file was met"); \ + if (awTlLastErr == AW_TLE_OK) awTlLastErr = AW_TLE_EOFMET; \ + } \ + if (pMedium->m_fError & MediaMedium::MME_EOFMET) { \ + db_log3("\tAn actual end of file was met"); \ + if (awTlLastErr == AW_TLE_OK) awTlLastErr = AW_TLE_EOFMET; \ + } \ + if (pMedium->m_fError & MediaMedium::MME_OPENFAIL) { \ + db_log3("\tThe file could not be opened"); \ + if (awTlLastErr == AW_TLE_OK) { awTlLastErr = AW_TLE_CANTOPENFILE; awTlLastWinErr = GetLastError(); } \ + } \ + if (pMedium->m_fError & MediaMedium::MME_CLOSEFAIL) { \ + db_log3("\tThe file could not be closed"); \ + if (awTlLastErr == AW_TLE_OK) { awTlLastErr = AW_TLE_CANTOPENFILE; awTlLastWinErr = GetLastError(); } \ + } \ + if (pMedium->m_fError & MediaMedium::MME_UNAVAIL) { \ + db_log3("\tA requested operation was not available"); \ + if (awTlLastErr == AW_TLE_OK) { awTlLastErr = AW_TLE_CANTREADFILE; awTlLastWinErr = GetLastError(); } \ + } \ + if (pMedium->m_fError & MediaMedium::MME_IOERROR) { \ + db_log3("\tA read error occurred"); \ + if (awTlLastErr == AW_TLE_OK) { awTlLastErr = AW_TLE_CANTREADFILE; awTlLastWinErr = GetLastError(); } \ + } \ + } + +AwTl::SurfUnion AwBackupTexture::Restore(AwTl::CreateTextureParms const & rParams) +{ + using namespace AwTl; + + ChoosePixelFormat(rParams); + + if (!pixelFormat.validB) + db_log3("AwCreateGraphic(): ERROR: pixel format not valid"); + if (!driverDesc.ddP || !driverDesc.validB && rParams.loadTextureB) + db_log3("AwCreateGraphic(): ERROR: driver description not valid"); + + awTlLastErr = pixelFormat.validB && driverDesc.ddP && (driverDesc.validB || !rParams.loadTextureB) ? AW_TLE_OK : AW_TLE_NOINIT; + + ON_ERROR_RETURN_NULL("initializing restore") + + OnBeginRestoring(pixelFormat.palettizedB ? 1< itFormat(&listTextureFormats); !itFormat.done(); itFormat.next()) + { + AdditionalPixelFormat const * pThisFormat = &itFormat(); + // is this format suitable? + // ignoring alpha for now + if + ( + (nMinPalSize <= 1U<bitsPerPixel && nMinPalSize || !pThisFormat->palettizedB) // few enough colours for palettized format + && (nColours <= pThisFormat->maxColours && nColours || !pThisFormat->maxColours) // pass the max colours test + && (pThisFormat->canDoTranspB || !m_bTranspMask) // pass the transparency test + ) + { + pFormat = pThisFormat; + } + } + + pixelFormat = *pFormat; + + #if DB_LEVEL >= 4 + if (pixelFormat.palettizedB) + { + db_logf4(("\tchosen %u-bit palettized texture format",pixelFormat.bitsPerPixel)); + } + else + { + if (pixelFormat.alphaB) + { + unsigned alpha_l_shft,alpha_r_shft; + SetBitShifts(&alpha_l_shft,&alpha_r_shft,pixelFormat.ddpf.dwRGBAlphaBitMask); + + db_logf4(("\tchosen %u-bit %u%u%u%u texture format", + pixelFormat.bitsPerPixel, + 8U-pixelFormat.redRightShift, + 8U-pixelFormat.greenRightShift, + 8U-pixelFormat.blueRightShift, + 8U-alpha_r_shft)); + } + else + { + db_logf4(("\tchosen %u-bit %u%u%u texture format", + pixelFormat.bitsPerPixel, + 8U-pixelFormat.redRightShift, + 8U-pixelFormat.greenRightShift, + 8U-pixelFormat.blueRightShift)); + } + } + #endif + } + else + { + // use display surface format + pixelFormat = pfSurfaceFormat; + } + +} + +AwTl::SurfUnion AwBackupTexture::CreateTexture(AwTl::CreateTextureParms const & _parmsR) +{ + using namespace AwTl; + + // which flags to use? + unsigned fMyFlags = + _parmsR.flags & AW_TLF_PREVSRCALL ? db_assert1(_parmsR.restoreH), + _parmsR.flags & (AW_TLF_CHECKLOST|AW_TLF_SKIPNOTLOST) | m_fFlags & ~(AW_TLF_CHECKLOST|AW_TLF_SKIPNOTLOST) + : _parmsR.flags & AW_TLF_PREVSRC ? db_assert1(_parmsR.restoreH), + _parmsR.flags & ~AW_TLF_TRANSP | m_fFlags & AW_TLF_TRANSP + : _parmsR.flags; + + db_code1(ULONG refcnt;) + + DDPalette * dd_paletteP = NULL; + LoadInfo * arrLoadInfo = NULL; + unsigned nLoadInfos = 0; + { + // quick error check + if (pixelFormat.palettizedB && (!m_nPaletteSize || 1U< _parmsR.rectA[i].left + && _parmsR.rectA[i].bottom > _parmsR.rectA[i].top + ) + { + // rectangle covers at least some of the image and non-null previous texture + arrLoadInfo[nLoadInfos].widthP = &_parmsR.rectA[i].width; + arrLoadInfo[nLoadInfos].heightP = &_parmsR.rectA[i].height; + if (_parmsR.prevTexB) + { + if (_parmsR.loadTextureB) + arrLoadInfo[nLoadInfos].prevTexP = _parmsR.rectA[i].pTexture; + else + arrLoadInfo[nLoadInfos].prevTexP = _parmsR.rectA[i].pSurface; + } + else + { + arrLoadInfo[nLoadInfos].prevTexP = static_cast(NULL); + if (_parmsR.loadTextureB) + _parmsR.rectA[i].pTexture = NULL; + else + _parmsR.rectA[i].pSurface = NULL; + } + + arrLoadInfo[nLoadInfos].rectP = &_parmsR.rectA[i]; + arrLoadInfo[nLoadInfos].top = _parmsR.rectA[i].top; + arrLoadInfo[nLoadInfos].left = _parmsR.rectA[i].left; + arrLoadInfo[nLoadInfos].bottom = _parmsR.rectA[i].bottom; + arrLoadInfo[nLoadInfos].right = _parmsR.rectA[i].right; + + if (arrLoadInfo[nLoadInfos].right > m_nWidth) arrLoadInfo[nLoadInfos].right = m_nWidth; + if (arrLoadInfo[nLoadInfos].bottom > m_nHeight) arrLoadInfo[nLoadInfos].bottom = m_nHeight; + + arrLoadInfo[nLoadInfos].width = arrLoadInfo[nLoadInfos].right - arrLoadInfo[nLoadInfos].left; + arrLoadInfo[nLoadInfos].height = arrLoadInfo[nLoadInfos].bottom - arrLoadInfo[nLoadInfos].top; + + ++nLoadInfos; + } + else + { + if (!_parmsR.prevTexB) + _parmsR.rectA[i].pTexture = NULL; + } + } + } + else + { + nLoadInfos = 1; + arrLoadInfo = new LoadInfo[1]; + arrLoadInfo[0].widthP = _parmsR.widthP; + arrLoadInfo[0].heightP = _parmsR.heightP; + arrLoadInfo[0].prevTexP = _parmsR.prevTexP; + arrLoadInfo[0].rectP = NULL; + arrLoadInfo[0].top = 0; + arrLoadInfo[0].left = 0; + arrLoadInfo[0].bottom = m_nHeight; + arrLoadInfo[0].right = m_nWidth; + arrLoadInfo[0].width = m_nWidth; + arrLoadInfo[0].height = m_nHeight; + } + + bool bSkipAll = true; + + // loop creating surfaces + {for (unsigned i=0; ileft,pLoadInfo->top,pLoadInfo->right,pLoadInfo->bottom)); + db_logf5(("\treference count on input surface %u",_parmsR.loadTextureB ? GetRefCount(pLoadInfo->prevTexP.textureP) : GetRefCount(pLoadInfo->prevTexP.surfaceP))); + + // determine what the width and height of the surface will be + + if (_parmsR.loadTextureB || fMyFlags & AW_TLF_TEXTURE) + { + awTlLastErr = + AwGetTextureSize + ( + &pLoadInfo->surface_width, + &pLoadInfo->surface_height, + fMyFlags & AW_TLF_MINSIZE && pLoadInfo->rectP ? pLoadInfo->rectP->right - pLoadInfo->rectP->left : pLoadInfo->width, + fMyFlags & AW_TLF_MINSIZE && pLoadInfo->rectP ? pLoadInfo->rectP->bottom - pLoadInfo->rectP->top : pLoadInfo->height + ); + if (awTlLastErr != AW_TLE_OK) + goto EXIT_WITH_ERROR; + } + else + { + pLoadInfo->surface_width = fMyFlags & AW_TLF_MINSIZE && pLoadInfo->rectP ? pLoadInfo->rectP->right - pLoadInfo->rectP->left : pLoadInfo->width; + pLoadInfo->surface_height = fMyFlags & AW_TLF_MINSIZE && pLoadInfo->rectP ? pLoadInfo->rectP->bottom - pLoadInfo->rectP->top : pLoadInfo->height; + #if 1 // not sure if this is required... + pLoadInfo->surface_width += 3; + pLoadInfo->surface_width &= ~3; + pLoadInfo->surface_height += 3; + pLoadInfo->surface_height &= ~3; + #endif + } + + if (pLoadInfo->widthP) *pLoadInfo->widthP = pLoadInfo->surface_width; + if (pLoadInfo->heightP) *pLoadInfo->heightP = pLoadInfo->surface_height; + + // Create DD Surface + + DD_SURFACE_DESC ddsd; + INITDXSTRUCT(ddsd); + ddsd.ddpfPixelFormat = pixelFormat.ddpf; + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + if (_parmsR.loadTextureB || fMyFlags & AW_TLF_TEXTURE) + pLoadInfo->dwCapsCaps = DDSCAPS_TEXTURE | (fMyFlags & (AW_TLF_COMPRESS|AW_TLF_TEXTURE) ? DDSCAPS_SYSTEMMEMORY : driverDesc.memFlag); + else + pLoadInfo->dwCapsCaps = DDSCAPS_OFFSCREENPLAIN | (fMyFlags & AW_TLF_VIDMEM ? DDSCAPS_VIDEOMEMORY : DDSCAPS_SYSTEMMEMORY); + ddsd.ddsCaps.dwCaps = pLoadInfo->dwCapsCaps; + ddsd.dwHeight = pLoadInfo->surface_height; + ddsd.dwWidth = pLoadInfo->surface_width; + + #if MIPMAPTEST + /* + D3DPTEXTURECAPS_POW2 + All nonmipmapped textures must have widths and heights specified as powers of two if this flag is set. + (Note that all mipmapped textures must always have dimensions that are powers of two.) + */ + if (128==pLoadInfo->surface_width && 128==pLoadInfo->surface_height) + { + ddsd.ddsCaps.dwCaps |= DDSCAPS_MIPMAP | DDSCAPS_COMPLEX; + ddsd.dwFlags |= DDSD_MIPMAPCOUNT; + ddsd.dwMipMapCount = 3; + } + #endif + + if (pLoadInfo->prevTexP.voidP && (!_parmsR.loadTextureB || !(fMyFlags & AW_TLF_COMPRESS))) + { + if (_parmsR.loadTextureB) + awTlLastDxErr = pLoadInfo->prevTexP.textureP->QueryInterface(GUID_DD_SURFACE,(LPVOID *)&pLoadInfo->surfaceP); + else + awTlLastDxErr = pLoadInfo->prevTexP.surfaceP->QueryInterface(GUID_DD_SURFACE,(LPVOID *)&pLoadInfo->surfaceP); + HANDLE_DXERROR("getting direct draw surface interface") + #if DB_LEVEL >= 5 + if (_parmsR.loadTextureB) + db_logf5(("\t\tnow prev tex ref %u new surface i/f ref %u",GetRefCount(pLoadInfo->prevTexP.textureP),GetRefCount(pLoadInfo->surfaceP))); + else + db_logf5(("\t\tnow prev surf ref %u new surface i/f ref %u",GetRefCount(pLoadInfo->prevTexP.surfaceP),GetRefCount(pLoadInfo->surfaceP))); + #endif + + // check for lost surfaces + if (fMyFlags & AW_TLF_CHECKLOST) + { + awTlLastDxErr = pLoadInfo->surfaceP->IsLost(); + + if (DDERR_SURFACELOST == awTlLastDxErr) + { + db_log4("\tRestoring Lost Surface"); + + awTlLastDxErr = pLoadInfo->surfaceP->Restore(); + } + else if (DD_OK == awTlLastDxErr && (fMyFlags & AW_TLF_SKIPNOTLOST)) + { + db_log4("\tSkipping Surface which was not Lost"); + + pLoadInfo->skipB = true; + } + + HANDLE_DXERROR("testing for lost surface and restoring if necessary"); + } + + if (!pLoadInfo->skipB) + { + // check that the surface desc is OK + // note that SetSurfaceDesc is *only* supported for changing the surface memory pointer + DD_SURFACE_DESC old_ddsd; + INITDXSTRUCT(old_ddsd); + awTlLastDxErr = pLoadInfo->surfaceP->GetSurfaceDesc(&old_ddsd); + HANDLE_DXERROR("getting previous surface desc") + // check width, height, RGBBitCount and memory type + if (old_ddsd.dwFlags & DDSD_ALL || (old_ddsd.dwFlags & (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT)) == (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT)) + { + if (old_ddsd.dwHeight == pLoadInfo->surface_height && old_ddsd.dwWidth == pLoadInfo->surface_width && (old_ddsd.ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY|DDSCAPS_VIDEOMEMORY|DDSCAPS_TEXTURE)) == pLoadInfo->dwCapsCaps) + { + unsigned bpp = 0; + if (old_ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) + bpp = 8; + else if (old_ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) + bpp = 4; + else if (old_ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED2) + bpp = 2; + else if (old_ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED1) + bpp = 1; + else if (old_ddsd.ddpfPixelFormat.dwFlags & DDPF_RGB) + bpp = old_ddsd.ddpfPixelFormat.dwRGBBitCount; + if (pixelFormat.bitsPerPixel != bpp) + awTlLastErr = AW_TLE_CANTRELOAD; + } + else + awTlLastErr = AW_TLE_CANTRELOAD; + } + else + awTlLastErr = AW_TLE_CANTRELOAD; + if (AW_TLE_OK != awTlLastErr) + { + db_log1("AwCreateGraphic() failed because existing surface is incompatible"); + goto EXIT_WITH_ERROR; + } + } + else + { + pLoadInfo->surfaceP->Release(); + pLoadInfo->surfaceP = NULL; + } + } + else + { + if (pLoadInfo->prevTexP.voidP && (fMyFlags & AW_TLF_CHECKLOST)) + { + db_assert1(_parmsR.loadTextureB); + + awTlLastDxErr = pLoadInfo->prevTexP.textureP->QueryInterface(GUID_DD_SURFACE,(LPVOID *)&pLoadInfo->surfaceP); + HANDLE_DXERROR("getting direct draw surface interface") + + db_logf5(("\t\tnow prev tex ref %u new surface i/f ref %u",GetRefCount(pLoadInfo->prevTexP.textureP),GetRefCount(pLoadInfo->surfaceP))); + + awTlLastDxErr = pLoadInfo->surfaceP->IsLost(); + + if (DDERR_SURFACELOST == awTlLastDxErr) + { + db_log4("\tRestoring Lost Surface"); + + awTlLastDxErr = pLoadInfo->surfaceP->Restore(); + } + else if (DD_OK == awTlLastDxErr && (fMyFlags & AW_TLF_SKIPNOTLOST)) + { + db_log4("\tSkipping Surface which was not Lost"); + + pLoadInfo->skipB = true; + } + + HANDLE_DXERROR("testing for lost surface and restoring if necessary"); + + pLoadInfo->surfaceP->Release(); + pLoadInfo->surfaceP = NULL; + } + + if (!pLoadInfo->skipB) + { + do + { + awTlLastDxErr = driverDesc.ddP->CreateSurface(&ddsd,&pLoadInfo->surfaceP,NULL); + } + while + ( + DDERR_OUTOFVIDEOMEMORY == awTlLastDxErr + && _parmsR.callbackF + && _parmsR.callbackF(_parmsR.callbackParam) + ); + + HANDLE_DXERROR("creating direct draw surface") + } + } + + if (pLoadInfo->skipB) + { + db_assert1(pLoadInfo->prevTexP.voidP); + + // skipping so result is same as input + pLoadInfo->resultP = pLoadInfo->prevTexP; + + if (_parmsR.loadTextureB) + pLoadInfo->prevTexP.textureP->AddRef(); + else + pLoadInfo->prevTexP.surfaceP->AddRef(); + } + + #if MIPMAPTEST + if (128==surface_width && 128==surface_height) + { + // test if we can get attached surfaces... + DDSCAPS ddscaps; + ZEROFILL(ddscaps); + ddscaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP; + DDSurface * mip2P; + awTlLastDxErr = pLoadInfo->surfaceP->GetAttachedSurface(&ddscaps,&mip2P); + HANDLE_DXERROR("getting first mipmap") + DDSurface * mip3P; + awTlLastDxErr = mip2P->GetAttachedSurface(&ddscaps,&mip3P); + HANDLE_DXERROR("getting second mipmap") + db_logf5(("\tabout to release 2nd mip with ref %u",GetRefCount(mip2P))); + db_code1(refcnt =) + mip2P->Release(); + db_onlyassert1(1==refcnt); + db_logf5(("\tabout to release 3nd mip with ref %u",GetRefCount(mip3P))); + db_code1(refcnt =) + mip3P->Release(); + db_onlyassert1(1==refcnt); + } + #endif + + bSkipAll = bSkipAll && pLoadInfo->skipB; + }} + + if (!bSkipAll) + { + Colour * paletteP = m_nPaletteSize ? GetPalette() : NULL; + + unsigned y = 0; + bool reversed_rowsB = AreRowsReversed(); + if (reversed_rowsB) + { + y = m_nHeight-1; + } + + for (unsigned rowcount = m_nHeight; rowcount; --rowcount) + { + PtrUnion src_rowP = GetRowPtr(y); + db_assert1(src_rowP.voidP); + + // allow loading of the next row from the file + LoadNextRow(src_rowP); + + // loop for copying data to surfaces + for (unsigned i=0; iskipB) + { + // are we in the vertical range of this surface? + if (y>=pLoadInfo->top && ybottom) + { + if (!pLoadInfo->surface_lockedB) + { + // lock the surfaces + DD_SURFACE_DESC ddsd; + INITDXSTRUCT(ddsd); + awTlLastDxErr = pLoadInfo->surfaceP->Lock(NULL,&ddsd,DDLOCK_WRITEONLY|DDLOCK_NOSYSLOCK,NULL); + HANDLE_DXERROR("locking direct draw surface") + pLoadInfo->surface_lockedB = true; + pLoadInfo->surface_dataP.voidP = ddsd.lpSurface; + pLoadInfo->surface_dataP.byteP += ddsd.lPitch * (y-pLoadInfo->top); + pLoadInfo->surface_pitch = ddsd.lPitch; + } + + // convert and copy the section of the row to the direct draw surface + ConvertRow(pLoadInfo->surface_dataP,pLoadInfo->surface_width,src_rowP,pLoadInfo->left,pLoadInfo->width,paletteP db_code1(DB_COMMA m_nPaletteSize)); + + // do the bottom row twice if the dd surface is bigger + if (pLoadInfo->bottom-1 == y && pLoadInfo->surface_height > pLoadInfo->height) + { + PtrUnion next_surface_rowP = pLoadInfo->surface_dataP; + next_surface_rowP.byteP += pLoadInfo->surface_pitch; + ConvertRow(next_surface_rowP,pLoadInfo->surface_width,src_rowP,pLoadInfo->left,pLoadInfo->width,paletteP db_code1(DB_COMMA m_nPaletteSize)); + } + + // next ddsurface row + if (reversed_rowsB) + pLoadInfo->surface_dataP.byteP -= pLoadInfo->surface_pitch; + else + pLoadInfo->surface_dataP.byteP += pLoadInfo->surface_pitch; + } + else if (pLoadInfo->surface_lockedB) + { + // unlock the surface + awTlLastDxErr = pLoadInfo->surfaceP->Unlock(NULL); + HANDLE_DXERROR("unlocking direct draw surface") + pLoadInfo->surface_lockedB = false; + } + } + } + + // next row + if (reversed_rowsB) + --y; + else + ++y; + + if (AW_TLE_OK != awTlLastErr) + { + db_log1("AwCreateGraphic() failed whilst copying data to direct draw surface"); + goto EXIT_WITH_ERROR; + } + } + + // create a palette for the surfaces if there is one + DWORD palcreateflags = 0; + PALETTEENTRY colour_tableA[256]; + if (pixelFormat.palettizedB) + { + if (!_parmsR.loadTextureB && !(fMyFlags & AW_TLF_TEXTURE)) + { + db_log3("AwCreateGraphic(): WARNING: setting a palette on a DD surface may have no effect"); + } + + #if 0 + if (m_bTranspMask) + { + colour_tableA[0].peRed = 0; + colour_tableA[0].peGreen = 0; + colour_tableA[0].peBlue = 0; + colour_tableA[0].peFlags = 0; + for (unsigned i=1; iCreatePalette(palcreateflags,colour_tableA,&dd_paletteP,NULL); + HANDLE_DXERROR("creating palette for direct draw surface") + } + + {for (unsigned i=0; iskipB) + { + // unlock the surface + if (pLoadInfo->surface_lockedB) + { + awTlLastDxErr = pLoadInfo->surfaceP->Unlock(NULL); + HANDLE_DXERROR("unlocking direct draw surface") + pLoadInfo->surface_lockedB = false; + } + + if (pixelFormat.palettizedB) + { + // set the palette on the surface + awTlLastDxErr = pLoadInfo->surfaceP->SetPalette(dd_paletteP); + HANDLE_DXERROR("setting palette on direct draw surface") + } + } + + }} + + if (pixelFormat.palettizedB) + { + db_logf5(("\tabout to release palette with ref %u",GetRefCount(dd_paletteP))); + dd_paletteP->Release(); + dd_paletteP = NULL; + } + + DWORD dwColourKey; + DDCOLORKEY invis; + // get colour for chroma keying if required + if (m_bTranspMask && (!pixelFormat.alphaB || fMyFlags & AW_TLF_CHROMAKEY)) + { + dwColourKey = GetTransparentColour(); + invis.dwColorSpaceLowValue = dwColourKey; + invis.dwColorSpaceHighValue = dwColourKey; + } + + {for (unsigned i=0; iskipB) + { + // do the copying crap and Texture::Load() stuff - see CopyD3DTexture in d3_func.cpp + + if (_parmsR.loadTextureB) + { + // get a texture pointer + awTlLastDxErr = pLoadInfo->surfaceP->QueryInterface(GUID_D3D_TEXTURE,(LPVOID *)&pLoadInfo->textureP); + HANDLE_DXERROR("getting texture interface on direct draw surface") + db_logf5(("\t\tnow surface ref %u texture ref %u",GetRefCount(pLoadInfo->surfaceP),GetRefCount(pLoadInfo->textureP))); + + if (fMyFlags & AW_TLF_COMPRESS) // deal with Texture::Load and ALLOCONLOAD flag + { + if (pLoadInfo->prevTexP.voidP) + { + // load into the existing texture + awTlLastDxErr = pLoadInfo->prevTexP.textureP->QueryInterface(GUID_DD_SURFACE,(LPVOID *)&pLoadInfo->dst_surfaceP); + HANDLE_DXERROR("getting direct draw surface interface") + db_logf5(("\t\tnow prev texture ref %u dst surface ref %u",GetRefCount(pLoadInfo->prevTexP.textureP),GetRefCount(pLoadInfo->dst_surfaceP))); + // check that the surface desc is OK + // note that SetSurfaceDesc is *only* supported for changing the surface memory pointer + DD_SURFACE_DESC old_ddsd; + INITDXSTRUCT(old_ddsd); + awTlLastDxErr = pLoadInfo->surfaceP->GetSurfaceDesc(&old_ddsd); + HANDLE_DXERROR("getting previous surface desc") + // check width, height, RGBBitCount and memory type + if (old_ddsd.dwFlags & DDSD_ALL || (old_ddsd.dwFlags & (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT)) == (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT)) + { + if (old_ddsd.dwHeight == pLoadInfo->surface_height && old_ddsd.dwWidth == pLoadInfo->surface_width && (old_ddsd.ddsCaps.dwCaps & (DDSCAPS_SYSTEMMEMORY|DDSCAPS_VIDEOMEMORY|DDSCAPS_TEXTURE)) == pLoadInfo->dwCapsCaps) + { + unsigned bpp = 0; + if (old_ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) + bpp = 8; + else if (old_ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) + bpp = 4; + else if (old_ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED2) + bpp = 2; + else if (old_ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED1) + bpp = 1; + else if (old_ddsd.ddpfPixelFormat.dwFlags & DDPF_RGB) + bpp = old_ddsd.ddpfPixelFormat.dwRGBBitCount; + if (pixelFormat.bitsPerPixel != bpp) + awTlLastErr = AW_TLE_CANTRELOAD; + } + else + awTlLastErr = AW_TLE_CANTRELOAD; + } + else + awTlLastErr = AW_TLE_CANTRELOAD; + if (AW_TLE_OK != awTlLastErr) + { + db_log1("AwCreateGraphic() failed because existing surface is incompatible"); + goto EXIT_WITH_ERROR; + } + } + else + { + DD_SURFACE_DESC ddsd; + + INITDXSTRUCT(ddsd); + + awTlLastDxErr = pLoadInfo->surfaceP->GetSurfaceDesc(&ddsd); + HANDLE_DXERROR("getting direct draw surface desc") + + ddsd.ddsCaps.dwCaps &= ~DDSCAPS_SYSTEMMEMORY; + ddsd.ddsCaps.dwCaps |= DDSCAPS_ALLOCONLOAD | driverDesc.memFlag; + do + { + awTlLastDxErr = driverDesc.ddP->CreateSurface(&ddsd,&pLoadInfo->dst_surfaceP,NULL); + } + while + ( + DDERR_OUTOFVIDEOMEMORY == awTlLastDxErr + && _parmsR.callbackF + && _parmsR.callbackF(_parmsR.callbackParam) + ); + HANDLE_DXERROR("creating destination direct draw surface") + } + + // create a zero palette if required -> Texture::Load() will copy in correct palette + if (pixelFormat.palettizedB) + { + memset(colour_tableA,0,sizeof colour_tableA); + + awTlLastDxErr = driverDesc.ddP->CreatePalette(palcreateflags,colour_tableA,&dd_paletteP,NULL); + HANDLE_DXERROR("creating palette for destination direct draw surface") + awTlLastDxErr = pLoadInfo->dst_surfaceP->SetPalette(dd_paletteP); + HANDLE_DXERROR("setting palette on destination direct draw surface") + db_logf5(("\tabout to release dest palette with ref %u",GetRefCount(dd_paletteP))); + dd_paletteP->Release(); + dd_paletteP = NULL; + } + + // get a texture pointer on the destination + awTlLastDxErr = pLoadInfo->dst_surfaceP->QueryInterface(GUID_D3D_TEXTURE,(LPVOID *)&pLoadInfo->dst_textureP); + HANDLE_DXERROR("getting texture interface on destination direct draw surface") + db_logf5(("\t\tnow dst surface ref %u dst texture ref %u",GetRefCount(pLoadInfo->dst_surfaceP),GetRefCount(pLoadInfo->dst_textureP))); + + do + { + awTlLastDxErr = pLoadInfo->dst_textureP->Load(pLoadInfo->textureP); + } + while + ( + DDERR_OUTOFVIDEOMEMORY == awTlLastDxErr + && _parmsR.callbackF + && _parmsR.callbackF(_parmsR.callbackParam) + ); + HANDLE_DXERROR("loading texture into destination") + + // release src texture and surface, and set pointers to point to dst texture and surface + db_logf5(("\tabout to release internal surface with ref %u",GetRefCount(pLoadInfo->surfaceP))); + db_code1(refcnt =) + pLoadInfo->surfaceP->Release(); + db_onlyassert1(1==refcnt); + pLoadInfo->surfaceP = pLoadInfo->dst_surfaceP; + pLoadInfo->dst_surfaceP = NULL; + + db_logf5(("\tabout to release internal texture i/f with ref %u",GetRefCount(pLoadInfo->textureP))); + db_code1(refcnt =) + pLoadInfo->textureP->Release(); + db_onlyassert1(!refcnt); + pLoadInfo->textureP = pLoadInfo->dst_textureP; + pLoadInfo->dst_textureP = NULL; + } + } + + // set chroma keying if required + if (m_bTranspMask && (!pixelFormat.alphaB || fMyFlags & AW_TLF_CHROMAKEY)) + { + awTlLastDxErr = pLoadInfo->surfaceP->SetColorKey(DDCKEY_SRCBLT,&invis); + HANDLE_DXERROR("setting the colour key") + } + + if (_parmsR.loadTextureB) + { + // release the direct draw interface: + // since the textureP was obtained with a call + // to QueryInterface on the surface (increasing + // its referenc count), this wont actually release + // the surface + + db_logf5(("\tabout to release surface i/f with ref %u",GetRefCount(pLoadInfo->surfaceP))); + db_code1(refcnt =) + pLoadInfo->surfaceP->Release(); + pLoadInfo->surfaceP = NULL; + // if loading into a previous texture, refcnt may be two or more, our ref and the ref passed to us + db_onlyassert1(1==refcnt|| pLoadInfo->prevTexP.voidP); + + pLoadInfo->resultP = pLoadInfo->textureP; + } + else + { + db_assert1(pLoadInfo->surfaceP); + + DDSurface * pSurfaceReturn = NULL; + + awTlLastDxErr = pLoadInfo->surfaceP->QueryInterface(GUID_DD_SURFACE, (LPVOID *)&pSurfaceReturn); + HANDLE_DXERROR("getting the required DDSurface interface") + db_logf5(("\t\tnow surface ref %u return surface ref %u",GetRefCount(pLoadInfo->surfaceP),GetRefCount(pSurfaceReturn))); + + pLoadInfo->resultP = pSurfaceReturn; + } + } + }} + + // release the IDirectDrawSurface interfaces if returning DDSurface interfaces + if (!_parmsR.loadTextureB) + { + for (unsigned i=0; iRelease(); + } + } + } + } + + // OK + db_log4("AwCreateGraphic() OK"); + + SurfUnion pRet = static_cast(NULL); + + if (!_parmsR.rectA) + { + // if loading the entire graphic as one surface/texture, return pointer to that + pRet = arrLoadInfo[0].resultP; + } + else + { + // return NULL, but fill in the pTexture or pSurface members of the AwCreateGraphicRegion + for (unsigned i=0; irectP); + + if (_parmsR.loadTextureB) + { + if (pLoadInfo->prevTexP.voidP) + { + db_assert1(pLoadInfo->prevTexP.textureP == pLoadInfo->rectP->pTexture); + db_assert1(pLoadInfo->resultP.textureP == pLoadInfo->rectP->pTexture); + db_logf5(("\tabout to release duplicate texture i/f with ref %u",GetRefCount(pLoadInfo->resultP.textureP))); + pLoadInfo->resultP.textureP->Release(); + } + else + { + pLoadInfo->rectP->pTexture = pLoadInfo->resultP.textureP; + } + db_logf5(("\tresultant texture for region with ref count %u",GetRefCount(pLoadInfo->rectP->pTexture))); + } + else + { + if (pLoadInfo->prevTexP.voidP) + { + db_assert1(pLoadInfo->prevTexP.surfaceP == pLoadInfo->rectP->pSurface); + db_assert1(pLoadInfo->resultP.surfaceP == pLoadInfo->rectP->pSurface); + db_logf5(("\tabout to release duplicate surface i/f with ref %u",GetRefCount(pLoadInfo->resultP.surfaceP))); + pLoadInfo->resultP.surfaceP->Release(); + } + else + { + pLoadInfo->rectP->pSurface = pLoadInfo->resultP.surfaceP; + } + db_logf5(("\tresultant texture for surface with ref count %u",GetRefCount(pLoadInfo->rectP->pSurface))); + } + } + } + delete[] arrLoadInfo; + + #if DB_LEVEL >= 5 + if (_parmsR.loadTextureB) + db_logf5(("AwCreateGraphic(): returning texture with ref cnt %u",GetRefCount(pRet.textureP))); + else + db_logf5(("AwCreateGraphic(): returning surface with ref cnt %u",GetRefCount(pRet.surfaceP))); + #endif + + return pRet; + } + + EXIT_WITH_ERROR: + { + + db_logf2(("AwCreateGraphic(): ERROR: %s",AwTlErrorToString())); + + if (arrLoadInfo) + { + for (unsigned i=0; idst_textureP), + GetRefCount(pLoadInfo->dst_surfaceP), + GetRefCount(pLoadInfo->textureP), + GetRefCount(pLoadInfo->surfaceP))); + + if (pLoadInfo->dst_textureP) + { + pLoadInfo->dst_textureP->Release(); + } + if (pLoadInfo->textureP) + { + pLoadInfo->textureP->Release(); + } + if (pLoadInfo->dst_surfaceP) + { + pLoadInfo->dst_surfaceP->Release(); + } + if (pLoadInfo->surfaceP) + { + if (pLoadInfo->surface_lockedB) + pLoadInfo->surfaceP->Unlock(NULL); + db_code1(refcnt =) + pLoadInfo->surfaceP->Release(); + db_onlyassert1(!refcnt); + } + + if (pLoadInfo->rectP) + { + pLoadInfo->rectP->width = 0; + pLoadInfo->rectP->height = 0; + } + } + + delete[] arrLoadInfo; + } + + if (dd_paletteP) + { + db_code1(refcnt =) + dd_paletteP->Release(); + db_onlyassert1(!refcnt); + } + + return static_cast(NULL); + } +} + +void AwBackupTexture::OnBeginRestoring(unsigned nMaxPaletteSize) +{ + if (nMaxPaletteSize && (nMaxPaletteSize < m_nPaletteSize || !m_nPaletteSize)) + { + awTlLastErr = AW_TLE_CANTPALETTIZE; + db_logf3(("AwCreateGraphic(): [restoring] ERROR: Palette size is %u, require %u",m_nPaletteSize,nMaxPaletteSize)); + } +} + +bool AwBackupTexture::AreRowsReversed() +{ + return false; +} + +void AwBackupTexture::ConvertRow(AwTl::PtrUnion pDest, unsigned nDestWidth, AwTl::PtrUnionConst pSrc, unsigned nSrcOffset, unsigned nSrcWidth, AwTl::Colour * pPalette db_code1(DB_COMMA unsigned nPaletteSize)) +{ + using namespace AwTl; + + if (pPalette) + { + if (pixelFormat.palettizedB) + { + GenericConvertRow::Do(pDest,nDestWidth,pSrc.byteP+nSrcOffset,nSrcWidth); + } + else + { + if (m_bTranspMask) + GenericConvertRow::Do(pDest,nDestWidth,pSrc.byteP+nSrcOffset,nSrcWidth,pPalette db_code1(DB_COMMA nPaletteSize)); + else + GenericConvertRow::Do(pDest,nDestWidth,pSrc.byteP+nSrcOffset,nSrcWidth,pPalette db_code1(DB_COMMA nPaletteSize)); + } + } + else + { + if (m_bTranspMask) + GenericConvertRow::Do(pDest,nDestWidth,pSrc.colourP+nSrcOffset,nSrcWidth); + else + GenericConvertRow::Do(pDest,nDestWidth,pSrc.colourP+nSrcOffset,nSrcWidth); + } +} + +void AwBackupTexture::OnFinishRestoring(bool) +{ +} + +namespace AwTl { + + Colour * TypicalBackupTexture::GetPalette() + { + return m_pPalette; + } + + PtrUnion TypicalBackupTexture::GetRowPtr(unsigned nRow) + { + return m_ppPixMap[nRow]; + } + + void TypicalBackupTexture::LoadNextRow(PtrUnion) + { + // already loaded + } + + unsigned TypicalBackupTexture::GetNumColours() + { + return m_nPaletteSize; + } + + unsigned TypicalBackupTexture::GetMinPaletteSize() + { + return m_nPaletteSize; + } + + + SurfUnion TexFileLoader::Load(MediaMedium * pMedium, CreateTextureParms const & rParams) + { + m_fFlags = rParams.flags; + + awTlLastErr = AW_TLE_OK; + + LoadHeaderInfo(pMedium); + + CHECK_MEDIA_ERRORS("loading file headers") + ON_ERROR_RETURN_NULL("loading file headers") + + ChoosePixelFormat(rParams); + + if (!pixelFormat.validB) + db_log3("AwCreateGraphic(): ERROR: pixel format not valid"); + if (!driverDesc.ddP || !driverDesc.validB && rParams.loadTextureB) + db_log3("AwCreateGraphic(): ERROR: driver description not valid"); + + awTlLastErr = pixelFormat.validB && driverDesc.ddP && (driverDesc.validB || !rParams.loadTextureB) ? AW_TLE_OK : AW_TLE_NOINIT; + + ON_ERROR_RETURN_NULL("initializing load") + + AllocateBuffers(rParams.backupHP ? true : false, pixelFormat.palettizedB ? 1<Release(); + else + pTex.surfaceP->Release(); + pTex.voidP = NULL; + } + else + { + db_assert1(rParams.rectA); + + for (unsigned i=0; ipTexture->Release(); + else + pRect->pSurface->Release(); + } + pRect->width = 0; + pRect->height = 0; + } + } + db_logf1(("AwCreateGraphic(): ERROR: %s",AwTlErrorToString())); + bOK = false; + } + + OnFinishLoading(bOK); + + if (bOK && rParams.backupHP) + { + *rParams.backupHP = CreateBackupTexture(); + } + + return pTex; + } + + void TexFileLoader::OnFinishLoading(bool) + { + } + + + TypicalTexFileLoader::~TypicalTexFileLoader() + { + if (m_pPalette) + { + delete[] m_pPalette; + + if (m_pRowBuf) delete[] m_pRowBuf.byteP; + if (m_ppPixMap) + { + delete[] m_ppPixMap->byteP; + delete[] m_ppPixMap; + } + } + else + { + if (m_pRowBuf) delete[] m_pRowBuf.colourP; + if (m_ppPixMap) + { + delete[] m_ppPixMap->colourP; + delete[] m_ppPixMap; + } + } + } + + unsigned TypicalTexFileLoader::GetNumColours() + { + return m_nPaletteSize; + } + + unsigned TypicalTexFileLoader::GetMinPaletteSize() + { + return m_nPaletteSize; + } + + void TypicalTexFileLoader::AllocateBuffers(bool bWantBackup, unsigned /*nMaxPaletteSize*/) + { + if (m_nPaletteSize) + { + m_pPalette = new Colour [ m_nPaletteSize ]; + } + + if (bWantBackup) + { + m_ppPixMap = new PtrUnion [m_nHeight]; + if (m_nPaletteSize) + { + m_ppPixMap->byteP = new BYTE [m_nHeight*m_nWidth]; + BYTE * pRow = m_ppPixMap->byteP; + for (unsigned y=1;ycolourP = new Colour [m_nHeight*m_nWidth]; + Colour * pRow = m_ppPixMap->colourP; + for (unsigned y=1;y(&rlcAwBmpLoader_187); + + mfidt.hack += reinterpret_cast(&rlcAwIffLoader_428); + mfidt.hack += reinterpret_cast(&rlcAwIffLoader_429); + mfidt.hack += reinterpret_cast(&rlcAwIffLoader_430); + + mfidt.hack += reinterpret_cast(&rlcAwPpmLoader_229); + mfidt.hack += reinterpret_cast(&rlcAwPgmLoader_230); + mfidt.hack += reinterpret_cast(&rlcAwPbmLoader_231); + + mfidt.hack += reinterpret_cast(&rccIlbmBmhdChunk_4); + mfidt.hack += reinterpret_cast(&rccIlbmCmapChunk_5); + mfidt.hack += reinterpret_cast(&rccIlbmBodyChunk_6); + mfidt.hack += reinterpret_cast(&rccIlbmGrabChunk_7); + } +#endif + g_pMagicFileIdTree = &mfidt; + + MagicFileIdTree * pLayer = g_pMagicFileIdTree; + + while (*pszMagic) + { + BYTE c = static_cast(*pszMagic++); + + if (!pLayer->m_arrNextLayer[c]) + pLayer->m_arrNextLayer[c] = new MagicFileIdTree; + + pLayer = pLayer->m_arrNextLayer[c]; + } + + db_assert1(!pLayer->m_pfnCreate); + + pLayer->m_pfnCreate = pfnCreate; + } + + static + TexFileLoader * CreateLoaderObject(MediaMedium * pMedium) + { + TexFileLoader * (* pfnBest) () = NULL; + + signed nMoveBack = 0; + + BYTE c; + + MagicFileIdTree * pLayer = g_pMagicFileIdTree; + + while (pLayer) + { + if (pLayer->m_pfnCreate) + pfnBest = pLayer->m_pfnCreate; + + MediaRead(pMedium,&c); + + -- nMoveBack; + + pLayer = pLayer->m_arrNextLayer[c]; + } + + pMedium->MovePos(nMoveBack); + + if (pfnBest) + return pfnBest(); + else + return NULL; + } + + /**********************************/ + /* These are the loader functions */ + /**********************************/ + + static inline SurfUnion DoLoadTexture(MediaMedium * pMedium, CreateTextureParms const & rParams) + { + TexFileLoader * pLoader = CreateLoaderObject(pMedium); + + if (!pLoader) + { + awTlLastErr = AW_TLE_BADFILEFORMAT; + db_log1("AwCreateGraphic(): ERROR: file format not recognized"); + return static_cast(NULL); + } + else + { + SurfUnion pTex = pLoader->Load(pMedium,rParams); + pLoader->Release(); + return pTex; + } + } + + static inline SurfUnion LoadTexture(MediaMedium * pMedium, CreateTextureParms const & _parmsR) + { + if (_parmsR.bytesReadP||_parmsR.maxReadBytes!=UINT_MAX) + { + MediaSection * pMedSect = new MediaSection; + pMedSect->Open(pMedium,_parmsR.maxReadBytes); + SurfUnion pTex = DoLoadTexture(pMedSect,_parmsR); + pMedSect->Close(); + if (_parmsR.bytesReadP) *_parmsR.bytesReadP = pMedSect->GetUsedSize(); + delete pMedSect; + return pTex; + } + else + { + return DoLoadTexture(pMedium,_parmsR); + } + } + + SurfUnion CreateTextureParms::DoCreate() const + { + if (INVALID_HANDLE_VALUE!=fileH) + { + MediaWinFileMedium * pMedium = new MediaWinFileMedium; + pMedium->Attach(fileH); + SurfUnion pTex = LoadTexture(pMedium,*this); + pMedium->Detach(); + pMedium->Release(); + return pTex; + } + else if (dataP) + { + MediaMemoryReadMedium * pMedium = new MediaMemoryReadMedium; + pMedium->Open(dataP); + SurfUnion pTex = LoadTexture(pMedium,*this); + pMedium->Close(); + pMedium->Release(); + return pTex; + } + else + { + db_assert1(restoreH); + return restoreH->Restore(*this); + } + } + + #if DB_LEVEL >= 4 + static void LogPrimCaps(LPD3DPRIMCAPS _pcP, bool _triB) + { + #define DEVCAP(mask,can_or_does,explanation) \ + db_logf4(("\t\t" can_or_does "%s " explanation, _pcP->MEMBER & (mask) ? "" : "not")); + + #define MEMBER dwMiscCaps + DEVCAP(D3DPMISCCAPS_CONFORMANT,"Does ","conform to OpenGL standard") + if (_triB) + { + DEVCAP(D3DPMISCCAPS_CULLCCW,"Does ","support counterclockwise culling through the D3DRENDERSTATE_CULLMODE state") + DEVCAP(D3DPMISCCAPS_CULLCW,"Does ","support clockwise triangle culling through the D3DRENDERSTATE_CULLMODE state") + db_logf4(("\t\tDoes %s perform triangle culling", _pcP->dwMiscCaps & (D3DPMISCCAPS_CULLNONE) ? "not" : "")); + } + else + { + DEVCAP(D3DPMISCCAPS_LINEPATTERNREP,"Can","handle values other than 1 in the wRepeatFactor member of the D3DLINEPATTERN structure") + } + DEVCAP(D3DPMISCCAPS_MASKPLANES,"Can","perform a bitmask of color planes") + DEVCAP(D3DPMISCCAPS_MASKZ,"Can","enable and disable modification of the z-buffer on pixel operations") + #undef MEMBER + #define MEMBER dwRasterCaps + DEVCAP(D3DPRASTERCAPS_ANISOTROPY,"Does ","support anisotropic filtering") + DEVCAP(D3DPRASTERCAPS_ANTIALIASEDGES,"Can","antialias lines forming the convex outline of objects") + DEVCAP(D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT,"Does","support antialiasing that is dependent on the sort order of the polygons") + DEVCAP(D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT,"Does","support antialiasing that is not dependent on the sort order of the polygons") + DEVCAP(D3DPRASTERCAPS_DITHER,"Can","dither to improve color resolution") + DEVCAP(D3DPRASTERCAPS_FOGRANGE,"Does ","support range-based fog") + DEVCAP(D3DPRASTERCAPS_FOGTABLE,"Does ","calculate the fog value by referring to a lookup table containing fog values that are indexed to the depth of a given pixel") + DEVCAP(D3DPRASTERCAPS_FOGVERTEX,"Does ","calculate the fog value during the lighting operation") + DEVCAP(D3DPRASTERCAPS_MIPMAPLODBIAS,"Does ","support level-of-detail (LOD) bias adjustments") + DEVCAP(D3DPRASTERCAPS_PAT,"Can","perform patterned drawing for the primitive being queried") + DEVCAP(D3DPRASTERCAPS_ROP2,"Can","support raster operations other than R2_COPYPEN") + DEVCAP(D3DPRASTERCAPS_STIPPLE,"Can","stipple polygons to simulate translucency") + DEVCAP(D3DPRASTERCAPS_SUBPIXEL,"Does ","perform subpixel placement of z, color, and texture data, rather than working with the nearest integer pixel coordinate") + DEVCAP(D3DPRASTERCAPS_SUBPIXELX,"Is ","subpixel accurate along the x-axis only and is clamped to an integer y-axis scan line") + DEVCAP(D3DPRASTERCAPS_XOR,"Can","support XOR operations") + DEVCAP(D3DPRASTERCAPS_ZBIAS,"Does ","support z-bias values") + DEVCAP(D3DPRASTERCAPS_ZBUFFERLESSHSR,"Can","perform hidden-surface removal without requiring the application to sort polygons, and without requiring the allocation of a z-buffer") + DEVCAP(D3DPRASTERCAPS_ZTEST,"Can","perform z-test operations") + #undef MEMBER + #define MEMBER dwZCmpCaps + DEVCAP(D3DPCMPCAPS_ALWAYS,"Can","always pass the z test") + DEVCAP(D3DPCMPCAPS_EQUAL,"Can","pass the z test if the new z equals the current z") + DEVCAP(D3DPCMPCAPS_GREATER,"Can","pass the z test if the new z is greater than the current z") + DEVCAP(D3DPCMPCAPS_GREATEREQUAL,"Can","pass the z test if the new z is greater than or equal to the current z") + DEVCAP(D3DPCMPCAPS_LESS,"Can","pass the z test if the new z is less than the current z") + DEVCAP(D3DPCMPCAPS_LESSEQUAL,"Can","pass the z test if the new z is less than or equal to the current z") + DEVCAP(D3DPCMPCAPS_NEVER,"Can","always fail the z test") + DEVCAP(D3DPCMPCAPS_NOTEQUAL,"Can","pass the z test if the new z does not equal the current z") + #undef MEMBER + #define MEMBER dwSrcBlendCaps + DEVCAP(D3DPBLENDCAPS_BOTHINVSRCALPHA,"Can","source blend with source blend factor of (1-As, 1-As, 1-As, 1-As) and destination blend factor of (As, As, As, As); the destination blend selection is overridden") + DEVCAP(D3DPBLENDCAPS_BOTHSRCALPHA,"Can","source blend with source blend factor of (As, As, As, As) and destination blend factor of (1-As, 1-As, 1-As, 1-As); the destination blend selection is overridden") + DEVCAP(D3DPBLENDCAPS_DESTALPHA,"Can","source blend with blend factor of (Ad, Ad, Ad, Ad)") + DEVCAP(D3DPBLENDCAPS_DESTCOLOR,"Can","source blend with blend factor of (Rd, Gd, Bd, Ad)") + DEVCAP(D3DPBLENDCAPS_INVDESTALPHA,"Can","source blend with blend factor of (1-Ad, 1-Ad, 1-Ad, 1-Ad)") + DEVCAP(D3DPBLENDCAPS_INVDESTCOLOR,"Can","source blend with blend factor of (1-Rd, 1-Gd, 1-Bd, 1-Ad)") + DEVCAP(D3DPBLENDCAPS_INVSRCALPHA,"Can","source blend with blend factor of (1-As, 1-As, 1-As, 1-As)") + DEVCAP(D3DPBLENDCAPS_INVSRCCOLOR,"Can","source blend with blend factor of (1-Rd, 1-Gd, 1-Bd, 1-Ad)") + DEVCAP(D3DPBLENDCAPS_ONE,"Can","source blend with blend factor of (1, 1, 1, 1)") + DEVCAP(D3DPBLENDCAPS_SRCALPHA,"Can","source blend with blend factor of (As, As, As, As)") + DEVCAP(D3DPBLENDCAPS_SRCALPHASAT,"Can","source blend with blend factor of (f, f, f, 1); f = min(As, 1-Ad).") + DEVCAP(D3DPBLENDCAPS_SRCCOLOR,"Can","source blend with blend factor of (Rs, Gs, Bs, As)") + DEVCAP(D3DPBLENDCAPS_ZERO,"Can","source blend with blend factor of (0, 0, 0, 0)") + #undef MEMBER + #define MEMBER dwDestBlendCaps + DEVCAP(D3DPBLENDCAPS_BOTHINVSRCALPHA,"Can","destination blend with source blend factor of (1-As, 1-As, 1-As, 1-As) and destination blend factor of (As, As, As, As); the destination blend selection is overridden") + DEVCAP(D3DPBLENDCAPS_BOTHSRCALPHA,"Can","destination blend with source blend factor of (As, As, As, As) and destination blend factor of (1-As, 1-As, 1-As, 1-As); the destination blend selection is overridden") + DEVCAP(D3DPBLENDCAPS_DESTALPHA,"Can","destination blend with blend factor of (Ad, Ad, Ad, Ad)") + DEVCAP(D3DPBLENDCAPS_DESTCOLOR,"Can","destination blend with blend factor of (Rd, Gd, Bd, Ad)") + DEVCAP(D3DPBLENDCAPS_INVDESTALPHA,"Can","destination blend with blend factor of (1-Ad, 1-Ad, 1-Ad, 1-Ad)") + DEVCAP(D3DPBLENDCAPS_INVDESTCOLOR,"Can","destination blend with blend factor of (1-Rd, 1-Gd, 1-Bd, 1-Ad)") + DEVCAP(D3DPBLENDCAPS_INVSRCALPHA,"Can","destination blend with blend factor of (1-As, 1-As, 1-As, 1-As)") + DEVCAP(D3DPBLENDCAPS_INVSRCCOLOR,"Can","destination blend with blend factor of (1-Rd, 1-Gd, 1-Bd, 1-Ad)") + DEVCAP(D3DPBLENDCAPS_ONE,"Can","destination blend with blend factor of (1, 1, 1, 1)") + DEVCAP(D3DPBLENDCAPS_SRCALPHA,"Can","destination blend with blend factor of (As, As, As, As)") + DEVCAP(D3DPBLENDCAPS_SRCALPHASAT,"Can","destination blend with blend factor of (f, f, f, 1); f = min(As, 1-Ad)") + DEVCAP(D3DPBLENDCAPS_SRCCOLOR,"Can","destination blend with blend factor of (Rs, Gs, Bs, As)") + DEVCAP(D3DPBLENDCAPS_ZERO,"Can","destination blend with blend factor of (0, 0, 0, 0)") + #undef MEMBER + #define MEMBER dwAlphaCmpCaps + DEVCAP(D3DPCMPCAPS_ALWAYS,"Can","always pass the alpha test") + DEVCAP(D3DPCMPCAPS_EQUAL,"Can","pass the alpha test if the new alpha equals the current alpha") + DEVCAP(D3DPCMPCAPS_GREATER,"Can","pass the alpha test if the new alpha is greater than the current alpha") + DEVCAP(D3DPCMPCAPS_GREATEREQUAL,"Can","pass the alpha test if the new alpha is greater than or equal to the current alpha") + DEVCAP(D3DPCMPCAPS_LESS,"Can","pass the alpha test if the new alpha is less than the current alpha") + DEVCAP(D3DPCMPCAPS_LESSEQUAL,"Can","pass the alpha test if the new alpha is less than or equal to the current alpha") + DEVCAP(D3DPCMPCAPS_NEVER,"Can","always fail the alpha test") + DEVCAP(D3DPCMPCAPS_NOTEQUAL,"Can","pass the alpha test if the new alpha does not equal the current alpha") + #undef MEMBER + #define MEMBER dwShadeCaps + DEVCAP(D3DPSHADECAPS_ALPHAFLATBLEND,"Can","support an alpha component for flat blended transparency") + DEVCAP(D3DPSHADECAPS_ALPHAFLATSTIPPLED,"Can","support an alpha component for flat stippled transparency") + DEVCAP(D3DPSHADECAPS_ALPHAGOURAUDBLEND,"Can","support an alpha component for Gouraud blended transparency") + DEVCAP(D3DPSHADECAPS_ALPHAGOURAUDSTIPPLED,"Can","support an alpha component for Gouraud stippled transparency") + DEVCAP(D3DPSHADECAPS_ALPHAPHONGBLEND,"Can","support an alpha component for Phong blended transparency") + DEVCAP(D3DPSHADECAPS_ALPHAPHONGSTIPPLED,"Can","support an alpha component for Phong stippled transparency") + DEVCAP(D3DPSHADECAPS_COLORFLATMONO,"Can","support colored flat shading in the D3DCOLOR_MONO color model") + DEVCAP(D3DPSHADECAPS_COLORFLATRGB,"Can","support colored flat shading in the D3DCOLOR_RGB color model") + DEVCAP(D3DPSHADECAPS_COLORGOURAUDMONO,"Can","support colored flat shading in the D3DCOLOR_MONO color model") + DEVCAP(D3DPSHADECAPS_COLORGOURAUDRGB,"Can","support colored Gouraud shading in the D3DCOLOR_RGB color model") + DEVCAP(D3DPSHADECAPS_COLORPHONGMONO,"Can","support colored Phong shading in the D3DCOLOR_MONO color model") + DEVCAP(D3DPSHADECAPS_COLORPHONGRGB,"Can","support colored Phong shading in the D3DCOLOR_RGB color model") + DEVCAP(D3DPSHADECAPS_FOGFLAT,"Can","support fog in the flat shading model") + DEVCAP(D3DPSHADECAPS_FOGGOURAUD,"Can","support fog in the Gouraud shading model") + DEVCAP(D3DPSHADECAPS_FOGPHONG,"Can","support fog in the Phong shading model") + DEVCAP(D3DPSHADECAPS_SPECULARFLATMONO,"Can","support specular highlights in flat shading in the D3DCOLOR_MONO color model") + DEVCAP(D3DPSHADECAPS_SPECULARFLATRGB,"Can","support specular highlights in flat shading in the D3DCOLOR_RGB color model") + DEVCAP(D3DPSHADECAPS_SPECULARGOURAUDMONO,"Can","support specular highlights in Gouraud shading in the D3DCOLOR_MONO color model") + DEVCAP(D3DPSHADECAPS_SPECULARGOURAUDRGB,"Can","support specular highlights in Gouraud shading in the D3DCOLOR_RGB color model") + DEVCAP(D3DPSHADECAPS_SPECULARPHONGMONO,"Can","support specular highlights in Phong shading in the D3DCOLOR_MONO color model") + DEVCAP(D3DPSHADECAPS_SPECULARPHONGRGB,"Can","support specular highlights in Phong shading in the D3DCOLOR_RGB color model") + #undef MEMBER + #define MEMBER dwTextureCaps + DEVCAP(D3DPTEXTURECAPS_ALPHA,"Does ","support RGBA textures in the D3DTEX_DECAL and D3DTEX_MODULATE texture filtering modes") + DEVCAP(D3DPTEXTURECAPS_BORDER,"Does ","support texture mapping along borders") + DEVCAP(D3DPTEXTURECAPS_PERSPECTIVE,"Does ","support perspective correction") + DEVCAP(D3DPTEXTURECAPS_POW2,"Does ","require all nonmipmapped textures to have widths and heights specified as powers of two") + DEVCAP(D3DPTEXTURECAPS_SQUAREONLY,"Does ","require all textures to be square") + DEVCAP(D3DPTEXTURECAPS_TRANSPARENCY,"Does ","support texture transparency") + #undef MEMBER + #define MEMBER dwTextureFilterCaps + DEVCAP(D3DPTFILTERCAPS_LINEAR,"Can","use a weighted average of a 2x2 area of texels surrounding the desired pixel") + DEVCAP(D3DPTFILTERCAPS_LINEARMIPLINEAR,"Can","use a weighted average of a 2x2 area of texels, and also interpolate between mipmaps") + DEVCAP(D3DPTFILTERCAPS_LINEARMIPNEAREST,"Can","use a weighted average of a 2x2 area of texels, and also use a mipmap") + DEVCAP(D3DPTFILTERCAPS_MIPLINEAR,"Can","choose two mipmaps whose texels most closely match the size of the pixel to be textured, and interpolate between them") + DEVCAP(D3DPTFILTERCAPS_MIPNEAREST,"Can","use an appropriate mipmap for texel selection") + DEVCAP(D3DPTFILTERCAPS_NEAREST,"Can","use the texel with coordinates nearest to the desired pixel value is used") + #undef MEMBER + #define MEMBER dwTextureBlendCaps + DEVCAP(D3DPTBLENDCAPS_ADD,"Can","use the additive texture-blending mode") + DEVCAP(D3DPTBLENDCAPS_COPY,"Can","use copy mode texture-blending") + DEVCAP(D3DPTBLENDCAPS_DECAL,"Can","use decal texture-blending mode") + DEVCAP(D3DPTBLENDCAPS_DECALALPHA,"Can","use decal-alpha texture-blending mode") + DEVCAP(D3DPTBLENDCAPS_DECALMASK,"Can","use decal-mask texture-blending mode") + DEVCAP(D3DPTBLENDCAPS_MODULATE,"Can","use modulate texture-blending mode") + DEVCAP(D3DPTBLENDCAPS_MODULATEALPHA,"Can","use modulate-alpha texture-blending mode") + DEVCAP(D3DPTBLENDCAPS_MODULATEMASK,"Can","use modulate-mask texture-blending mode") + #undef MEMBER + #define MEMBER dwTextureAddressCaps + DEVCAP(D3DPTADDRESSCAPS_BORDER,"Does ","support setting coordinates outside the range [0.0, 1.0] to the border color") + DEVCAP(D3DPTADDRESSCAPS_CLAMP,"Can","clamp textures to addresses") + DEVCAP(D3DPTADDRESSCAPS_INDEPENDENTUV,"Can","separate the texture-addressing modes of the U and V coordinates of the texture") + DEVCAP(D3DPTADDRESSCAPS_MIRROR,"Can","mirror textures to addresses") + DEVCAP(D3DPTADDRESSCAPS_WRAP,"Can","wrap textures to addresses") + #undef MEMBER + #undef DEVCAP + db_logf4(("\t\tMaximum size of the supported stipple is %u x %u",_pcP->dwStippleWidth,_pcP->dwStippleHeight)); + } + static void LogCaps(LPD3DDEVICEDESC _descP) + { + if (_descP->dwFlags & D3DDD_BCLIPPING) + { + db_logf4(("\tCan%s perform 3D clipping",_descP->bClipping ? "" : "not")); + } + else db_log4("\tHas unknown 3D clipping capability"); + + if (_descP->dwFlags & D3DDD_COLORMODEL) + { + db_logf4(("\tCan%s use mono (ramp) colour model",_descP->dcmColorModel & D3DCOLOR_MONO ? "" : "not")); + db_logf4(("\tCan%s use full RGB colour model",_descP->dcmColorModel & D3DCOLOR_RGB ? "" : "not")); + } + else db_log4("\tHas unknown colour model"); + + if (_descP->dwFlags & D3DDD_DEVCAPS) + { + #define DEVCAP(mask,can_or_does,explanation) \ + db_logf4(("\t" can_or_does "%s " explanation,_descP->dwDevCaps & (mask) ? "" : "not")); + + DEVCAP(D3DDEVCAPS_CANRENDERAFTERFLIP,"Can","queue rendering commands after a page flip") + DEVCAP(D3DDEVCAPS_DRAWPRIMTLVERTEX,"Does ","export a DrawPrimitive-aware HAL") + DEVCAP(D3DDEVCAPS_EXECUTESYSTEMMEMORY,"Can","use execute buffers from system memory") + DEVCAP(D3DDEVCAPS_EXECUTEVIDEOMEMORY,"Can","use execute buffer from video memory") + DEVCAP(D3DDEVCAPS_FLOATTLVERTEX,"Does ","accept floating point for post-transform vertex data") + DEVCAP(D3DDEVCAPS_SORTDECREASINGZ,"Does ","need Z data sorted for decreasing depth") + DEVCAP(D3DDEVCAPS_SORTEXACT,"Does ","need data sorted exactly") + DEVCAP(D3DDEVCAPS_SORTINCREASINGZ,"Does ","need data sorted for increasing depth") + DEVCAP(D3DDEVCAPS_TEXTURENONLOCALVIDMEM,"Can","retrieve textures from nonlocal video (AGP) memory") + DEVCAP(D3DDEVCAPS_TEXTURESYSTEMMEMORY,"Can","retrieve textures from system memory") + DEVCAP(D3DDEVCAPS_TEXTUREVIDEOMEMORY,"Can","retrieve textures from device memory") + DEVCAP(D3DDEVCAPS_TLVERTEXSYSTEMMEMORY,"Can","use buffers from system memory for transformed and lit vertices") + DEVCAP(D3DDEVCAPS_TLVERTEXVIDEOMEMORY,"Can","use buffers from video memory for transformed and lit vertices") + + #undef DEVCAP + } + else db_log4("\tHas unknown device capabilities"); + + if (_descP->dwFlags & D3DDD_DEVICERENDERBITDEPTH) + { + #define DEVCAP(mask,explanation) \ + db_logf4(("\tCan%s render to "explanation" surface",_descP->dwDeviceRenderBitDepth & (mask) ? "" : "not")); + + DEVCAP(DDBD_8,"an 8-bit") + DEVCAP(DDBD_16,"a 16-bit") + DEVCAP(DDBD_24,"a 24-bit") + DEVCAP(DDBD_32,"a 32-bit") + + #undef DEVCAP + } + else db_log4("\tHas unknown rendering target bitdepth requirements"); + + if (_descP->dwFlags & D3DDD_DEVICEZBUFFERBITDEPTH) + { + #define DEVCAP(mask,explanation) \ + db_logf4(("\tCan%s use "explanation" Z-buffer",_descP->dwDeviceZBufferBitDepth & (mask) ? "" : "not")); + + DEVCAP(DDBD_8,"an 8-bit") + DEVCAP(DDBD_16,"a 16-bit") + DEVCAP(DDBD_24,"a 24-bit") + DEVCAP(DDBD_32,"a 32-bit") + + #undef DEVCAP + } + else db_log4("\tHas unknown Z-buffer bitdepth requirements"); + + if (_descP->dwFlags & D3DDD_TRANSFORMCAPS) + { + db_log4("\tTransform capabilities are known"); + } + else db_log4("\tHas unknown transform capabilities"); + + if (_descP->dwFlags & D3DDD_LIGHTINGCAPS) + { + db_log4("\tLighting capabilities are known"); + } + else db_log4("\tHas unknown lighting capabilities"); + + if (_descP->dwFlags & D3DDD_LINECAPS) + { + db_log4("\tLine drawing capabilities follow"); + LogPrimCaps(&_descP->dpcLineCaps,false); + } + else db_log4("\tHas unknown line drawing capabilities"); + + if (_descP->dwFlags & D3DDD_TRICAPS) + { + db_log4("\tTriangle rendering capabilities follow"); + LogPrimCaps(&_descP->dpcTriCaps,true); + } + else db_log4("\tHas unknown triangle rendering capabilities"); + + if (_descP->dwFlags & D3DDD_MAXBUFFERSIZE) + { + unsigned max_exb = _descP->dwMaxBufferSize; + if (!max_exb) max_exb = UINT_MAX; + db_logf4(("\tMaximum execute buffer size is %u",max_exb)); + } + else db_log4("\tHas unknown maximum execute buffer size"); + + if (_descP->dwFlags & D3DDD_MAXVERTEXCOUNT) + { + db_logf4(("\tMaximum vertex count is %u",_descP->dwMaxVertexCount)); + } + else db_log4("\tHas unknown maximum vertex count"); + + unsigned max_tw = _descP->dwMaxTextureWidth; + unsigned max_th = _descP->dwMaxTextureHeight; + unsigned max_sw = _descP->dwMaxStippleWidth; + unsigned max_sh = _descP->dwMaxStippleHeight; + if (!max_tw) max_tw = UINT_MAX; + if (!max_th) max_th = UINT_MAX; + if (!max_sw) max_sw = UINT_MAX; + if (!max_sh) max_sh = UINT_MAX; + + db_logf4(("\tMinimum texture size is %u x %u",_descP->dwMinTextureWidth,_descP->dwMinTextureHeight)); + db_logf4(("\tMaximum texture size is %u x %u",max_tw,max_th)); + db_logf4(("\tMinimum stipple size is %u x %u",_descP->dwMinStippleWidth,_descP->dwMinStippleHeight)); + db_logf4(("\tMaximum stipple size is %u x %u",max_sw,max_sh)); + } + #endif + + // Parse the format string and get the parameters + + static bool ParseParams(CreateTextureParms * pParams, char const * _argFormatS, va_list ap) + { + bool bad_parmsB = false; + db_code2(unsigned ch_off = 0;) + db_code2(char ch = 0;) + + while (*_argFormatS && !bad_parmsB) + { + db_code2(++ch_off;) + db_code2(ch = *_argFormatS;) + switch (*_argFormatS++) + { + case 's': + if (pParams->fileNameS || INVALID_HANDLE_VALUE!=pParams->fileH || pParams->dataP || pParams->restoreH) + bad_parmsB = true; + else + { + pParams->fileNameS = va_arg(ap,LPCTSTR); + db_logf4(("\tFilename = \"%s\"",pParams->fileNameS)); + } + break; + case 'h': + if (pParams->fileNameS || INVALID_HANDLE_VALUE!=pParams->fileH || pParams->dataP || pParams->restoreH) + bad_parmsB = true; + else + { + pParams->fileH = va_arg(ap,HANDLE); + db_logf4(("\tFile HANDLE = 0x%08x",pParams->fileH)); + } + break; + case 'p': + if (pParams->fileNameS || INVALID_HANDLE_VALUE!=pParams->fileH || pParams->dataP || pParams->restoreH) + bad_parmsB = true; + else + { + pParams->dataP = va_arg(ap,void const *); + db_logf4(("\tData Pointer = %p",pParams->dataP)); + } + break; + case 'r': + if (pParams->fileNameS || INVALID_HANDLE_VALUE!=pParams->fileH || pParams->dataP || pParams->restoreH || UINT_MAX!=pParams->maxReadBytes || pParams->bytesReadP || pParams->backupHP) + bad_parmsB = true; + else + { + pParams->restoreH = va_arg(ap,AW_BACKUPTEXTUREHANDLE); + db_logf4(("\tRestore Handle = 0x%08x",pParams->restoreH)); + } + break; + case 'x': + if (UINT_MAX!=pParams->maxReadBytes || pParams->restoreH) + bad_parmsB = true; + else + { + pParams->maxReadBytes = va_arg(ap,unsigned); + db_logf4(("\tMax bytes to read = %u",pParams->maxReadBytes)); + } + break; + case 'N': + if (pParams->bytesReadP || pParams->restoreH) + bad_parmsB = true; + else + { + pParams->bytesReadP = va_arg(ap,unsigned *); + db_logf4(("\tPtr to bytes read = %p",pParams->bytesReadP)); + } + break; + case 'f': + if (AW_TLF_DEFAULT!=pParams->flags) + bad_parmsB = true; + else + { + pParams->flags = va_arg(ap,unsigned); + db_logf4(("\tFlags = 0x%08x",pParams->flags)); + } + break; + case 'W': + if (pParams->widthP || pParams->rectA) + bad_parmsB = true; + else + { + pParams->widthP = va_arg(ap,unsigned *); + db_logf4(("\tPtr to width = %p",pParams->widthP)); + } + break; + case 'H': + if (pParams->heightP || pParams->rectA) + bad_parmsB = true; + else + { + pParams->heightP = va_arg(ap,unsigned *); + db_logf4(("\tPtr to height = %p",pParams->heightP)); + } + break; + case 'X': + if (pParams->originalWidthP) + bad_parmsB = true; + else + { + pParams->originalWidthP = va_arg(ap,unsigned *); + db_logf4(("\tPtr to image width = %p",pParams->originalWidthP)); + } + break; + case 'Y': + if (pParams->originalHeightP) + bad_parmsB = true; + else + { + pParams->originalHeightP = va_arg(ap,unsigned *); + db_logf4(("\tPtr to image height = %p",pParams->originalHeightP)); + } + break; + case 'B': + if (pParams->backupHP || pParams->restoreH) + bad_parmsB = true; + else + { + pParams->backupHP = va_arg(ap,AW_BACKUPTEXTUREHANDLE *); + db_logf4(("\tPtr to backup handle = %p",pParams->backupHP)); + } + break; + case 't': + if (pParams->prevTexP.voidP) + bad_parmsB = true; + else if (pParams->rectA) + { + pParams->prevTexB = true; + db_log4("\tPrevious DDSurface * or D3DTexture * in rectangle array"); + } + else if (pParams->loadTextureB) + { + pParams->prevTexP = va_arg(ap,D3DTexture *); + db_logf4(("\tPrevious D3DTexture * = %p",pParams->prevTexP.textureP)); + } + else + { + pParams->prevTexP = va_arg(ap,DDSurface *); + db_logf4(("\tPrevious DDSurface * = %p",pParams->prevTexP.surfaceP)); + } + break; + case 'c': + if (pParams->callbackF) + bad_parmsB = true; + else + { + pParams->callbackF = va_arg(ap,AW_TL_PFN_CALLBACK); + pParams->callbackParam = va_arg(ap,void *); + db_logf4(("\tCallback function = %p, param = %p",pParams->callbackF,pParams->callbackParam)); + } + break; + case 'a': + if (pParams->prevTexP.voidP || pParams->rectA || pParams->widthP || pParams->heightP) + bad_parmsB = true; + else + { + pParams->numRects = va_arg(ap,unsigned); + pParams->rectA = va_arg(ap,AwCreateGraphicRegion *); + db_logf4(("\tRectangle array = %p, size = %u",pParams->rectA,pParams->numRects)); + } + break; + default: + bad_parmsB = true; + } + } + + if (!pParams->fileNameS && INVALID_HANDLE_VALUE==pParams->fileH && !pParams->dataP && !pParams->restoreH) + { + awTlLastErr = AW_TLE_BADPARMS; + db_log2("AwCreateGraphic(): ERROR: No data medium is specified"); + return false; + } + else if (bad_parmsB) + { + awTlLastErr = AW_TLE_BADPARMS; + db_logf2(("AwCreateGraphic(): ERROR: Unexpected '%c' in format string at character %u",ch,ch_off)); + return false; + } + else + { + db_log5("\tParameters are OK"); + return true; + } + } + + // Use the parameters parsed to load the surface or texture + + SurfUnion LoadFromParams(CreateTextureParms * pParams) + { + if (pParams->fileNameS) + { + pParams->fileH = CreateFile(pParams->fileNameS,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + + if (INVALID_HANDLE_VALUE==pParams->fileH) + { + awTlLastErr = AW_TLE_CANTOPENFILE; + awTlLastWinErr = GetLastError(); + db_logf1(("AwCreateGraphic(): ERROR opening file \"%s\"",pParams->fileNameS)); + db_log2(AwTlErrorToString()); + return static_cast(NULL); + } + + SurfUnion textureP = pParams->DoCreate(); + + CloseHandle(pParams->fileH); + + return textureP; + } + else return pParams->DoCreate(); + } + +} // namespace AwTl + +/******************************/ +/* PUBLIC: AwSetTextureFormat */ +/******************************/ + +#define IS_VALID_MEMBER(sP,mem) (reinterpret_cast(&(sP)->mem) - reinterpret_cast(sP) < static_cast((sP)->dwSize)) + +#if defined(__WATCOMC__) && (__WATCOMC__ <= 1100) // currently Watcom compiler crashes when the macro is expanded with the db_logf code in it +#define GET_VALID_MEMBER(sP,mem,deflt) (IS_VALID_MEMBER(sP,mem) ? (sP)->mem : (deflt)) +#else +#define GET_VALID_MEMBER(sP,mem,deflt) (IS_VALID_MEMBER(sP,mem) ? (sP)->mem : (db_logf4((FUNCTION_NAME ": WARNING: %s->%s is not valid",#sP ,#mem )),(deflt))) +#endif + +#define HANDLE_INITERROR(test,s) \ + if (!(test)) { \ + db_logf3((FUNCTION_NAME " failed becuse %s",s)); \ + db_log1(FUNCTION_NAME ": ERROR: unexpected parameters"); \ + return AW_TLE_BADPARMS; \ + } else { \ + db_logf5(("\t" FUNCTION_NAME " passed check '%s'",#test )); \ + } + +#define FUNCTION_NAME "AwSetD3DDevice()" + +AW_TL_ERC AwSetD3DDevice(D3DDevice * _d3ddeviceP) +{ + using AwTl::driverDesc; + + driverDesc.validB = false; + + db_logf4(("AwSetD3DDevice(%p) called",_d3ddeviceP)); + + HANDLE_INITERROR(_d3ddeviceP,"D3DDevice * is NULL") + + D3DDEVICEDESC hw_desc; + D3DDEVICEDESC hel_desc; + INITDXSTRUCT(hw_desc); + INITDXSTRUCT(hel_desc); + + awTlLastDxErr = _d3ddeviceP->GetCaps(&hw_desc,&hel_desc); + if (DD_OK != awTlLastDxErr) + { + db_logf2(("AwSetD3DDevice(): ERROR: %s",AwDxErrorToString())); + return AW_TLE_DXERROR; + } + + db_log4("Direct3D Device Hardware Capabilities:"); + db_code4(AwTl::LogCaps(&hw_desc);) + db_log4("Direct3D Device Emulation Capabilities:"); + db_code4(AwTl::LogCaps(&hel_desc);) + + LPD3DDEVICEDESC descP = (GET_VALID_MEMBER(&hw_desc,dwFlags,0) & D3DDD_COLORMODEL && GET_VALID_MEMBER(&hw_desc,dcmColorModel,0) & (D3DCOLOR_RGB|D3DCOLOR_MONO)) ? &hw_desc : &hel_desc; + db_logf4(("Direct3D Device is %s",&hw_desc==descP ? "HAL" : "emulation only")); + + HANDLE_INITERROR(GET_VALID_MEMBER(descP,dwFlags,0) & D3DDD_DEVCAPS && IS_VALID_MEMBER(descP,dwDevCaps),"LPD3DDEVICEDESC::dwDevCaps is not valid") + HANDLE_INITERROR(descP->dwDevCaps & (D3DDEVCAPS_TEXTUREVIDEOMEMORY|D3DDEVCAPS_TEXTURENONLOCALVIDMEM|D3DDEVCAPS_TEXTURESYSTEMMEMORY),"Textures cannot be in ANY type of memory") + + driverDesc.memFlag = descP->dwDevCaps & D3DDEVCAPS_TEXTURESYSTEMMEMORY ? DDSCAPS_SYSTEMMEMORY : DDSCAPS_VIDEOMEMORY; + driverDesc.minWidth = GET_VALID_MEMBER(descP,dwMinTextureWidth,0); + driverDesc.minHeight = GET_VALID_MEMBER(descP,dwMinTextureHeight,0); + driverDesc.maxWidth = GET_VALID_MEMBER(descP,dwMaxTextureWidth,0); + driverDesc.maxHeight = GET_VALID_MEMBER(descP,dwMaxTextureHeight,0); + driverDesc.needPow2B = GET_VALID_MEMBER(descP,dpcTriCaps.dwTextureCaps,0) & D3DPTEXTURECAPS_POW2 ? true : false; + driverDesc.needSquareB = GET_VALID_MEMBER(descP,dpcTriCaps.dwTextureCaps,0) & D3DPTEXTURECAPS_SQUAREONLY ? true : false; + // if max w and h are 0, make them as large as possible + if (!driverDesc.maxWidth) driverDesc.maxWidth = UINT_MAX; + if (!driverDesc.maxHeight) driverDesc.maxHeight = UINT_MAX; + + db_log4("AwSetD3DDevice() OK"); + + db_log4("Direct 3D Device texture characteristics follow:"); + db_logf4(("\tMinimum texture size: %u x %u",driverDesc.minWidth,driverDesc.minHeight)); + db_logf4(("\tMaximum texture size: %u x %u",driverDesc.maxWidth,driverDesc.maxHeight)); + db_logf4(("\tTextures %s be sqaure",driverDesc.needSquareB ? "must" : "need not")); + db_logf4(("\tTextures %s be a power of two in width and height",driverDesc.needPow2B ? "must" : "need not")); + db_logf4(("\tTextures can%s be in non-local video (AGP) memory",descP->dwDevCaps & D3DDEVCAPS_TEXTURENONLOCALVIDMEM ? "" : "not")); + db_logf4(("\tTextures can%s be in local video (device) memory",descP->dwDevCaps & D3DDEVCAPS_TEXTUREVIDEOMEMORY ? "" : "not")); + db_logf4(("\tTextures can%s be in system memory",descP->dwDevCaps & D3DDEVCAPS_TEXTURESYSTEMMEMORY ? "" : "not")); + db_logf4(("\tTextures will be in %s memory",driverDesc.memFlag & DDSCAPS_SYSTEMMEMORY ? "system" : "video")); + + driverDesc.validB = true; + + return AW_TLE_OK; +} + +AW_TL_ERC AwSetDDObject(DDObject * _ddP) +{ + using AwTl::driverDesc; + + db_logf4(("AwSetDDObject(%p) called.",_ddP)); + #ifdef DIRECTDRAW_VERSION + db_logf4(("\tCompiled with DirectDraw Version %u.%u",DIRECTDRAW_VERSION/0x100U,DIRECTDRAW_VERSION%0x100U)); + #else + db_log4("\tCompiled with unknown DirectDraw version"); + #endif + + + HANDLE_INITERROR(_ddP,"DDObject * is NULL") + driverDesc.ddP = _ddP; + + return AW_TLE_OK; +} + +AW_TL_ERC AwSetD3DDevice(DDObject * _ddP, D3DDevice * _d3ddeviceP) +{ + db_logf4(("AwSetD3DDevice(%p,%p) called",_ddP,_d3ddeviceP)); + + AW_TL_ERC iResult = AwSetDDObject(_ddP); + + if (AW_TLE_OK != iResult) + return iResult; + else + return AwSetD3DDevice(_d3ddeviceP); +} + +#undef FUNCTION_NAME +#define FUNCTION_NAME "AwSetPixelFormat()" +static AW_TL_ERC AwSetPixelFormat(AwTl::PixelFormat * _pfP, LPDDPIXELFORMAT _ddpfP) +{ + using AwTl::SetBitShifts; + + _pfP->validB = false; + + // parameter check + HANDLE_INITERROR(_ddpfP,"DDPIXELFORMAT is NULL") + HANDLE_INITERROR(IS_VALID_MEMBER(_ddpfP,dwFlags),"DDPIXELFORMAT::dwFlags is an invalid field") + HANDLE_INITERROR(!(_ddpfP->dwFlags & DDPF_ALPHA),"DDPIXELFORMAT describes an alpha only surface") + HANDLE_INITERROR(!(_ddpfP->dwFlags & DDPF_PALETTEINDEXEDTO8),"DDPIXELFORMAT describes a 1- 2- or 4- bit surface indexed to an 8-bit palette. This is not yet supported") + HANDLE_INITERROR(!(_ddpfP->dwFlags & DDPF_ZBUFFER),"DDPIXELFORMAT describes Z buffer") + HANDLE_INITERROR(!(_ddpfP->dwFlags & DDPF_ZPIXELS),"DDPIXELFORMAT describes a RGBZ surface") + HANDLE_INITERROR(!(_ddpfP->dwFlags & DDPF_YUV),"DDPIXELFORMAT describes a YUV surface. This is not yet supported") + HANDLE_INITERROR(!(_ddpfP->dwFlags & DDPF_FOURCC),"DDPIXELFORMAT gives a FourCC code for a non RGB surface. This is not yet supported") + + _pfP->palettizedB = true; + switch (_ddpfP->dwFlags & (DDPF_PALETTEINDEXED8|DDPF_PALETTEINDEXED4|DDPF_PALETTEINDEXED2|DDPF_PALETTEINDEXED1)) + { + case 0: + _pfP->palettizedB = false; + break; + case DDPF_PALETTEINDEXED1: + _pfP->bitsPerPixel = 1; + break; + case DDPF_PALETTEINDEXED2: + _pfP->bitsPerPixel = 2; + break; + case DDPF_PALETTEINDEXED4: + _pfP->bitsPerPixel = 4; + break; + case DDPF_PALETTEINDEXED8: + _pfP->bitsPerPixel = 8; + break; + default: + db_log1("AwSetPixelFormat(): ERROR: more than one DDPF_PALETTEINDEXED flags is set"); + return AW_TLE_BADPARMS; + } + + _pfP->alphaB = _ddpfP->dwFlags & DDPF_ALPHAPIXELS ? true : false; + + if (_pfP->palettizedB) + { + HANDLE_INITERROR(!_pfP->alphaB,"alpha channel info is on a palettized format. This is not yet supported") + #if DB_LEVEL >= 4 + if (_ddpfP->dwFlags & DDPF_RGB) + { + db_log4(FUNCTION_NAME ": WARNING: RGB data supplied for a palettized format is ignored"); + db_logf4(("\tRGB bitcount is %u",GET_VALID_MEMBER(_ddpfP,dwRGBBitCount,0))); + db_logf4(("\tRed Mask is 0x%08x",GET_VALID_MEMBER(_ddpfP,dwRBitMask,0))); + db_logf4(("\tGreen Mask is 0x%08x",GET_VALID_MEMBER(_ddpfP,dwGBitMask,0))); + db_logf4(("\tBlue Mask is 0x%08x",GET_VALID_MEMBER(_ddpfP,dwBBitMask,0))); + } + #endif + } + else + { + HANDLE_INITERROR(IS_VALID_MEMBER(_ddpfP,dwRGBBitCount),"DDPIXELFORMAT::dwRGBBitCount is an invalid field") + switch (_ddpfP->dwRGBBitCount) + { + case 4: + case 8: + case 16: + case 24: + case 32: + break; + default: + db_log1("AwSetPixelFormat(): ERROR: RGB bit count is not 4,8,16,24 or 32"); + return AW_TLE_BADPARMS; + } + + HANDLE_INITERROR(!_pfP->alphaB || GET_VALID_MEMBER(_ddpfP,dwRGBAlphaBitMask,0),"Pixel format specifies alpha channel info but alpha mask is zero") + HANDLE_INITERROR(IS_VALID_MEMBER(_ddpfP,dwRBitMask),"DDPIXELFORMAT::dwRBitMask is an invalid field") + HANDLE_INITERROR(IS_VALID_MEMBER(_ddpfP,dwGBitMask),"DDPIXELFORMAT::dwGBitMask is an invalid field") + HANDLE_INITERROR(IS_VALID_MEMBER(_ddpfP,dwBBitMask),"DDPIXELFORMAT::dwBBitMask is an invalid field") + + _pfP->bitsPerPixel = _ddpfP->dwRGBBitCount; + SetBitShifts(&_pfP->redLeftShift,&_pfP->redRightShift,_ddpfP->dwRBitMask); + SetBitShifts(&_pfP->greenLeftShift,&_pfP->greenRightShift,_ddpfP->dwGBitMask); + SetBitShifts(&_pfP->blueLeftShift,&_pfP->blueRightShift,_ddpfP->dwBBitMask); + } + ZEROFILL(_pfP->ddpf); + memcpy(&_pfP->ddpf,_ddpfP,__min(_ddpfP->dwSize,sizeof(DDPIXELFORMAT))); + if (!_pfP->alphaB) + _pfP->ddpf.dwRGBAlphaBitMask = 0; + + db_log4("AwSetPixelFormat() OK"); + + #if DB_LEVEL >= 4 + db_logf4(("Pixel Format is %u-bit %s",_pfP->bitsPerPixel,_pfP->palettizedB ? "palettized" : _pfP->alphaB ? "RGBA" : "RGB")); + if (!_pfP->palettizedB) + { + if (_pfP->alphaB) + { + unsigned alpha_l_shft,alpha_r_shft; + SetBitShifts(&alpha_l_shft,&alpha_r_shft,_pfP->ddpf.dwRGBAlphaBitMask); + db_logf4(("\t%u-%u-%u-%u",8-_pfP->redRightShift,8-_pfP->greenRightShift,8-_pfP->blueRightShift,8-alpha_r_shft)); + db_logf4(("\tAlpha->[%u..%u]",alpha_l_shft+7-alpha_r_shft,alpha_l_shft)); + } + else + { + db_logf4(("\t%u-%u-%u",8-_pfP->redRightShift,8-_pfP->greenRightShift,8-_pfP->blueRightShift)); + } + db_logf4(("\tRed->[%u..%u]",_pfP->redLeftShift+7-_pfP->redRightShift,_pfP->redLeftShift)); + db_logf4(("\tGreen->[%u..%u]",_pfP->greenLeftShift+7-_pfP->greenRightShift,_pfP->greenLeftShift)); + db_logf4(("\tBlue->[%u..%u]",_pfP->blueLeftShift+7-_pfP->blueRightShift,_pfP->blueLeftShift)); + } + #endif + + _pfP->validB = true; + return AW_TLE_OK; +} + +AW_TL_ERC AwSetTextureFormat2(LPDDPIXELFORMAT _ddpfP) +{ + db_logf4(("AwSetTextureFormat(%p) called",_ddpfP)); + + using namespace AwTl; + + while (listTextureFormats.size()) + listTextureFormats.delete_first_entry(); + + return AwSetPixelFormat(&pfTextureFormat, _ddpfP); +} + +AW_TL_ERC AwSetAdditionalTextureFormat2(LPDDPIXELFORMAT _ddpfP, unsigned _maxAlphaBits, int _canDoTransp, unsigned _maxColours) +{ + db_logf4(("AwSetAdditionalTextureFormat(%p.%u,%d,%u) called",_ddpfP,_maxAlphaBits,_canDoTransp,_maxColours)); + + using namespace AwTl; + + AdditionalPixelFormat pf; + + AW_TL_ERC erc = AwSetPixelFormat(&pf, _ddpfP); + + if (AW_TLE_OK == erc) + { + pf.canDoTranspB = _canDoTransp ? true : false; + pf.maxColours = _maxColours; + + listTextureFormats.add_entry_end(pf); + } + + return erc; +} + +AW_TL_ERC AwSetSurfaceFormat2(LPDDPIXELFORMAT _ddpfP) +{ + db_logf4(("AwSetSurfaceFormat(%p) called",_ddpfP)); + + using namespace AwTl; + + return AwSetPixelFormat(&pfSurfaceFormat, _ddpfP); +} + +/****************************/ +/* PUBLIC: AwGetTextureSize */ +/****************************/ + +AW_TL_ERC AwGetTextureSize(register unsigned * _widthP, register unsigned * _heightP, unsigned _width, unsigned _height) +{ + db_assert1(_widthP); + db_assert1(_heightP); + + using AwTl::driverDesc; + + if (!driverDesc.validB) + { + db_log3("AwGetTextureSize(): ERROR: driver description not valid"); + return AW_TLE_NOINIT; + } + + if (_width < driverDesc.minWidth) _width = driverDesc.minWidth; + if (_height < driverDesc.minHeight) _height = driverDesc.minHeight; + + if (driverDesc.needPow2B) + { + *_widthP = 1; + while (*_widthP < _width) *_widthP <<= 1; + *_heightP = 1; + while (*_heightP < _height) *_heightP <<= 1; + } + else + { + *_widthP = _width; + *_heightP = _height; + } + + if (driverDesc.needSquareB) + { + if (*_widthP < *_heightP) *_widthP = *_heightP; + else *_heightP = *_widthP; + } + + #if 1 // not sure if this is required... + *_widthP += 3; + *_widthP &= ~3; + *_heightP += 3; + *_heightP &= ~3; + #endif + + db_logf4(("\tAwGetTextureSize(): d3d texture will be %ux%u",*_widthP,*_heightP)); + + if (*_widthP > driverDesc.maxWidth || *_heightP > driverDesc.maxHeight) + { + db_log3("AwGetTextureSize(): ERROR: image size too large to be a d3d texture"); + return AW_TLE_IMAGETOOLARGE; + } + else return AW_TLE_OK; +} + + +/******************************/ +/* PUBLIC: AwCreate functions */ +/******************************/ + +D3DTexture * _AWTL_VARARG AwCreateTexture(char const * _argFormatS, ...) +{ + db_logf4(("AwCreateTexture(\"%s\") called",_argFormatS)); + + using namespace AwTl; + + va_list ap; + va_start(ap,_argFormatS); + CreateTextureParms parms; + parms.loadTextureB = true; + bool bParmsOK = ParseParams(&parms, _argFormatS, ap); + va_end(ap); + return bParmsOK ? LoadFromParams(&parms).textureP : NULL; +} + +DDSurface * _AWTL_VARARG AwCreateSurface(char const * _argFormatS, ...) +{ + db_logf4(("AwCreateSurface(\"%s\") called",_argFormatS)); + + using namespace AwTl; + + va_list ap; + va_start(ap,_argFormatS); + CreateTextureParms parms; + parms.loadTextureB = false; + bool bParmsOK = ParseParams(&parms, _argFormatS, ap); + va_end(ap); + return bParmsOK ? LoadFromParams(&parms).surfaceP : NULL; +} + +AW_TL_ERC AwDestroyBackupTexture(AW_BACKUPTEXTUREHANDLE _bH) +{ + db_logf4(("AwDestroyBackupTexture(0x%08x) called",_bH)); + if (_bH) + { + _bH->Release(); + return AW_TLE_OK; + } + else + { + db_log1("AwDestroyBackupTexture(): ERROR: AW_BACKUPTEXTUREHANDLE==NULL"); + return AW_TLE_BADPARMS; + } +} + +/*********************************/ +/* PUBLIC DEBUG: LastErr globals */ +/*********************************/ + +AW_TL_ERC awTlLastErr; +HRESULT awTlLastDxErr; +DWORD awTlLastWinErr; + +/*******************************************/ +/* PUBLIC DEBUG: AwErrorToString functions */ +/*******************************************/ + +#ifndef NDEBUG +char const * AwWinErrorToString(DWORD error) +{ + if (NO_ERROR==error) return "No error"; + static TCHAR buffer[1024]; + if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL,error,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),buffer,sizeof buffer/sizeof(TCHAR)-1,NULL)) + wsprintf(buffer,TEXT("FormatMessage() failed; previous Windows error code: 0x%08X"),error); + for (TCHAR * bufP = buffer; *bufP; ++bufP) + { + switch (*bufP) + { + case '\n': + case '\r': + *bufP=' '; + } + } + return reinterpret_cast(buffer); +} + +char const * AwTlErrorToString(AwTlErc error) +{ + char const * defaultS; + switch (error) + { + case AW_TLE_OK: + return "No error"; + case AW_TLE_DXERROR: + if (DD_OK==awTlLastDxErr) + return "Unknown DirectX error"; + else + return AwDxErrorToString(); + case AW_TLE_BADPARMS: + return "Invalid parameters or functionality not supported"; + case AW_TLE_NOINIT: + return "Initialization failed or not performed"; + case AW_TLE_CANTOPENFILE: + defaultS = "Unknown error opening file"; + goto WIN_ERR; + case AW_TLE_CANTREADFILE: + defaultS = "Unknown error reading file"; + WIN_ERR: + if (NO_ERROR==awTlLastWinErr) + return defaultS; + else + return AwWinErrorToString(); + case AW_TLE_EOFMET: + return "Unexpected end of file during texture load"; + case AW_TLE_BADFILEFORMAT: + return "Texture file format not recognized"; + case AW_TLE_BADFILEDATA: + return "Texture file data not consistent"; + case AW_TLE_CANTPALETTIZE: + return "Texture file data not palettized"; + case AW_TLE_IMAGETOOLARGE: + return "Image is too large for a texture"; + case AW_TLE_CANTRELOAD: + return "New image is wrong size or format to load into existing texture"; + default: + return "Unknown texture loading error"; + } +} + +char const * AwDxErrorToString(HRESULT error) +{ + switch(error) { + case DD_OK: + return "No error.\0"; + case DDERR_ALREADYINITIALIZED: + return "This object is already initialized.\0"; + case DDERR_BLTFASTCANTCLIP: + return "Return if a clipper object is attached to the source surface passed into a BltFast call.\0"; + case DDERR_CANNOTATTACHSURFACE: + return "This surface can not be attached to the requested surface.\0"; + case DDERR_CANNOTDETACHSURFACE: + return "This surface can not be detached from the requested surface.\0"; + case DDERR_CANTCREATEDC: + return "Windows can not create any more DCs.\0"; + case DDERR_CANTDUPLICATE: + return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created.\0"; + case DDERR_CLIPPERISUSINGHWND: + return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd.\0"; + case DDERR_COLORKEYNOTSET: + return "No src color key specified for this operation.\0"; + case DDERR_CURRENTLYNOTAVAIL: + return "Support is currently not available.\0"; + case DDERR_DIRECTDRAWALREADYCREATED: + return "A DirectDraw object representing this driver has already been created for this process.\0"; + case DDERR_EXCEPTION: + return "An exception was encountered while performing the requested operation.\0"; + case DDERR_EXCLUSIVEMODEALREADYSET: + return "An attempt was made to set the cooperative level when it was already set to exclusive.\0"; + case DDERR_GENERIC: + return "Generic failure.\0"; + case DDERR_HEIGHTALIGN: + return "Height of rectangle provided is not a multiple of reqd alignment.\0"; + case DDERR_HWNDALREADYSET: + return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or palettes created.\0"; + case DDERR_HWNDSUBCLASSED: + return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring state.\0"; + case DDERR_IMPLICITLYCREATED: + return "This surface can not be restored because it is an implicitly created surface.\0"; + case DDERR_INCOMPATIBLEPRIMARY: + return "Unable to match primary surface creation request with existing primary surface.\0"; + case DDERR_INVALIDCAPS: + return "One or more of the caps bits passed to the callback are incorrect.\0"; + case DDERR_INVALIDCLIPLIST: + return "DirectDraw does not support the provided cliplist.\0"; + case DDERR_INVALIDDIRECTDRAWGUID: + return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier.\0"; + case DDERR_INVALIDMODE: + return "DirectDraw does not support the requested mode.\0"; + case DDERR_INVALIDOBJECT: + return "DirectDraw received a pointer that was an invalid DIRECTDRAW object.\0"; + case DDERR_INVALIDPARAMS: + return "One or more of the parameters passed to the function are incorrect.\0"; + case DDERR_INVALIDPIXELFORMAT: + return "The pixel format was invalid as specified.\0"; + case DDERR_INVALIDPOSITION: + return "Returned when the position of the overlay on the destination is no longer legal for that destination.\0"; + case DDERR_INVALIDRECT: + return "Rectangle provided was invalid.\0"; + case DDERR_LOCKEDSURFACES: + return "Operation could not be carried out because one or more surfaces are locked.\0"; + case DDERR_NO3D: + return "There is no 3D present.\0"; + case DDERR_NOALPHAHW: + return "Operation could not be carried out because there is no alpha accleration hardware present or available.\0"; + case DDERR_NOBLTHW: + return "No blitter hardware present.\0"; + case DDERR_NOCLIPLIST: + return "No cliplist available.\0"; + case DDERR_NOCLIPPERATTACHED: + return "No clipper object attached to surface object.\0"; + case DDERR_NOCOLORCONVHW: + return "Operation could not be carried out because there is no color conversion hardware present or available.\0"; + case DDERR_NOCOLORKEY: + return "Surface doesn't currently have a color key\0"; + case DDERR_NOCOLORKEYHW: + return "Operation could not be carried out because there is no hardware support of the destination color key.\0"; + case DDERR_NOCOOPERATIVELEVELSET: + return "Create function called without DirectDraw object method SetCooperativeLevel being called.\0"; + case DDERR_NODC: + return "No DC was ever created for this surface.\0"; + case DDERR_NODDROPSHW: + return "No DirectDraw ROP hardware.\0"; + case DDERR_NODIRECTDRAWHW: + return "A hardware-only DirectDraw object creation was attempted but the driver did not support any hardware.\0"; + case DDERR_NOEMULATION: + return "Software emulation not available.\0"; + case DDERR_NOEXCLUSIVEMODE: + return "Operation requires the application to have exclusive mode but the application does not have exclusive mode.\0"; + case DDERR_NOFLIPHW: + return "Flipping visible surfaces is not supported.\0"; + case DDERR_NOGDI: + return "There is no GDI present.\0"; + case DDERR_NOHWND: + return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel HWND.\0"; + case DDERR_NOMIRRORHW: + return "Operation could not be carried out because there is no hardware present or available.\0"; + case DDERR_NOOVERLAYDEST: + return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on to establish a destination.\0"; + case DDERR_NOOVERLAYHW: + return "Operation could not be carried out because there is no overlay hardware present or available.\0"; + case DDERR_NOPALETTEATTACHED: + return "No palette object attached to this surface.\0"; + case DDERR_NOPALETTEHW: + return "No hardware support for 16 or 256 color palettes.\0"; + case DDERR_NORASTEROPHW: + return "Operation could not be carried out because there is no appropriate raster op hardware present or available.\0"; + case DDERR_NOROTATIONHW: + return "Operation could not be carried out because there is no rotation hardware present or available.\0"; + case DDERR_NOSTRETCHHW: + return "Operation could not be carried out because there is no hardware support for stretching.\0"; + case DDERR_NOT4BITCOLOR: + return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color palette.\0"; + case DDERR_NOT4BITCOLORINDEX: + return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color index palette.\0"; + case DDERR_NOT8BITCOLOR: + return "DirectDrawSurface is not in 8 bit color mode and the requested operation requires 8 bit color.\0"; + case DDERR_NOTAOVERLAYSURFACE: + return "Returned when an overlay member is called for a non-overlay surface.\0"; + case DDERR_NOTEXTUREHW: + return "Operation could not be carried out because there is no texture mapping hardware present or available.\0"; + case DDERR_NOTFLIPPABLE: + return "An attempt has been made to flip a surface that is not flippable.\0"; + case DDERR_NOTFOUND: + return "Requested item was not found.\0"; + case DDERR_NOTLOCKED: + return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this process, has been attempted.\0"; + case DDERR_NOTPALETTIZED: + return "The surface being used is not a palette-based surface.\0"; + case DDERR_NOVSYNCHW: + return "Operation could not be carried out because there is no hardware support for vertical blank synchronized operations.\0"; + case DDERR_NOZBUFFERHW: + return "Operation could not be carried out because there is no hardware support for zbuffer blitting.\0"; + case DDERR_NOZOVERLAYHW: + return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z layering of overlays.\0"; + case DDERR_OUTOFCAPS: + return "The hardware needed for the requested operation has already been allocated.\0"; + case DDERR_OUTOFMEMORY: + return "DirectDraw does not have enough memory to perform the operation.\0"; + case DDERR_OUTOFVIDEOMEMORY: + return "DirectDraw does not have enough video memory to perform the operation.\0"; + case DDERR_OVERLAYCANTCLIP: + return "The hardware does not support clipped overlays.\0"; + case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: + return "Can only have ony color key active at one time for overlays.\0"; + case DDERR_OVERLAYNOTVISIBLE: + return "Returned when GetOverlayPosition is called on a hidden overlay.\0"; + case DDERR_PALETTEBUSY: + return "Access to this palette is being refused because the palette is already locked by another thread.\0"; + case DDERR_PRIMARYSURFACEALREADYEXISTS: + return "This process already has created a primary surface.\0"; + case DDERR_REGIONTOOSMALL: + return "Region passed to Clipper::GetClipList is too small.\0"; + case DDERR_SURFACEALREADYATTACHED: + return "This surface is already attached to the surface it is being attached to.\0"; + case DDERR_SURFACEALREADYDEPENDENT: + return "This surface is already a dependency of the surface it is being made a dependency of.\0"; + case DDERR_SURFACEBUSY: + return "Access to this surface is being refused because the surface is already locked by another thread.\0"; + case DDERR_SURFACEISOBSCURED: + return "Access to surface refused because the surface is obscured.\0"; + case DDERR_SURFACELOST: + return "Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface object representing this surface should have Restore called on it.\0"; + case DDERR_SURFACENOTATTACHED: + return "The requested surface is not attached.\0"; + case DDERR_TOOBIGHEIGHT: + return "Height requested by DirectDraw is too large.\0"; + case DDERR_TOOBIGSIZE: + return "Size requested by DirectDraw is too large, but the individual height and width are OK.\0"; + case DDERR_TOOBIGWIDTH: + return "Width requested by DirectDraw is too large.\0"; + case DDERR_UNSUPPORTED: + return "Action not supported.\0"; + case DDERR_UNSUPPORTEDFORMAT: + return "FOURCC format requested is unsupported by DirectDraw.\0"; + case DDERR_UNSUPPORTEDMASK: + return "Bitmask in the pixel format requested is unsupported by DirectDraw.\0"; + case DDERR_VERTICALBLANKINPROGRESS: + return "Vertical blank is in progress.\0"; + case DDERR_WASSTILLDRAWING: + return "Informs DirectDraw that the previous Blt which is transfering information to or from this Surface is incomplete.\0"; + case DDERR_WRONGMODE: + return "This surface can not be restored because it was created in a different mode.\0"; + case DDERR_XALIGN: + return "Rectangle provided was not horizontally aligned on required boundary.\0"; + case D3DERR_BADMAJORVERSION: + return "D3DERR_BADMAJORVERSION\0"; + case D3DERR_BADMINORVERSION: + return "D3DERR_BADMINORVERSION\0"; + case D3DERR_EXECUTE_LOCKED: + return "D3DERR_EXECUTE_LOCKED\0"; + case D3DERR_EXECUTE_NOT_LOCKED: + return "D3DERR_EXECUTE_NOT_LOCKED\0"; + case D3DERR_EXECUTE_CREATE_FAILED: + return "D3DERR_EXECUTE_CREATE_FAILED\0"; + case D3DERR_EXECUTE_DESTROY_FAILED: + return "D3DERR_EXECUTE_DESTROY_FAILED\0"; + case D3DERR_EXECUTE_LOCK_FAILED: + return "D3DERR_EXECUTE_LOCK_FAILED\0"; + case D3DERR_EXECUTE_UNLOCK_FAILED: + return "D3DERR_EXECUTE_UNLOCK_FAILED\0"; + case D3DERR_EXECUTE_FAILED: + return "D3DERR_EXECUTE_FAILED\0"; + case D3DERR_EXECUTE_CLIPPED_FAILED: + return "D3DERR_EXECUTE_CLIPPED_FAILED\0"; + case D3DERR_TEXTURE_NO_SUPPORT: + return "D3DERR_TEXTURE_NO_SUPPORT\0"; + case D3DERR_TEXTURE_NOT_LOCKED: + return "D3DERR_TEXTURE_NOT_LOCKED\0"; + case D3DERR_TEXTURE_LOCKED: + return "D3DERR_TEXTURE_LOCKED\0"; + case D3DERR_TEXTURE_CREATE_FAILED: + return "D3DERR_TEXTURE_CREATE_FAILED\0"; + case D3DERR_TEXTURE_DESTROY_FAILED: + return "D3DERR_TEXTURE_DESTROY_FAILED\0"; + case D3DERR_TEXTURE_LOCK_FAILED: + return "D3DERR_TEXTURE_LOCK_FAILED\0"; + case D3DERR_TEXTURE_UNLOCK_FAILED: + return "D3DERR_TEXTURE_UNLOCK_FAILED\0"; + case D3DERR_TEXTURE_LOAD_FAILED: + return "D3DERR_TEXTURE_LOAD_FAILED\0"; + case D3DERR_MATRIX_CREATE_FAILED: + return "D3DERR_MATRIX_CREATE_FAILED\0"; + case D3DERR_MATRIX_DESTROY_FAILED: + return "D3DERR_MATRIX_DESTROY_FAILED\0"; + case D3DERR_MATRIX_SETDATA_FAILED: + return "D3DERR_MATRIX_SETDATA_FAILED\0"; + case D3DERR_SETVIEWPORTDATA_FAILED: + return "D3DERR_SETVIEWPORTDATA_FAILED\0"; + case D3DERR_MATERIAL_CREATE_FAILED: + return "D3DERR_MATERIAL_CREATE_FAILED\0"; + case D3DERR_MATERIAL_DESTROY_FAILED: + return "D3DERR_MATERIAL_DESTROY_FAILED\0"; + case D3DERR_MATERIAL_SETDATA_FAILED: + return "D3DERR_MATERIAL_SETDATA_FAILED\0"; + case D3DERR_LIGHT_SET_FAILED: + return "D3DERR_LIGHT_SET_FAILED\0"; + #if 0 // retained mode error codes + case D3DRMERR_BADOBJECT: + return "D3DRMERR_BADOBJECT\0"; + case D3DRMERR_BADTYPE: + return "D3DRMERR_BADTYPE\0"; + case D3DRMERR_BADALLOC: + return "D3DRMERR_BADALLOC\0"; + case D3DRMERR_FACEUSED: + return "D3DRMERR_FACEUSED\0"; + case D3DRMERR_NOTFOUND: + return "D3DRMERR_NOTFOUND\0"; + case D3DRMERR_NOTDONEYET: + return "D3DRMERR_NOTDONEYET\0"; + case D3DRMERR_FILENOTFOUND: + return "The file was not found.\0"; + case D3DRMERR_BADFILE: + return "D3DRMERR_BADFILE\0"; + case D3DRMERR_BADDEVICE: + return "D3DRMERR_BADDEVICE\0"; + case D3DRMERR_BADVALUE: + return "D3DRMERR_BADVALUE\0"; + case D3DRMERR_BADMAJORVERSION: + return "D3DRMERR_BADMAJORVERSION\0"; + case D3DRMERR_BADMINORVERSION: + return "D3DRMERR_BADMINORVERSION\0"; + case D3DRMERR_UNABLETOEXECUTE: + return "D3DRMERR_UNABLETOEXECUTE\0"; + #endif + default: + return "Unrecognized error value.\0"; + } +} +#endif diff --git a/3dc/win95/awTexLd.h b/3dc/win95/awTexLd.h new file mode 100644 index 0000000..8b143a9 --- /dev/null +++ b/3dc/win95/awTexLd.h @@ -0,0 +1,565 @@ +#ifndef _INCLUDED_AWTEXLD_H_ +#define _INCLUDED_AWTEXLD_H_ + +#include +#include + +/*********************************************/ +/* Note: */ +/* */ +/* This header file contains typedefs for */ +/* DDObject */ +/* D3DDevice */ +/* D3DTexture */ +/* D3DSurface */ +/* and #defines for their corresponding IIDs */ +/* GUID_DD_SURFACE */ +/* GUID_D3D_TEXTURE */ +/* */ +/* They are currently typedeffed as follows */ +/* typedef IDirectDraw2 DDObject; */ +/* typedef IDirect3DDevice D3DDevice; */ +/* typedef IDirect3DTexture D3DTexture; */ +/* typedef IDirect3DSurface DDSurface; */ +/*********************************************/ +#include "aw.h" + +/***********************************************************************************/ +/* awTexLd.h - Author: Jake Hotson */ +/* */ +/* Loading of textures into D3D surfaces */ +/* requires DirectX 5 or later */ +/* requires db.c and db.h */ +/* also requires */ +/* Watcom C++ 11.0 or later */ +/* or Microsoft Visual C++ 5.0 or later */ +/* or another suitable compiler */ +/* */ +/* Load any known file format */ +/* Microsoft bitmap (.BMP) */ +/* OS/2 1.x bitmap (.BMP) */ +/* OS/2 2.x bitmap (.BMP) */ +/* Portable Bitmap (.PBM) */ +/* Portable Graymap (.PGM) */ +/* Portable Pixelmap (.PPM) */ +/* */ +/* Load from various media */ +/* File name */ +/* Windows file handle */ +/* Raw file data in memory */ +/* */ +/* Load into any given texture format provided a conversion is possible */ +/* Pad to the required size that the driver will accept */ +/* */ +/* Optional handling of transparency */ +/* Use alpha bits if available */ +/* Otherwise chroma keying to be used */ +/* Transparency colour is RGB(0,0,0) for non palettized data */ +/* Or index 0 in palettized data */ +/* */ +/* Optional storing of processed raw data */ +/* Use internal format independent of DirectX */ +/* Function to reload from this data into a possibly different texture format */ +/* */ +/* Five optional levels of diagnostics possible */ +/* 1. Logs when a function returns because of an error */ +/* 2. Logs the nature of the error */ +/* 3. Logs immediately when an error occurs */ +/* 4. Logs information as data is parsed, and when main functions are called */ +/* 5. Logs success of every small subsection of code */ +/* */ +/* Maximum error reporting */ +/* */ +/* Optimal Loading Speed */ +/***********************************************************************************/ + +/* Version 2.1 */ +#define AW_TL_VERSION 210 /* Preprocessor constant can be used to determine the version of this code */ + +/* +Version History: +---------------- +version AW_TL_VERSION +0.9 090 Incomplete & May still contain bugs +0.91 091 AW_TLF_CHROMAKEY flag, and 't' option supported. Fewer bugs +0.92 092 Slightly more debug code +0.93 093 Using typedefs DDObject, D3DDevice, D3DTexture +1.0 100 Assumed to be bug-free +1.1 110 Internal redesign with interface to support any file format +1.2 120 Allow for loading into Direct Draw surfaces which are not textures +1.21 121 Two extra format flags to get width and height of actual image (as opposed to DD/D3D surface) +1.22 122 Split up the initialization function AwSetD3DDevice() into DD part and D3D part +1.3 130 New function: AwGetTextureSize() +1.31 131 New format flag for a callback function for when video mem runs out +1.4 140 Support for loading image split into several surfaces/textures and for loading surfaces as textures +1.5 150 Multiple texture format support + +2.0 200 Beginning support for DX 6.0 - new AwSet..Format functions take LPDDPIXELFORMAT not LPDDSURFACEDESC +2.1 210 AW_TLF_CHECKLOST and AW_TLF_SKIPNOTLOST flags added +*/ + +/**********************************************/ +/* Handle C++ linkage and optional parameters */ +/**********************************************/ + +#ifdef __cplusplus + extern "C" { + #define _AWTL_DEFAULTPARM(v) = (v) +#else /* ! __cplusplus */ + #define _AWTL_DEFAULTPARM(v) +#endif /* ? __cplusplus */ + +#ifdef _MSC_VER + #define _AWTL_VARARG __cdecl +#else + #define _AWTL_VARARG +#endif + +/******************************/ +/* return codes & error codes */ +/******************************/ + +typedef +enum AwTlErc +{ + /* General Errors */ + AW_TLE_OK /* apparent success */ + , AW_TLE_DXERROR /* unexpected DirectX error - see awTlLastDxErr */ + , AW_TLE_BADPARMS /* parameters passed to function were invalid, or requested unsupported functionality */ + , AW_TLE_NOINIT /* initialization functions have not been successfully called */ + /* File reading errors */ + , AW_TLE_CANTOPENFILE /* file open failed - see awTlLastWinErr for the Windows error code */ + , AW_TLE_CANTREADFILE /* unexpected error reading file - see awTlLastWinErr for the Windows error code */ + , AW_TLE_EOFMET /* unexpected end of file encountered */ + , AW_TLE_BADFILEFORMAT /* file format identifier not recognized */ + , AW_TLE_BADFILEDATA /* file data not consistent */ + /* Conversion errors */ + , AW_TLE_CANTPALETTIZE /* texture format is palettized; file data is not */ + , AW_TLE_IMAGETOOLARGE /* image size is larger in one or both dimensions than maximum texture size */ + , AW_TLE_CANTRELOAD /* loading a new texture into an existing surface failed because the existing surface is an unsuitable size, etc. */ +} + AW_TL_ERC; + +extern AW_TL_ERC awTlLastErr; +extern HRESULT awTlLastDxErr; +extern DWORD awTlLastWinErr; + +#ifdef NDEBUG + #define AwTlErrorToString ThisIsADebugFunction! /* generate compiler error */ + #define AwDxErrorToString ThisIsADebugFunction! /* generate compiler error */ + #define AwWinErrorToString ThisIsADebugFunction! /* generate compiler error */ +#else /* ! NDEBUG */ + extern char const * AwTlErrorToString(AW_TL_ERC _AWTL_DEFAULTPARM(awTlLastErr)); + extern char const * AwDxErrorToString(HRESULT _AWTL_DEFAULTPARM(awTlLastDxErr)); + extern char const * AwWinErrorToString(DWORD _AWTL_DEFAULTPARM(awTlLastWinErr)); +#endif /* ? NDEBUG */ + +/*********/ +/* Flags */ +/*********/ + +enum +{ + AW_TLF_DEFAULT = 0x00000000U /* no flags set */ + , AW_TLF_TRANSP = 0x00000001U /* src data has transparency */ + , AW_TLF_PREVSRC = 0x00000002U /* in AwRestoreTexture, use previously stored source data flags (AW_TLF_TRANSP only) */ + , AW_TLF_COMPRESS = 0x00000004U /* use ALLOCONLOAD flag */ + , AW_TLF_CHROMAKEY = 0x00000008U /* use chroma keying for transparency when the texture format has an alpha channel */ + , AW_TLF_VIDMEM = 0x00000010U /* use Video memory for surfaces which are not textures */ + , AW_TLF_PREVSRCALL = 0x00000020U /* in AwRestoreTexture, use ALL previously stored flags, except AW_TLF_CHECKLOST and AW_TLF_SKIPNOTLOST */ + , AW_TLF_TEXTURE = 0x00000040U /* in AwCreateSurface, create a surface in the texture format with the texture flag set */ + , AW_TLF_MINSIZE = 0x00000080U /* with the 'a' option, ensure all surfaces/textures created are at least as big as the rectangle specified even if the rect is partially off the image */ + , AW_TLF_CHECKLOST = 0x00000100U /* checks for lost surfaces and calls restore on them */ + , AW_TLF_SKIPNOTLOST = 0x00000200U /* if the above flag also is specified, does not bother trying to restore surfaces which weren't lost */ + + , _AW_TLF_FORCE32BITENUM = 0x0fffffffU /* probably entirely unnecessary */ +}; + +/*********/ +/* Types */ +/*********/ + +/* a callback function */ +typedef int (* AW_TL_PFN_CALLBACK) (void *); + +/* Structure for receiving specific regions of an image in a surface or texture. + * A pointer to an array of thise structures is passed to the AwCreate... + * functions if the 'a' format specifier is used. The fields 'left', 'right', + * 'top' and 'bottom' specify the rectangle to cut out of the image being loaded + * and must be valid. In AwCreateSurface, the 'pSurface' field is used and is a + * pointer to the Direct Draw surface created; in AwCreateTexture, the + * 'pTexture' field is used and is a pointer to the Direct 3D texture created. + * If an error occurs all the pointers in the array will be set to NULL. The + * 'width' and 'height' fields will be filled in with the width and height of + * the surface or texture that is created. If the rectangle specified is + * completely outsided the main image, the width and height will be set to zero, + * and the pointer field will be set to NULL, but this does not constitute an + * error. If the 't' option is used, the pointer fields are assumed to be valid + * textures or surfaces into which to load the new textures or surfaces. If the + * pointer is NULL, the structure is ignored. The pointers will remain unchanged + * even in the event of an error or a rectangle specified outside the main + * image, though the width and height will still be set to zero. + */ +struct AwCreateGraphicRegion +{ + unsigned left, top, right, bottom; /* rectangle to cut from the original image */ + unsigned width, height; /* width and height of the resulting surface or texture */ + union /* DDSurface or D3DTexture pointer depending on the context used */ + { + DDSurface * pSurface; /* Direct Draw Surface object pointer */ + D3DTexture * pTexture; /* Direct 3D Texture object pointer */ + }; +}; + +/* typedef to save typing 'struct' when not using C++ */ +typedef struct AwCreateGraphicRegion AW_CREATEGRAPHICREGION; + +/********************/ +/* Public functions */ +/********************/ + +/* AwSetD3DDevice(DDObject * _ddP, D3DDevice * _d3ddeviceP) + + Description: + Tells the texture loaders about the DirectDraw and + Direct3D setup. You must call this function before + loading any textures, and also every time you change + the DirectDraw or Direct3D device setup. + As of v1.22 this function is overloaded and only + available to C++ programmers. + + Parameters: + _ddP + Pointer to the DirectDraw object obtained from + a call to DirectDrawCreate(). + _d3ddeviceP + Pointer to the Direct3DDevice object obtained + from its GUID which is the lpGuid parameter in + a call to a D3DENUMDEVICESCALLBACK function for + your chosen driver. + + Returns: + AW_TLE_OK if the function completed successfully; + AW_TLE_BADPARMS if the parameters passed to the + function were incorrect + AW_TLE_DXERROR if a DirectX SDK call failed +*/ +#ifdef __cplusplus + extern "C++" AW_TL_ERC AwSetD3DDevice(DDObject * _ddP, D3DDevice * _d3ddeviceP); +#endif + +/* AwSetDDObject(DDObject * _ddP) + AwSetD3DDevice(D3DDevice * _d3ddeviceP) + + Description: + These functions together do what the two parameter + version of AwSetD3DDevice(), above, does. You + needn't call AwSetD3DDevice() if you are only + loading direct draw surfaces. The parameters and + return values are as described above. +*/ + +extern AW_TL_ERC AwSetD3DDevice(D3DDevice * _d3ddeviceP); +extern AW_TL_ERC AwSetDDObject(DDObject * _ddP); + +/* AwSetTextureFormat2(LPDDPIXELFORMAT _ddpfP) + + Description: + Informs the texture loaders of the currently slected + texture format. You must call this function before + loading any textures, and also every time you change + the texture format. + + Parameters: + _ddpfP + Pointer to a DDPIXELFORMAT structure which + describes the texture format. + + Returns: + AW_TLE_OK if the function completed successfully; + AW_TLE_BADPARMS if the parameters passed to the + function were incorrect +*/ +extern AW_TL_ERC AwSetTextureFormat2(LPDDPIXELFORMAT _ddpfP); +#define AwSetTextureFormat(_descP) (AwSetTextureFormat2((_descP) ? &(_descP)->ddpfPixelFormat : NULL)) + +/* AwSetAdditionalTextureFormat2(LPDDPIXELFORMAT _ddpfP, unsigned _maxAlphaBits, int _canDoTransp, unsigned _maxColours) + + Description: + Informs the texture loaders an additional texture + format that should be used in certain cases. After + a call to AwSetTextureFormat, there are no + additional formats. Each additional format that you + want to make available should be set with a call to + this function. When a texture is being loaded, the + additional formats are considered in the order that + they were set (ie. the order in which the calls to + this function were made). For each format + considered, if it could be used for the image and + the image's specification passes the tests for this + format, the format will replace the previously + chosen format (either the base format set by + AwSetTextureFormat or an earlier additional format + whose conditions of use were also met). + + Parameters: + _ddpfP + Pointer to a DDPIXELFORMAT structure which + describes the texture format. + _maxAlphaBits + Specifies that this format should only be used + for images that do not have more bits of alpha + information than this value. + _canDoTransp + If zero, specifies that this format should not + be used for images which have a transparent + colour. + _maxColours + Specifies that this format should only be used + for images that do not contain more unique + colours than this value. If this value is zero, + the format can be used for images with any + number of colours. If this value is non-zero, + this format will not be used for images whose + number of unique colours cannot be determined. + + Returns: + AW_TLE_OK if the function completed successfully; + AW_TLE_NOINIT if AwSetTextureFormat was not + previously called. + AW_TLE_BADPARMS if the parameters passed to the + function were incorrect +*/ +extern AW_TL_ERC AwSetAdditionalTextureFormat2(LPDDPIXELFORMAT _ddpfP, unsigned _maxAlphaBits, int _canDoTransp, unsigned _maxColours); +#define AwSetAdditionalTextureFormat(_descP, _maxAlphaBits, _canDoTransp, _maxColours) (AwSetAdditionalTextureFormat2((_descP) ? &(_descP->ddpfPixelFormat) : NULL,_maxAlphaBits,_canDoTransp,_maxColours)) + +/* AwSetSurfaceFormat2(LPDDPIXELFORMAT _ddpfP) + + Description: + As for AwSetTextureFormat but tells AwCreateSurface() + what format surfaces for blitting should be in +*/ +extern AW_TL_ERC AwSetSurfaceFormat2(LPDDPIXELFORMAT _ddpfP); +#define AwSetSurfaceFormat(_descP) (AwSetSurfaceFormat2((_descP) ? &(_descP)->ddpfPixelFormat : NULL)) + +/* AwGetTextureSize(unsigned * _widthP, unsigned * _heightP, unsigned _width, unsigned _height) + + Description: + Calculates the size required for a texture on the + current driver, given a minimum size required to + hold the proposed image. + + Parameters: + _widthP + Pointer to a variable which will receive the + width required for a Direct 3D texture. + _heightP + Pointer to a variable which will receive the + height. + _width + Minimum width required for the proposed image. + _height + Minimum height required. + + Returns: + AW_TLE_OK if the required Direct 3D texture size was + calculated; + AW_TLE_IMAGETOOLARGE if the driver specifies a + maximum texture size which is less than the size + that would be required to hold an image of the + proposed size; + AW_TLE_NOINIT if driver information was unavailable + because initialization functions weren't called. +*/ +extern AW_TL_ERC AwGetTextureSize(unsigned * _widthP, unsigned * _heightP, unsigned _width, unsigned _height); + +/* AwCreateTexture(char const * _argFormatS, ...) + + Description: + Creates a Direct3D texture for use by the device + renderer. The exact functionality is determined by + the first argument which is a format specifier + string. + + Parameters: + _argFormatS + Pointer to a null terminated string which + specifies the order, types and interpretations + of the other parameters. Each character in the + string corresponds to a parameter passed to the + function, and the parameters are parsed in the + same order as their format specifiers appear in + the string. For clarity, upper case letters are + used to indicate paramters which are pointers to + data that will be filled in by the function, and + lower case letters are used for parameters which + are simply data to be used by the function. + + The following specifiers are permitted: + + s The next argument is of type 'LPCTSTR' and is a + pointer to a ASCII or UNICODE string which is + the filename of an image file to load. + h The next argument is of type 'HANDLE' and is a + Windows file handle with its file pointer set to + the start of an image file's data. + p The next argument is of type 'void const *' and + is a pointer to an image file's data in memory. + r The next argument is of type + 'AW_BACKUPTEXTUREHANDLE' and is used to restore + a previously loaded texture, possibly with the + texture format or Direct3D device having + changed. + x The next argument is of type 'unsigned' and is + the maximum number of bytes that should be read + from a file or memory. If parsing the file data + would cause more bytes to be read than this + value, the function fails and the error is + 'AW_TLE_EOFMET'. This may be useful in + conjunction with format specifier 'm' in order + to prevent a general protection (GP) fault. + N The next argument is of type 'unsigned *' and + points to a variable which will receive the + number of bytes which are actually read from a + file or memory. This value will be filled in + even if the function fails (unless the error is + 'AW_TLE_BADPARMS'). + f The next argument is of type 'unsigned' and can + be any combination of 'AW_TLF_...' flags (above) + which control special functionality. + W The next argument is of type 'unsigned *' and + points to a variable which will receive the + width of the texture that is created. + H The next argument is of type 'unsigned *' and + points to a variable which will receive the + height of the texture that is created. + X The next argument is of type 'unsigned *' and + points to a variable which will receive the + width of the original image. + Y The next argument is of type 'unsigned *' and + points to a variable which will receive the + height of the original image. + B The next argument is of type + 'AW_BACKUPTEXTUREHANDLE *' and points to a + variable which will receive a handle that can + later be used with format specifier 'r' in a + call to this function in order to avoid + reloading from a file an image that has + previously been loaded. This value will be + filled in only if the function succeeds. When + you no longer need this handle, you should + deallocate the memory associated with it by + calling 'AwDestroyBackupTexture()'. + t The next argument is of type 'D3DTexture *' + and is used to load the new texture into an + existing texture surface. The parameter is NOT + Release()d; you should do this yourself. This is + only guaranteed to work if the new texture is of + the same height and pitch as the previous one + and compression is not used on either. + c The next two arguments indicate a callback + function which will be called if a texture cannot + be created due to insufficient video memory. The + idea is to allow the callee to free some video + memory and request further attempts at creating + the texture. The first of the two arguments is of + type AW_TL_PFN_CALLBACK and is a function pointer + to the function that would be called. This + function takes one parameter of type 'void *' + which is an implementation-specific value, and + returns type 'int', which is non-zero if another + attempt at creating the texture should be made. + If the callback function returns zero, then the + texture load will be aborted. The second of the + two arguments is of type 'void *' and is the + implementation-specific value passed to the + callback function. + a The next two arguments indicate an array of + rectangles to cut out of the original image and + create textures for each rectangle. The first of + these two arguments is of type 'unsigned' and is + the size of the array. The second argument is of + type 'AW_CREATEGRAPHICREGION *' and points to an + array of AwCreateGraphicRegion structs, each + indicating a region to cut out of the original + image and create a texture for. In this case, the + function always returns NULL, and you should test + for failure by examining awTlLastErr. The 't' + option, if used, must appear after 'a' in the + format string, and does not correspond to any + parameter, since the texture into which to + reload will be specified for each region in + the array of structures. The 'W' and 'H' options + will be ignored. For more information, see the + definition of this structure above. + + There are some restrictions on parameters: + + Exactly one of 's', 'h', 'p' or 'r' must be + used. + + Neither 'x' nor 'N' may be used with 'r'. + + 'r' cannot be used with 'B'. + + Neither 'W' or 'H' should be used with 'a'. + + Each specifier should be used only once. + + 't' may not appear before 'a'. + + There are no other restriction on the order + that the parameters occur. + + Returns: + A valid D3DTexture * if the function succeeds; + awTlLastErr will also be AW_TLE_OK + NULL if the function fails. awTlLastErr will be + AW_TLE_BADPARMS if the parameters were + incorrect, or any other error code if the + parameters were correct but another error + occurred. +*/ +extern D3DTexture * _AWTL_VARARG AwCreateTexture(char const * _argFormatS, ...); + +/* AwCreateSurface(char const * _argFormatS, ...) + + Description: + As for AwCreateTexture(), but returns a pointer to + a newly created direct draw surface which is not a + texture + + Parameters: + _argFormatS + As AwCreateTexture(), except + + t The next argument is of type 'DDSurface *' + +*/ +extern DDSurface * _AWTL_VARARG AwCreateSurface(char const * _argFormatS, ...); + +/* AwDestroyBackupTexture(AW_BACKUPTEXTUREHANDLE _bH) + + Description: + Deallocates the memory associated with a backup + texture handle, created by a call to + 'AwCreateTexture()' with a 'B' specifier. The handle + cannot be used after this. + + Parameters: + _bH + The handle whose associated memory should be + deallocated. + + Returns: + AW_TLE_OK if the function succeeds. + AW_TLE_BADPARMS if the handle was not valid. +*/ +extern AW_TL_ERC AwDestroyBackupTexture(AW_BACKUPTEXTUREHANDLE _bH); + +/* End Wrappers */ +#ifdef __cplusplus + } +#endif /* __cplusplus */ + +#endif /* ! _INCLUDED_AWTEXLD_H_ */ diff --git a/3dc/win95/awTexLd.hpp b/3dc/win95/awTexLd.hpp new file mode 100644 index 0000000..e47d87e --- /dev/null +++ b/3dc/win95/awTexLd.hpp @@ -0,0 +1,507 @@ +#ifndef _INCLUDED_AWTEXLD_HPP_ +#define _INCLUDED_AWTEXLD_HPP_ + +#include "awTexLd.h" +#include "media.hpp" +#include "db.h" +#ifndef DB_COMMA + #define DB_COMMA , +#endif + +// Nasty hack to touch the classes so MSVC++ doesn't discards them. +#ifdef _MSC_VER + extern class AwTlRegisterLoaderClass_AwBmpLoader_187 rlcAwBmpLoader_187; + + extern class AwTlRegisterLoaderClass_AwIffLoader_428 rlcAwIffLoader_428; + extern class AwTlRegisterLoaderClass_AwIffLoader_429 rlcAwIffLoader_429; + extern class AwTlRegisterLoaderClass_AwIffLoader_430 rlcAwIffLoader_430; + + extern class AwTlRegisterLoaderClass_AwPpmLoader_229 rlcAwPpmLoader_229; + extern class AwTlRegisterLoaderClass_AwPgmLoader_230 rlcAwPgmLoader_230; + extern class AwTlRegisterLoaderClass_AwPbmLoader_231 rlcAwPbmLoader_231; + + extern class RegisterChunkClassIlbmBmhdChunk_4 rccIlbmBmhdChunk_4; + extern class RegisterChunkClassIlbmCmapChunk_5 rccIlbmCmapChunk_5; + extern class RegisterChunkClassIlbmBodyChunk_6 rccIlbmBodyChunk_6; + extern class RegisterChunkClassIlbmGrabChunk_7 rccIlbmGrabChunk_7; + +#endif + +namespace AwTl { + + #define CANT_HAPPEN db_msgf1(("AwCreateTexture(): (Line %u) CAN'T HAPPEN!",__LINE__)); + + /*********************************/ + /* Pixel format global structure */ + /*********************************/ + + struct PixelFormat + { + PixelFormat() : validB(false){} + + bool palettizedB : 1; + bool alphaB : 1; + bool validB : 1; + + unsigned bitsPerPixel; + unsigned redLeftShift; + unsigned redRightShift; + unsigned greenLeftShift; + unsigned greenRightShift; + unsigned blueLeftShift; + unsigned blueRightShift; + + DDPIXELFORMAT ddpf; + }; + + // DO SOMTHING ABOUT THIS + extern PixelFormat pixelFormat; + + class CreateTextureParms; + + /********************/ + /* Colour structure */ + /********************/ + + struct Colour + { + BYTE r,g,b; + + class ConvNonTransp + { + public: + static inline unsigned DoConv (Colour const * _colP, Colour const * = NULL db_code1(DB_COMMA unsigned = 0)) + { + return + static_cast(_colP->r)>>pixelFormat.redRightShift<(_colP->g)>>pixelFormat.greenRightShift<(_colP->b)>>pixelFormat.blueRightShift<r; + unsigned bdiff = (1<b; + unsigned gdiff = (1<g; + if (bdiff<=rdiff && bdiff<=gdiff) + return 1<b && !_colP->r && !_colP->g) + //return pixelFormat.alphaB ? pixelFormat.ddsd.ddpfPixelFormat.dwRBitMask|pixelFormat.ddsd.ddpfPixelFormat.dwGBitMask|pixelFormat.ddsd.ddpfPixelFormat.dwBBitMask : 0; + return 0; + else + return MakeNonTranspCol(_colP); + } + static inline unsigned DoConv(BYTE const * _colP, Colour const * _paletteP db_code1(DB_COMMA unsigned _paletteSize)) + { + db_assert1(_paletteP); + db_onlyassert1(*_colP < _paletteSize); + if (!*_colP) + //return pixelFormat.alphaB ? pixelFormat.ddsd.ddpfPixelFormat.dwRBitMask|pixelFormat.ddsd.ddpfPixelFormat.dwGBitMask|pixelFormat.ddsd.ddpfPixelFormat.dwBBitMask : 0; + return 0; + else + return MakeNonTranspCol(&_paletteP[*_colP]); + } + }; + + class ConvNull + { + public: + static inline unsigned DoConv (BYTE const * _colP, Colour const * db_code1(DB_COMMA unsigned = 0)) + { + db_assert1(pixelFormat.palettizedB); + return *_colP; + } + }; + }; + + /*****************/ + /* Pointer union */ + /*****************/ + + union SurfUnion + { + D3DTexture * textureP; + DDSurface * surfaceP; + void * voidP; + SurfUnion(){} + SurfUnion(D3DTexture * p) : textureP(p){} + SurfUnion(DDSurface * p) : surfaceP(p){} + }; + + union PtrUnion + { + void * voidP; + char * charP; + signed char * scharP; + unsigned char * ucharP; + BYTE * byteP; + short * shortP; + unsigned short * ushortP; + WORD * wordP; + signed * intP; + unsigned * uintP; + DWORD * dwordP; + long * longP; + unsigned long * ulongP; + Colour * colourP; + + inline PtrUnion(){} + inline PtrUnion(void * _voidP):voidP(_voidP){} + inline operator void * () const { return voidP; } + }; + + union PtrUnionConst + { + void const * voidP; + char const * charP; + signed char const * scharP; + unsigned char const * ucharP; + BYTE const * byteP; + short const * shortP; + unsigned short const * ushortP; + WORD const * wordP; + signed const * intP; + unsigned const * uintP; + DWORD const * dwordP; + long const * longP; + unsigned long const * ulongP; + Colour const * colourP; + + inline PtrUnionConst(){} + inline PtrUnionConst(void const * _voidP):voidP(_voidP){} + inline PtrUnionConst(PtrUnion _uP):voidP(_uP.voidP){} + inline operator void const * () const { return voidP; } + }; + + /***************************************/ + /* Generic copying to surface function */ + /***************************************/ + + template + class GenericConvertRow + { + public: + static void Do (PtrUnion _dstRowP, unsigned _dstWidth, SRCTYPE const * _srcRowP, unsigned _srcWidth, Colour const * _paletteP = NULL db_code1(DB_COMMA unsigned _paletteSize = 0)); + }; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4701) +#endif + + template + void GenericConvertRow::Do (PtrUnion _dstRowP, unsigned _dstWidth, SRCTYPE const * _srcRowP, unsigned _srcWidth, Colour const * _paletteP db_code1(DB_COMMA unsigned _paletteSize)) + { + switch (pixelFormat.bitsPerPixel) + { + default: + CANT_HAPPEN + case 16: + { + db_assert1(!pixelFormat.palettizedB); + for (unsigned colcount = _srcWidth; colcount; --colcount) + { + *_dstRowP.wordP++ = static_cast(CONVERT::DoConv(_srcRowP++,_paletteP db_code1(DB_COMMA _paletteSize))); + } + if (_srcWidth<_dstWidth) + *_dstRowP.wordP = static_cast(CONVERT::DoConv(_srcRowP-1,_paletteP db_code1(DB_COMMA _paletteSize))); + break; + } + case 24: + { + db_assert1(!pixelFormat.palettizedB); + union { DWORD dw; BYTE b[3]; } u; + for (unsigned colcount = _srcWidth; colcount; --colcount) + { + u.dw = static_cast(CONVERT::DoConv(_srcRowP++,_paletteP db_code1(DB_COMMA _paletteSize))); + *_dstRowP.byteP++ = u.b[0]; + *_dstRowP.byteP++ = u.b[1]; + *_dstRowP.byteP++ = u.b[2]; + } + if (_srcWidth<_dstWidth) + { + *_dstRowP.byteP++ = u.b[0]; + *_dstRowP.byteP++ = u.b[1]; + *_dstRowP.byteP = u.b[2]; + } + } + case 32: + { + db_assert1(!pixelFormat.palettizedB); + for (unsigned colcount = _srcWidth; colcount; --colcount) + { + *_dstRowP.dwordP++ = static_cast(CONVERT::DoConv(_srcRowP++,_paletteP db_code1(DB_COMMA _paletteSize))); + } + if (_srcWidth<_dstWidth) + *_dstRowP.dwordP = static_cast(CONVERT::DoConv(_srcRowP-1,_paletteP db_code1(DB_COMMA _paletteSize))); + break; + } + case 8: + { + for (unsigned colcount = _srcWidth; colcount; --colcount) + { + *_dstRowP.byteP++ = static_cast(CONVERT::DoConv(_srcRowP++,_paletteP db_code1(DB_COMMA _paletteSize))); + } + if (_srcWidth<_dstWidth) + *_dstRowP.byteP = static_cast(CONVERT::DoConv(_srcRowP-1,_paletteP db_code1(DB_COMMA _paletteSize))); + break; + } + case 1: + case 2: + db_assert1(pixelFormat.palettizedB); + case 4: + { + unsigned shift=0; + unsigned val; + --_dstRowP.byteP; // decrement here because we increment before the first write + for (unsigned colcount = _srcWidth; colcount; --colcount) + { + val = CONVERT::DoConv(_srcRowP++,_paletteP db_code1(DB_COMMA _paletteSize)); + if (!shift) + *++_dstRowP.byteP = static_cast(val); + else + *_dstRowP.byteP |= static_cast(val<(val); + else + *_dstRowP.byteP |= static_cast(val<byteP; + delete[] m_ppPixMap; + } + } + else + { + if (m_ppPixMap) + { + delete[] m_ppPixMap->colourP; + delete[] m_ppPixMap; + } + } + } + + virtual Colour * GetPalette(); + + virtual PtrUnion GetRowPtr(unsigned nRow); + + virtual void LoadNextRow(PtrUnion pRow); + + // note: the palette size member must be set in + // LoadHeaderInfo() for these functions to work correctly + virtual unsigned GetNumColours(); + + virtual unsigned GetMinPaletteSize(); + + private: + PtrUnion * m_ppPixMap; + Colour * m_pPalette; + }; + + class TexFileLoader : public AwBackupTexture + { + public: + SurfUnion Load(MediaMedium * pMedium, CreateTextureParms const & rParams); + + protected: + // standard constructor + // & destructor + + // Interface Functions. Each overridden version should set awTlLastErr + // when an error occurs + + // Called to set the width and height members; the palette size member can also be safely set at this point. + // Neither the width height or palette size members need actually be set until AllocateBuffers returns + virtual void LoadHeaderInfo(MediaMedium * pMedium) = 0; + + // should ensure that the palette size is set + virtual void AllocateBuffers(bool bWantBackup, unsigned nMaxPaletteSize) = 0; + + virtual void OnFinishLoading(bool bSuccess); + + virtual AwBackupTexture * CreateBackupTexture() = 0; + }; + + class TypicalTexFileLoader : public TexFileLoader + { + protected: + TypicalTexFileLoader() : m_pRowBuf(NULL), m_ppPixMap(NULL), m_pPalette(NULL) {} + + virtual ~TypicalTexFileLoader(); + + virtual unsigned GetNumColours(); + + virtual unsigned GetMinPaletteSize(); + + virtual void AllocateBuffers(bool bWantBackup, unsigned nMaxPaletteSize); + + virtual PtrUnion GetRowPtr(unsigned nRow); + + virtual AwBackupTexture * CreateBackupTexture(); + + Colour * m_pPalette; + private: + PtrUnion * m_ppPixMap; + + PtrUnion m_pRowBuf; + }; + + extern void RegisterLoader(char const * pszMagic, AwTl::TexFileLoader * (* pfnCreate) () ); + +} // namespace AwTl + +#define AWTEXLD_IMPLEMENT_DYNCREATE(pszMagic, tokenClassName) _AWTEXLD_IMPLEMENT_DYNCREATE_LINE_EX(pszMagic,tokenClassName,__LINE__) +#define _AWTEXLD_IMPLEMENT_DYNCREATE_LINE_EX(pszMagic, tokenClassName, nLine) _AWTEXLD_IMPLEMENT_DYNCREATE_LINE(pszMagic,tokenClassName,nLine) + +#define _AWTEXLD_IMPLEMENT_DYNCREATE_LINE(pszMagic,tokenClassName,nLine) \ + AwTl::TexFileLoader * AwTlCreateClassObject ##_## tokenClassName ##_## nLine () { \ + return new tokenClassName; \ + } \ + class AwTlRegisterLoaderClass ##_## tokenClassName ##_## nLine { \ + public: AwTlRegisterLoaderClass ##_## tokenClassName ##_## nLine () { \ + AwTl::RegisterLoader(pszMagic, AwTlCreateClassObject ##_## tokenClassName ##_## nLine); \ + } \ + } rlc ## tokenClassName ##_## nLine; + +#endif // ! _INCLUDED_AWTEXLD_HPP_ diff --git a/3dc/win95/bink.c b/3dc/win95/bink.c new file mode 100644 index 0000000..6050fbe --- /dev/null +++ b/3dc/win95/bink.c @@ -0,0 +1,208 @@ +/* Bink! player, KJL 99/4/30 */ +#include "bink.h" + +#include "3dc.h" +#include "d3_func.h" + +#define UseLocalAssert 1 +#include "ourasert.h" + +extern char *ScreenBuffer; +extern LPDIRECTSOUND DSObject; +extern int GotAnyKey; +extern int IntroOutroMoviesAreActive; +extern DDPIXELFORMAT DisplayPixelFormat; + +extern void DirectReadKeyboard(void); + + +static int BinkSurfaceType; + +void PlayBinkedFMV(char *filenamePtr) +{ + BINK* binkHandle; + int playing = 1; + + if (!IntroOutroMoviesAreActive) return; + +// if (!IntroOutroMoviesAreActive) return; + BinkSurfaceType = GetBinkPixelFormat(); + + /* skip FMV if surface type not supported */ + if (BinkSurfaceType == -1) return; + + /* use Direct sound */ + BinkSoundUseDirectSound(DSObject); + /* open smacker file */ + binkHandle = BinkOpen(filenamePtr,0); + if (!binkHandle) + { + char message[100]; + sprintf(message,"Unable to access file: %s\n",filenamePtr); + MessageBox(NULL,message,"AvP Error",MB_OK+MB_SYSTEMMODAL); + exit(0x111); + return; + } + + while(playing) + { + CheckForWindowsMessages(); + if (!BinkWait(binkHandle)) + playing = NextBinkFrame(binkHandle); + + FlipBuffers(); + DirectReadKeyboard(); + if (GotAnyKey) playing = 0; + } + /* close file */ + BinkClose(binkHandle); +} + +static int NextBinkFrame(BINK *binkHandle) +{ + /* unpack frame */ + BinkDoFrame(binkHandle); + + BinkCopyToBuffer(binkHandle,(void*)ScreenBuffer,640*2,480,(640-binkHandle->Width)/2,(480-binkHandle->Height)/2,BinkSurfaceType); + + //BinkToBuffer(binkHandle,(640-binkHandle->Width)/2,(480-binkHandle->Height)/2,640*2,480,(void*)ScreenBuffer,GetBinkPixelFormat(&DisplayPixelFormat)); + + /* are we at the last frame yet? */ + if ((binkHandle->FrameNum==(binkHandle->Frames-1))) return 0; + + /* next frame, please */ + BinkNextFrame(binkHandle); + return 1; +} + +static int GetBinkPixelFormat(void) +{ + if( (DisplayPixelFormat.dwFlags & DDPF_RGB) && !(DisplayPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) ) + { + int m; + int redShift=0; + int greenShift=0; + int blueShift=0; + + m = DisplayPixelFormat.dwRBitMask; + LOCALASSERT(m); + while(!(m&1)) m>>=1; + while(m&1) + { + m>>=1; + redShift++; + } + + m = DisplayPixelFormat.dwGBitMask; + LOCALASSERT(m); + while(!(m&1)) m>>=1; + while(m&1) + { + m>>=1; + greenShift++; + } + + m = DisplayPixelFormat.dwBBitMask; + LOCALASSERT(m); + while(!(m&1)) m>>=1; + while(m&1) + { + m>>=1; + blueShift++; + } + + if(redShift == 5) + { + if (greenShift == 5) + { + if (blueShift == 5) + { + return BINKSURFACE555; + } + else // not supported + { + return -1; + } + } + else if (greenShift == 6) + { + if (blueShift == 5) + { + return BINKSURFACE565; + } + else // not supported + { + return -1; + } + } + } + else if (redShift == 6) + { + if (greenShift == 5) + { + if (blueShift == 5) + { + return BINKSURFACE655; + } + else // not supported + { + return -1; + } + } + else if (greenShift == 6) + { + if (blueShift == 4) + { + return BINKSURFACE664; + } + else // not supported + { + return -1; + } + } + } + else + { + return -1; + } + } + + return -1; +} + +BINK *MenuBackground = 0; + +extern void StartMenuBackgroundBink(void) +{ + char *filenamePtr = "fmvs/menubackground.bik";//newer.bik"; + + /* open smacker file */ + MenuBackground = BinkOpen(filenamePtr,0); + BinkSurfaceType = GetBinkPixelFormat(); + BinkDoFrame(MenuBackground); +} + +extern int PlayMenuBackgroundBink(void) +{ + int newframe = 0; + if(!MenuBackground) return 0; + + if (!BinkWait(MenuBackground)&&IntroOutroMoviesAreActive) newframe=1; + + if(newframe) BinkDoFrame(MenuBackground); + + BinkCopyToBuffer(MenuBackground,(void*)ScreenBuffer,640*2,480,(640-MenuBackground->Width)/2,(480-MenuBackground->Height)/2,BinkSurfaceType|BINKSURFACECOPYALL); + + /* next frame, please */ + if(newframe)BinkNextFrame(MenuBackground); + + return 1; +} +extern void EndMenuBackgroundBink(void) +{ + if(!MenuBackground) return; + + BinkClose(MenuBackground); + MenuBackground = 0; +} + diff --git a/3dc/win95/bink.h b/3dc/win95/bink.h new file mode 100644 index 0000000..2d5d29f --- /dev/null +++ b/3dc/win95/bink.h @@ -0,0 +1,488 @@ +#ifndef BINKH +#define BINKH + +#define BINKVERSION "0.8e" + +#ifndef __RADRES__ + +#include "bink_rad.h" + +RADDEFSTART + +typedef struct BINK PTR4* HBINK; + +typedef s32 (RADLINK PTR4* BINKIOOPEN) (struct BINKIO PTR4* Bnkio, const char PTR4 *name, u32 flags); +typedef u32 (RADLINK PTR4* BINKIOREADHEADER) (struct BINKIO PTR4* Bnkio, s32 Offset, void PTR4* Dest,u32 Size); +typedef u32 (RADLINK PTR4* BINKIOREADFRAME) (struct BINKIO PTR4* Bnkio, u32 Framenum,s32 origofs,void PTR4* dest,u32 size); +typedef u32 (RADLINK PTR4* BINKIOGETBUFFERSIZE)(struct BINKIO PTR4* Bnkio, u32 Size); +typedef void (RADLINK PTR4* BINKIOSETINFO) (struct BINKIO PTR4* Bnkio, void PTR4* Buf,u32 Size,u32 FileSize,u32 simulate); +typedef u32 (RADLINK PTR4* BINKIOIDLE) (struct BINKIO PTR4* Bnkio); +typedef void (RADLINK PTR4* BINKIOCLOSE) (struct BINKIO PTR4* Bnkio); + +typedef struct BINKIO { + BINKIOREADHEADER ReadHeader; + BINKIOREADFRAME ReadFrame; + BINKIOGETBUFFERSIZE GetBufferSize; + BINKIOSETINFO SetInfo; + BINKIOIDLE Idle; + BINKIOCLOSE Close; + HBINK bink; + volatile u32 DoingARead; + volatile u32 BytesRead; + volatile u32 TotalTime; + volatile u32 ForegroundTime; + volatile u32 BufSize; + volatile u32 BufHighUsed; + volatile u32 CurBufSize; + volatile u32 CurBufUsed; + volatile u8 iodata[128]; +} BINKIO; + +typedef s32 (RADLINK PTR4* BINKSNDOPEN) (struct BINKSND PTR4* BnkSnd, u32 freq, s32 bits, s32 chans, u32 flags, HBINK bink); +typedef void (RADLINK PTR4* BINKSNDRESET) (struct BINKSND PTR4* BnkSnd); +typedef s32 (RADLINK PTR4* BINKSNDREADY) (struct BINKSND PTR4* BnkSnd); +typedef s32 (RADLINK PTR4* BINKSNDLOCK) (struct BINKSND PTR4* BnkSnd, u8 PTR4* PTR4* addr, u32 PTR4* len); +typedef s32 (RADLINK PTR4* BINKSNDUNLOCK) (struct BINKSND PTR4* BnkSnd, u32 filled); +typedef void (RADLINK PTR4* BINKSNDVOLUME) (struct BINKSND PTR4* BnkSnd, s32 volume); +typedef void (RADLINK PTR4* BINKSNDPAN) (struct BINKSND PTR4* BnkSnd, s32 pan); +typedef s32 (RADLINK PTR4* BINKSNDOFF) (struct BINKSND PTR4* BnkSnd, s32 status); +typedef s32 (RADLINK PTR4* BINKSNDPAUSE) (struct BINKSND PTR4* BnkSnd, s32 status); +typedef void (RADLINK PTR4* BINKSNDCLOSE) (struct BINKSND PTR4* BnkSnd); + +typedef BINKSNDOPEN (RADLINK PTR4* BINKSNDSYSOPEN) (u32 param); + +typedef struct BINKSND { + BINKSNDRESET SetParam; + BINKSNDRESET Reset; + BINKSNDREADY Ready; + BINKSNDLOCK Lock; + BINKSNDUNLOCK Unlock; + BINKSNDVOLUME Volume; + BINKSNDPAN Pan; + BINKSNDPAUSE Pause; + BINKSNDOFF Off; + BINKSNDCLOSE Close; + u32 BestSizeIn16; + u32 SoundDroppedOut; + u32 freq; + s32 bits,chans; + u8 snddata[128]; +} BINKSND; + +typedef struct BINKRECT { + s32 Left,Top,Width,Height; +} BINKRECT; + +#define BINKMAXDIRTYRECTS 8 + +typedef struct BUNDLEPOINTERS { + void* typeptr; + void* type16ptr; + void* colorptr; + void* bits2ptr; + void* motionXptr; + void* motionYptr; + void* dctptr; + void* mdctptr; + void* patptr; +} BUNDLEPOINTERS; + + +typedef struct BINK { + u32 Width; // Width (1 based, 640 for example) + u32 Height; // Height (1 based, 480 for example) + u32 StretchWidth; // Default stretch width + u32 StretchHeight; // Default stretch height (used for Y double) + u32 Frames; // Number of frames (1 based, 100 = 100 frames) + u32 FrameNum; // Frame to *be* displayed (1 based) + u32 LastFrameNum; // Last frame decompressed or skipped (1 based) + + u32 FrameRate; // Frame Rate Numerator + u32 FrameRateDiv; // Frame Rate Divisor (frame rate=numerator/divisor) + + u32 ReadError; // Non-zero if a read error has ocurred + u32 OpenFlags; // flags used on open + u32 BinkType; // Bink flags + + u32 Size; // size of file + u32 FrameSize; // The current frame's size in bytes + u32 SndSize; // The current frame sound tracks' size in bytes + + BINKRECT FrameRects[BINKMAXDIRTYRECTS];// Dirty rects from BinkGetRects + s32 NumRects; + + u32 YPlaneNum; // which YPlane is current + void PTR4* YPlane[2]; // pointer to the uncompressed Y (Cr and Cr follow) + u32 YWidth; // widths and heights of the video planes + u32 YHeight; + u32 UVWidth; + u32 UVHeight; + + void PTR4* MaskPlane; // pointer to the mask plane (Ywidth/16*Yheight/16) + u32 MaskPitch; // Mask Pitch + u32 MaskLength; // total length of the mask plane + + u32 LargestFrameSize; // Largest frame size + u32 InternalFrames; // how many frames were potentially compressed + + s32 NumTracks; // how many tracks + + u32 Highest1SecRate; // Highest 1 sec data rate + u32 Highest1SecFrame; // Highest 1 sec data rate starting frame + + s32 Paused; // is the bink movie paused? + + u32 BackgroundThread; // handle to background thread + + // everything below is for internal Bink use + + void PTR4* compframe; // compressed frame data + void PTR4* preloadptr; // preloaded compressed frame data + u32* frameoffsets; // offsets of each of the frames + + BINKIO bio; // IO structure + u8 PTR4* ioptr; // io buffer ptr + u32 iosize; // io buffer size + u32 decompheight; // height not include interlacing + + s32 trackindex; // track index + u32 PTR4* tracksizes; // largest single frame of track + u32 PTR4* tracktypes; // type of each sound track + s32 PTR4* trackIDs; // external track numbers + + u32 numrects; // number of rects from BinkGetRects + + u32 playedframes; // how many frames have we played + u32 firstframetime; // very first frame start + u32 startframetime; // start frame start + u32 startblittime; // start of blit period + u32 startsynctime; // start of synched time + u32 startsyncframe; // frame of startsynctime + u32 twoframestime; // two frames worth of time + u32 entireframetime; // entire frame time + + u32 slowestframetime; // slowest frame in ms + u32 slowestframe; // slowest frame number + u32 slowest2frametime; // second slowest frame in ms + u32 slowest2frame; // second slowest frame + + u32 soundon; // sound turned on? + u32 videoon; // video turned on? + + u32 totalmem; // total memory used + u32 timedecomp; // total time decompressing + u32 timeblit; // total time blitting + u32 timeopen; // total open time + + u32 fileframerate; // frame rate originally in the file + u32 fileframeratediv; + + u32 threadcontrol; // controls the background reading thread + + u32 runtimeframes; // max frames for runtime analysis + u32 runtimemoveamt; // bytes to move each frame + u32 PTR4* rtframetimes; // start times for runtime frames + u32 PTR4* rtdecomptimes; // decompress times for runtime frames + u32 PTR4* rtblittimes; // blit times for runtime frames + u32 PTR4* rtreadtimes; // read times for runtime frames + + u32 lastdecompframe; // last frame number decompressed + + u32 sndbufsize; // sound buffer size + u8 PTR4* sndbuf; // sound buffer + u8 PTR4* sndend; // end of the sound buffer + u8 PTR4* sndwritepos; // current write position + u8 PTR4* sndreadpos; // current read position + u32 sndcomp; // sound compression handle + u32 sndamt; // amount of sound currently in the buffer + volatile u32 sndreenter; // re-entrancy check on the sound + u32 sndconvert8; // convert back to 8-bit sound at runtime + BINKSND bsnd; // SND structure + u32 skippedlastblit; // skipped last frame? + u32 skippedblits; // how many blits were skipped + u32 soundskips; // number of sound stops + + BUNDLEPOINTERS bunp; // pointers to internal temporary memory +} BINK; + + +typedef struct BINKSUMMARY { + u32 Width; // Width of frames + u32 Height; // Height of frames + u32 TotalTime; // total time (ms) + u32 FileFrameRate; // frame rate + u32 FileFrameRateDiv; // frame rate divisor + u32 FrameRate; // frame rate + u32 FrameRateDiv; // frame rate divisor + u32 TotalOpenTime; // Time to open and prepare for decompression + u32 TotalFrames; // Total Frames + u32 TotalPlayedFrames; // Total Frames played + u32 SkippedFrames; // Total number of skipped frames + u32 SkippedBlits; // Total number of skipped blits + u32 SoundSkips; // Total number of sound skips + u32 TotalBlitTime; // Total time spent blitting + u32 TotalReadTime; // Total time spent reading + u32 TotalDecompTime; // Total time spent decompressing + u32 TotalBackReadTime; // Total time spent reading in background + u32 TotalReadSpeed; // Total io speed (bytes/second) + u32 SlowestFrameTime; // Slowest single frame time (ms) + u32 Slowest2FrameTime; // Second slowest single frame time (ms) + u32 SlowestFrameNum; // Slowest single frame number + u32 Slowest2FrameNum; // Second slowest single frame number + u32 AverageDataRate; // Average data rate of the movie + u32 AverageFrameSize; // Average size of the frame + u32 HighestMemAmount; // Highest amount of memory allocated + u32 TotalIOMemory; // Total extra memory allocated + u32 HighestIOUsed; // Highest extra memory actually used + u32 Highest1SecRate; // Highest 1 second rate + u32 Highest1SecFrame; // Highest 1 second start frame +} BINKSUMMARY; + + +typedef struct BINKREALTIME { + u32 FrameNum; // Current frame number + u32 FrameRate; // frame rate + u32 FrameRateDiv; // frame rate divisor + u32 Frames; // frames in this sample period + u32 FramesTime; // time is ms for these frames + u32 FramesDecompTime; // time decompressing these frames + u32 FramesReadTime; // time reading these frames + u32 FramesBlitTime; // time blitting these frames + u32 ReadBufferSize; // size of read buffer + u32 ReadBufferUsed; // amount of read buffer currently used + u32 FramesDataRate; // data rate for these frames +} BINKREALTIME; + +#define BINKMARKER 'fKIB' + +typedef struct BINKHDR { + u32 Marker; // BNKa + u32 Size; // size of the file-8 + u32 Frames; // Number of frames (1 based, 100 = 100 frames) + u32 LargestFrameSize; // Size in bytes of largest frame + u32 InternalFrames; // Number of internal frames + + u32 Width; // Width (1 based, 640 for example) + u32 Height; // Height (1 based, 480 for example) + u32 FrameRate; // frame rate + u32 FrameRateDiv; // frame rate divisor (framerate/frameratediv=fps) + + u32 Flags; // height compression options + u32 NumTracks; // number of tracks +} BINKHDR; + + +//======================================================================= +#define BINKFRAMERATE 0x00080000L // Override fr (call BinkFrameRate first) +#define BINKPRELOADALL 0x00100000L // Preload the entire animation +#define BINKSNDTRACK 0x00200000L // Set the track number to play +#define BINKNOSKIP 0x00400000L // Don't skip frames if falling behind +#define BINKNOFILLIOBUF 0x00800000L // Fill the IO buffer in SmackOpen +#define BINKSIMULATE 0x01000000L // Simulate the speed (call BinkSim first) +#define BINKFILEHANDLE 0x02000000L // Use when passing in a file handle +#define BINKIOSIZE 0x04000000L // Set an io size (call BinkIOSize first) +#define BINKIOPROCESSOR 0x08000000L // Set an io processor (call BinkIO first) +#define BINKFROMMEMORY 0x40000000L // Use when passing in a pointer to the file +#define BINKNOTHREADEDIO 0x80000000L // Don't use a background thread for IO + +#define BINKSURFACEYINTERLACE 0x20000000L // Force interleaving Y scaling +#define BINKSURFACEYDOUBLE 0x10000000L // Force doubling Y scaling +#define BINKSURFACEYFORCENONE 0x30000000L // Force Y scaling off + +#define BINKSURFACEFAST 0x00000000L +#define BINKSURFACESLOW 0x80000000L +#define BINKSURFACEDIRECT 0x40000000L + +#define BINKSURFACEFLIPPED 0x08000000L +#define BINKSURFACECOPYALL 0x04000000L // copy all pixels (not just changed) +#define BINKSURFACENOSKIP 0x01000000L // don't skip the blit if behind in sound + +#define BINKSURFACE24 0 +#define BINKSURFACE32 1 +#define BINKSURFACE555 2 +#define BINKSURFACE565 3 +#define BINKSURFACE655 4 +#define BINKSURFACE664 5 +#define BINKSURFACE8P 6 +#define BINKSURFACEYUY2 7 +#define BINKSURFACEUYVY 8 +#define BINKSURFACEYV12 9 +#define BINKSURFACEMASK 15 + +#define BINKGOTOQUICK 1 + +#define BINKGETKEYPREVIOUS 0 +#define BINKGETKEYNEXT 1 +#define BINKGETKEYCLOSEST 2 +#define BINKGETKEYNOTEQUAL 128 + +//======================================================================= + +RADEXPFUNC void PTR4* RADEXPLINK BinkLogoAddress(void); + +RADEXPFUNC void RADEXPLINK BinkSetError(const char PTR4* err); +RADEXPFUNC char PTR4* RADEXPLINK BinkGetError(void); + +RADEXPFUNC HBINK RADEXPLINK BinkOpen(const char PTR4* name,u32 flags); + +#ifdef __RADMAC__ + #include + + RADEXPFUNC HBINK RADEXPLINK BinkMacOpen(FSSpec* fsp,u32 flags); +#endif + +RADEXPFUNC u32 RADEXPLINK BinkDoFrame(HBINK bnk); +RADEXPFUNC void RADEXPLINK BinkNextFrame(HBINK bnk); +RADEXPFUNC s32 RADEXPLINK BinkWait(HBINK bnk); +RADEXPFUNC void RADEXPLINK BinkClose(HBINK bnk); +RADEXPFUNC s32 RADEXPLINK BinkPause(HBINK bnk,s32 pause); +RADEXPFUNC s32 RADEXPLINK BinkCopyToBuffer(HBINK bnk,void* dest,u32 destpitch,u32 destheight,u32 destx,u32 desty,u32 flags); +RADEXPFUNC s32 RADEXPLINK BinkGetRects(HBINK bnk,u32 surfacetype); +RADEXPFUNC void RADEXPLINK BinkGoto(HBINK bnk,u32 frame,s32 flags); // use 1 for the first frame +RADEXPFUNC u32 RADEXPLINK BinkGetKeyFrame(HBINK bnk,u32 frame,s32 flags); + +RADEXPFUNC u32 RADEXPLINK BinkSetVideoOnOff(HBINK bnk,s32 onoff); +RADEXPFUNC u32 RADEXPLINK BinkSetSoundOnOff(HBINK bnk,s32 onoff); +RADEXPFUNC void RADEXPLINK BinkSetVolume(HBINK bnk,s32 volume); +RADEXPFUNC void RADEXPLINK BinkSetPan(HBINK bnk,s32 pan); +RADEXPFUNC void RADEXPLINK BinkService(HBINK bink); + +RADEXPFUNC u32 RADEXPLINK BinkGetTrackType(HBINK bnk,u32 trackindex); +RADEXPFUNC u32 RADEXPLINK BinkGetTrackID(HBINK bnk,u32 trackindex); +RADEXPFUNC u32 RADEXPLINK BinkGetTrackData(HBINK bnk,void PTR4* dest,u32 trackindex); + +RADEXPFUNC void RADEXPLINK BinkGetSummary(HBINK bnk,BINKSUMMARY PTR4* sum); +RADEXPFUNC void RADEXPLINK BinkGetRealtime(HBINK bink,BINKREALTIME PTR4* run,u32 frames); + +#define BINKNOSOUND 0xffffffff + +RADEXPFUNC void RADEXPLINK BinkSetSoundTrack(u32 track); +RADEXPFUNC void RADEXPLINK BinkSetIO(BINKIOOPEN io); +RADEXPFUNC void RADEXPLINK BinkSetFrameRate(u32 forcerate,u32 forceratediv); +RADEXPFUNC void RADEXPLINK BinkSetSimulate(u32 sim); +RADEXPFUNC void RADEXPLINK BinkSetIOSize(u32 iosize); + +RADEXPFUNC s32 RADEXPLINK BinkSetSoundSystem(BINKSNDSYSOPEN open, u32 param); + +#ifdef __RADWIN__ + + RADEXPFUNC BINKSNDOPEN RADEXPLINK BinkOpenDirectSound(u32 param); // don't call directly + #define BinkSoundUseDirectSound(lpDS) BinkSetSoundSystem(BinkOpenDirectSound,(u32)lpDS) + + #define BinkTimerSetup() + #define BinkTimerDone() + #define BinkTimerRead timeGetTime + + #define INCLUDE_MMSYSTEM_H + #include "windows.h" + #include "windowsx.h" + + #ifdef __RADNT__ // to combat WIN32_LEAN_AND_MEAN + + #include "mmsystem.h" + + RADEXPFUNC s32 RADEXPLINK BinkDDSurfaceType(void PTR4* lpDDS); + + #endif + +#endif + +#ifndef __RADMAC__ + + RADEXPFUNC BINKSNDOPEN RADEXPLINK BinkOpenMiles(u32 param); // don't call directly + #define BinkSoundUseMiles(hdigdriver) BinkSetSoundSystem(BinkOpenMiles,(u32)hdigdriver) + +#endif + + +#ifndef __RADDOS__ + +//========================================================================= +typedef struct BINKBUFFER * HBINKBUFFER; + +typedef struct BINKBUFFER { + u32 Width; + u32 Height; + u32 WindowWidth; + u32 WindowHeight; + u32 SurfaceType; + void* Buffer; + u32 BufferPitch; + s32 ClientOffsetX; + s32 ClientOffsetY; + u32 ScreenWidth; + u32 ScreenHeight; + u32 ScreenDepth; + u32 ExtraWindowWidth; + u32 ExtraWindowHeight; + u32 ScaleFlags; + u32 StretchWidth; + u32 StretchHeight; + + s32 surface; + void* ddsurface; + void* ddclipper; + s32 destx,desty; + u32 HWND; + s32 ddoverlay; + s32 ddoffscreen; + s32 lastovershow; + + s32 issoftcur; + u32 cursorcount; + void* buffertop; + u32 type; + s32 noclipping; + +} BINKBUFFER; + + +#define BINKBUFFERSTRETCHXINT 0x80000000 +#define BINKBUFFERSTRETCHX 0x40000000 +#define BINKBUFFERSHRINKXINT 0x20000000 +#define BINKBUFFERSHRINKX 0x10000000 +#define BINKBUFFERSTRETCHYINT 0x08000000 +#define BINKBUFFERSTRETCHY 0x04000000 +#define BINKBUFFERSHRINKYINT 0x02000000 +#define BINKBUFFERSHRINKY 0x01000000 +#define BINKBUFFERRESOLUTION 0x00800000 + +#define BINKBUFFERAUTO 0 +#define BINKBUFFERPRIMARY 1 +#define BINKBUFFERYV12OVERLAY 2 +#define BINKBUFFERYUY2OVERLAY 3 +#define BINKBUFFERUYVYOVERLAY 4 +#define BINKBUFFERYV12OFFSCREEN 5 +#define BINKBUFFERYUY2OFFSCREEN 6 +#define BINKBUFFERUYVYOFFSCREEN 7 +#define BINKBUFFERRGBOFFSCREENVIDEO 8 +#define BINKBUFFERRGBOFFSCREENSYSTEM 9 +#define BINKBUFFERDRAWDIB 10 +#define BINKBUFFERTYPEMASK 31 + +RADEXPFUNC HBINKBUFFER RADEXPLINK BinkBufferOpen( HWND wnd, u32 width, u32 height, u32 bufferflags); +RADEXPFUNC void RADEXPLINK BinkBufferClose( HBINKBUFFER buf); +RADEXPFUNC s32 RADEXPLINK BinkBufferLock( HBINKBUFFER buf); +RADEXPFUNC s32 RADEXPLINK BinkBufferUnlock( HBINKBUFFER buf); +RADEXPFUNC void RADEXPLINK BinkBufferSetResolution( s32 w, s32 h, s32 bits); +RADEXPFUNC void RADEXPLINK BinkBufferCheckWinPos( HBINKBUFFER buf, s32 PTR4* destx, s32 PTR4* desty); +RADEXPFUNC s32 RADEXPLINK BinkBufferSetOffset( HBINKBUFFER buf, s32 destx, s32 desty); +RADEXPFUNC void RADEXPLINK BinkBufferBlit( HBINKBUFFER buf, BINKRECT PTR4* rects, u32 numrects ); +RADEXPFUNC s32 RADEXPLINK BinkBufferSetScale( HBINKBUFFER buf, u32 w, u32 h); +RADEXPFUNC s32 RADEXPLINK BinkBufferSetHWND( HBINKBUFFER buf, HWND newwnd); +RADEXPFUNC char PTR4* RADEXPLINK BinkBufferDescription( HBINKBUFFER buf); +RADEXPFUNC char PTR4* RADEXPLINK BinkBufferGetError(); + +RADEXPFUNC s32 RADEXPLINK BinkDDSurfaceType(void PTR4* lpDDS); +RADEXPFUNC s32 RADEXPLINK BinkIsSoftwareCursor(void PTR4* lpDDSP,HCURSOR cur); +RADEXPFUNC s32 RADEXPLINK BinkCheckCursor(HWND wnd,s32 x,s32 y,s32 w,s32 h); +RADEXPFUNC void RADEXPLINK BinkRestoreCursor(s32 checkcount); + +#endif + +RADDEFEND + +#endif + +#endif + diff --git a/3dc/win95/bink_Rad.h b/3dc/win95/bink_Rad.h new file mode 100644 index 0000000..bfbc07e --- /dev/null +++ b/3dc/win95/bink_Rad.h @@ -0,0 +1,699 @@ +#ifndef __RAD__ +#define __RAD__ + +#define RADCOPYRIGHT "Copyright (C) 1994-99 RAD Game Tools, Inc." + +#ifndef __RADRES__ + +// __RADDOS__ means DOS code (16 or 32 bit) +// __RAD16__ means 16 bit code (Win16) +// __RAD32__ means 32 bit code (DOS, Win386, Win32s, Mac) +// __RADWIN__ means Windows code (Win16, Win386, Win32s) +// __RADWINEXT__ means Windows 386 extender (Win386) +// __RADNT__ means Win32s code +// __RADMAC__ means Macintosh +// __RAD68K__ means 68K Macintosh +// __RADPPC__ means PowerMac + + +#if (defined(__MWERKS__) && !defined(__INTEL__)) || defined(THINK_C) || defined(powerc) || defined(macintosh) || defined(__powerc) + + #define __RADMAC__ + #if defined(powerc) || defined(__powerc) + #define __RADPPC__ + #else + #define __RAD68K__ + #endif + + #define __RAD32__ + +#else + + #ifdef __MWERKS__ + #define _WIN32 + #endif + + #ifdef __DOS__ + #define __RADDOS__ + #endif + + #ifdef __386__ + #define __RAD32__ + #endif + + #ifdef _Windows //For Borland + #ifdef __WIN32__ + #define WIN32 + #else + #define __WINDOWS__ + #endif + #endif + + #ifdef _WINDOWS //For MS + #ifndef _WIN32 + #define __WINDOWS__ + #endif + #endif + + #ifdef _WIN32 + #define __RADWIN__ + #define __RADNT__ + #define __RAD32__ + #else + #ifdef __NT__ + #define __RADWIN__ + #define __RADNT__ + #define __RAD32__ + #else + #ifdef __WINDOWS_386__ + #define __RADWIN__ + #define __RADWINEXT__ + #define __RAD32__ + #else + #ifdef __WINDOWS__ + #define __RADWIN__ + #define __RAD16__ + #else + #ifdef WIN32 + #define __RADWIN__ + #define __RADNT__ + #define __RAD32__ + #endif + #endif + #endif + #endif + #endif + +#endif + +#if (!defined(__RADDOS__) && !defined(__RADWIN__) && !defined(__RADMAC__)) + #error RAD.H did not detect your platform. Define __DOS__, __WINDOWS__, WIN32, macintosh, or powerc. +#endif + +#ifdef __RADMAC__ + + // this define is for CodeWarrior 11's stupid new libs (even though + // we don't use longlong's). + + #define __MSL_LONGLONG_SUPPORT__ + + #define RADLINK + #define RADEXPLINK + + #ifdef __CFM68K__ + #ifdef __RADINDLL__ + #define RADEXPFUNC RADDEFFUNC __declspec(export) + #else + #define RADEXPFUNC RADDEFFUNC __declspec(import) + #endif + #else + #define RADEXPFUNC RADDEFFUNC + #endif + #define RADASMLINK + +#else + + #ifdef __RADNT__ + #ifndef _WIN32 + #define _WIN32 + #endif + #ifndef WIN32 + #define WIN32 + #endif + #endif + + #ifdef __RADWIN__ + #ifdef __RAD32__ + #ifdef __RADNT__ + + #define RADLINK __stdcall + #define RADEXPLINK __stdcall + + #ifdef __RADINEXE__ + #define RADEXPFUNC RADDEFFUNC + #else + #ifndef __RADINDLL__ + #define RADEXPFUNC RADDEFFUNC __declspec(dllimport) + #ifdef __BORLANDC__ + #if __BORLANDC__<=0x460 + #undef RADEXPFUNC + #define RADEXPFUNC RADDEFFUNC + #endif + #endif + #else + #define RADEXPFUNC RADDEFFUNC __declspec(dllexport) + #endif + #endif + #else + #define RADLINK __pascal + #define RADEXPLINK __far __pascal + #define RADEXPFUNC RADDEFFUNC + #endif + #else + #define RADLINK __pascal + #define RADEXPLINK __far __pascal __export + #define RADEXPFUNC RADDEFFUNC + #endif + #else + #define RADLINK __pascal + #define RADEXPLINK __pascal + #define RADEXPFUNC RADDEFFUNC + #endif + + #define RADASMLINK __cdecl + +#endif + +#ifdef __RADWIN__ + #ifndef _WINDOWS + #define _WINDOWS + #endif +#endif + +#ifdef __cplusplus + #define RADDEFFUNC extern "C" + #define RADDEFSTART extern "C" { + #define RADDEFEND } +#else + #define RADDEFFUNC + #define RADDEFSTART + #define RADDEFEND +#endif + + +RADDEFSTART + +#define s8 signed char +#define u8 unsigned char +#define u32 unsigned long +#define s32 signed long +#define u64 unsigned __int64 +#define s64 signed __int64 +#define f32 float +#define f64 double + + +#ifdef __RAD32__ + #define PTR4 + + #define u16 unsigned short + #define s16 signed short + + #ifdef __RADMAC__ + + #include + #include + #include + + #define radstrlen strlen + + #define radmemset memset + + #define radmemcmp memcmp + + #define radmemcpy(dest,source,size) BlockMoveData((Ptr)(source),(Ptr)(dest),size) + + #define radmemcpydb(dest,source,size) BlockMoveData((Ptr)(source),(Ptr)(dest),size) + + #define radstrcat strcat + + #define radstrcpy strcpy + + static u32 inline radsqr(s32 a) { return(a*a); } + + #ifdef __RAD68K__ + + #pragma parameter __D0 mult64anddiv(__D0,__D1,__D2) + u32 mult64anddiv(u32 m1,u32 m2,u32 d) ={0x4C01,0x0C01,0x4C42,0x0C01}; + // muls.l d1,d1:d0 divs.l d2,d1:d0 + + #pragma parameter radconv32a(__A0,__D0) + void radconv32a(void* p,u32 n) ={0x4A80,0x600C,0x2210,0xE059,0x4841,0xE059,0x20C1,0x5380,0x6EF2}; + // tst.l d0 bra.s @loope @loop: move.l (a0),d1 ror.w #8,d1 swap d1 ror.w #8,d1 move.l d1,(a0)+ sub.l #1,d0 bgt.s @loop @loope: + + #else + + u32 mult64anddiv(u32 m1,u32 m2,u32 d); + + void radconv32a(void* p,u32 n); + + #endif + + #else + + #ifdef __WATCOMC__ + + u32 radsqr(s32 a); + #pragma aux radsqr = "mul eax" parm [eax] modify [EDX eax]; + + u32 mult64anddiv(u32 m1,u32 m2,u32 d); + #pragma aux mult64anddiv = "mul ecx" "div ebx" parm [eax] [ecx] [ebx] modify [EDX eax]; + + s32 radabs(s32 ab); + #pragma aux radabs = "test eax,eax" "jge skip" "neg eax" "skip:" parm [eax]; + + #define radabs32 radabs + + u32 DOSOut(const char* str); + #pragma aux DOSOut = "cld" "mov ecx,0xffffffff" "xor eax,eax" "mov edx,edi" "repne scasb" "not ecx" "dec ecx" "mov ebx,1" "mov ah,0x40" "int 0x21" parm [EDI] modify [EAX EBX ECX EDX EDI] value [ecx]; + + void DOSOutNum(const char* str,u32 len); + #pragma aux DOSOutNum = "mov ah,0x40" "mov ebx,1" "int 0x21" parm [edx] [ecx] modify [eax ebx]; + + u32 ErrOut(const char* str); + #pragma aux ErrOut = "cld" "mov ecx,0xffffffff" "xor eax,eax" "mov edx,edi" "repne scasb" "not ecx" "dec ecx" "xor ebx,ebx" "mov ah,0x40" "int 0x21" parm [EDI] modify [EAX EBX ECX EDX EDI] value [ecx]; + + void ErrOutNum(const char* str,u32 len); + #pragma aux ErrOutNum = "mov ah,0x40" "xor ebx,ebx" "int 0x21" parm [edx] [ecx] modify [eax ebx]; + + void radmemset16(void* dest,u16 value,u32 size); + #pragma aux radmemset16 = "cld" "mov bx,ax" "shl eax,16" "mov ax,bx" "mov bl,cl" "shr ecx,1" "rep stosd" "mov cl,bl" "and cl,1" "rep stosw" parm [EDI] [EAX] [ECX] modify [EAX EDX EBX ECX EDI]; + + void radmemset(void* dest,u8 value,u32 size); + #pragma aux radmemset = "cld" "mov ah,al" "mov bx,ax" "shl eax,16" "mov ax,bx" "mov bl,cl" "shr ecx,2" "and bl,3" "rep stosd" "mov cl,bl" "rep stosb" parm [EDI] [AL] [ECX] modify [EAX EDX EBX ECX EDI]; + + void radmemset32(void* dest,u32 value,u32 size); + #pragma aux radmemset32 = "cld" "rep stosd" parm [EDI] [EAX] [ECX] modify [EAX EDX EBX ECX EDI]; + + void radmemcpy(void* dest,const void* source,u32 size); + #pragma aux radmemcpy = "cld" "mov bl,cl" "shr ecx,2" "rep movsd" "mov cl,bl" "and cl,3" "rep movsb" parm [EDI] [ESI] [ECX] modify [EBX ECX EDI ESI]; + + void __far *radfmemcpy(void __far* dest,const void __far* source,u32 size); + #pragma aux radfmemcpy = "cld" "push es" "push ds" "mov es,cx" "mov ds,dx" "mov ecx,eax" "shr ecx,2" "rep movsd" "mov cl,al" "and cl,3" "rep movsb" "pop ds" "pop es" parm [CX EDI] [DX ESI] [EAX] modify [ECX EDI ESI] value [CX EDI]; + + void radmemcpydb(void* dest,const void* source,u32 size); //Destination bigger + #pragma aux radmemcpydb = "std" "mov bl,cl" "lea esi,[esi+ecx-4]" "lea edi,[edi+ecx-4]" "shr ecx,2" "rep movsd" "and bl,3" "jz dne" "add esi,3" "add edi,3" "mov cl,bl" "rep movsb" "dne:" "cld" parm [EDI] [ESI] [ECX] modify [EBX ECX EDI ESI]; + + char* radstrcpy(void* dest,const void* source); + #pragma aux radstrcpy = "cld" "mov edx,edi" "lp:" "mov al,[esi]" "inc esi" "mov [edi],al" "inc edi" "cmp al,0" "jne lp" parm [EDI] [ESI] modify [EAX EDX EDI ESI] value [EDX]; + + char __far* radfstrcpy(void __far* dest,const void __far* source); + #pragma aux radfstrcpy = "cld" "push es" "push ds" "mov es,cx" "mov ds,dx" "mov edx,edi" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "pop ds" "pop es" parm [CX EDI] [DX ESI] modify [EAX EDX EDI ESI] value [CX EDX]; + + char* radstpcpy(void* dest,const void* source); + #pragma aux radstpcpy = "cld" "lp:" "mov al,[esi]" "inc esi" "mov [edi],al" "inc edi" "cmp al,0" "jne lp" "dec edi" parm [EDI] [ESI] modify [EAX EDI ESI] value [EDI]; + + char* radstpcpyrs(void* dest,const void* source); + #pragma aux radstpcpyrs = "cld" "lp:" "mov al,[esi]" "inc esi" "mov [edi],al" "inc edi" "cmp al,0" "jne lp" "dec esi" parm [EDI] [ESI] modify [EAX EDI ESI] value [ESI]; + + u32 radstrlen(const void* dest); + #pragma aux radstrlen = "cld" "mov ecx,0xffffffff" "xor eax,eax" "repne scasb" "not ecx" "dec ecx" parm [EDI] modify [EAX ECX EDI] value [ECX]; + + char* radstrcat(void* dest,const void* source); + #pragma aux radstrcat = "cld" "mov ecx,0xffffffff" "mov edx,edi" "xor eax,eax" "repne scasb" "dec edi" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" \ + parm [EDI] [ESI] modify [EAX ECX EDI ESI] value [EDX]; + + char* radstrchr(const void* dest,char chr); + #pragma aux radstrchr = "cld" "lp:" "lodsb" "cmp al,dl" "je fnd" "cmp al,0" "jnz lp" "mov esi,1" "fnd:" "dec esi" parm [ESI] [DL] modify [EAX ESI] value [esi]; + + s8 radmemcmp(const void* s1,const void* s2,u32 len); + #pragma aux radmemcmp = "cld" "rep cmpsb" "setne al" "jbe end" "neg al" "end:" parm [EDI] [ESI] [ECX] modify [ECX EDI ESI]; + + s8 radstrcmp(const void* s1,const void* s2); + #pragma aux radstrcmp = "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,ah" "jne set" "cmp al,0" "je set" "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" \ + parm [EDI] [ESI] modify [EAX EDI ESI]; + + s8 radstricmp(const void* s1,const void* s2); + #pragma aux radstricmp = "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" "cmp ah,'a'" "jb c2" "cmp ah,'z'" "ja c2" "sub ah,32" "c2:" "cmp al,ah" "jne set" "cmp al,0" "je set" \ + "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" \ + parm [EDI] [ESI] modify [EAX EDI ESI]; + + s8 radstrnicmp(const void* s1,const void* s2,u32 len); + #pragma aux radstrnicmp = "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" "cmp ah,'a'" "jb c2" "cmp ah,'z'" "ja c2" "sub ah,32" "c2:" "cmp al,ah" "jne set" "cmp al,0" "je set" \ + "dec ecx" "jz set" "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" \ + parm [EDI] [ESI] [ECX] modify [EAX ECX EDI ESI]; + + char* radstrupr(void* s1); + #pragma aux radstrupr = "mov ecx,edi" "lp:" "mov al,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub [edi],32" "c1:" "inc edi" "cmp al,0" "jne lp" parm [EDI] modify [EAX EDI] value [ecx]; + + char* radstrlwr(void* s1); + #pragma aux radstrlwr = "mov ecx,edi" "lp:" "mov al,[edi]" "cmp al,'A'" "jb c1" "cmp al,'Z'" "ja c1" "add [edi],32" "c1:" "inc edi" "cmp al,0" "jne lp" parm [EDI] modify [EAX EDI] value [ecx]; + + u32 radstru32(const void* dest); + #pragma aux radstru32 = "cld" "xor ecx,ecx" "xor ebx,ebx" "xor edi,edi" "lodsb" "cmp al,45" "jne skip2" "mov edi,1" "jmp skip" "lp:" "mov eax,10" "mul ecx" "lea ecx,[eax+ebx]" \ + "skip:" "lodsb" "skip2:" "cmp al,0x39" "ja dne" "cmp al,0x30" "jb dne" "mov bl,al" "sub bl,0x30" "jmp lp" "dne:" "test edi,1" "jz pos" "neg ecx" "pos:" \ + parm [ESI] modify [EAX EBX EDX EDI ESI] value [ecx]; + + u16 GetDS(); + #pragma aux GetDS = "mov ax,ds" value [ax]; + + #ifdef __RADWINEXT__ + + #define _16To32(ptr16) ((void*)(((GetSelectorBase((u16)(((u32)(ptr16))>>16))+((u16)(u32)(ptr16)))-GetSelectorBase(GetDS())))) + + #endif + + #ifndef __RADWIN__ + #define int86 int386 + #define int86x int386x + #endif + + #define u32regs x + #define u16regs w + + #else + + #define radstrcpy strcpy + #define radstrcat strcat + #define radmemcpy memcpy + #define radmemcpydb memmove + #define radmemcmp memcmp + #define radmemset memset + #define radstrlen strlen + #define radstrchr strchr + #define radtoupper toupper + #define radstru32(s) ((u32)atol(s)) + #define radstricmp _stricmp + #define radstrcmp strcmp + #define radstrupr _strupr + #define radstrlwr _strlwr + #define BreakPoint() __asm {int 3} + + #ifdef _MSC_VER + + #pragma warning( disable : 4035) + + typedef char* RADPCHAR; + + u32 __inline radsqr(u32 m) { + __asm { + mov eax,[m] + mul eax + } + } + + u32 __inline mult64anddiv(u32 m1,u32 m2, u32 d) { + __asm { + mov eax,[m1] + mov ecx,[m2] + mul ecx + mov ecx,[d] + div ecx + } + } + + s32 __inline radabs(s32 ab) { + __asm { + mov eax,[ab] + test eax,eax + jge skip + neg eax + skip: + } + } + + u8 __inline radinp(u16 p) { + __asm { + mov dx,[p] + in al,dx + } + } + + void __inline radoutp(u16 p,u8 v) { + __asm { + mov dx,[p] + mov al,[v] + out dx,al + } + } + + RADPCHAR __inline radstpcpy(char* p1, char* p2) { + __asm { + mov edx,[p1] + mov ecx,[p2] + cld + lp: + mov al,[ecx] + inc ecx + mov [edx],al + inc edx + cmp al,0 + jne lp + dec edx + mov eax,edx + } + } + + RADPCHAR __inline radstpcpyrs(char* p1, char* p2) { + __asm { + mov edx,[p1] + mov ecx,[p2] + cld + lp: + mov al,[ecx] + inc ecx + mov [edx],al + inc edx + cmp al,0 + jne lp + dec ecx + mov eax,ecx + } + } + + void __inline radmemset16(void* dest,u16 value,u32 sizeb) { + __asm { + mov edi,[dest] + mov ax,[value] + mov ecx,[sizeb] + shl eax,16 + cld + mov ax,[value] + mov bl,cl + shr ecx,1 + rep stosd + mov cl,bl + and cl,1 + rep stosw + } + } + + void __inline radmemset32(void* dest,u32 value,u32 sizeb) { + __asm { + mov edi,[dest] + mov eax,[value] + mov ecx,[sizeb] + cld + rep stosd + } + } + + u32 __inline __stdcall RADsqrt(u32 sq) { + __asm { + fild dword ptr [sq] + fsqrt + fistp word ptr [sq] + movzx eax,word ptr [sq] + } + } + + void __inline RADCycleTimerStartAddr(u32* addr) + { + __asm { + mov ecx,[addr] +#ifdef __MWERKS__ + rdtsc +#else +#if _MSC_VER<=1100 + __emit 0xf + __emit 0x31 +#else + rdtsc +#endif +#endif + mov [ecx],eax + } + } + + u32 __inline RADCycleTimerDeltaAddr(u32* addr) + { + __asm { +#ifdef __MWERKS__ + rdtsc +#else +#if _MSC_VER<=1100 + __emit 0xf + __emit 0x31 +#else + rdtsc +#endif +#endif + mov ecx,[addr] + sub eax,[ecx] + mov [ecx],eax + } + } + + #define RADCycleTimerStart(var) RADCycleTimerStartAddr(&var) + #define RADCycleTimerDelta(var) RADCycleTimerDeltaAddr(&var) + + #pragma warning( default : 4035) + + #endif + + #endif + + #endif + +#else + + #define PTR4 __far + + #define u16 unsigned int + #define s16 signed int + + #ifdef __WATCOMC__ + + u32 radsqr(s32 a); + #pragma aux radsqr = "shl edx,16" "mov dx,ax" "mov eax,edx" "xor edx,edx" "mul eax" "shld edx,eax,16" parm [dx ax] modify [DX ax] value [dx ax]; + + s16 radabs(s16 ab); + #pragma aux radabs = "test ax,ax" "jge skip" "neg ax" "skip:" parm [ax] value [ax]; + + s32 radabs32(s32 ab); + #pragma aux radabs32 = "test dx,dx" "jge skip" "neg dx" "neg ax" "sbb dx,0" "skip:" parm [dx ax] value [dx ax]; + + u32 DOSOut(const char far* dest); + #pragma aux DOSOut = "cld" "and edi,0xffff" "mov dx,di" "mov ecx,0xffffffff" "xor eax,eax" 0x67 "repne scasb" "not ecx" "dec ecx" "mov bx,1" "push ds" "push es" "pop ds" "mov ah,0x40" "int 0x21" "pop ds" "movzx eax,cx" "shr ecx,16" \ + parm [ES DI] modify [AX BX CX DX DI ES] value [CX AX]; + + void DOSOutNum(const char far* str,u16 len); + #pragma aux DOSOutNum = "push ds" "mov ds,cx" "mov cx,bx" "mov ah,0x40" "mov bx,1" "int 0x21" "pop ds" parm [cx dx] [bx] modify [ax bx cx]; + + u32 ErrOut(const char far* dest); + #pragma aux ErrOut = "cld" "and edi,0xffff" "mov dx,di" "mov ecx,0xffffffff" "xor eax,eax" 0x67 "repne scasb" "not ecx" "dec ecx" "xor bx,bx" "push ds" "push es" "pop ds" "mov ah,0x40" "int 0x21" "pop ds" "movzx eax,cx" "shr ecx,16" \ + parm [ES DI] modify [AX BX CX DX DI ES] value [CX AX]; + + void ErrOutNum(const char far* str,u16 len); + #pragma aux ErrOutNum = "push ds" "mov ds,cx" "mov cx,bx" "mov ah,0x40" "xor bx,bx" "int 0x21" "pop ds" parm [cx dx] [bx] modify [ax bx cx]; + + void radmemset(void far *dest,u8 value,u32 size); + #pragma aux radmemset = "cld" "and edi,0ffffh" "shl ecx,16" "mov cx,bx" "mov ah,al" "mov bx,ax" "shl eax,16" "mov ax,bx" "mov bl,cl" "shr ecx,2" 0x67 "rep stosd" "mov cl,bl" "and cl,3" "rep stosb" parm [ES DI] [AL] [CX BX]; + + void radmemset16(void far* dest,u16 value,u32 size); + #pragma aux radmemset16 = "cld" "and edi,0ffffh" "shl ecx,16" "mov cx,bx" "mov bx,ax" "shl eax,16" "mov ax,bx" "mov bl,cl" "shr ecx,1" "rep stosd" "mov cl,bl" "and cl,1" "rep stosw" parm [ES DI] [AX] [CX BX]; + + void radmemcpy(void far* dest,const void far* source,u32 size); + #pragma aux radmemcpy = "cld" "push ds" "mov ds,dx" "and esi,0ffffh" "and edi,0ffffh" "shl ecx,16" "mov cx,bx" "shr ecx,2" 0x67 "rep movsd" "mov cl,bl" "and cl,3" "rep movsb" "pop ds" parm [ES DI] [DX SI] [CX BX] modify [CX SI DI ES]; + + s8 radmemcmp(const void far* s1,const void far* s2,u32 len); + #pragma aux radmemcmp = "cld" "push ds" "mov ds,dx" "shl ecx,16" "mov cx,bx" "rep cmpsb" "setne al" "jbe end" "neg al" "end:" "pop ds" parm [ES DI] [DX SI] [CX BX] modify [CX SI DI ES]; + + char far* radstrcpy(void far* dest,const void far* source); + #pragma aux radstrcpy = "cld" "push ds" "mov ds,dx" "and esi,0xffff" "and edi,0xffff" "mov dx,di" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "pop ds" parm [ES DI] [DX SI] modify [AX DX DI SI ES] value [es dx]; + + char far* radstpcpy(void far* dest,const void far* source); + #pragma aux radstpcpy = "cld" "push ds" "mov ds,dx" "and esi,0xffff" "and edi,0xffff" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "dec di" "pop ds" parm [ES DI] [DX SI] modify [DI SI ES] value [es di]; + + u32 radstrlen(const void far* dest); + #pragma aux radstrlen = "cld" "and edi,0xffff" "mov ecx,0xffffffff" "xor eax,eax" 0x67 "repne scasb" "not ecx" "dec ecx" "movzx eax,cx" "shr ecx,16" parm [ES DI] modify [AX CX DI ES] value [CX AX]; + + char far* radstrcat(void far* dest,const void far* source); + #pragma aux radstrcat = "cld" "and edi,0xffff" "mov ecx,0xffffffff" "and esi,0xffff" "push ds" "mov ds,dx" "mov dx,di" "xor eax,eax" 0x67 "repne scasb" "dec edi" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "pop ds" \ + parm [ES DI] [DX SI] modify [AX CX DI SI ES] value [es dx]; + + char far* radstrchr(const void far* dest,char chr); + #pragma aux radstrchr = "cld" "lp:" 0x26 "lodsb" "cmp al,dl" "je fnd" "cmp al,0" "jnz lp" "xor ax,ax" "mov es,ax" "mov si,1" "fnd:" "dec si" parm [ES SI] [DL] modify [AX SI ES] value [es si]; + + s8 radstricmp(const void far* s1,const void far* s2); + #pragma aux radstricmp = "and edi,0xffff" "push ds" "mov ds,dx" "and esi,0xffff" "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" \ + "cmp ah,'a'" "jb c2" "cmp ah,'z'" "ja c2" "sub ah,32" "c2:" "cmp al,ah" "jne set" "cmp al,0" "je set" \ + "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" "pop ds" \ + parm [ES DI] [DX SI] modify [AX DI SI]; + + u32 radstru32(const void far* dest); + #pragma aux radstru32 = "cld" "xor ecx,ecx" "xor ebx,ebx" "xor edi,edi" 0x26 "lodsb" "cmp al,45" "jne skip2" "mov edi,1" "jmp skip" "lp:" "mov eax,10" "mul ecx" "lea ecx,[eax+ebx]" \ + "skip:" 0x26 "lodsb" "skip2:" "cmp al,0x39" "ja dne" "cmp al,0x30" "jb dne" "mov bl,al" "sub bl,0x30" "jmp lp" "dne:" "test edi,1" "jz pos" "neg ecx" "pos:" \ + "movzx eax,cx" "shr ecx,16" parm [ES SI] modify [AX BX DX DI SI] value [cx ax]; + + u32 mult64anddiv(u32 m1,u32 m2,u32 d); + #pragma aux mult64anddiv = "shl ecx,16" "mov cx,ax" "shrd eax,edx,16" "mov ax,si" "mul ecx" "shl edi,16" "mov di,bx" "div edi" "shld edx,eax,16" "and edx,0xffff" "and eax,0xffff" parm [cx ax] [dx si] [di bx] \ + modify [ax bx cx dx si di] value [dx ax]; + + #endif + +#endif + +RADDEFEND + +#define u32neg1 ((u32)(s32)-1) +#define RAD_align(var) var; u8 junk##var[4-(sizeof(var)&3)]; +#define RAD_align_after(var) u8 junk##var[4-(sizeof(var)&3)]={0}; +#define RAD_align_init(var,val) var=val; u8 junk##var[4-(sizeof(var)&3)]={0}; +#define RAD_align_array(var,num) var[num]; u8 junk##var[4-(sizeof(var)&3)]; +#define RAD_align_string(var,str) char var[]=str; u8 junk##var[4-(sizeof(var)&3)]={0}; + + +RADEXPFUNC void PTR4* RADEXPLINK radmalloc(u32 numbytes); +RADEXPFUNC void RADEXPLINK radfree(void PTR4* ptr); + + +#ifdef __WATCOMC__ + + char bkbhit(); + #pragma aux bkbhit = "mov ah,1" "int 0x16" "lahf" "shr eax,14" "and eax,1" "xor al,1" ; + + char bgetch(); + #pragma aux bgetch = "xor ah,ah" "int 0x16" "test al,0xff" "jnz done" "mov al,ah" "or al,0x80" "done:" modify [AX]; + + void BreakPoint(); + #pragma aux BreakPoint = "int 3"; + + u8 radinp(u16 p); + #pragma aux radinp = "in al,dx" parm [DX]; + + u8 radtoupper(u8 p); + #pragma aux radtoupper = "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" parm [al] value [al]; + + void radoutp(u16 p,u8 v); + #pragma aux radoutp = "out dx,al" parm [DX] [AL]; + +#else + +// for multi-processor machines + +#ifdef __RADNT__ + #define LockedIncrement(var) __asm { lock inc [var] } + #define LockedDecrement(var) __asm { lock dec [var] } + void __inline LockedIncrementFunc(void PTR4* var) { + __asm { + mov eax,[var] + lock inc [eax] + } + } + + void __inline LockedDecrementFunc(void PTR4* var) { + __asm { + mov eax,[var] + lock dec [eax] + } + } + +#else + + #ifdef __RADMAC__ + + #define LockedIncrement(var) {++(var);} + #define LockedDecrement(var) {--(var);} + + #define LockedIncrementFunc(ptr) {++(*((u32*)(var)));} + #define LockedDecrementFunc(ptr) {--(*((u32*)(var)));} + + #else + + #define LockedIncrement(var) __asm { inc [var] } + #define LockedDecrement(var) __asm { dec [var] } + void __inline LockedIncrementFunc(void PTR4* var) { __asm { mov eax,[var] + inc [eax] } } + void __inline LockedDecrementFunc(void PTR4* var) { __asm { mov eax,[var] + dec [eax] } } + #endif + +#endif + +#endif + +#endif + +#endif + diff --git a/3dc/win95/chnkload.cpp b/3dc/win95/chnkload.cpp new file mode 100644 index 0000000..2113372 --- /dev/null +++ b/3dc/win95/chnkload.cpp @@ -0,0 +1,4024 @@ +#include +#include + +#include "list_tem.hpp" +#include "chnkload.hpp" +#include "oechunk.h" +#include "stratdef.h" +//#include "bh_types.h" +#include "shpchunk.hpp" +#include "envchunk.hpp" +#include "obchunk.hpp" +#include "chunkpal.hpp" +#include "bmpnames.hpp" +#include "ltchunk.hpp" +#include "chnktexi.h" +#include "sprchunk.hpp" +#include "gsprchnk.hpp" +#include "animchnk.hpp" +#include "fragchnk.hpp" +#include "jsndsup.h" +#include "mempool.h" +#include +// for log file +void SetupAnimatedTextures(Shape_Chunk* sc,SHAPEHEADER* shp,Animation_Chunk* ac,Shape_Merge_Data_Chunk* smdc); +void SetupAnimOnTriangle(SHAPEHEADER* shp,TEXANIM* ta,int poly); +void SetupAnimOnQuad(Shape_Chunk* sc,SHAPEHEADER* shp,TEXANIM* ta1,TEXANIM* ta2,int poly); + +// what we need to do for now is load shapes into the mainshapelist +// and objects into the Mapheader - Map + + +double local_scale; + +File_Chunk * Env_Chunk = 0; + +RIFFHANDLE current_rif_handle; + +unsigned char const * PaletteMapTable; + +////////////////////////////////////////////////////////// +extern LOADED_SOUND const * GetSoundForMainRif(const char* wav_name); +extern char * extsounddir ; +extern char * sounddir ; + +struct Shape_Fragment_Type +{ + Shape_Fragment_Type(const char*); + ~Shape_Fragment_Type(); + void AddShape(SHAPEHEADER*); + void Setup_sh_frags(Fragment_Type_Chunk*); + + char* name; + List shapelist; + SHAPEFRAGMENTDESC* sh_fragdesc; +}; + +Shape_Fragment_Type::Shape_Fragment_Type(const char* _name) +{ + name=new char[strlen(_name)+1]; + strcpy(name,_name); + sh_fragdesc=0; +} + +Shape_Fragment_Type::~Shape_Fragment_Type() +{ + while(shapelist.size()) + { + shapelist.first_entry()->sh_fragdesc=0; + delete shapelist.first_entry(); + } + if(sh_fragdesc) + { + #if USE_LEVEL_MEMORY_POOL + if(sh_fragdesc->sh_fragsound) + { + if(sh_fragdesc->sh_fragsound->sound_loaded) + LoseSound(sh_fragdesc->sh_fragsound->sound_loaded); + } + #else + if(sh_fragdesc->sh_frags)DeallocateMem(sh_fragdesc->sh_frags); + if(sh_fragdesc->sh_fragsound) + { + if(sh_fragdesc->sh_fragsound->sound_loaded) + LoseSound(sh_fragdesc->sh_fragsound->sound_loaded); + DeallocateMem(sh_fragdesc->sh_fragsound); + } + DeallocateMem(sh_fragdesc); + #endif + + } + if(name) delete name; +} + +void Shape_Fragment_Type::AddShape(SHAPEHEADER* shp) +{ + shapelist.add_entry(shp); + if(sh_fragdesc) shp->sh_fragdesc=sh_fragdesc; +} + + +void Shape_Fragment_Type::Setup_sh_frags(Fragment_Type_Chunk* ftc) +{ + if(sh_fragdesc) return; + List chlist; + ftc->lookup_child("FRGTYPSC",chlist); + + sh_fragdesc=(SHAPEFRAGMENTDESC*)PoolAllocateMem(sizeof(SHAPEFRAGMENTDESC)); + for(LIF slif(&shapelist);!slif.done();slif.next()) + { + slif()->sh_fragdesc=sh_fragdesc; + } + + + sh_fragdesc->sh_frags = (SHAPEFRAGMENT *)PoolAllocateMem((chlist.size()+1) * sizeof(SHAPEFRAGMENT)); + int pos=0; + while(chlist.size()) + { + Fragment_Type_Shape_Chunk* ftsc=(Fragment_Type_Shape_Chunk*)chlist.first_entry(); + + int shapeindex=GetLoadedShapeMSL(ftsc->name); + if(shapeindex!=-1) + { + sh_fragdesc->sh_frags[pos].ShapeIndex=shapeindex; + sh_fragdesc->sh_frags[pos].NumFrags=ftsc->num_fragments; + + sh_fragdesc->sh_frags[pos].x_offset = 0; + sh_fragdesc->sh_frags[pos].y_offset = 0; + sh_fragdesc->sh_frags[pos].z_offset = 0; + pos++; + } + + chlist.delete_first_entry(); + } + sh_fragdesc->sh_frags[pos].ShapeIndex = -1; + sh_fragdesc->sh_frags[pos].NumFrags = -1; + + sh_fragdesc->sh_fragsound=0; + + Chunk * pChunk = ftc->lookup_single_child("FRGSOUND"); + if(pChunk) + { + Fragment_Type_Sound_Chunk* ftsoc=(Fragment_Type_Sound_Chunk*) pChunk; + + + sh_fragdesc->sh_fragsound=(SHAPEFRAGMENTSOUND*)PoolAllocateMem(sizeof(SHAPEFRAGMENTSOUND)); + sh_fragdesc->sh_fragsound->sound_loaded=GetSoundForMainRif (ftsoc->wav_name); + sh_fragdesc->sh_fragsound->inner_range=ftsoc->inner_range*local_scale; + sh_fragdesc->sh_fragsound->outer_range=ftsoc->outer_range*local_scale; + sh_fragdesc->sh_fragsound->pitch=ftsoc->pitch; + sh_fragdesc->sh_fragsound->max_volume=ftsoc->max_volume; + + } + + +} + + +static List FragList; + +void ApplyFragTypeToShape(SHAPEHEADER* shp,const char* name) +{ + for(LIF flif(&FragList);!flif.done();flif.next()) + { + if(!_stricmp(flif()->name,name)) + { + flif()->AddShape(shp); + return; + } + } + Shape_Fragment_Type* sft=new Shape_Fragment_Type(name); + sft->AddShape(shp); + FragList.add_entry(sft); +} + +void SetupFragmentType(Fragment_Type_Chunk* ftc) +{ + const char* name=ftc->get_name(); + if(!name) return; + + Shape_Fragment_Type* sft=0; + for(LIF flif(&FragList);!flif.done();flif.next()) + { + if(!_stricmp(flif()->name,name)) + { + sft=flif(); + break; + } + } + if(!sft) + { + return; + } + + sft->Setup_sh_frags(ftc); +} + +void DeallocateFragments(SHAPEHEADER* shp,SHAPEFRAGMENTDESC* sh_fragdesc) +{ + for(LIF flif(&FragList);!flif.done();flif.next()) + { + if(flif()->sh_fragdesc==sh_fragdesc) + { + flif()->shapelist.delete_entry(shp); + if(!flif()->shapelist.size()) + { + //no more shapes use this fragment type - so deallocate it + delete flif(); + flif.delete_current(); + } + return; + } + } + //sh_fragdesc not generated by a fragment type so deallocate it. + #if USE_LEVEL_MEMORY_POOL + if(sh_fragdesc->sh_fragsound) + { + if(sh_fragdesc->sh_fragsound->sound_loaded) + LoseSound(sh_fragdesc->sh_fragsound->sound_loaded); + } + #else + if(sh_fragdesc->sh_frags)DeallocateMem(sh_fragdesc->sh_frags); + if(sh_fragdesc->sh_fragsound) + { + if(sh_fragdesc->sh_fragsound->sound_loaded) + LoseSound(sh_fragdesc->sh_fragsound->sound_loaded); + DeallocateMem(sh_fragdesc->sh_fragsound); + } + DeallocateMem(sh_fragdesc); + #endif +} + +void DeallocateAllFragments() +{ + while(FragList.size()) + { + Shape_Fragment_Type* frag_type=FragList.first_entry(); + + while(frag_type->shapelist.size()) + { + frag_type->shapelist.delete_first_entry(); + } + frag_type->sh_fragdesc=0; + delete frag_type; + + FragList.delete_first_entry(); + } +} + +///////////////////////////////////////// +///////////////////////////////////////// +// Hold data about chunk loaded shapes // +///////////////////////////////////////// +///////////////////////////////////////// + +class ShapeInMSL +{ +private: + void AddToHashTables(); + void RemoveFromHashTables(); + + #define SIM_HASH_BITS 6 + #define SIM_HASH_SIZE (1< hash_msl[]; + static List hash_ptr[]; + static List hash_name[]; + + static int HashMSLFunc(int); + static int HashPtrFunc(SHAPEHEADER *); + static int HashNameFunc(char const *); + + + int listpos; + SHAPEHEADER * shptr; + String name; + BOOL in_hash_table; + +public: + + inline int Listpos() const { return listpos; } + inline SHAPEHEADER * Shptr() const { return shptr; } + inline char const * Name() const { return name; } + + static ShapeInMSL const * GetByName(char const *); + static ShapeInMSL const * GetByMSL(int); + static ShapeInMSL const * GetByPtr(SHAPEHEADER *); + static void PurgeMSLShapeList(); + + ShapeInMSL(); + ShapeInMSL(int _p); + ShapeInMSL(SHAPEHEADER * _s, char const * _n, int _p); + ShapeInMSL(ShapeInMSL const &); + ShapeInMSL & operator = (ShapeInMSL const &); + ~ShapeInMSL(); + + BOOL operator == (ShapeInMSL const & s2) const + { return (GLS_NOTINLIST==listpos && GLS_NOTINLIST==s2.listpos) ? shptr == s2.shptr : listpos == s2.listpos; } + inline BOOL operator != (ShapeInMSL const & s2) const { return ! operator == (s2); } +}; + +void ShapeInMSL::AddToHashTables() +{ + if (GLS_NOTINLIST != listpos) + hash_msl[HashMSLFunc(listpos)].add_entry(this); + hash_ptr[HashPtrFunc(shptr)].add_entry(this); + hash_name[HashNameFunc(name)].add_entry(this); + + in_hash_table = TRUE; +} + +void ShapeInMSL::RemoveFromHashTables() +{ + if (GLS_NOTINLIST != listpos) + hash_msl[HashMSLFunc(listpos)].delete_entry(this); + hash_ptr[HashPtrFunc(shptr)].delete_entry(this); + hash_name[HashNameFunc(name)].delete_entry(this); + + in_hash_table = FALSE; +} + +List ShapeInMSL::hash_msl[SIM_HASH_SIZE]; +List ShapeInMSL::hash_ptr[SIM_HASH_SIZE]; +List ShapeInMSL::hash_name[SIM_HASH_SIZE]; + +int ShapeInMSL::HashMSLFunc(int pos) +{ + return pos & SIM_HASH_MASK; +} + +int ShapeInMSL::HashPtrFunc(SHAPEHEADER * shp) +{ + size_t p = (size_t)shp; + + while (p>=SIM_HASH_SIZE) + p = (p & SIM_HASH_MASK) ^ (p>>SIM_HASH_BITS); + + return (int)p; +} + +int ShapeInMSL::HashNameFunc(char const * nam) +{ + int v = 0; + + while (*nam) v += (unsigned char)toupper(*nam++); + + return v & SIM_HASH_MASK; +} + +ShapeInMSL const * ShapeInMSL::GetByMSL(int pos) +{ + for (LIF i(&hash_msl[HashMSLFunc(pos)]); !i.done(); i.next()) + { + if (i()->listpos == pos) return i(); + } + return 0; +} + +ShapeInMSL const * ShapeInMSL::GetByPtr(SHAPEHEADER * shp) +{ + for (LIF i(&hash_ptr[HashPtrFunc(shp)]); !i.done(); i.next()) + { + if (i()->shptr == shp) return i(); + } + return 0; +} + +ShapeInMSL const * ShapeInMSL::GetByName(char const * nam) +{ + for (LIF i(&hash_name[HashNameFunc(nam)]); !i.done(); i.next()) + { + if (!_stricmp(i()->name,nam)) return i(); + } + return 0; +} + +ShapeInMSL::ShapeInMSL() +: shptr(0) +, listpos(GLS_NOTINLIST) +, in_hash_table(FALSE) +{ +} + +ShapeInMSL::ShapeInMSL(int _p) +: shptr(0) +, listpos(_p) +, in_hash_table(FALSE) +{ +} + +ShapeInMSL::ShapeInMSL(SHAPEHEADER * _s, char const * _n, int _p) +: shptr(_s) +, name(_n) +, listpos(_p) +, in_hash_table(FALSE) +{ + AddToHashTables(); +} + +ShapeInMSL::ShapeInMSL(ShapeInMSL const & sim) +: shptr(sim.shptr) +, name(sim.name) +, listpos(sim.listpos) +, in_hash_table(FALSE) +{ + if (sim.in_hash_table) AddToHashTables(); +} + +ShapeInMSL & ShapeInMSL::operator = (ShapeInMSL const & sim) +{ + if (&sim != this) + { + if (in_hash_table) RemoveFromHashTables(); + shptr = sim.shptr; + name = sim.name; + listpos = sim.listpos; + if (sim.in_hash_table) AddToHashTables(); + } + return *this; +} + +ShapeInMSL::~ShapeInMSL() +{ + if (in_hash_table) RemoveFromHashTables(); +} + + +static List msl_shapes; + +void ShapeInMSL::PurgeMSLShapeList() +{ + for(int i=0;iin_hash_table=FALSE; + delete shp_msl; + msl_shapes.delete_first_entry(); + } +} +void PurgeMSLShapeList() +{ + ShapeInMSL::PurgeMSLShapeList(); +} + +///////////////////////////////////////// +///////////////////////////////////////// +///////////////////////////////////////// + +extern "C" +{ + extern unsigned char *TextureLightingTable; + extern int ScanDrawMode; +}; + + +///////////////////////////////////////// +// Functions which operate on RIFFHANDLEs +///////////////////////////////////////// + +// load a rif file into memory +RIFFHANDLE load_rif (const char * fname) +{ + File_Chunk * fc = new File_Chunk (fname); + + if (fc->error_code != 0) + { + delete fc; + #if OUTPUT_LOG + CL_LogFile.lprintf("FAILED TO LOAD RIF: %s\n",fname); + #endif + ReleaseDirect3D(); + char message[200]; + sprintf(message,"Error loading %s",fname); + MessageBox(NULL,message,"AvP",MB_OK+MB_SYSTEMMODAL); + exit(0x111); + return INVALID_RIFFHANDLE; + } + #if OUTPUT_LOG + CL_LogFile.lprintf("Successfully Loaded RIF: %s\n",fname); + #endif + + RIFFHANDLE h = current_rif_handle = new _RifHandle; + h->fc = Env_Chunk = fc; + + Chunk * pChunk = fc->lookup_single_child("REBENVDT"); + if (pChunk) + { + h->envd = (Environment_Data_Chunk *)pChunk; + } + + return h; +} + +RIFFHANDLE load_rif_non_env (const char * fname) +{ + File_Chunk * fc = new File_Chunk (fname); + + if (fc->error_code != 0) + { + delete fc; + #if OUTPUT_LOG + CL_LogFile.lprintf("FAILED TO LOAD RIF: %s\n",fname); + #endif + + ReleaseDirect3D(); + char message[200]; + sprintf(message,"Error loading %s",fname); + MessageBox(NULL,message,"AvP",MB_OK+MB_SYSTEMMODAL); + exit(0x111); + return INVALID_RIFFHANDLE; + } + #if OUTPUT_LOG + CL_LogFile.lprintf("Successfully Loaded RIF: %s\n",fname); + #endif + + RIFFHANDLE h = current_rif_handle = new _RifHandle; + h->fc = fc; + + Chunk * pChunk = fc->lookup_single_child("REBENVDT"); + if (pChunk) + { + h->envd = (Environment_Data_Chunk *)pChunk; + } + + return h; +} + + +// deallocate the shapes, unload the rif, close the handle +void undo_rif_load (RIFFHANDLE h) +{ + deallocate_loaded_shapes(h); + unload_rif(h); + close_rif_handle(h); +} + +// deallocate the shapes copied from the rif +void deallocate_loaded_shapes (RIFFHANDLE h) +{ + + // because the SHAPEHEADER is calloced, we can + // just delete the arrays we want + + LIF msl_shape_lif(&msl_shapes); + + while (h->shape_nums.size()) + { + #if !StandardShapeLanguage + #error Must have standard shape language + #endif + + int list_pos = h->shape_nums.first_entry(); + h->shape_nums.delete_first_entry(); + + DeallocateLoadedShapeheader(mainshapelist[list_pos]); + + FreeMSLPos(list_pos); + + for(msl_shape_lif.restart();!msl_shape_lif.done();msl_shape_lif.next()) + { + if(list_pos==msl_shape_lif()->Listpos()) + { + delete msl_shape_lif(); + msl_shape_lif.delete_current(); + break; + } + } + } + + // ?????????? FIXME + if (Map[0].MapType6Objects) + { + DeallocateMem (Map[0].MapType6Objects); + Map[0].MapType6Objects = 0; + } +} + +// unloads the rif but keeps the handle and associated copied shapes +void unload_rif (RIFFHANDLE h) +{ + if (h->fc) + { + if (h->fc == Env_Chunk) + Env_Chunk = 0; + delete h->fc; + h->fc = 0; + } + h->envd = 0; + h->palparent = 0; + h->max_index = 0; + if (h->tex_index_nos) delete[] h->tex_index_nos; + h->tex_index_nos = 0; +} + +// close the handle - performs tidying up and memory deallocation +void close_rif_handle (RIFFHANDLE h) +{ + delete h; +} + + +////////////////////////////////////////////////////////// + + + +// copies sprite to msl +int copy_sprite_to_mainshapelist(RIFFHANDLE h, Sprite_Header_Chunk * shc, int/* flags*/) +{ + int list_pos = GetMSLPos(); + + copy_sprite_to_shapeheader (h, mainshapelist[list_pos], shc, list_pos); + + post_process_shape(mainshapelist[list_pos]); + + h->shape_nums.add_entry(list_pos); + + return list_pos; +} + +static void setup_tex_conv_array ( + int & max_indices, + int * & conv_array, + RIFFHANDLE h, + Chunk_With_Children * tmpshp + ) +{ + String rif_name; + + max_indices = h->max_index; + conv_array = h->tex_index_nos; + + // find out if its come from elsewhere!!!!!!! + // Doo Dee Doo Doh + // Just come back from the pub - sorry + + Chunk * pChunk = tmpshp->lookup_single_child("SHPEXTFL"); + + Shape_External_File_Chunk * seflc = 0; + Bitmap_List_Store_Chunk * blsc = 0; + + + if (pChunk) + { + seflc = (Shape_External_File_Chunk *)pChunk; + pChunk = seflc->lookup_single_child("BMPLSTST"); + if (pChunk) + { + blsc = (Bitmap_List_Store_Chunk *) pChunk; + } + pChunk = seflc->lookup_single_child("RIFFNAME"); + if (pChunk) + { + rif_name = ((RIF_Name_Chunk *)pChunk)->rif_name; + } + } + + if (blsc) + { + + // load in the textures from the shape + + max_indices = 0; + for (LIF bns (&blsc->bmps); !bns.done(); bns.next()) + { + max_indices = max(bns().index,max_indices); + } + + conv_array = new int [max_indices+1]; + for (int i=0; i<=max_indices; i++) + { + conv_array[i] = -1; + } + + if (Env_Chunk == 0) + Env_Chunk = h->fc; + // JH 17-2-97 -- image loaders have changed to avoid loading the same image twice + for (bns.restart() ; !bns.done(); bns.next()) + { + if (!(bns().flags & ChunkBMPFlag_NotInPC)) + { + String tex; + if (bns().flags & ChunkBMPFlag_IFF) + { + tex = bns().filename; + } + else + { + tex = rif_name; + tex += "\\"; + tex += bns().filename; + } + + int imgnum = load_rif_bitmap(tex,bns().flags); + if (GEI_NOTLOADED != imgnum) + conv_array[bns().index] = imgnum; + } + } + + } + +} + +CopyShapeAnimationHeader(SHAPEHEADER* shpfrom,SHAPEHEADER* shpto) +{ + GLOBALASSERT(shpfrom->numitems==shpto->numitems); + GLOBALASSERT(shpfrom->animation_header); + shpto->animation_header=shpfrom->animation_header; + shpto->animation_header->num_shapes_using_this++; + //find a sequence which has some frames; + + shapeanimationsequence* sas=0; + for(int i=0;ianimation_header->num_sequences;i++) + { + sas=&shpto->animation_header->anim_sequences[i]; + if(sas->num_frames) + break; + + } + GLOBALASSERT(ianimation_header->num_sequences); + + //copy the pointers for the first frame of this sequence + #if !USE_LEVEL_MEMORY_POOL + DeallocateMem(shpto->points[0]); + DeallocateMem(shpto->sh_normals[0]); + DeallocateMem(shpto->sh_vnormals[0]); + #endif + + shpto->points[0]=sas->anim_frames[0].vertices; + shpto->sh_normals[0]=sas->anim_frames[0].item_normals; + shpto->sh_vnormals[0]=sas->vertex_normals; + +} + +// copies shape to msl +CTM_ReturnType copy_to_mainshapelist(RIFFHANDLE h, Shape_Chunk * tmpshp, int flags,const ChunkObject* object) +{ + int local_max_index; + int * local_tex_index_nos; + + int list_pos = GetMSLPos(); + int main_shape_num = list_pos; + int start_shape_no = list_pos; + String rif_name; + + setup_tex_conv_array (local_max_index, local_tex_index_nos, h, tmpshp); + + + Shape_Preprocessed_Data_Chunk* spdc=(Shape_Preprocessed_Data_Chunk*)tmpshp->lookup_single_child("SHPPRPRO"); + if(spdc) + { + copy_preprocessed_to_shapeheader ( + h, + spdc, + mainshapelist[list_pos], + tmpshp, + flags, + local_max_index, + local_tex_index_nos, + list_pos, + object + ); + } + else + { + + copy_to_shapeheader ( + h, + tmpshp->shape_data, + mainshapelist[list_pos], + tmpshp, + flags, + local_max_index, + local_tex_index_nos, + list_pos, + object + ); + } + + Shape_External_File_Chunk * seflc = 0; + + Chunk * pChunk = tmpshp->lookup_single_child("SHPEXTFL"); + + if (pChunk) + { + seflc = (Shape_External_File_Chunk *)pChunk; + rif_name = seflc->get_shape_name(); + msl_shapes.add_entry(new ShapeInMSL(mainshapelist[list_pos],rif_name,list_pos)); + } + else + { + List const & oblist=tmpshp->list_assoc_objs(); + if(oblist.size()) + { + Object_Chunk* oc=oblist.first_entry(); + if(oc->get_header()->flags & OBJECT_FLAG_PLACED_OBJECT) + { + msl_shapes.add_entry(new ShapeInMSL(mainshapelist[list_pos],oc->object_data.o_name,list_pos)); + + } + } + } + + post_process_shape(mainshapelist[list_pos]); + + h->shape_nums.add_entry(list_pos); + + if (tmpshp->count_children("ANIMSEQU")) + { + //look for alternate texture mappings + pChunk=tmpshp->lookup_single_child("ASALTTEX"); + if(pChunk) + { + List chlst; + ((Chunk_With_Children*)pChunk)->lookup_child("SUBSHAPE",chlst); + for(LIF chlif(&chlst);!chlif.done();chlif.next()) + { + Shape_Sub_Shape_Chunk* sssc=(Shape_Sub_Shape_Chunk*)chlif(); + + list_pos=GetMSLPos(); + copy_to_shapeheader ( + h, + sssc->shape_data, + mainshapelist[list_pos], + sssc, + flags, + local_max_index, + local_tex_index_nos, + list_pos, + object + ); + CopyShapeAnimationHeader(mainshapelist[start_shape_no],mainshapelist[list_pos]); + + const char* shpname=sssc->get_shape_name(); + GLOBALASSERT(shpname); + msl_shapes.add_entry(new ShapeInMSL(mainshapelist[list_pos],shpname,list_pos)); + h->shape_nums.add_entry(list_pos); + + post_process_shape(mainshapelist[list_pos]); + + } + } + } + + Shape_Fragments_Chunk * sfc = 0; + + pChunk = tmpshp->lookup_single_child ("SHPFRAGS"); + + if (pChunk) + { + sfc = (Shape_Fragments_Chunk *)pChunk; + + pChunk=sfc->lookup_single_child("SHPFRGTP"); + if(pChunk) + { + //the shape is using a fragment type + Shape_Fragment_Type_Chunk* sftc=(Shape_Fragment_Type_Chunk*)pChunk; + ApplyFragTypeToShape(mainshapelist[main_shape_num],sftc->frag_type_name); + } + else + { + List cl; + sfc->lookup_child ("SUBSHAPE", cl); + if (cl.size()) + { + mainshapelist[main_shape_num]->sh_fragdesc = (SHAPEFRAGMENTDESC *)PoolAllocateMem(sizeof(SHAPEFRAGMENTDESC)); + + mainshapelist[main_shape_num]->sh_fragdesc->sh_frags = (SHAPEFRAGMENT *)PoolAllocateMem((cl.size()+1) * sizeof(SHAPEFRAGMENT)); + mainshapelist[main_shape_num]->sh_fragdesc->sh_fragsound = 0; + + int fragpos = 0; + + for (LIF cli(&cl); !cli.done(); cli.next(), fragpos++) + { + Shape_Sub_Shape_Chunk * sssc = ((Shape_Sub_Shape_Chunk *)cli()); + + list_pos = GetMSLPos(); + + + copy_to_shapeheader ( + h, + sssc->shape_data, + mainshapelist[list_pos], + sssc, + flags, + local_max_index, + local_tex_index_nos, + list_pos, + object + ); + post_process_shape(mainshapelist[list_pos]); + h->shape_nums.add_entry(list_pos); + + int num_frags = 1; + + pChunk = sssc->lookup_single_child("FRAGDATA"); + if (pChunk) + { + num_frags = ((Shape_Fragments_Data_Chunk *)pChunk)->num_fragments; + } + + Shape_Fragment_Location_Chunk * sflc = 0; + + pChunk = sssc->lookup_single_child("FRAGLOCN"); + if (pChunk) + { + sflc = (Shape_Fragment_Location_Chunk *)pChunk; + } + + + mainshapelist[main_shape_num]->sh_fragdesc->sh_frags[fragpos].ShapeIndex = list_pos; + mainshapelist[main_shape_num]->sh_fragdesc->sh_frags[fragpos].NumFrags = num_frags; + + if (sflc) + { + mainshapelist[main_shape_num]->sh_fragdesc->sh_frags[fragpos].x_offset = sflc->frag_loc.x * local_scale; + mainshapelist[main_shape_num]->sh_fragdesc->sh_frags[fragpos].y_offset = sflc->frag_loc.y * local_scale; + mainshapelist[main_shape_num]->sh_fragdesc->sh_frags[fragpos].z_offset = sflc->frag_loc.z * local_scale; + + } + else + { + mainshapelist[main_shape_num]->sh_fragdesc->sh_frags[fragpos].x_offset = 0; + mainshapelist[main_shape_num]->sh_fragdesc->sh_frags[fragpos].y_offset = 0; + mainshapelist[main_shape_num]->sh_fragdesc->sh_frags[fragpos].z_offset = 0; + } + + } + + mainshapelist[main_shape_num]->sh_fragdesc->sh_frags[fragpos].ShapeIndex = -1; + mainshapelist[main_shape_num]->sh_fragdesc->sh_frags[fragpos].NumFrags = -1; + + //see if fragment has a sound to go with it + Fragment_Type_Sound_Chunk* ftsoc=(Fragment_Type_Sound_Chunk*) sfc->lookup_single_child("FRGSOUND"); + if(ftsoc) + { + mainshapelist[main_shape_num]->sh_fragdesc->sh_fragsound=(SHAPEFRAGMENTSOUND*)PoolAllocateMem(sizeof(SHAPEFRAGMENTSOUND)); + mainshapelist[main_shape_num]->sh_fragdesc->sh_fragsound->sound_loaded=GetSoundForMainRif (ftsoc->wav_name); + mainshapelist[main_shape_num]->sh_fragdesc->sh_fragsound->inner_range=ftsoc->inner_range*local_scale; + mainshapelist[main_shape_num]->sh_fragdesc->sh_fragsound->outer_range=ftsoc->outer_range*local_scale; + mainshapelist[main_shape_num]->sh_fragdesc->sh_fragsound->pitch=ftsoc->pitch; + mainshapelist[main_shape_num]->sh_fragdesc->sh_fragsound->max_volume=ftsoc->max_volume; + } + + + } + } + } + + #if SupportMorphing && LOAD_MORPH_SHAPES + + /*-------------------** + ** Morphing stuff ** + **-------------------*/ + MORPHCTRL * mc = 0; + + if (!(flags & CCF_NOMORPH)) + { + pChunk = tmpshp->lookup_single_child ("SHPMORPH"); + if (pChunk) + { + // this shape has some morphing data + + // (store the list no. of the shape) + Shape_Morphing_Data_Chunk * smdc = (Shape_Morphing_Data_Chunk *)pChunk; + + // set all the subshape list_pos numbers to -1 + // so later we can check to see if it has already been loaded + List chlst; + smdc->lookup_child("SUBSHAPE",chlst); + for (LIF ssi(&chlst); !ssi.done(); ssi.next()) + { + ((Shape_Sub_Shape_Chunk *)ssi())->list_pos_number = -1; + } + + pChunk = smdc->lookup_single_child("FRMMORPH"); + if (pChunk) + { + Shape_Morphing_Frame_Data_Chunk * smfdc = (Shape_Morphing_Frame_Data_Chunk *)pChunk; + // Check there are some frames!! + if (smfdc->anim_frames.size()) + { + mc = (MORPHCTRL *)AllocateMem(sizeof(MORPHCTRL)); + mc->ObMorphFlags = smfdc->a_flags; + mc->ObMorphSpeed = smfdc->a_speed; + MORPHHEADER * mh = (MORPHHEADER *)AllocateMem(sizeof(MORPHHEADER)); + mc->ObMorphHeader = mh; + mh->mph_numframes = 0; + mh->mph_frames = (MORPHFRAME *)AllocateMem(sizeof(MORPHFRAME) * (smfdc->anim_frames.size()) ); + + int frame_no = 0; + + for (LIF afi(&smfdc->anim_frames); !afi.done(); afi.next()) + { + if (afi()->shape1a) + { + if (afi()->shape1a->list_pos_number == -1) + { + list_pos = GetMSLPos(); + + Shape_Preprocessed_Data_Chunk* spdc=(Shape_Preprocessed_Data_Chunk*)afi()->shape1a->lookup_single_child("SHPPRPRO"); + if(spdc) + { + copy_preprocessed_to_shapeheader ( + h, + spdc, + mainshapelist[list_pos], + afi()->shape1a, + flags, + local_max_index, + local_tex_index_nos, + list_pos, + object + ); + } + else + { + + copy_to_shapeheader ( + h, + afi()->shape1a->shape_data, + mainshapelist[list_pos], + afi()->shape1a, + flags, + local_max_index, + local_tex_index_nos, + list_pos, + object + ); + } + + post_process_shape(mainshapelist[list_pos]); + afi()->shape1a->list_pos_number = list_pos; + h->shape_nums.add_entry(list_pos); + /* + Copy the item data for this door shape from the main shape. This is largely done to cope + with the problem of the polygons being merged differently in different morph shapes. + */ + SHAPEHEADER* main_shape=mainshapelist[main_shape_num]; + SHAPEHEADER* this_shape=mainshapelist[list_pos]; + + this_shape->numitems=main_shape->numitems; + this_shape->items=main_shape->items; + this_shape->sh_textures=main_shape->sh_textures; + this_shape->sh_normals=main_shape->sh_normals; + + //update shape instructions (probably not uses anyway) + this_shape->sh_instruction[1].sh_numitems=main_shape->numitems; + this_shape->sh_instruction[1].sh_instr_data=main_shape->sh_normals; + + this_shape->sh_instruction[4].sh_numitems=main_shape->numitems; + this_shape->sh_instruction[4].sh_instr_data=main_shape->items; + + } + mh->mph_frames[frame_no].mf_shape1 = afi()->shape1a->list_pos_number; + } + else + { + mh->mph_frames[frame_no].mf_shape1 = main_shape_num; + } + + if (afi()->shape2a) + { + if (afi()->shape2a->list_pos_number == -1) + { + list_pos = GetMSLPos(); + + Shape_Preprocessed_Data_Chunk* spdc=(Shape_Preprocessed_Data_Chunk*)afi()->shape2a->lookup_single_child("SHPPRPRO"); + if(spdc) + { + copy_preprocessed_to_shapeheader ( + h, + spdc, + mainshapelist[list_pos], + afi()->shape1a, + flags, + local_max_index, + local_tex_index_nos, + list_pos, + object + ); + } + else + { + + copy_to_shapeheader ( + h, + afi()->shape2a->shape_data, + mainshapelist[list_pos], + afi()->shape2a, + 0, + local_max_index, + local_tex_index_nos, + list_pos, + object + ); + } + post_process_shape(mainshapelist[list_pos]); + afi()->shape2a->list_pos_number = list_pos; + h->shape_nums.add_entry(list_pos); + + /* + Copy the item data for this door shape from the main shape. This is largely done to cope + with the problem of the polygons being merged differently in different morph shapes. + */ + SHAPEHEADER* main_shape=mainshapelist[main_shape_num]; + SHAPEHEADER* this_shape=mainshapelist[list_pos]; + + this_shape->numitems=main_shape->numitems; + this_shape->items=main_shape->items; + this_shape->sh_textures=main_shape->sh_textures; + this_shape->sh_normals=main_shape->sh_normals; + + //update shape instructions (probably not uses anyway) + this_shape->sh_instruction[1].sh_numitems=main_shape->numitems; + this_shape->sh_instruction[1].sh_instr_data=main_shape->sh_normals; + + this_shape->sh_instruction[4].sh_numitems=main_shape->numitems; + this_shape->sh_instruction[4].sh_instr_data=main_shape->items; + } + mh->mph_frames[frame_no].mf_shape2 = afi()->shape2a->list_pos_number; + } + else + { + mh->mph_frames[frame_no].mf_shape2 = main_shape_num; + } + if (frame_no == 0) + { + start_shape_no = mh->mph_frames[frame_no].mf_shape1; + } + frame_no ++; + } + mh->mph_numframes = frame_no; + mh->mph_maxframes = frame_no << 16; + } + } + } + } + + CTM_ReturnType retval = { start_shape_no, main_shape_num, mc }; + if(local_tex_index_nos!=h->tex_index_nos) delete [] local_tex_index_nos; + return retval; + + #else + + if(local_tex_index_nos!=h->tex_index_nos) delete [] local_tex_index_nos; + return list_pos; + + #endif +} + +// load textures for environment +BOOL load_rif_bitmaps (RIFFHANDLE h, int/* flags*/) +{ + Global_BMP_Name_Chunk * gbnc = 0; + + if (h->envd) + { + Chunk * pChunk = h->envd->lookup_single_child ("BMPNAMES"); + if (pChunk) gbnc = (Global_BMP_Name_Chunk *) pChunk; + } + + h->max_index = 0; + + if (gbnc) + { + for (LIF bns (&gbnc->bmps); !bns.done(); bns.next()) + { + h->max_index = max(bns().index,h->max_index); + } + + if (h->tex_index_nos) delete h->tex_index_nos; + h->tex_index_nos = new int [h->max_index+1]; + for (int i=0; i<=h->max_index; i++) + { + h->tex_index_nos[i] = -1; + } + + if (Env_Chunk == 0) + Env_Chunk = h->fc; + for (bns.restart() ; !bns.done(); bns.next()) + { + if (!(bns().flags & ChunkBMPFlag_NotInPC)) + { + // JH 17-2-97 -- image loaders have changed to avoid loading the same image twice + int imgnum = load_rif_bitmap(bns().filename,bns().flags); + if (GEI_NOTLOADED != imgnum) + h->tex_index_nos[bns().index] = imgnum; + } + } + + return TRUE; + } + else return FALSE; +} + +// set the quantization event depending on cl_pszGameMode +BOOL set_quantization_event(RIFFHANDLE h, int /*flags*/) +{ + if (h->envd) + { + h->palparent = h->envd; + + if (cl_pszGameMode) + { + List egmcs; + h->envd->lookup_child("GAMEMODE",egmcs); + + for (LIF egmcLIF(&egmcs); !egmcLIF.done(); egmcLIF.next()) + { + Environment_Game_Mode_Chunk * egmcm = (Environment_Game_Mode_Chunk *) egmcLIF(); + if (egmcm->id_equals(cl_pszGameMode)) + { + h->palparent = egmcm; + break; + } + } + + } + + return TRUE; + } + else + { + h->palparent = 0; + return FALSE; + } +} + +// copy palette +BOOL copy_rif_palette (RIFFHANDLE h, int /*flags*/) +{ + if (h->palparent) + { + List chlst; + h->palparent->lookup_child("ENVPALET",chlst); + for (LIF i_ch(&chlst); !i_ch.done(); i_ch.next()) + { + Environment_Palette_Chunk * palch = (Environment_Palette_Chunk *)i_ch(); + if (!(palch->flags & EnvPalFlag_V2) && palch->width*palch->height <= 256 ) + { + for (int i=0; iwidth*palch->height*3; i++) + { + TestPalette[i] = (unsigned char)(palch->pixel_data[i] >> 2); + } + return TRUE; + } + } + } + + return FALSE; +} + +// copy texture lighting table +BOOL copy_rif_tlt (RIFFHANDLE h, int /*flags*/) +{ + if (h->palparent) + { + List chlst; + h->palparent->lookup_child("ENVTXLIT",chlst); + if(TextureLightingTable) + { + DeallocateMem(TextureLightingTable); + TextureLightingTable = 0; + } + for (LIF i_ch(&chlst); !i_ch.done(); i_ch.next()) + { + Environment_TLT_Chunk * tltch = (Environment_TLT_Chunk *)i_ch(); + + if ((tltch->flags & ChunkTLTFlag_V2 && + ScreenDescriptorBlock.SDB_Flags & SDB_Flag_TLTPalette || + !(tltch->flags & ChunkTLTFlag_V2) && + !(ScreenDescriptorBlock.SDB_Flags & SDB_Flag_TLTPalette)) && + tltch->table + ){ + TextureLightingTable = (unsigned char*)AllocateMem(tltch->width * tltch->num_levels); + memcpy(TextureLightingTable,tltch->table,tltch->width*tltch->num_levels); + if (ScreenDescriptorBlock.SDB_Flags & SDB_Flag_TLTPalette) + { + ScreenDescriptorBlock.SDB_Flags &= ~(SDB_Flag_TLTSize|SDB_Flag_TLTShift); + if (tltch->width != 256) + { + ScreenDescriptorBlock.SDB_Flags |= SDB_Flag_TLTSize; + ScreenDescriptorBlock.TLTSize = tltch->width; + for (int shft = 0; 1<width; ++shft) + ; + if (1<width) + { + ScreenDescriptorBlock.SDB_Flags |= SDB_Flag_TLTShift; + ScreenDescriptorBlock.TLTShift = shft; + } + } + } + return TRUE; + } + + } + } + + return FALSE; +} + +// copy palette remap table (15-bit) - post_process_shape may use it +BOOL get_rif_palette_remap_table (RIFFHANDLE h, int /*flags*/) +{ + PaletteMapTable = 0; + if (h->palparent) + { + Chunk * pChunk = h->palparent->lookup_single_child("CLRLOOKP"); + if (pChunk) + { + Coloured_Polygons_Lookup_Chunk * cplook = (Coloured_Polygons_Lookup_Chunk *)pChunk; + + if (cplook->table) + { + PaletteMapTable = cplook->table; + return TRUE; + } + + } + } + + return FALSE; +} + +// copy one named shape or sprite; intended to go in position listpos +static SHAPEHEADER * CreateShapeFromRif (RIFFHANDLE h, char const * shapename, int listpos = GLS_NOTINLIST) +{ + if (!h->fc) return 0; // no rif file loaded + + List shape_chunks; + h->fc->lookup_child("REBSHAPE",shape_chunks); + + for (LIF search(&shape_chunks); !search.done(); search.next()) + { + Shape_Chunk * cur_shape = (Shape_Chunk *) search(); + + Chunk * pShpextfile = cur_shape->lookup_single_child("SHPEXTFL"); + + if (pShpextfile) + { + Shape_External_File_Chunk * shexdata = (Shape_External_File_Chunk *) pShpextfile; + + Chunk * pRnc = shexdata->lookup_single_child("RIFFNAME"); + if (pRnc) + { + RIF_Name_Chunk * rnc = (RIF_Name_Chunk *) pRnc; + if (!_stricmp(rnc->rif_name,shapename)) // haha! matching shape found + { + SHAPEHEADER * shptr = 0; + int local_max_index; + int * local_tex_index_nos; + setup_tex_conv_array (local_max_index, local_tex_index_nos, h, cur_shape); + + copy_to_shapeheader( + h, + cur_shape->shape_data, + shptr, + cur_shape, + 0, + local_max_index, + local_tex_index_nos, + listpos + ); + if(local_tex_index_nos!=h->tex_index_nos) delete [] local_tex_index_nos; + + return shptr; + } + } + } + } + //look to see if is a sprite + Chunk * pSprite_chunks = h->fc->lookup_single_child("RSPRITES"); + if(pSprite_chunks) + { + AllSprites_Chunk* asc=(AllSprites_Chunk*) pSprite_chunks; + List sprite_chunks; + asc->lookup_child("SPRIHEAD",sprite_chunks); + for(LIF slif(&sprite_chunks);!slif.done();slif.next()) + { + Sprite_Header_Chunk* shc=(Sprite_Header_Chunk*)slif(); + Chunk * pRn=shc->lookup_single_child("RIFFNAME"); + if(pRn) + { + RIF_Name_Chunk* rnc=(RIF_Name_Chunk*)pRn; + if (!_stricmp(rnc->rif_name,shapename)) // haha! matching sprite found + { + SHAPEHEADER * shptr = 0; + copy_sprite_to_shapeheader(h,shptr, shc, listpos); + return shptr; + } + } + + } + } + return 0; // could not match shape +} + +// copy one named shape or sprite; does not put in main shape list +SHAPEHEADER * CopyNamedShapePtr (RIFFHANDLE h, char const * shapename) +{ + return CreateShapeFromRif(h,shapename); +} + +// copy one named shape or sprite; put it in the main shape list +int CopyNamedShapeMSL (RIFFHANDLE h, char const * shapename) +{ + int listpos = GetMSLPos(); + SHAPEHEADER * shp = CreateShapeFromRif(h,shapename,listpos); + if (shp) + { + h->shape_nums.add_entry(listpos); + mainshapelist[listpos] = shp; + return listpos; + } + else + { + FreeMSLPos(listpos); + return GLS_NOTINLIST; + } +} + +//////////////////////////////////////////////////////////////////////// +// Functions which do not operate on RIFFHANDLEs and may become obsolete +//////////////////////////////////////////////////////////////////////// + +SHAPEHEADER * CopyNamedShape (char const * shapename) +{ + return CopyNamedShapePtr (current_rif_handle,shapename); +} + +///////////////////////////////////////////// +// Functions for handling the main shape list +///////////////////////////////////////////// + +//////////////////////////////////////////////// +// Functions retrieving data about loaded shapes +//////////////////////////////////////////////// + +// gets the main shape list position of a shape loaded into the msl +int GetLoadedShapeMSL(char const * shapename) +{ + ShapeInMSL const * sim = ShapeInMSL::GetByName(shapename); + + if (sim) + return sim->Listpos(); + else + return GLS_NOTINLIST; +} + +// ditto, but returns a pointer; the shape need not be in the msl +SHAPEHEADER * GetLoadedShapePtr(char const * shapename) +{ + ShapeInMSL const * sim = ShapeInMSL::GetByName(shapename); + + if (sim) + return sim->Shptr(); + else + return 0; +} + +// gets name of shape from msl pos +char const * GetMSLLoadedShapeName(int listpos) +{ + ShapeInMSL const * sim = ShapeInMSL::GetByMSL(listpos); + + if (sim) + return sim->Name(); + else + return 0; +} + +// gets name of shape from pointer; the shape need not be in msl +char const * GetPtrLoadedShapeName(SHAPEHEADER * shptr) +{ + ShapeInMSL const * sim = ShapeInMSL::GetByPtr(shptr); + + if (sim) + return sim->Name(); + else + return 0; +} + +// free a reference to a named shape if it exists - not necessary since these are all tidied up +void FreeShapeNameReference(SHAPEHEADER * shptr) +{ + for (LIF search(&msl_shapes); !search.done(); search.next()) + { + if (search()->Shptr() == shptr) + { + delete search(); + search.delete_current(); + break; + } + } + + return; +} + +////////////////////////////////////////////////////////////////////////////// +// Initializing, deallocating of shapes, mainly hooks for project specific fns +////////////////////////////////////////////////////////////////////////////// + +// delete a shape by the shapeheader +void DeallocateLoadedShapePtr(SHAPEHEADER * shp) +{ + DeallocateLoadedShapeheader(shp); + + FreeShapeNameReference(shp); +} + +// delete a shape by the shape list number +void DeallocateLoadedShapeMSL(RIFFHANDLE h, int list_pos) +{ + h->shape_nums.delete_entry(list_pos); + + DeallocateLoadedShapeheader(mainshapelist[list_pos]); + + FreeMSLPos(list_pos); + + for(LIF msl_shape_lif(&msl_shapes);!msl_shape_lif.done();msl_shape_lif.next()) + { + if(list_pos==msl_shape_lif()->Listpos()) + { + delete msl_shape_lif(); + msl_shape_lif.delete_current(); + break; + } + } +} + +void DeallocateRifLoadedShapeheader(SHAPEHEADER * shp) +{ + // because the SHAPEHEADER is calloced, we can + // just delete the arrays we want + + #if !StandardShapeLanguage + #error Must have standard shape language + #endif + + int max_num_texs = 0; + int i; + + if(shp->animation_header) + { + // so it gets deallocated properly + shp->points[0] = 0; + shp->sh_normals[0] = 0; + shp->sh_vnormals[0] = 0; + } + if (shp->sh_fragdesc) + { + DeallocateFragments(shp,shp->sh_fragdesc); + } + + #if !USE_LEVEL_MEMORY_POOL + if (shp->points) + { + if (*shp->points) DeallocateMem(*shp->points); + DeallocateMem(shp->points); + } + if (shp->sh_normals) + { + if (*shp->sh_normals) DeallocateMem(*shp->sh_normals); + DeallocateMem(shp->sh_normals); + } + if (shp->sh_vnormals) + { + if (*shp->sh_vnormals) DeallocateMem(*shp->sh_vnormals); + DeallocateMem(shp->sh_vnormals); + } + if (shp->sh_extraitemdata) + DeallocateMem(shp->sh_extraitemdata); + /* the items are allocated in one big bunch + // 9 int's per item (to make bsp simple) + // this should be changed if it is to be done + // a different way + */ + if (shp->items) + { + if(shp->shapeflags & ShapeFlag_MultiViewSprite) + { + TXANIMHEADER** thlist=(TXANIMHEADER**)shp->sh_textures[0]; + for(int j=1;thlist[j]!=0;j++) + { + int k; + TXANIMHEADER* th=thlist[j]; + for(k=0;ktxa_numframes;k++) + { + txanimframe_mvs* tf=(txanimframe_mvs*)&th->txa_framedata[k]; + if(tf->txf_uvdata[0])DeallocateMem(tf->txf_uvdata[0]); + if(tf->txf_uvdata)DeallocateMem(tf->txf_uvdata); + if(tf->txf_images)DeallocateMem(tf->txf_images); + } + if(th->txa_framedata)DeallocateMem (th->txa_framedata); + DeallocateMem (th); + } + DeallocateMem (thlist); + shp->sh_textures[0]=0; + } + else + { + for (i=0; inumitems; i++) + { + if (is_textured(shp->items[i][0])) + { + int UVIndex = (shp->items[i][3] &0xffff0000) >> 16; + max_num_texs = max (max_num_texs, shp->items[i][3] &0x7fff); + if(shp->items[i][2]& iflag_txanim) + { + int j; + TXANIMHEADER** thlist=(TXANIMHEADER**)shp->sh_textures[UVIndex]; + for(j=1;thlist[j]!=0;j++) + { + int k; + TXANIMHEADER* th=thlist[j]; + for(k=0;ktxa_numframes;k++) + { + if(th->txa_framedata[k].txf_uvdata)DeallocateMem(th->txa_framedata[k].txf_uvdata); + } + if(th->txa_framedata)DeallocateMem (th->txa_framedata); + DeallocateMem (th); + } + DeallocateMem (thlist); + shp->sh_textures[UVIndex]=0; + } + else + { + if(shp->sh_textures[UVIndex])DeallocateMem(shp->sh_textures[UVIndex]); + } + } + } + } + DeallocateMem (*shp->items); + DeallocateMem (shp->items); + } + + if (shp->sh_textures) + { + DeallocateMem (shp->sh_textures); + } + + if (shp->sh_localtextures) + { + for (i=0; i<(max_num_texs+1); i++) + { + DeallocateMem (shp->sh_localtextures[i]); + } + DeallocateMem (shp->sh_localtextures); + } + + + + #if SupportTrackOptimisation + if (shp->sh_track_data) + DeallocateMem(shp->sh_track_data); + #endif + if (shp->sh_instruction) + DeallocateMem(shp->sh_instruction); + #if SupportBSP + if (shp->sh_bsp_blocks) + DeallocateMem(shp->sh_bsp_blocks); + #endif + + if(shp->animation_header) + { + shp->animation_header->num_shapes_using_this--; + if(shp->animation_header->num_shapes_using_this==0) + { + shapeanimationheader* sah=shp->animation_header; + for(int i=0;inum_sequences;i++) + { + shapeanimationsequence* sas=&sah->anim_sequences[i]; + for(int j=0;jnum_frames;j++) + { + shapeanimationframe*saf=&sas->anim_frames[j]; + DeallocateMem(saf->vertices); + DeallocateMem(saf->item_normals); + } + if(sas->vertex_normals)DeallocateMem(sas->vertex_normals); + if(sas->anim_frames)DeallocateMem(sas->anim_frames); + } + DeallocateMem(sah->anim_sequences); + DeallocateMem(sah); + } + } + + if(shp->shape_degradation_array) + { + DeallocateMem(shp->shape_degradation_array); + } + + DeallocateMem(shp); + #endif //!USE_LEVEL_MEMORY_POOL +} + +/////// +// Misc +/////// + +// return TRUE if the poly item type corresponds to a textured polygon +BOOL is_textured (int type) +{ + if ( + type == I_2dTexturedPolygon + || type == I_Gouraud2dTexturedPolygon + || type == I_3dTexturedPolygon + || type == I_Gouraud3dTexturedPolygon + || type == I_ZB_2dTexturedPolygon + || type == I_ZB_Gouraud2dTexturedPolygon + || type == I_ZB_3dTexturedPolygon + || type == I_ZB_Gouraud3dTexturedPolygon + ) + { + return(TRUE); + } + return(FALSE); +} + + +#if SupportModules + +// static Object_Chunk ** o_chunk_array; + +void copy_to_module (Object_Chunk * ob, int mod_pos, int shplst_pos) +{ + Object_Project_Data_Chunk * opdc = 0; + Map_Block_Chunk * mapblok = 0; + Strategy_Chunk * strat = 0; + + MODULEMAPBLOCK * Map = (MODULEMAPBLOCK *) PoolAllocateMem (sizeof(MODULEMAPBLOCK)); + + *Map = Empty_Module_Map; + + MainScene.sm_module[mod_pos].m_mapptr = Map; + MainScene.sm_module[mod_pos].name = (char *) PoolAllocateMem (strlen (ob->object_data.o_name)+1); + strcpy (MainScene.sm_module[mod_pos].name, ob->object_data.o_name); + + *((int *)MainScene.sm_module[mod_pos].m_name) = mod_pos + ONE_FIXED; + // add 65536 to this value to this value to preserve 0 + + Chunk * pChunk = ob->lookup_single_child("OBJPRJDT"); + if (pChunk) opdc = (Object_Project_Data_Chunk *)pChunk; + if (opdc) + { + pChunk = opdc->lookup_single_child("MAPBLOCK"); + if (pChunk) mapblok = (Map_Block_Chunk *)pChunk; + pChunk = opdc->lookup_single_child("STRATEGY"); + if (pChunk) strat = (Strategy_Chunk *)pChunk; + } + + if (mapblok) + { + Map->MapType = mapblok->map_data.MapType; + Map->MapFlags= mapblok->map_data.MapFlags; + #if (StandardStrategyAndCollisions || IntermediateSSACM) + Map->MapCType = mapblok->map_data.MapCType; + Map->MapCGameType = mapblok->map_data.MapCGameType; + Map->MapCStrategyS = mapblok->map_data.MapCStrategyS; + Map->MapCStrategyL = mapblok->map_data.MapCStrategyL; + #endif + Map->MapInteriorType = mapblok->map_data.MapInteriorType; +// Map->MapLightType = mapblok->map_data.MapLightType; +// Map->MapMass = mapblok->map_data.MapMass; +// Map->MapNewtonV.vx = mapblok->map_data.MapNewtonV.vx; +// Map->MapNewtonV.vy = mapblok->map_data.MapNewtonV.vy; +// Map->MapNewtonV.vz = mapblok->map_data.MapNewtonV.vz; +// Map->MapOrigin.vx = mapblok->map_data.MapOrigin.vx; +// Map->MapOrigin.vy = mapblok->map_data.MapOrigin.vy; +// Map->MapOrigin.vz = mapblok->map_data.MapOrigin.vz; +// Map->MapViewType = mapblok->map_data.MapViewType; + } + + #if (StandardStrategyAndCollisions || IntermediateSSACM) + if (strat) + { + Map->MapStrategy = strat->strategy_data.Strategy; + } + #endif + + Map->MapShape = shplst_pos; + + Map->MapWorld.vx = (int) (ob->object_data.location.x*local_scale); + Map->MapWorld.vy = (int) (ob->object_data.location.y*local_scale); + Map->MapWorld.vz = (int) (ob->object_data.location.z*local_scale); + +#if 0 + QUAT q; + + q.quatx = (int) (ob->object_data.orientation.x*ONE_FIXED); + q.quaty = (int) (ob->object_data.orientation.y*ONE_FIXED); + q.quatz = (int) (ob->object_data.orientation.z*ONE_FIXED); + q.quatw = (int) (ob->object_data.orientation.w*ONE_FIXED); + + + MATRIXCH m; + + QuatToMat (&q, &m); + + EULER e; + + MatrixToEuler(&m, &e); + + Map->MapEuler.EulerX = -e.EulerX; + Map->MapEuler.EulerY = -e.EulerY; + Map->MapEuler.EulerZ = -e.EulerZ; + +#endif + + +} + +#endif + +void SetupAnimOnTriangle(SHAPEHEADER* shp,TEXANIM* ta,int poly, int * local_tex_index_nos) +{ + if(!is_textured(shp->items[poly][0]))return; + txanimheader** thlist=(txanimheader**)PoolAllocateMem((ta->NumSeq+2)*sizeof(txanimheader*)); + thlist[0]=0; + thlist[ta->NumSeq+1]=0; + for(int i=0;iNumSeq;i++) + { + thlist[i+1]=(txanimheader*)PoolAllocateMem(sizeof(txanimheader)); + txanimheader* th=thlist[i+1]; + + FrameList* fl=ta->Seq[i]; + th->txa_flags=fl->Flags; + if(!(ta->AnimFlags & AnimFlag_NotPlaying))th->txa_flags|=txa_flag_play; + th->txa_numframes=fl->NumFrames+1; + if(fl->Flags & txa_flag_nointerptofirst) + { + th->txa_flags&=~txa_flag_nointerptofirst; + th->txa_numframes--; + } + th->txa_currentframe=0; + th->txa_state=0; + th->txa_maxframe=(th->txa_numframes-1)<<16; + th->txa_speed=fl->Speed; + th->txa_framedata=(txanimframe*)PoolAllocateMem(th->txa_numframes*sizeof(txanimframe)); + th->txa_anim_id=ta->Identifier; + + txanimframe* tf; + for(int j=0;jtxa_numframes;j++) + { + tf=&th->txa_framedata[j]; + tf->txf_flags=0; + tf->txf_scale=ONE_FIXED; + tf->txf_scalex=0; + tf->txf_scaley=0; + tf->txf_orient=0; + tf->txf_orientx=0; + tf->txf_orienty=0; + tf->txf_numuvs=3; + tf->txf_uvdata=(int*)PoolAllocateMem(6*sizeof(int)); + if(j==fl->NumFrames) + { + tf->txf_image=local_tex_index_nos[fl->Textures[0]]; + for(int k=0;k<6;k++) + { + tf->txf_uvdata[k]=fl->UVCoords[k]<<16; + } + } + else + { + tf->txf_image=local_tex_index_nos[fl->Textures[j]]; + for(int k=0;k<6;k++) + { + tf->txf_uvdata[k]=fl->UVCoords[j*6+k]<<16; + } + } + } + } + int UVIndex=shp->items[poly][3]>>16; + #if !USE_LEVEL_MEMORY_POOL + if(shp->sh_textures[UVIndex])DeallocateMem(shp->sh_textures[UVIndex]); + #endif + shp->sh_textures[UVIndex]=(int*)thlist; + shp->items[poly][2]|=iflag_txanim; + shp->items[poly][3]=UVIndex<<16; + +} +void SetupAnimOnQuad(Shape_Chunk* sc,SHAPEHEADER* shp,TEXANIM* ta1,TEXANIM* ta2,int poly, int * local_tex_index_nos) +{ + if(!is_textured(shp->items[poly][0]))return; + if(ta1->ID!=ta2->ID)return; + int VertConv[3];//conversion between vert nos in triangles and vert nos in quad + int VertFrom,VertTo;//for remaining vert in second poly + VertTo=6; + for(int i=0;i<3;i++) + { + for(int j=0;j<4;j++) + { + if(sc->shape_data.poly_list[ta1->poly].vert_ind[i]==(shp->items[poly][j+4]))break; + } + if(j==4)return; + VertConv[i]=j; + VertTo-=j; + } + for(i=0;i<3;i++) + { + if(sc->shape_data.poly_list[ta2->poly].vert_ind[i]==(shp->items[poly][4+VertTo]))break; + } + if(i==3)return; + VertFrom=i; + + txanimheader** thlist=(txanimheader**)PoolAllocateMem((ta1->NumSeq+2)*sizeof(txanimheader*)); + thlist[0]=0; + thlist[ta1->NumSeq+1]=0; + for(i=0;iNumSeq;i++) + { + thlist[i+1]=(txanimheader*)PoolAllocateMem(sizeof(txanimheader)); + txanimheader* th=thlist[i+1]; + FrameList* fl1=ta1->Seq[i]; + FrameList* fl2=ta2->Seq[i]; + th->txa_flags=fl1->Flags; + if(!(ta1->AnimFlags & AnimFlag_NotPlaying))th->txa_flags|=txa_flag_play; + th->txa_numframes=fl1->NumFrames+1; + if(fl1->Flags & txa_flag_nointerptofirst) + { + th->txa_flags&=~txa_flag_nointerptofirst; + th->txa_numframes--; + } + th->txa_currentframe=0; + th->txa_state=0; + th->txa_maxframe=(th->txa_numframes-1)<<16; + th->txa_speed=fl1->Speed; + th->txa_framedata=(txanimframe*)PoolAllocateMem(th->txa_numframes*sizeof(txanimframe)); + th->txa_anim_id=ta1->Identifier; + + txanimframe* tf; + for(int j=0;jtxa_numframes;j++) + { + tf=&th->txa_framedata[j]; + tf->txf_flags=0; + tf->txf_scale=ONE_FIXED; + tf->txf_scalex=0; + tf->txf_scaley=0; + tf->txf_orient=0; + tf->txf_orientx=0; + tf->txf_orienty=0; + tf->txf_numuvs=4; + tf->txf_uvdata=(int*)PoolAllocateMem(8*sizeof(int)); + if(j==fl1->NumFrames) + { + tf->txf_image=local_tex_index_nos[fl1->Textures[0]]; + for(int k=0;k<3;k++) + { + tf->txf_uvdata[VertConv[k]*2]=fl1->UVCoords[k*2]<<16; + tf->txf_uvdata[VertConv[k]*2+1]=fl1->UVCoords[k*2+1]<<16; + } + tf->txf_uvdata[VertTo*2]=fl2->UVCoords[VertFrom*2]<<16; + tf->txf_uvdata[VertTo*2+1]=fl2->UVCoords[VertFrom*2+1]<<16; + + } + else + { + tf->txf_image=local_tex_index_nos[fl1->Textures[j]]; + for(int k=0;k<3;k++) + { + tf->txf_uvdata[VertConv[k]*2]=fl1->UVCoords[j*6+k*2]<<16; + tf->txf_uvdata[VertConv[k]*2+1]=fl1->UVCoords[j*6+k*2+1]<<16; + } + tf->txf_uvdata[VertTo*2]=fl2->UVCoords[j*6+VertFrom*2]<<16; + tf->txf_uvdata[VertTo*2+1]=fl2->UVCoords[j*6+VertFrom*2+1]<<16; + } + } + } + int UVIndex=shp->items[poly][3]>>16; + #if !USE_LEVEL_MEMORY_POOL + if(shp->sh_textures[UVIndex])DeallocateMem(shp->sh_textures[UVIndex]); + #endif + shp->sh_textures[UVIndex]=(int*)thlist; + shp->items[poly][2]|=iflag_txanim; + shp->items[poly][3]=UVIndex<<16; + + +} +void SetupAnimatedTextures(Shape_Chunk* sc,SHAPEHEADER* shp,Animation_Chunk* ac,Shape_Merge_Data_Chunk* smdc, int * local_tex_index_nos) +{ + //create conversion between unmerged poly nos and merged poly nos + int* PolyConv=0; + int* mgd=0; + + if(smdc) + { + mgd=smdc->merge_data; + PolyConv=new int[smdc->num_polys]; + for(int i=0, j=0;inum_polys;i++) + { + if(mgd[i]==-1) + { + PolyConv[i]=j; + j++; + } + else if(mgd[i]>i) + { + if(shp->items[j][7]==-1) + { + //quad in merge data,but not actually merged; + PolyConv[i]=j; + j++; + PolyConv[mgd[i]]=j; + j++; + } + else + { + PolyConv[i]=j; + PolyConv[mgd[i]]=j; + j++; + } + } + + } + + for(i=0;iNumPolys;i++) + { + TEXANIM* ta1,*ta2; + ta1=ac->AnimList[i]; + if(mgd[ta1->poly]==-1) + { + SetupAnimOnTriangle(shp,ta1,PolyConv[ta1->poly], local_tex_index_nos); + } + else if(mgd[ta1->poly]>ta1->poly) + { + for(j=0;jNumPolys;j++) + { + if(ac->AnimList[j]->poly==mgd[ta1->poly])break; + } + if(jNumPolys) + { + ta2=ac->AnimList[j]; + if(PolyConv[ta1->poly]==PolyConv[ta2->poly]) + { + SetupAnimOnQuad(sc,shp,ta1,ta2,PolyConv[ta1->poly], local_tex_index_nos); + } + else + { + SetupAnimOnTriangle(shp,ta1,PolyConv[ta1->poly], local_tex_index_nos); + SetupAnimOnTriangle(shp,ta2,PolyConv[ta2->poly], local_tex_index_nos); + } + } + else if(PolyConv[ta1->poly]!=PolyConv[mgd[ta1->poly]]) + { + SetupAnimOnTriangle(shp,ta1,PolyConv[ta1->poly], local_tex_index_nos); + } + } + } + if(PolyConv)delete [] PolyConv; + } + else + { + for(int i=0;iNumPolys;i++) + { + SetupAnimOnTriangle(shp,ac->AnimList[i],ac->AnimList[i]->poly, local_tex_index_nos); + } + } + shp->shapeflags|=ShapeFlag_HasTextureAnimation; +} + + +void SetupAnimatingShape(Shape_Chunk* sc,SHAPEHEADER* shp, Shape_Merge_Data_Chunk* smdc) +{ + //create conversion between unmerged poly nos and merged poly nos + int* PolyConv=0; + int* mgd=0; + + PolyConv=new int[smdc->num_polys]; + + if(smdc) + { + mgd=smdc->merge_data; + for(int i=0, j=0;inum_polys;i++) + { + if(mgd[i]==-1) + { + PolyConv[i]=j; + j++; + } + else if(mgd[i]>i) + { + if(shp->items[j][7]==-1) + { + //quad in merge data,but not actually merged; + PolyConv[i]=j; + j++; + PolyConv[mgd[i]]=j; + j++; + } + else + { + PolyConv[i]=j; + PolyConv[mgd[i]]=j; + j++; + } + } + + } + + } + else + { + for(int i=0;inum_polys;i++) + { + PolyConv[i]=i; + } + } + + ChunkVectorInt Centre={0,0,0}; + Chunk * pChunk = sc->lookup_single_child("ANSHCEN2"); + if(pChunk) + Centre=((Anim_Shape_Centre_Chunk*)pChunk)->Centre; + + int numseq=0; + List chlist; + sc->lookup_child("ANIMSEQU",chlist); + for(LIF chlif(&chlist);!chlif.done();chlif.next()) + { + Anim_Shape_Sequence_Chunk* assc=(Anim_Shape_Sequence_Chunk*)chlif(); + numseq=max(assc->sequence_data.SequenceNum+1,numseq); + } + + shapeanimationheader* sah=(shapeanimationheader*)PoolAllocateMem(sizeof(shapeanimationheader)); + shp->animation_header=sah; + sah->num_sequences=numseq; + sah->anim_sequences=(shapeanimationsequence*)PoolAllocateMem(sizeof(shapeanimationsequence)*numseq); + sah->num_shapes_using_this=1; + //sah->vertices_store = shp->points[0]; + //sah->item_normals_store = shp->sh_normals[0]; + //sah->vertex_normals_store = shp->sh_vnormals[0]; + + for( int i=0;ianim_sequences[i].num_frames=0; + sah->anim_sequences[i].anim_frames=0; + } + + + + for(chlif.restart();!chlif.done();chlif.next()) + { + Anim_Shape_Sequence_Chunk* assc=(Anim_Shape_Sequence_Chunk*)chlif(); + assc->GenerateInterpolatedFrames(); + const ChunkAnimSequence * cas=& assc->sequence_data; + if(!cas->NumFrames)continue; + shapeanimationsequence* sas =&sah->anim_sequences[cas->SequenceNum]; + + sas->max_x=(int)((cas->max.x-Centre.x)*local_scale); + sas->min_x=(int)((cas->min.x-Centre.x)*local_scale); + sas->max_y=(int)((cas->max.y-Centre.y)*local_scale); + sas->min_y=(int)((cas->min.y-Centre.y)*local_scale); + sas->max_z=(int)((cas->max.z-Centre.z)*local_scale); + sas->min_z=(int)((cas->min.z-Centre.z)*local_scale); + + int x=max(-sas->min_x,sas->max_x); + int y=max(-sas->min_y,sas->max_y); + int z=max(-sas->min_z,sas->max_z); + sas->radius=sqrt(x*x+y*y+z*z); + + + sas->vertex_normals=(int*)PoolAllocateMem(sizeof(VECTORCH)*cas->num_verts); + for(i=0;inum_verts;i++) + { + sas->vertex_normals[i*3]=(int)(cas->v_normal_list[i].x*ONE_FIXED); + sas->vertex_normals[i*3+1]=(int)(cas->v_normal_list[i].y*ONE_FIXED); + sas->vertex_normals[i*3+2]=(int)(cas->v_normal_list[i].z*ONE_FIXED); + } + + sas->num_frames=cas->NumFrames; + sas->anim_frames=(shapeanimationframe*)PoolAllocateMem(sizeof(shapeanimationframe)*cas->NumFrames); + + for(i=0;iNumFrames;i++) + { + const ChunkAnimFrame* caf=cas->Frames[i]; + shapeanimationframe* saf=&sas->anim_frames[i]; + + saf->vertices=(int*)PoolAllocateMem(sizeof(VECTORCH)*caf->num_verts); + for(int j=0;jnum_verts;j++) + { + saf->vertices[j*3]=(int)((caf->v_list[j].x-Centre.x)*local_scale); + saf->vertices[j*3+1]=(int)((caf->v_list[j].y-Centre.y)*local_scale); + saf->vertices[j*3+2]=(int)((caf->v_list[j].z-Centre.z)*local_scale); + } + + saf->item_normals=(int*) PoolAllocateMem(sizeof(VECTORCH)*shp->numitems); + for(j=0;jnum_polys;j++) + { + saf->item_normals[PolyConv[j]*3]=(int)(caf->p_normal_list[j].x*ONE_FIXED); + saf->item_normals[PolyConv[j]*3+1]=(int)(caf->p_normal_list[j].y*ONE_FIXED); + saf->item_normals[PolyConv[j]*3+2]=(int)(caf->p_normal_list[j].z*ONE_FIXED); + + } + } + } + + delete [] PolyConv; + + + //find a sequence which has some frames; + shapeanimationsequence* sas=0; + for(i=0;ianimation_header->num_sequences;i++) + { + sas=&shp->animation_header->anim_sequences[i]; + if(sas->num_frames) + break; + + } + GLOBALASSERT(ianimation_header->num_sequences); + + //copy the pointers for the first frame of this sequence + #if !USE_LEVEL_MEMORY_POOL + DeallocateMem(shp->points[0]); + DeallocateMem(shp->sh_normals[0]); + DeallocateMem(shp->sh_vnormals[0]); + #endif + + shp->points[0]=sas->anim_frames[0].vertices; + shp->sh_normals[0]=sas->anim_frames[0].item_normals; + shp->sh_vnormals[0]=sas->vertex_normals; +} + + +BOOL copy_to_shapeheader ( + RIFFHANDLE h, + ChunkShape const & cshp, + SHAPEHEADER *& shphd, + Chunk_With_Children * shape, + int flags, + int local_max_index, + int * local_tex_index_nos, + int /*listpos*/, + const ChunkObject* object + ) +{ + ChunkShape merged_cshp; + const ChunkShape* cshp_ptr; + + if(shape->lookup_single_child("SHPMRGDT")) + { + merged_cshp=cshp; + pre_process_shape(h,merged_cshp,shape,flags); + + cshp_ptr=&merged_cshp; + } + else + { + cshp_ptr=&cshp; + } + + shphd = (SHAPEHEADER *) PoolAllocateMem(sizeof(SHAPEHEADER)); + memset(shphd,0,sizeof(SHAPEHEADER)); + + int i,j; + int * tptr; + + // header data (note shapeheader is calloced) + + shphd->numpoints = cshp_ptr->num_verts; + shphd->numitems = cshp_ptr->num_polys; + + + shphd->shaperadius = (int) (cshp_ptr->radius*local_scale); + + shphd->shapemaxx = (int) (cshp_ptr->max.x*local_scale); + shphd->shapeminx = (int) (cshp_ptr->min.x*local_scale); + shphd->shapemaxy = (int) (cshp_ptr->max.y*local_scale); + shphd->shapeminy = (int) (cshp_ptr->min.y*local_scale); + shphd->shapemaxz = (int) (cshp_ptr->max.z*local_scale); + shphd->shapeminz = (int) (cshp_ptr->min.z*local_scale); + + // AllocateMem arrays + + shphd->points = (int **) PoolAllocateMem (sizeof(int *)); + *(shphd->points) = (int *) PoolAllocateMem (sizeof(int) * shphd->numpoints * 3); + + shphd->sh_vnormals = (int **) PoolAllocateMem (sizeof(int *)); + *(shphd->sh_vnormals) = (int *) PoolAllocateMem (sizeof(int) * shphd->numpoints * 3); + + shphd->sh_normals = (int **) PoolAllocateMem (sizeof(int *)); + *(shphd->sh_normals) = (int *) PoolAllocateMem (sizeof(int) * shphd->numitems * 3); + + // for textures + if (cshp_ptr->num_uvs) + shphd->sh_textures = (int **) PoolAllocateMem (sizeof(int *) * cshp_ptr->num_uvs); + if (cshp_ptr->num_texfiles) + shphd->sh_localtextures = (char **) PoolAllocateMem (sizeof(char *) * (cshp_ptr->num_texfiles+1)); + + int * item_list; + + shphd->items = (int **) PoolAllocateMem (sizeof(int *) * shphd->numitems); + item_list = (int *) PoolAllocateMem (sizeof(int) * shphd->numitems * 9); + + tptr = *(shphd->points); + + + + if(object && local_scale!=1) + { + //convert from floating point to integers using world coordinates in an attempt to stop + //tears from being generated + ChunkVector object_float; + object_float.x=(double)object->location.x; + object_float.y=(double)object->location.y; + object_float.z=(double)object->location.z; + + VECTORCH object_int; + object_int.vx=object_float.x*local_scale; + object_int.vy=object_float.y*local_scale; + object_int.vz=object_float.z*local_scale; + + for (i=0; inumpoints; i++) { + tptr[i*3] = (int) ((cshp_ptr->v_list[i].x+object_float.x)*local_scale); + tptr[i*3 + 1] = (int) ((cshp_ptr->v_list[i].y+object_float.y)*local_scale); + tptr[i*3 + 2] = (int) ((cshp_ptr->v_list[i].z+object_float.z)*local_scale); + + tptr[i*3]-=object_int.vx; + tptr[i*3+1]-=object_int.vy; + tptr[i*3+2]-=object_int.vz; + } + + } + else + { + for (i=0; inumpoints; i++) { + tptr[i*3] = (int) (cshp_ptr->v_list[i].x*local_scale); + tptr[i*3 + 1] = (int) (cshp_ptr->v_list[i].y*local_scale); + tptr[i*3 + 2] = (int) (cshp_ptr->v_list[i].z*local_scale); + } + } + + tptr = *(shphd->sh_vnormals); + + for (i=0; inumpoints; i++) { + tptr[i*3] =(int) (cshp_ptr->v_normal_list[i].x*ONE_FIXED); + tptr[i*3 + 1] =(int) (cshp_ptr->v_normal_list[i].y*ONE_FIXED); + tptr[i*3 + 2] =(int) (cshp_ptr->v_normal_list[i].z*ONE_FIXED); + } + + tptr = *(shphd->sh_normals); + + for (i=0; inumitems; i++) { + tptr[i*3] =(int) (cshp_ptr->p_normal_list[i].x*ONE_FIXED); + tptr[i*3 + 1] =(int) (cshp_ptr->p_normal_list[i].y*ONE_FIXED); + tptr[i*3 + 2] =(int) (cshp_ptr->p_normal_list[i].z*ONE_FIXED); + } + + + for (i=0; inumitems; i++) + shphd->items[i] = &item_list[i*9]; + + int * uv_imnums = 0; + if (cshp_ptr->num_uvs) + { + uv_imnums = new int[cshp_ptr->num_uvs]; + for (i=0; inum_uvs; ++i) + { + uv_imnums[i]=-1; + shphd->sh_textures[i]=0; + } + } + + for (i=0; inumitems; i++) { + + item_list[i*9] = (cshp_ptr->poly_list[i].engine_type); + item_list[i*9 + 1] = (cshp_ptr->poly_list[i].normal_index * 3); + item_list[i*9 + 2] = (cshp_ptr->poly_list[i].flags&~ChunkInternalItemFlags); + item_list[i*9 + 3] = (cshp_ptr->poly_list[i].colour); + + if ( is_textured(item_list[i*9]) && !( item_list[i*9 + 3] & 0x8000 ) ) + { + int texno = item_list[i*9 + 3] & 0x7fff; + int UVIndex= item_list[i*9 + 3]>>16; + + if (texno <= local_max_index && + local_tex_index_nos[texno] != -1 && + cshp_ptr->uv_list[UVIndex].num_verts) + + { + item_list[i*9 + 3] &= 0xffff0000; + uv_imnums[item_list[i*9+3]>>16]=local_tex_index_nos[texno]; + item_list[i*9 + 3] += local_tex_index_nos[texno]; + + shphd->sh_textures[UVIndex] = (int *) PoolAllocateMem (sizeof(int) * cshp_ptr->uv_list[UVIndex].num_verts * 2); + for (j=0; juv_list[UVIndex].num_verts; j++) { + (shphd->sh_textures[UVIndex])[(j*2)] = ProcessUVCoord(h,UVC_POLY_U,(int)cshp_ptr->uv_list[UVIndex].vert[j].u,uv_imnums[UVIndex]); + (shphd->sh_textures[UVIndex])[(j*2)+1] = ProcessUVCoord(h,UVC_POLY_V,(int)cshp_ptr->uv_list[UVIndex].vert[j].v,uv_imnums[UVIndex]); + } + + + } + else + { + item_list[i*9] = I_Polyline; + item_list[i*9 + 2] = (cshp_ptr->poly_list[i].flags&~ChunkInternalItemFlags) | iflag_nolight; + item_list[i*9 + 3] = 0xffffffff; + } + } + + + for (j=0;jpoly_list[i].num_verts;j++) + // item_list[i*9 + 4 +j] = (cshp_ptr->poly_list[i].vert_ind[j] *3); + /* KJL 12:21:58 9/17/97 - I've removed the annoying *3 */ + item_list[i*9 + 4 +j] = (cshp_ptr->poly_list[i].vert_ind[j]); + for (;j<5;j++) + item_list[i*9 + 4 +j] = -1; + } + + if (uv_imnums) delete[] uv_imnums; + + if (cshp_ptr->num_texfiles) + { + for (i=0; inum_texfiles; i++) { + #if john + shphd->sh_localtextures[i] = + (char *) PoolAllocateMem (sizeof(char) * (strlen(cshp_ptr->texture_fns[i]) + strlen(TexturesRoot) + 1) ); + sprintf (shphd->sh_localtextures[i],"%s%s",TexturesRoot, cshp_ptr->texture_fns[i]); + char * dotpos; + dotpos = strrchr (shphd->sh_localtextures[i], '.'); + sprintf (dotpos,".pg0"); + #else + shphd->sh_localtextures[i] = + (char *) PoolAllocateMem (sizeof(char) * (strlen(cshp_ptr->texture_fns[i]) + 1) ); + strcpy (shphd->sh_localtextures[i], cshp_ptr->texture_fns[i]); + #endif + } + shphd->sh_localtextures[i] = 0; + } + + + + + SHAPEINSTR * instruct = (SHAPEINSTR *)PoolAllocateMem(sizeof(SHAPEINSTR)*6); + + shphd->sh_instruction = instruct; + + + instruct[0].sh_instr = I_ShapePoints; /*I_shapepoints*/ + instruct[0].sh_numitems = shphd->numpoints; + instruct[0].sh_instr_data = shphd->points; + + instruct[1].sh_instr = I_ShapeNormals; /*I_shapenormals*/ + instruct[1].sh_numitems = shphd->numitems; + instruct[1].sh_instr_data = shphd->sh_normals; + + instruct[2].sh_instr = I_ShapeProject; /*I_shapeproject*/ + instruct[2].sh_numitems = shphd->numpoints; + instruct[2].sh_instr_data = shphd->points; + + instruct[3].sh_instr = I_ShapeVNormals; /*I_shapevnormals*/ + instruct[3].sh_numitems = shphd->numpoints; + instruct[3].sh_instr_data = shphd->sh_vnormals; + + instruct[4].sh_instr = I_ShapeItems; + instruct[4].sh_numitems = shphd->numitems; + instruct[4].sh_instr_data = shphd->items; + + instruct[5].sh_instr = I_ShapeEnd; /*I_shapeEND*/ + instruct[5].sh_numitems = 0; + instruct[5].sh_instr_data = 0; + + + Chunk * pchAnim = shape->lookup_single_child("TEXTANIM"); + if(pchAnim) + { + Animation_Chunk* ac=(Animation_Chunk*)pchAnim; + Shape_Merge_Data_Chunk* smdc=0; + Chunk * pCh = shape->lookup_single_child("SHPMRGDT"); + if(pCh) smdc=(Shape_Merge_Data_Chunk*)pCh; + SetupAnimatedTextures((Shape_Chunk*)shape,shphd,ac,smdc, local_tex_index_nos); + } + + if(shape->count_children("ANIMSEQU")) + { + Shape_Merge_Data_Chunk* smdc=0; + Chunk * pCh=shape->lookup_single_child("SHPMRGDT"); + if(pCh) smdc=(Shape_Merge_Data_Chunk*)pCh; + SetupAnimatingShape((Shape_Chunk*)shape,shphd,smdc); + } + + return TRUE; + + +} +BOOL copy_preprocessed_to_shapeheader ( + RIFFHANDLE h, + Shape_Preprocessed_Data_Chunk* spdc, + SHAPEHEADER *& shphd, + Chunk_With_Children * shape, + int /*flags*/, + int local_max_index, + int * local_tex_index_nos, + int /*listpos*/, + const ChunkObject* object + ) +{ + shphd = (SHAPEHEADER*)spdc->GetMemoryBlock(); + + for (int i=0; inumitems; i++) + { + if(is_textured(shphd->items[i][0])) + { + int texno = shphd->items[i][3] & 0x7fff; + if (texno <= local_max_index && + local_tex_index_nos[texno] != -1) + + { + shphd->items[i][3] &= 0xffff0000; + shphd->items[i][3] += local_tex_index_nos[texno]; + + + } + else + { + shphd->items[i][0] = I_Polyline; + shphd->items[i][2] |=iflag_nolight; + shphd->items[i][3] = 0xffffffff; + } + } + } + + + return TRUE; + + +} + +BOOL copy_sprite_to_shapeheader (RIFFHANDLE h, SHAPEHEADER *& shphd,Sprite_Header_Chunk* shc, int listpos) +{ + Chunk * pChunk=shc->lookup_single_child("SPRITEPC"); + if(!pChunk) + { + return 0; + } + PC_Sprite_Chunk* sc=(PC_Sprite_Chunk*)pChunk; + + pChunk = shc->lookup_single_child("SPRISIZE"); + if(!pChunk) + { + return 0; + } + Sprite_Size_Chunk* ssc=(Sprite_Size_Chunk*)pChunk; + + Sprite_Extent_Chunk* sec=0; + pChunk=shc->lookup_single_child("SPREXTEN"); + if(pChunk) + sec=(Sprite_Extent_Chunk*)pChunk; + + pChunk=shc->lookup_single_child("SPRBMPSC"); + if(!pChunk) + { + return 0; + } + Sprite_Bitmap_Scale_Chunk* sbsc=(Sprite_Bitmap_Scale_Chunk*)pChunk; + + shphd = (SHAPEHEADER *) PoolAllocateMem(sizeof(SHAPEHEADER)); + memset(shphd,0,sizeof(SHAPEHEADER)); + + int i; + int * tptr; + int * BmpConv=0; + int local_max_index; + String sprite_name; + + + + Bitmap_List_Store_Chunk * blsc = 0; + + + pChunk = shc->lookup_single_child("BMPLSTST"); + if (pChunk) + { + blsc = (Bitmap_List_Store_Chunk *) pChunk; + } + pChunk = shc->lookup_single_child("RIFFNAME"); + if (pChunk) + { + sprite_name = ((RIF_Name_Chunk *)pChunk)->rif_name; + msl_shapes.add_entry(new ShapeInMSL(shphd,sprite_name,listpos)); + } + + if (blsc) + { + // load in the textures from the shape + + local_max_index = 0; + for (LIF bns (&blsc->bmps); !bns.done(); bns.next()) + { + local_max_index = max(bns().index,local_max_index); + } + + BmpConv = new int [local_max_index+1]; + for (i=0; i<=local_max_index; i++) + { + BmpConv[i] = -1; + } + + if (Env_Chunk == 0) + Env_Chunk = h->fc; + // JH 17-2-97 -- image loaders have changed to avoid loading the same image twice + for (bns.restart() ; !bns.done(); bns.next()) + { + if(bns().flags & ChunkBMPFlag_NotInPC) continue; + + String tex; + if (bns().flags & ChunkBMPFlag_IFF) + { + tex = bns().filename; + } + else + { + tex = sprite_name; + tex += "\\"; + tex += bns().filename; + } + + int imgnum = load_rif_bitmap(bns().filename,bns().flags); + if (GEI_NOTLOADED != imgnum) + BmpConv[bns().index] = imgnum; + } + + } + // header data (note shapeheader is calloced) + + shphd->numpoints = 4; + shphd->numitems = 1; + + + shphd->shaperadius =ssc->radius*GlobalScale; + + if(sec) + { + shphd->shapemaxx =sec->maxx*GlobalScale; + shphd->shapeminx =sec->minx*GlobalScale; + shphd->shapemaxy =sec->maxy*GlobalScale; + shphd->shapeminy =sec->miny*GlobalScale; + + } + else + { + shphd->shapemaxx =ssc->maxx*GlobalScale; + shphd->shapeminx =-ssc->maxx*GlobalScale; + shphd->shapemaxy =ssc->maxy*GlobalScale; + shphd->shapeminy =-ssc->maxy*GlobalScale; + } + shphd->shapemaxz =501*GlobalScale; + shphd->shapeminz =-501*GlobalScale; + + // AllocateMem arrays + + shphd->points = (int **) PoolAllocateMem (sizeof(int *)); + *(shphd->points) = (int *) PoolAllocateMem (sizeof(int) * shphd->numpoints * 3); + + shphd->sh_vnormals = (int **) PoolAllocateMem (sizeof(int *)); + *(shphd->sh_vnormals) = (int *) PoolAllocateMem (sizeof(int) * shphd->numpoints * 3); + + shphd->sh_normals = (int **) PoolAllocateMem (sizeof(int *)); + *(shphd->sh_normals) = (int *) PoolAllocateMem (sizeof(int) * shphd->numitems * 3); + + shphd->sh_textures = (int **) PoolAllocateMem (sizeof(int *)); + + int * item_list; + + shphd->items = (int **) PoolAllocateMem (sizeof(int *) * shphd->numitems); + item_list = (int *) PoolAllocateMem (sizeof(int) * shphd->numitems * 9); + + tptr = *(shphd->points); + + tptr[0]=shphd->shapemaxx; + tptr[1]=shphd->shapeminy; + tptr[2]=0; + tptr[3]=shphd->shapemaxx; + tptr[4]=shphd->shapemaxy; + tptr[5]=0; + tptr[6]=shphd->shapeminx; + tptr[7]=shphd->shapemaxy; + tptr[8]=0; + tptr[9]=shphd->shapeminx; + tptr[10]=shphd->shapeminy; + tptr[11]=0; + + tptr = *(shphd->sh_vnormals); + + for (i=0; inumpoints; i++) { + tptr[i*3] = 0; + tptr[i*3 + 1] = 0; + tptr[i*3 + 2] = ONE_FIXED; + } + + tptr = *(shphd->sh_normals); + + for (i=0; inumitems; i++) { + tptr[i*3] = 0; + tptr[i*3 + 1] = 0; + tptr[i*3 + 2] = ONE_FIXED; + } + + + for (i=0; inumitems; i++) + shphd->items[i] = &item_list[i*9]; + + + item_list[0]=I_2dTexturedPolygon; + item_list[1]=0; + item_list[2]=iflag_ignore0| iflag_txanim|iflag_no_bfc; + if(ssc->Flags & SpriteFlag_NoLight) item_list[2]|=iflag_nolight; + if(ssc->Flags & SpriteFlag_SemiTrans) item_list[2]|=iflag_transparent; + item_list[3]=0; + item_list[4]=0; + item_list[5]=1; + item_list[6]=2; + item_list[7]=3; + item_list[8]=-1; + + SHAPEINSTR * instruct = (SHAPEINSTR *)PoolAllocateMem(sizeof(SHAPEINSTR)*6); + + shphd->sh_instruction = instruct; + + instruct[0].sh_instr = I_ShapeSpriteRPoints; /*I_shapepoints*/ + instruct[0].sh_numitems = 4; + instruct[0].sh_instr_data = shphd->points; + + instruct[1].sh_instr = I_ShapeNormals; /*I_shapenormals*/ + instruct[1].sh_numitems = shphd->numitems; + instruct[1].sh_instr_data = shphd->sh_normals; + + instruct[2].sh_instr = I_ShapeProject; /*I_shapeproject*/ + instruct[2].sh_numitems = shphd->numpoints; + instruct[2].sh_instr_data = shphd->points; + + instruct[3].sh_instr = I_ShapeVNormals; /*I_shapevnormals*/ + instruct[3].sh_numitems = shphd->numpoints; + instruct[3].sh_instr_data = shphd->sh_vnormals; + + instruct[4].sh_instr = I_ShapeItems; + instruct[4].sh_numitems = shphd->numitems; + instruct[4].sh_instr_data = shphd->items; + + instruct[5].sh_instr = I_ShapeEnd; /*I_shapeEND*/ + instruct[5].sh_numitems = 0; + instruct[5].sh_instr_data = 0; + + shphd->shapeflags=ShapeFlag_MultiViewSprite|ShapeFlag_SpriteResizing|ShapeFlag_Sprite; + + List chlist; + sc->lookup_child("SPRACTIO",chlist); + + int MaxSeq=0; + for(LIFchlif(&chlist);!chlif.done();chlif.next()) + { + MaxSeq=max(MaxSeq,((Sprite_Action_Chunk*)chlif())->Action); + } + txanimheader** thlist=(txanimheader**)PoolAllocateMem((3+MaxSeq)*sizeof(txanimheader)); + thlist[0]=thlist[MaxSeq+2]=0; + for(i=1;itxa_numframes=0; + thlist[i]->txa_maxframe=0; + thlist[i]->txa_num_mvs_images=0; + thlist[i]->txa_framedata=0; + } + while(chlist.size()) + { + Sprite_Action_Chunk* sac=(Sprite_Action_Chunk*) chlist.first_entry(); + txanimheader* th=thlist[sac->Action+1]; + + th->txa_flags=txa_flag_play; + th->txa_numframes=sac->NumFrames+1; + th->txa_currentframe=0; + th->txa_state=0; + th->txa_maxframe=(th->txa_numframes-1)<<16; + if(sac->FrameTime) + th->txa_speed=65536000/sac->FrameTime; + else + th->txa_speed=65536*8; + + th->txa_num_mvs_images=sac->NumYaw*sac->NumPitch*2; + + th->txa_eulerxshift=12; + int j=sac->NumPitch; + while(j) + { + j=j>>1; + th->txa_eulerxshift--; + } + th->txa_euleryshift=12; + j=sac->NumYaw; + while(j) + { + j=j>>1; + th->txa_euleryshift--; + } + if(sac->NumYaw==1) + { + th->txa_euleryshift=12; + th->txa_num_mvs_images=sac->NumPitch; + } + + th->txa_framedata=(txanimframe*)PoolAllocateMem(th->txa_numframes*sizeof(txanimframe_mvs)); + + txanimframe_mvs* tf; + for(j=0;jtxa_numframes;j++) + { + int framefrom=j; + if(j==sac->NumFrames) framefrom=0; + tf=(txanimframe_mvs*)&th->txa_framedata[j]; + tf->txf_flags=0; + tf->txf_scale=ONE_FIXED; + tf->txf_scalex=0; + tf->txf_scaley=0; + tf->txf_orient=0; + tf->txf_orientx=0; + tf->txf_orienty=0; + tf->txf_numuvs=4; + + tf->txf_uvdata=(int**)PoolAllocateMem((th->txa_num_mvs_images)*sizeof(int*)); + int* uvdata=(int*)PoolAllocateMem(th->txa_num_mvs_images*16*sizeof(int)); + for(int k=0;ktxa_num_mvs_images;k++) + { + tf->txf_uvdata[k]=&uvdata[16*k]; + } + + tf->txf_images=(int*)PoolAllocateMem(th->txa_num_mvs_images*sizeof(int)); + int ny=2*sac->NumYaw; + if(sac->NumYaw==1) ny=1; + int y,y2; + int pos,pos2; + for(y=0;yNumPitch;p++) + { + y2=(y-1+ny)%ny; + pos=y*sac->NumPitch+p; + pos2=y2*sac->NumPitch+p; + Frame* f=&sac->FrameList[y/2][p][framefrom]; + + GLOBALASSERT(f->Texture<=local_max_index); + GLOBALASSERT(f->Texture>=0); + GLOBALASSERT(BmpConv[f->Texture]!=-1); + + tf->txf_images[pos]=BmpConv[f->Texture]; + tf->txf_images[pos2]=BmpConv[f->Texture]; + + float bmpscale=sbsc->Scale[f->Texture]; + if(y>ny/2 && (sac->Flags & SpriteActionFlag_FlipSecondSide)) + { + for(int l=0;l<4;l++) + { + tf->txf_uvdata[pos][l*2]=ProcessUVCoord(h,UVC_SPRITE_U,f->UVCoords[3-l][0]<<16,BmpConv[f->Texture]); + tf->txf_uvdata[pos][l*2+1]=ProcessUVCoord(h,UVC_SPRITE_V,f->UVCoords[3-l][1]<<16,BmpConv[f->Texture]); + tf->txf_uvdata[pos2][l*2]=ProcessUVCoord(h,UVC_SPRITE_U,f->UVCoords[3-l][0]<<16,BmpConv[f->Texture]); + tf->txf_uvdata[pos2][l*2+1]=ProcessUVCoord(h,UVC_SPRITE_V,f->UVCoords[3-l][1]<<16,BmpConv[f->Texture]); + + + tf->txf_uvdata[pos][l*2+8]=-(f->UVCoords[3-l][0]-f->CentreX)*bmpscale*GlobalScale; + tf->txf_uvdata[pos][l*2+9]=(f->UVCoords[3-l][1]-f->CentreY)*bmpscale*GlobalScale; + tf->txf_uvdata[pos2][l*2+8]=-(f->UVCoords[3-l][0]-f->CentreX)*bmpscale*GlobalScale; + tf->txf_uvdata[pos2][l*2+9]=(f->UVCoords[3-l][1]-f->CentreY)*bmpscale*GlobalScale; + + } + } + else + { + for(int l=0;l<4;l++) + { + tf->txf_uvdata[pos][l*2]=ProcessUVCoord(h,UVC_SPRITE_U,f->UVCoords[l][0]<<16,BmpConv[f->Texture]); + tf->txf_uvdata[pos][l*2+1]=ProcessUVCoord(h,UVC_SPRITE_V,f->UVCoords[l][1]<<16,BmpConv[f->Texture]); + tf->txf_uvdata[pos2][l*2]=ProcessUVCoord(h,UVC_SPRITE_U,f->UVCoords[l][0]<<16,BmpConv[f->Texture]); + tf->txf_uvdata[pos2][l*2+1]=ProcessUVCoord(h,UVC_SPRITE_V,f->UVCoords[l][1]<<16,BmpConv[f->Texture]); + + + tf->txf_uvdata[pos][l*2+8]=(f->UVCoords[l][0]-f->CentreX)*bmpscale*GlobalScale; + tf->txf_uvdata[pos][l*2+9]=(f->UVCoords[l][1]-f->CentreY)*bmpscale*GlobalScale; + tf->txf_uvdata[pos2][l*2+8]=(f->UVCoords[l][0]-f->CentreX)*bmpscale*GlobalScale; + tf->txf_uvdata[pos2][l*2+9]=(f->UVCoords[l][1]-f->CentreY)*bmpscale*GlobalScale; + + } + } + } + } + } + + chlist.delete_first_entry(); + } + shphd->sh_textures[0]=(int*)thlist; + delete [] BmpConv; + return TRUE; +} + + + +BOOL copy_to_map6(Object_Chunk * ob,MAPBLOCK6* mapblock, int shplst_pos) +{ + + Object_Project_Data_Chunk * opdc = 0; + Map_Block_Chunk * mapblok = 0; + Strategy_Chunk * strat = 0; + + if (ob->object_data.is_base_object) + *mapblock = Empty_Landscape_Type6; + else *mapblock = Empty_Object_Type6; + + + + Chunk * pChunk = ob->lookup_single_child("OBJPRJDT"); + if (pChunk) opdc = (Object_Project_Data_Chunk *)pChunk; + if (opdc) + { + pChunk = opdc->lookup_single_child("MAPBLOCK"); + if (pChunk) mapblok = (Map_Block_Chunk *)pChunk; + pChunk = opdc->lookup_single_child("STRATEGY"); + if (pChunk) strat = (Strategy_Chunk *)pChunk; + } + + if (mapblok) + { + mapblock->MapType = mapblok->map_data.MapType; + mapblock->MapFlags= mapblok->map_data.MapFlags; + + #if (StandardStrategyAndCollisions || IntermediateSSACM) + mapblock->MapCType = mapblok->map_data.MapCType; + mapblock->MapCGameType = mapblok->map_data.MapCGameType; + mapblock->MapCStrategyS = mapblok->map_data.MapCStrategyS; + mapblock->MapCStrategyL = mapblok->map_data.MapCStrategyL; + #endif + + mapblock->MapInteriorType = mapblok->map_data.MapInteriorType; +// mapblock->MapLightType = mapblok->map_data.MapLightType; +// mapblock->MapMass = mapblok->map_data.MapMass; +// mapblock->MapNewtonV.vx = mapblok->map_data.MapNewtonV.vx; +// mapblock->MapNewtonV.vy = mapblok->map_data.MapNewtonV.vy; +// mapblock->MapNewtonV.vz = mapblok->map_data.MapNewtonV.vz; +// mapblock->MapOrigin.vx = mapblok->map_data.MapOrigin.vx; +// mapblock->MapOrigin.vy = mapblok->map_data.MapOrigin.vy; +// mapblock->MapOrigin.vz = mapblok->map_data.MapOrigin.vz; +// mapblock->MapViewType = mapblok->map_data.MapViewType; + } + + #if (StandardStrategyAndCollisions || IntermediateSSACM) + if (strat) + { + mapblock->MapStrategy = strat->strategy_data.Strategy; + } + #endif + + mapblock->MapShape = shplst_pos; + + mapblock->MapWorld.vx = (int) (ob->object_data.location.x*local_scale); + mapblock->MapWorld.vy = (int) (ob->object_data.location.y*local_scale); + mapblock->MapWorld.vz = (int) (ob->object_data.location.z*local_scale); + + QUAT q; + + q.quatx = -ob->object_data.orientation.x*ONE_FIXED; + q.quaty = -ob->object_data.orientation.y*ONE_FIXED; + q.quatz = -ob->object_data.orientation.z*ONE_FIXED; + q.quatw = ob->object_data.orientation.w*ONE_FIXED; + + MATRIXCH m; + + QuatToMat (&q, &m); + + EULER e; + + MatrixToEuler(&m, &e); + + /* + This function is only being used by the tools. + At least for the moment I need the Euler to contain + the 'inverse' rotation ,until I get round to sorting things + out properly. Richard + */ + + mapblock->MapEuler.EulerX = e.EulerX; + mapblock->MapEuler.EulerY = e.EulerY; + mapblock->MapEuler.EulerZ = e.EulerZ; + + #if InterfaceEngine + mapblock->o_chunk = (void *)ob; + #endif + + return TRUE; +} + + + + + +BOOL tex_merge_polys ( ChunkPoly & p1, ChunkPoly & p2, ChunkPoly & p, ChunkShape & shp, int * /*mgd*/) +{ + int j; + + if (p1.engine_type != p2.engine_type) + return(FALSE); + + if ((p1.colour & 0xffff) != (p2.colour & 0xffff)) + return(FALSE); + + if (p1.flags != p2.flags) + return(FALSE); + + + int p1_uvind = p1.colour >> 16; + int p2_uvind = p2.colour >> 16; + + ChunkUV_List uv; + p = p1; + p.num_verts = 4; + uv.num_verts = 4; + + int num_ins = 0; + int p_onv = 0; + int new_p_onv; + int * p_on = p1.vert_ind; + int * p_oth = p2.vert_ind; + int * temp; + + ChunkUV * uv_on = shp.uv_list[p1_uvind].vert; + ChunkUV * uv_oth = shp.uv_list[p2_uvind].vert; + ChunkUV * uvtemp; + + while (num_ins < 4) + { + uv.vert[num_ins] = uv_on[p_onv]; + p.vert_ind[num_ins++] = p_on[p_onv]; + for (j=0; j<3; j++) + { + if (p_on[p_onv] == p_oth[j] && + (uv_on[p_onv].u != uv_oth[j].u || uv_on[p_onv].v != uv_oth[j].v)) + { + return(FALSE); + } + if (p_on[p_onv] == p_oth[j]) + break; + } + if (j==3) p_onv = (p_onv+1)%3; + else + { + new_p_onv = j; + for (j=0; j<3; j++) + { + if (p_on[(p_onv+1)%3] == p_oth[j] && + (uv_on[(p_onv+1)%3].u != uv_oth[j].u || uv_on[(p_onv+1)%3].v != uv_oth[j].v)) + { + return (FALSE); + } + if (p_on[(p_onv+1)%3] == p_oth[j]) + break; + } + if (j==3) p_onv = (p_onv+1)%3; + else + { + temp = p_on; + p_on = p_oth; + p_oth = temp; + p_onv = (new_p_onv+1)%3; + + uvtemp = uv_on; + uv_on = uv_oth; + uv_oth = uvtemp; + } + } + } + + shp.uv_list[p1_uvind] = uv; + + return(TRUE); + + +} + +BOOL merge_polys ( ChunkPoly & p1, ChunkPoly & p2, ChunkPoly & p, int * /*mgd*/) +{ + int j; + + if (p1.engine_type != p2.engine_type) + return(FALSE); + + if (p1.colour != p2.colour) + return(FALSE); + + if (p1.flags != p2.flags) + return(FALSE); + + + p = p1; + p.num_verts = 4; + int num_ins = 0; + int p_onv = 0; + int new_p_onv; + int * p_on = p1.vert_ind; + int * p_oth = p2.vert_ind; + int * temp; + + while (num_ins < 4) + { + p.vert_ind[num_ins++] = p_on[p_onv]; + for (j=0; j<3; j++) + { + if (p_on[p_onv] == p_oth[j]) + break; + } + if (j==3) p_onv = (p_onv+1)%3; + else + { + new_p_onv = j; + for (j=0; j<3; j++) + { + if (p_on[(p_onv+1)%3] == p_oth[j]) + break; + } + if (j==3) p_onv = (p_onv+1)%3; + else + { + temp = p_on; + p_on = p_oth; + p_oth = temp; + p_onv = (new_p_onv+1)%3; + } + } + } + return(TRUE); +} + + +void merge_polygons_in_chunkshape (ChunkShape & shp, Shape_Merge_Data_Chunk * smdc) +{ + int * mgd = smdc->merge_data; + + int p_no = 0; + + + ChunkPoly * new_polys = new ChunkPoly [shp.num_polys]; + ChunkVectorFloat * new_pnorms = new ChunkVectorFloat [shp.num_polys]; + + for (int i = 0; ii) + { + ChunkPoly p; + + BOOL merged = FALSE; + + //make sure points are within 10mm of being planar + + int mpoly=mgd[i]; + //find the 'unique vertex' in the second triangle + for(int j=0;j<3;j++) + { + for(int k=0;k<3;k++) + { + if(shp.poly_list[mpoly].vert_ind[j]==shp.poly_list[i].vert_ind[k])break; + } + if(k==3) + { + break; + } + } + GLOBALASSERT(j!=3); + int vert1=shp.poly_list[mpoly].vert_ind[j]; + int vert2=shp.poly_list[mpoly].vert_ind[(j+1)%3]; + ChunkVectorInt diff=shp.v_list[vert1]-shp.v_list[vert2]; + ChunkVectorFloat* norm=&shp.p_normal_list[i]; + + //take the dot product of the normal and the difference to find the distance form the first + //triangles plane + float distance= (float)diff.x*norm->x + (float)diff.y*norm->y + (float)diff.z*norm->z; + + if(distance>-1 && distance <1) + { + if (is_textured(shp.poly_list[i].engine_type)) + { + merged = tex_merge_polys ( shp.poly_list[i], shp.poly_list[mgd[i]], p, shp, mgd); + } + else + { + merged = merge_polys ( shp.poly_list[i], shp.poly_list[mgd[i]], p, mgd); + } + } + if (merged) + { + p.normal_index = p_no; + new_polys[p_no] = p; + new_pnorms[p_no] = shp.p_normal_list[i]; + p_no++; + } + else + { + new_polys[p_no] = shp.poly_list[i]; + new_polys[p_no].normal_index = p_no; + new_pnorms[p_no] = shp.p_normal_list[i]; + p_no ++; + + new_polys[p_no] = shp.poly_list[mgd[i]]; + new_polys[p_no].normal_index = p_no; + new_pnorms[p_no] = shp.p_normal_list[mgd[i]]; + p_no ++; + } + + } + } + + delete [] shp.poly_list; + delete [] shp.p_normal_list; + shp.poly_list = new_polys; + shp.p_normal_list = new_pnorms; + shp.num_polys = p_no; + +} + + + + + + +#if 0 +BOOL copy_to_mainshpl (Shape_Chunk * shp, int list_pos) +{ + SHAPEHEADER * shphd = (SHAPEHEADER *) AllocateMem(sizeof(SHAPEHEADER)); + memset(shphd,0,sizeof(SHAPEHEADER)); + + ChunkShape cshp = shp->shape_data; + + Shape_Merge_Data_Chunk * smdc = 0; + + Chunk * pChunk = shp->lookup_single_child("SHPMRGDT"); + if (pChunk) + { + smdc = (Shape_Merge_Data_Chunk *) pChunk; + } + + merge_polygons_in_chunkshape (cshp,smdc); + + int i,j, * tptr; + + mainshapelist[list_pos] = shphd; + + // header data (note shapeheader is calloced) + + shphd->shapeflags = shphd->shapeflags | (ShapeFlag_AugZ | ShapeFlag_AugZ_Lite | + ShapeFlag_SizeSortItems); // SIZE HACK!!! + shphd->numpoints = cshp.num_verts; + shphd->numitems = cshp.num_polys; + + shphd->shaperadius = (int) (cshp.radius*local_scale); + + shphd->shapemaxx = (int) (cshp.max.x*local_scale); + shphd->shapeminx = (int) (cshp.min.x*local_scale); + shphd->shapemaxy = (int) (cshp.max.y*local_scale); + shphd->shapeminy = (int) (cshp.min.y*local_scale); + shphd->shapemaxz = (int) (cshp.max.z*local_scale); + shphd->shapeminz = (int) (cshp.min.z*local_scale); + + // AllocateMem arrays + + shphd->points = (int **) AllocateMem (sizeof(int *)); + *(shphd->points) = (int *) AllocateMem (sizeof(int) * shphd->numpoints * 3); + + shphd->sh_vnormals = (int **) AllocateMem (sizeof(int *)); + *(shphd->sh_vnormals) = (int *) AllocateMem (sizeof(int) * shphd->numpoints * 3); + + shphd->sh_normals = (int **) AllocateMem (sizeof(int *)); + *(shphd->sh_normals) = (int *) AllocateMem (sizeof(int) * shphd->numitems * 3); + + // for textures + if (cshp.num_uvs) + shphd->sh_textures = (int **) AllocateMem (sizeof(int *) * cshp.num_uvs); + if (cshp.num_texfiles) + shphd->sh_localtextures = (char **) AllocateMem (sizeof(char *) * (cshp.num_texfiles+1)); + + int * item_list; + + shphd->items = (int **) AllocateMem (sizeof(int *) * shphd->numitems); + item_list = (int *) AllocateMem (sizeof(int) * shphd->numitems * 9); + + tptr = *(shphd->points); + + for (i=0; inumpoints; i++) { + tptr[i*3] = (int) (cshp.v_list[i].x*local_scale); + tptr[i*3 + 1] = (int) (cshp.v_list[i].y*local_scale); + tptr[i*3 + 2] = (int) (cshp.v_list[i].z*local_scale); + } + + tptr = *(shphd->sh_vnormals); + + for (i=0; inumpoints; i++) { + tptr[i*3] = (int) (cshp.v_normal_list[i].x*ONE_FIXED); + tptr[i*3 + 1] = (int) (cshp.v_normal_list[i].y*ONE_FIXED); + tptr[i*3 + 2] = (int) (cshp.v_normal_list[i].z*ONE_FIXED); + } + + tptr = *(shphd->sh_normals); + + for (i=0; inumitems; i++) { + tptr[i*3] = (int) (cshp.p_normal_list[i].x*ONE_FIXED); + tptr[i*3 + 1] = (int) (cshp.p_normal_list[i].y*ONE_FIXED); + tptr[i*3 + 2] = (int) (cshp.p_normal_list[i].z*ONE_FIXED); + } + + + for (i=0; inumitems; i++) + shphd->items[i] = &item_list[i*9]; + + + + for (i=0; inumitems; i++) { + + + item_list[i*9] = (cshp.poly_list[i].engine_type); +// item_list[i*9] = I_Polyline; + + /* trap for polylines*/ + if((item_list[i*9] < 2 ) || (item_list[i*9] > 9)) + { + item_list[i*9] = I_Polygon; + } +#if 1 + /* try to set gouraud, for hazing*/ + + if(item_list[i*9] == I_Polygon) + { + item_list[i*9] = I_GouraudPolygon; + } + + if(item_list[i*9] == I_2dTexturedPolygon) + { + item_list[i*9] = I_Gouraud2dTexturedPolygon; + } + + if(item_list[i*9] == I_3dTexturedPolygon) + { + item_list[i*9] = I_Gouraud2dTexturedPolygon; + } +#endif + +// if(item_list[i*9] == I_Polygon) +// { +// item_list[i*9] = I_ZB_Polygon; +// /*HACK HACK ROXHACK*/ +// } + + #if SupportZBuffering + #else + if(item_list[i*9] == I_ZB_Polygon) + item_list[i*9] = I_Polygon; + + if(item_list[i*9] == I_ZB_GouraudPolygon) + item_list[i*9] = I_GouraudPolygon; + + if(item_list[i*9] == I_ZB_PhongPolygon) + item_list[i*9] = I_PhongPolygon; + + if(item_list[i*9] == I_ZB_2dTexturedPolygon) + item_list[i*9] = I_2dTexturedPolygon; + + if(item_list[i*9] == I_ZB_Gouraud2dTexturedPolygon) + item_list[i*9] = I_Gouraud2dTexturedPolygon; + + if(item_list[i*9] == I_ZB_3dTexturedPolygon) + item_list[i*9] = I_3dTexturedPolygon; + #endif + + + + item_list[i*9 + 1] = (cshp.poly_list[i].normal_index * 3); + item_list[i*9 + 2] = (cshp.poly_list[i].flags&~ChunkInternalItemFlags); +// item_list[i*9 + 2] = (cshp.poly_list[i].flags) | iflag_nolight; + item_list[i*9 + 3] = (cshp.poly_list[i].colour); + +#if 1 + if ( (item_list[i*9] == I_2dTexturedPolygon + || item_list[i*9] == I_Gouraud2dTexturedPolygon + || item_list[i*9] == I_3dTexturedPolygon + || item_list[i*9] == I_Gouraud3dTexturedPolygon + ) && + !( item_list[i*9 + 3] & 0x8000 ) ) + { + int texno = item_list[i*9 + 3] & 0x7fff; + + if (texno <= max_index) + if ((tex_index_nos[texno] != -1)) + { + item_list[i*9 + 3] &= 0xffff0000; + item_list[i*9 + 3] += tex_index_nos[texno]; + + /* hack in iflag_no_light */ + item_list[i*9 + 2] |= iflag_gsort_ptest /*| iflag_nolight*/ | iflag_linear_s | iflag_tx2dor3d; + + } + else + { + item_list[i*9] = I_Polygon; + item_list[i*9 + 2] = (cshp.poly_list[i].flags&~ChunkInternalItemFlags) | iflag_nolight; + item_list[i*9 + 3] = 0xffffffff; + } + else + { + item_list[i*9] = I_Polygon; + item_list[i*9 + 2] = (cshp.poly_list[i].flags&~ChunkInternalItemFlags) | iflag_nolight; + item_list[i*9 + 3] = 0xffffffff; + } + } +#endif + +// item_list[i*9 + 3] = 0xffffffff; + + + for (j=0;jsh_textures[i] = (int *) AllocateMem (sizeof(int) * cshp.uv_list[i].num_verts * 2); + for (j=0; jsh_textures[i])[(j*2)] = (int)cshp.uv_list[i].vert[j].u; + (shphd->sh_textures[i])[(j*2)+1] = (int)cshp.uv_list[i].vert[j].v; + } + } + } + + if (cshp.num_texfiles) + { + for (i=0; ish_localtextures[i] = + (char *) AllocateMem (sizeof(char) * (strlen(cshp.texture_fns[i]) + strlen(TexturesRoot) + 1) ); + sprintf (shphd->sh_localtextures[i],"%s%s",TexturesRoot, cshp.texture_fns[i]); + char * dotpos; + dotpos = strrchr (shphd->sh_localtextures[i], '.'); + sprintf (dotpos,".pg0"); + #else + shphd->sh_localtextures[i] = + (char *) AllocateMem (sizeof(char) * (strlen(cshp.texture_fns[i]) + 1) ); + strcpy (shphd->sh_localtextures[i], cshp.texture_fns[i]); + #endif + } + shphd->sh_localtextures[i] = 0; + } + + + + + SHAPEINSTR * instruct = (SHAPEINSTR *)AllocateMem(sizeof(SHAPEINSTR)*6); + + shphd->sh_instruction = instruct; + + + + instruct[0].sh_instr = I_ShapePoints; /*I_shapepoints*/ + instruct[0].sh_numitems = shphd->numpoints; + instruct[0].sh_instr_data = shphd->points; + + instruct[1].sh_instr = I_ShapeNormals; /*I_shapenormals*/ + instruct[1].sh_numitems = shphd->numitems; + instruct[1].sh_instr_data = shphd->sh_normals; + + instruct[2].sh_instr = I_ShapeProject; /*I_shapeproject*/ + instruct[2].sh_numitems = shphd->numpoints; + instruct[2].sh_instr_data = shphd->points; + + instruct[3].sh_instr = I_ShapeVNormals; /*I_shapevnormals*/ + instruct[3].sh_numitems = shphd->numpoints; + instruct[3].sh_instr_data = shphd->sh_vnormals; + + instruct[4].sh_instr = I_ShapeItems; + instruct[4].sh_numitems = shphd->numitems; + instruct[4].sh_instr_data = shphd->items; + + instruct[5].sh_instr = I_ShapeEnd; /*I_shapeEND*/ + instruct[5].sh_numitems = 0; + instruct[5].sh_instr_data = 0; + + + Chunk * pchAnim = shp->lookup_single_child("TEXTANIM"); + if (pchAnim) + { + Shape_Merge_Data_Chunk* smdc=0; + Chunk * pChunk=shp->lookup_single_child("SHPMRGDT"); + if(pChunk) smdc=(Shape_Merge_Data_Chunk*)pChunk; + SetupAnimatedTextures(shp,shphd,(Animation_Chunk*)pchAnim,smdc); + } + + + + return TRUE; + +} +#endif + +#if 0 +BOOL copy_to_mainshpl (Shape_Sub_Shape_Chunk * shp, int list_pos) +{ + SHAPEHEADER * shphd = (SHAPEHEADER *) AllocateMem(sizeof(SHAPEHEADER)); + memset(shphd,0,sizeof(SHAPEHEADER)); + + ChunkShape cshp = shp->shape_data; + + Shape_Merge_Data_Chunk * smdc = 0; + + Chunk * pChunk = shp->lookup_single_child("SHPMRGDT"); + if (pChunk) + { + smdc = (Shape_Merge_Data_Chunk *) pChunk; + } + + merge_polygons_in_chunkshape (cshp,smdc); + + int i,j, * tptr; + + mainshapelist[list_pos] = shphd; + + // header data (note shapeheader is calloced) + + shphd->shapeflags = shphd->shapeflags | (ShapeFlag_AugZ | ShapeFlag_AugZ_Lite | + ShapeFlag_SizeSortItems); // SIZE HACK!!! + shphd->numpoints = cshp.num_verts; + shphd->numitems = cshp.num_polys; + + shphd->shaperadius = (int) (cshp.radius*local_scale); + + shphd->shapemaxx = (int) (cshp.max.x*local_scale); + shphd->shapeminx = (int) (cshp.min.x*local_scale); + shphd->shapemaxy = (int) (cshp.max.y*local_scale); + shphd->shapeminy = (int) (cshp.min.y*local_scale); + shphd->shapemaxz = (int) (cshp.max.z*local_scale); + shphd->shapeminz = (int) (cshp.min.z*local_scale); + + // AllocateMem arrays + + shphd->points = (int **) AllocateMem (sizeof(int *)); + *(shphd->points) = (int *) AllocateMem (sizeof(int) * shphd->numpoints * 3); + + shphd->sh_vnormals = (int **) AllocateMem (sizeof(int *)); + *(shphd->sh_vnormals) = (int *) AllocateMem (sizeof(int) * shphd->numpoints * 3); + + shphd->sh_normals = (int **) AllocateMem (sizeof(int *)); + *(shphd->sh_normals) = (int *) AllocateMem (sizeof(int) * shphd->numitems * 3); + + // for textures + if (cshp.num_uvs) + shphd->sh_textures = (int **) AllocateMem (sizeof(int *) * cshp.num_uvs); + if (cshp.num_texfiles) + shphd->sh_localtextures = (char **) AllocateMem (sizeof(char *) * (cshp.num_texfiles+1)); + + int * item_list; + + shphd->items = (int **) AllocateMem (sizeof(int *) * shphd->numitems); + item_list = (int *) AllocateMem (sizeof(int) * shphd->numitems * 9); + + tptr = *(shphd->points); + + for (i=0; inumpoints; i++) { + tptr[i*3] = (int) (cshp.v_list[i].x*local_scale); + tptr[i*3 + 1] = (int) (cshp.v_list[i].y*local_scale); + tptr[i*3 + 2] = (int) (cshp.v_list[i].z*local_scale); + } + + tptr = *(shphd->sh_vnormals); + + for (i=0; inumpoints; i++) { + tptr[i*3] = (int) (cshp.v_normal_list[i].x*ONE_FIXED); + tptr[i*3 + 1] = (int) (cshp.v_normal_list[i].y*ONE_FIXED); + tptr[i*3 + 2] = (int) (cshp.v_normal_list[i].z*ONE_FIXED); + } + + tptr = *(shphd->sh_normals); + + for (i=0; inumitems; i++) { + tptr[i*3] = (int) (cshp.p_normal_list[i].x*ONE_FIXED); + tptr[i*3 + 1] = (int) (cshp.p_normal_list[i].y*ONE_FIXED); + tptr[i*3 + 2] = (int) (cshp.p_normal_list[i].z*ONE_FIXED); + } + + + for (i=0; inumitems; i++) + shphd->items[i] = &item_list[i*9]; + + + + for (i=0; inumitems; i++) { + + + item_list[i*9] = (cshp.poly_list[i].engine_type); +// item_list[i*9] = I_Polyline; +#if 1 + /* try to set gouraud, for hazing*/ + + if(item_list[i*9] == I_Polygon) + { + item_list[i*9] = I_GouraudPolygon; + } + + if(item_list[i*9] == I_2dTexturedPolygon) + { + item_list[i*9] = I_Gouraud2dTexturedPolygon; + } + + if(item_list[i*9] == I_3dTexturedPolygon) + { + item_list[i*9] = I_Gouraud2dTexturedPolygon; + } +#endif + +// if((item_list[i*9] < 2 ) || (item_list[i*9] > 9)) +// { +// item_list[i*9] = I_Polygon; +// } +#if 1 + /* try to set gouraud, for hazing*/ + + if(item_list[i*9] == I_Polygon) + { + item_list[i*9] = I_GouraudPolygon; + } + + if(item_list[i*9] == I_2dTexturedPolygon) + { + item_list[i*9] = I_Gouraud2dTexturedPolygon; + } + + if(item_list[i*9] == I_3dTexturedPolygon) + { + item_list[i*9] = I_Gouraud2dTexturedPolygon; + } +#endif + +// if(item_list[i*9] == I_Polygon) +// { +// item_list[i*9] = I_ZB_Polygon; +// /*HACK HACK ROXHACK*/ +// } + + #if SupportZBuffering + #else + if(item_list[i*9] == I_ZB_Polygon) + item_list[i*9] = I_Polygon; + + if(item_list[i*9] == I_ZB_GouraudPolygon) + item_list[i*9] = I_GouraudPolygon; + + if(item_list[i*9] == I_ZB_PhongPolygon) + item_list[i*9] = I_PhongPolygon; + + if(item_list[i*9] == I_ZB_2dTexturedPolygon) + item_list[i*9] = I_2dTexturedPolygon; + + if(item_list[i*9] == I_ZB_Gouraud2dTexturedPolygon) + item_list[i*9] = I_Gouraud2dTexturedPolygon; + + if(item_list[i*9] == I_ZB_3dTexturedPolygon) + item_list[i*9] = I_3dTexturedPolygon; + #endif + + + + item_list[i*9 + 1] = (cshp.poly_list[i].normal_index * 3); + item_list[i*9 + 2] = (cshp.poly_list[i].flags&~ChunkInternalItemFlags); +// item_list[i*9 + 2] = (cshp.poly_list[i].flags) | iflag_nolight; + item_list[i*9 + 3] = (cshp.poly_list[i].colour); + +#if 1 + if ( (item_list[i*9] == 5 || item_list[i*9] == 6 + || item_list[i*9] == 7) && + !( item_list[i*9 + 3] & 0x8000 ) ) + { + int texno = item_list[i*9 + 3] & 0x7fff; + + if (texno <= max_index) + if ((tex_index_nos[texno] != -1)) + { + item_list[i*9 + 3] &= 0xffff0000; + item_list[i*9 + 3] += tex_index_nos[texno]; + + /* hack in iflag_no_light */ + item_list[i*9 + 2] |= iflag_gsort_ptest /*| iflag_nolight*/ | iflag_linear_s | iflag_tx2dor3d; + + } + else + { + item_list[i*9] = I_Polygon; + item_list[i*9 + 2] = (cshp.poly_list[i].flags&~ChunkInternalItemFlags) | iflag_nolight; + item_list[i*9 + 3] = 0xffffffff; + } + else + { + item_list[i*9] = I_Polygon; + item_list[i*9 + 2] = (cshp.poly_list[i].flags &~ChunkInternalItemFlags) | iflag_nolight; + item_list[i*9 + 3] = 0xffffffff; + } + } +#endif + +// item_list[i*9 + 3] = 0xffffffff; + + + for (j=0;jsh_textures[i] = (int *) AllocateMem (sizeof(int) * cshp.uv_list[i].num_verts * 2); + for (j=0; jsh_textures[i])[(j*2)] = (int)cshp.uv_list[i].vert[j].u; + (shphd->sh_textures[i])[(j*2)+1] = (int)cshp.uv_list[i].vert[j].v; + } + } + } + + if (cshp.num_texfiles) + { + for (i=0; ish_localtextures[i] = + (char *) AllocateMem (sizeof(char) * (strlen(cshp.texture_fns[i]) + strlen(TexturesRoot) + 1) ); + sprintf (shphd->sh_localtextures[i],"%s%s",TexturesRoot, cshp.texture_fns[i]); + char * dotpos; + dotpos = strrchr (shphd->sh_localtextures[i], '.'); + sprintf (dotpos,".pg0"); + #else + shphd->sh_localtextures[i] = + (char *) AllocateMem (sizeof(char) * (strlen(cshp.texture_fns[i]) + 1) ); + strcpy (shphd->sh_localtextures[i], cshp.texture_fns[i]); + #endif + } + shphd->sh_localtextures[i] = 0; + } + + + + + SHAPEINSTR * instruct = (SHAPEINSTR *)AllocateMem(sizeof(SHAPEINSTR)*6); + + shphd->sh_instruction = instruct; + + + instruct[0].sh_instr = I_ShapePoints; /*I_shapepoints*/ + instruct[0].sh_numitems = shphd->numpoints; + instruct[0].sh_instr_data = shphd->points; + + instruct[1].sh_instr = I_ShapeNormals; /*I_shapenormals*/ + instruct[1].sh_numitems = shphd->numitems; + instruct[1].sh_instr_data = shphd->sh_normals; + + instruct[2].sh_instr = I_ShapeProject; /*I_shapeproject*/ + instruct[2].sh_numitems = shphd->numpoints; + instruct[2].sh_instr_data = shphd->points; + + instruct[3].sh_instr = I_ShapeVNormals; /*I_shapevnormals*/ + instruct[3].sh_numitems = shphd->numpoints; + instruct[3].sh_instr_data = shphd->sh_vnormals; + + instruct[4].sh_instr = I_ShapeItems; + instruct[4].sh_numitems = shphd->numitems; + instruct[4].sh_instr_data = shphd->items; + + instruct[5].sh_instr = I_ShapeEnd; /*I_shapeEND*/ + instruct[5].sh_numitems = 0; + instruct[5].sh_instr_data = 0; + + + + return TRUE; +#if 0 + SHAPEHEADER * shphd = (SHAPEHEADER *) AllocateMem(sizeof(SHAPEHEADER)); + memset(shphd,0,sizeof(SHAPEHEADER)); + + ChunkShape cshp = shp->shape_data; + + Shape_Merge_Data_Chunk * smdc = 0; + + Chunk * pChunk = shp->lookup_single_child("SHPMRGDT"); + if (pChunk) + { + smdc = (Shape_Merge_Data_Chunk *) pChunk; + } + + merge_polygons_in_chunkshape (cshp,smdc); + + int i,j, * tptr; + + mainshapelist[list_pos] = shphd; + + // header data (note shapeheader is calloced) + + shphd->numpoints = cshp.num_verts; + shphd->numitems = cshp.num_polys; + + shphd->shaperadius = (int) (cshp.radius*local_scale); + + shphd->shapeflags = shphd->shapeflags | (ShapeFlag_AugZ | ShapeFlag_AugZ_Lite | + ShapeFlag_SizeSortItems); // SIZE HACK!!! + + shphd->shapemaxx = (int) (cshp.max.x*local_scale); + shphd->shapeminx = (int) (cshp.min.x*local_scale); + shphd->shapemaxy = (int) (cshp.max.y*local_scale); + shphd->shapeminy = (int) (cshp.min.y*local_scale); + shphd->shapemaxz = (int) (cshp.max.z*local_scale); + shphd->shapeminz = (int) (cshp.min.z*local_scale); + + // AllocateMem arrays + + shphd->points = (int **) AllocateMem (sizeof(int *)); + *(shphd->points) = (int *) AllocateMem (sizeof(int) * shphd->numpoints * 3); + + shphd->sh_vnormals = (int **) AllocateMem (sizeof(int *)); + *(shphd->sh_vnormals) = (int *) AllocateMem (sizeof(int) * shphd->numpoints * 3); + + shphd->sh_normals = (int **) AllocateMem (sizeof(int *)); + *(shphd->sh_normals) = (int *) AllocateMem (sizeof(int) * shphd->numitems * 3); + + // for textures + if (cshp.num_uvs) + shphd->sh_textures = (int **) AllocateMem (sizeof(int *) * cshp.num_uvs); + if (cshp.num_texfiles) + shphd->sh_localtextures = (char **) AllocateMem (sizeof(char *) * (cshp.num_texfiles+1)); + + int * item_list; + + shphd->items = (int **) AllocateMem (sizeof(int *) * shphd->numitems); + item_list = (int *) AllocateMem (sizeof(int) * shphd->numitems * 9); + + tptr = *(shphd->points); + + for (i=0; inumpoints; i++) { + tptr[i*3] = (int) (cshp.v_list[i].x*local_scale); + tptr[i*3 + 1] = (int) (cshp.v_list[i].y*local_scale); + tptr[i*3 + 2] = (int) (cshp.v_list[i].z*local_scale); + } + + tptr = *(shphd->sh_vnormals); + + for (i=0; inumpoints; i++) { + tptr[i*3] = (int) (cshp.v_normal_list[i].x*ONE_FIXED); + tptr[i*3 + 1] = (int) (cshp.v_normal_list[i].y*ONE_FIXED); + tptr[i*3 + 2] = (int) (cshp.v_normal_list[i].z*ONE_FIXED); + } + + tptr = *(shphd->sh_normals); + + for (i=0; inumitems; i++) { + tptr[i*3] = (int) (cshp.p_normal_list[i].x*ONE_FIXED); + tptr[i*3 + 1] = (int) (cshp.p_normal_list[i].y*ONE_FIXED); + tptr[i*3 + 2] = (int) (cshp.p_normal_list[i].z*ONE_FIXED); + } + + + for (i=0; inumitems; i++) + shphd->items[i] = &item_list[i*9]; + + + for (i=0; inumitems; i++) { + item_list[i*9] = (cshp.poly_list[i].engine_type); +// item_list[i*9] = I_Polyline; + + + if((item_list[i*9] < 2 ) || (item_list[i*9] > 9)) + { + item_list[i*9] = I_Polygon; + } + + if(item_list[i*9] == I_2dTexturedPolygon) + { + item_list[i*9] = I_Polygon; + } + + if(item_list[i*9] == I_3dTexturedPolygon) + { + item_list[i*9] = I_2dTexturedPolygon; + } + +// if(item_list[i*9] == I_Polygon) +// { +// item_list[i*9] = I_ZB_Polygon; +// /*HACK HACK ROXHACK*/ +// } + + item_list[i*9 + 1] = (cshp.poly_list[i].normal_index * 3); + item_list[i*9 + 2] = (cshp.poly_list[i].flags&~ChunkInternalItemFlags); +// item_list[i*9 + 2] = (cshp.poly_list[i].flags) | iflag_nolight; + item_list[i*9 + 3] = (cshp.poly_list[i].colour); + + if ( (item_list[i*9] == 5 || item_list[i*9] == 6) && + !( item_list[i*9 + 3] & 0x8000 ) ) + { + int texno = item_list[i*9 + 3] & 0x7fff; + + if (texno < max_index) + if (tex_index_nos[texno] != -1) + { + item_list[i*9 + 3] &= 0xffff0000; + item_list[i*9 + 3] += tex_index_nos[texno]; + } + else + { + item_list[i*9] = I_Polyline; + item_list[i*9 + 2] = (cshp.poly_list[i].flags &~ChunkInternalItemFlags) /*| iflag_nolight*/; + item_list[i*9 + 3] = 0xffffffff; + } + else + { + item_list[i*9] = I_Polyline; + item_list[i*9 + 2] = (cshp.poly_list[i].flags &~ChunkInternalItemFlags) /*| iflag_nolight*/; + item_list[i*9 + 3] = 0xffffffff; + } + } + + +// item_list[i*9 + 3] = 0xffffffff; + for (j=0;jsh_textures[i] = (int *) AllocateMem (sizeof(int) * cshp.uv_list[i].num_verts * 2); + for (j=0; jsh_textures[i])[(j*2)] = (int)cshp.uv_list[i].vert[j].u; + (shphd->sh_textures[i])[(j*2)+1] = (int)cshp.uv_list[i].vert[j].v; + } + } + } + /* + * FILENAME: e:\avpcode\3dc\win95\chnkload.cpp + * + * PARAMETERS: + * + * DESCRIPTION: + * + * RETURNS: + * + */ + + + if (cshp.num_texfiles) + { + for (i=0; ish_localtextures[i] = + (char *) AllocateMem (sizeof(char) * (strlen(cshp.texture_fns[i]) + strlen(TexturesRoot) + 1) ); + sprintf (shphd->sh_localtextures[i],"%s%s",TexturesRoot, cshp.texture_fns[i]); + char * dotpos; + dotpos = strrchr (shphd->sh_localtextures[i], '.'); + sprintf (dotpos,".pg0"); + #else + shphd->sh_localtextures[i] = + (char *) AllocateMem (sizeof(char) * (strlen(cshp.texture_fns[i]) + 1) ); + strcpy (shphd->sh_localtextures[i], cshp.texture_fns[i]); + #endif + } + shphd->sh_localtextures[i] = 0; + } + + + + + SHAPEINSTR * instruct = (SHAPEINSTR *)AllocateMem(sizeof(SHAPEINSTR)*6); + + shphd->sh_instruction = instruct; + + + instruct[0].sh_instr = I_ShapePoints; /*I_shapepoints*/ + instruct[0].sh_numitems = shphd->numpoints; + instruct[0].sh_instr_data = shphd->points; + + instruct[1].sh_instr = I_ShapeNormals; /*I_shapenormals*/ + instruct[1].sh_numitems = shphd->numitems; + instruct[1].sh_instr_data = shphd->sh_normals; + + instruct[2].sh_instr = I_ShapeProject; /*I_shapeproject*/ + instruct[2].sh_numitems = shphd->numpoints; + instruct[2].sh_instr_data = shphd->points; + + instruct[3].sh_instr = I_ShapeVNormals; /*I_shapevnormals*/ + instruct[3].sh_numitems = shphd->numpoints; + instruct[3].sh_instr_data = shphd->sh_vnormals; + + instruct[4].sh_instr = I_ShapeItems; + instruct[4].sh_numitems = shphd->numitems; + instruct[4].sh_instr_data = shphd->items; + + instruct[5].sh_instr = I_ShapeEnd; /*I_shapeEND*/ + instruct[5].sh_numitems = 0; + instruct[5].sh_instr_data = 0; + + + + return TRUE; +#endif +} +#endif + + + + + diff --git a/3dc/win95/d3_func.cpp b/3dc/win95/d3_func.cpp new file mode 100644 index 0000000..923e7f2 --- /dev/null +++ b/3dc/win95/d3_func.cpp @@ -0,0 +1,949 @@ + +// Interface functions (written in C++) for +// Direct3D immediate mode system + +// Must link to C code in main engine system + +extern "C" { + +// Mysterious definition required by objbase.h +// (included via one of the include files below) +// to start definition of obscure unique in the +// universe IDs required by Direct3D before it +// will deign to cough up with anything useful... + +#define INITGUID + +#include "3dc.h" + +#include "awTexLd.h" + +#include "dxlog.h" +#include "module.h" +#include "inline.h" + +#include "d3_func.h" +#include "d3dmacs.h" + +#include "string.h" + +#include "kshape.h" +#include "eax.h" +#include "vmanpset.h" + +extern "C++" { +#include "chnktexi.h" +#include "chnkload.hpp" // c++ header which ignores class definitions/member functions if __cplusplus is not defined ? +#include "r2base.h" +} + +#define UseLocalAssert No +#include "ourasert.h" + + + +// FIXME!!! Structures in d3d structure +// never have any size field set!!! +// This is how it's done in Microsoft's +// demo code --- but ARE THEY LYING??? + +// As far as I know the execute buffer should always be in +// system memory on any configuration, but this may +// eventually have to be changed to something that reacts +// to the caps bit in the driver, once drivers have reached +// the point where we can safely assume that such bits will be valid. +#define ForceExecuteBufferIntoSystemMemory Yes + +// To define TBLEND mode --- at present +// it must be on for ramp textures and +// off for evrything else... +#define ForceTBlendCopy No + +// Set to Yes for debugging, to No for normal +// operations (i.e. if we need a palettised +// file for an accelerator, load it from +// pre-palettised data, using code not yet +// written as of 27 / 8/ 96) +#define QuantiseOnLoad Yes + +// Set to Yes to make default texture filter bilinear averaging rather +// than nearest +BOOL BilinearTextureFilter = 1; + +extern LPDIRECTDRAW lpDD; + +#if 0// +// Externs + +extern int VideoMode; +extern int DXMemoryMode; +extern int ZBufferRequestMode; +extern int RasterisationRequestMode; +extern int SoftwareScanDrawRequestMode; +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; +extern VIEWDESCRIPTORBLOCK* Global_VDB_Ptr; +extern IMAGEHEADER ImageHeaderArray[]; +extern BOOL MMXAvailable; + + +//Globals + +int D3DDriverMode; + + + +static unsigned char DefaultD3DTextureFilterMin; +static unsigned char DefaultD3DTextureFilterMax; + + +#if SuppressWarnings +static int* itemptr_tmp; + +#ifdef __WATCOMC__ +#pragma warning 389 5 +#pragma message("Note: Disabled Warning W389 'Integral value may be truncated...'") +#endif + +#endif + + +#endif // +HRESULT LastError; +int ExBufSize; + +LPDIRECT3DEXECUTEBUFFER lpD3DExecCmdBuf; +LPDIRECTDRAWSURFACE lpZBuffer; +extern LPDIRECTDRAWSURFACE lpDDSBack; +extern LPDIRECTDRAWSURFACE lpDDSPrimary; +extern LPDIRECTDRAWPALETTE lpDDPal[]; // DirectDraw palette + +D3DINFO d3d; +BOOL D3DHardwareAvailable; + +int StartDriver; +int StartFormat; + + +static int devZBufDepth; + + +extern int WindowMode; +extern int ZBufferMode; +extern int ScanDrawMode; +extern int VideoModeColourDepth; + +extern enum TexFmt { D3TF_4BIT, D3TF_8BIT, D3TF_16BIT, D3TF_32BIT, D3TF_MAX } d3d_desired_tex_fmt; + +// Callback function to enumerate devices present +// on system (required so that device interface GUID +// can be retrieved if for no other reason). Device +// information is copied into instance of structure +// defined in d3_func.h + +HRESULT WINAPI DeviceEnumerator(LPGUID lpGuid, + LPSTR lpDeviceDescription, LPSTR lpDeviceName, + LPD3DDEVICEDESC lpHWDesc, LPD3DDEVICEDESC lpHELDesc, LPVOID lpContext) +{ + int *lpStartDriver = (int *)lpContext; + + /* + Record the D3D driver's description + of itself. + */ + + memcpy(&d3d.Driver[d3d.NumDrivers].Guid, lpGuid, sizeof(GUID)); + strcpy(d3d.Driver[d3d.NumDrivers].About, lpDeviceDescription); + strcpy(d3d.Driver[d3d.NumDrivers].Name, lpDeviceName); + + /* + Is this a hardware device or software emulation? Checking the color + model for a valid model works. + */ + + if (lpHWDesc->dcmColorModel) + { + D3DHardwareAvailable = Yes; + d3d.Driver[d3d.NumDrivers].Hardware = Yes; + memcpy(&d3d.Driver[d3d.NumDrivers].Desc, lpHWDesc, + sizeof(D3DDEVICEDESC)); + } + else + { + d3d.Driver[d3d.NumDrivers].Hardware = No; + memcpy(&d3d.Driver[d3d.NumDrivers].Desc, lpHELDesc, + sizeof(D3DDEVICEDESC)); + } + + /* + Does this driver do texture mapping? + */ + + d3d.Driver[d3d.NumDrivers].Textures = + (d3d.Driver[d3d.NumDrivers].Desc.dpcTriCaps.dwTextureCaps & + D3DPTEXTURECAPS_PERSPECTIVE) ? TRUE : FALSE; + + /* + Can this driver use a z-buffer? + */ + + d3d.Driver[d3d.NumDrivers].ZBuffer = + d3d.Driver[d3d.NumDrivers].Desc.dwDeviceZBufferBitDepth & (DDBD_16 | DDBD_24 | DDBD_32) + ? TRUE : FALSE; + +// The driver description is recorded here, +// and some basic things like ZBuffering +// availability are noted separately. Other +// things such as hardware acceleration for +// translucency could potentially be noted here +// for use in the Write functions to decide +// whether e.g. iflag_transparent should be +// treated as valid. Obviously this will +// require modification of the D3DDRIVERINFO +// structure in d3_func.h + + *lpStartDriver = d3d.NumDrivers; + + d3d.NumDrivers++; + if (d3d.NumDrivers == MAX_D3D_DRIVERS) + return (D3DENUMRET_CANCEL); + else + return (D3DENUMRET_OK); +} + +// This function is called from +// InitialiseDirect3DImmediateMode, to +// insert and execute opcodes which cannot +// be run during a "real" scene because of +// some obscure feature of Direct3D. + + + +// Initialise Direct3D immediate mode system + +BOOL InitialiseDirect3DImmediateMode(void) +{ + BOOL RetVal; +// to tell device enum function that it has not been called before + StartDriver = -1; +// to tell texture enum function that it has not been called before + StartFormat = -1; + +// default is no hardware +// note that we are still resetting +// this here just in case the test from +// InitialiseSystem failed and things aren't +// what we thought... + D3DHardwareAvailable = No; + +// Zero d3d structure + memset(&d3d, 0, sizeof(D3DINFO)); + +// Set up Direct3D interface object + + LastError = lpDD->QueryInterface(IID_IDirect3D, (LPVOID*) &d3d.lpD3D); + LOGDXERR(LastError); + + if (LastError != DD_OK) + return FALSE; +// Use callback function to enumerate available devices on system +// and acquire device GUIDs etc +// note that we are still resetting +// this here just in case the test from +// InitialiseSystem failed and things aren't +// what we thought... + LastError = d3d.lpD3D->EnumDevices(DeviceEnumerator, (LPVOID)&StartDriver); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + +// Must be run as soon as possible in the +// initialisation sequence, but after the +// device enumeration (and obviously after +// DirectDraw object and surface initialisation). + SelectD3DDriverAndDrawMode(); + d3d.ThisDriver = d3d.Driver[d3d.CurrentDriver].Desc; + +// Test!!! Release D3D object if we don't need it and do an +// early exit. Will this fix the banding problem on some +// accelerators in palettised modes?? +// Evidently not. Still, probably a good thing to do... +// But!!! The whole banding problem appears to be a +// modeX emulation problem on some 3D accelerator cards... + #if 1 + if (ScanDrawMode == ScanDrawDirectDraw) + { + ReleaseDirect3DNotDDOrImages(); + return TRUE; + } + #endif + + +// Note that this must be done BEFORE the D3D device object is created + #if SupportZBuffering + if (ZBufferMode != ZBufferOff) + { + RetVal = CreateD3DZBuffer(); + if (RetVal == FALSE) return FALSE; + } + #endif + +// Set up Direct3D device object (must be linked to back buffer) + LastError = lpDDSBack->QueryInterface(d3d.Driver[d3d.CurrentDriver].Guid, + (LPVOID*)&d3d.lpD3DDevice); + LOGDXERR(LastError); + + if (LastError != DD_OK) + return FALSE; + + AW_TL_ERC awErr = AwSetD3DDevice(d3d.lpD3DDevice); + GLOBALASSERT(AW_TLE_OK==awErr); +// Enumerate texture formats and pick one +// (palettised if possible). + d3d.NumTextureFormats = 0; + + d3d_desired_tex_fmt=D3TF_8BIT; + + LastError = d3d.lpD3DDevice->EnumTextureFormats + (TextureFormatsEnumerator, + (LPVOID)&StartFormat); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + #if debug + { + ReleaseDirect3D(); + exit(LastError); + } + #else + return FALSE; + #endif + + d3d.CurrentTextureFormat = StartFormat; + + // NEW NEW NEW + // Note: we are NOT restricted to only one texture format + awErr = AwSetTextureFormat(&d3d.TextureFormat[StartFormat].ddsd); + GLOBALASSERT(AW_TLE_OK==awErr); + +// Create viewport + LastError = d3d.lpD3D->CreateViewport(&d3d.lpD3DViewport, NULL); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + +// Add viewport to desired device + LastError = d3d.lpD3DDevice->AddViewport(d3d.lpD3DViewport); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + +// Set up viewport data + +// Note that the viewport is always set to the +// SDB limits because internal clipping is handled +// within the main engine code using the VDB +// system. + + { + // Configure viewport here + D3DVIEWPORT viewPort; + memset(&viewPort, 0, sizeof(D3DVIEWPORT)); + viewPort.dwSize = sizeof(D3DVIEWPORT); + viewPort.dwX = 0; // origins x and y + viewPort.dwY = 0; + viewPort.dwWidth = ScreenDescriptorBlock.SDB_Width; + viewPort.dwHeight = ScreenDescriptorBlock.SDB_Height; + viewPort.dvScaleX = D3DVAL((float)viewPort.dwWidth / 2.0); // ????was 2.0 + viewPort.dvScaleY = D3DVAL((float)viewPort.dwHeight / 2.0); // ????was 2.0 + viewPort.dvMaxX = D3DVAL(D3DDivide(D3DVAL(viewPort.dwWidth), + D3DVAL(2 * viewPort.dvScaleX))); // ???? + viewPort.dvMaxY = D3DVAL(D3DDivide(D3DVAL(viewPort.dwHeight), + D3DVAL(2 * viewPort.dvScaleY))); // ???? + + // And actually set viewport + LastError = d3d.lpD3DViewport->SetViewport(&viewPort); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + } + +// At present we will not set a background material for the +// viewport, staying instead with the blit code in backdrop.c + +// Also, we are not currently adding default lights to the +// viewport, since the engine lighting system is completely +// disconnected from the immediate mode lighting module. + +// Create execute buffer + + { + // Locals for execute buffer + D3DEXECUTEBUFFERDESC d3dexDesc; + + // Set up structure to initialise buffer + // Note some instructions (e.g. lines) may be smaller than a + // triangle, but none can be larger + ExBufSize = ((sizeof(D3DINSTRUCTION) + sizeof(D3DTRIANGLE)) + * MaxD3DInstructions) + + (sizeof(D3DTLVERTEX) * MaxD3DVertices); + memset(&d3dexDesc, 0, sizeof(D3DEXECUTEBUFFERDESC)); + d3dexDesc.dwSize = sizeof(D3DEXECUTEBUFFERDESC); + d3dexDesc.dwFlags = D3DDEB_BUFSIZE | D3DDEB_CAPS; + d3dexDesc.dwBufferSize = ExBufSize; + #if ForceExecuteBufferIntoSystemMemory + d3dexDesc.dwCaps = D3DDEBCAPS_SYSTEMMEMORY; + #else + d3dexDesc.dwCaps = D3DDEBCAPS_MEM; // untested!!! + #endif + + // Create buffer + LastError = d3d.lpD3DDevice->CreateExecuteBuffer + (&d3dexDesc, &lpD3DExecCmdBuf, NULL); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + } + + // Temporary patch here because the defaults function + // buggers palette setting in ScanDrawDirectDraw + // for some really obscure reason... + + if (ScanDrawMode != ScanDrawDirectDraw) + SetExecuteBufferDefaults(); + + + return TRUE; +} + +#if 1 + +// Note that error conditions have been removed +// on the grounds that an early exit will prevent +// EndScene being run if this function is used, +// which screws up all subsequent buffers + +BOOL RenderD3DScene(void) + +{ + // Begin scene + // My theory is that the functionality of this + // thing must invoke a DirectDraw surface lock + // on the back buffer without telling you. However, + // we shall see... + + LastError = d3d.lpD3DDevice->BeginScene(); + LOGDXERR(LastError); + + // if (LastError != D3D_OK) + // return FALSE; + + // Execute buffer + LastError = d3d.lpD3DDevice->Execute(lpD3DExecCmdBuf, + d3d.lpD3DViewport, D3DEXECUTE_UNCLIPPED); + LOGDXERR(LastError); + + // if (LastError != D3D_OK) + // return FALSE; + + // End scene + LastError = d3d.lpD3DDevice->EndScene(); + LOGDXERR(LastError); + + // if (LastError != D3D_OK) + // return FALSE; + + + + return TRUE; +} + +#else + +int Time1, Time2, Time3, Time4; + +BOOL RenderD3DScene(void) + +{ + + // Begin scene + // My theory is that the functionality of this + // thing must invoke a DirectDraw surface lock + // on the back buffer without telling you. However, + // we shall see... + + Time1 = GetWindowsTickCount(); + + LastError = d3d.lpD3DDevice->BeginScene(); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + + Time2 = GetWindowsTickCount(); + + // Execute buffer + #if 1 + LastError = d3d.lpD3DDevice->Execute(lpD3DExecCmdBuf, + d3d.lpD3DViewport, D3DEXECUTE_UNCLIPPED); + LOGDXERR(LastError); + #else + LastError = d3d.lpD3DDevice->Execute(lpD3DExecCmdBuf, + d3d.lpD3DViewport, D3DEXECUTE_CLIPPED); + LOGDXERR(LastError); + #endif + + if (LastError != D3D_OK) + return FALSE; + + Time3 = GetWindowsTickCount(); + + // End scene + LastError = d3d.lpD3DDevice->EndScene(); + LOGDXERR(LastError); + + if (LastError != D3D_OK) + return FALSE; + + Time4 = GetWindowsTickCount(); + + + + return TRUE; + +#endif + + +// With a bit of luck this should automatically +// release all the Direct3D and DirectDraw +// objects using their own functionality. +// A separate call to finiObjects +// is not required. +// NOTE!!! This depends on Microsoft macros +// in d3dmacs.h, which is in the win95 directory +// and must be upgraded from sdk upgrades!!! + +void ReleaseDirect3D(void) + +{ + DeallocateAllImages(); + RELEASE(d3d.lpD3DViewport); + RELEASE(d3d.lpD3DDevice); + #if SupportZBuffering + RELEASE(lpZBuffer); + #endif + RELEASE(lpDDPal[0]); + RELEASE(lpDDSBack); + RELEASE(lpDDSPrimary); + RELEASE(d3d.lpD3D); + RELEASE(lpDD); + + /* release Direct Input stuff */ + ReleaseDirectKeyboard(); + ReleaseDirectMouse(); + ReleaseDirectInput(); + + // Reset windows palette entry allocation + if ((VideoModeColourDepth == 8) && (WindowMode == WindowModeSubWindow)) + { + HDC hdc = GetDC(NULL); + SetSystemPaletteUse(hdc, SYSPAL_STATIC); + ReleaseDC(NULL, hdc); + } +} + +// Release all Direct3D objects +// but not DirectDraw + +void ReleaseDirect3DNotDDOrImages(void) + +{ + RELEASE(d3d.lpD3DViewport); + RELEASE(d3d.lpD3DDevice); + #if SupportZBuffering + RELEASE(lpZBuffer); + #endif + RELEASE(d3d.lpD3D); +} + +void ReleaseDirect3DNotDD(void) + +{ + DeallocateAllImages(); + RELEASE(d3d.lpD3DViewport); + RELEASE(d3d.lpD3DDevice); + #if SupportZBuffering + RELEASE(lpZBuffer); + #endif + RELEASE(d3d.lpD3D); +} + + +// NOTE!!! These functions depend on Microsoft macros +// in d3dmacs.h, which is in the win95 directory +// and must be upgraded from sdk upgrades!!! + + +// ALSO NOTE!!! All this stuff involves heavy +// use of floating point assembler in software +// emulation, probably hand parallelised between +// the FPU and the processor or something bizarre, +// implying that this stuff SHOULD NOT be used +// one anything below a Pentium. + +// AND AGAIN!!! Due to the nature of the item +// format, the rasterisation module MUST RECEIVE +// repeated vertices in the data area. Tough shit, +// Microsoft, that's what I say... + +void WritePolygonToExecuteBuffer(int* itemptr) + +{ +} + +void WriteGouraudPolygonToExecuteBuffer(int* itemptr) + +{ +} + +void Write2dTexturedPolygonToExecuteBuffer(int* itemptr) + +{ +} + +void WriteGouraud2dTexturedPolygonToExecuteBuffer(int* itemptr) + +{ +} + + +void Write3dTexturedPolygonToExecuteBuffer(int* itemptr) + +{ + } + +void WriteGouraud3dTexturedPolygonToExecuteBuffer(int* itemptr) + +{ +} + +#if SupportZBuffering + +// To make effective use of 16 bit z buffers (common +// on hardware accelerators) we must have a z coordinate +// which has been transformed into screen space in such a +// way that linearity and planearity are preserved, i.e. as +// if we had done a homogeneous transformation. For the case +// in which the far clipping plane is much further away than the +// near one (effectively true for 3dc, especially as there is +// no far clipping plane as such), the appropriate transformation +// can be reduced to zScreen = (ZWorld - ZNear) / ZWorld. This +// calculation is therefore (unfortunately) done for each vertex +// for z buffered items, taking ZNear to be the current +// VDB_ClipZ * GlobalScale. + + +void WriteZBPolygonToExecuteBuffer(int* itemptr) + +{ +} + +void WriteZBGouraudPolygonToExecuteBuffer(int* itemptr) + +{ +} + +void WriteZB2dTexturedPolygonToExecuteBuffer(int* itemptr) + +{ +} + + +void WriteZBGouraud2dTexturedPolygonToExecuteBuffer(int* itemptr) + +{ +} + +void WriteZB3dTexturedPolygonToExecuteBuffer(int* itemptr) + +{ +} + +void WriteZBGouraud3dTexturedPolygonToExecuteBuffer(int* itemptr) + +{ +} + +#endif + + + +void WriteBackdrop2dTexturedPolygonToExecuteBuffer(int* itemptr) + +{ +} + +// Same as ordinary 2d textured draw at present, but may e.g. +// require different texture wrapping behaviour or +// w values. + +void WriteBackdrop3dTexturedPolygonToExecuteBuffer(int* itemptr) + +{ +} + + +// Note that this is all dead crap and deeply unoptimised +// But then... a) it's really only a test and +// b) it's for the tools group anyway... + + +void DirectWriteD3DLine(VECTOR2D* LineStart, VECTOR2D* LineEnd, int LineColour) + +{ + +} + + +// reload D3D image -- assumes a base pointer points to the image loaded +// from disc, in a suitable format + +void ReloadImageIntoD3DImmediateSurface(IMAGEHEADER* iheader) +{ + + void *reloadedTexturePtr = ReloadImageIntoD3DTexture(iheader); + LOCALASSERT(reloadedTexturePtr != NULL); + + int gotTextureHandle = GetTextureHandle(iheader); + LOCALASSERT(gotTextureHandle == TRUE); +} + +void* ReloadImageIntoD3DTexture(IMAGEHEADER* iheader) +{ + // NOTE FIXME BUG HACK + // what if the image was a DD surface ?? + + if (iheader->hBackup) + { + iheader->D3DTexture = AwCreateTexture("rf",AW_TLF_PREVSRC|AW_TLF_COMPRESS); + return iheader->D3DTexture; + } + else return NULL; +} + +int GetTextureHandle(IMAGEHEADER *imageHeaderPtr) +{ + LPDIRECT3DTEXTURE Texture = (LPDIRECT3DTEXTURE) imageHeaderPtr->D3DTexture; + + LastError = Texture->GetHandle(d3d.lpD3DDevice, (D3DTEXTUREHANDLE*)&(imageHeaderPtr->D3DHandle)); + + if (LastError != D3D_OK) return FALSE; + + return TRUE; +} + + + +void ReleaseD3DTexture(void* D3DTexture) + +{ + LPDIRECT3DTEXTURE lpTexture; + + lpTexture = (LPDIRECT3DTEXTURE) D3DTexture; + RELEASE(lpTexture); +} + + +#if SupportZBuffering + +BOOL CreateD3DZBuffer(void) + +{ + DDSURFACEDESC ddsd; + + // For safety, kill any existing z buffer + #if SupportZBuffering + RELEASE(lpZBuffer); + #endif + + + // If we do not have z buffering support + // on this driver, give up now + if (!(d3d.Driver[d3d.CurrentDriver].ZBuffer)) + return FALSE; + + memset(&ddsd,0,sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = (DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_ZBUFFERBITDEPTH); + ddsd.dwHeight = ScreenDescriptorBlock.SDB_Height; + ddsd.dwWidth = ScreenDescriptorBlock.SDB_Width; + ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER; + + // If we are on a hardware driver, then the z buffer + // MUST be in video memory. Otherwise, it MUST be + // in system memory. I think. + + if (d3d.Driver[d3d.CurrentDriver].Hardware) + ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + else + ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + + // Get the Z buffer bit depth from this driver's + // D3D device description and add it to the description + // of the surface we want to create + + devZBufDepth = d3d.Driver[d3d.CurrentDriver].Desc.dwDeviceZBufferBitDepth; + + if (devZBufDepth & DDBD_32) + ddsd.dwZBufferBitDepth = 32; + else if (devZBufDepth & DDBD_24) + ddsd.dwZBufferBitDepth = 24; + else if (devZBufDepth & DDBD_16) + ddsd.dwZBufferBitDepth = 16; + else if (devZBufDepth & DDBD_8) + ddsd.dwZBufferBitDepth = 8; + else + { + #if debug + ReleaseDirect3D(); + exit(0x511621); + #else + return FALSE; + #endif + } + + // Eight-bit z buffer? Fuck off. + if (ddsd.dwZBufferBitDepth == 8) + return FALSE; + + // Now we must actually make the z buffer + + LastError = lpDD->CreateSurface(&ddsd,&lpZBuffer, NULL); + + if (LastError != DD_OK) + { + RELEASE(lpZBuffer); + return FALSE; + } + + LastError = lpDDSBack->AddAttachedSurface(lpZBuffer); + + if (LastError != DD_OK) + { + RELEASE(lpZBuffer); + return FALSE; + } + + return TRUE; +} + +#define ZFlushVal 0xffffffff + +// At present we are using my z flush function, with the +// (undocumented) addition of a fill colour for the +// actual depth fill, since it seems to work and at least +// I know what it does. If it starts failing we'll probably +// have to go back to invoking the viewport clear through +// Direct3D. + +void FlushD3DZBuffer(void) + +{ + + DDBLTFX ddbltfx; + + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillDepth = devZBufDepth; + ddbltfx.dwFillColor = ZFlushVal; + + /* lets blt a color to the surface*/ + LastError = lpZBuffer->Blt(NULL, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &ddbltfx); + +} +void SecondFlushD3DZBuffer(void) +{ + #if 1 + { + WriteEndCodeToExecuteBuffer(); + UnlockExecuteBufferAndPrepareForUse(); + ExecuteBuffer(); + LockExecuteBuffer(); + } + + DDBLTFX ddbltfx; + + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillDepth = devZBufDepth; + ddbltfx.dwFillColor = ZFlushVal; + + /* lets blt a color to the surface*/ + LastError = lpZBuffer->Blt(NULL, NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &ddbltfx); + #else + extern void ClearZBufferWithPolygon(void); + ClearZBufferWithPolygon(); + #endif +} + + +#endif +void FlushZB(void) +{ + HRESULT hRes; + D3DRECT d3dRect; + + + d3dRect.lX1 = 0; + d3dRect.lX2 = 640; + d3dRect.lY1 = 0; + d3dRect.lY2 = 480; + hRes = d3d.lpD3DViewport->Clear(1, &d3dRect, D3DCLEAR_ZBUFFER); + + +} + + + +// For extern "C" + +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/3dc/win95/d3_func.h b/3dc/win95/d3_func.h new file mode 100644 index 0000000..eedbd5e --- /dev/null +++ b/3dc/win95/d3_func.h @@ -0,0 +1,106 @@ +#ifndef _included_d3_func_h_ +#define _included_d3_func_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + Direct3D globals +*/ + +/* + Maximum number of Direct3D drivers ever + expected to be resident on the system. +*/ +#define MAX_D3D_DRIVERS 5 +/* + Maximum number of texture formats ever + expected to be reported by a Direct3D + driver. +*/ +#define MAX_TEXTURE_FORMATS 10 + +/* + Description of a D3D driver. +*/ + +typedef struct D3DDriverInfo { + char Name[30]; /* short name of driver */ + char About[50]; /* string about driver */ + D3DDEVICEDESC Desc; /* full driver description */ + GUID Guid; /* wacky universally unique id thingy */ + BOOL Hardware; /* accelerated driver? */ + BOOL Textures; /* Texture mapping available? */ + BOOL ZBuffer; /* Z Buffering available? */ +} D3DDRIVERINFO; + +/* + Description of a D3D driver texture + format. +*/ + +typedef struct D3DTextureFormat { + DDSURFACEDESC ddsd; /* DDSURFACEDESC for the surface description */ + BOOL Palette; /* is Palettized? */ + int RedBPP; /* #red bits per pixel */ + int BlueBPP; /* #blue bits per pixel */ + int GreenBPP; /* #green bits per pixel */ + int IndexBPP; /* number of bits in palette index */ +} D3DTEXTUREFORMAT; + + +typedef struct D3DInfo { + LPDIRECT3D lpD3D; + LPDIRECT3DDEVICE lpD3DDevice; + LPDIRECT3DVIEWPORT lpD3DViewport; + int NumDrivers; + int CurrentDriver; + D3DDEVICEDESC ThisDriver; + D3DDRIVERINFO Driver[MAX_D3D_DRIVERS]; + int CurrentTextureFormat; + int NumTextureFormats; + D3DTEXTUREFORMAT TextureFormat[MAX_TEXTURE_FORMATS]; +} D3DINFO; + + + +/* KJL 14:24:45 12/4/97 - render state information */ +enum TRANSLUCENCY_TYPE +{ + TRANSLUCENCY_OFF, + TRANSLUCENCY_NORMAL, + TRANSLUCENCY_INVCOLOUR, + TRANSLUCENCY_COLOUR, + TRANSLUCENCY_GLOWING, + TRANSLUCENCY_DARKENINGCOLOUR, + TRANSLUCENCY_JUSTSETZ, + TRANSLUCENCY_NOT_SET +}; + +enum FILTERING_MODE_ID +{ + FILTERING_BILINEAR_OFF, + FILTERING_BILINEAR_ON, + FILTERING_NOT_SET +}; + +typedef struct +{ + enum TRANSLUCENCY_TYPE TranslucencyMode; + enum FILTERING_MODE_ID FilteringMode; + int FogDistance; + unsigned int FogIsOn :1; + unsigned int WireFrameModeIsOn :1; + +} RENDERSTATES; + + + + + +#ifdef __cplusplus +} +#endif + +#endif /* ! _included_d3_func_h_ */ diff --git a/3dc/win95/d3dmacs.h b/3dc/win95/d3dmacs.h new file mode 100644 index 0000000..ce26f43 --- /dev/null +++ b/3dc/win95/d3dmacs.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 1995, 1996 Microsoft Corporation. All Rights Reserved. + * + * File: d3dmacs.h + * + * Useful macros for generating execute buffers. Consult the D3D sample + * code for examples of their usage. + * + * Use OP_NOP to QWORD align triangle and line instructions. + */ + +#ifndef __D3DMACS_H__ +#define __D3DMACS_H__ + +#undef RELEASE + +#ifndef __cplusplus +#define MAKE_MATRIX(lpDev, handle, data) \ + if (lpDev->lpVtbl->CreateMatrix(lpDev, &handle) != D3D_OK) \ + return FALSE; \ + if (lpDev->lpVtbl->SetMatrix(lpDev, handle, &data) != D3D_OK) \ + return FALSE +#define RELEASE(x) if (x != NULL) {x->lpVtbl->Release(x); x = NULL;} +#endif + +#ifdef __cplusplus +#define MAKE_MATRIX(lpDev, handle, data) \ + if (lpDev->CreateMatrix(&handle) != D3D_OK) \ + return FALSE; \ + if (lpDev->SetMatrix(handle, &data) != D3D_OK) \ + return FALSE +#define RELEASE(x) if (x != NULL) {x->Release(); x = NULL;} +#endif + +#define PUTD3DINSTRUCTION(op, sz, cnt, ptr) \ + ((LPD3DINSTRUCTION) ptr)->bOpcode = op; \ + ((LPD3DINSTRUCTION) ptr)->bSize = sz; \ + ((LPD3DINSTRUCTION) ptr)->wCount = cnt; \ + ptr = (void *)(((LPD3DINSTRUCTION) ptr) + 1) + +#define VERTEX_DATA(loc, cnt, ptr) \ + if ((ptr) != (loc)) memcpy((ptr), (loc), sizeof(D3DVERTEX) * (cnt)); \ + ptr = (void *)(((LPD3DVERTEX) (ptr)) + (cnt)) + +// OP_MATRIX_MULTIPLY size: 4 (sizeof D3DINSTRUCTION) +#define OP_MATRIX_MULTIPLY(cnt, ptr) \ + PUTD3DINSTRUCTION(D3DOP_MATRIXMULTIPLY, sizeof(D3DMATRIXMULTIPLY), cnt, ptr) + +// MATRIX_MULTIPLY_DATA size: 12 (sizeof MATRIXMULTIPLY) +#define MATRIX_MULTIPLY_DATA(src1, src2, dest, ptr) \ + ((LPD3DMATRIXMULTIPLY) ptr)->hSrcMatrix1 = src1; \ + ((LPD3DMATRIXMULTIPLY) ptr)->hSrcMatrix2 = src2; \ + ((LPD3DMATRIXMULTIPLY) ptr)->hDestMatrix = dest; \ + ptr = (void *)(((LPD3DMATRIXMULTIPLY) ptr) + 1) + +// OP_STATE_LIGHT size: 4 (sizeof D3DINSTRUCTION) +#define OP_STATE_LIGHT(cnt, ptr) \ + PUTD3DINSTRUCTION(D3DOP_STATELIGHT, sizeof(D3DSTATE), cnt, ptr) + +// OP_STATE_TRANSFORM size: 4 (sizeof D3DINSTRUCTION) +#define OP_STATE_TRANSFORM(cnt, ptr) \ + PUTD3DINSTRUCTION(D3DOP_STATETRANSFORM, sizeof(D3DSTATE), cnt, ptr) + +// OP_STATE_RENDER size: 4 (sizeof D3DINSTRUCTION) +#define OP_STATE_RENDER(cnt, ptr) \ + PUTD3DINSTRUCTION(D3DOP_STATERENDER, sizeof(D3DSTATE), cnt, ptr) + +// STATE_DATA size: 8 (sizeof D3DSTATE) +#define STATE_DATA(type, arg, ptr) \ + ((LPD3DSTATE) ptr)->drstRenderStateType = (D3DRENDERSTATETYPE)type; \ + ((LPD3DSTATE) ptr)->dwArg[0] = arg; \ + ptr = (void *)(((LPD3DSTATE) ptr) + 1) + +// OP_PROCESS_VERTICES size: 4 (sizeof D3DINSTRUCTION) +#define OP_PROCESS_VERTICES(cnt, ptr) \ + PUTD3DINSTRUCTION(D3DOP_PROCESSVERTICES, sizeof(D3DPROCESSVERTICES), cnt, ptr) + +// PROCESSVERTICES_DATA size: 16 (sizeof D3DPROCESSVERTICES) +#define PROCESSVERTICES_DATA(flgs, strt, cnt, ptr) \ + ((LPD3DPROCESSVERTICES) ptr)->dwFlags = flgs; \ + ((LPD3DPROCESSVERTICES) ptr)->wStart = strt; \ + ((LPD3DPROCESSVERTICES) ptr)->wDest = strt; \ + ((LPD3DPROCESSVERTICES) ptr)->dwCount = cnt; \ + ((LPD3DPROCESSVERTICES) ptr)->dwReserved = 0; \ + ptr = (void *)(((LPD3DPROCESSVERTICES) ptr) + 1) + +// OP_TRIANGLE_LIST size: 4 (sizeof D3DINSTRUCTION) +#define OP_TRIANGLE_LIST(cnt, ptr) \ + PUTD3DINSTRUCTION(D3DOP_TRIANGLE, sizeof(D3DTRIANGLE), cnt, ptr) + +#define TRIANGLE_LIST_DATA(loc, count, ptr) \ + if ((ptr) != (loc)) memcpy((ptr), (loc), sizeof(D3DTRIANGLE) * (count)); \ + ptr = (void *)(((LPD3DTRIANGLE) (ptr)) + (count)) + +// OP_LINE_LIST size: 4 (sizeof D3DINSTRUCTION) +#define OP_LINE_LIST(cnt, ptr) \ + PUTD3DINSTRUCTION(D3DOP_LINE, sizeof(D3DLINE), cnt, ptr) + +#define LINE_LIST_DATA(loc, count, ptr) \ + if ((ptr) != (loc)) memcpy((ptr), (loc), sizeof(D3DLINE) * (count)); \ + ptr = (void *)(((LPD3DLINE) (ptr)) + (count)) + +// OP_POINT_LIST size: 8 (sizeof D3DINSTRUCTION + sizeof D3DPOINT) +#define OP_POINT_LIST(first, cnt, ptr) \ + PUTD3DINSTRUCTION(D3DOP_POINT, sizeof(D3DPOINT), 1, ptr); \ + ((LPD3DPOINT)(ptr))->wCount = cnt; \ + ((LPD3DPOINT)(ptr))->wFirst = first; \ + ptr = (void*)(((LPD3DPOINT)(ptr)) + 1) + +// OP_SPAN_LIST size: 8 (sizeof D3DINSTRUCTION + sizeof D3DSPAN) +#define OP_SPAN_LIST(first, cnt, ptr) \ + PUTD3DINSTRUCTION(D3DOP_SPAN, sizeof(D3DSPAN), 1, ptr); \ + ((LPD3DSPAN)(ptr))->wCount = cnt; \ + ((LPD3DSPAN)(ptr))->wFirst = first; \ + ptr = (void*)(((LPD3DSPAN)(ptr)) + 1) + +// OP_BRANCH_FORWARD size: 18 (sizeof D3DINSTRUCTION + sizeof D3DBRANCH) +#define OP_BRANCH_FORWARD(tmask, tvalue, tnegate, toffset, ptr) \ + PUTD3DINSTRUCTION(D3DOP_BRANCHFORWARD, sizeof(D3DBRANCH), 1, ptr); \ + ((LPD3DBRANCH) ptr)->dwMask = tmask; \ + ((LPD3DBRANCH) ptr)->dwValue = tvalue; \ + ((LPD3DBRANCH) ptr)->bNegate = tnegate; \ + ((LPD3DBRANCH) ptr)->dwOffset = toffset; \ + ptr = (void *)(((LPD3DBRANCH) (ptr)) + 1) + +// OP_SET_STATUS size: 20 (sizeof D3DINSTRUCTION + sizeof D3DSTATUS) +#define OP_SET_STATUS(flags, status, _x1, _y1, _x2, _y2, ptr) \ + PUTD3DINSTRUCTION(D3DOP_SETSTATUS, sizeof(D3DSTATUS), 1, ptr); \ + ((LPD3DSTATUS)(ptr))->dwFlags = flags; \ + ((LPD3DSTATUS)(ptr))->dwStatus = status; \ + ((LPD3DSTATUS)(ptr))->drExtent.x1 = _x1; \ + ((LPD3DSTATUS)(ptr))->drExtent.y1 = _y1; \ + ((LPD3DSTATUS)(ptr))->drExtent.x2 = _x2; \ + ((LPD3DSTATUS)(ptr))->drExtent.y2 = _y2; \ + ptr = (void *)(((LPD3DSTATUS) (ptr)) + 1) + +// OP_NOP size: 4 +#define OP_NOP(ptr) \ + PUTD3DINSTRUCTION(D3DOP_TRIANGLE, sizeof(D3DTRIANGLE), 0, ptr) + +#define OP_EXIT(ptr) \ + PUTD3DINSTRUCTION(D3DOP_EXIT, 0, 0, ptr) + +#define QWORD_ALIGNED(ptr) \ + !(0x00000007L & (ULONG)(ptr)) + +#endif // __D3DMACS_H__ diff --git a/3dc/win95/d3load.c b/3dc/win95/d3load.c new file mode 100644 index 0000000..011106b --- /dev/null +++ b/3dc/win95/d3load.c @@ -0,0 +1,316 @@ +/***************************************************************************/ +/* Loading a PPM file into a surface */ +/***************************************************************************/ +/* + * LoadSurface + * Loads a ppm file into a texture map DD surface of the given format. The + * memory flag specifies DDSCAPS_SYSTEMMEMORY or DDSCAPS_VIDEOMEMORY. + */ +LPDIRECTDRAWSURFACE +D3DAppILoadSurface(LPDIRECTDRAW lpDD, LPCSTR lpName, + LPDDSURFACEDESC lpFormat, DWORD memoryflag) +{ + LPDIRECTDRAWSURFACE lpDDS; + DDSURFACEDESC ddsd, format; + D3DCOLOR colors[256]; + D3DCOLOR c; + DWORD dwWidth, dwHeight; + int i, j; + FILE *fp; + char *lpC; + CHAR buf[100]; + LPDIRECTDRAWPALETTE lpDDPal; + PALETTEENTRY ppe[256]; + int psize; + DWORD pcaps; + int color_count; + BOOL bQuant = FALSE; + HRESULT ddrval; + + /* + * Find the image file and open it + */ + fp = D3DAppIFindFile(lpName, "rb"); + if (fp == NULL) { + D3DAppISetErrorString("Cannot find %s.\n", lpName); + return NULL; + } + /* + * Is it a PPM file? + */ + fgets(buf, sizeof buf, fp); + if (lstrcmp(buf, "P6\n")) { + fclose(fp); + D3DAppISetErrorString("%s is not a PPM file.\n", lpName); + return NULL; + } + /* + * Skip any comments + */ + do { + fgets(buf, sizeof buf, fp); + } while (buf[0] == '#'); + /* + * Read the width and height + */ + sscanf(buf, "%d %d\n", &dwWidth, &dwHeight); + fgets(buf, sizeof buf, fp); /* skip next line */ + /* + * Create a surface of the given format using the dimensions of the PPM + * file. + */ + memcpy(&format, lpFormat, sizeof(DDSURFACEDESC)); + if (format.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) { + bQuant = TRUE; + psize = 256; + pcaps = DDPCAPS_8BIT | DDPCAPS_ALLOW256; + } else if (format.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED4) { + bQuant = TRUE; + psize = 16; + pcaps = DDPCAPS_4BIT; + } + memcpy(&ddsd, &format, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | memoryflag; + ddsd.dwHeight = dwHeight; + ddsd.dwWidth = dwWidth; + + ddrval = lpDD->lpVtbl->CreateSurface(lpDD, &ddsd, &lpDDS, NULL); + if (ddrval != DD_OK) { + D3DAppISetErrorString("CreateSurface for texture failed (loadtex).\n%s", + D3DAppErrorToString(ddrval)); + return NULL; + } + /* + * Lock the surface so it can be filled with the PPM file + */ + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddrval = lpDDS->lpVtbl->Lock(lpDDS, NULL, &ddsd, 0, NULL); + if (ddrval != DD_OK) { + lpDDS->lpVtbl->Release(lpDDS); + D3DAppISetErrorString("Lock failed while loading surface (loadtex).\n%s", + D3DAppErrorToString(ddrval)); + return NULL; + } + /* + * The method of loading depends on the pixel format of the dest surface + */ + if (!bQuant) { + /* + * The texture surface is not palettized + */ + unsigned long* lpLP; + unsigned short* lpSP; + unsigned char* lpCP; + unsigned long m; + int s; + int red_shift, red_scale; + int green_shift, green_scale; + int blue_shift, blue_scale; + /* + * Determine the red, green and blue masks' shift and scale. + */ + for (s = 0, m = format.ddpfPixelFormat.dwRBitMask; !(m & 1); + s++, m >>= 1); + red_shift = s; + red_scale = 255 / (format.ddpfPixelFormat.dwRBitMask >> s); + for (s = 0, m = format.ddpfPixelFormat.dwGBitMask; !(m & 1); + s++, m >>= 1); + green_shift = s; + green_scale = 255 / (format.ddpfPixelFormat.dwGBitMask >> s); + for (s = 0, m = format.ddpfPixelFormat.dwBBitMask; !(m & 1); + s++, m >>= 1); + blue_shift = s; + blue_scale = 255 / (format.ddpfPixelFormat.dwBBitMask >> s); + /* + * Each RGB bit count requires different pointers + */ + switch (format.ddpfPixelFormat.dwRGBBitCount) { + case 32 : + for (j = 0; j < (int)dwHeight; j++) { + /* + * Point to next row in texture surface + */ + lpLP = (unsigned long*)(((char*)ddsd.lpSurface) + + ddsd.lPitch * j); + for (i = 0; i < (int)dwWidth; i++) { + int r, g, b; + /* + * Read each value, scale it and shift it into position + */ + r = getc(fp) / red_scale; + g = getc(fp) / green_scale; + b = getc(fp) / blue_scale; + *lpLP = (r << red_shift) | (g << green_shift) | + (b << blue_shift); + lpLP++; + } + } + break; + case 16 : + for (j = 0; j < (int)dwHeight; j++) { + lpSP = (unsigned short*)(((char*)ddsd.lpSurface) + + ddsd.lPitch * j); + for (i = 0; i < (int)dwWidth; i++) { + int r, g, b; + r = getc(fp) / red_scale; + g = getc(fp) / green_scale; + b = getc(fp) / blue_scale; + *lpSP = (r << red_shift) | (g << green_shift) | + (b << blue_shift); + lpSP++; + } + } + break; + case 8: + for (j = 0; j < (int)dwHeight; j++) { + lpCP = (unsigned char*)(((char*)ddsd.lpSurface) + + ddsd.lPitch * j); + for (i = 0; i < (int)dwWidth; i++) { + int r, g, b; + r = getc(fp) / red_scale; + g = getc(fp) / green_scale; + b = getc(fp) / blue_scale; + *lpCP = (r << red_shift) | (g << green_shift) | + (b << blue_shift); + lpCP++; + } + } + break; + default: + /* + * This wasn't a format I recognize + */ + lpDDS->lpVtbl->Unlock(lpDDS, NULL); + fclose(fp); + lpDDS->lpVtbl->Release(lpDDS); + D3DAppISetErrorString("Unknown pixel format (loadtex)."); + return NULL; + } + /* + * Unlock the texture and return the surface pointer + */ + lpDDS->lpVtbl->Unlock(lpDDS, NULL); + fclose(fp); + return (lpDDS); + } + + /* + * We assume the 8-bit palettized case + */ + color_count = 0; /* number of colors in the texture */ + for (j = 0; j < (int)dwHeight; j++) { + /* + * Point to next row in surface + */ + lpC = ((char*)ddsd.lpSurface) + ddsd.lPitch * j; + for (i = 0; i < (int)dwWidth; i++) { + int r, g, b, k; + /* + * Get the next red, green and blue values and turn them into a + * D3DCOLOR + */ + r = getc(fp); + g = getc(fp); + b = getc(fp); + c = RGB_MAKE(r, g, b); + /* + * Search for this color in a table of colors in this texture + */ + for (k = 0; k < color_count; k++) + if (c == colors[k]) break; + if (k == color_count) { + /* + * This is a new color, so add it to the list + */ + color_count++; + /* + * More than 256 and we fail (8-bit) + */ + if (color_count > psize) { + color_count--; + k = color_count - 1; + //goto burst_colors; + } + colors[k] = c; + } + /* + * Set the "pixel" value on the surface to be the index into the + * color table + */ + if (psize == 16) { + if ((i & 1) == 0) + *lpC = k & 0xf; + else { + *lpC |= (k & 0xf) << 4; + lpC++; + } + } else { + *lpC = (char)k; + lpC++; + } + } + } + /* + * Close the file and unlock the surface + */ + fclose(fp); + lpDDS->lpVtbl->Unlock(lpDDS, NULL); + +//burst_colors: + if (color_count > psize) { + /* + * If there are more than 256 colors, we overran our palette + */ + lpDDS->lpVtbl->Unlock(lpDDS, NULL); + lpDDS->lpVtbl->Release(lpDDS); + D3DAppISetErrorString("Palette burst. (loadtex).\n"); + return (NULL); + } + + /* + * Create a palette with the colors in our color table + */ + memset(ppe, 0, sizeof(PALETTEENTRY) * 256); + for (i = 0; i < color_count; i++) { + ppe[i].peRed = (unsigned char)RGB_GETRED(colors[i]); + ppe[i].peGreen = (unsigned char)RGB_GETGREEN(colors[i]); + ppe[i].peBlue = (unsigned char)RGB_GETBLUE(colors[i]); + } + /* + * Set all remaining entry flags to D3DPAL_RESERVED, which are ignored by + * the renderer. + */ + for (; i < 256; i++) + ppe[i].peFlags = D3DPAL_RESERVED; + /* + * Create the palette with the DDPCAPS_ALLOW256 flag because we want to + * have access to all entries. + */ + ddrval = lpDD->lpVtbl->CreatePalette(lpDD, + DDPCAPS_INITIALIZE | pcaps, + ppe, &lpDDPal, NULL); + if (ddrval != DD_OK) { + lpDDS->lpVtbl->Release(lpDDS); + D3DAppISetErrorString("Create palette failed while loading surface (loadtex).\n%s", + D3DAppErrorToString(ddrval)); + return (NULL); + } + /* + * Finally, bind the palette to the surface + */ + ddrval = lpDDS->lpVtbl->SetPalette(lpDDS, lpDDPal); + if (ddrval != DD_OK) { + lpDDS->lpVtbl->Release(lpDDS); + lpDDPal->lpVtbl->Release(lpDDPal); + D3DAppISetErrorString("SetPalette failed while loading surface (loadtex).\n%s", + D3DAppErrorToString(ddrval)); + return (NULL); + } + + lpDDPal->lpVtbl->Release(lpDDPal); + + return lpDDS; +} diff --git a/3dc/win95/db.c b/3dc/win95/db.c new file mode 100644 index 0000000..90fd200 --- /dev/null +++ b/3dc/win95/db.c @@ -0,0 +1,1039 @@ +#ifndef NDEBUG + +/* ******************************************************************** * + * * + * DB.C - Debugging functions. * + * * + * By: Garry Lancaster Version: 2.0 * + * * + * ******************************************************************** */ + +/* N O T E S ********************************************************** */ + +/* A lot of these functions should be called via macros defined in db.h */ + +/* If you don't want to link this file with Windows OS files set the + * define DB_NOWINDOWS. This will also stop linking with the Direct Draw + * stuff, which is, after all, a part of Windows. If you want Windows + * stuff, but NOT Direct Draw, define DB_NODIRECTDRAW. + */ + +/* ******************************************************************** * + * * + * I N T E R F A C E - both internal and external. * + * * + * ******************************************************************** */ + +/* I N C L U D E S **************************************************** */ + +/* Windows includes. Actually internal, but here to allow pre-compilation. */ +#include "advwin32.h" +#ifndef DB_NOWINDOWS + #include + #include "advwin32.h" +#endif +#ifndef DB_NODIRECTDRAW + #include +#endif +#include "db.h" /* Contains most off the interface. */ + +/* G L O B A L S ****************************************************** */ +/* Have external linkage. */ +volatile BOOL DZ_NULL; + +/* This variable dictates whether macros ending _opt get executed. */ +int db_option = 0; /* Default is off. */ + +/* ******************************************************************** * + * * + * I N T E R N A L * + * * + * ******************************************************************** */ + +/* I N C L U D E S **************************************************** */ + +/* Defining DB_NOWINDOWS implies DB_NODIRECTDRAW should also be defined. */ +#ifdef DB_NOWINDOWS + #ifndef DB_NODIRECTDRAW + #define DB_NODIRECTDRAW + #endif +#endif + +/* ANSI includes. */ +#include +#include +#include +#include +#include /* For getcwd() */ +#include /* For variable arguments. */ + +/* C O N S T A N T S ************************************************** */ + +/* Possible return value for MessageBox() */ +#define NO_MEMORY 0 + +/* Possible value for the width field of a font_struct. */ +#define PROP_WIDTH 0 + +/* Logfile name */ +#define LOGFILE_NAME "LOGFILE.TXT" + +/* Set this to 1 if the logfile name is an absolute path. Otherwise the + * logfile will go in the directory that is current when db_log_init() + * is called. + */ +#define ABSOLUTE_PATH 0 + +/* M A C R O S ******************************************************** */ + +/* Causes a division by zero exception. */ +#define DB_FORCE_EXCEPTION() ( db_vol_zero = 1 / db_vol_zero ) + +/* Cause a brakepoint. */ +#define DB_FORCE_BRAKEPOINT() do {__asm int 3} while(0) + +/* T Y P E S ********************************************************** */ + + +typedef struct font_struct *fontPtr; + +struct font_struct { + void *dummy1; + unsigned short dummy2, dummy3; + void *dummy4; + char filename[16]; + unsigned short width, height; + unsigned short ascent, avgwidth; + unsigned char byte_width; + unsigned char filler1; + short filler2; + char facename[28]; + unsigned short *prop_width_dataP; + unsigned char *bitmapP; +}; + +union PtrPackTag +{ + unsigned char *cP; + unsigned short *wP; + unsigned long *lP; +}; + +/* G L O B A L ******************************************************** */ +/* Should all be static. */ +static BOOL db_use_brakepoints = FALSE; + +/* Name of file to output log messages to. */ +static char LogFileNameP[255]; + +/* Have we initialized the log file? */ +static int InitialisedLog = 0; + +/* Type of display mode we are in. */ +static int db_display_type = DB_DOS; + +/* For DirectDraw mode. */ +static struct db_dd_mode_tag dd_mode = {NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}; +static fontPtr FontP = NULL; + +/* Volatile zero. */ +static volatile int db_vol_zero = 0; + +/* Text strings for output. */ +static const char* db_assert_textA[ 3 ] = +{ + "ASSERTION FAILED!", + "Expression: %s", + "File: %s Line: %d" +}; +static const char* db_prompt_std = + "Quit program/force e(x)ception? [y/n/x]"; +static const char* db_prompt_windows = + "Quit program? [Yes/No]/force exception? [Cancel]"; +static const char* db_assert_log_begin_text = + "DB: FAILED ASSERTION BEGINS"; +static const char* db_assert_log_end_text = + "DB: FAILED ASSERTION ENDS"; +static const char* db_msg_log_begin_text = + "DB: MSG BEGINS"; +static const char* db_msg_log_end_text = + "DB: MSG ENDS"; + +#ifdef DB_NOWINDOWS +static char db_log_file_name[261] = LOGFILE_NAME; +#else +static char db_log_file_name[MAX_PATH+1] = LOGFILE_NAME; +#endif + + +/* P R O T O S ******************************************************** */ +/* Should all be static. */ + +static void db_do_std_prompt(unsigned yOffset); + +#ifndef DB_NOWINDOWS +static void db_do_win_prompt(const char* titleStrP, const char* bodyStrP); +#endif /* ifndef DB_NOWINDOWS */ + +#ifndef DB_NODIRECTDRAW + +/* Load debugging font, return NULL if we fail. */ +static fontPtr guiload_font(char *new_fname); + +/* Cleanup function for the above. */ +static fontPtr CleanupFontLoadFail(HANDLE fH, fontPtr fontP); + +/* Outputs debugging text. */ +static void out_text(LPDIRECTDRAWSURFACE surfP, int xc, int yc, + const char *text, short x_limit, fontPtr fP); + +/* Debounce all the keys the Direct Draw stuff uses. */ +static void Debounce(void); + +/* Wait for any outstanding flip operations to be completed, provided + * that the user specified DB_FLIP in the bltOrFlip field of the + * db_dd_mode_tag function. If they specified DB_BLIT this function returns + * immediately. + */ +static void DbWaitForHw(void); + +/* Flips between the draw and visible surfaces. */ +static void DbFlip(void); + +/* Blits the contents of the draw surface to the visible surface. */ +static void DbBlt(void); + +#endif /* ifndef DB_NODIRECTDRAW */ + +/* F U N C T I O N S ************************************************** */ + +/* ******************************************************************** * + * * + * I N T E R F A C E - both internal and external. * + * * + * ******************************************************************** */ + +/* NEW FNS for formatted debug strings. */ +void __cdecl db_logf_fired(const char *fmtStrP, ...) +{ + char msg[ 1024 ]; + va_list varArgList; + + va_start( varArgList, fmtStrP ); + vsprintf( msg, fmtStrP, varArgList ); + va_end( varArgList ); + + db_log_fired( msg ); +} + +void __cdecl db_printf_fired(int x, int y, const char *fmtStrP, ...) +{ + char msg[ 256 ]; + va_list varArgList; + + va_start( varArgList, fmtStrP ); + vsprintf( msg, fmtStrP, varArgList ); + va_end( varArgList ); + + db_print_fired( x, y, msg ); +} + +void __cdecl db_msgf_fired(const char *fmtStrP, ...) +{ + char msg[ 256 ]; + va_list varArgList; + + va_start( varArgList, fmtStrP ); + vsprintf( msg, fmtStrP, varArgList ); + va_end( varArgList ); + + db_msg_fired( (const char *) msg ); +} + +/* Called whenever an assertion fails. */ +void db_assert_fail(const char *exprP, const char *fileP, int line) +{ + db_log_fired( db_assert_log_begin_text ); + db_log_fired( db_assert_textA[ 0 ] ); + db_logf_fired( db_assert_textA[ 1 ], exprP ); + db_logf_fired( db_assert_textA[ 2 ], fileP, line ); + db_log_fired( db_assert_log_end_text ); + + switch(db_display_type) + { + case DB_DOS: + printf( db_assert_textA[ 0 ] ); + printf("\n"); + printf( db_assert_textA[ 1 ], exprP ); + printf("\n"); + printf( db_assert_textA[ 2 ], fileP, line ); + printf("\n"); + db_do_std_prompt( 0 ); + break; +#ifndef DB_NODIRECTDRAW + case DB_DIRECTDRAW: + { + char msg[256]; + unsigned short xLimit = (unsigned short) dd_mode.width; + + /* Wait for any hardware to finish flipping. */ + DbWaitForHw(); + + out_text((LPDIRECTDRAWSURFACE) dd_mode.drawSurfaceP, + 0, 0, db_assert_textA[ 0 ], xLimit, FontP); + wsprintf(msg, db_assert_textA[ 1 ], exprP); + out_text((LPDIRECTDRAWSURFACE) dd_mode.drawSurfaceP, + 0, 16, msg, xLimit, FontP); + wsprintf(msg, db_assert_textA[ 2 ], fileP, line); + out_text((LPDIRECTDRAWSURFACE) dd_mode.drawSurfaceP, + 0, 32, msg, xLimit, FontP); + db_do_std_prompt( 48 ); + } + break; +#endif +#ifndef DB_NOWINDOWS + case DB_WINDOWS: + { + char fmtMsg[ 256 ]; + char msg[256]; + + strcpy( fmtMsg, db_assert_textA[ 1 ] ); + strcat( fmtMsg, db_assert_textA[ 2 ] ); + strcat( fmtMsg, db_prompt_windows ); + sprintf(msg, fmtMsg, exprP, fileP, line); + + db_do_win_prompt( db_assert_textA[ 0 ], msg ); + } + break; +#endif + default: + break; + } +} + +/* Displays a message and has the program pause until the user responds + * to it. + */ +void db_msg_fired(const char *strP) +{ + db_log_fired( db_msg_log_begin_text ); + db_log_fired( strP ); + db_log_fired( db_msg_log_end_text ); + + switch(db_display_type) + { + case DB_DOS: + printf("%s\n", strP); + db_do_std_prompt( 0 ); + break; +#ifndef DB_NOWINDOWS + case DB_WINDOWS: + db_do_win_prompt( "Debugging Message", strP ); + break; +#endif +#ifndef DB_NODIRECTDRAW + case DB_DIRECTDRAW: + { + unsigned short xLimit = (unsigned short) dd_mode.width; + + /* Wait for any flip hardware to be ready. */ + DbWaitForHw(); + + out_text((LPDIRECTDRAWSURFACE) dd_mode.drawSurfaceP, + 0, 0, strP, xLimit, FontP); + db_do_std_prompt( 16 ); + } + break; +#endif + default: + break; + } +} + +/* Displays a message and continues program execution immediately. */ +void db_print_fired(int x, int y, const char *strP) +{ + switch(db_display_type) + { + case DB_DOS: + printf("%s\n", strP); + break; +#ifndef DB_NOWINDOWS + case DB_WINDOWS: + break; +#endif +#ifndef DB_NODIRECTDRAW + case DB_DIRECTDRAW: + { + unsigned short xLimit = (unsigned short) (dd_mode.width - x); + out_text((LPDIRECTDRAWSURFACE) dd_mode.drawSurfaceP, x, y, + strP, xLimit, FontP); + break; + } +#endif + default: + break; + } +} + +/* Writes a message to a log file. */ +/* At least files can be output in the same way under DOS, Windows and + * Direct Draw! + */ +void db_log_fired(const char *strP) +{ + /* Have we intialised the file? */ + if(!InitialisedLog) db_log_init(); + { + /* Open a file for appending, creating one if it doesn't yet exist. */ + FILE *fP = fopen(LogFileNameP, "a+"); + + if(!fP) return; + + fprintf(fP, "%s\n", strP); + fclose(fP); + } +} + +void db_log_init(void) +{ + #if ABSOLUTE_PATH + sprintf( LogFileNameP, "%s", db_log_file_name ); + #else + /* Append the log file name to the current working directory. */ + sprintf( LogFileNameP, "%s\\%s", getcwd( LogFileNameP, 240 ), + db_log_file_name ); + #endif + + /* Delete old log file. */ + remove(LogFileNameP); + + /* Flag that we have initialised the log file. */ + InitialisedLog = 1; +} + +extern void db_set_log_file_ex(const char *strP) +{ + InitialisedLog = 0; + + strcpy(db_log_file_name, strP); +} + +void db_set_mode_ex(int mode, void *modeInfoP, void *newFontP) +{ + db_display_type = mode; +#ifndef DB_NODIRECTDRAW + if(dd_mode.visibleSurfaceP) + { + IDirectDrawSurface_Release((LPDIRECTDRAWSURFACE) dd_mode.visibleSurfaceP); + dd_mode.visibleSurfaceP = NULL; + } + + if(dd_mode.drawSurfaceP) + { + IDirectDrawSurface_Release((LPDIRECTDRAWSURFACE) dd_mode.drawSurfaceP); + dd_mode.drawSurfaceP = NULL; + } + + if(mode == DB_DIRECTDRAW) + { + dd_mode = *((struct db_dd_mode_tag *) modeInfoP); + + if(dd_mode.visibleSurfaceP) + { + IDirectDrawSurface_AddRef((LPDIRECTDRAWSURFACE) dd_mode.visibleSurfaceP); + } + + if(dd_mode.drawSurfaceP) + { + IDirectDrawSurface_AddRef((LPDIRECTDRAWSURFACE) dd_mode.drawSurfaceP); + } + + if(!FontP) + { + if(!newFontP) + FontP = guiload_font("DIALOG.FNT"); + else + FontP = (fontPtr) newFontP; + } + if(!FontP) + { + db_log_fired("DB ERROR: Font load failed. Exiting..."); + exit(0); + } + } +#endif +} + +/* Called to set whether exceptions or brakepoints are called. */ +void DbUseBrakepoints(BOOL use_brakepoints) +{ + db_use_brakepoints = use_brakepoints; +} + +int db_get_mode(void** modeInfoPP, void **FontPP) +{ + // blank return areas + *FontPP = NULL; + *modeInfoPP = NULL; + +#ifndef DB_NODIRECTDRAW + if(db_display_type == DB_DIRECTDRAW) + { + // copy font data + *FontPP = (void *) FontP; + + // copy surface data + *modeInfoPP = (void *) &dd_mode; + } +#endif + return db_display_type; +} + +void db_uninit(void) +{ + #ifndef DB_NODIRECTDRAW + if(FontP) + { + if(FontP->bitmapP) + { + GlobalFree(FontP->bitmapP); + } + if(FontP->prop_width_dataP) + { + GlobalFree(FontP->prop_width_dataP); + } + + GlobalFree(FontP); + FontP = NULL; + } + + if(dd_mode.visibleSurfaceP) + { + IDirectDrawSurface_Release((LPDIRECTDRAWSURFACE) dd_mode.visibleSurfaceP); + } + + if(dd_mode.drawSurfaceP) + { + IDirectDrawSurface_Release((LPDIRECTDRAWSURFACE) dd_mode.drawSurfaceP); + } + + #endif +} + +/* ******************************************************************** * + * * + * I N T E R N A L * + * * + * ******************************************************************** */ + +static void db_do_std_prompt(unsigned yOffset) +{ + int ch = 0; + + switch(db_display_type) + { + case DB_DOS: + printf( db_prompt_std ); + printf("\n"); + do + { + ch = toupper(getch()); + } + while((ch != 'N') && (ch != 'Y') && (ch != 'X')); + break; +#ifndef DB_NODIRECTDRAW + case DB_DIRECTDRAW: + { + SHORT response; + BOOL done = FALSE; + unsigned short xLimit = (unsigned short) dd_mode.width; + + out_text((LPDIRECTDRAWSURFACE) dd_mode.drawSurfaceP, + 0, yOffset, db_prompt_std, xLimit, FontP); + + /* Show the message. */ + if(dd_mode.bltOrFlip == DB_FLIP) + { + DbFlip(); + } + else + { + DbBlt(); + } + + /* Wait for a valid key press. */ + do + { + response = GetAsyncKeyState('Y'); + if(response & 0x8000) + { + ch = 'Y'; + done = TRUE; + } + response = GetAsyncKeyState('N'); + if(response & 0x8000) + { + ch = 'N'; + done = TRUE; + } + response = GetAsyncKeyState('X'); + if(response & 0x8000) + { + ch = 'X'; + done = TRUE; + } + } + while(!done); + + Debounce(); + + /* Return the flip surfaces to their pre-message state. */ + if(dd_mode.bltOrFlip == DB_FLIP) + { + DbFlip(); + } + break; + } +#endif /* ifndef DB_NODIRECTDRAW */ + }/* switch(db_display_type) */ + + if(ch == 'Y') + { + exit(-10); + } + else if(ch == 'X') + { + if(db_use_brakepoints) + { + DB_FORCE_BRAKEPOINT(); + } + else + { + DB_FORCE_EXCEPTION(); + } + } + +}/* db_do_std_prompt() */ + +#ifndef DB_NOWINDOWS +static void db_do_win_prompt(const char* titleStrP, const char* bodyStrP) +{ + int response; + + response = MessageBox + ( + NULL, /* Dialog has no KNOWN parent window. */ + bodyStrP, /* Message to go in box. */ + titleStrP, /* Box title. */ + MB_YESNOCANCEL| /* Put up a 'Yes' and a 'No' button. */ + MB_SETFOREGROUND| /* Shove message box to front of display. */ + MB_ICONEXCLAMATION| /* Use an exclamation mark to decorate box. */ + MB_TASKMODAL /* Suspend current task until box is closed. */ + ); + + if((response == IDYES) || (response == NO_MEMORY)) + { + exit( -10 ); + } + else if(response == IDCANCEL) + { + if(db_use_brakepoints) + { + DB_FORCE_BRAKEPOINT(); + } + else + { + DB_FORCE_EXCEPTION(); + } + } +}/* db_do_win_prompt() */ +#endif /* ifndef DB_NOWINDOWS */ + +#ifndef DB_NODIRECTDRAW + +static fontPtr guiload_font(char *new_fname) +{ + HANDLE *fH; + BOOL status; + unsigned short c, byte, y; + union PtrPackTag dest; + unsigned char inByte; + fontPtr fntSP; + DWORD bytesRead; + + /* Open file for reading */ + fH = CreateFile(new_fname, GENERIC_READ, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if(!fH) + { + db_log_fired("DB ERROR: Couldn't open font file."); + return CleanupFontLoadFail(NULL, NULL); + } + + + /* Allocate memory for our font structure */ + fntSP = (fontPtr) + GlobalAlloc(GMEM_FIXED, sizeof(struct font_struct)); + if(!fntSP) + { + db_log_fired("DB ERROR: Not enough memory for font structure."); + return CleanupFontLoadFail(fH, NULL); + } + + /* Nullify pointers inside the font structure. */ + fntSP->bitmapP = NULL; + fntSP->prop_width_dataP = NULL; + + /* Load up font structure */ + status = ReadFile(fH, fntSP, sizeof(struct font_struct), &bytesRead, + NULL); + if((!status) || (bytesRead != sizeof(struct font_struct))) + { + db_log_fired("DB ERROR: Error reading structure from font file."); + return CleanupFontLoadFail(fH, fntSP); + } + + /* Allocate memory for font bitmap */ + fntSP->bitmapP = (unsigned char *) GlobalAlloc(GMEM_FIXED, + fntSP->byte_width * dd_mode.bitsPerPixel * fntSP->height * 128); + if(!fntSP->bitmapP) + { + db_log_fired("DB ERROR: Not enough memory for font bitmap."); + return CleanupFontLoadFail(fH, fntSP); + } + + /* Work out proportional text widths for this font + * (if the font is proportional). + */ + if(fntSP->width == PROP_WIDTH) + { + /* Allocate memory for proportional width data */ + fntSP->prop_width_dataP = (unsigned short *) + GlobalAlloc(GMEM_FIXED, 256); + if(!fntSP->prop_width_dataP) + { + db_log_fired("DB ERROR: Not enough memory for proportional " + "font data"); + return CleanupFontLoadFail(fH, fntSP); + } + + /* Read proportional width data */ + status = ReadFile(fH, fntSP->prop_width_dataP, 256, &bytesRead, + NULL); + if((!status) || (bytesRead != 256)) + { + db_log_fired("DB ERROR: Error reading proportional font data " + "from file."); + return CleanupFontLoadFail(fH, fntSP); + } + + /* Round width of font to nearest long word. */ + { + int i; + unsigned short *propP = fntSP->prop_width_dataP; + + if(dd_mode.bitsPerPixel == 8) + { + for(i = 0; i < 128; i ++) + { + /* Round up to 4 pixels. */ + *propP = (unsigned short) ((*propP + 3U) & (~3U)); + } + propP++; + } + else + { + for(i = 0; i < 128; i ++) + { + /* Round up to 2 pixels. */ + *propP = (unsigned short) ((*propP + 1U) & (~1U)); + } + propP++; + } + } + } + else + { + /* Round width to nearest long word. */ + if(dd_mode.bitsPerPixel == 8) + { + /* Round up to 4 pixels. */ + fntSP->width = (unsigned char) ((fntSP->width + 2) & (~3)); + } + else + { + /* Round up to 2 pixels. */ + fntSP->width = (unsigned char) ((fntSP->width + 1) & (~1)); + } + } + + /* Load up bitmap data */ + dest.cP = fntSP->bitmapP; + for(c = 0; c < 128; c ++) + { + for(y = 0; y < fntSP->height; y ++) + { + for(byte = 0; byte < fntSP->byte_width; byte ++) + { + unsigned char bitMask = 0x80; + + /* Read a byte of data */ + status = ReadFile(fH, &inByte, 1, &bytesRead, NULL); + if((!status) || (bytesRead != 1)) + { + db_log_fired("DB ERROR: Error reading font bitmap from " + "file."); + return CleanupFontLoadFail(fH, fntSP); + } + + /* Translate 1 bit per pixel data into current Direct Draw + * screen mode bit depth. + */ + if(dd_mode.bitsPerPixel == 8) + { + do + { + if(inByte & bitMask) *(dest.cP) = + (unsigned char) dd_mode.foreCol; + else *(dest.cP) = (unsigned char) dd_mode.backCol; + dest.cP++; + + /* Shift bitMask 1 bit to the right */ + bitMask >>= 1; + } + while(bitMask); + } + else + { + do + { + if(inByte & bitMask) *(dest.wP) = dd_mode.foreCol; + else *(dest.wP) = dd_mode.backCol; + dest.wP++; + + /* Shift bitMask 1 bit to the right */ + bitMask >>= 1; + } + while(bitMask); + } + } + } + } + + /* Close the font file */ + CloseHandle(fH); + + return fntSP; +} + +static fontPtr CleanupFontLoadFail(HANDLE fH, fontPtr fontP) +{ + /* Close file if necessary */ + if(fH) CloseHandle(fH); + + /* Is the font struct allocated? */ + if(fontP) + { + /* Yes. Is the bitmap allocated? If so, free it. */ + if(fontP->bitmapP) GlobalFree(fontP->bitmapP); + + /* Is the proportional width data allocated. If so, free it. */ + if(fontP->prop_width_dataP) GlobalFree(fontP->prop_width_dataP); + + /* Free the font structure. */ + GlobalFree(fontP); + } + + return NULL; +} + +static void out_text(LPDIRECTDRAWSURFACE surfP, int xc, int yc, + const char *text, short x_limit, fontPtr fP) +{ + register unsigned long *srcP, *destP; + register unsigned int x, y; + unsigned long heightTimesPitch, charOffset; + unsigned int prop_width; + int srcIncr, longsPerLine; + unsigned int bitShift; + DDSURFACEDESC surfaceDesc; + + /* Lock the surface. */ + { + HRESULT res; + + surfaceDesc.dwSize = sizeof surfaceDesc; + res = IDirectDrawSurface_Lock(surfP, NULL, &surfaceDesc, + DDLOCK_WAIT, NULL); + if(res != DD_OK) + { + db_log3("Couldn't lock surface."); + return; + } + } + + /* Round xc to nearest long word. */ + if(dd_mode.bitsPerPixel == 8) + { + xc = (xc + 2) & (~3); + bitShift = 2; + } + else + { + xc = (xc + 1) & (~1); + bitShift = 1; + } + + /* Point to DRAM buffer co-ordinate where the top left of the + * first character should be written. + */ + destP = (unsigned long *) surfaceDesc.lpSurface + + ((yc * surfaceDesc.lPitch) >> 2) + (xc >> bitShift); + heightTimesPitch = (fP->height * surfaceDesc.lPitch) >> 2; + longsPerLine = (fP->byte_width * dd_mode.bitsPerPixel) >> 2; + charOffset = longsPerLine * fP->height; + + /* Write our text string */ + while(*text != '\0') + { + /* Blit a single character */ + /* Point srcP to first byte of the bitmap for the current + * character. + */ + srcP = ((unsigned long *) fP->bitmapP) + (*text) * charOffset; + + /* Get width of this character (in pixels). */ + if(fP->width == PROP_WIDTH) + prop_width = *(fP->prop_width_dataP + (*text)); + else prop_width = fP->width; + + /* Check we will not exceed our original x_limit if we blit + * this character. If we will, we should stop writing. + */ + x_limit = (short) (x_limit - prop_width); + if(x_limit < 0) break; + + /* Convert prop_width from pixels to longs. */ + prop_width >>= bitShift; + + srcIncr = longsPerLine - prop_width; + + y = fP->height; + do + { + x = prop_width; + do + { + /* Move 1 long word. */ + *destP++ = *srcP++; + } + while(--x != 0); + + /* Point to start of next horizontal line of character square + * in DRAM buffer. + */ + destP += (surfaceDesc.lPitch >> 2) - prop_width; + srcP += srcIncr; + } + while(--y != 0); + + /* Point to start of next character position in DRAM buffer */ + destP -= heightTimesPitch - prop_width; + + /* Advance one character in text string */ + text++; + } + + /* Unlock surface. */ + { + HRESULT res; + + res = IDirectDrawSurface_Unlock(surfP, + (LPVOID) surfaceDesc.lpSurface); + if(res != DD_OK) db_log_fired("Couldn't unlock surface."); + } + return; +} + +static void Debounce(void) +{ + BOOL bouncing; + + /* Debounce all the keys we use - that is Y, N, and RETURN. */ + do + { + bouncing = FALSE; + if(GetAsyncKeyState('Y') & 0x8000) bouncing = TRUE; + if(GetAsyncKeyState('N') & 0x8000) bouncing = TRUE; + if(GetAsyncKeyState('X') & 0x8000) bouncing = TRUE; + if(GetAsyncKeyState(VK_RETURN) & 0x8000) bouncing = TRUE; + } + while(bouncing); +} + +static void DbWaitForHw(void) +{ + /* Wait until the last flip is finished and the last blt done */ + BOOL finished; + + /* Stay in this loop until the hardware is free. */ + do + { + finished = TRUE; + + /* Make sure all flips are done. */ + if(dd_mode.bltOrFlip == DB_FLIP) + { + if(IDirectDrawSurface_GetFlipStatus( + (LPDIRECTDRAWSURFACE) dd_mode.visibleSurfaceP, + DDGFS_ISFLIPDONE) != DD_OK) + finished = FALSE; + } + } + while(!finished); +} + +static void DbFlip(void) +{ + LPDIRECTDRAWSURFACE fromSurfP = + (LPDIRECTDRAWSURFACE) dd_mode.drawSurfaceP; + LPDIRECTDRAWSURFACE toSurfP = + (LPDIRECTDRAWSURFACE) dd_mode.visibleSurfaceP; + HRESULT res; + + /* Try to flip the screen. */ + res = IDirectDrawSurface_Flip(toSurfP, fromSurfP, DDFLIP_WAIT); + + if(res != DD_OK) + db_log_fired("Internal debug flip failed - message lost!"); +} + +static void DbBlt(void) +{ + LPDIRECTDRAWSURFACE fromSurfP = + (LPDIRECTDRAWSURFACE) dd_mode.drawSurfaceP; + LPDIRECTDRAWSURFACE toSurfP = + (LPDIRECTDRAWSURFACE) dd_mode.visibleSurfaceP; + HRESULT res; + RECT toRect; + + /* Initialise to Rect. */ + toRect.left = dd_mode.bltXOffset; + toRect.top = dd_mode.bltYOffset; + toRect.right = toRect.left + dd_mode.width; + toRect.bottom = toRect.top + dd_mode.height; + + /* Try to blit from the draw to the visible surface. */ + res = IDirectDrawSurface_Blt(toSurfP, &toRect, fromSurfP, NULL, + DDBLT_WAIT, NULL); + + if(res != DD_OK) + db_log_fired("Internal debug blit failed - message lost."); +} + +#endif + +#else + ; +#endif /* ! NDEBUG */ diff --git a/3dc/win95/fail.c b/3dc/win95/fail.c new file mode 100644 index 0000000..013f1ec --- /dev/null +++ b/3dc/win95/fail.c @@ -0,0 +1,37 @@ +/* LotU: Error handling functions. + + Copyright (C) 1995, Jamie Lokier. + Written for Rebellion Developments, Ltd. + + Permission to use, copy, modify and distribute this file for any + purpose by Rebellion Developments, Ltd. is hereby granted. If you + want to use this file outside the company, please let me know. +*/ + +#include "3dc.h" +#include "fail.h" +#include "dxlog.h" + +void +fail (const char * format, ...) +{ + va_list ap; + + LOGDXSTR(format); + va_start (ap, format); + if (format != 0) + vfprintf (stderr, format, ap); + va_end (ap); + + exit (EXIT_FAILURE); +} + +void FAILHandleCompilerWarningMessage(void) +{ + int temp; + + temp = D3DRMMAP_PERSPCORRECT; + temp = D3DRMMAP_WRAPU; + temp = D3DRMMAP_WRAPV; + temp = D3DRMGROUP_ALLGROUPS; +} \ No newline at end of file diff --git a/3dc/win95/fail.h b/3dc/win95/fail.h new file mode 100644 index 0000000..8838103 --- /dev/null +++ b/3dc/win95/fail.h @@ -0,0 +1,44 @@ +/* LotU: Error handling functions. + + Copyright (C) 1995, Jamie Lokier. + Written for Rebellion Developments, Ltd. + + Permission to use, copy, modify and distribute this file for any + purpose by Rebellion Developments, Ltd. is hereby granted. If you + want to use this file outside the company, please let me know. +*/ + +#ifndef __fail_h +#define __fail_h 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +#define VARARG_DECL __cdecl +#else +#define VARARG_DECL +#endif + +#ifdef __GNUC__ + +#if __GNUC__ >= 2 && __GNUC_MINOR__ >= 5 +extern void +VARARG_DECL fail (const char * __format, ...) + __attribute__ ((noreturn, format (printf, 1, 2))); +#else +extern __volatile__ void VARARG_DECL fail (const char * __format, ...); +#endif + +#else + +extern void VARARG_DECL fail (const char * __format, ...); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __fail_h */ diff --git a/3dc/win95/fragchnk.cpp b/3dc/win95/fragchnk.cpp new file mode 100644 index 0000000..dc998d7 --- /dev/null +++ b/3dc/win95/fragchnk.cpp @@ -0,0 +1,255 @@ +#include "fragchnk.hpp" + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(fragchnk) + +RIF_IMPLEMENT_DYNCREATE("FRAGTYPE",Fragment_Type_Chunk) + +CHUNK_WITH_CHILDREN_LOADER("FRAGTYPE",Fragment_Type_Chunk) + +/* +Children for Fragment_Type_Chunk : + +Fragment_Type_Data_Chunk "FRGTYPDC" +Fragment_Type_Shape_Chunk "FRGTYPSC" +Fragment_Type_Sound_Chunk "FRGSOUND" +*/ + + +const char* Fragment_Type_Chunk::get_name() +{ + Fragment_Type_Data_Chunk* ftdc=(Fragment_Type_Data_Chunk*)lookup_single_child("FRGTYPDC"); + + if(ftdc) + return ftdc->frag_type_name; + else + return 0; + +} + +//////////////////////////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("FRGTYPDC",Fragment_Type_Data_Chunk) + +Fragment_Type_Data_Chunk::Fragment_Type_Data_Chunk(Chunk_With_Children* parent,const char* name) +:Chunk(parent,"FRGTYPDC") +{ + frag_type_name=new char[strlen(name)+1]; + strcpy(frag_type_name,name); + pad1=pad2=pad3=0; +} + +Fragment_Type_Data_Chunk::Fragment_Type_Data_Chunk(Chunk_With_Children* const parent,const char* data,size_t const ) +:Chunk(parent,"FRGTYPDC") +{ + int length=strlen(data)+1; + frag_type_name=new char[length]; + strcpy(frag_type_name,data); + data+=(length+3)&~3; + + pad1=*(int*)data; + data+=4; + pad2=*(int*)data; + data+=4; + pad3=*(int*)data; + data+=4; +} + +Fragment_Type_Data_Chunk::~Fragment_Type_Data_Chunk() +{ + if(frag_type_name) delete frag_type_name; +} + +void Fragment_Type_Data_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + strcpy(data_start,frag_type_name); + data_start+=(strlen(frag_type_name)+4)&~3; + + *(int*)data_start=pad1; + data_start+=4; + *(int*)data_start=pad2; + data_start+=4; + *(int*)data_start=pad3; + data_start+=4; + +} + +size_t Fragment_Type_Data_Chunk::size_chunk() +{ + chunk_size=12+12; + chunk_size+=(strlen(frag_type_name)+4)&~3; + return chunk_size; +} + + +//////////////////////////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("FRGTYPSC",Fragment_Type_Shape_Chunk) + +Fragment_Type_Shape_Chunk::Fragment_Type_Shape_Chunk(Chunk_With_Children* parent,const char* _name,int number,ChunkVectorInt _location) +:Chunk(parent,"FRGTYPSC") +{ + name=new char[strlen(_name)+1]; + strcpy(name,_name); + num_fragments=number; + location=_location; + pad1=pad2=pad3=0; +} + +#if UseOldChunkLoader +Fragment_Type_Shape_Chunk::Fragment_Type_Shape_Chunk(Chunk_With_Children* const parent,const char* data,size_t const ) +:Chunk(parent,"FRGTYPSC") +{ + int length=strlen(data)+1; + name=new char[length]; + strcpy(name,data); + data+=(length+3)&~3; + + num_fragments=*(int*)data; + data+=4; + + location=*(ChunkVector*)data; + data+=sizeof(ChunkVector); + + + pad1=*(int*)data; + data+=4; + pad2=*(int*)data; + data+=4; + pad3=*(int*)data; + data+=4; +}; +#else +Fragment_Type_Shape_Chunk::Fragment_Type_Shape_Chunk(Chunk_With_Children* const parent,const char* data,size_t const ) +:Chunk(parent,"FRGTYPSC") +{ + int length=strlen(data)+1; + name=new char[length]; + strcpy(name,data); + data+=(length+3)&~3; + + num_fragments=*(int*)data; + data+=4; + + location=*(ChunkVectorInt*)data; + data+=sizeof(ChunkVectorInt); + + + pad1=*(int*)data; + data+=4; + pad2=*(int*)data; + data+=4; + pad3=*(int*)data; + data+=4; +} +#endif + +Fragment_Type_Shape_Chunk::~Fragment_Type_Shape_Chunk() +{ + if(name) delete name; +} + +void Fragment_Type_Shape_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + strcpy(data_start,name); + data_start+=(strlen(name)+4)&~3; + + *(int*)data_start=num_fragments; + data_start+=4; + + *(ChunkVectorInt*)data_start=location; + data_start+=sizeof(ChunkVectorInt); + + *(int*)data_start=pad1; + data_start+=4; + *(int*)data_start=pad2; + data_start+=4; + *(int*)data_start=pad3; + data_start+=4; + +} + +size_t Fragment_Type_Shape_Chunk::size_chunk() +{ + chunk_size=12+16+sizeof(ChunkVectorInt); + chunk_size+=(strlen(name)+4)&~3; + return chunk_size; +} + +//////////////////////////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("FRGSOUND",Fragment_Type_Sound_Chunk) + +Fragment_Type_Sound_Chunk::Fragment_Type_Sound_Chunk(Chunk_With_Children* parent) +:Chunk(parent,"FRGSOUND") +{ + wav_name=0; + inner_range=5000; + outer_range=40000; + max_volume=127; + pitch=0; + pad=0; +} + +Fragment_Type_Sound_Chunk::Fragment_Type_Sound_Chunk(Chunk_With_Children* const parent,const char* data,size_t const ) +:Chunk(parent,"FRGSOUND") +{ + inner_range=*(unsigned long*)data; + data+=4; + outer_range=*(unsigned long*)data; + data+=4; + + max_volume=*(int*)data; + data+=4; + pitch=*(int*)data; + data+=4; + pad=*(int*)data; + data+=4; + + wav_name=new char[strlen(data)+1]; + strcpy(wav_name,data); + +} + +Fragment_Type_Sound_Chunk::~Fragment_Type_Sound_Chunk() +{ + if(wav_name) delete wav_name; +} + +void Fragment_Type_Sound_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + + *(unsigned long*)data_start=inner_range; + data_start+=4; + *(unsigned long*)data_start=outer_range; + data_start+=4; + + *(int*)data_start=max_volume; + data_start+=4; + *(int*)data_start=pitch; + data_start+=4; + *(int*)data_start=pad; + data_start+=4; + + strcpy(data_start,wav_name); + +} + +size_t Fragment_Type_Sound_Chunk::size_chunk() +{ + chunk_size=12+20; + chunk_size+=(strlen(wav_name)+4)&~3; + return chunk_size; +} + diff --git a/3dc/win95/fragchnk.hpp b/3dc/win95/fragchnk.hpp new file mode 100644 index 0000000..4fc806e --- /dev/null +++ b/3dc/win95/fragchnk.hpp @@ -0,0 +1,82 @@ +#ifndef _fragchnk_hpp_ +#define _fragchnk_hpp_ + +#include "chunk.hpp" +#include "chnktype.hpp" + + +class Fragment_Type_Data_Chunk : public Chunk +{ +public : + + Fragment_Type_Data_Chunk(Chunk_With_Children* parent,const char* name); + Fragment_Type_Data_Chunk (Chunk_With_Children * const parent,const char *, size_t const); + ~Fragment_Type_Data_Chunk(); + + size_t size_chunk (); + void fill_data_block (char * data_start); + + + char* frag_type_name; + int pad1,pad2,pad3; + +}; + +class Fragment_Type_Shape_Chunk : public Chunk +{ +public: + + Fragment_Type_Shape_Chunk(Chunk_With_Children* parent,const char* _name,int number,ChunkVectorInt _location); + Fragment_Type_Shape_Chunk (Chunk_With_Children * const parent,const char *, size_t const); + ~Fragment_Type_Shape_Chunk(); + + size_t size_chunk (); + void fill_data_block (char * data_start); + + + int num_fragments; + ChunkVectorInt location; + char* name; + + int pad1,pad2,pad3; + +}; +class Fragment_Type_Sound_Chunk : public Chunk +{ +public: + + Fragment_Type_Sound_Chunk(Chunk_With_Children* parent); + Fragment_Type_Sound_Chunk (Chunk_With_Children * const parent,const char *, size_t const); + ~Fragment_Type_Sound_Chunk(); + + size_t size_chunk (); + void fill_data_block (char * data_start); + + char* wav_name; + unsigned long inner_range; + unsigned long outer_range; + int max_volume; + int pitch; + int pad; + +}; + +class Fragment_Type_Chunk : public Chunk_With_Children +{ +public : + Fragment_Type_Chunk(Chunk_With_Children * parent,const char* name) + : Chunk_With_Children (parent, "FRAGTYPE") + {new Fragment_Type_Data_Chunk(this,name);} + + Fragment_Type_Chunk (Chunk_With_Children * const parent,const char *, size_t const); + + const char* get_name(); + +}; + + + + + + +#endif \ No newline at end of file diff --git a/3dc/win95/hierchnk.cpp b/3dc/win95/hierchnk.cpp new file mode 100644 index 0000000..5b26379 --- /dev/null +++ b/3dc/win95/hierchnk.cpp @@ -0,0 +1,609 @@ +#include "hierchnk.hpp" +#include "obchunk.hpp" +//#include "animobs.hpp" + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(hierchnk) + +/////////////Object_Hierarchy_Chunk//////////////////// +RIF_IMPLEMENT_DYNCREATE("OBJCHIER",Object_Hierarchy_Chunk) + +//loader for Object_Hierarchy_Chunk +CHUNK_WITH_CHILDREN_LOADER("OBJCHIER",Object_Hierarchy_Chunk) + +/* +children for Object_Hierarchy_Chunk: + +"OBJCHIER" Object_Hierarchy_Chunk) +"OBJHIERD" Object_Hierarchy_Data_Chunk) +"OBHIERNM" Object_Hierarchy_Name_Chunk) +"HIERBBOX" Hierarchy_Bounding_Box_Chunk) +"OBANSEQS" Object_Animation_Sequences_Chunk) +"OBANALLS" Object_Animation_All_Sequence_Chunk) + +*/ + +List Object_Hierarchy_Chunk::list_h_children() +{ + List cl; + lookup_child ("OBJCHIER",cl); + List h_l; + + for (LIF cli(&cl); !cli.done(); cli.next()) + { + h_l.add_entry((Object_Hierarchy_Chunk *)cli()); + } + return(h_l); + +} + +Object_Hierarchy_Data_Chunk * Object_Hierarchy_Chunk::get_data () +{ + return((Object_Hierarchy_Data_Chunk *)lookup_single_child ("OBJHIERD")); + +} + +Object_Hierarchy_Name_Chunk * Object_Hierarchy_Chunk::get_name () +{ + return((Object_Hierarchy_Name_Chunk *)lookup_single_child ("OBHIERNM")); +} +////////////////////////////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("OBJHIERD",Object_Hierarchy_Data_Chunk) + +Object_Hierarchy_Data_Chunk::Object_Hierarchy_Data_Chunk (Object_Hierarchy_Chunk * parent, const char * obname) +: Chunk (parent, "OBJHIERD"), ob_name (0), object(0) +{ + num_extra_data=0; + extra_data=0; + + if (obname) + { + ob_name = new char [strlen(obname)+1]; + strcpy (ob_name, obname); + + Chunk_With_Children * root = GetRootChunk(); + + List oblist; + root->lookup_child ("RBOBJECT",oblist); + + for (LIF oli(&oblist); !oli.done(); oli.next()) + { + Object_Chunk * ob = (Object_Chunk *)oli(); + + if (!strcmp (ob->object_data.o_name, ob_name)) + { + *((Object_Chunk **)&object) = ob; + break; + } + } + } + +} + +Object_Hierarchy_Data_Chunk::~Object_Hierarchy_Data_Chunk() +{ + if (ob_name) + delete [] ob_name; + + if(extra_data) + delete extra_data; +} + + +size_t Object_Hierarchy_Data_Chunk::size_chunk () +{ + if (ob_name) + { + chunk_size = 12 + 4+4*num_extra_data + strlen(ob_name) + 4 - strlen(ob_name)%4; + } + else + { + chunk_size = 12 + 4+4*num_extra_data + 4; + } + return chunk_size; +} + + +void Object_Hierarchy_Data_Chunk::fill_data_block (char *data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *(int*) data_start=num_extra_data; + data_start+=4; + + for (int i=0; i oblist; + root->lookup_child ("RBOBJECT",oblist); + + for (LIF oli(&oblist); !oli.done(); oli.next()) + { + Object_Chunk * ob = (Object_Chunk *)oli(); + + if (!strcmp (ob->object_data.o_name, ob_name)) + { + *((Object_Chunk **)&object) = ob; + break; + } + } +} +////////////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("OBHIERNM",Object_Hierarchy_Name_Chunk) + +Object_Hierarchy_Name_Chunk::Object_Hierarchy_Name_Chunk (Object_Hierarchy_Chunk * parent, const char * hname) +: Chunk (parent, "OBHIERNM") +{ + if (hname) + { + hierarchy_name = new char [strlen(hname)+1]; + strcpy (hierarchy_name, hname); + } + else + { + hierarchy_name = new char [1]; + *hierarchy_name = 0; + } +} + +Object_Hierarchy_Name_Chunk::~Object_Hierarchy_Name_Chunk() +{ + if (hierarchy_name) + { + delete [] hierarchy_name; + } +} + +void Object_Hierarchy_Name_Chunk::fill_data_block (char *data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + strcpy (data_start, hierarchy_name); + +} + +Object_Hierarchy_Name_Chunk::Object_Hierarchy_Name_Chunk (Chunk_With_Children * parent, const char * data, size_t /*ssize*/) +: Chunk (parent, "OBHIERNM") +{ + hierarchy_name = new char [strlen(data)+1]; + strcpy (hierarchy_name, data); +} + + +/////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("OBHALTSH",Object_Hierarchy_Alternate_Shape_Set_Chunk) + +Object_Hierarchy_Alternate_Shape_Set_Chunk::Object_Hierarchy_Alternate_Shape_Set_Chunk(Chunk_With_Children* parent,int num,const char* name) +:Chunk(parent,"OBHALTSH") +{ + Shape_Set_Name=new char[strlen(name)+1]; + Shape_Set_Num=num; + strcpy(Shape_Set_Name,name); + flags=0; + spare[0]=spare[1]=spare[2]=0; +} +Object_Hierarchy_Alternate_Shape_Set_Chunk::Object_Hierarchy_Alternate_Shape_Set_Chunk(Chunk_With_Children* parent,const char* name) +:Chunk(parent,"OBHALTSH") +{ + Shape_Set_Name=new char[strlen(name)+1]; + strcpy(Shape_Set_Name,name); + flags=0; + spare[0]=spare[1]=spare[2]=0; + Shape_Set_Num=-1; + + //find next available shape set number + List chlist; + parent->lookup_child("OBHALTSH",chlist); + int num=0; + for(LIF chlif(&chlist);!chlif.done();) + { + Object_Hierarchy_Alternate_Shape_Set_Chunk* ohassc=(Object_Hierarchy_Alternate_Shape_Set_Chunk*) chlif(); + if(ohassc->Shape_Set_Num==num) + { + num++; + chlif.restart(); + } + else + { + chlif.next(); + } + } + + Shape_Set_Num=num; + +} + +Object_Hierarchy_Alternate_Shape_Set_Chunk::Object_Hierarchy_Alternate_Shape_Set_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk(parent,"OBHALTSH") +{ + + Shape_Set_Num=*(int*)data; + data+=4; + + int name_length=strlen(data)+1; + Shape_Set_Name=new char[name_length]; + strcpy(Shape_Set_Name,data); + data+=(name_length+3)&~3; + + int num_shapes=*(int*)data; + data+=4; + + for(int i=0;iold_object_name=new char[name_length]; + strcpy(rsd->old_object_name,data); + data+=(name_length+3)&~3; + + name_length=strlen(data)+1; + rsd->new_object_name=new char[name_length]; + strcpy(rsd->new_object_name,data); + data+=(name_length+3)&~3; + + Replaced_Shape_List.add_entry(rsd); + } + + flags=*(int*)data; + data+=4; + + for(i=0;i<3;i++) + { + spare[i]=*(int*)data; + data+=4; + } + +} + +Object_Hierarchy_Alternate_Shape_Set_Chunk::~Object_Hierarchy_Alternate_Shape_Set_Chunk() +{ + if(Shape_Set_Name) delete Shape_Set_Name; + + while(Replaced_Shape_List.size()) + { + delete Replaced_Shape_List.first_entry(); + Replaced_Shape_List.delete_first_entry(); + } + +} + +void Object_Hierarchy_Alternate_Shape_Set_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + + data_start += 8; + + *((int *) data_start) = chunk_size; + + data_start += 4; + + *(int*)data_start=Shape_Set_Num; + data_start+=4; + + strcpy(data_start,Shape_Set_Name); + data_start+=(strlen(Shape_Set_Name)+4)&~3; + + *(int*)data_start=Replaced_Shape_List.size(); + data_start+=4; + + for(LIF rlif(&Replaced_Shape_List);!rlif.done();rlif.next()) + { + strcpy(data_start,rlif()->old_object_name); + data_start+=(strlen(rlif()->old_object_name)+4)&~3; + + strcpy(data_start,rlif()->new_object_name); + data_start+=(strlen(rlif()->new_object_name)+4)&~3; + } + + *(int*)data_start=flags; + data_start+=4; + + for(int i=0;i<3;i++) + { + *(int*)data_start=spare[i]; + data_start+=4; + } + +} + +size_t Object_Hierarchy_Alternate_Shape_Set_Chunk::size_chunk() +{ + chunk_size=36; + chunk_size+=(strlen(Shape_Set_Name)+4)&~3; + for(LIF rlif(&Replaced_Shape_List);!rlif.done();rlif.next()) + { + chunk_size+=(strlen(rlif()->old_object_name)+4)&~3; + chunk_size+=(strlen(rlif()->new_object_name)+4)&~3; + } + return chunk_size; + +} + + +/////////////////////////////////////////////////// +RIF_IMPLEMENT_DYNCREATE("HSETCOLL",Hierarchy_Shape_Set_Collection_Chunk) + +Hierarchy_Shape_Set_Collection_Chunk::Hierarchy_Shape_Set_Collection_Chunk(Chunk_With_Children* parent,int num,const char* name) +:Chunk(parent,"HSETCOLL") +{ + Set_Collection_Name=new char[strlen(name)+1]; + Set_Collection_Num=num; + strcpy(Set_Collection_Name,name); + TypeIndex=flags=0; +} + + +Hierarchy_Shape_Set_Collection_Chunk::Hierarchy_Shape_Set_Collection_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk(parent,"HSETCOLL") +{ + + Set_Collection_Num=*(int*)data; + data+=4; + + int name_length=strlen(data)+1; + Set_Collection_Name=new char[name_length]; + strcpy(Set_Collection_Name,data); + data+=(name_length+3)&~3; + + int list_length=*(int*)data; + data+=4; + + for(int i=0;i slif(&Index_List);!slif.done();slif.next()) + { + *(int*)data_start=slif(); + data_start+=4; + } + + *(int*)data_start=TypeIndex; + data_start+=4; + *(int*)data_start=flags; + data_start+=4; + +} + +size_t Hierarchy_Shape_Set_Collection_Chunk::size_chunk() +{ + chunk_size=12+16; + chunk_size+=(strlen(Set_Collection_Name)+4)&~3; + chunk_size+=Index_List.size()*4; + return chunk_size; + +} + +/////////////////////////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("HIDEGDIS",Hierarchy_Degradation_Distance_Chunk) + +Hierarchy_Degradation_Distance_Chunk::Hierarchy_Degradation_Distance_Chunk(Chunk_With_Children* parent,int _num_detail_levels) +:Chunk(parent,"HIDEGDIS") +{ + num_detail_levels=_num_detail_levels; + if(num_detail_levels) + { + distance_array=new int[num_detail_levels]; + } + else + { + distance_array=0; + } + //fill in some arbitrary distance values + for(int i=0;i list_h_children(); + + Object_Hierarchy_Data_Chunk * get_data (); + Object_Hierarchy_Name_Chunk * get_name (); + + +#ifdef MAXEXPORT + INode* node; +#endif + + +}; + +class Object_Hierarchy_Data_Chunk : public Chunk +{ +public: + + Object_Hierarchy_Data_Chunk (Object_Hierarchy_Chunk * parent, const char * obname); + Object_Hierarchy_Data_Chunk (Chunk_With_Children * parent, const char * sdata, size_t /*ssize*/); + + ~Object_Hierarchy_Data_Chunk (); + + int num_extra_data; + int* extra_data; + + Object_Chunk * const object; + + virtual size_t size_chunk (); + + virtual void fill_data_block (char * data_start); + + virtual void post_input_processing(); + + void find_object_for_this_section(); //find the object_chunk from the name + + char * ob_name; + +private: + + friend class Object_Hierarchy_Chunk; + + +}; + + +// This chunk will normally go in the root as a way of identifiying the hierarchy +class Object_Hierarchy_Name_Chunk : public Chunk +{ +public: + + Object_Hierarchy_Name_Chunk (Object_Hierarchy_Chunk * parent, const char * hname); + Object_Hierarchy_Name_Chunk (Chunk_With_Children * parent, const char * sdata, size_t /*ssize*/); + ~Object_Hierarchy_Name_Chunk(); + + char * hierarchy_name; + + virtual size_t size_chunk () + { + return(chunk_size = 12 + strlen (hierarchy_name) + 4 - strlen (hierarchy_name)%4); + } + + virtual void fill_data_block (char * data_start); + +private: + + friend class Object_Hierarchy_Chunk; + + +}; + + +struct Replaced_Shape_Details +{ + ~Replaced_Shape_Details() + { + if(old_object_name) delete old_object_name; + if(new_object_name) delete new_object_name; + } + + //object name of shape to be replaced + char* old_object_name; + //object that replaces it. + char* new_object_name; +}; + + +#define Avp_ShapeSet_Flag_Female 0x00000001 + +#define List_Object_Hierarchy_Alternate_Shape_Set_Chunk(parent,list) (parent)->lookup_child("OBHALTSH",list) +class Object_Hierarchy_Alternate_Shape_Set_Chunk : public Chunk +{ +public : + Object_Hierarchy_Alternate_Shape_Set_Chunk(Chunk_With_Children* parent,int num,const char* name); + Object_Hierarchy_Alternate_Shape_Set_Chunk(Chunk_With_Children* parent,const char* name); + Object_Hierarchy_Alternate_Shape_Set_Chunk (Chunk_With_Children * parent, const char * data, size_t /*ssize*/); + ~Object_Hierarchy_Alternate_Shape_Set_Chunk(); + + virtual size_t size_chunk(); + + virtual void fill_data_block (char * data_start); + + char* Shape_Set_Name; + int Shape_Set_Num; + + List Replaced_Shape_List; + + int flags; + int spare[3]; + +private: + + +}; + + +#define AvP_HColl_Flag_NotRandom 0x00000001 + +#define List_Hierarchy_Shape_Set_Collection_Chunk(parent,list) (parent)->lookup_child("HSETCOLL",list) +//this chunk hold a list of indeces for shape_set_chunks that should be applied +class Hierarchy_Shape_Set_Collection_Chunk : public Chunk +{ +public : + Hierarchy_Shape_Set_Collection_Chunk(Chunk_With_Children* parent,int num,const char* name); + Hierarchy_Shape_Set_Collection_Chunk (Chunk_With_Children * parent, const char * data, size_t /*ssize*/); + ~Hierarchy_Shape_Set_Collection_Chunk(); + + virtual size_t size_chunk(); + + virtual void fill_data_block (char * data_start); + + char* Set_Collection_Name; + int Set_Collection_Num; + + List Index_List; + + int TypeIndex; + int flags; +}; + +class Hierarchy_Degradation_Distance_Chunk : public Chunk +{ +public : + Hierarchy_Degradation_Distance_Chunk(Chunk_With_Children * parent, const char * data, size_t /*ssize*/); + Hierarchy_Degradation_Distance_Chunk(Chunk_With_Children* parent,int _num_detail_levels); + ~Hierarchy_Degradation_Distance_Chunk(); + + virtual size_t size_chunk(); + + virtual void fill_data_block (char * data_start); + + int num_detail_levels; + int* distance_array; + + +private: +}; + +class Hierarchy_Bounding_Box_Chunk :public Chunk +{ +public : + Hierarchy_Bounding_Box_Chunk(Chunk_With_Children * parent,const char*data,size_t datasize); + + Hierarchy_Bounding_Box_Chunk(Chunk_With_Children * parent) + :Chunk(parent,"HIERBBOX") + {} + + virtual void fill_data_block (char * data_start); + + virtual size_t size_chunk() + {return chunk_size=12+6*4;} + + ChunkVectorInt min; + ChunkVectorInt max; +}; +#endif \ No newline at end of file diff --git a/3dc/win95/huffman.cpp b/3dc/win95/huffman.cpp new file mode 100644 index 0000000..b2a0275 --- /dev/null +++ b/3dc/win95/huffman.cpp @@ -0,0 +1,520 @@ +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "malloc.h" +#include "huffman.hpp" + +/* KJL 17:12:25 17/09/98 - Huffman compression/decompression routines */ + +typedef struct +{ + int Symbol; + unsigned int Count; +} HuffItem; + +typedef struct HuffNode // 16-byte node structure +{ + union + { // the FIRST four bytes + struct HuffNode *zero; // points to the "zero" branch or... + unsigned int value; // holds the value of an end node + }; + + union + { // the SECOND four bytes + struct HuffNode *one; // points to the "one" branch or... + struct HuffNode *link; // points to next end node in list + }; + + struct HuffNode *parent; // the THIRD four bytes, parent node + + union + { // the FOURTH four bytes + unsigned int bits; // the bit pattern of this end node + struct + { + unsigned char flag; + unsigned char curdepth; + unsigned char maxdepth; + unsigned char unused; + }; + }; + +} HuffNode; + +typedef struct +{ + long wid; + long bits; + +} HuffEncode; + +static HuffItem SymbolCensus[257]; +static HuffNode TreeNodes[2*257]; +static int Depths[MAX_DEPTH+1]; +static HuffEncode EncodingTable[257]; + +#define AllocateMemory malloc + + +/* KJL 17:16:03 17/09/98 - Compression */ +static void PerformSymbolCensus(unsigned char *sourcePtr, int length); +#ifdef __WATCOMC__ +static int HuffItemsSortSub(const void *cmp1, const void *cmp2); +#else +static int __cdecl HuffItemsSortSub(const void *cmp1, const void *cmp2); +#endif +static void SortCensusData(void); +static void BuildHuffmanTree(void); +static void MakeHuffTreeFromHuffItems(HuffNode *base, HuffItem *source, int count); +static void MakeCodeLengthsFromHuffTree(int *dest, HuffNode *source, int maxdepth); +static int HuffDepthsAdjust(int *depth, int maxdepth); +static void MakeHuffmanEncodeTable(HuffEncode *encodetable, HuffItem *item, int *depths); +static int HuffEncodeBytes(int *dest, unsigned char *source, int count, HuffEncode *table); + + +extern HuffmanPackage *HuffmanCompression(unsigned char *sourcePtr, int length) +{ + HuffmanPackage *outpackage; + + + // Step 1: Perform the symbol census + PerformSymbolCensus(sourcePtr,length); + // Step 2: Sorting the census data + SortCensusData(); + // Step 3: Building the Huffman tree + BuildHuffmanTree(); + // Step 4: Making the code lengths table + MakeCodeLengthsFromHuffTree(Depths, TreeNodes, MAX_DEPTH); + // Step 5: Limiting code lengths + HuffDepthsAdjust(Depths, MAX_DEPTH); + // Step 6: Making the encoding table + MakeHuffmanEncodeTable(EncodingTable,&SymbolCensus[256],Depths); + // Step 7: Encoding data + outpackage = (HuffmanPackage*)AllocateMemory(sizeof(HuffmanPackage)+length); + strncpy(outpackage->Identifier,COMPRESSED_RIF_IDENTIFIER,8); + outpackage->CompressedDataSize = HuffEncodeBytes((int*)(outpackage+1), sourcePtr, length, EncodingTable); + outpackage->UncompressedDataSize = length; + for (int n = 0; n < MAX_DEPTH; n++) + { + outpackage->CodelengthCount[n] = Depths[n + 1]; + } + for (n = 0; n < 256; n++) + { + outpackage->ByteAssignment[n] = SymbolCensus[n + 1].Symbol; + } + return outpackage; +} + +static void PerformSymbolCensus(unsigned char *sourcePtr, int length) +{ + // init array + for (int i=0; i<257; i++) + { + SymbolCensus[i].Symbol = i; + SymbolCensus[i].Count = 0; + } + + // count 'em + do + { + SymbolCensus[*sourcePtr++].Count++; + } + while (--length); +} + +#ifdef __WATCOMC__ +static int HuffItemsSortSub(const void *cmp1, const void *cmp2) +#else +static int __cdecl HuffItemsSortSub(const void *cmp1, const void *cmp2) +#endif +{ + if (((HuffItem *)cmp1)->Count > ((HuffItem *)cmp2)->Count) + return 1; + if (((HuffItem *)cmp1)->Count < ((HuffItem *)cmp2)->Count) + return -1; + return 0; +} +static void SortCensusData(void) +{ + qsort(SymbolCensus, 257, sizeof(HuffItem), HuffItemsSortSub); +} + +static void BuildHuffmanTree(void) +{ + MakeHuffTreeFromHuffItems(TreeNodes,SymbolCensus,257); +} + +static void MakeHuffTreeFromHuffItems(HuffNode *base, HuffItem *source, int count) +{ + HuffNode *movdest, *temp; + int n, upperlim, lowerlim, index; + unsigned int sum; + + if (!count) return; + + movdest = base + 1; + temp = base + count; + memset(temp, 0, count * sizeof(HuffNode)); + for (n = 0; n < count; n++) + { + temp[n].bits = source[n].Count; + } + while (upperlim = --count) + { + if (temp[0].zero) + temp[0].zero->parent = temp[0].one->parent = movdest; + if (temp[1].zero) + temp[1].zero->parent = temp[1].one->parent = movdest + 1; + movdest[0] = *temp++; + movdest[1] = *temp; + sum = movdest[0].bits + movdest[1].bits; + lowerlim = 1; + + while (lowerlim != upperlim) + { + index = (lowerlim + upperlim) >> 1; + if (sum >= temp[index].bits) + { + lowerlim = index + 1; + } + else + { + upperlim = index; + } + } + index = lowerlim - 1; + memmove(temp, temp + 1, index * sizeof(HuffNode)); + temp[index].bits = sum; + temp[index].zero = movdest; + temp[index].one = movdest + 1; + movdest += 2; + } + base[0] = temp[0]; + if (base[0].zero) + base[0].zero->parent = base[0].one->parent = base; +} + +static void MakeCodeLengthsFromHuffTree(int *dest, HuffNode *source, int maxdepth) +{ + int n, depth; + HuffNode *back; + + for (n = 0; n < maxdepth + 1; n++) + dest[n] = 0; + depth = 0; + while (1) + { + while (source->one) + { + source = source->one; + depth++; + } + + if (depth > maxdepth) dest[maxdepth]++; + else dest[depth]++; + + do + { + back = source; + source = source->parent; + if (!depth--) + return; + } + while (back == source->zero); + + source = source->zero; + depth++; + } +} + +static int HuffDepthsAdjust(int *depth, int maxdepth) +{ + unsigned int n, m, items, sum, goal, gain, busts; + unsigned int promotions, excess, hi; + + goal = 1 << maxdepth; + for (n = 0, sum = 0, items = 0; n <= maxdepth; n++) + { + items += depth[n]; + sum += (goal >> n) * depth[n]; + } + if (items > goal) + return -1; // failure + for (n = maxdepth - 1; sum > goal; n--) + { + if (depth[n]) + { + gain = (1 << (maxdepth - n)) - 1; + busts = (sum - goal + gain - 1) / gain; + busts = depth[n] < busts ? depth[n] : busts; + depth[n] -= busts; + depth[maxdepth] += busts; + sum -= busts * gain; + } + } + excess = goal - sum; + for (n = 0; excess; n++) + { + hi = 1 << (maxdepth - n); + for (m = n + 1; m <= maxdepth; m++) + { + gain = hi - (1 << (maxdepth - m)); + if (excess < gain) + break; + if (depth[m]) + { + promotions = excess / gain; + promotions = depth[m] > promotions ? promotions : depth[m]; + depth[n] += promotions; + depth[m] -= promotions; + excess -= promotions * gain; + } + } + } + return 0; // success +} + +static void MakeHuffmanEncodeTable(HuffEncode *encodetable, HuffItem *item, int *depths) +{ + unsigned int d, bitwidth, depthbit, bt, cur; + int *dep; + + dep = depths + 1; // skip depth zero + bitwidth = 0; // start from small bitwidths + cur = 0; // current bit pattern + do + { + do + { + bitwidth++; // go deeper + depthbit = 1 << (bitwidth - 1); // keep depth marker + d = *dep++; // get count here + } + while (!d); // until count non-zero + while (d--) + { // for all on this level + encodetable[item->Symbol].wid = bitwidth; // record width + encodetable[item->Symbol].bits = cur; // record bits + item--; // count backwards an item + bt = depthbit; // bt is a temp value + while (1) + { + cur ^= bt; // do an add modulo 1 + if ((cur & bt) || !bt) // break if now a 1 + break; // or out of bits + bt >>= 1; // do next bit position + } + } + } + while (cur); // until cur exhausted +} + +static int HuffEncodeBytes(int *dest, unsigned char *source, int count, HuffEncode *table) +{ + int *start; + int wid, val, available; + unsigned int accum, bits; + unsigned char *sourcelim, *sourceend; + + if (!count) return 0; + + start = dest; + sourcelim = sourceend = source + count; + available = 32; + if (sourcelim - 32 < sourcelim) + { + sourcelim -= 32; + } + else + { + sourcelim = source; + } + if (source < sourcelim) + { + do + { + goto lpstart; + do + { + accum = (accum >> wid) | (bits << (32 - wid)); +lpstart: val = *source++; + wid = table[val].wid; + bits = table[val].bits; + } + while ((available -= wid) >= 0); + + wid += available; + if (wid) accum = (accum >> wid) | (bits << (32 - wid)); + *dest++ = accum; + wid -= available; + accum = bits << (32 - wid); + available += 32; + } + while (source < sourcelim); + } + while (1) + { + if (source < sourceend) + { + val = *source++; + } + else if (source == sourceend) + { + val = 0x100; // terminator + source++; + } + else break; // done + + wid = table[val].wid; + bits = table[val].bits; + + if ((available -= wid) < 0) + { + wid += available; + if (wid) + accum = (accum >> wid) | (bits << (32 - wid)); + *dest++ = accum; + wid -= available; + accum = bits << (32 - wid); + available += 32; + } + else + { + accum = (accum >> wid) | (bits << (32 - wid)); + } + } + *dest++ = accum >> available; + return (dest - start) * 4; +} + + + + + + +/* KJL 17:16:24 17/09/98 - Decompression */ +static int DecodeTable[1<CodelengthCount, MAX_DEPTH, inpackage->ByteAssignment); + + // Step 2: Decode data + uncompressedData = (unsigned char*)AllocateMemory(inpackage->UncompressedDataSize+16); + if (uncompressedData) + { + HuffmanDecode(uncompressedData,(int*)(inpackage+1),DecodeTable,inpackage->UncompressedDataSize); + } + + return (char*)uncompressedData; +} + +static void MakeHuffmanDecodeTable(int *depth, int depthmax, unsigned char *list) +{ + int thisdepth, depthbit, repcount, repspace, lenbits, temp, count; + int *outp; + int o = 0; + unsigned char *p; + int *outtbl = DecodeTable; + + lenbits = 0; + repcount = 1 << depthmax; + repspace = 1; + thisdepth = 0; + depthbit = 4; + p = (unsigned char *)list + 255; + while (1) + { + do + { + lenbits++; + depthbit <<= 1; + repspace <<= 1; + repcount >>= 1; + } + while (!(thisdepth = *depth++)); + do + { + if (p < list) + { + temp = 0xff; + } + else + { + temp = lenbits | (*p-- << 8); + } + outp = outtbl + (o >> 2); + count = repcount; + do + { + *outp = temp; + outp += repspace; + } + while (--count); + temp = depthbit; + do + { + temp >>= 1; + if (temp & 3) return; + o ^= temp; + } + while (!(o & temp)); + } + while (--thisdepth); + } +} + + +#define EDXMASK ((((1 << (MAX_DEPTH + 1)) - 1) ^ 1) ^ -1) + +static int HuffmanDecode(unsigned char *dest, int *source, int *table, int length) +{ + unsigned char *start; + int available, reserve, fill, wid; + unsigned int bits=0, resbits; + unsigned char *p; + + start = dest; + available = 0; + reserve = 0; + wid = 0; + do + { + available += wid; + fill = 31 - available; + bits <<= fill; + if (fill > reserve) + { + fill -= reserve; + available += reserve; + if (reserve) + { + bits = (bits >> reserve) | (resbits << (32 - reserve)); + } + resbits = *source++; + reserve = 32; + } + bits = (bits >> fill) | (resbits << (32 - fill)); + resbits >>= fill; + reserve -= fill; + available = 31; + goto lpent; + do + { + bits >>= wid; + *dest++ = p[1]; +lpent: p = (unsigned char *)(((short *)table)+(bits & ~EDXMASK)); + } + while ((available -= (wid = *p)) >= 0 && (dest-start)!=length); + + } + while (available > -32 && (dest-start)!=length); + return dest - start; +} diff --git a/3dc/win95/huffman.hpp b/3dc/win95/huffman.hpp new file mode 100644 index 0000000..58faf2a --- /dev/null +++ b/3dc/win95/huffman.hpp @@ -0,0 +1,31 @@ +#ifndef _huffman_hpp_included +#define _huffman_hpp_included 1 + +#ifdef __cplusplus + extern "C" + { +#endif + +#define MAX_DEPTH 11 +typedef struct +{ + char Identifier[8]; + int CompressedDataSize; + int UncompressedDataSize; + int CodelengthCount[MAX_DEPTH]; + unsigned char ByteAssignment[256]; +} HuffmanPackage; + +/* KJL 17:16:03 17/09/98 - Compression */ +extern HuffmanPackage *HuffmanCompression(unsigned char *sourcePtr, int length); + +/* KJL 16:53:53 19/09/98 - Decompression */ +extern char *HuffmanDecompress(HuffmanPackage *inpackage); + + +#define COMPRESSED_RIF_IDENTIFIER "REBCRIF1" +#ifdef __cplusplus + }; +#endif + +#endif \ No newline at end of file diff --git a/3dc/win95/iff.cpp b/3dc/win95/iff.cpp new file mode 100644 index 0000000..fe455db --- /dev/null +++ b/3dc/win95/iff.cpp @@ -0,0 +1,826 @@ +#include "advwin32.h" +#include "iff.hpp" + +#include +#include + +#if defined(_CPPRTTI) && !defined(NDEBUG) + #include +#endif + +#ifndef NDEBUG + #define HT_FAIL(str) (::IFF::DisplayMessage(TEXT("IFF Internal Error"),TEXT(str)),exit(-45)) +#endif + +#include "hash_tem.hpp" + +namespace IFF +{ + /*****************************/ + /* Original File: iffObj.cpp */ + /*****************************/ + + #ifndef NDEBUG + + static bool g_bAllocListActive = false; + + class AllocList : public ::HashTable + { + public: + AllocList() + { + g_bAllocListActive = true; + } + ~AllocList() + { + #ifdef _CPPRTTI // this works in MSVC 5.0 - ie. the macro is defined if RTTI is turned on + // but there appears to be no preprocessor way of determining if RTTI is turned on under Watcom + // No, I think it works in Watcom too, actually... + #pragma message("Run-Time Type Identification (RTTI) is enabled") + for (Iterator itLeak(*this) ; !itLeak.Done() ; itLeak.Next()) + { + TCHAR buf[256]; + ::wsprintf(buf,TEXT("Object not deallocated:\nType: %s\nRefCnt: %u"),typeid(*itLeak.Get()).name(),itLeak.Get()->m_nRefCnt); + DisplayMessage(TEXT("Memory Leak!"),buf); + } + #else // ! _CPPRTTI + unsigned nRefs(0); + for (Iterator itLeak(*this) ; !itLeak.Done() ; itLeak.Next()) + { + nRefs += itLeak.Get()->m_nRefCnt; + } + if (Size()) + { + char buf[256]; + ::sprintf(buf,"Objects not deallocated:\nNumber of Objects: %u\nNumber of References: %u",Size(),nRefs); + DisplayMessage("Memory Leaks!",buf); + } + #endif // ! _CPPRTTI + g_bAllocListActive = false; + } + }; + + static AllocList g_listAllocated; + + void DbRemember(Unknown * pObj) + { + g_listAllocated.AddAsserted(pObj); + } + + void DbForget(Unknown * pObj) + { + if (g_bAllocListActive) + g_listAllocated.RemoveAsserted(pObj); + } + + #endif // ! NDEBUG + + /******************************/ + /* Original File: iffFile.cpp */ + /******************************/ + + bool GenericFile::Load(::MediaMedium * pMedium) + { + ArchvIn ar; + + ar.Open(pMedium); + if (!ar.m_bError) + Serialize(&ar); + ar.Close(); + + return ! ar.m_bError; + } + + #ifndef IFF_READ_ONLY + bool GenericFile::Write(::MediaMedium * pMedium) + { + ArchvOut ar; + + ar.Open(pMedium); + if (!ar.m_bError) + Serialize(&ar); + ar.Close(); + + return ! ar.m_bError; + } + #endif // ! IFF_READ_ONLY + + + #ifdef _IFF_WIN_TARGET + typedef ::MediaWinFileMedium DeviceFileHandle; + #else + typedef ::MediaStdFileMedium DeviceFileHandle; + #endif + + bool GenericFile::Load(TCHAR const * pszFileName) + { + #ifndef IFF_READ_ONLY + if (m_pszFileName) delete[] m_pszFileName; + m_pszFileName = new TCHAR [_tcslen(pszFileName)+1]; + _tcscpy(m_pszFileName,pszFileName); + #endif // ! IFF_READ_ONLY + + #ifdef _IFF_WIN_TARGET + ::MediaWinFileMedium * pMedium = new ::MediaWinFileMedium; + pMedium->Open(pszFileName, GENERIC_READ); + #else + ::MediaStdFileMedium * pMedium = new ::MediaStdFileMedium; + pMedium->Open(pszFileName, "rb"); + #endif + + bool bRet = Load(pMedium); + + pMedium->Release(); + + return bRet; + } + + #ifndef IFF_READ_ONLY + bool GenericFile::Write(TCHAR const * pszFileName) + { + if (pszFileName) + { + if (m_pszFileName) delete[] m_pszFileName; + m_pszFileName = new TCHAR [_tcslen(pszFileName)+1]; + _tcscpy(m_pszFileName,pszFileName); + } + + if (!m_pszFileName) return false; + + #ifdef _IFF_WIN_TARGET + ::MediaWinFileMedium * pMedium = new ::MediaWinFileMedium; + pMedium->Open(pszFileName, GENERIC_WRITE); + #else + ::MediaStdFileMedium * pMedium = new ::MediaStdFileMedium; + pMedium->Open(pszFileName, "wb"); + #endif + + bool bRet = Write(pMedium); + + pMedium->Release(); + + return bRet; + } + #endif // ! IFF_READ_ONLY + + void File::Serialize(Archive * pArchv) + { + if (pArchv->m_bIsLoading) + { + if (m_pContents) + { + m_pContents->Release(); + m_pContents = NULL; + } + + pArchv->Transfer(m_idType); + + if (!!m_idType && (m_idType == ID("FORM") || m_idType == ID("LIST") || m_idType == ID("CAT "))) + { + m_pContents = static_cast(Chunk::Load(ID_ANY,pArchv,m_idType)); + } + else + { + pArchv->m_bError = true; + } + } + else + { + if (m_pContents) + m_pContents->Chunk::Write(pArchv); + else + pArchv->m_bError = true; + } + } + + File::~File() + { + if (m_pContents) + m_pContents->Release(); + } + + /*******************************/ + /* Original File: iffChunk.cpp */ + /*******************************/ + + class RegEntry + { + public: + ID m_idParent; + ID m_idChunk; + Chunk * (* m_pfnCreate) (); + inline bool operator == (RegEntry const & rEntry) const + { + return m_idParent == rEntry.m_idParent && m_idChunk == rEntry.m_idChunk; + } + inline bool operator != (RegEntry const & rEntry) const + { + return ! operator == (rEntry); + } + }; + +} // namespace IFF + +inline unsigned HashFunction(IFF::RegEntry const & rEntry) +{ + return HashFunction(rEntry.m_idChunk.m_nID); +} + +namespace IFF { + + static ::HashTable * g_pRegister = NULL; + + void Chunk::Register(ID idParent, ID idChunk, Chunk * (* pfnCreate) () ) + { + static ::HashTable reg; + + g_pRegister = ® + + RegEntry entry; + entry.m_idParent = idParent; + entry.m_idChunk = idChunk; + entry.m_pfnCreate = pfnCreate; + + reg.AddAsserted(entry); + } + + Chunk * Chunk::DynCreate(ID idParent, ID idChunk) + { + if (g_pRegister) + { + RegEntry test; + test.m_idParent = idParent; + test.m_idChunk = idChunk; + test.m_pfnCreate = NULL; + + RegEntry const * pEntry = g_pRegister->Contains(test); + if (pEntry) + { + return pEntry->m_pfnCreate(); + } + } + return new MiscChunk(idChunk); + } + + void Chunk::Write(Archive * pArchv) + { + Archive * pSubArchv = pArchv->OpenSubArchive(); + + Serialize(pSubArchv); + + UINT32 nSize = pSubArchv->GetSize(); + pArchv->Transfer(m_idCk); + pArchv->Transfer(nSize); + + pArchv->CloseSubArchive(pSubArchv); + + BYTE z = 0; + if (nSize & 1) pArchv->Transfer(z); + } + + Chunk * Chunk::Load(ID idParent, Archive * pArchv, ID idChunk, bool bKnown) + { + if (!idChunk) + pArchv->Transfer(idChunk); + + Chunk * pChunk = bKnown ? DynCreate(idParent, idChunk) : new MiscChunk(idChunk); + + UINT32 nSize; + pArchv->Transfer(nSize); + + Archive * pSubArchv = pArchv->OpenSubArchive(nSize); + pChunk->Serialize(pSubArchv); + pArchv->CloseSubArchive(pSubArchv); + + BYTE z = 0; + if (nSize & 1) pArchv->Transfer(z); + + return pChunk; + } + + Chunk * Chunk::GetProperty(ID idProp) const + { + if (m_pParent && m_pNode) + return m_pParent->GetProperty(m_pNode,idProp); + else + return NULL; + } + + /*******************************/ + /* Original File: iffBlock.cpp */ + /*******************************/ + + Composite::~Composite() + { + DeleteAllChildren(); + } + + ChildNode * Composite::GetFirstChild(ID idMatch) const + { + for (ChildNode * pSrchNode = m_pFirst; pSrchNode; pSrchNode = GetNextChild(pSrchNode)) + { + if (pSrchNode->GetChunk()->m_idCk == idMatch && !pSrchNode->GetChunk()->IsUnknown()) return pSrchNode; + } + return NULL; + } + + ChildNode * Composite::GetLastChild(ID idMatch) const + { + for (ChildNode * pSrchNode = m_pLast; pSrchNode; pSrchNode = GetPrevChild(pSrchNode)) + { + if (pSrchNode->GetChunk()->m_idCk == idMatch && !pSrchNode->GetChunk()->IsUnknown()) return pSrchNode; + } + return NULL; + } + + ChildNode * Composite::GetNextChild(ChildNode const * pNode, ID idMatch) + { + for (ChildNode * pSrchNode = GetNextChild(pNode); pSrchNode; pSrchNode = GetNextChild(pSrchNode)) + { + if (pSrchNode->GetChunk()->m_idCk == idMatch && !pSrchNode->GetChunk()->IsUnknown()) return pSrchNode; + } + return NULL; + } + + ChildNode * Composite::GetPrevChild(ChildNode const * pNode, ID idMatch) + { + for (ChildNode * pSrchNode = GetPrevChild(pNode); pSrchNode; pSrchNode = GetPrevChild(pSrchNode)) + { + if (pSrchNode->GetChunk()->m_idCk == idMatch && !pSrchNode->GetChunk()->IsUnknown()) return pSrchNode; + } + return NULL; + } + + Chunk * Composite::GetProperty(ChildNode const * pNode, ID idProp) const + { + // search backward for ID + + ChildNode * pFindNode = GetPrevChild(pNode, idProp); + + if (pFindNode) return pFindNode->GetChunk(); + + // if not found, search parent backwards, for "PROP ...." then get that + // and if not in the parent, search its parent similarly + // provided all these parents are of type LIST .... + + for (Composite const * pThis = this; pThis->m_pParent && pThis->m_pParent->m_idCk == ID("LIST"); pThis = pThis->m_pParent) + { + if (pThis->m_pNode) + { + for (ChildNode * pFindProp = pThis->m_pParent->GetPrevChild(pThis->m_pNode,"PROP"); pFindProp; pFindProp = pThis->m_pParent->GetPrevChild(pFindProp,"PROP")) + { + Composite * pProp = static_cast(pFindProp->GetChunk()); + if (pProp->m_idData == m_idData) + { + ChildNode * pFindNode = pProp->GetLastChild(idProp); + + if (pFindNode) return pFindNode->GetChunk(); + } + } + + } + } + + return NULL; + } + + void Composite::DeleteChild(ChildNode * pNode) + { + if (pNode->m_pPrev) + pNode->m_pPrev->m_pNext = pNode->m_pNext; + else + m_pFirst = pNode->m_pNext; + + if (pNode->m_pNext) + pNode->m_pNext->m_pPrev = pNode->m_pPrev; + else + m_pLast = pNode->m_pPrev; + + pNode->m_pChunk->m_pParent = NULL; + pNode->m_pChunk->m_pNode = NULL; + pNode->m_pChunk->Release(); + pNode->Release(); + } + + void Composite::DeleteAllChildren() + { + while (m_pFirst) + DeleteChild(m_pFirst); + } + + ChildNode * Composite::InsertChildFirst(Chunk * pChunk) + { + pChunk->AddRef(); + pChunk->m_pParent = this; + + ChildNode * pNode = new ChildNode; + pChunk->m_pNode = pNode; + + pNode->m_pChunk = pChunk; + pNode->m_pPrev = NULL; + pNode->m_pNext = m_pFirst; + + if (m_pFirst) + m_pFirst->m_pPrev = pNode; + + m_pFirst = pNode; + + if (!m_pLast) + m_pLast = m_pFirst; + + return pNode; + } + + ChildNode * Composite::InsertChildLast(Chunk * pChunk) + { + pChunk->m_pParent = this; + pChunk->AddRef(); + + ChildNode * pNode = new ChildNode; + pChunk->m_pNode = pNode; + + pNode->m_pChunk = pChunk; + pNode->m_pNext = NULL; + pNode->m_pPrev = m_pLast; + + if (m_pLast) + m_pLast->m_pNext = pNode; + + m_pLast = pNode; + + if (!m_pFirst) + m_pFirst = m_pLast; + + return pNode; + } + + ChildNode * Composite::InsertChildAfter(ChildNode * pRefNode, Chunk * pChunk) + { + pChunk->m_pParent = this; + pChunk->AddRef(); + + ChildNode * pNode = new ChildNode; + pChunk->m_pNode = pNode; + + pNode->m_pChunk = pChunk; + pNode->m_pNext = pRefNode->m_pNext; + pNode->m_pPrev = pRefNode; + + if (pRefNode->m_pNext) + pRefNode->m_pNext->m_pPrev = pNode; + else + m_pLast = pNode; + + pRefNode->m_pNext = pNode; + + return pNode; + } + + ChildNode * Composite::InsertChildBefore(ChildNode * pRefNode, Chunk * pChunk) + { + pChunk->m_pParent = this; + pChunk->AddRef(); + + ChildNode * pNode = new ChildNode; + pChunk->m_pNode = pNode; + + pNode->m_pChunk = pChunk; + pNode->m_pPrev = pRefNode->m_pPrev; + pNode->m_pNext = pRefNode; + + if (pRefNode->m_pPrev) + pRefNode->m_pPrev->m_pNext = pNode; + else + m_pFirst = pNode; + + pRefNode->m_pPrev = pNode; + + return pNode; + } + + bool Composite::EnumChildren(ID idData, ID idChunk, bool (* pfnCallback) (Chunk *, void *), void * pData) const + { + if (m_idData != idData) return true; + + for (ChildNode * pNode = GetFirstChild(idChunk); pNode; pNode = GetNextChild(pNode,idChunk)) + { + if (!pfnCallback(pNode->GetChunk(),pData)) return false; + } + + return true; + } + + bool Composite::IsValidChildID(ID) const + { + return true; + } + + Chunk * Composite::LoadChunk(Archive * pArchv) const + { + ID idChunk; + pArchv->Transfer(idChunk); + + return Chunk::Load(m_idData, pArchv, idChunk, IsValidChildID(idChunk)); + } + + void Composite::Serialize(Archive * pArchv) + { + pArchv->Transfer(m_idData); + + if (pArchv->m_bIsLoading) + { + DeleteAllChildren(); + + while (pArchv->GetSize()) + { + Chunk * pChunk = LoadChunk(pArchv); + InsertChildLast(pChunk); + pChunk->Release(); + } + } + else + { + for (ChildNode * pNode = m_pFirst; pNode; pNode = GetNextChild(pNode)) + { + pNode->GetChunk()->Write(pArchv); + } + } + } + + bool Form::IsValidChildID(ID id) const + { + // contents: FORM | LIST | CAT | LocalChunk + return ID("PROP") != id; + } + + bool Cat::EnumChildren(ID idData, ID idChunk, bool (* pfnCallback) (Chunk *, void *), void * pData) const + { + for (ChildNode * pNode = GetFirstChild(); pNode; pNode = GetNextChild(pNode)) + { + Composite const * pComposite = static_cast(pNode->GetChunk()); + if (pComposite->m_idData == idData && !pComposite->EnumChildren(idData,idChunk,pfnCallback,pData)) return false; + } + + return true; + } + + bool Cat::IsValidChildID(ID id) const + { + // contentes: FROM | LIST | CAT + return ID("FORM") == id || ID("LIST") == id || ID("CAT ") == id; + } + + bool List::EnumChildren(ID idData, ID idChunk, bool (* pfnCallback) (Chunk *, void *), void * pData) const + { + for (ChildNode * pNode = GetFirstChild(); pNode; pNode = GetNextChild(pNode)) + { + Composite const * pComposite = static_cast(pNode->GetChunk()); + if (pComposite->m_idData == idData && !pComposite->EnumChildren(idData,idChunk,pfnCallback,pData)) return false; + } + + return true; + } + + bool List::IsValidChildID(ID id) const + { + // contentes: FROM | LIST | CAT | PROP + return ID("FORM") == id || ID("LIST") == id || ID("CAT ") == id || ID("PROP") == id; + } + + bool Prop::IsValidChildID(ID id) const + { + // contentes: LocalChunk + return ID("FORM") != id && ID("LIST") != id && ID("CAT ") != id && ID("PROP") != id; + } + + IFF_IMPLEMENT_DYNCREATE(ID_ANY,"FORM",Form) + IFF_IMPLEMENT_DYNCREATE(ID_ANY,"LIST",List) + IFF_IMPLEMENT_DYNCREATE(ID_ANY,"CAT ",Cat) + IFF_IMPLEMENT_DYNCREATE(ID_ANY,"PROP",Prop) + + /*******************************/ + /* Original File: iffMscCk.cpp */ + /*******************************/ + + #ifdef IFF_READ_ONLY + + void MiscChunk::Serialize(Archive * ){} + + #else // ! IFF_READ_ONLY + + void MiscChunk::Serialize(Archive * pArchv) + { + if (pArchv->m_bIsLoading) + { + if (m_pData) + delete[] m_pData; + m_nSize = pArchv->GetSize(); + m_pData = new BYTE [m_nSize]; + } + + pArchv->TransferBlock(m_pData,m_nSize); + } + + MiscChunk::~MiscChunk() + { + if (m_pData) + delete[] m_pData; + } + + /*******************************/ + /* Original File: iffSData.cpp */ + /*******************************/ + + DataBlock::~DataBlock() + { + delete[] m_pBlock; + } + + inline bool DataBlock::WriteToFile(::MediaMedium * pMedium) const + { + pMedium->WriteBlock(m_pBlock,m_nCurSize); + return pMedium->m_fError ? false : true; + } + + void DataBlock::Expand(unsigned nMinSize) + { + while (m_nMaxSize < nMinSize) + m_nMaxSize*=2; + + UBYTE * pNewBlock = new UBYTE [m_nMaxSize]; + memcpy(pNewBlock,m_pBlock,m_nCurSize); + delete[] m_pBlock; + m_pBlock = pNewBlock; + } + + DataNode::~DataNode() + { + if (m_pPrev) + m_pPrev->Release(); + if (m_pData) + m_pData->Release(); + if (m_pNext) + m_pNext->Release(); + } + + unsigned DataNode::GetDataSize() const + { + return + (m_pPrev ? m_pPrev->GetDataSize() : 0) + + (m_pData ? m_pData->GetDataSize() : 0) + + (m_pNext ? m_pNext->GetDataSize() : 0) + ; + } + + bool DataNode::WriteToFile(::MediaMedium * pMedium) const + { + return + (m_pPrev ? m_pPrev->WriteToFile(pMedium) : true) + && (m_pData ? m_pData->WriteToFile(pMedium) : true) + && (m_pNext ? m_pNext->WriteToFile(pMedium) : true) + ; + } + + SerialData::~SerialData() + { + m_pData->Release(); + if (m_pPrev) + m_pPrev->Release(); + } + + void SerialData::Clear() + { + m_pData->Release(); + if (m_pPrev) + m_pPrev->Release(); + m_pData = new DataBlock; + m_pPrev = NULL; + } + + unsigned SerialData::GetDataSize() const + { + return + (m_pPrev ? m_pPrev->GetDataSize() : 0) + + m_pData->GetDataSize() + ; + } + + bool SerialData::WriteToFile(::MediaMedium * pMedium) const + { + return + (m_pPrev ? m_pPrev->WriteToFile(pMedium) : true) + && m_pData->WriteToFile(pMedium) + ; + } + + /*******************************/ + /* Original File: iffArchO.cpp */ + /*******************************/ + + void ArchvOut::Open(::MediaMedium * pMedium) + { + if (m_pMedium) m_pMedium->Release(); + + m_pMedium = pMedium; + m_pMedium->AddRef(); + + if (m_pMedium->m_fError) + { + m_bError = true; + m_pMedium->Release(); + m_pMedium = NULL; + } + } + + void ArchvOut::Close() + { + if (m_pMedium) + { + if (!WriteToFile(m_pMedium)) + m_bError = true; + m_pMedium->Release(); + m_pMedium = NULL; + } + } + + ArchvOut::~ArchvOut() + { + Close(); + } + + Archive * ArchvOut::OpenSubArchive(unsigned) + { + return new ArchvOut; + } + + void ArchvOut::CloseSubArchive(Archive * pSub) + { + m_bError = m_bError || pSub->m_bError; + Append(static_cast(pSub)); + pSub->Release(); + } + + #endif // IFF_READ_ONLY + + /*******************************/ + /* Original File: iffArchI.cpp */ + /*******************************/ + + void ArchvIn::Open(::MediaMedium * pMedium) + { + if (m_pMedium) m_pMedium->Release(); + + m_pMedium = pMedium; + m_pMedium->AddRef(); + + if (m_pMedium->m_fError) + { + m_bError = true; + m_pMedium->Release(); + m_pMedium = NULL; + } + else + { + m_nEndPos = m_pMedium->GetRemainingSize(); + m_nBytesRemaining = m_nEndPos; + } + } + + void ArchvIn::Close() + { + if (m_pMedium) + { + m_pMedium->SetPos(m_nEndPos); + m_pMedium->Release(); + m_pMedium = NULL; + } + } + + inline ArchvIn::ArchvIn(ArchvIn * pParent, unsigned nSize) + : _IFF_ARCHI_FLAG(true) + , m_pMedium(pParent->m_pMedium) + , m_nBytesRemaining(nSize) + { + m_nEndPos = pParent->m_pMedium->GetPos(); + m_nEndPos += nSize; + pParent->m_nBytesRemaining -= nSize; + m_pMedium->AddRef(); + } + + ArchvIn::~ArchvIn() + { + Close(); + } + + Archive * ArchvIn::OpenSubArchive(unsigned nSize) + { + return new ArchvIn(this,nSize); + } + + void ArchvIn::CloseSubArchive(Archive * pSub) + { + m_bError = m_bError || pSub->m_bError; + pSub->Release(); + } + +} // namespace IFF \ No newline at end of file diff --git a/3dc/win95/iff.hpp b/3dc/win95/iff.hpp new file mode 100644 index 0000000..9250171 --- /dev/null +++ b/3dc/win95/iff.hpp @@ -0,0 +1,991 @@ +#ifndef _INCLUDED_IFF_HPP_ +#define _INCLUDED_IFF_HPP_ + +#if defined(_WIN32) || defined(WIN32) || defined(WINDOWS) || defined(_WINDOWS) + #define _IFF_WIN_TARGET + #include +#else // ! WIN32 && ! _WIN32 && ! WINDOWS && ! _WINDOWS + #include + #include +#endif // ! WIN32 && ! _WIN32 && ! WINDOWS && ! _WINDOWS + +#include "media.hpp" + +namespace IFF +{ + /*************************/ + /* Class Hierarchy: */ + /* */ + /* + Unknown */ + /* + SerializableObj */ + /* + GenericFile */ + /* + File */ + /* + Chunk */ + /* + Composite */ + /* + Form */ + /* + Cat */ + /* + List */ + /* + Prop */ + /* + MiscChunk */ + /* + */ + /* + Arvhive */ + /* + ArchvIn */ + /* + ArchvOut(*) */ + /* + DataBlock */ + /* + DataNode */ + /* + SerialData */ + /* + ArchvOut(*) */ + /* + ChildNode */ + /* + DeviceHandle */ + /*************************/ + + #ifdef _IFF_WIN_TARGET + inline void DisplayMessage(TCHAR const * pszTitle,TCHAR const * pszText) + { + ::MessageBox(NULL,pszText,pszTitle,MB_OK|MB_ICONEXCLAMATION|MB_SETFOREGROUND); + } + #else + inline void DisplayMessage(char const * pszTitle,char const * pszText) + { + ::printf("%s\n%s\n",pszTitle,pszText); + while (::kbhit()) + ::getch(); + while (!::kbhit() || '\r' != ::getch()) + ; + } + #endif + + // forward refs + //class Unknown; + //class SerializableObj; + //class GenericFile; + //class File; + //class Chunk; + class Composite; + //class Form; + //class Cat; + //class List; + //class Prop; + //class MiscChunk; + //class Archive; + //class ArchvIn; + //class ArchvOut; + //class DataBlock; + //class DataNode; + //class SerialData; + class ChildNode; + //class DeviceHandle; + + /*****************************/ + /* Original File: iffObj.hpp */ + /*****************************/ + + class Unknown + { + public: + unsigned AddRef() { return ++m_nRefCnt; } + unsigned Release() { if (0==(--m_nRefCnt)) { delete this; return 0;} else return m_nRefCnt; } + protected: + virtual ~Unknown() { + #ifndef NDEBUG + DbForget(this); + #endif + } + Unknown() : m_nRefCnt(1) { + #ifndef NDEBUG + DbRemember(this); + #endif + } + Unknown(Unknown const &) : m_nRefCnt(1) { + #ifndef NDEBUG + DbRemember(this); + #endif + } + private: + unsigned m_nRefCnt; + + #ifndef NDEBUG + friend void DbRemember(Unknown * pObj); + friend void DbForget(Unknown * pObj); + friend class AllocList; + #endif + }; + + /*******************************/ + /* Original File: iffTypes.hpp */ + /*******************************/ + + // deal with any silly bastard who's put #define BYTE ... in a header, etc. + #ifdef BYTE + #undef BYTE + #pragma message("BYTE was defined - undefining") + #endif + typedef signed char BYTE; + typedef unsigned char UBYTE; + + typedef signed short INT16; + typedef unsigned short UINT16; + + typedef signed INT32; + typedef unsigned UINT32; + + typedef signed __int64 INT64; + typedef unsigned __int64 UINT64; + + struct RGBTriple + { + UBYTE r; + UBYTE g; + UBYTE b; + }; + + union ID + { + UINT32 m_nID; + char m_sID[4]; + + inline ID(){} + inline ID(char const * pszID) { m_nID = *reinterpret_cast(pszID); } + inline ID(UINT32 nID) : m_nID(nID) {} + inline operator UINT32 () const { return m_nID; } + inline operator char const * () const { return &m_sID[0]; } + inline bool operator == (ID const & rId) const { return !m_nID || !rId.m_nID || m_nID == rId.m_nID; } + inline bool operator != (ID const & rId) const { return ! operator == (rId); } + inline bool operator ! () const { return !m_nID; } + }; + + ID const ID_ANY(0U); + + #ifndef IFF_READ_ONLY + + /*******************************/ + /* Original File: iffSData.hpp */ + /*******************************/ + + class DataBlock : public Unknown + { + public: + virtual ~DataBlock(); + DataBlock() : m_pBlock(new UBYTE [128]), m_nMaxSize(128), m_nCurSize(0) {} + + unsigned GetDataSize() const; + UBYTE const * GetDataPtr() const; + + bool WriteToFile(::MediaMedium * pMedium) const; + + void Append(UBYTE byte); + void Append(void const * pData, unsigned nSize); + + private: + void Expand(unsigned nMinSize); + + UBYTE * m_pBlock; + unsigned m_nMaxSize; + unsigned m_nCurSize; + }; + + inline unsigned DataBlock::GetDataSize() const + { + return m_nCurSize; + } + + inline UBYTE const * DataBlock::GetDataPtr() const + { + return m_pBlock; + } + + inline void DataBlock::Append(UBYTE byte) + { + if (m_nCurSize >= m_nMaxSize) + Expand(m_nCurSize+1); + + m_pBlock[m_nCurSize++] = byte; + } + + inline void DataBlock::Append(void const * pData, unsigned nSize) + { + if (m_nCurSize+nSize > m_nMaxSize) + Expand(m_nCurSize+nSize+32); + + memcpy(&m_pBlock[m_nCurSize],pData,nSize); + + m_nCurSize += nSize; + } + + class DataNode : public Unknown + { + public: + DataNode(DataNode * pNext, DataBlock * pData, DataNode * pPrev) + : m_pNext(pNext) + , m_pData(pData) + , m_pPrev(pPrev) + { + if (pNext) pNext->AddRef(); + if (pData) pData->AddRef(); + if (pPrev) pPrev->AddRef(); + } + virtual ~DataNode(); + + unsigned GetDataSize() const; + + bool WriteToFile(::MediaMedium * pMedium) const; + + private: + DataNode * m_pNext; + DataBlock * m_pData; + DataNode * m_pPrev; + }; + + class SerialData : public Unknown + { + public: + virtual ~SerialData(); + SerialData() : m_pPrev(NULL), m_pData(new DataBlock) {}; + + void Clear(); + + unsigned GetDataSize() const; + + bool WriteToFile(::MediaMedium * pMedium) const; + + void Append(UBYTE byte); + void Append(void const * pData, unsigned nSize); + + void Append(SerialData * pData); + + private: + DataBlock * m_pData; + DataNode * m_pPrev; + }; + + inline void SerialData::Append(UBYTE byte) + { + m_pData->Append(byte); + } + + inline void SerialData::Append(void const * pData, unsigned nSize) + { + m_pData->Append(pData,nSize); + } + + inline void SerialData::Append(SerialData * pIns) + { + DataNode * pNewNode = new DataNode(pIns->m_pPrev,m_pData,m_pPrev); + + m_pData->Release(); + m_pData = pIns->m_pData; + pIns->m_pData->AddRef(); + + if (m_pPrev) + m_pPrev->Release(); + m_pPrev = pNewNode; + } + + /*******************************/ + /* Original File: iffArchv.hpp */ + /*******************************/ + + class Archive : public Unknown + { + public: + // constructor - construct with true iff the archive is for loading data + Archive(bool bIsLoading) : m_bIsLoading(bIsLoading), m_bError(false) {} + + // to determine easily whenever necessary if the archive is loading data + bool const m_bIsLoading; + bool m_bError; + + // returns either the size in bytes of the data so far written to a storing archive + // or the number of bytes remaining to be read from a loading archive, could be negative + // if too many bytes were read + virtual signed GetSize() const = 0; + + // if the archive is loading, nSize bytes are sectioned off to be read from a sub-archive + // or if the archive is storing, nSize is ignored and data written to the sub-archive + // will be stored when the sub-archive is closed + virtual Archive * OpenSubArchive(unsigned nSize = 0) = 0; + + // commits data written temporarily to a sub-archive (if storing) + // and advances the archive to the next byte after the sub-archive's data + virtual void CloseSubArchive(Archive * pSub) = 0; + + virtual void Open(::MediaMedium * pMedium) = 0; + virtual void Close() = 0; + + virtual void Transfer(RGBTriple &) = 0; + virtual void Transfer(BYTE &) = 0; + virtual void Transfer(UBYTE &) = 0; + virtual void Transfer(INT16 &) = 0; + virtual void Transfer(UINT16 &) = 0; + virtual void Transfer(INT32 &) = 0; + virtual void Transfer(UINT32 &) = 0; + virtual void Transfer(INT64 &) = 0; + virtual void Transfer(UINT64 &) = 0; + virtual void Transfer(ID &) = 0; + + virtual void TransferBlock(void * pData,unsigned nSize) = 0; + }; + + /*******************************/ + /* Original File: iffArchO.hpp */ + /*******************************/ + + class ArchvOut : public Archive, public SerialData + { + public: + ArchvOut() : Archive(false), m_pMedium(NULL) {} + ~ArchvOut(); + + signed GetSize() const; + + Archive * OpenSubArchive(unsigned nSize = 0); + + void CloseSubArchive(Archive * pSub); + + void Open(::MediaMedium * pMedium); + void Close(); + + void Transfer(RGBTriple &); + void Transfer(BYTE &); + void Transfer(UBYTE &); + void Transfer(INT16 &); + void Transfer(UINT16 &); + void Transfer(INT32 &); + void Transfer(UINT32 &); + void Transfer(INT64 &); + void Transfer(UINT64 &); + void Transfer(ID &); + + void TransferBlock(void * pData,unsigned nSize); + + private: + ::MediaMedium * m_pMedium; + }; + + inline signed ArchvOut::GetSize() const + { + return GetDataSize(); + } + + inline void ArchvOut::Transfer(RGBTriple & n) + { + Append(n.r); + Append(n.g); + Append(n.b); + } + + inline void ArchvOut::Transfer(BYTE & n) + { + Append(n); + } + + inline void ArchvOut::Transfer(UBYTE & n) + { + Append(n); + } + + inline void ArchvOut::Transfer(INT16 & n) + { + Append(static_cast(n >> 8)); + Append(static_cast(n)); + } + + inline void ArchvOut::Transfer(UINT16 & n) + { + Append(static_cast(n >> 8)); + Append(static_cast(n)); + } + + inline void ArchvOut::Transfer(INT32 & n) + { + Append(static_cast(n >> 24)); + Append(static_cast(n >> 16)); + Append(static_cast(n >> 8)); + Append(static_cast(n)); + } + + inline void ArchvOut::Transfer(UINT32 & n) + { + Append(static_cast(n >> 24)); + Append(static_cast(n >> 16)); + Append(static_cast(n >> 8)); + Append(static_cast(n)); + } + + inline void ArchvOut::Transfer(INT64 & n) + { + Append(static_cast(n >> 56)); + Append(static_cast(n >> 48)); + Append(static_cast(n >> 40)); + Append(static_cast(n >> 32)); + Append(static_cast(n >> 24)); + Append(static_cast(n >> 16)); + Append(static_cast(n >> 8)); + Append(static_cast(n)); + } + + inline void ArchvOut::Transfer(UINT64 & n) + { + Append(static_cast(n >> 56)); + Append(static_cast(n >> 48)); + Append(static_cast(n >> 40)); + Append(static_cast(n >> 32)); + Append(static_cast(n >> 24)); + Append(static_cast(n >> 16)); + Append(static_cast(n >> 8)); + Append(static_cast(n)); + } + + inline void ArchvOut::Transfer(ID & n) + { + Append(&n,4); + } + + inline void ArchvOut::TransferBlock(void * pData,unsigned nSize) + { + Append(pData,nSize); + } + + #endif // ! IFF_READ_ONLY + + /*******************************/ + /* Original File: iffArchI.hpp */ + /*******************************/ + + #ifdef IFF_READ_ONLY + #define _IFF_ARCHI_BASE Unknown + #define _IFF_ARCHI_GENR ArchvIn + #define _IFF_ARCHI_FLAG m_bIsLoading + #define _IFF_ARCHI_INIT ,m_bError(false) + #else // ! IFF_READ_ONLY + #define _IFF_ARCHI_BASE Archive + #define _IFF_ARCHI_GENR Archive + #define _IFF_ARCHI_FLAG Archive + #define _IFF_ARCHI_INIT + #endif // ! IFF_READ_ONLY + + class ArchvIn : public _IFF_ARCHI_BASE + { + public: + ArchvIn() : _IFF_ARCHI_FLAG(true), m_pMedium(NULL) _IFF_ARCHI_INIT {} + ~ArchvIn(); + + #ifdef IFF_READ_ONLY + bool const m_bIsLoading; + bool m_bError; + #endif // IFF_READ_ONLY + + signed GetSize() const; + + _IFF_ARCHI_GENR * OpenSubArchive(unsigned nSize = 0); + + void CloseSubArchive(_IFF_ARCHI_GENR * pSub); + + void Open(::MediaMedium * pMedium); + void Close(); + + void Transfer(RGBTriple &); + void Transfer(BYTE &); + void Transfer(UBYTE &); + void Transfer(INT16 &); + void Transfer(UINT16 &); + void Transfer(INT32 &); + void Transfer(UINT32 &); + void Transfer(INT64 &); + void Transfer(UINT64 &); + void Transfer(ID &); + + void TransferBlock(void * pData,unsigned nSize); + + private: + ArchvIn(ArchvIn * pParent, unsigned nSize); + + ::MediaMedium * m_pMedium; + signed m_nBytesRemaining; + unsigned m_nEndPos; + }; + + #ifdef IFF_READ_ONLY + typedef ArchvIn Archive; + #endif // IFF_READ_ONLY + + inline signed ArchvIn::GetSize() const + { + return m_nBytesRemaining; + } + + inline void ArchvIn::Transfer(RGBTriple & n) + { + m_nBytesRemaining -= 3; + if (m_nBytesRemaining >= 0) + { + ::MediaRead(m_pMedium, &n.r); + ::MediaRead(m_pMedium, &n.g); + ::MediaRead(m_pMedium, &n.b); + if (m_pMedium->m_fError) m_bError = true; + } + else m_bError = true; + } + + inline void ArchvIn::Transfer(UBYTE & n) + { + m_nBytesRemaining -= 1; + if (m_nBytesRemaining >= 0) + { + ::MediaRead(m_pMedium, &n); + if (m_pMedium->m_fError) m_bError = true; + } + else m_bError = true; + } + + inline void ArchvIn::Transfer(BYTE & n) + { + m_nBytesRemaining -= 1; + if (m_nBytesRemaining >= 0) + { + ::MediaRead(m_pMedium, &n); + if (m_pMedium->m_fError) m_bError = true; + } + else m_bError = true; + } + + inline void ArchvIn::Transfer(UINT16 & n) + { + m_nBytesRemaining -= 2; + if (m_nBytesRemaining >= 0) + { + UBYTE byte; + ::MediaRead(m_pMedium, &byte); + n = byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + if (m_pMedium->m_fError) m_bError = true; + } + else m_bError = true; + } + + inline void ArchvIn::Transfer(INT16 & n) + { + m_nBytesRemaining -= 2; + if (m_nBytesRemaining >= 0) + { + BYTE byte; + ::MediaRead(m_pMedium, &byte); + n = byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + if (m_pMedium->m_fError) m_bError = true; + } + else m_bError = true; + } + + inline void ArchvIn::Transfer(UINT32 & n) + { + m_nBytesRemaining -= 4; + if (m_nBytesRemaining >= 0) + { + UBYTE byte; + ::MediaRead(m_pMedium, &byte); + n = byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + if (m_pMedium->m_fError) m_bError = true; + } + else m_bError = true; + } + + inline void ArchvIn::Transfer(INT32 & n) + { + m_nBytesRemaining -= 4; + if (m_nBytesRemaining >= 0) + { + BYTE byte; + ::MediaRead(m_pMedium, &byte); + n = byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + if (m_pMedium->m_fError) m_bError = true; + } + else m_bError = true; + } + + inline void ArchvIn::Transfer(UINT64 & n) + { + m_nBytesRemaining -= 8; + if (m_nBytesRemaining >= 0) + { + UBYTE byte; + ::MediaRead(m_pMedium, &byte); + n = byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + if (m_pMedium->m_fError) m_bError = true; + } + else m_bError = true; + } + + inline void ArchvIn::Transfer(INT64 & n) + { + m_nBytesRemaining -= 8; + if (m_nBytesRemaining >= 0) + { + BYTE byte; + ::MediaRead(m_pMedium, &byte); + n = byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + ::MediaRead(m_pMedium, &byte); + n <<= 8; + n |= byte; + if (m_pMedium->m_fError) m_bError = true; + } + else m_bError = true; + } + + inline void ArchvIn::Transfer(ID & n) + { + m_nBytesRemaining -= 4; + if (m_nBytesRemaining >= 0) + { + // cast pointer to pointer to 4 byte data type to force 4 byte 'fast' read + ::MediaRead(m_pMedium, reinterpret_cast(&n.m_sID[0])); + if (m_pMedium->m_fError) m_bError = true; + } + else m_bError = true; + } + + inline void ArchvIn::TransferBlock(void * pData,unsigned nSize) + { + m_nBytesRemaining -= nSize; + if (m_nBytesRemaining >= 0) + { + m_pMedium->ReadBlock(pData,nSize); + if (m_pMedium->m_fError) m_bError = true; + } + else m_bError = true; + } + + /*******************************/ + /* Original File: iffSrlOb.hpp */ + /*******************************/ + + class SerializableObj : public Unknown + { + public: + virtual void Serialize(Archive * pArchv) = 0; + }; + + /*******************************/ + /* Original File: iffChunk.hpp */ + /*******************************/ + + class Chunk : public SerializableObj + { + public: + ID m_idCk; + + Chunk * GetProperty(ID idProp) const; + + virtual bool IsUnknown() const { return false; } + + void Write(Archive * pArchv); + static Chunk * Load(ID idParent, Archive * pArchv, ID idChunk = ID_ANY, bool bKnown = true); + + static Chunk * DynCreate(ID idParent, ID idChunk); + static void Register(ID idParent, ID idChunk, Chunk * (* pfnCreate) () ); + + Composite const * GetParent() const { return m_pParent; } + + protected: + Chunk() : m_pParent(NULL) {} + + private: + Composite const * m_pParent; // mot reference counted + ChildNode const * m_pNode; // not reference counted either + + friend class Composite; + }; + + #define IFF_IMPLEMENT_DYNCREATE(idParent,idChunk,tokenClassName) _IFF_IMPLEMENT_DYNCREATE_LINE_EX(idParent,idChunk,tokenClassName,__LINE__) + #define _IFF_IMPLEMENT_DYNCREATE_LINE_EX(idParent,idChunk,tokenClassName,nLine) _IFF_IMPLEMENT_DYNCREATE_LINE(idParent,idChunk,tokenClassName,nLine) + + #define _IFF_IMPLEMENT_DYNCREATE_LINE(idParent,idChunk,tokenClassName,nLine) \ + static IFF::Chunk * CreateClassObject ## tokenClassName ##_## nLine () { \ + IFF::Chunk * pChunk = new IFF::tokenClassName; \ + pChunk->m_idCk = idChunk; \ + return pChunk; \ + } \ + class RegisterChunkClass ## tokenClassName ##_## nLine { \ + public: RegisterChunkClass ## tokenClassName ##_## nLine () { \ + IFF::Chunk::Register(idParent , idChunk , CreateClassObject ## tokenClassName ##_## nLine); \ + } \ + } rcc ## tokenClassName ##_## nLine; + + /*******************************/ + /* Original File: iffBlock.hpp */ + /*******************************/ + + class ChildNode : public Unknown + { + public: + Chunk * GetChunk() const { return m_pChunk; } + private: + ChildNode * m_pNext; + ChildNode * m_pPrev; + Chunk * m_pChunk; + + friend class Composite; + }; + + class Composite : public Chunk + { + public: + ID m_idData; + + Composite() : m_pFirst(NULL), m_pLast(NULL) {} + virtual ~Composite(); + + ChildNode * GetFirstChild() const { return m_pFirst; } + ChildNode * GetFirstChild(ID idMatch) const; + ChildNode * GetLastChild() const { return m_pLast; } + ChildNode * GetLastChild(ID idMatch) const; + static ChildNode * GetNextChild(ChildNode const * pNode) { return pNode->m_pNext; } + static ChildNode * GetNextChild(ChildNode const * pNode, ID idMatch); + static ChildNode * GetPrevChild(ChildNode const * pNode) { return pNode->m_pPrev; } + static ChildNode * GetPrevChild(ChildNode const * pNode, ID idMatch); + + Chunk * GetProperty(ChildNode const * pNode, ID idProp) const; + + void DeleteChild(ChildNode * pNode); + void DeleteAllChildren(); + + ChildNode * InsertChildFirst(Chunk * pChunk); + ChildNode * InsertChildLast(Chunk * pChunk); + ChildNode * InsertChildAfter(ChildNode * pNode, Chunk * pChunk); + ChildNode * InsertChildBefore(ChildNode * pNode, Chunk * pChunk); + + // pfnCallback should return true to continue the enumeration, false to finish + virtual bool EnumChildren(ID idData, ID idChunk, bool (* pfnCallback) (Chunk *, void *), void * pData) const; + + protected: + virtual void Serialize(Archive * pArchv); + + virtual Chunk * LoadChunk(Archive * pArchv) const; + virtual bool IsValidChildID(ID id) const; + + private: + ChildNode * m_pFirst; + ChildNode * m_pLast; + }; + + class Form : public Composite + { + public: + Form() { m_idCk = "FORM"; } + protected: + virtual bool IsValidChildID(ID id) const; + }; + + class Cat : public Composite + { + public: + Cat() { m_idCk = "CAT "; } + virtual bool EnumChildren(ID idData, ID idChunk, bool (* pfnCallback) (Chunk *, void *), void * pData) const; + protected: + virtual bool IsValidChildID(ID id) const; + }; + + class List : public Composite + { + public: + List() { m_idCk = "LIST"; } + virtual bool EnumChildren(ID idData, ID idChunk, bool (* pfnCallback) (Chunk *, void *), void * pData) const; + protected: + virtual bool IsValidChildID(ID id) const; + }; + + class Prop : public Composite + { + public: + Prop() { m_idCk = "PROP"; } + protected: + virtual bool IsValidChildID(ID id) const; + }; + + /*******************************/ + /* Original File: iffMscCk.hpp */ + /*******************************/ + + class MiscChunk : public Chunk + { + public: + MiscChunk(ID id) + #ifndef IFF_READ_ONLY + : m_pData(NULL) + #endif // ! IFF_READ_ONLY + { + m_idCk = id; + } + + virtual bool IsUnknown() const { return true; } + + protected: + virtual void Serialize(Archive * pArchv); + #ifndef IFF_READ_ONLY + virtual ~MiscChunk(); + #endif // ! IFF_READ_ONLY + + private: + #ifndef IFF_READ_ONLY + BYTE * m_pData; + unsigned m_nSize; + #endif // ! IFF_READ_ONLY + }; + + /******************************/ + /* Original File: iffFile.hpp */ + /******************************/ + + class GenericFile : public SerializableObj + { + public: + #ifndef IFF_READ_ONLY + GenericFile() : m_pszFileName(NULL) {} + virtual ~GenericFile() { if (m_pszFileName) delete[] m_pszFileName; } + #endif + + bool Load(TCHAR const * pszFileName); + bool Load(::MediaMedium * pMedium); + + #ifndef IFF_READ_ONLY + bool Write(TCHAR const * pszFileName = NULL); + bool Write(::MediaMedium * pMedium); + #endif // ! IFF_READ_ONLY + + private: + #ifndef IFF_READ_ONLY + TCHAR * m_pszFileName; + #endif // ! IFF_READ_ONLY + }; + + class File : public GenericFile + { + public: + virtual ~File(); + File() : m_pContents(NULL) {} + + Composite * GetContents() const; + void SetContents(Composite * pContents); + + protected: + virtual void Serialize(Archive * pArchv); + + private: + ID m_idType; + Composite * m_pContents; + }; + + inline Composite * File::GetContents() const + { + return m_pContents; + } + + inline void File::SetContents(Composite * pContents) + { + if (m_pContents) m_pContents->Release(); + if (pContents) + { + pContents->AddRef(); + m_idType = pContents->m_idCk; + } + m_pContents = pContents; + } + + // Have a static object of this in each file: + // It will detect if some files are compiled with + // IFF_READ_ONLY defined differently to each other + static class ConsistencyCheck + { + public: inline ConsistencyCheck() + { + #ifdef IFF_READ_ONLY + static bool bReadOnly = true; + if (!bReadOnly) + #else + static bool bReadOnly = false; + if (bReadOnly) + #endif + { + DisplayMessage + ( + #ifdef NDEBUG + TEXT("Error"), + TEXT("IFF_READ_ONLY definition not consistent") + #else + TEXT("IFF Compile Option Error"), + TEXT("Some files which #include \"iff.hpp\"\n") + TEXT("have the macro IFF_READ_ONLY defined\n") + TEXT("and some don't.\n\n") + TEXT("Please ensure this is consistent and recompile.") + #endif + ); + exit(-45); + } + } + } + consistencyCheck; + +} // namespace IFF + +#endif // ! _INCLUDED_IFF_HPP_ diff --git a/3dc/win95/iff_ILBM.cpp b/3dc/win95/iff_ILBM.cpp new file mode 100644 index 0000000..128f7ad --- /dev/null +++ b/3dc/win95/iff_ILBM.cpp @@ -0,0 +1,327 @@ +#include "advwin32.h" +#include "iff_ILBM.hpp" + +IFF_IMPLEMENT_DYNCREATE("ILBM","BMHD",IlbmBmhdChunk) +IFF_IMPLEMENT_DYNCREATE("ILBM","CMAP",IlbmCmapChunk) +IFF_IMPLEMENT_DYNCREATE("ILBM","BODY",IlbmBodyChunk) +IFF_IMPLEMENT_DYNCREATE("ILBM","GRAB",IlbmGrabChunk) + +namespace IFF +{ + void IlbmBmhdChunk::Serialize(Archive * pArchv) + { + pArchv->Transfer(width); + pArchv->Transfer(height); + pArchv->Transfer(xTopLeft); + pArchv->Transfer(yTopLeft); + pArchv->Transfer(nBitPlanes); + pArchv->Transfer(eMasking); + pArchv->Transfer(eCompression); + pArchv->Transfer(flags); + pArchv->Transfer(iTranspCol); + pArchv->Transfer(xAspectRatio); + pArchv->Transfer(yAspectRatio); + pArchv->Transfer(xMax); + pArchv->Transfer(yMax); + } + + void IlbmCmapChunk::Serialize(Archive * pArchv) + { + if (pArchv->m_bIsLoading) + { + nEntries = pArchv->GetSize()/3; + if (pTable) delete[] pTable; + pTable = new RGBTriple [nEntries]; + } + + for (unsigned i=0; iTransfer(pTable[i]); + } + + IlbmCmapChunk::~IlbmCmapChunk() + { + if (pTable) delete[] pTable; + } + + void IlbmBodyChunk::Serialize(Archive * pArchv) + { + if (pArchv->m_bIsLoading) + { + nSize = pArchv->GetSize(); + if (pData) delete[] pData; + pData = new UBYTE [nSize]; + } + + pArchv->TransferBlock(pData,nSize); + } + + bool IlbmBodyChunk::GetHeaderInfo() const + { + Chunk * pHdr = GetProperty("BMHD"); + if (!pHdr) + { + return false; + } + nWidth = static_cast(pHdr)->width; + eCompression = static_cast(pHdr)->eCompression; + nBitPlanes = static_cast(pHdr)->nBitPlanes; + return true; + } + + #ifndef IFF_READ_ONLY + bool IlbmBodyChunk::BeginEncode() + { + if (!GetHeaderInfo()) + { + return false; + } + + pEncodeDst = new DataBlock; + pEncodeSrc = new UBYTE [(nWidth+7)/8]; + + nSizeNonCprss = 0; + nSizeCprss = 0; + + return true; + } + +// The uninitialised part of byte is shifted out. +#ifdef _MSC_VER +#pragma warning(disable: 4701) +#endif + bool IlbmBodyChunk::EncodeNextRow(unsigned const * pRow) + { + if (!pEncodeDst) return false; + + for (unsigned b=0; b>b & 1; + + if (7==(x&7)) *pBuf++ = static_cast(byte); + } + if (nWidth & 7) + { + byte <<= 8-(nWidth & 7); + *pBuf = static_cast(byte); + } + + if (eCompression) + { + nSizeNonCprss += (nWidth+7)/8; + + UBYTE const * pBuf = pEncodeSrc; + unsigned i=(nWidth+7)/8; + + while (i) + { + if (1==i) + { + pEncodeDst->Append(0); + pEncodeDst->Append(*pBuf); + nSizeCprss += 2; + i=0; + } + else if (i>1) + { + if (pBuf[0]==pBuf[1]) + { + unsigned j=2; + while (jAppend(static_cast(0x101-j)); + pEncodeDst->Append(*pBuf); + pBuf += j; + i -= j; + nSizeCprss += 2; + } + else + { + unsigned j=2; + while (jAppend(static_cast(j-1)); + pEncodeDst->Append(pBuf,j); + pBuf += j; + i -= j; + nSizeCprss += j+1; + } + } + } + + } + else + { + pEncodeDst->Append(pEncodeSrc,(nWidth+7)/8); + } + } + + return true; + } +#ifdef _MSC_VER +#pragma warning(default: 4701) +#endif + + bool IlbmBodyChunk::EndEncode() + { + if (!pEncodeDst) return false; + + if (pData) delete[] pData; + nSize = pEncodeDst->GetDataSize(); + pData = new UBYTE[nSize]; + + memcpy(pData,pEncodeDst->GetDataPtr(),nSize); + + delete pEncodeDst; + delete[] pEncodeSrc; + + pEncodeDst = NULL; + pEncodeSrc = NULL; + + return true; + } + #endif + + bool IlbmBodyChunk::BeginDecode() const + { + if (pDecodeDst) delete[] pDecodeDst; + if (!pData || !GetHeaderInfo()) + { + pDecodeSrc = NULL; + pDecodeDst = NULL; + return false; + } + + pDecodeSrc = pData; + nRemaining = nSize; + + pDecodeDst = new unsigned [nWidth]; + + return pData != NULL; + } + +// The uninitialised part of pDecodeDst is shifted out. +#ifdef _MSC_VER +#pragma warning(disable: 4701) +#endif + unsigned const * IlbmBodyChunk::DecodeNextRow() const + { + if (!pDecodeSrc || !pDecodeDst) return NULL; + + for (unsigned x=0; x0x80) + { + repcnt = 0x100 - byte; + byte = *pDecodeSrc; + } + else goto REPEAT_SKIP; + } + } + + pDecodeDst[x] |= (byte>>7 & 1)<>7 & 1)<Transfer(xHotSpot); + pArchv->Transfer(yHotSpot); + } +} diff --git a/3dc/win95/iff_ILBM.hpp b/3dc/win95/iff_ILBM.hpp new file mode 100644 index 0000000..8a83b38 --- /dev/null +++ b/3dc/win95/iff_ILBM.hpp @@ -0,0 +1,164 @@ +#ifndef _INCLUDED_IFF_ILBM_HPP_ +#define _INCLUDED_IFF_ILBM_HPP_ + +#include "iff.hpp" + +namespace IFF +{ + class IlbmBmhdChunk : public Chunk + { + public: + UINT16 width; + UINT16 height; + UINT16 xTopLeft; + UINT16 yTopLeft; + UBYTE nBitPlanes; + enum + { + MASK_NONE = 0, + MASK_HASMASK = 1, + MASK_TRANSPARENTCOL = 2, + MASK_LASSO = 3 + }; + UBYTE eMasking; + enum + { + COMPRESS_NONE = 0, + COMPRESS_RUNLENGTH = 1, + COMPRESS_S3TC =2 //will have s3tc chunk instead of body chunk + }; + UBYTE eCompression; + UBYTE flags; + UINT16 iTranspCol; + UBYTE xAspectRatio; + UBYTE yAspectRatio; + UINT16 xMax; + UINT16 yMax; + + IlbmBmhdChunk() { m_idCk = "BMHD"; } + + protected: + virtual void Serialize(Archive * pArchv); + }; + + class IlbmCmapChunk : public Chunk + { + public: + unsigned nEntries; + RGBTriple * pTable; + + void CreateNew(unsigned nSize); + + IlbmCmapChunk() : pTable(NULL) { m_idCk = "CMAP"; } + virtual ~IlbmCmapChunk(); + + protected: + virtual void Serialize(Archive * pArchv); + }; + + inline void IlbmCmapChunk::CreateNew(unsigned nSize) + { + if (pTable) delete[] pTable; + pTable = new RGBTriple [nSize]; + nEntries = nSize; + } + + class IlbmBodyChunk : public Chunk + { + public: + IlbmBodyChunk() : pData(NULL), pDecodeDst(NULL) + #ifndef IFF_READ_ONLY + , pEncodeDst(NULL), pEncodeSrc(NULL) + #endif + { m_idCk = "BODY"; } + virtual ~IlbmBodyChunk(); + + #ifndef IFF_READ_ONLY + bool BeginEncode(); + bool EncodeFirstRow(unsigned const * pRow); + bool EncodeNextRow(unsigned const * pRow); + bool EndEncode(); + + float GetCompressionRatio() const; + #endif + + bool BeginDecode() const; + unsigned const * DecodeFirstRow() const; + unsigned const * DecodeNextRow() const; + bool EndDecode() const; + + protected: + virtual void Serialize(Archive * pArchv); + + virtual bool GetHeaderInfo() const; // fills in these three data members + mutable unsigned nWidth; + mutable unsigned eCompression; + mutable unsigned nBitPlanes; + + private: + unsigned nSize; + UBYTE * pData; + + mutable UBYTE const * pDecodeSrc; + mutable unsigned nRemaining; + mutable unsigned * pDecodeDst; + + #ifndef IFF_READ_ONLY + DataBlock * pEncodeDst; + UBYTE * pEncodeSrc; + + unsigned nSizeNonCprss; + unsigned nSizeCprss; + #endif + }; + + #ifndef IFF_READ_ONLY + inline bool IlbmBodyChunk::EncodeFirstRow(unsigned const * pRow) + { + if (BeginEncode()) + return EncodeNextRow(pRow); + else + return false; + } + + inline float IlbmBodyChunk::GetCompressionRatio() const + { + if (!nSizeNonCprss) return 0.0F; + + return (static_cast(nSizeNonCprss)-static_cast(nSizeCprss))/static_cast(nSizeNonCprss); + } + #endif + + inline unsigned const * IlbmBodyChunk::DecodeFirstRow() const + { + if (BeginDecode()) + return DecodeNextRow(); + else + return NULL; + } + + inline bool IlbmBodyChunk::EndDecode() const + { + if (pDecodeDst) + { + delete[] pDecodeDst; + pDecodeDst = NULL; + return true; + } + else return false; + } + + class IlbmGrabChunk : public Chunk + { + public: + UINT16 xHotSpot; + UINT16 yHotSpot; + + IlbmGrabChunk() { m_idCk = "GRAB"; } + + protected: + virtual void Serialize(Archive * pArchv); + }; +} + +#endif // ! _INCLUDED_IFF_ILBM_HPP_ diff --git a/3dc/win95/io.c b/3dc/win95/io.c new file mode 100644 index 0000000..ab2c540 --- /dev/null +++ b/3dc/win95/io.c @@ -0,0 +1,1970 @@ +#include "3dc.h" + +#include +#include + +#include "inline.h" +#include "module.h" +#include "krender.h" + +#include "chnktexi.h" +#include "d3d_hud.h" +#define UseLocalAssert Yes +#include "ourasert.h" +#include "hud_layout.h" + +#undef textprint + + +#if SupportTLTFiles +#define Output_TLT_File No +#endif + +#define Output_VEA_File No + +#define Proper_8Bit_MIP No + +#define DontLet222ColoursGoToBlack Yes + +#define textprintOn Yes + +#define DHMtextprint Yes + /* define to use Dave Malcolm's replacement textprint routines */ + + +/* As specified by Roxby */ +#define ClearScreenColour 1000 + +/* + To filter frame rate values from + Windows timer to provide a smoother + ride. This may make some AI systems + etc behave better, though it will take + some time to catch up if there is a genuine + abrupt transition in the frame rate. + + There may also be some sort of convergence + instability here!!!! IMPORTANT + FIXME!!!! (possibly) + + Although this code was derived from + some of Jamie's filter algorithms, I have + mangled it hideously, so _don't blame him_! +*/ + +#define KalmanTimer No + +/* + Experiment to try and fix mystery driver problems + Don't set with ForceWindowsPalette on!!! + Leave this on!!! + On some video cards it seems necessary not only to + set palette on vblanking interval, but also AFTER + D3D initialisation is complete... +*/ + +#define ChangePaletteOnVBAlways Yes + +/* + Turn on or off checking for the validity + of a video mode before switching to it. + Actually causes problems on some systems + because the DirectDraw enumerator fails to + report valid modes (although on other systems + it can report ones that can't be reached, ho + hum), so at least for Chris H. it needs to be + turned off. + NOTE THAT THIS SHOULD HAVE THE SAME SETTING AS + CheckVideoModes at the start of dd_func.cpp, at + least until we make it a system.h value or + something else sensible... +*/ + +#define CheckVideoModes No + + +/* + + externs for commonly used global variables and arrays + +*/ + +extern SCENE Global_Scene; +extern SHAPEHEADER **mainshapelist; +extern SHAPEHEADER *testpaletteshapelist[]; +extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; +extern int sine[]; +extern int cosine[]; +extern int AdaptiveHazingFlag; +extern int *Global_ShapeNormals; +extern int *Global_ShapePoints; +extern int *ItemPointers[]; +extern int ItemData[]; +extern char projectsubdirectory[]; + +extern int WinLeftX; +extern int WinRightX; +extern int WinTopY; +extern int WinBotY; + +extern int WindowRequestMode; +extern int VideoRequestMode; +extern int ZBufferRequestMode; +extern int RasterisationRequestMode; +extern int SoftwareScanDrawRequestMode; +extern int DXMemoryRequestMode; + +extern int TotalVideoMemory; +extern int NumAvailableVideoModes; +extern VIDEOMODEINFO AvailableVideoModes[]; + +extern int memoryInitialisationFailure; + +extern IMAGEHEADER ImageHeaderArray[]; /* Array of Image Headers */ + +/* + + Global Variables for PC Watcom Functions + and Windows 95! + +*/ + + int DrawMode = DrawPerVDB; +/* Win95 default ought to be per frame */ + +/* Timer */ + long lastTickCount; + + unsigned char *ScreenBuffer = 0; /* Ensure initialised to Null */ + unsigned char *ScreenBuffer2 = 0; + + + unsigned char LPTestPalette[1024]; /* to cast to lp*/ + + int InputMode; + + int VideoMode; + int VideoModeType; + int VideoModeTypeScreen; + int WindowMode; + int ScanDrawMode; + int ZBufferMode; + int DXMemoryMode; + unsigned char AttemptVideoModeRestart; + VIDEORESTARTMODES VideoRestartMode; + + PROCESSORTYPES ProcessorType; + BOOL MMXAvailable; + + unsigned char *TextureLightingTable = 0; + + unsigned char *PaletteRemapTable = 0; + + int **ShadingTableArray = 0; + int NumShadingTables = 0; + + unsigned char **PaletteShadingTableArray = 0; + int NumPaletteShadingTables = 0; + + int FrameRate; + int NormalFrameTime; + int PrevNormalFrameTime; + extern int CloakingPhase; + + /* These two are dummy values to get the DOS platform to compile */ + + unsigned char KeyCode; + unsigned char KeyASCII; + + + #if SuppressWarnings + unsigned char *palette_tmp; + static VIEWDESCRIPTORBLOCK* vdb_tmp; + static SCREENDESCRIPTORBLOCK* sdb_tmp; + #endif + + /* Keyboard */ + unsigned char KeyboardInput[MAX_NUMBER_OF_INPUT_KEYS]; + unsigned char GotAnyKey; + + /* Input communication with Windows Procedure */ + /* Print system */ + +#if !DHMtextprint + PRINTQUEUEITEM PrintQueue[MaxMessages]; + int MessagesStoredThisFrame; +#endif + + int textprintPosX; + int textprintPosY; + IMAGEHEADER* fontHeader; + + /* Added 28/11/97 by DHM: boolean for run-time switching on/off of textprint */ + int bEnableTextprint = No; + + /* Added 28/1/98 by DHM: as above, but applies specifically to textprintXY */ + int bEnableTextprintXY = Yes; + + /* Palette */ + + unsigned char PaletteBuffer[768 + 1]; + +/* Test Palette */ + +unsigned char TestPalette[768]; +unsigned char TestPalette2[768]; + + + + +/* KJL 11:48:45 28/01/98 - used to scale NormalFrameTime, so the game can be slowed down */ +int TimeScale=65536; + +/* KJL 16:00:11 28/01/98 - unscaled frame time */ +int RealFrameTime; +int GlobalFrameCounter; +int RouteFinder_CallsThisFrame; + +/* KJL 15:08:43 29/03/98 - added to give extra flexibility to debugging text */ +int PrintDebuggingText(const char* t, ...); +int ReleasePrintDebuggingText(const char* t, ...); + + +/* + + IO and Other Functions for the PC + +*/ + + +/* + + Get Shape Data + + Function returns a pointer to the Shape Header Block + +*/ + +SHAPEHEADER* GetShapeData(int shapenum) + +{ + + if(shapenum>=0 && shapenum< maxshapes) + { + SHAPEHEADER *sptr = mainshapelist[shapenum]; + return sptr; + } + + return NULL; +} + + +/* + + Platform specific VDB functions for Initialisation and ShowView() + +*/ + +void PlatformSpecificVDBInit(VIEWDESCRIPTORBLOCK *vdb) + +{ + #if SuppressWarnings + vdb_tmp = vdb; + #endif +} + + +void PlatformSpecificShowViewEntry(VIEWDESCRIPTORBLOCK *vdb, SCREENDESCRIPTORBLOCK *sdb) + +{ + #if SuppressWarnings + vdb_tmp = vdb; + sdb_tmp = sdb; + #endif +} + + +void PlatformSpecificShowViewExit(VIEWDESCRIPTORBLOCK *vdb, SCREENDESCRIPTORBLOCK *sdb) + +{ + #if SuppressWarnings + vdb_tmp = vdb; + sdb_tmp = sdb; + #endif +} + + +/* + + Convert UNIX to MS-DOS + +*/ + +void GetDOSFilename(char *fnameptr) + +{ + + while(*fnameptr) { + + if(*fnameptr == 0x2f) *fnameptr = 0x5c; + fnameptr++; + + } + +} + + +/* + + Compare two strings. + + Return Yes if they're the same, else No. + +*/ + +/* + IMPORTANT!!! + This function is not ideal!!! It is used + here because this is only an initialisation + stage, but if you want to compare strings + elsewhere you should either use the C library + function or (if there's a problem with that) + write your own. +*/ + +int CompareStringCH(char *string1, char *string2) + +{ + + char *srtmp; + char *srtmp2; + int slen1 = 0; + int slen2 = 0; + int i; + + + srtmp = string1; + + while(*srtmp++ != 0) + slen1++; + + srtmp = string2; + + while(*srtmp++ != 0) + slen2++; + + if(slen1 != slen2) return No; + + else { + + srtmp = string1; + srtmp2 = string2; + + for(i=slen1; i!=0; i--) + if(*srtmp++ != *srtmp2++) return No; + + return Yes; + + } + +} + + +/* + + Compare two filenames. + + The first filename is assumed to be raw i.e. has no project subdirectory appended. + The second is assumed to be ready for use. + + Make a copy of both strings, prefix the copy of the first with the project subdirectory + and convert them to DOS format before the comparison. + +*/ + +int CompareFilenameCH(char *string1, char *string2) + +{ + + char *srtmp1; + char *srtmp2; + int slen1 = 0; + int slen2 = 0; + int i; + char fname1[ImageNameSize]; + char fname2[ImageNameSize]; + + + #if 0 + textprint(" Compare "); textprint(string1); textprint("\n"); + textprint(" with "); textprint(string2); textprint("\n"); + /*WaitForReturn();*/ + #endif + + + /* Make a copy of string 1, adding the project subdirectory */ + + srtmp1 = projectsubdirectory; + srtmp2 = fname1; + while(*srtmp1) *srtmp2++ = *srtmp1++; + srtmp1 = string1; + while(*srtmp1) *srtmp2++ = *srtmp1++; + *srtmp2 = 0; + + /* Make a copy of string 2 */ + + srtmp1 = string2; + srtmp2 = fname2; + while(*srtmp1) *srtmp2++ = *srtmp1++; + *srtmp2 = 0; + + /* How long are they? */ + + srtmp1 = fname1; + while(*srtmp1++ != 0) + slen1++; + + srtmp2 = fname2; + while(*srtmp2++ != 0) + slen2++; + + fname1[slen1] = 0; /* Term */ + fname2[slen2] = 0; + + #if 0 + textprint("slen1 = %d, ", slen1); + textprint("slen2 = %d\n", slen2); + #endif + + #if 0 + textprint(" Compare "); textprint(fname1); textprint("\n"); + textprint(" with "); textprint(fname2); textprint("\n"); + /*WaitForReturn();*/ + #endif + + + GetDOSFilename(fname1); + GetDOSFilename(fname2); + + + if(slen1 != slen2) { + /*textprint("not same\n");*/ + return No; + } + + srtmp1 = fname1; + srtmp2 = fname2; + + #if 0 + textprint(" Compare "); textprint(srtmp1); textprint("\n"); + textprint(" with "); textprint(srtmp2); textprint("\n"); + WaitForReturn(); + #endif + + for(i = slen1; i!=0; i--) { + if(*srtmp1++ != *srtmp2++) { + /*textprint("not same\n");*/ + return No; + } + } + + /*textprint("same\n");*/ + return Yes; + +} + + + + + + + +/* + + Create an RGB table for "palette" + + "GetRemappedPaletteColour()" is an access function for this table + +*/ + + +#define remap_table_size (1 << (remap_table_rgb_bits * 3)) + + +#define cprt_info No +#define cprt_cnt No + + + +int NearestColour(int rs, int gs, int bs, unsigned char *palette) + +{ + + int i; + VECTORCH p0; + VECTORCH p1; + int nearest_index; + int nearest_delta; + int d; + + + p0.vx = rs; + p0.vy = gs; + p0.vz = bs; + + nearest_index = 0; + nearest_delta = bigint; + + for(i = 0; i < 256; i++) { + + p1.vx = palette[0]; + p1.vy = palette[1]; + p1.vz = palette[2]; + + d = FandVD_Distance_3d(&p0, &p1); + + if(d < nearest_delta) { + + nearest_delta = d; + nearest_index = i; + + } + + palette += 3; + + } + + return nearest_index; + +} + + + + + + + + + + +/*************************************************************************/ +/*************************************************************************/ + + + + + +/* + + PC Video Mode Array Functions + +*/ + + +#define m320diag (378 + 6) + + + + + +/* + + PC Video Mode Function Arrays + +*/ + +void (*SetVideoMode[]) (void) = { + +0 + +}; + + + + + + + + + + + + + + + + +/* + + Initialise System and System Variables + +*/ + +void InitialiseSystem(HINSTANCE hInstance, int nCmdShow) + +{ + BOOL rc; + + /* + Pick up processor type + */ + + ProcessorType = ReadProcessorType(); + + if ((ProcessorType == PType_PentiumMMX) || + (ProcessorType == PType_Klamath) || + (ProcessorType == PType_OffTopOfScale)) + MMXAvailable = TRUE; + else + MMXAvailable = FALSE; + + /* + Copy initial requests to current variables, + subject to later modification. + */ + + VideoMode = VideoRequestMode; + WindowMode = WindowRequestMode; + + /* + Initialise dubious restart + system for ModeX emulation + and other problems + */ + + AttemptVideoModeRestart = No; + + VideoRestartMode = NoRestartRequired; + + /* + Potentially a whole suite of caps + functions could be sensibly called + from here, to determine available + sound hardware, network links, 3D + hardware acceleration etc + */ + + /* + Initialise the basic Direct Draw object, + find a hardware 3D capable driver if + possible and appropriate, and + determine what display modes, available + video memory etc exist. + */ + + if (InitialiseDirectDrawObject() + == FALSE) + /* + If we cannot get a video mode, + fail. No point in a non debugging option + for this. + */ + { + ReleaseDirect3D(); + exit(0x997799); + } + + /* + Initialise global to say whether + we think there is an onboard 3D + acceleration card / motherboard + built-in + */ + + TestInitD3DObject(); + +/* + This is (HOPEFULLY!!) now the right + place to put this call. Note that it is + not absolutely certain that we can do test + blits from DirectDraw without setting + a cooperative level, however... And note also + that MMX works better with the back buffer in + system memory... +*/ + TestMemoryAccess(); + + /* Initialise main window, windows procedure etc */ + rc = InitialiseWindowsSystem(hInstance, nCmdShow, WinInitFull); + + /* Initialise input interface */ + memset((void*)KeyboardInput, No, MAX_NUMBER_OF_INPUT_KEYS); + GotAnyKey = No; + + /* launch Direct Input */ + InitialiseDirectInput(); + InitialiseDirectKeyboard(); + InitialiseDirectMouse(); + InitJoysticks(); + + /* Initialise textprint system */ + textprintPosX = 0; + textprintPosY = 0; + #if debug + InitPrintQueue(); + #endif + + #if SUPPORT_MMX + SelectMMXOptions(); + #endif + + { + /* CDF 4/2/97 */ + extern void ConstructOneOverSinTable(void); + + ConstructOneOverSinTable(); + } + +} + + +/* + + Exit the system + +*/ + +void ExitSystem(void) +{ + /* Game specific exit functions */ + ExitGame(); + + + // Added by Mark so that Direct Sound exits cleanly + #if SOUND_ON + ExitSoundSystem(); // In ds_func.cpp + #endif + + /* + Shaft DirectDraw and hit Direct3D + with a blunt Bill. + Note that ReleaseDirect3D is currently + responsible for whacking DirectDraw + and DirectInput as well; I should probably + rename it ReleaseDirectX sometime... + */ + + ReleaseDirect3D(); + + /* Kill windows procedures */ + ExitWindowsSystem(); +} + +/* + Timer functions are based on Windows timer + giving number of millisecond ticks since Windows + was last booted. Note this will wrap round after + Windows has been up continuously for approximately + 49.7 days. This is not considered to be too + significant a limitation... +*/ + + + +void ResetFrameCounter(void) +{ + lastTickCount = timeGetTime(); + + /* KJL 15:03:33 12/16/96 - I'm setting NormalFrameTime too, rather than checking that it's + non-zero everytime I have to divide by it, since it usually is zero on the first frame. */ + NormalFrameTime = 65536 >> 4; + PrevNormalFrameTime = NormalFrameTime; + + RealFrameTime = NormalFrameTime; + FrameRate = 16; + GlobalFrameCounter=0; + CloakingPhase = 0; + + + RouteFinder_CallsThisFrame=0; +} +void FrameCounterHandler(void) +{ + int newTickCount = timeGetTime(); + int fcnt; + + fcnt = newTickCount - lastTickCount; + lastTickCount = newTickCount; + + if (fcnt == 0) + fcnt = 1; /* for safety */ + + FrameRate = TimerFrame / fcnt; + + PrevNormalFrameTime = NormalFrameTime; + NormalFrameTime = DIV_FIXED(fcnt,TimerFrame); + + RealFrameTime = NormalFrameTime; + + { + if (TimeScale!=ONE_FIXED) + { + NormalFrameTime = MUL_FIXED(NormalFrameTime,TimeScale); + } + + } + /* cap NormalFrameTime if frame rate is really low */ + if (NormalFrameTime>16384) NormalFrameTime=16384; + GlobalFrameCounter++; + CloakingPhase += NormalFrameTime>>5; + + RouteFinder_CallsThisFrame=0; +} + +/* + + This jump table has been provided + solely to ensure compatibility with + DOS and other versions. + +*/ + +void (*UpdateScreen[]) (void) = { + + FlipBuffers, + FlipBuffers, + FlipBuffers, + FlipBuffers, + + FlipBuffers, + FlipBuffers, + FlipBuffers, + FlipBuffers, + + FlipBuffers, + FlipBuffers, + FlipBuffers, + FlipBuffers, + + FlipBuffers, + FlipBuffers, + FlipBuffers, + FlipBuffers, + + FlipBuffers, + FlipBuffers, + FlipBuffers, + FlipBuffers, + + FlipBuffers, + FlipBuffers, + FlipBuffers, + FlipBuffers + +}; + + +/* + Not supported in Windows 95 !!! +*/ + + +void PlotPixelTest(int x, int y, unsigned char col) + +{ + +} + + +/* + + Wait for Return Key + + Such a function may not be defined on some platforms + + On Windows 95 the description of this function has + been changed, so that it calls FlushTextprintBuffer + and FlipBuffers before going into the actual + WaitForReturn code. This is necessary if it is to + behave in the same way after a textprint call as it + does on the DOS platform. + +*/ + +void WaitForReturn(void) + +{ + /* Crude but probably serviceable for now */ + long SavedTickCount; + SavedTickCount = lastTickCount; + +/* Display any lingering text */ + FlushTextprintBuffer(); + FlipBuffers(); + + while (!(KeyboardInput[KEY_CR])) + DirectReadKeyboard(); + + lastTickCount = SavedTickCount; +} + + + + +/* + By copying the globals here we guarantee + that game functions will receive a set of + input values updated at a defined time +*/ + + +void ReadUserInput(void) +{ + DirectReadMouse(); + ReadJoysticks(); + DirectReadKeyboard(); +} + +/* + At present all keyboard and mouse input is handled + through project specific functionality in win_func, + and all these functions are therefore empty. Later + we may port to DirectInput, at which point we + may reactivate these. +*/ + + + +void ReadKeyboard(void) + +{ +} + + +void ReadMouse(void) + +{ + + +} + + + +/* + Not NECESSARILY the standard functionality, + but it seems good enough to me... +*/ + +void CursorHome(void) + +{ +/* Reset positions for textprint system */ + textprintPosX = 0; + textprintPosY = 0; +} + + +void GetProjectFilename(char *fname, char *image) +{ + + char *src; + char *dst; + + + src = projectsubdirectory; + dst = fname; + + while(*src) + *dst++ = *src++; + + src = image; + + while(*src) + *dst++ = *src++; + + *dst = 0; + +} + + + + + + + +/* + + Attempts to load the image file. + + Returns a pointer to the image if successful, else zero. + + Image Header is filled out if successful, else ignore it. + + NOTE + + The pointer to the image data is also stored in the image + header. + +*/ + +TEXTURE* LoadImageCH(char *fname, IMAGEHEADER *iheader) +{ + return 0; +} + + + + + + + + + +void ConvertToDDPalette(unsigned char* src, unsigned char* dst, int length, int flags) +{ + int i; + +/* + Copy palette, introducing flags and shifting up + to 8 bit triple +*/ + + for (i=0; ix, + pDPR->y, + pDPR->CharToPrint + ); + #else + D3D_BlitWhiteChar + ( + pDPR->x, + pDPR->y, + pDPR->CharToPrint + ); + #endif + pDPR++; + } + + if (fTextLost) + { + /* Display error message in case test has been lost due to clipping of Y edge, or buffer overflow */ + int i; + int NumChars=strlen(TextLostMessage); + + for (i=0;i=0) + && + (y<=LastDisplayableYForChars()) + ) + { + if (DHM_NumCharsInQueuex=x; + pDPR->y=y; + pDPR->CharToPrint=Ch; + } + else + { + /* Otherwise the queue if full, we will have to ignore this char; set an error flag so we get a message*/ + fTextLost=Yes; + } + } + else + { + /* Otherwise the text is off the top or bottom of the screen; set an error flag to get a message up*/ + fTextLost=Yes; + } +} + +static int DHM_MoveBufferToQueue(int* pPosX,int* pPosY,int fZeroLeftMargin) +{ + /* + Function takes two integers by reference (using pointers), and outputs whatever is in + the string buffer into the character queue, so that code can be shared by textprint() and textprintXY() + + Returns "number of lines": any carriage returns or word wraps + */ + + /* PRECONDITION */ + { + LOWLEVELASSERT(pPosX); + LOWLEVELASSERT(pPosY); + } + + /* CODE */ + { + int NumLines=0; + + int LeftMarginX; + + if (fZeroLeftMargin) + { + LeftMarginX=0; + } + else + { + LeftMarginX=*pPosX; + } + + + + /* Iterate through the string in the buffer, adding the individual characters to the queue */ + { + char* pCh=&TextprintBuffer[0]; + int SafetyCount=0; + + while + ( + ((*pCh)!='\0') + && + ((SafetyCount++)LastDisplayableXForChars()) + { + /* Wrap around to next line.,. */ + (*pPosY)+=HUD_FONT_HEIGHT; + (*pPosX)=LeftMarginX; + NumLines++; + } + } + } + + /* ...and on to the next character*/ + pCh++; + } + } + + /* Clear the string buffer */ + { + TextprintBuffer[0]='\0'; + } + + return NumLines; + } + +} + + +int textprint(const char* t, ...) +{ + #if (debug && textprintOn) + if + ( + bEnableTextprint + ) + { + /* + Get message string from arguments into buffer... + */ + { + va_list ap; + + va_start(ap, t); + vsprintf(&TextprintBuffer[0], t, ap); + va_end(ap); + } + + /* + Attempt to trap buffer overflows... + */ + { + LOWLEVELASSERT(strlen(TextprintBuffer)ScreenDescriptorBlock.SDB_Width)) + { + /* Display string and reset to start of next line */ + WriteStringToTextBuffer(textprintPosX, textprintPosY, + &outmsg[0]); + textprintPosX = 0; + textprintPosY += HUD_FONT_HEIGHT; + XPos=0; + /* Messages can pile up at bottom of screen */ + if (textprintPosY > ScreenDescriptorBlock.SDB_Height) + textprintPosY = ScreenDescriptorBlock.SDB_Height; + /* Clear output string and reset variables */ + { + int k; + for (k=0; k<(j+1); k++) + outmsg[k] = 0; + } + j = 0; + /* Record number of lines output */ + numlines++; + } + i++; + } + + /* Flush any remaining characters */ + WriteStringToTextBuffer(textprintPosX, textprintPosY, + &outmsg[0]); + textprintPosX = 0; + textprintPosY += HUD_FONT_HEIGHT; + /* Messages can pile up at bottom of screen */ + if (textprintPosY > ScreenDescriptorBlock.SDB_Height) + textprintPosY = ScreenDescriptorBlock.SDB_Height; + numlines++; + + return numlines; +} + +/* + Textprint to defined location on screen + (in screen coordinates for current video + mode). + NOTE!!! Newlines within strings sent to this + function will be IGNORED. +*/ + +int textprintXY(int x, int y, const char* t, ...) + +{ + va_list ap; + char message[MaxMsgChars]; + + va_start(ap, t); + + vsprintf(&message[0], t, ap); + + va_end(ap); + + WriteStringToTextBuffer(x, y, &message[0]); + + return 1; /* for one line */ +} + +#else + +int textprint(const char* t, ...) + +{ + return 0; +} + +int textprintXY(int x, int y, const char* t, ...) + +{ + return 0; +} + +#endif + + +/* + Add string to text buffer +*/ + +void WriteStringToTextBuffer(int x, int y, unsigned char *buffer) + +{ + if (MessagesStoredThisFrame < MaxMessages) + { + strcpy(PrintQueue[MessagesStoredThisFrame].text, buffer); + + PrintQueue[MessagesStoredThisFrame].text_length = strlen(buffer); + PrintQueue[MessagesStoredThisFrame].x = x; + PrintQueue[MessagesStoredThisFrame].y = y; + + MessagesStoredThisFrame++; + } +} + + +/* + Display string of chracters, starting at passed pointer, + at location on screen starting with x and y. + + Patched by Dave Malcolm 20/11/96 so that text wraps around when it reaches the right hand edge of the screen, in + this routine, at least... +*/ + + +void DisplayWin95String(int x, int y, unsigned char *buffer) + +{ + int InitialX=x; + int stlen; + unsigned char ch; + + stlen = strlen(buffer); + + do + { + ch = (unsigned char) *buffer; + BlitWin95Char(x, y, ch); + x += CharWidth; + if (x > (ScreenDescriptorBlock.SDB_Width + - CharWidth)) + { + #if 1 + /* Wrap to new line, based on coordinates for display...*/ + x=InitialX; + y+=HUD_FONT_HEIGHT; + #else + /* Characters will pile up at screen edge */ + x = (ScreenDescriptorBlock.SDB_Width - CharWidth); + #endif + } + + buffer++; + stlen--; + } + while ((ch != '\n') && (ch != '\0') && + (stlen > 0)); +} + +/* + Write all messages in buffer to screen + (to be called at end of frame, after surface + / execute buffer unlock in DrawItemListContents, + so that text appears at the front of the back + buffer immediately before the flip). +*/ + +void FlushTextprintBuffer(void) + +{ + int i; + + for (i=0; i> 2; + *dst++ = (*src++) >> 2; + *dst++ = (*src++) >> 2; + } +} + + diff --git a/3dc/win95/item.c b/3dc/win95/item.c new file mode 100644 index 0000000..af4edef --- /dev/null +++ b/3dc/win95/item.c @@ -0,0 +1,306 @@ + +#include "3dc.h" +#include "module.h" +#include "inline.h" +#include "krender.h" /* KJL 11:37:53 12/05/96 - new scandraws patch */ + +/* KJL 15:02:50 05/14/97 - new max lighting intensity */ +#define MAX_INTENSITY (65536*4-1) + + +#if StandardShapeLanguage + + +#define UseLocalAssert Yes + +#include "ourasert.h" + +/* + The outputclockwise compile option has been + maintained in case anyone wants to use the existing + triangle array code with counterclockwise ordering. + In the case of Win95, we might want to this if we can ever + persuade the Direct3D rasterisation module to come up + with CULL_CCW set. Note that outputtriangles has now been purged + from the system. +*/ + +#define outputclockwise Yes + +#define use_div_fixed Yes + +#define trip_debugger No + +#if trip_debugger +int testa = 0; +int testb = 100; +int testc = 0; +#endif + +/* + To make scan draws work backwards as + well as forwards, i.e. to cope with + items that would be backface culled + without the no cull flag set, as in racing + game TLOs. + This should now work for all polygon types. +*/ + +#define ReverseDraws Yes + +/* + To optimise scan draws with local variables + explicitly braced to improve compiler + optimisation. + NOTE THIS IS -->ONLY<-- IMPLEMENTED FOR + VIDEOMODETYPE_8, 2DTEXTURE, 3DTEXTURE (LINEAR) + AND 3DTEXTURE (LINEAR_S) AT PRESENT. + AND NOT ALL THE OPTIONS INSIDE THOSE!!! + NOTE ALSO THAT THIS APPEARS TO PRODUCE BAD CODE + WITH WATCOM 10.0 AND -oeitlr, BUT WE HOPE IT WILL + WORK WITH WATCOM 10.6 + -->CRASHES, AS IT HAPPENS!!!<-- +*/ +/* + Prototypes +*/ + + + +/* + + externs for commonly used global variables and arrays + +*/ + + extern int VideoModeType; + extern int VideoModeTypeScreen; + extern int ScanDrawMode; + extern int **ShadingTableArray; + extern unsigned char **PaletteShadingTableArray; + extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + extern unsigned char *ScreenBuffer; + + + + extern IMAGEHEADER *ImageHeaderPtrs[MaxImages]; + extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; + extern long BackBufferPitch; + + /* For multiple execute buffers */ + extern int NumVertices; + + +#endif /* for support3dtextures */ + +/* + + Global Variables + +*/ + + +// int *ItemPointers[maxpolyptrs]; + +// int ItemData[maxpolys * avgpolysize]; + + + int **NextFreeItemPtr; + int *NextFreeItemData; + + int NumFreeItemPtrs; + int NumFreeItemData; + + int ItemCount; /* Instead of a Terminator */ + + POLYHEADER *global_pheader; + + int MIP_Index; + +/* + + Global Variables For Scan Convertors + +*/ + + int ScanData[maxpolys*maxscansize]; + int *NextFreeScanData; + int NumFreeScanData; + int NumScans; + + + int NumPolyPts; + + + +/* + + Item Data Structures. + + Buffer Initialisation and Allocation Functions. + +*/ + + + + +/* + John and Neal's code + Note this is only experimental, for the interface engine, + and therefore does not go through the standard scan draw + function array!!! Also, it only works in VideoModeType_8!!! + USE AT YOUR PERIL!!!! +*/ + +void Draw_Line_VMType_8(VECTOR2D* LineStart, VECTOR2D* LineEnd, int LineColour) +{ + int gosa, tame, hani, dire; + int w, x, y; + int x1, y1, x2, y2; + unsigned char *sbufferptr; + unsigned char colour = LineColour; + + x1 = LineStart->vx; + y1 = LineStart->vy; + x2 = LineEnd->vx; + y2 = LineEnd->vy; + + x1=max(x1,Global_VDB_Ptr->VDB_ClipLeft); + x1=min(x1,Global_VDB_Ptr->VDB_ClipRight-1); + x2=max(x2,Global_VDB_Ptr->VDB_ClipLeft); + x2=min(x2,Global_VDB_Ptr->VDB_ClipRight-1); + + y1=max(y1,Global_VDB_Ptr->VDB_ClipUp); + y1=min(y1,Global_VDB_Ptr->VDB_ClipDown-1); + y2=max(y2,Global_VDB_Ptr->VDB_ClipUp); + y2=min(y2,Global_VDB_Ptr->VDB_ClipDown-1); + + if( abs( x2 - x1 ) < abs( y2 - y1 ) ) { + if( y2 < y1 ) { + w = y1; + y1 = y2; + y2 = w; + w = x1; + x1 = x2; + x2 = w; + } + dire = x1 < x2 ? 1 : -1; + gosa = abs( x2 - x1 ); + hani = y2 - y1; + tame = hani / 2; + x = x1; + for( y = y1; y <= y2; y++ ) { + sbufferptr = + ScreenBuffer + + (y * BackBufferPitch) + x; + *sbufferptr = colour; + tame += gosa; + if( tame > hani ) { + x += dire; + tame -= hani; + } + } + } else { + if( x2 < x1 ) { + w = x1; + x1 = x2; + x2 = w; + w = y1; + y1 = y2; + y2 = w; + } + dire = y1 < y2 ? 1 : -1; + gosa = abs( y2 - y1 ); + hani = x2 - x1; + tame = hani / 2; + y = y1; + for( x = x1; x <= x2; x++ ) { + sbufferptr = + ScreenBuffer + + (y * BackBufferPitch) + x; + *sbufferptr = colour; + tame += gosa; + if( tame > hani ) { + y += dire; + tame -= hani; + } + } + } + +} + + + +/* + + Scan Convert and Draw I_GouraudPolygon + +*/ + + +void Draw_Item_GouraudPolygon(int *itemptr) +{ + if (ScanDrawMode == ScanDrawDirectDraw) + { + KDraw_Item_GouraudPolygon(itemptr); + } +} + + +void Draw_Item_2dTexturePolygon(int *itemptr) +{ + if (ScanDrawMode == ScanDrawDirectDraw) + { + KDraw_Item_2dTexturePolygon(itemptr); + } +} + +void Draw_Item_Gouraud2dTexturePolygon(int *itemptr) +{ + if (ScanDrawMode == ScanDrawDirectDraw) + { + KDraw_Item_Gouraud2dTexturePolygon(itemptr); + } +} + +void Draw_Item_Gouraud3dTexturePolygon(int *itemptr) +{ + if (ScanDrawMode == ScanDrawDirectDraw) + { + KDraw_Item_Gouraud3dTexturePolygon(itemptr); + } +} + +void Draw_Item_ZB_Gouraud3dTexturePolygon(int *itemptr) +{ +} + +void Draw_Item_ZB_GouraudPolygon(int *itemptr) +{ +} + + +void Draw_Item_ZB_2dTexturePolygon(int *itemptr) +{ +} + + +void Draw_Item_ZB_Gouraud2dTexturePolygon(int *itemptr) +{ +} + + + +void Draw_Item_ZB_3dTexturedPolygon(int *itemptr) +{ +} + + + + + + + + + + diff --git a/3dc/win95/list_tem.cpp b/3dc/win95/list_tem.cpp new file mode 100644 index 0000000..08ead10 --- /dev/null +++ b/3dc/win95/list_tem.cpp @@ -0,0 +1,28 @@ +#ifdef NDEBUG +; +#else + +char const * list_fail_get_data_from_sentinel = "%s: Tried to get data from sentinel\n"; +char const * list_fail_add_entry_after = "%s: Tried to add after a nonexistent List entry\n"; +char const * list_fail_add_entry_before = "%s: Tried to add before a nonexistent List entry\n"; +char const * list_fail_delete_entry = "%s: Tried to delete a nonexistent List entry\n"; +char const * list_fail_delete_entry_by_pointer = "%s: Tried to delete-by-pointer the sentinel of a list.\n"; +char const * list_fail_alter_entry = "%s: Tried to alter a nonexistent List entry\n"; +char const * list_fail_next_entry_nonexist = "%s: Tried to get entry after nonexistent entry."; +char const * list_fail_next_entry_sentinel = "%s: Tried to get next entry, which is sentinel."; +char const * list_fail_prev_entry_nonexist = "%s: Tried to get entry before nonexistent entry"; +char const * list_fail_prev_entry_sentinel = "%s: Tried to get previous entry, which is sentinel."; +char const * list_fail_last_entry = "%s: Tried to get last entry from a 0-length list.\n."; +char const * list_fail_first_entry = "%s: Tried to get first entry from a 0-length list.\n."; +char const * list_fail_similar_entry = "%s: Tried to get entry similar to nonexistent entry"; +char const * list_fail_delete_last_entry = "%s: Tried to delete last element from an empty List.\n"; +char const * list_fail_delete_first_entry = "%s: Tried to delete first element from an empty List.\n"; +char const * list_fail_operator = "%s: Tried to get entry %d from %d-entry list.\n"; +char const * lit_fail_next = "%s: Tried to take an Iterator past the sentinel of a List.\n"; +char const * lit_fail_operator = "%s: Tried to take contents of sentinel of List\n"; +char const * lit_fail_delete_current = "%s: Tried to delete sentinel of List\n"; +char const * lit_fail_change_current = "%s: Tried to change contents of sentinel of List\n"; + +#endif + + diff --git a/3dc/win95/list_tem.hpp b/3dc/win95/list_tem.hpp new file mode 100644 index 0000000..1bd59ef --- /dev/null +++ b/3dc/win95/list_tem.hpp @@ -0,0 +1,871 @@ +// Doubly linked list class. +// +// Inserts new entries at the *end* of the list -- so add_entry() +// followed by delete_last_entry() will do nothing. +// +// +// Usage: +// +// List l; creates an empty list. +// Thing a; List l(a); creates a list containing a. +// +// void l.add_entry(Thing a); adds an entry. +// void l.delete_entry(Thing a); removes `a' from the list if it's there, +// aborts if it's not. +// void l.delete_{first,last}_entry deletes the first/last entry. +// Thing l.{first,last}_entry returns the first/last entry. +// bool l.contains(Thing a) is a in the list? +#ifndef list_template_hpp +#define list_template_hpp + +#pragma once + +#include + +#ifdef _CPPRTTI // run time type information available + #include + #define LIST_TEM_TYPEID_THIS typeid(*this).name() +#else + #define LIST_TEM_TYPEID_THIS "?" +#endif + +#if defined(engine) +// Not all preprocessors do lazy evaluation. DW +#if engine + #include "mem3dc.h" +#endif +#endif + +#ifdef NDEBUG + #define fail if (0) + #define list_fail_get_data_from_sentinel NULL + #define list_fail_add_entry_after NULL + #define list_fail_add_entry_before NULL + #define list_fail_delete_entry NULL + #define list_fail_delete_entry_by_pointer NULL + #define list_fail_alter_entry NULL + #define list_fail_next_entry_nonexist NULL + #define list_fail_next_entry_sentinel NULL + #define list_fail_prev_entry_nonexist NULL + #define list_fail_prev_entry_sentinel NULL + #define list_fail_last_entry NULL + #define list_fail_first_entry NULL + #define list_fail_similar_entry NULL + #define list_fail_delete_last_entry NULL + #define list_fail_delete_first_entry NULL + #define list_fail_operator NULL + #define lit_fail_next NULL + #define lit_fail_operator NULL + #define lit_fail_delete_current NULL + #define lit_fail_change_current NULL +#else + #include "fail.h" + extern char const * list_fail_get_data_from_sentinel; + extern char const * list_fail_add_entry_after; + extern char const * list_fail_add_entry_before; + extern char const * list_fail_delete_entry; + extern char const * list_fail_delete_entry_by_pointer; + extern char const * list_fail_alter_entry; + extern char const * list_fail_next_entry_nonexist; + extern char const * list_fail_next_entry_sentinel; + extern char const * list_fail_prev_entry_nonexist; + extern char const * list_fail_prev_entry_sentinel; + extern char const * list_fail_last_entry; + extern char const * list_fail_first_entry; + extern char const * list_fail_similar_entry; + extern char const * list_fail_delete_last_entry; + extern char const * list_fail_delete_first_entry; + extern char const * list_fail_operator; + extern char const * lit_fail_next; + extern char const * lit_fail_operator; + extern char const * lit_fail_delete_current; + extern char const * lit_fail_change_current; +#endif + +// The first declaration of these class templates was previously as friends +// of List. However, Visual C++ 5 can't parse them unless we give a +// forward declaration first - I think this is a compiler bug - Garry. +template +class List_Iterator_Forward; +template +class ConstList_Iterator_Forward; +template +class List_Iterator_Backward; +template +class ConstList_Iterator_Backward; +template +class List_Iterator_Loop; + +template +struct List_Member; + +template +struct List_Member_Base +{ + union + { + List_Member_Base *prev; + #ifndef __WATCOMC__ + List_Member *prev_debug; // encourage the debugger to display the list members data + #endif // hopefully casting from base to derived class would not + // cause the actual value of the ptr to change, so the debugger + // will display the information correctly, and this union + // won't cause any kind of performance hit + + //watcom doesn't appear to like this, unfortunately. + + + + }; + union + { + List_Member_Base *next; + #ifndef __WATCOMC__ + List_Member *next_debug; + #endif + }; + virtual ~List_Member_Base() {} +}; + +template +struct List_Member : public List_Member_Base +{ + T data; + List_Member(const T& n) : data(n) {} +}; + +template +class List { +private: + List_Member_Base *sentinel; + int n_entries; + mutable T **entry_pointers; + mutable bool calculated_indices; + + T& data(List_Member_Base* e) const + { + if (e == sentinel) + fail(list_fail_get_data_from_sentinel,LIST_TEM_TYPEID_THIS); + return ((List_Member*)e)->data; + } + +public: + List() { + sentinel = new List_Member_Base; + + sentinel->next = sentinel; + sentinel->prev = sentinel; + + n_entries = 0; + entry_pointers = 0; + calculated_indices = false; + } + + List(const T& n) { + sentinel = new List_Member_Base; + sentinel->next = sentinel; + sentinel->prev = sentinel; + n_entries = 0; + entry_pointers = 0; + calculated_indices = false; + + add_entry(n); + } + + List(const List& l) { + sentinel = new List_Member_Base; + + sentinel->next = sentinel; + sentinel->prev = sentinel; + n_entries = 0; + + entry_pointers = 0; + calculated_indices = false; + + List_Member_Base* m = l.sentinel->next; + while (m != l.sentinel) { + add_entry(data(m)); + m = m->next; + } + + } + + List& operator= (const List& l) { + while(n_entries != 0) delete_last_entry(); + if (entry_pointers != 0) + delete[] entry_pointers; + + List_Member_Base* m = l.sentinel->next; + while (m != l.sentinel) { + add_entry(data(m)); + m = m->next; + } + calculated_indices = false; + entry_pointers = 0; + return *this; + } + + ~List() { + while (n_entries != 0) delete_last_entry(); + delete sentinel; + delete[] entry_pointers; + } + + void add_entry(const T& n) { + add_entry_end(n); + } + + void add_entry_end(const T& n) { + List_Member *e = new List_Member(n); + e->next = sentinel; + e->prev = sentinel->prev; + sentinel->prev->next = e; + sentinel->prev = e; + n_entries++; + cleanup(); + } + + void add_entry_start(const T& n) { + List_Member *e = new List_Member(n); + e->prev = sentinel; + e->next = sentinel->next; + sentinel->next->prev = e; + sentinel->next = e; + n_entries++; + cleanup(); + } + + void add_entry_after(const T& n, const T& d) { + List_Member_Base *f = sentinel->next; + while (f != sentinel && data(f) != d) { + f = f->next; + } + if (f == sentinel) { + fail(list_fail_add_entry_after,LIST_TEM_TYPEID_THIS); + } else { + List_Member *e = new List_Member(n); + e->next = f->next; + e->prev = f; + e->next->prev = e; + f->next = e; + n_entries++; + } + cleanup(); + } + + void add_entry_before(const T& n, const T& d) { + List_Member_Base *f = sentinel->next; + while (f != sentinel && data(f) != d) { + f = f->next; + } + if (f == sentinel) { + fail(list_fail_add_entry_before,LIST_TEM_TYPEID_THIS); + } else { + List_Member *e = new List_Member(n); + e->prev = f->prev; + e->next = f; + e->prev->next = e; + f->prev = e; + n_entries++; + } + cleanup(); + } + + void delete_entry(const T& d) { + List_Member_Base *e = sentinel->next; + while (e != sentinel && data(e) != d && e != sentinel) { + e = e->next; + } + if (e == sentinel) { + fail(list_fail_delete_entry,LIST_TEM_TYPEID_THIS); + } else { + e->prev->next = e->next; + e->next->prev = e->prev; + delete e; + } + n_entries--; + cleanup(); + } + + void delete_entry_backward(const T& d) { + List_Member_Base *e = sentinel->prev; + while (e != sentinel && data(e) != d && e != sentinel) { + e = e->prev; + } + if (e == sentinel) { + fail(list_fail_delete_entry,LIST_TEM_TYPEID_THIS); + } else { + e->prev->next = e->next; + e->next->prev = e->prev; + delete e; + } + n_entries--; + cleanup(); + } + + void delete_entry_by_pointer(List_Member_Base* l) { + if (l == sentinel) + fail(list_fail_delete_entry_by_pointer,LIST_TEM_TYPEID_THIS); + l->next->prev = l->prev; + l->prev->next = l->next; + delete l; + l = 0; // so we get a seg if we try and reuse it + n_entries--; + cleanup(); + } + + void alter_entry(const T& od, const T& nd) { + List_Member_Base *e = sentinel->next; + while (e != sentinel && data(e) != od) { + e = e->next; + } + if (e == sentinel) { + fail(list_fail_alter_entry,LIST_TEM_TYPEID_THIS); + } else { + // Remove this entry, and put a new one in it's place. We can't + // just do e->data = nd, because that's assignment, and we don't + // want to require an assignment operator to be defined for + // every thing that we put on a list. + List_Member * n = new List_Member(nd); + e->prev->next = n; + e->next->prev = n; + n->next = e->next; + n->prev = e->prev; + delete e; + } + cleanup(); + } + + T next_entry(const T& d) const { + List_Member_Base *e = sentinel->next; + while (e != sentinel && data(e) != d && e != sentinel) { + e = e->next; + } + if (e == sentinel) { + fail(list_fail_next_entry_nonexist,LIST_TEM_TYPEID_THIS); + } else { + if (e->next == sentinel) + fail(list_fail_next_entry_sentinel,LIST_TEM_TYPEID_THIS); + return data(e->next); + } + return data(e->next); + } + + T prev_entry(const T& d) const { + List_Member_Base *e = sentinel->next; + while (e!= sentinel && data(e) != d) { + e = e->next; + } + if (e == sentinel) { + fail(list_fail_prev_entry_nonexist,LIST_TEM_TYPEID_THIS); + } else { + if (e->prev == sentinel) + fail(list_fail_prev_entry_sentinel,LIST_TEM_TYPEID_THIS); + return data(e->prev); + } + return data(e->prev); + } + + T const & similar_entry(T const& d) const + { + List_Member_Base *e = sentinel->next; + while (e != sentinel) + { + if (data(e) == d) + break; + e = e->next; + + } + if (e == sentinel) + { + fail(list_fail_similar_entry,LIST_TEM_TYPEID_THIS); + } + return data(e); + } + + bool contains(const T& d) { + List_Member_Base *e = sentinel->next; + while (e != sentinel && data(e) != d) { + e = e->next; + } + if (e == sentinel) return false; + else return true; + } + + void delete_last_entry() { + if (sentinel->prev == sentinel) { + fail(list_fail_delete_last_entry,LIST_TEM_TYPEID_THIS); + } else { + // aiee. These lines work, but are a bit hairy. + + sentinel->prev = sentinel->prev->prev; + delete sentinel->prev->next; + sentinel->prev->next = sentinel; + n_entries--; + } + cleanup(); + } + + void delete_first_entry() { + if (sentinel->next == sentinel) { + fail(list_fail_delete_last_entry,LIST_TEM_TYPEID_THIS); + } else { + sentinel->next = sentinel->next->next; + delete sentinel->next->prev; + sentinel->next->prev = sentinel; + n_entries--; + } + cleanup(); + } + + T const & operator[](int i) const { + if (i < 0 || i >= n_entries) + fail(list_fail_operator,LIST_TEM_TYPEID_THIS, i+1, n_entries); + + if (!calculated_indices) { + if (entry_pointers != 0) + delete[] entry_pointers; + entry_pointers = new T*[n_entries+1]; + List_Member_Base*e = sentinel->next; + int j = 0; + while (e != sentinel) { + entry_pointers[j] = &data(e); + e = e->next; + j++; + } + calculated_indices = true; + } + return *entry_pointers[i]; + } + + T & last_entry() + { + if (n_entries == 0) + fail(list_fail_last_entry,LIST_TEM_TYPEID_THIS); + return data(sentinel->prev); + } + + T const & last_entry() const + { + if (n_entries == 0) + fail(list_fail_last_entry,LIST_TEM_TYPEID_THIS); + return data(sentinel->prev); + } + + T & first_entry() + { + if (n_entries == 0) + fail(list_fail_first_entry,LIST_TEM_TYPEID_THIS); + return data(sentinel->next); + } + + T const & first_entry() const + { + if (n_entries == 0) + fail(list_fail_first_entry,LIST_TEM_TYPEID_THIS); + return data(sentinel->next); + } + + int size() const { return n_entries; } + + void cleanup() { calculated_indices = false; if (entry_pointers != 0) delete[] entry_pointers; entry_pointers = 0;} + + bool operator==(const List &l1) const + { + if (n_entries != l1.n_entries) return false; + for (List_Member_Base * e = sentinel->next, *e1 = l1.sentinel->next; e != sentinel; e = e->next, e1 = e1->next) + { + if (((List_Member *)e)->data != ((List_Member *)e1)->data) return false; + } + return true; + } + + bool operator!=(const List &l1) const + { + if (n_entries != l1.n_entries) return true; + for (List_Member_Base * e = sentinel->next, *e1 = l1.sentinel->next; e != sentinel; e = e->next, e1 = e1->next) + { + if (((List_Member *)e)->data != ((List_Member *)e1)->data) return true; + } + return false; + } + + friend class List_Iterator_Forward; + friend class ConstList_Iterator_Forward; + friend class List_Iterator_Backward; + friend class ConstList_Iterator_Backward; + friend class List_Iterator_Loop; +}; + +// Use List_Iterator_{Forward,Backward} as follows: +// +// for(List_Iterator_Forward oi(&(List_of_T*)); // a _pointer_ +// // to the list. +// !oi.done(); +// oi.next() ) { +// do_something( oi() ) ; +// } +// +// First entry is the one past the sentinel, and next() and +// operator() fail if you try and iterate too far; check if it's +// done() before doing anything else, basically. +// +// As it's a doubly-linked list, we can go backwards and +// forwards. next() takes us to the entry that the type of iterator +// suggests; un_next() takes us in the other direction. un_next() is +// an ugly name, but next() and prev() are too suggestive of a +// particular direction. + +template +class List_Iterator_Forward +{ +private: + union + { + List_Member_Base *m; + List_Member *m_debug; // encourage the debugger to display the list members data + // hopefully casting from base to derived class would not + // cause the actual value of the ptr to change, so the debugger + // will display the information correctly, and this union + // won't cause any kind of performance hit + }; + List *l; + +public: + List_Iterator_Forward() {} + List_Iterator_Forward(List *list) { l = list; m = l->sentinel->next; } + + void next() { + if (m != l->sentinel) { + m = m->next; + } else + fail(lit_fail_next,LIST_TEM_TYPEID_THIS); + } + + void un_next() { + if (m != l->sentinel) { + m = m->prev; + } else + fail(lit_fail_next,LIST_TEM_TYPEID_THIS); + } + + T & operator() () const { + if (m == l->sentinel) + fail(lit_fail_operator,LIST_TEM_TYPEID_THIS); + return l->data(m); + } + + void delete_current() { + if (m != l->sentinel) { + m = m->next; + l->delete_entry_by_pointer(m->prev); + } else + fail(lit_fail_delete_current,LIST_TEM_TYPEID_THIS); + } + + void change_current(T const &new_val) const { + if (m != l->sentinel) { + // Delete the current member out of the list, put a new one in. + + List_Member * n = new List_Member(new_val); + m->prev->next = n; + m->next->prev = n; + n->next = m->next; + n->prev = m->prev; + delete m; + *(List_Member_Base **)&m =n; // or we're pointing at the thing we just deleted. + l->cleanup(); // because it's changed, but the List doesn't know that. + } else + fail(lit_fail_change_current,LIST_TEM_TYPEID_THIS); + } + + bool done() { if (m == l->sentinel) return true; else return false; } + void restart() { m = l->sentinel->next; } + // Go to the end of the list. + void end() { m = l->sentinel->prev; } +}; + +#define LIF List_Iterator_Forward + +template +class ConstList_Iterator_Forward +{ + private: + union + { + List_Member_Base *m; + List_Member *m_debug; // encourage the debugger to display the list members data + }; + List const *l; + + public: + ConstList_Iterator_Forward(List const *list) { l = list; m = l->sentinel->next; } + ConstList_Iterator_Forward(){} + + void next() { + if (m == l->sentinel) { + fail(lit_fail_next,LIST_TEM_TYPEID_THIS); + } + m = m->next; + } + + void un_next() { + if (m == l->sentinel) { + fail(lit_fail_next,LIST_TEM_TYPEID_THIS); + } + m = m->prev; + } + + T const & operator() () const { + if (m == l->sentinel) + fail(lit_fail_operator,LIST_TEM_TYPEID_THIS); + return l->data(m); + } + + #if 0 // shouldn't really be available on a const list + void change_current(T const & new_val) const { + if (m != l->sentinel) { + m->data = new_val; + } else + fail(lit_fail_change_current,LIST_TEM_TYPEID_THIS); + } + #endif + + bool done() const { if (m == l->sentinel) return true; else return false; } + void restart() { m = l->sentinel->next; } + // Go to the end of the list. + void end() { m = l->sentinel->prev; } +}; + +#define CLIF ConstList_Iterator_Forward + +template +class List_Iterator_Backward +{ +private: + union + { + List_Member_Base *m; + List_Member *m_debug; // encourage the debugger to display the list members data + }; + List *l; + +public: + List_Iterator_Backward() {} + List_Iterator_Backward(List *list) { l = list; m = l->sentinel->prev; } + + void next() { + if (m != l->sentinel) { + m = m->prev; + } else + fail(lit_fail_next,LIST_TEM_TYPEID_THIS); + } + + void un_next() { + if (m != l->sentinel) { + m = m->next; + } else + fail(lit_fail_next,LIST_TEM_TYPEID_THIS); + } + + T & operator() () const { + if (m == l->sentinel) + fail(lit_fail_operator,LIST_TEM_TYPEID_THIS); + return l->data(m); + } + + void delete_current() { + if (m != l->sentinel) { + m = m->prev; + l->delete_entry_by_pointer(m->next); + } else + fail(lit_fail_delete_current,LIST_TEM_TYPEID_THIS); + } + + void change_current(T const & new_val) { + if (m != l->sentinel) { + // Delete the current member out of the list, put a new one in. + + List_Member * n = new List_Member(new_val); + m->prev->next = n; + m->next->prev = n; + n->next = m->next; + n->prev = m->prev; + delete m; + m = n; // or we're pointing at the thing we just deleted. + l->cleanup(); // because it's changed, but the List doesn't know that. + } else + fail(lit_fail_change_current,LIST_TEM_TYPEID_THIS); + } + + bool done() { if (m == l->sentinel) return true; else return false; } + void restart() { m = l->sentinel->prev; } + // Go to the end of the list. + void end() { m = l->sentinel->prev; } +}; + +#define LIB List_Iterator_Backward + +template +class ConstList_Iterator_Backward +{ + private: + union + { + List_Member_Base *m; + List_Member *m_debug; // encourage the debugger to display the list members data + }; + List const *l; + + public: + ConstList_Iterator_Backward(List const *list) { l = list; m = l->sentinel->prev; } + ConstList_Iterator_Backward(){} + + void next() { + if (m == l->sentinel) { + fail(lit_fail_next,LIST_TEM_TYPEID_THIS); + } + m = m->prev; + } + + void un_next() { + if (m == l->sentinel) { + fail(lit_fail_next,LIST_TEM_TYPEID_THIS); + } + m = m->next; + } + + T const & operator() () const { + if (m == l->sentinel) + fail(lit_fail_operator,LIST_TEM_TYPEID_THIS); + return l->data(m); + } + + #if 0 // shouldn't really be available on a const list + void change_current(T const & new_val) const { + if (m != l->sentinel) { + m->data = new_val; + } else + fail(lit_fail_change_current,LIST_TEM_TYPEID_THIS); + } + #endif + + bool done() const { if (m == l->sentinel) return true; else return false; } + void restart() { m = l->sentinel->prev; } + // Go to the end of the list. + void end() { m = l->sentinel->prev; } +}; + +#define CLIB ConstList_Iterator_Backward + +/* + A looping list iterator class : + next from the last member will go to the first + previous from the first member will go to the last +*/ + +template +class List_Iterator_Loop +{ + private: + union + { + List_Member_Base *m; + List_Member *m_debug; // encourage the debugger to display the list members data + }; + List *l; + + public: + List_Iterator_Loop(List *list) { l = list; m = l->sentinel->next; } + + void next() { + m=m->next; + if (m == l->sentinel) { + m = m->next; + } + } + + void previous() { + m=m->prev; + if (m == l->sentinel) { + m = m->prev; + } + } + + T const & operator() () { + if (m == l->sentinel) + { + m=m->next;//needed in case iterator was created before anything was added to the list + if (m == l->sentinel) + { + fail(lit_fail_operator,LIST_TEM_TYPEID_THIS); + } + } + return l->data(m); + } + + void delete_current() { + if (m == l->sentinel) + { + m=m->next;//needed in case iterator was created before anything was added to the list + if (m == l->sentinel) + { + fail(lit_fail_delete_current,LIST_TEM_TYPEID_THIS); + } + } + m = m->next; + l->delete_entry_by_pointer(m->prev); + } + + + void change_current(T const & new_val) + { + if (m == l->sentinel) + m=m->next;//needed in case iterator was created before anything was added to the list + + if (m != l->sentinel) + { + // Delete the current member out of the list, put a new one in. + List_Member * n = new List_Member(new_val); + m->prev->next = n; + m->next->prev = n; + n->next = m->next; + n->prev = m->prev; + delete m; + m = n; // or we're pointing at the thing we just deleted. + l->cleanup(); // because it's changed, but the List doesn't know that. + } + else + fail(lit_fail_change_current,LIST_TEM_TYPEID_THIS); + } + + // Go to the start of the list. + void restart() { m = l->sentinel->next; } + + // Go to the end of the list. + void end() { m = l->sentinel->prev; } + + // Is it on the last entry. + bool at_last() const { if (m == l->sentinel->prev) return true; else return false; } + + // Get the next entry but done move the pointer. + T const & get_next() { + if (m->next == l->sentinel) + { + if (m->next->next == l->sentinel) + { + fail(lit_fail_operator,LIST_TEM_TYPEID_THIS); + } + return l->data(m->next->next); + } + return l->data(m->next); + } +}; + +#define LIL List_Iterator_Loop + +#ifdef NDEBUG + #undef fail // allow other code to have local variables called or differently scoped 'fail' +#endif + +#endif diff --git a/3dc/win95/md5.c b/3dc/win95/md5.c new file mode 100644 index 0000000..a71a3c3 --- /dev/null +++ b/3dc/win95/md5.c @@ -0,0 +1,364 @@ +/* md5.c - Functions to compute MD5 message digest of files or memory blocks + according to the definition of MD5 in RFC 1321 from April 1992. + Copyright (C) 1995 Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Written by Ulrich Drepper . */ +#define STDC_HEADERS 1 + +#include "advwin32.h" + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#if STDC_HEADERS +# include +# include +#else +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + +#include "md5.h" + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#else +# define SWAP(n) (n) +#endif + + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void +md5_init_ctx (struct md5_ctx *ctx) +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; +} + +/* Put result from CTX in first 16 bytes following RESBUF. The result must + be in little endian byte order. */ +void * +md5_read_ctx(const struct md5_ctx *ctx, void *resbuf) +{ + ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); + ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); + ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); + ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); + + return resbuf; +} + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +#ifdef _MSC_VER +#pragma warning(disable: 4701) +#endif + +int md5_stream(FILE *stream, void *resblock) +{ + /* Important: BLOCKSIZE must be a multiple of 64. */ +#define BLOCKSIZE 64 + struct md5_ctx ctx; + md5_uint32 len[2]; + char buffer[BLOCKSIZE + 72]; + size_t pad, sum; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + len[0] = 0; + len[1] = 0; + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + do + { + n = fread (buffer, 1, BLOCKSIZE - sum, stream); + + sum += n; + } + while (sum < BLOCKSIZE && n != 0); + if (n == 0 && ferror (stream)) + return 1; + + /* RFC 1321 specifies the possible length of the file up to 2^64 bits. + Here we only compute the number of bytes. Do a double word + increment. */ + len[0] += sum; + if (len[0] < sum) + ++len[1]; + + /* If end of file is reached, end the loop. */ + if (n == 0) + break; + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + md5_process_block (buffer, BLOCKSIZE, &ctx); + } + + /* We can copy 64 byte because the buffer is always big enough. FILLBUF + contains the needed bits. */ + memcpy (&buffer[sum], fillbuf, 64); + + /* Compute amount of padding bytes needed. Alignment is done to + (N + PAD) % 64 == 56 + There is always at least one byte padded. I.e. even the alignment + is correctly aligned 64 padding bytes are added. */ + pad = sum & 63; + pad = pad >= 56 ? 64 + 56 - pad : 56 - pad; + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + *(md5_uint32 *) &buffer[sum + pad] = SWAP (len[0] << 3); + *(md5_uint32 *) &buffer[sum + pad + 4] = SWAP ((len[1] << 3) + | (len[0] >> 29)); + + /* Process last bytes. */ + md5_process_block (buffer, sum + pad + 8, &ctx); + + /* Construct result in desired memory. */ + md5_read_ctx (&ctx, resblock); + return 0; +} +#ifdef _MSC_VER +#pragma warning(default: 4701) +#endif + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +md5_buffer (const char *buffer, size_t len, void *resblock) +{ + struct md5_ctx ctx; + char restbuf[64 + 72]; + size_t blocks = len & ~63; + size_t pad, rest; + + /* Initialize the computation context. */ + md5_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + md5_process_block (buffer, blocks, &ctx); + + /* REST bytes are not processed yet. */ + rest = len - blocks; + /* Copy to own buffer. */ + memcpy (restbuf, &buffer[blocks], rest); + /* Append needed fill bytes at end of buffer. We can copy 64 byte + because the buffer is always big enough. */ + memcpy (&restbuf[rest], fillbuf, 64); + + /* PAD bytes are used for padding to correct alignment. Note that + always at least one byte is padded. */ + pad = rest >= 56 ? 64 + 56 - rest : 56 - rest; + + /* Put length of buffer in *bits* in last eight bytes. */ + *(md5_uint32 *) &restbuf[rest + pad] = (md5_uint32) SWAP (len << 3); + *(md5_uint32 *) &restbuf[rest + pad + 4] = (md5_uint32) SWAP (len >> 29); + + /* Process last bytes. */ + md5_process_block (restbuf, rest + pad + 8, &ctx); + + /* Put result in desired memory area. */ + return md5_read_ctx (&ctx, resblock); +} + + +/* These are the four functions used in the four steps of the MD5 algorithm + and defined in the RFC 1321. The first function is a little bit optimized + (as found in Colin Plumbs public domain implementation). */ +/* #define FF(b, c, d) ((b & c) | (~b & d)) */ +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF (d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ + +void +md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) +{ + md5_uint32 correct_words[16]; + const md5_uint32 *words = buffer; + size_t nwords = len / sizeof (md5_uint32); + const md5_uint32 *endp = words + nwords; + md5_uint32 A = ctx->A; + md5_uint32 B = ctx->B; + md5_uint32 C = ctx->C; + md5_uint32 D = ctx->D; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (words < endp) + { + md5_uint32 *cwp = correct_words; + md5_uint32 A_save = A; + md5_uint32 B_save = B; + md5_uint32 C_save = C; + md5_uint32 D_save = D; + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithms processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we store the swapped words in the array CORRECT_WORDS. */ + +#define OP(a, b, c, d, s, T) \ + do \ + { \ + a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ + ++words; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* It is unfortunate that C does not provide an operator for + cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) + + /* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + + T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 + */ + + /* Round 1. */ + OP (A, B, C, D, 7, 0xd76aa478); + OP (D, A, B, C, 12, 0xe8c7b756); + OP (C, D, A, B, 17, 0x242070db); + OP (B, C, D, A, 22, 0xc1bdceee); + OP (A, B, C, D, 7, 0xf57c0faf); + OP (D, A, B, C, 12, 0x4787c62a); + OP (C, D, A, B, 17, 0xa8304613); + OP (B, C, D, A, 22, 0xfd469501); + OP (A, B, C, D, 7, 0x698098d8); + OP (D, A, B, C, 12, 0x8b44f7af); + OP (C, D, A, B, 17, 0xffff5bb1); + OP (B, C, D, A, 22, 0x895cd7be); + OP (A, B, C, D, 7, 0x6b901122); + OP (D, A, B, C, 12, 0xfd987193); + OP (C, D, A, B, 17, 0xa679438e); + OP (B, C, D, A, 22, 0x49b40821); + + /* For the second to fourth round we have the possibly swapped words + in CORRECT_WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +#undef OP +#define OP(f, a, b, c, d, k, s, T) \ + do \ + { \ + a += f (b, c, d) + correct_words[k] + T; \ + CYCLIC (a, s); \ + a += b; \ + } \ + while (0) + + /* Round 2. */ + OP (FG, A, B, C, D, 1, 5, 0xf61e2562); + OP (FG, D, A, B, C, 6, 9, 0xc040b340); + OP (FG, C, D, A, B, 11, 14, 0x265e5a51); + OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP (FG, A, B, C, D, 5, 5, 0xd62f105d); + OP (FG, D, A, B, C, 10, 9, 0x02441453); + OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP (FG, D, A, B, C, 14, 9, 0xc33707d6); + OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP (FG, B, C, D, A, 8, 20, 0x455a14ed); + OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP (FG, C, D, A, B, 7, 14, 0x676f02d9); + OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); + + /* Round 3. */ + OP (FH, A, B, C, D, 5, 4, 0xfffa3942); + OP (FH, D, A, B, C, 8, 11, 0x8771f681); + OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP (FH, B, C, D, A, 14, 23, 0xfde5380c); + OP (FH, A, B, C, D, 1, 4, 0xa4beea44); + OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP (FH, B, C, D, A, 6, 23, 0x04881d05); + OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); + + /* Round 4. */ + OP (FI, A, B, C, D, 0, 6, 0xf4292244); + OP (FI, D, A, B, C, 7, 10, 0x432aff97); + OP (FI, C, D, A, B, 14, 15, 0xab9423a7); + OP (FI, B, C, D, A, 5, 21, 0xfc93a039); + OP (FI, A, B, C, D, 12, 6, 0x655b59c3); + OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP (FI, C, D, A, B, 10, 15, 0xffeff47d); + OP (FI, B, C, D, A, 1, 21, 0x85845dd1); + OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP (FI, C, D, A, B, 6, 15, 0xa3014314); + OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP (FI, A, B, C, D, 4, 6, 0xf7537e82); + OP (FI, D, A, B, C, 11, 10, 0xbd3af235); + OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP (FI, B, C, D, A, 9, 21, 0xeb86d391); + + /* Add the starting values of the context. */ + A += A_save; + B += B_save; + C += C_save; + D += D_save; + } + + /* Put checksum in context given as argument. */ + ctx->A = A; + ctx->B = B; + ctx->C = C; + ctx->D = D; +} diff --git a/3dc/win95/md5.h b/3dc/win95/md5.h new file mode 100644 index 0000000..2306a7e --- /dev/null +++ b/3dc/win95/md5.h @@ -0,0 +1,125 @@ + +#ifdef __cplusplus +extern "C"{ +#endif + +/* md5.h - Declaration of functions and data types used for MD5 sum + computing library functions. + Copyright (C) 1995 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _MD5_H +#define _MD5_H + +#include + +#if defined HAVE_LIMITS_H || _LIBC +# include +#endif + +/* The following contortions are an attempt to use the C preprocessor + to determine an unsigned integral type that is 32 bits wide. An + alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but + doing that would require that the configure script compile and *run* + the resulting executable. Locally running cross-compiled executables + is usually not possible. */ + +#if defined __STDC__ && __STDC__ +# define UINT_MAX_32_BITS 4294967295U +#else +# define UINT_MAX_32_BITS 0xFFFFFFFF +#endif + +/* If UINT_MAX isn't defined, assume it's a 32-bit type. + This should be valid for all systems GNU cares about because + that doesn't include 16-bit systems, and only modern systems + (that certainly have ) have 64+-bit integral types. */ + +#ifndef UINT_MAX +# define UINT_MAX UINT_MAX_32_BITS +#endif + +#if UINT_MAX == UINT_MAX_32_BITS + typedef unsigned int md5_uint32; +#else +# if USHRT_MAX == UINT_MAX_32_BITS + typedef unsigned short md5_uint32; +# else +# if ULONG_MAX == UINT_MAX_32_BITS + typedef unsigned long md5_uint32; +# else + /* The following line is intended to evoke an error. + Using #error is not portable enough. */ + "Cannot determine unsigned 32-bit data type." +# endif +# endif +#endif + +#undef __P +#if defined (__STDC__) && __STDC__ +#define __P(x) x +#else +#define __P(x) () +#endif + +/* Structure to save state of computation between the single steps. */ +struct md5_ctx +{ + md5_uint32 A; + md5_uint32 B; + md5_uint32 C; + md5_uint32 D; +}; + +/* + * The following three functions are build up the low level used in + * the functions `md5_stream' and `md5_buffer'. + */ + +/* Initialize structure containing state of computation. + (RFC 1321, 3.3: Step 3) */ +void md5_init_ctx __P ((struct md5_ctx *ctx)); + +/* Starting with the result of former calls of this function (or the + initialzation function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +void md5_process_block __P ((const void *buffer, size_t len, + struct md5_ctx *ctx)); + +/* Put result from CTX in first 16 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. */ +void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf)); + + +/* Compute MD5 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int md5_stream __P ((FILE *stream, void *resblock)); + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +//void *md5_buffer __P((const char *buffer, size_t len, void *resblock)); +void *md5_buffer (const char *buffer, size_t len, void *resblock); +#endif + +#ifdef __cplusplus +}; +#endif + diff --git a/3dc/win95/media.cpp b/3dc/win95/media.cpp new file mode 100644 index 0000000..acb1427 --- /dev/null +++ b/3dc/win95/media.cpp @@ -0,0 +1,556 @@ +#include "advwin32.h" +#include "media.hpp" + +void * MediaMedium::GetWriteBuffer(unsigned * pSize, unsigned /*nDesiredSize*/) +{ + *pSize = 0; + m_fError |= MME_UNAVAIL; + return NULL; +} + +void const * MediaMedium::GetReadBuffer(unsigned * pSize, unsigned /*nDesiredSize*/) +{ + *pSize = 0; + m_fError |= MME_UNAVAIL; + return NULL; +} + +void MediaMedium::CloseWriteBuffer(unsigned /*nPosOffset*/) +{ + m_fError |= MME_UNAVAIL; +} + +void MediaMedium::CloseReadBuffer(unsigned /*nPosOffset*/) +{ + m_fError |= MME_UNAVAIL; +} + +void MediaMedium::DoWriteBlock(void const * /*pData*/, unsigned /*nSize*/) +{ + m_fError |= MME_UNAVAIL; +} + +void MediaMedium::DoReadBlock(void * /*pData*/, unsigned /*nSize*/) +{ + m_fError |= MME_UNAVAIL; +} + +unsigned MediaMedium::GetRemainingSize() +{ + return UINT_MAX; +} + +// MediaWinFileMedium + +#ifdef _MEDIA_WIN_TARGET + +unsigned MediaWinFileMedium::GetRemainingSize() +{ + if (INVALID_HANDLE_VALUE == m_hFile) + { + m_fError |= MME_UNAVAIL; + return 0; + } + + unsigned nSize = GetFileSize(m_hFile,NULL); + + if (0xffffffff == nSize) + { + m_fError |= MME_UNAVAIL; + return 0; + } + + return nSize - GetPos(); +} + +void * MediaWinFileMedium::GetWriteBuffer(unsigned * pSize, unsigned nDesiredSize) +{ + m_pBuffer = new char [nDesiredSize]; + *pSize = nDesiredSize; + return m_pBuffer; +} + +void const * MediaWinFileMedium::GetReadBuffer(unsigned * pSize, unsigned nDesiredSize) +{ + if (INVALID_HANDLE_VALUE == m_hFile) + // the base/default implementation raises an error + return MediaMedium::GetReadBuffer(pSize,nDesiredSize); + + m_pBuffer = new char [nDesiredSize]; + + DWORD nBytesRead = 0; + + if (!ReadFile(m_hFile, m_pBuffer, nDesiredSize, &nBytesRead, NULL)) + m_fError |= MME_IOERROR; + else if (!nBytesRead) + m_fError |= MME_EOFMET; + + *pSize = m_nReadBufLen = nBytesRead; + + return m_pBuffer; +} + +void MediaWinFileMedium::CloseWriteBuffer(unsigned nPosOffset) +{ + if (INVALID_HANDLE_VALUE == m_hFile) + { + // the base/default implementation raises an error + MediaMedium::CloseWriteBuffer(nPosOffset); + return; + } + + DWORD nBytesWritten = 0; + + if (!WriteFile(m_hFile, m_pBuffer, nPosOffset, &nBytesWritten, NULL)) + m_fError |= MME_IOERROR; + else if (nBytesWritten < nPosOffset) + m_fError |= MME_EOFMET; + + delete [] m_pBuffer; +} + +void MediaWinFileMedium::CloseReadBuffer(unsigned nPosOffset) +{ + if (INVALID_HANDLE_VALUE == m_hFile) + { + // the base/default implementation raises an error + MediaMedium::CloseReadBuffer(nPosOffset); + return; + } + + if (nPosOffset != m_nReadBufLen && 0xffffffff == SetFilePointer(m_hFile,nPosOffset - m_nReadBufLen,NULL,FILE_CURRENT)) + m_fError |= MME_UNAVAIL; + + m_nReadBufLen = 0; + + delete [] m_pBuffer; +} + +void MediaWinFileMedium::DoWriteBlock(void const * pData, unsigned nSize) +{ + if (INVALID_HANDLE_VALUE == m_hFile) + { + MediaMedium::DoWriteBlock(pData,nSize); + return; + } + + DWORD nBytesWritten = 0; + + if (!WriteFile(m_hFile, pData, nSize, &nBytesWritten, NULL)) + m_fError |= MME_IOERROR; + else if (nBytesWritten < nSize) + m_fError |= MME_EOFMET; +} + +void MediaWinFileMedium::DoReadBlock(void * pData, unsigned nSize) +{ + if (INVALID_HANDLE_VALUE == m_hFile) + { + MediaMedium::DoReadBlock(pData,nSize); + return; + } + + DWORD nBytesRead = 0; + + if (!ReadFile(m_hFile, pData, nSize, &nBytesRead, NULL)) + m_fError |= MME_IOERROR; + else if (nBytesRead < nSize) + m_fError |= MME_EOFMET; +} + +unsigned MediaWinFileMedium::DoGetPos() +{ + unsigned nFilePos = SetFilePointer(m_hFile,0,NULL,FILE_CURRENT); + + if (0xffffffff == nFilePos) + { + m_fError |= MME_UNAVAIL; + return 0; + } + + return nFilePos - m_nReadBufLen; +} + +void MediaWinFileMedium::DoSetPos(unsigned nPos) +{ + if (0xffffffff == SetFilePointer(m_hFile,nPos,NULL,FILE_BEGIN)) + m_fError |= MME_UNAVAIL; +} + +#endif // _MEDIA_WIN_TARGET + +// MediaStdFileMedium + +unsigned MediaStdFileMedium::GetRemainingSize() +{ + if (!m_pFile) + { + m_fError |= MME_UNAVAIL; + return 0; + } + + long nPos = ftell(m_pFile); + + if (-1L == nPos || fseek(m_pFile,0,SEEK_END)) + { + m_fError |= MME_UNAVAIL; + return 0; + } + + long nSize = ftell(m_pFile); + + fseek(m_pFile,nPos,SEEK_SET); + + if (-1L == nSize) + { + m_fError |= MME_UNAVAIL; + return 0; + } + + return nSize - GetPos(); +} + +void * MediaStdFileMedium::GetWriteBuffer(unsigned * pSize, unsigned nDesiredSize) +{ + m_pBuffer = new char [nDesiredSize]; + *pSize = nDesiredSize; + return m_pBuffer; +} + +void const * MediaStdFileMedium::GetReadBuffer(unsigned * pSize, unsigned nDesiredSize) +{ + if (!m_pFile) + // the base/default implementation raises an error + return MediaMedium::GetReadBuffer(pSize,nDesiredSize); + + m_pBuffer = new char [nDesiredSize]; + + *pSize = m_nReadBufLen = fread(m_pBuffer, 1, nDesiredSize, m_pFile); + + if (!m_nReadBufLen) + { + if (feof(m_pFile)) + m_fError |= MME_EOFMET; + else + m_fError |= MME_IOERROR; + } + + return m_pBuffer; +} + +void MediaStdFileMedium::CloseWriteBuffer(unsigned nPosOffset) +{ + if (!m_pFile) + { + // the base/default implementation raises an error + MediaMedium::CloseWriteBuffer(nPosOffset); + return; + } + + if (fwrite(m_pBuffer, 1, nPosOffset, m_pFile) < nPosOffset) + { + if (feof(m_pFile)) + m_fError |= MME_EOFMET; + else + m_fError |= MME_IOERROR; + } + + delete [] m_pBuffer; +} + +void MediaStdFileMedium::CloseReadBuffer(unsigned nPosOffset) +{ + if (!m_pFile) + { + // the base/default implementation raises an error + MediaMedium::CloseReadBuffer(nPosOffset); + return; + } + + if (nPosOffset != m_nReadBufLen && fseek(m_pFile,nPosOffset - m_nReadBufLen,SEEK_CUR)) + m_fError |= MME_UNAVAIL; + + m_nReadBufLen = 0; + delete [] m_pBuffer; +} + +void MediaStdFileMedium::DoWriteBlock(void const * pData, unsigned nSize) +{ + if (!m_pFile) + { + MediaMedium::DoWriteBlock(pData,nSize); + return; + } + + if (fwrite(pData, 1, nSize, m_pFile) < nSize) + { + if (feof(m_pFile)) + m_fError |= MME_EOFMET; + else + m_fError |= MME_IOERROR; + } +} + +void MediaStdFileMedium::DoReadBlock(void * pData, unsigned nSize) +{ + if (!m_pFile) + { + MediaMedium::DoReadBlock(pData,nSize); + return; + } + + if (fread(pData, 1, nSize, m_pFile) < nSize) + { + if (feof(m_pFile)) + m_fError |= MME_EOFMET; + else + m_fError |= MME_IOERROR; + } +} + +unsigned MediaStdFileMedium::DoGetPos() +{ + long nFilePos = ftell(m_pFile); + + if (-1L == nFilePos) + { + m_fError |= MME_UNAVAIL; + return 0; + } + + return nFilePos - m_nReadBufLen; +} + +void MediaStdFileMedium::DoSetPos(unsigned nPos) +{ + if (fseek(m_pFile,nPos,SEEK_SET)) + m_fError |= MME_UNAVAIL; +} + +// MediaMemoryReadMedium + +void const * MediaMemoryReadMedium::GetReadBuffer(unsigned * pSize, unsigned nDesiredSize) +{ + if (!m_pMem) + // the base/default implementation raises an error + return MediaMedium::GetReadBuffer(pSize,nDesiredSize); + + *pSize = nDesiredSize; + + return static_cast(m_pMem)+m_nOffset/sizeof(char); +} + +void MediaMemoryReadMedium::CloseReadBuffer(unsigned nPosOffset) +{ + if (!m_pMem) + { + // the base/default implementation raises an error + MediaMedium::CloseReadBuffer(nPosOffset); + return; + } + + m_nOffset += nPosOffset; +} + +void MediaMemoryReadMedium::DoReadBlock(void * pData, unsigned nSize) +{ + if (!m_pMem) + { + MediaMedium::DoReadBlock(pData,nSize); + return; + } + + memcpy(pData,static_cast(m_pMem)+m_nOffset/sizeof(char),nSize); + + m_nOffset += nSize; +} + +unsigned MediaMemoryReadMedium::DoGetPos() +{ + return m_nOffset; +} + +void MediaMemoryReadMedium::DoSetPos(unsigned nPos) +{ + m_nOffset = nPos; +} + +// MediaMemoryMedium + +void * MediaMemoryMedium::GetWriteBuffer(unsigned * pSize, unsigned nDesiredSize) +{ + if (!m_pMem) + // the base/default implementation raises an error + return MediaMedium::GetWriteBuffer(pSize,nDesiredSize); + + *pSize = nDesiredSize; + + return static_cast(m_pMem)+m_nOffset/sizeof(char); +} + +void MediaMemoryMedium::CloseWriteBuffer(unsigned nPosOffset) +{ + if (!m_pMem) + { + // the base/default implementation raises an error + MediaMedium::CloseWriteBuffer(nPosOffset); + return; + } + + m_nOffset += nPosOffset; +} + +void MediaMemoryMedium::DoWriteBlock(void const * pData, unsigned nSize) +{ + if (!m_pMem) + { + MediaMedium::DoWriteBlock(pData,nSize); + return; + } + + memcpy(static_cast(m_pMem)+m_nOffset/sizeof(char),pData,nSize); + + m_nOffset += nSize; +} + +// MediaSection + +unsigned MediaSection::GetRemainingSize() +{ + if (!m_pMedium) + { + m_fError |= MME_UNAVAIL; + return 0; + } + + unsigned nSectionSize = m_nMaxSize - GetPos(); + unsigned nMediaSize = m_pMedium->GetRemainingSize(); + m_fError |= m_pMedium->m_fError; + + return nSectionSize < nMediaSize ? nSectionSize : nMediaSize; +} + +void * MediaSection::GetWriteBuffer(unsigned * pSize, unsigned nDesiredSize) +{ + if (!m_pMedium) + return MediaMedium::GetWriteBuffer(pSize,nDesiredSize); + + if (m_nPos + nDesiredSize > m_nMaxSize) + { + nDesiredSize = m_nMaxSize - m_nPos; + } + + void * p = m_pMedium->GetWriteBuffer(pSize,nDesiredSize); + m_fError |= m_pMedium->m_fError; + return p; +} + +void const * MediaSection::GetReadBuffer(unsigned * pSize, unsigned nDesiredSize) +{ + if (!m_pMedium) + return MediaMedium::GetReadBuffer(pSize,nDesiredSize); + + if (m_nPos + nDesiredSize > m_nMaxSize) + { + nDesiredSize = m_nMaxSize - m_nPos; + } + + void const * p = m_pMedium->GetReadBuffer(pSize,nDesiredSize); + m_fError |= m_pMedium->m_fError; + return p; +} + +void MediaSection::CloseWriteBuffer(unsigned nPosOffset) +{ + if (!m_pMedium) + { + MediaMedium::CloseWriteBuffer(nPosOffset); + return; + } + + m_nPos += nPosOffset; + + m_pMedium->CloseWriteBuffer(nPosOffset); + m_fError |= m_pMedium->m_fError; +} + +void MediaSection::CloseReadBuffer(unsigned nPosOffset) +{ + if (!m_pMedium) + { + MediaMedium::CloseReadBuffer(nPosOffset); + return; + } + + m_nPos += nPosOffset; + + m_pMedium->CloseReadBuffer(nPosOffset); + m_fError |= m_pMedium->m_fError; +} + +void MediaSection::DoWriteBlock(void const * pData, unsigned nSize) +{ + if (!m_pMedium) + { + MediaMedium::DoWriteBlock(pData,nSize); + return; + } + + if (m_nPos + nSize > m_nMaxSize) + { + m_fError |= MME_VEOFMET; + return; + } + + m_nPos += nSize; + + m_pMedium->DoWriteBlock(pData,nSize); + m_fError |= m_pMedium->m_fError; +} + +void MediaSection::DoReadBlock(void * pData, unsigned nSize) +{ + if (!m_pMedium) + { + MediaMedium::DoReadBlock(pData,nSize); + return; + } + + if (m_nPos + nSize > m_nMaxSize) + { + m_fError |= MME_VEOFMET; + return; + } + + m_nPos += nSize; + + m_pMedium->DoReadBlock(pData,nSize); + m_fError |= m_pMedium->m_fError; +} + +unsigned MediaSection::DoGetPos() +{ + return m_nPos; +} + +void MediaSection::DoSetPos(unsigned nPos) +{ + if (!m_pMedium) + { + m_fError |= MME_UNAVAIL; + return; + } + + if (nPos > m_nMaxSize) + { + m_fError |= MME_VEOFMET; + return; + } + + m_pMedium->DoSetPos(m_pMedium->DoGetPos()+nPos-m_nPos); + if (m_nPos > m_nUsedPos) m_nUsedPos = m_nPos; + m_nPos = nPos; + + m_fError |= m_pMedium->m_fError; +} + diff --git a/3dc/win95/media.hpp b/3dc/win95/media.hpp new file mode 100644 index 0000000..73f36b7 --- /dev/null +++ b/3dc/win95/media.hpp @@ -0,0 +1,681 @@ +#ifndef _INCLUDED_MEDIA_HPP_ +#define _INCLUDED_MEDIA_HPP_ + +#if defined(_WIN32) || defined(WIN32) || defined(WINDOWS) || defined(_WINDOWS) + #define _MEDIA_WIN_TARGET + #include +#endif // WIN32 || _WIN32 || WINDOWS || _WINDOWS + +#include +#include +#include +#include + +class MediaMedium; + +// use this to read in simple data types +// note especially that if the size of TYPE is greater than the +// default buffer size, then the operation will fail +// and the virtual end of file error flag will be set +// - use ReadBlock instead +template +void MediaRead(MediaMedium * pThis, TYPE * p); + +// use this to write simple data types +// note especially that if the size of TYPE is greater than the +// default buffer size, then the operation will fail +// and the virtual end of file error flag will be set +// - use WriteBlock instead +template +void MediaWrite(MediaMedium * pThis, TYPE d); + +#ifdef __WATCOMC__ +template class _Media_CompilerHack; +#endif + +class MediaMedium +{ + protected: + // standard constructor + MediaMedium() : m_nRefCnt(1), + m_fError(0), m_nDefBufSize(1024), + m_nWriteBufPos(0), m_nReadBufPos(0), + m_nBufLenUsed(0), m_nBufSize(0), + m_pReadBuffer(NULL), m_pWriteBuffer(NULL) {} + + virtual ~MediaMedium() {} + + public: + // allow reference counting + unsigned AddRef() { return ++m_nRefCnt; } + unsigned Release() { if (0==(--m_nRefCnt)) { delete this; return 0;} else return m_nRefCnt; } + + enum + { + // error code flags + MME_VEOFMET = 0x00000001 // virtual end of file met + ,MME_EOFMET = 0x00000002 // actual end of file met + ,MME_OPENFAIL = 0x00000004 // failed to open medium + ,MME_CLOSEFAIL = 0x00000008 // failed to close medium + ,MME_UNAVAIL = 0x00000010 // requested operation was not available + ,MME_IOERROR = 0x00000020 // read/write operation failed + }; + unsigned m_fError; + + unsigned m_nDefBufSize; // default read or write buffer sizes for buffering small objects + + // flush read/write buffers. You should call this function after the last read or write operation on the object + // alternatively, derived (implementation) classes close methods should call this + void Flush() + { + if (m_pReadBuffer) + { + unsigned nBufStartPos = DoGetPos(); + CloseReadBuffer(m_nReadBufPos > m_nBufLenUsed ? m_nReadBufPos : m_nBufLenUsed); + DoSetPos(nBufStartPos + m_nReadBufPos); + m_pReadBuffer = NULL; + m_nReadBufPos = 0; + } + else if (m_pWriteBuffer) + { + unsigned nBufStartPos = DoGetPos(); + CloseWriteBuffer(m_nWriteBufPos > m_nBufLenUsed ? m_nWriteBufPos : m_nBufLenUsed); + DoSetPos(nBufStartPos + m_nWriteBufPos); + m_pWriteBuffer = NULL; + m_nWriteBufPos = 0; + } + m_nBufSize = 0; + m_nBufLenUsed = 0; + } + + // use this to write a block of raw data + void WriteBlock(void const * pData, unsigned nSize) + { + Flush(); + DoWriteBlock(pData,nSize); + } + + // this may be faster, but will only work if the block size no more than the default buffer size + void WriteBufferedBlock(void const * pData, unsigned nSize) + { + if (m_nWriteBufPos + nSize <= m_nBufSize) + { + memcpy(static_cast(m_pWriteBuffer) + m_nWriteBufPos/sizeof(char), pData, nSize); + m_nWriteBufPos += nSize; + } + else + { + Flush(); + m_pWriteBuffer = GetWriteBuffer(&m_nBufSize,m_nDefBufSize); + if (nSize <= m_nBufSize) + { + memcpy(m_pWriteBuffer, pData, nSize); + m_nWriteBufPos = nSize; + } + else + { + m_fError |= MME_VEOFMET; + } + } + } + + // use this to read a block of raw data + void ReadBlock(void * pData, unsigned nSize) + { + Flush(); + DoReadBlock(pData,nSize); + } + + // this may be faster, but will only work if the block size no more than the default buffer size + void ReadBufferedBlock(void * pData, unsigned nSize) + { + if (m_nReadBufPos + nSize <= m_nBufSize) + { + memcpy(pData, static_cast(m_pReadBuffer) + m_nReadBufPos/sizeof(char), nSize); + m_nReadBufPos += nSize; + } + else + { + Flush(); + m_pReadBuffer = GetReadBuffer(&m_nBufSize,m_nDefBufSize); + if (nSize <= m_nBufSize) + { + memcpy(pData, m_pReadBuffer, nSize); + m_nReadBufPos = nSize; + } + else + { + m_fError |= MME_VEOFMET; + } + } + } + + // move the 'file' pointer nOffset bytes + // this will not necessarily cause buffers to be flushed + // if the pointer can be moved within the current buffer, + // some of the buffer may be left uninitialized, and no + // error will occur, which otherwise might (particularly + // if the object has write access) + void MovePos(signed nOffset) + { + if (m_pReadBuffer) + { + if (nOffset>0 && m_nReadBufPos+nOffset<=m_nBufSize) + { + m_nReadBufPos+=nOffset; + return; + } + else if (nOffset<=0 && m_nReadBufPos>=static_cast(-nOffset)) + { + if (m_nBufLenUsed < m_nReadBufPos) m_nBufLenUsed = m_nReadBufPos; + m_nReadBufPos+=nOffset; + return; + } + } + else if (m_pWriteBuffer) + { + if (nOffset>0 && m_nWriteBufPos+nOffset<=m_nBufSize) + { + m_nWriteBufPos+=nOffset; + return; + } + else if (nOffset<=0 && m_nWriteBufPos>=static_cast(-nOffset)) + { + if (m_nBufLenUsed < m_nWriteBufPos) m_nBufLenUsed = m_nWriteBufPos; + m_nWriteBufPos+=nOffset; + return; + } + } + // else + Flush(); + DoSetPos(DoGetPos()+nOffset); + } + + // set the 'file' pointer + // you would normally only pass values which have been + // previously returned by a call to GetPos + // note that this will not necessarily cause buffers to be flushed + // if the pointer can be moved within the current buffer, + // some of the buffer may be left uninitialized, and no + // error will occur, which otherwise might (particularly + // if the object has write access) + void SetPos(unsigned nPos) + { + unsigned nNewBufPos = nPos - DoGetPos(); + if (nNewBufPos <= m_nBufSize) + { + if (m_pReadBuffer) + { + if (m_nBufLenUsed < m_nReadBufPos) m_nBufLenUsed = m_nReadBufPos; + m_nReadBufPos = nNewBufPos; + } + else // pWriteBuffer + { + if (m_nBufLenUsed < m_nWriteBufPos) m_nBufLenUsed = m_nWriteBufPos; + m_nWriteBufPos = nNewBufPos; + } + } + else + { + Flush(); + DoSetPos(nPos); + } + } + + // get the 'file' pointer. The returned value + // can be used in a call to SetPos + unsigned GetPos() + { + return DoGetPos()+m_nReadBufPos+m_nWriteBufPos; + } + + virtual unsigned GetRemainingSize(); + + private: + void * m_pWriteBuffer; + void const * m_pReadBuffer; + unsigned m_nReadBufPos; + unsigned m_nWriteBufPos; + unsigned m_nBufSize; + unsigned m_nBufLenUsed; + + unsigned m_nRefCnt; + + protected: + + // the non-pure functions default implementation sets the unavailable error flag + + // it is safe to assume that these four functions will be called in a logical order + // and that only one buffer (read or write) will be required at once + + // this two functions may return NULL only if *pSize is set to zero + // *pSize should otherwise be set to the actual size of the buffer returned + + // get a pointer to memory where data can be written to directly + virtual void * GetWriteBuffer(unsigned * pSize, unsigned nDesiredSize); + + // get a pointer to memory where data can be read from directly + virtual void const * GetReadBuffer(unsigned * pSize, unsigned nDesiredSize); + + // close the buffer 'allocated' above and assume nPosOffset bytes were transferred + // and that the 'file' pointer should be positioned at the end of the transferred data + virtual void CloseWriteBuffer(unsigned nPosOffset); + virtual void CloseReadBuffer(unsigned nPosOffset); + + // transfer a block of data + // it is safe to assume that no buffer will be open + virtual void DoWriteBlock(void const * pData, unsigned nSize); + virtual void DoReadBlock(void * pData, unsigned nSize); + + // if a buffer is open, should return pos at start of buffer + virtual unsigned DoGetPos() = 0; + + // it is safe to assume that no buffer will be open + virtual void DoSetPos(unsigned nPos) = 0; + + friend class MediaSection; + + friend class _Media_CompilerHack; +}; + +#ifdef __WATCOMC__ +template +#endif +class _Media_CompilerHack +{ + public: + #ifndef __WATCOMC__ + template + #endif + static inline void MediaRead(MediaMedium * pThis, TYPE * p) + { + if (pThis->m_nReadBufPos + sizeof(TYPE) <= pThis->m_nBufSize) + { + *p = *reinterpret_cast(static_cast(pThis->m_pReadBuffer) + pThis->m_nReadBufPos/sizeof(char)); + + pThis->m_nReadBufPos += sizeof(TYPE); + } + else + { + pThis->Flush(); + pThis->m_pReadBuffer = pThis->GetReadBuffer(&pThis->m_nBufSize,pThis->m_nDefBufSize); + if (sizeof(TYPE) <= pThis->m_nBufSize) + { + *p = *static_cast(pThis->m_pReadBuffer); + pThis->m_nReadBufPos = sizeof(TYPE); + } + else + { + pThis->m_fError |= MediaMedium::MME_VEOFMET; + } + } + } + + #ifndef __WATCOMC__ + template + #endif + static inline void MediaWrite(MediaMedium * pThis, TYPE d) + { + if (pThis->m_nWriteBufPos + sizeof(TYPE) <= pThis->m_nBufSize) + { + *reinterpret_cast(static_cast(pThis->m_pWriteBuffer) + pThis->m_nWriteBufPos/sizeof(char)) = d; + + pThis->m_nWriteBufPos += sizeof(TYPE); + } + else + { + pThis->Flush(); + pThis->m_pWriteBuffer = pThis->GetWriteBuffer(&pThis->m_nBufSize,pThis->m_nDefBufSize); + if (sizeof(TYPE) <= pThis->m_nBufSize) + { + *static_cast(pThis->m_pWriteBuffer) = d; + pThis->m_nWriteBufPos = sizeof(TYPE); + } + else + { + pThis->m_fError |= MediaMedium::MME_VEOFMET; + } + } + } +}; + +// use this to read in simple data types +// note especially that if the size of TYPE is greater than the +// default buffer size, then the operation will fail +// and the virtual end of file error flag will be set +// - use ReadBlock instead +template +inline void MediaRead(MediaMedium * pThis, TYPE * p) +{ + _Media_CompilerHack + #ifdef __WATCOMC__ + + #endif + ::MediaRead(pThis,p); +} + +// use this to write simple data types +// note especially that if the size of TYPE is greater than the +// default buffer size, then the operation will fail +// and the virtual end of file error flag will be set +// - use WriteBlock instead +template +inline void MediaWrite(MediaMedium * pThis, TYPE d) +{ + _Media_CompilerHack + #ifdef __WATCOMC__ + + #endif + ::MediaWrite(pThis,d); +} + +#ifdef _MEDIA_WIN_TARGET + +class MediaWinFileMedium : public MediaMedium +{ + public: + MediaWinFileMedium() : m_hFile(INVALID_HANDLE_VALUE), m_nReadBufLen(0) {} + + void Attach(HANDLE hFile) + { + m_hFile = hFile; + } + void Detach() + { + Flush(); + m_hFile = INVALID_HANDLE_VALUE; + } + + void Open(LPCTSTR pszFileName, DWORD dwDesiredAccess) + { + DWORD dwShareMode; + DWORD dwCreationDistribution; + switch (dwDesiredAccess & (GENERIC_READ|GENERIC_WRITE)) + { + case 0: + dwShareMode = FILE_SHARE_READ|FILE_SHARE_WRITE; + dwCreationDistribution = OPEN_EXISTING; + break; + case GENERIC_READ: + dwShareMode = FILE_SHARE_READ; + dwCreationDistribution = OPEN_EXISTING; + break; + case GENERIC_WRITE: + dwShareMode = 0; + dwCreationDistribution = CREATE_ALWAYS; + break; + default: // GENERIC_WRITE|GENERIC_READ + dwCreationDistribution = OPEN_ALWAYS; + dwShareMode = 0; + } + m_hFile = CreateFile + ( + pszFileName, + dwDesiredAccess, + dwShareMode, + NULL, + dwCreationDistribution, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + if (INVALID_HANDLE_VALUE == m_hFile) + m_fError |= MME_OPENFAIL; + } + void Close() + { + if (INVALID_HANDLE_VALUE == m_hFile) + m_fError |= MME_CLOSEFAIL; + else + { + Flush(); + if (!CloseHandle(m_hFile)) + m_fError |= MME_CLOSEFAIL; + else + m_hFile = INVALID_HANDLE_VALUE; + } + } + + ~MediaWinFileMedium() + { + // should already be closed... + Close(); + } + + virtual unsigned GetRemainingSize(); + + private: + HANDLE m_hFile; + + char * m_pBuffer; + unsigned m_nReadBufLen; + + protected: + + // get a pointer to memory where data can be written to directly + virtual void * GetWriteBuffer(unsigned * pSize, unsigned nDesiredSize); + + // get a pointer to memory where data can be read from directly + virtual void const * GetReadBuffer(unsigned * pSize, unsigned nDesiredSize); + + // close the buffer allocated above and assume nPosOffset were transferred + virtual void CloseWriteBuffer(unsigned nPosOffset); + virtual void CloseReadBuffer(unsigned nPosOffset); + + // transfer a block of data: the buffer should be closed + virtual void DoWriteBlock(void const * pData, unsigned nSize); + virtual void DoReadBlock(void * pData, unsigned nSize); + + // if a buffer is open, should return pos at start of buffer + virtual unsigned DoGetPos(); + + // requires that no buffer is oben + virtual void DoSetPos(unsigned nPos); +}; + +#endif // _MEDIA_WIN_TARGET + +class MediaStdFileMedium : public MediaMedium +{ + public: + MediaStdFileMedium() : m_pFile(NULL), m_nReadBufLen(0) {} + + void Attach(FILE * pFile) + { + m_pFile = pFile; + } + void Detach() + { + Flush(); + m_pFile = NULL; + } + + void Open(char const * pszFileName, char const * pszOpenMode) + { + m_pFile = fopen(pszFileName,pszOpenMode); + if (!m_pFile) + m_fError |= MME_OPENFAIL; + } + void Close() + { + if (!m_pFile) + m_fError |= MME_CLOSEFAIL; + else + { + Flush(); + if (fclose(m_pFile)) + m_fError |= MME_CLOSEFAIL; + else + m_pFile = NULL; + } + } + + ~MediaStdFileMedium() + { + // should already be closed... + Close(); + } + + virtual unsigned GetRemainingSize(); + + private: + FILE * m_pFile; + + char * m_pBuffer; + unsigned m_nReadBufLen; + + protected: + + // get a pointer to memory where data can be written to directly + virtual void * GetWriteBuffer(unsigned * pSize, unsigned nDesiredSize); + + // get a pointer to memory where data can be read from directly + virtual void const * GetReadBuffer(unsigned * pSize, unsigned nDesiredSize); + + // close the buffer allocated above and assume nPosOffset were transferred + virtual void CloseWriteBuffer(unsigned nPosOffset); + virtual void CloseReadBuffer(unsigned nPosOffset); + + // transfer a block of data: the buffer should be closed + virtual void DoWriteBlock(void const * pData, unsigned nSize); + virtual void DoReadBlock(void * pData, unsigned nSize); + + // if a buffer is open, should return pos at start of buffer + virtual unsigned DoGetPos(); + + // requires that no buffer is oben + virtual void DoSetPos(unsigned nPos); +}; + +class MediaMemoryReadMedium : public MediaMedium +{ + public: + MediaMemoryReadMedium() : m_pMem(NULL) {} + + void Open(void const * p) + { + m_pMem = p; + m_nOffset = 0; + } + + void Close() + { + if (m_pMem) + { + Flush(); + m_pMem = NULL; + } + else + m_fError |= MME_CLOSEFAIL; + } + + private: + void const * m_pMem; + + protected: + unsigned m_nOffset; + + // get a pointer to memory where data can be read from directly + virtual void const * GetReadBuffer(unsigned * pSize, unsigned nDesiredSize); + + // close the buffer allocated above and assume nPosOffset were transferred + virtual void CloseReadBuffer(unsigned nPosOffset); + + // transfer a block of data: the buffer should be closed + virtual void DoReadBlock(void * pData, unsigned nSize); + + // if a buffer is open, should return pos at start of buffer + virtual unsigned DoGetPos(); + + // requires that no buffer is oben + virtual void DoSetPos(unsigned nPos); +}; + +class MediaMemoryMedium : public MediaMemoryReadMedium +{ + public: + MediaMemoryMedium() : m_pMem(NULL) {} + + void Open(void * p) + { + m_pMem = p; + MediaMemoryReadMedium::Open(p); + } + + void Close() + { + MediaMemoryReadMedium::Close(); + m_pMem = NULL; + } + + private: + void * m_pMem; + + protected: + + // get a pointer to memory where data can be written to directly + virtual void * GetWriteBuffer(unsigned * pSize, unsigned nDesiredSize); + + // close the buffer allocated above and assume nPosOffset were transferred + virtual void CloseWriteBuffer(unsigned nPosOffset); + + // transfer a block of data: the buffer should be closed + virtual void DoWriteBlock(void const * pData, unsigned nSize); +}; + + +class MediaSection : public MediaMedium +{ + public: + MediaSection() : m_pMedium(NULL) {} + + void Open(MediaMedium * pMedium, unsigned nMaxSize = UINT_MAX) + { + m_pMedium = pMedium; + m_nMaxSize = nMaxSize; + m_nPos = 0; + m_nUsedPos = 0; + } + void Close() + { + if (m_pMedium) + Flush(); + if (m_nPos > m_nUsedPos) m_nUsedPos = m_nPos; + m_pMedium = NULL; + } + unsigned GetUsedSize() const + { + return (m_nPos > m_nUsedPos) ? m_nPos : m_nUsedPos; + } + + virtual unsigned GetRemainingSize(); + + private: + MediaMedium * m_pMedium; + unsigned m_nMaxSize; + unsigned m_nPos; + unsigned m_nUsedPos; + + protected: + // get a pointer to memory where data can be written to directly + virtual void * GetWriteBuffer(unsigned * pSize, unsigned nDesiredSize); + + // get a pointer to memory where data can be read from directly + virtual void const * GetReadBuffer(unsigned * pSize, unsigned nDesiredSize); + + // close the buffer allocated above and assume nPosOffset were transferred + virtual void CloseWriteBuffer(unsigned nPosOffset); + virtual void CloseReadBuffer(unsigned nPosOffset); + + // transfer a block of data: the buffer should be closed + virtual void DoWriteBlock(void const * pData, unsigned nSize); + virtual void DoReadBlock(void * pData, unsigned nSize); + + // if a buffer is open, should return pos at start of buffer + virtual unsigned DoGetPos(); + + // requires that no buffer is oben + virtual void DoSetPos(unsigned nPos); +}; + + +#endif diff --git a/3dc/win95/objedit.h b/3dc/win95/objedit.h new file mode 100644 index 0000000..c39b2ec --- /dev/null +++ b/3dc/win95/objedit.h @@ -0,0 +1,84 @@ + +#include "Chunk.hpp" + +#define VECTOR VECTORCH + +struct ChunkMapBlock +{ + char TemplateName[20]; + char TemplateNotes[100]; + int MapType; + int MapShape; + int MapFlags; + int MapFlags2; + int MapFlags3; + int MapCType; + int MapCGameType; + int MapCStrategyS; + int MapCStrategyL; + int MapInteriorType; + int MapLightType; + int MapMass; + VECTOR MapNewtonV; + VECTOR MapOrigin; + int MapViewType; + + int MapVDBData; + int SimShapeList; + + + +}; + +class Map_Block_Chunk : public Chunk +{ +public: + virtual size_t size_chunk() + { + return (chunk_size=216); + } + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start); + + ChunkMapBlock map_data; + friend class Object_Project_Data_Chunk; + + Map_Block_Chunk (Object_Project_Data_Chunk * parent) + :Chunk(parent,"MAPBLOCK") + {} +private: + + //constructor from buffer + Map_Block_Chunk (Object_Project_Data_Chunk * parent,const char* data); +}; + +struct ChunkStrategy +{ + char StrategyName[20]; + char StrategyNotes[100]; + int Strategy; +}; + +class Strategy_Chunk : public Chunk +{ +public : + virtual size_t size_chunk() + { + return (chunk_size=136); + } + virtual BOOL output_chunk (HANDLE &); + + virtual void fill_data_block (char * data_start); + + ChunkStrategy strategy_data; + friend class Object_Project_Data_Chunk; + + Strategy_Chunk(Object_Project_Data_Chunk *parent) + :Chunk(parent,"STRATEGY") + {} +private: + + //constructor from buffer + Strategy_Chunk (Object_Project_Data_Chunk * parent,const char* data); +}; diff --git a/3dc/win95/plat_shp.c b/3dc/win95/plat_shp.c new file mode 100644 index 0000000..8a67984 --- /dev/null +++ b/3dc/win95/plat_shp.c @@ -0,0 +1,369 @@ +/*RWH moved to a seperate file*/ + + +#include "3dc.h" +#include "module.h" +#include "inline.h" + +#include "gameplat.h" +#include "gamedef.h" + + +#include "dynblock.h" +#include "dynamics.h" +#define UseLocalAssert No +#include "ourasert.h" + + +/* * + * + * + * * * + * * * + *** + * +*/ +/*KJL*********************************************** +* Polygon Access Functions V1.0, 18:12:27 11/07/96 * +***********************************************KJL*/ + +int SetupPolygonAccess(DISPLAYBLOCK *objectPtr); +void AccessNextPolygon(void); +void GetPolygonVertices(struct ColPolyTag *polyPtr); +void GetPolygonNormal(struct ColPolyTag *polyPtr); +int SetupPolygonAccessFromShapeIndex(int shapeIndex); + + +/* the following are needed for morphing support */ +#if SupportMorphing +extern MORPHDISPLAY MorphDisplay; +extern VECTORCH MorphedPts[]; +#endif + +VECTORCH *ShapePointsPtr; +int *ShapeNormalsPtr; +int *Shape2NormalsPtr; +char ShapeIsMorphed; +int **ItemArrayPtr; +POLYHEADER *PolyheaderPtr; + +int SetupPolygonAccess(DISPLAYBLOCK *objectPtr) +{ + SHAPEHEADER *shape1Ptr; + + #if SupportMorphing + if (objectPtr->ObMorphCtrl) /* morphable object? */ + { + VECTORCH *shape1PointsPtr; + VECTORCH *shape2PointsPtr; + + /* Set up the morph data */ + GetMorphDisplay(&MorphDisplay, objectPtr); + + shape1Ptr = MorphDisplay.md_sptr1; + + if(MorphDisplay.md_lerp == 0x0000) + { + + ShapePointsPtr = (VECTORCH *)*shape1Ptr->points; + ShapeNormalsPtr = (int *) *(shape1Ptr->sh_normals); + ShapeIsMorphed=0; + + } + else if(MorphDisplay.md_lerp == 0xffff) + { + SHAPEHEADER *shape2Ptr; + shape2Ptr = MorphDisplay.md_sptr2; + + ShapePointsPtr = (VECTORCH *)*shape2Ptr->points; + ShapeNormalsPtr = (int *) *(shape2Ptr->sh_normals); + ShapeIsMorphed=0; + } + else + { + SHAPEHEADER *shape2Ptr; + shape2Ptr = MorphDisplay.md_sptr2; + + shape1PointsPtr = (VECTORCH *)(*shape1Ptr->points); + shape2PointsPtr = (VECTORCH *)(*shape2Ptr->points); + + /* you're going to need all the points so you might as well morph them all at once now */ + { + int numberOfPoints = shape1Ptr->numpoints; + VECTORCH *morphedPointsPtr = (VECTORCH *) MorphedPts; + + while(numberOfPoints--) + { + VECTORCH vertex1 = *shape1PointsPtr; + VECTORCH vertex2 = *shape2PointsPtr; + + if( (vertex1.vx == vertex2.vx && vertex1.vy == vertex2.vy && vertex1.vz == vertex2.vz) ) + { + *morphedPointsPtr = vertex1; + } + else + { + /* KJL 15:27:20 05/22/97 - I've changed this to speed things up, If a vertex + component has a magnitude greater than 32768 things will go wrong. */ + morphedPointsPtr->vx = vertex1.vx + (((vertex2.vx-vertex1.vx)*MorphDisplay.md_lerp)>>16); + morphedPointsPtr->vy = vertex1.vy + (((vertex2.vy-vertex1.vy)*MorphDisplay.md_lerp)>>16); + morphedPointsPtr->vz = vertex1.vz + (((vertex2.vz-vertex1.vz)*MorphDisplay.md_lerp)>>16); + } + + shape1PointsPtr++; + shape2PointsPtr++; + morphedPointsPtr++; + } + } + + ShapePointsPtr = (VECTORCH *)MorphedPts; + ShapeNormalsPtr = (int *) *(shape1Ptr->sh_normals); + Shape2NormalsPtr = (int *) *(shape2Ptr->sh_normals); + ShapeIsMorphed=1; + } + ItemArrayPtr = (int **)shape1Ptr->items; + } + else /* not a morphing object */ + #endif + { + shape1Ptr = GetShapeData(objectPtr->ObShape); + + ShapePointsPtr = (VECTORCH *)(*shape1Ptr->points); + ShapeNormalsPtr = (int *)(*shape1Ptr->sh_normals); + ItemArrayPtr = (int **)shape1Ptr->items; + ShapeIsMorphed=0; + } + + { + int *itemPtr = *ItemArrayPtr; + PolyheaderPtr = (POLYHEADER *) itemPtr; + } + + return shape1Ptr->numitems; +} +void AccessNextPolygon(void) +{ + int *itemPtr = *(ItemArrayPtr++); + PolyheaderPtr = (POLYHEADER *) itemPtr; + return; +} + +void GetPolygonVertices(struct ColPolyTag *polyPtr) +{ + int *vertexNumberPtr = &PolyheaderPtr->Poly1stPt; + + polyPtr->PolyPoint[0] = *(ShapePointsPtr + *vertexNumberPtr++); + polyPtr->PolyPoint[1] = *(ShapePointsPtr + *vertexNumberPtr++); + polyPtr->PolyPoint[2] = *(ShapePointsPtr + *vertexNumberPtr++); + + if (*vertexNumberPtr != Term) + { + polyPtr->PolyPoint[3] = *(ShapePointsPtr + *vertexNumberPtr); + polyPtr->NumberOfVertices=4; + } + else + { + polyPtr->NumberOfVertices=3; + } + + return; +} +void GetPolygonNormal(struct ColPolyTag *polyPtr) +{ + if (ShapeIsMorphed) + { + VECTORCH n1Ptr = *(VECTORCH*)(ShapeNormalsPtr + PolyheaderPtr->PolyNormalIndex); + VECTORCH n2Ptr = *(VECTORCH*)(Shape2NormalsPtr + PolyheaderPtr->PolyNormalIndex); + + if( ((n1Ptr.vx == n2Ptr.vx) + && (n1Ptr.vy == n2Ptr.vy) + && (n1Ptr.vz == n2Ptr.vz)) + || (MorphDisplay.md_lerp == 0) ) + { + polyPtr->PolyNormal = n1Ptr; + } + else if(MorphDisplay.md_lerp == 0xffff) + { + polyPtr->PolyNormal = n2Ptr; + } + else + { + VECTORCH *pointPtr[3]; + int *vertexNumPtr = &PolyheaderPtr->Poly1stPt; + + pointPtr[0] = (ShapePointsPtr + *vertexNumPtr++); + pointPtr[1] = (ShapePointsPtr + *vertexNumPtr++); + pointPtr[2] = (ShapePointsPtr + *vertexNumPtr); + + MakeNormal + ( + pointPtr[0], + pointPtr[1], + pointPtr[2], + &polyPtr->PolyNormal + ); + } + } + else /* not morphed */ + { + polyPtr->PolyNormal = *(VECTORCH*)(ShapeNormalsPtr + PolyheaderPtr->PolyNormalIndex); + + /* KJL 20:55:36 05/14/97 - turned off for alpha */ + #if 0 + if( (polyPtr->PolyNormal.vx==0) + &&(polyPtr->PolyNormal.vy==0) + &&(polyPtr->PolyNormal.vz==0) ) + { + textprint("shape data has zero normal\n"); + } + #endif + + } + return; +} + +/*-----------------------Patrick 1/12/96-------------------------- + I have added this function to initialise polygon access for a + module based on the shape index specified in its mapblock.... + Specifically, this is for setting up location data for modules + during game initialisation, and so doesn't support morphing. + ----------------------------------------------------------------*/ +int SetupPolygonAccessFromShapeIndex(int shapeIndex) +{ + SHAPEHEADER *shape1Ptr; + + shape1Ptr = GetShapeData(shapeIndex); + ShapePointsPtr = (VECTORCH *)(*shape1Ptr->points); + ShapeNormalsPtr = (int *)(*shape1Ptr->sh_normals); + ItemArrayPtr = (int **)shape1Ptr->items; + ShapeIsMorphed=0; + + { + int *itemPtr = *ItemArrayPtr; + PolyheaderPtr = (POLYHEADER *) itemPtr; + } + + return shape1Ptr->numitems; +} + +/*--------------------Patrick 17/12/96---------------------------- + I have added some more shape data access functions...... + PSX versions are required. + ----------------------------------------------------------------*/ + +static VECTORCH patPointData; +static int patPolyVertexIndices[4]; +static VECTORCH *patShapePointsPtr; + +int SetupPointAccessFromShapeIndex(int shapeIndex) +{ + SHAPEHEADER *shapePtr; + + shapePtr = GetShapeData(shapeIndex); + patShapePointsPtr = (VECTORCH *)(*shapePtr->points); + + return shapePtr->numpoints; +} + + +VECTORCH* AccessNextPoint(void) +{ + patPointData = *patShapePointsPtr++; + return &patPointData; +} + +VECTORCH* AccessPointFromIndex(int index) +{ + patPointData = patShapePointsPtr[index]; + return &patPointData; +} + +/* KJL 18:51:08 21/11/98 - similiar function for polys */ +POLYHEADER *AccessPolyFromIndex(int index) +{ + int *itemPtr = *(ItemArrayPtr+index); + PolyheaderPtr = (POLYHEADER *) itemPtr; + return PolyheaderPtr; +} + +void DestroyPolygon(int shapeIndex,int polyIndex) +{ + SHAPEHEADER *shapePtr = GetShapeData(shapeIndex); + shapePtr->numitems--; + *(ItemArrayPtr+polyIndex) = *(ItemArrayPtr+shapePtr->numitems); +} + +void ReplaceVertexInPolygon(int polyIndex, int oldVertex, int newVertex) +{ + int *vertexNumberPtr; + int *itemPtr = *(ItemArrayPtr+polyIndex); + PolyheaderPtr = (POLYHEADER *) itemPtr; + + vertexNumberPtr = &PolyheaderPtr->Poly1stPt; + + while(*vertexNumberPtr != Term) + { + if (*vertexNumberPtr == oldVertex) + { + *vertexNumberPtr = newVertex; + } + vertexNumberPtr++; + } + + { + VECTORCH newNormal; + VECTORCH *pointPtr[3]; + int *vertexNumPtr = &PolyheaderPtr->Poly1stPt; + pointPtr[0] = (ShapePointsPtr + *vertexNumPtr++); + pointPtr[1] = (ShapePointsPtr + *vertexNumPtr++); + pointPtr[2] = (ShapePointsPtr + *vertexNumPtr); + MakeNormal + ( + pointPtr[0], + pointPtr[1], + pointPtr[2], + &newNormal + ); + *(VECTORCH*)(ShapeNormalsPtr + PolyheaderPtr->PolyNormalIndex)=newNormal; + } + + +} +VECTORCH *GetPolygonNormalFromIndex(void) +{ + return (VECTORCH*)(ShapeNormalsPtr + PolyheaderPtr->PolyNormalIndex); +} + +int *GetPolygonVertexIndices(void) +{ + int *vertexNumberPtr = &PolyheaderPtr->Poly1stPt; + int numberOfVertices=0; + + patPolyVertexIndices[3] = -1; + + while(*vertexNumberPtr != Term) + { + patPolyVertexIndices[numberOfVertices++] = (*vertexNumberPtr); + vertexNumberPtr++; + } + + return &patPolyVertexIndices[0]; +} + + +/*--------------------Roxby 3/7/97---------------------------- + I have added some more shape data access functions...... + taken from PSX versions + ----------------------------------------------------------------*/ + + +void SetupPolygonFlagAccessForShape(SHAPEHEADER *shape) +{ +} + + +int Request_PolyFlags(void *polygon) +{ + POLYHEADER *poly = (POLYHEADER*)polygon; + return poly->PolyFlags; +} diff --git a/3dc/win95/plat_shp.h b/3dc/win95/plat_shp.h new file mode 100644 index 0000000..c6551d8 --- /dev/null +++ b/3dc/win95/plat_shp.h @@ -0,0 +1,11 @@ +/* Plat_Shp.h */ + + +extern void SetupPolygonFlagAccessForShape(SHAPEHEADER *shape); +extern int Request_PolyFlags(void *polygon); + +extern int SetupPolygonAccess(DISPLAYBLOCK *objectPtr); +extern void AccessNextPolygon(void); +extern void GetPolygonVertices(struct ColPolyTag *polyPtr); +extern void GetPolygonNormal(struct ColPolyTag *polyPtr); +extern int SetupPolygonAccessFromShapeIndex(int shapeIndex); diff --git a/3dc/win95/platform.h b/3dc/win95/platform.h new file mode 100644 index 0000000..7cab03d --- /dev/null +++ b/3dc/win95/platform.h @@ -0,0 +1,939 @@ +#ifndef PLATFORM_INCLUDED + +/* + + Platform Specific Header Include + +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + Minimise header files to + speed compiles... +*/ + +#define WIN32_LEAN_AND_MEAN + +/* + Standard windows functionality +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* + DirectX functionality +*/ + +#include "ddraw.h" +#include "d3d.h" +#include "dsound.h" +#include "dplay.h" +#include "dinput.h" +#include "dplobby.h" +//#include "fastfile.h" + + +#define platform_pc Yes + +#define Saturn No + +#define Hardware2dTextureClipping No + + +/* + + Types + +*/ + +typedef RECT RECT_AVP; + + +/* Watcom C 64-bit values */ + +typedef struct LONGLONGCH { + + unsigned int lo32; + int hi32; + +} LONGLONGCH; + + +/* + + Sine and Cosine + +*/ + +#define GetSin(a) sine[a] +#define GetCos(a) cosine[a] + +/* + Available processor types +*/ + +typedef enum { + + PType_OffBottomOfScale, + PType_486, + PType_Pentium, + PType_P6, + PType_PentiumMMX, + PType_Klamath, + PType_OffTopOfScale + +} PROCESSORTYPES; + + +/* + + VGA Palette Entry + +*/ + +typedef struct vgapaletteentry { + + unsigned char vga_r; + unsigned char vga_g; + unsigned char vga_b; + +} VGAPALETTEENTRY; + + +extern void LoadAndChangeToPalette(char*); + +/* + Video mode decsription (to be filled + in by DirectDraw callback). +*/ + +typedef struct videomodeinfo { + + int Width; /* in pixels */ + int Height; /* in pixels */ + int ColourDepth; /* in bits per pixel */ + +} VIDEOMODEINFO; + +/* + Maximum number of display modes + that could be detected on unknown + hardware. +*/ + +#define MaxAvailableVideoModes 100 + +/* + #defines, structures etc for + textprint system +*/ + +#define MaxMsgChars 100 +#define MaxMessages 20 + +/* Font description */ + +#define CharWidth 8 /* In PIXELS, not bytes */ +#define CharHeight 10 /* In PIXELS, not bytes */ +#define CharVertSep (CharHeight + 0) /* In PIXELS, not bytes */ + +#define FontStart 33 // random squiggle in standard ASCII +#define FontEnd 127 // different random squiggle in standard ASCII + +#define FontInvisValue 0x00 // value to be colour keyed out of font blit + +typedef struct printqueueitem { + + char text[MaxMsgChars]; + int text_length; + int x; + int y; + +} PRINTQUEUEITEM; + + + +/* KJL 12:30:05 9/9/97 - new keyboard, mouse etc. enum */ +enum KEY_ID +{ + KEY_ESCAPE, + + KEY_0, + KEY_1, + KEY_2, + KEY_3, + KEY_4, + KEY_5, + KEY_6, + KEY_7, + KEY_8, + KEY_9, + + KEY_A, + KEY_B, + KEY_C, + KEY_D, + KEY_E, + KEY_F, + KEY_G, + KEY_H, + KEY_I, + KEY_J, + KEY_K, + KEY_L, + KEY_M, + KEY_N, + KEY_O, + KEY_P, + KEY_Q, + KEY_R, + KEY_S, + KEY_T, + KEY_U, + KEY_V, + KEY_W, + KEY_X, + KEY_Y, + KEY_Z, + + KEY_LEFT, + KEY_RIGHT, + KEY_UP, + KEY_DOWN, + KEY_CR, + KEY_TAB, + KEY_INS, + KEY_DEL, + KEY_END, + KEY_HOME, + KEY_PAGEUP, + KEY_PAGEDOWN, + KEY_BACKSPACE, + KEY_COMMA, + KEY_FSTOP, + KEY_SPACE, + + KEY_LEFTSHIFT, + KEY_RIGHTSHIFT, + KEY_LEFTALT, + KEY_RIGHTALT, + KEY_LEFTCTRL, + KEY_RIGHTCTRL, + + KEY_CAPS, + KEY_NUMLOCK, + KEY_SCROLLOK, + + KEY_NUMPAD0, + KEY_NUMPAD1, + KEY_NUMPAD2, + KEY_NUMPAD3, + KEY_NUMPAD4, + KEY_NUMPAD5, + KEY_NUMPAD6, + KEY_NUMPAD7, + KEY_NUMPAD8, + KEY_NUMPAD9, + KEY_NUMPADSUB, + KEY_NUMPADADD, + KEY_NUMPADDEL, + KEY_NUMPADENTER, + KEY_NUMPADDIVIDE, + KEY_NUMPADMULTIPLY, + + KEY_LBRACKET, + KEY_RBRACKET, + KEY_SEMICOLON, + KEY_APOSTROPHE, + KEY_GRAVE, + KEY_BACKSLASH, + KEY_SLASH, + KEY_CAPITAL, + KEY_MINUS, + KEY_EQUALS, + KEY_LWIN, + KEY_RWIN, + KEY_APPS, + + + 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_JOYSTICK_BUTTON_1, + KEY_JOYSTICK_BUTTON_2, + KEY_JOYSTICK_BUTTON_3, + KEY_JOYSTICK_BUTTON_4, + KEY_JOYSTICK_BUTTON_5, + KEY_JOYSTICK_BUTTON_6, + KEY_JOYSTICK_BUTTON_7, + KEY_JOYSTICK_BUTTON_8, + KEY_JOYSTICK_BUTTON_9, + KEY_JOYSTICK_BUTTON_10, + KEY_JOYSTICK_BUTTON_11, + KEY_JOYSTICK_BUTTON_12, + KEY_JOYSTICK_BUTTON_13, + KEY_JOYSTICK_BUTTON_14, + KEY_JOYSTICK_BUTTON_15, + KEY_JOYSTICK_BUTTON_16, + + KEY_LMOUSE, + KEY_MMOUSE, + KEY_RMOUSE, + + KEY_MOUSEBUTTON4, + KEY_MOUSEWHEELUP, + KEY_MOUSEWHEELDOWN, + + // Dutch + KEY_ORDINAL, + KEY_LESSTHAN, + KEY_PLUS, + + // French + KEY_RIGHTBRACKET, + KEY_ASTERISK, + KEY_DOLLAR, + KEY_U_GRAVE, + KEY_EXCLAMATION, + KEY_COLON, + + // German + KEY_BETA, + KEY_A_UMLAUT, + KEY_O_UMLAUT, + KEY_U_UMLAUT, + KEY_HASH, + + // Spanish + KEY_UPSIDEDOWNEXCLAMATION, + KEY_C_CEDILLA, + KEY_N_TILDE, + + // accents & diacritics + KEY_DIACRITIC_GRAVE, + KEY_DIACRITIC_ACUTE, + KEY_DIACRITIC_CARET, + KEY_DIACRITIC_UMLAUT, + + + KEY_VOID=255, // used to indicate a blank spot in the key config + MAX_NUMBER_OF_INPUT_KEYS, + +}; +/* + Mouse handler modes (velocity mode is for + interfacing to input functions that need + to read the mouse velocity, e.g. WeRequest + functions, while poistion mode is for menus + and similar problems). + + The initial mode is defined as a compiled in + global in game.c +*/ + +typedef enum { + + MouseVelocityMode, + MousePositionMode + +} MOUSEMODES; + + +/* Defines for the purpose of familiarity of name only */ + +#define LeftButton 0x0001 +#define RightButton 0x0002 +#define MiddleButton 0x0004 + + + + +/* + Video Modes +*/ + +typedef enum { + + VideoMode_DX_320x200x8, + VideoMode_DX_320x200x8T, + VideoMode_DX_320x200x15, + VideoMode_DX_320x240x8, + + VideoMode_DX_640x480x8, + VideoMode_DX_640x480x8T, + VideoMode_DX_640x480x15, + VideoMode_DX_640x480x24, + + VideoMode_DX_800x600x8, + VideoMode_DX_800x600x8T, + VideoMode_DX_800x600x15, + VideoMode_DX_800x600x24, + + VideoMode_DX_1024x768x8, + VideoMode_DX_1024x768x8T, + VideoMode_DX_1024x768x15, + VideoMode_DX_1024x768x24, + + VideoMode_DX_1280x1024x8, + VideoMode_DX_1280x1024x8T, + VideoMode_DX_1280x1024x15, + VideoMode_DX_1280x1024x24, + + VideoMode_DX_1600x1200x8, + VideoMode_DX_1600x1200x8T, + VideoMode_DX_1600x1200x15, + VideoMode_DX_1600x1200x24, + + MaxVideoModes + +} VIDEOMODES; + + +#define MaxScreenWidth 1600 /* Don't get this wrong! */ + + +/* + Max no of palettes -- at present there is NO + code for palette switching and ALL palette + calls within the DirectDraw interface system + run on palette 0 +*/ + +#define MaxPalettes 4 + +/* + + Video Mode Types + +*/ + +typedef enum { + + VideoModeType_8, + VideoModeType_15, + VideoModeType_24, + VideoModeType_8T + +} VIDEOMODETYPES; + + +/* + Windows modes +*/ + +typedef enum { + + WindowModeFullScreen, + WindowModeSubWindow + +} WINDOWMODES; + +typedef struct WinScaleXY { + + float x; + float y; + +} WINSCALEXY; + + +/* + Dubious hack for dubious + aspects of DirectDraw initialisation +*/ + +typedef enum { + + /* Default */ + NoRestartRequired, + /* + Characteristic of driver which + will not support changing to a different + bit depth without rebooting + */ + RestartDisplayModeNotAvailable, + /* + Characteristic of ModeX emulation leading + to no video memory being available because + of the need to cooperate with a large existing + GDI surface which cannot be reduced without a + reboot + */ + RestartOutOfVidMemForPrimary + +} VIDEORESTARTMODES; + +/* + Load modes for putting an image + in a DirectDraw surface --- either + do or do not deallocate the + system memory image, but always + keep the DirectDraw one +*/ + +typedef enum { + + LoadModeDirectDrawOnly, + LoadModeFull + +} IMAGELOADMODES; + + +/* + Direct3D driver modes +*/ + +typedef enum { + + D3DSoftwareRGBDriver, + D3DSoftwareRampDriver, + D3DHardwareRGBDriver + +} D3DMODES; + +/* + Software scan draw request modes +*/ + +typedef enum { + + RequestScanDrawDirectDraw, + RequestScanDrawSoftwareRGB, + RequestScanDrawRamp, + RequestScanDrawDefault + +} SOFTWARESCANDRAWREQUESTMODES; + +/* + Rasterisation request modes +*/ + +typedef enum { + + RequestSoftwareRasterisation, + RequestDefaultRasterisation + +} RASTERREQUESTMODES; + + +/* + Actual scan draw mode +*/ + +typedef enum { + + ScanDrawDirectDraw, + ScanDrawD3DRamp, + ScanDrawD3DSoftwareRGB, + ScanDrawD3DHardwareRGB + +} SCANDRAWMODES; + + +/* + Z buffering request modes +*/ + +typedef enum { + + RequestZBufferNever, + RequestZBufferAlways, + RequestZBufferDefault + +} ZBUFFERREQUESTMODES; + +/* + Z buffering modes +*/ + +typedef enum { + + ZBufferOn, + ZBufferWriteOnly, + ZBufferOff + +} ZBUFFERMODES; + +/* + Request modes for DirectX + memory usage +*/ + +typedef enum { + + RequestSystemMemoryAlways, + RequestDefaultMemoryAllocation + +} DXMEMORYREQUESTMODES; + + +/* + DirectX memory usage modes +*/ + +typedef enum { + + SystemMemoryPreferred, + VideoMemoryPreferred + +} DXMEMORYMODES; + +/* + + .BMP File header + +*/ + +/* + Pack the header to 1 byte alignment so that the + loader works (John's code, still under test). +*/ + +#ifdef __WATCOMC__ +#pragma pack (1) +#endif + +typedef struct bmpheader { + + unsigned short BMP_ID; /* Contains 'BM' */ + int BMP_Size; + + short BMP_Null1; + short BMP_Null2; + + int BMP_Image; /* Byte offset of image start relative to offset 14 */ + int BMP_HeadSize; /* Size of header (40 for Windows, 12 for OS/2) */ + int BMP_Width; /* Width of image in pixels */ + int BMP_Height; /* Height of image in pixels */ + + short BMP_Planes; /* Number of image planes (must be 1) */ + short BMP_Bits; /* Number of bits per pixel (1,4,8 or 24) */ + + int BMP_Comp; /* Compression type */ + int BMP_CSize; /* Size in bytes of compressed image */ + int BMP_Hres; /* Horizontal resolution in pixels/meter */ + int BMP_Vres; /* Vertical resolution in pixels/meter */ + int BMP_Colours; /* Number of colours used, below (N) */ + int BMP_ImpCols; /* Number of important colours */ + +} BMPHEADER; + +#ifdef __WATCOMC__ +#pragma pack (4) +#endif + +/* + Types of texture files that can be + requested from the main D3D texture + loader. +*/ + +typedef enum { + + TextureTypePGM, + TextureTypePPM + +} TEXTUREFILETYPE; + +/* + Windows initialisation modes. + See InitialiseWindowsSystem + in the default win_proj.cpp + for a full description. +*/ + +typedef enum { + + WinInitFull, + WinInitChange + +} WININITMODES; + +/* + + Triangle Array Limits etc. + +*/ + +#define maxarrtriangles 7 /* Could be 6 if all shape data in triangles */ +#define trianglesize (1 + 1 + 1 + 1 + (6 * 3) + 1) /* largest, could be 5*3 if no 3d texturing */ +#define pta_max 9 /* Could be 8 if all shape data in triangles */ + +/* header + xy + terminator */ +#define item_polygon_trianglesize (1 + 1 + 1 + 1 + (2 * 3) + 1) +/* header + xyi + terminator */ +#define item_gouraudpolygon_trianglesize (1 + 1 + 1 + 1 + (3 * 3) + 1) +/* header + xyuv + terminator */ +#define item_2dtexturedpolygon_trianglesize (1 + 1 + 1 + 1 + (4 * 3) + 1) +/* header + xyuvi + terminator */ +#define item_gouraud2dtexturedpolygon_trianglesize (1 + 1 + 1 + 1 + (5 * 3) + 1) +/* header + xyuvw + terminator */ +#define item_3dtexturedpolygon_trianglesize (1 + 1 + 1 + 1 + (5 * 3) + 1) +/* header + xyuvwi + terminator */ +#define item_gouraud3dtexturedpolygon_trianglesize (1 + 1 + 1 + 1 + (6 * 3) + 1) + +/* + + Vertex sizes + + For copying vertices from item list polygons to triangles + + e.g. + + Vertex 2 (x component) of the quad would be (for Item_Polygon) + + q[2 * i_poly_vsize + i_vstart + ix] + + WARNING: If the item format changes these MUST be updated + +*/ + +#define vstart 4 + +#define poly_vsize 2 +#define gpoly_vsize 3 +#define t2poly_vsize 4 +#define gt2poly_vsize 5 +#define t3poly_vsize 5 +#define gt3poly_vsize 6 + + + +/* + + Triangle Array Structure + +*/ + +typedef struct trianglearray { + + int TA_NumTriangles; + int *TA_ItemPtr; + int *TA_TriangleArray[maxarrtriangles]; + +} TRIANGLEARRAY; + +/* + Function prototypes +*/ + +/* + Windows functionality. Note current + DirectInput functions are also here since + they are really part of the Win32 multimedia + library. +*/ + +long GetWindowsTickCount(void); +void CheckForWindowsMessages(void); +BOOL ExitWindowsSystem(void); +BOOL InitialiseWindowsSystem(HANDLE hInstance, int nCmdShow, int WinInitMode); +void KeyboardHandlerKeyDown(WPARAM wParam); +void KeyboardHandlerKeyUp(WPARAM wParam); +void MouseVelocityHandler(UINT message, LPARAM lParam); +void MousePositionHandler(UINT message, LPARAM lParam); +int ReadJoystick(void); +int CheckForJoystick(void); +BOOL SpawnRasterThread(); +BOOL WaitForRasterThread(); + + +/* DirectDraw */ +void finiObjects(void); +void GenerateDirectDrawSurface(void); +void LockSurfaceAndGetBufferPointer(void); +void UnlockSurface(void); +void finiObjects(void); +void ColourFillBackBuffer(int FillColour); +void ColourFillBackBufferQuad(int FillColour, int LeftX, + int TopY, int RightX, int BotY); +void FlipBuffers(void); +void BlitToBackBuffer(void* lpBackground, RECT* destRectPtr, RECT* srcRectPtr); +void BlitToBackBufferWithoutTearing(void* lpBackground, RECT* destRectPtr, RECT* srcRectPtr); +void BlitWin95Char(int x, int y, unsigned char toprint); +void ReleaseDDSurface(void* DDSurface); +BOOL InitialiseDirectDrawObject(void); +BOOL ChangeDirectDrawObject(void); +BOOL CheckForVideoModes(int TestVideoMode); +void finiObjectsExceptDD(void); +BOOL TestMemoryAccess(void); +int ChangePalette (unsigned char* NewPalette); +int GetAvailableVideoMemory(void); +void HandleVideoModeRestarts(HINSTANCE hInstance, int nCmdShow); +void* MakeBackdropSurface(void); +void ReleaseBackdropSurface(void); +void LockBackdropSurface(void); +void UnlockBackdropSurface(void); +void ComposeBackdropBackBuffer(void); +int GetSingleColourForPrimary(int Colour); + +/* + DirectX functionality only available in + C++ under Watcom at present +*/ +#ifdef __cplusplus +HRESULT CALLBACK EnumDisplayModesCallback(LPDDSURFACEDESC pddsd, LPVOID Context); +BOOL FAR PASCAL EnumDDObjectsCallback(GUID FAR* lpGUID, LPSTR lpDriverDesc, + LPSTR lpDriverName, LPVOID lpContext); +#if triplebuffer +/* + must be WINAPI to support Windows FAR PASCAL + calling convention. Must be HRESULT to support + enumeration return value. NOTE THIS FUNCTION + DOESN'T WORK (DOCS WRONG) AND TRIPLE BUFFERING + HAS BEEN REMOVED ANYWAY 'COS IT'S USELESS... +*/ +HRESULT WINAPI InitTripleBuffers(LPDIRECTDRAWSURFACE lpdd, + LPDDSURFACEDESC lpsd, LPVOID lpc); +#endif +#endif + +/* Direct 3D Immediate Mode Rasterisation Module */ +BOOL InitialiseDirect3DImmediateMode(void); +BOOL LockExecuteBuffer(void); +BOOL UnlockExecuteBufferAndPrepareForUse(void); +BOOL BeginD3DScene(void); +BOOL EndD3DScene(void); +BOOL ExecuteBuffer(void); +BOOL RenderD3DScene(void); +void ReleaseDirect3D(void); +void WritePolygonToExecuteBuffer(int* itemptr); +void WriteGouraudPolygonToExecuteBuffer(int* itemptr); +void Write2dTexturedPolygonToExecuteBuffer(int* itemptr); +void WriteGouraud2dTexturedPolygonToExecuteBuffer(int* itemptr); +void Write3dTexturedPolygonToExecuteBuffer(int* itemptr); +void WriteGouraud3dTexturedPolygonToExecuteBuffer(int* itemptr); +void WriteBackdrop2dTexturedPolygonToExecuteBuffer(int* itemptr); +void WriteBackdrop3dTexturedPolygonToExecuteBuffer(int* itemptr); +void WriteEndCodeToExecuteBuffer(void); +void ReleaseD3DTexture(void* D3DTexture); +void ReleaseDirect3DNotDD(void); +void ReleaseDirect3DNotDDOrImages(void); +BOOL SetExecuteBufferDefaults(void); +void SelectD3DDriverAndDrawMode(void); +#if SUPPORT_MMX +void SelectMMXOptions(void); +#endif +BOOL TestInitD3DObject(void); + +#if SupportZBuffering +BOOL CreateD3DZBuffer(void); +void FlushD3DZBuffer(void); +void WriteZBPolygonToExecuteBuffer(int* itemptr); +void WriteZBGouraudPolygonToExecuteBuffer(int* itemptr); +void WriteZB2dTexturedPolygonToExecuteBuffer(int* itemptr); +void WriteZBGouraud2dTexturedPolygonToExecuteBuffer(int* itemptr); +void WriteZB3dTexturedPolygonToExecuteBuffer(int* itemptr); +void WriteZBGouraud3dTexturedPolygonToExecuteBuffer(int* itemptr); +#endif + +#ifdef __cplusplus +HRESULT WINAPI DeviceEnumerator(LPGUID lpGuid, + LPSTR lpDeviceDescription, LPSTR lpDeviceName, + LPD3DDEVICEDESC lpHWDesc, LPD3DDEVICEDESC lpHELDesc, LPVOID lpContext); +HRESULT CALLBACK TextureFormatsEnumerator + (LPDDSURFACEDESC lpDDSD, LPVOID lpContext); +#endif + +/* KJL 11:28:31 9/9/97 - Direct Input prototypes */ +BOOL InitialiseDirectInput(void); +void ReleaseDirectInput(void); +BOOL InitialiseDirectKeyboard(); +void DirectReadKeyboard(void); +void ReleaseDirectKeyboard(void); +BOOL InitialiseDirectMouse(); +void DirectReadMouse(void); +void ReleaseDirectMouse(void); + +/* + Internal +*/ +#ifdef AVP_DEBUG_VERSION +int textprint(const char* t, ...); +#else +#define textprint(ignore) +#endif + + +void MakePaletteShades(VGAPALETTEENTRY *vga_palptr, int hue, int pal_shades_per_hue); +void ConvertToDDPalette(unsigned char* src, unsigned char* dst, int length, int flags); +int textprintXY(int x, int y, const char* t, ...); +void LoadSystemFonts(char* fname); +void DisplayWin95String(int x, int y, unsigned char *buffer); +void WriteStringToTextBuffer(int x, int y, unsigned char *buffer); +void FlushTextprintBuffer(void); +void InitPrintQueue(void); +void InitJoysticks(void); +void ReadJoysticks(void); +int ChangeDisplayModes(HINSTANCE hInst, int nCmd, + int NewVideoMode, int NewWindowMode, + int NewZBufferMode, int NewRasterisationMode, + int NewSoftwareScanDrawMode, int NewDXMemoryMode); +int DeallocateAllImages(void); +int MinimizeAllImages(void); +int RestoreAllImages(void); +void ConvertDDToInternalPalette(unsigned char* src, unsigned char* dst, int length); +PROCESSORTYPES ReadProcessorType(void); + +/* EXTERNS FOR GLOBALS GO HERE !!!!!! */ +extern DDCAPS direct_draw_caps; + +/* + + Jake's image functions + +*/ + +void * CopyD3DTexture(struct imageheader *iheader); + +#ifdef MaxImageGroups + + #if (MaxImageGroups > 1) + + void SetCurrentImageGroup(unsigned int group); + int DeallocateCurrentImages(void); + + #endif /* MaxImageGroups > 1 */ + +#endif /* defined(MaxImageGroups) */ + + +/* + Project callbacks +*/ + +void ExitGame(void); + +void ProjectSpecificBufferFlipPostProcessing(); + +void ProjectSpecificItemListPostProcessing(); + +#if optimiseflip +void ProcessProjectWhileWaitingToBeFlippable(); +#endif + +#ifdef __cplusplus +}; +#endif + +#define PLATFORM_INCLUDED + +#endif diff --git a/3dc/win95/plspecfn.c b/3dc/win95/plspecfn.c new file mode 100644 index 0000000..26c9527 --- /dev/null +++ b/3dc/win95/plspecfn.c @@ -0,0 +1,1475 @@ + +#include "3dc.h" + +#include + +#include "inline.h" +#include "module.h" +#include "stratdef.h" +#include "gamedef.h" +#include "bh_types.h" +#include "pvisible.h" + + + +#if SupportWindows95 +#include "krender.h" /* KJL 10:48:25 02/05/97 */ +#include "kzsort.h" +#include "kshape.h" +#endif + + +/* + + Platform Specific Functions + + These functions have been written specifically for a given platform. + + They are not necessarily IO or inline functions; these have their own files. + +*/ + + +/* + + externs for commonly used global variables and arrays + +*/ + + extern VECTORCH RotatedPts[]; + extern unsigned int Outcodes[]; + extern DISPLAYBLOCK *Global_ODB_Ptr; + extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + extern SHAPEHEADER *Global_ShapeHeaderPtr; + extern MATRIXCH LToVMat; + #if SupportMorphing + extern VECTORCH MorphedPts[]; + extern MORPHDISPLAY MorphDisplay; + #endif + + extern DISPLAYBLOCK *OnScreenBlockList[]; + extern int NumOnScreenBlocks; + extern int NumActiveBlocks; + extern DISPLAYBLOCK *ActiveBlockList[]; + #if SupportModules + extern char *ModuleLocalVisArray; + #endif + + + +/* + + Global Variables + +*/ + + LONGLONGCH ll_one14 = {one14, 0}; + LONGLONGCH ll_zero = {0, 0}; + + + + + + +/* + + Find out which objects are in the View Volume. + + The list of these objects, "OnScreenBlockList", is constructed in a number + of stages. + + The Range Test is a simple outcode of the View Space Location against the + Object Radius. The View Volume Test is more involved. The VSL is tested + against each of the View Volume Planes. If it is more than one Object Radius + outside any plane, the test fails. + +*/ + +/* + + This is the main view volume test shell + +*/ + + + + + + + + +#if StandardShapeLanguage + + +/* + + Shape Points + + The item array is a table of pointers to item arrays. The points data is + in the first and only item array. + + Rotate each point and write it out to the Rotated Points Buffer + + NOTE: + + There is a global pointer to the shape header "Global_ShapeHeaderPtr" + +*/ + + +#define print_bfcro_stats No + +#if SupportMorphing +#define checkmorphpts No +#endif + + +void ShapePointsInstr(SHAPEINSTR *shapeinstrptr) + +{ + + int **shapeitemarrayptr; + int *shapeitemptr; + VECTORCH *rotptsptr; + int x, y, z; + int numitems; + #if print_bfcro_stats + int num_rot, num_not_rot; + #endif + + + + /* + + Kevin, morphed doors WON'T be using shared points, so I've put your + patch here, AFTER the intercept for the shared version of the points + instruction -- Chris. + + */ + + #if KZSORT_ON /* KJL 15:13:46 02/07/97 - used for z-sorting doors correctly! */ + { + extern int *MorphedObjectPointsPtr; + MorphedObjectPointsPtr = 0; + } + #endif + + + /* Set up pointers */ + + shapeitemarrayptr = shapeinstrptr->sh_instr_data; + shapeitemptr = *shapeitemarrayptr; + rotptsptr = &RotatedPts[0]; + + + + #if SupportMorphing + + if(Global_ODB_Ptr->ObMorphCtrl) { + + + #if LazyEvaluationForMorphing + + VECTORCH *morphptsptr; + + if(Global_ODB_Ptr->ObMorphedPts == 0) { + + Global_ODB_Ptr->ObMorphedPts = GetMorphedPts(Global_ODB_Ptr, + &MorphDisplay); + + } + + morphptsptr = Global_ODB_Ptr->ObMorphedPts; + + GLOBALASSERT(shapeinstrptr->sh_numitemssh_numitems; numitems!=0; numitems--) { + + #if SUPPORT_MMX + if (use_mmx_math) + MMX_VectorTransformedAndAdd(rotptsptr,morphptsptr,<oVMat,&Global_ODB_Ptr->ObView); + else + #endif + { + rotptsptr->vx = MUL_FIXED(LToVMat.mat11, morphptsptr->vx); + rotptsptr->vx += MUL_FIXED(LToVMat.mat21, morphptsptr->vy); + rotptsptr->vx += MUL_FIXED(LToVMat.mat31, morphptsptr->vz); + rotptsptr->vx += Global_ODB_Ptr->ObView.vx; + + rotptsptr->vy = MUL_FIXED(LToVMat.mat12, morphptsptr->vx); + rotptsptr->vy += MUL_FIXED(LToVMat.mat22, morphptsptr->vy); + rotptsptr->vy += MUL_FIXED(LToVMat.mat32, morphptsptr->vz); + rotptsptr->vy += Global_ODB_Ptr->ObView.vy; + + rotptsptr->vz = MUL_FIXED(LToVMat.mat13, morphptsptr->vx); + rotptsptr->vz += MUL_FIXED(LToVMat.mat23, morphptsptr->vy); + rotptsptr->vz += MUL_FIXED(LToVMat.mat33, morphptsptr->vz); + rotptsptr->vz += Global_ODB_Ptr->ObView.vz; + } + + rotptsptr->vy = MUL_FIXED(rotptsptr->vy,87381); + morphptsptr++; + rotptsptr++; + + } + + + #else /* LazyEvaluationForMorphing */ + + + VECTORCH *morphptsptr = &MorphedPts[0]; + SHAPEHEADER *sptr1; + SHAPEHEADER *sptr2; + int *shapeitemptr1; + int *shapeitemptr2; + int x1, y1, z1; + int x2, y2, z2; + #if checkmorphpts + int num_old_pts = 0; + int num_new_pts = 0; + #endif + + + /*textprint("morphing points\n");*/ + + sptr1 = MorphDisplay.md_sptr1; + sptr2 = MorphDisplay.md_sptr2; + + shapeitemptr1 = *(sptr1->points); + shapeitemptr2 = *(sptr2->points); + + + #if KZSORT_ON /* KJL 15:13:46 02/07/97 - used for z-sorting doors correctly! */ + { + extern int *MorphedObjectPointsPtr; + MorphedObjectPointsPtr = shapeitemptr2; + } + #endif + + + for(numitems = shapeinstrptr->sh_numitems; numitems!=0; numitems--) { + + x1 = shapeitemptr1[ix]; + y1 = shapeitemptr1[iy]; + z1 = shapeitemptr1[iz]; + + x2 = shapeitemptr2[ix]; + y2 = shapeitemptr2[iy]; + z2 = shapeitemptr2[iz]; + + if(x1 == x2 && y1 == y2 && z1 == z2) { + + x = x1; + y = y1; + z = z1; + + #if checkmorphpts + num_old_pts++; + #endif + + } + + else if(MorphDisplay.md_lerp == 0) { + + x = x1; + y = y1; + z = z1; + + } + + else if(MorphDisplay.md_lerp == 0xffff) { + + x = x2; + y = y2; + z = z2; + + } + + else + { + /* KJL 15:27:20 05/22/97 - I've changed this to speed things up, If a vertex + component has a magnitude greater than 32768 things will go wrong. */ + x = x1 + (((x2-x1)*MorphDisplay.md_lerp)>>16); + y = y1 + (((y2-y1)*MorphDisplay.md_lerp)>>16); + z = z1 + (((z2-z1)*MorphDisplay.md_lerp)>>16); + + #if checkmorphpts + num_new_pts++; + #endif + + } + + morphptsptr->vx = x; + morphptsptr->vy = y; + morphptsptr->vz = z; + + /* KJL 16:07:15 11/27/97 - I know this test is inside the loop, + but all this will go when I change to float everywhere. */ + #if MIRRORING_ON + if(!Global_ODB_Ptr->ObMyModule || MirroringActive) + #else + if (!Global_ODB_Ptr->ObMyModule) + #endif + { + #if SUPPORT_MMX + if (use_mmx_math) + MMX_VectorTransformedAndAdd(rotptsptr,morphptsptr,<oVMat,&Global_ODB_Ptr->ObView); + else + #endif + { + rotptsptr->vx = MUL_FIXED(LToVMat.mat11, x); + rotptsptr->vx += MUL_FIXED(LToVMat.mat21, y); + rotptsptr->vx += MUL_FIXED(LToVMat.mat31, z); + rotptsptr->vx += Global_ODB_Ptr->ObView.vx; + + rotptsptr->vy = MUL_FIXED(LToVMat.mat12, x); + rotptsptr->vy += MUL_FIXED(LToVMat.mat22, y); + rotptsptr->vy += MUL_FIXED(LToVMat.mat32, z); + rotptsptr->vy += Global_ODB_Ptr->ObView.vy; + + rotptsptr->vz = MUL_FIXED(LToVMat.mat13, x); + rotptsptr->vz += MUL_FIXED(LToVMat.mat23, y); + rotptsptr->vz += MUL_FIXED(LToVMat.mat33, z); + rotptsptr->vz += Global_ODB_Ptr->ObView.vz; + } + } + else /* KJL 14:33:24 11/27/97 - experiment to get rid of tears */ + { + x += Global_ODB_Ptr->ObWorld.vx - Global_VDB_Ptr->VDB_World.vx; + y += Global_ODB_Ptr->ObWorld.vy - Global_VDB_Ptr->VDB_World.vy; + z += Global_ODB_Ptr->ObWorld.vz - Global_VDB_Ptr->VDB_World.vz; + + rotptsptr->vx = MUL_FIXED(LToVMat.mat11, x); + rotptsptr->vx += MUL_FIXED(LToVMat.mat21, y); + rotptsptr->vx += MUL_FIXED(LToVMat.mat31, z); + + rotptsptr->vy = MUL_FIXED(LToVMat.mat12, x); + rotptsptr->vy += MUL_FIXED(LToVMat.mat22, y); + rotptsptr->vy += MUL_FIXED(LToVMat.mat32, z); + + rotptsptr->vz = MUL_FIXED(LToVMat.mat13, x); + rotptsptr->vz += MUL_FIXED(LToVMat.mat23, y); + rotptsptr->vz += MUL_FIXED(LToVMat.mat33, z); + } + + + shapeitemptr1 += vsize; + shapeitemptr2 += vsize; + morphptsptr++; + + rotptsptr->vy = MUL_FIXED(rotptsptr->vy,87381); + rotptsptr++; + + } + + #if checkmorphpts + textprint("num_old_pts = %d\n", num_old_pts); + textprint("num_new_pts = %d\n", num_new_pts); + #endif + + + #endif /* LazyEvaluationForMorphing */ + + + } + + else { + + #endif + + #if MIRRORING_ON + int useFirstMethod = 0; + + + if(!Global_ODB_Ptr->ObMyModule || MirroringActive) + { + useFirstMethod = 1; + } + if (Global_ODB_Ptr->ObStrategyBlock) + { + #if 0 + if(Global_ODB_Ptr->ObStrategyBlock->I_SBtype == I_BehaviourInanimateObject) + { + INANIMATEOBJECT_STATUSBLOCK* osPtr = Global_ODB_Ptr->ObStrategyBlock->SBdataptr; + if(osPtr->typeId==IOT_Static) + { + useFirstMethod=0; + } + } + #endif + } + + if(useFirstMethod) + #else + if (!Global_ODB_Ptr->ObMyModule) + #endif + { + for(numitems = shapeinstrptr->sh_numitems; numitems!=0; numitems--) + { + #if SUPPORT_MMX + if (use_mmx_math) + MMX_VectorTransformedAndAdd(rotptsptr,(VECTORCH *)shapeitemptr,<oVMat,&Global_ODB_Ptr->ObView); + else + #endif + { + x = shapeitemptr[ix]; + y = shapeitemptr[iy]; + z = shapeitemptr[iz]; + + rotptsptr->vx = MUL_FIXED(LToVMat.mat11, x); + rotptsptr->vx += MUL_FIXED(LToVMat.mat21, y); + rotptsptr->vx += MUL_FIXED(LToVMat.mat31, z); + rotptsptr->vx += Global_ODB_Ptr->ObView.vx; + + rotptsptr->vy = MUL_FIXED(LToVMat.mat12, x); + rotptsptr->vy += MUL_FIXED(LToVMat.mat22, y); + rotptsptr->vy += MUL_FIXED(LToVMat.mat32, z); + rotptsptr->vy += Global_ODB_Ptr->ObView.vy; + + rotptsptr->vz = MUL_FIXED(LToVMat.mat13, x); + rotptsptr->vz += MUL_FIXED(LToVMat.mat23, y); + rotptsptr->vz += MUL_FIXED(LToVMat.mat33, z); + rotptsptr->vz += Global_ODB_Ptr->ObView.vz; + } + shapeitemptr += 3; + rotptsptr->vy = MUL_FIXED(rotptsptr->vy,87381); + rotptsptr++; + + } + } + else + { + /* KJL 14:33:24 11/27/97 - experiment to get rid of tears */ + for(numitems = shapeinstrptr->sh_numitems; numitems!=0; numitems--) + { + x = shapeitemptr[ix]; + y = shapeitemptr[iy]; + z = shapeitemptr[iz]; + + x += Global_ODB_Ptr->ObWorld.vx - Global_VDB_Ptr->VDB_World.vx; + y += Global_ODB_Ptr->ObWorld.vy - Global_VDB_Ptr->VDB_World.vy; + z += Global_ODB_Ptr->ObWorld.vz - Global_VDB_Ptr->VDB_World.vz; + + rotptsptr->vx = MUL_FIXED(LToVMat.mat11, x); + rotptsptr->vx += MUL_FIXED(LToVMat.mat21, y); + rotptsptr->vx += MUL_FIXED(LToVMat.mat31, z); + + rotptsptr->vy = MUL_FIXED(LToVMat.mat12, x); + rotptsptr->vy += MUL_FIXED(LToVMat.mat22, y); + rotptsptr->vy += MUL_FIXED(LToVMat.mat32, z); + + rotptsptr->vz = MUL_FIXED(LToVMat.mat13, x); + rotptsptr->vz += MUL_FIXED(LToVMat.mat23, y); + rotptsptr->vz += MUL_FIXED(LToVMat.mat33, z); + shapeitemptr += 3; + rotptsptr->vy = MUL_FIXED(rotptsptr->vy,87381); + rotptsptr++; + } + + } + + #if SupportMorphing + } + #endif + + +} + + +#endif /* StandardShapeLanguage */ + + + + + + + +/* + + WideMul2NarrowDiv + + This function takes two pairs of integers, adds their 64-bit products + together, divides the summed product with another integer and then returns + the result of that divide, which is also an integer. + + It is not inlined for Watcom C, although the functions it calls ARE. + +*/ + +int WideMul2NarrowDiv(int a, int b, int c, int d, int e) + +{ + + LONGLONGCH f; + LONGLONGCH g; + + + MUL_I_WIDE(a, b, &f); + MUL_I_WIDE(c, d, &g); + ADD_LL_PP(&f, &g); + + return NarrowDivide(&f, e); + +} + + + + + +/* + + Square Root + + Returns the Square Root of a 32-bit number + +*/ + +#if (SupportFPMathsFunctions || SupportFPSquareRoot) +#else + + +int SqRoot32(int A) + +{ + + unsigned int edx = A; + unsigned int ecx; + + unsigned int ax = 0; + unsigned int bx = 0; + unsigned int di = 0; + + + for(ecx = 15; ecx!=0; ecx--) { + + bx <<= 1; + if(edx & 0x80000000) bx |= 1; + edx <<= 1; + + bx <<= 1; + if(edx & 0x80000000) bx |= 1; + edx <<= 1; + + ax += ax; + di = ax; + di += di; + + if(bx > di) { + + di++; + ax++; + + bx -= di; + + } + + } + + bx <<= 1; + if(edx & 0x80000000) bx |= 1; + edx <<= 1; + + bx <<= 1; + if(edx & 0x80000000) bx |= 1; + edx <<= 1; + + ax += ax; + di = ax; + di += di; + + if(bx > di) { + + ax++; + + } + + return ((int)ax); + +} + + +#endif /* SupportFPMathsFunctions */ + + + + + + +/* + + Calculate Plane Normal from three POP's + + The three input vectors are treated as POP's and used to make two vectors. + These are then crossed to create the normal. + + Make two vectors; (2-1) & (3-1) + Cross them + Normalise the vector + Find the magnitude of the vector + Divide each component by the magnitude + +*/ + +void MakeNormal(VECTORCH *v1, VECTORCH *v2, VECTORCH *v3, VECTORCH *v4) + +{ + + +#if SupportFPMathsFunctions + + + VECTORCHF vect0; + VECTORCHF vect1; + VECTORCHF n; + + + /* vect0 = v2 - v1 */ + + vect0.vx = v2->vx - v1->vx; + vect0.vy = v2->vy - v1->vy; + vect0.vz = v2->vz - v1->vz; + + /* vect1 = v3 - v1 */ + + vect1.vx = v3->vx - v1->vx; + vect1.vy = v3->vy - v1->vy; + vect1.vz = v3->vz - v1->vz; + + + /* nx = v0y.v1z - v0z.v1y */ + + n.vx = (vect0.vy * vect1.vz) - (vect0.vz * vect1.vy); + + /* ny = v0z.v1x - v0x.v1z */ + + n.vy = (vect0.vz * vect1.vx) - (vect0.vx * vect1.vz); + + /* nz = v0x.v1y - v0y.v1x */ + + n.vz = (vect0.vx * vect1.vy) - (vect0.vy * vect1.vx); + + + FNormalise(&n); + + f2i(v4->vx, n.vx * ONE_FIXED); + f2i(v4->vy, n.vy * ONE_FIXED); + f2i(v4->vz, n.vz * ONE_FIXED); + + + #if 0 + textprint("Magnitude of v4 = %d\n", Magnitude(v4)); + WaitForReturn(); + #endif + + + +#else /* SupportFPMathsFunctions */ + + + LONGLONGCH x; + LONGLONGCH y; + LONGLONGCH z; + LONGLONGCH tmp; + VECTORCH vect0; + VECTORCH vect1; + LONGLONGCH max_abs_xyz64; + LONGLONGCH abs_xyz[3]; + int s, shift; + + + /* vect0 = v2 - v1 */ + + vect0.vx = v2->vx - v1->vx; + vect0.vy = v2->vy - v1->vy; + vect0.vz = v2->vz - v1->vz; + + /* vect1 = v3 - v1 */ + + vect1.vx = v3->vx - v1->vx; + vect1.vy = v3->vy - v1->vy; + vect1.vz = v3->vz - v1->vz; + + + /* nx = v0y.v1z - v0z.v1y */ + + #if 0 + x = + (long long)vect0.vy * (long long)vect1.vz + -(long long)vect0.vz * (long long)vect1.vy; + #endif + + MUL_I_WIDE(vect0.vy, vect1.vz, &x); + MUL_I_WIDE(vect0.vz, vect1.vy, &tmp); + SUB_LL_MM(&x, &tmp); + + + /* ny = v0z.v1x - v0x.v1z */ + + #if 0 + y = + (long long)vect0.vz * (long long)vect1.vx + -(long long)vect0.vx * (long long)vect1.vz; + #endif + + MUL_I_WIDE(vect0.vz, vect1.vx, &y); + MUL_I_WIDE(vect0.vx, vect1.vz, &tmp); + SUB_LL_MM(&y, &tmp); + + + /* nz = v0x.v1y - v0y.v1x */ + + #if 0 + z = + (long long)vect0.vx * (long long)vect1.vy + -(long long)vect0.vy * (long long)vect1.vx; + #endif + + MUL_I_WIDE(vect0.vx, vect1.vy, &z); + MUL_I_WIDE(vect0.vy, vect1.vx, &tmp); + SUB_LL_MM(&z, &tmp); + + + /* Before we can normalise we must bring these vectors down to 14-bits */ + + #if 0 + abs_xyz[0] = x; + if(abs_xyz[0] < 0) abs_xyz[0] = -abs_xyz[0]; + + abs_xyz[1] = y; + if(abs_xyz[1] < 1) abs_xyz[1] = -abs_xyz[1]; + + abs_xyz[2] = z; + if(abs_xyz[2] < 0) abs_xyz[2] = -abs_xyz[2]; + + #endif + + EQUALS_LL(&abs_xyz[0], &x); + s = CMP_LL(&abs_xyz[0], &ll_zero); + if(s < 0) NEG_LL(&abs_xyz[0]); + + EQUALS_LL(&abs_xyz[1], &y); + s = CMP_LL(&abs_xyz[1], &ll_zero); + if(s < 0) NEG_LL(&abs_xyz[1]); + + EQUALS_LL(&abs_xyz[2], &z); + s = CMP_LL(&abs_xyz[2], &ll_zero); + if(s < 0) NEG_LL(&abs_xyz[2]); + + MaxLONGLONGCH(&abs_xyz[0], 3, &max_abs_xyz64); + + shift = FindShift64(&max_abs_xyz64, &ll_one14); + + #if 0 + x >>= shift; + y >>= shift; + z >>= shift; + #endif + + ASR_LL(&x, shift); + ASR_LL(&y, shift); + ASR_LL(&z, shift); + + /* Watcom specific copying of lower 32-bits of LONGLONGCH values */ + + v4->vx = x.lo32; + v4->vy = y.lo32; + v4->vz = z.lo32; + + + + /* Normalise the vector */ + + #if 0 + textprint("v4 = %d,%d,%d\n", x.lo32, y.lo32, z.lo32); + textprint("v4 = %d,%d,%d\n", v4->vx, v4->vy, v4->vz); + #endif + + Normalise(v4); + + #if 0 + textprint(" - v4 = %d,%d,%d\n", v4->vx, v4->vy, v4->vz); + #endif + +#endif /* SupportFPMathsFunctions */ + +} + + +/* + + Normalise a vector. + + The returned vector is a fixed point unit vector. + + WARNING! + + The vector must be no larger than 2<<14 because of the square root. + Because this is an integer function, small components produce errors. + + e.g. + + (100,100,0) + + m=141 (141.42) + + nx = 100 * ONE_FIXED / m = 46,479 + ny = 100 * ONE_FIXED / m = 46,479 + nz = 0 + + New m ought to be 65,536 but in fact is 65,731 i.e. 0.29% too large. + +*/ + +void Normalise(VECTORCH *nvector) + +{ + + +#if SupportFPMathsFunctions + + + VECTORCHF n; + float m; + + + n.vx = nvector->vx; + n.vy = nvector->vy; + n.vz = nvector->vz; + + m = 65536.0/sqrt((n.vx * n.vx) + (n.vy * n.vy) + (n.vz * n.vz)); + + f2i(nvector->vx, (n.vx * m) ); + f2i(nvector->vy, (n.vy * m) ); + f2i(nvector->vz, (n.vz * m) ); + + +#else /* SupportFPMathsFunctions */ + + + int m, s; + int xsq, ysq, zsq; + + LONGLONGCH max_abs_xyz64; + + LONGLONGCH abs_xyz[3]; + + int shift; + + + /* Before we can normalise we must bring these vectors down to 14-bits */ + + IntToLL(&abs_xyz[0], &nvector->vx); + s = CMP_LL(&abs_xyz[0], &ll_zero); + if(s < 0) NEG_LL(&abs_xyz[0]); + + IntToLL(&abs_xyz[1], &nvector->vy); + s = CMP_LL(&abs_xyz[1], &ll_zero); + if(s < 0) NEG_LL(&abs_xyz[1]); + + IntToLL(&abs_xyz[2], &nvector->vz); + s = CMP_LL(&abs_xyz[2], &ll_zero); + if(s < 0) NEG_LL(&abs_xyz[2]); + + MaxLONGLONGCH(&abs_xyz[0], 3, &max_abs_xyz64); + + + #if 0 + textprint("value to shift = %d, %d\n", max_abs_xyz64.lo32, max_abs_xyz64.hi32); + #endif + + shift = FindShift64(&max_abs_xyz64, &ll_one14); + + #if 0 + textprint("shift = %d\n", shift); + #endif + + nvector->vx >>= shift; + nvector->vy >>= shift; + nvector->vz >>= shift; + + + /* Normalise */ + + xsq = nvector->vx * nvector->vx; + ysq = nvector->vy * nvector->vy; + zsq = nvector->vz * nvector->vz; + + m = SqRoot32(xsq + ysq + zsq); + + if(m == 0) m = 1; /* Just in case */ + + nvector->vx = WideMulNarrowDiv(nvector->vx, ONE_FIXED, m); + nvector->vy = WideMulNarrowDiv(nvector->vy, ONE_FIXED, m); + nvector->vz = WideMulNarrowDiv(nvector->vz, ONE_FIXED, m); + + +#endif /* SupportFPMathsFunctions */ + + +} + + + + + + + +void Normalise2d(VECTOR2D *nvector) + +{ + + +#if SupportFPMathsFunctions + + + VECTOR2DF n; + float m; + + + n.vx = nvector->vx; + n.vy = nvector->vy; + + m = sqrt((n.vx * n.vx) + (n.vy * n.vy)); + + nvector->vx = (n.vx * ONE_FIXED) / m; + nvector->vy = (n.vy * ONE_FIXED) / m; + + +#else /* SupportFPMathsFunctions */ + + + int m, s; + int xsq, ysq; + LONGLONGCH max_abs_xy64; + LONGLONGCH abs_xy[2]; + int shift; + + + /* Before we can normalise we must bring these vectors down to 14-bits */ + + IntToLL(&abs_xyz[0], &nvector->vx); + s = CMP_LL(&abs_xyz[0], &ll_zero); + if(s < 0) NEG_LL(&abs_xyz[0]); + + IntToLL(&abs_xyz[1], &nvector->vy); + s = CMP_LL(&abs_xyz[1], &ll_zero); + if(s < 0) NEG_LL(&abs_xyz[1]); + + MaxLONGLONGCH(&abs_xy[0], 2, &max_abs_xy64); + + + #if 0 + textprint("value to shift = %d, %d\n", max_abs_xyz64.lo32, max_abs_xyz64.hi32); + #endif + + shift = FindShift64(&max_abs_xy64, &ll_one14); + + #if 0 + textprint("shift = %d\n", shift); + #endif + + nvector->vx >>= shift; + nvector->vy >>= shift; + + + /* Normalise */ + + xsq = nvector->vx * nvector->vx; + ysq = nvector->vy * nvector->vy; + + m = SqRoot32(xsq + ysq); + + if(m == 0) m = 1; /* Just in case */ + + nvector->vx = WideMulNarrowDiv(nvector->vx, ONE_FIXED, m); + nvector->vy = WideMulNarrowDiv(nvector->vy, ONE_FIXED, m); + + +#endif /* SupportFPMathsFunctions */ + + +} + + + + + + + +#if SupportFPMathsFunctions + +void FNormalise(VECTORCHF *n) + +{ + + float m; + + + m = sqrt((n->vx * n->vx) + (n->vy * n->vy) + (n->vz * n->vz)); + + n->vx /= m; + n->vy /= m; + n->vz /= m; + +} + +void FNormalise2d(VECTOR2DF *n) + +{ + + float m; + + + m = sqrt((n->vx * n->vx) + (n->vy * n->vy)); + + n->vx /= m; + n->vy /= m; + +} + +#endif /* SupportFPMathsFunctions */ + + +/* + + Return the magnitude of a vector + +*/ + +int Magnitude(VECTORCH *v) + +{ + + +#if SupportFPMathsFunctions + + + + VECTORCHF n; + int m; + + + n.vx = v->vx; + n.vy = v->vy; + n.vz = v->vz; + + f2i(m, sqrt((n.vx * n.vx) + (n.vy * n.vy) + (n.vz * n.vz))); + + return m; + + +#else /* SupportFPMathsFunctions */ + + + VECTORCH vtemp; + LONGLONGCH max_abs_xyz64; + LONGLONGCH abs_xyz[3]; + int shift; + int m; + int xsq, ysq, zsq; + int s; + + + /* + + Before we can square and add the components we must bring these vectors + down to 14-bits + + */ + + IntToLL(&abs_xyz[0], &v->vx); + s = CMP_LL(&abs_xyz[0], &ll_zero); + if(s < 0) NEG_LL(&abs_xyz[0]); + + IntToLL(&abs_xyz[1], &v->vy); + s = CMP_LL(&abs_xyz[1], &ll_zero); + if(s < 0) NEG_LL(&abs_xyz[1]); + + IntToLL(&abs_xyz[2], &v->vz); + s = CMP_LL(&abs_xyz[2], &ll_zero); + if(s < 0) NEG_LL(&abs_xyz[2]); + + MaxLONGLONGCH(&abs_xyz[0], 3, &max_abs_xyz64); + + shift = FindShift64(&max_abs_xyz64, &ll_one14); + + CopyVector(v, &vtemp); + + vtemp.vx >>= shift; + vtemp.vy >>= shift; + vtemp.vz >>= shift; + + xsq = vtemp.vx * vtemp.vx; + ysq = vtemp.vy * vtemp.vy; + zsq = vtemp.vz * vtemp.vz; + + m = SqRoot32(xsq + ysq + zsq); + + m <<= shift; + + return m; + + +#endif /* SupportFPMathsFunctions */ + + +} + + + + + + + + + + +/* + + 64-bit Square Root returns 32-bit result + + All 64-bit operations are now done using the type LONGLONGCH whose format + varies from platform to platform, although it is always 64-bits in size. + + NOTE: + + Function currently not available to Watcom C users + A Floating point version is STRONGLY advised for the PC anyway + +*/ + +#if 0 +int SqRoot64(LONGLONGCH *A) + +{ + +#if 0 + + unsigned long long edx = *A; + + unsigned int eax = 0; + unsigned int ebx = 0; + unsigned int edi = 0; + + unsigned int ecx; + + + unsigned long long TopBit = 0x8000000000000000LL; + + for(ecx = 31; ecx != 0; ecx--) { + + ebx <<= 1; + if(edx & TopBit) ebx |= 1; + edx <<= 1; + + ebx <<= 1; + if(edx & TopBit) ebx |= 1; + edx <<= 1; + + eax += eax; + edi = eax; + edi += edi; + + if(ebx > edi) { + + edi++; + eax++; + ebx -= edi; + + } + + } + + ebx <<= 1; + if(edx & TopBit) ebx |= 1; + edx <<= 1; + + ebx <<= 1; + if(edx & TopBit) ebx |= 1; + edx <<= 1; + + eax += eax; + edi = eax; + edi += edi; + + if(ebx > edi) { + + eax++; + + } + + return eax; + +#endif + + return (0); + +} + +#endif /* for #if 0 */ + +/* + + Shift the 64-bit value until is LTE the limit + + Return the shift value + +*/ + +int FindShift64(LONGLONGCH *value, LONGLONGCH *limit) + +{ + + int shift = 0; + int s; + LONGLONGCH value_tmp; + + + EQUALS_LL(&value_tmp, value); + + s = CMP_LL(&value_tmp, &ll_zero); + if(s < 0) NEG_LL(&value_tmp); + + + while(GT_LL(&value_tmp, limit)) { + + shift++; + + ASR_LL(&value_tmp, 1); + + } + + return shift; + +} + + +/* + + MaxLONGLONGCH + + Return a pointer to the largest value of a long long array + +*/ + +void MaxLONGLONGCH(LONGLONGCH *llarrayptr, int llarraysize, LONGLONGCH *llmax) + +{ + + int i; + + + EQUALS_LL(llmax, &ll_zero); + + for(i = llarraysize; i!=0; i--) { + + if(LT_LL(llmax, llarrayptr)) { + + EQUALS_LL(llmax, llarrayptr); + + } + + llarrayptr++; + + } + +} + + + + + + + + + + + + +/* + + Some operators derived from the 64-bit CMP function. + + These were first defined for pcwatcom\plspecfn.h and transferred as and + when needed to other platforms. + +*/ + + +/* + + GT_LL + + To express if(a > b) + + use + + if(GT_LL(a, b)) + +*/ + +int GT_LL(LONGLONGCH *a, LONGLONGCH *b) + +{ + + int s = CMP_LL(a, b); /* a-b */ + + + if(s > 0) return (Yes); + + else return (No); + +} + + +/* + + LT_LL + + To express if(a < b) + + use + + if(LT_LL(a, b)) + +*/ + +int LT_LL(LONGLONGCH *a, LONGLONGCH *b) + +{ + + int s = CMP_LL(a, b); /* a-b */ + + + if(s < 0) return (Yes); + + else return (No); + +} + + + + +/* + + Copy Clip Point Function + +*/ + +void CopyClipPoint(CLIP_POINT *cp1, CLIP_POINT *cp2) + +{ + + cp2->ClipPoint.vx = cp1->ClipPoint.vx; + cp2->ClipPoint.vy = cp1->ClipPoint.vy; + cp2->ClipPoint.vz = cp1->ClipPoint.vz; + + cp2->ClipNormal.vx = cp1->ClipNormal.vx; + cp2->ClipNormal.vy = cp1->ClipNormal.vy; + cp2->ClipNormal.vz = cp1->ClipNormal.vz; + + cp2->ClipTexel.uuu = cp1->ClipTexel.uuu; + cp2->ClipTexel.vee = cp1->ClipTexel.vee; + + cp2->ClipInt = cp1->ClipInt; + cp2->ClipZBuffer = cp1->ClipZBuffer; + +} + + +/* + + Matrix Rotatation of a Vector - Inline Version + + Overwrite the Source Vector with the Rotated Vector + + x' = v.c1 + y' = v.c2 + z' = v.c3 + +*/ + +void RotVect(VECTORCH *v, MATRIXCH *m) + +{ + + int x, y, z; + + x = MUL_FIXED(m->mat11, v->vx); + x += MUL_FIXED(m->mat21, v->vy); + x += MUL_FIXED(m->mat31, v->vz); + + y = MUL_FIXED(m->mat12, v->vx); + y += MUL_FIXED(m->mat22, v->vy); + y += MUL_FIXED(m->mat32, v->vz); + + z = MUL_FIXED(m->mat13, v->vx); + z += MUL_FIXED(m->mat23, v->vy); + z += MUL_FIXED(m->mat33, v->vz); + + v->vx = x; + v->vy = y; + v->vz = z; + +} + + + +/* + + Dot Product Function - Inline Version + + It accepts two pointers to vectors and returns an int result + +*/ + +int _Dot(VECTORCH *vptr1, VECTORCH *vptr2) + +{ + + int dp; + + dp = MUL_FIXED(vptr1->vx, vptr2->vx); + dp += MUL_FIXED(vptr1->vy, vptr2->vy); + dp += MUL_FIXED(vptr1->vz, vptr2->vz); + + return(dp); + +} + + +/* + + Make a Vector - Inline Version + + v3 = v1 - v2 + +*/ + +void MakeV(VECTORCH *v1, VECTORCH *v2, VECTORCH *v3) + +{ + + v3->vx = v1->vx - v2->vx; + v3->vy = v1->vy - v2->vy; + v3->vz = v1->vz - v2->vz; + +} + +/* + + Add a Vector. + + v2 = v2 + v1 + +*/ + +void AddV(VECTORCH *v1, VECTORCH *v2) + +{ + + v2->vx += v1->vx; + v2->vy += v1->vy; + v2->vz += v1->vz; + +} diff --git a/3dc/win95/shpanim.h b/3dc/win95/shpanim.h new file mode 100644 index 0000000..869cc41 --- /dev/null +++ b/3dc/win95/shpanim.h @@ -0,0 +1,201 @@ +#ifndef _shp_anim_h +#define _shp_anim_h 1 + + +#ifdef __cplusplus + + extern "C" { + +#endif + + +/* + + Structures for animating shapes (not morphing) + + I am using standard types to organise the + sequences as an enum would force a complete + recompile each time it changed + +*/ + +typedef struct shapeanimationframe +{ + + // Public variables + + + + // Private variables + + int * vertices; + int * item_normals; + + +} SHAPEANIMATIONFRAME; + + +typedef struct shapeanimationsequence +{ + + // Public variables + + int radius; + + int max_x; + int max_y; + int max_z; + + int min_x; + int min_y; + int min_z; + + + // Private variables + + unsigned long num_frames; + SHAPEANIMATIONFRAME * anim_frames; + +// unsigned long num_interpolated_frames_per_frame; + // 0 for none + + int * vertex_normals; + +} SHAPEANIMATIONSEQUENCE; + + +typedef struct shapeanimationheader +{ + + // Public variables + + + // Private variables + + unsigned long num_sequences; + + SHAPEANIMATIONSEQUENCE * anim_sequences; + + int num_shapes_using_this; //number of shapes sharing the same shapeanimationheader + +} SHAPEANIMATIONHEADER; + + + +typedef struct shapeanimationcontroldata +{ + + // Public variables + + // 16.16 fixed point + unsigned long seconds_per_frame; + // default is ONE_FIXED / 8 + + unsigned long sequence_no; + // default is 0 + + // if you're not interested in setting a start and an end frame + // then set the flag 'default_start_and_end_frames' below + unsigned long start_frame; + unsigned long end_frame; + // no default values + + unsigned long default_start_and_end_frames : 1; + // default is on + + unsigned long reversed : 1; + // default is off + + unsigned long stop_at_end : 1; + // default is off + + + + // Private variables + + unsigned long empty : 1; + unsigned long stop_now : 1; + unsigned long pause_at_end : 1; + + // if start_frame == end_frame + // then do not stop unless it has done at least one frame + unsigned long done_a_frame : 1; + + SHAPEANIMATIONSEQUENCE * sequence; + + signed long current_frame; + signed long time_to_next_frame; + +} SHAPEANIMATIONCONTROLDATA; + + +typedef struct shapeanimationcontroller +{ + + // Public variables + + SHAPEANIMATIONCONTROLDATA current; + + SHAPEANIMATIONCONTROLDATA next; + + unsigned long finished : 1; + + + // Private variables + + unsigned long playing : 1; + + SHAPEANIMATIONHEADER * anim_header; + +} SHAPEANIMATIONCONTROLLER; + + + + +////////////////////////////////////////////////////////////////////////////////// +///////////////////////////// Funtions ///////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +struct displayblock; +struct shapeheader; + +// This sets the current animation (and the next to empty) +unsigned int SetShapeAnimationSequence (struct displayblock *, SHAPEANIMATIONCONTROLDATA *); +unsigned int SetOrphanedShapeAnimationSequence (SHAPEANIMATIONCONTROLLER * sac, SHAPEANIMATIONCONTROLDATA * sacd); + +// This sets the next animation (if the current is empty it will set the current) +unsigned int SetNextShapeAnimationSequence (struct displayblock *, SHAPEANIMATIONCONTROLDATA *); + +// stop_now == 1 will cause the function to ignore the end_frame value +// set end_frame to -1 for no change to the ending frame of the sequence +void SetCurrentShapeAnimationToStop (struct displayblock *, unsigned long stop_now, signed long end_frame); + +SHAPEANIMATIONCONTROLDATA const * GetCurrentShapeAnimationSequenceData (struct displayblock *); +SHAPEANIMATIONCONTROLDATA const * GetNextShapeAnimationSequenceData (struct displayblock *); + +// pause_now == 1 will cause the function to ignore the end_frame value +// set end_frame to -1 for no change to the ending frame of the sequence +void PauseCurrentShapeAnimation (struct displayblock *, unsigned long pause_now, signed long end_frame); +void RestartCurrentShapeAnimation (struct displayblock *); + +// Please use these functions, whenever you create a block of each type +void InitShapeAnimationController (SHAPEANIMATIONCONTROLLER *, struct shapeheader *); +void InitShapeAnimationControlData (SHAPEANIMATIONCONTROLDATA *); + + + + +// These are for the system + +void DoAllShapeAnimations (); + +void CopyAnimationFrameToShape (SHAPEANIMATIONCONTROLDATA *sacd, struct displayblock * dptr); + +#ifdef __cplusplus + + }; + +#endif + + +#endif \ No newline at end of file diff --git a/3dc/win95/smacker.c b/3dc/win95/smacker.c new file mode 100644 index 0000000..9b46f83 --- /dev/null +++ b/3dc/win95/smacker.c @@ -0,0 +1,775 @@ +/* KJL 15:25:20 8/16/97 + * + * smacker.c - functions to handle FMV playback + * + */ +#include "3dc.h" +#include "module.h" +#include "inline.h" +#include "stratdef.h" +#include "gamedef.h" +#include "smacker.h" +#include "avp_menus.h" +#include "avp_userprofile.h" +#include "d3_func.h" + +#define UseLocalAssert 1 +#include "ourasert.h" + +int VolumeOfNearestVideoScreen; +int PanningOfNearestVideoScreen; + +extern char *ScreenBuffer; +extern LPDIRECTSOUND DSObject; +extern int GotAnyKey; +extern void DirectReadKeyboard(void); +extern IMAGEHEADER ImageHeaderArray[]; +#if MaxImageGroups>1 +extern int NumImagesArray[]; +#else +extern int NumImages; +#endif + +void PlayFMV(char *filenamePtr); +static int NextSmackerFrame(Smack *smackHandle); +static UpdatePalette(Smack *smackHandle); + +static int GetSmackerPixelFormat(DDPIXELFORMAT *pixelFormatPtr); +void FindLightingValueFromFMV(unsigned short *bufferPtr); +void FindLightingValuesFromTriggeredFMV(unsigned char *bufferPtr, FMVTEXTURE *ftPtr); + +int SmackerSoundVolume=ONE_FIXED/512; +int MoviesAreActive; +int IntroOutroMoviesAreActive=1; + +int FmvColourRed; +int FmvColourGreen; +int FmvColourBlue; + +void PlayFMV(char *filenamePtr) +{ + Smack* smackHandle; + int playing = 1; + + if (!IntroOutroMoviesAreActive) return; + + /* use Direct sound */ + SmackSoundUseDirectSound(DSObject); + /* open smacker file */ + smackHandle = SmackOpen(filenamePtr,SMACKTRACKS,SMACKAUTOEXTRA); + if (!smackHandle) + { + char message[100]; + sprintf(message,"Unable to access file: %s\n",filenamePtr); + MessageBox(NULL,message,"AvP Error",MB_OK+MB_SYSTEMMODAL); + exit(0x111); + return; + } + + while(playing) + { + CheckForWindowsMessages(); + if (!SmackWait(smackHandle)) + playing = NextSmackerFrame(smackHandle); + + /* do something else */ +// *(ScreenBuffer + 300*640 + smackHandle->FrameNum) = 255; + + FlipBuffers(); + #if ALLOW_SKIP_INTRO + DirectReadKeyboard(); + if (GotAnyKey) playing = 0; + #endif + } + /* close file */ + SmackClose(smackHandle); +} + + + + +static int NextSmackerFrame(Smack *smackHandle) +{ + /* do we have to change the palette? */ +// if (smackHandle->NewPalette) UpdatePalette(smackHandle); + + /* unpack frame */ + extern DDPIXELFORMAT DisplayPixelFormat; + SmackToBuffer(smackHandle,(640-smackHandle->Width)/2,(480-smackHandle->Height)/2,640*2,480,(void*)ScreenBuffer,GetSmackerPixelFormat(&DisplayPixelFormat)); + SmackDoFrame(smackHandle); + + /* are we at the last frame yet? */ + if ((smackHandle->FrameNum==(smackHandle->Frames-1))) return 0; + + /* next frame, please */ + SmackNextFrame(smackHandle); + return 1; +} + +Smack* SmackHandle[4]; +#define FMV_ON 0 + +void InitFMV(void) +{ +#if FMV_ON +// char *filenamePtr = "fmvs/hugtest.smk";//"dd64_64.smk";//nintendo.smk";//"trailer.smk";//"m_togran.smk"; + + /* use Direct sound */ +// SmackSoundUseDirectSound(DSObject); + + /* open smacker file */ + SmackHandle[0] = SmackOpen("fmvs/tyrargo.smk",SMACKTRACKS,SMACKAUTOEXTRA); + SmackHandle[1] = SmackOpen("fmvs/final.smk",SMACKTRACKS,SMACKAUTOEXTRA); + SmackHandle[2] = SmackOpen("fmvs/hugtest.smk",SMACKTRACKS,SMACKAUTOEXTRA); + SmackHandle[3] = SmackOpen("fmvs/alien.smk",SMACKTRACKS,SMACKAUTOEXTRA); + +#endif +} + +int NextFMVFrame(void*bufferPtr, int x, int y, int w, int h, int fmvNumber) +{ +#if FMV_ON + int smackerFormat; + + if(!SmackHandle[fmvNumber]) return 0; + + if (SmackWait(SmackHandle[fmvNumber])) return 0; + + /* unpack frame */ + { + extern D3DINFO d3d; + smackerFormat = GetSmackerPixelFormat(&(d3d.TextureFormat[d3d.CurrentTextureFormat].ddsd.ddpfPixelFormat)); + } + if (smackerFormat) w*=2; +// if (fmvNumber==0) FindLightingValueFromFMV((unsigned short *)bufferPtr); + SmackToBuffer(SmackHandle[fmvNumber],x,y,w,h,(void*)bufferPtr,smackerFormat); + + SmackDoFrame(SmackHandle[fmvNumber]); +// textprint("at frame %d\n",SmackHandle->FrameNum); + + /* next frame, please */ + SmackNextFrame(SmackHandle[fmvNumber]); +#endif + return 1; + +} + +void UpdateFMVPalette(PALETTEENTRY *FMVPalette, int fmvNumber) +{ + unsigned char *c; + int i; + if(!SmackHandle[fmvNumber]) return; + c=SmackHandle[fmvNumber]->Palette; + + for(i=0;i<256;i++) + { + FMVPalette[i].peRed=(*c++); + FMVPalette[i].peGreen=(*c++); + FMVPalette[i].peBlue=(*c++); + } +} + + +void CloseFMV(void) +{ +#if FMV_ON + extern void KillFMVTexture(void); + if(SmackHandle[0]) SmackClose(SmackHandle[0]); + if(SmackHandle[1]) SmackClose(SmackHandle[1]); + if(SmackHandle[2]) SmackClose(SmackHandle[2]); + if(SmackHandle[3]) SmackClose(SmackHandle[3]); + KillFMVTexture(); +#endif +} + +static int GetSmackerPixelFormat(DDPIXELFORMAT *pixelFormatPtr) +{ + + if( (pixelFormatPtr->dwFlags & DDPF_RGB) && !(pixelFormatPtr->dwFlags & DDPF_PALETTEINDEXED8) ) + { + int m; + int redShift=0; + + m = pixelFormatPtr->dwRBitMask; + LOCALASSERT(m); + while(!(m&1)) m>>=1; + while(m&1) + { + m>>=1; + redShift++; + } + + if(redShift == 5) + { + /* Red componant is 5. */ + int greenShift=0; + m = pixelFormatPtr->dwGBitMask; + LOCALASSERT(m); + while(!(m&1)) m>>=1; + while(m&1) + { + m>>=1; + greenShift++; + } + if(greenShift == 5) + { + /* Green componant is 5. */ + int blueShift=0; + m = pixelFormatPtr->dwBBitMask; + LOCALASSERT(m); + while(!(m&1)) m>>=1; + while(m&1) + { + m>>=1; + blueShift++; + } + if(blueShift == 5) + { + /* Blue componant is 5. */ + return SMACKBUFFER555; + } + else + { + /* Blue componant is 6. */ + // not supported + LOCALASSERT("Smacker does not support this pixel format"==0); + return SMACKBUFFER555; + //return SMACKBUFFER556; + } + } + else + { + /* Green componant is 6. */ + return SMACKBUFFER565; + } + } + else + { + /* Red componant is 6. */ + // not supported + LOCALASSERT("Smacker does not support this pixel format"==0); + return SMACKBUFFER555; + //return SMACKBUFFER655; + } + } + else + { + return 0; + } +} + + + + + + + + + + + +void StartMenuMusic(void) +{ + char *filenamePtr = "fmvs/introsound.smk"; + + /* use Direct sound */ + SmackSoundUseDirectSound(DSObject); + + /* open smacker file */ + SmackHandle[0] = SmackOpen(filenamePtr,SMACKTRACKS|SMACKNEEDVOLUME|SMACKNEEDPAN,SMACKAUTOEXTRA); +} + +void PlayMenuMusic(void) +{ + if(!SmackHandle[0]) return; + + SmackVolumePan(SmackHandle[0],SMACKTRACKS,SmackerSoundVolume*256,32768); + + if (SmackWait(SmackHandle[0])) return; + + /* unpack frame */ + SmackDoFrame(SmackHandle[0]); + + /* next frame, please */ + SmackNextFrame(SmackHandle[0]); +} +void EndMenuMusic(void) +{ + if(!SmackHandle[0]) return; + + SmackClose(SmackHandle[0]); +} + + +void FindLightingValueFromFMV(unsigned short *bufferPtr) +{ + unsigned int totalRed=0; + unsigned int totalBlue=0; + unsigned int totalGreen=0; + + int pixels = 128*96;//64*48;//256*192; + do + { + int source = (int)(*bufferPtr++); + totalBlue += source&31; + source>>=5; + totalGreen += source&63; + source>>=6; + totalRed += source&31; + } + while(--pixels); + FmvColourRed = totalRed*4/24; + FmvColourGreen = totalGreen*4/48; + FmvColourBlue = totalBlue*4/24; + +} + + +void FindLightingValueFromCentredFMV(unsigned short *bufferPtr) +{ + unsigned int totalRed=0; + unsigned int totalBlue=0; + unsigned int totalGreen=0; + + int x,y; + + for (y=32; y<32+48; y++) + for (x=32; x<32+64; x++) + { + int source = (int)(*(unsigned short*)(bufferPtr+x+y*128)); + totalBlue += source&31; + source>>=5; + totalGreen += source&63; + source>>=6; + totalRed += source&31; + } + FmvColourRed = totalRed*4/24; + FmvColourGreen = totalGreen*4/48; + FmvColourBlue = totalBlue*4/24; + +} + + + + + +/* KJL 12:45:23 10/08/98 - FMVTEXTURE stuff */ +#define MAX_NO_FMVTEXTURES 10 +FMVTEXTURE FMVTexture[MAX_NO_FMVTEXTURES]; +int NumberOfFMVTextures; + +void ScanImagesForFMVs(void) +{ + extern void SetupFMVTexture(FMVTEXTURE *ftPtr); + int i; + IMAGEHEADER *ihPtr; + NumberOfFMVTextures=0; + + #if MaxImageGroups>1 + for (j=0; jImageName,"FMVs")) + { + Smack *smackHandle; + char filename[30]; + { + char *filenamePtr = filename; + do + { + *filenamePtr++ = *strPtr; + } + while(*strPtr++!='.'); + + *filenamePtr++='s'; + *filenamePtr++='m'; + *filenamePtr++='k'; + *filenamePtr=0; + } + + smackHandle = SmackOpen(filename,SMACKTRACKS|SMACKNEEDVOLUME|SMACKNEEDPAN,SMACKAUTOEXTRA); + if (smackHandle) + { + FMVTexture[NumberOfFMVTextures].IsTriggeredPlotFMV = 0; + } + else + { + FMVTexture[NumberOfFMVTextures].IsTriggeredPlotFMV = 1; + } + + { + FMVTexture[NumberOfFMVTextures].SmackHandle = smackHandle; + FMVTexture[NumberOfFMVTextures].ImagePtr = ihPtr; + FMVTexture[NumberOfFMVTextures].StaticImageDrawn=0; + SetupFMVTexture(&FMVTexture[NumberOfFMVTextures]); + NumberOfFMVTextures++; + } + } + } + } + } + + +} + +void UpdateAllFMVTextures(void) +{ + extern void UpdateFMVTexture(FMVTEXTURE *ftPtr); + int i = NumberOfFMVTextures; + + while(i--) + { + UpdateFMVTexture(&FMVTexture[i]); + } + +} + +void ReleaseAllFMVTextures(void) +{ + extern void UpdateFMVTexture(FMVTEXTURE *ftPtr); + int i = NumberOfFMVTextures; + + while(i--) + { + FMVTexture[i].MessageNumber = 0; + if(FMVTexture[i].SmackHandle) + { + SmackClose(FMVTexture[i].SmackHandle); + FMVTexture[i].SmackHandle=0; + } + if (FMVTexture[i].SrcTexture) + { + ReleaseD3DTexture(FMVTexture[i].SrcTexture); + FMVTexture[i].SrcTexture=0; + } + if (FMVTexture[i].SrcSurface) + { + ReleaseDDSurface(FMVTexture[i].SrcSurface); + FMVTexture[i].SrcSurface=0; + } + if (FMVTexture[i].DestTexture) + { + ReleaseD3DTexture(FMVTexture[i].DestTexture); + FMVTexture[i].DestTexture = 0; + } + } + +} + + +int NextFMVTextureFrame(FMVTEXTURE *ftPtr, void *bufferPtr) +{ + int smackerFormat; + int w = 128; + + { + extern D3DINFO d3d; + smackerFormat = GetSmackerPixelFormat(&(d3d.TextureFormat[d3d.CurrentTextureFormat].ddsd.ddpfPixelFormat)); + } + if (smackerFormat) w*=2; + + if (MoviesAreActive && ftPtr->SmackHandle) + { + int volume = MUL_FIXED(SmackerSoundVolume*256,GetVolumeOfNearestVideoScreen()); + SmackVolumePan(ftPtr->SmackHandle,SMACKTRACKS,volume,PanningOfNearestVideoScreen); + ftPtr->SoundVolume = SmackerSoundVolume; + + if (SmackWait(ftPtr->SmackHandle)) return 0; + /* unpack frame */ + SmackToBuffer(ftPtr->SmackHandle,0,0,w,96,bufferPtr,smackerFormat); + + SmackDoFrame(ftPtr->SmackHandle); + + /* are we at the last frame yet? */ + if (ftPtr->IsTriggeredPlotFMV && (ftPtr->SmackHandle->FrameNum==(ftPtr->SmackHandle->Frames-1)) ) + { + SmackClose(ftPtr->SmackHandle); + ftPtr->SmackHandle = 0; + ftPtr->MessageNumber = 0; + } + else + { + /* next frame, please */ + SmackNextFrame(ftPtr->SmackHandle); + } + ftPtr->StaticImageDrawn=0; + } + else if (!ftPtr->StaticImageDrawn || smackerFormat) + { + int i = w*96/4; + unsigned int seed = FastRandom(); + int *ptr = (int*)bufferPtr; + do + { + seed = ((seed*1664525)+1013904223); + *ptr++ = seed; + } + while(--i); + ftPtr->StaticImageDrawn=1; + } + FindLightingValuesFromTriggeredFMV((unsigned char*)bufferPtr,ftPtr); + return 1; + +} + +void UpdateFMVTexturePalette(FMVTEXTURE *ftPtr) +{ + unsigned char *c; + int i; + + if (MoviesAreActive && ftPtr->SmackHandle) + { + c=ftPtr->SmackHandle->Palette; + + for(i=0;i<256;i++) + { + ftPtr->SrcPalette[i].peRed=(*c++); + ftPtr->SrcPalette[i].peGreen=(*c++); + ftPtr->SrcPalette[i].peBlue=(*c++); + } + } + else + { + { + unsigned int seed = FastRandom(); + for(i=0;i<256;i++) + { + int l = (seed&(seed>>24)&(seed>>16)); + seed = ((seed*1664525)+1013904223); + ftPtr->SrcPalette[i].peRed=l; + ftPtr->SrcPalette[i].peGreen=l; + ftPtr->SrcPalette[i].peBlue=l; + } + } + } +} + +extern void StartTriggerPlotFMV(int number) +{ + int i = NumberOfFMVTextures; + char buffer[25]; + + if (CheatMode_Active != CHEATMODE_NONACTIVE) return; + + sprintf(buffer,"FMVs//message%d.smk",number); + { + FILE* file=fopen(buffer,"rb"); + if(!file) + { + return; + } + fclose(file); + } + while(i--) + { + if (FMVTexture[i].IsTriggeredPlotFMV) + { + if(FMVTexture[i].SmackHandle) + { + SmackClose(FMVTexture[i].SmackHandle); + } + + FMVTexture[i].SmackHandle = SmackOpen(&buffer,SMACKTRACKS|SMACKNEEDVOLUME|SMACKNEEDPAN,SMACKAUTOEXTRA); + FMVTexture[i].MessageNumber = number; + } + } +} +extern void StartFMVAtFrame(int number, int frame) +{ + int i = NumberOfFMVTextures; + + StartTriggerPlotFMV(number); + + while(i--) + { + if (FMVTexture[i].IsTriggeredPlotFMV) + { + if(FMVTexture[i].SmackHandle) + { + SmackSoundOnOff(FMVTexture[i].SmackHandle,0); // turn off sound so that it is synched + SmackGoto(FMVTexture[i].SmackHandle,frame); + SmackSoundOnOff(FMVTexture[i].SmackHandle,1); // turn on sound so that it is synched +// SmackNextFrame(FMVTexture[i].SmackHandle); + } + } + } + +} +extern void GetFMVInformation(int *messageNumberPtr, int *frameNumberPtr) +{ + int i = NumberOfFMVTextures; + + while(i--) + { + if (FMVTexture[i].IsTriggeredPlotFMV) + { + if(FMVTexture[i].SmackHandle) + { + *messageNumberPtr = FMVTexture[i].MessageNumber; + *frameNumberPtr = FMVTexture[i].SmackHandle->FrameNum; + return; + } + } + } + + *messageNumberPtr = 0; + *frameNumberPtr = 0; +} + + +extern void InitialiseTriggeredFMVs(void) +{ + int i = NumberOfFMVTextures; + while(i--) + { + if (FMVTexture[i].IsTriggeredPlotFMV) + { + if(FMVTexture[i].SmackHandle) + { + SmackClose(FMVTexture[i].SmackHandle); + FMVTexture[i].MessageNumber = 0; + } + + FMVTexture[i].SmackHandle = 0; + } + } +} + +void FindLightingValuesFromTriggeredFMV(unsigned char *bufferPtr, FMVTEXTURE *ftPtr) +{ + unsigned int totalRed=0; + unsigned int totalBlue=0; + unsigned int totalGreen=0; + #if 0 + int pixels = 128*96;//64*48;//256*192; + do + { + unsigned char source = (*bufferPtr++); + totalBlue += ftPtr->SrcPalette[source].peBlue; + totalGreen += ftPtr->SrcPalette[source].peGreen; + totalRed += ftPtr->SrcPalette[source].peRed; + } + while(--pixels); + #else + int pixels = 128*96/4;//64*48;//256*192; + unsigned int *source = (unsigned int*) (bufferPtr); + do + { + int s = *source++; + { + int t = s&255; + totalBlue += ftPtr->SrcPalette[t].peBlue; + totalGreen += ftPtr->SrcPalette[t].peGreen; + totalRed += ftPtr->SrcPalette[t].peRed; + } + #if 0 + s >>=8; + { + int t = s&255; + totalBlue += ftPtr->SrcPalette[t].peBlue; + totalGreen += ftPtr->SrcPalette[t].peGreen; + totalRed += ftPtr->SrcPalette[t].peRed; + } + s >>=8; + { + int t = s&255; + totalBlue += ftPtr->SrcPalette[t].peBlue; + totalGreen += ftPtr->SrcPalette[t].peGreen; + totalRed += ftPtr->SrcPalette[t].peRed; + } + s >>=8; + { + int t = s; + totalBlue += ftPtr->SrcPalette[t].peBlue; + totalGreen += ftPtr->SrcPalette[t].peGreen; + totalRed += ftPtr->SrcPalette[t].peRed; + } + #endif + } + while(--pixels); + #endif + FmvColourRed = totalRed/48*16; + FmvColourGreen = totalGreen/48*16; + FmvColourBlue = totalBlue/48*16; + +} + +extern int NumActiveBlocks; +extern DISPLAYBLOCK *ActiveBlockList[]; +#include "showcmds.h" +int GetVolumeOfNearestVideoScreen(void) +{ + extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr; + int numberOfObjects = NumActiveBlocks; + int leastDistanceRecorded = 0x7fffffff; + VolumeOfNearestVideoScreen = 0; + + { + extern char LevelName[]; + if (!_stricmp(LevelName,"invasion_a")) + { + VolumeOfNearestVideoScreen = ONE_FIXED; + PanningOfNearestVideoScreen = ONE_FIXED/2; + } + } + + while (numberOfObjects) + { + DISPLAYBLOCK* objectPtr = ActiveBlockList[--numberOfObjects]; + STRATEGYBLOCK* sbPtr = objectPtr->ObStrategyBlock; + + if (sbPtr) + { + if (sbPtr->I_SBtype == I_BehaviourVideoScreen) + { + int dist; + VECTORCH disp; + + disp.vx = objectPtr->ObWorld.vx - Global_VDB_Ptr->VDB_World.vx; + disp.vy = objectPtr->ObWorld.vy - Global_VDB_Ptr->VDB_World.vy; + disp.vz = objectPtr->ObWorld.vz - Global_VDB_Ptr->VDB_World.vz; + + dist = Approximate3dMagnitude(&disp); + if (distONE_FIXED) VolumeOfNearestVideoScreen = ONE_FIXED; + + { + VECTORCH rightEarDirection; + #if 0 + rightEarDirection.vx = Global_VDB_Ptr->VDB_Mat.mat11; + rightEarDirection.vy = Global_VDB_Ptr->VDB_Mat.mat12; + rightEarDirection.vz = Global_VDB_Ptr->VDB_Mat.mat13; + Normalise(&disp); + #else + rightEarDirection.vx = Global_VDB_Ptr->VDB_Mat.mat11; + rightEarDirection.vy = 0; + rightEarDirection.vz = Global_VDB_Ptr->VDB_Mat.mat31; + disp.vy=0; + Normalise(&disp); + Normalise(&rightEarDirection); + #endif + PanningOfNearestVideoScreen = 32768 + DotProduct(&disp,&rightEarDirection)/2; + } + } + } + } + } + PrintDebuggingText("Volume: %d, Pan %d\n",VolumeOfNearestVideoScreen,PanningOfNearestVideoScreen); + return VolumeOfNearestVideoScreen; +} \ No newline at end of file diff --git a/3dc/win95/smacker.h b/3dc/win95/smacker.h new file mode 100644 index 0000000..3fd364a --- /dev/null +++ b/3dc/win95/smacker.h @@ -0,0 +1,43 @@ +/* KJL 15:25:20 8/16/97 + * + * smacker.h - functions to handle FMV playback + * + */ +#include "smack.h" + +extern void PlayFMV(char *filenamePtr); +extern void StartMenuMusic(void); +extern void PlayMenuMusic(void); +extern void EndMenuMusic(void); + + + +typedef struct +{ + IMAGEHEADER *ImagePtr; + Smack *SmackHandle; + int SoundVolume; + int IsTriggeredPlotFMV; + int StaticImageDrawn; + + int MessageNumber; + + LPDIRECTDRAWSURFACE SrcSurface; + LPDIRECT3DTEXTURE SrcTexture; + LPDIRECT3DTEXTURE DestTexture; + PALETTEENTRY SrcPalette[256]; + + int RedScale; + int GreenScale; + int BlueScale; + +} FMVTEXTURE; + + +extern int NextFMVTextureFrame(FMVTEXTURE *ftPtr, void *bufferPtr); +extern void UpdateFMVTexturePalette(FMVTEXTURE *ftPtr); +extern void InitialiseTriggeredFMVs(void); +extern void StartTriggerPlotFMV(int number); + +extern void StartFMVAtFrame(int number, int frame); +extern void GetFMVInformation(int *messageNumberPtr, int *frameNumberPtr); diff --git a/3dc/win95/vssver.scc b/3dc/win95/vssver.scc new file mode 100644 index 0000000..e1862dd Binary files /dev/null and b/3dc/win95/vssver.scc differ diff --git a/3dc/win95/win_func.cpp b/3dc/win95/win_func.cpp new file mode 100644 index 0000000..6be299e --- /dev/null +++ b/3dc/win95/win_func.cpp @@ -0,0 +1,334 @@ +/**** + +Windows functionality that is definitely +not project specific. + +****/ + +// To link code to main C functions + +extern "C" { + +#include "3dc.h" +#include "inline.h" + +// For modifications necessary to make Alt-Tabbing +// behaviour (WM_ACTIVATEAPP) work full screen. +// This is necessary to support full screen +// ActiveMovie play. + +#define SupportAltTab Yes + +// Globals + +static HANDLE RasterThread; + +// Externs + +extern BOOL bActive; + +// These function are here solely to provide a clean +// interface layer, since Win32 include files are fully +// available in both C and C++. +// All functions linking to standard windows code are +// in win_func.cpp or win_proj.cpp, and all DirectX +// interface functions +// should be in dd_func.cpp (in the Win95 directory) +// or d3_func.cpp, dp_func.cpp, ds_func.cpp etc. +// Project specific platfrom functionality for Win95 +// should be in project/win95, in files called +// dd_proj.cpp etc. + + +// GetTickCount is the standard windows return +// millisecond time function, which isn't actually +// accurate to a millisecond. In order to get FRI +// to work properly with GetTickCount at high frame +// rates, you will have to switch KalmanTimer to Yes +// at the start of io.c to turn on a filtering algorithm +// in the frame counter handler. +// Alternately, we can use the mm function +// timeGetTime to get the time accurate to a millisecond. +// There is still enough variation in this to make +// the kalman filter probably worthwhile, however. + +long GetWindowsTickCount(void) + +{ + #if 0 + return GetTickCount(); + #else + return timeGetTime(); + #endif +} + +// This function is set up using a PeekMessage check, +// with a return on a failure of GetMessage, on the +// grounds that it might be more stable than just +// GetMessage. But then again, maybe not. +// PM_NOREMOVE means do not take this message out of +// the queue. The while loop is designed to ensure +// that all messages are sent through to the Windows +// Procedure are associated with a maximum of one frame's +// delay in the main engine cycle, ensuring that e.g. +// keydown messages do not build up in the queue. + +// if necessary, one could extern this flag +// to determine if a task-switch has occurred which might +// have trashed a static display, to decide whether to +// redraw the screen. After doing so, one should reset +// the flag + +BOOL g_bMustRedrawScreen = FALSE; + +void CheckForWindowsMessages(void) +{ + MSG msg; + extern signed int MouseWheelStatus; + + MouseWheelStatus = 0; + + // Initialisation for the current embarassingly primitive mouse + // handler... + + do + { + while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) + { + if (!GetMessage(&msg, NULL, 0, 0)) + return; + + TranslateMessage(&msg); + DispatchMessage(&msg); + + #if (!SupportAltTab) + // Panic + if (!bActive) + { + // Dubious hack... + #if 0 + ExitSystem(); + #else + ReleaseDirect3D(); + exit(0x00); + #endif + } + #endif + } + + // JH 13/2/98 - if the app is not active we should not return from the message lopp + // until the app is re-activated + + if (!bActive) + { + ResetFrameCounter(); + Sleep(0); + g_bMustRedrawScreen = TRUE; + } + } + while (!bActive); +} + + + + +// Experimental functions to handle a separate +// thread to run rasterisation on hardware at low +// priority. + +// Note that the RenderD3DScene function does not need +// to call ExitThread explictly - the return at the +// end of the function will do this for this, giving +// thread exit code equal to the return value from +// the function. + +/* + Note that this assumes DrawPerFrame mode!!! + necessary for some hardware accelerators anyway + (deferred texturing problem!!!) +*/ + +BOOL SpawnRasterThread() + +{ + DWORD RasterThreadId; + // Stack size of new thread in bytes. + // For the moment, we will set it to + // 128K, the normal size for the engine + // process. + // Note that this is in bytes. + // Note that stack size should grow as + // necessary. We hope. + DWORD StackSize = 128 * 1024; + + + // Create the thread + RasterThread = CreateThread( + NULL, // no security + StackSize, // default stack size + (LPTHREAD_START_ROUTINE) RenderD3DScene, + 0, // no argument for function + 0, // default creation flags + &RasterThreadId); // get thread ID + + if (RasterThread == NULL) + { + #if debug + ReleaseDirect3D(); + exit(0xabab); + #else + return FALSE; + #endif + } + + #if 1 + // Set the priority on the thread to + // below normal, since we want this thread + // to be unimportant --- it is only monitoring + // the hardware rasteriser. Hopefully. + // Note that this priority value maybe should + // be THREAD_PRIORITY_LOWEST or THREAD_PRIORITY_IDLE, + // or maybe we shouldn't call this function at all. + // Also, we must have a THREAD_SET_INFORMATION + // access right associated with the thread for this + // to work. Hopefully, this should be the default + // when using CreateThread. + SetThreadPriority(RasterThread, + THREAD_PRIORITY_NORMAL); + #endif + + return TRUE; +} + +BOOL WaitForRasterThread() + +{ + BOOL RetVal; + DWORD ThreadStatus; + int i; + + // Note that if this is to work the + // rasterisation thread must have a + // THREAD_QUERY_INFORMATION access right, + // but we believe CreateThread should supply + // this as a default. + + // Note!!! At some stage we may want to put a + // delay loop in the statement below, in the + // time honoured Saturn fashion, depending on how + // much impact calling GetExitCodeThread has on the + // rest of the system - hopefully not much... + + do + { + RetVal = GetExitCodeThread(RasterThread, + &ThreadStatus); + } + while ((RetVal == TRUE) && + (ThreadStatus == STILL_ACTIVE)); + + // Failed to get a status report on the thread + if (RetVal == FALSE) + { + #if debug + ReleaseDirect3D(); + exit(0xabbb); + #else + return FALSE; + #endif + } + + return TRUE; +} + + +/* + Pick up processor types, + either from assembler test (note + I have asm to do this, but it must + be converted from as / Motorola format + to masm / Intel), or (more likely) from + a text file left by the launcher, which + can use GetProcessorType from the + mssetup api +*/ + +#ifdef __WATCOMC__ + +unsigned int GetCPUId(void); +#pragma aux GetCPUId = "mov eax,1" "cpuid" value [edx] modify [eax ebx ecx]; + +#elif defined(_MSC_VER) + +static unsigned int GetCPUId(void) +{ + unsigned int retval; + _asm + { + mov eax,1 + _emit 0x0f ; CPUID (00001111 10100010) - This is a Pentium + ; specific instruction which gets information on the + _emit 0xa2 ; processor. A Pentium family processor should set + ; bits 11-8 of eax to 5. + mov retval,edx + } + return retval; +} + +#else + +#error "Unknown compiler" + +#endif + + +PROCESSORTYPES ReadProcessorType(void) +{ + SYSTEM_INFO SystemInfo; + int ProcessorType; + PROCESSORTYPES RetVal; + + GetSystemInfo(&SystemInfo); + + ProcessorType = SystemInfo.dwProcessorType; + + switch (ProcessorType) + { + case PROCESSOR_INTEL_386: + RetVal = PType_OffBottomOfScale; + break; + + case PROCESSOR_INTEL_486: + RetVal = PType_486; + break; + + case PROCESSOR_INTEL_PENTIUM: + if (GetCPUId() & 0x00800000) + RetVal = PType_PentiumMMX; + else + RetVal = PType_Pentium; + break; + + #if 0 + case PROCESSOR_INTEL_SOMETHING: + RetVal = PType_Klamath; + break; + #endif + + default: + RetVal = PType_OffTopOfScale; + break; + } + + return RetVal; +} + + + +// End of extern C declaration + +}; + + + + diff --git a/3dc/win95/wpchunk.cpp b/3dc/win95/wpchunk.cpp new file mode 100644 index 0000000..c26a5a6 --- /dev/null +++ b/3dc/win95/wpchunk.cpp @@ -0,0 +1,575 @@ +#include "wpchunk.hpp" + +//macro for helping to force inclusion of chunks when using libraries +FORCE_CHUNK_INCLUDE_IMPLEMENT(wpchunk) + +ChunkWaypoint::ChunkWaypoint() +{ + index=-1; + NumWPLinks=0; + WayLinks=0; + NumModLinks=0; + ModLinks=0; + flags=0; + spare2=0; +} +ChunkWaypoint::~ChunkWaypoint() +{ + if(WayLinks) delete [] WayLinks; + if(ModLinks) delete [] ModLinks; +} +ModuleLink::~ModuleLink() +{ + if(module_name) delete module_name; +} + +RIF_IMPLEMENT_DYNCREATE("WAYPOINT",Module_Waypoint_Chunk) + + +#if UseOldChunkLoader +Module_Waypoint_Chunk::Module_Waypoint_Chunk(Chunk_With_Children* parent,const char* data,size_t datasize) +:Chunk(parent,"WAYPOINT") +{ + NumWaypoints=*(int*)data; + data+=4; + if(NumWaypoints) + Waypoints=new ChunkWaypoint[NumWaypoints]; + else + Waypoints=0; + + for(int i=0;iindex=i; + + cw->min=*(ChunkVector*)data; + data+=sizeof(ChunkVector); + cw->max=*(ChunkVector*)data; + data+=sizeof(ChunkVector); + cw->centre=*(ChunkVector*)data; + data+=sizeof(ChunkVector); + + cw->flags=*(int*)data; + data+=4; + cw->spare2=*(int*)data; + data+=4; + + cw->NumWPLinks=*(int*)data; + data+=4; + + if(cw->NumWPLinks) + cw->WayLinks=new WaypointLink[cw->NumWPLinks]; + else + cw->WayLinks=0; + + for(int j=0;jNumWPLinks;j++) + { + cw->WayLinks[j]=*(WaypointLink*)data; + data+=sizeof(WaypointLink); + } + + cw->NumModLinks=*(int*)data; + data+=4; + + if(cw->NumModLinks) + cw->ModLinks=new ModuleLink[cw->NumModLinks]; + else + cw->ModLinks=0; + + for(j=0;jNumModLinks;j++) + { + ModuleLink* ml=&cw->ModLinks[j]; + ml->module_name=new char[strlen(data)+1]; + strcpy(ml->module_name,data); + data+=(strlen(data)+4)&~3; + ml->flags=*(int*)data; + data+=4; + } + + + } + + spare1=*(int*)data; + data+=4; + spare2=*(int*)data; + data+=4; +} +#else +Module_Waypoint_Chunk::Module_Waypoint_Chunk(Chunk_With_Children* parent,const char* data,size_t datasize) +:Chunk(parent,"WAYPOINT") +{ + NumWaypoints=*(int*)data; + data+=4; + + NumGroundWaypoints=0; + NumAlienWaypoints=0; + AlienWaypoints=0; + GroundWaypoints=0; + + if(NumWaypoints) + Waypoints=new ChunkWaypoint[NumWaypoints]; + else + Waypoints=0; + + if(NumWaypoints) + { + int first_ground_waypoint=-1; + for(int i=0;iindex=i; + + cw->min=*(ChunkVectorInt*)data; + data+=sizeof(ChunkVectorInt); + cw->max=*(ChunkVectorInt*)data; + data+=sizeof(ChunkVectorInt); + cw->centre=*(ChunkVectorInt*)data; + data+=sizeof(ChunkVectorInt); + + cw->flags=*(int*)data; + data+=4; + cw->spare2=*(int*)data; + data+=4; + + cw->NumWPLinks=*(int*)data; + data+=4; + + if(cw->NumWPLinks) + cw->WayLinks=new WaypointLink[cw->NumWPLinks]; + else + cw->WayLinks=0; + + for(int j=0;jNumWPLinks;j++) + { + cw->WayLinks[j]=*(WaypointLink*)data; + data+=sizeof(WaypointLink); + } + + cw->NumModLinks=*(int*)data; + data+=4; + + if(cw->NumModLinks) + cw->ModLinks=new ModuleLink[cw->NumModLinks]; + else + cw->ModLinks=0; + + for(j=0;jNumModLinks;j++) + { + ModuleLink* ml=&cw->ModLinks[j]; + ml->module_name=new char[strlen(data)+1]; + strcpy(ml->module_name,data); + data+=(strlen(data)+4)&~3; + ml->flags=*(int*)data; + data+=4; + } + + if(cw->flags & WaypointFlag_FirstGroundWaypoint) + { + first_ground_waypoint=i; + cw->flags &=~WaypointFlag_FirstGroundWaypoint; + } + } + + if(first_ground_waypoint>=0) + { + GroundWaypoints=&Waypoints[first_ground_waypoint]; + NumGroundWaypoints=NumWaypoints-first_ground_waypoint; + } + NumAlienWaypoints=NumWaypoints-NumGroundWaypoints; + if(NumAlienWaypoints) + { + AlienWaypoints=&Waypoints[0]; + } + + + } + + + spare1=*(int*)data; + data+=4; + spare2=*(int*)data; + data+=4; + +} +#endif + +Module_Waypoint_Chunk::Module_Waypoint_Chunk(Chunk_With_Children* parent) +:Chunk(parent,"WAYPOINT") +{ + NumWaypoints=0; + Waypoints=0; + + NumAlienWaypoints=0; + AlienWaypoints=0; + + NumGroundWaypoints=0; + GroundWaypoints=0; + + + spare1=0; + spare2=0; +} + +Module_Waypoint_Chunk::~Module_Waypoint_Chunk() +{ + if(Waypoints) + delete [] Waypoints; +} + +size_t Module_Waypoint_Chunk::size_chunk() +{ + chunk_size=16; + for(int i=0;imin; + data_start+=sizeof(ChunkVectorInt); + *(ChunkVectorInt*)data_start=cw->max; + data_start+=sizeof(ChunkVectorInt); + *(ChunkVectorInt*)data_start=cw->centre; + data_start+=sizeof(ChunkVectorInt); + + if(i==NumAlienWaypoints) + { + //mark start of marine waypoints + *(int*)data_start=cw->flags | WaypointFlag_FirstGroundWaypoint; + } + else + { + *(int*)data_start=cw->flags; + } + data_start+=4; + + *(int*)data_start=cw->spare2; + data_start+=4; + + *(int*)data_start=cw->NumWPLinks; + data_start+=4; + + for(int j=0;jNumWPLinks;j++) + { + *(WaypointLink*)data_start=cw->WayLinks[j]; + data_start+=sizeof(WaypointLink); + } + + *(int*)data_start=cw->NumModLinks; + data_start+=4; + + for(j=0;jNumModLinks;j++) + { + ModuleLink* ml=&cw->ModLinks[j]; + strcpy(data_start,ml->module_name); + data_start+=(strlen(ml->module_name)+4)&~3; + *(int*)data_start=ml->flags; + data_start+=4; + } + + } +} + +void Module_Waypoint_Chunk::TransferWaypointData(Module_Waypoint_Chunk* mwc_from) +{ + if(!mwc_from)return; + if(!mwc_from->NumWaypoints)return; + if(mwc_from==this)return; + + if(mwc_from->NumWaypoints) + { + ChunkWaypoint* new_wp=new ChunkWaypoint[NumWaypoints+mwc_from->NumWaypoints]; + //first take alien waypoints from this chunk + for(int i=0;iNumAlienWaypoints;i++) + { + ChunkWaypoint* cw=&new_wp[i+NumAlienWaypoints]; + *cw=mwc_from->AlienWaypoints[i]; + //set pointers to zero so the memory doesn't get deallocated when the old + //waypoint chunk is deleted + mwc_from->AlienWaypoints[i].WayLinks=0; + mwc_from->AlienWaypoints[i].ModLinks=0; + + //adjust the indeces + cw->index+=NumAlienWaypoints; + for(int j=0;jNumWPLinks;j++) + { + cw->WayLinks[j].index+=NumAlienWaypoints; + } + } + NumAlienWaypoints+=mwc_from->NumAlienWaypoints; + + //now take ground waypoints from this chunk + for(i=0;iNumGroundWaypoints;i++) + { + ChunkWaypoint* cw=&new_wp[i+NumAlienWaypoints+NumGroundWaypoints]; + *cw=mwc_from->GroundWaypoints[i]; + //set pointers to zero so the memory doesn't get deallocated when the old + //waypoint chunk is deleted + mwc_from->GroundWaypoints[i].WayLinks=0; + mwc_from->GroundWaypoints[i].ModLinks=0; + + //adjust the indeces + cw->index+=NumGroundWaypoints; + for(int j=0;jNumWPLinks;j++) + { + cw->WayLinks[j].index+=NumGroundWaypoints; + } + } + NumGroundWaypoints+=mwc_from->NumGroundWaypoints; + + NumWaypoints+=mwc_from->NumWaypoints; + //replace pointer to waypoints + delete [] Waypoints; + Waypoints=new_wp; + } + + if(NumAlienWaypoints) + AlienWaypoints=&Waypoints[0]; + else + AlienWaypoints=0; + + if(NumGroundWaypoints) + GroundWaypoints=&Waypoints[NumAlienWaypoints]; + else + GroundWaypoints=0; + + + delete mwc_from; + +} +/////////////////////////////////////////////////////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("AIMODMAS",AI_Module_Master_Chunk) + +AI_Module_Master_Chunk::AI_Module_Master_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk(parent,"AIMODMAS") +{ +} + +AI_Module_Master_Chunk::AI_Module_Master_Chunk(Object_Module_Data_Chunk* parent) +:Chunk(parent,"AIMODMAS") +{ +} + + +size_t AI_Module_Master_Chunk::size_chunk() +{ + chunk_size=12; + return chunk_size; +} + +void AI_Module_Master_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; +} + +AI_Module_Slave_Chunk* AddModuleSlaveChunk(Object_Chunk* oc,Object_Chunk* master) +{ + Object_Module_Data_Chunk* omdc=0; + omdc=(Object_Module_Data_Chunk*)oc->lookup_single_child("MODULEDT"); + if(!omdc) + omdc=new Object_Module_Data_Chunk(oc); + + Chunk* child_chunk=omdc->lookup_single_child("AIMODSLA"); + + if(child_chunk) + delete child_chunk; + + return new AI_Module_Slave_Chunk(omdc,master); + +} + +void AI_Module_Master_Chunk::AddModule(Object_Chunk* oc) +{ + if(ModuleList.contains(oc)) return; + if(oc==get_my_object_chunk()) return; + + Object_Module_Data_Chunk* omdc=0; + omdc=(Object_Module_Data_Chunk*)oc->lookup_single_child("MODULEDT"); + + if(omdc) + { + List chlist; + omdc->lookup_child("AIMODMAS",chlist); + if(chlist.size()) + { + //if the module being added is a master , add all its slaves as well + AI_Module_Master_Chunk* ammc=(AI_Module_Master_Chunk*)chlist.first_entry(); + for(LIF oblif(&ammc->ModuleList);!oblif.done();oblif.next()) + { + if(!ModuleList.contains(oblif()) && oblif()!=get_my_object_chunk()) + { + ModuleList.add_entry(oblif()); + //create new slave chunks for the modules being added + AddModuleSlaveChunk(oblif(),get_my_object_chunk()); + } + } + delete ammc; + } + } + + //add this module + ModuleList.add_entry(oc); + AddModuleSlaveChunk(oc,get_my_object_chunk()); + + //see if there are any waypoints to copy + if(omdc) + { + Module_Waypoint_Chunk* mwc_from=(Module_Waypoint_Chunk*)omdc->lookup_single_child("WAYPOINT"); + if(mwc_from) + { + Module_Waypoint_Chunk* mwc_to=0; + + mwc_to=(Module_Waypoint_Chunk*)parent->lookup_single_child("WAYPOINT"); + if(!mwc_to) + mwc_to=new Module_Waypoint_Chunk(parent); + + mwc_to->TransferWaypointData(mwc_from); + + + } + } + +} + +Object_Chunk* AI_Module_Master_Chunk::get_my_object_chunk() +{ + return (Object_Chunk*)((Object_Module_Data_Chunk*)parent)->parent; +} + +/////////////////////////////////////////////////////////////////////////////// + +RIF_IMPLEMENT_DYNCREATE("AIMODSLA",AI_Module_Slave_Chunk) + +#if UseOldChunkLoader +AI_Module_Slave_Chunk::AI_Module_Slave_Chunk(Object_Module_Data_Chunk* parent,const char* data,size_t) +:Chunk(parent,"AIMODSLA") +{ + MasterModule=0; + MasterModuleName=new char[strlen(data)+1]; + strcpy(MasterModuleName,data); + MasterModuleIndex=0; +} +#else +AI_Module_Slave_Chunk::AI_Module_Slave_Chunk(Chunk_With_Children* parent,const char* data,size_t) +:Chunk(parent,"AIMODSLA") +{ + MasterModule=0; + MasterModuleIndex=*(int*)data; +} +#endif + +AI_Module_Slave_Chunk::AI_Module_Slave_Chunk(Object_Module_Data_Chunk* parent,Object_Chunk* _MasterModule) +:Chunk(parent,"AIMODSLA") +{ + MasterModule=_MasterModule; + MasterModuleIndex=MasterModule->object_data.index_num; +} + +AI_Module_Slave_Chunk::~AI_Module_Slave_Chunk() +{ + #if UseOldChunkLoader + delete [] MasterModuleName; + #endif +} + +size_t AI_Module_Slave_Chunk::size_chunk() +{ + chunk_size=16; + return chunk_size; +} + +void AI_Module_Slave_Chunk::fill_data_block(char* data_start) +{ + strncpy (data_start, identifier, 8); + data_start += 8; + *((int *) data_start) = chunk_size; + data_start += 4; + *((int *) data_start) = MasterModuleIndex; + data_start += 4; + + +} + +void AI_Module_Slave_Chunk::post_input_processing() +{ + #if !UseOldChunkLoader + File_Chunk* fc=(File_Chunk*)GetRootChunk(); + if(!strcmp(fc->identifier,"REBINFF2")) + { + Object_Chunk* oc=fc->get_object_by_index(MasterModuleIndex); + if(oc) + { + Object_Module_Data_Chunk* omdc=(Object_Module_Data_Chunk*)oc->lookup_single_child("MODULEDT"); + if(!omdc) + { + return; + } + + List chlist; + omdc->lookup_child("AIMODMAS",chlist); + if(!chlist.size()) + { + //master module doesn't have a master module chunk + return; + } + AI_Module_Master_Chunk* ammc=(AI_Module_Master_Chunk*)chlist.first_entry(); + ammc->ModuleList.add_entry(get_my_object_chunk()); + MasterModule=oc; + return; + + } + } + #endif +} + +Object_Chunk* AI_Module_Slave_Chunk::get_my_object_chunk() +{ + return (Object_Chunk*)((Object_Module_Data_Chunk*)parent)->parent; +} diff --git a/3dc/win95/wpchunk.hpp b/3dc/win95/wpchunk.hpp new file mode 100644 index 0000000..dbd34c4 --- /dev/null +++ b/3dc/win95/wpchunk.hpp @@ -0,0 +1,107 @@ +#ifndef wpchunk_hpp +#define wpchunk_hpp 1 + +#include "chunk.hpp" +#include "chnktype.hpp" +#include "obchunk.hpp" + +struct WaypointLink +{ + int index; + int flags; +}; + +struct ModuleLink +{ + ~ModuleLink(); + + char* module_name; + int flags; +}; + +#define WaypointFlag_CentreDefinedByUser 0x80000000 +#define WaypointFlag_FirstGroundWaypoint 0x40000000 +struct ChunkWaypoint +{ + ChunkWaypoint(); + ~ChunkWaypoint(); + + int index; + ChunkVectorInt min,max; //relative to centre + ChunkVectorInt centre; //relative to world + + int NumWPLinks; + WaypointLink* WayLinks; + + int NumModLinks; + ModuleLink* ModLinks; + + int flags,spare2; + +}; + +class Module_Waypoint_Chunk : public Chunk +{ + public : + Module_Waypoint_Chunk(Chunk_With_Children*,const char *,size_t); + Module_Waypoint_Chunk(Chunk_With_Children*); + ~Module_Waypoint_Chunk(); + + virtual size_t size_chunk(); + virtual void fill_data_block(char* data_start); + + //Copies waypoint data and deletes the old waypoint_chunk + void TransferWaypointData(Module_Waypoint_Chunk*); + + int NumWaypoints; + ChunkWaypoint* Waypoints; + + ChunkWaypoint* AlienWaypoints; + ChunkWaypoint* GroundWaypoints; + + short NumAlienWaypoints; + short NumGroundWaypoints; + + int spare1; + int spare2; +}; + +class AI_Module_Master_Chunk : public Chunk +{ + public : + AI_Module_Master_Chunk(Chunk_With_Children*,const char*,size_t); + AI_Module_Master_Chunk(Object_Module_Data_Chunk*); + + virtual size_t size_chunk(); + virtual void fill_data_block(char* data_start); + + void AddModule(Object_Chunk*); + Object_Chunk* get_my_object_chunk(); + + List ModuleList; +}; + +class AI_Module_Slave_Chunk : public Chunk +{ + public : + AI_Module_Slave_Chunk(Chunk_With_Children*,const char*,size_t); + AI_Module_Slave_Chunk(Object_Module_Data_Chunk*,Object_Chunk*); + ~AI_Module_Slave_Chunk(); + + virtual size_t size_chunk(); + virtual void fill_data_block(char* data_start); + virtual void post_input_processing(); + + Object_Chunk* get_my_object_chunk(); + + Object_Chunk* MasterModule; + #if UseOldChunkLoader + char* MasterModuleName; + #endif + int MasterModuleIndex; +}; + + +#endif + + diff --git a/3dc/win95/zbuffer.c b/3dc/win95/zbuffer.c new file mode 100644 index 0000000..b33ea85 --- /dev/null +++ b/3dc/win95/zbuffer.c @@ -0,0 +1,91 @@ +/***************************************************************************/ +/* Creation of Z-Buffer */ +/***************************************************************************/ +/* + * D3DAppICreateZBuffer + * Create a Z-Buffer of the appropriate depth and attach it to the back + * buffer. + */ +BOOL +D3DAppICreateZBuffer(int w, int h, int driver) +{ + DDSURFACEDESC ddsd; + DWORD devDepth; + /* + * Release any Z-Buffer that might be around just in case. + */ + RELEASE(d3dappi.lpZBuffer); + + /* + * If this driver does not do z-buffering, don't create a z-buffer + */ + if (!d3dappi.Driver[driver].bDoesZBuffer) + return TRUE; + + memset(&ddsd, 0 ,sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof( ddsd ); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | + DDSD_ZBUFFERBITDEPTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER; + ddsd.dwHeight = h; + ddsd.dwWidth = w; + /* + * If this is a hardware D3D driver, the Z-Buffer MUST end up in video + * memory. Otherwise, it MUST end up in system memory. + */ + if (d3dappi.Driver[driver].bIsHardware) + ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY; + else + ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + /* + * Get the Z buffer bit depth from this driver's D3D device description + */ + devDepth = d3dappi.Driver[driver].Desc.dwDeviceZBufferBitDepth; + if (devDepth & DDBD_32) + ddsd.dwZBufferBitDepth = 32; + else if (devDepth & DDBD_24) + ddsd.dwZBufferBitDepth = 24; + else if (devDepth & DDBD_16) + ddsd.dwZBufferBitDepth = 16; + else if (devDepth & DDBD_8) + ddsd.dwZBufferBitDepth = 8; + else { + D3DAppISetErrorString("Unsupported Z-buffer depth requested by device.\n"); + return FALSE; + } + LastError = d3dappi.lpDD->lpVtbl->CreateSurface(d3dappi.lpDD, &ddsd, + &d3dappi.lpZBuffer, + NULL); + if(LastError != DD_OK) { + D3DAppISetErrorString("CreateSurface for Z-buffer failed.\n%s", + D3DAppErrorToString(LastError)); + goto exit_with_error; + } + /* + * Attach the Z-buffer to the back buffer so D3D will find it + */ + LastError = + d3dappi.lpBackBuffer->lpVtbl->AddAttachedSurface(d3dappi.lpBackBuffer, + d3dappi.lpZBuffer); + if(LastError != DD_OK) { + D3DAppISetErrorString("AddAttachedBuffer failed for Z-Buffer.\n%s", + D3DAppErrorToString(LastError)); + goto exit_with_error; + } + /* + * Find out if it ended up in video memory (FYI). + */ + LastError = D3DAppIGetSurfDesc(&ddsd, d3dappi.lpZBuffer); + if (LastError != DD_OK) { + D3DAppISetErrorString("Failed to get surface description of Z buffer.\n%s", + D3DAppErrorToString(LastError)); + goto exit_with_error; + } + d3dappi.bZBufferInVideo = + (ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) ? TRUE : FALSE; + return TRUE; + +exit_with_error: + RELEASE(d3dappi.lpZBuffer); + return FALSE; +} diff --git a/AvP.dsp b/AvP.dsp new file mode 100644 index 0000000..4601689 --- /dev/null +++ b/AvP.dsp @@ -0,0 +1,2100 @@ +# Microsoft Developer Studio Project File - Name="AvP" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=AvP - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "AvP.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "AvP.mak" CFG="AvP - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "AvP - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "AvP - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE "AvP - Win32 Release For Fox" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "AvP - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /Zp4 /MT /W3 /GX /O2 /I "c:\mssdk\include" /I "3dc" /I "3dc\avp" /I "3dc\avp\support" /I "3dc\avp\win95" /I "3dc\avp\win95\frontend" /I "3dc\avp\win95\gadgets" /I "3dc\include" /I "3dc\win95" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D engine=1 /D "__STDC__" /D "AVP_DEBUG_VERSION" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ddraw.lib dsound.lib dplayx.lib dinput.lib smackw32.lib binkw32.lib winmm.lib /nologo /subsystem:windows /machine:I386 /out:"avpprog.exe" /libpath:"c:\mssdk\lib" /libpath:"3dc" + +!ELSEIF "$(CFG)" == "AvP - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /Zp4 /MTd /W3 /Gm /GX /ZI /Od /I "c:\mssdk\include" /I "3dc" /I "3dc\avp" /I "3dc\avp\support" /I "3dc\avp\win95" /I "3dc\avp\win95\frontend" /I "3dc\avp\win95\gadgets" /I "3dc\include" /I "3dc\win95" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D engine=1 /D "__STDC__" /D "AVP_DEBUG_VERSION" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ddraw.lib dsound.lib dplayx.lib dinput.lib smackw32.lib binkw32.lib winmm.lib /nologo /subsystem:windows /debug /machine:I386 /out:"debug_AvP.exe" /pdbtype:sept /libpath:"c:\mssdk\lib" /libpath:"3dc" + +!ELSEIF "$(CFG)" == "AvP - Win32 Release For Fox" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "AvP___Win32_Release_For_Fox" +# PROP BASE Intermediate_Dir "AvP___Win32_Release_For_Fox" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "AvP___Win32_Release_For_Fox" +# PROP Intermediate_Dir "AvP___Win32_Release_For_Fox" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /Zp4 /MT /W3 /GX /O2 /I "c:\mssdk\include" /I "3dc" /I "3dc\avp" /I "3dc\avp\support" /I "3dc\avp\win95" /I "3dc\avp\win95\frontend" /I "3dc\avp\win95\gadgets" /I "3dc\include" /I "3dc\win95" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D engine=1 /D "__STDC__" /YX /FD /c +# ADD CPP /nologo /Zp4 /MT /W3 /GX /O2 /I "c:\mssdk\include" /I "3dc" /I "3dc\avp" /I "3dc\avp\support" /I "3dc\avp\win95" /I "3dc\avp\win95\frontend" /I "3dc\avp\win95\gadgets" /I "3dc\include" /I "3dc\win95" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D engine=1 /D "__STDC__" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ddraw.lib dsound.lib dplayx.lib dinput.lib smackw32.lib binkw32.lib winmm.lib /nologo /subsystem:windows /machine:I386 /out:"AvP.exe" /libpath:"c:\mssdk\lib" /libpath:"3dc" +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ddraw.lib dsound.lib dplayx.lib dinput.lib smackw32.lib binkw32.lib winmm.lib /nologo /subsystem:windows /machine:I386 /out:"AvP.exe" /libpath:"c:\mssdk\lib" /libpath:"3dc" + +!ENDIF + +# Begin Target + +# Name "AvP - Win32 Release" +# Name "AvP - Win32 Debug" +# Name "AvP - Win32 Release For Fox" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\3dc\Afont.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\ahudgadg.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\AI_Sight.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\alt_tab.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Animchnk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\animobs.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Frontend\AvP_EnvInfo.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Frontend\AvP_Intro.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Frontend\AvP_MenuData.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Frontend\AvP_MenuGfx.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Frontend\AvP_Menus.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Frontend\AvP_MP_Config.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Frontend\AvP_UserProfile.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Avpchunk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\AvpReg.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Avpview.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\awBmpLd.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\awIffLd.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\awPnmLd.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\awTexLd.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_agun.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_ais.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_alien.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_binsw.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_cable.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_corpse.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_deathvol.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_debri.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_dummy.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_fan.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_far.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_fhug.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_gener.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_ldoor.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_lift.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_light.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_lnksw.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_ltfx.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_marin.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_mission.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_near.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_pargen.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_plachier.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_plift.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_pred.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_queen.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_RubberDuck.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_selfdest.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_snds.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_spcl.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_swdor.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_track.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_types.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_videoscreen.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_waypt.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_weap.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_xeno.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\bink.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Bmpnames.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\BonusAbilities.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\cconvars.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\CD_player.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\CDTrackSelection.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Cheat.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\CheatModes.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\chnkload.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Chnktexi.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Chnktype.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\chtcodes.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Chunk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Chunkpal.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\comp_map.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Comp_shp.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\consbind.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\consbtch.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\conscmnd.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\ConsoleLog.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\conssym.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\consvar.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\Coordstr.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\shapes\Cube.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\d3_func.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\d3d_hud.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\d3d_render.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\Daemon.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\davehook.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\db.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Dd_func.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Ddplat.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\deaths.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Debuglog.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\decal.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\DetailLevels.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Di_func.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\DirectPlay.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Dp_func.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\dplayext.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\DummyObjectChunk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\dx_proj.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Dxlog.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Dynamics.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Dynblock.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\endianio.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Enumchnk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Enumsch.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Envchunk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Equipmnt.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\equiputl.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\extents.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\fail.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Ffread.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Ffstdio.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\fragchnk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\frustrum.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\gadget.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Game.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\game_statistics.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\gamecmds.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\gameflow.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\gamevars.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\GammaControl.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gflwplat.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Gsprchnk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\hierchnk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\hierplace.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\HModel.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Hud.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\hudgadg.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\huffman.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\iff.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\iff_ILBM.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\ILBM_ext.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\indexfnt.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\intro.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Inventry.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\io.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\iofocus.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\jsndsup.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\Kshape.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Kzsort.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Langplat.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Language.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Lighting.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\list_tem.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\load_shp.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\los.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Ltchunk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\Map.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Maps.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\Maths.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\md5.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\media.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\mem3dc.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\Mem3dcpp.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\mempool.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\MessageHistory.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Mishchnk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\missions.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\modcmds.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\Module.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\Morph.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\MouseCentreing.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\movement.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\mp_launch.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\Mslhand.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Npcsetup.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Obchunk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\Object.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Objsetup.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\OEChunk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Our_mem.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Paintball.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\particle.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\PathChnk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Pcmenus.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Pfarlocs.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Pheromon.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\plat_shp.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Platsup.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Player.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Pldghost.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Pldnet.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\plspecfn.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Pmove.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\progress_bar.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Projload.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Psnd.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Psndplat.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Psndproj.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Pvisible.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\r2base.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\r2pos666.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\reflist.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\refobj.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\rentrntq.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\rootgadg.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\savegame.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\scream.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Scrshot.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\scstring.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\SecStats.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\sfx.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\shpanim.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Shpchunk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\smacker.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Sndchunk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\sphere.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Sprchunk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Strachnk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Stratdef.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\String.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\strtab.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\strutil.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\system.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\t_ingadg.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\Tables.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\tallfont.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\targeting.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\teletype.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Texio.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\textexp.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\textin.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Toolchnk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\track.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\trepgadg.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\trig666.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Triggers.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Txioctrl.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Usr_io.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\Vdb.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\version.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\VideoModes.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Vision.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Vramtime.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Weapons.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\win_func.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\win_proj.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\winmain.c +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\wpchunk.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\wrapstr.cpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Zsp.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\3dc\win95\advwin32.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\ahudgadg.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\AI_Sight.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\alt_tab.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Animchnk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\animobs.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Frontend\AvP_EnvInfo.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Frontend\AvP_MenuGfx.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Frontend\AvP_Menus.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Frontend\AvP_MP_Config.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Frontend\AvP_UserProfile.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Avpchunk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\avpitems.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\avppages.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\AvpReg.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Avpview.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\aw.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\awTexLd.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\awTexLd.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_agun.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_ais.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_alien.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_binsw.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_cable.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_corpse.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_deathvol.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_debri.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_dummy.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_fan.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_far.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_fhug.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_gener.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_ldoor.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_lift.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_light.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_lnksw.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_ltfx.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_marin.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_mission.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_near.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_paq.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_pargen.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_plachier.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_plift.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_pred.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_queen.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_RubberDuck.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_selfdest.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_snds.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_spcl.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_swdor.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_track.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_types.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_videoscreen.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_waypt.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\bh_weap.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Bh_xeno.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\bink.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\bink_Rad.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Bmp2.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Bmpnames.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\BonusAbilities.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\CD_player.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\CDTrackSelection.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Cheat.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Chnkload.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Chnkload.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Chnktexi.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Chnktype.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Chunk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Chunkpal.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\command.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Comp_shp.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\consbind.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\consbtch.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\conscmnd.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\ConsoleLog.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\conssym.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\consvar.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\Coordstr.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\d3_func.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\d3d_hud.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\d3d_render.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\d3dmacs.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\daemon.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Database.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\datatype.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\davehook.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Db.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\dbdefs.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\dcontext.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Debuglog.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Debuglog.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\decal.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\DetailLevels.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Dp_func.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\dp_Sprh.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\dplayext.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\DummyObjectChunk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Dxlog.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Dynamics.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Dynblock.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Eax.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\endianio.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Enumchnk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Enumsch.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Envchunk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Equates.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Equipmnt.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\equiputl.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\expvar.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\extents.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\fail.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Ffread.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Ffstdio.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\font.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\fragchnk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\frustrum.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\gadget.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\game_statistics.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Gamedef.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\gameflow.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Gameplat.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\GammaControl.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Gsprchnk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Hash_tem.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Heap_tem.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\hierchnk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\hierplace.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\hmodel.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Hud_data.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\HUD_layout.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Hud_map.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Huddefs.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\hudgadg.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Hudgfx.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\huffman.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Ia3d.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\iff.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\iff_ILBM.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\ILBM_ext.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\indexfnt.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Inline.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\intro.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Inventry.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\iofocus.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\jsndsup.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\Kshape.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Kzsort.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\langenum.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Language.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Lighting.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\list_tem.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\load_shp.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\los.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Ltchunk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\ltfx_exp.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Macro.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\md5.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\media.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\mempool.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\menudefs.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\menugfx.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Mishchnk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\missions.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Mmx_math.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\modcmds.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\Mslhand.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Multmenu.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Npcsetup.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Obchunk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\objedit.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Objsetup.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\OEChunk.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Ourasert.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\ourbool.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Paintball.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\particle.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\PathChnk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Pcmenus.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Pentime.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Pfarlocs.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Pheromon.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\plat_shp.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\platform.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Pldghost.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Pldnet.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Pmove.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\progress_bar.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\projfont.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Projload.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\projmenu.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\projtext.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Psnd.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Psndplat.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Psndproj.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Pvisible.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\r2base.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\r2pos666.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Rad.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\rebitems.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\rebmenus.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\reflist.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\refobj.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\rentrntq.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\rootgadg.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\savegame.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\scream.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Scrshot.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\scstring.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\sequnces.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\sfx.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\ShowCmds.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\shpanim.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Shpchunk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Smack.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\smacker.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Smsopt.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Sndchunk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\sphere.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Sprchunk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\statpane.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Strachnk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Stratdef.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\String.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\strtab.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\strutil.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\System.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\t_ingadg.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\tallfont.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\targeting.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\teletype.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\textexp.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\textin.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Toolchnk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\track.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\gadgets\trepgadg.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\trig666.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Triggers.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Txioctrl.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Usr_io.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\version.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\VideoModes.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Vision.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\win95\Vmanpset.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Vramtime.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\Weapons.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\wpchunk.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\avp\support\wrapstr.hpp +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Zmouse.h +# End Source File +# Begin Source File + +SOURCE=.\3dc\win95\Zsp.hpp +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/AvP.dsw b/AvP.dsw new file mode 100644 index 0000000..b862039 --- /dev/null +++ b/AvP.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "AvP"=.\AvP.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/AvP.opt b/AvP.opt new file mode 100644 index 0000000..f034ff6 Binary files /dev/null and b/AvP.opt differ diff --git a/AvP.plg b/AvP.plg new file mode 100644 index 0000000..d2a8b9b --- /dev/null +++ b/AvP.plg @@ -0,0 +1,515 @@ + + +
+

Build Log

+

+--------------------Configuration: AvP - Win32 Release For Fox-------------------- +

+

Command Lines

+Creating temporary file "c:\windows\TEMP\RSPA0F3.TMP" with contents +[ +/nologo /Zp4 /MT /W3 /GX /O2 /I "c:\mssdk\include" /I "3dc" /I "3dc\avp" /I "3dc\avp\support" /I "3dc\avp\win95" /I "3dc\avp\win95\frontend" /I "3dc\avp\win95\gadgets" /I "3dc\include" /I "3dc\win95" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D engine=1 /D "__STDC__" /Fp"AvP___Win32_Release_For_Fox/AvP.pch" /YX /Fo"AvP___Win32_Release_For_Fox/" /Fd"AvP___Win32_Release_For_Fox/" /FD /c +"C:\AvP_vc\3dc\Afont.c" +"C:\AvP_vc\3dc\avp\win95\gadgets\ahudgadg.cpp" +"C:\AvP_vc\3dc\avp\AI_Sight.c" +"C:\AvP_vc\3dc\win95\alt_tab.cpp" +"C:\AvP_vc\3dc\win95\Animchnk.cpp" +"C:\AvP_vc\3dc\win95\animobs.cpp" +"C:\AvP_vc\3dc\avp\win95\Frontend\AvP_EnvInfo.c" +"C:\AvP_vc\3dc\avp\win95\Frontend\AvP_Intro.cpp" +"C:\AvP_vc\3dc\avp\win95\Frontend\AvP_MenuData.c" +"C:\AvP_vc\3dc\avp\win95\Frontend\AvP_MenuGfx.cpp" +"C:\AvP_vc\3dc\avp\win95\Frontend\AvP_Menus.c" +"C:\AvP_vc\3dc\avp\win95\Frontend\AvP_MP_Config.cpp" +"C:\AvP_vc\3dc\avp\win95\Frontend\AvP_UserProfile.cpp" +"C:\AvP_vc\3dc\avp\win95\Avpchunk.cpp" +"C:\AvP_vc\3dc\avp\win95\AvpReg.cpp" +"C:\AvP_vc\3dc\avp\Avpview.c" +"C:\AvP_vc\3dc\win95\awBmpLd.cpp" +"C:\AvP_vc\3dc\win95\awIffLd.cpp" +"C:\AvP_vc\3dc\win95\awPnmLd.cpp" +"C:\AvP_vc\3dc\win95\awTexLd.cpp" +"C:\AvP_vc\3dc\avp\bh_agun.c" +"C:\AvP_vc\3dc\avp\bh_ais.c" +"C:\AvP_vc\3dc\avp\Bh_alien.c" +"C:\AvP_vc\3dc\avp\Bh_binsw.c" +"C:\AvP_vc\3dc\avp\bh_cable.c" +"C:\AvP_vc\3dc\avp\bh_corpse.c" +"C:\AvP_vc\3dc\avp\bh_deathvol.c" +"C:\AvP_vc\3dc\avp\Bh_debri.c" +"C:\AvP_vc\3dc\avp\bh_dummy.c" +"C:\AvP_vc\3dc\avp\bh_fan.c" +"C:\AvP_vc\3dc\avp\bh_far.c" +"C:\AvP_vc\3dc\avp\Bh_fhug.c" +"C:\AvP_vc\3dc\avp\Bh_gener.c" +"C:\AvP_vc\3dc\avp\bh_ldoor.c" +"C:\AvP_vc\3dc\avp\bh_lift.c" +"C:\AvP_vc\3dc\avp\bh_light.c" +"C:\AvP_vc\3dc\avp\Bh_lnksw.c" +"C:\AvP_vc\3dc\avp\bh_ltfx.c" +"C:\AvP_vc\3dc\avp\Bh_marin.c" +"C:\AvP_vc\3dc\avp\bh_mission.c" +"C:\AvP_vc\3dc\avp\Bh_near.c" +"C:\AvP_vc\3dc\avp\bh_pargen.c" +"C:\AvP_vc\3dc\avp\bh_plachier.c" +"C:\AvP_vc\3dc\avp\bh_plift.c" +"C:\AvP_vc\3dc\avp\Bh_pred.c" +"C:\AvP_vc\3dc\avp\bh_queen.c" +"C:\AvP_vc\3dc\avp\bh_RubberDuck.c" +"C:\AvP_vc\3dc\avp\bh_selfdest.c" +"C:\AvP_vc\3dc\avp\bh_snds.c" +"C:\AvP_vc\3dc\avp\bh_spcl.c" +"C:\AvP_vc\3dc\avp\Bh_swdor.c" +"C:\AvP_vc\3dc\avp\bh_track.c" +"C:\AvP_vc\3dc\avp\Bh_types.c" +"C:\AvP_vc\3dc\avp\bh_videoscreen.c" +"C:\AvP_vc\3dc\avp\bh_waypt.c" +"C:\AvP_vc\3dc\avp\bh_weap.c" +"C:\AvP_vc\3dc\avp\Bh_xeno.c" +"C:\AvP_vc\3dc\win95\bink.c" +"C:\AvP_vc\3dc\win95\Bmpnames.cpp" +"C:\AvP_vc\3dc\avp\BonusAbilities.c" +"C:\AvP_vc\3dc\avp\cconvars.cpp" +"C:\AvP_vc\3dc\win95\CD_player.c" +"C:\AvP_vc\3dc\avp\CDTrackSelection.cpp" +"C:\AvP_vc\3dc\avp\win95\Cheat.c" +"C:\AvP_vc\3dc\avp\CheatModes.c" +"C:\AvP_vc\3dc\win95\chnkload.cpp" +"C:\AvP_vc\3dc\win95\Chnktexi.cpp" +"C:\AvP_vc\3dc\win95\Chnktype.cpp" +"C:\AvP_vc\3dc\avp\win95\chtcodes.cpp" +"C:\AvP_vc\3dc\win95\Chunk.cpp" +"C:\AvP_vc\3dc\win95\Chunkpal.cpp" +"C:\AvP_vc\3dc\avp\comp_map.c" +"C:\AvP_vc\3dc\avp\Comp_shp.c" +"C:\AvP_vc\3dc\avp\support\consbind.cpp" +"C:\AvP_vc\3dc\avp\support\consbtch.cpp" +"C:\AvP_vc\3dc\avp\win95\gadgets\conscmnd.cpp" +"C:\AvP_vc\3dc\avp\ConsoleLog.cpp" +"C:\AvP_vc\3dc\avp\win95\gadgets\conssym.cpp" +"C:\AvP_vc\3dc\avp\win95\gadgets\consvar.cpp" +"C:\AvP_vc\3dc\avp\support\Coordstr.cpp" +"C:\AvP_vc\3dc\avp\shapes\Cube.c" +"C:\AvP_vc\3dc\win95\d3_func.cpp" +"C:\AvP_vc\3dc\avp\win95\d3d_hud.cpp" +"C:\AvP_vc\3dc\avp\win95\d3d_render.cpp" +"C:\AvP_vc\3dc\avp\support\Daemon.cpp" +"C:\AvP_vc\3dc\avp\davehook.cpp" +"C:\AvP_vc\3dc\win95\db.c" +"C:\AvP_vc\3dc\win95\Dd_func.cpp" +"C:\AvP_vc\3dc\avp\win95\Ddplat.cpp" +"C:\AvP_vc\3dc\avp\deaths.c" +"C:\AvP_vc\3dc\win95\Debuglog.cpp" +"C:\AvP_vc\3dc\avp\decal.c" +"C:\AvP_vc\3dc\avp\DetailLevels.c" +"C:\AvP_vc\3dc\win95\Di_func.cpp" +"C:\AvP_vc\3dc\avp\win95\DirectPlay.c" +"C:\AvP_vc\3dc\avp\win95\Dp_func.c" +"C:\AvP_vc\3dc\avp\win95\dplayext.c" +"C:\AvP_vc\3dc\win95\DummyObjectChunk.cpp" +"C:\AvP_vc\3dc\avp\win95\dx_proj.cpp" +"C:\AvP_vc\3dc\win95\Dxlog.c" +"C:\AvP_vc\3dc\avp\Dynamics.c" +"C:\AvP_vc\3dc\avp\Dynblock.c" +"C:\AvP_vc\3dc\avp\win95\endianio.c" +"C:\AvP_vc\3dc\win95\Enumchnk.cpp" +"C:\AvP_vc\3dc\win95\Enumsch.cpp" +"C:\AvP_vc\3dc\win95\Envchunk.cpp" +"C:\AvP_vc\3dc\avp\Equipmnt.c" +"C:\AvP_vc\3dc\avp\equiputl.cpp" +"C:\AvP_vc\3dc\avp\extents.c" +"C:\AvP_vc\3dc\win95\fail.c" +"C:\AvP_vc\3dc\avp\win95\Ffread.cpp" +"C:\AvP_vc\3dc\avp\win95\Ffstdio.cpp" +"C:\AvP_vc\3dc\win95\fragchnk.cpp" +"C:\AvP_vc\3dc\frustrum.c" +"C:\AvP_vc\3dc\avp\win95\gadgets\gadget.cpp" +"C:\AvP_vc\3dc\avp\Game.c" +"C:\AvP_vc\3dc\avp\game_statistics.c" +"C:\AvP_vc\3dc\avp\gamecmds.cpp" +"C:\AvP_vc\3dc\avp\gameflow.c" +"C:\AvP_vc\3dc\avp\gamevars.cpp" +"C:\AvP_vc\3dc\avp\win95\GammaControl.cpp" +"C:\AvP_vc\3dc\avp\win95\gflwplat.c" +"C:\AvP_vc\3dc\win95\Gsprchnk.cpp" +"C:\AvP_vc\3dc\win95\hierchnk.cpp" +"C:\AvP_vc\3dc\avp\win95\hierplace.cpp" +"C:\AvP_vc\3dc\avp\HModel.c" +"C:\AvP_vc\3dc\avp\Hud.c" +"C:\AvP_vc\3dc\avp\win95\gadgets\hudgadg.cpp" +"C:\AvP_vc\3dc\win95\huffman.cpp" +"C:\AvP_vc\3dc\win95\iff.cpp" +"C:\AvP_vc\3dc\win95\iff_ILBM.cpp" +"C:\AvP_vc\3dc\win95\ILBM_ext.cpp" +"C:\AvP_vc\3dc\avp\support\indexfnt.cpp" +"C:\AvP_vc\3dc\avp\win95\intro.cpp" +"C:\AvP_vc\3dc\avp\Inventry.c" +"C:\AvP_vc\3dc\win95\io.c" +"C:\AvP_vc\3dc\avp\win95\iofocus.cpp" +"C:\AvP_vc\3dc\avp\win95\jsndsup.cpp" +"C:\AvP_vc\3dc\Kshape.c" +"C:\AvP_vc\3dc\avp\win95\Kzsort.c" +"C:\AvP_vc\3dc\avp\win95\Langplat.c" +"C:\AvP_vc\3dc\avp\Language.c" +"C:\AvP_vc\3dc\avp\Lighting.c" +"C:\AvP_vc\3dc\win95\list_tem.cpp" +"C:\AvP_vc\3dc\avp\load_shp.c" +"C:\AvP_vc\3dc\avp\los.c" +"C:\AvP_vc\3dc\win95\Ltchunk.cpp" +"C:\AvP_vc\3dc\Map.c" +"C:\AvP_vc\3dc\avp\Maps.c" +"C:\AvP_vc\3dc\Maths.c" +"C:\AvP_vc\3dc\win95\md5.c" +"C:\AvP_vc\3dc\win95\media.cpp" +"C:\AvP_vc\3dc\mem3dc.c" +"C:\AvP_vc\3dc\Mem3dcpp.cpp" +"C:\AvP_vc\3dc\avp\mempool.c" +"C:\AvP_vc\3dc\avp\MessageHistory.c" +"C:\AvP_vc\3dc\win95\Mishchnk.cpp" +"C:\AvP_vc\3dc\avp\missions.cpp" +"C:\AvP_vc\3dc\avp\win95\modcmds.cpp" +"C:\AvP_vc\3dc\Module.c" +"C:\AvP_vc\3dc\Morph.c" +"C:\AvP_vc\3dc\avp\win95\MouseCentreing.cpp" +"C:\AvP_vc\3dc\avp\movement.c" +"C:\AvP_vc\3dc\avp\mp_launch.c" +"C:\AvP_vc\3dc\Mslhand.c" +"C:\AvP_vc\3dc\avp\win95\Npcsetup.cpp" +"C:\AvP_vc\3dc\win95\Obchunk.cpp" +"C:\AvP_vc\3dc\Object.c" +"C:\AvP_vc\3dc\avp\win95\Objsetup.cpp" +"C:\AvP_vc\3dc\win95\OEChunk.cpp" +"C:\AvP_vc\3dc\win95\Our_mem.c" +"C:\AvP_vc\3dc\avp\Paintball.c" +"C:\AvP_vc\3dc\avp\particle.c" +"C:\AvP_vc\3dc\avp\win95\PathChnk.cpp" +"C:\AvP_vc\3dc\avp\win95\Pcmenus.cpp" +"C:\AvP_vc\3dc\avp\Pfarlocs.c" +"C:\AvP_vc\3dc\avp\Pheromon.c" +"C:\AvP_vc\3dc\win95\plat_shp.c" +"C:\AvP_vc\3dc\avp\win95\Platsup.c" +"C:\AvP_vc\3dc\avp\Player.c" +"C:\AvP_vc\3dc\avp\win95\Pldghost.c" +"C:\AvP_vc\3dc\avp\win95\Pldnet.c" +"C:\AvP_vc\3dc\win95\plspecfn.c" +"C:\AvP_vc\3dc\avp\Pmove.c" +"C:\AvP_vc\3dc\avp\win95\progress_bar.cpp" +"C:\AvP_vc\3dc\avp\win95\Projload.cpp" +"C:\AvP_vc\3dc\avp\Psnd.c" +"C:\AvP_vc\3dc\avp\win95\Psndplat.c" +"C:\AvP_vc\3dc\avp\Psndproj.c" +"C:\AvP_vc\3dc\avp\Pvisible.c" +"C:\AvP_vc\3dc\avp\support\r2base.cpp" +"C:\AvP_vc\3dc\avp\support\r2pos666.cpp" +"C:\AvP_vc\3dc\avp\support\reflist.cpp" +"C:\AvP_vc\3dc\avp\support\refobj.cpp" +"C:\AvP_vc\3dc\avp\support\rentrntq.cpp" +"C:\AvP_vc\3dc\avp\win95\gadgets\rootgadg.cpp" +"C:\AvP_vc\3dc\avp\savegame.c" +"C:\AvP_vc\3dc\avp\scream.cpp" +"C:\AvP_vc\3dc\avp\win95\Scrshot.cpp" +"C:\AvP_vc\3dc\avp\support\scstring.cpp" +"C:\AvP_vc\3dc\avp\SecStats.c" +"C:\AvP_vc\3dc\avp\sfx.c" +"C:\AvP_vc\3dc\shpanim.c" +"C:\AvP_vc\3dc\win95\Shpchunk.cpp" +"C:\AvP_vc\3dc\win95\smacker.c" +"C:\AvP_vc\3dc\win95\Sndchunk.cpp" +"C:\AvP_vc\3dc\sphere.c" +"C:\AvP_vc\3dc\win95\Sprchunk.cpp" +"C:\AvP_vc\3dc\avp\win95\Strachnk.cpp" +"C:\AvP_vc\3dc\avp\Stratdef.c" +"C:\AvP_vc\3dc\win95\String.cpp" +"C:\AvP_vc\3dc\avp\support\strtab.cpp" +"C:\AvP_vc\3dc\avp\support\strutil.c" +"C:\AvP_vc\3dc\avp\win95\system.c" +"C:\AvP_vc\3dc\avp\win95\gadgets\t_ingadg.cpp" +"C:\AvP_vc\3dc\Tables.c" +"C:\AvP_vc\3dc\avp\support\tallfont.cpp" +"C:\AvP_vc\3dc\avp\targeting.c" +"C:\AvP_vc\3dc\avp\win95\gadgets\teletype.cpp" +"C:\AvP_vc\3dc\win95\Texio.c" +"C:\AvP_vc\3dc\avp\win95\gadgets\textexp.cpp" +"C:\AvP_vc\3dc\avp\win95\gadgets\textin.cpp" +"C:\AvP_vc\3dc\win95\Toolchnk.cpp" +"C:\AvP_vc\3dc\avp\track.c" +"C:\AvP_vc\3dc\avp\win95\gadgets\trepgadg.cpp" +"C:\AvP_vc\3dc\avp\support\trig666.cpp" +"C:\AvP_vc\3dc\avp\Triggers.c" +"C:\AvP_vc\3dc\win95\Txioctrl.cpp" +"C:\AvP_vc\3dc\avp\win95\Usr_io.c" +"C:\AvP_vc\3dc\Vdb.c" +"C:\AvP_vc\3dc\version.c" +"C:\AvP_vc\3dc\win95\VideoModes.cpp" +"C:\AvP_vc\3dc\avp\win95\Vision.c" +"C:\AvP_vc\3dc\win95\Vramtime.c" +"C:\AvP_vc\3dc\avp\Weapons.c" +"C:\AvP_vc\3dc\win95\win_func.cpp" +"C:\AvP_vc\3dc\avp\win95\win_proj.cpp" +"C:\AvP_vc\3dc\avp\win95\winmain.c" +"C:\AvP_vc\3dc\win95\wpchunk.cpp" +"C:\AvP_vc\3dc\avp\support\wrapstr.cpp" +"C:\AvP_vc\3dc\win95\Zsp.cpp" +] +Creating command line "cl.exe @c:\windows\TEMP\RSPA0F3.TMP" +Creating temporary file "c:\windows\TEMP\RSPA0F4.TMP" with contents +[ +kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ddraw.lib dsound.lib dplayx.lib dinput.lib smackw32.lib binkw32.lib winmm.lib /nologo /subsystem:windows /incremental:no /pdb:"AvP___Win32_Release_For_Fox/AvP.pdb" /machine:I386 /out:"AvP.exe" /libpath:"c:\mssdk\lib" /libpath:"3dc" +.\AvP___Win32_Release_For_Fox\Afont.obj +.\AvP___Win32_Release_For_Fox\ahudgadg.obj +.\AvP___Win32_Release_For_Fox\AI_Sight.obj +.\AvP___Win32_Release_For_Fox\alt_tab.obj +.\AvP___Win32_Release_For_Fox\Animchnk.obj +.\AvP___Win32_Release_For_Fox\animobs.obj +.\AvP___Win32_Release_For_Fox\AvP_EnvInfo.obj +.\AvP___Win32_Release_For_Fox\AvP_Intro.obj +.\AvP___Win32_Release_For_Fox\AvP_MenuData.obj +.\AvP___Win32_Release_For_Fox\AvP_MenuGfx.obj +.\AvP___Win32_Release_For_Fox\AvP_Menus.obj +.\AvP___Win32_Release_For_Fox\AvP_MP_Config.obj +.\AvP___Win32_Release_For_Fox\AvP_UserProfile.obj +.\AvP___Win32_Release_For_Fox\Avpchunk.obj +.\AvP___Win32_Release_For_Fox\AvpReg.obj +.\AvP___Win32_Release_For_Fox\Avpview.obj +.\AvP___Win32_Release_For_Fox\awBmpLd.obj +.\AvP___Win32_Release_For_Fox\awIffLd.obj +.\AvP___Win32_Release_For_Fox\awPnmLd.obj +.\AvP___Win32_Release_For_Fox\awTexLd.obj +.\AvP___Win32_Release_For_Fox\bh_agun.obj +.\AvP___Win32_Release_For_Fox\bh_ais.obj +.\AvP___Win32_Release_For_Fox\Bh_alien.obj +.\AvP___Win32_Release_For_Fox\Bh_binsw.obj +.\AvP___Win32_Release_For_Fox\bh_cable.obj +.\AvP___Win32_Release_For_Fox\bh_corpse.obj +.\AvP___Win32_Release_For_Fox\bh_deathvol.obj +.\AvP___Win32_Release_For_Fox\Bh_debri.obj +.\AvP___Win32_Release_For_Fox\bh_dummy.obj +.\AvP___Win32_Release_For_Fox\bh_fan.obj +.\AvP___Win32_Release_For_Fox\bh_far.obj +.\AvP___Win32_Release_For_Fox\Bh_fhug.obj +.\AvP___Win32_Release_For_Fox\Bh_gener.obj +.\AvP___Win32_Release_For_Fox\bh_ldoor.obj +.\AvP___Win32_Release_For_Fox\bh_lift.obj +.\AvP___Win32_Release_For_Fox\bh_light.obj +.\AvP___Win32_Release_For_Fox\Bh_lnksw.obj +.\AvP___Win32_Release_For_Fox\bh_ltfx.obj +.\AvP___Win32_Release_For_Fox\Bh_marin.obj +.\AvP___Win32_Release_For_Fox\bh_mission.obj +.\AvP___Win32_Release_For_Fox\Bh_near.obj +.\AvP___Win32_Release_For_Fox\bh_pargen.obj +.\AvP___Win32_Release_For_Fox\bh_plachier.obj +.\AvP___Win32_Release_For_Fox\bh_plift.obj +.\AvP___Win32_Release_For_Fox\Bh_pred.obj +.\AvP___Win32_Release_For_Fox\bh_queen.obj +.\AvP___Win32_Release_For_Fox\bh_RubberDuck.obj +.\AvP___Win32_Release_For_Fox\bh_selfdest.obj +.\AvP___Win32_Release_For_Fox\bh_snds.obj +.\AvP___Win32_Release_For_Fox\bh_spcl.obj +.\AvP___Win32_Release_For_Fox\Bh_swdor.obj +.\AvP___Win32_Release_For_Fox\bh_track.obj +.\AvP___Win32_Release_For_Fox\Bh_types.obj +.\AvP___Win32_Release_For_Fox\bh_videoscreen.obj +.\AvP___Win32_Release_For_Fox\bh_waypt.obj +.\AvP___Win32_Release_For_Fox\bh_weap.obj +.\AvP___Win32_Release_For_Fox\Bh_xeno.obj +.\AvP___Win32_Release_For_Fox\bink.obj +.\AvP___Win32_Release_For_Fox\Bmpnames.obj +.\AvP___Win32_Release_For_Fox\BonusAbilities.obj +.\AvP___Win32_Release_For_Fox\cconvars.obj +.\AvP___Win32_Release_For_Fox\CD_player.obj +.\AvP___Win32_Release_For_Fox\CDTrackSelection.obj +.\AvP___Win32_Release_For_Fox\Cheat.obj +.\AvP___Win32_Release_For_Fox\CheatModes.obj +.\AvP___Win32_Release_For_Fox\chnkload.obj +.\AvP___Win32_Release_For_Fox\Chnktexi.obj +.\AvP___Win32_Release_For_Fox\Chnktype.obj +.\AvP___Win32_Release_For_Fox\chtcodes.obj +.\AvP___Win32_Release_For_Fox\Chunk.obj +.\AvP___Win32_Release_For_Fox\Chunkpal.obj +.\AvP___Win32_Release_For_Fox\comp_map.obj +.\AvP___Win32_Release_For_Fox\Comp_shp.obj +.\AvP___Win32_Release_For_Fox\consbind.obj +.\AvP___Win32_Release_For_Fox\consbtch.obj +.\AvP___Win32_Release_For_Fox\conscmnd.obj +.\AvP___Win32_Release_For_Fox\ConsoleLog.obj +.\AvP___Win32_Release_For_Fox\conssym.obj +.\AvP___Win32_Release_For_Fox\consvar.obj +.\AvP___Win32_Release_For_Fox\Coordstr.obj +.\AvP___Win32_Release_For_Fox\Cube.obj +.\AvP___Win32_Release_For_Fox\d3_func.obj +.\AvP___Win32_Release_For_Fox\d3d_hud.obj +.\AvP___Win32_Release_For_Fox\d3d_render.obj +.\AvP___Win32_Release_For_Fox\Daemon.obj +.\AvP___Win32_Release_For_Fox\davehook.obj +.\AvP___Win32_Release_For_Fox\db.obj +.\AvP___Win32_Release_For_Fox\Dd_func.obj +.\AvP___Win32_Release_For_Fox\Ddplat.obj +.\AvP___Win32_Release_For_Fox\deaths.obj +.\AvP___Win32_Release_For_Fox\Debuglog.obj +.\AvP___Win32_Release_For_Fox\decal.obj +.\AvP___Win32_Release_For_Fox\DetailLevels.obj +.\AvP___Win32_Release_For_Fox\Di_func.obj +.\AvP___Win32_Release_For_Fox\DirectPlay.obj +.\AvP___Win32_Release_For_Fox\Dp_func.obj +.\AvP___Win32_Release_For_Fox\dplayext.obj +.\AvP___Win32_Release_For_Fox\DummyObjectChunk.obj +.\AvP___Win32_Release_For_Fox\dx_proj.obj +.\AvP___Win32_Release_For_Fox\Dxlog.obj +.\AvP___Win32_Release_For_Fox\Dynamics.obj +.\AvP___Win32_Release_For_Fox\Dynblock.obj +.\AvP___Win32_Release_For_Fox\endianio.obj +.\AvP___Win32_Release_For_Fox\Enumchnk.obj +.\AvP___Win32_Release_For_Fox\Enumsch.obj +.\AvP___Win32_Release_For_Fox\Envchunk.obj +.\AvP___Win32_Release_For_Fox\Equipmnt.obj +.\AvP___Win32_Release_For_Fox\equiputl.obj +.\AvP___Win32_Release_For_Fox\extents.obj +.\AvP___Win32_Release_For_Fox\fail.obj +.\AvP___Win32_Release_For_Fox\Ffread.obj +.\AvP___Win32_Release_For_Fox\Ffstdio.obj +.\AvP___Win32_Release_For_Fox\fragchnk.obj +.\AvP___Win32_Release_For_Fox\frustrum.obj +.\AvP___Win32_Release_For_Fox\gadget.obj +.\AvP___Win32_Release_For_Fox\Game.obj +.\AvP___Win32_Release_For_Fox\game_statistics.obj +.\AvP___Win32_Release_For_Fox\gamecmds.obj +.\AvP___Win32_Release_For_Fox\gameflow.obj +.\AvP___Win32_Release_For_Fox\gamevars.obj +.\AvP___Win32_Release_For_Fox\GammaControl.obj +.\AvP___Win32_Release_For_Fox\gflwplat.obj +.\AvP___Win32_Release_For_Fox\Gsprchnk.obj +.\AvP___Win32_Release_For_Fox\hierchnk.obj +.\AvP___Win32_Release_For_Fox\hierplace.obj +.\AvP___Win32_Release_For_Fox\HModel.obj +.\AvP___Win32_Release_For_Fox\Hud.obj +.\AvP___Win32_Release_For_Fox\hudgadg.obj +.\AvP___Win32_Release_For_Fox\huffman.obj +.\AvP___Win32_Release_For_Fox\iff.obj +.\AvP___Win32_Release_For_Fox\iff_ILBM.obj +.\AvP___Win32_Release_For_Fox\ILBM_ext.obj +.\AvP___Win32_Release_For_Fox\indexfnt.obj +.\AvP___Win32_Release_For_Fox\intro.obj +.\AvP___Win32_Release_For_Fox\Inventry.obj +.\AvP___Win32_Release_For_Fox\io.obj +.\AvP___Win32_Release_For_Fox\iofocus.obj +.\AvP___Win32_Release_For_Fox\jsndsup.obj +.\AvP___Win32_Release_For_Fox\Kshape.obj +.\AvP___Win32_Release_For_Fox\Kzsort.obj +.\AvP___Win32_Release_For_Fox\Langplat.obj +.\AvP___Win32_Release_For_Fox\Language.obj +.\AvP___Win32_Release_For_Fox\Lighting.obj +.\AvP___Win32_Release_For_Fox\list_tem.obj +.\AvP___Win32_Release_For_Fox\load_shp.obj +.\AvP___Win32_Release_For_Fox\los.obj +.\AvP___Win32_Release_For_Fox\Ltchunk.obj +.\AvP___Win32_Release_For_Fox\Map.obj +.\AvP___Win32_Release_For_Fox\Maps.obj +.\AvP___Win32_Release_For_Fox\Maths.obj +.\AvP___Win32_Release_For_Fox\md5.obj +.\AvP___Win32_Release_For_Fox\media.obj +.\AvP___Win32_Release_For_Fox\mem3dc.obj +.\AvP___Win32_Release_For_Fox\Mem3dcpp.obj +.\AvP___Win32_Release_For_Fox\mempool.obj +.\AvP___Win32_Release_For_Fox\MessageHistory.obj +.\AvP___Win32_Release_For_Fox\Mishchnk.obj +.\AvP___Win32_Release_For_Fox\missions.obj +.\AvP___Win32_Release_For_Fox\modcmds.obj +.\AvP___Win32_Release_For_Fox\Module.obj +.\AvP___Win32_Release_For_Fox\Morph.obj +.\AvP___Win32_Release_For_Fox\MouseCentreing.obj +.\AvP___Win32_Release_For_Fox\movement.obj +.\AvP___Win32_Release_For_Fox\mp_launch.obj +.\AvP___Win32_Release_For_Fox\Mslhand.obj +.\AvP___Win32_Release_For_Fox\Npcsetup.obj +.\AvP___Win32_Release_For_Fox\Obchunk.obj +.\AvP___Win32_Release_For_Fox\Object.obj +.\AvP___Win32_Release_For_Fox\Objsetup.obj +.\AvP___Win32_Release_For_Fox\OEChunk.obj +.\AvP___Win32_Release_For_Fox\Our_mem.obj +.\AvP___Win32_Release_For_Fox\Paintball.obj +.\AvP___Win32_Release_For_Fox\particle.obj +.\AvP___Win32_Release_For_Fox\PathChnk.obj +.\AvP___Win32_Release_For_Fox\Pcmenus.obj +.\AvP___Win32_Release_For_Fox\Pfarlocs.obj +.\AvP___Win32_Release_For_Fox\Pheromon.obj +.\AvP___Win32_Release_For_Fox\plat_shp.obj +.\AvP___Win32_Release_For_Fox\Platsup.obj +.\AvP___Win32_Release_For_Fox\Player.obj +.\AvP___Win32_Release_For_Fox\Pldghost.obj +.\AvP___Win32_Release_For_Fox\Pldnet.obj +.\AvP___Win32_Release_For_Fox\plspecfn.obj +.\AvP___Win32_Release_For_Fox\Pmove.obj +.\AvP___Win32_Release_For_Fox\progress_bar.obj +.\AvP___Win32_Release_For_Fox\Projload.obj +.\AvP___Win32_Release_For_Fox\Psnd.obj +.\AvP___Win32_Release_For_Fox\Psndplat.obj +.\AvP___Win32_Release_For_Fox\Psndproj.obj +.\AvP___Win32_Release_For_Fox\Pvisible.obj +.\AvP___Win32_Release_For_Fox\r2base.obj +.\AvP___Win32_Release_For_Fox\r2pos666.obj +.\AvP___Win32_Release_For_Fox\reflist.obj +.\AvP___Win32_Release_For_Fox\refobj.obj +.\AvP___Win32_Release_For_Fox\rentrntq.obj +.\AvP___Win32_Release_For_Fox\rootgadg.obj +.\AvP___Win32_Release_For_Fox\savegame.obj +.\AvP___Win32_Release_For_Fox\scream.obj +.\AvP___Win32_Release_For_Fox\Scrshot.obj +.\AvP___Win32_Release_For_Fox\scstring.obj +.\AvP___Win32_Release_For_Fox\SecStats.obj +.\AvP___Win32_Release_For_Fox\sfx.obj +.\AvP___Win32_Release_For_Fox\shpanim.obj +.\AvP___Win32_Release_For_Fox\Shpchunk.obj +.\AvP___Win32_Release_For_Fox\smacker.obj +.\AvP___Win32_Release_For_Fox\Sndchunk.obj +.\AvP___Win32_Release_For_Fox\sphere.obj +.\AvP___Win32_Release_For_Fox\Sprchunk.obj +.\AvP___Win32_Release_For_Fox\Strachnk.obj +.\AvP___Win32_Release_For_Fox\Stratdef.obj +.\AvP___Win32_Release_For_Fox\String.obj +.\AvP___Win32_Release_For_Fox\strtab.obj +.\AvP___Win32_Release_For_Fox\strutil.obj +.\AvP___Win32_Release_For_Fox\system.obj +.\AvP___Win32_Release_For_Fox\t_ingadg.obj +.\AvP___Win32_Release_For_Fox\Tables.obj +.\AvP___Win32_Release_For_Fox\tallfont.obj +.\AvP___Win32_Release_For_Fox\targeting.obj +.\AvP___Win32_Release_For_Fox\teletype.obj +.\AvP___Win32_Release_For_Fox\Texio.obj +.\AvP___Win32_Release_For_Fox\textexp.obj +.\AvP___Win32_Release_For_Fox\textin.obj +.\AvP___Win32_Release_For_Fox\Toolchnk.obj +.\AvP___Win32_Release_For_Fox\track.obj +.\AvP___Win32_Release_For_Fox\trepgadg.obj +.\AvP___Win32_Release_For_Fox\trig666.obj +.\AvP___Win32_Release_For_Fox\Triggers.obj +.\AvP___Win32_Release_For_Fox\Txioctrl.obj +.\AvP___Win32_Release_For_Fox\Usr_io.obj +.\AvP___Win32_Release_For_Fox\Vdb.obj +.\AvP___Win32_Release_For_Fox\version.obj +.\AvP___Win32_Release_For_Fox\VideoModes.obj +.\AvP___Win32_Release_For_Fox\Vision.obj +.\AvP___Win32_Release_For_Fox\Vramtime.obj +.\AvP___Win32_Release_For_Fox\Weapons.obj +.\AvP___Win32_Release_For_Fox\win_func.obj +.\AvP___Win32_Release_For_Fox\win_proj.obj +.\AvP___Win32_Release_For_Fox\winmain.obj +.\AvP___Win32_Release_For_Fox\wpchunk.obj +.\AvP___Win32_Release_For_Fox\wrapstr.obj +.\AvP___Win32_Release_For_Fox\Zsp.obj +] +Creating command line "link.exe @c:\windows\TEMP\RSPA0F4.TMP" +

Output Window

+Compiling... +Afont.c +ahudgadg.cpp +AI_Sight.c +C:\AvP_vc\3dc\avp\AI_Sight.c(177) : warning C4013: 'AGunSight_FrustrumReject' undefined; assuming extern returning int +alt_tab.cpp +Animchnk.cpp +animobs.cpp +AvP_EnvInfo.c +AvP_Intro.cpp + +
+ + diff --git a/License.txt b/License.txt new file mode 100644 index 0000000..aa3e1b2 --- /dev/null +++ b/License.txt @@ -0,0 +1 @@ +The source code to Aliens Vs Predator is copyright (c) 1999-2000 Rebellion and is provided as is with no warranty for its suitability for use. You may not use this source code in full or in part for commercial purposes. Any use must include a clearly visible credit to Rebellion as the creators and owners, and reiteration of this license. \ No newline at end of file diff --git a/avp395.mk b/avp395.mk new file mode 100644 index 0000000..f1ea96f --- /dev/null +++ b/avp395.mk @@ -0,0 +1,4 @@ +project : c:\avp_copy\avpprog.exe c:\avp_copy\release\avp.exe .SYMBOLIC + +!include c:\avp_copy\avpprog.mk1 +!include c:\avp_copy\release\avp.mk1 diff --git a/avp395.wpj b/avp395.wpj new file mode 100644 index 0000000..62d88d1 --- /dev/null +++ b/avp395.wpj @@ -0,0 +1,63 @@ +40 +projectIdent +0 +VpeMain +1 +WRect +0 +0 +10240 +10240 +2 +MProject +3 +MCommand +0 +4 +MCommand +0 +2 +5 +WFileName +11 +avpprog.tgt +6 +WFileName +19 +wat_release\avp.tgt +7 +WVList +2 +8 +VComponent +9 +WRect +160 +0 +4240 +4800 +0 +0 +10 +WFileName +11 +avpprog.tgt +203 +205 +11 +VComponent +12 +WRect +4560 +0 +4160 +4800 +0 +0 +13 +WFileName +19 +wat_release\avp.tgt +0 +4 +8 diff --git a/avpprog.lk1 b/avpprog.lk1 new file mode 100644 index 0000000..4d9e3f4 --- /dev/null +++ b/avpprog.lk1 @@ -0,0 +1,2 @@ +FIL mmx_math.obj,afont.obj,ai_sight.obj,avpview.obj,bh_agun.obj,bh_ais.obj,bh_alien.obj,bh_binsw.obj,bh_cable.obj,bh_corpse.obj,bh_deathvol.obj,bh_debri.obj,bh_dummy.obj,bh_fan.obj,bh_far.obj,bh_fhug.obj,bh_gener.obj,bh_ldoor.obj,bh_lift.obj,bh_light.obj,bh_lnksw.obj,bh_ltfx.obj,bh_marin.obj,bh_mission.obj,bh_near.obj,bh_pargen.obj,bh_plachier.obj,bh_plift.obj,bh_pred.obj,bh_queen.obj,bh_rubberduck.obj,bh_selfdest.obj,bh_snds.obj,bh_spcl.obj,bh_swdor.obj,bh_track.obj,bh_types.obj,bh_videoscreen.obj,bh_waypt.obj,bh_weap.obj,bh_xeno.obj,bonusabilities.obj,cheatmodes.obj,comp_map.obj,comp_shp.obj,deaths.obj,decal.obj,detaillevels.obj,dynamics.obj,dynblock.obj,equipmnt.obj,extents.obj,game.obj,game_statistics.obj,gameflow.obj,hmodel.obj,hud.obj,inventry.obj,language.obj,lighting.obj,los.obj,mempool.obj,messagehistory.obj,movement.obj,mp_launch.obj,paintball.obj,particle.obj,pfarlocs.obj,pheromon.obj,player.obj,pmove.obj,psnd.obj,psndproj.obj,pvisible.obj,savegame.obj,secstats.obj,sfx.obj,cube.obj,stratdef.obj,strutil.obj,targeting.obj,track.obj,triggers.obj,weapons.obj,cheat.obj,directplay.obj,dp_func.obj,dplayext.obj,endianio.obj,avp_envinfo.obj,avp_menudata.obj,avp_menus.obj,gflwplat.obj,kzsort.obj,langplat.obj,platsup.obj,pldghost.obj,pldnet.obj,psndplat.obj,system.obj,usr_io.obj,vision.obj,winmain.obj,frustrum.obj,kshape.obj,map.obj,maths.obj,mem3dc.obj,module.obj,morph.obj,mslhand.obj,object.obj,shpanim.obj,sphere.obj,tables.obj,vdb.obj,version.obj,bink.obj,cd_player.obj,db.obj,dxlog.obj,fail.obj,io.obj,md5.obj,our_mem.obj,plat_shp.obj,plspecfn.obj,smacker.obj,texio.obj,vramtime.obj,cconvars.obj,cdtrackselection.obj,consolelog.obj,davehook.obj,equiputl.obj,gamecmds.obj,gamevars.obj,missions.obj,scream.obj,consbind.obj,consbtch.obj,coordstr.obj,daemon.obj,indexfnt.obj,r2base.obj,r2pos666.obj,reflist.obj,refobj.obj,rentrntq.obj,scstring.obj,strtab.obj,tallfont.obj,trig666.obj,wrapstr.obj,avpchunk.obj,avpreg.obj,chtcodes.obj,d3d_hud.obj,d3d_render.obj,ddplat.obj,dx_proj.obj,ffread.obj,ffstdio.obj,avp_intro.obj,avp_menugfx.obj,avp_mp_config.obj,avp_userprofile.obj,ahudgadg.obj,conscmnd.obj,conssym.obj,consvar.obj,gadget.obj,hudgadg.obj,rootgadg.obj,t_ingadg.obj,teletype.obj,textexp.obj,textin.obj,trepgadg.obj,gammacontrol.obj,hierplace.obj,intro.obj,iofocus.obj,jsndsup.obj,modcmds.obj,mousecentreing.obj,npcsetup.obj,objsetup.obj,pathchnk.obj,pcmenus.obj,progress_bar.obj,projload.obj,scrshot.obj,strachnk.obj,win_proj.obj,mem3dcpp.obj,alt_tab.obj,animchnk.obj,animobs.obj,awbmpld.obj,awiffld.obj,awpnmld.obj,awtexld.obj,bmpnames.obj,bonechunk.obj,chnkload.obj,chnktexi.obj,chnktype.obj,chunk.obj,chunkpal.obj,d3_func.obj,dd_func.obj,debuglog.obj,di_func.obj,envchunk.obj,fragchnk.obj,gsprchnk.obj,hierchnk.obj,huffman.obj,iff.obj,iff_ilbm.obj,list_tem.obj,ltchunk.obj,media.obj,mishchnk.obj,obchunk.obj,shpchunk.obj,sndchunk.obj,sprchunk.obj,txioctrl.obj,videomodes.obj,win_func.obj,wpchunk.obj + diff --git a/avpprog.mk1 b/avpprog.mk1 new file mode 100644 index 0000000..77a507a --- /dev/null +++ b/avpprog.mk1 @@ -0,0 +1,2278 @@ +!define BLANK "" +c:\avp_copy\mmx_math.obj : c:\avp_copy\3dc\win95\mmx_math.asm .AUTODEPEND + @c: + cd c:\avp_copy + *wasm 3dc\win95\mmx_math.asm -i=C:\WATCOM\h;C:\WATCOM\h\nt -mf -5r -w4 -e25& + -zq + +c:\avp_copy\afont.obj : c:\avp_copy\3dc\afont.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\afont.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\avp;& +3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;3d& +c\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dAVP& +_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20 -& +d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\ai_sight.obj : c:\avp_copy\3dc\avp\ai_sight.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\ai_sight.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\avpview.obj : c:\avp_copy\3dc\avp\avpview.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\avpview.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_agun.obj : c:\avp_copy\3dc\avp\bh_agun.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_agun.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_ais.obj : c:\avp_copy\3dc\avp\bh_ais.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_ais.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc& +\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadge& +ts;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 & +-dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -o& +e20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_alien.obj : c:\avp_copy\3dc\avp\bh_alien.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_alien.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_binsw.obj : c:\avp_copy\3dc\avp\bh_binsw.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_binsw.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_cable.obj : c:\avp_copy\3dc\avp\bh_cable.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_cable.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_corpse.obj : c:\avp_copy\3dc\avp\bh_corpse.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_corpse.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;& +3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\ga& +dgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine& +=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or& + -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_deathvol.obj : c:\avp_copy\3dc\avp\bh_deathvol.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_deathvol.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -& +or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_debri.obj : c:\avp_copy\3dc\avp\bh_debri.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_debri.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_dummy.obj : c:\avp_copy\3dc\avp\bh_dummy.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_dummy.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_fan.obj : c:\avp_copy\3dc\avp\bh_fan.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_fan.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc& +\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadge& +ts;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 & +-dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -o& +e20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_far.obj : c:\avp_copy\3dc\avp\bh_far.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_far.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc& +\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadge& +ts;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 & +-dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -o& +e20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_fhug.obj : c:\avp_copy\3dc\avp\bh_fhug.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_fhug.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_gener.obj : c:\avp_copy\3dc\avp\bh_gener.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_gener.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_ldoor.obj : c:\avp_copy\3dc\avp\bh_ldoor.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_ldoor.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_lift.obj : c:\avp_copy\3dc\avp\bh_lift.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_lift.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_light.obj : c:\avp_copy\3dc\avp\bh_light.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_light.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_lnksw.obj : c:\avp_copy\3dc\avp\bh_lnksw.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_lnksw.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_ltfx.obj : c:\avp_copy\3dc\avp\bh_ltfx.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_ltfx.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_marin.obj : c:\avp_copy\3dc\avp\bh_marin.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_marin.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_mission.obj : c:\avp_copy\3dc\avp\bh_mission.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_mission.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h& +;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\g& +adgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengin& +e=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -o& +r -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_near.obj : c:\avp_copy\3dc\avp\bh_near.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_near.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_pargen.obj : c:\avp_copy\3dc\avp\bh_pargen.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_pargen.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;& +3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\ga& +dgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine& +=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or& + -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_plachier.obj : c:\avp_copy\3dc\avp\bh_plachier.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_plachier.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -& +or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_plift.obj : c:\avp_copy\3dc\avp\bh_plift.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_plift.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_pred.obj : c:\avp_copy\3dc\avp\bh_pred.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_pred.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_queen.obj : c:\avp_copy\3dc\avp\bh_queen.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_queen.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_rubberduck.obj : c:\avp_copy\3dc\avp\bh_rubberduck.c .AUTODEP& +END + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_rubberduck.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watco& +m\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win9& +5\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -den& +gine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa& + -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_selfdest.obj : c:\avp_copy\3dc\avp\bh_selfdest.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_selfdest.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -& +or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_snds.obj : c:\avp_copy\3dc\avp\bh_snds.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_snds.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_spcl.obj : c:\avp_copy\3dc\avp\bh_spcl.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_spcl.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_swdor.obj : c:\avp_copy\3dc\avp\bh_swdor.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_swdor.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_track.obj : c:\avp_copy\3dc\avp\bh_track.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_track.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_types.obj : c:\avp_copy\3dc\avp\bh_types.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_types.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_videoscreen.obj : c:\avp_copy\3dc\avp\bh_videoscreen.c .AUTOD& +EPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_videoscreen.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watc& +om\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win& +95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -de& +ngine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -o& +a -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_waypt.obj : c:\avp_copy\3dc\avp\bh_waypt.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_waypt.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_weap.obj : c:\avp_copy\3dc\avp\bh_weap.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_weap.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bh_xeno.obj : c:\avp_copy\3dc\avp\bh_xeno.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bh_xeno.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bonusabilities.obj : c:\avp_copy\3dc\avp\bonusabilities.c .AUTOD& +EPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\bonusabilities.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watc& +om\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win& +95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -de& +ngine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -o& +a -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\cheatmodes.obj : c:\avp_copy\3dc\avp\cheatmodes.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\cheatmodes.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h& +;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\g& +adgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengin& +e=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -o& +r -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\comp_map.obj : c:\avp_copy\3dc\avp\comp_map.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\comp_map.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\comp_shp.obj : c:\avp_copy\3dc\avp\comp_shp.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\comp_shp.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\deaths.obj : c:\avp_copy\3dc\avp\deaths.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\deaths.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc& +\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadge& +ts;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 & +-dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -o& +e20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\decal.obj : c:\avp_copy\3dc\avp\decal.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\decal.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\& +avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadget& +s;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -& +dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe& +20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\detaillevels.obj : c:\avp_copy\3dc\avp\detaillevels.c .AUTODEPEN& +D + @c: + cd c:\avp_copy + *wcc386 3dc\avp\detaillevels.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa & +-or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\dynamics.obj : c:\avp_copy\3dc\avp\dynamics.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\dynamics.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\dynblock.obj : c:\avp_copy\3dc\avp\dynblock.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\dynblock.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\equipmnt.obj : c:\avp_copy\3dc\avp\equipmnt.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\equipmnt.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\extents.obj : c:\avp_copy\3dc\avp\extents.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\extents.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\game.obj : c:\avp_copy\3dc\avp\game.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\game.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\a& +vp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets& +;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -d& +AVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe2& +0 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\game_statistics.obj : c:\avp_copy\3dc\avp\game_statistics.c .AUT& +ODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\game_statistics.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\wat& +com\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\wi& +n95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -d& +engine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -& +oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\gameflow.obj : c:\avp_copy\3dc\avp\gameflow.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\gameflow.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\hmodel.obj : c:\avp_copy\3dc\avp\hmodel.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\hmodel.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc& +\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadge& +ts;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 & +-dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -o& +e20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\hud.obj : c:\avp_copy\3dc\avp\hud.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\hud.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\av& +p;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;& +3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dA& +VP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20& + -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\inventry.obj : c:\avp_copy\3dc\avp\inventry.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\inventry.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\language.obj : c:\avp_copy\3dc\avp\language.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\language.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\lighting.obj : c:\avp_copy\3dc\avp\lighting.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\lighting.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\los.obj : c:\avp_copy\3dc\avp\los.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\los.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\av& +p;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;& +3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dA& +VP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20& + -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\mempool.obj : c:\avp_copy\3dc\avp\mempool.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\mempool.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\messagehistory.obj : c:\avp_copy\3dc\avp\messagehistory.c .AUTOD& +EPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\messagehistory.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watc& +om\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win& +95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -de& +ngine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -o& +a -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\movement.obj : c:\avp_copy\3dc\avp\movement.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\movement.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\mp_launch.obj : c:\avp_copy\3dc\avp\mp_launch.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\mp_launch.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;& +3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\ga& +dgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine& +=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or& + -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\paintball.obj : c:\avp_copy\3dc\avp\paintball.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\paintball.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;& +3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\ga& +dgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine& +=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or& + -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\particle.obj : c:\avp_copy\3dc\avp\particle.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\particle.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\pfarlocs.obj : c:\avp_copy\3dc\avp\pfarlocs.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\pfarlocs.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\pheromon.obj : c:\avp_copy\3dc\avp\pheromon.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\pheromon.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\player.obj : c:\avp_copy\3dc\avp\player.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\player.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc& +\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadge& +ts;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 & +-dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -o& +e20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\pmove.obj : c:\avp_copy\3dc\avp\pmove.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\pmove.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\& +avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadget& +s;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -& +dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe& +20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\psnd.obj : c:\avp_copy\3dc\avp\psnd.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\psnd.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\a& +vp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets& +;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -d& +AVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe2& +0 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\psndproj.obj : c:\avp_copy\3dc\avp\psndproj.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\psndproj.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\pvisible.obj : c:\avp_copy\3dc\avp\pvisible.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\pvisible.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\savegame.obj : c:\avp_copy\3dc\avp\savegame.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\savegame.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\secstats.obj : c:\avp_copy\3dc\avp\secstats.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\secstats.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\sfx.obj : c:\avp_copy\3dc\avp\sfx.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\sfx.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\av& +p;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;& +3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dA& +VP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20& + -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\cube.obj : c:\avp_copy\3dc\avp\shapes\cube.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\shapes\cube.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -& +or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\stratdef.obj : c:\avp_copy\3dc\avp\stratdef.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\stratdef.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\strutil.obj : c:\avp_copy\3dc\avp\support\strutil.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\support\strutil.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\wat& +com\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\wi& +n95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -d& +engine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -& +oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\targeting.obj : c:\avp_copy\3dc\avp\targeting.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\targeting.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;& +3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\ga& +dgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine& +=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or& + -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\track.obj : c:\avp_copy\3dc\avp\track.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\track.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\& +avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadget& +s;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -& +dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe& +20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\triggers.obj : c:\avp_copy\3dc\avp\triggers.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\triggers.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or & +-oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\weapons.obj : c:\avp_copy\3dc\avp\weapons.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\weapons.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\cheat.obj : c:\avp_copy\3dc\avp\win95\cheat.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\cheat.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -& +or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\directplay.obj : c:\avp_copy\3dc\avp\win95\directplay.c .AUTODEP& +END + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\directplay.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\wa& +tcom\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\w& +in95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -& +dengine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi & +-oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\dp_func.obj : c:\avp_copy\3dc\avp\win95\dp_func.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\dp_func.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watco& +m\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win9& +5\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -den& +gine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa& + -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\dplayext.obj : c:\avp_copy\3dc\avp\win95\dplayext.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\dplayext.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watc& +om\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win& +95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -de& +ngine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -o& +a -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\endianio.obj : c:\avp_copy\3dc\avp\win95\endianio.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\endianio.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watc& +om\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win& +95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -de& +ngine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -o& +a -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\avp_envinfo.obj : c:\avp_copy\3dc\avp\win95\frontend\avp_envinfo& +.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\frontend\avp_envinfo.c -i=c:\mssdk\include;c:\watcom\& +h\nt;c:\watcom\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support& +;3dc\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 & +-d_DEBUG -dengine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -o& +m -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\avp_menudata.obj : c:\avp_copy\3dc\avp\win95\frontend\avp_menuda& +ta.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\frontend\avp_menudata.c -i=c:\mssdk\include;c:\watcom& +\h\nt;c:\watcom\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\suppor& +t;3dc\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32& + -d_DEBUG -dengine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -& +om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\avp_menus.obj : c:\avp_copy\3dc\avp\win95\frontend\avp_menus.c .& +AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\frontend\avp_menus.c -i=c:\mssdk\include;c:\watcom\h\& +nt;c:\watcom\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3& +dc\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d& +_DEBUG -dengine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om & +-oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\gflwplat.obj : c:\avp_copy\3dc\avp\win95\gflwplat.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\gflwplat.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watc& +om\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win& +95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -de& +ngine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -o& +a -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\kzsort.obj : c:\avp_copy\3dc\avp\win95\kzsort.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\kzsort.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa & +-or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\langplat.obj : c:\avp_copy\3dc\avp\win95\langplat.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\langplat.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watc& +om\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win& +95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -de& +ngine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -o& +a -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\platsup.obj : c:\avp_copy\3dc\avp\win95\platsup.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\platsup.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watco& +m\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win9& +5\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -den& +gine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa& + -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\pldghost.obj : c:\avp_copy\3dc\avp\win95\pldghost.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\pldghost.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watc& +om\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win& +95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -de& +ngine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -o& +a -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\pldnet.obj : c:\avp_copy\3dc\avp\win95\pldnet.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\pldnet.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa & +-or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\psndplat.obj : c:\avp_copy\3dc\avp\win95\psndplat.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\psndplat.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watc& +om\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win& +95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -de& +ngine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -o& +a -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\system.obj : c:\avp_copy\3dc\avp\win95\system.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\system.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa & +-or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\usr_io.obj : c:\avp_copy\3dc\avp\win95\usr_io.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\usr_io.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa & +-or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\vision.obj : c:\avp_copy\3dc\avp\win95\vision.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\vision.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa & +-or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\winmain.obj : c:\avp_copy\3dc\avp\win95\winmain.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\avp\win95\winmain.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watco& +m\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win9& +5\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -den& +gine=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa& + -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\frustrum.obj : c:\avp_copy\3dc\frustrum.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\frustrum.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\a& +vp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets& +;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -d& +AVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe2& +0 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\kshape.obj : c:\avp_copy\3dc\kshape.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\kshape.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\avp& +;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;3& +dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dAV& +P_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20 & +-d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\map.obj : c:\avp_copy\3dc\map.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\map.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\avp;3d& +c\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;3dc\& +avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dAVP_D& +EBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20 -d2& + -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\maths.obj : c:\avp_copy\3dc\maths.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\maths.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\avp;& +3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;3d& +c\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dAVP& +_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20 -& +d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\mem3dc.obj : c:\avp_copy\3dc\mem3dc.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\mem3dc.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\avp& +;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;3& +dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dAV& +P_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20 & +-d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\module.obj : c:\avp_copy\3dc\module.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\module.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\avp& +;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;3& +dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dAV& +P_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20 & +-d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\morph.obj : c:\avp_copy\3dc\morph.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\morph.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\avp;& +3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;3d& +c\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dAVP& +_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20 -& +d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\mslhand.obj : c:\avp_copy\3dc\mslhand.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\mslhand.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\av& +p;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;& +3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dA& +VP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20& + -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\object.obj : c:\avp_copy\3dc\object.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\object.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\avp& +;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;3& +dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dAV& +P_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20 & +-d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\shpanim.obj : c:\avp_copy\3dc\shpanim.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\shpanim.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\av& +p;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;& +3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dA& +VP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20& + -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\sphere.obj : c:\avp_copy\3dc\sphere.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\sphere.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\avp& +;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;3& +dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dAV& +P_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20 & +-d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\tables.obj : c:\avp_copy\3dc\tables.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\tables.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\avp& +;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;3& +dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dAV& +P_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20 & +-d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\vdb.obj : c:\avp_copy\3dc\vdb.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\vdb.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\avp;3d& +c\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;3dc\& +avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dAVP_D& +EBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20 -d2& + -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\version.obj : c:\avp_copy\3dc\version.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\version.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\av& +p;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;& +3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -dA& +VP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe20& + -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bink.obj : c:\avp_copy\3dc\win95\bink.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\win95\bink.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc& +\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadge& +ts;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 & +-dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -o& +e20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\cd_player.obj : c:\avp_copy\3dc\win95\cd_player.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\win95\cd_player.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -& +or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\db.obj : c:\avp_copy\3dc\win95\db.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\win95\db.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\a& +vp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets& +;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -d& +AVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe2& +0 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\dxlog.obj : c:\avp_copy\3dc\win95\dxlog.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\win95\dxlog.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\fail.obj : c:\avp_copy\3dc\win95\fail.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\win95\fail.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc& +\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadge& +ts;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 & +-dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -o& +e20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\io.obj : c:\avp_copy\3dc\win95\io.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\win95\io.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\a& +vp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets& +;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -d& +AVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe2& +0 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\md5.obj : c:\avp_copy\3dc\win95\md5.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\win95\md5.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\& +avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadget& +s;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 -& +dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -oe& +20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\our_mem.obj : c:\avp_copy\3dc\win95\our_mem.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\win95\our_mem.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;& +3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\ga& +dgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine& +=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or& + -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\plat_shp.obj : c:\avp_copy\3dc\win95\plat_shp.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\win95\plat_shp.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h& +;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\g& +adgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengin& +e=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -o& +r -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\plspecfn.obj : c:\avp_copy\3dc\win95\plspecfn.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\win95\plspecfn.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h& +;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\g& +adgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengin& +e=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -o& +r -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\smacker.obj : c:\avp_copy\3dc\win95\smacker.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\win95\smacker.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;& +3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\ga& +dgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine& +=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or& + -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\texio.obj : c:\avp_copy\3dc\win95\texio.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\win95\texio.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -or -& +oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\vramtime.obj : c:\avp_copy\3dc\win95\vramtime.c .AUTODEPEND + @c: + cd c:\avp_copy + *wcc386 3dc\win95\vramtime.c -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h& +;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\g& +adgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengin& +e=1 -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi -oa -o& +r -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\cconvars.obj : c:\avp_copy\3dc\avp\cconvars.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\cconvars.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h& +;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\g& +adgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengin& +e=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc& + -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\cdtrackselection.obj : c:\avp_copy\3dc\avp\cdtrackselection.cpp & +.AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\cdtrackselection.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\& +watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp& +\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG& + -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+& + -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\consolelog.obj : c:\avp_copy\3dc\avp\consolelog.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\consolelog.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\davehook.obj : c:\avp_copy\3dc\avp\davehook.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\davehook.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h& +;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\g& +adgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengin& +e=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc& + -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\equiputl.obj : c:\avp_copy\3dc\avp\equiputl.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\equiputl.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h& +;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\g& +adgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengin& +e=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc& + -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\gamecmds.obj : c:\avp_copy\3dc\avp\gamecmds.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\gamecmds.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h& +;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\g& +adgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengin& +e=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc& + -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\gamevars.obj : c:\avp_copy\3dc\avp\gamevars.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\gamevars.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h& +;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\g& +adgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengin& +e=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc& + -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\missions.obj : c:\avp_copy\3dc\avp\missions.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\missions.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h& +;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\g& +adgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengin& +e=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc& + -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\scream.obj : c:\avp_copy\3dc\avp\scream.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\scream.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3& +dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gad& +gets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=& +1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -& +oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\consbind.obj : c:\avp_copy\3dc\avp\support\consbind.cpp .AUTODEP& +END + @c: + cd c:\avp_copy + *wpp386 3dc\avp\support\consbind.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\& +watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp& +\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG& + -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+& + -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\consbtch.obj : c:\avp_copy\3dc\avp\support\consbtch.cpp .AUTODEP& +END + @c: + cd c:\avp_copy + *wpp386 3dc\avp\support\consbtch.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\& +watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp& +\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG& + -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+& + -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\coordstr.obj : c:\avp_copy\3dc\avp\support\coordstr.cpp .AUTODEP& +END + @c: + cd c:\avp_copy + *wpp386 3dc\avp\support\coordstr.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\& +watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp& +\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG& + -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+& + -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\daemon.obj : c:\avp_copy\3dc\avp\support\daemon.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\support\daemon.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wa& +tcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\w& +in95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -& +dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -& +om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\indexfnt.obj : c:\avp_copy\3dc\avp\support\indexfnt.cpp .AUTODEP& +END + @c: + cd c:\avp_copy + *wpp386 3dc\avp\support\indexfnt.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\& +watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp& +\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG& + -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+& + -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\r2base.obj : c:\avp_copy\3dc\avp\support\r2base.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\support\r2base.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wa& +tcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\w& +in95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -& +dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -& +om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\r2pos666.obj : c:\avp_copy\3dc\avp\support\r2pos666.cpp .AUTODEP& +END + @c: + cd c:\avp_copy + *wpp386 3dc\avp\support\r2pos666.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\& +watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp& +\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG& + -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+& + -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\reflist.obj : c:\avp_copy\3dc\avp\support\reflist.cpp .AUTODEPEN& +D + @c: + cd c:\avp_copy + *wpp386 3dc\avp\support\reflist.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\w& +atcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\& +win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG & +-dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ & +-om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\refobj.obj : c:\avp_copy\3dc\avp\support\refobj.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\support\refobj.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wa& +tcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\w& +in95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -& +dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -& +om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\rentrntq.obj : c:\avp_copy\3dc\avp\support\rentrntq.cpp .AUTODEP& +END + @c: + cd c:\avp_copy + *wpp386 3dc\avp\support\rentrntq.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\& +watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp& +\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG& + -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+& + -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\scstring.obj : c:\avp_copy\3dc\avp\support\scstring.cpp .AUTODEP& +END + @c: + cd c:\avp_copy + *wpp386 3dc\avp\support\scstring.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\& +watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp& +\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG& + -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+& + -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\strtab.obj : c:\avp_copy\3dc\avp\support\strtab.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\support\strtab.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wa& +tcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\w& +in95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -& +dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -& +om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\tallfont.obj : c:\avp_copy\3dc\avp\support\tallfont.cpp .AUTODEP& +END + @c: + cd c:\avp_copy + *wpp386 3dc\avp\support\tallfont.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\& +watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp& +\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG& + -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+& + -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\trig666.obj : c:\avp_copy\3dc\avp\support\trig666.cpp .AUTODEPEN& +D + @c: + cd c:\avp_copy + *wpp386 3dc\avp\support\trig666.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\w& +atcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\& +win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG & +-dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ & +-om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\wrapstr.obj : c:\avp_copy\3dc\avp\support\wrapstr.cpp .AUTODEPEN& +D + @c: + cd c:\avp_copy + *wpp386 3dc\avp\support\wrapstr.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\w& +atcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\& +win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG & +-dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ & +-om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\avpchunk.obj : c:\avp_copy\3dc\avp\win95\avpchunk.cpp .AUTODEPEN& +D + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\avpchunk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wa& +tcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\w& +in95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -& +dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -& +om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\avpreg.obj : c:\avp_copy\3dc\avp\win95\avpreg.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\avpreg.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watc& +om\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win& +95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -de& +ngine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om& + -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\chtcodes.obj : c:\avp_copy\3dc\avp\win95\chtcodes.cpp .AUTODEPEN& +D + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\chtcodes.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wa& +tcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\w& +in95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -& +dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -& +om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\d3d_hud.obj : c:\avp_copy\3dc\avp\win95\d3d_hud.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\d3d_hud.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wat& +com\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\wi& +n95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -d& +engine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -o& +m -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\d3d_render.obj : c:\avp_copy\3dc\avp\win95\d3d_render.cpp .AUTOD& +EPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\d3d_render.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\& +watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp& +\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG& + -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+& + -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\ddplat.obj : c:\avp_copy\3dc\avp\win95\ddplat.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\ddplat.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watc& +om\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win& +95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -de& +ngine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om& + -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\dx_proj.obj : c:\avp_copy\3dc\avp\win95\dx_proj.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\dx_proj.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wat& +com\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\wi& +n95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -d& +engine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -o& +m -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\ffread.obj : c:\avp_copy\3dc\avp\win95\ffread.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\ffread.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watc& +om\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win& +95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -de& +ngine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om& + -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\ffstdio.obj : c:\avp_copy\3dc\avp\win95\ffstdio.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\ffstdio.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wat& +com\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\wi& +n95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -d& +engine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -o& +m -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\avp_intro.obj : c:\avp_copy\3dc\avp\win95\frontend\avp_intro.cpp& + .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\frontend\avp_intro.cpp -i=c:\mssdk\include;c:\watcom\& +h\nt;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support& +;3dc\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 & +-d_DEBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan & +-ol -ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\avp_menugfx.obj : c:\avp_copy\3dc\avp\win95\frontend\avp_menugfx& +.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\frontend\avp_menugfx.cpp -i=c:\mssdk\include;c:\watco& +m\h\nt;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\suppo& +rt;3dc\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN3& +2 -d_DEBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexa& +n -ol -ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\avp_mp_config.obj : c:\avp_copy\3dc\avp\win95\frontend\avp_mp_co& +nfig.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\frontend\avp_mp_config.cpp -i=c:\mssdk\include;c:\wat& +com\h\nt;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\sup& +port;3dc\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWI& +N32 -d_DEBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -ote& +xan -ol -ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\avp_userprofile.obj : c:\avp_copy\3dc\avp\win95\frontend\avp_use& +rprofile.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\frontend\avp_userprofile.cpp -i=c:\mssdk\include;c:\w& +atcom\h\nt;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\s& +upport;3dc\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -d& +WIN32 -d_DEBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -o& +texan -ol -ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\ahudgadg.obj : c:\avp_copy\3dc\avp\win95\gadgets\ahudgadg.cpp .A& +UTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\gadgets\ahudgadg.cpp -i=c:\mssdk\include;c:\watcom\h\& +nt;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3& +dc\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d& +_DEBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -o& +l -ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\conscmnd.obj : c:\avp_copy\3dc\avp\win95\gadgets\conscmnd.cpp .A& +UTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\gadgets\conscmnd.cpp -i=c:\mssdk\include;c:\watcom\h\& +nt;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3& +dc\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d& +_DEBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -o& +l -ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\conssym.obj : c:\avp_copy\3dc\avp\win95\gadgets\conssym.cpp .AUT& +ODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\gadgets\conssym.cpp -i=c:\mssdk\include;c:\watcom\h\n& +t;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3d& +c\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_& +DEBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol& + -ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\consvar.obj : c:\avp_copy\3dc\avp\win95\gadgets\consvar.cpp .AUT& +ODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\gadgets\consvar.cpp -i=c:\mssdk\include;c:\watcom\h\n& +t;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3d& +c\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_& +DEBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol& + -ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\gadget.obj : c:\avp_copy\3dc\avp\win95\gadgets\gadget.cpp .AUTOD& +EPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\gadgets\gadget.cpp -i=c:\mssdk\include;c:\watcom\h\nt& +;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc& +\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_D& +EBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol & +-ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\hudgadg.obj : c:\avp_copy\3dc\avp\win95\gadgets\hudgadg.cpp .AUT& +ODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\gadgets\hudgadg.cpp -i=c:\mssdk\include;c:\watcom\h\n& +t;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3d& +c\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_& +DEBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol& + -ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\rootgadg.obj : c:\avp_copy\3dc\avp\win95\gadgets\rootgadg.cpp .A& +UTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\gadgets\rootgadg.cpp -i=c:\mssdk\include;c:\watcom\h\& +nt;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3& +dc\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d& +_DEBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -o& +l -ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\t_ingadg.obj : c:\avp_copy\3dc\avp\win95\gadgets\t_ingadg.cpp .A& +UTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\gadgets\t_ingadg.cpp -i=c:\mssdk\include;c:\watcom\h\& +nt;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3& +dc\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d& +_DEBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -o& +l -ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\teletype.obj : c:\avp_copy\3dc\avp\win95\gadgets\teletype.cpp .A& +UTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\gadgets\teletype.cpp -i=c:\mssdk\include;c:\watcom\h\& +nt;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3& +dc\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d& +_DEBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -o& +l -ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\textexp.obj : c:\avp_copy\3dc\avp\win95\gadgets\textexp.cpp .AUT& +ODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\gadgets\textexp.cpp -i=c:\mssdk\include;c:\watcom\h\n& +t;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3d& +c\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_& +DEBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol& + -ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\textin.obj : c:\avp_copy\3dc\avp\win95\gadgets\textin.cpp .AUTOD& +EPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\gadgets\textin.cpp -i=c:\mssdk\include;c:\watcom\h\nt& +;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc& +\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_D& +EBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol & +-ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\trepgadg.obj : c:\avp_copy\3dc\avp\win95\gadgets\trepgadg.cpp .A& +UTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\gadgets\trepgadg.cpp -i=c:\mssdk\include;c:\watcom\h\& +nt;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3& +dc\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d& +_DEBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -o& +l -ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\gammacontrol.obj : c:\avp_copy\3dc\avp\win95\gammacontrol.cpp .A& +UTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\gammacontrol.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c& +:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\a& +vp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEB& +UG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -o& +l+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\hierplace.obj : c:\avp_copy\3dc\avp\win95\hierplace.cpp .AUTODEP& +END + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\hierplace.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\w& +atcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\& +win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG & +-dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ & +-om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\intro.obj : c:\avp_copy\3dc\avp\win95\intro.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\intro.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watco& +m\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win9& +5\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -den& +gine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om & +-oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\iofocus.obj : c:\avp_copy\3dc\avp\win95\iofocus.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\iofocus.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wat& +com\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\wi& +n95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -d& +engine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -o& +m -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\jsndsup.obj : c:\avp_copy\3dc\avp\win95\jsndsup.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\jsndsup.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wat& +com\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\wi& +n95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -d& +engine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -o& +m -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\modcmds.obj : c:\avp_copy\3dc\avp\win95\modcmds.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\modcmds.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wat& +com\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\wi& +n95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -d& +engine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -o& +m -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\mousecentreing.obj : c:\avp_copy\3dc\avp\win95\mousecentreing.cp& +p .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\mousecentreing.cpp -i=c:\mssdk\include;c:\watcom\h\nt& +;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc& +\avp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_D& +EBUG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol & +-ol+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\npcsetup.obj : c:\avp_copy\3dc\avp\win95\npcsetup.cpp .AUTODEPEN& +D + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\npcsetup.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wa& +tcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\w& +in95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -& +dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -& +om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\objsetup.obj : c:\avp_copy\3dc\avp\win95\objsetup.cpp .AUTODEPEN& +D + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\objsetup.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wa& +tcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\w& +in95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -& +dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -& +om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\pathchnk.obj : c:\avp_copy\3dc\avp\win95\pathchnk.cpp .AUTODEPEN& +D + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\pathchnk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wa& +tcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\w& +in95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -& +dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -& +om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\pcmenus.obj : c:\avp_copy\3dc\avp\win95\pcmenus.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\pcmenus.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wat& +com\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\wi& +n95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -d& +engine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -o& +m -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\progress_bar.obj : c:\avp_copy\3dc\avp\win95\progress_bar.cpp .A& +UTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\progress_bar.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c& +:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\a& +vp\win95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEB& +UG -dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -o& +l+ -om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\projload.obj : c:\avp_copy\3dc\avp\win95\projload.cpp .AUTODEPEN& +D + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\projload.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wa& +tcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\w& +in95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -& +dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -& +om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\scrshot.obj : c:\avp_copy\3dc\avp\win95\scrshot.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\scrshot.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wat& +com\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\wi& +n95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -d& +engine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -o& +m -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\strachnk.obj : c:\avp_copy\3dc\avp\win95\strachnk.cpp .AUTODEPEN& +D + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\strachnk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wa& +tcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\w& +in95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -& +dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -& +om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\win_proj.obj : c:\avp_copy\3dc\avp\win95\win_proj.cpp .AUTODEPEN& +D + @c: + cd c:\avp_copy + *wpp386 3dc\avp\win95\win_proj.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\wa& +tcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\w& +in95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -& +dengine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -& +om -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\mem3dcpp.obj : c:\avp_copy\3dc\mem3dcpp.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\mem3dcpp.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc& +\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadge& +ts;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1 & +-d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -oi& + -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\alt_tab.obj : c:\avp_copy\3dc\win95\alt_tab.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\alt_tab.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -o& +c -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\animchnk.obj : c:\avp_copy\3dc\win95\animchnk.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\animchnk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\animobs.obj : c:\avp_copy\3dc\win95\animobs.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\animobs.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -o& +c -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\awbmpld.obj : c:\avp_copy\3dc\win95\awbmpld.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\awbmpld.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -o& +c -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\awiffld.obj : c:\avp_copy\3dc\win95\awiffld.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\awiffld.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -o& +c -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\awpnmld.obj : c:\avp_copy\3dc\win95\awpnmld.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\awpnmld.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -o& +c -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\awtexld.obj : c:\avp_copy\3dc\win95\awtexld.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\awtexld.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -o& +c -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bmpnames.obj : c:\avp_copy\3dc\win95\bmpnames.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\bmpnames.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\bonechunk.obj : c:\avp_copy\3dc\win95\bonechunk.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\bonechunk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watco& +m\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win9& +5\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -den& +gine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om & +-oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\chnkload.obj : c:\avp_copy\3dc\win95\chnkload.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\chnkload.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\chnktexi.obj : c:\avp_copy\3dc\win95\chnktexi.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\chnktexi.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\chnktype.obj : c:\avp_copy\3dc\win95\chnktype.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\chnktype.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\chunk.obj : c:\avp_copy\3dc\win95\chunk.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\chunk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;& +3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\ga& +dgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine& +=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc & +-oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\chunkpal.obj : c:\avp_copy\3dc\win95\chunkpal.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\chunkpal.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\d3_func.obj : c:\avp_copy\3dc\win95\d3_func.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\d3_func.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -o& +c -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\dd_func.obj : c:\avp_copy\3dc\win95\dd_func.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\dd_func.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -o& +c -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\debuglog.obj : c:\avp_copy\3dc\win95\debuglog.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\debuglog.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\di_func.obj : c:\avp_copy\3dc\win95\di_func.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\di_func.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -o& +c -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\envchunk.obj : c:\avp_copy\3dc\win95\envchunk.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\envchunk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\fragchnk.obj : c:\avp_copy\3dc\win95\fragchnk.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\fragchnk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\gsprchnk.obj : c:\avp_copy\3dc\win95\gsprchnk.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\gsprchnk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\hierchnk.obj : c:\avp_copy\3dc\win95\hierchnk.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\hierchnk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\huffman.obj : c:\avp_copy\3dc\win95\huffman.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\huffman.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -o& +c -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\iff.obj : c:\avp_copy\3dc\win95\iff.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\iff.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3d& +c\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadg& +ets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine=1& + -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc -o& +i -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\iff_ilbm.obj : c:\avp_copy\3dc\win95\iff_ilbm.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\iff_ilbm.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\list_tem.obj : c:\avp_copy\3dc\win95\list_tem.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\list_tem.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\ltchunk.obj : c:\avp_copy\3dc\win95\ltchunk.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\ltchunk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -o& +c -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\media.obj : c:\avp_copy\3dc\win95\media.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\media.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;& +3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\ga& +dgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengine& +=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -oc & +-oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\mishchnk.obj : c:\avp_copy\3dc\win95\mishchnk.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\mishchnk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\obchunk.obj : c:\avp_copy\3dc\win95\obchunk.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\obchunk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -o& +c -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\shpchunk.obj : c:\avp_copy\3dc\win95\shpchunk.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\shpchunk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\sndchunk.obj : c:\avp_copy\3dc\win95\sndchunk.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\sndchunk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\sprchunk.obj : c:\avp_copy\3dc\win95\sprchunk.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\sprchunk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\txioctrl.obj : c:\avp_copy\3dc\win95\txioctrl.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\txioctrl.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\videomodes.obj : c:\avp_copy\3dc\win95\videomodes.cpp .AUTODEPEN& +D + @c: + cd c:\avp_copy + *wpp386 3dc\win95\videomodes.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watc& +om\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win& +95\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -de& +ngine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om& + -oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\win_func.obj : c:\avp_copy\3dc\win95\win_func.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\win_func.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom& +\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95& +\gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -deng& +ine=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -& +oc -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\wpchunk.obj : c:\avp_copy\3dc\win95\wpchunk.cpp .AUTODEPEND + @c: + cd c:\avp_copy + *wpp386 3dc\win95\wpchunk.cpp -i=c:\mssdk\include;c:\watcom\h\nt;c:\watcom\& +h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\& +gadgets;3dc\avp\win95\frontend;3dc -w4 -e25 -d_WIN32 -dWIN32 -d_DEBUG -dengi& +ne=1 -d__STDC__ -dAVP_DEBUG_VERSION -ei -zq -d_WIN32 -otexan -ol -ol+ -om -o& +c -oi -oa -or -oe20 -d2 -bm -fp5 -5r -bt=nt -mf + +c:\avp_copy\avpprog.exe : c:\avp_copy\mmx_math.obj c:\avp_copy\afont.obj c:\& +avp_copy\ai_sight.obj c:\avp_copy\avpview.obj c:\avp_copy\bh_agun.obj c:\avp& +_copy\bh_ais.obj c:\avp_copy\bh_alien.obj c:\avp_copy\bh_binsw.obj c:\avp_co& +py\bh_cable.obj c:\avp_copy\bh_corpse.obj c:\avp_copy\bh_deathvol.obj c:\avp& +_copy\bh_debri.obj c:\avp_copy\bh_dummy.obj c:\avp_copy\bh_fan.obj c:\avp_co& +py\bh_far.obj c:\avp_copy\bh_fhug.obj c:\avp_copy\bh_gener.obj c:\avp_copy\b& +h_ldoor.obj c:\avp_copy\bh_lift.obj c:\avp_copy\bh_light.obj c:\avp_copy\bh_& +lnksw.obj c:\avp_copy\bh_ltfx.obj c:\avp_copy\bh_marin.obj c:\avp_copy\bh_mi& +ssion.obj c:\avp_copy\bh_near.obj c:\avp_copy\bh_pargen.obj c:\avp_copy\bh_p& +lachier.obj c:\avp_copy\bh_plift.obj c:\avp_copy\bh_pred.obj c:\avp_copy\bh_& +queen.obj c:\avp_copy\bh_rubberduck.obj c:\avp_copy\bh_selfdest.obj c:\avp_c& +opy\bh_snds.obj c:\avp_copy\bh_spcl.obj c:\avp_copy\bh_swdor.obj c:\avp_copy& +\bh_track.obj c:\avp_copy\bh_types.obj c:\avp_copy\bh_videoscreen.obj c:\avp& +_copy\bh_waypt.obj c:\avp_copy\bh_weap.obj c:\avp_copy\bh_xeno.obj c:\avp_co& +py\bonusabilities.obj c:\avp_copy\cheatmodes.obj c:\avp_copy\comp_map.obj c:& +\avp_copy\comp_shp.obj c:\avp_copy\deaths.obj c:\avp_copy\decal.obj c:\avp_c& +opy\detaillevels.obj c:\avp_copy\dynamics.obj c:\avp_copy\dynblock.obj c:\av& +p_copy\equipmnt.obj c:\avp_copy\extents.obj c:\avp_copy\game.obj c:\avp_copy& +\game_statistics.obj c:\avp_copy\gameflow.obj c:\avp_copy\hmodel.obj c:\avp_& +copy\hud.obj c:\avp_copy\inventry.obj c:\avp_copy\language.obj c:\avp_copy\l& +ighting.obj c:\avp_copy\los.obj c:\avp_copy\mempool.obj c:\avp_copy\messageh& +istory.obj c:\avp_copy\movement.obj c:\avp_copy\mp_launch.obj c:\avp_copy\pa& +intball.obj c:\avp_copy\particle.obj c:\avp_copy\pfarlocs.obj c:\avp_copy\ph& +eromon.obj c:\avp_copy\player.obj c:\avp_copy\pmove.obj c:\avp_copy\psnd.obj& + c:\avp_copy\psndproj.obj c:\avp_copy\pvisible.obj c:\avp_copy\savegame.obj & +c:\avp_copy\secstats.obj c:\avp_copy\sfx.obj c:\avp_copy\cube.obj c:\avp_cop& +y\stratdef.obj c:\avp_copy\strutil.obj c:\avp_copy\targeting.obj c:\avp_copy& +\track.obj c:\avp_copy\triggers.obj c:\avp_copy\weapons.obj c:\avp_copy\chea& +t.obj c:\avp_copy\directplay.obj c:\avp_copy\dp_func.obj c:\avp_copy\dplayex& +t.obj c:\avp_copy\endianio.obj c:\avp_copy\avp_envinfo.obj c:\avp_copy\avp_m& +enudata.obj c:\avp_copy\avp_menus.obj c:\avp_copy\gflwplat.obj c:\avp_copy\k& +zsort.obj c:\avp_copy\langplat.obj c:\avp_copy\platsup.obj c:\avp_copy\pldgh& +ost.obj c:\avp_copy\pldnet.obj c:\avp_copy\psndplat.obj c:\avp_copy\system.o& +bj c:\avp_copy\usr_io.obj c:\avp_copy\vision.obj c:\avp_copy\winmain.obj c:\& +avp_copy\frustrum.obj c:\avp_copy\kshape.obj c:\avp_copy\map.obj c:\avp_copy& +\maths.obj c:\avp_copy\mem3dc.obj c:\avp_copy\module.obj c:\avp_copy\morph.o& +bj c:\avp_copy\mslhand.obj c:\avp_copy\object.obj c:\avp_copy\shpanim.obj c:& +\avp_copy\sphere.obj c:\avp_copy\tables.obj c:\avp_copy\vdb.obj c:\avp_copy\& +version.obj c:\avp_copy\bink.obj c:\avp_copy\cd_player.obj c:\avp_copy\db.ob& +j c:\avp_copy\dxlog.obj c:\avp_copy\fail.obj c:\avp_copy\io.obj c:\avp_copy\& +md5.obj c:\avp_copy\our_mem.obj c:\avp_copy\plat_shp.obj c:\avp_copy\plspecf& +n.obj c:\avp_copy\smacker.obj c:\avp_copy\texio.obj c:\avp_copy\vramtime.obj& + c:\avp_copy\cconvars.obj c:\avp_copy\cdtrackselection.obj c:\avp_copy\conso& +lelog.obj c:\avp_copy\davehook.obj c:\avp_copy\equiputl.obj c:\avp_copy\game& +cmds.obj c:\avp_copy\gamevars.obj c:\avp_copy\missions.obj c:\avp_copy\screa& +m.obj c:\avp_copy\consbind.obj c:\avp_copy\consbtch.obj c:\avp_copy\coordstr& +.obj c:\avp_copy\daemon.obj c:\avp_copy\indexfnt.obj c:\avp_copy\r2base.obj & +c:\avp_copy\r2pos666.obj c:\avp_copy\reflist.obj c:\avp_copy\refobj.obj c:\a& +vp_copy\rentrntq.obj c:\avp_copy\scstring.obj c:\avp_copy\strtab.obj c:\avp_& +copy\tallfont.obj c:\avp_copy\trig666.obj c:\avp_copy\wrapstr.obj c:\avp_cop& +y\avpchunk.obj c:\avp_copy\avpreg.obj c:\avp_copy\chtcodes.obj c:\avp_copy\d& +3d_hud.obj c:\avp_copy\d3d_render.obj c:\avp_copy\ddplat.obj c:\avp_copy\dx_& +proj.obj c:\avp_copy\ffread.obj c:\avp_copy\ffstdio.obj c:\avp_copy\avp_intr& +o.obj c:\avp_copy\avp_menugfx.obj c:\avp_copy\avp_mp_config.obj c:\avp_copy\& +avp_userprofile.obj c:\avp_copy\ahudgadg.obj c:\avp_copy\conscmnd.obj c:\avp& +_copy\conssym.obj c:\avp_copy\consvar.obj c:\avp_copy\gadget.obj c:\avp_copy& +\hudgadg.obj c:\avp_copy\rootgadg.obj c:\avp_copy\t_ingadg.obj c:\avp_copy\t& +eletype.obj c:\avp_copy\textexp.obj c:\avp_copy\textin.obj c:\avp_copy\trepg& +adg.obj c:\avp_copy\gammacontrol.obj c:\avp_copy\hierplace.obj c:\avp_copy\i& +ntro.obj c:\avp_copy\iofocus.obj c:\avp_copy\jsndsup.obj c:\avp_copy\modcmds& +.obj c:\avp_copy\mousecentreing.obj c:\avp_copy\npcsetup.obj c:\avp_copy\obj& +setup.obj c:\avp_copy\pathchnk.obj c:\avp_copy\pcmenus.obj c:\avp_copy\progr& +ess_bar.obj c:\avp_copy\projload.obj c:\avp_copy\scrshot.obj c:\avp_copy\str& +achnk.obj c:\avp_copy\win_proj.obj c:\avp_copy\mem3dcpp.obj c:\avp_copy\alt_& +tab.obj c:\avp_copy\animchnk.obj c:\avp_copy\animobs.obj c:\avp_copy\awbmpld& +.obj c:\avp_copy\awiffld.obj c:\avp_copy\awpnmld.obj c:\avp_copy\awtexld.obj& + c:\avp_copy\bmpnames.obj c:\avp_copy\bonechunk.obj c:\avp_copy\chnkload.obj& + c:\avp_copy\chnktexi.obj c:\avp_copy\chnktype.obj c:\avp_copy\chunk.obj c:\& +avp_copy\chunkpal.obj c:\avp_copy\d3_func.obj c:\avp_copy\dd_func.obj c:\avp& +_copy\debuglog.obj c:\avp_copy\di_func.obj c:\avp_copy\envchunk.obj c:\avp_c& +opy\fragchnk.obj c:\avp_copy\gsprchnk.obj c:\avp_copy\hierchnk.obj c:\avp_co& +py\huffman.obj c:\avp_copy\iff.obj c:\avp_copy\iff_ilbm.obj c:\avp_copy\list& +_tem.obj c:\avp_copy\ltchunk.obj c:\avp_copy\media.obj c:\avp_copy\mishchnk.& +obj c:\avp_copy\obchunk.obj c:\avp_copy\shpchunk.obj c:\avp_copy\sndchunk.ob& +j c:\avp_copy\sprchunk.obj c:\avp_copy\txioctrl.obj c:\avp_copy\videomodes.o& +bj c:\avp_copy\win_func.obj c:\avp_copy\wpchunk.obj .AUTODEPEND + @c: + cd c:\avp_copy + @%write avpprog.lk1 FIL mmx_math.obj,afont.obj,ai_sight.obj,avpview.obj,bh_& +agun.obj,bh_ais.obj,bh_alien.obj,bh_binsw.obj,bh_cable.obj,bh_corpse.obj,bh_& +deathvol.obj,bh_debri.obj,bh_dummy.obj,bh_fan.obj,bh_far.obj,bh_fhug.obj,bh_& +gener.obj,bh_ldoor.obj,bh_lift.obj,bh_light.obj,bh_lnksw.obj,bh_ltfx.obj,bh_& +marin.obj,bh_mission.obj,bh_near.obj,bh_pargen.obj,bh_plachier.obj,bh_plift.& +obj,bh_pred.obj,bh_queen.obj,bh_rubberduck.obj,bh_selfdest.obj,bh_snds.obj,b& +h_spcl.obj,bh_swdor.obj,bh_track.obj,bh_types.obj,bh_videoscreen.obj,bh_wayp& +t.obj,bh_weap.obj,bh_xeno.obj,bonusabilities.obj,cheatmodes.obj,comp_map.obj& +,comp_shp.obj,deaths.obj,decal.obj,detaillevels.obj,dynamics.obj,dynblock.ob& +j,equipmnt.obj,extents.obj,game.obj,game_statistics.obj,gameflow.obj,hmodel.& +obj,hud.obj,inventry.obj,language.obj,lighting.obj,los.obj,mempool.obj,messa& +gehistory.obj,movement.obj,mp_launch.obj,paintball.obj,particle.obj,pfarlocs& +.obj,pheromon.obj,player.obj,pmove.obj,psnd.obj,psndproj.obj,pvisible.obj,sa& +vegame.obj,secstats.obj,sfx.obj,cube.obj,stratdef.obj,strutil.obj,targeting.& +obj,track.obj,triggers.obj,weapons.obj,cheat.obj,directplay.obj,dp_func.obj,& +dplayext.obj,endianio.obj,avp_envinfo.obj,avp_menudata.obj,avp_menus.obj,gfl& +wplat.obj,kzsort.obj,langplat.obj,platsup.obj,pldghost.obj,pldnet.obj,psndpl& +at.obj,system.obj,usr_io.obj,vision.obj,winmain.obj,frustrum.obj,kshape.obj,& +map.obj,maths.obj,mem3dc.obj,module.obj,morph.obj,mslhand.obj,object.obj,shp& +anim.obj,sphere.obj,tables.obj,vdb.obj,version.obj,bink.obj,cd_player.obj,db& +.obj,dxlog.obj,fail.obj,io.obj,md5.obj,our_mem.obj,plat_shp.obj,plspecfn.obj& +,smacker.obj,texio.obj,vramtime.obj,cconvars.obj,cdtrackselection.obj,consol& +elog.obj,davehook.obj,equiputl.obj,gamecmds.obj,gamevars.obj,missions.obj,sc& +ream.obj,consbind.obj,consbtch.obj,coordstr.obj,daemon.obj,indexfnt.obj,r2ba& +se.obj,r2pos666.obj,reflist.obj,refobj.obj,rentrntq.obj,scstring.obj,strtab.& +obj,tallfont.obj,trig666.obj,wrapstr.obj,avpchunk.obj,avpreg.obj,chtcodes.ob& +j,d3d_hud.obj,d3d_render.obj,ddplat.obj,dx_proj.obj,ffread.obj,ffstdio.obj,a& +vp_intro.obj,avp_menugfx.obj,avp_mp_config.obj,avp_userprofile.obj,ahudgadg.& +obj,conscmnd.obj,conssym.obj,consvar.obj,gadget.obj,hudgadg.obj,rootgadg.obj& +,t_ingadg.obj,teletype.obj,textexp.obj,textin.obj,trepgadg.obj,gammacontrol.& +obj,hierplace.obj,intro.obj,iofocus.obj,jsndsup.obj,modcmds.obj,mousecentrei& +ng.obj,npcsetup.obj,objsetup.obj,pathchnk.obj,pcmenus.obj,progress_bar.obj,p& +rojload.obj,scrshot.obj,strachnk.obj,win_proj.obj,mem3dcpp.obj,alt_tab.obj,a& +nimchnk.obj,animobs.obj,awbmpld.obj,awiffld.obj,awpnmld.obj,awtexld.obj,bmpn& +ames.obj,bonechunk.obj,chnkload.obj,chnktexi.obj,chnktype.obj,chunk.obj,chun& +kpal.obj,d3_func.obj,dd_func.obj,debuglog.obj,di_func.obj,envchunk.obj,fragc& +hnk.obj,gsprchnk.obj,hierchnk.obj,huffman.obj,iff.obj,iff_ilbm.obj,list_tem.& +obj,ltchunk.obj,media.obj,mishchnk.obj,obchunk.obj,shpchunk.obj,sndchunk.obj& +,sprchunk.obj,txioctrl.obj,videomodes.obj,win_func.obj,wpchunk.obj + @%append avpprog.lk1 +!ifneq BLANK "" + *wlib -q -n -b avpprog.imp + @%append avpprog.lk1 LIBR avpprog.imp +!endif +!ifneq BLANK "" + @%append avpprog.lk1 op resource= +!endif + *wlink name avpprog d all SYS nt_win op m op st=256k libp c:\mssdk\lib;c:3d& +c libr ddraw,dsound,dplayx,dinput,smackw32,binkw32 op maxe=25 op q op symf @& +avpprog.lk1 + copy avpprog.exe 3dc\avpprog.exe + + diff --git a/avpprog.tgt b/avpprog.tgt new file mode 100644 index 0000000..17ddb7c --- /dev/null +++ b/avpprog.tgt @@ -0,0 +1,4862 @@ +40 +targetIdent +0 +MProject +1 +MComponent +0 +2 +WString +4 +NEXE +3 +WString +5 +nw2e9 +1 +0 +1 +4 +MCommand +0 +5 +MCommand +34 +copy avpprog.exe 3dc\avpprog.exe + +6 +MItem +11 +avpprog.exe +7 +WString +4 +NEXE +8 +WVList +4 +9 +MCState +10 +WString +7 +WINLINK +11 +WString +24 +?????Incremental Linking +1 +0 +12 +MVState +13 +WString +7 +WINLINK +14 +WString +11 +?????Stack: +1 +15 +WString +4 +256k +0 +16 +MVState +17 +WString +7 +WINLINK +18 +WString +28 +?????Library directories(;): +1 +19 +WString +18 +c:\mssdk\lib;c:3dc +0 +20 +MVState +21 +WString +7 +WINLINK +22 +WString +18 +?????Libraries(,): +1 +23 +WString +43 +ddraw,dsound,dplayx,dinput,smackw32,binkw32 +0 +24 +WVList +4 +25 +ActionStates +26 +WString +5 +&Make +27 +WVList +0 +28 +ActionStates +29 +WString +4 +&Run +30 +WVList +0 +31 +ActionStates +32 +WString +7 +Sam&ple +33 +WVList +0 +34 +ActionStates +35 +WString +6 +&Debug +36 +WVList +1 +37 +MVState +38 +WString +6 +WDEBUG +39 +WString +28 +?????Application parameters: +1 +40 +WString +15 +-w -h -n hangar +0 +-1 +1 +1 +0 +41 +WPickList +235 +42 +MItem +5 +*.asm +43 +WString +6 +ASMOBJ +44 +WVList +0 +45 +WVList +0 +-1 +1 +0 +0 +46 +MItem +22 +3dc\win95\mmx_math.asm +47 +WString +6 +ASMOBJ +48 +WVList +0 +49 +WVList +0 +42 +1 +1 +0 +50 +MItem +3 +*.c +51 +WString +4 +COBJ +52 +WVList +18 +53 +MVState +54 +WString +3 +WCC +55 +WString +25 +n????Include directories: +1 +56 +WString +152 +c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\avp;3dc\win95;3dc\include;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;3dc\avp\win95\frontend;3dc +0 +57 +MVState +58 +WString +3 +WCC +59 +WString +23 +?????Macro definitions: +1 +60 +WString +46 +_WIN32 WIN32 _DEBUG engine=1 AVP_DEBUG_VERSION +0 +61 +MCState +62 +WString +3 +WCC +63 +WString +31 +?????Force enums to be type int +1 +1 +64 +MVState +65 +WString +3 +WCC +66 +WString +19 +?????Other options: +1 +67 +WString +8 +-d_WIN32 +0 +68 +MRState +69 +WString +3 +WCC +70 +WString +21 +?????No optimizations +1 +0 +71 +MRState +72 +WString +3 +WCC +73 +WString +26 +?????Fastest possible code +1 +1 +74 +MCState +75 +WString +3 +WCC +76 +WString +23 +?????Loop optimizations +1 +1 +77 +MCState +78 +WString +3 +WCC +79 +WString +19 +?????Loop unrolling +1 +1 +80 +MCState +81 +WString +3 +WCC +82 +WString +23 +?????Math optimizations +1 +1 +83 +MCState +84 +WString +3 +WCC +85 +WString +30 +?????Call/return optimizations +1 +1 +86 +MCState +87 +WString +3 +WCC +88 +WString +32 +?????In-line intrinsic functions +1 +1 +89 +MCState +90 +WString +3 +WCC +91 +WString +25 +?????Relax alias checking +1 +1 +92 +MCState +93 +WString +3 +WCC +94 +WString +27 +?????Instruction scheduling +1 +1 +95 +MVState +96 +WString +3 +WCC +97 +WString +29 +?????Expand function in-line: +1 +98 +WString +2 +20 +1 +99 +MRState +100 +WString +3 +WCC +101 +WString +21 +?????Compiler default +1 +0 +102 +MCState +103 +WString +3 +WCC +104 +WString +30 +n????Multithreaded application +1 +1 +105 +MRState +106 +WString +3 +WCC +107 +WString +21 +?????Compiler default +1 +0 +108 +MRState +109 +WString +3 +WCC +110 +WString +33 +?????In-line Pentium instructions +1 +1 +111 +WVList +1 +112 +ActionStates +113 +WString +5 +&Make +114 +WVList +0 +-1 +1 +1 +0 +115 +MItem +11 +3dc\afont.c +116 +WString +4 +COBJ +117 +WVList +0 +118 +WVList +0 +50 +1 +1 +0 +119 +MItem +18 +3dc\avp\ai_sight.c +120 +WString +4 +COBJ +121 +WVList +0 +122 +WVList +0 +50 +1 +1 +0 +123 +MItem +17 +3dc\avp\avpview.c +124 +WString +4 +COBJ +125 +WVList +0 +126 +WVList +0 +50 +1 +1 +0 +127 +MItem +17 +3dc\avp\bh_agun.c +128 +WString +4 +COBJ +129 +WVList +0 +130 +WVList +0 +50 +1 +1 +0 +131 +MItem +16 +3dc\avp\bh_ais.c +132 +WString +4 +COBJ +133 +WVList +0 +134 +WVList +0 +50 +1 +1 +0 +135 +MItem +18 +3dc\avp\bh_alien.c +136 +WString +4 +COBJ +137 +WVList +0 +138 +WVList +0 +50 +1 +1 +0 +139 +MItem +18 +3dc\avp\bh_binsw.c +140 +WString +4 +COBJ +141 +WVList +0 +142 +WVList +0 +50 +1 +1 +0 +143 +MItem +18 +3dc\avp\bh_cable.c +144 +WString +4 +COBJ +145 +WVList +0 +146 +WVList +0 +50 +1 +1 +0 +147 +MItem +19 +3dc\avp\bh_corpse.c +148 +WString +4 +COBJ +149 +WVList +0 +150 +WVList +0 +50 +1 +1 +0 +151 +MItem +21 +3dc\avp\bh_deathvol.c +152 +WString +4 +COBJ +153 +WVList +0 +154 +WVList +0 +50 +1 +1 +0 +155 +MItem +18 +3dc\avp\bh_debri.c +156 +WString +4 +COBJ +157 +WVList +0 +158 +WVList +0 +50 +1 +1 +0 +159 +MItem +18 +3dc\avp\bh_dummy.c +160 +WString +4 +COBJ +161 +WVList +0 +162 +WVList +0 +50 +1 +1 +0 +163 +MItem +16 +3dc\avp\bh_fan.c +164 +WString +4 +COBJ +165 +WVList +0 +166 +WVList +0 +50 +1 +1 +0 +167 +MItem +16 +3dc\avp\bh_far.c +168 +WString +4 +COBJ +169 +WVList +0 +170 +WVList +0 +50 +1 +1 +0 +171 +MItem +17 +3dc\avp\bh_fhug.c +172 +WString +4 +COBJ +173 +WVList +0 +174 +WVList +0 +50 +1 +1 +0 +175 +MItem +18 +3dc\avp\bh_gener.c +176 +WString +4 +COBJ +177 +WVList +0 +178 +WVList +0 +50 +1 +1 +0 +179 +MItem +18 +3dc\avp\bh_ldoor.c +180 +WString +4 +COBJ +181 +WVList +0 +182 +WVList +0 +50 +1 +1 +0 +183 +MItem +17 +3dc\avp\bh_lift.c +184 +WString +4 +COBJ +185 +WVList +0 +186 +WVList +0 +50 +1 +1 +0 +187 +MItem +18 +3dc\avp\bh_light.c +188 +WString +4 +COBJ +189 +WVList +0 +190 +WVList +0 +50 +1 +1 +0 +191 +MItem +18 +3dc\avp\bh_lnksw.c +192 +WString +4 +COBJ +193 +WVList +0 +194 +WVList +0 +50 +1 +1 +0 +195 +MItem +17 +3dc\avp\bh_ltfx.c +196 +WString +4 +COBJ +197 +WVList +0 +198 +WVList +0 +50 +1 +1 +0 +199 +MItem +18 +3dc\avp\bh_marin.c +200 +WString +4 +COBJ +201 +WVList +0 +202 +WVList +0 +50 +1 +1 +0 +203 +MItem +20 +3dc\avp\bh_mission.c +204 +WString +4 +COBJ +205 +WVList +0 +206 +WVList +0 +50 +1 +1 +0 +207 +MItem +17 +3dc\avp\bh_near.c +208 +WString +4 +COBJ +209 +WVList +0 +210 +WVList +0 +50 +1 +1 +0 +211 +MItem +19 +3dc\avp\bh_pargen.c +212 +WString +4 +COBJ +213 +WVList +0 +214 +WVList +0 +50 +1 +1 +0 +215 +MItem +21 +3dc\avp\bh_plachier.c +216 +WString +4 +COBJ +217 +WVList +0 +218 +WVList +0 +50 +1 +1 +0 +219 +MItem +18 +3dc\avp\bh_plift.c +220 +WString +4 +COBJ +221 +WVList +0 +222 +WVList +0 +50 +1 +1 +0 +223 +MItem +17 +3dc\avp\bh_pred.c +224 +WString +4 +COBJ +225 +WVList +0 +226 +WVList +0 +50 +1 +1 +0 +227 +MItem +18 +3dc\avp\bh_queen.c +228 +WString +4 +COBJ +229 +WVList +0 +230 +WVList +0 +50 +1 +1 +0 +231 +MItem +23 +3dc\avp\bh_rubberduck.c +232 +WString +4 +COBJ +233 +WVList +0 +234 +WVList +0 +50 +1 +1 +0 +235 +MItem +21 +3dc\avp\bh_selfdest.c +236 +WString +4 +COBJ +237 +WVList +0 +238 +WVList +0 +50 +1 +1 +0 +239 +MItem +17 +3dc\avp\bh_snds.c +240 +WString +4 +COBJ +241 +WVList +0 +242 +WVList +0 +50 +1 +1 +0 +243 +MItem +17 +3dc\avp\bh_spcl.c +244 +WString +4 +COBJ +245 +WVList +0 +246 +WVList +0 +50 +1 +1 +0 +247 +MItem +18 +3dc\avp\bh_swdor.c +248 +WString +4 +COBJ +249 +WVList +0 +250 +WVList +0 +50 +1 +1 +0 +251 +MItem +18 +3dc\avp\bh_track.c +252 +WString +4 +COBJ +253 +WVList +0 +254 +WVList +0 +50 +1 +1 +0 +255 +MItem +18 +3dc\avp\bh_types.c +256 +WString +4 +COBJ +257 +WVList +0 +258 +WVList +0 +50 +1 +1 +0 +259 +MItem +24 +3dc\avp\bh_videoscreen.c +260 +WString +4 +COBJ +261 +WVList +0 +262 +WVList +0 +50 +1 +1 +0 +263 +MItem +18 +3dc\avp\bh_waypt.c +264 +WString +4 +COBJ +265 +WVList +0 +266 +WVList +0 +50 +1 +1 +0 +267 +MItem +17 +3dc\avp\bh_weap.c +268 +WString +4 +COBJ +269 +WVList +0 +270 +WVList +0 +50 +1 +1 +0 +271 +MItem +17 +3dc\avp\bh_xeno.c +272 +WString +4 +COBJ +273 +WVList +0 +274 +WVList +0 +50 +1 +1 +0 +275 +MItem +24 +3dc\avp\bonusabilities.c +276 +WString +4 +COBJ +277 +WVList +0 +278 +WVList +0 +50 +1 +1 +0 +279 +MItem +20 +3dc\avp\cheatmodes.c +280 +WString +4 +COBJ +281 +WVList +0 +282 +WVList +0 +50 +1 +1 +0 +283 +MItem +18 +3dc\avp\comp_map.c +284 +WString +4 +COBJ +285 +WVList +0 +286 +WVList +0 +50 +1 +1 +0 +287 +MItem +18 +3dc\avp\comp_shp.c +288 +WString +4 +COBJ +289 +WVList +0 +290 +WVList +0 +50 +1 +1 +0 +291 +MItem +16 +3dc\avp\deaths.c +292 +WString +4 +COBJ +293 +WVList +0 +294 +WVList +0 +50 +1 +1 +0 +295 +MItem +15 +3dc\avp\decal.c +296 +WString +4 +COBJ +297 +WVList +0 +298 +WVList +0 +50 +1 +1 +0 +299 +MItem +22 +3dc\avp\detaillevels.c +300 +WString +4 +COBJ +301 +WVList +0 +302 +WVList +0 +50 +1 +1 +0 +303 +MItem +18 +3dc\avp\dynamics.c +304 +WString +4 +COBJ +305 +WVList +0 +306 +WVList +0 +50 +1 +1 +0 +307 +MItem +18 +3dc\avp\dynblock.c +308 +WString +4 +COBJ +309 +WVList +0 +310 +WVList +0 +50 +1 +1 +0 +311 +MItem +18 +3dc\avp\equipmnt.c +312 +WString +4 +COBJ +313 +WVList +0 +314 +WVList +0 +50 +1 +1 +0 +315 +MItem +17 +3dc\avp\extents.c +316 +WString +4 +COBJ +317 +WVList +0 +318 +WVList +0 +50 +1 +1 +0 +319 +MItem +14 +3dc\avp\game.c +320 +WString +4 +COBJ +321 +WVList +0 +322 +WVList +0 +50 +1 +1 +0 +323 +MItem +25 +3dc\avp\game_statistics.c +324 +WString +4 +COBJ +325 +WVList +0 +326 +WVList +0 +50 +1 +1 +0 +327 +MItem +18 +3dc\avp\gameflow.c +328 +WString +4 +COBJ +329 +WVList +0 +330 +WVList +0 +50 +1 +1 +0 +331 +MItem +16 +3dc\avp\hmodel.c +332 +WString +4 +COBJ +333 +WVList +0 +334 +WVList +0 +50 +1 +1 +0 +335 +MItem +13 +3dc\avp\hud.c +336 +WString +4 +COBJ +337 +WVList +0 +338 +WVList +0 +50 +1 +1 +0 +339 +MItem +18 +3dc\avp\inventry.c +340 +WString +4 +COBJ +341 +WVList +0 +342 +WVList +0 +50 +1 +1 +0 +343 +MItem +18 +3dc\avp\language.c +344 +WString +4 +COBJ +345 +WVList +0 +346 +WVList +0 +50 +1 +1 +0 +347 +MItem +18 +3dc\avp\lighting.c +348 +WString +4 +COBJ +349 +WVList +0 +350 +WVList +0 +50 +1 +1 +0 +351 +MItem +13 +3dc\avp\los.c +352 +WString +4 +COBJ +353 +WVList +0 +354 +WVList +0 +50 +1 +1 +0 +355 +MItem +17 +3dc\avp\mempool.c +356 +WString +4 +COBJ +357 +WVList +0 +358 +WVList +0 +50 +1 +1 +0 +359 +MItem +24 +3dc\avp\messagehistory.c +360 +WString +4 +COBJ +361 +WVList +0 +362 +WVList +0 +50 +1 +1 +0 +363 +MItem +18 +3dc\avp\movement.c +364 +WString +4 +COBJ +365 +WVList +0 +366 +WVList +0 +50 +1 +1 +0 +367 +MItem +19 +3dc\avp\mp_launch.c +368 +WString +4 +COBJ +369 +WVList +0 +370 +WVList +0 +50 +1 +1 +0 +371 +MItem +19 +3dc\avp\paintball.c +372 +WString +4 +COBJ +373 +WVList +0 +374 +WVList +0 +50 +1 +1 +0 +375 +MItem +18 +3dc\avp\particle.c +376 +WString +4 +COBJ +377 +WVList +0 +378 +WVList +0 +50 +1 +1 +0 +379 +MItem +18 +3dc\avp\pfarlocs.c +380 +WString +4 +COBJ +381 +WVList +0 +382 +WVList +0 +50 +1 +1 +0 +383 +MItem +18 +3dc\avp\pheromon.c +384 +WString +4 +COBJ +385 +WVList +0 +386 +WVList +0 +50 +1 +1 +0 +387 +MItem +16 +3dc\avp\player.c +388 +WString +4 +COBJ +389 +WVList +0 +390 +WVList +0 +50 +1 +1 +0 +391 +MItem +15 +3dc\avp\pmove.c +392 +WString +4 +COBJ +393 +WVList +0 +394 +WVList +0 +50 +1 +1 +0 +395 +MItem +14 +3dc\avp\psnd.c +396 +WString +4 +COBJ +397 +WVList +0 +398 +WVList +0 +50 +1 +1 +0 +399 +MItem +18 +3dc\avp\psndproj.c +400 +WString +4 +COBJ +401 +WVList +0 +402 +WVList +0 +50 +1 +1 +0 +403 +MItem +18 +3dc\avp\pvisible.c +404 +WString +4 +COBJ +405 +WVList +0 +406 +WVList +0 +50 +1 +1 +0 +407 +MItem +18 +3dc\avp\savegame.c +408 +WString +4 +COBJ +409 +WVList +0 +410 +WVList +0 +50 +1 +1 +0 +411 +MItem +18 +3dc\avp\secstats.c +412 +WString +4 +COBJ +413 +WVList +0 +414 +WVList +0 +50 +1 +1 +0 +415 +MItem +13 +3dc\avp\sfx.c +416 +WString +4 +COBJ +417 +WVList +0 +418 +WVList +0 +50 +1 +1 +0 +419 +MItem +21 +3dc\avp\shapes\cube.c +420 +WString +4 +COBJ +421 +WVList +0 +422 +WVList +0 +50 +1 +1 +0 +423 +MItem +18 +3dc\avp\stratdef.c +424 +WString +4 +COBJ +425 +WVList +0 +426 +WVList +0 +50 +1 +1 +0 +427 +MItem +25 +3dc\avp\support\strutil.c +428 +WString +4 +COBJ +429 +WVList +0 +430 +WVList +0 +50 +1 +1 +0 +431 +MItem +19 +3dc\avp\targeting.c +432 +WString +4 +COBJ +433 +WVList +0 +434 +WVList +0 +50 +1 +1 +0 +435 +MItem +15 +3dc\avp\track.c +436 +WString +4 +COBJ +437 +WVList +0 +438 +WVList +0 +50 +1 +1 +0 +439 +MItem +18 +3dc\avp\triggers.c +440 +WString +4 +COBJ +441 +WVList +0 +442 +WVList +0 +50 +1 +1 +0 +443 +MItem +17 +3dc\avp\weapons.c +444 +WString +4 +COBJ +445 +WVList +0 +446 +WVList +0 +50 +1 +1 +0 +447 +MItem +21 +3dc\avp\win95\cheat.c +448 +WString +4 +COBJ +449 +WVList +0 +450 +WVList +0 +50 +1 +1 +0 +451 +MItem +26 +3dc\avp\win95\directplay.c +452 +WString +4 +COBJ +453 +WVList +0 +454 +WVList +0 +50 +1 +1 +0 +455 +MItem +23 +3dc\avp\win95\dp_func.c +456 +WString +4 +COBJ +457 +WVList +0 +458 +WVList +0 +50 +1 +1 +0 +459 +MItem +24 +3dc\avp\win95\dplayext.c +460 +WString +4 +COBJ +461 +WVList +0 +462 +WVList +0 +50 +1 +1 +0 +463 +MItem +24 +3dc\avp\win95\endianio.c +464 +WString +4 +COBJ +465 +WVList +0 +466 +WVList +0 +50 +1 +1 +0 +467 +MItem +36 +3dc\avp\win95\frontend\avp_envinfo.c +468 +WString +4 +COBJ +469 +WVList +0 +470 +WVList +0 +50 +1 +1 +0 +471 +MItem +37 +3dc\avp\win95\frontend\avp_menudata.c +472 +WString +4 +COBJ +473 +WVList +0 +474 +WVList +0 +50 +1 +1 +0 +475 +MItem +34 +3dc\avp\win95\frontend\avp_menus.c +476 +WString +4 +COBJ +477 +WVList +0 +478 +WVList +0 +50 +1 +1 +0 +479 +MItem +24 +3dc\avp\win95\gflwplat.c +480 +WString +4 +COBJ +481 +WVList +0 +482 +WVList +0 +50 +1 +1 +0 +483 +MItem +22 +3dc\avp\win95\kzsort.c +484 +WString +4 +COBJ +485 +WVList +0 +486 +WVList +0 +50 +1 +1 +0 +487 +MItem +24 +3dc\avp\win95\langplat.c +488 +WString +4 +COBJ +489 +WVList +0 +490 +WVList +0 +50 +1 +1 +0 +491 +MItem +23 +3dc\avp\win95\platsup.c +492 +WString +4 +COBJ +493 +WVList +0 +494 +WVList +0 +50 +1 +1 +0 +495 +MItem +24 +3dc\avp\win95\pldghost.c +496 +WString +4 +COBJ +497 +WVList +0 +498 +WVList +0 +50 +1 +1 +0 +499 +MItem +22 +3dc\avp\win95\pldnet.c +500 +WString +4 +COBJ +501 +WVList +0 +502 +WVList +0 +50 +1 +1 +0 +503 +MItem +24 +3dc\avp\win95\psndplat.c +504 +WString +4 +COBJ +505 +WVList +0 +506 +WVList +0 +50 +1 +1 +0 +507 +MItem +22 +3dc\avp\win95\system.c +508 +WString +4 +COBJ +509 +WVList +0 +510 +WVList +0 +50 +1 +1 +0 +511 +MItem +22 +3dc\avp\win95\usr_io.c +512 +WString +4 +COBJ +513 +WVList +0 +514 +WVList +0 +50 +1 +1 +0 +515 +MItem +22 +3dc\avp\win95\vision.c +516 +WString +4 +COBJ +517 +WVList +0 +518 +WVList +0 +50 +1 +1 +0 +519 +MItem +23 +3dc\avp\win95\winmain.c +520 +WString +4 +COBJ +521 +WVList +0 +522 +WVList +0 +50 +1 +1 +0 +523 +MItem +14 +3dc\frustrum.c +524 +WString +4 +COBJ +525 +WVList +0 +526 +WVList +0 +50 +1 +1 +0 +527 +MItem +12 +3dc\kshape.c +528 +WString +4 +COBJ +529 +WVList +0 +530 +WVList +0 +50 +1 +1 +0 +531 +MItem +9 +3dc\map.c +532 +WString +4 +COBJ +533 +WVList +0 +534 +WVList +0 +50 +1 +1 +0 +535 +MItem +11 +3dc\maths.c +536 +WString +4 +COBJ +537 +WVList +0 +538 +WVList +0 +50 +1 +1 +0 +539 +MItem +12 +3dc\mem3dc.c +540 +WString +4 +COBJ +541 +WVList +0 +542 +WVList +0 +50 +1 +1 +0 +543 +MItem +12 +3dc\module.c +544 +WString +4 +COBJ +545 +WVList +0 +546 +WVList +0 +50 +1 +1 +0 +547 +MItem +11 +3dc\morph.c +548 +WString +4 +COBJ +549 +WVList +0 +550 +WVList +0 +50 +1 +1 +0 +551 +MItem +13 +3dc\mslhand.c +552 +WString +4 +COBJ +553 +WVList +0 +554 +WVList +0 +50 +1 +1 +0 +555 +MItem +12 +3dc\object.c +556 +WString +4 +COBJ +557 +WVList +0 +558 +WVList +0 +50 +1 +1 +0 +559 +MItem +13 +3dc\shpanim.c +560 +WString +4 +COBJ +561 +WVList +0 +562 +WVList +0 +50 +1 +1 +0 +563 +MItem +12 +3dc\sphere.c +564 +WString +4 +COBJ +565 +WVList +0 +566 +WVList +0 +50 +1 +1 +0 +567 +MItem +12 +3dc\tables.c +568 +WString +4 +COBJ +569 +WVList +0 +570 +WVList +0 +50 +1 +1 +0 +571 +MItem +9 +3dc\vdb.c +572 +WString +4 +COBJ +573 +WVList +0 +574 +WVList +0 +50 +1 +1 +0 +575 +MItem +13 +3dc\version.c +576 +WString +4 +COBJ +577 +WVList +0 +578 +WVList +0 +50 +1 +1 +0 +579 +MItem +16 +3dc\win95\bink.c +580 +WString +4 +COBJ +581 +WVList +0 +582 +WVList +0 +50 +1 +1 +0 +583 +MItem +21 +3dc\win95\cd_player.c +584 +WString +4 +COBJ +585 +WVList +0 +586 +WVList +0 +50 +1 +1 +0 +587 +MItem +14 +3dc\win95\db.c +588 +WString +4 +COBJ +589 +WVList +0 +590 +WVList +0 +50 +1 +1 +0 +591 +MItem +17 +3dc\win95\dxlog.c +592 +WString +4 +COBJ +593 +WVList +0 +594 +WVList +0 +50 +1 +1 +0 +595 +MItem +16 +3dc\win95\fail.c +596 +WString +4 +COBJ +597 +WVList +0 +598 +WVList +0 +50 +1 +1 +0 +599 +MItem +14 +3dc\win95\io.c +600 +WString +4 +COBJ +601 +WVList +0 +602 +WVList +0 +50 +1 +1 +0 +603 +MItem +15 +3dc\win95\md5.c +604 +WString +4 +COBJ +605 +WVList +0 +606 +WVList +0 +50 +1 +1 +0 +607 +MItem +19 +3dc\win95\our_mem.c +608 +WString +4 +COBJ +609 +WVList +0 +610 +WVList +0 +50 +1 +1 +0 +611 +MItem +20 +3dc\win95\plat_shp.c +612 +WString +4 +COBJ +613 +WVList +0 +614 +WVList +0 +50 +1 +1 +0 +615 +MItem +20 +3dc\win95\plspecfn.c +616 +WString +4 +COBJ +617 +WVList +0 +618 +WVList +0 +50 +1 +1 +0 +619 +MItem +19 +3dc\win95\smacker.c +620 +WString +4 +COBJ +621 +WVList +0 +622 +WVList +0 +50 +1 +1 +0 +623 +MItem +17 +3dc\win95\texio.c +624 +WString +4 +COBJ +625 +WVList +0 +626 +WVList +0 +50 +1 +1 +0 +627 +MItem +20 +3dc\win95\vramtime.c +628 +WString +4 +COBJ +629 +WVList +0 +630 +WVList +0 +50 +1 +1 +0 +631 +MItem +5 +*.cpp +632 +WString +6 +CPPOBJ +633 +WVList +18 +634 +MVState +635 +WString +3 +WPP +636 +WString +25 +n????Include directories: +1 +637 +WString +152 +c:\mssdk\include;c:\watcom\h\nt;c:\watcom\h;3dc\avp;3dc\include;3dc\win95;3dc\avp\win95;3dc\avp\support;3dc\avp\win95\gadgets;3dc\avp\win95\frontend;3dc +0 +638 +MVState +639 +WString +3 +WPP +640 +WString +23 +?????Macro definitions: +1 +641 +WString +56 +_WIN32 WIN32 _DEBUG engine=1 __STDC__ AVP_DEBUG_VERSION +0 +642 +MCState +643 +WString +3 +WPP +644 +WString +31 +?????Force enums to be type int +1 +1 +645 +MVState +646 +WString +3 +WPP +647 +WString +19 +?????Other options: +1 +648 +WString +8 +-d_WIN32 +0 +649 +MRState +650 +WString +3 +WPP +651 +WString +21 +?????No optimizations +1 +0 +652 +MRState +653 +WString +3 +WPP +654 +WString +26 +?????Fastest possible code +1 +1 +655 +MCState +656 +WString +3 +WPP +657 +WString +23 +?????Loop optimizations +1 +1 +658 +MCState +659 +WString +3 +WPP +660 +WString +19 +?????Loop unrolling +1 +1 +661 +MCState +662 +WString +3 +WPP +663 +WString +23 +?????Math optimizations +1 +1 +664 +MCState +665 +WString +3 +WPP +666 +WString +30 +?????Call/return optimizations +1 +1 +667 +MCState +668 +WString +3 +WPP +669 +WString +32 +?????In-line intrinsic functions +1 +1 +670 +MCState +671 +WString +3 +WPP +672 +WString +25 +?????Relax alias checking +1 +1 +673 +MCState +674 +WString +3 +WPP +675 +WString +27 +?????Instruction scheduling +1 +1 +676 +MVState +677 +WString +3 +WPP +678 +WString +29 +?????Expand function in-line: +1 +679 +WString +2 +20 +1 +680 +MRState +681 +WString +3 +WPP +682 +WString +21 +?????Compiler default +1 +0 +683 +MCState +684 +WString +3 +WPP +685 +WString +30 +n????Multithreaded application +1 +1 +686 +MRState +687 +WString +3 +WPP +688 +WString +21 +?????Compiler default +1 +0 +689 +MRState +690 +WString +3 +WPP +691 +WString +33 +?????In-line Pentium instructions +1 +1 +692 +WVList +0 +-1 +1 +1 +0 +693 +MItem +20 +3dc\avp\cconvars.cpp +694 +WString +6 +CPPOBJ +695 +WVList +0 +696 +WVList +0 +631 +1 +1 +0 +697 +MItem +28 +3dc\avp\cdtrackselection.cpp +698 +WString +6 +CPPOBJ +699 +WVList +0 +700 +WVList +0 +631 +1 +1 +0 +701 +MItem +22 +3dc\avp\consolelog.cpp +702 +WString +6 +CPPOBJ +703 +WVList +0 +704 +WVList +0 +631 +1 +1 +0 +705 +MItem +20 +3dc\avp\davehook.cpp +706 +WString +6 +CPPOBJ +707 +WVList +0 +708 +WVList +0 +631 +1 +1 +0 +709 +MItem +20 +3dc\avp\equiputl.cpp +710 +WString +6 +CPPOBJ +711 +WVList +0 +712 +WVList +0 +631 +1 +1 +0 +713 +MItem +20 +3dc\avp\gamecmds.cpp +714 +WString +6 +CPPOBJ +715 +WVList +0 +716 +WVList +0 +631 +1 +1 +0 +717 +MItem +20 +3dc\avp\gamevars.cpp +718 +WString +6 +CPPOBJ +719 +WVList +0 +720 +WVList +0 +631 +1 +1 +0 +721 +MItem +20 +3dc\avp\missions.cpp +722 +WString +6 +CPPOBJ +723 +WVList +0 +724 +WVList +0 +631 +1 +1 +0 +725 +MItem +18 +3dc\avp\scream.cpp +726 +WString +6 +CPPOBJ +727 +WVList +0 +728 +WVList +0 +631 +1 +1 +0 +729 +MItem +28 +3dc\avp\support\consbind.cpp +730 +WString +6 +CPPOBJ +731 +WVList +0 +732 +WVList +0 +631 +1 +1 +0 +733 +MItem +28 +3dc\avp\support\consbtch.cpp +734 +WString +6 +CPPOBJ +735 +WVList +0 +736 +WVList +0 +631 +1 +1 +0 +737 +MItem +28 +3dc\avp\support\coordstr.cpp +738 +WString +6 +CPPOBJ +739 +WVList +0 +740 +WVList +0 +631 +1 +1 +0 +741 +MItem +26 +3dc\avp\support\daemon.cpp +742 +WString +6 +CPPOBJ +743 +WVList +0 +744 +WVList +0 +631 +1 +1 +0 +745 +MItem +28 +3dc\avp\support\indexfnt.cpp +746 +WString +6 +CPPOBJ +747 +WVList +0 +748 +WVList +0 +631 +1 +1 +0 +749 +MItem +26 +3dc\avp\support\r2base.cpp +750 +WString +6 +CPPOBJ +751 +WVList +0 +752 +WVList +0 +631 +1 +1 +0 +753 +MItem +28 +3dc\avp\support\r2pos666.cpp +754 +WString +6 +CPPOBJ +755 +WVList +0 +756 +WVList +0 +631 +1 +1 +0 +757 +MItem +27 +3dc\avp\support\reflist.cpp +758 +WString +6 +CPPOBJ +759 +WVList +0 +760 +WVList +0 +631 +1 +1 +0 +761 +MItem +26 +3dc\avp\support\refobj.cpp +762 +WString +6 +CPPOBJ +763 +WVList +0 +764 +WVList +0 +631 +1 +1 +0 +765 +MItem +28 +3dc\avp\support\rentrntq.cpp +766 +WString +6 +CPPOBJ +767 +WVList +0 +768 +WVList +0 +631 +1 +1 +0 +769 +MItem +28 +3dc\avp\support\scstring.cpp +770 +WString +6 +CPPOBJ +771 +WVList +0 +772 +WVList +0 +631 +1 +1 +0 +773 +MItem +26 +3dc\avp\support\strtab.cpp +774 +WString +6 +CPPOBJ +775 +WVList +0 +776 +WVList +0 +631 +1 +1 +0 +777 +MItem +28 +3dc\avp\support\tallfont.cpp +778 +WString +6 +CPPOBJ +779 +WVList +0 +780 +WVList +0 +631 +1 +1 +0 +781 +MItem +27 +3dc\avp\support\trig666.cpp +782 +WString +6 +CPPOBJ +783 +WVList +0 +784 +WVList +0 +631 +1 +1 +0 +785 +MItem +27 +3dc\avp\support\wrapstr.cpp +786 +WString +6 +CPPOBJ +787 +WVList +0 +788 +WVList +0 +631 +1 +1 +0 +789 +MItem +26 +3dc\avp\win95\avpchunk.cpp +790 +WString +6 +CPPOBJ +791 +WVList +0 +792 +WVList +0 +631 +1 +1 +0 +793 +MItem +24 +3dc\avp\win95\avpreg.cpp +794 +WString +6 +CPPOBJ +795 +WVList +0 +796 +WVList +0 +631 +1 +1 +0 +797 +MItem +26 +3dc\avp\win95\chtcodes.cpp +798 +WString +6 +CPPOBJ +799 +WVList +0 +800 +WVList +0 +631 +1 +1 +0 +801 +MItem +25 +3dc\avp\win95\d3d_hud.cpp +802 +WString +6 +CPPOBJ +803 +WVList +0 +804 +WVList +0 +631 +1 +1 +0 +805 +MItem +28 +3dc\avp\win95\d3d_render.cpp +806 +WString +6 +CPPOBJ +807 +WVList +0 +808 +WVList +0 +631 +1 +1 +0 +809 +MItem +24 +3dc\avp\win95\ddplat.cpp +810 +WString +6 +CPPOBJ +811 +WVList +0 +812 +WVList +0 +631 +1 +1 +0 +813 +MItem +25 +3dc\avp\win95\dx_proj.cpp +814 +WString +6 +CPPOBJ +815 +WVList +0 +816 +WVList +0 +631 +1 +1 +0 +817 +MItem +24 +3dc\avp\win95\ffread.cpp +818 +WString +6 +CPPOBJ +819 +WVList +0 +820 +WVList +0 +631 +1 +1 +0 +821 +MItem +25 +3dc\avp\win95\ffstdio.cpp +822 +WString +6 +CPPOBJ +823 +WVList +0 +824 +WVList +0 +631 +1 +1 +0 +825 +MItem +36 +3dc\avp\win95\frontend\avp_intro.cpp +826 +WString +6 +CPPOBJ +827 +WVList +0 +828 +WVList +0 +631 +1 +1 +0 +829 +MItem +38 +3dc\avp\win95\frontend\avp_menugfx.cpp +830 +WString +6 +CPPOBJ +831 +WVList +0 +832 +WVList +0 +631 +1 +1 +0 +833 +MItem +40 +3dc\avp\win95\frontend\avp_mp_config.cpp +834 +WString +6 +CPPOBJ +835 +WVList +0 +836 +WVList +0 +631 +1 +1 +0 +837 +MItem +42 +3dc\avp\win95\frontend\avp_userprofile.cpp +838 +WString +6 +CPPOBJ +839 +WVList +0 +840 +WVList +0 +631 +1 +1 +0 +841 +MItem +34 +3dc\avp\win95\gadgets\ahudgadg.cpp +842 +WString +6 +CPPOBJ +843 +WVList +0 +844 +WVList +0 +631 +1 +1 +0 +845 +MItem +34 +3dc\avp\win95\gadgets\conscmnd.cpp +846 +WString +6 +CPPOBJ +847 +WVList +0 +848 +WVList +0 +631 +1 +1 +0 +849 +MItem +33 +3dc\avp\win95\gadgets\conssym.cpp +850 +WString +6 +CPPOBJ +851 +WVList +0 +852 +WVList +0 +631 +1 +1 +0 +853 +MItem +33 +3dc\avp\win95\gadgets\consvar.cpp +854 +WString +6 +CPPOBJ +855 +WVList +0 +856 +WVList +0 +631 +1 +1 +0 +857 +MItem +32 +3dc\avp\win95\gadgets\gadget.cpp +858 +WString +6 +CPPOBJ +859 +WVList +0 +860 +WVList +0 +631 +1 +1 +0 +861 +MItem +33 +3dc\avp\win95\gadgets\hudgadg.cpp +862 +WString +6 +CPPOBJ +863 +WVList +0 +864 +WVList +0 +631 +1 +1 +0 +865 +MItem +34 +3dc\avp\win95\gadgets\rootgadg.cpp +866 +WString +6 +CPPOBJ +867 +WVList +0 +868 +WVList +0 +631 +1 +1 +0 +869 +MItem +34 +3dc\avp\win95\gadgets\t_ingadg.cpp +870 +WString +6 +CPPOBJ +871 +WVList +0 +872 +WVList +0 +631 +1 +1 +0 +873 +MItem +34 +3dc\avp\win95\gadgets\teletype.cpp +874 +WString +6 +CPPOBJ +875 +WVList +0 +876 +WVList +0 +631 +1 +1 +0 +877 +MItem +33 +3dc\avp\win95\gadgets\textexp.cpp +878 +WString +6 +CPPOBJ +879 +WVList +0 +880 +WVList +0 +631 +1 +1 +0 +881 +MItem +32 +3dc\avp\win95\gadgets\textin.cpp +882 +WString +6 +CPPOBJ +883 +WVList +0 +884 +WVList +0 +631 +1 +1 +0 +885 +MItem +34 +3dc\avp\win95\gadgets\trepgadg.cpp +886 +WString +6 +CPPOBJ +887 +WVList +0 +888 +WVList +0 +631 +1 +1 +0 +889 +MItem +30 +3dc\avp\win95\gammacontrol.cpp +890 +WString +6 +CPPOBJ +891 +WVList +0 +892 +WVList +0 +631 +1 +1 +0 +893 +MItem +27 +3dc\avp\win95\hierplace.cpp +894 +WString +6 +CPPOBJ +895 +WVList +0 +896 +WVList +0 +631 +1 +1 +0 +897 +MItem +23 +3dc\avp\win95\intro.cpp +898 +WString +6 +CPPOBJ +899 +WVList +0 +900 +WVList +0 +631 +1 +1 +0 +901 +MItem +25 +3dc\avp\win95\iofocus.cpp +902 +WString +6 +CPPOBJ +903 +WVList +0 +904 +WVList +0 +631 +1 +1 +0 +905 +MItem +25 +3dc\avp\win95\jsndsup.cpp +906 +WString +6 +CPPOBJ +907 +WVList +0 +908 +WVList +0 +631 +1 +1 +0 +909 +MItem +25 +3dc\avp\win95\modcmds.cpp +910 +WString +6 +CPPOBJ +911 +WVList +0 +912 +WVList +0 +631 +1 +1 +0 +913 +MItem +32 +3dc\avp\win95\mousecentreing.cpp +914 +WString +6 +CPPOBJ +915 +WVList +0 +916 +WVList +0 +631 +1 +1 +0 +917 +MItem +26 +3dc\avp\win95\npcsetup.cpp +918 +WString +6 +CPPOBJ +919 +WVList +0 +920 +WVList +0 +631 +1 +1 +0 +921 +MItem +26 +3dc\avp\win95\objsetup.cpp +922 +WString +6 +CPPOBJ +923 +WVList +0 +924 +WVList +0 +631 +1 +1 +0 +925 +MItem +26 +3dc\avp\win95\pathchnk.cpp +926 +WString +6 +CPPOBJ +927 +WVList +0 +928 +WVList +0 +631 +1 +1 +0 +929 +MItem +25 +3dc\avp\win95\pcmenus.cpp +930 +WString +6 +CPPOBJ +931 +WVList +0 +932 +WVList +0 +631 +1 +1 +0 +933 +MItem +30 +3dc\avp\win95\progress_bar.cpp +934 +WString +6 +CPPOBJ +935 +WVList +0 +936 +WVList +0 +631 +1 +1 +0 +937 +MItem +26 +3dc\avp\win95\projload.cpp +938 +WString +6 +CPPOBJ +939 +WVList +0 +940 +WVList +0 +631 +1 +1 +0 +941 +MItem +25 +3dc\avp\win95\scrshot.cpp +942 +WString +6 +CPPOBJ +943 +WVList +0 +944 +WVList +0 +631 +1 +1 +0 +945 +MItem +26 +3dc\avp\win95\strachnk.cpp +946 +WString +6 +CPPOBJ +947 +WVList +0 +948 +WVList +0 +631 +1 +1 +0 +949 +MItem +26 +3dc\avp\win95\win_proj.cpp +950 +WString +6 +CPPOBJ +951 +WVList +0 +952 +WVList +0 +631 +1 +1 +0 +953 +MItem +16 +3dc\mem3dcpp.cpp +954 +WString +6 +CPPOBJ +955 +WVList +0 +956 +WVList +0 +631 +1 +1 +0 +957 +MItem +21 +3dc\win95\alt_tab.cpp +958 +WString +6 +CPPOBJ +959 +WVList +0 +960 +WVList +0 +631 +1 +1 +0 +961 +MItem +22 +3dc\win95\animchnk.cpp +962 +WString +6 +CPPOBJ +963 +WVList +0 +964 +WVList +0 +631 +1 +1 +0 +965 +MItem +21 +3dc\win95\animobs.cpp +966 +WString +6 +CPPOBJ +967 +WVList +0 +968 +WVList +0 +631 +1 +1 +0 +969 +MItem +21 +3dc\win95\awbmpld.cpp +970 +WString +6 +CPPOBJ +971 +WVList +0 +972 +WVList +0 +631 +1 +1 +0 +973 +MItem +21 +3dc\win95\awiffld.cpp +974 +WString +6 +CPPOBJ +975 +WVList +0 +976 +WVList +0 +631 +1 +1 +0 +977 +MItem +21 +3dc\win95\awpnmld.cpp +978 +WString +6 +CPPOBJ +979 +WVList +0 +980 +WVList +0 +631 +1 +1 +0 +981 +MItem +21 +3dc\win95\awtexld.cpp +982 +WString +6 +CPPOBJ +983 +WVList +0 +984 +WVList +0 +631 +1 +1 +0 +985 +MItem +22 +3dc\win95\bmpnames.cpp +986 +WString +6 +CPPOBJ +987 +WVList +0 +988 +WVList +0 +631 +1 +1 +0 +989 +MItem +22 +3dc\win95\chnkload.cpp +990 +WString +6 +CPPOBJ +991 +WVList +0 +992 +WVList +0 +631 +1 +1 +0 +993 +MItem +22 +3dc\win95\chnktexi.cpp +994 +WString +6 +CPPOBJ +995 +WVList +0 +996 +WVList +0 +631 +1 +1 +0 +997 +MItem +22 +3dc\win95\chnktype.cpp +998 +WString +6 +CPPOBJ +999 +WVList +0 +1000 +WVList +0 +631 +1 +1 +0 +1001 +MItem +19 +3dc\win95\chunk.cpp +1002 +WString +6 +CPPOBJ +1003 +WVList +0 +1004 +WVList +0 +631 +1 +1 +0 +1005 +MItem +22 +3dc\win95\chunkpal.cpp +1006 +WString +6 +CPPOBJ +1007 +WVList +0 +1008 +WVList +0 +631 +1 +1 +0 +1009 +MItem +21 +3dc\win95\d3_func.cpp +1010 +WString +6 +CPPOBJ +1011 +WVList +0 +1012 +WVList +0 +631 +1 +1 +0 +1013 +MItem +21 +3dc\win95\dd_func.cpp +1014 +WString +6 +CPPOBJ +1015 +WVList +0 +1016 +WVList +0 +631 +1 +1 +0 +1017 +MItem +22 +3dc\win95\debuglog.cpp +1018 +WString +6 +CPPOBJ +1019 +WVList +0 +1020 +WVList +0 +631 +1 +1 +0 +1021 +MItem +21 +3dc\win95\di_func.cpp +1022 +WString +6 +CPPOBJ +1023 +WVList +0 +1024 +WVList +0 +631 +1 +1 +0 +1025 +MItem +22 +3dc\win95\envchunk.cpp +1026 +WString +6 +CPPOBJ +1027 +WVList +0 +1028 +WVList +0 +631 +1 +1 +0 +1029 +MItem +22 +3dc\win95\fragchnk.cpp +1030 +WString +6 +CPPOBJ +1031 +WVList +0 +1032 +WVList +0 +631 +1 +1 +0 +1033 +MItem +22 +3dc\win95\gsprchnk.cpp +1034 +WString +6 +CPPOBJ +1035 +WVList +0 +1036 +WVList +0 +631 +1 +1 +0 +1037 +MItem +22 +3dc\win95\hierchnk.cpp +1038 +WString +6 +CPPOBJ +1039 +WVList +0 +1040 +WVList +0 +631 +1 +1 +0 +1041 +MItem +21 +3dc\win95\huffman.cpp +1042 +WString +6 +CPPOBJ +1043 +WVList +0 +1044 +WVList +0 +631 +1 +1 +0 +1045 +MItem +17 +3dc\win95\iff.cpp +1046 +WString +6 +CPPOBJ +1047 +WVList +0 +1048 +WVList +0 +631 +1 +1 +0 +1049 +MItem +22 +3dc\win95\iff_ilbm.cpp +1050 +WString +6 +CPPOBJ +1051 +WVList +0 +1052 +WVList +0 +631 +1 +1 +0 +1053 +MItem +22 +3dc\win95\list_tem.cpp +1054 +WString +6 +CPPOBJ +1055 +WVList +0 +1056 +WVList +0 +631 +1 +1 +0 +1057 +MItem +21 +3dc\win95\ltchunk.cpp +1058 +WString +6 +CPPOBJ +1059 +WVList +0 +1060 +WVList +0 +631 +1 +1 +0 +1061 +MItem +19 +3dc\win95\media.cpp +1062 +WString +6 +CPPOBJ +1063 +WVList +0 +1064 +WVList +0 +631 +1 +1 +0 +1065 +MItem +22 +3dc\win95\mishchnk.cpp +1066 +WString +6 +CPPOBJ +1067 +WVList +0 +1068 +WVList +0 +631 +1 +1 +0 +1069 +MItem +21 +3dc\win95\obchunk.cpp +1070 +WString +6 +CPPOBJ +1071 +WVList +0 +1072 +WVList +0 +631 +1 +1 +0 +1073 +MItem +22 +3dc\win95\shpchunk.cpp +1074 +WString +6 +CPPOBJ +1075 +WVList +0 +1076 +WVList +0 +631 +1 +1 +0 +1077 +MItem +22 +3dc\win95\sndchunk.cpp +1078 +WString +6 +CPPOBJ +1079 +WVList +0 +1080 +WVList +0 +631 +1 +1 +0 +1081 +MItem +22 +3dc\win95\sprchunk.cpp +1082 +WString +6 +CPPOBJ +1083 +WVList +0 +1084 +WVList +0 +631 +1 +1 +0 +1085 +MItem +22 +3dc\win95\txioctrl.cpp +1086 +WString +6 +CPPOBJ +1087 +WVList +0 +1088 +WVList +0 +631 +1 +1 +0 +1089 +MItem +24 +3dc\win95\videomodes.cpp +1090 +WString +6 +CPPOBJ +1091 +WVList +0 +1092 +WVList +0 +631 +1 +1 +0 +1093 +MItem +22 +3dc\win95\win_func.cpp +1094 +WString +6 +CPPOBJ +1095 +WVList +0 +1096 +WVList +0 +631 +1 +1 +0 +1097 +MItem +21 +3dc\win95\wpchunk.cpp +1098 +WString +6 +CPPOBJ +1099 +WVList +0 +1100 +WVList +0 +631 +1 +1 +0 diff --git a/wat_release/avp.tgt b/wat_release/avp.tgt new file mode 100644 index 0000000..2849520 --- /dev/null +++ b/wat_release/avp.tgt @@ -0,0 +1,4955 @@ +40 +targetIdent +0 +MProject +1 +MComponent +0 +2 +WString +4 +NEXE +3 +WString +5 +nw2e9 +1 +0 +1 +4 +MCommand +0 +5 +MCommand +0 +6 +MItem +7 +avp.exe +7 +WString +4 +NEXE +8 +WVList +6 +9 +MRState +10 +WString +7 +WINLINK +11 +WString +25 +?????No debug information +1 +1 +12 +MRState +13 +WString +7 +WINLINK +14 +WString +14 +?????Debug All +1 +0 +15 +MCState +16 +WString +7 +WINLINK +17 +WString +24 +?????Incremental Linking +1 +0 +18 +MVState +19 +WString +7 +WINLINK +20 +WString +28 +?????Library directories(;): +1 +21 +WString +24 +c:\Dx6sdk\lib;c:\avp\3dc +0 +22 +MVState +23 +WString +7 +WINLINK +24 +WString +18 +?????Libraries(,): +1 +25 +WString +43 +ddraw,dsound,dplayx,dinput,smackw32,binkw32 +0 +26 +MCState +27 +WString +7 +WINLINK +28 +WString +24 +?????Eliminate dead code +1 +1 +29 +WVList +0 +-1 +1 +1 +0 +30 +WPickList +237 +31 +MItem +5 +*.asm +32 +WString +6 +ASMOBJ +33 +WVList +0 +34 +WVList +0 +-1 +1 +1 +0 +35 +MItem +25 +..\3dc\win95\mmx_math.asm +36 +WString +6 +ASMOBJ +37 +WVList +0 +38 +WVList +0 +31 +1 +1 +0 +39 +MItem +3 +*.c +40 +WString +4 +COBJ +41 +WVList +23 +42 +MVState +43 +WString +3 +WCC +44 +WString +25 +n????Include directories: +1 +45 +WString +177 +c:\Dx6sdk\include;c:\watcom\h\nt;c:\watcom\h;..\3dc\avp;..\3dc\win95;..\3dc\include;..\3dc\avp\win95;..\3dc\avp\support;..\3dc\avp\win95\gadgets;..\3dc\avp\win95\frontend;..\3dc +0 +46 +MCState +47 +WString +3 +WCC +48 +WString +33 +?????Disable stack depth checking +1 +1 +49 +MVState +50 +WString +3 +WCC +51 +WString +23 +?????Macro definitions: +1 +52 +WString +22 +_WIN32 WIN32 engine=1 +0 +53 +MCState +54 +WString +3 +WCC +55 +WString +31 +?????Force enums to be type int +1 +1 +56 +MRState +57 +WString +3 +WCC +58 +WString +20 +?????Pack structures +1 +0 +59 +MRState +60 +WString +3 +WCC +61 +WString +21 +?????8 byte alignment +1 +1 +62 +MRState +63 +WString +3 +WCC +64 +WString +21 +?????No optimizations +1 +0 +65 +MRState +66 +WString +3 +WCC +67 +WString +26 +?????Fastest possible code +1 +1 +68 +MCState +69 +WString +3 +WCC +70 +WString +23 +?????Loop optimizations +1 +1 +71 +MCState +72 +WString +3 +WCC +73 +WString +19 +?????Loop unrolling +1 +1 +74 +MCState +75 +WString +3 +WCC +76 +WString +23 +?????Math optimizations +1 +1 +77 +MCState +78 +WString +3 +WCC +79 +WString +32 +?????In-line intrinsic functions +1 +1 +80 +MCState +81 +WString +3 +WCC +82 +WString +25 +?????Relax alias checking +1 +1 +83 +MCState +84 +WString +3 +WCC +85 +WString +27 +?????Instruction scheduling +1 +1 +86 +MVState +87 +WString +3 +WCC +88 +WString +29 +?????Expand function in-line: +1 +89 +WString +2 +20 +1 +90 +MRState +91 +WString +3 +WCC +92 +WString +29 +?????No debugging information +1 +1 +93 +MRState +94 +WString +3 +WCC +95 +WString +24 +?????Full debugging info +1 +0 +96 +MRState +97 +WString +3 +WCC +98 +WString +21 +?????Compiler default +1 +0 +99 +MCState +100 +WString +3 +WCC +101 +WString +30 +n????Multithreaded application +1 +1 +102 +MRState +103 +WString +3 +WCC +104 +WString +21 +?????Compiler default +1 +0 +105 +MRState +106 +WString +3 +WCC +107 +WString +33 +?????In-line Pentium instructions +1 +1 +108 +MRState +109 +WString +3 +WCC +110 +WString +21 +?????Compiler default +1 +0 +111 +MRState +112 +WString +3 +WCC +113 +WString +29 +?????In-line with coprocessor +1 +1 +114 +WVList +0 +-1 +1 +0 +0 +115 +MItem +14 +..\3dc\afont.c +116 +WString +4 +COBJ +117 +WVList +0 +118 +WVList +0 +39 +1 +1 +0 +119 +MItem +21 +..\3dc\avp\ai_sight.c +120 +WString +4 +COBJ +121 +WVList +0 +122 +WVList +0 +39 +1 +1 +0 +123 +MItem +20 +..\3dc\avp\avpview.c +124 +WString +4 +COBJ +125 +WVList +0 +126 +WVList +0 +39 +1 +1 +0 +127 +MItem +20 +..\3dc\avp\bh_agun.c +128 +WString +4 +COBJ +129 +WVList +0 +130 +WVList +0 +39 +1 +1 +0 +131 +MItem +19 +..\3dc\avp\bh_ais.c +132 +WString +4 +COBJ +133 +WVList +0 +134 +WVList +0 +39 +1 +1 +0 +135 +MItem +21 +..\3dc\avp\bh_alien.c +136 +WString +4 +COBJ +137 +WVList +0 +138 +WVList +0 +39 +1 +1 +0 +139 +MItem +21 +..\3dc\avp\bh_binsw.c +140 +WString +4 +COBJ +141 +WVList +0 +142 +WVList +0 +39 +1 +1 +0 +143 +MItem +21 +..\3dc\avp\bh_cable.c +144 +WString +4 +COBJ +145 +WVList +0 +146 +WVList +0 +39 +1 +1 +0 +147 +MItem +22 +..\3dc\avp\bh_corpse.c +148 +WString +4 +COBJ +149 +WVList +0 +150 +WVList +0 +39 +1 +1 +0 +151 +MItem +24 +..\3dc\avp\bh_deathvol.c +152 +WString +4 +COBJ +153 +WVList +0 +154 +WVList +0 +39 +1 +1 +0 +155 +MItem +21 +..\3dc\avp\bh_debri.c +156 +WString +4 +COBJ +157 +WVList +0 +158 +WVList +0 +39 +1 +1 +0 +159 +MItem +21 +..\3dc\avp\bh_dummy.c +160 +WString +4 +COBJ +161 +WVList +0 +162 +WVList +0 +39 +1 +1 +0 +163 +MItem +19 +..\3dc\avp\bh_fan.c +164 +WString +4 +COBJ +165 +WVList +0 +166 +WVList +0 +39 +1 +1 +0 +167 +MItem +19 +..\3dc\avp\bh_far.c +168 +WString +4 +COBJ +169 +WVList +0 +170 +WVList +0 +39 +1 +1 +0 +171 +MItem +20 +..\3dc\avp\bh_fhug.c +172 +WString +4 +COBJ +173 +WVList +0 +174 +WVList +0 +39 +1 +1 +0 +175 +MItem +21 +..\3dc\avp\bh_gener.c +176 +WString +4 +COBJ +177 +WVList +0 +178 +WVList +0 +39 +1 +1 +0 +179 +MItem +21 +..\3dc\avp\bh_ldoor.c +180 +WString +4 +COBJ +181 +WVList +0 +182 +WVList +0 +39 +1 +1 +0 +183 +MItem +20 +..\3dc\avp\bh_lift.c +184 +WString +4 +COBJ +185 +WVList +0 +186 +WVList +0 +39 +1 +1 +0 +187 +MItem +21 +..\3dc\avp\bh_light.c +188 +WString +4 +COBJ +189 +WVList +0 +190 +WVList +0 +39 +1 +1 +0 +191 +MItem +21 +..\3dc\avp\bh_lnksw.c +192 +WString +4 +COBJ +193 +WVList +0 +194 +WVList +0 +39 +1 +1 +0 +195 +MItem +20 +..\3dc\avp\bh_ltfx.c +196 +WString +4 +COBJ +197 +WVList +0 +198 +WVList +0 +39 +1 +1 +0 +199 +MItem +21 +..\3dc\avp\bh_marin.c +200 +WString +4 +COBJ +201 +WVList +0 +202 +WVList +0 +39 +1 +1 +0 +203 +MItem +23 +..\3dc\avp\bh_mission.c +204 +WString +4 +COBJ +205 +WVList +0 +206 +WVList +0 +39 +1 +1 +0 +207 +MItem +20 +..\3dc\avp\bh_near.c +208 +WString +4 +COBJ +209 +WVList +0 +210 +WVList +0 +39 +1 +1 +0 +211 +MItem +22 +..\3dc\avp\bh_pargen.c +212 +WString +4 +COBJ +213 +WVList +0 +214 +WVList +0 +39 +1 +1 +0 +215 +MItem +24 +..\3dc\avp\bh_plachier.c +216 +WString +4 +COBJ +217 +WVList +0 +218 +WVList +0 +39 +1 +1 +0 +219 +MItem +21 +..\3dc\avp\bh_plift.c +220 +WString +4 +COBJ +221 +WVList +0 +222 +WVList +0 +39 +1 +1 +0 +223 +MItem +20 +..\3dc\avp\bh_pred.c +224 +WString +4 +COBJ +225 +WVList +0 +226 +WVList +0 +39 +1 +1 +0 +227 +MItem +21 +..\3dc\avp\bh_queen.c +228 +WString +4 +COBJ +229 +WVList +0 +230 +WVList +0 +39 +1 +1 +0 +231 +MItem +26 +..\3dc\avp\bh_rubberduck.c +232 +WString +4 +COBJ +233 +WVList +0 +234 +WVList +0 +39 +1 +1 +0 +235 +MItem +24 +..\3dc\avp\bh_selfdest.c +236 +WString +4 +COBJ +237 +WVList +0 +238 +WVList +0 +39 +1 +1 +0 +239 +MItem +20 +..\3dc\avp\bh_snds.c +240 +WString +4 +COBJ +241 +WVList +0 +242 +WVList +0 +39 +1 +1 +0 +243 +MItem +20 +..\3dc\avp\bh_spcl.c +244 +WString +4 +COBJ +245 +WVList +0 +246 +WVList +0 +39 +1 +1 +0 +247 +MItem +21 +..\3dc\avp\bh_swdor.c +248 +WString +4 +COBJ +249 +WVList +0 +250 +WVList +0 +39 +1 +1 +0 +251 +MItem +21 +..\3dc\avp\bh_track.c +252 +WString +4 +COBJ +253 +WVList +0 +254 +WVList +0 +39 +1 +1 +0 +255 +MItem +21 +..\3dc\avp\bh_types.c +256 +WString +4 +COBJ +257 +WVList +0 +258 +WVList +0 +39 +1 +1 +0 +259 +MItem +27 +..\3dc\avp\bh_videoscreen.c +260 +WString +4 +COBJ +261 +WVList +0 +262 +WVList +0 +39 +1 +1 +0 +263 +MItem +21 +..\3dc\avp\bh_waypt.c +264 +WString +4 +COBJ +265 +WVList +0 +266 +WVList +0 +39 +1 +1 +0 +267 +MItem +20 +..\3dc\avp\bh_weap.c +268 +WString +4 +COBJ +269 +WVList +0 +270 +WVList +0 +39 +1 +1 +0 +271 +MItem +20 +..\3dc\avp\bh_xeno.c +272 +WString +4 +COBJ +273 +WVList +0 +274 +WVList +0 +39 +1 +1 +0 +275 +MItem +27 +..\3dc\avp\bonusabilities.c +276 +WString +4 +COBJ +277 +WVList +0 +278 +WVList +0 +39 +1 +1 +0 +279 +MItem +23 +..\3dc\avp\cheatmodes.c +280 +WString +4 +COBJ +281 +WVList +0 +282 +WVList +0 +39 +1 +1 +0 +283 +MItem +21 +..\3dc\avp\comp_map.c +284 +WString +4 +COBJ +285 +WVList +0 +286 +WVList +0 +39 +1 +1 +0 +287 +MItem +21 +..\3dc\avp\comp_shp.c +288 +WString +4 +COBJ +289 +WVList +0 +290 +WVList +0 +39 +1 +1 +0 +291 +MItem +19 +..\3dc\avp\deaths.c +292 +WString +4 +COBJ +293 +WVList +0 +294 +WVList +0 +39 +1 +1 +0 +295 +MItem +18 +..\3dc\avp\decal.c +296 +WString +4 +COBJ +297 +WVList +0 +298 +WVList +0 +39 +1 +1 +0 +299 +MItem +25 +..\3dc\avp\detaillevels.c +300 +WString +4 +COBJ +301 +WVList +0 +302 +WVList +0 +39 +1 +1 +0 +303 +MItem +21 +..\3dc\avp\dynamics.c +304 +WString +4 +COBJ +305 +WVList +0 +306 +WVList +0 +39 +1 +1 +0 +307 +MItem +21 +..\3dc\avp\dynblock.c +308 +WString +4 +COBJ +309 +WVList +0 +310 +WVList +0 +39 +1 +1 +0 +311 +MItem +21 +..\3dc\avp\equipmnt.c +312 +WString +4 +COBJ +313 +WVList +0 +314 +WVList +0 +39 +1 +1 +0 +315 +MItem +20 +..\3dc\avp\extents.c +316 +WString +4 +COBJ +317 +WVList +0 +318 +WVList +0 +39 +1 +1 +0 +319 +MItem +17 +..\3dc\avp\game.c +320 +WString +4 +COBJ +321 +WVList +0 +322 +WVList +0 +39 +1 +1 +0 +323 +MItem +28 +..\3dc\avp\game_statistics.c +324 +WString +4 +COBJ +325 +WVList +0 +326 +WVList +0 +39 +1 +1 +0 +327 +MItem +21 +..\3dc\avp\gameflow.c +328 +WString +4 +COBJ +329 +WVList +0 +330 +WVList +0 +39 +1 +1 +0 +331 +MItem +19 +..\3dc\avp\hmodel.c +332 +WString +4 +COBJ +333 +WVList +0 +334 +WVList +0 +39 +1 +1 +0 +335 +MItem +16 +..\3dc\avp\hud.c +336 +WString +4 +COBJ +337 +WVList +0 +338 +WVList +0 +39 +1 +1 +0 +339 +MItem +21 +..\3dc\avp\inventry.c +340 +WString +4 +COBJ +341 +WVList +0 +342 +WVList +0 +39 +1 +1 +0 +343 +MItem +21 +..\3dc\avp\language.c +344 +WString +4 +COBJ +345 +WVList +0 +346 +WVList +0 +39 +1 +1 +0 +347 +MItem +21 +..\3dc\avp\lighting.c +348 +WString +4 +COBJ +349 +WVList +0 +350 +WVList +0 +39 +1 +1 +0 +351 +MItem +16 +..\3dc\avp\los.c +352 +WString +4 +COBJ +353 +WVList +0 +354 +WVList +0 +39 +1 +1 +0 +355 +MItem +20 +..\3dc\avp\mempool.c +356 +WString +4 +COBJ +357 +WVList +0 +358 +WVList +0 +39 +1 +1 +0 +359 +MItem +27 +..\3dc\avp\messagehistory.c +360 +WString +4 +COBJ +361 +WVList +0 +362 +WVList +0 +39 +1 +1 +0 +363 +MItem +21 +..\3dc\avp\movement.c +364 +WString +4 +COBJ +365 +WVList +0 +366 +WVList +0 +39 +1 +1 +0 +367 +MItem +22 +..\3dc\avp\mp_launch.c +368 +WString +4 +COBJ +369 +WVList +0 +370 +WVList +0 +39 +1 +1 +0 +371 +MItem +22 +..\3dc\avp\paintball.c +372 +WString +4 +COBJ +373 +WVList +0 +374 +WVList +0 +39 +1 +1 +0 +375 +MItem +21 +..\3dc\avp\particle.c +376 +WString +4 +COBJ +377 +WVList +0 +378 +WVList +0 +39 +1 +1 +0 +379 +MItem +21 +..\3dc\avp\pfarlocs.c +380 +WString +4 +COBJ +381 +WVList +0 +382 +WVList +0 +39 +1 +1 +0 +383 +MItem +21 +..\3dc\avp\pheromon.c +384 +WString +4 +COBJ +385 +WVList +0 +386 +WVList +0 +39 +1 +1 +0 +387 +MItem +19 +..\3dc\avp\player.c +388 +WString +4 +COBJ +389 +WVList +0 +390 +WVList +0 +39 +1 +1 +0 +391 +MItem +18 +..\3dc\avp\pmove.c +392 +WString +4 +COBJ +393 +WVList +0 +394 +WVList +0 +39 +1 +1 +0 +395 +MItem +17 +..\3dc\avp\psnd.c +396 +WString +4 +COBJ +397 +WVList +0 +398 +WVList +0 +39 +1 +1 +0 +399 +MItem +21 +..\3dc\avp\psndproj.c +400 +WString +4 +COBJ +401 +WVList +0 +402 +WVList +0 +39 +1 +1 +0 +403 +MItem +21 +..\3dc\avp\pvisible.c +404 +WString +4 +COBJ +405 +WVList +0 +406 +WVList +0 +39 +1 +1 +0 +407 +MItem +21 +..\3dc\avp\savegame.c +408 +WString +4 +COBJ +409 +WVList +0 +410 +WVList +0 +39 +1 +1 +0 +411 +MItem +21 +..\3dc\avp\secstats.c +412 +WString +4 +COBJ +413 +WVList +0 +414 +WVList +0 +39 +1 +1 +0 +415 +MItem +16 +..\3dc\avp\sfx.c +416 +WString +4 +COBJ +417 +WVList +0 +418 +WVList +0 +39 +1 +1 +0 +419 +MItem +24 +..\3dc\avp\shapes\cube.c +420 +WString +4 +COBJ +421 +WVList +0 +422 +WVList +0 +39 +1 +1 +0 +423 +MItem +21 +..\3dc\avp\stratdef.c +424 +WString +4 +COBJ +425 +WVList +0 +426 +WVList +0 +39 +1 +1 +0 +427 +MItem +28 +..\3dc\avp\support\strutil.c +428 +WString +4 +COBJ +429 +WVList +0 +430 +WVList +0 +39 +1 +1 +0 +431 +MItem +22 +..\3dc\avp\targeting.c +432 +WString +4 +COBJ +433 +WVList +0 +434 +WVList +0 +39 +1 +1 +0 +435 +MItem +18 +..\3dc\avp\track.c +436 +WString +4 +COBJ +437 +WVList +0 +438 +WVList +0 +39 +1 +1 +0 +439 +MItem +21 +..\3dc\avp\triggers.c +440 +WString +4 +COBJ +441 +WVList +0 +442 +WVList +0 +39 +1 +1 +0 +443 +MItem +20 +..\3dc\avp\weapons.c +444 +WString +4 +COBJ +445 +WVList +0 +446 +WVList +0 +39 +1 +1 +0 +447 +MItem +24 +..\3dc\avp\win95\cheat.c +448 +WString +4 +COBJ +449 +WVList +0 +450 +WVList +0 +39 +1 +1 +0 +451 +MItem +29 +..\3dc\avp\win95\directplay.c +452 +WString +4 +COBJ +453 +WVList +0 +454 +WVList +0 +39 +1 +1 +0 +455 +MItem +26 +..\3dc\avp\win95\dp_func.c +456 +WString +4 +COBJ +457 +WVList +0 +458 +WVList +0 +39 +1 +1 +0 +459 +MItem +27 +..\3dc\avp\win95\dplayext.c +460 +WString +4 +COBJ +461 +WVList +0 +462 +WVList +0 +39 +1 +1 +0 +463 +MItem +27 +..\3dc\avp\win95\endianio.c +464 +WString +4 +COBJ +465 +WVList +0 +466 +WVList +0 +39 +1 +1 +0 +467 +MItem +39 +..\3dc\avp\win95\frontend\avp_envinfo.c +468 +WString +4 +COBJ +469 +WVList +0 +470 +WVList +0 +39 +1 +1 +0 +471 +MItem +40 +..\3dc\avp\win95\frontend\avp_menudata.c +472 +WString +4 +COBJ +473 +WVList +0 +474 +WVList +0 +39 +1 +1 +0 +475 +MItem +37 +..\3dc\avp\win95\frontend\avp_menus.c +476 +WString +4 +COBJ +477 +WVList +0 +478 +WVList +0 +39 +1 +1 +0 +479 +MItem +27 +..\3dc\avp\win95\gflwplat.c +480 +WString +4 +COBJ +481 +WVList +0 +482 +WVList +0 +39 +1 +1 +0 +483 +MItem +25 +..\3dc\avp\win95\kzsort.c +484 +WString +4 +COBJ +485 +WVList +0 +486 +WVList +0 +39 +1 +1 +0 +487 +MItem +27 +..\3dc\avp\win95\langplat.c +488 +WString +4 +COBJ +489 +WVList +0 +490 +WVList +0 +39 +1 +1 +0 +491 +MItem +26 +..\3dc\avp\win95\platsup.c +492 +WString +4 +COBJ +493 +WVList +0 +494 +WVList +0 +39 +1 +1 +0 +495 +MItem +27 +..\3dc\avp\win95\pldghost.c +496 +WString +4 +COBJ +497 +WVList +0 +498 +WVList +0 +39 +1 +1 +0 +499 +MItem +25 +..\3dc\avp\win95\pldnet.c +500 +WString +4 +COBJ +501 +WVList +0 +502 +WVList +0 +39 +1 +1 +0 +503 +MItem +27 +..\3dc\avp\win95\psndplat.c +504 +WString +4 +COBJ +505 +WVList +0 +506 +WVList +0 +39 +1 +1 +0 +507 +MItem +25 +..\3dc\avp\win95\system.c +508 +WString +4 +COBJ +509 +WVList +0 +510 +WVList +0 +39 +1 +1 +0 +511 +MItem +25 +..\3dc\avp\win95\usr_io.c +512 +WString +4 +COBJ +513 +WVList +0 +514 +WVList +0 +39 +1 +1 +0 +515 +MItem +25 +..\3dc\avp\win95\vision.c +516 +WString +4 +COBJ +517 +WVList +0 +518 +WVList +0 +39 +1 +1 +0 +519 +MItem +26 +..\3dc\avp\win95\winmain.c +520 +WString +4 +COBJ +521 +WVList +0 +522 +WVList +0 +39 +1 +1 +0 +523 +MItem +17 +..\3dc\frustrum.c +524 +WString +4 +COBJ +525 +WVList +0 +526 +WVList +0 +39 +1 +1 +0 +527 +MItem +15 +..\3dc\kshape.c +528 +WString +4 +COBJ +529 +WVList +0 +530 +WVList +0 +39 +1 +1 +0 +531 +MItem +12 +..\3dc\map.c +532 +WString +4 +COBJ +533 +WVList +0 +534 +WVList +0 +39 +1 +1 +0 +535 +MItem +14 +..\3dc\maths.c +536 +WString +4 +COBJ +537 +WVList +0 +538 +WVList +0 +39 +1 +1 +0 +539 +MItem +15 +..\3dc\mem3dc.c +540 +WString +4 +COBJ +541 +WVList +0 +542 +WVList +0 +39 +1 +1 +0 +543 +MItem +15 +..\3dc\module.c +544 +WString +4 +COBJ +545 +WVList +0 +546 +WVList +0 +39 +1 +1 +0 +547 +MItem +14 +..\3dc\morph.c +548 +WString +4 +COBJ +549 +WVList +0 +550 +WVList +0 +39 +1 +1 +0 +551 +MItem +16 +..\3dc\mslhand.c +552 +WString +4 +COBJ +553 +WVList +0 +554 +WVList +0 +39 +1 +1 +0 +555 +MItem +15 +..\3dc\object.c +556 +WString +4 +COBJ +557 +WVList +0 +558 +WVList +0 +39 +1 +1 +0 +559 +MItem +16 +..\3dc\shpanim.c +560 +WString +4 +COBJ +561 +WVList +0 +562 +WVList +0 +39 +1 +1 +0 +563 +MItem +15 +..\3dc\sphere.c +564 +WString +4 +COBJ +565 +WVList +0 +566 +WVList +0 +39 +1 +1 +0 +567 +MItem +15 +..\3dc\tables.c +568 +WString +4 +COBJ +569 +WVList +0 +570 +WVList +0 +39 +1 +1 +0 +571 +MItem +12 +..\3dc\vdb.c +572 +WString +4 +COBJ +573 +WVList +0 +574 +WVList +0 +39 +1 +1 +0 +575 +MItem +16 +..\3dc\version.c +576 +WString +4 +COBJ +577 +WVList +0 +578 +WVList +0 +39 +1 +1 +0 +579 +MItem +19 +..\3dc\win95\bink.c +580 +WString +4 +COBJ +581 +WVList +0 +582 +WVList +0 +39 +1 +1 +0 +583 +MItem +24 +..\3dc\win95\cd_player.c +584 +WString +4 +COBJ +585 +WVList +0 +586 +WVList +0 +39 +1 +1 +0 +587 +MItem +17 +..\3dc\win95\db.c +588 +WString +4 +COBJ +589 +WVList +0 +590 +WVList +0 +39 +1 +1 +0 +591 +MItem +20 +..\3dc\win95\dxlog.c +592 +WString +4 +COBJ +593 +WVList +0 +594 +WVList +0 +39 +1 +1 +0 +595 +MItem +19 +..\3dc\win95\fail.c +596 +WString +4 +COBJ +597 +WVList +0 +598 +WVList +0 +39 +1 +1 +0 +599 +MItem +17 +..\3dc\win95\io.c +600 +WString +4 +COBJ +601 +WVList +0 +602 +WVList +0 +39 +1 +1 +0 +603 +MItem +18 +..\3dc\win95\md5.c +604 +WString +4 +COBJ +605 +WVList +0 +606 +WVList +0 +39 +1 +1 +0 +607 +MItem +22 +..\3dc\win95\our_mem.c +608 +WString +4 +COBJ +609 +WVList +0 +610 +WVList +0 +39 +1 +1 +0 +611 +MItem +23 +..\3dc\win95\plat_shp.c +612 +WString +4 +COBJ +613 +WVList +0 +614 +WVList +0 +39 +1 +1 +0 +615 +MItem +23 +..\3dc\win95\plspecfn.c +616 +WString +4 +COBJ +617 +WVList +0 +618 +WVList +0 +39 +1 +1 +0 +619 +MItem +22 +..\3dc\win95\smacker.c +620 +WString +4 +COBJ +621 +WVList +0 +622 +WVList +0 +39 +1 +1 +0 +623 +MItem +20 +..\3dc\win95\texio.c +624 +WString +4 +COBJ +625 +WVList +0 +626 +WVList +0 +39 +1 +1 +0 +627 +MItem +23 +..\3dc\win95\vramtime.c +628 +WString +4 +COBJ +629 +WVList +0 +630 +WVList +0 +39 +1 +1 +0 +631 +MItem +5 +*.cpp +632 +WString +6 +CPPOBJ +633 +WVList +22 +634 +MVState +635 +WString +3 +WPP +636 +WString +25 +n????Include directories: +1 +637 +WString +177 +c:\Dx6sdk\include;c:\watcom\h\nt;c:\watcom\h;..\3dc\avp;..\3dc\win95;..\3dc\include;..\3dc\avp\win95;..\3dc\avp\support;..\3dc\avp\win95\gadgets;..\3dc\avp\win95\frontend;..\3dc +0 +638 +MVState +639 +WString +3 +WPP +640 +WString +23 +?????Macro definitions: +1 +641 +WString +31 +_WIN32 WIN32 engine=1 __STDC__ +0 +642 +MCState +643 +WString +3 +WPP +644 +WString +31 +?????Force enums to be type int +1 +1 +645 +MRState +646 +WString +3 +WPP +647 +WString +20 +?????Pack structures +1 +0 +648 +MRState +649 +WString +3 +WPP +650 +WString +21 +?????8 byte alignment +1 +1 +651 +MRState +652 +WString +3 +WPP +653 +WString +21 +?????No optimizations +1 +0 +654 +MRState +655 +WString +3 +WPP +656 +WString +26 +?????Fastest possible code +1 +1 +657 +MCState +658 +WString +3 +WPP +659 +WString +23 +?????Loop optimizations +1 +1 +660 +MCState +661 +WString +3 +WPP +662 +WString +19 +?????Loop unrolling +1 +1 +663 +MCState +664 +WString +3 +WPP +665 +WString +23 +?????Math optimizations +1 +1 +666 +MCState +667 +WString +3 +WPP +668 +WString +32 +?????In-line intrinsic functions +1 +1 +669 +MCState +670 +WString +3 +WPP +671 +WString +25 +?????Relax alias checking +1 +1 +672 +MCState +673 +WString +3 +WPP +674 +WString +27 +?????Instruction scheduling +1 +1 +675 +MVState +676 +WString +3 +WPP +677 +WString +29 +?????Expand function in-line: +1 +678 +WString +2 +20 +1 +679 +MRState +680 +WString +3 +WPP +681 +WString +29 +?????No debugging information +1 +1 +682 +MRState +683 +WString +3 +WPP +684 +WString +24 +?????Full debugging info +1 +0 +685 +MRState +686 +WString +3 +WPP +687 +WString +21 +?????Compiler default +1 +0 +688 +MCState +689 +WString +3 +WPP +690 +WString +30 +n????Multithreaded application +1 +1 +691 +MRState +692 +WString +3 +WPP +693 +WString +21 +?????Compiler default +1 +0 +694 +MRState +695 +WString +3 +WPP +696 +WString +33 +?????In-line Pentium instructions +1 +1 +697 +MRState +698 +WString +3 +WPP +699 +WString +21 +?????Compiler default +1 +0 +700 +MRState +701 +WString +3 +WPP +702 +WString +29 +?????In-line with coprocessor +1 +1 +703 +WVList +0 +-1 +1 +1 +0 +704 +MItem +23 +..\3dc\avp\cconvars.cpp +705 +WString +6 +CPPOBJ +706 +WVList +0 +707 +WVList +0 +631 +1 +1 +0 +708 +MItem +31 +..\3dc\avp\cdtrackselection.cpp +709 +WString +6 +CPPOBJ +710 +WVList +0 +711 +WVList +0 +631 +1 +1 +0 +712 +MItem +25 +..\3dc\avp\consolelog.cpp +713 +WString +6 +CPPOBJ +714 +WVList +0 +715 +WVList +0 +631 +1 +1 +0 +716 +MItem +23 +..\3dc\avp\davehook.cpp +717 +WString +6 +CPPOBJ +718 +WVList +0 +719 +WVList +0 +631 +1 +1 +0 +720 +MItem +23 +..\3dc\avp\equiputl.cpp +721 +WString +6 +CPPOBJ +722 +WVList +0 +723 +WVList +0 +631 +1 +1 +0 +724 +MItem +23 +..\3dc\avp\gamecmds.cpp +725 +WString +6 +CPPOBJ +726 +WVList +0 +727 +WVList +0 +631 +1 +1 +0 +728 +MItem +23 +..\3dc\avp\gamevars.cpp +729 +WString +6 +CPPOBJ +730 +WVList +0 +731 +WVList +0 +631 +1 +1 +0 +732 +MItem +23 +..\3dc\avp\missions.cpp +733 +WString +6 +CPPOBJ +734 +WVList +0 +735 +WVList +0 +631 +1 +1 +0 +736 +MItem +21 +..\3dc\avp\scream.cpp +737 +WString +6 +CPPOBJ +738 +WVList +0 +739 +WVList +0 +631 +1 +1 +0 +740 +MItem +31 +..\3dc\avp\support\consbind.cpp +741 +WString +6 +CPPOBJ +742 +WVList +0 +743 +WVList +0 +631 +1 +1 +0 +744 +MItem +31 +..\3dc\avp\support\consbtch.cpp +745 +WString +6 +CPPOBJ +746 +WVList +0 +747 +WVList +0 +631 +1 +1 +0 +748 +MItem +31 +..\3dc\avp\support\coordstr.cpp +749 +WString +6 +CPPOBJ +750 +WVList +0 +751 +WVList +0 +631 +1 +1 +0 +752 +MItem +29 +..\3dc\avp\support\daemon.cpp +753 +WString +6 +CPPOBJ +754 +WVList +0 +755 +WVList +0 +631 +1 +1 +0 +756 +MItem +31 +..\3dc\avp\support\indexfnt.cpp +757 +WString +6 +CPPOBJ +758 +WVList +0 +759 +WVList +0 +631 +1 +1 +0 +760 +MItem +29 +..\3dc\avp\support\r2base.cpp +761 +WString +6 +CPPOBJ +762 +WVList +0 +763 +WVList +0 +631 +1 +1 +0 +764 +MItem +31 +..\3dc\avp\support\r2pos666.cpp +765 +WString +6 +CPPOBJ +766 +WVList +0 +767 +WVList +0 +631 +1 +1 +0 +768 +MItem +30 +..\3dc\avp\support\reflist.cpp +769 +WString +6 +CPPOBJ +770 +WVList +0 +771 +WVList +0 +631 +1 +1 +0 +772 +MItem +29 +..\3dc\avp\support\refobj.cpp +773 +WString +6 +CPPOBJ +774 +WVList +0 +775 +WVList +0 +631 +1 +1 +0 +776 +MItem +31 +..\3dc\avp\support\rentrntq.cpp +777 +WString +6 +CPPOBJ +778 +WVList +0 +779 +WVList +0 +631 +1 +1 +0 +780 +MItem +31 +..\3dc\avp\support\scstring.cpp +781 +WString +6 +CPPOBJ +782 +WVList +0 +783 +WVList +0 +631 +1 +1 +0 +784 +MItem +29 +..\3dc\avp\support\strtab.cpp +785 +WString +6 +CPPOBJ +786 +WVList +0 +787 +WVList +0 +631 +1 +1 +0 +788 +MItem +31 +..\3dc\avp\support\tallfont.cpp +789 +WString +6 +CPPOBJ +790 +WVList +0 +791 +WVList +0 +631 +1 +1 +0 +792 +MItem +30 +..\3dc\avp\support\trig666.cpp +793 +WString +6 +CPPOBJ +794 +WVList +0 +795 +WVList +0 +631 +1 +1 +0 +796 +MItem +30 +..\3dc\avp\support\wrapstr.cpp +797 +WString +6 +CPPOBJ +798 +WVList +0 +799 +WVList +0 +631 +1 +1 +0 +800 +MItem +29 +..\3dc\avp\win95\avpchunk.cpp +801 +WString +6 +CPPOBJ +802 +WVList +0 +803 +WVList +0 +631 +1 +1 +0 +804 +MItem +27 +..\3dc\avp\win95\avpreg.cpp +805 +WString +6 +CPPOBJ +806 +WVList +0 +807 +WVList +0 +631 +1 +1 +0 +808 +MItem +29 +..\3dc\avp\win95\chtcodes.cpp +809 +WString +6 +CPPOBJ +810 +WVList +0 +811 +WVList +0 +631 +1 +1 +0 +812 +MItem +28 +..\3dc\avp\win95\d3d_hud.cpp +813 +WString +6 +CPPOBJ +814 +WVList +0 +815 +WVList +0 +631 +1 +1 +0 +816 +MItem +31 +..\3dc\avp\win95\d3d_render.cpp +817 +WString +6 +CPPOBJ +818 +WVList +0 +819 +WVList +0 +631 +1 +1 +0 +820 +MItem +27 +..\3dc\avp\win95\ddplat.cpp +821 +WString +6 +CPPOBJ +822 +WVList +0 +823 +WVList +0 +631 +1 +1 +0 +824 +MItem +28 +..\3dc\avp\win95\dx_proj.cpp +825 +WString +6 +CPPOBJ +826 +WVList +0 +827 +WVList +0 +631 +1 +1 +0 +828 +MItem +27 +..\3dc\avp\win95\ffread.cpp +829 +WString +6 +CPPOBJ +830 +WVList +0 +831 +WVList +0 +631 +1 +1 +0 +832 +MItem +28 +..\3dc\avp\win95\ffstdio.cpp +833 +WString +6 +CPPOBJ +834 +WVList +0 +835 +WVList +0 +631 +1 +1 +0 +836 +MItem +39 +..\3dc\avp\win95\frontend\avp_intro.cpp +837 +WString +6 +CPPOBJ +838 +WVList +0 +839 +WVList +0 +631 +1 +1 +0 +840 +MItem +41 +..\3dc\avp\win95\frontend\avp_menugfx.cpp +841 +WString +6 +CPPOBJ +842 +WVList +0 +843 +WVList +0 +631 +1 +1 +0 +844 +MItem +43 +..\3dc\avp\win95\frontend\avp_mp_config.cpp +845 +WString +6 +CPPOBJ +846 +WVList +0 +847 +WVList +0 +631 +1 +1 +0 +848 +MItem +45 +..\3dc\avp\win95\frontend\avp_userprofile.cpp +849 +WString +6 +CPPOBJ +850 +WVList +0 +851 +WVList +0 +631 +1 +1 +0 +852 +MItem +37 +..\3dc\avp\win95\gadgets\ahudgadg.cpp +853 +WString +6 +CPPOBJ +854 +WVList +0 +855 +WVList +0 +631 +1 +1 +0 +856 +MItem +37 +..\3dc\avp\win95\gadgets\conscmnd.cpp +857 +WString +6 +CPPOBJ +858 +WVList +0 +859 +WVList +0 +631 +1 +1 +0 +860 +MItem +36 +..\3dc\avp\win95\gadgets\conssym.cpp +861 +WString +6 +CPPOBJ +862 +WVList +0 +863 +WVList +0 +631 +1 +1 +0 +864 +MItem +36 +..\3dc\avp\win95\gadgets\consvar.cpp +865 +WString +6 +CPPOBJ +866 +WVList +0 +867 +WVList +0 +631 +1 +1 +0 +868 +MItem +35 +..\3dc\avp\win95\gadgets\gadget.cpp +869 +WString +6 +CPPOBJ +870 +WVList +0 +871 +WVList +0 +631 +1 +1 +0 +872 +MItem +36 +..\3dc\avp\win95\gadgets\hudgadg.cpp +873 +WString +6 +CPPOBJ +874 +WVList +0 +875 +WVList +0 +631 +1 +1 +0 +876 +MItem +37 +..\3dc\avp\win95\gadgets\rootgadg.cpp +877 +WString +6 +CPPOBJ +878 +WVList +0 +879 +WVList +0 +631 +1 +1 +0 +880 +MItem +37 +..\3dc\avp\win95\gadgets\t_ingadg.cpp +881 +WString +6 +CPPOBJ +882 +WVList +0 +883 +WVList +0 +631 +1 +1 +0 +884 +MItem +37 +..\3dc\avp\win95\gadgets\teletype.cpp +885 +WString +6 +CPPOBJ +886 +WVList +0 +887 +WVList +0 +631 +1 +1 +0 +888 +MItem +36 +..\3dc\avp\win95\gadgets\textexp.cpp +889 +WString +6 +CPPOBJ +890 +WVList +0 +891 +WVList +0 +631 +1 +1 +0 +892 +MItem +35 +..\3dc\avp\win95\gadgets\textin.cpp +893 +WString +6 +CPPOBJ +894 +WVList +0 +895 +WVList +0 +631 +1 +1 +0 +896 +MItem +37 +..\3dc\avp\win95\gadgets\trepgadg.cpp +897 +WString +6 +CPPOBJ +898 +WVList +0 +899 +WVList +0 +631 +1 +1 +0 +900 +MItem +33 +..\3dc\avp\win95\gammacontrol.cpp +901 +WString +6 +CPPOBJ +902 +WVList +0 +903 +WVList +0 +631 +1 +1 +0 +904 +MItem +30 +..\3dc\avp\win95\hierplace.cpp +905 +WString +6 +CPPOBJ +906 +WVList +0 +907 +WVList +0 +631 +1 +1 +0 +908 +MItem +26 +..\3dc\avp\win95\intro.cpp +909 +WString +6 +CPPOBJ +910 +WVList +0 +911 +WVList +0 +631 +1 +1 +0 +912 +MItem +28 +..\3dc\avp\win95\iofocus.cpp +913 +WString +6 +CPPOBJ +914 +WVList +0 +915 +WVList +0 +631 +1 +1 +0 +916 +MItem +28 +..\3dc\avp\win95\jsndsup.cpp +917 +WString +6 +CPPOBJ +918 +WVList +0 +919 +WVList +0 +631 +1 +1 +0 +920 +MItem +28 +..\3dc\avp\win95\modcmds.cpp +921 +WString +6 +CPPOBJ +922 +WVList +0 +923 +WVList +0 +631 +1 +1 +0 +924 +MItem +35 +..\3dc\avp\win95\mousecentreing.cpp +925 +WString +6 +CPPOBJ +926 +WVList +0 +927 +WVList +0 +631 +1 +1 +0 +928 +MItem +29 +..\3dc\avp\win95\npcsetup.cpp +929 +WString +6 +CPPOBJ +930 +WVList +0 +931 +WVList +0 +631 +1 +1 +0 +932 +MItem +29 +..\3dc\avp\win95\objsetup.cpp +933 +WString +6 +CPPOBJ +934 +WVList +0 +935 +WVList +0 +631 +1 +1 +0 +936 +MItem +29 +..\3dc\avp\win95\pathchnk.cpp +937 +WString +6 +CPPOBJ +938 +WVList +0 +939 +WVList +0 +631 +1 +1 +0 +940 +MItem +28 +..\3dc\avp\win95\pcmenus.cpp +941 +WString +6 +CPPOBJ +942 +WVList +0 +943 +WVList +0 +631 +1 +1 +0 +944 +MItem +33 +..\3dc\avp\win95\progress_bar.cpp +945 +WString +6 +CPPOBJ +946 +WVList +0 +947 +WVList +0 +631 +1 +1 +0 +948 +MItem +29 +..\3dc\avp\win95\projload.cpp +949 +WString +6 +CPPOBJ +950 +WVList +0 +951 +WVList +0 +631 +1 +1 +0 +952 +MItem +28 +..\3dc\avp\win95\scrshot.cpp +953 +WString +6 +CPPOBJ +954 +WVList +0 +955 +WVList +0 +631 +1 +1 +0 +956 +MItem +29 +..\3dc\avp\win95\strachnk.cpp +957 +WString +6 +CPPOBJ +958 +WVList +0 +959 +WVList +0 +631 +1 +1 +0 +960 +MItem +29 +..\3dc\avp\win95\win_proj.cpp +961 +WString +6 +CPPOBJ +962 +WVList +0 +963 +WVList +0 +631 +1 +1 +0 +964 +MItem +19 +..\3dc\mem3dcpp.cpp +965 +WString +6 +CPPOBJ +966 +WVList +0 +967 +WVList +0 +631 +1 +1 +0 +968 +MItem +24 +..\3dc\win95\alt_tab.cpp +969 +WString +6 +CPPOBJ +970 +WVList +0 +971 +WVList +0 +631 +1 +1 +0 +972 +MItem +25 +..\3dc\win95\animchnk.cpp +973 +WString +6 +CPPOBJ +974 +WVList +0 +975 +WVList +0 +631 +1 +1 +0 +976 +MItem +24 +..\3dc\win95\animobs.cpp +977 +WString +6 +CPPOBJ +978 +WVList +0 +979 +WVList +0 +631 +1 +1 +0 +980 +MItem +24 +..\3dc\win95\awbmpld.cpp +981 +WString +6 +CPPOBJ +982 +WVList +0 +983 +WVList +0 +631 +1 +1 +0 +984 +MItem +24 +..\3dc\win95\awiffld.cpp +985 +WString +6 +CPPOBJ +986 +WVList +0 +987 +WVList +0 +631 +1 +1 +0 +988 +MItem +24 +..\3dc\win95\awpnmld.cpp +989 +WString +6 +CPPOBJ +990 +WVList +0 +991 +WVList +0 +631 +1 +1 +0 +992 +MItem +24 +..\3dc\win95\awtexld.cpp +993 +WString +6 +CPPOBJ +994 +WVList +0 +995 +WVList +0 +631 +1 +1 +0 +996 +MItem +25 +..\3dc\win95\bmpnames.cpp +997 +WString +6 +CPPOBJ +998 +WVList +0 +999 +WVList +0 +631 +1 +1 +0 +1000 +MItem +25 +..\3dc\win95\chnkload.cpp +1001 +WString +6 +CPPOBJ +1002 +WVList +0 +1003 +WVList +0 +631 +1 +1 +0 +1004 +MItem +25 +..\3dc\win95\chnktexi.cpp +1005 +WString +6 +CPPOBJ +1006 +WVList +0 +1007 +WVList +0 +631 +1 +1 +0 +1008 +MItem +25 +..\3dc\win95\chnktype.cpp +1009 +WString +6 +CPPOBJ +1010 +WVList +0 +1011 +WVList +0 +631 +1 +1 +0 +1012 +MItem +22 +..\3dc\win95\chunk.cpp +1013 +WString +6 +CPPOBJ +1014 +WVList +0 +1015 +WVList +0 +631 +1 +1 +0 +1016 +MItem +25 +..\3dc\win95\chunkpal.cpp +1017 +WString +6 +CPPOBJ +1018 +WVList +0 +1019 +WVList +0 +631 +1 +1 +0 +1020 +MItem +24 +..\3dc\win95\d3_func.cpp +1021 +WString +6 +CPPOBJ +1022 +WVList +0 +1023 +WVList +0 +631 +1 +1 +0 +1024 +MItem +24 +..\3dc\win95\dd_func.cpp +1025 +WString +6 +CPPOBJ +1026 +WVList +0 +1027 +WVList +0 +631 +1 +1 +0 +1028 +MItem +25 +..\3dc\win95\debuglog.cpp +1029 +WString +6 +CPPOBJ +1030 +WVList +0 +1031 +WVList +0 +631 +1 +1 +0 +1032 +MItem +24 +..\3dc\win95\di_func.cpp +1033 +WString +6 +CPPOBJ +1034 +WVList +0 +1035 +WVList +0 +631 +1 +1 +0 +1036 +MItem +25 +..\3dc\win95\envchunk.cpp +1037 +WString +6 +CPPOBJ +1038 +WVList +0 +1039 +WVList +0 +631 +1 +1 +0 +1040 +MItem +25 +..\3dc\win95\fragchnk.cpp +1041 +WString +6 +CPPOBJ +1042 +WVList +0 +1043 +WVList +0 +631 +1 +1 +0 +1044 +MItem +25 +..\3dc\win95\gsprchnk.cpp +1045 +WString +6 +CPPOBJ +1046 +WVList +0 +1047 +WVList +0 +631 +1 +1 +0 +1048 +MItem +25 +..\3dc\win95\hierchnk.cpp +1049 +WString +6 +CPPOBJ +1050 +WVList +0 +1051 +WVList +0 +631 +1 +1 +0 +1052 +MItem +24 +..\3dc\win95\huffman.cpp +1053 +WString +6 +CPPOBJ +1054 +WVList +0 +1055 +WVList +0 +631 +1 +1 +0 +1056 +MItem +20 +..\3dc\win95\iff.cpp +1057 +WString +6 +CPPOBJ +1058 +WVList +0 +1059 +WVList +0 +631 +1 +1 +0 +1060 +MItem +25 +..\3dc\win95\iff_ilbm.cpp +1061 +WString +6 +CPPOBJ +1062 +WVList +0 +1063 +WVList +0 +631 +1 +1 +0 +1064 +MItem +25 +..\3dc\win95\list_tem.cpp +1065 +WString +6 +CPPOBJ +1066 +WVList +0 +1067 +WVList +0 +631 +1 +1 +0 +1068 +MItem +24 +..\3dc\win95\ltchunk.cpp +1069 +WString +6 +CPPOBJ +1070 +WVList +0 +1071 +WVList +0 +631 +1 +1 +0 +1072 +MItem +22 +..\3dc\win95\media.cpp +1073 +WString +6 +CPPOBJ +1074 +WVList +0 +1075 +WVList +0 +631 +1 +1 +0 +1076 +MItem +25 +..\3dc\win95\mishchnk.cpp +1077 +WString +6 +CPPOBJ +1078 +WVList +0 +1079 +WVList +0 +631 +1 +1 +0 +1080 +MItem +24 +..\3dc\win95\obchunk.cpp +1081 +WString +6 +CPPOBJ +1082 +WVList +0 +1083 +WVList +0 +631 +1 +1 +0 +1084 +MItem +25 +..\3dc\win95\shpchunk.cpp +1085 +WString +6 +CPPOBJ +1086 +WVList +0 +1087 +WVList +0 +631 +1 +1 +0 +1088 +MItem +25 +..\3dc\win95\sndchunk.cpp +1089 +WString +6 +CPPOBJ +1090 +WVList +0 +1091 +WVList +0 +631 +1 +1 +0 +1092 +MItem +25 +..\3dc\win95\sprchunk.cpp +1093 +WString +6 +CPPOBJ +1094 +WVList +0 +1095 +WVList +0 +631 +1 +1 +0 +1096 +MItem +25 +..\3dc\win95\txioctrl.cpp +1097 +WString +6 +CPPOBJ +1098 +WVList +0 +1099 +WVList +0 +631 +1 +1 +0 +1100 +MItem +27 +..\3dc\win95\videomodes.cpp +1101 +WString +6 +CPPOBJ +1102 +WVList +0 +1103 +WVList +0 +631 +1 +1 +0 +1104 +MItem +25 +..\3dc\win95\win_func.cpp +1105 +WString +6 +CPPOBJ +1106 +WVList +0 +1107 +WVList +0 +631 +1 +1 +0 +1108 +MItem +24 +..\3dc\win95\wpchunk.cpp +1109 +WString +6 +CPPOBJ +1110 +WVList +0 +1111 +WVList +0 +631 +1 +1 +0 +1112 +MItem +4 +*.rc +1113 +WString +5 +NRESC +1114 +WVList +0 +1115 +WVList +0 +-1 +1 +1 +0 +1116 +MItem +13 +..\3dc\avp.rc +1117 +WString +5 +NRESC +1118 +WVList +0 +1119 +WVList +0 +1112 +1 +1 +0